fix: Windows/Termux compatibility, comic theme fonts, and UI fixes (#630)

* fix: comprehensive Windows compatibility and gateway management improvements

This commit addresses multiple Windows compatibility issues and improves
gateway management across all platforms.

## Windows Compatibility Fixes
- Add hermes-path.ts with cross-platform Hermes home/bin detection
- Fix Windows native installation paths (%LOCALAPPDATA%\hermes)
- Update terminal.ts to use PowerShell instead of /bin/bash on Windows
- Fix upload.ts path construction to use path.join() for cross-platform paths
- Fix download.ts to use isAbsolute() for Windows absolute path detection
- Update auth.ts to skip file mode 0o600 on Windows (unsupported)
- Add nodemon.json for cross-platform environment variable handling

## Gateway Management Improvements
- Simplify gateway startup: all platforms use 'run' mode uniformly
- Remove complex init system detection and platform-specific code paths
- Improve PID file validation: use health check instead of port detection
- Remove getPortByPid() method (too complex and error-prone)
- Remove checkPortAvailable() TCP bind test (TIME_WAIT false positives)
- Trust gateway --replace flag to handle real port conflicts
- Add smart PID validation: check if stale process via health check
- Fix port allocation to avoid incrementing when gateway restarts
- Add allocatedPorts.clear() on each startAll() call
- Add clearPidFile() method to clean up stale PID files

## Process Management
- Remove detached:true and unref() from gateway spawn
- Gateway processes now follow parent process lifecycle
- Add process reference storage in ManagedGateway interface
- Improve shutdown logic: call gatewayManager.stopAll() before exit
- Fix Windows process killing: use process.kill(pid) for Windows
- Remove PowerShell command for lock file cleanup (use Node.js fs.unlinkSync)

## Frontend Theme Fixes
- Fix main.ts localStorage key mismatch (hermes_theme → hermes_brightness)
- Add inline script in index.html to prevent FOUC (Flash of Unstyled Content)
- Apply theme classes before Vue mount to avoid visual glitches

## Developer Experience
- Fix nodemon windows-kill popup on Windows by removing signal config
- Add delay and environment variables to nodemon.json
- Add windowsHide: true to all child process spawns

## Breaking Changes
- Gateway management now exclusively uses 'run' mode on all platforms
- systemd/launchd integration removed (use --replace flag instead)

This fix ensures hermes-web-ui works correctly on Windows native
installations while maintaining compatibility with Linux/macOS/WSL2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix gateway lifecycle port handling

* fix: comprehensive Windows compatibility and gateway management improvements

- Simplified hermes CLI binary resolution logic
- Fixed Windows line ending compatibility in profile list parsing
- Migrated gateway restart logic from CLI to GatewayManager
- Added gateway restart to updateCredentials method
- Removed unnecessary gateway restarts from provider operations
- Fixed configuration preservation when switching profiles
- Added nodemon quiet mode and legacy watch to reduce Windows popups

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* revert: change back to nodemon due to tsx compatibility issues

- tsx has compatibility issues with Koa generator functions
- Restored nodemon with simplified configuration
- Added cross-env package for future Windows environment variable needs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: replace nodemon with ts-node-dev to eliminate Windows popup windows

- Installed ts-node-dev as nodemon replacement
- ts-node-dev has better Windows compatibility without console popups
- Supports respawning, inspector debugging, and TypeScript compilation
- Uses cross-env for Windows environment variable support
- Removed nodemon.json configuration file (no longer needed)

Benefits:
- No more Windows console popup windows during development
- Faster restart times compared to nodemon
- Built-in TypeScript compilation without ts-node overhead

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: improve log parsing and Windows compatibility for agent/error logs

- Fixed Pino JSON log parsing bug where logger field incorrectly used obj.msg
- Changed logger field to use obj.name to properly display log source
- Added Windows line ending support (\r\n) for log file listing
- Added support for 'error' log type in addition to 'errors'
- Improved error message extraction from obj.err when available

This fixes the missing agent and error logs issue on Windows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix gateway health checks and shutdown ownership

* Refine auth lock window and dev shutdown

* fix: improve Hermes plugin discovery on Windows by fixing Python path resolution

- Added support for Windows venv Scripts directory structure
- Fixed Python executable path detection for hermes.exe in venv/Scripts/
- Added Windows LOCALAPPDATA hermes-agent directory to search paths
- Improved cross-platform compatibility for plugin discovery

This fixes the "No module named 'hermes_cli'" error on Windows by correctly
locating the Python virtual environment that contains the Hermes modules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: improve cross-platform compatibility for Hermes plugin discovery

- Added platform detection to only add Windows-specific paths on Windows
- Prevents potential issues on Unix/Linux/macOS systems
- Ensures LOCALAPPDATA path is only used when available on Windows
- Maintains existing behavior for all platforms

This makes the Windows plugin discovery fix safer for cross-platform usage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: remove unused development dependencies

- Removed nodemon (replaced by ts-node-dev)
- Removed tsx (had compatibility issues with Koa)
- Removed nodemon.json configuration file
- Cleaned up development tools to only what's actually used

This reduces dependency size and eliminates the windows-kill popup
source that was part of nodemon.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: remove memory system files

- Removed MEMORY.md index file
- Removed memory/ directory and windows-compatibility.md
- Cleaned up unused memory persistence system

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: resolve TypeScript compilation error in plugins.ts

- Added type assertion 'as string[]' after filter(Boolean)
- Fixes TS2769 error: No overload matches this call
- Ensures type compatibility with hasHermesPluginModule function

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: comprehensive Windows compatibility and gateway management improvements

- Fix gateway detection after nodemon restart by adding health check-based detection
- Prevent port conflicts by detecting already-running gateways without PID files
- Switch to serial gateway startup to avoid lock file race conditions
- Return to nodemon from ts-node-dev for development stability
- Always stop gateways on shutdown to prevent orphan processes
- Prevent project root config files from being committed to git
- Fix syntax issues in plugins.ts

Resolves issues where default profile gateway failed to start after
nodemon restart and gateways were incorrectly marked as stopped
despite running on correct ports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: comic theme multilingual fonts, sidebar collapse fix, plugin discovery for Termux, and cron history

- Add Chinese (ZCOOL KuaiLe), Japanese (Zen Maru Gothic), Korean (Gaegu) handwritten fonts for Comic theme
- Fix collapsed sidebar: hide language switch, stack theme icons vertically
- Add hermes shebang parsing as fallback Python discovery for Termux
- Remove cron source filter from history sessions
- Add 0.5.17 changelog entries for all 8 locales

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: tolerate duplicate YAML keys in config parsing (closes #628)

Add `{ json: true }` to all 7 `yaml.load()` calls so duplicated mapping
keys (e.g. multiple `mcp_servers:` blocks) no longer crash the API.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: gateway ownership check requires PID file to prevent cross-profile port hijacking

Remove fallback that assumed ownership of healthy gateways without PID
verification. Now only claims a gateway if PID file exists and process
is alive, preventing one profile from hijacking another's port.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-05-11 20:08:13 +08:00
committed by GitHub
parent 0d14afe9b4
commit b4a80aceeb
46 changed files with 784 additions and 229 deletions
@@ -688,6 +688,19 @@ function openChangelog() {
.status-row {
justify-content: center;
:deep(.input-sm) {
display: none;
}
}
.version-info {
justify-content: center;
padding: 4px 0;
:deep(.theme-switch-container) {
flex-direction: column;
}
}
}
}
@@ -5,7 +5,7 @@ const { isDark, isComic, toggleBrightness, toggleStyle } = useTheme()
</script>
<template>
<div style="display: flex; gap: 4px; align-items: center;">
<div class="theme-switch-container" style="display: flex; gap: 4px; align-items: center;">
<button class="theme-switch" :title="isComic ? 'Ink style' : 'Comic style'" @click="toggleStyle">
<!-- Palette icon for comic toggle -->
<svg v-if="isComic" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+11
View File
@@ -5,6 +5,17 @@ export interface ChangelogEntry {
}
export const changelog: ChangelogEntry[] = [
{
version: '0.5.17',
date: '2026-05-11',
changes: [
'changelog.new_0_5_17_1',
'changelog.new_0_5_17_2',
'changelog.new_0_5_17_3',
'changelog.new_0_5_17_4',
'changelog.new_0_5_17_5',
],
},
{
version: '0.5.16',
date: '2026-05-10',
+5
View File
@@ -789,6 +789,11 @@ jobTriggered: 'Job ausgelost',
new_0_5_16_2: 'Echte API-Nutzung (Tokens, Cache, Reasoning) in Nutzungsstatistik-Tabelle speichern',
new_0_5_16_3: 'QQ-Gruppen-QR-Code zur Website-Navigationsleiste hinzugefügt',
new_0_5_16_4: 'Unbenutztes codex_reasoning_items-Feld aus dem Nachrichtenschema entfernt',
new_0_5_17_1: 'Vollständige Windows-Kompatibilität: Pfadverarbeitung, Prozessverwaltung, Terminal, Log-Parsing',
new_0_5_17_2: 'Gateway-Prozessverwaltung refaktoriert mit plattformübergreifendem Start/Stop/Health-Check',
new_0_5_17_3: 'Plugin-Erkennung auf Termux repariert durch Parsen des Hermes-Shebangs zur Python-Lokalisierung',
new_0_5_17_5: 'Auth-Sperrfenster und Dev-Shutdown-Ablauf verbessert',
new_0_5_17_6: 'Comic-Theme: Handschriften-Fonts für Chinesisch (ZCOOL KuaiLe), Japanisch (Zen Maru Gothic), Koreanisch (Gaegu) hinzugefügt',
new_0_5_13_1: 'Nachrichtenwarteschlange für sequenzielle Run-Verarbeitung hinzugefügt, um gleichzeitige Konflikte zu vermeiden',
new_0_5_13_2: 'Zwei-Ebenen-Skills-Verzeichnisstruktur mit Sonstige-Kategorie für flache Skills unterstützt',
new_0_5_13_3: 'Temporäre Sitzungen (eph_*) beim Start-Sync filtern, um interne Sitzungen nicht zu importieren',
+5
View File
@@ -1045,6 +1045,11 @@ export default {
new_0_5_16_2: 'Persist real API usage (tokens, cache, reasoning) to usage table',
new_0_5_16_3: 'Add QQ group QR code to website navigation bar',
new_0_5_16_4: 'Remove unused codex_reasoning_items field from message schema',
new_0_5_17_1: 'Full Windows compatibility: path handling, process management, terminal, log parsing',
new_0_5_17_2: 'Refactor Gateway process management with cross-platform start/stop/health-check',
new_0_5_17_3: 'Fix plugin discovery on Termux by parsing hermes shebang to locate Python',
new_0_5_17_5: 'Improve auth lock window and dev shutdown flow',
new_0_5_17_6: 'Add Chinese (ZCOOL KuaiLe), Japanese (Zen Maru Gothic), Korean (Gaegu) handwritten fonts for Comic theme',
new_0_5_13_1: 'Add message queue for sequential run processing to prevent concurrent request conflicts',
new_0_5_13_2: 'Support two-level skills directory structure with misc category for flat skills',
new_0_5_13_3: 'Filter out ephemeral sessions during startup sync to avoid importing internal sessions',
+5
View File
@@ -785,6 +785,11 @@ jobTriggered: 'Job ejecutado',
new_0_5_16_2: 'Persistir uso real de API (tokens, caché, razonamiento) en tabla de estadísticas',
new_0_5_16_3: 'Añadir código QR del grupo QQ a la barra de navegación del sitio web',
new_0_5_16_4: 'Eliminar campo codex_reasoning_items no utilizado del esquema de mensajes',
new_0_5_17_1: 'Compatibilidad completa con Windows: manejo de rutas, gestión de procesos, terminal, análisis de logs',
new_0_5_17_2: 'Refactorizada la gestión de procesos de Gateway con inicio/parada/health-check multiplataforma',
new_0_5_17_3: 'Corregido el descubrimiento de plugins en Termux analizando el shebang de hermes para localizar Python',
new_0_5_17_5: 'Mejorada la ventana de bloqueo de autenticación y el flujo de cierre del entorno de desarrollo',
new_0_5_17_6: 'Tema Comic: fuentes manuales para chino (ZCOOL KuaiLe), japonés (Zen Maru Gothic), coreano (Gaegu)',
new_0_5_13_1: 'Cola de mensajes para procesamiento secuencial de ejecuciones, evitando conflictos concurrentes',
new_0_5_13_2: 'Soporte para estructura de directorios de skills de dos niveles con categoría misc',
new_0_5_13_3: 'Filtrar sesiones efímeras (eph_*) durante la sincronización de inicio',
+5
View File
@@ -784,6 +784,11 @@ jobTriggered: 'Job declenche',
new_0_5_16_2: 'Persistance de l\'utilisation réelle de l\'API (tokens, cache, raisonnement) dans la table des statistiques',
new_0_5_16_3: 'Ajout du code QR du groupe QQ dans la barre de navigation du site',
new_0_5_16_4: 'Suppression du champ codex_reasoning_items inutilisé du schéma de messages',
new_0_5_17_1: 'Compatibilité Windows complète : gestion des chemins, des processus, terminal, analyse des logs',
new_0_5_17_2: 'Refonte de la gestion des processus Gateway avec démarrage/arrêt/health-check multiplateforme',
new_0_5_17_3: 'Correction de la découverte des plugins sur Termux en analysant le shebang hermes pour localiser Python',
new_0_5_17_5: 'Amélioration de la fenêtre de verrouillage d\'authentification et du processus d\'arrêt en dev',
new_0_5_17_6: 'Thème Comic : polices manuscrites pour chinois (ZCOOL KuaiLe), japonais (Zen Maru Gothic), coréen (Gaegu)',
new_0_5_13_1: 'File d\'attente de messages pour le traitement séquentiel des exécutions, évitant les conflits concurrents',
new_0_5_13_2: 'Prise en charge de la structure de répertoire de skills à deux niveaux avec catégorie divers',
new_0_5_13_3: 'Filtrer les sessions éphémères (eph_*) lors de la synchronisation au démarrage',
+5
View File
@@ -785,6 +785,11 @@ export default {
new_0_5_16_2: '実際の API 使用量(トークン、キャッシュ、推論)を統計テーブルに保存',
new_0_5_16_3: 'ウェブサイトのナビゲーションバーにQQグループのQRコードを追加',
new_0_5_16_4: 'メッセージスキーマから未使用の codex_reasoning_items フィールドを削除',
new_0_5_17_1: 'Windows完全対応:パス処理、プロセス管理、ターミナル、ログ解析',
new_0_5_17_2: 'Gatewayプロセス管理をリファクタリング、クロスプラットフォームの起動/停止/ヘルスチェックに対応',
new_0_5_17_3: 'Termuxでhermesのshebangを解析してPythonを見つけ、プラグイン検出を修正',
new_0_5_17_5: '認証ロックウィンドウと開発環境のシャットダウンフローを改善',
new_0_5_17_6: 'Comicテーマに中国語(ZCOOL KuaiLe)、日本語(Zen Maru Gothic)、韓国語(Gaegu)の手書きフォントを追加',
new_0_5_13_1: 'メッセージキューによる順次実行処理で同時リクエストの競合を防止',
new_0_5_13_2: '2階層スキルディレクトリ構造をサポート、フラットスキルは「その他」カテゴリに分類',
new_0_5_13_3: '起動同期時に一時セッション(eph_*)をフィルタリング',
+5
View File
@@ -785,6 +785,11 @@ export default {
new_0_5_16_2: '실제 API 사용량(토큰, 캐시, 추론)을 사용량 통계 테이블에 저장',
new_0_5_16_3: '웹사이트 내비게이션 바에 QQ 그룹 QR 코드 추가',
new_0_5_16_4: '메시지 스키마에서 사용하지 않는 codex_reasoning_items 필드 제거',
new_0_5_17_1: 'Windows 완전 호환: 경로 처리, 프로세스 관리, 터미널, 로그 파싱',
new_0_5_17_2: 'Gateway 프로세스 관리 리팩토링, 크로스 플랫폼 시작/중지/헬스체크 지원',
new_0_5_17_3: 'Termux에서 hermes shebang을 파싱하여 Python을 찾아 플러그인 발견 수정',
new_0_5_17_5: '인증 잠금 창 및 개발 환경 종료 흐름 개선',
new_0_5_17_6: 'Comic 테마에 중국어(ZCOOL KuaiLe), 일본어(Zen Maru Gothic), 한국어(Gaegu) 필기 폰트 추가',
new_0_5_13_1: '메시지 큐를 통한 순차 실행 처리로 동시 요청 충돌 방지',
new_0_5_13_2: '2단계 스킬 디렉토리 구조 지원, 플랫 스킬은 기타 카테고리로 분류',
new_0_5_13_3: '시작 동기화 시 임시 세션(eph_*) 필터링',
+5
View File
@@ -785,6 +785,11 @@ jobTriggered: 'Job acionado',
new_0_5_16_2: 'Persistir uso real da API (tokens, cache, raciocínio) na tabela de estatísticas',
new_0_5_16_3: 'Adicionar código QR do grupo QQ à barra de navegação do site',
new_0_5_16_4: 'Remover campo codex_reasoning_items não utilizado do esquema de mensagens',
new_0_5_17_1: 'Compatibilidade total com Windows: manipulação de caminhos, gerenciamento de processos, terminal, análise de logs',
new_0_5_17_2: 'Refatorado gerenciamento de processos do Gateway com início/parada/health-check multiplataforma',
new_0_5_17_3: 'Corrigida descoberta de plugins no Termux analisando o shebang do hermes para localizar o Python',
new_0_5_17_5: 'Melhorada janela de bloqueio de autenticação e fluxo de desligamento do ambiente de desenvolvimento',
new_0_5_17_6: 'Tema Comic: fontes manuscritas para chinês (ZCOOL KuaiLe), japonês (Zen Maru Gothic), coreano (Gaegu)',
new_0_5_13_1: 'Fila de mensagens para processamento sequencial de execuções, evitando conflitos concorrentes',
new_0_5_13_2: 'Suporte à estrutura de diretório de skills de dois níveis com categoria diversos',
new_0_5_13_3: 'Filtrar sessões efêmeras (eph_*) durante a sincronização na inicialização',
+5
View File
@@ -1047,6 +1047,11 @@ export default {
new_0_5_16_2: '持久化真实 API 用量(token、缓存、推理)到用量统计表',
new_0_5_16_3: '官网导航栏新增 QQ 群二维码',
new_0_5_16_4: '移除消息 schema 中未使用的 codex_reasoning_items 字段',
new_0_5_17_1: '全面兼容 Windows:路径处理、进程管理、终端、日志解析',
new_0_5_17_2: '重构 Gateway 进程管理,支持跨平台启动/停止/健康检查',
new_0_5_17_3: '修复 Termux 环境下插件发现失败的问题,自动解析 hermes shebang 定位 Python',
new_0_5_17_5: '优化认证锁定窗口和开发环境关闭流程',
new_0_5_17_6: 'Comic 主题新增中文(站酷快乐体)、日文(Zen Maru Gothic)、韩文(Gaegu)手写字体',
new_0_5_13_1: '新增消息队列,顺序处理运行请求,避免并发冲突',
new_0_5_13_2: '支持二级 Skills 目录结构,扁平化 Skill 归入"杂项"分类',
new_0_5_13_3: '启动同步时过滤临时会话(eph_*),避免导入内部会话',
+15 -3
View File
@@ -5,12 +5,24 @@ import { i18n } from './i18n'
import App from './App.vue'
import './styles/global.scss'
// Apply dark class before mount to prevent FOUC
const savedTheme = localStorage.getItem('hermes_theme') || 'system'
// Apply theme classes before mount to prevent FOUC (Flash of Unstyled Content)
const savedBrightness = localStorage.getItem('hermes_brightness') || 'system'
const savedStyle = localStorage.getItem('hermes_style') || 'ink'
// Resolve dark mode
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
if (savedTheme === 'dark' || (savedTheme === 'system' && prefersDark)) {
const isDark = savedBrightness === 'dark' || (savedBrightness === 'system' && prefersDark)
// Resolve style
const isComic = savedStyle === 'comic'
// Apply classes to prevent FOUC
if (isDark) {
document.documentElement.classList.add('dark')
}
if (isComic) {
document.documentElement.classList.add('comic')
}
// Read token from URL BEFORE router initializes (hash router strips params)
const urlParams = new URLSearchParams(window.location.search)
+35 -16
View File
@@ -6,15 +6,47 @@
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ComicNeue-Regular.ttf') format('truetype');
src: url('/fonts/ComicNeue-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'Comic Neue';
font-family: 'ZCOOL KuaiLe';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ZCOOLKuaiLe-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Zen Maru Gothic';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ZenMaruGothic-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Zen Maru Gothic';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/ComicNeue-Bold.ttf') format('truetype');
src: url('/fonts/ZenMaruGothic-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'Gaegu';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/Gaegu-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Gaegu';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/Gaegu-Bold.ttf') format('truetype');
}
*,
@@ -68,20 +100,7 @@ body {
-moz-osx-font-smoothing: grayscale;
}
html.comic body {
font-weight: var(--comic-font-weight, 700);
}
html.comic button,
html.comic input,
html.comic select,
html.comic textarea,
html.comic a,
html.comic span,
html.comic div,
html.comic label {
font-weight: var(--comic-font-weight, 700);
}
code, pre, .mono {
font-family: $font-code;
+1 -1
View File
@@ -149,7 +149,7 @@ export const darkThemeOverrides: GlobalThemeOverrides = {
export function getThemeOverrides(isDark: boolean, isComic?: boolean): GlobalThemeOverrides {
const base = isDark ? darkThemeOverrides : lightThemeOverrides
if (!isComic) return base
const comicFont = "'Comic Neue', 'Comic Sans MS', cursive, sans-serif"
const comicFont = "'Comic Neue', 'ZCOOL KuaiLe', 'Zen Maru Gothic', 'Gaegu', cursive, sans-serif"
return {
...base,
common: {
+1 -2
View File
@@ -115,10 +115,9 @@
--msg-system-border: #1a1a1a;
// Comic-specific
--font-ui: 'Comic Neue', 'Comic Sans MS', cursive, sans-serif;
--font-ui: 'Comic Neue', 'ZCOOL KuaiLe', 'Zen Maru Gothic', 'Gaegu', cursive, sans-serif;
--comic-border-width: 2.5px;
--comic-shadow: 3px 3px 0px rgba(0, 0, 0, 0.15);
--comic-font-weight: 700;
}
.dark.comic {