diff --git a/root/usr/bin/openclaw-env b/root/usr/bin/openclaw-env index 213aac7..1ce2e53 100755 --- a/root/usr/bin/openclaw-env +++ b/root/usr/bin/openclaw-env @@ -307,6 +307,22 @@ download_node() { log_info "Node.js ${installed_ver} 安装成功" return 0 fi + + if [ "$libc_type" = "musl" ] && [ "$node_arch" = "linux-arm64" ] && \ + [ "$OPENCLAW_INSTALL_ROOT" != "/opt" ] && oc_node_requires_opt_compat "$NODE_BIN"; then + log_warn "检测到旧版 ARM64 musl Node.js 资产,尝试创建 /opt 兼容链接" + if oc_ensure_opt_compat_link "$OC_ROOT"; then + installed_ver=$(oc_read_node_version "$NODE_BIN" || true) + if [ -n "$installed_ver" ] && oc_node_version_ge "$installed_ver" "$node_ver"; then + log_warn "已启用兼容链接: /opt/openclaw -> ${OC_ROOT}" + log_info "Node.js ${installed_ver} 安装成功" + return 0 + fi + else + log_warn "无法创建 /opt/openclaw 兼容链接,请检查该路径是否已被其他安装占用" + fi + fi + if [ -n "$installed_ver" ]; then log_error "Node.js 版本过低: v${installed_ver} < v${node_ver}" else diff --git a/root/usr/libexec/openclaw-node.sh b/root/usr/libexec/openclaw-node.sh index bc0b862..909aaac 100644 --- a/root/usr/libexec/openclaw-node.sh +++ b/root/usr/libexec/openclaw-node.sh @@ -1,6 +1,8 @@ #!/bin/sh # Shared OpenClaw Node.js runtime/version helpers. +OPENCLAW_LEGACY_ARM64_MUSL_INTERPRETER="${OPENCLAW_LEGACY_ARM64_MUSL_INTERPRETER:-/opt/openclaw/node/lib/ld-musl-aarch64.so.1}" + oc_normalize_node_version() { local version="${1:-}" local old_ifs @@ -67,6 +69,15 @@ oc_read_node_version() { oc_normalize_node_version "$version" } +oc_node_requires_opt_compat() { + local node_bin="${1:-}" + + [ -n "$node_bin" ] || return 1 + [ -f "$node_bin" ] || return 1 + + grep -aqF "$OPENCLAW_LEGACY_ARM64_MUSL_INTERPRETER" "$node_bin" +} + oc_select_node_release_asset_url() { local json_file="${1:-}" local node_arch="${2:-}" diff --git a/root/usr/libexec/openclaw-paths.sh b/root/usr/libexec/openclaw-paths.sh index 2863b61..ecf5dee 100644 --- a/root/usr/libexec/openclaw-paths.sh +++ b/root/usr/libexec/openclaw-paths.sh @@ -2,6 +2,7 @@ # Shared OpenClaw install-root and derived-path helpers. OPENCLAW_DEFAULT_INSTALL_ROOT="${OPENCLAW_DEFAULT_INSTALL_ROOT:-/opt}" +OPENCLAW_OPT_COMPAT_ROOT="${OPENCLAW_OPT_COMPAT_ROOT:-/opt}" oc_normalize_install_root() { local path="$1" @@ -66,6 +67,30 @@ oc_install_root_uses_opt_workaround() { [ "$(oc_normalize_install_root "${1:-$OPENCLAW_INSTALL_ROOT}")" = "/opt" ] } +oc_ensure_opt_compat_link() { + local target_root="$1" + local compat_root compat_link current_target + + target_root="$(oc_normalize_install_root "$target_root")" + [ "$target_root" = "/opt" ] && return 0 + + compat_root="$(oc_normalize_install_root "$OPENCLAW_OPT_COMPAT_ROOT")" + compat_link="${compat_root}/openclaw" + + if [ -L "$compat_link" ]; then + current_target="$(readlink "$compat_link" 2>/dev/null || true)" + [ "$current_target" = "$target_root" ] && return 0 + return 1 + fi + + if [ -e "$compat_link" ]; then + return 1 + fi + + mkdir -p "$compat_root" + ln -s "$target_root" "$compat_link" +} + oc_print_env() { oc_load_paths "$1" cat </dev/null 2>&1; then fail "broken node binary should not be accepted" fi +cat > "$tmpdir/node-legacy-opt" <<'EOF' +#!/bin/sh +/opt/openclaw/node/lib/ld-musl-aarch64.so.1 +EOF +chmod +x "$tmpdir/node-legacy-opt" + +oc_node_requires_opt_compat "$tmpdir/node-legacy-opt" || fail "legacy opt-bound node binary should be detected" +if oc_node_requires_opt_compat "$tmpdir/node-ok" >/dev/null 2>&1; then + fail "modern runnable node helper should not require opt compatibility" +fi + cat > "$tmpdir/node-bins-release.json" <<'EOF' { "tag_name": "node-bins", diff --git a/tests/test_openclaw_paths.sh b/tests/test_openclaw_paths.sh index 9630f7d..57f528f 100644 --- a/tests/test_openclaw_paths.sh +++ b/tests/test_openclaw_paths.sh @@ -27,4 +27,22 @@ trap 'rm -rf "$tmpdir"' EXIT INT TERM existing=$(oc_find_existing_path "$tmpdir/missing/nested") [ "$existing" = "$tmpdir" ] || fail "nearest existing path" +export OPENCLAW_OPT_COMPAT_ROOT="$tmpdir/compat-opt" +target_root="$tmpdir/install-root/openclaw" +mkdir -p "$target_root" + +oc_ensure_opt_compat_link "$target_root" || fail "compat symlink should be created for custom install root" +[ -L "$OPENCLAW_OPT_COMPAT_ROOT/openclaw" ] || fail "compat symlink should exist" +[ "$(readlink "$OPENCLAW_OPT_COMPAT_ROOT/openclaw")" = "$target_root" ] || fail "compat symlink should point to install root" + +oc_ensure_opt_compat_link "$target_root" || fail "compat symlink should be idempotent" + +conflict_root="$tmpdir/conflict-openclaw" +mkdir -p "$conflict_root" +rm -f "$OPENCLAW_OPT_COMPAT_ROOT/openclaw" +ln -s "$conflict_root" "$OPENCLAW_OPT_COMPAT_ROOT/openclaw" +if oc_ensure_opt_compat_link "$target_root" >/dev/null 2>&1; then + fail "compat symlink should fail when pointing at another install root" +fi + echo "ok"