Skip to content
dsh.fish
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

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source