5.2 KiB
Agent Note: Offline pnpm prefetch scripts
Status: implemented
English | 中文
Problem
源码检出在受支持的 Node 运行时、pnpm install 与 pnpm run build 物化 node_modules、各包 lib/ 以及 apps/web/dist 之前无法启动 dsh web。安装会访问 npm registry(Corepack 为 pnpm@11.7.0 也会访问);Node 发行包来自 nodejs.org/dist。Node 的 fetch 客户端不能使用 socks5h:// 代理,因此环境里只有 SOCKS 代理的机器即使 curl 经同一代理成功,pnpm install 仍会失败。后续在隔离网络中安装,需要按相同 OS 预取官方 Node 归档、lockfile store,以及一个不再访问 registry 的 Corepack home。
Decision
scripts/offline/download-deps(POSIX 对侧 .sh)在能访问 nodejs.org 与 registry 时运行。它从 DSH_NODE_DIST_BASE(默认 https://nodejs.org/dist)下载当前 OS 与 CPU 的官方 Node zip/tar,校验 SHASUMS256.txt,解压到已忽略的 .offline-cache/node/runtime,并写入 .offline-cache/node/runtime.json。Node 版本在设置了 DSH_NODE_VERSION 时用它,否则在运行中的 Node 满足 engines.node(^22.19.0 || >=24.0.0)时用该版本,否则用 index.json 中发布了当前平台归档的最新 v24.x。随后把 COREPACK_HOME 设为 .offline-cache/corepack,用该 Node 按根目录 package.json 的 packageManager 引脚执行 corepack prepare,并运行 pnpm fetch --frozen-lockfile --store-dir .offline-store。scripts/offline/install-deps(POSIX 对侧 .sh)在需要时解压缓存的 Node,把它前置到 PATH,设置 COREPACK_ENABLE_NETWORK=0,并对该 store 执行 pnpm install --offline --frozen-lockfile。可选的 -Build / --build 先运行 npm run build:lib,再运行 pnpm --dir apps/web run build,从而避开 npm run build:web 内部嵌套的 pnpm --filter——它可能选出与 packageManager 不同的 Corepack pnpm。
若设置了 DSH_NPM_HTTP_PROXY,它只作为 HTTP 覆盖层套在 corepack prepare 与 pnpm fetch 周围,随后恢复进程内的代理变量,因此调用方会话里的 SOCKS 代理保持不变。curl 使用继承的 HTTP_PROXY / HTTPS_PROXY / ALL_PROXY(包括 SOCKS),仅在这些变量都未设置时才回退到 DSH_NPM_HTTP_PROXY。供 Node/pnpm 使用的值(来自 DSH_NPM_HTTP_PROXY,或在未设置 HTTP 覆盖层时来自继承的代理变量)若为 socks5 或 socks5h,会在 Corepack 运行前失败,因为该 scheme 不是 pnpm 支持的传输。
脚本只为运行时所在主机的 OS 与 CPU 预取 Node 与 lockfile。它们不下载 LLM 权重、Playwright 浏览器或本地推理服务器。把包含 .offline-store 与 .offline-cache 的检出复制到离线机器。
Alternatives considered
让贡献者复制已完成的 node_modules 树并跳过第二次安装。 复制出的 isolated pnpm 布局与主机相关,在 store 路径或包 content-address 链接不匹配时会损坏;针对已 fetch 的 store 运行 pnpm install --offline 才是 pnpm 文档中的隔离网络路径。
把 supportedArchitectures 写进 download 脚本,使一份 store 同时服务 win32 与 linux。 拒绝作为默认:可选原生包(esbuild、koffi、node-pty)必须匹配安装主机,混合 store 仍需在相同 OS 上安装才能解出正确二进制。跨 OS 预取仍是显式的本地 pnpm fetch 配置,不是脚本默认。
在根 package.json 增加调用这些文件的 scripts。 npm run 下嵌套 pnpm 正是 build:web 上 Corepack 版本错配的原因;包装器保持按文件调用,以便自行控制 COREPACK_HOME 与 --store-dir。
在整个 download 脚本期间覆盖调用方的 HTTP_PROXY。 拒绝:.\download-deps.ps1 在当前 PowerShell 会话中运行,会话级覆盖会把后续命令仍可用的 SOCKS 代理换掉。curl 可以使用 SOCKS;只有 Node/pnpm 需要 HTTP 覆盖层,且仅针对这些子进程。
随脚本分发 Node 的 MSI 或 pkg 安装包。 拒绝:那些安装器需要管理员权限和全局安装;官方 zip/tar 可重定位,install 只需解压并前置 PATH。
在脚本中写死某一个 Node 版本。 拒绝:钉死的 patch 会相对 engines.node 与 CI(22.19、24、26)过时。与正在运行的 Node 对齐,可使可选原生包与预取主机一致;PATH 上没有 Node 时回退到 index.json。
把 pnpm store 纳入 git。 store 是数百 MB 的 registry tarball;.gitignore 使 .offline-store/ 与 .offline-cache/ 保持未跟踪。
Consequences
隔离网络准备是一对相同 OS 上的两条命令,不改变在线 pnpm install 路径。离线机器不需要预先安装 Node:install 会解压缓存的官方发行包。在运行 dsh plugin … add 安装 registry 或 git spec 的机器上仍然需要网络。本地对话仍需要另行安装的 OpenAI-compatible 服务器;这些脚本不能替代它。