@hyzyn/dsh-tty 0.20.2 → 0.22.0-rc.1

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/lib/probe.d.ts CHANGED
@@ -5,11 +5,39 @@ export declare const PROBE_TCP_TIMEOUT_MS = 6000;
5
5
  export declare const PROBE_AUTH_TIMEOUT_MS = 8000;
6
6
  /** 分类结果载荷(HTTP 回传;字段全部可 JSON)。 */
7
7
  export interface ProbeResult {
8
- /** tcp 阶段:DNS 解析 + TCP 建连。 */
8
+ /**
9
+ * tcp 阶段:DNS 解析 + TCP 建连。
10
+ *
11
+ * **有跳板机时探的是跳板机那一跳**(目标根本不能直连),标签与它的结论另见 `jump`——
12
+ * 客户端据此把这一行写成「跳板机 X 通/不通」,而不是让人读成「目标 TCP 可达」。
13
+ * **走代理命令时这一阶段整个跳过**(`skipped=true`):连不连得上由那条命令自己决定,
14
+ * 直连预检探的是目标主机、与本次连接路径无关,报「不可达」纯属误导读者的噪音。
15
+ */
9
16
  tcp: {
10
17
  ok: boolean;
11
18
  error?: string;
12
19
  ms?: number;
20
+ skipped?: boolean;
21
+ };
22
+ /** 跳板机维度(单跳):标签 + 它那一跳的 TCP 预检结论(与 `tcp` 同一份数据,便于客户端直接渲染)。 */
23
+ jump?: {
24
+ label: string;
25
+ tcp: {
26
+ ok: boolean;
27
+ error?: string;
28
+ ms: number;
29
+ };
30
+ };
31
+ /**
32
+ * 代理命令维度:配了 `proxyCommand` 时非空。
33
+ *
34
+ * `active=false` 表示**配了但闸门关着**(`allowProxyCommand` 未开),本次不会执行任何本机
35
+ * 命令——探针在这里就返回,把开关路径写清楚(而不是让人读成「目标连不上」)。
36
+ * **不回显命令原文**(它可能含凭据)。
37
+ */
38
+ proxy?: {
39
+ active: boolean;
40
+ error?: string;
13
41
  };
14
42
  /** hostkey 阶段:TOFU 比对(未到握手时为 unknown)。 */
15
43
  hostkey: {
package/lib/probe.js CHANGED
@@ -22,7 +22,7 @@
22
22
  */
23
23
  import { Client } from 'ssh2';
24
24
  import { connect as netConnect } from 'node:net';
25
- import { buildConnectConfig, classifyError, sshTarget } from './ssh.js';
25
+ import { attachSshTransport, classifyError, jumpTargetLabel, PROXY_COMMAND_DISABLED, PROXY_COMMAND_NOT_GRANTED, proxyCommandAllowedNow, proxyCommandGrantedNow, proxyFailureSuffix, sanitizeProxyCommand, sshTarget } from './ssh.js';
26
26
  /** TCP 预检超时(毫秒):DNS 解析 + 建连。 */
27
27
  export const PROBE_TCP_TIMEOUT_MS = 6_000;
28
28
  /** ssh2 握手/认证阶段超时(毫秒);覆盖 buildConnectConfig 的 readyTimeout。 */
@@ -118,16 +118,59 @@ export async function probeSsh(spec, store) {
118
118
  };
119
119
  const port = spec.port ?? 22;
120
120
  const target = sshTarget(spec);
121
- // ---- 阶段 1:agent 预检(与 spawnSsh 同款,快速失败) ----
121
+ /*
122
+ * ---- 阶段 0:代理命令闸门 ----
123
+ *
124
+ * 配了 `proxyCommand` 但开关(`allowProxyCommand`)没开时**在这里就返回**:这一档是
125
+ * 「本机任意命令执行」,关着的时候真实连接也会明确失败(见 ssh.ts 的 dialProxyCommand),
126
+ * 所以探针必须报同一件事——否则「试连」会去 TCP 预检目标主机,把用户引到网络排查上。
127
+ */
128
+ const proxyCommand = sanitizeProxyCommand(spec.proxyCommand);
129
+ const proxyActive = proxyCommand !== undefined && proxyCommandAllowedNow();
130
+ if (proxyCommand !== undefined) {
131
+ // 未启用分两种:**宿主没授权**(要去设环境变量 + 重启)与**开关关着**(去把开关打开)。
132
+ // 合成一句话会让用户对着一个点不动的开关反复点。
133
+ const blocked = proxyCommandGrantedNow() ? PROXY_COMMAND_DISABLED : PROXY_COMMAND_NOT_GRANTED;
134
+ result.proxy = { active: proxyActive, ...(proxyActive ? {} : { error: blocked }) };
135
+ if (!proxyActive) {
136
+ result.tcp = { ok: false, error: blocked, ms: 0 };
137
+ result.auth = { ok: false, error: blocked };
138
+ return finish();
139
+ }
140
+ /*
141
+ * 走代理命令时**不做直连 TCP 预检**:连不连得上由那条命令决定,探目标主机与本次路径无关
142
+ * (典型情况就是目标根本不可直连,报「不可达」纯属误导)。链路结论来自阶段 2 的握手。
143
+ */
144
+ result.tcp = { ok: false, skipped: true, ms: 0 };
145
+ }
146
+ /*
147
+ * ---- agent 预检(与 spawnSsh 同款,快速失败) ----
148
+ *
149
+ * **位置在代理命令闸门之后**(tty D67,Windows 真机实测纠正过一次顺序):原先它在闸门之前,于是
150
+ * 「配了代理命令 + 宿主没授权 + 这台机器又没有 ssh-agent」三件事同时成立时,探针只报
151
+ * 「agent 认证需要 SSH_AUTH_SOCK」——用户去把 agent 修好、再点一次,才看到真正挡路的那道门。
152
+ * 策略挡路(要不要放行本机命令执行)优先于环境挡路(本机有没有 agent),
153
+ * 也与 HTTP 路由「先过门、再干活」一致。macOS 开发机上因为本机有 agent,看不出来。
154
+ */
122
155
  if (spec.auth === 'agent' && (process.env.SSH_AUTH_SOCK === undefined || process.env.SSH_AUTH_SOCK === '')) {
123
156
  const message = 'agent 认证需要 SSH_AUTH_SOCK(本机未运行 ssh-agent 或变量未设置)';
124
157
  result.tcp = { ok: false, error: message, ms: 0 };
125
158
  result.auth = { ok: false, error: message };
126
159
  return finish();
127
160
  }
128
- // ---- 阶段 1:TCP 预检(DNS + 建连) ----
129
- const tcpResult = await new Promise((resolve) => {
130
- const sock = netConnect({ host: spec.host, port });
161
+ /*
162
+ * ---- 阶段 1:TCP 预检(DNS + 建连) ----
163
+ *
164
+ * **有跳板机时预检的是跳板机**:目标那一跳根本不能直连,探它只会得到一句「超时」,
165
+ * 而那正是用户要区分的东西。目标那一跳的结论来自阶段 2(经通道握手),见 result.auth。
166
+ * **走代理命令时整段跳过**(上面已经把 tcp 标成 skipped)。
167
+ */
168
+ const jumpLabel = jumpTargetLabel(spec);
169
+ const tcpHost = spec.jump !== undefined ? spec.jump.host.trim() : spec.host;
170
+ const tcpPort = spec.jump !== undefined ? spec.jump.port ?? 22 : port;
171
+ const tcpPrefix = jumpLabel === '' ? '' : `跳板机 ${jumpLabel} `;
172
+ const tcpResult = !proxyActive && await new Promise((resolve) => {
173
+ const sock = netConnect({ host: tcpHost, port: tcpPort });
131
174
  const tcpStart = Date.now();
132
175
  const done = (ok, error) => {
133
176
  try {
@@ -139,30 +182,40 @@ export async function probeSsh(spec, store) {
139
182
  resolve({ ok, error, ms: Date.now() - tcpStart });
140
183
  };
141
184
  sock.setTimeout(PROBE_TCP_TIMEOUT_MS, () => {
142
- done(false, 'TCP 连接超时:主机无响应(检查地址 / 防火墙 / 网络)');
185
+ // 没配跳板机时仍要点出这条最容易被误读的成因(企业内网主机几乎都要过 bastion)
186
+ const hint = jumpLabel === ''
187
+ ? ';若该主机只能经跳板机访问,请在这个连接条目里配置跳板机(也可从 ~/.ssh/config 导入,ProxyJump 会被自动带上)'
188
+ : '';
189
+ done(false, `${tcpPrefix}TCP 连接超时:无响应(检查地址 / 防火墙 / 网络${hint})`);
143
190
  });
144
191
  sock.once('connect', () => done(true));
145
192
  sock.once('error', (error) => {
146
- done(false, classifyError(error.message));
193
+ done(false, tcpPrefix + classifyError(error.message));
147
194
  });
148
195
  });
149
- result.tcp = tcpResult;
150
- if (!tcpResult.ok) {
151
- result.auth = { ok: false, error: tcpResult.error };
152
- return finish();
196
+ if (tcpResult !== false) {
197
+ result.tcp = tcpResult;
198
+ if (jumpLabel !== '')
199
+ result.jump = { label: jumpLabel, tcp: { ...tcpResult, ms: tcpResult.ms } };
200
+ if (!tcpResult.ok) {
201
+ result.auth = { ok: false, error: tcpResult.error };
202
+ return finish();
203
+ }
153
204
  }
154
205
  // ---- 阶段 2+3:ssh2 握手(host key 交换 + 认证) ----
206
+ // 有跳板机时**两跳都用探针的短超时**:否则「跳板机连不上」会把探针拖到 20s
155
207
  let connectConfig;
208
+ let transport;
156
209
  try {
157
- connectConfig = await buildConnectConfig(spec);
210
+ const attached = await attachSshTransport({ spec, store, readyTimeoutMs: PROBE_AUTH_TIMEOUT_MS });
211
+ connectConfig = attached.connectConfig;
212
+ transport = attached.transport;
158
213
  }
159
214
  catch (error) {
160
215
  const message = error instanceof Error ? error.message : String(error);
161
216
  result.auth = { ok: false, error: classifyError(message) };
162
217
  return finish();
163
218
  }
164
- // 探针专属更短握手超时(buildConnectConfig 默认 20s 对测试太长)
165
- connectConfig.readyTimeout = PROBE_AUTH_TIMEOUT_MS;
166
219
  const password = spec.auth === 'password' ? connectConfig.password ?? '' : '';
167
220
  const tryKeyboard = connectConfig.tryKeyboard === true;
168
221
  return new Promise((resolve) => {
@@ -180,6 +233,14 @@ export async function probeSsh(spec, store) {
180
233
  catch {
181
234
  /* 已断开 */
182
235
  }
236
+ try {
237
+ transport.bastion?.end();
238
+ }
239
+ catch {
240
+ /* 已断开 */
241
+ }
242
+ // 代理命令是子进程:探针收尾必须杀它(每次试连漏一个常驻进程是很容易漏的地方)
243
+ transport.proxy?.dispose();
183
244
  resolve(finish());
184
245
  };
185
246
  // hostVerifier 的 onResult 同步回调:把结论收集到 hostkeyState
@@ -199,7 +260,16 @@ export async function probeSsh(spec, store) {
199
260
  });
200
261
  }
201
262
  const authStart = Date.now();
263
+ /*
264
+ * **每个回调进来先看 settled**——这不是防御性代码,是修一个真缺陷(2026-09-26 真机验收发现):
265
+ * `settle()` 有幂等守卫,但这些 `result.auth = …` **赋值没有**。而 `resolve(finish())` 交出去的
266
+ * 是**同一个对象**,于是「后到的 close」会把已经定稿的字段覆写掉,调用方看到的是最后那句
267
+ * ——实测症状是 ssh2 连报两条错(`Connection lost before handshake` 带着代理命令的 stderr、
268
+ * 随后 `The operation was aborted` 什么线索都没有),文案被后者盖成一句空话。
269
+ */
202
270
  const timer = setTimeout(() => {
271
+ if (settled)
272
+ return;
203
273
  if (seenHostKey) {
204
274
  result.hostkey = hostkeyState;
205
275
  result.auth = { ok: false, error: '认证/协商超时(服务端在 8s 内未完成认证)', ms: Date.now() - authStart };
@@ -211,11 +281,15 @@ export async function probeSsh(spec, store) {
211
281
  }, PROBE_AUTH_TIMEOUT_MS + 1000);
212
282
  timer.unref?.();
213
283
  conn.on('ready', () => {
284
+ if (settled)
285
+ return;
214
286
  result.hostkey = hostkeyState;
215
287
  result.auth = { ok: true, ms: Date.now() - authStart };
216
288
  settle();
217
289
  });
218
290
  conn.on('error', (error) => {
291
+ if (settled)
292
+ return;
219
293
  const classified = classifyError(error.message);
220
294
  if (error.message === 'Host key verification failed' && hostkeyState.state === 'mismatch') {
221
295
  result.hostkey = hostkeyState;
@@ -224,13 +298,16 @@ export async function probeSsh(spec, store) {
224
298
  return;
225
299
  }
226
300
  result.hostkey = seenHostKey ? hostkeyState : { state: 'unknown', fingerprint: '' };
227
- // TCP 已通:这里只可能是协商 / 认证 / 协议层错误
228
- result.auth = { ok: false, error: classified, ms: Date.now() - authStart };
301
+ // TCP / 传输已通:这里只可能是协商 / 认证 / 协议层错误。
302
+ // 代理命令死了的话,ssh2 只会报「握手前连接中断」——把那件事补在后面,别把人支到目标主机上
303
+ result.auth = { ok: false, error: classified + proxyFailureSuffix(transport.proxy), ms: Date.now() - authStart };
229
304
  settle();
230
305
  });
231
306
  conn.on('close', () => {
232
307
  // 正常路径(ready / error / 超时)已 settle;未 settle 的 close 兜底
233
- result.auth = { ok: false, error: '连接已关闭(服务端主动断开)', ms: Date.now() - authStart };
308
+ if (settled)
309
+ return;
310
+ result.auth = { ok: false, error: `连接已关闭(服务端主动断开)${proxyFailureSuffix(transport.proxy)}`, ms: Date.now() - authStart };
234
311
  settle();
235
312
  });
236
313
  try {
@@ -238,8 +315,10 @@ export async function probeSsh(spec, store) {
238
315
  }
239
316
  catch (error) {
240
317
  const message = error instanceof Error ? error.message : String(error);
241
- result.auth = { ok: false, error: classifyError(message), ms: Date.now() - authStart };
242
- settle();
318
+ if (!settled) {
319
+ result.auth = { ok: false, error: classifyError(message), ms: Date.now() - authStart };
320
+ settle();
321
+ }
243
322
  }
244
323
  });
245
324
  }
package/lib/probe.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"probe.js","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAE7B,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,eAAe,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGrO,gCAAgC;AAChC,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAA;AACzC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAA;AAuC1C,sCAAsC;AACtC,6DAA6D;AAC7D,SAAS,eAAe,CAAC,MAAc,EAAE,IAAY,EAAE,IAAY,EAAE,KAAe,EAAE,OAAe;IACnG,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACrE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;IACnE,OAAO,CACL,gBAAgB,MAAM,QAAQ,KAAK,GAAG,IAAI,eAAe,OAAO,GAAG;QACnE,wEAAwE,CACzE,CAAA;AACH,CAAC;AAED,4DAA4D;AAC5D,SAAS,mBAAmB,CAAC,OAI5B;IACC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,OAAO,CAAC,IAAY,EAAE,EAAE;QACtB,IAAI,GAAG,IAAI,CAAA;QACX,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACzC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,kDAAkD;gBAClD,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;gBACnC,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;YACpD,CAAC;iBAAM,CAAC;gBACN,iBAAiB;gBACjB,QAAQ,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;YACnD,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YACxD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;QACvH,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,iBAAiB,CAAC,KAA8B;IAC9D,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACpE,MAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAChF,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;IACzC,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;IAC9C,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAA;QACjG,IAAI,GAAG,KAAK,CAAA;IACd,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAA;IACrF,MAAM,IAAI,GAAY,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;IACpD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAC7E,IAAI,OAAO,KAAK,EAAE;YAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAA;QACvD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,MAAM,UAAU,GAAG,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/E,IAAI,UAAU,KAAK,EAAE;YAAE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IACrD,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;QACzE,IAAI,QAAQ,KAAK,EAAE;YAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAA;QAC3D,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI;QAAE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;IACzD,OAAO,EAAE,IAAI,EAAE,CAAA;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAa,EAAE,KAAoB;IAChE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAgB;QAC1B,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE;QAClB,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE;QAC9C,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE;QACnB,OAAO,EAAE,CAAC;KACX,CAAA;IACD,MAAM,MAAM,GAAG,GAAgB,EAAE;QAC/B,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;QACvC,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAE9B;;;;;;OAMG;IACH,MAAM,YAAY,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAC5D,MAAM,WAAW,GAAG,YAAY,KAAK,SAAS,IAAI,sBAAsB,EAAE,CAAA;IAC1E,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,mDAAmD;QACnD,0BAA0B;QAC1B,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,yBAAyB,CAAA;QAC7F,MAAM,CAAC,KAAK,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;QAClF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,CAAA;YACjD,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;YAC3C,OAAO,MAAM,EAAE,CAAA;QACjB,CAAC;QACD;;;WAGG;QACH,MAAM,CAAC,GAAG,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAA;IAClD,CAAC;IAED;;;;;;;;OAQG;IACH,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,EAAE,CAAC,EAAE,CAAC;QAC3G,MAAM,OAAO,GAAG,kDAAkD,CAAA;QAClE,MAAM,CAAC,GAAG,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,CAAA;QACjD,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;QAC3C,OAAO,MAAM,EAAE,CAAA;IACjB,CAAC;IAED;;;;;;OAMG;IACH,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAA;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IACrE,MAAM,SAAS,GAAG,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,SAAS,GAAG,CAAA;IAC7D,MAAM,SAAS,GAAG,CAAC,WAAW,IAAI,MAAM,IAAI,OAAO,CAA8C,CAAC,OAAO,EAAE,EAAE;QAC3G,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC3B,MAAM,IAAI,GAAG,CAAC,EAAW,EAAE,KAAc,EAAQ,EAAE;YACjD,IAAI,CAAC;gBACH,IAAI,CAAC,OAAO,EAAE,CAAA;YAChB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAA;QACnD,CAAC,CAAA;QACD,IAAI,CAAC,UAAU,CAAC,oBAAoB,EAAE,GAAG,EAAE;YACzC,6CAA6C;YAC7C,MAAM,IAAI,GAAG,SAAS,KAAK,EAAE;gBAC3B,CAAC,CAAC,qEAAqE;gBACvE,CAAC,CAAC,EAAE,CAAA;YACN,IAAI,CAAC,KAAK,EAAE,GAAG,SAAS,+BAA+B,IAAI,GAAG,CAAC,CAAA;QACjE,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE;YAClD,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;QACvD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,GAAG,SAAS,CAAA;QACtB,IAAI,SAAS,KAAK,EAAE;YAAE,MAAM,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,GAAG,SAAS,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,EAAE,CAAA;QACjG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,CAAA;YACnD,OAAO,MAAM,EAAE,CAAA;QACjB,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,2CAA2C;IAC3C,IAAI,aAA4B,CAAA;IAChC,IAAI,SAAuB,CAAA;IAC3B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,CAAC,CAAA;QACjG,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAA;QACtC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAA;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACtE,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAA;QAC1D,OAAO,MAAM,EAAE,CAAA;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAE,aAAuC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACxG,MAAM,WAAW,GAAI,aAA2C,CAAC,WAAW,KAAK,IAAI,CAAA;IAErF,OAAO,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,EAAE;QAC1C,IAAI,OAAO,GAAG,KAAK,CAAA;QACnB,IAAI,WAAW,GAAG,KAAK,CAAA;QACvB,IAAI,YAAY,GAA2B,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,CAAA;QAChF,MAAM,MAAM,GAAG,GAAS,EAAE;YACxB,IAAI,OAAO;gBAAE,OAAM;YACnB,OAAO,GAAG,IAAI,CAAA;YACd,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,IAAI,CAAC;gBACH,IAAI,CAAC,GAAG,EAAE,CAAA;YACZ,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,IAAI,CAAC;gBACH,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,CAAA;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,yCAAyC;YACzC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,CAAA;YAC1B,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;QACnB,CAAC,CAAA;QACD,mDAAmD;QACnD,aAAa,CAAC,YAAY,GAAG,mBAAmB,CAAC;YAC/C,IAAI;YACJ,KAAK;YACL,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;gBACjB,WAAW,GAAG,IAAI,CAAA;gBAClB,YAAY,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;YAC/C,CAAC;SACF,CAAC,CAAA;QACF,kEAAkE;QAClE,MAAM,IAAI,GAAG,IAAI,MAAM,EAAE,CAAA;QACzB,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,EAAE,CAAC,sBAAsB,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;gBAClF,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YACtB,CAAC,CAAC,CAAA;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC5B;;;;;;WAMG;QACH,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,OAAO;gBAAE,OAAM;YACnB,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,CAAC,OAAO,GAAG,YAAY,CAAA;gBAC7B,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;YAC3F,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;YAC1F,CAAC;YACD,MAAM,EAAE,CAAA;QACV,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC,CAAA;QAChC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAA;QAEf,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACpB,IAAI,OAAO;gBAAE,OAAM;YACnB,MAAM,CAAC,OAAO,GAAG,YAAY,CAAA;YAC7B,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;YACtD,MAAM,EAAE,CAAA;QACV,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE;YAChC,IAAI,OAAO;gBAAE,OAAM;YACnB,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAC/C,IAAI,KAAK,CAAC,OAAO,KAAK,8BAA8B,IAAI,YAAY,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;gBAC1F,MAAM,CAAC,OAAO,GAAG,YAAY,CAAA;gBAC7B,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;gBACxF,MAAM,EAAE,CAAA;gBACR,OAAM;YACR,CAAC;YACD,MAAM,CAAC,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,CAAA;YACnF,oCAAoC;YACpC,kDAAkD;YAClD,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,GAAG,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;YAChH,MAAM,EAAE,CAAA;QACV,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACpB,uDAAuD;YACvD,IAAI,OAAO;gBAAE,OAAM;YACnB,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;YACtH,MAAM,EAAE,CAAA;QACV,CAAC,CAAC,CAAA;QACF,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACtE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;gBACtF,MAAM,EAAE,CAAA;YACV,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
package/lib/sftp.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * 下次操作自动重连(不做后台重连循环——SFTP 没有常驻监听需求,与隧道不同;
7
7
  * 解析 spec 由调用方每次传入,连接簿凭证热改后天然生效)。
8
8
  *
9
- * 连接建立复用 buildConnectConfig + applyHostKeyPolicy——TOFU 与终端会话、
9
+ * 连接建立复用 prepareSshConnect(含跳板机)——TOFU 与终端会话、
10
10
  * 隧道共用同一 HostKeyStore,指纹变更同样拒绝且文案一致;password 认证挂
11
11
  * keyboard-interactive 自动应答(同 spawnSsh,很多服务端只开这个)。
12
12
  *
@@ -23,7 +23,7 @@ import { mkdir as fsMkdir, readdir as fsReaddir, rm as fsRm, stat as fsStat } fr
23
23
  import { basename, dirname, join as pathJoin } from 'node:path';
24
24
  import { PassThrough } from 'node:stream';
25
25
  import { pipeline } from 'node:stream/promises';
26
- import { applyHostKeyPolicy, buildConnectConfig, sshTarget } from './ssh.js';
26
+ import { prepareSshConnect, proxyFailureSuffix, sshTarget } from './ssh.js';
27
27
  /** 连接空闲回收阈值:窗口内无任何操作即断开(下次操作自动重连)。 */
28
28
  const SFTP_IDLE_MS = 120_000;
29
29
  /** 扫描周期。 */
@@ -53,6 +53,22 @@ export function assertRemovableRemotePath(raw) {
53
53
  }
54
54
  /** OpenSSH 等 server 的 readdir 会带回 '.'/'..':目录列表与递归删除都要跳过。 */
55
55
  const DOT_ENTRIES = new Set(['.', '..']);
56
+ /**
57
+ * SFTP 失败文案:`<动作> <对象>: <原因>`。
58
+ *
59
+ * 为什么必须带对象(D59):agent 常把 sftp_list 当「这个路径存不存在」的探测用,
60
+ * 批量调用时只看到「读取目录失败: No such file」根本判断不出是哪一条失败——只能靠
61
+ * 事件序号回推。path / from→to 就在各调用点作用域里,没有理由不带。
62
+ *
63
+ * ssh2 把 SFTP 状态码挂在 `err.code` 上(SFTP.js `err.code = errorCode`):
64
+ * NO_SUCH_FILE / PERMISSION_DENIED 单独点明,省得调用方从英文 errno 里猜语义。
65
+ */
66
+ function sftpFail(action, target, error, note = '') {
67
+ const code = typeof error === 'object' && error !== null ? error.code : undefined;
68
+ const reason = error instanceof Error ? error.message : String(error);
69
+ const detail = code === 2 ? '不存在(NO_SUCH_FILE)' : code === 3 ? '权限不足(PERMISSION_DENIED)' : reason;
70
+ return new Error(`${action} ${target}: ${detail}${note}`);
71
+ }
56
72
  /** 远程路径拼接(POSIX 语义;本机路径拼接用 node:path)。 */
57
73
  function joinRemotePath(base, name) {
58
74
  return (base.endsWith('/') ? base : base + '/') + name;
@@ -198,7 +214,7 @@ export class SftpManager {
198
214
  catch (error) {
199
215
  // 请求的根目录读不到(不存在/权限)→ 明确报错;子目录失败记入 errors 继续
200
216
  if (isRoot)
201
- throw new Error(`读取目录失败: ${error instanceof Error ? error.message : String(error)}`);
217
+ throw sftpFail('读取目录失败', dir, error);
202
218
  errors.push({ path: dir, message: error instanceof Error ? error.message : String(error) });
203
219
  return;
204
220
  }
@@ -238,7 +254,7 @@ export class SftpManager {
238
254
  async rename(spec, from, to) {
239
255
  const sftp = await this.acquire(spec);
240
256
  await new Promise((resolve, reject) => {
241
- sftp.rename(from.trim(), to.trim(), (error) => (error != null ? reject(new Error(`重命名失败: ${error.message}`)) : resolve()));
257
+ sftp.rename(from.trim(), to.trim(), (error) => (error != null ? reject(sftpFail('重命名失败', `${from.trim()} → ${to.trim()}`, error)) : resolve()));
242
258
  });
243
259
  }
244
260
  /**
@@ -285,7 +301,7 @@ export class SftpManager {
285
301
  const target = path.trim();
286
302
  if (append) {
287
303
  const stream = sftp.createWriteStream(target, { flags: 'a' });
288
- const done = this.streamDone(stream, () => { });
304
+ const done = this.streamDone(stream, () => { }, target);
289
305
  done.catch(() => { });
290
306
  return { stream, done, writePath: target };
291
307
  }
@@ -308,7 +324,7 @@ export class SftpManager {
308
324
  stream.on('error', (error) => {
309
325
  settled = true;
310
326
  dropPart();
311
- reject(new Error(`上传写入失败: ${error.message}`));
327
+ reject(sftpFail('上传写入失败', target, error));
312
328
  });
313
329
  stream.on('close', () => {
314
330
  if (settled)
@@ -364,10 +380,10 @@ export class SftpManager {
364
380
  }
365
381
  }
366
382
  /** WriteStream 的 done Promise(close 即 resolve,error reject);onClose 钩子供覆盖写路径塞落盘逻辑。 */
367
- streamDone(stream, onClose) {
383
+ streamDone(stream, onClose, target) {
368
384
  return new Promise((resolve, reject) => {
369
385
  stream.on('error', (error) => {
370
- reject(new Error(`上传写入失败: ${error.message}`));
386
+ reject(sftpFail('上传写入失败', target, error));
371
387
  });
372
388
  stream.on('close', () => {
373
389
  onClose();
@@ -688,12 +704,19 @@ export class SftpManager {
688
704
  existing.lastUsed = Date.now();
689
705
  return existing.sftp;
690
706
  }
691
- const target = sshTarget(spec);
692
707
  const conn = new Client();
693
708
  let sftp;
709
+ let bastion = null;
710
+ let proxy = null;
711
+ let target = sshTarget(spec);
694
712
  try {
695
- const connectConfig = await buildConnectConfig(spec);
696
- const policy = applyHostKeyPolicy({ connectConfig, spec, store: this.store, logger: this.logger, target });
713
+ // 与终端/隧道/探针共用同一条准备路径:跳板机 / 代理命令只在 prepareSshConnect 里拨一次
714
+ const prepared = await prepareSshConnect({ spec, store: this.store, logger: this.logger });
715
+ const connectConfig = prepared.connectConfig;
716
+ const policy = prepared.policy;
717
+ bastion = prepared.bastion;
718
+ proxy = prepared.proxy;
719
+ target = prepared.target;
697
720
  // password 认证挂 keyboard-interactive 自动应答(同 spawnSsh;
698
721
  // tryKeyboard 只在 password 分支置位,见 buildConnectConfig)
699
722
  if (connectConfig.tryKeyboard === true) {
@@ -712,17 +735,21 @@ export class SftpManager {
712
735
  if (!settled) {
713
736
  settled = true;
714
737
  const mismatch = policy.mismatchMessage();
715
- reject(new Error(mismatch ?? `SSH 连接失败(${target}): ${error.message}`));
738
+ reject(new Error(mismatch ?? `SSH 连接失败(${target}): ${error.message}${proxyFailureSuffix(proxy)}`));
716
739
  }
717
740
  else {
718
741
  this.logger.warn(`[dsh-tty] sftp ${target} 连接错误: ${error.message}`);
719
742
  }
720
743
  });
721
744
  conn.on('close', () => {
722
- // 连接断开:丢弃池内条目,下次操作自动重连
745
+ // 连接断开:丢弃池内条目,下次操作自动重连。
746
+ // **必须走 close(rt) 而不是只 delete**(**D65**):跳板机 / 代理命令是「另一条连接 / 另一个进程」,
747
+ // 只摘池条目会把它们留在原地(前者靠 keepalive 一直挂着、后者变常驻孤儿)。
723
748
  const rt = this.conns.get(signature);
724
- if (rt !== undefined && rt.conn === conn)
749
+ if (rt !== undefined && rt.conn === conn) {
725
750
  this.conns.delete(signature);
751
+ this.close(rt);
752
+ }
726
753
  });
727
754
  try {
728
755
  conn.connect(connectConfig);
@@ -747,10 +774,18 @@ export class SftpManager {
747
774
  catch {
748
775
  /* 未建立 */
749
776
  }
777
+ try {
778
+ bastion?.end();
779
+ }
780
+ catch {
781
+ /* 未建立 */
782
+ }
783
+ proxy?.dispose();
784
+ proxy = null;
750
785
  throw error;
751
786
  }
752
787
  this.logger.info(`[dsh-tty] sftp ${target} 就绪`);
753
- const rt = { spec, signature, conn, sftp, lastUsed: Date.now() };
788
+ const rt = { spec, signature, conn, bastion, proxy, sftp, lastUsed: Date.now() };
754
789
  this.conns.set(signature, rt);
755
790
  return sftp;
756
791
  }
@@ -776,13 +811,22 @@ export class SftpManager {
776
811
  catch {
777
812
  /* 已断开 */
778
813
  }
814
+ try {
815
+ rt.bastion?.end();
816
+ }
817
+ catch {
818
+ /* 已断开 */
819
+ }
820
+ rt.bastion = null;
821
+ rt.proxy?.dispose();
822
+ rt.proxy = null;
779
823
  }
780
824
  /* -------------------------------------------------------------- */
781
825
  /* SFTPWrapper 回调的 Promise 化与递归删除 */
782
826
  /* -------------------------------------------------------------- */
783
827
  realpath(sftp, path) {
784
828
  return new Promise((resolve, reject) => {
785
- sftp.realpath(path, (error, absPath) => (error !== undefined ? reject(new Error(`realpath 失败: ${error.message}`)) : resolve(absPath)));
829
+ sftp.realpath(path, (error, absPath) => (error !== undefined ? reject(sftpFail('realpath 失败', path, error)) : resolve(absPath)));
786
830
  });
787
831
  }
788
832
  /** stat 的静默版:路径不存在等错误一律回 null(mkdir -p 的逐级探测用)。 */
@@ -793,21 +837,21 @@ export class SftpManager {
793
837
  }
794
838
  mkdirOne(sftp, path) {
795
839
  return new Promise((resolve, reject) => {
796
- sftp.mkdir(path, (error) => (error != null ? reject(new Error(`创建目录失败: ${error.message}`)) : resolve()));
840
+ sftp.mkdir(path, (error) => (error != null ? reject(sftpFail('创建目录失败', path, error)) : resolve()));
797
841
  });
798
842
  }
799
843
  readdir(sftp, path) {
800
844
  return new Promise((resolve, reject) => {
801
- sftp.readdir(path, (error, list) => (error !== undefined ? reject(new Error(`读取目录失败: ${error.message}`)) : resolve(list)));
845
+ sftp.readdir(path, (error, list) => (error !== undefined ? reject(sftpFail('读取目录失败', path, error)) : resolve(list)));
802
846
  });
803
847
  }
804
848
  async removeEntry(sftp, path, recursive) {
805
849
  const stats = await new Promise((resolve, reject) => {
806
- sftp.lstat(path, (error, stats) => (error !== undefined ? reject(new Error(`删除失败: ${error.message}`)) : resolve(stats)));
850
+ sftp.lstat(path, (error, stats) => (error !== undefined ? reject(sftpFail('删除失败', path, error)) : resolve(stats)));
807
851
  });
808
852
  if (!stats.isDirectory()) {
809
853
  await new Promise((resolve, reject) => {
810
- sftp.unlink(path, (error) => (error != null ? reject(new Error(`删除失败: ${error.message}`)) : resolve()));
854
+ sftp.unlink(path, (error) => (error != null ? reject(sftpFail('删除失败', path, error)) : resolve()));
811
855
  });
812
856
  return;
813
857
  }
@@ -815,7 +859,7 @@ export class SftpManager {
815
859
  await new Promise((resolve, reject) => {
816
860
  // 不预设原因:非空与权限拒绝在 SFTP 层都是笼统的 Failure,把两种可能
817
861
  // 一并列出让用户自行分辨(此前一律归因为「非空」误导权限问题)
818
- sftp.rmdir(path, (error) => (error != null ? reject(new Error(`删除目录失败: ${error.message}(目录非空时需 recursive:true;若非此原因,多为账号对该目录无写权限)`)) : resolve()));
862
+ sftp.rmdir(path, (error) => (error != null ? reject(sftpFail('删除目录失败', path, error, '(目录非空时需 recursive:true;若非此原因,多为账号对该目录无写权限)')) : resolve()));
819
863
  });
820
864
  return;
821
865
  }
@@ -827,7 +871,7 @@ export class SftpManager {
827
871
  await this.removeEntry(sftp, base + child.filename, true);
828
872
  }
829
873
  await new Promise((resolve, reject) => {
830
- sftp.rmdir(path, (error) => (error != null ? reject(new Error(`删除目录失败: ${error.message}`)) : resolve()));
874
+ sftp.rmdir(path, (error) => (error != null ? reject(sftpFail('删除目录失败', path, error)) : resolve()));
831
875
  });
832
876
  }
833
877
  }