# dsh-web-remote
ไธญๆ | English
> A plugin for DeepSeek Harness (DSH) that enables mobile and remote access via phone browser or WeChat. ## โจ Features | Feature | Description | |---------|-------------| | ๐ **Public Access** | Cloudflare Quick Tunnel โ no public IP or registration needed; auto-downloads `cloudflared` | | ๐ฅ๏ธ **Official Desktop App** | Works in the DSH desktop app (`dsh-app://`): button injection via the official structured channel, target port auto-detection | | ๐ก **LAN Direct** | HTTP + HTTPS as **two parallel links**: HTTP needs no cert, HTTPS is self-signed (just click "Proceed") | | ๐ **Secure Auth** | Random token per start; HttpOnly Cookie; LAN can be token-free | | โก **Performance** | Reverse proxy with automatic gzip compression for faster large session loads | | ๐ฑ **Sidebar Icon** | Phone shortcut button persists in the bottom-left corner | | ๐ **Custom Public URL** | Set your own public URL (e.g. ngrok); edit/clear from the panel | | ๐ **Custom Port** | HTTP / HTTPS ports are **independently configurable**, with same-port conflict blocking and occupancy detection | | ๐ค **WeChat Bot** | iLink protocol direct connection to WeChat; AI chat, session control, model switching | | ๐ฌ **Feishu Bot** | WebSocket long connection; command control, monitor notifications | | โ๏ธ **Telegram Bot** | Long polling; HTTP proxy support, command control, monitor push | | ๐ง **QQ Official Bot** | QQ Open Platform official integration; WebSocket long connection โ **no extra QQ account, no public endpoint/ICP filing** | | ๐ **DingTalk Bot** | Internal enterprise app + Stream-mode long connection โ **no public endpoint**; webhook replies + OpenAPI proactive push | | ๐๏ธ **Session Monitor** | `/monitor` โ get notified on your bound channel when the agent finishes | | ๐ฉบ **Channel Health** | Per-channel monitoring (WeChat/Feishu/Telegram/QQ/DingTalk); auto-stops after 3 consecutive failures, red-dot shortcut + one-click reconnect | ## ๐ Quick Start **3 steps:** ```bash # 1. Install plugin (run in DSH profile directory) cd $DSH_HOME/profiles/web pnpm add github:godchen520/dsh-web-remote # 2. Register bundle (edit package.json) # Add "dsh-web-remote" to the "dsh.profile.bundles" array # 3. Restart DSH dsh web ``` A ๐ฑ icon appears in the bottom-left corner โ click to open the remote panel. ## ๐ธ Screenshots **Sidebar button** (bottom-left corner):  **Remote Panel** (Public / LAN switch, copy link, QR code, start/stop):  ## ๐ Installation ### Option 1: GitHub Install (Recommended) ```bash cd $DSH_HOME/profiles/web pnpm add github:godchen520/dsh-web-remote ``` Add `"dsh-web-remote"` to `dsh.profile.bundles` in `package.json`, then restart DSH. > Use `--config.minimumReleaseAge=0` if pnpm 11 blocks new packages. ### Option 2: Manual Patch Place the package in profile's `node_modules`, then add to `cordis.patch.yml`: ```yaml - insert: - id: web-remote name: 'dsh-web-remote' ``` > Bundle install requires restart; cordis.patch.yml supports HMR hot-reload. ## โ๏ธ Configuration All optional. Override in `cordis.patch.yml`: | Option | Default | Description | |--------|---------|-------------| | `targetPort` | auto-detected | DSH's own port. **Explicit config wins**; otherwise `DSH_WEB_URL` โ `DSH_PORT` โ fallback `3080` | | `httpPortStart` | `3081` | LAN HTTP start port (auto-skips occupied) | | `httpsPortStart` | `3082` | LAN HTTPS start port | | `cloudflaredPath` | `''` | Specify cloudflared path; empty = auto-detect / auto-download | | `pfxPath` | `''` | PFX certificate; empty = auto-generate self-signed | | `pfxPass` | `''` | PFX password | | `toolsDir` | `''` | Tool & cert cache directory; empty = `$DSH_HOME/tools` | | `autoStart` | `true` | Auto-start on plugin load | | `lanOpen` | `true` | LAN token-free mode (private network bypass) | ## ๐ฑ Usage 1. After start, a ๐ฑ icon appears in the bottom-left corner 2. Click the icon โ panel shows status and links 3. Open the link in your phone browser **Public:** `https://xxx.trycloudflare.com/?token=...` **LAN** (same Wi-Fi; token-free by default, **two parallel links**): - `http://192.168.x.x:3081` โ **recommended**: no cert, opens straight away (not a secure context; clipboard API etc. are restricted) - `https://192.168.x.x:3082` โ self-signed cert: the browser warns, click "Advanced โ Proceed" (secure context) **Panel:** - Public tab: set a custom public URL (e.g. your own ngrok address) - LAN tab: each link's **port number is click-to-edit** (HTTP and HTTPS separately); the QR code points at the HTTP address so a phone scan opens it directly ## ๐ฅ๏ธ Official Desktop App The plugin works in the DSH desktop app (window URL `dsh-app://app/`). Two differences from the browser build: | Item | Note | |---|---| | **Button injection** | The desktop app uses the **static deployment** render path, which only consumes the official **structured injection rows** (`webserver/index-inject`) and **does not run `tapIndex`**. The plugin now uses both channels, so either build is covered | | **Target port** | The desktop app lets the host assign the port dynamically (measured: `19387`), and the plugin process **cannot see** `DSH_WEB_URL` (that is injected into the agent shell). It must be set explicitly | Add the port to the profile's `cordis.patch.yml`: ```yaml - id: web-remote name: dsh-web-remote config: targetPort: 19387 # replace with your desktop app's actual port ``` > Without it the plugin falls back to `3080`, which shows up as a tunnel **502 Bad Gateway / Host Error**. > `/remote/info` returns `targetPort` and `portSource` (`config` / `env` / `default`) so you can confirm which value was used. ## ๐ค WeChat Bot Control DSH directly from WeChat: **Remote Control Commands:** - `/link` โ Get public link (auto-starts if stopped) - `/stop` โ Stop remote service - `/monitor` โ Toggle session monitor (notify when agent finishes) **Session Management:** - `/sessions` โ List all sessions - `/select N` โ Select session N - `/session` โ Show selected session name - `/history` โ Show session's recent output **Model Switching:** - `/model` โ Show current model - `/switch-model` โ List and switch models - `/effort N` โ Set reasoning effort **Chat:** - Send content directly โ auto-sends to selected session with result - Shows prompt to select a session when none is selected ## ๐ฌ Feishu Bot Control DSH directly from Feishu (Lark): - `/link` โ Get public link - `/stop` โ Stop remote service - `/monitor` โ Toggle session monitor - `/help` โ Show command list **Setup:** DSH Web panel โ Bot tab โ Feishu, fill in App ID and App Secret, then bind. ## โ๏ธ Telegram Bot Control DSH directly from Telegram: - `/link` โ Get public link - `/stop` โ Stop remote service - `/monitor` โ Toggle session monitor - `/help` โ Show command list **Setup:** DSH Web panel โ Bot tab โ Telegram, fill in the Bot Token, then bind. **Proxy:** If the Telegram API is unreachable from your network, configure an HTTP proxy in the panel. ## ๐ง QQ Official Bot Official QQ bot via the **QQ Open Platform**: - `/link` โ Get public link - `/stop` โ Stop remote service - `/monitor` โ Toggle session monitor - `/model` โ Show current model - `/status` โ Channel status - `/help` โ Show command list **Scenarios:** QQ group chat + message-list private chat (C2C). **Setup (two options):** **Option 1 โ QR binding (recommended; no secrets to copy):** 1. DSH Web panel โ Bot tab โ **QQๅฎๆน** โ click "๐ฑ ๆซ็ ็ปๅฎ" 2. Scan the QR code with **mobile QQ** 3. Pick the bot you want to bind in the page that opens, then confirm 4. Credentials are filled in automatically and the channel connects > Scanning **binds an existing bot** โ it does not create one. Create one first via Option 2 if needed. **Option 2 โ Manual entry:** 1. Open the [QQ Open Platform quick-create page](https://q.qq.com/qqbot/openclaw/login.html), sign in with QQ, click "Create Bot" (individual accounts may create up to 5) 2. Copy the **AppID** and **AppSecret** from the platform's developer settings 3. Paste them into the panel and click connect **Highlights:** | Item | Notes | |---|---| | Extra QQ account | **Not required** โ the platform assigns a dedicated bot identity; your QQ is only the admin | | Public endpoint | **Not required** โ WebSocket long connection with built-in heartbeat and RESUME | | ICP filing | **Not required** | | Session persistence | Supported โ survives restarts via RESUME, replaying missed events | | Proactive push | Supported (you must have messaged the bot first; group needs owner permission) | **Group chat:** the group owner simply adds the bot to the group. Receiving *all* group messages requires the owner to enable it in the bot settings. **Note:** this is the plugin's **only** QQ integration. An earlier version shipped a OneBot 11 (NapCat) channel; it was removed in 5.0.0 โ the official bot is compliant, stable, needs no extra QQ account and no NapCat middleware. ## ๐ DingTalk Bot Integrated through a DingTalk Open Platform **internal enterprise app + robot**, using **Stream mode** (a long connection) โ so, like Feishu/QQ Official, it needs **no public IP, domain, certificate or tunnel**. **Commands:** identical to every other channel โ `/help` `/link` `/start` `/stop` `/monitor` `/status` `/sessions` `/select N` `/current` `/history` `/model` `/switch-model` `/effort`, plus **plain text** (no `/` prefix) which is relayed into the selected session. **Key facts:** | Item | Notes | |---|---| | Account requirement | An **organization** is required (personal DingTalk does not support app robots); a free team where you are admin works | | Public endpoint | **Not required** โ Stream mode long connection | | Passive reply | Uses the message's `sessionWebhook` (**no extra permission**); valid **1.5 hours**, then falls back to the OpenAPI | | Proactive push | OpenAPI (`oToMessages/batchSend` for C2C, `groupMessages/send` for groups); needs the **"ไผไธๅ ๆบๅจไบบๅ้ๆถๆฏๆ้"** permission | | Monitor notifications | Sent via the OpenAPI, **not limited by the 1.5-hour window**; the last conversation target is restored after a restart | | Group chats | The robot must be **@mentioned** to receive a message; proactive push **cannot @ people** | | Message length | Auto-split at 4000 chars (group API caps `msgParam` at 15000 bytes) | **Setup:** 1. Sign in to the [DingTalk developer console](https://open-dev.dingtalk.com) as an **org admin** (or ask an admin to grant you developer permission) 2. App development โ **Create internal enterprise app** โ note the **Client ID / Client Secret** 3. App capabilities โ add a **Robot** โ set **message receive mode to "Stream mode"** โ save 4. **Publish the app**: version management โ new version (**tick "Robot"**) โ publish > Until it is published the robot is not visible in chats and `senderStaffId` is not returned 5. Request the permission: development config โ permissions โ search **"ไผไธๅ ๆบๅจไบบๅ้ๆถๆฏๆ้"** > Passive replies work without it; `/monitor` notifications require it 6. For group chats: group settings โ group management โ robots โ add the robot 7. DSH panel โ Bot tab โ **DingTalk** โ enter Client ID / Client Secret โ "Verify & connect" ## ๐ฉบ Channel Health Monitoring WeChat / Feishu / Telegram / QQ Official / DingTalk are monitored independently: - **3 consecutive** failures โ that channel stops automatically and raises an alert - The remote icon shows a **red dot** (lights up when any channel is down) - **Clicking the red dot jumps straight** to the broken channel page, with a **one-click reconnect** button ## ๐ง Compatibility | DSH version | Status | |---|---| | **0.2.x (tested on 0.2.0-rc.2)** | โ Supported | | 0.1.2-rc.1 ~ 0.1.x | โ Supported | | < 0.1.2-rc.1 | โ Not supported (`session.events` was still a property back then; no `snapshotEvents()`) | This plugin **imports no `@deepseek-ai/*` package** โ every host capability (`webServer`, `subprocess`, `agents`, `sessions`, `sessionQuery`, โฆ) comes from cordis service injection. So a DSH change to **package exports** (e.g. 0.2.x removing `settingsNamespace` / `installSettingsSection` from `dsh-settings`) cannot affect it. Only the **service interfaces themselves** need adapting: currently `session.snapshotEvents()` (the 0.1.2+ form). ## โ FAQ **Q: LAN link shows "not secure"?** A: That is the **self-signed HTTPS cert** behaving as expected (the public tunnel uses a real cert and never warns). **Simplest fix: use the HTTP link the panel lists alongside it** โ no cert, opens straight away. Only use the HTTPS one when you actually need a secure context (clipboard API etc.): choose "Continue anyway" on mobile, or turn off "Enhanced Security" in Edge. **Q: Link changes after DSH restart?** A: Public tunnel generates a new address each restart โ this is normal. WeChat-bound tokens auto-restore. **Q: cloudflared download fails?** A: First start needs internet to download cloudflared (~10MB). Afterwards it's cached. You can also manually place it in `toolsDir`. **Q: WeChat disconnects after scanning?** A: After DSH restart, WeChat auto-reconnects (token is persisted). If still disconnected, re-send `/link` to rebind. ## ๐ Changelog See [CHANGELOG.md](CHANGELOG.md) for version history. ## ๐ค Contributing See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for development and submission guidelines. ## ๐ License [MIT](LICENSE)