mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
feat(cli): skin-aware light/dark theme mode with terminal auto-detection
Add display.theme_mode setting (auto/light/dark) that makes the CLI readable on light terminal backgrounds. - Auto-detect terminal background via COLORFGBG, OSC 11, and macOS appearance (fallback chain in hermes_cli/colors.py) - Add colors_light overrides to all 7 built-in skins with dark/readable colors for light backgrounds - SkinConfig.get_color() now returns light overrides when theme is light - get_prompt_toolkit_style_overrides() uses light bg colors for completion menus in light mode - init_skin_from_config() reads display.theme_mode from config - 7 new tests covering theme mode resolution, detection fallbacks, and light-mode skin overrides Salvaged from PR #1187 by @peteromallet. Core design preserved; adapted to current main (kept all existing helpers, tool_emojis, convenience functions that were added after the PR branched). Co-authored-by: Peter O'Mallet <peteromallet@users.noreply.github.com>
This commit is contained in:
parent
d156942419
commit
a1c81360a5
5 changed files with 362 additions and 6 deletions
|
|
@ -13,9 +13,13 @@ def reset_skin_state():
|
|||
from hermes_cli import skin_engine
|
||||
skin_engine._active_skin = None
|
||||
skin_engine._active_skin_name = "default"
|
||||
skin_engine._theme_mode = "auto"
|
||||
skin_engine._resolved_theme_mode = None
|
||||
yield
|
||||
skin_engine._active_skin = None
|
||||
skin_engine._active_skin_name = "default"
|
||||
skin_engine._theme_mode = "auto"
|
||||
skin_engine._resolved_theme_mode = None
|
||||
|
||||
|
||||
class TestSkinConfig:
|
||||
|
|
@ -312,3 +316,65 @@ class TestCliBrandingHelpers:
|
|||
assert overrides["clarify-title"] == f"{skin.get_color('banner_title')} bold"
|
||||
assert overrides["sudo-prompt"] == f"{skin.get_color('ui_error')} bold"
|
||||
assert overrides["approval-title"] == f"{skin.get_color('ui_warn')} bold"
|
||||
|
||||
|
||||
class TestThemeMode:
|
||||
def test_get_theme_mode_defaults_to_dark_on_unknown(self):
|
||||
from hermes_cli.skin_engine import get_theme_mode, set_theme_mode
|
||||
|
||||
set_theme_mode("auto")
|
||||
# In a test env, detection returns "unknown" → defaults to "dark"
|
||||
with patch("hermes_cli.colors.detect_terminal_background", return_value="unknown"):
|
||||
from hermes_cli import skin_engine
|
||||
skin_engine._resolved_theme_mode = None # force re-detection
|
||||
assert get_theme_mode() == "dark"
|
||||
|
||||
def test_set_theme_mode_light(self):
|
||||
from hermes_cli.skin_engine import get_theme_mode, set_theme_mode
|
||||
|
||||
set_theme_mode("light")
|
||||
assert get_theme_mode() == "light"
|
||||
|
||||
def test_set_theme_mode_dark(self):
|
||||
from hermes_cli.skin_engine import get_theme_mode, set_theme_mode
|
||||
|
||||
set_theme_mode("dark")
|
||||
assert get_theme_mode() == "dark"
|
||||
|
||||
def test_get_color_respects_light_mode(self):
|
||||
from hermes_cli.skin_engine import SkinConfig, set_theme_mode
|
||||
|
||||
skin = SkinConfig(
|
||||
name="test",
|
||||
colors={"banner_title": "#FFD700", "prompt": "#FFF8DC"},
|
||||
colors_light={"banner_title": "#6B4C00"},
|
||||
)
|
||||
set_theme_mode("light")
|
||||
assert skin.get_color("banner_title") == "#6B4C00"
|
||||
# Key not in colors_light falls back to colors
|
||||
assert skin.get_color("prompt") == "#FFF8DC"
|
||||
|
||||
def test_get_color_falls_back_in_dark_mode(self):
|
||||
from hermes_cli.skin_engine import SkinConfig, set_theme_mode
|
||||
|
||||
skin = SkinConfig(
|
||||
name="test",
|
||||
colors={"banner_title": "#FFD700", "prompt": "#FFF8DC"},
|
||||
colors_light={"banner_title": "#6B4C00"},
|
||||
)
|
||||
set_theme_mode("dark")
|
||||
assert skin.get_color("banner_title") == "#FFD700"
|
||||
assert skin.get_color("prompt") == "#FFF8DC"
|
||||
|
||||
def test_init_skin_from_config_reads_theme_mode(self):
|
||||
from hermes_cli.skin_engine import init_skin_from_config, get_theme_mode_setting
|
||||
|
||||
init_skin_from_config({"display": {"skin": "default", "theme_mode": "light"}})
|
||||
assert get_theme_mode_setting() == "light"
|
||||
|
||||
def test_builtin_skins_have_colors_light(self):
|
||||
from hermes_cli.skin_engine import _BUILTIN_SKINS, _build_skin_config
|
||||
|
||||
for name, data in _BUILTIN_SKINS.items():
|
||||
skin = _build_skin_config(data)
|
||||
assert len(skin.colors_light) > 0, f"Skin '{name}' has empty colors_light"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue