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.
- package/README.md +19 -17
- package/agents/agent-manifest.json +6 -6
- package/agents/linux-amd64/dsh-over-ssh-agent +0 -0
- package/agents/linux-arm64/dsh-over-ssh-agent +0 -0
- package/lib/client.js +422 -337
- package/lib/file-references.js +92 -35
- package/lib/fs.js +295 -113
- package/lib/index.js +6912 -4330
- package/lib/terminal-wrapper.js +9 -4
- package/lib/types/src/config.d.ts +156 -9
- package/lib/types/src/file-references.d.ts +0 -1
- package/lib/types/src/host/app/backend.d.ts +44 -3
- package/lib/types/src/host/app/recycle-bin/recycle-bin-contract.d.ts +0 -1
- package/lib/types/src/host/app/recycle-bin/recycle-bin-service.d.ts +0 -1
- package/lib/types/src/host/app/session-admin/session-admin-contract.d.ts +12 -1
- package/lib/types/src/host/app/session-admin/session-admin-service.d.ts +0 -1
- package/lib/types/src/host/app/transport/transport-selector.d.ts +0 -1
- package/lib/types/src/host/app/transport/transport-service.d.ts +0 -1
- package/lib/types/src/host/domain/capability.d.ts +0 -1
- package/lib/types/src/host/domain/errors.d.ts +0 -1
- package/lib/types/src/host/domain/roots/connection.d.ts +0 -1
- package/lib/types/src/host/domain/roots/root.d.ts +24 -9
- package/lib/types/src/host/domain/roots/session-roots.d.ts +23 -1
- package/lib/types/src/host/domain/roots/ssh-config.d.ts +0 -1
- package/lib/types/src/host/domain/session/session-admin.d.ts +0 -1
- package/lib/types/src/host/domain/transfer/recycle-bin.d.ts +0 -1
- package/lib/types/src/host/domain/transfer/transfer.d.ts +0 -1
- package/lib/types/src/host/infra/transport/agent/agent-installer.d.ts +0 -1
- package/lib/types/src/host/infra/transport/forward.d.ts +75 -0
- package/lib/types/src/host/infra/transport/ssh/ssh2-transport.d.ts +5 -1
- package/lib/types/src/host/infra/transport/transport-base.d.ts +0 -1
- package/lib/types/src/host/infra/transport/transport.d.ts +42 -2
- package/lib/types/src/host/integration/agent/agent-preflight.d.ts +0 -1
- package/lib/types/src/host/integration/fs/file-reference-provider.d.ts +0 -1
- package/lib/types/src/host/integration/fs/fs-provider.d.ts +18 -3
- package/lib/types/src/host/integration/transfer/transfer-service.d.ts +0 -1
- package/lib/types/src/index.d.ts +23 -1
- package/lib/types/src/local-bridge-refs.d.ts +0 -1
- package/lib/types/src/local-bridge.d.ts +0 -1
- package/lib/types/src/shared/root-keys.d.ts +120 -0
- package/lib/types/src/wiring/helpers.d.ts +0 -1
- package/package.json +5 -3
- package/lib/types/src/client/controls.d.ts +0 -131
- package/lib/types/src/client/core/card-focus-trap.d.ts +0 -45
- package/lib/types/src/client/core/controls.d.ts +0 -164
- package/lib/types/src/client/core/latest.d.ts +0 -48
- package/lib/types/src/client/core/locale.d.ts +0 -38
- package/lib/types/src/client/core/message.d.ts +0 -37
- package/lib/types/src/client/core/panel-model.d.ts +0 -134
- package/lib/types/src/client/core/portal.d.ts +0 -266
- package/lib/types/src/client/core/remote.d.ts +0 -84
- package/lib/types/src/client/core/styles.d.ts +0 -458
- package/lib/types/src/client/file-tree-io.d.ts +0 -19
- package/lib/types/src/client/file-tree.d.ts +0 -271
- package/lib/types/src/client/flows/directory-browser.d.ts +0 -587
- package/lib/types/src/client/flows/session-directory.d.ts +0 -415
- package/lib/types/src/client/flows/workspace-directory-flow.d.ts +0 -480
- package/lib/types/src/client/locale.d.ts +0 -31
- package/lib/types/src/client/panel-model.d.ts +0 -37
- package/lib/types/src/client/panel.d.ts +0 -77
- package/lib/types/src/client/roots/connection-test.d.ts +0 -69
- package/lib/types/src/client/roots/roots-panel-state.d.ts +0 -307
- package/lib/types/src/client/roots/roots-panel-view.d.ts +0 -280
- package/lib/types/src/client/roots/roots-panel.d.ts +0 -364
- package/lib/types/src/client/roots/transfer-panel-view.d.ts +0 -35
- package/lib/types/src/client/roots/transfer-panel.d.ts +0 -241
- package/lib/types/src/client/roots/transfer-progress.d.ts +0 -67
- package/lib/types/src/client/roots-panel-view.d.ts +0 -236
- package/lib/types/src/client/roots-panel.d.ts +0 -347
- package/lib/types/src/client/session/session-panel-view.d.ts +0 -336
- package/lib/types/src/client/session/session-panel.d.ts +0 -322
- package/lib/types/src/client/session/session-remote-mark.d.ts +0 -110
- package/lib/types/src/client/session/session-row-actions.d.ts +0 -398
- package/lib/types/src/client/session-panel.d.ts +0 -152
- package/lib/types/src/client/styles.d.ts +0 -252
- package/lib/types/src/client/workspace-directory-flow.d.ts +0 -342
- package/lib/types/src/fs.d.ts +0 -46
- package/lib/types/src/host/app/recycle-bin/recycle-bin-move.d.ts +0 -18
- package/lib/types/src/host/app/recycle-bin/recycle-bin-world.d.ts +0 -38
- package/lib/types/src/host/app/recycle-bin-contract.d.ts +0 -215
- package/lib/types/src/host/app/recycle-bin-move.d.ts +0 -18
- package/lib/types/src/host/app/recycle-bin-service.d.ts +0 -45
- package/lib/types/src/host/app/recycle-bin-world.d.ts +0 -35
- package/lib/types/src/host/app/roots/roots-api-connections.d.ts +0 -49
- package/lib/types/src/host/app/roots/roots-api-contract.d.ts +0 -369
- package/lib/types/src/host/app/roots/roots-api-directories.d.ts +0 -13
- package/lib/types/src/host/app/roots/roots-api-http.d.ts +0 -77
- package/lib/types/src/host/app/roots/roots-api-long-poll.d.ts +0 -130
- package/lib/types/src/host/app/roots/roots-api-projections.d.ts +0 -102
- package/lib/types/src/host/app/roots/roots-api-roots.d.ts +0 -13
- package/lib/types/src/host/app/roots/roots-api-state.d.ts +0 -22
- package/lib/types/src/host/app/roots/roots-api-transfers.d.ts +0 -26
- package/lib/types/src/host/app/roots/roots-api.d.ts +0 -55
- package/lib/types/src/host/app/roots/user-roots.d.ts +0 -552
- package/lib/types/src/host/app/roots-api-connections.d.ts +0 -49
- package/lib/types/src/host/app/roots-api-contract.d.ts +0 -339
- package/lib/types/src/host/app/roots-api-directories.d.ts +0 -13
- package/lib/types/src/host/app/roots-api-http.d.ts +0 -77
- package/lib/types/src/host/app/roots-api-projections.d.ts +0 -102
- package/lib/types/src/host/app/roots-api-roots.d.ts +0 -13
- package/lib/types/src/host/app/roots-api-state.d.ts +0 -22
- package/lib/types/src/host/app/roots-api-support.d.ts +0 -182
- package/lib/types/src/host/app/roots-api-transfers.d.ts +0 -13
- package/lib/types/src/host/app/roots-api.d.ts +0 -55
- package/lib/types/src/host/app/routed-fs.d.ts +0 -239
- package/lib/types/src/host/app/serialize.d.ts +0 -37
- package/lib/types/src/host/app/session-admin/session-admin-context.d.ts +0 -36
- package/lib/types/src/host/app/session-admin/session-admin-delete.d.ts +0 -34
- package/lib/types/src/host/app/session-admin-context.d.ts +0 -36
- package/lib/types/src/host/app/session-admin-contract.d.ts +0 -214
- package/lib/types/src/host/app/session-admin-delete.d.ts +0 -34
- package/lib/types/src/host/app/session-admin-service.d.ts +0 -38
- package/lib/types/src/host/app/takeover/takeover-plan.d.ts +0 -227
- package/lib/types/src/host/app/takeover/takeover-rows.d.ts +0 -55
- package/lib/types/src/host/app/transport-selector.d.ts +0 -98
- package/lib/types/src/host/app/transport-service.d.ts +0 -75
- package/lib/types/src/host/app/user-roots.d.ts +0 -461
- package/lib/types/src/host/domain/bin-location.d.ts +0 -79
- package/lib/types/src/host/domain/connection.d.ts +0 -95
- package/lib/types/src/host/domain/glob-pattern.d.ts +0 -62
- package/lib/types/src/host/domain/literal-text.d.ts +0 -63
- package/lib/types/src/host/domain/path-grammar.d.ts +0 -84
- package/lib/types/src/host/domain/recycle-bin.d.ts +0 -337
- package/lib/types/src/host/domain/root.d.ts +0 -74
- package/lib/types/src/host/domain/roots/bin-location.d.ts +0 -91
- package/lib/types/src/host/domain/roots/route-table.d.ts +0 -102
- package/lib/types/src/host/domain/route-table.d.ts +0 -80
- package/lib/types/src/host/domain/session/terminal-target.d.ts +0 -136
- package/lib/types/src/host/domain/session-admin.d.ts +0 -330
- package/lib/types/src/host/domain/shell.d.ts +0 -47
- package/lib/types/src/host/domain/ssh-config.d.ts +0 -73
- package/lib/types/src/host/domain/terminal-target.d.ts +0 -132
- package/lib/types/src/host/domain/tool-requests.d.ts +0 -369
- package/lib/types/src/host/domain/transfer.d.ts +0 -260
- package/lib/types/src/host/infra/backend/local-backend.d.ts +0 -84
- package/lib/types/src/host/infra/backend/local-version.d.ts +0 -43
- package/lib/types/src/host/infra/backend/platform-local-backend.d.ts +0 -89
- package/lib/types/src/host/infra/backend/remote-backend.d.ts +0 -239
- package/lib/types/src/host/infra/cache/lru.d.ts +0 -52
- package/lib/types/src/host/infra/cache/versioned.d.ts +0 -77
- package/lib/types/src/host/infra/temp-name.d.ts +0 -19
- package/lib/types/src/host/infra/transport/agent/agent-protocol-client.d.ts +0 -132
- package/lib/types/src/host/infra/transport/agent/agent-protocol-codec.d.ts +0 -140
- package/lib/types/src/host/infra/transport/agent/agent-protocol-errors.d.ts +0 -41
- package/lib/types/src/host/infra/transport/agent/agent-protocol-frames.d.ts +0 -197
- package/lib/types/src/host/infra/transport/agent/agent-protocol-types.d.ts +0 -564
- package/lib/types/src/host/infra/transport/agent/agent-transport.d.ts +0 -418
- package/lib/types/src/host/infra/transport/agent-installer.d.ts +0 -121
- package/lib/types/src/host/infra/transport/agent-protocol-client.d.ts +0 -123
- package/lib/types/src/host/infra/transport/agent-protocol-codec.d.ts +0 -131
- package/lib/types/src/host/infra/transport/agent-protocol-errors.d.ts +0 -41
- package/lib/types/src/host/infra/transport/agent-protocol-frames.d.ts +0 -197
- package/lib/types/src/host/infra/transport/agent-protocol-types.d.ts +0 -509
- package/lib/types/src/host/infra/transport/agent-transport.d.ts +0 -353
- package/lib/types/src/host/infra/transport/alias-transport.d.ts +0 -206
- package/lib/types/src/host/infra/transport/askpass-fs.d.ts +0 -20
- package/lib/types/src/host/infra/transport/askpass.d.ts +0 -133
- package/lib/types/src/host/infra/transport/command-pool.d.ts +0 -61
- package/lib/types/src/host/infra/transport/fs-commands.d.ts +0 -140
- package/lib/types/src/host/infra/transport/git-status-route.d.ts +0 -63
- package/lib/types/src/host/infra/transport/git-status.d.ts +0 -101
- package/lib/types/src/host/infra/transport/node-spawn.d.ts +0 -26
- package/lib/types/src/host/infra/transport/session-window.d.ts +0 -51
- package/lib/types/src/host/infra/transport/shell-quote.d.ts +0 -59
- package/lib/types/src/host/infra/transport/ssh/alias-transport.d.ts +0 -206
- package/lib/types/src/host/infra/transport/ssh/askpass-fs.d.ts +0 -20
- package/lib/types/src/host/infra/transport/ssh/askpass.d.ts +0 -133
- package/lib/types/src/host/infra/transport/ssh/shell-quote.d.ts +0 -62
- package/lib/types/src/host/infra/transport/ssh/ssh-argv.d.ts +0 -43
- package/lib/types/src/host/infra/transport/ssh-argv.d.ts +0 -43
- package/lib/types/src/host/infra/transport/ssh2-transport.d.ts +0 -302
- package/lib/types/src/host/integration/agent/agent-install-io.d.ts +0 -33
- package/lib/types/src/host/integration/agent/askpass-registry.d.ts +0 -66
- package/lib/types/src/host/integration/agent-install-io.d.ts +0 -33
- package/lib/types/src/host/integration/agent-preflight.d.ts +0 -56
- package/lib/types/src/host/integration/anchor-directory.d.ts +0 -56
- package/lib/types/src/host/integration/askpass-registry.d.ts +0 -59
- package/lib/types/src/host/integration/bin-root-resolver.d.ts +0 -81
- package/lib/types/src/host/integration/connection-test.d.ts +0 -73
- package/lib/types/src/host/integration/file-reference-provider.d.ts +0 -115
- package/lib/types/src/host/integration/fs/git-status-wiring.d.ts +0 -21
- package/lib/types/src/host/integration/fs/platform-errors.d.ts +0 -94
- package/lib/types/src/host/integration/fs/remote-file-tools.d.ts +0 -369
- package/lib/types/src/host/integration/fs/remote-index.d.ts +0 -177
- package/lib/types/src/host/integration/fs-provider.d.ts +0 -226
- package/lib/types/src/host/integration/lsp/lsp-framing.d.ts +0 -38
- package/lib/types/src/host/integration/lsp/lsp-registry.d.ts +0 -67
- package/lib/types/src/host/integration/lsp/lsp-session.d.ts +0 -130
- package/lib/types/src/host/integration/management-tools.d.ts +0 -64
- package/lib/types/src/host/integration/recycle-bin-service.d.ts +0 -247
- package/lib/types/src/host/integration/remote/connection-test.d.ts +0 -73
- package/lib/types/src/host/integration/remote/remote-face.d.ts +0 -127
- package/lib/types/src/host/integration/remote/remote-tool-backend.d.ts +0 -108
- package/lib/types/src/host/integration/remote-face.d.ts +0 -127
- package/lib/types/src/host/integration/remote-file-tools.d.ts +0 -241
- package/lib/types/src/host/integration/remote-home.d.ts +0 -69
- package/lib/types/src/host/integration/remote-index.d.ts +0 -165
- package/lib/types/src/host/integration/remote-job-tools.d.ts +0 -295
- package/lib/types/src/host/integration/remote-tool-backend.d.ts +0 -97
- package/lib/types/src/host/integration/remote-tools.d.ts +0 -206
- package/lib/types/src/host/integration/root-registry.d.ts +0 -115
- package/lib/types/src/host/integration/roots/anchor-directory.d.ts +0 -56
- package/lib/types/src/host/integration/roots/bin-root-resolver.d.ts +0 -81
- package/lib/types/src/host/integration/roots/remote-home.d.ts +0 -69
- package/lib/types/src/host/integration/roots/root-registry.d.ts +0 -144
- package/lib/types/src/host/integration/roots/roots-wiring.d.ts +0 -219
- package/lib/types/src/host/integration/roots/session-root-index.d.ts +0 -52
- package/lib/types/src/host/integration/roots-api.d.ts +0 -407
- package/lib/types/src/host/integration/roots-wiring.d.ts +0 -211
- package/lib/types/src/host/integration/session/session-api.d.ts +0 -88
- package/lib/types/src/host/integration/session/session-bin-lock.d.ts +0 -80
- package/lib/types/src/host/integration/session/session-header.d.ts +0 -151
- package/lib/types/src/host/integration/session/session-labels.d.ts +0 -56
- package/lib/types/src/host/integration/session/session-route-wiring.d.ts +0 -50
- package/lib/types/src/host/integration/session-admin-service.d.ts +0 -236
- package/lib/types/src/host/integration/session-api.d.ts +0 -81
- package/lib/types/src/host/integration/session-bin-lock.d.ts +0 -80
- package/lib/types/src/host/integration/session-header.d.ts +0 -118
- package/lib/types/src/host/integration/session-labels.d.ts +0 -56
- package/lib/types/src/host/integration/session-route-wiring.d.ts +0 -50
- package/lib/types/src/host/integration/session-scope.d.ts +0 -113
- package/lib/types/src/host/integration/session-tools.d.ts +0 -44
- package/lib/types/src/host/integration/strict-arguments.d.ts +0 -79
- package/lib/types/src/host/integration/takeover/takeover-api.d.ts +0 -62
- package/lib/types/src/host/integration/takeover/takeover-route-wiring.d.ts +0 -60
- package/lib/types/src/host/integration/takeover/takeover-service.d.ts +0 -167
- package/lib/types/src/host/integration/terminal-manifest.d.ts +0 -94
- package/lib/types/src/host/integration/tools/management-tools.d.ts +0 -245
- package/lib/types/src/host/integration/tools/remote-job-tools.d.ts +0 -316
- package/lib/types/src/host/integration/tools/remote-lsp-tools.d.ts +0 -43
- package/lib/types/src/host/integration/tools/remote-tools.d.ts +0 -236
- package/lib/types/src/host/integration/tools/session-target.d.ts +0 -52
- package/lib/types/src/host/integration/tools/session-tools.d.ts +0 -46
- package/lib/types/src/host/integration/tools/strict-arguments.d.ts +0 -79
- package/lib/types/src/host/integration/tools/terminal-manifest.d.ts +0 -94
- package/lib/types/src/host/integration/transfer/remote-copy.d.ts +0 -66
- package/lib/types/src/host/integration/transfer/transfer-adapters.d.ts +0 -48
- package/lib/types/src/host/integration/transfer/transfer-tracker.d.ts +0 -106
- package/lib/types/src/host/integration/transfer-adapters.d.ts +0 -44
- package/lib/types/src/host/integration/transfer-service.d.ts +0 -164
- package/lib/types/src/host/integration/transfer-tracker.d.ts +0 -106
- package/lib/types/src/host/integration/user-roots.d.ts +0 -461
- package/lib/types/src/wiring/connections.d.ts +0 -189
- package/lib/types/src/wiring/fs.d.ts +0 -13
- package/lib/types/src/wiring/install-memo.d.ts +0 -32
- package/lib/types/src/wiring/legacy-dirs.d.ts +0 -62
- package/lib/types/src/wiring/package-paths.d.ts +0 -35
- package/lib/types/src/wiring/roots.d.ts +0 -21
- package/lib/types/src/wiring/state-dir.d.ts +0 -29
- package/lib/types/src/wiring/tools.d.ts +0 -35
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* roots-api-support
|
|
3
|
-
*
|
|
4
|
-
* 请求/响应工具、公共投影与 body 读取——被分发器与三个 handler 家族共用。
|
|
5
|
-
*
|
|
6
|
-
* 从 `roots-api.ts` 的 `serveAction`(543 行 / 15 个 case)拆出(审计 0076):
|
|
7
|
-
* case 体逐字搬移,只把 `return;` 改成 `return true;`,未命中时返回 `false` 由分发器报 400。
|
|
8
|
-
*
|
|
9
|
-
* @module dsh-remote-workspace/app/roots-api-support
|
|
10
|
-
*/
|
|
11
|
-
import { type ConnectionPatch, type UserRootEntry, type UserRootsState } from './user-roots.ts';
|
|
12
|
-
import type { RootsApiRequest, RootsApiResponse, RootsApiDeps } from './roots-api-contract.ts';
|
|
13
|
-
export declare function readBody(req: RootsApiRequest): Promise<string>;
|
|
14
|
-
export declare function toBytes(chunk: unknown): Uint8Array;
|
|
15
|
-
/**
|
|
16
|
-
* Whitelist one live root, dropping everything else it carries (argv, anchor paths, transports).
|
|
17
|
-
*
|
|
18
|
-
* Both spellings the Lead may hand over are accepted: a bare `RootRef` and a `RootRecord`
|
|
19
|
-
* (`{ key, root, backend }` — what `RootRegistry.records` returns). Reading the nested `root` here is what
|
|
20
|
-
* keeps a wiring mistake from showing every root as `location: "unknown", path: ""`.
|
|
21
|
-
*/
|
|
22
|
-
export declare function publicRoot(raw: unknown): PublicRoot;
|
|
23
|
-
/**
|
|
24
|
-
* The live registry's own key for one persisted entry, or `undefined` when it is not live.
|
|
25
|
-
*
|
|
26
|
-
* The comparison goes through `sameUserRootKey` rather than `===`: the registry lower-cases Windows local
|
|
27
|
-
* paths (`domain/root.ts`'s `rootKey`), the persisted file keeps the caller's case, and the client rebuilds
|
|
28
|
-
* the key from the `path` the answer carried. Comparing them verbatim made a Windows local root impossible to
|
|
29
|
-
* remove - the file entry went, the live root stayed, and the row then had no delete button because it was no
|
|
30
|
-
* longer in the file.
|
|
31
|
-
*
|
|
32
|
-
* @param deps - the injected seams (only `listRoots` is read).
|
|
33
|
-
* @param entry - the entry to look for.
|
|
34
|
-
* @returns the key the registry holds it under, or `undefined`.
|
|
35
|
-
*/
|
|
36
|
-
export declare function matchedLiveKey(deps: RootsApiDeps, entry: UserRootEntry): Promise<string | undefined>;
|
|
37
|
-
/**
|
|
38
|
-
* Read one live record as a root key, matching it against `entry`.
|
|
39
|
-
*
|
|
40
|
-
* @param raw - a `RootRecord` (key + root) or a bare `RootRef`.
|
|
41
|
-
* @param entry - the entry to match.
|
|
42
|
-
* @returns the record's own key when it names `entry`, else `undefined`.
|
|
43
|
-
*/
|
|
44
|
-
export declare function liveKeyOfRecord(raw: unknown, entry: UserRootEntry): string | undefined;
|
|
45
|
-
/**
|
|
46
|
-
* Whitelist one live connection.
|
|
47
|
-
*
|
|
48
|
-
* This is the only place the host's connection profiles are turned into wire data, so it is the one place
|
|
49
|
-
* that must never copy a field it was not explicitly told to copy: `auth`, `keyPath`, `credentialKey`,
|
|
50
|
-
* `password`, `alias`, `proxyJump` and everything added later stay behind.
|
|
51
|
-
*/
|
|
52
|
-
export declare function publicConnection(raw: unknown): PublicConnection;
|
|
53
|
-
/** The machine-readable reason for one local listing failure, or `undefined` when it is not the caller's fault. */
|
|
54
|
-
export declare function localFailureReason(error: unknown): LocalFailureReason | undefined;
|
|
55
|
-
/** The human text for one {@link LocalFailureReason}; the path is always named so the message is actionable. */
|
|
56
|
-
export declare function localFailureMessage(reason: LocalFailureReason, path: string): string;
|
|
57
|
-
/**
|
|
58
|
-
* Narrow a whitelisted body down to the fields of a {@link ConnectionPatch} (never the id: see
|
|
59
|
-
* {@link UPDATE_CONNECTION_FIELDS}).
|
|
60
|
-
*
|
|
61
|
-
* **Absent means "keep what is there"** for every field, and this function is what makes that true rather than
|
|
62
|
-
* accidental: only keys the body actually carries are copied, so a body that names three fields cannot blank
|
|
63
|
-
* the four it did not mention.
|
|
64
|
-
*
|
|
65
|
-
* `port: ''`/`null` becomes `null`, which is the one value that means **drop the field** (back to the ssh
|
|
66
|
-
* default). Every other value is passed through untouched and judged by `normalizeConnectionEntry`; nothing is
|
|
67
|
-
* coerced here, because a bad port must be reported, not silently rounded.
|
|
68
|
-
*
|
|
69
|
-
* @param source - the whitelisted fields of the request body.
|
|
70
|
-
* @returns the patch.
|
|
71
|
-
*/
|
|
72
|
-
export declare function connectionPatchOf(source: Record<string, unknown>): Omit<ConnectionPatch, 'id'>;
|
|
73
|
-
/**
|
|
74
|
-
* The one body field this route refuses outright, whatever the action.
|
|
75
|
-
*
|
|
76
|
-
* `passphrase` has no representation anywhere in this feature, so accepting it would be a lie — and silently
|
|
77
|
-
* dropping it would tell the user their passphrase was stored.
|
|
78
|
-
*
|
|
79
|
-
* `password` is **not** refused any more: `add-connection` and `update-connection` take it, write it into the
|
|
80
|
-
* credential store and keep only the reference (FR-2.1.2). `credentialKey` is a *name*, not a secret, and
|
|
81
|
-
* travels normally.
|
|
82
|
-
*/
|
|
83
|
-
export declare function firstCredentialField(body: Record<string, unknown>, action: string): string | undefined;
|
|
84
|
-
/** One required non-empty string field of a body. */
|
|
85
|
-
export declare function requiredString(value: unknown, field: string): string;
|
|
86
|
-
export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
|
|
87
|
-
export declare function isValidationFailure(error: unknown): boolean;
|
|
88
|
-
export declare function messageOf(error: unknown): string;
|
|
89
|
-
/** The machine-readable reason a refusal carries in its details, when it has one. */
|
|
90
|
-
export declare function reasonOf(error: unknown): string | undefined;
|
|
91
|
-
export declare function send(req: RootsApiRequest, res: RootsApiResponse, status: number, value: unknown): void;
|
|
92
|
-
/**
|
|
93
|
-
* The wire shape of one tracked transfer.
|
|
94
|
-
*
|
|
95
|
-
* Whitelisted field by field, like every other projection on this route: the tracker's own object is a
|
|
96
|
-
* host-side value, and a field added there must be a deliberate decision to publish, not a leak.
|
|
97
|
-
*
|
|
98
|
-
* @param value - one entry from the tracker.
|
|
99
|
-
* @returns the row the client may see.
|
|
100
|
-
*/
|
|
101
|
-
export declare function publicTransfer(value: unknown): Record<string, unknown>;
|
|
102
|
-
/**
|
|
103
|
-
* Turn an alias into a connection id that passes {@link isValidConnectionId}.
|
|
104
|
-
*
|
|
105
|
-
* `~/.ssh/config` aliases routinely contain characters this plugin's ids reject (`@`, `:`, `/`, spaces) —
|
|
106
|
-
* `deploy@bastion` is a perfectly normal alias. Importing one verbatim would be refused by
|
|
107
|
-
* {@link normalizeConnectionEntry} with a message about id grammar, which reads as "the import is broken".
|
|
108
|
-
* The alias is therefore **kept as the ssh target** (`alias`), and only the *id* is sanitised.
|
|
109
|
-
*
|
|
110
|
-
* @param alias - the literal alias from the config.
|
|
111
|
-
* @returns a valid id, or `undefined` when sanitising leaves nothing usable.
|
|
112
|
-
*/
|
|
113
|
-
export declare function connectionIdFromAlias(alias: string): string | undefined;
|
|
114
|
-
/** The persisted state as the panel may see it: same connection projection, so `keyPath` never travels. */
|
|
115
|
-
export declare function publicUserState(state: UserRootsState): {
|
|
116
|
-
readonly version: number;
|
|
117
|
-
readonly roots: readonly UserRootEntry[];
|
|
118
|
-
readonly connections: readonly PublicConnection[];
|
|
119
|
-
};
|
|
120
|
-
/**
|
|
121
|
-
* The optional `path` field of a `list-local` body.
|
|
122
|
-
*
|
|
123
|
-
* Absent and empty (or blank) both mean "the host default", which is the user's home directory. Anything else
|
|
124
|
-
* that is not a string — `null` included — is the caller's fault and is refused before a directory is chosen:
|
|
125
|
-
* silently browsing the home directory because a client sent `null` would look like the request succeeded.
|
|
126
|
-
*/
|
|
127
|
-
export declare function optionalPath(value: unknown): string | undefined;
|
|
128
|
-
/** One root as the panel may see it: no credential can appear in a root, but the shape is still fixed. */
|
|
129
|
-
export interface PublicRoot {
|
|
130
|
-
readonly key?: string;
|
|
131
|
-
readonly location: string;
|
|
132
|
-
readonly connectionId?: string;
|
|
133
|
-
readonly path: string;
|
|
134
|
-
readonly label?: string;
|
|
135
|
-
readonly writable?: boolean;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* One connection as the panel may see it. **Deliberately without `keyPath`.**
|
|
139
|
-
*
|
|
140
|
-
* `transport` **is** projected, and it has to be: the edit form is filled from this answer and submits what it
|
|
141
|
-
* was filled with, so omitting the field silently rewrote every `alias`/`ssh2` connection to the default
|
|
142
|
-
* (`agent`) on the next save - even when the operator only changed the host.
|
|
143
|
-
*/
|
|
144
|
-
export interface PublicConnection {
|
|
145
|
-
readonly id: string;
|
|
146
|
-
readonly host: string;
|
|
147
|
-
readonly user: string;
|
|
148
|
-
readonly port?: number;
|
|
149
|
-
readonly authKind: string;
|
|
150
|
-
/** The transport this connection asks for; absent only for a record that names none. */
|
|
151
|
-
readonly transport?: string;
|
|
152
|
-
}
|
|
153
|
-
/** The reasons a local listing of a syntactically valid path can be refused with. */
|
|
154
|
-
type LocalFailureReason = 'not-found' | 'not-a-directory' | 'unreadable';
|
|
155
|
-
/**
|
|
156
|
-
* The absolute chain from the filesystem root down to `absolute`, inclusive.
|
|
157
|
-
*
|
|
158
|
-
* The client renders "up" and "home" from this instead of composing a parent path itself: drive letters, UNC
|
|
159
|
-
* shares and `/` are exactly the dialects a web client gets wrong, and one wrong guess sends `list-local` to a
|
|
160
|
-
* directory the user never asked for. Every element is an ancestor of the path the answer already carries, so
|
|
161
|
-
* the field discloses nothing the `path` field did not.
|
|
162
|
-
*
|
|
163
|
-
* @param absolute - an absolute, resolved path (what the handler answers with).
|
|
164
|
-
* @returns the chain, root first; empty when the platform reports no root (impossible for a resolved path).
|
|
165
|
-
*/
|
|
166
|
-
export declare function localPathCrumbs(absolute: string): readonly string[];
|
|
167
|
-
/** The persisted state, read fresh for every check (the file is the source of truth, not a cache). */
|
|
168
|
-
export declare function currentUserState(deps: RootsApiDeps): Promise<UserRootsState>;
|
|
169
|
-
/**
|
|
170
|
-
* Converge the persisted state on a target shape and return it.
|
|
171
|
-
*
|
|
172
|
-
* The handler never assumes who persisted what: it consults the file **after** the live seam ran, computes
|
|
173
|
-
* the state the request implies, and writes only when that differs. So a wiring whose `registerRoot` already
|
|
174
|
-
* persists produces no second write, and a wiring that only touches the live registry still ends with a file
|
|
175
|
-
* that matches reality.
|
|
176
|
-
*/
|
|
177
|
-
export declare function reconcile(deps: RootsApiDeps, transition: (state: UserRootsState) => UserRootsState): Promise<UserRootsState>;
|
|
178
|
-
/** Take only the named fields from a body; the body itself is never handed to a seam. */
|
|
179
|
-
export declare function pick(source: Record<string, unknown>, fields: readonly string[]): Record<string, unknown>;
|
|
180
|
-
export declare function requiredKey(value: unknown): string;
|
|
181
|
-
export {};
|
|
182
|
-
//# sourceMappingURL=roots-api-support.d.ts.map
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* roots-api-transfers
|
|
3
|
-
*
|
|
4
|
-
* 传输面板的 2 个 action:列表与清空。
|
|
5
|
-
*
|
|
6
|
-
* 从 `roots-api.ts` 的 `serveAction`(543 行 / 15 个 case)拆出(审计 0076):
|
|
7
|
-
* case 体逐字搬移,只把 `return;` 改成 `return true;`,未命中时返回 `false` 由分发器报 400。
|
|
8
|
-
*
|
|
9
|
-
* @module dsh-remote-workspace/app/roots-api-transfers
|
|
10
|
-
*/
|
|
11
|
-
import type { RootsApiRequest, RootsApiResponse, RootsApiDeps } from './roots-api-contract.ts';
|
|
12
|
-
export declare function handleTransferActions(action: string, body: Record<string, unknown>, req: RootsApiRequest, res: RootsApiResponse, deps: RootsApiDeps): Promise<boolean>;
|
|
13
|
-
//# sourceMappingURL=roots-api-transfers.d.ts.map
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The same-origin HTTP route a client panel uses to **edit** roots and connections.
|
|
3
|
-
*
|
|
4
|
-
* Why a plain HTTP route instead of a Typert `@Remote` service (the shape audit 0021 used for reads):
|
|
5
|
-
*
|
|
6
|
-
* - every action here carries **parameters**, and a Client Remote descriptor with parameters requires a
|
|
7
|
-
* generated strict codec that this repository cannot produce (`doc/02-platform/client-plugin.md` §4);
|
|
8
|
-
* - the panel is served from the GUI's own origin, so a relative `fetch` is same-origin: no CORS
|
|
9
|
-
* concession, no code generation, no `@Remote` registration — exactly the shape the third-party
|
|
10
|
-
* `dsh-plugin-stock-market` uses (`ctx.webServer.register({ kind: 'exact', path, handler })`).
|
|
11
|
-
*
|
|
12
|
-
* This module is a **handler factory decoupled from cordis**: everything it needs arrives through
|
|
13
|
-
* {@link RootsApiDeps}, so it can be unit-tested with fake dependencies and fake request/response objects.
|
|
14
|
-
* The Lead performs the actual registration:
|
|
15
|
-
*
|
|
16
|
-
* ```ts
|
|
17
|
-
* const api = createRootsApi({ ... })
|
|
18
|
-
* disposers.push(webServer.register({ kind: 'exact', path: ROOTS_API_PATH, handler: api.handle }))
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* Contract:
|
|
22
|
-
*
|
|
23
|
-
* | Request | Answer |
|
|
24
|
-
* |---|---|
|
|
25
|
-
* | `GET` | `200 { ok: true, roots, connections, userRoots, warnings }` |
|
|
26
|
-
* | `POST` `{ action: 'add-root' \| 'remove-root' \| 'add-connection' \| 'update-connection' \| 'remove-connection', ... }` | `200 { ok: true, action, state }` |
|
|
27
|
-
* | `POST` `{ action: 'add-root', location, path, connectionId?, workspaces?, reuseExisting? }` | `200 { ok: true, action, state, anchorPath? }` — `reuseExisting: true` makes an already-persisted root idempotent and answers its anchor instead of `400 该根已存在` |
|
|
28
|
-
* | `POST` `{ action: 'remove-root', key, workspace? }` | `200 { ok: true, action, state }` — `workspace` removes the root from that workspace only; the root disappears when the last one drops it |
|
|
29
|
-
* | `POST` `{ action: 'update-connection', id, newId?, host?, user?, port?, authKind?, keyPath?, credentialKey?, transport?, password? }` | `200 { ok: true, action, state }` — absent fields keep their value; `newId` renames and migrates the connection's roots (keeping their anchors) |
|
|
30
|
-
* | `POST` `{ action: 'list-remote', connectionId, path }` | `200 { ok: true, action, connectionId, path, entries: [{ name, kind }], truncated }` |
|
|
31
|
-
* | `POST` `{ action: 'list-local', path? }` | `200 { ok: true, action, path, entries: [{ name, kind }], crumbs, truncated }` |
|
|
32
|
-
* | `POST` `{ action: 'list-ssh-config' }` | `200 { ok: true, action, candidates: [{ alias, host, user?, port?, hasIdentityFile, hasProxyJump, suggestedId }], skipped: [{ pattern, reason, line }] }` (FR-2.1.4) |
|
|
33
|
-
* | `POST` `{ action: 'import-ssh-config', aliases: [alias, …] }` | `200 { ok: true, action, imported: [id, …], refused: [{ alias, reason }], state }` — the body names **aliases**, never ids/hosts/paths: every field is re-derived from the config |
|
|
34
|
-
* | any validation / trust / body failure | `400`/`403` `{ ok: false, error, reason? }` |
|
|
35
|
-
* | any other method | `405` `{ ok: false, error }` + `Allow: GET, HEAD, POST` |
|
|
36
|
-
*
|
|
37
|
-
* Two invariants this layer owns:
|
|
38
|
-
*
|
|
39
|
-
* 1. **Credentials never come back out.** `connections` (live and persisted), the `state` echoed by
|
|
40
|
-
* `POST` and every directory row (`list-remote` and `list-local`) are whitelist projections:
|
|
41
|
-
* `{ id, host, user, port, authKind, transport? }` and `{ name, kind }` respectively. `keyPath`, `password`,
|
|
42
|
-
* `passphrase`, `credentialKey`, `alias`, `proxyJump`, sizes, times, modes and symlink targets are
|
|
43
|
-
* never serialised, and no file content is readable through this route at all.
|
|
44
|
-
* 2. **Parameters are taken from a whitelist, one field at a time** — the body is never spread into a
|
|
45
|
-
* call. A field the UI does not own cannot reach the seam, however the body is shaped.
|
|
46
|
-
*
|
|
47
|
-
* @module dsh-remote-workspace/integration/roots-api
|
|
48
|
-
*/
|
|
49
|
-
import type { RootsApiDeps, RootsApi } from './roots-api-contract.ts';
|
|
50
|
-
export * from './roots-api-contract.ts';
|
|
51
|
-
export { localPathCrumbs } from './roots-api-projections.ts';
|
|
52
|
-
export { connectionIdFromAlias } from './roots-api-http.ts';
|
|
53
|
-
export type { PublicRoot, PublicConnection } from './roots-api-projections.ts';
|
|
54
|
-
export declare function createRootsApi(deps: RootsApiDeps): RootsApi;
|
|
55
|
-
//# sourceMappingURL=roots-api.d.ts.map
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The routed file system: one workspace, many roots, local and remote side by side.
|
|
3
|
-
*
|
|
4
|
-
* Responsibilities, in order:
|
|
5
|
-
*
|
|
6
|
-
* 1. **Resolve** a model-facing path to exactly one root plus a backend-absolute path
|
|
7
|
-
* (all rules live in `domain/route-table.ts`; this module only applies the result).
|
|
8
|
-
* One addition lives here rather than in the table: the **implicit session root**, so the session's own
|
|
9
|
-
* working directory is always usable even when no registered root covers it (see {@link
|
|
10
|
-
* RoutedFileSystem.tryResolve}).
|
|
11
|
-
* 2. **Namespace** target keys as `{backendId}\0{absolute path}` — the same file spelled locally
|
|
12
|
-
* and remotely must never collide, because core components key their state by target key.
|
|
13
|
-
* 3. **Fence writes**: resolution already rejects paths outside every root, so `workspace-write`
|
|
14
|
-
* means "inside the roots"; `read-only` denies every write; `danger-full-access` allows.
|
|
15
|
-
* This is the plugin's own multi-root confinement (the core's single-root fence cannot express
|
|
16
|
-
* several roots, see `doc/02-platform/fs-seam.md` §4).
|
|
17
|
-
* 4. Keep the operations the model's tools need: stat / list / read / write / edit.
|
|
18
|
-
*
|
|
19
|
-
* @module dsh-over-ssh/app/routed-fs
|
|
20
|
-
*/
|
|
21
|
-
import type { Backend, BackendEntry, BackendRead, BackendSandboxMode, BackendStat, BackendText } from './backend.ts';
|
|
22
|
-
import { SshDevError } from '../domain/errors.ts';
|
|
23
|
-
import { type RootRef } from '../domain/roots/root.ts';
|
|
24
|
-
import { type RouteOptions } from '../domain/roots/route-table.ts';
|
|
25
|
-
/** A resolved path: one root, one backend, one backend-absolute location. */
|
|
26
|
-
export interface RoutedTarget {
|
|
27
|
-
readonly root: RootRef;
|
|
28
|
-
readonly backend: Backend;
|
|
29
|
-
/** Key of the root, also the router's backend key. */
|
|
30
|
-
readonly backendKey: string;
|
|
31
|
-
/** Absolute path in the backend's own spelling. */
|
|
32
|
-
readonly absolute: string;
|
|
33
|
-
/** Namespaced identity: `{backendId}\0{absolute}`. */
|
|
34
|
-
readonly targetKey: string;
|
|
35
|
-
readonly relativePath: string;
|
|
36
|
-
/** Model-facing spelling (`ssh://…` for remote roots). */
|
|
37
|
-
readonly displayPath: string;
|
|
38
|
-
}
|
|
39
|
-
/** Resolution outcome with a resolved target, or the reason it failed. */
|
|
40
|
-
export type RoutedResolution = {
|
|
41
|
-
readonly ok: true;
|
|
42
|
-
readonly target: RoutedTarget;
|
|
43
|
-
} | {
|
|
44
|
-
readonly ok: false;
|
|
45
|
-
readonly error: SshDevError;
|
|
46
|
-
};
|
|
47
|
-
/** A directory entry with its resolved identity. */
|
|
48
|
-
export interface RoutedEntry extends BackendEntry {
|
|
49
|
-
readonly targetKey: string;
|
|
50
|
-
readonly displayPath: string;
|
|
51
|
-
}
|
|
52
|
-
/** Options for {@link RoutedFileSystem}. */
|
|
53
|
-
export interface RoutedFileSystemOptions {
|
|
54
|
-
readonly roots: readonly RootRef[];
|
|
55
|
-
/** Backends keyed by `rootKey(root)`. */
|
|
56
|
-
readonly backends: ReadonlyMap<string, Backend>;
|
|
57
|
-
readonly caseInsensitive?: boolean;
|
|
58
|
-
/** Cap for a single read; defaults to 8 MiB. */
|
|
59
|
-
readonly maxReadBytes?: number;
|
|
60
|
-
/**
|
|
61
|
-
* Builds the backend for the **implicit session root** — the session's own cwd (see {@link
|
|
62
|
-
* RoutedFileSystem.tryResolve}).
|
|
63
|
-
*
|
|
64
|
-
* Injected rather than imported because building a local backend needs `node:fs`, and this layer must not
|
|
65
|
-
* reach a concrete adapter (架构测试: `app` only depends on `infra` port modules). Omitting it **disables**
|
|
66
|
-
* the implicit root, which is the honest default: a router that was given no way to serve host paths keeps
|
|
67
|
-
* reporting `ROOT_OUTSIDE` for them.
|
|
68
|
-
*/
|
|
69
|
-
readonly createLocalBackend?: (root: RootRef) => Backend;
|
|
70
|
-
}
|
|
71
|
-
/** Write options. */
|
|
72
|
-
export interface RoutedWriteOptions {
|
|
73
|
-
readonly cwd?: string;
|
|
74
|
-
/** Version token that must match before the write proceeds. */
|
|
75
|
-
readonly expectedVersion?: string;
|
|
76
|
-
/** Policy the caller is operating under. */
|
|
77
|
-
readonly sandbox?: BackendSandboxMode;
|
|
78
|
-
readonly signal?: AbortSignal;
|
|
79
|
-
}
|
|
80
|
-
/** Literal edit request, mirroring the core's `editText` semantics. */
|
|
81
|
-
export interface RoutedEdit {
|
|
82
|
-
readonly find: string;
|
|
83
|
-
readonly replace: string;
|
|
84
|
-
/** Replace every occurrence instead of requiring a unique one. */
|
|
85
|
-
readonly all?: boolean;
|
|
86
|
-
}
|
|
87
|
-
/** Multi-root file system over a set of backends. */
|
|
88
|
-
export declare class RoutedFileSystem {
|
|
89
|
-
#private;
|
|
90
|
-
constructor(options: RoutedFileSystemOptions);
|
|
91
|
-
/** Registered roots, in registration order. */
|
|
92
|
-
get roots(): readonly RootRef[];
|
|
93
|
-
/** Confinement the router enforces itself. */
|
|
94
|
-
get sandboxMode(): BackendSandboxMode;
|
|
95
|
-
/** Register a root together with the backend that serves it. */
|
|
96
|
-
addRoot(root: RootRef, backend: Backend): void;
|
|
97
|
-
/** Remove a root and its backend binding. */
|
|
98
|
-
removeRoot(key: string): boolean;
|
|
99
|
-
/** Replace every root and backend binding at once. */
|
|
100
|
-
setRoots(entries: readonly {
|
|
101
|
-
readonly root: RootRef;
|
|
102
|
-
readonly backend: Backend;
|
|
103
|
-
}[]): void;
|
|
104
|
-
/**
|
|
105
|
-
* Resolve a path.
|
|
106
|
-
*
|
|
107
|
-
* @param input - model-facing path (host path, `ssh://…`, or relative to `cwd`).
|
|
108
|
-
* @param options - session cwd and case folding.
|
|
109
|
-
* @returns the resolved target.
|
|
110
|
-
* @throws SshDevError `ROOT_OUTSIDE` / `ROOT_AMBIGUOUS` / `ROOT_INVALID`.
|
|
111
|
-
*/
|
|
112
|
-
resolve(input: string, options?: RouteOptions): RoutedTarget;
|
|
113
|
-
/**
|
|
114
|
-
* Non-throwing resolution for UI code.
|
|
115
|
-
*
|
|
116
|
-
* A registered root is always asked first, so it wins over the implicit session root — the implicit root only
|
|
117
|
-
* answers paths the table refused.
|
|
118
|
-
*/
|
|
119
|
-
tryResolve(input: string, options?: RouteOptions): RoutedResolution;
|
|
120
|
-
/** Metadata for a path. */
|
|
121
|
-
stat(input: string, options?: RouteOptions & {
|
|
122
|
-
readonly signal?: AbortSignal;
|
|
123
|
-
}): Promise<BackendStat & {
|
|
124
|
-
readonly target: RoutedTarget;
|
|
125
|
-
}>;
|
|
126
|
-
/** Direct children of a directory, with resolved identities. */
|
|
127
|
-
list(input: string, options?: RouteOptions & {
|
|
128
|
-
readonly signal?: AbortSignal;
|
|
129
|
-
}): Promise<readonly RoutedEntry[]>;
|
|
130
|
-
/**
|
|
131
|
-
* List an already-resolved directory.
|
|
132
|
-
*
|
|
133
|
-
* Takes the target so callers that hold one (the core `FsTarget` contract hands one to every
|
|
134
|
-
* operation) do not pay for a second resolution.
|
|
135
|
-
*
|
|
136
|
-
* @param target - resolved directory.
|
|
137
|
-
* @param signal - cancellation.
|
|
138
|
-
* @returns direct children with resolved identities.
|
|
139
|
-
*/
|
|
140
|
-
listTarget(target: RoutedTarget, signal?: AbortSignal): Promise<readonly RoutedEntry[]>;
|
|
141
|
-
/**
|
|
142
|
-
* Stat an already-resolved target.
|
|
143
|
-
*
|
|
144
|
-
* @param target - resolved target.
|
|
145
|
-
* @param options - when `followSymlink` is false and the backend supports it, the link itself is
|
|
146
|
-
* inspected instead of its target.
|
|
147
|
-
* @returns metadata (never content).
|
|
148
|
-
*/
|
|
149
|
-
statTarget(target: RoutedTarget, options?: {
|
|
150
|
-
readonly followSymlink?: boolean;
|
|
151
|
-
readonly signal?: AbortSignal;
|
|
152
|
-
}): Promise<BackendStat>;
|
|
153
|
-
/**
|
|
154
|
-
* Resolve an opaque target key back to the root, backend and backend-absolute path that own it.
|
|
155
|
-
*
|
|
156
|
-
* Every operation after {@link resolve} arrives this way (the core hands back only the target key), so an
|
|
157
|
-
* implicit session root must be found here too: it is not in the table, but its backend id is what its target
|
|
158
|
-
* keys carry.
|
|
159
|
-
*/
|
|
160
|
-
targetFromKey(targetKey: string): RoutedTarget;
|
|
161
|
-
/** Whether a path exists. */
|
|
162
|
-
exists(input: string, options?: RouteOptions & {
|
|
163
|
-
readonly signal?: AbortSignal;
|
|
164
|
-
}): Promise<boolean>;
|
|
165
|
-
/** Read bytes, capped by the router's limit. */
|
|
166
|
-
readBytes(input: string, options?: RouteOptions & {
|
|
167
|
-
readonly maxBytes?: number;
|
|
168
|
-
readonly signal?: AbortSignal;
|
|
169
|
-
}): Promise<BackendRead & {
|
|
170
|
-
readonly target: RoutedTarget;
|
|
171
|
-
}>;
|
|
172
|
-
/** Read text. */
|
|
173
|
-
readText(input: string, options?: RouteOptions & {
|
|
174
|
-
readonly maxBytes?: number;
|
|
175
|
-
readonly signal?: AbortSignal;
|
|
176
|
-
}): Promise<BackendText & {
|
|
177
|
-
readonly target: RoutedTarget;
|
|
178
|
-
}>;
|
|
179
|
-
/**
|
|
180
|
-
* Write text after enforcing the router's own confinement.
|
|
181
|
-
*
|
|
182
|
-
* @param input - destination path.
|
|
183
|
-
* @param text - content to write.
|
|
184
|
-
* @param options - policy, version guard and cancellation.
|
|
185
|
-
* @returns the write outcome plus the resolved target.
|
|
186
|
-
*/
|
|
187
|
-
writeText(input: string, text: string, options?: RoutedWriteOptions): Promise<{
|
|
188
|
-
readonly bytes: number;
|
|
189
|
-
readonly version: string;
|
|
190
|
-
readonly target: RoutedTarget;
|
|
191
|
-
}>;
|
|
192
|
-
/**
|
|
193
|
-
* Apply a unified diff to one file, atomically.
|
|
194
|
-
*
|
|
195
|
-
* Forwarded rather than reimplemented: the backend owns the hunk matching, and a second implementation
|
|
196
|
-
* here would be a second set of edge cases to keep in sync.
|
|
197
|
-
*/
|
|
198
|
-
patchText(input: string, diff: string, options?: RoutedWriteOptions): Promise<{
|
|
199
|
-
readonly bytes: number;
|
|
200
|
-
readonly version: string;
|
|
201
|
-
readonly hunks: number;
|
|
202
|
-
readonly target: RoutedTarget;
|
|
203
|
-
}>;
|
|
204
|
-
/**
|
|
205
|
-
* Replace a literal string inside a file.
|
|
206
|
-
*
|
|
207
|
-
* Mirrors the core's semantics: an absent pattern and an ambiguous match without `all` are both
|
|
208
|
-
* errors, and a version guard can refuse the whole edit.
|
|
209
|
-
*
|
|
210
|
-
* @param input - file to edit.
|
|
211
|
-
* @param edit - find/replace plus the `all` flag.
|
|
212
|
-
* @param options - policy, version guard, cwd and cancellation.
|
|
213
|
-
* @returns the new version and the number of replacements.
|
|
214
|
-
*/
|
|
215
|
-
editText(input: string, edit: RoutedEdit, options?: RoutedWriteOptions): Promise<{
|
|
216
|
-
readonly replacements: number;
|
|
217
|
-
readonly version: string;
|
|
218
|
-
readonly target: RoutedTarget;
|
|
219
|
-
}>;
|
|
220
|
-
/**
|
|
221
|
-
* Whether one target is inside another.
|
|
222
|
-
*
|
|
223
|
-
* Both targets must belong to the same backend; across backends the answer is always `false`
|
|
224
|
-
* (a local path can never contain a remote path).
|
|
225
|
-
*/
|
|
226
|
-
contains(parent: RoutedTarget, child: RoutedTarget): boolean;
|
|
227
|
-
/** Host path for a child process in the target's world, when that world has one. */
|
|
228
|
-
processPath(target: RoutedTarget): string | undefined;
|
|
229
|
-
/** `file:` URL in the target's world. */
|
|
230
|
-
fileUrl(target: RoutedTarget): string | undefined;
|
|
231
|
-
}
|
|
232
|
-
/** Namespaced identity of one file; the backend id prevents local/remote collisions. */
|
|
233
|
-
export declare function makeTargetKey(backend: Backend, absolute: string): string;
|
|
234
|
-
/** Split a target key back into its parts (diagnostics and tests only). */
|
|
235
|
-
export declare function splitTargetKey(targetKey: string): {
|
|
236
|
-
readonly backendId: string;
|
|
237
|
-
readonly absolute: string;
|
|
238
|
-
} | undefined;
|
|
239
|
-
//# sourceMappingURL=routed-fs.d.ts.map
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Run asynchronous file work one operation at a time, in call order.
|
|
3
|
-
*
|
|
4
|
-
* Two places needed this and each carried its own copy of the same six lines: the panel-owned root/connection
|
|
5
|
-
* file (`app/roots/user-roots.ts`) and the session trash index (`app/session-admin/session-admin-context.ts`).
|
|
6
|
-
* Both are read-modify-write over one document, and in both the read is asynchronous, so two overlapping
|
|
7
|
-
* requests would read the same state and the second write would silently discard the first one's change — a
|
|
8
|
-
* lost update with no error anywhere. The idiom is small enough to look harmless and subtle enough to get
|
|
9
|
-
* wrong, which is exactly the case for one implementation (audit 2026-10-31 P3).
|
|
10
|
-
*
|
|
11
|
-
* The queue is **within one process** only. Two DSH processes writing the same file are still last-writer-wins;
|
|
12
|
-
* that needs a cross-process lock and is out of scope here.
|
|
13
|
-
*
|
|
14
|
-
* @module dsh-over-ssh/app/serialize
|
|
15
|
-
*/
|
|
16
|
-
/** A serial queue: `run` one task at a time, and `settled` to wait for what is already queued. */
|
|
17
|
-
export interface SerialQueue {
|
|
18
|
-
/**
|
|
19
|
-
* Queue `task`; it starts after every earlier task has settled.
|
|
20
|
-
*
|
|
21
|
-
* A rejection does **not** wedge the queue: the chain continues after it, so one failed write cannot stop
|
|
22
|
-
* every later one.
|
|
23
|
-
*
|
|
24
|
-
* @param task - the work to run alone.
|
|
25
|
-
* @returns the task's own result or rejection.
|
|
26
|
-
*/
|
|
27
|
-
run<T>(task: () => Promise<T>): Promise<T>;
|
|
28
|
-
/** Resolves once everything queued so far has settled — how a test waits without sleeping. */
|
|
29
|
-
settled(): Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Create one serial queue.
|
|
33
|
-
*
|
|
34
|
-
* @returns the queue (see {@link SerialQueue}).
|
|
35
|
-
*/
|
|
36
|
-
export declare function createSerialQueue(): SerialQueue;
|
|
37
|
-
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 会话管理的**上下文**:bin 根、索引读写、跨进程串行化、会话清单。
|
|
3
|
-
*
|
|
4
|
-
* 从 `session-admin-service.ts` 的工厂里抽出(审计 0076):所有方法族的公共底座。
|
|
5
|
-
*
|
|
6
|
-
* @module dsh-over-ssh/app/session-admin-context
|
|
7
|
-
*/
|
|
8
|
-
import { type SessionRecord, type SessionTrashEntry } from '../../domain/session/session-admin.ts';
|
|
9
|
-
import type { SessionAdminDeps, SessionAdminOptions } from './session-admin-contract.ts';
|
|
10
|
-
/** Whether a thrown error means "the path does not exist". */
|
|
11
|
-
export declare function isMissing(error: unknown): boolean;
|
|
12
|
-
export declare function createSessionAdminContext(deps: SessionAdminDeps): {
|
|
13
|
-
deps: SessionAdminDeps;
|
|
14
|
-
sessionsRoot: string;
|
|
15
|
-
binRoot: string;
|
|
16
|
-
indexePath: () => string;
|
|
17
|
-
serialized: <T>(operation: () => Promise<T>) => Promise<T>;
|
|
18
|
-
entryDir: (segment: string) => string;
|
|
19
|
-
readIndex: () => Promise<readonly SessionTrashEntry[]>;
|
|
20
|
-
writeIndex: (entries: readonly SessionTrashEntry[]) => Promise<void>;
|
|
21
|
-
inventory: (options?: SessionAdminOptions) => Promise<readonly SessionRecord[]>;
|
|
22
|
-
};
|
|
23
|
-
export type SessionAdminContext = ReturnType<typeof createSessionAdminContext>;
|
|
24
|
-
/**
|
|
25
|
-
* Fold a path to a comparison key: forward slashes, no trailing separator, lower case.
|
|
26
|
-
*
|
|
27
|
-
* The same fold the label resolver uses (`session-labels.ts`), duplicated here because this module must not
|
|
28
|
-
* import the resolver: the resolver reads platform services, this one is pure. Windows paths are
|
|
29
|
-
* case-insensitive and a header's `cwd` is the raw spawn directory while a workspace record's path is
|
|
30
|
-
* canonicalized, so an exact compare would miss real matches.
|
|
31
|
-
*
|
|
32
|
-
* @param path - a path in either spelling.
|
|
33
|
-
* @returns the comparison key.
|
|
34
|
-
*/
|
|
35
|
-
export declare function normalizePathKey(path: string): string;
|
|
36
|
-
//# sourceMappingURL=session-admin-context.d.ts.map
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 会话管理的**删除族**:预览、物理删除、移入回收站、批量清理、按工作区删除。
|
|
3
|
-
*
|
|
4
|
-
* 从 `session-admin-service.ts` 的工厂里抽出(审计 0076):只依赖上下文,不依赖列表/恢复/清扫。
|
|
5
|
-
*
|
|
6
|
-
* @module dsh-over-ssh/app/session-admin-delete
|
|
7
|
-
*/
|
|
8
|
-
import { type SessionTrashEntry, type SessionTrashEntryId } from '../../domain/session/session-admin.ts';
|
|
9
|
-
import { type SessionAdminContext } from './session-admin-context.ts';
|
|
10
|
-
import type { PurgeSessionResult, DeleteSessionResult } from './session-admin-contract.ts';
|
|
11
|
-
import type { DeleteDecision } from '../../domain/session/session-admin.ts';
|
|
12
|
-
export declare function createSessionAdminDelete(ctx: SessionAdminContext): {
|
|
13
|
-
previewDelete: (ids: readonly string[], options?: import("./session-admin-contract.ts").SessionAdminOptions & {
|
|
14
|
-
readonly keep?: readonly string[];
|
|
15
|
-
}) => Promise<DeleteDecision>;
|
|
16
|
-
deleteSession: (ids: readonly string[], options?: import("./session-admin-contract.ts").SessionAdminOptions & {
|
|
17
|
-
readonly mode?: "recycle" | "permanent";
|
|
18
|
-
readonly keep?: readonly string[];
|
|
19
|
-
}) => Promise<DeleteSessionResult>;
|
|
20
|
-
deleteWorkspaceSessions: (cwd: string, options?: import("./session-admin-contract.ts").SessionAdminOptions & {
|
|
21
|
-
readonly mode?: "recycle" | "permanent";
|
|
22
|
-
}) => Promise<DeleteSessionResult & {
|
|
23
|
-
readonly matched: number;
|
|
24
|
-
}>;
|
|
25
|
-
purgeEntry: (entryId: string) => Promise<PurgeSessionResult>;
|
|
26
|
-
purgeEntries: (doomed: readonly SessionTrashEntry[], known: readonly SessionTrashEntry[]) => Promise<{
|
|
27
|
-
readonly purged: readonly PurgeSessionResult[];
|
|
28
|
-
readonly failed: readonly {
|
|
29
|
-
readonly id: SessionTrashEntryId;
|
|
30
|
-
readonly reason: string;
|
|
31
|
-
}[];
|
|
32
|
-
}>;
|
|
33
|
-
};
|
|
34
|
-
//# sourceMappingURL=session-admin-delete.d.ts.map
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 会话管理的**上下文**:bin 根、索引读写、跨进程串行化、会话清单。
|
|
3
|
-
*
|
|
4
|
-
* 从 `session-admin-service.ts` 的工厂里抽出(审计 0076):所有方法族的公共底座。
|
|
5
|
-
*
|
|
6
|
-
* @module dsh-remote-workspace/app/session-admin-context
|
|
7
|
-
*/
|
|
8
|
-
import { type SessionRecord, type SessionTrashEntry } from '../domain/session-admin.ts';
|
|
9
|
-
import type { SessionAdminDeps, SessionAdminOptions } from './session-admin-contract.ts';
|
|
10
|
-
/** Whether a thrown error means "the path does not exist". */
|
|
11
|
-
export declare function isMissing(error: unknown): boolean;
|
|
12
|
-
export declare function createSessionAdminContext(deps: SessionAdminDeps): {
|
|
13
|
-
deps: SessionAdminDeps;
|
|
14
|
-
sessionsRoot: string;
|
|
15
|
-
binRoot: string;
|
|
16
|
-
indexePath: () => string;
|
|
17
|
-
serialized: <T>(operation: () => Promise<T>) => Promise<T>;
|
|
18
|
-
entryDir: (segment: string) => string;
|
|
19
|
-
readIndex: () => Promise<readonly SessionTrashEntry[]>;
|
|
20
|
-
writeIndex: (entries: readonly SessionTrashEntry[]) => Promise<void>;
|
|
21
|
-
inventory: (options?: SessionAdminOptions) => Promise<readonly SessionRecord[]>;
|
|
22
|
-
};
|
|
23
|
-
export type SessionAdminContext = ReturnType<typeof createSessionAdminContext>;
|
|
24
|
-
/**
|
|
25
|
-
* Fold a path to a comparison key: forward slashes, no trailing separator, lower case.
|
|
26
|
-
*
|
|
27
|
-
* The same fold the label resolver uses (`session-labels.ts`), duplicated here because this module must not
|
|
28
|
-
* import the resolver: the resolver reads platform services, this one is pure. Windows paths are
|
|
29
|
-
* case-insensitive and a header's `cwd` is the raw spawn directory while a workspace record's path is
|
|
30
|
-
* canonicalized, so an exact compare would miss real matches.
|
|
31
|
-
*
|
|
32
|
-
* @param path - a path in either spelling.
|
|
33
|
-
* @returns the comparison key.
|
|
34
|
-
*/
|
|
35
|
-
export declare function normalizePathKey(path: string): string;
|
|
36
|
-
//# sourceMappingURL=session-admin-context.d.ts.map
|