DeepSeek Harness 的 Node 门槛:230 份 manifest 没一份写 engines

2026-08-16

deepseek-harness 的时候,最先让人愣一下的不是它的插件架构,而是一个很小的工程细节:README 里对运行环境的全部要求,只有一句 Install `Node.js`, then run:README.md:17),紧跟着就是那条 npx @deepseek-ai/dsh webREADME.md:20)。到底要多新的 Node,这句话没说。

而仓库里把这个门槛写死的地方,全仓只有一处。

先把限定摆在前面:这个仓库建立于 2026-08-13,我们采集快照是 2026-08-16,前后只差三天;版本是 0.1.0-rc.5,GitHub 上一个 Release 都没有,README 自己标着「开发者预览」并明写未来会出现破坏兼容性的变更。下面写到的每一个文件路径、每一个默认值,都随时可能变。

唯一写着 engines 的那份 manifest

package.json:8-10

"engines": {
  "node": "^22.19.0 || >=24.0.0"
}

同一份文件往上两行,package.json:5"private": true

然后是这篇文章标题里的那个数字。我们按 packages/*/*/package.jsonapps/*/package.jsonvendor/*/package.json 三类通配扫过去,一共 230 份 manifest,其中带 engines 字段的是 0 份——包括将被发布出去的 apps/cli/package.jsonname@deepseek-ai/dshversion0.1.0-rc.5publishConfig.accesspublic)。

这两件事我们只做位置陈述:版本范围声明在一份标了 private: true 的根 manifest 里,而已发布形态的 CLI 包自己的 manifest 里没有这个字段。至于 npm 客户端在 npx 的时候会读到什么、会不会给提示,我们没有联网核实过 registry 上的实际发布内容,也没有运行过这条命令,不做任何推断。

230 是哪 230,别把它和 49 弄混

这个数字容易数错,值得单独说一句口径。

pnpm-workspace.yaml:1-21 里的 packages 列表包含 packages/*/*——注意是两层通配packages/ 下的二级目录(也就是分组)去重后是 49 个,从 acpapi 一直到 workflow;而真正含 package.json 的 workspace 成员,在 packages/*/* 下有 219 个。写「49 个包」是错的,49 是组。

上面那 230 份就是 219(packages/*/*)+ 2(apps/*)+ 9(vendor/*)。整个仓库含 package.json 的 workspace 成员一共 237 个,多出来的是 native 系 4 个,以及 websiteexamplespython/sdk-runtime 各 1 个;被 git 追踪的 package.json 文件总数是 248 份(含 fixture 之类的非成员)。native 系那 4 份不在我们这次扫的三类通配里,所以对它们有没有 engines,我们不做断言。

以上计数均为 2026-08-16 快照 47f9438 上的实读值。

同一个门槛,在四层里各写了一遍

engines 只有一处,但「要什么版本的 Node」这件事在仓库里被说了四遍,形态各不相同:

位置写法形态
package.json:8-10^22.19.0 || >=24.0.0机器可读的 semver 范围
AGENTS.md:62pnpm install # pnpm workspaces, node ^22.19 || >=24命令表里的注释
docs/development.md:11-14Node.js 支持 22.19+ 与 24+,CI 覆盖 22.19、24、26前置条件散文
.github/workflows/ci.yml:38PRIMARY_NODE_VERSION: '24'CI 变量
.github/workflows/ci.yml:272-279兼容矩阵两条:node: '22.19'node: 26,均在 ubuntu-latestCI 矩阵

这几处在数值上彼此对得上:22.x 一线的下限是 22.19,24 及以上全放行,中间的 23 整条线被排除在范围之外。差别在覆盖面——ci.yml 里显式出现的 Node 版本是 22.19、24、26 这三个,而且 ci.yml:272-279 那个兼容矩阵 job 的 if 条件是 github.event_name == 'pull_request'ci.yml:261)。至于范围内其余版本有没有在这份 938 行的 workflow 别处被跑到,我们只读了文件头与被点名的片段,没有逐条核完,不下结论。

下限为什么卡在 22.19 而不是 22.18,仓库里留了记录。.agents/notes/implemented/process/2026-07-06-node-engine-floor.md:20 写的是:所用的源码特性在 22.x 线上到 22.18 就已经可用,但安装进来的 Pi adapter 依赖把 LTS 下限抬到了 22.19;同一段还解释了这个区间「excludes Node 23 entirely」。

顺手记一条对不上的地方,只陈述差异、不推断原因:同一篇笔记的 :20 写的是 @deepseek-ai/dsh-llm-pi-ai 依赖 @earendil-works/pi-ai@0.79.3,而 packages/llm/llm-pi-ai/package.json:45 声明的是 "^0.82.1"pnpm-lock.yaml:9255 解析到的是 0.82.1pnpm-workspace.yaml:60minimumReleaseAgeExclude 里写的也是 '@earendil-works/pi-ai@0.82.1'。下限 22.19 这个结论本身与根 package.json:9 是一致的,这条差异只涉及被引用的依赖版本号。以我们实读的仓库状态为准。

钉在根上的不只是 Node

package.json:7"packageManager": "pnpm@11.7.0" 同样只有根这一处。docs/development.md:11-14 的前置条件里还列了:需要由 Corepack 启用的 pnpm、Git 2.26 或更新,以及一个可选的 DeepSeek API key。

安装本身带副作用:package.json:142"postinstall": "node scripts/install-lefthook.mjs"docs/development.md:24 说明它会给 worktree 配置本地的 Lefthook hooks 和 dsh-translation-pairing 这个 git merge driver。

另一处会实际拦人的,是 pnpm-workspace.yaml:40-55 的构建脚本白名单,其上方 :35-39 的注释原文写的是「deny by default」:allowBuilds 显式允许 esbuildlefthooknode-ptykoffi 等少数几项,显式拒绝 @google/genaiprotobufjs 等。对应到用户侧,apps/cli/reference/README.md:51 记了这条已知摩擦:git 托管、带源码的第三方插件靠 prepare 脚本构建,pnpm ≥10 会先拦下来,第一次 dsh plugin ... add 会失败并打印 allowBuilds 提示,需要把提示里的 key 复制进该 profile 目录下的 pnpm-workspace.yaml 再重跑。

起不来的时候,先分清是不是版本问题

判定动作很简单:本机跑 node -v,拿输出去比对根 package.json:8-10^22.19.0 || >=24.0.0——特别留意 23.x 落在范围之外;再跑 pnpm -v,比对 package.json:7 钉的 pnpm@11.7.0。文档给出的口径就是 22.19+ 或 24+,仓库没有给「推荐用哪个具体版本」的说法,选哪个取决于你的环境。

更值得说的是反面:下面这几种失败,仓库文档指向的是别的原因,不是 Node 版本。

  • 新克隆之后没单独跑构建。 apps/cli/reference/README.md:84 写得很直白:pnpm run build 必须在新克隆后单独跑;缺少 Typert host 产物时,profile boot 会以模块解析错误失败,而且不会提示你去构建;host 产物在、但缺前端或客户端 bundle 时,启动会报错并提示跑 pnpm run build;同一段还写了「The launcher does not check freshness, so existing stale bundles can run older browser code until rebuilt.」——启动器不检查产物新鲜度。所以一个模块解析错误,先怀疑没构建,而不是先怀疑 Node。
  • 第三方插件装不上。 如果报错里出现 allowBuilds 字样,那是上一节说的 pnpm 构建脚本白名单,与 Node 版本无关。
  • dsh web --host 0.0.0.0 直接退出。 packages/bundle/web-app/src/startup.ts:69-70 里是一句显式的 program.error,原文含 intentionally not supported yet for safety。这里顺带记一处口径差异:.agents/notes/implemented/feature/2026-07-22-web-bind-address.md:15 写的是 CLI 接受 --host 0.0.0.0 作为显式的全网卡模式,而 apps/cli/reference/README.md:64 与上面那段源码一致,写的是 CLI 目前有意不支持并以用法错误退出。两处不一致,位置如上,以我们实读的仓库状态为准。

还有一个快照里看不到的点:apps/cli/package.json:14-16 声明 bin: { "dsh": "lib/bin.js" },而 lib/.gitignore:4 里,apps/web/dist/.gitignore:33 里,构建产物都不入库——所以在克隆下来的仓库里直接找这个文件是找不到的。源码路线下另有一条 package.json:136 定义的 "dsh": "node --import tsx/esm apps/cli/src/bin.ts"

Windows 侧要多留一句

docs/user/guide/python-sdk.md:9-13 给 Python SDK 这条独立安装路径列了平台前置条件,原文是 Linux x64, Linux arm64, or macOS 14 or newer on arm64——Windows 不在这份列表里。同一份文档 :27 还写了 The installed runtime needs no system Node.js.,也就是说这条路径连系统 Node 都不要,前面那个 engines 门槛对它也无从谈起。

至于 Windows 上跑主线的情况,我们在仓库里只看到零散痕迹:package.json:58check:windows-wine:59-61 的三条 check:ci:windows-*.github/workflows/ci.yml:661runs-on: [self-hosted, dsh-win-ci, windows]apps/cli/tests/windows-shell.spec.ts 这个测试文件,以及 pnpm-workspace.yaml:43,51 里关于 ConPTY 与 MoveFileExW 的注释。至于「哪些功能在 Windows 上可用」,我们没能在仓库里找到一处完整清单

最后

一句话收束这篇的观察:engines 这个字段在整个仓库里只出现在一份 private: true 的 manifest 上,230 份被扫的 manifest 里一份都没有;而同一个版本门槛,在 AGENTS.md 的注释、docs/development.md 的散文、CI 的变量与矩阵里各自被复述了一遍。这三层复述在数值上互相对得上,差别在于谁是机器读的、谁是人读的。

顺带提醒一句:npx @deepseek-ai/dsh web 会在你自己的机器上执行代码,这个项目本身也会在本机跑工具与 shell。装不装、在什么机器上装,请结合自身环境判断。

延伸阅读


本文依据 DeepSeek Harness 官方仓库(github.com/deepseek-ai/deepseek-harness)的 README、docs/ 下的 架构与子系统文档、以及 packages/ 下的源码整理,核对日 2026-08-16,对应仓库快照 47f9438(版本 0.1.0-rc.5)。 本文内容为仓库源码与文档口径,我们没有安装、也没有运行过这个项目, 因此不涉及界面外观、操作手感与运行速度的任何描述。 该仓库建立于 2026-08-13,README 自述处于开发者预览阶段并明确说明未来会有破坏兼容性的变更, 文中出现的命令、配置与默认值随时可能变动,请以仓库最新内容为准。 安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。