Commit graph

6352 commits

Author SHA1 Message Date
nesquena-hermes
4f8bd1ef38 docs(changelog): #5487 stray-pointerup session-switch guard + #5458 IPv4-first gallery 2026-07-04 03:54:11 +00:00
nesquena-hermes
fe30f1ff00 Merge PR #5458 from rumotoshino: prefer IPv4 for extension gallery downloads 2026-07-04 03:39:19 +00:00
nesquena-hermes
fcd3de7d8f Merge PR #5487 from webtecnica: prevent unintended session switch on stray pointerup (#5462) 2026-07-04 03:39:18 +00:00
nesquena-hermes
98a3b0718c
Merge pull request #5507 from nesquena/release/stage-5460
Release — replace cross-profile empty sessions on profile switch (#5460)
2026-07-03 20:37:57 -07:00
nesquena-hermes
e874fc4149 docs(changelog): #5460 replace cross-profile empty sessions on profile switch 2026-07-04 03:33:06 +00:00
nesquena-hermes
dbf3c9d3c0 Merge PR #5460 from ruizanthony: replace cross-profile empty sessions on profile switch 2026-07-04 03:05:45 +00:00
nesquena-hermes
843e7748cc
Merge pull request #5503 from nesquena/release/stage-5496
Release — refresh dictation recognition.lang after locale change (#5496)
2026-07-03 19:48:30 -07:00
nesquena-hermes
8b6ababf8c docs(changelog): #5496 refresh dictation recognition.lang after locale change (#5483) 2026-07-04 02:42:56 +00:00
nesquena-hermes
091103cf6d Merge PR #5496 from webtecnica: refresh recognition.lang before dictation start (#5483) 2026-07-04 02:41:01 +00:00
nesquena-hermes
5e0d4d1e3d
Merge pull request #5495 from nesquena/release/stage-5480
Release — stale WebUI client recovery banner (#5480)
2026-07-03 18:32:52 -07:00
root
fe4e2851f7 fix: refresh recognition.lang before dictation start
After a runtime locale change (setLocale from Settings), the cached
recognition object retains its boot-time lang, causing dictation to
run in the wrong language. Set lang immediately before .start() at
the plain dictation path in _startMicCapture, matching the pattern
already used in _ensureSpeechRecognition().

Closes #5483
2026-07-03 22:28:35 -03:00
nesquena-hermes
378548b566 docs(changelog): #5480 stale WebUI client recovery banner (#5428) 2026-07-04 01:28:02 +00:00
nesquena-hermes
568d5c4b0e gate-fix #5480: suppress 'unknown' server version (case-insensitive) to prevent false banner
Codex gate: _normalizeWebUIVersion suppressed empty/__WEBUI_VERSION__/'not detected'
but NOT 'unknown' — api/updates.py emits WEBUI_VERSION='unknown' on git-describe
failure (Docker/CI images), so a real client version would falsely fire the
stale-client banner against server='unknown'. Suppress 'unknown' (+ case-insensitive
for all sentinels). + regression test asserting unknown/UNKNOWN/Unknown don't fire.
2026-07-04 01:15:26 +00:00
nesquena-hermes
b04f0387c4 Merge PR #5480 from rodboev: surface stale WebUI client recovery (#5428) 2026-07-04 01:09:14 +00:00
nesquena-hermes
f38cf44569
Merge pull request #5492 from nesquena/release/stage-5452
Release — fit fullscreen Mermaid diagrams to the lightbox (#5452)
2026-07-03 17:21:26 -07:00
nesquena-hermes
8b1109a079 docs(changelog): #5452 fit fullscreen Mermaid to lightbox (#5413) 2026-07-04 00:17:07 +00:00
nesquena-hermes
0eb80f6197 Merge PR #5452 from rodboev: fit fullscreen Mermaid diagrams to the lightbox (#5413) 2026-07-04 00:07:04 +00:00
nesquena-hermes
7a700b96db
Merge pull request #5489 from nesquena/release/stage-5467
Release v0.51.842 — sidebar render-skip on idle polls (#5467)
2026-07-03 16:48:46 -07:00
nesquena-hermes
8d9d37c118 Merge remote-tracking branch 'origin/master' into release/stage-5467
# Conflicts:
#	CHANGELOG.md
2026-07-03 23:44:49 +00:00
nesquena-hermes
f217f76862
Merge pull request #5491 from nesquena/release/stage-5488
Release v0.51.843 — failed-send draft restore hardening (#5488)
2026-07-03 16:40:00 -07:00
nesquena-hermes
ed508ff6ef Merge remote-tracking branch 'origin/master' into release/stage-5467
# Conflicts:
#	CHANGELOG.md
2026-07-03 23:39:31 +00:00
nesquena-hermes
1e4c5ee101 docs(changelog): #5488 hardening for #5472 failed-send draft restore 2026-07-03 23:36:53 +00:00
nesquena-hermes
5c54fd598c
fix(#5472): order draft re-persist after clear + honest happy-path test (#5488)
* fix(#5472): harden failed-send draft restore — order persist after clear, honest test

Two NIT-level follow-ups from the Opus review of #5484 (both on already-shipped
v0.51.842 code; neither is a functional break):

1. Draft clear/save ordering. send() fires an unawaited _clearComposerDraft POST
   (text:'') at send time, and the failed-send restore fired a separate
   _saveComposerDraftNow POST (text:<draft>). Under HTTP/2 multiplexing those two
   same-origin writes can be reordered, leaving the SERVER draft empty after a
   reload (the in-memory composer restore was always fine). send() now captures
   the clear POST's promise and passes it to the restore helper, which chains the
   re-persist after the clear resolves (falls back to immediate persist if the
   promise is absent/rejects).

2. Honest happy-path test. test_send_still_clears_composer_on_the_happy_path
   asserted a bare $('msg').value='' string that matches ~13 sites, so it would
   pass even if the MAIN-path clear were removed. It now anchors to the unique
   main-path _clearComposerDraft line and window-checks the composer wipe
   immediately precedes it.

Tests: +2 (promise-ordering behavioral via node-vm microtask ordering; absent-promise
fallback), signature/call assertions updated. 14 in the #5472 file, 93 across the
related composer/send/draft/upload surface — all green.

* fix(#5472): make deferred draft persist stale-aware (Codex #5488 catch)

The promise-ordering fix introduced a regression: the deferred _persist saved the
CAPTURED snapshot and its _saveComposerDraftNow clearTimeout cancelled any newer
debounced save. So if the user edited the restored composer before the clear POST
settled, the delayed persist overwrote their edit with the stale original text
(lost on reload).

Restructure the helper so the deferred persist is stale-aware at FIRE time:
- If the failed session is still visible, re-read the LIVE composer (.value
  + current S.pendingFiles) instead of the captured snapshot — a post-restore edit
  is captured, not clobbered.
- If we restored the visible session but the user has since switched away, SKIP the
  stale write entirely (the session-switch save path already saved that session).
- Background failure (sid never visible): persist the captured snapshot, since
  there's no live composer to read — it's the only copy.

The visible-composer restore + session guard are unchanged in behavior (moved above
the persist). Helper now returns whether it restored the VISIBLE composer.

Tests: +3 regression cases (post-restore edit captured; switch-away skip; background
snapshot persist), signature/guard assertions updated. 17 in the #5472 file, 87
across the related surface — all green.
2026-07-03 16:36:21 -07:00
nesquena-hermes
329e911327 fix: prevent unintended session switch on stray pointerup (#5462)
Clean rebase of webtecnica's #5487 (rebase-first).

Co-authored-by: webtecnica <webtecnica@users.noreply.github.com>
2026-07-03 23:34:37 +00:00
nesquena-hermes
f66944d006 docs(changelog): #5467 sidebar render-skip on idle polls (#5455) 2026-07-03 23:23:20 +00:00
nesquena-hermes
a53c183dd5 fix(test): widen _applySessionListPayload slice to reach _mustForceRender assertion 2026-07-03 23:05:03 +00:00
nesquena-hermes
4e8363035e
Merge pull request #5486 from nesquena/release/stage-5472
Release v0.51.842 — preserve composer draft on failed send (#5472)
2026-07-03 16:04:48 -07:00
nesquena-hermes
b438976507 gate-fix #5467 r2: force render when recovering from skeleton/error-banner DOM
Codex re-gate found 2 more false-skips (DOM state OUTSIDE the signature path):
- CORE: profile-switch skeleton stays visible if the new payload signature
  matches the last one (empty/same-shaped profile) — skip fires over the skeleton.
- SILENT: stale 'Could not load conversations' banner persists when a transient
  fetch failure heals with identical rows.
Fix: capture _hadSessionListSkeleton + _hadSessionListLoadError BEFORE clearing
them, and disallow the identical-signature skip when either was set. + regression
test. (messages.js:1462 finding is a base-comparison artifact for #5472/#5479/#5484,
not in #5467's diff.)
2026-07-03 23:04:41 +00:00
nesquena-hermes
88bc4feffe docs(changelog): #5472 preserve composer draft on failed send 2026-07-03 22:58:49 +00:00
nesquena-hermes
3999418b0e gate-fix #5467: serialize full rows in render-skip signature (close false-skips)
Codex gate found the render-skip signature omitted fields the sidebar renders:
- CORE: pending/running (active_stream_id/has_pending_user_message/pending_started_at)
- SILENT: attention dots
- SILENT: source/read-only/worktree/lineage/child/model/profile + _sidebarReferenceSessions
Any omitted field = a false-skip = stale sidebar.

Root-cause fix (most reliable): serialize the FULL applied row objects +
_sidebarReferenceSessions instead of a hand-picked allowlist — inherently
complete, can't rot when a new rendered field is added. Rewrote the
'ignores non-display fields' test into positive full-serialization + no-strip
regression assertions.
2026-07-03 22:58:21 +00:00
nesquena-hermes
603375d71c
fix(#5472): preserve composer draft when a send fails (#5484)
* fix(#5472): preserve composer draft when a send fails

When a provider/background error aborts a send, send() has already cleared
the composer and the persisted draft before /api/chat/start durably accepts
the turn. On a start-time throw the turn is never persisted, so the user's
typed message is lost and must be retyped.

Add _restoreComposerDraftAfterFailedSend(text, sid): restores the typed text
into the composer, keeps staged files in S.pendingFiles, and re-persists the
draft (via _saveComposerDraftNow) so it also survives a reload. Guarded to
no-op when there's nothing to restore and to never clobber a new message the
user began typing during the async send window. Wired into the /api/chat/start
throw handler's general-error branch. Mirrors the existing _trySteer /
_stashClarifyDraft draft-restore idioms.

Tests: tests/test_issue5472_preserve_draft_on_failed_send.py — 3 static wiring
assertions + 4 node-vm behavioral tests of the helper's branching logic.

* fix(#5472): address gate findings — original-payload snapshot, re-stage files, session-guard

Codex + Opus gate on the first commit converged on three real edges:

1. /moa and bundle sends rewrite `text` before /api/chat/start, so restoring
   `text` replayed the transformed payload, not the user's typed command.
   Fix: capture an immutable _failedSendDraftText snapshot right after the
   post-flush trim, before any slash rewrite, and restore that.

2. uploadPendingFiles() clears S.pendingFiles=[] before the start call, so the
   original 'keep staged files' assumption was false — a resend silently
   dropped attachments. Fix: snapshot S.pendingFiles before the upload drain
   (_failedSendFilesSnapshot) and re-stage from it (+ renderTray()) on failure.

3. A start failure after a session switch could write the failed old session's
   draft into the currently-visible composer. Fix: the helper now only mutates
   the visible composer/tray when sid === the visible session; the sid-keyed
   _saveComposerDraftNow persist stays unconditional so the draft survives a
   switch-back/reload.

Helper signature is now (draftText, filesSnapshot, sid). Tests expanded to 11
(5 static + 6 node-vm behavioral) covering all three edges: original-vs-mutated
payload, re-stage drained attachments, and cross-session no-pollution.

* test(#5472): bound send() body slice to LIVE_STREAMS instead of fixed char window

The #5472 snapshot-capture lines added ~400 chars near the top of send(), which
pushed 'cancelStream' (in the busy-interrupt branch) past the arbitrary
[send_idx:send_idx+5000] window that test_1062's structural assertions used —
a real CI failure (shard 1, all 3 Pythons) caused by a brittle test, not by the
fix logic. Bound both send()-body slices in test_1062 to the actual function
extent (up to the 'const LIVE_STREAMS=' decl that immediately follows send()) so
future additions near the top of send() don't false-fail these assertions.

---------

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-07-03 15:57:33 -07:00
nesquena-hermes
10e5e941d3 Merge PR #5467 from ai-ag2026: skip full session-list rebuild when payload unchanged (#5455) 2026-07-03 22:47:40 +00:00
nesquena-hermes
8f86ac73cc
Merge pull request #5485 from nesquena/release/stage-5469
Release v0.51.841 — desktop scroll jump-back fix (#5469)
2026-07-03 15:45:43 -07:00
nesquena-hermes
8db6ec1536 Merge remote-tracking branch 'origin/master' into release/stage-5469 2026-07-03 22:32:54 +00:00
nesquena-hermes
f18b384a2f docs(changelog): #5469 desktop scroll-anchor recover via sessionIdx 2026-07-03 22:32:53 +00:00
nesquena-hermes
7fa8b967ff
Merge pull request #5482 from nesquena/release/stage-5438b
Release v0.51.840 — preset cron schedule builder (#5438)
2026-07-03 15:31:12 -07:00
nesquena-hermes
3053b6522b docs(changelog): #5438 preset cron schedule builder (#5427) 2026-07-03 22:25:50 +00:00
nesquena-hermes
e81711d3a9 Merge PR #5469 from allenliang2022: recover viewport anchor via sessionIdx (desktop scroll jump-back) 2026-07-03 22:18:17 +00:00
nesquena-hermes
5cac66b4e5 Merge PR #5438 from rodboev: add preset cron schedule builder (#5427) 2026-07-03 22:16:37 +00:00
nesquena-hermes
0654e958ef
Merge pull request #5481 from nesquena/release/stage-5466
Release v0.51.839 — incremental live streaming render, O(n²)→O(n) (#5466)
2026-07-03 15:07:53 -07:00
nesquena-hermes
8269de961e fix(test): stub _cancelThrottledSnapshotTimer + _clearAnchorProseIncrementalNode in #5224 node harness
The #5466 fix added these two cleanup calls to _restoreSettledSession; the
test_issue5224 node harness extracts+runs that function with every helper
stubbed on globalThis, but hadn't stubbed the two new ones — so the calls threw,
the function's catch returned 'error' instead of 'restored', failing 8 CI shards.
Add the stubs. (Local full-suite missed it on first run; CI sharding surfaced it.)
2026-07-03 22:04:54 +00:00
nesquena-hermes
f3bf04c69a docs(changelog): #5466 incremental live streaming render (O(n^2)->O(n)) (#5455) 2026-07-03 21:44:10 +00:00
Rod Boev
f32938021c fix(#5428): surface stale WebUI client recovery 2026-07-03 17:43:46 -04:00
nesquena-hermes
eaf7d1e9ab gate-fix #5466: stamp anchor attrs on incremental node + teardown on all terminal paths
Codex gate findings (2 SILENT, both fixed):
- ui.js: incremental prose node now flows through the shared row-decoration
  block (data-anchor-scene-row/-row-id/-row-role/-source-event-type) instead of
  returning early, so live incremental rows keep the identity attrs the scene
  reconciler matches on.
- messages.js: _cancelThrottledSnapshotTimer() + _clearAnchorProseIncrementalNode()
  now run on apperror, cancel, _handleStreamError, and _restoreSettledSession
  terminal paths (previously only fallback/done/stream_end) — closes the
  snapshot-timer/anchor-cache/window-global teardown gap.
- test: extend test_messages_js_stream_perf_cleanup_lifecycle to pin teardown on
  all four additional terminal paths.

CORE equivalence (Codex flagged smd != renderMd): reconciled — Opus's 1498-frame
harness against real smd.min.js proves incremental-smd == whole-smd byte-identical;
live-smd-vs-renderMd difference is the already-shipped fidelity model (main live
body streams smd, settles renderMd), and the incremental path is gated on !settled
so settled DOM still comes from renderMd. Not a regression.
2026-07-03 21:24:08 +00:00
nesquena-hermes
819f1a1e7b Merge PR #5466 from ai-ag2026: reduce O(n^2) streaming render to O(n) (#5455) 2026-07-03 21:04:16 +00:00
nesquena-hermes
5e5b44e733 fix(webui): replace cross-profile empty sessions on profile switch + open all-profile rows under owning profile
Clean rebase of ruizanthony's #5460 (rebase-first).

Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-07-03 20:49:51 +00:00
nesquena-hermes
b9813af66c
Merge pull request #5476 from nesquena/release/stage-p1c
Release v0.51.838 — sidebar read-only projection (#5464) + pause hidden-tab polling (#5465)
2026-07-03 13:48:00 -07:00
nesquena-hermes
8fe2d63ec0 Merge remote-tracking branch 'origin/master' into release/stage-p1c
# Conflicts:
#	CHANGELOG.md
2026-07-03 20:44:31 +00:00
nesquena-hermes
bc0a3b299a docs(changelog): note hidden-tab attention-chime timing delta (Opus advisor) 2026-07-03 20:43:42 +00:00
nesquena-hermes
2fd2d0951f docs(changelog): Batch C — #5464 read-only session-listing projection + #5465 pause hidden-tab polling (#5455) 2026-07-03 20:32:58 +00:00