mcp-ssh-pty 1.0.0 → 1.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/dist/config.d.ts CHANGED
@@ -1,12 +1,24 @@
1
1
  import { ServersConfig, ServerConfig } from "./types.js";
2
+ export type ConfigScope = "local" | "global";
2
3
  export declare class ConfigManager {
3
4
  private config;
4
5
  private configPath;
5
- constructor(configPath?: string);
6
+ private scope;
7
+ constructor(configPath?: string, scope?: ConfigScope);
8
+ private getPathByScope;
9
+ static getLocalPath(): string;
10
+ static getGlobalPath(): string;
6
11
  private resolveConfigPath;
7
12
  private expandPath;
8
13
  load(): ServersConfig;
14
+ save(): void;
9
15
  getServer(name: string): ServerConfig | undefined;
10
16
  listServers(): ServerConfig[];
17
+ addServer(server: ServerConfig): void;
18
+ removeServer(name: string): boolean;
11
19
  getConfigPath(): string;
20
+ getScope(): ConfigScope;
21
+ configExists(): boolean;
22
+ static localConfigExists(): boolean;
23
+ static globalConfigExists(): boolean;
12
24
  }
package/dist/config.js CHANGED
@@ -1,24 +1,55 @@
1
- import { readFileSync, existsSync } from "fs";
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
2
2
  import { homedir } from "os";
3
- import { join } from "path";
3
+ import { join, dirname } from "path";
4
4
  export class ConfigManager {
5
5
  config = null;
6
6
  configPath;
7
- constructor(configPath) {
8
- this.configPath = configPath || this.resolveConfigPath();
7
+ scope;
8
+ constructor(configPath, scope) {
9
+ if (configPath) {
10
+ this.configPath = configPath;
11
+ this.scope = "global";
12
+ }
13
+ else if (scope) {
14
+ this.configPath = this.getPathByScope(scope);
15
+ this.scope = scope;
16
+ }
17
+ else {
18
+ const resolved = this.resolveConfigPath();
19
+ this.configPath = resolved.path;
20
+ this.scope = resolved.scope;
21
+ }
22
+ }
23
+ getPathByScope(scope) {
24
+ if (scope === "local") {
25
+ return join(process.cwd(), ".claude", "ssh-servers.json");
26
+ }
27
+ return join(homedir(), ".claude", "ssh-servers.json");
28
+ }
29
+ static getLocalPath() {
30
+ return join(process.cwd(), ".claude", "ssh-servers.json");
31
+ }
32
+ static getGlobalPath() {
33
+ return join(homedir(), ".claude", "ssh-servers.json");
9
34
  }
10
35
  resolveConfigPath() {
11
36
  // 1. 优先使用环境变量
12
37
  if (process.env.SSH_MCP_CONFIG_PATH) {
13
- return this.expandPath(process.env.SSH_MCP_CONFIG_PATH);
38
+ return {
39
+ path: this.expandPath(process.env.SSH_MCP_CONFIG_PATH),
40
+ scope: "global",
41
+ };
14
42
  }
15
43
  // 2. 查找项目目录下的 .claude/ssh-servers.json
16
44
  const projectPath = join(process.cwd(), ".claude", "ssh-servers.json");
17
45
  if (existsSync(projectPath)) {
18
- return projectPath;
46
+ return { path: projectPath, scope: "local" };
19
47
  }
20
48
  // 3. 查找用户目录下的 ~/.claude/ssh-servers.json
21
- return join(homedir(), ".claude", "ssh-servers.json");
49
+ return {
50
+ path: join(homedir(), ".claude", "ssh-servers.json"),
51
+ scope: "global",
52
+ };
22
53
  }
23
54
  expandPath(path) {
24
55
  if (path.startsWith("~")) {
@@ -28,7 +59,9 @@ export class ConfigManager {
28
59
  }
29
60
  load() {
30
61
  if (!existsSync(this.configPath)) {
31
- throw new Error(`配置文件不存在: ${this.configPath}\n请创建配置文件或设置 SSH_MCP_CONFIG_PATH 环境变量`);
62
+ // 如果配置文件不存在,返回空配置
63
+ this.config = { servers: [] };
64
+ return this.config;
32
65
  }
33
66
  try {
34
67
  const content = readFileSync(this.configPath, "utf-8");
@@ -42,6 +75,14 @@ export class ConfigManager {
42
75
  throw error;
43
76
  }
44
77
  }
78
+ save() {
79
+ // 确保目录存在
80
+ const dir = dirname(this.configPath);
81
+ if (!existsSync(dir)) {
82
+ mkdirSync(dir, { recursive: true });
83
+ }
84
+ writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
85
+ }
45
86
  getServer(name) {
46
87
  if (!this.config)
47
88
  this.load();
@@ -52,7 +93,44 @@ export class ConfigManager {
52
93
  this.load();
53
94
  return this.config.servers;
54
95
  }
96
+ addServer(server) {
97
+ if (!this.config)
98
+ this.load();
99
+ // 检查是否已存在
100
+ const existing = this.config.servers.findIndex((s) => s.name === server.name);
101
+ if (existing >= 0) {
102
+ // 更新已有配置
103
+ this.config.servers[existing] = server;
104
+ }
105
+ else {
106
+ this.config.servers.push(server);
107
+ }
108
+ this.save();
109
+ }
110
+ removeServer(name) {
111
+ if (!this.config)
112
+ this.load();
113
+ const index = this.config.servers.findIndex((s) => s.name === name);
114
+ if (index < 0) {
115
+ return false;
116
+ }
117
+ this.config.servers.splice(index, 1);
118
+ this.save();
119
+ return true;
120
+ }
55
121
  getConfigPath() {
56
122
  return this.configPath;
57
123
  }
124
+ getScope() {
125
+ return this.scope;
126
+ }
127
+ configExists() {
128
+ return existsSync(this.configPath);
129
+ }
130
+ static localConfigExists() {
131
+ return existsSync(ConfigManager.getLocalPath());
132
+ }
133
+ static globalConfigExists() {
134
+ return existsSync(ConfigManager.getGlobalPath());
135
+ }
58
136
  }
package/dist/index.js CHANGED
@@ -4,7 +4,25 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
4
  import { SSHManager } from "./ssh-manager.js";
5
5
  import { ConfigManager } from "./config.js";
6
6
  import { registerTools } from "./tools.js";
7
- async function main() {
7
+ import { runCLI } from "./cli.js";
8
+ // CLI 命令列表
9
+ const CLI_COMMANDS = ["list", "add", "remove", "rm", "test", "config", "help", "--help", "-h", "--version", "-V"];
10
+ /**
11
+ * 检查是否是 CLI 模式
12
+ */
13
+ function isCLIMode() {
14
+ const args = process.argv.slice(2);
15
+ // 没有参数时启动 MCP 服务器
16
+ if (args.length === 0) {
17
+ return false;
18
+ }
19
+ // 如果第一个参数是 CLI 命令,则进入 CLI 模式
20
+ return CLI_COMMANDS.includes(args[0]);
21
+ }
22
+ /**
23
+ * 启动 MCP 服务器
24
+ */
25
+ async function startServer() {
8
26
  const server = new McpServer({
9
27
  name: "ssh-mcp-server",
10
28
  version: "1.0.0",
@@ -14,19 +32,26 @@ async function main() {
14
32
  registerTools(server, sshManager, configManager);
15
33
  const transport = new StdioServerTransport();
16
34
  await server.connect(transport);
17
- console.error("SSH MCP Server 已启动");
18
- console.error(`配置文件路径: ${configManager.getConfigPath()}`);
19
35
  process.on("SIGINT", async () => {
20
- console.error("收到 SIGINT,正在关闭...");
21
36
  await sshManager.disconnect();
22
37
  process.exit(0);
23
38
  });
24
39
  process.on("SIGTERM", async () => {
25
- console.error("收到 SIGTERM,正在关闭...");
26
40
  await sshManager.disconnect();
27
41
  process.exit(0);
28
42
  });
29
43
  }
44
+ /**
45
+ * 主函数
46
+ */
47
+ async function main() {
48
+ if (isCLIMode()) {
49
+ await runCLI();
50
+ }
51
+ else {
52
+ await startServer();
53
+ }
54
+ }
30
55
  main().catch((error) => {
31
56
  console.error("启动失败:", error);
32
57
  process.exit(1);
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 敏感信息过滤器
3
+ * 用于在 MCP 返回中隐藏 IP、密码等敏感信息
4
+ */
5
+ export interface SensitivePattern {
6
+ pattern: RegExp;
7
+ replacement: string;
8
+ description: string;
9
+ }
10
+ export declare class Sanitizer {
11
+ private sensitiveValues;
12
+ private patterns;
13
+ constructor();
14
+ /**
15
+ * 添加自定义正则模式
16
+ */
17
+ addPattern(pattern: SensitivePattern): void;
18
+ /**
19
+ * 注册敏感值(如密码、私钥路径等)
20
+ * 这些值会被精确匹配并替换
21
+ */
22
+ addSensitiveValue(value: string, minLength?: number): void;
23
+ /**
24
+ * 批量注册敏感值
25
+ */
26
+ addSensitiveValues(values: (string | undefined)[]): void;
27
+ /**
28
+ * 清除所有注册的敏感值(保留模式)
29
+ */
30
+ clearSensitiveValues(): void;
31
+ /**
32
+ * 过滤文本中的敏感信息
33
+ */
34
+ sanitize(text: string): string;
35
+ /**
36
+ * 过滤对象中的敏感信息(递归处理)
37
+ */
38
+ sanitizeObject<T>(obj: T): T;
39
+ }
40
+ export declare function getSanitizer(): Sanitizer;
41
+ /**
42
+ * 便捷函数:过滤文本
43
+ */
44
+ export declare function sanitize(text: string): string;
45
+ /**
46
+ * 便捷函数:过滤对象
47
+ */
48
+ export declare function sanitizeObject<T>(obj: T): T;
@@ -0,0 +1,123 @@
1
+ /**
2
+ * 敏感信息过滤器
3
+ * 用于在 MCP 返回中隐藏 IP、密码等敏感信息
4
+ */
5
+ export class Sanitizer {
6
+ sensitiveValues = new Set();
7
+ patterns = [];
8
+ constructor() {
9
+ // 内置通用模式
10
+ this.addPattern({
11
+ pattern: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g,
12
+ replacement: "[IP]",
13
+ description: "IPv4 地址",
14
+ });
15
+ this.addPattern({
16
+ pattern: /\b([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g,
17
+ replacement: "[IPv6]",
18
+ description: "IPv6 地址",
19
+ });
20
+ this.addPattern({
21
+ pattern: /\b([0-9a-fA-F]{1,4}:){1,7}:\b/g,
22
+ replacement: "[IPv6]",
23
+ description: "IPv6 简写",
24
+ });
25
+ }
26
+ /**
27
+ * 添加自定义正则模式
28
+ */
29
+ addPattern(pattern) {
30
+ this.patterns.push(pattern);
31
+ }
32
+ /**
33
+ * 注册敏感值(如密码、私钥路径等)
34
+ * 这些值会被精确匹配并替换
35
+ */
36
+ addSensitiveValue(value, minLength = 3) {
37
+ if (value && value.length >= minLength) {
38
+ this.sensitiveValues.add(value);
39
+ }
40
+ }
41
+ /**
42
+ * 批量注册敏感值
43
+ */
44
+ addSensitiveValues(values) {
45
+ values.forEach((v) => {
46
+ if (v)
47
+ this.addSensitiveValue(v);
48
+ });
49
+ }
50
+ /**
51
+ * 清除所有注册的敏感值(保留模式)
52
+ */
53
+ clearSensitiveValues() {
54
+ this.sensitiveValues.clear();
55
+ }
56
+ /**
57
+ * 过滤文本中的敏感信息
58
+ */
59
+ sanitize(text) {
60
+ if (!text)
61
+ return text;
62
+ let result = text;
63
+ // 1. 先替换精确匹配的敏感值(按长度降序,避免短串误匹配)
64
+ const sortedValues = Array.from(this.sensitiveValues)
65
+ .filter((v) => v.length >= 3)
66
+ .sort((a, b) => b.length - a.length);
67
+ for (const value of sortedValues) {
68
+ // 转义正则特殊字符
69
+ const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
70
+ const regex = new RegExp(escaped, "g");
71
+ result = result.replace(regex, "[REDACTED]");
72
+ }
73
+ // 2. 应用正则模式
74
+ for (const { pattern, replacement } of this.patterns) {
75
+ // 重置正则状态(因为使用了 /g 标志)
76
+ pattern.lastIndex = 0;
77
+ result = result.replace(pattern, replacement);
78
+ }
79
+ return result;
80
+ }
81
+ /**
82
+ * 过滤对象中的敏感信息(递归处理)
83
+ */
84
+ sanitizeObject(obj) {
85
+ if (obj === null || obj === undefined) {
86
+ return obj;
87
+ }
88
+ if (typeof obj === "string") {
89
+ return this.sanitize(obj);
90
+ }
91
+ if (Array.isArray(obj)) {
92
+ return obj.map((item) => this.sanitizeObject(item));
93
+ }
94
+ if (typeof obj === "object") {
95
+ const result = {};
96
+ for (const [key, value] of Object.entries(obj)) {
97
+ result[key] = this.sanitizeObject(value);
98
+ }
99
+ return result;
100
+ }
101
+ return obj;
102
+ }
103
+ }
104
+ // 全局单例
105
+ let globalSanitizer = null;
106
+ export function getSanitizer() {
107
+ if (!globalSanitizer) {
108
+ globalSanitizer = new Sanitizer();
109
+ }
110
+ return globalSanitizer;
111
+ }
112
+ /**
113
+ * 便捷函数:过滤文本
114
+ */
115
+ export function sanitize(text) {
116
+ return getSanitizer().sanitize(text);
117
+ }
118
+ /**
119
+ * 便捷函数:过滤对象
120
+ */
121
+ export function sanitizeObject(obj) {
122
+ return getSanitizer().sanitizeObject(obj);
123
+ }
@@ -2,25 +2,42 @@ import { Client } from "ssh2";
2
2
  import { ShellResult, ShellConfig } from "./types.js";
3
3
  export declare class ShellManager {
4
4
  private shell;
5
+ private localProcess;
5
6
  private outputBuffer;
6
7
  private outputLines;
7
8
  private lastOutputTime;
8
9
  private config;
10
+ private isLocal;
9
11
  constructor(config?: Partial<ShellConfig>);
10
12
  /**
11
- * 打开 PTY Shell(在 SSH 连接成功后调用)
13
+ * 打开远程 PTY Shell(在 SSH 连接成功后调用)
12
14
  */
13
15
  open(client: Client): Promise<void>;
16
+ /**
17
+ * 打开本地 Shell
18
+ */
19
+ openLocal(): Promise<void>;
20
+ /**
21
+ * 设置 stream 的事件监听
22
+ */
23
+ private setupStream;
14
24
  /**
15
25
  * 检查 shell 是否已打开
16
26
  */
17
27
  isOpen(): boolean;
28
+ /**
29
+ * 是否是本地 shell
30
+ */
31
+ isLocalShell(): boolean;
18
32
  /**
19
33
  * 发送命令,智能等待完成
20
34
  */
21
35
  send(input: string, config?: Partial<ShellConfig>): Promise<ShellResult>;
22
36
  /**
23
37
  * 读取缓冲区内容
38
+ * @param lines 返回行数:不传默认 20 行,-1 返回全部,正整数返回对应行数
39
+ * @param offset 起始偏移,默认 0
40
+ * @param clear 读取后是否清空缓冲区
24
41
  */
25
42
  read(lines?: number, offset?: number, clear?: boolean): ShellResult;
26
43
  /**
@@ -1,3 +1,4 @@
1
+ import { spawn } from "child_process";
1
2
  const DEFAULT_CONFIG = {
2
3
  quickTimeout: 2000,
3
4
  maxTimeout: 5000,
@@ -6,15 +7,17 @@ const DEFAULT_CONFIG = {
6
7
  };
7
8
  export class ShellManager {
8
9
  shell = null;
10
+ localProcess = null;
9
11
  outputBuffer = "";
10
12
  outputLines = [];
11
13
  lastOutputTime = 0;
12
14
  config;
15
+ isLocal = false;
13
16
  constructor(config) {
14
17
  this.config = { ...DEFAULT_CONFIG, ...config };
15
18
  }
16
19
  /**
17
- * 打开 PTY Shell(在 SSH 连接成功后调用)
20
+ * 打开远程 PTY Shell(在 SSH 连接成功后调用)
18
21
  */
19
22
  async open(client) {
20
23
  return new Promise((resolve, reject) => {
@@ -24,31 +27,8 @@ export class ShellManager {
24
27
  return;
25
28
  }
26
29
  this.shell = stream;
27
- this.outputBuffer = "";
28
- this.outputLines = [];
29
- this.lastOutputTime = Date.now();
30
- // 监听数据事件
31
- stream.on("data", (data) => {
32
- const text = data.toString();
33
- this.outputBuffer += text;
34
- this.lastOutputTime = Date.now();
35
- // 按行分割并存储
36
- const lines = this.outputBuffer.split("\n");
37
- // 最后一个可能是不完整的行,保留在 buffer
38
- this.outputBuffer = lines.pop() || "";
39
- this.outputLines.push(...lines);
40
- // 限制缓冲区大小
41
- if (this.outputLines.length > this.config.maxBufferLines) {
42
- this.outputLines = this.outputLines.slice(-this.config.maxBufferLines);
43
- }
44
- });
45
- // 监听关闭事件
46
- stream.on("close", () => {
47
- this.shell = null;
48
- });
49
- stream.on("error", (err) => {
50
- console.error("Shell error:", err.message);
51
- });
30
+ this.isLocal = false;
31
+ this.setupStream(stream);
52
32
  // 等待初始提示符
53
33
  setTimeout(() => {
54
34
  resolve();
@@ -56,12 +36,111 @@ export class ShellManager {
56
36
  });
57
37
  });
58
38
  }
39
+ /**
40
+ * 打开本地 Shell
41
+ */
42
+ async openLocal() {
43
+ return new Promise((resolve, reject) => {
44
+ try {
45
+ // 检测系统默认 shell
46
+ const shellPath = process.env.SHELL || (process.platform === "win32" ? "cmd.exe" : "/bin/sh");
47
+ const proc = spawn(shellPath, [], {
48
+ stdio: ["pipe", "pipe", "pipe"],
49
+ env: { ...process.env, TERM: "xterm-256color" },
50
+ });
51
+ this.localProcess = proc;
52
+ this.isLocal = true;
53
+ // 创建统一的 stream 接口
54
+ const dataListeners = [];
55
+ const closeListeners = [];
56
+ const errorListeners = [];
57
+ proc.stdout?.on("data", (data) => {
58
+ dataListeners.forEach((l) => l(data));
59
+ });
60
+ proc.stderr?.on("data", (data) => {
61
+ dataListeners.forEach((l) => l(data));
62
+ });
63
+ proc.on("close", () => {
64
+ closeListeners.forEach((l) => l());
65
+ });
66
+ proc.on("error", (err) => {
67
+ errorListeners.forEach((l) => l(err));
68
+ });
69
+ const stream = {
70
+ write: (data) => {
71
+ proc.stdin?.write(data);
72
+ },
73
+ end: () => {
74
+ proc.stdin?.end();
75
+ proc.kill();
76
+ },
77
+ on: ((event, listener) => {
78
+ if (event === "data") {
79
+ dataListeners.push(listener);
80
+ }
81
+ else if (event === "close") {
82
+ closeListeners.push(listener);
83
+ }
84
+ else if (event === "error") {
85
+ errorListeners.push(listener);
86
+ }
87
+ }),
88
+ };
89
+ this.shell = stream;
90
+ this.setupStream(stream);
91
+ // 等待初始化
92
+ setTimeout(() => {
93
+ resolve();
94
+ }, 300);
95
+ }
96
+ catch (error) {
97
+ reject(new Error(`无法打开本地 shell: ${error instanceof Error ? error.message : String(error)}`));
98
+ }
99
+ });
100
+ }
101
+ /**
102
+ * 设置 stream 的事件监听
103
+ */
104
+ setupStream(stream) {
105
+ this.outputBuffer = "";
106
+ this.outputLines = [];
107
+ this.lastOutputTime = Date.now();
108
+ // 监听数据事件
109
+ stream.on("data", (data) => {
110
+ const text = data.toString();
111
+ this.outputBuffer += text;
112
+ this.lastOutputTime = Date.now();
113
+ // 按行分割并存储
114
+ const lines = this.outputBuffer.split("\n");
115
+ // 最后一个可能是不完整的行,保留在 buffer
116
+ this.outputBuffer = lines.pop() || "";
117
+ this.outputLines.push(...lines);
118
+ // 限制缓冲区大小
119
+ if (this.outputLines.length > this.config.maxBufferLines) {
120
+ this.outputLines = this.outputLines.slice(-this.config.maxBufferLines);
121
+ }
122
+ });
123
+ // 监听关闭事件
124
+ stream.on("close", () => {
125
+ this.shell = null;
126
+ this.localProcess = null;
127
+ });
128
+ stream.on("error", (err) => {
129
+ console.error("Shell error:", err.message);
130
+ });
131
+ }
59
132
  /**
60
133
  * 检查 shell 是否已打开
61
134
  */
62
135
  isOpen() {
63
136
  return this.shell !== null;
64
137
  }
138
+ /**
139
+ * 是否是本地 shell
140
+ */
141
+ isLocalShell() {
142
+ return this.isLocal;
143
+ }
65
144
  /**
66
145
  * 发送命令,智能等待完成
67
146
  */
@@ -85,14 +164,19 @@ export class ShellManager {
85
164
  }
86
165
  /**
87
166
  * 读取缓冲区内容
167
+ * @param lines 返回行数:不传默认 20 行,-1 返回全部,正整数返回对应行数
168
+ * @param offset 起始偏移,默认 0
169
+ * @param clear 读取后是否清空缓冲区
88
170
  */
89
171
  read(lines, offset, clear) {
90
172
  const startIdx = offset || 0;
91
- const endIdx = lines ? startIdx + lines : this.outputLines.length;
173
+ // 处理 lines 参数:undefined 默认 20,-1 返回全部,其他返回指定行数
174
+ const effectiveLines = lines === undefined ? 20 : (lines === -1 ? undefined : lines);
175
+ const endIdx = effectiveLines ? startIdx + effectiveLines : this.outputLines.length;
92
176
  const selectedLines = this.outputLines.slice(startIdx, endIdx);
93
177
  // 包含不完整的最后一行
94
178
  let output = selectedLines.join("\n");
95
- if (this.outputBuffer && (!lines || endIdx >= this.outputLines.length)) {
179
+ if (this.outputBuffer && (!effectiveLines || endIdx >= this.outputLines.length)) {
96
180
  output += (output ? "\n" : "") + this.outputBuffer;
97
181
  }
98
182
  const result = {
@@ -135,8 +219,13 @@ export class ShellManager {
135
219
  this.shell.end();
136
220
  this.shell = null;
137
221
  }
222
+ if (this.localProcess) {
223
+ this.localProcess.kill();
224
+ this.localProcess = null;
225
+ }
138
226
  this.outputLines = [];
139
227
  this.outputBuffer = "";
228
+ this.isLocal = false;
140
229
  }
141
230
  /**
142
231
  * 获取当前缓冲区行数
@@ -1,15 +1,34 @@
1
1
  import { ServerConfig, ConnectionStatus } from "./types.js";
2
2
  import { ShellManager } from "./shell-manager.js";
3
+ export declare const LOCAL_SERVER: ServerConfig;
3
4
  export declare class SSHManager {
4
5
  private client;
5
6
  private currentServer;
6
7
  private isConnected;
7
8
  private shellManager;
9
+ private isLocalConnection;
8
10
  constructor();
9
11
  private expandPath;
12
+ /**
13
+ * 检查是否是本地连接
14
+ */
15
+ static isLocalServer(config: ServerConfig): boolean;
10
16
  connect(config: ServerConfig): Promise<void>;
17
+ /**
18
+ * 本地连接
19
+ */
20
+ private connectLocal;
21
+ /**
22
+ * SSH 远程连接
23
+ */
24
+ private connectSSH;
11
25
  disconnect(): Promise<void>;
12
26
  private cleanup;
27
+ /**
28
+ * 注册服务器配置中的敏感信息
29
+ */
30
+ private registerSensitiveInfo;
13
31
  getShellManager(): ShellManager;
32
+ isLocal(): boolean;
14
33
  getStatus(): ConnectionStatus;
15
34
  }