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/repohttps://github.com/owner/repo):执行 pnpm add 更新依赖、锁文件与包文件,自动把声明 dsh.bundle 的新包加入 dsh.profile.bundles;安装后重启 dsh web 生效(与 CLI 安装语义一致)。

工作原理

  • lib/index.js 注入 Loader 和 WebServer,提供只读接口 GET /user-plugin-listGET /user-plugin-list/install/status 和写接口 POST /user-plugin-list/togglePOST /user-plugin-list/uninstallPOST /user-plugin-list/install
  • lib/classify.js 使用 Node 查找路径、realpath 与 Harness 维护的系统 fallback 判断插件来自 profile、Harness 安装实体还是外部路径;preset 解析到不同安装实体(如 npx 缓存与全局安装)时,fallback 中的同名系统包仍会被识别为系统插件。
  • lib/patch.js 用与 Harness 一致的 !!js YAML 方言读写用户 patch 层:停用追加 { id, disabled: true } 行,启用移除该行(若停用来自更低配置层则追加 disabled: false 覆盖行);写入串行化、原子化(.tmp + rename),保留文件头部注释。
  • lib/install.js 实现 GitHub 链接安装:仅接受 github:owner/repohttps://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 同样的规则把包名从 profile package.jsondsh.profile.bundles 中移除,随后删除 patch 层中引用该插件 id 的所有行,最后调用 ctx.loader.remove() 热卸载;pnpm 失败时不做任何文件改动(fail-closed)。对需要 pnpm 卸载的包,卸载前会扫描其他用户插件对它的依赖;home 层残留行始终会被检测;两者均以警告返回而不阻断。
  • lib/client.jssettings.plugins.tab 注册 user 页签,首次打开时读取快照,页签顶部提供 GitHub 安装表单,展开卡片时提供切换按钮与卸载按钮(卸载需输入插件名确认)。
  • cordis.patch.yml 声明 bundle 条目,安装后由 dsh 自动加入 web profile。

环境要求

  • DeepSeek Harness 0.1.0-rc.6 同系列版本。
  • 已初始化 web profile,并可打开默认地址 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.jsondependenciesdsh.profile.bundles 中不再有该包;cordis.patch.yml 中该插件的行被清空;node_modulespnpm-lock.yaml 由 pnpm 更新;运行中的插件立即停止。重启 dsh web 后完全生效(与 CLI 安装/卸载语义一致)。
  • 在页签顶部输入 github:95384/DSH-ds-balance 并点击 安装:等待 pnpm 完成后提示安装成功;package.jsondependencies 出现该包、声明 dsh.bundle 的包进入 dsh.profile.bundlesnode_modulespnpm-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/repohttps://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