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
@@ -20,9 +20,9 @@ var SshDevError = class extends Error {
20
20
  }
21
21
  };
22
22
 
23
- // src/host/domain/roots/root.ts
23
+ // src/shared/root-keys.ts
24
24
  function normalizeLocalPath(path, options = {}) {
25
- const caseInsensitive = options.caseInsensitive ?? process.platform === "win32";
25
+ const caseInsensitive = options.caseInsensitive ?? false;
26
26
  const unified = path.replace(/\\/g, "/");
27
27
  const unc = unified.startsWith("//");
28
28
  const posixAbsolute = unified.startsWith("/");
@@ -47,9 +47,14 @@ function normalizeLocalPath(path, options = {}) {
47
47
  else normalized = body === "" ? "." : body;
48
48
  return caseInsensitive ? normalized.toLowerCase() : normalized;
49
49
  }
50
+
51
+ // src/host/domain/roots/root.ts
52
+ function normalizeLocalPath2(path, options = {}) {
53
+ return normalizeLocalPath(path, { caseInsensitive: options.caseInsensitive ?? process.platform === "win32" });
54
+ }
50
55
  function localPathContains(root, candidate, options = {}) {
51
- const normalizedRoot = normalizeLocalPath(root, options);
52
- const normalizedCandidate = normalizeLocalPath(candidate, options);
56
+ const normalizedRoot = normalizeLocalPath2(root, options);
57
+ const normalizedCandidate = normalizeLocalPath2(candidate, options);
53
58
  if (normalizedRoot === "/" || /^[a-z]:\/$/.test(normalizedRoot)) {
54
59
  return normalizedCandidate.startsWith(normalizedRoot);
55
60
  }
@@ -84,8 +84,47 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
84
84
  */
85
85
  readCacheTtlMs: z<number, number, "defined">;
86
86
  readCacheMaxEntries: z<number, number, "defined">;
87
+ /**
88
+ * Byte ceiling for the read cache of **one remote root**, not for the plugin as a whole.
89
+ *
90
+ * 这条的语义必须写清楚,否则会读成"整个插件的上限":每个远端根各自持有一份版本缓存(外加一份
91
+ * 目录列举缓存),所以 N 个**同时存在**的根是 N × 这个数。上界因此是"活根数"而不是"历史根数"——
92
+ * 根被移除时 `Backend.dispose()` 会把它的缓存一起释放(审计 0112 P3-11 接线之前不是这样,
93
+ * 那才是 P3-12 真正的风险所在)。要压总占用就调小这个数,或者减少同时挂着的远端根。
94
+ */
87
95
  readCacheMaxBytes: z<number, number, "defined">;
96
+ /**
97
+ * Ceiling for the **sum** over every remote root's caches, not per root.
98
+ *
99
+ * 0112 P3-12 的缺口是"每个根各自封顶、加起来没人管":`readCacheMaxBytes` 是每根的额度,
100
+ * 十根就是十倍。这一项把总和钉住——超过时由**占用最大的那个**缓存让出最旧的条目(通常也是读者
101
+ * 正在看的那个,所以不让刚写的先挨刀)。
102
+ *
103
+ * 默认 64 MiB ≈ 8 个满额度的根。**必须是正整数**:要彻底关掉缓存请设
104
+ * `readCacheMaxBytes: 0`(那是"根本不缓存"),而不是把总预算设为 0——后者只会让每次写入
105
+ * 立刻把自己的条目淘汰掉,行为既不是"关缓存"也不是"缓存"。
106
+ */
107
+ readCacheTotalMaxBytes: z<number, number, "defined">;
108
+ /**
109
+ * 端口转发的空闲回收窗口(毫秒);`0` 关闭回收。
110
+ *
111
+ * 判据是"没有任何活跃连接且距最后一次活动超过这个窗口"。没有回收的话,一个被 agent 起过、
112
+ * 之后没人用的转发会一直占着本地端口(用户实测关心的问题)。默认 30 分钟:比一次开发会话的
113
+ * 间隔长,比"忘了关一整天"短。
114
+ */
115
+ forwardIdleTimeoutMs: z<number, number, "defined">;
88
116
  terminalStateDir: z<string, string, "plain">;
117
+ /**
118
+ * 是否给 `remote_exec` / `remote_exec_background` 套**远端写入围栏**(Tier 2 的 Landlock)。
119
+ *
120
+ * **默认关**是刻意的:围栏只放行 workspace 根与本会话添加的目录,构建工具往 `$HOME/.cache`、
121
+ * `/tmp` 写缓存时会被拒——默认开启会把正常命令弄坏。关着的时候 shell 命令能碰到 SSH 用户能碰的
122
+ * 一切,这与"添加目录"的文件边界是两件事,工具描述里如实写着。
123
+ *
124
+ * 打开之后,`remote_exec` 只能写:命令起始的 workspace 根、本会话添加的可写根。Tier 1(无代理)
125
+ * 没有 Landlock 能力,此项对它们无效。
126
+ */
127
+ execWriteFence: z<boolean, boolean, "defined">;
89
128
  transferChunkBytes: z<number, number, "defined">;
90
129
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
91
130
  transferConcurrency: z<number, number, "defined">;
@@ -110,8 +149,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
110
149
  sessionBinMaxEntries: z<number, number, "defined">;
111
150
  sessionBinMaxBytes: z<number, number, "defined">;
112
151
  sessionBinMaxAgeMs: z<number, number, "defined">;
113
- /** Delete the projection cache alongside the log when true (FR-3.4 step 8). */
114
- sessionPurgeProjection: z<boolean, boolean, "defined">;
115
152
  }>>, Schemastery.ObjectT<NoInfer<{
116
153
  maxReadBytes: z<number, number, "defined">;
117
154
  connectTimeoutMs: z<number, number, "defined">;
@@ -133,8 +170,47 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
133
170
  */
134
171
  readCacheTtlMs: z<number, number, "defined">;
135
172
  readCacheMaxEntries: z<number, number, "defined">;
173
+ /**
174
+ * Byte ceiling for the read cache of **one remote root**, not for the plugin as a whole.
175
+ *
176
+ * 这条的语义必须写清楚,否则会读成"整个插件的上限":每个远端根各自持有一份版本缓存(外加一份
177
+ * 目录列举缓存),所以 N 个**同时存在**的根是 N × 这个数。上界因此是"活根数"而不是"历史根数"——
178
+ * 根被移除时 `Backend.dispose()` 会把它的缓存一起释放(审计 0112 P3-11 接线之前不是这样,
179
+ * 那才是 P3-12 真正的风险所在)。要压总占用就调小这个数,或者减少同时挂着的远端根。
180
+ */
136
181
  readCacheMaxBytes: z<number, number, "defined">;
182
+ /**
183
+ * Ceiling for the **sum** over every remote root's caches, not per root.
184
+ *
185
+ * 0112 P3-12 的缺口是"每个根各自封顶、加起来没人管":`readCacheMaxBytes` 是每根的额度,
186
+ * 十根就是十倍。这一项把总和钉住——超过时由**占用最大的那个**缓存让出最旧的条目(通常也是读者
187
+ * 正在看的那个,所以不让刚写的先挨刀)。
188
+ *
189
+ * 默认 64 MiB ≈ 8 个满额度的根。**必须是正整数**:要彻底关掉缓存请设
190
+ * `readCacheMaxBytes: 0`(那是"根本不缓存"),而不是把总预算设为 0——后者只会让每次写入
191
+ * 立刻把自己的条目淘汰掉,行为既不是"关缓存"也不是"缓存"。
192
+ */
193
+ readCacheTotalMaxBytes: z<number, number, "defined">;
194
+ /**
195
+ * 端口转发的空闲回收窗口(毫秒);`0` 关闭回收。
196
+ *
197
+ * 判据是"没有任何活跃连接且距最后一次活动超过这个窗口"。没有回收的话,一个被 agent 起过、
198
+ * 之后没人用的转发会一直占着本地端口(用户实测关心的问题)。默认 30 分钟:比一次开发会话的
199
+ * 间隔长,比"忘了关一整天"短。
200
+ */
201
+ forwardIdleTimeoutMs: z<number, number, "defined">;
137
202
  terminalStateDir: z<string, string, "plain">;
203
+ /**
204
+ * 是否给 `remote_exec` / `remote_exec_background` 套**远端写入围栏**(Tier 2 的 Landlock)。
205
+ *
206
+ * **默认关**是刻意的:围栏只放行 workspace 根与本会话添加的目录,构建工具往 `$HOME/.cache`、
207
+ * `/tmp` 写缓存时会被拒——默认开启会把正常命令弄坏。关着的时候 shell 命令能碰到 SSH 用户能碰的
208
+ * 一切,这与"添加目录"的文件边界是两件事,工具描述里如实写着。
209
+ *
210
+ * 打开之后,`remote_exec` 只能写:命令起始的 workspace 根、本会话添加的可写根。Tier 1(无代理)
211
+ * 没有 Landlock 能力,此项对它们无效。
212
+ */
213
+ execWriteFence: z<boolean, boolean, "defined">;
138
214
  transferChunkBytes: z<number, number, "defined">;
139
215
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
140
216
  transferConcurrency: z<number, number, "defined">;
@@ -159,8 +235,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
159
235
  sessionBinMaxEntries: z<number, number, "defined">;
160
236
  sessionBinMaxBytes: z<number, number, "defined">;
161
237
  sessionBinMaxAgeMs: z<number, number, "defined">;
162
- /** Delete the projection cache alongside the log when true (FR-3.4 step 8). */
163
- sessionPurgeProjection: z<boolean, boolean, "defined">;
164
238
  }>>, "defined">;
165
239
  }>>, Schemastery.ObjectT<NoInfer<{
166
240
  connections: z<({
@@ -228,8 +302,47 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
228
302
  */
229
303
  readCacheTtlMs: z<number, number, "defined">;
230
304
  readCacheMaxEntries: z<number, number, "defined">;
305
+ /**
306
+ * Byte ceiling for the read cache of **one remote root**, not for the plugin as a whole.
307
+ *
308
+ * 这条的语义必须写清楚,否则会读成"整个插件的上限":每个远端根各自持有一份版本缓存(外加一份
309
+ * 目录列举缓存),所以 N 个**同时存在**的根是 N × 这个数。上界因此是"活根数"而不是"历史根数"——
310
+ * 根被移除时 `Backend.dispose()` 会把它的缓存一起释放(审计 0112 P3-11 接线之前不是这样,
311
+ * 那才是 P3-12 真正的风险所在)。要压总占用就调小这个数,或者减少同时挂着的远端根。
312
+ */
231
313
  readCacheMaxBytes: z<number, number, "defined">;
314
+ /**
315
+ * Ceiling for the **sum** over every remote root's caches, not per root.
316
+ *
317
+ * 0112 P3-12 的缺口是"每个根各自封顶、加起来没人管":`readCacheMaxBytes` 是每根的额度,
318
+ * 十根就是十倍。这一项把总和钉住——超过时由**占用最大的那个**缓存让出最旧的条目(通常也是读者
319
+ * 正在看的那个,所以不让刚写的先挨刀)。
320
+ *
321
+ * 默认 64 MiB ≈ 8 个满额度的根。**必须是正整数**:要彻底关掉缓存请设
322
+ * `readCacheMaxBytes: 0`(那是"根本不缓存"),而不是把总预算设为 0——后者只会让每次写入
323
+ * 立刻把自己的条目淘汰掉,行为既不是"关缓存"也不是"缓存"。
324
+ */
325
+ readCacheTotalMaxBytes: z<number, number, "defined">;
326
+ /**
327
+ * 端口转发的空闲回收窗口(毫秒);`0` 关闭回收。
328
+ *
329
+ * 判据是"没有任何活跃连接且距最后一次活动超过这个窗口"。没有回收的话,一个被 agent 起过、
330
+ * 之后没人用的转发会一直占着本地端口(用户实测关心的问题)。默认 30 分钟:比一次开发会话的
331
+ * 间隔长,比"忘了关一整天"短。
332
+ */
333
+ forwardIdleTimeoutMs: z<number, number, "defined">;
232
334
  terminalStateDir: z<string, string, "plain">;
335
+ /**
336
+ * 是否给 `remote_exec` / `remote_exec_background` 套**远端写入围栏**(Tier 2 的 Landlock)。
337
+ *
338
+ * **默认关**是刻意的:围栏只放行 workspace 根与本会话添加的目录,构建工具往 `$HOME/.cache`、
339
+ * `/tmp` 写缓存时会被拒——默认开启会把正常命令弄坏。关着的时候 shell 命令能碰到 SSH 用户能碰的
340
+ * 一切,这与"添加目录"的文件边界是两件事,工具描述里如实写着。
341
+ *
342
+ * 打开之后,`remote_exec` 只能写:命令起始的 workspace 根、本会话添加的可写根。Tier 1(无代理)
343
+ * 没有 Landlock 能力,此项对它们无效。
344
+ */
345
+ execWriteFence: z<boolean, boolean, "defined">;
233
346
  transferChunkBytes: z<number, number, "defined">;
234
347
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
235
348
  transferConcurrency: z<number, number, "defined">;
@@ -254,8 +367,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
254
367
  sessionBinMaxEntries: z<number, number, "defined">;
255
368
  sessionBinMaxBytes: z<number, number, "defined">;
256
369
  sessionBinMaxAgeMs: z<number, number, "defined">;
257
- /** Delete the projection cache alongside the log when true (FR-3.4 step 8). */
258
- sessionPurgeProjection: z<boolean, boolean, "defined">;
259
370
  }>>, Schemastery.ObjectT<NoInfer<{
260
371
  maxReadBytes: z<number, number, "defined">;
261
372
  connectTimeoutMs: z<number, number, "defined">;
@@ -277,8 +388,47 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
277
388
  */
278
389
  readCacheTtlMs: z<number, number, "defined">;
279
390
  readCacheMaxEntries: z<number, number, "defined">;
391
+ /**
392
+ * Byte ceiling for the read cache of **one remote root**, not for the plugin as a whole.
393
+ *
394
+ * 这条的语义必须写清楚,否则会读成"整个插件的上限":每个远端根各自持有一份版本缓存(外加一份
395
+ * 目录列举缓存),所以 N 个**同时存在**的根是 N × 这个数。上界因此是"活根数"而不是"历史根数"——
396
+ * 根被移除时 `Backend.dispose()` 会把它的缓存一起释放(审计 0112 P3-11 接线之前不是这样,
397
+ * 那才是 P3-12 真正的风险所在)。要压总占用就调小这个数,或者减少同时挂着的远端根。
398
+ */
280
399
  readCacheMaxBytes: z<number, number, "defined">;
400
+ /**
401
+ * Ceiling for the **sum** over every remote root's caches, not per root.
402
+ *
403
+ * 0112 P3-12 的缺口是"每个根各自封顶、加起来没人管":`readCacheMaxBytes` 是每根的额度,
404
+ * 十根就是十倍。这一项把总和钉住——超过时由**占用最大的那个**缓存让出最旧的条目(通常也是读者
405
+ * 正在看的那个,所以不让刚写的先挨刀)。
406
+ *
407
+ * 默认 64 MiB ≈ 8 个满额度的根。**必须是正整数**:要彻底关掉缓存请设
408
+ * `readCacheMaxBytes: 0`(那是"根本不缓存"),而不是把总预算设为 0——后者只会让每次写入
409
+ * 立刻把自己的条目淘汰掉,行为既不是"关缓存"也不是"缓存"。
410
+ */
411
+ readCacheTotalMaxBytes: z<number, number, "defined">;
412
+ /**
413
+ * 端口转发的空闲回收窗口(毫秒);`0` 关闭回收。
414
+ *
415
+ * 判据是"没有任何活跃连接且距最后一次活动超过这个窗口"。没有回收的话,一个被 agent 起过、
416
+ * 之后没人用的转发会一直占着本地端口(用户实测关心的问题)。默认 30 分钟:比一次开发会话的
417
+ * 间隔长,比"忘了关一整天"短。
418
+ */
419
+ forwardIdleTimeoutMs: z<number, number, "defined">;
281
420
  terminalStateDir: z<string, string, "plain">;
421
+ /**
422
+ * 是否给 `remote_exec` / `remote_exec_background` 套**远端写入围栏**(Tier 2 的 Landlock)。
423
+ *
424
+ * **默认关**是刻意的:围栏只放行 workspace 根与本会话添加的目录,构建工具往 `$HOME/.cache`、
425
+ * `/tmp` 写缓存时会被拒——默认开启会把正常命令弄坏。关着的时候 shell 命令能碰到 SSH 用户能碰的
426
+ * 一切,这与"添加目录"的文件边界是两件事,工具描述里如实写着。
427
+ *
428
+ * 打开之后,`remote_exec` 只能写:命令起始的 workspace 根、本会话添加的可写根。Tier 1(无代理)
429
+ * 没有 Landlock 能力,此项对它们无效。
430
+ */
431
+ execWriteFence: z<boolean, boolean, "defined">;
282
432
  transferChunkBytes: z<number, number, "defined">;
283
433
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
284
434
  transferConcurrency: z<number, number, "defined">;
@@ -303,10 +453,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
303
453
  sessionBinMaxEntries: z<number, number, "defined">;
304
454
  sessionBinMaxBytes: z<number, number, "defined">;
305
455
  sessionBinMaxAgeMs: z<number, number, "defined">;
306
- /** Delete the projection cache alongside the log when true (FR-3.4 step 8). */
307
- sessionPurgeProjection: z<boolean, boolean, "defined">;
308
456
  }>>, "defined">;
309
457
  }>>, "plain">;
310
458
  /** What {@link apply} receives: the schema's resolved output, which is what the loader passes. */
311
459
  export type ResolvedConfig = Schemastery.TypeT<typeof Config>;
312
- //# sourceMappingURL=config.d.ts.map
@@ -22,4 +22,3 @@ import { Context } from '@deepseek-ai/cordis';
22
22
  */
23
23
  export default function apply(ctx: Context): (import("@deepseek-ai/cordis").Fiber & PromiseLike<import("@deepseek-ai/cordis").Fiber>) | undefined;
24
24
  export { RemoteFileReferenceService, DEFAULT_MAX_RESULTS, LOCAL_EXCLUDED_DIRECTORIES, LOCAL_MAX_DEPTH, LOCAL_MAX_ENTRIES, type FileReferenceIndex, type LocalEntry, type RemoteFileReferenceOptions, } from './host/integration/fs/file-reference-provider.ts';
25
- //# sourceMappingURL=file-references.d.ts.map
@@ -69,6 +69,17 @@ export interface BackendWrite {
69
69
  }
70
70
  /** How a backend confines writes, mirroring the core's `SandboxMode`. */
71
71
  export type BackendSandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
72
+ /**
73
+ * Per-call write fence; structurally compatible with the platform's `SandboxExecutionPolicy`.
74
+ *
75
+ * 用结构化类型而不是 `import type { SandboxExecutionPolicy } from '@deepseek-ai/dsh-sandbox'`:app 层的端口
76
+ * 不该依赖平台包(`tests/architecture.test.ts` 的可测性规则)。只有真正把写入交给平台沙箱的
77
+ * {@link PlatformLocalBackend} 会读它,其余后端各有一套自己的围栏。
78
+ */
79
+ export interface BackendWritePolicy {
80
+ readonly mode: BackendSandboxMode;
81
+ readonly workspaceRoot: string;
82
+ }
72
83
  /** One backend serving one root. */
73
84
  export interface Backend {
74
85
  /** Stable id, also the namespace prefix of every target key it produces. */
@@ -77,6 +88,15 @@ export interface Backend {
77
88
  readonly sandboxMode: BackendSandboxMode | undefined;
78
89
  /** Whether the backend can watch for changes natively. */
79
90
  readonly watches: boolean;
91
+ /**
92
+ * Stop background work (watchers, poll loops) and release what this backend holds.
93
+ *
94
+ * Called when its root is retired. Optional: a backend with nothing to stop omits it. Without this call a
95
+ * removed root's watcher kept polling — `RemoteBackend.dispose()` existed but had **zero production callers**,
96
+ * so the poll loop outlived the root that started it and the remote inotify registration was never dropped
97
+ * (audit 0112 P3-11).
98
+ */
99
+ dispose?(): Promise<void>;
80
100
  /**
81
101
  * Watch one path for changes, in this backend's own absolute spelling (the backend layer has no `FsTarget`).
82
102
  *
@@ -104,8 +124,11 @@ export interface Backend {
104
124
  * Write text, atomically where the backend can.
105
125
  *
106
126
  * @param expectedVersion - when non-empty the write must fail if the current version differs.
127
+ * @param policy - the per-call sandbox policy, when the caller has one. Only backends that delegate to a
128
+ * platform sandbox consume it ({@link PlatformLocalBackend}); the others enforce their own fence and
129
+ * ignore it. Structural on purpose — the app layer must not import platform types.
107
130
  */
108
- writeText(absolute: string, text: string, expectedVersion: string | undefined, signal?: AbortSignal): Promise<BackendWrite>;
131
+ writeText(absolute: string, text: string, expectedVersion: string | undefined, signal?: AbortSignal, policy?: BackendWritePolicy): Promise<BackendWrite>;
109
132
  /**
110
133
  * Apply a unified diff to one file, atomically.
111
134
  *
@@ -122,9 +145,10 @@ export interface Backend {
122
145
  * apply the **same** three-state semantics as that fallback (not found / ambiguous / replaceAll) and
123
146
  * must honour `expectedVersion` across its own read-modify-write.
124
147
  */
125
- editText?(absolute: string, oldString: string, newString: string, replaceAll: boolean, expectedVersion: string | undefined, signal?: AbortSignal): Promise<BackendWrite & {
148
+ editText?(absolute: string, oldString: string, newString: string, replaceAll: boolean, expectedVersion: string | undefined, signal?: AbortSignal, policy?: BackendWritePolicy): Promise<BackendWrite & {
126
149
  readonly replaced: number;
127
150
  }>;
151
+ /** Per-call write fence, structurally compatible with the platform's `SandboxExecutionPolicy`. */
128
152
  /**
129
153
  * Create a directory, and its parents when asked (FR-2.2.2: the file tree's 「新建目录」).
130
154
  *
@@ -162,9 +186,26 @@ export interface Backend {
162
186
  * caller's `755` is octal digits, not decimal seven hundred and fifty-five, and that confusion is silent.
163
187
  */
164
188
  chmod?(absolute: string, mode: string, signal?: AbortSignal): Promise<void>;
189
+ /**
190
+ * Create a symbolic link at `linkPath` pointing at `target`.
191
+ *
192
+ * Optional, and it must **refuse** an existing path rather than replace it: silently turning a real file
193
+ * into a symlink is data loss, and "there used to be a file here" is not recoverable from the link.
194
+ *
195
+ * @param target - what the link points at (kept verbatim; a relative target resolves against the link's dir).
196
+ * @param linkPath - the link to create.
197
+ * @param signal - cancellation.
198
+ */
199
+ symlink?(target: string, linkPath: string, signal?: AbortSignal): Promise<void>;
200
+ /**
201
+ * Read a symbolic link's target, or `undefined` when the path is not a link.
202
+ *
203
+ * `undefined` (not an error) is the honest answer for "not a link": the caller asked a question whose
204
+ * answer is "no". Only a real failure throws.
205
+ */
206
+ readlink?(absolute: string, signal?: AbortSignal): Promise<string | undefined>;
165
207
  /** Host path a child process in this backend's world can open, if any. */
166
208
  processPath?(absolute: string): string | undefined;
167
209
  /** `file:` URL for this path in the backend's world. */
168
210
  fileUrl?(absolute: string): string;
169
211
  }
170
- //# sourceMappingURL=backend.d.ts.map
@@ -244,4 +244,3 @@ export interface RecycleBinService {
244
244
  /** Current undo/redo state. */
245
245
  history(): RecycleBinHistory;
246
246
  }
247
- //# sourceMappingURL=recycle-bin-contract.d.ts.map
@@ -42,4 +42,3 @@ export * from './recycle-bin-contract.ts';
42
42
  * @returns a {@link RecycleBinService}; its undo stack is per-instance, in memory and not persisted.
43
43
  */
44
44
  export declare function createRecycleBinService(deps: RecycleBinServiceDeps): RecycleBinService;
45
- //# sourceMappingURL=recycle-bin-service.d.ts.map
@@ -94,6 +94,18 @@ export interface SessionAdminDeps {
94
94
  readonly detachSession?: (sessionId: string) => Promise<void>;
95
95
  /** Announce the removal so clients drop the row (`api-session/removed`). */
96
96
  readonly emitRemoved?: (sessionId: string) => void;
97
+ /**
98
+ * The session is gone: drop it from any bookkeeping that remembers session ids.
99
+ *
100
+ * Fired **after** the deletion is durable, on both the permanent and the recycle path, and it is not awaited:
101
+ * losing a stale id in `user-roots.json` must not turn a completed deletion into a failure. The implementation
102
+ * is expected to be best-effort and to log its own warnings.
103
+ *
104
+ * Audit 0112 P3-13: before this, nothing told `user-roots.json` that a session had been deleted, so every root
105
+ * a session had added kept its dead id forever — the panel went on showing the root as "added by a session
106
+ * that no longer exists" and the file grew on every write.
107
+ */
108
+ readonly onSessionRemoved?: (sessionId: string) => void;
97
109
  /** Injected clock. */
98
110
  readonly now: () => number;
99
111
  /** Who confirmed, for the audit trail (FR-3.10); absent when the caller did not say. */
@@ -218,4 +230,3 @@ export interface SessionAdminService {
218
230
  * @throws SshDevError `ROOT_INVALID` when the bin root is inside the sessions root (that placement breaks the
219
231
  * platform's session listing — see the module note and ADR-0009).
220
232
  */
221
- //# sourceMappingURL=session-admin-contract.d.ts.map
@@ -37,4 +37,3 @@ export * from './session-admin-contract.ts';
37
37
  * @returns the {@link SessionAdminService}.
38
38
  */
39
39
  export declare function createSessionAdminService(deps: SessionAdminDeps): SessionAdminService;
40
- //# sourceMappingURL=session-admin-service.d.ts.map
@@ -95,4 +95,3 @@ export declare class TransportSelector {
95
95
  */
96
96
  noteMultiplexingFailure(profile: ConnectionProfile, reason: string): void;
97
97
  }
98
- //# sourceMappingURL=transport-selector.d.ts.map
@@ -79,4 +79,3 @@ export declare class TransportService {
79
79
  /** Dispose every connection (plugin unload, connection-service shutdown). */
80
80
  disposeAll(): Promise<void>;
81
81
  }
82
- //# sourceMappingURL=transport-service.d.ts.map
@@ -75,4 +75,3 @@ export declare function searchStrategyFor(capabilities: RemoteCapabilities): Sea
75
75
  export declare function indexStrategyFor(capabilities: RemoteCapabilities): IndexStrategy;
76
76
  /** Whether the host can run the plugin's file-transfer path. */
77
77
  export declare function canTransferBytes(capabilities: RemoteCapabilities): boolean;
78
- //# sourceMappingURL=capability.d.ts.map
@@ -52,4 +52,3 @@ export declare function sshFailureToError(connectionId: string, input: {
52
52
  }): SshDevError;
53
53
  /** Keep only the tail of a long diagnostic string so details stay bounded. */
54
54
  export declare function tail(text: string, maxChars: number): string;
55
- //# sourceMappingURL=errors.d.ts.map
@@ -103,4 +103,3 @@ export declare function validateConnectionProfile(input: unknown): ConnectionPro
103
103
  export declare function profileFromImportDraft(id: string, draft: SshConfigImportDraft): ConnectionProfile;
104
104
  /** One-line summary used by diagnostics and the settings list. */
105
105
  export declare function connectionSummary(profile: ConnectionProfile): string;
106
- //# sourceMappingURL=connection.d.ts.map
@@ -5,8 +5,9 @@
5
5
  *
6
6
  * @module dsh-over-ssh/domain/root
7
7
  */
8
- /** Where a root lives. */
9
- export type RootLocation = 'local' | 'remote';
8
+ import { isAbsoluteLocalPath, type RootKeyOptions, type RootLocation } from '../../../shared/root-keys.ts';
9
+ /** Where a root lives. The definition lives in `shared/root-keys.ts`, beside the key rule that needs it. */
10
+ export type { RootLocation };
10
11
  /** One project root. */
11
12
  export interface RootRef {
12
13
  /** Local or remote. */
@@ -76,24 +77,39 @@ export declare function makeRemoteRoot(connectionId: string, remotePath: string,
76
77
  * a child process receives via `processPath`.
77
78
  */
78
79
  export declare function makeLocalRoot(path: string, options?: RootOptions): RootRef;
79
- /** Whether a host path is absolute in either the Windows or the POSIX spelling. */
80
- export declare function isAbsoluteLocalPath(path: string): boolean;
80
+ /**
81
+ * Whether a host path is absolute in either the Windows or the POSIX spelling.
82
+ *
83
+ * **Re-exported, not re-implemented.** The rule lives in `shared/root-keys.ts` because the client panel has to
84
+ * answer the same question before it sends a request — and the two answers had drifted: this file rejected
85
+ * `\\server\share` while the panel accepted it (审计 0112 P2-11). Both UNC spellings are accepted now, which is
86
+ * what this function always claimed in its one-line doc.
87
+ */
88
+ export { isAbsoluteLocalPath };
81
89
  /**
82
90
  * Normalize a host path for comparison: separators to `/`, `.`/`..` resolved, trailing
83
91
  * separators dropped, and (optionally) the drive letter and case folded.
84
92
  *
93
+ * The **implementation** is `shared/root-keys.ts` (the client's key needs the same normalisation). What stays
94
+ * here is the platform default: `caseInsensitive` defaults to "this host folds case on Windows", which is a
95
+ * fact only the host has — a browser bundle has no `process` and must not guess it.
96
+ *
85
97
  * @param path - host path in either separator spelling.
86
98
  * @param options - `caseInsensitive` folds case for comparison keys.
87
99
  * @returns the normalized path.
88
100
  */
89
- export declare function normalizeLocalPath(path: string, options?: {
90
- readonly caseInsensitive?: boolean;
91
- }): string;
101
+ export declare function normalizeLocalPath(path: string, options?: RootKeyOptions): string;
92
102
  /** Whether a host path is `root` itself or a descendant of it. */
93
103
  export declare function localPathContains(root: string, candidate: string, options?: {
94
104
  readonly caseInsensitive?: boolean;
95
105
  }): boolean;
96
- /** Stable identity of a root, used as a cache/route key. */
106
+ /**
107
+ * Stable identity of a root, used as a cache/route key.
108
+ *
109
+ * The **spelling** is `shared/root-keys.ts`'s `rootKeySpelling`: the client rebuilds this same key for a row
110
+ * whose answer carried none, and a second spelling is what made the panel's delete button address a root the
111
+ * registry did not have (审计 0024 §8.3). Only the error policy and the platform's case fold stay here.
112
+ */
97
113
  export declare function rootKey(root: RootRef): string;
98
114
  /** The model-facing and UI-facing spelling of a root's directory. */
99
115
  export declare function rootDisplay(root: RootRef): string;
@@ -105,4 +121,3 @@ export declare function rootsOverlap(left: RootRef, right: RootRef): boolean;
105
121
  export declare function validateRoot(root: RootRef): void;
106
122
  /** FNV-1a (32-bit) over UTF-16 code units, rendered as 8 lowercase hex characters. */
107
123
  export declare function fnv1aHex(input: string): string;
108
- //# sourceMappingURL=root.d.ts.map
@@ -56,6 +56,29 @@ export interface SessionIdentity {
56
56
  /** The asking session's fork ancestors, nearest first. */
57
57
  readonly ancestors?: readonly string[] | undefined;
58
58
  }
59
+ /**
60
+ * How much of one root counts as **the session's workspace** for a `workspace-write` mutation.
61
+ *
62
+ * 产品决定(2026-11-04,用户明确):**「添加到会话的目录」= 该目录临时成为 workspace 的一部分,可写。**
63
+ * 在此之前插件对 `workspace-write` 只做两件事(`read-only` 拒绝、`root.writable === false` 拒绝),写入
64
+ * 范围实际是"本会话能看见的任何可写根"——比平台声明宽,且和"添加目录"的语义没有关系。
65
+ *
66
+ * 三个取值:
67
+ * - `whole-root`:整个根都属于 workspace(会话自己添加的目录;或映射到 workspace 的远端根——远端根与
68
+ * 本地锚点是 1:1 的,锚点就是 workspace);
69
+ * - `workspace-only`:根包含 workspace,但只有 `workspaceRoot` 之内可写(平台自己的语义:`target` 必须
70
+ * canonicalize 到 `workspaceRoot` 或其临时目录下);
71
+ * - `deny`:既不是会话添加的目录,也不是 workspace 本身。
72
+ *
73
+ * @param root - 一个已注册的根。
74
+ * @param workspaceRoot - 平台为本次调用解析出的 workspace 根(绝对本地路径)。
75
+ * @param cwd - 调用方的会话工作目录,用于判定历史条目(ADR-0013 之前只有 `workspaces`)。
76
+ * @param identity - 调用方的会话身份,用于判定本会话添加的条目。
77
+ * @returns 该根在 `workspace-write` 下的可写范围。
78
+ */
79
+ export declare function workspaceWriteArea(root: RootRef, workspaceRoot: string | undefined, cwd: string | undefined, identity?: SessionIdentity): WorkspaceWriteArea;
80
+ /** See {@link workspaceWriteArea}. */
81
+ export type WorkspaceWriteArea = 'whole-root' | 'workspace-only' | 'deny';
59
82
  /** The target shape the tools consume; kept structural so this module imports no integration code. */
60
83
  export interface SessionRootTarget {
61
84
  readonly connectionId: string;
@@ -148,4 +171,3 @@ export declare function ambiguousSessionRootMessage(candidates: readonly Session
148
171
  * @returns whether the root may serve that caller.
149
172
  */
150
173
  export declare function rootVisibleToSession(root: RootRef, cwd: string | undefined, identity?: SessionIdentity): boolean;
151
- //# sourceMappingURL=session-roots.d.ts.map
@@ -70,4 +70,3 @@ export declare function importableEntries(entries: readonly SshConfigEntry[], op
70
70
  readonly home?: string;
71
71
  readonly excluded?: readonly string[];
72
72
  }): SshConfigImportResult;
73
- //# sourceMappingURL=ssh-config.d.ts.map
@@ -342,4 +342,3 @@ export declare function makeSessionTrashEntry(input: {
342
342
  readonly movedBy: 'rename' | 'copy';
343
343
  readonly confirmedBy?: string | undefined;
344
344
  }): SessionTrashEntry;
345
- //# sourceMappingURL=session-admin.d.ts.map
@@ -334,4 +334,3 @@ export declare function serializeRecycleBinIndex(entries: readonly RecycleBinEnt
334
334
  * @throws SshDevError `TRASH_NOT_FOUND` when the document cannot be read as an index.
335
335
  */
336
336
  export declare function parseRecycleBinIndex(text: string): ParsedRecycleBinIndex;
337
- //# sourceMappingURL=recycle-bin.d.ts.map
@@ -257,4 +257,3 @@ export declare function isTransferFailure(error: unknown, kind?: TransferFailure
257
257
  */
258
258
  export declare function digestsMatch(left: string | undefined, right: string | undefined): boolean;
259
259
  export { formatBytes, formatDuration };
260
- //# sourceMappingURL=transfer.d.ts.map
@@ -118,4 +118,3 @@ export declare function loadAgentManifest(manifestPath: string): Promise<{
118
118
  /** Commit the artifacts were built from, when the manifest records it. */
119
119
  readonly sourceCommit?: string;
120
120
  }>;
121
- //# sourceMappingURL=agent-installer.d.ts.map
@@ -0,0 +1,75 @@
1
+ /**
2
+ * 端口转发:请求 / 句柄 / 转发器三个形状,以及请求校验。
3
+ *
4
+ * 为什么单独一个模块:两个 Tier 都要实现同一份契约,而调用方(Lead 之后接进 `Transport`)只需要这一份。
5
+ * 放在 `infra/transport/` 顶层而不是 `ssh/` 下,是因为它是**跨适配器**的端口:`alias-forward` 与
6
+ * `ssh2-forward` 各自实现它,谁都不该 import 对方。
7
+ *
8
+ * 本地端一律绑 `127.0.0.1`:转发出去的端口是给本机浏览器用的(DSH 侧栏只能开本地 URL),绑到
9
+ * `0.0.0.0` 等于把一个远端服务暴露给整个局域网。这是一条安全决定,不是默认值凑巧。
10
+ *
11
+ * @module dsh-over-ssh/infra/transport/forward
12
+ */
13
+ /** 本地监听地址;固定环回,见模块注释。 */
14
+ export declare const FORWARD_LOCAL_HOST = "127.0.0.1";
15
+ /** 一次转发请求。 */
16
+ export interface ForwardRequest {
17
+ /** 远端要连的主机(相对**远端**解析;`localhost` 指远端自己)。 */
18
+ readonly remoteHost: string;
19
+ /** 远端端口,1..65535。 */
20
+ readonly remotePort: number;
21
+ /** 本地端口;省略则自动选一个空闲端口。 */
22
+ readonly localPort?: number;
23
+ }
24
+ /** 一次已建立的转发。 */
25
+ export interface ForwardHandle {
26
+ /** 真实的本地端口(自动选择时也一定有值,调用方拿它开 URL)。 */
27
+ readonly localPort: number;
28
+ readonly remoteHost: string;
29
+ readonly remotePort: number;
30
+ /** 幂等:第二次调用是 no-op,不抛错。 */
31
+ close(): Promise<void>;
32
+ /**
33
+ * 订阅「这条转发已经关掉」,无论关闭的**原因**是什么。
34
+ *
35
+ * 为什么需要它:空闲回收(默认 30 分钟)、连接退役、`closeAll` 都能让一条转发消失,而调用方手里只有
36
+ * 一个 handle;没有这个回调时,调用方的台账(`remote_forward list`)会一直列出已经关掉的转发。
37
+ *
38
+ * 可选:只有实现了回收的传输才提供。回调恰好触发一次;可重复订阅。
39
+ *
40
+ * @param listener - 收到关闭通知(含回收)时调用。
41
+ */
42
+ readonly onClosed?: (listener: () => void) => void;
43
+ }
44
+ /** 一个连接的转发台账。 */
45
+ export interface Forwarder {
46
+ /** 建立一条转发;失败必须不留本地监听、也不留子进程。 */
47
+ forward(req: ForwardRequest, signal?: AbortSignal): Promise<ForwardHandle>;
48
+ /** 当前活着的转发(只读快照语义:调用方不得依赖它的身份稳定)。 */
49
+ readonly forwards: readonly ForwardHandle[];
50
+ /** 收掉全部转发,供 dispose 使用;幂等。 */
51
+ closeAll(): Promise<void>;
52
+ }
53
+ /**
54
+ * 校验并规整一个转发请求。
55
+ *
56
+ * **为什么在拼 argv 之前就校验**:`-L` 的规格串是 `local:remoteHost:remotePort`,靠冒号分隔。主机名里
57
+ * 多一个冒号(`host:80`、裸 `::1`)会把参数解析成完全不同的目标;空白与逗号同理。ssh 对这些的报错
58
+ * 文案不稳定,映射不成可操作的错误码,所以这里主动拒绝。
59
+ *
60
+ * 方括号 IPv6(`[::1]`)是**允许**的:那是 ssh 自己的写法,`-L` 里的冒号被方括号包住,解析无歧义。
61
+ *
62
+ * @param request - 调用方的原始请求。
63
+ * @returns 去掉首尾空白、字段已校验的请求。
64
+ * @throws SshDevError `CONNECTION_INVALID` 当主机或端口不合法。
65
+ */
66
+ export declare function normalizeForwardRequest(request: ForwardRequest): ForwardRequest;
67
+ /**
68
+ * 一行描述一条转发,日志与错误文案共用。
69
+ *
70
+ * `localPort` 缺席时写 `?`:那时端口还没选出来,写 0 会被误读成"转发到 0 号端口"。
71
+ *
72
+ * @param forward - 部分句柄(至少要有远端目标)。
73
+ * @returns 形如 `127.0.0.1:8080 -> db:5432` 的一行。
74
+ */
75
+ export declare function forwardLabel(forward: Pick<ForwardHandle, 'remoteHost' | 'remotePort'> & Partial<Pick<ForwardHandle, 'localPort'>>): string;