dsh-over-ssh 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/README.md +10 -10
  2. package/agents/agent-manifest.json +1 -1
  3. package/lib/client.js +363 -314
  4. package/lib/file-references.js +80 -35
  5. package/lib/fs.js +158 -75
  6. package/lib/index.js +4103 -3397
  7. package/lib/terminal-wrapper.js +9 -4
  8. package/lib/types/src/config.d.ts +80 -9
  9. package/lib/types/src/file-references.d.ts +0 -1
  10. package/lib/types/src/host/app/backend.d.ts +9 -1
  11. package/lib/types/src/host/app/recycle-bin/recycle-bin-contract.d.ts +0 -1
  12. package/lib/types/src/host/app/recycle-bin/recycle-bin-service.d.ts +0 -1
  13. package/lib/types/src/host/app/session-admin/session-admin-contract.d.ts +12 -1
  14. package/lib/types/src/host/app/session-admin/session-admin-service.d.ts +0 -1
  15. package/lib/types/src/host/app/transport/transport-selector.d.ts +0 -1
  16. package/lib/types/src/host/app/transport/transport-service.d.ts +0 -1
  17. package/lib/types/src/host/domain/capability.d.ts +0 -1
  18. package/lib/types/src/host/domain/errors.d.ts +0 -1
  19. package/lib/types/src/host/domain/roots/connection.d.ts +0 -1
  20. package/lib/types/src/host/domain/roots/root.d.ts +24 -9
  21. package/lib/types/src/host/domain/roots/session-roots.d.ts +0 -1
  22. package/lib/types/src/host/domain/roots/ssh-config.d.ts +0 -1
  23. package/lib/types/src/host/domain/session/session-admin.d.ts +0 -1
  24. package/lib/types/src/host/domain/transfer/recycle-bin.d.ts +0 -1
  25. package/lib/types/src/host/domain/transfer/transfer.d.ts +0 -1
  26. package/lib/types/src/host/infra/transport/agent/agent-installer.d.ts +0 -1
  27. package/lib/types/src/host/infra/transport/ssh/ssh2-transport.d.ts +0 -1
  28. package/lib/types/src/host/infra/transport/transport-base.d.ts +0 -1
  29. package/lib/types/src/host/infra/transport/transport.d.ts +16 -2
  30. package/lib/types/src/host/integration/agent/agent-preflight.d.ts +0 -1
  31. package/lib/types/src/host/integration/fs/file-reference-provider.d.ts +0 -1
  32. package/lib/types/src/host/integration/fs/fs-provider.d.ts +0 -2
  33. package/lib/types/src/host/integration/transfer/transfer-service.d.ts +0 -1
  34. package/lib/types/src/index.d.ts +23 -1
  35. package/lib/types/src/local-bridge-refs.d.ts +0 -1
  36. package/lib/types/src/local-bridge.d.ts +0 -1
  37. package/lib/types/src/shared/root-keys.d.ts +120 -0
  38. package/lib/types/src/wiring/helpers.d.ts +0 -1
  39. package/package.json +5 -3
  40. package/lib/types/src/client/controls.d.ts +0 -131
  41. package/lib/types/src/client/core/card-focus-trap.d.ts +0 -45
  42. package/lib/types/src/client/core/controls.d.ts +0 -164
  43. package/lib/types/src/client/core/latest.d.ts +0 -48
  44. package/lib/types/src/client/core/locale.d.ts +0 -38
  45. package/lib/types/src/client/core/message.d.ts +0 -37
  46. package/lib/types/src/client/core/panel-model.d.ts +0 -134
  47. package/lib/types/src/client/core/portal.d.ts +0 -266
  48. package/lib/types/src/client/core/remote.d.ts +0 -84
  49. package/lib/types/src/client/core/styles.d.ts +0 -458
  50. package/lib/types/src/client/file-tree-io.d.ts +0 -19
  51. package/lib/types/src/client/file-tree.d.ts +0 -271
  52. package/lib/types/src/client/flows/directory-browser.d.ts +0 -587
  53. package/lib/types/src/client/flows/session-directory.d.ts +0 -415
  54. package/lib/types/src/client/flows/workspace-directory-flow.d.ts +0 -480
  55. package/lib/types/src/client/locale.d.ts +0 -31
  56. package/lib/types/src/client/panel-model.d.ts +0 -37
  57. package/lib/types/src/client/panel.d.ts +0 -77
  58. package/lib/types/src/client/roots/connection-test.d.ts +0 -69
  59. package/lib/types/src/client/roots/roots-panel-state.d.ts +0 -307
  60. package/lib/types/src/client/roots/roots-panel-view.d.ts +0 -280
  61. package/lib/types/src/client/roots/roots-panel.d.ts +0 -364
  62. package/lib/types/src/client/roots/transfer-panel-view.d.ts +0 -35
  63. package/lib/types/src/client/roots/transfer-panel.d.ts +0 -241
  64. package/lib/types/src/client/roots/transfer-progress.d.ts +0 -67
  65. package/lib/types/src/client/roots-panel-view.d.ts +0 -236
  66. package/lib/types/src/client/roots-panel.d.ts +0 -347
  67. package/lib/types/src/client/session/session-panel-view.d.ts +0 -336
  68. package/lib/types/src/client/session/session-panel.d.ts +0 -322
  69. package/lib/types/src/client/session/session-remote-mark.d.ts +0 -110
  70. package/lib/types/src/client/session/session-row-actions.d.ts +0 -398
  71. package/lib/types/src/client/session-panel.d.ts +0 -152
  72. package/lib/types/src/client/styles.d.ts +0 -252
  73. package/lib/types/src/client/workspace-directory-flow.d.ts +0 -342
  74. package/lib/types/src/fs.d.ts +0 -46
  75. package/lib/types/src/host/app/recycle-bin/recycle-bin-move.d.ts +0 -18
  76. package/lib/types/src/host/app/recycle-bin/recycle-bin-world.d.ts +0 -38
  77. package/lib/types/src/host/app/recycle-bin-contract.d.ts +0 -215
  78. package/lib/types/src/host/app/recycle-bin-move.d.ts +0 -18
  79. package/lib/types/src/host/app/recycle-bin-service.d.ts +0 -45
  80. package/lib/types/src/host/app/recycle-bin-world.d.ts +0 -35
  81. package/lib/types/src/host/app/roots/roots-api-connections.d.ts +0 -49
  82. package/lib/types/src/host/app/roots/roots-api-contract.d.ts +0 -369
  83. package/lib/types/src/host/app/roots/roots-api-directories.d.ts +0 -13
  84. package/lib/types/src/host/app/roots/roots-api-http.d.ts +0 -77
  85. package/lib/types/src/host/app/roots/roots-api-long-poll.d.ts +0 -130
  86. package/lib/types/src/host/app/roots/roots-api-projections.d.ts +0 -102
  87. package/lib/types/src/host/app/roots/roots-api-roots.d.ts +0 -13
  88. package/lib/types/src/host/app/roots/roots-api-state.d.ts +0 -22
  89. package/lib/types/src/host/app/roots/roots-api-transfers.d.ts +0 -26
  90. package/lib/types/src/host/app/roots/roots-api.d.ts +0 -55
  91. package/lib/types/src/host/app/roots/user-roots.d.ts +0 -552
  92. package/lib/types/src/host/app/roots-api-connections.d.ts +0 -49
  93. package/lib/types/src/host/app/roots-api-contract.d.ts +0 -339
  94. package/lib/types/src/host/app/roots-api-directories.d.ts +0 -13
  95. package/lib/types/src/host/app/roots-api-http.d.ts +0 -77
  96. package/lib/types/src/host/app/roots-api-projections.d.ts +0 -102
  97. package/lib/types/src/host/app/roots-api-roots.d.ts +0 -13
  98. package/lib/types/src/host/app/roots-api-state.d.ts +0 -22
  99. package/lib/types/src/host/app/roots-api-support.d.ts +0 -182
  100. package/lib/types/src/host/app/roots-api-transfers.d.ts +0 -13
  101. package/lib/types/src/host/app/roots-api.d.ts +0 -55
  102. package/lib/types/src/host/app/routed-fs.d.ts +0 -239
  103. package/lib/types/src/host/app/serialize.d.ts +0 -37
  104. package/lib/types/src/host/app/session-admin/session-admin-context.d.ts +0 -36
  105. package/lib/types/src/host/app/session-admin/session-admin-delete.d.ts +0 -34
  106. package/lib/types/src/host/app/session-admin-context.d.ts +0 -36
  107. package/lib/types/src/host/app/session-admin-contract.d.ts +0 -214
  108. package/lib/types/src/host/app/session-admin-delete.d.ts +0 -34
  109. package/lib/types/src/host/app/session-admin-service.d.ts +0 -38
  110. package/lib/types/src/host/app/takeover/takeover-plan.d.ts +0 -227
  111. package/lib/types/src/host/app/takeover/takeover-rows.d.ts +0 -55
  112. package/lib/types/src/host/app/transport-selector.d.ts +0 -98
  113. package/lib/types/src/host/app/transport-service.d.ts +0 -75
  114. package/lib/types/src/host/app/user-roots.d.ts +0 -461
  115. package/lib/types/src/host/domain/bin-location.d.ts +0 -79
  116. package/lib/types/src/host/domain/connection.d.ts +0 -95
  117. package/lib/types/src/host/domain/glob-pattern.d.ts +0 -62
  118. package/lib/types/src/host/domain/literal-text.d.ts +0 -63
  119. package/lib/types/src/host/domain/path-grammar.d.ts +0 -84
  120. package/lib/types/src/host/domain/recycle-bin.d.ts +0 -337
  121. package/lib/types/src/host/domain/root.d.ts +0 -74
  122. package/lib/types/src/host/domain/roots/bin-location.d.ts +0 -91
  123. package/lib/types/src/host/domain/roots/route-table.d.ts +0 -102
  124. package/lib/types/src/host/domain/route-table.d.ts +0 -80
  125. package/lib/types/src/host/domain/session/terminal-target.d.ts +0 -136
  126. package/lib/types/src/host/domain/session-admin.d.ts +0 -330
  127. package/lib/types/src/host/domain/shell.d.ts +0 -47
  128. package/lib/types/src/host/domain/ssh-config.d.ts +0 -73
  129. package/lib/types/src/host/domain/terminal-target.d.ts +0 -132
  130. package/lib/types/src/host/domain/tool-requests.d.ts +0 -369
  131. package/lib/types/src/host/domain/transfer.d.ts +0 -260
  132. package/lib/types/src/host/infra/backend/local-backend.d.ts +0 -84
  133. package/lib/types/src/host/infra/backend/local-version.d.ts +0 -43
  134. package/lib/types/src/host/infra/backend/platform-local-backend.d.ts +0 -89
  135. package/lib/types/src/host/infra/backend/remote-backend.d.ts +0 -239
  136. package/lib/types/src/host/infra/cache/lru.d.ts +0 -52
  137. package/lib/types/src/host/infra/cache/versioned.d.ts +0 -77
  138. package/lib/types/src/host/infra/temp-name.d.ts +0 -19
  139. package/lib/types/src/host/infra/transport/agent/agent-protocol-client.d.ts +0 -132
  140. package/lib/types/src/host/infra/transport/agent/agent-protocol-codec.d.ts +0 -140
  141. package/lib/types/src/host/infra/transport/agent/agent-protocol-errors.d.ts +0 -41
  142. package/lib/types/src/host/infra/transport/agent/agent-protocol-frames.d.ts +0 -197
  143. package/lib/types/src/host/infra/transport/agent/agent-protocol-types.d.ts +0 -564
  144. package/lib/types/src/host/infra/transport/agent/agent-transport.d.ts +0 -418
  145. package/lib/types/src/host/infra/transport/agent-installer.d.ts +0 -121
  146. package/lib/types/src/host/infra/transport/agent-protocol-client.d.ts +0 -123
  147. package/lib/types/src/host/infra/transport/agent-protocol-codec.d.ts +0 -131
  148. package/lib/types/src/host/infra/transport/agent-protocol-errors.d.ts +0 -41
  149. package/lib/types/src/host/infra/transport/agent-protocol-frames.d.ts +0 -197
  150. package/lib/types/src/host/infra/transport/agent-protocol-types.d.ts +0 -509
  151. package/lib/types/src/host/infra/transport/agent-transport.d.ts +0 -353
  152. package/lib/types/src/host/infra/transport/alias-transport.d.ts +0 -206
  153. package/lib/types/src/host/infra/transport/askpass-fs.d.ts +0 -20
  154. package/lib/types/src/host/infra/transport/askpass.d.ts +0 -133
  155. package/lib/types/src/host/infra/transport/command-pool.d.ts +0 -61
  156. package/lib/types/src/host/infra/transport/fs-commands.d.ts +0 -140
  157. package/lib/types/src/host/infra/transport/git-status-route.d.ts +0 -63
  158. package/lib/types/src/host/infra/transport/git-status.d.ts +0 -101
  159. package/lib/types/src/host/infra/transport/node-spawn.d.ts +0 -26
  160. package/lib/types/src/host/infra/transport/session-window.d.ts +0 -51
  161. package/lib/types/src/host/infra/transport/shell-quote.d.ts +0 -59
  162. package/lib/types/src/host/infra/transport/ssh/alias-transport.d.ts +0 -206
  163. package/lib/types/src/host/infra/transport/ssh/askpass-fs.d.ts +0 -20
  164. package/lib/types/src/host/infra/transport/ssh/askpass.d.ts +0 -133
  165. package/lib/types/src/host/infra/transport/ssh/shell-quote.d.ts +0 -62
  166. package/lib/types/src/host/infra/transport/ssh/ssh-argv.d.ts +0 -43
  167. package/lib/types/src/host/infra/transport/ssh-argv.d.ts +0 -43
  168. package/lib/types/src/host/infra/transport/ssh2-transport.d.ts +0 -302
  169. package/lib/types/src/host/integration/agent/agent-install-io.d.ts +0 -33
  170. package/lib/types/src/host/integration/agent/askpass-registry.d.ts +0 -66
  171. package/lib/types/src/host/integration/agent-install-io.d.ts +0 -33
  172. package/lib/types/src/host/integration/agent-preflight.d.ts +0 -56
  173. package/lib/types/src/host/integration/anchor-directory.d.ts +0 -56
  174. package/lib/types/src/host/integration/askpass-registry.d.ts +0 -59
  175. package/lib/types/src/host/integration/bin-root-resolver.d.ts +0 -81
  176. package/lib/types/src/host/integration/connection-test.d.ts +0 -73
  177. package/lib/types/src/host/integration/file-reference-provider.d.ts +0 -115
  178. package/lib/types/src/host/integration/fs/git-status-wiring.d.ts +0 -21
  179. package/lib/types/src/host/integration/fs/platform-errors.d.ts +0 -94
  180. package/lib/types/src/host/integration/fs/remote-file-tools.d.ts +0 -369
  181. package/lib/types/src/host/integration/fs/remote-index.d.ts +0 -177
  182. package/lib/types/src/host/integration/fs-provider.d.ts +0 -226
  183. package/lib/types/src/host/integration/lsp/lsp-framing.d.ts +0 -38
  184. package/lib/types/src/host/integration/lsp/lsp-registry.d.ts +0 -67
  185. package/lib/types/src/host/integration/lsp/lsp-session.d.ts +0 -130
  186. package/lib/types/src/host/integration/management-tools.d.ts +0 -64
  187. package/lib/types/src/host/integration/recycle-bin-service.d.ts +0 -247
  188. package/lib/types/src/host/integration/remote/connection-test.d.ts +0 -73
  189. package/lib/types/src/host/integration/remote/remote-face.d.ts +0 -127
  190. package/lib/types/src/host/integration/remote/remote-tool-backend.d.ts +0 -108
  191. package/lib/types/src/host/integration/remote-face.d.ts +0 -127
  192. package/lib/types/src/host/integration/remote-file-tools.d.ts +0 -241
  193. package/lib/types/src/host/integration/remote-home.d.ts +0 -69
  194. package/lib/types/src/host/integration/remote-index.d.ts +0 -165
  195. package/lib/types/src/host/integration/remote-job-tools.d.ts +0 -295
  196. package/lib/types/src/host/integration/remote-tool-backend.d.ts +0 -97
  197. package/lib/types/src/host/integration/remote-tools.d.ts +0 -206
  198. package/lib/types/src/host/integration/root-registry.d.ts +0 -115
  199. package/lib/types/src/host/integration/roots/anchor-directory.d.ts +0 -56
  200. package/lib/types/src/host/integration/roots/bin-root-resolver.d.ts +0 -81
  201. package/lib/types/src/host/integration/roots/remote-home.d.ts +0 -69
  202. package/lib/types/src/host/integration/roots/root-registry.d.ts +0 -144
  203. package/lib/types/src/host/integration/roots/roots-wiring.d.ts +0 -219
  204. package/lib/types/src/host/integration/roots/session-root-index.d.ts +0 -52
  205. package/lib/types/src/host/integration/roots-api.d.ts +0 -407
  206. package/lib/types/src/host/integration/roots-wiring.d.ts +0 -211
  207. package/lib/types/src/host/integration/session/session-api.d.ts +0 -88
  208. package/lib/types/src/host/integration/session/session-bin-lock.d.ts +0 -80
  209. package/lib/types/src/host/integration/session/session-header.d.ts +0 -151
  210. package/lib/types/src/host/integration/session/session-labels.d.ts +0 -56
  211. package/lib/types/src/host/integration/session/session-route-wiring.d.ts +0 -50
  212. package/lib/types/src/host/integration/session-admin-service.d.ts +0 -236
  213. package/lib/types/src/host/integration/session-api.d.ts +0 -81
  214. package/lib/types/src/host/integration/session-bin-lock.d.ts +0 -80
  215. package/lib/types/src/host/integration/session-header.d.ts +0 -118
  216. package/lib/types/src/host/integration/session-labels.d.ts +0 -56
  217. package/lib/types/src/host/integration/session-route-wiring.d.ts +0 -50
  218. package/lib/types/src/host/integration/session-scope.d.ts +0 -113
  219. package/lib/types/src/host/integration/session-tools.d.ts +0 -44
  220. package/lib/types/src/host/integration/strict-arguments.d.ts +0 -79
  221. package/lib/types/src/host/integration/takeover/takeover-api.d.ts +0 -62
  222. package/lib/types/src/host/integration/takeover/takeover-route-wiring.d.ts +0 -60
  223. package/lib/types/src/host/integration/takeover/takeover-service.d.ts +0 -167
  224. package/lib/types/src/host/integration/terminal-manifest.d.ts +0 -94
  225. package/lib/types/src/host/integration/tools/management-tools.d.ts +0 -245
  226. package/lib/types/src/host/integration/tools/remote-job-tools.d.ts +0 -316
  227. package/lib/types/src/host/integration/tools/remote-lsp-tools.d.ts +0 -43
  228. package/lib/types/src/host/integration/tools/remote-tools.d.ts +0 -236
  229. package/lib/types/src/host/integration/tools/session-target.d.ts +0 -52
  230. package/lib/types/src/host/integration/tools/session-tools.d.ts +0 -46
  231. package/lib/types/src/host/integration/tools/strict-arguments.d.ts +0 -79
  232. package/lib/types/src/host/integration/tools/terminal-manifest.d.ts +0 -94
  233. package/lib/types/src/host/integration/transfer/remote-copy.d.ts +0 -66
  234. package/lib/types/src/host/integration/transfer/transfer-adapters.d.ts +0 -48
  235. package/lib/types/src/host/integration/transfer/transfer-tracker.d.ts +0 -106
  236. package/lib/types/src/host/integration/transfer-adapters.d.ts +0 -44
  237. package/lib/types/src/host/integration/transfer-service.d.ts +0 -164
  238. package/lib/types/src/host/integration/transfer-tracker.d.ts +0 -106
  239. package/lib/types/src/host/integration/user-roots.d.ts +0 -461
  240. package/lib/types/src/wiring/connections.d.ts +0 -189
  241. package/lib/types/src/wiring/fs.d.ts +0 -13
  242. package/lib/types/src/wiring/install-memo.d.ts +0 -32
  243. package/lib/types/src/wiring/legacy-dirs.d.ts +0 -62
  244. package/lib/types/src/wiring/package-paths.d.ts +0 -35
  245. package/lib/types/src/wiring/roots.d.ts +0 -21
  246. package/lib/types/src/wiring/state-dir.d.ts +0 -29
  247. package/lib/types/src/wiring/tools.d.ts +0 -35
@@ -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,7 +84,27 @@ 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">;
88
108
  terminalStateDir: z<string, string, "plain">;
89
109
  transferChunkBytes: z<number, number, "defined">;
90
110
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
@@ -110,8 +130,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
110
130
  sessionBinMaxEntries: z<number, number, "defined">;
111
131
  sessionBinMaxBytes: z<number, number, "defined">;
112
132
  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
133
  }>>, Schemastery.ObjectT<NoInfer<{
116
134
  maxReadBytes: z<number, number, "defined">;
117
135
  connectTimeoutMs: z<number, number, "defined">;
@@ -133,7 +151,27 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
133
151
  */
134
152
  readCacheTtlMs: z<number, number, "defined">;
135
153
  readCacheMaxEntries: z<number, number, "defined">;
154
+ /**
155
+ * Byte ceiling for the read cache of **one remote root**, not for the plugin as a whole.
156
+ *
157
+ * 这条的语义必须写清楚,否则会读成"整个插件的上限":每个远端根各自持有一份版本缓存(外加一份
158
+ * 目录列举缓存),所以 N 个**同时存在**的根是 N × 这个数。上界因此是"活根数"而不是"历史根数"——
159
+ * 根被移除时 `Backend.dispose()` 会把它的缓存一起释放(审计 0112 P3-11 接线之前不是这样,
160
+ * 那才是 P3-12 真正的风险所在)。要压总占用就调小这个数,或者减少同时挂着的远端根。
161
+ */
136
162
  readCacheMaxBytes: z<number, number, "defined">;
163
+ /**
164
+ * Ceiling for the **sum** over every remote root's caches, not per root.
165
+ *
166
+ * 0112 P3-12 的缺口是"每个根各自封顶、加起来没人管":`readCacheMaxBytes` 是每根的额度,
167
+ * 十根就是十倍。这一项把总和钉住——超过时由**占用最大的那个**缓存让出最旧的条目(通常也是读者
168
+ * 正在看的那个,所以不让刚写的先挨刀)。
169
+ *
170
+ * 默认 64 MiB ≈ 8 个满额度的根。**必须是正整数**:要彻底关掉缓存请设
171
+ * `readCacheMaxBytes: 0`(那是"根本不缓存"),而不是把总预算设为 0——后者只会让每次写入
172
+ * 立刻把自己的条目淘汰掉,行为既不是"关缓存"也不是"缓存"。
173
+ */
174
+ readCacheTotalMaxBytes: z<number, number, "defined">;
137
175
  terminalStateDir: z<string, string, "plain">;
138
176
  transferChunkBytes: z<number, number, "defined">;
139
177
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
@@ -159,8 +197,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
159
197
  sessionBinMaxEntries: z<number, number, "defined">;
160
198
  sessionBinMaxBytes: z<number, number, "defined">;
161
199
  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
200
  }>>, "defined">;
165
201
  }>>, Schemastery.ObjectT<NoInfer<{
166
202
  connections: z<({
@@ -228,7 +264,27 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
228
264
  */
229
265
  readCacheTtlMs: z<number, number, "defined">;
230
266
  readCacheMaxEntries: z<number, number, "defined">;
267
+ /**
268
+ * Byte ceiling for the read cache of **one remote root**, not for the plugin as a whole.
269
+ *
270
+ * 这条的语义必须写清楚,否则会读成"整个插件的上限":每个远端根各自持有一份版本缓存(外加一份
271
+ * 目录列举缓存),所以 N 个**同时存在**的根是 N × 这个数。上界因此是"活根数"而不是"历史根数"——
272
+ * 根被移除时 `Backend.dispose()` 会把它的缓存一起释放(审计 0112 P3-11 接线之前不是这样,
273
+ * 那才是 P3-12 真正的风险所在)。要压总占用就调小这个数,或者减少同时挂着的远端根。
274
+ */
231
275
  readCacheMaxBytes: z<number, number, "defined">;
276
+ /**
277
+ * Ceiling for the **sum** over every remote root's caches, not per root.
278
+ *
279
+ * 0112 P3-12 的缺口是"每个根各自封顶、加起来没人管":`readCacheMaxBytes` 是每根的额度,
280
+ * 十根就是十倍。这一项把总和钉住——超过时由**占用最大的那个**缓存让出最旧的条目(通常也是读者
281
+ * 正在看的那个,所以不让刚写的先挨刀)。
282
+ *
283
+ * 默认 64 MiB ≈ 8 个满额度的根。**必须是正整数**:要彻底关掉缓存请设
284
+ * `readCacheMaxBytes: 0`(那是"根本不缓存"),而不是把总预算设为 0——后者只会让每次写入
285
+ * 立刻把自己的条目淘汰掉,行为既不是"关缓存"也不是"缓存"。
286
+ */
287
+ readCacheTotalMaxBytes: z<number, number, "defined">;
232
288
  terminalStateDir: z<string, string, "plain">;
233
289
  transferChunkBytes: z<number, number, "defined">;
234
290
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
@@ -254,8 +310,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
254
310
  sessionBinMaxEntries: z<number, number, "defined">;
255
311
  sessionBinMaxBytes: z<number, number, "defined">;
256
312
  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
313
  }>>, Schemastery.ObjectT<NoInfer<{
260
314
  maxReadBytes: z<number, number, "defined">;
261
315
  connectTimeoutMs: z<number, number, "defined">;
@@ -277,7 +331,27 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
277
331
  */
278
332
  readCacheTtlMs: z<number, number, "defined">;
279
333
  readCacheMaxEntries: z<number, number, "defined">;
334
+ /**
335
+ * Byte ceiling for the read cache of **one remote root**, not for the plugin as a whole.
336
+ *
337
+ * 这条的语义必须写清楚,否则会读成"整个插件的上限":每个远端根各自持有一份版本缓存(外加一份
338
+ * 目录列举缓存),所以 N 个**同时存在**的根是 N × 这个数。上界因此是"活根数"而不是"历史根数"——
339
+ * 根被移除时 `Backend.dispose()` 会把它的缓存一起释放(审计 0112 P3-11 接线之前不是这样,
340
+ * 那才是 P3-12 真正的风险所在)。要压总占用就调小这个数,或者减少同时挂着的远端根。
341
+ */
280
342
  readCacheMaxBytes: z<number, number, "defined">;
343
+ /**
344
+ * Ceiling for the **sum** over every remote root's caches, not per root.
345
+ *
346
+ * 0112 P3-12 的缺口是"每个根各自封顶、加起来没人管":`readCacheMaxBytes` 是每根的额度,
347
+ * 十根就是十倍。这一项把总和钉住——超过时由**占用最大的那个**缓存让出最旧的条目(通常也是读者
348
+ * 正在看的那个,所以不让刚写的先挨刀)。
349
+ *
350
+ * 默认 64 MiB ≈ 8 个满额度的根。**必须是正整数**:要彻底关掉缓存请设
351
+ * `readCacheMaxBytes: 0`(那是"根本不缓存"),而不是把总预算设为 0——后者只会让每次写入
352
+ * 立刻把自己的条目淘汰掉,行为既不是"关缓存"也不是"缓存"。
353
+ */
354
+ readCacheTotalMaxBytes: z<number, number, "defined">;
281
355
  terminalStateDir: z<string, string, "plain">;
282
356
  transferChunkBytes: z<number, number, "defined">;
283
357
  /** Chunks in flight at once during a transfer. 1 restores the sequential behaviour. */
@@ -303,10 +377,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
303
377
  sessionBinMaxEntries: z<number, number, "defined">;
304
378
  sessionBinMaxBytes: z<number, number, "defined">;
305
379
  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
380
  }>>, "defined">;
309
381
  }>>, "plain">;
310
382
  /** What {@link apply} receives: the schema's resolved output, which is what the loader passes. */
311
383
  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
@@ -77,6 +77,15 @@ export interface Backend {
77
77
  readonly sandboxMode: BackendSandboxMode | undefined;
78
78
  /** Whether the backend can watch for changes natively. */
79
79
  readonly watches: boolean;
80
+ /**
81
+ * Stop background work (watchers, poll loops) and release what this backend holds.
82
+ *
83
+ * Called when its root is retired. Optional: a backend with nothing to stop omits it. Without this call a
84
+ * removed root's watcher kept polling — `RemoteBackend.dispose()` existed but had **zero production callers**,
85
+ * so the poll loop outlived the root that started it and the remote inotify registration was never dropped
86
+ * (audit 0112 P3-11).
87
+ */
88
+ dispose?(): Promise<void>;
80
89
  /**
81
90
  * Watch one path for changes, in this backend's own absolute spelling (the backend layer has no `FsTarget`).
82
91
  *
@@ -167,4 +176,3 @@ export interface Backend {
167
176
  /** `file:` URL for this path in the backend's world. */
168
177
  fileUrl?(absolute: string): string;
169
178
  }
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
@@ -148,4 +148,3 @@ export declare function ambiguousSessionRootMessage(candidates: readonly Session
148
148
  * @returns whether the root may serve that caller.
149
149
  */
150
150
  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
@@ -325,4 +325,3 @@ export declare function sftpError(operation: string, path: string, error?: Error
325
325
  * session.
326
326
  */
327
327
  export declare const defaultConnector: Ssh2Connector;
328
- //# sourceMappingURL=ssh2-transport.d.ts.map
@@ -31,4 +31,3 @@ export declare abstract class TransportBase {
31
31
  /** Forget the probe (a reconnect must not keep a stale timestamp). */
32
32
  protected clearProbed(): void;
33
33
  }
34
- //# sourceMappingURL=transport-base.d.ts.map
@@ -522,6 +522,20 @@ export interface Transport {
522
522
  }
523
523
  /** Encode bytes as base64 without line wrapping. */
524
524
  export declare function encodeBase64(bytes: Uint8Array): string;
525
- /** Decode base64, ignoring line breaks produced by remote tooling. */
525
+ /**
526
+ * Decode base64, ignoring line breaks produced by remote tooling.
527
+ *
528
+ * **两次多余的整串处理被去掉了**(审计 0112 P3-2):
529
+ *
530
+ * 1. `text.replace(/\s+/g, '')` 先把整串扫一遍去掉空白。Node 的 base64 解码**本来就忽略空白**
531
+ * (`\n` / `\r\n` / 空格 / 制表符都已实测逐字节等价,见本函数下方的测试),所以这一遍纯属浪费:
532
+ * 9 MiB 负载(12.7 MB base64)实测 17.3 ms → 7.1 ms。
533
+ * 2. `new Uint8Array(...)` 把解码结果再拷一遍。4 KiB 以上的解码本来就不走 Buffer 的共享池,
534
+ * `Buffer.from(str, 'base64')` 的返回对象已经是独占、正好大小的 `Uint8Array`,直接交出去即可
535
+ * (9 MiB 的一次拷贝实测 1.4 ms,而它正是这条读路径上最大的一块)。
536
+ *
537
+ * **小结果仍然拷一次,这是有意的**:`Buffer.from(string)` 在 4 KiB 以下会落进 Node 的 64 KiB 共享池,
538
+ * 原样返回会让一个几十字节的缓存值长期钉住 64 KiB(读缓存按 `byteLength` 记账,看不见这块)。
539
+ * 那次拷贝是几十字节,与热路径无关。
540
+ */
526
541
  export declare function decodeBase64(text: string): Uint8Array;
527
- //# sourceMappingURL=transport.d.ts.map
@@ -53,4 +53,3 @@ export interface AgentPreflight {
53
53
  * @returns the preflight, an installation lookup, and a way to forget a connection.
54
54
  */
55
55
  export declare function createAgentPreflight(options: AgentPreflightOptions): AgentPreflight;
56
- //# sourceMappingURL=agent-preflight.d.ts.map
@@ -139,4 +139,3 @@ export declare class RemoteFileReferenceService extends FileReferenceService {
139
139
  list(agent: Agent, query: string, signal: AbortSignal): Promise<FileReferenceCandidate[]>;
140
140
  }
141
141
  export default RemoteFileReferenceService;
142
- //# sourceMappingURL=file-reference-provider.d.ts.map
@@ -101,7 +101,6 @@ export interface RoutedFsProviderOptions {
101
101
  * model's file tools follow the router (see `cordis.patch.yml`).
102
102
  */
103
103
  export declare class RoutedFsProvider extends FileSystem {
104
- #private;
105
104
  static inject: string[];
106
105
  protected readonly rangeReader: BackendRangeReader | undefined;
107
106
  protected readonly rangeChunkBytes: number;
@@ -365,4 +364,3 @@ export declare function createBackendRangeReader(store: (backend: Backend, offse
365
364
  export declare function toFsError(error: SshDevError): FsError;
366
365
  /** Codes this provider can surface, exported for tests that assert the mapping table. */
367
366
  export declare const MAPPED_DOMAIN_CODES: readonly SshDevErrorCode[];
368
- //# sourceMappingURL=fs-provider.d.ts.map
@@ -209,4 +209,3 @@ export declare const RESUME_VERIFY_BYTES: number;
209
209
  * @returns the upload/download operations; no state is kept between calls.
210
210
  */
211
211
  export declare function createTransferService(dependencies: TransferDependencies): TransferService;
212
- //# sourceMappingURL=transfer-service.d.ts.map
@@ -1,3 +1,18 @@
1
+ /**
2
+ * The host plugin entry: configuration, services and the object graph behind this plugin.
3
+ *
4
+ * It provides two services and nothing else, deliberately:
5
+ *
6
+ * - `sshDevConnections` — the validated connection profiles (secrets referenced by credential key).
7
+ * - `sshDevRoots` — the {@link RootRegistry} the `ctx.fs` provider (`dsh-over-ssh/fs`) injects.
8
+ *
9
+ * Transports are constructed lazily and owned by a {@link TransportService}, so a client half (or a
10
+ * root added at runtime) simply calls into the registry and everything else follows. Nothing here
11
+ * reads a secret eagerly: passwords live in `ctx.credentials` and are resolved when a connection is
12
+ * actually opened.
13
+ *
14
+ * @module dsh-over-ssh
15
+ */
1
16
  import { Context } from '@deepseek-ai/cordis';
2
17
  import { TransportService } from './host/app/transport/transport-service.ts';
3
18
  import { Config } from './config.ts';
@@ -54,6 +69,14 @@ declare module '@deepseek-ai/cordis' {
54
69
  sshDevSessionAdmin: SessionAdminService;
55
70
  }
56
71
  }
72
+ /**
73
+ * Read a session log's header line.
74
+ *
75
+ * The bounded reader lives in {@link createDiskSessionHeaderReader} rather than here: a composition root
76
+ * cannot be exercised by a test (审计 0046 记录了同款教训), and a reader whose *memory bound* is its whole
77
+ * contract must have one. The previous inline version read the entire log before slicing 256 KiB off it —
78
+ * measured at 105.3 MiB of reads for this machine's 73 sessions, worst single log 10.9 MiB (审计 0050).
79
+ */
57
80
  /**
58
81
  * Install the plugin.
59
82
  *
@@ -63,4 +86,3 @@ declare module '@deepseek-ai/cordis' {
63
86
  */
64
87
  export { Config };
65
88
  export declare function apply(ctx: Context, config: ResolvedConfig): void;
66
- //# sourceMappingURL=index.d.ts.map
@@ -23,4 +23,3 @@ export default class LocalFileReferencesBridge {
23
23
  static inject: readonly ["fileReferences"];
24
24
  constructor(ctx: Context);
25
25
  }
26
- //# sourceMappingURL=local-bridge-refs.d.ts.map
@@ -33,4 +33,3 @@ export default class LocalFsBridge {
33
33
  static inject: readonly ["fs"];
34
34
  constructor(ctx: Context);
35
35
  }
36
- //# sourceMappingURL=local-bridge.d.ts.map
@@ -0,0 +1,120 @@
1
+ /**
2
+ * 根路径与根键的**唯一拼写规则**:client 与 host 两侧都 import 这一份。
3
+ *
4
+ * 为什么在 `shared/`:这三条规则此前各有两份实现,而每一对都已经分叉过一次(审计 0112 P2-11):
5
+ *
6
+ * - **根键**:客户端拼 `local:<原样路径>`,宿主拼 `local:<规范化路径>`(Windows 上还折叠大小写)。
7
+ * 0024 §8.3 的"删除按钮发出宿主匹配不上的键"就是这个分叉的直接后果——面板把那行显示出来,
8
+ * 点删除却什么也没发生,而两边各自的用例都是绿的;
9
+ * - **绝对本地路径**:宿主不认 `\\server\share`(它先规范化再判断,所以只认 `//server/share`),
10
+ * 客户端认。同一个 UNC 路径在两半得到相反的答案;
11
+ * - **远端父目录**:客户端自己 `lastIndexOf('/')`,宿主的 `remoteDirname` 先规范化(`/a//b/` 与
12
+ * `/a/b` 因此是不同的答案)。
13
+ *
14
+ * `shared/` 是两侧唯一都能 import 的位置:`tests/architecture.test.ts` 规定 client 只能依赖
15
+ * `client` 与 `shared`,而 `shared` 只能依赖自己。这也是 `routes.ts` / `format.ts` 住在这里的理由。
16
+ *
17
+ * 本模块是**纯函数**,且**不读 `process`**:它会被打进浏览器 bundle(`platform: 'browser'`),
18
+ * 那里没有 `process`。平台相关的决定由调用方作为参数传进来——见 {@link rootKeySpelling} 的
19
+ * `caseInsensitive`:宿主的 `domain/roots/root.ts` 传 `process.platform === 'win32'`,客户端不猜。
20
+ *
21
+ * 三个函数都是**全函数**(不抛错):宿主那一侧的错误策略(`SshDevError('ROOT_INVALID')`)留在
22
+ * `domain/` 里,因为客户端在 reducer 里抛错等于把界面炸掉。所以这里能共享的是**规则**,不是
23
+ * "遇到坏输入怎么办"。
24
+ *
25
+ * @module dsh-over-ssh/shared/root-keys
26
+ */
27
+ /** Where a root lives: on this machine, or behind a connection. */
28
+ export type RootLocation = 'local' | 'remote';
29
+ /**
30
+ * One option bag for every spelling rule here.
31
+ *
32
+ * Only `caseInsensitive` exists today, and only for **local** paths: a Windows host folds case in the
33
+ * registry, a POSIX host does not, and a browser cannot know which. So the decision travels as an argument
34
+ * instead of being read from `process` inside a function that both halves call.
35
+ */
36
+ export interface RootKeyOptions {
37
+ /** Fold case in a local path/key. Defaults to `false` — "keep the caller's case". */
38
+ readonly caseInsensitive?: boolean;
39
+ }
40
+ /**
41
+ * Whether a host path is absolute in either the Windows or the POSIX spelling.
42
+ *
43
+ * Both UNC spellings are accepted: `\\server\share` (what a Windows operator types) and `//server/share`
44
+ * (what {@link normalizeLocalPath} produces). The host used to accept only the second, the client only the
45
+ * first — so the panel and `makeLocalRoot` disagreed about the same string.
46
+ *
47
+ * @param path - candidate host path.
48
+ * @returns whether it names an absolute host path.
49
+ */
50
+ export declare function isAbsoluteLocalPath(path: string): boolean;
51
+ /**
52
+ * Normalize a host path for comparison: separators to `/`, `.`/`..` resolved, trailing separators dropped,
53
+ * and (optionally) the drive letter and case folded.
54
+ *
55
+ * Total: a relative spelling comes back as a relative spelling (`src` → `src`). The caller decides whether
56
+ * that is an error (the host's `makeLocalRoot`/`validateRoot` check {@link isAbsoluteLocalPath} after this).
57
+ *
58
+ * @param path - host path in either separator spelling.
59
+ * @param options - `caseInsensitive` folds case for comparison keys.
60
+ * @returns the normalized path.
61
+ */
62
+ export declare function normalizeLocalPath(path: string, options?: RootKeyOptions): string;
63
+ /**
64
+ * Normalize an absolute POSIX path: repeated separators collapsed, `.`/`..` resolved, trailing separators
65
+ * dropped (except for the root).
66
+ *
67
+ * Total: `undefined` means "not an absolute POSIX spelling". The host's `normalizeRemotePath` is the same
68
+ * rule plus the `SshDevError('ROOT_INVALID')` policy on top.
69
+ *
70
+ * @param path - candidate absolute POSIX path.
71
+ * @returns the normalized path, or `undefined` when the spelling is not absolute.
72
+ */
73
+ export declare function normalizePosixPath(path: string): string | undefined;
74
+ /**
75
+ * The parent directory of a **normalized** absolute POSIX path; the root's parent is `/`.
76
+ *
77
+ * One rule, two policies on top: the host's `remoteDirname` answers `/` for the root (a root's parent is
78
+ * itself, which is what its callers assume), while the directory browser's `parentRemotePath` answers
79
+ * `undefined` there (the "up" button must be disabled). The separator arithmetic is not repeated.
80
+ *
81
+ * @param normalized - an absolute POSIX path already passed through {@link normalizePosixPath}.
82
+ * @returns the parent directory.
83
+ */
84
+ export declare function posixDirname(normalized: string): string;
85
+ /**
86
+ * The key one root answers to, spelled the way **both halves** must spell it:
87
+ * `local:<normalized local path>` or `remote:<connectionId>:<normalized POSIX path>`.
88
+ *
89
+ * This is the string a client sends back to remove a root and the string the registry stores, so the two
90
+ * have to be the same function — the earlier client spelling (`local:-:<path>`, then `local:<raw path>`)
91
+ * produced keys the host could not match (audit 0024 §8.3, §8.5).
92
+ *
93
+ * Case is **not** folded here unless the caller asks: the host passes `{ caseInsensitive: process.platform
94
+ * === 'win32' }` (that is where its registry folds), and the client passes nothing because it cannot know
95
+ * the host's platform. Case-differing keys are therefore matched by {@link rootKeyIdentity} (the client's
96
+ * join) and by the host's own `sameRootKey`/`liveKeyFor` comparison — never by string equality on the key.
97
+ *
98
+ * @param location - local or remote.
99
+ * @param path - host path (either separator spelling) or absolute POSIX path.
100
+ * @param connectionId - the connection for a remote root; absent spells `remote::<path>` (the client's
101
+ * fallback for a malformed answer — the host rejects such a root before it ever gets here).
102
+ * @param options - `caseInsensitive` folds case in a local key.
103
+ * @returns the key.
104
+ */
105
+ export declare function rootKeySpelling(location: RootLocation, path: string, connectionId?: string, options?: RootKeyOptions): string;
106
+ /**
107
+ * The identity two root keys are joined by: `local:` keys compare **case-insensitively**, remote keys do not.
108
+ *
109
+ * Why unconditional for local: the host's registry folds a Windows local path to lower case while the panel's
110
+ * own file keeps the caller's case, so "the same root" routinely arrives with two spellings. The host has
111
+ * always compared this way (`sameRootKey` in `app/roots/user-roots.ts`, out of this change's write scope);
112
+ * this is the client's half of the same rule, and without it a live root reads as "not in the file", which
113
+ * silently removes its delete button (audit 0024 §8.5).
114
+ *
115
+ * Remote paths are POSIX and therefore case-sensitive, so their keys are compared verbatim.
116
+ *
117
+ * @param key - one root key (or anything shaped like one).
118
+ * @returns the join identity.
119
+ */
120
+ export declare function rootKeyIdentity(key: string): string;
@@ -141,4 +141,3 @@ export interface CredentialsLike {
141
141
  }
142
142
  /** 会话日志头读取器(原先在 index.ts 底部,被 tools 段的会话管理使用)。 */
143
143
  export declare const readSessionHeader: (dir: string) => Promise<import("../host/app/session-admin/session-admin-contract.ts").SessionHeader | undefined>;
144
- //# sourceMappingURL=helpers.d.ts.map