From 7f09418f7cc168813e934aca4934493c8f28d2ca Mon Sep 17 00:00:00 2001 From: murashit Date: Fri, 10 Jul 2026 12:48:36 +0900 Subject: [PATCH] Align Node 26 tooling and enforce recorded compatibility checks --- .github/workflows/check.yml | 8 +++++++- .github/workflows/release.yml | 2 +- .node-version | 1 + docs/development.md | 4 ++++ package-lock.json | 3 +++ package.json | 3 +++ scripts/api-baseline.mjs | 20 +++++++++++++------- tests/scripts/development-scripts.test.ts | 8 ++++++++ 8 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 .node-version diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index acd3ef40..6112ed63 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -23,11 +23,17 @@ jobs: - name: Setup Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: - node-version: 24 + node-version: 26 cache: npm - name: Install dependencies run: npm ci --ignore-scripts + - name: Check recorded API baselines + run: npm run api:baseline -- --recorded-only + + - name: Check release metadata + run: npm run release:check + - name: Check run: npm run check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de2f191c..faac3492 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: - node-version: 24 + node-version: 26 package-manager-cache: false - name: Install dependencies diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..6f4247a6 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +26 diff --git a/docs/development.md b/docs/development.md index 4c452500..35cea940 100644 --- a/docs/development.md +++ b/docs/development.md @@ -10,6 +10,8 @@ npm run fix npm run check ``` +Use Node.js 26, matching `.node-version`, CI, and the installed Node type definitions. + Use this as the normal edit loop: make the change, run `npm run fix`, then run `npm run check`. Treat `npm run fix` as trusted mechanical cleanup for formatting, import ordering, and Knip safe fixes; review the resulting diff at normal change-boundary checkpoints rather than after each tool adjustment. Use focused scripts such as `npm run typecheck`, `npm run test`, or `npm run build` only when diagnosing a specific failure or when a full check would obscure the signal while iterating. Do not treat focused scripts as a substitute for the final `npm run check`. CI and release preflight run the same `npm run check` command as local development. @@ -83,3 +85,5 @@ npm run api:baseline Obsidian runtime compatibility is declared through `manifest.json` and `versions.json`. The `obsidian` npm package provides compile-time TypeScript API definitions; it is not runtime validation for an Obsidian app-version matrix. Because the project does not run app-version smoke tests, keep the API type package in the same minor as `manifest.minAppVersion` and use the latest patch in that minor for local type checking. `npm run api:baseline` exits non-zero when the local environment or recorded baselines drift. Raise `manifest.minAppVersion` only when intentionally adopting a newer Obsidian app/API minor. Codex app-server compatibility is managed by Codex CLI minor version. README records the tested Codex CLI patch version, `src/app-server/connection/compatibility.json` records the machine-readable app-server capability baseline used by the panel client profile, and the baseline check verifies that the local `codex --version` is in the same minor before app-server binding or compatibility work. + +Pull-request CI runs `npm run api:baseline -- --recorded-only`, which validates checked-in compatibility declarations without requiring a Codex CLI installation. Local compatibility work should still run `npm run api:baseline` so the installed CLI is checked too. diff --git a/package-lock.json b/package-lock.json index 419203dc..100a3f66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "codex-panel", "version": "4.5.1", "license": "Apache-2.0", + "engines": { + "node": ">=26" + }, "dependencies": { "@preact/signals": "^2.9.2", "@tanstack/query-core": "^5.101.1", diff --git a/package.json b/package.json index 03bc92d8..9c6b2bfd 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "url": "https://github.com/murashit/codex-panel/issues" }, "homepage": "https://github.com/murashit/codex-panel#readme", + "engines": { + "node": ">=26" + }, "scripts": { "api:baseline": "node scripts/api-baseline.mjs", "build": "node esbuild.config.mjs", diff --git a/scripts/api-baseline.mjs b/scripts/api-baseline.mjs index 9303fa16..5f9ee338 100644 --- a/scripts/api-baseline.mjs +++ b/scripts/api-baseline.mjs @@ -3,19 +3,20 @@ import { readFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; -const validArgs = new Set(["--json"]); +const validArgs = new Set(["--json", "--recorded-only"]); if (isMain()) { const args = new Set(process.argv.slice(2)); const asJson = args.has("--json"); + const recordedOnly = args.has("--recorded-only"); for (const arg of args) { if (!validArgs.has(arg)) { - console.error("Usage: node scripts/api-baseline.mjs [--json]"); + console.error("Usage: node scripts/api-baseline.mjs [--json] [--recorded-only]"); process.exit(1); } } - const report = await createApiBaselineReport(); + const report = await createApiBaselineReport({ skipLocalCodex: recordedOnly }); if (asJson) { console.log(JSON.stringify(report, null, 2)); } else { @@ -59,7 +60,11 @@ export async function createApiBaselineReport(options = {}) { const readmeBaselines = readCompatibilityBaselines(inputs.readme); const codexReadmeVersion = readmeBaselines.codexTestedCliVersion; - const codexLocalVersion = options.readCodexVersion ? await options.readCodexVersion() : readCodexVersion(); + const codexLocalVersion = options.skipLocalCodex + ? null + : options.readCodexVersion + ? await options.readCodexVersion() + : readCodexVersion(); const codexReadmeSemver = parseSemver(codexReadmeVersion); const codexLocalSemver = parseSemver(codexLocalVersion); @@ -85,7 +90,7 @@ export async function createApiBaselineReport(options = {}) { if (!codexReadmeSemver) { fail("README.md Compatibility table must define `codex.testedCliVersion` as X.Y.Z."); } - if (!codexLocalSemver) { + if (!options.skipLocalCodex && !codexLocalSemver) { fail("local codex --version could not be read."); } if (codexReadmeSemver && codexLocalSemver && minorKey(codexReadmeSemver) !== minorKey(codexLocalSemver)) { @@ -143,6 +148,7 @@ export async function createApiBaselineReport(options = {}) { readmeTestedMinor: minorKey(codexReadmeSemver), localCliVersion: codexLocalVersion, localCliMinor: minorKey(codexLocalSemver), + localCliCheckSkipped: options.skipLocalCodex === true, localCliMatchesTestedMinor: codexReadmeSemver && codexLocalSemver ? minorKey(codexReadmeSemver) === minorKey(codexLocalSemver) : null, appServerGenerationExperimentalDeclared, appServerGenerationExperimental, @@ -275,8 +281,8 @@ function printReport(report) { console.log(` policy: ${report.codex.policy}`); console.log(` compatibility table CLI: ${displayValue(report.codex.readmeTestedCliVersion)}`); console.log(` compatibility table minor: ${displayValue(report.codex.readmeTestedMinor)}`); - console.log(` local codex CLI: ${displayValue(report.codex.localCliVersion)}`); - console.log(` local codex minor: ${displayValue(report.codex.localCliMinor)}`); + console.log(` local codex CLI: ${report.codex.localCliCheckSkipped ? "(skipped)" : displayValue(report.codex.localCliVersion)}`); + console.log(` local codex minor: ${report.codex.localCliCheckSkipped ? "(skipped)" : displayValue(report.codex.localCliMinor)}`); console.log(` declared generate-ts --experimental: ${report.codex.appServerGenerationExperimentalDeclared ? "yes" : "no"}`); console.log(` generate-ts --experimental: ${report.codex.appServerGenerationExperimental ? "yes" : "no"}`); console.log(` initialize experimentalApi: ${report.codex.initializeExperimentalApi ? "yes" : "no"}`); diff --git a/tests/scripts/development-scripts.test.ts b/tests/scripts/development-scripts.test.ts index f808a4e7..2cf10cd4 100644 --- a/tests/scripts/development-scripts.test.ts +++ b/tests/scripts/development-scripts.test.ts @@ -131,6 +131,14 @@ describe("development scripts", () => { expect(report.codex.initializeExperimentalApi).toBe(true); expect(report.codex.initializeRequestAttestationDisabled).toBe(true); expect(report.failures).toEqual([]); + + const recordedOnlyReport = await createApiBaselineReport({ + cwd, + readCodexVersion: () => null, + skipLocalCodex: true, + }); + expect(recordedOnlyReport.codex.localCliCheckSkipped).toBe(true); + expect(recordedOnlyReport.failures).toEqual([]); }); it("reports representative CSS usage policy failures", async () => {