diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index ed32ac2c..463b0fb9 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -179,7 +179,9 @@ The `latest.json` manifest supports optional policy fields: On launch, Basebuild shows a startup splash that checks for updates before the main shell becomes interactive. The splash has these states: -- **Checking** — Shows current version and update-check progress. +- **Checking** — Shows current version and update-check progress. Runs on + Windows, macOS, and Linux. After 8 seconds the app opens anyway and the + check finishes in the background. - **Optional update** — Shows target version, summary, and `Upgrade` / `Skip update for now` buttons. The skip is version-scoped: the user is not prompted again for the same target version, but will be prompted for @@ -187,7 +189,9 @@ the main shell becomes interactive. The splash has these states: - **Mandatory update** — Hides the skip button and auto-starts the update when the running version is below `minimumSupportedVersion`. - **Progress** — Shows download/install progress bar and step text. -- **Error** — Shows actionable diagnostics with retry and "Continue anyway". +- **Check failed** — never blocks startup: the app opens and the taskbar + update control shows the failure with a retry. The backend also logs it to + stderr with an `[updater]` prefix. The existing in-app update UI (taskbar button + Settings → Updates tab) remains functional after startup for manual checks and installs. diff --git a/docs/agents/desktop-shell.md b/docs/agents/desktop-shell.md index cc649355..0c73689b 100644 --- a/docs/agents/desktop-shell.md +++ b/docs/agents/desktop-shell.md @@ -297,7 +297,8 @@ Before the main shell renders, Basebuild shows a startup update splash that checks for updates. The splash displays the current build version and transitions through these states: -- **Checking** — update check in progress. +- **Checking** — update check in progress (every platform). After 8 seconds + the shell opens and the check continues in the background. - **Optional update** — target version, summary, and `Upgrade` / `Skip update for now` buttons. Skip is version-scoped: the same target version is not prompted again, but a newer release will prompt. @@ -306,7 +307,8 @@ and transitions through these states: update auto-starts. - **Progress** — download progress bar and step text (downloading, installing, restarting). -- **Error** — actionable diagnostics with retry and "Continue anyway". +- **Check failed** — the shell opens immediately; the taskbar update control + surfaces the failure and its retry. The splash does not replace the in-app update controls. The taskbar update button and Settings → Updates tab remain functional after startup. diff --git a/src-tauri/src/commands/updater.rs b/src-tauri/src/commands/updater.rs index 106a4d95..8a8ec671 100644 --- a/src-tauri/src/commands/updater.rs +++ b/src-tauri/src/commands/updater.rs @@ -288,14 +288,19 @@ pub async fn check_for_updates(app: AppHandle) -> Result { skipped: false, }); } - let updater = app - .updater() - .map_err(|e| format!("Failed to get updater: {e}"))?; + let updater = app.updater().map_err(|e| { + let message = format!("Failed to get updater: {e}"); + eprintln!("[updater] {message}"); + message + })?; let update = updater.check().await.map_err(|e| { let status = UpdateChannelStatus::from_plugin_error(&e); let explanation = status.explanation(); - format!("Failed to check for updates: {e} | channel_status={status:?} | {explanation}") + let message = + format!("Failed to check for updates: {e} | channel_status={status:?} | {explanation}"); + eprintln!("[updater] {message}"); + message })?; match update { diff --git a/src/components/layout/StartupSplash.tsx b/src/components/layout/StartupSplash.tsx index afb3bc2f..acaa995a 100644 --- a/src/components/layout/StartupSplash.tsx +++ b/src/components/layout/StartupSplash.tsx @@ -2,7 +2,6 @@ import { useEffect, useState } from "react"; import { AlertTriangle, Download, RefreshCw, X } from "lucide-react"; import type { UpdaterState } from "../../state/updater"; import { appVersion } from "../../lib/app"; -import { CopyButton } from "./CopyButton"; import { t } from "../../i18n"; type StartupSplashProps = { @@ -15,7 +14,6 @@ type SplashPhase = | "checking" | "mandatory" | "progress" - | "error" | "ready"; const SPLASH_CHECK_TIMEOUT_MS = 8_000; @@ -65,9 +63,11 @@ export function StartupSplash({ updates, onComplete }: StartupSplashProps) { return; } - // Error state. + // A failed check never blocks startup: enter the app; the taskbar update + // control shows the failure and offers a retry. if (status === "error") { - setPhase("error"); + setPhase("ready"); + onComplete(); return; } @@ -104,11 +104,6 @@ export function StartupSplash({ updates, onComplete }: StartupSplashProps) { onComplete(); }; - const handleRetry = () => { - void updates.checkNow(); - setAutoStarted(false); - }; - // Progress percentage from backend events. const progressPct = (() => { const p = updates.progress; @@ -191,49 +186,6 @@ export function StartupSplash({ updates, onComplete }: StartupSplashProps) { )} - {phase === "error" && ( -
-
- {t("startupSplash.updateCheckFailed")} -
-

- {updates.info?.channelExplanation ?? updates.error ?? t("startupSplash.couldNotCheckForUpdates")} -

- {updates.info?.rawError ? ( -
- {t("startupSplash.rawError")} -
{updates.info.rawError}
-
- ) : null} - {updates.info?.rawError ? ( -
- -
- ) : null} -
- - -
-
- )} - {phase === "checking" && (