mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 13:53:56 +08:00
💐 Sync 2026-07-09 02:25:04
This commit is contained in:
1 parent
f077ddaf47
commit
2af7926aeb
37 files changed
+597
-329
No files matched your search
@@ -13,6 +13,8 @@
|
||||
- 兼容没有 `su` / `runuser` 的 OpenWrt 固件,微信安装、升级、登录和下线改用 `start-stop-daemon` 兜底以 `openclaw` 用户执行。
|
||||
- 微信安装网络探测优先使用 `curl`,避免低内存/精简 musl 固件上 Node `fetch` 触发 undici Wasm OOM。
|
||||
- 微信官方 CLI 安装触发 undici Wasm OOM 时,自动改用 npm 直装到 OpenClaw `npm/projects` 并继续注册插件配置。
|
||||
- 微信插件安装/升级不再预先停止 Gateway,避免反复安装触发 procd crash-loop。
|
||||
- LuCI 状态页和 `status_service` 增强 procd 状态识别,能区分真实启动中、stale pidfile 和 crash-loop 抑制,不再误显示“正在启动”。
|
||||
- 微信登录前补充 Node、python3、插件目录、账号状态目录和配置写权限检查,并清理残留登录进程与旧二维码状态。
|
||||
- 登录失败时在 LuCI 页面展示真实日志详情,不再只显示“登录失败”。
|
||||
- 二维码链接提取更稳,页面明确提示“点击链接后用微信扫码”。
|
||||
|
||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-openclaw
|
||||
PKG_VERSION:=$(strip $(shell cat $(CURDIR)/VERSION 2>/dev/null || echo "1.0.0"))
|
||||
PKG_RELEASE:=20
|
||||
PKG_RELEASE:=21
|
||||
|
||||
PKG_MAINTAINER:=10000ge10000 <10000ge10000@users.noreply.github.com>
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
@@ -85,6 +85,21 @@ define Package/$(PKG_NAME)/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
( . /etc/uci-defaults/99-openclaw ) && rm -f /etc/uci-defaults/99-openclaw
|
||||
OPENCLAW_INSTALL_BASE="$$(uci -q get openclaw.main.install_path 2>/dev/null || echo /opt)"
|
||||
if [ -r /usr/libexec/openclaw-paths.sh ]; then
|
||||
. /usr/libexec/openclaw-paths.sh
|
||||
oc_load_paths "$${OPENCLAW_INSTALL_BASE}" 2>/dev/null || true
|
||||
else
|
||||
OPENCLAW_INSTALL_BASE="$${OPENCLAW_INSTALL_BASE%/}"
|
||||
OC_DATA="$${OPENCLAW_INSTALL_BASE}/openclaw/data"
|
||||
fi
|
||||
if [ -n "$${OC_DATA:-}" ] && [ -d "$${OC_DATA}/.openclaw" ] && [ -x /usr/libexec/openclaw-permissions.sh ]; then
|
||||
/usr/libexec/openclaw-permissions.sh fix-state "$${OC_DATA}/.openclaw" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [ "$$(uci -q get openclaw.main.enabled 2>/dev/null || echo 0)" = "1" ] && [ -x /etc/init.d/openclaw ]; then
|
||||
/etc/init.d/openclaw enable >/dev/null 2>&1 || true
|
||||
/etc/init.d/openclaw start >/dev/null 2>&1 || true
|
||||
fi
|
||||
rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* 2>/dev/null
|
||||
exit 0
|
||||
}
|
||||
|
||||
@@ -191,6 +191,7 @@ fs.writeFileSync(configPath, JSON.stringify(d, null, 2) + '\n');
|
||||
"REG_RC=$?; " ..
|
||||
"if [ $REG_RC -eq 0 ]; then " ..
|
||||
"chown openclaw:openclaw " .. shellquote(config_file) .. " 2>/dev/null; " ..
|
||||
"[ -x /usr/libexec/openclaw-permissions.sh ] && /usr/libexec/openclaw-permissions.sh fix-state " .. shellquote(oc_data .. "/.openclaw") .. " >/dev/null 2>&1; " ..
|
||||
"echo 'Registered openclaw-weixin npm plugin in OpenClaw config.' >> " .. shellquote(log_file) .. "; " ..
|
||||
"else RC=$REG_RC; echo $RC > " .. shellquote(exit_file) .. "; echo 'Failed to register openclaw-weixin npm plugin in OpenClaw config.' >> " .. shellquote(log_file) .. "; fi; " ..
|
||||
"else RC=127; echo $RC > " .. shellquote(exit_file) .. "; echo 'Node.js not found, cannot register openclaw-weixin plugin.' >> " .. shellquote(log_file) .. "; fi; " ..
|
||||
@@ -238,7 +239,13 @@ const timer = setTimeout(() => controller.abort(new Error('timeout')), 10000);
|
||||
end
|
||||
|
||||
local function openclaw_user_runner_cmd()
|
||||
return "_oc_as_openclaw() { " ..
|
||||
return "_oc_raise_openclaw_limits() { " ..
|
||||
"ulimit -v unlimited 2>/dev/null || true; " ..
|
||||
"ulimit -m unlimited 2>/dev/null || true; " ..
|
||||
"ulimit -d unlimited 2>/dev/null || true; " ..
|
||||
"}; " ..
|
||||
"_oc_as_openclaw() { " ..
|
||||
"_oc_raise_openclaw_limits; " ..
|
||||
"if command -v su >/dev/null 2>&1; then su -s /bin/sh openclaw -c \"$1\"; " ..
|
||||
"elif command -v runuser >/dev/null 2>&1; then runuser -u openclaw -- sh -c \"$1\"; " ..
|
||||
"elif command -v start-stop-daemon >/dev/null 2>&1; then _oc_pid=/tmp/openclaw-user-$$.pid; _oc_cwd=$(pwd); rm -f \"$_oc_pid\"; start-stop-daemon -S -m -p \"$_oc_pid\" -c openclaw:openclaw -d \"$_oc_cwd\" -x /bin/sh -- -c \"$1\"; _oc_rc=$?; rm -f \"$_oc_pid\"; return $_oc_rc; " ..
|
||||
@@ -267,6 +274,25 @@ local function wechat_npm_fallback_install_cmd(install_path, log_file, exit_file
|
||||
"fi; "
|
||||
end
|
||||
|
||||
local function wechat_npm_direct_install_cmd(install_path, log_file, exit_file)
|
||||
local package_json = "{\n \"private\": true,\n \"dependencies\": {\n \"@tencent-weixin/openclaw-weixin\": \"latest\"\n }\n}\n"
|
||||
return "echo '使用 npm 直装微信插件,避免官方安装器进入扫码等待...' >> " .. shellquote(log_file) .. "; " ..
|
||||
"OC_WECHAT_NPM_PROJECT=\"$OC_WECHAT_DATA/.openclaw/npm/projects/tencent-weixin-openclaw-weixin-7783ac86ba\"; " ..
|
||||
"mkdir -p \"$OC_WECHAT_NPM_PROJECT\" \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/npm/projects\"; " ..
|
||||
"chown -R openclaw:openclaw \"$OC_WECHAT_NPM_PROJECT\" \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/npm/projects\" 2>/dev/null; " ..
|
||||
"cat > \"$OC_WECHAT_NPM_PROJECT/package.json\" <<'OC_WECHAT_PACKAGE_JSON'\n" ..
|
||||
package_json ..
|
||||
"OC_WECHAT_PACKAGE_JSON\n" ..
|
||||
"chown openclaw:openclaw \"$OC_WECHAT_NPM_PROJECT/package.json\" 2>/dev/null; " ..
|
||||
"cd \"$OC_WECHAT_NPM_PROJECT\" && " ..
|
||||
"_oc_as_openclaw 'HOME=$OC_WECHAT_DATA OPENCLAW_HOME=$OC_WECHAT_DATA OPENCLAW_STATE_DIR=$OC_WECHAT_DATA/.openclaw OPENCLAW_CONFIG_PATH=$OC_WECHAT_DATA/.openclaw/openclaw.json " ..
|
||||
"NODE_ICU_DATA=" .. install_path .. "/node/share/icu NPM_CONFIG_CACHE=$OC_WECHAT_DATA/.npm npm_config_cache=$OC_WECHAT_DATA/.npm TMPDIR=$OC_WECHAT_DATA/.tmp " ..
|
||||
"PATH=" .. install_path .. "/node/bin:" .. install_path .. "/global/bin:$PATH " ..
|
||||
"npm install --omit=dev --omit=peer --legacy-peer-deps --no-audit --no-fund --loglevel=error' >> " .. shellquote(log_file) .. " 2>&1; " ..
|
||||
"RC=$?; echo $RC > " .. shellquote(exit_file) .. "; " ..
|
||||
"if [ $RC -eq 0 ]; then echo '✅ npm 直装微信插件完成' >> " .. shellquote(log_file) .. "; else echo '❌ npm 直装微信插件失败 (exit: '$RC')' >> " .. shellquote(log_file) .. "; fi; "
|
||||
end
|
||||
|
||||
local function wechat_tail_detail(text, max_lines)
|
||||
if not text or text == "" then
|
||||
return ""
|
||||
@@ -524,21 +550,36 @@ function action_status()
|
||||
local gw_check = sys.exec(gw_check_cmd):gsub("%s+", "")
|
||||
result.gateway_running = (tonumber(gw_check) or 0) > 0
|
||||
|
||||
-- 如果端口未监听但 procd 进程存在,说明正在启动中 (gateway 初始化需要数分钟)
|
||||
-- 如果端口未监听,结合 procd 与真实进程判断状态。
|
||||
-- 不能只看 pid 字段或 pidfile:procd crash-loop / stale pidfile 会让 LuCI 误显示“正在启动”。
|
||||
if not result.gateway_running and enabled == "1" then
|
||||
local procd_pid = sys.exec("ubus call service list '{\"name\":\"openclaw\"}' 2>/dev/null | jsonfilter -e '$.openclaw.instances.gateway.pid' 2>/dev/null"):gsub("%s+", "")
|
||||
local procd_running = sys.exec("ubus call service list '{\"name\":\"openclaw\"}' 2>/dev/null | jsonfilter -e '$.openclaw.instances.gateway.running' 2>/dev/null"):gsub("%s+", "")
|
||||
local procd_exit = sys.exec("ubus call service list '{\"name\":\"openclaw\"}' 2>/dev/null | jsonfilter -e '$.openclaw.instances.gateway.exit_code' 2>/dev/null"):gsub("%s+", "")
|
||||
if procd_pid == "null" or not procd_pid:match("^%d+$") then procd_pid = "" end
|
||||
if procd_exit == "null" then procd_exit = "" end
|
||||
result.gateway_exit_code = procd_exit
|
||||
|
||||
local procd_pid_alive = false
|
||||
if procd_pid ~= "" then
|
||||
procd_pid_alive = (sys.exec("[ -d /proc/" .. procd_pid .. " ] && echo 1 || echo 0"):gsub("%s+", "") == "1")
|
||||
end
|
||||
local pidfile_pid = sys.exec("cat /var/run/openclaw.pid 2>/dev/null || true"):gsub("%s+", "")
|
||||
local pidfile_stale = false
|
||||
if pidfile_pid ~= "" and pidfile_pid:match("^%d+$") then
|
||||
pidfile_stale = (sys.exec("[ -d /proc/" .. pidfile_pid .. " ] && echo 0 || echo 1"):gsub("%s+", "") == "1")
|
||||
end
|
||||
local crash_loop = sys.exec("logread 2>/dev/null | grep -E 'Instance openclaw::gateway.*crash loop' | tail -1"):gsub("^%s+", ""):gsub("%s+$", "")
|
||||
|
||||
if procd_exit ~= "" and tonumber(procd_exit) and tonumber(procd_exit) ~= 0 and procd_running ~= "true" then
|
||||
result.gateway_failed = true
|
||||
elseif procd_pid ~= "" or procd_running == "true" then
|
||||
elseif crash_loop ~= "" and pidfile_stale and procd_running ~= "true" and not procd_pid_alive then
|
||||
result.gateway_failed = true
|
||||
result.gateway_crash_loop = true
|
||||
if result.gateway_exit_code == "" then result.gateway_exit_code = "crash-loop" end
|
||||
elseif procd_running == "true" or procd_pid_alive then
|
||||
result.gateway_starting = true
|
||||
else
|
||||
local fallback_pid = sys.exec("pgrep -f 'openclaw.*gateway' 2>/dev/null | head -1"):gsub("%s+", "")
|
||||
if fallback_pid ~= "" then
|
||||
result.gateway_starting = true
|
||||
end
|
||||
result.pid = procd_pid
|
||||
end
|
||||
end
|
||||
|
||||
@@ -637,10 +678,14 @@ function action_service_ctl()
|
||||
-- stop 后额外等待确保端口释放
|
||||
sys.exec("sleep 2")
|
||||
elseif action == "restart" then
|
||||
-- 先完整 stop (确保端口释放),再后台 start
|
||||
sys.exec("/etc/init.d/openclaw stop >/dev/null 2>&1")
|
||||
sys.exec("sleep 2")
|
||||
sys.exec("/etc/init.d/openclaw start >/dev/null 2>&1 &")
|
||||
-- 常规“重启”只重启 Gateway,不重启 Web PTY,避免 stop+start 带来的长时间等待。
|
||||
-- 如果 procd 没有 gateway 实例,再回退到 start。
|
||||
local procd_running = sys.exec("ubus call service list '{\"name\":\"openclaw\"}' 2>/dev/null | jsonfilter -e '$.openclaw.instances.gateway.running' 2>/dev/null"):gsub("%s+", "")
|
||||
if procd_running == "true" then
|
||||
sys.exec("/etc/init.d/openclaw restart_gateway >/dev/null 2>&1 &")
|
||||
else
|
||||
sys.exec("/etc/init.d/openclaw start >/dev/null 2>&1 &")
|
||||
end
|
||||
elseif action == "enable" then
|
||||
sys.exec("/etc/init.d/openclaw enable 2>/dev/null")
|
||||
elseif action == "disable" then
|
||||
@@ -1549,10 +1594,7 @@ function action_wechat_install()
|
||||
return
|
||||
end
|
||||
|
||||
-- 后台执行安装
|
||||
-- 在启动安装前,确保网关端口可用(自动清理残留 gateway 进程)
|
||||
local port = uci:get("openclaw", "main", "port") or "18789"
|
||||
ensure_port_free(port)
|
||||
-- 后台执行安装。注意:插件安装不需要释放 Gateway 端口,避免误停正在运行的 Gateway 触发 procd crash-loop。
|
||||
-- 微信插件安装目录路径 (用于安装后权限修复)
|
||||
local extensions_dir = install_path .. "/data/.openclaw/extensions"
|
||||
local install_cmd = string.format(
|
||||
@@ -1569,13 +1611,7 @@ function action_wechat_install()
|
||||
"else mkdir -p \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/extensions\"; chown -R openclaw:openclaw \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" 2>/dev/null; chown openclaw:openclaw \"$OC_WECHAT_DATA/.openclaw\" 2>/dev/null; fi; " ..
|
||||
"if [ ! -w %s/.npm ] || [ ! -w %s/.tmp ]; then echo '❌ npm cache/tmp 目录不可写' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; fi; " ..
|
||||
"_oc_as_openclaw 'test -w %s/.npm && test -w %s/.tmp && test -w %s/.openclaw' || { echo '❌ openclaw 用户无法写入 npm cache/tmp/data 目录' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; }; " ..
|
||||
"cd %s && " ..
|
||||
"_oc_as_openclaw 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw " ..
|
||||
"OPENCLAW_CONFIG_PATH=%s/.openclaw/openclaw.json NPM_CONFIG_CACHE=%s/.npm npm_config_cache=%s/.npm TMPDIR=%s/.tmp " ..
|
||||
"PATH=%s/node/bin:%s/global/bin:$PATH " ..
|
||||
"%s -y @tencent-weixin/openclaw-weixin-cli install' >> /tmp/openclaw-wechat-install.log 2>&1; " ..
|
||||
"RC=$?; echo $RC > /tmp/openclaw-wechat-install.exit; " ..
|
||||
wechat_npm_fallback_install_cmd(install_path, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
|
||||
wechat_npm_direct_install_cmd(install_path, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
|
||||
wechat_register_plugin_cmd(install_path, node_bin, "/tmp/openclaw-wechat-install.log") ..
|
||||
-- 关键修复: 安装完成后强制修复插件目录权限 (确保 Gateway 可读取插件)
|
||||
-- 原因: npx/npm 以 root 身份创建目录,默认权限 700 导致其他用户无法读取
|
||||
@@ -1589,8 +1625,6 @@ function action_wechat_install()
|
||||
oc_data, oc_data,
|
||||
oc_data, oc_data, oc_data,
|
||||
install_path, oc_data, oc_data, oc_data,
|
||||
oc_data, oc_data, oc_data, oc_data,
|
||||
install_path, install_path, npx_bin,
|
||||
oc_data
|
||||
)
|
||||
sys.exec(install_cmd)
|
||||
@@ -1731,15 +1765,23 @@ function action_wechat_login()
|
||||
"if [ $RC -ne 0 ]; then echo '❌ 微信插件注册失败,无法登录' >> /tmp/openclaw-wechat-qrcode.txt; exit 0; fi; " ..
|
||||
"cd %s && " ..
|
||||
"_oc_as_openclaw 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw OPENCLAW_CONFIG_PATH=%s/.openclaw/openclaw.json " ..
|
||||
"NODE_ICU_DATA=%s/node/share/icu " ..
|
||||
"NPM_CONFIG_CACHE=%s/.npm npm_config_cache=%s/.npm TMPDIR=%s/.tmp PATH=%s/node/bin:%s/global/bin:$PATH " ..
|
||||
"%s %s channels login --channel openclaw-weixin' >> /tmp/openclaw-wechat-qrcode.txt 2>&1; " ..
|
||||
"echo $? > /tmp/openclaw-wechat-login.exit; " ..
|
||||
") >/dev/null 2>&1 & echo $! > /tmp/openclaw-wechat-login.pid",
|
||||
install_path, oc_entry, wechat_plugin_dir, node_bin,
|
||||
oc_data, oc_data, oc_data, oc_data, oc_data, oc_data, oc_data,
|
||||
oc_data, oc_data, oc_data, oc_data, oc_data, oc_data, oc_data,
|
||||
oc_data, oc_data, oc_data, oc_data, oc_data, oc_data, oc_data, oc_data,
|
||||
install_path, install_path, node_bin, oc_entry
|
||||
oc_data, oc_data, oc_data,
|
||||
oc_data,
|
||||
oc_data, oc_data, oc_data,
|
||||
oc_data, oc_data,
|
||||
oc_data, oc_data, oc_data, oc_data, oc_data,
|
||||
install_path,
|
||||
oc_data, oc_data, oc_data, oc_data,
|
||||
install_path,
|
||||
oc_data, oc_data, oc_data,
|
||||
install_path, install_path,
|
||||
node_bin, oc_entry
|
||||
)
|
||||
sys.exec(login_cmd)
|
||||
|
||||
@@ -1798,8 +1840,15 @@ function action_wechat_login_status()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 检查是否登录成功
|
||||
local logged_in = qrcode:find("登录成功") ~= nil or qrcode:find("成功登录") ~= nil or qrcode:find("Login success") ~= nil or qrcode:find("Logged in") ~= nil
|
||||
-- 检查是否登录成功。微信插件在 OpenClaw 2026.6.11 中可能已经保存认证,
|
||||
-- 但随后通过 Gateway 动态启动渠道时报 "invalid channels.start channel" 并返回
|
||||
-- 非 0;这种情况账号已配对成功,LuCI 不应误判为失败。
|
||||
local logged_in = qrcode:find("登录成功") ~= nil
|
||||
or qrcode:find("成功登录") ~= nil
|
||||
or qrcode:find("Login success") ~= nil
|
||||
or qrcode:find("Logged in") ~= nil
|
||||
or qrcode:find("已将此 OpenClaw 连接到微信") ~= nil
|
||||
or qrcode:find("Local login saved auth for openclaw%-weixin") ~= nil
|
||||
|
||||
local state = "idle"
|
||||
if logged_in then
|
||||
@@ -1825,10 +1874,11 @@ function action_wechat_login_status()
|
||||
end
|
||||
end
|
||||
|
||||
-- 如果刚登录成功,触发一次重启,确保主进程加载微信账号
|
||||
-- 如果刚登录成功,触发一次轻量重启,确保主进程加载微信账号。
|
||||
-- 不使用完整 /etc/init.d/openclaw restart,避免同时重启 Web PTY 和拉长等待时间。
|
||||
if state == "success" and not nixio.fs.stat("/tmp/openclaw-wechat-restarted", "type") then
|
||||
sys.exec("touch /tmp/openclaw-wechat-restarted")
|
||||
sys.exec("/etc/init.d/openclaw restart &")
|
||||
sys.exec("/etc/init.d/openclaw restart_gateway >/dev/null 2>&1 &")
|
||||
message = "微信登录成功,正在重新加载微信账号"
|
||||
end
|
||||
http.prepare_content("application/json")
|
||||
@@ -2013,10 +2063,7 @@ function action_wechat_upgrade_plugin()
|
||||
return
|
||||
end
|
||||
|
||||
-- 后台执行升级 (其实就是重新安装最新版)
|
||||
-- 在启动升级前,确保网关端口可用(自动清理残留 gateway 进程)
|
||||
local port = uci:get("openclaw", "main", "port") or "18789"
|
||||
ensure_port_free(port)
|
||||
-- 后台执行升级 (其实就是重新安装最新版)。不要释放 Gateway 端口,避免误停正在运行的 Gateway。
|
||||
-- 微信插件安装目录路径 (用于升级后权限修复)
|
||||
local extensions_dir = install_path .. "/data/.openclaw/extensions"
|
||||
local upgrade_cmd = string.format(
|
||||
@@ -2033,13 +2080,7 @@ function action_wechat_upgrade_plugin()
|
||||
"else mkdir -p \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/extensions\"; chown -R openclaw:openclaw \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" 2>/dev/null; chown openclaw:openclaw \"$OC_WECHAT_DATA/.openclaw\" 2>/dev/null; fi; " ..
|
||||
"if [ ! -w %s/.npm ] || [ ! -w %s/.tmp ]; then echo '❌ npm cache/tmp 目录不可写' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; fi; " ..
|
||||
"_oc_as_openclaw 'test -w %s/.npm && test -w %s/.tmp && test -w %s/.openclaw' || { echo '❌ openclaw 用户无法写入 npm cache/tmp/data 目录' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; }; " ..
|
||||
"cd %s && " ..
|
||||
"_oc_as_openclaw 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw " ..
|
||||
"OPENCLAW_CONFIG_PATH=%s/.openclaw/openclaw.json NPM_CONFIG_CACHE=%s/.npm npm_config_cache=%s/.npm TMPDIR=%s/.tmp " ..
|
||||
"PATH=%s/node/bin:%s/global/bin:$PATH " ..
|
||||
"%s -y @tencent-weixin/openclaw-weixin-cli install' >> /tmp/openclaw-wechat-install.log 2>&1; " ..
|
||||
"RC=$?; echo $RC > /tmp/openclaw-wechat-install.exit; " ..
|
||||
wechat_npm_fallback_install_cmd(install_path, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
|
||||
wechat_npm_direct_install_cmd(install_path, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
|
||||
wechat_register_plugin_cmd(install_path, node_bin, "/tmp/openclaw-wechat-install.log") ..
|
||||
-- 关键修复: 升级完成后强制修复插件目录权限 (确保 Gateway 可读取插件)
|
||||
-- 注意: 保持 root:root 属主 (OpenClaw v2026.4.9+ 安全要求),仅修复权限模式
|
||||
@@ -2052,8 +2093,6 @@ function action_wechat_upgrade_plugin()
|
||||
oc_data, oc_data,
|
||||
oc_data, oc_data, oc_data,
|
||||
install_path, oc_data, oc_data, oc_data,
|
||||
oc_data, oc_data, oc_data, oc_data,
|
||||
install_path, install_path, npx_bin,
|
||||
oc_data
|
||||
)
|
||||
sys.exec(upgrade_cmd)
|
||||
@@ -2114,10 +2153,10 @@ function action_wechat_logout()
|
||||
|
||||
-- 在后台执行 logout
|
||||
local logout_cmd = string.format(
|
||||
openclaw_user_runner_cmd() .. "cd %s && _oc_as_openclaw 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw OPENCLAW_CONFIG_PATH=%s/.openclaw/openclaw.json " ..
|
||||
openclaw_user_runner_cmd() .. "cd %s && _oc_as_openclaw 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw OPENCLAW_CONFIG_PATH=%s/.openclaw/openclaw.json NODE_ICU_DATA=%s/node/share/icu " ..
|
||||
"PATH=%s/node/bin:%s/global/bin:$PATH " ..
|
||||
"%s %s channels logout --channel openclaw-weixin --account \"%s\"'",
|
||||
oc_data, oc_data, oc_data, oc_data, oc_data, install_path, install_path, node_bin, oc_entry, account_id
|
||||
oc_data, oc_data, oc_data, oc_data, oc_data, install_path, install_path, install_path, node_bin, oc_entry, account_id
|
||||
)
|
||||
|
||||
sys.exec(logout_cmd .. " >/dev/null 2>&1")
|
||||
|
||||
@@ -149,7 +149,7 @@ local port = uci:get("openclaw", "main", "port") or "18789"
|
||||
loading.innerHTML = '<div style="text-align:center;color:#666;">' +
|
||||
'<div style="font-size:40px;margin-bottom:12px;">⏳</div>' +
|
||||
'<div style="font-size:15px;margin-bottom:6px;">OpenClaw 网关正在启动中...</div>' +
|
||||
'<div style="font-size:12px;color:#999;">首次启动可能需要 2~5 分钟,请耐心等待,页面会自动刷新。</div>' +
|
||||
'<div style="font-size:12px;color:#999;">通常 20~40 秒;首次安装或路由器负载较高时会更久,页面会自动刷新。</div>' +
|
||||
'</div>';
|
||||
} else {
|
||||
statusTextEl.innerHTML = '<span style="color:#cf222e;">● 网关未运行</span>';
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
if (d.gateway_running) {
|
||||
gwEl.innerHTML = '<span class="oc-dot oc-dot-green"></span>监听中 :' + d.port;
|
||||
} else if (d.gateway_starting) {
|
||||
gwEl.innerHTML = '<span class="oc-dot oc-dot-gray"></span>初始化中,首次启动可能需要 2~5 分钟...';
|
||||
gwEl.innerHTML = '<span class="oc-dot oc-dot-gray"></span>初始化中,通常 20~40 秒;首次安装或负载较高时会更久...';
|
||||
} else if (d.gateway_failed) {
|
||||
gwEl.innerHTML = '<span class="oc-dot oc-dot-red"></span>启动失败,退出码 ' + (d.gateway_exit_code || '-');
|
||||
} else {
|
||||
|
||||
@@ -448,7 +448,13 @@ if(changed){
|
||||
fi
|
||||
fix_openclaw_state_permissions 2>/dev/null || true
|
||||
|
||||
rm -rf /tmp/jiti 2>/dev/null || true
|
||||
# 不再每次启动都清理 /tmp/jiti。
|
||||
# OpenClaw 在低性能 OpenWrt 设备上依赖 JITI/模块缓存降低冷启动成本;
|
||||
# 每次 rm -rf 会让 gateway 在第一条 "starting..." 日志前重新编译/装载模块,
|
||||
# 实测会额外拉长 20 秒以上。需要强制清理时再显式打开 UCI 开关。
|
||||
if [ "$(uci -q get openclaw.main.clear_jiti_cache_on_start 2>/dev/null || echo 0)" = "1" ]; then
|
||||
rm -rf /tmp/jiti 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# v2026.4.10: 优化配置迁移 - 只在版本变更时运行 doctor --fix
|
||||
# 原因: doctor --fix 耗时 ~50 秒,每次重启都运行严重影响启动速度
|
||||
@@ -637,6 +643,13 @@ _ensure_port_free() {
|
||||
}
|
||||
_ensure_port_free "$port"
|
||||
|
||||
# Node 22 原生编译缓存。OpenClaw 主入口在路由器上首次 import/compile 较慢;
|
||||
# 保留该缓存可以显著缩短后续重启时 gateway 第一条日志前的等待时间。
|
||||
local node_compile_cache="/tmp/openclaw-node-compile-cache"
|
||||
mkdir -p "$node_compile_cache" 2>/dev/null || true
|
||||
chown openclaw:openclaw "$node_compile_cache" 2>/dev/null || true
|
||||
chmod 700 "$node_compile_cache" 2>/dev/null || true
|
||||
|
||||
# 启动 OpenClaw Gateway (主服务, 前台运行)
|
||||
# v2026.4.7/4.9: 环境变量安全验证 (阻止危险变量注入)
|
||||
_validate_path() {
|
||||
@@ -660,13 +673,15 @@ _ensure_port_free "$port"
|
||||
OPENCLAW_STATE_DIR="${OC_DATA}/.openclaw" \
|
||||
OPENCLAW_CONFIG_PATH="$CONFIG_FILE" \
|
||||
OPENCLAW_GATEWAY_TOKEN="$gw_token" \
|
||||
NODE_COMPILE_CACHE="$node_compile_cache" \
|
||||
NODE_ICU_DATA="${NODE_BASE}/share/icu" \
|
||||
NODE_BASE="$NODE_BASE" \
|
||||
OC_GLOBAL="$OC_GLOBAL" \
|
||||
OC_DATA="$OC_DATA" \
|
||||
PATH="${NODE_BASE}/bin:${OC_GLOBAL}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
procd_set_param user openclaw
|
||||
procd_set_param respawn 3600 10 5
|
||||
procd_set_param term_timeout 2
|
||||
procd_set_param respawn 3600 1 5
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param pidfile /var/run/openclaw.pid
|
||||
@@ -689,6 +704,7 @@ procd_set_param env \
|
||||
OC_CONFIG_PORT="$pty_port" \
|
||||
OC_PTY_TOKEN="$pty_token" \
|
||||
OC_CONFIG_SCRIPT="/usr/share/openclaw/oc-config.sh" \
|
||||
NODE_COMPILE_CACHE="$node_compile_cache" \
|
||||
NODE_ICU_DATA="${NODE_BASE}/share/icu" \
|
||||
NODE_BASE="$NODE_BASE" \
|
||||
OC_GLOBAL="$OC_GLOBAL" \
|
||||
@@ -699,6 +715,7 @@ OPENCLAW_STATE_DIR="${OC_DATA}/.openclaw" \
|
||||
OPENCLAW_CONFIG_PATH="$CONFIG_FILE" \
|
||||
PATH="${NODE_BASE}/bin:${OC_GLOBAL}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
procd_set_param respawn 3600 5 5
|
||||
procd_set_param term_timeout 2
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param pidfile /var/run/openclaw-pty.pid
|
||||
@@ -842,9 +859,10 @@ fi
|
||||
}
|
||||
|
||||
status_service() {
|
||||
local port pty_port
|
||||
local port pty_port enabled
|
||||
port=$(uci -q get openclaw.main.port || echo "18789")
|
||||
pty_port=$(uci -q get openclaw.main.pty_port || echo "18793")
|
||||
enabled=$(uci -q get openclaw.main.enabled || echo "0")
|
||||
|
||||
echo "=== OpenClaw 服务状态 ==="
|
||||
|
||||
@@ -908,10 +926,31 @@ local mins=$(( (uptime % 3600) / 60 ))
|
||||
echo "运行时间: ${hours}小时 ${mins}分钟"
|
||||
fi
|
||||
fi
|
||||
elif pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then
|
||||
echo "网关: 正在启动 (首次启动可能需要 2~5 分钟)"
|
||||
else
|
||||
echo "网关: 已停止"
|
||||
local procd_running procd_pid procd_exit procd_pid_alive pidfile_pid pidfile_stale crash_loop
|
||||
procd_running=$(ubus call service list '{"name":"openclaw"}' 2>/dev/null | jsonfilter -e '$.openclaw.instances.gateway.running' 2>/dev/null | tr -d '[:space:]')
|
||||
procd_pid=$(ubus call service list '{"name":"openclaw"}' 2>/dev/null | jsonfilter -e '$.openclaw.instances.gateway.pid' 2>/dev/null | tr -d '[:space:]')
|
||||
procd_exit=$(ubus call service list '{"name":"openclaw"}' 2>/dev/null | jsonfilter -e '$.openclaw.instances.gateway.exit_code' 2>/dev/null | tr -d '[:space:]')
|
||||
[ "$procd_pid" = "null" ] && procd_pid=""
|
||||
[ "$procd_exit" = "null" ] && procd_exit=""
|
||||
procd_pid_alive=0
|
||||
[ -n "$procd_pid" ] && [ -d "/proc/$procd_pid" ] && procd_pid_alive=1
|
||||
pidfile_pid=$(cat /var/run/openclaw.pid 2>/dev/null | tr -d '[:space:]')
|
||||
pidfile_stale=0
|
||||
[ -n "$pidfile_pid" ] && [ ! -d "/proc/$pidfile_pid" ] && pidfile_stale=1
|
||||
crash_loop=$(logread 2>/dev/null | grep -E 'Instance openclaw::gateway.*crash loop' | tail -1)
|
||||
if [ "$enabled" != "1" ]; then
|
||||
echo "网关: 已禁用"
|
||||
elif [ -n "$procd_exit" ] && [ "$procd_exit" != "0" ] && [ "$procd_running" != "true" ]; then
|
||||
echo "网关: 启动失败 (退出码 $procd_exit)"
|
||||
elif [ -n "$crash_loop" ] && [ "$pidfile_stale" = "1" ] && [ "$procd_running" != "true" ] && [ "$procd_pid_alive" != "1" ]; then
|
||||
echo "网关: 启动失败 (procd crash-loop 抑制)"
|
||||
elif [ "$procd_running" = "true" ] || [ "$procd_pid_alive" = "1" ]; then
|
||||
echo "网关: 正在启动 (通常 20~40 秒,首次安装或负载较高时会更久)"
|
||||
[ -n "$procd_pid" ] && echo "进程ID: $procd_pid"
|
||||
else
|
||||
echo "网关: 已停止"
|
||||
fi
|
||||
fi
|
||||
|
||||
# PTY port
|
||||
|
||||
@@ -229,6 +229,35 @@ assert_node_runtime() {
|
||||
if command -v oc_assert_node_min_version >/dev/null 2>&1; then
|
||||
oc_assert_node_min_version "$NODE_BIN" "$required" || exit 1
|
||||
fi
|
||||
|
||||
# OpenClaw CLI 依赖 Unicode property escapes(例如 \p{Extended_Pictographic})。
|
||||
# ARM64 musl 自托管 Node 包必须带上 NODE_ICU_DATA,否则用户直接执行
|
||||
# `openclaw status` 等子命令会在 CLI 入口阶段抛 SyntaxError。
|
||||
if ! NODE_ICU_DATA="${NODE_BASE}/share/icu" "$NODE_BIN" -e "new RegExp('\\\\p{Extended_Pictographic}','u')" >/dev/null 2>&1; then
|
||||
log_error "Node.js ICU/Unicode 正则能力异常,请重新安装 Node.js 运行时"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
install_openclaw_cli_wrapper() {
|
||||
local oc_entry
|
||||
oc_entry=$(find_oc_entry)
|
||||
[ -n "$oc_entry" ] || return 1
|
||||
ensure_mkdir "$OC_GLOBAL/bin"
|
||||
# npm 默认生成的 openclaw 可能是指向 openclaw.mjs 的 symlink。
|
||||
# 写 wrapper 前必须先 unlink,否则重定向会顺着 symlink 覆盖真实 CLI 入口。
|
||||
rm -f "$OC_GLOBAL/bin/openclaw" 2>/dev/null || true
|
||||
cat > "$OC_GLOBAL/bin/openclaw" << EOF
|
||||
#!/bin/sh
|
||||
export HOME="${OC_DATA}"
|
||||
export OPENCLAW_HOME="${OC_DATA}"
|
||||
export OPENCLAW_STATE_DIR="${OC_DATA}/.openclaw"
|
||||
export OPENCLAW_CONFIG_PATH="${OC_DATA}/.openclaw/openclaw.json"
|
||||
export NODE_ICU_DATA="${NODE_BASE}/share/icu"
|
||||
export PATH="${NODE_BASE}/bin:${OC_GLOBAL}/bin:\$PATH"
|
||||
exec "${NODE_BIN}" "${oc_entry}" "\$@"
|
||||
EOF
|
||||
chmod +x "$OC_GLOBAL/bin/openclaw" 2>/dev/null || true
|
||||
}
|
||||
|
||||
detect_arch() {
|
||||
@@ -471,6 +500,7 @@ install_openclaw() {
|
||||
fi
|
||||
|
||||
if [ -n "$oc_ver" ]; then
|
||||
install_openclaw_cli_wrapper || true
|
||||
log_info "OpenClaw v${oc_ver} 安装成功"
|
||||
assert_node_runtime
|
||||
else
|
||||
@@ -510,6 +540,7 @@ do_setup() {
|
||||
|
||||
# 检查是否已安装
|
||||
if [ -x "$NODE_BIN" ] && [ -n "$(find_oc_entry)" ]; then
|
||||
install_openclaw_cli_wrapper || true
|
||||
local oc_ver=""
|
||||
local oc_entry="$(find_oc_entry)"
|
||||
local oc_pkg_dir="$(dirname "$oc_entry")"
|
||||
@@ -665,6 +696,7 @@ do_upgrade() {
|
||||
|
||||
echo ""
|
||||
if [ -n "$new_ver" ]; then
|
||||
install_openclaw_cli_wrapper || true
|
||||
assert_node_runtime
|
||||
if [ "$current_ver" = "$new_ver" ]; then
|
||||
log_info "当前已是最新版本 v${new_ver}"
|
||||
@@ -827,6 +859,7 @@ do_setup_offline() {
|
||||
local oc_entry=$(find_oc_entry)
|
||||
if [ -n "$oc_entry" ]; then
|
||||
local oc_ver=$("$NODE_BIN" "$oc_entry" --version 2>/dev/null | tr -d '[:space:]')
|
||||
install_openclaw_cli_wrapper || true
|
||||
log_info "OpenClaw v${oc_ver} 安装成功"
|
||||
assert_node_runtime
|
||||
else
|
||||
|
||||
@@ -338,7 +338,15 @@ async function restartGateway() {
|
||||
console.log(`\n${C.yellow}正在重启 Gateway...${C.reset}`);
|
||||
|
||||
try {
|
||||
await runCommand('/etc/init.d/openclaw', ['restart_gateway']);
|
||||
await runCommand('/bin/sh', ['-c', [
|
||||
"if [ \"$(uci -q get openclaw.main.enabled 2>/dev/null || echo 0)\" != \"1\" ]; then",
|
||||
" uci -q set openclaw.main.enabled='1';",
|
||||
" uci -q commit openclaw;",
|
||||
" /etc/init.d/openclaw enable >/dev/null 2>&1 || true;",
|
||||
'fi;',
|
||||
'/etc/init.d/openclaw restart_gateway >/dev/null 2>&1 || true;',
|
||||
'/etc/init.d/openclaw start >/dev/null 2>&1 || true'
|
||||
].join(' ')]);
|
||||
} catch {}
|
||||
|
||||
const spin = spinner({ text: 'Gateway 启动中,请稍候 (约 15-30 秒)...' });
|
||||
|
||||
@@ -558,12 +558,22 @@ restart_gateway() {
|
||||
# 修复数据目录权限 (root 用户操作可能改变了文件属主)
|
||||
fix_openclaw_state_permissions 2>/dev/null || true
|
||||
|
||||
# 首次安装后 UCI 默认保持 disabled。用户在配置向导中确认“立即重启”
|
||||
# 即表示希望当前配置生效,这里同步启用服务,避免提示重启但实际仍为“已禁用”。
|
||||
if [ "$(uci -q get openclaw.main.enabled 2>/dev/null || echo 0)" != "1" ]; then
|
||||
echo -e " ${CYAN}检测到 Gateway 未启用,正在启用服务...${NC}"
|
||||
uci -q set openclaw.main.enabled='1' 2>/dev/null || true
|
||||
uci -q commit openclaw 2>/dev/null || true
|
||||
/etc/init.d/openclaw enable >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
local port
|
||||
port=$(json_get gateway.port)
|
||||
port=${port:-18789}
|
||||
|
||||
# ── kill gateway 进程,让 procd respawn ──
|
||||
/etc/init.d/openclaw restart_gateway >/dev/null 2>&1
|
||||
/etc/init.d/openclaw start >/dev/null 2>&1
|
||||
|
||||
# ── 等待端口恢复 (最多 30 秒,含端口释放 + Node.js 冷启动) ──
|
||||
echo -e " ${YELLOW}⏳ Gateway 启动中,请稍候 (约 15-30 秒)...${NC}"
|
||||
|
||||
@@ -94,7 +94,9 @@ chmod +x "$DATA_DIR/etc/profile.d/openclaw.sh"
|
||||
# 计算安装大小
|
||||
INSTALLED_SIZE=$(du -sk "$DATA_DIR" | awk '{print $1}')
|
||||
|
||||
(cd "$DATA_DIR" && tar czf "$STAGING/data.tar.gz" .)
|
||||
# 强制 data.tar.gz 内文件归属为 root:root,避免 GitHub runner / 本地构建用户
|
||||
# 的 UID/GID 泄漏到用户机器(例如安装后出现 1001:1001)。
|
||||
(cd "$DATA_DIR" && tar --owner=0 --group=0 --numeric-owner -czf "$STAGING/data.tar.gz" .)
|
||||
|
||||
# ── 构建 control.tar.gz ──
|
||||
CTRL_DIR="$STAGING/control"
|
||||
@@ -169,10 +171,48 @@ cat > "$CTRL_DIR/postinst" << 'EOF'
|
||||
|
||||
# 清理 LuCI 缓存
|
||||
rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* /tmp/luci-indexcache.*.json 2>/dev/null
|
||||
|
||||
# 双保险:确保系统侧文件保持 root:root,避免非 SDK 打包时构建机 UID/GID
|
||||
# 泄漏到目标机器。不要触碰 /opt/openclaw 运行数据。
|
||||
for p in \
|
||||
/etc/init.d/openclaw \
|
||||
/etc/profile.d/openclaw.sh \
|
||||
/usr/bin/openclaw-env \
|
||||
/usr/libexec/openclaw-permissions.sh \
|
||||
/usr/lib/lua/luci/controller/openclaw.lua \
|
||||
/usr/lib/lua/luci/model/cbi/openclaw \
|
||||
/usr/lib/lua/luci/view/openclaw \
|
||||
/usr/lib/lua/openclaw \
|
||||
/usr/share/openclaw \
|
||||
/usr/share/rpcd/acl.d/luci-app-openclaw.json
|
||||
do
|
||||
[ -e "$p" ] && chown -R root:root "$p" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# 升级/重装后修复已存在的 OpenClaw 运行数据权限。尤其是 npm 外部插件:
|
||||
# npm 安装阶段需要 openclaw 可写,运行阶段插件源码目录必须 root:root,
|
||||
# 否则 OpenClaw 会因为 suspicious ownership 拒绝加载微信插件。
|
||||
OPENCLAW_INSTALL_BASE="$(uci -q get openclaw.main.install_path 2>/dev/null || echo /opt)"
|
||||
if [ -r /usr/libexec/openclaw-paths.sh ]; then
|
||||
. /usr/libexec/openclaw-paths.sh
|
||||
oc_load_paths "$OPENCLAW_INSTALL_BASE" 2>/dev/null || true
|
||||
else
|
||||
OPENCLAW_INSTALL_BASE="${OPENCLAW_INSTALL_BASE%/}"
|
||||
OC_DATA="${OPENCLAW_INSTALL_BASE}/openclaw/data"
|
||||
fi
|
||||
if [ -n "${OC_DATA:-}" ] && [ -d "${OC_DATA}/.openclaw" ] && [ -x /usr/libexec/openclaw-permissions.sh ]; then
|
||||
/usr/libexec/openclaw-permissions.sh fix-state "${OC_DATA}/.openclaw" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# 重启 Web PTY (使其加载新文件和新 token)
|
||||
PTY_PID=$(pgrep -f 'web-pty.js' 2>/dev/null | head -1)
|
||||
[ -n "$PTY_PID" ] && kill "$PTY_PID" 2>/dev/null || true
|
||||
|
||||
# 如果用户原本启用了 OpenClaw,opkg reinstall/upgrade 后恢复服务。
|
||||
if [ "$(uci -q get openclaw.main.enabled 2>/dev/null || echo 0)" = "1" ] && [ -x /etc/init.d/openclaw ]; then
|
||||
/etc/init.d/openclaw enable >/dev/null 2>&1 || true
|
||||
/etc/init.d/openclaw start >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
@@ -132,6 +132,24 @@ echo "正在安装文件..."
|
||||
ARCHIVE=$(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0")
|
||||
tail -n +$ARCHIVE "$0" | tar xzf - -C / 2>/dev/null
|
||||
|
||||
# 双保险:即使构建环境 tar 不支持 owner 规范化,也不要把构建机 UID/GID
|
||||
# 带到路由器系统文件中。这里仅修复本插件安装的系统侧文件,不触碰
|
||||
# /opt/openclaw 运行数据和 OpenClaw npm 插件状态目录。
|
||||
for p in \
|
||||
/etc/init.d/openclaw \
|
||||
/etc/profile.d/openclaw.sh \
|
||||
/usr/bin/openclaw-env \
|
||||
/usr/libexec/openclaw-permissions.sh \
|
||||
/usr/lib/lua/luci/controller/openclaw.lua \
|
||||
/usr/lib/lua/luci/model/cbi/openclaw \
|
||||
/usr/lib/lua/luci/view/openclaw \
|
||||
/usr/lib/lua/openclaw \
|
||||
/usr/share/openclaw \
|
||||
/usr/share/rpcd/acl.d/luci-app-openclaw.json
|
||||
do
|
||||
[ -e "$p" ] && chown -R root:root "$p" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# UCI 配置文件保护: 升级时不覆盖用户已有配置
|
||||
if [ -f /etc/config/openclaw ] && [ -f /etc/config/openclaw.default ]; then
|
||||
# 已有配置, 移除默认文件 (保留用户配置)
|
||||
@@ -261,7 +279,9 @@ echo "[4/4] 打包..."
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
# 创建 payload tarball
|
||||
(cd "$STAGING/payload" && tar czf "$STAGING/payload.tar.gz" .)
|
||||
# 强制 payload 内文件归属为 root:root,避免 GitHub runner / 本地构建用户
|
||||
# 的 UID/GID 泄漏到用户机器(例如安装后出现 1001:1001)。
|
||||
(cd "$STAGING/payload" && tar --owner=0 --group=0 --numeric-owner -czf "$STAGING/payload.tar.gz" .)
|
||||
|
||||
# 组合: installer header + payload
|
||||
RUN_FILE="$OUT_DIR/${PKG_NAME}_${PKG_VERSION}.run"
|
||||
|
||||
@@ -11,6 +11,12 @@ grep -q "NODE_VERSION_V2=\"22.23.0\"" root/usr/bin/openclaw-env || fail "default
|
||||
grep -q "OC_NODE_MIN_VERSION=\"\${OC_NODE_MIN_VERSION:-22.19.0}\"" root/usr/bin/openclaw-env || fail "minimum Node.js version not pinned"
|
||||
grep -q "oc_assert_node_min_version" root/usr/bin/openclaw-env || fail "Node.js minimum version check missing"
|
||||
grep -q 'oc_node_version_ge "$from_pkg" "$required"' root/usr/bin/openclaw-env || fail "package Node.js requirement must not lower static minimum"
|
||||
grep -q "install_openclaw_cli_wrapper" root/usr/bin/openclaw-env || fail "OpenClaw CLI wrapper must set runtime env"
|
||||
grep -q 'export NODE_ICU_DATA="${NODE_BASE}/share/icu"' root/usr/bin/openclaw-env || fail "OpenClaw CLI wrapper must export NODE_ICU_DATA"
|
||||
grep -q 'rm -f "$OC_GLOBAL/bin/openclaw"' root/usr/bin/openclaw-env || fail "OpenClaw CLI wrapper must unlink npm symlink before writing"
|
||||
grep -q "Extended_Pictographic" root/usr/bin/openclaw-env || fail "Node runtime must validate Unicode property escapes"
|
||||
grep -q "uci -q set openclaw.main.enabled='1'" root/usr/share/openclaw/oc-config.sh || fail "traditional config restart must enable gateway after first install"
|
||||
grep -q "uci -q set openclaw.main.enabled='1'" root/usr/share/openclaw/oc-config-interactive.js || fail "interactive config restart must enable gateway after first install"
|
||||
if grep -q 'v1_tarball' root/usr/bin/openclaw-env; then
|
||||
fail "installer must not silently fall back to legacy Node.js tarball"
|
||||
fi
|
||||
@@ -18,6 +24,10 @@ fi
|
||||
grep -q "wechat.htm" Makefile || fail "Makefile must install wechat.htm"
|
||||
grep -q "luci-app-openclaw.json" Makefile || fail "Makefile must install rpcd ACL"
|
||||
grep -q "openclaw-permissions.sh" Makefile || fail "Makefile must install permission helper"
|
||||
grep -q 'openclaw-permissions.sh fix-state "$${OC_DATA}/.openclaw"' Makefile || fail "postinst must repair existing OpenClaw state permissions after reinstall"
|
||||
grep -q '/etc/init.d/openclaw start >/dev/null 2>&1' Makefile || fail "postinst must restart enabled OpenClaw service after reinstall"
|
||||
grep -q 'openclaw-permissions.sh fix-state "${OC_DATA}/.openclaw"' scripts/build_ipk.sh || fail "release ipk postinst must repair existing OpenClaw state permissions after reinstall"
|
||||
grep -q '/etc/init.d/openclaw start >/dev/null 2>&1' scripts/build_ipk.sh || fail "release ipk postinst must restart enabled OpenClaw service after reinstall"
|
||||
if grep -q "openclaw.zh-cn.lmo" Makefile; then
|
||||
fail "main package must not install openclaw.zh-cn.lmo"
|
||||
fi
|
||||
@@ -52,11 +62,19 @@ grep -q "packageName: '@tencent-weixin/openclaw-weixin'" luasrc/controller/openc
|
||||
grep -q "channels\\['openclaw-weixin'\\].enabled = true" luasrc/controller/openclaw.lua || fail "wechat channel enable registration missing"
|
||||
grep -q "Registered openclaw-weixin npm plugin" luasrc/controller/openclaw.lua || fail "wechat install log must confirm config registration"
|
||||
grep -q "wechat_network_probe_cmd" luasrc/controller/openclaw.lua || fail "wechat network probe helper missing"
|
||||
grep -q "NODE_ICU_DATA=%s/node/share/icu" luasrc/controller/openclaw.lua || fail "wechat LuCI CLI commands must export NODE_ICU_DATA"
|
||||
grep -q "openclaw_user_runner_cmd" luasrc/controller/openclaw.lua || fail "wechat commands need user runner compatibility helper"
|
||||
grep -q "ulimit -v unlimited" luasrc/controller/openclaw.lua || fail "wechat commands must lift LuCI inherited address-space limit before Node CLI"
|
||||
grep -q "start-stop-daemon -S -m -p" luasrc/controller/openclaw.lua || fail "wechat commands must support OpenWrt without su"
|
||||
grep -q "command -v curl" luasrc/controller/openclaw.lua || fail "wechat network probe should prefer curl"
|
||||
grep -q "%%{http_code}" luasrc/controller/openclaw.lua || fail "wechat curl probe percent must be escaped for string.format"
|
||||
grep -q "wechat_npm_fallback_install_cmd" luasrc/controller/openclaw.lua || fail "wechat install needs npm fallback for OpenWrt Node undici OOM"
|
||||
if awk '/function action_wechat_install\(\)/,/function action_wechat_install_log\(\)/' luasrc/controller/openclaw.lua | grep -q "ensure_port_free"; then
|
||||
fail "wechat install must not stop gateway before plugin installation"
|
||||
fi
|
||||
if awk '/function action_wechat_upgrade_plugin\(\)/,/function action_wechat_uninstall_plugin\(\)/' luasrc/controller/openclaw.lua | grep -q "ensure_port_free"; then
|
||||
fail "wechat upgrade must not stop gateway before plugin upgrade"
|
||||
fi
|
||||
grep -q "npm install --omit=dev --omit=peer" luasrc/controller/openclaw.lua || fail "wechat npm fallback install command missing"
|
||||
grep -q "tencent-weixin-openclaw-weixin-7783ac86ba" luasrc/controller/openclaw.lua || fail "wechat npm fallback project dir missing"
|
||||
grep -q "export OC_WECHAT_DATA" luasrc/controller/openclaw.lua || fail "wechat npm fallback must export data dir into openclaw user shell"
|
||||
@@ -66,6 +84,9 @@ grep -q "is_newer_version(latest_version, current_version)" luasrc/controller/op
|
||||
grep -q "ilinkai.weixin.qq.com" luasrc/controller/openclaw.lua || fail "wechat network probe endpoint missing"
|
||||
grep -q "微信接口连通性检查" luasrc/controller/openclaw.lua || fail "wechat network probe log missing"
|
||||
grep -q "error_detail" luasrc/controller/openclaw.lua || fail "wechat login failure detail response missing"
|
||||
grep -q "已将此 OpenClaw 连接到微信" luasrc/controller/openclaw.lua || fail "wechat login status must treat saved auth as success"
|
||||
grep -q "Local login saved auth for openclaw%-weixin" luasrc/controller/openclaw.lua || fail "wechat login status must tolerate channels.start restart warning"
|
||||
grep -q "/etc/init.d/openclaw restart_gateway >/dev/null 2>&1 &" luasrc/controller/openclaw.lua || fail "wechat login success should use lightweight gateway restart"
|
||||
grep -q "self_heal_wechat_npm_plugin_config" root/etc/init.d/openclaw || fail "init.d wechat npm plugin self-heal missing"
|
||||
grep -q "已自愈注册 openclaw-weixin npm plugin" root/etc/init.d/openclaw || fail "init.d wechat self-heal log missing"
|
||||
grep -q "OC_WECHAT_PLUGIN_DIR" root/etc/init.d/openclaw || fail "init.d wechat self-heal plugin dir env missing"
|
||||
@@ -74,6 +95,14 @@ grep -q "fix_openclaw_state_permissions" root/etc/init.d/openclaw || fail "init.
|
||||
grep -q 'NODE_ICU_DATA="${NODE_BASE}/share/icu" PATH="${NODE_BASE}/bin:${OC_GLOBAL}/bin:$PATH"' root/etc/init.d/openclaw || fail "doctor migration must run with Node ICU data"
|
||||
grep -q "Token 同步 (doctor 后): UCI -> JSON" root/etc/init.d/openclaw || fail "doctor must restore missing JSON token from UCI"
|
||||
grep -q 'OPENCLAW_GATEWAY_TOKEN="$gw_token"' root/etc/init.d/openclaw || fail "gateway must receive token env fallback"
|
||||
grep -q "clear_jiti_cache_on_start" root/etc/init.d/openclaw || fail "JITI cache cleanup must be opt-in to avoid slow startup"
|
||||
grep -q "procd_set_param term_timeout 2" root/etc/init.d/openclaw || fail "procd term timeout must be bounded for faster restart"
|
||||
grep -q "procd_set_param respawn 3600 1 5" root/etc/init.d/openclaw || fail "gateway respawn timeout must be short for faster restart_gateway"
|
||||
grep -q 'openclaw.main.clear_jiti_cache_on_start' root/etc/init.d/openclaw || fail "JITI cleanup must be guarded by UCI flag"
|
||||
grep -q "openclaw-node-compile-cache" root/etc/init.d/openclaw || fail "Node compile cache must be enabled for faster warm restarts"
|
||||
grep -q 'NODE_COMPILE_CACHE="$node_compile_cache"' root/etc/init.d/openclaw || fail "gateway and pty must receive Node compile cache env"
|
||||
grep -q "通常 20~40 秒" root/etc/init.d/openclaw luasrc/view/openclaw/status.htm luasrc/view/openclaw/console.htm || fail "startup hint must match measured OpenWrt timing"
|
||||
grep -q "restart_gateway >/dev/null 2>&1 &" luasrc/controller/openclaw.lua || fail "LuCI restart action should use lightweight gateway restart"
|
||||
grep -q "oc_fix_npm_projects_permissions" root/usr/libexec/openclaw-permissions.sh || fail "npm projects permission helper missing"
|
||||
grep -q "openclaw.plugin.json" root/usr/libexec/openclaw-permissions.sh || fail "npm plugin root detection must use plugin manifest"
|
||||
grep -q "node_modules/@tencent-weixin/openclaw-weixin" root/usr/libexec/openclaw-permissions.sh || fail "wechat npm plugin compatibility permission fix missing"
|
||||
@@ -125,6 +154,10 @@ fi
|
||||
grep -q "root/usr/libexec" scripts/build_ipk.sh || fail "ipk script must package shell helpers"
|
||||
grep -q "root/usr/libexec" scripts/build_run.sh || fail "run script must package shell helpers"
|
||||
grep -q "for dep in luci-compat luci-base curl openssl-util script-utils tar libstdcpp6" scripts/build_run.sh || fail ".run installer must install runtime dependencies"
|
||||
grep -q -- "--owner=0 --group=0 --numeric-owner" scripts/build_run.sh || fail ".run payload must normalize file ownership to root"
|
||||
grep -q -- "--owner=0 --group=0 --numeric-owner" scripts/build_ipk.sh || fail ".ipk payload must normalize file ownership to root"
|
||||
grep -q "chown -R root:root" scripts/build_run.sh || fail ".run installer must repair root-owned system files after extraction"
|
||||
grep -q "chown -R root:root" scripts/build_ipk.sh || fail ".ipk postinst must repair root-owned system files after extraction"
|
||||
grep -q "先解压到临时目录并确认完整,再替换 NODE_BASE" root/usr/bin/openclaw-env || fail "Node install must not delete existing runtime before extraction succeeds"
|
||||
grep -q "OC_SETUP_FRESH_ROOT" root/usr/bin/openclaw-env || fail "setup cleanup must preserve existing runtime roots"
|
||||
|
||||
|
||||
@@ -16,10 +16,19 @@ grep -Fq "ubus call service list" "$CONTROLLER" || fail "status API should inspe
|
||||
grep -Fq "openclaw.instances.gateway" "$CONTROLLER" || fail "status API should inspect gateway instance state"
|
||||
grep -Fq "gateway_failed" "$CONTROLLER" || fail "status API should report gateway failure state"
|
||||
grep -Fq "gateway_exit_code" "$CONTROLLER" || fail "status API should expose recent gateway exit code"
|
||||
grep -Fq "gateway_crash_loop" "$CONTROLLER" || fail "status API should expose procd crash-loop state"
|
||||
grep -Fq "procd_pid_alive" "$CONTROLLER" || fail "status API should ignore stale procd pidfiles"
|
||||
grep -Fq "pidfile_stale" "$CONTROLLER" || fail "status API should require current stale pidfile evidence for crash-loop"
|
||||
grep -Fq 'enabled=$(uci -q get openclaw.main.enabled' "$INIT_SCRIPT" || fail "status_service should honor disabled service state"
|
||||
grep -Fq "网关: 已禁用" "$INIT_SCRIPT" || fail "status_service should report disabled gateway before crash-loop"
|
||||
if grep -Fq 'pgrep -f "openclaw.*gateway"' "$CONTROLLER" "$INIT_SCRIPT" || grep -Fq "pgrep -f 'openclaw.*gateway'" "$CONTROLLER" "$INIT_SCRIPT"; then
|
||||
fail "status checks must not use broad pgrep fallback that can match the status shell itself"
|
||||
fi
|
||||
|
||||
grep -Fq "启动失败" "$STATUS_VIEW" || fail "status panel should distinguish startup failure from startup in progress"
|
||||
grep -Fq "gateway_failed" "$STATUS_VIEW" || fail "status panel should render gateway failure state"
|
||||
|
||||
grep -Fq "ubus call service list" "$INIT_SCRIPT" || fail "status_service should inspect procd state via ubus"
|
||||
grep -Fq "crash-loop 抑制" "$INIT_SCRIPT" || fail "status_service should report procd crash-loop suppression"
|
||||
|
||||
echo "ok"
|
||||
Reference in new issue
Block a user