diff --git a/AGENTS.md b/AGENTS.md index 61e2f12..d97a8f6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,10 @@ bun). without updating README's privacy section. - Follow the Pickforge design system: ember `#FF7A1A` accent, Geist/Geist Mono, tokens over raw values. +- Async waits built on event listeners must re-check the awaited condition + right after the listener registers (the state can change in the gap) and + re-verify every condition on each event instead of trusting the event + payload alone — pickgauge#70's eligibility gate shipped both mistakes. ## Releasing diff --git a/bun.lock b/bun.lock index 71e63f8..c14e4ac 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,8 @@ "name": "pickgauge", "dependencies": { "@pickforge/brand": "0.2.1", + "@pickforge/flags": "^0.4.0", + "@pickforge/tauri-updater": "^0.12.0", "@tauri-apps/api": "^2.9.0", "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-updater": "^2.10.1", @@ -138,8 +140,12 @@ "@pickforge/brand": ["@pickforge/brand@0.2.1", "", { "dependencies": { "@fontsource/geist-mono": "^5.2.8", "@fontsource/geist-sans": "^5.2.5" } }, "sha512-8VASbOUFJKUkb2zVvqto7aPynyICISCMzrh8jMRcvovtKNpzbLMrZ2xS7eeIPQyVs5NRbJ0457Vb0HQC+sIhQQ=="], + "@pickforge/flags": ["@pickforge/flags@0.4.0", "", {}, "sha512-Z0nlxk3/0HXA7em8+ZQ+BV3jfF2U0E8uCdDPdyW2WdbMHe2pF7rgukTAIAyAZexEB3c7SATEYCbrnNsEd9V9Nw=="], + "@pickforge/tauri-release": ["@pickforge/tauri-release@0.3.0", "", { "bin": { "pickforge-tauri-release": "dist/cli.js" } }, "sha512-LTpsp6+zB9WU9eflvWH8tRFGNCJmiQW7ULYNnffQYCgfZ3fSqF33yDBKW38WdXdlyDBEcYpFnYjkw0+YnLob8Q=="], + "@pickforge/tauri-updater": ["@pickforge/tauri-updater@0.12.0", "", {}, "sha512-3q5SgSAJBV/ctpxFGKUvKOHZ6uIszhgO3BPajgA+BrffulARzrW9Uv4fXRy4TFWoV83LNlSy9GVnCi6dYWnJBw=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.62.2", "", { "os": "android", "cpu": "arm" }, "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.62.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw=="], diff --git a/docs/release-evidence/update-dialog-available-1000x700.png b/docs/release-evidence/update-dialog-available-1000x700.png new file mode 100644 index 0000000..fa338ea Binary files /dev/null and b/docs/release-evidence/update-dialog-available-1000x700.png differ diff --git a/docs/release-evidence/update-dialog-available-820x580.png b/docs/release-evidence/update-dialog-available-820x580.png new file mode 100644 index 0000000..fa43f4e Binary files /dev/null and b/docs/release-evidence/update-dialog-available-820x580.png differ diff --git a/docs/release-evidence/update-dialog-downloading-1000x700.png b/docs/release-evidence/update-dialog-downloading-1000x700.png new file mode 100644 index 0000000..46366b0 Binary files /dev/null and b/docs/release-evidence/update-dialog-downloading-1000x700.png differ diff --git a/docs/release-evidence/update-dialog-downloading-820x580.png b/docs/release-evidence/update-dialog-downloading-820x580.png new file mode 100644 index 0000000..a6193ca Binary files /dev/null and b/docs/release-evidence/update-dialog-downloading-820x580.png differ diff --git a/docs/releases/UNRELEASED.md b/docs/releases/UNRELEASED.md index 700a3a8..1fb6d62 100644 --- a/docs/releases/UNRELEASED.md +++ b/docs/releases/UNRELEASED.md @@ -54,6 +54,17 @@ reset this file. - Added blocking CI gates for Rust and frontend complexity, coverage, secrets, and high/critical dependency advisories, with one required aggregate status. +- Added the shared `@pickforge/tauri-updater` dialog behind the `studioUpdateDialog` + flag (default off; `@pickforge/flags`), part of + pickforge/pickforge-platform#36. While off, the legacy `window.confirm` + updater in `src/lib/updater.ts` is untouched. When on, `src/lib/updateDialog.ts` + mounts the shared controller only on the visible main window: a Tauri + window-label check excludes the floating capsule outright, and a hidden + main window (tray/login-start) defers the check until its first focus + event, mirroring the pre-existing `checkForUpdatesWhenVisible` deferral. + One controller per process enforces a single check. A dev-only fixture + (`?updateDialogFixture=available|downloading`, tree-shaken from production + builds) stands in for a visual baseline since PickGauge has no VRT harness. - Headless `usage --json` refreshes independent providers concurrently (join-all, emit in fixed service order) so an offline credentialed install pays ~max per-provider timeout instead of the sequential sum. @@ -154,8 +165,18 @@ reset this file. candidate by several days. The validated candidate remains installed with a checksum-verified rollback backup. +- pickforge/pickforge-platform#36 (PR 5, PickGauge integration): `bun run + lint`, `bun run check`, `bun run test` (85 vitest tests including + `flags.test.ts` and `updateDialog.test.ts`, covering flag-off default, + eligibility for an already-visible main window, capsule exclusion by + window label, and hidden-main-window deferral until focus), and `bun run + test:coverage` (ratchet holds). No Rust touched. + ### Not yet tested +- pickforge/pickforge-platform#36 (PR 5): owner-gated packaged-update smoke + (old build to staged newer build) and design-lead visual acceptance from + the dev-only fixture; both deferred to a later PR per the issue's PR plan. - Issue #49: real KDE Wayland/XWayland Alt+Tab, taskbar, and pager behavior for the float capsule — deferred to Elberte-PC, a live KDE session with `qdbus`/`kwriteconfig6` available. diff --git a/package.json b/package.json index 5124a26..ef1e8d3 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ }, "dependencies": { "@pickforge/brand": "0.2.1", + "@pickforge/flags": "^0.4.0", + "@pickforge/tauri-updater": "^0.12.0", "@tauri-apps/api": "^2.9.0", "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-updater": "^2.10.1", diff --git a/src/App.svelte b/src/App.svelte index 5c46482..8844cbe 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -18,6 +18,9 @@ EVENT_SNAPSHOTS, } from "./lib/api"; import { serviceLabels, settingsSaveDisplayState } from "./lib/display"; + import { flagEnabled } from "./lib/flags"; + import { mountUpdateDialog, type UpdateDialogHost } from "./lib/updateDialog"; + import { shouldMountSharedUpdateDialog } from "./lib/updateRouting"; import { browserPreviewSnapshots, browserPreviewStateFromSearch, @@ -47,6 +50,8 @@ let statusMessage = $state(null); let statusIsError = $state(false); let statusTimer: ReturnType | null = null; + let updateDialogEl: HTMLElement | undefined = $state(); + const showUpdateDialog = shouldMountSharedUpdateDialog(flagEnabled("studioUpdateDialog")); const navItems: { id: View; label: string; icon: typeof Gauge }[] = [ { id: "dashboard", label: "Dashboard", icon: Gauge }, @@ -102,6 +107,10 @@ let cancelled = false; const cleanups: (() => void)[] = []; + if (showUpdateDialog && updateDialogEl) { + mountUpdateDialog(updateDialogEl as unknown as UpdateDialogHost); + } + if (!desktopApiAvailable()) { snapshots = browserPreviewSnapshots(browserPreviewStateFromSearch(window.location.search)); loading = false; @@ -288,6 +297,10 @@ {/if} +{#if showUpdateDialog} + +{/if} +