From 60055baaffbf8cec9f10dc647eabd177966b7fe7 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 12 Nov 2026 17:23:07 -0500 Subject: [PATCH 1/4] build: run Vite+'s type-aware lint on tsrslint vp lint runs the bin/tsgolint of its own oxlint-tsgolint, so a pnpm override makes that package tools/tsrslint-shim, which runs @maschwenk/tsrslint's binary. A whole-repo vp lint takes 9-10 s and 2 GB at most, against 16 s and 3.6 GB on Vite+'s tsgolint. --- ...alls-and-scripts-and-tsrs-for-typecheck.md | 2 +- docs/adr/0055-vite-plus-and-pnpm.md | 10 +- docs/development/dependencies.md | 1 + package.json | 1 + pnpm-lock.yaml | 110 +++++++----------- pnpm-workspace.yaml | 2 + tools/tsrslint-shim/bin/tsgolint.js | 13 +++ 7 files changed, 68 insertions(+), 71 deletions(-) create mode 100755 tools/tsrslint-shim/bin/tsgolint.js diff --git a/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md b/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md index 0b83b91d..d033ca59 100644 --- a/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md +++ b/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md @@ -1,5 +1,5 @@ --- -status: accepted, partly superseded by ADR-0055 (pnpm installs and runs the scripts, Vite+ runs the tasks instead of Turborepo, and type-aware lint runs on Vite+'s bundled tsgolint instead of tsrslint; tsrs still typechecks) +status: accepted, partly superseded by ADR-0055 (pnpm installs and runs the scripts, Vite+ runs the tasks instead of Turborepo, and tsrslint becomes Vite+'s type-aware lint backend through a pnpm override instead of `scripts/link-tsrslint.sh`; tsrs still typechecks) --- # Bun installs and runs scripts, tsrs typechecks, and Vitest stays on Node diff --git a/docs/adr/0055-vite-plus-and-pnpm.md b/docs/adr/0055-vite-plus-and-pnpm.md index 4606fe12..297931c2 100644 --- a/docs/adr/0055-vite-plus-and-pnpm.md +++ b/docs/adr/0055-vite-plus-and-pnpm.md @@ -4,24 +4,24 @@ status: accepted # pnpm installs, and Vite+ checks, lints, formats and runs the tasks -The repo installs with pnpm again, and its toolchain is Vite+ (`vite-plus`): `vp check` formats, lints and runs the type-aware lint once at the root, `vp run` runs every package's tasks and caches them, and `vp staged` with `.vite-hooks/` replaces lint-staged and Husky. This replaces [ADR-0028](0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md)'s Bun, Turborepo and tsrslint; each package's typecheck stays `effect-tsgo tsrs`, for the Effect diagnostics that `vp check`'s type-check does not run. +The repo installs with pnpm again, and its toolchain is Vite+ (`vite-plus`): `vp check` formats, lints and runs the type-aware lint (on tsrslint) once at the root, `vp run` runs every package's tasks and caches them, and `vp staged` with `.vite-hooks/` replaces lint-staged and Husky. This replaces [ADR-0028](0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md)'s Bun and Turborepo, and the link that made tsrslint oxlint's backend; each package's typecheck stays `effect-tsgo tsrs`, for the Effect diagnostics that `vp check`'s type-check does not run. - **pnpm** (`packageManager`, `mise.toml`): `pnpm-workspace.yaml` holds the workspace, the patched dependencies, the packages allowed to run install scripts (`allowBuilds`: the pnpm list from before ADR-0028, with `core-js-pure` still blocked and `just-bash`'s optional compressors now blocked too, as ADR-0028 found they serve only its Node command line; `typescript`, which Bun had to trust for the effect-tsgo patch, needs no entry under pnpm) and the exemptions from pnpm's default minimum release age of a day. Workspace dependencies stay plain `"*"` for npm's production install of the root (`pi install git:…`), so `linkWorkspacePackages` links them. `dedupePeers` tells peer variants apart by their peers' versions alone: without it the server had two `@cloudflare/computer`s, and `infra` two `alchemy`s (one per `ws`, which an override now holds at one version), and their typechecks failed. - **One config** (`vite.config.ts` at the root): the lint rules, the anti-slop plugins and every package's own rules (as `lint.overrides` by path; Vite+ reads no nested lint or format config), the format settings and the staged-file rules. `vp check` runs at the root, not per package: it lints the whole repo in one process. - **Tasks** (`packages/config/src/tasks.ts`, passed to `run.tasks` by each package's `vite.config.ts`): `typecheck` and `test`. Vite Task records the files each task reads and replays a task none of whose inputs changed, so a change to a package's source reruns its dependents' tasks without Turborepo's `transit` node or `apps/web/turbo.json`'s hand-listed inputs. A cached task runs in a clean environment, so `test` names the variables that change what a test checks (`CI`, the live tests' and benchmarks' switches, `UPDATE_SNAPSHOT`) and passes the rest through untracked. `test` is `vitest run`, not `vp test`: Vite Task runs a `vp test` inside the `vp` that started it, with that copy's Vitest, and a `vp` that is not the project's (mise's `npm:vite-plus`) gives the workerd projects a second Vitest, which `@cloudflare/vitest-plugin`'s worker cannot reach. -- **Versions**: `vite-plus` 1.4.0, the last release that bundles Vitest 5.0.5; 1.5 and 1.6 bundle 5.1, under which the workerd tests fail (docs/development/dependencies.md). Overrides make every `vite` Vite+'s core and every `vitest` 5.0.5. Vite+ 1.4.0 bundles oxlint 1.89, oxfmt 0.74 and tsgolint 7.0.2004, older than the 1.91, 0.76 and tsrslint they replace; oxfmt 0.74 wraps three signatures differently, reformatted with the switch. +- **Versions**: `vite-plus` 1.4.0, the last release that bundles Vitest 5.0.5; 1.5 and 1.6 bundle 5.1, under which the workerd tests fail (docs/development/dependencies.md). Overrides make every `vite` Vite+'s core and every `vitest` 5.0.5. Vite+ 1.4.0 bundles oxlint 1.89 and oxfmt 0.74, older than the 1.91 and 0.76 they replace (tsrslint 0.1.6, built against oxlint 1.91, runs under 1.89); oxfmt 0.74 wraps three signatures differently, reformatted with the switch. - **CI** sets up with `voidzero-dev/setup-vp`, which installs the Vite+ of the root `package.json` (so its `vp` runs the project's copy), Node and pnpm, and caches pnpm's store. Each check part restores and saves its Vite Task cache (`node_modules/.vite/task-cache`) under a rolling key and clears it past 1 GiB, since Vite Task never evicts. Measured on an 8-core Apple Silicon laptop (2026-11-12), warm caches: -- **Lint**: `vp lint` over the whole repo, type-aware with type-check, 16 s wall, 48 s of CPU, 3.6 GB peak memory (ADR-0028's tsrslint, one package after another: 18–24 s, 19 s, 0.47 GB). +- **Lint**: `vp lint` over the whole repo, type-aware with type-check, on tsrslint: 9–10 s wall, 13–14 s of CPU, 1.5–2.1 GB peak memory (two runs); on Vite+'s own tsgolint 7.0.2004: 16 s, 48 s, 3.6 GB (ADR-0028's tsrslint, one package after another: 18–24 s, 19 s, 0.47 GB). - **Typecheck**: `vp run -r typecheck`, 7–11 s uncached; 0.9 s when every task replays. - **Tests**: `vp run -r test`, 4 min uncached; 1 min when only the tasks that modify their own inputs (`@cloudpid/mcp`'s import-rule test plants files) and `@cloudpid/sandbox-image`'s, which is uncached, run again. - **Install** with a warm store and no `node_modules`, `prepare` included: 5.1 s wall, 1.1 s of user CPU (ADR-0028: Bun 0.85 s, pnpm 2.4 s, before `prepare`'s `vp config`). ## Consequences -- The type-aware lint is tsgolint again, not tsrslint: Vite+ sets `OXLINT_TSGOLINT_PATH` to its own `oxlint-tsgolint` and ignores `node_modules/.bin/tsgolint`. It takes more memory than tsrslint in one process, but runs once rather than per package. `scripts/link-tsrslint.sh` and `@maschwenk/tsrslint` are gone. +- The type-aware lint stays on tsrslint, by another route: Vite+ sets `OXLINT_TSGOLINT_PATH` to the `bin/tsgolint` of its own `oxlint-tsgolint` and ignores `node_modules/.bin/tsgolint`, so `scripts/link-tsrslint.sh` is gone, and a pnpm override makes `oxlint-tsgolint` the repo's `tools/tsrslint-shim`, whose `bin/tsgolint.js` runs `@maschwenk/tsrslint`'s binary. It rests on where Vite+ looks for its backend, which a Vite+ upgrade can change: `vp lint` then fails (`Error running tsgolint`) rather than lint without it. The shim has no `package.json`, or `effect-tsgo patch` finds it as Vite+'s `oxlint-tsgolint` and fails `prepare` looking for tsgolint's platform binary. tsrslint ships for macOS arm64 and Linux x64 and arm64 (glibc) only, as before. This lasts until tsrs ships its own linter (oxc-project/tsrs#378). - Run the project's own `vp`: `pnpm exec vp`, the root scripts, or the standalone global CLI from vite.plus, which hands a command to the project's copy. mise's `npm:vite-plus` is a second copy of the whole toolchain. - Turborepo's CI pruning is gone; the Vite Task cache is experimental in CI (Vite+'s docs say so) and is bounded by size instead. - On macOS, Vite Task runs a cached task's system coreutils as uutils' to record what it reads. The tests that probe the host for GNU coreutils check `--version` for `(GNU coreutils)`, and `@cloudpid/sandbox-image`'s `test` is uncached, since its memory-guard tests fail under uutils. Linux is unaffected. @@ -34,4 +34,4 @@ Measured on an 8-core Apple Silicon laptop (2026-11-12), warm caches: - **Keeping Bun with Vite+.** Vite+ supports Bun, but the owner chose pnpm; Bun's install speed was most of ADR-0028's case for it, and pnpm's global virtual store is available where it matters, on the Container. - **Keeping Turborepo with Vite+'s lint and format.** Turborepo's `transit` node and hand-listed inputs were what Vite Task's file tracking does by itself, and one task runner is one less tool. - **Vite+ 1.6 with Vitest 5.1.** The workerd tests fail under Vitest 5.1 (dependencies.md); 1.4.0 holds Vitest at 5.0.5 until that is fixed. -- **tsrslint behind `vp lint`** (an override of `oxlint-tsgolint` with a package that runs tsrslint). Possible, but a shim around a shim; one lint over the repo already costs about what the per-package tsrslint runs did. +- **Vite+'s own tsgolint**, with nothing to keep in step with Vite+. One lint over the repo on it took 16 s and 3.6 GB against tsrslint's 9–10 s and 2 GB at most, and needs no shim, but ADR-0028 chose tsrslint for that cost, and the shim is one file. diff --git a/docs/development/dependencies.md b/docs/development/dependencies.md index af59e86c..a856c824 100644 --- a/docs/development/dependencies.md +++ b/docs/development/dependencies.md @@ -6,6 +6,7 @@ Some dependencies carry a patch (`patches/`) or an exact pin. When upgrading one | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `@cloudflare/vitest-plugin` | `patches/@cloudflare__vitest-plugin@1.5.1.patch` | Keeps the module snapshot it sends a reused worker under workerd's 32 MiB WebSocket message limit, past which the worker dies with `1009 Message is too large` ([cloudflare/workers-sdk#16349](https://github.com/cloudflare/workers-sdk/issues/16349)). Drop it once #16349 is fixed. | | `vite-plus`, `vitest` | exact `1.4.0` (`vite-plus`) in the root `package.json` and `apps/web`; exact `5.0.5` (`vitest`) at the root and in the packages whose test plugins peer it; the `vite` and `vitest` `overrides` in `pnpm-workspace.yaml` (`@voidzero-dev/vite-plus-core@1.4.0`, `5.0.5`) | Vite+ bundles its own Vitest (1.4.0 bundles 5.0.5; 1.5 and later bundle 5.1), so `vite-plus`, the `vite` override and `vitest` move together. Vitest is held below 5.1: under 5.1.0 the workerd pool delays a timer a Durable Object request sets (`setImmediate`, `setTimeout(0)`) until a later request to an object awaits a real timer, so an Effect fiber forked in a request (Effect's scheduler starts it with `setImmediate`) starts late: a Session reports itself idle only at its next request, and `apps/server/src/session/admission.workerd.test.ts` ("Stop waits for it"), `host.workerd.test.ts` and `import.workerd.test.ts` fail. Bisected on its own (5.0.5 with the same workerd, `@cloudflare/vitest-plugin`, Effect and pi-durable delivers them at once); deployed workerd is unaffected. Before lifting it, check that a `setImmediate` set in a `runInDurableObject` callback runs before the next no-op `runInDurableObject` returns, and rerun those three files. | +| `@maschwenk/tsrslint`, `oxlint-tsgolint` | exact `0.1.6` in the root `package.json`; `oxlint-tsgolint` overridden to `link:./tools/tsrslint-shim` in `pnpm-workspace.yaml` | Vite+'s type-aware lint backend is tsrslint, through the shim (`tools/tsrslint-shim/bin/tsgolint.js`; [ADR-0055](../adr/0055-vite-plus-and-pnpm.md) → Consequences). When upgrading `vite-plus` or tsrslint, check that `pnpm exec vp lint` on a file with a type error and a floating promise still reports both (`typescript(TS2322)`, `no-floating-promises`): a Vite+ that looks for its backend elsewhere fails with `Error running tsgolint`, and a tsrslint built against a newer oxlint than Vite+ bundles may not speak its protocol. Drop both once tsrs ships its own linter (oxc-project/tsrs#378). | | `ws` | exact `8.22.1`, an `overrides` entry in `pnpm-workspace.yaml` | One `ws` for every package: `@earendil-works/chord` pins `8.21.0` and the rest resolve 8.22, and each `ws` is a peer variant of `alchemy`, whose two copies then fail `infra`'s typecheck (a union of two `AlchemyContext`s). Drop it once chord allows 8.22, or move it with the newest `ws` chord allows. | | `@cloudflare/computer` | `patches/@cloudflare__computer@0.9.0.patch` | Adds `Workspace.remount()`, which `updateSkills` runs: computer checks a mount's version only at a Workspace's first index ([`../architecture/workspace.md`](../architecture/workspace.md) → _The Skill set_). Drop it once computer can index a mount again; rerun `apps/server/src/workspace/skills.workerd.test.ts` either way. Also update the `bash` routing lists if the Worker Shell changed ([`workers.md`](workers.md) → _The Workspace DO_). | | `@cloudflare/computer`, computerd | read for the file-change signal | The file-change signal ([`../architecture/container.md`](../architecture/container.md) → _File-change signals_) reads computer's change-log tables (`apps/server/src/workspace/change-log.ts`) and span names (`notify.ts`), and needs computerd's `setxattr` on its mount to stay a no-op the kernel reports. When upgrading either, rerun `src/workspace/notify.workerd.test.ts` and `notify.test.ts`, and recheck by hand as that section's _Limits_ says. | diff --git a/package.json b/package.json index c2c09d2f..a9a4ad9c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@commitlint/cli": "21.2.4", "@commitlint/config-conventional": "21.2.4", "@effect/tsgo": "0.64.1", + "@maschwenk/tsrslint": "0.1.6", "skills": "^1.7.6", "typescript": "^7.0.2", "vite-plus": "1.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfe7b315..a3a9ac5c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -167,6 +167,7 @@ overrides: vite@*: npm:@voidzero-dev/vite-plus-core@1.4.0 vitest@*: 5.0.5 ws: 8.22.1 + oxlint-tsgolint: link:./tools/tsrslint-shim patchedDependencies: '@alchemy.run/cloudflare@2.0.0-beta.85': 42560d88385a37a4a65b7d0f3d0f4746d76477154fea680e52ae463e3f9f326c @@ -190,6 +191,9 @@ importers: '@effect/tsgo': specifier: 0.64.1 version: 0.64.1 + '@maschwenk/tsrslint': + specifier: 0.1.6 + version: 0.1.6 skills: specifier: ^1.7.6 version: 1.7.6 @@ -1995,6 +1999,28 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@maschwenk/tsrslint-darwin-arm64@0.1.6': + resolution: {integrity: sha512-4cd/YRhspvIUxfr6xx2oWv3+WTeKLxfOe4tW49zPdo80X6rp4mxkWQg3C9vkm+1ugeAakoQgtOHNP9SnH5raLA==} + cpu: [arm64] + os: [darwin] + + '@maschwenk/tsrslint-linux-arm64@0.1.6': + resolution: {integrity: sha512-f2G8zGWoXHTHGegUdrqiX5EjyYDGFtk/vq0JeEAHlcjl3LtDD2cIl8kkuCypA69CohAqxm49yf2gtVyMSF/EMg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@maschwenk/tsrslint-linux-x64@0.1.6': + resolution: {integrity: sha512-e1XeesEMB+m3LocBzjzUxZ+F0CpSZodC/Cp8EynPGA6Buz4l0rDx1bPHHZAgcq2bcKN2Mgk+ep3KY75P8UuRFA==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@maschwenk/tsrslint@0.1.6': + resolution: {integrity: sha512-s/dMOF/F5gINLYMpcZpLAFVH5hWcSc4N/I8uaOkD8nMUWSFVSN/R+Jx7/rMbj5hX+ej4rthgfVhx0ZZb7/pNSg==} + engines: {node: '>=18'} + hasBin: true + '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} @@ -2254,36 +2280,6 @@ packages: cpu: [x64] os: [win32] - '@oxlint-tsgolint/darwin-arm64@7.0.2004': - resolution: {integrity: sha512-uJk3ttju7Lz+Nv8WG4CsLyewoL1qf/Ny8S8OksJ7Bm/F14Tc9gMfW6arM1PCc57IzH/X/I79YsCWTgxX1FKibQ==} - cpu: [arm64] - os: [darwin] - - '@oxlint-tsgolint/darwin-x64@7.0.2004': - resolution: {integrity: sha512-0BFfHTzDxNDFPcu0UZAXT6CyCJHAXM0dZveyDb4KEHa2qF/DSnOKOrmvK/wFuFol9kvijbGM9JfuOsor+zWXRw==} - cpu: [x64] - os: [darwin] - - '@oxlint-tsgolint/linux-arm64@7.0.2004': - resolution: {integrity: sha512-TAehQc+qdRXyDN3nl/r/3/oPrBVrbtrDeGMkFyG6mf+XphpoJ2lAMVFLclyvrVZCw02RbKROjyw8h72XwQQHcw==} - cpu: [arm64] - os: [linux] - - '@oxlint-tsgolint/linux-x64@7.0.2004': - resolution: {integrity: sha512-LPunZvm6ZbWPfHMAyfZf9ci3HHvNEzLejO8zdqO3GoVGoSEHqqufHUD7+OgeatVSaJP7uXDJ2HaNOHIoH7go4Q==} - cpu: [x64] - os: [linux] - - '@oxlint-tsgolint/win32-arm64@7.0.2004': - resolution: {integrity: sha512-FVWplzDImWhiuawnIZVETaQecv4GWom6Jv4Fx2xj7hhXXDZ5okEgiw1gTCImHTIQsi2ycC5oSxVwrn69bMh7iw==} - cpu: [arm64] - os: [win32] - - '@oxlint-tsgolint/win32-x64@7.0.2004': - resolution: {integrity: sha512-7PsxuUx11Ry9DYTWcljTzRbmZY9B6O9fFFfZV+aodQEMy6pfRT3fhoQRv9PtGN/89z1pPz3nFKrsFm6WqNtX7w==} - cpu: [x64] - os: [win32] - '@oxlint/binding-android-arm-eabi@1.89.0': resolution: {integrity: sha512-Pflpba5F3gRAQ12sWglRxvWTHEdAusNDvmi4Y5N1T5SY1AGkM7AixOnET8qkrnLJ/F32qAlNokO6eCknT8tmnw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5574,10 +5570,6 @@ packages: vite-plus: optional: true - oxlint-tsgolint@7.0.2004: - resolution: {integrity: sha512-vQ9WDF3fiZJvRdSDosNOflerOCOpwol6vWzVDxW76RcU19cjTh7engvkHLvmv+tzedR8fAiJUVUGr6IVZdkzXQ==} - hasBin: true - oxlint@1.89.0: resolution: {integrity: sha512-a25hkfo61okGPvJz432fRIPoxlKtNnOVy9w4rzrmGgNm4iVTPwpSQlmdqNWnp6p9QyyPVfAZRgnf5XvSBZFk/A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7773,6 +7765,21 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 + '@maschwenk/tsrslint-darwin-arm64@0.1.6': + optional: true + + '@maschwenk/tsrslint-linux-arm64@0.1.6': + optional: true + + '@maschwenk/tsrslint-linux-x64@0.1.6': + optional: true + + '@maschwenk/tsrslint@0.1.6': + optionalDependencies: + '@maschwenk/tsrslint-darwin-arm64': 0.1.6 + '@maschwenk/tsrslint-linux-arm64': 0.1.6 + '@maschwenk/tsrslint-linux-x64': 0.1.6 + '@mixmark-io/domino@2.2.0': {} '@modelcontextprotocol/client@2.4.0': @@ -7996,24 +8003,6 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.74.0': optional: true - '@oxlint-tsgolint/darwin-arm64@7.0.2004': - optional: true - - '@oxlint-tsgolint/darwin-x64@7.0.2004': - optional: true - - '@oxlint-tsgolint/linux-arm64@7.0.2004': - optional: true - - '@oxlint-tsgolint/linux-x64@7.0.2004': - optional: true - - '@oxlint-tsgolint/win32-arm64@7.0.2004': - optional: true - - '@oxlint-tsgolint/win32-x64@7.0.2004': - optional: true - '@oxlint/binding-android-arm-eabi@1.89.0': optional: true @@ -11166,16 +11155,7 @@ snapshots: '@oxfmt/binding-win32-x64-msvc': 0.74.0 vite-plus: 1.4.0(@opentelemetry/api@1.10.0)(@types/node@26.6.6)(@vitest/ui@5.0.5)(esbuild@0.28.2)(happy-dom@21.0.4)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.1) - oxlint-tsgolint@7.0.2004: - optionalDependencies: - '@oxlint-tsgolint/darwin-arm64': 7.0.2004 - '@oxlint-tsgolint/darwin-x64': 7.0.2004 - '@oxlint-tsgolint/linux-arm64': 7.0.2004 - '@oxlint-tsgolint/linux-x64': 7.0.2004 - '@oxlint-tsgolint/win32-arm64': 7.0.2004 - '@oxlint-tsgolint/win32-x64': 7.0.2004 - - oxlint@1.89.0(oxlint-tsgolint@7.0.2004)(vite-plus@1.4.0): + oxlint@1.89.0(oxlint-tsgolint@tools+tsrslint-shim)(vite-plus@1.4.0): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.89.0 '@oxlint/binding-android-arm64': 1.89.0 @@ -11196,7 +11176,7 @@ snapshots: '@oxlint/binding-win32-arm64-msvc': 1.89.0 '@oxlint/binding-win32-ia32-msvc': 1.89.0 '@oxlint/binding-win32-x64-msvc': 1.89.0 - oxlint-tsgolint: 7.0.2004 + oxlint-tsgolint: link:tools/tsrslint-shim vite-plus: 1.4.0(@opentelemetry/api@1.10.0)(@types/node@26.6.6)(@vitest/ui@5.0.5)(esbuild@0.28.2)(happy-dom@21.0.4)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.1) p-retry@4.6.2: @@ -12146,8 +12126,8 @@ snapshots: '@vitest/spy': 5.0.5 '@vitest/utils': 5.0.5 oxfmt: 0.74.0(vite-plus@1.4.0) - oxlint: 1.89.0(oxlint-tsgolint@7.0.2004)(vite-plus@1.4.0) - oxlint-tsgolint: 7.0.2004 + oxlint: 1.89.0(oxlint-tsgolint@tools+tsrslint-shim)(vite-plus@1.4.0) + oxlint-tsgolint: link:tools/tsrslint-shim vite: '@voidzero-dev/vite-plus-core@1.4.0(@types/node@26.6.6)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.1)' vitest: 5.0.5(@opentelemetry/api@1.10.0)(@types/node@26.6.6)(@vitest/browser-preview@5.0.5)(@vitest/ui@5.0.5)(@voidzero-dev/vite-plus-core@1.4.0)(happy-dom@21.0.4) optionalDependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f7cbb547..8c12bfa7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -37,6 +37,8 @@ overrides: # One `ws` for every package: chord pins 8.21.0 and the rest resolve 8.22, and each `ws` is a peer variant of alchemy, # whose two copies then fail the typecheck of `infra` (`AlchemyContext | AlchemyContext`). ws: 8.22.1 + # Vite+'s type-aware lint backend runs tsrslint instead of tsgolint (tools/tsrslint-shim/bin/tsgolint.js). + oxlint-tsgolint: link:./tools/tsrslint-shim # Vite+'s core stands in for `vite`, and packages that peer an older `vite` or `vitest` accept it (`vp migrate`'s rule). peerDependencyRules: diff --git a/tools/tsrslint-shim/bin/tsgolint.js b/tools/tsrslint-shim/bin/tsgolint.js new file mode 100755 index 00000000..82d031a5 --- /dev/null +++ b/tools/tsrslint-shim/bin/tsgolint.js @@ -0,0 +1,13 @@ +#!/usr/bin/env node +// Vite+'s type-aware lint backend, run as tsrslint (tsgolint's rules ported to Rust on tsrs) instead of tsgolint +// (docs/adr/0055-vite-plus-and-pnpm.md → Consequences). `vp lint` and `vp check` run the `bin/tsgolint` of their own +// `oxlint-tsgolint`, whatever `OXLINT_TSGOLINT_PATH` or `node_modules/.bin` say, so `pnpm-workspace.yaml`'s overrides +// make this directory that package. It has no `package.json` on purpose: `effect-tsgo patch` (the root `prepare`) looks +// for Vite+'s `oxlint-tsgolint` by its `package.json`, and would then fail the install looking for tsgolint's platform +// binary, which this replaces. +import { createRequire } from "node:module"; + +const { binaryPath } = createRequire(import.meta.url)("@maschwenk/tsrslint"); +const exe = binaryPath(); + +process.execve(exe, [exe, ...process.argv.slice(2)]); From 69594ec311c1afe5e3c520093a4cdb35877bafcc Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 12 Nov 2026 17:26:00 -0500 Subject: [PATCH 2/4] build: run tsrslint as a child on a Node without process.execve --- docs/adr/0055-vite-plus-and-pnpm.md | 4 ++-- tools/tsrslint-shim/bin/tsgolint.js | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/docs/adr/0055-vite-plus-and-pnpm.md b/docs/adr/0055-vite-plus-and-pnpm.md index 297931c2..2544391a 100644 --- a/docs/adr/0055-vite-plus-and-pnpm.md +++ b/docs/adr/0055-vite-plus-and-pnpm.md @@ -21,7 +21,7 @@ Measured on an 8-core Apple Silicon laptop (2026-11-12), warm caches: ## Consequences -- The type-aware lint stays on tsrslint, by another route: Vite+ sets `OXLINT_TSGOLINT_PATH` to the `bin/tsgolint` of its own `oxlint-tsgolint` and ignores `node_modules/.bin/tsgolint`, so `scripts/link-tsrslint.sh` is gone, and a pnpm override makes `oxlint-tsgolint` the repo's `tools/tsrslint-shim`, whose `bin/tsgolint.js` runs `@maschwenk/tsrslint`'s binary. It rests on where Vite+ looks for its backend, which a Vite+ upgrade can change: `vp lint` then fails (`Error running tsgolint`) rather than lint without it. The shim has no `package.json`, or `effect-tsgo patch` finds it as Vite+'s `oxlint-tsgolint` and fails `prepare` looking for tsgolint's platform binary. tsrslint ships for macOS arm64 and Linux x64 and arm64 (glibc) only, as before. This lasts until tsrs ships its own linter (oxc-project/tsrs#378). +- The type-aware lint stays on tsrslint, by another route: Vite+ sets `OXLINT_TSGOLINT_PATH` to the `bin/tsgolint` of its own `oxlint-tsgolint` and ignores `node_modules/.bin/tsgolint`, so `scripts/link-tsrslint.sh` is gone, and a pnpm override makes `oxlint-tsgolint` the repo's `tools/tsrslint-shim`, whose `bin/tsgolint.js` runs `@maschwenk/tsrslint`'s binary. It rests on where Vite+ looks for its backend (docs/development/dependencies.md says what to check on an upgrade). The shim has no `package.json`, or `effect-tsgo patch` finds it as Vite+'s `oxlint-tsgolint` and fails `prepare` looking for tsgolint's platform binary. tsrslint ships for macOS arm64 and Linux x64 and arm64 (glibc) only, as before. This lasts until tsrs ships its own linter (oxc-project/tsrs#378). - Run the project's own `vp`: `pnpm exec vp`, the root scripts, or the standalone global CLI from vite.plus, which hands a command to the project's copy. mise's `npm:vite-plus` is a second copy of the whole toolchain. - Turborepo's CI pruning is gone; the Vite Task cache is experimental in CI (Vite+'s docs say so) and is bounded by size instead. - On macOS, Vite Task runs a cached task's system coreutils as uutils' to record what it reads. The tests that probe the host for GNU coreutils check `--version` for `(GNU coreutils)`, and `@cloudpid/sandbox-image`'s `test` is uncached, since its memory-guard tests fail under uutils. Linux is unaffected. @@ -34,4 +34,4 @@ Measured on an 8-core Apple Silicon laptop (2026-11-12), warm caches: - **Keeping Bun with Vite+.** Vite+ supports Bun, but the owner chose pnpm; Bun's install speed was most of ADR-0028's case for it, and pnpm's global virtual store is available where it matters, on the Container. - **Keeping Turborepo with Vite+'s lint and format.** Turborepo's `transit` node and hand-listed inputs were what Vite Task's file tracking does by itself, and one task runner is one less tool. - **Vite+ 1.6 with Vitest 5.1.** The workerd tests fail under Vitest 5.1 (dependencies.md); 1.4.0 holds Vitest at 5.0.5 until that is fixed. -- **Vite+'s own tsgolint**, with nothing to keep in step with Vite+. One lint over the repo on it took 16 s and 3.6 GB against tsrslint's 9–10 s and 2 GB at most, and needs no shim, but ADR-0028 chose tsrslint for that cost, and the shim is one file. +- **Vite+'s own tsgolint**, with nothing to keep in step with Vite+. One lint over the repo on it took 16 s and 3.6 GB against tsrslint's 9–10 s and 2.1 GB at most, and needs no shim, but ADR-0028 chose tsrslint for that cost, and the shim is one file. diff --git a/tools/tsrslint-shim/bin/tsgolint.js b/tools/tsrslint-shim/bin/tsgolint.js index 82d031a5..37299e10 100755 --- a/tools/tsrslint-shim/bin/tsgolint.js +++ b/tools/tsrslint-shim/bin/tsgolint.js @@ -1,13 +1,24 @@ #!/usr/bin/env node // Vite+'s type-aware lint backend, run as tsrslint (tsgolint's rules ported to Rust on tsrs) instead of tsgolint -// (docs/adr/0055-vite-plus-and-pnpm.md → Consequences). `vp lint` and `vp check` run the `bin/tsgolint` of their own -// `oxlint-tsgolint`, whatever `OXLINT_TSGOLINT_PATH` or `node_modules/.bin` say, so `pnpm-workspace.yaml`'s overrides -// make this directory that package. It has no `package.json` on purpose: `effect-tsgo patch` (the root `prepare`) looks -// for Vite+'s `oxlint-tsgolint` by its `package.json`, and would then fail the install looking for tsgolint's platform -// binary, which this replaces. +// (docs/adr/0055-vite-plus-and-pnpm.md → Consequences). `vp lint` and `vp check` run the `bin/tsgolint` of the +// `oxlint-tsgolint` they resolve, from the working directory first and then from `vite-plus`, and set +// `OXLINT_TSGOLINT_PATH` to it themselves, so `pnpm-workspace.yaml`'s overrides make this directory that package (no +// workspace package declares `oxlint-tsgolint`, which would take its place). It has no `package.json` on purpose: +// `effect-tsgo patch` (the root `prepare`) looks for Vite+'s `oxlint-tsgolint` by its `package.json`, and would then fail +// the install looking for tsgolint's platform binary, which this replaces. +import { spawn } from "node:child_process"; import { createRequire } from "node:module"; const { binaryPath } = createRequire(import.meta.url)("@maschwenk/tsrslint"); -const exe = binaryPath(); +const tsrslint = binaryPath(); +const args = process.argv.slice(2); -process.execve(exe, [exe, ...process.argv.slice(2)]); +// Node 22.15 and 23.11 and later replace this process with tsrslint; an older Node runs it as a child, with oxlint's +// pipes, and exits as it does. +if ("execve" in process) process.execve(tsrslint, [tsrslint, ...args]); + +const child = spawn(tsrslint, args, { stdio: "inherit" }); + +child.on("exit", (code, signal) => + signal ? process.kill(process.pid, signal) : process.exit(code ?? 1), +); From 8757260467b0682cde3e4e95798d65e20b5ff42e Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 12 Nov 2026 18:19:56 -0500 Subject: [PATCH 3/4] build: run Vite+'s type-aware lint on tsrs's own linter tsrs 0.21 ships tsgolint's port as tsrs-lint, so the shim loads the tsrs package's linter in place of @maschwenk/tsrslint. A whole-repo vp lint takes 7-8 s and 1 GB at most. --- ...alls-and-scripts-and-tsrs-for-typecheck.md | 2 +- docs/adr/0055-vite-plus-and-pnpm.md | 11 +- docs/development/dependencies.md | 2 +- package.json | 2 +- pnpm-lock.yaml | 135 ++++++++++++------ pnpm-workspace.yaml | 4 +- tools/tsrs-lint-shim/bin/tsgolint.js | 17 +++ tools/tsrslint-shim/bin/tsgolint.js | 24 ---- 8 files changed, 118 insertions(+), 79 deletions(-) create mode 100755 tools/tsrs-lint-shim/bin/tsgolint.js delete mode 100755 tools/tsrslint-shim/bin/tsgolint.js diff --git a/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md b/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md index d033ca59..ca1712d4 100644 --- a/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md +++ b/docs/adr/0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md @@ -1,5 +1,5 @@ --- -status: accepted, partly superseded by ADR-0055 (pnpm installs and runs the scripts, Vite+ runs the tasks instead of Turborepo, and tsrslint becomes Vite+'s type-aware lint backend through a pnpm override instead of `scripts/link-tsrslint.sh`; tsrs still typechecks) +status: accepted, partly superseded by ADR-0055 (pnpm installs and runs the scripts, Vite+ runs the tasks instead of Turborepo, and tsrs's own linter replaces tsrslint as the type-aware lint backend, through a pnpm override instead of `scripts/link-tsrslint.sh`; tsrs still typechecks) --- # Bun installs and runs scripts, tsrs typechecks, and Vitest stays on Node diff --git a/docs/adr/0055-vite-plus-and-pnpm.md b/docs/adr/0055-vite-plus-and-pnpm.md index 2544391a..c189fde6 100644 --- a/docs/adr/0055-vite-plus-and-pnpm.md +++ b/docs/adr/0055-vite-plus-and-pnpm.md @@ -4,24 +4,24 @@ status: accepted # pnpm installs, and Vite+ checks, lints, formats and runs the tasks -The repo installs with pnpm again, and its toolchain is Vite+ (`vite-plus`): `vp check` formats, lints and runs the type-aware lint (on tsrslint) once at the root, `vp run` runs every package's tasks and caches them, and `vp staged` with `.vite-hooks/` replaces lint-staged and Husky. This replaces [ADR-0028](0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md)'s Bun and Turborepo, and the link that made tsrslint oxlint's backend; each package's typecheck stays `effect-tsgo tsrs`, for the Effect diagnostics that `vp check`'s type-check does not run. +The repo installs with pnpm again, and its toolchain is Vite+ (`vite-plus`): `vp check` formats, lints and runs the type-aware lint (on tsrs's linter) once at the root, `vp run` runs every package's tasks and caches them, and `vp staged` with `.vite-hooks/` replaces lint-staged and Husky. This replaces [ADR-0028](0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md)'s Bun and Turborepo, and tsrslint, the link that made a port of tsgolint on tsrs oxlint's backend; each package's typecheck stays `effect-tsgo tsrs`, for the Effect diagnostics that `vp check`'s type-check does not run. - **pnpm** (`packageManager`, `mise.toml`): `pnpm-workspace.yaml` holds the workspace, the patched dependencies, the packages allowed to run install scripts (`allowBuilds`: the pnpm list from before ADR-0028, with `core-js-pure` still blocked and `just-bash`'s optional compressors now blocked too, as ADR-0028 found they serve only its Node command line; `typescript`, which Bun had to trust for the effect-tsgo patch, needs no entry under pnpm) and the exemptions from pnpm's default minimum release age of a day. Workspace dependencies stay plain `"*"` for npm's production install of the root (`pi install git:…`), so `linkWorkspacePackages` links them. `dedupePeers` tells peer variants apart by their peers' versions alone: without it the server had two `@cloudflare/computer`s, and `infra` two `alchemy`s (one per `ws`, which an override now holds at one version), and their typechecks failed. - **One config** (`vite.config.ts` at the root): the lint rules, the anti-slop plugins and every package's own rules (as `lint.overrides` by path; Vite+ reads no nested lint or format config), the format settings and the staged-file rules. `vp check` runs at the root, not per package: it lints the whole repo in one process. - **Tasks** (`packages/config/src/tasks.ts`, passed to `run.tasks` by each package's `vite.config.ts`): `typecheck` and `test`. Vite Task records the files each task reads and replays a task none of whose inputs changed, so a change to a package's source reruns its dependents' tasks without Turborepo's `transit` node or `apps/web/turbo.json`'s hand-listed inputs. A cached task runs in a clean environment, so `test` names the variables that change what a test checks (`CI`, the live tests' and benchmarks' switches, `UPDATE_SNAPSHOT`) and passes the rest through untracked. `test` is `vitest run`, not `vp test`: Vite Task runs a `vp test` inside the `vp` that started it, with that copy's Vitest, and a `vp` that is not the project's (mise's `npm:vite-plus`) gives the workerd projects a second Vitest, which `@cloudflare/vitest-plugin`'s worker cannot reach. -- **Versions**: `vite-plus` 1.4.0, the last release that bundles Vitest 5.0.5; 1.5 and 1.6 bundle 5.1, under which the workerd tests fail (docs/development/dependencies.md). Overrides make every `vite` Vite+'s core and every `vitest` 5.0.5. Vite+ 1.4.0 bundles oxlint 1.89 and oxfmt 0.74, older than the 1.91 and 0.76 they replace (tsrslint 0.1.6, built against oxlint 1.91, runs under 1.89); oxfmt 0.74 wraps three signatures differently, reformatted with the switch. +- **Versions**: `vite-plus` 1.4.0, the last release that bundles Vitest 5.0.5; 1.5 and 1.6 bundle 5.1, under which the workerd tests fail (docs/development/dependencies.md). Overrides make every `vite` Vite+'s core and every `vitest` 5.0.5. Vite+ 1.4.0 bundles oxlint 1.89 and oxfmt 0.74, older than the 1.91 and 0.76 they replace (tsrs's linter, which speaks tsgolint 7.0.2005's protocol, runs under 1.89); oxfmt 0.74 wraps three signatures differently, reformatted with the switch. - **CI** sets up with `voidzero-dev/setup-vp`, which installs the Vite+ of the root `package.json` (so its `vp` runs the project's copy), Node and pnpm, and caches pnpm's store. Each check part restores and saves its Vite Task cache (`node_modules/.vite/task-cache`) under a rolling key and clears it past 1 GiB, since Vite Task never evicts. Measured on an 8-core Apple Silicon laptop (2026-11-12), warm caches: -- **Lint**: `vp lint` over the whole repo, type-aware with type-check, on tsrslint: 9–10 s wall, 13–14 s of CPU, 1.5–2.1 GB peak memory (two runs); on Vite+'s own tsgolint 7.0.2004: 16 s, 48 s, 3.6 GB (ADR-0028's tsrslint, one package after another: 18–24 s, 19 s, 0.47 GB). +- **Lint**: `vp lint` over the whole repo, type-aware with type-check, on tsrs 0.24's linter: 7–8 s wall, 15 s of CPU, 0.9–1.0 GB peak memory (two runs); on tsrslint 0.1.6: 9–10 s, 13–14 s, 1.5–2.1 GB; on Vite+'s own tsgolint 7.0.2004: 16 s, 48 s, 3.6 GB (ADR-0028's tsrslint, one package after another: 18–24 s, 19 s, 0.47 GB). - **Typecheck**: `vp run -r typecheck`, 7–11 s uncached; 0.9 s when every task replays. - **Tests**: `vp run -r test`, 4 min uncached; 1 min when only the tasks that modify their own inputs (`@cloudpid/mcp`'s import-rule test plants files) and `@cloudpid/sandbox-image`'s, which is uncached, run again. - **Install** with a warm store and no `node_modules`, `prepare` included: 5.1 s wall, 1.1 s of user CPU (ADR-0028: Bun 0.85 s, pnpm 2.4 s, before `prepare`'s `vp config`). ## Consequences -- The type-aware lint stays on tsrslint, by another route: Vite+ sets `OXLINT_TSGOLINT_PATH` to the `bin/tsgolint` of its own `oxlint-tsgolint` and ignores `node_modules/.bin/tsgolint`, so `scripts/link-tsrslint.sh` is gone, and a pnpm override makes `oxlint-tsgolint` the repo's `tools/tsrslint-shim`, whose `bin/tsgolint.js` runs `@maschwenk/tsrslint`'s binary. It rests on where Vite+ looks for its backend (docs/development/dependencies.md says what to check on an upgrade). The shim has no `package.json`, or `effect-tsgo patch` finds it as Vite+'s `oxlint-tsgolint` and fails `prepare` looking for tsgolint's platform binary. tsrslint ships for macOS arm64 and Linux x64 and arm64 (glibc) only, as before. This lasts until tsrs ships its own linter (oxc-project/tsrs#378). +- The type-aware lint runs on tsrs's own linter (`tsrs-lint`, `tsrs --lint`, since tsrs 0.21: tsgolint's headless protocol and its 61 type-aware rules), which replaces tsrslint, its predecessor outside tsrs. Vite+ sets `OXLINT_TSGOLINT_PATH` to the `bin/tsgolint` of its own `oxlint-tsgolint` and ignores `node_modules/.bin`, so `scripts/link-tsrslint.sh` is gone, and a pnpm override makes `oxlint-tsgolint` the repo's `tools/tsrs-lint-shim`, whose `bin/tsgolint.js` loads the root `tsrs` package's `tsrs-lint`. It rests on where Vite+ looks for its backend (docs/development/dependencies.md says what to check on an upgrade). The shim has no `package.json`, or `effect-tsgo patch` finds it as Vite+'s `oxlint-tsgolint` and fails `prepare` looking for tsgolint's platform binary. The `tsrs` package is the linter only: `effect-tsgo tsrs` typechecks with the Effect-patched tsrs that `@effect/tsgo` ships. It goes once `effect-tsgo --tsrs-lint vp lint` (`@effect/tsgo` 0.68 and later: Vite+'s lint on the Effect-patched tsrs, with the Effect rules, and no shim) can run, which needs oxlint 1.91 or later, so a Vite+ past 1.4.0 (`Versions`). - Run the project's own `vp`: `pnpm exec vp`, the root scripts, or the standalone global CLI from vite.plus, which hands a command to the project's copy. mise's `npm:vite-plus` is a second copy of the whole toolchain. - Turborepo's CI pruning is gone; the Vite Task cache is experimental in CI (Vite+'s docs say so) and is bounded by size instead. - On macOS, Vite Task runs a cached task's system coreutils as uutils' to record what it reads. The tests that probe the host for GNU coreutils check `--version` for `(GNU coreutils)`, and `@cloudpid/sandbox-image`'s `test` is uncached, since its memory-guard tests fail under uutils. Linux is unaffected. @@ -34,4 +34,5 @@ Measured on an 8-core Apple Silicon laptop (2026-11-12), warm caches: - **Keeping Bun with Vite+.** Vite+ supports Bun, but the owner chose pnpm; Bun's install speed was most of ADR-0028's case for it, and pnpm's global virtual store is available where it matters, on the Container. - **Keeping Turborepo with Vite+'s lint and format.** Turborepo's `transit` node and hand-listed inputs were what Vite Task's file tracking does by itself, and one task runner is one less tool. - **Vite+ 1.6 with Vitest 5.1.** The workerd tests fail under Vitest 5.1 (dependencies.md); 1.4.0 holds Vitest at 5.0.5 until that is fixed. -- **Vite+'s own tsgolint**, with nothing to keep in step with Vite+. One lint over the repo on it took 16 s and 3.6 GB against tsrslint's 9–10 s and 2.1 GB at most, and needs no shim, but ADR-0028 chose tsrslint for that cost, and the shim is one file. +- **Vite+'s own tsgolint**, with nothing to keep in step with Vite+. One lint over the repo on it took 16 s and 3.6 GB against tsrs's 7–8 s and 1.0 GB at most, and needs no shim, but ADR-0028 chose a linter on tsrs for that cost, and the shim is one file. +- **tsrslint** (`@maschwenk/tsrslint`) behind the same shim. It worked (9–10 s, 2.1 GB at most), but tsrs now ships the same port itself, and its author means to fold tsrslint into it. diff --git a/docs/development/dependencies.md b/docs/development/dependencies.md index a856c824..03af949c 100644 --- a/docs/development/dependencies.md +++ b/docs/development/dependencies.md @@ -6,7 +6,7 @@ Some dependencies carry a patch (`patches/`) or an exact pin. When upgrading one | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `@cloudflare/vitest-plugin` | `patches/@cloudflare__vitest-plugin@1.5.1.patch` | Keeps the module snapshot it sends a reused worker under workerd's 32 MiB WebSocket message limit, past which the worker dies with `1009 Message is too large` ([cloudflare/workers-sdk#16349](https://github.com/cloudflare/workers-sdk/issues/16349)). Drop it once #16349 is fixed. | | `vite-plus`, `vitest` | exact `1.4.0` (`vite-plus`) in the root `package.json` and `apps/web`; exact `5.0.5` (`vitest`) at the root and in the packages whose test plugins peer it; the `vite` and `vitest` `overrides` in `pnpm-workspace.yaml` (`@voidzero-dev/vite-plus-core@1.4.0`, `5.0.5`) | Vite+ bundles its own Vitest (1.4.0 bundles 5.0.5; 1.5 and later bundle 5.1), so `vite-plus`, the `vite` override and `vitest` move together. Vitest is held below 5.1: under 5.1.0 the workerd pool delays a timer a Durable Object request sets (`setImmediate`, `setTimeout(0)`) until a later request to an object awaits a real timer, so an Effect fiber forked in a request (Effect's scheduler starts it with `setImmediate`) starts late: a Session reports itself idle only at its next request, and `apps/server/src/session/admission.workerd.test.ts` ("Stop waits for it"), `host.workerd.test.ts` and `import.workerd.test.ts` fail. Bisected on its own (5.0.5 with the same workerd, `@cloudflare/vitest-plugin`, Effect and pi-durable delivers them at once); deployed workerd is unaffected. Before lifting it, check that a `setImmediate` set in a `runInDurableObject` callback runs before the next no-op `runInDurableObject` returns, and rerun those three files. | -| `@maschwenk/tsrslint`, `oxlint-tsgolint` | exact `0.1.6` in the root `package.json`; `oxlint-tsgolint` overridden to `link:./tools/tsrslint-shim` in `pnpm-workspace.yaml` | Vite+'s type-aware lint backend is tsrslint, through the shim (`tools/tsrslint-shim/bin/tsgolint.js`; [ADR-0055](../adr/0055-vite-plus-and-pnpm.md) → Consequences). When upgrading `vite-plus` or tsrslint, check that `pnpm exec vp lint` on a file with a type error and a floating promise still reports both (`typescript(TS2322)`, `no-floating-promises`): a Vite+ that looks for its backend elsewhere fails with `Error running tsgolint`, and a tsrslint built against a newer oxlint than Vite+ bundles may not speak its protocol. Drop both once tsrs ships its own linter (oxc-project/tsrs#378). | +| `tsrs`, `oxlint-tsgolint` | exact `0.24.0-ts7.1.0-beta` (`tsrs`) in the root `package.json`; `oxlint-tsgolint` overridden to `link:./tools/tsrs-lint-shim` in `pnpm-workspace.yaml` | Vite+'s type-aware lint backend is tsrs's own linter, `tsrs-lint`, through the shim (`tools/tsrs-lint-shim/bin/tsgolint.js`; [ADR-0055](../adr/0055-vite-plus-and-pnpm.md) → Consequences). This `tsrs` is the linter only; the typecheck is `effect-tsgo tsrs`, the tsrs that `@effect/tsgo` ships, whatever this pin says. When upgrading `vite-plus` or `tsrs`, check that `pnpm exec vp lint` on a file with a type error and a floating promise still reports both (`typescript(TS2322)`, `no-floating-promises`): a Vite+ that looks for its backend elsewhere fails with `Error running tsgolint`, and a tsrs that speaks a newer tsgolint protocol than Vite+'s oxlint may not be understood. Drop both, and `tsrs` from the root, once `effect-tsgo --tsrs-lint vp lint` runs (`@effect/tsgo` 0.68 and later, with oxlint 1.91 or later). | | `ws` | exact `8.22.1`, an `overrides` entry in `pnpm-workspace.yaml` | One `ws` for every package: `@earendil-works/chord` pins `8.21.0` and the rest resolve 8.22, and each `ws` is a peer variant of `alchemy`, whose two copies then fail `infra`'s typecheck (a union of two `AlchemyContext`s). Drop it once chord allows 8.22, or move it with the newest `ws` chord allows. | | `@cloudflare/computer` | `patches/@cloudflare__computer@0.9.0.patch` | Adds `Workspace.remount()`, which `updateSkills` runs: computer checks a mount's version only at a Workspace's first index ([`../architecture/workspace.md`](../architecture/workspace.md) → _The Skill set_). Drop it once computer can index a mount again; rerun `apps/server/src/workspace/skills.workerd.test.ts` either way. Also update the `bash` routing lists if the Worker Shell changed ([`workers.md`](workers.md) → _The Workspace DO_). | | `@cloudflare/computer`, computerd | read for the file-change signal | The file-change signal ([`../architecture/container.md`](../architecture/container.md) → _File-change signals_) reads computer's change-log tables (`apps/server/src/workspace/change-log.ts`) and span names (`notify.ts`), and needs computerd's `setxattr` on its mount to stay a no-op the kernel reports. When upgrading either, rerun `src/workspace/notify.workerd.test.ts` and `notify.test.ts`, and recheck by hand as that section's _Limits_ says. | diff --git a/package.json b/package.json index a9a4ad9c..268c93c7 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "@commitlint/cli": "21.2.4", "@commitlint/config-conventional": "21.2.4", "@effect/tsgo": "0.64.1", - "@maschwenk/tsrslint": "0.1.6", "skills": "^1.7.6", + "tsrs": "0.24.0-ts7.1.0-beta", "typescript": "^7.0.2", "vite-plus": "1.4.0", "vitest": "5.0.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3a9ac5c..18bf53af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -167,7 +167,7 @@ overrides: vite@*: npm:@voidzero-dev/vite-plus-core@1.4.0 vitest@*: 5.0.5 ws: 8.22.1 - oxlint-tsgolint: link:./tools/tsrslint-shim + oxlint-tsgolint: link:./tools/tsrs-lint-shim patchedDependencies: '@alchemy.run/cloudflare@2.0.0-beta.85': 42560d88385a37a4a65b7d0f3d0f4746d76477154fea680e52ae463e3f9f326c @@ -191,12 +191,12 @@ importers: '@effect/tsgo': specifier: 0.64.1 version: 0.64.1 - '@maschwenk/tsrslint': - specifier: 0.1.6 - version: 0.1.6 skills: specifier: ^1.7.6 version: 1.7.6 + tsrs: + specifier: 0.24.0-ts7.1.0-beta + version: 0.24.0-ts7.1.0-beta typescript: specifier: ^7.0.2 version: 7.0.2 @@ -1999,28 +1999,6 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@maschwenk/tsrslint-darwin-arm64@0.1.6': - resolution: {integrity: sha512-4cd/YRhspvIUxfr6xx2oWv3+WTeKLxfOe4tW49zPdo80X6rp4mxkWQg3C9vkm+1ugeAakoQgtOHNP9SnH5raLA==} - cpu: [arm64] - os: [darwin] - - '@maschwenk/tsrslint-linux-arm64@0.1.6': - resolution: {integrity: sha512-f2G8zGWoXHTHGegUdrqiX5EjyYDGFtk/vq0JeEAHlcjl3LtDD2cIl8kkuCypA69CohAqxm49yf2gtVyMSF/EMg==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@maschwenk/tsrslint-linux-x64@0.1.6': - resolution: {integrity: sha512-e1XeesEMB+m3LocBzjzUxZ+F0CpSZodC/Cp8EynPGA6Buz4l0rDx1bPHHZAgcq2bcKN2Mgk+ep3KY75P8UuRFA==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@maschwenk/tsrslint@0.1.6': - resolution: {integrity: sha512-s/dMOF/F5gINLYMpcZpLAFVH5hWcSc4N/I8uaOkD8nMUWSFVSN/R+Jx7/rMbj5hX+ej4rthgfVhx0ZZb7/pNSg==} - engines: {node: '>=18'} - hasBin: true - '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} @@ -3633,6 +3611,52 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tsrs/darwin-arm64@0.24.0-ts7.1.0-beta': + resolution: {integrity: sha512-GxGPRieCGIXevJgGlbne9pRqkfAN+VmBQvBHWWcF8rXLNX9yCxYo78/a7Auqjf723b4eFTlM5mgkclUit/Fu9w==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@tsrs/darwin-x64@0.24.0-ts7.1.0-beta': + resolution: {integrity: sha512-TrXdOyEq++blyYp6KphoHGmsGxAn1flYzjm0peLEI3c88z1UQa+pKkcuPgZ6FOxTW6fSaT9572n21kz+0bWi/g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@tsrs/linux-arm64-gnu@0.24.0-ts7.1.0-beta': + resolution: {integrity: sha512-Ph5NK0vnaR4gnBW2LgrZsUPx4mKF+9tCQUYZFOHmny6SMojSsm/5GCiBu0sHZEZhmyIqq8UbineUEA7T0QImnw==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tsrs/linux-arm64-musl@0.24.0-ts7.1.0-beta': + resolution: {integrity: sha512-vjgx8wGuAVSOPLlb2eVQpQVolImZa7vsH/1kvYOaokcP/KZXVUmHzgroxK0t9gxJ0SXvT4VKNjWZ+t+4tDNu1A==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tsrs/linux-x64-gnu@0.24.0-ts7.1.0-beta': + resolution: {integrity: sha512-tj1SNWBnJoBUzU2zrD18tUu3h6o36FXQGPpmIXsADHSfU5H9pVQdK/QzPIO76rb72P7foXHluE+xGTXXf8nNaA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tsrs/linux-x64-musl@0.24.0-ts7.1.0-beta': + resolution: {integrity: sha512-sizu0EdGw9ITqEaZKg60TDhDk5PXT9RzVkCdesBjk/BZhS0BVU2cRhvoRBmDbk+2vCUgW14j+Otg3tl+002qNQ==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tsrs/win32-x64@0.24.0-ts7.1.0-beta': + resolution: {integrity: sha512-WAbzgd5JBOauQ/oL6DTdGEh09tM/q8tlGAcRORskhPK7eIQVVa8Js2pc7DVW0XokWTSADeD9v6HKtU2Ge0r/fQ==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -6147,6 +6171,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsrs@0.24.0-ts7.1.0-beta: + resolution: {integrity: sha512-Iy7q93qfRHcI0Y31IKx6fCsDQCsSjtrT01PIgOVolBXPJTMdm84oH1pEYyAMPQ/SnRqWDSWI8wEUHbv6e9TmHA==} + engines: {node: '>=16.20.0'} + hasBin: true + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -7765,21 +7794,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 - '@maschwenk/tsrslint-darwin-arm64@0.1.6': - optional: true - - '@maschwenk/tsrslint-linux-arm64@0.1.6': - optional: true - - '@maschwenk/tsrslint-linux-x64@0.1.6': - optional: true - - '@maschwenk/tsrslint@0.1.6': - optionalDependencies: - '@maschwenk/tsrslint-darwin-arm64': 0.1.6 - '@maschwenk/tsrslint-linux-arm64': 0.1.6 - '@maschwenk/tsrslint-linux-x64': 0.1.6 - '@mixmark-io/domino@2.2.0': {} '@modelcontextprotocol/client@2.4.0': @@ -9188,6 +9202,27 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@tsrs/darwin-arm64@0.24.0-ts7.1.0-beta': + optional: true + + '@tsrs/darwin-x64@0.24.0-ts7.1.0-beta': + optional: true + + '@tsrs/linux-arm64-gnu@0.24.0-ts7.1.0-beta': + optional: true + + '@tsrs/linux-arm64-musl@0.24.0-ts7.1.0-beta': + optional: true + + '@tsrs/linux-x64-gnu@0.24.0-ts7.1.0-beta': + optional: true + + '@tsrs/linux-x64-musl@0.24.0-ts7.1.0-beta': + optional: true + + '@tsrs/win32-x64@0.24.0-ts7.1.0-beta': + optional: true + '@types/aria-query@5.0.4': {} '@types/chai@5.2.3': @@ -11155,7 +11190,7 @@ snapshots: '@oxfmt/binding-win32-x64-msvc': 0.74.0 vite-plus: 1.4.0(@opentelemetry/api@1.10.0)(@types/node@26.6.6)(@vitest/ui@5.0.5)(esbuild@0.28.2)(happy-dom@21.0.4)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.1) - oxlint@1.89.0(oxlint-tsgolint@tools+tsrslint-shim)(vite-plus@1.4.0): + oxlint@1.89.0(oxlint-tsgolint@tools+tsrs-lint-shim)(vite-plus@1.4.0): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.89.0 '@oxlint/binding-android-arm64': 1.89.0 @@ -11176,7 +11211,7 @@ snapshots: '@oxlint/binding-win32-arm64-msvc': 1.89.0 '@oxlint/binding-win32-ia32-msvc': 1.89.0 '@oxlint/binding-win32-x64-msvc': 1.89.0 - oxlint-tsgolint: link:tools/tsrslint-shim + oxlint-tsgolint: link:tools/tsrs-lint-shim vite-plus: 1.4.0(@opentelemetry/api@1.10.0)(@types/node@26.6.6)(@vitest/ui@5.0.5)(esbuild@0.28.2)(happy-dom@21.0.4)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.1) p-retry@4.6.2: @@ -11950,6 +11985,16 @@ snapshots: tslib@2.8.1: {} + tsrs@0.24.0-ts7.1.0-beta: + optionalDependencies: + '@tsrs/darwin-arm64': 0.24.0-ts7.1.0-beta + '@tsrs/darwin-x64': 0.24.0-ts7.1.0-beta + '@tsrs/linux-arm64-gnu': 0.24.0-ts7.1.0-beta + '@tsrs/linux-arm64-musl': 0.24.0-ts7.1.0-beta + '@tsrs/linux-x64-gnu': 0.24.0-ts7.1.0-beta + '@tsrs/linux-x64-musl': 0.24.0-ts7.1.0-beta + '@tsrs/win32-x64': 0.24.0-ts7.1.0-beta + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 @@ -12126,8 +12171,8 @@ snapshots: '@vitest/spy': 5.0.5 '@vitest/utils': 5.0.5 oxfmt: 0.74.0(vite-plus@1.4.0) - oxlint: 1.89.0(oxlint-tsgolint@tools+tsrslint-shim)(vite-plus@1.4.0) - oxlint-tsgolint: link:tools/tsrslint-shim + oxlint: 1.89.0(oxlint-tsgolint@tools+tsrs-lint-shim)(vite-plus@1.4.0) + oxlint-tsgolint: link:tools/tsrs-lint-shim vite: '@voidzero-dev/vite-plus-core@1.4.0(@types/node@26.6.6)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.1)' vitest: 5.0.5(@opentelemetry/api@1.10.0)(@types/node@26.6.6)(@vitest/browser-preview@5.0.5)(@vitest/ui@5.0.5)(@voidzero-dev/vite-plus-core@1.4.0)(happy-dom@21.0.4) optionalDependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8c12bfa7..85f3dce8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -37,8 +37,8 @@ overrides: # One `ws` for every package: chord pins 8.21.0 and the rest resolve 8.22, and each `ws` is a peer variant of alchemy, # whose two copies then fail the typecheck of `infra` (`AlchemyContext | AlchemyContext`). ws: 8.22.1 - # Vite+'s type-aware lint backend runs tsrslint instead of tsgolint (tools/tsrslint-shim/bin/tsgolint.js). - oxlint-tsgolint: link:./tools/tsrslint-shim + # Vite+'s type-aware lint backend runs tsrs's linter instead of tsgolint (tools/tsrs-lint-shim/bin/tsgolint.js). + oxlint-tsgolint: link:./tools/tsrs-lint-shim # Vite+'s core stands in for `vite`, and packages that peer an older `vite` or `vitest` accept it (`vp migrate`'s rule). peerDependencyRules: diff --git a/tools/tsrs-lint-shim/bin/tsgolint.js b/tools/tsrs-lint-shim/bin/tsgolint.js new file mode 100755 index 00000000..d819f238 --- /dev/null +++ b/tools/tsrs-lint-shim/bin/tsgolint.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node +// Vite+'s type-aware lint backend, run as tsrs's own linter (`tsrs-lint`, tsrs's port of tsgolint's headless mode and +// rules) instead of tsgolint (docs/adr/0055-vite-plus-and-pnpm.md → Consequences). `vp lint` and `vp check` run the +// `bin/tsgolint` of the `oxlint-tsgolint` they resolve, from the working directory first and then from `vite-plus`, and +// set `OXLINT_TSGOLINT_PATH` to it themselves, so `pnpm-workspace.yaml`'s overrides make this directory that package (no +// workspace package declares `oxlint-tsgolint`, which would take its place). It has no `package.json` on purpose: +// `effect-tsgo patch` (the root `prepare`) looks for Vite+'s `oxlint-tsgolint` by its `package.json`, and would then fail +// the install looking for tsgolint's platform binary, which this replaces. +import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; +import { pathToFileURL } from "node:url"; + +// `tsrs`'s `tsrs-lint` command (its `bin/tsrs-lint`) loads this launcher, which reads `process.argv` from its third +// entry on, as this script's are. +const tsrs = dirname(createRequire(import.meta.url).resolve("tsrs/package.json")); + +await import(pathToFileURL(join(tsrs, "lib", "tsrs-lint.js")).href); diff --git a/tools/tsrslint-shim/bin/tsgolint.js b/tools/tsrslint-shim/bin/tsgolint.js deleted file mode 100755 index 37299e10..00000000 --- a/tools/tsrslint-shim/bin/tsgolint.js +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env node -// Vite+'s type-aware lint backend, run as tsrslint (tsgolint's rules ported to Rust on tsrs) instead of tsgolint -// (docs/adr/0055-vite-plus-and-pnpm.md → Consequences). `vp lint` and `vp check` run the `bin/tsgolint` of the -// `oxlint-tsgolint` they resolve, from the working directory first and then from `vite-plus`, and set -// `OXLINT_TSGOLINT_PATH` to it themselves, so `pnpm-workspace.yaml`'s overrides make this directory that package (no -// workspace package declares `oxlint-tsgolint`, which would take its place). It has no `package.json` on purpose: -// `effect-tsgo patch` (the root `prepare`) looks for Vite+'s `oxlint-tsgolint` by its `package.json`, and would then fail -// the install looking for tsgolint's platform binary, which this replaces. -import { spawn } from "node:child_process"; -import { createRequire } from "node:module"; - -const { binaryPath } = createRequire(import.meta.url)("@maschwenk/tsrslint"); -const tsrslint = binaryPath(); -const args = process.argv.slice(2); - -// Node 22.15 and 23.11 and later replace this process with tsrslint; an older Node runs it as a child, with oxlint's -// pipes, and exits as it does. -if ("execve" in process) process.execve(tsrslint, [tsrslint, ...args]); - -const child = spawn(tsrslint, args, { stdio: "inherit" }); - -child.on("exit", (code, signal) => - signal ? process.kill(process.pid, signal) : process.exit(code ?? 1), -); From 0eadb180638047603b76c668edc05568d7cc0c83 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 12 Nov 2026 18:21:34 -0500 Subject: [PATCH 4/4] build: load tsrs-lint by its bin entry, and say the shim is not for Windows --- docs/adr/0055-vite-plus-and-pnpm.md | 4 ++-- docs/development/dependencies.md | 2 +- tools/tsrs-lint-shim/bin/tsgolint.js | 10 ++++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/adr/0055-vite-plus-and-pnpm.md b/docs/adr/0055-vite-plus-and-pnpm.md index c189fde6..c7479ac5 100644 --- a/docs/adr/0055-vite-plus-and-pnpm.md +++ b/docs/adr/0055-vite-plus-and-pnpm.md @@ -4,7 +4,7 @@ status: accepted # pnpm installs, and Vite+ checks, lints, formats and runs the tasks -The repo installs with pnpm again, and its toolchain is Vite+ (`vite-plus`): `vp check` formats, lints and runs the type-aware lint (on tsrs's linter) once at the root, `vp run` runs every package's tasks and caches them, and `vp staged` with `.vite-hooks/` replaces lint-staged and Husky. This replaces [ADR-0028](0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md)'s Bun and Turborepo, and tsrslint, the link that made a port of tsgolint on tsrs oxlint's backend; each package's typecheck stays `effect-tsgo tsrs`, for the Effect diagnostics that `vp check`'s type-check does not run. +The repo installs with pnpm again, and its toolchain is Vite+ (`vite-plus`): `vp check` formats, lints and runs the type-aware lint (on tsrs's linter) once at the root, `vp run` runs every package's tasks and caches them, and `vp staged` with `.vite-hooks/` replaces lint-staged and Husky. This replaces [ADR-0028](0028-bun-for-installs-and-scripts-and-tsrs-for-typecheck.md)'s Bun and Turborepo, and `scripts/link-tsrslint.sh`, which made tsrslint oxlint's type-aware backend; each package's typecheck stays `effect-tsgo tsrs`, for the Effect diagnostics that `vp check`'s type-check does not run. - **pnpm** (`packageManager`, `mise.toml`): `pnpm-workspace.yaml` holds the workspace, the patched dependencies, the packages allowed to run install scripts (`allowBuilds`: the pnpm list from before ADR-0028, with `core-js-pure` still blocked and `just-bash`'s optional compressors now blocked too, as ADR-0028 found they serve only its Node command line; `typescript`, which Bun had to trust for the effect-tsgo patch, needs no entry under pnpm) and the exemptions from pnpm's default minimum release age of a day. Workspace dependencies stay plain `"*"` for npm's production install of the root (`pi install git:…`), so `linkWorkspacePackages` links them. `dedupePeers` tells peer variants apart by their peers' versions alone: without it the server had two `@cloudflare/computer`s, and `infra` two `alchemy`s (one per `ws`, which an override now holds at one version), and their typechecks failed. - **One config** (`vite.config.ts` at the root): the lint rules, the anti-slop plugins and every package's own rules (as `lint.overrides` by path; Vite+ reads no nested lint or format config), the format settings and the staged-file rules. `vp check` runs at the root, not per package: it lints the whole repo in one process. @@ -21,7 +21,7 @@ Measured on an 8-core Apple Silicon laptop (2026-11-12), warm caches: ## Consequences -- The type-aware lint runs on tsrs's own linter (`tsrs-lint`, `tsrs --lint`, since tsrs 0.21: tsgolint's headless protocol and its 61 type-aware rules), which replaces tsrslint, its predecessor outside tsrs. Vite+ sets `OXLINT_TSGOLINT_PATH` to the `bin/tsgolint` of its own `oxlint-tsgolint` and ignores `node_modules/.bin`, so `scripts/link-tsrslint.sh` is gone, and a pnpm override makes `oxlint-tsgolint` the repo's `tools/tsrs-lint-shim`, whose `bin/tsgolint.js` loads the root `tsrs` package's `tsrs-lint`. It rests on where Vite+ looks for its backend (docs/development/dependencies.md says what to check on an upgrade). The shim has no `package.json`, or `effect-tsgo patch` finds it as Vite+'s `oxlint-tsgolint` and fails `prepare` looking for tsgolint's platform binary. The `tsrs` package is the linter only: `effect-tsgo tsrs` typechecks with the Effect-patched tsrs that `@effect/tsgo` ships. It goes once `effect-tsgo --tsrs-lint vp lint` (`@effect/tsgo` 0.68 and later: Vite+'s lint on the Effect-patched tsrs, with the Effect rules, and no shim) can run, which needs oxlint 1.91 or later, so a Vite+ past 1.4.0 (`Versions`). +- The type-aware lint runs on tsrs's own linter (`tsrs-lint`, `tsrs --lint`, since tsrs 0.21: tsgolint's headless protocol and its 61 type-aware rules), which replaces tsrslint, its predecessor outside tsrs. Vite+ sets `OXLINT_TSGOLINT_PATH` to the `bin/tsgolint` of its own `oxlint-tsgolint` and ignores `node_modules/.bin`, so `scripts/link-tsrslint.sh` is gone, and a pnpm override makes `oxlint-tsgolint` the repo's `tools/tsrs-lint-shim`, whose `bin/tsgolint.js` loads the root `tsrs` package's `tsrs-lint`. It rests on where Vite+ looks for its backend (docs/development/dependencies.md says what to check on an upgrade). The shim has no `package.json`, or `effect-tsgo patch` finds it as Vite+'s `oxlint-tsgolint` and fails `prepare` looking for tsgolint's platform binary. The `tsrs` package is the linter only: `effect-tsgo tsrs` typechecks with the Effect-patched tsrs that `@effect/tsgo` ships. It goes once `effect-tsgo --tsrs-lint vp lint` (`@effect/tsgo` 0.68 and later: Vite+'s lint on the Effect-patched tsrs, with the Effect rules, and no shim) can run, which needs oxlint 1.91 or later, so a Vite+ past 1.4.0 (`Versions`). The shim does not run on Windows, where Vite+ looks for `tsgolint.exe` or `tsgolint.cmd` in `.bin`, not the `.js` the shim is; tsrs itself ships for macOS, Linux (glibc and musl) and Windows. - Run the project's own `vp`: `pnpm exec vp`, the root scripts, or the standalone global CLI from vite.plus, which hands a command to the project's copy. mise's `npm:vite-plus` is a second copy of the whole toolchain. - Turborepo's CI pruning is gone; the Vite Task cache is experimental in CI (Vite+'s docs say so) and is bounded by size instead. - On macOS, Vite Task runs a cached task's system coreutils as uutils' to record what it reads. The tests that probe the host for GNU coreutils check `--version` for `(GNU coreutils)`, and `@cloudpid/sandbox-image`'s `test` is uncached, since its memory-guard tests fail under uutils. Linux is unaffected. diff --git a/docs/development/dependencies.md b/docs/development/dependencies.md index 03af949c..706cd4c6 100644 --- a/docs/development/dependencies.md +++ b/docs/development/dependencies.md @@ -6,7 +6,7 @@ Some dependencies carry a patch (`patches/`) or an exact pin. When upgrading one | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `@cloudflare/vitest-plugin` | `patches/@cloudflare__vitest-plugin@1.5.1.patch` | Keeps the module snapshot it sends a reused worker under workerd's 32 MiB WebSocket message limit, past which the worker dies with `1009 Message is too large` ([cloudflare/workers-sdk#16349](https://github.com/cloudflare/workers-sdk/issues/16349)). Drop it once #16349 is fixed. | | `vite-plus`, `vitest` | exact `1.4.0` (`vite-plus`) in the root `package.json` and `apps/web`; exact `5.0.5` (`vitest`) at the root and in the packages whose test plugins peer it; the `vite` and `vitest` `overrides` in `pnpm-workspace.yaml` (`@voidzero-dev/vite-plus-core@1.4.0`, `5.0.5`) | Vite+ bundles its own Vitest (1.4.0 bundles 5.0.5; 1.5 and later bundle 5.1), so `vite-plus`, the `vite` override and `vitest` move together. Vitest is held below 5.1: under 5.1.0 the workerd pool delays a timer a Durable Object request sets (`setImmediate`, `setTimeout(0)`) until a later request to an object awaits a real timer, so an Effect fiber forked in a request (Effect's scheduler starts it with `setImmediate`) starts late: a Session reports itself idle only at its next request, and `apps/server/src/session/admission.workerd.test.ts` ("Stop waits for it"), `host.workerd.test.ts` and `import.workerd.test.ts` fail. Bisected on its own (5.0.5 with the same workerd, `@cloudflare/vitest-plugin`, Effect and pi-durable delivers them at once); deployed workerd is unaffected. Before lifting it, check that a `setImmediate` set in a `runInDurableObject` callback runs before the next no-op `runInDurableObject` returns, and rerun those three files. | -| `tsrs`, `oxlint-tsgolint` | exact `0.24.0-ts7.1.0-beta` (`tsrs`) in the root `package.json`; `oxlint-tsgolint` overridden to `link:./tools/tsrs-lint-shim` in `pnpm-workspace.yaml` | Vite+'s type-aware lint backend is tsrs's own linter, `tsrs-lint`, through the shim (`tools/tsrs-lint-shim/bin/tsgolint.js`; [ADR-0055](../adr/0055-vite-plus-and-pnpm.md) → Consequences). This `tsrs` is the linter only; the typecheck is `effect-tsgo tsrs`, the tsrs that `@effect/tsgo` ships, whatever this pin says. When upgrading `vite-plus` or `tsrs`, check that `pnpm exec vp lint` on a file with a type error and a floating promise still reports both (`typescript(TS2322)`, `no-floating-promises`): a Vite+ that looks for its backend elsewhere fails with `Error running tsgolint`, and a tsrs that speaks a newer tsgolint protocol than Vite+'s oxlint may not be understood. Drop both, and `tsrs` from the root, once `effect-tsgo --tsrs-lint vp lint` runs (`@effect/tsgo` 0.68 and later, with oxlint 1.91 or later). | +| `tsrs`, `oxlint-tsgolint` | exact `0.24.0-ts7.1.0-beta` (`tsrs`) in the root `package.json` (0.25 was under pnpm's day-old minimum release age when it was pinned); `oxlint-tsgolint` overridden to `link:./tools/tsrs-lint-shim` in `pnpm-workspace.yaml` | Vite+'s type-aware lint backend is tsrs's own linter, `tsrs-lint`, through the shim (`tools/tsrs-lint-shim/bin/tsgolint.js`; [ADR-0055](../adr/0055-vite-plus-and-pnpm.md) → Consequences). This `tsrs` is the linter only; the typecheck is `effect-tsgo tsrs`, the tsrs that `@effect/tsgo` ships, whatever this pin says. When upgrading `vite-plus` or `tsrs`, check that `pnpm exec vp lint` on a file with a type error and a floating promise still reports both (`typescript(TS2322)`, `no-floating-promises`): a Vite+ that looks for its backend elsewhere fails with `Error running tsgolint`, and a tsrs that speaks a newer tsgolint protocol than Vite+'s oxlint may not be understood. It does not run on Windows, where Vite+ looks for `tsgolint.exe` or `.cmd` instead. Drop the override, the shim and `tsrs` once `effect-tsgo --tsrs-lint vp lint` runs (`@effect/tsgo` 0.68 and later, with oxlint 1.91 or later). | | `ws` | exact `8.22.1`, an `overrides` entry in `pnpm-workspace.yaml` | One `ws` for every package: `@earendil-works/chord` pins `8.21.0` and the rest resolve 8.22, and each `ws` is a peer variant of `alchemy`, whose two copies then fail `infra`'s typecheck (a union of two `AlchemyContext`s). Drop it once chord allows 8.22, or move it with the newest `ws` chord allows. | | `@cloudflare/computer` | `patches/@cloudflare__computer@0.9.0.patch` | Adds `Workspace.remount()`, which `updateSkills` runs: computer checks a mount's version only at a Workspace's first index ([`../architecture/workspace.md`](../architecture/workspace.md) → _The Skill set_). Drop it once computer can index a mount again; rerun `apps/server/src/workspace/skills.workerd.test.ts` either way. Also update the `bash` routing lists if the Worker Shell changed ([`workers.md`](workers.md) → _The Workspace DO_). | | `@cloudflare/computer`, computerd | read for the file-change signal | The file-change signal ([`../architecture/container.md`](../architecture/container.md) → _File-change signals_) reads computer's change-log tables (`apps/server/src/workspace/change-log.ts`) and span names (`notify.ts`), and needs computerd's `setxattr` on its mount to stay a no-op the kernel reports. When upgrading either, rerun `src/workspace/notify.workerd.test.ts` and `notify.test.ts`, and recheck by hand as that section's _Limits_ says. | diff --git a/tools/tsrs-lint-shim/bin/tsgolint.js b/tools/tsrs-lint-shim/bin/tsgolint.js index d819f238..b38d8a97 100755 --- a/tools/tsrs-lint-shim/bin/tsgolint.js +++ b/tools/tsrs-lint-shim/bin/tsgolint.js @@ -6,12 +6,14 @@ // workspace package declares `oxlint-tsgolint`, which would take its place). It has no `package.json` on purpose: // `effect-tsgo patch` (the root `prepare`) looks for Vite+'s `oxlint-tsgolint` by its `package.json`, and would then fail // the install looking for tsgolint's platform binary, which this replaces. +import { readFileSync } from "node:fs"; import { createRequire } from "node:module"; import { dirname, join } from "node:path"; import { pathToFileURL } from "node:url"; -// `tsrs`'s `tsrs-lint` command (its `bin/tsrs-lint`) loads this launcher, which reads `process.argv` from its third -// entry on, as this script's are. -const tsrs = dirname(createRequire(import.meta.url).resolve("tsrs/package.json")); +// The `tsrs` package's `tsrs-lint` command, by its `bin` entry, run in this process: it reads `process.argv` from its +// third entry on, as this script's are. +const manifest = createRequire(import.meta.url).resolve("tsrs/package.json"); +const { bin } = JSON.parse(readFileSync(manifest, "utf8")); -await import(pathToFileURL(join(tsrs, "lib", "tsrs-lint.js")).href); +await import(pathToFileURL(join(dirname(manifest), bin["tsrs-lint"])).href);