/** * Host-neutral widget style system (subagent-ui-theming-and-style, design D1). * * Approach A — themed chrome, fixed game bars: * - CHROME (borders, lane rules, empty-bar glyphs, muted captions, dim/overlay * text) is emitted through injected chrome functions the host binds to its * theme's semantic tokens. Light/dark AND truecolor→256 downgrade come free * from the host for these. * - GAME colors (bar fills, harness identity, role tile) are deliberate, * theme-independent identity. They are the ONLY colors emitted as raw hexes, * downgraded host-neutrally here (truecolor pass-through, else nearest * 256-color via the xterm cube + gray ramp). * * This module is core: no pi imports (enforced by * test/host-import-boundary.test.ts) and no IO — pure types, palettes, and * color math. */ export type ColorScheme = "dark" | "light"; export type ColorMode = "truecolor" | "256color"; /** One bar's fixed game colors (hexes; scheme-appropriate variants). */ export interface BarStyle { /** Fill color — the bar body up to the metric point. */ fill: string; /** * Explicit background override for the empty (past-the-metric) portion. * Undefined by default — the renderer derives the empty track from `fill` * via {@link fadeHex} (design D2, borderless redesign); an explicit * `bg` here still wins over that derivation. */ bg?: string; } /** * The injectable style object the renderer consumes (`FramesOptions.style`). * The host adapter builds it from the active theme (chrome functions), the * detected color scheme/mode, and the resolved GLOBAL config style; per-record * role styles (`SubagentRecord.style`) are applied on top at render time via * `applyStyleConfig`. */ export interface WidgetStyle { colorScheme: ColorScheme; colorMode: ColorMode; bars: { health: BarStyle; mana: BarStyle; cast: BarStyle; }; /** Per-harness identity hex overrides (fallback: HARNESS_COLOR_TOKENS). */ harnessColors: Record; /** Portrait tile hex; undefined → the agent's harness color. */ roleColor?: string; /** Portrait glyph override; undefined → the role-keyword glyph table. */ portraitGlyph?: string; /** Frame edges, lane rules, empty raid edges. */ border(text: string): string; /** Captions, empty-bar glyphs, idle cast text. */ muted(text: string): string; /** Terminal-state dimming. */ dim(text: string): string; /** Portrait glyph / bar-label contrast text. */ text(text: string): string; } /** * The serializable `style:` config shape (`tmux-pilot.config.yaml`, global * and role scope) — also what is persisted per record at spawn. All fields * optional: absent fields fall through to the scheme-default palette. */ export interface BarStyleConfig { fill?: string; bg?: string; } export interface StyleConfig { bars?: { health?: BarStyleConfig; mana?: BarStyleConfig; cast?: BarStyleConfig; }; /** Per-harness identity hex overrides. */ harnessColors?: Record; /** Portrait tile hex (scalar — overridden wholesale). */ roleColor?: string; /** Portrait glyph override for the role. */ portrait?: { glyph?: string; }; } /** Dark-scheme default bar palette. */ export declare const DARK_BAR_PALETTE: { health: BarStyle; mana: BarStyle; cast: BarStyle; }; /** * Light-scheme default bar palette. Fills darken (light terminals need * saturation, not brightness); tints go pastel so overlaid dark text reads. * Validated live during QA (design open item). */ export declare const LIGHT_BAR_PALETTE: { health: BarStyle; mana: BarStyle; cast: BarStyle; }; /** Scheme-appropriate default palette lookup. */ export declare function defaultBarPalette(scheme: ColorScheme): { health: BarStyle; mana: BarStyle; cast: BarStyle; }; export type TerminalStatus = "completed" | "failed" | "crashed" | "interrupted"; /** 3 shades (index 0=health, 1=mana, 2=cast) plus contrast text per scheme. */ export interface TerminalPalette { shades: { dark: [string, string, string]; light: [string, string, string]; }; fg: { dark: string; light: string; }; } /** completed=green, failed/crashed=red (shared), interrupted=amber. */ export declare const TERMINAL_PALETTES: Record; /** Scheme-resolved terminal palette for a status: 3 shades + one fg. */ export declare function terminalPaletteFor(status: TerminalStatus, scheme: ColorScheme): { shades: [string, string, string]; fg: string; }; /** * Build a self-contained style with no host theme: dark scheme, truecolor, * neutral-gray chrome. Used whenever `FramesOptions.style` is absent. */ export declare function fallbackStyle(): WidgetStyle; /** * Shallow per-leaf-group merge of two style configs: `over` wins per field * within `bars.health|mana|cast`, `portrait`, and per key within * `harnessColors`; scalar `roleColor` is overridden wholesale. */ export declare function mergeStyleConfig(base: StyleConfig, over: StyleConfig): StyleConfig; /** * Apply a (record-level or global) style config over a concrete WidgetStyle, * producing the effective style. Chrome functions and scheme/mode pass * through untouched — config can only override the fixed game colors. */ export declare function applyStyleConfig(style: WidgetStyle, config: StyleConfig | undefined): WidgetStyle; /** `#rrggbb` shape check used by config validation. */ export declare function isValidHexColor(value: unknown): value is string; /** * Nearest xterm-256 index for a hex color: compares the best 6×6×6 cube * entry (16–231) against the best gray-ramp entry (232–255) by squared RGB * distance. The 16 basic colors are skipped (terminal-redefined, unreliable). */ export declare function hexToAnsi256(hex: string): number; /** OPEN (unreset) foreground code for a fixed hex in the given color mode. */ export declare function fgFixedOpen(mode: ColorMode, hex: string): string; /** OPEN (unreset) background code for a fixed hex in the given color mode. */ export declare function bgFixedOpen(mode: ColorMode, hex: string): string; /** Wrap text in a mode-aware fixed-hex foreground. */ export declare function fgFixed(mode: ColorMode, hex: string, text: string): string; /** Wrap text in a mode-aware DIMMED fixed-hex foreground (terminal states). */ export declare function fgFixedDim(mode: ColorMode, hex: string, text: string): string; /** WCAG-ish relative luminance (0–1) — mirrors pi's detection math. */ export declare function relativeLuminance(r: number, g: number, b: number): number; /** Contrast foreground (near-black / near-white) for text over a hex bg. */ export declare function contrastFg(bgHex: string): string; /** * Low-headroom escalation WITHIN the health fill color (design D2): red is * the resting color, so urgency is brightness/saturation, not a hue change. * Works on user-overridden fills too. ≥50% → base; <50% → mild; <25% → hot. */ export declare function escalateHealthFill(fillHex: string, headroomPct: number, scheme: ColorScheme): string; /** * Same-hue, fixed-factor darker variant of a fill (design D3) — the mana * grace reserve. Analogous to {@link escalateHealthFill}, but unconditional: * drops HSL lightness by `factor` (0–1) while preserving hue and saturation, * so the reserve reads as the same blue, just deeper. Works on any scheme's * mana fill (light-scheme fills are already darker, so the reserve lands * darker still — still legible against the pastel empty tint). */ export declare function darkenHex(hex: string, factor: number): string; /** * Derived "depleted" track color (borderless redesign, design D2): same hue * as `hex`, heavily desaturated, and dimmed by `factor` (0-1) — the * RPG-style empty-resource-bar look. This is the DEFAULT empty track for * every bar (health/mana/cast idle), replacing the old fixed near-black * `bars.*.bg`; an explicit `bars.*.bg` config override still wins over it. * Sibling of {@link darkenHex} (which preserves saturation for the mana * grace reserve). */ export declare function fadeHex(hex: string, factor?: number): string; /** Linear per-channel interpolation between two hexes (`t=0` → `a`, `t=1` → `b`). */ export declare function mixHex(a: string, b: string, t: number): string; /** * Darkening factor for the cast lane's ACTIVE track (design D3): deeper than * a resting fill but not the heavily-desaturated {@link fadeHex} look, so the * traveling sweep head reads as bright against it. */ export declare const CAST_ACTIVE_DARKEN = 0.35; /** * Cast lane track color for idle vs. active states (design D3): idle is the * standard faded/depleted track (a light resting yellow); active is a * darker — but still saturated — yellow that the casting sweep travels over. */ export declare function castTrackColor(fill: string, active: boolean): string; /** Scheme for a probed terminal background color. */ export declare function schemeForRgb(r: number, g: number, b: number): ColorScheme; /** xterm-256 index → RGB (basic 16 via the standard palette). */ export declare function ansi256ToRgb(index: number): [number, number, number]; /** * COLORFGBG-based scheme detection (`;` or `;;`). * Returns undefined when the variable is absent/unparseable — callers fall * back to a dark default. */ export declare function detectSchemeFromEnv(env?: Record): ColorScheme | undefined; //# sourceMappingURL=widget-style.d.ts.map