@zhangfengshun/dsh-remote-ssh 2.3.5 → 2.3.7
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/CHANGELOG.md +12 -0
- package/README.md +22 -3
- package/README_EN.md +22 -3
- package/lib/index.js +43 -10
- package/package.json +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
本文件的版本号与 `package.json` 的 `version` 保持一致。每个版本对应一个 Cordis Package 快照(`pkg-N`)。
|
|
4
4
|
|
|
5
|
+
## [2.3.7] — Windows host 连接诊断增强:过滤 PQ 警告、ssh -v 诊断、跨平台测试探测
|
|
6
|
+
### 修复
|
|
7
|
+
- **过滤 OpenSSH「后量子 KEX」警告横幅**:新版本客户端对非 PQ 加密的 stderr 警告(三行 `** WARNING…`)与认证成败无关,此前混入错误信息会误导用户以为是不支持加密算法;现在统一过滤(错误提示、一次性连接 stderr、持久会话关闭诊断)。
|
|
8
|
+
- **测试连接探测命令改为跨平台 `echo __DSH_OK__`**:旧命令尾部 `uname -a`/`pwd` 在 Windows host(cmd/PowerShell)上必然报错,导致**认证成功的 Windows host 也误报失败**。
|
|
9
|
+
- **认证失败自动带 ssh -v 诊断**:测试连接认证失败时重跑一次 `ssh -v` 握手,抽取关键诊断行(私钥加载 / 公钥提供 / 服务器拒绝方法 / 口令要求)附在错误信息里,用户一眼定位失败环节。
|
|
10
|
+
- **公钥失败提示覆盖 Windows 三大圈套**:① 私钥带口令 + 批处理模式无法交互输入(先 ssh-add 或去口令);② Windows host 且用户在 Administrators 组时公钥须写入 `C:\ProgramData\ssh\administrators_authorized_keys`;③ 用户名写法(`user` / `.\user` / `user@domain`)须与手动连接一致。
|
|
11
|
+
|
|
12
|
+
## [2.3.6] — settings 注册迁移至字符串命名空间,移除 legacy 导出依赖
|
|
13
|
+
### 变更
|
|
14
|
+
- **不再从 `@deepseek-ai/dsh-settings` 导入 `settingsNamespace`**:该导出在 dsh-settings 中被标注为 legacy(仅为 alpha.2 之前的插件保留,未来版本可能移除)。`parseSettingsNamespace` 实为恒等函数(校验 `/^[a-z][a-z0-9-]*$/` 后原样返回),故 `register(NS, schema)` 与原 `register(settingsNamespace(NS), schema)` 存储键完全一致——零数据迁移,老用户配置无缝保留。
|
|
15
|
+
- **peerDependencies 移除 `@deepseek-ai/dsh-settings`**(已无导入;`ctx.settings` 能力由 DSH 内核的 settings 服务提供,与该 npm 包导入无关),安装时少一条未解析 peer 警告。
|
|
16
|
+
|
|
5
17
|
## [2.3.5] — 地球角标样式重制:右下角、默认文件夹形状、透明底白经纬线
|
|
6
18
|
### 变更
|
|
7
19
|
- **文件夹形状与默认完全一致**:不再自绘/改写文件夹几何,壳层 IconFolderOpen16/Close16 的原始路径与几何零改写,仅向工作区行首槽位 svg **追加**一个透明地球经纬线组(appendChild 不触碰 React 管理的子节点,零对账风险)。
|
package/README.md
CHANGED
|
@@ -13,14 +13,31 @@
|
|
|
13
13
|
| 💻 远程终端 | 内置「终端」页签自动检测远程工作区,SSH 交互式终端 |
|
|
14
14
|
| 🌐 远程工作区 | 选择远程目录创建原生工作区,一键进入远程环境 |
|
|
15
15
|
| 🤖 模型工具 | 12 个 `remote_ssh_*` 工具,会话感知免填连接参数 |
|
|
16
|
+
| ⚡ 打开提速 | 单往返合并读 + raw 文本快路径 + 结果缓存(LRU + 5s TTL):首开 ≈**1.31×**,TTL 内重复打开 **0 往返**,过期复验 **≈5×**(真实超算实测);`remote_ssh_exec` 连接复用 **≈15×** |
|
|
17
|
+
|
|
18
|
+
## 截图
|
|
19
|
+
|
|
20
|
+
**设置 → 🖥️ 远程连接**:连接配置(密钥 / 密码 / ProxyJump 跳板机)· 连接测试 · 从 `~/.ssh/config` 一键导入
|
|
21
|
+
|
|
22
|
+
<p align="center"><img src="assets/settings-remote-connections.png" width="420" alt="设置:远程连接"></p>
|
|
23
|
+
|
|
24
|
+
**内置「文件」页签**:直接浏览远程主机文件(右侧文件树即远程目录,编辑保存直写远程)
|
|
25
|
+
|
|
26
|
+
<p align="center"><img src="assets/remote-files-tab.webp" width="820" alt="内置文件页签直接浏览远程文件"></p>
|
|
27
|
+
|
|
28
|
+
**内置「终端」页签**:自动 SSH 到远程超算(图为 SLURM 作业调度环境);左侧会话即模型免填调用 `remote_ssh_*` 工具
|
|
29
|
+
|
|
30
|
+
<p align="center"><img src="assets/remote-terminal.webp" width="820" alt="内置终端页签自动 SSH 远程超算"></p>
|
|
16
31
|
|
|
17
32
|
## 安装
|
|
18
33
|
|
|
19
34
|
```bash
|
|
20
|
-
dsh plugin --profile <name> add @zhangfengshun/dsh-remote-ssh@2.3.
|
|
35
|
+
dsh plugin --profile <name> add @zhangfengshun/dsh-remote-ssh@2.3.5
|
|
21
36
|
```
|
|
22
37
|
|
|
23
38
|
> 安装后需**重启 DSH**。`@zhangfengshun/dsh-remote-ssh` 必须在 bundles 列表中排在 `dsh-better-sidebar` **之后**。
|
|
39
|
+
>
|
|
40
|
+
> 内置「文件」页签的 SSH 直读依赖 **dsh-better-sidebar ≥ 0.15** 的文件 API(`/sidebar/api/fs.*` 端点),请勿使用更早版本;当前已逐点验证至 **dsh-better-sidebar 0.18.0**。
|
|
24
41
|
|
|
25
42
|
## 使用
|
|
26
43
|
|
|
@@ -46,17 +63,19 @@ dsh plugin --profile <name> add @zhangfengshun/dsh-remote-ssh@2.3.0
|
|
|
46
63
|
| `remote_ssh_sync` | 远端同步到本地镜像 |
|
|
47
64
|
| `remote_ssh_push` | 本地镜像推送回远端 |
|
|
48
65
|
|
|
49
|
-
远程工作区会话中调用工具可免填 `profileId`
|
|
66
|
+
远程工作区会话中调用工具可免填 `profileId` 等连接参数;全部文件/命令类工具走持久 SSH 会话池 + 结果缓存,`remote_ssh_exec` 单命令实测 ≈15× 提速。
|
|
50
67
|
|
|
51
68
|
## 原理
|
|
52
69
|
|
|
53
70
|
插件注册 4 个 exact 路由(`/sidebar/api/fs.tree`、`fs.read`、`fs.write`、`fs.search`),在 better-sidebar 的 prefix 路由之前拦截。会话 cwd 含 `.remote-ssh.json` 时走 SSH,否则走本地 fs。客户端看到的是本地镜像路径,Host 自动转换为远程路径——对客户端完全透明。
|
|
54
71
|
|
|
72
|
+
远程读取采用**单往返合并读**:一条池化命令同时返回 `size/mtime` 帧与文件内容(文本类扩展名优先 raw 直传,字节长 + U+FFFD 双校验失败自动回退 base64,结果逐字节一致);配合主机侧结果缓存与变更失效(见下节)。
|
|
73
|
+
|
|
55
74
|
Shell wrapper(`~/.dsh/remote-ssh/dsh-remote-shell[.cmd]`)检测工作区 `.remote-ssh.json`,自动 `ssh -tt` 连接远程,使内置「终端」页签透明接入。
|
|
56
75
|
|
|
57
76
|
## 缓存与一致性
|
|
58
77
|
|
|
59
|
-
|
|
78
|
+
远程读取与目录列举结果在主机侧缓存(读 LRU 32 条 + 列举 LRU 64 条,TTL 5 秒;单条 >1MiB 不缓存、总量 32MB 字节预算,防止大文件驻留拖慢宿主):TTL 内重复打开或切回页签 **0 网络往返**;过期后先做一次轻量 mtime+size 复验,未变化则免重传。写、删除、移动、建目录、上传、推送(push)、成功的远端 exec 与变更类 git 子命令(add/reset/commit/checkout/revert/cherry-pick)会自动失效相关缓存,并以每 profile 缓存代(epoch)兜底「同秒同 size 写」等粒度盲区。
|
|
60
79
|
|
|
61
80
|
已知限制:
|
|
62
81
|
|
package/README_EN.md
CHANGED
|
@@ -13,14 +13,31 @@ A **DSH** plugin like **VSCode Remote-SSH**: connect to remote HPC / servers via
|
|
|
13
13
|
| 💻 Remote Terminal | Built-in **Terminal** tab auto-detects remote workspaces, opens SSH interactive shell |
|
|
14
14
|
| 🌐 Remote Workspace | Select a remote directory to create a native workspace, one-click enter |
|
|
15
15
|
| 🤖 Model Tools | 12 `remote_ssh_*` tools, session-aware with auto-filled connection params |
|
|
16
|
+
| ⚡ Faster Opens | Single-roundtrip merged reads + raw text fast path + result cache (LRU + 5s TTL): first open ≈**1.31×**, repeat opens within TTL **0 round-trips**, expired revalidation **≈5×** (measured on a real HPC); `remote_ssh_exec` connection reuse **≈15×** |
|
|
17
|
+
|
|
18
|
+
## Screenshots
|
|
19
|
+
|
|
20
|
+
**Settings → 🖥️ Remote SSH**: connection profiles (key / password / ProxyJump bastion) · connection test · one-click import from `~/.ssh/config`
|
|
21
|
+
|
|
22
|
+
<p align="center"><img src="assets/settings-remote-connections.png" width="420" alt="Settings: Remote Connections"></p>
|
|
23
|
+
|
|
24
|
+
**Built-in Files tab**: browse the remote host directly (the right-hand tree IS the remote directory, edits save back to remote)
|
|
25
|
+
|
|
26
|
+
<p align="center"><img src="assets/remote-files-tab.webp" width="820" alt="Built-in Files tab browsing remote files"></p>
|
|
27
|
+
|
|
28
|
+
**Built-in Terminal tab**: auto-SSH to the HPC (SLURM environment shown); the left panel shows the model calling `remote_ssh_*` tools without connection params
|
|
29
|
+
|
|
30
|
+
<p align="center"><img src="assets/remote-terminal.webp" width="820" alt="Built-in Terminal tab auto-SSH to remote HPC"></p>
|
|
16
31
|
|
|
17
32
|
## Installation
|
|
18
33
|
|
|
19
34
|
```bash
|
|
20
|
-
dsh plugin --profile <name> add @zhangfengshun/dsh-remote-ssh@2.3.
|
|
35
|
+
dsh plugin --profile <name> add @zhangfengshun/dsh-remote-ssh@2.3.5
|
|
21
36
|
```
|
|
22
37
|
|
|
23
38
|
> **Restart DSH** after installation. `@zhangfengshun/dsh-remote-ssh` must come **after** `dsh-better-sidebar` in the bundles list.
|
|
39
|
+
>
|
|
40
|
+
> The built-in **Files** tab SSH interception relies on the file API of **dsh-better-sidebar ≥ 0.15** (`/sidebar/api/fs.*` endpoints) — do not use older versions; verified point-by-point against **dsh-better-sidebar 0.18.0**.
|
|
24
41
|
|
|
25
42
|
## Usage
|
|
26
43
|
|
|
@@ -46,17 +63,19 @@ dsh plugin --profile <name> add @zhangfengshun/dsh-remote-ssh@2.3.0
|
|
|
46
63
|
| `remote_ssh_sync` | Sync remote to local mirror |
|
|
47
64
|
| `remote_ssh_push` | Push local mirror back to remote |
|
|
48
65
|
|
|
49
|
-
In a remote-workspace session, `profileId` and other connection params can be omitted.
|
|
66
|
+
In a remote-workspace session, `profileId` and other connection params can be omitted. All file/command tools run over the persistent SSH session pool + result cache; `remote_ssh_exec` measures ≈15× faster per command.
|
|
50
67
|
|
|
51
68
|
## How It Works
|
|
52
69
|
|
|
53
70
|
The plugin registers 4 exact routes (`/sidebar/api/fs.tree`, `fs.read`, `fs.write`, `fs.search`) that intercept better-sidebar's prefix route. When the session cwd contains `.remote-ssh.json`, requests go through SSH; otherwise local fs. The client sees local mirror paths — the Host transparently translates them to remote paths.
|
|
54
71
|
|
|
72
|
+
Remote reads use a **single-roundtrip merged read**: one pooled command returns the `size/mtime` frame plus the file content (text extensions prefer raw transfer with byte-length + U+FFFD validation and automatic base64 fallback — results are byte-identical), combined with host-side result caching and change invalidation (see below).
|
|
73
|
+
|
|
55
74
|
A shell wrapper (`~/.dsh/remote-ssh/dsh-remote-shell[.cmd]`) detects the workspace's `.remote-ssh.json` and auto-launches `ssh -tt`, making the built-in **Terminal** tab transparently connect to remote.
|
|
56
75
|
|
|
57
76
|
## Caching & Consistency
|
|
58
77
|
|
|
59
|
-
Remote reads and directory listings are cached host-side (LRU 32
|
|
78
|
+
Remote reads and directory listings are cached host-side (read LRU 32 + listing LRU 64 entries, TTL 5s; entries >1MiB are not cached, total budget 32MB so large files never weigh down the host): re-opening or switching back to a tab within the TTL costs **0 network round-trips**; after expiry a lightweight mtime+size revalidation runs first, and unchanged files are served without re-transfer. Writes, deletes, moves, mkdir, uploads, push (syncUp), successful remote exec and mutating git subcommands automatically invalidate the affected cache entries, with a per-profile cache epoch guarding same-second same-size writes and path-space mismatches.
|
|
60
79
|
|
|
61
80
|
Known limitations:
|
|
62
81
|
|
package/lib/index.js
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import z from "schemastery";
|
|
12
12
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
13
|
-
import { settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
14
13
|
import { mkdir, rm, writeFile, readFile, opendir, stat, open, rename, readdir } from "node:fs/promises";
|
|
15
14
|
import { existsSync, readFileSync } from "node:fs";
|
|
16
15
|
import { homedir } from "node:os";
|
|
@@ -217,7 +216,7 @@ class CommandSession {
|
|
|
217
216
|
});
|
|
218
217
|
const onEnd = () => {
|
|
219
218
|
this.alive = false;
|
|
220
|
-
const errMsg = "ssh 会话已关闭" + (this.errBuf.trim() ? ": " + this.errBuf.trim().slice(-300) : "");
|
|
219
|
+
const errMsg = "ssh 会话已关闭" + (this.errBuf.trim() ? ": " + stripPqBanner(this.errBuf).trim().slice(-300) : "");
|
|
221
220
|
if (this.current) { this.current.reject(new Error(errMsg)); this.current = null; }
|
|
222
221
|
while (this.queue.length) this.queue.shift().reject(new Error(errMsg));
|
|
223
222
|
};
|
|
@@ -337,7 +336,7 @@ class CommandSession {
|
|
|
337
336
|
}
|
|
338
337
|
}
|
|
339
338
|
|
|
340
|
-
function sshArgv(p, remoteCmd, tty) {
|
|
339
|
+
function sshArgv(p, remoteCmd, tty, extraOpts) {
|
|
341
340
|
const opts = ["ssh"];
|
|
342
341
|
if (tty) opts.push("-tt");
|
|
343
342
|
opts.push("-p", String(p.port || 22));
|
|
@@ -357,6 +356,7 @@ function sshArgv(p, remoteCmd, tty) {
|
|
|
357
356
|
opts.push("-o", "BatchMode=yes");
|
|
358
357
|
opts.push("-o", "PreferredAuthentications=publickey");
|
|
359
358
|
}
|
|
359
|
+
if (Array.isArray(extraOpts) && extraOpts.length) opts.push(...extraOpts);
|
|
360
360
|
const target = String(p.user || "") + "@" + String(p.host || "");
|
|
361
361
|
const head = (p.authMethod === "password" && p.password) ? ["sshpass", "-p", String(p.password)] : [];
|
|
362
362
|
const argv = head.concat(opts, [target]);
|
|
@@ -364,12 +364,23 @@ function sshArgv(p, remoteCmd, tty) {
|
|
|
364
364
|
return argv;
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
-
|
|
367
|
+
/** 过滤 OpenSSH 客户端的“后量子 KEX”警告横幅(stderr 噪音,与认证成败无关,
|
|
368
|
+
* 混进错误信息会误导用户以为是不支持加密算法)。 */
|
|
369
|
+
function stripPqBanner(text) {
|
|
370
|
+
return String(text || "")
|
|
371
|
+
.split("\n")
|
|
372
|
+
.filter(function (line) {
|
|
373
|
+
return !/^\s*\*\*\s*(WARNING: connection is not using a post-quantum|This session may be vulnerable to .?store now|The server may need to be upgraded)/i.test(line);
|
|
374
|
+
})
|
|
375
|
+
.join("\n");
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async function runRemote(subprocess, p, remoteCmd, stdinData, maxBytes, extraOpts) {
|
|
368
379
|
const max = maxBytes || MAX_BYTES;
|
|
369
380
|
let handle;
|
|
370
381
|
try {
|
|
371
382
|
handle = subprocess.spawn({
|
|
372
|
-
argv: sshArgv(p, remoteCmd, false),
|
|
383
|
+
argv: sshArgv(p, remoteCmd, false, extraOpts),
|
|
373
384
|
cwd: process.cwd(),
|
|
374
385
|
stdio: {
|
|
375
386
|
stdin: stdinData !== undefined ? { data: String(stdinData) } : "ignore",
|
|
@@ -390,7 +401,7 @@ async function runRemote(subprocess, p, remoteCmd, stdinData, maxBytes) {
|
|
|
390
401
|
const so = (handle.collected && handle.collected.stdout) ? handle.collected.stdout.readFrom(0) : { text: "", nextOffset: 0, lossy: false };
|
|
391
402
|
const se = (handle.collected && handle.collected.stderr) ? handle.collected.stderr.readFrom(0) : { text: "", nextOffset: 0, lossy: false };
|
|
392
403
|
const outText = so.text;
|
|
393
|
-
const errText = se.text;
|
|
404
|
+
const errText = stripPqBanner(se.text);
|
|
394
405
|
let error = "";
|
|
395
406
|
if (outcome.exitCode !== 0 && !outText && !errText) {
|
|
396
407
|
error = "ssh 退出码 " + outcome.exitCode + (outcome.signal ? " (signal " + outcome.signal + ")" : "");
|
|
@@ -1055,12 +1066,12 @@ function apply(ctx, config) {
|
|
|
1055
1066
|
}
|
|
1056
1067
|
/** 把 SSH 常见失败翻译成带修复建议的中文提示。 */
|
|
1057
1068
|
function sshErrorHint(text) {
|
|
1058
|
-
const t = String(text || "");
|
|
1069
|
+
const t = stripPqBanner(String(text || ""));
|
|
1059
1070
|
if (/remote port forwarding failed for listen port (\d+)/i.test(t)) {
|
|
1060
1071
|
const m = t.match(/remote port forwarding failed for listen port (\d+)/i);
|
|
1061
1072
|
return "SSH 端口转发失败(本地端口 " + m[1] + " 已被占用)。这通常由 ~/.ssh/config 里的 RemoteForward 造成:远端该端口被上次会话占用时,ExitOnForwardFailure yes 会让 ssh 直接退出。本插件已对该连接加 ClearAllForwardings,若仍出现请检查 ssh config。原始信息: " + t.trim().slice(0, 300);
|
|
1062
1073
|
}
|
|
1063
|
-
if (/permission denied \(publickey/i.test(t)) return "
|
|
1074
|
+
if (/permission denied \(publickey/i.test(t)) return "公钥认证失败(服务器拒绝了公钥)。请依次检查:① keyPath 指向的私钥是否正确、是否带口令——测试连接以批处理模式运行无法交互输口令,可先 ssh-add 加载或改用无口令密钥;② 远端是否收录对应公钥——Windows 主机且目标用户在 Administrators 组时需写入 C:\\ProgramData\\ssh\\administrators_authorized_keys;③ profile 的用户名写法与手动连接是否一致(user / .\\user / user@domain 在 Windows sshd 中解析不同)。原始信息: " + t.trim().slice(0, 300);
|
|
1064
1075
|
if (/connection refused/i.test(t)) return "连接被拒绝:请确认远端 sshd 已启动且端口正确。原始信息: " + t.trim().slice(0, 300);
|
|
1065
1076
|
if (/connection timed out|timed out/i.test(t)) return "连接超时:请确认网络可达、端口开放,或检查 ProxyJump 配置。原始信息: " + t.trim().slice(0, 300);
|
|
1066
1077
|
if (/could not resolve hostname/i.test(t)) return "无法解析主机名:请检查连接配置中的 host 拼写。原始信息: " + t.trim().slice(0, 300);
|
|
@@ -1110,7 +1121,10 @@ function apply(ctx, config) {
|
|
|
1110
1121
|
updateWorkspaces: async () => {}
|
|
1111
1122
|
};
|
|
1112
1123
|
ctx.inject(["settings"], (sctx) => {
|
|
1113
|
-
|
|
1124
|
+
// settings 命名空间直接传插件 id(匹配 /^[a-z][a-z0-9-]*$/)。不再依赖
|
|
1125
|
+
// @deepseek-ai/dsh-settings 的 legacy `settingsNamespace` 构造器(该导出仅为
|
|
1126
|
+
// alpha.2 之前的插件保留,未来可能移除);恒等语义下两种写法存储键完全一致。
|
|
1127
|
+
const scope = sctx.settings.register(NS, PrefsSchema);
|
|
1114
1128
|
settingsFace = {
|
|
1115
1129
|
read: () => {
|
|
1116
1130
|
const v = scope.get();
|
|
@@ -1237,7 +1251,26 @@ function apply(ctx, config) {
|
|
|
1237
1251
|
testConnection: async (args) => {
|
|
1238
1252
|
const p = getProfile(args && args.id);
|
|
1239
1253
|
if (!p) return { ok: false, error: "未找到连接配置" };
|
|
1240
|
-
|
|
1254
|
+
// 认证探测只用跨平台 echo:Windows host 无 uname/pwd,且默认 shell 语义各异
|
|
1255
|
+
// (旧命令尾部 uname -a 会让认证成功的 Windows host 也误报失败)。
|
|
1256
|
+
const r = await runRemote(subprocess, p, "echo __DSH_OK__", undefined, 16 * 1024);
|
|
1257
|
+
if (r.ok) return r;
|
|
1258
|
+
const baseErr = sshErrorHint([r.error, stripPqBanner(r.stderr).trim()].filter(Boolean).join(" ") || ("ssh 退出码 " + r.exitCode));
|
|
1259
|
+
// 认证类失败:带 ssh -v 重跑一次握手 + 认证,抽取关键诊断行
|
|
1260
|
+
// (私钥加载 / 公钥提供 / 服务器拒绝方法),定位 Windows 常见坑。
|
|
1261
|
+
let error = baseErr;
|
|
1262
|
+
if (/permission denied|publickey/i.test(baseErr + " " + stripPqBanner(r.stderr))) {
|
|
1263
|
+
const diag = await runRemote(subprocess, p, "exit 0", undefined, 16 * 1024, ["-v"]);
|
|
1264
|
+
const diagText = String(diag.stderr || "")
|
|
1265
|
+
.split("\n")
|
|
1266
|
+
.filter(function (l) {
|
|
1267
|
+
return /debug1: (Offering public key|Authentications that can continue|Server accepts key|Trying private key|no such identity)|Load key|Permission denied|passphrase/i.test(l);
|
|
1268
|
+
})
|
|
1269
|
+
.join("\n")
|
|
1270
|
+
.slice(0, 1200);
|
|
1271
|
+
if (diagText) error = baseErr + "\n\nssh -v 诊断:\n" + diagText;
|
|
1272
|
+
}
|
|
1273
|
+
return { ok: false, exitCode: r.exitCode, signal: r.signal, stdout: r.stdout, stderr: r.stderr, truncated: r.truncated, error: error };
|
|
1241
1274
|
},
|
|
1242
1275
|
listWorkspaces: async () => ({ ok: true, workspaces: settingsFace.read().workspaces }),
|
|
1243
1276
|
createRemoteWorkspace: async (args) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhangfengshun/dsh-remote-ssh",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.7",
|
|
4
4
|
"description": "DSH web plugin: VSCode Remote-SSH-like remote development (SSH to supercomputers/servers, remote workspace, file explorer, integrated terminal), integrated with dsh-better-sidebar and DSH settings.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
60
60
|
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6",
|
|
61
61
|
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6",
|
|
62
|
-
"@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
|
|
63
62
|
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6"
|
|
64
63
|
},
|
|
65
64
|
"files": [
|