Introduction¶
The design philosophy of DSH is “everything is a plugin”. After a Host upgrade, configuration changes, or service anomalies, the Host needs to be restarted for the changes to take effect. The conventional approach is to open the terminal, manually end the process, and start it up again. There is no entry point on the Web interface, and running conversations and terminals will be interrupted, making it difficult to complete a reliable restart within the browser.
The dsh-restart introduced below aims to move this action into the Web GUI: add a line in Settings → General, add an item in the sidebar account menu, and also expose an agent tool dsh_restart. The plugin is maintained by dengnianchen, hosted on GitHub, falls under the client category, and is listed on the main site directory page.
What is this¶
In short: Add a Host restart entry to the DeepSeek Harness Web interface, and make it work even without systemd.
The problems it solves are:
- Unable to trigger Host restart on the Web GUI; after changing configuration, one can only rely on the terminal.
- Calling
systemctl restartdirectly inside the process will kill itself (the implementation part below explains the reason). - Reliable judgment is needed after page refresh following restart; brief disconnections during the process cannot be mistaken for success.
The plugin is a normal bundle plugin, containing the Host half and the Web half (an ESM module plus some client code), without changing the sidebar footer icon, Host file, or manually written config in the profile.
Core Features¶
There are three entry points, all performing the same action:
| Entry Point | Location | Implementation |
|---|---|---|
| Settings Row | Settings → General, after “Performance & usage” | Official settings.general.item slot, order: 35, inherits Host’s own General row styling |
| Account Menu Item | Between Settings / Feedback / Restart dsh / Sign out | DOM bridging, see the limitation notes below |
| Agent Tool | dsh_restart({ delayMs? }) |
Uses the same restart logic as the two UI entry points above |
The interaction flow of the restart action:
- The first click enters a warning state, prompting
Click again to confirm, automatically invalid after 4.5 seconds. - The second click schedules the restart, and the interface displays
Restarting…. - The page polls
/dsh-restart/statusevery 0.7 seconds; it only reloads when the pid returned by the Host is different from before—this prevents brief disconnections during restart from being misjudged as success. - If no new process appears within 120 seconds, the control turns to an error state and provides a retry.
During the restart, running conversations and terminals will be interrupted; sessions, transcripts, and settings will be preserved.
Installation and Enablement¶
The installation command comes from the plugin README:
plugin_manager install_bundle @dyapple/dsh-restart
The plugin requires DeepSeek Harness ≥ 0.2.1-rc.3 because it uses ctx.connection.requestRejection and the settings.general.item slot.
How Restart Occurs¶
The Host side splits into two paths based on the runtime environment; both delay first to ensure the HTTP response returns to the page before the Host exits.
-
systemd environment. The plugin determines if it is running under systemd via
INVOCATION_IDand a normal.servicein/proc/self/cgroup, and confirmssystemd-run --useris available; at this point, it uses a detached transient unit to delay executingsystemctl --user restart <unit>.You cannot call
systemctl restartdirectly from inside the process here: dsh-web hasKillMode=control-group, so the restart will first kill the helper process that executed the command along with itself. The transient unit runs in a separate cgroup, which can bypass this problem. -
Non-systemd environment (e.g., a manually started process). Use a detached
/bin/shto wait for the old pid to disappear and the port to stabilize, thenexecthe same command line, while the old process exits.
HTTP Interface¶
The plugin registers two interfaces:
| Path | Method | Purpose |
|---|---|---|
/dsh-restart/status |
GET | Returns {ok, version, pid, mode, unit, command, startedAt, uptimeMs, restarting} |
/dsh-restart/restart |
POST | Body is {delayMs?}, default 700 ms |
Both interfaces go through ctx.connection.requestRejection() first (Connection’s Host/Origin restrictions plus a signed Cookie); POST additionally requires content-type: application/json, as cross-site simple requests cannot carry this header. When there is no Cookie, both interfaces return 401.
Limitations of the Account Menu Item¶
The account menu item is implemented via DOM bridging, not an official slot. The reason is: the menu items in @deepseek-ai/dsh-client-ui-settings-account are a hardcoded array with no slot reserved for extra rows; its only location settings.launcher is single-valued, occupying it equals replacing the entire account menu.
Therefore, the plugin’s approach is: listen to the [role="menu"] node, use a selector that contains both Settings and Feedback tags to locate the account menu, clone the Settings row released with the bundle (inheriting its class, geometry, and hover styles), replace the icon and text, and then insert it before Sign out / Sign in.
Specific limitations:
- It is outside React’s menu item list; the Tab key can reach it, but arrow keys cannot.
- It depends on the menu text and structure released with the bundle. If the text is changed in a later version, it will silently disappear—no error is reported, and it does not affect other UI. The settings row is unaffected because it uses the official slot.
- The node is rebuilt every time the menu opens, using a
WeakSetto prevent duplicate insertion.
Suitable Scenarios and Notes¶
- Suitable for: People who already manage DSH Host with a systemd user service and operate mainly via the Web GUI; developers who want to trigger a restart via a tool inside an agent.
- Not suitable for: Scenarios requiring immediate restart completion. Even with the default delay, there will be a few seconds of pause from click to Host recovery, during which running conversations and terminals will be interrupted.
Notes when using:
- The plugin runs with the permissions of the current dsh process, so the restart action inherits the user permissions that started the process. Before installing, check the source code (repository is open on GitHub) and the license. This plugin uses the MIT license, copyright by Nianchen Deng.
- The account menu item depends on the client UI’s text structure. If the entry disappears after upgrading the client, you can fall back to the line in Settings → General or use the
dsh_restarttool directly.
Development and Debugging¶
When developing from source, follow the steps in the README:
git clone https://github.com/dengnianchen/dsh-restart.git
plugin_manager install_bundle ./dsh-restart
The profile will link to this checkout, so changes to client.js take effect via HMR; changes to index.js require restarting the Host—which can be done using this plugin itself. The Host half is a single-file ESM module, introduced only once per process.
Summary¶
dsh-restart moves the Host restart from the terminal into the Web GUI, uses the official slot to guarantee the reliability of the settings row, uses pid changes to judge whether the restart is truly complete, and provides a working implementation in both systemd and non-systemd environments. The trade-off is that the account menu item depends on the current structure of the client UI, so one may need to pay attention after upgrading the client.
Related information pages:
- Community directory page: https://www.skillhub.cn/plugins/dengnianchen/dsh-restart
- Code repository: https://github.com/dengnianchen/dsh-restart