Replies: 1 comment
|
独立复验:我在已发布的 npm 包上确认了同一结论 —— 与你测的仓库构建(tsx)路径是不同表面,结论一致。 1) 端用户侧同样成立用真实 Node 二进制直接跑
分界同样落在 24.2.0。所以 2) 一处需要修正的细节:发布包根本没有 engines你写 所以「把它们移出 engines 范围」在消费侧还差一步 —— 那里没有 engines 可移,需要先加上。 3) 这也确认了守卫是端用户侧的唯一阻塞点入口已经导出
桥: 我完全支持这个提案尤其是「让失败可见」这一半:静默 exit 0 是这次问题里最贵的部分 —— 它把定位成本从 |
Uh oh!
There was an error while loading. Please reload this page.
标题:fix(cli): 让入口守卫在 Node 24.0–24.1 上失败可见,并把它们移出 engines 范围
关联讨论:#4047(build 静默跳过)、#5082(Node < 24.2 下 build 静默退出、退出码 0)、#5100(残留目录导致误导性
MISSING_EXPORT)、以及社区帖 #5084 相邻的 loader shape 问题
。
摘要
仓库在
423412b7bf(fix(runtime): simplify executable entry dispatch,2026-09-03)把入口判定统一换成了import.meta.main,共 14 处。该 API 在 Node 24.0.0–24.1.x 上求值为undefined(既不是true也不是false),而
engines.node声明为^22.19.0 || >=24.0.0—— 这些版本声明支持、却不满足任何入口守卫。后果是进程零输出、退出码 0,
pnpm run build与pnpm dsh web都表现为"没有任何报错,直接退出"。影响
pnpm dsh webpnpm dsh --profile headless "..."pnpm run buildbuild:lib/build:web从未执行)dsh(npm 全局安装,bin→lib/bin.js)name-server(subprocess-local/lib/runner.js)二次伤害:
pnpm run build静默成功会留下"看似已构建"的残缺工作区(缺packages/*/*/lib/client.js),后续启动才报client bundles not found,把排查引向错误方向。复现
根因与实测
1)
import.meta.main的版本行为(本机实测,非文档推断)import.meta.main(.mjs / .ts 经 tsx 加载)trueundefinedundefinedtruetruetrue即 24.x 行的分界是 24.2.0。(未找到对应的 Node release note,以上为实测结论;若维护者掌握上游出处,欢迎补充。)
2) 同一棵构建产物在不同 Node 上的表现(同一份
apps/cli/lib/bin.js)3) 受影响的 14 处源码入口
其中随包发布、直接影响下游的 3 个产物:
apps/cli/lib/bin.js(@deepseek-ai/dsh的bin)、apps/desktop-host/lib/index.js、packages/subprocess/subprocess-local/lib/runner.js。为什么 CI 没有拦住
两处叠加:
.github/workflows/ci.yml的版本矩阵是22.19 / 24.9 / 26(24.9 是刻意钉住的,注释说明 24.0–24.11.1 携带 v1 内部 loader),主 CI 跑
PRIMARY_NODE_VERSION: '24'= 最新 24。24.0–24.1 从未被任何一条腿执行到,而它们又恰好落在
engines.node声明范围内。pnpm install不会失败(24.1 满足>=24.0.0),所以"声明范围"与"实际可用范围"的缺口没有任何信号。
另外,源码启动路径(
node --import tsx/esm apps/cli/src/bin.ts)与已构建入口在 24.1 上同样静默,因此pnpm dsh和
dsh都不能作为对照。关于"为什么当初改掉旧守卫"
不能简单回退。
423412b7bf把旧的换成了
import.meta.main,同时新增了apps/cli/tests/built-bin.e2e.ts的runs through an installed-style symlink用例 —— 即旧写法在 npm/pnpm 全局安装的符号链接场景下不可靠,而import.meta.main能正确处理(并且它本来就是为了让
runCli可被python/sdk-runtime/runtime-bootstrap.mjs直接 import 调用)。所以修复必须同时满足:符号链接下正确 + 24.0–24.1 上可诊断。
建议修复
A. 收紧
engines.node(必做,最小改动)把声明范围与实测可用范围对齐,排除 24.0–24.1:
理由:
^22.19.0上import.meta.main已可用(实测true),24.x 行自 24.2.0 起可用。若维护者希望 24.x 下界取更高、更整洁的值(例如与兼容矩阵 24.9 对齐),我按你们的判断调整。
B. 入口守卫失败要可见(必做,防止同类回归)
import.meta.main在undefined时静默不执行,这是本次事故的放大器。建议在共享位置(或各入口)加一条 fail-loud断言,把"版本不被支持"从零输出变成明确报错:
C. 补一条落在缺口里的 CI 腿(建议)
在兼容矩阵加
24.1(或24.0)一条最小腿,跑pnpm run build+apps/cli/lib/bin.js --version。这条腿会直接复现"退出码 0 且无输出",是本次缺口唯一的自动化防护。注意 24.0–24.1 与已钉住的 24.9 一样属于 v1 loader 区间
,
DSH_GATE_FAIL_FAST/ gate 并发等设置需按现有约定处理。D. 断言层(可选,但推荐)
在
apps/cli/tests/built-bin.e2e.ts已有的 built-bin 用例旁,加一条"入口必须真的执行"的断言(例如--version必须有非空 stdout),而不是只断言
exitCode === 0。当前 24.1 下exitCode恰好是0,只用退出码判定会漏掉这个缺陷。同步文档:
.agents/notes/implemented/process/2026-07-06-node-engine-floor.md记录了引擎下限的推导(
node:sqlite、原生类型剥离、pi-ai 依赖下限)。若采纳 A,该 Note 的"24.x 分支保持>=24.0.0"一句需同步更新并补充import.meta.main这一条新增约束(按仓库约定,同一 PR 内更新)。不推荐的方案
argv[1]+pathToFileURL字符串比较:会重新引入423412b7bf修掉的符号链接问题。若要走这条路,必须改成
realpathSync规范化后再比较,并保留现有的 symlink e2e 用例。需自行猜测版本。
验证方式
修复后预期:22.19.0 / 24.2.0 / 24.9.0 / 26.8.1 输出
0.1.5-rc.2;24.0.0 / 24.1.0 输出明确的does not provide import.meta.main错误并返回非零。附:本次报告者的原始现象
Node v24.1.0 上:
切到 Node 24.21.0 后同一工作区:
pnpm run build→build: recorded 234 client artifact(s),pnpm dsh web→dsh web: http://127.0.0.1:3080/?token=...并正常常驻。这与上表完全一致。(另:排查过程中还遇到
#5100描述的残留目录问题 —— 已从仓库删除但无package.json、不被pnpm run clean识别的packages/host/apiproxy、packages/session/session-persistence-sqlite会让 tsdown 报误导性的MISSING_EXPORT。删除后构建才通过。此事已在 #5100 单独记录,本 PR 不重复处理。)
All reactions