@tiphareth/dsh-hardssh 0.1.2 → 0.2.2
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/LICENSE +30 -0
- package/README.md +49 -25
- package/SKILLS.md +140 -0
- package/lib/base/index.js +95 -0
- package/lib/client.js +1171 -1321
- package/lib/fs.js +307 -416
- package/lib/index.js +5428 -2991
- package/lib/ledger-B-LXlftp.js +43 -0
- package/lib/ledger-D2ezq1iW.js +376 -0
- package/lib/model-Cp7f70Mb.js +5 -0
- package/lib/registry-CViuzKYI.js +421 -0
- package/lib/subprocess.js +92 -549
- package/lib/types/backend.d.ts +73 -78
- package/lib/types/base/capability.d.ts +4 -0
- package/lib/types/base/ledger-router.d.ts +42 -26
- package/lib/types/base/ledger.d.ts +30 -19
- package/lib/types/base/model.d.ts +17 -8
- package/lib/types/base/plugin.d.ts +11 -0
- package/lib/types/base/registry.d.ts +28 -31
- package/lib/types/base/router.d.ts +0 -7
- package/lib/types/client/api.d.ts +8 -8
- package/lib/types/client/connect-host.d.ts +13 -0
- package/lib/types/client/index.d.ts +6 -4
- package/lib/types/client/locales.d.ts +15 -1
- package/lib/types/client/session-connect-gate.d.ts +71 -0
- package/lib/types/client/ssh/api.d.ts +11 -9
- package/lib/types/client/ssh/apply.d.ts +14 -8
- package/lib/types/client/ssh/locales.d.ts +8 -1
- package/lib/types/client/ssh/ops-tab.d.ts +34 -0
- package/lib/types/client/ssh/panel/ClusterTab.d.ts +3 -1
- package/lib/types/client/ssh/panel/ConnectionErrorDialog.d.ts +8 -0
- package/lib/types/client/ssh/panel/SessionSecretDialog.d.ts +4 -1
- package/lib/types/client/ssh/panel/SshPanel.d.ts +8 -8
- package/lib/types/client/ssh/panel/TerminalTab.d.ts +3 -5
- package/lib/types/client/ssh/panel/TransferTab.d.ts +5 -1
- package/lib/types/client/ssh/panel/TunnelsTab.d.ts +3 -1
- package/lib/types/client/ssh/session-target.d.ts +17 -0
- package/lib/types/client/state.d.ts +4 -1
- package/lib/types/client/workspace-panel-entry.d.ts +30 -0
- package/lib/types/client/workspace-panel.d.ts +24 -0
- package/lib/types/client-http.d.ts +77 -6
- package/lib/types/core.d.ts +5 -16
- package/lib/types/fs.d.ts +18 -25
- package/lib/types/index.d.ts +138 -9
- package/lib/types/ledger.d.ts +16 -111
- package/lib/types/protocol.d.ts +0 -5
- package/lib/types/providers/index.d.ts +6 -3
- package/lib/types/providers/local/provider.d.ts +83 -23
- package/lib/types/providers/ssh/provider.d.ts +24 -57
- package/lib/types/remote/environment.d.ts +2 -0
- package/lib/types/remote/remote-fs.d.ts +12 -1
- package/lib/types/remote/remote-process.d.ts +22 -1
- package/lib/types/remote/remote-subprocess.d.ts +13 -1
- package/lib/types/remote/remote-terminal.d.ts +4 -0
- package/lib/types/remote-search.d.ts +3 -3
- package/lib/types/routes.d.ts +36 -8
- package/lib/types/runtime/dsh-capabilities.d.ts +18 -0
- package/lib/types/runtime/workspace-core.d.ts +73 -38
- package/lib/types/runtime/workspace-migration.d.ts +113 -0
- package/lib/types/ssh/connection/lease.d.ts +23 -0
- package/lib/types/ssh/connection/manager.d.ts +359 -0
- package/lib/types/ssh/connection/pool.d.ts +8 -1
- package/lib/types/ssh/engine.d.ts +97 -267
- package/lib/types/ssh/known-hosts.d.ts +22 -5
- package/lib/types/ssh/local-transfer-policy.d.ts +20 -0
- package/lib/types/ssh/plugin.d.ts +10 -15
- package/lib/types/ssh/protocol.d.ts +18 -0
- package/lib/types/ssh/routes.d.ts +15 -7
- package/lib/types/ssh/sftp/service.d.ts +216 -0
- package/lib/types/ssh/store.d.ts +20 -8
- package/lib/types/ssh/terminal/service.d.ts +49 -0
- package/lib/types/ssh/tunnel/service.d.ts +26 -0
- package/lib/types/ssh/vault.d.ts +51 -4
- package/lib/types/subprocess.d.ts +13 -21
- package/lib/types/switch/switch-fs.d.ts +52 -2
- package/lib/types/switch/switch-subprocess.d.ts +32 -3
- package/lib/types/tools.d.ts +7 -6
- package/lib/types/workspace-tool-ops.d.ts +33 -0
- package/lib/types/workspace.d.ts +18 -0
- package/lib/vault-3gpWct2Q.js +559 -0
- package/lib/workspace.js +2 -0
- package/package.json +58 -25
- package/scripts/export-legacy-workspaces.mjs +136 -0
- package/src/backend.ts +155 -483
- package/src/base/capability.ts +4 -0
- package/src/base/ledger-router.ts +214 -65
- package/src/base/ledger.ts +175 -48
- package/src/base/model.ts +18 -8
- package/src/base/plugin.ts +15 -4
- package/src/base/registry.ts +49 -41
- package/src/base/router.ts +0 -8
- package/src/client/api.ts +8 -36
- package/src/client/connect-host.ts +199 -0
- package/src/client/directory-flow.tsx +91 -36
- package/src/client/index.ts +56 -53
- package/src/client/locales.ts +14 -0
- package/src/client/session-connect-gate.ts +163 -0
- package/src/client/ssh/api.ts +245 -108
- package/src/client/ssh/apply.ts +23 -24
- package/src/client/ssh/locales.ts +16 -2
- package/src/client/ssh/ops-tab.tsx +79 -0
- package/src/client/ssh/panel/ClusterTab.tsx +9 -20
- package/src/client/ssh/panel/ConnectionErrorDialog.tsx +33 -0
- package/src/client/ssh/panel/SessionSecretDialog.tsx +5 -1
- package/src/client/ssh/panel/SshPanel.tsx +81 -77
- package/src/client/ssh/panel/TerminalTab.tsx +18 -37
- package/src/client/ssh/panel/TransferTab.tsx +43 -33
- package/src/client/ssh/panel/TunnelsTab.tsx +9 -26
- package/src/client/ssh/panel/panel.module.css +90 -127
- package/src/client/ssh/session-target.ts +69 -0
- package/src/client/state.ts +9 -1
- package/src/client/workspace-badges.ts +99 -96
- package/src/client/workspace-panel-entry.tsx +91 -0
- package/src/client/workspace-panel.tsx +227 -0
- package/src/client/workspace.module.css +76 -2
- package/src/client-http.ts +118 -18
- package/src/core.ts +37 -47
- package/src/fs.ts +137 -85
- package/src/index.ts +535 -244
- package/src/ledger.ts +62 -416
- package/src/protocol.ts +0 -6
- package/src/providers/index.ts +8 -4
- package/src/providers/local/provider.ts +259 -87
- package/src/providers/ssh/provider.ts +158 -155
- package/src/remote/environment.ts +22 -1
- package/src/remote/remote-fs.ts +123 -34
- package/src/remote/remote-process.ts +265 -203
- package/src/remote/remote-subprocess.ts +61 -18
- package/src/remote/remote-terminal.ts +106 -21
- package/src/remote-search.ts +122 -26
- package/src/routes.ts +416 -395
- package/src/runtime/dsh-capabilities.ts +19 -0
- package/src/runtime/workspace-core.ts +171 -88
- package/src/runtime/workspace-migration.ts +472 -0
- package/src/ssh/connection/lease.ts +35 -0
- package/src/ssh/connection/manager.ts +1083 -0
- package/src/ssh/connection/pool.ts +341 -275
- package/src/ssh/engine.ts +269 -1477
- package/src/ssh/known-hosts.ts +42 -18
- package/src/ssh/local-transfer-policy.ts +83 -0
- package/src/ssh/plugin.ts +20 -19
- package/src/ssh/protocol.ts +22 -1
- package/src/ssh/routes.ts +419 -187
- package/src/ssh/sftp/service.ts +967 -0
- package/src/ssh/store.ts +169 -72
- package/src/ssh/terminal/service.ts +177 -0
- package/src/ssh/tools.ts +42 -20
- package/src/ssh/tunnel/service.ts +217 -0
- package/src/ssh/vault.ts +245 -91
- package/src/subprocess.ts +88 -71
- package/src/switch/switch-fs.ts +141 -10
- package/src/switch/switch-subprocess.ts +80 -6
- package/src/tools.ts +217 -221
- package/src/workspace-tool-ops.ts +101 -0
- package/src/workspace.ts +52 -0
- package/lib/environment-BL1jddfB.js +0 -449
- package/lib/switch-fs-CAJpFY9C.js +0 -193
- package/lib/switch-fs-RrZtG2gv.js +0 -210
- package/lib/types/client/manager-button.d.ts +0 -32
- package/lib/types/client/ssh/mount.d.ts +0 -13
- package/lib/types/client/ssh/panel/HostsTab.d.ts +0 -10
- package/lib/types/client/ssh/panel/controller.d.ts +0 -23
- package/lib/types/client/ssh/sidebar-entry.d.ts +0 -25
- package/lib/types/client/workspace-gate.d.ts +0 -15
- package/lib/types/remote-runner.d.ts +0 -83
- package/lib/types/seam-state.d.ts +0 -69
- package/src/client/manager-button.tsx +0 -269
- package/src/client/ssh/mount.tsx +0 -83
- package/src/client/ssh/panel/HostsTab.tsx +0 -236
- package/src/client/ssh/panel/controller.ts +0 -48
- package/src/client/ssh/sidebar-entry.ts +0 -123
- package/src/client/workspace-gate.ts +0 -225
- package/src/remote-runner.ts +0 -201
- package/src/seam-state.ts +0 -185
|
@@ -11,7 +11,14 @@ export declare const zh: {
|
|
|
11
11
|
'manager.label': string;
|
|
12
12
|
'manager.tooltip': string;
|
|
13
13
|
'manager.title': string;
|
|
14
|
+
'panel.workspaces': string;
|
|
15
|
+
'ops.tab': string;
|
|
16
|
+
'ops.guide': string;
|
|
14
17
|
'manager.empty': string;
|
|
18
|
+
'manager.connected': string;
|
|
19
|
+
'manager.disconnected': string;
|
|
20
|
+
'manager.connectionUnknown': string;
|
|
21
|
+
'manager.connectionError': string;
|
|
15
22
|
'manager.delete': string;
|
|
16
23
|
'manager.editServer': string;
|
|
17
24
|
'manager.deleteServer': string;
|
|
@@ -60,7 +67,14 @@ export declare const dictionaries: {
|
|
|
60
67
|
'manager.label': string;
|
|
61
68
|
'manager.tooltip': string;
|
|
62
69
|
'manager.title': string;
|
|
70
|
+
'panel.workspaces': string;
|
|
71
|
+
'ops.tab': string;
|
|
72
|
+
'ops.guide': string;
|
|
63
73
|
'manager.empty': string;
|
|
74
|
+
'manager.connected': string;
|
|
75
|
+
'manager.disconnected': string;
|
|
76
|
+
'manager.connectionUnknown': string;
|
|
77
|
+
'manager.connectionError': string;
|
|
64
78
|
'manager.delete': string;
|
|
65
79
|
'manager.editServer': string;
|
|
66
80
|
'manager.deleteServer': string;
|
|
@@ -99,6 +113,6 @@ export declare const dictionaries: {
|
|
|
99
113
|
'gate.failed': string;
|
|
100
114
|
'gate.retryLimit': string;
|
|
101
115
|
};
|
|
102
|
-
readonly en: Record<"manager.label" | "manager.tooltip" | "manager.title" | "manager.empty" | "manager.delete" | "manager.editServer" | "manager.deleteServer" | "manager.newHost" | "manager.hostInUse" | "create.host" | "create.hostEmpty" | "create.dir" | "create.dirPlaceholder" | "create.browse" | "create.up" | "create.current" | "create.titleLabel" | "create.titlePlaceholder" | "create.submit" | "create.cancel" | "create.connecting" | "create.needHost" | "create.needDir" | "create.needTitle" | "create.needConnect" | "host.add" | "host.save" | "host.needFields" | "host.needPassword" | "dialog.alias" | "dialog.host" | "dialog.port" | "dialog.user" | "dialog.password" | "dialog.passwordHint" | "flow.local" | "flow.ssh" | "flow.useThisDir" | "panel.loading" | "gate.failed" | "gate.retryLimit", string>;
|
|
116
|
+
readonly en: Record<"manager.label" | "manager.tooltip" | "manager.title" | "panel.workspaces" | "ops.tab" | "ops.guide" | "manager.empty" | "manager.connected" | "manager.disconnected" | "manager.connectionUnknown" | "manager.connectionError" | "manager.delete" | "manager.editServer" | "manager.deleteServer" | "manager.newHost" | "manager.hostInUse" | "create.host" | "create.hostEmpty" | "create.dir" | "create.dirPlaceholder" | "create.browse" | "create.up" | "create.current" | "create.titleLabel" | "create.titlePlaceholder" | "create.submit" | "create.cancel" | "create.connecting" | "create.needHost" | "create.needDir" | "create.needTitle" | "create.needConnect" | "host.add" | "host.save" | "host.needFields" | "host.needPassword" | "dialog.alias" | "dialog.host" | "dialog.port" | "dialog.user" | "dialog.password" | "dialog.passwordHint" | "flow.local" | "flow.ssh" | "flow.useThisDir" | "panel.loading" | "gate.failed" | "gate.retryLimit", string>;
|
|
103
117
|
};
|
|
104
118
|
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-open connection gate: whenever the shell opens a session whose cwd
|
|
3
|
+
* belongs to an SSH-bound workspace, probe the owning server FIRST so the
|
|
4
|
+
* interactive connection dialogs appear (host-key TOFU confirm / VSCode-style
|
|
5
|
+
* session password) instead of the workspace silently failing underneath.
|
|
6
|
+
*
|
|
7
|
+
* This replaces the old sidebar row-click gate. The shell exposes no row slot
|
|
8
|
+
* for workspace rows, and the previous `[class*="projectRow"]` DOM listener was
|
|
9
|
+
* never a contract — the session list, by contrast, IS a public client surface
|
|
10
|
+
* (`ctx.sessions.list`), so the trigger is now "a session became current" (open)
|
|
11
|
+
* plus "a session appeared while we were watching" (New Session in an SSH
|
|
12
|
+
* workspace) rather than a click on a DOM node we do not own.
|
|
13
|
+
*
|
|
14
|
+
* Probing is delegated to `connectHost`, which owns the TTL pass cache and the
|
|
15
|
+
* in-flight coalescing: re-selecting the same workspace inside the TTL, or
|
|
16
|
+
* creating several sessions in it, prompts at most once.
|
|
17
|
+
*
|
|
18
|
+
* @module dsh-hardssh/client/session-connect-gate
|
|
19
|
+
*/
|
|
20
|
+
/** The narrow slice of `ctx.sessions.list` this gate reads. Structural on
|
|
21
|
+
* purpose: the shell's `SessionId`/`SessionSummary` types stay out of the
|
|
22
|
+
* plugin's public surface, and the adapter at the call site does the one
|
|
23
|
+
* unavoidable cast. */
|
|
24
|
+
export interface SessionGateList {
|
|
25
|
+
subscribe(listener: () => void): () => void;
|
|
26
|
+
/** Initial host list arrival; pending means an empty list is not authoritative. */
|
|
27
|
+
phase(): 'pending' | 'ready';
|
|
28
|
+
/** Currently selected session, undefined on the empty state. */
|
|
29
|
+
currentSessionId(): string | undefined;
|
|
30
|
+
/** Listed session ids, in host order. */
|
|
31
|
+
sessionIds(): readonly string[];
|
|
32
|
+
/** The session's workspace cwd (the anchor path for SSH workspaces). */
|
|
33
|
+
sessionCwd(sessionId: string): string | undefined;
|
|
34
|
+
}
|
|
35
|
+
/** Gate dependencies. */
|
|
36
|
+
export interface SessionConnectGateDeps {
|
|
37
|
+
sessions: SessionGateList;
|
|
38
|
+
/** Alias owning the SSH workspace that CONTAINS this cwd, when bound. */
|
|
39
|
+
aliasForCwd(cwd: string | undefined): string | undefined;
|
|
40
|
+
/** Probe + prompt; resolves true once the server may be used. */
|
|
41
|
+
ensureConnected(alias: string): Promise<boolean>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build the cwd → workspace resolver over a live workspace list. The LONGEST
|
|
45
|
+
* matching anchor wins, so a workspace nested under another one still routes to
|
|
46
|
+
* its own server.
|
|
47
|
+
* @param workspaces - live records carrying an anchor path.
|
|
48
|
+
* @returns resolver returning the owning record, or undefined when unbound.
|
|
49
|
+
*/
|
|
50
|
+
export declare function makeAnchorWorkspaceResolver<T extends {
|
|
51
|
+
anchorPath: string;
|
|
52
|
+
}>(workspaces: () => ReadonlyArray<T>): (cwd: string | undefined) => T | undefined;
|
|
53
|
+
/** Alias-only compatibility face used by the connection gate. */
|
|
54
|
+
export declare function makeAnchorAliasResolver(workspaces: () => ReadonlyArray<{
|
|
55
|
+
alias: string;
|
|
56
|
+
anchorPath: string;
|
|
57
|
+
}>): (cwd: string | undefined) => string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Watch the session list and probe the server behind every SSH-bound session
|
|
60
|
+
* the operator opens or creates.
|
|
61
|
+
*
|
|
62
|
+
* The first pass ADOPTS the existing list without probing: a GUI restore must
|
|
63
|
+
* not fire one connection dialog per remembered session. Only the session the
|
|
64
|
+
* shell actually selects (including the restored current one) and sessions
|
|
65
|
+
* created after that pass trigger a probe.
|
|
66
|
+
*
|
|
67
|
+
* @param deps - session list view, anchor resolver and probe.
|
|
68
|
+
* @returns disposer removing the subscription.
|
|
69
|
+
*/
|
|
70
|
+
export declare function mountSessionConnectGate(deps: SessionConnectGateDeps): () => void;
|
|
71
|
+
//# sourceMappingURL=session-connect-gate.d.ts.map
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* Browser-side API client for the /api/dsh-ssh route family. The only data
|
|
3
3
|
* access path the panel components use — plain fetch/WebSocket, same origin.
|
|
4
4
|
*/
|
|
5
|
+
import { HttpApiError } from '../../client-http.ts';
|
|
5
6
|
import { type ClusterResult, type ExecResult, type HostPayload, type ImportResult, type KnownHostAction, type KnownHostView, type RemoteDirEntry, type SshHostSummary, type TestResult, type TransferProgress, type TunnelInfo } from '../../ssh/protocol.ts';
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
/**
|
|
8
|
+
* This family's error name for the ONE shared transport error
|
|
9
|
+
* (`HttpApiError`): same class at runtime, so it carries the HTTP status and
|
|
10
|
+
* the parsed body (code / secret / hostKeyFingerprint / hostKeyMismatch /
|
|
11
|
+
* remaining / retryAfterMs) and existing `instanceof SshApiError` checks keep
|
|
12
|
+
* working. Parsing lives in ./client-http.ts — never re-implemented here.
|
|
13
|
+
*/
|
|
14
|
+
export { HttpApiError as SshApiError };
|
|
13
15
|
/** One open terminal connection (WebSocket JSON frames). */
|
|
14
16
|
export interface TerminalConnection {
|
|
15
17
|
/** Fired on the ready frame (shell is up). */
|
|
@@ -56,7 +58,7 @@ export declare class SshApi {
|
|
|
56
58
|
* Upload one file (raw bytes) to a remote path. Progress arrives through
|
|
57
59
|
* the NDJSON response stream; resolves when the result frame lands.
|
|
58
60
|
*/
|
|
59
|
-
uploadFile(file: File, alias: string, remotePath: string, onProgress?: (progress: TransferProgress) => void): Promise<{
|
|
61
|
+
uploadFile(file: File, alias: string, remotePath: string, onProgress?: (progress: TransferProgress) => void, signal?: AbortSignal): Promise<{
|
|
60
62
|
transferredBytes: number;
|
|
61
63
|
}>;
|
|
62
64
|
/**
|
|
@@ -64,7 +66,7 @@ export declare class SshApi {
|
|
|
64
66
|
* disk when the File System Access API is available (no full-file RAM
|
|
65
67
|
* copy); otherwise falls back to an in-memory Blob.
|
|
66
68
|
*/
|
|
67
|
-
downloadFile(alias: string, remotePath: string, onProgress?: (progress: TransferProgress) => void): Promise<{
|
|
69
|
+
downloadFile(alias: string, remotePath: string, onProgress?: (progress: TransferProgress) => void, signal?: AbortSignal): Promise<{
|
|
68
70
|
blob?: Blob;
|
|
69
71
|
filename: string;
|
|
70
72
|
streamed: boolean;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SSH operations browser surfaces, hosted inside dsh-hardssh's client bundle
|
|
3
|
-
* (migrated from the legacy dsh-ssh package): the 'dsh-ssh'
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* the
|
|
3
|
+
* (migrated from the legacy dsh-ssh package): the 'dsh-ssh' locale
|
|
4
|
+
* dictionaries and the SSH operations console mounted as a RIGHT-Sidebar page
|
|
5
|
+
* tab.
|
|
6
|
+
*
|
|
7
|
+
* Nothing here touches the DOM. The old build injected a sidebar row and a
|
|
8
|
+
* panel container by selector, which the 0.1.5 shell no longer renders — the
|
|
9
|
+
* surfaces are standard plugin extension points now (see ./ops-tab.tsx).
|
|
8
10
|
*/
|
|
9
11
|
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
12
|
+
import type { SshApi } from './api.ts';
|
|
13
|
+
import type { SessionSshTargetSource } from './session-target.ts';
|
|
10
14
|
/** Locale namespace this capability owns (kept as 'dsh-ssh'). */
|
|
11
15
|
export declare const NS = "dsh-ssh";
|
|
12
16
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
@@ -16,8 +20,10 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
|
-
* Mount the SSH operations surfaces (
|
|
20
|
-
* @param ctx - client root context (locale service).
|
|
23
|
+
* Mount the SSH operations surfaces (locale dictionaries + the right-Sidebar tab).
|
|
24
|
+
* @param ctx - client root context (locale service, slot registry, tab registry).
|
|
25
|
+
* @param api - shared SSH API client.
|
|
26
|
+
* @param target - selected Session's fixed SSH target, or null for local Sessions.
|
|
21
27
|
*/
|
|
22
|
-
export declare function mountSshOperations(ctx: ClientContext): void;
|
|
28
|
+
export declare function mountSshOperations(ctx: ClientContext, api: SshApi, target: SessionSshTargetSource): void;
|
|
23
29
|
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -10,6 +10,13 @@ export declare const zh: {
|
|
|
10
10
|
readonly 'tab.transfer': "传输";
|
|
11
11
|
readonly 'tab.tunnels': "隧道";
|
|
12
12
|
readonly 'tab.cluster': "集群";
|
|
13
|
+
readonly 'session.server': "当前服务器";
|
|
14
|
+
readonly 'session.target': "跟随当前会话:{alias} · {remoteRoot}";
|
|
15
|
+
readonly 'session.localTitle': "当前会话位于本地工作区";
|
|
16
|
+
readonly 'session.localUnavailable': "SSH 操作台仅适用于 SSH 工作区会话。请切换到远程会话后使用。";
|
|
17
|
+
readonly 'connectionError.title': "无法连接服务器 {alias}";
|
|
18
|
+
readonly 'connectionError.intro': "SSH 连接未建立,请检查服务器地址、网络和认证配置。";
|
|
19
|
+
readonly 'connectionError.close': "知道了";
|
|
13
20
|
readonly 'hosts.empty': "尚未配置主机。点击「新增主机」添加,或从 ~/.ssh/config 导入。";
|
|
14
21
|
readonly 'hosts.add': "新增主机";
|
|
15
22
|
readonly 'hosts.import': "导入 ~/.ssh/config";
|
|
@@ -64,7 +71,7 @@ export declare const zh: {
|
|
|
64
71
|
readonly 'terminal.selectHost': "选择主机";
|
|
65
72
|
readonly 'terminal.connect': "连接";
|
|
66
73
|
readonly 'terminal.disconnect': "断开";
|
|
67
|
-
readonly 'terminal.placeholder': "
|
|
74
|
+
readonly 'terminal.placeholder': "点击「连接」打开当前会话服务器的远程终端。";
|
|
68
75
|
readonly 'terminal.connecting': "正在连接…";
|
|
69
76
|
readonly 'terminal.ready': "终端已连接({alias})";
|
|
70
77
|
readonly 'terminal.exited': "终端已退出({alias})";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SSH operations surface as a RIGHT-Sidebar page tab.
|
|
3
|
+
*
|
|
4
|
+
* Registration follows the same public two-stage path any shipped tab type
|
|
5
|
+
* uses:
|
|
6
|
+
* 1. `ctx.sidebarRightTabs.register(...)` declares the type — its `id` is the
|
|
7
|
+
* key its body and chip title register under, its `kind` is what
|
|
8
|
+
* `ctx.sidebarRight.openTab(kind)` names.
|
|
9
|
+
* 2. the body goes into the keyed `sidebar.right.pane.tab` seat, the chip title
|
|
10
|
+
* into `sidebar.right.pane.tab.title`, both under that `id`.
|
|
11
|
+
*
|
|
12
|
+
* It is a PAGE type (no `patterns`): it recognizes no resource address, so it is
|
|
13
|
+
* opened by kind from the right sidebar's own add control or from its guide
|
|
14
|
+
* entry — the plugin never forces the column open.
|
|
15
|
+
*
|
|
16
|
+
* The left sidebar's workspace manager is a separate, GLOBAL surface; host
|
|
17
|
+
* CRUD lives there, so this console keeps only the per-session operations:
|
|
18
|
+
* terminal, transfer, tunnels, cluster.
|
|
19
|
+
*/
|
|
20
|
+
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
21
|
+
import type { SshApi } from './api.ts';
|
|
22
|
+
import type { SessionSshTargetSource } from './session-target.ts';
|
|
23
|
+
/** This implementation's identity in the tab system; also the body/title key. */
|
|
24
|
+
export declare const OPS_TAB_ID = "@tiphareth/dsh-hardssh/operations";
|
|
25
|
+
/** The page kind `ctx.sidebarRight.openTab(kind)` names. */
|
|
26
|
+
export declare const OPS_TAB_KIND = "hardssh-operations";
|
|
27
|
+
/**
|
|
28
|
+
* Register the regression type, its body, and its chip title.
|
|
29
|
+
* @param ctx - client root context carrying the tab registry and slot registry.
|
|
30
|
+
* @param api - the SSH API client the panel's tabs operate through.
|
|
31
|
+
* @param target - live target inherited from the selected Session.
|
|
32
|
+
*/
|
|
33
|
+
export declare function registerOperationsTab(ctx: ClientContext, api: SshApi, target: SessionSshTargetSource): void;
|
|
34
|
+
//# sourceMappingURL=ops-tab.d.ts.map
|
|
@@ -2,7 +2,9 @@ import type { SshApi } from '../api.ts';
|
|
|
2
2
|
/** Cluster tab props. */
|
|
3
3
|
export interface ClusterTabProps {
|
|
4
4
|
api: SshApi;
|
|
5
|
+
/** Fixed alias inherited from the selected Session. */
|
|
6
|
+
alias: string;
|
|
5
7
|
}
|
|
6
8
|
/** The cluster execution tab. */
|
|
7
|
-
export declare function ClusterTab({ api }: ClusterTabProps): import("react").JSX.Element;
|
|
9
|
+
export declare function ClusterTab({ api, alias }: ClusterTabProps): import("react").JSX.Element;
|
|
8
10
|
//# sourceMappingURL=ClusterTab.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ConnectionErrorDialogProps {
|
|
2
|
+
alias: string;
|
|
3
|
+
detail: string;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
}
|
|
6
|
+
/** A small acknowledgement dialog for non-interactive SSH connection failures. */
|
|
7
|
+
export declare function ConnectionErrorDialog({ alias, detail, onClose }: ConnectionErrorDialogProps): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=ConnectionErrorDialog.d.ts.map
|
|
@@ -7,10 +7,13 @@ export interface SessionSecretDialogProps {
|
|
|
7
7
|
user?: string;
|
|
8
8
|
/** Which secret the connection needs. */
|
|
9
9
|
secret: 'password' | 'passphrase';
|
|
10
|
+
/** A previous attempt's failure to show at the top (re-prompt with a
|
|
11
|
+
* reason — wrong password, unreachable host, …), VSCode-style. */
|
|
12
|
+
reason?: string;
|
|
10
13
|
onClose: () => void;
|
|
11
14
|
/** Called after the secret was provided (retry the operation). */
|
|
12
15
|
onProvided: () => void;
|
|
13
16
|
}
|
|
14
17
|
/** Prompt for a session-only credential. */
|
|
15
|
-
export declare function SessionSecretDialog({ api, alias, user, secret, onClose, onProvided }: SessionSecretDialogProps): import("react").JSX.Element;
|
|
18
|
+
export declare function SessionSecretDialog({ api, alias, user, secret, reason, onClose, onProvided }: SessionSecretDialogProps): import("react").JSX.Element;
|
|
16
19
|
//# sourceMappingURL=SessionSecretDialog.d.ts.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { SshApi } from '../api.ts';
|
|
2
|
-
import type {
|
|
3
|
-
/** The
|
|
4
|
-
export type SshTab = '
|
|
5
|
-
/**
|
|
2
|
+
import type { SessionSshTargetSource } from '../session-target.ts';
|
|
3
|
+
/** The console's tab identifiers. */
|
|
4
|
+
export type SshTab = 'terminal' | 'transfer' | 'tunnels' | 'cluster';
|
|
5
|
+
/** Console props. */
|
|
6
6
|
export interface SshPanelProps {
|
|
7
|
-
/** The panel state owner (open/close/toggle). */
|
|
8
|
-
controller: PanelController;
|
|
9
7
|
/** The SSH API client every tab operates through. */
|
|
10
8
|
api: SshApi;
|
|
9
|
+
/** Selected Session's fixed SSH target; null means a local Session. */
|
|
10
|
+
target: SessionSshTargetSource;
|
|
11
11
|
}
|
|
12
|
-
/** The tabbed SSH
|
|
13
|
-
export declare function SshPanel({
|
|
12
|
+
/** The tabbed SSH operations console. */
|
|
13
|
+
export declare function SshPanel({ api, target }: SshPanelProps): import("react").JSX.Element;
|
|
14
14
|
//# sourceMappingURL=SshPanel.d.ts.map
|
|
@@ -2,11 +2,9 @@ import type { SshApi } from '../api.ts';
|
|
|
2
2
|
/** Terminal tab props. */
|
|
3
3
|
export interface TerminalTabProps {
|
|
4
4
|
api: SshApi;
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
/** Monotonic id of the connect request (re-applies presetAlias). */
|
|
8
|
-
requestId?: number;
|
|
5
|
+
/** Fixed alias inherited from the selected Session's SSH workspace. */
|
|
6
|
+
alias: string;
|
|
9
7
|
}
|
|
10
8
|
/** The xterm terminal view. */
|
|
11
|
-
export declare function TerminalTab({ api,
|
|
9
|
+
export declare function TerminalTab({ api, alias }: TerminalTabProps): import("react").JSX.Element;
|
|
12
10
|
//# sourceMappingURL=TerminalTab.d.ts.map
|
|
@@ -2,7 +2,11 @@ import type { SshApi } from '../api.ts';
|
|
|
2
2
|
/** Transfer tab props. */
|
|
3
3
|
export interface TransferTabProps {
|
|
4
4
|
api: SshApi;
|
|
5
|
+
/** Fixed alias inherited from the selected Session. */
|
|
6
|
+
alias: string;
|
|
7
|
+
/** Initial browser/path root inherited from the Session's SSH workspace. */
|
|
8
|
+
remoteRoot: string;
|
|
5
9
|
}
|
|
6
10
|
/** The upload/download tab. */
|
|
7
|
-
export declare function TransferTab({ api }: TransferTabProps): import("react").JSX.Element;
|
|
11
|
+
export declare function TransferTab({ api, alias, remoteRoot }: TransferTabProps): import("react").JSX.Element;
|
|
8
12
|
//# sourceMappingURL=TransferTab.d.ts.map
|
|
@@ -2,7 +2,9 @@ import type { SshApi } from '../api.ts';
|
|
|
2
2
|
/** Tunnels tab props. */
|
|
3
3
|
export interface TunnelsTabProps {
|
|
4
4
|
api: SshApi;
|
|
5
|
+
/** Fixed alias inherited from the selected Session. */
|
|
6
|
+
alias: string;
|
|
5
7
|
}
|
|
6
8
|
/** The tunnels tab. */
|
|
7
|
-
export declare function TunnelsTab({ api }: TunnelsTabProps): import("react").JSX.Element;
|
|
9
|
+
export declare function TunnelsTab({ api, alias }: TunnelsTabProps): import("react").JSX.Element;
|
|
8
10
|
//# sourceMappingURL=TunnelsTab.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SessionGateList } from '../session-connect-gate.ts';
|
|
2
|
+
import type { WorkspaceManager } from '../state.ts';
|
|
3
|
+
/** Fixed SSH identity inherited from the currently selected Session. */
|
|
4
|
+
export interface SessionSshTarget {
|
|
5
|
+
sessionId: string;
|
|
6
|
+
workspaceId: string;
|
|
7
|
+
alias: string;
|
|
8
|
+
remoteRoot: string;
|
|
9
|
+
}
|
|
10
|
+
/** React-compatible external store; null means the Session is local/unbound. */
|
|
11
|
+
export interface SessionSshTargetSource {
|
|
12
|
+
subscribe(listener: () => void): () => void;
|
|
13
|
+
getSnapshot(): SessionSshTarget | null;
|
|
14
|
+
}
|
|
15
|
+
/** Build one stable Session → SSH target source over the public session list and workspace manager. */
|
|
16
|
+
export declare function createSessionSshTargetSource(sessions: SessionGateList, manager: Pick<WorkspaceManager, 'getSnapshot' | 'subscribe'>): SessionSshTargetSource;
|
|
17
|
+
//# sourceMappingURL=session-target.d.ts.map
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* between polls. There is NO global local/remote mode anymore — a session's
|
|
6
6
|
* execution world is decided host-side by its cwd (an anchor path of an SSH
|
|
7
7
|
* workspace routes remote); this client state only drives the management UI
|
|
8
|
-
* (list / create / delete) and the sidebar
|
|
8
|
+
* (list / create / delete) and the sidebar row decoration (remote badge + the
|
|
9
|
+
* shell's hover card path rewrite).
|
|
9
10
|
*/
|
|
10
11
|
import type { SshWorkspaceRecord } from '../protocol.ts';
|
|
11
12
|
import type { WorkspaceApi } from './api.ts';
|
|
@@ -20,6 +21,8 @@ export declare class WorkspaceManager {
|
|
|
20
21
|
private state;
|
|
21
22
|
private readonly listeners;
|
|
22
23
|
private timer;
|
|
24
|
+
/** Monotonic list-workspaces request id; only the newest request may commit. */
|
|
25
|
+
private refreshSequence;
|
|
23
26
|
constructor(api: WorkspaceApi);
|
|
24
27
|
getSnapshot(): WorkspaceManagerState;
|
|
25
28
|
subscribe(listener: () => void): () => void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SSH workspace manager's LEFT-sidebar global entry and its CENTER panel.
|
|
3
|
+
*
|
|
4
|
+
* Both are standard plugin extension points, not DOM injection:
|
|
5
|
+
* - `sidebar.panellist` declares the row between "New session" and the
|
|
6
|
+
* workspace browser. Its `id` IS the main-panel key the row selects, and the
|
|
7
|
+
* shell owns the button, the label, and the active highlight.
|
|
8
|
+
* - `main` hosts the panel body under that same key.
|
|
9
|
+
*
|
|
10
|
+
* The id is deliberately our own rather than a shipped one: a fresh id is
|
|
11
|
+
* added beside the shipped rows, while reusing one would replace that row.
|
|
12
|
+
*/
|
|
13
|
+
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
14
|
+
import type { WorkspaceManager } from './state.ts';
|
|
15
|
+
import type { SshApi } from './ssh/api.ts';
|
|
16
|
+
/** The main-panel key AND the sidebar row id: one identity addresses both. */
|
|
17
|
+
export declare const WORKSPACE_PANEL_ID = "dsh-hardssh-workspaces";
|
|
18
|
+
/** Dependencies the panel body needs at render time. */
|
|
19
|
+
export interface WorkspacePanelDeps {
|
|
20
|
+
manager: WorkspaceManager;
|
|
21
|
+
/** Absent when the plugin is mounted without the SSH operations half. */
|
|
22
|
+
sshApi?: SshApi;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Register the left-sidebar row and the center panel body.
|
|
26
|
+
* @param ctx - client root context carrying the slot registry.
|
|
27
|
+
* @param deps - the workspace manager and the host API the panel uses.
|
|
28
|
+
*/
|
|
29
|
+
export declare function registerWorkspacePanel(ctx: ClientContext, deps: WorkspacePanelDeps): void;
|
|
30
|
+
//# sourceMappingURL=workspace-panel-entry.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SSH workspace manager as a CENTER panel (left sidebar global entry →
|
|
3
|
+
* `main` slot). Content is unchanged from the old session-header dropdown:
|
|
4
|
+
* server rows with their SSH-bound workspaces underneath, server edit/delete
|
|
5
|
+
* (delete is refused while the server still backs a workspace), and a
|
|
6
|
+
* "new server" action at the bottom.
|
|
7
|
+
*
|
|
8
|
+
* This is a plain panel body: no portal, no anchoring, no click-outside
|
|
9
|
+
* dismissal. The left sidebar owns the entry row and the center column owns
|
|
10
|
+
* the frame; closing the panel is the shell's business (select the
|
|
11
|
+
* Conversation row back), not ours.
|
|
12
|
+
*/
|
|
13
|
+
import { type ReactElement } from 'react';
|
|
14
|
+
import type { WorkspaceManager } from './state.ts';
|
|
15
|
+
import type { SshApi } from './ssh/api.ts';
|
|
16
|
+
/** Panel props: the workspace snapshot owner and the host API. */
|
|
17
|
+
export interface WorkspaceManagerPanelProps {
|
|
18
|
+
manager: WorkspaceManager;
|
|
19
|
+
/** Full SSH host API (list/create/update/delete) for server management. */
|
|
20
|
+
sshApi?: SshApi;
|
|
21
|
+
}
|
|
22
|
+
/** The workspace manager panel body. */
|
|
23
|
+
export declare function WorkspaceManagerPanel({ manager, sshApi }: WorkspaceManagerPanelProps): ReactElement;
|
|
24
|
+
//# sourceMappingURL=workspace-panel.d.ts.map
|
|
@@ -1,15 +1,86 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Browser-side HTTP
|
|
3
|
-
*
|
|
2
|
+
* Browser-side HTTP transport for the dsh-hardssh route clients — the ONE
|
|
3
|
+
* fetch / JSON-error layer shared by the workspace client (./client/api.ts)
|
|
4
|
+
* and the SSH client (./client/ssh/api.ts). Plain fetch / same-origin —
|
|
5
|
+
* bundled inline into the client bundle.
|
|
6
|
+
*
|
|
7
|
+
* Business layers may translate the error (named subclasses/aliases), but they
|
|
8
|
+
* must not re-parse a response: every route error is decoded here, once, into
|
|
9
|
+
* {@link HttpApiError} with the HTTP status AND the parsed body.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Every route's JSON error body (superset of the SSH `ApiErrorBody`): the
|
|
13
|
+
* stable machine code plus the interactive-gate fields the UI reads.
|
|
14
|
+
*/
|
|
15
|
+
export interface HttpErrorBody {
|
|
16
|
+
/** Human-readable message (`error` is the wire field name). */
|
|
17
|
+
error?: string;
|
|
18
|
+
/** Stable machine code (HOST_KEY_UNKNOWN / NEEDS_PASSWORD / VAULT_* / …). */
|
|
19
|
+
code?: string;
|
|
20
|
+
/** Which secret a connection needs when code === 'NEEDS_PASSWORD'. */
|
|
21
|
+
secret?: 'password' | 'passphrase';
|
|
22
|
+
/** The fingerprint when a host key was refused. */
|
|
23
|
+
hostKeyFingerprint?: string;
|
|
24
|
+
/** Mismatch detail (expected vs actual) when the host key changed. */
|
|
25
|
+
hostKeyMismatch?: {
|
|
26
|
+
expected: string;
|
|
27
|
+
actual: string;
|
|
28
|
+
};
|
|
29
|
+
/** Workspace titles referencing a host that cannot be deleted (HOST_IN_USE). */
|
|
30
|
+
workspaces?: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** Vault lockout: attempts left before the next lockout window. */
|
|
35
|
+
remaining?: number;
|
|
36
|
+
/** Vault lockout: milliseconds until the next attempt is allowed. */
|
|
37
|
+
retryAfterMs?: number;
|
|
38
|
+
/** Forward-compatible: unlisted fields stay reachable through `body`. */
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The single transport error: HTTP status plus the PARSED response body, so
|
|
43
|
+
* no caller re-parses a response and no field is flattened away. The SSH
|
|
44
|
+
* client re-exports it as `SshApiError`; the workspace client subclasses it as
|
|
45
|
+
* `WorkspaceApiError`. Both are this class at runtime, so the UI's
|
|
46
|
+
* `instanceof` / `.code` / `.hostKeyFingerprint` checks keep working.
|
|
4
47
|
*/
|
|
5
|
-
/** Error carrying the route's JSON error message and stable code/status. */
|
|
6
48
|
export declare class HttpApiError extends Error {
|
|
7
|
-
|
|
49
|
+
/** HTTP status, when the error came from a response. */
|
|
8
50
|
readonly status?: number | undefined;
|
|
9
|
-
|
|
51
|
+
/** Parsed JSON error body, when the route sent one. */
|
|
52
|
+
readonly body?: HttpErrorBody | undefined;
|
|
53
|
+
constructor(message: string,
|
|
54
|
+
/** HTTP status, when the error came from a response. */
|
|
55
|
+
status?: number | undefined,
|
|
56
|
+
/** Parsed JSON error body, when the route sent one. */
|
|
57
|
+
body?: HttpErrorBody | undefined);
|
|
58
|
+
/** Stable machine code from the route error body. */
|
|
59
|
+
get code(): string | undefined;
|
|
60
|
+
/** Which secret a connection needs when {@link code} === 'NEEDS_PASSWORD'. */
|
|
61
|
+
get secret(): 'password' | 'passphrase' | undefined;
|
|
62
|
+
/** The fingerprint when a host key was refused. */
|
|
63
|
+
get hostKeyFingerprint(): string | undefined;
|
|
64
|
+
/** Mismatch detail (expected vs actual) when the host key changed. */
|
|
65
|
+
get hostKeyMismatch(): {
|
|
66
|
+
expected: string;
|
|
67
|
+
actual: string;
|
|
68
|
+
} | undefined;
|
|
69
|
+
/** Vault lockout: attempts left. */
|
|
70
|
+
get remaining(): number | undefined;
|
|
71
|
+
/** Vault lockout: milliseconds until the next attempt is allowed. */
|
|
72
|
+
get retryAfterMs(): number | undefined;
|
|
10
73
|
}
|
|
11
74
|
/** Query-string helper (skips undefined and empty values). */
|
|
12
75
|
export declare function buildQuery(params: Record<string, string | number | undefined>): string;
|
|
13
|
-
/** Parse a JSON response or throw
|
|
76
|
+
/** Parse a JSON response or throw {@link HttpApiError} (status + body kept). */
|
|
14
77
|
export declare function readJson<T>(response: Response): Promise<T>;
|
|
78
|
+
/**
|
|
79
|
+
* Throw {@link HttpApiError} for a response that does NOT carry a JSON
|
|
80
|
+
* success body (streamed upload/download): a JSON error body is still parsed
|
|
81
|
+
* and preserved, so the caller sees the route's code instead of raw text.
|
|
82
|
+
* @param response - the non-ok response (or a stream that could not start).
|
|
83
|
+
* @param fallback - message prefix used when the route sent no `error` field.
|
|
84
|
+
*/
|
|
85
|
+
export declare function throwHttpError(response: Response, fallback: string): Promise<never>;
|
|
15
86
|
//# sourceMappingURL=client-http.d.ts.map
|
package/lib/types/core.d.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The shared
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* The shared SSH operations core provided as `ctx.hardsshCore` by the main
|
|
3
|
+
* plugin row. Workspace routing is owned exclusively by `ctx.workspaceCore`;
|
|
4
|
+
* this service retains only the host store and shared SSH engine needed by
|
|
5
|
+
* SSH-specific integrations.
|
|
5
6
|
*/
|
|
6
7
|
import type { SshEngine } from './ssh/engine.ts';
|
|
7
8
|
import type { SshHostEntry, SshHostSummary } from './ssh/protocol.ts';
|
|
8
|
-
import type { SshWorkspaceLedger } from './ledger.ts';
|
|
9
|
-
import type { RemoteWorkspaceRunner } from './remote-runner.ts';
|
|
10
|
-
import type { WorkspaceSeamState } from './seam-state.ts';
|
|
11
9
|
/** Read-only host-store surface exposed on the core (the write paths live in
|
|
12
10
|
* the SSH routes, which get the full store). Avoids coupling the core type
|
|
13
11
|
* to either the plaintext HostStore or the vault-backed SecureHostStore. */
|
|
@@ -17,19 +15,10 @@ export interface HostStoreView {
|
|
|
17
15
|
find(alias: string): SshHostEntry | undefined;
|
|
18
16
|
summarize(entry: SshHostEntry): SshHostSummary;
|
|
19
17
|
}
|
|
20
|
-
/** One process-wide core
|
|
18
|
+
/** One process-wide SSH operations core. Workspace consumers use WorkspaceCore. */
|
|
21
19
|
export interface HardsshCore {
|
|
22
20
|
hosts: HostStoreView;
|
|
23
21
|
engine: SshEngine;
|
|
24
|
-
/** The SSH-bound workspace ledger (anchor dir -> remote dir). */
|
|
25
|
-
ledger: SshWorkspaceLedger;
|
|
26
|
-
/** The shared seam state: ledger-derived routing snapshot + per-record
|
|
27
|
-
* fs/subprocess instances, consumed by the fs/subprocess switch rows. */
|
|
28
|
-
seams: WorkspaceSeamState;
|
|
29
|
-
/** Remote-workspace runner: resolve local anchor paths to remote channels
|
|
30
|
-
* (git / files / commands) so other plugins (dsh-workbench-tiphareth) can
|
|
31
|
-
* operate SSH-bound workspaces transparently. Optional in older builds. */
|
|
32
|
-
resolveRemote?: RemoteWorkspaceRunner['resolveRemote'];
|
|
33
22
|
}
|
|
34
23
|
/**
|
|
35
24
|
* @deprecated Use HardsshCore. Kept as a source-compatible migration alias.
|