dsh-restart-button:为 DSH 桌面端标题栏补上「重启」按钮

前言

在 DSH 桌面端(Windows)里改完 profile、换插件 bundle,或 Host 状态异常时,往往需要整应用退出再打开——Electron shell、DSH Host、渲染进程和插件守护进程要一起重来。Electron 自带的「重启应用与 Host」菜单项在正式安装包里被 development 门槛挡住,日常看不到;而 DSH 插件跑在 Host 子进程里,拿不到 app.relaunch(),也没有往原生菜单插项或请求主进程重启的 IPC。社区插件 dsh-restart-button(维护者 wangbofan,分类:客户端)从标题栏菜单和 Host 侧配合,实现「点一次、整应用关闭并自动重新打开」,且不改 app.asar、不依赖桌面端版本。

这是什么

dsh-restart-button 给 DSH 桌面端(Windows)的标题栏菜单栏增加第三个按钮「重启」。点击后经过确认,整个应用(Electron shell + DSH Host + 渲染进程 + 插件守护进程)退出并自动重新启动。实现完全在插件内完成,不 patch 安装包内的 app.asar。

为什么插件只能「从外面」重启

DSH 桌面端的「应用」菜单由 Electron 主进程用原生 Menu 弹出,菜单项列表硬编码在主进程里。Host 子进程由 DeepSeek Harness.exe 以 --expose-internals 等方式加载 @deepseek-ai/dsh-desktop-host,与主进程之间的 IPC 主要是主进程 → Host 单向(如 shutdown),没有「请主进程重启」的扩展点。因此本插件的策略是:在 Host 里安排一次外部助手脚本,先让 HTTP 响应返回,再按 exe 路径终止本应用全部相关进程,最后用 WMI 重新启动同一个 exe。

核心功能

Host 侧 HTTP 接口

路由前缀为 /restart-button(代码内常量 ROUTE_PREFIX)。

方法 路径 说明
GET /restart-button/status 可用性、exe、工作目录、主进程与 Host PID、Electron 版本、日志路径等
POST /restart-button/restart 安排一次重启,立即返回 { ok, via, dryRun, delayMs, scriptPath, logPath }

重启序列概要:将 VBScript 助手写到 %TEMP%\dsh-restart-button-<random>.vbs;通过 WMI 以 wscript.exe 启动助手(使助手不在本应用进程树下,避免被杀进程步骤误杀);助手等待约 1500ms(HELPER_DELAY_MS)后按 exe 路径终止所有相关进程并重新启动;决策链写入 %TEMP%\dsh-restart-button.log。

两个路由均限制为 loopback Host、非 cross-site、且 origin 同源或 dsh-app://app,判定口径与官方插件 isTrustedApiRequest 一致。

Client 侧 UI

Windows 标题栏的「应用 / 编辑」区域由 preload 在页面 DOM(div[data-windows-menu],open shadow root)中绘制。client 半边在该菜单栏追加「重启」按钮:点击后出现中英双语确认(跟随 document.documentElement.lang);确认后 POST /restart-button/restart,全屏遮罩并每 2s 轮询 /status(探不通表示 Host 已退出、重启进行中);25s 内仍可探通则提示失败并可重试。若约 2.5s 内找不到菜单栏(例如在 dsh web 环境),退化为右下角浮动按钮 #dsh-restart-button-floating。

弹窗、遮罩与按钮使用 DSH 语义 token(--dsw-alias-*),随浅色/深色主题切换,不写死颜色。

演练模式

不杀进程、只写日志,可用于排查:

  • 环境变量:DSH_RESTART_BUTTON_DRY_RUN=1
  • 或单次请求:POST /restart-button/restart?dryRun=1

安装与启用

前置:DSH 桌面端(Windows)。profile 目录默认 %USERPROFILE%\.dsh\profiles\desktop。

方式 A:dsh-super-injector(热装配,可免重启应用)

若已安装 dsh-super-injector,可注入本插件目录绝对路径:

dev_inject_plugin   dir=<本插件目录绝对路径>

或写入 profile(重启后仍保留):

dev_install_package dir=<本插件目录绝对路径> profile=desktop

注意:上述注入方式与 bundle patch 的正式条目不要同时存在,否则可能出现 webserver: duplicate prefix route "/restart-button"。需清理临时 entry 或重启一次应用。

方式 B:手动装进 profile

  1. 将插件目录链到 profile 的 node_modules(目录拷贝或 junction 均可):
mklink /J "%USERPROFILE%\.dsh\profiles\desktop\node_modules\dsh-restart-button" "C:\path\to\dsh-restart-button"
  1. 编辑 %USERPROFILE%\.dsh\profiles\desktop\package.json,在 dependencies 中加入 link: 依赖,并在 dsh.profile.bundles 中加入 "dsh-restart-button"。

  2. 重启 DSH(关闭桌面端再打开,或重启 dsh web)。

方式 C:从 GitHub 或 tgz 安装

在 profile 目录使用 DSH 捆绑的 pnpm,安装后把包名加入 dsh.profile.bundles,再重启:

pnpm add "dsh-restart-button@github:wangbofan/dsh-restart-button"

或:

pnpm add "file:C:\path\to\dsh-restart-button-1.0.0.tgz"

卸载

从 dsh.profile.bundles 与 dependencies 移除 dsh-restart-button,删除 node_modules 下对应链接或目录,重启 DSH。插件除 %TEMP% 下的脚本与日志外不写其它位置。

典型用法

标题栏菜单:应用 | 编辑 | 重启 → 点「重启」→ 确认 → 应用关闭并自动重新打开。按钮放在菜单栏上、紧邻「应用」,是因为插件无法向 Electron 主进程内原生「应用」下拉菜单插入项。

查看 Host 状态示例(在可信 origin 下访问):

GET http://127.0.0.1:<host-port>/restart-button/status

适用场景与注意

适合谁: 经常在 Windows 桌面端调整 profile、bundles 或插件,需要整应用重启而不是只刷新页面;希望在不改 app.asar 的前提下获得接近「重启应用与 Host」的体验。

限制(README 已说明):

  • 仅 Windows 桌面端;dsh web 下 capabilities() 返回 available: false(reason: "not-supervised"),浮动按钮可用但点击会提示不可用。
  • 不是优雅关闭:按 exe 路径终止进程,正在运行的任务会被中断(确认气泡中有说明)。
  • 重启后会话与窗口位置由桌面端自行恢复,插件不保存状态。
  • Node 引擎要求:>=22(见 package.json)。

安全与信任: 插件在 Host 进程权限下运行,重启逻辑会终止并重新拉起本机 DSH 可执行文件。安装前应阅读 源码与 LICENSE(MIT),确认接受其 WMI/VBScript 助手行为。社区目录 SkillHub 为独立站点,与 DeepSeek / 幻方无官方从属关系;DSH 生态强调「一切皆插件」,本插件属于社区贡献的客户端能力扩展。

结尾

dsh-restart-button 用 Host HTTP + 页面菜单栏按钮,补上了正式包中不可见的整应用重启路径,并刻意避开改包与控制台窗口等坑。需要安装步骤与自测细节时,以 GitHub README 为准;在目录页可查看条目摘要:https://www.skillhub.cn/plugins/wangbofan/dsh-restart-button。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜