dsh-over-ssh 0.1.0 → 0.2.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 (250) hide show
  1. package/README.md +19 -17
  2. package/agents/agent-manifest.json +6 -6
  3. package/agents/linux-amd64/dsh-over-ssh-agent +0 -0
  4. package/agents/linux-arm64/dsh-over-ssh-agent +0 -0
  5. package/lib/client.js +422 -337
  6. package/lib/file-references.js +92 -35
  7. package/lib/fs.js +295 -113
  8. package/lib/index.js +6912 -4330
  9. package/lib/terminal-wrapper.js +9 -4
  10. package/lib/types/src/config.d.ts +156 -9
  11. package/lib/types/src/file-references.d.ts +0 -1
  12. package/lib/types/src/host/app/backend.d.ts +44 -3
  13. package/lib/types/src/host/app/recycle-bin/recycle-bin-contract.d.ts +0 -1
  14. package/lib/types/src/host/app/recycle-bin/recycle-bin-service.d.ts +0 -1
  15. package/lib/types/src/host/app/session-admin/session-admin-contract.d.ts +12 -1
  16. package/lib/types/src/host/app/session-admin/session-admin-service.d.ts +0 -1
  17. package/lib/types/src/host/app/transport/transport-selector.d.ts +0 -1
  18. package/lib/types/src/host/app/transport/transport-service.d.ts +0 -1
  19. package/lib/types/src/host/domain/capability.d.ts +0 -1
  20. package/lib/types/src/host/domain/errors.d.ts +0 -1
  21. package/lib/types/src/host/domain/roots/connection.d.ts +0 -1
  22. package/lib/types/src/host/domain/roots/root.d.ts +24 -9
  23. package/lib/types/src/host/domain/roots/session-roots.d.ts +23 -1
  24. package/lib/types/src/host/domain/roots/ssh-config.d.ts +0 -1
  25. package/lib/types/src/host/domain/session/session-admin.d.ts +0 -1
  26. package/lib/types/src/host/domain/transfer/recycle-bin.d.ts +0 -1
  27. package/lib/types/src/host/domain/transfer/transfer.d.ts +0 -1
  28. package/lib/types/src/host/infra/transport/agent/agent-installer.d.ts +0 -1
  29. package/lib/types/src/host/infra/transport/forward.d.ts +75 -0
  30. package/lib/types/src/host/infra/transport/ssh/ssh2-transport.d.ts +5 -1
  31. package/lib/types/src/host/infra/transport/transport-base.d.ts +0 -1
  32. package/lib/types/src/host/infra/transport/transport.d.ts +42 -2
  33. package/lib/types/src/host/integration/agent/agent-preflight.d.ts +0 -1
  34. package/lib/types/src/host/integration/fs/file-reference-provider.d.ts +0 -1
  35. package/lib/types/src/host/integration/fs/fs-provider.d.ts +18 -3
  36. package/lib/types/src/host/integration/transfer/transfer-service.d.ts +0 -1
  37. package/lib/types/src/index.d.ts +23 -1
  38. package/lib/types/src/local-bridge-refs.d.ts +0 -1
  39. package/lib/types/src/local-bridge.d.ts +0 -1
  40. package/lib/types/src/shared/root-keys.d.ts +120 -0
  41. package/lib/types/src/wiring/helpers.d.ts +0 -1
  42. package/package.json +5 -3
  43. package/lib/types/src/client/controls.d.ts +0 -131
  44. package/lib/types/src/client/core/card-focus-trap.d.ts +0 -45
  45. package/lib/types/src/client/core/controls.d.ts +0 -164
  46. package/lib/types/src/client/core/latest.d.ts +0 -48
  47. package/lib/types/src/client/core/locale.d.ts +0 -38
  48. package/lib/types/src/client/core/message.d.ts +0 -37
  49. package/lib/types/src/client/core/panel-model.d.ts +0 -134
  50. package/lib/types/src/client/core/portal.d.ts +0 -266
  51. package/lib/types/src/client/core/remote.d.ts +0 -84
  52. package/lib/types/src/client/core/styles.d.ts +0 -458
  53. package/lib/types/src/client/file-tree-io.d.ts +0 -19
  54. package/lib/types/src/client/file-tree.d.ts +0 -271
  55. package/lib/types/src/client/flows/directory-browser.d.ts +0 -587
  56. package/lib/types/src/client/flows/session-directory.d.ts +0 -415
  57. package/lib/types/src/client/flows/workspace-directory-flow.d.ts +0 -480
  58. package/lib/types/src/client/locale.d.ts +0 -31
  59. package/lib/types/src/client/panel-model.d.ts +0 -37
  60. package/lib/types/src/client/panel.d.ts +0 -77
  61. package/lib/types/src/client/roots/connection-test.d.ts +0 -69
  62. package/lib/types/src/client/roots/roots-panel-state.d.ts +0 -307
  63. package/lib/types/src/client/roots/roots-panel-view.d.ts +0 -280
  64. package/lib/types/src/client/roots/roots-panel.d.ts +0 -364
  65. package/lib/types/src/client/roots/transfer-panel-view.d.ts +0 -35
  66. package/lib/types/src/client/roots/transfer-panel.d.ts +0 -241
  67. package/lib/types/src/client/roots/transfer-progress.d.ts +0 -67
  68. package/lib/types/src/client/roots-panel-view.d.ts +0 -236
  69. package/lib/types/src/client/roots-panel.d.ts +0 -347
  70. package/lib/types/src/client/session/session-panel-view.d.ts +0 -336
  71. package/lib/types/src/client/session/session-panel.d.ts +0 -322
  72. package/lib/types/src/client/session/session-remote-mark.d.ts +0 -110
  73. package/lib/types/src/client/session/session-row-actions.d.ts +0 -398
  74. package/lib/types/src/client/session-panel.d.ts +0 -152
  75. package/lib/types/src/client/styles.d.ts +0 -252
  76. package/lib/types/src/client/workspace-directory-flow.d.ts +0 -342
  77. package/lib/types/src/fs.d.ts +0 -46
  78. package/lib/types/src/host/app/recycle-bin/recycle-bin-move.d.ts +0 -18
  79. package/lib/types/src/host/app/recycle-bin/recycle-bin-world.d.ts +0 -38
  80. package/lib/types/src/host/app/recycle-bin-contract.d.ts +0 -215
  81. package/lib/types/src/host/app/recycle-bin-move.d.ts +0 -18
  82. package/lib/types/src/host/app/recycle-bin-service.d.ts +0 -45
  83. package/lib/types/src/host/app/recycle-bin-world.d.ts +0 -35
  84. package/lib/types/src/host/app/roots/roots-api-connections.d.ts +0 -49
  85. package/lib/types/src/host/app/roots/roots-api-contract.d.ts +0 -369
  86. package/lib/types/src/host/app/roots/roots-api-directories.d.ts +0 -13
  87. package/lib/types/src/host/app/roots/roots-api-http.d.ts +0 -77
  88. package/lib/types/src/host/app/roots/roots-api-long-poll.d.ts +0 -130
  89. package/lib/types/src/host/app/roots/roots-api-projections.d.ts +0 -102
  90. package/lib/types/src/host/app/roots/roots-api-roots.d.ts +0 -13
  91. package/lib/types/src/host/app/roots/roots-api-state.d.ts +0 -22
  92. package/lib/types/src/host/app/roots/roots-api-transfers.d.ts +0 -26
  93. package/lib/types/src/host/app/roots/roots-api.d.ts +0 -55
  94. package/lib/types/src/host/app/roots/user-roots.d.ts +0 -552
  95. package/lib/types/src/host/app/roots-api-connections.d.ts +0 -49
  96. package/lib/types/src/host/app/roots-api-contract.d.ts +0 -339
  97. package/lib/types/src/host/app/roots-api-directories.d.ts +0 -13
  98. package/lib/types/src/host/app/roots-api-http.d.ts +0 -77
  99. package/lib/types/src/host/app/roots-api-projections.d.ts +0 -102
  100. package/lib/types/src/host/app/roots-api-roots.d.ts +0 -13
  101. package/lib/types/src/host/app/roots-api-state.d.ts +0 -22
  102. package/lib/types/src/host/app/roots-api-support.d.ts +0 -182
  103. package/lib/types/src/host/app/roots-api-transfers.d.ts +0 -13
  104. package/lib/types/src/host/app/roots-api.d.ts +0 -55
  105. package/lib/types/src/host/app/routed-fs.d.ts +0 -239
  106. package/lib/types/src/host/app/serialize.d.ts +0 -37
  107. package/lib/types/src/host/app/session-admin/session-admin-context.d.ts +0 -36
  108. package/lib/types/src/host/app/session-admin/session-admin-delete.d.ts +0 -34
  109. package/lib/types/src/host/app/session-admin-context.d.ts +0 -36
  110. package/lib/types/src/host/app/session-admin-contract.d.ts +0 -214
  111. package/lib/types/src/host/app/session-admin-delete.d.ts +0 -34
  112. package/lib/types/src/host/app/session-admin-service.d.ts +0 -38
  113. package/lib/types/src/host/app/takeover/takeover-plan.d.ts +0 -227
  114. package/lib/types/src/host/app/takeover/takeover-rows.d.ts +0 -55
  115. package/lib/types/src/host/app/transport-selector.d.ts +0 -98
  116. package/lib/types/src/host/app/transport-service.d.ts +0 -75
  117. package/lib/types/src/host/app/user-roots.d.ts +0 -461
  118. package/lib/types/src/host/domain/bin-location.d.ts +0 -79
  119. package/lib/types/src/host/domain/connection.d.ts +0 -95
  120. package/lib/types/src/host/domain/glob-pattern.d.ts +0 -62
  121. package/lib/types/src/host/domain/literal-text.d.ts +0 -63
  122. package/lib/types/src/host/domain/path-grammar.d.ts +0 -84
  123. package/lib/types/src/host/domain/recycle-bin.d.ts +0 -337
  124. package/lib/types/src/host/domain/root.d.ts +0 -74
  125. package/lib/types/src/host/domain/roots/bin-location.d.ts +0 -91
  126. package/lib/types/src/host/domain/roots/route-table.d.ts +0 -102
  127. package/lib/types/src/host/domain/route-table.d.ts +0 -80
  128. package/lib/types/src/host/domain/session/terminal-target.d.ts +0 -136
  129. package/lib/types/src/host/domain/session-admin.d.ts +0 -330
  130. package/lib/types/src/host/domain/shell.d.ts +0 -47
  131. package/lib/types/src/host/domain/ssh-config.d.ts +0 -73
  132. package/lib/types/src/host/domain/terminal-target.d.ts +0 -132
  133. package/lib/types/src/host/domain/tool-requests.d.ts +0 -369
  134. package/lib/types/src/host/domain/transfer.d.ts +0 -260
  135. package/lib/types/src/host/infra/backend/local-backend.d.ts +0 -84
  136. package/lib/types/src/host/infra/backend/local-version.d.ts +0 -43
  137. package/lib/types/src/host/infra/backend/platform-local-backend.d.ts +0 -89
  138. package/lib/types/src/host/infra/backend/remote-backend.d.ts +0 -239
  139. package/lib/types/src/host/infra/cache/lru.d.ts +0 -52
  140. package/lib/types/src/host/infra/cache/versioned.d.ts +0 -77
  141. package/lib/types/src/host/infra/temp-name.d.ts +0 -19
  142. package/lib/types/src/host/infra/transport/agent/agent-protocol-client.d.ts +0 -132
  143. package/lib/types/src/host/infra/transport/agent/agent-protocol-codec.d.ts +0 -140
  144. package/lib/types/src/host/infra/transport/agent/agent-protocol-errors.d.ts +0 -41
  145. package/lib/types/src/host/infra/transport/agent/agent-protocol-frames.d.ts +0 -197
  146. package/lib/types/src/host/infra/transport/agent/agent-protocol-types.d.ts +0 -564
  147. package/lib/types/src/host/infra/transport/agent/agent-transport.d.ts +0 -418
  148. package/lib/types/src/host/infra/transport/agent-installer.d.ts +0 -121
  149. package/lib/types/src/host/infra/transport/agent-protocol-client.d.ts +0 -123
  150. package/lib/types/src/host/infra/transport/agent-protocol-codec.d.ts +0 -131
  151. package/lib/types/src/host/infra/transport/agent-protocol-errors.d.ts +0 -41
  152. package/lib/types/src/host/infra/transport/agent-protocol-frames.d.ts +0 -197
  153. package/lib/types/src/host/infra/transport/agent-protocol-types.d.ts +0 -509
  154. package/lib/types/src/host/infra/transport/agent-transport.d.ts +0 -353
  155. package/lib/types/src/host/infra/transport/alias-transport.d.ts +0 -206
  156. package/lib/types/src/host/infra/transport/askpass-fs.d.ts +0 -20
  157. package/lib/types/src/host/infra/transport/askpass.d.ts +0 -133
  158. package/lib/types/src/host/infra/transport/command-pool.d.ts +0 -61
  159. package/lib/types/src/host/infra/transport/fs-commands.d.ts +0 -140
  160. package/lib/types/src/host/infra/transport/git-status-route.d.ts +0 -63
  161. package/lib/types/src/host/infra/transport/git-status.d.ts +0 -101
  162. package/lib/types/src/host/infra/transport/node-spawn.d.ts +0 -26
  163. package/lib/types/src/host/infra/transport/session-window.d.ts +0 -51
  164. package/lib/types/src/host/infra/transport/shell-quote.d.ts +0 -59
  165. package/lib/types/src/host/infra/transport/ssh/alias-transport.d.ts +0 -206
  166. package/lib/types/src/host/infra/transport/ssh/askpass-fs.d.ts +0 -20
  167. package/lib/types/src/host/infra/transport/ssh/askpass.d.ts +0 -133
  168. package/lib/types/src/host/infra/transport/ssh/shell-quote.d.ts +0 -62
  169. package/lib/types/src/host/infra/transport/ssh/ssh-argv.d.ts +0 -43
  170. package/lib/types/src/host/infra/transport/ssh-argv.d.ts +0 -43
  171. package/lib/types/src/host/infra/transport/ssh2-transport.d.ts +0 -302
  172. package/lib/types/src/host/integration/agent/agent-install-io.d.ts +0 -33
  173. package/lib/types/src/host/integration/agent/askpass-registry.d.ts +0 -66
  174. package/lib/types/src/host/integration/agent-install-io.d.ts +0 -33
  175. package/lib/types/src/host/integration/agent-preflight.d.ts +0 -56
  176. package/lib/types/src/host/integration/anchor-directory.d.ts +0 -56
  177. package/lib/types/src/host/integration/askpass-registry.d.ts +0 -59
  178. package/lib/types/src/host/integration/bin-root-resolver.d.ts +0 -81
  179. package/lib/types/src/host/integration/connection-test.d.ts +0 -73
  180. package/lib/types/src/host/integration/file-reference-provider.d.ts +0 -115
  181. package/lib/types/src/host/integration/fs/git-status-wiring.d.ts +0 -21
  182. package/lib/types/src/host/integration/fs/platform-errors.d.ts +0 -94
  183. package/lib/types/src/host/integration/fs/remote-file-tools.d.ts +0 -369
  184. package/lib/types/src/host/integration/fs/remote-index.d.ts +0 -177
  185. package/lib/types/src/host/integration/fs-provider.d.ts +0 -226
  186. package/lib/types/src/host/integration/lsp/lsp-framing.d.ts +0 -38
  187. package/lib/types/src/host/integration/lsp/lsp-registry.d.ts +0 -67
  188. package/lib/types/src/host/integration/lsp/lsp-session.d.ts +0 -130
  189. package/lib/types/src/host/integration/management-tools.d.ts +0 -64
  190. package/lib/types/src/host/integration/recycle-bin-service.d.ts +0 -247
  191. package/lib/types/src/host/integration/remote/connection-test.d.ts +0 -73
  192. package/lib/types/src/host/integration/remote/remote-face.d.ts +0 -127
  193. package/lib/types/src/host/integration/remote/remote-tool-backend.d.ts +0 -108
  194. package/lib/types/src/host/integration/remote-face.d.ts +0 -127
  195. package/lib/types/src/host/integration/remote-file-tools.d.ts +0 -241
  196. package/lib/types/src/host/integration/remote-home.d.ts +0 -69
  197. package/lib/types/src/host/integration/remote-index.d.ts +0 -165
  198. package/lib/types/src/host/integration/remote-job-tools.d.ts +0 -295
  199. package/lib/types/src/host/integration/remote-tool-backend.d.ts +0 -97
  200. package/lib/types/src/host/integration/remote-tools.d.ts +0 -206
  201. package/lib/types/src/host/integration/root-registry.d.ts +0 -115
  202. package/lib/types/src/host/integration/roots/anchor-directory.d.ts +0 -56
  203. package/lib/types/src/host/integration/roots/bin-root-resolver.d.ts +0 -81
  204. package/lib/types/src/host/integration/roots/remote-home.d.ts +0 -69
  205. package/lib/types/src/host/integration/roots/root-registry.d.ts +0 -144
  206. package/lib/types/src/host/integration/roots/roots-wiring.d.ts +0 -219
  207. package/lib/types/src/host/integration/roots/session-root-index.d.ts +0 -52
  208. package/lib/types/src/host/integration/roots-api.d.ts +0 -407
  209. package/lib/types/src/host/integration/roots-wiring.d.ts +0 -211
  210. package/lib/types/src/host/integration/session/session-api.d.ts +0 -88
  211. package/lib/types/src/host/integration/session/session-bin-lock.d.ts +0 -80
  212. package/lib/types/src/host/integration/session/session-header.d.ts +0 -151
  213. package/lib/types/src/host/integration/session/session-labels.d.ts +0 -56
  214. package/lib/types/src/host/integration/session/session-route-wiring.d.ts +0 -50
  215. package/lib/types/src/host/integration/session-admin-service.d.ts +0 -236
  216. package/lib/types/src/host/integration/session-api.d.ts +0 -81
  217. package/lib/types/src/host/integration/session-bin-lock.d.ts +0 -80
  218. package/lib/types/src/host/integration/session-header.d.ts +0 -118
  219. package/lib/types/src/host/integration/session-labels.d.ts +0 -56
  220. package/lib/types/src/host/integration/session-route-wiring.d.ts +0 -50
  221. package/lib/types/src/host/integration/session-scope.d.ts +0 -113
  222. package/lib/types/src/host/integration/session-tools.d.ts +0 -44
  223. package/lib/types/src/host/integration/strict-arguments.d.ts +0 -79
  224. package/lib/types/src/host/integration/takeover/takeover-api.d.ts +0 -62
  225. package/lib/types/src/host/integration/takeover/takeover-route-wiring.d.ts +0 -60
  226. package/lib/types/src/host/integration/takeover/takeover-service.d.ts +0 -167
  227. package/lib/types/src/host/integration/terminal-manifest.d.ts +0 -94
  228. package/lib/types/src/host/integration/tools/management-tools.d.ts +0 -245
  229. package/lib/types/src/host/integration/tools/remote-job-tools.d.ts +0 -316
  230. package/lib/types/src/host/integration/tools/remote-lsp-tools.d.ts +0 -43
  231. package/lib/types/src/host/integration/tools/remote-tools.d.ts +0 -236
  232. package/lib/types/src/host/integration/tools/session-target.d.ts +0 -52
  233. package/lib/types/src/host/integration/tools/session-tools.d.ts +0 -46
  234. package/lib/types/src/host/integration/tools/strict-arguments.d.ts +0 -79
  235. package/lib/types/src/host/integration/tools/terminal-manifest.d.ts +0 -94
  236. package/lib/types/src/host/integration/transfer/remote-copy.d.ts +0 -66
  237. package/lib/types/src/host/integration/transfer/transfer-adapters.d.ts +0 -48
  238. package/lib/types/src/host/integration/transfer/transfer-tracker.d.ts +0 -106
  239. package/lib/types/src/host/integration/transfer-adapters.d.ts +0 -44
  240. package/lib/types/src/host/integration/transfer-service.d.ts +0 -164
  241. package/lib/types/src/host/integration/transfer-tracker.d.ts +0 -106
  242. package/lib/types/src/host/integration/user-roots.d.ts +0 -461
  243. package/lib/types/src/wiring/connections.d.ts +0 -189
  244. package/lib/types/src/wiring/fs.d.ts +0 -13
  245. package/lib/types/src/wiring/install-memo.d.ts +0 -32
  246. package/lib/types/src/wiring/legacy-dirs.d.ts +0 -62
  247. package/lib/types/src/wiring/package-paths.d.ts +0 -35
  248. package/lib/types/src/wiring/roots.d.ts +0 -21
  249. package/lib/types/src/wiring/state-dir.d.ts +0 -29
  250. package/lib/types/src/wiring/tools.d.ts +0 -35
@@ -1,164 +0,0 @@
1
- /**
2
- * The controls the three surfaces share, as plain `createElement` templates.
3
- *
4
- * **No hooks, on purpose.** `:hover`, `:active`, `:focus-visible` and `:disabled` come from the stylesheet in
5
- * [`styles.ts`](./styles.ts) via class names, because a component holding `useState` cannot be rendered by
6
- * this repository's tests: they call the section functions **directly**, outside any React render, where a
7
- * hook throws `Invalid hook call`. Classes keep the templates pure element trees — a test walks the returned
8
- * tree and reads the same `type` / `name` / `disabled` / `role` it always did — while the browser still gets
9
- * real interaction states.
10
- *
11
- * These are deliberately **not** the platform's `dsh-client-ui-primitives` atoms: those factories import
12
- * per-component CSS modules, which a third-party bundle cannot supply (the loader materialises only
13
- * registered factories), and the package is not a dependency of this repository. `styles.ts` carries the
14
- * tokens those atoms are built from.
15
- *
16
- * @module dsh-over-ssh/client/controls
17
- */
18
- import { type ChangeEvent, type ReactNode } from 'react';
19
- /** The sizes a control may have. */
20
- export type ControlSize = 'normal' | 'compact';
21
- /** The visual weight of a button. */
22
- export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'row' | 'chip';
23
- /** Props every control shares: extra classes from the caller. */
24
- export interface ControlClassProps {
25
- /** Extra classes from the caller; appended after the vocabulary's own. */
26
- readonly className?: string;
27
- }
28
- /**
29
- * The part of a keyboard event a card's Esc handler reads.
30
- *
31
- * Structural, so the pure templates need no DOM types and a test drives the handler with a plain object. It is
32
- * assignable from React's `KeyboardEvent` (which carries both members), and it is the whole reason a dialog
33
- * closes on Esc: the shell focuses into the card when it opens, so the event reaches the card's own handler.
34
- */
35
- export interface KeyEventLike {
36
- /** The key name, e.g. `'Escape'`. */
37
- readonly key?: string;
38
- /** Stop the platform's own Esc handling from also firing while the dialog is up. */
39
- stopPropagation?(): void;
40
- }
41
- /** True when the event is the Esc key. */
42
- export declare function isEscape(event: KeyEventLike): boolean;
43
- /**
44
- * One button.
45
- *
46
- * @param props - the button's own props plus the variants this plugin uses.
47
- * @returns the button element.
48
- */
49
- export declare function Button(props: ControlClassProps & {
50
- readonly variant: ButtonVariant;
51
- readonly size?: ControlSize;
52
- readonly type?: 'button' | 'submit';
53
- readonly disabled?: boolean;
54
- readonly name?: string;
55
- readonly title?: string;
56
- /** The name a screen reader reads instead of the visible text, when the text alone is not a name. */
57
- readonly ariaLabel?: string;
58
- /** For a control that opens something: whether it is open right now (`aria-expanded`). */
59
- readonly ariaExpanded?: boolean;
60
- /** What the control opens (`aria-haspopup`). */
61
- readonly ariaHaspopup?: 'dialog' | 'menu';
62
- readonly onClick?: () => void;
63
- readonly children?: ReactNode;
64
- }): ReactNode;
65
- /** Props of a text input, narrowed to what the templates pass. */
66
- export interface TextInputProps extends ControlClassProps {
67
- readonly id: string;
68
- readonly name: string;
69
- readonly value: string;
70
- readonly disabled?: boolean;
71
- readonly placeholder?: string;
72
- readonly inputMode?: 'numeric';
73
- /** `password` for a secret field: the browser masks it and no autofill offers to save it. */
74
- readonly type?: 'text' | 'password';
75
- readonly autoComplete?: 'off' | 'new-password';
76
- readonly size?: ControlSize;
77
- readonly onChange: (event: ChangeEvent<HTMLInputElement>) => void;
78
- }
79
- /**
80
- * One text input, with the platform's border, inset surface and focus ring.
81
- *
82
- * @param props - the input's own props.
83
- * @returns the input element.
84
- */
85
- export declare function TextInput(props: TextInputProps): ReactNode;
86
- /** One option of a {@link Select}. */
87
- export interface SelectOption {
88
- readonly value: string;
89
- readonly label: string;
90
- }
91
- /**
92
- * A `<select>` over a fixed list of options.
93
- *
94
- * @param props - id, name, the current value, the options and the change handler.
95
- * @returns the select element.
96
- */
97
- export declare function Select(props: ControlClassProps & {
98
- readonly id: string;
99
- readonly name: string;
100
- readonly value: string;
101
- readonly options: readonly SelectOption[];
102
- readonly disabled?: boolean;
103
- readonly size?: ControlSize;
104
- readonly onChange: (value: string) => void;
105
- }): ReactNode;
106
- /**
107
- * A labelled field: the caption above its control, so the column and its label move together.
108
- *
109
- * @param props - the label text, the control's id and the control itself.
110
- * @returns the labelled column.
111
- */
112
- export declare function Field(props: {
113
- readonly label: string;
114
- readonly htmlFor: string;
115
- readonly children: ReactNode;
116
- }): ReactNode;
117
- /**
118
- * An inline notice block: the surface for a refusal, a host warning or "no host data".
119
- *
120
- * Three tones, and the split is deliberate: **`warn` is the default** (something the operator may need to act
121
- * on), `info` is a neutral status, and `error` is a hard failure. Before this, a failed read and a soft
122
- * warning rendered identically — both `role: 'alert'` on the amber surface — so "the host refused" and
123
- * "the host is telling you something" looked the same. A failure is not a warning.
124
- *
125
- * @param props - the tone, the role, and the text.
126
- * @returns the notice element carrying the role its caller needs (`alert` / `note` / `status`).
127
- */
128
- export declare function Notice(props: {
129
- readonly role: 'alert' | 'note' | 'status';
130
- readonly tone?: 'warn' | 'info' | 'error';
131
- readonly children: ReactNode;
132
- }): ReactNode;
133
- /**
134
- * A checkbox whose whole row is the hit target.
135
- *
136
- * The templates used to render a bare `<input type="checkbox">`: the stylesheet had **no rule for it at all**,
137
- * so it kept the browser's default size and accent colour, and — in the session inventory — it sat next to a
138
- * body that was not a `<label>`, so clicking the row's own text did nothing and the target was a 16px square.
139
- *
140
- * `id`/`name` are optional because the two call sites differ: the ssh-config list already pairs the box with a
141
- * separate `<label htmlFor>` naming the alias, while the session row wants the box and its body wrapped
142
- * together. Passing neither is allowed; passing `id` makes the input addressable by a sibling label.
143
- *
144
- * @param props - the box's identity, state and handler.
145
- * @returns the input element.
146
- */
147
- export declare function Checkbox(props: {
148
- readonly checked: boolean;
149
- readonly disabled?: boolean;
150
- readonly id?: string;
151
- readonly name?: string;
152
- readonly onChange: () => void;
153
- /** The accessible name, when no `<label>` wraps or names this box. */
154
- readonly ariaLabel?: string;
155
- }): ReactNode;
156
- /**
157
- * The status dot of a connection row, so the row's state is not carried by colour alone.
158
- *
159
- * @param props - the dot's accessible description.
160
- * @returns the dot element.
161
- */
162
- export declare function StatusDot(props: {
163
- readonly label: string;
164
- }): ReactNode;
@@ -1,48 +0,0 @@
1
- /**
2
- * The "only the newest answer may land" gate.
3
- *
4
- * Why a module instead of a `let token = 0` in each caller: this repository's client tests **cannot render a
5
- * React component** (no `react-dom`, see [`portal.ts`](./portal.ts)), so a generation counter written inside a
6
- * component's `useCallback` is a decision no test can reach. Extracting it makes "a late answer is dropped"
7
- * something a test can hold on to, which is the same reason `actionQueryKey` / `rootsQueryKey` /
8
- * long-poll re-arms exist.
9
- *
10
- * The three call sites share one failure mode: two requests are in flight, the **older** one answers last, and
11
- * its answer overwrites the newer state. That is not a theoretical race here — every one of these surfaces has
12
- * a button that starts a second request while the first is still open (a refresh during an action, a re-read
13
- * after a scope change, a poll racing a manual refresh).
14
- *
15
- * ```text
16
- * const gate = createLatestOnly();
17
- * const mine = gate.begin();
18
- * const answer = await call();
19
- * if (!gate.isCurrent(mine)) return; // a newer request owns the surface now
20
- * ```
21
- *
22
- * @module dsh-over-ssh/client/latest
23
- */
24
- /** A monotonic gate that admits only the most recently issued request. */
25
- export interface LatestOnly {
26
- /**
27
- * Issue a new request id.
28
- *
29
- * @returns the id this request must present when it answers.
30
- */
31
- begin(): number;
32
- /**
33
- * Whether an issued id is still the newest.
34
- *
35
- * @param token - the id `begin` returned to the request that is answering.
36
- * @returns `true` only for the newest id; every earlier one is stale.
37
- */
38
- isCurrent(token: number): boolean;
39
- }
40
- /**
41
- * Build a gate.
42
- *
43
- * Ids start at 1, so `0` (a value a caller can get from an uninitialised variable) is never "current" by
44
- * accident.
45
- *
46
- * @returns the gate.
47
- */
48
- export declare function createLatestOnly(): LatestOnly;
@@ -1,38 +0,0 @@
1
- /**
2
- * Client-half copy for the `over-ssh` namespace.
3
- *
4
- * Registration is the **typed** form of `ctx.locale.register`: the namespace is merged into
5
- * `LocaleNamespaceMap`, so a missing key in either shipped locale is a compile error, and the runtime
6
- * additionally requires both locales at registration (bilingual balance). Keeping the dictionaries in a
7
- * pure module is what makes them testable without a browser.
8
- *
9
- * @module dsh-over-ssh/client/locale
10
- */
11
- /** Namespace owned by this plugin's client half. */
12
- export declare const OVER_SSH_NS = "over-ssh";
13
- /**
14
- * Keys of this namespace.
15
- *
16
- * `LocaleNamespaceMap` maps a namespace to its **key union** (not to a value interface): the runtime then
17
- * derives `Record<Key, string>` per locale, which is exactly what makes a missing translation a compile
18
- * error.
19
- */
20
- export type OverSshKey = 'sectionTitle' | 'sectionDescription' | 'noHostData'
21
- /** The connection list's own heading / empty state / unknown-transport badge (audit ui P2-6, P2-7). */
22
- | 'connectionsHeading' | 'connectionsEmpty' | 'connectionsTransportUnknown' | 'close' | 'rootsTitle' | 'rootsDescription' | 'rootsAdvancedSummary' | 'rootsAdvancedNote' | 'rootsEmpty' | 'rootsPending' | 'rootsAuthPassword' | 'rootsPasswordLabel' | 'rootsTestConnection' | 'rootsTesting' | 'rootsTestOk' | 'sessionPanelTitle' | 'sessionPanelDescription' | 'sessionPanelUnavailable' | 'sessionPanelLoading' | 'sessionPanelLoadFailed' | 'sessionPanelSessionsEmpty' | 'sessionPanelSessions' | 'sessionPanelBin' | 'sessionPanelBinEmpty' | 'sessionPanelSelectAll' | 'sessionPanelClear' | 'sessionPanelDeleteRecycle' | 'sessionPanelDeletePermanent' | 'sessionPanelRestore' | 'sessionPanelPurge' | 'sessionPanelSweep' | 'sessionPanelRefresh' | 'sessionPanelClose' | 'sessionPanelLive' | 'sessionPanelSubsession' | 'sessionPanelUnreadable' | 'sessionPanelConfirmTitle' | 'sessionPanelConfirmBody' | 'sessionPanelConfirmPurgeBody' | 'sessionPanelConfirmCancel' | 'sessionPanelConfirmAccept' | 'sessionPanelDeleteWorkspace' | 'sessionPanelConfirmWorkspaceBody' | 'sessionPanelSubsessionsHidden' | 'sessionPanelTotals' | 'sessionPanelOpen' | 'sessionPanelLiveWarning' | 'sessionRowRecycle' | 'sessionRowDelete' | 'sessionRowRecycleBody' | 'sessionRowDeleteBody' | 'sessionRowConfirmRecycle' | 'sessionRowConfirmDelete' | 'sessionRowCancel' | 'sessionRowClose' | 'sessionRowLoading' | 'sessionRowBlockedRunning' | 'sessionRowBlockedSubsession' | 'sessionRowBlockedUnreadable' | 'sessionRowMissing' | 'sessionRowUnavailable' | 'rootsTestDegraded' | 'rootsTestFailed' | 'rootsAddConnection' | 'rootsRemove' | 'rootsSave' | 'rootsEdit' | 'rootsEditTitle' | 'rootsEditSave' | 'rootsEditCancel' | 'rootsEditPasswordHint' | 'rootsEditRenameHint' | 'rootsConfirmRemoveTitle' | 'rootsConfirmRemoveBody' | 'rootsConfirmRemoveAccept' | 'rootsConfirmRemoveCancel' | 'rootsConnection' | 'rootsConnectionPlaceholder' | 'rootsRemotePathLabel' | 'rootsIdLabel' | 'rootsHostLabel' | 'rootsUserLabel' | 'rootsAuthLabel' | 'rootsAuthKey' | 'rootsKeyPathLabel' | 'rootsPortLabel' | 'rootsBadgeLocal' | 'rootsBadgeRemote' | 'rootsErrorPathRequired' | 'rootsErrorRemotePath' | 'rootsErrorConnectionRequired' | 'rootsErrorLocalPath' | 'rootsErrorDuplicate' | 'rootsErrorIdRequired' | 'rootsErrorIdInvalid' | 'rootsErrorIdDuplicate' | 'rootsErrorHostRequired' | 'rootsErrorUserRequired' | 'rootsErrorPort' | 'rootsImportTitle' | 'rootsImportDescription' | 'rootsImportOpen' | 'rootsImportEmpty' | 'rootsImportRefresh' | 'rootsImportSelectAll' | 'rootsImportClear' | 'rootsImportAccept' | 'rootsImportCancel' | 'rootsImportBusy' | 'rootsImportDone' | 'rootsImportIdHint' | 'rootsImportSkippedTitle' | 'rootsImportSkipWildcard' | 'rootsImportSkipDuplicate' | 'rootsImportSkipTaken' | 'rootsImportSkipUnusableId' | 'rootsImportSkipNotImportable' | 'rootsImportSkipUnknown' | 'rootsImportHasKey' | 'rootsImportHasJump' | 'transferTitle' | 'transferDescription' | 'transferEmpty' | 'transferLoading' | 'transferRefresh' | 'transferClear' | 'transferFailedTitle' | 'transferDone' | 'transferCancelled' | 'transferUploadLabel' | 'transferDownloadLabel' | 'transferFailed' | 'transferFailedHttp' | 'transferFailedHost' | 'transferFailureLine' | 'transferErrorCodeUnknown' | 'remoteFilesHint' | 'rootsImportFailed' | 'rootsErrorKeyPathRequired' | 'rootsErrorPasswordRequired' | 'rootsNoticeUnavailable' | 'rootsNoticeWarnings' | 'rootsNoticeSavedConnection' | 'rootsNoticeSavedEdit' | 'flowTitle' | 'flowDescription' | 'flowLocalHeading' | 'flowLocalHint' | 'flowPickFailed' | 'flowRemoteHeading' | 'flowRemoteHint' | 'flowConfirmRemote' | 'flowCancel' | 'flowPending' | 'flowBusy' | 'flowNoConnections' | 'flowConnectionsLoading' | 'flowNoAnchor' | 'flowUnavailable' | 'browseHeading' | 'browseUp' | 'browseHome' | 'browseCurrent' | 'browseEmpty' | 'browseLoading' | 'browseRetry' | 'browseFailed' | 'browseUnavailable' | 'browseNeedConnection' | 'browseTruncated'
23
- /** The remote world's connection list: reading, and failed-with-reason (audit 2026-11-01b ui P2-4). */
24
- | 'browseConnectionsLoading' | 'browseConnectionsFailed' | 'browseKindFile' | 'browseKindSymlink' | 'browseKindOther' | 'browseLocalMode' | 'browsePickNative' | 'browseRemoteMode' | 'browseOpenLocal' | 'browseOpenRemote' | 'browseChoose' | 'sessionAddOpen' | 'sessionAddTitle' | 'sessionAddHint' | 'sessionAddWorkspace' | 'sessionAddWorkspaceUnknown' | 'sessionAddPick' | 'sessionBrowse' | 'sessionBrowseBack' | 'sessionRootsTitle' | 'sessionRootsEmpty'
25
- /** The session entry's card while it reads its directory list (the empty state must not be shown then). */
26
- | 'sessionRootsLoading' | 'sessionRootsHint' | 'sessionRootsFailed' | 'sessionAddDone' | 'sessionAddFailed' | 'sessionResultNoSelection' | 'sessionResultMissingCwd' | 'sessionResultMissingEntryId' | 'sessionResultHttpFailed' | 'sessionResultHostRefused' | 'sessionResultActionFailed' | 'sessionResultUnreachable' | 'sessionResultDeletedPermanent' | 'sessionResultDeleteNone' | 'sessionResultRecycled' | 'sessionResultWorkspaceEmpty' | 'sessionResultWorkspacePurged' | 'sessionResultWorkspacePurgedRefused' | 'sessionResultWorkspaceRecycled' | 'sessionResultWorkspaceRecycledRefused' | 'sessionResultRestored' | 'sessionResultPurged' | 'sessionResultSweepNone' | 'sessionResultSweepDone' | 'sessionWorkspaceUnknown' | 'connectionTestNoAnswer' | 'connectionTestFailed' | 'connectionTestRefused'
27
- /** The probe ran out of the client's own deadline (no host sentence exists for it). */
28
- | 'connectionTestTimeout' | 'transferSummaryRunning' | 'transferSummaryDone' | 'transferRemaining' | 'transferRemainingUnknown' | 'transferDurationUnknown' | 'rootsImportSummary' | 'rootsImportRefusedTitle' | 'rootsImportRefusedLine';
29
- /** Merge this plugin's namespace into the shared locale map, so `t('over-ssh.…')` is typed. */
30
- declare module '@deepseek-ai/dsh-client-ui-slots' {
31
- interface LocaleNamespaceMap {
32
- 'over-ssh': OverSshKey;
33
- }
34
- }
35
- /** Every shipped locale's dictionary. Both `zh` and `en` are required by the runtime. */
36
- export declare const OVER_SSH_DICTS: Record<'zh' | 'en', Record<OverSshKey, string>>;
37
- /** Dictionary keys, so a completeness test never has to restate them. */
38
- export declare function overSshKeys(): readonly OverSshKey[];
@@ -1,37 +0,0 @@
1
- /**
2
- * Deferred copy: a dictionary key plus its parameters, and the one resolver for it.
3
- *
4
- * Why this is `core/` and not `roots/`: three modules need the same two lines — the roots panel model, the
5
- * transfer panel and (since the audit) the session panel's result sentences — and two of them are **pure
6
- * models** that must not import React. `roots/roots-panel-state.ts` used to own the resolver, which meant every
7
- * pure model either imported a React-bearing module or (what actually happened) duplicated the six lines with a
8
- * comment apologising for the duplication (`core/panel-model.ts`). One implementation, no React.
9
- *
10
- * The contract a dictionary keeps: a **missing** key renders as the key itself. That is deliberate — a missing
11
- * translation must be visible in the UI, never silently blank (see `roots-panel-state.ts`'s original note).
12
- *
13
- * @module dsh-over-ssh/client/message
14
- */
15
- /** A message is a key plus its parameters; a component resolves it against the active dictionary. */
16
- export interface MessageKey {
17
- /** The dictionary key (an entry of `OverSshKey` for this plugin's own copy). */
18
- readonly key: string;
19
- /** Values for the template's `{name}` placeholders. */
20
- readonly params?: Readonly<Record<string, string | number>>;
21
- }
22
- /**
23
- * Substitute `{name}` placeholders in one template.
24
- *
25
- * @param template - the dictionary string.
26
- * @param params - the values to substitute; an absent value leaves the placeholder in place.
27
- * @returns the rendered text.
28
- */
29
- export declare function resolveTemplate(template: string, params: Readonly<Record<string, string | number>> | undefined): string;
30
- /**
31
- * Resolve one message against a dictionary.
32
- *
33
- * @param copy - the active locale's dictionary (a plain string map).
34
- * @param message - the key plus optional parameters.
35
- * @returns the rendered text, or `message.key` itself when the dictionary has no such key.
36
- */
37
- export declare function resolveMessage(copy: Readonly<Record<string, string>>, message: MessageKey): string;
@@ -1,134 +0,0 @@
1
- /**
2
- * The settings panel's pure logic and copy wiring.
3
- *
4
- * Two rules that keep a client component testable without a browser:
5
- *
6
- * - **no `ctx` in components** (the platform contract): everything a component shows arrives through props;
7
- * - consequently all decision-making lives here, where Node can run it. The component is a template.
8
- *
9
- * The host data channel arrives as **untrusted wire data** (`unknown`), so the conversion below whitelists
10
- * fields one by one: a leaked `keyPath` / `password` / `credentialKey` cannot reach the panel even if the host
11
- * ever started sending one. That is the client half's half of the "no credentials over the channel" rule the
12
- * host face also enforces.
13
- *
14
- * @module dsh-over-ssh/client/panel-model
15
- */
16
- import type { OverSshKey } from './locale.ts';
17
- /**
18
- * Transports a connection row can name; `unknown` means "the host did not say".
19
- *
20
- * Declared once, in the roots model the wire parser lives in, and re-exported here so both halves of the panel
21
- * vocabulary agree (a second identical union is how `unknown` ended up rendered as a raw English word).
22
- */
23
- /**
24
- * How a connection reaches the host: `alias`/`ssh2` are Tier 1 (no agent), `agent` is Tier 2, `unknown` is
25
- * "the host did not say".
26
- *
27
- * Defined **here**, in `core`, and re-exported by `roots/roots-panel.ts`, not the other way round: the
28
- * dependency rule for this half is `core → roots → session → flows → entry`, and importing it from `roots`
29
- * was a reverse edge that `tests/architecture.test.ts` caught (the panel model is what a caller without the
30
- * editor imports, so it must not reach into a feature folder for a type it owns).
31
- */
32
- export type ConnectionTransport = 'alias' | 'ssh2' | 'agent' | 'unknown';
33
- /** One connection line: what the user needs to know about a single saved connection. */
34
- export interface ConnectionRow {
35
- /** Connection id (the profile key the user sees in `ssh://` paths). */
36
- readonly id: string;
37
- /** Host name as configured. */
38
- readonly host: string;
39
- /** Transport currently in force, or `unknown` before the first connection. */
40
- readonly transport: ConnectionTransport;
41
- /** Whether the current transport is a degraded substitute. */
42
- readonly degraded: boolean;
43
- /** Why: the degradation reason, else the decision's explanation, else "not connected yet". */
44
- readonly note: string;
45
- /**
46
- * The row's badge text, already localized by whoever built the row.
47
- *
48
- * The template used to render {@link ConnectionRow.transport} raw, so every row carried a badge reading the
49
- * English wire word `unknown` in the Chinese UI as well. `alias`/`ssh2`/`agent` are protocol names and stay as
50
- * they are; only the "the host did not say" case needs a word, and it now arrives from the dictionary
51
- * (audit 2026-11-01b ui P2-6).
52
- */
53
- readonly transportLabel?: string;
54
- /**
55
- * The 「测试」 button's state for this row, already localized; absent when the panel has no tester.
56
- *
57
- * The template stays copy-free (`panel.ts` renders text it is handed), and the strings are rebuilt on every
58
- * re-registration, so a locale change re-renders them without any subscription here.
59
- */
60
- readonly test?: {
61
- readonly status: 'idle' | 'running' | 'ok' | 'failed';
62
- /** Button label: 「测试」, or 「测试中…」 while the probe runs. */
63
- readonly label: string;
64
- /** Result line; empty while running. */
65
- readonly detail: string;
66
- };
67
- /**
68
- * The row's own edit/delete labels, already localized; absent when the panel has no editor.
69
- *
70
- * Localized here rather than in the component for the same reason as {@link ConnectionRow.test}: the
71
- * template renders strings it is handed and never looks up copy itself.
72
- */
73
- readonly actions?: {
74
- readonly editLabel: string;
75
- readonly removeLabel: string;
76
- };
77
- }
78
- /** What the panel renders. */
79
- export interface PanelModel {
80
- readonly title: string;
81
- readonly description: string;
82
- /** One line per connection; empty either before the host answered or when no connection is configured. */
83
- readonly connections: readonly ConnectionRow[];
84
- /** Heading of the connection list (it had none: the rows started right under the description). */
85
- readonly connectionsHeading: string;
86
- /** What an answered-but-empty list says (it used to render nothing at all). */
87
- readonly connectionsEmpty: string;
88
- /**
89
- * Notice about the missing host data channel; empty once the host answered. An answered-but-empty list
90
- * clears it too — "you configured no connection" and "the channel is not wired" are different facts, and
91
- * the panel must not claim the second one when the first is true.
92
- */
93
- readonly notice: string;
94
- readonly closeLabel: string;
95
- /**
96
- * The confirmation card's text for deleting one connection, or absent when the panel cannot delete.
97
- *
98
- * A function of the row because the sentence names the connection **and** how many remote roots go with it
99
- * - the fact that makes the confirmation necessary at all.
100
- */
101
- readonly confirmRemove?: {
102
- readonly title: string;
103
- readonly cancelLabel: string;
104
- readonly acceptLabel: string;
105
- readonly body: (row: ConnectionRow, remoteRoots: number) => string;
106
- };
107
- }
108
- /**
109
- * Convert the host's connection status payload into panel rows.
110
- *
111
- * Every field is read individually and type-checked; unknown fields (including any credential the host might
112
- * ever add) are dropped rather than forwarded. A row without a usable `id` and `host` is skipped: an
113
- * unidentifiable line is worse than a missing one.
114
- *
115
- * @param value - the remote call's value, exactly as it arrived over the wire.
116
- * @returns the rows the panel may render, in the host's order.
117
- */
118
- export declare function toConnectionRows(value: unknown): readonly ConnectionRow[];
119
- /**
120
- * Build the panel model from one locale's dictionary.
121
- *
122
- * @param copy - the dictionary the caller resolved (`zh` or `en`, chosen by the locale runtime).
123
- * @param options - `rows` are the connection lines the host channel produced; **omitted** means the channel
124
- * never answered, which is the only case that shows the notice.
125
- * @returns everything the component needs, with no further lookups.
126
- */
127
- export declare function buildPanelModel(copy: Record<OverSshKey, string>, options?: {
128
- readonly rows?: readonly ConnectionRow[];
129
- /**
130
- * Whether the panel has an editor behind it. When true, rows carry their edit/delete labels and the model
131
- * carries the removal confirmation; when false (the default) the page is read-only.
132
- */
133
- readonly editable?: boolean;
134
- }): PanelModel;