LivXue/dsh-plugin-shop

dsh-plugin-shop

从 npm 与 GitHub 每日采集的 DSH 插件目录:一键安装、启停、更新与卸载;装前就给出 dsh 会拒绝的原因与豁免命令;安装前的事实(engines.dsh、依赖数、bin 名、安装脚本)、回滚与收藏。

插件市场与管理agentdeepseekdeepseek-harness

dsh-plugin-shop

DeepSeek Harness 的插件商店 —— 在左侧栏里自己的一页 浏览 dsh 插件目录、一键安装、管理已装插件。

English | 中文


📦 安装

下面两条路做的是同一件事,按读者是谁挑一条。

🧑 给人看

前置条件: Node.js。运行 harness 本身无需安装——上游文档的形式是 npx -y @deepseek-ai/dsh web。插件管理经由 dsh plugin,它会分别 spawn dsh 命令和 pnpm——用一条命令装好两者:npm install -g @deepseek-ai/dsh pnpm,并用 dsh --version 和 pnpm --version 验证。

# dsh 在 PATH 上(全局安装)。必须钉版本号:pnpm 11 会拦下刚发布的新版本,
# 不写版本号的裸安装可能给你旧版。下面是当前版本——用
# `npm view dsh-plugin-shop version` 查最新值。
dsh plugin --profile web add dsh-plugin-shop@0.9.4
# 或全程走 npx,什么都不装:
npx -y @deepseek-ai/dsh plugin --profile web add dsh-plugin-shop@0.9.4

如果你用的不是 web profile,把它换成你自己的。然后重启一次 dsh——新加的 bundle 不会作用于 已在运行的进程——再打开

左侧栏里的 插件商店

进去是一片插件卡片货架,带搜索框。首次加载要联网读目录,可能要等几秒,期间由一层扫光骨架占位。

🤖 给 agent 看

全程非交互,无提示、无需确认。--profile 是必填的——不给它,dsh plugin 会以 error: required option '--profile <name>' not specified 退出。

1. 确定 profile 名。 profile 是 $DSH_HOME/profiles 下的目录($DSH_HOME 默认 ~/.dsh)。那里还会出现 node_modules,它不是 profile。

ls -1 "${DSH_HOME:-$HOME/.dsh}/profiles" | grep -v '^node_modules$'

2. 安装。 钉版本号——显式钉版本能绕过 pnpm 的发布冷却期,确定性安装本来也是 agent 路径的要点。

dsh plugin --profile <profile> add dsh-plugin-shop@0.9.4

3. 验证——这步别省。 第 2 步返回 0 只说明 pnpm 解析到了这个包,不代表 profile 会加载它。 要断言的是 bundle 列表:

dsh plugin --profile <profile> list --depth 0

dsh-plugin-shop 必须出现并带有已解析的版本号。想直接读清单也行,同一事实位于 $DSH_HOME/profiles/<profile>/package.json 的 dsh.profile.bundles。

4. 重启该 profile——dsh --profile <profile>,web profile 用 dsh web。启停已安装的 插件是热生效的;新增 bundle 不是。

失败模式

你看到什么含义怎么办
error: required option '--profile <name>' not specified漏了 --profile补上,它没有默认值
装到的版本比 npm 的 latest 旧pnpm 11 会压住刚发布不久的版本显式钉版本:dsh plugin --profile <p> add dsh-plugin-shop@<版本号>
client bundles not found ... lib/client.js磁盘上那份没有构建浏览器半边从 npm 安装而不是从源码 checkout,或在该 checkout 里跑 pnpm build
dsh: pnpm not found on PATH — install pnpm to manage profile pluginsdsh plugin 转发给 pnpm,而 pnpm 缺失npm install -g pnpm
no profile directory found above <path>插件定位不到自己的 profile请报告——这是由 ctx.baseUrl 解析的,不该失败
重启后标签没出现bundle 不在 profile 的 bundles 里重跑第 3 步;若确实不在,说明第 2 步没走完

🖼️ 界面预览

dsh 侧栏插件商店页面上的货架
dsh 会拒绝安装的插件,卡片上会说明原因深色主题下的同一片货架
dsh 会拒绝安装的插件,卡片上会说明原因深色主题下的同一片货架

✨ 能做什么

浏览与搜索数千个插件,按 dsh-plugin 与 deepseek-harness 关键字从整个公共 npm registry 采集(外加把这些关键字用作 topic 的 GitHub 仓库);作者若自己声明了简介就用作者原话,并归入七个分类。货架可以按星标、最新上架或最近更新排序,后两种在卡片上标出日期;版本号会写明自己是什么:npm 版本、GitHub 发布还是 GitHub 提交。切回标签页会重新读取目录,最多每五分钟一次
安装一次点击,没有对话框。本机 dsh 会拒绝的安装——harness peer 不被当前版本接受,或名字已被另一个已装插件占用——卡片会在按钮的位置显示红色标签并写明原因,peer 被拒时附上 dsh 自己的豁免命令。较长的红字折叠成两行,点「展开」看全文。安装失败时,会给出指向插件自己仓库的预填 GitHub issue
启停对已安装插件生效,无需重启。带浏览器半边的插件还需要刷新当前页面,商店会在需要时给出按钮
已安装状态已安装的插件在卡片上显示「已安装」,目录有新版本时改为「更新」按钮,另有「卸载」按钮;顶部「已安装」筛选只看已装插件
体积与作者每张卡片显示装上它会占多少磁盘,紧挨着发布账号——用的是 npm 自己的解包体积,所以和该包的 npm 页面对得上
滤掉跑不起来的必需的组件你这套安装没有提供,或者作者声明支持的 dsh 版本、profile 跟你正在用的不符,这样的插件会被标为不兼容,类别栏末尾的筛选可以把它们从货架上拿掉。它不会隐藏名字已被别的安装占用的插件,也不会从「已安装」视图里减东西——那些卡片是唯一能说明问题、也是唯一能撤销它的地方
刷新当卸载或启停已经在服务端生效、只是当前页面还停在旧状态时,商店提议刷新这个页面——不会自动刷新,因为刷新会丢掉进行中的工作
重启插件的宿主半边没能热挂载时;以及它挂载成功、但插件带浏览器半边时——会话中途装上的插件,它的界面要重启 dsh 才进得了页面,所以商店直说,而不是给一个按了也不会变的刷新。提议前先讲清代价:页面会断开,进行中的工作会中断
自更新搜索框旁显示商店自己的版本号,自动查 npm 有没有新版本,有则一键用钉死版本更新,随后照常重启

🔎 货架是怎么来的

目录不是谁手工维护的名单。每天跑六步,其中两步是这个货架值得一读的原因:

  1. 全网爬取。 npm 上带 dsh-plugin 或 deepseek-harness 的包全部过一遍,外加把这些关键字 用作 topic 的 GitHub 仓库。不需要提交,也没有排队。
  2. 逐个筛查。 采到的东西大多进不了货架; 仓库 README 顶部的实时徽章同时统计两边的数量。没有 dsh.bundle 的是库,不是插件;没有许可证或仓库的无从审查;npm 上已废弃的直接出局;仓库来源还额外要求无构建 脚本、无 workspace: 依赖——这两样任一都会让安装在你机器上失败;名字跟热门包只差一两个字符 的会被扣住,等人核过才放。十七种记录在案的拒收理由,全是 机械判定,每条拒收都附一句作者能读懂的话。
  3. 分类与记录。 七个分类,每个插件必需的 peer 模块——只记名字,从不记版本范围——以及作者 自己声明的 dsh.compatibility(如果有)。
  4. 发布。 内容寻址的 JSON,同时发到 npm 与 GitHub Pages。
  5. 在你这边拉取。 本包竞速多个来源,并在信任任何字节之前校验 sha256。
  6. 依赖检测也在你这边。 你的安装拿那些 peer 名字去查你自己的 profile,再剔除 dsh 网页端 自己就提供的模块。两边都没有的,卡片显示不兼容并列出缺了什么;作者声明支持的 dsh 版本或 profile 跟你正在用的不符,卡片同样显示不兼容,并写明声明的是什么、你实际运行的是什么。 这个结论必须在你机器上算,因为答案取决于你实际跑的是哪个 harness,而不是构建当时跑的那个。

完整流程图在 仓库 README。

有一件事它没有做:没有任何一条收录被人读过。今天 verified.yml 是空的,全部条目都是社区 层。机械筛查不等于评审。

🧩 结构

一个包里装了两半,两者之间的分界就是安全边界:

半边入口能触及不能触及
Hostdsh-plugin-shop网络(取目录并校验 sha256)、文件系统(缓存)、per-profile 互斥锁下的 dsh plugin add——
Clientdsh-plugin-shop/client仅九个 shop/* Remote 方法网络、文件系统

攻破浏览器那一半,攻击者拿到的就是那九个调用,别无其他。

⚙️ 配置

插件目录会从几个来源里挑最先响应的那个读:npm 包 dsh-plugin-shop-catalog(走你配置的 registry、npmmirror 或 npmjs),或者 https://LivXue.github.io/dsh-plugin-shop/v1/。几个来源的内容完全一致,之所以要赛跑,是因为不同网络到它们的快慢可以差出几百倍。设了 DSH_SHOP_CATALOG_URL 就不再赛跑,只读你指定的那个。

变量作用
DSH_SHOP_CATALOG_URL只从这个地址读目录,不再在默认来源之间赛跑

📚 目录

每日从公共 npm registry 构建,以静态 JSON 发布:

  • /v1/index.json —— 指针,携带 schemaVersion、builtAt、收录数 count 与过滤数 rejected(上面的徽章实时读它们)和内容哈希
  • /v1/plugins.<sha256>.json —— 数据,内容寻址,可无限期缓存

指针足够小,适合轮询。在信任数据文件的任何一个字节之前,商店会先用指针里的 sha256 校验它。

⚠️ 不作何承诺

出现在货架上不等于背书。

capabilities 只是作者对自己包的自述。v0 没有沙箱,界面也从不把这个字段渲染成一份被强制 执行的权限清单。verified 层的含义是有人读过那个确切版本;一旦发布新版本就降级为 verified-stale,评审记录仍钉在它当初对应的版本上——所以过一次评审,买不到后续每个版本的信任。

🏷️ 面向插件作者

在 package.json 里加上采集关键字——"keywords": ["dsh-plugin"] 或 "keywords": ["deepseek-harness"]——然后发布;或者不走 npm:把关键字作为 GitHub 仓库的 topic, 并在仓库根放一个带 name 和 dsh.bundle 的 package.json——目录会收录该仓库并把默认分支的 commit 钉为版本。每日构建就会找到你,不需要向本项目提交任何东西。声明 dsh.catalog 段可以自己掌控分类、简介和 capabilities;不声明,目录会从 你的 npm description 推导一条 listing。

完整参考:docs/schema.zh.md。

📄 许可

Apache-2.0 © LivXue