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,66 @@
1
+ /**
2
+ * Per-connection store of `SSH_ASKPASS` helpers.
3
+ *
4
+ * Why this exists as a module: preparing a helper is **async** (it reads the secret from the credential
5
+ * service and writes two files), but transport factories are **synchronous** and are also reached from
6
+ * `createAlias` during the install ladder. The two are joined here: something async calls
7
+ * {@link AskpassRegistry.prepare} first, and the factory then reads {@link AskpassRegistry.envFor}
8
+ * without awaiting.
9
+ *
10
+ * Three rules:
11
+ *
12
+ * 1. **One helper per connection.** Preparing twice returns the same handle, so a reconnect does not
13
+ * accumulate temp directories (and the secret is read once).
14
+ * 2. **Only password connections get one.** Key and agent connections never prompt; handing them
15
+ * `BatchMode=no` would let a misconfigured host block on an interactive prompt forever.
16
+ * 3. **A failure is a degradation, not a throw.** If the secret cannot be resolved the connection still
17
+ * works through the transports that do not need it; {@link AskpassRegistry.prepare} reports `undefined`
18
+ * and the caller keeps its previous behaviour.
19
+ *
20
+ * @module dsh-over-ssh/integration/askpass-registry
21
+ */
22
+ import { type AskpassHandle } from '../../infra/transport/ssh/askpass.ts';
23
+ import type { ConnectionProfile } from '../../domain/roots/connection.ts';
24
+ /** Options for {@link createAskpassRegistry}. */
25
+ export interface AskpassRegistryOptions {
26
+ /** Resolve the connection's password. Throws when it is missing or the credential service is absent. */
27
+ readonly readSecret: (profile: ConnectionProfile) => Promise<string>;
28
+ /** Materialise one helper for a secret. */
29
+ readonly create: (secret: string) => Promise<AskpassHandle>;
30
+ /** Optional sink for "we could not prepare one" so the reason is not swallowed. */
31
+ readonly onUnavailable?: (connectionId: string, reason: string) => void;
32
+ }
33
+ /** The registry surface the composition root needs. */
34
+ export interface AskpassRegistry {
35
+ /**
36
+ * Ensure a helper exists for this connection.
37
+ *
38
+ * @param profile - the connection.
39
+ * @returns the environment to hand `ssh`, or `undefined` when this connection needs none or preparation
40
+ * failed (in which case the caller must keep its non-prompting behaviour).
41
+ */
42
+ prepare(profile: ConnectionProfile): Promise<Record<string, string> | undefined>;
43
+ /** The environment prepared for this connection, if any. Synchronous, for transport factories. */
44
+ envFor(profile: ConnectionProfile): Record<string, string> | undefined;
45
+ /** Whether a connection is currently using a password helper. */
46
+ has(connectionId: string): boolean;
47
+ /** Drop one connection's helper (its transport was released, or the connection changed). */
48
+ forget(connectionId: string): Promise<void>;
49
+ /**
50
+ * Allow a retired connection id to prepare a helper again.
51
+ *
52
+ * Call this only when the connection is deliberately re-established. Without it, a re-saved connection
53
+ * could never get a password helper, because `forget` leaves a tombstone that `prepare` honours.
54
+ */
55
+ revive(connectionId: string): void;
56
+ /** Drop every helper (plugin unload). */
57
+ disposeAll(): Promise<void>;
58
+ }
59
+ /**
60
+ * Build the registry.
61
+ *
62
+ * @param options - injected secret reader, helper factory and optional sink.
63
+ * @returns the registry.
64
+ */
65
+ export declare function createAskpassRegistry(options: AskpassRegistryOptions): AskpassRegistry;
66
+ //# sourceMappingURL=askpass-registry.d.ts.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The install ladder's I/O, built on the connection's **Tier 1 transport**.
3
+ *
4
+ * The agent cannot install itself, so every step of the ladder runs through the transport that already
5
+ * works: `exec` for the probe, `writeFile` for the upload (the Tier 1 transports already implement bounded,
6
+ * atomic remote writes), and one more `exec` for the digest. Nothing here opens a second authentication
7
+ * path, which is what keeps "upload" as trustworthy as "run a command".
8
+ *
9
+ * @module dsh-remote-workspace/integration/agent-install-io
10
+ */
11
+ import type { AgentInstallIo } from '../infra/transport/agent-installer.ts';
12
+ import type { Transport } from '../infra/transport/transport.ts';
13
+ /** Options for {@link createAgentInstallIo}. */
14
+ export interface AgentInstallIoOptions {
15
+ /** The Tier 1 transport of the connection being installed onto. */
16
+ readonly transport: Transport;
17
+ /** Refuse to upload anything larger than this (a corrupt manifest must not fill the host's disk). */
18
+ readonly maxUploadBytes?: number;
19
+ /** Local file reader, injected so tests never touch a real file. */
20
+ readonly readLocalFile?: (path: string) => Promise<Uint8Array>;
21
+ /** Local size lookup, so an oversized artifact is rejected before it is read into memory. */
22
+ readonly localSize?: (path: string) => Promise<number>;
23
+ /** Cap for exec output while probing; the ladder only needs tiny answers. */
24
+ readonly probeMaxBytes?: number;
25
+ }
26
+ /**
27
+ * Build the ladder's I/O from an existing transport.
28
+ *
29
+ * @param options - transport plus optional readers and caps.
30
+ * @returns an {@link AgentInstallIo} that never opens a second connection.
31
+ */
32
+ export declare function createAgentInstallIo(options: AgentInstallIoOptions): AgentInstallIo;
33
+ //# sourceMappingURL=agent-install-io.d.ts.map
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The bridge between the install ladder and transport selection.
3
+ *
4
+ * Selection is synchronous (it may only consult cached facts) while the ladder must talk to the host, so
5
+ * the two are joined by an **async preflight**: the selector's first answer is revised before any transport
6
+ * is built. That is what makes "agent unavailable ⇒ Tier 1" true without making the selector depend on I/O.
7
+ *
8
+ * Two rules this module exists to enforce:
9
+ *
10
+ * 1. **No host traffic unless the connection asked for the agent.** A non-agent decision returns
11
+ * immediately, so an ordinary alias connection never probes or uploads anything.
12
+ * 2. **A failed ladder is a degradation, never an exception.** `ensureAgent` already turns every remote
13
+ * problem into a `tier1` outcome; this module forwards that as a revised decision plus a hint.
14
+ *
15
+ * @module dsh-remote-workspace/integration/agent-preflight
16
+ */
17
+ import type { TransportPreflight } from '../app/transport-service.ts';
18
+ import type { ConnectionProfile } from '../domain/connection.ts';
19
+ import type { AgentInstallation } from '../infra/transport/agent-installer.ts';
20
+ /** What the preflight learned about one connection. */
21
+ export type AgentPreflightOutcome = {
22
+ readonly kind: 'agent';
23
+ readonly remotePath: string;
24
+ readonly platform: string;
25
+ readonly reused: boolean;
26
+ } | {
27
+ readonly kind: 'tier1';
28
+ readonly reason: string;
29
+ readonly hint: string;
30
+ };
31
+ /** Options for {@link createAgentPreflight}. */
32
+ export interface AgentPreflightOptions {
33
+ /** Run (or reuse a memoized) ladder for one connection. Injected so this module stays offline-testable. */
34
+ readonly ensure: (profile: ConnectionProfile, signal?: AbortSignal) => Promise<AgentInstallation>;
35
+ /** Optional sink so the connection UI can show what happened. */
36
+ readonly onOutcome?: (connectionId: string, outcome: AgentPreflightOutcome) => void;
37
+ /** Optional logger for the "we are not even trying" path; defaults to silence. */
38
+ readonly onSkipped?: (profile: ConnectionProfile) => void;
39
+ }
40
+ /** The preflight plus the installation facts the agent factory needs. */
41
+ export interface AgentPreflight {
42
+ /** Pass this to {@link TransportServiceOptions.preflight}. */
43
+ readonly preflight: TransportPreflight;
44
+ /** The installation for a connection, once the ladder approved one. */
45
+ installationFor(connectionId: string): AgentPreflightOutcome | undefined;
46
+ /** Forget one connection (its transport was released, or the user changed the connection). */
47
+ forget(connectionId: string): void;
48
+ }
49
+ /**
50
+ * Build the preflight.
51
+ *
52
+ * @param options - ladder plus optional sinks.
53
+ * @returns the preflight, an installation lookup, and a way to forget a connection.
54
+ */
55
+ export declare function createAgentPreflight(options: AgentPreflightOptions): AgentPreflight;
56
+ //# sourceMappingURL=agent-preflight.d.ts.map
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The local anchor directory of a remote root.
3
+ *
4
+ * A remote root needs a **local** path to stand in for it, because a workspace path must exist on this machine
5
+ * (`root.ts` keeps that anchor on the `RootRef`). The platform then resolves that path with `realpath` when it
6
+ * opens a workspace on it, so the directory has to be **created**, not just computed:
7
+ *
8
+ * workspace create failed: workspace/invalid-path: cannot create a Workspace at
9
+ * "C:\\Users\\…\\.dsh\\ssh-dev\\roots\\腾讯云\\39d1e90c": ENOENT …
10
+ *
11
+ * That failure is what this module exists to prevent. It lives in its own file so the rule ("a remote root's
12
+ * anchor must exist") is in one place and testable without a real home directory (红线 3: 外部依赖走注入).
13
+ *
14
+ * @module dsh-remote-workspace/integration/anchor-directory
15
+ */
16
+ import type { RootRef } from '../domain/root.ts';
17
+ /** The one filesystem call this module needs. */
18
+ export interface AnchorDirectoryIo {
19
+ /**
20
+ * Create a directory and its parents; a no-op when it already exists.
21
+ *
22
+ * The return value is ignored on purpose (`node:fs` answers with the first created path): this module only
23
+ * cares that the directory exists afterwards, so the seam stays as narrow as that fact.
24
+ */
25
+ mkdir(path: string, options: {
26
+ readonly recursive: true;
27
+ }): Promise<unknown> | unknown;
28
+ }
29
+ /**
30
+ * Make one root's local anchor exist.
31
+ *
32
+ * Local roots are their own anchor (the directory is the user's own path, which the platform checks itself), and
33
+ * a remote root without an anchor simply has nothing to create - both cases return without touching the disk.
34
+ *
35
+ * @param root - the root that is about to become live.
36
+ * @param io - the injected filesystem.
37
+ * @returns nothing; a failure propagates so the caller decides whether it is fatal.
38
+ */
39
+ export declare function ensureAnchorDirectory(root: Pick<RootRef, 'location' | 'anchorPath'>, io: AnchorDirectoryIo): Promise<void>;
40
+ /**
41
+ * The last path segment of a remote root's anchor: **the remote folder's own name**.
42
+ *
43
+ * Why it matters: the platform titles a new workspace with `defaultWorkspaceTitle(path)` =
44
+ * `basename(path)` (`dsh-workspace/lib/types/paths.js:26-29`), and the directory-flow contract only carries a
45
+ * `path` - there is no title parameter to pass (`DirectoryFlowOwnerProps`). So the segment this function
46
+ * returns **is** the name the user sees in the sidebar. A digest-only anchor made every remote workspace show
47
+ * up as `daf8c293`; this is what turns it into `stress_10`.
48
+ *
49
+ * Identity is *not* this function's job: the caller keeps a digest directory above it, so two remote paths with
50
+ * the same folder name still get two anchors (one canonical path per workspace).
51
+ *
52
+ * @param remotePath - absolute POSIX path on the remote host.
53
+ * @returns a segment that is safe to create on this machine and readable as a workspace name.
54
+ */
55
+ export declare function anchorLeafName(remotePath: string): string;
56
+ //# sourceMappingURL=anchor-directory.d.ts.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Per-connection store of `SSH_ASKPASS` helpers.
3
+ *
4
+ * Why this exists as a module: preparing a helper is **async** (it reads the secret from the credential
5
+ * service and writes two files), but transport factories are **synchronous** and are also reached from
6
+ * `createAlias` during the install ladder. The two are joined here: something async calls
7
+ * {@link AskpassRegistry.prepare} first, and the factory then reads {@link AskpassRegistry.envFor}
8
+ * without awaiting.
9
+ *
10
+ * Three rules:
11
+ *
12
+ * 1. **One helper per connection.** Preparing twice returns the same handle, so a reconnect does not
13
+ * accumulate temp directories (and the secret is read once).
14
+ * 2. **Only password connections get one.** Key and agent connections never prompt; handing them
15
+ * `BatchMode=no` would let a misconfigured host block on an interactive prompt forever.
16
+ * 3. **A failure is a degradation, not a throw.** If the secret cannot be resolved the connection still
17
+ * works through the transports that do not need it; {@link AskpassRegistry.prepare} reports `undefined`
18
+ * and the caller keeps its previous behaviour.
19
+ *
20
+ * @module dsh-remote-workspace/integration/askpass-registry
21
+ */
22
+ import { type AskpassHandle } from '../infra/transport/askpass.ts';
23
+ import type { ConnectionProfile } from '../domain/connection.ts';
24
+ /** Options for {@link createAskpassRegistry}. */
25
+ export interface AskpassRegistryOptions {
26
+ /** Resolve the connection's password. Throws when it is missing or the credential service is absent. */
27
+ readonly readSecret: (profile: ConnectionProfile) => Promise<string>;
28
+ /** Materialise one helper for a secret. */
29
+ readonly create: (secret: string) => Promise<AskpassHandle>;
30
+ /** Optional sink for "we could not prepare one" so the reason is not swallowed. */
31
+ readonly onUnavailable?: (connectionId: string, reason: string) => void;
32
+ }
33
+ /** The registry surface the composition root needs. */
34
+ export interface AskpassRegistry {
35
+ /**
36
+ * Ensure a helper exists for this connection.
37
+ *
38
+ * @param profile - the connection.
39
+ * @returns the environment to hand `ssh`, or `undefined` when this connection needs none or preparation
40
+ * failed (in which case the caller must keep its non-prompting behaviour).
41
+ */
42
+ prepare(profile: ConnectionProfile): Promise<Record<string, string> | undefined>;
43
+ /** The environment prepared for this connection, if any. Synchronous, for transport factories. */
44
+ envFor(profile: ConnectionProfile): Record<string, string> | undefined;
45
+ /** Whether a connection is currently using a password helper. */
46
+ has(connectionId: string): boolean;
47
+ /** Drop one connection's helper (its transport was released, or the connection changed). */
48
+ forget(connectionId: string): Promise<void>;
49
+ /** Drop every helper (plugin unload). */
50
+ disposeAll(): Promise<void>;
51
+ }
52
+ /**
53
+ * Build the registry.
54
+ *
55
+ * @param options - injected secret reader, helper factory and optional sink.
56
+ * @returns the registry.
57
+ */
58
+ export declare function createAskpassRegistry(options: AskpassRegistryOptions): AskpassRegistry;
59
+ //# sourceMappingURL=askpass-registry.d.ts.map
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Decide, per root, where its file-level recycle bin lives — and make that place resolvable.
3
+ *
4
+ * The bin must sit **outside** the caller's repository (a "safe delete" that pollutes `git status` is not safe),
5
+ * yet it must be reachable by the router, which only resolves paths inside a registered root (ADR-0011). So the
6
+ * bin directory is registered as a **hidden root**: routable, but absent from `RootRegistry.records` and
7
+ * therefore from every user-facing list.
8
+ *
9
+ * This module owns the one decision that cannot be pure — *is the chosen directory usable?* — and it answers by
10
+ * measuring rather than assuming: the bin's parent must exist and must be on the **same device** as the root,
11
+ * because a cross-device `rename` is refused outright and the file-level bin has no copy fallback
12
+ * (`fs-commands.ts`, `recycle-bin-service.ts`). If a measurement fails, the bin stays inside the root — the old
13
+ * behaviour — and the reason is recorded, so a fallback is **visible** rather than silent.
14
+ *
15
+ * @module dsh-remote-workspace/integration/bin-root-resolver
16
+ */
17
+ import { type RootRef } from '../domain/root.ts';
18
+ import type { RootRecord } from './root-registry.ts';
19
+ /** Where one root's bin ended up, and why. */
20
+ export interface BinRootChoice {
21
+ /** Absolute bin directory. */
22
+ readonly binRoot: string;
23
+ /** `beside` = outside the repository (the goal); `inside` = the documented fallback. */
24
+ readonly placement: 'beside' | 'inside';
25
+ /** Whether a hidden root was registered for it (only for `beside`). */
26
+ readonly hidden: boolean;
27
+ /** Human-readable reason for a fallback, or for an inconclusive measurement. */
28
+ note?: string;
29
+ }
30
+ /** What the resolver needs from its owner. */
31
+ export interface BinRootResolverDeps {
32
+ /** Register a hidden root; returns the record. */
33
+ readonly addHiddenRoot: (root: RootRef) => RootRecord;
34
+ /** Drop a hidden root by key; used when a migration fails and the new location is abandoned. */
35
+ readonly removeHiddenRoot?: (key: string) => void;
36
+ /** The configured bin directory name (`limits.binDir`). */
37
+ readonly binDir: string;
38
+ /**
39
+ * Whether two paths are on the same device.
40
+ *
41
+ * `undefined` means **unknown**, and unknown is treated as *usable*: refusing to move a file into the bin is
42
+ * worse than putting the bin in an untidy place, and a transport without a working `stat` cannot answer.
43
+ */
44
+ readonly sameDevice: (root: RootRef, left: string, right: string) => Promise<boolean | undefined>;
45
+ /** Whether a directory exists. */
46
+ readonly exists: (root: RootRef, path: string) => Promise<boolean>;
47
+ /**
48
+ * Move a directory, creating the destination's parents.
49
+ *
50
+ * Only ever called for the **old bin → new bin** migration, where the two are on one device (already
51
+ * measured), so a plain `rename` is the whole implementation.
52
+ */
53
+ readonly moveDirectory: (root: RootRef, from: string, to: string) => Promise<void>;
54
+ }
55
+ /** The resolver handed to the recycle-bin wiring. */
56
+ export interface BinRootResolver {
57
+ /**
58
+ * The bin directory for one root, registering a hidden root on first use.
59
+ *
60
+ * Synchronous by contract: the bin service asks repeatedly and cannot await (`binRootFor`). The measurement
61
+ * therefore happens in {@link BinRootResolver.prepare}, which the composition calls when a root is registered.
62
+ *
63
+ * @param root - the root being served.
64
+ * @returns its bin directory.
65
+ */
66
+ binRootFor: (root: RootRef) => string;
67
+ /** Measure and register a root's bin placement; call this when the root is added. */
68
+ prepare: (root: RootRef) => Promise<BinRootChoice>;
69
+ /** The choice made for one root, if any (for diagnostics). */
70
+ choiceFor: (root: RootRef) => BinRootChoice | undefined;
71
+ /** Drop one root's cached choice (its root was removed, or its connection changed). */
72
+ forget: (key: string) => void;
73
+ }
74
+ /**
75
+ * Build the resolver.
76
+ *
77
+ * @param deps - injected registration, configuration and measurement seams.
78
+ * @returns the resolver.
79
+ */
80
+ export declare function createBinRootResolver(deps: BinRootResolverDeps): BinRootResolver;
81
+ //# sourceMappingURL=bin-root-resolver.d.ts.map
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The connectivity probe behind the panel's 「测试」 button.
3
+ *
4
+ * What "testing a connection" means here, and why it is a real connection rather than a TCP ping:
5
+ *
6
+ * - it goes through the **same transport service** the rest of the plugin uses, so it answers the only question
7
+ * that matters to the user - "would a remote operation work right now" - including the transport the
8
+ * selector picked and whether that pick was a degradation;
9
+ * - the last step is an actual command round-trip (`printf`), so a host that accepts TCP but has no usable
10
+ * shell (or a transport that cannot execute) is reported as a failure, not as a success;
11
+ * - the probe **warms the connection** the caller will use next, because `acquire` is memoized per connection.
12
+ *
13
+ * Everything it needs is injected (红线 3: 外部依赖走注入), so the whole classification is testable without a
14
+ * server, and the entry is the only place that knows about profiles.
15
+ *
16
+ * @module dsh-remote-workspace/integration/connection-test
17
+ */
18
+ /** The slice of `Transport` the probe uses. Narrow on purpose: the probe must not be able to do more. */
19
+ export interface ProbeTransport {
20
+ readonly id: string;
21
+ connect(signal?: AbortSignal): Promise<void>;
22
+ exec(request: {
23
+ readonly argv: readonly string[];
24
+ readonly maxBytes?: number;
25
+ }, signal?: AbortSignal): Promise<{
26
+ readonly exitCode: number;
27
+ readonly stdout: string;
28
+ }>;
29
+ }
30
+ /** One acquisition: the transport plus the decision that produced it. */
31
+ export interface ProbeAcquisition {
32
+ readonly transport: ProbeTransport;
33
+ readonly decision: {
34
+ readonly kind: string;
35
+ readonly degradations?: readonly {
36
+ readonly code: string;
37
+ }[];
38
+ };
39
+ }
40
+ /** What the probe needs. */
41
+ export interface ConnectionProbeDeps {
42
+ /** Acquire (and, on first use, connect) the connection's transport. Rejects with `CONNECTION_NOT_FOUND` for an unknown id. */
43
+ readonly acquire: (connectionId: string) => Promise<ProbeAcquisition>;
44
+ /** Budget for the whole probe; each transport keeps its own timeouts on top of it. */
45
+ readonly timeoutMs?: number;
46
+ /** Clock, injected so a test can assert the reported milliseconds. */
47
+ readonly now?: () => number;
48
+ }
49
+ /** The wire answer: success carries the facts the row shows, failure carries a reason it can print. */
50
+ export type ConnectionProbeResult = {
51
+ readonly ok: true;
52
+ readonly transport: string;
53
+ readonly degraded: boolean;
54
+ readonly degradation?: string;
55
+ readonly ms: number;
56
+ } | {
57
+ readonly ok: false;
58
+ readonly code: string;
59
+ readonly message: string;
60
+ readonly ms: number;
61
+ };
62
+ /**
63
+ * Probe one connection.
64
+ *
65
+ * Never throws: a refused or broken connection is a **result** the panel prints, because a button that rejects
66
+ * leaves the user with nothing to read.
67
+ *
68
+ * @param connectionId - the connection to test.
69
+ * @param deps - the injected acquisition, clock and budget.
70
+ * @returns the outcome, with the elapsed milliseconds either way.
71
+ */
72
+ export declare function probeConnection(connectionId: string, deps: ConnectionProbeDeps): Promise<ConnectionProbeResult>;
73
+ //# sourceMappingURL=connection-test.d.ts.map
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Multi-root implementation of the core `ctx.fileReferences` seam.
3
+ *
4
+ * The core ships [`@deepseek-ai/dsh-file-reference-local`] for **one** local workspace. This plugin's whole
5
+ * point is several roots of two kinds, so this provider answers the same contract for both:
6
+ *
7
+ * - a **remote** root is enumerated by {@link RemoteIndex} (Tier 2 `index.scan` when the connection has an
8
+ * agent, else one bounded `find`/`git ls-files`), cached per root;
9
+ * - a **local** root is enumerated here with a bounded walk, because installing this provider **replaces**
10
+ * the core's local one — returning nothing for local agents would be a regression, not a feature.
11
+ *
12
+ * Candidate paths use the router's display spelling (`ssh://<connection>/abs` for remote roots) so a token
13
+ * stays unambiguous in a multi-root workspace; the local case keeps ordinary host paths.
14
+ *
15
+ * @module dsh-remote-workspace/integration/file-reference-provider
16
+ */
17
+ import { Context } from '@deepseek-ai/cordis';
18
+ import FileReferenceService, { type FileReferenceCandidate } from '@deepseek-ai/dsh-file-reference';
19
+ import type { Agent } from '@deepseek-ai/dsh-agent';
20
+ /** What the provider needs from the index layer (provided as `ctx.sshDevIndex`). */
21
+ export interface FileReferenceIndex {
22
+ /**
23
+ * Rank candidates for a partially typed `@` query inside one remote root.
24
+ *
25
+ * @param connectionId - connection that owns the root.
26
+ * @param root - backend-absolute remote root path.
27
+ * @param query - text after `@`.
28
+ * @param signal - caller cancellation.
29
+ * @returns ranked candidates whose `path` is a router-resolvable spelling
30
+ * (`ssh://<connection>/abs`), so a token stays unambiguous across roots.
31
+ */
32
+ complete(connectionId: string, root: string, query: string, signal: AbortSignal): Promise<readonly FileReferenceCandidate[]>;
33
+ }
34
+ declare module '@deepseek-ai/cordis' {
35
+ interface Context {
36
+ /** Remote index used by the file-reference provider. */
37
+ sshDevIndex: FileReferenceIndex;
38
+ }
39
+ }
40
+ /** Directory names never traversed by the local walk (same intent as the core's exclusion list). */
41
+ export declare const LOCAL_EXCLUDED_DIRECTORIES: readonly string[];
42
+ /** Default cap for the local walk; the core uses a comparable bound for its own index. */
43
+ export declare const LOCAL_MAX_ENTRIES = 20000;
44
+ /** How deep the local walk may go before it gives up (protects against pathological trees). */
45
+ export declare const LOCAL_MAX_DEPTH = 12;
46
+ /**
47
+ * How long a local enumeration may be reused before the tree is walked again.
48
+ *
49
+ * **Short on purpose, and much shorter than the remote branch's 30 s** (`RemoteIndex` `ttlMs`). That cache
50
+ * exists to avoid a *network round trip*; this one exists only to collapse **one typing burst** into a single
51
+ * walk. A burst is a few keystrokes a couple of hundred milliseconds apart, so a quarter second folds the
52
+ * whole burst while keeping staleness below the threshold where a user could notice — creating a file and
53
+ * typing `@` again within 250 ms is not something a person does.
54
+ *
55
+ * The failure mode is deliberately the cheap one: a miss costs a walk, i.e. exactly today's behaviour, so
56
+ * this can never be *slower* than not caching, only less fresh for at most this long.
57
+ *
58
+ * Measured (`.verify/probe-local-fref-cache.ts`, 10 000-entry tree): typing `@module` walked the whole tree
59
+ * **6 times** and cost 413 ms; the walk is ~68 ms each, and it is paid per keystroke, on the host's event loop.
60
+ */
61
+ export declare const LOCAL_CACHE_TTL_MS = 250;
62
+ /**
63
+ * Cap for the local enumeration cache.
64
+ *
65
+ * Keys are registry root paths, so the set is bounded by how many roots the user registered — but it is
66
+ * capped anyway, for the same reason `RemoteIndex` bounds its own caches: a bound that depends on "the
67
+ * caller will not do that" is not a bound.
68
+ */
69
+ export declare const LOCAL_MAX_CACHED_ROOTS = 8;
70
+ /** How many candidates one query returns (the core's local provider uses the same order of magnitude). */
71
+ export declare const DEFAULT_MAX_RESULTS = 50;
72
+ /** One locally enumerated entry, with the kind completion needs. */
73
+ export interface LocalEntry {
74
+ readonly path: string;
75
+ readonly kind: 'file' | 'directory';
76
+ }
77
+ /** Construction options; `walk` is injected so tests never touch a real filesystem. */
78
+ export interface RemoteFileReferenceOptions {
79
+ /** Maximum entries collected in one local walk. Default {@link LOCAL_MAX_ENTRIES}. */
80
+ readonly maxEntries?: number;
81
+ /** Maximum depth of the local walk. Default {@link LOCAL_MAX_DEPTH}. */
82
+ readonly maxDepth?: number;
83
+ /** Maximum candidates returned per query. Default {@link DEFAULT_MAX_RESULTS}. */
84
+ readonly maxResults?: number;
85
+ /** Local enumerator, injected for tests. Defaults to a real bounded `readdir` walk. */
86
+ readonly walk?: (root: string, signal: AbortSignal) => Promise<readonly LocalEntry[]>;
87
+ /** How long a local enumeration stays reusable. Default {@link LOCAL_CACHE_TTL_MS}. */
88
+ readonly localTtlMs?: number;
89
+ /** Cap for the local enumeration cache. Default {@link LOCAL_MAX_CACHED_ROOTS}. */
90
+ readonly maxCachedRoots?: number;
91
+ /** Injectable clock, so the TTL is testable without sleeping. */
92
+ readonly now?: () => number;
93
+ }
94
+ /**
95
+ * The provider.
96
+ *
97
+ * Lifecycle note: it is registered as a **separate module** (`dsh-remote-workspace/file-references`) so the
98
+ * composition decides whether to replace the core's local service — enabling it is an explicit choice.
99
+ */
100
+ export declare class RemoteFileReferenceService extends FileReferenceService {
101
+ #private;
102
+ static inject: string[];
103
+ constructor(ctx: Context, options?: RemoteFileReferenceOptions);
104
+ /**
105
+ * List candidates for one agent's working directory.
106
+ *
107
+ * @param agent - target agent; its session cwd decides which root answers.
108
+ * @param query - text after `@` (may be empty: "show the shallowest entries").
109
+ * @param signal - caller cancellation.
110
+ * @returns ranked candidates, best first; empty when the cwd is outside every registered root.
111
+ */
112
+ list(agent: Agent, query: string, signal: AbortSignal): Promise<FileReferenceCandidate[]>;
113
+ }
114
+ export default RemoteFileReferenceService;
115
+ //# sourceMappingURL=file-reference-provider.d.ts.map