DSHPluginHub-Market-Framework
DeepSeek Harness 插件市场通用模板框架(DSH Plugin Market framework)
- Stars
- 0
- Language
- JavaScript
- Created
- Oct 3, 2026
- Updated
- Oct 5, 2026
Introduction
DSH 插件市场
它是一个插件市场,也是它自己的第一个插件。
装上它,侧边栏会多出一个与内置「插件」平行的 插件市场 入口。进去可以浏览、搜索、一键安装收录的插件 —— 装完的插件出现在官方「插件」页里,默认未启用,什么时候开由你决定。
目录
为什么需要它
DSH 添加插件现在的路径是「插件页 → + 添加插件 → 手填 npm 包名 / 本地路径 / git 地址」,一次一个。
想装一批插件时这件事很烦,而且分发方还得保证每个插件都能被单独拉到。
插件市场把「一批插件」变成一个可以整体分发的包:
收录插件的源码就在市场包里面。 不依赖任何外部 registry、不依赖网络、也不需要在别处搭建索引。
marketplace/ ← 市场包(本身就是一个 DSH bundle 插件)
├─ catalog.json ← 收录目录(谁被收录、版本、说明)
├─ icon.png ← 市场自己的标志
└─ plugins/ ← 收录插件的完整源码(自包含,随包一起分发)
├─ plugin-hello/ ← 最小 Host 插件
├─ plugin-quick-notes/ ← 纯客户端插件
└─ plugin-session-tools/ ← 注册模型可见工具的插件
界面
浏览:一行一个插件,行尾只有一个动作
顶部是市场版本与统计胶囊,下面是搜索框、状态筛选(全部 / 已安装 / 已启用 / 可安装,都带实时计数) 与「刷新」「打开插件页」。列表刻意参考 ChatGPT Desktop 的插件清单:一行一个插件,行里只有 图标 · 名称 · 一句话说明 · 右侧一个动作。
| 状态 | 行尾形状 |
|---|---|
| 未安装 | 「+」 |
| 安装中 | 圆形进度环 |
| 已安装未启用 / 已启用 | 开关 |
装没装、启没启用看行尾形状就够了,不再挂重复的状态徽标。点行的任意位置(包括中间的说明文字) 都能进详情页。宽屏(≥1440px)下一排两个,上限就是两个。
详情
| 区块 | 内容 |
|---|---|
| 头部 | 插件名字、版本号、插件 id(包名)、一段 description;右上角是安装 / 卸载 + 开关 |
| 包含的组件 | 这个插件包含的每个 Loader 组件:图标、id、描述、右侧运行状态 |
| 版本信息 | 目录 id / 包名 / 目录版本 / 已装版本 / 目录路径 / profile 内软链 |
- 无论插件本体是否启用,都会列出它包含的组件 —— 插件还没装载时,
行数据来自市场从它源码的
cordis.patch.yml里静态解析出的声明。 - 装之前不显示每一行的启用/停用状态(那时还谈不到)。
- 安装会写入 profile 并让插件代码在本机进程内运行,这条操作后果直接写在页面上; 「市场怎么运作的」这类背景知识收在标题右侧的 (i) 浮窗里。
(i) 浮窗长这样
安装
点「安装」就开始装。进度由那一行行尾的圆形进度环表达(installBundle 不回报百分比,
所以不编造精度);成功后顶部浮出一条提示,几秒后自动消失。
| 事件 | 提示 |
|---|---|
| 安装 / 更新成功 | 顶部浮动提示 |
| 启用 / 停用 / 卸载成功 | 什么都不弹 —— 开关已经把结果说清楚了 |
| 任何失败 | 结果条(含可展开的诊断)—— 失败必须留痕 |
卸载是破坏性操作,会确认一次。
装完之后
插件出现在官方「插件」页的 已安装 分组里,开关默认关闭;启用、停用、卸载都在官方那边照常可用。 市场不接管官方插件页,它只是把插件送进去。
安装市场
在「插件」页 → + 添加插件,用任一方式:
| 方式 | 填什么 |
|---|---|
| 本地路径(推荐) | 本仓库 marketplace/ 目录的绝对路径,例如 /path/to/DSHPluginHub/marketplace |
| git 仓库 | 要指向子目录,不能只填仓库地址 —— 见下 |
| npm 包 | 发布之后填包名 |
关于 git 地址:本仓库根目录没有
package.json—— 包本体在marketplace/子目录里 (根目录只有 README / LICENSE / 文档)。所以「填仓库地址就能装」是不成立的: 安装器把 spec 直接交给pnpm add,它不会自动去子目录里找包。 要用 git 方式,得填带子目录的形式,例如git+https://<host>/<you>/DSHPluginHub-Market-Framework.git#path:/marketplace(也可以用file:前缀的本地路径变体)。最省事、也最不会出错的是上面那条「本地路径」。
装完刷新一次页面,侧边栏就会出现「插件市场」。
它为什么能「自包含 + 闭环」
- 收录即分发。 收录插件的源码就在市场包内部,不需要外部 registry。
- 安装走官方逻辑。 市场把内部目录的绝对路径交给官方
pluginManager.installBundle(), 官方用当前 profile 的 pnpm 执行pnpm add <绝对路径>,于是 profile 的node_modules里 出现一个指向市场包内部的软链。 - 官方刷新即同步。 你在官方插件页(或市场里)刷新市场插件版本后,市场包源码被整体替换, 而软链天然指向新源码 —— 所有已装插件无需重装就拿到了新版本。这是闭环的关键。
- 默认不启用。 安装后插件出现在官方插件页的 Bundles 分组里,市场紧接着调用官方的 行级开关把它置为「未启用」。
机制细节、勘验证据与失败模式见 docs/ARCHITECTURE.md。
不变量:市场自己不落任何安装代码,安装 / 卸载 / 启停一律调官方服务; 官方的兼容性闸门、构建脚本审批、失败回滚语义全部照旧生效。
仓库结构
marketplace/ 市场插件包(自包含)
catalog.json 收录目录(单一数据源)
cordis.patch.yml 市场自己的激活层
icon.png 市场标志
lib/ 构建产物(Loader 入口 + 客户端 bundle)
src/host/ Host 半边源码
src/client/ 客户端半边源码(ui/ 下按视图分文件)
plugins/* 收录插件(每个都是可独立安装的 DSH bundle 包)
scripts/ 构建、收录、离线验证
tools/ 真实浏览器验收工具链(CDP + 临时 profile)
docs/ 方案、架构、验收、上手指南
images/ README 用的实机截图
AGENTS.md 维护本仓库需要知道的一切(给人和 AI 用)
开发与验证
# 构建与收录
node scripts/build-client.mjs # 构建客户端 bundle(--check 只校验)
node scripts/sync-catalog.mjs # 收录 plugins/ 到 catalog.json(--check 只校验)
# 离线套件(提交前必须全绿)
node scripts/verify.mjs # 用真实 dsh --dump-config 验证组合与软链
node scripts/check-client-bundle.mjs # 在 vm 里真执行客户端工厂脚本 + 渲染烟测
node scripts/check-client-state.mjs # 用真实 RemoteResult 样例驱动状态机
node scripts/simulate.mjs # 用桩上下文真跑 Host 半边与安装编排
node scripts/verify-plugins.mjs # 收录插件的静态校验
node tools/render-logo.mjs # 由 icon.png 缩出 README 用的大图
node tools/icons.mjs # 图标流水线:GPT 生图 → 后处理 → 小尺寸目视验收图
# 真实浏览器端到端(Edge headless + 临时 profile,不碰你自己的 profile)
node tools/dsh-preview.mjs --port 18855 --bundle ./marketplace --keep
node tools/market-e2e.mjs --port 18855 --entry plugin-hello # 期望 exit 0
node tools/dsh-preview.mjs --port 18855 --stop
| 套件 | 结果 |
|---|---|
scripts/verify.mjs | 29/29 |
scripts/build-client.mjs --check | 0(产物与源码同步) |
scripts/sync-catalog.mjs --check | 0(目录与 plugins/ 同步) |
scripts/check-client-bundle.mjs | 51/51(渲染烟测 + 官方几何 + 类名反向检查 + 主题/交互) |
scripts/check-client-state.mjs | 38/38 |
scripts/simulate.mjs | 39/39 |
scripts/verify-plugins.mjs | 137 项检查,0 error |
tools/market-e2e.mjs | 117/117(真实 Edge headless,退出码 0) |
端到端成功运行后会更新 tools/market-e2e-receipt.json,记录实际条数与测试脚本的 SHA-256。
verify.mjs 默认用这份回执核对中英文计数;回执缺失、损坏或脚本变更后尚未重跑都会失败。
无需设置 DSH_E2E_TOTAL;若手动提供,该值也必须与回执一致。发布时应一并同步成功回执。
端到端要跑两条分支:带 Loader 行的插件(
plugin-hello)与纯客户端插件 (plugin-quick-notes)。这里说准确一点:
plugin-quick-notes的 Host 实现是空的,但它仍然声明了一行 (cordis.patch.yml里- id: dsh-plugin-quick-notes),因为启停/卸载需要两侧对称。 所以这两条覆盖的是「Host 有实现」与「Host 是空壳」,不是「有行 vs 完全没行」—— 真正零行的插件不在收录样例里,那是官方加载器的行为,本市场造不出来。
逐条实测结果与对应的用户要求见 docs/ACCEPTANCE.md。
想加插件见 docs/ADD-A-PLUGIN.md,
想知道「改这个仓库必须注意什么」见 AGENTS.md。
已知限制
- 改了插件 Host 半边源码后需要重启 DSH。 DSH 的 HMR 只热重载客户端 bundle, 第三方插件的 Host 源码不会热更新。
- 首次装完市场需要刷新一次页面,客户端 bundle 才会进入引导图。
- 组合行的刷新时机:刚装完一个插件时,它的 Loader 行可能还没进入组合, 详情页的「包含的组件」会如实显示为「已关闭 / 未装载」;重新加载页面后就是真实状态。
- 组件行图标用市场图标兜底:官方那种「每个组件一个独立图标」用的是上游模块自己的图标资源, 第三方拿不到,所以我们统一用市场图标。
边界与取舍
- 只做自包含分发。 不支持「目录里放一个 registry 包名,安装时去公网拉」—— 那会破坏「市场自包含」这个核心卖点。
- 不绕过官方权限模型。 市场调用的是官方
pluginManager,因此官方的兼容性闸门、 构建脚本审批、失败回滚语义全部照旧生效。 - 不改 DSH 自身。 市场只是官方服务的消费者。
- 零第三方依赖。 包括测试工具链在内,本仓库不引入任何 npm 依赖;
连截图裁剪都是用 CDP 的
clip参数做的。
Licensed under the terms in LICENSE.