tui

package
v0.0.73 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var HistoryPathOverride string

HistoryPathOverride can be set by tests to redirect history I/O to a temp file.

Functions

func SaveHistory

func SaveHistory(entries []HistoryEntry)

SaveHistory writes history entries to disk.

Types

type ActivePaneComponent

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

ActivePaneComponent manages the in-progress jobs pane.

"In Progress (N)" reflects items where Claude is actively running — not items whose dispatch goroutines have merely launched. JobStartedEvent is emitted by processItem / processComments past all early-return guards (lock acquired, all pre-work checks passed), never at goroutine launch. The matching JobCompletedEvent is emitted by InvocationObserver on the success path (Skipped: false). A synthetic JobCompletedEvent{Skipped: true} is also deferred unconditionally at the emission site as a cleanup guard; HistoryPaneComponent filters it out so only InvocationObserver events reach history. Do NOT re-add JobStartedEvent emission to dispatch goroutines — that causes indefinite ghost entries whenever processItem early-returns without invoking Claude.

func (ActivePaneComponent) ActiveCount

func (a ActivePaneComponent) ActiveCount() int

ActiveCount returns len(active).

func (ActivePaneComponent) Height

func (a ActivePaneComponent) Height() int

func (ActivePaneComponent) SelectedJob

func (a ActivePaneComponent) SelectedJob() *activeJob

SelectedJob returns the currently selected active job, or nil if none.

func (*ActivePaneComponent) SetFocused

func (a *ActivePaneComponent) SetFocused(f bool)

SetFocused updates the focused state.

func (ActivePaneComponent) TotalCount

func (a ActivePaneComponent) TotalCount() int

TotalCount returns len(active) + len(blocked).

func (ActivePaneComponent) Update

func (a ActivePaneComponent) Update(msg tea.Msg) (Component, tea.Cmd)

func (ActivePaneComponent) View

func (a ActivePaneComponent) View(width int) string

type AlertBannerComponent

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

AlertBannerComponent renders a single high-visibility row when the GraphQL budget is exhausted or probe failures attributable to rate limiting have been observed. It implements the Component interface. Height() returns 1 when the banner is visible and 0 otherwise, so the layout budget in model.go is correct.

func (AlertBannerComponent) Height

func (a AlertBannerComponent) Height() int

Height returns 1 when the banner is visible, 0 otherwise.

func (AlertBannerComponent) Update

func (a AlertBannerComponent) Update(msg tea.Msg) (Component, tea.Cmd)

Update handles events relevant to the alert banner.

func (AlertBannerComponent) View

func (a AlertBannerComponent) View(width int) string

View renders the alert banner at the given width.

type Component

type Component interface {
	Update(msg tea.Msg) (Component, tea.Cmd)
	View(width int) string
	Height() int
}

Component is the interface implemented by each TUI pane/section. The root Model orchestrates layout and focus; each Component owns its own state and rendering. Hit-testing (HandleClick) is implemented as a pointer-receiver method on each component, not part of this interface, since it needs to mutate state directly.

type CustomWorkflowEvent

type CustomWorkflowEvent struct{}

CustomWorkflowEvent is emitted when the three-way plugin comparison determines that the operator has local customizations in .fabrik/plugin/ that differ from the last recorded installed-version. This state is mutually exclusive with SkillsStaleEvent (customWorkflow takes priority over skillsStaleCount).

type DetailItem

type DetailItem struct {
	IssueNumber    int
	Title          string
	StageName      string
	StageModel     string
	IsActive       bool // true for in-flight jobs, false for history entries
	Elapsed        time.Duration
	Duration       time.Duration
	Success        bool
	Completed      bool
	BlockedOnInput bool
	TurnsUsed      int
	MaxTurns       int
	CostUSD        float64
	CompletedAt    time.Time
}

DetailItem is a union type holding fields needed for detail panel rendering. Constructed by the root model from whichever pane is focused.

type DetailPanelComponent

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

DetailPanelComponent renders metadata for a selected item. It is a pure view component — Update is a no-op.

func (DetailPanelComponent) HandleClick

func (d DetailPanelComponent) HandleClick(x, y int) bool

func (DetailPanelComponent) Height

func (d DetailPanelComponent) Height() int

func (DetailPanelComponent) IsVisible

func (d DetailPanelComponent) IsVisible() bool

IsVisible returns whether the detail panel is shown.

func (*DetailPanelComponent) SetItem

func (d *DetailPanelComponent) SetItem(item *DetailItem)

SetItem updates the item displayed in the detail panel.

func (*DetailPanelComponent) SetVisible

func (d *DetailPanelComponent) SetVisible(v bool)

SetVisible controls whether the detail panel is shown.

func (*DetailPanelComponent) SetWidth

func (d *DetailPanelComponent) SetWidth(w int)

SetWidth records the terminal width for use in Height() calculations.

func (DetailPanelComponent) Update

func (d DetailPanelComponent) Update(msg tea.Msg) (Component, tea.Cmd)

func (DetailPanelComponent) View

func (d DetailPanelComponent) View(width int) string

type Event

type Event interface {
	// contains filtered or unexported methods
}

Event is the interface implemented by all typed engine events.

type FooterComponent

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

FooterComponent renders the bottom status bar: project info, rate limit stats, and (when webhook mode is active) the webhook health indicator.

func (FooterComponent) Height

func (f FooterComponent) Height() int

func (FooterComponent) Update

func (f FooterComponent) Update(msg tea.Msg) (Component, tea.Cmd)

func (FooterComponent) View

func (f FooterComponent) View(width int) string

type HeaderComponent

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

HeaderComponent renders the top status bar: title, status line, and poll timer.

func (HeaderComponent) HandleClick

func (h HeaderComponent) HandleClick(x, y int) bool

func (HeaderComponent) Height

func (h HeaderComponent) Height() int

func (*HeaderComponent) SetCustomWorkflow

func (h *HeaderComponent) SetCustomWorkflow(v bool)

SetCustomWorkflow sets the custom workflow state. When true, a persistent [u] custom workflow badge is shown (with priority over skillsStaleCount).

func (*HeaderComponent) SetSkillsStaleCount

func (h *HeaderComponent) SetSkillsStaleCount(n int)

SetSkillsStaleCount sets the number of plugin skill files that differ from the embedded versions. When n > 0, a persistent badge is shown in the header.

func (*HeaderComponent) SetStatusMsg

func (h *HeaderComponent) SetStatusMsg(msg string)

SetStatusMsg sets a transient status message shown in the header.

func (HeaderComponent) Update

func (h HeaderComponent) Update(msg tea.Msg) (Component, tea.Cmd)

func (HeaderComponent) View

func (h HeaderComponent) View(width int) string

type HelpPanelComponent

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

HelpPanelComponent renders a scrollable help overlay with keybindings and label reference. It follows the DetailPanelComponent pattern: value-type component with pointer-receiver setters and Height() returning 0 when not visible.

func (HelpPanelComponent) Height

func (h HelpPanelComponent) Height() int

Height returns the total rendered height by measuring the actual rendered view. Returns 0 when not visible. Uses the same approach as DetailPanelComponent to correctly account for any line wrapping inside the border.

func (*HelpPanelComponent) ScrollToTop

func (h *HelpPanelComponent) ScrollToTop()

ScrollToTop scrolls the viewport to the top.

func (*HelpPanelComponent) SetLayout

func (h *HelpPanelComponent) SetLayout(width, targetHeight int)

SetLayout sizes the internal viewport to fit within targetHeight terminal rows. The viewport height is targetHeight - 3 (subtracting 1 title and 2 border lines). On resize the existing scroll offset is preserved so an open panel stays in place.

func (*HelpPanelComponent) SetVisible

func (h *HelpPanelComponent) SetVisible(v bool)

SetVisible controls whether the help panel is shown.

func (HelpPanelComponent) Update

func (h HelpPanelComponent) Update(msg tea.Msg) (Component, tea.Cmd)

Update is a no-op. Scrolling is handled by forwarding key events from the root model directly to vp.

func (HelpPanelComponent) View

func (h HelpPanelComponent) View(width int) string

View renders the help panel. Returns an empty string when not visible.

type HistoryEntry

type HistoryEntry struct {
	IssueNumber    int
	Repo           string // "owner/repo" — empty for single-repo projects
	Title          string
	StageName      string
	StageModel     string // model configured for the stage; empty means use claude default
	IsComment      bool
	Success        bool
	Completed      bool
	BlockedOnInput bool
	Duration       time.Duration
	CompletedAt    time.Time
	TurnsUsed      int
	MaxTurns       int
	CostUSD        float64
}

HistoryEntry records a completed job for the history pane.

func LoadHistory

func LoadHistory() []HistoryEntry

LoadHistory reads saved history entries from disk.

type HistoryPaneComponent

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

HistoryPaneComponent manages the completed jobs history pane.

func NewHistoryPaneComponent

func NewHistoryPaneComponent(defaultRepo string) HistoryPaneComponent

NewHistoryPaneComponent creates a new HistoryPaneComponent with loaded history. defaultRepo is "owner/repo" used for OSC 8 issue links when a history entry's Repo is empty.

func (HistoryPaneComponent) ConfirmClear

func (h HistoryPaneComponent) ConfirmClear() bool

ConfirmClear returns the confirmClear state.

func (HistoryPaneComponent) Height

func (h HistoryPaneComponent) Height() int

func (HistoryPaneComponent) HistIdx

func (h HistoryPaneComponent) HistIdx() int

HistIdx returns the current history selection index.

func (HistoryPaneComponent) History

func (h HistoryPaneComponent) History() []HistoryEntry

History returns the history entries.

func (*HistoryPaneComponent) ScrollToTop

func (h *HistoryPaneComponent) ScrollToTop()

ScrollToTop scrolls the viewport to the top.

func (*HistoryPaneComponent) ScrollToVisible

func (h *HistoryPaneComponent) ScrollToVisible()

ScrollToVisible ensures histIdx is visible within the viewport.

func (HistoryPaneComponent) SelectedEntry

func (h HistoryPaneComponent) SelectedEntry() *HistoryEntry

SelectedEntry returns the currently selected history entry, or nil if none.

func (*HistoryPaneComponent) SetConfirmClear

func (h *HistoryPaneComponent) SetConfirmClear(v bool)

SetConfirmClear sets the confirmClear state.

func (*HistoryPaneComponent) SetFocused

func (h *HistoryPaneComponent) SetFocused(f bool)

SetFocused updates the focused state.

func (*HistoryPaneComponent) SetHistIdx

func (h *HistoryPaneComponent) SetHistIdx(idx int)

SetHistIdx sets the history selection index.

func (*HistoryPaneComponent) SetLayout

func (h *HistoryPaneComponent) SetLayout(width, availableHeight int, confirmQuit bool, activeCount int)

SetLayout updates the viewport dimensions based on available space.

func (HistoryPaneComponent) Update

func (h HistoryPaneComponent) Update(msg tea.Msg) (Component, tea.Cmd)

func (HistoryPaneComponent) VPHeight

func (h HistoryPaneComponent) VPHeight() int

VPHeight returns the viewport height.

func (HistoryPaneComponent) View

func (h HistoryPaneComponent) View(width int) string

func (HistoryPaneComponent) YOffset

func (h HistoryPaneComponent) YOffset() int

YOffset returns the current viewport Y offset.

type IssueBlockedEvent

type IssueBlockedEvent struct {
	IssueNumber int
	Repo        string // "owner/repo" — empty for single-repo projects
	Title       string
	StageName   string
	WaitingFor  []string // e.g. ["#214", "owner/repo#215"]
}

IssueBlockedEvent is emitted when an issue is held at the dependency gate. It is emitted each time checkDependencies fires for a blocked issue.

type JobCompletedEvent

type JobCompletedEvent struct {
	IssueNumber    int
	Repo           string // "owner/repo" — empty for single-repo projects
	Title          string
	StageName      string
	StageModel     string // model configured for the stage (e.g. "sonnet")
	IsComment      bool   // true when processing a user comment, not a stage run
	Success        bool   // no error from processItem
	Completed      bool   // stage actually completed (FABRIK_STAGE_COMPLETE detected)
	BlockedOnInput bool   // stage needs user input (FABRIK_BLOCKED_ON_INPUT detected)
	Duration       time.Duration
	CompletedAt    time.Time
	TurnsUsed      int
	MaxTurns       int
	CostUSD        float64
	Skipped        bool // synthetic fallback emit (deferred at emission site); InvocationObserver is authoritative (Skipped:false)
}

JobCompletedEvent is emitted when a worker goroutine finishes.

type JobStartedEvent

type JobStartedEvent struct {
	IssueNumber int
	Repo        string // "owner/repo" — empty for single-repo projects
	Title       string
	StageName   string
	IsComment   bool // true when processing a user comment, not a stage run
	StartedAt   time.Time
}

JobStartedEvent is emitted when a worker goroutine begins processing an item.

type LogEvent

type LogEvent struct {
	IssueNumber int
	Tag         string
	Message     string
}

LogEvent carries a single log line emitted by the engine.

type Model

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

Model is the bubbletea TUI model for Fabrik.

func New

func New(pollSeconds int, info ProjectInfo, pluginDir string, wakeCh chan struct{}, stopCh chan StopRequest, skillsStaleCount int, customWorkflow bool) Model

New creates an initial TUI model. pollSeconds is the configured polling interval. info provides project metadata displayed in the footer. pluginDir is the Fabrik plugin directory passed to claude --plugin-dir (may be empty). wakeCh is an optional channel the TUI sends on to wake the engine poll loop (may be nil). stopCh is an optional channel the TUI sends on to stop a specific in-flight issue (may be nil). skillsStaleCount is the number of plugin skill files that differ from embedded; 0 means up to date. customWorkflow is true when the three-way plugin comparison detects operator customizations.

func (Model) Init

func (m Model) Init() tea.Cmd

Init starts the 1-second tick.

func (Model) PendingReconcilePrompt

func (m Model) PendingReconcilePrompt() string

PendingReconcilePrompt returns the reconciliation prompt text set when the user selects [1] from the custom-workflow dialog, or an empty string if none. The caller (runTUI) should print this to stderr after p.Run() returns.

func (Model) Update

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

Update handles all messages (events and tea messages).

func (Model) View

func (m Model) View() string

View renders the full TUI.

type PollCompletedEvent

type PollCompletedEvent struct {
	ItemCount         int
	Dispatched        int
	GraphQLStats      RateLimitStats
	EffectiveInterval time.Duration
}

PollCompletedEvent is emitted when a poll cycle finishes dispatching.

type PollStartedEvent

type PollStartedEvent struct {
	Owner   string
	Repo    string
	Project int
}

PollStartedEvent is emitted at the beginning of each poll cycle.

type ProjectInfo

type ProjectInfo struct {
	CWD           string // display-ready CWD (home-relative or absolute)
	BoardTitle    string // GitHub Project board title; empty until startup board fetch succeeds
	BoardURL      string // https://github.com/{orgs|users}/{owner}/projects/{num}
	Repo          string // "owner/repo" — used as fallback for OSC 8 issue links when per-entry Repo is empty
	Version       string // optional version or module name of the monitored project; empty if unknown
	FabrikVersion string // fabrik binary version (e.g. "v1.2.3" or "dev(abc1234)")
}

ProjectInfo holds display metadata about the monitored project shown in the footer.

type ProjectMetaEvent

type ProjectMetaEvent struct {
	BoardTitle string // display name of the GitHub Project board
	BoardURL   string // https://github.com/{orgs|users}/{owner}/projects/{num}
}

ProjectMetaEvent is emitted once after the startup board fetch succeeds. It delivers the project board title and URL to the TUI for display in the footer.

type RateLimitAlertEvent

type RateLimitAlertEvent struct {
	Exhausted bool
	Reset     time.Time
}

RateLimitAlertEvent is emitted by the engine when the GraphQL rate-limit state transitions: Exhausted=true when a probe failure occurs while quota is low or zero; Exhausted=false when quota recovers above rateLimitHealthyThreshold. Reset is the time at which the quota is expected to reset (zero if unknown).

type RateLimitStats

type RateLimitStats struct {
	Limit     int
	Remaining int
	Reset     time.Time
}

RateLimitStats holds the minimal GraphQL rate limit data needed by the TUI.

type SkillsStaleEvent

type SkillsStaleEvent struct {
	Count int
}

SkillsStaleEvent is emitted once after startup when the on-disk plugin skill files differ from the embedded versions. Count is the number of diffing files; zero means skills are up to date (used to clear the header badge after upgrade).

type StageChangedEvent

type StageChangedEvent struct {
	Repo     string // "owner/repo" — empty for single-repo projects
	Number   int
	Title    string
	NewStage string // the new board column / stage name
}

StageChangedEvent is emitted when an issue moves to a new project-board stage. It allows the TUI to reactively update the displayed stage for an active item without waiting for the next full poll cycle.

type StopRequest added in v0.0.71

type StopRequest struct {
	IssueNumber int
	Repo        string // "owner/repo" — empty for single-repo projects
	StageName   string // stage name at time of stop, for the posted comment
}

StopRequest is sent by the TUI on the stopCh channel to ask the engine to cancel a specific in-flight issue and apply fabrik:paused.

type TickEvent

type TickEvent struct {
	At time.Time
}

TickEvent is emitted once per second by the TUI loop to drive timer updates.

type TurnProgressEvent

type TurnProgressEvent struct {
	IssueNumber int
	TurnsUsed   int
	MaxTurns    int // 0 means unlimited
}

TurnProgressEvent is emitted after each user event (logical turn start) during a Claude invocation. It carries the current live turn count and effective budget so the TUI can display a real-time turn counter for in-progress stages.

type WarningsPaneComponent added in v0.0.69

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

WarningsPaneComponent renders the persistent pre-flight warnings panel.

func NewWarningsPaneComponent added in v0.0.69

func NewWarningsPaneComponent() WarningsPaneComponent

NewWarningsPaneComponent creates a WarningsPaneComponent loaded from disk.

func (WarningsPaneComponent) Height added in v0.0.69

func (c WarningsPaneComponent) Height() int

Height returns the rendered height of the warnings panel.

func (WarningsPaneComponent) SelectedEntry added in v0.0.69

func (c WarningsPaneComponent) SelectedEntry() *warnings.Entry

SelectedEntry returns the currently selected entry, or nil if none.

func (*WarningsPaneComponent) SetFocused added in v0.0.69

func (c *WarningsPaneComponent) SetFocused(f bool)

SetFocused updates the focused state.

func (*WarningsPaneComponent) SetLayout added in v0.0.69

func (c *WarningsPaneComponent) SetLayout(width, availableH int)

SetLayout updates the available width and height.

func (WarningsPaneComponent) Update added in v0.0.69

func (c WarningsPaneComponent) Update(msg tea.Msg) (Component, tea.Cmd)

Update handles messages for the warnings pane.

func (WarningsPaneComponent) View added in v0.0.69

func (c WarningsPaneComponent) View(width int) string

View renders the warnings panel.

type WebhookStatusEvent

type WebhookStatusEvent struct {
	State       string         // WebhookHealthState as string to avoid import cycle
	EventCounts map[string]int // per-event-type received counts
}

WebhookStatusEvent is emitted when the webhook stream health state changes or when new events are received. State is one of: "starting_up", "healthy", "unhealthy", or "" (webhook mode disabled).

Jump to

Keyboard shortcuts

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