检测并一键安装新版,自检插件完整性并修复
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Yara2090/dsh-update-center该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · dev
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 30 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 39 处,展示前 27 条)
- 发起网络请求client.js:61
const response = await fetch(`${base}${pathname}`, init); - 读取本地文件lib/center.js:263
if (!existsSync(statePath)) return; - 读取本地文件lib/center.js:265
const parsed = JSON.parse(readFileSync(statePath, 'utf8')); - 写入本地文件lib/center.js:308
await writeFile(statePath, payload, 'utf8'); - 发起网络请求lib/center.js:345
const response = await fetch(url, { - 执行外部命令来自配置/变量lib/center.js:512
child = spawn(command, args, { - 读取本地文件lib/installation.js:31
const parsed = JSON.parse(readFileSync(manifestPath, 'utf8')); - 读取本地文件lib/installation.js:90
return existsSync(path.join(dir, name)); - 读取本地文件lib/integrity.js:124
const entries = await readdir(path.join(home, 'profiles'), { withFileTypes: true }); - 读取本地文件lib/integrity.js:137
const canonicalRoot = await realpath(pluginRoot).catch(() => undefined); - 读取本地文件lib/integrity.js:143
const resolved = await realpath(path.join(candidate, 'node_modules', pluginName)).catch(() => undefined); - 读取本地文件lib/integrity.js:233
const text = await readFile(target, 'utf8'); - 读取本地文件lib/integrity.js:257
source = await readFile(absolute, 'utf8'); - 读取本地文件lib/integrity.js:267
if (!existsSync(path.join(root, resolved))) missing.push(resolved); - 写入本地文件lib/integrity.js:281
await writeFile(backup, await readFile(target), 'utf8'); - 删除本地文件lib/integrity.js:291
await unlink(target); - 删除本地文件lib/integrity.js:297
await rmdir(target); - 写入本地文件lib/integrity.js:484
await mkdir(home, { recursive: true }); - 写入本地文件lib/integrity.js:579
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8'); - 写入本地文件lib/integrity.js:588
await mkdir(path.dirname(linkPath), { recursive: true }); - 写入本地文件lib/integrity.js:612
await writeFile(statePath, `${JSON.stringify(options.preferences ?? {}, null, 2)}\n`, 'utf8'); - 写入本地文件lib/integrity.js:619
await mkdir(home, { recursive: true }); - 读取本地文件lib/lifecycle.js:48
return { home, stopper, canStop: existsSync(stopper) }; - 读取本地文件lib/lifecycle.js:61
const parsed = JSON.parse(readFileSync(statePath, 'utf8')); - 读取本地文件lib/progress.js:75
entries = await readdir(dir, { withFileTypes: true }); - 读取本地文件lib/progress.js:89
total += (await stat(full)).size; - 读取本地文件lib/progress.js:104
const info = await stat(target);
扫描于 2026/10/31(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 检测新版本
- 一键安装更新
- 自检并修复插件
README
由 DeepSeek 最新模型翻译生成DSH 更新与版本(dsh-update-center)
给 DeepSeek Harness Web 设置面板加一个「更新与版本」页面:显示当前安装的 @deepseek-ai/dsh 版本、自动检测注册表上的新版本、一键装到同一个全局目录,并且能 自检插件的完整性(文件、依赖、配置)并在缺东西时一键修复。
一个 DSH Cordis 插件(Host + Client 双半边),纯 JavaScript,无构建步骤、无运行时依赖。
English summary: an "Updates & Version" settings page for the DeepSeek Harness Web GUI.
It reads the running @deepseek-ai/dsh version, checks the npm registry for a newer
release on a selectable channel, and installs it into the same global prefix. It also
self-checks its own installation (files, links, settings) and repairs the parts that can
展开完整文档(README 剩余 1 节)
DSH 更新与版本(dsh-update-center)
给 DeepSeek Harness Web 设置面板加一个「更新与版本」页面:显示当前安装的 @deepseek-ai/dsh 版本、自动检测注册表上的新版本、一键装到同一个全局目录,并且能 自检插件的完整性(文件、依赖、配置)并在缺东西时一键修复。
一个 DSH Cordis 插件(Host + Client 双半边),纯 JavaScript,无构建步骤、无运行时依赖。
English summary: an "Updates & Version" settings page for the DeepSeek Harness Web GUI.
It reads the running @deepseek-ai/dsh version, checks the npm registry for a newer
release on a selectable channel, and installs it into the same global prefix. It also
self-checks its own installation (files, links, settings) and repairs the parts that can
be repaired safely. Plain ESM, no bundler, no runtime dependencies; the browser half only
imports react.
更新与版本设置页
设置 → 更新与版本:已安装与最新版本、更新通道、上次检测,以及完整性自检逐项结果。
亮点
- 版本一眼看清 —— 同时显示「已安装」与「最新」两个版本,可切「稳定版 / 预览版」通道;装到磁盘但还没重启时会并排列出「已安装」和「运行中」,不让人误以为已经生效。
- 一键更新,进度是真的 —— 不编造百分比(npm 不告诉调用方总量),给的是真实数字:已用时长、已取包数,以及 npm 下的下载字节与速率(pnpm 缓存布局不同,宁可不显示也不显示一个错的数字);静默时另有说明,不假装一切正常。
- 完整性自检 + 一键修复 —— 10 项检查覆盖插件文件、源码依赖、profile 注册与链接、偏好文件、运行环境。每项修复先写 .bak 备份,只补缺失、不删用户内容,反复点也不会越改越乱。
- 不用再去桌面找快捷方式 —— 「停止 Harness」做进设置页,点两次确认。顺带把「关浏览器 ≠ 停服务」这件事在页面上说清楚。
- 只对本机开放 —— 那条能替换全局 npm 包的路由只接受回环地址,非回环一律 403;每个会写磁盘的动作都有明确边界。
- 零依赖、无构建 —— 纯 ESM,插件自身不装任何运行时依赖,也没有打包步骤;浏览器半边只用宿主提供的 react。
安装
两种方式,任选一种。前提:已经装好 Node ≥ 20 和 DeepSeek Harness。
方式一:纯手动
1. 下载
git clone https://github.com/Yara2090/dsh-update-center.git C:\dsh\dsh-update-center
2. 装进 web profile(装依赖)
dsh plugin --profile web add "file:C:\dsh\dsh-update-center"
3. 让插件真正启用:打开 ~/.dsh/profiles/web/package.json,在 dsh.profile.bundles 里加上一行 "@local/dsh-update-center"。
这一步别省:dsh plugin add 只装依赖,不写 bundle 列表。少了它,插件不会被加载,设置里也就不会出现「更新与版本」。
4. 重启 Harness,打开 设置 → 更新与版本。
方式二:把 GitHub 地址交给 DSH,让它装
在 Harness 的对话框里发一句:
把 https://github.com/Yara2090/dsh-update-center 装成插件
DSH 会自己克隆、装依赖、并把插件写进 profile 的 bundle 列表;按它说的重启一次即可。
装好之后基本不用管:默认每 6 小时自动查一次新版本,有新版就在这个页面里提示。
出问题时
| 现象 | 怎么办 |
| 设置里找不到「更新与版本」 | 多半是 bundle 列表没写进去;按方式一第 3 步检查 dsh.profile.bundles |
| 页面在,但卡片里报问题 | 点卡片里的「一键修复」,能补的它会补,补不了的会说明要你做什么 |
| 浏览器打不开这个页面 | 它只对本机回环地址开放,在跑 Harness 的那台机器上打开 |
| 提示找不到 dsh 命令 | 先 npm i -g @deepseek-ai/dsh |
卸载
三步,都不影响你装的其它插件:
1. 从 profile 的 bundle 列表里删掉 "@local/dsh-update-center" 那一行(~/.dsh/profiles/web/package.json 的 dsh.profile.bundles)。
2. 卸掉依赖:dsh plugin --profile web remove @local/dsh-update-center
3. 重启 Harness。
偏好文件 <DSH_HOME>/dsh-update-center.json 可以留着(以后装回来设置还在),也可以直接删。
没有别的残留:它不改 Harness 的核心文件,也不往别处写东西。唯一的例外是你点过「一键修复」——那只动 profile 清单、profile 里的插件链接和上面那个偏好文件,而且每项都留了同名 .bak 备份。
目录
- 亮点
- 安装
- 卸载
- 界面与功能
- 完整性检查与一键修复
- 运行控制:停止
- 工作原理
- HTTP 接口
- 配置
- 开发与测试
- 目录结构
- 安全边界
- 已知限制
- 更新日志
- 许可
界面与功能
页面注册在设置面板的 settings.section 插槽,导航位置 order: 12(「模型」之后、「插件」之前)。
| 卡片 | 内容 |
| 版本信息 | 已安装版本、最新版本(按通道)、更新通道切换(稳定版 / 预览版)、状态行、上次检测时间、「立即检查」、「立即更新」 |
| 完整性检查 | 10 项自检结果(文件 / 依赖 / 配置 / 运行环境)、「检查完整性」、「一键修复」 |
| 自动检测 | 自动检测开关、检测频率(1 / 6 / 12 / 24 小时)、自动安装开关(默认关闭,开启时给出风险提示) |
| 安装 | 将执行的完整命令、安装进度(不确定进度条 + 已用时长 / 已下载字节 / 速率 / 已取包数)、安装输出实时回显、安装结果与总耗时、以及「需要重启才生效」的提示 |
| 运行控制 | 「停止 Harness」(点两次确认);停止后弹出浮层并自动尝试关闭标签页,浏览器不允许时提示按 Ctrl+W |
自动检测、安装与运行控制
同一页往下:自动检测频率与自动安装开关、将执行的完整安装命令、「停止 Harness」。
几个刻意的行为:
- 不把「读不懂」当成「已是最新」:定位不到安装版本、或注册表没返回所选标签时,页面显示明确的状态/错误,而不是绿色的「已是最新」。
- 不自动降级:本机跑预发布版、注册表上的 latest 还是更旧的稳定版时,判定为「无更新」。
- 更新完成但未重启时,页面同时列出「已安装」和「运行中」两个版本,说明磁盘上已经是新版、进程里仍是旧代码。
- 空闲时零请求:只有检测或安装进行中才以 1s 轮询状态,其余时间页面完全不访问后端。
- 不编造百分比:npm 不告诉调用者「总共要下多少」,所以进度条是不确定态,旁边给的是真实数字(时间、字节、速率、包数),而不是一个看起来精确、实际瞎猜的百分数。
安装期间看得见什么
npm install --global 的进度条只在 TTY 下画;输出被父进程用管道接走之后它一个字都不吐,调试日志也要等进程结束才落盘。结果是「正在下载 100 MB」和「已经卡死」在页面上长得一模一样。
这个面板用四条互相独立的信号把它拆开:
| 信号 | 来源 | 说明 |
| 已用时长 | 1s 心跳(Host 侧) | 只要进程活着就一直在走 |
| 已下载 / 速率 | 直接量 npm 下载缓存 _cacache/content-v2 的体积 | 静默下载大压缩包时,唯一能证明「在下载」而不只是「进程还活着」的信号 |
| 已取包数 | --loglevel=http 打出的 npm http fetch 行 | 只在真的拿到应答时增加 |
| 静默提示 | 上述活动时间距现在超过 90 秒 | 给一句「npm 在下载/解包阶段本来就不输出」的说明,而不是假装一切正常 |
安装命令因此带上了 --loglevel=http(pnpm 用 --reporter=append-only),让安装器在管道里也开口说话。
完整性检查与一键修复
插件由三部分组成:插件目录里的文件、profile 里的注册与链接、运行环境的配置。
任何一处缺了,表现出来往往就是「页面不见了」或「点了没反应」,很难从现象反推原因。
这一页把三部分逐项查一遍,并把其中能安全修的修掉。
十项检查(进入页面时自动跑一次,纯磁盘只读):
| 检查项 | 查什么 | 一键修复 |
| 插件文件 | 清单声明的入口、图标、语言包等是否都在 | — |
| 插件清单 | package.json 能否解析,name / version / dsh.bundle.patch / dsh.client 是否齐全 | — |
| 源码依赖 | 顺着相对导入走一遍宿主半边,用到的文件是否都存在;有没有依赖没随插件交付的外部包 | — |
| 浏览器半边 | client.js 是否完整(含模块加载标记) | — |
| profile 注册 | profile 清单里的依赖项与 dsh.profile.bundles 是否都指向本插件 | ✅ 补回缺失项(先备份) |
| profile 链接 | node_modules/@local/dsh-update-center 是否存在且指向插件目录 | ✅ 重建链接(只删链接,绝不碰它指向的目录) |
| 偏好文件 | <DSH_HOME>/dsh-update-center.json 是否还是合法 JSON | ✅ 用当前设置重写(先备份) |
| DSH 主目录可写 | 状态与偏好需要落盘的地方是否可写 | ✅ 创建目录 |
| Node 版本 | 是否 ≥ 20 | — |
| Harness 安装 | 能否定位全局安装的 @deepseek-ai/dsh | — |
几条刻意的规矩:
- 检查永远只读,只有点「一键修复」才写磁盘,而且每一项都先备份(同名 .bak)。
- 修复只补不删:往 profile 清单里补缺失的依赖项与 bundle 条目,绝不动用户已有的其它内容,因此反复点也不会越改越乱(幂等)。
- 不确定就不动手:链接位置如果是普通目录,脚本不会去删它——那可能是别人手工拷贝的一份插件(提示「是拷贝而不是链接」),也可能是别的东西占了名字(报错并让人工处理)。
- 修完把新的自检结果一并返回,页面直接显示修好之后的样子,而不是让用户再点一次检查。
运行控制:停止
关闭浏览器并不会停止 Harness。 关标签页只是断开连接,服务仍在后台跑着——这个误会会让人以为「改了代码页面却没变」,所以「停止」直接做进设置页。
这里只有一个动作:停止。曾经还有一个「重启」,但两个按钮带来的是「我到底点的是哪个、接下来会发生什么」的持续困惑;而「停止 + 用桌面快捷方式启动」本来就是同一条路径,少一个概念就少一处误解。
- 「停止 Harness」需要点两次确认,第二次才真的执行。
- 动作延后约 1.5 秒执行,并且做成独立子进程——要被停掉的正是这个进程,HTTP 回包必须先发出去。
- 不自己实现杀进程,而是调用你机器上原有的 stop-deepseek-harness.ps1(由安装器放在 <DSH_HOME> 下)。认端口、清状态这些细节只有一份实现,行为与桌面快捷方式完全一致。
- 脚本缺失时按钮禁用,并在页面上写明缺的是哪个文件,而不是让按钮点了没反应。
- Windows 上不能给子进程加 detached:它会带来 DETACHED_PROCESS(新进程没有控制台),而 Windows PowerShell 在这种状态下会以退出码 0 静默退出、一行脚本都不执行。Windows 本来就不会因为父进程退出而杀掉子进程,所以这里不需要它。
- 卡片上常驻一行「上次动作」:子进程是否真的起来了由 spawn / error 事件上报,并写进偏好文件跨重启保留(动作会把进程换掉,只有落盘才答得了「刚点的按钮生效没有」)。
- 安装进行中拒绝停止(409),避免把正在跑的安装器一起带走。
点完之后:关掉这个标签页
停止一旦执行,这个页面的连接就注定回不来(服务已经不在了,没有任何东西能再服务它)。所以动作排定后会盖一层浮层,说明「服务即将关闭、这个标签页可以关掉了」,并自动尝试关闭标签页。
但浏览器通常不允许页面关闭自己。 实测(Chromium/Edge):
history.length = 2, window.opener = false → window.close() 被拒绝,标签页仍在
Chromium 只允许「由脚本打开的」或「没有历史记录的」标签页被脚本关闭;而这里的页面是启动器从外部打开的(带令牌的地址 303 之后还留下了两条历史)。既然做不到,页面就不能假装做到了:调用之后等一小段时间,如果代码还在跑就说明被拒绝,于是如实提示按 Ctrl+W 关闭,而不是留一个转圈的界面。
工作原理
┌──────────────────────── 浏览器 ────────────────────────┐ │ client.js → settings.section 页面 │ │ fetch('/dsh-update-center/state' | '/check' | ...) │ └───────────────────────────┬────────────────────────────┘ │ 同源 HTTP,仅回环 ┌───────────────────────────▼────────────────────────────┐ │ index.js → ctx.webServer.register(prefix) │ │ lib/center.js 状态机 / 路由 / 自动检测 / 安装子进程 │ │ lib/integrity.js 自检与修复:文件、链接、注册、环境 │ │ lib/lifecycle.js 停止服务:调用本机停止脚本并安排脱离本进程的执行 │ │ lib/progress.js 进度信号:缓存体积、抓取计数、静默判定 │ │ lib/semver.js 版本解析与 semver 优先级比较 │ │ lib/installation.js 定位安装目录、探测包管理器 │ └────────────────────────────────────────────────────────┘
- Host 半边(index.js + lib/)持有三件浏览器拿不到的事实:本机安装的版本、注册表发布的版本、以及「把新版装上去」的能力。它注册一条前缀路由 /dsh-update-center,并把状态、检查、偏好、安装、自检、修复六个动作暴露成 JSON。
- Client 半边(client.js)只从浏览器模块表取 react,不 import 任何 Harness Client 包——那些包会随版本变化,而这个页面崩溃会让整个 slot entry 变空。
- 偏好落盘到 <DSH_HOME>/dsh-update-center.json(通道、自动检测、自动安装、频率、上次检测时间)。运行期数据(安装输出、错误)只留在内存里。
HTTP 接口
所有路由都在前缀 /dsh-update-center 之下,返回 application/json; charset=utf-8,并且只接受来自本机回环地址的请求,非回环一律 403。
| 方法 | 路径 | 作用 |
| GET | /dsh-update-center/state | 读取完整状态快照 |
| POST | /dsh-update-center/check | 查注册表;可带 {"channel":"latest"\|"next"};等检测完成再返回 |
| POST | /dsh-update-center/settings | 写偏好,字段 channel / autoCheck / autoInstall / checkIntervalHours |
| POST | /dsh-update-center/update | 启动安装;立即返回,进度靠轮询 /state |
| GET | /dsh-update-center/integrity | 跑一次完整性自检(只读),返回检查报告 |
| POST | /dsh-update-center/repair | 修复可自动处理的项,返回动作清单与修复后的新报告 |
| POST | /dsh-update-center/stop | 安排停止服务;约 1.5 秒后执行,因此回包会先返回 |
没有 /restart:重启服务请用桌面快捷方式(见「运行控制:停止」一节)。
状态对象的主要字段:
| 字段 | 含义 |
| currentVersion | 磁盘上已安装的版本(安装成功后会刷新) |
| runningVersion | 本进程启动时加载的版本 |
| latestVersion | 所选通道在注册表上的版本 |
| updateAvailable | 是否确实有更新(false 也包含「无法判定」) |
| checking / checkedAt / checkError | 检测中 / 上次检测时间 / 检测错误(无错误为 null) |
| updating / updateOutput / updateResult | 安装中 / 安装输出 / 安装结果 |
| updateStartedAt / updateElapsedMs / updateFinishedAt | 安装开始时间 / 已用毫秒(心跳刷新,结束即冻结) / 结束时间 |
| updateCacheBytes / updateCacheRate | 已下载字节(npm 缓存实量,估算值) / 字节每秒 |
| updateFetchCount / updatePackageCount | 已完成的注册表抓取次数 / 其中的压缩包数 |
| updateSilentMs / updateStalled | 距上次活动的毫秒数 / 是否已静默超过 90 秒 |
| installCommand | 将执行(或已执行)的完整命令 |
| restartRequired | 是否已装上磁盘但还没重启 |
| channels / statePath | 允许的通道列表 / 偏好文件路径 |
| lifecycle | { canStop, stopper }:本机能不能停止,以及停止脚本的路径 |
上表是状态对象的完整字段。其中只有「无错误」槽位(checkError / updateResult / currentVersionError)始终以 null 出现;其余字段在尚未发生时会整个不出现在 JSON 里——例如 latestVersion 要检测过一次才有,updateCacheBytes 要等安装开始之后才有。取值前先判一下。
自检报告(/integrity 与 /repair 共用同一形状):
| 字段 | 含义 |
| pluginRoot / pluginName / profileDir / statePath | 本次自检认定的插件目录 / 包名 / profile 目录(判定不出为 null)/ 偏好文件 |
| summary | errors / warnings / repairable / total 计数 |
| checks[] | 每项为 { id, status, repairable, detail };status 取 ok / warn / error |
| /repair 额外返回 | repaired[](含每项的 ok 与说明)、repairedCount、failedCount、restartRequired、以及修复后的 report |
配置
写在 profile 的 cordis.patch.yml 覆盖行里,字段全部可选:
- id: dsh-update-center
name: "@local/dsh-update-center"
config:
channel: latest # latest | next,默认 latest registry: "https://registry.npmjs.org/" # 检测与安装都用的源,可换成内网镜像 autoCheck: true # 后台自动检测,默认 true autoInstall: false # 检测到就自动安装,默认 false checkIntervalHours: 6 # 自动检测频率,默认 6
界面上能改的只有 channel / autoCheck / autoInstall / checkIntervalHours,它们会落到偏好文件里并覆盖这里的默认值;registry 只能在配置里改,并且检测与安装用的是同一个源(安装命令会带上 --registry=<地址>)。这样换成内网镜像后,检测到的新版本也真的能从镜像装下来,不会出现「检测到有新版本、安装却从另一个源拉不到」。
开发与测试
无需安装依赖、无需构建:
node --test # 100 个用例:版本比较 + 进度信号 + 自检与修复 + 停止计划 + 路由与拒绝分支 + 接口与文档一致性
node --check index.js # 语法检查(client.js / lib/*.js 同理)
如果运行环境禁止 Node 测试运行器 fork 子进程(沙箱会报 spawn EPERM),改用单进程模式:
npm run test:single # 等价于 node --test --test-isolation=none
测试不访问外网:注册表由本地假 HTTP 服务提供,偏好文件写在临时目录里,也绝不会真的执行 npm install。
其中 test/endpoints.test.js 是接口一致性检查,不是功能测试:前端(client.js)与后端(lib/center.js)靠字符串约定动作名,两边各改一半,写代码时不会有任何报错,只会在运行时 404。
它断言三件事:前端调的每个动作后端都认、后端认的每个动作前端都在用、两边路由前缀一致;检查自身也带非空断言,避免「什么都抽不到于是永远通过」。
推上去会自动跑同一套用例(见顶部徽章):Ubuntu 上跑 Node 20 与 22,Windows 上跑 Node 22。
Windows 那条会让 test/lifecycle.test.js 里的 PowerShell 冒烟测试真的执行——那条用例是「detached 让 PowerShell 静默退出」的产物,只在 Windows 上跑才有意义,其余平台自动跳过。
index.js 与 client.js 不被任何用例导入,因此 CI 里另外单独对它们跑 node --check。
改动 client.js 后,运行中的 Harness 会通过 bundle 探测自动热加载新的浏览器半边;改动 Host 半边(index.js / lib/)通常需要重启 Harness 才会载入新的模块代。
目录结构
├── index.js Host 半边入口:inject + apply,只做挂载 ├── client.js 浏览器半边:单文件,settings.section 页面 ├── lib/ │ ├── center.js 状态机、HTTP 路由、自动检测、安装子进程与进度心跳 │ ├── integrity.js 自检与一键修复:文件、源码依赖、profile 注册与链接、偏好文件 │ ├── lifecycle.js 停止:探测本机停止脚本并安排脱离本进程的执行 │ ├── progress.js 进度信号:缓存体积、抓取计数、静默判定(纯函数) │ ├── semver.js 版本解析与 semver 优先级比较(纯函数) │ └── installation.js 定位安装目录、探测包管理器、拼装安装命令 ├── test/ │ ├── semver.test.js 版本比较的边界用例 │ ├── progress.test.js 进度信号与安装命令的边界用例 │ ├── integrity.test.js 自检判定与修复安全性(含「不误删真实目录」) │ ├── lifecycle.test.js 停止的命令拼装与能力判定(含唯一真的拉起进程的 Windows 冒烟测试) │ ├── center.test.js 路由 / 状态 / 拒绝分支 / 安装出口的版本号校验 │ ├── endpoints.test.js 前后端接口一致性:动作名与路由前缀不许两边各改一半 │ └── docs.test.js 文档一致性:目录锚点、目录结构树、文中用例数 ├── locale/ │ ├── zh.json 插件卡片的中文显示名与描述 │ └── en.json 英文显示名与描述 ├── docs/ │ ├── screenshot.png README 顶部:版本信息与完整性检查 │ └── screenshot-2.png 「界面与功能」:自动检测、安装与运行控制 ├── .github/workflows/ │ └── test.yml CI:Ubuntu(Node 20/22)与 Windows(Node 22)跑 npm test ├── cordis.patch.yml bundle 补丁:插入 Host 插件行 ├── icon.svg 插件卡片图标 ├── CHANGELOG.md 逐版本的功能与取舍记录 └── package.json 清单:dsh.bundle.patch + dsh.client
安全边界
这条路由能替换机器上的全局 npm 包,因此:
- 仅回环:req.socket.remoteAddress 不是 ::1 / 127.0.0.0/8 / ::ffff:127.0.0.1
就直接 403,并且不返回任何状态;空地址也按拒绝处理。
- 不自动安装:autoInstall 默认关闭,开启后界面会常驻一条风险提示。
- 同时只跑一个安装:检测与安装互相排斥,重复请求返回 409。
- 插件卸载即收尾:路由、定时器、正在运行的安装子进程都由 ctx.effect 的清理函数一起释放。
- 更新仍需重启:安装只换磁盘上的文件,新版本要重启 Harness 才真正生效。
- 修复的写权限:只有「一键修复」会写磁盘,范围仅限 profile 清单(补依赖项与 bundle 条目)、 profile 里的插件链接、以及偏好文件;每项都先写同名 .bak 备份,且只补缺失、不删用户内容。
检查(GET /integrity)永远只读。
重建链接是唯一会删东西的动作,但它只删链接本身:链接指向的真实目录、以及「这里并不是链接」的情况,都绝不触碰。
- 停止不接受页面传来的任何命令:它只会调用 <DSH_HOME> 下那个固定名字的脚本,页面能选的只有「停止」这一个已定义动作,不存在把任意命令拼进参数的可能。
- 进命令行的外部输入都先校验:安装命令在 Windows 上经由 shell 执行(shell: true,因为
npm / pnpm 是 .cmd 包装脚本),参数不会被转义。因此注册表返回的 dist-tag 必须能按
semver 解析,配置里的 registry 必须是 http/https 的合法 URL——前者不合法就报错,后者不合法就退回官方源。这道校验有两层:读取注册表时一层,安装出口 runUpdate 自己再一层(安全闸不能只建在调用方)。
已知限制
- 需要 Node ≥ 20(用到全局 fetch 与 AbortSignal.timeout)。
- 安装用的是「同一个全局前缀 + 探测到的包管理器(npm / pnpm)」。如果这个包当初是用其它方式(例如手工拷贝)放进去的,探测会退回 npm,可能不符合你的环境;此时请手工执行界面上展示的那条命令。
- Windows 上正在运行的进程可能占住原生模块文件,导致全局安装失败;界面会把安装器的原始输出原样显示出来,按提示手动执行即可。
- 安装期间不要让本插件被卸载或重载:插件被卸载时会一并终止正在运行的安装子进程(这是「不留孤儿 npm」的代价)。界面在安装中会常驻这条提示。
- npm 在解包阶段会连续几分钟不输出任何东西,此时进度条只靠时间与缓存体积证明进程还活着;真正「卡住」与「正在解包」在外部无法彻底区分,超过 90 秒静默时界面会给出说明而不是结论。
- 桌面(Electron)版的更新走 Harness 自带通道,与本插件无关。
- 一键修复只覆盖「能安全补回来」的部分:插件源码文件丢了、Node 版本太低、Harness 没装,这些只能重新克隆仓库或自行升级,页面会如实说明而不是假装修好。
- 修复改的是 profile 清单与链接,因此改完之后需要重启 Harness 才生效(页面会提示)。
- 自检报告的文案由浏览器半边渲染,Host 只回 id 与细节字符串;因此新增检查项时忘记补文案,页面会退回显示检查项 id,而不是空白。
- 没有浏览器控制的环境下无法验证视觉呈现;本项目的验证覆盖语法、清单、Host 路由与实时 Client 插槽注册。
更新日志
完整历史与每一版的取舍理由见 CHANGELOG.md; Releases 里有对应的版本标签。
许可
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Yara2090/dsh-update-center
检测并一键安装新版,自检插件完整性并修复
相关插件 · 开发 / 工程
隐私简历生成器reactive-resume/reactive-resume
Reactive Resume 已迁至 GitHub 上的…
★ 45,125已汉化MCP
71.7
AI 架构文档生成器sopaco/deepwiki-rs
🚀 Litho 已进化为 Terrain —— 给你的 AI 智能体一张会呼吸的代码库地图。
★ 3,157已汉化DSH
70.8
长时任务执行闭环AMAP-ML/LongHorizon-Harness
面向 Computer-Use Agent 的 Loop Engineering
★ 1,764已汉化DSH
70.5
AI 编程纪律方法包GanyuanRan/Aegis
让 AI 编程 agent 变得可信:少返工、更安全、说“完成”前先给证据。
★ 1,384已汉化DSH
69.6
多代理编排运行时Enderfga/claw-orchestrator
面向编程智能体的运行时。把 Claude Code、Codex、Antigravity、Grok…
★ 586已汉化MCP
69.4
记忆进化插件csyangwen/dsh-memory-evolve
dsh-memory-evolve 使用场景指南
★ 461已汉化DSH
67.9