build: upgrade to 22.19 for deps

This commit is contained in:
imccyu
2026-07-07 17:39:04 +08:00
parent 6edce91735
commit 92b5eccc96
19 changed files with 59 additions and 56 deletions
@@ -14,7 +14,7 @@ Every AGENTS.md promise gets a command that exits non-zero, wired into git hooks
- ESLint strict-type-checked + @stylistic (the house style, enforced); vendored code excluded.
- Per-file 100% coverage on `packages/*/src` (v8); unreachable defensive guards carry `/* v8 ignore */ ` with stated reasons instead of deletion.
- knip (dead code/deps), publint (package correctness), workspace constraints (workspace rules: private, cordis peer+dev, uniform version, ESM), and a NodeNext consumer typecheck for built package declarations.
- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 22.18/24/26 plus a demo smoke test driving the echo-agent end to end.
- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 22.19/24/26 plus a demo smoke test driving the echo-agent end to end.
## Consequences
@@ -1,34 +0,0 @@
# RFC: Lower the Node engines floor to 22.18
Status: implemented
## Problem
The root `engines.node` was `>=24`, which excluded the entire Node 22 LTS line for no runtime reason. The harness has exactly two Node features whose availability gates the floor, and both are satisfied well below Node 24 — so the floor was higher than the code actually requires. Pinning it honestly widens the supported install base (Node 22 LTS is in service until 2027) without weakening any guarantee, provided CI proves the claim on the floor version rather than merely asserting it in a manifest.
## Decision
Set `engines.node` to `^22.18.0 || >=24.0.0` (Node 22.18+ on the LTS line, or 24+) and test it on the keyless CI matrix `['22.18', 24, 26]`. The real-API e2e workflow stays on Node 24 because it exercises API integration rather than the runtime floor. Two Node features gate the range, each with its own LTS-line and Current-line unflag point:
- **`node:sqlite`** — `packages/session-persistence/session-persistence-sqlite` does a top-level `import { DatabaseSync } from 'node:sqlite'`. The module dropped its `--experimental-sqlite` flag requirement at **22.13** (LTS) and **23.4** (Current); before those, importing it throws at load.
- **Native TypeScript type-stripping** — the `packages/ui/stdio-agent/tests/built-bin.e2e.ts` smoke boots the published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` plugins (`mock-llm.ts`, `echo-tool.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`.
On the 22.x line both features clear at **22.18** (the later of 22.13/22.18), so `^22.18.0` is the LTS floor. The range is **disjoint** rather than an open `>=22.18` because the Node **23.023.5** window still has at least one feature flagged (sqlite until 23.4, stripping until 23.6): `>=22.18` would advertise support there, where the sqlite backend throws `ERR_UNKNOWN_BUILTIN_MODULE` at load. Node 23 is non-LTS and already end-of-life, so rather than carve out `>=23.6` the range skips the whole line and resumes at `>=24.0.0` — the same shape several of the repo's own dependencies already declare (`^22.18.0 || >=24.11.0`).
`@types/node` is pinned to the 22.x line (`^22.20.0`) to match the floor: reaching for a Node 23+/24+/25+ API then fails `tsc` on every machine and in the typecheck gate, rather than compiling clean and surviving to a runtime failure only the 22.18 matrix leg could catch. The whole tree typechecks clean against the Node 22 type surface today, so the pin costs nothing.
## Consequences
- The supported base widens to the Node 22 LTS line, and the `['22.18', 24, 26]` matrix proves it on every push and PR rather than trusting the manifest.
- The built-bin smoke needs no version-conditional flag: at 22.18 type-stripping is already the default, so the test stays the plain `node lib/bin.js` path it documents.
- A future change reaching for a Node 23+ API fails `tsc` immediately (the `@types/node` pin); one reaching for an API added in 22.19/22.20 — inside the 22.x type surface but above the floor — is caught instead by the 22.18 matrix leg. Either way the floor must move in the same change.
- The `vendor/hmr` and `vendor/loader` comments about Node 24 module-cache internals are unaffected — they describe dev-time HMR loader behavior, not the shipped runtime contract, and are pinned vendored source.
## Alternatives considered
- **Floor `>=22.13` (the `node:sqlite` boundary) plus `--experimental-strip-types` in the built-bin smoke on 22.1322.17.** Rejected: it adds a version-conditional test flag for one narrow range and dresses up an experimental-flag dependency as first-class support. 22.18 clears both boundaries with zero test special-casing, and the five-patch gap below it buys nothing real.
- **Keep `>=24`.** Rejected: it excludes Node 22 LTS with no runtime justification once the two boundaries above are known.
- **Open-ended `>=22.18`.** Rejected: it advertises support for Node 23.023.5, where `node:sqlite` (until 23.4) or type-stripping (until 23.6) is still flagged, so the sqlite backend throws at load. The disjoint `^22.18.0 || >=24.0.0` matches the real runtime boundary.
- **Include Node 23.6+ (`^22.18.0 || >=23.6.0`).** Rejected: 23.6+ does run both features unflagged, but Node 23 is end-of-life — advertising a dead release line adds a range term (and, to back it, a CI leg) for a runtime no deployment should use. 24 is the meaningful resumption point, and the 22.18 and 24 legs already bracket the same unflagged code paths.
- **Matrix `[22, 24, 26]` (latest 22.x) instead of pinning `22.18`.** Rejected: "latest 22.x" drifts upward over time and would silently stop exercising the declared floor. Pinning the floor version is what makes the matrix a proof of the claim rather than a proof of some newer 22.x.
- **Keep `@types/node` ahead of the floor (`^25`).** Rejected: types ahead of the runtime floor let a Node 24/25-only API compile clean and fail only at runtime on 22.18 — exactly the "green types, broken product" gap. Pinning `@types/node` to the 22.x line turns that into a compile error everywhere, and the tree already typechecks clean against the Node 22 surface, so the pin is free.
@@ -0,0 +1,37 @@
# RFC: Raise the Node LTS engine floor to 22.19
Status: implemented
## Problem
The Node 22 branch of the root `engines.node` range is a contract for the installed workspace, not only for the runtime APIs the harness source calls directly. It must be no lower than package `engines.node` declarations for dependencies the workspace installs on that branch; otherwise `pnpm install --engine-strict` fails at an advertised LTS version, and non-strict installs run outside a dependency's supported runtime.
## Decision
Set `engines.node` to `^22.19.0 || >=24.0.0` and test the keyless CI compatibility matrix on `['22.19', 24, 26]`. The real-API e2e workflow stays on Node 24 because it exercises API integration rather than the runtime floor.
Two Node features gate the source runtime:
- **`node:sqlite`** — `packages/session-persistence/session-persistence-sqlite` does a top-level `import { DatabaseSync } from 'node:sqlite'`. The module dropped its `--experimental-sqlite` flag requirement at **22.13** (LTS) and **23.4** (Current); before those, importing it throws at load.
- **Native TypeScript type-stripping** — the `packages/ui/stdio-agent/tests/built-bin.e2e.ts` smoke boots the published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` plugins (`mock-llm.ts`, `echo-tool.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`.
Those source features clear on the 22.x line at **22.18**, but the installed Pi adapter dependency raises the advertised LTS floor. `@deepseek-ai/dsh-llm-pi-ai` depends on `@earendil-works/pi-ai@0.79.3`, whose package declares `engines.node >=22.19.0`, so the LTS floor is **22.19**. The 24.x branch remains `>=24.0.0`. The disjoint range excludes Node 23 entirely: Node 23.023.5 still has at least one flagged source feature, and the 23 line is non-LTS/EOL, so advertising `>=23.6` would add a dead release line and a CI leg no deployment should use.
`@types/node` remains pinned to the 22.x line (`^22.20.0`) to match the LTS support line: reaching for a Node 23+/24+/25+ API fails `tsc` on every machine and in the typecheck gate, rather than compiling clean and surviving to a runtime failure only a floor matrix leg could catch. The whole tree typechecks clean against the Node 22 type surface today, so the pin costs nothing.
## Consequences
- The advertised LTS branch no longer undercuts the Pi adapter dependency floor.
- CI proves the Node 22 LTS floor directly with Node 22.19, keeps the Node 24 branch on `node: 24`, and keeps Node 26 for the next even line.
- The built-bin smoke needs no version-conditional flag: at 22.19 type-stripping is already the default, so the test stays the plain `node lib/bin.js` path it documents.
- A future dependency or source API that raises the runtime floor must move `engines.node`, the compatibility matrix, and this RFC in the same change.
## Alternatives considered
- **Keep `^22.18.0 || >=24.0.0`.** Rejected: it advertises an LTS version lower than the Pi adapter dependency floor. `@earendil-works/pi-ai@0.79.3` requires `>=22.19.0`.
- **Downgrade or pin `@earendil-works/pi-ai` to preserve the 22.18 advertised range.** Rejected: the current Pi adapter dependency is part of the intended workspace, and 22.19 is still inside the Node 22 LTS line.
- **Floor `>=22.13` (the `node:sqlite` boundary) plus `--experimental-strip-types` in the built-bin smoke on 22.1322.17.** Rejected: it adds a version-conditional test flag for one narrow range and dresses up an experimental-flag dependency as first-class support. The Pi adapter dependency already requires a higher LTS floor.
- **Open-ended `>=22.19`.** Rejected: it advertises support for Node 23.023.5, where `node:sqlite` (until 23.4) or type-stripping (until 23.6) is still flagged.
- **Include Node 23.6+ (`^22.19.0 || >=23.6.0`).** Rejected: 23.6+ does run both source features unflagged, but Node 23 is end-of-life; advertising a dead release line adds a range term and a CI leg for a runtime no deployment should use.
- **Matrix `[22, 24, 26]` instead of pinning `22.19`.** Rejected: floating major-version entries drift upward over time and silently stop exercising the declared LTS floor.
- **Keep `@types/node` ahead of the floor (`^25`).** Rejected: types ahead of the runtime floor let a Node 24/25-only API compile clean and fail only at runtime on 22.x. Pinning `@types/node` to the 22.x line turns that into a compile error everywhere.