chore: CHANGELOG for v0.50.237 batch (21 PRs)

This commit is contained in:
Hermes Agent
2026-04-29 05:08:28 +00:00
parent 867f2a3f81
commit bbd754a496
+28 -49
View File
@@ -2,58 +2,37 @@
## [Unreleased]
## [v0.50.237] — 2026-04-29
### Added
- **Embedded workspace terminal prototype**`/terminal` opens a compact utility card tucked behind the composer, following the approval-card layering pattern instead of adding a permanent composer icon or full-width dock. The terminal stays bound to the current session workspace with live output, command input, resize, restart, clear, copy output, and close actions. Backend terminal processes use explicit per-process `cwd`/`env` and do not mutate global `os.environ`. (`api/terminal.py`, `api/routes.py`, `static/index.html`, `static/terminal.js`, `static/commands.js`, `static/style.css`, `static/i18n.js`)
- **Embedded workspace terminal**`/terminal` slash command opens a compact PTY-backed terminal card anchored above the composer. Supports collapse/expand/dock, resize, restart, clear, copy output, and per-session workspace binding. Env vars are allowlisted so server credentials are not exposed in the shell. (`api/terminal.py`, `static/terminal.js`, `static/commands.js`, `static/i18n.js`) @franksong2702 — Closes #1099
- **Collapsible JSON/YAML tree viewer** — fenced `json`/`yaml` code blocks get a Tree/Raw toggle. Tree view renders collapsible, type-colored nodes (keys blue, strings green, numbers blue, booleans amber, nulls muted); auto-collapsed beyond depth 2. Default is Tree for blocks with 10+ lines. YAML parsing uses js-yaml loaded lazily via CDN with SRI. (`static/ui.js`, `static/style.css`, `static/i18n.js`) @bergeouss — Closes #484
- **Inline diff/patch viewer** — fenced `diff`/`patch` blocks render with colored `+`/`-`/`@@` lines. `MEDIA:` links to `.patch`/`.diff` files fetch and render inline with a 50 KB cap. (`static/ui.js`, `static/style.css`, `static/i18n.js`) @bergeouss — Closes #483
- **MCP server management UI** — Settings System panel now lists MCP servers with transport badges, and provides add/edit/delete forms. Backend: `GET/PUT/DELETE /api/mcp/servers` with masked secrets (round-trip safe). i18n coverage across 7 locales. (`api/routes.py`, `static/panels.js`, `static/i18n.js`) @bergeouss — Closes #538
- **Cron run status tracking and watch mode** — after "Run Now", the cron detail view shows a live spinner, running label, and elapsed timer (polls every 3 s). Auto-starts watch when opening an already-running job. `GET /api/crons/status` endpoint. Double-run guard prevents concurrent execution of the same job. (`api/routes.py`, `static/panels.js`, `static/style.css`, `static/i18n.js`) @bergeouss — Closes #526
- **Duplicate cron job** — Duplicate button in cron detail header pre-fills the create form with the existing job settings, appends "(copy)" to the name (auto-increments on collision), and saves as paused. (`static/panels.js`, `static/i18n.js`) @bergeouss — Closes #528
- **Upload and extract zip/tar archives into workspace** — zip, tar.gz, tgz, tar.bz2, tar.xz files are auto-extracted into a named subfolder. Zip-slip/tar-slip protection via `is_relative_to()`; zip-bomb protection via 200 MB cumulative extraction limit on actual bytes. (`api/upload.py`, `api/routes.py`, `static/ui.js`, `static/i18n.js`) @bergeouss — Closes #525
- **Workspace directory CRUD** — right-click context menu on workspace file/dir rows adds Rename and Delete for directories. `shutil.rmtree()` guarded by `safe_resolve()` path validation. Expanded-dir cache updated on rename/delete. (`api/routes.py`, `static/ui.js`, `static/i18n.js`) @bergeouss — Closes #1104
- **Workspace drag-to-reorder** — drag handles on workspace rows; `PUT /api/workspaces/reorder` persists new order. Reorder is confirmed (not optimistic); unmentioned workspaces are appended. (`api/routes.py`, `static/panels.js`, `static/i18n.js`) @bergeouss — Closes #492
- **Compress affordance in context ring** — context usage tooltip shows a pre-fill button for `/compress` at ≥50% usage (hint style) and ≥75% (urgent red style). No auto-fire. (`static/ui.js`, `static/index.html`, `static/style.css`, `static/i18n.js`) @bergeouss — Closes #524
- **DeepSeek V4, Z.AI/GLM provider, model tags** — adds `deepseek-v4-flash` and `deepseek-v4-pro`; keeps V3/R1 as `(legacy)` until 2026-07-24. Adds Z.AI/GLM provider (`glm-5.1`, `glm-5`, `glm-5-turbo`, `glm-4.7`, `glm-4.5`, `glm-4.5-flash`). Provider cards show model names; custom providers from `config.yaml` are scanned. (`api/config.py`, `api/onboarding.py`, `static/panels.js`) @jasonjcwu — Closes #1213
- **NVIDIA NIM provider** — adds `nvidia` to the provider catalog with display name, aliases, model list, API key mapping, OpenAI-compat endpoint (`https://integrate.api.nvidia.com/v1`), and onboarding entry. (`api/config.py`, `api/providers.py`, `api/routes.py`, `api/onboarding.py`) @JinYue-GitHub — Closes #1220
### Fixed
- **Background session completion unread dots** — sidebar unread dots no longer
depend solely on `message_count` increasing after a stream finishes. Background
`done` events now set an explicit unread-completion marker, including
session-switch races and hidden/unfocused tabs where the old session is no
longer being viewed. Session-list polling also marks unread when a session the
page previously saw streaming later reports stopped, including local
`INFLIGHT`-only sidebar spinners, cache-rendered visible spinners, and
reconnect/settled-stream fallback paths. Long-running sessions also use a
per-session message snapshot fallback and a persisted observed-running marker
so a completed background turn still becomes unread if the original
SSE/in-memory streaming context was missed or lost during a reload.
The `done` event now also updates the sidebar cache immediately before the
completion cue plays, so the row flips from spinner to unread without waiting
for the next session-list refresh, including auto-compression paths where the
final session id differs from the stream's original id.
The marker clears only when that session is opened or the user returns to the
active completed session.
(`static/sessions.js`,
`static/messages.js`, `tests/test_issue856_background_completion_unread.py`)
- **Auto-title generic fallback** — when the auxiliary title-generation call
fails and the local fallback can only produce the generic label
`Conversation topic`, the WebUI now keeps the existing provisional title
instead of persisting the generic placeholder as a generated title. The
`title_status` diagnostic still preserves the underlying LLM failure reason.
(`api/streaming.py`, `tests/test_title_aux_routing.py`) Closes #1155.
- **Recurring cron jobs with no next run need attention** — the Tasks panel now
distinguishes anomalous recurring jobs (`enabled=false`, `state=completed`,
`next_run_at=null`) from ordinary off jobs, shows a warning with recovery
actions, and lets users copy diagnostics for scheduler/runtime failures.
(`static/panels.js`, `static/style.css`, `static/i18n.js`,
`tests/test_cron_needs_attention.py`)
- **Auto-compression notification uses compression cards** — automatic context
compression now renders as a transient compression card in the transcript
instead of adding an italic fake assistant message, and preserved task-list
snapshots appended by Hermes Agent render as compression sub-cards instead of
ordinary user bubbles. (`static/messages.js`, `static/ui.js`,
`static/i18n.js`)
- **Legacy `@provider:model` session models** — persisted sessions with an
old explicit provider hint (for example `@copilot:gpt-5.5`) now pass through
the same stale-model compatibility recovery as slash-prefixed session models,
so they can continue after the active provider changes. (`api/routes.py`)
- **Docker Hindsight memory provider dependency** — Docker startup now ensures
`hindsight-client` is installed in the WebUI container venv, even on fast
restarts where `/app/venv/.deps_installed` already exists. This lets
two-container WebUI deployments import Hermes Agent's Hindsight memory
provider without a manual container-side install. (`docker_init.bash`,
`tests/test_issue926_hindsight_docker_dependency.py`) Closes #926.
- **Background session unread dots** — sidebar unread dots no longer depend solely on `message_count` delta. Explicit completion markers, polling fallback, INFLIGHT/S.busy sidebar spinner tracking, localStorage-persisted observed-running state, and auto-compression session-id rotation all handled. (`static/sessions.js`, `static/messages.js`) @franksong2702 — Closes #856
- **Clarify draft preserved on timeout** — unsent clarify text is moved to the main composer when the clarify card expires or is dismissed. Countdown indicator shows remaining time; urgent styling for final seconds. (`api/clarify.py`, `static/messages.js`, `static/style.css`, `static/index.html`) @sixianli — Closes #1216
- **Mobile busy-input composer button** — unified send/stop/queue/interrupt/steer action button so mobile users (tap-only) can queue, interrupt, or steer while the agent is busy. Dynamic icon/label/color. Removes separate cancel button path. (`static/ui.js`, `static/messages.js`, `static/sessions.js`, `static/boot.js`, `static/i18n.js`) @starship-s — Closes #1215
- **Session sidecar repair hardened** — centralized `_apply_core_sync_or_error_marker()` helper; non-blocking lock acquire to avoid deadlock in cache-miss repair path; streaming-finally and cache-miss repair paths share logic. (`api/models.py`, `api/streaming.py`) @starship-s — Closes #1230
- **Scroll position preserved when loading older messages**`_loadOlderMessages` now uses `#messages` (the actual scrollable container) instead of `#msgInner`; resets `_scrollPinned` after restoring position so `scrollToBottom` does not re-fire. (`static/sessions.js`) @jasonjcwu — Closes #1219
- **Model picker duplicate IDs across providers**`_deduplicate_model_ids()` detects bare model IDs appearing in 2+ groups and prefixes collisions with `@provider_id:` (deterministic alphabetical tie-break). Frontend `norm()` regex strips `@provider:` prefixes for fuzzy matching. (`api/config.py`, `static/ui.js`) @bergeouss — Closes #1228
- **`/api/models` cache metadata preserved** — disk and TTL cache now include `active_provider` and `default_model` alongside `groups`. Legacy `groups`-only cache files are rejected and rebuilt. (`api/config.py`) @franksong2702 — Closes #1239
- **Clarify model scope copy** — composer model-selector dropdown shows "Applies to this conversation from your next message." sticky note; preferences Default Model shows "Used for new conversations." helper text. (`static/ui.js`, `static/boot.js`, `static/i18n.js`) @franksong2702 — Closes #1241
- **Workspace panel stale after profile switch**`loadDir('.')` called in `switchToProfile()` Case B so the file tree refreshes to the new profile. (`static/panels.js`) @bergeouss — Closes #1214
- **OAuth providers show as unconfigured** — expanded `_OAUTH_PROVIDERS` set; live `get_auth_status()` fallback for unknown OAuth providers (gated by pid regex validation and closed `key_source` allowlist). (`api/providers.py`) @bergeouss — Closes #1212
- **MCP delete button XSS** — replaced `onclick="...esc(s.name)..."` inline handler with `data-mcp-name` attribute + event delegation (absorb fix). (`static/panels.js`)
- **Zip/tar-slip path traversal** — replaced `startswith` prefix check with `is_relative_to()`; zip-bomb check now tracks actual extracted bytes instead of trusting `member.file_size` (absorb fix). (`api/upload.py`)
- **Terminal PTY env secret leak** — terminal shell env uses a safe allowlist instead of `os.environ.copy()`, preventing API keys from being visible inside the terminal (absorb fix). (`api/terminal.py`)
- **Terminal resize handle wired**`terminalResizeHandle` element added to `index.html`; `_terminalEls()` returns `handle` (absorb fix). (`static/index.html`, `static/terminal.js`)
## [v0.50.235] — 2026-04-28