DeepSeek Harness plugin

dsh-system-control

DSH web 系统控制插件:侧边栏底部「系统」菜单(重启=退出码42 / 关闭=退出码0),经 /system RPC 通道(loopback 权限)调用宿主 appExit。双面:bundle patch 挂宿主半,dsh.client 装配浏览器半。

Jump to install

Source facts

Repository
FrankZhangIronly/dsh-system-control
Latest update
Aug 14, 2026
Category
Security & Permissions
GitHub stars
0
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/FrankZhangIronly/dsh-system-control
Plugin: dsh-system-control
Author: FrankZhangIronly

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer3 files
README.mdSource · read only
README language

dsh-system-control

> A DeepSeek Harness (DSH) web plugin that adds a System menu to the sidebar footer with Restart and Shutdown controls. Restart cycles the launcher (dsh web exits with code 42 and is relaunched); Shutdown exits cleanly (0). Both are routed over a loopback RPC channel so non-local callers are rejected automatically.

The plugin is shipped as a two-sided DSH plugin: a host (Node) half that owns the /system RPC channel and calls the existing appExit exit hook, and a browser half that renders the sidebar button + the centered modal dialog.

> 🌏 中文版本 / Chinese version is also available.

---

Features

  • Sidebar trigger in the sidebar footer mirroring the official settings button shape (wide-bar / collapsed-circle variants).
  • Centered modal with two side-by-side actions: Restart service and Shutdown service. Shutdown asks for a second confirmation (auto-reverts after 4 s).
  • Loopback-only RPC so anyone hitting the host port from another network is blocked with 403 by DSH's existing authority check.
  • Ack-before-exit: the response is flushed before appExit() is invoked (80 ms timer), so the browser receives a clean acknowledgement.
  • Zero changes to DSH core — installed as an ordinary plugin, survives @deepseek-ai/dsh updates.

---

Installation

dsh plugin --profile web add dsh-system-control

Restart dsh web. The new 系统 / System button appears at the bottom of the sidebar.

To install from a local checkout:

dsh plugin --profile web add /path/to/dsh-system-control

---

Exit-code protocol

ActionExit codeLauncher behavior
Shutdown0The launcher loop exits and the window closes.
Restart42The launcher loop relaunches dsh web.
Statusn/aProbe: returns { exitAvailable, exitType }.

The companion launcher DSH Web.ps1 already implements this contract:

  • exit 0 → close window,
  • exit 42 → relaunch,
  • any other code → log and exit.

If you launch DSH through a different mechanism (systemd unit, plain dsh web, etc.) make sure it understands these codes. Anything else will be treated as a hard crash.

---

How it works

┌────────────────────┐  connection.rpc.call('/system', 'restart', {})   ┌──────────────────────────┐
│  Sidebar button    │ ───────────────────────────────────────────────▶ │  HostConnectionService   │
│  + modal (browser) │                                                │  → loopback authority    │
└────────────────────┘                                                │  → /system handler       │
                                                                      │  → ctx.get('appExit')(42)│
                                                                      └──────────────────────────┘

1. The bundle patch inserts a single host row system-control that injects connection and (transitively, via connection startup) appExit (which the cmdline launcher registers before any plugin mounts). 2. The host half registers an RPC handler on channel /system with authority: 'loopback'. Anything not bound to loopback is automatically rejected. 3. The browser half registers a slot entry under sidebar.footer.action with order 20 and renders the trigger + modal component. 4. appExit(code) is invoked through ctx.get('timer').timeout(..., 80) so the 200 OK response can flush first.

---

RPC contract (host half)

Channel: /system · authority: loopback (non-local callers get 403).

EndpointReturns
status{ ok: true, value: { exitAvailable: <is function>, exitType: <typeof> } }
restart{ ok: true, value: { accepted: true, code: 42 } } then appExit(42) after ~80 ms.
shutdown{ ok: true, value: { accepted: true, code: 0 } } then appExit(0) after ~80 ms.
anything else{ ok: false, error: { code: 'internal', message: 'unknown endpoint …' } }

The status endpoint is purely a sanity probe used by the modal to display "退出通道:可用 / 不可用" in the dialog header.

---

Repository layout

system-control/
├── cordis.patch.yml       # bundle patch: insert the system-control row
├── lib/
│   ├── index.js           # host half (Node): /system RPC + appExit bridge
│   └── client.js          # browser half: sidebar trigger + modal
├── package.json
└── README.md

The cordis.patch.yml adds a single row to the host composition tree that injects connection. appExit is provided by the cmdline launcher before the tree mounts, so it is consumed implicitly rather than declared in inject: [...].

---

Compatibility

  • @deepseek-ai/dsh ≥ current web profile (consumes connection, slots, timer).
  • Node ≥ 18 (matches DSH host runtime).
  • Browser: Chromium-based (uses standard React + KeyboardEvent / document APIs).

---

License

MIT