diff --git a/sundynix-desktop/frontend/src/components/UpdateBanner.tsx b/sundynix-desktop/frontend/src/components/UpdateBanner.tsx
new file mode 100644
index 0000000..633c00b
--- /dev/null
+++ b/sundynix-desktop/frontend/src/components/UpdateBanner.tsx
@@ -0,0 +1,38 @@
+import { useEffect, useState } from "react";
+import { Download, X } from "lucide-react";
+import { checkUpdate, openExternal, type ReleaseInfo } from "../lib/version";
+
+// 启动时查 GitHub Releases,有新版则在顶部显示一条可关闭的横幅,点击去下载页。
+export function UpdateBanner() {
+ const [rel, setRel] = useState
(null);
+ const [dismissed, setDismissed] = useState(false);
+
+ useEffect(() => {
+ let alive = true;
+ void checkUpdate().then((r) => {
+ if (alive) setRel(r);
+ });
+ return () => {
+ alive = false;
+ };
+ }, []);
+
+ if (!rel || dismissed) return null;
+ return (
+
+
+
+ 新版本 v{rel.version} 可用
+
+
+
+
+ );
+}
diff --git a/sundynix-desktop/frontend/src/lib/version.ts b/sundynix-desktop/frontend/src/lib/version.ts
new file mode 100644
index 0000000..34d4348
--- /dev/null
+++ b/sundynix-desktop/frontend/src/lib/version.ts
@@ -0,0 +1,50 @@
+// 桌面端版本与"检查更新"——查 GitHub Releases 最新版,比当前版本新则提示下载。
+// 发版流程:bump 此处 APP_VERSION(= package.json version)→ 打 tag vX.Y.Z → release workflow 自动构建+发布。
+
+export const APP_VERSION = "0.1.0"; // 当前桌面端版本(与 git tag 去掉 v 前缀对齐)
+
+const REPO = "blizzardzhang/sundynix-agentix";
+
+export interface ReleaseInfo {
+ version: string; // 最新版本号(不含 v)
+ url: string; // release 页面(用户在此选 mac/win 安装包)
+ notes: string; // 更新日志
+}
+
+// checkUpdate 查 GitHub 最新 release;有比当前更新的版本则返回信息,否则 null(含出错/限流时静默)。
+export async function checkUpdate(): Promise {
+ try {
+ const res = await fetch(`https://api.github.com/repos/${REPO}/releases/latest`, {
+ headers: { Accept: "application/vnd.github+json" },
+ });
+ if (!res.ok) return null; // 404=还没发过 release / 403=限流 → 静默
+ const d = (await res.json()) as { tag_name?: string; html_url?: string; body?: string };
+ const latest = String(d.tag_name ?? "").replace(/^v/, "");
+ if (!latest || !isNewer(latest, APP_VERSION)) return null;
+ return { version: latest, url: d.html_url ?? `https://github.com/${REPO}/releases/latest`, notes: d.body ?? "" };
+ } catch {
+ return null; // 离线等 → 不打扰
+ }
+}
+
+// openExternal 在系统浏览器打开链接(Wails 用 runtime.BrowserOpenURL,浏览器模式回退 window.open)。
+export function openExternal(url: string): void {
+ const w = window as unknown as { runtime?: { BrowserOpenURL?: (u: string) => void } };
+ if (w.runtime?.BrowserOpenURL) {
+ w.runtime.BrowserOpenURL(url);
+ } else {
+ window.open(url, "_blank");
+ }
+}
+
+// isNewer 语义化版本比较:a 是否比 b 新(按 major.minor.patch)。
+function isNewer(a: string, b: string): boolean {
+ const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
+ const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
+ for (let i = 0; i < 3; i++) {
+ const x = pa[i] ?? 0;
+ const y = pb[i] ?? 0;
+ if (x !== y) return x > y;
+ }
+ return false;
+}