dsh-over-ssh 0.1.0 → 0.1.1

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 (247) hide show
  1. package/README.md +10 -10
  2. package/agents/agent-manifest.json +1 -1
  3. package/lib/client.js +363 -314
  4. package/lib/file-references.js +80 -35
  5. package/lib/fs.js +158 -75
  6. package/lib/index.js +4103 -3397
  7. package/lib/terminal-wrapper.js +9 -4
  8. package/lib/types/src/config.d.ts +80 -9
  9. package/lib/types/src/file-references.d.ts +0 -1
  10. package/lib/types/src/host/app/backend.d.ts +9 -1
  11. package/lib/types/src/host/app/recycle-bin/recycle-bin-contract.d.ts +0 -1
  12. package/lib/types/src/host/app/recycle-bin/recycle-bin-service.d.ts +0 -1
  13. package/lib/types/src/host/app/session-admin/session-admin-contract.d.ts +12 -1
  14. package/lib/types/src/host/app/session-admin/session-admin-service.d.ts +0 -1
  15. package/lib/types/src/host/app/transport/transport-selector.d.ts +0 -1
  16. package/lib/types/src/host/app/transport/transport-service.d.ts +0 -1
  17. package/lib/types/src/host/domain/capability.d.ts +0 -1
  18. package/lib/types/src/host/domain/errors.d.ts +0 -1
  19. package/lib/types/src/host/domain/roots/connection.d.ts +0 -1
  20. package/lib/types/src/host/domain/roots/root.d.ts +24 -9
  21. package/lib/types/src/host/domain/roots/session-roots.d.ts +0 -1
  22. package/lib/types/src/host/domain/roots/ssh-config.d.ts +0 -1
  23. package/lib/types/src/host/domain/session/session-admin.d.ts +0 -1
  24. package/lib/types/src/host/domain/transfer/recycle-bin.d.ts +0 -1
  25. package/lib/types/src/host/domain/transfer/transfer.d.ts +0 -1
  26. package/lib/types/src/host/infra/transport/agent/agent-installer.d.ts +0 -1
  27. package/lib/types/src/host/infra/transport/ssh/ssh2-transport.d.ts +0 -1
  28. package/lib/types/src/host/infra/transport/transport-base.d.ts +0 -1
  29. package/lib/types/src/host/infra/transport/transport.d.ts +16 -2
  30. package/lib/types/src/host/integration/agent/agent-preflight.d.ts +0 -1
  31. package/lib/types/src/host/integration/fs/file-reference-provider.d.ts +0 -1
  32. package/lib/types/src/host/integration/fs/fs-provider.d.ts +0 -2
  33. package/lib/types/src/host/integration/transfer/transfer-service.d.ts +0 -1
  34. package/lib/types/src/index.d.ts +23 -1
  35. package/lib/types/src/local-bridge-refs.d.ts +0 -1
  36. package/lib/types/src/local-bridge.d.ts +0 -1
  37. package/lib/types/src/shared/root-keys.d.ts +120 -0
  38. package/lib/types/src/wiring/helpers.d.ts +0 -1
  39. package/package.json +5 -3
  40. package/lib/types/src/client/controls.d.ts +0 -131
  41. package/lib/types/src/client/core/card-focus-trap.d.ts +0 -45
  42. package/lib/types/src/client/core/controls.d.ts +0 -164
  43. package/lib/types/src/client/core/latest.d.ts +0 -48
  44. package/lib/types/src/client/core/locale.d.ts +0 -38
  45. package/lib/types/src/client/core/message.d.ts +0 -37
  46. package/lib/types/src/client/core/panel-model.d.ts +0 -134
  47. package/lib/types/src/client/core/portal.d.ts +0 -266
  48. package/lib/types/src/client/core/remote.d.ts +0 -84
  49. package/lib/types/src/client/core/styles.d.ts +0 -458
  50. package/lib/types/src/client/file-tree-io.d.ts +0 -19
  51. package/lib/types/src/client/file-tree.d.ts +0 -271
  52. package/lib/types/src/client/flows/directory-browser.d.ts +0 -587
  53. package/lib/types/src/client/flows/session-directory.d.ts +0 -415
  54. package/lib/types/src/client/flows/workspace-directory-flow.d.ts +0 -480
  55. package/lib/types/src/client/locale.d.ts +0 -31
  56. package/lib/types/src/client/panel-model.d.ts +0 -37
  57. package/lib/types/src/client/panel.d.ts +0 -77
  58. package/lib/types/src/client/roots/connection-test.d.ts +0 -69
  59. package/lib/types/src/client/roots/roots-panel-state.d.ts +0 -307
  60. package/lib/types/src/client/roots/roots-panel-view.d.ts +0 -280
  61. package/lib/types/src/client/roots/roots-panel.d.ts +0 -364
  62. package/lib/types/src/client/roots/transfer-panel-view.d.ts +0 -35
  63. package/lib/types/src/client/roots/transfer-panel.d.ts +0 -241
  64. package/lib/types/src/client/roots/transfer-progress.d.ts +0 -67
  65. package/lib/types/src/client/roots-panel-view.d.ts +0 -236
  66. package/lib/types/src/client/roots-panel.d.ts +0 -347
  67. package/lib/types/src/client/session/session-panel-view.d.ts +0 -336
  68. package/lib/types/src/client/session/session-panel.d.ts +0 -322
  69. package/lib/types/src/client/session/session-remote-mark.d.ts +0 -110
  70. package/lib/types/src/client/session/session-row-actions.d.ts +0 -398
  71. package/lib/types/src/client/session-panel.d.ts +0 -152
  72. package/lib/types/src/client/styles.d.ts +0 -252
  73. package/lib/types/src/client/workspace-directory-flow.d.ts +0 -342
  74. package/lib/types/src/fs.d.ts +0 -46
  75. package/lib/types/src/host/app/recycle-bin/recycle-bin-move.d.ts +0 -18
  76. package/lib/types/src/host/app/recycle-bin/recycle-bin-world.d.ts +0 -38
  77. package/lib/types/src/host/app/recycle-bin-contract.d.ts +0 -215
  78. package/lib/types/src/host/app/recycle-bin-move.d.ts +0 -18
  79. package/lib/types/src/host/app/recycle-bin-service.d.ts +0 -45
  80. package/lib/types/src/host/app/recycle-bin-world.d.ts +0 -35
  81. package/lib/types/src/host/app/roots/roots-api-connections.d.ts +0 -49
  82. package/lib/types/src/host/app/roots/roots-api-contract.d.ts +0 -369
  83. package/lib/types/src/host/app/roots/roots-api-directories.d.ts +0 -13
  84. package/lib/types/src/host/app/roots/roots-api-http.d.ts +0 -77
  85. package/lib/types/src/host/app/roots/roots-api-long-poll.d.ts +0 -130
  86. package/lib/types/src/host/app/roots/roots-api-projections.d.ts +0 -102
  87. package/lib/types/src/host/app/roots/roots-api-roots.d.ts +0 -13
  88. package/lib/types/src/host/app/roots/roots-api-state.d.ts +0 -22
  89. package/lib/types/src/host/app/roots/roots-api-transfers.d.ts +0 -26
  90. package/lib/types/src/host/app/roots/roots-api.d.ts +0 -55
  91. package/lib/types/src/host/app/roots/user-roots.d.ts +0 -552
  92. package/lib/types/src/host/app/roots-api-connections.d.ts +0 -49
  93. package/lib/types/src/host/app/roots-api-contract.d.ts +0 -339
  94. package/lib/types/src/host/app/roots-api-directories.d.ts +0 -13
  95. package/lib/types/src/host/app/roots-api-http.d.ts +0 -77
  96. package/lib/types/src/host/app/roots-api-projections.d.ts +0 -102
  97. package/lib/types/src/host/app/roots-api-roots.d.ts +0 -13
  98. package/lib/types/src/host/app/roots-api-state.d.ts +0 -22
  99. package/lib/types/src/host/app/roots-api-support.d.ts +0 -182
  100. package/lib/types/src/host/app/roots-api-transfers.d.ts +0 -13
  101. package/lib/types/src/host/app/roots-api.d.ts +0 -55
  102. package/lib/types/src/host/app/routed-fs.d.ts +0 -239
  103. package/lib/types/src/host/app/serialize.d.ts +0 -37
  104. package/lib/types/src/host/app/session-admin/session-admin-context.d.ts +0 -36
  105. package/lib/types/src/host/app/session-admin/session-admin-delete.d.ts +0 -34
  106. package/lib/types/src/host/app/session-admin-context.d.ts +0 -36
  107. package/lib/types/src/host/app/session-admin-contract.d.ts +0 -214
  108. package/lib/types/src/host/app/session-admin-delete.d.ts +0 -34
  109. package/lib/types/src/host/app/session-admin-service.d.ts +0 -38
  110. package/lib/types/src/host/app/takeover/takeover-plan.d.ts +0 -227
  111. package/lib/types/src/host/app/takeover/takeover-rows.d.ts +0 -55
  112. package/lib/types/src/host/app/transport-selector.d.ts +0 -98
  113. package/lib/types/src/host/app/transport-service.d.ts +0 -75
  114. package/lib/types/src/host/app/user-roots.d.ts +0 -461
  115. package/lib/types/src/host/domain/bin-location.d.ts +0 -79
  116. package/lib/types/src/host/domain/connection.d.ts +0 -95
  117. package/lib/types/src/host/domain/glob-pattern.d.ts +0 -62
  118. package/lib/types/src/host/domain/literal-text.d.ts +0 -63
  119. package/lib/types/src/host/domain/path-grammar.d.ts +0 -84
  120. package/lib/types/src/host/domain/recycle-bin.d.ts +0 -337
  121. package/lib/types/src/host/domain/root.d.ts +0 -74
  122. package/lib/types/src/host/domain/roots/bin-location.d.ts +0 -91
  123. package/lib/types/src/host/domain/roots/route-table.d.ts +0 -102
  124. package/lib/types/src/host/domain/route-table.d.ts +0 -80
  125. package/lib/types/src/host/domain/session/terminal-target.d.ts +0 -136
  126. package/lib/types/src/host/domain/session-admin.d.ts +0 -330
  127. package/lib/types/src/host/domain/shell.d.ts +0 -47
  128. package/lib/types/src/host/domain/ssh-config.d.ts +0 -73
  129. package/lib/types/src/host/domain/terminal-target.d.ts +0 -132
  130. package/lib/types/src/host/domain/tool-requests.d.ts +0 -369
  131. package/lib/types/src/host/domain/transfer.d.ts +0 -260
  132. package/lib/types/src/host/infra/backend/local-backend.d.ts +0 -84
  133. package/lib/types/src/host/infra/backend/local-version.d.ts +0 -43
  134. package/lib/types/src/host/infra/backend/platform-local-backend.d.ts +0 -89
  135. package/lib/types/src/host/infra/backend/remote-backend.d.ts +0 -239
  136. package/lib/types/src/host/infra/cache/lru.d.ts +0 -52
  137. package/lib/types/src/host/infra/cache/versioned.d.ts +0 -77
  138. package/lib/types/src/host/infra/temp-name.d.ts +0 -19
  139. package/lib/types/src/host/infra/transport/agent/agent-protocol-client.d.ts +0 -132
  140. package/lib/types/src/host/infra/transport/agent/agent-protocol-codec.d.ts +0 -140
  141. package/lib/types/src/host/infra/transport/agent/agent-protocol-errors.d.ts +0 -41
  142. package/lib/types/src/host/infra/transport/agent/agent-protocol-frames.d.ts +0 -197
  143. package/lib/types/src/host/infra/transport/agent/agent-protocol-types.d.ts +0 -564
  144. package/lib/types/src/host/infra/transport/agent/agent-transport.d.ts +0 -418
  145. package/lib/types/src/host/infra/transport/agent-installer.d.ts +0 -121
  146. package/lib/types/src/host/infra/transport/agent-protocol-client.d.ts +0 -123
  147. package/lib/types/src/host/infra/transport/agent-protocol-codec.d.ts +0 -131
  148. package/lib/types/src/host/infra/transport/agent-protocol-errors.d.ts +0 -41
  149. package/lib/types/src/host/infra/transport/agent-protocol-frames.d.ts +0 -197
  150. package/lib/types/src/host/infra/transport/agent-protocol-types.d.ts +0 -509
  151. package/lib/types/src/host/infra/transport/agent-transport.d.ts +0 -353
  152. package/lib/types/src/host/infra/transport/alias-transport.d.ts +0 -206
  153. package/lib/types/src/host/infra/transport/askpass-fs.d.ts +0 -20
  154. package/lib/types/src/host/infra/transport/askpass.d.ts +0 -133
  155. package/lib/types/src/host/infra/transport/command-pool.d.ts +0 -61
  156. package/lib/types/src/host/infra/transport/fs-commands.d.ts +0 -140
  157. package/lib/types/src/host/infra/transport/git-status-route.d.ts +0 -63
  158. package/lib/types/src/host/infra/transport/git-status.d.ts +0 -101
  159. package/lib/types/src/host/infra/transport/node-spawn.d.ts +0 -26
  160. package/lib/types/src/host/infra/transport/session-window.d.ts +0 -51
  161. package/lib/types/src/host/infra/transport/shell-quote.d.ts +0 -59
  162. package/lib/types/src/host/infra/transport/ssh/alias-transport.d.ts +0 -206
  163. package/lib/types/src/host/infra/transport/ssh/askpass-fs.d.ts +0 -20
  164. package/lib/types/src/host/infra/transport/ssh/askpass.d.ts +0 -133
  165. package/lib/types/src/host/infra/transport/ssh/shell-quote.d.ts +0 -62
  166. package/lib/types/src/host/infra/transport/ssh/ssh-argv.d.ts +0 -43
  167. package/lib/types/src/host/infra/transport/ssh-argv.d.ts +0 -43
  168. package/lib/types/src/host/infra/transport/ssh2-transport.d.ts +0 -302
  169. package/lib/types/src/host/integration/agent/agent-install-io.d.ts +0 -33
  170. package/lib/types/src/host/integration/agent/askpass-registry.d.ts +0 -66
  171. package/lib/types/src/host/integration/agent-install-io.d.ts +0 -33
  172. package/lib/types/src/host/integration/agent-preflight.d.ts +0 -56
  173. package/lib/types/src/host/integration/anchor-directory.d.ts +0 -56
  174. package/lib/types/src/host/integration/askpass-registry.d.ts +0 -59
  175. package/lib/types/src/host/integration/bin-root-resolver.d.ts +0 -81
  176. package/lib/types/src/host/integration/connection-test.d.ts +0 -73
  177. package/lib/types/src/host/integration/file-reference-provider.d.ts +0 -115
  178. package/lib/types/src/host/integration/fs/git-status-wiring.d.ts +0 -21
  179. package/lib/types/src/host/integration/fs/platform-errors.d.ts +0 -94
  180. package/lib/types/src/host/integration/fs/remote-file-tools.d.ts +0 -369
  181. package/lib/types/src/host/integration/fs/remote-index.d.ts +0 -177
  182. package/lib/types/src/host/integration/fs-provider.d.ts +0 -226
  183. package/lib/types/src/host/integration/lsp/lsp-framing.d.ts +0 -38
  184. package/lib/types/src/host/integration/lsp/lsp-registry.d.ts +0 -67
  185. package/lib/types/src/host/integration/lsp/lsp-session.d.ts +0 -130
  186. package/lib/types/src/host/integration/management-tools.d.ts +0 -64
  187. package/lib/types/src/host/integration/recycle-bin-service.d.ts +0 -247
  188. package/lib/types/src/host/integration/remote/connection-test.d.ts +0 -73
  189. package/lib/types/src/host/integration/remote/remote-face.d.ts +0 -127
  190. package/lib/types/src/host/integration/remote/remote-tool-backend.d.ts +0 -108
  191. package/lib/types/src/host/integration/remote-face.d.ts +0 -127
  192. package/lib/types/src/host/integration/remote-file-tools.d.ts +0 -241
  193. package/lib/types/src/host/integration/remote-home.d.ts +0 -69
  194. package/lib/types/src/host/integration/remote-index.d.ts +0 -165
  195. package/lib/types/src/host/integration/remote-job-tools.d.ts +0 -295
  196. package/lib/types/src/host/integration/remote-tool-backend.d.ts +0 -97
  197. package/lib/types/src/host/integration/remote-tools.d.ts +0 -206
  198. package/lib/types/src/host/integration/root-registry.d.ts +0 -115
  199. package/lib/types/src/host/integration/roots/anchor-directory.d.ts +0 -56
  200. package/lib/types/src/host/integration/roots/bin-root-resolver.d.ts +0 -81
  201. package/lib/types/src/host/integration/roots/remote-home.d.ts +0 -69
  202. package/lib/types/src/host/integration/roots/root-registry.d.ts +0 -144
  203. package/lib/types/src/host/integration/roots/roots-wiring.d.ts +0 -219
  204. package/lib/types/src/host/integration/roots/session-root-index.d.ts +0 -52
  205. package/lib/types/src/host/integration/roots-api.d.ts +0 -407
  206. package/lib/types/src/host/integration/roots-wiring.d.ts +0 -211
  207. package/lib/types/src/host/integration/session/session-api.d.ts +0 -88
  208. package/lib/types/src/host/integration/session/session-bin-lock.d.ts +0 -80
  209. package/lib/types/src/host/integration/session/session-header.d.ts +0 -151
  210. package/lib/types/src/host/integration/session/session-labels.d.ts +0 -56
  211. package/lib/types/src/host/integration/session/session-route-wiring.d.ts +0 -50
  212. package/lib/types/src/host/integration/session-admin-service.d.ts +0 -236
  213. package/lib/types/src/host/integration/session-api.d.ts +0 -81
  214. package/lib/types/src/host/integration/session-bin-lock.d.ts +0 -80
  215. package/lib/types/src/host/integration/session-header.d.ts +0 -118
  216. package/lib/types/src/host/integration/session-labels.d.ts +0 -56
  217. package/lib/types/src/host/integration/session-route-wiring.d.ts +0 -50
  218. package/lib/types/src/host/integration/session-scope.d.ts +0 -113
  219. package/lib/types/src/host/integration/session-tools.d.ts +0 -44
  220. package/lib/types/src/host/integration/strict-arguments.d.ts +0 -79
  221. package/lib/types/src/host/integration/takeover/takeover-api.d.ts +0 -62
  222. package/lib/types/src/host/integration/takeover/takeover-route-wiring.d.ts +0 -60
  223. package/lib/types/src/host/integration/takeover/takeover-service.d.ts +0 -167
  224. package/lib/types/src/host/integration/terminal-manifest.d.ts +0 -94
  225. package/lib/types/src/host/integration/tools/management-tools.d.ts +0 -245
  226. package/lib/types/src/host/integration/tools/remote-job-tools.d.ts +0 -316
  227. package/lib/types/src/host/integration/tools/remote-lsp-tools.d.ts +0 -43
  228. package/lib/types/src/host/integration/tools/remote-tools.d.ts +0 -236
  229. package/lib/types/src/host/integration/tools/session-target.d.ts +0 -52
  230. package/lib/types/src/host/integration/tools/session-tools.d.ts +0 -46
  231. package/lib/types/src/host/integration/tools/strict-arguments.d.ts +0 -79
  232. package/lib/types/src/host/integration/tools/terminal-manifest.d.ts +0 -94
  233. package/lib/types/src/host/integration/transfer/remote-copy.d.ts +0 -66
  234. package/lib/types/src/host/integration/transfer/transfer-adapters.d.ts +0 -48
  235. package/lib/types/src/host/integration/transfer/transfer-tracker.d.ts +0 -106
  236. package/lib/types/src/host/integration/transfer-adapters.d.ts +0 -44
  237. package/lib/types/src/host/integration/transfer-service.d.ts +0 -164
  238. package/lib/types/src/host/integration/transfer-tracker.d.ts +0 -106
  239. package/lib/types/src/host/integration/user-roots.d.ts +0 -461
  240. package/lib/types/src/wiring/connections.d.ts +0 -189
  241. package/lib/types/src/wiring/fs.d.ts +0 -13
  242. package/lib/types/src/wiring/install-memo.d.ts +0 -32
  243. package/lib/types/src/wiring/legacy-dirs.d.ts +0 -62
  244. package/lib/types/src/wiring/package-paths.d.ts +0 -35
  245. package/lib/types/src/wiring/roots.d.ts +0 -21
  246. package/lib/types/src/wiring/state-dir.d.ts +0 -29
  247. package/lib/types/src/wiring/tools.d.ts +0 -35
@@ -1,266 +0,0 @@
1
- /**
2
- * The **body-level portal**: the one place this plugin's cards are mounted outside the host's own layout.
3
- *
4
- * Why it has to exist, and why the previous "inline, narrow-first" plan was wrong: the
5
- * `sidebar.workspaces.directoryFlow` hole renders **inside the sidebar's title row**, which is a flex row
6
- * that clips its overflow. A card rendered in place there is a flex item, and a flex item is *shrunk*
7
- * (`flex-shrink: 1`) before it ever overflows - `max-width: 100%` says nothing about shrinking, and the row
8
- * does not wrap. The real screenshot after the last release showed exactly that: two or three vertical lines
9
- * with a clipped "选择连接并填写". That is a fact about the real DOM, not a hypothesis, so the card has to
10
- * leave the row: one container per mount, appended to the **injected** `document.body` while the interaction
11
- * is open, removed again when it closes, and `position: fixed` inside it.
12
- *
13
- * Two rules this module keeps:
14
- *
15
- * - **The DOM is injected.** {@link createCardPortal} takes the document; nothing here touches `document` at
16
- * module scope, so importing this module off-browser (Node's test runner, the host half) does nothing, and
17
- * every branch is driven by a fake in the offline tests.
18
- * - **One container per mount.** `mount()` and `unmount()` are idempotent: a re-render while the card is open
19
- * must not append a second container, and a double close must not remove the same node twice.
20
- *
21
- * `createPortal` comes from `react-dom`, which is **not** a dependency of this repository but *is* a client
22
- * baseline external: `PLATFORM_MODULES` in `packages/client/web/src/platform.ts` names it among the modules
23
- * the shell seeds into the frozen module table, and the loader calls every client factory as
24
- * `factory(require)` with a `require` that looks a specifier up in that seed table first
25
- * (`ClientModuleSystem.makeRequire`). The lookup below therefore goes through that same `require` instead of
26
- * a static import, for one concrete reason: a static `import 'react-dom'` is evaluated when Node's test
27
- * runner loads this module, and `react-dom` is not installed here - every offline client test would fail at
28
- * import time. The lookup is lazy, and a runtime that cannot supply `react-dom` renders the card in place
29
- * (the pre-portal behaviour) instead of failing, with one warning so the degradation is visible in a log.
30
- *
31
- * @module dsh-over-ssh/client/portal
32
- */
33
- import type { ReactNode } from 'react';
34
- /** The part of `document` this module uses. Structural, so a fake document is a full citizen. */
35
- export interface PortalDocument {
36
- /** The element a card container is attached to while the card is open. */
37
- readonly body?: PortalContainer | null | undefined;
38
- /** Whatever held focus when the card opened; the card gives focus back to it when it closes. */
39
- readonly activeElement?: FocusTarget | null | undefined;
40
- createElement(tag: string): PortalElement;
41
- /**
42
- * Present on a real document; the shell hangs its global key listener here.
43
- *
44
- * `options` exists for one caller: the settings-hosted card traps Tab in the **capture** phase. The platform's
45
- * own modal layer listens on `document` in the bubble phase and, seeing focus outside its panel, pulls it back
46
- * — a bubble listener of ours would run *after* it (registration order) and could no longer tell which field
47
- * Tab came from. Capture runs first, so the card keeps the key it owns.
48
- */
49
- addEventListener?(type: 'keydown', listener: (event: PortalKeyEvent) => void, options?: boolean): void;
50
- /** The other half of {@link addEventListener}. */
51
- removeEventListener?(type: 'keydown', listener: (event: PortalKeyEvent) => void, options?: boolean): void;
52
- }
53
- /** One element the portal created. Only what the portal itself does with it is typed here. */
54
- export interface PortalElement {
55
- /** The class attribute; the port has already been given its vocabulary classes when it is attached. */
56
- className: string;
57
- /** Present on a real element; used to move focus into the card. */
58
- querySelector?(selector: string): FocusTarget | null | undefined;
59
- /** Present on a real element; used by the Tab trap to list the card's controls in order. */
60
- querySelectorAll?(selector: string): ArrayLike<FocusTarget> | null | undefined;
61
- }
62
- /**
63
- * The part of a keyboard event the portal reads.
64
- *
65
- * Structural, like {@link KeyEventLike} in `./controls.ts`: the pure helpers are testable offline, and a real
66
- * `KeyboardEvent` is assignable to it.
67
- */
68
- export interface PortalKeyEvent {
69
- /** The key name, e.g. `'Escape'` or `'Tab'`. */
70
- readonly key?: string;
71
- /** True while Shift is held: the Tab trap walks backwards. */
72
- readonly shiftKey?: boolean;
73
- /** Cancel the browser's own focus move when the trap takes over. */
74
- preventDefault?(): void;
75
- /** Stop the event before a modal layer behind the card sees it (see {@link trapCardTab}). */
76
- stopPropagation?(): void;
77
- }
78
- /**
79
- * The **one** shell every confirmation card is portalled into.
80
- *
81
- * A confirmation is the same object wherever it is raised: a sentence naming what will be destroyed, and two
82
- * buttons. Three surfaces used to compose that object three ways (audit 2026-11-01b ui P2-8 / task-12 B1); this
83
- * constant is the whole fix, together with {@link CONFIRM_BACKDROP_CLASS}.
84
- */
85
- export declare const CONFIRM_PORTAL_CLASS: string;
86
- /**
87
- * The confirmation's click sink.
88
- *
89
- * It uses the settings tier (1001) because the settings panel is one of the three raisers and its modal uses
90
- * 900/1001; the overlay is above everything and sits at the same tier, so one constant is right for both.
91
- */
92
- export declare const CONFIRM_BACKDROP_CLASS: string;
93
- /** The two operations the portal needs from `document.body`. */
94
- export interface PortalContainer {
95
- appendChild(node: PortalElement): unknown;
96
- removeChild(node: PortalElement): unknown;
97
- }
98
- /** Anything that can take focus; `document.activeElement` is one. */
99
- export interface FocusTarget {
100
- focus?(): void;
101
- readonly isConnected?: boolean;
102
- }
103
- /** Render a card somewhere else. The browser passes a function built on `react-dom`'s `createPortal`. */
104
- export type PortalRenderer = (children: ReactNode, container: unknown) => ReactNode;
105
- /**
106
- * What a template needs to put its card in a portal: the container element (created from the injected
107
- * document) and the renderer that fills it.
108
- *
109
- * The template never creates either of them - it only decides whether it has one. That keeps the templates
110
- * pure element trees the offline tests walk, and makes "the card is not in the host container" an assertion
111
- * about an injected fake rather than about React.
112
- */
113
- export interface CardPortalTarget {
114
- /** The body-level element the card is rendered into. */
115
- readonly container: unknown;
116
- /** Render the card into {@link container}. */
117
- readonly render: PortalRenderer;
118
- }
119
- /** One mount's body-level container, plus its attach/detach lifecycle. */
120
- export interface CardPortal extends CardPortalTarget {
121
- /**
122
- * The click sink that sits **under** the card and counts as "the page behind the dialog".
123
- *
124
- * `undefined` when the caller asked for no backdrop, when there is no document, or when the runtime cannot
125
- * portal at all (an in-place card has no modal geometry to protect). See {@link CreateCardPortalOptions.backdropClassName}.
126
- */
127
- readonly backdrop: PortalElement | undefined;
128
- /** True while the container is attached to `document.body`. */
129
- readonly mounted: boolean;
130
- /** Attach the container; a second call while attached does nothing. */
131
- mount(): void;
132
- /** Detach the container; a second call while detached does nothing. */
133
- unmount(): void;
134
- /** Move focus to the card's first control. `false` when there is nothing focusable (or no DOM). */
135
- focusCard(): boolean;
136
- }
137
- /** What {@link createCardPortal} needs: the injected document, the container's classes and the renderer. */
138
- export interface CreateCardPortalOptions {
139
- /** The page's `document`, or `undefined` off-browser, where the whole portal is a no-op. */
140
- readonly document: PortalDocument | undefined;
141
- /** Classes of the body-level container (`CLASS.portal` plus one placement class). */
142
- readonly className: string;
143
- /** How the card is rendered into the container; the shells pass {@link renderInPortal}. */
144
- readonly render: PortalRenderer;
145
- /**
146
- * Classes of the **backdrop**: the element this portal inserts under the card to swallow pointer input.
147
- *
148
- * Why it exists at all: the card claims `aria-modal="true"` and traps Tab, but the page behind it stayed
149
- * *clickable* — the portal only ever created the card's own container, which hugs the card, so everywhere else
150
- * the pointer reached the surface underneath. With the connection editor open that meant a click could land on
151
- * the 「保存」 of the form behind it (and, before the drafts were split, submit the dialog's values as a new
152
- * connection). A backdrop is the pointer half of the modal promise; the Tab trap is the keyboard half
153
- * (audit 2026-11-01b ui P2-1).
154
- *
155
- * Optional so a caller that renders a **non-modal** card keeps the old behaviour, and so the offline portal
156
- * tests can keep asserting the container lifecycle alone.
157
- */
158
- readonly backdropClassName?: string;
159
- }
160
- /**
161
- * The selector of the first thing in a card that can take focus.
162
- *
163
- * Disabled controls are excluded, and so is a `tabindex="-1"` element (a programmatic focus target, not a
164
- * user one): the point of the initial focus is that the next Tab goes somewhere sensible.
165
- */
166
- export declare const CARD_FOCUS_SELECTOR = "button:not([disabled]), input:not([disabled]), select:not([disabled]), a[href], [tabindex]:not([tabindex=\"-1\"])";
167
- /**
168
- * Create one mount's card portal.
169
- *
170
- * The container is created **eagerly** (a React portal needs its container during the commit that renders the
171
- * card) but attached **lazily**: nothing is in the body until `mount()` runs, which the shell does from a
172
- * layout effect on the open edge, so a closed surface costs no DOM at all.
173
- *
174
- * @param options - the injected document, the container's classes and the card renderer.
175
- * @returns the portal handle; every method is safe with no document and safe to call twice.
176
- */
177
- export declare function createCardPortal(options: CreateCardPortalOptions): CardPortal;
178
- /**
179
- * Move focus to the first control inside a container.
180
- *
181
- * @param container - the card's container, or `undefined` when there is no DOM.
182
- * @returns whether something actually took focus.
183
- */
184
- export declare function focusFirstControl(container: PortalElement | undefined): boolean;
185
- /**
186
- * Every control inside the card that Tab can reach, in DOM order.
187
- *
188
- * @param container - the card's container, or `undefined` when there is no DOM.
189
- * @returns the focusable elements; `[]` when the container or `querySelectorAll` is absent.
190
- */
191
- export declare function focusableWithin(container: PortalElement | undefined): readonly FocusTarget[];
192
- /**
193
- * Keep Tab inside the open card.
194
- *
195
- * A dialog that lets Tab walk into the page behind it is a dialog the keyboard user can leave without
196
- * dismissing; trapping the two ends is the minimum the modal promise requires. `active` is passed in (rather
197
- * than read from the document) so the rule is a pure function of its arguments.
198
- *
199
- * @param event - the keydown event, structurally.
200
- * @param container - the card's container.
201
- * @param active - the element that currently holds focus.
202
- * @returns whether the trap handled the key (and already called `preventDefault`).
203
- */
204
- export declare function trapTab(event: {
205
- readonly shiftKey?: boolean;
206
- preventDefault?(): void;
207
- }, container: PortalElement | undefined, active: FocusTarget | undefined): boolean;
208
- /**
209
- * Keep Tab inside a card that is hosted **inside another modal**.
210
- *
211
- * The settings page is a platform modal with its own focus trap (`useModalLayer`): it listens for Tab on
212
- * `document` and, when focus is not inside its panel, moves focus to that panel's first control. This card is
213
- * deliberately *outside* that panel (it is portalled to the body above the modal layers, audit 0088), so without
214
- * this the platform would pull the caret out of the dialog on the first Tab.
215
- *
216
- * Two things have to happen, in this order:
217
- *
218
- * 1. `stopPropagation` — the platform's listener is on `document` in the **bubble** phase, so the card's own
219
- * listener must be registered in the capture phase ({@link PortalDocument.addEventListener}'s `options`) and
220
- * consume the event before it bubbles back up;
221
- * 2. delegate to {@link trapTab} for the wrap at both ends. **In the middle it returns `false` and does not
222
- * preventDefault** — the browser's own Tab then walks the card's fields in order, which is exactly right.
223
- *
224
- * @param event - the keydown event, structurally.
225
- * @param container - the card's container.
226
- * @param active - the element that currently holds focus.
227
- * @returns whether Tab was consumed (the trap already called `preventDefault`).
228
- */
229
- export declare function trapCardTab(event: PortalKeyEvent, container: PortalElement | undefined, active: FocusTarget | undefined): boolean;
230
- /**
231
- * Remember what held focus before the card opened.
232
- *
233
- * @param doc - the page's `document`, or `undefined` off-browser.
234
- * @returns the focused element, or `undefined` when nothing was focused.
235
- */
236
- export declare function captureFocusOrigin(doc: PortalDocument | undefined): FocusTarget | undefined;
237
- /**
238
- * Give focus back to the element {@link captureFocusOrigin} remembered.
239
- *
240
- * @param origin - the remembered element.
241
- * @returns whether focus was handed back; `false` when the trigger is gone (the owner re-rendered it away).
242
- */
243
- export declare function restoreFocusOrigin(origin: FocusTarget | undefined): boolean;
244
- /**
245
- * True when a card can actually be portalled here: this runtime supplies `react-dom`.
246
- *
247
- * Without it the shell must render the card in place and skip the container lifecycle entirely (an empty
248
- * body-level node would just be appended and removed for nothing).
249
- *
250
- * @returns whether {@link renderInPortal} has a `createPortal` to work with.
251
- */
252
- export declare function canRenderInPortal(): boolean;
253
- /**
254
- * Render a card into the portal container, with `react-dom`'s `createPortal`.
255
- *
256
- * @param children - the card element the template built.
257
- * @param container - the body-level element from {@link createCardPortal}.
258
- * @returns the portal element, or `children` unchanged when this runtime supplies no `react-dom`.
259
- */
260
- export declare function renderInPortal(children: ReactNode, container: unknown): ReactNode;
261
- /**
262
- * The page's `document`, when this module runs in a browser.
263
- *
264
- * @returns the structural document view, or `undefined` off-browser.
265
- */
266
- export declare function browserPortalDocument(): PortalDocument | undefined;
@@ -1,84 +0,0 @@
1
- /**
2
- * The client half's host data channel: mount the `sshdev` namespace and read connection status.
3
- *
4
- * Three facts decide the shape of this module, all read from 0.2.0-rc.2 (see
5
- * [`doc/02-platform/remote-data-channel.md`](../../doc/02-platform/remote-data-channel.md)):
6
- *
7
- * 1. **The namespace is mounted by us, not by `api-remotes`.** That core assembly lists its packages
8
- * explicitly, so a third-party plugin mounts its own `TypertRemoteContribution` through
9
- * `ctx.remote.$mount`.
10
- * 2. **`remote.<ns>` must NOT be in the plugin's `inject`.** We create the namespace ourselves inside
11
- * `apply`; declaring it as a dependency would wait forever for a service only we can provide.
12
- * 3. **The descriptors are hand-written and zero-argument.** `$mount` rejects any descriptor whose
13
- * parameter/uplink/Context codec is not strict, and only the Typert build pipeline produces strict
14
- * codecs. A method with **no parameters** triggers none of those checks, which is why the slice stops
15
- * at one zero-argument read; anything with arguments needs generated `lib/typert.remote-client.js`.
16
- *
17
- * The wire contract (`sshdev/connections` → an array of `{id, host, transport, degraded, note}`) is mirrored
18
- * in `src/host/integration/remote-face.ts`; the two halves are separate tsconfig programs and cannot import
19
- * each other, so the constants below are a hand-synchronized pair.
20
- *
21
- * @module dsh-over-ssh/client/remote
22
- */
23
- import type { Context } from '@deepseek-ai/cordis';
24
- import type { InvocationDescriptor, TypertDisposer, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol';
25
- import { type ConnectionRow } from './panel-model.ts';
26
- /** Wire namespace; the host face declares the same string. */
27
- export declare const SSH_DEV_REMOTE_NAMESPACE = "sshdev";
28
- /** Endpoint method name. */
29
- export declare const SSH_DEV_REMOTE_METHOD = "connections";
30
- /** Host Cordis service key the descriptor dispatches to (must match the host face's service name). */
31
- export declare const SSH_DEV_REMOTE_SERVICE = "sshDevRemote";
32
- /** Contribution identity; `$mount` rejects a repeat of the same package name. */
33
- export declare const SSH_DEV_REMOTE_PACKAGE = "dsh-over-ssh";
34
- /**
35
- * The one descriptor this slice mounts.
36
- *
37
- * `result: { mode: 'src-json' }` is the honest declaration: no strict result codec exists for this endpoint in
38
- * this repository, and the Client Remote only consults `result.decode` when the mode is `strict`
39
- * (`packages/api/gateway/src/client/index.ts:449-451`), so the raw JSON value passes through and is narrowed
40
- * by {@link toConnectionRows} instead.
41
- */
42
- export declare const SSH_DEV_CONNECTIONS_DESCRIPTOR: InvocationDescriptor;
43
- /** The mountable contribution. */
44
- export declare const SSH_DEV_REMOTE_CONTRIBUTION: TypertRemoteContribution;
45
- /**
46
- * Mount the `sshdev` namespace in the caller's fiber.
47
- *
48
- * The returned disposer withdraws the namespace and its concrete method; `$mount` also registers everything
49
- * as an effect of the calling context, so unloading the plugin tears the channel down even if the caller
50
- * never keeps the disposer.
51
- *
52
- * @param ctx - the plugin's client context (needs `remote`).
53
- * @returns the mount disposer.
54
- */
55
- export declare function mountConnectionChannel(ctx: Context): Promise<TypertDisposer>;
56
- /**
57
- * Read the host's connection status once.
58
- *
59
- * Deliberately non-throwing: a channel that is absent, unmounted, offline, answered with a failure, or that
60
- * rejects outright yields `undefined`, and the panel keeps its "no host data" notice.
61
- *
62
- * @param ctx - the plugin's client context; the namespace must already be mounted.
63
- * @returns the panel rows, or `undefined` when no usable answer arrived.
64
- */
65
- export declare function fetchConnectionRows(ctx: Context): Promise<readonly ConnectionRow[] | undefined>;
66
- /** Where {@link openConnectionChannel} reports its outcome. */
67
- export interface ConnectionChannelObserver {
68
- /** Called once with the first rows the host answered — including an empty list (no connection configured). */
69
- readonly onRows: (rows: readonly ConnectionRow[]) => void;
70
- /** Called when the channel could not be mounted or answered; the panel keeps its notice. */
71
- readonly onUnavailable?: (reason: unknown) => void;
72
- }
73
- /**
74
- * Mount the channel, read it once, and hand the rows to `observer.onRows`.
75
- *
76
- * One read, no polling and no subscription: the panel is a snapshot of the moment the settings page (or the
77
- * plugin) came up. Live refresh needs an observable source on the inject face — see the limitations section of
78
- * `doc/02-platform/remote-data-channel.md`.
79
- *
80
- * @param ctx - the plugin's client context (needs `remote`).
81
- * @param observer - row sink plus an optional unavailable-reason sink.
82
- * @returns the mount disposer, or `undefined` when the channel never mounted.
83
- */
84
- export declare function openConnectionChannel(ctx: Context, observer: ConnectionChannelObserver): Promise<TypertDisposer | undefined>;