mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-08-07 06:33:58 +08:00
feat(openclaw): support 2026.7.1 stable
This commit is contained in:
@@ -50,7 +50,8 @@
|
||||
- **Hermes 0.18.0 资源兼容** — 保留 Dashboard 兼容兜底,但新版已内置 `dashboard_auth` 与 `web_dist` 时会自动使用上游真实资源
|
||||
- **Hermes Provider Registry 对齐** — 新增 Google Vertex AI provider 入口,移除上游已撤下的 `google-gemini-cli` OAuth 入口,并在安装向导展示外部凭据 / SDK 类 provider,避免误引导用户填写不存在的静态 API Key
|
||||
- **Hermes Provider 补齐** — 跟进上游 `novita` 与 `stepfun` provider,桌面端和 Web/headless 模式的安装向导保持一致
|
||||
- **OpenClaw 推荐稳定版更新** — 推荐稳定版切换到官方 `2026.6.11` / 汉化版 `2026.6.11-zh.1`,并保留新版 `tui`、`tools.toolSearch`、`secrets` 与 `auth.profiles` 等高级配置字段,避免校准修复误清理
|
||||
- **OpenClaw 2026.7.1 稳定版适配** — 推荐稳定版切换到官方 `2026.7.1` / 汉化修复版 `2026.7.1-zh.2`;桌面端、Web/headless、Linux 部署与 standalone 安装统一使用同一稳定基线
|
||||
- **OpenClaw 7.1 Node.js 门槛对齐** — 优先读取安装包 `engines.node`,缺少包元数据时按 `>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0` 兜底,避免误放行 Node.js 23 或过旧的 24.x
|
||||
|
||||
### 改进 (Improvements)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
| 依赖 | 最低版本 | 说明 |
|
||||
|------|----------|------|
|
||||
| Node.js | 18+ | 前端构建与 Web 后端;运行 OpenClaw Gateway 时按当前 OpenClaw 的 `engines.node` 检测,OpenClaw 2026.6.5+ 通常需要 22.19.0+ |
|
||||
| Node.js | 18+ | 前端构建与 Web 后端;运行 OpenClaw Gateway 时按当前 OpenClaw 的 `engines.node` 检测,OpenClaw 2026.7.1 要求 `>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0` |
|
||||
| Rust | stable | Tauri 后端编译 |
|
||||
| Tauri CLI | v2 | `cargo install tauri-cli --version "^2"` |
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ ClawPanel 提供**纯 Web 版部署模式**(零 GUI 依赖),天然兼容 A
|
||||
- **Orange Pi / 树莓派 / RK3588** 等 ARM64 板子 — `npm run serve` 即可运行
|
||||
- **Docker ARM64 镜像** — `docker run ghcr.io/qingchencloud/openclaw:latest` 开箱即用
|
||||
- **Armbian / Debian / Ubuntu Server** — 一键部署脚本自动检测架构
|
||||
- 无需 Rust / Tauri / 图形界面;ClawPanel Web 后端需要 **Node.js 18+**,运行 OpenClaw Gateway 时会按当前 OpenClaw 的 `engines.node` 自动检测(OpenClaw 2026.6.5+ 通常需要 **Node.js 22.19.0+**)
|
||||
- 无需 Rust / Tauri / 图形界面;ClawPanel Web 后端需要 **Node.js 18+**,运行 OpenClaw Gateway 时会按当前 OpenClaw 的 `engines.node` 自动检测(OpenClaw 2026.7.1 要求 `>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0`)
|
||||
|
||||
> 📖 详见 [Armbian 部署指南](docs/armbian-deploy.md) | [Web 版开发说明](#web-开发版无需-rusttauri)
|
||||
|
||||
@@ -757,7 +757,7 @@ Web 版适用于 Linux 服务器(无桌面环境),通过浏览器远程管
|
||||
|
||||
### 环境要求
|
||||
|
||||
- **Node.js** >= 18(ClawPanel Web 后端);运行 OpenClaw Gateway 会按当前 OpenClaw 要求自动检测,OpenClaw 2026.6.5+ 通常需要 **22.19.0+**
|
||||
- **Node.js** >= 18(ClawPanel Web 后端);运行 OpenClaw Gateway 会按当前 OpenClaw 要求自动检测,OpenClaw 2026.7.1 要求 `>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0`
|
||||
- **Git**(用于 OpenClaw 依赖安装)
|
||||
- **端口** 1420(ClawPanel)+ 18789(Gateway)
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
| 依赖 | 最低版本 | 说明 |
|
||||
|------|----------|------|
|
||||
| Node.js | 18+ | ClawPanel Web 后端;运行 OpenClaw Gateway 时按当前 OpenClaw `engines.node` 检测,OpenClaw 2026.6.5+ 通常需要 22.19.0+ |
|
||||
| Node.js | 18+ | ClawPanel Web 后端;运行 OpenClaw Gateway 时按当前 OpenClaw `engines.node` 检测,OpenClaw 2026.7.1 要求 `>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0` |
|
||||
| npm | 随 Node.js | 包管理器 |
|
||||
| Git | 任意 | 克隆仓库 |
|
||||
| OpenClaw | 最新 | ClawPanel 管理的对象 |
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
},
|
||||
"default": {
|
||||
"official": {
|
||||
"recommended": "2026.6.11"
|
||||
"recommended": "2026.7.1"
|
||||
},
|
||||
"chinese": {
|
||||
"recommended": "2026.6.11-zh.1"
|
||||
"recommended": "2026.7.1-zh.2"
|
||||
}
|
||||
},
|
||||
"panels": {
|
||||
|
||||
@@ -334,8 +334,10 @@ const PANEL_VERSION = (() => {
|
||||
})()
|
||||
const SITE_BASE_URL = 'https://claw.qt.cool'
|
||||
const VERSION_POLICY_PATH = path.join(__dev_dirname, '..', 'openclaw-version-policy.json')
|
||||
const OPENCLAW_NODE_REQUIREMENT_VERSION_FLOOR = '2026.6.5'
|
||||
const OPENCLAW_NODE_REQUIREMENT_FOR_NEWER_RUNTIME = '>=22.19.0'
|
||||
const OPENCLAW_NODE_22_19_VERSION_FLOOR = '2026.6.5'
|
||||
const OPENCLAW_NODE_22_19_REQUIREMENT = '>=22.19.0'
|
||||
const OPENCLAW_NODE_7_1_VERSION_FLOOR = '2026.7.1'
|
||||
const OPENCLAW_NODE_7_1_REQUIREMENT = '>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0'
|
||||
|
||||
function ensureArrayContains(value, required) {
|
||||
const current = Array.isArray(value)
|
||||
@@ -746,9 +748,15 @@ function openclawNodeRequirement() {
|
||||
}
|
||||
}
|
||||
if (!installedVersion && cliPath) installedVersion = readVersionFromInstallation(cliPath)
|
||||
return installedVersion && versionGe(baseVersion(installedVersion), OPENCLAW_NODE_REQUIREMENT_VERSION_FLOOR)
|
||||
? OPENCLAW_NODE_REQUIREMENT_FOR_NEWER_RUNTIME
|
||||
: null
|
||||
return fallbackOpenclawNodeRequirement(installedVersion)
|
||||
}
|
||||
|
||||
function fallbackOpenclawNodeRequirement(installedVersion) {
|
||||
if (!installedVersion) return null
|
||||
const version = baseVersion(installedVersion)
|
||||
if (versionGe(version, OPENCLAW_NODE_7_1_VERSION_FLOOR)) return OPENCLAW_NODE_7_1_REQUIREMENT
|
||||
if (versionGe(version, OPENCLAW_NODE_22_19_VERSION_FLOOR)) return OPENCLAW_NODE_22_19_REQUIREMENT
|
||||
return null
|
||||
}
|
||||
|
||||
function parseNodeVersionTriplet(value) {
|
||||
@@ -772,10 +780,18 @@ function nodeVersionSatisfiesClause(version, clause) {
|
||||
const min = parseNodeVersionTriplet(raw.slice(2))
|
||||
return !!min && compareVersionTriplet(version, min) >= 0
|
||||
}
|
||||
if (raw.startsWith('<=')) {
|
||||
const max = parseNodeVersionTriplet(raw.slice(2))
|
||||
return !!max && compareVersionTriplet(version, max) <= 0
|
||||
}
|
||||
if (raw.startsWith('>')) {
|
||||
const min = parseNodeVersionTriplet(raw.slice(1))
|
||||
return !!min && compareVersionTriplet(version, min) > 0
|
||||
}
|
||||
if (raw.startsWith('<')) {
|
||||
const max = parseNodeVersionTriplet(raw.slice(1))
|
||||
return !!max && compareVersionTriplet(version, max) < 0
|
||||
}
|
||||
if (raw.startsWith('^')) {
|
||||
const min = parseNodeVersionTriplet(raw.slice(1))
|
||||
if (!min) return false
|
||||
@@ -17665,7 +17681,7 @@ async function _apiMiddleware(req, res, next) {
|
||||
}
|
||||
|
||||
// 导出供 serve.js 独立部署使用
|
||||
export { _initApi, _apiMiddleware }
|
||||
export { _initApi, _apiMiddleware, nodeVersionSatisfiesRequirement }
|
||||
|
||||
export function devApiPlugin() {
|
||||
let _inited = false
|
||||
|
||||
@@ -12,10 +12,13 @@ REPO_URL="https://github.com/qingchencloud/clawpanel.git"
|
||||
REPO_URL_GITEE="https://gitee.com/QtCodeCreators/clawpanel.git"
|
||||
NPM_REGISTRY="https://registry.npmmirror.com"
|
||||
PANEL_NODE_MIN_VERSION="18.0.0"
|
||||
OPENCLAW_RECOMMENDED_VERSION="2026.5.18-zh.1"
|
||||
OPENCLAW_NODE_RUNTIME_FLOOR_VERSION="2026.6.5"
|
||||
OPENCLAW_NEW_NODE_MIN_VERSION="22.19.0"
|
||||
OPENCLAW_RECOMMENDED_VERSION="2026.7.1-zh.2"
|
||||
OPENCLAW_NODE_22_19_FLOOR_VERSION="2026.6.5"
|
||||
OPENCLAW_NODE_7_1_FLOOR_VERSION="2026.7.1"
|
||||
OPENCLAW_NODE_22_19_REQUIREMENT=">=22.19.0"
|
||||
OPENCLAW_7_1_NODE_REQUIREMENT=">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0"
|
||||
NODE_MIN_VERSION="$PANEL_NODE_MIN_VERSION"
|
||||
NODE_REQUIREMENT=">=${PANEL_NODE_MIN_VERSION}"
|
||||
|
||||
# 检测权限模式
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
@@ -95,13 +98,24 @@ version_ge() {
|
||||
[ "$actual_patch" -ge "$min_patch" ]
|
||||
}
|
||||
|
||||
node_version_ge_min() {
|
||||
version_ge "$1" "$NODE_MIN_VERSION"
|
||||
node_version_satisfies_7_1() {
|
||||
local actual="${1#v}"
|
||||
local major
|
||||
actual=$(printf '%s' "$actual" | grep -Eo '[0-9]+(\.[0-9]+){0,2}' | head -1 || true)
|
||||
major=${actual%%.*}
|
||||
case "$major" in
|
||||
22) version_ge "$actual" "22.22.3" && ! version_ge "$actual" "23.0.0" ;;
|
||||
24) version_ge "$actual" "24.15.0" && ! version_ge "$actual" "25.0.0" ;;
|
||||
*) [ "$major" -ge 25 ] 2>/dev/null && version_ge "$actual" "25.9.0" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
openclaw_version_needs_new_node() {
|
||||
local base_version="${1%%-*}"
|
||||
[ -n "$base_version" ] && version_ge "$base_version" "$OPENCLAW_NODE_RUNTIME_FLOOR_VERSION"
|
||||
node_version_satisfies_requirement() {
|
||||
if [ "$NODE_REQUIREMENT" = "$OPENCLAW_7_1_NODE_REQUIREMENT" ]; then
|
||||
node_version_satisfies_7_1 "$1"
|
||||
else
|
||||
version_ge "$1" "$NODE_MIN_VERSION"
|
||||
fi
|
||||
}
|
||||
|
||||
# 安装 Node.js
|
||||
@@ -109,15 +123,15 @@ install_node() {
|
||||
if command -v node &> /dev/null; then
|
||||
local node_version
|
||||
node_version=$(node -v)
|
||||
if node_version_ge_min "$node_version"; then
|
||||
if node_version_satisfies_requirement "$node_version"; then
|
||||
echo "✅ Node.js $(node -v) 已安装"
|
||||
return 0
|
||||
else
|
||||
echo "⚠️ Node.js $(node -v) 版本过低,需要 >=${NODE_MIN_VERSION}"
|
||||
echo "⚠️ Node.js $(node -v) 不满足要求 ${NODE_REQUIREMENT}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "📦 安装 Node.js LTS(要求 >=${NODE_MIN_VERSION})..."
|
||||
echo "📦 安装 Node.js LTS(要求 ${NODE_REQUIREMENT})..."
|
||||
case "$OS" in
|
||||
ubuntu|debian|linuxmint|pop)
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | run_pkg_cmd bash -
|
||||
@@ -139,9 +153,9 @@ install_node() {
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if ! node_version_ge_min "$(node -v)"; then
|
||||
echo "❌ Node.js $(node -v) 仍低于 OpenClaw 要求 >=${NODE_MIN_VERSION}"
|
||||
echo " 请手动安装 Node.js ${NODE_MIN_VERSION} 或更高版本后重试"
|
||||
if ! node_version_satisfies_requirement "$(node -v)"; then
|
||||
echo "❌ Node.js $(node -v) 仍不满足 OpenClaw 要求 ${NODE_REQUIREMENT}"
|
||||
echo " 请手动安装满足 ${NODE_REQUIREMENT} 的 Node.js 后重试"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Node.js $(node -v) 安装完成"
|
||||
@@ -149,9 +163,16 @@ install_node() {
|
||||
|
||||
ensure_node_for_openclaw_version() {
|
||||
local openclaw_version="$1"
|
||||
if openclaw_version_needs_new_node "$openclaw_version"; then
|
||||
NODE_MIN_VERSION="$OPENCLAW_NEW_NODE_MIN_VERSION"
|
||||
echo "ℹ️ OpenClaw ${openclaw_version} 需要 Node.js >=${NODE_MIN_VERSION}"
|
||||
local base_version="${openclaw_version%%-*}"
|
||||
if [ -n "$base_version" ] && version_ge "$base_version" "$OPENCLAW_NODE_7_1_FLOOR_VERSION"; then
|
||||
NODE_MIN_VERSION="22.22.3"
|
||||
NODE_REQUIREMENT="$OPENCLAW_7_1_NODE_REQUIREMENT"
|
||||
echo "ℹ️ OpenClaw ${openclaw_version} 需要 Node.js ${NODE_REQUIREMENT}"
|
||||
install_node
|
||||
elif [ -n "$base_version" ] && version_ge "$base_version" "$OPENCLAW_NODE_22_19_FLOOR_VERSION"; then
|
||||
NODE_MIN_VERSION="22.19.0"
|
||||
NODE_REQUIREMENT="$OPENCLAW_NODE_22_19_REQUIREMENT"
|
||||
echo "ℹ️ OpenClaw ${openclaw_version} 需要 Node.js ${NODE_REQUIREMENT}"
|
||||
install_node
|
||||
fi
|
||||
}
|
||||
@@ -222,6 +243,7 @@ detect_openclaw_source() {
|
||||
|
||||
# 安装 OpenClaw
|
||||
install_openclaw() {
|
||||
ensure_node_for_openclaw_version "$OPENCLAW_RECOMMENDED_VERSION"
|
||||
local oc_path=$(find_openclaw)
|
||||
local oc_ver=""
|
||||
if [ -n "$oc_path" ]; then
|
||||
|
||||
@@ -167,11 +167,21 @@ fn node_version_satisfies_clause(version: [u32; 3], clause: &str) -> bool {
|
||||
.map(|min| cmp_version_triplet(version, min).is_ge())
|
||||
.unwrap_or(false);
|
||||
}
|
||||
if let Some(raw) = clause.strip_prefix("<=") {
|
||||
return parse_node_version_triplet(raw)
|
||||
.map(|max| cmp_version_triplet(version, max).is_le())
|
||||
.unwrap_or(false);
|
||||
}
|
||||
if let Some(raw) = clause.strip_prefix('>') {
|
||||
return parse_node_version_triplet(raw)
|
||||
.map(|min| cmp_version_triplet(version, min).is_gt())
|
||||
.unwrap_or(false);
|
||||
}
|
||||
if let Some(raw) = clause.strip_prefix('<') {
|
||||
return parse_node_version_triplet(raw)
|
||||
.map(|max| cmp_version_triplet(version, max).is_lt())
|
||||
.unwrap_or(false);
|
||||
}
|
||||
if let Some(raw) = clause.strip_prefix('^') {
|
||||
let Some(min) = parse_node_version_triplet(raw) else {
|
||||
return false;
|
||||
@@ -210,11 +220,20 @@ fn read_package_json_field(path: &std::path::Path, pointer: &str) -> Option<Stri
|
||||
.filter(|v| !v.is_empty())
|
||||
}
|
||||
|
||||
const OPENCLAW_NODE_REQUIREMENT_VERSION_FLOOR: &str = "2026.6.5";
|
||||
const OPENCLAW_NODE_REQUIREMENT_FOR_NEWER_RUNTIME: &str = ">=22.19.0";
|
||||
const OPENCLAW_NODE_22_19_VERSION_FLOOR: &str = "2026.6.5";
|
||||
const OPENCLAW_NODE_22_19_REQUIREMENT: &str = ">=22.19.0";
|
||||
const OPENCLAW_NODE_7_1_VERSION_FLOOR: &str = "2026.7.1";
|
||||
const OPENCLAW_NODE_7_1_REQUIREMENT: &str = ">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0";
|
||||
|
||||
fn openclaw_version_requires_node_22_19(version: &str) -> bool {
|
||||
parse_version(&base_version(version)) >= parse_version(OPENCLAW_NODE_REQUIREMENT_VERSION_FLOOR)
|
||||
fn fallback_openclaw_node_requirement(version: &str) -> Option<&'static str> {
|
||||
let version = parse_version(&base_version(version));
|
||||
if version >= parse_version(OPENCLAW_NODE_7_1_VERSION_FLOOR) {
|
||||
return Some(OPENCLAW_NODE_7_1_REQUIREMENT);
|
||||
}
|
||||
if version >= parse_version(OPENCLAW_NODE_22_19_VERSION_FLOOR) {
|
||||
return Some(OPENCLAW_NODE_22_19_REQUIREMENT);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn cli_source_prefers_zh_package(cli_source: &str) -> bool {
|
||||
@@ -271,8 +290,9 @@ pub(crate) fn openclaw_node_requirement() -> Option<String> {
|
||||
.and_then(|pkg| read_package_json_field(pkg, "/version"))
|
||||
.or_else(|| read_version_from_installation(cli_path_ref));
|
||||
installed_version
|
||||
.filter(|version| openclaw_version_requires_node_22_19(version))
|
||||
.map(|_| OPENCLAW_NODE_REQUIREMENT_FOR_NEWER_RUNTIME.to_string())
|
||||
.as_deref()
|
||||
.and_then(fallback_openclaw_node_requirement)
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
fn standalone_bundled_node_bin(cli_path: &str) -> Option<PathBuf> {
|
||||
@@ -7707,9 +7727,9 @@ pub fn invalidate_path_cache() -> Result<(), String> {
|
||||
mod write_openclaw_config_merge_tests {
|
||||
use super::apply_reset_inheritance;
|
||||
use super::calibration_richness_score;
|
||||
use super::fallback_openclaw_node_requirement;
|
||||
use super::merge_configs_preserving_fields;
|
||||
use super::node_version_satisfies_requirement;
|
||||
use super::openclaw_version_requires_node_22_19;
|
||||
use super::path_without_curdir_string;
|
||||
use super::promote_nested_standalone_dir;
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -7978,11 +7998,33 @@ mod write_openclaw_config_merge_tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openclaw_node_requirement_floor_starts_at_2026_6_5() {
|
||||
assert!(!openclaw_version_requires_node_22_19("2026.6.4"));
|
||||
assert!(openclaw_version_requires_node_22_19("2026.6.5"));
|
||||
assert!(openclaw_version_requires_node_22_19("2026.6.5-zh.1"));
|
||||
assert!(openclaw_version_requires_node_22_19("2026.7.1"));
|
||||
fn openclaw_node_requirement_fallback_tracks_runtime_floors() {
|
||||
assert_eq!(fallback_openclaw_node_requirement("2026.6.4"), None);
|
||||
assert_eq!(
|
||||
fallback_openclaw_node_requirement("2026.6.5-zh.1"),
|
||||
Some(">=22.19.0")
|
||||
);
|
||||
assert_eq!(
|
||||
fallback_openclaw_node_requirement("2026.7.1"),
|
||||
Some(">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0")
|
||||
);
|
||||
assert_eq!(
|
||||
fallback_openclaw_node_requirement("2026.7.1-zh.1"),
|
||||
Some(">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openclaw_2026_7_1_node_range_rejects_unsupported_gaps() {
|
||||
let requirement = ">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0";
|
||||
assert!(!node_version_satisfies_requirement("v22.22.2", requirement));
|
||||
assert!(node_version_satisfies_requirement("v22.22.3", requirement));
|
||||
assert!(!node_version_satisfies_requirement("v23.11.1", requirement));
|
||||
assert!(!node_version_satisfies_requirement("v24.14.9", requirement));
|
||||
assert!(node_version_satisfies_requirement("v24.15.0", requirement));
|
||||
assert!(!node_version_satisfies_requirement("v25.8.9", requirement));
|
||||
assert!(node_version_satisfies_requirement("v25.9.0", requirement));
|
||||
assert!(node_version_satisfies_requirement("v33.0.0", requirement));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -196,8 +196,8 @@ export const KERNEL_TARGET = {
|
||||
// 不要与 dev-api.js 中设备签名 payload 字符串前缀 `v3|deviceId|...` 混淆——
|
||||
// 后者是 **device signature payload 字符串格式版本**,两者完全独立、互不相关。
|
||||
// 即使在 v4 握手协议下,签名 payload 字符串仍以 `v3|` 开头(这是 payload schema 版本)。
|
||||
official: '2026.5.19',
|
||||
chinese: '2026.5.18-zh.1',
|
||||
official: '2026.7.1',
|
||||
chinese: '2026.7.1-zh.2',
|
||||
},
|
||||
hermes: {
|
||||
default: '0.13.x',
|
||||
|
||||
@@ -162,8 +162,8 @@ test('buildSnapshot edge case: version slightly below 5.6 feature requirement',
|
||||
test('buildSnapshot.isLatest works against KERNEL_TARGET', () => {
|
||||
const atOfficial = buildSnapshot('openclaw', KERNEL_TARGET.openclaw.official)
|
||||
const atChinese = buildSnapshot('openclaw', KERNEL_TARGET.openclaw.chinese)
|
||||
const aboveTarget = buildSnapshot('openclaw', '2026.6.0')
|
||||
const belowTarget = buildSnapshot('openclaw', '2026.5.18')
|
||||
const aboveTarget = buildSnapshot('openclaw', '2026.7.2')
|
||||
const belowTarget = buildSnapshot('openclaw', '2026.6.11')
|
||||
assert.equal(atOfficial.isLatest, true)
|
||||
assert.equal(atChinese.isLatest, true)
|
||||
assert.equal(aboveTarget.isLatest, true)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { nodeVersionSatisfiesRequirement } from '../scripts/dev-api.js'
|
||||
|
||||
const devApi = readFileSync(new URL('../scripts/dev-api.js', import.meta.url), 'utf8')
|
||||
const rustConfig = readFileSync(new URL('../src-tauri/src/commands/config.rs', import.meta.url), 'utf8')
|
||||
@@ -27,13 +28,29 @@ test('desktop check_node prefers standalone bundled Node before PATH lookup', ()
|
||||
assert.match(rustConfig, /"standalone-bundled"/)
|
||||
})
|
||||
|
||||
test('Node 22.19 fallback is gated by OpenClaw 2026.6.5 or newer', () => {
|
||||
assert.match(devApi, /OPENCLAW_NODE_REQUIREMENT_VERSION_FLOOR = '2026\.6\.5'/)
|
||||
assert.match(devApi, /OPENCLAW_NODE_REQUIREMENT_FOR_NEWER_RUNTIME = '>=22\.19\.0'/)
|
||||
assert.match(devApi, /versionGe\(baseVersion\(installedVersion\), OPENCLAW_NODE_REQUIREMENT_VERSION_FLOOR\)/)
|
||||
test('Node fallback follows the OpenClaw 6.5 and 7.1 runtime floors', () => {
|
||||
assert.match(devApi, /OPENCLAW_NODE_22_19_VERSION_FLOOR = '2026\.6\.5'/)
|
||||
assert.match(devApi, /OPENCLAW_NODE_22_19_REQUIREMENT = '>=22\.19\.0'/)
|
||||
assert.match(devApi, /OPENCLAW_NODE_7_1_VERSION_FLOOR = '2026\.7\.1'/)
|
||||
assert.match(devApi, /OPENCLAW_NODE_7_1_REQUIREMENT = '>=22\.22\.3 <23 \|\| >=24\.15\.0 <25 \|\| >=25\.9\.0'/)
|
||||
assert.match(devApi, /fallbackOpenclawNodeRequirement\(installedVersion\)/)
|
||||
assert.doesNotMatch(devApi, /DEFAULT_OPENCLAW_NODE_REQUIREMENT/)
|
||||
|
||||
assert.match(rustConfig, /OPENCLAW_NODE_REQUIREMENT_VERSION_FLOOR: &str = "2026\.6\.5"/)
|
||||
assert.match(rustConfig, /OPENCLAW_NODE_REQUIREMENT_FOR_NEWER_RUNTIME: &str = ">=22\.19\.0"/)
|
||||
assert.match(rustConfig, /openclaw_version_requires_node_22_19/)
|
||||
assert.match(rustConfig, /OPENCLAW_NODE_22_19_VERSION_FLOOR: &str = "2026\.6\.5"/)
|
||||
assert.match(rustConfig, /OPENCLAW_NODE_22_19_REQUIREMENT: &str = ">=22\.19\.0"/)
|
||||
assert.match(rustConfig, /OPENCLAW_NODE_7_1_VERSION_FLOOR: &str = "2026\.7\.1"/)
|
||||
assert.match(rustConfig, /OPENCLAW_NODE_7_1_REQUIREMENT: &str =\s*">=22\.22\.3 <23 \|\| >=24\.15\.0 <25 \|\| >=25\.9\.0"/)
|
||||
assert.match(rustConfig, /fallback_openclaw_node_requirement/)
|
||||
})
|
||||
|
||||
test('Web Node range parser accepts OpenClaw 2026.7.1 supported versions only', () => {
|
||||
const requirement = '>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0'
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v22.22.2', requirement), false)
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v22.22.3', requirement), true)
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v23.11.1', requirement), false)
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v24.14.9', requirement), false)
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v24.15.0', requirement), true)
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v25.8.9', requirement), false)
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v25.9.0', requirement), true)
|
||||
assert.equal(nodeVersionSatisfiesRequirement('v33.0.0', requirement), true)
|
||||
})
|
||||
|
||||
37
tests/openclaw-2026-7-1-compat.test.js
Normal file
37
tests/openclaw-2026-7-1-compat.test.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
const policy = JSON.parse(readFileSync(new URL('../openclaw-version-policy.json', import.meta.url), 'utf8'))
|
||||
const featureCatalog = readFileSync(new URL('../src/lib/feature-catalog.js', import.meta.url), 'utf8')
|
||||
const linuxDeploy = readFileSync(new URL('../scripts/linux-deploy.sh', import.meta.url), 'utf8')
|
||||
const webBackend = readFileSync(new URL('../scripts/dev-api.js', import.meta.url), 'utf8')
|
||||
const desktopDevice = readFileSync(new URL('../src-tauri/src/commands/device.rs', import.meta.url), 'utf8')
|
||||
|
||||
test('ClawPanel recommends the matching official and Chinese 2026.7.1 stable builds', () => {
|
||||
assert.equal(policy.default.official.recommended, '2026.7.1')
|
||||
assert.equal(policy.default.chinese.recommended, '2026.7.1-zh.2')
|
||||
assert.match(featureCatalog, /official: '2026\.7\.1'/)
|
||||
assert.match(featureCatalog, /chinese: '2026\.7\.1-zh\.2'/)
|
||||
})
|
||||
|
||||
test('Linux deployment installs the Chinese 2026.7.1 stable build', () => {
|
||||
assert.match(linuxDeploy, /OPENCLAW_RECOMMENDED_VERSION="2026\.7\.1-zh\.2"/)
|
||||
assert.match(linuxDeploy, /\[ "\$major" -ge 25 \]/)
|
||||
assert.match(
|
||||
linuxDeploy,
|
||||
/OPENCLAW_7_1_NODE_REQUIREMENT=">=22\.22\.3 <23 \|\| >=24\.15\.0 <25 \|\| >=25\.9\.0"/,
|
||||
)
|
||||
|
||||
const installStart = linuxDeploy.indexOf('install_openclaw() {')
|
||||
const npmInstall = linuxDeploy.indexOf('npm install -g "$openclaw_spec"', installStart)
|
||||
const runtimeGuard = linuxDeploy.indexOf('ensure_node_for_openclaw_version "$OPENCLAW_RECOMMENDED_VERSION"', installStart)
|
||||
assert.ok(installStart >= 0 && runtimeGuard > installStart, 'OpenClaw install must preflight its target runtime')
|
||||
assert.ok(npmInstall > runtimeGuard, 'Node runtime preflight must happen before npm installs OpenClaw')
|
||||
})
|
||||
|
||||
test('Gateway connect frames retain a range that overlaps OpenClaw 2026.7.1 protocol v4', () => {
|
||||
assert.match(webBackend, /minProtocol: 3, maxProtocol: 4/)
|
||||
assert.match(desktopDevice, /"minProtocol": 3/)
|
||||
assert.match(desktopDevice, /"maxProtocol": 4/)
|
||||
})
|
||||
Reference in New Issue
Block a user