tui

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package tui hosts gskill's interactive surfaces, rendered over the app service layer and refusing to launch without a TTY: the dashboard (a bubbles table stacked over a glamour SKILL.md preview viewport), the guided onboarding wizard (a step state machine whose agents and version steps are huh forms, while the source and skill-picker steps stay custom where the keyboard contract demands it), and the bounded, filterable multi-select skill picker. One Theme feeds every surface — and the CLI's styled output — so the looks cannot drift apart.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AccentColor added in v0.3.0

func AccentColor() lipgloss.AdaptiveColor

AccentColor returns the theme's adaptive accent for components that need a color rather than a style.

func InstallCounterLine added in v0.3.2

func InstallCounterLine(sum app.InstallSummary) string

InstallCounterLine renders the non-zero counters unstyled ("" when all are zero); the glyphs are plain text so the line reads identically without color (FR-027). The plain CLI consumes this directly.

func InstallHeadline added in v0.3.2

func InstallHeadline(sum app.InstallSummary) string

InstallHeadline maps a run's outcome onto the summary headline. One copy of this user-facing contract text serves the TUI and the plain CLI.

func OrDash added in v0.3.2

func OrDash(s string) string

OrDash substitutes — for an empty untrusted value, sanitizing otherwise: the single FR-014 placeholder rule shared by every renderer (TUI and CLI).

func PhaseTitle added in v0.3.2

func PhaseTitle(p app.InstallPhase) string

PhaseTitle returns the display text for a phase.

func PlannedTitle added in v0.3.2

func PlannedTitle(action string) string

PlannedTitle returns the display text for a dry-run planned action; unknown actions render their wire value so a new action is never hidden. Shared by the TUI table and the plain CLI renderer.

func Preview

func Preview(markdown string, width int) (string, error)

Preview renders SKILL.md markdown for terminal display, sanitizing untrusted escape sequences before rendering so remote content cannot inject terminal control codes (FR-045).

func Run

func Run(rows []SkillRow, isTTY bool) error

Run launches the interactive dashboard. It refuses to start without a TTY, returning a usage error that points at the equivalent CLI commands (FR-041).

func Sanitize

func Sanitize(s string) string

Sanitize strips terminal control sequences and non-printable control characters from untrusted content before it is rendered, defending against terminal-injection via remote SKILL.md content (FR-045). Newlines and tabs are preserved.

func SelectSkills added in v0.1.0

func SelectSkills(items []SkillItem, isTTY bool) ([]int, error)

SelectSkills runs the interactive multi-select picker and returns the indices of the chosen skills. It refuses to start without a TTY. A cancelled picker returns an empty selection and a nil error (the caller treats that as "no skill selected").

Types

type InstallProgress added in v0.3.2

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

InstallProgress renders a run's live progress. It is a value type in the Bubble Tea style: Observe and SetWidth return the updated copy.

func NewInstallProgress added in v0.3.2

func NewInstallProgress() InstallProgress

NewInstallProgress builds the component with the shared theme and the same accent-filled bar construction the CLI's fetch renderer uses.

func (InstallProgress) Done added in v0.3.2

func (m InstallProgress) Done() bool

Done reports whether every skill has a terminal result.

func (InstallProgress) Observe added in v0.3.2

Observe folds one lifecycle event into the model. Run-scoped events (SkillName == "") never count toward progress or replace the current skill (contract guarantee 6).

func (InstallProgress) Percent added in v0.3.2

func (m InstallProgress) Percent() int

Percent is the terminal-driven progress percentage (0 for an empty run).

func (InstallProgress) SetWidth added in v0.3.2

func (m InstallProgress) SetWidth(w int) InstallProgress

SetWidth adapts the layout (and bar width) to the terminal width.

func (InstallProgress) View added in v0.3.2

func (m InstallProgress) View() string

View renders the wide or compact layout depending on the last SetWidth.

type InstallResults added in v0.3.2

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

InstallResults renders the result screen. Value semantics, Bubble Tea style: Update and SetSize return the modified copy.

func NewInstallResults added in v0.3.2

func NewInstallResults(results []app.LockSkillResult) InstallResults

NewInstallResults aggregates the run's results and selects the table rows: unsuccessful entries only (clarification #2), or every entry with its planned action on a dry run (FR-017 exception).

func (InstallResults) Cursor added in v0.3.2

func (m InstallResults) Cursor() int

Cursor exposes the selected row index for tests and hosts.

func (InstallResults) HasRows added in v0.3.2

func (m InstallResults) HasRows() bool

HasRows reports whether the table has anything to show.

func (InstallResults) Hints added in v0.3.2

func (m InstallResults) Hints() string

Hints returns the footer hint line for the current mode.

func (InstallResults) SetSize added in v0.3.2

func (m InstallResults) SetSize(w, h int) InstallResults

SetSize adapts the table to the terminal. Unchanged dimensions are a no-op so resize-event bursts don't rebuild identical tables.

func (InstallResults) Summary added in v0.3.2

func (m InstallResults) Summary() app.InstallSummary

Summary exposes the aggregated counters.

func (InstallResults) Update added in v0.3.2

func (m InstallResults) Update(msg tea.KeyMsg) (InstallResults, bool)

Update handles the result screen's keys (FR-018). exit=true means the host should leave the screen.

func (InstallResults) View added in v0.3.2

func (m InstallResults) View() string

View renders the summary plus the table or the selected row's detail.

type LockWizardConfig added in v0.3.0

type LockWizardConfig struct {
	LockPath string
	Skills   []LockWizardSkill
	Phases   LockWizardPhases
}

LockWizardConfig configures a lock-install wizard run.

type LockWizardOutcome added in v0.3.0

type LockWizardOutcome struct {
	Cancelled bool // user quit before approving: zero writes (CodeCancelled)
	NoAgents  bool // nothing to select: zero writes (CodeUnsupportedAgent)
	Executed  bool
	AgentIDs  []string
	Result    app.InstallFromLockResult
	Err       error
}

LockWizardOutcome is what a finished flow reports back to the CLI.

func RunLockWizard added in v0.3.0

func RunLockWizard(ctx context.Context, cfg LockWizardConfig, isTTY bool) (LockWizardOutcome, error)

RunLockWizard runs the lock-install flow on the terminal. It refuses to start without a TTY (the CLI gates on interactivity before calling this).

type LockWizardPhases added in v0.3.0

type LockWizardPhases struct {
	Agents  func(context.Context) ([]app.AgentChoice, error)
	Execute func(context.Context, []string, func(app.InstallProgressEvent)) (app.InstallFromLockResult, error)
}

LockWizardPhases are the app-layer use-cases the flow drives, injected by the CLI so the wizard stays view-pure and unit-testable. Execute receives the wizard's progress callback so the run streams install lifecycle events into the live progress view (spec 014 US1).

type LockWizardSkill added in v0.3.0

type LockWizardSkill struct {
	Name   string
	Source string
	// Agents is the entry's currently recorded gskill.agents (nil for a raw,
	// unmanaged entry), used to compute the kept/added/removed plan the
	// preview screen shows before the user confirms (spec 013 FR-006).
	Agents []string
}

LockWizardSkill is one lock entry shown in the flow.

type Session added in v0.3.0

type Session struct {
	Source         string
	SourceAnswered bool

	Selected       []discovery.DiscoveredSkill
	SkillsAnswered bool

	// Requested version pin (one of Version/RefSpec/Commit), plus a display
	// label for the preview.
	Version         string
	RefSpec         string
	Commit          string
	VersionLabel    string
	VersionAnswered bool

	AgentIDs       []string
	AgentsAnswered bool

	// ApprovalAnswered maps --yes: the approval step auto-approves a
	// conflict-free plan (it never bypasses a conflicted one, FR-016).
	ApprovalAnswered bool
}

Session is the user's answers accumulated across steps (data-model.md). The *Answered flags mark answers supplied on the command line (FR-004): those steps are skipped, both forward and when navigating back.

type SkillItem added in v0.1.0

type SkillItem struct {
	ID          string
	DisplayName string
	Description string
	RepoPath    string
	Valid       bool
	// InvalidReason is the first error-severity diagnostic for an invalid
	// skill, shown when the cursor is on its row (FR-011).
	InvalidReason string
}

SkillItem is one selectable skill in the interactive picker.

type SkillRow

type SkillRow struct {
	Name     string
	Version  string
	Source   string
	Status   string
	Markdown string // SKILL.md content for the preview pane
}

SkillRow is one entry shown in the dashboard.

type Theme added in v0.3.0

type Theme struct {
	Title    lipgloss.Style // step/screen headings
	Subtitle lipgloss.Style // secondary heading line
	Accent   lipgloss.Style // source names, counts, selections
	Hint     lipgloss.Style // keyboard hint footers
	Cursor   lipgloss.Style // the "❯" row cursor
	Selected lipgloss.Style // chosen items / active option
	Invalid  lipgloss.Style // non-selectable rows
	Success  lipgloss.Style // confirmation lines
	Warning  lipgloss.Style // degraded notes, warnings
	Error    lipgloss.Style // failures, conflicts
	Badge    lipgloss.Style // step-position badge ("step 2/6")

	Border      lipgloss.Style // panel borders
	TableHeader lipgloss.Style // column header rows
}

Theme is the package-wide visual vocabulary (design 2026-07-08). Every color is a lipgloss.AdaptiveColor so light and dark terminals both read well, and lipgloss's automatic color-profile detection (via termenv) degrades to reduced palettes or plain text on NO_COLOR/dumb terminals — no capability probing of our own. One Theme feeds every surface: the wizard (directly and via Huh()), the dashboard (via TableStyles()), and the CLI's styled output, so the surfaces cannot drift apart.

func DefaultTheme added in v0.3.0

func DefaultTheme() Theme

DefaultTheme returns the indigo-minimal palette.

func (Theme) HealthCell added in v0.3.0

func (t Theme) HealthCell(state string) string

HealthCell renders an active-layer or agent-target health state with its semantic glyph and color (internal/active and internal/app/health.go vocabularies). Unknown states render plain so a new state is never hidden or miscolored.

func (Theme) Huh added in v0.3.0

func (t Theme) Huh() *huh.Theme

Huh adapts the theme for huh forms (the agents and version steps), mapping the wizard vocabulary onto huh's FieldStyles.

func (Theme) InstallStatusCell added in v0.3.2

func (t Theme) InstallStatusCell(status string) string

InstallStatusCell renders an install-result status with its semantic glyph and color (spec 014 status vocabulary, internal/app/installprogress.go). State is never communicated by color alone — the textual status is always part of the cell — and unknown statuses render plain so a new status is never hidden or miscolored.

func (Theme) Panel added in v0.3.0

func (t Theme) Panel() lipgloss.Style

Panel returns a thin bordered panel style in the theme's border color.

func (Theme) StatusCell added in v0.3.0

func (t Theme) StatusCell(status string) string

StatusCell renders a drift status with its semantic glyph and color (internal/integrity/driftstatus.go vocabulary). Unknown statuses render plain so a new status is never hidden or miscolored.

func (Theme) TableStyles added in v0.3.0

func (t Theme) TableStyles() table.Styles

TableStyles adapts the theme for bubbles/table: subtle bold headers over a thin rule and a foreground-accent (not background-highlight) cursor row, per the indigo-minimal design. Cell keeps bubbles' default Padding(0,1) — Header carries the same padding, so replacing Cell with an unpadded style would shift every header right of its column and delete the gutters.

type WizardConfig added in v0.3.0

type WizardConfig struct {
	Session Session
	Phases  WizardPhases
	// SourceSuggestions are configured sources offered as a pick list on the
	// source step (US5), above the free-form input.
	SourceSuggestions []string
}

WizardConfig configures a wizard run.

type WizardOutcome added in v0.3.0

type WizardOutcome struct {
	Cancelled bool
	Executed  bool
	Result    app.AddResult
	Err       error
}

WizardOutcome is what a finished wizard reports back to the CLI.

func RunWizard added in v0.3.0

func RunWizard(ctx context.Context, cfg WizardConfig, isTTY bool) (WizardOutcome, error)

RunWizard runs the guided flow on the terminal. It refuses to start without a TTY (FR-003; the CLI gates on interactivity before calling this).

type WizardPhases added in v0.3.0

type WizardPhases struct {
	Discover func(context.Context) (app.DiscoverResult, error)
	Versions func(context.Context) (app.VersionList, error)
	Agents   func(context.Context) ([]app.AgentChoice, error)
	Plan     func(context.Context, *Session) (app.InstallPlan, error)
	Execute  func(context.Context, app.InstallPlan, func(app.InstallProgressEvent)) (app.AddResult, error)
	// ValidateSource vets typed source input on the source step (US5).
	ValidateSource func(string) error
	// ResolveSelection, when set, resolves flag-given skill selectors against
	// the discovery result; the selection step is then skipped (FR-004).
	ResolveSelection func(context.Context, app.DiscoverResult) ([]discovery.DiscoveredSkill, error)
	// SourceChosen, when set, is called with the source accepted on the
	// source step, before discovery starts — the CLI's phase closures read
	// the chosen source through it (US5).
	SourceChosen func(string)
}

WizardPhases are the app-layer use-cases the wizard drives, injected by the CLI so the wizard stays view-pure and unit-testable (contracts/app-phases.md). Versions and Agents are optional; a nil closure skips that step.

Jump to

Keyboard shortcuts

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