@pyrokine/mcp-ssh 1.1.0 → 1.1.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/README.md CHANGED
@@ -19,16 +19,16 @@ A comprehensive SSH MCP Server for AI assistants (Claude, Cursor, Windsurf, etc.
19
19
  - **Connection Management**: Connection pooling, keepalive, auto-reconnect
20
20
  - **Session Persistence**: Sessions info saved for reconnection
21
21
  - **Command Execution**:
22
- - Basic exec with timeout
23
- - PTY mode (for interactive commands like `top`, `htop`)
24
- - `sudo` execution
25
- - `su` (switch user) execution - *run commands as different user*
26
- - Batch execution
27
- - Parallel execution on multiple hosts
22
+ - Basic exec with timeout
23
+ - PTY mode (for interactive commands like `top`, `htop`)
24
+ - `sudo` execution
25
+ - `su` (switch user) execution - *run commands as different user*
26
+ - Batch execution
27
+ - Parallel execution on multiple hosts
28
28
  - **Persistent PTY Sessions**: For long-running interactive commands (top, htop, tmux, vim, etc.)
29
- - Output buffering with polling read
30
- - Send keystrokes and commands
31
- - Window resize support
29
+ - Output buffering with polling read
30
+ - Send keystrokes and commands
31
+ - Window resize support
32
32
  - **File Operations**: Upload, download, read, write, list directory (via SFTP)
33
33
  - **Smart Sync**: Directory sync with rsync (auto-fallback to SFTP if rsync unavailable)
34
34
  - **Environment Configuration**: LANG, LC_ALL, custom env vars
@@ -36,15 +36,15 @@ A comprehensive SSH MCP Server for AI assistants (Claude, Cursor, Windsurf, etc.
36
36
 
37
37
  ## Compatible Clients
38
38
 
39
- | Client | Status |
40
- |--------|--------|
41
- | Claude Code | ✅ |
42
- | Claude Desktop | ✅ |
43
- | Cursor | ✅ |
44
- | Windsurf | ✅ |
45
- | Continue.dev | ✅ |
46
- | Cline | ✅ |
47
- | Any MCP-compatible client | ✅ |
39
+ | Client | Status |
40
+ |---------------------------|--------|
41
+ | Claude Code | ✅ |
42
+ | Claude Desktop | ✅ |
43
+ | Cursor | ✅ |
44
+ | Windsurf | ✅ |
45
+ | Continue.dev | ✅ |
46
+ | Cline | ✅ |
47
+ | Any MCP-compatible client | ✅ |
48
48
 
49
49
  ## Installation
50
50
 
@@ -90,57 +90,57 @@ Add to your MCP settings (e.g., `~/.claude/settings.json` or client-specific con
90
90
 
91
91
  ### Connection Management
92
92
 
93
- | Tool | Description |
94
- |------|-------------|
95
- | `ssh_connect` | Establish SSH connection (supports ~/.ssh/config) |
96
- | `ssh_disconnect` | Close connection |
97
- | `ssh_list_sessions` | List active sessions |
98
- | `ssh_reconnect` | Reconnect a disconnected session |
99
- | `ssh_config_list` | List hosts from ~/.ssh/config |
93
+ | Tool | Description |
94
+ |---------------------|---------------------------------------------------|
95
+ | `ssh_connect` | Establish SSH connection (supports ~/.ssh/config) |
96
+ | `ssh_disconnect` | Close connection |
97
+ | `ssh_list_sessions` | List active sessions |
98
+ | `ssh_reconnect` | Reconnect a disconnected session |
99
+ | `ssh_config_list` | List hosts from ~/.ssh/config |
100
100
 
101
101
  ### Command Execution
102
102
 
103
- | Tool | Description |
104
- |------|-------------|
105
- | `ssh_exec` | Execute command (supports PTY mode) |
106
- | `ssh_exec_as_user` | Execute as different user (via `su`) |
107
- | `ssh_exec_sudo` | Execute with `sudo` |
108
- | `ssh_exec_batch` | Execute multiple commands sequentially |
103
+ | Tool | Description |
104
+ |---------------------|-----------------------------------------------|
105
+ | `ssh_exec` | Execute command (supports PTY mode) |
106
+ | `ssh_exec_as_user` | Execute as different user (via `su`) |
107
+ | `ssh_exec_sudo` | Execute with `sudo` |
108
+ | `ssh_exec_batch` | Execute multiple commands sequentially |
109
109
  | `ssh_exec_parallel` | Execute command on multiple hosts in parallel |
110
- | `ssh_quick_exec` | One-shot: connect, execute, disconnect |
110
+ | `ssh_quick_exec` | One-shot: connect, execute, disconnect |
111
111
 
112
112
  ### File Operations
113
113
 
114
- | Tool | Description |
115
- |------|-------------|
116
- | `ssh_upload` | Upload local file to remote server |
117
- | `ssh_download` | Download remote file to local |
118
- | `ssh_read_file` | Read remote file content |
119
- | `ssh_write_file` | Write content to remote file |
120
- | `ssh_list_dir` | List remote directory contents |
121
- | `ssh_file_info` | Get file/directory metadata |
122
- | `ssh_mkdir` | Create remote directory |
123
- | `ssh_sync` | Smart sync with rsync (fallback to SFTP) |
114
+ | Tool | Description |
115
+ |------------------|------------------------------------------|
116
+ | `ssh_upload` | Upload local file to remote server |
117
+ | `ssh_download` | Download remote file to local |
118
+ | `ssh_read_file` | Read remote file content |
119
+ | `ssh_write_file` | Write content to remote file |
120
+ | `ssh_list_dir` | List remote directory contents |
121
+ | `ssh_file_info` | Get file/directory metadata |
122
+ | `ssh_mkdir` | Create remote directory |
123
+ | `ssh_sync` | Smart sync with rsync (fallback to SFTP) |
124
124
 
125
125
  ### PTY Sessions (Persistent Interactive Terminal)
126
126
 
127
- | Tool | Description |
128
- |------|-------------|
129
- | `ssh_pty_start` | Start persistent PTY session (for top, htop, tmux, etc.) |
130
- | `ssh_pty_write` | Send data to PTY (keystrokes, commands) |
131
- | `ssh_pty_read` | Read PTY output (screen mode: current screen, raw mode: ANSI stream) |
132
- | `ssh_pty_resize` | Resize PTY window |
133
- | `ssh_pty_close` | Close PTY session |
134
- | `ssh_pty_list` | List all PTY sessions |
127
+ | Tool | Description |
128
+ |------------------|----------------------------------------------------------------------|
129
+ | `ssh_pty_start` | Start persistent PTY session (for top, htop, tmux, etc.) |
130
+ | `ssh_pty_write` | Send data to PTY (keystrokes, commands) |
131
+ | `ssh_pty_read` | Read PTY output (screen mode: current screen, raw mode: ANSI stream) |
132
+ | `ssh_pty_resize` | Resize PTY window |
133
+ | `ssh_pty_close` | Close PTY session |
134
+ | `ssh_pty_list` | List all PTY sessions |
135
135
 
136
136
  ### Port Forwarding
137
137
 
138
- | Tool | Description |
139
- |------|-------------|
140
- | `ssh_forward_local` | Local port forwarding (ssh -L): access remote services |
138
+ | Tool | Description |
139
+ |----------------------|--------------------------------------------------------|
140
+ | `ssh_forward_local` | Local port forwarding (ssh -L): access remote services |
141
141
  | `ssh_forward_remote` | Remote port forwarding (ssh -R): expose local services |
142
- | `ssh_forward_close` | Close port forwarding |
143
- | `ssh_forward_list` | List all port forwards |
142
+ | `ssh_forward_close` | Close port forwarding |
143
+ | `ssh_forward_list` | List all port forwards |
144
144
 
145
145
  ## Usage Examples
146
146
 
@@ -161,6 +161,7 @@ ssh_connect(configHost="myserver", configPath="/custom/path/config")
161
161
  ```
162
162
 
163
163
  Supported SSH config features:
164
+
164
165
  - `Host` with multiple aliases (e.g., `Host a b c`)
165
166
  - `Host *` global defaults inheritance (first `Host *` block only)
166
167
  - `HostName`, `User`, `Port`, `IdentityFile`
@@ -168,11 +169,13 @@ Supported SSH config features:
168
169
  - Explicit parameters override config values (e.g., `ssh_connect(configHost="x", user="override")`)
169
170
 
170
171
  **Not supported** (skipped):
172
+
171
173
  - `Include` directive
172
174
  - `Match` blocks (entire block skipped until next `Host`)
173
175
  - Wildcard patterns (e.g., `Host *.example.com`)
174
176
 
175
177
  **Behavior notes**:
178
+
176
179
  - Multiple `Host *` blocks: only first is used
177
180
  - Duplicate Host definitions: `ssh_config_list` shows all, `ssh_connect` uses first
178
181
  - IPv6 in ProxyJump: use bracket notation `[2001:db8::1]:22`
@@ -224,6 +227,10 @@ Perfect for scenarios where you SSH as root but need to run commands as another
224
227
  // Output: appuser
225
228
  ```
226
229
 
230
+ By default, shell profile is loaded to ensure environment variables are available (since `su -c` creates a
231
+ non-interactive shell which doesn't execute rc files). Supports bash (`.bashrc`), zsh (`.zshrc`), and other shells (
232
+ `.profile`). Disable with `loadProfile=false` if not needed.
233
+
227
234
  ### Interactive Commands (PTY mode)
228
235
 
229
236
  For commands that need a terminal:
@@ -306,7 +313,8 @@ ssh_sync(..., dryRun=true)
306
313
 
307
314
  If rsync is not available on remote or local, it automatically falls back to SFTP.
308
315
 
309
- **Note**: rsync mode uses SSH key/agent authentication and disables strict host key checking (`StrictHostKeyChecking=no`) for convenience. If you require host key verification, use SFTP mode instead.
316
+ **Note**: rsync mode uses SSH key/agent authentication and disables strict host key checking (
317
+ `StrictHostKeyChecking=no`) for convenience. If you require host key verification, use SFTP mode instead.
310
318
 
311
319
  ### Persistent PTY Sessions (top, tmux, etc.)
312
320
 
@@ -345,6 +353,7 @@ ssh_pty_write(ptyId="pty_1_xxx", data="\x02d")
345
353
  ```
346
354
 
347
355
  Common control sequences:
356
+
348
357
  - Enter: `\r` or `\n`
349
358
  - Ctrl+C: `\x03`
350
359
  - Ctrl+D: `\x04`
@@ -374,25 +383,25 @@ ssh_forward_close(forwardId="fwd_1_xxx")
374
383
 
375
384
  ### Connection Options
376
385
 
377
- | Option | Type | Default | Description |
378
- |--------|------|---------|-------------|
379
- | `host` | string | *required* | Server address |
380
- | `user` | string | *required* | Username |
381
- | `password` | string | - | Password authentication |
382
- | `keyPath` | string | - | Path to SSH private key |
383
- | `port` | number | 22 | SSH port |
384
- | `alias` | string | auto-generated | Connection alias for reference |
385
- | `env` | object | - | Environment variables |
386
- | `keepaliveInterval` | number | 30000 | Keepalive interval in ms |
386
+ | Option | Type | Default | Description |
387
+ |---------------------|--------|----------------|--------------------------------|
388
+ | `host` | string | *required* | Server address |
389
+ | `user` | string | *required* | Username |
390
+ | `password` | string | - | Password authentication |
391
+ | `keyPath` | string | - | Path to SSH private key |
392
+ | `port` | number | 22 | SSH port |
393
+ | `alias` | string | auto-generated | Connection alias for reference |
394
+ | `env` | object | - | Environment variables |
395
+ | `keepaliveInterval` | number | 30000 | Keepalive interval in ms |
387
396
 
388
397
  ### Exec Options
389
398
 
390
- | Option | Type | Default | Description |
391
- |--------|------|---------|-------------|
392
- | `timeout` | number | 30000 | Command timeout in ms |
393
- | `cwd` | string | - | Working directory |
394
- | `env` | object | - | Additional environment variables |
395
- | `pty` | boolean | false | Enable PTY mode for interactive commands |
399
+ | Option | Type | Default | Description |
400
+ |-----------|---------|---------|------------------------------------------|
401
+ | `timeout` | number | 30000 | Command timeout in ms |
402
+ | `cwd` | string | - | Working directory |
403
+ | `env` | object | - | Additional environment variables |
404
+ | `pty` | boolean | false | Enable PTY mode for interactive commands |
396
405
 
397
406
  ## Project Structure
398
407
 
package/README_zh.md CHANGED
@@ -19,16 +19,16 @@
19
19
  - **连接管理**:连接池复用、心跳保持、自动重连
20
20
  - **会话持久化**:会话信息保存,支持重连
21
21
  - **命令执行**:
22
- - 基础执行(带超时)
23
- - PTY 模式(用于 `top`、`htop` 等交互式命令)
24
- - `sudo` 执行
25
- - `su` 切换用户执行
26
- - 批量执行
27
- - 多主机并行执行
22
+ - 基础执行(带超时)
23
+ - PTY 模式(用于 `top`、`htop` 等交互式命令)
24
+ - `sudo` 执行
25
+ - `su` 切换用户执行
26
+ - 批量执行
27
+ - 多主机并行执行
28
28
  - **持久化 PTY 会话**:用于长时间运行的交互式命令(top、htop、tmux、vim 等)
29
- - 输出缓冲区,支持轮询读取
30
- - 发送按键和命令
31
- - 窗口大小调整
29
+ - 输出缓冲区,支持轮询读取
30
+ - 发送按键和命令
31
+ - 窗口大小调整
32
32
  - **文件操作**:上传、下载、读取、写入、目录列表(通过 SFTP)
33
33
  - **智能同步**:目录同步,优先使用 rsync(无 rsync 时自动回退到 SFTP)
34
34
  - **环境配置**:LANG、LC_ALL、自定义环境变量
@@ -36,15 +36,15 @@
36
36
 
37
37
  ## 兼容客户端
38
38
 
39
- | 客户端 | 状态 |
40
- |--------|------|
41
- | Claude Code | ✅ |
42
- | Claude Desktop | ✅ |
43
- | Cursor | ✅ |
44
- | Windsurf | ✅ |
45
- | Continue.dev | ✅ |
46
- | Cline | ✅ |
47
- | 其他 MCP 兼容客户端 | ✅ |
39
+ | 客户端 | 状态 |
40
+ |----------------|----|
41
+ | Claude Code | ✅ |
42
+ | Claude Desktop | ✅ |
43
+ | Cursor | ✅ |
44
+ | Windsurf | ✅ |
45
+ | Continue.dev | ✅ |
46
+ | Cline | ✅ |
47
+ | 其他 MCP 兼容客户端 | ✅ |
48
48
 
49
49
  ## 安装
50
50
 
@@ -90,57 +90,57 @@ claude mcp add ssh -- node /path/to/mcp-ssh/dist/index.js
90
90
 
91
91
  ### 连接管理
92
92
 
93
- | 工具 | 描述 |
94
- |------|------|
95
- | `ssh_connect` | 建立 SSH 连接(支持 ~/.ssh/config) |
96
- | `ssh_disconnect` | 关闭连接 |
97
- | `ssh_list_sessions` | 列出活跃会话 |
98
- | `ssh_reconnect` | 重新连接断开的会话 |
99
- | `ssh_config_list` | 列出 ~/.ssh/config 中的 Host |
93
+ | 工具 | 描述 |
94
+ |---------------------|-----------------------------|
95
+ | `ssh_connect` | 建立 SSH 连接(支持 ~/.ssh/config) |
96
+ | `ssh_disconnect` | 关闭连接 |
97
+ | `ssh_list_sessions` | 列出活跃会话 |
98
+ | `ssh_reconnect` | 重新连接断开的会话 |
99
+ | `ssh_config_list` | 列出 ~/.ssh/config 中的 Host |
100
100
 
101
101
  ### 命令执行
102
102
 
103
- | 工具 | 描述 |
104
- |------|------|
105
- | `ssh_exec` | 执行命令(支持 PTY 模式) |
106
- | `ssh_exec_as_user` | 以其他用户身份执行(通过 `su`) |
107
- | `ssh_exec_sudo` | 使用 `sudo` 执行 |
108
- | `ssh_exec_batch` | 批量执行多条命令 |
109
- | `ssh_exec_parallel` | 在多台主机上并行执行命令 |
110
- | `ssh_quick_exec` | 一次性执行:连接、执行、断开 |
103
+ | 工具 | 描述 |
104
+ |---------------------|--------------------|
105
+ | `ssh_exec` | 执行命令(支持 PTY 模式) |
106
+ | `ssh_exec_as_user` | 以其他用户身份执行(通过 `su`) |
107
+ | `ssh_exec_sudo` | 使用 `sudo` 执行 |
108
+ | `ssh_exec_batch` | 批量执行多条命令 |
109
+ | `ssh_exec_parallel` | 在多台主机上并行执行命令 |
110
+ | `ssh_quick_exec` | 一次性执行:连接、执行、断开 |
111
111
 
112
112
  ### 文件操作
113
113
 
114
- | 工具 | 描述 |
115
- |------|------|
116
- | `ssh_upload` | 上传本地文件到远程 |
117
- | `ssh_download` | 从远程下载文件到本地 |
118
- | `ssh_read_file` | 读取远程文件内容 |
119
- | `ssh_write_file` | 写入内容到远程文件 |
120
- | `ssh_list_dir` | 列出远程目录内容 |
121
- | `ssh_file_info` | 获取文件/目录元数据 |
122
- | `ssh_mkdir` | 创建远程目录 |
123
- | `ssh_sync` | 智能同步(优先 rsync,回退 SFTP) |
114
+ | 工具 | 描述 |
115
+ |------------------|------------------------|
116
+ | `ssh_upload` | 上传本地文件到远程 |
117
+ | `ssh_download` | 从远程下载文件到本地 |
118
+ | `ssh_read_file` | 读取远程文件内容 |
119
+ | `ssh_write_file` | 写入内容到远程文件 |
120
+ | `ssh_list_dir` | 列出远程目录内容 |
121
+ | `ssh_file_info` | 获取文件/目录元数据 |
122
+ | `ssh_mkdir` | 创建远程目录 |
123
+ | `ssh_sync` | 智能同步(优先 rsync,回退 SFTP) |
124
124
 
125
125
  ### PTY 会话(持久化交互式终端)
126
126
 
127
- | 工具 | 描述 |
128
- |------|------|
129
- | `ssh_pty_start` | 启动持久化 PTY 会话(用于 top、htop、tmux 等) |
130
- | `ssh_pty_write` | 向 PTY 发送数据(按键、命令) |
131
- | `ssh_pty_read` | 读取 PTY 输出(screen 模式:当前屏幕,raw 模式:ANSI 流) |
132
- | `ssh_pty_resize` | 调整 PTY 窗口大小 |
133
- | `ssh_pty_close` | 关闭 PTY 会话 |
134
- | `ssh_pty_list` | 列出所有 PTY 会话 |
127
+ | 工具 | 描述 |
128
+ |------------------|-----------------------------------------|
129
+ | `ssh_pty_start` | 启动持久化 PTY 会话(用于 top、htop、tmux 等) |
130
+ | `ssh_pty_write` | 向 PTY 发送数据(按键、命令) |
131
+ | `ssh_pty_read` | 读取 PTY 输出(screen 模式:当前屏幕,raw 模式:ANSI 流) |
132
+ | `ssh_pty_resize` | 调整 PTY 窗口大小 |
133
+ | `ssh_pty_close` | 关闭 PTY 会话 |
134
+ | `ssh_pty_list` | 列出所有 PTY 会话 |
135
135
 
136
136
  ### 端口转发
137
137
 
138
- | 工具 | 描述 |
139
- |------|------|
140
- | `ssh_forward_local` | 本地端口转发(ssh -L):访问远程服务 |
138
+ | 工具 | 描述 |
139
+ |----------------------|-----------------------|
140
+ | `ssh_forward_local` | 本地端口转发(ssh -L):访问远程服务 |
141
141
  | `ssh_forward_remote` | 远程端口转发(ssh -R):暴露本地服务 |
142
- | `ssh_forward_close` | 关闭端口转发 |
143
- | `ssh_forward_list` | 列出所有端口转发 |
142
+ | `ssh_forward_close` | 关闭端口转发 |
143
+ | `ssh_forward_list` | 列出所有端口转发 |
144
144
 
145
145
  ## 使用示例
146
146
 
@@ -161,6 +161,7 @@ ssh_connect(configHost="myserver", configPath="/custom/path/config")
161
161
  ```
162
162
 
163
163
  支持的 SSH config 特性:
164
+
164
165
  - `Host` 多别名(如 `Host a b c`)
165
166
  - `Host *` 全局默认继承(仅第一个 `Host *` 块)
166
167
  - `HostName`、`User`、`Port`、`IdentityFile`
@@ -168,11 +169,13 @@ ssh_connect(configHost="myserver", configPath="/custom/path/config")
168
169
  - 显式参数优先于 config 值(如 `ssh_connect(configHost="x", user="覆盖值")`)
169
170
 
170
171
  **不支持**(跳过):
172
+
171
173
  - `Include` 指令
172
174
  - `Match` 块(整个块跳过直到下一个 `Host`)
173
175
  - 通配符模式(如 `Host *.example.com`)
174
176
 
175
177
  **行为说明**:
178
+
176
179
  - 多个 `Host *` 块:仅使用第一个
177
180
  - 重复的 Host 定义:`ssh_config_list` 显示全部,`ssh_connect` 使用第一个
178
181
  - ProxyJump 中的 IPv6:使用方括号格式 `[2001:db8::1]:22`
@@ -224,6 +227,9 @@ ssh_connect(
224
227
  // 输出: appuser
225
228
  ```
226
229
 
230
+ 默认加载 shell 配置以确保环境变量可用(`su -c` 创建非交互式 shell,不会自动执行 rc 文件)。支持 bash(`.bashrc`)、zsh(`.zshrc`
231
+ )及其他 shell(`.profile`)。如不需要可设置 `loadProfile=false`。
232
+
227
233
  ### 交互式命令(PTY 模式)
228
234
 
229
235
  用于需要终端的命令:
@@ -306,7 +312,8 @@ ssh_sync(..., dryRun=true)
306
312
 
307
313
  如果远程或本地没有 rsync,会自动回退到 SFTP。
308
314
 
309
- **注意**:rsync 模式使用 SSH 密钥/代理认证,并禁用严格主机密钥检查(`StrictHostKeyChecking=no`)以方便使用。如需主机密钥验证,请使用 SFTP 模式。
315
+ **注意**:rsync 模式使用 SSH 密钥/代理认证,并禁用严格主机密钥检查(`StrictHostKeyChecking=no`)以方便使用。如需主机密钥验证,请使用
316
+ SFTP 模式。
310
317
 
311
318
  ### 持久化 PTY 会话(top、tmux 等)
312
319
 
@@ -345,6 +352,7 @@ ssh_pty_write(ptyId="pty_1_xxx", data="\x02d")
345
352
  ```
346
353
 
347
354
  常用控制序列:
355
+
348
356
  - 回车: `\r` 或 `\n`
349
357
  - Ctrl+C: `\x03`
350
358
  - Ctrl+D: `\x04`
@@ -374,25 +382,25 @@ ssh_forward_close(forwardId="fwd_1_xxx")
374
382
 
375
383
  ### 连接选项
376
384
 
377
- | 选项 | 类型 | 默认值 | 描述 |
378
- |------|------|--------|------|
379
- | `host` | string | *必需* | 服务器地址 |
380
- | `user` | string | *必需* | 用户名 |
381
- | `password` | string | - | 密码认证 |
382
- | `keyPath` | string | - | SSH 私钥路径 |
383
- | `port` | number | 22 | SSH 端口 |
384
- | `alias` | string | 自动生成 | 连接别名,用于后续引用 |
385
- | `env` | object | - | 环境变量 |
386
- | `keepaliveInterval` | number | 30000 | 心跳间隔(毫秒) |
385
+ | 选项 | 类型 | 默认值 | 描述 |
386
+ |---------------------|--------|-------|-------------|
387
+ | `host` | string | *必需* | 服务器地址 |
388
+ | `user` | string | *必需* | 用户名 |
389
+ | `password` | string | - | 密码认证 |
390
+ | `keyPath` | string | - | SSH 私钥路径 |
391
+ | `port` | number | 22 | SSH 端口 |
392
+ | `alias` | string | 自动生成 | 连接别名,用于后续引用 |
393
+ | `env` | object | - | 环境变量 |
394
+ | `keepaliveInterval` | number | 30000 | 心跳间隔(毫秒) |
387
395
 
388
396
  ### 执行选项
389
397
 
390
- | 选项 | 类型 | 默认值 | 描述 |
391
- |------|------|--------|------|
392
- | `timeout` | number | 30000 | 命令超时(毫秒) |
393
- | `cwd` | string | - | 工作目录 |
394
- | `env` | object | - | 额外环境变量 |
395
- | `pty` | boolean | false | 启用 PTY 模式(用于交互式命令) |
398
+ | 选项 | 类型 | 默认值 | 描述 |
399
+ |-----------|---------|-------|--------------------|
400
+ | `timeout` | number | 30000 | 命令超时(毫秒) |
401
+ | `cwd` | string | - | 工作目录 |
402
+ | `env` | object | - | 额外环境变量 |
403
+ | `pty` | boolean | false | 启用 PTY 模式(用于交互式命令) |
396
404
 
397
405
  ## 项目结构
398
406
 
package/dist/file-ops.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * SSH File Operations - 文件操作
3
3
  */
4
+ import { execSync } from 'child_process';
4
5
  import * as fs from 'fs';
5
6
  import * as path from 'path';
6
- import { execSync } from 'child_process';
7
7
  import { sessionManager } from './session-manager.js';
8
8
  /**
9
9
  * 上传文件
@@ -20,12 +20,14 @@ export async function uploadFile(alias, localPath, remotePath, onProgress) {
20
20
  const writeStream = sftp.createWriteStream(remotePath);
21
21
  let settled = false;
22
22
  const cleanup = (err) => {
23
- if (settled)
23
+ if (settled) {
24
24
  return;
25
+ }
25
26
  settled = true;
26
27
  sftp.end();
27
- if (err)
28
+ if (err) {
28
29
  reject(err);
30
+ }
29
31
  };
30
32
  let transferred = 0;
31
33
  readStream.on('data', (chunk) => {
@@ -58,10 +60,12 @@ export async function downloadFile(alias, remotePath, localPath, onProgress) {
58
60
  // 获取远程文件大小
59
61
  const stats = await new Promise((resolve, reject) => {
60
62
  sftp.stat(remotePath, (err, stats) => {
61
- if (err)
63
+ if (err) {
62
64
  reject(err);
63
- else
65
+ }
66
+ else {
64
67
  resolve(stats);
68
+ }
65
69
  });
66
70
  });
67
71
  const totalSize = stats.size;
@@ -75,12 +79,14 @@ export async function downloadFile(alias, remotePath, localPath, onProgress) {
75
79
  const writeStream = fs.createWriteStream(localPath);
76
80
  let settled = false;
77
81
  const cleanup = (err) => {
78
- if (settled)
82
+ if (settled) {
79
83
  return;
84
+ }
80
85
  settled = true;
81
86
  sftp.end();
82
- if (err)
87
+ if (err) {
83
88
  reject(err);
89
+ }
84
90
  };
85
91
  let transferred = 0;
86
92
  readStream.on('data', (chunk) => {
@@ -108,16 +114,17 @@ export async function downloadFile(alias, remotePath, localPath, onProgress) {
108
114
  /**
109
115
  * 读取远程文件内容
110
116
  */
111
- export async function readFile(alias, remotePath, maxBytes = 1024 * 1024 // 默认最大 1MB
112
- ) {
117
+ export async function readFile(alias, remotePath, maxBytes = 1024 * 1024) {
113
118
  const sftp = await sessionManager.getSftp(alias);
114
119
  // 获取文件大小
115
120
  const stats = await new Promise((resolve, reject) => {
116
121
  sftp.stat(remotePath, (err, stats) => {
117
- if (err)
122
+ if (err) {
118
123
  reject(err);
119
- else
124
+ }
125
+ else {
120
126
  resolve(stats);
127
+ }
121
128
  });
122
129
  });
123
130
  const actualSize = stats.size;
@@ -264,10 +271,12 @@ export async function mkdir(alias, remotePath, recursive = false) {
264
271
  return new Promise((resolve, reject) => {
265
272
  sftp.mkdir(remotePath, (err) => {
266
273
  sftp.end();
267
- if (err)
274
+ if (err) {
268
275
  reject(err);
269
- else
276
+ }
277
+ else {
270
278
  resolve(true);
279
+ }
271
280
  });
272
281
  });
273
282
  }
@@ -279,10 +288,12 @@ export async function removeFile(alias, remotePath) {
279
288
  return new Promise((resolve, reject) => {
280
289
  sftp.unlink(remotePath, (err) => {
281
290
  sftp.end();
282
- if (err)
291
+ if (err) {
283
292
  reject(err);
284
- else
293
+ }
294
+ else {
285
295
  resolve(true);
296
+ }
286
297
  });
287
298
  });
288
299
  }
@@ -323,7 +334,7 @@ export async function syncFiles(alias, localPath, remotePath, direction, options
323
334
  * 转义 shell 路径参数
324
335
  */
325
336
  function escapeShellPath(p) {
326
- return `'${p.replace(/'/g, "'\\''")}'`;
337
+ return `'${p.replace(/'/g, '\'\\\'\'')}'`;
327
338
  }
328
339
  /**
329
340
  * 使用 rsync 同步文件
@@ -336,7 +347,8 @@ async function syncWithRsync(alias, localPath, remotePath, direction, options) {
336
347
  execSync('which rsync', { stdio: 'pipe' });
337
348
  hasLocalRsync = true;
338
349
  }
339
- catch { }
350
+ catch {
351
+ }
340
352
  if (!hasLocalRsync) {
341
353
  // 本地没有 rsync,回退到 SFTP
342
354
  return syncWithSftp(alias, localPath, remotePath, direction, options);
@@ -374,13 +386,16 @@ async function syncWithRsync(alias, localPath, remotePath, direction, options) {
374
386
  const result = execSync(rsyncCmd, {
375
387
  encoding: 'utf-8',
376
388
  timeout: 600000, // 10 分钟超时
377
- stdio: ['pipe', 'pipe', 'pipe']
389
+ stdio: ['pipe', 'pipe', 'pipe'],
378
390
  });
379
391
  // 解析 rsync 输出统计文件数
380
392
  const lines = result.split('\n');
381
393
  let filesTransferred = 0;
382
394
  for (const line of lines) {
383
- if (line.trim() && !line.startsWith('sending') && !line.startsWith('receiving') && !line.startsWith('total')) {
395
+ if (line.trim() &&
396
+ !line.startsWith('sending') &&
397
+ !line.startsWith('receiving') &&
398
+ !line.startsWith('total')) {
384
399
  filesTransferred++;
385
400
  }
386
401
  }
@@ -409,7 +424,8 @@ async function syncWithSftp(alias, localPath, remotePath, direction, options) {
409
424
  return {
410
425
  success: true,
411
426
  method: 'sftp',
412
- output: 'Dry run mode: would transfer files via SFTP' + (warnings.length ? `. Warning: ${warnings.join('; ')}` : ''),
427
+ output: 'Dry run mode: would transfer files via SFTP' +
428
+ (warnings.length ? `. Warning: ${warnings.join('; ')}` : ''),
413
429
  };
414
430
  }
415
431
  try {