dengnianchen/dsh-restart:在 Web GUI 裏重啓 DSH Host

前言

DSH 的設計是「一切皆插件」,Host 升級、配置改動、服務異常之後,都需要重啓 Host 讓改動生效。常規做法是打開終端手動結束進程再拉起來,Web 界面上沒有任何入口,跑着的回合和終端也會被中斷,因此很難在瀏覽器裏完成一次靠譜的重啓。

下面介紹的 dsh-restart 就是爲了把這個動作放進 Web GUI:在 Settings → General 里加一行,在側邊欄賬號菜單里加一項,同時也暴露一個 agent 工具 dsh_restart。插件由 dengnianchen 維護,託管在 GitHub,屬於客戶端分類,主站目錄頁有收錄。

這是什麼

一句話:給 DeepSeek Harness 的 Web 界面加一個 Host 重啓入口,並且在沒有 systemd 時也能工作。

它解決的問題是:

  • Web GUI 上無法觸發 Host 重啓,改完配置只能靠終端。
  • 在進程內直接調用 systemctl restart 會連自己一起殺掉(下面的實現部分解釋原因)。
  • 重啓後的頁面刷新需要可靠判斷,不能把一次短暫斷連當成成功。

插件是普通的 bundle plugin,包含 Host 半部分和 Web 半部分(一個 ESM 模塊加一段客戶端代碼),不改動側邊欄 footer 圖標、Host 文件和 profile 裏手寫的配置。

核心功能

三個入口,做的是同一件事:

入口 位置 實現方式
設置行 Settings → General,排在 “Performance & usage” 之後 官方 settings.general.item 插槽,order: 35,行外殼沿用 Host 自己的 General 行樣式
賬號菜單項 Settings / Feedback / Restart dsh / Sign out 之間 DOM 橋接,原因見下面的限制說明
Agent 工具 dsh_restart({ delayMs? }) 與上面兩個 UI 入口走同一套重啓邏輯

重啓動作的交互流程:

  1. 第一次點擊進入警告態,提示 Click again to confirm,4.5 秒後自動失效。
  2. 第二次點擊排定重啓,界面顯示 Restarting…。
  3. 頁面每 0.7 秒輪詢 /dsh-restart/status,只有當 Host 返回的 pid 與之前不同時才重新加載頁面——這樣重啓過程中的短暫斷連不會被誤判爲成功。
  4. 如果 120 秒內沒有出現新進程,控件轉爲錯誤態並提供重試。

重啓過程中,正在運行的回合和終端會被中斷;會話、transcript 和設置都會保留。

安裝與啓用

安裝命令來自插件 README:

plugin_manager install_bundle  @dyapple/dsh-restart

插件需要 DeepSeek Harness ≥ 0.2.1-rc.3,因爲它使用了 ctx.connection.requestRejection 和 settings.general.item 插槽。

重啓是怎麼發生的

Host 側按運行環境分兩條路徑,兩者都會先延時,保證 HTTP 響應在 Host 退出之前回到頁面。

  1. systemd 環境。插件通過 INVOCATION_ID 和 /proc/self/cgroup 裏的普通 .service 判斷自己是否跑在 systemd 下,並確認 systemd-run --user 可用;此時會用一個 detached transient unit 延時執行 systemctl --user restart <unit>。

這裏不能直接從進程內調用 systemctl restart:dsh-web 的 KillMode=control-group,重啓會先把執行調用的輔助進程一起殺掉。transient unit 跑在另一個 cgroup 裏,可以繞開這個問題。

  1. 非 systemd 環境(例如手工啓動的進程)。用一個 detached 的 /bin/sh 等待舊 pid 消失、端口穩定,然後 exec 同一條命令行,同時舊進程退出。

HTTP 接口

插件註冊了兩個接口:

路徑 方法 用途
/dsh-restart/status GET 返回 {ok, version, pid, mode, unit, command, startedAt, uptimeMs, restarting}
/dsh-restart/restart POST Body 爲 {delayMs?},默認 700 ms

兩個接口都先經過 ctx.connection.requestRejection()(Connection 的 Host/Origin 限制加上簽名 Cookie);POST 還額外要求 content-type: application/json,跨站的簡單請求無法攜帶這個頭。沒有 Cookie 時兩個接口都返回 401。

賬號菜單項的限制

賬號菜單項是 DOM 橋接實現,不是官方插槽。原因是:@deepseek-ai/dsh-client-ui-settings-account 裏的菜單項是硬編碼數組,沒有爲額外行預留插槽;它唯一的位置 settings.launcher 是單值的,佔用它等於替換整個賬號菜單。

因此插件的做法是:監聽 [role="menu"] 節點,用同時包含 Settings 和 Feedback 標籤來定位賬號菜單,克隆隨包發佈的 Settings 行(繼承其 class、幾何與 hover 樣式),替換圖標和文案,再插到 Sign out / Sign in 之前。

具體限制:

  • 它在 React 的菜單項列表之外,Tab 鍵可以到達,方向鍵不行。
  • 它依賴隨包發佈的菜單文案和結構。如果後續版本改了文案,它會靜默消失——不報錯,也不影響其他 UI。設置行不受影響,因爲它用的是官方插槽。
  • 每次菜單打開時節點會被重建,用 WeakSet 防止重複插入。

適用場景與注意

  • 適合:已經用 systemd user service 託管 DSH Host、並且主要通過 Web GUI 操作的人;想在 agent 裏通過工具觸發重啓的開發者。
  • 不適合:需要重啓立刻完成的場景。即使使用默認延時,從點擊到 Host 恢復也會有數秒停頓,正在運行的回合和終端會被中斷。

使用時需要注意:

  • 插件以當前 dsh 進程的權限運行,重啓動作因此繼承了啓動該進程的用戶權限。安裝前應先檢查源碼(倉庫公開在 GitHub)和許可證。本插件使用 MIT 許可證,版權人爲 Nianchen Deng。
  • 賬號菜單項依賴客戶端 UI 的文案結構,升級客戶端後如果入口消失,可回退到 Settings → General 裏的那一行,或直接使用 dsh_restart 工具。

開發調試

從源碼開發時按 README 的步驟:

git clone https://github.com/dengnianchen/dsh-restart.git
plugin_manager install_bundle  ./dsh-restart

profile 會鏈接這份 checkout,因此 client.js 的改動通過 HMR 生效;index.js 的改動需要重啓 Host——恰好可以用這個插件自己來做。Host 半部分是一個單文件 ESM 模塊,每個進程只引入一次。

小結

dsh-restart 把 Host 重啓從終端搬進 Web GUI,用官方插槽保證設置行的可靠性,用 pid 變化判斷重啓是否真正完成,並在 systemd 和非 systemd 兩種環境下都給出可工作的實現。代價是賬號菜單項依賴客戶端 UI 的當前結構,升級客戶端後可能需要留意。

相關信息頁:

  • 社區目錄頁:https://www.skillhub.cn/plugins/dengnianchen/dsh-restart
  • 代碼倉庫:https://github.com/dengnianchen/dsh-restart
羽毛球分组比赛记分
小程序二维码

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

小夜