dsh-mobile 0.3.16 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  Notable changes to DSH Mobile are recorded here. GitHub Releases remain the source for downloadable packages and complete generated commit notes.
4
4
 
5
+ ## Unreleased
6
+
7
+ No unreleased changes.
8
+
9
+ ## 0.4.1 - 2026-09-15
10
+
11
+ - Allow the desktop Mobile access admin API and sidebar control on RFC1918 and IPv4 link-local Host values when the TCP peer remains loopback, so headless Linux hosts and LAN reverse proxies can open DSH Web without a localhost-only browser. Public IPs, CGNAT, and arbitrary DNS names stay rejected. The dedicated Mobile HTTPS listener remains the phone surface (thanks @xingleiwu for PR #79).
12
+ - Let the proxied DSH GUI frame its own same-origin surfaces and embed external http(s) and blob: pages, so the right-sidebar browser tab, the HTML/diff previews, and the PDF preview work over LAN and remote access; gateway-owned login, pairing, and JSON responses keep refusing every frame (thanks @idoall for PR #77).
13
+ - Bound advisory operating-system route inspection so a slow Windows network query falls back to explicit network selection instead of holding the local setup page open.
14
+ - Keep Android CI and release setup limited to currently available SDK packages so APK verification is not blocked by the retired `tools` package.
15
+ - Require a same-origin `Origin` header on every mutating desktop management request, including clients that omit Fetch Metadata, so private-Host reverse proxies cannot bypass the browser CSRF check.
16
+ - Accept the DSH conversation scroll marker wherever it lives under the conversation skeleton, keeping the compatibility gate valid when upstream extracts the body into a separate component.
17
+ - Allow HTTP iframe sources for compatibility while showing a localized warning that unencrypted pages can be altered and should not be used for sensitive work.
18
+ - Fix mobile extension Host actions that sent JSON without an explicit content type, which caused every `api.host.invoke()` call to return `415 unsupported_media_type`.
19
+ - Accept callable Schemastery input schemas as well as existing `parse(value)` adapters for extension actions, so documented `api.schema.object(...)` inputs are validated and normalized before `run()`.
20
+ - Update the development peers and source compatibility gate for DeepSeek Harness `0.1.6-alpha.1`: the checker follows extracted conversation/composer markers and the named global transport hook without weakening the Host-trust or authenticated RPC checks.
21
+ - Correct bilingual navigation and historical issue links, clarify Android task-reminder versus browser-notification behavior, and add a complete English self-hosted FRP guide without changing runtime behavior.
22
+
23
+ ## 0.4.0 - 2026-09-14
24
+
25
+ - Add multi-device management to the Android app: migrate existing LAN and remote credentials, show each paired computer with its Origin and HTTPS reachability state, connect the most recently used valid device on direct startup, and provide list, rename, re-pair, delete, and launch-behavior controls.
26
+ - Complete plugin-side localization for Chinese, English, and Italian, including diagnostic report copy, browser pairing pages, and reauthentication guidance selected from `Accept-Language`; Android resources remain key-complete across all three supported locales.
27
+ - Use a bounded session-free native probe for list reachability checks, with a renewal fallback for older plugins so status refreshes cannot evict an active DSH session.
28
+ - Preserve a local row after computer-side revocation, stop automatic retries for revoked credentials, and expose a short-lived undo action for local deletion without restoring a computer-side authorization.
29
+ - Follow the DSH conversation's actual nested scroll container when showing or hiding the Android toolbar, keeping task-notification settings reachable on current DSH Web layouts.
30
+ - Let cpolar choose its default route instead of forcing `cn`; explicit region settings remain available for advanced deployments.
31
+ - Add Android task-completion and pending-input reminders through authenticated Host events and the exact-origin native bridge; notification permission is enabled explicitly from the foreground app menu, lock-screen text stays generic, and each completed turn keeps a separate reminder (thanks @qzyqmzn for PR #75).
32
+ - Show and re-copy remote pairing links without invalidating the QR code's active one-time pairing window (thanks @qzyqmzn for PR #75).
33
+ - Detect plugin-market installations that have not completed LAN setup, prevent the loopback-only `127.0.0.1` fallback from being presented as phone access, and provide a localized in-panel network picker that creates private TLS material and LAN-only Windows firewall rules after explicit confirmation. The configured gateway starts after one DSH restart (thanks @cangming99 for #72).
34
+ - Keep native DSH file selection in the composer Add group, add only camera capture there, and reuse the native menu-row styling for the mobile action.
35
+ - Add a native-app-only Switch computer action to the WebView's DSH General settings page, keeping the Android device-list settings and DSH content toolbar focused on their own controls.
36
+ - Hide the Android shell toolbar above the WebView so DSH occupies the full safe viewport; the system status-bar color continues to follow the page background.
5
37
 
6
38
  ## 0.3.16 - 2026-09-12
7
39
 
@@ -75,7 +107,7 @@ Notable changes to DSH Mobile are recorded here. GitHub Releases remain the sour
75
107
 
76
108
  ## 0.3.7 - 2026-09-02
77
109
 
78
- - Fix the Windows DSH Desktop startup failure reported in [#22#22](https://github.com/saya-ch/dsh-mobile/issues/22): capture subprocess output through the callback API instead of relying on `execFile` promisify metadata that a host wrapper may omit. Thanks @XChen446 for the precise 0.3.6 stack trace.
110
+ - Fix the Windows DSH Desktop startup failure reported in [#22](https://github.com/saya-ch/dsh-mobile/issues/22): capture subprocess output through the callback API instead of relying on `execFile` promisify metadata that a host wrapper may omit. Thanks @XChen446 for the precise 0.3.6 stack trace.
79
111
  - Apply the same output handling to Windows SID resolution, private-file ACLs, route selection, and firewall diagnostics/setup. Invalid SID output and ACL failures still reject the operation; a failed SID lookup can be retried and Windows permission commands have bounded execution time.
80
112
  - Retain the 0.3.6 removal of the exact DSH version allowlist. Existing 0.3.3-0.3.6 Android apps and paired devices remain compatible; the 0.3.7 APK updates version metadata only.
81
113
 
@@ -87,7 +119,7 @@ Notable changes to DSH Mobile are recorded here. GitHub Releases remain the sour
87
119
 
88
120
  ## 0.3.5 - 2026-09-01
89
121
 
90
- - Fix [#26#26](https://github.com/saya-ch/dsh-mobile/issues/26): prevent mobile startup from remaining on “Loading plugins” over LAN or remote access when DSH sends the WebSocket upgrade response and initial snapshot together. The gateway now preserves that snapshot without relaxing its 16 KiB response-header limit. Thanks @oliverwan97 for the detailed report.
122
+ - Fix [#26](https://github.com/saya-ch/dsh-mobile/issues/26): prevent mobile startup from remaining on “Loading plugins” over LAN or remote access when DSH sends the WebSocket upgrade response and initial snapshot together. The gateway now preserves that snapshot without relaxing its 16 KiB response-header limit. Thanks @oliverwan97 for the detailed report.
91
123
 
92
124
  ## 0.3.4 - 2026-08-31
93
125
 
@@ -110,7 +142,7 @@ Notable changes to DSH Mobile are recorded here. GitHub Releases remain the sour
110
142
 
111
143
  ## 0.3.2 - 2026-08-29
112
144
 
113
- - Special thanks to @JackRushante for [#16#16](https://github.com/saya-ch/dsh-mobile/pull/16): the secure Android media bridge, image attachments, localization foundation, bounded extension requests, and Funnel lifecycle hardening. This release retains all four original commits and their author metadata.
145
+ - Special thanks to @JackRushante for [#16](https://github.com/saya-ch/dsh-mobile/pull/16): the secure Android media bridge, image attachments, localization foundation, bounded extension requests, and Funnel lifecycle hardening. This release retains all four original commits and their author metadata.
114
146
  - Move image selection and camera capture into a dedicated top row of the composer command menu, without focusing the message editor.
115
147
  - Push extension and `/mobile` changes to authenticated phones immediately, while retaining bounded polling as a network-recovery fallback.
116
148
  - Bind each mobile UI to its matching Host, script, style, and asset generation; retain the previous Host through a bounded refresh window, fail closed on client activation errors, and tighten scoped requests against encoded path traversal.
@@ -120,7 +152,7 @@ Notable changes to DSH Mobile are recorded here. GitHub Releases remain the sour
120
152
 
121
153
  ## 0.3.1 - 2026-08-28
122
154
 
123
- - Credit @BlueandwhiteXD ([#15#15](https://github.com/saya-ch/dsh-mobile/pull/15)) for the Android keyboard inset report and fix incorporated into the 0.3 mobile layout.
155
+ - Credit @BlueandwhiteXD ([#15](https://github.com/saya-ch/dsh-mobile/pull/15)) for the Android keyboard inset report and fix incorporated into the 0.3 mobile layout.
124
156
 
125
157
  ## 0.3.0 - 2026-08-28
126
158
 
package/README.en.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <h1 align="center">DSH Mobile</h1>
6
6
 
7
- <p align="center">Secure, live LAN access to DeepSeek Harness from a phone.</p>
7
+ <p align="center">Secure, live access to DeepSeek Harness from a phone.</p>
8
8
 
9
9
  <p align="center">
10
10
  <a href="https://www.npmjs.com/package/dsh-mobile"><img src="https://img.shields.io/npm/v/dsh-mobile?label=npm&amp;color=CB3837" alt="npm version"></a>
@@ -15,18 +15,29 @@
15
15
  <a href="https://github.com/awesome-dsh-plugin/awesome-dsh-plugin"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="Awesome DSH Plugin"></a>
16
16
  </p>
17
17
 
18
- <p align="center"><a href="README.md">简体中文</a> · <a href="CHANGELOG.md">Changelog</a></p>
18
+ <p align="center">
19
+ <a href="#what-it-does">What it does</a> ·
20
+ <a href="#quick-start">Quick start</a> ·
21
+ <a href="#connection-guide">Connection guide</a> ·
22
+ <a href="#extend-and-customize">Extend and customize</a> ·
23
+ <a href="#device-management">Device management</a> ·
24
+ <a href="#third-party-plugin-compatibility">Third-party plugins</a> ·
25
+ <a href="#security">Security</a> ·
26
+ <a href="#compatibility">Compatibility</a> ·
27
+ <a href="CHANGELOG.md">Changelog</a> ·
28
+ <a href="README.md">简体中文</a>
29
+ </p>
19
30
 
20
31
  > DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
21
32
  >
22
- > **0.3.16 update**: supports community task-board pane anchors, improves wide-screen rightbar docking and phone question cards, and fixes custom DSH Web ports still targeting the saved default upstream. [Details](CHANGELOG.md).
33
+ > **0.4.1 update**: adapts to DeepSeek Harness 0.1.6-alpha.1, fixes extension action requests and LAN route inspection, hardens admin CSRF checks, HTTP iframe warnings, and the frontend compatibility gate, and adds a complete English self-hosted FRP guide. [Details](CHANGELOG.md).
23
34
  >
24
- > **Upgrade reminder**: update the plugin to **0.3.16** and restart DSH. Existing pairings and app 0.3.15 remain compatible; the 0.3.16 APK changes only Android version metadata, so the app update is optional. [Compatibility notes](#compatibility).
35
+ > **Upgrade reminder**: the 0.4.1 plugin continues to work with the 0.4.0 Android app and existing devices do not need re-pairing. Install the 0.4.1 app as well if you want this Android build. [Compatibility notes](#compatibility).
25
36
 
26
37
  <p align="center">
27
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.16/dsh-mobile-android-v0.3.16.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
28
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.16/dsh-mobile-android-v0.3.16.apk"><strong>Download Android app 0.3.16</strong></a><br>
29
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.16">Release notes and checksums</a></sub>
38
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
39
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><strong>Download Android app 0.4.1</strong></a><br>
40
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.1">Release notes and checksums</a></sub>
30
41
  </p>
31
42
 
32
43
  DSH Mobile is a DeepSeek Harness plugin that lets a mobile browser or the Android app connect over a protected LAN or an optional Tailscale Funnel, cpolar, or self-hosted FRP remote path. Local and remote access keep the same sessions, Workspaces, messages, and tools while using separate switches and paired-device stores without modifying DeepSeek Harness source.
@@ -40,7 +51,7 @@ It also lets you customize the phone from a DSH conversation: `/mobile <what you
40
51
  - **Continue DSH work from a phone**: the same sessions, Workspaces, messages, and tools, in real time.
41
52
  - **Customize the phone UI by talking to DSH**: change the mobile layout, interactions, and features from a conversation; open pages refresh within seconds.
42
53
  - **A dedicated touch layout**: session drawer, tool details, settings, question cards, and composer reorganized for phones. Native app screens follow the Android system locale in Simplified Chinese, English, or Italian. Plugin-owned Web UI follows DSH's selected locale; Italian resources are ready for a future DSH Italian locale.
43
- - **Image attachments**: use the top row of the composer plus menu to select an image or take a photo; PNG, JPEG, WebP, and GIF files up to 8 MiB are supported, plus full-resolution JPEG capture.
54
+ - **Image attachments**: file selection uses DSH's native **Add** group; DSH Mobile only adds **Take photo** to that group, and captured images follow DSH's native attachment flow.
44
55
  - **Auto-discovery, no re-pairing**: Wi-Fi, hotspot, or IP changes normally recover automatically.
45
56
  - **One-click connection diagnostics**: check versions, gateway, network interface, firewall, and the remote path; stable reason codes are localized in the UI, and the copied report excludes credentials and complete addresses.
46
57
  - **One-click approval for third-party plugin WebSockets**: the diagnostics view groups blocked plugin connections by directory (with attempt counts); allowing a path unblocks that exact path while everything unapproved stays blocked, and a red badge marks the sidebar entry until reviewed (#47). If a plugin keeps failing to connect (for example a terminal reporting 1006), first look at the diagnostics view for blocked connections and approve them in one click — manual configuration is usually unnecessary.
@@ -74,13 +85,13 @@ Or via the plugin market (optional):
74
85
  dsh plugin --profile web add dshmarket
75
86
  ```
76
87
 
77
- Restart DSH, then search for **dsh-mobile** under **Settings → Plugin Market** and install it with one click.
88
+ Restart DSH, then search for **dsh-mobile** under **Settings → Plugin Market** and install it. On first opening Mobile access, the Local network page lists this computer's current networks; confirm one to create private certificates and LAN configuration, then restart DSH once as prompted. No terminal `setup` command is required for this path.
78
89
 
79
90
  `setup` automatically selects and remembers the current LAN; Wi-Fi, hotspot, and IP changes normally recover without re-pairing. Use `--address 192.168.x.x` only when automatic selection fails. Settings, certificates, devices, and customization files live under `$DSH_HOME/mobile-access/`.
80
91
 
81
92
  After installation, start DSH and use the connection guide below to choose LAN or remote access.
82
93
 
83
- Registry-installed plugins check for updates when the desktop UI loads and show “Update plugin” beside the access-panel title when a newer release is available. Restart DSH after installation. The app download entry shows the latest version; local development packages are not overwritten, and Android does not send update notifications.
94
+ Registry-installed plugins check for updates when the desktop UI loads and show “Update plugin” beside the access-panel title when a newer release is available. Restart DSH after installation. The app download entry shows the latest version; local development packages are not overwritten, and Android does not check for or push app-version updates.
84
95
 
85
96
  ## Connection guide
86
97
 
@@ -101,8 +112,12 @@ Use this when the phone and computer share Wi-Fi, Ethernet, or a phone hotspot.
101
112
 
102
113
  Port note: `dsh web --port` changes the DSH Web upstream port (3080 by default), which the plugin follows automatically. `dsh-mobile setup --port` changes the Mobile HTTPS listener (3443 by default), and the pairing QR code includes the selected port.
103
114
 
115
+ Headless Linux hosts, and browsers that open DSH Web through a LAN IP or reverse proxy, can use the same **Mobile access** control in the lower-left corner. The admin API still requires a loopback TCP peer (for example a local `socat` or reverse proxy to `127.0.0.1`) so the plugin itself is not LAN-exposed. The browser Host may be `localhost`, RFC1918, or an IPv4 link-local address; public IPs and arbitrary DNS names still return 403. The reverse proxy must be limited to trusted local or LAN callers and must not publicly forward `/api/mobile-access`. The dedicated Mobile HTTPS listener (3443 by default) remains the phone surface and does not become the desktop admin panel.
116
+
104
117
  The app is optional: select **Copy pairing link** and open it in a mobile browser. The browser must manually trust the plugin certificate on the first visit.
105
118
 
119
+ Browser pairing and reauthentication pages use the browser's `Accept-Language` to show Simplified Chinese, English, or Italian. Android screens follow the system language, while the DSH plugin control panel follows the language selected by DSH.
120
+
106
121
  ### Remote access
107
122
 
108
123
  Use this after the phone leaves the computer's network. Remote access is disabled by default, and the phone needs no separate Tailscale, cpolar, or FRP app.
@@ -116,12 +131,12 @@ Remote providers may impose bandwidth and connection limits: the [cpolar Free pl
116
131
  1. Open **Mobile Access → Remote** in the lower-left corner of DeepSeek Harness and choose a provider:
117
132
  - **Tailscale Funnel**: select **Enable remote access**, complete the one-time Tailscale sign-in on the official page, follow the panel prompt to allow Funnel, then return to DSH and wait until the connection is ready.
118
133
  - **cpolar**: select **Install official component**, sign in to the cpolar dashboard and obtain an Authtoken, paste it, then select **Save and connect**. The component is downloaded into the plugin's private directory only after confirmation; free temporary addresses may change after DSH or cpolar restarts.
119
- - **Self-hosted FRP (advanced)**: expand **Self-hosted connection**, enter the VPS, frps port, shared token, and public HTTPS origin. The origin may use your domain or the VPS public IPv4 address (for example, `https://203.0.113.10` — substitute your own real address; documentation ranges are rejected). Apply the restricted template manually or enter an SSH user, port, and local private-key path for automatic deployment. Automatic deployment supports Ubuntu/Debian with systemd, uses OpenSSH keys or an agent, refuses password auth, and does not overwrite Caddy configuration it does not manage; both deployment and server cleanup display the SSH host keys for verification against the VPS console before continuing. IPv4 mode obtains a roughly six-day Let's Encrypt IP certificate and installs daily automatic renewal. Install the official `frpc` on demand and verify the path afterward. A reviewable uninstall script or one-click server cleanup removes only DSH Mobile-owned services and configs. This requires Android app 0.3.3 or later.
134
+ - **Self-hosted FRP (advanced)**: expand **Self-hosted connection**, enter the VPS, frps port, shared token, and public HTTPS origin. The origin may use your domain or the VPS public IPv4 address (for example, `https://203.0.113.10` — substitute your own real address; documentation ranges are rejected). Apply the restricted template manually or enter an SSH user, port, and local private-key path for automatic deployment. Automatic deployment supports Ubuntu/Debian with systemd, uses OpenSSH keys or an agent, refuses password auth, and does not overwrite Caddy configuration it does not manage; both deployment and server cleanup display the SSH host keys for verification against the VPS console before continuing. IPv4 mode obtains a roughly six-day Let's Encrypt IP certificate and installs daily automatic renewal. Install the official `frpc` on demand and verify the path afterward. A reviewable uninstall script or one-click server cleanup removes only DSH Mobile-owned services and configs. This requires Android app 0.3.3 or later. See the [English self-hosted FRP guide](docs/SELF_HOSTED_FRP.en.md) for the complete procedure.
120
135
  2. When the panel reports that remote access is ready, select **Create remote pairing QR code**.
121
136
  3. In the Android app, open **Remote access** and scan the QR code to create its separate pairing.
122
137
  4. The app saves the current address and device credential for automatic reconnection. If a free cpolar address changes, scan the computer's current remote QR code to verify the connection again; clearing app data is unnecessary. A stored device token is sent only to its exact saved Origin, never to a new QR-code domain.
123
138
 
124
- > **Remote notifications**: browser notification permission is granted per origin, so allow it separately for the remote address; OS-level toasts only appear on the computer, never on the phone. To push task completion to the phone, use a third-party channel (e.g. dsh-messager's Feishu/WeCom/Telegram push), which is delivered server-side and unaffected by the gateway.
139
+ > **Remote notifications**: browser `Notification` permission is granted per Origin, and a web-page system toast appears only on the device running that page. Android task reminders are a separate 0.4.0 feature: enable them from the app's foreground menu, and keep the WebView page alive; they are not a general background push service. For reliable background delivery, use a server-side webhook or bot channel you have configured.
125
140
 
126
141
  Tailscale Funnel has broad reach but may be unreliable from mainland China. Its runtime ties the public listener to the parent process and a bounded control channel; parent exit, channel closure, or an explicit stop ends the current generation and cleans up its resources. cpolar is better suited to mainland networks, while self-hosted FRP fits users who already have a VPS and want to avoid public-provider bandwidth quotas. An unregistered domain on a mainland-China VPS may be intercepted by the cloud provider; public IPv4 mode avoids that dependency. The plugin validates pinned on-demand components, stores their configuration and programs entirely under `$DSH_HOME/mobile-access/`, and can remove them completely from the panel.
127
142
 
@@ -147,6 +162,8 @@ Two kinds of changes are supported: the phone UI itself (theme, layout, buttons)
147
162
 
148
163
  Extension manifests, scripts, styles, and assets are revisioned. When the plugin observes a `/mobile` or extension-file change, it notifies authenticated phones to refresh immediately; 45-second visible and 5-minute hidden checks remain only as recovery fallbacks. A failed Host staging pass keeps the current version; if the Host has changed but the new phone UI cannot activate, that extension closes and retries instead of mixing generations.
149
164
 
165
+ An extension action's `input` may use a callable Schemastery schema such as `api.schema.object(...)` or an adapter with `parse(value)`; mobile `api.host.invoke()` sends JSON explicitly, and the input is validated and normalized before the computer-side action runs.
166
+
150
167
  <sub>You can even use an extension to connect to SillyTavern running on the same computer, give it a lightweight mobile frontend, and open it from the same app.</sub>
151
168
 
152
169
  > `host.mjs` has the same privileges as a local program. Create and run only computer-side extensions that you understand and trust.
@@ -160,6 +177,56 @@ The examples above, applied:
160
177
  <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/cyberpunk-monitor-1.png" width="22%" style="margin-left:8px" alt="Mobile UI customized into a cyberpunk computer monitor">
161
178
  </p>
162
179
 
180
+ ### Device management
181
+
182
+ The Android app keeps LAN, cpolar, Tailscale Funnel, and self-hosted FRP pairings in one **Paired computers** list. The first upgrade migrates the legacy LAN and remote credentials without requiring another pairing; when an address changes, the app merges the row by the DSH installation's stable `instanceId` and keeps its custom name. Device tokens and LAN CAs remain encrypted by Android Keystore and never appear in the list or QR code.
183
+
184
+ Each row shows its custom name, transport, Origin, live reachability, and last connection time. A green dot means **Reachable**; a gray dot means **Checking**, **Temporarily unreachable**, **Pairing expired**, or **Removed on computer**. The check validates the DSH Gateway over HTTPS instead of using ICMP, so a temporary network outage is not mistaken for computer-side revocation.
185
+
186
+ - **Startup behavior → Open DSH directly** (default): one device connects directly; with multiple devices, the app tries the last-used device first, then the still-valid device with the most recent connection. A bounded connection budget returns to the list instead of spinning forever.
187
+ - **Startup behavior → Show device list**: choose a computer on every launch, which is useful when switching between several machines. The option is in the list's top-right settings button and is saved immediately.
188
+ - Tap a row to connect. The overflow button and long press open the same action sheet for rename, check now, pair again, or delete the local record. Deletion has a second confirmation and a short undo window; undo restores only the local row and never restores a computer-side revocation.
189
+ - Open DSH **Settings → General** in the WebView and select **Switch computer** to return to the paired-device list; this action appears only in the Android app. If the computer revokes a device, the app keeps its row as **Removed on computer**, stops automatic reconnection, and offers **Pair again** or **Delete device**.
190
+
191
+ <table>
192
+ <tr>
193
+ <td align="center" valign="top" width="50%">
194
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/device-management.jpg" width="44%" alt="Paired computer list in the Android app"><br>
195
+ <sub>Device management: paired computers, transport, and reachability</sub>
196
+ </td>
197
+ <td align="center" valign="top" width="50%">
198
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/startup-behavior.jpg" width="44%" alt="Startup behavior settings in the Android app"><br>
199
+ <sub>Startup behavior: open DSH directly or show the device list</sub>
200
+ </td>
201
+ </tr>
202
+ </table>
203
+
204
+ ### Third-party plugin compatibility
205
+
206
+ The mobile adaptation keeps DSH's existing Workspace, task-management, terminal, and file-panel entry points instead of isolating third-party plugin content in a separate page. The wide-layout screenshot below shows the Android app in a wide viewport. The app adapts to the available width: phones use drawers and overlays, while wide screens use side-by-side panels; both layouts expose the same features and connection methods. DSH still loads third-party plugins itself—the mobile layer only adapts layout and access, without modifying DeepSeek Harness source.
207
+
208
+ Compatibility and WebSocket rules:
209
+
210
+ Proxied pages allow HTTP frames for compatibility with some community plugins; those pages are unencrypted and can be altered, and browsers may still block them as mixed content. Use HTTPS for sensitive work. The same warning appears at the top of the remote panel when it is opened over HTTPS.
211
+
212
+ - The released 0.4.0 is contract-checked against DSH `0.1.5-rc.2` (renderer-v2) and retains the `0.1.5-rc.1` LAN verification. The DSH page must expose the standard session, `main`/`panelInfo`, and `rightbar` slots; the community plugin must register its panel or sidebar content through DSH's standard entry points.
213
+ - The gateway allows first-party DSH WebSocket paths by default, including `/sidebar/ws/terminal`. Other paths used by community sidebar plugins are blocked by default and appear in Diagnostics; the `/sidebar/ws/agent-opens` and `/sidebar/ws/agent-terminals` paths in the image are examples that must be reviewed for the actual plugin.
214
+ - In **Connection diagnostics → Third-party WebSocket paths**, select **Allow** only for an exact path you have verified. Query strings and fuzzy prefixes are rejected; **Allow all** is not recommended. Approved paths can be removed at any time, and the same policy applies to LAN and remote connections.
215
+ - Approval only lets that path pass through the authenticated, same-origin DSH Mobile gateway. It does not open arbitrary TCP/UDP ports or bypass device pairing. If a community plugin still fails, check the path recorded by Diagnostics and approve one path at a time.
216
+
217
+ <table>
218
+ <tr>
219
+ <td align="center" valign="top" width="50%">
220
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/third-party-plugin-adaptation.png" width="96%" alt="Android app wide layout with a community sidebar plugin adapted"><br>
221
+ <sub>Community sidebar plugin compatibility in the Android app</sub>
222
+ </td>
223
+ <td align="center" valign="top" width="50%">
224
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/websocket-diagnostics.png" width="96%" alt="Third-party WebSocket path diagnostics in the Android app"><br>
225
+ <sub>Connection diagnostics: review and allow third-party WebSocket paths</sub>
226
+ </td>
227
+ </tr>
228
+ </table>
229
+
163
230
  ## App or mobile browser
164
231
 
165
232
  | Client | Best for | Notes |
@@ -203,7 +270,8 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
203
270
 
204
271
  | DSH Mobile plugin | Verified DeepSeek Harness version |
205
272
  | --- | --- |
206
- | `0.3.15`, `0.3.16` | `0.1.5-rc.2` (contract check); `0.1.5-rc.1` (@idoall LAN verification) |
273
+ | `0.4.1` | `0.1.6-alpha.1` (local source and renderer-v2 contract check) |
274
+ | `0.3.15`, `0.3.16`, `0.4.0` | `0.1.5-rc.2` (contract check); `0.1.5-rc.1` (@idoall LAN verification) |
207
275
  | `0.3.14` | `0.1.3-alpha.2` |
208
276
  | `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
209
277
  | `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
@@ -211,7 +279,7 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
211
279
  | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
212
280
  | `0.1.4`, `0.2.x` | `0.1.1-rc.2` |
213
281
 
214
- Existing 0.3.3–0.3.16 apps do not need re-pairing. cpolar users should use app 0.3.15 or later because earlier apps may time out before a slow first load over the free route finishes; earlier apps also use a different status-bar strategy. App 0.1.3 or earlier requires reinstalling and pairing again.
282
+ Existing 0.3.3–0.4.0 apps do not need re-pairing. cpolar users should use app 0.3.15 or later because earlier apps may time out before a slow first load over the free route finishes; earlier apps also use a different status-bar strategy. The 0.4.0 app adds the multi-device list, startup behavior, and computer-side revocation status; older apps continue to connect to their saved single device. App 0.1.3 or earlier requires reinstalling and pairing again.
215
283
 
216
284
  ## Uninstall
217
285
 
package/README.md CHANGED
@@ -20,20 +20,24 @@
20
20
  <a href="#快速开始">快速开始</a> ·
21
21
  <a href="#连接教程">连接教程</a> ·
22
22
  <a href="#扩展与自定义">扩展与自定义</a> ·
23
+ <a href="#设备管理">设备管理</a> ·
24
+ <a href="#第三方插件适配">第三方插件适配</a> ·
25
+ <a href="#安全">安全</a> ·
26
+ <a href="#兼容性">兼容性</a> ·
23
27
  <a href="CHANGELOG.md">更新记录</a> ·
24
28
  <a href="README.en.md">English</a>
25
29
  </p>
26
30
 
27
31
  > DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
28
32
  >
29
- > **0.3.16 更新**:兼容社区任务看板的移动布局锚点,优化宽屏右栏与手机提问卡片,并修复自定义 DSH Web 端口仍连接旧默认端口的问题。[详细记录](CHANGELOG.md)。
33
+ > **0.4.1 更新**:适配 DeepSeek Harness 0.1.6-alpha.1,修复扩展动作请求和局域网路由检测,强化管理请求 CSRF、HTTP iframe 警告与前端兼容性检查,并补齐中英文 FRP 文档。[详细记录](CHANGELOG.md)。
30
34
  >
31
- > **升级提醒**:建议将插件升级至 **0.3.16** 并重启 DSH;现有配对与 0.3.15 App 保持兼容,本次 Android App 仅同步版本号,可按需更新。[兼容说明](#兼容性)。
35
+ > **升级提醒**:0.4.1 插件可继续使用 0.4.0 Android App;已有设备无需重新配对。若要使用本次 Android 构建,请同时安装 0.4.1 App。[兼容说明](#兼容性)。
32
36
 
33
37
  <p align="center">
34
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.16/dsh-mobile-android-v0.3.16.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
35
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.16/dsh-mobile-android-v0.3.16.apk"><strong>下载 Android App 0.3.16</strong></a><br>
36
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.16">版本说明与校验文件</a></sub>
38
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
39
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.1/dsh-mobile-android-v0.4.1.apk"><strong>下载 Android App 0.4.1</strong></a><br>
40
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.1">版本说明与校验文件</a></sub>
37
41
  </p>
38
42
 
39
43
  DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
@@ -47,7 +51,7 @@ DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App
47
51
  - **在手机上继续电脑端的工作**:同一份会话、工作区、消息和工具,实时同步。
48
52
  - **用对话定制手机端**:直接在 DSH 对话里改手机页面的布局、交互和功能,几秒内刷新。
49
53
  - **专属触屏布局**:会话抽屉、工具详情、设置、提问卡片和输入栏都按手机重新组织。App 原生页面跟随系统显示简体中文、英文或意大利文;插件界面跟随 DSH 的语言设置,意大利语资源已为 DSH 后续支持预留。
50
- - **图片附件**:在已打开会话的输入栏加号菜单顶部选择图片或拍照;支持 PNG、JPEG、WebP、GIF(不超过 8 MiB)和完整分辨率 JPEG。
54
+ - **图片附件**:文件选择使用 DSH 原生“添加”组;DSH Mobile 只在该组补充“拍照”,拍摄结果按 DSH 原生附件流程发送。
51
55
  - **自动发现、无需重新配对**:切换 Wi-Fi、热点或 IP 后通常自动恢复。
52
56
  - **一键连接诊断**:检查版本、网关、网卡、防火墙和远程通道;稳定的原因码在界面中本地化,并生成不含凭据与完整地址的脱敏报告。
53
57
  - **第三方插件 WebSocket 一键放行**:诊断页按目录分组记录被拦截的插件连接(含次数),点允许即放行确切路径,未批准的一律拦截;有新拦截时侧栏红点提醒(#47)。若某插件的连接一直失败(如终端报 1006),先到诊断页看看有没有被拦的连接,一键放行即可,通常无需手动配置。
@@ -81,13 +85,13 @@ pnpm dsh --profile web
81
85
  dsh plugin --profile web add dshmarket
82
86
  ```
83
87
 
84
- 重启 DSH 后,在 **设置 → 插件市场** 里搜索 dsh-mobile,一键安装即可。
88
+ 重启 DSH 后,在 **设置 → 插件市场** 里搜索 dsh-mobile 并安装。首次打开“移动访问”时,局域网页会列出电脑当前网络;确认网卡后由插件生成私有证书并配置局域网,按提示重启一次 DSH 即可使用,无需再打开终端运行 `setup`。
85
89
 
86
90
  `setup` 会自动选择并记住当前局域网,切换 Wi-Fi、热点或 IP 后通常自动恢复;仅在自动选择失败时使用 `--address 192.168.x.x`。设置、证书、设备和自定义文件保存在 `$DSH_HOME/mobile-access/`。
87
91
 
88
92
  安装并启动 DSH 后,按照下一节选择局域网或远程连接。
89
93
 
90
- 通过 npm 安装的插件会在桌面界面加载时检查新版本,有更新时在访问面板标题右侧显示“更新插件”,安装后需重启 DSH。App 下载入口展示最新版本;本地开发包不会被自动覆盖,Android App 暂无主动更新通知。
94
+ 通过 npm 安装的插件会在桌面界面加载时检查新版本,有更新时在访问面板标题右侧显示“更新插件”,安装后需重启 DSH。App 下载入口展示最新版本;本地开发包不会被自动覆盖,Android App 不会主动检查或推送版本更新。
91
95
 
92
96
  ## 连接教程
93
97
 
@@ -108,8 +112,12 @@ dsh plugin --profile web add dshmarket
108
112
 
109
113
  端口说明:`dsh web --port` 修改 DSH Web 上游端口(默认 3080),插件会自动跟随;`dsh-mobile setup --port` 修改 Mobile HTTPS 监听端口(默认 3443),配对二维码会包含实际端口。
110
114
 
115
+ 无图形界面的 Linux 主机,或通过局域网 IP / 反向代理打开 DSH Web 时,左下角 **移动访问** 管理口同样可用。管理 API 仍要求 TCP 对端是本机回环(例如本机 `socat` / 反向代理连到 `127.0.0.1`),不会把插件自己暴露到公网;浏览器 Host 可以是 `localhost`、RFC1918 或 IPv4 链路本地地址,公网 IP 和任意域名仍会返回 403。反向代理必须只对可信的本机或内网请求开放,不能把 `/api/mobile-access` 管理路径公开转发到互联网。手机走的独立 HTTPS 入口(默认 3443)仍是移动端界面,不会变成桌面管理口。
116
+
111
117
  不安装 App 也可以访问:点击 **复制配对链接**,在手机浏览器中打开;首次访问需要按浏览器提示手动信任插件证书。
112
118
 
119
+ 手机浏览器中的配对和重新连接页面会按浏览器的 `Accept-Language` 显示简体中文、英文或意大利文;Android App 则跟随系统语言。DSH 内的插件控制面板继续跟随 DSH 当前语言。
120
+
113
121
  ### 远程访问
114
122
 
115
123
  适合手机离开电脑所在网络后使用。远程访问默认关闭,手机不需要另外安装 Tailscale、cpolar 或 FRP。
@@ -123,12 +131,12 @@ dsh plugin --profile web add dshmarket
123
131
  1. 在 DeepSeek Harness 左下角打开 **移动访问 → 远程**,选择一种连接方式:
124
132
  - **Tailscale Funnel**:点击 **启用远程访问**,在打开的官方页面完成一次 Tailscale 登录;按面板提示继续允许 Funnel,然后返回 DSH 等待连接就绪。
125
133
  - **cpolar**:点击 **安装官方组件**,登录 cpolar 控制台取得 Authtoken,粘贴后点击 **保存并连接**。组件只会在确认后下载到插件私有目录;免费临时地址可能在 DSH 或 cpolar 重启后变化。
126
- - **自建 FRP(高级)**:展开 **自建连接**,填写 VPS、frps 端口、共享 Token 和公开 HTTPS 地址;公开地址可以是自己的域名,也可以直接是 VPS 公网 IPv4(例如 `https://203.0.113.10`,请换成你自己的真实地址,文档示例网段会被拒绝)。可以复制受限模板手动部署,也可以填写 SSH 用户、SSH 端口和本机私钥路径,点击 **部署 frps + Caddy** 自动部署。自动部署支持 Ubuntu/Debian + systemd,使用 OpenSSH 密钥或 ssh-agent,不接受密码,也不会覆盖非 DSH Mobile 管理的 Caddyfile;部署与清理前都会展示服务器主机指纹,需到 VPS 控制台核对后才能继续。公网 IP 模式会申请约 6 天有效的 Let’s Encrypt IP 证书并配置每日自动续期。部署完成后再安装官方 `frpc` 并验证连接。不再需要服务器时可用“复制 VPS 卸载脚本”或一键清理,只删除 DSH Mobile 自己的服务与配置。需要 Android App 0.3.3 或更高版本。详见[自建 FRP 使用指南](docs/SELF_HOSTED_FRP.md)。
134
+ - **自建 FRP(高级)**:展开 **自建连接**,填写 VPS、frps 端口、共享 Token 和公开 HTTPS 地址;公开地址可以是自己的域名,也可以直接是 VPS 公网 IPv4(例如 `https://203.0.113.10`,请换成你自己的真实地址,文档示例网段会被拒绝)。可以复制受限模板手动部署,也可以填写 SSH 用户、SSH 端口和本机私钥路径,点击 **部署 frps + Caddy** 自动部署。自动部署支持 Ubuntu/Debian + systemd,使用 OpenSSH 密钥或 ssh-agent,不接受密码,也不会覆盖非 DSH Mobile 管理的 Caddyfile;部署与清理前都会展示服务器主机指纹,需到 VPS 控制台核对后才能继续。公网 IP 模式会申请约 6 天有效的 Let’s Encrypt IP 证书并配置每日自动续期。部署完成后再安装官方 `frpc` 并验证连接。不再需要服务器时可用“复制 VPS 卸载脚本”或一键清理,只删除 DSH Mobile 自己的服务与配置。需要 Android App 0.3.3 或更高版本。详见 [自建 FRP 使用指南](docs/SELF_HOSTED_FRP.md)。
127
135
  2. 状态变为“远程访问已就绪”后,点击 **生成远程配对二维码**。
128
136
  3. 在 Android App 中进入 **远程访问**,扫描二维码完成独立配对。
129
137
  4. 此后 App 会保存当前地址和设备凭据并自动重连。若 cpolar 免费临时地址发生变化,请扫描电脑端当前远程二维码重新验证连接;无需清除 App 数据。旧设备 token 只会发送到原先保存的精确 Origin,不会发送给二维码中的新域名。
130
138
 
131
- > **远程通知说明**:浏览器通知权限按地址分别授权,远程地址需在浏览器中单独允许;系统级弹窗只出现在电脑上,手机收不到。任务完成要推送到手机时,请使用第三方通道(如 dsh-messager 的飞书/企业微信/Telegram 推送),它们走服务端下发,不受网关影响。
139
+ > **远程通知说明**:浏览器的 `Notification` 权限按 Origin 分别授权,网页系统通知只显示在运行该网页的设备上。Android App 的任务提醒是独立的 0.4.0 功能,需要在 App 前台菜单中主动开启,且依赖 WebView 页面仍存活;它不是通用的后台推送。需要可靠的后台推送时,请使用你已配置的服务端 webhook 或机器人通道。
132
140
 
133
141
  Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。其运行组件把公开监听生命周期绑定到父进程和受限控制通道;父进程退出、控制通道关闭或显式停止时会结束当前代次并清理资源。cpolar 更适合国内网络;自建 FRP 适合已有 VPS、希望避开公共服务带宽限制的用户。中国大陆 VPS 上的未备案域名可能被云厂商拦截,此时可使用公网 IPv4 模式。插件会校验按需下载的固定版本组件,配置与程序均保存在 `$DSH_HOME/mobile-access/`,可随时在面板中彻底清除。
134
142
 
@@ -154,7 +162,9 @@ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。
154
162
 
155
163
  扩展清单及其脚本、样式和资源按版本标识刷新。插件监听到 `/mobile` 或扩展文件变化后,会通过已认证连接通知手机立即更新;页面可见时每 45 秒、隐藏时每 5 分钟的检查只作为断线兜底。Host 暂存失败会继续使用现有版本;若 Host 已更新但新手机界面激活失败,则关闭该扩展并自动重试,避免混用新旧能力。
156
164
 
157
- <sub>你甚至可以通过扩展连接电脑上运行的酒馆(</sub>
165
+ 扩展动作的 `input` 可以直接使用 `api.schema.object(...)` 等 Schemastery schema,也可以使用带 `parse(value)` 的适配器;手机端 `api.host.invoke()` 会按 JSON 请求发送,输入会在电脑端动作执行前完成校验和规范化。
166
+
167
+ <sub>你甚至可以通过扩展连接电脑上运行的酒馆,并从同一 App 打开它的简易移动前端。</sub>
158
168
 
159
169
  > `host.mjs` 与本机程序拥有相同权限;仅创建和运行你理解并信任的电脑端扩展。
160
170
 
@@ -167,6 +177,56 @@ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。
167
177
  <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/cyberpunk-monitor-1.png" width="22%" style="margin-left:8px" alt="/mobile 定制为赛博朋克监控面板">
168
178
  </p>
169
179
 
180
+ ### 设备管理
181
+
182
+ Android App 将局域网、cpolar、Tailscale Funnel 和自建 FRP 统一整理到“已配对设备”列表。首次升级会自动迁移旧版局域网与远程凭据,不要求重新配对;地址变化时按 DSH 安装的稳定 `instanceId` 合并原记录,保留自定义名称。设备 Token 和局域网 CA 继续由 Android Keystore 加密保存,不会显示在列表或二维码中。
183
+
184
+ 每条记录显示自定义名称、连接方式、Origin、实时可达状态和最近连接时间。绿色状态点表示“可达”,灰色状态点表示“检测中”“暂不可达”“配对已过期”或“电脑端已移除”;可达性检查直接验证 DSH Gateway,不依赖 ICMP,也不会把暂时断网误判成电脑端撤销。
185
+
186
+ - **启动时打开 → 直接进入 DSH**(默认):单设备直接连接;多设备优先连接上次使用的设备,其次按最近连接时间选择仍有效的设备。连接超过有限重试预算后自动回到列表,不会无限转圈。
187
+ - **启动时打开 → 显示设备列表**:每次启动先选择电脑,适合经常在多台设备之间切换。该选项位于列表右上角的设置按钮中,修改后立即保存。
188
+ - 点按设备行可连接;右侧“…”和长按提供相同的操作面板,可编辑名称、立即检测、重新配对或删除本地记录。删除前会二次确认,并提供短暂撤销;撤销只恢复本机记录,不恢复电脑端已经撤销的授权。
189
+ - 在 WebView 页面打开 DSH **设置 → 通用**,选择 **切换电脑** 可回到已配对设备列表;该动作仅在 Android App 中显示。电脑端撤销设备后,App 保留该条目并显示“电脑端已移除”,停止自动重连,同时提供 **重新配对** 和 **删除本地记录**。
190
+
191
+ <table>
192
+ <tr>
193
+ <td align="center" valign="top" width="50%">
194
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/device-management.jpg" width="44%" alt="Android App 已配对设备列表"><br>
195
+ <sub>设备管理列表:查看已配对电脑、连接方式和可达状态</sub>
196
+ </td>
197
+ <td align="center" valign="top" width="50%">
198
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/startup-behavior.jpg" width="44%" alt="Android App 启动行为设置"><br>
199
+ <sub>启动行为设置:选择直接进入 DSH 或显示设备列表</sub>
200
+ </td>
201
+ </tr>
202
+ </table>
203
+
204
+ ### 第三方插件适配
205
+
206
+ 移动适配保持 DSH 原有的工作区、任务管理、终端和文件面板入口,不会把第三方插件内容隔离成另一套页面。下面的宽屏截图展示 Android App 在宽屏下的布局。App 会根据屏幕宽度自适应:手机使用抽屉和浮层,宽屏使用并排面板;两种布局共享相同的功能和连接方式。第三方插件仍由 DSH 自己加载,移动层负责适配布局与连接,不修改 DeepSeek Harness 源码。
207
+
208
+ 兼容条件与 WebSocket 放行规则:
209
+
210
+ 代理页面为兼容部分社区插件允许嵌入 HTTP 页面;这类内容未加密,可能被篡改,浏览器也可能因混合内容策略拦截。处理敏感内容时请使用 HTTPS。通过 HTTPS 管理入口打开远程面板时,页面顶部会显示相同提醒。
211
+
212
+ - 已发布的 0.4.0 按 DSH `0.1.5-rc.2` 做过 renderer-v2 合同检查,并保留对 `0.1.5-rc.1` 局域网路径的验证。DSH 页面需要提供标准的会话、`main`/`panelInfo` 和 `rightbar` 插槽;插件自身需要通过 DSH 的标准面板或侧边栏入口注册内容。
213
+ - 网关默认只允许 DSH 内置的第一方 WebSocket 路径。社区侧边栏插件使用的其他路径默认拦截,通常会在诊断页显示为待处理项目;截图中的`/sidebar/ws/agent-opens` 和`/sidebar/ws/agent-terminals` 就属于这类需要按实际插件确认的路径。
214
+ - 在 **连接诊断 → 第三方 WebSocket 路径** 中,只对确认过的精确路径点击 **允许**。系统不接受带查询字符串或模糊前缀的路径;不建议使用“全部允许”。已允许的路径可以随时移除,局域网和远程连接使用同一套规则。
215
+ - 放行只代表该路径可以通过已认证、同源的 DSH Mobile 网关,不会开放任意 TCP/UDP 端口,也不会绕过设备配对。若社区插件仍然连接失败,先看诊断页的实际拦截路径,再按一条路径放行。
216
+
217
+ <table>
218
+ <tr>
219
+ <td align="center" valign="top" width="50%">
220
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/third-party-plugin-adaptation.png" width="96%" alt="Android App 宽屏布局与社区侧边栏插件适配"><br>
221
+ <sub>Android App 下社区侧边栏插件的兼容</sub>
222
+ </td>
223
+ <td align="center" valign="top" width="50%">
224
+ <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/websocket-diagnostics.png" width="96%" alt="Android App 第三方 WebSocket 路径诊断"><br>
225
+ <sub>连接诊断:检查第三方 WebSocket 路径并按需放行</sub>
226
+ </td>
227
+ </tr>
228
+ </table>
229
+
170
230
  ## App 与手机浏览器
171
231
 
172
232
 
@@ -210,17 +270,19 @@ flowchart LR
210
270
 
211
271
  下表列出各插件版本验证支持到的 DeepSeek Harness 版本(早于该版本的 0.1.x 均兼容)。0.3.6 起插件不再按版本号拒绝启动,未列出的更新版本由 CI 契约检查兜底。历史记录见 [CHANGELOG.md](CHANGELOG.md)。
212
272
 
213
- | DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
214
- | --- | --- |
215
- | `0.3.15`、`0.3.16` | `0.1.5-rc.2`(契约检查);`0.1.5-rc.1`(@idoall 局域网实测) |
216
- | `0.3.14` | `0.1.3-alpha.2` |
217
- | `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
218
- | `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
219
- | `0.3.4`、`0.3.5` | `0.1.2-alpha.2` |
220
- | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
221
- | `0.1.4`、`0.2.x` | `0.1.1-rc.2` |
222
-
223
- 现有 0.3.3–0.3.16 App 无需重新配对;cpolar 用户应使用 0.3.15 或更新 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.1.3 及更早版本需卸载重装并重新配对。
273
+
274
+ | DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
275
+ | ----------------------------------------- | -------------------------------------------------------------- |
276
+ | `0.4.1` | `0.1.6-alpha.1`(本机源码与 renderer-v2 契约检查) |
277
+ | `0.3.15`、`0.3.16`、`0.4.0` | `0.1.5-rc.2`(契约检查);`0.1.5-rc.1`(@idoall 局域网实测) |
278
+ | `0.3.14` | `0.1.3-alpha.2` |
279
+ | `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
280
+ | `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
281
+ | `0.3.4`、`0.3.5` | `0.1.2-alpha.2` |
282
+ | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
283
+ | `0.1.4`、`0.2.x` | `0.1.1-rc.2` |
284
+
285
+ 现有 0.3.3–0.4.0 App 无需重新配对;cpolar 用户应使用 0.3.15 或更新 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.4.0 才支持多设备列表、启动行为设置和电脑端撤销状态同步;旧版 App 仍可连接已保存的单台设备。App 0.1.3 及更早版本需卸载重装并重新配对。
224
286
 
225
287
  ## 卸载
226
288
 
package/SECURITY.md CHANGED
@@ -16,6 +16,7 @@ The maintainer will acknowledge a complete report within seven days. Publication
16
16
 
17
17
  - Keep the ordinary DSH Web listener on loopback.
18
18
  - Expose only the plugin-owned HTTPS listener to the LAN.
19
+ - The desktop admin API may accept an RFC1918 or IPv4 link-local Host only when the TCP peer is loopback, for a trusted local reverse proxy or headless host. Do not publicly forward `/api/mobile-access`; Host and loopback checks are not a replacement for proxy access control. Mutating admin requests must carry a same-origin `Origin` header.
19
20
  - DNS-SD/mDNS, periodic UDP announcements, active UDP query replies, and HTTPS discovery return only the device name, public HTTPS origin, port, protocol version, and stable non-secret installation identifier. Discovery never returns the CA, a pairing key, a device token, Cookies, credentials, or private configuration.
20
21
  - For LAN pairing, only after a user selects a device and enters the fingerprint-bound pairing key may Android fetch the public CA from that exact HTTPS origin. The bootstrap GET sends no key or credential. The app retains the CA in its encrypted credential record and never adds it to Android's system trust settings. Native requests use a private trust store; WebView accepts only the otherwise-untrusted leaf signed by that CA, for the exact origin and validity period. Every other TLS error is cancelled.
21
22
  - Public remote origins provided by Funnel, cpolar, or self-hosted FRP use platform-trusted HTTPS. Android stores no private CA for those credentials and cancels every TLS error. It sends a persisted device token only to the exact Origin that previously received it; a changed remote Origin requires a current one-time pairing token before the app replaces the saved credential. A QR-provided installation identifier alone never authorizes credential renewal. Browser clients likewise require a certificate trusted by their platform.
@@ -33,6 +34,7 @@ The maintainer will acknowledge a complete report within seven days. Publication
33
34
  - Treat `mobile.js` as application code with the paired page's same-origin authority. Restrict write access to trusted host-side DSH sessions and review generated API calls or browser-permission use.
34
35
  - Treat every extension `host.mjs` as a local program with the desktop user's Node.js privileges. It is never sandboxed and is not editable through the mobile gateway; only place code there that you trust.
35
36
  - Extension Actions and Routes receive filtered request data, a device identifier, and an abort signal. They cannot set proxy security headers or access the gateway's cookies, device tokens, CSRF tokens, or internal request headers.
37
+ - Proxied GUI responses allow HTTP iframe sources for compatibility with community surfaces. HTTP content is unauthenticated and unencrypted; use HTTPS for sensitive work, and do not treat the compatibility allowance as a transport-security guarantee.
36
38
 
37
39
  ## Known limitation
38
40
 
@@ -0,0 +1,75 @@
1
+ # Self-hosted FRP guide
2
+
3
+ Self-hosted FRP is for users who already operate a VPS and want to avoid the bandwidth limits of public tunnels. The phone reaches Caddy on the VPS over HTTPS, crosses the encrypted FRP tunnel, and then reaches DSH on the computer. FRP only transports the request; DSH pairing is still required.
4
+
5
+ ```text
6
+ Android app
7
+ -> HTTPS (domain or public IPv4)
8
+ -> Caddy on the VPS
9
+ -> 127.0.0.1:7080 (frps HTTP vhost, loopback only)
10
+ -> encrypted FRP tunnel
11
+ -> computer running DSH
12
+ ```
13
+
14
+ ## Two entry modes
15
+
16
+ - **Domain mode**: use your own public domain; Caddy obtains and renews the certificate automatically.
17
+ - **Public IPv4 mode**: use the VPS public IPv4 address directly. The plugin uses Certbot to request a roughly six-day Let's Encrypt IP certificate and installs a daily renewal timer. Documentation ranges such as `203.0.113.10`, private addresses, and other reserved addresses are rejected; enter a real routable public IP.
18
+
19
+ The custom remote-origin flow requires Android app 0.3.3 or later. Older supported apps continue to work with LAN, cpolar, and Tailscale.
20
+
21
+ ## Manual deployment vs automatic deployment
22
+
23
+ - **Manual deployment**: copy the restricted template from the panel. Save the frps section as `/etc/dsh-mobile/frps.toml`, save the Caddy snippet as `/etc/caddy/dsh-mobile-dsh.caddy`, and add exactly this line to the main Caddyfile: `import /etc/caddy/dsh-mobile-dsh.caddy`. If the Caddyfile does not exist, create one containing only that line. Copying the template changes nothing by itself. Public IPv4 mode also requires the Certbot steps in the template because Caddy cannot issue an IP certificate; domain mode is automatic.
24
+ - **Automatic deployment**: enter an SSH user, port, and local private-key path (leave the path empty to use ssh-agent or SSH configuration), then select the one-click deployment action. The VPS must run Ubuntu or Debian with systemd. Only key-based login is accepted; passwords are not supported.
25
+
26
+ Before deployment, the panel lists every VPS change. It installs Caddy from its official APT source; public IPv4 mode additionally installs a Python virtual environment, Certbot, and the renewal timer. It creates or reuses the `dsh-mobile` system user, the frps service and configuration, the Caddy snippet and one import line, and—when UFW is active—allows the FRP control port plus 80/tcp and 443/tcp. **Your existing Caddy content is never merged or overwritten**: an existing DSH Mobile import is only normalized to one line; another non-empty configuration stops the deployment and asks you to add the import manually.
27
+
28
+ ## Verify the host keys every time
29
+
30
+ Automatic deployment and one-click cleanup read the VPS host keys before opening an authenticated SSH connection:
31
+
32
+ 1. Select deployment or cleanup. The panel shows the current `KEYTYPE SHA256:…` fingerprints.
33
+ 2. Compare every fingerprint with the VPS provider console or the information supplied when the server was created.
34
+ 3. Continue only when every key matches. Cancel when a key cannot be verified. The plugin never accepts an unknown host key silently, and a key change during the operation aborts it.
35
+
36
+ The SSH user, port, and private-key path are kept only in this browser's `localStorage` under `dsh-mobile.frp-vps-form.v1` for convenience. The shared token never enters `localStorage`, and the private-key file is never uploaded.
37
+
38
+ ## Clean up the VPS
39
+
40
+ The local **Remove FRP completely** action removes only the computer's managed frpc, token, and configuration; it does not touch the VPS. Server cleanup has two equivalent paths, and both remove only DSH Mobile-owned files, services, and tagged firewall rules:
41
+
42
+ 1. **Copy the uninstall script**: select **Copy VPS uninstall script**, review it, and run it as root on the VPS. The script stops and removes the frps service and certificate-renewal timer, deletes DSH Mobile configuration, binaries, certificates, and the Caddy snippet, removes the import line from the main Caddyfile while preserving your content, and removes UFW rules carrying the DSH Mobile marker. It deletes the `dsh-mobile` system user only when this deployment created it; an existing user is kept and reported.
43
+ 2. **One-click cleanup**: select **Remove DSH Mobile from the VPS**. The panel verifies the host keys again and runs the same script over pinned SSH after confirmation.
44
+
45
+ Public IPv4 mode also removes the corresponding Let's Encrypt IP certificate. Domain-mode certificates remain managed by Caddy.
46
+
47
+ ## Operations and troubleshooting
48
+
49
+ On the VPS:
50
+
51
+ ```bash
52
+ sudo systemctl status dsh-mobile-frps.service caddy dsh-mobile-cert-renew.timer
53
+ sudo journalctl -u dsh-mobile-frps.service -u caddy -n 200 --no-pager
54
+ sudo ss -lntp
55
+ curl -vk https://PUBLIC_HOST/
56
+ ```
57
+
58
+ On the computer, start with the plugin log at `$DSH_HOME/mobile-access/logs/dsh-mobile.log` (JSONL, 5 MB rotation, tokens and keys redacted) and the panel diagnostic report. Windows antivirus software can quarantine frpc; if it does, create the smallest possible exception for the verified component directory only.
59
+
60
+ ## Limits
61
+
62
+ - An unregistered domain on a mainland-China VPS may be intercepted by the cloud provider; use public IPv4 mode in that case.
63
+ - An IPv4 certificate is short-lived; keep its renewal timer and Caddy service running.
64
+ - SSH form values are browser-profile state. Changing browsers or clearing site data requires entering them again; private keys and passwords are never stored.
65
+ - VPS SSH targets currently cannot use IPv6.
66
+ - The frps plaintext vhost must bind to `127.0.0.1`. The plugin rejects a publicly reachable plaintext port and reports readiness only after public discovery identifies the current computer.
67
+
68
+ ## Manual end-to-end checklist (before release)
69
+
70
+ - [x] Ubuntu IP mode: one-click redeploy on a VPS → public IPv4 ready → App discovery returned this computer (2026-09-03, Tencent Cloud).
71
+ - [ ] Ubuntu domain mode: fresh VPS deployment → public domain ready → App pairing → send and receive messages.
72
+ - [x] Existing Caddy coexistence: deploy into a Caddyfile containing an existing site and import line; verify user content is byte-for-byte preserved, the import occurs exactly once, and validation passes (2026-09-03, Tencent Cloud; concurrent writes use `flock`).
73
+ - [x] Host-key change abort: an unconfirmed key set stops deployment/cleanup with `vps_host_key_mismatch` before network authentication (unit-test coverage plus full device fingerprint review).
74
+ - [x] One-click cleanup: after deployment, services, files, timers, marked firewall rules, the owned system user, and the LE certificate were removed while the user's Caddy installation remained (2026-09-03, Tencent Cloud).
75
+ - [x] Uninstall-script review: only DSH Mobile-owned paths and rules are touched (unit assertions plus device review).
@@ -1,5 +1,7 @@
1
1
  # 自建 FRP 使用指南
2
2
 
3
+ [English guide](SELF_HOSTED_FRP.en.md)
4
+
3
5
  自建 FRP 适合已有 VPS、希望避开公共隧道带宽限制的用户。手机经 VPS 上的 Caddy 进入加密 FRP 隧道,再到达电脑上的 DSH;FRP 只负责传输,仍需完成 DSH 配对才能进入。
4
6
 
5
7
  ```text
@@ -23,7 +25,7 @@
23
25
  - **手动部署**:在面板复制受限模板,把 frps 部分存为 `/etc/dsh-mobile/frps.toml`,把 Caddy 片段存为 `/etc/caddy/dsh-mobile-dsh.caddy`,并确保主 Caddyfile 里有且仅需这一行:`import /etc/caddy/dsh-mobile-dsh.caddy`(没有 Caddyfile 就新建一个只写这一行)。复制操作本身不改变任何东西。公网 IPv4 还需要按模板里的注释步骤用 Certbot 申请一次 IP 证书(Caddy 自己签发不了 IP 证书);域名模式 Caddy 全自动。
24
26
  - **自动部署**:填写 SSH 用户、端口和本机私钥路径(留空则用 ssh-agent 或 SSH 配置),点击一键部署。要求 Ubuntu/Debian + systemd,只接受密钥登录,不接受密码。
25
27
 
26
- 点部署按钮前,面板会列出自动部署将在 VPS 上做的全部改动:从官方 APT 源安装 Caddy、安装 Python venv 与 Certbot、创建 `dsh-mobile` 系统用户(已存在则复用,卸载时保留)、frps 配置与服务、Caddy 片段加主文件里的一行 import、证书续期定时器、在 UFW 放行 FRP 控制端口与 80/443。**主 Caddyfile 里你自己的内容永远不会被改写或合并**:没有 Caddyfile、空文件或官方默认文件时才写入这一行 import;其他情况部署直接停止并告诉你手动加这一行。
28
+ 点部署按钮前,面板会列出自动部署将在 VPS 上做的全部改动:从官方 APT 源安装 Caddy;仅在公网 IPv4 模式安装 Python venv、Certbot 和证书续期定时器;创建 `dsh-mobile` 系统用户(已存在则复用,卸载时保留)、frps 配置与服务、Caddy 片段和主文件里的一行 import;如果 UFW 已启用,则放行 FRP 控制端口与 80/443。**主 Caddyfile 里你自己的内容永远不会被改写或合并**:没有 Caddyfile、空文件或官方默认文件时才写入这一行 import;已有 DSH Mobile import 时只整理为一行,其他非空配置会停止部署并告诉你手动加这一行。
27
29
 
28
30
  ## 主机指纹核对(每次必做)
29
31