/** * The TUI's colour system: semantic roles, and the palettes that fill them. * * Three rules shape this file, and each one came from a product that had to * learn it the hard way: * * 1. **Primary text takes the terminal's own foreground.** Forcing `37` looks * right on a dark terminal and is unreadable on a light one; Codex's own TUI * style guide says "most of the time, just use the default foreground colour" * and warns against unchecked custom foregrounds. So assistant text and tool * output carry *no* colour token at all. * 2. **A theme is a role table, not a palette.** Callers ask for `error`, not for * red — that is what lets the monochrome theme keep bold/underline while it * drops colour, and what lets a low-colour terminal (`color-depth.ts`) * downgrade by hue family without any theme knowing about it. * 3. **A theme must survive 8 colours and no colour.** Every token here is * emitted as ordinary SGR and passes through `downgradeSgr`, so a `38;2;…` * token on a 256- or 16-colour terminal becomes the nearest hue its palette * has. `mono` goes further and never emits colour at all — the shape of the * line (bold, dim, underline) is what carries meaning, which is exactly what * Gemini CLI's first-class `no-color` theme does. * * @module dsh-ssh-tui/theme */ import type { DisplayKind } from './transcript-types.js'; /** * Roles that are not transcript rows: subagent chips, warning glyphs, links. * * They live here rather than as constants beside their callers for one reason: a * colour literal anywhere outside this module is a colour the palettes cannot * reach, and `tests/theme.test.mjs` fails over exactly that. */ export type ExtraRole = 'subagent-self' | 'subagent-foreign' | 'warn' | 'link' | 'accent' | 'notice' | 'md-bold' | 'md-italic' | 'md-code' | 'md-link' | 'md-muted' | 'md-h1' | 'md-h2' | 'md-h3' | 'md-quote' | 'md-rule' | 'tool-running' | 'tool-ok'; /** One palette. Tokens are SGR parameter strings, without the escape. */ export interface Theme { /** Key used by `/theme`, `DSH_TUI_THEME`, and the `theme` setting. */ name: string; /** Order in `/theme` output; lower is closer to the original look. */ rank: number; /** Row role → SGR parameters. A missing role falls back to `default`'s. */ tokens: Partial>; /** Diff emphasis uses a second, brighter variant of the same fill. */ emphasis?: Partial>; /** Non-row roles. */ extra?: Partial>; } export declare const THEMES: readonly Theme[]; /** Every theme name, in the order `/theme` lists them. */ export declare function themeNames(): string[]; /** * Resolve a theme name. * @param name - a name from the environment, the settings file, or `/theme`. * @returns the theme, or undefined when the name is unknown (the caller decides * whether to fall back quietly — a typo in a settings file should not crash a * session, but `/theme bogus` has to say so). */ export declare function themeByName(name: string | undefined): Theme | undefined; /** The theme a `DSH_TUI_THEME`/`theme` value selects, defaulting to `default`. */ export declare function resolveTheme(name: string | undefined): Theme; /** * Publish the active palette. * @param name - the theme name, as resolved from the environment or settings. * @returns the theme that is now active. */ export declare function setActiveTheme(name: string | undefined): Theme; /** The active palette, for renderers that have no session handle. */ export declare function activeTheme(): Theme; /** * The SGR parameters for one row role. * @param theme - the active theme. * @param kind - the display role being painted. * @returns SGR parameters without the escape, or `''` for "leave it to the * terminal" (which is what primary text wants). */ export declare function themeToken(theme: Theme, kind: DisplayKind): string; /** * The SGR parameters for a changed word inside a diff row. * @param theme - the active theme. * @param kind - `diff-add` or `diff-del`. * @returns the emphasised variant, or undefined when the theme has none. */ export declare function themeEmphasisToken(theme: Theme, kind: DisplayKind): string | undefined; /** * The SGR parameters for a non-row role. * @param theme - the active theme. * @param role - the extra role requested. * @returns SGR parameters without the escape. */ export declare function themeExtraToken(theme: Theme, role: ExtraRole): string; /** A threshold level used by the status area's gauges. */ export type ThresholdLevel = 'ok' | 'warn' | 'over'; /** * The token for a gauge threshold: context usage, a quota window, a spend bar. * * One vocabulary for all of them, so a reader learns it once — under 70% is * fine, 70–89% is worth noting, 90% and up is a problem. The numbers behind the * levels live in the status area; the colours live here, and `mono` answers with * attributes instead of giving up the distinction. * @param theme - the active theme. * @param level - which threshold the gauge is in. * @returns SGR parameters without the escape. */ export declare function themeThresholdToken(theme: Theme, level: ThresholdLevel): string; /** * Whether a theme paints colour at all. * @param theme - the active theme. * @returns false for `mono`, whose tokens are attributes only. */ export declare function themeHasColour(theme: Theme): boolean;