feat: auto-install a staged update at the next quiet moment#21
Merged
Conversation
Auto-update staged the build but only relaunched if the app was already backgrounded and silent at the instant staging finished — a one-shot check. Miss it (on a call, popover open) and the update stranded on a manual "Restart" click, against the intent of "update automatically". Re-evaluate the same guard whenever a quiet window can open: the app resigning active and the output device falling idle, for an instant reaction — backed by a low-frequency timer so correctness never rests on those signals firing (the sibling per-process running property is a known non-deliverer on macOS 26). Every watcher exists only while an update waits and is torn down on relaunch; nothing runs in steady state. The audio guard stays — a relaunch mid-playback would blip per-app taps to unity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
With auto-update on, Sparkle silently downloads and stages the new build, then the app relaunches into it — but only if it's already in the background with the output device idle at the instant staging finishes. That check ran once. Catch the user mid-call with the popover open and the staged update fell back to a manual "Restart" click, which reads as "auto-update didn't work" — exactly what was reported for 0.16.0 → 0.17.0.
Fix
Re-evaluate the same quiet-window guard whenever one can open, instead of giving up after the single check:
didResignActiveNotification.kAudioDevicePropertyDeviceIsRunningSomewhere, re-armed across default-output changes.Every watcher is armed only while a staged update waits and is torn down on relaunch — nothing runs in steady state, honoring the "don't burn resources idling" constraint. The audio guard is kept deliberately: a relaunch mid-playback drops process taps for a moment and would blip per-app volumes to unity. The "Restart to Update" row and install-on-quit remain as the explicit/backstop paths.
Net effect: with auto-update enabled it now installs fully silently at the first unobtrusive moment, no clicks.
Testing
make build(Swift 6, strict concurrency complete),make test(43 tests),pre-commit— all green. No unit test added: the path depends onNSApp.isActive, live HAL state, and Sparkle staging an update, none observable without a running app and a real newer build to stage; the bounded timer is what makes the outcome guaranteed rather than event-timing-dependent.