Regressions I introduced, now fixed:
#8d Mic/Camera OFF went DIM — my new `.meet-ic.off` rule overrode the original RED.
Scoped the lite style to the speaker button only; mic/cam OFF are red again.
#7 Guest "left the meeting" was unstyled (dark text on blue, no card): the card CSS was
scoped to .guest-prejoin only. Shared with .guest-left. Rejoin no longer dead-ends —
if the room is gone we say "This meeting has ended" and hide the button.
Reported:
#8d Speaker button no longer shows on desktop (devices already live under the mic ▾).
#8c/#8e Mobile speaker button now CYCLES Speaker → Earpiece → Bluetooth (icon follows the
route); dropped the redundant "Audio devices" entry from the ⋮ menu.
#8a iOS gap under the bottom rail: the page rubber-band-bounced, exposing background beneath
the fixed bar. overscroll-behavior:none + fixed body pins it.
#8b Pull-to-refresh now fires on iOS too (overscroll-behavior:contain on the lists so Safari's
rubber band stops swallowing the gesture; scrollTop>2 tolerance for momentum).
#5 A meeting link no longer opens a whole new window: same-origin urls navigate the main
window in the shell, and a link clicked in chat joins the meeting IN PLACE.
New observations:
1. The viewer's mic now starts MUTED on a screen session (and can actually be un/muted).
2. iOS lightbox close/download buttons moved below the Dynamic Island (safe-area insets).
3. Meeting chat: recipient picker moved to the BOTTOM next to the input; a private message
auto-targets your reply back to that person; private vs everyone are visibly different
(brand amber vs blue/neutral) and the compose area tints in private mode.
4. Meeting bar + screen-session bars are DRAGGABLE (position remembered) so they stop
covering the shared screen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Guest pre-join redesigned: brand backdrop, live camera preview, mic/cam toggles
applied on entry, initials avatar, name required, "host may admit you" note.
2. Post-admit bug: the guest stayed on "Waiting for the host…" forever — the lobby
screen had replaced the call UI and meeting-joined never re-rendered it. Now it
rebuilds the call on admission (_inLobby).
3. Audio devices: dropped the standalone headphones button. The MIC now has a ▾ caret
opening one Teams-style menu with Speaker + Microphone sections (radio-selected);
speaker uses setSinkId/LiveKit switchActiveDevice, mic switches the live input.
Mobile gets a speakerphone toggle that prefers a connected BT/headset when off.
4. Remote-control keyboard:
- Injector now maps the PHYSICAL key (KeyboardEvent.code) instead of the character,
so Shift+1 types "!" etc. Character mapping was why typing "performed differently".
- Keys reach the sharer ONLY while control is ENGAGED (window focused AND you clicked
their screen). Minimised/unfocused/chat typing stays local. Esc or clicking away
releases; modifiers are released on disengage so nothing sticks.
- Explicit control icons: viewer gets a Control ON/OFF button (green when engaged) +
an on-screen hint; the SHARER gets a control icon beside mic/chat to allow/stop
access at a glance, synced with the consent dialog and banner.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
General #1/#2 (closed-app notifications): the desktop app now CLOSES TO TRAY instead
of quitting, keeping its chat WebSocket alive so calls/messages still notify. Tray
icon + menu (Open / Quit), single-instance lock, first-close hint.
Guest #4 (lobby/admit): meetings can require the host to admit guests joining by link.
Setting on the schedule form ("Guests must be admitted by the host", default on) +
ad-hoc default. Guests wait on a "waiting to be let in" screen; the host gets an
Admit/Deny prompt; auto-cleanup on leave. Logged-in members always join directly.
Guest #5 (speaker): headphones/speaker output picker in the meeting (setSinkId),
remembered and applied to every tile.
Guest #3 (link expiry): guest link/token dies ~2h after a scheduled meeting's end
(HTTP 410) with a clear message; live-room links expire when the room empties.
RC #4 (mobile): touch→mouse mapping so a phone/tablet viewer can control (tap=click,
drag=move). Uses the same letterbox-correct coordinate mapping.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes the core "viewer can't control the sharer even on desktop" gap. Three root
causes addressed:
- share.html DISCARDED every input-channel message (onmessage=()=>{}). It now
parses the viewer's mouse/keyboard events and forwards them to the desktop shell.
- The main desktop app had NO OS injector (it lived only in the separate agent).
Ported the nut-js injector (agent/input/inject.js) into desktop/input, wired an
inject IPC + injectInput bridge, HARD-gated behind a consent flag (rcArmed).
- /share runs in an iframe (no direct bridge access) → it postMessages input to
the top frame (home.html), which relays to the native bridge.
Consent + safety: the sharer sees an Allow/Deny prompt the first time the agent
interacts; while active a persistent "your screen is being controlled — Stop"
banner; instant revoke; auto-release on session end/teardown. Browser sharers stay
view-only (no OS injection possible). nut-js is an optionalDependency (N-API, ABI-
stable across Electron) — degrades to no-op if the native module is unavailable.
Windows-first; maps to the primary display.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Group message toast had no icon: the generated group icon is a data: URL, but
the 0.1.11 handler only used ALREADY-cached icons and skipped it. data: URLs
are synchronous — use them immediately, so every group toast shows an icon.
2. Spell suggestions on a LEFT click: clicking a red-squiggled word in the message
box now pops the native suggestions menu (renderer asks the shell to synthesize
a right-click at that point → real dictionary suggestions). No right-click.
3. Scroll felt "stuck" because an incoming message yanked you to the bottom even
when you'd scrolled up to read history (worse now that bg messages arrive live).
appendBubble now keeps your position unless you were at the bottom / it's your
own message, and surfaces the "jump to latest" control instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Message-info popup: ONE scroll region for the whole list with sticky
Seen / Not-seen headers (was a separate scrollbar per section), realigned.
2. Group message notifications now title = GROUP name, body = "Sender: text".
3. Unread taskbar badge: solid red rounded-square (Teams-style) + white outline
instead of the gradient disc.
4. Pasting Excel/Sheets cells no longer uploads a screenshot — when the clipboard
carries real text, the text is pasted; image-only clipboards still upload.
5. Spell check in the message box (red squiggles) with a right-click menu of
corrections + add-to-dictionary; spellcheck enabled on the textarea.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Notifications/messages lagged when the desktop window was backgrounded —
Electron throttles hidden renderers by default, stalling the chat WS's
onmessage + timers. Set backgroundThrottling:false → real-time in the tray.
(Transport is WebSocket; no Firebase needed.)
2. Joining a call via the header Join button left the Join/Decline invite popup
on screen — enterMeeting now dismisses the invite (and stops the ring).
3. Seen-by is now "Message info": real contact DPs, a "Not seen yet" list for
groups, and dark lettering (white-on-pastel initials were invisible).
4. App-icon unread badge: red→pink gradient pill with a white ring + shadow,
drawn at 2x, instead of a flat red disc.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause of the persistent "notification opens a dead page / no Join" bug:
openFromNotif gated the in-place open on `window.ME`, but ME is declared with
`let` — which never creates a global property — so window.ME was ALWAYS
undefined and every click hit the full-page-reload fallback. Use bare `ME`.
Also:
- Notifications fire instantly: never block on the DP download. Use the photo
only if already cached; warm the cache in the background + pre-warm all
contact DPs on chat load (precache-avatars IPC). Removes the ~2.5s lag.
- Wire call Join/Decline handlers BEFORE firing the OS notification so Join is
live the instant the invite popup appears (was dead until the toast settled).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Custom branded screen/window picker (picker.html) — useSystemPicker was
silently no-op on Win11 and auto-shared the primary display with no choice.
- Use checkForUpdates (not ...AndNotify): drops electron-updater's own native
"Update ready" toast that duplicated our in-app banner (two restart prompts).
- Call notification DP: wait up to 2.5s for the caller photo on persistent
(call) toasts instead of 600ms so the DP actually shows.
- Re-surface Join/Decline invite when opening a chat with an active incoming
call, so a call-notification click always lands on a joinable call.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- #2: 'Seen by' opens an on-screen popup listing readers (was a flash toast).
- #5: the DM contact-info view now shows the DP; clicking it previews full-size.
- Desktop notifications: cache DPs per-sender (fast AND with photo after the first);
removed timeoutType:'never' which added an unwanted 'Close' button.
- Update flow: dropped the unbranded native restart dialog — the branded web banner
handles Restart. Banner text clearer ('Downloading update…'), plus an update
indicator that cascades profile 'i' badge → Settings → version line, with the
Settings button becoming 'Restart now' when the update is downloaded. desktop 0.1.7.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Desktop notifications were slow (~15s), vanished in ~1s, and clicks did nothing:
* don't block the toast on the avatar download (race a 600ms cap) → shows instantly
* keep a strong reference to each Notification (Electron GC'd them → premature close
+ dead click)
* call invites use timeoutType:'never' + a 45s window so they stay until clicked/ended;
web marks call notifications persistent.
- #9: enable the OS screen/window PICKER (useSystemPicker) so users choose what to share
(a single window avoids the whole-screen mirror); falls back to primary display.
- desktop 0.1.5 -> 0.1.6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Settings now shows 'Biz Connect for Desktop · Version x.y.z' with a Check for
updates button (desktop only, feature-detected).
- preload exposes checkForUpdates(); main.js adds the check-updates IPC (returns
available/current/dev/error) and, when a build finishes downloading, shows a
Restart now / Later dialog instead of only the silent on-next-launch install.
- desktop version bumped 0.1.4 -> 0.1.5.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Message actions (reply/react/edit/delete) consolidated into ONE hover pill anchored to the
bubble's top-right, overlapping it so on short messages the icons no longer float off into
empty space and vanish before you can click.
- Desktop toast + mobile(FCM)/web-background push now show the sender's real DP:
* renderer passes the DP URL through; desktop shell downloads it for the toast icon
(canvas-drawing an external DP tainted it → initials). Desktop bumped to 0.1.4.
* DM push payload carries icon=sender avatar; sw.js already uses it (web background),
sendFcm sets notification.image (Android).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Live presence (fixes stale in-call/status until refresh — impossible in apps):
- server broadcasts a user's status over the chat socket on connect/disconnect, call
join/leave, and status change (chat.js broadcastPresence; signaling + routes hooks).
- client onPresence() updates the contact dot + open-chat header live.
Chat delivery ticks (#6): chat-list row now mirrors the thread (delivered→double grey,
read→blue) via a new 'with' field on the delivered relay + onChatRead/onChatDelivered.
Call fixes: no bogus 'host handed over' when a 1:1 call ends (leaveMeeting forced);
branded call-connecting + chat-thread loaders; header subtitle tracks live call state.
Notifications: web notify + sw.js use sender/group DP + brand icon (not old wordmark);
desktop shell drops Web Push so only the single native toast fires (#5).
Brand: master icon/splash/loaders wired everywhere (PWA/favicon/apple-touch/.ico),
branded login (blue + gold CTA), branded toasts (BZToast) on all pages, Electron splash.
Desktop: dev auto-targets localhost (packaged→prod); version 0.1.3 with new multi-size
icon; dropped unused node-notifier; removed home-mockup.html.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- node-notifier's WindowsToaster forwards raw opts to SnoreToast, so inject -tb (reply box)
+ -p (image). Reuses its named-pipe + result parsing (exit 5 = TextEntered). No pwsh needed.
Logs the raw toast result to userData/toast-debug.log to confirm the reply field on real HW.
- home.html: notifAvatarDataUrl draws the DM sender's pic / group's DP (else colored initials)
to a round PNG and passes it as the toast image. Reply -> sendReplyTo; click -> open chat.
- dropped powertoast (ESM + needs pwsh 7, absent here). build batch22.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reply to a chat straight from the OS notification, no app switch:
- node-notifier (bundles SnoreToast) renders a native Windows toast with a reply box —
Electron's own Notification can't do Windows inline reply.
- main.js reply-notification handler resolves {text}|{open}|null; preload exposes replyNotify.
- home.html notify() routes chat toasts through it on desktop: a typed reply -> sendReplyTo()
POSTs to /api/messages without opening the app; a click opens the chat. Web/PWA path unchanged.
- Works only in the installed app (needs the installer's AppUserModelID). desktop 0.1.2, build batch21.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- home.html: login is now a real <form> with a submit button, so Enter (or click) both
submit natively — replaces the ad-hoc keydown handler. (build batch19; header stays removed)
- desktop/main.js: app.setAppUserModelId('com.bizgaze.connect.desktop') so Windows resolves
the installed shortcut and toasts read "Biz Connect" instead of "electron.app.BizConnect".
- desktop version → 0.1.1; installer rebuilt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- package.json build config: NSIS installer, app icon, generic publish provider →
https://remote.bizgaze.com/downloads/ (self-hosted update feed).
- main.js: electron-updater checks the feed on launch + every 6h, downloads in the
background, installs on restart. Active only in packaged builds.
- build/icon.ico app icon; PACKAGING.md documents build/release/signing.
- Key design: web/UI changes reach installed apps instantly (they load the live server);
only native shell changes need an auto-updated build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>