dsh-zen-remote 2.3.11 → 2.4.0

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 (244) hide show
  1. package/CHANGELOG.md +39 -78
  2. package/README.md +94 -84
  3. package/README.zh-CN.md +90 -81
  4. package/bin/zen-remote.mjs +5 -0
  5. package/docs/interface.md +6 -6
  6. package/docs/remote-access.en.md +6 -4
  7. package/docs/remote-access.md +6 -4
  8. package/dsh-push.mjs +96 -10
  9. package/lib/adapters/dsh-better-sidebar/index.js +7 -3
  10. package/lib/adapters/dsh-better-sidebar/index.js.map +1 -1
  11. package/lib/admin-routes.js +10 -2
  12. package/lib/admin-routes.js.map +1 -1
  13. package/lib/cli/args.js +251 -0
  14. package/lib/cli/args.js.map +1 -0
  15. package/lib/cli/bootstrap.js +449 -0
  16. package/lib/cli/bootstrap.js.map +1 -0
  17. package/lib/cli/command-setup.js +484 -0
  18. package/lib/cli/command-setup.js.map +1 -0
  19. package/lib/cli/commands-client.js +359 -0
  20. package/lib/cli/commands-client.js.map +1 -0
  21. package/lib/cli/commands-host.js +1108 -0
  22. package/lib/cli/commands-host.js.map +1 -0
  23. package/lib/cli/commands-status.js +279 -0
  24. package/lib/cli/commands-status.js.map +1 -0
  25. package/lib/cli/config-writer.js +334 -0
  26. package/lib/cli/config-writer.js.map +1 -0
  27. package/lib/cli/context.js +10 -0
  28. package/lib/cli/context.js.map +1 -0
  29. package/lib/cli/i18n.js +620 -0
  30. package/lib/cli/i18n.js.map +1 -0
  31. package/lib/cli/ipc-client.js +160 -0
  32. package/lib/cli/ipc-client.js.map +1 -0
  33. package/lib/cli/ipc-server.js +464 -0
  34. package/lib/cli/ipc-server.js.map +1 -0
  35. package/lib/cli/main.js +245 -0
  36. package/lib/cli/main.js.map +1 -0
  37. package/lib/cli/qr-terminal.js +48 -0
  38. package/lib/cli/qr-terminal.js.map +1 -0
  39. package/lib/client-data/qr.js +286 -0
  40. package/lib/client-data/qr.js.map +1 -0
  41. package/lib/client-routes.js +308 -25
  42. package/lib/client-routes.js.map +1 -1
  43. package/lib/client.js +1013 -229
  44. package/lib/config.js +50 -12
  45. package/lib/config.js.map +1 -1
  46. package/lib/debug-report.js +28 -1
  47. package/lib/debug-report.js.map +1 -1
  48. package/lib/fetch-route-intercept.js +334 -26
  49. package/lib/fetch-route-intercept.js.map +1 -1
  50. package/lib/index.js +564 -363
  51. package/lib/index.js.map +1 -1
  52. package/lib/intercept.js +1833 -280
  53. package/lib/intercept.js.map +1 -1
  54. package/lib/lan-gate-server.cjs +36 -10
  55. package/lib/merge-streams.js +103 -11
  56. package/lib/merge-streams.js.map +1 -1
  57. package/lib/plugin-route-intercept.js +93 -63
  58. package/lib/plugin-route-intercept.js.map +1 -1
  59. package/lib/relay-access.js +8 -1
  60. package/lib/relay-access.js.map +1 -1
  61. package/lib/relay-client.js +133 -4
  62. package/lib/relay-client.js.map +1 -1
  63. package/lib/relay-pool.js +275 -0
  64. package/lib/relay-pool.js.map +1 -0
  65. package/lib/relay-server.js +269 -17
  66. package/lib/relay-server.js.map +1 -1
  67. package/lib/restart-fields.js +6 -4
  68. package/lib/restart-fields.js.map +1 -1
  69. package/lib/share-store.js +65 -27
  70. package/lib/share-store.js.map +1 -1
  71. package/lib/state-store.js +400 -0
  72. package/lib/state-store.js.map +1 -0
  73. package/lib/types/adapters/dsh-better-sidebar/index.d.ts +3 -2
  74. package/lib/types/adapters/dsh-better-sidebar/index.d.ts.map +1 -1
  75. package/lib/types/admin-routes.d.ts.map +1 -1
  76. package/lib/types/cli/args.d.ts +78 -0
  77. package/lib/types/cli/args.d.ts.map +1 -0
  78. package/lib/types/cli/bootstrap.d.ts +170 -0
  79. package/lib/types/cli/bootstrap.d.ts.map +1 -0
  80. package/lib/types/cli/command-setup.d.ts +72 -0
  81. package/lib/types/cli/command-setup.d.ts.map +1 -0
  82. package/lib/types/cli/commands-client.d.ts +36 -0
  83. package/lib/types/cli/commands-client.d.ts.map +1 -0
  84. package/lib/types/cli/commands-host.d.ts +82 -0
  85. package/lib/types/cli/commands-host.d.ts.map +1 -0
  86. package/lib/types/cli/commands-status.d.ts +46 -0
  87. package/lib/types/cli/commands-status.d.ts.map +1 -0
  88. package/lib/types/cli/config-writer.d.ts +92 -0
  89. package/lib/types/cli/config-writer.d.ts.map +1 -0
  90. package/lib/types/cli/context.d.ts +39 -0
  91. package/lib/types/cli/context.d.ts.map +1 -0
  92. package/lib/types/cli/i18n.d.ts +32 -0
  93. package/lib/types/cli/i18n.d.ts.map +1 -0
  94. package/lib/types/cli/ipc-client.d.ts +83 -0
  95. package/lib/types/cli/ipc-client.d.ts.map +1 -0
  96. package/lib/types/cli/ipc-server.d.ts +113 -0
  97. package/lib/types/cli/ipc-server.d.ts.map +1 -0
  98. package/lib/types/cli/main.d.ts +57 -0
  99. package/lib/types/cli/main.d.ts.map +1 -0
  100. package/lib/types/cli/qr-terminal.d.ts +17 -0
  101. package/lib/types/cli/qr-terminal.d.ts.map +1 -0
  102. package/lib/types/client/RemoteStatusIcon.d.ts.map +1 -1
  103. package/lib/types/client/current-session-report.d.ts +4 -0
  104. package/lib/types/client/current-session-report.d.ts.map +1 -1
  105. package/lib/types/client/effects/model-group-side.d.ts.map +1 -1
  106. package/lib/types/client/effects/remote-session.d.ts.map +1 -1
  107. package/lib/types/client/locales.d.ts +47 -3
  108. package/lib/types/client/locales.d.ts.map +1 -1
  109. package/lib/types/client/settings/SettingsSection.d.ts.map +1 -1
  110. package/lib/types/client/settings/settings-css.d.ts +1 -1
  111. package/lib/types/client/settings/settings-css.d.ts.map +1 -1
  112. package/lib/types/client/styles/remote-session.css.d.ts +1 -1
  113. package/lib/types/client/styles/remote-session.css.d.ts.map +1 -1
  114. package/lib/types/client/wizard/GatewayWizard.d.ts.map +1 -1
  115. package/lib/types/client/wizard/cards/ProxyCard.d.ts.map +1 -1
  116. package/lib/types/client/wizard/wizard-css.d.ts +1 -1
  117. package/lib/types/client/wizard/wizard-css.d.ts.map +1 -1
  118. package/lib/types/client-data/model-group-side.d.ts +23 -2
  119. package/lib/types/client-data/model-group-side.d.ts.map +1 -1
  120. package/lib/types/client-data/remote-status.d.ts +47 -1
  121. package/lib/types/client-data/remote-status.d.ts.map +1 -1
  122. package/lib/types/client-data/settings-form.d.ts +85 -1
  123. package/lib/types/client-data/settings-form.d.ts.map +1 -1
  124. package/lib/types/client-data/wizard.d.ts +56 -1
  125. package/lib/types/client-data/wizard.d.ts.map +1 -1
  126. package/lib/types/client-routes.d.ts +25 -1
  127. package/lib/types/client-routes.d.ts.map +1 -1
  128. package/lib/types/config.d.ts +40 -14
  129. package/lib/types/config.d.ts.map +1 -1
  130. package/lib/types/debug-report.d.ts.map +1 -1
  131. package/lib/types/fetch-route-intercept.d.ts +66 -8
  132. package/lib/types/fetch-route-intercept.d.ts.map +1 -1
  133. package/lib/types/index.d.ts +9 -2
  134. package/lib/types/index.d.ts.map +1 -1
  135. package/lib/types/intercept.d.ts +72 -10
  136. package/lib/types/intercept.d.ts.map +1 -1
  137. package/lib/types/merge-streams.d.ts +79 -1
  138. package/lib/types/merge-streams.d.ts.map +1 -1
  139. package/lib/types/plugin-route-intercept.d.ts +25 -9
  140. package/lib/types/plugin-route-intercept.d.ts.map +1 -1
  141. package/lib/types/relay-access.d.ts +3 -1
  142. package/lib/types/relay-access.d.ts.map +1 -1
  143. package/lib/types/relay-client.d.ts +23 -2
  144. package/lib/types/relay-client.d.ts.map +1 -1
  145. package/lib/types/relay-pool.d.ts +148 -0
  146. package/lib/types/relay-pool.d.ts.map +1 -0
  147. package/lib/types/relay-server.d.ts +30 -3
  148. package/lib/types/relay-server.d.ts.map +1 -1
  149. package/lib/types/restart-fields.d.ts +5 -5
  150. package/lib/types/restart-fields.d.ts.map +1 -1
  151. package/lib/types/share-store.d.ts.map +1 -1
  152. package/lib/types/state-store.d.ts +179 -0
  153. package/lib/types/state-store.d.ts.map +1 -0
  154. package/lib/types/upload-limits.d.ts +15 -0
  155. package/lib/types/upload-limits.d.ts.map +1 -1
  156. package/lib/types/virtual-id.d.ts +21 -0
  157. package/lib/types/virtual-id.d.ts.map +1 -1
  158. package/lib/types/wizard/probe.d.ts.map +1 -1
  159. package/lib/types/wizard/proxy-snippets.d.ts +3 -0
  160. package/lib/types/wizard/proxy-snippets.d.ts.map +1 -1
  161. package/lib/types/wizard/routes.d.ts +1 -0
  162. package/lib/types/wizard/routes.d.ts.map +1 -1
  163. package/lib/types/wizard/status.d.ts +9 -0
  164. package/lib/types/wizard/status.d.ts.map +1 -1
  165. package/lib/types/wizard/verify.d.ts +3 -0
  166. package/lib/types/wizard/verify.d.ts.map +1 -1
  167. package/lib/upload-limits.js +15 -0
  168. package/lib/upload-limits.js.map +1 -1
  169. package/lib/virtual-id.js +60 -0
  170. package/lib/virtual-id.js.map +1 -1
  171. package/lib/wizard/probe.js +46 -1
  172. package/lib/wizard/probe.js.map +1 -1
  173. package/lib/wizard/proxy-snippets.js +14 -1
  174. package/lib/wizard/proxy-snippets.js.map +1 -1
  175. package/lib/wizard/routes.js +23 -4
  176. package/lib/wizard/routes.js.map +1 -1
  177. package/lib/wizard/status.js +21 -0
  178. package/lib/wizard/status.js.map +1 -1
  179. package/lib/wizard/verify.js +31 -8
  180. package/lib/wizard/verify.js.map +1 -1
  181. package/package.json +8 -4
  182. package/pwa/icons/badge-96.png +0 -0
  183. package/pwa/icons/badge.svg +1 -0
  184. package/pwa/manifest.json +2 -1
  185. package/pwa/sw.js +3 -1
  186. package/scripts/check-debug-report.mjs +41 -1
  187. package/scripts/check-settings-form.mjs +14 -3
  188. package/scripts/check-settings-view.mjs +247 -0
  189. package/scripts/check-wizard-ui.mjs +37 -0
  190. package/src/adapters/dsh-better-sidebar/index.ts +7 -3
  191. package/src/admin-routes.ts +10 -2
  192. package/src/cli/args.ts +289 -0
  193. package/src/cli/bootstrap.ts +569 -0
  194. package/src/cli/command-setup.ts +540 -0
  195. package/src/cli/commands-client.ts +369 -0
  196. package/src/cli/commands-host.ts +1127 -0
  197. package/src/cli/commands-status.ts +296 -0
  198. package/src/cli/config-writer.ts +354 -0
  199. package/src/cli/context.ts +38 -0
  200. package/src/cli/i18n.ts +645 -0
  201. package/src/cli/ipc-client.ts +216 -0
  202. package/src/cli/ipc-server.ts +531 -0
  203. package/src/cli/main.ts +285 -0
  204. package/src/cli/qr-terminal.ts +49 -0
  205. package/src/client/RemoteStatusIcon.tsx +4 -1
  206. package/src/client/current-session-report.ts +28 -4
  207. package/src/client/effects/model-group-side.ts +19 -5
  208. package/src/client/effects/remote-session.ts +26 -6
  209. package/src/client/locales.ts +96 -6
  210. package/src/client/settings/SettingsSection.tsx +287 -92
  211. package/src/client/settings/settings-css.ts +18 -0
  212. package/src/client/styles/remote-session.css.ts +15 -1
  213. package/src/client/wizard/GatewayWizard.tsx +470 -109
  214. package/src/client/wizard/cards/ProxyCard.tsx +2 -1
  215. package/src/client/wizard/wizard-css.ts +23 -0
  216. package/src/client-data/model-group-side.ts +37 -10
  217. package/src/client-data/remote-status.ts +112 -17
  218. package/src/client-data/settings-form.ts +164 -8
  219. package/src/client-data/wizard.ts +112 -2
  220. package/src/client-routes.ts +334 -26
  221. package/src/config.ts +62 -16
  222. package/src/debug-report.ts +27 -1
  223. package/src/fetch-route-intercept.ts +381 -32
  224. package/src/index.ts +566 -367
  225. package/src/intercept.ts +1866 -286
  226. package/src/merge-streams.ts +155 -10
  227. package/src/plugin-route-intercept.ts +120 -71
  228. package/src/relay-access.ts +14 -3
  229. package/src/relay-client.ts +163 -5
  230. package/src/relay-pool.ts +387 -0
  231. package/src/relay-server.ts +312 -16
  232. package/src/restart-fields.ts +6 -4
  233. package/src/share-store.ts +59 -26
  234. package/src/state-store.ts +428 -0
  235. package/src/upload-limits.ts +16 -0
  236. package/src/virtual-id.ts +57 -0
  237. package/src/wizard/probe.ts +54 -2
  238. package/src/wizard/proxy-snippets.ts +17 -2
  239. package/src/wizard/routes.ts +24 -5
  240. package/src/wizard/status.ts +28 -0
  241. package/src/wizard/verify.ts +33 -11
  242. package/AGENTS.md +0 -185
  243. package/docs/adr/0001-plugin-bridge-forwards-plugin-routes.md +0 -15
  244. package/docs/adr/0002-relay-emulates-websocket.md +0 -8
package/CHANGELOG.md CHANGED
@@ -5,131 +5,92 @@
5
5
  [GitHub Releases](https://github.com/KyoMio/dsh-zen-remote/releases)(tag 驱动自动生成)。
6
6
  界面半边的细节叙事另见 [`docs/interface.md`](docs/interface.md) 的「更新日志」一节。
7
7
 
8
+ ## 2.4.0(2026-11-09)
9
+
10
+ ### 新增
11
+
12
+ - **无头服务器命令行工具 `dsh-zen-remote`**:支持在终端完成三步配置向导(`setup`)、设备配对与二维码展示、公网入口管理与连通自检,以及查看状态与导出脱敏诊断报告。
13
+ - **子客户端多服务端同时连接(最多 8 台)**:子客户端现在可同时配对并连接最多 8 台主服务端,侧边栏远程分组按配对顺序合并(同名服务端自动编号),插件页向导与设置卡支持逐台管理与状态查看。
14
+ - **会话通知总开关与来源会话名**([#55](https://github.com/KyoMio/dsh-zen-remote/issues/55)):新增 `pushEnabled` 一键停用全部自动推送与 `push_notify` 工具,以及 `pushSessionName` 在推送正文首行显示来源会话名。
15
+ - **主进程状态文件合并**:将本机服务端 ID、共享会话表与已配对服务端列表统一收口到 `~/.dsh/zen-remote-state.json`,启动时自动迁移旧状态文件。
16
+
17
+ ### 修复
18
+
19
+ - **修复 DSH 0.2.2+ 下远程会话终端报「此功能暂不支持远程会话」**:适配 DSH 0.2.2 新的 `terminal/attach` 双工终端通道并兼容 `dsh-better-sidebar` 0.30.1,远程会话终端可正常打开与输入。
20
+ - **远程会话正文图片无法显示**([#55](https://github.com/KyoMio/dsh-zen-remote/issues/55)):子客户端查看远程会话时,回复正文与文档预览中的本地图片现在会自动转发到对应主服务端读取,不再因本机无该路径而显示破图。
21
+ - **PWA 通知小图标显示为实心方块**([#55](https://github.com/KyoMio/dsh-zen-remote/issues/55)):将通知状态栏小图标换为透明底单色剪影,避免在系统状态栏与任务栏被渲染成实心色块。
22
+
8
23
  ## 2.3.11(2026-11-06)
9
24
 
10
25
  ### 修复
11
26
 
12
- - **修复冷启动竞态导致「会话与插件同步:异常」**([#53](https://github.com/KyoMio/dsh-zen-remote/issues/53)):
13
- DSH 0.2.1-alpha.3 起网关调用必须自带 Peer,而客户端同步拦截的安装只等网关服务——
14
- 宿主的 connection 服务经另一层注入、可能显著滞后(插件多、启动慢的机器上尤甚)。
15
- 自检在 Peer 缺位时以 `reading 'signal'` 失败并按策略卸载拦截,此后无恢复路径,
16
- 表现为远程会话同步失效、需手动重载插件。现在安装声明等待 connection 服务,
17
- 服务到齐才安装并自检;0.1.7 / Electron 组合本就无此安装路径,行为不变。
27
+ - **修复冷启动竞态导致「会话与插件同步:异常」**([#53](https://github.com/KyoMio/dsh-zen-remote/issues/53)):等待宿主 `connection` 服务就绪后再安装客户端同步拦截并执行自检,避免启动较慢时自检失败导致远程会话同步失效。
18
28
 
19
29
  ## 2.3.10(2026-11-06)
20
30
 
21
31
  ### 修复
22
32
 
23
- - **适配 DSH 0.2.2-rc.1 移动端会话页空屏与首页设置按钮失灵**:DSH 0.2.2-rc.1 的
24
- `AppFrame` 给主栏显式设置 `grid-area: 1/2`(落入移动端单列网格的 `0px` 第 2 列导致进入
25
- 会话一片空白),并在 `< 768px` 新增 `[data-sidebar-mask]`(作为首个子元素挤掉原先
26
- `:first-child` 侧栏选择器)、`[data-shell-leading]` 左上角悬浮按钮与侧栏 `inert` /
27
- `visibility: hidden`。现将主栏显式钉回第 1 列(`grid-area: 1 / 1`)、按稳定类名后缀
28
- `[class$="_sidebarCol"]` 匹配侧栏并隐藏宿主遮罩与左上角悬浮按钮,同时在手机壳下剥离侧栏
29
- `inert` 属性,恢复会话页正常渲染及首页设置按钮、底部芯片代点。
33
+ - **适配 DSH 0.2.2-rc.1 移动端会话页空屏与首页设置按钮失灵**:修复 DSH 0.2.2-rc.1 网格列调整与新增遮罩导致的手机端进入会话空白、侧栏及首页设置按钮无法点击的问题。
30
34
 
31
35
  ## 2.3.9(2026-11-05)
32
36
 
33
37
  ### 新增
34
38
 
35
- - **适配 `dsh-better-sidebar` 0.30.0**:适配器新增 `/sidebar/sidechat-image` 旁聊图片路由适配,
36
- 并为多图载荷设置转发上限,旧版侧边栏插件的行为不受影响。
37
- - **手机端新建会话先定工作区(UX-3)**:点「+ 新建会话」直接进无工作区空会话时,
38
- 手机端此前会卡在英雄区 inert 的「选择工作区」状态。现在点下 FAB 先做决定:
39
- 已选工作区直接开;零或一个工作区直接用唯一值(无工作区的宿主保持原样可用);
40
- 多个工作区且未选时,FAB 先弹出与标题栏一致的工作区底部抽屉,选好才开始会话。
41
- 工作区切换瞬间(建会话 → `replaceMain` 重挂载)输入栏短暂锁定置灰
42
- (上限 1.5s 自动解锁),防止消息落在旧空会话上被重挂载抹掉、界面弹回占位态。
43
- - **首次激活子客户端后自动重载页面(UX-1)**:页面三条常驻全局流在加载时打开,
44
- 后端的流拦截器要等插件行重载后才装上——已打开的流不被包装,服务端的远程会话
45
- 从此进不了侧边栏。现在首次配对或保存把角色切到 client 后,等待
46
- `client/status` 就绪(最多 3 秒)即自动重载;已是 client 的重新配对、写盘未落、
47
- 旧服务端(无诊断应答)都保持不重载。
39
+ - **适配 `dsh-better-sidebar` 0.30.0**:支持远程会话转发旁聊图片路由 `/sidebar/sidechat-image`。
40
+ - **手机端新建会话先定工作区**:多工作区未选定状态下点「+ 新建会话」先弹出工作区选择抽屉,防止卡在空会话占位页或切换瞬间丢消息。
41
+ - **首次激活子客户端后自动重载页面**:首次配对或切换为子客户端角色后自动刷新页面,让侧边栏远程分组立即生效。
48
42
 
49
43
  ### 修复
50
44
 
51
- - **手机端任务/子代理弹出层点错位(UX-2)**:活动胶囊的触发器选择器此前先命中
52
- 面包屑的父会话切换器(同为 tree 弹层、文档序更靠前),胶囊上盖的是错误按钮;
53
- 弹出层也不再跟随胶囊位置。现在按类名后缀精确锁定目录触发器,并把触发器及其
54
- 锚点容器(同步 `z-index: 3` 层叠上下文)钉在活动胶囊的固定视口矩形上,弹出层
55
- 即随胶囊出现;同时固定左上角返回按钮在智能体团队按钮左侧并隐去后者文字标签。
56
- - **手机端右侧栏初始引导页纵向滚动**:当注册的侧边栏标签页变多超出屏幕高度时,
57
- 宿主引导页(`[data-sidebar-right-guide]`)此前因居中溢出与外层 `overflow: hidden`
58
- 裁切导致排在前面的入口无法看到或点击,现支持完整上下滚动。
45
+ - **手机端任务/子代理弹出层点错位**:修复会话顶栏活动胶囊误触父会话切换器及弹层位置偏移的问题。
46
+ - **手机端右侧栏初始引导页纵向滚动**:修复右侧栏标签较多超出屏幕高度时无法上下滚动查看的问题。
59
47
 
60
48
  ## 2.3.8(2026-11-03)
61
49
 
62
50
  ### 兼容
63
51
 
64
- - **DSH 0.2.2-alpha.3**:`session/control` 的实时 `projection` 帧改为按事件批量
65
- (`seq` + `changes[{key, val}]`,取代逐键的 `key` / `value`)。子客户端合并远程
66
- 控制流时两种形态都能读,并统一拆成「逐键字段 + 单条 `changes`」的双形态帧,
67
- 本机 DSH 新旧版本都能直接应用(本机与服务端版本不一致时会话标题、模型选择等
68
- 投影不再停更或打断控制流);服务端补发的投影帧同样改为双形态。
69
- - 插件清单声明 `dsh.manifestVersion: 1` 与 `engines.dsh: ">=0.2.1-alpha.2 <0.3.0-0"`
70
- (含预发布:覆盖 npm latest 0.2.1-rc.5 与 alpha 通道 0.2.2-alpha.3)。
52
+ - **适配 DSH 0.2.2-alpha.3**:兼容批量格式的实时会话状态投影帧,跨版本连接时会话标题与模型选择等状态正常同步。
53
+ - **更新插件版本声明**:声明 `dsh.manifestVersion: 1` 与 `engines.dsh: ">=0.2.1-alpha.2 <0.3.0-0"`。
71
54
 
72
55
  ## 2.3.7(2026-11-02)
73
56
 
74
57
  ### 新增
75
58
 
76
- - **远程附件守卫扩展到回形针与粘贴**(issue #49):此前只有拖拽会把「带子客户端
77
- 本机路径的非图片文件」从宿主的零拷贝捷径里拦下、改走字节上传,现在回形针选择器
78
- 与编辑器粘贴同样命中;拖入 / 粘贴**文件夹**时整批拦下并提示;附带 fetch-route
79
- 懒装重试与卸载守卫。
80
- - **导出诊断信息**:插件设置区块底部一键下载 `zen-remote-debug-<role>-<时间戳>.json`
81
- (版本与角色 / 配置形态 / 诊断聚合 / host 另含网关摘要 / 近 300 条插件事件),
82
- 两层脱敏(配置按字段名挑选 + 统一脱敏器),可直接附到 GitHub issue;
83
- 经网关打开时拒绝导出,报告只能在本机生成。
59
+ - **远程附件上传扩展到回形针与粘贴**([#49](https://github.com/KyoMio/dsh-zen-remote/issues/49)):子客户端远程会话中通过回形针选择或粘贴本机非图片文件时自动转为字节上传到服务端,并在拖入或粘贴文件夹时明确提示不支持。
60
+ - **导出诊断信息**:插件设置页底部支持一键下载脱敏诊断 JSON,便于排查问题与附到 GitHub issue。
84
61
 
85
62
  ### 修复
86
63
 
87
- - **宽幅平板独立 PWA 顶部安全区**(≥1024px:iPad 横屏、12.9/13 吋 iPad 竖屏恰为
88
- 1024、安卓平板):网关对所有非 desktop 设备注入 `viewport-fit=cover`,但安全区
89
- 补偿止步于 1023px 断点,顶部控件被压进状态栏、难以点按。新增
90
- `(min-width: 1024px) and (display-mode: standalone)` 双门控规则补齐上下两个安全区
91
- (锚定官方 AppFrame,`border-box` + `--mnav-sat`/`--mnav-sab`);桌面浏览器与
92
- 桌面 App 构造性 no-op,≥1024px 桌面逐像素不变的硬约束不受影响。
93
- - **平板 PWA 整页可拖动弹回**:壳级 `overscroll-behavior` 此前只写在 body 且仅
94
- 纵轴,视口级橡皮筋在 768px 以上仍然活着。现 html/body 双写、双向杀掉;
95
- 内部滚动区不受影响,只是边缘滚动不再链到整页。
64
+ - **宽幅平板独立 PWA 顶部安全区**:补齐 ≥1024px 独立 PWA 模式下的上下安全区内边距,避免顶部按钮被状态栏遮挡。
65
+ - **平板 PWA 整页拖动回弹**:禁用视口级橡皮筋回弹,避免边缘滑动时整页跟着晃动。
96
66
 
97
67
  ## 2.3.6(2026-10-31)
98
68
 
99
- - 插件桥:支持 json-body WebSocket 帧的会话 id 定位与改写(`/sidebar/ws/sidechat`)。
100
- - 中继:观察 `agent/created` 的父会话,同步未通告的 sidechat / 子代理摘要。
101
- - 手机端:turn-tail 的 24h 时钟不再折行;信息卡合并 turns / steps 计数并显示 tok/s 速度。
69
+ - 插件桥:支持 `/sidebar/ws/sidechat` 旁聊 WebSocket 的会话定位与转发。
70
+ - 中继:同步新建子代理与旁聊会话的实时运行状态。
71
+ - 手机端:修复对话尾部 24h 时间折行,信息卡合并轮次/步数并新增 `tok/s` 输出速度。
102
72
 
103
73
  ## 2.3.5(2026-10-30)
104
74
 
105
- - turn-fold:纯签名推理步不再留下空行(适配 DSH 0.2.1-rc.5)。
106
- - 安全与维护:新增 SECURITY.md 与 Dependabot(`@deepseek-ai/*` 闭包手动管理)、
107
- 测试以 `vm` 替代 `eval`;中继背压用例改为按余量驻留,修掉 CI 上的两连假失败。
75
+ - 折叠:修复 DSH 0.2.1-rc.5 下纯签名推理步留下空行的问题。
76
+ - 维护:新增 `SECURITY.md` 与 Dependabot 配置,优化测试稳定性。
108
77
 
109
78
  ## 2.3.4(2026-10-28)
110
79
 
111
- - 插件桥 v2 声明补全(PB-22 ~ PB-25):`deny` 路由对一切远程上下文统一 503 拒答;
112
- `rewriteIds` 新增创建型 `{ fields }` 声明,深扫改写范围扩到「请求自带 ∪ 已知会话
113
- 清单」;路径段 / json-body 定位路由进入协作校验链(逐命中共享校验、请求体体积
114
- 上限、隧道升级前置校验)。
80
+ - 插件桥 v2:支持 `deny` 路由拒答、`rewriteIds` 响应会话 ID 改写,以及路径段与 JSON 体的会话定位校验。
115
81
 
116
82
  ## 2.3.3(2026-10-27)
117
83
 
118
- - 适配 dsh-better-sidebar 0.28.2;接受 DSH 0.2.2-alpha peer 并钉该版本的会话指纹。
84
+ - 适配 `dsh-better-sidebar` 0.28.2,并支持 DSH 0.2.2-alpha 版本接口指纹。
119
85
 
120
86
  ## 2.3.2(2026-10-26)
121
87
 
122
- - 发版重跑,无代码变化(仅版本号与 README 徽章)。
88
+ - 发版流程重跑,仅更新版本号与文档徽章。
123
89
 
124
90
  ## 2.3.1(2026-10-26)
125
91
 
126
- - 配置向导:三步配置向导上线(README 安装 / 向导快速上手重排并配截图);Caddy
127
- 预编译发行版与国内镜像自动探测、cloudflared / Caddy 的连接与停滞超时、模式切换
128
- 停进程与状态清理;CI 每日预编译 Caddy + cloudflared 全平台产物并自动跟踪上游。
129
- - 安全:网关在 `0.0.0.0` 上拒绝未反代的公网 IP 直连;Caddy / Tunnel 模式把 host
130
- 重置回 `127.0.0.1`。
131
- - Windows:修复 Caddy 裸二进制下载、Cloudflare Tunnel UUID CNAME 校验、向导保存
132
- CF token 前先切回 host 角色、重命名回退,以及网关 spawn 时绕开 `node.cmd`
133
- 批处理包装。
92
+ - 配置向导:上线三步配置向导,支持内置 Caddy 自动证书与 Cloudflare Tunnel 一键拉起(含国内镜像加速)。
93
+ - 安全:网关监听 `0.0.0.0` 时拒绝公网 IP 未反代直连,Caddy / Tunnel 模式自动切回 `127.0.0.1`。
94
+ - Windows:修复 Caddy / Tunnel 向导配置与网关子进程启动兼容问题。
134
95
 
135
96
  更早版本(≤ 2.2.9)见 [GitHub Releases](https://github.com/KyoMio/dsh-zen-remote/releases)。
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <h1 align="center">dsh-zen-remote</h1>
2
- <p align="center">One DeepSeek Harness plugin, two roles. The <b>host</b> turns DSH into a phone-reachable PWA (mobile UI, pairing gateway, lock-screen push) and shares chosen sessions to paired desktops. The <b>client</b> runs inside another DSH desktop app and puts the host's shared sessions right into its own sidebar — full history, live progress, messages, approvals, terminal, everything executes on the host.</p>
2
+ <p align="center">One DeepSeek Harness plugin, two roles. The <b>host</b> turns DSH into a phone-reachable PWA (mobile UI, pairing gateway, lock-screen push) and shares chosen sessions to paired desktops. The <b>client</b> runs inside another DSH desktop app and puts the host's shared sessions right into its own sidebar (up to <b>8 hosts</b> connected simultaneously) — full history, live progress, messages, approvals, terminal, everything executes on the host.</p>
3
3
 
4
4
  <p align="center">
5
5
  <a href="https://www.npmjs.com/package/dsh-zen-remote"><img src="https://img.shields.io/npm/v/dsh-zen-remote?style=flat-square&color=5B4CF0&logo=npm&label=npm" alt="npm version"></a>
@@ -21,7 +21,7 @@
21
21
  | ![Session list home](assets/home.png) | ![Session page](assets/session.png) | ![Session info card](assets/info.png) |
22
22
 
23
23
  | Composer permission sheet | Pairing page a public visitor sees |
24
- | --- | --- |
24
+ | --- | --- | --- |
25
25
  | ![Composer permission sheet](assets/sheet.png) | ![Pairing page](assets/pairing.png) |
26
26
 
27
27
  > Screenshots are a 390×844 phone viewport in the light theme; both themes are supported. The pairing page is drawn by the gateway in DSH's official style, following the system light / dark appearance.
@@ -33,7 +33,7 @@
33
33
  1. [Install](#1-install)
34
34
  2. [Quick Start (Unified Setup & Pairing Wizard)](#2-quick-start-unified-setup--pairing-wizard)
35
35
  - [Scenario A: Set up as Host (Phone & Desktop Access)](#scenario-a-set-up-as-host-phone--desktop-access)
36
- - [Scenario B: Set up another computer as Desktop Client](#scenario-b-set-up-another-computer-as-desktop-client)
36
+ - [Scenario B: Set up as Desktop Client (Connect up to 8 Hosts)](#scenario-b-set-up-as-desktop-client-connect-up-to-8-hosts)
37
37
  3. [Daily Usage: Session Sharing & Cross-Device Workflow](#3-daily-usage-session-sharing--cross-device-workflow)
38
38
  4. [Lock-Screen Push: When Notifications Fire](#4-lock-screen-push-when-notifications-fire)
39
39
  5. [Features](#5-features)
@@ -52,11 +52,44 @@ Open the **Plugins** page in the DSH sidebar → click **Add plugin** → type `
52
52
 
53
53
  ```sh
54
54
  dsh plugin --profile web add dsh-zen-remote
55
- # then restart dsh web
55
+ # then restart dsh web (or run `npx dsh-zen-remote setup` to install, start, and configure in one go)
56
56
  ```
57
57
 
58
58
  > `dsh plugin` requires `--profile` to name the target profile. The desktop app's `desktop` profile is managed exclusively by the app (`--profile desktop` is refused on the CLI), so use the UI install above on the desktop app.
59
59
 
60
+ ### Headless Server CLI Wizard (`dsh-zen-remote`)
61
+
62
+ The plugin ships a bundled CLI tool so remote VPS / headless servers (`dsh web`) can complete the entire setup, ingress configuration, three-light verification, and QR / desktop pairing flow in a terminal without opening a browser:
63
+
64
+ ```sh
65
+ npx dsh-zen-remote setup # 3-step interactive wizard: role → ingress → verify + terminal QR & desktop pairing
66
+ dsh-zen-remote status # current role, gateway & connection state (--json; --debug exports redacted diagnostics)
67
+ ```
68
+
69
+ <details>
70
+ <summary>Expand full CLI subcommand reference (<code>host</code> / <code>client</code> / non-interactive flags)</summary>
71
+
72
+ ```sh
73
+ # Host commands (when role is host)
74
+ dsh-zen-remote host device pair --device-role web # mint a phone/browser pairing code + terminal QR (or desktop-client)
75
+ dsh-zen-remote host device list # list paired devices (--json supported)
76
+ dsh-zen-remote host device revoke <id|--all> [--yes] # revoke one or all paired devices
77
+ dsh-zen-remote host ingress start --mode lan # configure & start ingress (caddy | cloudflared | external | lan)
78
+ dsh-zen-remote host ingress stop [--yes] # stop managed Caddy / Cloudflare Tunnel processes
79
+ dsh-zen-remote host ingress verify [--no-wait] # three-light check + mint web QR & desktop pairing codes
80
+ dsh-zen-remote host ingress snippet [--proxy nginx|caddy|lucky] # print reverse-proxy config snippets
81
+
82
+ # Client commands (when role is client, up to 8 paired hosts)
83
+ dsh-zen-remote client pair http://192.168.1.2:3088 --code 12345678 [--name My-Mac]
84
+ dsh-zen-remote client list # list all paired hosts (up to 8) and connection states
85
+ dsh-zen-remote client unpair <hostUrl|entryId|--all> [--yes] # remove one or all paired hosts
86
+ ```
87
+
88
+ - **Preflight & non-interactive automation**: `setup` automatically scans candidate profiles for multi-select plugin installation (`desktop` is skipped) and launches the DSH daemon / app before starting the wizard. Pass `--yes` with the required flags (e.g. `setup --role host --ingress lan --no-wait --yes`) for unattended scripts.
89
+ - **Architecture**: the CLI communicates with the running plugin over a `0600` local IPC socket (`~/.dsh/zen-remote-cli.sock`); Caddy and `cloudflared` stay managed by the plugin process. Use `--lang zh|en` to switch output language.
90
+
91
+ </details>
92
+
60
93
  <details>
61
94
  <summary>Manual Profile Edit / Local Development (<code>link:</code>), Upgrading & Uninstall</summary>
62
95
 
@@ -66,7 +99,7 @@ dsh plugin --profile web add dsh-zen-remote
66
99
  // ~/.dsh/profiles/desktop/package.json
67
100
  {
68
101
  "dependencies": {
69
- "dsh-zen-remote": "^2.3.11" // for local development: "link:/path/to/dsh-zen-remote"
102
+ "dsh-zen-remote": "^2.4.0" // for local development: "link:/path/to/dsh-zen-remote"
70
103
  }
71
104
  }
72
105
  ```
@@ -80,7 +113,7 @@ cd ~/.dsh/profiles/desktop && pnpm install
80
113
  - **Upgrading with HMR on**: remove `dsh-zen-remote` first, then install the new version (`dsh plugin --profile <name> remove dsh-zen-remote` → `add dsh-zen-remote`, or Uninstall → Add in the Plugins page).
81
114
  - **DSH 0.2.1-alpha.3+ profile reset**: `dsh --profile <name> --from-default-profile <template>` replaces an existing custom profile with a fresh copy; back up `~/.dsh/profiles/<name>` first.
82
115
  - **Upgrading from 1.x**: since 2.0.0 the composition layer is a single row (`dsh-zen-remote`). Remove any legacy `dsh-zen-remote-gateway`, `dsh-zen-remote-push`, or manual `dsh-push.mjs` lines from `cordis.patch.yml`. Existing `~/.dsh/lan-gate.config.json` settings and paired devices carry over automatically.
83
- - **Uninstalling**: click **Uninstall** on the `dsh-zen-remote` plugin page and restart. To also wipe pairing and share state, delete `~/.dsh/lan-gate-state.json`, `~/.dsh/lan-gate.config.json`, `~/.dsh/zen-remote-shares.json`, and `~/.dsh/zen-remote-server.json`.
116
+ - **Uninstalling**: click **Uninstall** on the `dsh-zen-remote` plugin page and restart. To also wipe pairing and share state, delete `~/.dsh/lan-gate-state.json`, `~/.dsh/lan-gate.config.json`, and `~/.dsh/zen-remote-state.json` (older versions also kept `~/.dsh/zen-remote-shares.json` and `~/.dsh/zen-remote-server.json` — they migrate into the state file automatically on first start and are then deleted).
84
117
 
85
118
  </details>
86
119
 
@@ -90,9 +123,9 @@ cd ~/.dsh/profiles/desktop && pnpm install
90
123
 
91
124
  The same plugin supports two roles:
92
125
  - **Server (`role: host`, default)**: runs your sessions, spawns the local security gateway and Web Push service, and lets your phone (PWA) or another computer connect.
93
- - **Desktop Client (`role: client`)**: runs inside another computer's DSH desktop app, connects to the host, and mounts the host's shared sessions directly into its own sidebar (without spawning a local gateway or fighting for port 3088).
126
+ - **Desktop Client (`role: client`)**: runs inside another computer's DSH desktop app, connects to **up to 8 hosts simultaneously**, and mounts their shared sessions directly into its own sidebar (without spawning a local gateway or fighting for port 3088).
94
127
 
95
- Open **Plugins → `dsh-zen-remote`** in DSH. The **Remote Access & Device Pairing** card sits right at the top of the page:
128
+ Open **Plugins → `dsh-zen-remote`** in DSH. The **Remote Access & Device Pairing** card sits right at the top of the page (or run `npx dsh-zen-remote setup` on a headless server):
96
129
 
97
130
  ![Remote Access & Device Pairing overview card on the plugin detail page](docs/images/wizard-overview.png)
98
131
 
@@ -100,51 +133,47 @@ Open **Plugins → `dsh-zen-remote`** in DSH. The **Remote Access & Device Pairi
100
133
 
101
134
  ### Scenario A: Set up as Host (Phone & Desktop Access)
102
135
 
103
- Click **Start Setup Wizard** (or **Reconfigure Wizard** if already configured) to complete setup in three guided steps:
136
+ Click **Start Setup Wizard** (or **Reconfigure Wizard**) to complete setup in three guided steps:
104
137
 
105
138
  #### Step 1: Choose "Act as Server (Host)" & an Access Method
106
139
 
107
140
  ![Wizard Step 1: Choose machine role and server access method](docs/images/wizard-step1-role-path.png)
108
141
 
109
- Pick one of the four access methods based on your network environment (switching methods automatically stops any managed process from the previous mode and updates the gateway bind address):
110
-
111
142
  | Access method | Best for | What the wizard automates |
112
143
  | --- | --- | --- |
113
- | **Managed Caddy (Recommended)** | Public IP (or router port forwarding) + domain on Cloudflare | Automatically downloads a prebuilt `Caddy + caddy-dns/cloudflare` binary (auto-accelerated via mainland China mirrors when needed) and issues/renews TLS certificates via DNS-01; gateway listens only on `127.0.0.1:3088` |
114
- | **Existing Reverse Proxy** | Already running Nginx, Caddy, or Lucky | Generates ready-to-paste proxy snippets with WebSocket and `X-Forwarded-*` headers, plus one-click `trustedProxies` registration (full manual guide: [docs/remote-access.en.md](docs/remote-access.en.md)) |
115
- | **Cloudflare Tunnel** | No public IP / no router port forwarding + domain on Cloudflare | Automatically downloads `cloudflared` (with mainland China mirror failover), creates or reuses a tunnel via the Cloudflare API, writes the DNS CNAME record, and starts the tunnel; gateway listens only on `127.0.0.1:3088` |
116
- | **LAN / Tailscale Direct** | Same Wi-Fi / LAN or shared Tailscale virtual network | No domain or TLS certificate needed; auto-detects the machine's LAN / Tailscale IPv4 address and binds `0.0.0.0:3088`, while the gateway's built-in **private-IP wall** rejects any unproxied direct connection from a public internet IP (`403 public-direct-forbidden`) |
144
+ | **Managed Caddy (Recommended)** | Public IP (or router port forwarding) + domain on Cloudflare | Downloads prebuilt `Caddy + caddy-dns/cloudflare` and issues/renews TLS certificates via DNS-01 (`127.0.0.1:3088`) |
145
+ | **Existing Reverse Proxy** | Already running Nginx, Caddy, or Lucky | Generates ready-to-paste proxy snippets + one-click `trustedProxies` registration ([manual guide](docs/remote-access.en.md)) |
146
+ | **Cloudflare Tunnel** | No public IP / no port forwarding + domain on Cloudflare | Downloads `cloudflared`, creates/reuses a tunnel, configures CNAME, and starts the tunnel (`127.0.0.1:3088`) |
147
+ | **LAN / Tailscale Direct** | Same Wi-Fi / LAN or shared Tailscale network | Auto-detects LAN / Tailscale IPv4 and binds `0.0.0.0:3088` behind the built-in **private-IP wall** (`403 public-direct-forbidden`) |
117
148
 
118
149
  #### Step 2: Fill in Connection Parameters
119
- - **Managed Caddy / Cloudflare Tunnel**: enter your public domain (e.g. `dsh.example.com`) and paste your Cloudflare API Token (click *"How do I get an API token?"* for step-by-step instructions and required permissions, or *"Domain not on Cloudflare yet?"* for onboarding steps).
120
- - **Existing Reverse Proxy**: enter the external `https://` URL of your proxy and copy the generated Nginx / Caddy / Lucky configuration snippet.
121
- - **LAN / Tailscale Direct**: the wizard automatically detects and pre-fills `http://<your-LAN-or-Tailscale-IP>:3088`.
150
+ - **Managed Caddy / Cloudflare Tunnel**: enter your public domain (e.g. `dsh.example.com`) and paste your Cloudflare API Token.
151
+ - **Existing Reverse Proxy**: enter the external `https://` URL and copy the generated Nginx / Caddy / Lucky configuration snippet.
152
+ - **LAN / Tailscale Direct**: confirm the auto-detected `http://<your-LAN-or-Tailscale-IP>:3088` address.
122
153
 
123
154
  #### Step 3: Verify Connectivity & Pair Devices
124
155
 
125
156
  ![Wizard Step 3: Automatic connectivity check, phone QR pairing, and desktop client pairing](docs/images/wizard-step3-verify-pair.png)
126
157
 
127
- 1. **Start Ingress Service & Auto-Probe**:
128
- - For Managed Caddy or Cloudflare Tunnel, click **Start Caddy** or **Create & Start Tunnel** in the service bar.
129
- - The wizard automatically probes **Local gateway ready** and **Access URL reachable** (verifying that `/` serves the `401` pairing page and `/lan-gate/admin` returns `403`).
130
- 2. **Pair Phone / Browser (Web App)**:
131
- - On the **Pair Phone / Browser (QR)** tab, click **Generate Pairing QR**.
132
- - Scan the QR code with your phone camera or browser, enter the 8-character pairing code, and use **"Add to Home Screen"** to install DSH as a standalone PWA with lock-screen push notifications.
133
- 3. **Pair Another Computer (Desktop Client)**:
134
- - Switch to the **Pair Desktop Client** tab, click **Generate Desktop Pairing Code**, and click **Copy Server URL & Code** to send to your other computer.
158
+ 1. **Start Ingress Service & Auto-Probe**: click **Start Caddy** or **Create & Start Tunnel** if applicable; the wizard automatically checks **Local gateway ready** and **Access URL reachable**.
159
+ 2. **Pair Phone / Browser (Web App)**: on the **Pair Phone / Browser (QR)** tab, click **Generate Pairing QR**, scan with your phone, enter the 8-character code, and use **"Add to Home Screen"** to install DSH as a standalone PWA with lock-screen push.
160
+ 3. **Pair Another Computer (Desktop Client)**: switch to the **Pair Desktop Client** tab, click **Generate Desktop Pairing Code**, and click **Copy Server URL & Code**.
135
161
 
136
- > **Quick actions after setup**: once configured, you can directly click **Pair Phone (QR)**, **Pair Desktop Client**, or **Manage Devices** (rename devices, switch device roles, revoke one or all devices, or send a test push) right from the overview card footer without re-running the wizard.
162
+ > **Quick actions after setup**: once configured, you can directly click **Pair Phone (QR)**, **Pair Desktop Client**, or **Manage Devices** right from the overview card footer without re-running the wizard.
137
163
 
138
164
  ---
139
165
 
140
- ### Scenario B: Set up another computer as Desktop Client
166
+ ### Scenario B: Set up as Desktop Client (Connect up to 8 Hosts)
141
167
 
142
- On the second computer running the DSH desktop app:
168
+ On another computer running the DSH desktop app (or via `dsh-zen-remote client pair <hostUrl> --code <8-char-code>` on the CLI):
143
169
 
144
- 1. Open **Plugins → `dsh-zen-remote`** and click **Start Setup Wizard**.
145
- 2. **Step 1**: select **Act as Desktop Client** and click **Next**.
146
- 3. **Step 2**: enter a name for this computer (e.g. `Living-Room-Mac`), the host's gateway URL (`https://` for public URLs, or `http://192.168.x.x:3088` / `http://100.x.x.x:3088` for LAN / Tailscale), and the 8-character desktop pairing code from the host, then click **Pair & Connect**.
170
+ 1. Open **Plugins → `dsh-zen-remote`** and click **Start Setup Wizard** (or **+ Add Server** if already in client mode).
171
+ 2. **Step 1**: select **Desktop Client** and click **Next**.
172
+ 3. **Step 2**: enter this computer's display name (e.g. `Living-Room-Mac`), the host's gateway URL (`https://` for public URLs, or `http://192.168.x.x:3088` / `http://100.x.x.x:3088` for LAN / Tailscale), and the 8-character desktop pairing code from the host, then click **Pair & Connect**.
147
173
  4. **Step 3**: once all three status lights (**Pairing token**, **Server connection**, **Session & plugin sync**) turn green, the host's shared workspaces and sessions appear in your left sidebar immediately.
174
+ 5. **Multi-Server Management (up to 8 hosts)**:
175
+ - Click **+ Add Another Server** in Step 3, **+ Add Server** on the overview card, or **Manage Servers** to view per-server status, **Reconnect**, **Re-pair**, **Remove**, or **Remove All** (when all `8 / 8` slots are full, a red limit notice appears; re-pairing an existing URL still overwrites in place).
176
+ - Sidebar groups from all paired hosts merge **in pairing order** after your local workspaces. Duplicate host names are automatically numbered `Name-1`, `Name-2`; model pickers, connection status icons, read-only banners, plugin bridges, and file uploads are strictly isolated per host `serverId`.
148
177
 
149
178
  ---
150
179
 
@@ -153,18 +182,18 @@ On the second computer running the DSH desktop app:
153
182
  | | **Web App Device (Phone / Tablet / Browser)** | **Desktop Client (Another DSH Desktop App)** |
154
183
  | --- | --- | --- |
155
184
  | Visible sessions | **All** sessions on the host | **Only** sessions with remote access enabled on the host (enforced server-side) |
156
- | Credential | Long-lived HttpOnly cookie | Secret device token stored in the plugin config (`Bearer` token) |
185
+ | Credential | Long-lived HttpOnly cookie | Secret device token stored in `~/.dsh/zen-remote-state.json` (`Bearer` token) |
157
186
 
158
187
  ### Enabling or Disabling Remote Access on a Session
159
188
 
160
- Remote access is controlled per session (or automatically enabled for new sessions if you turn on *Auto-share new sessions* in Step 2 of the wizard). You can toggle it from four places:
189
+ Remote access is controlled per session (or automatically enabled for new sessions if you turn on *Auto-share new sessions*). You can toggle it from four places:
161
190
 
162
191
  1. **Host sidebar**: open a session's `"…"` menu and click **开启远程 / 关闭远程** (Enable / Disable remote);
163
192
 
164
193
  ![Enabling remote access from a session's menu on the host](docs/images/host-share-menu.png)
165
194
 
166
- 2. **Host session header**: click the globe icon in the session title row (hover to see remaining idle time; a dot indicates a desktop client is currently viewing it);
167
- 3. **Phone (Web App) session info card**: open the info card at the top right of a session and toggle **远程访问** (Remote access);
195
+ 2. **Host session header**: click the globe icon in the session title row (hover to see remaining idle time; a green dot indicates a desktop client is currently viewing it);
196
+ 3. **Phone (Web App) session info card**: open the `ⓘ` info card at the top right of a session and toggle **远程访问** (Remote access);
168
197
 
169
198
  <p align="center"><img src="docs/images/mobile-info-remote.png" alt="Remote access toggle inside the phone session info card" width="320"></p>
170
199
 
@@ -172,11 +201,11 @@ Remote access is controlled per session (or automatically enabled for new sessio
172
201
 
173
202
  ### Working in Remote Sessions on a Desktop Client
174
203
 
175
- - **Sidebar groups**: once a host workspace has at least one remote-enabled session, a **"Server Name · Workspace Name"** group appears in the client's sidebar. Click any session to view full history, stream responses, approve tools, use the server terminal, browse files and diffs, download deliverables, or drag-and-drop files to upload.
204
+ - **Sidebar groups**: once a host workspace has at least one remote-enabled session, a **"Server Name · Workspace Name"** group appears in the client's sidebar (up to 8 paired hosts, stacked in pairing order). Click any session to view full history, stream responses, approve tools, use the server terminal, browse files and diffs, preview inline images, download deliverables, or drag/paste/pick files to upload.
176
205
 
177
206
  ![Remote workspace group in the desktop client sidebar](docs/images/client-sidebar.png)
178
207
 
179
- - **Closing & idle sleep**: a shared session automatically closes remote access after **48 hours** (`idleHours`) of inactivity (mid-turn sessions or sessions waiting on approvals/questions never sleep). When remote access is closed—or when the client unpairs or its token is revoked—remote sessions are automatically archived/hidden from the sidebar; an actively open session displays a "remote closed" banner and recovers automatically if re-shared.
208
+ - **Closing & idle sleep**: a shared session automatically closes remote access after **48 hours** (`idleHours`) of inactivity (running or waiting sessions never sleep). Closed or unpaired sessions are automatically archived/hidden from the sidebar; an actively open session displays a "remote closed" banner and recovers automatically if re-shared.
180
209
 
181
210
  ![Banner shown when remote access is closed on an open session](docs/images/client-remote-closed.png)
182
211
 
@@ -184,34 +213,22 @@ Remote access is controlled per session (or automatically enabled for new sessio
184
213
 
185
214
  ## 4. Lock-Screen Push: When Notifications Fire
186
215
 
187
- Notifications fire only when **you are actually needed**, along two independent paths (all payloads are end-to-end encrypted with `aes128gcm`):
216
+ Notifications fire only when **you are actually needed**, along two independent paths (all payloads are end-to-end encrypted with `aes128gcm`; toggle `pushEnabled` to disable all notifications and unregister `push_notify`, or enable `pushSessionName` to show `Session: <name>` on the first line of the notification body):
188
217
 
189
- 1. **System-triggered (always on, never suppressed by debounce)**:
190
- - **Tool waiting for approval**: pushes *"DSH needs your approval"* with the tool name. Waits `DSH_PUSH_APPROVAL_GRACE_MS` (default 5s) before sending so fast auto-approver plugins can answer first without buzzing your phone.
218
+ 1. **System-triggered (always on when `pushEnabled` is on, never suppressed by debounce)**:
219
+ - **Tool waiting for approval**: pushes *"DSH needs your approval"* with the tool name after `DSH_PUSH_APPROVAL_GRACE_MS` (default 5s, so fast auto-approvers can answer first without buzzing your phone).
191
220
  - **`ask_user_question` waiting for your answer**: pushes *"DSH is waiting for your answer"*.
192
- - Works for both top-level sessions and subagent sessions across Web and Desktop hosts.
193
221
  2. **Model-triggered (`push_notify` tool)**:
194
- - Called by the agent when you asked to be notified upon completion, or when it hits a blocker that requires your decision.
195
- - Ordinary turn completions do not push by default (enable `pushTurnEnd` in advanced settings if you want a push after every turn; enable `pushSummary` to include up to 120 characters of the final reply in the notification body).
222
+ - Called by the agent when you asked to be notified upon completion, or when it hits a blocker that requires your decision. Ordinary turn completions do not push by default (enable `pushTurnEnd` if wanted; enable `pushSummary` to include up to 120 characters of the final reply).
196
223
 
197
224
  ---
198
225
 
199
226
  ## 5. Features
200
227
 
201
- - **Mobile PWA UI (Host)**:
202
- - Two-level page stack (session list home + standalone session page with left-edge swipe back, Android back-gesture support, first-frame boot skeleton, and immutable asset caching)
203
- - Home-screen plugin entry chips (auto-discovered per installed plugin, individually toggleable)
204
- - Compact mobile composer with bottom sheets for permissions/models and direct phone attachment uploads
205
- - Session info card (6-tile stats, log export, rename, fork, archive, one-tap full-conversation PNG share image, and remote access switch)
206
- - **Unified Setup & Pairing Wizard (2.3)**:
207
- - Top-of-page 2×2 live overview card and 3-step modal wizard covering all four host ingress modes (Managed Caddy, Existing Reverse Proxy, Cloudflare Tunnel, LAN / Tailscale Direct) and Desktop Client pairing
208
- - Automatic download of prebuilt `Caddy + caddy-dns/cloudflare` and `cloudflared` binaries with mainland China network auto-detection, mirror acceleration (`gh-proxy.com` / `ghfast.top`), connect/stall failover watchdogs, and daily upstream release tracking via GitHub Actions
209
- - Automatic LAN / Tailscale IPv4 discovery and local network probing, backed by the gateway's private-IP wall (`403 public-direct-forbidden`) against accidental public exposure
210
- - Dedicated **Manage Devices** modal and automatic sidebar cleanup on client unpair/revocation
211
- - **Cross-Desktop Remote Sessions (Client)**:
212
- - Full-featured remote sessions in the sidebar: history, streaming, approvals/questions, server model catalog, file tree, changes summary/diff, server-side terminal, windowed artifact downloads, server-side LibreOffice PDF preview, up to 500 MiB file uploads, and drag-and-drop file upload interception; in remote sessions, non-image files added via the paperclip picker or pasted are likewise converted to byte uploads instead of unreadable local-path references
213
- - **Plugin Bridge**:
214
- - Cooperative plugins and built-in adapters (such as `dsh-better-sidebar`) route their panel requests in remote sessions to the host machine (with explicit owner consent for whole-machine data). See [Plugin Bridge Guide](docs/plugin-bridge.md).
228
+ - **Mobile PWA UI (Host)**: two-level page stack (session list home + session page with swipe-back and Android back-gesture support, first-frame boot skeleton, immutable asset caching), auto-discovered plugin entry chips, compact mobile composer with bottom sheets and phone attachment uploads, and a session info card (6-tile stats with `tok/s` output speed, log export, rename, fork, archive, one-tap full-conversation PNG share image, and remote access switch).
229
+ - **Unified Setup Wizard & Headless CLI (`dsh-zen-remote`)**: top-of-page 2×2 live overview card, 3-step modal wizard, and a full-featured terminal CLI (`setup` / `status` / `host` / `client`) covering all four host ingress modes (Managed Caddy, Existing Reverse Proxy, Cloudflare Tunnel, LAN / Tailscale Direct with private-IP wall) and client pairing.
230
+ - **Cross-Desktop Remote Sessions & Multi-Server Pool (Client)**: connect up to **8 main servers** simultaneously in pairing order; supports full history & live streaming, approval/question sync, per-server isolated model catalog, file tree & Git diffs, duplex server-side terminal (`terminal/attach`), inline Markdown image & media forwarding, windowed artifact downloads, server-side LibreOffice PDF preview, up to 500 MiB file uploads (drag-and-drop, paperclip picker, and paste), and one-click redacted diagnostics export.
231
+ - **Plugin Bridge**: cooperative plugins and built-in adapters (such as `dsh-better-sidebar` `0.25.0`–`0.30.1`) route their panel HTTP and WebSocket requests in remote sessions to the host machine (with explicit owner consent for whole-machine data). See [Plugin Bridge Guide](docs/plugin-bridge.md).
215
232
 
216
233
  In depth: [Interface Design](docs/interface.md) · [Public Access & Relay Protocol](docs/remote-access.en.md)
217
234
 
@@ -219,21 +236,21 @@ In depth: [Interface Design](docs/interface.md) · [Public Access & Relay Protoc
219
236
 
220
237
  ## 6. Advanced Settings & Field Reference
221
238
 
222
- Day-to-day setup and device management are handled entirely by the **Remote Access & Device Pairing Wizard** at the top of the `dsh-zen-remote` page. To fine-tune individual low-level fields, click `dsh-zen-remote` a second time under **Included components** on the plugin detail page.
223
-
224
- <details>
225
- <summary>View underlying component settings screenshots & full field reference table</summary>
226
-
227
- Each field resolves in order: **environment variable > plugin row settings > `~/.dsh/lan-gate.config.json` > default**. Saving a field that requires a gateway/push restart reloads the plugin row automatically without restarting the app.
239
+ Day-to-day setup and device management are handled entirely by the **Remote Access & Device Pairing Wizard** (or `npx dsh-zen-remote setup`). To fine-tune individual low-level fields, click `dsh-zen-remote` a second time under **Included components** on the plugin detail page.
228
240
 
229
241
  | Host Role & Pairing Cards | Shared Sessions List | Client Settings & Diagnostics |
230
242
  | --- | --- | --- |
231
243
  | ![Host role](docs/images/host-settings-role.png) ![Host pairing](docs/images/host-pairing.png) | ![Shared sessions](docs/images/host-settings-shares.png) | ![Client settings](docs/images/client-settings.png) |
232
244
 
245
+ <details>
246
+ <summary>Expand full configuration field reference table & environment variables</summary>
247
+
248
+ Each field resolves in order: **environment variable > plugin row settings > `~/.dsh/lan-gate.config.json` > default**. Saving a field that requires a gateway/push restart reloads the plugin row automatically without restarting the app.
249
+
233
250
  | Field | Default | What it does |
234
251
  | --- | --- | --- |
235
252
  | `role` | `host` | `host` runs gateway + push + sharing; `client` connects to a remote host |
236
- | `serverName` | computer name | **Device name** (≤ 40 chars): sidebar group title on a host, registered device name on a client; syncs both ways automatically |
253
+ | `serverName` | computer name | **Device name** (≤ 40 chars): sidebar group title on a host, registered device name on a client; renaming on a client broadcasts the new name to all its paired servers (one-way — the server never rewrites it) |
237
254
  | `port` | `3088` | Gateway port; retries upward (up to +20) if occupied |
238
255
  | `host` | `127.0.0.1` | Gateway bind address (`127.0.0.1` for local proxy/tunnel, `0.0.0.0` for LAN/Tailscale direct) |
239
256
  | `targetPort` | *(auto)* | Local DSH Web UI port; leave empty to auto-discover the host's listening port |
@@ -241,6 +258,8 @@ Each field resolves in order: **environment variable > plugin row settings > `~/
241
258
  | `trustedProxies` | empty | Comma-separated trusted proxy IPs when the reverse proxy runs on another machine |
242
259
  | `vapidSubject` | `mailto:admin@localhost` | Web Push contact (**must be a real `mailto:` or `https://` URL for iOS delivery**) |
243
260
  | `lang` | `auto` | Gateway & notification language: `auto` (browser `Accept-Language`), `zh`, or `en` |
261
+ | `pushEnabled` | on | Master switch for session notifications; off stops every automatic push and unregisters the `push_notify` tool and its system-prompt hint |
262
+ | `pushSessionName` | off | Open the notification body with `Session: <name>` (the source session's name; the title keeps the fixed event heading) |
244
263
  | `pushTurnEnd` | off | Also send a push when an ordinary turn finishes (approvals/questions always push) |
245
264
  | `pushEvents` | `agent/turn-stopping` | Comma-separated events that count as turn end when `pushTurnEnd` is on |
246
265
  | `pushDebounceMs` | `15000` | Minimum interval (ms) between automatic pushes |
@@ -249,13 +268,13 @@ Each field resolves in order: **environment variable > plugin row settings > `~/
249
268
  | `idleHours` | `48` | Idle-sleep window in hours for shared sessions; range `(0, 8760]` |
250
269
  | `autoShareNewSessions` | off | Automatically enable remote access on new sessions created on the host |
251
270
  | `pluginBridgeConsent` | `{}` | Whole-machine data consent map (`pluginName -> boolean`) for the plugin bridge |
252
- | `serverUrl` *(client)* | empty | Remote server gateway URL (`https://` required for public hosts; `http://` allowed on private LAN/Tailscale ranges) |
253
- | `deviceToken` *(client)* | empty | Paired client token (secret field, redacted everywhere) |
271
+ | `serverUrl` *(client)* | empty | Remote server gateway URL (`https://` required for public hosts; `http://` allowed on private LAN/Tailscale ranges). Legacy single-server field: the paired list now lives in `~/.dsh/zen-remote-state.json` (up to 8 servers) and these row credentials migrate into it automatically on first start |
272
+ | `deviceToken` *(client)* | empty | Paired client token (secret field, redacted everywhere). Legacy single-server field, migrated into `~/.dsh/zen-remote-state.json` like `serverUrl`; new pairings go through the settings card / wizard and never echo the token back to the browser |
254
273
  | `turnFoldDesktop` | off | Enable turn-process folding on desktop widths as well as mobile |
255
274
  | `keyboardLiftRatio` / `keyboardLiftMaxPx` / `keyboardSafetyPadPx` | `0.42` / `400` / `15` | Soft-keyboard lift calibration fallback for environments where the OS hides keyboard height |
256
275
  | `maxUploadBytes` | 20 MB | Mobile attachment upload cap |
257
276
 
258
- Legacy environment variables (outrank row settings): `LAN_GATE_PORT`, `LAN_GATE_HOST`, `LAN_GATE_TARGET_PORT`, `LAN_GATE_RATE_LIMIT`, `LAN_GATE_TRUSTED_PROXIES`, `LAN_GATE_VAPID_SUBJECT`, `LAN_GATE_LANG`, `DSH_PUSH_TURN_END`, `DSH_PUSH_EVENTS`, `DSH_PUSH_DEBOUNCE_MS`, `DSH_PUSH_SUMMARY`, `DSH_PUSH_TOOL`, `DSH_PUSH_LANG`, `DSH_PUSH_APPROVAL_GRACE_MS`.
277
+ Legacy environment variables (outrank row settings): `LAN_GATE_PORT`, `LAN_GATE_HOST`, `LAN_GATE_TARGET_PORT`, `LAN_GATE_RATE_LIMIT`, `LAN_GATE_TRUSTED_PROXIES`, `LAN_GATE_VAPID_SUBJECT`, `LAN_GATE_LANG`, `DSH_PUSH_ENABLED`, `DSH_PUSH_SESSION_NAME`, `DSH_PUSH_TURN_END`, `DSH_PUSH_EVENTS`, `DSH_PUSH_DEBOUNCE_MS`, `DSH_PUSH_SUMMARY`, `DSH_PUSH_TOOL`, `DSH_PUSH_LANG`, `DSH_PUSH_APPROVAL_GRACE_MS`.
259
278
 
260
279
  </details>
261
280
 
@@ -263,23 +282,14 @@ Legacy environment variables (outrank row settings): `LAN_GATE_PORT`, `LAN_GATE_
263
282
 
264
283
  ## 7. Security Model, Version Tolerance & Known Notes
265
284
 
266
- ### Security Model
267
-
268
- - **A paired desktop client is a trusted device**: the remote session terminal runs as the **host's OS user**, file-preview endpoints can read files accessible to the host process, and the client can create sessions in any host workspace.
269
- - **Unshared sessions are strictly isolated at the relay**: list rows, history, live events, approvals/questions, and embedded `dsh-session:` references for unshared sessions are filtered or refused server-side.
270
- - **Public direct-connection guard on `0.0.0.0`**: even when the gateway binds `0.0.0.0` for LAN / Tailscale mode, `isPrivateOrLoopbackIp` only admits direct connections from loopback, RFC1918 LAN ranges, link-local, and Tailscale (`100.64.0.0/10` / `fd7a:115c:a1e0::/48`); any unproxied direct connection from a public internet IP is rejected with `403 public-direct-forbidden`.
271
- - **Admin actions are local-only**: minting pairing codes, changing device roles, running the setup wizard, and revoking devices are only permitted directly on the host machine.
272
- - **Data & privacy**: the plugin reports nothing to any third party. Pairing state lives in `~/.dsh/lan-gate-state.json`, shared sessions in `~/.dsh/zen-remote-shares.json`, and Cloudflare tokens in `0600` files under `~/.dsh/zen-remote-ingress/`.
273
-
274
- ### Version Tolerance
275
-
276
- 1. **Relay protocol version**: both host and client must run the same `dsh-zen-remote` version.
277
- 2. **DSH host version**: DSH versions may differ between host and client. Normalized interface fingerprints are compared during handshake; any differing group is annotated `"(版本有差异)"` and degrades only the affected panel.
278
-
279
- ### Known Limitations & Third-Party Plugin Support
285
+ - **Trusted client & strict session isolation**: a paired desktop client runs terminals and file previews as the host's OS user, while unshared sessions are strictly filtered and refused at the relay layer. Even when binding `0.0.0.0` for LAN/Tailscale, the gateway's private-IP wall rejects any unproxied public internet IP (`403 public-direct-forbidden`), and all admin/wizard mutations are restricted to the host machine itself.
286
+ - **Version tolerance**: both ends must run the same `dsh-zen-remote` version; DSH host versions may differ (interface fingerprints are compared at handshake and degrade only mismatched panels).
280
287
 
281
288
  <details>
282
- <summary>Expand known limitations, iOS PWA notes & adapted third-party plugins</summary>
289
+ <summary>Expand security & state-file details, known limitations, iOS PWA notes & adapted third-party plugins</summary>
290
+
291
+ **Data & state files**
292
+ - The plugin reports nothing to any third party. Pairing state lives in `~/.dsh/lan-gate-state.json`; the unified state file `~/.dsh/zen-remote-state.json` (`0600`) carries the local `serverId`, the shared-session table `sessions`, and the client's paired servers list `servers` (up to 8 servers, tokens included); Cloudflare tokens live in `0600` files under `~/.dsh/zen-remote-ingress/`.
283
293
 
284
294
  **Known limitations**
285
295
  - With multiple DSH windows open simultaneously on a client, active-session detection may occasionally dismiss a closed session early.
@@ -295,7 +305,7 @@ Legacy environment variables (outrank row settings): `LAN_GATE_PORT`, `LAN_GATE_
295
305
 
296
306
  | Plugin | Adaptation summary | Version tested |
297
307
  | --- | --- | --- |
298
- | [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar) | Full-screen mobile right-sidebar drawer with notch safe-area padding and swipe-back; **Plugin Bridge** built-in adapter for `0.25.0` through `0.30.0` (eight versions) (reads/writes host file/Git/task panels in remote sessions with host owner consent) | 0.19.1 / adapter 0.25–0.30.0 |
308
+ | [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar) | Full-screen mobile right-sidebar drawer with notch safe-area padding and swipe-back; **Plugin Bridge** built-in adapter for `0.25.0` through `0.30.1` (nine versions) (reads/writes host file/Git/task panels in remote sessions with host owner consent) | 0.19.1 / adapter 0.25–0.30.1 |
299
309
  | [@nanmicoder/dsh-agent-teams](https://github.com/NanmiCoder/dsh-agent-teams) | Repositions AgentTeams floating pill below session header and preserves parent session back-link | 0.1.9 |
300
310
  | [@ychris12138/dsh-usage-stats](https://github.com/Ychris12138/dsh-usage-stats) | Moves usage & balance entry into the mobile home chips bar | 0.2.9 |
301
311
  | [@opendsh/dsh-plugin-scheduled-tasks](https://github.com/Ceelog/dsh-plugins) | Moves scheduled tasks entry into the mobile home chips bar | 0.2.3 |