@whaletalk/dsh-codex-collab 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,38 +6,51 @@
6
6
 
7
7
  **Codex 主导,DeepSeek 执行,Codex 验收。** 一个插件体系,让 ChatGPT(Codex)像项目经理一样把编码任务派给本机 DeepSeek Harness 的编码子代理,实时回传结果,读文件验收,并由独立评审员实际跑通构建/测试后出具评审报告。
8
8
 
9
+ 派活有**两种目标**,必须显式选一种——"接进用户正在用的那条对话"和"新建一个干活的子代理"是两件事:
10
+
11
+ | 目标 | 什么时候用 | 效果 |
12
+ |---|---|---|
13
+ | `worker`(默认) | 全新任务、独立项目目录 | 在 `--cwd` 里新建持久编码子代理(多工作区 · 多 lane · fast/pro 模型) |
14
+ | `session` | 用户已经在某条对话里推进这件事,你只是替他继续 | 指令**投递进那条会话**,沿用它的上下文,**不新建会话/工作区** |
15
+
9
16
  ```
10
17
  Codex 工作区 (ChatGPT)
11
- │ 派活 / 评审 / 验收
18
+ │ dsh_task / dsh_sessions / dsh_review / dsh_read_file
12
19
  ▼
13
- DeepSeek Harness 网关 ── 编码子代理(多工作区、多 lane、fast/pro 模型)
14
- │ 独立评审子代理(必须跑通构建/测试)
15
- ▼
16
- 共享工作目录(任意目录,--cwd 指定)
20
+ DeepSeek Harness 网关 /api/dsh-bridge
21
+ ├─ worker 目标 ──→ 新建编码子代理(多工作区 · 多 lane · fast/pro)─┐
22
+ ├─ session 目标 ─→ 已有那条会话(prompt 投递,queue / steer) ──┤
23
+ └─ 独立评审子代理(必须跑通构建/测试)───────────────────────────┴→ 共享目录 / 原会话
17
24
  ```
18
25
 
19
26
  ```mermaid
20
27
  flowchart LR
21
28
  subgraph Codex["Codex (ChatGPT) — 项目经理 + 验收员"]
22
- A1[dsh_task 派活]
23
- A2[dsh_review 评审]
24
- A3[dsh_read_file 验收]
29
+ A1[dsh_sessions 找会话]
30
+ A2[dsh_task 派活]
31
+ A3[dsh_review 评审]
32
+ A4[dsh_read_file 验收]
25
33
  end
26
34
  subgraph DSH["DeepSeek Harness"]
27
35
  B1[HTTP 网关 /api/dsh-bridge]
28
- B2[编码子代理<br/>多工作区 · 多 lane · fast/pro]
29
- B3[独立评审子代理<br/>必须跑通构建/测试]
36
+ B2[worker 目标<br/>新建编码子代理]
37
+ B3[session 目标<br/>投递进已有会话]
38
+ B4[独立评审子代理<br/>必须跑通构建/测试]
30
39
  end
31
- subgraph FS["共享工作目录"]
32
- C1[任意项目目录]
40
+ subgraph FS["工作现场"]
41
+ C1[共享工作目录]
42
+ C2[已有会话与其上下文]
33
43
  end
34
- A1 --> B1
44
+ A1 -->|只读查找| B1
35
45
  A2 --> B1
36
- A3 --> C1
46
+ A3 --> B1
47
+ A4 --> C1
37
48
  B1 --> B2 --> C1
38
- B1 --> B3 --> C1
49
+ B1 --> B3 --> C2
50
+ B1 --> B4 --> C1
39
51
  B2 -.实时回传汇报.-> B1
40
- B1 -.任务结果.-> A1
52
+ B3 -.实时回传汇报.-> B1
53
+ B1 -.任务结果.-> A2
41
54
  ```
42
55
 
43
56
  ---
@@ -48,7 +61,10 @@ flowchart LR
48
61
  |---|---|---|
49
62
  | `codex-plugin/` | Codex 本地市场插件包 | 标准 marketplace 结构(`.agents/plugins/marketplace.json` + 插件目录),含协作技能 `dsh-collab` |
50
63
  | `mcp/dsh-mcp.mjs` | MCP 服务器(零依赖 Node) | stdio 传输(Codex `[mcp_servers]` 直连)+ Streamable HTTP 传输(`--http`,供 Secure MCP Tunnel / cloudflared 桥接 ChatGPT);6 个工具:`dsh_task` / `dsh_sessions` / `dsh_task_status` / `dsh_task_cancel` / `dsh_review` / `dsh_read_file` |
51
- | `harness/dsh-bridge.mjs` | DeepSeek Harness 宿主组合网关插件 | 提供 HTTP 网关(`/api/dsh-bridge/*`)、WS 推送、原生工具,管理编码/评审子代理会话。**必须装进 harness 宿主组合**(见下文) |
64
+ | `harness/dsh-bridge.mjs` | DeepSeek Harness 宿主组合网关插件 | 提供 HTTP 网关(`/api/dsh-bridge/*`)、WS 推送、原生工具;管理编码/评审子代理,并把任务投递进已有会话。**必须装进 harness 宿主组合**(见下文) |
65
+ | `harness/session-target.mjs` | 会话目标的纯决策层 | 目标判定、候选挑选(0/1/N 不猜)、RemoteError→稳定 reason、基线切分、汇报选文。无 DSH import,可单测;`dsh-bridge.mjs` 依赖它,**两个文件必须一起部署** |
66
+ | `test/` | 25 项 Node 测试 | `session-target` 纯函数单测 + `dsh-bridge` 路由级回归测试(假 DSH 运行时加载真实 bridge)。CI 每次都跑 |
67
+ | `templates/codex-mcp/` | 反向通道配置模板 | 把 Codex CLI 当 MCP 服务端挂进 DSH(得到 `mcp__codex__*` 工具),让 DSH 侧也能调用 Codex。见下文「反向通道」 |
52
68
  | `cordis.patch.yml` | bundle patch | 把网关插件挂进 DSH 宿主组合;`dsh.bundle.patch` 指向它,所以 `dsh plugin add` 能自动 reconcile |
53
69
 
54
70
  ## 功能
@@ -69,7 +85,8 @@ flowchart LR
69
85
 
70
86
  ```sh
71
87
  # 1) 网关插件装进 harness profile(自动 reconcile bundles,无需手工复制文件)
72
- dsh plugin --profile web add @whaletalk/dsh-codex-collab
88
+ dsh plugin --profile desktop add @whaletalk/dsh-codex-collab
89
+ # ↑ DSH 客户端用的就是 desktop profile;纯 Web 部署换成 --profile web
73
90
 
74
91
  # 2) MCP 服务器交给 Codex
75
92
  npm install -g @whaletalk/dsh-codex-collab
@@ -81,9 +98,27 @@ npm install -g @whaletalk/dsh-codex-collab
81
98
  [mcp_servers.dsh]
82
99
  command = 'dsh-mcp'
83
100
  startup_timeout_sec = 120
101
+ env = { DSH_BRIDGE_URL = "http://127.0.0.1:3080" } # 见下方"端口";不写则默认 3080
84
102
  ```
85
103
 
86
- 装完**必须重启 profile 进程**——`dsh plugin add` 改的是 bundles 列表与 node_modules,HMR 不监控这两处。
104
+ **端口**:网关挂在 profile 的 `webServer` 上,地址取决于 profile 怎么起的——独立 harness 通常 `3080`,而 DSH 客户端里就是 **GUI 自己的端口**(例如 `http://127.0.0.1:19387`)。MCP 与 CLI 都用 `DSH_BRIDGE_URL` 找网关,指错只会看到连接失败或 401。验证:
105
+
106
+ ```sh
107
+ curl http://127.0.0.1:3080/api/dsh-bridge/status
108
+ ```
109
+
110
+ 装完**必须重启 profile 进程**——`dsh plugin add` 改的是 bundles 列表与 node_modules,HMR 不监控这两处;**替换包内容也不会热重载**(ESM 缓存),只有重启进程才加载新版本。
111
+
112
+ ### 升级到新版本(有坑,照做)
113
+
114
+ ```sh
115
+ # 1) 带精确版本号安装:不带版本号时 lockfile 会把旧版按回来
116
+ dsh plugin --profile desktop add @whaletalk/dsh-codex-collab@<新版本>
117
+ # 2) 重启 profile 进程:不重启不会加载新的 JS 模块
118
+ ```
119
+
120
+ - **不要用"卸载 → 重装"**:卸载会把这个包从 `dsh.profile.bundles` 移除;重装后若没被重新选中,插件根本不会挂载(表现:所有 `/api/dsh-bridge/*` 都落到网关鉴权层返回 **401**)。真遇到了就在客户端插件页把它的开关打开。
121
+ - **刚发布的版本约 24 小时内装不上**:profile 的 pnpm 带 `minimumReleaseAge` 供应链冷却(`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`)。管理器会把它写进 `pnpm-workspace.yaml` 的 `minimumReleaseAgeExclude` 才放行;手工安装可临时加 `--config.minimumReleaseAge=0`。
87
122
 
88
123
  > 本包只提供 bundle patch,不含 profile 之外的强依赖:`@deepseek-ai/dsh-tools` 是 optional peer,由 DSH 安装树在运行时提供。因此 `npm install` 不会去 registry 拉它,也不会因它缺失而报错。
89
124
 
@@ -92,21 +127,23 @@ startup_timeout_sec = 120
92
127
 
93
128
  ### 1. DeepSeek Harness 网关(必需,后端)
94
129
 
95
- 把 `harness/dsh-bridge.mjs` 复制到你的 dsh profile 目录(例如 `$DSH_HOME/profiles/web/`),并在该目录的 `cordis.patch.yml` 中追加:
130
+ 把 **`harness/` 整个目录**复制到你的 dsh profile 目录(例如 `$DSH_HOME/profiles/web/` 下的 `harness/`),并在该目录的 `cordis.patch.yml` 中追加:
96
131
 
97
132
  ```yaml
98
133
  - insert:
99
134
  - id: dsh-bridge
100
- name: './dsh-bridge.mjs'
135
+ name: './harness/dsh-bridge.mjs'
101
136
  ```
102
137
 
138
+ > `dsh-bridge.mjs` 会 `import './session-target.mjs'`——**两个文件必须在一起**,只复制前者会直接加载失败。
139
+
103
140
  重启 harness。默认共享工作目录为 `D:\Harness`,可用环境变量 `DSH_BRIDGE_WORKSPACE` 覆盖。验证:
104
141
 
105
142
  ```
106
143
  GET http://127.0.0.1:3080/api/dsh-bridge/status
107
144
  ```
108
145
 
109
- > 手工方式必须用相对路径 `'./dsh-bridge.mjs'`,因为文件就在 profile 目录里;npm 方式则用包子路径 `@whaletalk/dsh-codex-collab/bridge`,两者不要混用。
146
+ > 手工方式必须用相对路径(文件就在 profile 目录里);npm 方式则用包子路径 `@whaletalk/dsh-codex-collab/bridge`,两者不要混用。
110
147
 
111
148
  ### 2. Codex 侧(二选一或都用)
112
149
 
@@ -158,12 +195,27 @@ tunnel-client run --profile dsh
158
195
 
159
196
  **Codex 工作区会话**(MCP 工具就绪后):
160
197
 
161
- > 用 dsh_task 让 DeepSeek 生成一个随机密码 CLI + 测试 + README,放在当前项目目录,完成后你用 dsh_read_file 验收,再 dsh_review 评审
198
+ > **新建子代理**:用 dsh_task 让 DeepSeek 生成一个随机密码 CLI + 测试 + README,放在当前项目目录,完成后你用 dsh_read_file 验收,再 dsh_review 评审
199
+ >
200
+ > **接进原对话**:先用 dsh_sessions 按标题找到用户正在用的那条会话,再用 dsh_task 带 sessionId 把下一步指令投递进去(不要新建会话)
201
+
202
+ **MCP 工具**(Codex 侧首选,工具名带 `mcp__dsh__` 前缀):
203
+
204
+ ```jsonc
205
+ // 1) 找到会话(只读)
206
+ dsh_sessions({ "query": "按文档启动OKX策略实验计划" })
207
+ // → { "items": [{ "sessionId": "session-8d481ad9-…", "snippet": "按文档启动OKX策略实验计划",
208
+ // "agentAvailable": true }], "matchedBy": "list" }
209
+
210
+ // 2) 投递进那条会话
211
+ dsh_task({ "instruction": "继续推进第 3 步…", "sessionId": "session-8d481ad9-…" })
212
+ // deliver 可选 "queue"(默认,排队)或 "steer"(插入当前回合)
213
+ ```
162
214
 
163
215
  **命令行**(npm 安装后直接用;源码方式用 `node <脚本路径>`):
164
216
 
165
217
  ```bash
166
- # 新建子代理(原有行为)
218
+ # 新建子代理(默认行为)
167
219
  dsh-task --in "<指令>" --cwd "<目录>" [--lane backend] [--model fast|pro] [--commit]
168
220
 
169
221
  # 接进已有会话:先找,再派
@@ -180,19 +232,74 @@ dsh-task --list | --status <taskId> | --cancel <taskId> [--force]
180
232
  ```bash
181
233
  # 1) 找到(只读,不创建任何东西)
182
234
  dsh-task --sessions "按文档启动OKX策略实验计划"
183
- # → {"items":[{"sessionId":"session-8d481ad9-...","snippet":"@okx-strategy-lab/ 开始按照文档进行计划"}]}
235
+ # → {"items":[{"sessionId":"session-8d481ad9-…","snippet":"按文档启动OKX策略实验计划",
236
+ # "agentAvailable":true}],"total":1,"matchedBy":"list"}
184
237
 
185
- # 2) 接通(指令投递进那条会话,跑完把这一轮的助手回复作为汇报返回)
186
- dsh-task --in "<继续推进的指令>" --session "session-8d481ad9-..."
238
+ # 2) 接通(投递进那条会话;这一轮的助手回复作为汇报返回,只回报本轮新增文本)
239
+ dsh-task --in "<继续推进的指令>" --session "session-8d481ad9-…"
187
240
  ```
188
241
 
242
+ `matchedBy` 说明"找到"走了哪条路:`search` = 会话搜索索引;`list` = 索引被部署禁用时退回遍历列表 + 标题投影(都不激活 Agent)。
243
+
189
244
  失败一律返回稳定 `reason` 且**不创建任何会话/工作区**:`session-query-empty`(没命中)、`session-ambiguous`(多条命中,附 `candidates`)、`session-not-found`、`session-busy`、`session-writer-held`(会话被别的写入方占用)、`session-archived`、`session-not-accepted`、`session-timeout`、`session-cancel-refused`(取消会话目标默认被拒,需 `--force`)。
190
245
 
246
+ ## 反向通道:让 DSH 调用 Codex
247
+
248
+ 上面的链路都是 **Codex → DSH**。反过来的 **DSH → Codex** 也能做,但要分清两种含义:
249
+
250
+ | 含义 | 可行性 |
251
+ |---|---|
252
+ | 让 DSH 调用 Codex(把 Codex 当执行器/评审员) | ✅ 两端原生支持,见下 |
253
+ | 让 DSH 往你**正开着的某条 ChatGPT/Codex 对话**里插一条消息、就地开一轮 | ❌ 做不到 |
254
+
255
+ 第二种做不到的原因:现有链路是 Codex 主动(它启动 `dsh-mcp` 子进程调工具),而 MCP 是
256
+ **客户端发起**的协议——服务端无法命令客户端开一轮。服务端→客户端只有 `notifications/*`
257
+ (纯通知,不触发回合)、`sampling/createMessage`、`elicitation/create`(取决于客户端是否
258
+ 实现,且不等于"在对话里跑工具");ChatGPT 侧同样没有公开 API 能向用户会话投消息。
259
+
260
+ ### 方案 A:反向通道已内置在本包里(推荐)
261
+
262
+ **装本包就同时得到两个方向**——`cordis.patch.yml` 里插了两行:`dsh-bridge`(Codex → DSH 派活)与 `codex-mcp`(DSH → Codex 反向调用)。原理是两端各有一个原生件:
263
+
264
+ - DSH 侧 `@deepseek-ai/dsh-mcp-client`(harness 自带):连外部 MCP 服务器,并把工具以 `mcp__<serverName>__<tool>` 注册进 `ctx.tools`;
265
+ - Codex 侧 `codex mcp-server`(stdio):把 Codex 暴露成 MCP 服务端。
266
+
267
+ 内置的那一行等价于:
268
+
269
+ ```yaml
270
+ - insert:
271
+ - id: codex-mcp
272
+ name: '@deepseek-ai/dsh-mcp-client'
273
+ config:
274
+ serverName: codex
275
+ transport: stdio
276
+ command: codex # 跨平台:SDK 用 cross-spawn,Windows 的 .cmd 垫片也能解析
277
+ args: ['mcp-server']
278
+ failOnStartupError: false # 没装/没登录 Codex 只是没这批工具,不会拖垮 harness
279
+ toolCallTimeoutMs: 600000 # 默认只有 60s,Codex 跑一轮常常不够
280
+ ```
281
+
282
+ - 前提:本机装了 Codex CLI 并已登录(`codex --version` / `codex mcp-server --help` 能跑)。
283
+ - **不需要反向通道**?在 profile 的 `cordis.patch.yml` 里覆盖一行即可关掉:`- id: codex-mcp` + `disabled: true`。
284
+ - 想单独用反向通道(不装本插件主体)可以用独立模板 [`templates/codex-mcp/`](templates/codex-mcp/README.md)。
285
+ - 装完需**重启 profile 进程**;连接失败只是这批工具不出现(日志里有原因)。
286
+ - 排查:若 `codex` 不在 DSH 进程的 PATH 上,把 `command` 换成 `node` + `args: ['<...>/@openai/codex/bin/codex.js', 'mcp-server']`,或直接指向平台 `codex.exe`。
287
+
288
+ ### 方案 B:worker 里直接跑 `codex exec`
289
+
290
+ ```powershell
291
+ codex exec "把刚才的 diff 审一遍,只回结论" --cd E:\proj
292
+ ```
293
+
294
+ 一次性、零协议改动;代价是每次都是新会话(无跨轮记忆),且需要执行 shell 的权限。
295
+
296
+ > 注意:插件自带的 `dsh_collab_send` / `dsh_collab_review` 是 **DSH 侧入口**,只回到同一个网关,**不经过 Codex**。要"叫 Codex 干活"用上面 A/B;要"让 Codex 那条对话继续",只能等 Codex 自己下一轮(`dsh_task --wait` 或 `dsh_task_status`)。
297
+
191
298
  ## 环境变量
192
299
 
193
300
  | 变量 | 默认 | 说明 |
194
301
  |---|---|---|
195
- | `DSH_BRIDGE_URL` | `http://127.0.0.1:3080` | 网关地址 |
302
+ | `DSH_BRIDGE_URL` | `http://127.0.0.1:3080` | 网关地址。**必须指向插件实际挂载的那个 profile 的端口**(DSH 客户端里就是 GUI 端口,例如 19387) |
196
303
  | `DSH_BRIDGE_WORKSPACE` | `D:\Harness` | 网关默认共享工作目录 |
197
304
  | `DSH_BRIDGE_ROOT` | `D:\Harness` | `dsh_read_file` 相对路径基准 |
198
305
  | `DSH_BRIDGE_HISTORY` | 多级降级 | 协作历史文件位置(默认 D 盘 → 用户目录 → 临时目录逐级降级) |
@@ -211,12 +318,26 @@ dsh-task --in "<继续推进的指令>" --session "session-8d481ad9-..."
211
318
  - **评审不支持会话目标**:评审员必须与编码会话隔离,"独立评审"才成立
212
319
  - session 目标不使用 `cwd`/`lane`/`model`/`--commit`(会话自带这些语义),传了会被判 `invalid-target`
213
320
  - 网关重启会丢失内存中的任务表(含 session 观察器),这是既有设计
321
+ - **替换包内容不会热重载**:升级后必须重启 profile 进程,否则跑的还是旧 JS 模块(HMR 只重挂组合,不复用新代码)
322
+ - **组合包被取消选中 = 插件完全不挂载**:此时所有 `/api/dsh-bridge/*` 都落到网关鉴权层返回 401(不是 404,容易误判成没装)
214
323
  - **DSH profile 的 pnpm 供应链冷却**:新发布的版本约 24 小时内会被 `minimumReleaseAge` 拒绝安装(`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`);管理器会把它写进 `pnpm-workspace.yaml` 的 `minimumReleaseAgeExclude` 才放行。刚发版就装不上属正常,不是包的问题
215
- - 升级已装组合包 = **卸载 → 重新安装**;卸载会把该包从 `dsh.profile.bundles` 移除,所以重装后**要确认它被重新选中**,否则插件不会挂载(表现为所有 `/api/dsh-bridge/*` 都落到网关鉴权层返回 401)
324
+ - 升级已装组合包:客户端插件页没有升级入口,官方姿势是**卸载 → 重装**;但卸载会把该包从 `dsh.profile.bundles` 移除,重装后**要确认它被重新选中**,否则插件不会挂载(表现为所有 `/api/dsh-bridge/*` 都落到网关鉴权层返回 401)。更省事的做法是直接 `dsh plugin add <包>@<版本>`,见上文「升级到新版本」
216
325
  - Codex Desktop Windows 本地市场技能注入 bug(见上,MCP 通道不受影响)
217
326
  - 动态插件环境无 `AbortSignal`,冷恢复失败时自动降级为一次性执行;宿主组合持久化版无此问题
218
327
  - ChatGPT Plus 写入型 MCP 的开放度取决于 OpenAI 产品策略
219
328
 
329
+ ## 开发与测试
330
+
331
+ ```sh
332
+ node test/session-target.test.mjs # 纯函数:目标判定 / 候选挑选 / 错误映射 / 基线切分 / 汇报选文
333
+ node test/dsh-bridge.test.mjs # 路由级:假 DSH 运行时 + 桩 peer,加载真实 bridge 跑真实路由
334
+ node --test test/*.test.mjs # 两个一起跑(CI 用的是这条)
335
+ ```
336
+
337
+ - 路由级测试会断言 **worker 分支确实调用了 `startContinuable`**、**session 分支只调用 `prompt` 且不建 owner/子代理**——这类"参数遮蔽/串线"缺陷只有在这一层才抓得到(v0.1.2~0.1.4 的 `deliver` 遮蔽 bug 就是它抓回来的)。
338
+ - CI(`.github/workflows/publish.yml`)每次 tag 都跑:语法检查 → 单测 → 包契约 → 版本号三处一致 → tarball 清单 → 干净目录安装 + CLI/MCP 冒烟 → 6 工具握手断言 → bridge 导出契约。**任何一步失败都不会发布**。
339
+ - 发布:`package.json` / `.codex-plugin/plugin.json` / `mcp/dsh-mcp.mjs` 的 `SERVER_VERSION` 三处同步改版本 → commit → 打 tag `vX.Y.Z` → 推 tag,CI 自动带 provenance 发布。
340
+
220
341
  ## License
221
342
 
222
343
  MIT
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Codex 主导的双向编码协作插件:ChatGPT 把编码任务下发给本机 DeepSeek Harness 的持久编码子代理执行,DeepSeek 在共享工作目录 D:\\Harness 中写代码并实时回传进度与汇报,Codex 读文件验收、反馈修正,直到通过。",
5
5
  "author": {
6
6
  "name": "FuJackGao"
package/cordis.patch.yml CHANGED
@@ -1,20 +1,45 @@
1
- # DSH Collab bundle layer — 双向编码协作网关。
1
+ # DSH Collab bundle layer —— 双向协作:Codex → DSH 派活 + DSH → Codex 反向调用。
2
2
  #
3
3
  # 安装(npm):
4
- # dsh plugin --profile web add @whaletalk/dsh-codex-collab
5
- # `dsh plugin add` 会把本包加入 profile 的 dsh.profile.bundles,并自动套用本
6
- # patch,无需手工复制 dsh-bridge.mjs。
4
+ # dsh plugin --profile desktop add @whaletalk/dsh-codex-collab
5
+ # `dsh plugin add` 会把本包加入 profile 的 dsh.profile.bundles,并自动套用本 patch。
7
6
  #
8
- # 下面这一行把宿主网关插件插进 bundle:
9
- # - id dsh-bridge —— 行 id。用户的 patch 层可用同 id 覆盖整段 config。
10
- # - name用包子路径而非相对路径(对比 './dsh-bridge.mjs'):只有这样从 npm 安装
11
- # 后解析器才能定位到包内文件,同时保持 profile 目录干净。
7
+ # 本 bundle 插两行:
12
8
  #
13
- # 依赖的服务:webServer / agents / subagents / tools 四个注入,加上运行时取用的
14
- # timer、sessionQuery、agentPresets、sessionPersistence、workspaceRegistry、llm。
15
- # 其中 webServer 由 dsh-web-app 提供 —— 因此本 bundle 只能挂 web / desktop
16
- # profile,headless profile 没有该服务会一直 pending。
17
- # 本插件不使用 workflowEngine,所以 web GUI 默认禁用 workflow 引擎不影响它。
9
+ # 1) dsh-bridge —— 宿主网关插件(Codex → DSH 的派活通道)
10
+ # - id 行 id;用户的 patch 层可用同 id 覆盖整段 config。
11
+ # - name 用包子路径而非相对路径(对比 './dsh-bridge.mjs'):只有这样从 npm 安装
12
+ # 后解析器才能定位到包内文件,同时保持 profile 目录干净。
13
+ # 依赖的服务:webServer / agents / subagents / tools 四个注入,加上运行时取用的
14
+ # timer、sessionQuery、agentPresets、sessionPersistence、workspaceRegistry、llm。
15
+ # 其中 webServer 由 dsh-web-app 提供 —— 因此本 bundle 只能挂 web / desktop
16
+ # profile,headless profile 没有该服务会一直 pending。
17
+ # 本插件不使用 workflowEngine,所以 web GUI 默认禁用 workflow 引擎不影响它。
18
+ #
19
+ # 2) codex-mcp —— 反向通道(DSH → Codex)
20
+ # 把 Codex CLI 当 MCP 服务端挂进来:DSH 侧 agent 会拿到 mcp__codex__* 工具,
21
+ # 可以把活交回 Codex。两端都是现成的(DSH 自带 @deepseek-ai/dsh-mcp-client,
22
+ # Codex 自带 `codex mcp-server`),这里只是配置。
23
+ #
24
+ # - command 写裸名 `codex` 即可跨平台:MCP SDK 的 stdio 用 cross-spawn
25
+ # (shell:false)spawn,它在 Windows 上会正确解析 npm 的 .cmd 垫片。
26
+ # 若你的 codex 不在 PATH 上,改成 `node` + args 指向
27
+ # `...\@openai\codex\bin\codex.js`,或直接指向平台 codex.exe。
28
+ # - toolCallTimeoutMs 默认只有 60s,Codex 跑一轮读仓库常常不够。
29
+ # - failOnStartupError:false:没装/没登录 Codex 时只是这批工具不出现并记一条
30
+ # 日志,不会拖垮 harness。
31
+ # - 不需要反向通道?在 profile 的 cordis.patch.yml 里加一行覆盖即可关掉:
32
+ # - id: codex-mcp
33
+ # disabled: true
18
34
  - insert:
19
35
  - id: dsh-bridge
20
- name: '@whaletalk/dsh-codex-collab/bridge'
36
+ name: '@whaletalk/dsh-codex-collab/bridge'
37
+ - id: codex-mcp
38
+ name: '@deepseek-ai/dsh-mcp-client'
39
+ config:
40
+ serverName: codex
41
+ transport: stdio
42
+ command: codex
43
+ args: ['mcp-server']
44
+ failOnStartupError: false
45
+ toolCallTimeoutMs: 600000
package/mcp/dsh-mcp.mjs CHANGED
@@ -6,7 +6,7 @@
6
6
  // 客户端(Secure MCP Tunnel / cloudflared)桥接给 ChatGPT 等远程产品。
7
7
  const GATEWAY = process.env.DSH_BRIDGE_URL || 'http://127.0.0.1:3080'
8
8
  const SERVER_NAME = 'dsh-bridge'
9
- const SERVER_VERSION = '0.1.5'
9
+ const SERVER_VERSION = '0.1.6'
10
10
  const PROTOCOL_VERSION = '2024-11-05'
11
11
 
12
12
  const log = (...args) => console.error('[dsh-mcp]', ...args)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whaletalk/dsh-codex-collab",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Codex × DeepSeek Harness 双向编码协作:Codex 主导派活与验收,DeepSeek Harness 编码子代理在共享工作目录执行并回传,独立评审子代理实际跑通构建/测试后出具报告。提供 DSH 宿主网关插件、零依赖 MCP 服务器与 Codex 技能三件套。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,6 +23,7 @@
23
23
  "harness/",
24
24
  "mcp/",
25
25
  "codex-plugin/",
26
+ "templates/",
26
27
  "cordis.patch.yml",
27
28
  "README.md",
28
29
  "LICENSE",
@@ -0,0 +1,84 @@
1
+ # templates/codex-mcp —— 反向通道:让 DSH 调用 Codex
2
+
3
+ > **注意:主包已内置这一行。** 装 `@whaletalk/dsh-codex-collab` 时会同时挂上
4
+ > `dsh-bridge`(Codex → DSH 派活)和 `codex-mcp`(DSH → Codex),不需要再单独装。
5
+ > 本目录是**独立版本**:只想用反向通道、或想单独调参时用。关掉内置的那一行只需在
6
+ > profile 的 `cordis.patch.yml` 里覆盖 `- id: codex-mcp` + `disabled: true`。
7
+
8
+ 把 **Codex CLI 当作 MCP 服务端**挂进 DeepSeek Harness,于是 DSH 侧的 agent(包括
9
+ 本插件派出去的 worker)会拿到 `mcp__codex__*` 工具,可以把活**交回 Codex**。
10
+
11
+ - DSH 侧负责连接的是 harness 自带的 `@deepseek-ai/dsh-mcp-client`(把外部 MCP
12
+ 服务器的工具注册进 `ctx.tools`,支持 `stdio` 与 `streamable-http`,带断线重连)。
13
+ - Codex 侧负责暴露的是 `codex mcp-server`(stdio)。
14
+
15
+ ## 装法
16
+
17
+ **A. 并进你现有的 profile patch**(推荐,最少文件):把 `cordis.patch.yml` 里那行
18
+ `insert` 追加到 `~/.dsh/profiles/<profile>/cordis.patch.yml` 数组末尾。
19
+
20
+ **B. 当作独立 bundle 安装**:
21
+
22
+ ```sh
23
+ dsh plugin --profile desktop add "<本目录绝对路径>"
24
+ ```
25
+
26
+ 两种方式都一样:**装完必须重启 profile 进程**(新增组合包不会热挂载),
27
+ 重启后工具才会出现在列表里。
28
+
29
+ ## 配置要点
30
+
31
+ | 字段 | 说明 |
32
+ |---|---|
33
+ | `serverName` | 工具命名空间,工具名形如 `mcp__codex__<tool>`;同时挂多个服务器时各自独立 |
34
+ | `transport` | `stdio`(本地进程)或 `streamable-http`(远端) |
35
+ | `command` / `args` / `env` / `cwd` | 仅 stdio:可执行文件、参数、追加环境变量、工作目录 |
36
+ | `failOnStartupError` | `false` = 连不上也照常启动 harness,只是没有这批工具 |
37
+ | `toolCallTimeoutMs` | 每次 `tools/call` 超时;**默认只有 60s**,Codex 跑一轮常常不够,建议 600000 |
38
+
39
+ ### `command` 怎么写(Windows 也能用裸名)
40
+
41
+ **默认写裸名 `codex` 即可,跨平台。** DSH 的 MCP 客户端走官方 SDK 的
42
+ `StdioClientTransport`,它内部用 **cross-spawn**(`shell: false`)spawn——cross-spawn
43
+ 在 Windows 上会正确解析 npm 的 `.cmd` 垫片。实测:
44
+
45
+ ```
46
+ cross-spawn('codex', ['--version']) → exit 0, "codex-cli 0.147.0"
47
+ ```
48
+
49
+ 只有当 `codex` 不在 DSH 进程的 PATH 上(或你想完全绕开 npm 垫片)时才需要换写法:
50
+
51
+ ```yaml
52
+ # 备选 1:node 跑垫片背后的 JS
53
+ command: node
54
+ args: ['C:\Users\<you>\AppData\Roaming\npm\node_modules\@openai\codex\bin\codex.js', 'mcp-server']
55
+
56
+ # 备选 2:直接指向平台二进制(路径随版本/架构略有不同)
57
+ command: 'C:\Users\<you>\AppData\Roaming\npm\node_modules\@openai\codex\node_modules\@openai\codex-win32-x64\vendor\x86_64-pc-windows-msvc\bin\codex.exe'
58
+ args: ['mcp-server']
59
+ ```
60
+
61
+ ## 验证
62
+
63
+ ```sh
64
+ codex --version # 需要 CLI 已登录可用
65
+ codex mcp-server --help # 应打印 "Start Codex as an MCP server (stdio)"
66
+ ```
67
+
68
+ 接好后在 DSH 侧让 agent 调一次 `mcp__codex__*`;工具没出现就去看 harness 日志
69
+ (连接失败会记录原因,且不会中止启动)。
70
+
71
+ ## 能做什么、不能做什么
72
+
73
+ | | 可行性 |
74
+ |---|---|
75
+ | 让 DSH 调用 Codex(当执行器/评审员) | ✅ 本目录的做法 |
76
+ | 让 DSH 往你**正开着的某条 ChatGPT/Codex 对话**里插消息、就地开一轮 | ❌ 做不到 |
77
+
78
+ 原因:现有链路是 Codex 主动(它启动 `dsh-mcp` 子进程调工具),MCP 是**客户端发起**
79
+ 的协议,服务端无法命令客户端开一轮;服务端→客户端只有 `notifications/*`(不触发
80
+ 回合)、`sampling/createMessage`、`elicitation/create`(取决于客户端实现,且不等于
81
+ "在对话里跑工具")。ChatGPT 侧同样没有公开 API 能向用户会话投消息。
82
+
83
+ > 另注:本插件自带的 `dsh_collab_send` / `dsh_collab_review` 是 **DSH 侧入口**,
84
+ > 它们只回到同一个网关,**不经过 Codex**。
@@ -0,0 +1,46 @@
1
+ # 反向通道:把 Codex 挂成 DSH 的一个 MCP 服务端。
2
+ #
3
+ # 谁提供什么:
4
+ # - DSH 侧:@deepseek-ai/dsh-mcp-client(harness 自带)——连外部 MCP 服务器,
5
+ # 并把它们的工具以 mcp__<serverName>__<tool> 注册进 ctx.tools。
6
+ # - Codex 侧:codex mcp-server(stdio)——把 Codex 暴露成 MCP 服务端。
7
+ #
8
+ # 用法(二选一):
9
+ # A) 把下面这行 insert 追加到你的 profile cordis.patch.yml 数组末尾;
10
+ # B) 把本目录当作一个 bundle 安装(路径写绝对路径):
11
+ # dsh plugin --profile <profile> add <本目录绝对路径>
12
+ #
13
+ # 注意:主包 @whaletalk/dsh-codex-collab 已内置等价的一行;本文件是**独立版本**,
14
+ # 用于只想单独挂反向通道、或想单独调参的场景。
15
+ #
16
+ # 装完必须**重启 profile 进程**:新增组合包不会热挂载,只有重启后工具才会出现。
17
+ # 之后在 DSH 侧的工具列表里找 mcp__codex__*(例如 mcp__codex__codex)。
18
+ - insert:
19
+ - id: codex-mcp
20
+ name: '@deepseek-ai/dsh-mcp-client'
21
+ config:
22
+ serverName: codex
23
+ transport: stdio
24
+
25
+ # 裸名 `codex` 跨平台可用:DSH 的 MCP 客户端用官方 SDK 的
26
+ # StdioClientTransport,内部是 cross-spawn(shell:false),在 Windows 上
27
+ # 也能正确解析 npm 的 .cmd 垫片(本机实测 exit 0)。
28
+ command: codex
29
+ args: ['mcp-server']
30
+
31
+ # 若 codex 不在 DSH 进程的 PATH 上,改成下面任一种:
32
+ # command: node
33
+ # args: ['C:\Users\<you>\AppData\Roaming\npm\node_modules\@openai\codex\bin\codex.js', 'mcp-server']
34
+ # 或直接指向平台二进制:
35
+ # command: 'C:\Users\<you>\AppData\Roaming\npm\node_modules\@openai\codex\node_modules\@openai\codex-win32-x64\vendor\x86_64-pc-windows-msvc\bin\codex.exe'
36
+ # args: ['mcp-server']
37
+
38
+ # 远端 Codex(有人把 mcp-server 包成 HTTP 时)用:
39
+ # transport: streamable-http
40
+ # url: http://127.0.0.1:3000/mcp
41
+ # headers: { Authorization: 'Bearer ...' }
42
+
43
+ # 启动失败不拖垮 harness:插件仍激活,只是不注册这批工具,日志里有原因。
44
+ failOnStartupError: false
45
+ # Codex 一轮可能跑很久(要读完仓库再答),给足超时;默认只有 60s。
46
+ toolCallTimeoutMs: 600000
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "dsh-codex-mcp-bridge",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "把 Codex CLI 当作 MCP 服务端挂进 DeepSeek Harness:DSH 侧 agent 获得 mcp__codex__* 工具,可反向调用 Codex。",
7
+ "dsh": {
8
+ "bundle": {
9
+ "patch": "./cordis.patch.yml"
10
+ }
11
+ }
12
+ }