user-plugin-list
August 14, 2026 · View on GitHub
当前版本:V0.9.3
DeepSeek Harness Web 的用户插件列表。在 设置 -> 插件 -> 用户插件 中显示当前 Loader 树里的非系统插件,并沿用内置插件列表的搜索、状态和折叠卡片交互。展开卡片详情后可以对用户插件执行启用 / 停用 / 彻底卸载(卸载需输入插件名确认)。
功能
- 根据实际 Node 包解析位置区分系统插件和用户插件,不依赖包名前缀。
- 展示 profile 本地插件、外部路径插件,以及已启用和已停用的 Loader 条目。
- 排除 Harness 安装目录、profile 系统 fallback 和 agent preset 中的内置插件。
- 不扫描传递依赖,避免把 React 等普通 npm 包误列为插件。
- Host 接口不向浏览器返回本机绝对路径。
- 展开卡片详情后可切换插件启用状态:会话内立即生效(Loader 热卸载/热装载),并持久化到 profile 的
cordis.patch.yml,重启后保持。 - 展开卡片详情后可彻底卸载用户插件(需输入插件名二次确认):删除包文件与依赖(
pnpm remove)、从dsh.profile.bundles移除、清理cordis.patch.yml中全部相关行,并立即热卸载;卸载后建议重启dsh web以完全清除内存中的 bundle 快照。 - 页签顶部可通过 GitHub 链接安装用户插件(
github:owner/repo或https://github.com/owner/repo):执行pnpm add更新依赖、锁文件与包文件,自动把声明dsh.bundle的新包加入dsh.profile.bundles;安装后重启dsh web生效(与 CLI 安装语义一致)。
工作原理
lib/index.js注入 Loader 和 WebServer,提供只读接口GET /user-plugin-list、GET /user-plugin-list/install/status和写接口POST /user-plugin-list/toggle、POST /user-plugin-list/uninstall、POST /user-plugin-list/install。lib/classify.js使用 Node 查找路径、realpath与 Harness 维护的系统 fallback 判断插件来自 profile、Harness 安装实体还是外部路径;preset 解析到不同安装实体(如 npx 缓存与全局安装)时,fallback 中的同名系统包仍会被识别为系统插件。lib/patch.js用与 Harness 一致的!!jsYAML 方言读写用户 patch 层:停用追加{ id, disabled: true }行,启用移除该行(若停用来自更低配置层则追加disabled: false覆盖行);写入串行化、原子化(.tmp+ rename),保留文件头部注释。lib/install.js实现 GitHub 链接安装:仅接受github:owner/repo与https://github.com/owner/repo白名单 spec(https://规范化为github:,其余一律拒绝),执行pnpm add(与dsh plugin --profile <name> add语义一致),再按 CLI 同样的规则把新依赖中声明dsh.bundle的包追加进dsh.profile.bundles;未声明dsh.bundle的新依赖给出提示,安装为普通依赖。安装以异步任务运行:POST /install立即返回jobId(202;单任务槽,同时只允许一个安装),页面每秒轮询GET /install/status?jobId=获取阶段(pnpm / reconcile)与最终结果;任务完成后保留一段时间,超时惰性清理;安装进行中时卸载接口返回 409 互斥。lib/pnpm.js提供 install/uninstall 共用的 pnpm 子进程封装:异步执行、输出有界截尾、超时保护、Windows 文件锁(EBUSY/EPERM 等)自动重试。lib/uninstall.js实现彻底卸载:先pnpm remove移除包、锁文件与依赖(与dsh plugin --profile <name> remove语义一致,pnpm 是三者唯一可靠的维护者),再按 CLI 同样的规则把包名从 profilepackage.json的dsh.profile.bundles中移除,随后删除 patch 层中引用该插件 id 的所有行,最后调用ctx.loader.remove()热卸载;pnpm 失败时不做任何文件改动(fail-closed)。对需要 pnpm 卸载的包,卸载前会扫描其他用户插件对它的依赖;home 层残留行始终会被检测;两者均以警告返回而不阻断。lib/client.js向settings.plugins.tab注册user页签,首次打开时读取快照,页签顶部提供 GitHub 安装表单,展开卡片时提供切换按钮与卸载按钮(卸载需输入插件名确认)。cordis.patch.yml声明 bundle 条目,安装后由 dsh 自动加入webprofile。
环境要求
- DeepSeek Harness
0.1.0-rc.6同系列版本。 - 已初始化
webprofile,并可打开默认地址http://127.0.0.1:3080。 dsh plugin使用的pnpm已在 PATH 中;也可以通过 Corepack 提供 pnpm。- 运行时依赖
js-yaml(Harness 安装已携带;本地开发时在仓库内npm install)。
安装
支持两种安装方式,任选其一。
方式一:在线安装(推荐)
直接以 GitHub 为源安装,包会以实体副本形式进入 profile,与本地目录无关:
dsh plugin --profile web add github:95384/DSH-user-plugin-list
更新到最新版本:
dsh plugin --profile web update user-plugin-list
方式二:本地安装(源码开发/调试)
克隆仓库并以本地目录安装:
git clone https://github.com/95384/DSH-user-plugin-list.git
cd DSH-user-plugin-list
dsh plugin --profile web add .
本地安装以链接方式指向源码目录,修改源码后重启 dsh web 即可生效;本地目录需保留,删除后请改用在线安装。
通用说明
本包声明了 dsh.bundle,安装成功后会自动加入 profile 的 bundle 层并写入 Loader 条目,无需手动编辑 cordis.patch.yml。重启 dsh web 并刷新浏览器后生效。
验证
- 打开 设置 -> 插件,确认右侧出现 用户插件 页签。
- 确认页面只显示非系统 Loader 条目,例如本插件自身和其他 profile 插件。
- 访问
http://127.0.0.1:3080/user-plugin-list,应返回包含entries的 JSON。 - 展开某个用户插件的卡片,点击 停用:状态标签变为"已停用",
cordis.patch.yml中出现- id: <行id>+disabled: true行;刷新页面、重启dsh web后状态保持。再次展开点击 启用 可恢复。 - 展开某个用户插件的卡片,点击 卸载 并输入插件名确认:卡片消失;
package.json的dependencies与dsh.profile.bundles中不再有该包;cordis.patch.yml中该插件的行被清空;node_modules与pnpm-lock.yaml由 pnpm 更新;运行中的插件立即停止。重启dsh web后完全生效(与 CLI 安装/卸载语义一致)。 - 在页签顶部输入
github:95384/DSH-ds-balance并点击 安装:等待 pnpm 完成后提示安装成功;package.json的dependencies出现该包、声明dsh.bundle的包进入dsh.profile.bundles,node_modules与pnpm-lock.yaml由 pnpm 更新。重启dsh web后插件出现在列表中(与 CLI 安装语义一致)。
卸载
dsh plugin --profile web remove user-plugin-list
卸载后重启 dsh web 并刷新浏览器。
开发与验证
npm install
npm test
npm pack --dry-run
测试覆盖包来源分类、系统 fallback、agent preset 直接解析、Loader 列表过滤、patch 层读写(含 !!js 往返、原子写、幂等)、卸载(pnpm seam、bundle reconcile、行清理、热卸载、依赖警告、home 层检测、fail-closed)、安装(GitHub spec 白名单校验、bundle reconcile 追加、非 bundle 警告、fail-closed)和浏览器页签注册与 install/toggle/uninstall 注入。
兼容性与限制
- 这里只列出当前 Loader 树里的插件;已安装但没有 Loader 条目的普通依赖不会显示。
- 页面读取一次快照,不持续订阅 Loader 变化;修改插件配置后需要重新打开设置或刷新页面。切换成功后列表会就地刷新。
- 来源判断依赖 file-backed profile、Node 包解析和 Harness 维护的系统 fallback。
- Host/Client 插件接口与 Harness
0.1.0-rc.6对齐,升级 Harness 后应重新运行测试。 - 启用 / 停用仅对 非系统 条目开放(与列表范围一致);停用后 Loader 热卸载并写入 patch 层,无需重启。
- 无法解析(
unresolved)的条目不能启用——启用后下次启动会因加载失败而 fail-loud;被父级组停用的条目不在详情中提供切换按钮。 user-plugin-list自身不能停用(否则本页签与切换接口一起消失)。- 被
!!js表达式停用的条目不能通过按钮启用,需手动编辑 patch 层。 - 若
$DSH_HOME/cordis.patch.yml(home 层)停用了某条目,profile 层无法覆盖,需在 home 层处理。 - 卸载仅对非系统条目开放;
user-plugin-list自身不能卸载(否则本页签与接口一起消失),请用dsh plugin --profile web remove user-plugin-list。 - 卸载需要 web 进程能执行
pnpm(与 CLI 相同)且 profile 目录可写;pnpm 缺失时返回明确错误,不产生任何文件改动。 - 卸载后建议重启
dsh web:bundle 层是启动时快照,重启前内存中仍保留被删插件的行;若重启前又修改了 patch 层(如切换其他插件),重组会因找不到已删包而失败并记录错误,重启后恢复。 - 被其他用户插件直接依赖的包在被卸载时只给出警告不阻断;home 层残留行只检测不删除(需手动编辑
$DSH_HOME/cordis.patch.yml)。 - 本地
link:安装卸载的是链接,源码目录不受影响(与 CLI 行为一致);无法解析(unresolved)的条目卸载时只清理配置行,若其仍保留在dependencies中,请用 CLI 完成收尾。 - 外部路径(
external)来源的条目不在 profile 的 pnpm 管理范围内,卸载时不运行 pnpm,只做 bundle reconcile、patch 行清理与热卸载。 - 若热卸载失败(例如插件正在加载中),文件层的卸载仍然完成,返回的警告会提示重启
dsh web后生效。 - 安装仅接受
github:owner/repo或https://github.com/owner/repo(可带#ref)链接,其他 spec(本地路径、其他域名、git+https 等)一律拒绝;安装的插件会在下次启动时由 Loader 执行其代码。 - 安装后需要重启
dsh web才生效(bundle 层是启动时快照);git 源插件若有构建脚本,pnpm 会要求先在pnpm-workspace.yaml配置allowBuilds,失败信息会透传给页面。 - 安装任务在 web 进程内存中运行:同时只允许一个安装任务(第二个返回 409);安装进行中时卸载接口返回 409;
dsh web重启会丢失进行中的任务,页面轮询到任务不存在时提示重新安装。 - 改写
cordis.patch.yml会保留文件头部注释,但会丢失行内注释并规范化排版。
目录结构
.
|-- README.md
|-- package.json
|-- cordis.patch.yml
|-- lib/
| |-- index.js
| |-- client.js
| |-- classify.js
| |-- patch.js
| |-- install.js
| |-- uninstall.js
| \-- pnpm.js
\-- test/
许可证
MIT,详见 LICENSE。