-
+
安装程序
.exe
-
+
MSI 安装包
.msi
@@ -736,11 +736,11 @@
Linux
支持主流 Linux 发行版
-
+
通用版
.AppImage
-
+
Debian / Ubuntu
.deb
diff --git a/package.json b/package.json
index 82d651d..6acad32 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "clawpanel",
- "version": "0.4.0",
+ "version": "0.4.1",
"private": true,
"description": "ClawPanel - OpenClaw 可视化管理面板,基于 Tauri v2 的跨平台桌面应用",
"type": "module",
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index 70f1b2b..3e5cb02 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -328,7 +328,7 @@ dependencies = [
[[package]]
name = "clawpanel"
-version = "0.2.1"
+version = "0.4.1"
dependencies = [
"base64 0.22.1",
"chrono",
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index da55ab6..8927131 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clawpanel"
-version = "0.2.1"
+version = "0.4.1"
edition = "2021"
description = "ClawPanel - OpenClaw 可视化管理面板"
authors = ["qingchencloud"]
diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs
index e272420..02da0c9 100644
--- a/src-tauri/src/commands/config.rs
+++ b/src-tauri/src/commands/config.rs
@@ -39,6 +39,7 @@ fn npm_command() -> Command {
{
let mut cmd = Command::new("npm");
cmd.args(["--registry", ®istry]);
+ cmd.env("PATH", super::enhanced_path());
cmd
}
}
@@ -635,6 +636,8 @@ pub fn check_node() -> Result
{
let mut result = serde_json::Map::new();
let mut cmd = Command::new("node");
cmd.arg("--version");
+ #[cfg(not(target_os = "windows"))]
+ cmd.env("PATH", super::enhanced_path());
#[cfg(target_os = "windows")]
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
match cmd.output() {
diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs
index f17e8f5..35d0b3a 100644
--- a/src-tauri/src/commands/mod.rs
+++ b/src-tauri/src/commands/mod.rs
@@ -13,3 +13,25 @@ pub mod service;
pub fn openclaw_dir() -> PathBuf {
dirs::home_dir().unwrap_or_default().join(".openclaw")
}
+
+/// macOS/Linux 上 Tauri 从 Finder 启动时 PATH 很短(只有 /usr/bin:/bin:/usr/sbin:/sbin),
+/// 需要补充 Node.js / npm 常见安装路径,否则 check_node / npm_command 找不到命令
+#[cfg(not(target_os = "windows"))]
+pub fn enhanced_path() -> String {
+ let current = std::env::var("PATH").unwrap_or_default();
+ let home = dirs::home_dir().unwrap_or_default();
+ let extra: Vec = vec![
+ "/usr/local/bin".into(),
+ "/opt/homebrew/bin".into(),
+ format!("{}/.nvm/current/bin", home.display()),
+ format!("{}/.volta/bin", home.display()),
+ format!("{}/.nodenv/shims", home.display()),
+ format!("{}/.fnm/current/bin", home.display()),
+ format!("{}/n/bin", home.display()),
+ ];
+ let mut parts: Vec<&str> = extra.iter().map(|s| s.as_str()).collect();
+ if !current.is_empty() {
+ parts.push(¤t);
+ }
+ parts.join(":")
+}
diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs
index 09e01de..6a53c8d 100644
--- a/src-tauri/src/utils.rs
+++ b/src-tauri/src/utils.rs
@@ -15,7 +15,9 @@ pub fn openclaw_command() -> std::process::Command {
}
#[cfg(not(target_os = "windows"))]
{
- std::process::Command::new("openclaw")
+ let mut cmd = std::process::Command::new("openclaw");
+ cmd.env("PATH", crate::commands::enhanced_path());
+ cmd
}
}
@@ -31,6 +33,8 @@ pub fn openclaw_command_async() -> tokio::process::Command {
}
#[cfg(not(target_os = "windows"))]
{
- tokio::process::Command::new("openclaw")
+ let mut cmd = tokio::process::Command::new("openclaw");
+ cmd.env("PATH", crate::commands::enhanced_path());
+ cmd
}
}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 234e8d0..782f7fa 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json",
"productName": "ClawPanel",
- "version": "0.4.0",
+ "version": "0.4.1",
"identifier": "ai.openclaw.clawpanel",
"build": {
"frontendDist": "../dist",
diff --git a/src/lib/error-diagnosis.js b/src/lib/error-diagnosis.js
new file mode 100644
index 0000000..6464b66
--- /dev/null
+++ b/src/lib/error-diagnosis.js
@@ -0,0 +1,67 @@
+/**
+ * npm install / upgrade 常见错误诊断
+ * 解析 npm 错误信息,返回用户友好的提示和修复建议
+ */
+
+/**
+ * @param {string} errStr - npm 错误输出
+ * @returns {{ title: string, hint?: string, command?: string }}
+ */
+export function diagnoseInstallError(errStr) {
+ const s = errStr.toLowerCase()
+
+ // git 未安装(exit 128 + access rights)
+ if (s.includes('code 128') || s.includes('exit 128') || s.includes('access rights')) {
+ return {
+ title: '安装失败 — 需要安装 Git',
+ hint: '部分依赖需要通过 Git 下载。请先安装 Git 后重试。',
+ command: '下载 Git: https://git-scm.com/downloads',
+ }
+ }
+
+ // ENOENT(文件找不到)
+ if (s.includes('enoent') || s.includes('-4058') || s.includes('code -4058')) {
+ return {
+ title: '安装失败 — 文件访问错误',
+ hint: '尝试以管理员身份运行 ClawPanel,或在终端手动安装:',
+ command: 'npm install -g @qingchencloud/openclaw-zh --registry https://registry.npmmirror.com',
+ }
+ }
+
+ // 权限不足(EACCES / EPERM)
+ if (s.includes('eacces') || s.includes('eperm') || s.includes('permission denied')) {
+ const isMac = navigator.platform?.includes('Mac') || navigator.userAgent?.includes('Mac')
+ return {
+ title: '安装失败 — 权限不足',
+ hint: isMac ? '请在终端使用 sudo 安装:' : '请以管理员身份打开终端安装:',
+ command: isMac
+ ? 'sudo npm install -g @qingchencloud/openclaw-zh --registry https://registry.npmmirror.com'
+ : 'npm install -g @qingchencloud/openclaw-zh --registry https://registry.npmmirror.com',
+ }
+ }
+
+ // 网络错误
+ if (s.includes('etimedout') || s.includes('econnrefused') || s.includes('enotfound')
+ || s.includes('network') || s.includes('fetch failed') || s.includes('socket hang up')) {
+ return {
+ title: '安装失败 — 网络连接错误',
+ hint: '请检查网络连接,或尝试切换 npm 镜像源后重试。',
+ }
+ }
+
+ // npm 缓存损坏
+ if (s.includes('integrity') || s.includes('sha512') || s.includes('cache')) {
+ return {
+ title: '安装失败 — npm 缓存异常',
+ hint: '尝试清理 npm 缓存后重试:',
+ command: 'npm cache clean --force',
+ }
+ }
+
+ // 通用 fallback
+ return {
+ title: '安装失败',
+ hint: '请在终端手动尝试安装,查看完整错误信息:',
+ command: 'npm install -g @qingchencloud/openclaw-zh --registry https://registry.npmmirror.com',
+ }
+}
diff --git a/src/pages/services.js b/src/pages/services.js
index 6bb56c7..c4a1f65 100644
--- a/src/pages/services.js
+++ b/src/pages/services.js
@@ -6,6 +6,7 @@ import { api } from '../lib/tauri-api.js'
import { toast } from '../components/toast.js'
import { showConfirm, showUpgradeModal } from '../components/modal.js'
import { isMacPlatform, setUpgrading, setUserStopped, resetAutoRestart } from '../lib/app-state.js'
+import { diagnoseInstallError } from '../lib/error-diagnosis.js'
// HTML 转义,防止 XSS
function escapeHtml(str) {
@@ -421,8 +422,13 @@ async function doUpgradeWithModal(source, page) {
modal.setDone(typeof msg === 'string' ? msg : (msg?.message || '升级完成'))
await loadVersion(page)
} catch (e) {
- modal.appendLog(String(e))
- modal.setError('升级失败')
+ const errStr = String(e)
+ modal.appendLog(errStr)
+ const diagnosis = diagnoseInstallError(errStr)
+ modal.setError(diagnosis.title)
+ if (diagnosis.hint) modal.appendLog('')
+ if (diagnosis.hint) modal.appendLog('ℹ️ ' + diagnosis.hint)
+ if (diagnosis.command) modal.appendLog('💻 ' + diagnosis.command)
} finally {
setUpgrading(false)
unlistenLog?.()
diff --git a/src/pages/setup.js b/src/pages/setup.js
index 1b2b3b1..4983759 100644
--- a/src/pages/setup.js
+++ b/src/pages/setup.js
@@ -5,7 +5,8 @@
import { api } from '../lib/tauri-api.js'
import { showUpgradeModal } from '../components/modal.js'
import { toast } from '../components/toast.js'
-import { setUpgrading } from '../lib/app-state.js'
+import { setUpgrading, isMacPlatform } from '../lib/app-state.js'
+import { diagnoseInstallError } from '../lib/error-diagnosis.js'
export async function render() {
const page = document.createElement('div')
@@ -84,7 +85,12 @@ function renderSteps(page, { node, cliOk, config }) {
OpenClaw 基于 Node.js 运行,请先安装。
下载 Node.js
- 安装后点击「重新检测」`
+ 安装后点击「重新检测」
+ ${isMacPlatform() ? `
+
+ 已经装了但检测不到? macOS 上从 Finder 启动可能找不到 Node.js。试试关掉 ClawPanel 后从终端启动:
+ open /Applications/ClawPanel.app
+
` : ''}`
}
`
@@ -211,8 +217,13 @@ function bindEvents(page, nodeOk) {
toast('OpenClaw 安装成功', 'success')
setTimeout(() => window.location.reload(), 1500)
} catch (e) {
- modal.appendLog(String(e))
- modal.setError('安装失败')
+ const errStr = String(e)
+ modal.appendLog(errStr)
+ const diagnosis = diagnoseInstallError(errStr)
+ modal.setError(diagnosis.title)
+ if (diagnosis.hint) modal.appendLog('')
+ if (diagnosis.hint) modal.appendLog('ℹ️ ' + diagnosis.hint)
+ if (diagnosis.command) modal.appendLog('💻 ' + diagnosis.command)
} finally {
setUpgrading(false)
unlistenLog?.()
@@ -221,4 +232,3 @@ function bindEvents(page, nodeOk) {
})
}
-