ui

package
v0.2.26 Latest Latest
Warning

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

Go to latest
Published: Mar 4, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Overview

Package ui provides the terminal user interface.

Package ui provides the terminal user interface.

Index

Constants

View Source
const (
	// Unicode icons
	IconBacklogUnicode    = "◦"
	IconInProgressUnicode = "▶"
	IconBlockedUnicode    = "⚠"
	IconDoneUnicode       = "✓"
	IconPinUnicode        = "📌"
	IconWarningUnicode    = "⚠"
	IconArrowUpUnicode    = "↑"
	IconArrowDownUnicode  = "↓"
	IconArrowLeftUnicode  = "←"
	IconArrowRightUnicode = "→"
	IconShiftUpUnicode    = "⇧↑"
	IconShiftDownUnicode  = "⇧↓"

	// ASCII fallbacks
	IconBacklogASCII      = "o"
	IconInProgressASCII   = ">"
	IconProcessingASCII   = "~"
	IconBlockedASCII      = "!"
	IconDoneASCII         = "*"
	IconPinASCII          = "P"
	IconWarningASCII      = "!"
	IconArrowUpASCII      = "^"
	IconArrowDownASCII    = "v"
	IconArrowLeftASCII    = "<"
	IconArrowRightASCII   = ">"
	IconShiftUpASCII      = "^^"
	IconShiftDownASCII    = "vv"
	IconProcessingUnicode = "⋯"
	IconDefaultUnicode    = "·"
	IconDefaultASCII      = "."
)

Icon constants - Unicode and ASCII versions

View Source
const MobileWidthThreshold = 80

MobileWidthThreshold is the minimum width for showing all columns. Below this, only the selected column is shown.

Variables

View Source
var (
	// Primary colors
	ColorPrimary   = lipgloss.Color("#61AFEF") // Soft blue (OneDark default)
	ColorSecondary = lipgloss.Color("#56B6C2") // Cyan
	ColorSuccess   = lipgloss.Color("#98C379") // Green
	ColorWarning   = lipgloss.Color("#E5C07B") // Yellow
	ColorError     = lipgloss.Color("#E06C75") // Red
	ColorDangerous = lipgloss.Color("#E06C75") // Red (same as error, for dangerous mode indicator)
	ColorMuted     = lipgloss.Color("#5C6370") // Gray

	// Status colors
	ColorInProgress = lipgloss.Color("#D19A66") // Orange
	ColorDone       = lipgloss.Color("#98C379") // Green
	ColorBlocked    = lipgloss.Color("#E06C75") // Red

	// Default project colors palette - used when no color is set
	// These are distinct, visually pleasing colors for project labels
	DefaultProjectColors = []string{
		"#C678DD",
		"#61AFEF",
		"#56B6C2",
		"#98C379",
		"#E5C07B",
		"#E06C75",
		"#D19A66",
		"#ABB2BF",
	}

	// Type colors (fixed, not theme-dependent)
	ColorCode     = lipgloss.Color("#C678DD") // Purple
	ColorWriting  = lipgloss.Color("#E5C07B") // Yellow
	ColorThinking = lipgloss.Color("#56B6C2") // Cyan
)

Colors - these are updated by refreshStyles() when theme changes

View Source
var (
	// Text styles
	Bold           = lipgloss.NewStyle().Bold(true)
	Dim            = lipgloss.NewStyle().Foreground(ColorMuted)
	Title          = lipgloss.NewStyle().Bold(true).Foreground(ColorPrimary)
	Subtitle       = lipgloss.NewStyle().Foreground(ColorSecondary)
	Success        = lipgloss.NewStyle().Foreground(ColorSuccess)
	Warning        = lipgloss.NewStyle().Foreground(ColorWarning)
	Error          = lipgloss.NewStyle().Foreground(ColorError)
	AttachmentChip = lipgloss.NewStyle().
					Border(lipgloss.RoundedBorder()).
					BorderForeground(ColorMuted).
					Foreground(ColorMuted).
					Padding(0, 1)
	AttachmentChipSelected = lipgloss.NewStyle().
							Border(lipgloss.RoundedBorder()).
							BorderForeground(ColorPrimary).
							Foreground(ColorPrimary).
							Bold(true).
							Padding(0, 1)

	// Status badges
	StatusInProgress = lipgloss.NewStyle().
						Foreground(ColorInProgress).
						SetString("⋯")
	StatusDone = lipgloss.NewStyle().
				Foreground(ColorDone).
				SetString("✓")
	StatusBlocked = lipgloss.NewStyle().
					Foreground(ColorBlocked).
					SetString("!")

	// Box styles
	Box = lipgloss.NewStyle().
		Border(lipgloss.RoundedBorder()).
		BorderForeground(ColorMuted).
		Padding(0, 1)

	FocusedBox = lipgloss.NewStyle().
				Border(lipgloss.RoundedBorder()).
				BorderForeground(ColorPrimary).
				Padding(0, 1)

	// List item styles
	ListItem = lipgloss.NewStyle().
				PaddingLeft(2)

	SelectedListItem = lipgloss.NewStyle().
						PaddingLeft(2).
						Foreground(ColorPrimary).
						Bold(true)

	// Help bar
	HelpBar = lipgloss.NewStyle().
			Foreground(ColorMuted).
			Padding(1, 0)

	HelpKey = lipgloss.NewStyle().
			Foreground(ColorSecondary).
			Bold(true)

	HelpDesc = lipgloss.NewStyle().
				Foreground(ColorMuted)

	// Header
	Header = lipgloss.NewStyle().
			Bold(true).
			Foreground(ColorPrimary).
			Padding(0, 1).
			MarginBottom(1)

	// Tag styles
	ProjectTag = lipgloss.NewStyle().
				Foreground(ColorSecondary).
				Bold(true)

	TypeTag = lipgloss.NewStyle().
			Foreground(ColorMuted).
			Italic(true)
)

Base styles - these are updated by refreshStyles() when theme changes

View Source
var (
	ColorPROpen    = lipgloss.Color("#98C379") // Green - ready to merge
	ColorPRDraft   = lipgloss.Color("#5C6370") // Gray - draft
	ColorPRMerged  = lipgloss.Color("#C678DD") // Purple - merged
	ColorPRClosed  = lipgloss.Color("#E06C75") // Red - closed
	ColorPRPending = lipgloss.Color("#E5C07B") // Yellow - checks running
	ColorPRFailing = lipgloss.Color("#E06C75") // Red - checks failing
)

PR status colors

View Source
var (
	ColorDiffAdd    = lipgloss.Color("#98C379") // Green for additions (bright)
	ColorDiffDel    = lipgloss.Color("#E06C75") // Red for deletions (bright)
	ColorDiffAddDim = lipgloss.Color("#5C7A4A") // Dim green for unselected
	ColorDiffDelDim = lipgloss.Color("#8B4C52") // Dim red for unselected
)

Diff stat colors (git-style green/red)

View Source
var BuiltinThemes = map[string]Theme{
	"onedark":    OneDarkTheme,
	"default":    DefaultTheme,
	"nord":       NordTheme,
	"gruvbox":    GruvboxTheme,
	"catppuccin": CatppuccinTheme,
	"dracula":    DraculaTheme,
}

BuiltinThemes contains all built-in themes.

View Source
var CatppuccinTheme = Theme{
	Name: "catppuccin",

	Primary:   "#CBA6F7",
	Secondary: "#89DCEB",
	Muted:     "#6C7086",

	Success: "#A6E3A1",
	Warning: "#F9E2AF",
	Error:   "#F38BA8",

	InProgress: "#FAB387",
	Done:       "#A6E3A1",
	Blocked:    "#F38BA8",
	Backlog:    "#6C7086",

	CardBg:         "#313244",
	CardFg:         "#CDD6F4",
	CardBorder:     "#45475A",
	CardBorderHi:   "#CBA6F7",
	ColumnBorder:   "#45475A",
	ColumnBorderHi: "#CBA6F7",
}

CatppuccinTheme is inspired by Catppuccin Mocha - soothing pastel colors.

View Source
var DefaultTheme = Theme{
	Name: "default",

	Primary:   "#7C3AED",
	Secondary: "#06B6D4",
	Muted:     "#6B7280",

	Success: "#10B981",
	Warning: "#F59E0B",
	Error:   "#EF4444",

	InProgress: "#9A9463",
	Done:       "#10B981",
	Blocked:    "#EF4444",
	Backlog:    "#6B7280",

	CardBg:         "#333333",
	CardFg:         "#FFFFFF",
	CardBorder:     "#6B7280",
	CardBorderHi:   "#7C3AED",
	ColumnBorder:   "#6B7280",
	ColumnBorderHi: "#7C3AED",
}

DefaultTheme is the original purple-heavy theme.

View Source
var DraculaTheme = Theme{
	Name: "dracula",

	Primary:   "#BD93F9",
	Secondary: "#8BE9FD",
	Muted:     "#6272A4",

	Success: "#50FA7B",
	Warning: "#F1FA8C",
	Error:   "#FF5555",

	InProgress: "#FFB86C",
	Done:       "#50FA7B",
	Blocked:    "#FF5555",
	Backlog:    "#6272A4",

	CardBg:         "#44475A",
	CardFg:         "#F8F8F2",
	CardBorder:     "#6272A4",
	CardBorderHi:   "#BD93F9",
	ColumnBorder:   "#6272A4",
	ColumnBorderHi: "#BD93F9",
}

DraculaTheme is inspired by the Dracula color scheme - vibrant purples and pinks.

View Source
var GruvboxTheme = Theme{
	Name: "gruvbox",

	Primary:   "#83A598",
	Secondary: "#B8BB26",
	Muted:     "#665C54",

	Success: "#B8BB26",
	Warning: "#FABD2F",
	Error:   "#FB4934",

	InProgress: "#FE8019",
	Done:       "#B8BB26",
	Blocked:    "#FB4934",
	Backlog:    "#665C54",

	CardBg:         "#3C3836",
	CardFg:         "#EBDBB2",
	CardBorder:     "#504945",
	CardBorderHi:   "#83A598",
	ColumnBorder:   "#504945",
	ColumnBorderHi: "#83A598",
}

GruvboxTheme is inspired by the Gruvbox color scheme - retro, earthy tones.

View Source
var NordTheme = Theme{
	Name: "nord",

	Primary:   "#88C0D0",
	Secondary: "#81A1C1",
	Muted:     "#4C566A",

	Success: "#A3BE8C",
	Warning: "#EBCB8B",
	Error:   "#BF616A",

	InProgress: "#D08770",
	Done:       "#A3BE8C",
	Blocked:    "#BF616A",
	Backlog:    "#4C566A",

	CardBg:         "#3B4252",
	CardFg:         "#ECEFF4",
	CardBorder:     "#4C566A",
	CardBorderHi:   "#88C0D0",
	ColumnBorder:   "#4C566A",
	ColumnBorderHi: "#88C0D0",
}

NordTheme is inspired by the Nord color palette - arctic, bluish tones.

View Source
var OneDarkTheme = Theme{
	Name: "onedark",

	Primary:   "#61AFEF",
	Secondary: "#56B6C2",
	Muted:     "#5C6370",

	Success: "#98C379",
	Warning: "#E5C07B",
	Error:   "#E06C75",

	InProgress: "#D19A66",
	Done:       "#98C379",
	Blocked:    "#E06C75",
	Backlog:    "#5C6370",

	CardBg:         "#3E4451",
	CardFg:         "#ABB2BF",
	CardBorder:     "#3E4451",
	CardBorderHi:   "#61AFEF",
	ColumnBorder:   "#3E4451",
	ColumnBorderHi: "#61AFEF",
}

OneDarkTheme is inspired by Atom's One Dark theme - subtle and easy on the eyes.

Functions

func CloseLogger

func CloseLogger()

CloseLogger closes the log file.

func GetDefaultProjectColor

func GetDefaultProjectColor(index int) string

GetDefaultProjectColor returns a default color for a project based on its index. Used when a project doesn't have a color set.

func GetThemeBorderColors

func GetThemeBorderColors() (normal, highlighted lipgloss.Color)

GetThemeBorderColors returns border colors from the current theme.

func GetThemeCardColors

func GetThemeCardColors() (bg, fg lipgloss.Color)

GetThemeCardColors returns card-specific colors from the current theme.

func Icon

func Icon(unicodeIcon, asciiIcon string) string

Icon returns the appropriate icon based on terminal Unicode support.

func IconArrowDown

func IconArrowDown() string

IconArrowDown returns the down arrow.

func IconArrowLeft

func IconArrowLeft() string

IconArrowLeft returns the left arrow.

func IconArrowRight

func IconArrowRight() string

IconArrowRight returns the right arrow.

func IconArrowUp

func IconArrowUp() string

IconArrowUp returns the up arrow.

func IconBacklog

func IconBacklog() string

IconBacklog returns the backlog status icon.

func IconBlocked

func IconBlocked() string

IconBlocked returns the blocked status icon.

func IconDefault

func IconDefault() string

IconDefault returns the default/unknown status icon.

func IconDone

func IconDone() string

IconDone returns the done status icon.

func IconInProgress

func IconInProgress() string

IconInProgress returns the in-progress status icon.

func IconPin

func IconPin() string

IconPin returns the pin icon.

func IconProcessing

func IconProcessing() string

IconProcessing returns the processing status icon.

func IconShiftDown

func IconShiftDown() string

IconShiftDown returns the shift+down icon.

func IconShiftUp

func IconShiftUp() string

IconShiftUp returns the shift+up icon.

func IsGlobalDangerousMode

func IsGlobalDangerousMode() bool

IsGlobalDangerousMode returns true if the system is running in global dangerous mode. This is set by the WORKTREE_DANGEROUS_MODE=1 environment variable.

func ListThemes

func ListThemes() []string

ListThemes returns the names of all built-in themes (sorted).

func LoadProjectColors

func LoadProjectColors(database *db.DB)

LoadProjectColors loads all project colors from the database into the cache.

func LoadThemeFromDB

func LoadThemeFromDB(getSetting func(string) (string, error))

LoadThemeFromDB loads and applies the saved theme from the database. If no theme is saved or the theme is invalid, OneDark is used as the default.

func LogPath

func LogPath() string

LogPath returns the path to the log file.

func PRDiffStats

func PRDiffStats(pr *github.PRInfo) string

PRDiffStats returns a formatted diff stats string like "+123 -45" with dim colors. Use this for unselected items. Returns empty string if no changes or PR is nil.

func PRDiffStatsBright

func PRDiffStatsBright(pr *github.PRInfo) string

PRDiffStatsBright returns diff stats with bright colors (for selected items).

func PRDiffStatsPlain

func PRDiffStatsPlain(pr *github.PRInfo) string

PRDiffStatsPlain returns diff stats without color (for selected items with inverted bg).

func PRStatusBadge

func PRStatusBadge(pr *github.PRInfo) string

PRStatusBadge returns a styled badge for a PR status.

func PRStatusDescription

func PRStatusDescription(pr *github.PRInfo) string

PRStatusDescription returns a human-readable description of PR status.

func PRStatusIcon

func PRStatusIcon(pr *github.PRInfo) string

PRStatusIcon returns just the icon character for a PR status (without styling). This is useful for creating consistently-sized badges with different color schemes.

func ProjectColor

func ProjectColor(project string) lipgloss.Color

ProjectColor returns the color for a project. It uses the cached color from the database, or falls back to a default color.

func RingBell

func RingBell()

RingBell sends the BEL character (\a) to the terminal to trigger an audible bell. It writes directly to /dev/tty to bypass any stdout buffering that might occur when running inside a TUI framework like Bubble Tea.

func SetProjectColor

func SetProjectColor(project, color string)

SetProjectColor sets the color for a single project.

func SetProjectColors

func SetProjectColors(colors map[string]string)

SetProjectColors updates the project color cache with colors from the database. This should be called when projects are loaded.

func SetTheme

func SetTheme(name string) error

SetTheme sets the current theme by name.

func SetThemeFromJSON

func SetThemeFromJSON(data string) error

SetThemeFromJSON sets a custom theme from JSON.

func StatusColor

func StatusColor(status string) lipgloss.Color

StatusColor returns the background color for a status.

func StatusIcon

func StatusIcon(status string) string

StatusIcon returns the icon for a given status.

func StatusStyle

func StatusStyle(status string) lipgloss.Style

StatusStyle returns the style for a given status.

func SupportsUnicode

func SupportsUnicode() bool

SupportsUnicode returns true if the terminal likely supports Unicode characters. It checks LANG, LC_ALL, and LC_CTYPE environment variables for UTF-8 indicators.

func TaskIndexFromShortcut

func TaskIndexFromShortcut(shortcut string) int

TaskIndexFromShortcut converts a shortcut string to a 1-indexed visible task index. Returns 0 if the shortcut is invalid.

func TaskShortcutHint

func TaskShortcutHint(visibleIndex int) string

TaskShortcutHint returns the keyboard shortcut hint for a visible task. Tasks 1-9 use single digits "1"-"9". Tasks 10-18 use double digits "11", "22", "33", etc. Returns empty string for tasks beyond 18.

func ThemeToJSON

func ThemeToJSON(theme Theme) (string, error)

ThemeToJSON serializes a theme to JSON.

Types

type AppModel

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

AppModel is the main application model.

func NewAppModel

func NewAppModel(database *db.DB, exec *executor.Executor, workingDir string, version ...string) *AppModel

NewAppModel creates a new application model.

func (*AppModel) DumpDebugStateToFile

func (m *AppModel) DumpDebugStateToFile(path string) error

DumpDebugStateToFile writes the current debug state to a file.

func (*AppModel) GenerateDebugState

func (m *AppModel) GenerateDebugState() DebugState

GenerateDebugState creates a snapshot of the current application state.

func (*AppModel) Init

func (m *AppModel) Init() tea.Cmd

Init initializes the model.

func (*AppModel) SetDebugStatePath

func (m *AppModel) SetDebugStatePath(path string)

SetDebugStatePath sets the path for dumping debug state.

func (*AppModel) SetTasks

func (m *AppModel) SetTasks(tasks []*db.Task)

SetTasks sets the tasks for the model (useful for debugging/testing).

func (*AppModel) Update

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

Update handles messages.

func (*AppModel) View

func (m *AppModel) View() string

View renders the current view.

type AttachmentsModel

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

AttachmentsModel displays and manages task attachments.

func NewAttachmentsModel

func NewAttachmentsModel(task *db.Task, database *db.DB, width, height int) *AttachmentsModel

NewAttachmentsModel creates a new attachments view.

func (*AttachmentsModel) AddFile

func (m *AttachmentsModel) AddFile(path string) tea.Cmd

AddFile adds a file to the task's attachments.

func (*AttachmentsModel) Init

func (m *AttachmentsModel) Init() tea.Cmd

Init initializes the model.

func (*AttachmentsModel) Update

func (m *AttachmentsModel) Update(msg tea.Msg) (*AttachmentsModel, tea.Cmd)

Update handles messages.

func (*AttachmentsModel) View

func (m *AttachmentsModel) View() string

View renders the attachments view.

type CommandPaletteModel

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

CommandPaletteModel represents the Command+P task switcher and AI command input.

func NewCommandPaletteModel

func NewCommandPaletteModel(database *db.DB, tasks []*db.Task, width, height int) *CommandPaletteModel

NewCommandPaletteModel creates a new command palette model.

func (*CommandPaletteModel) Init

func (m *CommandPaletteModel) Init() tea.Cmd

Init initializes the command palette.

func (*CommandPaletteModel) IsAICommandRequest

func (m *CommandPaletteModel) IsAICommandRequest() bool

IsAICommandRequest returns true if the user pressed Enter with text that should go to AI.

func (*CommandPaletteModel) IsCancelled

func (m *CommandPaletteModel) IsCancelled() bool

IsCancelled returns true if the user cancelled the palette.

func (*CommandPaletteModel) Projects

func (m *CommandPaletteModel) Projects() []*db.Project

Projects returns the available projects for AI context.

func (*CommandPaletteModel) RawInput

func (m *CommandPaletteModel) RawInput() string

RawInput returns the raw input text for AI command processing.

func (*CommandPaletteModel) SelectedTask

func (m *CommandPaletteModel) SelectedTask() *db.Task

SelectedTask returns the selected task, or nil if cancelled.

func (*CommandPaletteModel) SetSize

func (m *CommandPaletteModel) SetSize(width, height int)

SetSize updates the command palette dimensions.

func (*CommandPaletteModel) Update

Update handles messages.

func (*CommandPaletteModel) View

func (m *CommandPaletteModel) View() string

View renders the command palette.

type DebugColumn

type DebugColumn struct {
	Name   string      `json:"name"`
	Tasks  []DebugTask `json:"tasks"`
	Focus  bool        `json:"is_focused"`
	Status string      `json:"status"`
}

type DebugDashboard

type DebugDashboard struct {
	Columns       []DebugColumn `json:"columns"`
	FocusedColumn int           `json:"focused_column"`
	SelectedTask  int64         `json:"selected_task_id,omitempty"`
}

type DebugDetail

type DebugDetail struct {
	TaskID   int64  `json:"task_id"`
	Title    string `json:"title"`
	Status   string `json:"status"`
	Project  string `json:"project"`
	Focused  bool   `json:"is_focused"`
	Logs     int    `json:"log_count"`
	HasPanes bool   `json:"has_panes"`
}

type DebugFilter

type DebugFilter struct {
	Active bool   `json:"active"`
	Text   string `json:"text"`
}

type DebugForm

type DebugForm struct {
	Title        string            `json:"title"`
	Fields       map[string]string `json:"fields"`
	FocusedField string            `json:"focused_field"`
	Project      string            `json:"project"`
	Type         string            `json:"type"`
	Executor     string            `json:"executor"`
}

type DebugModals

type DebugModals struct {
	ActiveConfirm string `json:"active_confirm,omitempty"` // "delete", "close", "archive", "quit", etc.
}

type DebugNotification

type DebugNotification struct {
	Message string `json:"message"`
	TaskID  int64  `json:"task_id,omitempty"`
}

type DebugSize

type DebugSize struct {
	Width  int `json:"width"`
	Height int `json:"height"`
}

type DebugState

type DebugState struct {
	View         string             `json:"view"`
	Size         DebugSize          `json:"size"`
	Dashboard    *DebugDashboard    `json:"dashboard,omitempty"`
	Detail       *DebugDetail       `json:"detail,omitempty"`
	Form         *DebugForm         `json:"form,omitempty"`
	Modals       *DebugModals       `json:"modals,omitempty"`
	Filter       *DebugFilter       `json:"filter,omitempty"`
	Notification *DebugNotification `json:"notification,omitempty"`
	Timestamp    time.Time          `json:"timestamp"`
}

DebugState represents the application state as a "Text DOM" for AI agents.

type DebugTask

type DebugTask struct {
	ID       int64  `json:"id"`
	Title    string `json:"title"`
	Status   string `json:"status"`
	Project  string `json:"project"`
	Selected bool   `json:"is_selected"`
	Pinned   bool   `json:"is_pinned,omitempty"`
}

type DetailModel

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

DetailModel represents the task detail view.

func NewDetailModel

func NewDetailModel(t *db.Task, database *db.DB, exec *executor.Executor, width, height int, focusExecutor bool) (*DetailModel, tea.Cmd)

NewDetailModel creates a new detail model. Returns the model and an optional command for async pane setup. If focusExecutor is true, the executor pane will be focused after panes are joined.

func (*DetailModel) ClaudePaneID

func (m *DetailModel) ClaudePaneID() string

ClaudePaneID returns the tmux pane ID where Claude is running.

func (*DetailModel) Cleanup

func (m *DetailModel) Cleanup()

Cleanup should be called when leaving detail view. It saves the current pane height before breaking the panes.

func (*DetailModel) CleanupWithoutSaving

func (m *DetailModel) CleanupWithoutSaving()

CleanupWithoutSaving cleans up panes without saving the height. Use this during task transitions (prev/next) to avoid rounding errors that accumulate with each transition and cause the pane to shrink.

func (*DetailModel) ClearPaneState

func (m *DetailModel) ClearPaneState()

ClearPaneState clears the cached pane state without breaking panes. Use this when the tmux window has been recreated externally (e.g., dangerous mode toggle).

func (*DetailModel) GetServerURL

func (m *DetailModel) GetServerURL() string

GetServerURL returns the server URL if a server is listening on the task's port.

func (*DetailModel) HandleLogsLoaded

func (m *DetailModel) HandleLogsLoaded(msg logsLoadedMsg)

HandleLogsLoaded processes the result of async log loading.

func (*DetailModel) HasRunningShellProcess

func (m *DetailModel) HasRunningShellProcess() bool

HasRunningShellProcess returns true if the shell pane has a running process.

func (*DetailModel) InFeedbackMode

func (m *DetailModel) InFeedbackMode() bool

InFeedbackMode returns false - use tmux pane for interaction.

func (*DetailModel) IsFocused

func (m *DetailModel) IsFocused() bool

IsFocused returns true if the detail pane is the active tmux pane.

func (*DetailModel) IsShellPaneHidden

func (m *DetailModel) IsShellPaneHidden() bool

IsShellPaneHidden returns true if the shell pane is currently hidden.

func (*DetailModel) Refresh

func (m *DetailModel) Refresh() tea.Cmd

Refresh reloads task and logs from database. Returns a tea.Cmd if async work (like log loading) needs to happen.

func (*DetailModel) RefreshFocusState

func (m *DetailModel) RefreshFocusState()

RefreshFocusState is a lightweight refresh that only updates focus state. Used by the fast focus tick for responsive dimming without full refresh overhead.

func (*DetailModel) RefreshPanesCmd

func (m *DetailModel) RefreshPanesCmd() tea.Cmd

RefreshPanesCmd returns a command to refresh the tmux panes. Use this after ClearPaneState() to rejoin panes to a recreated window.

func (*DetailModel) SetPRInfo

func (m *DetailModel) SetPRInfo(prInfo *github.PRInfo)

SetPRInfo sets the PR info for this task.

func (*DetailModel) SetPosition

func (m *DetailModel) SetPosition(position, total int)

SetPosition updates the task's position in its column.

func (*DetailModel) SetSize

func (m *DetailModel) SetSize(width, height int)

SetSize updates the viewport size.

func (*DetailModel) StartTmuxTicker

func (m *DetailModel) StartTmuxTicker() tea.Cmd

StartTmuxTicker is no longer needed - real tmux pane handles display.

func (*DetailModel) Task

func (m *DetailModel) Task() *db.Task

Task returns the current task.

func (*DetailModel) ToggleShellPane

func (m *DetailModel) ToggleShellPane()

ToggleShellPane toggles the visibility of the shell pane. When hidden, the shell pane is moved to the daemon window and Claude expands to full width. When shown, the shell pane is rejoined from the daemon or a new one is created.

func (*DetailModel) Update

func (m *DetailModel) Update(msg tea.Msg) (*DetailModel, tea.Cmd)

Update handles messages.

func (*DetailModel) UpdateTask

func (m *DetailModel) UpdateTask(t *db.Task)

UpdateTask updates the task and refreshes the view.

func (*DetailModel) View

func (m *DetailModel) View() string

View renders the detail view.

type FileBrowserModel

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

FileBrowserModel is a directory browser for selecting paths.

func NewFileBrowserModel

func NewFileBrowserModel(startPath string, width, height int) *FileBrowserModel

NewFileBrowserModel creates a new file browser starting at the given path.

func (*FileBrowserModel) CurrentDir

func (m *FileBrowserModel) CurrentDir() string

CurrentDir returns the currently displayed directory.

func (*FileBrowserModel) Init

func (m *FileBrowserModel) Init() tea.Cmd

Init initializes the model.

func (*FileBrowserModel) OnCancel

func (m *FileBrowserModel) OnCancel(fn func())

OnCancel sets the callback for when browsing is cancelled.

func (*FileBrowserModel) OnSelect

func (m *FileBrowserModel) OnSelect(fn func(path string))

OnSelect sets the callback for when a path is selected.

func (*FileBrowserModel) SetSize

func (m *FileBrowserModel) SetSize(width, height int)

SetSize updates the browser size.

func (*FileBrowserModel) Update

func (m *FileBrowserModel) Update(msg tea.Msg) (*FileBrowserModel, tea.Cmd)

Update handles messages.

func (*FileBrowserModel) View

func (m *FileBrowserModel) View() string

View renders the file browser.

type FilterAutocompleteModel

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

FilterAutocompleteModel provides project name autocomplete for the filter.

func NewFilterAutocompleteModel

func NewFilterAutocompleteModel(database *db.DB) *FilterAutocompleteModel

NewFilterAutocompleteModel creates a new filter autocomplete model.

func (*FilterAutocompleteModel) HasResults

func (m *FilterAutocompleteModel) HasResults() bool

func (*FilterAutocompleteModel) MoveDown

func (m *FilterAutocompleteModel) MoveDown()

func (*FilterAutocompleteModel) MoveUp

func (m *FilterAutocompleteModel) MoveUp()

func (*FilterAutocompleteModel) Reset

func (m *FilterAutocompleteModel) Reset()

func (*FilterAutocompleteModel) Select

func (m *FilterAutocompleteModel) Select() string

Select returns the selected project name.

func (*FilterAutocompleteModel) SetQuery

func (m *FilterAutocompleteModel) SetQuery(query string)

SetQuery filters projects based on query and resets selection.

func (*FilterAutocompleteModel) View

func (m *FilterAutocompleteModel) View() string

View renders the dropdown.

type FormField

type FormField int

FormField represents the currently focused field.

const (
	FieldProject FormField = iota // Project first for immediate context
	FieldTitle
	FieldBody
	FieldAttachments // Moved after body for proximity - drag works from any field
	FieldType
	FieldExecutor
	FieldCount
)

type FormModel

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

FormModel represents the new task form.

func NewEditFormModel

func NewEditFormModel(database *db.DB, task *db.Task, width, height int, availableExecutors []string) *FormModel

NewEditFormModel creates a form model pre-populated with an existing task's data for editing.

func NewFormModel

func NewFormModel(database *db.DB, width, height int, workingDir string, availableExecutors []string) *FormModel

NewFormModel creates a new form model.

func (*FormModel) GetAttachment

func (m *FormModel) GetAttachment() string

GetAttachment returns the first attachment for backwards compatibility.

func (*FormModel) GetAttachments

func (m *FormModel) GetAttachments() []string

GetAttachments returns the parsed attachment file paths.

func (*FormModel) GetDBTask

func (m *FormModel) GetDBTask() *db.Task

GetDBTask returns a db.Task from the form values.

func (*FormModel) Init

func (m *FormModel) Init() tea.Cmd

Init initializes the form.

func (*FormModel) OriginalProject

func (m *FormModel) OriginalProject() string

OriginalProject returns the original project when editing.

func (*FormModel) ProjectChanged

func (m *FormModel) ProjectChanged() bool

ProjectChanged returns true if the project was changed during editing. Only relevant when isEdit is true.

func (*FormModel) SetQueue

func (m *FormModel) SetQueue(queue bool)

SetQueue sets whether to queue the task.

func (*FormModel) SetSize

func (m *FormModel) SetSize(width, height int)

SetSize updates the form dimensions for window resize handling.

func (*FormModel) Update

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

Update handles messages.

func (*FormModel) View

func (m *FormModel) View() string

View renders the form.

type KanbanBoard

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

KanbanBoard manages the kanban board state.

func NewKanbanBoard

func NewKanbanBoard(width, height int) *KanbanBoard

NewKanbanBoard creates a new kanban board.

func (*KanbanBoard) ClearOriginColumn

func (k *KanbanBoard) ClearOriginColumn()

ClearOriginColumn clears the origin column, returning to normal navigation.

func (*KanbanBoard) ColumnCount

func (k *KanbanBoard) ColumnCount() int

ColumnCount returns the number of columns.

func (*KanbanBoard) FocusColumn

func (k *KanbanBoard) FocusColumn(colIdx int)

FocusColumn moves selection to a specific column by index. If the column is collapsed, it will be uncollapsed first.

func (*KanbanBoard) GetOpenBlockerCount

func (k *KanbanBoard) GetOpenBlockerCount(taskID int64) int

GetOpenBlockerCount returns the number of open blockers for a task. Returns 0 if the task has no blockers.

func (*KanbanBoard) GetPRInfo

func (k *KanbanBoard) GetPRInfo(taskID int64) *github.PRInfo

GetPRInfo returns the PR info for a task.

func (*KanbanBoard) GetTaskPosition

func (k *KanbanBoard) GetTaskPosition() (int, int)

GetTaskPosition returns the position of the currently selected task in its column. Returns (position, total) where position is 1-indexed, or (0, 0) if no task is selected.

func (*KanbanBoard) HandleClick

func (k *KanbanBoard) HandleClick(x, y int) *db.Task

HandleClick handles a mouse click at the given coordinates. Returns the clicked task if a task card was clicked, nil otherwise. Also updates the selection to the clicked task.

func (*KanbanBoard) HasNextTask

func (k *KanbanBoard) HasNextTask() bool

HasNextTask returns true if there is a next task in the current column. Returns false if already at the last task or no tasks exist.

func (*KanbanBoard) HasOriginColumn

func (k *KanbanBoard) HasOriginColumn() bool

HasOriginColumn returns true if an origin column is set.

func (*KanbanBoard) HasPrevTask

func (k *KanbanBoard) HasPrevTask() bool

HasPrevTask returns true if there is a previous task in the current column. Returns false if already at the first task or no tasks exist.

func (*KanbanBoard) HasRunningProcess

func (k *KanbanBoard) HasRunningProcess(taskID int64) bool

HasRunningProcess returns true if the task has a running shell process.

func (*KanbanBoard) IsBlockedByDeps

func (k *KanbanBoard) IsBlockedByDeps(taskID int64) bool

IsBlockedByDeps returns true if the task is blocked by dependencies.

func (*KanbanBoard) IsColumnCollapsed

func (k *KanbanBoard) IsColumnCollapsed(colIdx int) bool

IsColumnCollapsed returns true if the column at the given index is collapsed.

func (*KanbanBoard) IsEmpty

func (k *KanbanBoard) IsEmpty() bool

IsEmpty returns true if all columns have no tasks.

func (*KanbanBoard) IsMobileMode

func (k *KanbanBoard) IsMobileMode() bool

IsMobileMode returns true if the board should show single-column mode.

func (*KanbanBoard) JumpToPinned

func (k *KanbanBoard) JumpToPinned()

JumpToPinned moves selection to the first pinned task in the current column. If there are no pinned tasks, moves to the top of the column.

func (*KanbanBoard) JumpToUnpinned

func (k *KanbanBoard) JumpToUnpinned()

JumpToUnpinned moves selection to the first unpinned task in the current column. If all tasks are pinned or there are no tasks, stays at current position.

func (*KanbanBoard) MoveDown

func (k *KanbanBoard) MoveDown()

MoveDown moves selection down within the current column. If at the bottom, wraps around to the top.

func (*KanbanBoard) MoveLeft

func (k *KanbanBoard) MoveLeft()

MoveLeft moves selection to the left column, skipping collapsed columns.

func (*KanbanBoard) MoveRight

func (k *KanbanBoard) MoveRight()

MoveRight moves selection to the right column, skipping collapsed columns.

func (*KanbanBoard) MoveUp

func (k *KanbanBoard) MoveUp()

MoveUp moves selection up within the current column. If at the top, wraps around to the bottom.

func (*KanbanBoard) NeedsInput

func (k *KanbanBoard) NeedsInput(taskID int64) bool

NeedsInput returns true if the task has an active input notification.

func (*KanbanBoard) RefreshTheme

func (k *KanbanBoard) RefreshTheme()

RefreshTheme updates column colors after a theme change.

func (*KanbanBoard) SelectByShortcut

func (k *KanbanBoard) SelectByShortcut(num int) *db.Task

SelectByShortcut selects the Nth visible task in the current column (1-18). Returns the selected task, or nil if the shortcut doesn't correspond to a visible task.

func (*KanbanBoard) SelectTask

func (k *KanbanBoard) SelectTask(id int64) bool

SelectTask selects a task by ID.

func (*KanbanBoard) SelectedTask

func (k *KanbanBoard) SelectedTask() *db.Task

SelectedTask returns the currently selected task.

func (*KanbanBoard) SetBlockedByDeps

func (k *KanbanBoard) SetBlockedByDeps(blockedByDeps map[int64]int)

SetBlockedByDeps updates the map of tasks blocked by dependencies. The map contains task ID -> number of open blockers.

func (*KanbanBoard) SetHiddenDoneCount

func (k *KanbanBoard) SetHiddenDoneCount(count int)

SetHiddenDoneCount sets the number of done tasks not shown in the kanban.

func (*KanbanBoard) SetOriginColumn

func (k *KanbanBoard) SetOriginColumn()

SetOriginColumn sets the origin column for detail view navigation. This preserves the column context even if the task moves to a different column.

func (*KanbanBoard) SetPRInfo

func (k *KanbanBoard) SetPRInfo(taskID int64, info *github.PRInfo)

SetPRInfo updates the PR info for a task.

func (*KanbanBoard) SetRunningProcesses

func (k *KanbanBoard) SetRunningProcesses(running map[int64]bool)

SetRunningProcesses updates the map of tasks with running shell processes.

func (*KanbanBoard) SetSize

func (k *KanbanBoard) SetSize(width, height int)

SetSize updates the board dimensions.

func (*KanbanBoard) SetTasks

func (k *KanbanBoard) SetTasks(tasks []*db.Task)

SetTasks updates the tasks in the kanban board.

func (*KanbanBoard) SetTasksNeedingInput

func (k *KanbanBoard) SetTasksNeedingInput(needsInput map[int64]bool)

SetTasksNeedingInput updates the map of tasks waiting for user input.

func (*KanbanBoard) ToggleColumnCollapse

func (k *KanbanBoard) ToggleColumnCollapse(colIdx int)

ToggleColumnCollapse toggles the collapsed state of a column. Cannot collapse the currently selected column.

func (*KanbanBoard) TotalTaskCount

func (k *KanbanBoard) TotalTaskCount() int

TotalTaskCount returns the total number of tasks across all columns.

func (*KanbanBoard) View

func (k *KanbanBoard) View() string

View renders the kanban board.

type KanbanColumn

type KanbanColumn struct {
	Title  string
	Status string // The status this column represents
	Tasks  []*db.Task
	Color  lipgloss.Color
	Icon   string // Visual icon for the column
}

KanbanColumn represents a column in the kanban board.

type KeyMap

type KeyMap struct {
	Left               key.Binding
	Right              key.Binding
	Up                 key.Binding
	Down               key.Binding
	Enter              key.Binding
	Back               key.Binding
	New                key.Binding
	Edit               key.Binding
	Queue              key.Binding
	Retry              key.Binding
	Close              key.Binding
	Archive            key.Binding
	Delete             key.Binding
	Refresh            key.Binding
	Settings           key.Binding
	Help               key.Binding
	Quit               key.Binding
	ChangeStatus       key.Binding
	CommandPalette     key.Binding
	ToggleDangerous    key.Binding
	TogglePin          key.Binding
	Filter             key.Binding
	OpenWorktree       key.Binding
	ToggleShellPane    key.Binding
	JumpToNotification key.Binding
	// Column focus shortcuts
	FocusBacklog    key.Binding
	FocusInProgress key.Binding
	FocusBlocked    key.Binding
	FocusDone       key.Binding
	// Jump to pinned/unpinned tasks
	JumpToPinned   key.Binding
	JumpToUnpinned key.Binding
	// Column collapse
	CollapseBacklog key.Binding
	CollapseDone    key.Binding
	// Open browser
	OpenBrowser key.Binding
	// Quick approve/deny for executor prompts
	ApprovePrompt key.Binding
	DenyPrompt    key.Binding
	// Spotlight mode
	Spotlight     key.Binding
	SpotlightSync key.Binding
	// Quick input focus
	QuickInput key.Binding
}

KeyMap defines key bindings.

func ApplyKeybindingsConfig

func ApplyKeybindingsConfig(km KeyMap, cfg *config.KeybindingsConfig) KeyMap

ApplyKeybindingsConfig applies custom keybindings from a config to the KeyMap. Only non-nil config values override the defaults.

func DefaultKeyMap

func DefaultKeyMap() KeyMap

DefaultKeyMap returns the default key bindings.

func LoadKeyMap

func LoadKeyMap() KeyMap

LoadKeyMap loads the KeyMap from the config file, falling back to defaults.

func (KeyMap) FullHelp

func (k KeyMap) FullHelp() [][]key.Binding

FullHelp returns keybindings for the expanded help view.

func (KeyMap) ShortHelp

func (k KeyMap) ShortHelp() []key.Binding

ShortHelp returns key bindings to show in the mini help.

type RetryModel

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

RetryModel handles retrying a blocked/failed task with optional feedback.

func NewRetryModel

func NewRetryModel(task *db.Task, database *db.DB, width, height int) *RetryModel

NewRetryModel creates a new retry model.

func (*RetryModel) GetAttachment

func (m *RetryModel) GetAttachment() string

GetAttachment returns the first attachment path.

func (*RetryModel) GetAttachments

func (m *RetryModel) GetAttachments() []string

GetAttachments returns all attachment paths.

func (*RetryModel) GetFeedback

func (m *RetryModel) GetFeedback() string

GetFeedback returns the feedback text.

func (*RetryModel) Init

func (m *RetryModel) Init() tea.Cmd

Init initializes the model.

func (*RetryModel) SetSize

func (m *RetryModel) SetSize(width, height int)

SetSize updates the size.

func (*RetryModel) Update

func (m *RetryModel) Update(msg tea.Msg) (*RetryModel, tea.Cmd)

Update handles messages.

func (*RetryModel) View

func (m *RetryModel) View() string

View renders the retry view.

type SettingsModel

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

SettingsModel represents the settings view.

func NewSettingsModel

func NewSettingsModel(database *db.DB, width, height int) *SettingsModel

NewSettingsModel creates a new settings model.

func (*SettingsModel) Init

func (m *SettingsModel) Init() tea.Cmd

Init initializes the model.

func (*SettingsModel) SetSize

func (m *SettingsModel) SetSize(width, height int)

SetSize updates the view size.

func (*SettingsModel) Update

func (m *SettingsModel) Update(msg tea.Msg) (*SettingsModel, tea.Cmd)

Update handles messages.

func (*SettingsModel) View

func (m *SettingsModel) View() string

View renders the settings view.

type TaskRefAutocompleteModel

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

TaskRefAutocompleteModel provides inline autocomplete for task references (#123). It appears as a floating dropdown when the user types '#' in a text field.

func NewTaskRefAutocompleteModel

func NewTaskRefAutocompleteModel(database *db.DB, width int) *TaskRefAutocompleteModel

NewTaskRefAutocompleteModel creates a new task reference autocomplete model.

func (*TaskRefAutocompleteModel) Dismiss

func (m *TaskRefAutocompleteModel) Dismiss()

Dismiss closes the autocomplete without selecting.

func (*TaskRefAutocompleteModel) GetCursorPos

func (m *TaskRefAutocompleteModel) GetCursorPos() int

GetCursorPos returns the position where '#' was typed.

func (*TaskRefAutocompleteModel) GetQueryLength

func (m *TaskRefAutocompleteModel) GetQueryLength() int

GetQueryLength returns the length of the query (including #).

func (*TaskRefAutocompleteModel) GetReference

func (m *TaskRefAutocompleteModel) GetReference() string

GetReference returns the task reference string (e.g., "#123 (Task Title)") for the selected task.

func (*TaskRefAutocompleteModel) HasResults

func (m *TaskRefAutocompleteModel) HasResults() bool

HasResults returns true if there are matching tasks.

func (*TaskRefAutocompleteModel) IsDismissed

func (m *TaskRefAutocompleteModel) IsDismissed() bool

IsDismissed returns true if the autocomplete was dismissed.

func (*TaskRefAutocompleteModel) MoveDown

func (m *TaskRefAutocompleteModel) MoveDown()

MoveDown moves selection down.

func (*TaskRefAutocompleteModel) MoveUp

func (m *TaskRefAutocompleteModel) MoveUp()

MoveUp moves selection up.

func (*TaskRefAutocompleteModel) Reset

func (m *TaskRefAutocompleteModel) Reset()

Reset resets the autocomplete state.

func (*TaskRefAutocompleteModel) Select

func (m *TaskRefAutocompleteModel) Select()

Select confirms the current selection.

func (*TaskRefAutocompleteModel) SelectedTask

func (m *TaskRefAutocompleteModel) SelectedTask() *db.Task

SelectedTask returns the selected task, or nil if none selected.

func (*TaskRefAutocompleteModel) SetQuery

func (m *TaskRefAutocompleteModel) SetQuery(query string, cursorPos int)

SetQuery sets the search query and filters tasks.

func (*TaskRefAutocompleteModel) View

func (m *TaskRefAutocompleteModel) View() string

View renders the autocomplete dropdown.

type Theme

type Theme struct {
	Name string `json:"name"`

	// Core colors
	Primary   string `json:"primary"`   // Main accent color (selections, highlights)
	Secondary string `json:"secondary"` // Secondary accent (links, tags)
	Muted     string `json:"muted"`     // Dimmed text, borders

	// Semantic colors
	Success string `json:"success"` // Success states, done
	Warning string `json:"warning"` // Warning states
	Error   string `json:"error"`   // Error states, blocked

	// Status colors
	InProgress string `json:"in_progress"` // Queued/processing tasks
	Done       string `json:"done"`        // Completed tasks
	Blocked    string `json:"blocked"`     // Blocked tasks
	Backlog    string `json:"backlog"`     // Backlog tasks

	// Card colors
	CardBg         string `json:"card_bg"`          // Selected card background
	CardFg         string `json:"card_fg"`          // Selected card foreground
	CardBorder     string `json:"card_border"`      // Card border
	CardBorderHi   string `json:"card_border_hi"`   // Highlighted card border
	ColumnBorder   string `json:"column_border"`    // Column border
	ColumnBorderHi string `json:"column_border_hi"` // Selected column border
}

Theme defines all colors used in the UI.

func CurrentTheme

func CurrentTheme() Theme

CurrentTheme returns the current theme.

type UILogger

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

UILogger provides file-based logging for the UI package. Logs are written to ~/.local/share/task/ui.log

func GetLogger

func GetLogger() *UILogger

GetLogger returns the singleton UI logger instance. Call CloseLogger() when the application exits.

func (*UILogger) Debug

func (l *UILogger) Debug(format string, args ...interface{})

Debug logs a debug message.

func (*UILogger) Error

func (l *UILogger) Error(format string, args ...interface{})

Error logs an error message.

func (*UILogger) Info

func (l *UILogger) Info(format string, args ...interface{})

Info logs an info message.

func (*UILogger) Warn

func (l *UILogger) Warn(format string, args ...interface{})

Warn logs a warning message.

type View

type View int

View represents the current view.

const (
	ViewDashboard View = iota
	ViewDetail
	ViewNewTask
	ViewNewTaskConfirm
	ViewEditTask
	ViewProjectChangeConfirm // Confirmation when changing a task's project
	ViewDeleteConfirm
	ViewCloseConfirm
	ViewArchiveConfirm
	ViewQuitConfirm
	ViewSettings
	ViewRetry
	ViewAttachments
	ViewChangeStatus
	ViewCommandPalette
)

Jump to

Keyboard shortcuts

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