mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 13:03:56 +08:00
🍉 Sync 2026-05-16 08:37:13
This commit is contained in:
1 parent
8c1c3dd8ec
commit
8ed4c2a2a5
32 files changed
+1145
-234
No files matched your search
@@ -19,19 +19,37 @@ NODE_VERSION_V1="22.15.1"
|
||||
# 默认使用 V2 版本 (可通过 NODE_VERSION 环境变量覆盖)
|
||||
NODE_VERSION="${NODE_VERSION:-${NODE_VERSION_V2}}"
|
||||
# 经过验证的 OpenClaw 稳定版本 (更新此值需同步测试)
|
||||
OC_TESTED_VERSION="2026.4.9"
|
||||
OC_TESTED_VERSION="2026.5.12"
|
||||
# OpenClaw 2026.5.x package.json engines.node 的最低要求。
|
||||
# 如果未来上游提高要求,安装成功后还会从 package.json 再做一次强校验。
|
||||
OC_NODE_MIN_VERSION="${OC_NODE_MIN_VERSION:-22.14.0}"
|
||||
# 用户可通过 OC_VERSION 环境变量覆盖安装版本
|
||||
OC_VERSION="${OC_VERSION:-}"
|
||||
|
||||
[ -r /usr/libexec/openclaw-paths.sh ] && . /usr/libexec/openclaw-paths.sh
|
||||
[ -r /usr/libexec/openclaw-node.sh ] && . /usr/libexec/openclaw-node.sh
|
||||
|
||||
# ── 安装路径 (支持自定义) ──
|
||||
# 从 UCI 配置读取自定义路径,默认为 /opt
|
||||
# 用户可在 LuCI 界面或通过 uci set openclaw.main.install_path=/mnt/data 设置
|
||||
# 程序会在此路径下自动创建 openclaw 目录
|
||||
OC_BASE_PATH="${OC_INSTALL_PATH:-$(uci -q get openclaw.main.install_path || echo '/opt')}"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
NODE_BASE="${OC_INSTALL_PATH}/node"
|
||||
OC_GLOBAL="${OC_INSTALL_PATH}/global"
|
||||
OC_DATA="${OC_INSTALL_PATH}/data"
|
||||
# UCI 公开字段继续使用 openclaw.main.install_path,语义为“基础目录”。
|
||||
# 兼容用户误填 /mnt/data/openclaw:统一剥离末尾 openclaw,避免得到
|
||||
# /mnt/data/openclaw/openclaw 这种双拼路径。
|
||||
OC_CONFIGURED_PATH="${OC_INSTALL_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
|
||||
echo " [✗] 安装路径无效: $OC_CONFIGURED_PATH"
|
||||
echo " [!] 请使用绝对路径,例如 /opt、/mnt/data;不要使用相对路径、空格或 shell 特殊字符。"
|
||||
exit 1
|
||||
fi
|
||||
OC_BASE_PATH="$OPENCLAW_INSTALL_PATH"
|
||||
OC_INSTALL_PATH="$OC_ROOT"
|
||||
else
|
||||
OC_BASE_PATH="${OC_CONFIGURED_PATH%/}"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
NODE_BASE="${OC_INSTALL_PATH}/node"
|
||||
OC_GLOBAL="${OC_INSTALL_PATH}/global"
|
||||
OC_DATA="${OC_INSTALL_PATH}/data"
|
||||
CONFIG_FILE="${OC_DATA}/.openclaw/openclaw.json"
|
||||
fi
|
||||
|
||||
# ── OverlayFS 兼容性修复 ──
|
||||
# iStoreOS/OpenWrt 上 Docker 的 bind mount (/overlay/upper/opt/docker)
|
||||
@@ -82,11 +100,58 @@ ensure_mkdir() {
|
||||
[ -d "$target" ] && return 0
|
||||
if ! mkdir -p "$target" 2>/dev/null; then
|
||||
log_error "无法创建目录: $target"
|
||||
log_error "如果安装了 Docker,可能需要手动执行: mount --bind /overlay/upper/opt /opt"
|
||||
local probe_parent="/"
|
||||
command -v oc_find_existing_path >/dev/null 2>&1 && probe_parent=$(oc_find_existing_path "$target")
|
||||
log_error "请检查挂载点是否只读、overlay 是否已满,以及 ${probe_parent} 是否可写。"
|
||||
[ "$OC_BASE_PATH" = "/opt" ] && log_error "如果安装了 Docker,可能需要手动执行: mount --bind /overlay/upper/opt /opt"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_openclaw_user() {
|
||||
# OpenWrt 默认没有 useradd/adduser 的完整实现,所以沿用 uci-defaults 的轻量写法。
|
||||
# 这里在安装链路再兜底一次,避免用户删除账号后微信插件安装或 Gateway 启动失败。
|
||||
if id openclaw >/dev/null 2>&1 || grep -q '^openclaw:' /etc/passwd 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local oc_uid=1000
|
||||
while grep -q "^[^:]*:x:${oc_uid}:" /etc/passwd 2>/dev/null; do
|
||||
oc_uid=$((oc_uid + 1))
|
||||
done
|
||||
local oc_gid="$oc_uid"
|
||||
while grep -q "^[^:]*:x:${oc_gid}:" /etc/group 2>/dev/null; do
|
||||
oc_gid=$((oc_gid + 1))
|
||||
done
|
||||
|
||||
echo "openclaw:x:${oc_uid}:${oc_gid}:openclaw:${OC_DATA}:/bin/false" >> /etc/passwd
|
||||
echo 'openclaw:x:0:0:99999:7:::' >> /etc/shadow
|
||||
echo "openclaw:x:${oc_gid}:" >> /etc/group
|
||||
log_info "已创建 openclaw 系统用户 (uid=${oc_uid}, gid=${oc_gid})"
|
||||
}
|
||||
|
||||
probe_install_root() {
|
||||
if command -v oc_probe_writable_root >/dev/null 2>&1; then
|
||||
if ! oc_probe_writable_root "$OC_BASE_PATH"; then
|
||||
log_error "安装路径不可写: $OC_BASE_PATH"
|
||||
log_error "常见原因: overlay 已满、文件系统只读、挂载点未挂载或权限不正确。"
|
||||
local check_path="/"
|
||||
command -v oc_find_existing_path >/dev/null 2>&1 && check_path=$(oc_find_existing_path "$OC_BASE_PATH")
|
||||
df -h "$check_path" 2>/dev/null | tail -1 || true
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup_partial_install() {
|
||||
# 只在确认目标是规范化后的 openclaw 运行根目录时清理,避免误删用户目录。
|
||||
if command -v oc_safe_openclaw_root >/dev/null 2>&1 && oc_safe_openclaw_root "$OC_INSTALL_PATH"; then
|
||||
log_warn "安装失败,清理未完成的运行目录: $OC_INSTALL_PATH"
|
||||
rm -rf "$OC_INSTALL_PATH" 2>/dev/null || true
|
||||
[ -d /overlay/upper ] && rm -rf "/overlay/upper${OC_INSTALL_PATH}" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# 检测 C 运行时类型 (glibc vs musl)
|
||||
detect_libc() {
|
||||
if ldd --version 2>&1 | grep -qi musl; then
|
||||
@@ -126,6 +191,38 @@ $ver_dir"
|
||||
done
|
||||
}
|
||||
|
||||
detect_oc_node_requirement() {
|
||||
local oc_entry pkg_json required
|
||||
oc_entry=$(find_oc_entry)
|
||||
[ -n "$oc_entry" ] || return 1
|
||||
pkg_json="$(dirname "$oc_entry")/package.json"
|
||||
[ -f "$pkg_json" ] || return 1
|
||||
[ -x "$NODE_BIN" ] || return 1
|
||||
|
||||
required=$(OC_PKG_JSON="$pkg_json" "$NODE_BIN" -e "
|
||||
const fs=require('fs');
|
||||
try{
|
||||
const pkg=JSON.parse(fs.readFileSync(process.env.OC_PKG_JSON,'utf8'));
|
||||
const spec=(pkg.engines&&pkg.engines.node)||'';
|
||||
const m=String(spec).match(/([0-9]+\\.[0-9]+\\.[0-9]+)/);
|
||||
if(m) process.stdout.write(m[1]);
|
||||
}catch(e){}
|
||||
" 2>/dev/null)
|
||||
[ -n "$required" ] || return 1
|
||||
printf '%s\n' "$required"
|
||||
}
|
||||
|
||||
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 command -v oc_assert_node_min_version >/dev/null 2>&1; then
|
||||
oc_assert_node_min_version "$NODE_BIN" "$required" || exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
detect_arch() {
|
||||
local arch
|
||||
arch=$(uname -m)
|
||||
@@ -158,6 +255,7 @@ download_node() {
|
||||
current_ver=$("$NODE_BIN" --version 2>/dev/null | sed 's/^v//')
|
||||
if [ "$current_ver" = "$node_ver" ]; then
|
||||
log_info "Node.js v${node_ver} 已安装, 跳过下载"
|
||||
assert_node_runtime
|
||||
return 0
|
||||
fi
|
||||
# ARM64 musl 使用 Alpine 打包,版本号可能不完全匹配
|
||||
@@ -166,6 +264,7 @@ download_node() {
|
||||
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}), 跳过下载"
|
||||
assert_node_runtime
|
||||
return 0
|
||||
fi
|
||||
log_warn "当前 Node.js v${current_ver}, 将更新到 v${node_ver}"
|
||||
@@ -273,6 +372,7 @@ download_node() {
|
||||
local installed_ver
|
||||
installed_ver=$("$NODE_BIN" --version 2>/dev/null || echo "unknown")
|
||||
log_info "Node.js ${installed_ver} 安装成功"
|
||||
assert_node_runtime
|
||||
else
|
||||
log_error "Node.js 安装验证失败"
|
||||
exit 1
|
||||
@@ -309,12 +409,15 @@ install_openclaw() {
|
||||
|
||||
# 确定安装版本
|
||||
local oc_pkg="openclaw"
|
||||
if [ -n "$OC_VERSION" ]; then
|
||||
if [ -z "$OC_VERSION" ] || [ "$OC_VERSION" = "stable" ]; then
|
||||
oc_pkg="openclaw@${OC_TESTED_VERSION}"
|
||||
log_info "默认稳定版: v${OC_TESTED_VERSION}"
|
||||
elif [ "$OC_VERSION" = "latest" ]; then
|
||||
oc_pkg="openclaw@latest"
|
||||
log_info "安装 npm latest 稳定标签版本"
|
||||
else
|
||||
oc_pkg="openclaw@${OC_VERSION}"
|
||||
log_info "指定版本: v${OC_VERSION}"
|
||||
else
|
||||
oc_pkg="openclaw@latest"
|
||||
log_info "安装最新版本"
|
||||
fi
|
||||
|
||||
local libc_type
|
||||
@@ -371,6 +474,7 @@ install_openclaw() {
|
||||
|
||||
if [ -n "$oc_ver" ]; then
|
||||
log_info "OpenClaw v${oc_ver} 安装成功"
|
||||
assert_node_runtime
|
||||
else
|
||||
log_error "OpenClaw 安装验证失败"
|
||||
exit 1
|
||||
@@ -435,16 +539,23 @@ do_setup() {
|
||||
if [ -n "$OC_VERSION" ]; then
|
||||
echo " OpenClaw: v${OC_VERSION} (稳定版)"
|
||||
else
|
||||
echo " OpenClaw: 最新版"
|
||||
echo " OpenClaw: v${OC_TESTED_VERSION} (默认稳定版)"
|
||||
fi
|
||||
echo " 安装路径: ${OC_INSTALL_PATH}"
|
||||
echo " 数据路径: ${OC_DATA}"
|
||||
echo ""
|
||||
|
||||
ensure_openclaw_user
|
||||
probe_install_root
|
||||
OC_SETUP_CLEANUP=1
|
||||
trap 'rc=$?; if [ $rc -ne 0 ] && [ "${OC_SETUP_CLEANUP:-0}" = "1" ]; then cleanup_partial_install; fi; exit $rc' EXIT
|
||||
|
||||
download_node "$node_ver"
|
||||
install_pnpm
|
||||
install_openclaw
|
||||
init_openclaw
|
||||
OC_SETUP_CLEANUP=0
|
||||
trap - EXIT
|
||||
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════════════════╗"
|
||||
@@ -533,7 +644,11 @@ do_upgrade() {
|
||||
|
||||
echo "=== 正在升级 OpenClaw ==="
|
||||
echo ""
|
||||
"$NPM_BIN" install -g openclaw@latest --prefix="$OC_GLOBAL" $install_flags 2>&1
|
||||
local target_pkg="openclaw@${OC_TESTED_VERSION}"
|
||||
[ "$OC_VERSION" = "latest" ] && target_pkg="openclaw@latest"
|
||||
[ -n "$OC_VERSION" ] && [ "$OC_VERSION" != "latest" ] && [ "$OC_VERSION" != "stable" ] && target_pkg="openclaw@${OC_VERSION}"
|
||||
echo "目标版本: ${target_pkg#openclaw@}"
|
||||
"$NPM_BIN" install -g "$target_pkg" --prefix="$OC_GLOBAL" $install_flags 2>&1
|
||||
|
||||
# 验证升级结果
|
||||
local new_ver=""
|
||||
@@ -547,6 +662,7 @@ do_upgrade() {
|
||||
|
||||
echo ""
|
||||
if [ -n "$new_ver" ]; then
|
||||
assert_node_runtime
|
||||
if [ "$current_ver" = "$new_ver" ]; then
|
||||
log_info "当前已是最新版本 v${new_ver}"
|
||||
else
|
||||
@@ -658,6 +774,9 @@ do_setup_offline() {
|
||||
echo " 离线包: ${offline_dir}"
|
||||
echo ""
|
||||
|
||||
ensure_openclaw_user
|
||||
probe_install_root
|
||||
|
||||
# [1] 安装 Node.js
|
||||
local node_tarball="$offline_dir/node.tar.xz"
|
||||
if [ -f "$node_tarball" ]; then
|
||||
@@ -681,6 +800,7 @@ do_setup_offline() {
|
||||
|
||||
if [ -x "$NODE_BIN" ]; then
|
||||
log_info "Node.js $($NODE_BIN --version 2>/dev/null) 安装成功"
|
||||
assert_node_runtime
|
||||
else
|
||||
log_error "Node.js 安装失败"
|
||||
exit 1
|
||||
@@ -705,6 +825,7 @@ do_setup_offline() {
|
||||
if [ -n "$oc_entry" ]; then
|
||||
local oc_ver=$("$NODE_BIN" "$oc_entry" --version 2>/dev/null | tr -d '[:space:]')
|
||||
log_info "OpenClaw v${oc_ver} 安装成功"
|
||||
assert_node_runtime
|
||||
else
|
||||
log_error "OpenClaw 安装验证失败"
|
||||
exit 1
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
# OpenClaw Node.js 版本校验工具。
|
||||
|
||||
oc_normalize_node_version() {
|
||||
local raw="${1:-}"
|
||||
raw=${raw#v}
|
||||
case "$raw" in
|
||||
[0-9]*.[0-9]*.[0-9]*) printf '%s\n' "$raw"; return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
oc_read_node_version() {
|
||||
local node_bin="$1"
|
||||
local raw
|
||||
[ -x "$node_bin" ] || return 1
|
||||
raw=$("$node_bin" --version 2>/dev/null) || return 1
|
||||
oc_normalize_node_version "$raw"
|
||||
}
|
||||
|
||||
oc_node_version_ge() {
|
||||
local current required
|
||||
current=$(oc_normalize_node_version "$1") || return 1
|
||||
required=$(oc_normalize_node_version "$2") || return 1
|
||||
|
||||
awk -v a="$current" -v b="$required" '
|
||||
BEGIN {
|
||||
split(a, av, "."); split(b, bv, ".");
|
||||
for (i = 1; i <= 3; i++) {
|
||||
ai = av[i] + 0; bi = bv[i] + 0;
|
||||
if (ai > bi) exit 0;
|
||||
if (ai < bi) exit 1;
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
oc_assert_node_min_version() {
|
||||
local node_bin="$1"
|
||||
local required="$2"
|
||||
local current
|
||||
|
||||
current=$(oc_read_node_version "$node_bin") || {
|
||||
echo " [✗] Node.js 不可执行或无法读取版本: $node_bin"
|
||||
return 1
|
||||
}
|
||||
|
||||
if ! oc_node_version_ge "$current" "$required"; then
|
||||
echo " [✗] Node.js v${current} 低于 OpenClaw 要求 v${required}"
|
||||
echo " [!] 请重新运行 openclaw-env node 或 openclaw-env setup 更新运行时"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo " [✓] Node.js v${current} 满足要求 (>= v${required})"
|
||||
return 0
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
#!/bin/sh
|
||||
# luci-app-openclaw 统一路径解析工具
|
||||
#
|
||||
# 为什么单独抽出来:
|
||||
# OpenClaw 的安装根目录会被 init、openclaw-env、Web PTY、LuCI 控制器等多处使用。
|
||||
# 如果每处都自己拼路径,用户输入 /mnt/data/openclaw 时就容易得到
|
||||
# /mnt/data/openclaw/openclaw 这种错误路径,后续权限修复和卸载也会变得危险。
|
||||
|
||||
oc_normalize_install_path() {
|
||||
local raw="${1:-}"
|
||||
|
||||
# 空值统一回到 /opt,保持历史兼容。
|
||||
[ -n "$raw" ] || raw="/opt"
|
||||
|
||||
# 去掉首尾空白和末尾斜杠。OpenWrt busybox sed 支持基础表达式。
|
||||
raw=$(printf '%s' "$raw" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s:/*$::')
|
||||
[ -n "$raw" ] || raw="/"
|
||||
|
||||
case "$raw" in
|
||||
/*) ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
|
||||
case "$raw" in
|
||||
*[\ \ ]*|*\'*|*\"*|*\`*|*\$*|*\;*|*\&*|*\|*|*\<*|*\>*|*\(*|*\)*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$raw" in
|
||||
/|/proc|/proc/*|/sys|/sys/*|/dev|/dev/*|/tmp|/tmp/*|/var|/var/*|/etc|/etc/*|/usr|/usr/*|/bin|/bin/*|/sbin|/sbin/*|/lib|/lib/*|/rom|/rom/*|/overlay|/overlay/*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# 用户如果填写的是实际运行目录 /xxx/openclaw,这里回退到根目录 /xxx。
|
||||
case "$raw" in
|
||||
*/openclaw)
|
||||
raw=${raw%/openclaw}
|
||||
[ -n "$raw" ] || raw="/"
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '%s\n' "$raw"
|
||||
}
|
||||
|
||||
oc_quote() {
|
||||
# POSIX 单引号转义,用于拼接少量必须经 shell 执行的命令。
|
||||
printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
|
||||
}
|
||||
|
||||
oc_load_paths() {
|
||||
local input="${1:-}"
|
||||
local normalized
|
||||
|
||||
normalized=$(oc_normalize_install_path "$input") || return 1
|
||||
|
||||
OPENCLAW_INSTALL_PATH="$normalized"
|
||||
if [ "$OPENCLAW_INSTALL_PATH" = "/" ]; then
|
||||
OC_ROOT="/openclaw"
|
||||
else
|
||||
OC_ROOT="${OPENCLAW_INSTALL_PATH}/openclaw"
|
||||
fi
|
||||
NODE_BASE="${OC_ROOT}/node"
|
||||
OC_GLOBAL="${OC_ROOT}/global"
|
||||
OC_DATA="${OC_ROOT}/data"
|
||||
CONFIG_FILE="${OC_DATA}/.openclaw/openclaw.json"
|
||||
|
||||
export OPENCLAW_INSTALL_PATH OC_ROOT NODE_BASE OC_GLOBAL OC_DATA CONFIG_FILE
|
||||
}
|
||||
|
||||
oc_find_existing_path() {
|
||||
local path="$1"
|
||||
while [ -n "$path" ] && [ "$path" != "/" ]; do
|
||||
[ -e "$path" ] && { printf '%s\n' "$path"; return 0; }
|
||||
path=${path%/*}
|
||||
done
|
||||
printf '/\n'
|
||||
}
|
||||
|
||||
oc_probe_writable_root() {
|
||||
local base="$1"
|
||||
local probe_parent
|
||||
local probe_dir
|
||||
|
||||
probe_parent=$(oc_find_existing_path "$base")
|
||||
[ -d "$probe_parent" ] || return 1
|
||||
[ -w "$probe_parent" ] || return 1
|
||||
|
||||
probe_dir="${probe_parent}/.openclaw-write-test-$$"
|
||||
if mkdir "$probe_dir" 2>/dev/null; then
|
||||
rmdir "$probe_dir" 2>/dev/null || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
oc_safe_openclaw_root() {
|
||||
local root="${1:-}"
|
||||
case "$root" in
|
||||
*/openclaw) ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
case "$root" in
|
||||
/openclaw|/opt/openclaw|/mnt/*/openclaw|/media/*/openclaw|/srv/*/openclaw|/overlay/upper/opt/openclaw)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
@@ -33,10 +33,20 @@ get_pid_by_port() {
|
||||
}
|
||||
|
||||
# ── 路径 (OpenWrt 适配,支持自定义安装路径) ──
|
||||
# 从 UCI 配置读取自定义路径,环境变量可覆盖
|
||||
# 用户配置的是基础路径,程序会在此路径下创建 openclaw 目录
|
||||
OC_BASE_PATH="${OC_INSTALL_PATH:-$(uci -q get openclaw.main.install_path 2>/dev/null || echo '/opt')}"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
# 从 UCI 配置读取自定义路径,环境变量可覆盖。
|
||||
# 注意 OC_INSTALL_PATH 历史上被当作“基础路径”传入,统一解析后再展开到 openclaw 根目录。
|
||||
[ -r /usr/libexec/openclaw-paths.sh ] && . /usr/libexec/openclaw-paths.sh
|
||||
OC_CONFIGURED_PATH="${OC_INSTALL_PATH:-$(uci -q get openclaw.main.install_path 2>/dev/null || echo '/opt')}"
|
||||
if command -v oc_load_paths >/dev/null 2>&1 && oc_load_paths "$OC_CONFIGURED_PATH"; then
|
||||
OC_INSTALL_PATH="$OC_ROOT"
|
||||
else
|
||||
OC_BASE_PATH="${OC_CONFIGURED_PATH%/}"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
NODE_BASE="${NODE_BASE:-${OC_INSTALL_PATH}/node}"
|
||||
OC_GLOBAL="${OC_GLOBAL:-${OC_INSTALL_PATH}/global}"
|
||||
OC_DATA="${OC_DATA:-${OC_INSTALL_PATH}/data}"
|
||||
CONFIG_FILE="${OC_DATA}/.openclaw/openclaw.json"
|
||||
fi
|
||||
NODE_BASE="${NODE_BASE:-${OC_INSTALL_PATH}/node}"
|
||||
OC_GLOBAL="${OC_GLOBAL:-${OC_INSTALL_PATH}/global}"
|
||||
OC_DATA="${OC_DATA:-${OC_INSTALL_PATH}/data}"
|
||||
|
||||
@@ -19,10 +19,19 @@ const PORT = parseInt(process.env.OC_CONFIG_PORT || '18793', 10);
|
||||
const HOST = process.env.OC_CONFIG_HOST || '0.0.0.0'; // token 认证保护,可安全绑定所有接口
|
||||
// 从 UCI 读取安装路径,默认为 /opt/openclaw
|
||||
const { execSync } = require('child_process');
|
||||
function normalizeInstallPath(raw) {
|
||||
let value = String(raw || '').trim().replace(/\/+$/, '');
|
||||
if (!value) value = '/opt';
|
||||
if (!value.startsWith('/')) return '/opt';
|
||||
if (/[\s'"`$;&|<>()]/.test(value)) return '/opt';
|
||||
if (/^\/(proc|sys|dev|tmp|var|etc|usr|bin|sbin|lib|rom|overlay)(\/|$)/.test(value) || value === '/') return '/opt';
|
||||
if (value.endsWith('/openclaw')) value = value.slice(0, -'/openclaw'.length) || '/opt';
|
||||
return value;
|
||||
}
|
||||
let installPath = '/opt/openclaw';
|
||||
try {
|
||||
const uciPath = execSync('uci -q get openclaw.main.install_path 2>/dev/null', { encoding: 'utf8', timeout: 3000 }).trim();
|
||||
if (uciPath) installPath = uciPath + '/openclaw';
|
||||
if (uciPath) installPath = normalizeInstallPath(uciPath) + '/openclaw';
|
||||
} catch {}
|
||||
const NODE_BASE = process.env.NODE_BASE || installPath + '/node';
|
||||
const OC_GLOBAL = process.env.OC_GLOBAL || installPath + '/global';
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
{
|
||||
"luci-app-openclaw": {
|
||||
"description": "Grant UCI access for luci-app-openclaw",
|
||||
"description": "Grant access to the OpenClaw LuCI application",
|
||||
"read": {
|
||||
"uci": [ "openclaw" ]
|
||||
"uci": [ "openclaw" ],
|
||||
"ubus": {
|
||||
"service": [ "list" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "openclaw" ]
|
||||
"uci": [ "openclaw" ],
|
||||
"ubus": {
|
||||
"service": [ "list", "set", "delete" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user