Commit Graph
533 Commits
Author SHA1 Message Date
nesquena-hermes f94508994f release: v0.51.505 — allow macOS Mail message: links in chat markdown (#4420, #4319)
Co-authored-by: bergeouss <bergeouss@users.noreply.github.com>

Closes #4420
Closes #4319
2026-06-19 01:58:28 +00:00
nesquena-hermes b3a848967e Merge commit 'refs/pull/4440/head' of github.com:nesquena/hermes-webui into release/stage-4440b 2026-06-19 01:31:54 +00:00
nesquena-hermes 7827297011 Merge commit 'refs/pull/4439/head' of github.com:nesquena/hermes-webui into release/stage-4439b 2026-06-19 00:55:13 +00:00
nesquena-hermesandrodboev 670e3dbdca release: v0.51.500 — fix stuck-scroll on long sessions with dense tool blocks (#4434)
Co-authored-by: rodboev <rodboev@users.noreply.github.com>

Closes #4434
2026-06-18 21:26:54 +00:00
Rod Boev a4058e31e4 Move sub-group rendering inside heading scope to fix wrapper ReferenceError 2026-06-18 16:27:07 -04:00
Rod Boev 851cc0e313 Fix lexical scope errors caught by cross-provider review 2026-06-18 16:15:39 -04:00
Rod Boev 7aa0649e3e feat(#4336): add vendor prefix sub-grouping in model picker for OpenRouter and Nous 2026-06-18 15:47:11 -04:00
Rod Boev d85979cd69 fix(#4373): mark process-wakeup turns as synthetic and filter from visible transcript 2026-06-18 15:47:06 -04:00
nesquena-hermesandRod Boev 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
nesquena-hermesandGouranga satapathy 98a81118a1 fix(#4353): render all PDF pages in a scrollable inline preview
The inline PDF preview rendered only page 1, so multi-page documents
looked clipped. loadPdfInline now renders every page (capped at MAX_PAGES=20
for memory) sequentially into a scrollable .pdf-preview-body, shows the page
count in the header, and appends a "Showing the first N of M pages" notice
(pdf_truncated, 13 locales) when the PDF exceeds the cap.

Robustness: renderPage(i) attaches each canvas only AFTER its render
promise resolves, and a per-page failure is caught and skipped
(`.then(()=>renderPage(i+1)).catch(()=>renderPage(i+1))`) so one corrupt
page can't halt the preview or surface an unhandled rejection. XSS-safe
(esc(fname), t() with numeric args).

Co-authored-by: Gouranga satapathy <29521030+gourangasatapathyvit@users.noreply.github.com>
2026-06-17 20:57:38 +00:00
edoumoandRod Boev 9194ade18f fix: report non-git installs as "can't check" instead of "up to date" (#4356)
Docker images and pip installs have no .git directory, so _check_repo
returned None and the frontend interpreted both update-target parts being
falsy as "Up to date" — a stale Docker image would misleadingly look
current. _check_repo now returns a minimal sentinel dict ({name, behind:
None, no_git: True}) instead of None so the Settings panel can distinguish
"can't check" from "up to date", and _formatUpdateTargetStatus /
checkUpdatesNow surface a localized "Can't check for updates" state
(settings_update_no_git, added across all 13 locale blocks). In mixed
deployments where one component has a git checkout and the other does not,
the valid git-side update info is still shown. The sentinel's behind: None
flows safely through the existing notification/summary builders, which all
gate on int(info.get('behind') or 0) > 0.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-17 16:36:26 +00:00
edoumoandEd 446cd2cd98 fix: prevent cross-provider model selection from silently reverting to default (#4363)
When the model dropdown rebuilds (panel switch, provider refresh, or a
live-model fetch that times out and serves a fallback catalog), a
cross-provider selection could vanish from the refreshed catalog and the
browser would snap the <select> back to its first <option> (the default
model). _reconcileModelDropdownSelection now routes each selection branch
through an _applyOrEnsure helper that delegates to
_ensureModelOptionInDropdown, re-injecting the chosen model as a custom
option when it is missing from the rebuilt catalog instead of returning
null. Branch order and per-branch model/provider arguments are unchanged.

Maintainer note: simplified the contributor's helper to delegate straight
to _ensureModelOptionInDropdown (which already applies-first-then-injects),
removing a redundant double scan; re-pointed the
test_populate_model_dropdown_reconciles_selection_after_rebuild string
assertions to the new form (the behavioral node-driver tests for boot-default
precedence and in-page selection preservation are unchanged and still pass).

Co-authored-by: Ed <edou@edoudoux.com>
2026-06-17 16:22:51 +00:00
nesquena-hermesandlinux-fertxo ef6f43c69c Release v0.51.475 — ElevenLabs TTS engine (#3510)
Ships @linux-fertxo's ElevenLabs TTS engine: selectable alongside Browser and
Edge TTS, using the agent's existing ELEVENLABS_API_KEY + tts.elevenlabs config.
ElevenLabs is a built-in Hermes TTS provider (Anchor A parity). Backend validates
voice_id as a safe path segment, honors the 5000-char cap + rate limit.

Rebased onto current master (552 behind; net code-diff applied, byte-identical to
PR head). Added regression coverage (test_issue3510_elevenlabs_tts.py): missing-key
503, config voice_id traversal rejection, happy-path mp3 stream, shared char-cap.

Co-authored-by: linux-fertxo <linux-fertxo@users.noreply.github.com>
2026-06-17 05:50:37 +00:00
nesquena-hermes 810414b438 feat(#4325): opt-out toggle to disable transcript virtualization
Adds a Preferences setting 'Virtualize long transcripts' (default ON, opt-out).
When disabled, _currentMessageVirtualWindow returns a full non-virtualized window
so the entire transcript renders at once (also short-circuits the virtual
re-measure loop). Server-persisted (virtualize_transcript bool, default True),
hot-applies via renderMessages on toggle. i18n in all 13 locales.

Pairs with @rodboev's #4328 stream-end anchor scroll fix (cherry-picked into
this branch) to fully resolve #4325.
2026-06-17 01:52:06 +00:00
Rod Boev 31191a6c50 fix(scroll): mount virtualized-out anchor row before same-frame restore 2026-06-17 01:42:44 +00:00
Rod Boev 387af5d9c9 fix(scroll): remove synchronous _programmaticScroll toggle around DOM clear 2026-06-17 01:42:44 +00:00
Rod Boev 152b44c138 Clear _programmaticScroll after innerHTML wipe to prevent stuck flag on early-return paths 2026-06-17 01:42:44 +00:00
Rod Boev b24aa661dc fix(#4325): use semantic viewport anchoring for stream-end scroll restore 2026-06-17 01:42:44 +00:00
nesquena-hermesandRod Boev 53adcfc33f feat(#4226): display symlinks in workspace file tree (#4228)
Render symlinks in the workspace file tree with a distinct chain-link
icon (vs regular file/folder icons), and show "Symlink → {target}" on
hover with long targets middle-elided. Directory and file symlinks are
both handled; regular entries keep their normal icons.

Rebased onto master (v0.51.466) and code-diff verified byte-identical to
the contributor's PR head before staging.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-16 23:24:15 +00:00
nesquena-hermes 62a65a4ff1 review polish: surface plugin-provider check failures at warning (greptile P2) + fix #4253 comment mislabel
Independent review (APPROVED clean) + greptile both flagged one non-blocking nit:
_is_known_model_provider swallowed a transient _is_plugin_model_provider failure
at debug level, so a real plugin-backed provider could briefly vanish from the
picker with no visible log. Promoted to logger.warning(exc_info=True).

Also corrected the endpoint-error-hint comments in ui.js: they cited #4253, which
is actually a cron release (mislabel carried from #4279's body). Comment-only —
no logic change to the browser-verified collapsible-groups code.
2026-06-16 22:09:57 +00:00
nesquena-hermesandakrhin 872a8a391e feat(model-picker): collapsible provider groups — collapsed-except-selected, cleaner show-more, de-noised rows
Builds on #4279's collapsible-group foundation and extends it into a complete
provider-group UX:

- Groups start COLLAPSED except the group that owns the selected model, so the
  picker opens scannable instead of as a long flat list. Search auto-expands
  matching groups (and searches hidden overflow models); clearing the search
  restores the collapsed-except-selected view.
- 'Show more' restyled as a distinct '+ Show all N models' expander (muted
  italic, indented, no model-id line) that reveals overflow IN PLACE — the group
  stays open, other groups keep their state, and the view scrolls to the newly
  revealed models instead of resetting to the top. Falls back to a full
  re-render in minimal/headless DOM. Endpoint-error groups (#4253) and the
  expanded group persist correctly across a search round-trip.
- Per-row provider chip suppressed for rows already under their own provider
  heading (removes the repetitive 'provider on every row' noise); kept for
  hoisted/search rows.

Verified end-to-end on desktop + mobile 390px (collapse/expand, search +
overflow-search + clear-reset + no-results, load-more in-place + stay-open +
scroll-to-new, endpoint-error visibility). #3691 driver tests updated for the
collapsible-group structure + de-noised chip. In-place-path CI coverage tracked
in #4331.

Co-authored-by: akrhin <akrhin@users.noreply.github.com>
2026-06-16 21:45:30 +00:00
32458c442b Release PI (v0.51.448): fix blank transcript viewport regression (#4277) (#4288)
* stage-4281: restore virtualized transcript viewport anchors (fixes #4277, #3714 regression)

* Release PI: fix blank transcript viewport regression (#4277, #3714 follow-up)

rodboev's #4281. Codex SAFE + Opus net-positive-and-safe + 20 virtualization/
scroll tests green. Viewport-anchor restore + blank-state recovery.

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

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-15 18:43:14 -07:00
nesquena-hermesandnesquena-hermes 70b7cf865c Release PH (v0.51.447): toolset selector shows active-profile defaults (#3100) (#4287)
* stage-3632: surface active-profile toolset defaults in selector (#3100)

* Release PH: toolset selector shows active-profile defaults (#3100) — CHANGELOG

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-06-15 18:00:13 -07:00
0b0e2a3213 Release PG (v0.51.446): model picker show-all overflow for large catalogs (#3691) (#4282)
* stage-3712: model picker show-all overflow + fix per-row count leak (#3691)

Self-rebased rodboev's #3712 onto master. FIX (Nathan-caught): the per-row
provider chip stripped the '(N of M)' overflow count — that count belongs on the
group heading only, and was reading as nonsense post-expand (row 30 showing
'15 of 30'). Updated test to assert heading-carries-count + rows-do-not.

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

* stage-3712: + dedupe overflow expand (Codex SILENT) — reuse existing injected option

Codex caught: select hidden overflow model from search → reopen → Show all could
duplicate the row (_appendOverflowOptionsToGroup blindly appended every extra
model without checking the select for an already-injected option). Now moves/reuses
an existing same-value option instead of re-creating it.

* stage-3712: + fix expanded-heading double-count (Opus) — strip decoration, count rendered rows

Opus caught: post-expand the heading showed 'Nous (2 of 4) (4)' (appended its own
count onto the already-decorated backend label) and used modelCount (incl hoisted-
configured) vs rendered rows. Now strips the '(N of M)' suffix when expanded +
counts groupRows.length. Test asserts no double count on out[expanded].

* stage-3712: + include extra_models in Settings/Cron/Profile/Aux native selectors (Codex CORE)

Codex caught: the server overflow split moves models>15 into extra_models for ALL
providers, but the 4 native <select> builders in panels.js (settingsModel:6690,
cronFormModel:1112, profileFormModel:5784, _auxProviders:8287) read g.models only
— silently dropping the overflow tail for large providers. Now concat
models+extra_models at all 4 sites. Test guard added.

* Release PG: model picker show-all overflow for large provider catalogs (#3691)

Self-rebased rodboev's #3712 onto v0.51.445; full browser-tested (desktop+mobile,
before/after) + Nathan screenshot-approved. 4 gate-caught issues fixed inline:
per-row count leak (Nathan), overflow-expand dedup (Codex), heading double-count
(Opus), and native Settings/Cron/Profile/Aux selectors dropping the overflow tail
(Codex CORE). Codex SAFE + Opus SHIP + 41 picker tests green.

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

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-15 17:16:36 -07:00
fe12eebbf3 perf(chat): virtualize long message transcripts (#500) (#4214)
* perf(chat): virtualize long message transcripts (#500)

* fix(chat): preserve virtual height cache on append (#500)

* fix(chat): bound virtual tail follow-up (#500)

* fix(chat): surface older history and bound virtual rerenders (#500)

* fix(chat): stabilize virtual history fallback (#500)

* fix(chat): preserve virtual compression anchors (#500)

* Keep virtualization regressions aligned with rebased sources (#500)

* fix(chat): preserve virtual heights across prepends (#500)

* test(update): isolate restart timing checks (#814)

* fix(chat): restore render contracts around virtual cache

* fix(chat): preserve legacy assistant anchor predicates

* fix(#3714): restore worklog-disclosure capture after HTML-cache early-return

Deep-review finding: the capture of _captureWorklogDetailDisclosureState was
moved before the HTML-cache fast-path return, failing the invariant test
test_render_rebuild_preserves_worklog_detail_disclosure_click_state (it must
not traverse the previous-session DOM when the cache path returns early).
Moved it back to just before inner.innerHTML='' (after the cache return).

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* fix(#3714): restore Transparent Stream rehydration in HTML-cache fast path

Full-suite gate caught test_issue3820_chat_activity_display_mode failure: the
virtualization rewrite of the renderMessages HTML-cache fast-path block dropped
the _rehydrateTransparentStreamDom(inner) call (master has it; PR had 2 of 3
occurrences). On a cache-restore session switch, Transparent Stream controls
lost their property-assigned handlers. Restored the call in the same position
master has it (right after _sessionHtmlCacheSid=sid).

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* fix(#3714): preserve live turn on scroll-rebuild even with zero streamed text

Opus ship-review residual (now fixed, not deferred): the live-turn re-attach
after a scroll-triggered virtualized rebuild was gated on _preservedLen>0, so a
turn showing only Activity/tool/worklog blocks with no streamed text yet (mid
tool-call) would not be preserved — scrolling up into history on a >80-row
transcript mid-stream could blink those live-only blocks for a frame. Broaden
the gate to also restore when the preserved turn has MORE structural blocks than
the rebuilt (lagging-S.messages) turn. Hoisted the _structuralCount helper above
the gate; whole-turn-vs-segment restore logic unchanged.

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* chore(release): stamp v0.51.423 (Release OJ) for #500 transcript virtualization

---------

Co-authored-by: Rod Boev <rod.boev@gmail.com>
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-06-14 19:11:32 -07:00
92ecf8edb4 fix(models): preserve colon-suffixed model IDs in normalization (#3959, ships #4196) (#4204)
* fix(models): preserve colon-suffixed model IDs in normalization (#3959)

* fix(models): align configured-model normalizer parity (#3959)

* chore(release): stamp v0.51.421 (Release OH) CHANGELOG for #3959/#4196

---------

Co-authored-by: Rod Boev <rod.boev@gmail.com>
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-06-14 16:27:39 -07:00
nesquena-hermes 51c4f06038 Release NX (v0.51.411): stamp CHANGELOG + bound offline /health probe with 3s timeout (Opus SHOULD-FIX on #4179) 2026-06-14 17:11:13 +00:00
Rod Boev 11f50350f0 fix(recovery): prevent duplicate offline soft recovery 2026-06-14 10:20:21 -04:00
Rod Boev 85e26705da fix(recovery): verify offline browser state before banner (#4170) 2026-06-14 09:55:43 -04:00
nesquena-hermesandRod Boev a875bcbb9e feat(ux): enlarge Mermaid diagrams in chat (#4075) + workspace CSV table preview (#4025)
Combined light-UX release NW. Both rebased onto current master (were 96 and
247 behind; net 3-dot diffs applied, byte-identical to PR heads). Both reuse
existing renderers (chat image lightbox / chat CSV table renderer).

Review fix (#4025, Codex): the CSV table preview previously stripped the
workspace Edit affordance .csv had when it fell through to the code preview.
Restored: csv mode is editable, renderCsvPreviewContent caches raw content for
the edit textarea, and saving an edited CSV re-renders the table (not markdown).
Verified the full edit round-trip live + regression test.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-14 06:12:24 +00:00
nesquena-hermes cd5a6de231 fix(transparent-stream): keep live prose chronological, don't fold into top Worklog rail (#4096)
In Transparent Stream mode a live multi-round turn (narrate -> tools ->
narrate -> tools) rendered all assistant prose bunched at the top with
every tool/thinking row clustered below; it self-healed only once the
turn settled.

_syncLiveWorklogReasonsForAnchor() runs on every live segment render
(_flushPendingSegmentRender + the RAF _doRender in messages.js) and
unconditionally built the top-anchored live-worklog rail, mirrored each
round's prose into a wl-reason row there, and hid the real inline
assistant-segment via assistant-segment-worklog-source (display:none).
That prose-folding is the Compact Worklog presentation (#3401) and must
not run in Transparent Stream mode.

Gate the helper on isCompactWorklogMode() so transparent mode keeps prose
as visible, chronologically-placed inline segments interleaved with tool
rows (matching the already-correct settled render). Compact Worklog
folding is unchanged. Verified in an isolated mock-LLM env via an
on-screen visual-position probe (before: textAfterFirstTool=0,
allTextAboveAllTools=true; after: textAfterFirstTool=3,
allTextAboveAllTools=false) and confirmed compact_worklog still folds.

Adds a behavioral regression test asserting the gate is the first
statement in the helper (precedes the rail build), red/green validated.
2026-06-14 02:18:33 +00:00
Rod Boev e5640a42b9 Keep prompt-attention title badges from breaking title ownership 2026-06-13 15:05:03 -04:00
Rod Boev 4329768288 feat(topbar): badge pending prompts in document title (#4121) 2026-06-13 15:04:20 -04:00
Frank Song 0fdcd00858 Fix PWA final answer scroll refresh 2026-06-14 01:46:04 +08:00
Frank Song b990bd09dd feat(anchor): project settled final answer through anchor 2026-06-13 13:23:15 +08:00
nesquena-hermes 2bd8b40b15 harden(#4063): stamp disclosure-state snapshot with session id (Opus belt-and-suspenders)
_captureWorklogDetailDisclosureState stamps state._sid; _restoreWorklogDetailDisclosureState
skips restore on sid mismatch. Cross-session isolation no longer depends solely on the
sessions.js #msgInner wipe invariant — a future change to that loading-placeholder
behavior can't silently replay one session's collapse state onto another.
2026-06-13 04:47:36 +00:00
nesquena-hermes c9930d2a3d Merge #4063 (preserve Worklog detail disclosure across rebuilds) onto master
# Conflicts:
#	CHANGELOG.md
#	static/ui.js
2026-06-13 04:41:17 +00:00
nesquena-hermes 6ced477822 fix(#4006): explicit-settle flag + pre-wipe snapshot capture (Codex r3)
1. _settleMessageScrollToBottom(force, explicit): when explicit (End-button /
   scrollToBottom), late-layout settling runs even with Auto-follow OFF — the
   setting only suppresses AUTOMATIC follow, not a deliberate jump. The RO + 2s
   fallback guards now bail on (!_autoScrollFollow && !explicit). scrollToBottom()
   passes explicit=true; the automatic scrollIfPinned() path stays guarded.
2. renderMessages now captures the pre-wipe scrollSnapshot when (Auto-follow off
   && user unpinned) too, so the non-preserve restore lands the reader where they
   were instead of receiving a null snapshot (no-op).
2026-06-13 04:16:48 +00:00
nesquena-hermes 2bdef4166f fix(#4006): gate the #3920 RO settle + render fall-through on _autoScrollFollow (Codex cross-PR catch)
Codex found that with Auto-follow OFF the #3920 ResizeObserver settle + 2s fallback
+ the non-preserve render path still force-scrolled to bottom (the setting was
incomplete vs the scroll machinery shipped in #3920). Fixes:
1. RO settle guard (ui.js:3153): bail when !_autoScrollFollow.
2. 2s static fallback guard (ui.js:3186): bail when !_autoScrollFollow.
3. non-preserve render fall-through (ui.js:8653): when Auto-follow off AND the user
   has unpinned, restore the scroll snapshot instead of scrollToBottom() — also
   closes the send() race (renderMessages runs before S.activeStreamId is set).
   A fresh session load (not unpinned) still lands at the bottom. Explicit
   user-initiated scrollToBottom() (End button) is untouched.
2026-06-13 04:09:58 +00:00
nesquena-hermes c02c31c837 Merge #4006 (scroll auto-follow setting + pin guards) onto master
# Conflicts:
#	api/config.py
#	static/panels.js
2026-06-13 03:54:11 +00:00
nesquena-hermes b5eabe1494 fix(#3920): apply Codex gate findings — observe #msgInner, instance-owned RO cleanup, restore .messages overflow-anchor
Codex SHIP-ONLY-WITH-FIXES (3 real issues; Codex+Opus disagreed on #1, stricter wins):
1. CORE — .messages lost overflow-anchor:none, reopening the #1360 (d21c9720) streaming-scroll-anchor regression. Restored it (native anchoring stays OFF; the RO does the settle). Opus had judged this removal acceptable; took Codex's stricter call.
2. SILENT — the ResizeObserver observed #messages (the scroll container, fixed by flex layout, never resizes) instead of #msgInner (.messages-inner, the growing transcript node) → callback would never fire. Now observes #msgInner.
3. SILENT — stale RO callbacks mutated the global _settleRO, which could disconnect a newer active observer after settle re-entry. Now instance-owned: close over const ro, only clear the global when _settleRO===ro.
2026-06-13 03:32:16 +00:00
nesquena-hermes f9055c5d97 fix(#3920): address review — restore sidebar overflow-anchor, wire _settleFinalScroll via 2s fallback, + CHANGELOG v0.51.377
3 maintainer-review items the contributor hadn't addressed:
1. (blocking) restored .session-list overflow-anchor:none — the PR accidentally reverted the deliberate Firefox sidebar fix (2dfe765b); only the on-topic .messages removal is kept.
2/3. _settleFinalScroll was dead code + the promised 2s static-content safety timeout was missing — wired _settleFinalScroll(token) via a single 2s top-level fallback after _settleRO.observe(el), declared _settleFinalTimer + cleared it in _cancelBottomSettle and at settle re-entry.
2026-06-13 03:25:48 +00:00
nesquena-hermes 965baeb78c Merge #3920 (Firefox scroll ResizeObserver) onto master 2026-06-13 03:23:49 +00:00
nesquena-hermes 35877dab1b fix(#3971): move show-thinking gate to the real Worklog render paths (Opus catch)
Opus final gate caught that the staged re-implementation placed the
window._showThinking===false gate in _worklogReasonNodeFromText, which has
ZERO callers — so live/settled reasoning rows (built by _syncWorklogReasonFromAnchor
and _appendWorklogReason) were never actually hidden, and removeThinking swept
data-worklog-reason-source=reasoning which the real rows (data-worklog-anchor-reason=1)
don't carry. The string-match tests passed against the dead function = green-suite blind spot.

Fix:
- Gate _syncWorklogReasonFromAnchor (live + settled): when _showThinking===false, remove any
  existing reasoning row and bail before building.
- Gate _appendWorklogReason (settled rebuild): return null when _showThinking===false.
- removeThinking + the settled-rebuild cleanup now sweep BOTH data-worklog-anchor-reason=1
  (the real attribute) and the legacy data-worklog-reason-source=reasoning.
- Re-anchor the tests to assert against the real render functions + the correct attribute.
2026-06-13 03:09:50 +00:00
nesquena-hermes 52c502a984 Merge #3971 (hide Worklog reasoning when Thinking disabled) onto master 2026-06-13 02:52:31 +00:00
nesquena-hermes c45adb910a fix(#4024): wire dormant recency-fade to live turn + include Interrupted in progress-bar completed set (Opus final-gate observations)
- _applyTransparentRowFading was only called from the settled loop (which the fn skips), so live-turn recency fade never applied — now called from _syncTransparentEventControls (internally live-gated, no-ops on settled).
- _attachProgressBar isCompleted now includes Interrupted so an interrupted row's bar fills 100% instead of rendering empty.
2026-06-13 01:53:11 +00:00
nesquena-hermes d952dfe3a2 fix(#4024): trifecta round-2 — rehydrate root-turn, always-preserve detail tab, drop redundant Running: name prefix
- C1-r2 (both Codex+Opus): _rehydrateTransparentStreamDom now also rewires the root element when it IS the assistant turn (querySelectorAll only matched descendants), so turn-toggle + event-controls re-bind after a live-turn restore.
- O-Bug2-r2: preserve the Full/Output detail tab regardless of open state.
- r2 #4: drop the 'Running: ' name prefix — the legible status badge already carries it (V6 redundancy class).
2026-06-13 01:16:56 +00:00
nesquena-hermes ed3ac13fc5 fix(#4024): trifecta UX + correctness pass — rehydrate live-restore, thinking dedup, quiet thinking rows, legible failures, skin-proof reset, compact args, flat output, live-only fade/anim
Functional (Codex+Opus trifecta findings):
- C1: restoreLiveTurnHtmlForSession now calls _rehydrateTransparentStreamDom (controls were dead after active-session live-turn restore).
- O-Bug1: per-turn echoed-thinking dedup in the transparent settled path (mirrors the compact seenReasons), fixes duplicate out-of-order Thinking rows.
- O-Bug2: tool completion preserves the row's open state + Full/Output tab.
- O-Edge: settled/reloaded done===false tools show 'Interrupted' (not a permanent Running shimmer); progress bar clears for Interrupted too.

Visual (trifecta CSS):
- V1: reset .thinking-card to flat/transparent (was the heaviest object in the stream).
- V2: failed=error color + left border, running/interrupted legible (was an invisible muted badge).
- V3: scoped !important reset beats the 6 per-skin .tool-card re-card rules.
- V4: inline key:value args (was a tall stacked form).
- V5/V7: output pre flattened to a quiet left-rail, max-height:none (one expanded zone, no nested scroll).
- V6: drop redundant tool/status pseudo-args from the detail body.
- V8: row fading gated to the live turn only + floor raised for WCAG; settled history stays full-opacity.
- V9: entrance animation scoped to #liveAssistantTurn (was replaying on every renderMessages).
- V10: larger mobile header tap targets + active detail-tab underline.

O-Bug3 (live thinking overwrite when no seq) intentionally deferred — documented follow-up; settled render is already correct and a live heuristic risks a streaming regression.
2026-06-13 01:08:41 +00:00
nesquena-hermes 92f7a24448 Merge #4024 Transparent Stream onto master (rebase)
# Conflicts:
#	CHANGELOG.md
2026-06-13 00:40:17 +00:00
Frank Song 9f0e76c182 Preserve worklog detail disclosure state 2026-06-13 07:43:12 +08:00