From 5f3936d4df64af816e6bd6bd32c1e5831df868ae Mon Sep 17 00:00:00 2001 From: Joshua Timothy <19790363+jdtimothy@users.noreply.github.com> Date: Sat, 8 Aug 2026 01:39:19 +0000 Subject: [PATCH] docs: clarify Theme Switcher SSH setup --- README.md | 35 ++++++++++++++++++++++++++--------- tests/test_theme_pack.py | 19 +++++++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index dab04b5..4b3bbf6 100644 --- a/README.md +++ b/README.md @@ -136,10 +136,12 @@ Every theme is generated from a seed palette by `scripts/generate_themes.py`, wh Re-run the generator to regenerate all skins and the preview gallery, or edit any `.yaml` by hand and reload. -## Theme Switcher (desktop browser) +## Theme Switcher (native Desktop app) The pack also ships a **Theme Switcher** desktop plugin: a "Themes" entry in the app's left sidebar (like Achievements) that lists every installed skin, marks the active one, and applies a new one with one click. No terminal needed to flip themes. +The Themes page is for the **native Hermes Desktop app only**. It does not load in `hermes dashboard`, whose browser UI uses a separate plugin SDK and bundle format. The skins themselves still work across Hermes surfaces; this limitation applies only to the Theme Switcher page. + Features: - **Every skin in one view** — all installed skins in a compact grid, grouped by category, each card showing the real palette (accent line, name, swatches, description) @@ -154,20 +156,35 @@ Features: - **Statusbar chip** — the bottom bar shows the active theme with its color dot; click to open the Themes page - **Command palette** — ⌘K → "Themes: Open" -Install the backend and desktop plugin: +Install the backend and desktop plugin. With a local Desktop connection, both commands run on the same machine. With Desktop over SSH, install the backend on the **remote backend host** and the UI plugin on the **local Desktop computer**. + +On the Hermes backend host: ```bash -# backend plugin -mkdir -p ~/.hermes/plugins/theme-switcher -cp -R plugins/theme-switcher/* ~/.hermes/plugins/theme-switcher/ +mkdir -p "${HERMES_HOME:-$HOME/.hermes}/plugins/theme-switcher" +cp -R plugins/theme-switcher/* "${HERMES_HOME:-$HOME/.hermes}/plugins/theme-switcher/" hermes plugins enable theme-switcher +``` + +On the computer running the native Hermes Desktop app: + +macOS or Linux: + +```bash +mkdir -p "${HERMES_HOME:-$HOME/.hermes}/desktop-plugins/theme-switcher" +cp desktop-plugin/theme-switcher/plugin.js "${HERMES_HOME:-$HOME/.hermes}/desktop-plugins/theme-switcher/" +``` + +Windows PowerShell: -# desktop plugin -mkdir -p ~/.hermes/desktop-plugins/theme-switcher -cp desktop-plugin/theme-switcher/plugin.js ~/.hermes/desktop-plugins/theme-switcher/ +```powershell +$hermesHome = if ($env:HERMES_HOME) { $env:HERMES_HOME } else { Join-Path $env:LOCALAPPDATA "hermes" } +$destination = Join-Path $hermesHome "desktop-plugins\theme-switcher" +New-Item -ItemType Directory -Force -Path $destination | Out-Null +Copy-Item ".\desktop-plugin\theme-switcher\plugin.js" $destination ``` -Restart the app once so the backend mounts, then open **Themes** from the sidebar. +The backend API routes are mounted when the Hermes backend server starts. If the backend was already running when you enabled the plugin, restart or reconnect it before opening **Themes**; reloading the page or desktop plugin alone cannot mount a missing backend route. For Desktop over SSH, disconnect and reconnect first. If Desktop enters a verification loop or the fresh connection still returns 404, use nonce-aware stale Desktop SSH backend recovery: verify that the process matches Desktop's ownership nonce, terminate only that matching backend, and remove only its matching lock/token state before reconnecting. Do not kill the backend PID directly, because leaving its ownership state behind can prevent Desktop from verifying or restarting the connection. ## Development diff --git a/tests/test_theme_pack.py b/tests/test_theme_pack.py index 1b7e383..585d0e9 100644 --- a/tests/test_theme_pack.py +++ b/tests/test_theme_pack.py @@ -165,6 +165,25 @@ def category_of(name): assert mentioned == names, f"README table missing themes: {sorted(names - mentioned)}" +def test_readme_distinguishes_desktop_ui_from_web_dashboard_and_remote_backend(): + """Install guidance must name both plugin systems and both SSH hosts.""" + readme = (REPO / "README.md").read_text() + section_match = re.search( + r"^## Theme Switcher \(native Desktop app\)\n(?P.*?)(?=^## )", + readme, + re.MULTILINE | re.DOTALL, + ) + + assert section_match, "README must identify the native Desktop plugin in its heading" + section = section_match.group("body") + assert "does not load in `hermes dashboard`" in section + assert "remote backend host" in section + assert "local Desktop computer" in section + assert "$env:LOCALAPPDATA" in section + assert "nonce-aware stale Desktop SSH backend recovery" in section + assert "Do not kill the backend PID directly" in section + + def test_twin_pairs_resolve_to_real_opposite_polarity_themes(): """Every light/dark twin pair names existing themes of opposite polarity.