From de8b2ade8018c084950d2d56318a8b4440c240d8 Mon Sep 17 00:00:00 2001
From: 10000ge10000 <10000ge10000@users.noreply.github.com>
Date: Wed, 11 Mar 2026 21:21:47 +0800
Subject: [PATCH] =?UTF-8?q?release:=20v1.0.12=20=E2=80=94=20=E7=A7=BB?=
=?UTF-8?q?=E9=99=A4=20OpenClaw=20=E7=89=88=E6=9C=AC=E6=A3=80=E6=B5=8B?=
=?UTF-8?q?=E3=80=81BusyBox=20tar=20=E5=85=BC=E5=AE=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 14 +++
VERSION | 2 +-
luasrc/controller/openclaw.lua | 178 +++++-----------------------
luasrc/model/cbi/openclaw/basic.lua | 108 +++--------------
luasrc/view/openclaw/status.htm | 2 -
root/usr/bin/openclaw-env | 22 +++-
6 files changed, 85 insertions(+), 241 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 395b16e..eed9d6d 100644
--- a/CHANGELOG.md
+++ b/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
diff --git a/VERSION b/VERSION
index 59e9e60..bb83058 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.11
+1.0.12
diff --git a/luasrc/controller/openclaw.lua b/luasrc/controller/openclaw.lua
index 4f44b87..e6b1621 100644
--- a/luasrc/controller/openclaw.lua
+++ b/luasrc/controller/openclaw.lua
@@ -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
- if plugin_current ~= "" and plugin_latest ~= "" and plugin_current ~= plugin_latest then
- plugin_has_update = true
+ -- 提取 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
+
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")
diff --git a/luasrc/model/cbi/openclaw/basic.lua b/luasrc/model/cbi/openclaw/basic.lua
index 794a16f..82282d1 100644
--- a/luasrc/model/cbi/openclaw/basic.lua
+++ b/luasrc/model/cbi/openclaw/basic.lua
@@ -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="❌ 错误";}'
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("⚠️ OpenClaw 运行环境未安装");}'
- html[#html+1] = 'else if(r.has_update){msgs.push("📦 OpenClaw: v"+r.current+" → v"+r.latest+" (有新版本)");}'
- html[#html+1] = 'else{msgs.push("✅ OpenClaw: v"+r.current+" (已是最新)");}'
-- 插件版本检查
html[#html+1] = 'if(r.plugin_current){'
html[#html+1] = 'if(r.plugin_has_update){msgs.push("🔌 插件: v"+r.plugin_current+" → v"+r.plugin_latest+" (有新版本)");}'
html[#html+1] = 'else if(r.plugin_latest){msgs.push("✅ 插件: v"+r.plugin_current+" (已是最新)");}'
html[#html+1] = 'else{msgs.push("🔌 插件: v"+r.plugin_current+" (无法检查最新版本)");}'
html[#html+1] = '}'
+ html[#html+1] = 'if(msgs.length===0)msgs.push("无法获取版本信息");'
html[#html+1] = 'el.innerHTML=msgs.join("
");'
- -- 显示 OpenClaw 升级按钮
- html[#html+1] = 'if(r.has_update){'
- html[#html+1] = 'act.style.display="block";'
- html[#html+1] = 'act.innerHTML=\'\';'
- 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||"")+\' \';'
- html[#html+1] = 'act.innerHTML=act.innerHTML+\' 📥 手动下载\';'
+ html[#html+1] = 'var notesHtml="";'
+ html[#html+1] = 'if(r.release_notes){'
+ html[#html+1] = 'var escaped=r.release_notes.replace(/&/g,"&").replace(//g,">");'
+ html[#html+1] = 'notesHtml=\'
\'+escaped+\'\'' + html[#html+1] = '+\'
cat /tmp/openclaw-upgrade.log