DSH Restart Button
> 中文文档
A persistent DeepSeek Harness (DSH) plugin that adds a "Restart DSH" button to the web settings. Clicking it force-kills the running DSH process and relaunches it — a real process restart, not an in-process reload — and the page reconnects automatically.
Optionally, a small supervisor loop can run alongside DSH so that the new process comes back in the same console (logs + Ctrl+C), giving a true "in-place" restart.
---
What it does
- Adds a
重启 DSH(Restart DSH) button in Settings → General, right below the theme/appearance switch. - Two-step confirm (click → "确认重启" → restart) to avoid accidental kills.
- On restart:
1. Writes a flag file (dsh-restart.pending). 2. Spawns a detached worker that runs taskkill /F /PID <dsh>. 3. The worker waits a few seconds: - If the supervisor loop relaunched DSH (port 3080 comes back up) → done, in-place. - Otherwise → headless fallback relaunch (no window).
- The browser polls the plugin endpoint and reloads only after a new process (new PID) is serving, with a 30-second hard fallback.
---
Why it works this way
A dynamic Cordis plugin dies with the process, so a persistent plugin cannot restart its own host from inside. The restart therefore needs an external hand:
┌─────────────── Web UI ───────────────┐
│ settings.general.item (order 15) │
│ [重启 DSH] button ──POST──────────► │
└──────────────────────────────────────┘
│
▼
host plugin (lib/index.js)
┌─────────────────────────────────────────────┐
│ write flag + spawn detached node worker │
│ worker: taskkill /F /PID <dsh> │
│ wait → port 3080 up? │
│ yes → supervisor did it │
│ no → headless fallback │
└─────────────────────────────────────────────┘
optional supervisor (dsh-loop.cjs) ← runs in your terminal
┌─────────────────────────────────────────────┐
│ loop { spawn dsh web (stdio inherit) } │
│ on exit: flag exists? → relaunch : exit │
└─────────────────────────────────────────────┘detached: trueon the worker is essential: it must survive DSH's own death (taskkill) to finish the relaunch. A non-detached child is taken down with the parent on Windows.AttachConsolewas tried to re-attach to the original terminal, but it fails withERROR_INVALID_PARAMETER (87)under modern terminals (ConPTY / Windows Terminal), so the supervisor-loop approach is used instead — it is console-API-free and reliable.
---
Repository layout
dsh-restart-button/ # the plugin package (@dsh-external/dsh-restart-button)
├── package.json # DSH bundle + client manifest
├── cordis.patch.yml # inserts the plugin row into the composition
├── lib/
│ ├── index.js # HOST: /api/dsh-restart route + restart worker
│ └── client.js # CLIENT: the settings button + auto-reload polling
├── dsh-loop.cjs # in-place restart supervisor (run in your terminal)
└── desktop/
├── dsh-start.cmd # double-click launcher (runs the supervisor)
└── DSH.vbs # desktop shortcut launcher (hidden start + auto-open browser)---
Installation
1. Install the plugin into your DSH profile
node "C:\Users\<you>\AppData\Roaming\npm\node_modules\@deepseek-ai\dsh\lib\bin.js" plugin --profile web add "C:\path\to\dsh-restart-button"(or use the dsh shim directly if it is on your PATH: dsh plugin --profile web add <path>)
This adds @dsh-external/dsh-restart-button to the profile bundle. Restart DSH to load it.
2. (Optional) Run the supervisor for in-place restart
Without the supervisor, the button still works but relaunches DSH headless (no console window). To get a true in-place restart in your own terminal:
node "C:\path\to\dsh-restart-button\dsh-loop.cjs"This loops dsh web (same console, stdio: inherit). Stop it with Ctrl+C.
3. (Optional) Desktop shortcut
desktop/DSH.vbs is the script behind the "DeepSeek Harness (DSH)" desktop shortcut. Double-clicking it:
1. Checks whether DSH is already up on http://127.0.0.1:3080. 2. If not, launches the supervisor (hidden console). 3. Waits for DSH, then opens the browser.
desktop/dsh-start.cmd is the visible-console variant (shows logs / Ctrl+C).
---
Configuration
A few absolute paths are hard-coded for a specific machine. Adjust them if you install elsewhere:
| File | What to change |
|---|---|
lib/index.js | LOG (log file path), FLAG (restart flag path) |
dsh-loop.cjs | BIN (path to the DSH bin.js), FLAG (must match lib/index.js) |
desktop/DSH.vbs | the powershell.exe ... node '<path-to-dsh-loop.cjs>' command |
desktop/dsh-start.cmd | path to dsh-loop.cjs |
The plugin derives node and args from process.execPath / process.argv at runtime, so those do not need hard-coding.
---
Troubleshooting
The restart flow writes a detailed log to dsh-restart.log (path configured in lib/index.js). Useful markers:
[runner] taskkill done, status=0— old process was killed.[runner] port 3080 is up -> supervisor relaunched in-place, no fallback needed— in-place restart succeeded.[runner] port 3080 still down after wait -> headless fallback— no supervisor running; DSH was relaunched headless.restart handler error:— the plugin itself failed.
---
License
[MIT](LICENSE)