站点图标 高效码农

DeepSeek Harness接入Codex、Claude Code实战:三步解决npm安装与版本冲突

# 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-codexdsh-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。

退出移动版