dsh-over-ssh 0.0.0-stage → 0.1.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 (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -2
  3. package/agents/agent-manifest.json +20 -0
  4. package/agents/linux-amd64/dsh-over-ssh-agent +0 -0
  5. package/agents/linux-arm64/dsh-over-ssh-agent +0 -0
  6. package/cordis.patch.yml +84 -0
  7. package/lib/client.js +6611 -0
  8. package/lib/file-references.js +366 -0
  9. package/lib/fs.js +1368 -0
  10. package/lib/index.js +19034 -0
  11. package/lib/local-bridge-refs.js +16 -0
  12. package/lib/local-bridge.js +16 -0
  13. package/lib/terminal-wrapper.js +294 -0
  14. package/lib/types/src/client/controls.d.ts +131 -0
  15. package/lib/types/src/client/core/card-focus-trap.d.ts +45 -0
  16. package/lib/types/src/client/core/controls.d.ts +164 -0
  17. package/lib/types/src/client/core/latest.d.ts +48 -0
  18. package/lib/types/src/client/core/locale.d.ts +38 -0
  19. package/lib/types/src/client/core/message.d.ts +37 -0
  20. package/lib/types/src/client/core/panel-model.d.ts +134 -0
  21. package/lib/types/src/client/core/portal.d.ts +266 -0
  22. package/lib/types/src/client/core/remote.d.ts +84 -0
  23. package/lib/types/src/client/core/styles.d.ts +458 -0
  24. package/lib/types/src/client/file-tree-io.d.ts +19 -0
  25. package/lib/types/src/client/file-tree.d.ts +271 -0
  26. package/lib/types/src/client/flows/directory-browser.d.ts +587 -0
  27. package/lib/types/src/client/flows/session-directory.d.ts +415 -0
  28. package/lib/types/src/client/flows/workspace-directory-flow.d.ts +480 -0
  29. package/lib/types/src/client/index.d.ts +49 -0
  30. package/lib/types/src/client/locale.d.ts +31 -0
  31. package/lib/types/src/client/panel-model.d.ts +37 -0
  32. package/lib/types/src/client/panel.d.ts +77 -0
  33. package/lib/types/src/client/roots/connection-test.d.ts +69 -0
  34. package/lib/types/src/client/roots/roots-panel-state.d.ts +307 -0
  35. package/lib/types/src/client/roots/roots-panel-view.d.ts +280 -0
  36. package/lib/types/src/client/roots/roots-panel.d.ts +364 -0
  37. package/lib/types/src/client/roots/transfer-panel-view.d.ts +35 -0
  38. package/lib/types/src/client/roots/transfer-panel.d.ts +241 -0
  39. package/lib/types/src/client/roots/transfer-progress.d.ts +67 -0
  40. package/lib/types/src/client/roots-panel-view.d.ts +236 -0
  41. package/lib/types/src/client/roots-panel.d.ts +347 -0
  42. package/lib/types/src/client/session/session-panel-view.d.ts +336 -0
  43. package/lib/types/src/client/session/session-panel.d.ts +322 -0
  44. package/lib/types/src/client/session/session-remote-mark.d.ts +110 -0
  45. package/lib/types/src/client/session/session-row-actions.d.ts +398 -0
  46. package/lib/types/src/client/session-panel.d.ts +152 -0
  47. package/lib/types/src/client/styles.d.ts +252 -0
  48. package/lib/types/src/client/workspace-directory-flow.d.ts +342 -0
  49. package/lib/types/src/config.d.ts +312 -0
  50. package/lib/types/src/file-references.d.ts +25 -0
  51. package/lib/types/src/fs.d.ts +46 -0
  52. package/lib/types/src/host/app/backend.d.ts +170 -0
  53. package/lib/types/src/host/app/recycle-bin/recycle-bin-contract.d.ts +247 -0
  54. package/lib/types/src/host/app/recycle-bin/recycle-bin-move.d.ts +18 -0
  55. package/lib/types/src/host/app/recycle-bin/recycle-bin-service.d.ts +45 -0
  56. package/lib/types/src/host/app/recycle-bin/recycle-bin-world.d.ts +38 -0
  57. package/lib/types/src/host/app/recycle-bin-contract.d.ts +215 -0
  58. package/lib/types/src/host/app/recycle-bin-move.d.ts +18 -0
  59. package/lib/types/src/host/app/recycle-bin-service.d.ts +45 -0
  60. package/lib/types/src/host/app/recycle-bin-world.d.ts +35 -0
  61. package/lib/types/src/host/app/roots/roots-api-connections.d.ts +49 -0
  62. package/lib/types/src/host/app/roots/roots-api-contract.d.ts +369 -0
  63. package/lib/types/src/host/app/roots/roots-api-directories.d.ts +13 -0
  64. package/lib/types/src/host/app/roots/roots-api-http.d.ts +77 -0
  65. package/lib/types/src/host/app/roots/roots-api-long-poll.d.ts +130 -0
  66. package/lib/types/src/host/app/roots/roots-api-projections.d.ts +102 -0
  67. package/lib/types/src/host/app/roots/roots-api-roots.d.ts +13 -0
  68. package/lib/types/src/host/app/roots/roots-api-state.d.ts +22 -0
  69. package/lib/types/src/host/app/roots/roots-api-transfers.d.ts +26 -0
  70. package/lib/types/src/host/app/roots/roots-api.d.ts +55 -0
  71. package/lib/types/src/host/app/roots/user-roots.d.ts +552 -0
  72. package/lib/types/src/host/app/roots-api-connections.d.ts +49 -0
  73. package/lib/types/src/host/app/roots-api-contract.d.ts +339 -0
  74. package/lib/types/src/host/app/roots-api-directories.d.ts +13 -0
  75. package/lib/types/src/host/app/roots-api-http.d.ts +77 -0
  76. package/lib/types/src/host/app/roots-api-projections.d.ts +102 -0
  77. package/lib/types/src/host/app/roots-api-roots.d.ts +13 -0
  78. package/lib/types/src/host/app/roots-api-state.d.ts +22 -0
  79. package/lib/types/src/host/app/roots-api-support.d.ts +182 -0
  80. package/lib/types/src/host/app/roots-api-transfers.d.ts +13 -0
  81. package/lib/types/src/host/app/roots-api.d.ts +55 -0
  82. package/lib/types/src/host/app/routed-fs.d.ts +239 -0
  83. package/lib/types/src/host/app/serialize.d.ts +37 -0
  84. package/lib/types/src/host/app/session-admin/session-admin-context.d.ts +36 -0
  85. package/lib/types/src/host/app/session-admin/session-admin-contract.d.ts +221 -0
  86. package/lib/types/src/host/app/session-admin/session-admin-delete.d.ts +34 -0
  87. package/lib/types/src/host/app/session-admin/session-admin-service.d.ts +40 -0
  88. package/lib/types/src/host/app/session-admin-context.d.ts +36 -0
  89. package/lib/types/src/host/app/session-admin-contract.d.ts +214 -0
  90. package/lib/types/src/host/app/session-admin-delete.d.ts +34 -0
  91. package/lib/types/src/host/app/session-admin-service.d.ts +38 -0
  92. package/lib/types/src/host/app/takeover/takeover-plan.d.ts +227 -0
  93. package/lib/types/src/host/app/takeover/takeover-rows.d.ts +55 -0
  94. package/lib/types/src/host/app/transport/transport-selector.d.ts +98 -0
  95. package/lib/types/src/host/app/transport/transport-service.d.ts +82 -0
  96. package/lib/types/src/host/app/transport-selector.d.ts +98 -0
  97. package/lib/types/src/host/app/transport-service.d.ts +75 -0
  98. package/lib/types/src/host/app/user-roots.d.ts +461 -0
  99. package/lib/types/src/host/domain/bin-location.d.ts +79 -0
  100. package/lib/types/src/host/domain/capability.d.ts +78 -0
  101. package/lib/types/src/host/domain/connection.d.ts +95 -0
  102. package/lib/types/src/host/domain/errors.d.ts +55 -0
  103. package/lib/types/src/host/domain/glob-pattern.d.ts +62 -0
  104. package/lib/types/src/host/domain/literal-text.d.ts +63 -0
  105. package/lib/types/src/host/domain/path-grammar.d.ts +84 -0
  106. package/lib/types/src/host/domain/recycle-bin.d.ts +337 -0
  107. package/lib/types/src/host/domain/root.d.ts +74 -0
  108. package/lib/types/src/host/domain/roots/bin-location.d.ts +91 -0
  109. package/lib/types/src/host/domain/roots/connection.d.ts +106 -0
  110. package/lib/types/src/host/domain/roots/root.d.ts +108 -0
  111. package/lib/types/src/host/domain/roots/route-table.d.ts +102 -0
  112. package/lib/types/src/host/domain/roots/session-roots.d.ts +151 -0
  113. package/lib/types/src/host/domain/roots/ssh-config.d.ts +73 -0
  114. package/lib/types/src/host/domain/route-table.d.ts +80 -0
  115. package/lib/types/src/host/domain/session/session-admin.d.ts +345 -0
  116. package/lib/types/src/host/domain/session/terminal-target.d.ts +136 -0
  117. package/lib/types/src/host/domain/session-admin.d.ts +330 -0
  118. package/lib/types/src/host/domain/shell.d.ts +47 -0
  119. package/lib/types/src/host/domain/ssh-config.d.ts +73 -0
  120. package/lib/types/src/host/domain/terminal-target.d.ts +132 -0
  121. package/lib/types/src/host/domain/tool-requests.d.ts +369 -0
  122. package/lib/types/src/host/domain/transfer/recycle-bin.d.ts +337 -0
  123. package/lib/types/src/host/domain/transfer/transfer.d.ts +260 -0
  124. package/lib/types/src/host/domain/transfer.d.ts +260 -0
  125. package/lib/types/src/host/infra/backend/local-backend.d.ts +84 -0
  126. package/lib/types/src/host/infra/backend/local-version.d.ts +43 -0
  127. package/lib/types/src/host/infra/backend/platform-local-backend.d.ts +89 -0
  128. package/lib/types/src/host/infra/backend/remote-backend.d.ts +239 -0
  129. package/lib/types/src/host/infra/cache/lru.d.ts +52 -0
  130. package/lib/types/src/host/infra/cache/versioned.d.ts +77 -0
  131. package/lib/types/src/host/infra/temp-name.d.ts +19 -0
  132. package/lib/types/src/host/infra/transport/agent/agent-installer.d.ts +121 -0
  133. package/lib/types/src/host/infra/transport/agent/agent-protocol-client.d.ts +132 -0
  134. package/lib/types/src/host/infra/transport/agent/agent-protocol-codec.d.ts +140 -0
  135. package/lib/types/src/host/infra/transport/agent/agent-protocol-errors.d.ts +41 -0
  136. package/lib/types/src/host/infra/transport/agent/agent-protocol-frames.d.ts +197 -0
  137. package/lib/types/src/host/infra/transport/agent/agent-protocol-types.d.ts +564 -0
  138. package/lib/types/src/host/infra/transport/agent/agent-transport.d.ts +418 -0
  139. package/lib/types/src/host/infra/transport/agent-installer.d.ts +121 -0
  140. package/lib/types/src/host/infra/transport/agent-protocol-client.d.ts +123 -0
  141. package/lib/types/src/host/infra/transport/agent-protocol-codec.d.ts +131 -0
  142. package/lib/types/src/host/infra/transport/agent-protocol-errors.d.ts +41 -0
  143. package/lib/types/src/host/infra/transport/agent-protocol-frames.d.ts +197 -0
  144. package/lib/types/src/host/infra/transport/agent-protocol-types.d.ts +509 -0
  145. package/lib/types/src/host/infra/transport/agent-transport.d.ts +353 -0
  146. package/lib/types/src/host/infra/transport/alias-transport.d.ts +206 -0
  147. package/lib/types/src/host/infra/transport/askpass-fs.d.ts +20 -0
  148. package/lib/types/src/host/infra/transport/askpass.d.ts +133 -0
  149. package/lib/types/src/host/infra/transport/command-pool.d.ts +61 -0
  150. package/lib/types/src/host/infra/transport/fs-commands.d.ts +140 -0
  151. package/lib/types/src/host/infra/transport/git-status-route.d.ts +63 -0
  152. package/lib/types/src/host/infra/transport/git-status.d.ts +101 -0
  153. package/lib/types/src/host/infra/transport/node-spawn.d.ts +26 -0
  154. package/lib/types/src/host/infra/transport/session-window.d.ts +51 -0
  155. package/lib/types/src/host/infra/transport/shell-quote.d.ts +59 -0
  156. package/lib/types/src/host/infra/transport/ssh/alias-transport.d.ts +206 -0
  157. package/lib/types/src/host/infra/transport/ssh/askpass-fs.d.ts +20 -0
  158. package/lib/types/src/host/infra/transport/ssh/askpass.d.ts +133 -0
  159. package/lib/types/src/host/infra/transport/ssh/shell-quote.d.ts +62 -0
  160. package/lib/types/src/host/infra/transport/ssh/ssh-argv.d.ts +43 -0
  161. package/lib/types/src/host/infra/transport/ssh/ssh2-transport.d.ts +328 -0
  162. package/lib/types/src/host/infra/transport/ssh-argv.d.ts +43 -0
  163. package/lib/types/src/host/infra/transport/ssh2-transport.d.ts +302 -0
  164. package/lib/types/src/host/infra/transport/transport-base.d.ts +34 -0
  165. package/lib/types/src/host/infra/transport/transport.d.ts +527 -0
  166. package/lib/types/src/host/integration/agent/agent-install-io.d.ts +33 -0
  167. package/lib/types/src/host/integration/agent/agent-preflight.d.ts +56 -0
  168. package/lib/types/src/host/integration/agent/askpass-registry.d.ts +66 -0
  169. package/lib/types/src/host/integration/agent-install-io.d.ts +33 -0
  170. package/lib/types/src/host/integration/agent-preflight.d.ts +56 -0
  171. package/lib/types/src/host/integration/anchor-directory.d.ts +56 -0
  172. package/lib/types/src/host/integration/askpass-registry.d.ts +59 -0
  173. package/lib/types/src/host/integration/bin-root-resolver.d.ts +81 -0
  174. package/lib/types/src/host/integration/connection-test.d.ts +73 -0
  175. package/lib/types/src/host/integration/file-reference-provider.d.ts +115 -0
  176. package/lib/types/src/host/integration/fs/file-reference-provider.d.ts +142 -0
  177. package/lib/types/src/host/integration/fs/fs-provider.d.ts +368 -0
  178. package/lib/types/src/host/integration/fs/git-status-wiring.d.ts +21 -0
  179. package/lib/types/src/host/integration/fs/platform-errors.d.ts +94 -0
  180. package/lib/types/src/host/integration/fs/remote-file-tools.d.ts +369 -0
  181. package/lib/types/src/host/integration/fs/remote-index.d.ts +177 -0
  182. package/lib/types/src/host/integration/fs-provider.d.ts +226 -0
  183. package/lib/types/src/host/integration/lsp/lsp-framing.d.ts +38 -0
  184. package/lib/types/src/host/integration/lsp/lsp-registry.d.ts +67 -0
  185. package/lib/types/src/host/integration/lsp/lsp-session.d.ts +130 -0
  186. package/lib/types/src/host/integration/management-tools.d.ts +64 -0
  187. package/lib/types/src/host/integration/recycle-bin-service.d.ts +247 -0
  188. package/lib/types/src/host/integration/remote/connection-test.d.ts +73 -0
  189. package/lib/types/src/host/integration/remote/remote-face.d.ts +127 -0
  190. package/lib/types/src/host/integration/remote/remote-tool-backend.d.ts +108 -0
  191. package/lib/types/src/host/integration/remote-face.d.ts +127 -0
  192. package/lib/types/src/host/integration/remote-file-tools.d.ts +241 -0
  193. package/lib/types/src/host/integration/remote-home.d.ts +69 -0
  194. package/lib/types/src/host/integration/remote-index.d.ts +165 -0
  195. package/lib/types/src/host/integration/remote-job-tools.d.ts +295 -0
  196. package/lib/types/src/host/integration/remote-tool-backend.d.ts +97 -0
  197. package/lib/types/src/host/integration/remote-tools.d.ts +206 -0
  198. package/lib/types/src/host/integration/root-registry.d.ts +115 -0
  199. package/lib/types/src/host/integration/roots/anchor-directory.d.ts +56 -0
  200. package/lib/types/src/host/integration/roots/bin-root-resolver.d.ts +81 -0
  201. package/lib/types/src/host/integration/roots/remote-home.d.ts +69 -0
  202. package/lib/types/src/host/integration/roots/root-registry.d.ts +144 -0
  203. package/lib/types/src/host/integration/roots/roots-wiring.d.ts +219 -0
  204. package/lib/types/src/host/integration/roots/session-root-index.d.ts +52 -0
  205. package/lib/types/src/host/integration/roots-api.d.ts +407 -0
  206. package/lib/types/src/host/integration/roots-wiring.d.ts +211 -0
  207. package/lib/types/src/host/integration/session/session-api.d.ts +88 -0
  208. package/lib/types/src/host/integration/session/session-bin-lock.d.ts +80 -0
  209. package/lib/types/src/host/integration/session/session-header.d.ts +151 -0
  210. package/lib/types/src/host/integration/session/session-labels.d.ts +56 -0
  211. package/lib/types/src/host/integration/session/session-route-wiring.d.ts +50 -0
  212. package/lib/types/src/host/integration/session-admin-service.d.ts +236 -0
  213. package/lib/types/src/host/integration/session-api.d.ts +81 -0
  214. package/lib/types/src/host/integration/session-bin-lock.d.ts +80 -0
  215. package/lib/types/src/host/integration/session-header.d.ts +118 -0
  216. package/lib/types/src/host/integration/session-labels.d.ts +56 -0
  217. package/lib/types/src/host/integration/session-route-wiring.d.ts +50 -0
  218. package/lib/types/src/host/integration/session-scope.d.ts +113 -0
  219. package/lib/types/src/host/integration/session-tools.d.ts +44 -0
  220. package/lib/types/src/host/integration/strict-arguments.d.ts +79 -0
  221. package/lib/types/src/host/integration/takeover/takeover-api.d.ts +62 -0
  222. package/lib/types/src/host/integration/takeover/takeover-route-wiring.d.ts +60 -0
  223. package/lib/types/src/host/integration/takeover/takeover-service.d.ts +167 -0
  224. package/lib/types/src/host/integration/terminal-manifest.d.ts +94 -0
  225. package/lib/types/src/host/integration/tools/management-tools.d.ts +245 -0
  226. package/lib/types/src/host/integration/tools/remote-job-tools.d.ts +316 -0
  227. package/lib/types/src/host/integration/tools/remote-lsp-tools.d.ts +43 -0
  228. package/lib/types/src/host/integration/tools/remote-tools.d.ts +236 -0
  229. package/lib/types/src/host/integration/tools/session-target.d.ts +52 -0
  230. package/lib/types/src/host/integration/tools/session-tools.d.ts +46 -0
  231. package/lib/types/src/host/integration/tools/strict-arguments.d.ts +79 -0
  232. package/lib/types/src/host/integration/tools/terminal-manifest.d.ts +94 -0
  233. package/lib/types/src/host/integration/transfer/remote-copy.d.ts +66 -0
  234. package/lib/types/src/host/integration/transfer/transfer-adapters.d.ts +48 -0
  235. package/lib/types/src/host/integration/transfer/transfer-service.d.ts +212 -0
  236. package/lib/types/src/host/integration/transfer/transfer-tracker.d.ts +106 -0
  237. package/lib/types/src/host/integration/transfer-adapters.d.ts +44 -0
  238. package/lib/types/src/host/integration/transfer-service.d.ts +164 -0
  239. package/lib/types/src/host/integration/transfer-tracker.d.ts +106 -0
  240. package/lib/types/src/host/integration/user-roots.d.ts +461 -0
  241. package/lib/types/src/index.d.ts +66 -0
  242. package/lib/types/src/local-bridge-refs.d.ts +26 -0
  243. package/lib/types/src/local-bridge.d.ts +36 -0
  244. package/lib/types/src/shared/format.d.ts +13 -0
  245. package/lib/types/src/wiring/connections.d.ts +189 -0
  246. package/lib/types/src/wiring/fs.d.ts +13 -0
  247. package/lib/types/src/wiring/helpers.d.ts +144 -0
  248. package/lib/types/src/wiring/install-memo.d.ts +32 -0
  249. package/lib/types/src/wiring/legacy-dirs.d.ts +62 -0
  250. package/lib/types/src/wiring/package-paths.d.ts +35 -0
  251. package/lib/types/src/wiring/roots.d.ts +21 -0
  252. package/lib/types/src/wiring/state-dir.d.ts +29 -0
  253. package/lib/types/src/wiring/tools.d.ts +35 -0
  254. package/package.json +120 -4
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Wire the panel's HTTP route to the live roots, the live connections and the persisted panel state.
3
+ *
4
+ * This module is the seam the API handler and the registry never see each other through: the handler is pure
5
+ * request/response (see {@link createRootsApi}), the registry owns live routing, and this file is the only
6
+ * place that knows both. It exists as its own module so the wiring is one small, reviewable call in the entry
7
+ * rather than twenty lines inside it.
8
+ *
9
+ * Two behaviours worth stating:
10
+ *
11
+ * - **Startup merge**: roots and connections the panel wrote survive a restart because they are read back
12
+ * from `user-roots.json` and applied to the live side at load. A file that cannot be applied is reported as
13
+ * a warning, never as a load failure: losing the panel's extra roots must not stop the plugin.
14
+ * - **Same-origin only**: the route is registered on the browser carrier (`ctx.webServer`). When that service
15
+ * is absent (a headless profile), the plugin still works and simply has no panel data channel — the reason
16
+ * is logged instead of thrown.
17
+ *
18
+ * @module dsh-over-ssh/host/integration/roots-wiring
19
+ */
20
+ import { type CredentialsSeam, type RemoteFileOperations, type TransferReport, type RootsApi } from '../../app/roots/roots-api.ts';
21
+ import { type UserConnectionRecord, type UserRootEntry, type UserRootsIo, type UserRootsStore } from '../../app/roots/user-roots.ts';
22
+ /** The browser HTTP carrier the host exposes; only the one method this wiring needs. */
23
+ export interface RootsRouteHost {
24
+ register(route: {
25
+ readonly kind: 'exact';
26
+ readonly path: string;
27
+ readonly handler: (req: never, res: never) => Promise<void>;
28
+ }): () => void;
29
+ }
30
+ /**
31
+ * Deferred carrier: run `callback` once `webServer` is **available**, and again whenever it comes back.
32
+ *
33
+ * `ctx.inject` is the platform's documented way to depend on a service that a later composition layer
34
+ * provides (`dsh-client-connection` does exactly this for the `/api` route). A bare `ctx.get('webServer')`
35
+ * at activation time is **not** equivalent: measured on the packaged 0.2.0-rc.2 runtime
36
+ * (`dsh --profile web`, `ctx.get('webServer') === undefined`, `'webServer' in ctx === false`) while
37
+ * `ctx.get('tools')` was already an object — the carrier row is constructed after the plugin entries
38
+ * activate. With `ctx.get` the route was never registered, the shell's `dsh-app://app/api/…` proxy fell
39
+ * through to the SPA fallback, and the panel reported `http-404` while the plugin looked healthy.
40
+ *
41
+ * `scoped.get` is typed `unknown` and narrowed by {@link asRootsRouteHost} rather than declared as the
42
+ * carrier type: this module stays clear of `@deepseek-ai/*` types (红线 2), and a cordis `Context` is
43
+ * structurally richer than this one-method seam, so the narrower declaration would reject the real `ctx`.
44
+ */
45
+ export interface RootsRouteHostProvider {
46
+ inject(names: readonly string[], callback: (scoped: {
47
+ get(name: string): unknown;
48
+ }) => void | (() => void)): unknown;
49
+ }
50
+ /** Why a route could not be registered; both variants are warnings, never activation failures. */
51
+ export type RootsRouteWarning =
52
+ /** No `webServer` service ever appeared (a headless composition): the panel has no data channel. */
53
+ {
54
+ readonly kind: 'no-carrier';
55
+ }
56
+ /** The carrier refused the registration, e.g. a duplicate `(kind, path)` pair. */
57
+ | {
58
+ readonly kind: 'refused';
59
+ readonly reason: string;
60
+ };
61
+ /** Everything the wiring needs from the entry. */
62
+ export interface RootsWiringDeps {
63
+ /** Plugin state directory; `user-roots.json` lives inside it. */
64
+ readonly stateDir: string;
65
+ /**
66
+ * Optional: the directory remote roots' local anchors live under.
67
+ *
68
+ * Passed through to the `GET` snapshot as `anchorRoot`: a client uses it to recognise a session whose cwd
69
+ * is a remote workspace, which is otherwise indistinguishable from a local folder (the shell has no
70
+ * per-workspace icon and no workspace-row slot). Absent means the snapshot simply omits it.
71
+ */
72
+ readonly anchorRootDir?: string | undefined;
73
+ /** Live roots (the registry's records). */
74
+ readonly listRoots: () => readonly unknown[];
75
+ /** Live connections (the entry's profiles). */
76
+ readonly listConnections: () => readonly unknown[];
77
+ /** Make a root live and routable. */
78
+ /**
79
+ * Make a root live. **Awaitable**: registering a remote root also creates its local anchor directory, and the
80
+ * panel hands that path straight to the platform's `createWorkspace`, which resolves it with `realpath`.
81
+ */
82
+ readonly registerRoot: (entry: UserRootEntry) => Promise<void> | void;
83
+ /** Drop a root from the live side. */
84
+ readonly unregisterRoot: (key: string) => void;
85
+ /** Make a connection usable without a restart. */
86
+ readonly applyConnection: (entry: UserConnectionRecord, previousId: string) => void;
87
+ /**
88
+ * Forget a deleted connection on the live side: its profile, and everything cached per connection.
89
+ *
90
+ * Required, not optional: the `GET` answer lists connections from the live side, so a wiring that omitted this
91
+ * would keep answering with a connection the user deleted (see `RootsApiDeps.removeConnection`). Making it
92
+ * required means the compiler — not a reviewer — notices a wiring that forgot it.
93
+ */
94
+ readonly removeConnection: (id: string) => void;
95
+ /**
96
+ * Optional: list one directory on a connection (names and kinds only), for the `list-remote` action.
97
+ *
98
+ * Passed through to the handler untouched: this wiring knows nothing about transports, and a composition
99
+ * without it simply answers that action with an explicit failure.
100
+ */
101
+ readonly listRemoteDirectory?: ((input: {
102
+ readonly connectionId: string;
103
+ readonly path: string;
104
+ }) => Promise<readonly unknown[]> | readonly unknown[]) | undefined;
105
+ /**
106
+ * Optional: the directory a remote browse starts at when the client names no path.
107
+ *
108
+ * The same pass-through as {@link RootsWiringDeps.listRemoteDirectory}, and the same reason to have it: the
109
+ * start directory is the remote login user's home, which only the transport can answer (an account may live
110
+ * under `/home`, `/home1`, …). A composition without it degrades to `/`, the pre-existing behaviour.
111
+ */
112
+ readonly remoteHomeDirectory?: ((connectionId: string) => Promise<string> | string) | undefined;
113
+ /**
114
+ * Optional: list one directory **on this machine** (names and kinds only), for the `list-local` action.
115
+ *
116
+ * The same pass-through as {@link RootsWiringDeps.listRemoteDirectory}, and the same reason to have it: a
117
+ * profile whose platform directory picker offers only the native dialog (no `browse` capability) still gets
118
+ * a working browser from the host, which always has `node:fs`. A composition that does not provide it
119
+ * answers that action with an explicit failure rather than pretending the directory is empty.
120
+ */
121
+ readonly listLocalDirectory?: ((input: {
122
+ readonly path: string;
123
+ }) => Promise<readonly unknown[]> | readonly unknown[]) | undefined;
124
+ /**
125
+ * Optional: the text of the user's own `~/.ssh/config`, for the import flow (FR-2.1.4).
126
+ *
127
+ * The same pass-through as the directory seams, and the same reason: this wiring reads no files, and the
128
+ * handler wants **text** so the parsing stays a pure function under test. Absent means the import actions
129
+ * answer an explicit failure.
130
+ */
131
+ readonly readSshConfig?: (() => Promise<string | undefined> | string | undefined) | undefined;
132
+ /**
133
+ * Optional: the mutating remote-file operations the file tree needs (FR-2.2.2).
134
+ *
135
+ * The same pass-through as the other seams: this wiring resolves nothing itself. Absent means those actions
136
+ * answer an explicit refusal.
137
+ */
138
+ readonly remoteFiles?: RemoteFileOperations | undefined;
139
+ /**
140
+ * Optional: the in-flight and recent transfers (FR-2.6.4).
141
+ *
142
+ * The same pass-through as the other seams. Absent means the transfer actions answer an explicit refusal.
143
+ */
144
+ readonly transfers?: TransferReport | undefined;
145
+ /**
146
+ * Optional: the credential store, read **per request** (a getter, not a value — see `RootsApiDeps`).
147
+ *
148
+ * Absent in a composition with no credentials service: password connections are then refused with an
149
+ * explicit 400 instead of being written into a file that is documented to hold no secrets.
150
+ */
151
+ readonly readCredentials?: (() => CredentialsSeam | undefined) | undefined;
152
+ /** Optional: really connect to one saved connection (the panel's 「测试」 button). */
153
+ readonly testConnection?: ((id: string) => Promise<unknown> | unknown) | undefined;
154
+ /** Optional: the deferred `ctx.webServer` carrier. Absent in a headless profile. */
155
+ readonly webServerProvider?: RootsRouteHostProvider | undefined;
156
+ /** Optional file-system binding for the store; tests inject an in-memory one (红线 3). */
157
+ readonly io?: UserRootsIo | undefined;
158
+ }
159
+ /** What the entry holds on to. */
160
+ export interface RootsWiring {
161
+ readonly api: RootsApi;
162
+ readonly store: UserRootsStore;
163
+ /** Apply everything the panel persisted, so UI edits survive a restart. */
164
+ mergeUserRoots(): Promise<{
165
+ readonly roots: number;
166
+ readonly connections: number;
167
+ readonly warnings: readonly string[];
168
+ }>;
169
+ /**
170
+ * Human-readable warnings collected while trying to own the route: an absent carrier, or one that
171
+ * refused the registration. Exposed so the entry can log them **after** activation, when `ctx.logger`
172
+ * itself resolves (it is undefined at activation time, the same ordering fact this file works around).
173
+ */
174
+ readonly routeWarnings: () => readonly string[];
175
+ /**
176
+ * The route's own facts, for the entry's one-line diagnostic.
177
+ *
178
+ * `injectRan` and `routeRegistered` are the two facts nothing else can answer: the first says whether the
179
+ * deferred carrier callback ever executed (a callback that never ran means `webServer` never appeared),
180
+ * the second whether the carrier actually accepted the route. Both are read **after** activation, on the
181
+ * next tick, because at activation time neither can be true yet on the packaged runtime.
182
+ */
183
+ readonly routeFacts: () => RootsRouteFacts;
184
+ readonly dispose: () => void;
185
+ }
186
+ /** What the wiring knows about its own route attempt; the rest of the diagnostic comes from the entry. */
187
+ export interface RootsRouteFacts {
188
+ /** True once the deferred carrier callback ran at least once. */
189
+ readonly injectRan: boolean;
190
+ /** True when the route is currently registered on a carrier. */
191
+ readonly routeRegistered: boolean;
192
+ /** The warnings collected so far, in order. */
193
+ readonly warnings: readonly string[];
194
+ }
195
+ /**
196
+ * The one-line diagnostic the entry logs when the route is still missing after the next tick.
197
+ *
198
+ * **Why this exists**: the panel's failure mode is `http-404`, and a 404 alone cannot tell "the carrier
199
+ * refused the route" from "the carrier never appeared" from "the plugin never asked". Each of those has a
200
+ * different fix, so the line carries the four facts that separate them - whether the `ctx.inject`
201
+ * callback ran, whether `'webServer' in ctx` is true on the entry's own context, what `ctx.get('tools')`
202
+ * resolved to (a non-undefined service proves the context itself is live), and the warnings registered so
203
+ * far - with the warnings inline, so a single log line is enough to act on.
204
+ *
205
+ * @param facts - the wiring's own facts plus the two the entry samples from its context.
206
+ * @returns one structured line, safe for any logger.
207
+ */
208
+ export declare function rootsRouteDiagnostic(facts: RootsRouteFacts & {
209
+ readonly hasWebServerProperty: boolean;
210
+ readonly toolsType: string;
211
+ }): string;
212
+ /**
213
+ * Build the wiring and register the route when a carrier exists.
214
+ *
215
+ * @param deps - live roots, live connections and the persist location.
216
+ * @returns the wiring; call {@link RootsWiring.dispose} on unload to release the route.
217
+ */
218
+ export declare function createRootsWiring(deps: RootsWiringDeps): RootsWiring;
219
+ //# sourceMappingURL=roots-wiring.d.ts.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * A cached read of `user-roots.json`, answering "which remote directories did this session add?".
3
+ *
4
+ * `resolveSessionRoot` runs on **every** remote tool call, so it must not touch the disk each time: a tool call
5
+ * is latency the user feels, and the file only changes when the user acts on the panel. The cache is
6
+ * therefore bounded by time, not by events — there is no change hook on the persisted file, and inventing one
7
+ * would couple the tool surface to the panel's writer.
8
+ *
9
+ * Two properties worth naming:
10
+ *
11
+ * - **A read failure never breaks a tool call.** A missing file (a fresh profile) answers "no session roots";
12
+ * a malformed one does too. The user's fallback is the old `ROOT_OUTSIDE` message, which is exactly what
13
+ * they got before this feature existed — strictly better than a tool that throws because a JSON file is
14
+ * being rewritten at that instant.
15
+ * - **The rule itself is not here.** Selection lives in `domain/roots/session-roots.ts` (pure, offline
16
+ * tested); this module only decides *when* to re-read and hands the parsed entries over.
17
+ *
18
+ * @module dsh-over-ssh/integration/roots/session-root-index
19
+ */
20
+ import { type SessionIdentity, type SessionRootOutcome } from '../../domain/roots/session-roots.ts';
21
+ /** What the index needs. */
22
+ export interface SessionRootIndexDeps {
23
+ /** Absolute path of `user-roots.json`. */
24
+ readonly filePath: string;
25
+ /** Read one file as UTF-8; injected so tests need no disk. */
26
+ readonly readFile: (path: string, encoding: 'utf8') => Promise<string>;
27
+ /** How long a parsed answer stays usable (milliseconds). */
28
+ readonly ttlMs: number;
29
+ /** Clock, injected so a test can advance it without sleeping. */
30
+ readonly now?: (() => number) | undefined;
31
+ }
32
+ /** The seam the tool backend consumes. */
33
+ export interface SessionRootIndex {
34
+ /**
35
+ * Which remote root this session may target when its cwd names none.
36
+ *
37
+ * @param workspacePath - the session's cwd.
38
+ * @param identity - the session identity, when the platform could supply one (ADR-0013).
39
+ * @returns the rule's outcome; `none` also covers "the file could not be read".
40
+ */
41
+ outcomeFor(workspacePath: string, identity?: SessionIdentity): SessionRootOutcome;
42
+ /** Drop the cache (a panel write, or a test asserting a fresh read). */
43
+ invalidate(): void;
44
+ }
45
+ /**
46
+ * Build the cached index.
47
+ *
48
+ * @param deps - file path, reader, TTL, clock.
49
+ * @returns the index.
50
+ */
51
+ export declare function createSessionRootIndex(deps: SessionRootIndexDeps): SessionRootIndex;
52
+ //# sourceMappingURL=session-root-index.d.ts.map