预发布版本规则
默认只选择稳定版;用户显式声明允许时,可以采用匹配的预发布版。
预发布许可只对被声明的工具生效。锁文件推断、版本统计和兼容数据维护仍只处理稳定版。
packageManager: "pnpm@>=10.0.0-rc.1 <10.0.0"
这里允许 pnpm 使用匹配的预发布版;推导 Node 时仍只选稳定版,除非 Node 自己的显式声明也允许预发布版。
不沿父目录查找
inputnodepackageManager
18.20.8 → 单一版本18 → 18.x18.20 →
18.20.x
^18.20 · ~18.20>=18 <21 · *18 || 20
·
18 - 20
名称@范围。
调用方把已有配置转换为 node 和 packageManager 传入。包本身只接收这两个值。
这些来源都与所在目录有关;先读完一层,再进入父目录
startDir
gitRoot
读取 startDir → 父目录 → … → gitRoot,包含两端;不越过 gitRoot。Git worktree 的 .git 文件也属于仓库标记。
目录不属于 Git 仓库时,只读取 startDir 并警告,不向文件系统根目录继续查找。
/repo/packages/web↑/repo/packages↑/repo读完即停
本层 .nvmrc 优先于 父层 volta.node,也优先于
父层 packageManager。同目录、同字段的重复项按出现顺序。
每层只读取一次;如果 startDir 就是 gitRoot,目录队列只有第 0 层。
有锁文件时:查随包的冻结安装兼容表 → 得到可用的包管理器具体版本集合或有证据的范围。
engines.node→得到每个候选兼容的父层条件继续收窄范围;冲突条件及其推导的 Node 要求一起忽略。没有包管理器类型声明时,默认使用 npm。
有 → 采用该版本
是 → 采用当前版本
从官方 Node 发行表中筛选,再取最大值。
有 → 采用该版本
pnpm --version / yarn --version↓ 读取本地命令结果本地安装的具体版本
是 → 采用候选版本
否 / 未安装 → 从官方包版本表中,取满足两者的最大版本
完全没有声明:使用当前进程的 Node 和与它绑定的 npm。“最大版本”:从实时获取、符合预发布规则的候选版本中,按 semver 条件取最大值。锁兼容性来自有证据的冻结安装记录,查看数据来源与维护规范。未知兼容性单独警告,不能当作冲突或通过。
默认只选择稳定版;用户显式声明允许时,可以采用匹配的预发布版。
预发布许可只对被声明的工具生效。锁文件推断、版本统计和兼容数据维护仍只处理稳定版。
packageManager: "pnpm@>=10.0.0-rc.1 <10.0.0"
这里允许 pnpm 使用匹配的预发布版;推导 Node 时仍只选稳定版,除非 Node 自己的显式声明也允许预发布版。
留空表示没有声明。每次修改,结果与警告都会重新计算。
模拟调用这个包的机器。Node 版本可选择,它绑定的 npm 根据官方发行数据自动显示。
主表位于 startDir(第 0 层)。先检查这一层的全部声明,再检查第 1 层、第 2 层,直到 gitRoot。每一层内部才按来源编号排序。
↑ 查看完整目录查找图:起点、每层来源、父目录回路与停止边界
同名且冲突本层 .nvmrc = 18,父层 .nvmrc = 20→ 保留 18;忽略父层的 20 并警告。
同名且兼容本层 .nvmrc = 18,父层 .nvmrc = 18.20.8→ 两条都保留,范围收窄到 18.20.8。
字段不同本层 .nvmrc = 18,父层 volta.node = 20→ 本层更近,保留 18;父层 Volta 被忽略并警告。
规定数据来源、获取方式、维护原则与操作流程,适用于维护人员和 AI。数据分为运行时获取、随包发布与维护仓库保存三类。
已发布版本、每个版本的 engines.node、每个 Node 发行版绑定的 npm。
维护脚本根据实测生成版本范围;infer 使用随包的范围,未知锁格式使用
*。
当前 Node、本地 pnpm / Yarn、项目声明每次调用时读取;属于本次输入,不是随包维护的版本表。当前 Node 来自 process.versions.node;pnpm
/ Yarn 来自本地命令的实际版本。
由脚本下载和解析官方数据;版本与 engines 使用原始声明。
| 数据项 | 原始来源 / 读取字段 | 获取方式 | 维护方式 |
|---|---|---|---|
| Node 已发布版本与 LTS 信息决定哪些 Node 版本可选 |
nodejs.org/dist/index.json ↗[].version · [].lts · [].date
|
运行时
每次 infer() 都请求官方接口校验更新。同一 Node 进程中的后续调用携带 ETag / Last-Modified;返回 304 就复用进程内数据。并发请求同一来源时只发一次。 默认不写磁盘。新进程第一次调用重新获取。同步脚本另外供维护和测试使用,不依靠项目文件缓存官方数据。 |
新增版本:自动处理
重新拉取、检查字段、规范化版本并保存来源与时间。 接口结构变化:维护解析器字段缺失或范围非法时保留原响应并记录异常;不得静默排除异常版本后输出最大版本结论。 发布版本及 engines 不人工填写。 |
| 每个 Node 绑定的 npmnpm 的优先候选 |
同一份 Node 发行索引 ↗[].version → [].npm同一条记录直接关联,不按 Node 主版本猜。
|
||
| npm 版本与 Node 要求 |
registry.npmjs.org/npm ↗versions[v].version
|
||
| pnpm 版本与 Node 要求 |
registry.npmjs.org/pnpm ↗versions[v].version
|
||
| Yarn 历史发行版与 Node 要求 |
registry.npmjs.org/yarn ↗versions[v],包含 Classic 与历史 Berry 发行版
|
||
| Yarn Berry 版本与 Node 要求 |
registry.npmjs.org/@yarnpkg/cli-dist ↗versions[v],其中 v 为 >=2 <6同版本的声明优先级:cli-dist、yarn、cli。保留每条声明的实际来源。
|
||
| 补全 Yarn 历史声明 |
registry.npmjs.org/@yarnpkg/cli ↗versions[v].version · versions[v].engines.node补全 2.1–2.4 等历史版本。此 npm 包没有独立命令,不能直接当作测试用可执行文件。
|
||
| Yarn 官方分发版本 |
repo.yarnpkg.com/tags ↗tags[]合并官方版本列表。注册表中缺少的版本,按官方 tag 查询 packages/yarnpkg-cli/package.json 的
version 与 engines.node;缺失字段保留未知并给出警告。
|
||
| Yarn 6+ 原生版本 |
repo.yarnpkg.com/releases ↗releaseLines.zpm.stable / canary / tags[]原生程序,无宿主 Node 要求。预发布版按用户显式声明的版本或范围查询,不加入稳定版统计。
|
默认使用进程内缓存:数据放在这个包的模块变量中,同一模块实例的多次
infer()
共用;不缓存项目推断结果,不写用户磁盘,不要求调用方持有实例。
infer({ cwd: '/repo/a' })HTTP 200 → 保存官方元数据
同时读取 A 项目的文件,计算 A 的结果。
infer({ cwd: '/repo/b' })条件请求 → 304 则复用数据
读取 B 项目的文件,重新计算 B;若返回 200,则更新元数据。
新进程中的 infer(...)内存已释放 → 重新下载
不同进程 / worker 不共用这份缓存。
缓存键:官方来源 URL + 解析结构版本。缓存里保存响应数据、ETag / Last-Modified、数据获取时间、最近校验时间。没有 HTTP 校验标记的来源,每次重新下载;304 更新校验时间。并发中的失败请求会移出队列,下一次可重试。
每次仍读取该目录的声明和本地工具版本,并重新做优先级与范围计算。项目结果不跨调用缓存;同一进程中不同项目可以复用相同的官方版本事实。
若本进程已有成功响应,可继续使用并警告数据时间;“最大版本”只指这份数据的范围。新进程无缓存且请求失败时,无法核实的数据标为未知。
保留“官方未声明”这个事实;不能写成官方支持任意 Node。它的 Node 兼容性标为未知,不伪造约束。
当前安装绑定的 npm 从该 Node 安装位置核对;选择另一个 Node 发行版时,查官方索引的 npm 字段。不会把任意 PATH 上的 npm 当作绑定版本。
实测检查冻结安装、锁文件和依赖。兼容判定另行应用已确认的上游 bug 例外;测试失败记录始终保留。
pnpm 按待测版本选择冻结参数:早于 3.0.0-alpha.3 时执行
--frozen-shrinkwrap;从该版本起执行 --frozen-lockfile。两种锁文件都遵守这条规则。
| 锁文件 / 识别信息 | 维护时使用的原始来源 | 实际执行的安装方式 |
|---|---|---|
package-lock.jsonlockfileVersion + 相关内容特征 |
npm/cli 官方发布源码 ↗
对应发布版本的锁文件读取、校验和安装流程;两个文件类型分别建样例。 |
npm ci ↗
|
npm-shrinkwrap.jsonlockfileVersion + 相关内容特征 |
||
pnpm-lock.yamllockfileVersion + settings / 特征字段 |
pnpm/pnpm 官方发布源码 ↗
读取器、迁移分支、冻结安装检查,以及补丁 / 校验字段的处理。 |
pnpm install --frozen-lockfile ↗
|
shrinkwrap.yamlshrinkwrapVersion + importers / 内容特征 |
pnpm/pnpm 官方发布源码 ↗
旧版 pnpm 的读取器、共享 workspace 模式与冻结安装检查。 |
pnpm install --frozen-shrinkwrap
按上方版本边界切换冻结参数。 |
yarn.lock · Classic# yarn lockfile v1 + 依赖内容 |
yarnpkg/yarn 官方发布源码 ↗
Classic 的 lockfile parser 与 install 检查。 |
yarn install --frozen-lockfile ↗
|
yarn.lock · Berry YAML(>=2 <6)__metadata.version + 相关特征cacheKey 是单独维度,不当成锁格式号。
|
yarnpkg/berry 官方发布源码 ↗
Project 的锁文件读取 / 迁移与 immutable 校验。 |
yarn install --immutable ↗
|
yarn.lock · Yarn 6+ JSON(ZPM)JSON __metadata.version + 相关特征与 Berry YAML 的相同格式号分别识别;没有稳定版实测范围时使用 *。
|
yarnpkg/zpm 官方发布源码 ↗
原生 ZPM 的 JSON 锁文件读取与 immutable 校验。 |
yarn install --immutable |
Registry 中的具体发布版本 → dist.tarball +
dist.integrity 校验 → 实际执行该版本 → 生成测试记录。分析源码时使用该版本对应的 tag /
commit,并与发布包核对。
Yarn 独立脚本:官方 tags → tag 对应的 commit → 该 commit 中的 yarn.js。保存不可变 URL、commit、文件大小和下载脚本计算的 SHA-512;执行前校验字节并核对 --version。这份摘要由维护脚本计算,不作为官方发布的 SRI 声明。
随包:精简后的 compatibility.json,包含锁格式 /
特征、生成的版本范围、数据日期和必要的已知 bug
标记。维护仓库:原始测试记录、完整证据索引、样例、生成脚本与维护规范。已验证的历史记录直接保留;完整
provenance 不随包发布。
与已保存记录比较,旧结果直接复用
新版本 × 现有样例;跳过已有记录
AI 解析新格式,真实生成样例并补测边界
根据已确认的兼容变化点生成范围,随包发布
数据更新方式:安装或升级 node-toolchain-infer 时获得兼容表。包管理器发布新版,不会改变用户已安装的这份表;infer 仍用表内范围匹配运行时获取的已发布版本。只有升级 infer,才采用新版表中的实测边界。
范围由维护脚本生成并随包发布;infer 运行时只查表、匹配版本。
build-compatibility
按包管理器、锁格式和内容特征分组,按 semver 排序具体版本的记录。从不支持变为支持的版本写成下界
>=版本;从支持变为不支持的版本写成上界 <版本;后来恢复支持则新增一段,用
||
合并。边界精确到实际发生变化的版本,不固定按主版本切分。
*,仍保留 npm / pnpm / Yarn
类型。新发布的包管理器版本是否可选,只需匹配这份表,无需在运行时补测或重新生成范围。
推断原则:除非当前随包数据明确排除兼容性,否则按最大的可能兼容性推断。允许参与选择不等于已经实测通过。
pnpm 7.28.0 可以读取并安装 lockfile 5.1。冻结安装重写 YAML,导致字节检查失败,但解析后的内容和依赖均相同。上游 #6158 / #6260 确认了该 bug,7.30.1 修复。该失败保留为 rewrite,兼容判定标为 known-bug-compatible,不在版本范围中挖掉这一段。
已知 bug 标记只影响兼容判定,不意味着安装没有 bug。选中受影响版本时,计算结果会给出对应提示。
pnpm #6260遵循预发布版本规则:版本列表、统计、样例发现、矩阵测试、维护巡检及兼容范围编译均只处理稳定版;显式指定的预发布版仅在计算时按需查询,不加入这些数据。
>=9.0.0以下版本与行为用于说明算法,不是实际测试结论。假设已确认 lockfile 9 的首次支持版本是 pnpm 9.0.0,此前版本不支持,且测试覆盖的 9 / 10 / 11 / 12 版本均支持。
| 维护时已确认的测试结果 | 脚本生成的 lockfile 9 范围 | 生成依据 |
|---|---|---|
| 从 9.0.0 起支持,尚无停止支持的边界 | >=9.0.0 |
只写下界;测试到 12 不产生上界。 |
| 后来确认从 13.0.0 起不再支持 | >=9.0.0 <13.0.0 |
在已确认的变化点补上界。 |
| 再后来确认从 14.0.0 起恢复支持 | >=9.0.0 <13.0.0 || >=14.0.0 |
保留中间的不兼容区间,新增一段。 |
假设旧版 infer 的表只有
lockfile 9 → >=9.0.0。随后 pnpm 13.0.0 发布;维护测试确认它从这个版本起不再支持 lockfile
9,并开始支持 lockfile 10,于是发布新版 infer。
| 用户实际安装的 infer | 遇到 lockfile 9 | 遇到 lockfile 10 |
|---|---|---|
| 仍是旧版 infer | >=9.0.013.0.0 满足旧表范围,仍可参与选择。 |
*旧表没有此格式,不限制 pnpm 版本。 |
| 已升级到新版 infer | >=9.0.0 <13.0.0使用新表,13.0.0 被此条件排除。 |
>=13.0.0使用新增格式的实测下界。 |
以上只决定锁文件提供的版本条件。候选仍来自官方已发布版本,并按既定优先级与其他声明、每个候选实际的
engines.node 一起计算。未知锁格式的 * 不会取消其他来源的限制。
安装成功、文件字节不变、依赖版本正确。再用与锁文件矛盾的清单做对照:明确拒绝安装,或仍安装原锁定版本且文件字节不变,才算通过;静默改装成清单中新要求的版本不算。
可复现地拒绝锁文件或改写文件。保留版本边界和失败证据。
包括旧表范围内的新发布版本。允许参与推断,不把范围匹配标为实测通过。
表中无对应格式时使用 *。未完成的测试或网络 / 环境失败不产生不兼容边界。
| 待检查的组合 | 处理方式 |
|---|---|
| 旧版本 × 旧样例,已有有效结果 | 直接读取历史记录,跳过测试。 |
| 新版本 × 已有样例 | 只跑新增的这一行,确认兼容行为是否变化。 |
| 旧版本 × 新格式样例 | 仅补测确定兼容边界所需、且尚无有效记录的版本。 |
| 新版本 × 新格式样例 | 首次测试,纳入新格式的基线。 |
每条记录以工具版本 / 发布包摘要、fixture 摘要、测试 Node、平台和安装参数标识。相同组合的有效结果直接复用;网络失败等无结论记录可以重试。新增样例单独建档,旧样例及其结果保留。
按文件类型 → 锁格式 → 内容特征组织测试目录。
fixtures/ npm/package-lock/<format>/<case>/ npm/shrinkwrap/<format>/<case>/ pnpm/<format>/<case>/ yarn/classic/v1/<case>/ yarn/modern/<format>/<case>/
每个目录保存:package.json、真实生成的锁文件、必要配置和依赖材料、fixture.json。
fixture.json 记录生成工具的具体版本、Node
版本、生成命令、样例特征、预期依赖与文件摘要。基础安装、workspace、peer、patch
和相关校验字段按需要拆成不同 case。
新格式先用实际发布的包管理器生成,不能只手改锁格式数字。新增 fixture 后,只补测确定边界所需的历史版本;这些是“旧版本 × 新样例”的新组合,不重跑旧组合。
每次运行保存实际工具 --version、Node、OS /
架构、命令、退出码、前后摘要和日志。每次复制到干净目录执行,避免沿用旧的安装状态。
GitHub Actions 通过
schedule 定时运行固定脚本,同时提供
workflow_dispatch
手动触发。脚本完成下载、检测和实测;需要修改兼容表、解析器或样例时,输出报告并失败,由维护人员把报告交给
AI。
首次运行固定官方版本清单,逐个测试 npm、pnpm、Yarn 的全部稳定版本,排除预发布版。每个版本执行该包管理器的全部锁文件样例。
pnpm data:seed --concurrency 6
pnpm data:seed --concurrency 6 --retry-incomplete
重复命令会续跑,已完成且输入摘要相同的组合直接复用。新增样例只补测新组合;更换版本清单使用新的 --output 目录,保留原目录。
Yarn 还合并官方 tags 和独立脚本,覆盖未发布到 cli-dist 的历史版本。扩充清单时保留旧快照;编译器核对旧、新清单中的制品地址和校验值相同后复用旧实验,按完整新清单重新判断相邻版本。
每组记录包含具体工具、下载校验、Node、命令、日志、安装前后文件摘要与实际依赖版本。summary.json 汇总通过、不兼容、改写文件、依赖不符和未完成;下载或启动失败不算不兼容。
maintenance/evidence/initial-matrix/
engines.node 的
Node,对已有样例执行冻结安装,检查退出结果、文件摘要和实际安装的依赖。已有相同组合的有效记录直接复用,只运行新增组合。
| 检查结果 | Action 行为 |
|---|---|
| 没有新版本,也没有未处理事项 | 成功 |
| 有新版本,格式可识别,实测符合现有规则 | 保存新增记录,成功 |
| 生成了兼容表中没有的新锁格式 |
失败 · 需要维护 补充解析、真实样例和兼容数据。 |
| 按现有范围应当兼容,但冻结安装失败、文件变化或依赖不正确,且没有匹配的已审核 bug 例外 |
失败 · 需要维护 定位原因,确认是否出现不兼容边界。 |
| 已确认语义兼容,失败记录与已审核的上游 bug 例外匹配 |
通过 · 保留 bug 标记 原始失败仍保存;按兼容参与范围生成。 |
| 按现有范围不兼容,但冻结安装成功、文件不变且依赖正确 |
失败 · 需要维护 确认是否恢复支持,并补测变化点。 |
| 官方数据或锁文件无法解析 |
失败 · 需要维护 保存原始输入,维护解析器。 |
| 下载超时、网络故障或测试环境无法启动 |
重试后仍失败 · 检查未完成 不记为锁格式不兼容,不据此生成版本边界。 |
每次输出供人阅读的摘要和机器可读的
report.json。摘要写入 GitHub Actions
的运行页面,原始数据、样例和安装日志作为附件保存。收集完可完成的检查并保存报告后,再统一设置退出码。
问题类型、包管理器具体版本、锁格式、内容特征和样例路径。
当前兼容范围、预期结果、实际退出结果、文件变化和依赖检查结果。
工具发布包摘要、测试 Node、平台、执行命令、输入文件、前后摘要和完整日志。
需要修改的解析器、样例或数据,以及尚未确认、需要补测的版本边界。
0:检查通过。1 · MAINTENANCE_REQUIRED:检查已完成,但存在维护事项。2 · CHECK_INCOMPLETE:检查因网络或环境等原因未完成。后两种都让 Action 失败;同次运行出现两类问题时退出
2,报告同时保留已发现的维护事项。
专用数据分支:Action 自动追加原始测试记录、来源与摘要,后续运行读取并复用。记录区分已确认结论、待复核异常和无结论失败;待复核异常不能直接变成随包的兼容边界。
主分支:保存解析器、样例、维护脚本和随包兼容表。AI 确认异常原因、补齐边界证据后,由脚本生成范围,维护变更进入主分支。
缓存与运行附件:缓存用于加速下载,附件用于交付本次报告和日志。长期有效的历史证据保存在 Git 中,不能只依赖有保留期限的缓存或附件。
未处理事项持续失败。后续运行复用已有记录,重新对照当前规则;维护变更完成、必要测试补齐且规则与实测一致后,才将事项标为已解决。不能仅记录“已检查版本”,第二天跳过问题并恢复成功。
sync-catalog:下载、校验官方元数据。
check-releases:列出新增具体版本,读取未处理事项。
generate-fixture:用指定工具真实生成锁文件并检查格式。
test-compatibility:复用有效记录,只执行新增测试组合。
build-compatibility:按已确认的变化点生成范围;未确认的异常不生成边界。算法见维护原则与示例。
维护人员根据失败报告启动 AI 维护。AI 读取报告、现有规则、样例与历史证据,定位原因;需要时核对对应发布版本的源码。
新格式需要更新解析器并用真实工具生成样例;兼容变化需要确认首次支持、停止支持或恢复支持的精确版本。
固定脚本的检查范围由现有样例决定。发现样例未覆盖的相关行为时,AI 增加样例;已有有效历史记录保留,不重复测试。
实测记录与推断范围分别保存,每个已确认边界须能追溯到具体版本和样例。没有对应规则的锁格式标记为未知,但版本条件使用 *,不因此阻止推断;匹配范围也不代表该版本已经实测。
查看官方接口响应、获取时间,以及这次响应中的 Node、npm、pnpm 和 Yarn 版本。
显示各官方接口的响应状态、获取时间与版本记录。
网页与包共用官方数据模块和纯解析器。打开页面时获取数据,计算前检查是否超过 60 秒,刷新按钮立即校验更新。网页让浏览器用 HTTP 缓存重新校验;脚本只发送 Accept,不手工添加 If-None-Match / If-Modified-Since,避免触发额外的 CORS 预检。请求失败时可复用页面内已有数据并标出获取时间。页面重新加载后重新获取;应用不向 localStorage / IndexedDB 写版本快照,浏览器 HTTP 缓存遵循浏览器自身策略。锁文件条件使用随包兼容表;未知格式保留包管理器类型并使用 *,不表示已实测通过。
下表展示官方接口返回的稳定版本和 Node 要求;包管理器的锁格式匹配来自随包兼容规则。未声明 engines.node 会明确标出。
| Node 版本 | 绑定的 npm 版本 | 匹配的锁文件格式 · 随包规则 | 数据来源 |
|---|
来源:随包 data/compatibility.json 的编译规则;fixtures/recipes.json 仅补全格式目录。未知格式使用 * 保留类型,不代表支持任何版本。
兼容表生成时间:
横向滚动表格可查看 bug 与数据来源。
| 包管理器与锁格式 | 完整稳定版范围 | 已知安装 bug | 随包数据来源 |
|---|
数据来源:Node 官方发行索引 ↗npm 注册表 ↗pnpm 元数据 ↗Yarn 历史发行元数据 ↗Yarn Berry 元数据 ↗Yarn CLI 历史声明 ↗Yarn 官方版本列表 ↗Yarn 6+ 原生发行索引 ↗