- Remove trailing comma in SUPPORTED_LOCALES that caused Locale type to
include undefined, fixing all downstream type errors
- Remove unused webcamSizePreset from useMemo dependency array
- Use parsed.toString() instead of raw url in shell.openExternal per
Electron security best practice
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Address two issues raised during review:
P1 – When a recording is cancelled or restarted, setRecordingState(false)
enqueues its cursor batch but store-recorded-session is never called,
leaving a stale batch that contaminates the next recording's telemetry.
Add discardLatestPending() to the buffer and a discard-cursor-telemetry
IPC handler; the renderer now calls it on the discard path.
P2 – takeNextBatch() dequeued the batch before fs.writeFile, so a write
failure would permanently lose the telemetry. Wrap the write in
try/catch and re-insert the batch via prependBatch() on failure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, the main process kept two module-scope arrays —
activeCursorSamples and pendingCursorSamples — and set-recording-state
on a new recording wiped BOTH. When a user stopped recording and
immediately started a new one before store-recorded-session fired,
the previous recording's pending samples were discarded or later
overwritten with the new session's data, producing empty or mismatched
.cursor.json files.
Replace the two arrays with a small FIFO buffer
(createCursorTelemetryBuffer) that:
- Keeps pending batches per completed recording, never wiping them on
a new session start.
- Yields batches in arrival order to storeRecordedSessionFiles.
- Caps pending batches (default 8) so a never-stored sequence cannot
leak unbounded memory.
Unit-tested directly in src/lib/cursorTelemetryBuffer.test.ts, including
the rapid-restart race that motivated the change.
Both windows had alwaysOnTop but lacked setVisibleOnAllWorkspaces, so
they stayed pinned to the Space they were first opened on. Users moving
to a different virtual desktop would lose sight of the overlay.
Calls setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true })
on macOS only — no-op on Windows/Linux so cross-platform behaviour is
unchanged.
1. Validate URL scheme in open-external-url handler
- Prevent opening file:// or other dangerous schemes via shell.openExternal
- Only allow http:, https:, and mailto: protocols
2. Fix latest video detection using mtime instead of lexicographic sort
- Lexicographic sort gives wrong results (e.g. recording-9 > recording-10)
- Now sorts by file modification time for reliable latest-file detection
3. Add null guard for AudioData.format in cloneWithTimestamp
- Replace non-null assertion (!) with proper validation
- Throws descriptive error if format is unexpectedly null
4. Prevent encodeQueue counter underflow in VideoExporter
- Use Math.max(0, ...) to prevent negative queue count
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add useCameraDevices hook to enumerate video input devices
- Update useScreenRecorder to support webcamDeviceId selection
- Add device selector UI above HUD bar (mic + webcam, hover-to-expand)
- All selectors and HUD bar are absolute-positioned to prevent layout shifts
- Increase HUD window to 600x200px to accommodate device panels
- Add unit tests for useCameraDevices hook
- Fix IPC handler to properly await shell.openPath() promise
- Export dialog now shows file name below the button for better UX
- Toast message now generic (works for both video and GIF exports)
- Fixed formatting in electron type definitions