From 98a7b1334823ee0be3e3fa5cab7a2e349e438dab Mon Sep 17 00:00:00 2001 From: Tyler <109685178+tlongwell-block@users.noreply.github.com> Date: Mon, 27 Jul 2026 18:18:02 -0400 Subject: [PATCH] fix(node): bump Buzz-supplied Node runtimes past OpenClaw's >=24.15.0 floor (#3218) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem User report: ``` Buzz Node mismatch: Buzz supplies Node 24.14.0; OpenClaw requires >=24.15.0. All 10 ACP workers immediately crash. ``` Buzz supplies Node to agent processes from two places, and both were below OpenClaw's floor: | Supply path | Was | Now | |---|---|---| | hermit dev env (`bin/.node-*.pkg`) — the 24.14.0 in the report | 24.14.0 | **24.15.0** (newest hermit publishes; satisfies `>=24.15.0`) | | Desktop managed runtime (`managed_node.rs` / `managed_node_paths.rs`) | v24.11.0 | **v24.18.0** (current latest v24) | The managed runtime sits **first** on the worker PATH (`managed_agents/runtime/path.rs`), so a user-installed newer Node can't mask a stale managed one — the pin itself has to move. ## Verification - SHA-256 digests for all six platform artifacts taken from `https://nodejs.org/dist/v24.18.0/SHASUMS256.txt`; darwin-arm64 independently re-verified by downloading the tarball (hash match), extracting, and running `bin/node --version` → `v24.18.0`. - All artifacts within `MANAGED_NODE_MAX_BYTES` (largest linux-x64 at 57 MB < 90 MB cap); tar.gz layout keeps the `node-vX-platform/bin/node` shape `verify_node_tree` expects. - `cargo test --lib` in `desktop/src-tauri`: **1801 passed, 0 failed** at this commit; `cargo fmt --check` + `cargo clippy --lib -D warnings` clean. - Existing readiness check (`node --version == MANAGED_NODE_VERSION`) makes upgrade automatic: installed v24.11.0 trees fail readiness and the installer stages v24.18.0 atomically (rename with `.old` rollback — existing logic, unchanged). Note: CI `node-version: 24.14.1` pins in `release.yml`/`windows-canary.yml` are build-env only (already `>=` nothing OpenClaw touches) and left alone to keep this minimal. Signed-off-by: Tyler Longwell Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Tyler Longwell --- bin/{.node-24.14.0.pkg => .node-24.15.0.pkg} | 0 bin/corepack | 2 +- bin/node | 2 +- bin/npm | 2 +- bin/npx | 2 +- .../commands/agent_discovery/managed_node.rs | 34 +++++++++---------- .../src/managed_agents/managed_node_paths.rs | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) rename bin/{.node-24.14.0.pkg => .node-24.15.0.pkg} (100%) diff --git a/bin/.node-24.14.0.pkg b/bin/.node-24.15.0.pkg similarity index 100% rename from bin/.node-24.14.0.pkg rename to bin/.node-24.15.0.pkg diff --git a/bin/corepack b/bin/corepack index 07e8834efb..4df063726c 120000 --- a/bin/corepack +++ b/bin/corepack @@ -1 +1 @@ -.node-24.14.0.pkg \ No newline at end of file +.node-24.15.0.pkg \ No newline at end of file diff --git a/bin/node b/bin/node index 07e8834efb..4df063726c 120000 --- a/bin/node +++ b/bin/node @@ -1 +1 @@ -.node-24.14.0.pkg \ No newline at end of file +.node-24.15.0.pkg \ No newline at end of file diff --git a/bin/npm b/bin/npm index 07e8834efb..4df063726c 120000 --- a/bin/npm +++ b/bin/npm @@ -1 +1 @@ -.node-24.14.0.pkg \ No newline at end of file +.node-24.15.0.pkg \ No newline at end of file diff --git a/bin/npx b/bin/npx index 07e8834efb..4df063726c 120000 --- a/bin/npx +++ b/bin/npx @@ -1 +1 @@ -.node-24.14.0.pkg \ No newline at end of file +.node-24.15.0.pkg \ No newline at end of file diff --git a/desktop/src-tauri/src/commands/agent_discovery/managed_node.rs b/desktop/src-tauri/src/commands/agent_discovery/managed_node.rs index 2d7e13d1d7..72108f0291 100644 --- a/desktop/src-tauri/src/commands/agent_discovery/managed_node.rs +++ b/desktop/src-tauri/src/commands/agent_discovery/managed_node.rs @@ -5,7 +5,7 @@ use std::{io::Read, io::Write}; use crate::managed_agents::{is_npm_global_install, InstallStepResult}; -const MANAGED_NODE_VERSION: &str = "v24.11.0"; +const MANAGED_NODE_VERSION: &str = "v24.18.0"; const MANAGED_NODE_MAX_BYTES: u64 = 90 * 1024 * 1024; #[derive(Debug, Clone, Copy)] @@ -18,43 +18,43 @@ struct ManagedNodeArtifact { #[cfg(all(target_os = "macos", target_arch = "aarch64"))] const MANAGED_NODE_ARTIFACT: Option = Some(ManagedNodeArtifact { platform: "darwin-arm64", - filename: "node-v24.11.0-darwin-arm64.tar.gz", - sha256: "0be2ab2816a4fa02d1acff014a434f29f56d8d956f5af6a98b70ced6c5f4d201", + filename: "node-v24.18.0-darwin-arm64.tar.gz", + sha256: "e1a97e14c99c803e96c7339403282ea05a499c32f8d83defe9ef5ec66f979ed1", }); #[cfg(all(target_os = "macos", target_arch = "x86_64"))] const MANAGED_NODE_ARTIFACT: Option = Some(ManagedNodeArtifact { platform: "darwin-x64", - filename: "node-v24.11.0-darwin-x64.tar.gz", - sha256: "3884671e87f46f773832d98a0a6cabcc5ec4f637084f0f3515b69e66ea27f2f1", + filename: "node-v24.18.0-darwin-x64.tar.gz", + sha256: "dfd0dbd3e721503434df7b7205e719f61b3a3a31b2bcf9729b8b91fea240f080", }); #[cfg(all(target_os = "linux", target_arch = "x86_64"))] const MANAGED_NODE_ARTIFACT: Option = Some(ManagedNodeArtifact { platform: "linux-x64", - filename: "node-v24.11.0-linux-x64.tar.gz", - sha256: "b3c071cdf47aab867c3b2aa287257df12ec5d7c962bf922b32fd33226c4295fd", + filename: "node-v24.18.0-linux-x64.tar.gz", + sha256: "783130984963db7ba9cbd01089eaf2c2efb055c7c1693c943174b967b3050cb8", }); #[cfg(all(target_os = "linux", target_arch = "aarch64"))] const MANAGED_NODE_ARTIFACT: Option = Some(ManagedNodeArtifact { platform: "linux-arm64", - filename: "node-v24.11.0-linux-arm64.tar.gz", - sha256: "4786d00c4d259d3ff0b2328307f764ef3ced65f2d6e9502d433e68d66238509d", + filename: "node-v24.18.0-linux-arm64.tar.gz", + sha256: "6b4484c2190274175df9aa8f28e2d758a819cb1c1fe6ab481e2f95b463ab8508", }); #[cfg(all(target_os = "windows", target_arch = "x86_64"))] const MANAGED_NODE_ARTIFACT: Option = Some(ManagedNodeArtifact { platform: "win-x64", - filename: "node-v24.11.0-win-x64.zip", - sha256: "1054540bce22b54ec7e50ebc078ec5d090700a77657607a58f6a64df21f49fdd", + filename: "node-v24.18.0-win-x64.zip", + sha256: "0ae68406b42d7725661da979b1403ec9926da205c6770827f33aac9d8f26e821", }); #[cfg(all(target_os = "windows", target_arch = "aarch64"))] const MANAGED_NODE_ARTIFACT: Option = Some(ManagedNodeArtifact { platform: "win-arm64", - filename: "node-v24.11.0-win-arm64.zip", - sha256: "12d3b1aa9696b7411e115a4fa2aef57f95560b5ee16bb62cd69843e535ec72be", + filename: "node-v24.18.0-win-arm64.zip", + sha256: "f274669adb93b1fd0fbf8f21fd078609e9dcc84333d4f2718d2dde3f9a161a01", }); #[cfg(not(any( @@ -615,9 +615,9 @@ mod tests { #[test] fn test_validate_zip_accepts_normal_entries() { let tmp = make_zip_with_entries(&[ - "node-v24.11.0-win-x64/node.exe", - "node-v24.11.0-win-x64/npm.cmd", - "node-v24.11.0-win-x64/npm", + "node-v24.18.0-win-x64/node.exe", + "node-v24.18.0-win-x64/npm.cmd", + "node-v24.18.0-win-x64/npm", ]); let file = std::fs::File::open(tmp.path()).unwrap(); let archive = zip::ZipArchive::new(file).unwrap(); @@ -677,7 +677,7 @@ mod tests { #[test] fn test_validate_zip_rejects_backslash_traversal() { // Path traversal using Windows separator — must reject on every host. - let tmp = make_zip_with_entries(&["node-v24.11.0-win-x64\\..\\..\\evil"]); + let tmp = make_zip_with_entries(&["node-v24.18.0-win-x64\\..\\..\\evil"]); let file = std::fs::File::open(tmp.path()).unwrap(); let archive = zip::ZipArchive::new(file).unwrap(); let err = validate_managed_node_zip_entries(&archive).unwrap_err(); diff --git a/desktop/src-tauri/src/managed_agents/managed_node_paths.rs b/desktop/src-tauri/src/managed_agents/managed_node_paths.rs index e4b4c36967..ffcdea8181 100644 --- a/desktop/src-tauri/src/managed_agents/managed_node_paths.rs +++ b/desktop/src-tauri/src/managed_agents/managed_node_paths.rs @@ -4,7 +4,7 @@ pub(crate) fn buzz_managed_npm_prefix() -> Option { dirs::data_dir().map(|dir| dir.join("Buzz").join("node-tools")) } -const BUZZ_MANAGED_NODE_VERSION: &str = "v24.11.0"; +const BUZZ_MANAGED_NODE_VERSION: &str = "v24.18.0"; pub(crate) fn buzz_managed_node_root() -> Option { dirs::data_dir().map(|dir| dir.join("Buzz").join("runtimes").join("node"))