dsh-plugin-restart-desktop:给 DSH 桌面版补一个保留窗口的一键重启

前言

DSH 桌面版(DeepSeek Harness 的 Electron 壳)没有「重启」这个动作:打包版菜单里找不到重启项,托盘菜单在 Windows 上只有「打开应用」和「退出」,渲染进程的 dshDesktop API 里也没有重启方法。更麻烦的是窗口几何从不落盘——主进程的 createWindow() 把尺寸写死成 1280×820,所以正常退出再开,窗口一定回到默认尺寸。顺带还有一个容易踩的坑:点窗口的关闭按钮并没有退出应用,主进程只是 preventDefault 加 hide,把窗口收进托盘。

下面介绍的 dsh-plugin-restart-desktop 就是对着这个缺口做的:由 railgun20001 维护,MIT 许可,当前版本 1.0.0,从 npm 发布。它提供一个侧栏入口,单击即重启,重启后保留窗口的位置、大小、最大化状态和所在显示器,可选地把重启那一刻真正被打断的会话自动接上。插件没有设置页,全部行为由宿主侧开关控制,且只支持 Windows 桌面版。

这是什么

一句话定位:DSH 桌面版的一键重启插件,解决「重启丢窗口位置」和「重启后要手动找回被打断的会话」这两件事。

它值得说明的一点是,这不是把官方隐藏功能挖出来,而是官方确实没有留通道。README 里给出的依据是解包 app.asar 读主进程源码的结论:完整 IPC 只有 shutdown / quit-inspection / update-tasks 等有限几项,没有重启相关接口。因此插件的做法是自己派一个分离的 helper 进程,由它结束 Electron 主进程、等端口释放、拉起新实例,再把窗口逐像素还原。

核心功能

下面是已核实的能力,全部来自插件 README。

  1. 保留窗口几何。 重启时捕获窗口的正常矩形(rcNormalPosition)、showCmd(常规/最小化/最大化)和所在显示器,重启后用 SetWindowPos 加 ShowWindow 放回去,并读回实际值(含显示器、wanted / actual / onTarget 等字段)写进日志和结果文件。最大化窗口按「先放回原矩形、再最大化」的顺序处理,避免被拉回主屏;最小化同理。
  2. 单击即重启。 唯一入口是侧栏底部账号行右侧的刷新图标按钮。单击直接排程重启,没有二次确认,宿主守卫(有任务在跑、插件正在安装)也不要求再点一次,只在按钮悬停提示里说明会打断它们。
  3. 自动续接被打断的会话。 宿主在排程那一刻取实况,把当时正在生成或正在跑工具的会话逐个恢复成活 Agent,并各注入一条纯事实的恢复消息。它会主动排除空闲会话、历史会话和挂后台任务的会话。
  4. 提供一条斜杠命令兜底。 /restart-desktop 同样单击即重启,这条路上的宿主侧警告仍需 /restart-desktop --force 越过。
  5. 不猜 DOM。 账号行按钮靠观察官方已写死的 data-signed-out 与 aria-haspopup="menu" 特征识别,判据里不含哈希类名;认不出来时回落到官方给第三方插件的动作座位 sidebar.footer.action,功能不会凭空消失。

安装与启用

从 npm 安装,官方命令如下。注意这是 DSH 的 plugin_manager 调用,不是普通的包管理器命令。

plugin_manager(action: "install_bundle", target: "dsh-plugin-restart-desktop")

也可以把插件直接写进 profile,bundles 与 dependencies 两处都要有:

// ~/.dsh/profiles/desktop/package.json
"dsh": { "profile": { "bundles": [ /* … */ "dsh-plugin-restart-desktop" ] } },
"dependencies": { "dsh-plugin-restart-desktop": "^1.0.0" }

开发本仓库时用 link: 指向本地目录,改完代码立即生效:

plugin_manager(action: "install_bundle", target: "link:C:\work\my\dsh\plugins\dsh-plugin-restart-desktop")

安装后 DSH 的 HMR 会当场把宿主半和客户端半挂上,一般不需要重启;如果入口没出现,刷新一次页面即可。package.json 的 engines.dsh 要求 >=0.2.0-rc.1,作者本机实测于 0.2.1-rc.5。

典型用法

装好之后没有额外的上手步骤,直接点入口。

点侧栏底部账号行右侧的刷新图标,一次点击即排程重启。窗口的位置、大小、最大化状态与所在显示器保留,当时真正在跑的会话被逐个接上,页面随后断开,应用重启并回到原来的样子。

插件没有设置页,界面开关一个都不提供。两个宿主侧行为开关有默认值(都是开),需要时改插件 config 或宿主侧设置文件:

// ~/.dsh/profiles/desktop/package.json 里本插件那一行的 config
{ "geometry": true, "resume": true }   // 还原窗口几何 / 自动续接被打断的会话

宿主侧设置文件 ~/.dsh/restart-desktop/settings.json 优先级高于 config;也可以直接往插件路由改:POST /dsh-plugin-restart-desktop/api/settings?geometry=0&resume=0。

排障时可以在浏览器控制台里看这些:

__DSH_RESTART_DESKTOP__.status()      // 宿主状态快照
__DSH_RESTART_DESKTOP__.button()      // 账号行按钮的注入状态(found / injected / lastReason)
__DSH_RESTART_DESKTOP__.sweep()       // 立刻重扫一次账号行
__DSH_RESTART_DESKTOP__.action()      // 按钮此刻的动作状态

宿主侧的交接记录落在 ~/.dsh/restart-desktop/,保留最近 20 组 handoff-*.json、restart-*.log、restart-*.result.json、restart-*.geometry.json。几何结果文件里还能看到窗口到底落在哪块屏。

适用场景与注意

适合这两类工作场景:

  • 在 Windows 上以桌面版做日常会话,希望重启(装依赖、升版本、改配置)时窗口布局不被打断。
  • 会话里挂着长任务,重启后不想让历史上下文中断、需要自动接回。

需要说清楚的边界,主要是插件本身的行为边界,不是 bug:

  • 正在跑的那一轮一定会断,不会自动续跑;自动恢复注入的是一份事实报告,不是重放那一轮。
  • 正在被工具写入的文件可能停在半路,插件不做回滚。
  • 后台任务、子 Agent、teammate 都会被杀掉,定时任务在应用关闭期间不会触发;被杀的后台任务不会换来恢复消息,需要的话重启后自己再拉起。
  • 只支持 Windows 桌面版,能力探测不通过会明确拒绝。

另外,插件以当前 DSH 进程的权限运行,可结束主进程、拉起新实例、读写会话状态。安装前建议先读一遍 README、lib/ 下的源码与 cordis.patch.yml,确认许可证为 MIT 后再启用;cordis.patch.yml 属于宿主侧补丁,属于改动宿主行为的一类安装,值得单独评估。

结尾

这个插件的价值很具体:把官方没有留通道的重启动作补齐,并且把「窗口几何不落盘」这个隐性损失解决掉。它不追求大体量的设置项,靠宿主侧两个开关和一个分离 helper 把链路走完,边界也写在 README 里,方便按自己的工作方式判断是否启用。

目录页:https://www.skillhub.cn/plugins/railgun20001/dsh-plugin-restart-desktop

仓库:https://github.com/railgun20001/dsh-plugin-restart-desktop

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

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

小夜