dsh-mobile 0.4.1 → 0.4.3

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,9 +2,35 @@
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.
5
+ ## 0.4.3 - 2026-09-19
6
+
7
+ - Support Linux for the Funnel, cpolar and cloudflared remote providers, including x64 and arm64 Funnel host binaries.
8
+ - Stay compatible with DSH 0.1.6-alpha.2 (plan-review without scroll marker).
9
+ - Split oversized mobile boot batches so profiles with heavy client bundles (e.g. a 21 MB office viewer) boot on phones again: the layout batch is chunked under a 16 MiB budget, single bundles at or above the per-entry cap pass through on their own `/plugins` row, and pass-through fetches get the same bounded transient retry the merged assembly already has (thanks @abworks-dev for PR #91).
10
+ - A saved LAN interface that is not connected (e.g. after switching from Wi-Fi to Ethernet) no longer fails the whole DSH boot: mobile access logs a warning, stays dormant with its refresh poller armed, and recovers on its own when the adapter returns. Genuine config/TLS errors still fail loudly (thanks @1624318455 for PR #93).
11
+ - Correct the merged boot-batch separator accounting and mark the Linux Funnel binaries executable so the license/binary check passes in CI.
12
+
13
+ ## 0.4.2 - 2026-09-16
14
+
15
+ - Add an Own reverse proxy provider under Remote → Self-hosted for an existing user-managed HTTPS proxy. It provides a separate authenticated private HTTP origin (default 3444), strict private bind/source-CIDR validation, custom public HTTPS ports, local configuration and safe settings-only purge (thanks @xingleiwu for PR #84).
16
+ - Distinguish backend listening from unverified public HTTPS/certificate/WebSocket reachability, with localized setup, errors and diagnostics; retain the existing LAN gateway, remote pairing and Android protocol.
17
+ - Cover the HTTPS proxy → private HTTP origin → DSH path with real loopback pairing, authenticated HTTP and WebSocket tests, including Host/Origin/forwarded-header rejection and LAN independence.
18
+ - Permanently remove revoked devices from durable storage and the desktop list, terminate their active Sessions, and compact legacy `revokedAt` rows on startup. Deleted credentials are rejected as `authentication_failed`; no revocation tombstones are retained. An offline revoked device is therefore re-paired rather than shown as revoked when it reconnects (thanks @xingleiwu for PR #85).
19
+ - Load a bundled Iterator compatibility script before DSH boot on the dedicated mobile frontend, preventing `Iterator is not defined` on WebViews without Iterator helpers. The script is served locally behind the existing gateway authentication and uses feature detection to preserve or repair native helpers without weakening CSP or dropping script nonces (thanks @xingleiwu for PR #86).
20
+ - Add a cloudflared remote provider (Windows x64) in two modes. The pinned official client is downloaded from the official release page and SHA-256 verified only after confirmation, is launched with automatic updates disabled, and does not add a system service, startup item, registry entry, or PATH entry. **Quick mode** needs no account, token, or DNS record: cloudflared allocates a temporary `*.trycloudflare.com` address, which the gateway validates before adopting it — including rejecting the reserved control-plane hosts the banner can print first, such as `api.trycloudflare.com`, which would otherwise have put Cloudflare's API in the pairing QR code. **Named mode** uses a connector token, a public hostname, and a local forward port: the hostname stays the same across restarts, the token is stored only in the DSH Mobile private directory and handed to cloudflared through `TUNNEL_TOKEN` rather than the command line, and it is never returned to any client. Because Cloudflare routes the hostname to that exact port, the port is bound as configured and a taken port is reported as a hard failure instead of silently moving; readiness comes from the connector's own `Registered tunnel connection` line, since a named tunnel prints no banner. Switching back to a quick tunnel removes the stored token.
21
+ - Let the Android app classify `*.trycloudflare.com` as a supported remote tunnel host, so a scanned cloudflared pairing link selects remote access on its own instead of being rejected while no flow has been chosen yet. A named tunnel uses a domain the operator owns, which the app cannot classify by itself, so it is accepted only while the Remote flow is active. Both require an app build that includes this change; earlier builds still pair from the Remote access flow.
22
+ - Keep the mobile gateway usable when its broadcast discovery socket cannot bind the UDP port: Windows keeps separate TCP and UDP port-exclusion tables, so the port the operating system handed the TCP listener can be refused for UDP, and another process may already hold it. Discovery now degrades on its own while mDNS, HTTP and WebSocket service continue, instead of failing the whole listener.
23
+ - Make the remote provider chooser readable now that it offers three providers: the cards list one per row instead of leaving the third orphaned in half a row, the card description — the copy that decides the choice — is no longer the smallest text in the panel, and the destructive inline actions are no longer its smallest targets.
24
+ - Fix the on-demand component download, so the cloudflared component can actually install: a pinned GitHub release URL answers with a redirect, and the downloader refused every redirect, which failed the install in under a second with `TypeError: fetch failed` and no bytes transferred. One redirect hop is now followed after validating its scheme and a release-asset host, and a transport failure is retried once, because a 55 MB transfer through a TUN proxy can reset mid-stream.
25
+ - Keep a failed provider action readable: the status line now holds its message through the repaint that follows, instead of being replaced by the server snapshot within a frame, which made a failed download look like a click that did nothing.
26
+ - Replace the panel's hardcoded colours and its smallest type with DSH tokens and one 11px floor, and reduce interactive targets to two tiers (36px inline, 44px primary). An earlier attempt at the colour work referenced four DSH aliases that do not exist, so every var() fell back to its light literal and the dark theme never adapted; the panel now uses the real border-l1/l2/l3 and state tokens, and a guard test parses the stylesheet so a stray brace can no longer silently drop declarations.
27
+ - Show a failed provider request in the user's own language. A rejection carries its error code, and the panel stringified the whole error, so a rejected tunnel hostname or a failed component download printed the raw code in every locale while the translated sentence sat unreachable; provider failures now resolve through one code-to-copy table.
28
+ - Keep broadcast discovery observable when its UDP port cannot be bound: the failure is reported through the management status and logged once at startup, instead of vanishing while the phone simply cannot find the computer. A missing bundled mobile asset is reported the same way rather than appearing only as a failed subresource.
29
+ - Never let the compatibility bundle break the mobile frontend. An index without a script tag used to fail the whole page, markup inside an HTML comment was accepted as the injection point (so the fix silently never ran), and an already-injected bundle went unrecognised when the document used single quotes.
30
+ - Reserve DSH's own WebServer port (3080) for the reverse-proxy backend and keep that port in the unprivileged range, matching the LAN gateway reservation that already refused 3443.
31
+ - Export the cloudflared tunnel configuration surface so installation tooling can pre-seed a named tunnel through the same validated path instead of writing JSON by hand.
32
+ - Document that a named tunnel must be scanned from inside the app's Remote flow, and that device credentials are bound to their exact origin, so moving a remote channel to a fixed hostname requires pairing the phone again.
33
+ - Reorganize the shipped guides into a bilingual index and remove their broken relative links.
8
34
 
9
35
  ## 0.4.1 - 2026-09-15
10
36
 
@@ -27,7 +53,7 @@ No unreleased changes.
27
53
  - 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
54
  - 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
55
  - 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.
56
+ - Let cpolar choose its default route instead of forcing `cn`: the plugin no longer passes `-region`, so cpolar selects its own tunnel server. No profile or environment setting exposes an explicit region.
31
57
  - 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
58
  - Show and re-copy remote pairing links without invalidating the QR code's active one-time pairing window (thanks @qzyqmzn for PR #75).
33
59
  - 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).
package/README.en.md CHANGED
@@ -30,17 +30,17 @@
30
30
 
31
31
  > DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
32
32
  >
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).
33
+ > **0.4.3 update**: the Funnel, cpolar and cloudflared remote channels now support Linux (x64/arm64); a disconnected saved LAN interface no longer blocks the whole DSH boot (it stays dormant until the network returns); and heavy profiles no longer white-screen phones (boot-batch chunking plus large-bundle pass-through). [Details](CHANGELOG.md).
34
34
  >
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).
35
+ > **Upgrade reminder**: the 0.4.3 plugin continues to work with existing Android apps and paired devices do not need re-pairing. Install the 0.4.3 app as well if you want this Android build. [Compatibility notes](#compatibility).
36
36
 
37
37
  <p align="center">
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>
38
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.3/dsh-mobile-android-v0.4.3.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.3/dsh-mobile-android-v0.4.3.apk"><strong>Download Android app 0.4.3</strong></a><br>
40
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.3">Release notes and checksums</a></sub>
41
41
  </p>
42
42
 
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.
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, cloudflared, self-hosted FRP, or own reverse-proxy 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.
44
44
 
45
45
  Mobile access runs on its own HTTPS origin with pinned certificates; only paired devices pass validation.
46
46
 
@@ -50,13 +50,12 @@ It also lets you customize the phone from a DSH conversation: `/mobile <what you
50
50
 
51
51
  - **Continue DSH work from a phone**: the same sessions, Workspaces, messages, and tools, in real time.
52
52
  - **Customize the phone UI by talking to DSH**: change the mobile layout, interactions, and features from a conversation; open pages refresh within seconds.
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.
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.
55
- - **Auto-discovery, no re-pairing**: Wi-Fi, hotspot, or IP changes normally recover automatically.
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.
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.
58
- - **Faster reconnection**: trusted connections race during restore, revisioned assets are reused, and mobile boot batches are compressed.
59
- - **Three pairing options**: scan a QR code, paste a pairing link, or enter a key.
53
+ - **A dedicated touch layout**: session drawer, tool details, settings, question cards, and composer reorganized for phones; the app follows the system locale (Chinese/English/Italian), plugin UI follows DSH's locale.
54
+ - **Every remote path covered**: Tailscale, cpolar, cloudflared quick/named tunnels, self-hosted FRP, or your own reverse proxy.
55
+ - **Pairing and multi-device**: pair once via QR code, link, or key; Wi-Fi, hotspot, or IP changes normally recover automatically; the app shows all paired computers together in one device list (LAN and every remote), each with live reachability — switch, re-pair, or delete in one tap.
56
+ - **One-click diagnostics and approval**: check versions, gateway, network interface, firewall, and the remote path with a redacted report; approve blocked third-party plugin connections per exact path.
57
+ - **Task system notifications**: completion and pending-input alerts via Android system notifications, enabled from the app foreground menu, with redacted lock-screen text.
58
+ - **Defense in depth**: dedicated HTTPS with pinned certificates, Keystore-backed credentials, device tokens sent only to their exact Origin, third-party WebSockets blocked by default.
60
59
 
61
60
  A paired device is fully trusted and can operate the DSH on the computer. Use this only on a trusted home or office LAN, or a trusted VPN.
62
61
 
@@ -120,9 +119,9 @@ Browser pairing and reauthentication pages use the browser's `Accept-Language` t
120
119
 
121
120
  ### Remote access
122
121
 
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.
122
+ Use this after the phone leaves the computer's network. Remote access is disabled by default, and the phone needs no separate Tailscale, cpolar, cloudflared, or FRP app.
124
123
 
125
- Remote providers may impose bandwidth and connection limits: the [cpolar Free plan](https://svip.cpolar.com/pricing) currently lists 1 Mbps, while [Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) has non-configurable bandwidth limits. DSH Mobile reduces transfer and waiting with 10-message pages, load-on-scroll history, gzip, and a persistent WebSocket, but it cannot raise provider quotas.
124
+ Remote providers may impose bandwidth and connection limits: the [cpolar Free plan](https://svip.cpolar.com/pricing) currently lists 1 Mbps, while [Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) has non-configurable bandwidth limits, and a cloudflared quick tunnel is a free Cloudflare address with randomized hostnames and rate limiting. DSH Mobile reduces transfer and waiting with 10-message pages, load-on-scroll history, gzip, and a persistent WebSocket, but it cannot raise provider quotas.
126
125
 
127
126
  <p align="center">
128
127
  <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/remote-access-en.png" width="82%" alt="DSH Mobile remote access and provider selection">
@@ -132,17 +131,22 @@ Remote providers may impose bandwidth and connection limits: the [cpolar Free pl
132
131
  - **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.
133
132
  - **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.
134
133
  - **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.
135
- 2. When the panel reports that remote access is ready, select **Create remote pairing QR code**.
134
+ - **Own reverse proxy**: open **Self-hosted connection → Own reverse proxy**, enter the public HTTPS origin (custom ports supported), private listen IPv4, separate HTTP backend port (default 3444), and allowed proxy source CIDRs, then select **Save and start backend**. This uses your existing Lucky/Nginx/Caddy without a tunnel component and requires Android app 0.4.0 or later. See the [own reverse proxy guide](docs/SELF_HOSTED_ORIGIN.en.md).
135
+ - **cloudflared quick tunnel**: select **Install official component**. After you confirm, the plugin downloads a pinned build from the official release page into its private directory and requests a temporary public address (a quick tunnel) with **no sign-up or sign-in**. Choose this when you would rather not create an account. The quick-tunnel hostname changes on every reconnect, and Cloudflare positions quick tunnels for testing: they are rate-limited and carry no uptime guarantee, so do not rely on one for production access that must stay reachable; it suits temporary or verification use.
136
+ - **cloudflared named tunnel**: with a Cloudflare account and domain, switch **Tunnel type** to **Named**, then supply a connector token, a public hostname and a local forward port to get an address that survives restarts. The token is stored only in the private directory and reaches cloudflared through the environment rather than the command line; see [Cloudflare named tunnel](docs/CLOUDFLARE_TUNNEL.en.md).
137
+ 2. When the panel reports that remote access is ready, select **Create remote pairing QR code**. Own reverse proxy reports only **Backend listening**: public HTTPS, its certificate and WebSocket still require verification from your phone.
136
138
  3. In the Android app, open **Remote access** and scan the QR code to create its separate pairing.
137
139
  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.
138
140
 
139
141
  > **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.
140
142
 
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.
143
+ 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. cloudflared runs in two modes: a quick tunnel needs no account or sign-in, but its hostname is random, changes on every reconnect, and is positioned by Cloudflare for testing with no uptime guarantee, so it suits temporary or verification use rather than a permanent channel; a named tunnel uses a Cloudflare account token and keeps one fixed public hostname across restarts. 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.
142
144
 
143
145
  Self-hosted FRP generates only one HTTP vhost to the DSH loopback gateway. It exposes no arbitrary FRP configuration, TCP/UDP proxy, or FRP plugin. The VPS plaintext vhost must bind to `127.0.0.1`, with Caddy providing public HTTPS; the plugin rejects a publicly reachable plaintext port and reports readiness only after public discovery identifies the current computer.
144
146
 
145
- The public remote origin still requires DSH device pairing. The bundled Funnel and managed cpolar components currently support Windows x64; on-demand FRP 0.70.1 supports Windows, Linux, and macOS on x64 and arm64.
147
+ The own-proxy HTTP backend must remain on a trusted private network: **never port-forward it publicly or bypass it by proxying to DSH or the existing LAN 3443 gateway**. CIDRs match the proxy's direct TCP peer, not forwarded headers. Preserve the external Host (including port), Origin, cookies and WebSocket. Clearing proxy settings keeps paired remote devices.
148
+
149
+ The public remote origin still requires DSH device pairing. The bundled Funnel and the managed cpolar and cloudflared components support Windows x64 and Linux x64/arm64; on-demand FRP 0.70.1 supports Windows, Linux, and macOS on x64 and arm64. See [Compatibility](#compatibility) for the per-channel OS matrix.
146
150
 
147
151
  ## Extend and customize
148
152
 
@@ -177,16 +181,18 @@ The examples above, applied:
177
181
  <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">
178
182
  </p>
179
183
 
180
- ### Device management
184
+ ## Device management
181
185
 
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.
186
+ The Android app shows multiple computers at once in one **Paired computers** list: LAN, cpolar, cloudflared, Tailscale Funnel, and self-hosted FRP pairings together. 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
187
 
184
188
  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
189
 
186
190
  - **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
191
  - **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
192
  - 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**.
193
+ - 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. When an online device receives the computer's revocation notification, the app keeps its row as **Removed on computer**, stops automatic reconnection, and offers **Pair again** or **Delete device**.
194
+
195
+ Revoking a device permanently deletes its durable record and token digest instead of retaining a `revokedAt` tombstone. Startup also removes legacy revoked rows. A deleted token receives `401 authentication_failed`, just like an unknown token. Existing apps checking a device that was revoked while offline may therefore show **Pairing expired** and require pairing again; online Sessions still receive the revocation notification and disconnect immediately.
190
196
 
191
197
  <table>
192
198
  <tr>
@@ -201,7 +207,7 @@ Each row shows its custom name, transport, Origin, live reachability, and last c
201
207
  </tr>
202
208
  </table>
203
209
 
204
- ### Third-party plugin compatibility
210
+ ## Third-party plugin compatibility
205
211
 
206
212
  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
213
 
@@ -209,7 +215,7 @@ Compatibility and WebSocket rules:
209
215
 
210
216
  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
217
 
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.
218
+ - The released 0.4.3 is contract-checked against DSH `0.1.6-alpha.2` (renderer-v2). 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
219
  - 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
220
  - 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
221
  - 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.
@@ -236,6 +242,8 @@ Proxied pages allow HTTP frames for compatibility with some community plugins; t
236
242
 
237
243
  The Android app is a thin Kotlin WebView shell and contains no frontend copy; mobile browsers load the same page. For compatibility diagnosis, append `?frontend=stock` to the browser URL to temporarily use the previous desktop-page adaptation.
238
244
 
245
+ The dedicated mobile page synchronously loads the authenticated, same-origin `/mobile-access/compat.js` before the first DSH boot script. This bundled core-js compatibility layer supplies `Iterator` / Iterator helpers to WebViews that lack them, preventing the startup error `Iterator is not defined`. It uses feature detection to preserve or repair native helpers, needs no CDN, and does not weaken CSP. It does not change the Android APK, desktop page, or `?frontend=stock` page. This is not a promise to support every old engine: the frontend still targets ES2022. Update Android System WebView / Chrome first if other compatibility errors remain.
246
+
239
247
  > **Community client (unofficial)**: [WeChat Mini-Program client](https://github.com/StrawberryAO/dsh-mobile-minapp)
240
248
  > A native WeChat Mini-Program that reuses the Mobile Access pairing and Remote stream protocol (requires dsh-mobile ≥ 0.3.8).
241
249
  > Because WeChat release builds enforce a domain allow-list (ICP-registered HTTPS origins only), it currently works via WeChat DevTools / real-device debugging; see its README.
@@ -258,18 +266,44 @@ Three layers: the Host face for discovery, pairing, HTTPS, loopback proxying, an
258
266
  - Use the LAN listener only on a trusted home, office, or hotspot network; do not add your own port forwarding.
259
267
  - A remote origin is publicly reachable, but unpaired requests cannot enter DSH; turn the remote switch off when it is not needed.
260
268
  - cpolar downloads a pinned official build only after confirmation and verifies its size and SHA-256. It installs no system service, PATH entry, or startup task, and plugin cleanup removes its managed files.
269
+ - cloudflared likewise downloads a pinned build from the official GitHub Release only after confirmation and verifies the exact size and SHA-256, and it launches the client with automatic updates disabled so the running binary is always the verified one. A quick tunnel needs no account, token, or DNS record; a named tunnel token is stored only in the plugin private directory and reaches cloudflared through the environment, and cleanup deletes every file it manages.
261
270
  - Self-hosted FRP downloads pinned official `frpc` only after confirmation and verifies the origin, exact size, SHA-256, archive paths, and executable version. The shared token never appears in status, diagnostics, or logs. Copying the server template places it on the system clipboard, so clear the clipboard after use; local cleanup removes only plugin-managed files, while the VPS is cleaned separately with the uninstall script or one-click server cleanup. Automatic deployment and server cleanup both display the SSH host keys, which must be verified against the VPS console before continuing.
262
271
  - A paired device is a fully trusted DeepSeek Harness operator and can run tools on the computer; revoke lost devices from the computer.
263
272
  - The LAN gateway listens only while Mobile Access is enabled; with it off, DSH keeps running normally on the computer.
264
273
 
265
274
  See [SECURITY.md](SECURITY.md).
266
275
 
276
+ ## Troubleshooting
277
+
278
+ - **Boot fails with `saved LAN interface "XXX" is not connected`**: the
279
+ computer switched networks (Wi-Fi/Ethernet/dock) and the previously saved
280
+ adapter is down. Either reconnect that network, re-run setup on the new
281
+ one, or set `mobile-access` to `disabled: true` in `cordis.patch.yml` if
282
+ phone access is not needed. Recent versions no longer block boot in this
283
+ case — the plugin logs a warning, stays dormant, and recovers when the
284
+ adapter returns.
285
+
267
286
  ## Compatibility
268
287
 
269
288
  The table below lists, for each plugin version, the DeepSeek Harness version it is verified to support (earlier 0.1.x releases are compatible as well). Starting with 0.3.6 the plugin no longer rejects a DSH version by number alone; newer unlisted versions are covered by CI's contract checks. History lives in [CHANGELOG.md](CHANGELOG.md).
270
289
 
290
+ ### OS support matrix
291
+
292
+ | Channel | Windows x64 | Linux x64 | Linux arm64 | macOS |
293
+ | --- | --- | --- | --- | --- |
294
+ | Local network | Yes (firewall automated) | Yes (open the firewall yourself) | Yes | Yes |
295
+ | Tailscale Funnel | Yes (bundled) | Yes (bundled) | Yes (bundled) | No |
296
+ | cpolar | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | No |
297
+ | cloudflared quick/named tunnel | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | No |
298
+ | Self-hosted FRP | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) |
299
+ | Own reverse proxy | Yes (config only) | Yes (config only) | Yes (config only) | Yes (config only) |
300
+
301
+ On macOS, local network, self-hosted FRP, and the own reverse proxy work; the three managed components have no macOS build yet. The diagnostics firewall check currently covers Windows only and reports “not applicable” elsewhere.
302
+
271
303
  | DSH Mobile plugin | Verified DeepSeek Harness version |
272
304
  | --- | --- |
305
+ | `0.4.3` | `0.1.6-alpha.2` (local source and renderer-v2 contract check) |
306
+ | `0.4.2` | `0.1.6-alpha.1` (local source and renderer-v2 contract check) |
273
307
  | `0.4.1` | `0.1.6-alpha.1` (local source and renderer-v2 contract check) |
274
308
  | `0.3.15`, `0.3.16`, `0.4.0` | `0.1.5-rc.2` (contract check); `0.1.5-rc.1` (@idoall LAN verification) |
275
309
  | `0.3.14` | `0.1.3-alpha.2` |
@@ -279,7 +313,7 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
279
313
  | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
280
314
  | `0.1.4`, `0.2.x` | `0.1.1-rc.2` |
281
315
 
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.
316
+ Existing apps (0.3.3 and later) 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.
283
317
 
284
318
  ## Uninstall
285
319
 
@@ -303,4 +337,4 @@ npm ci
303
337
  npm run verify
304
338
  ```
305
339
 
306
- See the [Android guide](apps/mobile/README.md). Licensed under [Apache-2.0](LICENSE).
340
+ See the [Android guide](https://github.com/saya-ch/dsh-mobile/blob/main/apps/mobile/README.md). Licensed under [Apache-2.0](LICENSE).
package/README.md CHANGED
@@ -30,17 +30,17 @@
30
30
 
31
31
  > DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
32
32
  >
33
- > **0.4.1 更新**:适配 DeepSeek Harness 0.1.6-alpha.1,修复扩展动作请求和局域网路由检测,强化管理请求 CSRF、HTTP iframe 警告与前端兼容性检查,并补齐中英文 FRP 文档。[详细记录](CHANGELOG.md)。
33
+ > **0.4.3 更新**:Funnel、cpolar、cloudflared 远程通道支持 Linux(x64/arm64);保存的局域网网卡断开不再阻断整个 DSH 启动(休眠等网卡回来);插件多的用户手机端白屏修好(启动包分片 + 大 bundle 直通)。[详细记录](CHANGELOG.md)。
34
34
  >
35
- > **升级提醒**:0.4.1 插件可继续使用 0.4.0 Android App;已有设备无需重新配对。若要使用本次 Android 构建,请同时安装 0.4.1 App。[兼容说明](#兼容性)。
35
+ > **升级提醒**:0.4.3 插件可继续使用现有 Android App,已有设备无需重新配对。若要使用本次 Android 构建,请同时安装 0.4.3 App。[兼容说明](#兼容性)。
36
36
 
37
37
  <p align="center">
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>
38
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.3/dsh-mobile-android-v0.4.3.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.3/dsh-mobile-android-v0.4.3.apk"><strong>下载 Android App 0.4.3</strong></a><br>
40
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.3">版本说明与校验文件</a></sub>
41
41
  </p>
42
42
 
43
- DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
43
+ DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、cloudflared、自建 FRP 或自有反向代理远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
44
44
 
45
45
  移动访问使用独立的 HTTPS 与证书固定,只有配对过的设备能通过校验接入。
46
46
 
@@ -50,13 +50,12 @@ DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App
50
50
 
51
51
  - **在手机上继续电脑端的工作**:同一份会话、工作区、消息和工具,实时同步。
52
52
  - **用对话定制手机端**:直接在 DSH 对话里改手机页面的布局、交互和功能,几秒内刷新。
53
- - **专属触屏布局**:会话抽屉、工具详情、设置、提问卡片和输入栏都按手机重新组织。App 原生页面跟随系统显示简体中文、英文或意大利文;插件界面跟随 DSH 的语言设置,意大利语资源已为 DSH 后续支持预留。
54
- - **图片附件**:文件选择使用 DSH 原生“添加”组;DSH Mobile 只在该组补充“拍照”,拍摄结果按 DSH 原生附件流程发送。
55
- - **自动发现、无需重新配对**:切换 Wi-Fi、热点或 IP 后通常自动恢复。
56
- - **一键连接诊断**:检查版本、网关、网卡、防火墙和远程通道;稳定的原因码在界面中本地化,并生成不含凭据与完整地址的脱敏报告。
57
- - **第三方插件 WebSocket 一键放行**:诊断页按目录分组记录被拦截的插件连接(含次数),点允许即放行确切路径,未批准的一律拦截;有新拦截时侧栏红点提醒(#47)。若某插件的连接一直失败(如终端报 1006),先到诊断页看看有没有被拦的连接,一键放行即可,通常无需手动配置。
58
- - **更快恢复连接**:远程重开会并行恢复可信连接、复用版本化资源,并压缩移动端启动批次。
59
- - **三种配对方式**:扫码、配对链接、密钥。
53
+ - **专属触屏布局**:会话抽屉、工具详情、设置、提问卡片和输入栏都按手机重新组织;App 跟随系统语言(简/英/意),插件界面跟随 DSH 语言。
54
+ - **多种远程通道**:Tailscale、cpolar、cloudflared 快速/命名隧道、自建 FRP、自有反向代理,按网络任选。
55
+ - **配对与多设备**:扫码、链接或密钥配对一次;切换 Wi-Fi、热点或 IP 后通常自动恢复;App 在一个设备列表中同时显示多台已配对电脑(局域网与全部远程),每台实时显示可达状态,一键切换、重新配对或删除。
56
+ - **一键诊断与放行**:检查版本、网关、网卡、防火墙和远程通道,生成脱敏报告;被拦截的第三方插件连接按确切路径一键放行。
57
+ - **任务系统通知**:任务完成与待输入以 Android 系统通知推送,在 App 前台菜单开启,锁屏文本脱敏。
58
+ - **纵深安全**:独立 HTTPS 与证书固定,凭据存 Keystore,设备令牌只发往精确 Origin,第三方 WS 默认拦截。
60
59
 
61
60
  配对设备被视为完全信任,可以操作电脑上的 DSH;建议只在可信的家庭、办公局域网或可信 VPN 中使用。
62
61
 
@@ -120,9 +119,9 @@ dsh plugin --profile web add dshmarket
120
119
 
121
120
  ### 远程访问
122
121
 
123
- 适合手机离开电脑所在网络后使用。远程访问默认关闭,手机不需要另外安装 Tailscale、cpolar 或 FRP。
122
+ 适合手机离开电脑所在网络后使用。远程访问默认关闭,手机不需要另外安装 Tailscale、cpolar、cloudflared 或 FRP。
124
123
 
125
- 远程服务可能受带宽和连接限额影响:[cpolar 免费方案](https://svip.cpolar.com/pricing) 当前为 1 Mbps,[Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) 也存在不可配置的带宽限制。DSH Mobile 通过 10 条分页、顶部按需加载、gzip 和 WebSocket 长连接减少流量与等待,但无法突破服务商限额。
124
+ 远程服务可能受带宽和连接限额影响:[cpolar 免费方案](https://svip.cpolar.com/pricing) 当前为 1 Mbps,[Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) 也存在不可配置的带宽限制,cloudflared 的 quick tunnel 由 Cloudflare 免费提供、地址随机且有限流。DSH Mobile 通过 10 条分页、顶部按需加载、gzip 和 WebSocket 长连接减少流量与等待,但无法突破服务商限额。
126
125
 
127
126
  <p align="center">
128
127
  <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/remote-access.png" width="82%" alt="DSH Mobile 远程访问与通道选择">
@@ -132,17 +131,22 @@ dsh plugin --profile web add dshmarket
132
131
  - **Tailscale Funnel**:点击 **启用远程访问**,在打开的官方页面完成一次 Tailscale 登录;按面板提示继续允许 Funnel,然后返回 DSH 等待连接就绪。
133
132
  - **cpolar**:点击 **安装官方组件**,登录 cpolar 控制台取得 Authtoken,粘贴后点击 **保存并连接**。组件只会在确认后下载到插件私有目录;免费临时地址可能在 DSH 或 cpolar 重启后变化。
134
133
  - **自建 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)。
135
- 2. 状态变为“远程访问已就绪”后,点击 **生成远程配对二维码**。
134
+ - **自有反向代理**:展开 **自建连接 → 自有反向代理**,填写公网 HTTPS 地址(支持自定义端口)、私有监听 IPv4、独立 HTTP 后端端口(默认 3444)和代理来源 CIDR,再点击 **保存并启动后端**。适合已有 Lucky/Nginx/Caddy 的用户,无需隧道组件;需要 Android App 0.4.0 或更高版本。详见 [自有反向代理指南](docs/SELF_HOSTED_ORIGIN.md)。
135
+ - **cloudflared 快速隧道**:点击 **安装官方组件**,插件在确认后从官方发布页下载固定版本到插件私有目录,随后自动申请一个临时公网地址(quick tunnel),**无需注册或登录**。适合不想注册账号的用户;quick tunnel 地址每次重连都会变化,官方定位为测试用途、有限流且无可用性保证,请勿用于必须长期可达的生产访问,只适合临时或验证场景。
136
+ - **cloudflared 命名隧道**:已有 Cloudflare 账号和域名时,把隧道类型切到 **命名隧道**,填入连接器令牌、公网域名与本机转发端口,即可获得重启后不变的固定地址(令牌只存私有目录、只经环境变量传给 cloudflared)。步骤见 [Cloudflare 命名隧道](docs/CLOUDFLARE_TUNNEL.md)。
137
+ 2. 状态变为“远程访问已就绪”后,点击 **生成远程配对二维码**。自有反向代理仅显示“后端已监听”:它不验证公网连通性,仍需检查代理 HTTPS、证书与 WebSocket 并用手机验收。
136
138
  3. 在 Android App 中进入 **远程访问**,扫描二维码完成独立配对。
137
139
  4. 此后 App 会保存当前地址和设备凭据并自动重连。若 cpolar 免费临时地址发生变化,请扫描电脑端当前远程二维码重新验证连接;无需清除 App 数据。旧设备 token 只会发送到原先保存的精确 Origin,不会发送给二维码中的新域名。
138
140
 
139
141
  > **远程通知说明**:浏览器的 `Notification` 权限按 Origin 分别授权,网页系统通知只显示在运行该网页的设备上。Android App 的任务提醒是独立的 0.4.0 功能,需要在 App 前台菜单中主动开启,且依赖 WebView 页面仍存活;它不是通用的后台推送。需要可靠的后台推送时,请使用你已配置的服务端 webhook 或机器人通道。
140
142
 
141
- Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。其运行组件把公开监听生命周期绑定到父进程和受限控制通道;父进程退出、控制通道关闭或显式停止时会结束当前代次并清理资源。cpolar 更适合国内网络;自建 FRP 适合已有 VPS、希望避开公共服务带宽限制的用户。中国大陆 VPS 上的未备案域名可能被云厂商拦截,此时可使用公网 IPv4 模式。插件会校验按需下载的固定版本组件,配置与程序均保存在 `$DSH_HOME/mobile-access/`,可随时在面板中彻底清除。
143
+ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。其运行组件把公开监听生命周期绑定到父进程和受限控制通道;父进程退出、控制通道关闭或显式停止时会结束当前代次并清理资源。cpolar 更适合国内网络;自建 FRP 适合已有 VPS、希望避开公共服务带宽限制的用户。cloudflared 有两种模式:快速隧道不需要账号或登录,但地址随机、每次重连都会变化,官方定位为测试用途且无可用性保证,因此只适合临时或验证场景;命名隧道使用 Cloudflare 账号令牌,能保留重启后不变的固定公网域名。中国大陆 VPS 上的未备案域名可能被云厂商拦截,此时可使用公网 IPv4 模式。插件会校验按需下载的固定版本组件,配置与程序均保存在 `$DSH_HOME/mobile-access/`,可随时在面板中彻底清除。
142
144
 
143
145
  自建 FRP 只生成一个指向 DSH 回环网关的 HTTP vhost,不提供任意 FRP 配置、TCP/UDP 代理或 FRP 插件。VPS 的明文 vhost 必须只监听 `127.0.0.1`,由 Caddy 提供公网 HTTPS;插件会拒绝可从公网访问的明文端口,并在公开发现接口确认连接到当前电脑后才显示“已就绪”。
144
146
 
145
- 远程公开地址仍受 DSH 设备配对保护。内置 Funnel 与托管 cpolar 当前支持 Windows x64;按需安装的 FRP 0.70.1 支持 Windows、Linux、macOS 的 x64 与 arm64。
147
+ 自有反向代理的 HTTP 后端只允许留在可信私网;**不要把它映射到公网,也不要绕过它直连 DSH 或现有 LAN 3443**。来源 CIDR 匹配代理的直接 TCP 来源,不信任转发头;反代须保留外部 Host(含端口)、Origin、Cookie 和 WebSocket。清除代理配置不会删除已配对远程设备。
148
+
149
+ 远程公开地址仍受 DSH 设备配对保护。内置 Funnel 与托管 cpolar、cloudflared 支持 Windows x64 与 Linux x64/arm64;按需安装的 FRP 0.70.1 支持 Windows、Linux、macOS 的 x64 与 arm64。各通道的系统支持矩阵见[兼容性](#兼容性)。
146
150
 
147
151
  ## 扩展与自定义
148
152
 
@@ -177,16 +181,18 @@ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。
177
181
  <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 定制为赛博朋克监控面板">
178
182
  </p>
179
183
 
180
- ### 设备管理
184
+ ## 设备管理
181
185
 
182
- Android App 将局域网、cpolar、Tailscale Funnel 和自建 FRP 统一整理到“已配对设备”列表。首次升级会自动迁移旧版局域网与远程凭据,不要求重新配对;地址变化时按 DSH 安装的稳定 `instanceId` 合并原记录,保留自定义名称。设备 Token 和局域网 CA 继续由 Android Keystore 加密保存,不会显示在列表或二维码中。
186
+ Android App 用一个“已配对设备”列表同时显示多台电脑:局域网、cpolar、cloudflared、Tailscale Funnel 和自建 FRP 配对共处一处。首次升级会自动迁移旧版局域网与远程凭据,不要求重新配对;地址变化时按 DSH 安装的稳定 `instanceId` 合并原记录,保留自定义名称。设备 Token 和局域网 CA 继续由 Android Keystore 加密保存,不会显示在列表或二维码中。
183
187
 
184
188
  每条记录显示自定义名称、连接方式、Origin、实时可达状态和最近连接时间。绿色状态点表示“可达”,灰色状态点表示“检测中”“暂不可达”“配对已过期”或“电脑端已移除”;可达性检查直接验证 DSH Gateway,不依赖 ICMP,也不会把暂时断网误判成电脑端撤销。
185
189
 
186
190
  - **启动时打开 → 直接进入 DSH**(默认):单设备直接连接;多设备优先连接上次使用的设备,其次按最近连接时间选择仍有效的设备。连接超过有限重试预算后自动回到列表,不会无限转圈。
187
191
  - **启动时打开 → 显示设备列表**:每次启动先选择电脑,适合经常在多台设备之间切换。该选项位于列表右上角的设置按钮中,修改后立即保存。
188
192
  - 点按设备行可连接;右侧“…”和长按提供相同的操作面板,可编辑名称、立即检测、重新配对或删除本地记录。删除前会二次确认,并提供短暂撤销;撤销只恢复本机记录,不恢复电脑端已经撤销的授权。
189
- - 在 WebView 页面打开 DSH **设置 → 通用**,选择 **切换电脑** 可回到已配对设备列表;该动作仅在 Android App 中显示。电脑端撤销设备后,App 保留该条目并显示“电脑端已移除”,停止自动重连,同时提供 **重新配对** 和 **删除本地记录**。
193
+ - 在 WebView 页面打开 DSH **设置 → 通用**,选择 **切换电脑** 可回到已配对设备列表;该动作仅在 Android App 中显示。在线收到电脑端撤销通知后,App 保留该条目并显示“电脑端已移除”,停止自动重连,同时提供 **重新配对** 和 **删除本地记录**。
194
+
195
+ 电脑端撤销会永久删除持久化存储中的设备记录及令牌摘要,而不是保留 `revokedAt` 标记;启动时也会清理旧版留下的已撤销记录。删除后,旧令牌与未知令牌一样返回 `401 authentication_failed`。现有 App 若在离线期间被撤销,再次检测时可能显示“配对已过期”,需要重新配对;在线会话仍会收到撤销通知并立即断开。
190
196
 
191
197
  <table>
192
198
  <tr>
@@ -201,7 +207,7 @@ Android App 将局域网、cpolar、Tailscale Funnel 和自建 FRP 统一整理
201
207
  </tr>
202
208
  </table>
203
209
 
204
- ### 第三方插件适配
210
+ ## 第三方插件适配
205
211
 
206
212
  移动适配保持 DSH 原有的工作区、任务管理、终端和文件面板入口,不会把第三方插件内容隔离成另一套页面。下面的宽屏截图展示 Android App 在宽屏下的布局。App 会根据屏幕宽度自适应:手机使用抽屉和浮层,宽屏使用并排面板;两种布局共享相同的功能和连接方式。第三方插件仍由 DSH 自己加载,移动层负责适配布局与连接,不修改 DeepSeek Harness 源码。
207
213
 
@@ -209,7 +215,7 @@ Android App 将局域网、cpolar、Tailscale Funnel 和自建 FRP 统一整理
209
215
 
210
216
  代理页面为兼容部分社区插件允许嵌入 HTTP 页面;这类内容未加密,可能被篡改,浏览器也可能因混合内容策略拦截。处理敏感内容时请使用 HTTPS。通过 HTTPS 管理入口打开远程面板时,页面顶部会显示相同提醒。
211
217
 
212
- - 已发布的 0.4.0 按 DSH `0.1.5-rc.2` 做过 renderer-v2 合同检查,并保留对 `0.1.5-rc.1` 局域网路径的验证。DSH 页面需要提供标准的会话、`main`/`panelInfo` 和 `rightbar` 插槽;插件自身需要通过 DSH 的标准面板或侧边栏入口注册内容。
218
+ - 已发布的 0.4.3 按 DSH `0.1.6-alpha.2` 做过 renderer-v2 合同检查。DSH 页面需要提供标准的会话、`main`/`panelInfo` 和 `rightbar` 插槽;插件自身需要通过 DSH 的标准面板或侧边栏入口注册内容。
213
219
  - 网关默认只允许 DSH 内置的第一方 WebSocket 路径。社区侧边栏插件使用的其他路径默认拦截,通常会在诊断页显示为待处理项目;截图中的`/sidebar/ws/agent-opens` 和`/sidebar/ws/agent-terminals` 就属于这类需要按实际插件确认的路径。
214
220
  - 在 **连接诊断 → 第三方 WebSocket 路径** 中,只对确认过的精确路径点击 **允许**。系统不接受带查询字符串或模糊前缀的路径;不建议使用“全部允许”。已允许的路径可以随时移除,局域网和远程连接使用同一套规则。
215
221
  - 放行只代表该路径可以通过已认证、同源的 DSH Mobile 网关,不会开放任意 TCP/UDP 端口,也不会绕过设备配对。若社区插件仍然连接失败,先看诊断页的实际拦截路径,再按一条路径放行。
@@ -237,6 +243,8 @@ Android App 将局域网、cpolar、Tailscale Funnel 和自建 FRP 统一整理
237
243
 
238
244
  Android App 只是 Kotlin WebView 薄壳,不内置另一份网页;手机浏览器访问的是同一页面。需要排查兼容性时,可在浏览器地址后追加 `?frontend=stock`,临时回到旧的桌面页面适配模式。
239
245
 
246
+ 专用移动页面会在 DSH 的第一个启动脚本之前,同步加载经网关鉴权的同源 `/mobile-access/compat.js`,为缺少 `Iterator` / Iterator helpers 的 WebView 提供随插件打包的 core-js 兼容实现,避免启动时出现 `Iterator is not defined`。兼容层按能力检测保留或修正原生 helper,不依赖 CDN,也不会放宽 CSP;不修改 Android APK、桌面页面或 `?frontend=stock` 页面。此修复并不承诺支持所有旧内核,前端仍以 ES2022 为构建目标;若还有其他兼容错误,请优先更新 Android System WebView / Chrome。
247
+
240
248
  > **社区客户端(非官方)**:[微信小程序客户端](https://github.com/StrawberryAO/dsh-mobile-minapp)
241
249
  > 原生微信小程序实现,复用「移动访问」的配对与 Remote 流协议(需 dsh-mobile ≥ 0.3.8)。
242
250
  > 因微信正式版强制「合法域名」(需 ICP 备案的自有 HTTPS 域名),目前需通过微信开发者工具 / 真机调试使用,详见其 README。
@@ -260,19 +268,43 @@ flowchart LR
260
268
  - 局域网监听只用于可信家庭、办公网络或可信热点;不要自行做端口转发。
261
269
  - 远程地址可从公网到达,但未配对请求无法进入 DSH;不使用时应关闭远程开关。
262
270
  - cpolar 仅在用户确认后下载固定官方版本并校验大小和 SHA-256;不会安装系统服务、写入 PATH 或设置开机启动,插件清理会删除其托管文件。
271
+ - cloudflared 同样仅在用户确认后从官方 GitHub Release 下载固定版本并校验精确大小和 SHA-256,且启动时关闭自动更新,以保证运行的始终是已校验的那份二进制;快速隧道不需要账号、Token 或 DNS 记录;命名隧道令牌只存插件私有目录、只经环境变量传给 cloudflared,清理时删除插件托管的全部文件。
263
272
  - 自建 FRP 仅在用户确认后从官方 Release 下载固定版本 `frpc`,校验来源、精确大小、SHA-256、压缩包路径和可执行文件版本;共享 Token 不会出现在状态、诊断或日志中。复制服务器模板时 Token 会进入系统剪贴板,请粘贴后及时清除;本机清理只删除插件管理的文件,VPS 需要用面板提供的卸载脚本或一键清理单独清除。自动部署与一键清理前都会展示 SSH 主机指纹,必须到 VPS 控制台核对后才能继续。
264
273
  - 配对设备拥有控制电脑端 DeepSeek Harness 的能力,应视为完全可信设备;丢失手机后应在电脑端撤销设备。
265
274
  - 移动网关开启时才监听局域网;关闭后 DeepSeek Harness 仍正常在电脑本机运行。
266
275
 
267
276
  完整说明见 [SECURITY.md](SECURITY.md)。
268
277
 
278
+ ## 故障排查
279
+
280
+ - **启动报 `saved LAN interface "XXX" is not connected` 且 DSH 起不来**:
281
+ 电脑切换过网络(WiFi/有线/扩展坞),之前保存的网卡当前未连接。处理方式
282
+ (三选一):连回原来的网络;按新网络重跑一遍 setup;暂时不用手机访问时,
283
+ 在 `cordis.patch.yml` 把 `mobile-access` 设 `disabled: true`。新版本中该
284
+ 情况不再阻断启动——插件记一条警告后休眠,等网卡回来自动恢复。
285
+
269
286
  ## 兼容性
270
287
 
271
288
  下表列出各插件版本验证支持到的 DeepSeek Harness 版本(早于该版本的 0.1.x 均兼容)。0.3.6 起插件不再按版本号拒绝启动,未列出的更新版本由 CI 契约检查兜底。历史记录见 [CHANGELOG.md](CHANGELOG.md)。
272
289
 
290
+ ### 系统支持矩阵
291
+
292
+ | 通道 | Windows x64 | Linux x64 | Linux arm64 | macOS |
293
+ | --- | --- | --- | --- | --- |
294
+ | 局域网 | 支持(自动配防火墙) | 支持(防火墙自理) | 支持 | 支持 |
295
+ | Tailscale Funnel | 支持(随包提供) | 支持(随包提供) | 支持(随包提供) | 不支持 |
296
+ | cpolar | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 不支持 |
297
+ | cloudflared 快速/命名隧道 | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 不支持 |
298
+ | 自建 FRP | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) |
299
+ | 自有反向代理 | 支持(纯配置) | 支持(纯配置) | 支持(纯配置) | 支持(纯配置) |
300
+
301
+ macOS 上局域网、自建 FRP 与自有反向代理可用;三个托管组件暂未提供 macOS 包。诊断页的防火墙检查目前仅覆盖 Windows,其他系统显示“不适用”。
302
+
273
303
 
274
304
  | DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
275
305
  | ----------------------------------------- | -------------------------------------------------------------- |
306
+ | `0.4.3` | `0.1.6-alpha.2`(本机源码与 renderer-v2 契约检查) |
307
+ | `0.4.2` | `0.1.6-alpha.1`(本机源码与 renderer-v2 契约检查) |
276
308
  | `0.4.1` | `0.1.6-alpha.1`(本机源码与 renderer-v2 契约检查) |
277
309
  | `0.3.15`、`0.3.16`、`0.4.0` | `0.1.5-rc.2`(契约检查);`0.1.5-rc.1`(@idoall 局域网实测) |
278
310
  | `0.3.14` | `0.1.3-alpha.2` |
@@ -282,7 +314,7 @@ flowchart LR
282
314
  | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
283
315
  | `0.1.4`、`0.2.x` | `0.1.1-rc.2` |
284
316
 
285
- 现有 0.3.3–0.4.0 App 无需重新配对;cpolar 用户应使用 0.3.15 或更新 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.4.0 才支持多设备列表、启动行为设置和电脑端撤销状态同步;旧版 App 仍可连接已保存的单台设备。App 0.1.3 及更早版本需卸载重装并重新配对。
317
+ 现有 App(0.3.3 及更新)无需重新配对;cpolar 用户应使用 0.3.15 或更新 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.4.0 才支持多设备列表、启动行为设置和电脑端撤销状态同步;旧版 App 仍可连接已保存的单台设备。App 0.1.3 及更早版本需卸载重装并重新配对。
286
318
 
287
319
  ## 卸载
288
320
 
@@ -306,6 +338,6 @@ npm ci
306
338
  npm run verify
307
339
  ```
308
340
 
309
- Android 构建见 [App 文档](apps/mobile/README.zh-CN.md)。
341
+ Android 构建见 [App 文档](https://github.com/saya-ch/dsh-mobile/blob/main/apps/mobile/README.zh-CN.md)。
310
342
 
311
343
  Apache-2.0,详见 [LICENSE](LICENSE)。
@@ -6,6 +6,35 @@ The optional cpolar component is not included in the npm package or Android App.
6
6
 
7
7
  The optional [FRP](https://github.com/fatedier/frp) client is not included in the npm package or Android App. When a user explicitly chooses self-hosted FRP installation, DSH Mobile downloads the pinned official `frpc` 0.70.1 archive, verifies its origin, exact size, SHA-256 digest, archive paths, and executable version, then stores only `frpc` under the user's DSH Mobile data directory. FRP is distributed under the Apache License 2.0.
8
8
 
9
+ The optional [cloudflared](https://github.com/cloudflare/cloudflared) client is not included in the npm package or Android App. When a user explicitly chooses cloudflared installation, DSH Mobile downloads the pinned official `cloudflared-windows-amd64.exe` release asset (version recorded in `src/cloudflared-component.ts`), verifies its exact size and SHA-256 digest, and stores it only under the user's DSH Mobile data directory. The client is started with automatic updates disabled and no account credential is requested or stored. cloudflared is distributed under the Apache License 2.0; use of Cloudflare's quick tunnels remains subject to Cloudflare's [website terms](https://www.cloudflare.com/website-terms/).
10
+
9
11
  The npm package declares direct runtime dependencies on [Schemastery](https://github.com/shigma/schemastery) `^3.18.1`, [bonjour-service](https://github.com/onlxltd/bonjour-service) `^1.4.4`, [qrcode](https://github.com/soldair/node-qrcode) `^1.5.4`, and [selfsigned](https://github.com/jfromaniello/selfsigned) `^5.5.0`. These packages are distributed under the MIT License; the release checkout's exact transitive versions appear in the attached CycloneDX npm SBOM.
10
12
 
11
13
  The Android App runtime contains [Kotlin standard library](https://github.com/JetBrains/kotlin) `2.1.0`, [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) `1.6.4`, [JetBrains annotations](https://github.com/JetBrains/java-annotations) `13.0`, [AndroidX Core](https://developer.android.com/jetpack/androidx/releases/core) `1.15.0`, [AndroidX WebKit](https://developer.android.com/jetpack/androidx/releases/webkit) `1.12.1`, their AndroidX transitive components, [Guava listenablefuture](https://github.com/google/guava) `1.0`, and [ZXing Core](https://github.com/zxing/zxing) `3.5.4`. These runtime libraries are distributed under the Apache License 2.0; the exact resolved tree is attached to each release as `dsh-mobile-android-v<version>-dependencies.txt`.
14
+
15
+ ## core-js browser compatibility bundle
16
+
17
+ The standalone `lib/mobile-compat.js` bundles selected Iterator modules from [core-js](https://github.com/zloirock/core-js) `^3.50.0` (exact version recorded in `package-lock.json`). It is built into the npm package; browsers do not download a polyfill from a CDN. core-js is distributed under the following MIT License:
18
+
19
+ ```text
20
+ Copyright (c) 2013–2025 Denis Pushkarev (zloirock.ru)
21
+ Copyright (c) 2025–2026 CoreJS Company (core-js.io)
22
+
23
+ Permission is hereby granted, free of charge, to any person obtaining a copy
24
+ of this software and associated documentation files (the "Software"), to deal
25
+ in the Software without restriction, including without limitation the rights
26
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27
+ copies of the Software, and to permit persons to whom the Software is
28
+ furnished to do so, subject to the following conditions:
29
+
30
+ The above copyright notice and this permission notice shall be included in
31
+ all copies or substantial portions of the Software.
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39
+ THE SOFTWARE.
40
+ ```
Binary file