Skip to content

FEATURE: Keep the Windows client working with upstream's API 4 server - #7

Merged
M4NU5 merged 102 commits into
mainfrom
t3/review-upstream-additions
Oct 20, 2026
Merged

M4NU5 merged 102 commits into
mainfrom
t3/review-upstream-additions

Conversation

@M4NU5

@M4NU5 M4NU5 commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Upstream's server moved to API 4. It refuses the shared admin token on data routes and lists history as summaries, so the Windows client stopped working against it. This brings in upstream main (davis7dotsh#36) on top of the whole Windows stack, then updates the client.

  • Connecting with the admin token enrolls the PC and swaps the token for its own credential, as the Mac does.
  • A refused token rechecks once a minute instead of every 5 s, so the server's 10-failure lockout never trips.
  • History loads the selected record on its own. Transcribe again and Delete audio match the Mac.

Verified: on Windows against an upstream API 4 server on port 8392. Enrollment stored a working device credential. A mic test went through admission, upload and the tested delivery. History list and detail, Transcribe again, Delete audio and Try again all worked, and a bad token for 75 s never hit 429. Sol review came back clean after 3 rounds.

Assumptions: merge commit, not squash, so later upstream syncs stay clean.

Written by claude-opus-5-5 on behalf of Will 🚀

…-only

warning 0xA65A00: 4.76:1 on canvas, 5.06:1 on surface. muted 0x6B6270: 4.79:1 on sidebar, 5.40:1 on canvas.
M4NU5 and others added 27 commits October 18, 2026 02:30
A key held before the hold began, such as a movement key in a game or a
stuck key, keeps sending auto-repeat key-downs. The chord rule counted each
repeat as a new shortcut and cancelled every take. The hook now tracks which
keys are down, refreshes that set when a hold starts, and only cancels on a
fresh key-down. Found on a PC where Numpad 0 was held throughout.

The README also explains the chord rule and how to spot a muted microphone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	Sources/Inlay/InlayController.swift
#	Sources/Inlay/Views/PreferencesPage.swift
#	Sources/InlayCore/InlayConfiguration.swift
- Enrollment: after legacy enrollment closes, the admin token can no longer mint or rotate any device credential (only a device renews itself); revoked device ids can never re-enroll instead of being resurrected.
- Devices: serialize store writes in a chain so a background touch() can no longer undo a revocation on disk; emit whole-second timestamps (and normalize stored ones) so whole-second ISO 8601 client decoding accepts them.
- Audio purge: retention sweep and purge-all now take per-generation locks and re-check eligibility there (incl. current retention policy), and snapshot candidate ids so recordings created mid-purge are untouched.
- Client: an incomplete upload after key release is treated as interrupted (clipboard-only, visibly reported) instead of silently inserting a truncated prefix; a lost chunk acknowledgement no longer makes recovery cancel speech the server already holds (seal falls back to the unacknowledged frame count, persisted for replay).
- Setup: XML-escape values substituted into the LaunchAgent plist template.
- Setup paths: app-managed server files now live under Application Support/Inlay like the scripts (both builds, one LaunchAgent); legacy installs are adopted via their marker, and uninstall clears both marker layouts.
- Server: cancelled-then-reprocessed recordings can no longer be cancelled by their draining old task, queue positions follow the replacement attempt, and Wispr Flow enrichment holds the generation lock so it cannot race deletion.
- Upload: pipe backlog during connection retries now salvages the acknowledged audio instead of cancelling the generation; live takes no longer surface as recovered results; connection saves keep pending results for the same endpoint and stale credentials cannot delete them.
- Hotkeys: custom trigger keys are swallowed so they no longer also run the focused app's command (separate active tap, Accessibility-gated), modifier chords no longer start dictation, and modifiers added mid-take no longer cancel it.
- History/setup UI: detail reloads when its summary changes, failed detail loads show a retry instead of spinning, and model integrity hashing runs off the main actor with cancellation.
- Release/install: client release imports the Developer ID certificate into a temporary keychain (new INLAY_CODESIGN_P12_* secrets), and install-service.sh escapes paths for sed/plist and rejects newlines.
- install() claims the installing state before its first await and rejects overlap; detect() no longer resets that state when the setup view reappears, so repeated clicks cannot run competing installs.
- History detail: a failed reload now reaches the error/retry pane instead of silently keeping the cached record on screen.
- Align first-run model downloads with both development runners, including exact-manifest legacy fallback and Linux defaults.
- Sign the distribution app bundle with a secure timestamp.
- Type revoke-device IDs as strings, preserve arbitrary accepted IDs as one URL segment, and keep accepted IDs inside router/request-line limits.
- Restore documented event heartbeats and let valid device credentials bypass admin-token guessing throttles without resetting them.
- Correct stale lifecycle, API-version, service-installation, and concurrency documentation.
ENHANCED: Improve dictation recovery and setup
…pill

Settings is now a dark window with a sidebar for Dictation, Server and About.
Its fields, choices, toggle and buttons are drawn by the client. The tray menu
is a themed popup with a status header. Dropdowns in Settings use the same
popup.

A click-through pill above the taskbar shows each take. A small orb breathes
while the microphone starts, then opens into a black pill whose bars follow
the live mic level. It shrinks back to an orb with a spinner while
transcribing. Once the text is pasted the spinner closes into a green ring and
a tick draws in. Each change of stage morphs in size and colour.

The pill reads the microphone level from audio.rs. It learns when capture
started and when a paste landed from two new timestamps in the app status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Long dropdowns now fit the screen and scroll with the wheel or arrow keys.
A header refresh keeps that limit. Right-clicking a tray menu item selects
it, as it did with the system menu. An open tray menu drops an expired
notice. The pill shows Pasted as soon as the paste lands instead of after
the delivery receipt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FEATURE: Make the Windows client look native to Inlay, with a live recording pill
…, like the Mac (#3)

* FEATURE: Stream the recording pill's waveform right to left, as on the Mac

Each of the 9 bars is one loudness sample, twenty a second, with the newest
on the right. The bars slide left between samples. The meter now matches the
Mac client's: -68 to -18 dBFS, a 20 ms rise and a 130 ms fall, timed from
the samples rather than from how often buffers arrive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* FIX: Keep the waveform's bars still while the loudness flows through them

Each bar eases towards its right neighbour's sample, so the volume moves right
to left while the bars stay put. Samples arrive every 55 ms, 10% slower than
the Mac.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* FIX: Keep the waveform's sample timing steady and start each take clean

Sampling keeps its phase when a frame is late, so samples average 55 ms
apart whatever the frame rate. A take that starts while the pill is still
shrinking away begins with silent bars, not the last take's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* FIX: Start the pill's tick as the paste keystroke goes out

The tick used to start after paste waited half a second to restore the
clipboard, so the text appeared well before it. paste now reports when the
keystroke is sent, and the pill shows Pasted from then on, ahead of the
still-running take. A paste that fails before the keystroke shows no tick. A
new take clears the last one's tick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…, Microphone and This PC pages

The settings dialog becomes a resizable main window with a sidebar, as on
the Mac. Pages are laid out from the app's state and scroll when the
window is shorter than the page.

- Dictation: the dictation key as a key cap, the server status with Check
  connection, the last dictation with Copy, what became of it and its
  length, and Test microphone.
- Microphone: the input picker, the microphone the next dictation will use,
  and Test microphone.
- This PC: server address, access token and device name, applied with
  Connect; the dictation key and start at sign-in, applied straight away;
  the version and settings folder.

Test microphone records a `test` generation until Finish dictation, shows
the transcript and reports `tested` without pasting. The tray menu now
reads Copy last message and Open Inlay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tray message

Test microphone on the Microphone page showed its result only on the
Dictation page. It now shows in a boxed Test result card under the button,
while it listens, while it transcribes and after. The tray menu says
"Hold Right Ctrl" instead of "Hold Right Ctrl to dictate", and is narrower.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g choices

A test that ended without a transcript, such as one too short or one whose
microphone failed, left the previous test's result on the Microphone page.
It now shows the reason instead. A long microphone name could also cover
the "Choose input" label in a narrow window; choices now stop at the label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in the pill's waveform (#3). Also carries its follow-up meter fix,
which landed on the pill branch after #3 merged: -55 to -5 dBFS with a
quicker fall, so speech on loud microphones no longer fills every bar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A test still transcribing could overwrite a later test's result when it
finished. Results are now tied to their take, and only the latest test's
result or failure shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tice

The reason came from the tray's latest notice, which another take could
replace just before the test's guard read it. Each take runs on its own
thread, so the guard now reads the last notice raised on that thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared history from the server, newest first, beside the selected
dictation. Filter by device and source, refresh, and load older pages.
Copy a transcript, delete a dictation after confirming, or open its audio
in the default player. The list and the dictation scroll on their own, and
the page reloads after each new take. The Dictation page gains a History
button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A click selects the row it hit, even if a reply changed the list since.
- A delete drops a load already under way, which could still list it, and
  loads again. Deleting the last loaded record moves Load older's cursor.
- The audio buttons use short labels when the pane is narrow.
- Scroll offsets stay within the panes after the window grows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deleting every loaded record cleared the cursor, hiding older records still
on the server. Load the newest page again instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
FEATURE: Browse shared history on Windows, like the Mac's History page
FEATURE: Give Windows the Mac app's window, starting with Dictation, Microphone and This PC
…ice credential

Upstream's server now requires API version 4, refuses its admin token on
data routes, and lists history as summaries. The Windows client:

- enrolls with the admin token and keeps the per-device credential it gets
  back, as the Mac does, one enrollment at a time
- backs off to a minute when the server refuses the credential, so it
  doesn't trip the ten-failure sign-in throttle
- shows History from summaries and loads the selected record on its own
- adds Transcribe again and Delete audio, as on the Mac
- treats a cut-off event line as a dropped connection, and accepts 24-bit
  and 64-bit microphone formats

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c40d0b7f-8cf2-4533-824e-947152d4ff6a
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@M4NU5
M4NU5 marked this pull request as ready for review October 20, 2026 14:30
@M4NU5
M4NU5 merged commit c2913d9 into main Oct 20, 2026
17 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants