从 DSH 左侧栏打开独立的插件市场页面,浏览 awesome-dsh-plugin 目录。支持按分类或安装状态筛选、按名称或简介搜索,以及按 Star、下载量、名称或收录时间排序;三个标签分别显示全部插件、已安装插件和可更新插件,并单独提示无法判断更新状态的数量。自动识别当前 Web 或桌面 profile,使用 DSH 提供的包管理器一键安装和更新,保留其他插件的停用状态。支持通过 HMR 重载 profile,不可用时提示重启。各 profile 的安装状态独立,安装与重载互斥,分页保持已提交的搜索条件。目录在本地缓存一小时,官方源不可达时依次回退到镜像、CDN 与 npm。
安装
# npm 包(预构建)
dsh plugin --profile web add @99galaxy/dsh-plugin-market
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:99galaxy/dsh-plugin-market
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
从 DeepSeek Harness 的左侧栏打开插件市场,一键安装。
A sidebar plugin-market page for DeepSeek Harness: browse the community catalog, see what you already have on its own tab, and install with one click.
数据来自 awesome-dsh-plugin 维护的
官方目录 plugins.json —— 约 4,400+ 个插件、23 个双语分类,带 Star 数、下载量、收录日期,
以及每个条目的官方安装命令。
它做什么
左侧栏新增 「插件市场」 入口,点击后在主区域打开独立页面。页面内有三个标签:
| 标签 | 内容 |
|---|---|
| 全部插件 | 完整目录。可按分类筛选、按 Star/下载量/名称/收录时间排序、搜索插件名或简介 |
| 已安装 | 只列出你已经装过的插件,标签上直接显示数量 |
| 可更新 | 只列出装了但目录里有更新版本的插件,标签上直接显示数量 |
- 一键安装:点「安装」即执行该条目的官方安装命令,装到当前 profile
- 安装状态:已安装的条目带绿色徽章;若目录名与你实际装的包名不同,会标出真实包名
- 更新检测:拿目录里的
version和 profile 里实际装的版本比对,有更新的挂橙色徽章 「可更新 1.47.0(当前 1.46.1)」,按钮从「重新安装」变成「更新」 - 中英切换:简介可切中文/英文
- 本地缓存:目录存到本地,1 小时内直接复用;要最新的点「强制重新获取」
- 一键重载 profile:装完插件点「重载 profile」,通过 DSH 的 HMR 重新组合当前 profile,不必重启;没有 HMR 的 profile 会提示你重启
- 四级降级:官方域名 → 镜像 → CDN → npm,任一条通即可
安装
这是一个 DSH bundle:装进 profile 后重启 DSH 自动加载。
cd ~/.dsh/profiles/web # Web 版;DSH 桌面版换成 desktop
pnpm add github:99galaxy/dsh-plugin-market
也可以显式用 HTTPS 地址:
pnpm add https://github.com/99galaxy/dsh-plugin-market
装进来的包名是 @99galaxy/dsh-plugin-market —— 与仓库名不同,所以下面层列表里要写这个
带 scope 的名字。
DSH 0.2.x 桌面版跑的是
desktopprofile。插件会通过ctx.profileContext.name自动识别当前 profile,所以页面里的「安装」不需要你在命令里写死--profile。
然后把它加进 package.json 的层列表 —— 声明了 dsh.bundle 的依赖才会被加载:
{
"dsh": {
"profile": {
"bundles": ["...", "@99galaxy/dsh-plugin-market"]
}
}
}
重启 DSH。
github:前缀在部分 git 配置下会被解析成git+ssh,而匿名 HTTPS 不需要任何凭据。 若 pnpm 报找不到仓库或索要 SSH 密钥,改用上面的 HTTPS 形式。
使用
- 点击左侧栏的 插件市场
- 浏览或搜索;点卡片右侧「安装」
- 安装完成后点工具栏的「重载 profile」;没有启用 HMR 的 profile 仍需重启 DSH
「已安装」标签里可以确认某个插件是否已经在你的 profile 里;「可更新」标签里是可以升级的那些。
关于「更新」:它执行的仍是目录里那条安装命令,所以装的是目录指定的那个来源 —— 一个用
github:装的插件,如果目录对应的条目是 npm 包名,更新后会变成 npm 包。 想留在固定 commit 上就别点更新。判断不了的插件:目录里没有
version、或目录根本没收录的插件,无法判断有没有更新。 它们不会出现在「可更新」标签里,但标签内会单独说明有多少个 —— 免得把「判断不了」误读成「已经是最新」。
架构
┌─ 浏览器半边 ────────────────────────────────────────────────┐
│ window.__ModuleLoader__.load({ id, factory(require) }) │
│ require('react');槽位服务由 ctx 注入 │
│ sidebar.panellist → 左侧栏「插件市场」入口 │
│ main → 独立的「DSH 插件市场」页面 │
│ 页面内三个标签:全部插件 / 已安装 / 可更新 │
│ 筛选、排序、分页、更新比对全部在宿主侧完成 │
└───────────────┬─────────────────────────────────────────────┘
│ fetch() ← 不是动态插件的私有 RPC,也不是 ctx.remote
┌───────────────▼─────────────────────────────────────────────┐
│ 宿主半边 index.js │
│ ctx.inject(['webServer']) → │
│ GET /dsh-plugin-market/list │
│ POST /dsh-plugin-market/install │
│ POST /dsh-plugin-market/reload │
│ 子进程输出经**文件描述符**捕获(非管道、非 shell) │
└───────────────┬─────────────────────────────────────────────┘
│ spawn(node, [market-core.mjs, …])
┌───────────────▼─────────────────────────────────────────────┐
│ market-core.mjs(真实文件,可单独运行) │
│ catalog 抓取/缓存目录(官方 → 镜像 → CDN → npm) │
│ installed 读 profile 依赖 + node_modules + 已装版本 │
│ install 优先用 DSH 提供的包管理器;CLI 回退到 pnpm │
└─────────────────────────────────────────────────────────────┘
为什么用 HTTP 而不是 ctx.remote
浏览器半边要调用宿主能力,但 ctx.remote.<ns> 的方法来自 DSH 的 Typert 代码生成 ——
本地手写的插件无法注册自己的命名空间(ctx.remote.$mount() 只接受生成的贡献)。
而 webserver 的命名路由注册是公开服务:
ctx.inject(['webServer'], (host) => {
host.webServer.register({ kind: 'exact', path: '…', handler: (req, res) => {} })
})
于是宿主暴露三条路由,浏览器半边用 fetch 调用。
HTTP 接口
| 方法 | 路径 | 入参 | 出参 |
|---|---|---|---|
GET |
/dsh-plugin-market/list |
bypass, category, q, sort, only, limit, offset(only 取 all / installed / notinstalled / updatable) |
{ ok, payload: { items, categories, count, total, matched, installedTotal, updatableTotal, unknownTotal, offset, sort, only, category, q, catalogFromCache, fetchedAt, catalogUpdated, source, note } } |
POST |
/dsh-plugin-market/install |
{ install, name? } |
{ ok, spec, seconds, log } |
POST |
/dsh-plugin-market/reload |
{} |
{ ok, warnings, pending, restartReason } |
items 里的每个条目除了插件本身,还带 installed / installedAs / installedVersion / update。
updatableTotal 是可更新数,unknownTotal 是判断不了的数(目录里没有版本,或目录没收录已声明的 bundle);普通 profile 依赖不计入。
更新判断只比对目录里的 version,不额外发任何网络请求。
bypass=1 是唯一的强制重新抓取旗标;只有「强制重新获取」按钮发它,其余调用都只做新鲜度检查。
三个标签都是页面内的:插件注册一个 sidebar.panellist 入口和对应的 main 页面,标签由页面自己渲染。
三条路由只接受同源调用(校验 Sec-Fetch-Site 与 Origin),安装和重载接口还要求
Content-Type: application/json —— 直接挂在 webServer 上的路由不受 DSH /api 那道
browser-trust fence 保护,所以插件自己拦。安装命令里的包名若以 - 开头会被拒绝
(它会成为 pnpm 的一个选项而不是包名)。
重载走 DSH 的 hmr 服务:hmr.runExclusive(() => hmr.reconcileProfile()),会把新装的
bundle 重新组合进运行中的 Loader 树。返回里的 pending 是仍需重启才能替换的模块,
restartReason 是 profile 级重启原因;两者都为空才会自动刷新页面。安装进行中会拒绝重载。
包内容
package.json 声明 dsh.bundle.patch 与 dsh.client.platform
cordis.patch.yml 把自己插进 profile 的层栈
index.js 宿主半边:三条 HTTP 路由
market-core.mjs 市场逻辑(生成物,请勿手改)
client/client.js 浏览器半边:左侧栏入口 + 主区域页面 + 页内三个标签
market-core.mjs 由源生成后一并提交,所以 clone 下来即可安装,不需要任何构建步骤。
许可
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-plugin-manager★ 9321
设置 → 插件 分区里的插件管理 Tab:从 npm/git 安装带进度、下次启动生效的启停开关、安装冲突对账可撤销、失败一键转交修复会话。
dsh-market/dsh-market★ 8235
在 DeepSeek Harness 设置页内浏览、搜索并安装社区插件,支持分类筛选、一键更新与停用,以及主题切换与配置备份。
kingOfSoySauce/dsh-skin-market★ 246
原生皮肤市场与生命周期管理器,发现社区皮肤、展示预览与兼容状态,并提供已验证的一键安装或手动安装入口。
awesome-dsh-plugin/dsh-find-plugin★ 204
会话内直接找插件:按关键词/分类搜索本精选 registry,返回描述与可直接执行的安装命令。
bradeGithub/DSH-Plugins-Marketplace★ 188
面向 GitHub dsh-plugin 话题的插件与技能市场:设置页内逛自动收录的全量索引(CI 每 2 小时刷新),一键安装带类型识别、安装脚本与宿主依赖遮蔽安全检查、环境变量密钥管理,并附 STANDARD.md 识别层规范。
Sanqi-normal/dsh-webui-market-plugin★ 104
dsh Web GUI 内的社区插件市场:浏览 awesome-dsh-plugin.com 目录,从 设置 → 插件 → 插件市场 安装/卸载插件到 profile。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。