# DeepSeek Harness 嵌入 Codex 和 Claude Code 实战:从 npm 安装到版本冲突排查
如果你准备在 DeepSeek Harness 里接入 Codex 和 Claude Code,最容易踩坑的地方并不在 npm install 本身。真正麻烦的是 DSH 的 Profile、Bundle、Subagent Provider 和核心依赖版本之间存在严格的对应关系。
这次实际操作中,我先尝试安装 @deepseek-ai/dsh-subagent-codex,遇到了 npm 安装异常。确认 npm 仓库确实存在这个包之后,本地安装成功,但启动 DSH 又连续遇到了两个问题。
第一个问题是把 Subagent 包放进了 Profile 的 bundles,导致 DSH 把普通 Subagent Provider 当成 Bundle 加载。
第二个问题更加典型,dsh-subagent 需要 dsh-session 提供 findLastMessageTurnEnd,当前实际加载到的 dsh-session 却没有这个导出,最终触发 ESM 模块加载失败。
下面按照实际排查过程,把这套配置完整梳理出来。
## DeepSeek Harness 怎么接入 Codex 和 Claude Code
如果你的目标是让 DeepSeek Harness 调用 Codex 和 Claude Code,可以先把整体结构理解成四层。
DeepSeek Harness
│
├── dsh-base
│ │
│ └── dsh-subagent
│
├── dsh-web-app
│
├── dsh-subagent-codex
│
└── dsh-subagent-claude-code
│
┌────────┴────────┐
│ │
Codex Claude Code
其中:
@deepseek-ai/dsh-subagent-codex
对应 Codex 子代理。
npm 对这个包的描述是:
One-shot Codex subagent provider over the official app-server protocol
Claude Code 对应:
@deepseek-ai/dsh-subagent-claude-code
npm 对它的描述是:
One-shot Claude Code subagent provider over the official Agent SDK
因此安装这两个包之后,还需要让它们和 DSH 自身的版本体系保持一致。
## 第一步先确认 npm 上到底有没有这两个包
之前有一个判断很容易误导排查。
如果直接检查当前 DSH 的 node_modules,找不到:
@deepseek-ai/dsh-subagent-codex
@deepseek-ai/dsh-subagent-claude-code
并不能据此判断 npm 上没有这两个包。
实际使用:
npm view @deepseek-ai/dsh-subagent-codex
可以看到:
@deepseek-ai/dsh-subagent-codex@0.0.1-rc.1
同时 npm 返回了:
versions: 9
latest: 0.0.1-rc.1
next: 0.1.0-rc.8
Claude Code 包同样存在:
npm view @deepseek-ai/dsh-subagent-claude-code
返回:
@deepseek-ai/dsh-subagent-claude-code@0.0.1-rc.1
并且同样存在:
latest: 0.0.1-rc.1
next: 0.1.0-rc.8
这一步解决的是包是否存在的问题。
# npm install -g 安装失败怎么办
第一次尝试使用全局安装:
npm install -g @deepseek-ai/dsh-subagent-codex
npm 返回:
npm error Cannot read properties of null (reading 'children')
但随后测试:
npm install -g lodash
可以正常完成。
这说明 npm 本身并没有完全失效。
继续进入 DSH Profile:
cd C:\Users\reanod\.dsh\profiles\web
然后执行本地安装:
npm install @deepseek-ai/dsh-subagent-codex
结果:
added 22 packages in 9s
这一步最终证明,当前问题可以绕过全局安装,直接在 DSH Profile 中安装 Subagent 包。
# DSH Profile 里的 Subagent 包应该怎么放
这是整个过程中第一个真正的配置坑。
当时的 package.json 是:
{
"name": "dsh-profile-web",
"private": true,
"dependencies": {
"@deepseek-ai/dsh-subagent-claude-code": "^0.0.1-rc.1",
"@deepseek-ai/dsh-subagent-codex": "^0.0.1-rc.1"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"@deepseek-ai/dsh-subagent-codex",
"@deepseek-ai/dsh-subagent-claude-code"
]
}
}
}
然后运行:
dsh web
直接得到:
Error: dsh: profile bundle "@deepseek-ai/dsh-subagent-codex" declares no dsh.bundle in its package.json
错误信息已经把问题说得很清楚。
DSH 正在按照 Profile Bundle 的方式加载:
@deepseek-ai/dsh-subagent-codex
但这个 npm 包没有声明:
dsh.bundle
所以 DSH 拒绝继续加载。
## 正确的 Profile 配置方式
dsh-subagent-codex 和 dsh-subagent-claude-code 可以作为 npm dependency 安装。
它们不要继续放在:
"dsh": {
"profile": {
"bundles": []
}
}
里面。
应该调整为:
{
"name": "dsh-profile-web",
"private": true,
"dependencies": {
"@deepseek-ai/dsh-subagent-claude-code": "^0.0.1-rc.1",
"@deepseek-ai/dsh-subagent-codex": "^0.0.1-rc.1"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app"
]
}
}
}
这里有两个概念需要分开。
### Profile Bundle
@deepseek-ai/dsh-base
@deepseek-ai/dsh-web-app
它们属于 DSH Profile 的 Bundle。
### Subagent Provider
@deepseek-ai/dsh-subagent-codex
@deepseek-ai/dsh-subagent-claude-code
它们通过 npm dependency 安装。
这个区别直接决定 DSH 能不能成功启动。
# 第二个错误来自 dsh-session 版本不匹配
修改 Bundle 后再次执行:
dsh web
这一次错误发生在:
@deepseek-ai/dsh-subagent
具体错误是:
The requested module '@deepseek-ai/dsh-session'
does not provide an export named 'findLastMessageTurnEnd'
错误堆栈进一步显示:
C:\Users\reanod\.dsh\profiles\web\node_modules\@deepseek-ai\dsh-subagent\lib\index.js
其中存在:
import {
Session,
SessionId,
findLastMessageTurnEnd,
snapshotJsonValue
} from "@deepseek-ai/dsh-session";
问题发生在模块初始化阶段。
dsh-subagent 需要:
findLastMessageTurnEnd
而当前实际加载到的:
@deepseek-ai/dsh-session
没有这个 export。
Node.js 因此直接抛出:
SyntaxError
DSH 还没有进入 Web 服务正常运行阶段。
# 为什么需要检查 DSH 的完整版本树
这时候单独看:
dsh-subagent
的版本还不够。
因为 DSH 是一个由大量 @deepseek-ai/* 包组成的 npm 依赖体系。
例如当前全局 DSH 的依赖树中,可以看到:
@deepseek-ai/dsh@0.1.0-rc.8
│
├── @deepseek-ai/dsh-base@0.1.0-rc.8
│ ├── @deepseek-ai/dsh-agent-loop@0.1.0-rc.8
│ │ └── @deepseek-ai/dsh-session@0.1.0-rc.8
│ │
│ ├── @deepseek-ai/dsh-subagent@0.1.0-rc.8
│ │ └── @deepseek-ai/dsh-session@0.1.0-rc.8
│ │
│ └── ...
│
└── @deepseek-ai/dsh-session@0.1.0-rc.8
大量依赖最终都统一到了:
@deepseek-ai/dsh-session@0.1.0-rc.8
例如实际检查:
npm list -g @deepseek-ai/dsh-session
可以看到大量:
@deepseek-ai/dsh-session@0.1.0-rc.8 deduped
这说明当前全局 DSH 本身的核心依赖已经统一在:
0.1.0-rc.8
# 当前 DSH 实际已经是 rc.8
全局检查:
npm list -g @deepseek-ai/dsh
得到:
C:\nvm4w\nodejs -> .\
`-- @deepseek-ai/dsh@0.1.0-rc.8
继续检查:
npm list -g @deepseek-ai/dsh-subagent
结果显示:
@deepseek-ai/dsh-subagent@0.1.0-rc.8
因此当前核心组件已经是:
@deepseek-ai/dsh 0.1.0-rc.8
@deepseek-ai/dsh-session 0.1.0-rc.8
@deepseek-ai/dsh-subagent 0.1.0-rc.8
这给后续处理提供了一个明确的版本基准。
# Codex 和 Claude Code 应该优先检查哪个版本
npm 对两个 Subagent Provider 同时提供了:
latest
0.0.1-rc.1
以及:
next
0.1.0-rc.8
当前 DSH 核心已经是:
0.1.0-rc.8
因此实际配置时,应该优先检查同一 RC 系列的:
@deepseek-ai/dsh-subagent-codex@0.1.0-rc.8
@deepseek-ai/dsh-subagent-claude-code@0.1.0-rc.8
可以先确认版本是否存在。
npm view @deepseek-ai/dsh-subagent-codex@0.1.0-rc.8 version
npm view @deepseek-ai/dsh-subagent-claude-code@0.1.0-rc.8 version
如果都返回:
0.1.0-rc.8
就可以继续统一 Profile 版本。
# 为什么这里建议锁定版本
当前属于多个高度相关的 RC 包一起运行。
例如:
dsh
dsh-session
dsh-subagent
dsh-subagent-codex
dsh-subagent-claude-code
这些包之间存在接口调用关系。
因此在排查阶段,建议使用:
"@deepseek-ai/dsh-subagent-codex": "0.1.0-rc.8",
"@deepseek-ai/dsh-subagent-claude-code": "0.1.0-rc.8"
暂时不要写成:
"@deepseek-ai/dsh-subagent-codex": "^0.1.0-rc.8"
这样可以减少 npm 安装时产生额外版本变化。
# Node.js 25 是否是当前主要问题
当前日志没有直接指向 Node.js 25 的兼容性问题。
实际环境是:
node -v
返回:
v25.0.0
而 npm:
npm -v
返回:
11.6.2
此前:
npm install @deepseek-ai/dsh-subagent-codex
已经成功。
因此当前最直接的故障点仍然是 DSH 包之间的模块接口匹配。
在依赖版本还没有统一之前,贸然切换 Node 版本会增加变量,排查效率反而会下降。
# Windows 下还要检查 DSH 到底从哪里启动
这次排查还发现了一个很容易被忽略的现象。
执行:
where node
得到:
C:\nvm4w\nodejs\node.exe
执行:
where npm
得到:
C:\nvm4w\nodejs\npm
C:\nvm4w\nodejs\npm.cmd
执行:
where dsh
得到:
C:\nvm4w\nodejs\dsh
C:\nvm4w\nodejs\dsh.cmd
全局 npm 路径:
npm prefix -g
返回:
C:\nvm4w\nodejs
全局 node_modules:
npm root -g
返回:
C:\nvm4w\nodejs\node_modules
因此当前命令行环境统一指向:
C:\nvm4w\nodejs
# 为什么报错堆栈里却出现了 D 盘
dsh.cmd 的内容是:
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\node_modules\@deepseek-ai\dsh\lib\bin.js" %*
根据这个脚本,dsh 应该使用:
C:\nvm4w\nodejs\node.exe
以及:
C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh\lib\bin.js
但此前 dsh web 的堆栈出现:
D:\instal\nvm\v25.0.0\node_modules\@deepseek-ai\dsh
因此还需要检查 C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh 本身是否存在链接、重定向或者其他安装残留。
可以执行:
dir C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh
再检查:
fsutil reparsepoint query C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh
还可以直接读取:
type C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh\package.json
确认:
"name": "@deepseek-ai/dsh",
"version": "0.1.0-rc.8"
# 可以绕过 dsh.cmd 直接测试
为了排除 Windows 命令 Shim 的干扰,可以直接执行:
C:\nvm4w\nodejs\node.exe C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh\lib\bin.js web
这个测试很有价值。
如果这里仍然出现:
D:\instal\nvm\v25.0.0\node_modules\@deepseek-ai\dsh
就可以继续检查 C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh 的实际内容和依赖。
如果这里使用的是:
C:\nvm4w\nodejs\node_modules\@deepseek-ai\dsh
那么排查范围就可以继续缩小到 Profile 的依赖树。
# 推荐的最终 Profile 形态
当版本统一到 0.1.0-rc.8 后,Profile 可以采用下面这种结构。
{
"name": "dsh-profile-web",
"private": true,
"dependencies": {
"@deepseek-ai/dsh-subagent-codex": "0.1.0-rc.8",
"@deepseek-ai/dsh-subagent-claude-code": "0.1.0-rc.8"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app"
]
}
}
}
这里的关键关系可以简单理解成:
dependencies
│
├── dsh-subagent-codex
└── dsh-subagent-claude-code
dsh.profile.bundles
│
├── dsh-base
└── dsh-web-app
两个 Subagent Provider 不进入 bundles。
# 重新安装 Profile 依赖
确认 package.json 已经改成 0.1.0-rc.8 后,可以在 Profile 目录执行:
cd C:\Users\reanod\.dsh\profiles\web
删除旧依赖:
rmdir /s /q node_modules
删除锁文件:
del package-lock.json
重新安装:
npm install
然后检查:
npm list --depth=0
重点检查:
npm list @deepseek-ai/dsh-subagent-codex
npm list @deepseek-ai/dsh-subagent-claude-code
npm list @deepseek-ai/dsh-subagent
npm list @deepseek-ai/dsh-session
理想结果应该统一到:
0.1.0-rc.8
# 一套完整的排查顺序
实际操作时,建议严格按照下面顺序执行。
## 1. 确认 Node
node -v
当前环境:
v25.0.0
## 2. 确认 npm
npm -v
当前环境:
11.6.2
## 3. 确认 DSH
npm list -g @deepseek-ai/dsh
当前:
@deepseek-ai/dsh@0.1.0-rc.8
## 4. 确认核心 Subagent
npm list -g @deepseek-ai/dsh-subagent
当前:
@deepseek-ai/dsh-subagent@0.1.0-rc.8
## 5. 确认 Session
npm list -g @deepseek-ai/dsh-session
当前核心版本:
@deepseek-ai/dsh-session@0.1.0-rc.8
## 6. 检查 Codex 版本
npm view @deepseek-ai/dsh-subagent-codex@0.1.0-rc.8 version
## 7. 检查 Claude Code 版本
npm view @deepseek-ai/dsh-subagent-claude-code@0.1.0-rc.8 version
## 8. 修改 Profile
dependencies
├── dsh-subagent-codex@0.1.0-rc.8
└── dsh-subagent-claude-code@0.1.0-rc.8
Bundle 只保留:
dsh-base
dsh-web-app
## 9. 清理 Profile
rmdir /s /q node_modules
del package-lock.json
## 10. 重新安装
npm install
## 11. 检查依赖树
npm list @deepseek-ai/dsh-subagent-codex
npm list @deepseek-ai/dsh-subagent-claude-code
npm list @deepseek-ai/dsh-subagent
npm list @deepseek-ai/dsh-session
## 12. 最后再启动
dsh web
# 常见问题
## DSH 为什么提示 Codex 包没有 dsh.bundle
因为它被放进了:
"dsh": {
"profile": {
"bundles": []
}
}
DSH 会按照 Bundle 处理它。
正确做法是把它放在:
"dependencies": {}
里面。
## npm install -g @deepseek-ai/dsh-subagent-codex 失败怎么办
当前实际测试中,全局安装这个包曾经出现:
Cannot read properties of null (reading 'children')
随后普通 npm 包安装可以正常完成。
因此当前 Profile 场景可以优先使用:
cd C:\Users\reanod\.dsh\profiles\web
npm install @deepseek-ai/dsh-subagent-codex
## 为什么 npm list @deepseek-ai/dsh 显示 empty
如果当前目录是:
C:\Users\reanod
那么:
npm list @deepseek-ai/dsh
查询的是当前目录的本地依赖。
全局 DSH 应该使用:
npm list -g @deepseek-ai/dsh
## 为什么 npm root -g 很重要
它可以确认 npm 全局包安装在哪里。
当前结果是:
C:\nvm4w\nodejs\node_modules
这和:
where dsh
得到的:
C:\nvm4w\nodejs\dsh
是一致的。
## findLastMessageTurnEnd 是什么问题
当前错误发生在模块导入阶段。
dsh-subagent 代码尝试从:
@deepseek-ai/dsh-session
导入:
findLastMessageTurnEnd
实际加载的 Session 包没有这个 export,于是 Node.js 抛出 ESM SyntaxError。
当前排查重点是统一:
dsh
dsh-subagent
dsh-session
dsh-subagent-codex
dsh-subagent-claude-code
的 RC 版本。
## Codex 和 Claude Code 可以同时安装吗
从当前 Profile 的依赖结构来看,可以同时声明:
"@deepseek-ai/dsh-subagent-codex": "0.1.0-rc.8",
"@deepseek-ai/dsh-subagent-claude-code": "0.1.0-rc.8"
二者分别对应 Codex 和 Claude Code 的 Subagent Provider。
## 为什么建议锁死版本
当前使用的是 RC 版本。
DSH 核心组件之间存在 API 依赖,当前已经出现了:
dsh-subagent
↓
dsh-session
↓
findLastMessageTurnEnd
这样的接口依赖。
排查阶段锁定:
0.1.0-rc.8
更容易确认到底是哪一个包产生了版本分叉。
# 最后检查清单
[ ] node -v 已确认
[ ] npm -v 已确认
[ ] where node 已确认
[ ] where npm 已确认
[ ] where dsh 已确认
[ ] DSH 已确认为 0.1.0-rc.8
[ ] dsh-session 已确认为 0.1.0-rc.8
[ ] dsh-subagent 已确认为 0.1.0-rc.8
[ ] Codex 使用 0.1.0-rc.8
[ ] Claude Code 使用 0.1.0-rc.8
[ ] Codex 没有放进 dsh.profile.bundles
[ ] Claude Code 没有放进 dsh.profile.bundles
[ ] Profile 只保留 dsh-base 和 dsh-web-app Bundle
[ ] 删除旧 node_modules
[ ] 删除 package-lock.json
[ ] npm install
[ ] npm list 检查版本是否统一
[ ] 最后执行 dsh web
当前这套排查已经把问题从“怎么安装 Codex 和 Claude Code”缩小到了两个具体点。一个是 Profile Bundle 与 npm dependency 的区别,另一个是 dsh-session API 与 dsh-subagent 的 RC 版本匹配。只有这两层稳定以后,才适合继续配置 DeepSeek Harness 如何实际把任务委托给 Codex 和 Claude Code。
