Merge pull request #3688 from nesquena/release/stage-verdigris

Release v0.51.281 — Release IW (stage-verdigris — Verdigris emerald/bronze skin #3602)
This commit is contained in:
nesquena-hermes authored and GitHub committed 2026-06-05 15:27:56 -07:00
commit e663bc98d6
8 files changed
+111 -16

No files matched your search

+5
View File
@@ -3,6 +3,11 @@
## [Unreleased]
## [v0.51.281] — 2026-06-05 — Release IW (stage-verdigris — Verdigris emerald/bronze skin)
### Added
- **New "Verdigris" appearance skin** — a dark-only emerald/forest-green palette (`#0F1714` background, `#121D18` sidebar) with bronze-gold accents (`#C89A5A`), named for the green-bronze patina on aged copper. Selectable in Settings → Appearance and via `/theme verdigris`. Fully scoped under `:root.dark[data-skin="verdigris"]` (no bleed into the default appearance or other skins), with component-level accents for the new-chat button, scrollbar, tool cards, tree viewer, session badges/tags, diff blocks, MCP status, and image lightbox. (#3602, @rodboev; closes #3357)
## [v0.51.280] — 2026-06-05 — Release IV (stage-p3i — Windows self-update restart fix)
### Fixed
+1
View File
@@ -5127,6 +5127,7 @@ _SETTINGS_SKIN_VALUES = {
"nous",
"geist-contrast",
"zeus",
"verdigris",
}
_SETTINGS_LEGACY_THEME_MAP = {
# Legacy full themes now map onto the closest supported theme + accent skin pair.
+1
View File
@@ -1502,6 +1502,7 @@ const _SKINS=[
{name:'Neon', colors:['#B347FF','#C76BFF','#00DDFF']},
{name:'Geist Contrast', value:'geist-contrast', colors:['#000000','#ffffff','#FFF175']},
{name:'Zeus', colors:['#FFD700','#FFBF00','#1A1A00']},
{name:'Verdigris', value:'verdigris', colors:['#C89A5A','#0F1714','#22342C']},
];
const _VALID_THEMES=new Set((_THEMES||[]).map(t=>t.value));
const _VALID_SKINS=new Set((_SKINS||[]).map(s=>(s.value||s.name).toLowerCase()));
+12 -12
View File
@@ -202,7 +202,7 @@ const LOCALES = {
cmd_terminal: 'Open the workspace terminal',
cmd_new: 'Start a new chat session',
cmd_usage: 'Toggle token usage display on/off',
cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Switch agent personality',
cmd_skills: 'List available Hermes skills',
cmd_use: 'Force a skill for the next message',
@@ -1539,7 +1539,7 @@ const LOCALES = {
cmd_terminal: 'Apri il terminale del workspace',
cmd_new: 'Avvia una nuova sessione di chat',
cmd_usage: 'Attiva/disattiva visualizzazione uso token',
cmd_theme: 'Cambia aspetto (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Cambia aspetto (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: "Cambia personalità dell'agente",
cmd_skills: 'Elenca le skill Hermes disponibili',
cmd_use: 'Forza una skill per il prossimo messaggio',
@@ -2868,7 +2868,7 @@ const LOCALES = {
cmd_terminal: 'ワークスペースのターミナルを開く',
cmd_new: '新しいチャットセッションを開始',
cmd_usage: 'トークン使用量表示の ON/OFF を切り替え',
cmd_theme: '外観を切り替え (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: '外観を切り替え (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'エージェントのパーソナリティを切り替え',
cmd_skills: '利用可能な Hermes スキルを一覧表示',
cmd_use: '次のメッセージにスキルを強制適用',
@@ -4159,7 +4159,7 @@ const LOCALES = {
cmd_terminal: 'Открыть терминал рабочей области',
cmd_new: 'Начать новую сессию чата',
cmd_usage: 'Показать или скрыть использование токенов',
cmd_theme: 'Переключить внешний вид (тема: system/dark/light, скин: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Переключить внешний вид (тема: system/dark/light, скин: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Переключить личность агента',
cmd_skills: 'Показать доступные навыки Hermes',
cmd_use: 'Принудительно применить навык к следующему сообщению',
@@ -5459,7 +5459,7 @@ const LOCALES = {
cmd_terminal: 'Abrir terminal del espacio de trabajo',
cmd_new: 'Iniciar una nueva sesión de chat',
cmd_usage: 'Activar o desactivar el uso de tokens',
cmd_theme: 'Cambiar apariencia (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Cambiar apariencia (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Cambiar la personalidad del agente',
cmd_skills: 'Listar las skills de Hermes disponibles',
cmd_use: 'Forzar una skill para el próximo mensaje',
@@ -6700,7 +6700,7 @@ const LOCALES = {
cmd_terminal: 'Workspace-Terminal öffnen',
cmd_new: 'Neue Chat-Sitzung starten',
cmd_usage: 'Token-Verbrauchsanzeige umschalten',
cmd_theme: 'Darstellung wechseln (Theme: system/dark/light, Skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Darstellung wechseln (Theme: system/dark/light, Skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Agenten-Persönlichkeit wechseln',
cmd_skills: 'Verfügbare Hermes-Skills auflisten',
cmd_use: 'Einen Skill für die nächste Nachricht erzwingen',
@@ -7992,7 +7992,7 @@ const LOCALES = {
cmd_terminal: '打开工作区 Terminal',
cmd_new: '新建聊天会话',
cmd_usage: '切换 token 用量显示',
cmd_theme: '切换外观(主题:system/dark/light,皮肤:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: '切换外观(主题:system/dark/light,皮肤:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: '切换 Agent 人设',
cmd_skills: '列出可用的 Hermes 技能',
cmd_use: '为下一条消息强制使用技能',
@@ -9270,7 +9270,7 @@ const LOCALES = {
cmd_terminal: '開啟工作區 Terminal',
cmd_new: '開始新的聊天對話',
cmd_usage: '開啟或關閉 token 用量顯示',
cmd_theme: '切換外觀(主題:system/dark/light,skin:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: '切換外觀(主題:system/dark/light,skin:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: '切換 Agent 角色',
cmd_skills: '列出可用的 Hermes 技能',
cmd_use: '為下一則訊息強制使用技能',
@@ -10518,7 +10518,7 @@ const LOCALES = {
cmd_workspace: 'Trocar workspace por nome',
cmd_new: 'Iniciar nova sessão de chat',
cmd_usage: 'Alternar exibição de uso de tokens',
cmd_theme: 'Trocar aparência (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Trocar aparência (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Trocar personalidade do agente',
cmd_skills: 'Listar skills disponíveis do Hermes',
cmd_use: 'Forçar uma skill para a próxima mensagem',
@@ -11732,7 +11732,7 @@ const LOCALES = {
cmd_terminal: '워크스페이스 터미널 열기',
cmd_new: '새 채팅 세션 시작',
cmd_usage: '토큰 사용량 표시 켜기/끄기',
cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Switch agent personality',
cmd_skills: 'List available Hermes skills',
cmd_use: 'Force a skill for the next message',
@@ -13054,7 +13054,7 @@ const LOCALES = {
cmd_terminal: 'Ouvrez le terminal de l\'espace de travail',
cmd_new: 'Démarrer une nouvelle session de discussion',
cmd_usage: 'Activer/désactiver l\'affichage de l\'utilisation du jeton',
cmd_theme: 'Changer d\'apparence (thème : system/dark/light, skin : default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Changer d\'apparence (thème : system/dark/light, skin : default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Personnalité de l\'agent de commutation',
cmd_skills: 'Lister les compétences Hermès disponibles',
cmd_use: 'Forcer une compétence pour le prochain message',
@@ -14329,7 +14329,7 @@ const LOCALES = {
cmd_terminal: 'Çalışma alanı terminalini açın',
cmd_new: 'Yeni bir sohbet oturumu başlatın',
cmd_usage: 'Token kullanımı ekranını aç/kapat',
cmd_theme: 'Görünümü değiştir (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)',
cmd_theme: 'Görünümü değiştir (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus/verdigris)',
cmd_personality: 'Temsilci kişiliğini değiştir',
cmd_skills: 'Mevcut Hermes becerilerini listele',
cmd_use: 'Sonraki mesaj için bir beceriyi zorla',
+1 -1
View File
@@ -17,7 +17,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Hermes">
<link rel="apple-touch-icon" sizes="512x512" href="static/apple-touch-icon.png">
<script>(function(){try{var themes={light:1,dark:1,system:1},skins={default:1,ares:1,mono:1,graphite:1,slate:1,poseidon:1,sisyphus:1,charizard:1,sienna:1,catppuccin:1,hepburn:1,nous:1,'geist-contrast':1,neon:1,zeus:1},legacy={slate:['dark','slate'],solarized:['dark','poseidon'],monokai:['dark','sisyphus'],nord:['dark','slate'],oled:['dark','default']},t=(localStorage.getItem('hermes-theme')||'dark').toLowerCase(),s=(localStorage.getItem('hermes-skin')||'').toLowerCase(),m=legacy[t],theme=m?m[0]:(themes[t]?t:'dark'),skin=skins[s]?s:(m?m[1]:'default');localStorage.setItem('hermes-theme',theme);localStorage.setItem('hermes-skin',skin);if(theme==='system')theme=window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';if(theme==='dark')document.documentElement.classList.add('dark');if(skin!=='default')document.documentElement.dataset.skin=skin;}catch(e){document.documentElement.classList.add('dark');}})()</script>
<script>(function(){try{var themes={light:1,dark:1,system:1},skins={default:1,ares:1,mono:1,graphite:1,slate:1,poseidon:1,sisyphus:1,charizard:1,sienna:1,catppuccin:1,hepburn:1,nous:1,'geist-contrast':1,neon:1,zeus:1,'verdigris':1},legacy={slate:['dark','slate'],solarized:['dark','poseidon'],monokai:['dark','sisyphus'],nord:['dark','slate'],oled:['dark','default']},t=(localStorage.getItem('hermes-theme')||'dark').toLowerCase(),s=(localStorage.getItem('hermes-skin')||'').toLowerCase(),m=legacy[t],theme=m?m[0]:(themes[t]?t:'dark'),skin=skins[s]?s:(m?m[1]:'default');localStorage.setItem('hermes-theme',theme);localStorage.setItem('hermes-skin',skin);if(theme==='system')theme=window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';if(theme==='dark')document.documentElement.classList.add('dark');if(skin!=='default')document.documentElement.dataset.skin=skin;}catch(e){document.documentElement.classList.add('dark');}})()</script>
<script>(function(){try{var fs=localStorage.getItem('hermes-font-size');if(fs&&fs!=='default')document.documentElement.dataset.fontSize=fs;}catch(e){}})()</script>
<!-- theme-color: surfaces the active app chrome color to native status bars (Safari status bar, PWA, native WKWebView wrappers). Updated dynamically by boot.js when theme/skin changes. The light/dark default values match style.css :root --sidebar / :root.dark --sidebar. -->
<meta name="theme-color" content="#FAF7F0" media="(prefers-color-scheme: light)">
+48
View File
@@ -755,6 +755,54 @@
:root.dark[data-skin="zeus"] .kanban-modal-overlay{background:rgba(0,0,0,.72);}
:root.dark[data-skin="zeus"] .kanban-board-switcher-menu{background:linear-gradient(180deg,rgba(24,24,24,.99),rgba(15,15,15,.99));border-color:rgba(255,215,0,0.15);}
/* ═══ VERDIGRIS — emerald/bronze dashboard palette (dark-only) ═══ */
:root.dark[data-skin="verdigris"]{
--bg:#0F1714;--sidebar:#121D18;--border:#22342C;--border2:rgba(200,154,90,0.10);
--text:#F3ECDD;--muted:#A8B4A5;--accent:#C89A5A;--blue:#C89A5A;--gold:#C89A5A;--code-bg:#111B17;
--surface:#16211C;--topbar-bg:rgba(15,23,20,.98);--main-bg:rgba(22,33,28,.55);
--focus-ring:rgba(200,154,90,.30);--focus-glow:rgba(200,154,90,.10);
--input-bg:rgba(255,255,255,.025);--hover-bg:rgba(255,255,255,.045);
--strong:#FFF8EB;--em:#D8C5AA;--code-text:#D6AE74;--code-inline-bg:rgba(200,154,90,.08);--pre-text:#F3ECDD;
--accent-hover:#D6AE74;--accent-bg:rgba(200,154,90,.08);--accent-bg-strong:rgba(200,154,90,.14);--accent-text:#E4C28D;
--error:#D26A6A;--success:#719A68;--warning:#D1A45C;--info:#C89A5A;
--radius-sm:1px;--radius-md:2px;--radius-card:2px;--radius-lg:4px;
--surface-subtle:rgba(255,255,255,.02);--surface-subtle-hover:rgba(255,255,255,.04);
--border-subtle:rgba(255,255,255,.06);--border-muted:rgba(255,255,255,.10);
}
/* ── Verdigris skin: component-level overrides ── */
/* New chat button: gold */
:root.dark[data-skin="verdigris"] .new-chat-btn{background:var(--accent);border-color:var(--accent);color:#0F1714;font-weight:600;}
:root.dark[data-skin="verdigris"] .new-chat-btn:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:#0F1714;}
/* Scrollbar: gold tint */
:root.dark[data-skin="verdigris"]::-webkit-scrollbar-thumb{background:rgba(200,154,90,.20);border-radius:3px;}
:root.dark[data-skin="verdigris"]::-webkit-scrollbar-thumb:hover{background:rgba(200,154,90,.35);}
:root.dark[data-skin="verdigris"]{scrollbar-width:thin;scrollbar-color:rgba(200,154,90,.20) transparent;}
/* Tool cards */
:root.dark[data-skin="verdigris"] .tool-card{background:rgba(200,154,90,0.03);border-color:rgba(200,154,90,0.08);}
:root.dark[data-skin="verdigris"] .tool-card:hover{border-color:rgba(200,154,90,0.18);}
:root.dark[data-skin="verdigris"] .tool-card-running{background:var(--accent-bg);border-color:var(--accent-bg-strong);}
:root.dark[data-skin="verdigris"] .tool-arg-key,
:root.dark[data-skin="verdigris"] .tool-card-more{color:var(--accent-text);}
:root.dark[data-skin="verdigris"] .tool-card-running-dot{background:var(--accent);}
/* Tree viewer: gold family */
:root.dark[data-skin="verdigris"] .tree-key{color:#C89A5A;}
:root.dark[data-skin="verdigris"] .tree-str{color:#E4C28D;}
:root.dark[data-skin="verdigris"] .tree-num{color:#C89A5A;}
:root.dark[data-skin="verdigris"] .tree-bool{color:#C89A5A;}
/* Session badges/tags */
:root.dark[data-skin="verdigris"] .session-child-count{background:rgba(200,154,90,.14);color:#E4C28D;}
:root.dark[data-skin="verdigris"] .session-child-count:hover{background:rgba(200,154,90,.24);color:#F0D0A0;}
:root.dark[data-skin="verdigris"] .session-tree-badge{background:rgba(200,154,90,.16);color:#E4C28D;}
:root.dark[data-skin="verdigris"] .session-tag{background:rgba(200,154,90,.16);color:#E4C28D;}
/* Diff blocks */
:root.dark[data-skin="verdigris"] .diff-block .diff-plus{color:#C89A5A;}
/* MCP status */
:root.dark[data-skin="verdigris"] .mcp-http{color:#E4C28D;}
:root.dark[data-skin="verdigris"] .mcp-status-active{color:#E4C28D;}
/* Image lightbox */
:root.dark[data-skin="verdigris"] .img-lightbox-close:hover{background:rgba(200,154,90,.35);}
:root.dark[data-skin="verdigris"] .img-lightbox-nav:hover{background:rgba(200,154,90,.40);}
/* #594: app-dialog light mode overrides — base styles use hardcoded dark gradients */
:root:not(.dark) .app-dialog{
background:linear-gradient(180deg,rgba(240,237,232,.99),rgba(228,224,216,.99));
+41
View File
@@ -0,0 +1,41 @@
"""Verdigris skin registration and emerald/bronze palette affordances."""
from pathlib import Path
REPO = Path(__file__).parent.parent
CSS = (REPO / "static" / "style.css").read_text(encoding="utf-8")
BOOT_JS = (REPO / "static" / "boot.js").read_text(encoding="utf-8")
CONFIG_PY = (REPO / "api" / "config.py").read_text(encoding="utf-8")
INDEX_HTML = (REPO / "static" / "index.html").read_text(encoding="utf-8")
I18N_JS = (REPO / "static" / "i18n.js").read_text(encoding="utf-8")
def test_verdigris_skin_is_registered_in_all_files():
assert "{name:'Verdigris'" in BOOT_JS
assert "'verdigris':1" in INDEX_HTML
assert '"verdigris"' in CONFIG_PY
def test_verdigris_dark_palette_is_emerald():
assert ':root.dark[data-skin="verdigris"]' in CSS
assert "--bg:#0F1714" in CSS
assert "--sidebar:#121D18" in CSS
assert "--border:#22342C" in CSS
def test_verdigris_accent_is_bronze():
assert "--accent:#C89A5A" in CSS
assert "--accent-hover:#D6AE74" in CSS
assert "--focus-ring:rgba(200,154,90,.30)" in CSS
def test_verdigris_has_no_light_variant():
# The skin is dark-only; no light root block should be registered.
assert ':root[data-skin="verdigris"]{' not in CSS
assert ':root[data-skin=\"verdigris\"]{\n' not in CSS
def test_verdigris_i18n_lists_skin_in_all_locales():
# There are 12 locales; each should now include verdigris as the trailing skin.
# 10 locales use ASCII closing paren, 2 Chinese locales use full-width paren.
assert I18N_JS.count("verdigris)") + I18N_JS.count("verdigris)") == 12
+2 -3
View File
@@ -44,6 +44,5 @@ def test_zeus_modals_are_not_navy():
def test_zeus_i18n_lists_skin_in_all_locales():
# Zeus is the last skin in each locale's cmd_theme string, so it appears
# as `…/zeus)` rather than `/zeus/`. There are 10 locales.
assert I18N_JS.count("zeus)") == 10
# There are 12 locales; each should include zeus in the skin list.
assert I18N_JS.count("/zeus/") == 12