mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 15:03:57 +00:00
174 lines
8.7 KiB
Markdown
174 lines
8.7 KiB
Markdown
# Auto-update
|
|
|
|
The desktop shell (`app/src-tauri`) auto-updates itself via Tauri's
|
|
[`plugin-updater`](https://tauri.app/plugin/updater/) against a manifest
|
|
published on GitHub Releases. The OpenHuman core sidecar (`openhuman` binary)
|
|
ships inside the `.app` bundle, so a shell update upgrades both.
|
|
|
|
## Architecture
|
|
|
|
| Piece | Role |
|
|
| --------------------------------------------------- | ------------------------------------------------------------- |
|
|
| `app/src-tauri/Cargo.toml` | declares `tauri-plugin-updater` |
|
|
| `app/src-tauri/tauri.conf.json` (`plugins.updater`) | endpoint + minisign pubkey |
|
|
| `app/src-tauri/permissions/allow-app-update.toml` | ACL allow-list for the four updater commands |
|
|
| `app/src-tauri/src/lib.rs::check_app_update` | probe-only; returns version info |
|
|
| `app/src-tauri/src/lib.rs::download_app_update` | downloads bundle bytes, stages them, does NOT install |
|
|
| `app/src-tauri/src/lib.rs::install_app_update` | installs previously-staged bytes + relaunches |
|
|
| `app/src-tauri/src/lib.rs::apply_app_update` | legacy combined download+install+restart (kept for compat) |
|
|
| `app/src/hooks/useAppUpdate.ts` | React state machine, auto-check, auto-download |
|
|
| `app/src/components/AppUpdatePrompt.tsx` | global banner (mounted in `App.tsx`) — silent during download |
|
|
| `app/src/components/settings/panels/AboutPanel.tsx` | manual "Check for updates" |
|
|
| `.github/workflows/release.yml` | builds + signs + publishes `latest.json` |
|
|
|
|
The shell emits two Tauri events while updating:
|
|
|
|
- `app-update:status` — string payload, one of `checking`, `downloading`,
|
|
`ready_to_install`, `installing`, `restarting`, `up_to_date`, `error`
|
|
- `app-update:progress` — `{ chunk: number, total: number | null }`
|
|
|
|
`useAppUpdate` listens on both and exposes a state machine
|
|
(`idle | checking | available | downloading | ready_to_install | installing |
|
|
restarting | up_to_date | error`).
|
|
|
|
## User flow (Option 2: auto-download, prompt to restart)
|
|
|
|
1. ~30 seconds after launch, the hook runs a silent `check_app_update`. It
|
|
re-checks every 4 hours.
|
|
2. If the manifest reports a newer version, the hook **automatically calls
|
|
`download_app_update`** in the background — the user sees nothing.
|
|
3. Once the bytes are staged, the Rust side emits `ready_to_install` and the
|
|
bottom-right banner appears with the header **"Update ready to install"**
|
|
and a body line of **"Version <version> is ready to install."** (falling
|
|
back to **"A new version is ready to install."** when the manifest didn't
|
|
supply a version), followed by **Restart now** / **Later** buttons.
|
|
4. Clicking **Restart now** invokes `install_app_update`, which acquires the
|
|
core restart lock, shuts down the in-process core, calls
|
|
`Update::install(staged_bytes)` (no re-download), and then `app.restart()`.
|
|
5. **Later** dismisses the banner without canceling the staged bytes — the
|
|
user can also click "Check for updates" in Settings → About to surface the
|
|
prompt again on demand.
|
|
|
|
Why this flow vs. silent install: a chat / AI app often has in-flight
|
|
conversations and background agent work. Yanking the process away mid-task
|
|
costs more user trust than a one-click "Restart now" prompt earns in
|
|
convenience. We download invisibly so the _only_ action the user takes is
|
|
choosing the restart moment.
|
|
|
|
## Validating end-to-end (issue #677 acceptance criteria)
|
|
|
|
The auto-update path must be validated against a real signed bundle and a
|
|
real `latest.json` — `pnpm tauri dev` does not produce updater-compatible
|
|
artifacts. Use this recipe.
|
|
|
|
### Prerequisites
|
|
|
|
- A published GitHub release at a higher version than what you'll build
|
|
locally (e.g. the latest `v0.53.x`). The release must include the signed
|
|
bundle for your platform plus `latest.json`.
|
|
- **No signing key needed for verification.** Minisign signature
|
|
verification on the downloaded bundle uses the public key already baked
|
|
into `tauri.conf.json::plugins.updater.pubkey`, which the local build
|
|
picks up automatically. `TAURI_SIGNING_PRIVATE_KEY` (+ its password) is
|
|
required only by CI to _sign_ new releases — never to verify existing
|
|
ones. Treat the private key as a secret and keep it out of dev machines.
|
|
|
|
### Recipe
|
|
|
|
1. **Pick a target older than the published release.** Edit all four version
|
|
sources to a known-older value (e.g. `0.53.0` if `0.53.4` is published):
|
|
|
|
```text
|
|
app/package.json::version
|
|
app/src-tauri/Cargo.toml::package.version
|
|
app/src-tauri/tauri.conf.json::version
|
|
Cargo.toml::workspace.package.version
|
|
```
|
|
|
|
`scripts/release/verify-version-sync.js` exists exactly to keep these
|
|
four in lockstep — run it after editing.
|
|
|
|
2. **Build a packaged bundle locally.**
|
|
|
|
```bash
|
|
pnpm --filter openhuman-app tauri:ensure # vendored CEF-aware tauri-cli
|
|
pnpm --filter openhuman-app tauri:build:ui # exports CEF_PATH + builds the .app
|
|
```
|
|
|
|
`tauri:build:ui` exports `CEF_PATH=~/Library/Caches/tauri-cef` before
|
|
running `cargo tauri build` — the bundler needs this to copy
|
|
`Chromium Embedded Framework.framework` into `Contents/Frameworks/`.
|
|
A bare `pnpm tauri build` skips that step and the resulting binary
|
|
panics in `cef::library_loader::LibraryLoader::new`.
|
|
|
|
On macOS the artifact lands in
|
|
`app/src-tauri/target/release/bundle/macos/OpenHuman.app`.
|
|
|
|
3. **Run the packaged build.**
|
|
|
|
```bash
|
|
open app/src-tauri/target/release/bundle/macos/OpenHuman.app
|
|
# or, with Rust + frontend logs in the terminal:
|
|
./app/src-tauri/target/release/bundle/macos/OpenHuman.app/Contents/MacOS/OpenHuman
|
|
```
|
|
|
|
You should see `[app-update]` lines start to flow ~30 seconds after
|
|
launch (auto-check), or immediately after clicking
|
|
**Settings → About → Check for updates**.
|
|
|
|
4. **Trigger the check** — either wait ~30s for the auto-check, or open
|
|
**Settings → About** → **Check for updates**. The check is silent;
|
|
the prompt appears only once the download has staged.
|
|
|
|
5. **Watch the auto-download flow** (fires automatically — no click needed
|
|
to start the download). Expected log sequence:
|
|
- `[app-update] check requested (current: <old-version>)`
|
|
- `[app-update] update available: <old> -> <new>`
|
|
- `[app-update] download_app_update invoked from frontend`
|
|
- `[app-update] downloading <new-version> (background)`
|
|
- `[app-update] download complete — staging for install`
|
|
- `[app-update] staged <new-version> — awaiting user-initiated install`
|
|
|
|
At this point the bottom-right banner appears with the header
|
|
**"Update ready to install"** and a body line of
|
|
**"Version <new-version> is ready to install."** (or
|
|
**"A new version is ready to install."** as the fallback when the
|
|
manifest didn't supply a version string), followed by **Restart now** /
|
|
**Later** buttons.
|
|
|
|
6. **Click "Restart now"**. Expected log sequence:
|
|
- `[app-update] install_app_update invoked from frontend`
|
|
- `[app-update] installing staged version <new-version>`
|
|
- `[app-update] install complete — relaunching`
|
|
|
|
The app relaunches itself; the new bundle's version (in
|
|
**Settings → About**) should match the published release.
|
|
|
|
7. **Confirm the core sidecar came back up.** `[core]` log lines should
|
|
appear after relaunch and `core_rpc` calls from the UI must succeed.
|
|
|
|
### Troubleshooting
|
|
|
|
- **"signature did not verify"** — the local bundle was built with a
|
|
different signing key than the one whose pubkey is in `tauri.conf.json`.
|
|
Rebuild against the same `TAURI_SIGNING_PRIVATE_KEY` used by the
|
|
release workflow, or temporarily swap the pubkey while testing.
|
|
- **"endpoint did not return a valid JSON manifest"** — the redirect from
|
|
`releases/latest/download/latest.json` resolved to a release that lacks
|
|
the asset. Confirm the latest non-draft release on GitHub has
|
|
`latest.json` attached (job `publish-updater-manifest`).
|
|
- **Updater doesn't fire in dev** — `pnpm tauri dev` sets
|
|
`bundle.createUpdaterArtifacts: false` (see `scripts/prepareTauriConfig.js`),
|
|
so the dev profile never produces a bundle the updater can swap in. Use
|
|
`pnpm tauri build`.
|
|
- **The banner never shows on first launch** — that's expected; the
|
|
initial probe is delayed 30s. To force it, click "Check for updates" in
|
|
the About panel.
|
|
|
|
## Logs
|
|
|
|
- Rust side: `log::info!("[app-update] ...")` / `log::warn!` / `log::error!`
|
|
- Frontend: `console.debug('[app-update] ...')` and friends
|
|
|
|
Both prefixes are stable and grep-friendly per `CLAUDE.md`.
|