前言¶
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。
- 保留窗口几何。 重启时捕获窗口的正常矩形(
rcNormalPosition)、showCmd(常规/最小化/最大化)和所在显示器,重启后用SetWindowPos加ShowWindow放回去,并读回实际值(含显示器、wanted/actual/onTarget等字段)写进日志和结果文件。最大化窗口按「先放回原矩形、再最大化」的顺序处理,避免被拉回主屏;最小化同理。 - 单击即重启。 唯一入口是侧栏底部账号行右侧的刷新图标按钮。单击直接排程重启,没有二次确认,宿主守卫(有任务在跑、插件正在安装)也不要求再点一次,只在按钮悬停提示里说明会打断它们。
- 自动续接被打断的会话。 宿主在排程那一刻取实况,把当时正在生成或正在跑工具的会话逐个恢复成活 Agent,并各注入一条纯事实的恢复消息。它会主动排除空闲会话、历史会话和挂后台任务的会话。
- 提供一条斜杠命令兜底。
/restart-desktop同样单击即重启,这条路上的宿主侧警告仍需/restart-desktop --force越过。 - 不猜 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