fix: make CLI status bar skin-aware

Route prompt_toolkit status bar colors through the skin engine so /skin updates the status bar alongside the rest of the interactive TUI.

Add regression coverage for the new status bar style override keys and CLI style composition.
This commit is contained in:
kshitij
2026-04-22 13:20:02 -07:00
committed by Teknium
parent de849c410d
commit c323217188
3 changed files with 268 additions and 8 deletions
+242 -7
View File
@@ -30,6 +30,14 @@ All fields are optional. Missing values inherit from the ``default`` skin.
prompt: "#FFF8DC" # Prompt text color
input_rule: "#CD7F32" # Input area horizontal rule
response_border: "#FFD700" # Response box border (ANSI)
status_bar_bg: "#1a1a2e" # Status bar background
status_bar_text: "#C0C0C0" # Status bar default text
status_bar_strong: "#FFD700" # Status bar highlighted text
status_bar_dim: "#8B8682" # Status bar separators/muted text
status_bar_good: "#8FBC8F" # Healthy context usage
status_bar_warn: "#FFD700" # Warning context usage
status_bar_bad: "#FF8C00" # High context usage
status_bar_critical: "#FF6B6B" # Critical context usage
session_label: "#DAA520" # Session label color
session_border: "#8B8682" # Session ID dim color
status_bar_bg: "#1a1a2e" # TUI status/usage bar background
@@ -170,9 +178,40 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
"prompt": "#FFF8DC",
"input_rule": "#CD7F32",
"response_border": "#FFD700",
"status_bar_bg": "#1a1a2e",
"status_bar_text": "#C0C0C0",
"status_bar_strong": "#FFD700",
"status_bar_dim": "#8B8682",
"status_bar_good": "#8FBC8F",
"status_bar_warn": "#FFD700",
"status_bar_bad": "#FF8C00",
"status_bar_critical": "#FF6B6B",
"session_label": "#DAA520",
"session_border": "#8B8682",
},
"colors_light": {
"banner_border": "#7A5A00",
"banner_title": "#6B4C00",
"banner_accent": "#7A5500",
"banner_dim": "#8B7355",
"banner_text": "#3D2B00",
"prompt": "#3D2B00",
"ui_accent": "#7A5500",
"ui_label": "#01579B",
"ui_ok": "#1B5E20",
"input_rule": "#7A5A00",
"response_border": "#6B4C00",
"status_bar_bg": "#F2EEE3",
"status_bar_text": "#5C4300",
"status_bar_strong": "#6B4C00",
"status_bar_dim": "#8B7355",
"status_bar_good": "#1B5E20",
"status_bar_warn": "#7A5500",
"status_bar_bad": "#B85C00",
"status_bar_critical": "#B3261E",
"session_label": "#5C4300",
"session_border": "#8B7355",
},
"spinner": {
# Empty = use hardcoded defaults in display.py
},
@@ -203,9 +242,40 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
"prompt": "#F1E6CF",
"input_rule": "#9F1C1C",
"response_border": "#C7A96B",
"status_bar_bg": "#2A1212",
"status_bar_text": "#F1E6CF",
"status_bar_strong": "#C7A96B",
"status_bar_dim": "#6E584B",
"status_bar_good": "#7BC96F",
"status_bar_warn": "#C7A96B",
"status_bar_bad": "#DD4A3A",
"status_bar_critical": "#EF5350",
"session_label": "#C7A96B",
"session_border": "#6E584B",
},
"colors_light": {
"banner_border": "#6B1010",
"banner_title": "#5C4300",
"banner_accent": "#8B1A1A",
"banner_dim": "#5C4030",
"banner_text": "#3A1800",
"prompt": "#3A1800",
"ui_accent": "#8B1A1A",
"ui_label": "#5C4300",
"ui_ok": "#1B5E20",
"input_rule": "#6B1010",
"response_border": "#7A1515",
"status_bar_bg": "#F6E7DB",
"status_bar_text": "#5C4300",
"status_bar_strong": "#7A1515",
"status_bar_dim": "#8A6F5A",
"status_bar_good": "#1B5E20",
"status_bar_warn": "#8B4000",
"status_bar_bad": "#8B1A1A",
"status_bar_critical": "#B3261E",
"session_label": "#5C4300",
"session_border": "#5C4A3A",
},
"spinner": {
"waiting_faces": ["(⚔)", "(⛨)", "(▲)", "(<>)", "(/)"],
"thinking_faces": ["(⚔)", "(⛨)", "(▲)", "(⌁)", "(<>)"],
@@ -267,9 +337,41 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
"prompt": "#c9d1d9",
"input_rule": "#444444",
"response_border": "#aaaaaa",
"status_bar_bg": "#1F1F1F",
"status_bar_text": "#C9D1D9",
"status_bar_strong": "#E6EDF3",
"status_bar_dim": "#777777",
"status_bar_good": "#B5B5B5",
"status_bar_warn": "#AAAAAA",
"status_bar_bad": "#D0D0D0",
"status_bar_critical": "#F0F0F0",
"session_label": "#888888",
"session_border": "#555555",
},
"colors_light": {
"banner_border": "#333333",
"banner_title": "#222222",
"banner_accent": "#333333",
"banner_dim": "#555555",
"banner_text": "#333333",
"prompt": "#222222",
"ui_accent": "#333333",
"ui_label": "#444444",
"ui_ok": "#444444",
"ui_error": "#333333",
"input_rule": "#333333",
"response_border": "#444444",
"status_bar_bg": "#EEEEEE",
"status_bar_text": "#333333",
"status_bar_strong": "#222222",
"status_bar_dim": "#666666",
"status_bar_good": "#444444",
"status_bar_warn": "#555555",
"status_bar_bad": "#333333",
"status_bar_critical": "#111111",
"session_label": "#444444",
"session_border": "#666666",
},
"spinner": {},
"branding": {
"agent_name": "Hermes Agent",
@@ -298,9 +400,40 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
"prompt": "#c9d1d9",
"input_rule": "#4169e1",
"response_border": "#7eb8f6",
"status_bar_bg": "#151C2F",
"status_bar_text": "#C9D1D9",
"status_bar_strong": "#7EB8F6",
"status_bar_dim": "#4B5563",
"status_bar_good": "#63D0A6",
"status_bar_warn": "#E6A855",
"status_bar_bad": "#F7A072",
"status_bar_critical": "#FF7A7A",
"session_label": "#7eb8f6",
"session_border": "#4b5563",
},
"colors_light": {
"banner_border": "#1A3A7A",
"banner_title": "#1A3570",
"banner_accent": "#1E4090",
"banner_dim": "#3B4555",
"banner_text": "#1A2A50",
"prompt": "#1A2A50",
"ui_accent": "#1A3570",
"ui_label": "#1E3A80",
"ui_ok": "#1B5E20",
"input_rule": "#1A3A7A",
"response_border": "#2A4FA0",
"status_bar_bg": "#E9EEF8",
"status_bar_text": "#1A2A50",
"status_bar_strong": "#1A3570",
"status_bar_dim": "#5A6070",
"status_bar_good": "#1B5E20",
"status_bar_warn": "#8B5E00",
"status_bar_bad": "#B85C38",
"status_bar_critical": "#B3261E",
"session_label": "#1A3570",
"session_border": "#5A6070",
},
"spinner": {},
"branding": {
"agent_name": "Hermes Agent",
@@ -403,9 +536,40 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
"prompt": "#EAF7FF",
"input_rule": "#2A6FB9",
"response_border": "#5DB8F5",
"status_bar_bg": "#0F2440",
"status_bar_text": "#EAF7FF",
"status_bar_strong": "#A9DFFF",
"status_bar_dim": "#496884",
"status_bar_good": "#6ED7B0",
"status_bar_warn": "#5DB8F5",
"status_bar_bad": "#2A6FB9",
"status_bar_critical": "#D94F4F",
"session_label": "#A9DFFF",
"session_border": "#496884",
},
"colors_light": {
"banner_border": "#0D3060",
"banner_title": "#0D3060",
"banner_accent": "#154080",
"banner_dim": "#2A4565",
"banner_text": "#0A2850",
"prompt": "#0A2850",
"ui_accent": "#0D3060",
"ui_label": "#0D3060",
"ui_ok": "#1B5E20",
"input_rule": "#0D3060",
"response_border": "#1A5090",
"status_bar_bg": "#E6F4FF",
"status_bar_text": "#0A2850",
"status_bar_strong": "#0D3060",
"status_bar_dim": "#3A5575",
"status_bar_good": "#1B5E20",
"status_bar_warn": "#1A5090",
"status_bar_bad": "#154080",
"status_bar_critical": "#B3261E",
"session_label": "#0D3060",
"session_border": "#3A5575",
},
"spinner": {
"waiting_faces": ["(≈)", "(Ψ)", "(∿)", "(◌)", "(◠)"],
"thinking_faces": ["(Ψ)", "(∿)", "(≈)", "(⌁)", "(◌)"],
@@ -467,9 +631,42 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
"prompt": "#F5F5F5",
"input_rule": "#656565",
"response_border": "#B7B7B7",
"status_bar_bg": "#202020",
"status_bar_text": "#D3D3D3",
"status_bar_strong": "#F5F5F5",
"status_bar_dim": "#656565",
"status_bar_good": "#B7B7B7",
"status_bar_warn": "#D3D3D3",
"status_bar_bad": "#E7E7E7",
"status_bar_critical": "#F5F5F5",
"session_label": "#919191",
"session_border": "#656565",
},
"colors_light": {
"banner_border": "#666666",
"banner_title": "#222222",
"banner_accent": "#333333",
"banner_dim": "#555555",
"banner_text": "#333333",
"prompt": "#222222",
"ui_accent": "#333333",
"ui_label": "#444444",
"ui_ok": "#444444",
"ui_error": "#333333",
"ui_warn": "#444444",
"input_rule": "#666666",
"response_border": "#555555",
"status_bar_bg": "#F0F0F0",
"status_bar_text": "#333333",
"status_bar_strong": "#222222",
"status_bar_dim": "#777777",
"status_bar_good": "#444444",
"status_bar_warn": "#555555",
"status_bar_bad": "#333333",
"status_bar_critical": "#111111",
"session_label": "#444444",
"session_border": "#777777",
},
"spinner": {
"waiting_faces": ["(◉)", "(◌)", "(◬)", "(⬤)", "(::)"],
"thinking_faces": ["(◉)", "(◬)", "(◌)", "(○)", "(●)"],
@@ -532,9 +729,40 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
"prompt": "#FFF0D4",
"input_rule": "#C75B1D",
"response_border": "#F29C38",
"status_bar_bg": "#2B160E",
"status_bar_text": "#FFF0D4",
"status_bar_strong": "#FFD39A",
"status_bar_dim": "#6C4724",
"status_bar_good": "#6BCB77",
"status_bar_warn": "#F29C38",
"status_bar_bad": "#E2832B",
"status_bar_critical": "#EF5350",
"session_label": "#FFD39A",
"session_border": "#6C4724",
},
"colors_light": {
"banner_border": "#7A3511",
"banner_title": "#5C2D00",
"banner_accent": "#8B4000",
"banner_dim": "#5A3A1A",
"banner_text": "#3A1E00",
"prompt": "#3A1E00",
"ui_accent": "#8B4000",
"ui_label": "#5C2D00",
"ui_ok": "#1B5E20",
"input_rule": "#7A3511",
"response_border": "#8B4513",
"status_bar_bg": "#F8EADF",
"status_bar_text": "#3A1E00",
"status_bar_strong": "#5C2D00",
"status_bar_dim": "#6B5540",
"status_bar_good": "#1B5E20",
"status_bar_warn": "#8B4513",
"status_bar_bad": "#8B4000",
"status_bar_critical": "#B3261E",
"session_label": "#5C2D00",
"session_border": "#6B5540",
},
"spinner": {
"waiting_faces": ["(✦)", "(▲)", "(◇)", "(<>)", "(🔥)"],
"thinking_faces": ["(✦)", "(▲)", "(◇)", "(⌁)", "(🔥)"],
@@ -770,6 +998,13 @@ def get_prompt_toolkit_style_overrides() -> Dict[str, str]:
warn = skin.get_color("ui_warn", "#FF8C00")
error = skin.get_color("ui_error", "#FF6B6B")
status_bg = skin.get_color("status_bar_bg", "#1a1a2e")
status_text = skin.get_color("status_bar_text", text)
status_strong = skin.get_color("status_bar_strong", title)
status_dim = skin.get_color("status_bar_dim", dim)
status_good = skin.get_color("status_bar_good", skin.get_color("ui_ok", "#8FBC8F"))
status_warn = skin.get_color("status_bar_warn", warn)
status_bad = skin.get_color("status_bar_bad", skin.get_color("banner_accent", warn))
status_critical = skin.get_color("status_bar_critical", error)
voice_bg = skin.get_color("voice_status_bg", status_bg)
menu_bg = skin.get_color("completion_menu_bg", "#1a1a2e")
menu_current_bg = skin.get_color("completion_menu_current_bg", "#333355")
@@ -782,13 +1017,13 @@ def get_prompt_toolkit_style_overrides() -> Dict[str, str]:
"prompt": prompt,
"prompt-working": f"{dim} italic",
"hint": f"{dim} italic",
"status-bar": f"bg:{status_bg} {text}",
"status-bar-strong": f"bg:{status_bg} {title} bold",
"status-bar-dim": f"bg:{status_bg} {dim}",
"status-bar-good": f"bg:{status_bg} {skin.get_color('ui_ok', '#8FBC8F')} bold",
"status-bar-warn": f"bg:{status_bg} {warn} bold",
"status-bar-bad": f"bg:{status_bg} {skin.get_color('banner_accent', warn)} bold",
"status-bar-critical": f"bg:{status_bg} {error} bold",
"status-bar": f"bg:{status_bg} {status_text}",
"status-bar-strong": f"bg:{status_bg} {status_strong} bold",
"status-bar-dim": f"bg:{status_bg} {status_dim}",
"status-bar-good": f"bg:{status_bg} {status_good} bold",
"status-bar-warn": f"bg:{status_bg} {status_warn} bold",
"status-bar-bad": f"bg:{status_bg} {status_bad} bold",
"status-bar-critical": f"bg:{status_bg} {status_critical} bold",
"input-rule": input_rule,
"image-badge": f"{label} bold",
"completion-menu": f"bg:{menu_bg} {text}",