dsh-remote 0.8.45 → 0.8.46
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/client.js +31 -17
- package/lib/pool.js +6 -3
- package/lib/web-attach.js +6 -2
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -3415,26 +3415,40 @@ window.__ModuleLoader__.load({
|
|
|
3415
3415
|
const mirror = mirrorForCwd(cwd, MIRRORS.list)
|
|
3416
3416
|
if (!mirror) return null
|
|
3417
3417
|
const remoteRoot = String(mirror.remotePath || '').replace(/[\\/]+$/, '')
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3418
|
+
// The REMOTE host's separator is INDEPENDENT of this machine's, and taking
|
|
3419
|
+
// it from the address was wrong: a Windows client mirroring a Linux host
|
|
3420
|
+
// is the ordinary case here, and reading the separator off the local path
|
|
3421
|
+
// then glued a POSIX root to a Windows join ("/home/u/app" + "\" + "x.c").
|
|
3422
|
+
// Decide from the remote root alone.
|
|
3423
|
+
const remoteIsWin = /^[A-Za-z]:/.test(remoteRoot) || (remoteRoot.includes('\\') && !remoteRoot.includes('/'))
|
|
3424
|
+
const remoteSep = remoteIsWin ? '\\' : '/'
|
|
3425
|
+
const toRemote = (s) => String(s).replace(/[\\/]+/g, remoteSep)
|
|
3426
|
+
// Comparison is separator-INSENSITIVE: `@` completion may insert either
|
|
3427
|
+
// style, and the two sides describe the same directory. The local side
|
|
3428
|
+
// folds case when it looks like a Windows path (Windows paths do).
|
|
3429
|
+
const canon = (s) => String(s).replace(/[\\/]+/g, '/').replace(/\/+$/, '')
|
|
3430
|
+
const localDir = String(mirror.dir || '')
|
|
3431
|
+
const localIsWin = /^[A-Za-z]:/.test(localDir) || localDir.includes('\\')
|
|
3432
|
+
const fold = (s) => (localIsWin ? s.toLowerCase() : s)
|
|
3433
|
+
const rel = canon(parsed.path || '')
|
|
3434
|
+
const mirrorDir = canon(localDir)
|
|
3423
3435
|
// The mirror's own directory prefix may be baked into the address when the
|
|
3424
|
-
// link was written against the
|
|
3425
|
-
//
|
|
3426
|
-
|
|
3427
|
-
const
|
|
3428
|
-
? rel.slice(mirrorDir.length).replace(
|
|
3436
|
+
// link was written against the LOCAL path (that is what `@` completion
|
|
3437
|
+
// inserts); strip it so the result is remote-relative rather than
|
|
3438
|
+
// duplicated under the remote root.
|
|
3439
|
+
const stripped = rel && mirrorDir && (fold(rel) === fold(mirrorDir) || fold(rel).startsWith(fold(mirrorDir) + '/'))
|
|
3440
|
+
? rel.slice(mirrorDir.length).replace(/^\/+/, '')
|
|
3429
3441
|
: rel
|
|
3430
|
-
|
|
3442
|
+
const relBody = canon(stripped)
|
|
3443
|
+
if (!remoteRoot) return relBody ? toRemote(relBody) : remoteSep
|
|
3431
3444
|
if (!relBody) return remoteRoot
|
|
3432
|
-
//
|
|
3433
|
-
//
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3445
|
+
// A drive-letter absolute path on a POSIX remote is a LOCAL path that fell
|
|
3446
|
+
// outside the mirror: nothing on the remote can name it, so refuse rather
|
|
3447
|
+
// than invent "/home/u/app/D:/x.c".
|
|
3448
|
+
if (!remoteIsWin && /^[A-Za-z]:/.test(relBody)) return null
|
|
3449
|
+
// Genuinely absolute: the reader meant that path on the remote.
|
|
3450
|
+
if (/^[A-Za-z]:/.test(relBody) || /^\//.test(relBody)) return toRemote(relBody)
|
|
3451
|
+
return remoteRoot + remoteSep + toRemote(relBody)
|
|
3438
3452
|
}
|
|
3439
3453
|
function NativeExplorer(props) {
|
|
3440
3454
|
const info = props.useTabInfo()
|
package/lib/pool.js
CHANGED
|
@@ -31,7 +31,7 @@ export function createPool(config, opts) {
|
|
|
31
31
|
*
|
|
32
32
|
* ssh2 reports a dead connection by THROWING synchronously —
|
|
33
33
|
* `if (!this._sock || !isWritable(this._sock)) throw new Error('Not connected')`
|
|
34
|
-
* (ssh2
|
|
34
|
+
* (ssh2 >= 1.16, `Client.forwardOut`) — and never calls the callback, so a
|
|
35
35
|
* callback-only error path cannot guard this call (issue #54). Two further
|
|
36
36
|
* consequences justify a shared helper rather than an inline try/catch:
|
|
37
37
|
*
|
|
@@ -40,8 +40,11 @@ export function createPool(config, opts) {
|
|
|
40
40
|
* • called from a `net.Server` connection handler the throw escapes to the
|
|
41
41
|
* process top level and kills the host.
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* This guards the CALLER's side of the contract rather than assuming one
|
|
44
|
+
* backend's behaviour: the system-OpenSSH backend (lib/openssh.js `forwardOut`)
|
|
45
|
+
* already converts its own spawn failure into a callback error, so for it the
|
|
46
|
+
* try/catch below is dead code — but a backend is free to throw, and the one
|
|
47
|
+
* that does must not be able to take the process down.
|
|
45
48
|
*
|
|
46
49
|
* @param {object} client - an ssh2 Client or OpenSshConnection.
|
|
47
50
|
* @param {object} spec - `srcHost`/`srcPort`/`dstHost`/`dstPort`.
|
package/lib/web-attach.js
CHANGED
|
@@ -228,8 +228,12 @@ export class WebAttach {
|
|
|
228
228
|
*/
|
|
229
229
|
constructor(opts = {}) {
|
|
230
230
|
this.net = opts.net || net
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
// `??`, not `||`: port 0 is a MEANINGFUL value here (let the OS pick), and
|
|
232
|
+
// `0 || 3088` silently turned "let the OS choose" into a bind on a fixed
|
|
233
|
+
// port. An explicit 0 now survives, which is also what lets a test ask for a
|
|
234
|
+
// port without risking a collision with something really listening.
|
|
235
|
+
this.localPortStart = opts.localPortStart ?? 3088
|
|
236
|
+
this.localPortMax = opts.localPortMax ?? 50
|
|
233
237
|
/** Whether the pool's lifecycle hooks are ours to install. */
|
|
234
238
|
this.trackPool = opts.trackPool !== false
|
|
235
239
|
/** @type {import('node:net').Server|null} */ this.server = null
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.46",
|
|
4
4
|
"description": "Remote-work assistant for DeepSeek Harness: connect SSH (password/key/agent/keyboard-interactive/proxy jump), pick a remote workspace, operate on it with 22 rw_* tools (incl. rw_edit/rw_stat/rw_mkdir/rw_remove/rw_move/rw_forward), conflict-aware mirror sync, one-click remote dsh deploy + web UI attach, port forwarding, optional side-bar remote file editing, audit log, keychain passwords.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "flymysql <flyphp@outlook.com>",
|
|
@@ -84,6 +84,6 @@
|
|
|
84
84
|
"semver": "^7.8.5"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
|
-
"test": "node --import ./test/setup-telemetry-off.mjs --test"
|
|
87
|
+
"test": "node --import ./test/setup-telemetry-off.mjs --test --test-timeout=20000 --test-force-exit"
|
|
88
88
|
}
|
|
89
89
|
}
|