dsh-restart-button
English | 中文
One-click restart DSH from the sidebar. A small icon button pinned to the
left of the sidebar fold toggle: POST /dsh-restart → the host kills the
current dsh --profile web process gracefully, relaunches the same command
line detached in the background, and the page auto-reloads once the server is
back.
Features
- Icon-only sidebar button (standard refresh icon); the label appears on hover, like the other sidebar buttons.
- Pinned to the left of the sidebar fold toggle; follows the sidebar across wide/rail states and window resize.
- Graceful restart:
SIGTERM first (dsh flushes sessions), SIGKILL escalation, waits for the port to free, relaunches the exact same command line detached, logs to /tmp/dsh-restart-button.log.
- Environment survives the restart: the relaunch runs through your login shell and sources the shell rc first, so every variable you keep there (GitHub token, any other MCP server token, proxies, PATH overrides) reaches the new process — not just the stale snapshot from when dsh started. The current process env (
DSH_HOME, …) is inherited as-is; the result is the union of both.
- Auto page refresh: polls the origin every second (up to 60s) after the kill and hard-reloads when the new server answers.
- Safety fence: the
/dsh-restart endpoint only accepts loopback clients whose Origin (when present) matches the server's own Host (403 otherwise).
Install
# install the published bundle into the web profile
dsh plugin --profile web add dsh-restart-button
# restart dsh once to activate the new bundle
dsh web
For local development from a checkout:
dsh plugin --profile web add link:/absolute/path/to/dsh-restart-button
dsh web
The button appears at the top of the sidebar, immediately left of the collapse toggle.
How it works
- Host half (
lib/host.js): registers the exact route POST /dsh-restart
on the harness web server. On request it writes a small restart script to a
temp file and spawns it fully detached (detached: true, stdio: ignore,
unref()), so the script survives this process's death. The script:
- sleeps 2s (the HTTP response reaches the browser first);
- finds the PID LISTENing on the server's actual port — read from
ctx.webServer, never hardcoded — via lsof -nP -tiTCP:<port> -sTCP:LISTEN
(the server only, never browser connections);
- kills it gracefully and waits for the port to free;
- relaunches the same command line detached through the user's login shell
(
$SHELL), sourcing ~/.zshrc / ~/.bash_profile first — see the
environment note above.
- Client half (
lib/client.js): a window.__ModuleLoader__.load bundle that
registers a sidebar.footer.action slot entry. The button is position: fixed
and re-measured against the fold toggle on resize/sidebar-state changes; when
the sidebar is a collapsed rail the toggle sits at the left edge, so the
button falls back to its right side. After a successful POST it polls / and
calls window.location.reload() once the server responds.
Notes
- The restarted process runs detached in the background (the original
terminal session is gone). Stop it with
lsof -nP -tiTCP:<port> -sTCP:LISTEN
→ kill <pid>, or run dsh web in a terminal yourself instead.
lsof is required on the host (present by default on macOS/Linux).
- The fallback relaunch command defaults to
dsh --profile web when the old
command line cannot be recovered.
License
MIT