feat(cli): add self-update command (reasonix upgrade/update)#3941
feat(cli): add self-update command (reasonix upgrade/update)#3941lanshi17 wants to merge 1 commit into
Conversation
Add 'reasonix upgrade' (alias: 'reasonix update') to download and apply the latest release from GitHub in-place. Includes '--check' flag for version-only comparison without downloading. The command: - Fetches the latest release from the GitHub Releases API - Compares semver versions (dev builds are skipped) - Downloads the platform-appropriate binary (.tar.gz or .zip) - Verifies SHA256 checksum against the release's SHA256SUMS file - Atomically replaces the running binary via temp+rename Uses the project's existing netclient proxy support so corporate environments work transparently. All user-facing strings are bilingual (en/zh) via the i18n catalogue. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1b6d45e to
50c0725
Compare
esengine
left a comment
There was a problem hiding this comment.
Thanks — the structure is clean, and two things here are genuinely better than the parallel attempt in #3859: every user-facing string goes through the i18n catalogue, and checksum verification fails closed (mismatch/missing-entry abort the install instead of warning and proceeding). Both of those are the bar.
But two of the same blockers from the #3859 review apply here too, and one of them fires on every single run today:
1. /releases/latest is the wrong endpoint for this repository (blocker — currently 100% broken). This repo publishes three release namespaces: v* (CLI), npm-v*, and desktop-v*. /releases/latest returns whichever release is marked Latest — which right now is desktop-v1.5.0. semver.IsValid("desktop-v1.5.0") is false, so as merged this command would error out on the invalid-tag path every time (and if a desktop release ever passed validation, it would try to download CLI archives from a desktop tag). You need to list /releases and select the newest tag matching ^v[0-9] — see the namespace filter in #3859, which got this part right. Skip "prerelease": true entries while you're there.
2. Windows cannot rename over the running executable (blocker). os.Rename(tmpName, resolved) fails with ERROR_ACCESS_DENIED while reasonix.exe is memory-mapped — the standard dance is rename the running exe aside to .old (allowed while running), rename the new binary into place, best-effort delete the .old and sweep stale ones on a later run. desktop/internal/update already implements this pattern.
On the overlap with #3859: two PRs are now solving the same feature; I've reviewed both against the same checklist (namespace filter ✅ there / ❌ here; fail-closed checksum ❌ there / ✅ here; Windows replace ❌ both; i18n ❌ there / ✅ here). Whichever lands first with all four points addressed gets merged, and I'll close the other crediting both. You two are also welcome to combine forces on one branch — between #3859's release-selection logic and this PR's verification/i18n, the complete implementation already exists across the two diffs.
|
Closing in favor of #3859 as the base implementation 鈥?see the cross-review there. The deciding issues were structural: |
…ngine#3859 Merge the best of both PRs per owner review feedback: - List /releases + isCLITag filter instead of /releases/latest (from esengine#3859) Fixes 100% breakage when newest release is desktop-v* or npm-v*. - Add --force flag for reinstalling the same version (from esengine#3859) - Add humanSize for download progress display (from esengine#3859) - Windows two-phase rename (.old) with rollback (new, based on minio/selfupdate) - Keep fail-closed checksum verification from esengine#3941 (hard-abort on mismatch) - Keep full en/zh i18n catalogue from esengine#3941 - Fix extractFromZip double-.exe bug (binName already carries .exe) - Add hide_windows.go / hide_other.go with build tags Refs: esengine#3941, esengine#3859
…ngine#3859 Merge the best of both PRs per owner review feedback: - List /releases + isCLITag filter instead of /releases/latest (from esengine#3859) Fixes 100% breakage when newest release is desktop-v* or npm-v*. - Add --force flag for reinstalling the same version (from esengine#3859) - Add humanSize for download progress display (from esengine#3859) - Windows two-phase rename (.old) with rollback (new, based on minio/selfupdate) - Keep fail-closed checksum verification from esengine#3941 (hard-abort on mismatch) - Keep full en/zh i18n catalogue from esengine#3941 - Fix extractFromZip double-.exe bug (binName already carries .exe) - Add hide_windows.go / hide_other.go with build tags Refs: esengine#3941, esengine#3859
Summary
Add
reasonix upgrade(alias:reasonix update) to download and apply the latest CLI release from GitHub Releases in-place.Changes
reasonix upgrade [--check]— fetches the latest release, compares semver, downloads the platform binary, verifies SHA256, and replaces the running executable atomically.--checkflag: version-only comparison without downloading — useful for scripts/CI.netclientproxy infrastructure so corporate environments work transparently.How it works
esengine/DeepSeek-Reasonix/releases/latestgolang.org/x/mod/semver.tar.gzfor Linux/macOS,.zipfor Windows)SHA256SUMSfilereasonixbinary and replaces the running executable via temp-file + renameSafety
version = "dev") are skipped — they never self-update.Usage
Files changed
internal/cli/upgrade.gointernal/cli/upgrade_test.gointernal/cli/cli.goupgrade/updatein command routerinternal/i18n/i18n.gointernal/i18n/messages_en.gointernal/i18n/messages_zh.gogo.mod/go.sumgolang.org/x/mod(semver comparison)