fix: repair rb update on Windows and wire the background update check#37
Merged
Conversation
rb update extracted the release archive straight into the binary's own directory. The payload (rb / rb.exe) shares the running executable's name, so Expand-Archive -Force tried to overwrite the live, locked exe. On Windows its internal Remove-Item fails with "Access to the path is denied", aborting the update. The extractedPath !== binPath guard was then false (both resolved to the same rb.exe), so the .new staging rename was skipped and the run died with "extracted binary not found at expected location". Extract into an isolated .rb-update-<ts> temp dir instead, then stage the result as .new and rename-swap into place. Renaming a running binary is permitted on Windows; deleting it is not. The existing .bak rollback and post-swap --version verification are unchanged. The temp dir is always removed via finally. Verified end-to-end on Windows: a pinned 1.2.0 standalone self-replaced to the live 1.3.0 release, kept rb.exe.bak for rollback, left no temp dirs, and re-ran as a clean no-op.
The "Update available" notice on the welcome screen read a cache that nothing ever populated: checkForUpdate() was only ever called from tests, so the cache stayed empty and getPendingNotification() always returned null. The notice could never fire on its own. A naive inline call cannot fix this — short-lived commands (the welcome screen exits immediately) terminate long before the GitHub round-trip completes, so the fetch would be killed mid-flight. Instead spawn a detached, unref'd `rb __update-check` process on launch that outlives the command and warms the cache for the next run (the same approach gh and update-notifier use). - add isRefreshDue(): cheap sync gate (honors skip rules + 24h TTL) so a fresh cache costs zero subprocesses - add the hidden __update-check entrypoint in main.ts; gate it before routing - spawn the detached refresh only in standalone builds (IS_BIN); dev mode's execPath is bun, not rb - skip entirely in CI and under --quiet/--json/--url-only (existing shouldSkip) Verified end-to-end on Windows: a pinned 1.2.0 standalone spawned the detached check, the cache filled with 1.3.0, and the next run rendered "Update available: 1.2.0 -> 1.3.0". --quiet produced no output and no spawn.
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.
What
rb updateextracted the release archive straight into the running binary's own directory. The archive payload (rb/rb.exe) shares the live executable's name, so:Expand-Archive -Force(Windows) /tar -xzftried to overwrite the running, locked exe. On Windows the archiver's internalRemove-Itemfails withAccess to the path '...\rb.exe' is denied.extractedPath !== binPathguard was then false (both resolved to<binDir>/rb.exe), so the.newstaging rename was skipped — leaving the run to die withextracted binary not found at expected location.Net effect:
rb updatewas completely broken on Windows.Fix
Extract into an isolated
.rb-update-<ts>temp dir, then stage the extracted binary as.newand rename-swap into place. Renaming a running binary is permitted on Windows; deleting it is not — which is exactly what the existing.bak/.newswap relies on. The temp dir is always cleaned viafinally.The existing
.bakone-version rollback and the post-swap--versionverification are unchanged.Test plan
Verified end-to-end on Windows 11 (the platform that was failing):
rb.exepinned to1.2.0(same--define IS_STANDALONE/PLATFORMflags ascli-binaries.yml).rb updateagainst the live1.3.0release:Update complete→ exit 0rb.exereplaced in place (114154496 → 98544640 bytes),rb.exe --version→ 1.3.0rb.exe.bakpreserved for rollback.rb-update-*temp dir, no stray.newrb update→Already on the latest version (1.3.0), exit 0 (clean idempotent no-op).pnpm typecheckgreen. The 8 failing tests in this environment are pre-existingspawn 'bun'ENOENT integration tests (localbunis a.ps1shim node can't exec) — unrelated to this change.