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
|
@@ -27,6 +27,7 @@ import type { HostKeyPolicy } from '../../../domain/roots/connection.ts';
|
|
|
27
27
|
import { SshDevError } from '../../../domain/errors.ts';
|
|
28
28
|
import { type ExecRequest, type ExecResult, type ReadFileRangeRequest, type ReadFileRequest, type RemoteFileChunk, type RemoteWriteOutcome, type RemoveRequest, type RenameRequest, type Transport, type WriteFileRangeRequest, type WriteFileRequest } from '../transport.ts';
|
|
29
29
|
import { TransportBase } from '../transport-base.ts';
|
|
30
|
+
import type { ForwardHandle, ForwardRequest } from '../forward.ts';
|
|
30
31
|
/** Authentication material for one hop. */
|
|
31
32
|
export interface Ssh2Auth {
|
|
32
33
|
readonly password?: string;
|
|
@@ -227,6 +228,10 @@ export declare class Ssh2Transport extends TransportBase implements Transport {
|
|
|
227
228
|
*/
|
|
228
229
|
connect(signal?: AbortSignal): Promise<void>;
|
|
229
230
|
/** Close the session. Idempotent. */
|
|
231
|
+
/** {@inheritDoc Transport.forward} */
|
|
232
|
+
forward(request: ForwardRequest, signal?: AbortSignal): Promise<ForwardHandle>;
|
|
233
|
+
/** {@inheritDoc Transport.closeForwards} */
|
|
234
|
+
closeForwards(): Promise<void>;
|
|
230
235
|
dispose(): Promise<void>;
|
|
231
236
|
/** Run one remote command over a channel of the shared session. */
|
|
232
237
|
exec(request: ExecRequest, signal?: AbortSignal): Promise<ExecResult>;
|
|
@@ -325,4 +330,3 @@ export declare function sftpError(operation: string, path: string, error?: Error
|
|
|
325
330
|
* session.
|
|
326
331
|
*/
|
|
327
332
|
export declare const defaultConnector: Ssh2Connector;
|
|
328
|
-
//# sourceMappingURL=ssh2-transport.d.ts.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module dsh-over-ssh/infra/transport/transport
|
|
9
9
|
*/
|
|
10
|
+
import type { ForwardHandle, ForwardRequest } from './forward.ts';
|
|
10
11
|
import type { RemoteCapabilities } from '../../domain/capability.ts';
|
|
11
12
|
/** Lifecycle of one transport instance. */
|
|
12
13
|
export type TransportState = 'idle' | 'connecting' | 'ready' | 'lost';
|
|
@@ -35,6 +36,15 @@ export interface ExecRequest {
|
|
|
35
36
|
* *encoded* payload into the file, i.e. silent corruption).
|
|
36
37
|
*/
|
|
37
38
|
readonly stdinBase64?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Landlock write fence: when non-empty, the command may only write under these roots.
|
|
41
|
+
*
|
|
42
|
+
* **Tier 2 only.** The agent builds the fence before `exec` and refuses with `REMOTE_UNSUPPORTED` when it
|
|
43
|
+
* cannot (no Landlock, missing root); a Tier 1 transport has no fence at all and must refuse the field
|
|
44
|
+
* rather than silently run unfenced — "the fence was requested but skipped" is a security lie, not a
|
|
45
|
+
* degradation. Surfaced through `limits.execWriteFence`.
|
|
46
|
+
*/
|
|
47
|
+
readonly writeRoots?: readonly string[];
|
|
38
48
|
}
|
|
39
49
|
/** One finished remote command. */
|
|
40
50
|
export interface ExecResult {
|
|
@@ -458,6 +468,22 @@ export interface Transport {
|
|
|
458
468
|
* hunk matching rules, which is where a patch applier goes wrong.
|
|
459
469
|
*/
|
|
460
470
|
patchFile?(request: PatchFileRequest, signal?: AbortSignal): Promise<PatchFileResult>;
|
|
471
|
+
/**
|
|
472
|
+
* 建立一条本地 → 远端的 TCP 转发(端口转发)。
|
|
473
|
+
*
|
|
474
|
+
* 可选:**系统 ssh 的两条路径(Tier 1 与默认 Tier 2)都实现了它**,`ssh2` 传输没有——那一条会诚实
|
|
475
|
+
* 地不声明这个方法,调用方据此报"该连接不支持端口转发",而不是给一个连不上的端口。
|
|
476
|
+
*
|
|
477
|
+
* 只绑 `127.0.0.1`:转发出来的端口是给本机浏览器/客户端用的,绑 `0.0.0.0` 等于把一个远端服务暴露给
|
|
478
|
+
* 整个局域网。要给别人用请走 SSH 自己的 `GatewayPorts` 配置,而不是让插件默认放宽。
|
|
479
|
+
*
|
|
480
|
+
* @param request - 远端目标与可选本地端口。
|
|
481
|
+
* @param signal - 取消建立过程(已建立的转发不会因此关闭)。
|
|
482
|
+
* @returns 句柄,`localPort` 一定是真实端口(自动选择时也回填)。
|
|
483
|
+
*/
|
|
484
|
+
forward?(request: ForwardRequest, signal?: AbortSignal): Promise<ForwardHandle>;
|
|
485
|
+
/** 关掉这条传输上的所有转发(dispose 时调用);幂等。 */
|
|
486
|
+
closeForwards?(): Promise<void>;
|
|
461
487
|
/** Native delete (`fs.remove`); absent on Tier 1, which uses its shell primitive instead. */
|
|
462
488
|
removePath?(request: RemovePathRequest, signal?: AbortSignal): Promise<void>;
|
|
463
489
|
/** Native rename/move (`fs.rename`); absent on Tier 1, which uses its shell primitive. */
|
|
@@ -522,6 +548,20 @@ export interface Transport {
|
|
|
522
548
|
}
|
|
523
549
|
/** Encode bytes as base64 without line wrapping. */
|
|
524
550
|
export declare function encodeBase64(bytes: Uint8Array): string;
|
|
525
|
-
/**
|
|
551
|
+
/**
|
|
552
|
+
* Decode base64, ignoring line breaks produced by remote tooling.
|
|
553
|
+
*
|
|
554
|
+
* **两次多余的整串处理被去掉了**(审计 0112 P3-2):
|
|
555
|
+
*
|
|
556
|
+
* 1. `text.replace(/\s+/g, '')` 先把整串扫一遍去掉空白。Node 的 base64 解码**本来就忽略空白**
|
|
557
|
+
* (`\n` / `\r\n` / 空格 / 制表符都已实测逐字节等价,见本函数下方的测试),所以这一遍纯属浪费:
|
|
558
|
+
* 9 MiB 负载(12.7 MB base64)实测 17.3 ms → 7.1 ms。
|
|
559
|
+
* 2. `new Uint8Array(...)` 把解码结果再拷一遍。4 KiB 以上的解码本来就不走 Buffer 的共享池,
|
|
560
|
+
* `Buffer.from(str, 'base64')` 的返回对象已经是独占、正好大小的 `Uint8Array`,直接交出去即可
|
|
561
|
+
* (9 MiB 的一次拷贝实测 1.4 ms,而它正是这条读路径上最大的一块)。
|
|
562
|
+
*
|
|
563
|
+
* **小结果仍然拷一次,这是有意的**:`Buffer.from(string)` 在 4 KiB 以下会落进 Node 的 64 KiB 共享池,
|
|
564
|
+
* 原样返回会让一个几十字节的缓存值长期钉住 64 KiB(读缓存按 `byteLength` 记账,看不见这块)。
|
|
565
|
+
* 那次拷贝是几十字节,与热路径无关。
|
|
566
|
+
*/
|
|
526
567
|
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;
|
|
@@ -285,7 +284,24 @@ export declare class RoutedFsProvider extends FileSystem {
|
|
|
285
284
|
*/
|
|
286
285
|
private syncSessionRoots;
|
|
287
286
|
private routedTarget;
|
|
288
|
-
/**
|
|
287
|
+
/**
|
|
288
|
+
* Enforce the per-call policy and the root's own writability.
|
|
289
|
+
*
|
|
290
|
+
* Three gates, in order:
|
|
291
|
+
* 1. `read-only` denies every mutation (the platform's own contract);
|
|
292
|
+
* 2. a root registered `writable: false` denies;
|
|
293
|
+
* 3. under **`workspace-write`**, the target must be inside the session's workspace — where "workspace"
|
|
294
|
+
* includes the directories **this session added** (product decision 2026-11-04: 「添加到会话的目录」=
|
|
295
|
+
* 该目录临时成为 workspace 的一部分). Before that decision the plugin admitted every writable root it
|
|
296
|
+
* could route, which made the mode wider than the platform's own `fs-sandbox` fence
|
|
297
|
+
* (`workspace-write` = "canonicalizes under `workspaceRoot` or the platform temp area").
|
|
298
|
+
*
|
|
299
|
+
* A call without a per-call policy keeps the historical behaviour (the mode comes from
|
|
300
|
+
* {@link sandboxMode}); the area rule needs `workspaceRoot`, which only the policy carries.
|
|
301
|
+
*
|
|
302
|
+
* @param routed - the resolved target.
|
|
303
|
+
* @param policy - the per-call sandbox policy the tool layer resolved.
|
|
304
|
+
*/
|
|
289
305
|
private assertWritable;
|
|
290
306
|
/**
|
|
291
307
|
* Previous text content, when it is readable text inside the cap; `undefined` otherwise.
|
|
@@ -365,4 +381,3 @@ export declare function createBackendRangeReader(store: (backend: Backend, offse
|
|
|
365
381
|
export declare function toFsError(error: SshDevError): FsError;
|
|
366
382
|
/** Codes this provider can surface, exported for tests that assert the mapping table. */
|
|
367
383
|
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
|
package/lib/types/src/index.d.ts
CHANGED
|
@@ -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
|
|
@@ -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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-over-ssh",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "SSH remote development for DeepSeek Harness: connections (key/password/ProxyJump/ssh config), remote files without sync, remote terminal, remote workspaces, remote @-completion, upload/download.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -56,12 +56,14 @@
|
|
|
56
56
|
"typecheck:client": "tsc -p tsconfig.client.json --pretty false",
|
|
57
57
|
"build:client": "node tools/build-client.mjs --check",
|
|
58
58
|
"build:host": "node tools/build-host.mjs",
|
|
59
|
-
"build": "npm run build:host && npm run build:
|
|
59
|
+
"build": "npm run build:host && npm run build:types && npm run build:terminal-wrapper && npm run build:client",
|
|
60
60
|
"agents": "node tools/agent-manifest.mjs generate --from ../dsh-over-ssh-agent/dist --out agents/agent-manifest.json --copy-to agents --platforms linux-amd64,linux-arm64 --require-provenance",
|
|
61
61
|
"build:types:client": "node ./node_modules/typescript/bin/tsc -p tsconfig.client.types.json --pretty false",
|
|
62
62
|
"prepack": "npm run build && node tools/prepack-agents.mjs && node tools/release-note.mjs --check",
|
|
63
63
|
"build:terminal-wrapper": "node tools/build-terminal-wrapper.mjs",
|
|
64
|
-
"release:note": "node tools/release-note.mjs"
|
|
64
|
+
"release:note": "node tools/release-note.mjs",
|
|
65
|
+
"build:types:host": "node ./node_modules/typescript/bin/tsc -p tsconfig.host.types.json",
|
|
66
|
+
"build:types": "node tools/clean-types.mjs && npm run build:types:host && npm run build:types:client && node tools/prune-types.mjs"
|
|
65
67
|
},
|
|
66
68
|
"peerDependencies": {
|
|
67
69
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The controls the three surfaces share, as plain `createElement` templates.
|
|
3
|
-
*
|
|
4
|
-
* **No hooks, on purpose.** `:hover`, `:active`, `:focus-visible` and `:disabled` come from the stylesheet in
|
|
5
|
-
* [`styles.ts`](./styles.ts) via class names, because a component holding `useState` cannot be rendered by
|
|
6
|
-
* this repository's tests: they call the section functions **directly**, outside any React render, where a
|
|
7
|
-
* hook throws `Invalid hook call`. Classes keep the templates pure element trees — a test walks the returned
|
|
8
|
-
* tree and reads the same `type` / `name` / `disabled` / `role` it always did — while the browser still gets
|
|
9
|
-
* real interaction states.
|
|
10
|
-
*
|
|
11
|
-
* These are deliberately **not** the platform's `dsh-client-ui-primitives` atoms: those factories import
|
|
12
|
-
* per-component CSS modules, which a third-party bundle cannot supply (the loader materialises only
|
|
13
|
-
* registered factories), and the package is not a dependency of this repository. `styles.ts` carries the
|
|
14
|
-
* tokens those atoms are built from.
|
|
15
|
-
*
|
|
16
|
-
* @module dsh-remote-workspace/client/controls
|
|
17
|
-
*/
|
|
18
|
-
import { type ChangeEvent, type ReactNode } from 'react';
|
|
19
|
-
/** The sizes a control may have. */
|
|
20
|
-
export type ControlSize = 'normal' | 'compact';
|
|
21
|
-
/** The visual weight of a button. */
|
|
22
|
-
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'row' | 'chip';
|
|
23
|
-
/** Props every control shares: extra classes from the caller. */
|
|
24
|
-
export interface ControlClassProps {
|
|
25
|
-
/** Extra classes from the caller; appended after the vocabulary's own. */
|
|
26
|
-
readonly className?: string;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* The part of a keyboard event a card's Esc handler reads.
|
|
30
|
-
*
|
|
31
|
-
* Structural, so the pure templates need no DOM types and a test drives the handler with a plain object. It is
|
|
32
|
-
* assignable from React's `KeyboardEvent` (which carries both members), and it is the whole reason a dialog
|
|
33
|
-
* closes on Esc: the shell focuses into the card when it opens, so the event reaches the card's own handler.
|
|
34
|
-
*/
|
|
35
|
-
export interface KeyEventLike {
|
|
36
|
-
/** The key name, e.g. `'Escape'`. */
|
|
37
|
-
readonly key?: string;
|
|
38
|
-
/** Stop the platform's own Esc handling from also firing while the dialog is up. */
|
|
39
|
-
stopPropagation?(): void;
|
|
40
|
-
}
|
|
41
|
-
/** True when the event is the Esc key. */
|
|
42
|
-
export declare function isEscape(event: KeyEventLike): boolean;
|
|
43
|
-
/**
|
|
44
|
-
* One button.
|
|
45
|
-
*
|
|
46
|
-
* @param props - the button's own props plus the variants this plugin uses.
|
|
47
|
-
* @returns the button element.
|
|
48
|
-
*/
|
|
49
|
-
export declare function Button(props: ControlClassProps & {
|
|
50
|
-
readonly variant: ButtonVariant;
|
|
51
|
-
readonly size?: ControlSize;
|
|
52
|
-
readonly type?: 'button' | 'submit';
|
|
53
|
-
readonly disabled?: boolean;
|
|
54
|
-
readonly name?: string;
|
|
55
|
-
readonly title?: string;
|
|
56
|
-
readonly onClick?: () => void;
|
|
57
|
-
readonly children?: ReactNode;
|
|
58
|
-
}): ReactNode;
|
|
59
|
-
/** Props of a text input, narrowed to what the templates pass. */
|
|
60
|
-
export interface TextInputProps extends ControlClassProps {
|
|
61
|
-
readonly id: string;
|
|
62
|
-
readonly name: string;
|
|
63
|
-
readonly value: string;
|
|
64
|
-
readonly disabled?: boolean;
|
|
65
|
-
readonly placeholder?: string;
|
|
66
|
-
readonly inputMode?: 'numeric';
|
|
67
|
-
/** `password` for a secret field: the browser masks it and no autofill offers to save it. */
|
|
68
|
-
readonly type?: 'text' | 'password';
|
|
69
|
-
readonly autoComplete?: 'off' | 'new-password';
|
|
70
|
-
readonly size?: ControlSize;
|
|
71
|
-
readonly onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* One text input, with the platform's border, inset surface and focus ring.
|
|
75
|
-
*
|
|
76
|
-
* @param props - the input's own props.
|
|
77
|
-
* @returns the input element.
|
|
78
|
-
*/
|
|
79
|
-
export declare function TextInput(props: TextInputProps): ReactNode;
|
|
80
|
-
/** One option of a {@link Select}. */
|
|
81
|
-
export interface SelectOption {
|
|
82
|
-
readonly value: string;
|
|
83
|
-
readonly label: string;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* A `<select>` over a fixed list of options.
|
|
87
|
-
*
|
|
88
|
-
* @param props - id, name, the current value, the options and the change handler.
|
|
89
|
-
* @returns the select element.
|
|
90
|
-
*/
|
|
91
|
-
export declare function Select(props: ControlClassProps & {
|
|
92
|
-
readonly id: string;
|
|
93
|
-
readonly name: string;
|
|
94
|
-
readonly value: string;
|
|
95
|
-
readonly options: readonly SelectOption[];
|
|
96
|
-
readonly disabled?: boolean;
|
|
97
|
-
readonly size?: ControlSize;
|
|
98
|
-
readonly onChange: (value: string) => void;
|
|
99
|
-
}): ReactNode;
|
|
100
|
-
/**
|
|
101
|
-
* A labelled field: the caption above its control, so the column and its label move together.
|
|
102
|
-
*
|
|
103
|
-
* @param props - the label text, the control's id and the control itself.
|
|
104
|
-
* @returns the labelled column.
|
|
105
|
-
*/
|
|
106
|
-
export declare function Field(props: {
|
|
107
|
-
readonly label: string;
|
|
108
|
-
readonly htmlFor: string;
|
|
109
|
-
readonly children: ReactNode;
|
|
110
|
-
}): ReactNode;
|
|
111
|
-
/**
|
|
112
|
-
* An inline notice block: the surface for a refusal, a host warning or "no host data".
|
|
113
|
-
*
|
|
114
|
-
* @param props - `warn` for something the operator may need to act on, `info` for a neutral status.
|
|
115
|
-
* @returns the notice element carrying the role its caller needs (`alert` / `note` / `status`).
|
|
116
|
-
*/
|
|
117
|
-
export declare function Notice(props: {
|
|
118
|
-
readonly role: 'alert' | 'note' | 'status';
|
|
119
|
-
readonly tone?: 'warn' | 'info';
|
|
120
|
-
readonly children: ReactNode;
|
|
121
|
-
}): ReactNode;
|
|
122
|
-
/**
|
|
123
|
-
* The status dot of a connection row, so the row's state is not carried by colour alone.
|
|
124
|
-
*
|
|
125
|
-
* @param props - the dot's accessible description.
|
|
126
|
-
* @returns the dot element.
|
|
127
|
-
*/
|
|
128
|
-
export declare function StatusDot(props: {
|
|
129
|
-
readonly label: string;
|
|
130
|
-
}): ReactNode;
|
|
131
|
-
//# sourceMappingURL=controls.d.ts.map
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The **one** Tab trap every card in this plugin installs.
|
|
3
|
-
*
|
|
4
|
-
* Five surfaces are dialogs and every one of them has to keep Tab inside itself, for two different reasons:
|
|
5
|
-
*
|
|
6
|
-
* - the settings-hosted cards sit **outside** the platform settings modal, whose own focus trap listens on
|
|
7
|
-
* `document` in the bubble phase and pulls focus back into its panel — a bubble-phase listener of ours would
|
|
8
|
-
* run after it (registration order) and could no longer tell which field Tab came from, so the trap has to
|
|
9
|
-
* be in the **capture** phase (audit 0090);
|
|
10
|
-
* - the overlay and composer cards are simply modals: Tab walking into the page behind them is a dialog the
|
|
11
|
-
* keyboard user leaves without dismissing.
|
|
12
|
-
*
|
|
13
|
-
* Both cases want the same mechanics, so they live here instead of being spelled out per surface (the two that
|
|
14
|
-
* were first — the connection editor and the session-panel confirmation — each carried their own copy of the
|
|
15
|
-
* same eight lines, and the two newer ones had none at all; audit 2026-10-31 `client.md` §2.3).
|
|
16
|
-
*
|
|
17
|
-
* The split is the same one the rest of `core/` uses: {@link installCardTabTrap} is pure and takes the document
|
|
18
|
-
* as an argument (so an offline test drives it with a fake), and {@link useCardTabTrap} is the two-line React
|
|
19
|
-
* binding.
|
|
20
|
-
*
|
|
21
|
-
* @module dsh-over-ssh/client/card-focus-trap
|
|
22
|
-
*/
|
|
23
|
-
import { type PortalDocument } from './portal.ts';
|
|
24
|
-
/**
|
|
25
|
-
* Install the card's Tab trap on one document.
|
|
26
|
-
*
|
|
27
|
-
* Capture phase on purpose: see the module note. The listener is removed with the same `options` value, so a
|
|
28
|
-
* runtime that keys listeners by phase cannot leak one.
|
|
29
|
-
*
|
|
30
|
-
* @param doc - the page's document, or `undefined` off-browser (where this is a no-op).
|
|
31
|
-
* @param container - the card's body-level container; `undefined` while it is not attached.
|
|
32
|
-
* @returns the remover; safe to call more than once.
|
|
33
|
-
*/
|
|
34
|
-
export declare function installCardTabTrap(doc: PortalDocument | undefined, container: unknown): () => void;
|
|
35
|
-
/**
|
|
36
|
-
* Trap Tab while a card is open.
|
|
37
|
-
*
|
|
38
|
-
* `open` is the caller's own condition (`editingId !== undefined`, `pending !== undefined`, `request !==
|
|
39
|
-
* undefined`); the container comes from that surface's portal. Nothing is installed while the card is closed, so
|
|
40
|
-
* the settings panel keeps its own Tab behaviour the rest of the time.
|
|
41
|
-
*
|
|
42
|
-
* @param open - whether the card is up.
|
|
43
|
-
* @param container - the card's container from its portal.
|
|
44
|
-
*/
|
|
45
|
-
export declare function useCardTabTrap(open: boolean, container: unknown): void;
|