dsh-plugin-devkit
Verified@effaf/dsh-plugin-devkit · v0.1.0 · MIT
DSH Plugin DevKit: runtime observation kernel, isolated debug boot, host contract tests, slot preview
Install
dsh plugin add @effaf/dsh-plugin-devkit Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
DSH Plugin DevKit
English | 中文
用于开发 DeepSeek Harness(DSH)插件的工具集: 一个可以在实时会话里查询的运行时检查器、一个用于测试的隔离启动器、无需浏览器的宿主契约测试, 以及面向客户端半边(client half)的槽位预览。
状态: 四个模块全部实现。547 个单元测试,外加六项真机检查 —— 跑在真实的 cordis 运行时、
真实的 DSH 启动,以及真实的一次模型轮次上。已在 DSH 0.1.5-rc.2 上验证。
社区项目。 本 DevKit 由社区维护,与 DeepSeek AI 无隶属关系,也不由其背书或提供支持。 「DeepSeek Harness」「DSH」指它所面向的上游平台。
快速开始
四个工具都在同一个 npm 包里。把运行时检查器挂进 DSH profile:
dsh plugin --profile web add @effaf/dsh-plugin-devkit
dsh plugin 会在 profile 目录里执行 pnpm,然后对账 dsh.profile.bundles ——
由于该包声明了 dsh.bundle.patch,它会自动加入层栈。重启 DSH 后 /debug health 即可回答。
三条 CLI 也在同一个包里,全局装一次就都在 PATH 上:
npm install -g @effaf/dsh-plugin-devkit # debug-boot、dsh-plugin-test、dsh-plugin-preview
要在自己的插件代码里用某个模块,直接引子路径:
import { createFakeContext } from '@effaf/dsh-plugin-devkit/fake-host'
import { noPending } from '@effaf/dsh-plugin-devkit/assertions'
不用 npm、直接从仓库来:
git clone https://github.com/CkEFFAF/dsh-plugin-devkit.git
cd dsh-plugin-devkit
npm install
dsh plugin --profile web add "$PWD"
为什么不用
npm install git+https://…? npm 直到 10.5 才支持 git 子目录;更早的版本会 静默安装整个仓库根目录,而不是你指定的那个包 —— 你拿到的是一个没有入口点、也不报错的文件夹。 安装已发布的包,或克隆后按路径安装,则在任何版本上都可用。已在 npm 10.1 + node 22 上验证。
环境要求
DSH 0.1.5-rc.2 —— 本 DevKit 开发与验证所针对的版本,四个包都用 engines.dsh 声明。
DevKit 只通过公开接缝接触宿主(ctx.debugger、/debug、CLI 退出码、JSON 报告),
所以相近的版本通常可用,但其他版本未经测试。
Node 22 或更高。dsh-plugin-preview 可选地使用系统 Edge/Chrome 截图、使用 esbuild 打包;
两者都在运行时探测,缺失时会明确报告,绝不会自行下载。
各模块的用途
四个模块都在同一个包里:@effaf/dsh-plugin-devkit。
| 模块 | 做什么 | 需要了解 |
|---|---|---|
dsh-debugger |
观察一个实时组合:有界时间线、/debug 命令,以及可编程的 ctx.debugger |
ctx.debugger、/debug |
dsh-debug-boot |
启动隔离的 DSH profile,让真机检查永远不碰你的日常环境 | debug-boot CLI |
dsh-plugin-test |
不开浏览器断言宿主行为:假 Cordis 宿主 + JSON 报告 | dsh-plugin-test CLI |
dsh-plugin-preview |
把客户端半边挂进假槽位外壳,按官方主题尺寸近似渲染 | dsh-plugin-preview CLI |
dsh-debugger 是运行时检查器,不是源码级单步调试器 —— 需要断点请用 NODE_OPTIONS=--inspect
配合编辑器 attach(DevKit 自己的 /debug health 也会提醒你)。
它能做什么
- 问一个正在运行的组合现在什么状态。
/debug health给一句结论;/debug plugins --not-active点名一个从未激活的插件,以及它在等哪个服务;/debug services显示谁提供了什么。 - 把一次调用从头追到尾。
/debug trace <callId>返回共享同一 correlation id 的全部记录 —— 一次工具调用就是pre-execute → execute → result,带耗时。 - 看见模型轮次,而不只是工具调用。 纯文本的一轮也会留下一条
llm/stream记录, 含 provider、model、消息计数,并关联到它所属的 session。 - 在副本上复现故障。
debug-boot从随包模板派生一个一次性 profile, 真机检查永远不碰你的日常实例。 - 不开浏览器就证明插件的宿主契约。
dsh-plugin-test把插件挂到假 Cordis 宿主上, 返回稳定 schema 的 JSON 报告。 - 看看客户端半边。
dsh-plugin-preview把它渲染进假槽位,按官方主题尺寸近似显示, light/dark × narrow/wide 四种变体。
以上全部都能在你已经打开的那个会话里查询 —— 不用 attach DevTools,不用开第二个窗口。
与同类工具的差异
DSH 自带若干检查面,社区也做了不少工具。它们回答的是不同的问题,本 DevKit 的设计目标是 与它们并排,而不是取代它们。
对比 DSH 自带的检查面
| 本 DevKit | dsh-experimental-inspector |
dsh-tool-cordis |
Plugins 设置页 | |
|---|---|---|---|---|
| 从哪用 | 聊天会话(/debug)与 CLI |
Chrome DevTools 经 CDP 连接 | 模型工具调用 | Web 设置页 |
| 实时组合(fiber 状态、pending/failed 根因) | 有 —— 直接点名在等哪个服务 | Elements 面板里的 Cordis 树 | 有 | 只读的 loader 清单 |
工具 / 命令 / LLM 时间线,按 callId 关联 |
有,有界并计数 | Console + Network 面板 | 无 | 无 |
| 采集负载里的密钥 | 进缓冲前就已脱敏 | 不脱敏(官方文档明示) | 不适用 | 不适用 |
| 能否改变组合 | 不能 —— 纯旁观 | 不直接改,但 CDP 授予任意求值 | 能 —— 创建并运行临时包 | 不能 |
| 获取方式 | 公开、MIT、单个 npm 包(@effaf/dsh-plugin-devkit) |
私有、实验性、不随发布 | 随 DSH 发布,需自行挂载 | 随 profile 自带 |
对比社区插件
下表的描述都引自各项目自己的仓库与 npm 页面。
| 项目 | 它是什么 | 本 DevKit 的差别 |
|---|---|---|
dsh-doctor |
「Deterministic diagnostics and recovery for DeepSeek Harness」—— WebUI 里的本机救援服务,外加 CLI(scan、boot、recover、checkpoint、rollback) |
Doctor 会修:把配置重置回健康检查点、对齐依赖、再验证启动。本 DevKit 只观察和报告 —— 有界时间线、pending/failed 根因、工具与 LLM 关联 —— 绝不写你的组合。 |
dsh-sseye |
「DeepSeek Harness 里的 LLM 调试控制台 —— 捕获每一次模型调用、看全内容、重放任何一次」 | 重叠最大:两者都挂 llm/stream waterfall。sseye 捕获完整 LLM 负载并能重放或改写调用;本 DevKit 只记标量、在入库前脱敏,覆盖的是整个组合而不只是模型调用。 |
@ddtcorex/dsh-maestro-devkit |
「DeepSeek Harness 通用开发工具箱 —— 可视化审查、HMR、样式检查器、Cordis/Govard/Skills 开发」—— 已在 npm 弃用:「Retired: duplicated DSH core, CDP, Supervisor, Govard, and skill capabilities without completing a demonstrated workflow」 | 现存最接近「同类 DevKit」的东西,而且已停止维护。本项目的承诺更窄:四个小工具,以及离线的槽位预览,而不是实时 HMR 与样式检查。 |
这些差异换来了什么:
- 四个工具,一个仓库。 观察实时组合、隔离启动、测宿主契约、预览客户端半边 —— 上面每一个替代品都只覆盖其中一件事。
- 它不会弄坏被观察的对象。 waterfall 探针原样返回
next()的引用 —— 返回副本会搞坏整个 组合的生成,因此有一个针对真实LlmRuntime的检查把它钉住。 - 密钥在入库前脱敏,而不是显示时才处理 —— 泄漏的 key 根本进不了缓冲。
- 证据不会悄悄消失。 缓冲有界、溢出被计数,JSON 报告带
summary.overflowed/recordsDropped,因此「丢了证据」的一次运行不可能被读成干净的通过。 - 它测的是契约,不是 mock。 假宿主镜像
normalizeDefinition与真实的execute(agent, line, …)签名 —— 这正是它抓到「单测全绿、真机上却什么都不做」那类插件的原因。 - 隔离是硬规则。 真机检查跑在派生 profile 上;永不激活的插件被报成
plugin-pending(退出码 7)并点名它在等的服务,而不是甩一段 loader 堆栈。 - 边界明说,不暗示。 不承诺像素级一致,截图只拍不比,任何东西都不经过检查器代理。
别人走得更远的地方,如实说:
dsh-sseye捕获完整的请求与响应 —— system prompt、tool schema、每一个流式分片、真实端点 —— 并且能重放或改写一次调用。本 DevKit 只记标量。dsh-doctor能动手:把坏掉的 profile 回滚到最近一次健康检查点,之后还会再次验证启动。 本项目不写你的环境。dsh-doctor与dsh-sseye都用裸包名发布,也是更成熟的项目 ——dsh-doctor单月就有数百次 npm 下载。本 DevKit 发的是@effaf/dsh-plugin-devkit,名字带 scope 而不是裸名, 下载量也从零开始。
它刻意不做的事: 源码级单步(那是 NODE_OPTIONS=--inspect 的活)、插件市场或安装 UI、
agent 轨迹工作台;也从不对自己注入 tools。
工作流
# 1. 针对假宿主跑契约测试 —— 不需要浏览器,不需要服务器。
node --test tests/*.test.mjs
dsh-plugin-test tests/cases.mjs --plugin .
# 2. 看看你的客户端半边长什么样。
dsh-plugin-preview --slot tool.view.mine --client ./client.mjs --serve
# 3. 挂上你的插件,启动一个隔离实例。
debug-boot --plugin ./index.mjs --port 8080
# 4. 在那个会话里:
# /debug health 一切都在活动吗?
# /debug plugins --name mine
# /debug plugins --not-active
# /debug events --category tool -v
# /debug trace <callId>
dsh-plugin-test
import { noPending, serviceActive, noSecrets } from 'dsh-plugin-test'
// The runner mounts this on its host before running your cases.
export const plugin = { name: 'my-plugin', apply }
export const cases = [
{
name: 'my service is provided',
run: ({ ctx, plugin: mine }) => {
if (!ctx.get('mine')) throw new Error('not provided')
},
},
{ name: 'nothing is stuck pending', run: ({ debugger: d }) => noPending(d) },
]
run 收到 { ctx, debugger, host, plugin, pluginError }。它可以什么都不返回(视为成功)、
返回 true,或返回断言辅助函数的返回值 —— 失败时抛错是通常写法,报告会原样带上你自己的消息。
退出码:0 全部通过,1 有用例失败,2 用法错误,3 模块或插件加载失败。
报告是稳定 schema 的 JSON,含 summary.overflowed 与 recordsDropped,
因此「证据被丢弃」的一次运行不可能被读成干净的通过。
dsh-plugin-preview
你的客户端半边导出 mount(el, { fixture, slot, scheme, viewport }),或一个同签名的默认导出函数。
页面会渲染 light/dark × narrow/wide 四种变体,并定义官方 --dsw-alias-* token 名,
因此按这些名字写的 CSS 能正常解析。
# 边写边看。
dsh-plugin-preview --slot tool.view.mine --client ./client.mjs --serve
# 一个可以直接打开的独立 HTML 文件。
dsh-plugin-preview --slot tool.view.mine --client ./client.mjs --inline-client --out page.html
# 每个变体一张 PNG,供你自己做截图 diff。
dsh-plugin-preview --slot tool.view.mine --client ./client.mjs --serve --shot ./shots
--serve 与 --inline-client 是两条不同的路径,原因来自实测:内联模块(blob:/data:)
既解析不了裸模块名,也解析不了相对路径,所以引用 react 的客户端会先用 esbuild 打平 ——
如果 esbuild 不存在,工具会拒绝,而不是写出一个静默显示占位内容的页面。
它不承诺像素级一致。 尺寸是近似值,页面自己也这么写;布局回归需要在真实外壳上做截图 diff。
--shot 只负责截图,不负责比对。
仓库结构
| 路径 | 内容 |
|---|---|
packages/ |
本包的四个模块 |
skills/plugin-devkit/ |
描述本产品不变量的 agent skill |
跑测试
npm test # 547 个测试
node --test "packages/dsh-debugger/tests/*.test.mjs" # 232
node --test "packages/dsh-debug-boot/tests/*.test.mjs" # 178
node --test "packages/dsh-plugin-test/tests/*.test.mjs" # 74
node --test "packages/dsh-plugin-preview/tests/*.test.mjs" # 63
先腾出 8080 端口。 debug-boot 的 CLI 测试会断言一次成功启动;如果有个在跑的 debug-boot
实例仍占着 8080,其中十二个测试会以 port-in-use 失败。
需要真机的检查
这些不属于 npm test —— 它们需要 DSH 检出目录或一台真实服务器。在你的 DSH 检出目录里运行:
cd /path/to/deepseek-harness
node --import tsx/esm /path/to/dsh-plugin-devkit/packages/dsh-debugger/tests/real-cordis.mjs
node --import tsx/esm /path/to/dsh-plugin-devkit/packages/dsh-plugin-test/tests/real-process.mjs
node --import tsx/esm /path/to/dsh-plugin-devkit/packages/dsh-debugger/tests/real-registration.mjs
node --import tsx/esm /path/to/dsh-plugin-devkit/packages/dsh-debugger/tests/real-llm-probe.mjs
node --import tsx/esm /path/to/dsh-plugin-devkit/packages/dsh-plugin-test/tests/real-fake-audit.mjs
| 检查 | 预期 |
|---|---|
real-cordis.mjs |
14/14 |
real-process.mjs |
15/15 |
real-registration.mjs |
8/8 |
real-llm-probe.mjs |
6/6 |
real-fake-audit.mjs |
20/20 surfaces AGREE |
以及隔离启动 smoke:它会在一台真实服务器上起 8099,并为自己准备一个一次性的 DSH_HOME:
node packages/dsh-debug-boot/tests/real-boot.mjs # 6/6
开工前值得知道的两个坑
0 字节的 $DSH_HOME/cordis.patch.yml 会让每次启动都失败。 DSH 会拒绝空的 patch 列表,
所以连 dsh --profile rescue --dump-config 也一样失败 —— 与本项目无关。
空文件不等于空数组:内容必须是 []。
一个永不激活的插件会让整个启动停住。 如果你的插件 inject 了组合里没有提供的服务,
DSH 会拒绝启动,/debug 也就永远跑不起来 —— 于是检查器无法解释这件事。
debug-boot 识别这种情况,并以 plugin-pending(退出码 7)报告,同时点名它在等哪个服务。
许可证
MIT —— 见 LICENSE。