You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(update): make the update flow report the truth and stop wedging (#38)
## Related Issue
No issue — reported directly. The problem is described below.
## Problem
A user's terminal showed `↑ Update available — v0.11.0` on the banner
while `/update` answered
`Update to v0.10.0 already in progress`, and nothing ever changed.
Investigating it found a whole class
of defects behind that one screen:
- The manifest advertised a **version**, so the client had to guess a
GitHub asset URL and poll for it.
When the guess was wrong it polled for ~6 minutes, on every launch.
- No installer network call had a timeout, so one hung request wedged
every update path with no expiry.
- A live pid held an install lease forever, with no ceiling, so a
recycled pid wedged updates permanently.
- The background installer's outcome was written by the parent process,
and the product tells the user to
close that terminal — so failures went unrecorded, the attempt counter
never advanced, and a version
that could not succeed was retried on every launch.
- `install.sh` rendered a progress bar only on a TTY; in the background
it blocked in a single silent
`curl` and reported nothing at all, which is why an update in flight
looked identical to a wedged one.
- Two foreground install paths ignored the lock entirely and could run
while a detached installer was
writing the same executable.
- The banner chip and `/update` read different files, which is how they
came to disagree.
## What changed
Fourteen commits, each with tests, in the order they were verified.
Grouped:
**The channel tells the truth.** `latest.json` now carries the resolved
per-platform artifact
(`url` + `sha256`), copied from the release's own native manifest, and a
native client requires an entry
for its platform before it will advertise or install anything.
npm-family sources are exempt — the
published version *is* their artifact — and that exemption is the case
the tests protect hardest.
`minRequiredVersion` lets a release bypass the staged rollout when a
client cannot skip it.
**Progress is visible.** The installer emits newline-terminated machine
progress on stderr — the stream
the parent already pipes — and the parent records it on the install
record. The footer status row under
the prompt renders `↑ v0.11.0`, `↓ v0.11.0 ▰▰▰▱▱▱▱▱ 42%`, `↑ v0.11.0
restart to apply`, reusing the
context gauge's own bar glyphs. An unknown download size drops the bar
rather than inventing a
percentage.
**Nothing wedges.** Every installer fetch has a connect bound, a
per-attempt ceiling and a stall guard
(`--retry` is deliberately absent: it resets `--max-time`). One
`lease.ts` states the lease rule once,
with a ceiling on live pids. Startup reconciles an abandoned install
into a recorded failure so a doomed
version parks. Both foreground paths hold the lock and write their
outcome.
**It says what is happening.** `/update` reports the installing version
*and* the newer target that
follows, and reports a parked version's attempt count and recorded
reason instead of a bare command.
Deletions rather than additions where the shape allowed: the plain-text
`/latest` fallback (it carried no
platform data, so it reported an unverifiable target as verified), the
duplicate `install.sh`/`install.ps1`
under `apps/site/public/`, the duplicated `isProcessRunning` and four
lease constants, the banner's update
chip and its per-frame `readFileSync`, and one of the two update
decisions per launch.
Two scope decisions worth flagging: killing an in-flight installer to
switch targets is **not**
implemented — the lease ceiling and reconciliation make the wait finite,
and honest reporting fixes what
the user saw. And a writability precheck was dropped in favour of
surfacing the installer's own recorded
error, which covers EACCES, network faults and disk-full alike.
Base is `fix/release-cdn-version-truth` (#37) because the manifest
generator work stacks on it.
## Checklist
- [x] I have read the
[CONTRIBUTING](https://github.com/Pythoughts-labs/pythinker-code/blob/main/CONTRIBUTING.md)
document.
- [x] I have linked a related issue, or explained the problem above.
- [x] I have added tests that prove my feature works.
- [x] Ran `gen-changesets` skill, or this PR needs no changeset.
- [x] Ran `gen-docs` skill, or this PR needs no doc update.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Update status now appears beneath the prompt, including availability,
download progress, required updates, waiting, and failures.
- Updates can enforce a minimum supported version.
- Platform-specific update availability is validated before
installation.
- **Bug Fixes**
- Prevented conflicting or abandoned installations from blocking future
updates.
- Added clearer failure messages and retry information.
- Installers now use connection, metadata, and download timeouts to
avoid hanging.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Stop offering an update with no build for the running platform, give every installer network call a timeout, expire a stale install lease instead of blocking updates forever, and say which version is installing and why a failed one stopped retrying.
Show update availability and live download progress in the status row under the prompt, replacing the startup banner chip that was computed once and never refreshed.
0 commit comments