perf(ci): use tsrs and reduce PE acceptance startup (#5795)

Use pinned tsrs on supported development hosts while retaining stable official
TypeScript on Windows and unsupported platforms. Partition compile/typecheck
caches by actual compiler and qualify fallback hosts for compiler inputs and
lifecycle hooks.

Reduce PE acceptance startup through the existing bounded compiled CLI. Retain
upstream named MCP definitions, every fixture/assertion and the original 30s
deadline. Verify that browser transport loss preserves the observed target.

Validation: full qualification and real host lanes in
https://github.com/morluto/rea/actions/runs/39590450889 ; 450 focused regressions
passed with two documented conditional skips. All 1724 production emit files
match SHA-256 and size across both compilers. Current-head Codex/Greptile review
found no actionable issues. Measurements and limitations are in the PR.

Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
This commit is contained in:
gensokyo-dev authored and GitHub committed 2026-10-21 19:47:52 +08:00
1 parent 33f912919d
commit 905cbaf239
22 files changed
+837 -46

No files matched your search

+6
View File
@@ -819,6 +819,11 @@ jobs:
with:
save: "true"
- run: npm ci
- name: Typecheck with the official Windows compiler
env:
GOMAXPROCS: "2"
GOMEMLIMIT: "3GiB"
run: npm run typecheck -- --checkers 2
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: rea-build-cache
@@ -849,6 +854,7 @@ jobs:
npx vitest run --coverage.enabled=false
src/process/capture/FilesystemSnapshot.test.ts
tests/process-global/filesystemSnapshotFallbackCancellation.test.ts
tests/boundary/filesystem/typescriptCompiler.test.ts
tests/boundary/filesystem/binaryTarget.test.ts
tests/boundary/filesystem/safeOutputTree.test.ts
tests/boundary/providers/native/artifactProvider.archiveSafety.test.ts
+28 -2
View File
@@ -46,6 +46,24 @@ without executing tests or building. A missing Git base reports how to fetch
it or select another revision.
Source typechecking needs no compiled runtime or generated test metadata.
Typecheck, runtime compilation, and Frida binding verification share
`scripts/run-typescript.mjs`. The pinned tsrs package supplies Linux x64/arm64
(GNU and musl) and macOS arm64 compilers. Windows and other unsupported hosts
retain the existing stable official TypeScript compiler. Its upstream version
can differ from tsrs, so both compiler tasks hash the selected package and version
through `scripts/run-turbo.mjs` before cache lookup. Outputs from different
compilers occupy different cache entries. Repository npm scripts and focused-test
preparation use that entrypoint; a raw Turbo compiler task without matching
identity fails instead of publishing an ambiguous successful cache entry.
A missing binary on a supported host also fails without silently falling back.
The Rust compiler defaults to at most two checker threads. For `--noEmit` checks,
`--maxMemory 3G` also sets a soft memory target; emit builds do not use that target.
Explicit compiler arguments can override the defaults. These controls do not
impose a process-family memory limit. Termux's explicit build, Stryker's compiler
API dependency, and independent fixture compiler oracles keep their existing
TypeScript versions.
`npm run build:cached` compiles the CLI/MCP runtime and its packaged skill.
Turbo's strict task environment preserves caller-selected `GOMAXPROCS`,
`GOMEMLIMIT`, and `UV_THREADPOOL_SIZE` for resource-constrained builds and
@@ -233,6 +251,11 @@ and retain representative compiled CLI parity checks. Every distinct source
scenario still runs through the public workflow; session-lifecycle scenarios
need their own sessions and cleanup assertions.
When a matrix already holds a named tool definition from live `tools/list`,
pass that definition through the SDK's `toolDefinition` call option. This keeps
the selected output-schema validation without eagerly compiling unrelated
catalog schemas. Re-read definitions if the server advertises a changed list.
Report unavailable authority as a named skip. Await owned cleanup before a
verifier reports success. Native process inspectors are released at Vitest
worker teardown; fork termination does not run Node exit hooks, and per-file
@@ -648,8 +671,11 @@ missing entries are omitted as whole entries, and consumers rebuild cache misses
including when every entry is unavailable. Malformed plans, non-file entries,
and I/O errors other than disappearance still fail publication. After a trusted
static run, superseded cross-run Turbo snapshots for that OS and architecture
are deleted down to the two newest generations. The Windows lane relies on the Linux static job for typechecking. They retain the normal build and prepack
commands, which restore matching outputs or rebuild on a cache miss. Native
are deleted down to the two newest generations. The Windows lane also runs the
official compiler's complete source typecheck with two checker threads,
independently of the accelerated Linux checker. Both lanes retain the normal
build and prepack commands, which restore matching outputs or rebuild on a cache
miss. Native
artifacts, dependency installs, package archives, and runtime verification remain
host-local. Keep platform-dependent outputs out of this shared cache.
+31 -1
View File
@@ -2,7 +2,7 @@ REA npm dependency inventory
Prepared from the root package-lock.json; refresh this inventory when locked dependencies change.
License identifiers are upstream lockfile declarations, not a legal assessment.
Runtime includes transitive and optional platform packages; development includes build, test and website tooling.
Locked package entries: 752; runtime: 180.
Locked package entries: 758; runtime: 180.
Full runtime copyright/license/NOTICE texts: npm-runtime-notices.txt.
@algolia/[email protected] | development | MIT
@@ -1390,6 +1390,31 @@ [email protected] | runtime | MIT
Package: https://www.npmjs.com/package/@toon-format/toon/v/2.3.1
Archive: https://registry.npmjs.org/@toon-format/toon/-/toon-2.3.1.tgz
Integrity: sha512-sWqEMeAJGMda9qRrfPKrX3C4c33CO9SJuvJzzrcBEn5sbDB+k6pSLkDsfN0rVnLQwR97MV3sDgVbcxQNsq8xVw==
@tsrs/[email protected] | development, optional | Apache-2.0
Lockfile path: node_modules/@tsrs/darwin-arm64
Package: https://www.npmjs.com/package/@tsrs/darwin-arm64/v/0.18.0-ts7.1.0-dev.20260929
Archive: https://registry.npmjs.org/@tsrs/darwin-arm64/-/darwin-arm64-0.18.0-ts7.1.0-dev.20260929.tgz
Integrity: sha512-sAirMpaGA9uRQm2W+t4zC7PjnijNuFa4PCSIfLKKo0JyAUCRfnMeev0UGBQ9F3g+9Nz187tvikUs5Irh5+eajA==
@tsrs/[email protected] | development, optional | Apache-2.0
Lockfile path: node_modules/@tsrs/linux-arm64-gnu
Package: https://www.npmjs.com/package/@tsrs/linux-arm64-gnu/v/0.18.0-ts7.1.0-dev.20260929
Archive: https://registry.npmjs.org/@tsrs/linux-arm64-gnu/-/linux-arm64-gnu-0.18.0-ts7.1.0-dev.20260929.tgz
Integrity: sha512-zm9/z9yylig68JiZF4Aq0Cm26n09KEU8YoQRlG7tdDWTBNAIViYw8knxnWYsjMWVZ2XiU4mYq1xdrOKuOgABHg==
@tsrs/[email protected] | development, optional | Apache-2.0
Lockfile path: node_modules/@tsrs/linux-arm64-musl
Package: https://www.npmjs.com/package/@tsrs/linux-arm64-musl/v/0.18.0-ts7.1.0-dev.20260929
Archive: https://registry.npmjs.org/@tsrs/linux-arm64-musl/-/linux-arm64-musl-0.18.0-ts7.1.0-dev.20260929.tgz
Integrity: sha512-Lw7VVU/YQ9JcarODICEiwzMLdFqZprqh5RGTgbS5Uc6I95P635/g5xA1pOC8RVs4efBvAR30J54iDG3l5JEYiw==
@tsrs/[email protected] | development, optional | Apache-2.0
Lockfile path: node_modules/@tsrs/linux-x64-gnu
Package: https://www.npmjs.com/package/@tsrs/linux-x64-gnu/v/0.18.0-ts7.1.0-dev.20260929
Archive: https://registry.npmjs.org/@tsrs/linux-x64-gnu/-/linux-x64-gnu-0.18.0-ts7.1.0-dev.20260929.tgz
Integrity: sha512-EdBwBgNICGu1r1h23ixdcKwsMo6E9ll7ZsY3mNERNYqE1Pwdtcat99d5E7zB1J+oy/Xk6YqiizaB6nolIjpDTw==
@tsrs/[email protected] | development, optional | Apache-2.0
Lockfile path: node_modules/@tsrs/linux-x64-musl
Package: https://www.npmjs.com/package/@tsrs/linux-x64-musl/v/0.18.0-ts7.1.0-dev.20260929
Archive: https://registry.npmjs.org/@tsrs/linux-x64-musl/-/linux-x64-musl-0.18.0-ts7.1.0-dev.20260929.tgz
Integrity: sha512-LHk+AOAtXuTlhJhOJ2+elriEIX17ycXljojeNxrrzckOipTG1LksoVWuCSas2nu00EnWAzrdKpt9oqPylUKZfQ==
@turbo/[email protected] | development, optional | MIT
Lockfile path: node_modules/@turbo/darwin-64
Package: https://www.npmjs.com/package/@turbo/darwin-64/v/2.11.7
@@ -3400,6 +3425,11 @@ [email protected] | development | 0BSD
Package: https://www.npmjs.com/package/tslib/v/2.8.1
Archive: https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz
Integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
[email protected] | development | Apache-2.0
Lockfile path: node_modules/tsrs
Package: https://www.npmjs.com/package/tsrs/v/0.18.0-ts7.1.0-dev.20260929
Archive: https://registry.npmjs.org/tsrs/-/tsrs-0.18.0-ts7.1.0-dev.20260929.tgz
Integrity: sha512-9T0b4Uam/yMFIK16GUx0fUrJqYZnJ/gvSmV9JB8NTyDePvwCI45WFWxyEV/UMV3KfdNRJG/PBsm3fSIB9WmWsA==
[email protected] | development | MIT
Lockfile path: node_modules/tsx
Package: https://www.npmjs.com/package/tsx/v/4.23.15
+118
View File
@@ -74,6 +74,7 @@
"oxfmt": "0.72.0",
"oxlint": "1.87.0",
"rolldown": "1.2.12",
"tsrs": "0.18.0-ts7.1.0-dev.20260929",
"tsx": "4.23.15",
"turbo": "2.11.7",
"typescript": "7.0.2",
@@ -4407,6 +4408,103 @@
"integrity": "sha512-sWqEMeAJGMda9qRrfPKrX3C4c33CO9SJuvJzzrcBEn5sbDB+k6pSLkDsfN0rVnLQwR97MV3sDgVbcxQNsq8xVw==",
"license": "MIT"
},
"node_modules/@tsrs/darwin-arm64": {
"version": "0.18.0-ts7.1.0-dev.20260929",
"resolved": "https://registry.npmjs.org/@tsrs/darwin-arm64/-/darwin-arm64-0.18.0-ts7.1.0-dev.20260929.tgz",
"integrity": "sha512-sAirMpaGA9uRQm2W+t4zC7PjnijNuFa4PCSIfLKKo0JyAUCRfnMeev0UGBQ9F3g+9Nz187tvikUs5Irh5+eajA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@tsrs/linux-arm64-gnu": {
"version": "0.18.0-ts7.1.0-dev.20260929",
"resolved": "https://registry.npmjs.org/@tsrs/linux-arm64-gnu/-/linux-arm64-gnu-0.18.0-ts7.1.0-dev.20260929.tgz",
"integrity": "sha512-zm9/z9yylig68JiZF4Aq0Cm26n09KEU8YoQRlG7tdDWTBNAIViYw8knxnWYsjMWVZ2XiU4mYq1xdrOKuOgABHg==",
"cpu": [
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@tsrs/linux-arm64-musl": {
"version": "0.18.0-ts7.1.0-dev.20260929",
"resolved": "https://registry.npmjs.org/@tsrs/linux-arm64-musl/-/linux-arm64-musl-0.18.0-ts7.1.0-dev.20260929.tgz",
"integrity": "sha512-Lw7VVU/YQ9JcarODICEiwzMLdFqZprqh5RGTgbS5Uc6I95P635/g5xA1pOC8RVs4efBvAR30J54iDG3l5JEYiw==",
"cpu": [
"arm64"
],
"dev": true,
"libc": [
"musl"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@tsrs/linux-x64-gnu": {
"version": "0.18.0-ts7.1.0-dev.20260929",
"resolved": "https://registry.npmjs.org/@tsrs/linux-x64-gnu/-/linux-x64-gnu-0.18.0-ts7.1.0-dev.20260929.tgz",
"integrity": "sha512-EdBwBgNICGu1r1h23ixdcKwsMo6E9ll7ZsY3mNERNYqE1Pwdtcat99d5E7zB1J+oy/Xk6YqiizaB6nolIjpDTw==",
"cpu": [
"x64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@tsrs/linux-x64-musl": {
"version": "0.18.0-ts7.1.0-dev.20260929",
"resolved": "https://registry.npmjs.org/@tsrs/linux-x64-musl/-/linux-x64-musl-0.18.0-ts7.1.0-dev.20260929.tgz",
"integrity": "sha512-LHk+AOAtXuTlhJhOJ2+elriEIX17ycXljojeNxrrzckOipTG1LksoVWuCSas2nu00EnWAzrdKpt9oqPylUKZfQ==",
"cpu": [
"x64"
],
"dev": true,
"libc": [
"musl"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@turbo/darwin-64": {
"version": "2.11.7",
"resolved": "https://registry.npmjs.org/@turbo/darwin-64/-/darwin-64-2.11.7.tgz",
@@ -9832,6 +9930,26 @@
"dev": true,
"license": "0BSD"
},
"node_modules/tsrs": {
"version": "0.18.0-ts7.1.0-dev.20260929",
"resolved": "https://registry.npmjs.org/tsrs/-/tsrs-0.18.0-ts7.1.0-dev.20260929.tgz",
"integrity": "sha512-9T0b4Uam/yMFIK16GUx0fUrJqYZnJ/gvSmV9JB8NTyDePvwCI45WFWxyEV/UMV3KfdNRJG/PBsm3fSIB9WmWsA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsrs": "bin/tsrs"
},
"engines": {
"node": ">=16.20.0"
},
"optionalDependencies": {
"@tsrs/darwin-arm64": "0.18.0-ts7.1.0-dev.20260929",
"@tsrs/linux-arm64-gnu": "0.18.0-ts7.1.0-dev.20260929",
"@tsrs/linux-arm64-musl": "0.18.0-ts7.1.0-dev.20260929",
"@tsrs/linux-x64-gnu": "0.18.0-ts7.1.0-dev.20260929",
"@tsrs/linux-x64-musl": "0.18.0-ts7.1.0-dev.20260929"
}
},
"node_modules/tsx": {
"version": "4.23.15",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz",
+22 -21
View File
@@ -104,31 +104,31 @@
"metadata:generate": "node scripts/run-exclusive.mjs artifacts node scripts/generate-package-metadata.mjs",
"metadata:check": "node scripts/generate-package-metadata.mjs --check",
"mcp-registry:check": "node scripts/verify-mcp-registry-metadata.mjs",
"mcp-catalog:generate": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:mcp-catalog",
"mcp-catalog:check": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run mcp-catalog:check:built",
"mcp-catalog:generate": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:mcp-catalog",
"mcp-catalog:check": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run mcp-catalog:check:built",
"prebuild": "npm run deps:check",
"build": "node scripts/run-exclusive.mjs artifacts turbo run artifacts:skills --force",
"build": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:skills --force",
"precheck": "npm run deps:check",
"check": "node scripts/run-exclusive.mjs artifacts turbo run typecheck lint:built format:check knip metadata:check && npm run verify:architecture-guards",
"check": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check && npm run verify:architecture-guards",
"precheck:fast": "npm run deps:check",
"check:fast": "turbo run typecheck lint --output-logs=errors-only",
"check:fast": "node scripts/run-turbo.mjs run typecheck lint --output-logs=errors-only",
"precheck:changed": "npm run deps:check",
"check:changed": "npm run check:fast && npm run test:changed",
"precheck:test": "npm run deps:check",
"check:test": "node scripts/run-exclusive.mjs artifacts turbo run typecheck lint:built format:check knip metadata:check test:run",
"check:test": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check test:run",
"precheck:pr": "npm run deps:check",
"check:pr": "node scripts/run-exclusive.mjs artifacts turbo run typecheck lint:built format:check knip metadata:check test:run && npm run test:python && npm run docs:check && npm run jscpd && npm run scan:todos",
"check:pr": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check test:run && npm run test:python && npm run docs:check && npm run jscpd && npm run scan:todos",
"precheck:ci": "npm run deps:check",
"precheck:ci:fast": "npm run deps:check",
"precheck:ci:deep": "npm run deps:check",
"check:ci": "npm run check:ci:fast && npm run check:ci:deep",
"check:ci:fast": "node scripts/run-exclusive.mjs artifacts npm run check:ci:fast:tasks",
"check:ci:fast:tasks": "turbo run typecheck lint:built format:check",
"check:ci:fast:tasks": "node scripts/run-turbo.mjs run typecheck lint:built format:check",
"check:ci:deep": "node scripts/run-exclusive.mjs artifacts npm run check:ci:deep:tasks && npm run verify:architecture-guards && npm run verify:test-discovery && npm run test:python",
"check:ci:deep:tasks": "turbo run knip metadata:check jscpd scan:todos",
"check:ci:tasks": "turbo run typecheck lint:built format:check knip metadata:check jscpd scan:todos",
"check:ci:deep:tasks": "node scripts/run-turbo.mjs run knip metadata:check jscpd scan:todos",
"check:ci:tasks": "node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check jscpd scan:todos",
"ci:static-context": "node scripts/ci/static-task-context.mjs",
"build:cached": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:skills",
"build:cached": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:skills",
"build:termux": "node scripts/run-exclusive.mjs artifacts npm run build:termux:run",
"build:termux:run": "npm run compile:termux && npm run artifacts:skills",
"format": "oxfmt .",
@@ -151,7 +151,7 @@
"test:built": "node scripts/ci/test-group.mjs built",
"pretest:boundary": "npm run test:prepare",
"test:boundary": "vitest run --project boundary --project cli-boundary --project process-boundary --project mcp-boundary --project process-global",
"pretest:mcp": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:skills artifacts:mcp-catalog",
"pretest:mcp": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:skills artifacts:mcp-catalog",
"test:mcp": "vitest run --project mcp-boundary",
"pretest:acceptance": "npm run build:cached",
"test:acceptance": "vitest run --project acceptance",
@@ -174,7 +174,7 @@
"test:watch": "vitest --project domain --project services --project adapters --project composition --project conformance --project evaluation --changed",
"pretest:watch:all": "npm run test:prepare",
"test:watch:all": "vitest --changed",
"typecheck": "tsc --noEmit",
"typecheck": "node scripts/run-typescript.mjs --noEmit",
"verify:test-temp-hygiene": "npm run test:prepare && node scripts/verify-test-temp-hygiene.mjs",
"verify:hopper": "npm run verify:fixtures && npm run build:cached && node scripts/verify-real-hopper.mjs",
"verify:hopper:deadlines": "npm run verify:fixtures && npm run build:cached && node scripts/verify-real-hopper-deadlines.mjs",
@@ -213,7 +213,7 @@
"verify:ghidra:windows": "npm run build:cached && npm run build:ghidra-windows-fixture && node scripts/verify-real-ghidra-windows.mjs",
"verify:browser": "npm run build:cached && node scripts/verify-real-browser.mjs",
"verify:frida": "npm run build:cached && node scripts/verify-frida.mjs",
"verify:frida:bindings": "tsc --noEmit -p tsconfig.frida-verification.json",
"verify:frida:bindings": "node scripts/run-typescript.mjs --noEmit -p tsconfig.frida-verification.json",
"verify:browser:dom": "node scripts/verify-browser-dom-destinations.mjs",
"verify:browser:network": "npm run build:cached && node scripts/verify-browser-network.mjs",
"verify:electron": "npm run build:cached && node scripts/verify-real-electron.mjs",
@@ -256,17 +256,17 @@
"probe:windows-capabilities": "npm run build:cached && node scripts/windows-capabilities.mjs",
"verify:published": "node scripts/verify-published-package.mjs",
"config:print": "node scripts/print-mcp-config.mjs",
"evidence:generate": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:managed-evidence",
"evidence:check": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run evidence:check:built",
"evidence:generate": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:managed-evidence",
"evidence:check": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run evidence:check:built",
"predocs:dev": "npm run docs:generate",
"docs:dev": "vitepress dev docs",
"predocs:build": "npm run docs:generate",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs",
"docs:generate": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts npm run docs:prepare",
"docs:check": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run docs:check:built && npm run test:local -- tests/conformance/readmeConsistency.test.ts",
"docs:check": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run docs:check:built && npm run test:local -- tests/conformance/readmeConsistency.test.ts",
"docs:check:built": "node scripts/generate-package-metadata.mjs --check && node scripts/generate-skill-metadata.mjs --check && node scripts/generate-product-catalog.mjs --check && node scripts/generate-completion-ledger.mjs --check && node scripts/check-doc-facts.mjs && node scripts/generate-error-schema.mjs --check && npm run licenses:check",
"docs:error-schema": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:error-schema",
"docs:error-schema": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:error-schema",
"prepack": "node scripts/prepack.mjs",
"prepare": "node scripts/prepare.mjs",
"verify:asset-catalog": "npm run build:cached && node scripts/verify/apple/asset-catalog.mjs",
@@ -305,16 +305,16 @@
"verify:solidity:metadata": "npm run build:cached && node scripts/verify-solidity-metadata.mjs",
"verify:recorded:crash": "npm run build:cached && node scripts/verify-recorded-crash.mjs",
"mcp-catalog:check:built": "node scripts/generate-mcp-tool-catalog.mjs --check",
"compile": "node scripts/clean-build-output.mjs && tsc -p tsconfig.build.json && node scripts/record-catalog-digests.mjs && node scripts/bundle-runtime.mjs",
"compile": "node scripts/clean-build-output.mjs && node scripts/run-typescript.mjs -p tsconfig.build.json && node scripts/record-catalog-digests.mjs && node scripts/bundle-runtime.mjs",
"compile:termux": "node scripts/clean-build-output.mjs && node --max-old-space-size=3072 node_modules/typescript-termux/lib/tsc.js -p tsconfig.build.json && node scripts/record-catalog-digests.mjs && node scripts/bundle-runtime.mjs",
"artifacts:mcp-catalog": "node scripts/generate-mcp-tool-catalog.mjs",
"artifacts:skills": "node scripts/generate-skill-metadata.mjs",
"artifacts:product-catalog": "node scripts/generate-product-catalog.mjs",
"artifacts:managed-evidence": "node scripts/generate-completion-ledger.mjs",
"artifacts:error-schema": "node scripts/generate-error-schema.mjs",
"test:prepare": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:mcp-catalog artifacts:product-catalog artifacts:managed-evidence",
"test:prepare": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:mcp-catalog artifacts:product-catalog artifacts:managed-evidence",
"evidence:check:built": "node scripts/generate-completion-ledger.mjs --check",
"docs:prepare": "node scripts/generate-package-metadata.mjs && turbo run artifacts:product-catalog artifacts:managed-evidence artifacts:error-schema",
"docs:prepare": "node scripts/generate-package-metadata.mjs && node scripts/run-turbo.mjs run artifacts:product-catalog artifacts:managed-evidence artifacts:error-schema",
"verify:web:qlog": "npm run build:cached && node scripts/verify-qlog-captures.mjs",
"licenses:generate": "node scripts/generate-third-party-inventory.mjs",
"licenses:check": "node scripts/generate-third-party-inventory.mjs --check"
@@ -396,6 +396,7 @@
"oxfmt": "0.72.0",
"oxlint": "1.87.0",
"rolldown": "1.2.12",
"tsrs": "0.18.0-ts7.1.0-dev.20260929",
"tsx": "4.23.15",
"turbo": "2.11.7",
"typescript": "7.0.2",
+25
View File
@@ -63,6 +63,31 @@ function classifyPackage(base, head) {
const after = JSON.parse(git("show", `${head}:package.json`));
const { scripts: beforeScripts, ...beforeRest } = before;
const { scripts: afterScripts, ...afterRest } = after;
const compilerDependencies = (metadata) => ({
dependencies: {
typescript: metadata.dependencies?.typescript,
tsrs: metadata.dependencies?.tsrs,
},
devDependencies: {
typescript: metadata.devDependencies?.typescript,
tsrs: metadata.devDependencies?.tsrs,
},
});
const compilerScripts = [
"compile",
"typecheck",
"build",
"build:cached",
"test:prepare",
"docs:prepare",
"verify:frida:bindings",
].flatMap((name) => [name, `pre${name}`, `post${name}`]);
selected.package ||=
JSON.stringify(compilerDependencies(before)) !==
JSON.stringify(compilerDependencies(after)) ||
compilerScripts.some(
(name) => beforeScripts?.[name] !== afterScripts?.[name],
);
if (JSON.stringify(beforeRest) !== JSON.stringify(afterRest)) {
full("Package metadata or dependencies changed");
return;
+12
View File
@@ -92,6 +92,17 @@ export const SCOPES = {
],
// Four-host installed-package matrix and the Windows curated lane.
package: [
// Both host compilers must be exercised when their installation, options,
// or entrypoints change; Linux's accelerated checker cannot stand in for Go.
"scripts/run-typescript.*",
"scripts/run-turbo.mjs",
"turbo.json",
"tsconfig.json",
"tsconfig.build.json",
"tsconfig.frida-verification.json",
"package-lock.json",
".nvmrc",
".npmrc",
".github/actions/publish-mcp/**",
".github/actions/prepare-release-package/**",
".github/workflows/release-recovery.yml",
@@ -135,6 +146,7 @@ export const SCOPES = {
"src/application/DshCordis*.ts",
"src/cli/interactiveSetup.ts",
"src/cli/setupCommands.ts",
"tests/boundary/filesystem/typescriptCompiler.test.ts",
"tests/boundary/filesystem/binaryTarget.test.ts",
"tests/boundary/filesystem/safeOutputTree.test.ts",
"tests/boundary/providers/native/artifactProvider.archiveSafety.test.ts",
+1 -1
View File
@@ -59,7 +59,7 @@ try {
"scripts/run-exclusive.mjs",
"artifacts",
process.execPath,
resolve("node_modules/turbo/bin/turbo"),
resolve("scripts/run-turbo.mjs"),
"run",
...(plan.needsBuild ? ["artifacts:skills"] : []),
...plan.artifactTasks,
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env node
import { createRequire } from "node:module";
import { pathToFileURL } from "node:url";
import { resolveTypeScriptCompiler } from "./run-typescript.mjs";
// Compute the actual host compiler before Turbo hashes or restores its tasks.
process.env.REA_TYPESCRIPT_COMPILER = resolveTypeScriptCompiler().identity;
const require = createRequire(import.meta.url);
await import(pathToFileURL(require.resolve("turbo/bin/turbo")).href);
+11
View File
@@ -0,0 +1,11 @@
export function selectTypeScriptCompiler(
platform: string,
arch: string,
optionalDependencies: Readonly<Record<string, string>>,
): "tsrs" | "typescript";
export function resolveTypeScriptCompiler(): {
readonly name: "tsrs" | "typescript";
readonly identity: string;
readonly launcher: string;
};
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env node
import { readFileSync } from "node:fs";
import { createRequire } from "node:module";
import { availableParallelism } from "node:os";
import { dirname, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
/** Use the pinned package's platform inventory; let its launcher select libc. */
export const selectTypeScriptCompiler = (
platform,
arch,
optionalDependencies,
) => {
if (platform === "win32") return "typescript";
const prefix = `@tsrs/${platform}-${arch}`;
return Object.keys(optionalDependencies).some(
(name) => name === prefix || name.startsWith(`${prefix}-`),
)
? "tsrs"
: "typescript";
};
export const resolveTypeScriptCompiler = () => {
const require = createRequire(import.meta.url);
const rustPackagePath = require.resolve("tsrs/package.json");
const rustPackage = JSON.parse(readFileSync(rustPackagePath, "utf8"));
const compiler = selectTypeScriptCompiler(
process.platform,
process.arch,
rustPackage.optionalDependencies,
);
const packagePath =
compiler === "tsrs"
? rustPackagePath
: require.resolve("typescript/package.json");
const metadata =
compiler === "tsrs"
? rustPackage
: JSON.parse(readFileSync(packagePath, "utf8"));
const command = compiler === "tsrs" ? "tsrs" : "tsc";
return {
name: compiler,
identity: `${compiler}@${metadata.version}`,
launcher: resolve(dirname(packagePath), metadata.bin[command]),
};
};
const main = async () => {
const compiler = resolveTypeScriptCompiler();
if (
process.env.TURBO_HASH !== undefined &&
process.env.REA_TYPESCRIPT_COMPILER !== compiler.identity
)
throw new Error(
"Compiler identity is missing or stale. Run Turbo through scripts/run-turbo.mjs.",
);
if (compiler.name === "tsrs") {
const args = process.argv.slice(2);
// Rust consumes --maxMemory once; duplicating it becomes an unknown option.
// Preserve explicit resource choices rather than injecting another value.
const defaults = [
["--checkers", String(Math.min(2, availableParallelism()))],
["--maxMemory", "3G"],
].flatMap(([option, value]) =>
args.includes(option) ? [] : [option, value],
);
process.argv.splice(2, 0, ...defaults);
}
// Delegate execution, diagnostics, status and signals to the package's launcher.
// An unavailable binary on a supported host must fail rather than hide drift.
await import(pathToFileURL(compiler.launcher).href);
};
if (process.argv[1] === fileURLToPath(import.meta.url)) await main();
+6
View File
@@ -555,6 +555,12 @@ async function verifyPageScopedTransport(provider, proxy, origin) {
throw new Error(
"Page-scoped CDP disconnect must report transport loss without claiming a target crash",
);
const remaining = await provider.listTargets(
listBrowserTargetsInputSchema.parse({ cdp_endpoint: proxy.endpoint }),
);
if (!remaining.ok) throw remaining.error;
if (!remaining.value.targets.some(({ target_id }) => target_id === target))
throw new Error("Page-scoped CDP disconnect removed its live target");
}
async function browserExecutable() {
@@ -5,6 +5,7 @@ import {
createAnalysisExecution,
type AnalysisClient,
type AnalysisProviderCandidate,
type AnalysisProviderInspectionOptions,
type CapabilityDescriptor,
type ProviderAvailability,
type ProviderIdentity,
@@ -825,7 +826,9 @@ it("joins cancelled readiness finalization and shutdown before admitting another
const registry = new AnalysisProviderRegistry([
{
...base,
inspectAvailability: async ({ signal } = {}) => {
inspectAvailability: async ({
signal,
}: AnalysisProviderInspectionOptions = {}) => {
calls++;
if (calls === 1) {
observed = signal;
@@ -982,7 +985,9 @@ it("registers selection before async readiness can race shutdown", async () => {
const registry = new AnalysisProviderRegistry([
{
...base,
inspectAvailability: async ({ signal } = {}) => {
inspectAvailability: async ({
signal,
}: AnalysisProviderInspectionOptions = {}) => {
calls++;
observed = signal;
return base.inspectAvailability();
@@ -9,7 +9,11 @@ import { peResourcesSchema } from "../../../src/domain/native/peResources.js";
import { peResourceFixture } from "../../../src/native/pe/PeResources.fixture.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
import { cliTest, type TestCli } from "../../support/cli/cliFixture.js";
import {
cliTest,
runFileCli,
type TestCli,
} from "../../support/cli/cliFixture.js";
type PeResourceCall = (
arguments_: Record<string, unknown>,
@@ -22,7 +26,7 @@ const expectPeInputFailureAcrossAdapters = async (input: {
readonly reason: "invalid_format" | "invalid_value";
}) => {
const { cli, call, path, reason } = input;
const result = await cli.run({
const result = await runFileCli(cli, {
arguments: ["inspect-pe-resources", path, "--json"],
});
expect(result.exitCode).toBe(1);
@@ -105,7 +109,7 @@ const expectPeWordAlignedRecordsAcrossAdapters = async (input: {
);
const path = join(root, `word-aligned-${plus}-${index}.exe`);
await writeFile(path, fixture.bytes);
const result = await cli.run({
const result = await runFileCli(cli, {
arguments: ["inspect-pe-resources", path, "--json"],
});
expect(result.exitCode, result.stderr).toBe(0);
@@ -196,7 +200,7 @@ const expectPeMappingOwnershipAcrossAdapters = async (
});
continue;
}
const result = await cli.run({
const result = await runFileCli(cli, {
arguments: ["inspect-pe-resources", path, "--json"],
});
expect(result.exitCode, name).toBe(0);
@@ -249,9 +253,14 @@ const expectPeInventoriesAcrossAdapters = async (
`resource${plus ? "64" : "32"}${empty ? "-empty" : ""}.exe`,
);
await writeFile(path, fixture.bytes);
const result = await cli.run({
const invocation = {
arguments: ["inspect-pe-resources", path, "--json"],
});
};
// Keep an independent public-wrapper process for both PE32 and PE32+.
// The empty-payload variants reuse only compiled-command startup.
const result = await (empty
? runFileCli(cli, invocation)
: cli.run(invocation));
expect(result.exitCode).toBe(0);
const evidence = contract.outputSchema.parse(result.json);
const report = peResourcesSchema.parse(evidence.normalized_result);
@@ -660,7 +660,7 @@ it.each([
{
code: true,
runtime: true,
package: false,
package: true,
evm: false,
browser: false,
},
@@ -1155,7 +1155,7 @@ it.each([
{
code: true,
runtime: true,
package: false,
package: true,
browser: false,
evm: false,
sqlite: false,
@@ -1166,7 +1166,7 @@ it.each([
{
code: true,
runtime: true,
package: false,
package: true,
browser: false,
evm: false,
},
@@ -1496,3 +1496,89 @@ it("never runs a manual-only verifier from an automatic workflow", async () => {
),
).toEqual([]);
});
it.each([
"scripts/run-typescript.mjs",
"scripts/run-typescript.d.mts",
"scripts/run-turbo.mjs",
"turbo.json",
"tsconfig.json",
"tsconfig.build.json",
"tsconfig.frida-verification.json",
"package-lock.json",
".nvmrc",
".npmrc",
])("selects package hosts for compiler input %s", async (path) => {
const { directory, base } = await fixture();
const head = await change(directory, [path]);
const plan = await classify(directory, base, head);
expect(plan).toMatchObject({
tier: "fast",
code: true,
runtime: true,
package: true,
});
expect(plan.matrix).toEqual({
include: [
{ os: "ubuntu-latest", platform: "linux", architecture: "x64" },
{ os: "ubuntu-24.04-arm", platform: "linux", architecture: "arm64" },
{ os: "macos-15", platform: "darwin", architecture: "arm64" },
],
});
});
it.each(["typescript", "tsrs"])(
"selects fallback host checks when compiler dependency %s changes",
async (name) => {
const { directory } = await fixture();
const before = { name: "fixture", devDependencies: { [name]: "1.0.0" } };
const base = await change(
directory,
["package.json"],
JSON.stringify(before),
);
const head = await change(
directory,
["package.json"],
JSON.stringify({ ...before, devDependencies: { [name]: "2.0.0" } }),
);
expect(await classify(directory, base, head)).toMatchObject({
code: true,
runtime: true,
package: true,
});
},
);
it.each([
"compile",
"typecheck",
"build",
"build:cached",
"test:prepare",
"docs:prepare",
"verify:frida:bindings",
"prebuild:cached",
"postcompile",
"pretypecheck",
])(
"selects fallback host checks when compiler command %s changes",
async (name) => {
const { directory } = await fixture();
const base = await change(
directory,
["package.json"],
JSON.stringify({ scripts: { [name]: "node scripts/old.mjs" } }),
);
const head = await change(
directory,
["package.json"],
JSON.stringify({ scripts: { [name]: "node scripts/new.mjs" } }),
);
expect(await classify(directory, base, head)).toMatchObject({
code: true,
runtime: true,
package: true,
});
},
);
@@ -364,7 +364,7 @@ it("runs the existing onboarding and Python producer guards from their selected
"node scripts/run-exclusive.mjs artifacts npm run check:ci:fast:tasks",
);
expect(scripts["check:ci:fast:tasks"]).toBe(
"turbo run typecheck lint:built format:check",
"node scripts/run-turbo.mjs run typecheck lint:built format:check",
);
expect(scripts["test:python"]).toContain(
"bridge/native/test_rea_lldb_tracer.py",
@@ -196,6 +196,8 @@ const createBuildCacheFixture = async (): Promise<string> => {
"tsconfig.json",
"tsconfig.build.json",
"scripts/check-dependency-install.mjs",
"scripts/run-turbo.mjs",
"scripts/run-typescript.mjs",
"scripts/run-exclusive.mjs",
"scripts/run-exclusive-command.mjs",
"scripts/lib/windows-owned-command.mjs",
@@ -277,7 +279,7 @@ const runTurbo = (cwd: string, environment: NodeJS.ProcessEnv = process.env) =>
run(
process.execPath,
[
join(cwd, "node_modules", "turbo", "bin", "turbo"),
join(cwd, "scripts", "run-turbo.mjs"),
"run",
"artifacts:skills",
"--output-logs=full",
@@ -1,6 +1,7 @@
import { spawnSync } from "node:child_process";
import { createRequire } from "node:module";
import { mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, it } from "vitest";
@@ -8,9 +9,10 @@ import { z } from "zod";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { workflowGit } from "../../support/workflowGit.js";
import { resolveTypeScriptCompiler } from "../../../scripts/run-typescript.mjs";
const repository = fileURLToPath(new URL("../../../", import.meta.url));
const turbo = join(repository, "node_modules/turbo/bin/turbo");
const turbo = join(repository, "scripts/run-turbo.mjs");
const reportScript = join(repository, "scripts/ci/static-check-report.mjs");
const rootConfigSchema = z.object({
globalDependencies: z.array(z.string()).optional(),
@@ -349,6 +351,13 @@ it.each([
diagnostic: "TS2322",
invalidatesCompile: false,
},
{
label: "compiler launcher",
path: "scripts/run-typescript.mjs",
content: 'throw new Error("compiler launcher changed");\n',
diagnostic: "compiler launcher changed",
invalidatesCompile: true,
},
{
label: "source declaration",
path: "src/types.d.mts",
@@ -410,11 +419,15 @@ it.each([
["compile", "typecheck"],
{
// Exercise the real compiler phase with the production task inputs.
compile: "tsc -p tsconfig.build.json",
typecheck: "tsc --noEmit",
compile: "node scripts/run-typescript.mjs -p tsconfig.build.json",
typecheck: "node scripts/run-typescript.mjs --noEmit",
},
{ "#compiler-scope": "./scripts/root-types.d.mts" },
);
await writeFile(
join(root, "scripts/run-typescript.mjs"),
await readFile(join(repository, "scripts/run-typescript.mjs")),
);
for (const name of [
"tsconfig.json",
"tsconfig.build.json",
@@ -612,3 +625,125 @@ it("invalidates checker task hashes for Node, ignore, and VitePress config chang
`${task} must ignore vitest.config.ts`,
).toBe(initial.get(task));
});
it.skipIf(resolveTypeScriptCompiler().name !== "tsrs")(
"does not replay an official compiler success for a Rust compiler error",
async () => {
const root = await createTestTempDirectory("rea-cross-compiler-cache-");
const cache = await createTestTempDirectory("rea-cross-compiler-store-");
const require = createRequire(import.meta.url);
await mkdir(join(root, "scripts"));
await mkdir(join(root, "src"));
await mkdir(join(root, "node_modules/tsrs"), { recursive: true });
for (const name of ["typescript", "turbo"])
await symlink(
dirname(require.resolve(`${name}/package.json`)),
join(root, "node_modules", name),
"junction",
);
for (const name of ["run-typescript.mjs", "run-turbo.mjs"])
await writeFile(
join(root, "scripts", name),
await readFile(join(repository, "scripts", name)),
);
await writeTaskFixture(root, ["compile", "typecheck"], {
compile: "node scripts/run-typescript.mjs -p tsconfig.build.json",
typecheck: "node scripts/run-typescript.mjs --noEmit",
});
const rustPath = require.resolve("tsrs/package.json");
const rust = z
.object({ version: z.string(), bin: z.object({ tsrs: z.string() }) })
.parse(JSON.parse(await readFile(rustPath, "utf8")));
const writeInventory = (supported: boolean) =>
writeFile(
join(root, "node_modules/tsrs/package.json"),
JSON.stringify({
name: "tsrs",
version: rust.version,
bin: { tsrs: resolve(dirname(rustPath), rust.bin.tsrs) },
optionalDependencies: supported
? { [`@tsrs/${process.platform}-${process.arch}`]: rust.version }
: {},
}),
);
await writeInventory(false);
await writeFile(
join(root, "tsconfig.json"),
JSON.stringify({
compilerOptions: {
strict: true,
rootDir: "src",
types: [],
lib: ["ES2023", "DOM"],
target: "ES2023",
module: "NodeNext",
outDir: "dist",
},
include: ["src/**/*.ts"],
}),
);
await writeFile(
join(root, "tsconfig.build.json"),
'{"extends":"./tsconfig.json"}\n',
);
await writeFile(
join(root, ".gitignore"),
"node_modules/\ndist/\n.cache/\n.turbo/\n",
);
// TS 7.0 accepts this contextual callback; TS 7.1 reports TS7031.
// The source stays identical while only the selected compiler changes.
await writeFile(
join(root, "src/repro.ts"),
[
"interface Options { signal?: AbortSignal }",
"interface Provider { inspect(options?: Options): Promise<void> }",
"declare const base: Provider;",
"const providers: Provider[] = [{ ...base, inspect: async ({ signal } = {}) => {",
" if (signal?.aborted) throw signal.reason;",
"} }];",
].join("\n"),
);
await workflowGit(root, ["init", "--initial-branch=main"]);
await workflowGit(root, ["add", "."]);
await workflowGit(root, ["commit", "-m", "test: seed compiler isolation"]);
const run = (task: string, dryRun = false) =>
execute(
join(root, "scripts/run-turbo.mjs"),
[
"run",
task,
...(dryRun ? ["--dry=json"] : ["--output-logs=errors-only"]),
"--cache=local:rw",
"--cache-dir",
cache,
],
root,
);
const hash = (task: string) => {
const result = run(task, true);
expect(result.status, result.stdout + result.stderr).toBe(0);
const entry = dryRunSchema
.parse(JSON.parse(result.stdout))
.tasks.find((value) => value.taskId === task);
if (entry === undefined) throw new Error(`Missing compiler task ${task}`);
return entry.hash;
};
const hashes = new Map<string, string>();
for (const task of ["compile", "typecheck"]) {
const cold = run(task);
expect(cold.status, cold.stdout + cold.stderr).toBe(0);
hashes.set(task, hash(task));
const warm = run(task);
expect(warm.status, warm.stdout + warm.stderr).toBe(0);
expect(warm.stdout).toMatch(/Cached:\s+1 cached/u);
}
await writeInventory(true);
for (const task of ["compile", "typecheck"]) {
const result = run(task);
expect(result.status, result.stdout + result.stderr).toBeGreaterThan(0);
expect(result.stdout + result.stderr).toContain("TS7031");
expect(result.stdout).toMatch(/Cached:\s+0 cached/u);
expect(hash(task)).not.toBe(hashes.get(task));
}
},
);
@@ -0,0 +1,206 @@
import { spawnSync } from "node:child_process";
import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
import { createRequire } from "node:module";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, it } from "vitest";
import { z } from "zod";
import {
resolveTypeScriptCompiler,
selectTypeScriptCompiler,
} from "../../../scripts/run-typescript.mjs";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const repository = fileURLToPath(new URL("../../../", import.meta.url));
const launcher = join(repository, "scripts/run-typescript.mjs");
const require = createRequire(import.meta.url);
const rustPackage = z
.object({
version: z.string(),
optionalDependencies: z.record(z.string(), z.string()),
})
.parse(
JSON.parse(await readFile(require.resolve("tsrs/package.json"), "utf8")),
);
const officialPackage = z
.object({ version: z.string() })
.parse(
JSON.parse(
await readFile(require.resolve("typescript/package.json"), "utf8"),
),
);
const execute = (script: string, args: string[]) =>
spawnSync(process.execPath, [script, ...args], {
encoding: "utf8",
timeout: 15_000,
env: { ...process.env, TURBO_HASH: undefined },
});
it.each([
["linux", "x64", "tsrs"],
["linux", "arm64", "tsrs"],
["darwin", "arm64", "tsrs"],
["win32", "x64", "typescript"],
["win32", "arm64", "typescript"],
["darwin", "x64", "typescript"],
["android", "arm64", "typescript"],
["linux", "riscv64", "typescript"],
])(
"selects %s/%s compiler %s from the pinned inventory",
(platform, arch, compiler) => {
expect(
selectTypeScriptCompiler(
platform,
arch,
rustPackage.optionalDependencies,
),
).toBe(compiler);
},
);
it("always retains the official compiler on Windows", () => {
expect(
selectTypeScriptCompiler("win32", "x64", { "@tsrs/win32-x64": "future" }),
).toBe("typescript");
});
it("runs the selected installed compiler", () => {
const result = execute(launcher, ["--version"]);
expect(result.error).toBeUndefined();
expect(result.status, result.stderr).toBe(0);
const compiler = selectTypeScriptCompiler(
process.platform,
process.arch,
rustPackage.optionalDependencies,
);
expect(result.stdout).toContain(
compiler === "tsrs"
? `tsrs ${rustPackage.version}`
: `Version ${officialPackage.version}`,
);
});
it("forwards build arguments and preserves real type errors and exit status", async () => {
const root = await createTestTempDirectory("rea-typescript-compiler-");
const input = join(root, "input.ts");
await writeFile(
join(root, "tsconfig.json"),
JSON.stringify({
compilerOptions: {
strict: true,
target: "ES2023",
types: [],
outDir: "output",
},
files: ["input.ts"],
}),
);
await writeFile(input, "export const value: number = 1;\n");
const valid = execute(launcher, ["-p", root, "--pretty", "false"]);
expect(valid.error).toBeUndefined();
expect(valid.status, valid.stdout + valid.stderr).toBe(0);
expect(await readFile(join(root, "output/input.js"), "utf8")).toContain(
"value = 1",
);
const resourceArgs =
resolveTypeScriptCompiler().name === "tsrs"
? ["--checkers", "1", "--maxMemory", "1G"]
: ["--checkers", "1"];
const checked = execute(launcher, ["-p", root, "--noEmit", ...resourceArgs]);
expect(checked.error).toBeUndefined();
expect(checked.status, checked.stdout + checked.stderr).toBe(0);
await writeFile(input, 'export const value: number = "invalid";\n');
const invalid = execute(launcher, [
"-p",
root,
"--noEmit",
"--pretty",
"false",
]);
const direct = execute(resolveTypeScriptCompiler().launcher, [
"-p",
root,
"--noEmit",
"--pretty",
"false",
]);
expect(direct.error).toBeUndefined();
expect(direct.status, direct.stdout + direct.stderr).toBeGreaterThan(0);
expect(direct.stdout + direct.stderr).toContain("TS2322");
expect(invalid.error).toBeUndefined();
expect(invalid.status, invalid.stdout + invalid.stderr).toBe(direct.status);
expect(invalid.stdout + invalid.stderr).toContain("TS2322");
expect(await readFile(join(root, "output/input.js"), "utf8")).toContain(
"value = 1",
);
});
it.skipIf(process.platform === "win32")(
"does not retry failed supported compilers with the official compiler",
async () => {
const root = await createTestTempDirectory("rea-typescript-failure-");
const script = join(root, "run-typescript.mjs");
await copyFile(launcher, script);
for (const name of ["tsrs", "typescript"]) {
const directory = join(root, "node_modules", name);
await mkdir(directory, { recursive: true });
await writeFile(
join(directory, "package.json"),
JSON.stringify({
name,
type: "module",
bin: { [name === "tsrs" ? "tsrs" : "tsc"]: "cli.mjs" },
optionalDependencies: {
[`@tsrs/${process.platform}-${process.arch}`]: "fixture",
},
}),
);
await writeFile(
join(directory, "cli.mjs"),
name === "tsrs"
? 'console.error("supported compiler failed"); process.exitCode = 42;\n'
: 'console.log("unexpected fallback");\n',
);
}
const result = execute(script, ["--noEmit"]);
expect(result.error).toBeUndefined();
expect(result.status, result.stdout + result.stderr).toBe(42);
expect(result.stderr).toContain("supported compiler failed");
expect(result.stdout).not.toContain("unexpected fallback");
// The same selection must expose a missing installed launcher as a failure.
await writeFile(
join(root, "node_modules/tsrs/package.json"),
JSON.stringify({
name: "tsrs",
bin: { tsrs: "missing.mjs" },
optionalDependencies: {
[`@tsrs/${process.platform}-${process.arch}`]: "fixture",
},
}),
);
const missing = execute(script, ["--noEmit"]);
expect(missing.status, missing.stdout + missing.stderr).toBe(1);
expect(missing.stderr).toContain("ERR_MODULE_NOT_FOUND");
expect(missing.stdout).not.toContain("unexpected fallback");
},
);
it.each([undefined, "typescript@stale"])(
"rejects missing or stale compiler identity %s inside a Turbo task",
(identity) => {
const result = spawnSync(process.execPath, [launcher, "--version"], {
encoding: "utf8",
timeout: 15_000,
env: {
...process.env,
TURBO_HASH: "compiler-task",
REA_TYPESCRIPT_COMPILER: identity,
},
});
expect(result.error).toBeUndefined();
expect(result.status, result.stdout + result.stderr).toBe(1);
expect(result.stderr).toContain("Compiler identity is missing or stale");
},
);
@@ -12,6 +12,7 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import {
createAnalysisExecution,
type AnalysisProviderCandidate,
type AnalysisProviderInspectionOptions,
type CapabilityDescriptor,
type ProviderIdentity,
} from "../../../src/application/AnalysisProvider.js";
@@ -411,7 +412,9 @@ it.each(["ready", "cancelled", "physical"] as const)(
new AnalysisProviderRegistry([
{
...base,
inspectAvailability: async ({ signal } = {}) => {
inspectAvailability: async ({
signal,
}: AnalysisProviderInspectionOptions = {}) => {
enter();
await gate;
if (mode === "physical")
@@ -136,3 +136,16 @@ it("keeps every explicit focused CI test path executable after file moves", asyn
);
expect(missing.filter((path) => path !== undefined)).toEqual([]);
}, 10_000);
it("checks the complete source with the fallback compiler before Windows build reuse", async () => {
const workflow = workflowSchema.parse(
parse(await readFile(WORKFLOW, "utf8")),
);
const steps = workflow.jobs["windows-curated"]?.steps ?? [];
const checked = steps.findIndex(
(step) => step.run === "npm run typecheck -- --checkers 2",
);
const built = steps.findIndex((step) => step.run === "npm run build:cached");
expect(checked).toBeGreaterThan(-1);
expect(built).toBeGreaterThan(checked);
});
+14 -3
View File
@@ -3,13 +3,20 @@
"cacheMaxAge": "7d",
"cacheMaxSize": "500MB",
"globalDependencies": [".nvmrc", ".npmrc"],
"globalPassThroughEnv": ["GOMAXPROCS", "GOMEMLIMIT", "UV_THREADPOOL_SIZE"],
"globalPassThroughEnv": [
"GOMAXPROCS",
"GOMEMLIMIT",
"UV_THREADPOOL_SIZE",
"REA_TYPESCRIPT_COMPILER"
],
"tasks": {
"compile": {
"dependsOn": ["metadata:check"],
"inputs": [
"package.json",
"package-lock.json",
"scripts/run-turbo.mjs",
"scripts/run-typescript.mjs",
"scripts/check-dependency-install.mjs",
"scripts/clean-build-output.mjs",
"scripts/bundle-runtime.mjs",
@@ -22,12 +29,15 @@
"tsconfig.json",
"tsconfig.build.json"
],
"outputs": ["dist/**"]
"outputs": ["dist/**"],
"env": ["REA_TYPESCRIPT_COMPILER"]
},
"typecheck": {
"inputs": [
"package.json",
"package-lock.json",
"scripts/run-turbo.mjs",
"scripts/run-typescript.mjs",
"src/**/*.{cts,mts,ts,tsx}",
"src/**/package.json",
"tests/**/*.{cts,mts,ts,tsx}",
@@ -44,7 +54,8 @@
"!docs/.vitepress/cache/**",
"!docs/.vitepress/dist/**"
],
"outputs": []
"outputs": [],
"env": ["REA_TYPESCRIPT_COMPILER"]
},
"metadata:check": {
"inputs": [