mirror of
https://github.com/hotwa/luci-app-openclaw.git
synced 2026-03-31 04:52:33 +00:00
release: v1.0.12 — 移除 OpenClaw 版本检测、BusyBox tar 兼容
This commit is contained in:
14
CHANGELOG.md
14
CHANGELOG.md
@@ -4,6 +4,20 @@
|
||||
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
|
||||
|
||||
## [1.0.12] - 2026-03-11
|
||||
|
||||
### 移除 OpenClaw 版本检测 & 修复 BusyBox tar 兼容性
|
||||
|
||||
#### 变更
|
||||
- **「检测升级」按钮**: 不再检查 OpenClaw (npm) 版本,仅检查插件 (luci-app-openclaw) 是否有新版本
|
||||
- **「检测升级」显示更新内容**: 检测到新插件版本时,直接展示该版本的 Release Notes,告知用户升级了什么
|
||||
- **状态面板**: 移除「OpenClaw」版本显示行,保留 Node.js 和插件版本
|
||||
- **内部清理**: 移除 `get_openclaw_version()` 函数、`action_do_update`、`action_upgrade_log` 等已废弃后端 API
|
||||
|
||||
#### 修复
|
||||
- **BusyBox tar 兼容性** (#18, #30): `openclaw-env` 安装 Node.js 时的解压命令优先使用 GNU tar `--strip-components=1`;若不支持则自动回退到 BusyBox tar 兼容方式(解压到临时目录后移动),无需用户手动安装 `tar`
|
||||
- **插件升级网络错误提示**: 下载后检测文件内容,若 GitHub 返回 `Not Found`(GFW 拦截等情况)则显示明确提示,并附手动下载链接
|
||||
|
||||
## [1.0.11] - 2026-03-09
|
||||
|
||||
### 修复 Telegram 配对后无法使用的严重 Bug
|
||||
|
||||
@@ -1,32 +1,6 @@
|
||||
-- luci-app-openclaw — LuCI Controller
|
||||
module("luci.controller.openclaw", package.seeall)
|
||||
|
||||
-- 公共辅助: 获取 OpenClaw 版本号
|
||||
local function get_openclaw_version()
|
||||
local sys = require "luci.sys"
|
||||
-- 优先从 package.json 读取版本号 (轻量),避免每次启动 node 进程
|
||||
local dirs = {
|
||||
"/opt/openclaw/global/lib/node_modules/openclaw",
|
||||
"/opt/openclaw/global/node_modules/openclaw",
|
||||
}
|
||||
-- pnpm 版本目录
|
||||
local pnpm_glob = sys.exec("ls -d /opt/openclaw/global/*/node_modules/openclaw 2>/dev/null"):gsub("%s+$", "")
|
||||
for d in pnpm_glob:gmatch("[^\n]+") do
|
||||
dirs[#dirs + 1] = d
|
||||
end
|
||||
for _, d in ipairs(dirs) do
|
||||
local pkg = d .. "/package.json"
|
||||
local f = io.open(pkg, "r")
|
||||
if f then
|
||||
local content = f:read("*a")
|
||||
f:close()
|
||||
local ver = content:match('"version"%s*:%s*"([^"]+)"')
|
||||
if ver and ver ~= "" then return ver end
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function index()
|
||||
-- 主入口: 服务 → OpenClaw (🧠 作为菜单图标)
|
||||
local page = entry({"admin", "services", "openclaw"}, alias("admin", "services", "openclaw", "basic"), _("OpenClaw"), 90)
|
||||
@@ -50,15 +24,9 @@ function index()
|
||||
-- 安装/升级日志 API (轮询)
|
||||
entry({"admin", "services", "openclaw", "setup_log"}, call("action_setup_log"), nil).leaf = true
|
||||
|
||||
-- 版本检查 API
|
||||
-- 版本检查 API (仅检查插件版本)
|
||||
entry({"admin", "services", "openclaw", "check_update"}, call("action_check_update"), nil).leaf = true
|
||||
|
||||
-- 执行升级 API
|
||||
entry({"admin", "services", "openclaw", "do_update"}, call("action_do_update"), nil).leaf = true
|
||||
|
||||
-- 升级日志 API (轮询)
|
||||
entry({"admin", "services", "openclaw", "upgrade_log"}, call("action_upgrade_log"), nil).leaf = true
|
||||
|
||||
-- 卸载运行环境 API
|
||||
entry({"admin", "services", "openclaw", "uninstall"}, call("action_uninstall"), nil).leaf = true
|
||||
|
||||
@@ -99,7 +67,6 @@ function action_status()
|
||||
memory_kb = 0,
|
||||
uptime = "",
|
||||
node_version = "",
|
||||
openclaw_version = "",
|
||||
plugin_version = "",
|
||||
}
|
||||
|
||||
@@ -119,12 +86,6 @@ function action_status()
|
||||
result.node_version = node_ver
|
||||
end
|
||||
|
||||
-- 检查 OpenClaw 版本
|
||||
local oc_ver = get_openclaw_version()
|
||||
if oc_ver and oc_ver ~= "" then
|
||||
result.openclaw_version = "v" .. oc_ver
|
||||
end
|
||||
|
||||
-- 网关端口检查
|
||||
local gw_check = sys.exec("netstat -tlnp 2>/dev/null | grep -c ':" .. port .. " ' || echo 0"):gsub("%s+", "")
|
||||
result.gateway_running = (tonumber(gw_check) or 0) > 0
|
||||
@@ -306,18 +267,7 @@ function action_check_update()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
|
||||
-- 当前 OpenClaw 版本
|
||||
local current = get_openclaw_version()
|
||||
|
||||
-- 最新 OpenClaw 版本 (从 npm registry 查询)
|
||||
local latest = sys.exec("PATH=/opt/openclaw/node/bin:/opt/openclaw/global/bin:$PATH npm view openclaw version 2>/dev/null"):gsub("%s+", "")
|
||||
|
||||
local has_update = false
|
||||
if current ~= "" and latest ~= "" and current ~= latest then
|
||||
has_update = true
|
||||
end
|
||||
|
||||
-- 插件版本检查 (从 GitHub API 获取最新 release tag)
|
||||
-- 插件版本检查 (从 GitHub API 获取最新 release tag + release notes)
|
||||
local plugin_current = ""
|
||||
local pf = io.open("/usr/share/openclaw/VERSION", "r")
|
||||
or io.open("/root/luci-app-openclaw/VERSION", "r")
|
||||
@@ -327,108 +277,38 @@ function action_check_update()
|
||||
end
|
||||
|
||||
local plugin_latest = ""
|
||||
local release_notes = ""
|
||||
local plugin_has_update = false
|
||||
-- 仅在请求参数含 check_plugin=1 或 quick=1 时检查插件版本
|
||||
local check_plugin = http.formvalue("check_plugin") or ""
|
||||
local quick = http.formvalue("quick") or ""
|
||||
if check_plugin == "1" or quick == "1" then
|
||||
-- 使用 GitHub API 获取最新 release tag (轻量, 不下载任何文件)
|
||||
local gh_resp = sys.exec("curl -sf --connect-timeout 5 --max-time 10 'https://api.github.com/repos/10000ge10000/luci-app-openclaw/releases/latest' 2>/dev/null | grep -o '\"tag_name\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | head -1 | cut -d'\"' -f4")
|
||||
gh_resp = gh_resp:gsub("%s+", "")
|
||||
if gh_resp ~= "" then
|
||||
-- tag 可能是 v1.0.3 或 1.0.3
|
||||
plugin_latest = gh_resp:gsub("^v", "")
|
||||
|
||||
-- 使用 GitHub API 获取最新 release (tag + body)
|
||||
local gh_json = sys.exec("curl -sf --connect-timeout 5 --max-time 10 'https://api.github.com/repos/10000ge10000/luci-app-openclaw/releases/latest' 2>/dev/null")
|
||||
if gh_json and gh_json ~= "" then
|
||||
-- 提取 tag_name
|
||||
local tag = gh_json:match('"tag_name"%s*:%s*"([^"]+)"')
|
||||
if tag and tag ~= "" then
|
||||
plugin_latest = tag:gsub("^v", ""):gsub("%s+", "")
|
||||
end
|
||||
-- 提取 body (release notes), 处理 JSON 转义
|
||||
-- 结束引号后可能紧跟 \n、空格、, 或 },用宽松匹配
|
||||
local body = gh_json:match('"body"%s*:%s*"(.-)"[,}%]\n ]')
|
||||
if body and body ~= "" then
|
||||
-- 还原 JSON 转义: \n \r \" \\
|
||||
body = body:gsub("\\n", "\n"):gsub("\\r", ""):gsub('\\"', '"'):gsub("\\\\", "\\")
|
||||
release_notes = body
|
||||
end
|
||||
end
|
||||
|
||||
if plugin_current ~= "" and plugin_latest ~= "" and plugin_current ~= plugin_latest then
|
||||
plugin_has_update = true
|
||||
end
|
||||
end
|
||||
|
||||
http.prepare_content("application/json")
|
||||
http.write_json({
|
||||
status = "ok",
|
||||
current = current,
|
||||
latest = latest,
|
||||
has_update = has_update,
|
||||
plugin_current = plugin_current,
|
||||
plugin_latest = plugin_latest,
|
||||
plugin_has_update = plugin_has_update
|
||||
})
|
||||
end
|
||||
|
||||
-- ═══════════════════════════════════════════
|
||||
-- 执行升级 API (后台执行 + 日志轮询)
|
||||
-- ═══════════════════════════════════════════
|
||||
function action_do_update()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
|
||||
-- 清理旧日志和状态
|
||||
sys.exec("rm -f /tmp/openclaw-upgrade.log /tmp/openclaw-upgrade.pid /tmp/openclaw-upgrade.exit")
|
||||
|
||||
-- 后台执行升级,升级完成后自动重启服务
|
||||
sys.exec("( /usr/bin/openclaw-env upgrade > /tmp/openclaw-upgrade.log 2>&1; RC=$?; echo $RC > /tmp/openclaw-upgrade.exit; if [ $RC -eq 0 ]; then echo '' >> /tmp/openclaw-upgrade.log; echo '正在重启服务...' >> /tmp/openclaw-upgrade.log; /etc/init.d/openclaw restart >> /tmp/openclaw-upgrade.log 2>&1; echo ' [✓] 服务已重启' >> /tmp/openclaw-upgrade.log; fi ) & echo $! > /tmp/openclaw-upgrade.pid")
|
||||
|
||||
http.prepare_content("application/json")
|
||||
http.write_json({
|
||||
status = "ok",
|
||||
message = "升级已在后台启动,请查看升级日志..."
|
||||
})
|
||||
end
|
||||
|
||||
-- ═══════════════════════════════════════════
|
||||
-- 升级日志轮询 API
|
||||
-- ═══════════════════════════════════════════
|
||||
function action_upgrade_log()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
|
||||
-- 读取日志内容
|
||||
local log = ""
|
||||
local f = io.open("/tmp/openclaw-upgrade.log", "r")
|
||||
if f then
|
||||
log = f:read("*a") or ""
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- 检查进程是否还在运行
|
||||
local running = false
|
||||
local pid_file = io.open("/tmp/openclaw-upgrade.pid", "r")
|
||||
if pid_file then
|
||||
local pid = pid_file:read("*a"):gsub("%s+", "")
|
||||
pid_file:close()
|
||||
if pid ~= "" then
|
||||
local check = sys.exec("kill -0 " .. pid .. " 2>/dev/null && echo yes || echo no"):gsub("%s+", "")
|
||||
running = (check == "yes")
|
||||
end
|
||||
end
|
||||
|
||||
-- 读取退出码
|
||||
local exit_code = -1
|
||||
if not running then
|
||||
local exit_file = io.open("/tmp/openclaw-upgrade.exit", "r")
|
||||
if exit_file then
|
||||
local code = exit_file:read("*a"):gsub("%s+", "")
|
||||
exit_file:close()
|
||||
exit_code = tonumber(code) or -1
|
||||
end
|
||||
end
|
||||
|
||||
-- 判断状态
|
||||
local state = "idle"
|
||||
if running then
|
||||
state = "running"
|
||||
elseif exit_code == 0 then
|
||||
state = "success"
|
||||
elseif exit_code > 0 then
|
||||
state = "failed"
|
||||
end
|
||||
|
||||
http.prepare_content("application/json")
|
||||
http.write_json({
|
||||
state = state,
|
||||
exit_code = exit_code,
|
||||
log = log
|
||||
plugin_has_update = plugin_has_update,
|
||||
release_notes = release_notes
|
||||
})
|
||||
end
|
||||
|
||||
@@ -512,8 +392,14 @@ function action_plugin_upgrade()
|
||||
"else " ..
|
||||
" FSIZE=$(wc -c < /tmp/luci-app-openclaw-update.run 2>/dev/null | tr -d ' '); " ..
|
||||
" echo \"下载完成 (${FSIZE} bytes)\" >> /tmp/openclaw-plugin-upgrade.log; " ..
|
||||
" FHEAD=$(head -c 9 /tmp/luci-app-openclaw-update.run 2>/dev/null); " ..
|
||||
" if [ \"$FSIZE\" -lt 10000 ] 2>/dev/null; then " ..
|
||||
" echo '文件过小,可能下载失败或链接无效' >> /tmp/openclaw-plugin-upgrade.log; " ..
|
||||
" if [ \"$FHEAD\" = 'Not Found' ]; then " ..
|
||||
" echo '❌ GitHub 返回 \"Not Found\",可能是网络被拦截(GFW)或 Release 资产不存在' >> /tmp/openclaw-plugin-upgrade.log; " ..
|
||||
" else " ..
|
||||
" echo '❌ 文件过小,可能 GitHub 访问受限或网络异常' >> /tmp/openclaw-plugin-upgrade.log; " ..
|
||||
" fi; " ..
|
||||
" echo '请检查路由器是否能访问 github.com,或手动下载后安装: %s' >> /tmp/openclaw-plugin-upgrade.log; " ..
|
||||
" echo 1 > /tmp/openclaw-plugin-upgrade.exit; " ..
|
||||
" else " ..
|
||||
" echo '' >> /tmp/openclaw-plugin-upgrade.log; " ..
|
||||
@@ -530,7 +416,7 @@ function action_plugin_upgrade()
|
||||
" rm -f /tmp/luci-app-openclaw-update.run; " ..
|
||||
"fi " ..
|
||||
") & echo $! > /tmp/openclaw-plugin-upgrade.pid",
|
||||
version, run_url, run_url
|
||||
version, run_url, run_url, run_url
|
||||
))
|
||||
|
||||
http.prepare_content("application/json")
|
||||
|
||||
@@ -24,8 +24,6 @@ act.cfgvalue = function(self, section)
|
||||
local ctl_url = luci.dispatcher.build_url("admin", "services", "openclaw", "service_ctl")
|
||||
local log_url = luci.dispatcher.build_url("admin", "services", "openclaw", "setup_log")
|
||||
local check_url = luci.dispatcher.build_url("admin", "services", "openclaw", "check_update")
|
||||
local update_url = luci.dispatcher.build_url("admin", "services", "openclaw", "do_update")
|
||||
local upgrade_log_url = luci.dispatcher.build_url("admin", "services", "openclaw", "upgrade_log")
|
||||
local uninstall_url = luci.dispatcher.build_url("admin", "services", "openclaw", "uninstall")
|
||||
local plugin_upgrade_url = luci.dispatcher.build_url("admin", "services", "openclaw", "plugin_upgrade")
|
||||
local plugin_upgrade_log_url = luci.dispatcher.build_url("admin", "services", "openclaw", "plugin_upgrade_log")
|
||||
@@ -223,116 +221,44 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = '}catch(e){el.innerHTML="<span style=\\"color:red\\">❌ 错误</span>";}'
|
||||
html[#html+1] = '});}'
|
||||
|
||||
-- 检测升级 (同时检查 OpenClaw + 插件版本)
|
||||
-- 检测升级 (只检查插件版本,有新版本时显示更新内容)
|
||||
html[#html+1] = 'function ocCheckUpdate(){'
|
||||
html[#html+1] = 'var btn=document.getElementById("btn-check-update");'
|
||||
html[#html+1] = 'var el=document.getElementById("action-result");'
|
||||
html[#html+1] = 'var act=document.getElementById("oc-update-action");'
|
||||
html[#html+1] = 'btn.disabled=true;btn.textContent="⏳ 正在检测...";el.textContent="";act.style.display="none";'
|
||||
html[#html+1] = '(new XHR()).get("' .. check_url .. '?check_plugin=1",null,function(x){'
|
||||
html[#html+1] = '(new XHR()).get("' .. check_url .. '",null,function(x){'
|
||||
html[#html+1] = 'btn.disabled=false;btn.textContent="🔍 检测升级";'
|
||||
html[#html+1] = 'var dot=document.getElementById("update-dot");if(dot)dot.style.display="none";'
|
||||
html[#html+1] = 'try{var r=JSON.parse(x.responseText);'
|
||||
html[#html+1] = 'var msgs=[];'
|
||||
-- OpenClaw 版本检查
|
||||
html[#html+1] = 'if(!r.current){msgs.push("<span style=\\"color:#999\\">⚠️ OpenClaw 运行环境未安装</span>");}'
|
||||
html[#html+1] = 'else if(r.has_update){msgs.push("<span style=\\"color:#e36209\\">📦 OpenClaw: v"+r.current+" → v"+r.latest+" (有新版本)</span>");}'
|
||||
html[#html+1] = 'else{msgs.push("<span style=\\"color:green\\">✅ OpenClaw: v"+r.current+" (已是最新)</span>");}'
|
||||
-- 插件版本检查
|
||||
html[#html+1] = 'if(r.plugin_current){'
|
||||
html[#html+1] = 'if(r.plugin_has_update){msgs.push("<span style=\\"color:#e36209\\">🔌 插件: v"+r.plugin_current+" → v"+r.plugin_latest+" (有新版本)</span>");}'
|
||||
html[#html+1] = 'else if(r.plugin_latest){msgs.push("<span style=\\"color:green\\">✅ 插件: v"+r.plugin_current+" (已是最新)</span>");}'
|
||||
html[#html+1] = 'else{msgs.push("<span style=\\"color:#999\\">🔌 插件: v"+r.plugin_current+" (无法检查最新版本)</span>");}'
|
||||
html[#html+1] = '}'
|
||||
html[#html+1] = 'if(msgs.length===0)msgs.push("<span style=\\"color:#999\\">无法获取版本信息</span>");'
|
||||
html[#html+1] = 'el.innerHTML=msgs.join("<br/>");'
|
||||
-- 显示 OpenClaw 升级按钮
|
||||
html[#html+1] = 'if(r.has_update){'
|
||||
html[#html+1] = 'act.style.display="block";'
|
||||
html[#html+1] = 'act.innerHTML=\'<button class="btn cbi-button cbi-button-apply" type="button" onclick="ocDoUpdate()" id="btn-do-update">⬆️ 立即升级 OpenClaw</button>\';'
|
||||
html[#html+1] = '}'
|
||||
-- 插件有更新时: 一键升级按钮 + GitHub 下载链接
|
||||
-- 插件有更新时: release notes + 一键升级按钮 + GitHub 下载链接
|
||||
html[#html+1] = 'if(r.plugin_has_update){'
|
||||
html[#html+1] = 'act.style.display="block";'
|
||||
html[#html+1] = 'window._pluginLatestVer=r.plugin_latest;'
|
||||
html[#html+1] = 'act.innerHTML=(act.innerHTML||"")+\' <button class="btn cbi-button cbi-button-apply" type="button" onclick="ocPluginUpgrade()" id="btn-plugin-upgrade">⬆️ 升级插件 v\'+r.plugin_latest+\'</button>\';'
|
||||
html[#html+1] = 'act.innerHTML=act.innerHTML+\' <a href="https://github.com/10000ge10000/luci-app-openclaw/releases/latest" target="_blank" rel="noopener" class="btn cbi-button cbi-button-action" style="text-decoration:none;">📥 手动下载</a>\';'
|
||||
html[#html+1] = 'var notesHtml="";'
|
||||
html[#html+1] = 'if(r.release_notes){'
|
||||
html[#html+1] = 'var escaped=r.release_notes.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");'
|
||||
html[#html+1] = 'notesHtml=\'<div style="margin:10px 0 8px;padding:10px 14px;background:#fffbf0;border:1px solid #f0c040;border-radius:6px;">\''
|
||||
html[#html+1] = '+\'<div style="font-size:12px;font-weight:600;color:#8a6a00;margin-bottom:6px;">📋 v\'+r.plugin_latest+\' 更新内容</div>\''
|
||||
html[#html+1] = '+\'<pre style="margin:0;font-size:12px;color:#444;white-space:pre-wrap;word-break:break-word;line-height:1.6;">\'+escaped+\'</pre>\''
|
||||
html[#html+1] = '+\'</div>\';'
|
||||
html[#html+1] = '}'
|
||||
html[#html+1] = 'act.innerHTML=notesHtml'
|
||||
html[#html+1] = '+\'<button class="btn cbi-button cbi-button-apply" type="button" onclick="ocPluginUpgrade()" id="btn-plugin-upgrade">⬆️ 升级插件 v\'+r.plugin_latest+\'</button>\''
|
||||
html[#html+1] = '+\' <a href="https://github.com/10000ge10000/luci-app-openclaw/releases/latest" target="_blank" rel="noopener" class="btn cbi-button cbi-button-action" style="text-decoration:none;">📥 手动下载</a>\';'
|
||||
html[#html+1] = '}'
|
||||
html[#html+1] = '}catch(e){el.innerHTML="<span style=\\"color:red\\">❌ 检测失败</span>";}'
|
||||
html[#html+1] = '});}'
|
||||
|
||||
-- 执行升级 (带实时日志, 和安装一样的体验)
|
||||
html[#html+1] = 'var _upgradeTimer=null;'
|
||||
html[#html+1] = 'function ocDoUpdate(){'
|
||||
html[#html+1] = 'var btn=document.getElementById("btn-do-update");'
|
||||
html[#html+1] = 'var panel=document.getElementById("setup-log-panel");'
|
||||
html[#html+1] = 'var logEl=document.getElementById("setup-log-content");'
|
||||
html[#html+1] = 'var titleEl=document.getElementById("setup-log-title");'
|
||||
html[#html+1] = 'var statusEl=document.getElementById("setup-log-status");'
|
||||
html[#html+1] = 'var resultEl=document.getElementById("setup-log-result");'
|
||||
html[#html+1] = 'var actionEl=document.getElementById("action-result");'
|
||||
html[#html+1] = 'if(!confirm("确定要升级 OpenClaw?升级期间服务将短暂中断。"))return;'
|
||||
html[#html+1] = 'btn.disabled=true;btn.textContent="⏳ 正在升级...";'
|
||||
html[#html+1] = 'actionEl.textContent="";'
|
||||
html[#html+1] = 'panel.style.display="block";'
|
||||
html[#html+1] = 'logEl.textContent="正在启动升级...\\n";'
|
||||
html[#html+1] = 'titleEl.textContent="📋 升级日志";'
|
||||
html[#html+1] = 'statusEl.innerHTML="<span style=\\"color:#7aa2f7;\\">⏳ 升级进行中...</span>";'
|
||||
html[#html+1] = 'resultEl.style.display="none";'
|
||||
html[#html+1] = '(new XHR()).get("' .. update_url .. '",null,function(x){'
|
||||
html[#html+1] = 'try{JSON.parse(x.responseText);}catch(e){}'
|
||||
html[#html+1] = 'ocPollUpgradeLog();'
|
||||
html[#html+1] = '});'
|
||||
html[#html+1] = '}'
|
||||
|
||||
-- 轮询升级日志
|
||||
html[#html+1] = 'function ocPollUpgradeLog(){'
|
||||
html[#html+1] = 'if(_upgradeTimer)clearInterval(_upgradeTimer);'
|
||||
html[#html+1] = '_upgradeTimer=setInterval(function(){'
|
||||
html[#html+1] = '(new XHR()).get("' .. upgrade_log_url .. '",null,function(x){'
|
||||
html[#html+1] = 'try{'
|
||||
html[#html+1] = 'var r=JSON.parse(x.responseText);'
|
||||
html[#html+1] = 'var logEl=document.getElementById("setup-log-content");'
|
||||
html[#html+1] = 'var statusEl=document.getElementById("setup-log-status");'
|
||||
html[#html+1] = 'if(r.log)logEl.textContent=r.log;'
|
||||
html[#html+1] = 'logEl.scrollTop=logEl.scrollHeight;'
|
||||
html[#html+1] = 'if(r.state==="running"){'
|
||||
html[#html+1] = 'statusEl.innerHTML="<span style=\\"color:#7aa2f7;\\">⏳ 升级进行中...</span>";'
|
||||
html[#html+1] = '}else if(r.state==="success"){'
|
||||
html[#html+1] = 'clearInterval(_upgradeTimer);_upgradeTimer=null;'
|
||||
html[#html+1] = 'ocUpgradeDone(true);'
|
||||
html[#html+1] = '}else if(r.state==="failed"){'
|
||||
html[#html+1] = 'clearInterval(_upgradeTimer);_upgradeTimer=null;'
|
||||
html[#html+1] = 'ocUpgradeDone(false);'
|
||||
html[#html+1] = '}'
|
||||
html[#html+1] = '}catch(e){}'
|
||||
html[#html+1] = '});'
|
||||
html[#html+1] = '},1500);'
|
||||
html[#html+1] = '}'
|
||||
|
||||
-- 升级完成处理
|
||||
html[#html+1] = 'function ocUpgradeDone(ok){'
|
||||
html[#html+1] = 'var btn=document.getElementById("btn-do-update");'
|
||||
html[#html+1] = 'var statusEl=document.getElementById("setup-log-status");'
|
||||
html[#html+1] = 'var resultEl=document.getElementById("setup-log-result");'
|
||||
html[#html+1] = 'var actEl=document.getElementById("oc-update-action");'
|
||||
html[#html+1] = 'if(btn){btn.disabled=false;btn.textContent="⬆️ 立即升级";}'
|
||||
html[#html+1] = 'resultEl.style.display="block";'
|
||||
html[#html+1] = 'if(ok){'
|
||||
html[#html+1] = 'statusEl.innerHTML="<span style=\\"color:#1a7f37;\\">✅ 升级完成</span>";'
|
||||
html[#html+1] = 'resultEl.innerHTML="<div style=\\"border:1px solid #c6e9c9;background:#e6f7e9;padding:12px 16px;border-radius:6px;\\">"+'
|
||||
html[#html+1] = '"<strong style=\\"color:#1a7f37;font-size:14px;\\">🎉 升级成功!服务已自动重启。</strong><br/>"+'
|
||||
html[#html+1] = '"<span style=\\"color:#555;font-size:13px;line-height:1.8;\\">点击下方按钮刷新页面查看最新状态。</span><br/>"+'
|
||||
html[#html+1] = '"<button class=\\"btn cbi-button cbi-button-apply\\" type=\\"button\\" onclick=\\"location.reload()\\" style=\\"margin-top:10px;\\">🔄 刷新页面</button></div>";'
|
||||
html[#html+1] = 'actEl.style.display="none";'
|
||||
html[#html+1] = '}else{'
|
||||
html[#html+1] = 'statusEl.innerHTML="<span style=\\"color:#cf222e;\\">❌ 升级失败</span>";'
|
||||
html[#html+1] = 'resultEl.innerHTML="<div style=\\"border:1px solid #f5c6cb;background:#ffeef0;padding:12px 16px;border-radius:6px;\\">"+'
|
||||
html[#html+1] = '"<strong style=\\"color:#cf222e;font-size:14px;\\">❌ 升级失败</strong><br/>"+'
|
||||
html[#html+1] = '"<span style=\\"color:#555;font-size:13px;\\">请查看上方日志了解详情。也可在终端查看:<code>cat /tmp/openclaw-upgrade.log</code></span><br/>"+'
|
||||
html[#html+1] = '"<button class=\\"btn cbi-button cbi-button-apply\\" type=\\"button\\" onclick=\\"location.reload()\\" style=\\"margin-top:10px;\\">🔄 刷新页面</button></div>";'
|
||||
html[#html+1] = '}'
|
||||
html[#html+1] = '}'
|
||||
|
||||
-- ═══ 插件一键升级 ═══
|
||||
html[#html+1] = 'var _pluginUpgradeTimer=null;'
|
||||
|
||||
@@ -436,9 +362,9 @@ act.cfgvalue = function(self, section)
|
||||
-- 页面加载时静默检查是否有更新 (仅显示小红点提示)
|
||||
html[#html+1] = '(function(){'
|
||||
html[#html+1] = 'setTimeout(function(){'
|
||||
html[#html+1] = '(new XHR()).get("' .. check_url .. '?quick=1",null,function(x){'
|
||||
html[#html+1] = '(new XHR()).get("' .. check_url .. '",null,function(x){'
|
||||
html[#html+1] = 'try{var r=JSON.parse(x.responseText);'
|
||||
html[#html+1] = 'if(r.has_update||r.plugin_has_update){'
|
||||
html[#html+1] = 'if(r.plugin_has_update){'
|
||||
html[#html+1] = 'var dot=document.getElementById("update-dot");'
|
||||
html[#html+1] = 'if(dot)dot.style.display="block";'
|
||||
html[#html+1] = '}'
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
<tr><td>内存占用</td><td id="oc-st-mem">-</td></tr>
|
||||
<tr><td>运行时间</td><td id="oc-st-uptime">-</td></tr>
|
||||
<tr><td>Node.js</td><td id="oc-st-node">-</td></tr>
|
||||
<tr><td>OpenClaw</td><td id="oc-st-ocver">-</td></tr>
|
||||
<tr><td>插件版本</td><td id="oc-st-plugin">-</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -137,7 +136,6 @@
|
||||
|
||||
document.getElementById('oc-st-uptime').textContent = d.uptime || '-';
|
||||
document.getElementById('oc-st-node').textContent = d.node_version || '未安装';
|
||||
document.getElementById('oc-st-ocver').textContent = d.openclaw_version || '未安装';
|
||||
document.getElementById('oc-st-plugin').textContent = d.plugin_version ? ('v' + d.plugin_version) : '-';
|
||||
|
||||
} catch(e) {
|
||||
|
||||
@@ -224,7 +224,27 @@ download_node() {
|
||||
rm -rf "/overlay/upper${NODE_BASE}" 2>/dev/null
|
||||
fi
|
||||
ensure_mkdir "$NODE_BASE"
|
||||
tar xf "$tmp_file" -C "$NODE_BASE" --strip-components=1
|
||||
# 兼容 BusyBox tar (不支持 --strip-components) 和 GNU tar
|
||||
# 方法: 先解压到临时目录,再移动顶层子目录内容到目标目录
|
||||
if tar --strip-components=1 -xf "$tmp_file" -C "$NODE_BASE" 2>/dev/null; then
|
||||
: # GNU tar 成功
|
||||
else
|
||||
# BusyBox tar 回退: 解压到临时目录后手动移动
|
||||
local tmp_extract="/tmp/node-extract-$$"
|
||||
ensure_mkdir "$tmp_extract"
|
||||
tar xf "$tmp_file" -C "$tmp_extract"
|
||||
# 找顶层目录 (node-vX.X.X-linux-xxx)
|
||||
local top_dir
|
||||
top_dir=$(ls "$tmp_extract" 2>/dev/null | head -1)
|
||||
if [ -n "$top_dir" ] && [ -d "$tmp_extract/$top_dir" ]; then
|
||||
cp -a "$tmp_extract/$top_dir/." "$NODE_BASE/"
|
||||
else
|
||||
log_error "解压后未找到顶层目录,安装失败"
|
||||
rm -rf "$tmp_extract"
|
||||
exit 1
|
||||
fi
|
||||
rm -rf "$tmp_extract"
|
||||
fi
|
||||
rm -f "$tmp_file"
|
||||
|
||||
# 验证
|
||||
|
||||
Reference in New Issue
Block a user