From ea08f2eb8c35a863820d7e7822d5eb3aae95eb59 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 25 Mar 2026 06:15:21 -0700 Subject: [PATCH] fix(runtime): support Node 22.14 installs --- CHANGELOG.md | 1 + docs/index.md | 2 +- docs/install/ansible.md | 2 +- docs/install/bun.md | 2 +- docs/install/index.md | 2 +- docs/install/installer.md | 4 ++-- docs/install/node.md | 4 ++-- docs/platforms/linux.md | 2 +- docs/platforms/mac/bundled-gateway.md | 2 +- docs/platforms/mac/dev-setup.md | 2 +- docs/platforms/mac/signing.md | 2 +- docs/start/getting-started.md | 2 +- docs/start/setup.md | 2 +- package.json | 2 +- scripts/install.sh | 2 +- src/cli/update-cli.test.ts | 4 ++-- src/cli/update-cli/update-command.ts | 2 +- src/commands/doctor-gateway-services.ts | 2 +- src/daemon/program-args.ts | 2 +- src/daemon/runtime-paths.test.ts | 22 ++++++++--------- src/daemon/runtime-paths.ts | 2 +- src/daemon/service-audit.ts | 2 +- src/infra/runtime-guard.test.ts | 32 ++++++++++++------------- src/infra/runtime-guard.ts | 4 ++-- src/infra/update-check.test.ts | 4 ++-- src/memory/embeddings.ts | 2 +- 26 files changed, 56 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f0fd6dc99..bb6d2d52ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Runtime/install: lower the supported Node 22 floor to `22.14+` while continuing to recommend Node 24, so npm installs and self-updates do not strand Node 22.14 users on older releases. - CLI/update: preflight the target npm package `engines.node` before `openclaw update` runs a global package install, so outdated Node runtimes fail with a clear upgrade message instead of attempting an unsupported latest release. ## 2026.3.24-beta.1 diff --git a/docs/index.md b/docs/index.md index 270f0835287..bdfca54fe97 100644 --- a/docs/index.md +++ b/docs/index.md @@ -54,7 +54,7 @@ OpenClaw is a **self-hosted gateway** that connects your favorite chat apps — - **Agent-native**: built for coding agents with tool use, sessions, memory, and multi-agent routing - **Open source**: MIT licensed, community-driven -**What do you need?** Node 24 (recommended), or Node 22 LTS (`22.16+`) for compatibility, an API key from your chosen provider, and 5 minutes. For best quality and security, use the strongest latest-generation model available. +**What do you need?** Node 24 (recommended), or Node 22 LTS (`22.14+`) for compatibility, an API key from your chosen provider, and 5 minutes. For best quality and security, use the strongest latest-generation model available. ## How it works diff --git a/docs/install/ansible.md b/docs/install/ansible.md index 84ed56c5d03..06eebc2ff2c 100644 --- a/docs/install/ansible.md +++ b/docs/install/ansible.md @@ -48,7 +48,7 @@ The Ansible playbook installs and configures: 1. **Tailscale** -- mesh VPN for secure remote access 2. **UFW firewall** -- SSH + Tailscale ports only 3. **Docker CE + Compose V2** -- for agent sandboxes -4. **Node.js 24 + pnpm** -- runtime dependencies (Node 22 LTS, currently `22.16+`, remains supported) +4. **Node.js 24 + pnpm** -- runtime dependencies (Node 22 LTS, currently `22.14+`, remains supported) 5. **OpenClaw** -- host-based, not containerized 6. **Systemd service** -- auto-start with security hardening diff --git a/docs/install/bun.md b/docs/install/bun.md index 080479fc6b0..d0e11d5b166 100644 --- a/docs/install/bun.md +++ b/docs/install/bun.md @@ -41,7 +41,7 @@ Bun is an optional local runtime for running TypeScript directly (`bun run ...`, Bun blocks dependency lifecycle scripts unless explicitly trusted. For this repo, the commonly blocked scripts are not required: -- `@whiskeysockets/baileys` `preinstall` -- checks Node major >= 20 (OpenClaw defaults to Node 24 and still supports Node 22 LTS, currently `22.16+`) +- `@whiskeysockets/baileys` `preinstall` -- checks Node major >= 20 (OpenClaw defaults to Node 24 and still supports Node 22 LTS, currently `22.14+`) - `protobufjs` `postinstall` -- emits warnings about incompatible version schemes (no build artifacts) If you hit a runtime issue that requires these scripts, trust them explicitly: diff --git a/docs/install/index.md b/docs/install/index.md index 8830e377059..a3fe18e8f21 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -45,7 +45,7 @@ For all flags and CI/automation options, see [Installer internals](/install/inst ## System requirements -- **Node 24** (recommended) or Node 22.16+ — the installer script handles this automatically +- **Node 24** (recommended) or Node 22.14+ — the installer script handles this automatically - **macOS, Linux, or Windows** — both native Windows and WSL2 are supported; WSL2 is more stable. See [Windows](/platforms/windows). - `pnpm` is only needed if you build from source diff --git a/docs/install/installer.md b/docs/install/installer.md index f32fe2de198..dcf1ec8b759 100644 --- a/docs/install/installer.md +++ b/docs/install/installer.md @@ -71,7 +71,7 @@ Recommended for most interactive installs on macOS/Linux/WSL. Supports macOS and Linux (including WSL). If macOS is detected, installs Homebrew if missing. - Checks Node version and installs Node 24 if needed (Homebrew on macOS, NodeSource setup scripts on Linux apt/dnf/yum). OpenClaw still supports Node 22 LTS, currently `22.16+`, for compatibility. + Checks Node version and installs Node 24 if needed (Homebrew on macOS, NodeSource setup scripts on Linux apt/dnf/yum). OpenClaw still supports Node 22 LTS, currently `22.14+`, for compatibility. Installs Git if missing. @@ -257,7 +257,7 @@ Designed for environments where you want everything under a local prefix (defaul Requires PowerShell 5+. - If missing, attempts install via winget, then Chocolatey, then Scoop. Node 22 LTS, currently `22.16+`, remains supported for compatibility. + If missing, attempts install via winget, then Chocolatey, then Scoop. Node 22 LTS, currently `22.14+`, remains supported for compatibility. - `npm` method (default): global npm install using selected `-Tag` diff --git a/docs/install/node.md b/docs/install/node.md index 6e2f7062c42..3e95ab34b32 100644 --- a/docs/install/node.md +++ b/docs/install/node.md @@ -9,7 +9,7 @@ read_when: # Node.js -OpenClaw requires **Node 22.16 or newer**. **Node 24 is the default and recommended runtime** for installs, CI, and release workflows. Node 22 remains supported via the active LTS line. The [installer script](/install#alternative-install-methods) will detect and install Node automatically — this page is for when you want to set up Node yourself and make sure everything is wired up correctly (versions, PATH, global installs). +OpenClaw requires **Node 22.14 or newer**. **Node 24 is the default and recommended runtime** for installs, CI, and release workflows. Node 22 remains supported via the active LTS line. The [installer script](/install#alternative-install-methods) will detect and install Node automatically — this page is for when you want to set up Node yourself and make sure everything is wired up correctly (versions, PATH, global installs). ## Check your version @@ -17,7 +17,7 @@ OpenClaw requires **Node 22.16 or newer**. **Node 24 is the default and recommen node -v ``` -If this prints `v24.x.x` or higher, you're on the recommended default. If it prints `v22.16.x` or higher, you're on the supported Node 22 LTS path, but we still recommend upgrading to Node 24 when convenient. If Node isn't installed or the version is too old, pick an install method below. +If this prints `v24.x.x` or higher, you're on the recommended default. If it prints `v22.14.x` or higher, you're on the supported Node 22 LTS path, but we still recommend upgrading to Node 24 when convenient. If Node isn't installed or the version is too old, pick an install method below. ## Install Node diff --git a/docs/platforms/linux.md b/docs/platforms/linux.md index 522218ddc72..ba6804500e3 100644 --- a/docs/platforms/linux.md +++ b/docs/platforms/linux.md @@ -15,7 +15,7 @@ Native Linux companion apps are planned. Contributions are welcome if you want t ## Beginner quick path (VPS) -1. Install Node 24 (recommended; Node 22 LTS, currently `22.16+`, still works for compatibility) +1. Install Node 24 (recommended; Node 22 LTS, currently `22.14+`, still works for compatibility) 2. `npm i -g openclaw@latest` 3. `openclaw onboard --install-daemon` 4. From your laptop: `ssh -N -L 18789:127.0.0.1:18789 @` diff --git a/docs/platforms/mac/bundled-gateway.md b/docs/platforms/mac/bundled-gateway.md index e6e57cc1809..2414d0b448f 100644 --- a/docs/platforms/mac/bundled-gateway.md +++ b/docs/platforms/mac/bundled-gateway.md @@ -16,7 +16,7 @@ running (or attaches to an existing local Gateway if one is already running). ## Install the CLI (required for local mode) -Node 24 is the default runtime on the Mac. Node 22 LTS, currently `22.16+`, still works for compatibility. Then install `openclaw` globally: +Node 24 is the default runtime on the Mac. Node 22 LTS, currently `22.14+`, still works for compatibility. Then install `openclaw` globally: ```bash npm install -g openclaw@ diff --git a/docs/platforms/mac/dev-setup.md b/docs/platforms/mac/dev-setup.md index 0e7c058a934..2a13f259b5a 100644 --- a/docs/platforms/mac/dev-setup.md +++ b/docs/platforms/mac/dev-setup.md @@ -14,7 +14,7 @@ This guide covers the necessary steps to build and run the OpenClaw macOS applic Before building the app, ensure you have the following installed: 1. **Xcode 26.2+**: Required for Swift development. -2. **Node.js 24 & pnpm**: Recommended for the gateway, CLI, and packaging scripts. Node 22 LTS, currently `22.16+`, remains supported for compatibility. +2. **Node.js 24 & pnpm**: Recommended for the gateway, CLI, and packaging scripts. Node 22 LTS, currently `22.14+`, remains supported for compatibility. ## 1. Install Dependencies diff --git a/docs/platforms/mac/signing.md b/docs/platforms/mac/signing.md index 0feac8cd281..bb1fc30bbfc 100644 --- a/docs/platforms/mac/signing.md +++ b/docs/platforms/mac/signing.md @@ -14,7 +14,7 @@ This app is usually built from [`scripts/package-mac-app.sh`](https://github.com - calls [`scripts/codesign-mac-app.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/codesign-mac-app.sh) to sign the main binary and app bundle so macOS treats each rebuild as the same signed bundle and keeps TCC permissions (notifications, accessibility, screen recording, mic, speech). For stable permissions, use a real signing identity; ad-hoc is opt-in and fragile (see [macOS permissions](/platforms/mac/permissions)). - uses `CODESIGN_TIMESTAMP=auto` by default; it enables trusted timestamps for Developer ID signatures. Set `CODESIGN_TIMESTAMP=off` to skip timestamping (offline debug builds). - inject build metadata into Info.plist: `OpenClawBuildTimestamp` (UTC) and `OpenClawGitCommit` (short hash) so the About pane can show build, git, and debug/release channel. -- **Packaging defaults to Node 24**: the script runs TS builds and the Control UI build. Node 22 LTS, currently `22.16+`, remains supported for compatibility. +- **Packaging defaults to Node 24**: the script runs TS builds and the Control UI build. Node 22 LTS, currently `22.14+`, remains supported for compatibility. - reads `SIGN_IDENTITY` from the environment. Add `export SIGN_IDENTITY="Apple Development: Your Name (TEAMID)"` (or your Developer ID Application cert) to your shell rc to always sign with your cert. Ad-hoc signing requires explicit opt-in via `ALLOW_ADHOC_SIGNING=1` or `SIGN_IDENTITY="-"` (not recommended for permission testing). - runs a Team ID audit after signing and fails if any Mach-O inside the app bundle is signed by a different Team ID. Set `SKIP_TEAM_ID_CHECK=1` to bypass. diff --git a/docs/start/getting-started.md b/docs/start/getting-started.md index 22a5fe80914..342c63597ff 100644 --- a/docs/start/getting-started.md +++ b/docs/start/getting-started.md @@ -14,7 +14,7 @@ and a working chat session. ## What you need -- **Node.js** — Node 24 recommended (Node 22.16+ also supported) +- **Node.js** — Node 24 recommended (Node 22.14+ also supported) - **An API key** from a model provider (Anthropic, OpenAI, Google, etc.) — onboarding will prompt you diff --git a/docs/start/setup.md b/docs/start/setup.md index 1b36e46b412..98e3d875178 100644 --- a/docs/start/setup.md +++ b/docs/start/setup.md @@ -21,7 +21,7 @@ For onboarding details, see [Onboarding (CLI)](/start/wizard). ## Prereqs (from source) -- Node 24 recommended (Node 22 LTS, currently `22.16+`, still supported) +- Node 24 recommended (Node 22 LTS, currently `22.14+`, still supported) - `pnpm` - Docker (optional; only for containerized setup/e2e — see [Docker](/install/docker)) diff --git a/package.json b/package.json index 0bba86fc076..d3667f86774 100644 --- a/package.json +++ b/package.json @@ -837,7 +837,7 @@ "openshell": "0.1.0" }, "engines": { - "node": ">=22.16.0" + "node": ">=22.14.0" }, "packageManager": "pnpm@10.32.1", "pnpm": { diff --git a/scripts/install.sh b/scripts/install.sh index 736f16e5390..c008afe0b1b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -18,7 +18,7 @@ NC='\033[0m' # No Color DEFAULT_TAGLINE="All your chats, one OpenClaw." NODE_DEFAULT_MAJOR=24 NODE_MIN_MAJOR=22 -NODE_MIN_MINOR=16 +NODE_MIN_MINOR=14 NODE_MIN_VERSION="${NODE_MIN_MAJOR}.${NODE_MIN_MINOR}" ORIGINAL_PATH="${PATH:-}" diff --git a/src/cli/update-cli.test.ts b/src/cli/update-cli.test.ts index 52f1d544b0c..e3ab58f78ab 100644 --- a/src/cli/update-cli.test.ts +++ b/src/cli/update-cli.test.ts @@ -311,7 +311,7 @@ describe("update-cli", () => { vi.mocked(fetchNpmPackageTargetStatus).mockResolvedValue({ target: "latest", version: "9999.0.0", - nodeEngine: ">=22.16.0", + nodeEngine: ">=22.14.0", }); vi.mocked(resolveNpmChannelTag).mockResolvedValue({ tag: "latest", @@ -588,7 +588,7 @@ describe("update-cli", () => { vi.mocked(fetchNpmPackageTargetStatus).mockResolvedValue({ target: "latest", version: "2026.3.23-2", - nodeEngine: ">=22.16.0", + nodeEngine: ">=22.14.0", }); nodeVersionSatisfiesEngine.mockReturnValue(false); diff --git a/src/cli/update-cli/update-command.ts b/src/cli/update-cli/update-command.ts index c51b60ac006..ef43bd3922e 100644 --- a/src/cli/update-cli/update-command.ts +++ b/src/cli/update-cli/update-command.ts @@ -161,7 +161,7 @@ async function resolvePackageRuntimePreflightError(params: { return [ `Node ${process.versions.node ?? "unknown"} is too old for openclaw@${targetLabel}.`, `The requested package requires ${status.nodeEngine}.`, - "Upgrade Node to 22.16+ or Node 24, then rerun `openclaw update`.", + "Upgrade Node to 22.14+ or Node 24, then rerun `openclaw update`.", "Bare `npm i -g openclaw` can silently install an older compatible release.", "After upgrading Node, use `npm i -g openclaw@latest`.", ].join("\n"); diff --git a/src/commands/doctor-gateway-services.ts b/src/commands/doctor-gateway-services.ts index 25c25ea2bc2..e46c7bb6014 100644 --- a/src/commands/doctor-gateway-services.ts +++ b/src/commands/doctor-gateway-services.ts @@ -258,7 +258,7 @@ export async function maybeRepairGatewayServiceConfig( note(warning, "Gateway runtime"); } note( - "System Node 22 LTS (22.16+) or Node 24 not found. Install via Homebrew/apt/choco and rerun doctor to migrate off Bun/version managers.", + "System Node 22 LTS (22.14+) or Node 24 not found. Install via Homebrew/apt/choco and rerun doctor to migrate off Bun/version managers.", "Gateway runtime", ); } diff --git a/src/daemon/program-args.ts b/src/daemon/program-args.ts index 9e60f26f761..fd5c7b468ef 100644 --- a/src/daemon/program-args.ts +++ b/src/daemon/program-args.ts @@ -154,7 +154,7 @@ async function resolveBinaryPath(binary: string): Promise { throw new Error("Bun not found in PATH. Install bun: https://bun.sh"); } throw new Error( - "Node not found in PATH. Install Node 24 (recommended) or Node 22 LTS (22.16+).", + "Node not found in PATH. Install Node 24 (recommended) or Node 22 LTS (22.14+).", ); } } diff --git a/src/daemon/runtime-paths.test.ts b/src/daemon/runtime-paths.test.ts index 8130aa7d4d5..62d8cdb8e0c 100644 --- a/src/daemon/runtime-paths.test.ts +++ b/src/daemon/runtime-paths.test.ts @@ -56,7 +56,7 @@ describe("resolvePreferredNodePath", () => { const execFile = vi .fn() .mockResolvedValueOnce({ stdout: "18.0.0\n", stderr: "" }) // execPath too old - .mockResolvedValueOnce({ stdout: "22.16.0\n", stderr: "" }); // system node ok + .mockResolvedValueOnce({ stdout: "22.14.0\n", stderr: "" }); // system node ok const result = await resolvePreferredNodePath({ env: {}, @@ -73,7 +73,7 @@ describe("resolvePreferredNodePath", () => { it("ignores execPath when it is not node", async () => { mockNodePathPresent(darwinNode); - const execFile = vi.fn().mockResolvedValue({ stdout: "22.16.0\n", stderr: "" }); + const execFile = vi.fn().mockResolvedValue({ stdout: "22.14.0\n", stderr: "" }); const result = await resolvePreferredNodePath({ env: {}, @@ -93,8 +93,8 @@ describe("resolvePreferredNodePath", () => { it("uses system node when it meets the minimum version", async () => { mockNodePathPresent(darwinNode); - // Node 22.16.0+ is the minimum required version - const execFile = vi.fn().mockResolvedValue({ stdout: "22.16.0\n", stderr: "" }); + // Node 22.14.0+ is the minimum required version + const execFile = vi.fn().mockResolvedValue({ stdout: "22.14.0\n", stderr: "" }); const result = await resolvePreferredNodePath({ env: {}, @@ -111,8 +111,8 @@ describe("resolvePreferredNodePath", () => { it("skips system node when it is too old", async () => { mockNodePathPresent(darwinNode); - // Node 22.15.x is below minimum 22.16.0 - const execFile = vi.fn().mockResolvedValue({ stdout: "22.15.0\n", stderr: "" }); + // Node 22.13.x is below minimum 22.14.0 + const execFile = vi.fn().mockResolvedValue({ stdout: "22.13.0\n", stderr: "" }); const result = await resolvePreferredNodePath({ env: {}, @@ -168,7 +168,7 @@ describe("resolveStableNodePath", () => { it("resolves versioned node@22 formula to opt symlink", async () => { mockNodePathPresent("/opt/homebrew/opt/node@22/bin/node"); - const result = await resolveStableNodePath("/opt/homebrew/Cellar/node@22/22.16.0/bin/node"); + const result = await resolveStableNodePath("/opt/homebrew/Cellar/node@22/22.14.0/bin/node"); expect(result).toBe("/opt/homebrew/opt/node@22/bin/node"); }); @@ -218,8 +218,8 @@ describe("resolveSystemNodeInfo", () => { it("returns supported info when version is new enough", async () => { mockNodePathPresent(darwinNode); - // Node 22.16.0+ is the minimum required version - const execFile = vi.fn().mockResolvedValue({ stdout: "22.16.0\n", stderr: "" }); + // Node 22.14.0+ is the minimum required version + const execFile = vi.fn().mockResolvedValue({ stdout: "22.14.0\n", stderr: "" }); const result = await resolveSystemNodeInfo({ env: {}, @@ -229,7 +229,7 @@ describe("resolveSystemNodeInfo", () => { expect(result).toEqual({ path: darwinNode, - version: "22.16.0", + version: "22.14.0", supported: true, }); }); @@ -251,7 +251,7 @@ describe("resolveSystemNodeInfo", () => { "/Users/me/.fnm/node-22/bin/node", ); - expect(warning).toContain("below the required Node 22.16+"); + expect(warning).toContain("below the required Node 22.14+"); expect(warning).toContain(darwinNode); }); }); diff --git a/src/daemon/runtime-paths.ts b/src/daemon/runtime-paths.ts index 486ff5959ad..b5928037981 100644 --- a/src/daemon/runtime-paths.ts +++ b/src/daemon/runtime-paths.ts @@ -151,7 +151,7 @@ export function renderSystemNodeWarning( } const versionLabel = systemNode.version ?? "unknown"; const selectedLabel = selectedNodePath ? ` Using ${selectedNodePath} for the daemon.` : ""; - return `System Node ${versionLabel} at ${systemNode.path} is below the required Node 22.16+.${selectedLabel} Install Node 24 (recommended) or Node 22 LTS from nodejs.org or Homebrew.`; + return `System Node ${versionLabel} at ${systemNode.path} is below the required Node 22.14+.${selectedLabel} Install Node 24 (recommended) or Node 22 LTS from nodejs.org or Homebrew.`; } export { resolveStableNodePath }; diff --git a/src/daemon/service-audit.ts b/src/daemon/service-audit.ts index 8524e79da47..a78a7ddb1b2 100644 --- a/src/daemon/service-audit.ts +++ b/src/daemon/service-audit.ts @@ -362,7 +362,7 @@ async function auditGatewayRuntime( issues.push({ code: SERVICE_AUDIT_CODES.gatewayRuntimeNodeSystemMissing, message: - "System Node 22 LTS (22.16+) or Node 24 not found; install it before migrating away from version managers.", + "System Node 22 LTS (22.14+) or Node 24 not found; install it before migrating away from version managers.", level: "recommended", }); } diff --git a/src/infra/runtime-guard.test.ts b/src/infra/runtime-guard.test.ts index 99d4e938e81..5ab1984bddd 100644 --- a/src/infra/runtime-guard.test.ts +++ b/src/infra/runtime-guard.test.ts @@ -15,21 +15,21 @@ describe("runtime-guard", () => { it("parses semver with or without leading v", () => { expect(parseSemver("v22.1.3")).toEqual({ major: 22, minor: 1, patch: 3 }); expect(parseSemver("1.3.0")).toEqual({ major: 1, minor: 3, patch: 0 }); - expect(parseSemver("22.16.0-beta.1")).toEqual({ major: 22, minor: 16, patch: 0 }); + expect(parseSemver("22.14.0-beta.1")).toEqual({ major: 22, minor: 14, patch: 0 }); expect(parseSemver("invalid")).toBeNull(); }); it("compares versions correctly", () => { - expect(isAtLeast({ major: 22, minor: 16, patch: 0 }, { major: 22, minor: 16, patch: 0 })).toBe( + expect(isAtLeast({ major: 22, minor: 14, patch: 0 }, { major: 22, minor: 14, patch: 0 })).toBe( true, ); - expect(isAtLeast({ major: 22, minor: 17, patch: 0 }, { major: 22, minor: 16, patch: 0 })).toBe( + expect(isAtLeast({ major: 22, minor: 15, patch: 0 }, { major: 22, minor: 14, patch: 0 })).toBe( true, ); - expect(isAtLeast({ major: 22, minor: 15, patch: 0 }, { major: 22, minor: 16, patch: 0 })).toBe( + expect(isAtLeast({ major: 22, minor: 13, patch: 0 }, { major: 22, minor: 14, patch: 0 })).toBe( false, ); - expect(isAtLeast({ major: 21, minor: 9, patch: 0 }, { major: 22, minor: 16, patch: 0 })).toBe( + expect(isAtLeast({ major: 21, minor: 9, patch: 0 }, { major: 22, minor: 14, patch: 0 })).toBe( false, ); }); @@ -37,11 +37,11 @@ describe("runtime-guard", () => { it("validates runtime thresholds", () => { const nodeOk: RuntimeDetails = { kind: "node", - version: "22.16.0", + version: "22.14.0", execPath: "/usr/bin/node", pathEnv: "/usr/bin", }; - const nodeOld: RuntimeDetails = { ...nodeOk, version: "22.15.0" }; + const nodeOld: RuntimeDetails = { ...nodeOk, version: "22.13.0" }; const nodeTooOld: RuntimeDetails = { ...nodeOk, version: "21.9.0" }; const unknown: RuntimeDetails = { kind: "unknown", @@ -53,22 +53,22 @@ describe("runtime-guard", () => { expect(runtimeSatisfies(nodeOld)).toBe(false); expect(runtimeSatisfies(nodeTooOld)).toBe(false); expect(runtimeSatisfies(unknown)).toBe(false); - expect(isSupportedNodeVersion("22.16.0")).toBe(true); - expect(isSupportedNodeVersion("22.15.9")).toBe(false); + expect(isSupportedNodeVersion("22.14.0")).toBe(true); + expect(isSupportedNodeVersion("22.13.9")).toBe(false); expect(isSupportedNodeVersion(null)).toBe(false); }); it("parses simple minimum node engine ranges", () => { - expect(parseMinimumNodeEngine(">=22.16.0")).toEqual({ major: 22, minor: 16, patch: 0 }); + expect(parseMinimumNodeEngine(">=22.14.0")).toEqual({ major: 22, minor: 14, patch: 0 }); expect(parseMinimumNodeEngine(" >=v24.0.0 ")).toEqual({ major: 24, minor: 0, patch: 0 }); - expect(parseMinimumNodeEngine("^22.16.0")).toBeNull(); + expect(parseMinimumNodeEngine("^22.14.0")).toBeNull(); }); it("checks node versions against simple engine ranges", () => { - expect(nodeVersionSatisfiesEngine("22.16.0", ">=22.16.0")).toBe(true); - expect(nodeVersionSatisfiesEngine("22.15.9", ">=22.16.0")).toBe(false); - expect(nodeVersionSatisfiesEngine("24.0.0", ">=22.16.0")).toBe(true); - expect(nodeVersionSatisfiesEngine("22.16.0", "^22.16.0")).toBeNull(); + expect(nodeVersionSatisfiesEngine("22.14.0", ">=22.14.0")).toBe(true); + expect(nodeVersionSatisfiesEngine("22.13.9", ">=22.14.0")).toBe(false); + expect(nodeVersionSatisfiesEngine("24.0.0", ">=22.14.0")).toBe(true); + expect(nodeVersionSatisfiesEngine("22.14.0", "^22.14.0")).toBeNull(); }); it("throws via exit when runtime is too old", () => { @@ -99,7 +99,7 @@ describe("runtime-guard", () => { const details: RuntimeDetails = { ...detectRuntime(), kind: "node", - version: "22.16.0", + version: "22.14.0", execPath: "/usr/bin/node", }; expect(() => assertSupportedRuntime(runtime, details)).not.toThrow(); diff --git a/src/infra/runtime-guard.ts b/src/infra/runtime-guard.ts index 8397cac95ed..52ca376372e 100644 --- a/src/infra/runtime-guard.ts +++ b/src/infra/runtime-guard.ts @@ -9,7 +9,7 @@ type Semver = { patch: number; }; -const MIN_NODE: Semver = { major: 22, minor: 16, patch: 0 }; +const MIN_NODE: Semver = { major: 22, minor: 14, patch: 0 }; const MINIMUM_ENGINE_RE = /^\s*>=\s*v?(\d+\.\d+\.\d+)\s*$/i; export type RuntimeDetails = { @@ -111,7 +111,7 @@ export function assertSupportedRuntime( runtime.error( [ - "openclaw requires Node >=22.16.0.", + "openclaw requires Node >=22.14.0.", `Detected: ${runtimeLabel} (exec: ${execLabel}).`, `PATH searched: ${details.pathEnv}`, "Install Node: https://nodejs.org/en/download", diff --git a/src/infra/update-check.test.ts b/src/infra/update-check.test.ts index db36c4d1dbb..b71e935c67e 100644 --- a/src/infra/update-check.test.ts +++ b/src/infra/update-check.test.ts @@ -50,7 +50,7 @@ describe("resolveNpmChannelTag", () => { status: version != null ? 200 : 404, json: async () => ({ version, - engines: version != null ? { node: ">=22.16.0" } : undefined, + engines: version != null ? { node: ">=22.14.0" } : undefined, }), } as Response; }), @@ -105,7 +105,7 @@ describe("resolveNpmChannelTag", () => { ).resolves.toEqual({ target: "latest", version: "1.0.4", - nodeEngine: ">=22.16.0", + nodeEngine: ">=22.14.0", }); await expect(fetchNpmTagVersion({ tag: "latest", timeoutMs: 1000 })).resolves.toEqual({ tag: "latest", diff --git a/src/memory/embeddings.ts b/src/memory/embeddings.ts index 3e38ef7f210..23d63ad766a 100644 --- a/src/memory/embeddings.ts +++ b/src/memory/embeddings.ts @@ -310,7 +310,7 @@ function formatLocalSetupError(err: unknown): string { : undefined, missing && detail ? `Detail: ${detail}` : null, "To enable local embeddings:", - "1) Use Node 24 (recommended for installs/updates; Node 22 LTS, currently 22.16+, remains supported)", + "1) Use Node 24 (recommended for installs/updates; Node 22 LTS, currently 22.14+, remains supported)", missing ? "2) Reinstall OpenClaw (this should install node-llama-cpp): npm i -g openclaw@latest" : null,