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
Copy file name to clipboardExpand all lines: docs/specs/auto-update.md
+27-18Lines changed: 27 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Auto-Update Spec
2
2
3
-
The standalone app checks for updates on launch, downloads silently in the background, and installs when the user quits. A banner tells the user an update is pending. On next launch, a brief banner confirms the update succeeded (or notes a failure).
3
+
The standalone app checks for updates on launch and prompts in the Baseboard when one is available. It does not download or install the update until the user approves the prompt. Once approved, the app downloads the update in the background and installs it when the user quits. On next launch, a brief banner confirms the update succeeded (or notes a failure).
4
4
5
5
## How it works
6
6
@@ -9,40 +9,49 @@ app launch
9
9
│
10
10
├─ check for post-install markers in localStorage
11
11
│ ├─ success marker → show "Updated to vX.Y.Z" banner (auto-dismisses after 10s)
12
-
│ ├─ failure marker → show "Update failed — will retry" banner
12
+
│ ├─ failure marker → show "Update failed." banner with debug action
13
13
│ └─ no marker → continue
14
14
│
15
15
├─ wait 5 seconds
16
16
│
17
17
├─ check(endpoint) ──→ no update ──→ done (silent)
18
18
│ │
19
-
│ └─→ update available → download in background
20
-
│ ├─ success → show "will install when you quit" banner
21
-
│ └─ failure → log error, done (silent)
19
+
│ └─→ update available → show approval prompt
20
+
│ │
21
+
│ ├─ dismissed/no approval → no download, no install
22
+
│ │
23
+
│ └─ user approves → download in background
24
+
│ ├─ success → show "will install when you quit" banner
25
+
│ └─ failure → log error, return to approval prompt
The `Update` object from `download()` is held in memory for the session. The close handler intercepts the window close event, writes a success marker to `localStorage`*before* calling `install()` (because on Windows, NSIS force-kills the process), then calls `install()`. In Vite dev mode (`pnpm dev:standalone`), the close handler skips `install()` without preventing the close. Dev mode is useful for testing check/download/banner behavior, but install must be tested from a packaged app because the updater resolves its replacement target from the current executable path.
37
+
The `Update` object returned by `check()` is held in memory as an available update. Clicking the approval action calls `download()` and promotes it to a pending update only after the download succeeds. The close handler intercepts the window close event only when there is an approved, downloaded update, writes a success marker to `localStorage`*before* calling `install()` (because on Windows, NSIS force-kills the process), then calls `install()`. In Vite dev mode (`pnpm dev:standalone`), the close handler skips `install()` without preventing the close. Dev mode is useful for testing check/download/banner behavior, but install must be tested from a packaged app because the updater resolves its replacement target from the current executable path.
34
38
35
39
## Update notice in the Baseboard
36
40
37
41
Update status appears as a text notice on the right side of the Baseboard (the always-visible bottom strip — see `layout.md`). It coexists with doors and shortcut hints.
38
42
39
-
| State | Message | Changelog | Auto-dismiss |
40
-
|-------|---------|-----------|--------------|
41
-
|`downloaded`| "Update downloaded (v0.5.0) — will install when you quit." | Yes | No |
42
-
|`post-update-success`| "Updated to v0.5.0 — from v0.4.0." | Yes | 10 seconds |
43
-
|`post-update-failure`| "Update to v0.5.0 failed — will retry next launch." | No | No |
43
+
| State | Message | Actions | Auto-dismiss |
44
+
|-------|---------|---------|--------------|
45
+
|`available`| "Update available" | "Changelog", "Install when I quit" | No |
46
+
|`downloading`| "Downloading update v0.5.0" | "Changelog" | No |
47
+
|`downloaded`| "Update downloaded (v0.5.0) — will install when you quit" | "Changelog" | No |
48
+
|`post-update-success`| "Updated to v0.5.0 — from v0.4.0" | "Changelog" | 10 seconds |
49
+
|`post-update-failure`| "Update failed" | "Click here to debug" | No |
44
50
45
-
All states are dismissible via [×]. Dismissing hides the notice for the session only — it does not affect whether the update installs on quit.
51
+
The "Install when I quit" action is the user's approval to download the update now and install it when they quit. The inline "Changelog" action calls Tauri's `getVersion()` and opens `https://mouseterm.com/changelog/after/<current-version>`.
52
+
When a notice has follow-up actions, it uses ` · ` as the separator between the message and action labels.
53
+
54
+
All states are dismissible via [×]. Dismissing an unapproved `available` notice means no update is downloaded or installed in that session. Dismissing a `downloading` or `downloaded` notice hides it for the session only — it does not cancel an already-approved download/install.
46
55
47
56
The notice matches the Baseboard's existing text style (9px mono, `text-muted`). It's pushed right via `ml-auto` so it doesn't compete with doors or the shortcut hint on the left.
48
57
@@ -70,13 +79,13 @@ Single key: `mouseterm:update-result`
70
79
| Successful install |`{ "from": "0.4.0", "to": "0.5.0" }`| On next launch, after reading |
71
80
| Failed install |`{ "failed": true, "version": "0.5.0", "error": "..." }`| On next launch, after reading |
72
81
73
-
The success marker is written *before*`install()` because Windows NSIS force-kills the process — if we wrote it after, it would never persist. If `install()` then throws, the marker is overwritten with a failure entry.
82
+
The success marker is written *before*`install()` because Windows NSIS force-kills the process — if we wrote it after, it would never persist. If `install()` then throws, the marker is overwritten with a failure entry. No marker is written for an update that was found but never approved.
74
83
75
84
## Files
76
85
77
86
| File | Role |
78
87
|------|------|
79
-
|[`standalone/src/updater.ts`](../../standalone/src/updater.ts)| State machine, update check, background download, close handler, post-install markers |
88
+
|[`standalone/src/updater.ts`](../../standalone/src/updater.ts)| State machine, update check, user-approved download, close handler, post-install markers |
80
89
|[`standalone/src/UpdateBanner.tsx`](../../standalone/src/UpdateBanner.tsx)| Pure presentational component — renders inline notice content for the Baseboard |
81
90
|[`standalone/src/main.tsx`](../../standalone/src/main.tsx)| Passes `<ConnectedUpdateBanner />` as the `baseboardNotice` prop to `<App />`, calls `startUpdateCheck()` after platform init |
82
91
@@ -108,9 +117,9 @@ The Rust side registers the plugin with `tauri_plugin_updater::Builder::new().bu
108
117
109
118
## Design decisions
110
119
111
-
**Why install on quit, not on demand?** MouseTerm is a terminal app with running processes. A mid-session relaunch would kill all sessions. By installing at quit time, the user has already decided to close their terminals.
120
+
**Why install on quit after approval, not immediately?** MouseTerm is a terminal app with running processes. A mid-session relaunch would kill all sessions. By installing at quit time, the user has already decided to close their terminals.
112
121
113
-
**Why no "skip this version"?**The update is already downloaded and will install on quit regardless. There's nothing to opt out of. [×] just hides the notification.
122
+
**Why no silent download?**Update bundles can be large, can fail for environment-specific reasons, and may surprise users who did not opt into changing the app. The launch probe is silent, but download/install only begins after explicit approval.
114
123
115
124
**Why the Baseboard, not a top banner?** A top banner pushes terminal content down, which is disruptive in a terminal app. The Baseboard is already a status strip — the update notice fits naturally alongside doors and shortcut hints. It also avoids adding a new UI element; the notice just occupies unused space in an existing one.
0 commit comments