Commit graph

1540 commits

Author SHA1 Message Date
nesquena-hermes
f7e144d59f
Release v0.51.566 — isolated-profile opt-in hardening (#4620) (#4642)
* stage #4620 (franksong2702): snapshot isolated-profile opt-in at import (fixes #4590)

Security/deployment-hardening follow-up to #4586/#4589. Snapshots
HERMES_WEBUI_ISOLATED_PROFILE at module import (_INITIAL_ISOLATED_PROFILE_OPT_IN)
so _isolated_profile_opt_in() reads the startup snapshot, not live os.environ — a
pinned profile .env loaded later can't flip the isolation posture. _reload_dotenv
key filter kept as defense-in-depth. Adds one-time warning when HERMES_HOME has a
profile-dir shape but isolated wasn't opted in at startup. Code byte-faithful from
PR head 5ef14264.

Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>

* Release v0.51.566 — Release TY (isolated-profile opt-in hardening; #4620)

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
2026-06-21 17:12:52 -07:00
nesquena-hermes
b4c434fb65
Release v0.51.565 — API-server sidecar prune (#4619) + mic insecure-origin message (#4621) (#4639)
* stage batch #4619+#4621 (franksong2702): API-server sidecar orphan-prune + mic insecure-origin message

#4619 (fixes #4591): widen the #3238 orphan-prune to also reconcile API-server
imported sidecars (api/routes.py _is_api_server_sidecar_row). Webui-source guard
intact, fail-closed probe (agent_session_rows_existing degrades to assume-present).
#4621 (fixes #4571): detect insecure non-local http origins for voice dictation +
hands-free, show mic_insecure_origin message, preflight before capture. mic_insecure_origin
added to all 13 locale blocks (zh-Hant real translation + English TODO fallbacks).
Disjoint files (backend routes vs frontend boot/i18n). Code byte-faithful from PR heads.

Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>

* Release v0.51.565 — Release TX (API-server sidecar prune #4619 + mic insecure-origin #4621)

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
2026-06-21 16:50:32 -07:00
nesquena-hermes
0fd9bf3c37
Release v0.51.564 — loopback sidecar diagnostics (#4612) (#4632)
* stage #4612 (santastabber): surface loopback sidecar diagnostics + CHANGELOG

Settings -> Extensions surfaces manifest-declared loopback sidecar companion services
(type:loopback, http(s) on 127.0.0.1/localhost/::1 only, sanitized origin+health_path)
as read-only health cards w/ a browser-side credentials-omitted health probe. Backend
hard-whitelists scheme + loopback host, rejects userinfo/path/query/traversal, rebuilds
output from parsed components (no echo of rejected input); frontend esc()'s every field,
whitelists badge status, fetch never reads body. Purely additive to GET /api/extensions/status.
Code applied byte-faithful from PR head 7080929f3727. 33 own tests pass.
Nathan concept-approved (loopback-companion direction).

Co-authored-by: santastabber <santastabber@users.noreply.github.com>

* fix #4612 Codex gate findings: reject encoded query/fragment in health_path + align CSP loopback allowlist

Codex SHIP-WITH-FIXES (2 reproduced SILENT findings):
1. _normalize_sidecar_health_path percent-decoded AFTER the raw query/fragment ban,
   so /health%3Ftoken=abc -> ?token=abc survived into the probed URL. Now re-rejects
   decoded ? and # + regression test (%3F/%23 skipped with sidecar_health_path_rejected).
2. The origin validator accepts https:// and [::1], but CSP connect-src only listed
   http 127.0.0.1/localhost -> accepted https/IPv6 loopback sidecars would be CSP-blocked.
   Aligned _CSP_CONNECT_BASE (added https v4/localhost + http(s) [::1]) + updated the 4
   exact-string CSP tests + a regression test asserting all loopback forms are allowed.

Co-authored-by: santastabber <santastabber@users.noreply.github.com>

* Release v0.51.564 — Release TW (loopback sidecar diagnostics; #4612)

* fix(#4612): drop browser-invalid [::1]:* CSP source (browser-smoke fail)

The CSP-loopback-alignment fix added http(s)://[::1]:* to connect-src, but CSP
host-source grammar can't express a port wildcard on a bracketed IPv6 literal —
Chromium rejects '[::1]:*' as an invalid source, which browser-smoke flags as a
console error (CI fail). Keep the valid https://127.0.0.1:*/localhost:* additions;
drop the IPv6 wildcard entries. IPv6 [::1] sidecars are still accepted by the
validator (displayed in the card); their browser health probe surfaces as
'blocked' under CSP unless an operator adds a specific-port [::1]:<port> via
HERMES_WEBUI_CSP_CONNECT_EXTRA. Tests updated to match + assert [::1]:* absent.

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: santastabber <santastabber@users.noreply.github.com>
2026-06-21 13:07:32 -07:00
nesquena-hermes
b549c004cb
stage #4598 (Paladin173): composer footer control visibility toggles + rebase + contract test (#4630)
Per-control show/hide for composer footer controls (primary vs situational groups),
per-profile persist + live-apply. Visibility-only — footer layout unchanged.
nesquena-hermes deep-reviewed safe (Codex+Opus+suite 9930). Rebased onto master:
resolved api/config.py boolean-keys conflict (kept both auth_disabled_acknowledged +
the 15 hide_composer_* keys) and panels.js settings-load conflict (kept both
render_user_markdown wiring + composer-control chip render). Contributor closed the
en-only-i18n CI blocker (19 keys x 13 locales verified). Added the missing static-
contract test (sibling pattern test_sidebar_tab_visibility.py).

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: Paladin173 <Paladin173@users.noreply.github.com>
2026-06-21 12:42:42 -07:00
nesquena-hermes
0dba26d06e
Release v0.51.562 — selected-context quote cards (#4380) (#4629)
* stage #4380 (santastabber): render selected context as quote cards + CHANGELOG

Evolves the shipped #2543 named-context-blocks: composer chips -> quote cards
(accent rail, editable label w/ rename, remove, clipped excerpt) + thread render
of labeled selections as <figure> cards. Label+quote esc()'d on every path
(adversarial harness 0 survivors). 3 new i18n keys in all 13 locales (parity green).
Code applied from PR head 2eefc11c02a7 (own 3-dot contribution, CHANGELOG re-stamped).

Co-authored-by: santastabber <santastabber@users.noreply.github.com>

* fix #4380 Codex gate finding: selection-only reply must enable the primary Send button

Codex CORE: #4380 moved selected context out of the textarea into _pendingSelections,
but _composerHasContent() only checked textarea+files -> getComposerPrimaryAction()
returned disabled for a selection-only reply (desktop Enter calls send() directly so
it worked, but click/tap/mobile users were blocked). Fix: expose
window._hasPendingSelections() from messages.js, fold it into _composerHasContent(),
and call updateSendBtn() from _renderSelectionChips() so add/remove/clear refreshes
the button. + regression test.

* Release v0.51.562 — Release TU (selected-context quote cards; #4380)

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: santastabber <santastabber@users.noreply.github.com>
2026-06-21 12:24:42 -07:00
nesquena-hermes
ee0b476f62
Release v0.51.561 — context-window indicator stays correct after model switch (#4618) (#4628)
* stage #4618 (allenliang2022): broaden streaming stale-compressor guard to any model-window mismatch + #4618 regression tests + CHANGELOG

Broadens #3256's default-only live-usage guard: the streaming SSE snapshot now
always resolves the real per-model window via the same helper GET /api/session
hydration uses (_context_length_lookup_inputs_for_model + get_model_context_length)
and corrects whenever it differs from the compressor's cached value, with a
TypeError fallback to the legacy 2-arg form. Fixes 'refresh shows 1M, send reverts
to stale 168k + early auto-compress' on model-switched sessions. Per-stream cache
preserved (one lookup/stream). Code byte-identical to PR head 3beb18e92d73.

Adds 4 source-structure regression tests (RED-proven on master).

Co-authored-by: allenliang2022 <allenliang2022@users.noreply.github.com>

* fix #4618 gate findings: profile-scoped config (Codex cross-profile) + #4248 256k acceptance gate (Opus downward-clobber)

Codex SHIP-WITH-FIXES: live-snapshot used ambient get_config() which in the
detached streaming worker resolves the process-global/default profile (#3294) ->
for a non-default profile pinning a different per-model context_length it would
surface the WRONG profile's window. Now resolves via get_config_for_profile_home
on the session's own profile home (mirrors the worker's _cfg resolution).

Opus SHIP-WITH-FIXES: broadened guard aligned resolution w/ hydration but not its
#4248 acceptance gate -> a transient low-confidence 256k metadata probe could
clobber a LARGER cached window mid-stream. Now reuses the exact hydration helper
_should_accept_session_context_length_refresh on both modern + legacy paths.

+ regression tests for both. Co-authored-by: allenliang2022 <allenliang2022@users.noreply.github.com>

* fix #4618 Codex re-gate findings: broaden save + SSE-done stale-compressor guards too

Codex re-gate found the broadened live-snapshot guard fixed metering but the two
SIBLING paths still used the old default-only exact-cap test:
  - api/streaming.py final session-save: persisted stale other-model window (168k)
    to s.context_length -> wrong window on reload.
  - api/streaming.py terminal  SSE: emitted stale window -> indicator REVERTS
    on stream end (messages.js overwrites S.lastUsage) = the exact 'send reverts to
    168k' symptom.
Both now resolve the real per-model window via the same hydration helper and honor
the #4248 acceptance gate (no 256k downward-clobber), with legacy 2-arg fallback.
This is the root-cause completion across all 3 paths (live/save/SSE-done).

+ 2 regression tests. Co-authored-by: allenliang2022 <allenliang2022@users.noreply.github.com>

* docs(#4618): note model_changed-omission rationale (Opus) + broaden CHANGELOG to all-3-paths

* Release v0.51.561 — Release TT (context-window indicator stays correct after model switch; #4618)

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: allenliang2022 <allenliang2022@users.noreply.github.com>
2026-06-21 11:36:26 -07:00
nesquena-hermes
11625aac1a fix(bootstrap): discover agent installed as root (FHS) or behind the bash launcher
A fresh root install on Linux (e.g. a new Proxmox/Ubuntu VM) places the Hermes
Agent at /usr/local/lib/hermes-agent and links the CLI into /usr/local/bin,
while the modern `hermes` launcher is a `#!/usr/bin/env bash` wrapper that
exec's the venv entrypoint. The old discovery only checked
~/.hermes/hermes-agent-style paths and parsed the launcher's shebang as a Python
interpreter, so on a root VM discover_agent_dir() returned None, bootstrap built
a WebUI-only .venv, and chat aborted at launch with "Python environment cannot
import both WebUI dependencies and Hermes Agent."

Two complementary fixes:
- Add /usr/local/lib/hermes-agent to discover_agent_dir()'s candidate list.
- Harden _agent_dir_from_hermes_cli() to follow the launcher's exec target (any
  absolute path quoted in the wrapper) up to run_agent.py, not just a Python
  shebang. Skips /usr/bin/env indirection.

Now `python3 bootstrap.py` works out of the box for root/container installs with
no HERMES_WEBUI_PYTHON override needed. Adds tests for the bash-wrapper shape,
the env-indirection no-false-positive case, and the FHS candidate probe; updates
docs/troubleshooting.md.
2026-06-21 16:55:40 +00:00
nesquena-hermes
f3d443c6d4 docs(release): stamp v0.51.560 — recovered journal output reaches model context (#4608) 2026-06-21 10:19:20 +00:00
nesquena-hermes
b2818cd46f docs(release): stamp v0.51.559 — cron model picker copy polish (#4031) 2026-06-21 09:57:22 +00:00
nesquena-hermes
7641e7d42e docs(release): stamp v0.51.558 — escape-target symlink display-only rows (#4581) + dialog Cancel fix 2026-06-21 09:17:46 +00:00
nesquena-hermes
f763b8adf8 docs(release): stamp v0.51.557 — desktop question-jump discoverable (#4592) 2026-06-21 08:53:10 +00:00
nesquena-hermes
1ef996b112 docs(release): stamp v0.51.556 — id-ID Edge TTS voice + Listen button state (#4599) 2026-06-21 08:43:17 +00:00
nesquena-hermes
760a5168c9 docs(release): stamp v0.51.555 — mobile reload recovery after compression (#2980/#3133-adjacent) 2026-06-21 08:19:15 +00:00
nesquena-hermes
05d776d6d3 docs(release): stamp v0.51.554 — preserve mid-stream scroll anchor (#4578/#4295) 2026-06-21 07:36:46 +00:00
nesquena-hermes
5eafbfb41a docs(release): stamp v0.51.553 — extensions diagnostics panel (#4588) 2026-06-21 07:19:49 +00:00
nesquena-hermes
4aa0c7a37f docs(release): stamp v0.51.552 — extension sidecar CSP docs (#4593) 2026-06-21 07:05:19 +00:00
nesquena-hermes
d281b7cf63 docs(release): stamp v0.51.551 — manual /compress preserves visible transcript (#4594/#3133) 2026-06-21 06:54:48 +00:00
nesquena-hermes
d38b95076a docs(release): stamp v0.51.550 — Transparent Stream activity survives settle/reload (#4587/#4568) 2026-06-21 06:35:16 +00:00
nesquena-hermes
fbab5bb42b docs(release): stamp v0.51.549 — hotfix profile switching for single-user named profiles (#4589/#4586) 2026-06-21 05:32:53 +00:00
nesquena-hermes
4fa9abd9d2 docs(release): stamp v0.51.548 — extension load diagnostics (#4569) 2026-06-21 04:16:58 +00:00
nesquena-hermes
a9a20d3d98 docs(release): stamp v0.51.547 — re-auth before disabling password auth (#3581) 2026-06-21 02:45:34 +00:00
nesquena-hermes
6b2ac55b8d stage #4566 + stamp v0.51.546 — fix flaky gateway_sync test (#4557)
rodboev: settings-write-version counter widens the session-list cache key + flush CLI-sessions
cache on visibility toggle, killing the mtime_ns-bucket collision flake. Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-21 02:04:09 +00:00
nesquena-hermes
3e229141af stage #4561 + stamp v0.51.545 — extension manifest asset bundles
santastabber. HERMES_WEBUI_EXTENSION_MANIFEST: bundle extension assets via a 64KB JSON manifest
instead of long URL lists. Same same-origin allowlist validator, traversal-guarded manifest path,
default-off. Nathan blessed (richer extension system). Co-authored-by: santastabber <santastabber@users.noreply.github.com>
2026-06-21 00:37:08 +00:00
nesquena-hermes
2471e277cb rebase #3933 + stamp v0.51.544 — opt-in render markdown in user messages
rodboev. Default-off; OFF path byte-identical to master (cache key 'u' + _renderUserFencedBlocks
unchanged when window._renderUserMarkdown falsy). ON routes user text through the same renderMd
SAFE_TAGS/_isSafeUrl sanitizer as assistant msgs. Nathan override-approved (likes the idea, opt-in).
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-21 00:03:02 +00:00
nesquena-hermes
feeb5b760a docs(release): stamp v0.51.543 — stable assistant turn anchors (#4411/#3926) 2026-06-20 22:38:38 +00:00
nesquena-hermes
01985bba04 docs(release): stamp v0.51.542 — model picker syncs with agent catalog (#4413) 2026-06-20 21:38:35 +00:00
nesquena-hermes
3d9487cbaf docs(release): stamp v0.51.541 — stale models cache fallback on catalog timeout (#3928) 2026-06-20 19:11:56 +00:00
nesquena-hermes
a46c368854 docs(release): stamp v0.51.540 — cross-provider model selection + gateway reasoning effort 2026-06-20 18:44:43 +00:00
nesquena-hermes
1ee5666870 docs(release): stamp v0.51.539 — gateway session_id + slash-model routing 2026-06-20 17:42:42 +00:00
nesquena-hermes
79bb2a9a34 docs(release): stamp v0.51.538 — gateway legacy approval relay (#4549) 2026-06-20 17:36:45 +00:00
nesquena-hermes
2f3abb00be stage #4540 + CHANGELOG 2026-06-20 07:12:51 +00:00
nesquena-hermes
348381bda3 stage #4542 @696bf798 (incl perf: pre-scan burst IDs) + CHANGELOG 2026-06-20 06:56:34 +00:00
nesquena-hermes
2b398bb2b1 stage #4537: keep open model picker stable during stream sync (#4531, head 92de7615 incl duplicate-rebuild fix) + v0.51.535 CHANGELOG 2026-06-20 06:10:04 +00:00
nesquena-hermes
15fe6add30 stage #4524: clarify 409-terminal (id-guarded, loading-cleared) + SSE-notify on expiry (#4504) + v0.51.534 CHANGELOG 2026-06-20 05:36:56 +00:00
nesquena-hermes
90505c0a8e stage #3285: gateway restart from agent-health alert (POST /api/health/restart) + v0.51.533 CHANGELOG 2026-06-20 04:40:49 +00:00
nesquena-hermes
07174e06b3
docs(changelog): correct v0.51.530 attribution to @MinhoJJang (#4522) (#4528)
PR #4522 (fix /api/profiles UnboundLocalError 500) was authored by
@MinhoJJang, not @TomBanksAU. The wrong handle was carried forward from
the immediately preceding release (v0.51.529 / #4518, which IS TomBanksAU).
Corrects the credit on the v0.51.530 entry only.

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-06-19 21:16:03 -07:00
nesquena-hermes
acd2c186ef stage #4516: apply config defaults to non-default profile reads (#4465 / #4513) + v0.51.532 CHANGELOG 2026-06-20 03:51:55 +00:00
nesquena-hermes
a60ba78298 stage #4517: plugins panel active-provider badge via is_active_provider (#4496) + v0.51.531 CHANGELOG 2026-06-20 03:35:44 +00:00
nesquena-hermes
51e2fce823 stage #4522: fix /api/profiles UnboundLocalError 500 (regression from v0.51.528) + v0.51.530 CHANGELOG 2026-06-20 03:18:33 +00:00
nesquena-hermes
6592416b35 stage #4518: match per-response jump button to session jump pill (#2246) + v0.51.529 CHANGELOG 2026-06-20 02:07:44 +00:00
nesquena-hermes
8b598ac133 changelog: stamp v0.51.528 (Release SM) for #2698 isolated HERMES_HOME mode 2026-06-20 00:49:06 +00:00
nesquena-hermes
d473f6c5a6 fix(notifications): notify on completion if tab was hidden during the stream (#4416)
A background tab's SSE is throttled by Chromium, so the stream 'done' event
arrives late (after the user returns, document.hidden=false) and the
response-complete notification was suppressed by the live visibility check.
Track per-stream whether the tab was hidden at ANY point during the stream
(_STREAM_WAS_HIDDEN, set at attach, OR'd by one idempotent visibilitychange
listener, read+cleared at done) and pass forceHidden accordingly.
sendBrowserNotification bypasses ONLY the live visibility gate on forceHidden,
still honoring the user's notifications-enabled setting — so a watched stream
stays silent (matches Slack/Discord/Gmail/Claude) but a backgrounded one
notifies. Correct fix for the #4416 root cause; supersedes #4421's always-fire
approach (which would also fire when the tab was never hidden).

Co-authored-by: bergeouss <bergeouss@users.noreply.github.com>
2026-06-19 23:48:42 +00:00
nesquena-hermes
0a1e5d97a4 stage #4424: unstuck Running indicator when SSE dies during provider retry (#4354) + v0.51.526 CHANGELOG 2026-06-19 22:51:02 +00:00
nesquena-hermes
9ade727e63 stage #4494: expose built-in personalities in WebUI config (#4465) + v0.51.525 CHANGELOG 2026-06-19 22:26:30 +00:00
nesquena-hermes
580a157ab1 stage #4447: opt-in chunked SSE for buffering proxies (#4447) + v0.51.524 CHANGELOG 2026-06-19 22:09:17 +00:00
nesquena-hermes
139663f4a7 changelog: stamp v0.51.523 (Release SH) for #4375 wiki listing cache + hardlink rejection 2026-06-19 21:11:57 +00:00
nesquena-hermes
36730fe9f9 changelog: stamp v0.51.522 (Release SG) for #4488 live-model key scoping 2026-06-19 20:43:59 +00:00
nesquena-hermes
87aefad22f stage #4489: scope imported sessions to active profile (#4489) + v0.51.521 CHANGELOG 2026-06-19 20:25:43 +00:00
nesquena-hermes
99c12c6c8d changelog: stamp v0.51.520 (Release SE) for #4310 untracked-file recovery 2026-06-19 20:10:02 +00:00
nesquena-hermes
5a8ce51eb7 changelog: stamp v0.51.519 (Release SD) for #4492 stale active-run reconcile 2026-06-19 19:53:26 +00:00