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,353 +0,0 @@
1
- /**
2
- * 代理传输:把协议客户端适配成 {@link Transport}。
3
- *
4
- * 从原 3,388 行文件拆出(审计 0077):协议层(帧 / 类型 / 客户端)已移到
5
- * `agent-protocol-{frames,types,client}.ts`,本文件只剩**传输适配**——连接状态机、
6
- * 能力探测、各方法的 RPC 调用、以及真实启动器。
7
- *
8
- * 兼容性:下面 re-export 三个协议模块,既有调用方(integration / wiring / tests)
9
- * 从 `agent-transport.ts` 取符号的路径不变。
10
- *
11
- * @module dsh-remote-workspace/infra/transport/agent-transport
12
- */
13
- export * from './agent-protocol-frames.ts';
14
- export * from './agent-protocol-types.ts';
15
- export * from './agent-protocol-codec.ts';
16
- export * from './agent-protocol-errors.ts';
17
- export * from './agent-protocol-client.ts';
18
- import { type RemoteCapabilities } from '../../domain/capability.ts';
19
- import { type ExecRequest, type ExecResult, type ReadFileRangeRequest, type ReadFileRequest, type RemoteFileChunk, type RemoteStatResult, type RemoteWriteOutcome, type RemoveRequest, type RenameRequest, type Transport, type WriteFileRangeRequest, type WriteFileRequest } from './transport.ts';
20
- import type { EditFileRequest, EditFileResult, HashFileRequest, HashFileResult, JobStdinRequest, JobStdinResult, MakeDirRequest, GlobPathsRequest, GlobPathsResult, RemovePathRequest, RenamePathRequest } from './transport.ts';
21
- import { TransportBase } from './transport-base.ts';
22
- import type { AgentLauncher, AgentTransportOptions, AgentIndexScanResult, AgentProcStartRequest, AgentJobStatus, AgentJobKill, AgentJobOutput, AgentLspStartRequest, AgentLspStatus, AgentLspRead, AgentIndexScanRequest, AgentSearchResult, AgentSearchGrepRequest, AgentWatchStartResult, AgentWatchStartRequest, AgentWatchPollResult, AgentWatchPollRequest, AgentWatchStopResult, AgentCapabilities } from './agent-protocol-types.ts';
23
- export declare class AgentTransport extends TransportBase implements Transport {
24
- #private;
25
- readonly id: string;
26
- constructor(options: AgentTransportOptions);
27
- /**
28
- * Session the agent echoed at handshake (`hello.result.sessionId`), or `undefined` when it sent none.
29
- *
30
- * `undefined` is the honest answer for an agent that predates sessions, and callers must not treat it as
31
- * `"default"`: doing so would claim per-session isolation the agent never agreed to.
32
- */
33
- get negotiatedSessionId(): string | undefined;
34
- /**
35
- * Whether the agent said jobs outlive this connection (`hello.result.daemon`).
36
- *
37
- * `false` until a handshake says otherwise, because today's agent does tie job lifetime to the
38
- * connection; assuming `true` would make callers skip the cleanup that is still required.
39
- */
40
- get daemon(): boolean;
41
- /**
42
- * The agent's own capability record (Tier 2 facts).
43
- *
44
- * `capabilities` is deliberately the Tier 1 shape, so the agent's extra bits (`watch`, `index`,
45
- * `atomicWrite`, `landlock`, `exec`) would otherwise be dropped on the floor. Tier 2 callers must gate
46
- * on **this** record: `watch !== 'native'` means no `watch.*`, and `exec !== true` means no `proc.exec`.
47
- * Empty until the first handshake.
48
- */
49
- get agentCapabilities(): AgentCapabilities;
50
- /** `uname` derived from the agent's `os`, or `undefined` when the agent reported nothing usable. */
51
- get agentUname(): string | undefined;
52
- /**
53
- * Open the session and handshake. Idempotent and single-flight: concurrent callers share one attempt.
54
- *
55
- * @throws SshDevError `CONNECTION_LOST` when the handshake fails or the protocol version mismatches
56
- * (the only correct reaction is falling back to Tier 1), `CONNECTION_UNREACHABLE` when the session
57
- * cannot be started at all.
58
- */
59
- connect(signal?: AbortSignal): Promise<void>;
60
- /**
61
- * Close the session. Idempotent, and safe to call while connecting (the attempt is abandoned).
62
- *
63
- * A later `connect` opens a fresh session, so the transport is reusable after a disconnect.
64
- */
65
- dispose(): Promise<void>;
66
- /**
67
- * Run one command through the agent.
68
- *
69
- * Protocol v1 has no arbitrary-command method, so there are exactly two paths:
70
- *
71
- * - an injected {@link AgentExecCommand} (a deployment whose agent build does add one);
72
- * - otherwise the client asks `proc.exec` and maps `E_METHOD` onto `REMOTE_UNSUPPORTED` — an honest
73
- * "this agent version cannot run commands", never a silent fallback to the Tier 1 transport.
74
- */
75
- exec(request: ExecRequest, signal?: AbortSignal): Promise<ExecResult>;
76
- /**
77
- * Stat a path with the agent's own `fs.stat`, so the token is the **same one `fs.read` reports**.
78
- *
79
- * This is the member that closes the read→write token gap on Tier 2. `fs.stat` returns the agent's
80
- * `Version{Size, MtimeNs}.String()` (`size:mtimeNs`), which is exactly what `fs.read` returns and exactly
81
- * what `fs.write`'s `expectedVersion` guard compares against. Deriving a token here instead — or letting
82
- * the caller fall back to a shell `stat -c '%Y'` — would produce seconds and make every guard mismatch.
83
- *
84
- * The agent's `version` string is passed through **untouched** rather than re-formatted locally: there is
85
- * one token producer (the agent) and this is not a second one.
86
- */
87
- statPath(path: string, signal?: AbortSignal): Promise<RemoteStatResult>;
88
- /**
89
- * Read a remote file: `fs.read` (control frame) followed by its blob frame.
90
- *
91
- * The version token is the string the **agent** returned (`size:mtimeNs`), passed through untouched:
92
- * re-deriving it locally would produce a token that no longer matches the guard the agent applies on
93
- * the next write. Note this is *not* byte-identical to the Tier 1 `size:mtimeSeconds` token, because
94
- * the agent reports nanoseconds (verified in its `Version.String()`); {@link statPath} exists so a caller
95
- * can obtain the *same* Tier 2 token from a stat instead of comparing the two shapes.
96
- */
97
- readFile(request: ReadFileRequest, signal?: AbortSignal): Promise<RemoteFileChunk>;
98
- /**
99
- * Write a remote file: `fs.write` (control frame, then one blob frame with the content).
100
- *
101
- * **The guard here is a version comparison, not a digest comparison.** Protocol v1's `fs.write` accepts
102
- * `expectedVersion` and nothing else, so the guard is implemented as: `fs.stat` the target, refuse when the
103
- * observed version differs from the caller's token, and otherwise pass that same version to the agent as
104
- * `expectedVersion` so the agent re-checks it at write time (that is the compare-and-swap closing the race
105
- * between our stat and our write). When the target does not exist, no version token can match, so the write
106
- * is refused with `TRANSFER_CONFLICT` rather than overwriting blind.
107
- *
108
- * **Which field carries the token.** {@link WriteFileRequest.expectedVersion} is the explicit channel and
109
- * wins when present. {@link WriteFileRequest.expectedSha256} is still accepted as a *version* token for
110
- * callers written before the explicit field existed, and that legacy overloading is exactly what this
111
- * transport used to do implicitly; the error details say `guard: 'version'` in both cases so a caller is
112
- * never told a digest was verified when a version was.
113
- *
114
- * The alternative — refusing every guarded write with `REMOTE_UNSUPPORTED` — was rejected because the
115
- * version round trip is available, cheap, and strictly safer than an unguarded overwrite.
116
- */
117
- writeFile(request: WriteFileRequest, signal?: AbortSignal): Promise<RemoteWriteOutcome>;
118
- /**
119
- * Offset read: the agent's own `fs.read` with `offset`.
120
- *
121
- * This used to borrow `proc.exec` (`tail -c +N | head -c M | base64`) because protocol v1's `fs.read` had no
122
- * offset. The agent now serves `offset` natively (audit 0006), so the shell hop is gone: no `tail`/`head`/
123
- * `base64` on the remote, no shell quoting, and the bytes are framed instead of base64-inflated (the old path
124
- * asked for `2 * cap + 4096` bytes of headroom precisely because of that inflation).
125
- *
126
- * The agent's `truncated` already means "there is more after this window", so it is passed through rather
127
- * than recomputed from `size - offset`.
128
- */
129
- readFileRange(request: ReadFileRangeRequest, signal?: AbortSignal): Promise<RemoteFileChunk>;
130
- /**
131
- * Positioned write: `fs.write` with `offset` (the agent's `WriteAt`).
132
- *
133
- * This used to shell out (`dd of=… seek=… conv=notrunc`) because protocol v1's `fs.write` only replaced a
134
- * whole file. The agent serves `offset` natively now (audit 0006), so the payload travels as a real blob
135
- * frame instead of base64-on-stdin: no `dd`, no shell quoting, and no 4/3 size inflation. The agent owns the
136
- * POSIX rules (offset 0 may create and keeps the tail, offset > 0 refuses a missing file) — see
137
- * `WriteAt` in the agent, which is the single place those rules are written down.
138
- */
139
- writeFileRange(request: WriteFileRangeRequest, signal?: AbortSignal): Promise<RemoteWriteOutcome>;
140
- /** Move a path; a cross-device move fails instead of silently copying. */
141
- /** {@inheritDoc Transport.editFile} — atomic in-place edit: one round trip, no file transfer. */
142
- editFile(request: EditFileRequest, signal?: AbortSignal): Promise<EditFileResult>;
143
- /** {@inheritDoc Transport.removePath} */
144
- removePath(request: RemovePathRequest, signal?: AbortSignal): Promise<void>;
145
- /** {@inheritDoc Transport.renamePath} */
146
- renamePath(request: RenamePathRequest, signal?: AbortSignal): Promise<void>;
147
- /** {@inheritDoc Transport.hashFile} */
148
- hashFile(request: HashFileRequest, signal?: AbortSignal): Promise<HashFileResult>;
149
- /** {@inheritDoc Transport.makeDir} */
150
- makeDir(request: MakeDirRequest, signal?: AbortSignal): Promise<void>;
151
- /** {@inheritDoc Transport.globPaths} */
152
- globPaths(request: GlobPathsRequest, signal?: AbortSignal): Promise<GlobPathsResult>;
153
- /** `proc.stdin` for the job layer: same call, job-shaped arguments (审计 0030). */
154
- procStdin(id: string, data: string, close: boolean, signal?: AbortSignal): Promise<JobStdinResult>;
155
- /** {@inheritDoc Transport.jobStdin} */
156
- jobStdin(request: JobStdinRequest, signal?: AbortSignal): Promise<JobStdinResult>;
157
- rename(request: RenameRequest, signal?: AbortSignal): Promise<void>;
158
- /** Remove a file or (with `recursive`) a directory tree. */
159
- remove(request: RemoveRequest, signal?: AbortSignal): Promise<void>;
160
- /**
161
- * Enumerate remote files for `@` completion: `index.scan`.
162
- *
163
- * Gated on `agentCapabilities.index === true` **before** anything is written; when the agent did not
164
- * advertise indexing this throws `REMOTE_UNSUPPORTED` and leaves `agent.methods()` untouched, so a
165
- * caller can fall back to Tier 1 without a wasted round trip.
166
- *
167
- * The returned numbers are **the agent's own report** (entry count, strategy, truncation); this client
168
- * does not re-validate them, and an unrecognised `strategy` stays unrecognised (`"unknown"`).
169
- *
170
- * This is the **full** scan. When the agent has a snapshot from a previous scan it can refresh
171
- * incrementally instead — see {@link scanIndexRefresh}, which is what a caller polling for `@` completion
172
- * should use after the first scan.
173
- *
174
- * The agent's per-scan deadline is the request's `timeoutMs` (it has its own 5 s default); the *client's*
175
- * deadline is the transport's `requestTimeoutMs`.
176
- *
177
- * @throws SshDevError `REMOTE_UNSUPPORTED` when the capability is absent, `REMOTE_COMMAND_FAILED`
178
- * (`E_PARAMS`) for an empty `roots`, `CANCELLED`/`CONNECTION_LOST` per the shared request rules.
179
- */
180
- scanIndex(request: AgentIndexScanRequest, signal?: AbortSignal): Promise<AgentIndexScanResult>;
181
- /**
182
- * Refresh the remote index **incrementally**: `index.refresh`.
183
- *
184
- * The agent keeps a bounded snapshot per (roots, caps) identity from the last scan and reuses the file
185
- * listing of every directory whose mtime did not move, so a poll after the first scan costs
186
- * `O(directories)` instead of `O(files)`. Measured on a synthetic 13-directory / 52-file tree:
187
- * 65 syscalls → 13.
188
- *
189
- * **The agent's own report is what the caller gets.** When it cannot refresh safely (no snapshot yet,
190
- * different roots, expired entry) it answers with a full scan and says so in `strategy`/`warnings` — this
191
- * method never pretends an incremental answer was incremental.
192
- *
193
- * ## The boundary a caller must know
194
- *
195
- * A reused directory keeps the `size`/`mtimeNs` recorded at the last scan: a directory's mtime does not
196
- * change when a file's **content** changes, only when its set of entries does. So this is right for
197
- * `@` completion (which needs paths and kinds, and where added/removed/renamed files *are* picked up), and
198
- * wrong for anything that needs current file sizes. Use {@link scanIndex} for that.
199
- *
200
- * @throws SshDevError same vocabulary as {@link scanIndex}. An agent predating `index.refresh` answers
201
- * `E_METHOD`, which maps to `REMOTE_UNSUPPORTED` — callers should treat that as "fall back to scanIndex".
202
- */
203
- scanIndexRefresh(request: AgentIndexScanRequest, signal?: AbortSignal): Promise<AgentIndexScanResult>;
204
- /**
205
- * Start a background command and return immediately: `proc.start`.
206
- *
207
- * The agent runs it in a job table and answers with an id; progress and output come from
208
- * {@link procStatus} / {@link procOutput}. **Nothing is pushed** - v1's frame discipline (a control
209
- * frame plus an optional blob frame, strictly paired, written by one goroutine) has no room for
210
- * server-initiated frames, so the caller polls.
211
- *
212
- * Jobs die with the connection: the agent kills them all when the ssh channel closes. This is
213
- * "reconnectable within one connection", not a durable task queue.
214
- *
215
- * @throws SshDevError `REMOTE_UNSUPPORTED` when the agent predates `proc.start` (`E_METHOD`).
216
- */
217
- procStart(request: AgentProcStartRequest, signal?: AbortSignal): Promise<AgentJobStatus>;
218
- /**
219
- * One job's state: `proc.status`.
220
- *
221
- * @throws SshDevError `REMOTE_NOT_FOUND` for an unknown (or already forgotten) id.
222
- */
223
- procStatus(id: string, signal?: AbortSignal, waitMs?: number): Promise<AgentJobStatus>;
224
- /**
225
- * Incremental output read: `proc.output`.
226
- *
227
- * `offset` is a **position, not a cursor**: pass `nextOffset` from the previous call to get only what is
228
- * new. Re-reading an older offset re-sends that span (nothing is remembered as already read).
229
- *
230
- * The agent keeps a bounded ring buffer that drops the **oldest** bytes (errors tend to be at the end),
231
- * so a result with `lost: true` means the requested span was already discarded - the caller must not
232
- * treat it as continuous output.
233
- */
234
- procOutput(id: string, offset?: number, signal?: AbortSignal, waitMs?: number): Promise<AgentJobOutput>;
235
- /** Terminate a job: `proc.kill`. Idempotent - an already-finished job answers `killed: false`. */
236
- procKill(id: string, signal?: AbortSignal): Promise<AgentJobKill>;
237
- /**
238
- * End one session explicitly: kill its running jobs and drop its finished ones (`session.end`).
239
- *
240
- * With `--shared` (the default) a daemon keeps jobs alive across connections, so a session that
241
- * simply goes away leaves its long-running commands behind — "survives reconnects" would silently
242
- * become "leaks forever" (protocol.md §9.4). Callers end the session when it is genuinely over.
243
- *
244
- * Idempotent: an unknown or already-clean session reports `killed: 0, forgotten: 0`.
245
- */
246
- endSession(session?: string, signal?: AbortSignal): Promise<{
247
- readonly session: string;
248
- readonly killed: number;
249
- readonly forgotten: number;
250
- readonly lspStopped: number;
251
- }>;
252
- /** Every job this connection has started: `proc.list`. */
253
- procList(signal?: AbortSignal): Promise<readonly AgentJobStatus[]>;
254
- /**
255
- * Host a language server: `lsp.start`.
256
- *
257
- * The agent is a **stdio pipe**, not an LSP implementation: it starts the process and moves bytes.
258
- * `lspWrite` takes bytes (base64 on the wire) and `lspRead` pages the server's output by offset - the
259
- * caller owns all JSON-RPC framing and semantics.
260
- *
261
- * @throws SshDevError `REMOTE_UNSUPPORTED` when the agent predates `lsp.start`.
262
- */
263
- lspStart(request: AgentLspStartRequest, signal?: AbortSignal): Promise<AgentLspStatus>;
264
- /** Send bytes to a language server's stdin: `lsp.write` (base64 on the wire). */
265
- lspWrite(id: string, bytes: Uint8Array, signal?: AbortSignal): Promise<{
266
- readonly id: string;
267
- readonly written: number;
268
- readonly state: string;
269
- }>;
270
- /** Read a language server's output from `offset`: `lsp.read`. Same offset semantics as {@link procOutput}. */
271
- lspRead(id: string, offset?: number, signal?: AbortSignal): Promise<AgentLspRead>;
272
- /** One language-server session's state: `lsp.status`. */
273
- lspStatus(id: string, signal?: AbortSignal): Promise<AgentLspStatus>;
274
- /** Terminate a language-server session: `lsp.stop` (closes stdin, then kills if it will not exit). */
275
- lspStop(id: string, signal?: AbortSignal): Promise<AgentLspStatus>;
276
- /**
277
- * Bounded content search: `search.grep`, always available in protocol v1 (no capability bit gates it).
278
- *
279
- * `literal` defaults to the wire default (`true`); `ignoreCase` defaults to `true` and is written as
280
- * the agent's inverted `caseSensitive` flag. Everything the caller omits is omitted from the frame, so
281
- * the agent's own default applies — this client does not pre-fill values it cannot see the effect of.
282
- *
283
- * A regex that the *agent* cannot compile comes back as `E_PARAMS` → `REMOTE_COMMAND_FAILED`; v1 has no
284
- * cancel frame, so a long search is bounded only by `timeoutMs` and the workload caps.
285
- *
286
- * @throws SshDevError `REMOTE_COMMAND_FAILED` for an empty `paths`/`query` (refused locally),
287
- * `REMOTE_UNSUPPORTED` when the agent answers `E_METHOD` (plugin/agent version mismatch).
288
- */
289
- searchGrep(request: AgentSearchGrepRequest, signal?: AbortSignal): Promise<AgentSearchResult>;
290
- /**
291
- * Start (or replace) the remote native watcher: `watch.start`.
292
- *
293
- * Requires `agentCapabilities.watch === 'native'`. `'poll'` (darwin/windows builds) and `'none'` are
294
- * **not** enough: on those platforms the protocol answers `E_UNSUPPORTED`, and the intended Tier 1
295
- * behaviour is polling by the plugin — so this method refuses locally with `REMOTE_UNSUPPORTED`.
296
- *
297
- * `watched` is the list of **roots** that were really registered — not every subdirectory — and
298
- * `truncated` (not a thrown error) is how `maxWatches` / the kernel's `max_user_watches` report that
299
- * only part of a tree is covered. Calling `start` while a watcher runs replaces it; a failed
300
- * replacement leaves no watcher behind, because the old one is stopped first.
301
- */
302
- startWatch(request: AgentWatchStartRequest, signal?: AbortSignal): Promise<AgentWatchStartResult>;
303
- /**
304
- * Collect queued watch events: `watch.poll`.
305
- *
306
- * Since ADR-0009 the agent dispatches requests concurrently, so a poll no longer blocks the connection:
307
- * a concurrent `fs.read`/`search.grep` proceeds and is answered as soon as the agent gets to it. The poll
308
- * still *occupies one in-flight slot* for up to `timeoutMs`, so a loop of long polls can crowd the
309
- * {@link DEFAULT_AGENT_MAX_IN_FLIGHT}-slot window; keep `timeoutMs` small and poll in a loop, or use a
310
- * second connection when you need a dedicated watcher.
311
- *
312
- * Keep `timeoutMs` below the transport's `requestTimeoutMs` (default 15 s): the client deadline is a
313
- * separate clock, and when it fires first the poll fails with `CONNECTION_LOST` even though the agent
314
- * is healthy. `timeout: true` with few or no events is the normal "nothing happened" outcome, not an
315
- * error; when `truncated` is true the remaining events are still queued, so poll again.
316
- *
317
- * `dropped` is **cumulative since `watch.start`**; a growing value (or `truncated`) means the event
318
- * stream is incomplete and the honest reaction is a full `scanIndex` rescan.
319
- */
320
- pollWatch(request?: AgentWatchPollRequest, signal?: AbortSignal): Promise<AgentWatchPollResult>;
321
- /**
322
- * Stop one remote watcher: `watch.stop`. Idempotent, and stopping an absent watcher is **not** an
323
- * error — the agent answers `{ "stopped": false }`, which is returned as-is.
324
- *
325
- * `watcherId` selects which watcher to stop; omit it for the agent's `"default"` watcher, which is what
326
- * a caller that never sets one has always stopped. Stopping one id never touches another, so two
327
- * sessions sharing a connection cannot stop each other's listener.
328
- *
329
- * The first parameter also still accepts an `AbortSignal` (the pre-`watcherId` signature), so a caller
330
- * written against the old positional form keeps working instead of having its signal silently read as a
331
- * watcher name. Prefer the explicit two-argument form.
332
- *
333
- * Unpolled events are discarded by the agent, so a caller that needs a consistent view must rescan
334
- * rather than assume the queue survives the stop.
335
- */
336
- stopWatch(watcherId?: string | AbortSignal, signal?: AbortSignal): Promise<AgentWatchStopResult>;
337
- /**
338
- * Discover capabilities from the agent, cached like the other transports.
339
- *
340
- * The handshake already carries the capability record, so a fresh connection answers from cache;
341
- * `maxAgeMs` (default 5 minutes) decides when to re-ask.
342
- */
343
- probeCapabilities(signal?: AbortSignal, maxAgeMs?: number): Promise<RemoteCapabilities>;
344
- }
345
- /**
346
- * The real launcher: `ssh <alias> <agent> --stdio` through `node:child_process`.
347
- *
348
- * Only this function touches the process API; every test injects its own launcher. stdout carries
349
- * protocol frames only (the agent writes diagnostics to stderr), so stderr is inherited for the
350
- * operator and stdin is the pipe this client owns.
351
- */
352
- export declare const defaultLauncher: AgentLauncher;
353
- //# sourceMappingURL=agent-transport.d.ts.map
@@ -1,206 +0,0 @@
1
- /**
2
- * The `alias` transport: the system OpenSSH client in ControlMaster mode.
3
- *
4
- * Why the system client: it inherits everything the user already configured — `~/.ssh/config`
5
- * aliases, identity files, `ProxyJump`, `known_hosts`, ssh-agent — which is exactly the
6
- * "import type { MultiplexingCache } from './transport.ts';
7
-
8
- import my ssh config and it just works" requirement. Password authentication is not offered
9
- * here (a non-interactive `ssh` must not block on a prompt); the `ssh2` transport covers that.
10
- *
11
- * Remote file bytes travel as base64 over the multiplexed connection, so the plugin needs
12
- * nothing installed on the remote host beyond POSIX `sh`, `base64` and (for version tokens)
13
- * `stat` or `wc`.
14
- *
15
- * @module dsh-remote-workspace/infra/transport/alias-transport
16
- */
17
- import { type RemoteCapabilities } from '../../domain/capability.ts';
18
- import type { HostKeyPolicy } from '../../domain/connection.ts';
19
- import { type ExecRequest, type ExecResult, type ReadFileRangeRequest, type ReadFileRequest, type RemoteFileChunk, type RemoteWriteOutcome, type RemoveRequest, type RenameRequest, type Transport, type TransportState, type WriteFileRangeRequest, type WriteFileRequest } from './transport.ts';
20
- import type { MultiplexingCache } from './transport.ts';
21
- export type { MultiplexingCache } from './transport.ts';
22
- /** One spawned process result as reported by the injected spawner. */
23
- export interface SpawnResult {
24
- readonly code: number;
25
- readonly signal: string | null;
26
- readonly stdout: string;
27
- readonly stderr: string;
28
- /** Whether the spawner cut stdout at the requested cap. */
29
- readonly truncated?: boolean;
30
- /**
31
- * Whether the spawner dropped stderr bytes.
32
- *
33
- * Optional because a spawner is free not to track it; absent means "this spawner cannot say", and the
34
- * transport then reports `false` rather than guessing. `createNodeSpawner` keeps only the first 64 stderr
35
- * chunks, so it **does** drop bytes and must set this.
36
- */
37
- readonly stderrTruncated?: boolean;
38
- /**
39
- * Whether the spawner's **own deadline** ended the process.
40
- *
41
- * Optional because a spawner that has no deadline cannot report it; absent means "this spawner cannot
42
- * say", and the transport then reports `false` rather than blaming a timeout it never observed.
43
- * `createNodeSpawner` kills the child on `timeoutMs` and **does** know, so it sets this.
44
- */
45
- readonly timedOut?: boolean;
46
- }
47
- /** Spawn options honoured by the injected spawner. */
48
- export interface SpawnOptions {
49
- readonly timeoutMs?: number;
50
- readonly signal?: AbortSignal;
51
- readonly stdin?: string;
52
- readonly maxBytes?: number;
53
- /**
54
- * Environment entries merged over the parent's environment for this child only.
55
- *
56
- * Exists for the `SSH_ASKPASS` wiring (`askpass.ts`): a password must reach the `ssh` child without being
57
- * written to a file or interpolated into a command line. Absent means "inherit unchanged", which is what
58
- * every other caller wants.
59
- */
60
- readonly env?: Record<string, string>;
61
- }
62
- /** Injected process spawner (real: `node:child_process`; tests: a scripted fake). */
63
- export type SpawnFn = (argv: readonly string[], options: SpawnOptions) => Promise<SpawnResult>;
64
- /** How connection reuse is behaving for one transport. */
65
- export type MultiplexingMode = 'unknown' | 'master' | 'unsupported' | 'off';
66
- /**
67
- * Remembers hosts whose `ssh` client cannot multiplex.
68
- *
69
- * The measurement that motivates this: the OpenSSH client shipped with Windows fails
70
- * ControlMaster with `getsockname failed: Not a socket`, so retrying the master on every connect
71
- * would cost a failed process per command sequence. See `doc/03-decisions/0006-…`.
72
- */
73
- /** Create an in-memory multiplexing cache (one per process by default). */
74
- export declare function createMultiplexingCache(): MultiplexingCache;
75
- /** Process-wide cache shared by every alias transport. */
76
- export declare const sharedMultiplexingCache: MultiplexingCache;
77
- /**
78
- * Whether a failed `ssh` run failed *because multiplexing is unavailable*, as opposed to a real
79
- * connection problem.
80
- *
81
- * Deliberately narrow: a vanished control socket also mentions "control socket", but that is a
82
- * connection loss (retryable), not "this client cannot multiplex" (permanent for this client).
83
- *
84
- * @param stderr - the failed client's stderr.
85
- * @returns whether the failure indicates missing multiplexing support.
86
- */
87
- export declare function isMultiplexingFailure(stderr: string): boolean;
88
- /** Construction options for the alias transport. */
89
- export interface AliasTransportOptions {
90
- /** Connection id (also the pool key). */
91
- readonly connectionId: string;
92
- /** OpenSSH alias that carries user/port/identity/jump configuration. */
93
- readonly alias: string;
94
- /** Directory holding this plugin's ControlMaster sockets. */
95
- readonly controlDir: string;
96
- /** `ssh` executable; defaults to `ssh` on PATH. */
97
- readonly sshBinary?: string;
98
- /**
99
- * Identity file to pass as `-i`.
100
- *
101
- * The alias transport inherits `~/.ssh/config`, but when the connection **itself** names a key
102
- * (`auth.kind === 'key'`) that key must win: silently ignoring it means the user's explicit choice only
103
- * works if their config happens to agree (found by the agent-path e2e).
104
- */
105
- readonly identityFile?: string;
106
- /** Known-hosts file to pass as `-o UserKnownHostsFile`; omitted means ssh's own default. */
107
- readonly knownHostsFile?: string;
108
- /**
109
- * Remote user to pass as `-l`.
110
- *
111
- * Same reasoning as {@link identityFile}: when the connection names a user, that user must win. Without
112
- * this, `ssh <bare-host>` silently used the **local** username (found by the agent-path e2e: the ladder
113
- * failed with `yerier@host: Permission denied` even though the profile said `root`).
114
- */
115
- readonly user?: string;
116
- readonly hostKeyPolicy?: HostKeyPolicy;
117
- readonly connectTimeoutMs?: number;
118
- readonly commandTimeoutMs?: number;
119
- readonly keepAliveSeconds?: number;
120
- /** When true (default) authentication never prompts. */
121
- readonly batchMode?: boolean;
122
- /**
123
- * Extra environment for every `ssh` child this transport spawns.
124
- *
125
- * The askpass wiring lives here (`askpass.ts`): with a password connection the transport must both stop
126
- * forbidding prompts ({@link batchMode} false) and hand ssh the helper that answers them. Passing it at
127
- * construction means master, command and shutdown invocations all authenticate the same way — the drift
128
- * that a per-call override would reintroduce.
129
- */
130
- readonly env?: Record<string, string>;
131
- /** `auto` (default) probes multiplexing and degrades; `off` never opens a master. */
132
- readonly multiplexing?: 'auto' | 'off';
133
- /** Injected cache so tests stay isolated; defaults to the process-wide cache. */
134
- readonly multiplexingCache?: MultiplexingCache;
135
- /** Injected spawner; the transport never touches `node:child_process` itself. */
136
- readonly spawn: SpawnFn;
137
- /** Injectable clock for diagnostics. */
138
- readonly now?: () => number;
139
- }
140
- interface ParsedReadHeaders {
141
- readonly size: number;
142
- readonly mtime: number;
143
- readonly bodyStart: number;
144
- }
145
- /** System-ssh transport with ControlMaster session reuse. */
146
- export declare class AliasTransport implements Transport {
147
- #private;
148
- readonly id: string;
149
- constructor(options: AliasTransportOptions);
150
- get state(): TransportState;
151
- get capabilities(): RemoteCapabilities;
152
- /** Whether commands share one master connection, and why not when they do not. */
153
- get multiplexing(): MultiplexingMode;
154
- /** Human-readable reason when {@link multiplexing} is `unsupported`. */
155
- multiplexingReason(): string | undefined;
156
- /** Path of this connection's ControlMaster socket. */
157
- controlPath(): string;
158
- /** The argv that establishes (and persists) the multiplexed master connection. */
159
- buildMasterArgv(): readonly string[];
160
- /**
161
- * The argv for one command.
162
- *
163
- * `-S` is only attached when a master connection actually exists: on a client without
164
- * multiplexing it would make every command fail with a socket error.
165
- */
166
- buildCommandArgv(command: string): readonly string[];
167
- /** Establish the connection; concurrent calls share one attempt. */
168
- connect(signal?: AbortSignal): Promise<void>;
169
- /** Close the master connection when one exists. Idempotent. */
170
- dispose(): Promise<void>;
171
- /** Run one remote command. */
172
- exec(request: ExecRequest, signal?: AbortSignal): Promise<ExecResult>;
173
- /** Read a remote file with a version token from the same round trip. */
174
- readFile(request: ReadFileRequest, signal?: AbortSignal): Promise<RemoteFileChunk>;
175
- /** Write a remote file, optionally guarded by the digest of the current content. */
176
- writeFile(request: WriteFileRequest, signal?: AbortSignal): Promise<RemoteWriteOutcome>;
177
- /**
178
- * Read `[offset, offset+maxBytes)` in one round trip.
179
- *
180
- * The command comes from `fs-commands.ts`, the same module the agent transport uses, so a shell offset read
181
- * cannot drift between the two.
182
- */
183
- readFileRange(request: ReadFileRangeRequest, signal?: AbortSignal): Promise<RemoteFileChunk>;
184
- /** Write at `offset`, leaving the earlier bytes untouched (`dd conv=notrunc`). */
185
- writeFileRange(request: WriteFileRangeRequest, signal?: AbortSignal): Promise<RemoteWriteOutcome>;
186
- /** Move a path; a cross-device move fails instead of silently copying. */
187
- rename(request: RenameRequest, signal?: AbortSignal): Promise<void>;
188
- /** Remove a file or (with `recursive`) a directory tree. */
189
- remove(request: RemoveRequest, signal?: AbortSignal): Promise<void>;
190
- /**
191
- * Probe the remote host once and remember the result.
192
- *
193
- * @param signal - cancellation.
194
- * @param maxAgeMs - reuse a previous probe inside this window (default 5 minutes).
195
- * @returns the discovered capabilities.
196
- */
197
- probeCapabilities(signal?: AbortSignal, maxAgeMs?: number): Promise<RemoteCapabilities>;
198
- }
199
- /**
200
- * Parse the header lines emitted by {@link AliasTransport.readFile}.
201
- *
202
- * @param stdout - raw stdout of the read script.
203
- * @returns size, mtime and the base64 body, or `undefined` when the headers are missing.
204
- */
205
- export declare function parseReadHeaders(stdout: string): ParsedReadHeaders | undefined;
206
- //# sourceMappingURL=alias-transport.d.ts.map
@@ -1,20 +0,0 @@
1
- /**
2
- * The real filesystem behind {@link AskpassIo}.
3
- *
4
- * Deliberately tiny and separate, for the same reason `node-spawn.ts` is: the askpass logic is pure and
5
- * testable, and this is the only module that touches a disk. Nothing here ever writes a secret — the
6
- * helper it materialises reads the secret from the environment at run time.
7
- *
8
- * @module dsh-remote-workspace/infra/transport/askpass-fs
9
- */
10
- import type { AskpassIo } from './askpass.ts';
11
- /**
12
- * Build the production {@link AskpassIo}.
13
- *
14
- * The helper lives in a fresh private directory under the OS temp root, named with the plugin's prefix so a
15
- * leftover is recognisable. Files are created `0o600`/`0o700` where the platform supports modes.
16
- *
17
- * @returns a filesystem adapter for {@link createAskpass}.
18
- */
19
- export declare function createAskpassFs(): AskpassIo;
20
- //# sourceMappingURL=askpass-fs.d.ts.map