@linxin666/dsh-remote-web-ui 0.3.6 → 0.3.9

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.
Files changed (238) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +77 -468
  3. package/README.zh.md +83 -113
  4. package/lib/client.js +955 -203
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +1136 -1466
  7. package/lib/types/client/FooterRemoteEntry.d.ts +6 -7
  8. package/lib/types/client/FooterRemoteEntry.d.ts.map +1 -1
  9. package/lib/types/client/FooterRemoteEntry.js +1 -1
  10. package/lib/types/client/RemoteEntry.d.ts +7 -4
  11. package/lib/types/client/RemoteEntry.d.ts.map +1 -1
  12. package/lib/types/client/RemoteEntry.js +7 -10
  13. package/lib/types/client/RemotePanel.d.ts +2 -2
  14. package/lib/types/client/RemotePanel.d.ts.map +1 -1
  15. package/lib/types/client/RemotePanel.js +2 -2
  16. package/lib/types/client/RemoteSettingsCard.d.ts +9 -5
  17. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
  18. package/lib/types/client/RemoteSettingsCard.js +56 -3
  19. package/lib/types/client/deep-link.d.ts +10 -13
  20. package/lib/types/client/deep-link.d.ts.map +1 -1
  21. package/lib/types/client/deep-link.js +14 -74
  22. package/lib/types/client/index.d.ts +2 -6
  23. package/lib/types/client/index.d.ts.map +1 -1
  24. package/lib/types/client/index.js +73 -39
  25. package/lib/types/client/locales.d.ts +26 -12
  26. package/lib/types/client/locales.d.ts.map +1 -1
  27. package/lib/types/client/locales.js +36 -22
  28. package/lib/types/client/mobile-adapt.d.ts +40 -0
  29. package/lib/types/client/mobile-adapt.d.ts.map +1 -0
  30. package/lib/types/client/mobile-adapt.js +967 -0
  31. package/lib/types/client/pair-api.d.ts +24 -6
  32. package/lib/types/client/pair-api.d.ts.map +1 -1
  33. package/lib/types/client/pair-api.js +9 -14
  34. package/lib/types/client/remote-channel.d.ts +3 -0
  35. package/lib/types/client/remote-channel.d.ts.map +1 -1
  36. package/lib/types/client/remote-channel.js +35 -3
  37. package/lib/types/client/settings-form.d.ts +35 -43
  38. package/lib/types/client/settings-form.d.ts.map +1 -1
  39. package/lib/types/client/settings-form.js +60 -53
  40. package/lib/types/firewall.d.ts +75 -0
  41. package/lib/types/firewall.d.ts.map +1 -0
  42. package/lib/types/firewall.js +184 -0
  43. package/lib/types/gate.d.ts +11 -5
  44. package/lib/types/gate.d.ts.map +1 -1
  45. package/lib/types/gate.js +11 -5
  46. package/lib/types/index.d.ts +39 -10
  47. package/lib/types/index.d.ts.map +1 -1
  48. package/lib/types/index.js +206 -58
  49. package/lib/types/inner-auth.d.ts +32 -0
  50. package/lib/types/inner-auth.d.ts.map +1 -0
  51. package/lib/types/inner-auth.js +72 -0
  52. package/lib/types/lan-bind-plan.d.ts +55 -0
  53. package/lib/types/lan-bind-plan.d.ts.map +1 -0
  54. package/lib/types/lan-bind-plan.js +60 -0
  55. package/lib/types/lan-bind.d.ts +69 -0
  56. package/lib/types/lan-bind.d.ts.map +1 -0
  57. package/lib/types/lan-bind.js +128 -0
  58. package/lib/types/loopback-proxy.d.ts +9 -2
  59. package/lib/types/loopback-proxy.d.ts.map +1 -1
  60. package/lib/types/loopback-proxy.js +24 -2
  61. package/lib/types/pairing.d.ts +15 -3
  62. package/lib/types/pairing.d.ts.map +1 -1
  63. package/lib/types/pairing.js +20 -6
  64. package/lib/types/remote-api.d.ts +30 -13
  65. package/lib/types/remote-api.d.ts.map +1 -1
  66. package/lib/types/remote-api.js +55 -42
  67. package/lib/types/remote-channel-boot.d.ts +21 -2
  68. package/lib/types/remote-channel-boot.d.ts.map +1 -1
  69. package/lib/types/remote-channel-boot.js +65 -3
  70. package/lib/types/remote-channel-rules.d.ts +8 -0
  71. package/lib/types/remote-channel-rules.d.ts.map +1 -1
  72. package/lib/types/remote-channel-rules.js +9 -2
  73. package/lib/types/remote-methods.d.ts +45 -11
  74. package/lib/types/remote-methods.d.ts.map +1 -1
  75. package/lib/types/remote-methods.js +56 -27
  76. package/lib/types/remote-presence-pet.d.ts +51 -0
  77. package/lib/types/remote-presence-pet.d.ts.map +1 -0
  78. package/lib/types/remote-presence-pet.js +101 -0
  79. package/lib/types/routes.d.ts +76 -4
  80. package/lib/types/routes.d.ts.map +1 -1
  81. package/lib/types/routes.js +336 -19
  82. package/lib/types/tunnel.d.ts.map +1 -1
  83. package/lib/types/tunnel.js +7 -1
  84. package/package.json +20 -18
  85. package/src/client/FooterRemoteEntry.tsx +9 -10
  86. package/src/client/RemoteEntry.tsx +13 -14
  87. package/src/client/RemotePanel.tsx +5 -16
  88. package/src/client/RemoteSettingsCard.tsx +72 -13
  89. package/src/client/deep-link.ts +14 -75
  90. package/src/client/index.ts +77 -39
  91. package/src/client/locales.ts +36 -22
  92. package/src/client/mobile-adapt.ts +913 -0
  93. package/src/client/pair-api.ts +26 -15
  94. package/src/client/remote-channel.ts +31 -3
  95. package/src/client/settings-form.ts +78 -92
  96. package/src/dsh-home.ts +1 -1
  97. package/src/firewall.ts +230 -0
  98. package/src/gate.ts +11 -5
  99. package/src/index.ts +235 -65
  100. package/src/inner-auth.ts +85 -0
  101. package/src/lan-bind-plan.ts +81 -0
  102. package/src/lan-bind.ts +145 -0
  103. package/src/loopback-proxy.ts +34 -0
  104. package/src/pairing.persist.test.ts +1 -1
  105. package/src/pairing.ts +20 -6
  106. package/src/remote-api.ts +67 -45
  107. package/src/remote-channel-boot.ts +70 -3
  108. package/src/remote-channel-rules.ts +17 -2
  109. package/src/remote-methods.ts +58 -27
  110. package/src/remote-presence-pet.ts +129 -0
  111. package/src/routes.ts +358 -19
  112. package/src/tunnel.ts +7 -1
  113. package/assets/apple-touch-icon.png +0 -0
  114. package/assets/mobile-icon-192.png +0 -0
  115. package/assets/mobile-icon-512.png +0 -0
  116. package/assets/mobile-service-worker.js +0 -63
  117. package/lib/mobile.js +0 -17658
  118. package/lib/mobile.js.map +0 -1
  119. package/lib/types/mobile/PairRequiredView.d.ts +0 -7
  120. package/lib/types/mobile/PairRequiredView.d.ts.map +0 -1
  121. package/lib/types/mobile/PairRequiredView.js +0 -28
  122. package/lib/types/mobile/PairRequiredView.test.d.ts +0 -2
  123. package/lib/types/mobile/PairRequiredView.test.d.ts.map +0 -1
  124. package/lib/types/mobile/PairRequiredView.test.js +0 -24
  125. package/lib/types/mobile/api.d.ts +0 -145
  126. package/lib/types/mobile/api.d.ts.map +0 -1
  127. package/lib/types/mobile/api.js +0 -103
  128. package/lib/types/mobile/index.d.ts +0 -10
  129. package/lib/types/mobile/index.d.ts.map +0 -1
  130. package/lib/types/mobile/index.js +0 -38
  131. package/lib/types/mobile/markdown.d.ts +0 -34
  132. package/lib/types/mobile/markdown.d.ts.map +0 -1
  133. package/lib/types/mobile/markdown.js +0 -285
  134. package/lib/types/mobile/markdown.test.d.ts +0 -2
  135. package/lib/types/mobile/markdown.test.d.ts.map +0 -1
  136. package/lib/types/mobile/markdown.test.js +0 -79
  137. package/lib/types/mobile/messages.d.ts +0 -149
  138. package/lib/types/mobile/messages.d.ts.map +0 -1
  139. package/lib/types/mobile/messages.js +0 -561
  140. package/lib/types/mobile/messages.test.d.ts +0 -2
  141. package/lib/types/mobile/messages.test.d.ts.map +0 -1
  142. package/lib/types/mobile/messages.test.js +0 -356
  143. package/lib/types/mobile/mobile-styles.d.ts +0 -6
  144. package/lib/types/mobile/mobile-styles.d.ts.map +0 -1
  145. package/lib/types/mobile/mobile-styles.js +0 -1438
  146. package/lib/types/mobile/mobile-theme.d.ts +0 -22
  147. package/lib/types/mobile/mobile-theme.d.ts.map +0 -1
  148. package/lib/types/mobile/mobile-theme.js +0 -70
  149. package/lib/types/mobile/mobile-theme.test.d.ts +0 -2
  150. package/lib/types/mobile/mobile-theme.test.d.ts.map +0 -1
  151. package/lib/types/mobile/mobile-theme.test.js +0 -71
  152. package/lib/types/mobile/mux.d.ts +0 -128
  153. package/lib/types/mobile/mux.d.ts.map +0 -1
  154. package/lib/types/mobile/mux.js +0 -305
  155. package/lib/types/mobile/mux.test.d.ts +0 -2
  156. package/lib/types/mobile/mux.test.d.ts.map +0 -1
  157. package/lib/types/mobile/mux.test.js +0 -267
  158. package/lib/types/mobile/pairing.d.ts +0 -31
  159. package/lib/types/mobile/pairing.d.ts.map +0 -1
  160. package/lib/types/mobile/pairing.js +0 -62
  161. package/lib/types/mobile/rpc.d.ts +0 -38
  162. package/lib/types/mobile/rpc.d.ts.map +0 -1
  163. package/lib/types/mobile/rpc.js +0 -83
  164. package/lib/types/mobile/theme-toggle.d.ts +0 -12
  165. package/lib/types/mobile/theme-toggle.d.ts.map +0 -1
  166. package/lib/types/mobile/theme-toggle.js +0 -26
  167. package/lib/types/mobile/views/App.d.ts +0 -57
  168. package/lib/types/mobile/views/App.d.ts.map +0 -1
  169. package/lib/types/mobile/views/App.js +0 -150
  170. package/lib/types/mobile/views/App.test.d.ts +0 -2
  171. package/lib/types/mobile/views/App.test.d.ts.map +0 -1
  172. package/lib/types/mobile/views/App.test.js +0 -52
  173. package/lib/types/mobile/views/ChatView.d.ts +0 -63
  174. package/lib/types/mobile/views/ChatView.d.ts.map +0 -1
  175. package/lib/types/mobile/views/ChatView.js +0 -821
  176. package/lib/types/mobile/views/ChatView.stream.test.d.ts +0 -2
  177. package/lib/types/mobile/views/ChatView.stream.test.d.ts.map +0 -1
  178. package/lib/types/mobile/views/ChatView.stream.test.js +0 -236
  179. package/lib/types/mobile/views/ChatView.test.d.ts +0 -2
  180. package/lib/types/mobile/views/ChatView.test.d.ts.map +0 -1
  181. package/lib/types/mobile/views/ChatView.test.js +0 -718
  182. package/lib/types/mobile/views/SessionListView.d.ts +0 -27
  183. package/lib/types/mobile/views/SessionListView.d.ts.map +0 -1
  184. package/lib/types/mobile/views/SessionListView.js +0 -139
  185. package/lib/types/mobile/views/SessionListView.test.d.ts +0 -2
  186. package/lib/types/mobile/views/SessionListView.test.d.ts.map +0 -1
  187. package/lib/types/mobile/views/SessionListView.test.js +0 -167
  188. package/lib/types/mobile/views/WorkspaceView.d.ts +0 -21
  189. package/lib/types/mobile/views/WorkspaceView.d.ts.map +0 -1
  190. package/lib/types/mobile/views/WorkspaceView.js +0 -93
  191. package/lib/types/mobile/views/WorkspaceView.test.d.ts +0 -2
  192. package/lib/types/mobile/views/WorkspaceView.test.d.ts.map +0 -1
  193. package/lib/types/mobile/views/WorkspaceView.test.js +0 -183
  194. package/lib/types/mobile-api.d.ts +0 -65
  195. package/lib/types/mobile-api.d.ts.map +0 -1
  196. package/lib/types/mobile-api.js +0 -404
  197. package/lib/types/mobile-pending.d.ts +0 -38
  198. package/lib/types/mobile-pending.d.ts.map +0 -1
  199. package/lib/types/mobile-pending.js +0 -59
  200. package/lib/types/mobile-pwa.d.ts +0 -6
  201. package/lib/types/mobile-pwa.d.ts.map +0 -1
  202. package/lib/types/mobile-pwa.js +0 -17
  203. package/lib/types/mobile-routes.d.ts +0 -13
  204. package/lib/types/mobile-routes.d.ts.map +0 -1
  205. package/lib/types/mobile-routes.js +0 -217
  206. package/lib/types/paired-model-catalog.d.ts +0 -17
  207. package/lib/types/paired-model-catalog.d.ts.map +0 -1
  208. package/lib/types/paired-model-catalog.js +0 -311
  209. package/src/mobile/PairRequiredView.test.tsx +0 -28
  210. package/src/mobile/PairRequiredView.tsx +0 -58
  211. package/src/mobile/api.ts +0 -229
  212. package/src/mobile/index.tsx +0 -41
  213. package/src/mobile/markdown.test.ts +0 -91
  214. package/src/mobile/markdown.ts +0 -291
  215. package/src/mobile/messages.test.ts +0 -402
  216. package/src/mobile/messages.ts +0 -685
  217. package/src/mobile/mobile-styles.ts +0 -1439
  218. package/src/mobile/mobile-theme.test.ts +0 -84
  219. package/src/mobile/mobile-theme.ts +0 -76
  220. package/src/mobile/mux.test.ts +0 -314
  221. package/src/mobile/mux.ts +0 -336
  222. package/src/mobile/pairing.ts +0 -77
  223. package/src/mobile/rpc.ts +0 -90
  224. package/src/mobile/theme-toggle.tsx +0 -47
  225. package/src/mobile/views/App.test.tsx +0 -62
  226. package/src/mobile/views/App.tsx +0 -213
  227. package/src/mobile/views/ChatView.stream.test.tsx +0 -268
  228. package/src/mobile/views/ChatView.test.tsx +0 -816
  229. package/src/mobile/views/ChatView.tsx +0 -1342
  230. package/src/mobile/views/SessionListView.test.tsx +0 -207
  231. package/src/mobile/views/SessionListView.tsx +0 -244
  232. package/src/mobile/views/WorkspaceView.test.tsx +0 -227
  233. package/src/mobile/views/WorkspaceView.tsx +0 -245
  234. package/src/mobile-api.ts +0 -418
  235. package/src/mobile-pending.ts +0 -88
  236. package/src/mobile-pwa.ts +0 -19
  237. package/src/mobile-routes.ts +0 -231
  238. package/src/paired-model-catalog.ts +0 -272
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Mobile remote control — browser half. Registers the `remote` dictionaries,
3
- * the sidebar-foot entry (phone trigger + pairing panel) into the
4
- * ui-sidebar-declared `sidebar.remote` seat, and runs the phone-side boot
5
- * flow (pair accept + workspace deep-link + presence heartbeats) plus the
6
- * one-time failed-pair notice. Export discipline: packages/client/AGENTS.md
7
- * — the /client surface carries only what cordis loading needs plus types.
2
+ * Remote control — browser half. Registers the `remote` dictionaries, the
3
+ * sidebar-foot entry (phone trigger + pairing panel + update trigger), and
4
+ * the pair boot flow (accept + presence heartbeats) plus the one-time
5
+ * failed-pair notice. The portrait-touch adaptation of the official UI
6
+ * starts at module scope (startMobileAdapt) so its focus guard is installed
7
+ * before the app boots. Export discipline: packages/client/AGENTS.md — the
8
+ * /client surface carries only what cordis loading needs plus types.
8
9
  */
9
10
  import { createElement } from 'react';
10
11
  import { createRoot } from 'react-dom/client';
11
12
  import { FooterRemoteEntry } from "./FooterRemoteEntry.js";
12
- import { RemoteEntry } from "./RemoteEntry.js";
13
13
  import { PairFailedNotice } from "./PairFailedNotice.js";
14
14
  import { RemoteSettingsCard, RemoteSettingsCardController } from "./RemoteSettingsCard.js";
15
15
  import { en, zh } from "./locales.js";
@@ -18,6 +18,12 @@ import { readPairGatePolicy, sendHeartbeat } from "./pair-api.js";
18
18
  import { channelTransition, installRemoteChannel, isLoopbackHostname, remoteChannelRequired, REMOTE_CHANNEL_BOOT_GLOBAL, } from "./remote-channel.js";
19
19
  import { FenceNotice } from "./FenceNotice.js";
20
20
  import { reportDailyHeartbeat } from "./telemetry.js";
21
+ import { startMobileAdapt } from "./mobile-adapt.js";
22
+ // Portrait-touch adaptation of the official UI: installed at module scope so
23
+ // the composer focus guard exists before any app entry mounts React. The
24
+ // layer self-evaluates and reverts with the viewport; the plugin apply below
25
+ // wires its toggleSidebar onto the official layout service.
26
+ startMobileAdapt();
21
27
  /** Dictionary namespace owned by this plugin. */
22
28
  const NS = 'remote';
23
29
  /** Settings namespace the remote-control card edits (the Host plugin registers it). */
@@ -42,6 +48,42 @@ export function apply(ctx) {
42
48
  return () => { };
43
49
  }
44
50
  }, 'remote-web-ui: dictionaries');
51
+ // The mobile adapt's whale button expands the collapsed sidebar and the
52
+ // activation closes the details panel — both through the official layout
53
+ // service (ctx.layout.toggleSidebar / closeDetails flip the panel state;
54
+ // the narrow-viewport semantics open the drawer).
55
+ const layout = ctx.get('layout');
56
+ const adapt = window.__dshRemoteAdapt;
57
+ // The official layout face throws (by contract) when the root entry has
58
+ // not mounted yet; these closures also fire from gestures racing that
59
+ // first mount, so they tolerate the throw instead of surfacing it.
60
+ const layoutCall = (call) => {
61
+ try {
62
+ call?.();
63
+ }
64
+ catch {
65
+ // Boot-order throw: the panel action is a no-op before the root entry.
66
+ }
67
+ };
68
+ if (layout !== undefined && adapt !== undefined) {
69
+ if (typeof layout.toggleSidebar === 'function') {
70
+ adapt.toggleSidebar = () => {
71
+ layoutCall(layout.toggleSidebar);
72
+ };
73
+ }
74
+ if (typeof layout.closeDetails === 'function') {
75
+ adapt.closeDetails = () => {
76
+ layoutCall(layout.closeDetails);
77
+ };
78
+ }
79
+ }
80
+ if (adapt !== undefined && adapt.toggleSidebar === null) {
81
+ // Layout face unavailable (older composition): fall back to clicking the
82
+ // official rail toggle when it exists.
83
+ adapt.toggleSidebar = () => {
84
+ document.querySelector('[class$="_railFish"] button, [class$="_logoRow"] [class*="_iconButton"]')?.click();
85
+ };
86
+ }
45
87
  const t = ctx.locale.bind(NS);
46
88
  const binder = ctx.get('webUiSettings') ?? ctx.settingsScope;
47
89
  const settingsScope = binder.bind({ namespace: REMOTE_WEB_UI_NS });
@@ -51,38 +93,30 @@ export function apply(ctx) {
51
93
  ? snapshot.value?.enabled ?? true
52
94
  : snapshot.status === 'unavailable';
53
95
  };
54
- // Sidebar foot entry: the shell declares 'sidebar.remote' in unconstrained
55
- // order, so registration is declaration-aware — slots.inject waits on the
56
- // declaration, removes the contribution when it collapses, and re-runs
57
- // after a redeclaration. The entry follows the plugin's enabled setting:
58
- // toggling it off removes the trigger, toggling it back on re-registers it.
59
- ctx.slots.inject('sidebar.remote', () => {
60
- let disposeEntry;
61
- const syncEntry = () => {
62
- if (enabled() && disposeEntry === undefined) {
63
- try {
64
- disposeEntry = ctx.slots.register({ name: 'sidebar.remote', locale: NS }, RemoteEntry);
65
- }
66
- catch {
67
- // ignore registration collision
68
- }
69
- }
70
- else if (!enabled() && disposeEntry !== undefined) {
71
- disposeEntry();
72
- disposeEntry = undefined;
73
- }
74
- };
75
- const unsubscribe = settingsScope.subscribe(syncEntry);
76
- syncEntry();
77
- return () => {
78
- unsubscribe();
79
- disposeEntry?.();
80
- };
81
- });
82
- // Current shells declare `sidebar.footer.action` instead of the legacy
83
- // `sidebar.remote` seat; this fallback registers the same entry there when
84
- // the legacy seat never arrives (declaration-aware: only one of the two
85
- // injects ever fires, so the trigger can never render twice).
96
+ // Master switch for the adaptation layer: the module-scope install runs
97
+ // before any config is readable, so flip it once the settings snapshot is
98
+ // bound and on every later change (disabled plugin = no injected surface).
99
+ // Also replay the pending closeDetails: the first portrait apply ran
100
+ // before the layout face was wired, so its closeDetails was a no-op and a
101
+ // restored details panel would otherwise sit hidden until landscape.
102
+ const syncAdaptEnabled = () => {
103
+ ;
104
+ window.__dshRemoteAdapt?.setEnabled?.(enabled());
105
+ };
106
+ settingsScope.subscribe(syncAdaptEnabled);
107
+ syncAdaptEnabled();
108
+ // The replay closes a details panel restored before the wiring; the
109
+ // layout face throws while the root entry has not mounted yet (a real
110
+ // boot-order race on slow remote loads), and the plugin's apply world
111
+ // must survive it — the replay is a best-effort no-op then.
112
+ try {
113
+ adapt?.flushCloseDetails?.();
114
+ }
115
+ catch { }
116
+ // Sidebar foot entry: the sidebar foot seat is `sidebar.footer.action` in
117
+ // the 0.1.2 shell composition (the legacy `sidebar.remote` seat is gone
118
+ // upstream). The pairing link is origin-agnostic, so the entry needs no
119
+ // workspace source.
86
120
  ctx.slots.inject('sidebar.footer.action', () => {
87
121
  let disposeEntry;
88
122
  const syncEntry = () => {
@@ -24,8 +24,7 @@ export declare const zh: {
24
24
  'address.hint': string;
25
25
  'pair.expires': string;
26
26
  'pair.expired': string;
27
- 'pair.phoneLabel': string;
28
- 'pair.desktopLabel': string;
27
+ 'pair.linkLabel': string;
29
28
  'pair.oneTimeHint': string;
30
29
  'pair.failed.title': string;
31
30
  'pair.failed.detail': string;
@@ -48,8 +47,7 @@ export declare const zh: {
48
47
  'action.stop': string;
49
48
  'action.refresh': string;
50
49
  'action.copy': string;
51
- 'action.copyPhone': string;
52
- 'action.copyDesktop': string;
50
+ 'action.copyLink': string;
53
51
  'action.copied': string;
54
52
  'devices.title': string;
55
53
  'devices.empty': string;
@@ -84,8 +82,17 @@ export declare const zh: {
84
82
  'settings.publicBaseUrlHint': string;
85
83
  'settings.autoTunnel': string;
86
84
  'settings.autoTunnelHint': string;
87
- 'settings.mobileEnterToSend': string;
88
- 'settings.mobileEnterToSendHint': string;
85
+ 'settings.lanBind': string;
86
+ 'settings.lanBindHint': string;
87
+ 'lan.cardTitle': string;
88
+ 'lan.bind': string;
89
+ 'lan.off': string;
90
+ 'lan.urls': string;
91
+ 'lan.firewall.ok': string;
92
+ 'lan.firewall.bad': string;
93
+ 'lan.firewall.unmanaged': string;
94
+ 'lan.untouched': string;
95
+ 'lan.pendingRestart': string;
89
96
  'settings.inherit': string;
90
97
  'settings.on': string;
91
98
  'settings.off': string;
@@ -172,8 +179,7 @@ export declare const en: {
172
179
  'address.hint': string;
173
180
  'pair.expires': string;
174
181
  'pair.expired': string;
175
- 'pair.phoneLabel': string;
176
- 'pair.desktopLabel': string;
182
+ 'pair.linkLabel': string;
177
183
  'pair.oneTimeHint': string;
178
184
  'pair.failed.title': string;
179
185
  'pair.failed.detail': string;
@@ -196,8 +202,7 @@ export declare const en: {
196
202
  'action.stop': string;
197
203
  'action.refresh': string;
198
204
  'action.copy': string;
199
- 'action.copyPhone': string;
200
- 'action.copyDesktop': string;
205
+ 'action.copyLink': string;
201
206
  'action.copied': string;
202
207
  'devices.title': string;
203
208
  'devices.empty': string;
@@ -232,8 +237,17 @@ export declare const en: {
232
237
  'settings.publicBaseUrlHint': string;
233
238
  'settings.autoTunnel': string;
234
239
  'settings.autoTunnelHint': string;
235
- 'settings.mobileEnterToSend': string;
236
- 'settings.mobileEnterToSendHint': string;
240
+ 'settings.lanBind': string;
241
+ 'settings.lanBindHint': string;
242
+ 'lan.cardTitle': string;
243
+ 'lan.bind': string;
244
+ 'lan.off': string;
245
+ 'lan.urls': string;
246
+ 'lan.firewall.ok': string;
247
+ 'lan.firewall.bad': string;
248
+ 'lan.firewall.unmanaged': string;
249
+ 'lan.untouched': string;
250
+ 'lan.pendingRestart': string;
237
251
  'settings.inherit': string;
238
252
  'settings.on': string;
239
253
  'settings.off': string;
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgJmB,CAAA;AAElC,sCAAsC;AACtC,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AAEvC,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAA;AAEvC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgJsB,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuJmB,CAAA;AAElC,sCAAsC;AACtC,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AAEvC,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAA;AAEvC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuJsB,CAAA"}
@@ -3,15 +3,15 @@
3
3
  export const zh = {
4
4
  'entry.label': '远程访问',
5
5
  'title': '远程访问',
6
- 'subtitle': '通过手机或另一台电脑配对,远程访问当前工作区',
6
+ 'subtitle': '通过手机或另一台电脑配对,远程使用同一份 Web 界面(官方界面 + 移动端适配)',
7
7
  'card.title': '设备配对',
8
8
  'public.badge': '公网',
9
9
  'status.waiting': '等待设备连接',
10
10
  'status.connected': '已连接 {n} 台设备',
11
11
  'status.disconnected': '已配对设备离线',
12
12
  'status.stopped': '已停止远程访问',
13
- 'status.lanRequired': '此功能需要以 --host 0.0.0.0 启动 dsh web,或配置公网地址才能使用',
14
- 'status.lanRequiredHint': '当前服务仅绑定在 127.0.0.1 且未配置公网地址,手机无法访问。请用 dsh web --host 0.0.0.0 重新启动,或在设置中填写内网穿透的公网地址。',
13
+ 'status.lanRequired': '此功能需要局域网绑定或公网地址才能使用',
14
+ 'status.lanRequiredHint': '当前服务仅绑定在 127.0.0.1 且未配置公网地址,手机无法访问。可在下方设置卡片打开“局域网访问”,或用 dsh web --host 0.0.0.0 重新启动,或填写内网穿透的公网地址。',
15
15
  'status.loopbackRequired': '配对面板仅限本机使用',
16
16
  'status.loopbackRequiredHint': '请通过 http://127.0.0.1 打开此页面后重试;手机请使用配对链接访问。',
17
17
  'status.unreachable': '无法连接配对服务',
@@ -24,9 +24,8 @@ export const zh = {
24
24
  'address.hint': '远程设备不在同一网络时请使用公网地址;局域网地址仅限同一网络内使用。',
25
25
  'pair.expires': '二维码有效至 {time}',
26
26
  'pair.expired': '二维码已过期,请刷新',
27
- 'pair.phoneLabel': '手机配对链接',
28
- 'pair.desktopLabel': '电脑配对链接',
29
- 'pair.oneTimeHint': '两条链接共用同一枚一次性令牌;任意设备配对成功后,另一条链接立即失效。',
27
+ 'pair.linkLabel': '配对链接',
28
+ 'pair.oneTimeHint': '链接含一次性令牌;任一设备配对成功后立即失效,配对下一台设备请刷新二维码。',
30
29
  'pair.failed.title': '配对失败',
31
30
  'pair.failed.detail': '链接无效或已使用,请回到电脑端刷新二维码后重新扫码。',
32
31
  'fence.unpaired.title': '此设备未配对,无法访问工作区数据',
@@ -48,8 +47,7 @@ export const zh = {
48
47
  'action.stop': '停止',
49
48
  'action.refresh': '刷新二维码',
50
49
  'action.copy': '复制链接',
51
- 'action.copyPhone': '复制手机链接',
52
- 'action.copyDesktop': '复制电脑链接',
50
+ 'action.copyLink': '复制链接',
53
51
  'action.copied': '已复制',
54
52
  'devices.title': '已授权设备',
55
53
  'devices.empty': '还没有已配对的设备。扫码或打开链接后会出现在这里。',
@@ -85,14 +83,23 @@ export const zh = {
85
83
  'settings.publicBaseUrlHint': '内网穿透的公网地址,如 Cloudflare Tunnel:https://xxx.trycloudflare.com。填写后二维码将生成公网链接,手机不在同一网络也能配对;留空则仅局域网可用。',
86
84
  'settings.autoTunnel': '自动公网隧道',
87
85
  'settings.autoTunnelHint': '开启后插件自动启动 Cloudflare quick tunnel(无需安装任何工具),并自动更新公网地址与信任配置,手机随时可用公网配对;关闭时使用上方手动填写的公网地址。',
88
- 'settings.mobileEnterToSend': '移动端回车发送',
89
- 'settings.mobileEnterToSendHint': '开启:移动端输入框按 Enter 直接发送,Shift+Enter 换行;关闭:Enter 换行,仅点发送按钮发送。',
86
+ 'settings.lanBind': '局域网访问(绑定 0.0.0.0)',
87
+ 'settings.lanBindHint': '开启后插件把绑定默认改写为 0.0.0.0 并写入 profile 补丁(显式 --host 仍优先),同时维护主机防火墙放行(Windows/Linux;macOS 无需管理);关闭回退 127.0.0.1。绑定变化通常在重启 dsh web 后生效。',
88
+ 'lan.cardTitle': '局域网访问',
89
+ 'lan.bind': '绑定:{host}:{port}',
90
+ 'lan.off': '当前仅本机可访问。',
91
+ 'lan.urls': '局域网地址:{urls}',
92
+ 'lan.firewall.ok': '防火墙已放行',
93
+ 'lan.firewall.bad': '防火墙未放行(需管理员权限)',
94
+ 'lan.firewall.unmanaged': '防火墙不由插件管理(未检测到受支持的防火墙)',
95
+ 'lan.untouched': '开关尚未使用:打开后插件才会改写 profile 补丁。',
96
+ 'lan.pendingRestart': '绑定将在重启 dsh web 后生效。',
90
97
  'settings.inherit': '继承',
91
98
  'settings.on': '开',
92
99
  'settings.off': '关',
93
100
  'settings.overridden': '已覆盖',
94
101
  'settings.reset': '恢复默认',
95
- 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。',
102
+ 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 $DSH_HOME/settings.yaml 直接配置,或确认提供该命名空间的插件已挂载其设置域并重启。',
96
103
  'settings.readOnly': '当前部署的设置只读。',
97
104
  'settings.expand': '展开设置',
98
105
  'settings.collapse': '收起设置',
@@ -149,15 +156,15 @@ export const zh = {
149
156
  export const en = {
150
157
  'entry.label': 'Remote access',
151
158
  'title': 'Remote access',
152
- 'subtitle': 'Pair a phone or another computer to access this workspace remotely',
159
+ 'subtitle': 'Pair a phone or another computer to share the same Web GUI (official UI + mobile adaptation)',
153
160
  'card.title': 'Pair a device',
154
161
  'public.badge': 'Public',
155
162
  'status.waiting': 'Waiting for a device',
156
163
  'status.connected': '{n} device(s) connected',
157
164
  'status.disconnected': 'Paired devices offline',
158
165
  'status.stopped': 'Remote access stopped',
159
- 'status.lanRequired': 'This feature needs dsh web started with --host 0.0.0.0, or a configured public address',
160
- 'status.lanRequiredHint': 'The server is bound to 127.0.0.1 and no public address is configured, so a phone cannot reach it. Restart with dsh web --host 0.0.0.0, or set the tunneled public address in settings.',
166
+ 'status.lanRequired': 'This feature needs a LAN bind or a public address',
167
+ 'status.lanRequiredHint': 'The server is bound to 127.0.0.1 and no public address is configured, so a phone cannot reach it. Turn on LAN access in the settings card below, restart with dsh web --host 0.0.0.0, or set the tunneled public address in settings.',
161
168
  'status.loopbackRequired': 'The pairing panel works on this machine only',
162
169
  'status.loopbackRequiredHint': 'Open this page at http://127.0.0.1 to mint a QR code; phones use the paired link.',
163
170
  'status.unreachable': 'Cannot reach the pairing service',
@@ -170,9 +177,8 @@ export const en = {
170
177
  'address.hint': 'Use the public address when the remote device is on another network; LAN addresses only work on the same network.',
171
178
  'pair.expires': 'QR code valid until {time}',
172
179
  'pair.expired': 'QR code expired — refresh it',
173
- 'pair.phoneLabel': 'Phone pairing link',
174
- 'pair.desktopLabel': 'Computer pairing link',
175
- 'pair.oneTimeHint': 'Both links share one single-use token. Pairing either device invalidates the other link immediately.',
180
+ 'pair.linkLabel': 'Pairing link',
181
+ 'pair.oneTimeHint': 'The link carries one single-use token; it dies as soon as any device pairs. Refresh the QR to pair the next device.',
176
182
  'pair.failed.title': 'Pairing failed',
177
183
  'pair.failed.detail': 'The link is invalid or was already used. Refresh the QR code on your computer and scan again.',
178
184
  'fence.unpaired.title': 'This device is not paired and cannot reach workspace data',
@@ -194,8 +200,7 @@ export const en = {
194
200
  'action.stop': 'Stop',
195
201
  'action.refresh': 'Refresh QR',
196
202
  'action.copy': 'Copy link',
197
- 'action.copyPhone': 'Copy phone link',
198
- 'action.copyDesktop': 'Copy computer link',
203
+ 'action.copyLink': 'Copy link',
199
204
  'action.copied': 'Copied',
200
205
  'devices.title': 'Authorized devices',
201
206
  'devices.empty': 'No paired devices yet. Scan the QR or open the link to add one.',
@@ -231,14 +236,23 @@ export const en = {
231
236
  'settings.publicBaseUrlHint': 'The public URL of a tunnel in front of this server, e.g. a Cloudflare Tunnel: https://xxx.trycloudflare.com. When set, the QR link is built from it so a phone anywhere can pair; leave blank for LAN-only usage.',
232
237
  'settings.autoTunnel': 'Auto public tunnel',
233
238
  'settings.autoTunnelHint': 'When on, the plugin runs its own Cloudflare quick tunnel (no tool installation needed) and keeps the public address and trust config in sync automatically, so a phone anywhere can pair at any time; when off, the manually entered public address above applies.',
234
- 'settings.mobileEnterToSend': 'Enter to send on mobile',
235
- 'settings.mobileEnterToSendHint': 'On: Enter in the mobile composer sends immediately and Shift+Enter inserts a newline. Off: Enter inserts a newline and only the send button sends.',
239
+ 'settings.lanBind': 'LAN access (bind 0.0.0.0)',
240
+ 'settings.lanBindHint': 'When on, the plugin writes a managed block into the profile patch defaulting the bind to 0.0.0.0 (an explicit --host flag still wins), and maintains the matching host firewall rule (Windows/Linux; other platforms need none). When off, the block pins 127.0.0.1. The bind change usually takes effect after dsh web restarts.',
241
+ 'lan.cardTitle': 'LAN access',
242
+ 'lan.bind': 'Bind: {host}:{port}',
243
+ 'lan.off': 'Currently localhost-only.',
244
+ 'lan.urls': 'LAN URLs: {urls}',
245
+ 'lan.firewall.ok': 'firewall open',
246
+ 'lan.firewall.bad': 'firewall blocked (needs admin)',
247
+ 'lan.firewall.unmanaged': 'firewall not managed (no supported firewall detected)',
248
+ 'lan.untouched': 'The toggle has never been used; the profile patch is only written once you flip it.',
249
+ 'lan.pendingRestart': 'The bind change takes effect after dsh web restarts.',
236
250
  'settings.inherit': 'Inherit',
237
251
  'settings.on': 'On',
238
252
  'settings.off': 'Off',
239
253
  'settings.overridden': 'Overridden',
240
254
  'settings.reset': 'Reset to default',
241
- 'settings.notExposed': 'This DSH version does not expose this plugin\'s settings namespace to the configuration page, so the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to dsh-host-apiproxy\'s WEB_SETTINGS_NAMESPACES allowlist and restart.',
255
+ 'settings.notExposed': 'This DSH version does not expose this plugin\'s settings namespace to the configuration page, so the form is unavailable. Edit $DSH_HOME/settings.yaml directly, or confirm that the plugin owning the namespace is mounted with its settings domain and restart.',
242
256
  'settings.readOnly': 'This deployment stores settings read-only.',
243
257
  'settings.expand': 'Show settings',
244
258
  'settings.collapse': 'Hide settings',
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Portrait-touch adaptation of the OFFICIAL desktop Web GUI (the dsh-LAN
3
+ * approach): while a touch device is in portrait, inject a CSS + gesture
4
+ * layer on top of the running SPA instead of maintaining a second UI. The
5
+ * official layout already auto-collapses the sidebar below 1024px; this
6
+ * layer adds touch-target sizing, 16px inputs (iOS focus zoom), safe-area
7
+ * padding, a floating whale button as the collapsed-sidebar entry (with a
8
+ * verified toggle fallback for cohorts whose layout face mounts inert),
9
+ * swipe gestures, long-press session menus, a bottom-sheet composer picker
10
+ * (model / effort / permission menus), desktop-surface suppression, and
11
+ * composer/header compaction.
12
+ * Landscape, desktop, and wide viewports stay untouched; a manual
13
+ * sessionStorage opt-out (dsh-remote-force-desktop=1) disables the layer.
14
+ *
15
+ * Selector strategy: CSS Modules class names are hash-prefixed with the
16
+ * semantic name as a stable suffix (`pI_x6G_centerCol`), so attribute
17
+ * suffix selectors survive official rebuilds that only change the hash. The
18
+ * semantic names were read off the 0.1.2-alpha.1 official client build and
19
+ * are re-verified on every GUI QA round; rules borrowed from the dsh-LAN
20
+ * reference (MIT, v47-v78) keep their version comments.
21
+ * @module @linxin666/dsh-remote-web-ui/client/mobile-adapt
22
+ */
23
+ /** The window global the plugin apply() wires the layout service into. */
24
+ export interface RemoteAdaptGlobal {
25
+ evaluate: () => void;
26
+ /** Wired by the plugin apply once ctx.layout is live. */
27
+ toggleSidebar: (() => void) | null;
28
+ /** Wired by the plugin apply once ctx.layout is live. */
29
+ closeDetails: (() => void) | null;
30
+ /** Plugin master switch: false reverts the layer, true re-evaluates. */
31
+ setEnabled(on: boolean): void;
32
+ /** Replays a pending closeDetails once the layout face is wired (the first apply ran before the wiring). */
33
+ flushCloseDetails(): void;
34
+ }
35
+ /**
36
+ * Install the adaptation layer. Runs once per page (idempotent); the
37
+ * evaluate loop re-applies on orientation/resize and reverts off-portrait.
38
+ */
39
+ export declare function startMobileAdapt(): void;
40
+ //# sourceMappingURL=mobile-adapt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-adapt.d.ts","sourceRoot":"","sources":["../../../src/client/mobile-adapt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,yDAAyD;IACzD,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IAClC,yDAAyD;IACzD,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IACjC,wEAAwE;IACxE,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7B,4GAA4G;IAC5G,iBAAiB,IAAI,IAAI,CAAA;CAC1B;AAgOD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CA0oBvC"}