DeepSeek Harness Hub
← 返回列表

插件热重载管理kyorakuyk/dsh-hotreload-plugin-manager

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

在运行中热装热卸插件,无需重启即可生效

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/15 · 已提供中文文档

DeepSeek Harness 插件:从运行中的 dsh web 热安装 / 卸载 / 更新 / 启用-禁用 profile 插件包——无需重启,包含 Web UI。

综合分
28.3
GitHub 分
28.3
用户评分
★ Stars
2
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add kyorakuyk/dsh-hotreload-plugin-manager
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/cordis-plugin-hmr@deepseek-ai/cordis-plugin-include@deepseek-ai/cordis-plugin-timer@deepseek-ai/dsh-app-boot@deepseek-ai/dsh-typert-protocol
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-hotreload-plugin-manager

一个树外(out-of-tree)DeepSeek Harness
插件:在运行中的实例上直接完成插件的热安装、热卸载、禁用/启用——无需重启,
并提供 Web 设置页标签页:

- 🔥 热安装:按 spec(npm 包名 / git URL / github:owner/repo / file: 路径)
安装插件 bundle,立即热生效于运行中的 dsh web,且重启后保留。
- 🔥 热卸载:移除 bundle——行与 fiber 即刻卸载、依赖被清理、陈旧的
bundle 层条目一并移除。
- 🔥 禁用 / 启用:在 UI 上一键切换已安装 bundle 的条目开关,状态持久化且立即生效。
- 热更新:热替换 bundle 的补丁行并实时重放配置(模块代码变更按 Node 进程内
缓存特性仍需重启)。
- 零内核改动:纯树外 bundle,dsh checkout 完全不被触碰。
- 双面包:一个 npm 包同时是 host 网关与浏览器设置标签页。

架构

┌────────────────────────────── 浏览器(React)──────────────────────────────┐
│  设置 → 插件 → "插件管理"标签页(槽位 settings.plugins.tab)                 │
│        │  fetch('/plugin-manager/')                                      │
└────────┼──────────────────────────────────────────────────────────────────┘
▼
┌──────────────────────────── dsh web 进程 ──────────────────────────────────┐
│  webserver 路由(node:http)──▶ manager 核心                               │
│    ① pnpm add/remove(profile 内的真实依赖)                               │
│    ② 行写入 profile 用户补丁层(cordis.patch.yml)                         │
│    ③ 根 Include entry.update → Loader 挂载/卸载 fiber                      │
│  网关:TypertRemoteService(源码模式反射,无代码生成)                       │
└────────────────────────────────────────────────────────────────────────────┘

包是双面的:

- Node 半(lib/index.js,tsc 编译)——PluginManagerGateway,一个注册为
pluginManager 的 TypertRemoteService。api-gateway 可通过源码模式反射
分发它的 @Remote 方法(无需生成产物);同时它在 webServer 服务上注册浏览器
HTTP 传输。
- 浏览器半(lib/client.js,esbuild 打包)——注册进 settings.plugins.tab
槽位(id manager)的 Web 设置标签页,由 dsh-client-modules 发现,并以普通
模块表 bundle(window.__ModuleLoader__.load)形式服务。

工作原理

全部复用 launcher 已有的机制,因此插件不需要对 dsh checkout 做任何改动:

1. 安装:在 profile 目录执行 pnpm add 。包成为真实依赖(进入
profile 的 node_modules 与 package.json,pnpm 不会剪除它)。管理器读取
该 bundle 的 dsh.bundle.patch 行,写入 profile 的用户补丁层
(cordis.patch.yml)。
2. 热应用:直接对根 Include 条目调用 entry.update(携带新补丁列表)——
与 launcher 用户补丁 watcher 相同的调用。管理器自己应用自己的写入,因为文件
watcher 可能漏掉紧跟其后的写入事件。
3. 重启持久:用户补丁层在启动时被重新组合,因此已安装 bundle 在重启后保留,
且不触碰 dsh.profile.bundles(也就不会双组合行)。
4. 卸载 / 更新:移除或替换行,并执行 pnpm remove / pnpm update
(registry 包)或 remove + re-add(file:/link:——pnpm 的增量重拷不会
物化新增文件)。
5. 启停:写入用户层禁用行({ id, disabled }),按 id 覆盖 bundle 行而不
产生重复。

依赖语义透传给 pnpm。 管理器不解释被安装 bundle 的 manifest:
optionalDependencies 与可选 peer 的行为完全遵循 pnpm 的定义(失败的可选
依赖被跳过、安装继续;profile 使用 autoInstallPeers: false,peer 从不被
自动安装,运行时从 dsh 安装闭包解析)。插件若 import 非闭包 peer,其可用性
由 bundle 作者负责。

浏览器半通过插件自有的同源 HTTP 传输(/plugin-manager/)与 host 通信,
而不是 Typert remote 管线:npm 上的 dsh-api-gateway 包装不了(其若干依赖
dsh-type-meta、dsh-compact 等未发布),树外无法挂载 client contribution。
host 网关仍注册 Typert 绑定,供进程内消费者使用。

可安装的插件(什么能装)

唯一硬性要求:一个 npm 包,其 package.json 声明
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }(标准 DSH 插件
bundle)。满足即装,插件内部形态不限。

来源形式(spec 白名单,底层透传 pnpm add,pnpm 能解析的规范基本都能用):

- npm 包名(可带版本):@kyorakuyk/dsh-plugin-manager、@scope/name@^1.0.0
- git URL:https://github.com/x/y.git、git+ssh://…
- GitHub 简写:github:owner/repo、owner/repo
- 本地路径:file:C:/path/to/bundle、link:…(开发/离线最常用)

插件内部可以是什么(补丁行由根 Include 的插值机制统一处理):

- Host 插件:普通 Cordis 插件、Service、工具注册
- 浏览器 UI 插件:双面 dsh.client 包(浏览器半经 dsh-client-modules 可用)
- skill 提供方 / MCP 适配器:挂 dsh-skill-filesystem、dsh-mcp-client 的 bundle
- 补丁行含 insert / id-targeted 覆盖 / 禁用行 / group / !!js 表达式
- 带 optionalDependencies 的 bundle(缺失的可选依赖被跳过、安装继续——已实测)

装不了的(会明确拒绝):

- 无 dsh.bundle.patch 的普通库 → 拒绝并自动 pnpm remove 回滚,不留残渣
- 旧 .dsh-plugin / config.yaml 安装格式 → 不支持(DSH 核心已整体移除该路径)
- 补丁行 id 与用户层或其他 bundle 冲突 → 拒绝安装(防双组合)
- git 规格装完无法识别包名 → 明确报错 "could not resolve the installed package name"

边界提醒:

- 非闭包 peer:bundle 若 import 既不在 profile 也不在 dsh 安装闭包里的
peer,运行时挂——这是 bundle 作者的责任,管理器不干预
- 模块代码级更新需重启(Node 进程内缓存,见"已知限制")
- 管理器与 dsh plugin CLI 不要对同一 bundle 混用(卸载会自动清理 CLI
残留的 bundle 层条目)

快速开始(其他用户)

前置条件:Node ≥ 22、pnpm ≥ 10、已安装 dsh 并初始化过目标 profile。

① 直接从 GitHub 安装(推荐)——无需克隆本仓库:

dsh plugin --profile web add "github:kyorakuyk/dsh-hotreload-plugin-manager"
或完整 git URL:
dsh plugin --profile web add "https://github.com/kyorakuyk/dsh-hotreload-plugin-manager.git"

② 或者克隆后本地安装:

git clone https://github.com/kyorakuyk/dsh-hotreload-plugin-manager.git
dsh plugin --profile web add "file:$(pwd)/dsh-hotreload-plugin-manager"

③ 或者从 npm 安装(发布后可用):

dsh plugin --profile web add "@kyorakuyk/dsh-plugin-manager"

装完后必须重启 dsh web 实例(新 bundle 需要重启才挂载;仓库已包含构建产物 lib/,无需先构建),浏览器硬刷新一次(Ctrl+Shift+R):

dsh --profile web

然后打开 Web UI → 设置 → 插件 → 插件管理,按 spec 安装其他插件——npm 包名、
git URL、github:owner/repo、或 file:/link: 路径均可。

npm 已发布:dsh plugin --profile web add "@kyorakuyk/dsh-plugin-manager"。

Web UI

设置 → 插件 → 插件管理:

- 安装输入框(支持上述 spec 形式);
- 已安装列表,每个包带 禁用/启用、更新、卸载 按钮(禁用后显示
"(已禁用)",按钮切换为"启用");
- 手动 刷新 按钮(列表实时反映热变更,无需整页刷新);
- 操作结果内联展示(失败时包含 pnpm 输出尾部)。

HTTP API

| 方法 | 路径 | Body | 结果 |
|---|---|---|---|
| GET | /plugin-manager/list | — | { ok, value: Bundle[] } |
| POST | /plugin-manager/install | { spec } | { ok, message, exitCode?, tail? } |
| POST | /plugin-manager/uninstall | { packageName } | 同上 |
| POST | /plugin-manager/update | { packageName } | 同上 |
| POST | /plugin-manager/setEnabled | { entryId, enabled } | 同上 |

Bundle 形如 { packageName, version?, spec, rowIds, disabled }。

开发

pnpm install
pnpm build        # tsc(Node 半)+ esbuild(浏览器 bundle)
pnpm test         # vitest:REAL-composition / HTTP / bundle 契约共 22 个测试
pnpm typecheck

发布(npm Trusted Publishing)

发布走 GitHub Actions OIDC 信任发布——无需 token、无需 OTP/恢复码:

npm version 0.1.5 --no-git-tag-version   # 升版本sh
git add package.json pnpm-lock.yaml && git commit -m "pkg: bump to 0.1.5"
git push
git tag v0.1.5 && git push origin v0.1.5 # 触发 .github/workflows/publish.yml

workflow 会:typecheck → build → test → npm publish --provenance(OIDC)
→ 自动创建 GitHub Release。发布失败可重跑:
sh
gh workflow run publish.yml --ref main -f publish_ref=refs/tags/v0.1.5

前置:npm 账号需把本仓库 + publish.yml 注册为该包的 Trusted Publisher
(npmjs.com → 包设置 → Trusted Publisher)。

目录结构:

src/                 host 半(tsc → lib/.js)
├── index.ts         PluginManagerGateway(TypertRemoteService + @Remote)
├── manager.ts       核心生命周期操作
├── http.ts          webserver 路由处理器
└── spec|pnpm|patch-layer|state|types.ts
src/client/index.tsx 浏览器半(esbuild → lib/client.js)
scripts/build-client.mjs  esbuild 配置(模块表闭包契约)
tests/               vitest 套件 + fixtures/ 测试夹具

依赖按"运行时共享安装内单一 Cordis 实例"分类:@deepseek-ai/ 包为
peerDependencies(从 dsh 安装闭包解析),js-yaml 是唯一运行时依赖,构建与
测试工具放在 devDependencies。

已知限制与待办

- 远程信任:/plugin-manager/ 路由对任何能触达服务器的人都开放。Web 面
默认仅回环绑定(launcher 拒绝 --host 0.0.0.0),但暴露到局域网时不能依赖
/api 信任围栏的保护;按可信权威校验为待办。
- 与 CLI 混用:管理器把 bundle 装为真实依赖,但不加入 dsh.profile.bundles
(行在用户补丁层)。之后若再运行 dsh plugin CLI,reconcile 会把声明
dsh.bundle 的依赖并入 bundle 层,下一次启动时双组合这些行。每个 bundle 只用
一种机制(卸载时会自动清理 CLI 残留的 bundle 层条目)。
- 无法解析包名的 spec:安装 git URL 时若无法在 profile 的 node_modules
中识别出包名,会以 "could not resolve the installed package name" 明确失败。
- 行 id 冲突在安装时被拒绝:补丁行与用户层(或其他 bundle)冲突的 bundle
不会被安装。
- 更新热应用的是组合与配置,不是模块代码。Node 会在进程内缓存已解析的模块
与包 exports,因此 代码* 或 exports map 变更的版本需要重启才生效;manager
的 update 热替换补丁行(行集合与行配置),依赖本身经 pnpm update
(registry)或 remove + re-add(file:/link:)刷新。
- 启停按行 id 定位条目;非补丁行 id 的生成式 Loader id 无法被切换。
- pnpm ≥ 11 的 supply-chain 策略:默认 minimumReleaseAge(24h)会拒绝
"刚发布"的包(ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION)。管理器执行
pnpm 时统一附加 --config.minimumReleaseAge=0 跳过冷却(安装是用户主动
操作),并把违规包的 scope 追加到 profile pnpm-workspace.yaml 的
minimumReleaseAgeExclude(例如 @kyorakuyk/*)作为第二道防线。带
构建脚本的 git 依赖(prepare 等)会被 allowBuilds 白名单拦截
(ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED / ERR_PNPM_IGNORED_BUILDS):
管理器会从 pnpm 输出提取其要求的精确 spec(包名@git+url#sha),
自动写入 allowBuilds 并重试一次。手动处理时把对应 scope/spec 加入
pnpm-workspace.yaml 对应区块即可。
- 暂无插件市场:安装是 spec 驱动的;浏览与精选发现为待办。
- 向运行中的 profile 部署 bundle 变更需要重启。启动清单里的 bundle rev 与
host 半都在进程激活时冻结:把变更后的代码重装进已运行的 profile,服务端按
请求读取新 client bundle,但 host 仍运行旧逻辑(且启动图保持旧 rev);浏览器
也可能在旧 URL 下缓存旧 bundle。重装 host 代码后请重启实例,并硬刷新一次
浏览器;管理器标签页能容忍错配窗口(对缺失的行状态做了防御)。
- in-box 的"插件清单"标签页是即时快照。它在首次挂载时拉取一次 Loader
快照,之后保持挂载(隐藏),因此不会反映在"插件管理"里做的热生命周期变更
——需要刷新页面。管理器标签页本身是实时的(每次操作后自动重拉,并有手动
刷新按钮)。

Model Experience

无:管理器不注册任何 prompt、工具、消息或 provider 请求。

KV Cache 影响

无;本包从不组装模型输入。

License

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群