@tiphareth/dsh-hardssh 0.1.2-alpha
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 +50 -0
- package/cordis.patch.yml +26 -0
- package/lib/client.js +17794 -0
- package/lib/environment-BL1jddfB.js +449 -0
- package/lib/fs.js +478 -0
- package/lib/index.js +6758 -0
- package/lib/subprocess.js +600 -0
- package/lib/switch-fs-CAJpFY9C.js +193 -0
- package/lib/switch-fs-RrZtG2gv.js +210 -0
- package/lib/types/backend.d.ts +108 -0
- package/lib/types/base/capability.d.ts +107 -0
- package/lib/types/base/index.d.ts +18 -0
- package/lib/types/base/ledger-router.d.ts +48 -0
- package/lib/types/base/ledger.d.ts +82 -0
- package/lib/types/base/model.d.ts +108 -0
- package/lib/types/base/namespace.d.ts +57 -0
- package/lib/types/base/plugin.d.ts +102 -0
- package/lib/types/base/registry.d.ts +60 -0
- package/lib/types/base/router.d.ts +40 -0
- package/lib/types/client/api.d.ts +85 -0
- package/lib/types/client/directory-flow.d.ts +82 -0
- package/lib/types/client/icons.d.ts +19 -0
- package/lib/types/client/index.d.ts +34 -0
- package/lib/types/client/locales.d.ts +104 -0
- package/lib/types/client/manager-button.d.ts +32 -0
- package/lib/types/client/migrate.d.ts +20 -0
- package/lib/types/client/ssh/api.d.ts +89 -0
- package/lib/types/client/ssh/apply.d.ts +23 -0
- package/lib/types/client/ssh/locales.d.ts +156 -0
- package/lib/types/client/ssh/mount.d.ts +13 -0
- package/lib/types/client/ssh/panel/ClusterTab.d.ts +8 -0
- package/lib/types/client/ssh/panel/HostFingerprintDialog.d.ts +16 -0
- package/lib/types/client/ssh/panel/HostFormDialog.d.ts +13 -0
- package/lib/types/client/ssh/panel/HostsTab.d.ts +10 -0
- package/lib/types/client/ssh/panel/SessionSecretDialog.d.ts +16 -0
- package/lib/types/client/ssh/panel/SshPanel.d.ts +14 -0
- package/lib/types/client/ssh/panel/TerminalTab.d.ts +12 -0
- package/lib/types/client/ssh/panel/TransferTab.d.ts +8 -0
- package/lib/types/client/ssh/panel/TunnelsTab.d.ts +8 -0
- package/lib/types/client/ssh/panel/controller.d.ts +23 -0
- package/lib/types/client/ssh/panel/helpers.d.ts +15 -0
- package/lib/types/client/ssh/panel/xterm.css.d.ts +3 -0
- package/lib/types/client/ssh/sidebar-entry.d.ts +25 -0
- package/lib/types/client/state.d.ts +32 -0
- package/lib/types/client/text.d.ts +11 -0
- package/lib/types/client/workspace-badges.d.ts +38 -0
- package/lib/types/client/workspace-gate.d.ts +15 -0
- package/lib/types/client-http.d.ts +15 -0
- package/lib/types/core.d.ts +43 -0
- package/lib/types/fs.d.ts +36 -0
- package/lib/types/host-http.d.ts +25 -0
- package/lib/types/index.d.ts +53 -0
- package/lib/types/ledger.d.ts +132 -0
- package/lib/types/protocol.d.ts +101 -0
- package/lib/types/providers/index.d.ts +19 -0
- package/lib/types/providers/local/provider.d.ts +58 -0
- package/lib/types/providers/ssh/provider.d.ts +112 -0
- package/lib/types/remote/environment.d.ts +29 -0
- package/lib/types/remote/output.d.ts +38 -0
- package/lib/types/remote/remote-fs.d.ts +69 -0
- package/lib/types/remote/remote-process.d.ts +41 -0
- package/lib/types/remote/remote-subprocess.d.ts +31 -0
- package/lib/types/remote/remote-terminal.d.ts +41 -0
- package/lib/types/remote-runner.d.ts +83 -0
- package/lib/types/remote-search.d.ts +50 -0
- package/lib/types/routes.d.ts +24 -0
- package/lib/types/runtime/workspace-core.d.ts +59 -0
- package/lib/types/seam-state.d.ts +69 -0
- package/lib/types/shell.d.ts +8 -0
- package/lib/types/ssh/connection/lease.d.ts +16 -0
- package/lib/types/ssh/connection/pool.d.ts +57 -0
- package/lib/types/ssh/engine.d.ts +434 -0
- package/lib/types/ssh/exec/output.d.ts +31 -0
- package/lib/types/ssh/known-hosts.d.ts +89 -0
- package/lib/types/ssh/plugin.d.ts +57 -0
- package/lib/types/ssh/protocol.d.ts +236 -0
- package/lib/types/ssh/routes.d.ts +44 -0
- package/lib/types/ssh/store.d.ts +107 -0
- package/lib/types/ssh/tools.d.ts +35 -0
- package/lib/types/ssh/transfer/progress.d.ts +14 -0
- package/lib/types/ssh/vault.d.ts +110 -0
- package/lib/types/subprocess.d.ts +32 -0
- package/lib/types/switch/switch-fs.d.ts +88 -0
- package/lib/types/switch/switch-subprocess.d.ts +34 -0
- package/lib/types/tools.d.ts +12 -0
- package/package.json +142 -0
- package/src/backend.ts +624 -0
- package/src/base/capability.ts +86 -0
- package/src/base/index.ts +18 -0
- package/src/base/ledger-router.ts +128 -0
- package/src/base/ledger.ts +299 -0
- package/src/base/model.ts +118 -0
- package/src/base/namespace.ts +102 -0
- package/src/base/plugin.ts +170 -0
- package/src/base/registry.ts +109 -0
- package/src/base/router.ts +43 -0
- package/src/client/api.ts +196 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/directory-flow.tsx +482 -0
- package/src/client/icons.tsx +50 -0
- package/src/client/index.ts +210 -0
- package/src/client/locales.ts +105 -0
- package/src/client/manager-button.tsx +269 -0
- package/src/client/migrate.ts +109 -0
- package/src/client/ssh/api.ts +411 -0
- package/src/client/ssh/apply.ts +50 -0
- package/src/client/ssh/locales.ts +322 -0
- package/src/client/ssh/mount.tsx +83 -0
- package/src/client/ssh/panel/ClusterTab.tsx +123 -0
- package/src/client/ssh/panel/HostFingerprintDialog.tsx +82 -0
- package/src/client/ssh/panel/HostFormDialog.tsx +228 -0
- package/src/client/ssh/panel/HostsTab.tsx +236 -0
- package/src/client/ssh/panel/SessionSecretDialog.tsx +80 -0
- package/src/client/ssh/panel/SshPanel.tsx +77 -0
- package/src/client/ssh/panel/TerminalTab.tsx +176 -0
- package/src/client/ssh/panel/TransferTab.tsx +232 -0
- package/src/client/ssh/panel/TunnelsTab.tsx +177 -0
- package/src/client/ssh/panel/controller.ts +48 -0
- package/src/client/ssh/panel/helpers.ts +26 -0
- package/src/client/ssh/panel/panel.module.css +1006 -0
- package/src/client/ssh/panel/xterm.css.ts +2 -0
- package/src/client/ssh/sidebar-entry.ts +123 -0
- package/src/client/state.ts +99 -0
- package/src/client/text.ts +22 -0
- package/src/client/workspace-badges.ts +99 -0
- package/src/client/workspace-gate.ts +232 -0
- package/src/client/workspace.module.css +283 -0
- package/src/client-http.ts +45 -0
- package/src/core.ts +47 -0
- package/src/fs.ts +85 -0
- package/src/host-http.ts +74 -0
- package/src/index.ts +244 -0
- package/src/ledger.ts +416 -0
- package/src/protocol.ts +114 -0
- package/src/providers/index.ts +34 -0
- package/src/providers/local/provider.ts +179 -0
- package/src/providers/ssh/provider.ts +274 -0
- package/src/remote/environment.ts +123 -0
- package/src/remote/output.ts +142 -0
- package/src/remote/remote-fs.ts +532 -0
- package/src/remote/remote-process.ts +203 -0
- package/src/remote/remote-subprocess.ts +159 -0
- package/src/remote/remote-terminal.ts +141 -0
- package/src/remote-runner.ts +201 -0
- package/src/remote-search.ts +163 -0
- package/src/routes.ts +395 -0
- package/src/runtime/workspace-core.ts +154 -0
- package/src/seam-state.ts +185 -0
- package/src/shell.ts +10 -0
- package/src/ssh/connection/lease.ts +17 -0
- package/src/ssh/connection/pool.ts +275 -0
- package/src/ssh/engine.ts +1761 -0
- package/src/ssh/exec/output.ts +70 -0
- package/src/ssh/known-hosts.ts +214 -0
- package/src/ssh/plugin.ts +184 -0
- package/src/ssh/protocol.ts +227 -0
- package/src/ssh/routes.ts +892 -0
- package/src/ssh/store.ts +544 -0
- package/src/ssh/tools.ts +402 -0
- package/src/ssh/transfer/progress.ts +75 -0
- package/src/ssh/vault.ts +477 -0
- package/src/subprocess.ts +71 -0
- package/src/switch/switch-fs.ts +253 -0
- package/src/switch/switch-subprocess.ts +59 -0
- package/src/tools.ts +221 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SSH operations capability, now hosted inside dsh-hardssh (migrated
|
|
3
|
+
* from the legacy dsh-ssh package): host config store
|
|
4
|
+
* (~/.dsh/dsh-ssh.json), the shared ssh2 engine, /api/dsh-ssh routes, the
|
|
5
|
+
* six ssh_* agent tools, the `dsh-ssh` settings namespace, and the SSH
|
|
6
|
+
* system-prompt section.
|
|
7
|
+
*
|
|
8
|
+
* This module deliberately does NOT create or dispose the engine/store:
|
|
9
|
+
* ownership belongs to src/index.ts (one instance, one dispose point). It
|
|
10
|
+
* only mounts/unmounts surfaces against the shared instances.
|
|
11
|
+
*/
|
|
12
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
13
|
+
import z from '@deepseek-ai/schemastery';
|
|
14
|
+
import type { SshEngine } from './engine.ts';
|
|
15
|
+
/** Settings namespace of the SSH capability. Kept as 'dsh-ssh' so existing
|
|
16
|
+
* user settings survive the package merge unchanged. */
|
|
17
|
+
export declare const SSH_SETTINGS_NAMESPACE = "dsh-ssh";
|
|
18
|
+
/** SSH-capability config, validated by the same-named schemastery schema. */
|
|
19
|
+
export interface SshConfig {
|
|
20
|
+
/** When true (default), a system-prompt section announces the SSH capability. */
|
|
21
|
+
announceToAgent?: boolean;
|
|
22
|
+
/** Master switch for the SSH surfaces (routes, tools, prompt section). */
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Secret storage mode:
|
|
26
|
+
* - 'none' (default): passwords/passphrases are NEVER persisted; each
|
|
27
|
+
* session's first connection prompts for them (VSCode Remote-SSH style)
|
|
28
|
+
* and they live in memory (session password table) for the connection
|
|
29
|
+
* pool lifetime (idle 30 min auto-disconnect; new terminals reuse it).
|
|
30
|
+
* - 'vault': store secrets encrypted at rest (AES-256-GCM) under a master
|
|
31
|
+
* password / DSH_CREDENTIAL_PASSWORD; for headless agents that must run
|
|
32
|
+
* password hosts unattended.
|
|
33
|
+
*/
|
|
34
|
+
secretStorage?: 'none' | 'vault';
|
|
35
|
+
}
|
|
36
|
+
export declare const SshConfig: z<SshConfig>;
|
|
37
|
+
/** Model-facing announcement: SSH operations capability, capabilities, limits. */
|
|
38
|
+
export declare const SSH_GUIDANCE = "\u672C\u673A\u5DF2\u5B89\u88C5 dsh-hardssh \u63D2\u4EF6\uFF08\u5185\u5EFA DSH \u8FDC\u7A0B SSH \u8FD0\u7EF4\uFF09\uFF1A\u4FA7\u8FB9\u680F\u300CSSH\u300D\u5165\u53E3\uFF1BSSH \u8FD0\u7EF4\u4E0E SSH \u5DE5\u4F5C\u533A\u5728 dsh-hardssh \u4E2D\u7EDF\u4E00\u7EF4\u62A4\u3002\u80FD\u529B\uFF1A\u4E3B\u673A\u914D\u7F6E\u5B58 ~/.dsh/dsh-ssh.json\uFF08\u53EF\u4ECE ~/.ssh/config \u5BFC\u5165\uFF09\uFF1B\u6301\u4E45\u8FDE\u63A5\u6C60\u590D\u7528\u957F\u8FDE\u63A5\uFF08\u7A7A\u95F2 30 \u5206\u949F\u81EA\u52A8\u65AD\u5F00\uFF09\uFF1Bssh_list \u5217\u51FA\u4E3B\u673A\u3001ssh_exec \u6267\u884C\u8FDC\u7A0B\u547D\u4EE4\u3001ssh_upload/ssh_download \u4F20\u8F93\u6587\u4EF6\u3001ssh_tunnel \u672C\u5730\u7AEF\u53E3\u8F6C\u53D1\uFF08\u8BBF\u95EE\u8FDC\u7A0B\u6570\u636E\u5E93/\u5185\u7F51\u670D\u52A1\uFF09\u3001ssh_cluster \u96C6\u7FA4\u5E76\u53D1\u6267\u884C\uFF1B\u652F\u6301\u5BC6\u94A5/\u5BC6\u7801\u8BA4\u8BC1\u3001passphrase \u5BC6\u94A5\u4E0E ProxyJump \u8DF3\u677F\u673A\uFF1BWeb \u7EC8\u7AEF\u8D70 WebSocket\u3002\u9650\u5236\uFF1A\u4E3B\u673A\u64CD\u4F5C\u7531\u7528\u6237\u5728 GUI \u4E2D\u914D\u7F6E\u540E agent \u65B9\u53EF\u4F7F\u7528\uFF1B\u5BC6\u7801\u4EE5\u660E\u6587\u5B58\u5728\u7528\u6237\u4E3B\u76EE\u5F55\u79C1\u6709\u6587\u4EF6\uFF08\u6743\u9650 0600\uFF09\uFF1B\u547D\u4EE4\u8F93\u51FA\u539F\u6837\u8FD4\u56DE\u3001\u53EF\u80FD\u542B\u654F\u611F\u4FE1\u606F\uFF1B\u8FDE\u63A5\u5EFA\u7ACB\u5931\u8D25\u4F1A\u81EA\u52A8\u91CD\u8FDE\uFF0C\u4F46\u547D\u4EE4\u6216\u6587\u4EF6\u64CD\u4F5C\u4E00\u65E6\u63D0\u4EA4\u5C31\u4E0D\u4F1A\u81EA\u52A8\u91CD\u8BD5\u2014\u2014\u7ED3\u679C\u4E0D\u660E\u786E\u65F6\u5E94\u5148\u6838\u5B9E\u8FDC\u7AEF\u72B6\u6001\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u4EBA\u5DE5\u91CD\u8BD5\uFF1B\u4F20\u8F93/\u6267\u884C\u6D88\u8017\u771F\u5B9E\u8FDC\u7A0B\u8D44\u6E90\uFF0C\u5148\u786E\u8BA4\u518D\u64CD\u4F5C\u3002\u7528\u6237\u63D0\u5230\u300CSSH / \u8FDC\u7A0B\u670D\u52A1\u5668 / \u670D\u52A1\u5668\u64CD\u4F5C / \u8DF3\u677F\u673A / \u96A7\u9053 / \u90E8\u7F72 / \u4E0A\u4F20\u4E0B\u8F7D\u300D\u65F6\u5373\u6307\u672C\u63D2\u4EF6\uFF0C\u8BF7\u636E\u6B64\u534F\u4F5C\u3002";
|
|
39
|
+
/** Shared instances the SSH surfaces run on. */
|
|
40
|
+
export interface SshCapabilityDeps {
|
|
41
|
+
store: import('./store.ts').SecureHostStore;
|
|
42
|
+
engine: SshEngine;
|
|
43
|
+
/** Host-key TOFU trust store; absent → host-key verification disabled. */
|
|
44
|
+
knownHosts?: import('./known-hosts.ts').KnownHostsStore;
|
|
45
|
+
/** Credential vault; absent → vault endpoints disabled. */
|
|
46
|
+
vault?: import('./vault.ts').Vault;
|
|
47
|
+
/** SSH-bound workspace ledger (host-delete reference guard). */
|
|
48
|
+
ledger?: import('../ledger.ts').SshWorkspaceLedger;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Mount the SSH operations surfaces (routes, tools, settings, prompt) against
|
|
52
|
+
* the shared engine/store. Called from src/index.ts BEFORE the workspace
|
|
53
|
+
* `enabled` early-return, so the SSH capability stays independently togglable
|
|
54
|
+
* via its own `dsh-ssh` settings namespace.
|
|
55
|
+
*/
|
|
56
|
+
export declare function mountSshCapability(ctx: Context, deps: SshCapabilityDeps): void;
|
|
57
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract between the host half (routes.ts) and the browser half
|
|
3
|
+
* (client/api.ts). Pure types only — imported by both halves, bundled into
|
|
4
|
+
* each, no runtime identity to share.
|
|
5
|
+
*/
|
|
6
|
+
/** Authentication flavors a host entry may carry. */
|
|
7
|
+
export type SshAuthKind = 'key' | 'password';
|
|
8
|
+
/** One stored host entry (the ~/.dsh/dsh-ssh.json store shape). */
|
|
9
|
+
export interface SshHostEntry {
|
|
10
|
+
/** Stable, user-chosen identifier used by every operation. */
|
|
11
|
+
alias: string;
|
|
12
|
+
/** Hostname or IP of the target. */
|
|
13
|
+
host: string;
|
|
14
|
+
/** SSH port (default 22). */
|
|
15
|
+
port: number;
|
|
16
|
+
/** Login user. */
|
|
17
|
+
user: string;
|
|
18
|
+
/** Authentication. */
|
|
19
|
+
auth: {
|
|
20
|
+
kind: SshAuthKind;
|
|
21
|
+
/** Absolute path to the private key for 'key' auth. */
|
|
22
|
+
keyPath?: string;
|
|
23
|
+
/** Passphrase for an encrypted key. */
|
|
24
|
+
passphrase?: string;
|
|
25
|
+
/** Password for 'password' auth. */
|
|
26
|
+
password?: string;
|
|
27
|
+
/** Vault ref to the encrypted password/passphrase (v2 secure store). */
|
|
28
|
+
secretRef?: string;
|
|
29
|
+
};
|
|
30
|
+
/** Jump chain: local aliases connected through in order (ProxyJump). */
|
|
31
|
+
proxyJump: string[];
|
|
32
|
+
/** Free-form note. */
|
|
33
|
+
description?: string;
|
|
34
|
+
/** Deployment environment label (development / production / ...). */
|
|
35
|
+
environment?: string;
|
|
36
|
+
/** Free-form tags. */
|
|
37
|
+
tags: string[];
|
|
38
|
+
/** Physical location note. */
|
|
39
|
+
location?: string;
|
|
40
|
+
createdAt: number;
|
|
41
|
+
updatedAt: number;
|
|
42
|
+
}
|
|
43
|
+
/** Public (secret-free) projection of an entry, safe for the browser/agent. */
|
|
44
|
+
export interface SshHostSummary {
|
|
45
|
+
alias: string;
|
|
46
|
+
host: string;
|
|
47
|
+
port: number;
|
|
48
|
+
user: string;
|
|
49
|
+
auth: SshAuthKind;
|
|
50
|
+
/** Whether the key path exists on the host machine (key auth only). */
|
|
51
|
+
keyReady: boolean;
|
|
52
|
+
proxyJump: string[];
|
|
53
|
+
description?: string;
|
|
54
|
+
environment?: string;
|
|
55
|
+
tags: string[];
|
|
56
|
+
location?: string;
|
|
57
|
+
createdAt: number;
|
|
58
|
+
updatedAt: number;
|
|
59
|
+
}
|
|
60
|
+
/** Result of one non-interactive command execution. */
|
|
61
|
+
export interface ExecResult {
|
|
62
|
+
success: boolean;
|
|
63
|
+
/** Remote exit code, or null when the channel died without one. */
|
|
64
|
+
exitCode: number | null;
|
|
65
|
+
timedOut: boolean;
|
|
66
|
+
stdout: string;
|
|
67
|
+
stderr: string;
|
|
68
|
+
/** Wall-clock duration of the round trip in ms. */
|
|
69
|
+
durationMs: number;
|
|
70
|
+
/** Connection error message when the command never ran. */
|
|
71
|
+
error?: string;
|
|
72
|
+
}
|
|
73
|
+
/** One server entry in a cluster run. */
|
|
74
|
+
export interface ClusterResult {
|
|
75
|
+
alias: string;
|
|
76
|
+
ok: boolean;
|
|
77
|
+
exitCode?: number | null;
|
|
78
|
+
timedOut?: boolean;
|
|
79
|
+
stdout?: string;
|
|
80
|
+
stderr?: string;
|
|
81
|
+
durationMs?: number;
|
|
82
|
+
error?: string;
|
|
83
|
+
}
|
|
84
|
+
/** SFTP transfer progress frame (upload stream). */
|
|
85
|
+
export interface TransferProgress {
|
|
86
|
+
phase: 'connecting' | 'transferring' | 'done' | 'error';
|
|
87
|
+
file: string;
|
|
88
|
+
transferred: number;
|
|
89
|
+
total: number;
|
|
90
|
+
percent: number;
|
|
91
|
+
speedBps?: number;
|
|
92
|
+
error?: string;
|
|
93
|
+
}
|
|
94
|
+
/** One active local port-forward tunnel. */
|
|
95
|
+
export interface TunnelInfo {
|
|
96
|
+
id: string;
|
|
97
|
+
alias: string;
|
|
98
|
+
localPort: number;
|
|
99
|
+
remoteHost: string;
|
|
100
|
+
remotePort: number;
|
|
101
|
+
state: 'forwarding' | 'connecting' | 'failed';
|
|
102
|
+
error?: string;
|
|
103
|
+
startedAt: number;
|
|
104
|
+
}
|
|
105
|
+
/** One directory listing entry (remote file browser). */
|
|
106
|
+
export interface RemoteDirEntry {
|
|
107
|
+
name: string;
|
|
108
|
+
type: 'dir' | 'file' | 'other';
|
|
109
|
+
size: number;
|
|
110
|
+
mtimeMs: number;
|
|
111
|
+
mode?: number;
|
|
112
|
+
}
|
|
113
|
+
/** Test-connection outcome. */
|
|
114
|
+
export interface TestResult {
|
|
115
|
+
ok: boolean;
|
|
116
|
+
latencyMs?: number;
|
|
117
|
+
error?: string;
|
|
118
|
+
/** Stable machine code for host-key routing (HOST_KEY_UNKNOWN / HOST_KEY_MISMATCH / NEEDS_PASSWORD). */
|
|
119
|
+
code?: string;
|
|
120
|
+
/** Which secret a connection needs when code === 'NEEDS_PASSWORD'. */
|
|
121
|
+
secret?: 'password' | 'passphrase';
|
|
122
|
+
/** The pending/expected fingerprint when a host key was refused. */
|
|
123
|
+
hostKeyFingerprint?: string;
|
|
124
|
+
/** Mismatch detail (expected vs actual) when the host key changed. */
|
|
125
|
+
hostKeyMismatch?: {
|
|
126
|
+
expected: string;
|
|
127
|
+
actual: string;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Host edit payload (create/update); 'alias' comes from the URL for updates. */
|
|
131
|
+
export interface HostPayload {
|
|
132
|
+
alias?: string;
|
|
133
|
+
host: string;
|
|
134
|
+
port?: number;
|
|
135
|
+
user: string;
|
|
136
|
+
/**
|
|
137
|
+
* Authentication. Required on create; on update an omitted auth keeps the
|
|
138
|
+
* stored secrets (the browser never receives them back).
|
|
139
|
+
*/
|
|
140
|
+
auth?: SshHostEntry['auth'];
|
|
141
|
+
proxyJump?: string[];
|
|
142
|
+
description?: string;
|
|
143
|
+
environment?: string;
|
|
144
|
+
tags?: string[];
|
|
145
|
+
location?: string;
|
|
146
|
+
}
|
|
147
|
+
/** Import outcome from ~/.ssh/config. */
|
|
148
|
+
export interface ImportResult {
|
|
149
|
+
parsed: number;
|
|
150
|
+
added: number;
|
|
151
|
+
skipped: number;
|
|
152
|
+
/** Aliases that failed to map (wildcard patterns, missing HostName, ...). */
|
|
153
|
+
skippedNames: string[];
|
|
154
|
+
}
|
|
155
|
+
/** JSON error body used by every route. */
|
|
156
|
+
export interface ApiErrorBody {
|
|
157
|
+
error: string;
|
|
158
|
+
/** Stable machine code (HOST_KEY_UNKNOWN / HOST_KEY_MISMATCH / HOST_IN_USE / ...). */
|
|
159
|
+
code?: string;
|
|
160
|
+
/** Which secret a connection needs when code === 'NEEDS_PASSWORD'. */
|
|
161
|
+
secret?: 'password' | 'passphrase';
|
|
162
|
+
/** The fingerprint when a host key was refused. */
|
|
163
|
+
hostKeyFingerprint?: string;
|
|
164
|
+
/** Mismatch detail (expected vs actual) when the host key changed. */
|
|
165
|
+
hostKeyMismatch?: {
|
|
166
|
+
expected: string;
|
|
167
|
+
actual: string;
|
|
168
|
+
};
|
|
169
|
+
/** Workspace titles referencing a host that cannot be deleted (HOST_IN_USE). */
|
|
170
|
+
workspaces?: Array<{
|
|
171
|
+
id: string;
|
|
172
|
+
title: string;
|
|
173
|
+
}>;
|
|
174
|
+
}
|
|
175
|
+
/** WebSocket terminal protocol frames (host -> client and client -> host). */
|
|
176
|
+
export type TerminalServerFrame = {
|
|
177
|
+
type: 'ready';
|
|
178
|
+
alias: string;
|
|
179
|
+
} | {
|
|
180
|
+
type: 'output';
|
|
181
|
+
data: string;
|
|
182
|
+
} | {
|
|
183
|
+
type: 'exit';
|
|
184
|
+
code: number | null;
|
|
185
|
+
error?: string;
|
|
186
|
+
};
|
|
187
|
+
export type TerminalClientFrame = {
|
|
188
|
+
type: 'input';
|
|
189
|
+
data: string;
|
|
190
|
+
} | {
|
|
191
|
+
type: 'resize';
|
|
192
|
+
cols: number;
|
|
193
|
+
rows: number;
|
|
194
|
+
};
|
|
195
|
+
/** Route paths the client calls (shared literals). */
|
|
196
|
+
export declare const SSH_API_BASE: "/api/dsh-ssh";
|
|
197
|
+
export declare const SSH_API: {
|
|
198
|
+
readonly hosts: string;
|
|
199
|
+
readonly importSshConfig: string;
|
|
200
|
+
readonly test: string;
|
|
201
|
+
readonly exec: string;
|
|
202
|
+
readonly cluster: string;
|
|
203
|
+
readonly upload: string;
|
|
204
|
+
readonly download: string;
|
|
205
|
+
readonly ls: string;
|
|
206
|
+
readonly tunnel: string;
|
|
207
|
+
readonly terminal: string;
|
|
208
|
+
readonly knownHosts: string;
|
|
209
|
+
readonly vault: string;
|
|
210
|
+
readonly sessionSecret: string;
|
|
211
|
+
readonly connections: string;
|
|
212
|
+
};
|
|
213
|
+
/** One known-host record as seen by the browser (no secrets). */
|
|
214
|
+
export interface KnownHostView {
|
|
215
|
+
alias: string;
|
|
216
|
+
host: string;
|
|
217
|
+
port: number;
|
|
218
|
+
keyType: string;
|
|
219
|
+
fingerprint: string;
|
|
220
|
+
status: 'pending' | 'trusted';
|
|
221
|
+
firstSeenAt: number;
|
|
222
|
+
confirmedAt: number | null;
|
|
223
|
+
}
|
|
224
|
+
/** Host-key trust actions the browser can perform. */
|
|
225
|
+
export type KnownHostAction = 'trust' | 'forget';
|
|
226
|
+
/** NDJSON transfer stream line shapes (upload). */
|
|
227
|
+
export type TransferStreamLine = {
|
|
228
|
+
type: 'progress';
|
|
229
|
+
progress: TransferProgress;
|
|
230
|
+
} | {
|
|
231
|
+
type: 'result';
|
|
232
|
+
ok: boolean;
|
|
233
|
+
transferredBytes?: number;
|
|
234
|
+
error?: string;
|
|
235
|
+
};
|
|
236
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The /api/dsh-ssh route family: host CRUD, exec, cluster, SFTP transfer
|
|
3
|
+
* (NDJSON progress stream for uploads, binary stream for downloads), remote
|
|
4
|
+
* listing, tunnels, and the WebSocket PTY terminal upgrade. Every route
|
|
5
|
+
* carries a loopback-only trust fence (plus browser same-origin markers) —
|
|
6
|
+
* these endpoints execute commands on remote servers, so LAN-exposed dsh web
|
|
7
|
+
* deployments must not serve them.
|
|
8
|
+
*/
|
|
9
|
+
import type { WebRoute, WebUpgradeRoute } from '@deepseek-ai/dsh-host-webserver';
|
|
10
|
+
import type { SshEngine } from './engine.ts';
|
|
11
|
+
import { type KnownHostsStore } from './known-hosts.ts';
|
|
12
|
+
/** Cap on declared upload bodies (staged to disk before SFTP). */
|
|
13
|
+
export declare const DEFAULT_MAX_UPLOAD_BYTES: number;
|
|
14
|
+
/** Route family dependencies. */
|
|
15
|
+
export interface SshRoutesDeps {
|
|
16
|
+
/** The host store (CRUD; vault-backed for secrets). */
|
|
17
|
+
store: import('./store.ts').SecureHostStore;
|
|
18
|
+
/** The engine (ops). */
|
|
19
|
+
engine: SshEngine;
|
|
20
|
+
/** Host-key trust store (TOFU); absent → host-key verification disabled. */
|
|
21
|
+
knownHosts?: KnownHostsStore;
|
|
22
|
+
/** Credential vault (optional; enables /api/dsh-ssh/vault endpoints). */
|
|
23
|
+
vault?: import('./vault.ts').Vault;
|
|
24
|
+
/** SSH-bound workspace ledger (host-delete reference check). */
|
|
25
|
+
ledger?: import('../ledger.ts').SshWorkspaceLedger;
|
|
26
|
+
/** Temp dir for upload/download staging (tests inject a sandbox). */
|
|
27
|
+
stagingDir?: string;
|
|
28
|
+
/** Hard cap on ACTUAL upload bytes accepted (chunked requests included).
|
|
29
|
+
* Defaults to 4 GiB; tests inject a small value. */
|
|
30
|
+
uploadLimitBytes?: number;
|
|
31
|
+
/** Called after a host PATCH/DELETE persisted, so derived caches (e.g. the
|
|
32
|
+
* remote environment cache) can drop that alias. */
|
|
33
|
+
onHostInvalidated?: (alias: string) => void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build every /api/dsh-ssh route (exact paths) plus the terminal upgrade.
|
|
37
|
+
* @param deps - store, engine, staging dir.
|
|
38
|
+
* @returns routes and the upgrade route.
|
|
39
|
+
*/
|
|
40
|
+
export declare function makeRoutes(deps: SshRoutesDeps): {
|
|
41
|
+
routes: WebRoute[];
|
|
42
|
+
upgrade: WebUpgradeRoute;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host config store: one JSON file (`~/.dsh/dsh-ssh.json`) holding every
|
|
3
|
+
* SSH host entry, written atomically (tmp + rename). Also parses the user's
|
|
4
|
+
* standard `~/.ssh/config` for one-shot import. Secrets (passwords,
|
|
5
|
+
* passphrases) live in this user-owned file in plaintext — same trust model
|
|
6
|
+
* as ssh-skill's annotated ssh-config comments; document it, never log it.
|
|
7
|
+
*/
|
|
8
|
+
import type { HostPayload, ImportResult, SshAuthKind, SshHostEntry, SshHostSummary } from './protocol.ts';
|
|
9
|
+
/** Store file location: <home>/.dsh/dsh-ssh.json. */
|
|
10
|
+
export declare function storePath(): string;
|
|
11
|
+
/** The user's standard OpenSSH config path. */
|
|
12
|
+
export declare function sshConfigPath(): string;
|
|
13
|
+
/** Payload shape the validator enforces: full create vs partial patch. */
|
|
14
|
+
export type HostPayloadValidationMode = 'create' | 'patch';
|
|
15
|
+
/** Validate the wire shape of a host payload; returns a message or undefined.
|
|
16
|
+
* `mode` picks the required fields: 'create' demands host/user/auth,
|
|
17
|
+
* 'patch' only validates the fields that are present (same rules).
|
|
18
|
+
* `allowSecretless` relaxes the password requirement so SecureHostStore can
|
|
19
|
+
* persist stripped entries (secrets in vault / never persisted). */
|
|
20
|
+
export declare function validateHostPayload(payload: unknown, mode?: HostPayloadValidationMode, allowSecretless?: boolean): string | undefined;
|
|
21
|
+
/** Validate an alias for creation. */
|
|
22
|
+
export declare function validateAlias(alias: string): string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The host store. Pure file I/O — no cordis dependency, unit-testable.
|
|
25
|
+
*/
|
|
26
|
+
export declare class HostStore {
|
|
27
|
+
/** The JSON file path. */
|
|
28
|
+
readonly path: string;
|
|
29
|
+
/** Optional override of the ~/.ssh/config path (tests). */
|
|
30
|
+
private readonly sshConfigOverride;
|
|
31
|
+
/**
|
|
32
|
+
* @param path - store file path (defaults to the standard location).
|
|
33
|
+
* @param sshConfigOverride - ssh config path override (tests only).
|
|
34
|
+
*/
|
|
35
|
+
constructor(path?: string, sshConfigOverride?: string);
|
|
36
|
+
/** Load all entries (empty store when the file is absent). */
|
|
37
|
+
list(): SshHostEntry[];
|
|
38
|
+
/** Find one entry by alias. */
|
|
39
|
+
find(alias: string): SshHostEntry | undefined;
|
|
40
|
+
/** Secret-free projection for the browser and agent surfaces. */
|
|
41
|
+
summarize(entry: SshHostEntry): SshHostSummary;
|
|
42
|
+
/** Create one entry. Throws on alias collision or invalid payload. */
|
|
43
|
+
create(payload: HostPayload, allowSecretless?: boolean): SshHostEntry;
|
|
44
|
+
/** Update the fields present in `patch`; unknown aliases throw. */
|
|
45
|
+
update(alias: string, patch: Partial<HostPayload>, allowSecretless?: boolean): SshHostEntry;
|
|
46
|
+
/** Remove one entry. */
|
|
47
|
+
delete(alias: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Import hosts from `~/.ssh/config`: Host blocks with a single non-wildcard
|
|
50
|
+
* pattern and a HostName become entries (key auth via IdentityFile, jump
|
|
51
|
+
* hosts via ProxyJump). Existing aliases are skipped.
|
|
52
|
+
* @returns import statistics.
|
|
53
|
+
*/
|
|
54
|
+
importFromSshConfig(): ImportResult;
|
|
55
|
+
private skippedNames;
|
|
56
|
+
private load;
|
|
57
|
+
private save;
|
|
58
|
+
}
|
|
59
|
+
/** Expand a leading `~` in a filesystem path. */
|
|
60
|
+
export declare function expandHome(path: string): string;
|
|
61
|
+
/** Resolved authentication for one connect (vault-aware). */
|
|
62
|
+
export interface ResolvedAuth {
|
|
63
|
+
kind: SshAuthKind;
|
|
64
|
+
keyPath?: string;
|
|
65
|
+
password?: string;
|
|
66
|
+
passphrase?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Secure host store: composes the plaintext HostStore (host/port/user/… +
|
|
70
|
+
* key paths — non-secrets) with the credential handling chosen by
|
|
71
|
+
* `secretStorage`:
|
|
72
|
+
*
|
|
73
|
+
* - **'vault'**: passwords/passphrases are stored encrypted in the
|
|
74
|
+
* credential vault (AES-256-GCM); the hosts file keeps only a `secretRef`,
|
|
75
|
+
* and resolveAuth reveals on demand. For headless agents running password
|
|
76
|
+
* hosts unattended.
|
|
77
|
+
*
|
|
78
|
+
* - **'none' (default, VSCode Remote-SSH style)**: secrets are NEVER
|
|
79
|
+
* persisted. create/update strip the password/passphrase from the entry
|
|
80
|
+
* (kind + keyPath stay); the engine prompts once per session and holds the
|
|
81
|
+
* credential in-memory (session password table). The plaintext HostStore
|
|
82
|
+
* remains untouched, so existing v1 tests and dual-format reads keep
|
|
83
|
+
* working.
|
|
84
|
+
*/
|
|
85
|
+
export declare class SecureHostStore {
|
|
86
|
+
private readonly vault;
|
|
87
|
+
private readonly mode;
|
|
88
|
+
private readonly inner;
|
|
89
|
+
constructor(vault: import('./vault.ts').Vault | undefined, path?: string, sshConfigOverride?: string, mode?: 'none' | 'vault');
|
|
90
|
+
list(): SshHostEntry[];
|
|
91
|
+
find(alias: string): SshHostEntry | undefined;
|
|
92
|
+
summarize(entry: SshHostEntry): SshHostSummary;
|
|
93
|
+
get path(): string;
|
|
94
|
+
/** Legacy ssh-config import (delegates; passwords imported stay inline —
|
|
95
|
+
* a follow-up may route them through the vault). */
|
|
96
|
+
importFromSshConfig(): ImportResult;
|
|
97
|
+
/** Create: secrets are stashed per mode; entry only keeps kind (+ keyPath). */
|
|
98
|
+
create(payload: HostPayload): Promise<SshHostEntry>;
|
|
99
|
+
/** Update: auth present -> re-stash (or strip in none mode); absent → keep. */
|
|
100
|
+
update(alias: string, patch: Partial<HostPayload>): Promise<SshHostEntry>;
|
|
101
|
+
/** Delete: drop the host (and its vault secrets in vault mode, best-effort). */
|
|
102
|
+
delete(alias: string): Promise<void>;
|
|
103
|
+
/** Resolve the authentication for one entry (vault reveal when needed). */
|
|
104
|
+
resolveAuth(entry: SshHostEntry): Promise<ResolvedAuth>;
|
|
105
|
+
private stashSecrets;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent tools: the DSH-native counterpart of ssh-skill's CLI. Every tool
|
|
3
|
+
* talks to the same engine the web UI uses, so a host configured in the GUI
|
|
4
|
+
* is immediately operable by any agent, and vice versa.
|
|
5
|
+
*
|
|
6
|
+
* Result contract (P1-20): every tool resolves to an envelope — `ok` is a
|
|
7
|
+
* required discriminator, business fields appear only on success, and a
|
|
8
|
+
* single `error` string carries failures. Business errors never reject;
|
|
9
|
+
* parameter and engine errors never masquerade as fake payloads. The output
|
|
10
|
+
* schema mirrors this: `ok` required, payload fields optional.
|
|
11
|
+
*/
|
|
12
|
+
import type { SshEngine } from './engine.ts';
|
|
13
|
+
/**
|
|
14
|
+
* Uniform tool result: `{ ok: true, ...payload }` or `{ ok: false, error }`.
|
|
15
|
+
* Business fields only appear on success — no zero-value placeholders.
|
|
16
|
+
*/
|
|
17
|
+
export type ToolEnvelope<T extends object> = ({
|
|
18
|
+
ok: true;
|
|
19
|
+
} & T) | {
|
|
20
|
+
ok: false;
|
|
21
|
+
error: string;
|
|
22
|
+
};
|
|
23
|
+
/** The host-list tool. */
|
|
24
|
+
export declare function sshListTool(engine: SshEngine): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
25
|
+
/** The command-execution tool. */
|
|
26
|
+
export declare function sshExecTool(engine: SshEngine): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
27
|
+
/** The upload tool. */
|
|
28
|
+
export declare function sshUploadTool(engine: SshEngine): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
29
|
+
/** The download tool. */
|
|
30
|
+
export declare function sshDownloadTool(engine: SshEngine): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
31
|
+
/** The tunnel tool. */
|
|
32
|
+
export declare function sshTunnelTool(engine: SshEngine): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
33
|
+
/** The cluster tool. */
|
|
34
|
+
export declare function sshClusterTool(engine: SshEngine): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
35
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared transfer-progress tracker for fastPut/fastGet (P1-19): one
|
|
3
|
+
* throttle/speed/percent rule set so uploads and downloads cannot drift.
|
|
4
|
+
* Sends an initial 0-frame on creation, never throttles the final step,
|
|
5
|
+
* keeps the last known progress on failure, and always reports 100% on done.
|
|
6
|
+
*/
|
|
7
|
+
import type { TransferProgress } from '../protocol.ts';
|
|
8
|
+
export interface TransferProgressTracker {
|
|
9
|
+
step(transferred: number, total: number): void;
|
|
10
|
+
done(): void;
|
|
11
|
+
fail(error: unknown): void;
|
|
12
|
+
}
|
|
13
|
+
export declare function createTransferProgressTracker(file: string, initialTotal: number, emit?: (progress: TransferProgress) => void, now?: () => number): TransferProgressTracker;
|
|
14
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential vault: secrets (SSH passwords, key passphrases) encrypted at
|
|
3
|
+
* rest with AES-256-GCM under a master key derived from a password via
|
|
4
|
+
* scrypt (Node built-in). Each entry uses an independent random nonce and
|
|
5
|
+
* binds its credential reference as GCM AAD; every ciphertext additionally
|
|
6
|
+
* carries a SHA3-256 digest for integrity self-checks. Brute-force lockout
|
|
7
|
+
* persists across restarts.
|
|
8
|
+
*
|
|
9
|
+
* The vault is deliberately dependency-free (node:crypto + fs only) and has
|
|
10
|
+
* no cordis coupling, matching the HostStore style. KDF parameters are stored
|
|
11
|
+
* in the file header so a later KDF upgrade never invalidates existing
|
|
12
|
+
* vaults (algorithm is a stable switch point).
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-hardssh/vault
|
|
15
|
+
*/
|
|
16
|
+
/** Types of secrets the vault stores. */
|
|
17
|
+
export type VaultPurpose = 'host.password' | 'host.passphrase';
|
|
18
|
+
/** KDF parameters persisted in the file header. */
|
|
19
|
+
export interface VaultKdfParams {
|
|
20
|
+
algorithm: 'scrypt';
|
|
21
|
+
N: number;
|
|
22
|
+
r: number;
|
|
23
|
+
p: number;
|
|
24
|
+
saltB64: string;
|
|
25
|
+
}
|
|
26
|
+
/** Vault status (no secrets exposed). */
|
|
27
|
+
export interface VaultStatus {
|
|
28
|
+
locked: boolean;
|
|
29
|
+
mode: 'env' | 'password';
|
|
30
|
+
entries: number;
|
|
31
|
+
}
|
|
32
|
+
/** Default vault file location: <home>/.dsh/dsh-ssh-vault.json. */
|
|
33
|
+
export declare function vaultPath(): string;
|
|
34
|
+
/** SHA3-256 hex of a UTF-8 string. */
|
|
35
|
+
export declare function sha3_256Hex(text: string): string;
|
|
36
|
+
/** Errors raised by the vault. */
|
|
37
|
+
export declare class VaultError extends Error {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
constructor(code: string, message: string);
|
|
40
|
+
}
|
|
41
|
+
/** Unlocked-password or wrong-password errors. */
|
|
42
|
+
export declare class VaultLockedError extends VaultError {
|
|
43
|
+
constructor(message?: string);
|
|
44
|
+
}
|
|
45
|
+
/** Wrong unlock password (with remaining attempts). */
|
|
46
|
+
export declare class VaultAuthError extends VaultError {
|
|
47
|
+
readonly remaining: number;
|
|
48
|
+
constructor(message: string, remaining: number);
|
|
49
|
+
}
|
|
50
|
+
/** Locked out due to repeated failures. */
|
|
51
|
+
export declare class VaultLockoutError extends VaultError {
|
|
52
|
+
readonly retryAfterMs: number;
|
|
53
|
+
constructor(message: string, retryAfterMs: number);
|
|
54
|
+
}
|
|
55
|
+
/** One revealed secret value, registered for output redaction. */
|
|
56
|
+
export interface RevealedSecret {
|
|
57
|
+
ref: string;
|
|
58
|
+
value: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The credential vault. Plain file I/O + node:crypto; no cordis dependency.
|
|
62
|
+
* Construction never requires a password (status/describe work locked); the
|
|
63
|
+
* master key is derived on unlock and cached in memory for the session.
|
|
64
|
+
*/
|
|
65
|
+
export declare class Vault {
|
|
66
|
+
private readonly path;
|
|
67
|
+
private readonly passwordProvider;
|
|
68
|
+
private document;
|
|
69
|
+
private unlockedKey;
|
|
70
|
+
private lockTimer;
|
|
71
|
+
private readonly leaked;
|
|
72
|
+
constructor(filePath?: string, options?: {
|
|
73
|
+
/** Session password source (loopback unlock route passes a password). */
|
|
74
|
+
passwordProvider?: () => Promise<string | undefined>;
|
|
75
|
+
/** Vault idle auto-lock (ms); 0 disables (default 30 min). */
|
|
76
|
+
idleLockMs?: number;
|
|
77
|
+
});
|
|
78
|
+
private load;
|
|
79
|
+
private save;
|
|
80
|
+
private deriveKey;
|
|
81
|
+
private lockoutRetryAfter;
|
|
82
|
+
private checkLockout;
|
|
83
|
+
private verifyPassword;
|
|
84
|
+
private encryptEntryBuffer;
|
|
85
|
+
private decryptEntryBuffer;
|
|
86
|
+
private requireKey;
|
|
87
|
+
private tryEnvUnlock;
|
|
88
|
+
/** Current status (locked / mode / entry count) — safe for UIs. */
|
|
89
|
+
status(): VaultStatus;
|
|
90
|
+
/** Unlock with a password (loopback route / env). Persists lockout on failure. */
|
|
91
|
+
unlock(password: string): Promise<void>;
|
|
92
|
+
/** Lock: drop the in-memory key. JS strings cannot be zeroized; the Buffer
|
|
93
|
+
* key is wiped. */
|
|
94
|
+
lock(): void;
|
|
95
|
+
/** Store one secret, returning a random ref. Requires unlock. */
|
|
96
|
+
store(purpose: VaultPurpose, alias: string, secret: string): Promise<string>;
|
|
97
|
+
/** Reveal one secret (unlock required); registers it for redaction. */
|
|
98
|
+
reveal(ref: string): Promise<string>;
|
|
99
|
+
/** Delete one secret (host delete / cleanup). */
|
|
100
|
+
remove(ref: string): Promise<void>;
|
|
101
|
+
/** Rekey with a new password: decrypt all, re-encrypt under a fresh KDF. */
|
|
102
|
+
rekey(newPassword: string): Promise<void>;
|
|
103
|
+
/** Redact every leaked secret value in `text` (Leak Guard light). */
|
|
104
|
+
redact(text: string): string;
|
|
105
|
+
/** Dispose: wipe the key and stop the idle timer. */
|
|
106
|
+
dispose(): void;
|
|
107
|
+
}
|
|
108
|
+
/** Constant-time helper (kept for completeness; GCM auth is the real gate). */
|
|
109
|
+
export declare function secretsEqual(a: string, b: string): boolean;
|
|
110
|
+
//# sourceMappingURL=vault.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `ctx.subprocess` switch row: provides the workspace-routing subprocess
|
|
3
|
+
* facade in the host scope. The local runtime is mounted in an isolated
|
|
4
|
+
* child scope; every SSH-bound workspace record gets its OWN remote runtime
|
|
5
|
+
* bound to that record's alias + remote root; the facade routes each spawn by
|
|
6
|
+
* its cwd. The facade auto-provides `subprocess` here because the plain
|
|
7
|
+
* subprocess row is disabled by the profile patch.
|
|
8
|
+
*
|
|
9
|
+
* Routing and per-record remote runtimes are owned by the SHARED seam state
|
|
10
|
+
* (hardsshCore.seams): the row binds its per-record runtime factory and reads
|
|
11
|
+
* the state on every spawn. The seam state re-applies the ledger snapshot
|
|
12
|
+
* synchronously on every commit, so creating or removing an SSH workspace
|
|
13
|
+
* takes effect without a plugin restart and the fs/subprocess seams can never
|
|
14
|
+
* disagree. Before the initial ledger load finishes, routing degrades to
|
|
15
|
+
* local with a one-time warning for anchor-root paths.
|
|
16
|
+
*
|
|
17
|
+
* @module dsh-hardssh/subprocess
|
|
18
|
+
*/
|
|
19
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
20
|
+
import type { HardsshCore } from './core.ts';
|
|
21
|
+
declare module '@deepseek-ai/cordis' {
|
|
22
|
+
interface Context {
|
|
23
|
+
hardsshCore: HardsshCore;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Stable cordis plugin name. */
|
|
27
|
+
export declare const name = "hardssh-subprocess";
|
|
28
|
+
/** Services required: the shared workspace core (mode store + engine). */
|
|
29
|
+
export declare const inject: string[];
|
|
30
|
+
/** Mount the switching subprocess facade. */
|
|
31
|
+
export declare function apply(ctx: Context): void;
|
|
32
|
+
//# sourceMappingURL=subprocess.d.ts.map
|