dsh-mobile 0.3.14 → 0.3.15
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 +19 -0
- package/README.en.md +9 -8
- package/README.md +9 -8
- package/SECURITY.md +1 -1
- package/docs/DSH_0.1.5_LAN.md +27 -0
- package/lib/client.js +41 -8
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +13 -0
- package/lib/index.mjs +200 -23
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-layout.js +116 -11
- package/lib/mobile-layout.js.map +1 -1
- package/package.json +14 -12
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
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
5
|
|
|
6
|
+
## 0.3.15 - 2026-09-11
|
|
7
|
+
|
|
8
|
+
- Support the DeepSeek Harness 0.1.5 keyed `main` panel, root `panelInfo` hook, navigation lifecycle, and root right sidebar while retaining the earlier `conversation` and `details` paths.
|
|
9
|
+
- Recover mobile boot batches from transient upstream resets with bounded retry, lower concurrency, and one request-independent assembly shared by concurrent clients; proxy DSH installations that disable browser launch-token authentication (thanks @longisland-icetea for PRs #59 and #60).
|
|
10
|
+
- Synchronize Mobile drawer dismissal with the DSH 0.1.5 right-Sidebar state, and keep the wide-screen right panel non-modal so its scrim cannot cover the composer (thanks @idoall for reporting #62).
|
|
11
|
+
- Keep the injected drawer backdrop and transient toasts out of wide desktop document flow while preserving the narrow overlay behavior (thanks @longisland-icetea for PR #63).
|
|
12
|
+
- The gateway now proxies the DSH desktop UI's sidebar terminal by default: its upgrade path (`/sidebar/ws/terminal`, first-party DSH surface, renderer-v2) joins the built-in WebSocket allow-list, so pairing no longer fails with repeated `1006` when the terminal connects. Third-party plugin paths still require one-click approval in the connection diagnostics.
|
|
13
|
+
- Let the mobile-access entry share the desktop footer-action row, preserve the compact rail target, and separate folded or expanded reasoning from the reply (thanks @IvyC-zz for reporting #58).
|
|
14
|
+
- Declare DSH 0.1.5 prerelease peers, align the development toolchain with rc.2, and update `js-yaml` to the compatible security fix 4.3.2.
|
|
15
|
+
- Follow cpolar public-origin rotations by rebuilding the authenticated gateway on the existing loopback port. Android identifies an expired temporary cpolar address, opens the remote scanner directly, and never sends a stored device token to a different QR-provided Origin; the new Origin is accepted only through one-time pairing.
|
|
16
|
+
- Allow up to 120 seconds for an authenticated cpolar page to finish its first load while retaining the 15-second LAN and 30-second other-remote budgets. ADB and Chrome DevTools reproduced a valid 200 response whose 4.41 MB compressed DSH 0.1.5 boot module needed 88 seconds over the free route; the App now lets that transfer finish instead of misreporting the healthy tunnel as unreachable.
|
|
17
|
+
- The 0.1.5 LAN path was first verified on rc.1 by @idoall; current compatibility checks target rc.2. See [the verification record](docs/DSH_0.1.5_LAN.md).
|
|
18
|
+
|
|
19
|
+
### Contributors
|
|
20
|
+
|
|
21
|
+
- @longisland-icetea contributed PRs #59, #60, and #63: browser-auth-disabled proxying, the DSH 0.1.5 layout and boot-batch adaptation, and the wide-screen scrim fix.
|
|
22
|
+
- @idoall contributed PR #61's LAN verification and documentation, and provided the detailed right-Sidebar state report in #62.
|
|
23
|
+
- @IvyC-zz provided the terminal and mobile UI reproductions in #58.
|
|
24
|
+
|
|
6
25
|
## 0.3.14 - 2026-09-08
|
|
7
26
|
|
|
8
27
|
- The panel's “Update plugin” action now shows a preview card first: the latest release notes (fetched from the GitHub releases API, graceful fallback when unavailable) plus fixed upgrade notices (restart DSH after installing; apps and paired devices need no re-pairing; check the README compatibility table when unsure about the desktop version), then explicit Update now / Not now buttons. Notes are served from the release itself, so a user on any older plugin version sees the current guidance before updating.
|
package/README.en.md
CHANGED
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
|
|
20
20
|
> DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
|
|
21
21
|
>
|
|
22
|
-
> **0.3.
|
|
22
|
+
> **0.3.15 update**: fully adapts to DeepSeek Harness **0.1.5-rc.2**, improves the new frontend and cpolar address rotation and slow first loads, and fixes right-sidebar dismissal, wide-screen scrims, terminal WebSockets, shared desktop footer layout, and reasoning/reply spacing. [Details](CHANGELOG.md).
|
|
23
23
|
>
|
|
24
|
-
> **Upgrade reminder**: plugin **0.3.
|
|
24
|
+
> **Upgrade reminder**: DSH 0.1.5 requires plugin **0.3.15** and a DSH restart. Existing pairings remain valid; cpolar users should also install app 0.3.15 so an older app does not cancel a slow first load. [Compatibility notes](#compatibility).
|
|
25
25
|
|
|
26
26
|
<p align="center">
|
|
27
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
28
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
29
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.
|
|
27
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.15/dsh-mobile-android-v0.3.15.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.15/dsh-mobile-android-v0.3.15.apk"><strong>Download Android app 0.3.15</strong></a><br>
|
|
29
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.15">Release notes and checksums</a></sub>
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
32
|
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.
|
|
@@ -113,11 +113,11 @@ Remote providers may impose bandwidth and connection limits: the [cpolar Free pl
|
|
|
113
113
|
|
|
114
114
|
1. Open **Mobile Access → Remote** in the lower-left corner of DeepSeek Harness and choose a provider:
|
|
115
115
|
- **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.
|
|
116
|
-
- **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.
|
|
116
|
+
- **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.
|
|
117
117
|
- **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.
|
|
118
118
|
2. When the panel reports that remote access is ready, select **Create remote pairing QR code**.
|
|
119
119
|
3. In the Android app, open **Remote access** and scan the QR code to create its separate pairing.
|
|
120
|
-
4. The app
|
|
120
|
+
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.
|
|
121
121
|
|
|
122
122
|
> **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.
|
|
123
123
|
|
|
@@ -201,6 +201,7 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
|
|
|
201
201
|
|
|
202
202
|
| DSH Mobile plugin | Verified DeepSeek Harness version |
|
|
203
203
|
| --- | --- |
|
|
204
|
+
| `0.3.15` | `0.1.5-rc.2` (contract check); `0.1.5-rc.1` (@idoall LAN verification) |
|
|
204
205
|
| `0.3.14` | `0.1.3-alpha.2` |
|
|
205
206
|
| `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
|
|
206
207
|
| `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
|
|
@@ -208,7 +209,7 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
|
|
|
208
209
|
| `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
|
|
209
210
|
| `0.1.4`, `0.2.x` | `0.1.1-rc.2` |
|
|
210
211
|
|
|
211
|
-
Existing 0.3.3
|
|
212
|
+
Existing 0.3.3–0.3.15 apps do not need re-pairing. cpolar users should update to app 0.3.15 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.
|
|
212
213
|
|
|
213
214
|
## Uninstall
|
|
214
215
|
|
package/README.md
CHANGED
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
|
|
27
27
|
> DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
|
|
28
28
|
>
|
|
29
|
-
> **0.3.
|
|
29
|
+
> **0.3.15 更新**:完整适配 DeepSeek Harness **0.1.5-rc.2**,提升新版前端及 cpolar 换址、慢速首屏加载的稳定性,并修复移动右栏关闭、宽屏遮罩、终端 WebSocket、桌面 footer 共存及思考/正文间距。[详细记录](CHANGELOG.md)。
|
|
30
30
|
>
|
|
31
|
-
>
|
|
31
|
+
> **升级提醒**:DSH 0.1.5 用户需将插件升级至 **0.3.15** 并重启 DSH;现有配对继续有效,cpolar 用户需同步安装 0.3.15 App,以免慢速首屏被旧版 App 提前终止。[兼容说明](#兼容性)。
|
|
32
32
|
|
|
33
33
|
<p align="center">
|
|
34
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
35
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
36
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.
|
|
34
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.15/dsh-mobile-android-v0.3.15.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.15/dsh-mobile-android-v0.3.15.apk"><strong>下载 Android App 0.3.15</strong></a><br>
|
|
36
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.15">版本说明与校验文件</a></sub>
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
39
|
DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
|
|
@@ -120,11 +120,11 @@ dsh plugin --profile web add dshmarket
|
|
|
120
120
|
|
|
121
121
|
1. 在 DeepSeek Harness 左下角打开 **移动访问 → 远程**,选择一种连接方式:
|
|
122
122
|
- **Tailscale Funnel**:点击 **启用远程访问**,在打开的官方页面完成一次 Tailscale 登录;按面板提示继续允许 Funnel,然后返回 DSH 等待连接就绪。
|
|
123
|
-
- **cpolar**:点击 **安装官方组件**,登录 cpolar 控制台取得 Authtoken,粘贴后点击
|
|
123
|
+
- **cpolar**:点击 **安装官方组件**,登录 cpolar 控制台取得 Authtoken,粘贴后点击 **保存并连接**。组件只会在确认后下载到插件私有目录;免费临时地址可能在 DSH 或 cpolar 重启后变化。
|
|
124
124
|
- **自建 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)。
|
|
125
125
|
2. 状态变为“远程访问已就绪”后,点击 **生成远程配对二维码**。
|
|
126
126
|
3. 在 Android App 中进入 **远程访问**,扫描二维码完成独立配对。
|
|
127
|
-
4. 此后 App
|
|
127
|
+
4. 此后 App 会保存当前地址和设备凭据并自动重连。若 cpolar 免费临时地址发生变化,请扫描电脑端当前远程二维码重新验证连接;无需清除 App 数据。旧设备 token 只会发送到原先保存的精确 Origin,不会发送给二维码中的新域名。
|
|
128
128
|
|
|
129
129
|
> **远程通知说明**:浏览器通知权限按地址分别授权,远程地址需在浏览器中单独允许;系统级弹窗只出现在电脑上,手机收不到。任务完成要推送到手机时,请使用第三方通道(如 dsh-messager 的飞书/企业微信/Telegram 推送),它们走服务端下发,不受网关影响。
|
|
130
130
|
|
|
@@ -210,6 +210,7 @@ flowchart LR
|
|
|
210
210
|
|
|
211
211
|
| DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
|
|
212
212
|
| --- | --- |
|
|
213
|
+
| `0.3.15` | `0.1.5-rc.2`(契约检查);`0.1.5-rc.1`(@idoall 局域网实测) |
|
|
213
214
|
| `0.3.14` | `0.1.3-alpha.2` |
|
|
214
215
|
| `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
|
|
215
216
|
| `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
|
|
@@ -217,7 +218,7 @@ flowchart LR
|
|
|
217
218
|
| `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
|
|
218
219
|
| `0.1.4`、`0.2.x` | `0.1.1-rc.2` |
|
|
219
220
|
|
|
220
|
-
现有 0.3.3
|
|
221
|
+
现有 0.3.3–0.3.15 App 无需重新配对;cpolar 用户应升级到 0.3.15 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.1.3 及更早版本需卸载重装并重新配对。
|
|
221
222
|
|
|
222
223
|
## 卸载
|
|
223
224
|
|
package/SECURITY.md
CHANGED
|
@@ -18,7 +18,7 @@ The maintainer will acknowledge a complete report within seven days. Publication
|
|
|
18
18
|
- Expose only the plugin-owned HTTPS listener to the LAN.
|
|
19
19
|
- 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
20
|
- 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
|
-
- 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. Browser clients likewise require a certificate trusted by their platform.
|
|
21
|
+
- 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.
|
|
22
22
|
- Keep pairing closed except during a short local onboarding action.
|
|
23
23
|
- Revoke a lost device immediately and rotate the device registry if credential theft is suspected.
|
|
24
24
|
- Do not expose the LAN gateway through router port forwarding. Optional remote access uses a separate loopback gateway behind the selected Tailscale Funnel, cpolar, or self-hosted FRP path. The outer provider or Caddy terminates public TLS, while DSH pairing, device authentication, CSRF checks, and session revocation remain enforced by the plugin gateway.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# DeepSeek Harness 0.1.5 局域网验证
|
|
2
|
+
|
|
3
|
+
本页记录 DSH Mobile 0.3.15 对 DeepSeek Harness 0.1.5 的局域网兼容性证据,以及该次实测没有覆盖的远程路径。
|
|
4
|
+
|
|
5
|
+
## 验证环境
|
|
6
|
+
|
|
7
|
+
| 项目 | 版本 / 结果 |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| DSH Mobile | `0.3.15` 开发版本 |
|
|
10
|
+
| DeepSeek Harness | `0.1.5-rc.1` |
|
|
11
|
+
| 安装方式 | 本地 `link:` 插件,`setup` 绑定 `en0` |
|
|
12
|
+
| 访问路径 | 手机通过插件提供的局域网 HTTPS 地址连接 |
|
|
13
|
+
| 验证人 | [@idoall](https://github.com/idoall) |
|
|
14
|
+
|
|
15
|
+
局域网配对、会话列表、对话区、新建会话和右侧栏均可用。DeepSeek Harness `0.1.5-rc.2` 继续通过仓库的前端接口检查。
|
|
16
|
+
|
|
17
|
+
## 兼容范围
|
|
18
|
+
|
|
19
|
+
移动布局支持 0.1.5 的 keyed `main`、根级 `panelInfo`、导航生命周期和根级右栏,并保留较早宿主使用的 `conversation` 与 `details` 路径。
|
|
20
|
+
|
|
21
|
+
移动启动批处理对暂态上游连接失败执行有限重试,并让并发客户端共用一次独立于单个请求的组装任务。非法路径、非 200 响应和超限内容直接失败。
|
|
22
|
+
|
|
23
|
+
## 未覆盖路径
|
|
24
|
+
|
|
25
|
+
该次贡献者实测没有覆盖 Tailscale Funnel、cpolar 或自建 FRP。远程路径在正式发布前由维护者单独验证;局域网结果不作为远程服务可用性的证明。
|
|
26
|
+
|
|
27
|
+
本次适配不改变 Android 配对协议、证书模型或局域网 `setup` 命令。现有已配对 App 不需要因布局适配重新配对。
|
package/lib/client.js
CHANGED
|
@@ -110,7 +110,7 @@ window.__ModuleLoader__.load({
|
|
|
110
110
|
cpolarUnsupported: "Only Windows x64 is currently supported. You can still use the built-in Tailscale Funnel.",
|
|
111
111
|
cpolarNotInstalled: "Not installed. A fixed version is downloaded from the official cpolar website only after you click the button below.",
|
|
112
112
|
cpolarNeedsToken: "Official component {version} is verified. Save the account token to continue.",
|
|
113
|
-
cpolarReady: "Official component {version} and the local account configuration are ready.",
|
|
113
|
+
cpolarReady: "Official component {version} and the local account configuration are ready. Free temporary addresses may change after DSH or cpolar restarts; if the app cannot connect, scan the current remote QR code again.",
|
|
114
114
|
remoteOff: "Remote access is disabled. Local network access is unaffected.",
|
|
115
115
|
remoteUnavailableCpolar: "cpolar is not installed or its local account is not configured.",
|
|
116
116
|
remoteUnavailableTailscale: "This computer is missing the Funnel runtime component. Reinstall the complete plugin package.",
|
|
@@ -277,7 +277,7 @@ window.__ModuleLoader__.load({
|
|
|
277
277
|
cpolarUnsupported: "Attualmente è supportato solo Windows x64. Puoi comunque usare Tailscale Funnel integrato.",
|
|
278
278
|
cpolarNotInstalled: "Non installato. Una versione fissa viene scaricata dal sito ufficiale cpolar solo dopo aver premuto il pulsante.",
|
|
279
279
|
cpolarNeedsToken: "Componente ufficiale {version} verificato. Salva il token account per continuare.",
|
|
280
|
-
cpolarReady: "Componente ufficiale {version} e configurazione account locale pronti.",
|
|
280
|
+
cpolarReady: "Componente ufficiale {version} e configurazione account locale pronti. Gli indirizzi temporanei gratuiti possono cambiare dopo il riavvio di DSH o cpolar; se l’app non si connette, scansiona di nuovo il QR remoto corrente.",
|
|
281
281
|
remoteOff: "Accesso remoto disattivato. La rete locale non è interessata.",
|
|
282
282
|
remoteUnavailableCpolar: "cpolar non è installato o l’account locale non è configurato.",
|
|
283
283
|
remoteUnavailableTailscale: "Su questo computer manca il componente runtime Funnel. Reinstalla il pacchetto completo del plugin.",
|
|
@@ -446,7 +446,7 @@ window.__ModuleLoader__.load({
|
|
|
446
446
|
cpolarUnsupported: "当前仅支持 Windows x64。你仍可选择内置的 Tailscale Funnel。",
|
|
447
447
|
cpolarNotInstalled: "尚未安装。只有点击下方按钮后,才会从 cpolar 官网下载固定版本。",
|
|
448
448
|
cpolarNeedsToken: "官方组件 {version} 已校验,下一步只需保存账号令牌。",
|
|
449
|
-
cpolarReady: "官方组件 {version}
|
|
449
|
+
cpolarReady: "官方组件 {version} 与本机账号配置已就绪。免费临时地址可能在 DSH 或 cpolar 重启后变化;App 无法连接时,请重新扫描当前远程二维码。",
|
|
450
450
|
remoteOff: "远程访问未启用。局域网访问不受影响。",
|
|
451
451
|
remoteUnavailableCpolar: "cpolar 尚未安装或未完成本机账号配置。",
|
|
452
452
|
remoteUnavailableTailscale: "当前电脑缺少 Funnel 运行组件,请重新安装完整插件包。",
|
|
@@ -1131,9 +1131,25 @@ window.__ModuleLoader__.load({
|
|
|
1131
1131
|
}
|
|
1132
1132
|
//#endregion
|
|
1133
1133
|
//#region src/native-mobile.ts
|
|
1134
|
+
/**
|
|
1135
|
+
* Viewport below which the injected chrome becomes an overlay drawer: the
|
|
1136
|
+
* sidebar slides in as a sheet, the right panel as a drawer, and the scrim dims
|
|
1137
|
+
* the page behind them. The stylesheet and the scrim's visibility both read
|
|
1138
|
+
* this query, so a wider viewport never grows drawer chrome whose rules cannot
|
|
1139
|
+
* style it.
|
|
1140
|
+
*/
|
|
1141
|
+
const NATIVE_MOBILE_OVERLAY_QUERY = "(max-width:720px)";
|
|
1134
1142
|
/** Mobile feature and compatibility rules applied to DSH React surfaces. */
|
|
1135
1143
|
const NATIVE_MOBILE_STYLES = `
|
|
1136
|
-
|
|
1144
|
+
/* The surface appends chrome to <body> on every non-loopback page load, but
|
|
1145
|
+
every rule that gives that chrome a box lives inside the overlay query
|
|
1146
|
+
below. Outside the query the scrim kept the UA button box: an empty,
|
|
1147
|
+
nameless button in normal flow at the document's bottom-left, whose click
|
|
1148
|
+
still collapsed the sidebar. Keep the neutral state explicitly invisible —
|
|
1149
|
+
the query restores the fixed scrim, and its more specific [hidden] rule
|
|
1150
|
+
keeps winning there. */
|
|
1151
|
+
.dsh-native-mobile-backdrop,.dsh-mobile-branch-toast,.dsh-mobile-media-toast { display:none; }
|
|
1152
|
+
@media ${NATIVE_MOBILE_OVERLAY_QUERY} {
|
|
1137
1153
|
html.dsh-native-mobile-active,html.dsh-native-mobile-active body { width:100%; height:100%; overflow:hidden; }
|
|
1138
1154
|
html.dsh-native-mobile-active { --dsh-mobile-motion-duration:200ms; --dsh-mobile-motion-ease:cubic-bezier(.22,1,.36,1); }
|
|
1139
1155
|
html.dsh-native-mobile-active :is(a,button,[role="button"],[role="tab"],[tabindex]) { -webkit-tap-highlight-color:transparent; }
|
|
@@ -1178,7 +1194,7 @@ window.__ModuleLoader__.load({
|
|
|
1178
1194
|
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) > :not([data-dsh-mobile-toggle]) { display:none !important; }
|
|
1179
1195
|
[data-dsh-mobile-toggle] { width:44px !important; height:44px !important; min-width:44px !important; min-height:44px !important; }
|
|
1180
1196
|
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-toggle] > svg[class*="_railFish"] { transform:translateY(-4px) !important; }
|
|
1181
|
-
.dsh-native-mobile-backdrop { position:fixed; z-index:235; inset:env(safe-area-inset-top) 0 0; border:0; background:rgb(15 23 42 / 32%); }
|
|
1197
|
+
.dsh-native-mobile-backdrop { display:block; position:fixed; z-index:235; inset:env(safe-area-inset-top) 0 0; border:0; background:rgb(15 23 42 / 32%); }
|
|
1182
1198
|
.dsh-native-mobile-backdrop:not([hidden]) { animation:dsh-mobile-fade-in var(--dsh-mobile-motion-duration) ease-out; }
|
|
1183
1199
|
.dsh-native-mobile-backdrop[hidden] { display:none; }
|
|
1184
1200
|
[data-dsh-mobile-details] { position:fixed !important; z-index:250 !important; inset:0 0 0 auto !important; width:min(94vw,460px) !important; max-width:none !important; transform:translateX(100%); transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); background:var(--dsw-bg, #fff); box-shadow:-18px 0 46px rgb(15 23 42 / 18%); }
|
|
@@ -1234,6 +1250,8 @@ window.__ModuleLoader__.load({
|
|
|
1234
1250
|
[data-dsh-mobile-message-column] [data-context-fields] > * { display:grid !important; grid-template-columns:minmax(72px,30%) minmax(0,1fr) !important; gap:4px 10px !important; }
|
|
1235
1251
|
[data-dsh-mobile-message-column] [class*="_ioSection"] { grid-template-columns:1fr !important; row-gap:4px !important; }
|
|
1236
1252
|
[data-dsh-mobile-message-column] [class*="_body"] { max-width:100% !important; overflow-wrap:anywhere; }
|
|
1253
|
+
/* Keep folded and expanded reasoning visually separate from the reply. */
|
|
1254
|
+
[data-dsh-mobile-message-column] [class*="_body"] > div:has(> [data-variant="think"]) { margin-bottom:12px !important; }
|
|
1237
1255
|
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"],
|
|
1238
1256
|
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }
|
|
1239
1257
|
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"] [class*="_sep"],
|
|
@@ -1261,7 +1279,7 @@ window.__ModuleLoader__.load({
|
|
|
1261
1279
|
[data-dsh-mobile-center] [role="dialog"][aria-label*="Context"] [class*="_rows"] > [class*="_row"] { display:flex !important; align-items:center !important; justify-content:space-between !important; width:100% !important; min-width:0 !important; white-space:nowrap !important; }
|
|
1262
1280
|
[data-dsh-mobile-center] [role="dialog"][aria-label*="上下文"] :is(dt,dd),
|
|
1263
1281
|
[data-dsh-mobile-center] [role="dialog"][aria-label*="Context"] :is(dt,dd) { white-space:nowrap !important; word-break:keep-all !important; }
|
|
1264
|
-
.dsh-mobile-branch-toast,.dsh-mobile-media-toast { position:fixed; z-index:330; top:max(12px,env(safe-area-inset-top)); left:50%; max-width:calc(100vw - 32px); box-sizing:border-box; padding:7px 14px; border:1px solid rgb(15 23 42 / 10%); border-radius:999px; background:rgb(15 23 42 / 92%); color:#fff; font-size:13px; line-height:20px; text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; opacity:0; pointer-events:none; transform:translate(-50%,-8px); transition:opacity 160ms ease,transform 160ms ease; }
|
|
1282
|
+
.dsh-mobile-branch-toast,.dsh-mobile-media-toast { display:block; position:fixed; z-index:330; top:max(12px,env(safe-area-inset-top)); left:50%; max-width:calc(100vw - 32px); box-sizing:border-box; padding:7px 14px; border:1px solid rgb(15 23 42 / 10%); border-radius:999px; background:rgb(15 23 42 / 92%); color:#fff; font-size:13px; line-height:20px; text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; opacity:0; pointer-events:none; transform:translate(-50%,-8px); transition:opacity 160ms ease,transform 160ms ease; }
|
|
1265
1283
|
.dsh-mobile-branch-toast[data-visible="true"],.dsh-mobile-media-toast[data-visible="true"] { opacity:1; transform:translate(-50%,0); }
|
|
1266
1284
|
.dsh-mobile-media-shortcuts { box-sizing:border-box; display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px; width:100%; padding:4px 4px 8px; margin-bottom:4px; border-bottom:1px solid var(--dsw-alias-border-inverted,var(--dsw-alias-border-subtle,rgb(148 163 184 / 28%))); }
|
|
1267
1285
|
.dsh-mobile-media-action { box-sizing:border-box; display:flex; align-items:center; justify-content:flex-start; gap:8px; width:100%; min-width:0; min-height:44px; padding:8px 10px; border:0; border-radius:10px; background:var(--dsw-alias-interactive-bg-hover,rgb(148 163 184 / 12%)); color:var(--dsw-alias-label-primary,inherit); cursor:pointer; font:inherit; font-size:14px; line-height:22px; text-align:left; touch-action:manipulation; }
|
|
@@ -1375,6 +1393,18 @@ window.__ModuleLoader__.load({
|
|
|
1375
1393
|
function shouldAutoLoadEarlier(previousTop, currentTop) {
|
|
1376
1394
|
return currentTop <= AUTO_HISTORY_THRESHOLD_PX && currentTop < previousTop - .5;
|
|
1377
1395
|
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Whether the overlay scrim belongs on screen. The scrim exists for the
|
|
1398
|
+
* slide-in drawer only — it dims the page and catches the tap that closes the
|
|
1399
|
+
* drawer — so it is shown while that drawer is open *and* the overlay query is
|
|
1400
|
+
* in force. `hidden` carries the whole decision rather than the width rules
|
|
1401
|
+
* alone: the attribute still hides the element when the injected stylesheet
|
|
1402
|
+
* never lands (a CSP without inline styles, a shell that drops the <style>
|
|
1403
|
+
* node), where the element would otherwise fall back to the UA button box.
|
|
1404
|
+
*/
|
|
1405
|
+
function drawerScrimVisible(sidebarCollapsed, overlayActive) {
|
|
1406
|
+
return !sidebarCollapsed && overlayActive;
|
|
1407
|
+
}
|
|
1378
1408
|
/** Check that an asynchronous picker result still belongs to its originating session and composer. */
|
|
1379
1409
|
function isComposerMediaOriginCurrent(origin, current) {
|
|
1380
1410
|
return !current.disposed && origin.generation === current.generation && origin.href === current.href && origin.composer !== null && current.composerConnected && origin.composer === current.composer && origin.sessionRoot !== null && origin.sessionRoot === current.sessionRoot && origin.sessionId !== null && origin.sessionId === current.sessionId;
|
|
@@ -1434,6 +1464,7 @@ window.__ModuleLoader__.load({
|
|
|
1434
1464
|
};
|
|
1435
1465
|
document.addEventListener("pointerdown", onPointerDown, true);
|
|
1436
1466
|
document.addEventListener("keydown", onKeyDown, true);
|
|
1467
|
+
const overlayQuery = window.matchMedia(NATIVE_MOBILE_OVERLAY_QUERY);
|
|
1437
1468
|
const backdrop = document.createElement("button");
|
|
1438
1469
|
backdrop.type = "button";
|
|
1439
1470
|
backdrop.className = "dsh-native-mobile-backdrop";
|
|
@@ -1843,7 +1874,7 @@ window.__ModuleLoader__.load({
|
|
|
1843
1874
|
if (toggle !== void 0) toggle.dataset.dshMobileToggle = "true";
|
|
1844
1875
|
const collapsed = classToken(sidebarRoot, "_collapsed");
|
|
1845
1876
|
sidebar.dataset.open = String(!collapsed);
|
|
1846
|
-
backdrop.hidden = collapsed;
|
|
1877
|
+
backdrop.hidden = !drawerScrimVisible(collapsed, overlayQuery.matches);
|
|
1847
1878
|
};
|
|
1848
1879
|
const schedule = () => {
|
|
1849
1880
|
if (scheduled === 0) scheduled = requestAnimationFrame(sync);
|
|
@@ -1863,6 +1894,7 @@ window.__ModuleLoader__.load({
|
|
|
1863
1894
|
"data-dsh-mobile-session"
|
|
1864
1895
|
]
|
|
1865
1896
|
});
|
|
1897
|
+
overlayQuery.addEventListener("change", schedule);
|
|
1866
1898
|
backdrop.addEventListener("click", () => {
|
|
1867
1899
|
if (sidebar?.dataset.open === "true") toggle?.click();
|
|
1868
1900
|
});
|
|
@@ -1874,6 +1906,7 @@ window.__ModuleLoader__.load({
|
|
|
1874
1906
|
restoreLanguageMarker();
|
|
1875
1907
|
for (const cleanup of [...browserPickerCleanups]) cleanup();
|
|
1876
1908
|
observer.disconnect();
|
|
1909
|
+
overlayQuery.removeEventListener("change", schedule);
|
|
1877
1910
|
document.removeEventListener("click", onBranchClick, true);
|
|
1878
1911
|
fileButton.removeEventListener("pointerdown", quietMediaPointer);
|
|
1879
1912
|
cameraButton.removeEventListener("pointerdown", quietMediaPointer);
|
|
@@ -5299,7 +5332,7 @@ window.__ModuleLoader__.load({
|
|
|
5299
5332
|
@keyframes dsh-diagnostic-spin{to{transform:rotate(360deg)}}@keyframes dsh-diagnostic-reveal{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
|
|
5300
5333
|
.dsh-mobile-control__actions{display:flex;flex-wrap:nowrap;gap:6px}.dsh-mobile-control__actions button{flex:1 1 0;min-width:0;min-height:40px;padding:8px 4px;border-radius:10px;font:12px/1.2 system-ui;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}
|
|
5301
5334
|
.dsh-mobile-control button:focus-visible,.dsh-mobile-control a:focus-visible,.dsh-mobile-control input:focus-visible,.dsh-mobile-control summary:focus-visible{outline:3px solid rgb(37 99 235 / 28%);outline-offset:2px}
|
|
5302
|
-
.dsh-mobile-control__trigger{box-sizing:border-box;flex:
|
|
5335
|
+
.dsh-mobile-control__trigger{box-sizing:border-box;flex:1 1 auto;display:flex;align-items:center;gap:8px;width:100%;height:42px;margin:4px 0;padding:0 10px 0 8px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font-family:inherit;font-size:14px;line-height:22px;cursor:pointer;overflow:hidden}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger:active,.dsh-mobile-control__trigger[aria-expanded="true"]{background:var(--dsw-alias-interactive-bg-active,#e8ebf0)}.dsh-mobile-control__trigger:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:2px}.dsh-mobile-control__trigger.is-rail{flex:0 0 auto;width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;gap:0;border-radius:50%}.dsh-mobile-control__trigger-icon{display:block;flex:none}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
|
|
5303
5336
|
.dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__ws-paths{margin:10px 0 0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__ws-paths-list{margin:0 0 8px;padding:0;list-style:none}.dsh-mobile-control__ws-paths-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px}.dsh-mobile-control__ws-paths-item{display:flex;align-items:center;gap:8px;padding:6px 0}.dsh-mobile-control__ws-paths-item + .dsh-mobile-control__ws-paths-item{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__ws-paths-item code{flex:1 1 0;min-width:0;overflow:hidden;font:11px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__ws-paths-remove{flex:none;min-height:28px;padding:4px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:8px;background:transparent;color:inherit;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__trigger,.dsh-mobile-control__diagnostic-entry{position:relative}.dsh-mobile-control__ws-dot{position:absolute;top:2px;right:2px;z-index:1;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:#dc2626;color:#fff;font:650 10px/16px system-ui;text-align:center;cursor:pointer}.dsh-mobile-control__ws-dot::after{content:'';position:absolute;inset:-5px}.dsh-mobile-control__ws-sr-status{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.dsh-mobile-control__ws-paths-row{display:flex;gap:8px}.dsh-mobile-control__ws-paths-row .dsh-mobile-control__primary{width:auto;flex:none;padding:9px 14px;border-radius:10px}.dsh-mobile-control__ws-paths-group{padding:6px 0}.dsh-mobile-control__ws-paths-group + .dsh-mobile-control__ws-paths-group{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__ws-paths-group-head{display:flex;align-items:center;gap:8px}.dsh-mobile-control__ws-count{flex:none;padding:1px 7px;border-radius:999px;background:#e8f0ff;color:#1d4ed8;font:650 10px/1.6 system-ui}.dsh-mobile-control__ws-paths-item.is-child{padding-left:12px}.dsh-mobile-control__ws-paths-group-head .dsh-mobile-control__primary,.dsh-mobile-control__ws-paths-item .dsh-mobile-control__primary{width:auto;flex:none;min-height:34px;padding:6px 12px;border-radius:10px}.dsh-mobile-control__ws-paths-row input{flex:1 1 0;min-width:0;box-sizing:border-box;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__ws-paths-row button{flex:none}.dsh-mobile-control__ws-paths-detected-title{margin:0 0 2px;font:600 12px/1.4 system-ui}.dsh-mobile-control__ws-paths-advanced{margin-top:8px}.dsh-mobile-control__ws-paths-advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary,#606873);font:12px/1.4 system-ui;user-select:none}.dsh-mobile-control__ws-paths-advanced summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:2px;border-radius:4px}.dsh-mobile-control__ws-paths-advanced[open] summary{margin-bottom:6px}.dsh-mobile-control__ws-paths-advanced .dsh-mobile-control__status{margin:6px 0 0}
|
|
5304
5337
|
@media (max-width:359px){.dsh-mobile-control__provider-choices{grid-template-columns:1fr}.dsh-mobile-control__provider{min-height:68px}}@media (prefers-reduced-motion:reduce){.dsh-mobile-control__provider,.dsh-mobile-control__cpolar-connect{transition:none}.dsh-mobile-control__diagnostic-summary.is-running .dsh-mobile-control__diagnostic-summary-icon::before,.dsh-mobile-control__diagnostic-checks{animation:none}}
|
|
5305
5338
|
`;
|