Merge latest master into compression recovery action

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Frank SongandPaperclip committed 2026-07-05 12:43:07 +08:00
commit 1262148fc8
3 files changed
+26 -1

No files matched your search

+1
View File
@@ -14,6 +14,7 @@
### Fixed
- **Mobile: the command/tool approval popup is taller so its options fit without scrolling inside it.** On phones the approval card capped its height low enough that a prompt with several options (or a long command) pushed the bottom actions off the visible area, forcing you to scroll within the cramped popup to reach them. The mobile height cap is raised (from `min(52dvh, 360px)` to `min(60dvh, 420px)`), so a typical approval prompt now shows all its options at once; very tall content still scrolls inside the card, and desktop is unaffected. Thanks @nankingjing. (#5539, #5385)
- **Security: CORS preflight no longer advertises wildcard cross-origin access.** The server answered every CORS preflight (`OPTIONS`) with `Access-Control-Allow-Origin: *`, which on a password-less deployment could let any website read authenticated responses. The preflight now echoes the request's origin only when it's same-origin or explicitly allowlisted via `HERMES_WEBUI_ALLOWED_ORIGINS` — the same policy the CSRF gate already enforces for real requests — and never emits `*`. Default deployments (no allowlist) are unaffected. Thanks @mo7al876any. (#5534)
- **Clearing a conversation can no longer be undone by crash recovery — even after you send a new message.** `Clear conversation` writes a one-time `.json.bak` before wiping the transcript; if the app then crashed or restarted, startup recovery saw the backup as "larger" than the cleared session and could restore the cleared history — including on top of a message you'd sent after clearing. Clear now stamps a unique per-clear marker on the session, and recovery treats a backup that predates that marker as stale, so a cleared conversation stays cleared. Genuine crash-loss recovery (unmarked or same-generation backups, unreadable/partial files) still restores as before. Hardens the clear-conversation data-loss fix from the prior releases. Thanks @rodboev. (#5584, #5570)
- **A message containing a broken emoji (lone Unicode surrogate) no longer breaks scroll position tracking.** If a message's text held a lone UTF-16 surrogate — e.g. a half-copied emoji from a truncated paste or interrupted stream — computing that message's scroll-anchor key threw an error, which broke scroll-position restore for the whole transcript. The anchor-key builder now handles lone surrogates safely (valid emoji are preserved; only the broken half is dropped), so scroll anchoring keeps working. Thanks @rumotoshino. (#5573, #5552)
+1 -1
View File
@@ -3159,7 +3159,7 @@
/* Approval card */
.approval-card{padding-left:10px;padding-right:10px;bottom:8px;overflow:visible;}
.approval-inner{max-height:min(52vh,360px);overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:12px 12px 14px;border-radius:12px;box-shadow:0 -10px 30px rgba(0,0,0,.24);}
@supports (height:100dvh){.approval-inner{max-height:min(52dvh,360px);}}
@supports (height:100dvh){.approval-inner{max-height:min(60dvh,420px);}}
.approval-header{margin-bottom:8px;}
.approval-collapse,.approval-dismiss{width:44px;height:44px;line-height:1;overflow:hidden;}
.approval-cmd{max-height:86px;margin-bottom:10px;}
@@ -0,0 +1,24 @@
"""#5385 / #5539: the mobile approval card must give command/tool approval
options enough height so they don't require scrolling within a cramped popup.
The mobile (@supports height:100dvh) rule caps .approval-inner height; the fix
raises that cap from min(52dvh,360px) to min(60dvh,420px). Source-level guard so
the taller cap can't silently regress.
"""
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
STYLE = (ROOT / "static" / "style.css").read_text(encoding="utf-8")
def test_mobile_approval_inner_dvh_cap_raised():
# The dvh-based cap must be the raised value, not the old cramped one.
assert "max-height:min(60dvh,420px)" in STYLE
assert "max-height:min(52dvh,360px)}" not in STYLE.replace(" ", "")
def test_mobile_approval_inner_still_scrolls_as_fallback():
# The non-dvh fallback keeps overflow-y:auto so very tall content still
# scrolls rather than clipping (the cap is a ceiling, not a fixed height).
assert "overflow-y:auto" in STYLE