Commit Graph
100 Commits
Author SHA1 Message Date
nesquena-hermes 31f2ec31c0 docs(changelog): stamp #3224 nested forks as v0.51.407 (Release NT) 2026-06-14 04:36:45 +00:00
nesquena-hermes c73da44757 docs(changelog): stamp #3866 project-context Memory tab as v0.51.406 (Release NS) 2026-06-14 03:49:17 +00:00
nesquena-hermes 918139461b docs(changelog): stamp #4096 transparent-stream live prose fix as v0.51.405 (Release NR) + fix changelog blank-line nit (greptile P2) 2026-06-14 02:58:12 +00:00
nesquena-hermes b8a84f13e1 docs(changelog): stamp #4151 PWA multi-window SSE fix as v0.51.404 (Release NQ) 2026-06-14 01:33:14 +00:00
nesquena-hermesandddiall 408dbeb4f0 fix(sse): close global sidebar streams on PWA window blur (#4151)
Two side-by-side PWA standalone windows saturate the browser's per-origin
HTTP/1.1 connection limit, causing 'Request timed out' toasts to cycle every
~30s. The idle-SSE close added in #3992/#3996 keys off the Page Visibility API
(visibilitychange / document.hidden), but a PWA standalone window does not
reliably fire visibilitychange when it loses focus to another window of the
same app -- document.hidden only flips on minimize. So both windows stay
'visible', each holds its two global sidebar SSE streams (session-events +
gateway) open, 2x3 = 6 hits the connection cap, and subsequent fetch() calls
(the 30s background polls) queue behind the saturated pool and time out.

The two global sidebar streams now also close on a sustained window blur (gated
on document.hasFocus(), the signal visibilitychange misses) and reopen --
catching up the session list -- on focus, via a shared _sidebarSseBackgrounded()
predicate and a debounced _installSidebarSseFocusHook().

The per-session live stream (messages.js startSessionStream) is intentionally
left visibility-only: it carries live bg_task_complete toasts and
server_turn_started live-view that an unfocused-but-visible window must still
receive (the OS-notification path is gated on document.hidden, so the in-app
toast is the only completion signal a visible-unfocused window gets). Closing
it on blur would regress the multi-window live-view UX.

Reported by @ddiall with a thorough root-cause analysis.

Co-authored-by: ddiall <ddiall@users.noreply.github.com>
2026-06-14 00:54:28 +00:00
nesquena-hermes 219635f8ae docs(changelog): stamp #4109 notification focus-existing-tab as v0.51.403 (Release NP) 2026-06-14 00:26:15 +00:00
nesquena-hermes e044a2e938 Merge #4143 (focus existing chat tab on notification click, #4109) onto master 2026-06-14 00:25:09 +00:00
nesquena-hermes e069a2dbcc docs(changelog): stamp #4087 skill-bundle slash commands (precedence-fixed) as v0.51.400 (Release NM) 2026-06-13 23:14:31 +00:00
nesquena-hermes 5812df5f7b Merge #4112 (skill bundles in WebUI slash commands, #4087) onto master 2026-06-13 23:13:28 +00:00
nesquena-hermes c0ea19407b docs(changelog): stamp #3940 v2 (claim-under-pool-lock) as v0.51.399 (Release NL) 2026-06-13 22:05:58 +00:00
nesquena-hermes fa19eae6d1 Merge #3940 v2 (claim probe workers under pool lock, #3787) onto master 2026-06-13 22:05:05 +00:00
nesquena-hermes 961bfbd2ba docs(changelog): stamp #3987 v2 (reload-before-save) as v0.51.398 (Release NK) 2026-06-13 21:47:42 +00:00
nesquena-hermes 4f1ce2661e Merge #3998 v2 (imported-session titles + reload-before-save fix, #3987) onto master 2026-06-13 21:46:36 +00:00
nesquena-hermes e0e4ebfde5 docs(changelog): stamp #4071 /credits WebUI command as v0.51.397 (Release NJ) 2026-06-13 21:16:33 +00:00
nesquena-hermes f7047d4d19 Merge #4072 (wire /credits through WebUI command dispatch, #4071) onto master 2026-06-13 21:15:22 +00:00
nesquena-hermes 31af2da234 docs(changelog): stamp #4139 full-history-load timeout as v0.51.396 (Release NI) 2026-06-13 20:44:06 +00:00
nesquena-hermes fd972ff2a5 Merge #4139 (extend timeout for full-history session loads) onto master 2026-06-13 20:42:17 +00:00
nesquena-hermes c117d57706 docs(changelog): stamp #3930 source-filter pushdown as v0.51.395 (Release NH) 2026-06-13 20:18:54 +00:00
nesquena-hermes 12107f3ae5 Merge #4011 (push source filters into agent session scans, #3930) onto master 2026-06-13 20:17:51 +00:00
nesquena-hermes 5a33a51cec Merge #4131 (badge pending prompts in document title, #1694) onto master
# Conflicts:
#	CHANGELOG.md
2026-06-13 19:19:24 +00:00
nesquena-hermes 9240a7d429 docs(changelog): stamp #4127 /yolo busy-send as v0.51.393 (Release NF) 2026-06-13 19:05:44 +00:00
nesquena-hermes 45b88b55b7 Merge #4127 (run /yolo immediately on busy send path) onto master 2026-06-13 19:04:13 +00:00
nesquena-hermes 30cc15975e fix(#4130): coerce stale 'max' in get_reasoning_status read path too (Codex catch)
get_reasoning_status() returned the raw config reasoning_effort, so a stale saved
'max' surfaced on boot/status/chip even though streaming coerces it to xhigh. Now
routes the status value through coerce_reasoning_effort_for_model() with the resolved
model/provider/base_url, so all read paths agree. Added a stale-max->xhigh status
regression test.
2026-06-13 18:50:00 +00:00
nesquena-hermes bf6efb1a05 docs(changelog): stamp #4130 reasoning-effort alignment (drop max) as v0.51.392 (Release NE) 2026-06-13 18:44:41 +00:00
nesquena-hermes 540af21444 Merge #4130 (hide unsupported max reasoning effort from WebUI) onto master 2026-06-13 18:43:11 +00:00
nesquena-hermes acac104362 Merge #4126 (anchor renderer snapshot adapter, slice 8, inert) onto master
# Conflicts:
#	CHANGELOG.md
2026-06-13 18:20:36 +00:00
nesquena-hermes 0805f557e9 test(#4124): re-anchor scroll-cue test to readerAwayFromBottom-guarded early-return 2026-06-13 18:07:59 +00:00
nesquena-hermes 8db88c882d fix(#4123): preserve reader position on PWA same-session refresh + re-anchor 2 scroll tests
#4124: treat preserved snapshot bottom>250px as active reader (restore before follow-to-bottom),
re-mark restored mid-answer as unpinned, scope _resetScrollDirectionTracker to real session
switches only. Re-anchored test_preserve_scroll_restores_unpinned_viewport + test_render_messages_
preserve_scroll to the new readerAwayFromBottom-guarded early-return (was pinning the old exact line).
CHANGELOG stamped v0.51.390 (NC).
2026-06-13 17:53:53 +00:00
nesquena-hermes 670691c387 Merge #4124 (fix PWA final answer scroll refresh) onto master
# Conflicts:
#	CHANGELOG.md
2026-06-13 17:51:36 +00:00
nesquena-hermes 465d229800 Merge #4103 (surface dirty install state in update-check, #4085) onto master
# Conflicts:
#	CHANGELOG.md
2026-06-13 17:38:48 +00:00
nesquena-hermes 33b7517b81 docs(changelog): stamp #4120 anchor dual-run reconciler (inert, slice 7) as v0.51.388 (Release NA) 2026-06-13 17:24:12 +00:00
nesquena-hermes 3e6309d8a8 Merge #4120 (assistant turn anchor dual-run reconciler, slice 7, inert) onto master 2026-06-13 17:22:56 +00:00
nesquena-hermes 310edac58e fix(#4108): add creation-time backstop cleanup to bound the registry-leak class
Codex found leak paths across 3 rounds (settled-restore, stream-end-fallback, reconnect-
preflight-inactive, stale-bailout, non-current-pane error, external cancelSessionStream).
Rather than chase every current+future teardown route, schedule an identity-guarded cleanup
at registry CREATION (600s) so window._liveAnchorRegistries self-expires no matter how the
stream ends — including external paths (boot.js cancelSessionStream) that bypass the SSE
handlers. Explicit terminal-path calls just expire it sooner. Shadow-only + identity-guarded,
so a rare >10min active stream only loses reconnect-continuity of an unconsumed registry.
2026-06-13 16:19:18 +00:00
nesquena-hermes 3cf96b1293 fix(#4108): cleanup anchor registry on reconnect-preflight-inactive + stale-stream-bailout paths (Codex round 2)
Two more early-return paths created the registry (early in attachLiveStream) then
returned without scheduling cleanup: (1) reconnect preflight when /api/chat/stream/status
is inactive/no-replay (~3966); (2) _bailOutOfTerminalEventsFromStaleStream (~1490) when a
stale stream's terminal event arrives after a newer stream owns the session. Both now
schedule identity-guarded cleanup (map.get(streamId)===registry, keyed on the stale
closure's own streamId so the newer registry is untouched).
2026-06-13 16:13:55 +00:00
nesquena-hermes 9594b97223 fix(#4108): schedule anchor registry cleanup on settled-restore + stream-end-fallback terminal paths (Codex leak catch)
Codex found window._liveAnchorRegistries retained registries for streams ending via
_restoreSettledSession() and _finalizeStreamEndFallback() (both terminal-close without
cleanup). Added _flushReasoningToAnchor()+_scheduleAnchorRegistryCleanup() to both —
identity-guarded delete already prevents clobbering a newer registry. All anchor helpers
are nested in attachLiveStream's closure (hoisted), ESLint runtime gate clean.
2026-06-13 16:09:20 +00:00
nesquena-hermes fcad7d6db2 docs(changelog): stamp #4108 anchor live shadow feed (inert) as v0.51.387 (Release MZ) 2026-06-13 16:05:06 +00:00
nesquena-hermes 30dd5647ed Merge #4108 (Stable Assistant Turn Anchors: live shadow feed, slice 6) onto master 2026-06-13 16:03:35 +00:00
nesquena-hermes 8b5c8e32fd docs(changelog): stamp #3983 voice-mode watchdog as v0.51.386 (Release MY) 2026-06-13 07:38:19 +00:00
nesquena-hermes f61f88f16b Merge #4016 (re-arm browser voice mode when speechSynthesis drops, #3983) onto master 2026-06-13 07:37:31 +00:00
nesquena-hermes a31466b1a3 docs(changelog): stamp #803 profile-cookie env var rename as v0.51.385 (Release MX) 2026-06-13 07:21:34 +00:00
nesquena-hermes 6e6931a8c3 Merge #4028 (align profile cookie env var with HERMES_WEBUI_ prefix) onto master 2026-06-13 07:20:58 +00:00
nesquena-hermes e129203854 test(#3899): re-anchor 4 test_inflight_stream_reuse tests to post-#3899 loadSession shape
rfind for the Phase-2 INFLIGHT branch (idle-reset added an earlier if(INFLIGHT[sid]){);
and test_load_session_attaches_sse_before_auxiliary_work now asserts each auxiliary call
individually (the old contiguous syncTopbar();renderMessages();appendThinking();loadDir
literal was legitimately broken up by the new restoreLiveTurnHtmlForSession insertion +
renderMessages(preserveScroll) arg — all calls still run after attachLiveStream). Behavior unchanged.
2026-06-13 07:10:15 +00:00
nesquena-hermes 377a1889aa test(#3899): widen 2 more fixed-window loadSession slices displaced by idle-reset block
test_issue3306 _load_session_clear_block (4000->6500) + test_issue_new_chat_draft_restore
body window (4000->6500): #3899's idle-reset + live-turn-snapshot blocks pushed the
carry-forward snapshot + destructive S.messages clear past the old fixed windows. Behavior
+ ordering unchanged; windows widened to contain them.
2026-06-13 06:55:36 +00:00
nesquena-hermes 5f3e0ab8d9 test(#3899): re-anchor 5 brittle source-window tests displaced by the idle-reset block
#3899's new idle-reset added an EARLIER if(INFLIGHT[sid]){ block in loadSession, so
4 test_regressions tests' src.find('if(INFLIGHT[sid]){') grabbed the wrong (idle-cleanup)
occurrence instead of the Phase-2 restore branch → switched to rfind (the substantive
branch). And the idle-cleanup comment changed from 'discard any browser-side inflight'
to 'reset browser-side streaming flags' → re-anchored test_frontend_drops_inflight_cache
on the new comment + nested if(!activeStreamId){...if(INFLIGHT[sid]){ form (behavior
preserved + enhanced). No production code changed.
2026-06-13 06:48:21 +00:00
nesquena-hermes 5bbddbad1e fix(#3900): false streaming + activity-timer reset on session switch (absorb #3899) + re-anchor regression tests
Production fixes (Tamaz-sujashvili, reviewed sound by maintainer):
- loadSession clears S.busy/S.activeStreamId as soon as metadata confirms no active_stream_id, before the async message-load gap (idle session no longer shows streaming chrome).
- Snapshots the live turn before wiping msgInner + seeds INFLIGHT, restores on the active-stream return path (timer/trace survive switch-back).

Re-anchored the 2 brittle regression tests per maintainer review: test_..snapshots.. now anchors on the unique 'Loading conversation...' marker (was matching the no-space 'Session not available' error path); test_..restores.. now asserts the LIVE Phase 2a restore (after loadInflightState) instead of the unreachable Phase-2b/1184 branch. CHANGELOG stamped v0.51.384 (MW).
2026-06-13 06:39:22 +00:00
nesquena-hermes 8c54973ed4 docs(changelog): stamp #4086 document-title-owner fix as v0.51.383 (Release MV) 2026-06-13 06:12:28 +00:00
nesquena-hermes d85fd2c967 Merge #4094 (preserve session document title during bot-name refresh) onto master 2026-06-13 06:11:24 +00:00
nesquena-hermes 4eec21c434 docs(changelog): stamp #4093 activity-scene projection (inert) as v0.51.382 (Release MU) 2026-06-13 05:56:53 +00:00
nesquena-hermes 9cf67cbeb2 Merge #4093 (anchor activity scene projection + tool_limit_reached stream label) onto master 2026-06-13 05:56:09 +00:00
nesquena-hermes f230a16f4d docs(changelog): stamp #4092 settled final-answer projection as v0.51.381 (Release MT) 2026-06-13 05:36:35 +00:00
nesquena-hermes 841d78d4e5 Merge #4092 (assistant turn anchor settled final projection) onto master 2026-06-13 05:36:00 +00:00
nesquena-hermes e4bdcbfeae Merge #3823 (tool iteration limit terminal state) onto master
# Conflicts:
#	CHANGELOG.md
2026-06-13 05:06:46 +00: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 f5fb50983b fix(#4006): defensive !==false at the 2 remaining settings-hydration sites (Opus note)
panels.js _autosaveAppearanceSettings (6309) + _applySavedSettingsUi (7837) read
auto_scroll_follow from a settings/body object — use !==false (default True) for
consistency with boot.js + the checkbox render, so a future partial-body refactor
can't silently default the True setting OFF. The .checked reads (6223/8170) keep !!
(a real bool).
2026-06-13 04:27:01 +00:00
nesquena-hermes 9f6ed5a61b test(#4006): re-anchor scroll tests to the explicit-settle signature + new snapshot-capture condition
scrollToBottom now calls _settleMessageScrollToBottom(false, true); renderMessages
captures scrollSnapshot when (preserveScroll || (!_autoScrollFollow && _messageUserUnpinned)).
Updated the 4 change-detector assertions in test_tars_scroll_reset_regressions.py +
test_issue1690_scroll_completion.py to the new strings; behavioral intent unchanged.
2026-06-13 04:20:25 +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 36239700e6 i18n(#4006): add auto-follow setting label+desc to the remaining 11 locales (Opus note)
The keys shipped only in en+zh; added it/ja/ru/es/de/zh-Hant/pt/ko/fr/tr/pl so the
Settings → Appearance auto-follow toggle isn't English-only outside those two.
2026-06-13 04:12:11 +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 00ea7766db feat(#4006): default auto-follow ON (Codex/Claude-Code parity) + fix default-hydration mismatch + CHANGELOG v0.51.378
Per maintainer decision, auto_scroll_follow defaults TRUE (sticky-bottom: follow
new output while streaming, scroll-up unpins and is respected) — matching Codex
CLI / Claude Code. The PR shipped it default-False.

Default-mismatch bug fixed (would have shown the True default as OFF for existing
users with no saved value):
- boot.js settings path: !!s.auto_scroll_follow -> s.auto_scroll_follow!==false
- boot.js no-settings fallback: false -> true
- panels.js checkbox render: !!settings.auto_scroll_follow -> !==false

Resolved the config.py + panels.js merge conflicts (kept both the Transparent
Stream setting and auto_scroll_follow). Added test_issue4006_auto_scroll_follow_default.py
pinning the True default across config/boot/panels + the follow-gate references.
2026-06-13 03:55:28 +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 d3c694251f test(#3920): re-anchor tars scroll regression tests to the ResizeObserver settle
The 2 failing assertions pinned the removed implementation (const passes=[0,16,80,180]
setTimeout fan-out + _settleMessageScrollToBottom(true) in scrollToBottom). Updated to
assert the new behavior contract: ResizeObserver on #msgInner + 2s static fallback +
force=false so the observer runs. Behavioral intent (settle survives late markdown
growth; sync write before settle scheduling) preserved.
2026-06-13 03:39: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 02e201fcf1 docs(changelog): stamp #3903 Worklog-reasoning-hide as v0.51.376 (Release MO) 2026-06-13 03:19:44 +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 9f1933f81e chore(#4024): drop docs/ui-ux/review-shots/ trifecta scratch from the release diff
These 5 PNGs (722K) are the agent trifecta review-pass screenshots copied into
the worktree so the Opus gate could read them — review scratch, not durable UX
evidence. The intended evidence lives in docs/ui-ux/evidence/pr4024-*.png and is
kept. Mirrors the .review-crops/ cleanup; gitignore the dir so review scratch
can't leak into a release diff. No code or test change.
2026-06-13 02:15:01 +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 f18e8d6545 docs(changelog): stamp Transparent Stream (#3820/#4024) as v0.51.375 (Release MN) 2026-06-13 01:43:25 +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 5dad3e03e5 test(#4024): update CSS-literal assertions to the new quiet treatment + add 8 trifecta-fix regression guards
- Re-anchor test_old_event_fading + test_transparent_event_row_quiet_metadata_visual_rhythm to the new contract (left-rail output, inline-row args, underline active tab, WCAG fade floor, live-only fade).
- Add guards: live-turn-restore rehydrate (C1), echoed-thinking dedup (O-Bug1), thinking-card flat reset (V1), skin-proof reset (V3), legible failed status (V2), interrupted settled status (O-Edge), completion preserves expand state (O-Bug2), live-only entrance animation (V9).
2026-06-13 01:12:09 +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
nesquena-hermes e8529c84e5 Merge #4060: pass custom provider keys to context probes (#4059) 2026-06-13 00:17:16 +00:00
nesquena-hermes 89ca46eeb5 harden(#4020): prune lineage cache by collapsed-row key too (Opus SHOULD-FIX)
Opus advisor found a key-space asymmetry: _pruneLineageReportCacheToVisibleSessions
built visibleKeys from RAW rows via _sidebarLineageKeyForRow, but the render loop
keys the lineage-report cache by _sidebarLineageKeyForRow on the COLLAPSED row,
which can differ when collapse merges segments. On a malformed/edge chain the
expanded row's cache could be evicted every payload and re-fetched ~every 5s
(partial regression of the bug #4020 fixes). Fold the collapsed rows' cache keys
into the visible set too, mirroring the _resolveSessionIdFromSidebarLineage
precedent, behind a defensive try/catch.

docs(changelog): stamp #4020+#4055 as v0.51.373 (Release ML)
2026-06-13 00:03:30 +00:00
nesquena-hermes 0fdfa4b9fa Merge #4055 into stage-ml 2026-06-12 23:43:28 +00:00
nesquena-hermes 3ddf99c6f1 Merge #4020 into stage-ml 2026-06-12 23:43:28 +00:00
nesquena-hermes f083cf54d1 docs(changelog): stamp Phase-2 batch as v0.51.372 (Release MK) 2026-06-12 23:37:34 +00:00
nesquena-hermes 4874126b6d Merge #4066 into stage-mk 2026-06-12 23:18:00 +00:00
nesquena-hermes 0eee1b85ec Merge #4010 into stage-mk 2026-06-12 23:18:00 +00:00
nesquena-hermes f4ce459f79 Merge #4017 into stage-mk 2026-06-12 23:18:00 +00:00
nesquena-hermes ce013de195 Merge master (docs #4061) into stage-mj 2026-06-12 20:40:35 +00:00
nesquena-hermes 31936c3026 docs(changelog): stamp Phase-1 low-risk batch as v0.51.371 (Release MJ) 2026-06-12 20:29:28 +00:00
nesquena-hermes 6ec5527386 harden(#4057): pass local skills dir to _skill_category_from_path explicitly (Opus SHOULD-FIX)
_active_skill_search_dirs filters to existing dirs, so on a host with no local
skills dir but configured external dirs the local root is dropped from the list
and the position-based skills_dirs[0]==local assumption misclassified the first
external root as local (its flat skills silently lost their category label).
Pass the local dir explicitly (backward-compatible optional param defaulting to
the old skills_dirs[0] behavior) + regression test for the absent-local-dir case.
2026-06-12 20:28:46 +00:00
nesquena-hermes 2fea2d588b Merge #4058 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes 4ad3299449 Merge #4057 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes 1e5a741f50 Merge #4054 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes 10481d4f34 Merge #4051 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes 13fdb0755f Merge #4049 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes ffa9f533ef Merge #4048 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes 1052f4ab87 Merge #4047 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes 99ee11a733 Merge #4046 into stage-mj 2026-06-12 20:14:42 +00:00
nesquena-hermes fb3d689619 Merge #4050 into stage-mj 2026-06-12 20:14:41 +00:00
nesquena-hermes 82fcf665eb harden(#4052): tolerate providers.*.models list-of-dicts keyed by model/name (Opus SHOULD-FIX)
The richer static-catalog builder's group-building loop used a strict item["id"]
extraction that would KeyError (caught → degrade to the minimal one-model catalog)
for legal config shapes where providers.<id>.models is a list of dicts keyed by
"model"/"name" rather than "id". Mirror the tolerant id-or-model-or-name resolution
the detection loop already uses, skip entries with nothing usable, and add a
regression test. No behavior change for the common list-of-strings / list-of-id-dicts
shapes.

docs(changelog): stamp #4052 model-picker budget fallback as v0.51.370 (Release MI)
2026-06-12 20:05:12 +00:00
nesquena-hermes 1c82dab798 Merge #4052: real static catalog when /api/models times out (#3928) 2026-06-12 19:50:52 +00:00
nesquena-hermes 6204dbe9ea docs(changelog): stamp #4022 runtime base_url fix as v0.51.369 (Release MH) 2026-06-12 08:16:00 +00:00
nesquena-hermes c35c1c6e70 test(#4022): update sprint42 runtime-route assertion for target_model threading
#4022 now calls resolve_runtime_provider(requested=..., target_model=...) so
per-model base_url normalization applies; the sprint42 test pinned the old
single-arg signature. Updated the assertion to expect target_model (pre-existing
test, not a behavior regression — confirmed it passes on master only because the
call signature changed here).
2026-06-12 07:57:26 +00:00
nesquena-hermes 005b2ca460 fix(#4022): preserve different-endpoint config base_url override (Codex CORE)
Codex caught a regression: the contributor's _runtime_preferred_base_url preferred
the runtime base_url for ALL non-custom providers, which would clobber an explicit
providers.<id>.base_url override pointing at a different host/port (LM Studio at a
LAN IP, an OpenRouter mirror). Now only prefer the runtime URL when it's the SAME
scheme+host+port as the configured one (the #3895 /v1-dedup case is path-only on
the same host); a genuinely different configured endpoint wins. Added
_same_base_url_endpoint() + 2 regression tests (different-endpoint preserved,
same-endpoint normalization).
2026-06-12 07:54:48 +00:00