diff --git a/agents.md b/agents.md
index 985154a..2393475 100644
--- a/agents.md
+++ b/agents.md
@@ -59,7 +59,28 @@
- `docs/plans/2026-02-15-clawpal-mvp-design.md`(设计)
- `docs/plans/2026-02-15-clawpal-mvp-implementation-plan.md`(计划)
-## 7. 安全与风险
+## 7. 部署
+
+### 官网(clawpal.zhixian.io)
+
+使用 Cloudflare Pages Direct Upload 部署,源目录为 `docs/site/`。
+
+部署命令:
+```bash
+npx wrangler pages deploy docs/site --project-name clawpal
+```
+
+项目域名:`clawpal.zhixian.io`(也可通过 `clawpal.pages.dev` 访问)。
+
+### 桌面应用 Release
+
+通过 GitHub Actions 自动构建,push tag 触发(如 `v0.1.1`):
+- CI workflow: `.github/workflows/release.yml`
+- 构建产物:macOS (ARM/x64 .dmg)、Windows (.exe/.msi)、Linux (.deb/.AppImage)
+- 需要 `TAURI_SIGNING_PRIVATE_KEY` 等 secrets,本地无法打 release bundle
+- 发布新版本流程:更新 `package.json` + `src-tauri/Cargo.toml` 版本号 → commit → `git tag vX.Y.Z` → push
+
+## 8. 安全与风险
- 禁止提交明文密钥/配置路径泄露
- 避免大文件和自动生成产物直接提交
diff --git a/docs/site/index.html b/docs/site/index.html
index a060d8d..5ae3724 100644
--- a/docs/site/index.html
+++ b/docs/site/index.html
@@ -423,6 +423,12 @@
+
+
+
+
+
+
@@ -449,14 +455,16 @@
Manage AI agents, models, and configs with a visual interface.
Stop editing JSON by hand.
diff --git a/src/App.tsx b/src/App.tsx
index d9b87fe..dc3cd46 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,6 @@
import { useCallback, useEffect, useRef, useState } from "react";
+import { check } from "@tauri-apps/plugin-updater";
+import { relaunch } from "@tauri-apps/plugin-process";
import { Home } from "./pages/Home";
import { Recipes } from "./pages/Recipes";
import { Cook } from "./pages/Cook";
@@ -80,6 +82,30 @@ export function App() {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, []);
+ // App self-update (manual check from sidebar)
+ const [checkingAppUpdate, setCheckingAppUpdate] = useState(false);
+
+ const handleCheckForUpdates = useCallback(async () => {
+ setCheckingAppUpdate(true);
+ try {
+ const update = await check();
+ if (update) {
+ const confirmed = window.confirm(`ClawPal v${update.version} is available. Update and restart now?`);
+ if (confirmed) {
+ await update.downloadAndInstall();
+ await relaunch();
+ }
+ } else {
+ showToast("You're on the latest version");
+ }
+ } catch (e) {
+ console.error("Update check failed:", e);
+ showToast(`Update check failed: ${e}`, "error");
+ } finally {
+ setCheckingAppUpdate(false);
+ }
+ }, [showToast]);
+
const handleInstanceSelect = useCallback((id: string) => {
setActiveInstance(id);
if (id !== "local") {
@@ -285,6 +311,14 @@ export function App() {
>
Settings
+
{/* Dirty config action bar */}
diff --git a/src/components/UpgradeDialog.tsx b/src/components/UpgradeDialog.tsx
index 91915f9..770eafb 100644
--- a/src/components/UpgradeDialog.tsx
+++ b/src/components/UpgradeDialog.tsx
@@ -11,6 +11,11 @@ import {
type Step = "confirm" | "backup" | "upgrading" | "done";
+/** Strip ANSI escape codes from terminal output */
+function stripAnsi(str: string): string {
+ return str.replace(/\x1b\[[0-9;]*m/g, "").replace(/\x1b\[[0-9;]*[A-Za-z]/g, "");
+}
+
export function UpgradeDialog({
open,
onOpenChange,
@@ -31,6 +36,7 @@ export function UpgradeDialog({
const [output, setOutput] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
+ const [showLog, setShowLog] = useState(false);
const reset = () => {
setStep("confirm");
@@ -38,6 +44,7 @@ export function UpgradeDialog({
setOutput("");
setError("");
setLoading(false);
+ setShowLog(false);
};
const handleClose = (open: boolean) => {
@@ -77,11 +84,12 @@ export function UpgradeDialog({
const result = isRemote
? await api.remoteRunOpenclawUpgrade(instanceId)
: await api.runOpenclawUpgrade();
- setOutput(result);
+ setOutput(stripAnsi(result));
setStep("done");
} catch (e) {
- setOutput(String(e));
+ setOutput(stripAnsi(String(e)));
setError("Upgrade failed. See output below.");
+ setShowLog(true);
} finally {
setLoading(false);
}
@@ -163,9 +171,19 @@ export function UpgradeDialog({
Upgrade completed successfully.
{output && (
-
- {output}
-
+ <>
+
+ {showLog && (
+
+ {output}
+
+ )}
+ >
)}
)}
diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx
index 5972999..24bae84 100644
--- a/src/pages/Home.tsx
+++ b/src/pages/Home.tsx
@@ -201,9 +201,8 @@ export function Home({
return () => clearTimeout(timer);
}, [isRemote, isConnected, instanceId]);
- // ClawPal app self-update check (local only)
+ // ClawPal app self-update check
useEffect(() => {
- if (isRemote) return;
setAppUpdateChecking(true);
check()
.then((update) => {
@@ -213,10 +212,9 @@ export function Home({
})
.catch((e) => console.error("Failed to check app update:", e))
.finally(() => setAppUpdateChecking(false));
- }, [isRemote]);
+ }, []);
const handleAppUpdate = useCallback(async () => {
- if (isRemote) return;
setAppUpdating(true);
setAppUpdateProgress(0);
try {
@@ -242,7 +240,7 @@ export function Home({
setAppUpdating(false);
setAppUpdateProgress(null);
}
- }, [isRemote]);
+ }, []);
const handleDeleteAgent = (agentId: string) => {
if (isRemote && !isConnected) return;
@@ -303,8 +301,8 @@ export function Home({
)}
- {/* ClawPal app self-update (local only) */}
- {!isRemote && (appUpdateChecking || appUpdate) && (
+ {/* ClawPal app self-update */}
+ {(appUpdateChecking || appUpdate) && (
<>