Commit graph

4459 commits

Author SHA1 Message Date
nesquena-hermes
dbc7b317e7
Merge pull request #4436 from nesquena/release/stage-4432
Release v0.51.498 — RH (profile runtime env no longer clobbers core shell identity, #4432)
2026-06-18 13:20:08 -07:00
nesquena-hermes
0a5912f0fb release: v0.51.498 — filter core shell-identity vars from projected profile env (#4432)
Co-authored-by: lunarnexus <lunarnexus@users.noreply.github.com>

Closes #4432
2026-06-18 20:06:26 +00:00
nesquena-hermes
23527bf846 Merge commit 'refs/pull/4432/head' of github.com:nesquena/hermes-webui into release/stage-4432 2026-06-18 19:58:18 +00:00
nesquena-hermes
ad9a7edab0
Merge pull request #4433 from nesquena/release/stage-4410
Release v0.51.497 — RG (rollback checkpoint diffs no longer follow symlinks, #4410) [security]
2026-06-18 12:41:50 -07:00
nesquena-hermes
9a54fe9aeb fix(#4410): pre-check workspace leaf type via lstat + close fd on non-regular (Codex gate v2)
Codex re-gate found two issues in the uncapped-read fix: (1) open_anchored_fd
opens blocking O_RDONLY, which HANGS on a workspace FIFO/special file swapped in
at a regular-file path; (2) the non-regular fstat branch returned without
closing the fd (leak). Fix: lstat the symlink-resolved target BEFORE any open to
skip non-regular leaves (no blocking open on a FIFO), and close the fd on the
non-regular fstat branch. Adds a threaded FIFO-no-hang regression test.
2026-06-18 19:22:29 +00:00
nesquena-hermes
94909590ad fix(#4410): read workspace diff content uncapped + symlink-safe (Codex gate)
Codex regression gate found that routing workspace reads through
read_file_content() introduced a 400KB MAX_FILE_BYTES cap not present on master
(Path.read_text), so a large but legitimate workspace file raised ValueError ->
caught -> None -> the rollback diff falsely reported it as DELETED. Replace with
an uncapped anchored O_NOFOLLOW read (safe_resolve_ws + open_anchored_fd +
S_ISREG fstat check) that keeps the symlink-escape protection but has no size
cap. Adds a >400KB regression test (RED on the capped path, GREEN with the fix).

Co-authored-by: Hinotoi-agent <Hinotoi-agent@users.noreply.github.com>
2026-06-18 19:18:11 +00:00
nesquena-hermes
35f040d19f Merge commit 'refs/pull/4410/head' of github.com:nesquena/hermes-webui into release/stage-4410
# Conflicts:
#	CHANGELOG.md
2026-06-18 19:11:38 +00:00
James
dfcc06acdb fix: align webui runtime env handling with gateway behavior 2026-06-18 19:01:17 +00:00
nesquena-hermes
6f233d3a20
Merge pull request #4431 from nesquena/release/stage-4419b
Release v0.51.496 — RF (compact provider quota chip on narrow composer, #4419)
2026-06-18 11:56:48 -07:00
nesquena-hermes
3cc4c859cf release: v0.51.496 — compact provider quota chip on narrow composer (#4419)
Co-authored-by: bergeouss <bergeouss@users.noreply.github.com>

Closes #4419
Closes #4358
2026-06-18 18:48:11 +00:00
nesquena-hermes
6f699642d5
Merge pull request #4429 from nesquena/release/stage-4422
Release v0.51.495 — RE (suppress ERR_ABORTED console noise on SSE close, #4422)
2026-06-18 11:41:17 -07:00
nesquena-hermes
df16a2eb10 release: v0.51.495 — guard EventSource.close() to suppress ERR_ABORTED noise (#4422)
Co-authored-by: bergeouss <bergeouss@users.noreply.github.com>

Closes #4422
2026-06-18 18:23:41 +00:00
nesquena-hermes
348078a617 Merge commit 'refs/pull/4422/head' of github.com:nesquena/hermes-webui into release/stage-4422 2026-06-18 18:22:37 +00:00
nesquena-hermes
1a6fcc115b
Merge pull request #4427 from nesquena/release/stage-4412c
Release v0.51.494 — RD (TLS-aware launcher health probes, #4412)
2026-06-18 11:20:44 -07:00
nesquena-hermes
a308fdd5e8 release: v0.51.494 — TLS-aware launcher health probes (#4412)
Absorbs #4412 (tomas-forgac) rebased onto fresh master, plus two
Codex-regression-gate fixes: (1) use the scheme that actually answered the
probe for the ready/already-up URL + browser-open, (2) honor an explicit
HERMES_WEBUI_HEALTH_URL override in the WSL autostart probe.

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

Closes #4412
2026-06-18 18:13:46 +00:00
nesquena-hermes
67f81b60a2
Merge pull request #4426 from nesquena/release/stage-4417
Release v0.51.493 — RC (ignore malformed background-process wakeup events, #4417)
2026-06-18 11:12:06 -07:00
nesquena-hermes
18d5df74a9 release: v0.51.493 — ignore malformed background-process wakeup events (#4417) 2026-06-18 18:04:28 +00:00
nesquena-hermes
d228195da9 merge #4417: ignore malformed process wakeup events (resolve CHANGELOG) 2026-06-18 17:56:40 +00:00
nesquena-hermes
8bd0b38abe
Merge pull request #4425 from nesquena/release/stage-4418
Release v0.51.492 — RB (large context window preserved on session reload, #4248)
2026-06-18 10:46:13 -07:00
nesquena-hermes
c7fc114c85 release: v0.51.492 — preserve large context window on session reload (#4248, #4418) 2026-06-18 17:39:50 +00:00
nesquena-hermes
561843ee9d fix(#4248): normalize slash-qualified model id in reload identity check
Codex regression gate found that _session_model_identity_matches normalized
only the @provider:model form, not provider/model (slash). A session stored as
'deepseek/deepseek-v4-1m' resolving to bare 'deepseek-v4-1m' was treated as a
model change -> the 256k fallback bypassed the accept-guard and clobbered the
persisted 1M window (the same #4248 bug on slash-qualified IDs). Mirror the
slash-aware split already used by _model_matches_configured_default. Adds a
route-level regression + unit test for the slash shape.

Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
2026-06-18 17:37:52 +00:00
ai-ag2026
352e1893cb test: cover malformed wakeup edge cases 2026-06-18 19:30:24 +02:00
bergeouss
d812f70116 fix(#4313): guard EventSource.close() calls to suppress ERR_ABORTED noise
Add readyState !== CLOSED (2) guards to all EventSource.close() calls across
messages.js, sessions.js, panels.js, and terminal.js. Chromium reports
net::ERR_ABORTED when close() is called on an already-closed EventSource,
polluting the console during normal lifecycle transitions (session switch,
panel close, stream teardown).

Key hotspots:
- closeLiveStream() double-close via onerror → _closeSource chain
- _closeSessionEventsSSE, _gatewaySSE.onerror missing try/catch
- _kanbanStopPolling, terminal close handlers

20 close() calls guarded across 4 files, no structural changes to stream
lifecycle.
2026-06-18 17:25:18 +00:00
Frank Song
531c5787c6 fix: refine context reload fallback guard 2026-06-19 00:05:52 +08:00
Frank Song
9f174f6cc3 test: update session context fallback guard 2026-06-18 23:19:58 +08:00
Frank Song
f9d6b127e3 fix: preserve large context window on session reload 2026-06-18 23:13:19 +08:00
ai-ag2026
ff0ac7c7a4 fix: ignore malformed process wakeup events 2026-06-18 16:17:27 +02:00
hinotoi-agent
f42248d321 fix: harden rollback restore checkpoint reads 2026-06-18 16:04:39 +08:00
hinotoi-agent
b6f8fc2a5c fix(rollback): avoid symlinked checkpoint diff reads 2026-06-18 13:36:06 +08:00
nesquena-hermes
bc11cfe6d2
Merge pull request #4409 from nesquena/stage-4405
Release v0.51.491 — RA (rollback restore writes contained to workspace #4405)
2026-06-17 22:15:46 -07:00
nesquena-hermes
330e0672b8 fix(#4405): contain rollback checkpoint restore writes to the workspace
Restore previously used pathname-based shutil.copy2() which follows an in-tree
symlink whose target escapes the workspace. Route restore writes through the
workspace-anchored file helpers so a restored file always lands inside the
workspace tree. +regression test (escaping symlink refused, normal restore ok).

Co-authored-by: hinotoi-agent <paperlantern.agent@gmail.com>
2026-06-18 05:12:49 +00:00
nesquena-hermes
f46a447dc3
Merge pull request #4408 from nesquena/stage-4372
Release v0.51.490 — QZ (large plain-text pastes become .md attachments #4372)
2026-06-17 22:12:03 -07:00
nesquena-hermes
299fab5631 feat(#4372): attach large composer text pastes as .md files
Pastes over 4000 chars or 100 lines attach as a timestamped pasted-text-*.md in
the upload tray instead of flooding the composer. Image-paste path unchanged; an
oversize paste that exceeds MAX_UPLOAD_BYTES falls through to a normal inline
paste so nothing is lost.

Co-authored-by: santastabber <204424800+santastabber@users.noreply.github.com>
2026-06-18 05:09:11 +00:00
nesquena-hermes
9f14dd6686
Merge pull request #4407 from nesquena/stage-4402
Release v0.51.489 — QY (outline button no longer collides with scroll control #2124)
2026-06-17 21:58:19 -07:00
nesquena-hermes
4ac9684223 fix(#2124): stop the conversation-outline button colliding with the scroll control
The outline FAB was position:fixed at z-index 9999 and could stack on top of the
scroll-to-bottom button. Anchor it inside the messages shell (position:absolute,
z-index 12) so the two controls don't overlap.

Co-authored-by: Mohamed Habib <Habib1001-m@users.noreply.github.com>
2026-06-18 04:46:50 +00:00
nesquena-hermes
d5f9e98252
Merge pull request #4406 from nesquena/stage-4216
Release v0.51.488 — QW (rescue state.db user prompts before newer sidecar tail #4216)
2026-06-17 21:37:46 -07:00
nesquena-hermes
c592ae3acc fix(#4216): insert state.db-only user prompts chronologically in merge_session_messages_append_only
A user prompt that exists only in Hermes state.db (no sidecar copy) and falls
chronologically BEFORE a newer sidecar message tail was being appended after the
tail (or skipped) by merge_session_messages_append_only — losing or mis-ordering
it on load. The merge now inserts such a state.db user message at its correct
chronological position via _insert_state_message_chronologically, with a
role-aware tie-break for equal timestamps. Append-only invariant + dedup
(seen_content_keys) preserved.

Deterministic-ordering guard (maintainer add, addresses Codex review): on an
equal-timestamp collision the insert no longer lands at a slot whose left
neighbour shares the message's role — it advances past the same-role
equal-timestamp run, so an already-answered earlier turn can't be re-ordered
into user,user,assistant. (The agent core merges adjacent users before send, so
this was benign in practice, but the guard keeps the merged transcript correctly
ordered regardless.) +1 same-second multi-turn regression test, toothless-checked.

Co-authored-by: Dennis Soong <dso2ng@gmail.com>
2026-06-18 04:25:11 +00:00
nesquena-hermes
cbf6f747b4
Merge pull request #4404 from nesquena/stage-4398
Release v0.51.487 — QX (multi-container Docker: staged source writable #4395)
2026-06-17 21:19:45 -07:00
nesquena-hermes
60218c302d fix(#4395): make staged hermes-agent source writable after rsync/cp in docker_init
Multi-container Docker deploys died at startup with 'could not create
hermes_agent.egg-info: Permission denied'. docker_init.bash stages the :ro
hermes-agent-src into /tmp/hermes-agent-build to avoid EROFS, but rsync -a/cp -a
preserve mode bits — a source mounted 555 left the staged copy 555, so
setuptools couldn't write egg-info next to the package. chmod -R u+w the staged
tree after the copy (error_exit on failure) so the build dir is genuinely
writable, not just owned by hermeswebui.

Co-authored-by: enihcam <enihcam@users.noreply.github.com>
2026-06-18 04:15:08 +00:00
nesquena-hermes
5ced430628
Merge pull request #4403 from nesquena/stage-4399
Release v0.51.486 — QV (archived cron runs stay hidden on state.db re-projection #4397)
2026-06-17 20:45:50 -07:00
nesquena-hermes
5c62f849fa fix(#4397): keep archived cron runs hidden on state.db re-projection
Follow-up to #4385/#4388: that fix stopped stale cron sidecars from being
treated as CLI rows, but get_cli_sessions() still re-projected the same cron
run from Hermes state.db with a hardcoded archived: false after all_sessions()
omitted the hidden sidecar — so an archived run reappeared on refresh.

- New _state_projection_sidecar_metadata(sid) helper returns UI-owned title +
  archived flag from the WebUI sidecar (load_metadata_only), degrading
  gracefully to {title:None, archived:False} on any miss.
- Both state.db-projection paths (standard CLI + cron fallback) now use it and
  carry the archived flag onto the projected row (was hardcoded False), so an
  archived cron/tool/API run stays hidden regardless of which path surfaces it.
  Title-preference behavior (#1486 rename persistence) is preserved.

Co-authored-by: TomBanksAU <246584738+TomBanksAU@users.noreply.github.com>
2026-06-18 03:33:44 +00:00
nesquena-hermes
f5f882b1dd
docs: fairly count absorbed-but-closed contributor PRs (backfill @Isla-Liu trio) (#4401) 2026-06-17 20:08:08 -07:00
nesquena-hermes
a6214d0927
Merge pull request #4400 from nesquena/stage-4394
Release v0.51.485 — QU (mobile: 44px hamburger + browser edge-swipe #4394)
2026-06-17 19:50:29 -07:00
nesquena-hermes
ed827248ba feat(#4394): mobile — 44px hamburger tap target + browser edge-swipe sidebar
- Hamburger button: 32x32 -> 44x44 tap target (iOS HIG minimum), SVG icon
  20 -> 24px. flex-shrink:0 preserved; spacer keeps the title centered.
- Edge-swipe-to-open-sidebar: edge zone 28 -> 80px, trigger 72 -> 64px, max
  vertical 48 -> 56px; removes the _isPwaStandalone() gate in
  _onPwaSidebarSwipeStart so the gesture works in a normal mobile browser, not
  only the installed PWA. Still _isDesktopWidth()-blocked, touch/pen-only,
  interactive-target-excluded, and requires horizontal intent (dx>=64 &&
  dx>|dy|*1.5), so scroll/tap won't trigger it.

Known tradeoff (Nathan-approved ship-as-is): in mobile BROWSER the 80px left
edge zone overlaps iOS Safari's back-swipe; degrades gracefully (PWA, the
primary mobile target, has no back gesture).

Verified live at 390x844: hamburger renders 44x44 + tap opens sidebar; a
left-edge swipe opens the sidebar in a non-PWA context. 66 existing mobile/
swipe/titlebar tests pass.

Co-authored-by: kaishi00 <kaishi00@users.noreply.github.com>
2026-06-18 02:40:13 +00:00
nesquena-hermes
265786c2fe
Merge pull request #4396 from nesquena/stage-4223
Release v0.51.484 — QT (collapsible paused cron section #4026)
2026-06-17 19:18:42 -07:00
nesquena-hermes
a195c9f589 feat(#4026): collapse paused cron jobs into a collapsible sidebar section
Paused/disabled cron jobs are partitioned out of the active list into a
collapsible 'Paused (N)' <details> section so they don't drown the active
jobs. _cronList stays the single source of truth — only the render is split,
so openCronDetail / _cronNewJobIds / detail-refresh are untouched. Reuses the
already-translated cron_status_paused label (zero new i18n keys). Collapsed
state persisted in localStorage.

Maintainer polish on absorb: wrapped both localStorage read/write in try/catch
(repo convention — a storage throw in private mode must not dump the cron
sidebar into the error banner) + added the CHANGELOG entry.

Co-authored-by: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com>
2026-06-18 02:08:28 +00:00
nesquena-hermes
f5efa1f89f
Merge pull request #4392 from nesquena/fix-gateway-sync-flake
test: fix recurring gateway_sync StopIteration flake (show_cli_sessions isolation)
2026-06-17 18:33:08 -07:00
nesquena-hermes
1c3b1ecdc9 test(gateway_sync): fix intermittent StopIteration flake (test-isolation root cause)
The A3 flake (test_sessions_response_backfills_imported_messaging_source_metadata
failing with StopIteration on a sharded CI run while passing in isolation +
sequentially) had two compounding causes, both fixed:

1. ROOT CAUSE — show_cli_sessions setting leak across shard-ordered tests.
   33 gateway_sync tests flip show_cli_sessions=True but only ~30 reset it,
   and cleanup_test_sessions didn't reset it. Under pytest-shard ordering a
   test could run with the setting in an unexpected state, so its session was
   occasionally absent from /api/sessions. cleanup_test_sessions now resets
   show_cli_sessions to its default (off) after every test, the same way it
   already resets last_workspace.

2. SYMPTOM — bare next(generator) with no default raised an opaque
   StopIteration (read as a mystery flake) instead of a diagnosable failure
   when the session was absent. The 5 bare next() call sites over /api/sessions
   results now use next(..., None) + an explicit assertion naming the missing
   session, so any future isolation regression fails clearly instead of
   masquerading as a flake.

No production code change; tests + fixture only.
2026-06-18 01:19:20 +00:00
nesquena-hermes
f5512aa507
Merge pull request #4389 from nesquena/stage-4346-cluster
Release v0.51.483 — QS (virtual-scroll scroll-jump fixes #4367 + #4368)
2026-06-17 18:04:14 -07:00
nesquena-hermes
f4d014194c fix(#4346): virtual-scroll height + measurement scroll-jump cluster (#4367, #4368)
Two coherent fixes for the #4346 transcript-virtualization scroll-jump
cluster, shipped together (contributor-approved) because both touch
static/ui.js + the same virtualization test file and interact (the
cache-reset path uses the per-role default from #4367). Both only run when
the default-OFF experimental "Virtualize long transcripts" setting is on.

#4367 — per-role virtual scroll height estimates:
  Replaces the flat 140px unmeasured-row estimate with per-role fallbacks
  (user 120 / assistant 160 / tool_call 400 / default 140) via
  _messageVirtualDefaultHeightForRole + _messageVirtualRoleForEntry, so
  tool-call rows (which measure 500-2000px) aren't under-counted before
  measurement. Additive + backward-compat (opts.roleForIdx optional → flat
  default when absent). The two sibling offset calculators route through the
  per-role defaults too.

#4368 — anchor-based scroll compensation during measurement:
  Adds _compensateScrollForMeasurementDelta (capture anchor + scrollTop →
  render → re-pin scrollTop by the anchor row's measured delta; null/missing/
  <2px guards; programmatic-scroll flag managed) wrapping
  renderMessages({preserveScroll:true}) in _scheduleMessageVirtualizedRender,
  plus a 150ms scroll-active guard deferring measurement refresh while the user
  scrolls, and session-switch cleanup of the three scroll-settle globals.

Maintainer note: combining the two required the test harness for
test_clear_height_cache_resets_scroll_settle_globals (#4368) to also eval
_messageVirtualDefaultHeightForRole + define MESSAGE_VIRTUAL_DEFAULT_ROW_HEIGHTS
(#4367), since the combined _clearMessageVirtualHeightCache resets the estimate
via the per-role helper. Both PRs' test sets retained.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-18 00:50:53 +00:00