dsh-plugin-desktop-restart
中文简介
在 DeepSeek Harness 桌面窗口的标题栏(「应用 / 编辑」同一行)右侧加一个重启按钮:第一次点击变为「确认重启」,再点一次才真正重启应用,避免误触中断正在运行的任务。
- 重启由 Electron 外壳执行,插件通过打过补丁的
window.dshDesktop.restart() 调用;
- 应用更新会替换
app.asar,补丁与按钮随之消失;用 tools/patch-shell-restart.mjs 重新打补丁即可恢复;
- 按钮只在桌面应用窗口渲染(普通浏览器页面没有该桥接,不会显示);
- 补丁原理与字节长度保持细节见下方英文小节。
A Restart button in the sidebar footer of the DeepSeek Harness Web GUI, next
to the account credit chip.
Why the app has to be patched for this
The restart is the Electron shell's job — only it can relaunch the process — and
the shell exposes exactly one channel to the page: the preload bridge
(window.dshDesktop). That bridge ships with no restart method, and the shell's
own "Restart App and Host" item is built behind a development flag, so a plugin
cannot reach it. This plugin therefore needs two size-preserving edits inside the
application's resources/app.asar, applied by tools/patch-shell-restart.mjs:
| File | Change |
|---|
/lib/main.js | A dsh-desktop:restart IPC handler that validates the sender and calls app.relaunch(); quitWithoutConfirmation() — the shell's own relaunch idiom. |
/lib/preload-app.cjs | restart() on the dshDesktop bridge, so the page can invoke that handler. |
Both edits keep their file's byte length identical (each inserts code and rewrites
one comment block to absorb exactly the same number of bytes), so no offset in the
ASAR moves and every other file stays untouched.
An app update replaces app.asar and removes the patch; the button then
disappears by itself, because it only renders when the bridge actually provides
restart (see below). Re-apply with the same tool to get it back.
What the button does
It sits in the Windows caption menubar, the row at the top of the application
window that already holds 应用 / 编辑 (Application / Edit).
That row is built by the desktop preload, not by the Web client: it is a
div[data-windows-menu] with an open shadow root containing a <style> and
div[role=menubar], plus one button per menu. Open mode is what makes this
placement possible without patching the shell again — the plugin reaches the
menubar through host.shadowRoot and appends its own <button>, which the shadow
tree's element styles then dress exactly like the shipped buttons. The plugin
therefore ships no CSS at all.
- It renders only when
window.dshDesktop.restart is a function and the
caption row exists. Opened as a plain page over the loopback URL there is no
bridge and no caption row, so nothing is added rather than a button that cannot
work. The preload mounts that row once the shell overlay appears, so the plugin
watches for it (a MutationObserver plus a slow poll, both torn down with the
plugin).
- The confirmation lives in the button's own label: the first click turns 重启 into
确认重启 (tinted with the warning colour), and only the second click asks the
shell to relaunch. The shell's relaunch path does not ask about in-flight work,
so without that step a stray click would discard a running task. Clicking
anywhere else withdraws the confirmation.
- While the request is in flight the label reads 正在重启…; a refused request is
reported in the label and logged to the console.
- The label follows the interface language through the client locale service, and
the button stays out of the menubar's roving tab order (
tabIndex = -1).
Layout
| Path | Role |
|---|
lib/client.js | The whole feature: the caption-row mount, the button, its confirmation, and the zh/en dictionaries. |
lib/index.js | Host half — an empty apply; the row just has to exist for the browser half to be served. |
cordis.patch.yml | Bundle patch inserting the desktop-restart row by bare package name (a subpath would leave the browser half unresolved). |
Install and verify
Register the package as a profile bundle (cordis.patch.yml), then restart
DSH so the client row is composed. The shell patch is applied with the tool
bundled in this repository:
# rehearse on a workspace copy (the real archive is not touched)
node tools/patch-shell-restart.mjs "D:/DeepseekHarness/resources/app.asar"
# back up, install, re-verify; restores the backup automatically on any doubt
node tools/patch-shell-restart.mjs "D:/DeepseekHarness/resources/app.asar" --apply