Back to home

ZhijiangTang

dsh-plugin-template

Template repository for creating DSH plugins (npm bundle + scaffold script)

Stars
0
Language
Shell
Created
Aug 15, 2026
Updated
Aug 15, 2026

Introduction

dsh-plugin-template

DSH 组合包(bundle)插件模板:脚手架一个新工具插件的最小可用骨架。 本仓库本身不是可安装插件package.jsonprivate: true,keywords 是 dsh-plugin-template,不发布 npm)。

  • 纯 ESM、零依赖、无构建步骤
  • 一个 hello_world 占位工具(含参数 / 输出 schema / render / execute)
  • mount 自检走 ctx.tools.execute 真实管道(CallId 来自 @deepseek-ai/dsh-llm

开发前必读:../notes/plugin-development.md(本 hub 的实测笔记,所有结论均已验证)。官方文档本地副本在 ../reference/,发布教程见 https://deepseek-harness.github.io/deepseek-harness/develop/basic/publish.html

使用步骤

以下示例以新包名 dsh-mytool 为例。

1. 克隆 / 复制模板

# 方式 A:在本 hub 内用脚手架(推荐)
bash scripts/scaffold.sh dsh-mytool   # 生成 ../dsh-mytool/ 并替换占位符

# 方式 B:作为 GitHub 模板仓库 clone 后手工改
git clone <模板仓库地址> dsh-mytool && cd dsh-mytool

2. 改 package.json(哪些字段要改)

字段模板值要改成
namedsh-plugin-template你的 npm 包名(如 dsh-mytool
privatetrue删除(要发布 npm)
keywords["dsh-plugin-template"]["dsh-plugin", "<你的包名>"]
description模板描述你的插件一句话描述
version0.1.0按语义化版本维护

用脚手架 scaffold.sh 会自动完成前两项(删 private + 改写 name/keywords)。

3. 改 cordis.patch.yml 的 id / name

cordis.patch.ymlid: <id> 是稳定身份(不带 id 的行每次启动重新挂载);name: <你的包名>npm 包名 引用代码。

4. 改 index.js 的工具

index.js 里所有「改这里」注释:插件名 export const name、工具名 name: 'hello_world'、参数 / 输出 schema / execute 逻辑。

5. 验证配方(本地实测)

export DSH_HOME="$PWD/.dsh-test"
export PATH="$PWD/.tools:$PATH"

# file: 安装(自动初始化 px-tdemo profile,仅含 base)
dsh plugin --profile px-tdemo add file:./plugins/dsh-mytool

# web-app 补丁:把 in-box bundle web-app 加进 bundles(web 组合 = base + web-app)。
# 勿用 `dsh plugin add @deepseek-ai/dsh-web-app`:in-box bundle 不该当依赖装,且
# pnpm 的 minimumReleaseAge 会解析到坏掉的旧版 0.0.1-rc.1(实测 404)。
node -e 'const fs=require("fs");const p=".dsh-test/profiles/px-tdemo/package.json";const m=JSON.parse(fs.readFileSync(p));const b=m.dsh.profile.bundles;if(!b.includes("@deepseek-ai/dsh-web-app"))b.splice(1,0,"@deepseek-ai/dsh-web-app");fs.writeFileSync(p,JSON.stringify(m,null,2)+"\n")'

# boot 并抓自检行
dsh --profile px-tdemo --port 0 2>&1 | grep -m1 'self-test ok'

# 确认自检通过后清理
rm -rf plugins/dsh-mytool .dsh-test/profiles/px-tdemo

6. 发布

cd plugins/dsh-mytool
pnpm publish                 # 无构建步骤则直接发源码
# 用户安装:dsh plugin --profile <name> add dsh-mytool

GitHub:建仓库并打 dsh-plugin topic(详见 ../notes/plugin-development.md §7)。

第一批实测坑速查(务必先读)

  1. 本地安装必须 file:dsh plugin add ./目录 生成 link: 符号链接,Node 按真实路径解析 @deepseek-ai/*ERR_MODULE_NOT_FOUND。用 file:./目录 复制安装即可解析成功。
  2. schema DSL 三事实output.schema 不接受顶层 required 数组 → 用属性级 required: true;可空值用 oneOf: [{...}, {type:'null'}]type:'json' 是合法类型。本模板 note 字段演示了「属性级 required + oneOf null」姿势。
  3. pnpm 24h 门控:新版本发布不满 24h,pnpm add <包> 会解析到上一个「已成熟」版本。文档要写 add <包>@<版本> 显式安装。
  4. allowBuilds:含原生依赖(node-pty 等)时 dsh plugin add 失败 ERR_PNPM_IGNORED_BUILDS,需把包名写进 profile 的 pnpm-workspace.yamlallowBuilds插件尽量零原生依赖
  5. PENDING 静默inject 的服务没提供方时插件静默停在 PENDING(不报错)。插件没输出先遍历 ctx.registry 看 fiber 状态。

工具开发硬规则(节选,全量见 ../notes/plugin-development.md §3)

  • 参数已按 schema 校验(类型/必填/字面量/联合分支);schema 表达不了的约束自己查。
  • execute() 返回规范 JSON 值output.schema 声明的),不是内容块;异常/无效值 = isError。
  • 遵守 exec.signal 取消;exec 携带不可变身份(callId/name/arguments/agent/token/parent)。
  • 注册后别改 schema/回调;UI 卡片(presentCall/presentResult)必须纯函数
  • 模型可见内容由 output.render 生成,与 UI 卡片是两件事。

文件结构

.
├── package.json        # 清单:name/version/private/exports/files/peerDeps/dsh.bundle
├── index.js            # 插件:name/inject + defineTool + mount 自检
├── cordis.patch.yml    # 层 patch:insert 行引用本包
├── README.md           # 本文档
├── LICENSE             # MIT
├── .gitignore          # node_modules/ *.log .DS_Store
├── CONTRIBUTING.md     # 与 dsh-plugins hub 的关系 + batch-check 用法(模板专属)
└── scripts/scaffold.sh # 脚手架(模板专属,不复制到新插件)

License

MIT