社区生态与扩展边界
这篇回答一个很容易混淆的问题:不修改 DSH 源码,怎样接入自己的功能?答案是使用已经存在的服务、事件、工具注册表、配置组合层或外部 hook 桥接;如果目标位置没有公开扩展点,就不能把任意运行时改写自动称为插件。
如果你只想先得到一个能照着判断的短答案,先读工具预算与插件责任决策卡;本篇再提供固定版本源码、社区仓库和 dsh-super-injector 案例的详细核验。
第一次读本篇时只需要先认五个标签:普通插件、Bundle、Hook bridge、patched fork、运行时注入器。后面的术语表是查阅用的;不必先背 Fiber、Loader 或 registry 的实现细节。涉及“工具多不多、模型会看到什么”的问题,先转到工具可见性与非侵入扩展,不要把它和本篇的身份分类混在一起。
本轮公开 GitHub 观测(2026-08-16)
下面是 2026-08-16(Asia/Shanghai)访问公开 GitHub 页面、raw 文件和未认证 repository search API 得到的观察。它们是带时间的证据快照,不是官方目录、推荐名单、安全审计或兼容性承诺;“项目自述”只证明仓库写了什么,“静态源码”只证明提交中存在什么,二者都不等于独立运行验证。
| 对象 | 本轮可复核的公开事实 | 证据等级与不能推出的结论 |
|---|---|---|
| 上游仓库 | deepseek-ai/deepseek-harness 的 GitHub 元数据把默认分支标为 master,本轮读取到的 HEAD 仍是固定提交 aa6c361a972c8369148dea7380bb5c21c24e07ec;仓库 topics 含 dsh-plugin。见上游仓库。 | 上游仓库元数据和固定源码是高等级来源,只能证明上游仓库当前公开了这些内容,不能把 topic 变成插件认证或安全结论。 |
dsh-plugin topic 查询 | 2026-08-16 查询 q=topic:dsh-plugin&per_page=30 返回 total_count=5142(第12 课记录的同日另一次读取是 4136,同一天的计数也在变);结果中同时出现上游仓库、目录、桌面应用和其他描述含 DSH 的项目。见查询 URL。 | 这是一次检索结果计数,受时间、索引、可见性和查询参数影响,不是“DSH 已验证插件数量”,也不是兼容项目数量。 |
| 普通 Bundle 样本 | omdsh-dev/dsh-annotation 的固定 README/package 自称 dsh.bundle + dsh.client、Node half 为空且“不改核心”;vlln/dsh-navbar 的固定 README 自称纯浏览器端 bundle、Node half 为空、0 patch。见批注 README和导航条 README。 | 这是项目自述加 manifest 的静态证据,支持“第三方 Bundle/客户端插件候选”的分类;没有证明上游背书、目标版本运行兼容、权限安全或卸载完整。 |
| 能力与宿主封装样本 | NanmiCoder/dsh-agent-teams README 自称提供协作工具、持久化状态和 Web UI;dsh-tui/dsh-tui README 自称是 out-of-tree plugin bundle、未 fork 上游,同时明确写着仍对 pre-release rc 线开发且恢复的测试尚未运行。见AgentTeams README和TUI README。 | README 可以证明项目声明和已写出的限制;不能把“plugin”“nothing is forked”或安装命令写成独立兼容性/安全结论。 |
| patched fork 样本 | rpmalouin/deepseek-harness 的 GitHub 页面标记为 forked from deepseek-ai/deepseek-harness,README 自称增加 graph-first review、OpenRouter routing 和 Hermes/delegation 三类集成;G36maid/deepseek-harness 页面也显示 forked from 上游,但 README 主要保留上游运行说明。见rpm fork 页面和G36 fork 页面。 | GitHub fork 关系是仓库元数据证据,README 增量是项目自述;本轮没有逐文件比较两个 fork 与上游的完整差异,因此不把它们写成“已验证 patched fork 兼容”。 |
| 注入器边界样本 | yjh051108/dsh-super-injector 的固定提交中可见 junction、ctx.loader.create()、ctx.loader.internal.loadCache、Fiber/registry 管理和宿主表清理;package.json 同时写有 private: true,cordis.patch.yml 只负责把引导器装入插件树。见注入器源码和注入器清单。 | 这是固定提交的静态源码证据,足以把它拆成“Bundle 引导器 + 运行时注入器”;不证明官方支持、生产可用、安全、卸载后无残留或跨版本兼容。 |
本文后续的“官方”只在明确限定为“上游仓库交付的源码/包”时使用;对社区项目统一写“项目自述”“仓库元数据”或“本轮静态观察”,不写官方背书和安全结论。
2026-08-17 的只读刷新
次日用已登录的 GitHub CLI 只读重查了仓库元数据和 topic 搜索。q=topic:dsh-plugin&per_page=30 返回 total_count=5511;上游 deepseek-ai/deepseek-harness 的 topics 包含 dsh-plugin,yjh051108/dsh-super-injector 的 topics 是 dsh、dsh-plugin,而 shine-233/dsh-plugin-debug 当前没有 topic——一天之内计数变了 369,正好说明它只是检索快照,不是注册表。
本次刷新仍然只核对元数据和检索结果,没有安装、启动或卸载任何项目;判断候选项目的完整流程见下文六步。
先给结论
“我 patch 了源码,所以可以自由 hook”需要把“自由”限定在自己的 fork 内:你可以修改事件声明、生产者、消费者和注册过程,因此能在自己的版本里加入新的 hook;这证明你拥有一份修改版源码的控制权,不证明它是官方插件,也不保证任意插入位置都安全或稳定。
“不 patch 源码也能 hook”也正确,但这里的 hook 必须落在宿主已经提供的扩展点上,例如 ctx.on('tools/result', ...)、ctx.tools.register(...)、ctx.provide(...) 或官方文档列出的 waterfall 事件。
更准确的自我介绍可以这样写:
我维护的是基于 DSH 固定提交的源码 fork,并在 fork 中增加了内部 hook。若改用不修改上游源码的方式,则应通过 Cordis 插件、公开服务/事件、Bundle 的
cordis.patch.yml或官方 hook bridge 接入;依赖私有注册表、构建产物改写或进程注入的方案应标为兼容层、运行时补丁或非官方集成。
这里的四个词不在同一层:hook 说的是接入点,plugin 说的是扩展单元和生命周期,patch 说的是修改边界,injection 说的是把依赖或代码放进运行时的方式。
术语要分开
展开术语要分开(13 行)
| 术语 | 它描述的对象 | DSH 中的例子 | 能否直接称为官方插件 |
|---|---|---|---|
| hook | 一个可以观察、包装、转换或阻止流程的接入点 | tools/pre-execute、tools/result、ctx.on(...) | 不能单凭“有 hook”判断 |
| 官方扩展点 | 上游明确声明并给出类型、语义和生命周期的接口 | ctx.tools.register()、Cordis ctx.on()、ctx.provide()、ctx.effect() | 使用它的第三方代码可以是合规插件,但不等于官方维护 |
| 插件 | 一个由 Cordis 挂载、拥有 Fiber 生命周期的函数、类或对象 | 导出 apply(ctx) 的模块 | 只有发布者和维护归属得到官方确认时才是官方插件 |
| Bundle(组合包) | 带有 dsh.bundle manifest 和 patch 文件的可安装 npm 包 | cordis.patch.yml 插入插件行 | 包是官方还是社区的,要看维护者,不看 manifest 名字 |
| 配置 patch | 修改 Profile 插件树的 YAML 层,不改上游 TypeScript | --patch、Profile 的 cordis.patch.yml | 可是官方支持的组合方式,但不是源码 patch |
| 源码 patch | 修改上游源文件或构建产物并维护自己的差异 | 修改 vendor/cordis 或 packages/core | 叫 fork、patched build 或私有补丁更准确 |
| 依赖注入 | 通过公开服务接口提供实现,让消费者按名称获取 | inject: ['tools']、ctx.provide('myService', value) | 这是正常架构模式,不是偷偷注入 |
| 依赖声明 | 声明当前插件要等待哪些服务就绪 | inject: ['tools'] | 这是等待 provider 的依赖关系,不是事件 hook,也不负责注册服务 |
| 运行时代码注入 | 程序启动后把代码、替代实现或监听器塞进进程 | 覆盖模块导出、动态改写私有对象 | 通常是非官方运行时补丁,除非宿主明确定义该入口 |
| 注册表修改 | 改变插件、服务或工具的登记状态 | ctx.tools.register()、ctx.registry.plugin()、ctx.registry.delete() 是公开操作;直接改未文档化 Map 不是 | 公开操作可以由插件调用,但手工重建 Loader/Fiber 仍不是稳定的热插拔承诺 |
| 兼容层 | 把外部协议或旧接口翻译到公开扩展点 | Claude Code/Codex hook bridge | 可以是合规第三方插件,但不能冒称官方实现 |
| 私有 fork | 长期维护一份带源码修改的独立版本 | 固定上游 SHA、维护补丁分支 | 不属于上游官方发行物 |
| 冒用官方插件 | 使用官方包名、命名空间、标识或维护者身份误导用户 | 第三方代码伪装成 DeepSeek 发布 | 不应称为官方插件,并有供应链信任风险 |
“注册表”还有两个含义,不要混写。ctx.tools.register()、ctx.provide() 这类调用是通过公开接口登记资源;ctx.registry.plugin()、ctx.registry.delete() 是 Cordis Registry 暴露的登记和删除方法,但把它们用于手工重建 Loader/Fiber 关系,并不等于拥有稳定的热插拔公共契约。
ctx.events._hooks、loader.internal.loadCache、entry._dispose()、entry.fiber 和宿主内部表属于未文档化的实现状态,直接改写它们才是实现层篡改。Windows 注册表修改又是操作系统层的加载或配置手段,和 DSH 的 Cordis registry 不是同一个东西。
往下滚动时,右边五段解说明白一件事:四级边界加一级风险案例,每一级由谁动手、要付什么代价。读完这张阶梯图,你面对一个新扩展方案时就有地方放它。
## DSH 的真实扩展链固定提交中的扩展链可以按下面顺序阅读:
Cordis Context
-> Plugin / Fiber 生命周期
-> Service 与 Event
-> DSH 能力服务(tools、llm、agents、sessions 等)
-> 插件模块
-> Bundle 的 cordis.patch.yml
-> Profile、home patch、--patch overlay
-> Loader 启动最终插件树1. Context 是运行时入口
vendor/cordis/src/context.ts(见固定源码)定义根 Context 和子 Context。它通过代理把服务访问、事件方法和插件方法组合到 ctx 上,并支持隔离作用域;这不是一个允许随意写入私有字段的全局对象。
2. Plugin 和 Fiber 负责所有权
vendor/cordis/src/registry.ts(见固定源码)接受函数、类和带 apply 的对象插件,ctx.plugin() 返回一个 Fiber 句柄。
vendor/cordis/src/fiber.ts(见固定源码)记录插件状态、依赖和 effects。通过 ctx.on()、ctx.provide() 或 ctx.effect() 注册的资源,应归属于当前 Fiber,并在 Fiber 卸载时撤销。
3. Service 是能力的替换接口
vendor/cordis/src/service.ts(见固定源码)说明 Service 如何以名称注册到 Context,并随所属 Fiber 消失。
消费者声明 inject,然后使用 ctx.<service>;inject 只表示“本插件需要等待这个服务”,不表示它自己提供服务、改变派发顺序或拦截事件。它不需要导入某个具体 provider。这样才能在 Profile 中替换实现,也才能在测试中安装 fake provider,而不修改消费者源码。
4. Event 是观察和决策的扩展点
vendor/cordis/src/events.ts(见固定源码)提供 on、once、emit、parallel、serial、bail 和 waterfall。
普通观察者使用 emit 类事件;需要协作修改或作出决策时才使用带明确返回类型的 waterfall。只观察、不拥有决策权的 waterfall 监听器必须调用 next(),否则它会有意短路后续行为。
5. DSH 能力包定义产品级入口
工具扩展的真实入口在 packages/core/tools 的 README 和类型中,包括 ctx.tools.register()、ctx.tools.guard()、tools/pre-execute、tools/execute、tools/post-execute 和 tools/result。
模型适配、Agent、Session、系统提示词和客户端也各自有自己的服务或事件。不能因为某个内部函数能被调用,就把它当成跨版本公共 hook;先看该包 README、类型声明和扩展点说明。
工具事件不是同一种 Hook
工具流水线的事件名字很像,但职责和能否改写结果不同:
| 入口 | 作用 | 是否能改变结果 |
|---|---|---|
tools/pre-execute | 允许、拒绝或询问的 waterfall 门禁 | 可以作出类型化决策,但不能随意改写已记录的参数 |
tools/execute | 围绕实际执行的环绕包装层,例如 timeout、retry、metrics | 可以包裹执行并返回规范结果,必须遵守执行协议 |
tools/post-execute | 检查或变换结果、附加上下文、通过反馈阻止 | 可以按公开契约替换内容或规范值 |
tools/result | 结果物化后的只观察 live event,载荷被冻结 | 不能通过监听器替换结果,也不是权限授权 |
tool/result | Agent Loop 随后写入 Session 的持久事件 | 是日志事实,不是实时 hook |
因此,想记录结果先用 tools/result;想参与决策先读 tools/pre-execute 和 ctx.tools.guard() 的约束;不要把名称相近的 tools/result 和 tool/result 混成同一个事件。
6. Bundle 和 Profile 负责组合,不负责伪造身份
apps/cli/src/profile-boot.ts(见固定源码)负责把 Bundle 层、Profile 层、home 层和 --patch overlay 组合起来。
apps/cli/src/args.ts(见固定源码)把 dsh plugin --profile <name> ... 转发到该 Profile 的包管理目录;它不是给第三方包授予官方维护者身份。
官方 Bundle 入口包括 packages/bundle/base/src/index.ts、packages/bundle/headless/src/index.ts 和 packages/bundle/web-app/src/index.ts;它们通过 patch 文件装配插件树,并在需要时提供运行时 glue。
7. Hook bridge 是协议适配器
packages/hooks/hook-protocol/src/codec.ts 和 packages/hooks/hook-protocol/src/types.ts 是共享协议库,不是插件,也不负责向 Context 注册功能。对应链接见codec和types。
Claude Code 和 Codex 的桥接包把外部 shell hook 的输入输出翻译到 DSH 的类型化扩展点。桥接包可以是普通插件;协议库本身不能因为名字里有 hook 就被称为官方插件。
不改源码时的公开接入方式
| 目标 | 首选入口 | 典型代码或配置 | 说明 |
|---|---|---|---|
| 观察工具结果 | ctx.on('tools/result', ...) | 监听器插件 | 只读观察,不改变结果 |
| 允许、拒绝或询问工具调用 | tools/pre-execute 或 ctx.tools.guard() | 返回类型化决策 | 先看工具包规定的单调性和顺序 |
| 新增工具 | ctx.tools.register(...) | defineTool 或完整 ToolDefinition | 注册返回的 disposer 归当前 Fiber 管理 |
| 提供可替换能力 | ctx.provide()、Service、inject | provider + consumer | 服务名、配置和生命周期必须有清楚归属 |
| 接入外部 hook 协议 | 官方或自有 bridge 插件 | 协议输入输出翻译 | bridge 是兼容层,不应冒充上游实现 |
配置组合是另一类接入方式:把插件包放进 Bundle 的 cordis.patch.yml,或者使用 Profile 的 cordis.patch.yml 与 --patch overlay。它改变的是“哪些插件被装配”,不是“官方源码被改写”。因此上表的五类代码接入方式之外,还要单独记录这一类配置组合方式。
普通插件作者与宿主维护者的责任
普通插件作者应在公开 Service、Event、Tool API 和 Bundle 组合层内工作。若需求必须修改核心事件语义、私有 registry、模块缓存、进程或系统配置,不能把这些动作隐藏在普通插件安装里;这已经需要宿主或发行版维护者承担版本、权限、回滚和安全责任。
插件作者可以公开维护一个 patched fork,但此时对外身份应是“基于某个上游提交的发行版/兼容层维护者”,而不是“普通插件自动完成了侵入式修改”。安装说明要写清基线 commit、修改范围、权限、卸载和失败恢复。
外部 shell hook bridge 属于兼容层
固定提交中的 dsh-hooks-claude-code 和 dsh-hooks-codex 会把外部 shell hook 配置翻译成 DSH 事件监听器;源码中可以看到它们监听 agent/session-start、agent/pre-step、tools/pre-execute、tools/post-execute 和 agent/turn-stopping 等点。
这条路线不需要改 DSH 核心源码,但它仍然有清楚的前提:bridge 自己是一个普通 Cordis 插件,外部命令的输入输出必须遵守协议,配置路径、超时、错误和卸载都由 bridge 负责。它应称为 hook bridge 或兼容层,而不是“官方把任意脚本注入了核心”。
packages/hooks/hook-protocol 只提供协议 codec、匹配、执行结果解析和合并工具;官方 README 明确说明它不注册插件,也不注入运行时。把“协议库”“bridge 插件”和“操作系统进程注入”混成一个词,会让读者误判支持范围。
为什么源码 patch 后能“自由 hook”
源码 patch 可以直接增加新的事件名、改变事件生产者、把调用包在新中间件里,甚至改变私有 registry 的数据结构;因为生产者和消费者都在你的 fork 中,你可以同时修改两端。
这种自由度的代价是兼容性由你承担:上游更新可能改掉调用顺序、事件 payload、生命周期状态、构建入口或持久化格式;外部插件也无法仅凭官方版本的类型判断你的新 hook 存在。
因此,源码 patch 后新增的 hook 最准确的名称是“fork 私有扩展点”或“补丁版内部 hook”。只有当上游接受并文档化它,或者你的 fork 明确维护自己的公开协议时,其他人才能把它当作可依赖接口。
怎样判断一个方案属于哪一类
按下面的问题逐项回答,通常就能得到准确分类:
- 是否改了官方 TypeScript、C/C++、构建产物或 vendored 源码?如果是,属于源码 patch、patched build 或 fork。
- 是否只增加了自己的插件模块和
cordis.patch.yml?如果是,属于插件加 Bundle/配置组合层,不是源码 patch。 - 是否只调用公开的
ctx.on、ctx.provide、ctx.tools.register或文档列出的服务方法?如果是,属于正常扩展。 - 是否直接访问未文档化字段、替换模块导出、修改内部 Map 或改写已经注册的函数?如果是,属于 monkey patch、registry patch 或兼容层,不应宣传为稳定官方插件。
ctx.registry.plugin()和ctx.registry.delete()虽然是公开 Registry 操作,但把它们用于手术式重建 Loader/Fiber 仍需单独承担内部生命周期风险。 - 是否在进程外通过 DLL、启动项、Windows 注册表或其他系统机制改变加载路径?这属于 OS 级加载改写或运行时注入,不是 DSH Cordis 插件。
- 是否使用官方包名、官方命名空间、官方 logo 或暗示 DeepSeek 维护?如果不是上游发布物,就必须使用自己的包名和清晰的第三方声明。
- 是否能独立安装、卸载、测试,并在卸载后清理监听器、服务、子进程和文件 watcher?不能做到时,至少不能声称自己是生命周期完整的插件。
“能 hook”只回答了技术上能否插入某个时刻;“是不是插件”还要回答它是否有自己的模块边界、公开接入方式、生命周期、安装方式、测试和身份说明。
Windows 注册表、注入和信任边界
“注册表修改”如果指 Windows Registry,常见作用是改变启动关联、加载路径或系统集成位置。固定提交没有把 Windows Registry 记录为 DSH 插件装配机制;除非某个具体宿主明确读取某个 registry key,否则改注册表不会改变 Cordis 服务、事件或 Fiber 生命周期,也不会自动获得插件的卸载和版本语义。
“注入”如果指依赖注入,是 DSH 正常使用的架构词;如果指向运行中的进程注入代码,则是另一种高风险实现手段。两者都可以让代码进入运行时,但只有前者天然属于公开插件模型。
不要在学习材料中把 DLL 注入、模块劫持、私有 registry 改写写成插件教程。它们可能绕过宿主的信任、更新和清理边界,也可能违反软件分发或组织安全政策;研究时应标为非官方实验,并说明环境、权限和风险。
社区生态的分层
| 层 | 主要产物 | 读者应该看什么 | 可信度判断 |
|---|---|---|---|
| 上游核心 | DSH 源码、官方 Bundle、官方文档 | 固定提交、源码、测试、包 README | 以官方仓库和固定 commit 为准 |
| 官方扩展机制 | Cordis API、DSH 服务/事件、Bundle manifest | 类型、生命周期、配置层顺序 | 只有文档和源码共同支持时才称公共入口 |
| 合规社区插件 | 独立 npm/GitHub 包、自己的 Bundle | 包名、权限、依赖、测试、卸载行为 | 是第三方插件,不等于官方插件 |
| 协议兼容层 | hook bridge、旧接口适配器 | 输入输出转换、版本矩阵、失败策略 | 明确写“兼容”而不是“官方实现” |
| 私有 fork | 修改后的完整源码仓库 | 上游 SHA、补丁、同步策略、构建产物 | 维护者承担全部兼容成本 |
| 运行时补丁 | monkey patch、注入器、私有 registry 改写 | 进入时机、权限、回滚和供应链风险 | 通常是非官方且脆弱的集成 |
| 身份冒用 | 仿冒包名、官方 namespace 或发布者 | 包来源、签名、仓库归属、许可证 | 应视为信任风险,而不是生态扩展 |
这套分层也解释了为什么社区里会出现“看起来都能 hook”的方案:它们可能在不同层解决问题,不能只根据最终效果给出同一个名称。
dsh-super-injector:一个必须单独拆解的边界案例
这一类项目很适合放进教材,因为它同时使用了“官方装配入口”和“非官方运行时管理”。如果只看它能不能让插件立即出现,很容易把两层混成一个词。
本次核验到的对象
本次联网核验的主仓库是yjh051108/dsh-super-injector。截至 2026-08-16,它的 main HEAD 是 f4ef59fb31439225abefe45d6e793235a2a9d5e0,仓库有 v0.3.3 标签;下面关于实现的判断都以这个提交的文件为依据。
还找到同名的lileikeji/dsh-super-injector。定点核验时,主仓库的 main 和 v0.3.3 都指向 f4ef59fb31439225abefe45d6e793235a2a9d5e0,同名仓库的 main 则指向 236a211204877b8d4aa39120606ca4ff4367b978。
同名仓库的 package.json 版本是 0.3.1,不能因为名称相同就把两个仓库当成同一个 commit 或官方镜像。它可能是镜像、派生快照或独立维护版本;安装前应核对仓库所有者、具体 commit、发布资产和源码是否完整。
主仓库的 package.json 把包名写成 @dsh-external/dsh-super-injector、版本写成 0.3.3,并同时标记 private: true 和 license: BSD-3-Clause;这说明包清单、GitHub Release 和 npm 可发布性不能互相推断。
它的 cordis.patch.yml 只插入一个引导器条目:
- insert:
- id: dsh-super-injector
name: '@dsh-external/dsh-super-injector'
config: {}这部分是“第三方 Bundle 通过 DSH 配置层装入一个插件”。这个 patch 文件本身没有修改 DSH 的 TypeScript 源码;该固定仓库树也没有 packages/ 或 vendor/ 这类 DSH 上游源码目录。但这只能说明该仓库提交中采用了运行时装配方式,不能推断作者在其他 checkout 中没有维护源码修改,也不能因此获得 DeepSeek 的官方维护身份。
它的两层实现
| 代码或行为 | 应该怎样称呼 | 为什么这样分 |
|---|---|---|
package.json 的 dsh.bundle.patch | 第三方 DSH Bundle / 引导包 | 它借用 DSH 的 manifest 和 Profile 组合机制,把引导器装进插件树 |
apply(ctx) 中注册 dev_* 工具 | 一个 Cordis 插件功能面 | 工具注册本身可以挂在 Fiber 生命周期上 |
| Windows junction 或目录链接 | 文件系统层的包解析桥 | 它把本地目录放到 Profile 的 node_modules 解析路径,不是 Cordis registry |
ctx.loader.create() | 运行时创建 Loader entry | 它绕过“重启后由 Bundle 列表装配”的正常启动时机,在活进程中新增 entry |
ctx.loader.internal.loadCache、entry._dispose()、entry.fiber | Loader 内部兼容层 / 运行时补丁 | 这些是低层状态和下划线命名的内部方法,不是普通插件应依赖的稳定扩展 API |
ctx.registry.plugin()、ctx.registry.delete() | 通过公开 Registry 方法增删插件登记 | 方法本身是公开操作;但把它们用于手工重建、关联和等待 Loader/Fiber,已经超出普通 ctx.on() 或 ctx.tools.register() 的安装路径 |
runtime.fibers | 访问运行时 Fiber 集合 | 这是未文档化的生命周期状态,注入器必须自己保持关联和清理,跨版本风险高 |
webServer.exact、prefixes、upgrades 和 clientModules 的表 | 宿主内部表的自愈操作 | 这是为了清理热重载后的残留路由和客户端元数据,跨版本脆弱性更高 |
~/.dsh/super-injector/registry.json | 注入器自己的持久化清单 | 它不是 DSH 官方 Profile 配置,也不等于官方安装数据库 |
对应的源码证据集中在src/index.ts和SPEC 文档:dev_inject_plugin 会建立 junction,再调用 loader.create。
dev_reload_package 会清理 loadCache、重新 import、dispose 旧 Fiber、创建新 Fiber 并尝试回滚。
dev_uninject_plugin 会移除 entry、清理清单、删除 junction,并写入 disabled 条目防止配置刷新后再次装回。它还提供 watch、路由清理、客户端模块补扫、插件管理 HTTP 接口和一个内嵌的 dev_self_test。
DSH 官方固定提交中的 Loader 实现可以解释它为什么要这样做:Entry.refresh() 在 entry 已经有 Fiber 时直接返回,Entry._dispose() 会设置 _disposing 并等待旧 Fiber 清理。
Loader 的 internal/plugin 处理也会把 _disposing 当成“Loader 正在替换或移除”的豁免条件。注入器的设计因此是在模仿官方 Loader 的 REPLACE 生命周期,而不是调用一个已经公开承诺的“任意热插拔 API”。见官方 Entry 实现和官方 Loader 生命周期处理。
最准确的分类
把它拆成四句话最不容易误导读者:
- 它的
cordis.patch.yml部分是第三方 Bundle 的官方格式入口。 - 它的
apply(ctx)部分是由 Cordis 装入的第三方插件。 - 它的主要卖点——运行中注入、整包热重载、自重载、模块缓存清理、Fiber 重建、路由自愈——属于第三方运行时注入器和兼容层。
- 在这个固定仓库树中未见 DSH 上游源码目录,也未见通过该仓库文件修改上游源码的证据,所以单看这个仓库不应叫“源码 patch”;如果用户另外维护了一份改过 DSH 源码的 fork,那份 fork 才叫 patched fork,二者可以同时存在,但不能混为一谈。
因此,教材中的推荐写法是:
dsh-super-injector是一个第三方 DSH Bundle 加运行时注入器。它通过 DSH 的 Bundle manifest 安装引导器,再使用 junction、Loader entry、模块缓存、Fiber 和宿主内部表实现热注入与自愈。它不是 DeepSeek 官方插件,也不是只调用公开 Cordis API 的普通插件。它的 SPEC 按 DSH
0.1.0-rc.6的源码语义书写,而本学习材料固定提交的根包版本是0.1.1-rc.2,两者不是同一份接口,所以它是内部 API 风险案例,不是本固定版本兼容性的证明。
这也解释了它和“源码 patch 后自由 hook”的差别:源码 fork 是你修改了生产者和消费者,可以新增自己的事件;dsh-super-injector 是在不改上游文件的前提下,运行时触碰宿主已有对象和低层状态。前者的主要风险是同步补丁,后者的主要风险是内部 API 漂移、残留资源、重复 entry、缓存状态和回滚失败。
读这个案例时必须把“项目声明”和“独立证据”分开
主仓库的SPEC 设计文档是作者根据 DSH 0.1.0-rc.6 源码写出的设计契约,不是 DeepSeek 官方发布的 DSH 规范。README 和 CHANGELOG 声称自检 8/8、支持 Release 包、可以免重启恢复。
在本次抓到的 commit 的完整仓库树中,文件包含 README、安装手册、规格文档、src/、构建脚本和 package.json,没有独立 tests/ 目录,也没有可见的 GitHub Actions 工作流。
package scripts 主要是 build、build:client 和 typecheck。结合上一段对仓库树的观察,比较准确的记录是:“项目内嵌自检存在,独立测试与持续集成证据有限”。
还发现一个值得学习的文档一致性问题:package.json 和 cordis.patch.yml 使用 @dsh-external/dsh-super-injector,但同一提交的INSTALL.md仍有示例使用 @yjh051108/dsh-super-injector。
这不一定代表代码不能运行,却说明安装文档、manifest、发布资产必须一起核对;一个社区项目有 README、包清单和源码,并不自动意味着它已经完成发布级文档审计。
GitHub dsh-plugin topic 代表什么,不代表什么
GitHub 的dsh-plugin topic适合做“发现入口”,不适合做“官方注册表”。前两节的两次读取(5142、5511)已经演示了数字如何随时间和索引漂移;引用时保留当时的查询 URL 和日期就够。
把名称列出来只是发现的开始;下面的分层按项目解决的问题重新整理这份候选名单。
我把截至 2026-08-16 能观察到的社区项目按它们解决的问题分成下面几层。每个名称都是公开仓库发现样本,链接是来源;例子不是官方推荐名单:
下表的“做什么”一列仍然只是自述与静态观察,适用本页开头的证据等级规则。
| 社区层 | 代表项目 | 它们在生态中做什么 | 读者的核验重点 |
|---|---|---|---|
| 目录和 Awesome List | awesome-dsh-plugin、awesome-deepseek-harness、dsh-plugins | 收集链接、分类、安装提示和风险声明;有的从 GitHub topic 或其他目录同步 | 目录是索引者的筛选结果,不是官方安全认证;看收录规则、更新时间和是否允许项目自报 |
| 自动雷达和测试目录 | awesome-dsh-plugins Radar、Oh-My-DSH | 自动扫描候选仓库、去重、分类,部分项目声称用容器或 DSH 实机测试 | “扫描到”不等于“通过”;要求它公开测试环境、版本、日志、失败样本和更新时间 |
| 插件市场和管理器 | dsh-market、dshfind、DSH Plugins Marketplace、dsh-plugin-marketplace、dsh-manager、dsh-plugins-store | 把目录变成 Web 设置页中的搜索、安装、更新、卸载和兼容提示;有的项目维护自己的 registry | 市场本身也是第三方插件;检查它读取的 registry、安装脚本、网络请求、重启权限、来源锁定方式和“验证”到底证明了什么 |
| Web UI、皮肤和侧栏 | dsh-web-ui、DSH-better-sidebar | 使用 client manifest、UI slot、设置页或主题资源改变 Web 界面 | 分清 host 插件与 client 注入;确认 CSS、路由、WebSocket、文件和终端权限是否可卸载 |
| 能力和 Agent 扩展 | dsh-agent-teams、dsh-vision-toolkit、modlens | 增加多 Agent 协作、视觉工具、OCR、外部服务或新的工具集合 | 查看 API key、外部服务、子进程、Python/Node 运行时、Session 写入和失败回滚 |
| 静态审计、调试和 preflight | dsh-plugin-debug、dsh-guardian、dsh-plugin-sentinel、dsh-plugin-firewall、pluginvet | 在安装或运行前做插件预检、静态规则检查、诊断、故障隔离或跨 Agent 扫描 | “扫描通过”不等于安全、“自带测试”不等于官方验证;区分静态扫描、Bundle 装配、真实 DSH 运行、模型调用和卸载验证 |
| 预设、工作台和宿主封装 | dsh-manager、dsh-web-ui、awesome-deepseek-harness中的相关条目 | 把插件树、preset、设置界面或其他 Agent 生态组合起来;具体是否为插件要看各自的 manifest 和 README | 它们可能是 Bundle、preset、host wrapper 或独立应用,不要看到“支持 DSH”就归为插件 |
| 运行时注入和开发工具 | dsh-super-injector | 解决活进程注入、热重载、侧挂测试、Fiber 重建和开发态自愈 | 重点查是否访问 Loader、registry、缓存、路由和私有字段;必须单独标注版本绑定与回滚风险 |
几个目录的数量不同是正常现象:有的只收录声明了 dsh.bundle.patch 的包,有的把 UI 皮肤、MCP、Skill、preset、桌面 wrapper、调试器和静态扫描器也算进去,有的还会按 topic 自动收录。二次核验还发现了带 verifiedAgainst、lastVerified 和过滤规则的第三方 registry,以及拥有安装、更新、回滚、环境扫描和市场功能的插件管理器;它们比普通目录多做了一层工作,但本身仍是需要审查的第三方代码。因此“社区插件数量”首先是分类规则的产物,其次才是仓库数量。
其中,awesome-dsh-plugin的 README 明确提醒:安装插件会在本机权限下运行第三方代码,进入目录不等于安全审查;dsh-market则把安装源限制到它自己的精选 registry,并提示 CLI 插件和重启行为。这些项目的价值是把发现和安装做得更方便,但它们不能替代用户对源码、权限、依赖、许可证和版本的检查。
调试和扫描项目也要单独看。以dsh-plugin-debug为例,公开清单把它定位为 dsh-publication-candidate,且 publishedCommit 的 JSON 值是 null;教材可以把它写成“第三方公开源码候选项目”,不能把它写成 DeepSeek 官方调试插件。
类似地,dsh-guardian、dsh-plugin-sentinel 和 dsh-plugin-firewall 的 manifest 或 README 只能证明各自项目声明的 Bundle/扫描能力;是否在某个固定 DSH commit 上真实运行、是否安全、是否卸载干净,都要单独记录证据。扫描器、市场和注入器解决的是不同问题,不应因为都能“帮助插件”就合并成一个官方生态层。
本次新增核验的代表性样本包括第三方 registry、Web 插件管理器、dsh-annotation、dsh-navbar、dsh-agent-teams、dsh-tui和DSH Computer Use,分别展示目录过滤、安装管理、纯浏览器 UI、Agent 能力、独立 TUI 和系统级辅助功能等不同边界。完整的固定 commit、查询参数和写插件检查表见GitHub 生态检索与插件实战核验。
从 topic 发现一个项目后,按这六步核验
- 先核身份。 看仓库所有者、包名、许可证、维护者和发布渠道;是否使用
@deepseek-ai/*等容易造成官方背书错觉的命名空间。 - 再核装配。 打开
package.json和cordis.patch.yml,确认它是普通 import 库、Cordis 插件、第三方 Bundle、preset 还是桌面 wrapper。dsh.bundle.patch只证明它采用了可识别的装配格式,不证明它由官方维护。 - 再核接入点。 搜
ctx.on、ctx.provide、ctx.tools.register、Service、client manifest 和公开类型;再搜loader.internal、私有 Map、entry.fiber、模块缓存、路由表、替换导出和进程外加载。 - 再核权限。 查文件读写、凭据、网络、shell、子进程、Python/Node 环境、watcher、junction 和启动脚本。尤其要把
prepare、postinstall、远程安装脚本当作安装阶段代码审查。 - 再核验证。 区分 typecheck/build、自带 self-test、Loader 组合测试、真实 Web 测试、真实模型调用和作者口头“可用”。写清测试的 DSH 版本、平台、日期和未覆盖部分。
- 最后核卸载。 卸载后检查 Fiber、工具、事件、路由、client registry、定时器、子进程、文件链接、Profile patch 和持久化清单是否都恢复;“页面上不显示”不等于已经卸载干净。
这六步会把“看起来是插件”的仓库整理成可追溯的核验记录:入口是谁提供的、改到了哪一层、版本成本谁承担、对用户机器有什么权限、出问题时能不能回滚。
本文的判断边界
本篇只把固定提交中有源码或官方文档证据的入口称为 DSH 扩展点。第三方文章、逆向教程、注入脚本和仿官方包只能作为生态现象或风险案例,不能反过来证明 DSH 官方支持该做法。
如果你需要的能力没有出现在服务、事件、工具注册表、Bundle manifest 或官方文档中,最稳妥的顺序是:先寻找相邻公开扩展点,再向上游提出扩展需求;只有确实需要改变核心行为时,才维护清楚标注的 fork。
下一篇如何写一个合规插件会把这些规则落实成一个可以安装、运行、卸载和测试的最小包。
参考资料
- DSH Cordis 第一个插件教程(固定提交)
- DSH Cordis 生命周期与 effect(固定提交)
- DSH 进入 harness 的工具插件教程(固定提交)
- DSH 扩展插件手册(固定提交)
- DSH 插件打包与安装(固定提交)
- Cordis 官方固定副本 README
- VS Code Extension API:对比一个有明确公开扩展 API、版本和权限说明的成熟生态。
- Tauri Plugin 文档:对比插件包、宿主能力和平台权限如何分层。
- Koishi 插件指南:对比同样基于上下文与插件生命周期的中文社区生态;它不是 DSH 的实现证据。