Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v22
37 changes: 28 additions & 9 deletions scripts/check-node-runtime.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const minimumNodeVersion = [22, 13, 0];
const minimumNodeVersionLabel = "22.13.0";
const supportedNodeMajor = 22;
const maximumNodeVersionLabel = "23";
const nodeVersionRequirementLabel = `>=${minimumNodeVersionLabel} and <${maximumNodeVersionLabel}`;

function parseNodeVersion(version) {
return version
Expand All @@ -17,6 +20,14 @@ function isAtLeastMinimum(version) {
return true;
}

function isSupportedMajor(version) {
return (parseNodeVersion(version)[0] ?? 0) === supportedNodeMajor;
}

function formatNodeVersion(version) {
return version.startsWith("v") ? version : `v${version}`;
}

function fail(message) {
console.error(`[pilotdeck] ${message}`);
process.exit(1);
Expand All @@ -32,17 +43,25 @@ process.emitWarning = (warning, typeOrOptions, ...args) => {
emitWarning(warning, typeOrOptions, ...args);
};

const nodeVersion = process.versions.node;
if (!isAtLeastMinimum(nodeVersion)) {
const testMode = process.env.PILOTDECK_RUNTIME_CHECK_TEST_MODE === "1";
const nodeVersion =
testMode && process.env.PILOTDECK_TEST_NODE_VERSION
? process.env.PILOTDECK_TEST_NODE_VERSION
: process.versions.node;
const skipSqliteCheck = testMode && process.env.PILOTDECK_TEST_SKIP_SQLITE === "1";

if (!isAtLeastMinimum(nodeVersion) || !isSupportedMajor(nodeVersion)) {
fail(
`Node.js >=${minimumNodeVersionLabel} is required because PilotDeck uses node:sqlite. Current: v${nodeVersion}.`,
`Node.js ${nodeVersionRequirementLabel} is required because PilotDeck uses node:sqlite and native packages are built for Node.js ${supportedNodeMajor}. Current: ${formatNodeVersion(nodeVersion)}. Switch to Node.js ${supportedNodeMajor} and reinstall dependencies.`,
);
}

try {
await import("node:sqlite");
} catch {
fail(
`Current Node.js (v${nodeVersion}) does not provide node:sqlite. Switch to Node.js ${minimumNodeVersionLabel}+ and reinstall dependencies.`,
);
if (!skipSqliteCheck) {
try {
await import("node:sqlite");
} catch {
fail(
`Current Node.js (${formatNodeVersion(nodeVersion)}) does not provide node:sqlite. Switch to Node.js ${minimumNodeVersionLabel}+ and reinstall dependencies.`,
);
}
}
2 changes: 1 addition & 1 deletion src/context/memory/edgeclaw-memory-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"type": "module",
"engines": {
"node": ">=22.13.0"
"node": ">=22.13.0 <23"
},
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
Expand Down
35 changes: 35 additions & 0 deletions tests/cli/check-node-runtime.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { join } from "node:path";
import test from "node:test";

const scriptPath = join(process.cwd(), "scripts", "check-node-runtime.mjs");

function runRuntimeCheck(nodeVersion: string) {
return spawnSync(process.execPath, [scriptPath], {
cwd: process.cwd(),
env: {
...process.env,
PILOTDECK_RUNTIME_CHECK_TEST_MODE: "1",
PILOTDECK_TEST_NODE_VERSION: nodeVersion,
PILOTDECK_TEST_SKIP_SQLITE: "1",
},
encoding: "utf8",
});
}

test("runtime check accepts the supported Node 22 range", () => {
assert.equal(runRuntimeCheck("22.13.0").status, 0);
assert.equal(runRuntimeCheck("22.22.0").status, 0);
});

test("runtime check rejects Node versions outside the supported range", () => {
const tooOld = runRuntimeCheck("22.12.0");
assert.equal(tooOld.status, 1);
assert.match(tooOld.stderr, />=22\.13\.0 and <23/);

const tooNew = runRuntimeCheck("25.5.0");
assert.equal(tooNew.status, 1);
assert.match(tooNew.stderr, />=22\.13\.0 and <23/);
assert.match(tooNew.stderr, /native packages are built for Node\.js 22/);
});
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "module",
"main": "server/index.js",
"engines": {
"node": ">=22.13.0"
"node": ">=22.13.0 <23"
},
"scripts": {
"check:runtime": "node ../scripts/check-node-runtime.mjs",
Expand Down
1 change: 1 addition & 0 deletions ui/server/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env node
import '../../scripts/check-node-runtime.mjs';
// Load environment variables before other imports execute
import { assertRequiredPilotDeckEnv } from './load-env.js';
// Install global fetch proxy (PILOTDECK_PROXY / HTTPS_PROXY) before any network calls
Expand Down