dsh-over-ssh 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +19 -17
  2. package/agents/agent-manifest.json +6 -6
  3. package/agents/linux-amd64/dsh-over-ssh-agent +0 -0
  4. package/agents/linux-arm64/dsh-over-ssh-agent +0 -0
  5. package/lib/client.js +422 -337
  6. package/lib/file-references.js +92 -35
  7. package/lib/fs.js +295 -113
  8. package/lib/index.js +6912 -4330
  9. package/lib/terminal-wrapper.js +9 -4
  10. package/lib/types/src/config.d.ts +156 -9
  11. package/lib/types/src/file-references.d.ts +0 -1
  12. package/lib/types/src/host/app/backend.d.ts +44 -3
  13. package/lib/types/src/host/app/recycle-bin/recycle-bin-contract.d.ts +0 -1
  14. package/lib/types/src/host/app/recycle-bin/recycle-bin-service.d.ts +0 -1
  15. package/lib/types/src/host/app/session-admin/session-admin-contract.d.ts +12 -1
  16. package/lib/types/src/host/app/session-admin/session-admin-service.d.ts +0 -1
  17. package/lib/types/src/host/app/transport/transport-selector.d.ts +0 -1
  18. package/lib/types/src/host/app/transport/transport-service.d.ts +0 -1
  19. package/lib/types/src/host/domain/capability.d.ts +0 -1
  20. package/lib/types/src/host/domain/errors.d.ts +0 -1
  21. package/lib/types/src/host/domain/roots/connection.d.ts +0 -1
  22. package/lib/types/src/host/domain/roots/root.d.ts +24 -9
  23. package/lib/types/src/host/domain/roots/session-roots.d.ts +23 -1
  24. package/lib/types/src/host/domain/roots/ssh-config.d.ts +0 -1
  25. package/lib/types/src/host/domain/session/session-admin.d.ts +0 -1
  26. package/lib/types/src/host/domain/transfer/recycle-bin.d.ts +0 -1
  27. package/lib/types/src/host/domain/transfer/transfer.d.ts +0 -1
  28. package/lib/types/src/host/infra/transport/agent/agent-installer.d.ts +0 -1
  29. package/lib/types/src/host/infra/transport/forward.d.ts +75 -0
  30. package/lib/types/src/host/infra/transport/ssh/ssh2-transport.d.ts +5 -1
  31. package/lib/types/src/host/infra/transport/transport-base.d.ts +0 -1
  32. package/lib/types/src/host/infra/transport/transport.d.ts +42 -2
  33. package/lib/types/src/host/integration/agent/agent-preflight.d.ts +0 -1
  34. package/lib/types/src/host/integration/fs/file-reference-provider.d.ts +0 -1
  35. package/lib/types/src/host/integration/fs/fs-provider.d.ts +18 -3
  36. package/lib/types/src/host/integration/transfer/transfer-service.d.ts +0 -1
  37. package/lib/types/src/index.d.ts +23 -1
  38. package/lib/types/src/local-bridge-refs.d.ts +0 -1
  39. package/lib/types/src/local-bridge.d.ts +0 -1
  40. package/lib/types/src/shared/root-keys.d.ts +120 -0
  41. package/lib/types/src/wiring/helpers.d.ts +0 -1
  42. package/package.json +5 -3
  43. package/lib/types/src/client/controls.d.ts +0 -131
  44. package/lib/types/src/client/core/card-focus-trap.d.ts +0 -45
  45. package/lib/types/src/client/core/controls.d.ts +0 -164
  46. package/lib/types/src/client/core/latest.d.ts +0 -48
  47. package/lib/types/src/client/core/locale.d.ts +0 -38
  48. package/lib/types/src/client/core/message.d.ts +0 -37
  49. package/lib/types/src/client/core/panel-model.d.ts +0 -134
  50. package/lib/types/src/client/core/portal.d.ts +0 -266
  51. package/lib/types/src/client/core/remote.d.ts +0 -84
  52. package/lib/types/src/client/core/styles.d.ts +0 -458
  53. package/lib/types/src/client/file-tree-io.d.ts +0 -19
  54. package/lib/types/src/client/file-tree.d.ts +0 -271
  55. package/lib/types/src/client/flows/directory-browser.d.ts +0 -587
  56. package/lib/types/src/client/flows/session-directory.d.ts +0 -415
  57. package/lib/types/src/client/flows/workspace-directory-flow.d.ts +0 -480
  58. package/lib/types/src/client/locale.d.ts +0 -31
  59. package/lib/types/src/client/panel-model.d.ts +0 -37
  60. package/lib/types/src/client/panel.d.ts +0 -77
  61. package/lib/types/src/client/roots/connection-test.d.ts +0 -69
  62. package/lib/types/src/client/roots/roots-panel-state.d.ts +0 -307
  63. package/lib/types/src/client/roots/roots-panel-view.d.ts +0 -280
  64. package/lib/types/src/client/roots/roots-panel.d.ts +0 -364
  65. package/lib/types/src/client/roots/transfer-panel-view.d.ts +0 -35
  66. package/lib/types/src/client/roots/transfer-panel.d.ts +0 -241
  67. package/lib/types/src/client/roots/transfer-progress.d.ts +0 -67
  68. package/lib/types/src/client/roots-panel-view.d.ts +0 -236
  69. package/lib/types/src/client/roots-panel.d.ts +0 -347
  70. package/lib/types/src/client/session/session-panel-view.d.ts +0 -336
  71. package/lib/types/src/client/session/session-panel.d.ts +0 -322
  72. package/lib/types/src/client/session/session-remote-mark.d.ts +0 -110
  73. package/lib/types/src/client/session/session-row-actions.d.ts +0 -398
  74. package/lib/types/src/client/session-panel.d.ts +0 -152
  75. package/lib/types/src/client/styles.d.ts +0 -252
  76. package/lib/types/src/client/workspace-directory-flow.d.ts +0 -342
  77. package/lib/types/src/fs.d.ts +0 -46
  78. package/lib/types/src/host/app/recycle-bin/recycle-bin-move.d.ts +0 -18
  79. package/lib/types/src/host/app/recycle-bin/recycle-bin-world.d.ts +0 -38
  80. package/lib/types/src/host/app/recycle-bin-contract.d.ts +0 -215
  81. package/lib/types/src/host/app/recycle-bin-move.d.ts +0 -18
  82. package/lib/types/src/host/app/recycle-bin-service.d.ts +0 -45
  83. package/lib/types/src/host/app/recycle-bin-world.d.ts +0 -35
  84. package/lib/types/src/host/app/roots/roots-api-connections.d.ts +0 -49
  85. package/lib/types/src/host/app/roots/roots-api-contract.d.ts +0 -369
  86. package/lib/types/src/host/app/roots/roots-api-directories.d.ts +0 -13
  87. package/lib/types/src/host/app/roots/roots-api-http.d.ts +0 -77
  88. package/lib/types/src/host/app/roots/roots-api-long-poll.d.ts +0 -130
  89. package/lib/types/src/host/app/roots/roots-api-projections.d.ts +0 -102
  90. package/lib/types/src/host/app/roots/roots-api-roots.d.ts +0 -13
  91. package/lib/types/src/host/app/roots/roots-api-state.d.ts +0 -22
  92. package/lib/types/src/host/app/roots/roots-api-transfers.d.ts +0 -26
  93. package/lib/types/src/host/app/roots/roots-api.d.ts +0 -55
  94. package/lib/types/src/host/app/roots/user-roots.d.ts +0 -552
  95. package/lib/types/src/host/app/roots-api-connections.d.ts +0 -49
  96. package/lib/types/src/host/app/roots-api-contract.d.ts +0 -339
  97. package/lib/types/src/host/app/roots-api-directories.d.ts +0 -13
  98. package/lib/types/src/host/app/roots-api-http.d.ts +0 -77
  99. package/lib/types/src/host/app/roots-api-projections.d.ts +0 -102
  100. package/lib/types/src/host/app/roots-api-roots.d.ts +0 -13
  101. package/lib/types/src/host/app/roots-api-state.d.ts +0 -22
  102. package/lib/types/src/host/app/roots-api-support.d.ts +0 -182
  103. package/lib/types/src/host/app/roots-api-transfers.d.ts +0 -13
  104. package/lib/types/src/host/app/roots-api.d.ts +0 -55
  105. package/lib/types/src/host/app/routed-fs.d.ts +0 -239
  106. package/lib/types/src/host/app/serialize.d.ts +0 -37
  107. package/lib/types/src/host/app/session-admin/session-admin-context.d.ts +0 -36
  108. package/lib/types/src/host/app/session-admin/session-admin-delete.d.ts +0 -34
  109. package/lib/types/src/host/app/session-admin-context.d.ts +0 -36
  110. package/lib/types/src/host/app/session-admin-contract.d.ts +0 -214
  111. package/lib/types/src/host/app/session-admin-delete.d.ts +0 -34
  112. package/lib/types/src/host/app/session-admin-service.d.ts +0 -38
  113. package/lib/types/src/host/app/takeover/takeover-plan.d.ts +0 -227
  114. package/lib/types/src/host/app/takeover/takeover-rows.d.ts +0 -55
  115. package/lib/types/src/host/app/transport-selector.d.ts +0 -98
  116. package/lib/types/src/host/app/transport-service.d.ts +0 -75
  117. package/lib/types/src/host/app/user-roots.d.ts +0 -461
  118. package/lib/types/src/host/domain/bin-location.d.ts +0 -79
  119. package/lib/types/src/host/domain/connection.d.ts +0 -95
  120. package/lib/types/src/host/domain/glob-pattern.d.ts +0 -62
  121. package/lib/types/src/host/domain/literal-text.d.ts +0 -63
  122. package/lib/types/src/host/domain/path-grammar.d.ts +0 -84
  123. package/lib/types/src/host/domain/recycle-bin.d.ts +0 -337
  124. package/lib/types/src/host/domain/root.d.ts +0 -74
  125. package/lib/types/src/host/domain/roots/bin-location.d.ts +0 -91
  126. package/lib/types/src/host/domain/roots/route-table.d.ts +0 -102
  127. package/lib/types/src/host/domain/route-table.d.ts +0 -80
  128. package/lib/types/src/host/domain/session/terminal-target.d.ts +0 -136
  129. package/lib/types/src/host/domain/session-admin.d.ts +0 -330
  130. package/lib/types/src/host/domain/shell.d.ts +0 -47
  131. package/lib/types/src/host/domain/ssh-config.d.ts +0 -73
  132. package/lib/types/src/host/domain/terminal-target.d.ts +0 -132
  133. package/lib/types/src/host/domain/tool-requests.d.ts +0 -369
  134. package/lib/types/src/host/domain/transfer.d.ts +0 -260
  135. package/lib/types/src/host/infra/backend/local-backend.d.ts +0 -84
  136. package/lib/types/src/host/infra/backend/local-version.d.ts +0 -43
  137. package/lib/types/src/host/infra/backend/platform-local-backend.d.ts +0 -89
  138. package/lib/types/src/host/infra/backend/remote-backend.d.ts +0 -239
  139. package/lib/types/src/host/infra/cache/lru.d.ts +0 -52
  140. package/lib/types/src/host/infra/cache/versioned.d.ts +0 -77
  141. package/lib/types/src/host/infra/temp-name.d.ts +0 -19
  142. package/lib/types/src/host/infra/transport/agent/agent-protocol-client.d.ts +0 -132
  143. package/lib/types/src/host/infra/transport/agent/agent-protocol-codec.d.ts +0 -140
  144. package/lib/types/src/host/infra/transport/agent/agent-protocol-errors.d.ts +0 -41
  145. package/lib/types/src/host/infra/transport/agent/agent-protocol-frames.d.ts +0 -197
  146. package/lib/types/src/host/infra/transport/agent/agent-protocol-types.d.ts +0 -564
  147. package/lib/types/src/host/infra/transport/agent/agent-transport.d.ts +0 -418
  148. package/lib/types/src/host/infra/transport/agent-installer.d.ts +0 -121
  149. package/lib/types/src/host/infra/transport/agent-protocol-client.d.ts +0 -123
  150. package/lib/types/src/host/infra/transport/agent-protocol-codec.d.ts +0 -131
  151. package/lib/types/src/host/infra/transport/agent-protocol-errors.d.ts +0 -41
  152. package/lib/types/src/host/infra/transport/agent-protocol-frames.d.ts +0 -197
  153. package/lib/types/src/host/infra/transport/agent-protocol-types.d.ts +0 -509
  154. package/lib/types/src/host/infra/transport/agent-transport.d.ts +0 -353
  155. package/lib/types/src/host/infra/transport/alias-transport.d.ts +0 -206
  156. package/lib/types/src/host/infra/transport/askpass-fs.d.ts +0 -20
  157. package/lib/types/src/host/infra/transport/askpass.d.ts +0 -133
  158. package/lib/types/src/host/infra/transport/command-pool.d.ts +0 -61
  159. package/lib/types/src/host/infra/transport/fs-commands.d.ts +0 -140
  160. package/lib/types/src/host/infra/transport/git-status-route.d.ts +0 -63
  161. package/lib/types/src/host/infra/transport/git-status.d.ts +0 -101
  162. package/lib/types/src/host/infra/transport/node-spawn.d.ts +0 -26
  163. package/lib/types/src/host/infra/transport/session-window.d.ts +0 -51
  164. package/lib/types/src/host/infra/transport/shell-quote.d.ts +0 -59
  165. package/lib/types/src/host/infra/transport/ssh/alias-transport.d.ts +0 -206
  166. package/lib/types/src/host/infra/transport/ssh/askpass-fs.d.ts +0 -20
  167. package/lib/types/src/host/infra/transport/ssh/askpass.d.ts +0 -133
  168. package/lib/types/src/host/infra/transport/ssh/shell-quote.d.ts +0 -62
  169. package/lib/types/src/host/infra/transport/ssh/ssh-argv.d.ts +0 -43
  170. package/lib/types/src/host/infra/transport/ssh-argv.d.ts +0 -43
  171. package/lib/types/src/host/infra/transport/ssh2-transport.d.ts +0 -302
  172. package/lib/types/src/host/integration/agent/agent-install-io.d.ts +0 -33
  173. package/lib/types/src/host/integration/agent/askpass-registry.d.ts +0 -66
  174. package/lib/types/src/host/integration/agent-install-io.d.ts +0 -33
  175. package/lib/types/src/host/integration/agent-preflight.d.ts +0 -56
  176. package/lib/types/src/host/integration/anchor-directory.d.ts +0 -56
  177. package/lib/types/src/host/integration/askpass-registry.d.ts +0 -59
  178. package/lib/types/src/host/integration/bin-root-resolver.d.ts +0 -81
  179. package/lib/types/src/host/integration/connection-test.d.ts +0 -73
  180. package/lib/types/src/host/integration/file-reference-provider.d.ts +0 -115
  181. package/lib/types/src/host/integration/fs/git-status-wiring.d.ts +0 -21
  182. package/lib/types/src/host/integration/fs/platform-errors.d.ts +0 -94
  183. package/lib/types/src/host/integration/fs/remote-file-tools.d.ts +0 -369
  184. package/lib/types/src/host/integration/fs/remote-index.d.ts +0 -177
  185. package/lib/types/src/host/integration/fs-provider.d.ts +0 -226
  186. package/lib/types/src/host/integration/lsp/lsp-framing.d.ts +0 -38
  187. package/lib/types/src/host/integration/lsp/lsp-registry.d.ts +0 -67
  188. package/lib/types/src/host/integration/lsp/lsp-session.d.ts +0 -130
  189. package/lib/types/src/host/integration/management-tools.d.ts +0 -64
  190. package/lib/types/src/host/integration/recycle-bin-service.d.ts +0 -247
  191. package/lib/types/src/host/integration/remote/connection-test.d.ts +0 -73
  192. package/lib/types/src/host/integration/remote/remote-face.d.ts +0 -127
  193. package/lib/types/src/host/integration/remote/remote-tool-backend.d.ts +0 -108
  194. package/lib/types/src/host/integration/remote-face.d.ts +0 -127
  195. package/lib/types/src/host/integration/remote-file-tools.d.ts +0 -241
  196. package/lib/types/src/host/integration/remote-home.d.ts +0 -69
  197. package/lib/types/src/host/integration/remote-index.d.ts +0 -165
  198. package/lib/types/src/host/integration/remote-job-tools.d.ts +0 -295
  199. package/lib/types/src/host/integration/remote-tool-backend.d.ts +0 -97
  200. package/lib/types/src/host/integration/remote-tools.d.ts +0 -206
  201. package/lib/types/src/host/integration/root-registry.d.ts +0 -115
  202. package/lib/types/src/host/integration/roots/anchor-directory.d.ts +0 -56
  203. package/lib/types/src/host/integration/roots/bin-root-resolver.d.ts +0 -81
  204. package/lib/types/src/host/integration/roots/remote-home.d.ts +0 -69
  205. package/lib/types/src/host/integration/roots/root-registry.d.ts +0 -144
  206. package/lib/types/src/host/integration/roots/roots-wiring.d.ts +0 -219
  207. package/lib/types/src/host/integration/roots/session-root-index.d.ts +0 -52
  208. package/lib/types/src/host/integration/roots-api.d.ts +0 -407
  209. package/lib/types/src/host/integration/roots-wiring.d.ts +0 -211
  210. package/lib/types/src/host/integration/session/session-api.d.ts +0 -88
  211. package/lib/types/src/host/integration/session/session-bin-lock.d.ts +0 -80
  212. package/lib/types/src/host/integration/session/session-header.d.ts +0 -151
  213. package/lib/types/src/host/integration/session/session-labels.d.ts +0 -56
  214. package/lib/types/src/host/integration/session/session-route-wiring.d.ts +0 -50
  215. package/lib/types/src/host/integration/session-admin-service.d.ts +0 -236
  216. package/lib/types/src/host/integration/session-api.d.ts +0 -81
  217. package/lib/types/src/host/integration/session-bin-lock.d.ts +0 -80
  218. package/lib/types/src/host/integration/session-header.d.ts +0 -118
  219. package/lib/types/src/host/integration/session-labels.d.ts +0 -56
  220. package/lib/types/src/host/integration/session-route-wiring.d.ts +0 -50
  221. package/lib/types/src/host/integration/session-scope.d.ts +0 -113
  222. package/lib/types/src/host/integration/session-tools.d.ts +0 -44
  223. package/lib/types/src/host/integration/strict-arguments.d.ts +0 -79
  224. package/lib/types/src/host/integration/takeover/takeover-api.d.ts +0 -62
  225. package/lib/types/src/host/integration/takeover/takeover-route-wiring.d.ts +0 -60
  226. package/lib/types/src/host/integration/takeover/takeover-service.d.ts +0 -167
  227. package/lib/types/src/host/integration/terminal-manifest.d.ts +0 -94
  228. package/lib/types/src/host/integration/tools/management-tools.d.ts +0 -245
  229. package/lib/types/src/host/integration/tools/remote-job-tools.d.ts +0 -316
  230. package/lib/types/src/host/integration/tools/remote-lsp-tools.d.ts +0 -43
  231. package/lib/types/src/host/integration/tools/remote-tools.d.ts +0 -236
  232. package/lib/types/src/host/integration/tools/session-target.d.ts +0 -52
  233. package/lib/types/src/host/integration/tools/session-tools.d.ts +0 -46
  234. package/lib/types/src/host/integration/tools/strict-arguments.d.ts +0 -79
  235. package/lib/types/src/host/integration/tools/terminal-manifest.d.ts +0 -94
  236. package/lib/types/src/host/integration/transfer/remote-copy.d.ts +0 -66
  237. package/lib/types/src/host/integration/transfer/transfer-adapters.d.ts +0 -48
  238. package/lib/types/src/host/integration/transfer/transfer-tracker.d.ts +0 -106
  239. package/lib/types/src/host/integration/transfer-adapters.d.ts +0 -44
  240. package/lib/types/src/host/integration/transfer-service.d.ts +0 -164
  241. package/lib/types/src/host/integration/transfer-tracker.d.ts +0 -106
  242. package/lib/types/src/host/integration/user-roots.d.ts +0 -461
  243. package/lib/types/src/wiring/connections.d.ts +0 -189
  244. package/lib/types/src/wiring/fs.d.ts +0 -13
  245. package/lib/types/src/wiring/install-memo.d.ts +0 -32
  246. package/lib/types/src/wiring/legacy-dirs.d.ts +0 -62
  247. package/lib/types/src/wiring/package-paths.d.ts +0 -35
  248. package/lib/types/src/wiring/roots.d.ts +0 -21
  249. package/lib/types/src/wiring/state-dir.d.ts +0 -29
  250. package/lib/types/src/wiring/tools.d.ts +0 -35
@@ -1,132 +0,0 @@
1
- /**
2
- * Which terminal a session gets: the remote host, or the local machine.
3
- *
4
- * The platform's only official extension point for the Web terminal is `terminalController.Config.shell`
5
- * (`{ path, name, args }`), so this plugin ships a **wrapper** as that shell: the wrapper decides at launch
6
- * time whether to `exec ssh` or the local login shell. See `doc/02-platform/terminal.md` §5 for the evidence
7
- * and the accepted costs.
8
- *
9
- * This module is the decision itself, kept pure (no filesystem, no spawn) so it can be tested in
10
- * milliseconds — the wrapper script is a thin `spawn` around it.
11
- *
12
- * Two inputs decide it, in this order:
13
- *
14
- * 1. **the session's recorded target** (`state/<sessionId>.json`): the host writes it when it resolves a
15
- * remote root for that session, so it works even when the core hands us an unrelated cwd;
16
- * 2. **the root manifest** (`roots.json`): a directory→connection map, used when the wrapper has no session
17
- * id (a terminal opened by hand) — a cwd under a remote root's anchor means the user is working remotely.
18
- *
19
- * @module dsh-remote-workspace/domain/terminal-target
20
- */
21
- /** How the wrapper reaches a connection's host: pre-built ssh arguments the host already resolved. */
22
- export interface SshInvocation {
23
- /** `user@host` or a `~/.ssh/config` alias. */
24
- readonly destination: string;
25
- /** Extra arguments (`-i`, `-o UserKnownHostsFile=…`, `-p`, jump options…), already credential-resolved. */
26
- readonly args: readonly string[];
27
- }
28
- /** One remote root as the wrapper needs it. */
29
- export interface ManifestRoot {
30
- readonly connectionId: string;
31
- /** Backend-absolute remote path (POSIX). */
32
- readonly remoteRoot: string;
33
- /** Local anchor directory that maps to this remote root. */
34
- readonly anchorPath: string;
35
- /** How to reach the host. */
36
- readonly ssh: SshInvocation;
37
- }
38
- /** The root manifest the host writes for the wrapper. */
39
- export interface RootManifest {
40
- /** Manifest format version; a wrapper that does not know the version falls back to local. */
41
- readonly version: number;
42
- readonly roots: readonly ManifestRoot[];
43
- }
44
- /** One session's recorded remote target. */
45
- export interface SessionState {
46
- readonly sessionId: string;
47
- readonly connectionId: string;
48
- readonly remoteRoot: string;
49
- readonly ssh: SshInvocation;
50
- /** Epoch milliseconds; the wrapper ignores entries older than {@link SESSION_STATE_MAX_AGE_MS}. */
51
- readonly recordedAt: number;
52
- }
53
- /** Current manifest version. */
54
- export declare const MANIFEST_VERSION = 1;
55
- /** A session state older than this is ignored (a stale file must not send the user to the wrong host). */
56
- export declare const SESSION_STATE_MAX_AGE_MS: number;
57
- /** The decision the wrapper acts on. */
58
- export type TerminalDecision = {
59
- readonly kind: 'remote';
60
- readonly connectionId: string;
61
- readonly remoteRoot: string;
62
- /** Full argv to spawn: `[ssh, -tt, …args, destination, --, command]`. */
63
- readonly argv: readonly string[];
64
- /** Remote command: `cd <root> && exec <login shell> -l`. */
65
- readonly remoteCommand: string;
66
- /** Why this decision was taken (for diagnostics and tests). */
67
- readonly reason: 'session' | 'anchor';
68
- } | {
69
- readonly kind: 'local';
70
- /** Full argv to spawn: the local login shell. */
71
- readonly argv: readonly string[];
72
- readonly reason: 'no-target' | 'state-unusable' | 'manifest-unusable';
73
- };
74
- /** Options for {@link decideTerminal}. */
75
- export interface DecideTerminalOptions {
76
- /** Working directory the terminal was launched in. */
77
- readonly cwd: string;
78
- /** Manifest, when readable and valid. */
79
- readonly manifest?: RootManifest;
80
- /** This session's state, when readable and valid. */
81
- readonly sessionState?: SessionState;
82
- /** Local login shell to fall back to (platform default resolved by the caller). */
83
- readonly localShell: string;
84
- /** Remote login shell; `$SHELL` expands remotely, which is the right default. */
85
- readonly remoteShell?: string;
86
- /** Clock, injected for the staleness check. */
87
- readonly now?: number;
88
- }
89
- /** Quote one word for a POSIX shell (single quotes). */
90
- export declare function posixQuote(value: string): string;
91
- /** Whether a path is the anchor itself or lives under it. */
92
- export declare function isUnder(candidate: string, directory: string): boolean;
93
- /**
94
- * Parse a root manifest.
95
- *
96
- * @param raw - file contents.
97
- * @returns the manifest, or `undefined` when it is unusable (wrong version, malformed, empty).
98
- */
99
- export declare function parseRootManifest(raw: string): RootManifest | undefined;
100
- /**
101
- * Parse one session state file.
102
- *
103
- * @param raw - file contents.
104
- * @returns the state, or `undefined` when malformed.
105
- */
106
- export declare function parseSessionState(raw: string): SessionState | undefined;
107
- /** Serialize a manifest for the wrapper (stable key order, so the file diff is readable). */
108
- export declare function serializeRootManifest(manifest: RootManifest): string;
109
- /** Serialize one session state. */
110
- export declare function serializeSessionState(state: SessionState): string;
111
- /** Build the command the remote shell runs: enter the workspace and be a login shell. */
112
- export declare function remoteCommandFor(remoteRoot: string, remoteShell?: string): string;
113
- /**
114
- * Build the ssh argv for one remote target.
115
- *
116
- * `-tt` is what makes an interactive terminal work through the wrapper (the child needs a TTY on both
117
- * sides). `--` ends option parsing before the destination, and the remote command is a single argument.
118
- *
119
- * @param ssh - resolved destination and credential arguments.
120
- * @param remoteCommand - command to run remotely.
121
- * @returns the argv to spawn.
122
- */
123
- export declare function sshArgvFor(ssh: SshInvocation, remoteCommand: string): readonly string[];
124
- /**
125
- * Decide which terminal to open.
126
- *
127
- * @param options - cwd, manifest, session state, local shell, clock.
128
- * @returns the decision, always total (never throws): an unusable input degrades to the local shell, with
129
- * `reason` naming why.
130
- */
131
- export declare function decideTerminal(options: DecideTerminalOptions): TerminalDecision;
132
- //# sourceMappingURL=terminal-target.d.ts.map
@@ -1,369 +0,0 @@
1
- /**
2
- * Pure request/response logic for the remote tools.
3
- *
4
- * Kept in the domain layer on purpose (AGENTS.md 红线 2): no `@deepseek-ai/*` import, so command building,
5
- * argument clamping and output parsing are all testable offline, in milliseconds, with no transport.
6
- *
7
- * Everything here is **bounded**: a tool call is model-driven, so an unbounded `grep` or `exec` would let a
8
- * single call read an entire remote disk. Caps are part of the contract, and hitting one is *reported*
9
- * (`truncated`) rather than silently obeyed.
10
- *
11
- * **One path rule for the whole tool family** (audit 0052): {@link resolveUnderRoot} is the only place that
12
- * turns a model-supplied spelling into a remote path. Both spellings are accepted — an absolute path must be
13
- * inside the root (an outside one is *refused*, never silently re-rooted) and a relative path is resolved
14
- * against the root, where `..` folds but cannot climb out. `joinUnderRoot` is the legacy folder kept for the
15
- * transfer layer; it is now idempotent for in-root absolute paths so a resolved path cannot be prefixed twice
16
- * (that doubling was the cause of `remote_exec { cwd: "<the root itself>/..." }` failing).
17
- *
18
- * @module dsh-over-ssh/domain/tool-requests
19
- */
20
- import { quote } from './shell.ts';
21
- /** Cap on matches returned by one search. */
22
- export declare const MAX_GREP_RESULTS = 200;
23
- /** Cap on paths returned by one glob. */
24
- export declare const MAX_GLOB_RESULTS = 500;
25
- /** Cap on bytes of one command's output handed back to the model. */
26
- export declare const MAX_OUTPUT_BYTES: number;
27
- /** Default cooperative timeout for a remote command. */
28
- export declare const DEFAULT_EXEC_TIMEOUT_MS = 30000;
29
- /** Hard ceiling for a model-requested command timeout. */
30
- export declare const MAX_EXEC_TIMEOUT_MS = 300000;
31
- /**
32
- * Cap on environment entries one command may carry.
33
- *
34
- * A bound rather than a silent trim: the whole point of `env` is that the caller can see what it asked
35
- * for, so an oversized map is refused by name instead of having entries quietly dropped.
36
- */
37
- export declare const MAX_EXEC_ENV_ENTRIES = 64;
38
- /** A search request, after validation. */
39
- export interface GrepRequest {
40
- /** Pattern text (literal or regular expression). */
41
- readonly pattern: string;
42
- /** Directory to search; a root-relative or in-root absolute spelling, `undefined` means the root itself. */
43
- readonly path: string | undefined;
44
- /** Whether `pattern` is a regular expression. */
45
- readonly regex: boolean;
46
- /**
47
- * Whether matching distinguishes case. Default `false`, matching the agent's wire default
48
- * (`caseSensitive: false`) — the two tiers must not disagree about one tool call.
49
- */
50
- readonly caseSensitive?: boolean | undefined;
51
- /**
52
- * Whether ignore rules are dropped: VCS ignores (`.gitignore`) **and** {@link DEFAULT_EXCLUDE_DIRS}.
53
- * Default `false`.
54
- *
55
- * The tiers can only do part of this, and the split is deliberate rather than silent: Tier 2 (the agent)
56
- * stops applying both, while Tier 1's `grep` never read `.gitignore` at all, so there the flag controls
57
- * only the noise-directory list. `tests/remote-tool-backend.test.ts` pins that both tiers receive the same
58
- * intent, and the residual difference is stated in `remote_grep`'s description.
59
- */
60
- readonly noIgnore?: boolean | undefined;
61
- /** Filename filters, symmetric with the agent's `search.grep` `exclude`. */
62
- readonly include?: readonly string[] | undefined;
63
- readonly maxResults: number;
64
- }
65
- /** A glob request, after validation. */
66
- export interface GlobRequest {
67
- /** Substring or suffix to match against enumerated paths. */
68
- readonly pattern: string;
69
- /** Directory to enumerate; a root-relative or in-root absolute spelling, `undefined` means the root itself. */
70
- readonly path: string | undefined;
71
- readonly maxResults: number;
72
- }
73
- /** A command request, after validation. */
74
- export interface ExecRequest {
75
- readonly command: string;
76
- /** Working directory; a root-relative or in-root absolute spelling, `undefined` means the root itself. */
77
- readonly cwd: string | undefined;
78
- /** Environment assignments applied to this command only; `undefined` when none were requested. */
79
- readonly env?: Readonly<Record<string, string>> | undefined;
80
- readonly timeoutMs: number;
81
- }
82
- /** One search hit. */
83
- export interface GrepHit {
84
- readonly path: string;
85
- /** 1-based line number. */
86
- readonly line: number;
87
- readonly text: string;
88
- }
89
- /** Search outcome; `truncated` is set when a cap was hit. */
90
- export interface GrepOutcome {
91
- readonly matches: readonly GrepHit[];
92
- readonly truncated: boolean;
93
- /** Which tier answered (`agent` or the shell strategy). */
94
- readonly strategy: string;
95
- /** Why the search stopped early, when the answering tier can say (audit 0052 P7). */
96
- readonly truncation?: SearchTruncation | undefined;
97
- }
98
- /** Text plus the fact that something was cut. */
99
- export interface BoundedText {
100
- readonly text: string;
101
- readonly truncated: boolean;
102
- }
103
- /**
104
- * Normalize a caller-supplied permission spelling into the octal digit string `chmod` takes.
105
- *
106
- * A number is read as **octal digits**, because that is what a caller who writes `755` means; a string may
107
- * also carry the `0o` prefix. Everything else — `"rwxr-xr-x"`, `"8"`, `true`, `""` — is refused rather than
108
- * guessed: quietly ignoring a requested mode is precisely the class of failure this round removes, and a
109
- * wrong-but-accepted mode on a build script is worse than a refusal.
110
- *
111
- * @param value - the raw `mode` argument.
112
- * @returns the normalized 3-4 digit octal string, or an error naming the accepted forms.
113
- */
114
- export declare function fileModeArg(value: unknown): {
115
- readonly mode: string | undefined;
116
- } | {
117
- readonly error: string;
118
- };
119
- /**
120
- * Cap on filename filters one search may carry.
121
- *
122
- * Bounded for the same reason every other cap here is: the filters become `--include` argv words in the
123
- * shell strategy, so an unbounded list is an unbounded command line.
124
- */
125
- export declare const MAX_GREP_INCLUDES = 16;
126
- /**
127
- * The noise directory names a search excludes by default.
128
- *
129
- * **This mirrors `dsh-over-ssh-agent/internal/index/scan.go`'s `DefaultExcludes`.** The duplication is forced:
130
- * Tier 1 is a plain `grep` with no agent to ask, so it has to name the same directories itself, or the same
131
- * tool call would search a different file set depending on which tier answered — the disagreement this
132
- * module already refuses to allow for case sensitivity.
133
- *
134
- * Two consequences are deliberate:
135
- * - the list is pinned **verbatim by a test**, so editing it is always an explicit act rather than drift;
136
- * - keeping the two copies equal is a cross-repository obligation that no test in this repository can
137
- * mechanically enforce. Audit 0064 records the debt, with the Go side as the source of truth.
138
- */
139
- export declare const DEFAULT_EXCLUDE_DIRS: readonly string[];
140
- /** Merge a requested sub-path with the root, refusing to escape it. */
141
- export declare function joinUnderRoot(root: string, path: string | undefined): string;
142
- /**
143
- * Resolve a model-supplied path spelling into one remote path inside `root`.
144
- *
145
- * **One rule for the whole tool family** (`remote_exec.cwd`, `remote_grep.path`, `remote_glob.path`,
146
- * `remote_delete.path`, and the file tools built on top): both spellings are accepted, and the two differ
147
- * only in what an out-of-root request means.
148
- *
149
- * - **Absolute** (`/…`): normalized, then required to be `root` itself or below it. An outside path is
150
- * **refused** with a message naming both the path and the root. It is never silently re-rooted — that
151
- * silent re-rooting is what turned `cwd: "/tmp"` into `<root>/tmp` and made the remote `chdir` fail with
152
- * a message about `/bin/sh` (audit 0052 P1), and it is what doubled a fully-qualified in-root path.
153
- * - **Relative**: folded onto `cwd` (itself resolved by this same function) or onto `root`, with `.`
154
- * dropped and `..` popping. `..` **cannot climb out of the root**: extra leading `..` are ignored, which
155
- * is the pre-existing, deliberately-kept clamp behaviour (audit 0052 P1.3). It also cannot climb above
156
- * `root` from a `cwd`, so `cwd: "src", path: "../../etc"` still lands in `<root>/etc`.
157
- *
158
- * A path that is empty/blank means the root itself. `cwd` is ignored for an absolute `path`.
159
- *
160
- * An `ssh://<connection>/<absolute>` spelling is accepted **when it names the connection this call runs
161
- * on** (`connectionId`). Its own refusal message used to recommend that spelling while the parser did not
162
- * understand it, so a caller who followed the advice got `E_NOT_FOUND` (audit 0064 P2). A reference to a
163
- * *different* connection is refused by name: these tools are bound to one remote root, and silently
164
- * re-rooting into another host's tree is exactly the kind of guess this module refuses to make.
165
- *
166
- * @param root - absolute remote root directory.
167
- * @param path - requested spelling, absolute, root-relative, or `ssh://`-qualified.
168
- * @param cwd - optional root-relative directory the relative spelling is resolved against.
169
- * @param connectionId - the connection this call targets; required to accept an `ssh://` spelling.
170
- * @returns the resolved root-absolute path, or an object whose `error` explains the refusal.
171
- */
172
- export declare function resolveUnderRoot(root: string, path: string, cwd?: string, connectionId?: string): string | {
173
- readonly error: string;
174
- };
175
- /**
176
- * Validate search arguments.
177
- *
178
- * @param args - model arguments, however malformed.
179
- * @returns the request, or an error message naming the offending field.
180
- */
181
- export declare function parseGrepArgs(args: unknown): GrepRequest | {
182
- readonly error: string;
183
- };
184
- /** Validate glob arguments (same shape as search minus `regex`). */
185
- export declare function parseGlobArgs(args: unknown): GlobRequest | {
186
- readonly error: string;
187
- };
188
- /** Validate command arguments. */
189
- export declare function parseExecArgs(args: unknown): ExecRequest | {
190
- readonly error: string;
191
- };
192
- /** Whether a parse result is an error. */
193
- export declare function isToolArgError(value: {
194
- readonly error: string;
195
- } | object): value is {
196
- readonly error: string;
197
- };
198
- /**
199
- * Quote one shell word safely (single quotes, POSIX).
200
- *
201
- * Re-exported from {@link ./shell.ts} rather than implemented here: this file builds `grep` command lines,
202
- * and the same quoting is needed by the ssh transports and the terminal wrapper. There used to be three
203
- * copies and only one of them refused NUL.
204
- */
205
- export { quote };
206
- /**
207
- * Tier 1 search command: one bounded `grep -rn` (no ripgrep on the benchmark host).
208
- *
209
- * `-I` skips binaries, `-n` gives line numbers, `-E`/`-F` switch regex/literal. `-i` used to be
210
- * unconditional for the reason recorded here — the agent's `search.grep` was case-insensitive by default,
211
- * and the two tiers must not disagree about what the same tool call means (the real-host run caught exactly
212
- * that disagreement). It is now conditional on `caseSensitive`, which the agent also honours, so the
213
- * agreement is kept while the caller can finally ask for an exact match.
214
- * `head` bounds the output before it crosses the wire, and `--` ends option parsing so a pattern starting
215
- * with `-` is not read as a flag.
216
- *
217
- * `include` entries become `--include=<glob>` filters. They are **filename globs** (`*.cpp`), matching the
218
- * agent's field of the same name; each entry is shell-quoted because it is model-supplied text, and the
219
- * `--include=` prefix keeps a pattern that starts with `-` from being read as a flag.
220
- *
221
- * `noIgnore` controls {@link DEFAULT_EXCLUDE_DIRS}, emitted as `--exclude-dir=` words. **It cannot turn VCS
222
- * ignores off or on**: plain `grep` never read `.gitignore`, so this tier already searches ignored files.
223
- * That residual difference is stated in `remote_grep`'s description and pinned by the two-tier consistency
224
- * test rather than left for a caller to discover by comparing two hosts.
225
- */
226
- export declare function grepCommand(request: GrepRequest, root: string): string;
227
- /**
228
- * Parse `grep -rn` output (`path:line:text`).
229
- *
230
- * A path containing `:` is ambiguous — the first two colon-separated fields win when the second is numeric,
231
- * and the rest is text. That is the same convention every editor uses, and it degrades to "line 0" rather
232
- * than dropping the hit.
233
- *
234
- * @param stdout - command output.
235
- * @param maxResults - the cap the command was built with.
236
- * @returns hits plus whether the cap was reached.
237
- */
238
- export declare function parseGrepOutput(stdout: string, maxResults: number): {
239
- readonly matches: GrepHit[];
240
- readonly truncated: boolean;
241
- };
242
- /**
243
- * Bound one output string by bytes, cutting on a line boundary when possible.
244
- *
245
- * **Which end to keep is a real decision, not a default** (审计 0052 §8.1). `tail` exists because the
246
- * transports already made that decision and the renderer was contradicting them: `ssh2-transport.ts` keeps
247
- * the **last** 256 KiB of stderr precisely because "every consumer of this string wants the last thing the
248
- * command said", and a command's verdict — the compiler error, the failing test, the `DSH_ERROR=` refusal —
249
- * is at the end. Bounding to the **head** at 64 KiB then threw away the very bytes the transport had
250
- * deliberately preserved, which is the user's original complaint ("编译报错永远在最后几行,恰好被砍掉")
251
- * reappearing one layer up.
252
- *
253
- * @param text - raw output.
254
- * @param maxBytes - cap.
255
- * @param keep - which end survives; defaults to `head` for callers that want the beginning.
256
- * @returns the kept text plus whether anything was dropped.
257
- */
258
- export declare function boundOutput(text: string, maxBytes?: number, keep?: 'head' | 'tail'): BoundedText;
259
- /**
260
- * Make one enumerated path relative to the directory that was enumerated.
261
- *
262
- * The two enumerators disagree on shape: the Tier 2 agent answers paths relative to the root it was given,
263
- * while the Tier 1 `find` fallback prints absolute ones. A glob pattern is anchored at the enumerated
264
- * directory, so both have to arrive in the same shape before matching — and the tool's own output then has
265
- * one shape too, instead of depending on which tier answered.
266
- *
267
- * @param base - absolute path of the enumerated directory.
268
- * @param path - one path as the enumerator reported it.
269
- * @returns the root-relative path, unchanged when it was already relative.
270
- */
271
- export declare function relativeToRoot(base: string, path: string): string;
272
- /**
273
- * Rank enumerated paths for a glob query: glob match, shallowest first.
274
- *
275
- * The matching itself lives in `./glob-pattern.ts`, whose rules are ported from the Tier 2 agent's Go
276
- * implementation. It used to be a literal substring test here, which meant the same `remote_glob` call matched
277
- * different files depending on the transport (audit 0052 P3 chose substring; audit 0030 added the Go fast path
278
- * and the two silently diverged).
279
- *
280
- * @param paths - enumerated paths, relative to the enumerated root.
281
- * @param pattern - glob pattern (see `./glob-pattern.ts`); the empty pattern keeps its documented meaning of
282
- * "no filter, shallowest first" rather than being compiled into a pattern that matches nothing.
283
- * @param maxResults - cap.
284
- * @returns matched paths plus whether the cap was reached.
285
- * @throws GlobPatternError when the pattern is not a valid glob.
286
- */
287
- export declare function matchGlob(paths: readonly string[], pattern: string, maxResults: number): {
288
- readonly matches: readonly string[];
289
- readonly truncated: boolean;
290
- };
291
- /** How much of one command's output was cut, per stream, plus where the full text can be read. */
292
- export interface ExecTruncation {
293
- /** Compatibility alias: at least one stream was cut. */
294
- readonly truncated: boolean;
295
- readonly stdoutTruncated: boolean;
296
- readonly stderrTruncated: boolean;
297
- /** Remote path holding the **full** stdout, present only when stdout was cut. */
298
- readonly stdoutSpillPath: string | undefined;
299
- /** Remote path holding the **full** stderr, present only when stderr was cut. */
300
- readonly stderrSpillPath: string | undefined;
301
- }
302
- /**
303
- * Read the per-stream truncation fields out of a raw agent `proc.exec` result.
304
- *
305
- * Contract (agreed with the Go agent, audit 0052 §P4/§8):
306
- *
307
- * - `stdoutTruncated` / `stderrTruncated` are booleans;
308
- * - `stdoutSpillPath` / `stderrSpillPath` are strings that exist **only** when that stream was cut
309
- * (`omitempty` on the Go side), so "absent" and "empty" must both read as "no spill";
310
- * - `truncated` is kept as a deprecated alias meaning `stdoutTruncated || stderrTruncated`.
311
- *
312
- * **The legacy fallback is stdout-only, and that is the whole point** (审计 0052 §8). An older agent sends
313
- * only `truncated`, whose documented meaning is "stdout was cut at maxBytes" (`transport.ts`). Mapping it to
314
- * *both* streams told the caller that compiler diagnostics on stderr had been cut when nothing said so — and
315
- * that over-report is what a real agent exposed: `stderrTruncated: false` arrived, and the rendered result
316
- * still claimed "被截断的流:stdout 与 stderr". Reporting less than the truth is a bug; reporting **more** is
317
- * a worse one, because it sends the reader to re-run an expensive build or to open a spill file that has
318
- * nothing to add.
319
- *
320
- * `??`-style semantics, never `||`: an explicit `false` is a real answer ("this stream was not cut") and must
321
- * survive. A caller that genuinely knows stderr was cut says so by sending `stderrTruncated: true`.
322
- *
323
- * @param raw - the agent's result object, however malformed or old.
324
- * @returns the normalized truncation report.
325
- */
326
- export declare function readExecTruncation(raw: unknown): ExecTruncation;
327
- /** Why a search stopped early. Mirrors the agent's `truncatedReasons` values. */
328
- export type SearchTruncationReason = 'maxResults' | 'bytesScanned' | 'maxFileBytes' | 'timeout' | 'maxEntries';
329
- /** How a search ended, in enough detail to tell the caller what to change. */
330
- export interface SearchTruncation {
331
- /** Compatibility flag: any bound was hit. */
332
- readonly truncated: boolean;
333
- /** Which bounds were hit, de-duplicated and in a stable order. Empty when nothing was cut. */
334
- readonly reasons: readonly string[];
335
- /**
336
- * How many candidate files the filename filters removed, or `undefined` when the agent did not say.
337
- *
338
- * This is what makes `include` **observable**: a mistyped filter yields zero matches with every candidate
339
- * filtered out, which looks identical to "the symbol is not there" unless the count is reported.
340
- */
341
- readonly filesFiltered: number | undefined;
342
- }
343
- /**
344
- * Normalize a search result's truncation report.
345
- *
346
- * Contract (agreed with the Go agent, audit 0052 P7): `truncatedReasons` is a de-duplicated `[]string` whose
347
- * values are `maxResults` / `bytesScanned` / `maxFileBytes` / `timeout` / `maxEntries`, and `filesFiltered`
348
- * is an int. Both are **new**, so an older agent returns neither — and then the single `truncated` boolean
349
- * must still work. `??` (not `||`) keeps an explicit `false` and a legitimate `0` meaningful.
350
- *
351
- * An unrecognized reason is kept verbatim rather than dropped: a newer agent naming a bound this build does
352
- * not know about must not be silently reported as "nothing was truncated".
353
- *
354
- * @param raw - the agent's result object, however old or malformed.
355
- * @returns the normalized report.
356
- */
357
- export declare function readSearchTruncation(raw: unknown): SearchTruncation;
358
- /**
359
- * Turn one truncation reason into the change that would actually help.
360
- *
361
- * The five bounds are not interchangeable (audit 0052 P7): `maxResults` is fixed by narrowing the *pattern*,
362
- * `bytesScanned` by narrowing the *paths*, and so on. A single "results were truncated" left the caller to
363
- * guess, and guessing wrong meant re-running an expensive whole-tree scan.
364
- *
365
- * @param reason - a value from the agent's `truncatedReasons`.
366
- * @returns a model-facing, actionable sentence.
367
- */
368
- export declare function searchTruncationAdvice(reason: string): string;
369
- //# sourceMappingURL=tool-requests.d.ts.map