Skip to content
dsh.fish
Bundle

dsh-wsl-tray

DSH plugin: Windows desktop shortcut and system-tray launcher for DSH running in WSL

Source
liyu34
stars
2 stars
License
MIT
Updated
Updated 4 days ago

Readme

# dsh-wsl-tray

[中文](README.zh.md) | English

A DeepSeek Harness plugin for WSL deployments: it puts a Windows desktop
shortcut and a system-tray launcher in front of the DSH web server running
inside WSL.

## Features

- Double-click the **DeepSeek Harness** desktop shortcut to start DSH in the
  background (or reuse an already-running instance). The default browser opens
  exactly once when DSH is ready (the built-in DSH browser-open is disabled by
  `--no-open`; only the tray opens it).
- A DSH fish tray icon appears. Right-click menu:
  - 打开 DeepSeek Harness / open the DSH web page
  - 重新生成桌面快捷方式 / recreate the desktop shortcut
  - 重启 DSH 服务 / restart the DSH service
  - 暂停守护进程 / 恢复守护进程 / pause or resume the watchdog
  - 退出 / exit the tray icon
- **Double-clicking the tray icon** also opens the DSH web page.
- **A watchdog daemon runs inside the tray**: it probes the DSH URL on a
  timer, restarts DSH when the probes fail, gives up after a bounded number of
  consecutive failed restarts, and writes a full audit trail to
  `watchdog.log` (see [Watchdog](#watchdog) below).
- The plugin-configuration card shows live status (tray files + watchdog
  state) and a button that recreates the desktop shortcut without touching
  WSL by hand. The card can also show the tail of the watchdog log.
- No console window is shown: the shortcut goes through `wscript.exe` + VBS and
  the entire chain is launched with window style 0.

## Requirements

- DSH itself must be running inside WSL (`WSL_DISTRO_NAME` set, `/mnt/c`
  accessible).
- Windows must be able to run `wscript.exe`, `powershell.exe`, and `wsl.exe`.
- DSH web 0.1.0-rc.7 or newer (settings cards + client bundle machinery).

## Install

Once published to npm:

```sh
dsh plugin --profile web add dsh-wsl-tray
```

Or add it manually to a DSH web profile:

```sh
cd ~/.dsh/profiles/web
pnpm add dsh-wsl-tray
```

and add `"dsh-wsl-tray"` to `package.json`:

```json
"dsh": {
  "profile": {
    "bundles": [
      "@deepseek-ai/dsh-base",
      "@deepseek-ai/dsh-web-app",
      "dsh-wsl-tray"
    ]
  }
}
```

Restart `dsh web` and open **Settings → Plugins → Plugin configuration** to see
the **WSL 桌面与托盘** card.

## Generated files

The plugin writes five generated files:

| File | Location |
|---|---|
| `dsh.ico` | `%USERPROFILE%\.dsh\dsh-wsl-tray\dsh.ico` |
| `dsh-tray.ps1` | `%USERPROFILE%\.dsh\dsh-wsl-tray\dsh-tray.ps1` |
| `dsh-tray.vbs` | `%USERPROFILE%\.dsh\dsh-wsl-tray\dsh-tray.vbs` |
| `start.sh` | `~/.dsh/dsh-wsl-tray/start.sh` |
| `stop.sh` | `~/.dsh/dsh-wsl-tray/stop.sh` |

and creates:

```
%USERPROFILE%\Desktop\DeepSeek Harness.lnk
```

While the tray runs, the watchdog maintains two runtime files (both are shown
on the config card):

| File | Location |
|---|---|
| `watchdog.log` | `%USERPROFILE%\.dsh\dsh-wsl-tray\watchdog.log` (rotated at 512 KB) |
| `watchdog-status.json` | `%USERPROFILE%\.dsh\dsh-wsl-tray\watchdog-status.json` (latest tick) |

The shortcut points at `wscript.exe`, which runs `dsh-tray.vbs`; the VBS starts
the tray PowerShell hidden, and the tray starts `start.sh` inside WSL through
`WScript.Shell.Run(..., 0, false)`.

## Watchdog

The watchdog lives inside the tray helper (the one process that is deliberately
independent of DSH), and answers the three questions a restart daemon has to:

1. **How liveness is judged** — an HTTP `Invoke-WebRequest` probe of the DSH
   web URL every `probeIntervalSec` (default 10 s, probe timeout 3 s). Each
   probe records its status code or error text, so a *refused* connection
   (nothing listening), a *timeout* (hung server) and a *bad status* stay
   distinguishable in the log. DSH is only considered DOWN after
   `downThreshold` (3) consecutive failed probes.
2. **Restart success & giving up** — a restart is triggered (stop + start via
   `wsl.exe`) and the watchdog waits up to `restartWaitSec` (180 s) for the URL
   to answer again: an answer = success, which resets the failure counter; an
   unanswered window = one failed restart. After `maxRestartFailures` (3)
   consecutive failures the watchdog **pauses** instead of looping forever. It
   resumes from the tray menu (`恢复守护进程`), or automatically as soon as DSH
   answers again.
3. **Logging** — every probe transition, restart trigger, success/failure and
   pause/resume is appended to `watchdog.log` with a timestamp, level and the
   probe detail; the current state machine snapshot goes to
   `watchdog-status.json` every tick. The plugin card exposes both through
   `/dsh-wsl-tray/watchdog` and `/dsh-wsl-tray/watchdog-log`.

Phases: `starting` (initial boot grace) → `probing` (steady state) →
`restarting` (waiting after a restart) → `backoff` (cooldown) or `paused`
(give-up / manual pause). The tuning values above are baked into
`dsh-tray.ps1`; change them in `src/artifacts.ts`
(`DEFAULT_WATCHDOG_CONFIG`) and regenerate.

## Install without npm publishing

If npm publishing is not an option, install the prebuilt tarball that is
included in this repository:

```sh
cd ~/.dsh/profiles/web
pnpm add /path/to/dsh-wsl-tray-github/dist/dsh-wsl-tray-0.1.4.tgz
```

Then add `"dsh-wsl-tray"` to the profile bundle list as above.

## How it works

1. **Hidden launch**: shortcut → `wscript.exe` → VBS → hidden PowerShell tray.
2. **DSH stays alive**: `start.sh` runs DSH in the **foreground** of the hidden
   `wsl.exe` session, so WSL does not recycle the process after the one-shot
   launcher exits.
3. **Automatic browser open**: a Windows-side timer in the tray polls the DSH
   URL every 2 seconds and calls `Start-Process $webUrl` once DSH answers.
4. **Watchdog**: a second tray timer probes the URL every 10 seconds and runs
   the state machine described above.
5. **Regeneration**: the config card and the tray menu both run
   `dsh-tray.ps1 -Regenerate`.

## Development

```sh
npm install
npm run typecheck
npm test
npm run build
npm pack --dry-run
```

## Known limitations

- Only enabled inside WSL; on non-WSL hosts the card reports that the feature
  is unavailable.
- The watchdog runs only while the tray icon is up: choosing 退出 stops the
  watchdog and the DSH instance (via the generated `stop.sh`: a PID file
  tracks the instance `start.sh` launched, then a pattern fallback covers
  `bin.js web` launches from source checkouts, npm global installs and npx).
  Add the shortcut to the Windows Startup folder if you want the watchdog to
  follow Windows boot.
- A DSH web instance started any other way (different flags, another tool) is
  not tracked by the PID file; stop it by hand (Windows Task Manager or
  `wsl --shutdown`) if the pattern fallback does not reach it.

Install

dsh plugin --profile web add github:liyu34/dsh-wsl-tray

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source