Desktop app self-update reliability across platforms
NousResearch/hermes-agent · cluster 37557 · apps/desktop
Data as of
4 open items. Fix merged in #50448. Check it covers your case.
The short answer
- Known?
- Yes. 13 related items grouped here, 6 issues already closed.
- Fix event
- A fix was merged to main in PR #50448. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
partially resolved, deciding PRs #50448, #86675. That is separate from the fix event. - Still open
- 3 issues and 1 PR.
Next step: read #50448, then check whether your report is one of the 3 still open.
Read #50448Pick up a Lab taskThese issues and pull requests address bugs and improvements in the desktop app's in-app self-update flow on both macOS and Windows, covering problems such as silent failures, update loops, missing progress feedback, and unreliable updater handoff.
Open issues3
- Issue#39248[Bug]: Desktop app update process is broken
- Issue#46076Hermes Desktop in-app update does not reliably apply or relaunch on macOS
- Issue#64577[Bug]: macOS desktop self-update fails four ways on long-lived installs (stale staged updater, silent backup, canonical-app desync, retry-loop errors)
Open PRs1
- PR#57763fix: macOS in-app update silent failure handling (#57645)
Fixes on record
-
#50448 feat(desktop/windows): show update-in-progress feedback before the desktop exits
files:
apps/desktop/electron/main.cjs,apps/desktop/src/i18n/en.ts,apps/desktop/src/i18n/ja.ts,apps/desktop/src/i18n/zh-hant.ts,apps/desktop/src/i18n/zh.tsShow the diff
-
apps/desktop/electron/main.cjs@@ -1129,6 +1129,14 @@ function directoryExists(filePath) { // marker's own age ceiling; covers a stuck-but-alive updater). const UPDATE_WAIT_TIMEOUT_MS = 20 * 60 * 1000 const UPDATE_WAIT_POLL_MS = 1000 +// How long the desktop lingers on the "updating, don't reopen" overlay after +// spawning the detached updater, before it quits to release the venv shim. The +// old 600ms was long enough to register the child process but far too short for +// the user to READ the overlay — the window just vanished, looked like a crash, +// and the user relaunched mid-update (the #50238 restart-loop trigger). A +// couple of seconds lets the message land and bridges the gap until the +// updater's own progress window appears. (#50419) +const UPDATE_HANDOFF_DWELL_MS = 2500 // Block until no live update is in progress (or we hit the wait timeout). // Emits a boot-progress phase so the renderer shows "Update in progress…" @@ -1867,7 +1875,11 @@ async function applyUpdates(opts = {}) { return { ok: true, manual: true, command, hermesRoot: updateRoot } } - emitUpdateProgress({ stage: 'restart', message: 'Handing off to the Hermes updater…', percent: 100 }) + emitUpdateProgress({ + stage: 'restart', + message: 'Updating Hermes — this window will close and the updater will open. Don’t reopen Hermes yourself; it restarts automatically when the update finishes.', + percent: 100 + }) repairMacUpdaterHelper(updater) const updateRoot = resolveUpdateRoot() @@ -1903,11 +1915,14 @@ async function applyUpdates(opts = {}) { rememberLog(`[updates] launched updater: ${updater} ${updaterArgs.join(' ')}; exiting desktop to release venv shim`) - // Give the OS a beat to register the new process, then quit. The updater - // rebuilds and relaunches us when it's done. + // Linger on the "updating — don't reopen" overlay long enough for the user + // to actually read it (and to bridge the gap until the updater's own window + // appears), THEN quit to release the venv shim. The updater rebuilds and + // relaunches us when it's done. (#50419 — a 600ms quit looked like a crash + // and lured users into the #50238 relaunch loop.) setTimeout(() => { app.quit() - }, 600) + }, UPDATE_HANDOFF_DWELL_MS) return { ok: true, handedOff: true, updater } } finally { @@ -1946,9 +1961,12 @@ async function handOffWindowsBootstrapRecovery(reason) { child.unref() rememberLog(`[bootstrap] handed off ${reason} recovery to updater: ${updater} ${updaterArgs.join(' ')}; exiting desktop to release app.asar`) + // Same dwell as the in-app update hand-off (#50419): give the updater's + // window time to appear before we vanish, so the recovery doesn't look like + // a crash and provoke a mid-recovery relaunch. setTimeout(() => { app.quit() - }, 600) + }, UPDATE_HANDOFF_DWELL_MS) return true } -
apps/desktop/src/i18n/en.ts@@ -1382,10 +1382,11 @@ export const en: Translations = { copy: 'Copy', copied: 'Copied', done: 'Done', - applyingBody: 'The Hermes updater will take over in its own window and reopen Hermes when it’s done.', + applyingBody: + 'The Hermes updater takes over in its own window and reopens Hermes automatically when it’s done. Please don’t reopen Hermes yourself while it’s updating.', applyingBodyBackend: 'The remote backend is applying the update and will restart. Hermes reconnects automatically when it’s back.', - applyingClose: 'Hermes will close to apply the update.', + applyingClose: 'This window will close while the update runs, then Hermes reopens on its own.', errorTitle: 'Update didn’t finish', errorBody: 'No worries — nothing was lost. You can try again now.', notNow: 'Not now', -
apps/desktop/src/i18n/ja.ts@@ -1512,9 +1512,9 @@ export const ja = defineLocale({ copy: 'コピー', copied: 'コピーしました', done: '完了', - applyingBody: 'Hermes アップデーターが独自のウィンドウで引き継ぎ、完了後に Hermes を再度開きます。', + applyingBody: 'Hermes アップデーターが独自のウィンドウで引き継ぎ、完了後に自動的に Hermes を再度開きます。更新中はご自分で Hermes を開き直さないでください。', applyingBodyBackend: 'リモートバックエンドが更新を適用して再起動します。復帰すると Hermes が自動的に再接続します。', - applyingClose: 'Hermes は更新を適用するために閉じます。', + applyingClose: 'このウィンドウは更新中に閉じ、その後 Hermes が自動的に再度開きます。', errorTitle: '更新が完了しませんでした', errorBody: 'ご安心ください。何も失われていません。今すぐ再試行できます。', notNow: '今は後で', -
apps/desktop/src/i18n/zh-hant.ts@@ -1463,9 +1463,9 @@ export const zhHant = defineLocale({ copy: '複製', copied: '已複製', done: '完成', - applyingBody: 'Hermes 更新程式會在自己的視窗中接管,並在完成後重新開啟 Hermes。', + applyingBody: 'Hermes 更新程式會在自己的視窗中接管,並在完成後自動重新開啟 Hermes。更新期間請勿自行重新開啟 Hermes。', applyingBodyBackend: '遠端後端正在套用更新並將重新啟動。恢復後 Hermes 會自動重新連線。', - applyingClose: 'Hermes 將關閉以套用更新。', + applyingClose: '此視窗會在更新期間關閉,隨後 Hermes 會自動重新開啟。', errorTitle: '更新未完成', errorBody: '沒有資料遺失。您可以現在重試。', notNow: '暫不', -
apps/desktop/src/i18n/zh.ts@@ -1568,9 +1568,9 @@ export const zh: Translations = { copy: '复制', copied: '已复制', done: '完成', - applyingBody: 'Hermes 更新器会在自己的窗口中接管,并在完成后重新打开 Hermes。', + applyingBody: 'Hermes 更新器会在自己的窗口中接管,并在完成后自动重新打开 Hermes。更新期间请不要自行重新打开 Hermes。', applyingBodyBackend: '远程后端正在应用更新并将重启。恢复后 Hermes 会自动重新连接。', - applyingClose: 'Hermes 将关闭以应用更新。', + applyingClose: '此窗口会在更新期间关闭,随后 Hermes 会自动重新打开。', errorTitle: '更新未完成', errorBody: '没有数据丢失。你可以现在重试。', notNow: '暂不',
-
-
#86675 fix(desktop): confirm detached updater spawn before quitting for hand-off (#66753)
files:
apps/desktop/electron/main.ts,apps/desktop/electron/updater-process.test.ts,apps/desktop/electron/updater-process.ts
1 PR closed without merging
From the close comments: other 1
- #42121 fix(desktop): stop macOS Update & Restart loop by always updating in-app · other
Closed issues · 6
- Closed#37557[Bug]: Windows desktop: /update from chat silently hangs — no progress/logs, updater handoff not observable
- Closed#39339[Bug]: Desktop app update installs but version remains unchanged — update loop on macOS
- Closed#43531[Bug]: hermes desktop errors out when updating
- Closed#50419feat(desktop/windows): show update progress before the desktop exits so it doesn't look like a crash
- Closed#57645[Bug]: desktop in-app update on macOS closes without updating
- Closed#66753[Bug]: Desktop exits without confirming detached updater spawn or early process survival
How this cluster was grouped
-
Link evidence (
partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text. - Members outside that structural core may belong to a different underlying problem.
-
Pairwise link density
0.12: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the Lab