* refactor: replace jobs proxy with local controller and optimize model loading
- Add local jobs controller that directly fetches upstream gateway with
profile support and 30s timeout, replacing unreliable proxy catch-all
- Upstream errors (non-200) return 502 instead of leaking to frontend
- Switch loadModels() from fetchAvailableModels (slow, fetches all
provider APIs) to fetchConfigModels (reads config.yaml only)
- Hide logo dance video in sidebar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve TypeScript errors from previous refactor
- Remove unused imports (danceVideo, useTheme) in AppSidebar
- Map ConfigModelsResponse.groups to AvailableModelGroup[] format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(models): add custom model name input with provider selector
- Add custom model input field at bottom of model selector modal
- Add provider dropdown to specify target provider for custom model
- Track custom models in app store and display with CUSTOM badge
- Merge custom model into provider group list
- Fix custom provider models being overwritten by API response (keep both)
* Upload screenshot
* fix(i18n): add i18n support for custom model feature in ModelSelector
Replace hardcoded English strings (CUSTOM badge, placeholder, hint) with
vue-i18n t() calls and add corresponding translation keys to all 8 locales
(en, zh, ja, ko, fr, es, de, pt).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: toller892 <892@users.noreply.github.com>
Co-authored-by: Tony <125938283+toller892@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Log rotation previously only ran at startup, causing logs to grow
indefinitely on long-running processes (reported up to 71GB/day).
Now checks file size every 60 seconds and truncates when exceeding 3MB.
Fixes#155
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Display persistent warning bar when Node.js version < 23
- Fix provider model fetching to support non-v1 API versions (e.g. /v4)
- Add v0.4.4 changelog entries to frontend
- Bump version to 0.4.4
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add file browser and file download with multi-backend support
Adds a built-in File Browser page and a File Download system to Hermes
Web UI, enabling users to browse, edit, preview, upload, and download
files from the workspace directly from the web dashboard.
File Browser (/hermes/files):
- New view FilesView.vue plus components under components/hermes/files/
(FileTree, FileList, FileBreadcrumb, FileToolbar, FileContextMenu,
FileEditor, FilePreview, FileRenameModal, FileUploadModal)
- New Pinia store stores/hermes/files.ts for directory tree, selection,
and editing state
- New API module api/hermes/files.ts
- New server routes routes/hermes/files.ts with CRUD, rename, upload,
and directory listing
- New service services/hermes/file-provider.ts with a pluggable
provider architecture (local filesystem + multi-terminal backends)
File Download:
- New server route routes/hermes/download.ts and client API
api/hermes/download.ts
- Integration in chat messages (MessageItem.vue, MarkdownRenderer.vue)
to surface downloadable file references
Packaging:
- package.json: add a prepare script so the package can be installed
directly from a git URL with dist/ built automatically
i18n: add files/download translations to en.ts and zh.ts.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use clipboard fallback for non-secure HTTP contexts
navigator.clipboard is undefined on HTTP intranet deployments (only
available in secure contexts). The previous synchronous calls threw
silently and the success toast still fired, making 'copy' actions
appear broken.
- Add packages/client/src/utils/clipboard.ts with execCommand fallback
via a hidden textarea
- Use the helper in FileContextMenu (copy file path), CodexLoginModal
(copy user code), NousLoginModal (copy user code), ChatPanel (copy
session id)
- Each call now awaits the result and shows success/failure based on
the actual outcome
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(search): handle numeric query FTS errors regardless of table existence
Remove the `no such table: messages_fts` condition so numeric queries
fall back to LIKE search on any FTS failure (malformed MATCH, missing
table, etc.).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(search): handle special char queries, polish live badge UI
- Add hasUnsafeChars() to catch FTS5-breaking queries (¥, @, #, etc.)
and fall back to LIKE search, preventing 500 errors
- Polish session live badge: smaller size, remove border/shadow,
add pulsing dot indicator for a cleaner look
- Remove spinner drop-shadow glow effect
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(chat): add direct live badge to session rows
* fix(live): use session DB for conversations monitor
* docs: add chat vs live monitor direction plan
* fix(search): avoid numeric session search 500 without FTS table
The isOAuthAuthorized check only looked for Codex's nested
`providers.{key}.tokens.access_token` structure, missing Nous's flat
`providers.nous.access_token`. Now checks both paths so all OAuth
providers are correctly detected and displayed in the provider list.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add StepFun provider (API key auth, STEPFUN_API_KEY)
- Add Nous Portal provider with full OAuth device code flow
(device code request → poll for token → mint agent key → save to auth.json)
- Add NousLoginModal component for OAuth UI (user code display + verification link)
- Update ProviderFormModal to handle Nous OAuth flow (hide API key fields)
- Add nous-auth backend controller and routes
- Update PROVIDER_ENV_MAP with stepfun and nous entries
- Add i18n translations for Nous OAuth in all 8 locales
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add username/password login as additional auth mechanism alongside existing token
- First login must use token; password can be configured in Settings > Account
- Password login returns the existing static token (no auth middleware changes)
- Add account settings: setup, change password, change username, remove password
- Add logout button to sidebar footer
- Add version changelog popup (click version number in sidebar)
- Support all 8 locales (en, zh, de, es, fr, ja, ko, pt)
- Bump version to 0.4.3
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: specify TS_NODE_PROJECT for dev:server script
ts-node/register resolves tsconfig from the entry file upward,
finding the root solution-style tsconfig.json (no compilerOptions).
This causes target to default to ES3, breaking MapIterator spread
syntax (TS2802). Set TS_NODE_PROJECT env var to point to the server
tsconfig which targets ES2024.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add token usage tracking, context display, and dynamic context length
- Intercept SSE proxy to capture run.completed events and persist token
usage (input_tokens, output_tokens) per session to SQLite/JSON store
- Display context usage bar in ChatInput showing used/total/remaining tokens
- Resolve actual context length from Hermes models_dev_cache.json based
on the active profile's default model (fallback 200K), with 5min in-memory cache
- Move sessions-db.ts to db/hermes/ for unified database layer
- Add usage store with SQLite + JSON fallback (auto-migration via ensureTable)
- Fix proxy SSE path regex to match rewritten upstream path
- Fix route ordering: /sessions/usage before /sessions/:id to avoid 404
- Fetch per-session usage on session enter instead of batch
- Add unit tests for usage-store, db index, and proxy SSE interception
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add single-page live session monitor and chat pinning
* fix: restore full test green after main merge
* fix: use Array.from instead of Set spread for ts-node compatibility
[...new Set()] requires downlevelIteration which isn't enabled in
ts-node dev mode, causing sonic-boom crash on startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: ekko <fqsy1416@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add glm-coding-plan to PROVIDER_ENV_MAP for proper env mapping
- Rename GLMCodingPlan value from 'glm' to 'glm-coding-plan' (kebab-case)
- Match custom providers against PROVIDER_PRESETS to reuse builtin models
- Fix provider key matching in create/update (use entry.name consistently)
- Clear stale base_url/api_key from config on provider create
- Clear model config when all providers are removed
- Add gateway restart on provider remove
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(chat): polish syntax highlighting and tool payload rendering (#94)
* [verified] feat(chat): polish syntax highlighting and tool payload rendering
* [verified] fix(chat): tighten large tool payload rendering
* docs: update data volume path in Docker docs
Align documentation with docker-compose.yml change:
hermes-web-ui-data -> hermes-web-ui, /app/dist/data -> /root/.hermes-web-ui
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: bundle server build and restructure service modules
- Add build-server.mjs script for standalone server compilation
- Add logger service with structured output
- Restructure auth, gateway-manager, hermes-cli, hermes services
- Update docker-compose volume mount path
- Update tsconfig and entry point for bundled server
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: separate controllers from routes and centralize route registration
- Extract business logic from route handlers into controllers/
- Add centralized route registry in routes/index.ts with public/auth/protected layers
- Replace global auth whitelist with sequential middleware registration
- Extract shared helpers to services/config-helpers.ts
- Allow custom provider name to be user-editable in ProviderFormModal
- Deduplicate custom providers by poolKey instead of base_url in getAvailable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: auth bypass via path case, SPA serving, and provider improvements
- Fix auth bypass: path case-insensitive check for /api, /v1, /upload
- Fix SPA returning 401: skip auth for non-API paths (static files)
- Fix profile switch: use local loading state instead of shared store ref
- Auto-append /v1 to base_url when fetching models (frontend + backend)
- Guard .env writing to built-in providers only
- Add builtin field to provider presets, enable base_url input in form
- Print auth token to console on startup (pino only writes to file)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Zhicheng Han <43314240+hanzckernel@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract inline middleware from index.ts into separate modules
- Extract update middleware to routes/update.ts
- Extract health middleware and version logic to routes/health.ts
- Extract shutdown logic to services/shutdown.ts
- Extract gateway init to services/gateway-bootstrap.ts
- Remove unused variables, fix duplicate app creation
- Bump version to 0.4.0
index.ts: 260 lines → 80 lines
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: require auth for file upload and add 50MB size limit
Fixes#86
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Extract update middleware to routes/update.ts
- Extract health middleware and version logic to routes/health.ts
- Extract shutdown logic to services/shutdown.ts
- Extract gateway init to services/gateway-bootstrap.ts
- Remove unused variables, fix duplicate app creation
- Bump version to 0.4.0
index.ts: 260 lines → 80 lines
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Normalize request path to lowercase before auth check to prevent
bypassing authentication with uppercase paths like /API/hermes/sessions
- Auto-restart server after in-page update via detached hermes-web-ui restart
Closes#77
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix multipart upload parsing to use Buffer operations instead of latin1
string conversion, preserving multi-byte characters in filenames (#72)
- Support RFC 5987 filename* encoding for cross-platform compatibility
- Fix in-page update by running npm install directly instead of CLI command
that kills the server process before response is sent (#71)
- Add no-cache header to version check to avoid stale latest version
- Change version check interval from 4 hours to 1 hour
Closes#72, Closes#71
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Profile-aware proxy: inject API key from profile-specific .env, route requests via X-Hermes-Profile header
- Remove auth.json dependency: built-in providers use .env, custom providers use config.yaml
- Add allProviders field to available-models response with all hardcoded provider catalogs
- Add Models tab in Settings for editing provider API keys (built-in → .env, custom → config.yaml)
- Add PUT /api/config/providers/:poolKey for updating provider credentials
- ProviderFormModal uses backend allProviders for preset dropdown
- Gateway log format support: parse both agent and gateway log formats
- Add webui server.log to log viewer with log rotation at 3MB
- Fix provider delete loading state and OAuth provider cleanup
- Setup script: require Node.js 23+, auto-upgrade if version too low
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When multiple providers share the same model name, the selector now
uses both model ID and provider as the unique identifier instead of
model name alone. Backend returns default_provider alongside default
model, and model switching sends provider to the config.
Fixes#52
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix chat store cache keys to include profile name, prevent data leaking between profiles
- Defer cache hydration to after profile load to avoid race condition
- Remove collapsible sidebar feature (not needed)
- Remove confirmation dialog on profile switch (direct reload)
- Auto-start gateway when creating new profile
- Clear profile-specific localStorage cache on profile delete (safe prefix matching)
- Clean up unused imports in SettingsView
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add GatewayManager for multi-profile gateway lifecycle management
- Auto-detect running gateways on startup via PID + health check
- Port conflict detection: check managed gateways, allocated ports, and
system-level port availability (TCP bind test)
- Two-phase startup: sequential port resolution, parallel process launch
- Use `gateway start/restart` on normal systems, `gateway run --replace`
on WSL/Docker
- Wait for health check before returning start/stop responses
- Add Gateways page with card-based layout showing profile status
- Reorganize sidebar navigation into collapsible groups
- Hide API server settings (now auto-managed by GatewayManager)
- Profile switch reloads page; Ctrl+C no longer stops gateways
- Remove redundant ensureApiServerConfig from index.ts and profiles.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace static top-level import with runtime version check and dynamic
import() so Node < 22.5 gracefully falls back to CLI path instead of
crashing at module load time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SQLite path was returning null title for sessions without an explicit
title, while the CLI path derives it from the first user message.
Now uses the preview (first user message content) as title fallback,
matching the original CLI behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add OpenAI Codex Device Code Flow login (backend polling + frontend modal)
- Codex provider integrated into preset dropdown (hides URL/API key fields)
- Sync provider model catalogs with Hermes system
- Fix channel config not displaying on first visit (wait for data load)
- Fix sidebar model list not refreshing after adding provider
- Add autocomplete="off" to API key input to prevent browser autofill
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Allow manual model name input when adding custom providers (NSelect tag mode)
- Sync provider model catalogs with Hermes _PROVIDER_MODELS
- Add new providers: kimi-coding-cn, moonshot, arcee
- Fix provider key naming to match Hermes (kilo→kilocode, vercel→ai-gateway, etc.)
- Ensure custom_providers from config.yaml always appear in available-models
- Append configured default model to model list if not in catalog
- Fix provider deletion with case-insensitive key matching
- Add selectOrInput i18n key to all 8 locales
Closes#24
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backend: replace shallow merge with recursive deepMerge in PUT /api/hermes/config
to prevent nested config fields from being lost when updating partial values
- Frontend: switch all NInput fields to default-value + @change (save on blur)
instead of :value + @update:value (save on every keystroke) in both
PlatformSettings.vue and SettingsView.vue api_server tab
- Remove unused debounce logic and dead changeKey function
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix#25: job update sends schedule as plain string but upstream expects
{ kind, expr, display } object, causing "'str' object has no attribute 'get'"
- Move hermes-cli.ts, hermes.ts, hermes-profile.ts into services/hermes/
for multi-agent namespacing consistency
- Fix ts-node Set spread compatibility in filesystem.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add MiniMax-M2.7/M2.5/M2.1/M2 -highspeed variants for both
international and China providers (#17)
- Deduplicate models in /available-models response to fix
repeated entries when using Copilot or other providers (#18)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- add docker-compose setup with hermes-agent + hermes-webui
- make runtime config env-driven (compose vars + HERMES_BIN)
- improve gateway startup/restart resilience in docker
- make base image configurable via BASE_IMAGE/HERMES_AGENT_IMAGE
Closes https://github.com/EKKOLearnAI/hermes-web-ui/issues/14
Node-pty's darwin helper can lose its execute bit in local installs, which leaves the module loadable but causes terminal session creation to fail with posix_spawnp errors. Normalize helper permissions before loading node-pty and remove the rebuild-only hint so startup repairs the real failure mode automatically.
Constraint: Must preserve Node 24 and the existing node-pty integration path
Rejected: Pipe fallback transport | loses true PTY behavior such as proper terminal semantics
Rejected: Tell users to run npm rebuild node-pty | rebuild alone did not restore the helper execute bit here
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If a future node-pty release changes helper locations, update the helperCandidates list before touching terminal startup again
Tested: npm run build
Tested: WebSocket terminal session create + echo command on localhost:8648 under Node 24/macOS
Not-tested: Non-macOS helper layouts
- Set up Vitest with jsdom for client tests, node for server tests
- Add tests for auth service, proxy handler, API client, and profiles store
- Strip Authorization header in proxy to prevent web-ui token leaking to gateway
- Distinguish local BFF vs proxied gateway 401s to avoid false logouts
- Remove unused hero.png asset
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change profile import from server path input to browser file upload (multipart)
- Fix startup script to wait for health check before opening browser
- Add overflow scroll with hidden scrollbar to sidebar nav
- Graceful degradation when node-pty fails to load (WSL compatibility)
- Remove rename button from profile cards
- Restrict profile name input to English letters, numbers, hyphens
- Use raw.githubusercontent.com URLs in README setup script
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add hermes-profile.ts for dynamic profile path resolution (all backend
routes now read from active profile directory instead of hardcoded ~/.hermes/)
- Add profile switcher dropdown in sidebar, reload page on switch
- Sync PROVIDER_PRESETS with Hermes CLI (fix keys: kimi-coding→kimi-for-coding,
kilocode→kilo, ai-gateway→vercel, opencode-zen→opencode; remove moonshot)
- Sync PROVIDER_ENV_MAP with Hermes models.dev + overlays (correct env var names)
- Add gateway restart after adding model provider
- Don't write GLM_BASE_URL/KIMI_BASE_URL for zai/kimi (let Hermes auto-detect)
- Write API keys to .env and credential_pool for all providers
- Built-in providers skip custom_providers in config.yaml
- Add debounce + per-field loading state for channel settings inputs
- Run hermes setup --reset for profiles without config.yaml
- Create empty .env for new profiles (not copied from default)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplify ensureApiServerConfig to unconditionally write default
platforms.api_server values, preventing missing config issues.
Bump version to 0.2.7.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add frontend API layer, Pinia store, and 5 components (ProfileCard, ProfilesPanel, ProfileCreateModal, ProfileRenameModal, ProfileImportModal)
- Add ProfilesView page with card grid layout and expandable details
- Modify export endpoint to stream file as browser download instead of returning server path
- Add sidebar nav entry, router route, and i18n translations (en/zh)
- Support create, rename, delete, switch (with gateway restart), export, and import profiles
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>