🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

Codex 会话桥接 JUYANJY/dsh-codex-bridge

DeepSeek Harnessv0.1.0
JUYANJY15 天前有提交已提供中文文档扫描:含敏感能力

在 DeepSeek Harness 里观察并操控本地 CodexOpenAI会话。

30.7/100
综合分
1
GitHub 星标
42
npm 周下载
—/5
用户评分

数据截至 2026/10/18 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add @juyanjy/dsh-codex-bridge
npm 源 · @juyanjy/dsh-codex-bridge 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · model
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 15 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包@juyanjy/dsh-codex-bridge @ 0.1.0
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/14 00:35:02

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 3 处,展示前 3 条)
  • 读取本地文件
    src/app-server.js:44
    if (existsSync(candidate)) return candidate;
  • 执行外部命令来自配置/变量
    src/app-server.js:109
    const child = spawn(this.bin, this.args, {
  • 执行外部命令固定命令
    src/codex.js:117
    execFile("ps", ["-axo", "pid=,etime=,command="], { maxBuffer: 8 * 1024 * 1024 }, (error, stdout) => {
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-tools@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 观察本地Codex会话
  • 操控本地Codex会话

在 DeepSeek Harness 里通过 codex app-server 协议观察并操控本地 Codex(OpenAI)会话。

v0.1.02026-10-13
首次发布版本。 工具:共六个,走 codex app-server 的 JSON-RPC 协议(Codex 桌面应用说的也是这套):codex_status、codex_threads、codex_transcript、codex_watch、codex_send、codex_approvals。 面板:侧边栏里一个只读的 Codex 会话面板,四列如实呈现(等待批准、运行中、排队中、未观测),其中「未观测」就是字面意思。每张卡片带一行最后记录的动作,并原样引用该条目的状态,不做解读。 安装:pnpm add @juyanjy/dsh-codex-bridge(npm 上也有:或直接从本仓库安装)。 79 个单元测试,无需安装 Codex。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-codex-bridge 在 DeepSeek Harness 里观察并操控本地 Codex(OpenAI)会话。 插件与 codex app-server 通信——Codex 应用本身用的也是这套协议——实时功能全靠它: | | 读取 rollout .jsonl | 本插件 | | 对话记录 | 写入之后才能读 | 实时增量,外加轮询 | | 推理过程 | 只有已刷盘的部分 | 摘要增量随流推送 | | 速率限制额度 | 没有 | account/rateLimits/read | | 发送消息 | 做不到 | 队列(唯一的跨进程通道) | | 回应审批 | 做不到 | 仅限本桥接发起的轮次 | 它的定位是 DSH 侧的对应物,对面是 Codex 桌面应用里跑着的 Codex 会话:读那个会话在做什么,把下一条指令递过去,并且清楚哪些事根本做不到,而不是靠猜。 工具 | 工具 | 作用 | | codex_status | 账户、套餐、速率限制额度、本地进程、最新线程、待处理审批。Codex 连不上时降级为一条可读消息,不抛异常。 | | codex_threads | 最近的线程,可按搜索字符串过滤。 | | codex_transcript | 某个线程的条目,最新的在前。
展开完整文档(README 剩余 1 节)
dsh-codex-bridge

在 DeepSeek Harness 里观察并操控本地 Codex(OpenAI)会话。

插件与 codex app-server 通信——Codex 应用本身用的也是这套协议——实时功能全靠它:

| | 读取 rollout .jsonl | 本插件 |
| 对话记录 | 写入之后才能读 | 实时增量,外加轮询 |
| 推理过程 | 只有已刷盘的部分 | 摘要增量随流推送 |
| 速率限制额度 | 没有 | account/rateLimits/read |
| 发送消息 | 做不到 | 队列(唯一的跨进程通道) |
| 回应审批 | 做不到 | 仅限本桥接发起的轮次 |

它的定位是 DSH 侧的对应物,对面是 Codex 桌面应用里跑着的 Codex 会话:读那个会话在做什么,把下一条指令递过去,并且清楚哪些事根本做不到,而不是靠猜。

工具

| 工具 | 作用 |
| codex_status | 账户、套餐、速率限制额度、本地进程、最新线程、待处理审批。Codex 连不上时降级为一条可读消息,不抛异常。 |
| codex_threads | 最近的线程,可按搜索字符串过滤。 |
| codex_transcript | 某个线程的条目,最新的在前。 |
| codex_watch | 观察某个线程 N 秒,返回这段时间流过的内容,把实时通知流与对话记录轮询合并,并标注每个事件的 source。 |
| codex_send | queue(默认)、turn 或 steer。桌面应用占着线程写锁时回退到队列。 |
| codex_approvals | 列出待处理审批请求并作答。 |
| codex_queue | 查看线程上仍在等待的消息(action=list),用 action=delete 取消一条。报告 app-server 确认的结果,因为活跃会话通常先消费掉排队消息。 |
| codex_budget | 读取速率限制桶,判断 Codex 是否耗尽配额,并引用服务端自己的标志。usedPercent 高只是水位,不是上限,所以 100% 不会被报成「配额耗尽」。 |
| codex_ask | 在一次性 Codex 线程上问一个问题,可指定模型和推理强度,然后把答案原样交回开发线程(feed:false 则只读不回)。这是 DSH↔Codex 的快速对话通道;Codex 拒绝的模型覆盖会让调用失败,而不是悄悄改用默认模型。 |
| codex_handoff | 用线程自己的记录拼出接管简报——目标、逐字引用的指令、碰过什么、停在哪里、当时的配额,以及简报无从知晓的部分。saveTo 写入文件。action: "prepare" 把配额已耗尽的线程写成接管;action: "claim" 记录某人或本会话已实际接管。 |

面板

同一份投影在 Harness 里也是一个面板:侧边栏有一行 Codex,点开是一块看板,列为 Needs you(红)、Blocked(橙)、 运行中(绿色)和未观察到(灰色),按此顺序——四种状态定义在 src/task-state.js 里,每个状态一条规则。

所有判断都在宿主上完成,用纯函数实现,所以面板无法编造协议从未报告过的状态。每张卡片显示状态、该状态是 reported 还是 inferred、背后的原因、所依据的证据、最新记录的轮次状态条,以及进度条——仅当 Codex 报告了分母时才显示进度条(目标 token 预算,或计划步骤数)。没有分母时,卡片显示它真正拥有的计数,并注明 no progress denominator reported,而不是凭空画一根进度条。

六条规则保证判断诚实:

- 某线程持有本连接负责的审批时,状态为 Needs you,即使它同时还有排队消息,也绝不归入 Blocked。
- 运行中 意味着 Codex 报告该轮次正在推进,或 本桥接的连接看到了 turn/started 且尚未看到它结束,或 rollout 在几秒前被触碰过——最后一种情况会标注为 inferred。第四列是 未观察到,绝不是「空闲」:连接作用域协议里的沉默,不能证明什么都没发生。
- 每张卡片都带一行 last:rollout 报告的最新条目,排除加密推理,并原样打印该条目自身的状态。它报告线程最后做了什么,并不声称有轮次正在运行。
- 时长是判断的一部分,不是装饰,而且时长取的是轮次自身的结束时间(completedAt),绝不是线程最后被触碰的时间——打开线程或重启 Codex 都会更新 updatedAt,否则一天前的失败会看起来像新的。失败的轮次在新鲜期内是 Needs you;在没有目标的线程上,超过 FAILURE_ATTENTION_MS(48 小时)的失败保留错误文本作为证据,卡片归于灰色。看板第一次实际运行出现了三张红卡,失败时间分别是几秒前、3.6 天前和 12.8 天前,只有第一张需要处理——一根永远清不空的红列,人们会不再看它。同样的失败如果发生在仍带目标的线程上,无论多久都保持红色,因为目标是 Codex 自己对「本应运行的工作」的正式声明。
- 队列、条目、轮次和目标的检查都是采样的(每次刷新有线程数上限,全部记录在快照的 probe 块里),看板会说明这一点,而不是把部分读取当成全量呈现。
- 账户行和配额行与 codex_budget 使用同一个判定函数,配额达到上限时给出警告,并引用服务端的标记。

Codex 用尽时:先准备,再认领

配额达到上限是这里唯一不重试的失败——它不是运行停止了,而是账户用尽了,而一张永远无法改变的红卡,人们会不再看它。所以配额卡片提供 Prepare a takeover:插件会写入交给 <project>/.codex-handoff/<threadId>-.md 的交接简报,卡片上也是这么写的。

准备好的简报不等于交接,面板一直这么说。 插件无法推入 Harness 会话,所以 claimed 只能由显式的 codex_handoff action=claim(或卡片上的 Mark taken over 按钮)设置。在那之前,卡片显示 takeover prepared, unclaimed,并附上那句话。记录在本次运行期间留在内存里;文件落在磁盘上,留给下一个查看的人。

面板上的控件几乎全是只读的,只有一个能触达 Codex。Refresh 重新读取快照。Takeover brief 渲染出与 codex_handoff 相同的 markdown,带 Copy 和 Close 按钮。Pause this thread / Resume this thread 让自动驾驶不再碰那一个线程。Prepare a takeover 和 Mark taken over 驱动本地接管存储——前者只在卡片确实请求时可用,后者只在前者之后可用。Evaluate one pass 通过同样的守卫跑一次自动驾驶,所以自动驾驶关闭时它什么也不写。

Keep Codex moving for 30m 是唯一给自动驾驶上膛的控件。上膛期间(也只有那时),宿主侧定时器可以通过 thread/queue/add 往 Blocked 线程,或往 Needs you 线程(其失败被监督者判定为暂时性)排入一条续跑消息——与 codex_send 用的是同一个写入。

它发送什么

不是一句干巴巴的「continue」。每条自动消息都是一份监督简报,由该线程自己的记录构建——且只来自它:Codex 拿到的目标 objective、Codex 自己最后一条 agentMessage 原文(连同其阶段)、最新一轮的状态,失败时还有 Codex 记录的错误文本以及那是多久以前、该轮的条目计数、队列是否仍未消费。不转述,不编造;记录为空的地方简报会直说(这个线程没有记录目标、没有留下可读的回复文字)。

续跑,不要重放

发送监督消息之前,会用 git status --porcelain 读取线程的工作目录(只读,5s,绝不致命)。续跑不是重跑:如果目录里已有未提交的改动——或者失败的那一轮自己记录了文件变更——简报会写 工作区状态:the working directory already has N uncommitted change(s) 并列出它们,后面跟 不要重做已经完成的修改。目录读不到时(不是仓库、git 缺失),简报会说明无法确认,并把任务当作 continue, do not redo;目录干净时简报也会说明,这样重试就是安全的。这项检查无法知道 Codex 是否已经做完并提交了——这正是简报里「what this cannot know」那一节的用途。

它会接什么、不接什么

真正需要人时,红灯线程保持红灯。失败从 Codex 自己的错误文本分类,只有两类会重试:
- 可重试 —— transient(流中断、传输/网络错误、502/503/504、超时)和 context(上下文窗口耗尽)。这些是中途停下的运行,不是决策,所以简报里写的是 这类失败可以直接重试,不必等人。
- 永不重试 —— quota(用量上限、速率限制、支出控制)、auth(凭据、401/403)和 unknown,即模式列表识别不出的任何情况。简报里则说不要重试,并说明它需要什么。

线程在等审批、某一轮提了问题、队列非空、某一轮在 90 秒内动过、同一轮卡住两次,或者触到每线程与每轮的上限,都会让它停下。两次发送失败就中止该线程,条带会写明这一点;手动暂停的线程会被跳过,并显示 autopilot paused here 标签。启用状态 30 分钟后自动过期,Stop keeping it moving 立即结束它,每个决策——已发送、已跳过、已中止,连同它发送的消息全文引用——都列在条带里。失败的卡片带一行 retryable failure (transient) / needs a person (quota),引用错误信息,这样主管做了什么决定、为什么,在卡片上就能看到,不只是在日志里。它从不替人回答审批:那仍然由人来做。

分类是对 Codex 自身错误字符串做模式匹配——是启发式,不是诊断,模块在它产生的每条字符串里都这么说。它按失败即关闭来写:识别不出的失败留给人处理,而不是盲目重试。

客户端那一半是纯 JS,由 Web 客户端加载——没有构建步骤,和随附的客户端插件一样,页面加载时从磁盘重新读取。宿主那一半在启动时导入,所以宿主改动需要重启 Harness。

你不能做什么,以及为什么

其中五项是结构性的,不是缺功能——完整证据见 docs/limitations.md:

1. 桌面应用对它打开过的每个线程持有独占写锁,即使空闲时也一样。所以这些线程用不了 turn/steer,queue 是唯一的写入路径。
2. 审批发给拥有该轮的客户端。 对 Codex 应用正在跑的某一轮,codex_approvals 什么都看不到,也无法替它回答。通过这个协议从这里审批应用的轮次是不可能的。
3. 实时增量只发给拥有连接。 观察桌面拥有的线程可行,但走的是轮询,所以最多落后约 1.2 秒,且以 source: "transcript" 到达。
4. 推理正文是加密的。 你拿到的是已发出的摘要——没有时渲染为 (reasoning not exposed: encrypted)——而不是隐藏的思维链。
5. 这个插件无法推入 Harness 会话。 没有协议方法能把 Codex 线程的状态交给另一个进程,面板由页面调用,而不是反过来。因此接管是准备好的给人(或后续 Harness 轮次,通过 codex_handoff action=claim)用,绝不注入。

另外:codex_send 是真正的写入,而看板的自动驾驶是第二种写入,范围窄得多(只排队,点击才启用,有上限,会过期,且记录日志)。排队的消息很快就会被取走——测试中几乎立刻取走——所以排队就是发送,不是草稿。
codex_queue action=delete 能取消还在等待的条目,但这是竞态而非撤销:工具报告的是 app-server 自己的答复,而不是假定消息从未发出。

安装

作为 bundle(从 npm 或从 GitHub)

这个包自带 dsh.bundle.patch,所以安装它并在 dsh.profile.bundles 里列出它的配置档,无需手写 YAML 就能挂载。它已发布到 npm,包名 @juyanjy/dsh-codex-bridge,所以两种来源都行:

cd ~/.dsh/profiles/desktop
pnpm add @juyanjy/dsh-codex-bridge # from npm
pnpm add "git+https://github.com/JUYANJY/dsh-codex-bridge.git" # or straight from GitHub

然后在该 package.json 的 dsh.profile.bundles 里加上 "@juyanjy/dsh-codex-bridge"。加载器读的就是这个列表:它从配置档的 node_modules 解析每个列出的名字,并合并其声明的 dsh.bundle.patch。DSH 插件 UI 会为 bundle 完成这两步,而 dsh plugin --profile desktop add "<spec>" 会在配置档目录内转发给 pnpm。

要写完整的 git+https:// URL——github:user/repo 简写走 SSH,在没有 GitHub SSH 密钥的机器上会失败。GitHub 路线已用真实配置档的副本验证过:pnpm 拉取 codeload.github.com/JUYANJY/dsh-codex-bridge,安装 node_modules/@juyanjy/dsh-codex-bridge,整个检出内容都会到位——cordis.patch.yml、每个 src/.js,以及本仓库的 tests/、scripts/ 和智能体文档。

npm 路线安装的是已发布的 tarball,它是检出内容的子集:src/、cordis.patch.yml、README.md、LICENSE,以及两份面向用户的文档(docs/limitations.md、docs/protocol.md)。它不含 tests/,不含 scripts/,也不含 docs/agents/ 或 docs/research/ 中的任何内容。本文件刻意不固定文件数和 shasum——两者每次发布都会变,所以向你即将安装的版本查询 registry:

npm view @juyanjy/dsh-codex-bridge version dist.fileCount dist.unpackedSize dist.shasum

从检出安装(开发路线)

如果要改这个仓库,或者让配置档跟踪工作树而不是拉取的副本,也可以把插件 vendor 进来并按名字加载。脚本会创建两个符号链接,把已有的 vendored 副本移到一边(绝不删除),并记录所做的操作,以便回滚:

node scripts/install.mjs --dry-run # show the plan
node scripts/install.mjs # apply it
node scripts/install.mjs --write-config # also append the loader entry if missing

默认写入 ~/.dsh/profiles/desktop;用 --profile <dir> 或 DSH_PROFILE_DIR 覆盖。

包名是 @juyanjy/dsh-codex-bridge,是我们的包,已发布到 npm。不带作用域的 dsh-codex-bridge 属于另一个无关项目,所以软链接和 loader 条目都不用这个名字。两条安装路径解析到同一个带作用域的包名:

| 路径 | 安装目录 | 条目 name |
| bundle | node_modules/@juyanjy/dsh-codex-bridge | @juyanjy/dsh-codex-bridge(随 cordis.patch.yml 一起提供) |
| checkout | node_modules/@juyanjy/dsh-codex-bridge → vendor/@juyanjy/dsh-codex-bridge | @juyanjy/dsh-codex-bridge |

Cordis 条目的短 id 仍是 dsh-codex-bridge,配置树和 plugin_manager 都按这个 id 寻址。浏览器工厂 id 不一样:它必须是完整包名 @juyanjy/dsh-codex-bridge,这样客户端 loader 才能认出已经预加载的工厂,不会把 bundle 再执行一遍。

如果 dsh.profile.bundles 里已经列出这个包,安装器就保留随包提供的 bundle 路径,不再追加一行 profile 配置。否则 --write-config 会追加一行显式配置。只保留一条注册行,不要两条都用。

然后重启 DeepSeek Harness。这一步不能省:patchReload: live 重新读取的是配置,不是模块代码,所以正在运行的 Harness 仍然用着已经导入的模块(见限制 6)。

要撤销: bash
node scripts/uninstall.mjs --dry-run
node scripts/uninstall.mjs

profile 的 cordis.patch.yml 里的 loader 条目是手工维护的配置,绝不会被悄悄改动——条目缺失时,install.mjs 会打印出要粘贴的 YAML 原文;uninstall.mjs 会告诉你该删掉哪一段。

配置

每个条目都带同样的配置和同样的带作用域包名。bundle 路径从随包提供的 cordis.patch.yml 里取;--write-config 可以把等价的一行写进 profile。
yaml
- insert:
- id: dsh-codex-bridge
name: '@juyanjy/dsh-codex-bridge'
config:
binary: "" # explicit path to codex; empty = auto-detect
requestTimeoutMs: 30000

二进制解析顺序:

1. 显式指定的 binary
2. $DSH_CODEX_BIN
3. /Applications/ChatGPT.app/Contents/Resources/codex
4. /opt/homebrew/bin/codex
5. /usr/local/bin/codex
6. /usr/bin/codex
7. 裸 codex(在 PATH 上解析)

开发

两个命令都需要 checkout:tests/ 和 scripts/ 都不在 npm tarball 里(见 安装)。
bash
npm test # 228 unit tests, no Codex install required
node scripts/smoke.mjs # live handshake against the real app-server

tests/helpers/fake-codex.js 是真正的 codex app-server 替身:它在子进程里通过 stdio 讲协议,所以传输、分帧、关联和超时路径都是真跑,不是 mock。它的行为由通过环境变量:

- FAKE_CODEX_LOCK=1 — thread/resume 和 turn/steer 会返回 active-writer 错误,桌面端持有的线程就是这个行为。
- FAKE_CODEX_SILENT=1 — 永不回应,用于超时路径。

冒烟脚本是唯一需要安装 Codex 的测试,而且它不写入任何线程。

tests/client.test.js 在测试进程里渲染面板的 React 树,对照的是宿主路由真实会返回的快照,用的是最小化的 React 替身(无 DOM、无浏览器)。它覆盖座位、四个状态列、chip 及其依据、进度条(只有存在真实分母时才出现)、配额行及其警告、autopilot 条(默认关闭、启用、日志、中止、按线程暂停)、接管简报和失败路径。它不覆盖挂载两个座位的 shell,也不覆盖任何视觉部分——这些请用眼睛检查。

目录结构

src/index.js cordis entrypoint: name/inject/Config/apply
src/bridge.js one shared app-server connection, lazily started
src/app-server.js spawn, JSONL framing, request correlation, inbound requests
src/codex.js protocol payloads -> compact records
src/notifications.js which notification methods matter, and how to describe them
src/errors.js the active-writer error and the explanation shown to users
src/board.js the projection the tools and the board share
src/task-state.js the four states, the reasons behind them, and the progress rules
src/autopilot.js the opt-in queue-only continuation policy, and its log
src/supervise.js reads Codex's own failure text, and writes the brief handed back
src/quota.js the one "is Codex out of quota" predicate
src/handoff.js the takeover brief, built from a thread's own records
src/workspace.js "resume, do not replay": the read-only git status a pass sees
src/takeover.js what happens when the quota is gone: keep red, prepare, claim
src/board-channel.js the host route the panel calls (snapshot, autopilot, handoff, takeover)
src/client.js the panel itself; loaded by the web client, never by Node
src/tools/.js one factory per tool

环境要求

- Node >= 22(用到 node:test、ESM、randomUUID)
- 任何实时功能都需要安装 Codex;单元测试不需要

许可证

MIT — 见 LICENSE。
预览分享卡片长什么样 ↓JUYANJY/dsh-codex-bridge
分享 · DeepSeek Harness Hub
JUYANJY/dsh-codex-bridge

在 DeepSeek Harness 里观察并操控本地 CodexOpenAI会话。

回到顶部