课程总纲 / 阶段 3 · 插件开发
L18

发布与「读懂社区插件」五步法

能发布自己的插件;拿到任何社区插件,10 分钟内看懂它在干什么。

预计阅读 30 分钟难度 ★★★☆☆阶段 3 收官

一、打包成 bundle:两个 manifestBundle It

发布插件 = 做成 bundle(发行层,L10 讲过)。最小目录结构与三份文件:

hello-plugin/
├── package.json       # 声明 dsh.bundle
├── cordis.patch.yml   # 该包贡献的配置层
└── index.js           # 补丁行引用的插件模块
// package.json —— 关键是 dsh.bundle 指向补丁文件
{
  "name": "dsh-hello-plugin",
  "version": "0.1.0",
  "type": "module",
  "main": "index.js",
  "files": ["index.js", "cordis.patch.yml"],
  "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}

// index.js —— 插件本体
export const name = 'hello-plugin'
export function apply() { console.log('[hello-plugin] loaded!') }

# cordis.patch.yml —— 注意:按"包名"引用(Node 解析),不是绝对路径
- insert:
    - id: hello
      name: dsh-hello-plugin
没有 dsh.bundle 声明的包:照常安装但只是普通依赖——dsh 警告且不激活任何层。适合"给插件包 import 的工具库",而非让用户启用的插件。

二、安装进 profile 并验证Install & Verify

dsh plugin --profile demo add ./hello-plugin   # 首次自动初始化 profile(含 dsh-base)
dsh --profile demo --dump-config                # 应出现 "# == dsh-hello-plugin" 层注释
dsh --profile demo                              # 启动
dsh plugin --profile demo remove dsh-hello-plugin  # 连依赖带层一起删

安装后 profile 的 package.json 自动出现 dsh.profile.bundles 清单(dsh-base 在前,你的包追加在后),不用手写。

三、三种分发方式与一个大坑Distribution

方式命令特点
npm 发布dsh plugin add your-package最顺滑:发布时已构建好 lib/,用户装的是成品
tarballdsh plugin add ./x-0.1.0.tgzpnpm pack 打包,同样免构建权限
Git 直装dsh plugin add github:you/hello-plugin拉的是源码不是产物——见下面的坑
Git 直装的坑(两端各一半责任): 安全视角:allowBuilds = 授权该包在你机器上执行安装期代码(智能体沙箱之外)。只给读过源码的包开;用 github:you/x#<sha> 钉住 commit 防偷换。不想麻烦用户就走 npm / tarball。

四、让社区发现你Discoverability

五、读插件五步法The 5-Step Read

拿到任何社区插件按此顺序读,10 分钟出结论:

看哪回答什么
① manifestpackage.json 的 dsh 字段它是 bundle(贡献层)还是普通库?依赖哪些包?
② inject源码的 inject 声明它站在谁的肩膀上?(tools?某能力缝?)
③ applyapply 里注册了什么它的本质动作:注册工具?挂监听器?提供服务?
④ Config导出的 Config/Schema怎么配?有哪些必填?默认值合理吗?
⑤ READMEModel Experience 段对模型行为和 token 开销有什么影响?

叠加 L06 的角色判断:③里"实现某个抽象服务"→Provider;"调用某服务并注册工具"→Consumer;"只声明抽象类和类型"→Definition。角色 + 五步 = 任何插件的完整画像。

六、常见插件形态对照表Shape Catalog

形态识别特征仓库内标准范例
工具型inject ['tools'] + defineToolpackages/todo/
拦截/策略型ctx.on 挂 waterfall 事件packages/guard/(循环卫生)
Provider 型extends 抽象 Servicedsh-bash-local
Definition 型导出抽象类 + Request/Result 类型dsh-shell
UI 型ConversationNode / 设置卡片packages/client/web/
协议桥型stdio/wire ↔ ctx.agents 互译packages/acp/acp/(官方"可运行范例")
模型适配型LlmAdapter 子类 + registerAdapterdsh-llm-deepseek
dsh-plugin topic
GitHub 上发现 dsh 插件的官方话题标签。
prepare 脚本
git 安装后自动执行的构建钩子。
allowBuilds
pnpm 的安装期构建白名单(安全边界!)
Model Experience
README 里描述对模型/token 影响的段落。
✏️ 动手练习
  1. 把 scratch-plugin 整理成 hello-plugin bundle(三份文件),dsh plugin --profile demo add 装进 demo profile 并 --dump-config 验证。
  2. 任选两个 dsh-tool-* 包,用五步法各写一份"画像笔记"(manifest→inject→apply→Config→README)。
  3. 在 GitHub 搜 dsh-plugin 话题找一个社区插件,只读 package.json 预测它干什么,再用五步法验证。
预期结果:跑通"写作→打包→安装→验证"闭环;读陌生插件不再从 main 函数瞎翻。
📝 自测(点击展开答案)
1. bundle 的 package.json 里,dsh.bundle 和 dsh.profile 分别回答什么问题?
dsh.bundle(你创作分发的包)回答"贡献什么"——指向补丁文件;dsh.profile(用户的启动组合)回答"哪些 bundle 按什么顺序组成这次运行"。一包只居其一。
2. git 直装失败的两个常见原因?
① 作者没写自包含 prepare 脚本(git 拉的是源码无产物);② pnpm≥10 拒绝跑构建脚本,需把包名加进 pnpm-workspace.yaml allowBuilds 再 add。
3. allowBuilds 白名单的安全含义?
授权该包在你机器上、智能体沙箱之外执行安装期代码。只给读过源码的包开并用 #sha 钉住 commit;npm/tarball 分发完全不需要。
4. 读插件五步法的顺序?每步看什么?
① package.json 的 dsh 字段(bundle 还是库)→② inject(站在谁肩膀上)→③ apply(本质动作)→④ Config(怎么配)→⑤ README 的 Model Experience(对模型影响)。再叠加三角色判断。
5. 一个包没有 dsh.bundle 声明但被安装了,会发生什么?
作为普通依赖安装,dsh 打警告、不激活任何配置层——适合工具库,不适合用户启用的插件。
权威出处:basic/publish.zh.md(本课主源) · CLI reference(层序与 profile 机制) · README(dsh-plugin topic)