🎈 Sync 2026-06-08 16:57:14

This commit is contained in:
github-actions[bot] committed 2026-06-08 16:57:14 +08:00
1 parent a75bbbe729
commit e41d0593c1
37 files changed
+275 -10683

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
tests/ export-ignore
docs/notes/ export-ignore
.claude/ export-ignore
+31
View File
@@ -4,6 +4,37 @@
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
## [2.0.6] - 2026-06-08
### 适配 OpenClaw v2026.6.1
- `OC_TESTED_VERSION` 更新为 `2026.6.1`,默认稳定版跟随 npm `latest` 稳定标签。
- 默认 Node.js 运行时更新为 `24.15.0`,最低要求同步提升到 `22.19.0`,匹配 OpenClaw 2026.6.x 的 `engines.node`。
- 安装脚本不再从当前 Node 版本静默回退到旧版 V1 tarball,避免下载失败后装入过低 Node.js 并在 OpenClaw 安装后失败。
- ARM64 musl 预编译 Node.js 构建流程更新为 `24.15.0`,并校验默认路径和自定义安装路径均可运行。
### 修复安装、控制台与状态体验
- Node.js 下载失败时保留明确失败路径,避免 ARM64 musl 缺少当前版本资产时误判为可继续安装。
- Web 控制台改为新窗口打开,继续强制使用 HTTP Gateway URL 和最新 token,规避 LuCI HTTPS、iframe 安全头和旧 token 混用问题。
- 状态接口和页面继续区分“运行中 / 启动中 / 启动失败”,并保留 procd Gateway 退出码,便于定位升级后的启动失败。
- 保留微信插件安装预检和权限修复链路,覆盖 `python3`、`openclaw` 用户、npm cache、tmp 和数据目录权限。
### 测试
- 更新 OpenClaw/Node.js 版本契约测试。
- 新增控制台新窗口、状态失败展示、ARM64 musl Node 打包与路径兼容契约测试。
### 致谢
感谢以下用户通过 Issue 或 PR 提供问题反馈、复现信息和修复思路:
- @djbadboyvip (#94)、@alan9771 (#93, #82)、@luckymai3688 (#92, #91)、@lucian521 (#90)
- @svgr110 (#89)、@Cuscito (#88)、@ayysama (#87)、@jameslau-tech (#86)、@hwliu11 (#84)
- @zhuxf8 (#81)、@yiyibuguai (#80)、@nbagui (#79)、@sam528300-lab (#78)、@hotwa (#85)
---
## [2.0.5] - 2026-05-15
### 适配 OpenClaw v2026.5.12
+1 -1
View File
@@ -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:=15
PKG_RELEASE:=16
PKG_MAINTAINER:=10000ge10000 <10000ge10000@users.noreply.github.com>
PKG_LICENSE:=GPL-3.0
+2 -2
View File
@@ -27,8 +27,8 @@
| 组件 | 默认版本 | 说明 |
|------|----------|------|
| OpenClaw | `2026.5.12` | npm `latest` 稳定标签;不默认追 `2026.5.14-beta.2` |
| Node.js | `22.16.0` | 安装后会按 OpenClaw `engines.node` 做强校验,低于要求会直接失败 |
| OpenClaw | `2026.6.1` | npm `latest` 稳定标签;不默认追 `2026.6.5-beta.2` |
| Node.js | `24.15.0` | OpenClaw 2026.6.x 要求 `>=22.19.0`;安装后会按 `engines.node` 做强校验,低于要求会直接失败 |
| 微信插件 | `@tencent-weixin/openclaw-weixin@2.4.3` | CLI 使用 `@tencent-weixin/openclaw-weixin-cli@2.1.4` |
## 📦 安装
+1 -1
View File
@@ -1 +1 @@
2.0.5
2.0.6
@@ -71,6 +71,21 @@ grep -q '^openclaw:' /etc/group 2>/dev/null || echo "openclaw:x:${OC_GID}:" >> /
return uid ~= ""
end
local function find_wechat_plugin_dir(install_path)
local sys = require "luci.sys"
local ext_dir = install_path .. "/data/.openclaw/extensions/openclaw-weixin"
if nixio.fs.stat(ext_dir .. "/openclaw.plugin.json", "type") then
return ext_dir
end
local npm_projects = install_path .. "/data/.openclaw/npm/projects"
local cmd = "find " .. shellquote(npm_projects) .. " -path '*/node_modules/@tencent-weixin/openclaw-weixin/openclaw.plugin.json' -type f 2>/dev/null | head -n 1"
local plugin_json = sys.exec(cmd):match("[^\r\n]+")
if plugin_json and plugin_json ~= "" then
return plugin_json:gsub("/openclaw%.plugin%.json$", "")
end
return nil
end
local function write_wechat_log_and_exit(log_file, exit_file, content, exit_code)
local f = io.open(log_file, "w")
if f then
@@ -1206,9 +1221,9 @@ function action_wechat_status()
}
-- 检测微信插件是否已安装
local wechat_ext_dir = install_path .. "/data/.openclaw/extensions/openclaw-weixin"
local wechat_plugin_json = wechat_ext_dir .. "/openclaw.plugin.json"
local wechat_package_json = wechat_ext_dir .. "/package.json"
local wechat_ext_dir = find_wechat_plugin_dir(install_path)
local wechat_plugin_json = wechat_ext_dir and (wechat_ext_dir .. "/openclaw.plugin.json") or ""
local wechat_package_json = wechat_ext_dir and (wechat_ext_dir .. "/package.json") or ""
if nixio.fs.stat(wechat_plugin_json, "type") then
result.plugin_installed = true
@@ -1629,7 +1644,7 @@ function action_wechat_check_upgrade()
-- 获取当前已安装版本
local current_version = ""
local wechat_ext_dir = install_path .. "/data/.openclaw/extensions/openclaw-weixin"
local wechat_ext_dir = find_wechat_plugin_dir(install_path) or (install_path .. "/data/.openclaw/extensions/openclaw-weixin")
local plugin_json = wechat_ext_dir .. "/openclaw.plugin.json"
local pf = io.open(plugin_json, "r")
if pf then
@@ -1,6 +1,6 @@
<%#
luci-app-openclaw — Web 控制台页面
嵌入 OpenClaw 官方 Web UI,用户可在此配置模型/渠道并直接对话
打开 OpenClaw 官方 Web UI,用户可在此配置模型/渠道并直接对话
-%>
<%+header%>
@@ -51,8 +51,6 @@ local port = uci:get("openclaw", "main", "port") or "18789"
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
#oc-console-iframe { width: 100%; height: 700px; border: none; display: block; }
.oc-console-loading {
display: flex; flex-direction: column; align-items: center; justify-content: center;
height: 300px; color: #666; font-size: 14px; background: #fafafa;
@@ -135,7 +133,7 @@ local port = uci:get("openclaw", "main", "port") or "18789"
statusTextEl.innerHTML = '<span style="color:#1a7f37;">● 网关运行中</span>';
openBtn.href = url;
openBtn.style.display = '';
showIframe(url);
showLaunch(url);
} else if (d.gateway_failed) {
statusTextEl.innerHTML = '<span style="color:#cf222e;">● 网关启动失败</span>';
openBtn.style.display = 'none';
@@ -169,22 +167,13 @@ local port = uci:get("openclaw", "main", "port") or "18789"
});
}
function showIframe(url) {
function showLaunch(url) {
loading.style.display = 'none';
var existing = document.getElementById('oc-console-iframe');
if (existing) {
if (existing.src !== url) existing.src = url;
return;
}
var iframe = document.createElement('iframe');
iframe.id = 'oc-console-iframe';
iframe.src = url;
iframe.style.width = '100%';
iframe.style.height = '700px';
iframe.style.border = 'none';
iframe.setAttribute('allowfullscreen', 'true');
container.appendChild(iframe);
container.innerHTML = '<div class="oc-console-loading" style="height:220px;">' +
'<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;">请点击上方「新窗口打开」访问控制台。</div>' +
'</div>';
}
checkAndLoad();
+47 -3
View File
@@ -15,7 +15,7 @@ EXTRA_HELP=" setup 下载 Node.js 并安装 OpenClaw
# 统一路径解析可以兼容 /mnt/data/openclaw 输入,避免双拼路径。
[ -r /usr/libexec/openclaw-paths.sh ] && . /usr/libexec/openclaw-paths.sh
[ -r /usr/libexec/openclaw-node.sh ] && . /usr/libexec/openclaw-node.sh
OC_NODE_MIN_VERSION="${OC_NODE_MIN_VERSION:-22.14.0}"
OC_NODE_MIN_VERSION="${OC_NODE_MIN_VERSION:-22.19.0}"
OC_CONFIGURED_PATH="$(uci -q get openclaw.main.install_path 2>/dev/null || echo '/opt')"
if command -v oc_load_paths >/dev/null 2>&1; then
if ! oc_load_paths "$OC_CONFIGURED_PATH"; then
@@ -252,6 +252,9 @@ if(Array.isArray(d.plugins.allow)){
delete d.plugins[ns].weixin;
}
});
if(d.plugins.entries&&d.plugins.entries['openclaw-weixin']){
delete d.plugins.entries['openclaw-weixin'];
}
['channel','channels'].forEach(ns=>{
if(d[ns]&&d[ns].weixin){
if(!d[ns]['openclaw-weixin'])d[ns]['openclaw-weixin']=d[ns].weixin;
@@ -365,10 +368,35 @@ fi
# v2026.4.10 补充: 同时修复权限模式为 755,确保 Gateway 可读取插件
# 原因: npm/npx 以 root 创建目录时默认权限 700,其他用户无法读取
local ext_dir="${OC_DATA}/.openclaw/extensions"
local npm_projects_dir="${OC_DATA}/.openclaw/npm/projects"
local wechat_legacy_dir="${ext_dir}/openclaw-weixin"
local wechat_npm_plugin=""
if [ -d "$npm_projects_dir" ]; then
wechat_npm_plugin=$(find "$npm_projects_dir" -path "*/node_modules/@tencent-weixin/openclaw-weixin/openclaw.plugin.json" -type f 2>/dev/null | head -n 1)
fi
if [ -n "$wechat_npm_plugin" ] && [ -d "$wechat_legacy_dir" ]; then
local archive_root="${OC_DATA}/.openclaw/archived-extensions"
mkdir -p "$archive_root" 2>/dev/null || true
local archived_dir="${archive_root}/openclaw-weixin.legacy.$(date +%Y%m%d%H%M%S)"
mv "$wechat_legacy_dir" "$archived_dir" 2>/dev/null && logger -t openclaw "已归档旧微信扩展目录: $archived_dir"
fi
if [ -n "$wechat_npm_plugin" ] && [ -d "$ext_dir" ]; then
local archive_root="${OC_DATA}/.openclaw/archived-extensions"
mkdir -p "$archive_root" 2>/dev/null || true
for stale_dir in "$ext_dir"/openclaw-weixin.legacy.*; do
[ -d "$stale_dir" ] || continue
local stale_name="${stale_dir##*/}"
mv "$stale_dir" "${archive_root}/${stale_name}" 2>/dev/null || true
done
fi
if [ -d "$ext_dir" ]; then
chown -R root:root "$ext_dir" 2>/dev/null || true
chmod -R 755 "$ext_dir" 2>/dev/null || true
fi
if [ -d "$npm_projects_dir" ]; then
chown -R root:root "$npm_projects_dir" 2>/dev/null || true
chmod -R 755 "$npm_projects_dir" 2>/dev/null || true
fi
# v2026.4.x: 清理 jiti 缓存目录 (修复微信插件加载权限问题)
# jiti 编译 TypeScript 时会在 /tmp/jiti 创建缓存,如果由 root 创建则 openclaw 用户无法写入
@@ -486,8 +514,16 @@ if(d.gateway&&d.gateway.auth&&d.gateway.auth.token)process.stdout.write(d.gatewa
# v2026.4.10: 最终权限修复 - 确保 Gateway 启动前所有数据目录权限正确
# doctor --fix 或 _ensure_critical_config 可能创建新的目录/文件
# 关键: agents 目录下的 agent 子目录必须可被 openclaw 用户写入
find "${OC_DATA}/.openclaw" -user root -type d -exec chown openclaw:openclaw {} \; 2>/dev/null || true
find "${OC_DATA}/.openclaw" -user root -type f -exec chown openclaw:openclaw {} \; 2>/dev/null || true
find "${OC_DATA}/.openclaw" -user root \
! -path "${OC_DATA}/.openclaw/extensions*" \
! -path "${OC_DATA}/.openclaw/archived-extensions*" \
! -path "${OC_DATA}/.openclaw/npm/projects*" \
-type d -exec chown openclaw:openclaw {} \; 2>/dev/null || true
find "${OC_DATA}/.openclaw" -user root \
! -path "${OC_DATA}/.openclaw/extensions*" \
! -path "${OC_DATA}/.openclaw/archived-extensions*" \
! -path "${OC_DATA}/.openclaw/npm/projects*" \
-type f -exec chown openclaw:openclaw {} \; 2>/dev/null || true
# 特别确保 agents/main/agent 目录权限 (模型配置写入目录)
local agent_dir="${OC_DATA}/.openclaw/agents/main/agent"
if [ -d "$agent_dir" ]; then
@@ -500,6 +536,14 @@ if(d.gateway&&d.gateway.auth&&d.gateway.auth.token)process.stdout.write(d.gatewa
chown -R root:root "${OC_DATA}/.openclaw/extensions" 2>/dev/null || true
chmod -R 755 "${OC_DATA}/.openclaw/extensions" 2>/dev/null || true
fi
if [ -d "${OC_DATA}/.openclaw/archived-extensions" ]; then
chown -R root:root "${OC_DATA}/.openclaw/archived-extensions" 2>/dev/null || true
chmod -R 700 "${OC_DATA}/.openclaw/archived-extensions" 2>/dev/null || true
fi
if [ -d "${OC_DATA}/.openclaw/npm/projects" ]; then
chown -R root:root "${OC_DATA}/.openclaw/npm/projects" 2>/dev/null || true
chmod -R 755 "${OC_DATA}/.openclaw/npm/projects" 2>/dev/null || true
fi
# Patch iframe 安全头,允许 LuCI 嵌入
patch_iframe_headers
+13 -18
View File
@@ -7,22 +7,22 @@
# openclaw-env upgrade — 升级 OpenClaw 到最新版
# openclaw-env node — 仅下载/更新 Node.js
# 环境变量:
# OC_VERSION — 指定 OpenClaw 版本 (如 2026.3.1),不设置则安装最新版
# OC_VERSION — 指定 OpenClaw 版本 (如 2026.6.1),不设置则安装已测试稳定版
# ============================================================================
set -e
# ── Node.js 版本策略 (双版本兼容) ──
# V2: 当前推荐版本,用于 OpenClaw v2026.3.22+ (要求 >= 22.14.0,使用 22.16.0 确保兼容)
# V2: 当前推荐版本,用于 OpenClaw v2026.6.1+ (要求 >= 22.19.0,使用 24.15.0 确保兼容)
# V1: 旧版兼容,用于 OpenClaw v2026.3.8 及更早版本
NODE_VERSION_V2="22.16.0"
NODE_VERSION_V2="24.15.0"
NODE_VERSION_V1="22.15.1"
# 默认使用 V2 版本 (可通过 NODE_VERSION 环境变量覆盖)
NODE_VERSION="${NODE_VERSION:-${NODE_VERSION_V2}}"
# 经过验证的 OpenClaw 稳定版本 (更新此值需同步测试)
OC_TESTED_VERSION="2026.5.12"
# OpenClaw 2026.5.x package.json engines.node 的最低要求。
OC_TESTED_VERSION="2026.6.1"
# OpenClaw 2026.6.x package.json engines.node 的最低要求。
# 如果未来上游提高要求,安装成功后还会从 package.json 再做一次强校验。
OC_NODE_MIN_VERSION="${OC_NODE_MIN_VERSION:-22.14.0}"
OC_NODE_MIN_VERSION="${OC_NODE_MIN_VERSION:-22.19.0}"
# 用户可通过 OC_VERSION 环境变量覆盖安装版本
OC_VERSION="${OC_VERSION:-}"
@@ -216,7 +216,11 @@ assert_node_runtime() {
local required="$OC_NODE_MIN_VERSION"
local from_pkg
from_pkg=$(detect_oc_node_requirement 2>/dev/null || true)
[ -n "$from_pkg" ] && required="$from_pkg"
if [ -n "$from_pkg" ] && command -v oc_node_version_ge >/dev/null 2>&1; then
if oc_node_version_ge "$from_pkg" "$required"; then
required="$from_pkg"
fi
fi
if command -v oc_assert_node_min_version >/dev/null 2>&1; then
oc_assert_node_min_version "$NODE_BIN" "$required" || exit 1
@@ -258,12 +262,8 @@ download_node() {
assert_node_runtime
return 0
fi
# ARM64 musl 使用 Alpine 打包,版本号可能不完全匹配
# 只要主版本号相同即认为兼容 (如 22.15.1 vs 22.15.0)
local cur_major=$(echo "$current_ver" | cut -d. -f1)
local want_major=$(echo "$node_ver" | cut -d. -f1)
if [ "$cur_major" = "$want_major" ]; then
log_info "Node.js v${current_ver} 已安装 (兼容 v${node_ver}), 跳过下载"
if command -v oc_node_version_ge >/dev/null 2>&1 && oc_node_version_ge "$current_ver" "$node_ver"; then
log_info "Node.js v${current_ver} 已安装 (>= v${node_ver}), 跳过下载"
assert_node_runtime
return 0
fi
@@ -285,11 +285,6 @@ download_node() {
mirror_list="${NODE_SELF_HOST}/${musl_tarball}"
# 2) unofficial-builds (留作将来可能支持)
mirror_list="$mirror_list ${NODE_MUSL_MIRROR}/v${node_ver}/${musl_tarball}"
# 3) 回退到 V1 版本 (兼容旧环境,仅当请求 V2 时)
if [ "$node_ver" = "$NODE_VERSION_V2" ]; then
local v1_tarball="node-v${NODE_VERSION_V1}-${node_arch}-musl.tar.xz"
mirror_list="$mirror_list ${NODE_SELF_HOST}/${v1_tarball}"
fi
else
# x64 musl: unofficial-builds 提供
# 1) unofficial-builds
@@ -606,7 +606,11 @@ show_current_config() {
# 检测微信渠道
local wechat_ext_dir="${OC_STATE_DIR}/extensions/openclaw-weixin"
if [ -d "$wechat_ext_dir" ] && [ -f "${wechat_ext_dir}/openclaw.plugin.json" ]; then
local wechat_npm_plugin=""
if [ -d "${OC_STATE_DIR}/npm/projects" ]; then
wechat_npm_plugin=$(find "${OC_STATE_DIR}/npm/projects" -path "*/node_modules/@tencent-weixin/openclaw-weixin/openclaw.plugin.json" -type f 2>/dev/null | head -n 1)
fi
if { [ -d "$wechat_ext_dir" ] && [ -f "${wechat_ext_dir}/openclaw.plugin.json" ]; } || [ -n "$wechat_npm_plugin" ]; then
echo -e "${GREEN}│${NC} 微信 .............. ${GREEN}✅ 已配置${NC}"
else
echo -e "${GREEN}│${NC} 微信 .............. ${YELLOW}❌ 未配置${NC}"
+19 -19
View File
@@ -18,7 +18,6 @@
# ============================================================================
set -e
INSTALL_PREFIX="/opt/openclaw/node"
BUILD_MODE="${BUILD_MODE:-apk}"
echo "=== Node.js ARM64 musl Build ==="
@@ -198,10 +197,10 @@ finalize_package() {
# 用 patchelf 修改 node 二进制
echo "=== Patching ELF binary ==="
patchelf --set-interpreter "${INSTALL_PREFIX}/lib/ld-musl-aarch64.so.1" "${PKG_DIR}/bin/node"
patchelf --set-rpath "${INSTALL_PREFIX}/lib" "${PKG_DIR}/bin/node"
echo " interpreter: ${INSTALL_PREFIX}/lib/ld-musl-aarch64.so.1"
echo " rpath: ${INSTALL_PREFIX}/lib"
patchelf --set-interpreter "/lib/ld-musl-aarch64.so.1" "${PKG_DIR}/bin/node"
patchelf --set-rpath '$ORIGIN/../lib' "${PKG_DIR}/bin/node"
echo " interpreter: /lib/ld-musl-aarch64.so.1"
echo " rpath: \$ORIGIN/../lib"
# 创建 node wrapper 脚本
cat > "${PKG_DIR}/bin/node-wrapper" << 'NODEWRAPPER'
@@ -229,20 +228,21 @@ exec "${SELF_DIR}/node" "${SELF_DIR}/../lib/node_modules/npm/bin/npx-cli.js" "$@
NPXWRAPPER
chmod +x "${PKG_DIR}/bin/npm" "${PKG_DIR}/bin/npx"
# 验证
echo "=== Verification ==="
mkdir -p "${INSTALL_PREFIX}"
cp -a "${PKG_DIR}"/* "${INSTALL_PREFIX}/"
# 设置库路径并测试
export LD_LIBRARY_PATH="${INSTALL_PREFIX}/lib"
"${INSTALL_PREFIX}/bin/node" --version
"${INSTALL_PREFIX}/bin/node" -e "console.log('execPath:', process.execPath)"
"${INSTALL_PREFIX}/bin/node" -e "console.log(process.arch, process.platform, process.versions.modules)"
NODE_ICU_DATA="${INSTALL_PREFIX}/share/icu" "${INSTALL_PREFIX}/bin/npm" --version 2>/dev/null || echo "npm needs ICU data"
rm -rf "${INSTALL_PREFIX}"
verify_prefix() {
local prefix="$1"
echo "=== Verifying prefix: ${prefix} ==="
rm -rf "$prefix"
mkdir -p "$prefix"
cp -a "${PKG_DIR}"/* "$prefix/"
"${prefix}/bin/node" --version
"${prefix}/bin/node" -e "console.log('execPath:', process.execPath)"
"${prefix}/bin/node" -e "console.log(process.arch, process.platform, process.versions.modules)"
NODE_ICU_DATA="${prefix}/share/icu" "${prefix}/bin/npm" --version 2>/dev/null || echo "npm needs ICU data"
rm -rf "$prefix"
}
verify_prefix /opt/openclaw/node
verify_prefix /tmp/custom-openclaw-root/openclaw/node
# 打包
echo "=== Creating tarball ==="
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
CONSOLE_VIEW="$REPO_ROOT/luasrc/view/openclaw/console.htm"
fail() {
echo "FAIL: $1" >&2
exit 1
}
grep -Fq "var url = 'http://' + host + ':' + gwPort + '/'" "$CONSOLE_VIEW" || fail "console view should force HTTP gateway URL"
grep -Fq '请点击上方「新窗口打开」访问控制台。' "$CONSOLE_VIEW" || fail "console view should direct users to a new window"
if grep -Fq "document.createElement('iframe')" "$CONSOLE_VIEW"; then
fail "console view should not embed the OpenClaw UI in an iframe"
fi
if grep -Fq 'window.location.protocol' "$CONSOLE_VIEW"; then
fail "console view should not reuse the LuCI page protocol for the gateway URL"
fi
cr=$(printf '\r')
if LC_ALL=C grep -q "$cr" "$CONSOLE_VIEW"; then
fail "console view should use LF line endings"
fi
echo "ok"
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
BUILD_SCRIPT="$REPO_ROOT/scripts/build-node-musl.sh"
WORKFLOW="$REPO_ROOT/.github/workflows/build-node-musl.yml"
ENV_SCRIPT="$REPO_ROOT/root/usr/bin/openclaw-env"
fail() {
echo "FAIL: $1" >&2
exit 1
}
grep -Fq 'patchelf --set-interpreter "/lib/ld-musl-aarch64.so.1"' "$BUILD_SCRIPT" || fail "build script should use system musl loader"
grep -Fq '$ORIGIN/../lib' "$BUILD_SCRIPT" || fail "build script should use relative rpath"
if grep -Fq 'patchelf --set-interpreter "${INSTALL_PREFIX}/lib/ld-musl-aarch64.so.1"' "$BUILD_SCRIPT"; then
fail "build script should not hardcode interpreter to install prefix"
fi
grep -Fq 'verify_prefix /opt/openclaw/node' "$BUILD_SCRIPT" || fail "build script should verify default install path"
grep -Fq 'verify_prefix /tmp/custom-openclaw-root/openclaw/node' "$BUILD_SCRIPT" || fail "build script should verify custom install path"
grep -Fq 'NODE_VER="24.15.0"' "$WORKFLOW" || fail "workflow should build current Node.js"
grep -Fq 'BUILD_MODE=cross' "$WORKFLOW" || fail "workflow should use cross mode for current ARM64 musl package"
grep -Fq 'oc_node_version_ge "$current_ver" "$node_ver"' "$ENV_SCRIPT" || fail "installer should require installed Node.js to satisfy target version"
if grep -Fq 'v1_tarball' "$ENV_SCRIPT"; then
fail "installer should not auto-fallback from current Node.js to legacy tarball"
fi
echo "ok"
@@ -6,8 +6,14 @@ fail() {
exit 1
}
grep -q "OC_TESTED_VERSION=\"2026.5.12\"" root/usr/bin/openclaw-env || fail "tested OpenClaw version not pinned"
grep -q "OC_TESTED_VERSION=\"2026.6.1\"" root/usr/bin/openclaw-env || fail "tested OpenClaw version not pinned"
grep -q "NODE_VERSION_V2=\"24.15.0\"" root/usr/bin/openclaw-env || fail "default Node.js version not pinned"
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"
if grep -q 'v1_tarball' root/usr/bin/openclaw-env; then
fail "installer must not silently fall back to legacy Node.js tarball"
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"
@@ -31,9 +37,18 @@ grep -q "command -v python3" luasrc/controller/openclaw.lua || fail "wechat inst
grep -q "ensure_openclaw_user" luasrc/controller/openclaw.lua || fail "wechat install must ensure openclaw user"
grep -q "NPM_CONFIG_CACHE" luasrc/controller/openclaw.lua || fail "wechat install must set npm cache"
grep -q "openclaw-weixin" root/etc/init.d/openclaw || fail "weixin channel migration missing"
grep -q "delete d.plugins.entries\\['openclaw-weixin'\\]" root/etc/init.d/openclaw || fail "weixin duplicate entries cleanup missing"
grep -q "npm/projects" root/etc/init.d/openclaw || fail "npm plugin project ownership fix missing"
grep -q "! -path.*npm/projects" root/etc/init.d/openclaw || fail "npm plugin projects should be excluded from openclaw ownership reset"
grep -q "archived-extensions" root/etc/init.d/openclaw || fail "legacy weixin extension archive missing"
grep -q "find_wechat_plugin_dir" luasrc/controller/openclaw.lua || fail "wechat npm plugin detection missing"
grep -q "@tencent-weixin/openclaw-weixin/openclaw.plugin.json" root/usr/share/openclaw/oc-config.sh || fail "oc-config wechat npm detection missing"
grep -q "var url = 'http://'" luasrc/view/openclaw/console.htm || fail "console must force HTTP gateway URL"
grep -q "existing.src" luasrc/view/openclaw/console.htm || fail "console iframe must refresh token URL"
grep -q "新窗口打开" luasrc/view/openclaw/console.htm || fail "console must expose a new-window entry"
if grep -q "document.createElement('iframe')" luasrc/view/openclaw/console.htm; then
fail "console must not embed OpenClaw in an iframe"
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"
@@ -8,11 +8,11 @@ fail() {
exit 1
}
[ "$(oc_normalize_node_version v22.16.0)" = "22.16.0" ] || fail "normalize v"
oc_node_version_ge 22.16.0 22.16.0 || fail "exact version"
oc_node_version_ge 22.16.1 22.16.0 || fail "patch version"
oc_node_version_ge 23.0.0 22.16.0 || fail "major version"
if oc_node_version_ge 22.15.1 22.16.0; then
[ "$(oc_normalize_node_version v24.15.0)" = "24.15.0" ] || fail "normalize v"
oc_node_version_ge 22.19.0 22.19.0 || fail "exact version"
oc_node_version_ge 22.19.1 22.19.0 || fail "patch version"
oc_node_version_ge 24.15.0 22.19.0 || fail "major version"
if oc_node_version_ge 22.18.1 22.19.0; then
fail "older minor accepted"
fi
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
CONTROLLER="$REPO_ROOT/luasrc/controller/openclaw.lua"
STATUS_VIEW="$REPO_ROOT/luasrc/view/openclaw/status.htm"
INIT_SCRIPT="$REPO_ROOT/root/etc/init.d/openclaw"
fail() {
echo "FAIL: $1" >&2
exit 1
}
grep -Fq "ubus call service list" "$CONTROLLER" || fail "status API should inspect procd state via ubus"
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 "启动失败" "$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"
echo "ok"