diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index 4ae8c3251d2..3a854033195 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -13087,6 +13087,17 @@ def _resolve_chat_argv( # the dashboard PTY path. env.setdefault("HERMES_TUI_DISABLE_MOUSE", "1") env.setdefault("HERMES_TUI_INLINE", "1") + # The dashboard terminal is xterm.js, which always renders 24-bit RGB. + # But chalk inside the TUI child decides its color depth from the + # SERVER process env — and hosted/cloud deploys run the dashboard under + # a process manager (container init, systemd) with no COLORTERM, so + # chalk downgrades every hex color to the xterm 256 palette. The skin's + # bronze border #CD7F32 snaps to palette 173 (#D7875F, salmon-red) and + # the banner reads red/yellow instead of gold. Local launches dodge + # this only because the operator's interactive terminal leaks + # COLORTERM=truecolor into os.environ. Backfill it for the PTY child; + # setdefault so an explicit operator value still wins. + env.setdefault("COLORTERM", "truecolor") env["HERMES_TUI_DASHBOARD"] = "1" if profile_dir is not None: diff --git a/tests/hermes_cli/test_web_server.py b/tests/hermes_cli/test_web_server.py index 18f5facbb6b..dc1bfcccf79 100644 --- a/tests/hermes_cli/test_web_server.py +++ b/tests/hermes_cli/test_web_server.py @@ -5919,6 +5919,39 @@ class TestPtyWebSocket: assert env["HERMES_TUI_INLINE"] == "1" assert env["HERMES_TUI_DISABLE_MOUSE"] == "1" + def test_resolve_chat_argv_backfills_colorterm_truecolor(self, monkeypatch): + """Headless servers (cloud/systemd) have no COLORTERM, which made + chalk in the TUI child degrade skin hex colors to the xterm 256 + palette (gold banner rendered salmon-red). xterm.js always supports + 24-bit color, so the PTY env must advertise truecolor.""" + import hermes_cli.main as main_mod + + monkeypatch.setattr( + main_mod, + "_make_tui_argv", + lambda project_root, tui_dev=False: (["node", "dist/entry.js"], "/tmp/ui-tui"), + ) + monkeypatch.delenv("COLORTERM", raising=False) + + _argv, _cwd, env = self.ws_module._resolve_chat_argv() + + assert env["COLORTERM"] == "truecolor" + + def test_resolve_chat_argv_keeps_operator_colorterm(self, monkeypatch): + """An explicit operator COLORTERM wins over the backfill.""" + import hermes_cli.main as main_mod + + monkeypatch.setattr( + main_mod, + "_make_tui_argv", + lambda project_root, tui_dev=False: (["node", "dist/entry.js"], "/tmp/ui-tui"), + ) + monkeypatch.setenv("COLORTERM", "24bit") + + _argv, _cwd, env = self.ws_module._resolve_chat_argv() + + assert env["COLORTERM"] == "24bit" + def test_resolve_chat_argv_applies_terminal_backend_config( self, monkeypatch, _isolate_hermes_home ):