Bundle
dsh-restart-control
為 DSH Web 提供跨平台受控的自重啟設定頁面。
- Source
- darkchaox
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 5 days ago
Readme
# dsh-restart-control
[](./LICENSE)
為 DSH Web 提供跨平台、受控的「重啟 DSH」設定頁面。管理者可以在 Web UI 發出固定格式的重啟請求,插件會先保存狀態,再依主機環境選擇交由外部服務管理器重啟,或由內建的 portable helper 重新拉起 DSH。
> [!WARNING]
> 若 DSH 已由 PM2、Docker、Windows Service、systemd 或其他服務管理器負責自動重啟,請使用 `DSH_RESTART_CONTROL_MODE=external`,避免外部管理器與 portable helper 同時拉起多個 DSH 進程。若 DSH 是在 Windows、macOS 或沒有服務管理器的 Linux 上手動啟動,預設的 `auto` 模式會使用跨平台 portable helper。
## 功能
- **Web 設定頁:** 在 DSH Web 的設定頁加入「重啟 DSH」區塊,提供確認、狀態顯示與重新整理按鈕。
- **跨平台重啟:** 支援 Windows、macOS 及 Linux;沒有 systemd 或其他外部管理器時,可由內建 helper 重新拉起原本的 DSH 進程。
- **外部管理器整合:** 在 systemd、PM2、Docker、Windows Service 等環境中,可只退出並返回固定的 exit code 75,讓既有管理器依其重啟策略接管。
- **受控重啟:** 瀏覽器只提交 `settings` 狀態,不接受 shell 命令、檔案路徑或服務管理器參數。
- **可靠確認:** 宿主端先保存 `scheduled` 狀態;新進程產生新的 `bootId` 後才會將狀態標記為 `success`。
- **失敗可見:** 請求逾期、時間格式錯誤、連續重啟過快、狀態保存失敗或 helper 無法啟動時,UI 會顯示失敗原因,不會偽報成功。
- **無需廣泛權限:** 插件不要求為 DSH Web 授予 root、sudo、systemd 或 shell 執行權限。
## 重啟策略
插件讀取環境變數 `DSH_RESTART_CONTROL_MODE`。只接受下列固定值;未設定或填入未知值時會回到 `auto`:
| 值 | 行為 | 適用情境 |
| --- | --- | --- |
| `auto`(預設) | Windows 直接使用 portable;macOS/Linux 偵測到 systemd 管理環境時使用 external,否則使用 portable。 | 手動啟動的 DSH,或希望由插件自動判斷的環境。 |
| `portable` | 啟動內建 helper,等待目前 DSH 進程退出後,以原本的 Node executable、參數、工作目錄與環境重新拉起 DSH。 | Windows、macOS、沒有服務管理器的 Linux。 |
| `external` | 保存 `scheduled` 後以 exit code 75 結束目前進程,不自行啟動子進程。 | systemd、PM2、Docker、Windows Service 或其他已配置自動重啟的管理器。 |
| `systemd` | `external` 的相容別名。 | 舊版只使用 systemd 命名的部署設定。 |
`auto` 不會呼叫 `systemctl` 或其他服務管理命令;在非 Windows 環境只讀取 systemd 注入的 `INVOCATION_ID`、`NOTIFY_SOCKET` 或 `SYSTEMD_EXEC_PID` 來判斷是否交由外部管理器。若部署環境的偵測結果不符合預期,請明確設定 `portable` 或 `external`。
### 建議選擇
- **Windows 本機手動啟動:** 保持 `auto`,或明確設定為 `portable`。
- **macOS/Linux 手動啟動:** 保持 `auto`;沒有 systemd 時會使用 `portable`。
- **systemd 服務:** 保持 `auto` 即可;插件偵測到 systemd 後會使用 `external`。也可以明確設定 `external`。
- **PM2、Docker、Windows Service 或其他管理器:** 明確設定 `external`,由原有管理器處理 exit code 75。
- **不要在同一個 DSH 進程同時使用 portable 與外部自動重啟:** 否則可能產生重複進程。
### 設定環境變數
在 Windows PowerShell 7 中,先在同一個 PowerShell 工作階段設定,再使用原本的 DSH 啟動命令:
~~~powershell
$env:DSH_RESTART_CONTROL_MODE = 'portable'
# 在此執行你原本的 DSH 啟動命令
~~~
若 DSH 由 Windows Service、PM2 或 Docker 啟動,請把 `DSH_RESTART_CONTROL_MODE=external` 加到該管理器的服務環境,而不是只在互動式 PowerShell 中設定。設定完成後,必須重啟 DSH,新的環境變數才會生效。
## 安全模型
插件把瀏覽器請求限制在 `dsh-restart-control` settings namespace,請求只包含下列固定狀態欄位:
| 欄位 | 用途 |
| --- | --- |
| `state` | `idle`、`requested`、`scheduled`、`success` 或 `failed` |
| `requestId` | 識別單次重啟請求,只接受受限格式的字串 |
| `requestedAt` | 判斷請求是否仍在 10 分鐘有效期內 |
| `scheduledAt`、`completedAt` | 記錄排程與完成時間 |
| `bootId` | 識別目前 DSH 進程,確認服務確實經歷了重啟 |
| `message` | 顯示受控流程的結果或失敗原因 |
宿主端的處理順序如下:
1. 驗證 `state`、`requestId` 與 `requestedAt`,拒絕不合法、過期或時間超前過多的請求。
2. 以 `scheduled` 狀態保存請求,讓前端在 DSH 暫時離線前取得可靠的排程記錄。
3. 在 `portable` 模式啟動本地 helper;在 `external` 模式不啟動子進程,只以 exit code 75 結束。
4. portable helper 不使用 shell,會等待原本的 DSH 進程退出,再使用宿主在啟動時的 executable、參數、工作目錄與環境拉起新的 DSH。
5. 新進程產生新的 `bootId`,讀到上一個 `scheduled` 請求後標記為 `success`。
6. Web UI 在服務短暫離線期間輪詢 `settings.describe`,只有在看到相同 `requestId`、新的 `bootId` 與 `success` 時才顯示重啟成功。
瀏覽器提交的 payload 沒有 command、path、executable 或服務管理器參數欄位。插件不把使用者提供的內容拼接成命令列,也不執行 `shell: true`、`exec` 或 `systemctl`。
## 環境需求
- 已安裝 DSH Web,並使用 `web` profile。
- DSH 執行環境提供下列 peer dependencies:
- `@deepseek-ai/cordis` `^4.0.1`
- `@deepseek-ai/dsh-settings` `0.1.0-rc.7`
- `@deepseek-ai/schemastery` `^3.18.1`
- Web client 可使用 DSH Web 已提供的 React runtime。
- 若使用 `external`,外部服務管理器必須已配置在 DSH 退出後自動重啟。
- 若使用 `portable`,DSH 必須由可重複使用的 Node executable、參數與工作目錄啟動;插件會沿用目前進程的啟動資訊。
## 安裝
### 使用官方 DSH CLI(推薦)
如果主機已安裝官方 `dsh` CLI,推薦直接使用以下命令從 GitHub 安裝。這也是 DSH 插件市場優先識別的官方安裝入口;若 CLI 不可用,市場才會回退到 GitHub bundle 安裝。
~~~sh
dsh plugin --profile web install darkchaox/dsh-restart-control
~~~
以下命令在 DSH 主機上執行。先將 GitHub repository clone 到本地插件目錄,再把該目錄加入 `web` profile。
### Linux、macOS 或其他 Unix-like 環境
~~~sh
git clone https://github.com/darkchaox/dsh-restart-control.git /home/dsh/local-plugins/dsh-restart-control
dsh plugin --profile web add /home/dsh/local-plugins/dsh-restart-control
~~~
若 DSH 由 systemd 管理,完成插件安裝後可使用原本的服務管理命令重啟:
~~~sh
sudo systemctl restart deepseek-harness.service
~~~
systemd 環境可以保持 `DSH_RESTART_CONTROL_MODE=auto`;插件會依 systemd 注入的環境資訊選擇 `external`。如需明確設定,可在服務單元加入:
~~~ini
[Service]
Environment=DSH_RESTART_CONTROL_MODE=external
~~~
### Windows PowerShell 7
以下範例使用 PowerShell 7;請把本地目錄替換為你的 DSH 插件目錄:
~~~powershell
New-Item -ItemType Directory -Force -Path 'C:/dsh/local-plugins' | Out-Null
git clone https://github.com/darkchaox/dsh-restart-control.git 'C:/dsh/local-plugins/dsh-restart-control'
dsh plugin --profile web add 'C:/dsh/local-plugins/dsh-restart-control'
~~~
Windows 本機手動啟動 DSH 時,推薦使用預設的 `auto`,或在同一個 PowerShell 工作階段明確使用 `portable`:
~~~powershell
$env:DSH_RESTART_CONTROL_MODE = 'portable'
# 執行你原本的 DSH 啟動命令
~~~
如果 DSH 已由 Windows Service 或其他 Windows 服務管理器啟動,請改用 `external`,並在該服務的環境設定中加入:
~~~text
DSH_RESTART_CONTROL_MODE=external
~~~
不要在 Windows Service 已配置自動重啟時使用 `portable`;portable helper 與 Windows Service 可能同時拉起 DSH。
### 更新插件
Linux、macOS:
~~~sh
git -C /home/dsh/local-plugins/dsh-restart-control pull --ff-only
dsh plugin --profile web add /home/dsh/local-plugins/dsh-restart-control
~~~
Windows PowerShell 7:
~~~powershell
git -C 'C:/dsh/local-plugins/dsh-restart-control' pull --ff-only
dsh plugin --profile web add 'C:/dsh/local-plugins/dsh-restart-control'
~~~
更新後請使用 DSH 原本的啟動方式重啟一次。重新整理 DSH Web 設定頁;若側欄沒有立即出現新項目,請使用 `Ctrl + F5` 清除舊的 client bundle cache。
## 使用方式
1. 開啟 DSH Web 的設定頁。
2. 找到「重啟 DSH」區塊,先按「重啟 DSH」。
3. 確認目前所有 Web 連線會短暫中斷,再按「確認重啟」。
4. 插件保存 `scheduled` 狀態後,會依重啟模式退出或啟動 portable helper。
5. 等待 DSH 重新連線。UI 會在最多 60 秒內輪詢服務狀態。
6. 只有新的 DSH 進程完成啟動並回報新的 `bootId`,畫面才會顯示「重啟成功」。
重啟期間請不要重複提交請求。宿主端有 10 秒冷卻時間,用於避免連續重啟。
## 外部服務管理器設定
### systemd
systemd 服務需要具備自動重啟策略,例如 `Restart=on-failure`。可先檢查:
~~~sh
systemctl show deepseek-harness.service --property=Restart
~~~
預期輸出:
~~~text
Restart=on-failure
~~~
插件在 systemd 下使用 `external`,以 exit code 75 結束,讓 systemd 依服務單元設定重新拉起 DSH。若服務不是 systemd 啟動,請不要只套用 systemd 指令,改用對應的管理器日誌與重啟設定。
### PM2、Docker、Windows Service
這些管理器都應使用 `external`。核心要求是:管理器要把 DSH 的 exit code 75 視為需要重新啟動的結束狀態。
Docker Compose 的環境設定可參考:
~~~yaml
services:
dsh:
environment:
DSH_RESTART_CONTROL_MODE: external
restart: on-failure
~~~
PM2、Windows Service 或其他管理器請在其服務環境中設定 `DSH_RESTART_CONTROL_MODE=external`,並確認既有的「進程異常退出後重啟」策略已啟用。插件不會替你修改這些管理器的設定。
## 故障排查
### 畫面顯示「重啟超時」
這表示 Web UI 在 60 秒內沒有等到新的 DSH 進程。請先確認你使用的重啟模式:
- 手動啟動的 Windows、macOS 或 Linux:確認 `DSH_RESTART_CONTROL_MODE` 是 `auto` 或 `portable`,並確認原本的 DSH 啟動命令仍可正常執行。
- systemd、PM2、Docker、Windows Service 或其他管理器:確認設定為 `external`,且管理器確實會在 exit code 75 後重新啟動 DSH。
- 不要在外部管理器已經自動重啟時使用 `portable`,避免同時出現兩個 DSH 進程。
接著查看對應啟動程序的日誌:
- systemd:`journalctl -u deepseek-harness.service -n 100 --no-pager`
- Docker:查看容器 logs 及容器的 restart status。
- PM2:查看 PM2 process log 與 process status。
- Windows Service:查看 Windows Event Viewer 或該服務管理器的日誌。
- 手動啟動:查看啟動 DSH 的 PowerShell、終端機或程序日誌。
### 畫面顯示「重啟失敗」
常見原因包括:
- 請求超過 10 分鐘有效期,或 `requestedAt` 不是有效的 ISO 8601 時間。
- 距離上次重啟不足 10 秒,觸發冷卻保護。
- DSH settings service 無法保存 `scheduled` 或 `failed` 狀態。
- 上一個進程在保存 `scheduled` 前就中斷,插件因此不會在新進程中自動重試。
- portable helper 無法啟動,或原本的 executable、參數、工作目錄已不再可用。
請先查看 UI 顯示的 `message`,再檢查 DSH 日誌與啟動程序設定。
### Windows 出現重複進程
這通常表示 Windows Service 或其他管理器已負責自動重啟,但模式仍為 `portable` 或 `auto`。在服務管理器的環境設定中加入:
~~~text
DSH_RESTART_CONTROL_MODE=external
~~~
然後停止重複的 DSH 進程,只保留一個由服務管理器管理的實例,再重新啟動服務。
### 設定頁沒有出現插件
請依序確認:
1. 插件已加入 `web` profile,而不是其他 profile。
2. `dsh plugin --profile web add` 使用的是包含 `package.json` 與 `cordis.patch.yml` 的插件根目錄。
3. 已使用 DSH 原本的方式重新啟動 DSH。
4. 瀏覽器已使用 `Ctrl + F5` 重新載入 client bundle。
5. DSH 日誌沒有顯示 peer dependency 或插件載入錯誤。
## 發布披露
此插件不把資料傳送到外部雲端,也不需要 API key、Token 或其他外部憑據。以下資訊與 `package.json` 的 `disclosure` 欄位保持一致:
- **雲端依賴:** 否;`network` 為空陣列,插件不主動連線到外部端點。
- **離線模式:** 是;插件只透過 DSH 自身的 settings 與 Web RPC 工作,不依賴外部網路服務。
- **憑據處理:** 不讀取、儲存或寫入 API key、Token、密碼或其他秘密,也不會把秘密寫入日誌。
- **環境變數:** 只讀取 `DSH_RESTART_CONTROL_MODE`,並把它限制在 `auto`、`portable`、`external` 及相容別名 `systemd`。
- **進程權限:** 重啟請求通過驗證且狀態保存成功後,插件以 exit code 75 結束自身進程;portable 模式另外啟動固定用途的 `restart-helper`。helper 只使用宿主提供的 executable、參數、工作目錄與環境,不使用 shell。
- **檔案系統:** 插件不直接讀寫檔案;重啟狀態由 DSH settings service 持久化,helper 只負責等待與重新啟動進程。
- **DSH settings:** 只讀寫 `dsh-restart-control` namespace 的固定狀態欄位。
- **法域標籤:** 未宣稱特定法域;本項不構成法律意見。
- **資料保留:** `server`;只保留重啟流程狀態,不保留使用者對話內容。狀態清理方式請參考「回滾」章節。
## 檔案結構
~~~text
dsh-restart-control/
├── cordis.patch.yml # 將插件加入 web profile 的 Cordis patch
├── package.json # 插件 metadata、peer dependencies 與 disclosure
├── README.md # 本說明文件
└── src/
├── client.js # DSH Web 設定頁 bundle
├── host.mjs # DSH 宿主端狀態機與重啟策略
└── restart-helper.mjs # 跨平台 portable 重啟輔助程序
~~~
## 開發與驗證
本插件沒有額外的 build script;宿主端與 Web client 由 DSH 的插件載入流程直接使用。提交變更前,可以使用 Node.js 進行基本語法與打包檢查:
~~~powershell
node --check .\src\host.mjs
node --check .\src\client.js
node --check .\src\restart-helper.mjs
npm pack --dry-run --json --ignore-scripts
~~~
也可以使用相同的 Node major version 啟動一個短暫測試進程,驗證 helper 會等待父進程退出後再拉起指定進程;不要直接對正在運行的正式 DSH 實例做重啟測試。
插件的 runtime dependencies 由 DSH 執行環境提供,請不要把 DSH 的設定檔、服務金鑰或本地主機資料提交到 repository。
## 回滾
移除插件後,請使用 DSH 原本的服務管理方式重啟:
~~~powershell
dsh plugin --profile web remove dsh-restart-control
# 使用原本的 DSH 啟動命令或服務管理器重新啟動
~~~
Linux systemd 可使用:
~~~sh
sudo systemctl restart deepseek-harness.service
~~~
移除插件不會刪除其他 settings namespace。若要清理插件留下的狀態,請先確認不再需要重啟記錄,再由 DSH 設定頁或受控的設定檔維護流程移除 `dsh-restart-control` 分節。
## 許可證
本專案採用 [MIT License](./LICENSE)。
Install
dsh plugin --profile web add github:darkchaox/dsh-restart-control
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-restart-control from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.