Bundle
@dsh-external/dsh-mod-manager
DSH Web profile 模组管理器:在设置页里开关第三方插件,通过改写 profile 的 cordis.patch.yml 并由 patch watcher 热生效,无需手动改文件、无需重启。
- Source
- HamSamMike
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 14 days ago
Readme
# dsh-mod-manager
面向 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web profile 的第三方插件管理器。
它把 Harness 插件变成类似游戏模组的开关:在 **设置 → 模组管理** 中即可启用或禁用已安装的插件,不必反复手动编辑 `cordis.patch.yml`。
## 功能
- 在 Harness 设置页集中显示第三方插件状态。
- 自动发现通过 `dsh plugin --profile … add …` 安装到 profile 的第三方 bundle。
- 一键启用或禁用插件,无需卸载插件包。
- 修改后通过 Harness patch watcher 热更新,通常无需重启 `dsh web`。
- 自动排除 Harness 核心 bundle 和管理器自身。
- 保留 `config.mods`,用于自定义名称或补充无法自动关联的插件行。
- 保留 `cordis.patch.yml` 中与受管插件无关的用户配置。
- 兼容空文件、纯注释文件和 `[]` 空补丁数组。
> [!IMPORTANT]
> 本插件负责的是**发现、启用与禁用**,不会替你安装或卸载其它插件。目标插件必须已经添加到同一个 profile;新安装 bundle 后需要重启一次 `dsh web` 才会进入 Loader,之后便会自动出现在管理器中。
## 环境要求
- DeepSeek Harness Web profile
- Node.js `^22.19.0` 或 `>=24.0.0`
- 需要管理的第三方插件已经安装到目标 profile
## 安装
### 从 GitHub 安装
```powershell
dsh plugin --profile web add github:HamSamMike/dsh-mod-manager
```
如果你通过 Harness 源码仓库里的 `pnpm dsh` 使用 CLI:
```powershell
pnpm dsh plugin --profile web add github:HamSamMike/dsh-mod-manager
```
### 从本地目录安装
```powershell
dsh plugin --profile web add C:\path\to\dsh-mod-manager
```
安装完成后重启一次 Harness:
```powershell
dsh web
```
也可以检查插件是否已经进入最终组合配置:
```powershell
dsh --profile web --dump-config
```
## 使用
1. 打开 [http://localhost:3080](http://localhost:3080)。
2. 进入 **设置 → 模组管理**。
3. 点击目标插件右侧的 **开启** 或 **关闭**。
页面中可能出现以下状态:
| 状态 | 含义 |
| --- | --- |
| 运行中 | 插件已安装,Loader 当前处于启用状态 |
| 已关闭 | 插件已安装,并被 `disabled: true` 禁用 |
| 未安装 | 配置的插件行 ID 没有出现在当前 Loader 组合树中 |
切换插件时,管理器会更新:
```text
$DSH_HOME/profiles/<profile>/cordis.patch.yml
```
未设置 `DSH_HOME` 时,默认位置为:
```text
~/.dsh/profiles/<profile>/cordis.patch.yml
```
## 自动发现插件
默认情况下,管理器会读取目标 profile 的 `package.json → dsh.profile.bundles`,并与当前 Loader 行进行匹配。通过以下命令安装的第三方插件会在重启 Harness 后自动出现:
```powershell
dsh plugin --profile web add dsh-pet
```
自动发现会排除:
- `@deepseek-ai/dsh-base`
- `@deepseek-ai/dsh-web-app`
- `@dsh-external/dsh-mod-manager` / `dsh-mod-manager`
仓库自带配置位于 [`cordis.patch.yml`](./cordis.patch.yml):
```yaml
- insert:
- id: dsh-mod-manager
name: '@dsh-external/dsh-mod-manager'
config:
profile: web
autoDiscover: true
mods:
- id: ui-skin-maid-atelier
name: 鲸娘皮肤 · maid-atelier
- id: dsh-ads
name: 广告恶搞 · dsh-ads
```
配置字段:
- `profile`:需要修改的 Harness profile,默认为 `web`。
- `autoDiscover`:是否自动发现当前 profile 中的第三方 bundle,默认为 `true`。
- `mods[].id`:可选的 Loader **行 ID**,用于补充自动发现无法关联的行。
- `mods[].name`:可选的友好名称;ID 与自动发现结果相同时会覆盖默认包名。
### 如何找到正确的插件 ID
大多数插件无需手动填写 ID。只有需要自定义名称,或插件的 Loader 模块名无法与 bundle 包名关联时,才需要使用 `config.mods`。
这里需要的是插件 bundle 补丁中 `insert` 条目的 `id`,不是 npm 包名。
例如,目标插件的 `cordis.patch.yml` 为:
```yaml
- insert:
- id: example-plugin
name: '@example/dsh-plugin'
```
管理器中应填写:
```yaml
mods:
- id: example-plugin
name: Example Plugin
```
### 在 profile 中覆盖默认列表
也可以在目标 profile 自己的 `cordis.patch.yml` 中覆盖管理器配置,而不修改本仓库:
```yaml
- id: dsh-mod-manager
config:
profile: web
autoDiscover: true
mods:
- id: example-plugin
name: Example Plugin
```
如需完全使用手动列表,可设置 `autoDiscover: false`。修改管理器自身配置或安装新的 bundle 后,需要重启一次 `dsh web`;之后通过页面启用或禁用插件时不需要重启。
## 工作原理
Host 模块 [`lib/index.js`](./lib/index.js) 注入 Harness 的 `webServer` 和 `loader` 服务,并注册两个同源路由:
- `GET /dsh-mod-manager/list.json`:合并 profile bundle 自动发现结果与显式 `config.mods`,读取安装与启用状态。
- `POST /dsh-mod-manager/set.json`:接收 `{ id, enabled }` 并更新用户补丁文件。
Client 模块 [`lib/client.js`](./lib/client.js) 在 `settings.section` 中注册“模组管理”页面,通过上述路由与 Host 通信。
禁用插件时,管理器会写入一个带边界标记的区块:
```yaml
# === dsh-mod-manager (generated — use 设置 → 模组管理, not this file) ===
- id: example-plugin
disabled: true
# === end dsh-mod-manager ===
```
重新启用后,对应条目会被移除。没有其它用户补丁时,文件会保留为合法的空数组:
```yaml
[]
```
## 开发与测试
本项目使用原生 ESM,当前不需要额外构建步骤。
运行回归测试:
```powershell
npm test
```
项目结构:
```text
dsh-mod-manager/
├─ cordis.patch.yml # Bundle 补丁与受管插件列表
├─ lib/
│ ├─ index.js # Host 插件、状态读取与补丁写入
│ └─ client.js # 设置页面
├─ test/
│ └─ index.test.js # 禁用/启用与 YAML 回归测试
└─ package.json
```
## 常见问题
### 插件显示“未安装”
确认目标插件已经添加到当前 profile,并检查 `mods[].id` 是否与目标插件 `cordis.patch.yml` 中的 `insert[].id` 完全一致。
### 新安装的插件没有自动出现
确认安装命令使用了管理器所指向的同一个 profile,并在安装后重启一次 `dsh web`。自动发现依赖启动后的 Loader 行;仅刷新浏览器不会加载新 bundle。
### 修改 `mods` 后页面没有变化
`mods` 属于管理器自身的启动配置。修改后重启 `dsh web`,再刷新浏览器页面。
### Harness 启动时提示补丁必须是顶层 YAML 数组
检查 profile 的 `cordis.patch.yml`。没有任何补丁时也应写成:
```yaml
[]
```
不能只保留注释。当前版本的管理器会在后续切换时自动维持合法格式。
## 安全边界
- 只读写目标 profile 的 `cordis.patch.yml`。
- 自动发现范围只来自目标 profile 明确登记的 `dsh.profile.bundles`,不会扫描任意 `node_modules`。
- 切换接口只接受当前自动发现或 `config.mods` 明确登记的 Loader 行 ID。
- 不扫描插件目录,不修改插件源码,也不删除已安装的插件包。
- 手写的受管插件禁用条目会由管理器接管并整理到生成区块中;其它补丁条目会保留。
## License
[MIT](./LICENSE)
Install
dsh plugin --profile web add github:HamSamMike/dsh-mod-manager
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-external-dsh-mod-manager from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.