dsh-zen-remote 1.1.16 → 2.0.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 (255) hide show
  1. package/AGENTS.md +54 -9
  2. package/README.md +249 -190
  3. package/README.zh-CN.md +247 -201
  4. package/assets/home.png +0 -0
  5. package/assets/info.png +0 -0
  6. package/assets/pairing.png +0 -0
  7. package/assets/session.png +0 -0
  8. package/assets/sheet.png +0 -0
  9. package/cordis.patch.yml +12 -11
  10. package/cordis.patch.yml.example +24 -9
  11. package/docs/interface.md +57 -2
  12. package/docs/remote-access.en.md +99 -58
  13. package/docs/remote-access.md +99 -42
  14. package/dsh-push.mjs +67 -54
  15. package/lan-gate.mjs +88 -20
  16. package/lib/activity.js +168 -0
  17. package/lib/activity.js.map +1 -0
  18. package/lib/admin-routes.js +526 -0
  19. package/lib/admin-routes.js.map +1 -0
  20. package/lib/client-pairing.js +224 -0
  21. package/lib/client-pairing.js.map +1 -0
  22. package/lib/client-routes.js +674 -0
  23. package/lib/client-routes.js.map +1 -0
  24. package/lib/client.js +10051 -4777
  25. package/lib/config.js +346 -0
  26. package/lib/config.js.map +1 -0
  27. package/lib/fetch-route-intercept.js +418 -0
  28. package/lib/fetch-route-intercept.js.map +1 -0
  29. package/lib/fingerprint.js +363 -0
  30. package/lib/fingerprint.js.map +1 -0
  31. package/lib/http.js +69 -0
  32. package/lib/http.js.map +1 -0
  33. package/lib/index.js +675 -54
  34. package/lib/index.js.map +1 -1
  35. package/lib/intercept-shape.js +81 -0
  36. package/lib/intercept-shape.js.map +1 -0
  37. package/lib/intercept.js +3040 -0
  38. package/lib/intercept.js.map +1 -0
  39. package/lib/lan-gate-server.cjs +532 -121
  40. package/lib/merge-streams.js +1165 -0
  41. package/lib/merge-streams.js.map +1 -0
  42. package/lib/relay-access.js +496 -0
  43. package/lib/relay-access.js.map +1 -0
  44. package/lib/relay-client.js +1303 -0
  45. package/lib/relay-client.js.map +1 -0
  46. package/lib/relay-filter.js +282 -0
  47. package/lib/relay-filter.js.map +1 -0
  48. package/lib/relay-server.js +1792 -0
  49. package/lib/relay-server.js.map +1 -0
  50. package/lib/restart-fields.js +34 -0
  51. package/lib/restart-fields.js.map +1 -0
  52. package/lib/restart-watcher.js +106 -0
  53. package/lib/restart-watcher.js.map +1 -0
  54. package/lib/session-reference.js +157 -0
  55. package/lib/session-reference.js.map +1 -0
  56. package/lib/share-export.js +16 -1
  57. package/lib/share-export.js.map +1 -1
  58. package/lib/share-ops.js +86 -0
  59. package/lib/share-ops.js.map +1 -0
  60. package/lib/share-store.js +294 -0
  61. package/lib/share-store.js.map +1 -0
  62. package/lib/types/activity.d.ts +99 -0
  63. package/lib/types/activity.d.ts.map +1 -0
  64. package/lib/types/admin-routes.d.ts +129 -0
  65. package/lib/types/admin-routes.d.ts.map +1 -0
  66. package/lib/types/client/MobileDrawerFooter.d.ts.map +1 -1
  67. package/lib/types/client/MobileHome.d.ts +1 -1
  68. package/lib/types/client/MobileHome.d.ts.map +1 -1
  69. package/lib/types/client/MobileHomeChips.d.ts +1 -1
  70. package/lib/types/client/MobileHomeChips.d.ts.map +1 -1
  71. package/lib/types/client/MobileSessionHeader.d.ts +13 -2
  72. package/lib/types/client/MobileSessionHeader.d.ts.map +1 -1
  73. package/lib/types/client/MobileSessionInfo.d.ts +20 -3
  74. package/lib/types/client/MobileSessionInfo.d.ts.map +1 -1
  75. package/lib/types/client/RemoteComposerBanner.d.ts +42 -0
  76. package/lib/types/client/RemoteComposerBanner.d.ts.map +1 -0
  77. package/lib/types/client/RemoteHeaderIcon.d.ts +37 -0
  78. package/lib/types/client/RemoteHeaderIcon.d.ts.map +1 -0
  79. package/lib/types/client/RemoteShareMenu.d.ts +28 -0
  80. package/lib/types/client/RemoteShareMenu.d.ts.map +1 -0
  81. package/lib/types/client/RemoteStatusIcon.d.ts +36 -0
  82. package/lib/types/client/RemoteStatusIcon.d.ts.map +1 -0
  83. package/lib/types/client/compat/desktop.d.ts +21 -0
  84. package/lib/types/client/compat/desktop.d.ts.map +1 -0
  85. package/lib/types/client/compat/types.d.ts +57 -0
  86. package/lib/types/client/compat/types.d.ts.map +1 -1
  87. package/lib/types/client/current-session-report.d.ts +37 -0
  88. package/lib/types/client/current-session-report.d.ts.map +1 -0
  89. package/lib/types/client/effects/header-status.d.ts.map +1 -1
  90. package/lib/types/client/effects/keyboard-guard.d.ts.map +1 -1
  91. package/lib/types/client/effects/permission-sheet.d.ts +39 -0
  92. package/lib/types/client/effects/permission-sheet.d.ts.map +1 -0
  93. package/lib/types/client/effects/remote-session.d.ts +25 -0
  94. package/lib/types/client/effects/remote-session.d.ts.map +1 -0
  95. package/lib/types/client/effects/turn-fold.d.ts +9 -0
  96. package/lib/types/client/effects/turn-fold.d.ts.map +1 -1
  97. package/lib/types/client/index.d.ts.map +1 -1
  98. package/lib/types/client/locales.d.ts +187 -2
  99. package/lib/types/client/locales.d.ts.map +1 -1
  100. package/lib/types/client/remote-fetch.d.ts +51 -0
  101. package/lib/types/client/remote-fetch.d.ts.map +1 -0
  102. package/lib/types/client/remote-group-expansion.d.ts +41 -0
  103. package/lib/types/client/remote-group-expansion.d.ts.map +1 -0
  104. package/lib/types/client/remote-share-css.d.ts +19 -0
  105. package/lib/types/client/remote-share-css.d.ts.map +1 -0
  106. package/lib/types/client/remote-share-register.d.ts +113 -0
  107. package/lib/types/client/remote-share-register.d.ts.map +1 -0
  108. package/lib/types/client/remote-status-css.d.ts +15 -0
  109. package/lib/types/client/remote-status-css.d.ts.map +1 -0
  110. package/lib/types/client/remote-status-register.d.ts +46 -0
  111. package/lib/types/client/remote-status-register.d.ts.map +1 -0
  112. package/lib/types/client/settings/SettingsSection.d.ts +46 -0
  113. package/lib/types/client/settings/SettingsSection.d.ts.map +1 -0
  114. package/lib/types/client/settings/register-settings.d.ts +58 -0
  115. package/lib/types/client/settings/register-settings.d.ts.map +1 -0
  116. package/lib/types/client/settings/settings-css.d.ts +10 -0
  117. package/lib/types/client/settings/settings-css.d.ts.map +1 -0
  118. package/lib/types/client/share/share-preview.d.ts.map +1 -1
  119. package/lib/types/client/styles/composer.css.d.ts +1 -1
  120. package/lib/types/client/styles/composer.css.d.ts.map +1 -1
  121. package/lib/types/client/styles/header.css.d.ts +1 -1
  122. package/lib/types/client/styles/header.css.d.ts.map +1 -1
  123. package/lib/types/client/styles/info.css.d.ts +1 -1
  124. package/lib/types/client/styles/info.css.d.ts.map +1 -1
  125. package/lib/types/client/styles/remote-session.css.d.ts +2 -0
  126. package/lib/types/client/styles/remote-session.css.d.ts.map +1 -0
  127. package/lib/types/client-data/current-session.d.ts +41 -0
  128. package/lib/types/client-data/current-session.d.ts.map +1 -0
  129. package/lib/types/client-data/remote-group-expansion.d.ts +76 -0
  130. package/lib/types/client-data/remote-group-expansion.d.ts.map +1 -0
  131. package/lib/types/client-data/remote-status.d.ts +148 -0
  132. package/lib/types/client-data/remote-status.d.ts.map +1 -0
  133. package/lib/types/client-data/settings-form.d.ts +774 -0
  134. package/lib/types/client-data/settings-form.d.ts.map +1 -0
  135. package/lib/types/client-data/shares.d.ts +211 -0
  136. package/lib/types/client-data/shares.d.ts.map +1 -0
  137. package/lib/types/client-pairing.d.ts +114 -0
  138. package/lib/types/client-pairing.d.ts.map +1 -0
  139. package/lib/types/client-routes.d.ts +112 -0
  140. package/lib/types/client-routes.d.ts.map +1 -0
  141. package/lib/types/config.d.ts +200 -0
  142. package/lib/types/config.d.ts.map +1 -0
  143. package/lib/types/fetch-route-intercept.d.ts +156 -0
  144. package/lib/types/fetch-route-intercept.d.ts.map +1 -0
  145. package/lib/types/fingerprint.d.ts +164 -0
  146. package/lib/types/fingerprint.d.ts.map +1 -0
  147. package/lib/types/http.d.ts +41 -0
  148. package/lib/types/http.d.ts.map +1 -0
  149. package/lib/types/index.d.ts +56 -24
  150. package/lib/types/index.d.ts.map +1 -1
  151. package/lib/types/intercept-shape.d.ts +32 -0
  152. package/lib/types/intercept-shape.d.ts.map +1 -0
  153. package/lib/types/intercept.d.ts +432 -0
  154. package/lib/types/intercept.d.ts.map +1 -0
  155. package/lib/types/merge-streams.d.ts +393 -0
  156. package/lib/types/merge-streams.d.ts.map +1 -0
  157. package/lib/types/relay-access.d.ts +310 -0
  158. package/lib/types/relay-access.d.ts.map +1 -0
  159. package/lib/types/relay-client.d.ts +274 -0
  160. package/lib/types/relay-client.d.ts.map +1 -0
  161. package/lib/types/relay-filter.d.ts +103 -0
  162. package/lib/types/relay-filter.d.ts.map +1 -0
  163. package/lib/types/relay-server.d.ts +208 -0
  164. package/lib/types/relay-server.d.ts.map +1 -0
  165. package/lib/types/restart-fields.d.ts +22 -0
  166. package/lib/types/restart-fields.d.ts.map +1 -0
  167. package/lib/types/restart-watcher.d.ts +83 -0
  168. package/lib/types/restart-watcher.d.ts.map +1 -0
  169. package/lib/types/session-reference.d.ts +66 -0
  170. package/lib/types/session-reference.d.ts.map +1 -0
  171. package/lib/types/share-export.d.ts +14 -1
  172. package/lib/types/share-export.d.ts.map +1 -1
  173. package/lib/types/share-ops.d.ts +79 -0
  174. package/lib/types/share-ops.d.ts.map +1 -0
  175. package/lib/types/share-store.d.ts +87 -0
  176. package/lib/types/share-store.d.ts.map +1 -0
  177. package/lib/types/virtual-id.d.ts +38 -0
  178. package/lib/types/virtual-id.d.ts.map +1 -0
  179. package/lib/virtual-id.js +52 -0
  180. package/lib/virtual-id.js.map +1 -0
  181. package/llms.txt +17 -14
  182. package/package.json +60 -50
  183. package/scripts/build-client.mjs +5 -3
  184. package/scripts/check-host-shadow.mjs +19 -2
  185. package/scripts/check-settings-form.mjs +933 -0
  186. package/scripts/check-shares.mjs +397 -0
  187. package/scripts/check-upload-endpoint.mjs +59 -3
  188. package/scripts/sync-doc-version.mjs +8 -15
  189. package/scripts/verify-fingerprint-live.mjs +111 -0
  190. package/src/activity.ts +218 -0
  191. package/src/admin-routes.ts +627 -0
  192. package/src/client/MobileAttachButton.tsx +2 -2
  193. package/src/client/MobileAttachChips.tsx +3 -3
  194. package/src/client/MobileDrawerFooter.tsx +7 -4
  195. package/src/client/MobileHome.tsx +20 -16
  196. package/src/client/MobileHomeChips.tsx +16 -16
  197. package/src/client/MobileNavOverlay.tsx +2 -2
  198. package/src/client/MobileNavToggle.tsx +3 -3
  199. package/src/client/MobileSessionHeader.tsx +63 -42
  200. package/src/client/MobileSessionInfo.tsx +118 -17
  201. package/src/client/RemoteComposerBanner.tsx +76 -0
  202. package/src/client/RemoteHeaderIcon.tsx +103 -0
  203. package/src/client/RemoteShareMenu.tsx +57 -0
  204. package/src/client/RemoteStatusIcon.tsx +91 -0
  205. package/src/client/compat/desktop.ts +22 -0
  206. package/src/client/compat/types.ts +62 -0
  207. package/src/client/current-session-report.ts +164 -0
  208. package/src/client/effects/header-status.ts +21 -17
  209. package/src/client/effects/keyboard-guard.ts +65 -1
  210. package/src/client/effects/permission-sheet.ts +149 -0
  211. package/src/client/effects/remote-session.ts +68 -0
  212. package/src/client/effects/turn-fold.ts +52 -0
  213. package/src/client/index.tsx +151 -36
  214. package/src/client/locales.ts +396 -2
  215. package/src/client/remote-fetch.ts +125 -0
  216. package/src/client/remote-group-expansion.ts +190 -0
  217. package/src/client/remote-share-css.ts +54 -0
  218. package/src/client/remote-share-register.ts +244 -0
  219. package/src/client/remote-status-css.ts +64 -0
  220. package/src/client/remote-status-register.ts +107 -0
  221. package/src/client/settings/SettingsSection.tsx +1229 -0
  222. package/src/client/settings/register-settings.ts +116 -0
  223. package/src/client/settings/settings-css.ts +236 -0
  224. package/src/client/share/share-preview.tsx +6 -3
  225. package/src/client/share/share-sheet.tsx +3 -3
  226. package/src/client/styles/composer.css.ts +119 -26
  227. package/src/client/styles/header.css.ts +7 -7
  228. package/src/client/styles/info.css.ts +74 -0
  229. package/src/client/styles/remote-session.css.ts +251 -0
  230. package/src/client-data/current-session.ts +57 -0
  231. package/src/client-data/remote-group-expansion.ts +145 -0
  232. package/src/client-data/remote-status.ts +374 -0
  233. package/src/client-data/settings-form.ts +1371 -0
  234. package/src/client-data/shares.ts +467 -0
  235. package/src/client-pairing.ts +244 -0
  236. package/src/client-routes.ts +732 -0
  237. package/src/config.ts +447 -0
  238. package/src/fetch-route-intercept.ts +510 -0
  239. package/src/fingerprint.ts +408 -0
  240. package/src/http.ts +68 -0
  241. package/src/index.ts +719 -62
  242. package/src/intercept-shape.ts +87 -0
  243. package/src/intercept.ts +3362 -0
  244. package/src/merge-streams.ts +1272 -0
  245. package/src/relay-access.ts +669 -0
  246. package/src/relay-client.ts +1514 -0
  247. package/src/relay-filter.ts +291 -0
  248. package/src/relay-server.ts +2025 -0
  249. package/src/restart-fields.ts +36 -0
  250. package/src/restart-watcher.ts +140 -0
  251. package/src/session-reference.ts +156 -0
  252. package/src/share-export.ts +26 -1
  253. package/src/share-ops.ts +114 -0
  254. package/src/share-store.ts +373 -0
  255. package/src/virtual-id.ts +59 -0
@@ -1,4 +1,5 @@
1
- import type { ClientContext, SessionId, WorkspaceId } from './compat/types.ts'
1
+ import type { ClientContext, JobsLike, SessionId, WorkspaceId } from './compat/types.ts'
2
+ import { isDesktopShell } from './compat/desktop.ts'
2
3
  import { MobileNavToggle } from './MobileNavToggle.tsx'
3
4
  import { MobileNavOverlay } from './MobileNavOverlay.tsx'
4
5
  import { MobileDrawerFooter } from './MobileDrawerFooter.tsx'
@@ -18,13 +19,27 @@ import { installGestures } from './effects/gestures.ts'
18
19
  import { installTurnFold } from './effects/turn-fold.ts'
19
20
  import { installModalBack } from './effects/modal-back.ts'
20
21
  import { installModelSheetExtras } from './effects/model-sheet-extras.ts'
22
+ import { installPermissionSheet } from './effects/permission-sheet.ts'
21
23
  import { installNativeTriggerOverlay } from './effects/native-trigger-overlay.ts'
22
24
  import { installWelcomeNoticeOptOut } from './effects/welcome-notice.ts'
23
25
  import { installKeyboardGuard } from './effects/keyboard-guard.ts'
24
26
  import { installKeyboardAvoid } from './effects/keyboard-avoid.ts'
25
27
  import { SharePreview } from './share/share-preview.tsx'
26
- import { NS, en, zh } from './locales.ts'
28
+ import { NS } from './locales.ts'
27
29
  import type { MobileNavKey } from './locales.ts'
30
+ import { SettingsSection } from './settings/SettingsSection.tsx'
31
+ import { registerSettingsPage } from './settings/register-settings.ts'
32
+ import { RemoteHeaderIcon } from './RemoteHeaderIcon.tsx'
33
+ import { RemoteShareMenuItem } from './RemoteShareMenu.tsx'
34
+ import { getSharesStore } from '../client-data/shares.ts'
35
+ import { registerRemoteShareUi } from './remote-share-register.ts'
36
+ import { RemoteStatusIcon } from './RemoteStatusIcon.tsx'
37
+ import { RemoteComposerBanner } from './RemoteComposerBanner.tsx'
38
+ import { registerRemoteStatusUi } from './remote-status-register.ts'
39
+ import { mountCurrentSessionReporter } from './current-session-report.ts'
40
+ import { mountRemoteGroupExpansionKeeper } from './remote-group-expansion.ts'
41
+ import { installRemoteApiFetch } from './remote-fetch.ts'
42
+ import { installRemoteSessionGuard } from './effects/remote-session.ts'
28
43
 
29
44
  declare module '@deepseek-ai/dsh-client-ui-slots' {
30
45
  interface LocaleNamespaceMap {
@@ -37,20 +52,50 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
37
52
  export const inject = ['slots', 'layout', 'locale', 'sessionLogDownload', 'sessions', 'workspaces']
38
53
 
39
54
  /**
40
- * 0.1.2 把新建会话和归档会话的界面级操作挪到了 uiWorkspace 服务;
41
- * 0.1.1 没有这个服务,那两个操作还在 ctx.workspaces 上。这里按存在探测,
42
- * 不把 uiWorkspace 写进 inject(写了 0.1.1 就永远不激活)。
43
- * 类型用本地最小接口,不 import 那个 dsh-client-ui-workspace 包
44
- * ——0.1.1 装不到。
55
+ * 0.1.2 把新建会话、归档会话与打开会话的界面级操作挪到了 uiWorkspace
56
+ * 服务(0.1.7 删掉了 ctx.sessions.open,这是它唯一的替代入口)。类型用
57
+ * 本地最小接口,不 import 那个 dsh-client-ui-workspace 包——本插件的
58
+ * peerDependencies 不含它,运行时实例由宿主提供,类型自己声明就够。
45
59
  */
46
60
  interface UiWorkspaceLike {
61
+ openSession(target: SessionId): void
47
62
  startSession(workspaceId?: WorkspaceId): void
48
63
  archiveSession(sessionId: SessionId): Promise<void>
49
64
  }
50
65
 
51
- /** 0.1.1 的 ctx.workspaces 上还有 startSession;0.1.2 的类型里没有了。 */
52
- interface LegacyWorkspacesLike {
53
- startSession(workspaceId?: WorkspaceId): void
66
+ /**
67
+ * Activity data both session-header entries read (0.1.7 sources — 0.1.5's
68
+ * per-parent subagent snapshot and per-session job snapshot are gone):
69
+ * - the subagent catalog is read straight off the sessions snapshot's
70
+ * explicit-read store (`projectionsBySession[id].values.subagentCatalog`),
71
+ * exactly like the official SubagentHeaderLineage — no refresh is issued
72
+ * from here: every projection refresh call registers another session in
73
+ * the controller's load table, and all of them are re-read on every
74
+ * reconnect (manager handleConnected), so per-open refreshes would grow
75
+ * into a batch of re-reads forever;
76
+ * - job rows come from the `jobs` client service; the inject face mirrors
77
+ * the official JobListAction registration (`hooks.jobs` observable → the
78
+ * renderer hands the component a `useJobs` hook prop). When the service is
79
+ * absent (a build without the job controller) a fixed empty source keeps
80
+ * the prop present, so the component's hook count never varies — the
81
+ * counts simply read zero instead of the pill silently disappearing.
82
+ */
83
+ const NO_JOBS_SNAPSHOT = Object.freeze({ rows: Object.freeze({}) }) as {
84
+ readonly rows: Readonly<Record<string, readonly never[]>>
85
+ }
86
+ /** Module-level singleton: one stable observable identity across renders. */
87
+ const NO_JOBS_SOURCE = {
88
+ getSnapshot: () => NO_JOBS_SNAPSHOT,
89
+ subscribe: (): (() => void) => () => {},
90
+ }
91
+ const NO_WATCH_ROWS = (): (() => void) => () => {}
92
+
93
+ function activityInject(ctx: ClientContext) {
94
+ const jobs = ctx.get('jobs') as JobsLike | undefined
95
+ return {
96
+ hooks: { jobs: jobs === undefined ? NO_JOBS_SOURCE : jobs.state },
97
+ watchRows: jobs === undefined ? NO_WATCH_ROWS : (id: SessionId) => jobs.watchRows(id),
98
+ }
54
99
  }
55
100
 
56
101
  /**
@@ -60,7 +105,58 @@ interface LegacyWorkspacesLike {
60
105
  * @param ctx - client root context.
61
106
  */
62
107
  export function apply(ctx: ClientContext): void {
63
- ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-mobile-nav: dictionaries')
108
+ // 2.0.0 设置页:必须在桌面门之前注册——桌面端 App 里手机外壳整体不生效,
109
+ // 但设置页必须生效(主服务端就是桌面端)。字典、设置页样式与设置表单服务
110
+ // 的按需注入都在 registerSettingsPage 里(那个服务名绝不进顶层的 inject
111
+ // 数组,否则没有该服务的环境整个界面半边都加载不了)。
112
+ registerSettingsPage(ctx, SettingsSection)
113
+
114
+ // T33b 会话共享的三个入口里前两个(标题行远程图标、会话右键菜单项):
115
+ // 同样必须在桌面门之前注册——桌面端 App 就是主服务端,图标和菜单恰好
116
+ // 住在它的标题行与会话菜单里。部件自身按数据降级:shares 路由 404
117
+ // (子客户端部署没有这条路由)时渲染为空;手机外壳下样式表把
118
+ // header.actions 全量隐藏(styles/header.css.ts),图标也就不订阅
119
+ // (subscribeIfNotPhoneShell)——订阅是轮询的燃料,不订阅就不发
120
+ // admin/shares 请求。设置页的共享列表在 SettingsSection 内部,随设置
121
+ // 页已在门之前。
122
+ registerRemoteShareUi(ctx, RemoteHeaderIcon, RemoteShareMenuItem)
123
+
124
+ // T34 子客户端的远程状态两件套(标题行连接图标、composer 横幅):同样在
125
+ // 桌面门之前注册——桌面端 App 也能以 client 角色接入服务端。部件自身按
126
+ // 数据降级:只在虚拟 id 会话渲染、首次 GET 应答前不渲染,所以主服务端
127
+ // 的页面上两者都是空,桌面保持逐像素 no-op;订阅本身也按虚拟 id 门控
128
+ // (remote-status.ts 的 subscribeIfVirtual)——本地会话不建立订阅,
129
+ // store 只在有订阅者时才轮询,主服务端的页面不白发 remote-status 请求。
130
+ registerRemoteStatusUi(ctx, RemoteStatusIcon, RemoteComposerBanner)
131
+ // T62 当前会话信号的上报:拦截层跑在后台 Node 进程里,读不到浏览器的
132
+ // localStorage——由这里(唯一读得到宿主选择存储的地方)把「当前打开的
133
+ // 会话」在值变化时 POST 给后台路由。同样在桌面门之前挂载:client 角色
134
+ // 的桌面端 App 正是远程会话所在;只在探测出的子客户端角色下运行,主
135
+ // 服务端的页面探测一次后就静默。
136
+ mountCurrentSessionReporter(ctx)
137
+ // T64 服务端分组展开状态的记忆与恢复:宿主在工作区列表 ready 时会把不在
138
+ // 列表里的分组展开记录清掉(retainAccountKeys),而本地工作区先 ready、
139
+ // 服务端分组后并入,zr~ 键每次加载都被清掉、分组回到折叠。与上报器共用
140
+ // 挂载点与角色判断(同一个 client-config 探测)、同样的 1 秒节拍(自己的
141
+ // 定时器),逻辑在 remote-group-expansion.ts 自己的文件里。
142
+ mountRemoteGroupExpansionKeeper(ctx)
143
+ // T41b 的两个远程会话部件:fetch 改写(改动 / diff 面板的两条 /api GET)与
144
+ // 远程会话标记(data-zr-remote-session + 隐藏「在服务端机器上打开」类入口
145
+ // 的样式)。同样必须在桌面门之前注册——桌面窗口也可以是配对好的子客户端,
146
+ // 改写与隐藏在它里面一样必要。改写只碰「同源 + 精确两条路径 + zr~ 虚拟
147
+ // 会话 id」的 GET(remote-fetch.ts),宿主角色的桌面端(会话 id 永非虚拟)
148
+ // 逐字节原样放行;标记属性只在虚拟会话打开时出现,卸载时还原。
149
+ ctx.effect(() => installRemoteApiFetch(window), 'dsh-zen-remote: remote api fetch')
150
+ installRemoteSessionGuard(ctx)
151
+
152
+ // Desktop gate (DSH 0.1.7): the official Electron shell can be dragged
153
+ // down to ~520px wide, where every width-based gate would flip the phone
154
+ // shell on inside the desktop app. Inside that shell this plugin is a
155
+ // complete no-op — no stylesheet, no effects, no slot entries, which is
156
+ // bit-for-bit "not installed" and also retires the desktop-fold knobs
157
+ // there (they exist for narrow desktop *browsers*, which never carry the
158
+ // dshDesktop bridge). See compat/desktop.ts for the marker's provenance.
159
+ if (isDesktopShell()) return
64
160
 
65
161
  ctx.effect(() => {
66
162
  const tag = document.createElement('style')
@@ -111,6 +207,9 @@ export function apply(ctx: ClientContext): void {
111
207
  // Third-party composer entries (speed chip, vision toggle) move into the
112
208
  // model sheet — the row has no width to spare and both are model settings.
113
209
  installModelSheetExtras(ctx)
210
+ // T70: the permission menu portals to body on DSH 0.2.0 — mark it so
211
+ // composer.css section 4 can still make it the bottom sheet.
212
+ installPermissionSheet(ctx)
114
213
 
115
214
  // "内测声明" first-run notice: keep it visible (CSS-hiding it leaked the
116
215
  // dialog's #root inert lock — see effects/welcome-notice.ts) and offer a
@@ -156,6 +255,8 @@ export function apply(ctx: ClientContext): void {
156
255
  id: 'mobile-header-actions',
157
256
  order: 0,
158
257
  locale: NS,
258
+ // Activity-pill data (subagent catalog + job roster), see activityInject.
259
+ inject: () => activityInject(ctx),
159
260
  }, MobileHeaderActions))
160
261
 
161
262
  // Session-info entry (placeholder — S4 owns the sheet) + workbench entry
@@ -180,14 +281,29 @@ export function apply(ctx: ClientContext): void {
180
281
  locale: NS,
181
282
  // The factory's own sessionId param is unused: every function below
182
283
  // takes its own session id explicitly (they're generic action bindings
183
- // reused verbatim, not closures over one particular session).
284
+ // reused verbatim, not closures over one particular session). The
285
+ // spread adds the activity-pill data (subagent catalog + job roster for
286
+ // the info-sheet badges), see activityInject.
184
287
  inject: (_sessionId: SessionId) => ({
288
+ ...activityInject(ctx),
289
+ // T67: the SAME page-wide shares store the header icon and the menu
290
+ // item read — the row subscribes only while the sheet is open, so no
291
+ // second poll loop and no phone-shell polling either.
292
+ shares: getSharesStore(),
185
293
  forkSession: (id: SessionId) => ctx.sessions.fork({ sessionId: id }),
186
- openSession: (id: SessionId) => ctx.sessions.open(id),
294
+ // 0.1.7: ctx.sessions.open is gone; uiWorkspace.openSession is the one
295
+ // navigation entry (also what the official subagent catalog uses).
296
+ // Lazy lookup like every other uiWorkspace binding here: the callback
297
+ // runs on a user tap, by which time the service is registered.
298
+ openSession: (id: SessionId) => {
299
+ const ui = ctx.get('uiWorkspace') as UiWorkspaceLike | undefined
300
+ if (ui === undefined) console.warn('[dsh-zen-remote] uiWorkspace service unavailable; cannot open session', id)
301
+ else ui.openSession(id)
302
+ },
187
303
  renameSession: (id: SessionId, title: string) => ctx.sessions.binding(id)?.session.rename(title),
188
304
  // 0.1.2 的界面级归档在 uiWorkspace(顺带清当前选中);懒查——回调是用户
189
- // 点击才跑,那时服务必已注册。本插件的 inject 不包含 uiWorkspace(0.1.1
190
- // 没有它),所以启动时不能查一次就用:可能早于它注册。
305
+ // 点击才跑,那时服务必已注册。本插件的 inject 不包含 uiWorkspace,
306
+ // 所以启动时不能查一次就用:可能早于它注册。
191
307
  archiveSession: (id: SessionId) => {
192
308
  const ui = ctx.get('uiWorkspace') as UiWorkspaceLike | undefined
193
309
  return ui === undefined ? ctx.workspaces.archiveSession(id) : ui.archiveSession(id)
@@ -242,16 +358,18 @@ export function apply(ctx: ClientContext): void {
242
358
  locale: NS,
243
359
  store: nav,
244
360
  inject: () => ({
245
- openSession: (id: SessionId) => ctx.sessions.open(id),
361
+ // Same uiWorkspace.openSession binding as the session-info sheet above.
362
+ openSession: (id: SessionId) => {
363
+ const ui = ctx.get('uiWorkspace') as UiWorkspaceLike | undefined
364
+ if (ui === undefined) console.warn('[dsh-zen-remote] uiWorkspace service unavailable; cannot open session', id)
365
+ else ui.openSession(id)
366
+ },
246
367
  // uiWorkspace 懒查:回调是用户点击才跑,服务那时必已注册(inject 不含
247
- // uiWorkspace,启动时可能先于它注册,不能启动查一次就用)。0.1.1 上恒
248
- // undefined,退回 ctx.workspaces.startSession——0.1.1 专用分支,0.1.2 的
249
- // 类型里该方法已不存在,故对类型做 LegacyWorkspacesLike cast,运行时走不到。
368
+ // uiWorkspace,启动时可能先于它注册,不能启动查一次就用)。
250
369
  startSession: (workspaceId?: WorkspaceId) => {
251
370
  const ui = ctx.get('uiWorkspace') as UiWorkspaceLike | undefined
252
- return ui === undefined
253
- ? (ctx.workspaces as unknown as LegacyWorkspacesLike).startSession(workspaceId)
254
- : ui.startSession(workspaceId)
371
+ if (ui === undefined) console.warn('[dsh-zen-remote] uiWorkspace service unavailable; cannot start a session')
372
+ else ui.startSession(workspaceId)
255
373
  },
256
374
  // S5 session-log chip — the same service call MobileDrawerFooter uses.
257
375
  downloadSessionLog: (id: SessionId) => ctx.sessionLogDownload.download(id),
@@ -315,22 +433,19 @@ import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
315
433
  import type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'
316
434
  import type {} from '@deepseek-ai/dsh-client-locale/client'
317
435
  import type {} from '@deepseek-ai/dsh-session-log-export/client'
318
- // 0.1.2-only package: augments GlobalStandardProps with
319
- // useSessions/useSessionPendingInteraction and SessionStandardProps with
320
- // sessionId/useSession/useProjection, and declares the `ctx.uiSession`
321
- // service. 0.1.1 has no such package — but this is `import type`, so the
322
- // build output carries no trace of it and the runtime is unaffected.
436
+ // ui-session: augments GlobalStandardProps with useSessions /
437
+ // useSessionPendingInteraction / useSessionStatus and SessionStandardProps
438
+ // with sessionId/useSession/useProjection, and declares the `ctx.uiSession`
439
+ // service.
323
440
  import type {} from '@deepseek-ai/dsh-client-ui-session/client'
324
- // 0.1.2-only controller packages: their `/client` type entries merge
325
- // `ctx.sessions` / `ctx.workspaces` onto the cordis Context (0.1.1 declared
326
- // both from dsh-client-runtime). Type-only again — nothing to load at
327
- // runtime, so a 0.1.1 installation is unaffected.
441
+ // Controller packages: their `/client` type entries merge `ctx.sessions` /
442
+ // `ctx.workspaces` onto the cordis Context. Type-only — nothing to load at
443
+ // runtime.
328
444
  import type {} from '@deepseek-ai/dsh-api-session-controller/client'
329
445
  import type {} from '@deepseek-ai/dsh-api-workspace-controller/client'
330
- // 0.1.2-only, type-only: the renderer declares `ctx.slots` on the cordis
331
- // Context (the service this plugin registers every slot through) and
332
- // `dsh-subagent/client` types the subagent catalog rows the session header
333
- // reads (SessionListState.subagentsByParent). 0.1.1 had both declared in the
334
- // dsh-client-runtime bundle that no longer exists.
446
+ // Type-only: the renderer declares `ctx.slots` on the cordis Context (the
447
+ // service this plugin registers every slot through) and `dsh-subagent/client`
448
+ // types the subagent catalog projection entries the session header reads
449
+ // (projectionsBySession[].values.subagentCatalog on 0.1.7).
335
450
  import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
336
451
  import type {} from '@deepseek-ai/dsh-subagent/client'