Commit Graph
4391 Commits
Author SHA1 Message Date
jared 200ef4993c Merge pull request 'fix(a11y): the keyboard shortcuts dialog lists every shortcut (#334)' (#401) from fix/shortcuts-dialog into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 05:21:22 -04:00
jared 0ebf7f0806 Merge pull request 'fix(forward): warn when forwarding out of an encrypted room into one that is not (#330)' (#400) from fix/forward-encryption-warning into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 05:05:17 -04:00
jared 397eb7da81 Merge pull request 'fix(calls): no "the shared window was closed" toast when an admin turns sharing off (#297)' (#398) from fix/screenshare-double-toast into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 04:23:18 -04:00
jared a20e68596a Merge pull request 'fix(notifications): notification replies re-check encryption at send time and use the right account (#299)' (#397) from fix/sw-reply-checks into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 03:55:01 -04:00
jared df9591c44c Merge pull request 'fix(calls): the call PiP no longer opens on top of the composer (#323)' (#396) from fix/pip-default-position into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 03:24:13 -04:00
jared ed24d7f78e Merge pull request 'fix(notifications): in-app toasts no longer need browser notification permission (#324)' (#395) from fix/inapp-toast-permission into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 03:06:12 -04:00
Lotus CIandClaude Opus 5.5 37b3ae1ad7 fix(desktop): without a tray, the first-close dialog defaults to Quit (cinny-desktop #37)
CI / Build & Quality Checks (pull_request) Successful in 3m13s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 13s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m14s
On desktops with no tray host (stock GNOME), "Keep running in the tray"
hid the window with no icon to bring it back. Ask the desktop app
(has_tray_host); without a tray, say so, focus "Quit when I close the
window", and offer "Keep running in the background" as the secondary
choice. Older desktop builds keep the current dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 02:41:04 -04:00
jared 667925733e Merge pull request 'fix(notifications): timed mutes are lifted by any Lotus device, not just the one that set them (#333)' (#393) from fix/mute-timers-account-data into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 02:22:21 -04:00
jared ea5a0d4906 Merge pull request 'fix(moderation): policy viewer lists a stable rule and its legacy twin once (#321)' (#392) from fix/policy-dedupe into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 02:05:12 -04:00
jared a6e90c7bc4 Merge pull request 'fix(security): a dismissed status announcement no longer hides the security nudge (#307)' (#391) from fix/nudge-dismissed-strip into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 01:49:48 -04:00
jared c87fa4f6d5 Merge pull request 'fix(status): banner Details strips Markdown syntax, not every #, _, >, * (#308)' (#390) from fix/kuma-plain-text into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 01:33:17 -04:00
Lotus CIandClaude Opus 5.5 f8efbfe38b fix(calls): explain when the soundboard is not allowed in a voice channel (EC #47)
CI / Build & Quality Checks (pull_request) Successful in 2m47s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 11s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m47s
The fork now refuses a clip it cannot publish (audio-only rooms grant
only the microphone source) with reason "not_permitted". Say "The
soundboard isn't available in this voice channel" instead of the
generic error. Older forks are unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 01:22:50 -04:00
jared 5ecf4132f5 Merge pull request 'fix(calls): DM-aware rejoin toast, and no rejoining a DM call that ended (#302)' (#389) from fix/rejoin-dm into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 01:16:23 -04:00
Lotus CIandClaude Opus 5.5 c4c54dad7a feat(calls): minimise the call PiP to a small bar; phones start minimised (#323)
CI / Build & Quality Checks (pull_request) Successful in 2m51s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 12s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m22s
The PiP had no way to get out of the way short of dragging it. Add a
minimise / expand button: minimised it is a 220×40 bar with the call
room's name (still draggable, tap to return to the call). The choice is
remembered; with no saved choice, phones start minimised.

Fixes #323

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 01:08:36 -04:00
jared d412f9c56c Merge pull request 'fix(search): an edited message shows once, with its latest text (#288)' (#388) from fix/search-edit-dupes into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 00:59:46 -04:00
Lotus CIandClaude Opus 5.5 fe70616412 fix(calls): the call bar shows "Call disconnected" and reconnects when sync is back (#318)
After a homeserver stall Element Call showed "Connection lost" while the
call bar still looked joined. Handle the fork's io.lotus.call_error:
show "Call disconnected" with a Reconnect button (io.lotus.reconnect),
and reconnect automatically once sync is back.

Fixes #318

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:55:29 -04:00
Lotus CIandClaude Opus 5.5 acc17f422b fix(calls): say when ML noise suppression fails or falls back; drop the spoofable listener (#260)
CI / Build & Quality Checks (pull_request) Successful in 2m46s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 7s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m56s
The fork reports what actually runs as io.lotus.denoise_state, but the
host never listened ("unsupported action"), so a failed ML denoiser
silently published the raw mic. Handle it: toast when ML did not start
or fell back to another model. Remove LotusDenoiseFeature, which waited
for a postMessage nothing sends any more and accepted it from any frame.

Refs #260

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:48:46 -04:00
jared ad5631819d Merge pull request 'fix(sidebar): the room filter hides empty sections and says when nothing matches (#289)' (#387) from fix/room-filter-empty into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 00:45:28 -04:00
Lotus CIandClaude Opus 5.5 5feb2184be docs: document the 55 features missing from LOTUS_FEATURES.md; refresh the Synapse re-check (#294)
CI / Build & Quality Checks (pull_request) Successful in 3m0s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 8s
CI / Playwright smoke (e2e) (pull_request) Successful in 16m11s
LOTUS_FEATURES.md had not been updated since September and was missing
55 shipped features. Add a "June–October 2026 Additions" section,
grouped by area, one line per feature with its commit and issue.
LOTUS_REFERENCE.md's blocked-features note is re-checked against
production Synapse 1.162.0.

Fixes #294

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:29:54 -04:00
Lotus CIandClaude Opus 5.5 86b77ac9f3 fix(settings): desktop-only settings get their own Desktop section (#290)
CI / Build & Quality Checks (pull_request) Successful in 2m50s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 19s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m11s
Custom Window Chrome, Launch on login / When I close the window and the
keychain status sat inside Appearance, between Monochrome Mode and
Twitter Emoji. Move them to a Desktop section (above App Updates),
rendered only in the desktop app.

Fixes #290

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:28:12 -04:00
jared 83933fb5ac Merge pull request 'fix(composer): Escape closes the emoji and sticker boards (#304)' (#386) from fix/emoji-board-escape into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 00:27:07 -04:00
Lotus CIandClaude Opus 5.5 cd760ebc3c fix(dev): ML noise suppression works on npm start; no lotusTheme warning per call (#293)
CI / Build & Quality Checks (pull_request) Successful in 3m4s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 10s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m16s
The denoise worklets/wasm/models were only copied into dist/ by the
lotus-denoise closeBundle hook, so on the dev server the call frame got
the SPA fallback for them and silently used the raw mic. The asset list
is now shared (denoiseSources) between that copy and a dev-server
middleware serving the same paths. Also send lotusTheme=true with
lotusTransparent, which the fork warned about in every call.

Fixes #293

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:24:03 -04:00
Lotus CIandClaude Opus 5.5 f41de57893 fix(translate): no "use the Lotus desktop app" advice inside the desktop app (#349)
CI / Build & Quality Checks (pull_request) Successful in 3m24s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 16s
CI / Playwright smoke (e2e) (pull_request) Failing after 18m15s
Where the on-device Translator/LanguageDetector APIs are missing,
Settings said to use Chrome/Edge "or the Lotus desktop app", but the
Linux and macOS apps (WebKit) lack them too, and showed the advice to
people already in the app. Word it by platform. (The per-message
Translate action was already hidden where unsupported.)

Fixes #349

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:19:48 -04:00
Lotus CIandClaude Opus 5.5 1511cb0b97 fix(pwa): the installed app can rotate, and "New Message" opens a new DM (#292)
CI / Build & Quality Checks (pull_request) Successful in 2m55s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 8s
CI / Playwright smoke (e2e) (pull_request) Successful in 23m55s
manifest.json locked the installed app to portrait (no landscape video,
screenshare or call view on Android / tablets) and its "New Message"
shortcut pointed at /, the home page. Drop the orientation lock and
point the shortcut at ./direct/create/ (Create Chat).

Fixes #292

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:18:23 -04:00
Lotus CIandClaude Opus 5.5 3e11a6fc0b fix(translate): say why Translate did nothing (#287)
CI / Build & Quality Checks (pull_request) Successful in 3m5s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 8s
CI / Playwright smoke (e2e) (pull_request) Successful in 13m42s
When a message was already in the target language, or its language
could not be detected, Translate switched itself back off with no chip,
no "Translating…" and no error. Show a short toast instead: "This
message is already in English." or "Couldn't tell what language this
message is in, so it wasn't translated."

Fixes #287

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:17:04 -04:00
Lotus CIandClaude Opus 5.5 5ce4692a7b fix(consent): a retry that fails again reopens the terms prompt (#311)
CI / Build & Quality Checks (pull_request) Successful in 3m16s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Playwright smoke (e2e) (pull_request) Successful in 19m50s
CI / Secret scan (gitleaks) (pull_request) Successful in 16s
Closing the dialog via "I've accepted — retry" also deactivated its focus
trap, whose onDeactivate is "Later": every close set the 10 s snooze, so
a retry made before the terms were really accepted failed silently.
Retry now closes without snoozing (and clears any earlier snooze).

Fixes #311

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:11:34 -04:00
Lotus CIandClaude Opus 5.5 4486f02bc6 fix(privacy): "Remove Photo Metadata" also covers emoji/sticker packs and badges (#332)
CI / Build & Quality Checks (pull_request) Successful in 3m25s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 8s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m42s
Custom emoji and sticker images, pack avatars and power-level badge
images were uploaded with their EXIF intact (GPS location, timestamp),
although they are published to every member of the room or space. Route
those three pickers through a new useStrippedFilePicker, which applies
the same stripImageMetadata as attachments and avatars.

Fixes #332

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:09:14 -04:00
jared a7c9d15824 Merge pull request 'fix(calls): the call-failed screen gets a Try again button (#301)' (#385) from fix/call-failed-retry into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-18 00:08:25 -04:00
Lotus CIandClaude Opus 5.5 7b3d1bad8f fix(previews): no genuine preview card for a site a deceptive link only pretends to be (#286)
CI / Build & Quality Checks (pull_request) Successful in 3m6s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 9s
CI / Playwright smoke (e2e) (pull_request) Successful in 21m16s
Previews are built from the plain body, clicks follow formatted_body's
hrefs, and a sender controls both: text "https://paypal.com" linked to
evil.example showed a real PayPal card. Drop body URLs whose site is
only claimed by the visible text of a mismatched link (linkSafety).

Fixes #286

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:05:06 -04:00
Lotus CIandClaude Opus 5.5 2c11bd3b8e fix(previews): a page can no longer pose as a YouTube (etc.) player via its og:url (#326)
CI / Build & Quality Checks (pull_request) Successful in 4m30s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 15s
CI / Playwright smoke (e2e) (pull_request) Successful in 17m17s
The embed fallback used the preview's og:url whatever site was posted.
og:url is set by the page, so evil.example could render as a playable
YouTube card (attacker's video) whose links go to evil.example. Only use
an og:url on the same provider as the posted link, including the
provider's own short-link domains (youtu.be, spotify.link, redd.it, …).

Fixes #326

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 23:54:50 -04:00
Lotus CIandClaude Opus 5.5 6f7a8f64e2 fix(settings): valid HTML in setting tiles; start uploads in an effect (#291)
CI / Build & Quality Checks (pull_request) Successful in 4m24s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 11s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m43s
SettingTile rendered its description in a <p>, and many tiles pass
blocks (badges, Box, Text), so Settings had <div>/<p> inside <p> and
React warned on every page. Render it as a <div>. UploadCardRenderer
called startUpload() during render, which now updates the desktop
taskbar-progress hook mid-render; start it from an effect instead.

Refs #291

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 23:51:19 -04:00
jared e6e52cdc37 Merge pull request 'fix(share): room share and invite links open Lotus Chat, not matrix.to (#285)' (#384) from fix/share-links-lotus into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 23:50:18 -04:00
Lotus CIandClaude Opus 5.5 4969ef9b6d fix(a11y): the keyboard shortcuts dialog lists every shortcut (#334)
CI / Build & Quality Checks (pull_request) Successful in 4m3s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 24s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m52s
The ? dialog showed 7 shortcuts and left out Ctrl+K, ↑ to edit, all
composer formatting keys and the push-to-talk / deafen keys. Add them:
formatting rows are generated from the editor's INLINE_HOTKEYS /
BLOCK_HOTKEYS so they can't drift, and the call keys show the user's
own bindings.

Fixes #334

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 23:43:49 -04:00
Lotus CIandClaude Opus 5.5 be71931a81 fix(forward): warn when forwarding out of an encrypted room into one that is not (#330)
CI / Build & Quality Checks (pull_request) Successful in 3m42s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 17s
CI / Playwright smoke (e2e) (pull_request) Successful in 13m6s
Forwarding from an encrypted room into an unencrypted one posts the text
(and a re-uploaded plaintext attachment) where the server can read it,
with the original author attached, and the dialog said nothing. Show a
note above Send naming the unencrypted destination(s).

Refs #330

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 23:40:58 -04:00
jared 4ab5a8fd06 Merge pull request 'fix(polls): you can vote on a poll you just created (#284)' (#383) from fix/poll-vote-local-echo into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 23:26:31 -04:00
jared 4e30ae763e Merge pull request 'fix(schedule): load scheduled messages from the server; offer to cancel them at logout (#322)' (#382) from fix/scheduled-from-server into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 23:05:38 -04:00
jared f9265d2d90 Merge pull request 'fix(calls): one delayed-event restart in flight per id, with a timeout (#318)' (#381) from fix/delayed-restart-dedupe into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 22:37:01 -04:00
jared 82c5728a96 Merge pull request 'fix(calls): Reject sends the decline to the ring notification (#313)' (#375) from fix/decline-references-notification into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 22:13:55 -04:00
jared dd6cf156ba Merge pull request 'fix(status): show a strip when the homeserver hangs, not 110 s later (#317)' (#380) from fix/stall-watchdog into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 21:58:23 -04:00
jared e94cdfe5dc Merge pull request 'fix(timeline): media gallery / activity log no longer make the timeline drop messages (#259)' (#368) from fix/filtered-timeline-double-count into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 21:37:08 -04:00
jared bb2ace82eb Merge pull request 'fix(calls): lift CallControl's listener limit so ended calls can be freed (#316)' (#379) from fix/call-listener-limit into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 21:19:12 -04:00
Lotus CIandClaude Opus 5.5 3a74699fef fix(media): "Compress image" no longer blackens transparent images or freezes animations (#331)
CI / Build & Quality Checks (pull_request) Successful in 3m13s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 13s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m29s
Compression re-encodes through a canvas to JPEG. Only PNG was skipped,
so a transparent WebP came out on a black background, and an animated
GIF or WebP became one still frame. GIF and APNG are no longer offered;
an animated WebP (VP8X animation flag) or any image with a transparent
pixel is kept as the original.

Fixes #331

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:57:33 -04:00
Lotus CIandClaude Opus 5.5 7fc42b32d4 fix(calls): no "the shared window was closed" toast when an admin turns sharing off (#297)
CI / Build & Quality Checks (pull_request) Successful in 3m3s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 11s
CI / Playwright smoke (e2e) (pull_request) Successful in 16m14s
When a room admin turned off Allow Screen Sharing, the sharer got two
toasts: the correct "turned off by a room admin" and the fork's
"ended" notice, "the shared window was closed", which was wrong. Skip
the ended notice while the room policy forbids sharing.

Fixes #297

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:55:05 -04:00
Lotus CIandClaude Opus 5.5 005fc9e768 fix(notifications): notification replies re-check encryption at send time and use the right account (#299)
CI / Build & Quality Checks (pull_request) Successful in 2m43s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 12s
CI / Playwright smoke (e2e) (pull_request) Successful in 16m49s
The service worker posts inline notification replies in the clear (it
cannot encrypt). The Reply action was only withheld for rooms that were
encrypted when the notification was shown, so a reply typed hours later
into a room that has since turned on encryption went out unencrypted.
It also posted with the newest session the worker knew, not the
notification's account.

The worker now GETs the room's m.room.encryption state first and only
sends on a definite 404; notifications carry the user id and the worker
uses that account's session (or refuses). "Reply not sent" says why.

Fixes #299

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:52:12 -04:00
Lotus CIandClaude Opus 5.5 33cc0de97c fix(calls): the call PiP no longer opens on top of the composer (#323)
CI / Build & Quality Checks (pull_request) Successful in 3m22s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 15s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m4s
The first-use PiP position was bottom-right, 72px from the bottom: on
desktop over Send, on phones over Send, Emoji and the message box, so
the first thing you typed or tapped in the text room hit the call.
Default to top-right under the room header instead. A dragged position
is still remembered.

Refs #323

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:47:34 -04:00
Lotus CIandClaude Opus 5.5 3bf040f17a fix(notifications): in-app toasts no longer need browser notification permission (#324)
CI / Build & Quality Checks (pull_request) Successful in 3m2s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 11s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m38s
notify() shows an in-page toast while the window is focused and only
falls back to an OS notification otherwise, but both message and invite
notifications were gated on Notification.permission === granted. Anyone
who declined (or was never asked) heard the ping with nothing on screen.
Gate only the OS path on the permission.

Fixes #324

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:41:48 -04:00
jared 906a034e26 Merge pull request 'fix(calls): starting a call in a voice channel no longer @room-pings everyone (#295)' (#378) from fix/voice-room-no-room-ping into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 20:38:37 -04:00
Lotus CIandClaude Opus 5.5 c8576cbb1f fix(status): any Lotus device clears an auto-expiring status, not just the one that set it (#300)
CI / Build & Quality Checks (pull_request) Successful in 3m2s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 9s
CI / Playwright smoke (e2e) (pull_request) Successful in 25m12s
"Clear after 1 hour" lived in that device's localStorage, so a status
set on a laptop that was then closed stayed on the server until the
laptop opened Lotus again. The expiry is now also kept in account data
(io.lotus.status_expiry: { status_msg, expires_at }). Every device's
StatusExpiryMonitor clears the status when due, but only if it is still
the one that was set to expire (otherwise it just forgets the expiry).

Fixes #300

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:37:21 -04:00
Lotus CIandClaude Opus 5.5 69e05bbf8d fix(notifications): timed mutes are lifted by any Lotus device, not just the one that set them (#333)
CI / Build & Quality Checks (pull_request) Successful in 3m3s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 8s
CI / Playwright smoke (e2e) (pull_request) Successful in 16m45s
A timed mute writes a server-side push rule (muted everywhere), but the
unmute timer lived in one browser's localStorage: close that laptop and
the room stayed muted on the phone until it was reopened, and forever
after a logout there. Timers now live in account data
(io.lotus.mute_timers: { timers: { [roomId]: unmuteAt } }). Every
client schedules from it, reschedules when it changes, and the first one
online after expiry unmutes. An indefinite mute clears a pending timer.
Local timers from before are migrated once.

Fixes #333

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:33:32 -04:00
Lotus CIandClaude Opus 5.5 15f2fcc4d1 fix(moderation): policy viewer lists a stable rule and its legacy twin once (#321)
CI / Build & Quality Checks (pull_request) Successful in 3m0s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 15s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m30s
dedupePolicyEntries keyed on the raw recommendation, so m.ban and
org.matrix.mjolnir.ban for the same entity never matched and the rule
showed twice (both labelled "Ban"). Key on the normalised value; move
the pure helpers to policyEntries.ts with unit tests.

Fixes #321

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:28:34 -04:00