mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-06-25 17:54:10 +08:00
fix: macOS PATH detection + npm install error diagnosis (v0.4.1)
- Fix macOS Node.js/npm/openclaw detection by adding enhanced_path() with common install locations (/usr/local/bin, /opt/homebrew/bin, ~/.nvm, ~/.volta, etc.) - Add npm install error diagnosis: auto-detect git missing (exit 128), ENOENT, permission denied, network errors, cache corruption - Show macOS-specific hint when Node.js detection fails in setup page - Add shared error-diagnosis.js module used by both setup and services pages - Add troubleshooting section to README.md - Bump version to 0.4.1
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -5,6 +5,18 @@
|
||||
格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
||||
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||
|
||||
## [0.4.1] - 2026-03-06
|
||||
|
||||
### 修复 (Bug Fixes)
|
||||
|
||||
- **macOS Node.js 检测失败** — Tauri 从 Finder 启动时 PATH 不含 `/usr/local/bin`、`/opt/homebrew/bin` 等常见路径,导致 `check_node`、`npm_command`、`openclaw_command` 找不到命令。新增 `enhanced_path()` 补充 nvm/volta/nodenv/fnm/n 等 Node.js 管理器路径
|
||||
- **npm 安装失败无引导** — 安装/升级 OpenClaw 失败时仅显示"安装失败",现在自动诊断错误类型(Git 未安装 / 文件访问 / 权限不足 / 网络错误 / 缓存损坏)并给出具体修复命令
|
||||
|
||||
### 优化 (Improvements)
|
||||
|
||||
- **macOS 检测引导** — 安装引导页 Node.js 检测失败时,macOS 用户会看到"已经装了但检测不到?"提示,引导从终端启动
|
||||
- **错误诊断模块** — 新增 `error-diagnosis.js` 共享模块,安装引导页和服务管理页共用错误诊断逻辑
|
||||
|
||||
## [0.4.0] - 2026-03-05
|
||||
|
||||
### 新增 (Features)
|
||||
|
||||
43
README.md
43
README.md
@@ -257,6 +257,49 @@ npm run tauri build -- --bundles nsis
|
||||
|
||||
产物位于 `src-tauri/target/release/` 目录。
|
||||
|
||||
## 常见问题
|
||||
|
||||
### macOS 提示"已损坏,无法打开"
|
||||
|
||||
没有苹果开发者签名,macOS Gatekeeper 会拦截。终端执行:
|
||||
|
||||
```bash
|
||||
sudo xattr -rd com.apple.quarantine /Applications/ClawPanel.app
|
||||
```
|
||||
|
||||
或前往「系统设置 → 隐私与安全性」点击「仍要打开」。
|
||||
|
||||
### macOS 检测不到 Node.js
|
||||
|
||||
从 Finder/Dock 启动 ClawPanel 时,应用的 PATH 环境变量可能不包含 Node.js 安装路径。
|
||||
|
||||
**v0.4.1 已修复**:自动补充 `/usr/local/bin`、`/opt/homebrew/bin`、`~/.nvm`、`~/.volta` 等常见路径。
|
||||
|
||||
临时解决:从终端启动 ClawPanel:
|
||||
|
||||
```bash
|
||||
open /Applications/ClawPanel.app
|
||||
```
|
||||
|
||||
### Windows 安装 OpenClaw 报 ENOENT (-4058)
|
||||
|
||||
通常是文件权限或 npm 缓存问题:
|
||||
|
||||
1. 以管理员身份运行 ClawPanel
|
||||
2. 或打开 PowerShell(管理员)手动安装:
|
||||
```powershell
|
||||
npm install -g @qingchencloud/openclaw-zh --registry https://registry.npmmirror.com
|
||||
```
|
||||
3. 如果仍报错,清理 npm 缓存:`npm cache clean --force`
|
||||
|
||||
### Windows 安装报 exit 128 (access rights)
|
||||
|
||||
npm 依赖需要 Git,但系统未安装。请先安装 [Git for Windows](https://git-scm.com/download/win),安装后重启 ClawPanel。
|
||||
|
||||
### 安装后 Node.js 检测不到(Windows)
|
||||
|
||||
安装 Node.js 后需要重启 ClawPanel(或重启电脑),新的 PATH 环境变量才能生效。
|
||||
|
||||
## 相关项目
|
||||
|
||||
| 项目 | 说明 |
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"description": "OpenClaw AI Agent 可视化管理面板,基于 Tauri v2 的跨平台桌面应用。支持仪表盘监控、多模型配置、实时 AI 聊天、记忆管理、Agent 管理、网关配置、内网穿透等功能。",
|
||||
"url": "https://claw.qt.cool/",
|
||||
"downloadUrl": "https://github.com/qingchencloud/clawpanel/releases/latest",
|
||||
"softwareVersion": "0.4.0",
|
||||
"softwareVersion": "0.4.1",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "晴辰云 QingchenCloud",
|
||||
@@ -429,7 +429,7 @@
|
||||
<div class="orb orb-1" id="orb1"></div>
|
||||
<div class="orb orb-2" id="orb2"></div>
|
||||
<div class="hero-inner">
|
||||
<div class="reveal hero-badge"><span class="pulse"></span> v0.4.0 已发布 — Gateway 守护、配置同步、流式超时</div>
|
||||
<div class="reveal hero-badge"><span class="pulse"></span> v0.4.1 已发布 — Gateway 守护、配置同步、流式超时</div>
|
||||
<h1 class="reveal hero-title">管理你的 <span class="gradient-text shimmer">AI Agent</span><br>从未如此直观</h1>
|
||||
<p class="reveal hero-subtitle">ClawPanel 是 <strong>OpenClaw</strong> 的可视化管理面板,基于 Tauri v2 构建。<br>仪表盘、模型配置、实时聊天、记忆管理 — 一站式掌控。</p>
|
||||
<div class="reveal hero-cta">
|
||||
@@ -696,7 +696,7 @@
|
||||
<div class="orb orb-2" style="top:auto;bottom:-100px"></div>
|
||||
<div class="container-sm" style="position:relative;z-index:10">
|
||||
<div class="section-header">
|
||||
<div class="reveal download-version"><span class="pulse"></span> v0.4.0 最新版</div>
|
||||
<div class="reveal download-version"><span class="pulse"></span> v0.4.1 最新版</div>
|
||||
<h2 class="reveal section-title"><span class="gradient-text">下载安装</span></h2>
|
||||
<p class="reveal section-desc">选择你的操作系统,一键下载安装</p>
|
||||
</div>
|
||||
@@ -706,11 +706,11 @@
|
||||
<h3>macOS</h3>
|
||||
<p class="dl-desc">支持 Apple Silicon 和 Intel 芯片</p>
|
||||
<div class="dl-links">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.0_aarch64.dmg" target="_blank" rel="noopener">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.1_aarch64.dmg" target="_blank" rel="noopener">
|
||||
Apple Silicon (M1/M2/M3/M4)
|
||||
<span class="dl-format">.dmg</span>
|
||||
</a>
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.0_x64.dmg" target="_blank" rel="noopener">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.1_x64.dmg" target="_blank" rel="noopener">
|
||||
Intel 芯片
|
||||
<span class="dl-format">.dmg</span>
|
||||
</a>
|
||||
@@ -721,11 +721,11 @@
|
||||
<h3>Windows</h3>
|
||||
<p class="dl-desc">支持 Windows 10 及以上版本</p>
|
||||
<div class="dl-links">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.0_x64-setup.exe" target="_blank" rel="noopener">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.1_x64-setup.exe" target="_blank" rel="noopener">
|
||||
安装程序
|
||||
<span class="dl-format">.exe</span>
|
||||
</a>
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.0_x64_en-US.msi" target="_blank" rel="noopener">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.1_x64_en-US.msi" target="_blank" rel="noopener">
|
||||
MSI 安装包
|
||||
<span class="dl-format">.msi</span>
|
||||
</a>
|
||||
@@ -736,11 +736,11 @@
|
||||
<h3>Linux</h3>
|
||||
<p class="dl-desc">支持主流 Linux 发行版</p>
|
||||
<div class="dl-links">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.0_amd64.AppImage" target="_blank" rel="noopener">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.1_amd64.AppImage" target="_blank" rel="noopener">
|
||||
通用版
|
||||
<span class="dl-format">.AppImage</span>
|
||||
</a>
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.0_amd64.deb" target="_blank" rel="noopener">
|
||||
<a class="dl-link" href="https://github.com/qingchencloud/clawpanel/releases/latest/download/ClawPanel_0.4.1_amd64.deb" target="_blank" rel="noopener">
|
||||
Debian / Ubuntu
|
||||
<span class="dl-format">.deb</span>
|
||||
</a>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clawpanel",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.1",
|
||||
"private": true,
|
||||
"description": "ClawPanel - OpenClaw 可视化管理面板,基于 Tauri v2 的跨平台桌面应用",
|
||||
"type": "module",
|
||||
|
||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -328,7 +328,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clawpanel"
|
||||
version = "0.2.1"
|
||||
version = "0.4.1"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clawpanel"
|
||||
version = "0.2.1"
|
||||
version = "0.4.1"
|
||||
edition = "2021"
|
||||
description = "ClawPanel - OpenClaw 可视化管理面板"
|
||||
authors = ["qingchencloud"]
|
||||
|
||||
@@ -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<Value, String> {
|
||||
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() {
|
||||
|
||||
@@ -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<String> = 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(":")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
67
src/lib/error-diagnosis.js
Normal file
67
src/lib/error-diagnosis.js
Normal file
@@ -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',
|
||||
}
|
||||
}
|
||||
@@ -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?.()
|
||||
|
||||
@@ -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 运行,请先安装。
|
||||
</p>
|
||||
<a class="btn btn-primary btn-sm" href="https://nodejs.org/" target="_blank" rel="noopener">下载 Node.js</a>
|
||||
<span class="form-hint" style="margin-left:8px">安装后点击「重新检测」</span>`
|
||||
<span class="form-hint" style="margin-left:8px">安装后点击「重新检测」</span>
|
||||
${isMacPlatform() ? `
|
||||
<div style="margin-top:var(--space-sm);padding:8px 12px;background:var(--bg-tertiary);border-radius:var(--radius-sm);font-size:var(--font-size-xs);color:var(--text-secondary);line-height:1.6">
|
||||
<strong>已经装了但检测不到?</strong> macOS 上从 Finder 启动可能找不到 Node.js。试试关掉 ClawPanel 后从终端启动:<br>
|
||||
<code style="background:var(--bg-secondary);padding:2px 6px;border-radius:3px;user-select:all">open /Applications/ClawPanel.app</code>
|
||||
</div>` : ''}`
|
||||
}
|
||||
</div>
|
||||
`
|
||||
@@ -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) {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user