DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

harmless0819-dev /

harmless0819-dev/dsh-power-controls

Verified

Close / restart DSH buttons in Settings > General, plus an opt-out auto-close that waits until every browser page has stopped beaconing.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@db752597

dsh-power-controls

设置 → 普通设置(General)里的两枚电源按钮。

按钮 做什么
重启 DSH 电源循环后端:杀掉当前 dsh web → 等 3080 释放 → 重新拉起 → 验证监听。页面断线几秒后自动刷新回来
关闭 DSH 只关后端。浏览器标签页会停在断线状态,需要双击桌面的 DSH Web 图标重新打开

为什么重启要绕一圈计划任务

第一版的重启是「spawn 一个 detached helper,然后自己 exit」。这是错的:dsh 退出时会回收自己的进程树, helper 跟着一起死,于是后端再也起不来(用户看到的「关闭/重启后不会重新起来」就是这个)。

Windows 上没有可靠办法让子进程比父进程活得久(job object 说了算),所以重启改成把活交给任务计划程序:

点「重启 DSH」
  └─ 后端: Register-ScheduledTask DSHPowerRestart + Start-ScheduledTask   ← 确认成功后才 exit
       └─ 计划任务(独立进程树): respawn-dsh-web.ps1
            ├─ 按端口找到旧的 dsh web 并停掉
            ├─ 等 3080 释放(最多 60 秒)
            ├─ start-dsh-web.ps1 -NoOpen  拉起新实例
            └─ 验证端口,最多重试 3 次

关键点:注册计划任务成功后才允许自己退出。注册失败就返回 500 并继续活着, 否则用户会面对一个「点了按钮、后端没了、也没有人来拉」的死局。

文件

路径 作用
lib/index.js 后端:/dsh-power/close、/dsh-power/restart、/dsh-power/ping、/dsh-power/report、/dsh-power/health,以及 tapIndex 注入
lib/client.js 前端:往 [data-slot="settings.general.item"] 所在的 section 追加按钮行(每次请求都从磁盘读,改完只要 F5)
test-harness.mjs 离线自检:mock 掉 ctx.webServer,直接驱动路由验证自动收尾规则(node test-harness.mjs)
respawn-dsh-web.ps1 计划任务跑的电源循环脚本(ASCII-only,PS 5.1 按 ANSI 读无 BOM 的 .ps1)
logs/dsh-power-restart.log 电源循环日志
logs/dsh-power-restart.{out,err}.log 新实例的 stdout/stderr

自检(看不到浏览器时的验收通道)

curl http://127.0.0.1:3080/dsh-power/health

返回 lastReport / reportCount / clicks:客户端注入成功会上报 injected, 点了按钮会上报 click,重连成功会上报 reconnect。看见 injected 就说明按钮已经画到设置页上了。

安装

# 从 GitHub(推荐)
dsh plugin --profile web add github:harmless0819-dev/dsh-power-controls

# 或从本地克隆
dsh plugin --profile web add link:<本仓库绝对路径>

装/卸这个插件会让 pnpm 重解析依赖树,而 正在运行的 dsh web 锁着 lightningcss 原生模块, 所以必须先停后端再装(我踩过:不停后端会 拒绝访问 (os error 5))。

顺带:浏览器标签页图标(web icon)

同一个插件还负责把标签页 favicon 换成鲸鱼娘(图片由用户提供,128px 落在 assets/web-icon.png)。

为什么不走皮肤:皮肤中心的 canServeSkinHooks() 只放行内置皮肤和字节校验过的官方市场皮肤, 用户目录里的皮肤即使 manifest 合法,它的 hooks.mjs 也会被拒绝执行(原文:hooks only run for built-in or byte-verified official-market skins)。所以 favicon 只能从受信代码路径注入。

两条腿走路,互为兜底:

层 做什么
服务端 tapIndex 摘掉原有的 <link rel="icon">(stock 是 favicon.svg),在 <head> 里声明 /dsh-power/web-icon.png
客户端 applyFavicon() SPA 重渲染可能把 stock 图标放回来,所以每次 tick 重新确认我们的 link 是唯一候选

资源路由 /dsh-power/web-icon.png 每次请求从磁盘读,换图不用重启。

自动收尾:关掉浏览器之后(默认开启)

关标签页不会停掉 dsh web —— 它是服务器,会话/正在跑的回合都靠它活着。但那会白占 ~0.5GB 内存。 所以页面会主动打招呼,并且每次都报上自己的可见性(document.hidden):

时机 请求 作用
页面打开期间,每 3 秒 POST /dsh-power/alive { cid, hidden } 登记这个页面还活着、以及它是不是被切到后台了
可见性变化(切走 / 切回) 同上,立即补一次 不用等下一个 3 秒 tick
关闭 / 刷新 / 跳转 navigator.sendBeacon('/dsh-power/leaving', { cid, hidden }) 明确道别(beacon 能在页面消失后送出,普通 fetch 会被丢)

「客户端消失」有两种,含义完全不同:

现象 判定 处理
收到 pagehide 道别 leaving 立刻从客户端表移除
12 秒(CLIENT_STALE_MS)没心跳,最后上报是可见 stale-visible 移除(人走开了 / 断网 / 浏览器被杀)
12 秒没心跳,最后上报是隐藏 静默但保留 不算离开:后台标签被浏览器节流是常态,页面很可能还开着

只有客户端表彻底空了才开始计时(默认 15 秒,autoCloseMs 可调,设 0 = 关掉这个功能):

  1. 宽限期内页面回来了(刷新、手快重开)→ 直接取消,什么都不做
  2. 宽限到了但还有回合在跑(宿主 ctx.get('agents') 里 status === 'running')→ 继续等,直到回合跑完
  3. 没人看 + 没有回合在跑 → 退出进程把内存还回去,并把原因写下来

退出时日志里会写明原因,例如:

auto-close firing: reason=explicit-pagehide: last client p4x… (visible) said goodbye, no client for 16s …
auto-close firing: reason=silent-visible: last client p4x… (visible) went quiet, no client for 16s …

同一份记录还会落到 D:\deepseek\logs\dsh-power-last-exit.json,由下一次启动的 /dsh-power/health 里的 lastExit 报出来 —— 「上一次到底为什么退出」不用再靠猜。

怎么区分「用户没在看」和「用户把页面关了」

日志里看到 结论
page left (cid, visible/hidden) 明确的关闭 / 刷新 / 跳转
client cid went stale while visible 可见页面静默失联(断网、浏览器被杀)
client cid went quiet while hidden … kept alive 后台标签被节流 —— 页面还在,只是没在被看
同一个 cid 隔一会儿又出现 同一个页面实例一直活着(cid 每次页面加载重新铸,且不写入任何存储)
出现新 cid,而旧 cid 之前没有 page left 旧页面是没打招呼就没了(强杀 / 崩溃 / 信标丢包)

自检通道:/dsh-power/health 的 clients[].hidden / clients[].quiet、visibleClients、 autoClose.pendingReason / autoClose.lastRemoval、lastExit、logFile、runningTurns; 日志写在 D:\deepseek\logs\dsh-power-auto-close.log。

离线自检

node test-harness.mjs

Mocks ctx.webServer + ctx.get('agents'),直接驱动插件自己的路由,覆盖上面全部规则(可见性计数、 hidden 静默保留、visible 静默丢弃、道别移除、退出原因与 last-exit.json 的跨进程回报)。 退出路径跑在子进程里,所以它的 process.exit 不会杀掉测试本身。

测试用 tickMs / staleMs / logFile 三个配置缩短等待并把日志写进临时目录 (为了可测性而存在,生产环境不要设)。

—/ 5

No ratings yet

Verified DSH bundle

Commit db75259750de

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout