Claude Code Mods 与 DSH Plugins:兼容边界与迁移

作者
DeepSeekAgent.io 编辑部
发布
更新

DeepSeek Harness v0.2.1-alpha.1 增加了实验性 Claude Code Mods Bridge。它没有把 DSH 变成 Claude Code,也不是“一键安装所有 Mod”的兼容模式;它验证的是一个更具体的判断:Claude Code Mod 的 Hook API 有一部分可以作为 DSH Plugin 的上层接口运行。

理解这条边界,才能判断一个 Mod 是可以直接包装、需要重写,还是依赖 Claude Code 内部能力而暂时无法迁移。

两套扩展模型如何对应

Claude Code Mod 的核心入口是 register(on, options)。它通过 on 订阅 Engine 事件,再通过 $ 调用 Session、工具、文件、UI 等能力。DSH 的原生扩展单元则是 Cordis Plugin,由 Profile 组合并通过 Harness Service 和事件管线工作。

Bridge 使用 defineMod 完成适配:

import { defineMod, type ModOn } from '@deepseek-ai/dsh-experimental-claude-code-mods'

declare const register: (on: ModOn, options: Readonly<Record<string, unknown>>) => void

export default defineMod({
  name: 'token-weather',
  version: '0.1.0',
  root: import.meta.dirname,
  register,
})

包装后的 Mod 按 Cordis Plugin 加载,配置来自 defineMod 的默认值与 cordis.yml 覆盖项。Bridge 必须先挂载,Mods 再按顺序加入 Hook Chain。

当前能够映射的能力

Claude Code Mod 能力DSH Bridge 状态
session.start / session.end根 Agent 创建与销毁时触发,Sub-agent 不触发
prompt.submit可改写用户文本、追加 Context 或丢弃 Prompt
turn.start / turn.complete映射到 Agent Turn 生命周期
tool.call可观察、拒绝、直接返回结果或改写执行后的结果
command.run支持 Mod 注册和处理命令
ui.render只支持输入框上方的 AbovePrompt Band
$.tool / $.command可注册、调用与列出工具或命令
$.fs / $.process / $.http支持受 Bridge 约束的文件、进程和网络操作
$.state / $.store支持 Session 内状态和每插件持久化存储

官方三个样例覆盖了不同层次:Token Weather 读取用量并绘制状态;Blast Radius 在命令执行前提供风险确认;Replay Theater 记录 Edit/Write 并回放差异。这说明 Bridge 已能承载“观察—拦截—交互”的基本闭环。

为什么不能把它称为完整兼容

Bridge 没有实现 Claude Code 的完整 Engine。以下差异会直接影响迁移:

  • tool.call 在 DSH 权限判断之后触发,不能改写已经记录的工具名称或参数;
  • Pane、焦点、滚动、输入组件与多数 UI 事件没有实现;
  • agent.spawn、prompt.context、tool.check、engine.create 与 Telemetry 事件不会触发;
  • $.model、$.agent、$.settings、$.telemetry 等命名空间尚未提供;
  • Claude Code 的 user/project/managed Tier 在 DSH 中统一作为 user 处理;
  • 正式安装包不会自动转译 .ts Hook 模块,应发布可由 Node 直接加载的 JavaScript;
  • plugin.json 与 hooks.json 不会被 Bridge 读取,身份和配置需要进入 defineMod 与 cordis.yml。

官方对现有大型 Mods 的源码核对也验证了这一点:依赖 Pane、Telemetry、agent.spawn 或 Managed Policy 的项目不能原样运行。

安全边界比 API 兼容更重要

Mod 在 DSH Host 进程内执行,不受 Agent 命令沙箱保护。即使它通过 $ 接口访问能力,Hook 模块本身仍拥有 Node 全局环境:

  • $.env 可读写 Harness 进程环境;
  • $.http.fetch 可以访问网络;
  • $.fs 与 $.tool.call 以当前 Session 权限工作;
  • 模块代码还可能直接使用 Node 能力。

因此“能通过 Bridge 加载”不等于“可以安全安装”。审查时应把它当作普通本地 Plugin,而不是受限的提示词扩展。尤其不要在包含生产凭证的 Profile 中直接试跑来源不明的 Mod。

迁移评估:先做事件和能力清单

迁移一个 Mod 前,先从源码提取两张表。

第一张是事件表:

register() 使用了哪些 on(event)?
哪些事件 Bridge 会触发?
事件触发顺序是否与 Claude Code 相同?
Hook 是否尝试改写工具参数?

第二张是 $ 调用表:

使用了哪些 $.namespace.method?
Bridge 是否提供?
返回结构是否相同?
是否依赖 Pane、Telemetry、Managed Tier 或完整消息历史?

如果只有 prompt.submit、tool.call、命令、文件和 AbovePrompt UI,通常适合包装验证;如果核心逻辑依赖未触发事件或未实现命名空间,应改写为原生 DSH Plugin,而不是堆兼容补丁。

一条可维护的迁移路径

  1. 固定 DSH 0.2.1-alpha.1,不要跟随浮动 alpha。
  2. 用 defineMod 包装原 register,把身份与默认配置移入 spec。
  3. 在 cordis.yml 中先挂载 Bridge,再挂载 Mod。
  4. 使用 createModTestKit 重放事件,覆盖允许、拒绝、超时与错误路径。
  5. 对未触发事件和未实现 $ 方法建立明确的降级行为。
  6. 在隔离 Profile 中验证真实 Tool 权限、Session 恢复和插件卸载。
  7. 若适配代码开始承担大量 DSH 专用逻辑,改写为原生 Plugin。

什么时候选择原生 DSH Plugin

以下情况直接写原生 Plugin 更合理:

  • 需要完整 Sidebar 页面、配置页或多个 Client Slot;
  • 需要 Sub-agent、Compaction、Provider、Session Projection 等 DSH 服务;
  • 需要在权限判断前处理工具输入;
  • 需要精确控制 Plugin 生命周期、HMR 和依赖关系;
  • 目标只运行在 DSH,不需要与 Claude Code 共享同一 Hook 模块。

Mods Bridge 的价值是降低已有 Hook 逻辑的验证成本,而不是替代 DSH Plugin API。它证明了两套扩展系统存在可映射的公共子集,也把剩余差异列成了明确的工程清单。

相关阅读

参考资料