
Security News
Deno Goes the Way of the Dinosaur
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.
dsh-power-button
Advanced tools
Restart and quit controls for the DSH desktop GUI, in two independently switchable places: a draggable floating button that snaps to a screen edge and collapses into a thin strip, and a power button in the sidebar footer.
简体中文 ・ English
给 DSH 桌面版(DeepSeek Harness Desktop)补两个电源入口,各自可单独开关:
拖动 → 贴边收起 → 鼠标移上去展开 → 点击 →(有任务在跑才二次确认)→ 重启 或 退出
DSH 桌面版本身没有界内重启入口:托盘菜单里的重启只在开发构建下出现,发布版只能先退出、 再从开始菜单重新打开。这个插件补的就是这一格。
taskkill、WMI 与系统自带的 Windows PowerShell 5.1。@linxin666/dsh-web-all 时落在同一位置)。本插件由 DeepSeek Harness Desktop + DeepSeek v4.1 flash 制作:代码和这两份 README 都是模型
写的,人工只参与了调试与审阅。它属于 vibe code 产物——每个反直觉的实现都在
docs/DESIGN.md 里留了取证与实测数据,但请按"别人家 AI 养大的项目"来对待:上手前先看
「已知边界」,遇到问题欢迎提 issue。
安装会改动 profile 的 package.json 与 pnpm-lock.yaml,先备份:
Copy-Item "$env:DSH_HOME\profiles\desktop\package.json" `
"$env:DSH_HOME\profiles\desktop\package.json.bak" -Force
git clone https://github.com/WhichWitchWin/dsh-power-button.git
& 'D:\DeepSeek Harness\resources\runtime\cli\bin\dsh.cmd' `
plugin --profile desktop add 'D:\path\to\dsh-power-button'
& 'D:\DeepSeek Harness\resources\runtime\cli\bin\dsh.cmd' `
plugin --profile desktop add 'github:WhichWitchWin/dsh-power-button'
两种方式都会把依赖写进 profile 的 package.json,并把本包加进 dsh.profile.bundles
(dsh.bundle.patch 一声明即激活)。装完重启一次 DSH(托盘退出再打开),两个界面就会
出现。lib/ 是可直接加载的成品,没有构建步骤,包内不含 src/、node_modules/ 或中间产物。
CLI 路径以你的实际安装目录为准,并且必须用桌面版自带的这个入口:它给 profile
desktop开了manageDesktopProfile;PATH里随便一个dsh会以profile "desktop" is managed exclusively by the Electron application拒绝。 装到别的 profile 时把--profile换成那个名字即可。
& 'D:\DeepSeek Harness\resources\runtime\cli\bin\dsh.cmd' `
plugin --profile desktop remove dsh-power-button
| 操作 | 结果 |
|---|---|
| 拖动悬浮按钮 | 移动位置;松手时靠近左右边缘会吸附并收起 |
| 鼠标移到细边上 | 展开成完整按钮(移开即收回) |
| 点击按钮 | 弹出电源菜单 |
| 点击菜单外的空白 | 关闭菜单,控件回到细条(不会常驻展开) |
Esc | 关闭菜单 |
Enter / Space | 等价于点击按钮 |
localStorage。两个按钮都会"捏":
scale(.9, 1.1),0.16s),顺手挤出几颗 7px 的小
水珠,顺着你按压的方向甩出去、边飞边缩小淡掉。scale(.5,1) 且透明),落位时轻轻
弹几下(0.44s)。所以它不只是"能用":按住有肉感,松手有回弹,贴边之后探出来也软软的。
(时长和曲线是实测调过的——改之前先看 docs/DESIGN.md,那里面的数字互相咬着。)
插件管理器里本插件自己的配置页上有两个开关:悬浮电源按钮 / 侧栏底部电源图标。 插件卡片上的开关管的是整个包,这两个管的是各自的界面,改动即时生效、无需刷新。
界面开关存在 profile 目录下的 dsh-power-button.json,由配置页写入:
{ "floating": true, "sidebar": true }
宿主半另有一个可选 config 块,两个与机器性能相关的上限(默认值适合普通机器):
| 键 | 默认 | 范围 | 含义 |
|---|---|---|---|
settleMs | 500 | 0–30000 | 杀进程前留给 HTTP 响应抵达浏览器的时间 |
waitForExitSeconds | 20 | 1–300 | 等待旧壳真正消失的上限 |
端口一释放就立刻继续,所以这两个值通常不会被等满。慢机器或高负载机器上如果日志出现
WARNING: proceeding after ...s,就把它调大。加在 profile 的 bundle patch 里:
- insert:
- id: ui-restart-button
name: 'dsh-power-button'
config:
settleMs: 800
waitForExitSeconds: 30
桌面版的重启由 Electron 主进程持有(app.relaunch() + app.quit()),但没有把这条能力开给
插件,所以插件只能从外部复刻一次重启。这里有个先有鸡还是先有蛋的约束:宿主进程是
Electron 主进程的子进程,杀掉主进程会连带杀掉宿主,下杀手的那段代码不能待在宿主进程里。
于是工作交给一个脱离进程树的 PowerShell 辅助进程:
点击「重启 DSH」→ 二次确认
↓
宿主半 POST /api/dsh-restart/action { action: "restart" }
↓
宿主半同步等待 lib/restart-helper.ps1 的「引导阶段」返回
↓
引导阶段用 Win32_Process.Create (WMI) 把自己重建为「工作阶段」,然后退出
↓
工作进程(父进程是 WmiPrvSE,不在应用进程树里,taskkill 够不到它):
1. 记下起始时刻与 settleMs 的截止时刻
2. 趁主进程还活着,读它自己的命令行 ← 复刻 app.relaunch() 的语义
3. 趁宿主还活着,问出它监听的端口与绑定的地址(IPv4 / IPv6 都覆盖)
4. 杀旧进程树,等它彻底消失
5. 等端口释放(以 bind 那个地址判定)
6. 按原参数拉起新实例(并交接 DSH_* 环境变量)
7. 轮询新实例的窗口并置前,避免被别的程序遮住
detached: true 的 spawn 不够:子进程仍以本进程为父,taskkill /T 会连它一起杀掉;
只有 WMI 创建的子进程既脱离进程树、又能在创建者退出后活下来。
「退出」走 taskkill:宿主进程一退出,这个壳会把它的退出码一律当致命错误处理,这条路上
没有更优雅的实现。
三条路由都在 Host 源下,且必须自己调用 requestRejection——它们注册为 exact 路由,会先于
Host 的 /api 前缀表被派发,因此会遮蔽 Host 给其他 /api 端点加的身份验证。插件主动复用
Host 自己的授权判断(Host/Origin fence + 浏览器鉴权 cookie),待在同一个权限模型里。
::1、IPv4-mapped),Host 头也必须
是回环权威。X-Forwarded-For 从不采信,sec-fetch-site: cross-site 直接拒。日志在 DSH 的 logs 目录下:restart-button.log(拒绝标记 restart-button.refused)。
这个目录按 $DSH_HOME\logs → 从宿主自己的 profile 参数反推 → %TEMP% 的顺序解析,
所以 DSH_HOME 不是 ~/.dsh 时,日志在它实际指向的地方。
taskkill、Win32_Process.Create(WMI)与
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe;macOS / Linux 返回
supported: false 并隐藏界面。dsh web)下两个界面都不出现。 那里没有可复刻的重启语义,插件回答
supported: false 并整体隐藏,而不是留一个点了没用的按钮。:has() 与外壳的 class 后缀(footArea / footerActions /
settingsArea);不支持 :has() 时这段重排整体失效,退化成外壳自己的堆叠布局,
与本插件出现之前一样,不会更糟。悬浮按钮与此无关。| 文件 | 作用 |
|---|---|
lib/index.js | 宿主半:三条 loopback 路由(status / action / config)、桌面拓扑探测、启动并等待引导进程 |
lib/restart-helper.ps1 | 两阶段辅助:引导阶段用 WMI 重建工作进程;工作阶段读命令行、问端口、杀树、等条件、按原参数重启、把新窗口置前 |
lib/client.js | 浏览器半:悬浮控件(拖动 / 贴边 / 悬停展开 / 果冻反馈)、侧栏电源、配置页两个开关 |
cordis.patch.yml | bundle patch:一个宿主行;浏览器半由 dsh.client 自动挂载 |
docs/DESIGN.md | 工程笔记(中文):每个反直觉决定的取证与实测数据 |
LICENSE | MIT |
lib/ 是直接加载的成品,改完在界面上热重载即可看到效果(profile 以 link: 方式安装时,
源码改动不需要重装)。改代码前建议先读 docs/DESIGN.md,它记录了那些看起来可以简化、
实际上会炸的地方。
MIT
FAQs

Security News
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.

Security News
Anthropic’s free OSS Scanner uses Mythos and other Claude models to find open source vulnerabilities and send maintainers reports with proposed fixes.

Security News
On Front Lines’ Early Adopters: CISO podcast, Andrew Becherer shares lessons from Datadog, weighs the long-term costs of AI-built tools, and explains how founders can actually gain a CISO’s trust.