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,415 +0,0 @@
1
- /**
2
- * The **session entry**: add a directory to the workspace the current session is in, without leaving the
3
- * conversation and **without creating a workspace**.
4
- *
5
- * What the user asked for: "不要在设置中加,不方便" (adding directories through the settings page is
6
- * inconvenient), and the directory-flow hole is no answer to it either - that hole's owner
7
- * (`ui-workspace`) adopts a picked path by calling `createWorkspace({ path })`, which **creates a new
8
- * workspace**. This entry is the other shape: it registers the directory as one of this plugin's roots
9
- * (the same `/api/over-ssh/roots` action the settings panel uses), and nothing else. The root is
10
- * live immediately, so the session that is already open - and every other one - can read and write under
11
- * it through the router. No workspace is created, no session is moved.
12
- *
13
- * Where it lives: `conversation.input.left`, a `list`-kind, session-scoped hole in the composer tool row
14
- * ("compact controls at the left of the composer tool row"). It is the only one of the four candidate
15
- * holes that is **inside the conversation**: the two `sidebar.workspaces.session.*` holes are row actions
16
- * of the sidebar list (they hand out a `sessionId`, not the composer), and `conversation.input.right` sits
17
- * next to the submit button, where a mis-click costs more than it saves. `ctx.slots.inject` is used rather
18
- * than a bare `register`, because the hole belongs to `ui-conversation` and may be declared after this
19
- * plugin (a bare register into an undeclared slot **throws** and would take the settings section down with
20
- * it), and the registration re-runs on `locale/change` for the same reason the other two surfaces do.
21
- *
22
- * Where "the current workspace" comes from: the framework hands every session-scoped occupant a
23
- * `sessionId` seat plus the `useSessions` / `useWorkspaces` selector hooks. The session's `cwd` comes from
24
- * the session list; when that seat is absent the workspace containing the session is looked up by
25
- * `sessionIds` instead. **Neither is guaranteed**: a composition without those packages hands out neither, and
26
- * then the entry says so in the panel (`sessionAddWorkspaceUnknown`) and **refuses to add anything** — every
27
- * root this card can list is scoped to a workspace, so with no workspace there is nothing to scope one to. It
28
- * used to write an unscoped root "which is in effect for every session anyway"; that sentence was wrong twice
29
- * over (audit 0056): unscoped roots are listed by no session, and the tool layer resolves by cwd/anchor rather
30
- * than by workspace, so "in effect for every session" was never something the list could promise. The entry
31
- * never guesses a path.
32
- *
33
- * The card is **portalled** through `./portal.ts`, exactly like the directory-flow dialog: a container on
34
- * `document.body` while the card is up. The composer tool row is a flex row this plugin does not own, and a
35
- * `position: fixed` card *inside* it would still be re-anchored by any ancestor with a `transform` or
36
- * `contain`; from `body` there is no such ancestor to worry about. The trigger stays where it is, so closing
37
- * hands focus back to it (it is whatever held focus before the card opened).
38
- *
39
- * **Unverified** (see `doc/02-platform/workspace-directory-flow.md`): the portal has not been looked at in a
40
- * real GUI.
41
- *
42
- * @module dsh-over-ssh/client/session-directory
43
- */
44
- import { type ReactNode } from 'react';
45
- import { type DirectoryBrowserIo } from './directory-browser.ts';
46
- import type { OverSshKey } from '../core/locale.ts';
47
- import { type CardPortalTarget } from '../core/portal.ts';
48
- import { type ApiResult, type FetchLike, type MessageKey, type RootRow } from '../roots/roots-panel.ts';
49
- import { type RootsPanelCopy } from '../roots/roots-panel-view.ts';
50
- /** The hole this entry fills: a `list`-kind, session-scoped seat at the left of the composer tool row. */
51
- export declare const SESSION_DIRECTORY_SLOT = "conversation.input.left";
52
- /**
53
- * The hole's declaration, mirrored.
54
- *
55
- * `@deepseek-ai/dsh-client-ui-conversation` declares this key (and its `session` scope) but is **not** a
56
- * dependency of this repository, while the registration below has to type-check here. The shape is quoted
57
- * from `packages/client/ui-conversation/src/client/contract/slots.ts`:
58
- * `'conversation.input.left': { kind: 'list'; scope: 'session' }`.
59
- */
60
- declare module '@deepseek-ai/dsh-client-ui-slots' {
61
- interface SlotMap {
62
- /** Compact controls at the left of the composer tool row. */
63
- 'conversation.input.left': {
64
- kind: 'list';
65
- scope: 'session';
66
- };
67
- }
68
- }
69
- /** Stable entry id, so a locale-driven re-registration replaces the same row instead of adding a second. */
70
- export declare const SESSION_DIRECTORY_ID = "over-ssh-add-directory";
71
- /** Placement among the shipped composer controls (the platform uses 100-steps). */
72
- export declare const SESSION_DIRECTORY_ORDER = 200;
73
- /**
74
- * Classes of the body-level container this entry's card is portalled into: the floating shell
75
- * (`CLASS.portal`) plus this surface's own name (`CLASS.portalComposer`). Both placements now centre the card
76
- * in the window; the class distinguishes the surface, not the geometry (see `styles.ts`).
77
- */
78
- export declare const SESSION_DIRECTORY_PORTAL_CLASS: string;
79
- /**
80
- * The card's click sink: the composer entry sits in the conversation and its dialog is modal, so pointer input has
81
- * to stop at the card (audit 2026-11-01b ui P2-1).
82
- */
83
- export declare const SESSION_DIRECTORY_BACKDROP_CLASS: "dsh-rw-backdrop";
84
- /** One root as this entry adds it. Local roots carry no connection; remote ones must. */
85
- export interface SessionDirectoryRootDraft {
86
- readonly location: 'local' | 'remote';
87
- readonly path: string;
88
- readonly connectionId?: string;
89
- /** The workspace this directory is added to; the card lists only roots that carry it. */
90
- readonly workspaces?: readonly string[];
91
- /** The conversation this directory is added to — the strict scope (ADR-0013). */
92
- readonly sessions?: readonly string[];
93
- }
94
- /** The calls this entry makes: the browser's three plus the one write. */
95
- export interface SessionDirectoryIo extends DirectoryBrowserIo {
96
- /**
97
- * Register one root and answer the **anchor path** the host computed, when it reports one.
98
- *
99
- * The anchor is not needed here (this entry creates no workspace) but it is what the host answers, and
100
- * dropping it would make this call diverge from the settings panel's for no gain.
101
- */
102
- addRoot(draft: SessionDirectoryRootDraft): Promise<ApiResult<{
103
- readonly anchorPath?: string;
104
- }>>;
105
- /** The plugin's roots as the route reports them (narrowed locally; no credential field survives). */
106
- loadRoots(workspacePath: string | undefined, sessionId?: string): Promise<ApiResult<readonly RootRow[]>>;
107
- /**
108
- * Drop one root from **this** workspace.
109
- *
110
- * `workspaces` is a union on the add side, so a root can be listed by several workspaces; removing it from
111
- * one must not take it from the others. The host removes the root itself only when the last workspace drops
112
- * it (the global delete, which the settings panel performs, omits `workspace`).
113
- */
114
- removeRoot(key: string, workspacePath?: string, sessionId?: string): Promise<ApiResult<unknown>>;
115
- /**
116
- * 宿主系统的原生目录选择框;`null` 表示用户取消,缺席表示这个组合没有这个能力。
117
- *
118
- * 可选:没有它时对话框照旧用内置浏览器,只是少一颗「浏览…」按钮。
119
- */
120
- pickLocal?: (() => Promise<string | null>) | undefined;
121
- }
122
- /**
123
- * Bind the entry's calls to this plugin's route.
124
- *
125
- * @param options - `fetch` (same-origin in the app) and a route override for tests.
126
- * @returns the calls the entry uses.
127
- */
128
- export declare function createSessionDirectoryIo(options: {
129
- readonly fetchImpl: FetchLike;
130
- readonly path?: string;
131
- /** 原生目录选择框;见 {@link SessionDirectoryIo.pickLocal}。 */
132
- readonly pickLocal?: (() => Promise<string | null>) | undefined;
133
- }): SessionDirectoryIo;
134
- /** Everything the entry renders from. */
135
- export interface SessionDirectoryState {
136
- /** True while the floating card is up. */
137
- readonly open: boolean;
138
- /** True while the add-root request is in flight. */
139
- readonly pending: boolean;
140
- /** The workspace the session is in, as the framework seats reported it; absent when unavailable. */
141
- readonly workspacePath?: string;
142
- /** The conversation this card acts for, when the platform handed one over (ADR-0013). */
143
- readonly sessionId?: string;
144
- /** The directory that was just added (the path the user chose). */
145
- readonly added?: string;
146
- /** The last refusal or failure. */
147
- readonly notice?: MessageKey;
148
- /** The plugin's roots as last read; empty until the first answer. */
149
- readonly roots: readonly RootRow[];
150
- /** True while a roots read or a removal is in flight. */
151
- readonly rootsPending: boolean;
152
- /**
153
- * True while the card is **reading** its roots list.
154
- *
155
- * Separate from {@link SessionDirectoryState.rootsPending}, which is the removal gate: the card used to render
156
- * 「还没有添加目录。点「浏览…」…」 during the first read, i.e. it claimed the list was empty before it had an
157
- * answer (audit 2026-11-01b ui P2-3).
158
- */
159
- readonly rootsReading: boolean;
160
- /** True while the browser **step** is open (the card shows the picker instead of its buttons). */
161
- readonly browsing: boolean;
162
- /** The root key being removed, so its own row can hold still. */
163
- readonly removing?: string;
164
- }
165
- /** What the reducer accepts. */
166
- export type SessionDirectoryAction = {
167
- readonly type: 'toggled';
168
- } | {
169
- readonly type: 'closed';
170
- } | {
171
- readonly type: 'workspace-known';
172
- readonly path?: string | undefined;
173
- } | {
174
- readonly type: 'session-known';
175
- readonly sessionId?: string | undefined;
176
- } | {
177
- readonly type: 'submitted';
178
- } | {
179
- readonly type: 'added';
180
- readonly path: string;
181
- } | {
182
- readonly type: 'refused';
183
- readonly message: MessageKey;
184
- } | {
185
- readonly type: 'failed';
186
- readonly reason: string;
187
- } | {
188
- readonly type: 'browse-toggled';
189
- }
190
- /** A roots read started; the list keeps what it had and the card may say "reading". */
191
- | {
192
- readonly type: 'roots-reading';
193
- } | {
194
- readonly type: 'roots-loaded';
195
- readonly roots: readonly RootRow[];
196
- } | {
197
- readonly type: 'roots-failed';
198
- readonly reason: string;
199
- } | {
200
- readonly type: 'root-removing';
201
- readonly key: string;
202
- } | {
203
- readonly type: 'root-removed';
204
- readonly key: string;
205
- };
206
- /** @returns the state a freshly mounted entry holds. */
207
- export declare function initialSessionDirectoryState(): SessionDirectoryState;
208
- /**
209
- * The entry's state machine. Pure: an action that changes nothing returns the **same object**.
210
- *
211
- * `workspace-known` is dispatched by the shell on every render (the seat can resolve later); it is a no-op
212
- * when the path has not moved, so the panel is not re-rendered by an unchanged fact.
213
- *
214
- * @param state - the current state.
215
- * @param action - what happened.
216
- * @returns the next state.
217
- */
218
- export declare function sessionDirectoryReducer(state: SessionDirectoryState, action: SessionDirectoryAction): SessionDirectoryState;
219
- /** The complete render input. */
220
- export interface SessionDirectoryView {
221
- /** True while the floating card is up. */
222
- readonly visible: boolean;
223
- /** True while the add-root request is in flight. */
224
- readonly pending: boolean;
225
- /** The workspace the session is in, or `undefined` when the seats could not answer. */
226
- readonly workspacePath?: string;
227
- /** The directory that was just added. */
228
- readonly added?: string;
229
- /** The refusal or failure text, resolved against the active dictionary. */
230
- readonly notice: string;
231
- /** The workspace line, resolved against the active dictionary. */
232
- readonly workspaceLine: string;
233
- /** The directories this session can use, ready to render. */
234
- readonly roots: readonly SessionRootRow[];
235
- /** True while the list is being read or a row is being removed. */
236
- readonly rootsPending: boolean;
237
- /** True while the list is being read (so the empty state must not be shown). */
238
- readonly rootsReading: boolean;
239
- /** True while the browser step is open. */
240
- readonly browsing: boolean;
241
- }
242
- /** One directory row of the session card; text is already localized. */
243
- export interface SessionRootRow {
244
- readonly key: string;
245
- readonly title: string;
246
- readonly subtitle: string;
247
- /** 「本地」/「远端」 — the one fact a path alone cannot state. */
248
- readonly badge: string;
249
- /** Only a root in the plugin's own file can be removed; a profile-declared one cannot. */
250
- readonly removable: boolean;
251
- }
252
- /**
253
- * Turn the state into render input, resolving the two dynamic lines through the active dictionary.
254
- *
255
- * @param state - the entry state.
256
- * @param copy - the dictionary of the active locale.
257
- * @returns the flags and the resolved text.
258
- */
259
- export declare function selectSessionDirectoryView(state: SessionDirectoryState, copy: RootsPanelCopy): SessionDirectoryView;
260
- /** What the controller needs. */
261
- export interface SessionDirectoryDeps {
262
- readonly io: SessionDirectoryIo;
263
- /** The dictionary of the active locale; a thunk, because the locale can change under a mounted entry. */
264
- readonly copy: () => RootsPanelCopy;
265
- }
266
- /** The calls the container makes. */
267
- export interface SessionDirectoryController {
268
- readonly getState: () => SessionDirectoryState;
269
- readonly subscribe: (listener: () => void) => () => void;
270
- /** Open or close the floating card. */
271
- readonly toggle: () => void;
272
- readonly close: () => void;
273
- /** Push the workspace the framework seats reported (or `undefined` when they could not). */
274
- readonly setWorkspacePath: (path: string | undefined) => void;
275
- /** Push the conversation this card acts for (ADR-0013), or `undefined` when the seat could not answer. */
276
- readonly setSessionId: (sessionId: string | undefined) => void;
277
- /** Validate and register the picked directory; the world comes from whether a connection was used. */
278
- readonly commit: (path: string, connectionId: string | undefined) => Promise<void>;
279
- /** Open or close the browser step. */
280
- readonly browse: () => void;
281
- /** Re-read the plugin's roots (on open, and after every change). */
282
- readonly refreshRoots: () => Promise<void>;
283
- /** Drop one root from this plugin's list. */
284
- readonly removeRoot: (key: string) => Promise<void>;
285
- /** Re-arm after a mount (React's development replay runs the cleanup once before the real lifetime). */
286
- readonly activate: () => void;
287
- readonly dispose: () => void;
288
- }
289
- /**
290
- * Build the stateful half of the entry.
291
- *
292
- * The write goes through `validateRootDraft` - the same authority the settings panel and the directory-flow
293
- * dialog use - so a local path that is not absolute, or a remote path with `..` in it, is refused here
294
- * before anything reaches the host. A `remote` pick without a connection is refused the same way.
295
- *
296
- * @param deps - the injected calls and the active dictionary.
297
- * @returns the controller the container subscribes to.
298
- */
299
- export declare function createSessionDirectory(deps: SessionDirectoryDeps): SessionDirectoryController;
300
- /** What the entry's controls call. */
301
- export interface SessionDirectorySectionActions {
302
- readonly onToggle: () => void;
303
- readonly onClose: () => void;
304
- /** Open or close the browser step. */
305
- readonly onBrowse: () => void;
306
- /** Drop one directory from this session's list. */
307
- readonly onRemoveRoot: (key: string) => void;
308
- }
309
- /** Props of the pure template: copy, state, callbacks and the browser the shell mounted (or `null` in tests). */
310
- export interface SessionDirectorySectionProps {
311
- readonly copy: RootsPanelCopy;
312
- readonly state: SessionDirectoryState;
313
- readonly actions: SessionDirectorySectionActions;
314
- /** The directory browser element, built by the container; `null` renders the card without one. */
315
- readonly browser?: ReactNode;
316
- /**
317
- * The body-level portal the card is mounted into. Absent renders the card **in place**, which is the
318
- * DOM-less degradation (SSR, a direct template call): a runtime without a document has no composer row to
319
- * escape either.
320
- */
321
- readonly portal?: CardPortalTarget | undefined;
322
- /**
323
- * `id` of the card's heading, referenced by `aria-labelledby`.
324
- *
325
- * **Required**, and supplied by the caller (`useId()` in the container). It used to default to a module-level
326
- * constant — one id for every mount — which is the shape the id audit (2026-10-31 client.md §2.4) is about.
327
- */
328
- readonly titleId: string;
329
- }
330
- /**
331
- * Render the session entry. Pure: calling it twice with the same props yields the same tree.
332
- *
333
- * @param props - copy, state, callbacks, the browser element, the portal and the heading's id.
334
- * @returns the trigger and, while open, the card (inside the portal when one is given).
335
- */
336
- export declare function SessionDirectorySection({ copy, state, actions, browser, portal, titleId, }: SessionDirectorySectionProps): ReactNode;
337
- /** The minimal shape of the session list snapshot this module reads (a structural mirror). */
338
- interface SessionListLike {
339
- readonly byId?: Readonly<Record<string, {
340
- readonly cwd?: string;
341
- } | undefined>>;
342
- }
343
- /** The minimal shape of the workspace snapshot this module reads (a structural mirror). */
344
- interface WorkspaceSnapshotLike {
345
- readonly items?: readonly {
346
- readonly path?: string;
347
- readonly sessionIds?: readonly string[];
348
- }[];
349
- }
350
- /**
351
- * One framework selector seat, as this module calls it.
352
- *
353
- * Structural on purpose: `useSessions` / `useWorkspaces` are merged into `GlobalStandardProps` by packages
354
- * that are **not** dependencies of this repository, so the seat is described by the one call this module
355
- * makes instead of imported.
356
- */
357
- export type SessionSeatHook<Snapshot> = (selector: (snapshot: Snapshot) => unknown) => unknown;
358
- /** Props of the React shell: the injected calls plus whatever seats the renderer handed this occurrence. */
359
- export interface SessionDirectoryContainerProps {
360
- /** The active locale's dictionary; the shell resolves its own dynamic keys through it. */
361
- readonly copy: RootsPanelCopy;
362
- /** The injected calls. Created once by the entry, never by the component. */
363
- readonly io: SessionDirectoryIo;
364
- /** Session identity (the `sessionId` seat of a session-scoped slot); absent without `ui-session`. */
365
- readonly sessionId?: string | undefined;
366
- /** The `useSessions` seat; absent without `ui-session`. */
367
- readonly useSessions?: SessionSeatHook<SessionListLike> | undefined;
368
- /** The `useWorkspaces` seat; absent without `ui-workspace`. */
369
- readonly useWorkspaces?: SessionSeatHook<WorkspaceSnapshotLike> | undefined;
370
- }
371
- /**
372
- * Read the current workspace path from whichever framework seat can answer.
373
- *
374
- * The session's own `cwd` is preferred (it is the directory the session actually runs in); the workspace
375
- * containing the session is the fallback, looked up by `sessionIds`. Both are `undefined` in a composition
376
- * that hands out neither seat, which the panel states rather than hides.
377
- *
378
- * Exported so the preference order and the fallback are asserted offline: the seats are plain callbacks, and
379
- * a test needs no renderer to drive them.
380
- *
381
- * @param props - the shell props carrying the seats.
382
- * @returns the workspace path, or `undefined`.
383
- */
384
- export declare function readWorkspacePath(props: SessionDirectoryContainerProps): string | undefined;
385
- /**
386
- * The identity of a roots read: which workspace the list is scoped to, or that the card is closed.
387
- *
388
- * A read is only valid for the workspace it was issued for, so this value is what decides **when a re-read is
389
- * owed**. It is a named pure function rather than a bare dependency array because this repository's tests do
390
- * not render hooks (`client-roots-view.test.ts` says why): an effect's dependency list cannot be executed by a
391
- * test, so the *decision* is extracted here where it can be. (A mutation that drops the dependency from the
392
- * effect used to leave every test green — found by the round-2 mutation experiment.)
393
- *
394
- * Why it matters: the seats that answer "which workspace is this session in" can answer **after** the card is
395
- * already open. Reading only on `open` made the first (unknown-workspace) answer final, so a late seat left the
396
- * list empty until the card was closed and reopened (audit 0056, review T3).
397
- *
398
- * @param state - the entry state.
399
- * @returns `closed` when the card is closed, otherwise a key that changes when the workspace does.
400
- */
401
- export declare function rootsQueryKey(state: SessionDirectoryState): string;
402
- /**
403
- * Subscribe to a per-mount entry and render {@link SessionDirectorySection}.
404
- *
405
- * The card is **portalled** (`./portal.ts`): one container per mount, attached to `document.body` while the
406
- * card is up and removed when it closes. The trigger alone stays in the composer row. Opening also moves focus
407
- * into the card and remembers the trigger, so Esc closes and closing hands focus back.
408
- *
409
- * @param props - the injected dictionary and calls plus the framework seats.
410
- * @returns the trigger and, while open, the card with its browser.
411
- */
412
- export declare function SessionDirectoryContainer(props: SessionDirectoryContainerProps): ReactNode;
413
- /** The dictionary keys this module renders, so a test can assert the two locales carry them. */
414
- export type SessionDirectoryKey = Extract<OverSshKey, 'sessionAddOpen' | 'sessionAddTitle' | 'sessionAddHint' | 'sessionAddWorkspace' | 'sessionAddWorkspaceUnknown' | 'sessionAddDone' | 'sessionAddFailed' | 'sessionAddPick' | 'sessionBrowse' | 'sessionBrowseBack' | 'sessionRootsTitle' | 'sessionRootsEmpty' | 'sessionRootsHint' | 'sessionRootsFailed' | 'rootsRemove' | 'close' | 'flowPending'>;
415
- export {};