feat(theme): user-configurable color themes
Description
Adds a theme system so users can customize glab's terminal colors. The active theme controls fang's help and error rendering, huh's interactive prompts, and the ANSI color layer used in command output — all three surfaces now read from the same resolved palette.
The built-in gitlab theme preserves existing colors exactly. Everything else is opt-in.
Theme layer (internal/theme/): Refactored GitLabColors into a generic Colors struct with semantic roles (Primary, Secondary, Info, Success, Warning, Error, Text, Subtle) and a Theme type holding separate light and dark palettes. FangColorScheme and HuhTheme are now parameterised on these structs rather than hardcoding hex values. This also fixes a pre-existing bug where HuhTheme re-derived its own light/dark hex constants inline instead of reading from the shared palette.
Registry (internal/theme/registry/): Discovers built-in themes (plain Go values, no embed or parsing) and user-authored YAML files from <ConfigDir>/themes/*.yml. Built-ins win on name collision. The YAML parser validates #RRGGBB hex format and requires all 8 semantic fields in both light and dark palettes.
Config key: theme added to KeySchema with GLAB_THEME env override, fallback to gitlab, and UserSettable: true.
Wiring (cmd/glab/main.go): Active theme resolves once at startup, falls back silently to gitlab on error, then threads into fang via WithColorSchemeFunc and into IOStreams via a new WithTheme option.
glab theme commands:
| Command | What it does |
|---|---|
glab theme list |
Table of available themes with source and active marker |
glab theme get [name] |
Shows the palette (light + dark hex values) for a theme |
glab theme set <name> |
Validates against the registry, then writes the theme config key |
glab theme create <name> |
Scaffolds a new YAML file from a seed theme; opens $EDITOR with --edit |
glab theme edit <name> |
Opens a user theme in $EDITOR, validates before saving, rejects built-ins |
glab theme path |
Prints <ConfigDir>/themes |
Theme file format — a YAML file with light and dark palette blocks:
name: mytheme
light:
primary: "#FC6D26"
secondary: "#7759C2"
info: "#1068BF"
success: "#217645"
warning: "#C97A00"
error: "#C91C00"
text: "#171321"
subtle: "#6B6B73"
dark:
# same fields, dark-background variantsRelated issues
N/A — discussion happened in planning session, no upstream issue yet.
How has this been tested?
Unit tests cover the registry (parsing, validation, round-trip marshal, builtin precedence, missing directory) and the list, get, and set commands via cmdtest.SetupCmdForTest. The TestParse_InvalidHex test caught a real validation bug during development — lipgloss.Color("notacolor") returns NoColor{} rather than nil, so the alpha check was wrong; fixed with explicit hex-format validation.
All existing tests pass (go test ./...). make gen-docs regenerates cleanly and the new docs/source/theme/ pages are included in the commit.