diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 4ca902d..e200028 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -25,6 +25,7 @@ "@tauri-apps/plugin-dialog": "^2.0.0", "@tauri-apps/plugin-fs": "^2.0.0", "@tauri-apps/plugin-opener": "^2.0.0", + "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-shell": "^2.0.0", "@tauri-apps/plugin-updater": "^2.0.0", "react": "^18.3.0", diff --git a/apps/desktop/src-tauri/Cargo.lock b/apps/desktop/src-tauri/Cargo.lock index 586f252..ef83151 100644 --- a/apps/desktop/src-tauri/Cargo.lock +++ b/apps/desktop/src-tauri/Cargo.lock @@ -682,6 +682,7 @@ dependencies = [ "tauri-plugin-dialog", "tauri-plugin-fs", "tauri-plugin-opener", + "tauri-plugin-process", "tauri-plugin-shell", "tauri-plugin-updater", "thiserror 1.0.69", @@ -3894,6 +3895,16 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-process" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" +dependencies = [ + "tauri", + "tauri-plugin", +] + [[package]] name = "tauri-plugin-shell" version = "2.3.5" diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index bd42e2a..0826990 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -20,6 +20,7 @@ tauri-plugin-fs = "2" tauri-plugin-opener = "2" tauri-plugin-shell = "2" tauri-plugin-updater = "2" +tauri-plugin-process = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "1" diff --git a/apps/desktop/src-tauri/capabilities/default.json b/apps/desktop/src-tauri/capabilities/default.json index ae1f743..b23265a 100644 --- a/apps/desktop/src-tauri/capabilities/default.json +++ b/apps/desktop/src-tauri/capabilities/default.json @@ -14,6 +14,8 @@ "fs:default", "opener:default", "shell:default", - "updater:default" + "updater:default", + "process:default", + "process:allow-restart" ] } diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index 107a627..c8f0e62 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -29,6 +29,7 @@ pub fn run() { .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_updater::Builder::new().build()) + .plugin(tauri_plugin_process::init()) .invoke_handler(tauri::generate_handler![ get_app_info, read_credentials, diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index 08ff4b5..6f2fbc7 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -55,12 +55,12 @@ }, "plugins": { "updater": { - "active": false, + "active": true, "endpoints": [ "https://github.com/oratis/deepcode/releases/latest/download/latest.json" ], "dialog": false, - "pubkey": "" + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDk0MDMzRUQ0RkVFNUREODUKUldTRjNlWCsxRDREbEttVHEwUEplK1FKbnRCakpGb3dVWTYveFdxSmxwK2ZROWFZcW1kYzZMSGcK" } } } diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 232ea1c..924d06c 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react'; import { Nav, type ScreenName } from './components/Nav.js'; import { UpdateBanner } from './components/UpdateBanner.js'; +import { onUpdateDownloaded, startUpdaterPolling } from './lib/updater.js'; import { AboutScreen } from './screens/About.js'; import { ChatScreen } from './screens/Chat.js'; import { MCPManagerScreen } from './screens/MCPManager.js'; @@ -26,8 +27,15 @@ export function App(): JSX.Element { useEffect(() => { void window.deepcode.version().then(setVersion); void window.deepcode.creds.load().then((c) => setHasKey(c.hasKey)); - const off = window.deepcode.onUpdateDownloaded((info) => setUpdate(info)); - return () => off(); + const offShim = window.deepcode.onUpdateDownloaded((info) => setUpdate(info)); + // Also subscribe to the real Tauri updater (so even if the shim + // surface drifts, the banner still fires). + const offReal = onUpdateDownloaded((info) => setUpdate(info)); + startUpdaterPolling(); + return () => { + offShim(); + offReal(); + }; }, []); if (hasKey === null) { diff --git a/apps/desktop/src/components/UpdateBanner.tsx b/apps/desktop/src/components/UpdateBanner.tsx index bf6612c..abc7668 100644 --- a/apps/desktop/src/components/UpdateBanner.tsx +++ b/apps/desktop/src/components/UpdateBanner.tsx @@ -1,9 +1,9 @@ -// "Relaunch to update vX.Y.Z" banner — fires when electron-updater has -// downloaded a new release. Click → app.relaunch() (host wires this in M6-rest). +// "Relaunch to update vX.Y.Z" banner — fires when tauri-plugin-updater has +// downloaded a new release. Clicking Relaunch calls tauri-plugin-process.relaunch(). // Spec: docs/VISUAL_DESIGN.html screen #11 -// Milestone: M6 skeleton import { useState } from 'react'; +import { relaunchNow } from '../lib/updater.js'; import type { UpdateInfo } from '../types/global.js'; interface BannerProps { @@ -12,22 +12,29 @@ interface BannerProps { export function UpdateBanner({ info }: BannerProps): JSX.Element | null { const [dismissed, setDismissed] = useState(false); + const [relaunching, setRelaunching] = useState(false); if (dismissed) return null; + + async function handleRelaunch(): Promise { + setRelaunching(true); + try { + await relaunchNow(); + } catch (err) { + console.error('relaunch failed:', err); + setRelaunching(false); + } + } + return (
- - DeepCode v{info.version} is ready to install. Relaunch to update. - + DeepCode v{info.version} is ready to install. Relaunch to update.