diff --git a/AGENTS.md b/AGENTS.md index 0f9e4a8..4801816 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -65,6 +65,7 @@ test/ quickActions.test.ts Quick action command building, path containment, patch merge (95 tests) verifyMcp.test.ts MCP server verify and JSON-RPC response parsing (15 tests) downloadIntegration.test.ts HTTP download, redirect, streaming SHA-256 (12 tests) + packageEngines.test.ts engines.node major meets installed vsce and ovsx floors (1 test) suite/ index.ts VS Code extension integration tests runExtensionTests.ts Test runner using @vscode/test-electron diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 97a84f1..d52878f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ npm run compile npm test ``` -**Requirements:** Node.js 20+ and VS Code 1.90+. +**Requirements:** Node.js 22+ and VS Code 1.90+. Packaging uses `@vscode/vsce` 4, which does not run on Node 20. `.nvmrc` pins 22. ## Development workflow diff --git a/package-lock.json b/package-lock.json index f76e6ec..937d931 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "vscode-extension-tester": "^8.27.0" }, "engines": { - "node": ">=20", + "node": ">=22", "vscode": "^1.90.0" } }, @@ -1710,9 +1710,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", - "integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.3.tgz", + "integrity": "sha512-dsqMQQoeTLqu9wynDD00q573mNzso3IdQOAfHRJqLCcmCFPoGo9A1bDpUcv/9tnKpErQWv9uKeGfl37EIS02Yg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index e2bb795..91cf65c 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "engines": { "vscode": "^1.90.0", - "node": ">=20" + "node": ">=22" }, "icon": "images/logo-512.png", "galleryBanner": { diff --git a/test/unit/packageEngines.test.ts b/test/unit/packageEngines.test.ts new file mode 100644 index 0000000..2e5b897 --- /dev/null +++ b/test/unit/packageEngines.test.ts @@ -0,0 +1,38 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import path from "node:path"; +import test from "node:test"; + +const repoRoot = path.resolve(__dirname, "../../.."); + +function enginesNode(packageJsonPath: string): string { + const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { + engines?: { node?: string }; + }; + const node = pkg.engines?.node; + if (typeof node !== "string") { + throw new Error(`missing engines.node in ${packageJsonPath}`); + } + return node; +} + +function nodeMajor(enginesNodeSpec: string): number { + const match = /(\d+)/.exec(enginesNodeSpec); + assert.ok(match, `cannot parse engines.node major from ${enginesNodeSpec}`); + return Number(match[1]); +} + +test("engines.node major meets installed vsce and ovsx floors", () => { + const extensionNode = enginesNode(path.join(repoRoot, "package.json")); + const vsceNode = enginesNode(path.join(repoRoot, "node_modules/@vscode/vsce/package.json")); + const ovsxNode = enginesNode(path.join(repoRoot, "node_modules/ovsx/package.json")); + const extensionMajor = nodeMajor(extensionNode); + assert.ok( + extensionMajor >= nodeMajor(vsceNode), + `engines.node ${extensionNode} is below @vscode/vsce ${vsceNode}` + ); + assert.ok( + extensionMajor >= nodeMajor(ovsxNode), + `engines.node ${extensionNode} is below ovsx ${ovsxNode}` + ); +});