dsh-plugin-rack 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +212 -2
- package/client.js +2867 -0
- package/cordis.patch.yml +3 -0
- package/icon.svg +11 -0
- package/index.js +4081 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +73 -4
- package/test/behaviour.mjs +549 -0
- package/test/download.mjs +221 -0
- package/test/job-background.mjs +205 -0
- package/test/pnpm-command.mjs +49 -0
- package/test/self-check.mjs +124 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-plugin-dashboard contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,213 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-plugin-dashboard · 插件管理台
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
DSH(DeepSeek Harness)的插件面板:**所有插件一屏看完,一个开关直接开关,更新完不用重启。**
|
|
4
|
+
|
|
5
|
+
装在侧边栏,不用进设置页翻。
|
|
6
|
+
|
|
7
|
+
## 用来干什么
|
|
8
|
+
|
|
9
|
+
插件装多了以后有几件事很烦:
|
|
10
|
+
|
|
11
|
+
- 装了哪些、现在开着还是关着、是本地开发版还是线上版,得一个个翻;
|
|
12
|
+
- 关一个插件要重启整个 DSH;
|
|
13
|
+
- 想看看有没有新版要自己去查 npm,装错了还得自己回滚;
|
|
14
|
+
- 有些插件是 GitHub 直装、本地 tar 包、甚至只是个软链,普通办法根本看不出有没有新版。
|
|
15
|
+
|
|
16
|
+
这个面板把它们收进一个列表。
|
|
17
|
+
|
|
18
|
+
## 功能
|
|
19
|
+
|
|
20
|
+
### 列表
|
|
21
|
+
|
|
22
|
+
- **四个页签**:已安装插件 / 核心组件 / 异常 / 更新。
|
|
23
|
+
- 每行显示:**开关**、**手动或自动**标记、**装法来源**(npm、npmmirror、github、本地文件包、本地软链)、**有新版时的行内更新按钮**。
|
|
24
|
+
- **点整行展开详情**:包名、版本、许可、作者、安装目录、依赖、GitHub / npm / 主页链接,以及具体功能说明。
|
|
25
|
+
- 核心组件(`@deepseek-ai/*`)也全部列出,并按用途配了中文功能名,例如「插件设置」「文件工具」「会话检索」,知道哪个组件管什么才不会误关。
|
|
26
|
+
- 「异常」页用来放加载失败的插件,写明失败原因;「被插件包关闭」这类由别的插件主动隐藏的组件会单独成组,**那不是故障**。
|
|
27
|
+
|
|
28
|
+
### 开关
|
|
29
|
+
|
|
30
|
+
- 每个插件一个开关,**点完立即生效,不需要重启 DSH**(宿主支持热替换时)。
|
|
31
|
+
- **手动 / 自动**标记:只有标为「自动」的插件才会被「一键全部开启 / 关闭」影响。标成手动的,一键操作永远不会碰它。
|
|
32
|
+
- 每页有自己的一套批量按钮:一键全部开启、一键全部关闭、全部设为自动、全部设为手动,**只对当前这一页生效**。
|
|
33
|
+
- 批量操作前在面板内弹出确认条(不是浏览器弹窗),写清楚要动几个、动哪些。
|
|
34
|
+
- 每行最左有一盏**状态灯**:绿=运行中、黄=加载中、红=加载失败、灰=未启用、空心=只读核心组件。加载失败的行整行淡红,不用展开就能看见。
|
|
35
|
+
- 第一次打开时,「自动」名单默认只包含这个 profile 安装的第三方插件,并且排除本面板自己;内置核心组件一律「手动」,所以一键全关不会把 harness 拆掉。
|
|
36
|
+
|
|
37
|
+
### 更新
|
|
38
|
+
|
|
39
|
+
- 「检查更新」把 profile 里按精确版本锁定的依赖逐个查 registry 最新版,有新的直接在列表行里标出来:`⬆ v0.1.29 ➡ v0.1.30 npm`,**点一下只更新那一个插件**。
|
|
40
|
+
- 更新由宿主执行:**点完就可以关掉面板**,pnpm 照样跑完。重新打开面板时,顶部会显示「后台更新中 · N 个插件」,跑完了补一条结果提示。不用守着这个界面,也不用去翻日志。卡住了可以点横幅右边的「取消」。
|
|
41
|
+
- **会话正忙时也不白点**:需要下载的更新会先把附件取下来、核对 sha256,然后排队;宿主每 10 秒看一眼,等所有会话都空了就自己装上(下载过的东西不会重下)。排队期间横幅显示「已排队…」。
|
|
42
|
+
- **网络不用你配**:下载按这个顺序自动选路,`config.json` 里明确指定的代理 → 环境变量(`HTTPS_PROXY` / `ALL_PROXY`,`NO_PROXY` 会照规矩跳过)→ 系统代理(Windows 的 Internet 设置)→ 直连;一条走不通就换下一条,不会因为代理没开就整个更新失败。HTTP 代理和 SOCKS5 都支持,带用户名密码也行,查 GitHub 接口的部分同样走这些代理。
|
|
43
|
+
- **pnpm 从哪来**:先找 PATH 上的 pnpm,再找 `%APPDATA%\npm`、`%LOCALAPPDATA%\pnpm`、`PNPM_HOME`、`~/.local/share/pnpm`、Homebrew 与系统级安装;Windows 的 `pnpm.cmd` / `pnpm.ps1` 会用 `cmd.exe` / `powershell` 包一层再跑。
|
|
44
|
+
- 想固定某个代理,在数据目录写 `config.json`:`{ "download": { "proxy": "http://127.0.0.1:7897" } }`;写 `"off"` 就只直连;不写就是自动。
|
|
45
|
+
- **断点续传**:连接断了按 `Range` 接着下,取消或失败后保留 `.part`,下次点更新从断的地方继续,不用重下 30 MB。总上限 30 分钟,30 秒没有数据就判定卡死。GitHub 偶尔会把连接挂住,宁可报错也不让面板一直转圈。下过的包按 sha256 复用,重试同一版本不会重新下载。
|
|
46
|
+
- **所有更新通道合在一个列表、一个按钮里**:勾选后按来源自动分流。精确版本锁定的依赖合成一次 `pnpm add` 跑完;GitHub 直装走重新拉取;本地压缩包走「下载官方附件 → 核对 sha256 → 替换」;压缩包地址走重新 pin。每个渠道各自成败,一条渠道失败不会中断其它渠道,最后给一份合并报告(「N 组里 M 组失败,其余已完成」)。
|
|
47
|
+
- 装完**自动热替换**,新版本当场生效,不用重启;界面类插件刷新一下页面即可。
|
|
48
|
+
- 能识别 **GitHub 直装 / npm 镜像 tar 包 / 本地文件包 / 本地软链** 这四种装法,并在同一个列表里标出各自来源;本地软链没有「升级」这回事,不会被勾选。
|
|
49
|
+
- registry 取 profile 自己的配置(`pluginManager.registries()`),不强行走 npmjs;装了 `GITHUB_TOKEN` 的话查 GitHub 版本会用它提额。
|
|
50
|
+
|
|
51
|
+
### 安装与卸载
|
|
52
|
+
|
|
53
|
+
- 输入包名先「检查」:**只做预检,什么都不动**。它会告诉你这是不是个 DSH 插件包、版本多少、干什么用的。像 `is-odd` 这种普通 npm 包会被拦下来,因为它没声明 `dsh.bundle`,装了也不会被加载。
|
|
54
|
+
- 确认了再「安装」,走宿主官方的插件管理接口。
|
|
55
|
+
- 每行可以「卸载」,**要点两下确认**;由宿主管理、不允许移除的核心包会被拒绝。
|
|
56
|
+
|
|
57
|
+
### 安全设计
|
|
58
|
+
|
|
59
|
+
这个面板能改你的运行环境,所以几条底线是硬编码的:
|
|
60
|
+
|
|
61
|
+
- **动手之前先备份** `package.json` 与 `pnpm-lock.yaml`,失败整体写回;更新失败还会补跑一次重同步,避免「文件回滚了但 `node_modules` 没回滚」的假回滚。
|
|
62
|
+
- **批量操作要过维护门**:有会话正在跑时不动文件,等它空闲。
|
|
63
|
+
- **并发守卫**:安装 / 卸载 / 更新 / 批量操作四者互斥。同一时刻只允许一条写操作在跑。两个 pnpm 同时改同一份 `package.json` 会把 profile 写坏。
|
|
64
|
+
- **面板不会卸载自己**;`removable` 为 false 的包一律拒绝。
|
|
65
|
+
- 只有标为「自动」的插件才进批量范围,**页面筛选只能缩小范围,不能扩大**。
|
|
66
|
+
- 核心组件**不会**被一刀切跳过:204 个 `@deepseek-ai/*` 行里只有 16 个真只读,其余受开关控制。真正被跳过的只有**面板自己那一行**(在自己发起的请求里关自己,会让正在响应的路由断掉)。
|
|
67
|
+
|
|
68
|
+
## 自检
|
|
69
|
+
|
|
70
|
+
改动源码后跑一遍,它会检查那些「坏了但不会报错」的东西:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
node test/self-check.mjs
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
检查项:中英文词条是否一一对应、有没有用到字典里没有的键、头部注释里列的路由和实际路由表是否一致、**提前 return 之后有没有落下的 hook**(这个曾经把整个面板搞崩过)、以及残留的调试语句。
|
|
77
|
+
|
|
78
|
+
## 安装
|
|
79
|
+
|
|
80
|
+
在 DSH 里装有三条路,任选其一:
|
|
81
|
+
|
|
82
|
+
**① 从 GitHub 装(推荐,不依赖 npm)**
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
dsh plugin add github:LZM-P/dsh-plugin-dashboard
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**② 从 npm 装(发布后可用)**
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
dsh plugin add dsh-plugin-dashboard
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**③ 在插件管理界面里点「安装」**,把上面任意一条的 spec 填进去。
|
|
95
|
+
|
|
96
|
+
装好后侧边栏会出现「插件管理」。
|
|
97
|
+
|
|
98
|
+
> 如果宿主版本不认 `github:` 前缀,改用 tarball 地址:
|
|
99
|
+
> `dsh plugin add https://github.com/LZM-P/dsh-plugin-dashboard/archive/refs/heads/main.tar.gz`
|
|
100
|
+
|
|
101
|
+
## 数据放在哪
|
|
102
|
+
|
|
103
|
+
- 代码:插件自己的安装目录。
|
|
104
|
+
- 运行时数据目录:`<DSH_HOME>/plugin-dashboard/profiles/<profile>/`(Windows 默认 `C:\Users\<你>\.dsh\plugin-dashboard\profiles\desktop\`)。一个 profile 一个目录,里面是:
|
|
105
|
+
- `state.json`:哪几个插件被标成了自动,以及面板自己创建过哪些配置覆盖。几行 JSON。删掉只会让自动清单重置,**不影响任何插件**。
|
|
106
|
+
- `job.json`:正在跑或上一次跑完的更新任务。面板关掉再打开靠它接回来。
|
|
107
|
+
- `queue.json`:已下载校验、等会话空闲才装的更新。
|
|
108
|
+
- `config.json`:下载代理等手工配置。
|
|
109
|
+
- `last-update.log` / `update-log.jsonl`:前一个是最近一次更新的完整日志,后一个是每次更新的追加历史。
|
|
110
|
+
- **每个 profile 各存一份**:同一个 DSH 下开多个 profile 时,自动清单、正在跑的任务、待装队列、代理配置互不串台。
|
|
111
|
+
|
|
112
|
+
### 从旧版本升级(单一目录 → 按 profile 分目录)
|
|
113
|
+
|
|
114
|
+
早期版本把所有东西都放在 `<DSH_HOME>/plugin-rack/` 这一个目录里。升级后第一次启动时,上面这些文件会**逐个复制**到按 profile 分的目录(已存在的不覆盖,旧文件保留不删):
|
|
115
|
+
|
|
116
|
+
- 排好队还没装的更新会跟过来,不会静默丢失;
|
|
117
|
+
- 手工配的下载代理继续生效,不用重配;
|
|
118
|
+
- 任务历史与更新日志都能在面板里看到。
|
|
119
|
+
|
|
120
|
+
如果旧目录里的文件已经被你手动删掉,那这几项就按新装处理(队列空、代理回落到环境变量、历史为空),不影响插件本身。
|
|
121
|
+
|
|
122
|
+
## 结构
|
|
123
|
+
|
|
124
|
+
| 文件 | 作用 |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `index.js` | 宿主端:注册 `/api/dsh-plugin-rack` 前缀路由,负责读取插件状态、批量操作、更新与安装卸载 |
|
|
127
|
+
| `client.js` | 客户端:侧边栏图标 + `main` 面板的界面(无需构建步骤,浏览器直接加载) |
|
|
128
|
+
| `cordis.patch.yml` | bundle 补丁,插入 `plugin-dashboard` 这一行 |
|
|
129
|
+
| `locale/{en,zh}.json` | 插件名与描述(插件管理页展示用) |
|
|
130
|
+
| `icon.svg` | 插件图标 |
|
|
131
|
+
| `test/self-check.mjs` | 自检脚本:词条对照、路由对照、hook 顺序、调试残留 |
|
|
132
|
+
|
|
133
|
+
## 接口
|
|
134
|
+
|
|
135
|
+
宿主端只暴露一个同源前缀路由,客户端直接用 `fetch` 调用,因此**不依赖** `remoteAccess` 对 `pluginManager/*` 的授权策略:
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
GET /api/dsh-plugin-rack/ping 存活探测,不碰任何服务
|
|
139
|
+
GET /api/dsh-plugin-rack/ ping 的别名
|
|
140
|
+
GET /api/dsh-plugin-rack/state 全部插件行 + 自动名单 + 批量进度
|
|
141
|
+
GET /api/dsh-plugin-rack/detail 某个插件的包信息(?entryId=)
|
|
142
|
+
GET /api/dsh-plugin-rack/updates 检查更新(按精确版本锁定的依赖)
|
|
143
|
+
GET /api/dsh-plugin-rack/extras 非精确版本的安装来源(github / tar 包 / 本地文件 / 软链),供更新页分流
|
|
144
|
+
GET /api/dsh-plugin-rack/updatelog 上一次更新的日志
|
|
145
|
+
GET /api/dsh-plugin-rack/registries 当前生效的 registry
|
|
146
|
+
GET /api/dsh-plugin-rack/removable 可以卸载的插件名单
|
|
147
|
+
GET /api/dsh-plugin-rack/inspect 安装预检(?spec=,只查不装)
|
|
148
|
+
GET /api/dsh-plugin-rack/fileplan ?name= 本地 file: 依赖会升到哪个版本
|
|
149
|
+
GET /api/dsh-plugin-rack/job 正在跑的装包任务,或上一次的结果(running / finishedAt / interrupted)+ 待装队列
|
|
150
|
+
POST /api/dsh-plugin-rack/job { action: 'cancel' } 取消正在跑的那一次
|
|
151
|
+
GET /api/dsh-plugin-rack/summary 只读精简行,给脚本和 agent 用
|
|
152
|
+
POST /api/dsh-plugin-rack/plugin { entryId, enabled?, auto? }
|
|
153
|
+
POST /api/dsh-plugin-rack/bulk { enabled, scope, save?, cancel? }
|
|
154
|
+
POST /api/dsh-plugin-rack/roster { mode: 'group', scope, auto }
|
|
155
|
+
POST /api/dsh-plugin-rack/updates { names: [...] }
|
|
156
|
+
POST /api/dsh-plugin-rack/extras { name, action }
|
|
157
|
+
POST /api/dsh-plugin-rack/install { spec }
|
|
158
|
+
POST /api/dsh-plugin-rack/uninstall { name }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### `save` 模式
|
|
162
|
+
|
|
163
|
+
`POST /bulk` 带 `save: true` 时**只写一次 profile 的 `cordis.patch.yml`,不逐个去动插件**:
|
|
164
|
+
|
|
165
|
+
| | `save: true` | 默认(逐个热生效) |
|
|
166
|
+
| --- | --- | --- |
|
|
167
|
+
| 写文件耗时 | 约 0.4 秒 | — |
|
|
168
|
+
| 重载方式 | 宿主看到文件变了,**一次性重载整批** | 每个插件一次卸载+加载(宿主 O(N) 对账,通常几秒到几十秒) |
|
|
169
|
+
| 适合 | 「先全关 → 去更新 → 再重启」 | 想马上看到单个插件的变化 |
|
|
170
|
+
|
|
171
|
+
写入是原子的(临时文件 + rename),只删自己创建过的覆盖项,用户原有的配置行原样保留。
|
|
172
|
+
|
|
173
|
+
只读行(`management-required` / `unaddressable`)在界面上开关与模式按钮都被禁用,并带标签说明原因。
|
|
174
|
+
|
|
175
|
+
## 安全模型
|
|
176
|
+
|
|
177
|
+
这个插件会写你的 `cordis.patch.yml`、调 pnpm、删包。为了让这些操作可控,做了四层防护:
|
|
178
|
+
|
|
179
|
+
1. **网络暴露面**:API 只在 `127.0.0.1` / `localhost` / `::1` 上可达。宿主的 web server 本来就只绑 loopback,所以外网碰不到这个端口。
|
|
180
|
+
2. **Host / Origin 校验**:每个请求都先过两道闸:Host 头必须指向 loopback,Origin 头(如果存在)也必须解析到 loopback。这挡的是同机浏览器里的恶意网页:它无法用 `<img>` 或 `fetch` 跨站调用你的 API(DNS rebinding / CSRF 都被这两道闸拦下)。
|
|
181
|
+
2b. **写操作还要求"你确实是从面板来的"**:`POST` 除了要 `application/json`,还必须带 `Origin`、或 `Sec-Fetch-Site: same-origin`、或显式加上 `x-dsh-plugin-dashboard: 1` 请求头。
|
|
182
|
+
|
|
183
|
+
这道门挡的是**无意的跨站 POST**(比如别处一个表单顺手打过来、或者某个页面被 XSS 后盲发请求),它对「完全不带 Origin」的请求本来是不设防的,而 `curl -X POST` 正好属于这一类。
|
|
184
|
+
|
|
185
|
+
它**不是鉴权**:本机任何拿到这个端口的脚本,加一行请求头就能过。真要防住同机脚本得引入 token 或随机口令,目前没有做,也不假装做了。面板自己永远带这个头;写脚本调接口时也带一个:
|
|
186
|
+
```bash
|
|
187
|
+
curl -X POST http://127.0.0.1:9546/api/dsh-plugin-rack/bulk \
|
|
188
|
+
-H 'content-type: application/json' \
|
|
189
|
+
-H 'x-dsh-plugin-dashboard: 1' \
|
|
190
|
+
-d '{"enabled":false,"scope":"installed"}'
|
|
191
|
+
```
|
|
192
|
+
3. **卸载白名单**:界面上的「卸载」按钮不是对所有行都显示。只有宿主 `pluginManager` 服务明确标记为 `removable` 的包才会出现按钮。核心组件、面板自己、harness 命脉都**永远不会**出现在可卸载列表里,所以误点卸载也不会把系统拆坏。
|
|
193
|
+
4. **更新回滚**:批量更新前会备份 `package.json` + `pnpm-lock.yaml` + `pnpm-workspace.yaml` 三个文件。pnpm 返回非零退出码时,先把这三个文件写回原内容,再跑一次 `pnpm install --prefer-offline` 把 `node_modules` 也拨回去。**失败 = 一个包都没改动**,不会留下半个新依赖树。
|
|
194
|
+
|
|
195
|
+
写入 `cordis.patch.yml` 是原子操作(写临时文件 + rename),只删这个插件自己创建过的覆盖项,用户手写的内容原样保留。
|
|
196
|
+
|
|
197
|
+
## 兼容性
|
|
198
|
+
|
|
199
|
+
- DSH 的 Web 界面(`dsh.client.platform = web`)。
|
|
200
|
+
- 需要宿主提供 `pluginManager` 服务;没有它会明确报错,而不是假装成功。
|
|
201
|
+
- 热替换依赖宿主的 HMR 服务;拿不到时退回提示「重启一次生效」,**不会骗你说已经生效了**。
|
|
202
|
+
|
|
203
|
+
## English
|
|
204
|
+
|
|
205
|
+
A plugin dashboard panel for DSH (DeepSeek Harness): every plugin in one list, a power switch per plugin,
|
|
206
|
+
an auto/manual flag that scopes the one-click bulk actions, inline update badges, and — the part that
|
|
207
|
+
matters — **updates are hot-swapped, so you do not restart DSH**. It also detects GitHub / tarball /
|
|
208
|
+
local-file / symlink installs, and can install and uninstall plugins through the host's official plugin
|
|
209
|
+
manager API, with backups and rollback.
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT
|