dsh-web-restart:給 DSH WebUI 加重啓按鈕,配 launchd 自動拉起

前言

用 DeepSeek Harness(DSH)跑 WebUI 的開發者會遇到一個很具體的麻煩:dsh web 是單個 Node 進程。改完配置、裝了新 bundle,或者進程乾脆崩了,UI 就斷線——你得回到終端,找到那個進程,手動再敲一遍啓動命令,然後回瀏覽器刷新。重啓這個動作本身不難,但每次都要離開瀏覽器去做,很打斷。

反過來拆一下需求就是兩件事:在 WebUI 裏能直接觸發重啓;進程退出之後,有東西負責把它拉起來,讓頁面自己恢復。dsh-web-restart 就是把這兩件事配成一套的插件。DSH 的理念是「一切皆插件」,這類基建能力正好適合以插件形式補上。

這是什麼

dsh-web-restart 由 QIN-SMART 維護,MIT 許可證,當前版本 0.1.0,運行時依賴 @deepseek-ai/schemastery ^3.18.1。它做兩件事:

1、在 DSH WebUI 側邊欄底部加一個「⇄ 重啓 DSH」按鈕,點擊後進程退出,頁面進入遮罩狀態並輪詢,服務恢復後自動刷新;
2、配套 macOS launchd LaunchAgent(launcher/macos/),用 KeepAlive 在 dsh web 退出或崩潰後自動拉起,支持登錄自啓。

有一點要先說清楚:插件本身無法在死後自舉——進程都沒了,按鈕自然也渲染不出來。所以重啓按鈕與外部守護是配套的兩半,缺一不可。

核心功能

重啓按鈕(client 端)

  • 注入側邊欄底部槽 sidebar.footer.action,渲染「⇄ 重啓 DSH」按鈕;
  • 兩段式確認防誤觸。實現上不依賴 window.confirm,因爲在嵌入/沙箱 WebView 裏它會被靜默禁用;
  • 觸發後全屏遮罩掛在 documentElement 上(z-index 最大),提示「正在重啓 DSH…」,每 2 秒輪詢服務是否恢復,恢復後自動刷新頁面。

host 端:端點、命令與退出模式

  • 通過 webServer 服務註冊同源 HTTP 端點 POST /api/_dsh/restart。瀏覽器與 server 同源,fetch 直接可用,不依賴活躍會話;
  • 端點命中後返回 202,稍作延遲讓響應落盤,再執行退出;
  • 退出模式兩種:
  • mode: "exit"(默認):process.exit(),交給 launchd KeepAlive 拉起;
  • mode: "exec":同進程內 spawn 一個新的 dsh web 並 unref,舊進程退出,適合沒有外部守護、從終端手動跑的場景;
  • 可選 token 校驗,支持 Authorization / X-Dsh-Restart-Token 兩種頭;
  • 同時註冊 /restart slash 命令(enableCommand)。觸發機制是雙通道:首選 DSH 官方 RPC(remote.commands.execute("/restart")),回退同源 fetch。

launchd 守護與啓動臺圖標

  • KeepAlive 自動拉起崩潰/退出的進程,支持登錄自啓;
  • 安裝腳本會把 dsh-web-start.sh 複製到 ~/Library/Application Support/dsh-web/ 再交給 launchd——因爲 macOS TCC 隱私保護下 launchd 無法讀取 ~/Documents 等目錄裏的腳本;
  • 啓動腳本自動探測 node 與 dsh 的路徑(nvm / PATH),也可用 NODE_BIN / DSH_ENTRY / DSH_HOME 環境變量覆蓋;
  • 附帶 AppleScript 源碼,可編譯成啓動臺 .app 圖標,點擊啓動 + 打開瀏覽器;
  • launchd 日誌位於 ~/.dsh/dsh-web.launchd.log 與 ~/.dsh/dsh-web.launchd.err.log。

安裝與啓用

插件安裝到你的 DSH profile 目錄,默認是 ~/.dsh/profiles/web/。

方式 A,從 GitHub 安裝(README 推薦)。注意 <你的用戶名>/<倉庫名> 是 README 原文的佔位符,請替換爲你實際託管的倉庫:

cd ~/.dsh/profiles/web
pnpm add "dsh-web-restart@github:<你的用戶名>/<倉庫名>"

然後在 ~/.dsh/profiles/web/package.json 的 dsh.profile.bundles 數組末尾加上 "dsh-web-restart":

"dsh": {
  "profile": {
    "bundles": [
      "@deepseek-ai/dsh-base",
      "@deepseek-ai/dsh-web-app",
      "dsh-web-restart"        // ← 加這一行
    ]
  }
}

重啓 dsh web 後生效。

方式 B,本地 link(開發用):

cd ~/.dsh/profiles/web
pnpm add "link:/絕對/路徑/dsh-web-restart"

同樣在 bundles 里加上 "dsh-web-restart",重啓生效。

默認配置的四項(mode / token / flushMs / enableCommand)可以在 profile 的 cordis.patch.yml 裏覆蓋,例如設置 token:

- id: web-restart
  name: dsh-web-restart
  token: my-secret

macOS:裝守護和啓動臺圖標

先安裝 launchd 守護:

chmod +x launcher/macos/*.sh
launcher/macos/dsh-web-control.sh install

常用子命令:

命令 作用
dsh-web-control.sh status 查看 launchd 狀態
dsh-web-control.sh restart 手動重啓
dsh-web-control.sh stop / start 停 / 啓(停止不解除自啓)
dsh-web-control.sh uninstall 卸載

再編譯啓動臺圖標,用 macOS 自帶的 osacompile:

mkdir -p build
osacompile -o build/DSH.app launcher/macos/DSH-Web-Launcher.applescript
cp -R build/DSH.app /Applications/

README 還給了一個 Automator 的替代做法:新建「應用程序」→ 運行 shell 腳本:

~/Library/Application Support/dsh-web/dsh-web-start.sh
sleep 3
open http://127.0.0.1:3080

另存爲 DSH.app,拖到 Dock / 啓動臺即可。

開發自測

改完代碼先過兩步:

node --check index.mjs lib/client.js   # 語法檢查
node validate.mjs                      # host 邏輯自測(樁 ctx,不啓動服務)

適用場景與注意

適合的人:在 macOS 上把 DSH WebUI 當常駐服務用,希望從瀏覽器裏直接重啓、崩潰或退出後能自動恢復的用戶。如果當前沒有外部守護、從終端手動跑,把 mode 改成 "exec" 即可;倉庫自帶的守護腳本只覆蓋 launchd。

幾點注意:

1、重啓按鈕與外部守護是配套的兩半。只裝插件不裝 launchd 守護時,默認的 mode "exit" 按下去進程就沒了,回不來;
2、macOS TCC 限制:launchd 讀不了 ~/Documents 等目錄裏的腳本,安裝腳本已經處理(複製到 ~/Library/Application Support/dsh-web/),不要自己把啓動腳本挪迴文檔目錄;
3、如果重啓端點不只本機訪問,建議在 cordis.patch.yml 裏配置 token 校驗。

安全方面要說明:這個插件以當前 dsh 進程的權限運行,並且具備觸發進程退出的能力。安裝前建議先檢查源碼與許可證(MIT),確認行爲符合預期再裝進 profile。

小結

dsh-web-restart 解決的是一個很小但高頻的問題:讓「重啓 DSH」從回到終端敲命令,變成瀏覽器裏點一下按鈕,再由 launchd 保證進程一定能回來。按鈕負責觸發和恢復 UI,launchd 負責拉起進程,兩半配齊纔算完整。

  • 社區目錄頁:https://www.skillhub.cn/plugins/QIN-SMART/dsh-web-restart (社區維護的獨立站點,與 DeepSeek / 幻方無官方從屬關係)
  • GitHub:https://github.com/QIN-SMART/dsh-web-restart
羽毛球分组比赛记分
小程序二维码

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

小夜