dsh-mobile 0.3.10 → 0.3.11

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
@@ -3,6 +3,11 @@
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.11 - 2026-09-07
7
+
8
+ - Sync the browser tab title with the current session on the dedicated layout, matching the stock behavior (thanks @idoall for reporting #45).
9
+ - Allow installed plugins' WebSocket endpoints through the gateway via admin-approved exact paths (e.g. `/sidebar/ws/terminal`), managed in the remote panel behind local-admin trust; built-in DSH paths keep working and everything else stays blocked (thanks @idoall for reporting #47).
10
+
6
11
  ## 0.3.10 - 2026-09-07
7
12
 
8
13
  - Keep the workspace sidebar open on desktop-sized viewports (≥900px): the dedicated layout docks it as a persistent panel that survives reconnects and no longer auto-closes after selecting a session, and the dimming scrim only covers the narrow overlay drawer and details panel. Narrow screens keep the overlay drawer behavior unchanged (thanks @idoall for reporting #42).
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.10 update**: thanks to @idoall for reporting — on wide viewports (≥900px) the session sidebar now stays open until explicitly collapsed; plugin-market storefront screenshots are declared. [Details](CHANGELOG.md).
22
+ > **0.3.11 update**: remote pages follow the current session in the browser tab (#45); third-party plugin WebSockets can be approved by the admin (e.g. terminals, #47). Thanks @idoall for reporting. [Details](CHANGELOG.md).
23
23
  >
24
- > **Upgrade reminder**: Windows DSH Desktop users should update to plugin 0.3.10. Existing 0.3.3-0.3.9 apps and paired devices remain compatible without re-pairing. [Compatibility notes](#compatibility).
24
+ > **Upgrade reminder**: Windows DSH Desktop users should update to plugin 0.3.11. Existing 0.3.3-0.3.10 apps and paired devices remain compatible without re-pairing. [Compatibility notes](#compatibility).
25
25
 
26
26
  <p align="center">
27
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.10/dsh-mobile-android-v0.3.10.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.10/dsh-mobile-android-v0.3.10.apk"><strong>Download Android app 0.3.10</strong></a><br>
29
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.10">Release notes and checksums</a></sub>
27
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.11/dsh-mobile-android-v0.3.11.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.11/dsh-mobile-android-v0.3.11.apk"><strong>Download Android app 0.3.11</strong></a><br>
29
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.11">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.
@@ -198,14 +198,14 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
198
198
 
199
199
  | DSH Mobile plugin | Verified DeepSeek Harness version |
200
200
  | --- | --- |
201
- | `0.3.10` | `0.1.3-alpha.1` |
201
+ | `0.3.10`, `0.3.11` | `0.1.3-alpha.1` |
202
202
  | `0.3.9` | `0.1.3-alpha.1` |
203
203
  | `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
204
204
  | `0.3.4`, `0.3.5` | `0.1.2-alpha.2` |
205
205
  | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
206
206
  | `0.1.4`, `0.2.x` | `0.1.1-rc.2` |
207
207
 
208
- Existing 0.3.3-0.3.9 apps do not need re-pairing. Earlier apps use a different status-bar strategy, so updating both is recommended. App 0.1.3 or earlier requires reinstalling and pairing again.
208
+ Existing 0.3.3-0.3.10 apps do not need re-pairing. Earlier apps use a different status-bar strategy, so updating both is recommended. App 0.1.3 or earlier requires reinstalling and pairing again.
209
209
 
210
210
  ## Uninstall
211
211
 
package/README.md CHANGED
@@ -26,14 +26,14 @@
26
26
 
27
27
  > DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
28
28
  >
29
- > **0.3.10 更新**:感谢 @idoall 反馈,大屏(≥900px)会话侧边栏不再自动收起,常驻显示直到手动关闭;同时声明插件市场展示截图。[详细记录](CHANGELOG.md)。
29
+ > **0.3.11 更新**:远程页浏览器标签页跟随当前会话标题(#45);第三方插件 WebSocket 可经管理员批准放行(如终端,#47)。感谢 @idoall 反馈。[详细记录](CHANGELOG.md)。
30
30
  >
31
- > **升级提醒**:Windows DSH Desktop 用户请更新至插件 0.3.10;现有 0.3.3-0.3.9 App 可继续使用,无需重新配对。[兼容说明](#兼容性)。
31
+ > **升级提醒**:Windows DSH Desktop 用户请更新至插件 0.3.11;现有 0.3.3-0.3.10 App 可继续使用,无需重新配对。[兼容说明](#兼容性)。
32
32
 
33
33
  <p align="center">
34
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.10/dsh-mobile-android-v0.3.10.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.10/dsh-mobile-android-v0.3.10.apk"><strong>下载 Android App 0.3.10</strong></a><br>
36
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.10">版本说明与校验文件</a></sub>
34
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.11/dsh-mobile-android-v0.3.11.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.11/dsh-mobile-android-v0.3.11.apk"><strong>下载 Android App 0.3.11</strong></a><br>
36
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.11">版本说明与校验文件</a></sub>
37
37
  </p>
38
38
 
39
39
  DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
@@ -207,14 +207,14 @@ flowchart LR
207
207
 
208
208
  | DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
209
209
  | --- | --- |
210
- | `0.3.10` | `0.1.3-alpha.1` |
210
+ | `0.3.10`、`0.3.11` | `0.1.3-alpha.1` |
211
211
  | `0.3.9` | `0.1.3-alpha.1` |
212
212
  | `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
213
213
  | `0.3.4`、`0.3.5` | `0.1.2-alpha.2` |
214
214
  | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
215
215
  | `0.1.4`、`0.2.x` | `0.1.1-rc.2` |
216
216
 
217
- 现有 0.3.3-0.3.9 App 无需重新配对;更早的 App 使用不同的状态栏策略,建议同步升级;App 0.1.3 及更早版本需卸载重装并重新配对。
217
+ 现有 0.3.3-0.3.10 App 无需重新配对;更早的 App 使用不同的状态栏策略,建议同步升级;App 0.1.3 及更早版本需卸载重装并重新配对。
218
218
 
219
219
  ## 卸载
220
220
 
package/lib/client.js CHANGED
@@ -151,7 +151,14 @@ window.__ModuleLoader__.load({
151
151
  remoteQrReady: "Remote pairing QR code generated. Scan it from “Remote access” in the app.",
152
152
  resetCpolarConfirm: "Disable the cpolar remote channel and remove all remote paired devices? Your cpolar account and other tunnels are unchanged.",
153
153
  resetTailscaleConfirm: "Sign out of Tailscale on this computer and remove all remote paired devices? Local network configuration is unchanged.",
154
- requestFailed: "Request failed: {error}"
154
+ requestFailed: "Request failed: {error}",
155
+ wsPathsTitle: "Third-party WebSocket paths",
156
+ wsPathsIntro: "Let installed plugins’ WebSocket endpoints (exact paths such as /sidebar/ws/terminal) work through the gateway. Built-in DSH paths always work; everything else stays blocked.",
157
+ wsPathsPlaceholder: "/sidebar/ws/terminal",
158
+ wsPathsAdd: "Allow path",
159
+ wsPathsRemove: "Remove",
160
+ wsPathsEmpty: "No extra paths allowed.",
161
+ wsPathsInvalid: "Enter an exact path starting with / (no query string)."
155
162
  },
156
163
  it: {
157
164
  mobileAccess: "Accesso mobile",
@@ -297,7 +304,14 @@ window.__ModuleLoader__.load({
297
304
  remoteQrReady: "QR di abbinamento remoto generato. Scansionalo da “Accesso remoto” nell’app.",
298
305
  resetCpolarConfirm: "Disattivare il canale remoto cpolar e rimuovere tutti i dispositivi remoti? Account cpolar e altri tunnel restano invariati.",
299
306
  resetTailscaleConfirm: "Uscire da Tailscale su questo computer e rimuovere tutti i dispositivi remoti? La configurazione della rete locale resta invariata.",
300
- requestFailed: "Richiesta non riuscita: {error}"
307
+ requestFailed: "Richiesta non riuscita: {error}",
308
+ wsPathsTitle: "Percorsi WebSocket di terze parti",
309
+ wsPathsIntro: "Consenti agli endpoint WebSocket dei plugin installati (percorsi esatti come /sidebar/ws/terminal) di passare dal gateway. I percorsi DSH integrati funzionano sempre; tutto il resto resta bloccato.",
310
+ wsPathsPlaceholder: "/sidebar/ws/terminal",
311
+ wsPathsAdd: "Consenti percorso",
312
+ wsPathsRemove: "Rimuovi",
313
+ wsPathsEmpty: "Nessun percorso aggiuntivo consentito.",
314
+ wsPathsInvalid: "Inserisci un percorso esatto che inizi con / (senza query)."
301
315
  },
302
316
  zh: {}
303
317
  };
@@ -445,7 +459,14 @@ window.__ModuleLoader__.load({
445
459
  remoteQrReady: "远程配对二维码已生成。请在 App 的“远程访问”中扫描。",
446
460
  resetCpolarConfirm: "关闭 cpolar 远程通道并移除所有远程配对设备?不会修改你的 cpolar 账号或其他隧道。",
447
461
  resetTailscaleConfirm: "退出电脑上的 Tailscale 登录并移除所有远程配对设备?局域网配置不会改变。",
448
- requestFailed: "请求失败:{error}"
462
+ requestFailed: "请求失败:{error}",
463
+ wsPathsTitle: "第三方 WebSocket 路径",
464
+ wsPathsIntro: "允许已装插件的 WebSocket 端点(确切路径,如 /sidebar/ws/terminal)经网关通行。DSH 内置路径始终可用,其余一律拦截。",
465
+ wsPathsPlaceholder: "/sidebar/ws/terminal",
466
+ wsPathsAdd: "允许该路径",
467
+ wsPathsRemove: "移除",
468
+ wsPathsEmpty: "暂无额外允许的路径。",
469
+ wsPathsInvalid: "请输入以 / 开头的确切路径(不带 query)。"
449
470
  });
450
471
  Object.assign(MOBILE_CONTROL_MESSAGES.en, {
451
472
  selfHostedConnections: "Self-hosted connection",
@@ -2527,8 +2548,85 @@ window.__ModuleLoader__.load({
2527
2548
  remoteManageRow.append(remoteDevices, remoteReset);
2528
2549
  const remoteDevicePanel = element("div", "dsh-mobile-control__devices");
2529
2550
  remoteDevicePanel.hidden = true;
2551
+ const wsPathsSection = element("section", "dsh-mobile-control__ws-paths");
2552
+ const wsPathsTitle = element("h3", "dsh-mobile-control__section-title");
2553
+ wsPathsTitle.textContent = t("wsPathsTitle");
2554
+ const wsPathsIntro = element("p", "dsh-mobile-control__intro");
2555
+ wsPathsIntro.textContent = t("wsPathsIntro");
2556
+ const wsPathsList = element("ul", "dsh-mobile-control__ws-paths-list");
2557
+ const wsPathsRow = element("div", "dsh-mobile-control__ws-paths-row");
2558
+ const wsPathsInput = element("input", "dsh-mobile-control__ws-paths-input");
2559
+ wsPathsInput.type = "text";
2560
+ wsPathsInput.placeholder = t("wsPathsPlaceholder");
2561
+ wsPathsInput.setAttribute("aria-label", t("wsPathsTitle"));
2562
+ const wsPathsAdd = element("button", "dsh-mobile-control__secondary");
2563
+ wsPathsAdd.type = "button";
2564
+ wsPathsAdd.textContent = t("wsPathsAdd");
2565
+ const wsPathsStatus = element("p", "dsh-mobile-control__status");
2566
+ wsPathsStatus.hidden = true;
2567
+ wsPathsStatus.setAttribute("aria-live", "polite");
2568
+ wsPathsRow.append(wsPathsInput, wsPathsAdd);
2569
+ wsPathsSection.append(wsPathsTitle, wsPathsIntro, wsPathsList, wsPathsRow, wsPathsStatus);
2570
+ let wsPathsCurrent = [];
2571
+ let wsPathsLoaded = false;
2572
+ const renderWsPaths = (paths) => {
2573
+ wsPathsCurrent = [...paths];
2574
+ wsPathsList.replaceChildren();
2575
+ if (paths.length === 0) {
2576
+ const empty = element("li", "dsh-mobile-control__ws-paths-empty");
2577
+ empty.textContent = t("wsPathsEmpty");
2578
+ wsPathsList.append(empty);
2579
+ }
2580
+ for (const path of paths) {
2581
+ const item = element("li", "dsh-mobile-control__ws-paths-item");
2582
+ const label = element("code");
2583
+ label.textContent = path;
2584
+ const remove = element("button", "dsh-mobile-control__ws-paths-remove");
2585
+ remove.type = "button";
2586
+ remove.textContent = t("wsPathsRemove");
2587
+ remove.setAttribute("aria-label", `${t("wsPathsRemove")}: ${path}`);
2588
+ remove.addEventListener("click", () => {
2589
+ saveWsPaths(wsPathsCurrent.filter((entry) => entry !== path));
2590
+ });
2591
+ item.append(label, remove);
2592
+ wsPathsList.append(item);
2593
+ }
2594
+ };
2595
+ const loadWsPaths = () => {
2596
+ controlRequestJson("/api/mobile-access/remote/websocket-paths").then((data) => {
2597
+ wsPathsLoaded = true;
2598
+ wsPathsStatus.hidden = true;
2599
+ renderWsPaths(Array.isArray(data.paths) ? data.paths.filter((entry) => typeof entry === "string") : []);
2600
+ }, (error) => {
2601
+ wsPathsStatus.hidden = false;
2602
+ wsPathsStatus.textContent = t("requestFailed", { error: String(error) });
2603
+ });
2604
+ };
2605
+ const saveWsPaths = (paths) => {
2606
+ wsPathsStatus.hidden = true;
2607
+ controlRequestJson("/api/mobile-access/remote/websocket-paths", {
2608
+ method: "POST",
2609
+ body: JSON.stringify({ paths })
2610
+ }).then((data) => {
2611
+ wsPathsLoaded = true;
2612
+ renderWsPaths(Array.isArray(data.paths) ? data.paths.filter((entry) => typeof entry === "string") : []);
2613
+ }, (error) => {
2614
+ wsPathsStatus.hidden = false;
2615
+ wsPathsStatus.textContent = t("requestFailed", { error: String(error) });
2616
+ });
2617
+ };
2618
+ wsPathsAdd.addEventListener("click", () => {
2619
+ const value = wsPathsInput.value.trim();
2620
+ if (value === "") {
2621
+ wsPathsStatus.hidden = false;
2622
+ wsPathsStatus.textContent = t("wsPathsInvalid");
2623
+ return;
2624
+ }
2625
+ wsPathsInput.value = "";
2626
+ saveWsPaths([...wsPathsCurrent, value]);
2627
+ });
2530
2628
  const remoteWorkspace = element("section", "dsh-mobile-control__remote-workspace");
2531
- remoteWorkspace.append(providerSetupHeader, remoteStatus, remoteAccess, remoteGuide, providerSetupBody, remoteActions, remoteQr, remoteManageRow, remoteDevicePanel);
2629
+ remoteWorkspace.append(providerSetupHeader, remoteStatus, remoteAccess, remoteGuide, providerSetupBody, remoteActions, remoteQr, remoteManageRow, remoteDevicePanel, wsPathsSection);
2532
2630
  const diagnosticsView = element("div", "dsh-mobile-control__view is-diagnostics");
2533
2631
  diagnosticsView.hidden = true;
2534
2632
  const diagnosticsIntro = element("p", "dsh-mobile-control__intro");
@@ -2669,6 +2767,7 @@ window.__ModuleLoader__.load({
2669
2767
  remoteTab.addEventListener("click", () => {
2670
2768
  selectView("remote");
2671
2769
  loadRemote();
2770
+ if (!wsPathsLoaded) loadWsPaths();
2672
2771
  });
2673
2772
  const setOpen = (open) => {
2674
2773
  panel.hidden = !open;
@@ -5003,7 +5102,7 @@ window.__ModuleLoader__.load({
5003
5102
  .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}
5004
5103
  .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}
5005
5104
  .dsh-mobile-control__trigger{box-sizing:border-box;flex:none;display:flex;align-items:center;gap:8px;width:calc(100% + 4px);height:42px;margin:4px -2px;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{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}
5006
- .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}
5105
+ .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__ws-paths-row{display:flex;gap:8px}.dsh-mobile-control__ws-paths-row input{flex:1 1 0;min-width:0;box-sizing:border-box;min-height:40px;padding:8px 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:14px/1.4 system-ui}.dsh-mobile-control__ws-paths-row button{flex:none}
5007
5106
  @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}}
5008
5107
  `;
5009
5108
  /** Mount the desktop control or mobile feature enhancements. */