v0.50.295 — 3-PR batch (YAML/JSON/diff newlines + macOS scroll race + custom:* providers + glued-bold-lift raw pre)
3 PRs from 3 contributors. Closes 5 issues: #1360, #1451, #1463, #1618, #1619.
Highlights
YAML/JSON/diff code blocks render multi-line again (#1642, closes #1618 / #1463)
Reporter @Zixim flagged that YAML rendering had been flattened to a single line since v0.50.237 (PR #484), despite PR #1516's CSS-only "fix" in v0.50.279. Live-rendered both ```yaml ... ``` and a control ```yml ... ``` block through renderMd() in the browser to verify — @Zixim was right, the bug was real on master.
Root cause: PR #484 introduced <pre class="tree-raw-view"> for JSON/YAML and <pre class="diff-block"> for diff/patch, but the _pre_stash regex matched only literal <pre> (no attributes). PR #1516's CSS rule pre code.language-yaml .token { white-space: pre } was the wrong layer — by the time Prism built tokens, paragraph-wrap had already replaced \n with <br> inside <code>. One-character regex relax (<pre> → <pre[^>]*>) pulls JSON, YAML, AND diff/patch blocks into the stash so paragraph-wrap can't mangle them. Bash, Python, Go, etc. were never affected because they emit bare <pre>.
Parallel-discovery attribution: @Michaelyklam independently filed PR #1641 with the exact same one-character regex relax (4 minutes before #1642). #1641 closed as superseded; UI before/after PNGs from #1641 adopted into the release with Co-authored-by: Michael Lam trailer on the docs commit so Michael's visual evidence ships alongside the canonical fix.
macOS WKWebView scroll race (#1639, closes #1360)
Trackpad scrolling up during streaming snapped viewport back to bottom because the _programmaticScroll setTimeout(0) guard raced with WKWebView momentum scrolling. Mid-momentum events either got swallowed or falsely reported nearBottom, keeping _scrollPinned=true. Fix: rAF-debounce the scroll listener so the nearBottom check fires on the next paint frame when scroll position has settled, plus a 2-sample hysteresis counter requiring two consecutive near-bottom samples before re-pinning.
Custom:* provider model list (#1639, closes #1619)
Custom:* providers via custom_providers in config.yaml were only showing the default model in the dropdown. /api/models/live only handled bare custom, not custom:* slugs. Fix: broaden the provider check to provider == "custom" or provider.startswith("custom:"). Plus defensive belt-and-braces in api/config.py dedup-fallback (Opus advisor noted this is unreachable under current population logic; kept for future-proofing with clarifying comment).
Glued-bold-heading lift no longer mangles raw <pre> (#1637, closes #1451)
renderMd() was restoring raw <pre> blocks BEFORE the glued-bold-heading lift ran, so literal preformatted text containing Para text.**Heading**\n\nNext got mangled by the lift inserting \n\n mid-content. Fix: delay rawPreStash restore until after markdown/link rewrites and before HTML sanitization. Test pins both sides — raw <pre> is preserved AND regular glued headings outside preformatted blocks still lift correctly.
Tests
4245 → 4255 passing (+10). 0 regressions. Full suite ~120s.
Pre-release verification
- Opus advisor on stage-295 combined diff: SHIP verdict. All 6 verification questions cleared.
static/ui.jsoverlap between #1637 (rawPreStash R-token, line 1675), #1639 (scroll listener, line 1191), and #1642 (_pre_stash E-token, line 1925) verified non-overlapping with separate token namespaces and correct ordering. #1637's relocated restore (line 1668 → 1815) traced through every intermediate rewrite pass — placeholder\x00R{N}\x00has no syntactic chars matching any rewrite. #1642 nested-<pre>non-greedy verified identical to existingrawPreStashregex (no regression). #1639 hysteresis verified correct shape. - #1642 has nesquena APPROVED with comprehensive end-to-end behavioral trace.
- JS syntax:
static/ui.jsclean. - Browser API sanity: 11/11 endpoints OK on stage server.
- Live behavioral verification post-deploy: all 9 #1618 regression tests pass on production master; deployed code shows correct
<pre[^>]*>regex, correctrawPreStashordering at line 1815, correct rAF + 2-sample hysteresis, correctcustom:*startswith handling.
Authors
- @nesquena-hermes — 1 PR (#1642, with co-author trailer for @Michaelyklam's UI media adoption)
- @Michaelyklam — 1 PR (#1637)
- @bergeouss — 1 PR (#1639, AI-assisted via Hermes Agent)
Full changelog: https://github.com/nesquena/hermes-webui/blob/master/CHANGELOG.md