mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-30 04:40:18 +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:
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