diff --git a/apps/desktop/src/app/updates-overlay.tsx b/apps/desktop/src/app/updates-overlay.tsx
index 0c24dbb8978..b4c0f30cebc 100644
--- a/apps/desktop/src/app/updates-overlay.tsx
+++ b/apps/desktop/src/app/updates-overlay.tsx
@@ -382,6 +382,8 @@ function ApplyingView({ apply, isBackend }: { apply: UpdateApplyState; isBackend
const u = t.updates
const label = u.stages[apply.stage as DesktopUpdateStage] ?? u.stages.idle
const body = isBackend ? u.applyingBodyBackend : u.applyingBody
+ const currentMessage = apply.message.trim()
+ const recentLog = apply.log.slice(-4)
const percent =
typeof apply.percent === 'number' && Number.isFinite(apply.percent)
@@ -397,6 +399,12 @@ function ApplyingView({ apply, isBackend }: { apply: UpdateApplyState; isBackend
+ {currentMessage} +
+ ) : null}{u.applyingClose}
) diff --git a/apps/desktop/src/store/updates.test.ts b/apps/desktop/src/store/updates.test.ts index 25ceda7c22f..09f89daa0da 100644 --- a/apps/desktop/src/store/updates.test.ts +++ b/apps/desktop/src/store/updates.test.ts @@ -370,6 +370,40 @@ describe('applyBackendUpdate recovery', () => { expect($backendUpdateApply.get().applying).toBe(false) }) + it('surfaces backend update action log lines while the action is running', async () => { + updateHermesSpy.mockResolvedValue({ ok: true, name: 'update', pid: 1 }) + getActionStatusSpy + .mockResolvedValueOnce({ + exit_code: null, + lines: ['Pulling updates...', 'Installing dependencies...'], + name: 'update', + pid: 1, + running: true + }) + .mockRejectedValueOnce(new Error('ECONNREFUSED')) + checkHermesUpdateSpy.mockResolvedValue({ + install_method: 'git', + current_version: '0.16.0', + behind: 0, + update_available: false, + can_apply: true, + update_command: 'hermes update', + message: null + }) + + const promise = applyBackendUpdate() + await vi.advanceTimersByTimeAsync(1500) + + expect($backendUpdateApply.get().message).toBe('Installing dependencies...') + expect($backendUpdateApply.get().log.map(entry => entry.message)).toEqual([ + 'Pulling updates...', + 'Installing dependencies...' + ]) + + await vi.advanceTimersByTimeAsync(5000) + await promise + }) + it('surfaces an error when the backend never comes back after the restart', async () => { updateHermesSpy.mockResolvedValue({ ok: true, name: 'update', pid: 1 }) getActionStatusSpy.mockRejectedValue(new Error('ECONNREFUSED')) @@ -383,4 +417,3 @@ describe('applyBackendUpdate recovery', () => { expect($backendUpdateApply.get().stage).toBe('error') }) }) - diff --git a/apps/desktop/src/store/updates.ts b/apps/desktop/src/store/updates.ts index 3297b6e9a90..45e0ad7e678 100644 --- a/apps/desktop/src/store/updates.ts +++ b/apps/desktop/src/store/updates.ts @@ -455,6 +455,25 @@ function finishBackendApply(returned: boolean): DesktopUpdateApplyResult { return { ok: false, error: 'apply-failed', message: 'Backend did not come back online.' } } +function ingestBackendActionStatus(status: Awaited