Skip to content

CH 23 · 发布与分发

全文字数3913 字预估耗时约 20 分钟前置CH 17、CH 22难度可照做

本章目标

PART 04 一路走下来,你已经会装插件、会写插件了——但它现在还躺在你自己工作区里的文件夹里,别人怎么拿到它? 这一章把它变成"别人一条命令就能装"的发布物:先讲清别人装插件的底层机制(bundle 组合包),再给三种分发方式,最后发布前先自己装一遍验证,确认没问题再发出去。

先搞清楚:别人怎么装你的插件

dsh 没有内置插件市场,官方安装统一走 dsh plugin --profile <名字> add <来源>。来源就四种:npm 包名 / 本地目录 / tarball / GitHub Release(CH 17 系统讲过)。所以你要做的,就是把你写的插件变成这四种来源里的任何一种。

而"能被人 add 的插件",在 dsh 里有个正式名字——bundle(组合包)。两个概念别混:

  • bundle你编写并分发的东西。它的 package.json 声明 dsh.bundle,回答的是"这个包贡献什么"——一个插入或覆盖插件行的 patch 文件。
  • profile用户用 dsh --profile <名字> 启动的东西。它的 package.json 声明 dsh.profile,回答的是"这套配置由哪些 bundle 按什么顺序组成"。

没有东西同时是两者。你分发 bundle,用户用 profile 装它、跑它。

一个可发布的插件长什么样

你写好的插件目录里,最关键的三个东西:

text
your-plugin/
├── package.json       # 声明 dsh.bundle(带 UI 的还要声明 dsh.client)
├── cordis.patch.yml   # 被安装时应用的那一层 patch
└── lib/               # 构建产物——别人装到的就是它

package.json 里这些字段,一个都不能含糊:

字段说明
name包名,和插件匹配、读起来合适
version语义化版本,主版本.次版本.修订号,初始 0.0.1
description一句话说清插件是干嘛的,会显示在安装列表里
typemodule(ESM)
main指向构建产物,如 lib/index.js
files只打包要发的东西libcordis.patch.ymlLICENSE 等。漏了 lib 别人装完加载必失败
keywords搜索关键词,["deepseek","harness","dsh","dsh-plugin",...]——dsh-plugin 是标配,方便被搜到
license开源必须声明,如 MIT
dsh.bundle{"patch":"./cordis.patch.yml"}——声明这是一个组合包,装进去自动挂载
dsh.client带 UI 的插件声明 client 注入(CH 22 讲过那套)

三种分发方式

由轻到重。第一种纯本地自测,不需要任何账号;后面两种都要注册账号——GitHub 那步要 GitHub 账号,npm 那步要 npm 账号。

方式一:本地目录 / tarball——发布前先自测

  • 本地目录dsh plugin --profile demo add ./your-plugin,pnpm 直接 link 那个目录,适合开发阶段快速试。
  • tarball:在插件目录里 pnpm pack 打出 .tgz,再 dsh plugin --profile demo add ./your-plugin-0.0.1.tgz

发布之前,一定先用 tarball 自己装一遍——tarball 和你发出去的东西一模一样,能装通、能跑,才轮得到考虑往外发。完整自测三步:

powershell
# 在插件目录打包
pnpm pack

# 换一个干净的临时 profile 装上
dsh plugin --profile test add ./your-plugin-0.0.1.tgz

# 看它有没有进配置树
dsh --profile test --dump-config

--dump-config 输出里能看到你插件那一层,说明组合包加载成功了。然后 dsh --profile test 启动,测插件的功能是否正常,都正常再发。

两个细节记牢:

  • bundle 成员变更后要重启 profile 才生效——运行中的 profile 保留它启动那一刻的 bundle 集合(CH 17 那个边界),装完先重启再测。
  • 加载顺序:profile 的 bundles 列表 → profile 自己的 cordis.patch.yml → $DSH_HOME/cordis.patch.yml--patch overlay,后应用的行胜出。你的插件在里面属于第一层。

你也可以直接让 dsh 帮你做:把下面这条发给它,它自己读文档、打包、装临时 profile、验证,你只管验收。

text
把我当前工作区里的插件打包成可发布的形式,并做一次发布前自测:先去 dsh 官方文档读清楚插件怎么打包、怎么安装(bundle 组合包、dsh plugin add 的四种来源),按官方规范来;把插件打包成 tarball,检查 package.json 元数据(版本号、description、files、keywords、license)是否齐全;用一个临时 profile 装上它并验证能加载、功能正常;最后把验证结果和打包产物路径告诉我,并说明发布到 npm 还需要我做什么。

方式二:GitHub——别人一个 URL 就能装

社区里最多的就是这种:构建好产物,传到 GitHub Release,别人拿一个 URL 直接装。我们 CH 12 装的 DSH Skill & MCP Panel 就是这么发的。

做法三步:

  1. 打包:在插件目录 pnpm pack,得到 your-plugin-0.0.1.tgz
  2. 上传:把仓库推到 GitHub,到仓库页建一个 Release(写个版本号 v0.0.1),把 .tgz 传上去。
  3. 给安装地址:别人用这个地址装:
powershell
dsh plugin --profile web add https://github.com/你的用户名/仓库名/releases/download/v0.0.1/your-plugin-0.0.1.tgz

装的是构建产物,不需要 allowBuilds 授权,和 npm 装起来一样省事。想固定一个"永远指向最新版"的地址,把 download/v0.0.1/... 换成 releases/latest/download/your-plugin.tgz(文件名别带版本号)。

注意:走这条路的插件,lib/ 一般不进 git——仓库里只放源码,发布前本地 build 好、pnpm pack 出 tarball 再传 Release。

进阶:GitHub Actions 自动打包发布

手动打包、建 Release 传文件做一次还行,版本多了就烦。可以让 GitHub Actions 替你做:往仓库推一个 v0.0.1 这样的 tag,Actions 自动跑 build → pnpm pack → 创建 Release → 把 tarball 传上去。以后发新版本只需要打个 tag 推上去,别的全自动。

典型 workflow 放在仓库的 .github/workflows/release.yml:触发条件是 push: tags: ['v*'],步骤依次为 checkout 代码、安装 Node、pnpm installpnpm buildpnpm pack、用 softprops/action-gh-release 创建 Release 并把生成的 .tgz 作为附件上传。配好一次,以后每个版本都不用再手动传文件。

你也可以直接让 dsh 帮你发

打包、推仓库、建 Release 这些重复活,直接交给 dsh 自己干。在 Web UI 输入框发这条:

text
把我当前工作区里的插件发布到 GitHub,发 v0.0.1 版本,按 dsh 官方规范用 GitHub Actions 自动打包发布,最后告诉我别人用什么地址可以安装。

它会自己读文档、自己跑命令、自己处理 git 和 Release。你只需要在它推仓库、建 Release 这类越界操作时按权限策略确认一下,最后验收安装地址对不对。

方式三:发布到 npm——装完别人直接写包名

把插件发到 npm,别人装起来最简洁:dsh plugin --profile web add your-plugin

流程四步:

  1. 注册并登录 npm:在 npm 官网 注册账号(免费),然后 npm login(会让你输用户名、密码和邮箱)。
  2. 构建:确保 lib/ 是构建产物。源码型插件要先 pnpm build 再发——npm 装的是预构建代码,不构建就发,别人拿到手是空的。
  3. 发布:在插件目录执行 pnpm publish
  4. 验证:换一个干净 profile,dsh plugin --profile test add your-plugin,确认能装上、能跑。

发布完:打 dsh-plugin 话题

无论是哪种方式,在 GitHub 仓库的 Topics 里加上 dsh-plugin——官方明确建议这么做,让其他人更容易找到你的插件。npm 包的 keywords 里也记得带上 dsh-plugin,双管齐下。

常见坑

问题怎么回事怎么处理
装完没生效bundle 成员变更没重启装完重启 profile 再测
别人装完加载失败files 漏了 lib/,只发了源码files 里加上构建产物目录,重新打包
版本号重复同版本号 publish 会被 npm 永久拒绝改个版本号再发
包名被占用npm 上已有同名包换个不冲突的包名
装了但没激活包没声明 dsh.bundle补上 "dsh":{"bundle":{...}},否则只作普通依赖不挂载

这一章你学到了什么

能自己完成下面几条,就算过关:

  • [ ] 知道 bundle 是"你分发的东西"、profile 是"用户启动的东西",两者 manifest 不同
  • [ ] 能给一个可发布插件写出正确的 package.json:name / version / files / keywords / license / dsh.bundle,带 UI 的还有 dsh.client
  • [ ] 知道三种分发方式各自的适用场景:本地/tarball 自测、GitHub Release tarball(主流一键装,支持 Actions 自动发布)、npm 发布
  • [ ] 会发布前自测:pnpm pack → 临时 profile add--dump-config 确认 → 重启验证
  • [ ] 知道可以让 dsh 帮你完成打包自测和发布到 GitHub,不用手动一步步操作
  • [ ] 知道发布后给 GitHub 仓库打 dsh-plugin 话题、npm 包 keywords 带 dsh-plugin
  • [ ] 能避开常见坑:files 漏了 lib/、bundle 变更没重启、包没声明 dsh.bundle

Open Source · MIT · Community Driven