H2O-YAOZE/dsh-mobile-workbench--packages-mobile-ui ↗★ 1
dsh-zen-remote
一个插件、两种角色:主服务端把 DeepSeek Harness 变成手机能安全访问的 PWA(移动端界面、配对码网关、Web Push),并把选定会话共享给已配对的桌面端;子客户端在另一台 DSH 桌面端的侧边栏里远程使用这些会话。One DSH plugin, two roles: the host turns DeepSeek Harness into a phone-reachable PWA (mobile UI, pairing-code gateway behind your own reverse proxy, Web Push) and shares chosen sessions to paired desktops; the client uses those sessions remotely from another DSH desktop app's sidebar. 适合需要在手机上安全访问或在多台电脑间同步会话的用户。
同名パッケージの別リポジトリ
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:H2O-YAOZE/dsh-mobile-workbench#4d5d2dccf67dacd7aa5a7c064cb452e39d489a5f&path:packages/mobile-uiドキュメント
README 全文を読む ↗Configuration
Settings page walkthrough
Where it is: in DSH, click 插件 (Plugins) in the left bar → click dsh-zen-remote in the plugin list → click dsh-zen-remote once more under 包含的组件 (components); the settings block is below.
Common controls: 已覆盖 (overridden) at a field's top right means the value is saved in the plugin settings (overriding the config file or the default); 重置 (reset) falls back to the next layer. Click 保存 (save) at the bottom of the card when done. Fields that need a reload say so, and the plugin reloads itself after saving — no app restart.
Host
-
Set 运行角色 (role) to 主服务端 (host) and give it a recognizable 设备名称 (device name), e.g. "书房" (study) — it titles the group in clients' sidebars and shows on the phone. Save.

-
网关与反代 (gateway and reverse proxy): keep the defaults for local use and phone access through a proxy; for public access see Setting up public access. For clients on the LAN to reach the gateway directly, set 监听地址 (listen address) to
0.0.0.0(it must include loopback — the settings page manages the gateway over loopback). -
配对 (pairing): choose Web 应用端 (phones, browsers) or 桌面应用端 (another DSH desktop app), click 生成配对码 (generate code) and enter it on the other device within 10 minutes. The 设备 (devices) list renames devices, changes their role and revokes them.

-
远程共享 (remote sharing): the idle-sleep window and whether new sessions are shared automatically. Below the card, 已开启远程的会话 (remote-enabled sessions) lists what is shared right now, the idle time left and whether a device is watching; close them one by one or all at once.

-
推送 (push): push summaries, turn-end pushes and so on, as you like — see When notifications fire.
Client
-
Set 运行角色 (role) to 子客户端 (client) and save — the plugin reloads and the page switches to the client's settings.
-
Give this computer a 设备名称 (device name), e.g. "客厅" (living room); it is registered in the host's device list when pairing. Save.
-
连接服务端 (connect to server): enter the host's gateway address (on a LAN e.g.
http://192.168.1.10:3088; public addresses must behttps://) and a 桌面应用端 pairing code from the host, then click 配对 (pair). -
Done when 连接状态 (connection state) reads 已连接到「host name」 (connected to "host name"); the host's groups appear in the sidebar right away. The 诊断 (diagnostics) area lists the request interceptor state and recent remote-call failures — the first place to look when something is off.

Addresses and pairing codes in the screenshots are demo values.
Field reference
Everything is edited in the DSH Plugins page → dsh-zen-remote settings block. Per field the first legal value wins in this order: environment variable > plugin row settings > ~/.dsh/lan-gate.config.json > default. A value that fails its field's check (type, range, enum) makes that layer transparent. Saving a field that needs a gateway/push restart (role, port, host, targetPort, rateLimit, trustedProxies, vapidSubject, lang, and the push fields) reloads the plugin row automatically — no app restart required; everything else takes effect immediately.
Row fields (matching src/config.ts):
| Field | Default | What it does |
|---|---|---|
role | host | host runs gateway + push + sharing; client connects to a server. Anything not exactly client degrades to host |
port | 3088 | Gateway port; if taken it retries upward (up to +20) |
host | 127.0.0.1 | Gateway listen address; only open this up when the proxy is on another machine |
targetPort | (auto) | Local DSH Web UI port. Leave unset: the gateway discovers the host's real listening port (desktop builds use a configurable one) |
rateLimit | 120 | Per-minute cap on unpaired requests, per real client IP |
trustedProxies | empty | Comma-separated IPs; required when the proxy is on another machine |
vapidSubject | mailto:admin@localhost | Push contact. On iOS this must be a real email or https URL, or Apple refuses to deliver |
lang | auto | Language of the gateway's pages, the push opt-in card and the notification copy. auto follows the browser's Accept-Language (falling back to Chinese); zh/en pin it |
pushTurnEnd | off | Also push when a turn ends. Off by default — a finished turn doesn't mean you're needed. Approval/question pushes are unaffected and always fire |
pushEvents | agent/turn-stopping | Which events count as "turn ended", comma-separated; only meaningful with pushTurnEnd |
pushDebounceMs | 15000 | Minimum gap between two automatic pushes; approval/question notifications are never suppressed by it |
pushSummary | off | Include the turn's final reply (prose only, never the reasoning; clipped to 120 chars) and the question text in the body |
pushTool | on | Set false to remove the model-callable push_notify tool |
serverName | computer name | Device name (≤ 40 chars), shared by both roles: on a host it is the display name in clients' group titles; on a client it is the name registered when pairing. Syncs both ways with the server automatically |
idleHours | 48 | Idle-sleep window in hours for remote-enabled sessions; range (0, 8760] |
autoShareNewSessions | off | Auto-enable remote on every session the host creates |
serverUrl (client) | empty | The server's gateway address, normalized per the rules above |
deviceToken (client) | empty | The paired device token; stored as a secret field, redacted everywhere |
turnFoldDesktop | off | Turn-process folding at every width, not just phone widths |
keyboardLiftRatio / keyboardLiftMaxPx / keyboardSafetyPadPx | 0.42 / 400 / 15 | Soft-keyboard lift calibration for browsers that never report the keyboard (see the known-issues note below) |
maxUploadBytes | 20 MB | Attachment upload cap |
The legacy environment variables keep working and outrank the row: LAN_GATE_PORT, LAN_GATE_HOST, LAN_GATE_TARGET_PORT, LAN_GATE_RATE_LIMIT, LAN_GATE_TRUSTED_PROXIES, LAN_GATE_VAPID_SUBJECT, LAN_GATE_LANG, DSH_PUSH_TURN_END, DSH_PUSH_EVENTS, DSH_PUSH_DEBOUNCE_MS, DSH_PUSH_SUMMARY, DSH_PUSH_TOOL, DSH_PUSH_LANG (notification-copy override; without it lang decides), and DSH_PUSH_APPROVAL_GRACE_MS (how long to wait before pushing "approval pending" so a faster auto-approver's verdict wins; default 5000; it and the file-only pushApprovalGraceMs key are not part of the settings surface). LAN_GATE_RELAY_SECRET is not settable: the plugin mints it per load and hands it to the gateway itself.
The upload-size, keyboard-calibration and turn-fold knobs behave exactly as in 1.x — just moved from "plugin row YAML" to "settings page" (a hand-edited row works too).