结论先行
在 Windows 上装好 OpenAI Codex CLI(pnpm add -g @openai/codex)后,一运行就报:
Error: Missing optional dependency @openai/codex-win32-x64. Reinstall Codex: pnpm add -g @openai/codex@latest
按提示重装了两三次都失败。最终定位到两个坑叠加:
- pnpm 对可选依赖(optionalDependencies)下载失败是静默的——Codex 的 Windows 平台二进制包(
@openai/codex-win32-x64,141MB)没下载成功,pnpm 也照常完成安装,运行时才暴露。 - 网络对持续大文件下载不稳定——连接在约 60~66MB 处被切断,而 pnpm 每次重试都从零开始下载,永远到不了 141MB。
解决办法:用支持断点续传的 curl -C - 把平台包完整拉下来,再手动补装进 pnpm 的全局虚拟 store。全程不需要重装 Codex 本体。
症状:命令存在,一运行就抛异常
$ codex
file:///C:/Users/peini/AppData/Local/pnpm/global/v11/.../node_modules/@openai/codex/bin/codex.js:107
throw new Error(
^
Error: Missing optional dependency @openai/codex-win32-x64. Reinstall Codex: pnpm add -g @openai/codex@latest
codex 命令本身存在(shim、主包都装好了),但启动脚本 codex.js 在运行时找不到对应平台的二进制包,直接抛异常。报错信息还很贴心地给了重装命令。
第一次误判:按提示重装
执行 pnpm add -g @openai/codex@latest,发现它在下载 @openai/codex@0.153.4-win32-x64(141.49 MB)时,进度到约 60~66MB 就报 operation timed out,然后从头开始重试,再断,再从头…… 官方 npm 源、npmmirror 镜像源都是同样的规律,说明不是源的问题,是本机网络对长连接不稳。
观察到的关键现象:
- pnpm 每次重试,下载进度都从 0 重新计数,不支持断点续传;
- 失败的是可选依赖,pnpm 最终仍然以「安装成功」收场,没有任何失败提示;
- 检查
node_modules/.pnpm/虚拟 store:@openai+codex@0.153.4在,但平台包目录根本不存在。
再查 node_modules/.modules.yaml 里的 skipped 列表,居然没有列出 win32-x64——元数据声称它被安装了,文件系统却告诉我们没有。信任文件系统,别信元数据。
根因:两个坑叠在一起
坑一:可选依赖失败被静默忽略
Codex CLI 的发布方式:主包 @openai/codex(纯 JS 启动器)把各平台的 Rust 二进制拆成独立的可选依赖包(@openai/codex-win32-x64、-darwin-arm64、-linux-x64……),运行时按 process.platform + arch 解析对应包。这种模式很常见(esbuild、sharp 都这么干)。
问题是:可选依赖下载失败,pnpm 默认不报错。codex.js 的 require.resolve("@openai/codex-win32-x64/package.json") 找不到包,只能抛 Missing optional dependency。
坑二:网络扛不住 60MB+ 的长连接,而 pnpm 重试从零开始
两三个源都断在同样的量级,说明是本机网络的持续传输不稳定(常见于代理、弱网、运营商限速场景)。pnpm 的 fetch 重试是「整包重下」,不是「从断点续传」,所以只要单次下载超过网络能扛的阈值,就永远装不完。
解决方案:curl 断点续传 + 手动补装
第 1 步:curl 拉包(关键:-C - 断点续传)
curl -L -C - --retry 10 --retry-all-errors --retry-delay 3 \
-o codex-win32-x64-0.153.4.tgz \
"https://registry.npmmirror.com/@openai/codex/-/codex-0.153.4-win32-x64.tgz"
-C - 让 curl 在连接断开后从已下载的字节位置继续,断多少次都最终能拉完整。实际下载断了几次,但文件完整到达:141,495,386 字节。
第 2 步:解压验证
tar -xzf codex-win32-x64-0.153.4.tgz
# 确认关键二进制存在:
# package/vendor/x86_64-pc-windows-msvc/bin/codex.exe
第 3 步:放进 pnpm 全局虚拟 store(注意命名规则)
pnpm 虚拟 store 的目录名规则是 @scope+name@version,其中 version 是该包 package.json 里的完整版本字段。平台包的 version 是 0.153.4-win32-x64,所以规范目录名是:
node_modules/.pnpm/@openai+codex@0.153.4-win32-x64/node_modules/@openai/codex-win32-x64/
注意:不是 @openai+codex-win32-x64@0.153.4。我最初按「包名 + 版本」直觉建错了目录,导致 require.resolve 依旧失败。
第 4 步:mklink /J 建链接(避开 PowerShell 的坑)
Codex 启动器是从 node_modules/.pnpm/@openai+codex@0.153.4/node_modules/ 向上解析依赖的,所以要在它的 node_modules 下建一个指向平台包的链接:
mklink /J "…\@openai+codex@0.153.4\node_modules\@openai\codex-win32-x64" "…\@openai+codex@0.153.4-win32-x64\node_modules\@openai\codex-win32-x64"
这里踩了一个 PowerShell 的坑:New-Item -ItemType Junction 生成的链接不可用(类型变成了符号链接、目标路径被改写成错误的相对路径),换 cmd /c mklink /J 用绝对路径一次成功。Windows 上建目录链接,用 mklink /J,别用 PowerShell 的 New-Item。
第 5 步:验证
# 1. 解析验证
node -e "const {createRequire}=require('node:module'); const r=createRequire('…/bin/codex.js'); console.log(r.resolve('@openai/codex-win32-x64/package.json'))"
# 2. 实跑验证
codex --version # → codex-cli 0.153.4 ✓
期望:给 pnpm 的愿望清单
这次经历最难受的两点,恰好都是 pnpm 可以改进的:
- 下载支持断点续传:请求带
Range头、重试从上次断点继续,大包(几十上百 MB)在弱网环境下就不至于永远装不完。curl 一个-C -就解决的事,包管理器不该没有。 - 可选依赖失败要显式告警:安装失败可以继续(可选嘛),但至少在安装结束时明确提示「以下可选依赖下载失败:@openai/codex-win32-x64(141.49MB)」,而不是让人在运行时报错后才回头查。
npm install对这种情况也有同样的问题。 - 顺带一个元数据一致性问题:
.modules.yaml的skipped列表与实际落盘不一致,排查时一度被误导,建议安装完成后校验「声明的已安装项」与「实际文件」是否一致。
在 pnpm 支持之前,我们自己可以做的:
- 装完带原生二进制的包,立刻跑一次
--version验证,别等用的时候才发现; - 大包先预热:遇到几十 MB 以上的包下载失败,先
curl -C -拉 tarball,再喂给包管理器或手动补装; - 换网络通道:代理 / 镜像源 / 网络环境变化后重试,往往一次就过。
避坑清单
| 坑 | 表现 | 规避 |
|---|---|---|
| 可选依赖静默失败 | 安装「成功」,运行时才报 Missing dependency | 装完立刻跑 --version 验证 |
| 网络长连接不稳 | 大包下载到 60MB 左右断流 | curl -C - 断点续传拉包 |
| pnpm 重试从头下 | 每次重试进度归零,永远下不完 | 换通道 / 预热 tarball |
| 虚拟 store 目录名猜错 | require.resolve 仍失败 |
目录名按 package.json 的 version 字段拼 @scope+name@version |
PowerShell New-Item 建链接不可用 |
生成错误的符号链接、目标错乱 | 用 cmd /c mklink /J 绝对路径 |
| 元数据与实际不一致 | .modules.yaml 声称已装,文件不存在 |
以文件系统为准,别信元数据 |