dsh-remote 0.8.48 → 0.8.50

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.
Files changed (132) hide show
  1. package/README.md +1 -0
  2. package/lib/client.js +100 -19
  3. package/lib/index.js +134 -26
  4. package/lib/remote-shell-child.cjs +305 -0
  5. package/lib/remote-shell.js +518 -0
  6. package/lib/sshconfig.js +256 -15
  7. package/package.json +1 -2
  8. package/node_modules/buildcheck/.eslintrc.js +0 -5
  9. package/node_modules/buildcheck/.github/workflows/ci.yml +0 -88
  10. package/node_modules/buildcheck/.github/workflows/lint.yml +0 -27
  11. package/node_modules/buildcheck/.npmignore +0 -3
  12. package/node_modules/buildcheck/LICENSE +0 -19
  13. package/node_modules/buildcheck/README.md +0 -106
  14. package/node_modules/buildcheck/deps/Find-VisualStudio.cs +0 -250
  15. package/node_modules/buildcheck/lib/findvs.js +0 -361
  16. package/node_modules/buildcheck/lib/index.js +0 -738
  17. package/node_modules/buildcheck/package.json +0 -36
  18. package/node_modules/buildcheck/test/test.js +0 -8
  19. package/node_modules/cpu-features/.eslintrc.js +0 -5
  20. package/node_modules/cpu-features/.github/workflows/ci.yml +0 -74
  21. package/node_modules/cpu-features/.github/workflows/lint.yml +0 -27
  22. package/node_modules/cpu-features/LICENSE +0 -19
  23. package/node_modules/cpu-features/README.md +0 -59
  24. package/node_modules/cpu-features/binding.gyp +0 -16
  25. package/node_modules/cpu-features/buildcheck.js +0 -32
  26. package/node_modules/cpu-features/deps/cpu_features/.clang-format +0 -4
  27. package/node_modules/cpu-features/deps/cpu_features/.dockerignore +0 -31
  28. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/Dockerfile +0 -5
  29. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/aarch64_linux_cmake.yml +0 -30
  30. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_freebsd_cmake.yml +0 -22
  31. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_linux_bazel.yml +0 -26
  32. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_linux_cmake.yml +0 -31
  33. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_macos_cmake.yml +0 -43
  34. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_windows_cmake.yml +0 -25
  35. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/arm_linux_cmake.yml +0 -31
  36. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/clang_format.yml +0 -24
  37. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/mips_linux_cmake.yml +0 -30
  38. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/power_linux_cmake.yml +0 -29
  39. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/riscv_linux_cmake.yml +0 -28
  40. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/s390x_linux_cmake.yml +0 -27
  41. package/node_modules/cpu-features/deps/cpu_features/.grenrc.yml +0 -21
  42. package/node_modules/cpu-features/deps/cpu_features/BUILD.bazel +0 -329
  43. package/node_modules/cpu-features/deps/cpu_features/CMakeLists.txt +0 -261
  44. package/node_modules/cpu-features/deps/cpu_features/CONTRIBUTING.md +0 -23
  45. package/node_modules/cpu-features/deps/cpu_features/LICENSE +0 -230
  46. package/node_modules/cpu-features/deps/cpu_features/README.md +0 -272
  47. package/node_modules/cpu-features/deps/cpu_features/WORKSPACE +0 -19
  48. package/node_modules/cpu-features/deps/cpu_features/bazel/ci/README.md +0 -5
  49. package/node_modules/cpu-features/deps/cpu_features/bazel/platforms.bzl +0 -11
  50. package/node_modules/cpu-features/deps/cpu_features/cmake/CpuFeaturesConfig.cmake.in +0 -3
  51. package/node_modules/cpu-features/deps/cpu_features/cmake/CpuFeaturesNdkCompatConfig.cmake.in +0 -3
  52. package/node_modules/cpu-features/deps/cpu_features/cmake/README.md +0 -30
  53. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/Makefile +0 -252
  54. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/README.md +0 -40
  55. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/doc/docker.dot +0 -64
  56. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/doc/docker.svg +0 -312
  57. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/doc/generate_image.sh +0 -7
  58. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/docker/amd64/Dockerfile +0 -48
  59. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/docker/toolchain/Dockerfile +0 -34
  60. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/sample/CMakeLists.txt +0 -22
  61. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/sample/main.cpp +0 -11
  62. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/vagrant/freebsd/Vagrantfile +0 -107
  63. package/node_modules/cpu-features/deps/cpu_features/cmake/googletest.CMakeLists.txt.in +0 -15
  64. package/node_modules/cpu-features/deps/cpu_features/cpu_features.gyp +0 -105
  65. package/node_modules/cpu-features/deps/cpu_features/include/cpu_features_cache_info.h +0 -54
  66. package/node_modules/cpu-features/deps/cpu_features/include/cpu_features_macros.h +0 -384
  67. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_aarch64.h +0 -259
  68. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_arm.h +0 -121
  69. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_mips.h +0 -74
  70. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_ppc.h +0 -149
  71. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_riscv.h +0 -72
  72. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_s390x.h +0 -108
  73. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_x86.h +0 -288
  74. package/node_modules/cpu-features/deps/cpu_features/include/internal/bit_utils.h +0 -40
  75. package/node_modules/cpu-features/deps/cpu_features/include/internal/cpuid_x86.h +0 -37
  76. package/node_modules/cpu-features/deps/cpu_features/include/internal/filesystem.h +0 -39
  77. package/node_modules/cpu-features/deps/cpu_features/include/internal/hwcaps.h +0 -240
  78. package/node_modules/cpu-features/deps/cpu_features/include/internal/stack_line_reader.h +0 -49
  79. package/node_modules/cpu-features/deps/cpu_features/include/internal/string_view.h +0 -110
  80. package/node_modules/cpu-features/deps/cpu_features/include/internal/windows_utils.h +0 -70
  81. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/CMakeLists.txt +0 -60
  82. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/README.md +0 -4
  83. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/cpu-features.c +0 -205
  84. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/cpu-features.h +0 -320
  85. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/ndk-compat-test.c +0 -12
  86. package/node_modules/cpu-features/deps/cpu_features/patches/0001-Add-Apple-Silicon-Support.patch +0 -456
  87. package/node_modules/cpu-features/deps/cpu_features/scripts/generate_badges.d +0 -165
  88. package/node_modules/cpu-features/deps/cpu_features/scripts/make_release.sh +0 -75
  89. package/node_modules/cpu-features/deps/cpu_features/scripts/run_integration.sh +0 -490
  90. package/node_modules/cpu-features/deps/cpu_features/scripts/test_integration.sh +0 -79
  91. package/node_modules/cpu-features/deps/cpu_features/src/copy.inl +0 -19
  92. package/node_modules/cpu-features/deps/cpu_features/src/define_introspection.inl +0 -86
  93. package/node_modules/cpu-features/deps/cpu_features/src/define_introspection_and_hwcaps.inl +0 -26
  94. package/node_modules/cpu-features/deps/cpu_features/src/equals.inl +0 -22
  95. package/node_modules/cpu-features/deps/cpu_features/src/filesystem.c +0 -62
  96. package/node_modules/cpu-features/deps/cpu_features/src/hwcaps.c +0 -169
  97. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64__base_implementation.inl +0 -88
  98. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64_linux_or_android.c +0 -79
  99. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64_macos_or_iphone.c +0 -82
  100. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64_windows.c +0 -138
  101. package/node_modules/cpu-features/deps/cpu_features/src/impl_arm_linux_or_android.c +0 -212
  102. package/node_modules/cpu-features/deps/cpu_features/src/impl_mips_linux_or_android.c +0 -93
  103. package/node_modules/cpu-features/deps/cpu_features/src/impl_ppc_linux.c +0 -163
  104. package/node_modules/cpu-features/deps/cpu_features/src/impl_riscv_linux.c +0 -111
  105. package/node_modules/cpu-features/deps/cpu_features/src/impl_s390x_linux.c +0 -120
  106. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86__base_implementation.inl +0 -2055
  107. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_freebsd.c +0 -68
  108. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_linux_or_android.c +0 -58
  109. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_macos.c +0 -57
  110. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_windows.c +0 -58
  111. package/node_modules/cpu-features/deps/cpu_features/src/stack_line_reader.c +0 -132
  112. package/node_modules/cpu-features/deps/cpu_features/src/string_view.c +0 -192
  113. package/node_modules/cpu-features/deps/cpu_features/src/utils/list_cpu_features.c +0 -461
  114. package/node_modules/cpu-features/deps/cpu_features/test/CMakeLists.txt +0 -114
  115. package/node_modules/cpu-features/deps/cpu_features/test/bit_utils_test.cc +0 -53
  116. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_aarch64_test.cc +0 -396
  117. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_arm_test.cc +0 -384
  118. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_mips_test.cc +0 -176
  119. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_ppc_test.cc +0 -131
  120. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_riscv_test.cc +0 -180
  121. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_s390x_test.cc +0 -82
  122. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_x86_test.cc +0 -1729
  123. package/node_modules/cpu-features/deps/cpu_features/test/filesystem_for_testing.cc +0 -103
  124. package/node_modules/cpu-features/deps/cpu_features/test/filesystem_for_testing.h +0 -61
  125. package/node_modules/cpu-features/deps/cpu_features/test/hwcaps_for_testing.cc +0 -52
  126. package/node_modules/cpu-features/deps/cpu_features/test/hwcaps_for_testing.h +0 -31
  127. package/node_modules/cpu-features/deps/cpu_features/test/stack_line_reader_test.cc +0 -132
  128. package/node_modules/cpu-features/deps/cpu_features/test/string_view_test.cc +0 -202
  129. package/node_modules/cpu-features/lib/index.js +0 -5
  130. package/node_modules/cpu-features/package.json +0 -40
  131. package/node_modules/cpu-features/src/binding.cc +0 -151
  132. package/node_modules/cpu-features/test/test.js +0 -12
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The program the host terminal runs when the user picks the "Remote SSH" shell.
4
+ *
5
+ * It is started by a generated launcher (see `remote-shell.js`) inside the
6
+ * session's working directory, resolves which remote checkout that directory
7
+ * belongs to, and then replaces itself with `ssh`. Inheriting stdio is the whole
8
+ * point: the local pty stays in charge of the screen, so resize and key handling
9
+ * keep working without this script knowing anything about terminals.
10
+ *
11
+ * Plain CommonJS on purpose: it is spawned as a standalone script, and it must
12
+ * not depend on how the plugin package itself is loaded.
13
+ */
14
+
15
+ 'use strict'
16
+
17
+ const { spawn } = require('node:child_process')
18
+ const { existsSync, readFileSync } = require('node:fs')
19
+ const path = require('node:path')
20
+
21
+ /** Name of the marker the host half writes into every local mirror root. */
22
+ const META_FILE = '.dsh-remote-meta.json'
23
+ /** How far up from the working directory a marker may be found. */
24
+ const MAX_WALK_UP = 12
25
+
26
+ /**
27
+ * Read and parse a JSON file, returning undefined for anything unusable.
28
+ * @param {string} file
29
+ * @returns {any}
30
+ */
31
+ function readJson(file) {
32
+ try {
33
+ return JSON.parse(readFileSync(file, 'utf8'))
34
+ } catch {
35
+ return undefined
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Find the mirror root that contains `cwd` by walking upwards for the marker.
41
+ * @param {string} cwd - session working directory
42
+ * @param {{ exists?: (p: string) => boolean, readJsonFile?: (p: string) => any, maxUp?: number }} deps
43
+ * @returns {{ dir: string, meta: object } | null}
44
+ */
45
+ function findMirror(cwd, deps = {}) {
46
+ const exists = deps.exists || ((p) => existsSync(p))
47
+ const read = deps.readJsonFile || readJson
48
+ const maxUp = deps.maxUp || MAX_WALK_UP
49
+ let dir = path.resolve(cwd || '.')
50
+ for (let depth = 0; depth <= maxUp; depth += 1) {
51
+ const marker = path.join(dir, META_FILE)
52
+ if (exists(marker)) {
53
+ const meta = read(marker)
54
+ if (meta && typeof meta === 'object' && meta.host) return { dir, meta }
55
+ }
56
+ const parent = path.dirname(dir)
57
+ if (parent === dir) break
58
+ dir = parent
59
+ }
60
+ return null
61
+ }
62
+
63
+ /**
64
+ * Pick the saved connection that owns a mirror.
65
+ *
66
+ * The marker records the SSH alias when the machine was saved from
67
+ * `~/.ssh/config` (issue #38), so the alias is the most precise key; otherwise
68
+ * host + user + port identify it. A missing entry is not fatal — the marker
69
+ * alone is enough to connect, and ssh will use its own defaults for the key.
70
+ *
71
+ * @param {object} meta - mirror marker
72
+ * @param {{ list?: object[] }} registry - parsed `machines.json`
73
+ * @returns {object | undefined}
74
+ */
75
+ function matchMachine(meta, registry) {
76
+ const list = registry && Array.isArray(registry.list) ? registry.list : []
77
+ const port = Number(meta.port || 22)
78
+ if (meta.alias) {
79
+ const byAlias = list.find((m) => m && m.host === meta.alias)
80
+ if (byAlias) return byAlias
81
+ }
82
+ return list.find((m) => m && m.host === meta.host
83
+ && String(m.username || '') === String(meta.username || '')
84
+ && Number(m.port || 22) === port)
85
+ }
86
+
87
+ /**
88
+ * Quote one path for a POSIX shell, single quotes only.
89
+ * @param {string} value
90
+ * @returns {string}
91
+ */
92
+ function quotePosix(value) {
93
+ return "'" + String(value).replace(/'/g, "'\\''") + "'"
94
+ }
95
+
96
+ /**
97
+ * Build the `cd` half of the remote command, keeping `~` for the *remote* shell
98
+ * to expand: the local home is not the remote home, so expanding it here would
99
+ * silently land in the wrong directory.
100
+ * @param {string} remotePath
101
+ * @returns {string}
102
+ */
103
+ function remoteCd(remotePath) {
104
+ const raw = String(remotePath || '').trim()
105
+ if (raw === '' || raw === '~') return 'cd "$HOME"'
106
+ if (raw === '~/') return 'cd "$HOME"'
107
+ if (raw.startsWith('~/')) return 'cd "$HOME"/' + quotePosix(raw.slice(2))
108
+ return 'cd ' + quotePosix(raw)
109
+ }
110
+
111
+ /**
112
+ * The remote command: land in the workspace, then hand over to a login shell.
113
+ *
114
+ * `exec` keeps the pty attached to a single interactive shell, so the exit code
115
+ * the terminal sees is the shell's own, and a deleted workspace falls back to
116
+ * `$HOME` instead of leaving a broken terminal.
117
+ *
118
+ * @param {string} remotePath
119
+ * @returns {string}
120
+ */
121
+ function remoteCommand(remotePath) {
122
+ return `${remoteCd(remotePath)} 2>/dev/null || cd "$HOME"; exec "\${SHELL:-/bin/bash}" -l`
123
+ }
124
+
125
+ /** Absolute Windows path: `D:\x`, `D:/x`, or a `\\server\share` UNC path.
126
+ * These cannot be the operand of a POSIX `cd`. */
127
+ const WINDOWS_REMOTE_PATH = /^(?:[a-zA-Z]:[\\/]|\\\\)/
128
+
129
+ /**
130
+ * Whether a remote workspace path is a Windows one.
131
+ *
132
+ * A Windows remote speaks cmd or PowerShell in its default shell, so the POSIX
133
+ * `cd … || …; exec "$SHELL"` line would fail outright there — `2>/dev/null`,
134
+ * `||` and `exec` are not cmd syntax at all. The marker records no remote
135
+ * platform, but the path form is unambiguous: `/srv/x` and `~/x` are POSIX,
136
+ * while `D:\x` and `\\server\share` are not valid POSIX paths.
137
+ *
138
+ * @param {string} p - `remotePath` from the mirror marker
139
+ * @returns {boolean}
140
+ */
141
+ function isWindowsRemotePath(p) {
142
+ return WINDOWS_REMOTE_PATH.test(String(p || '').trim())
143
+ }
144
+
145
+ /**
146
+ * Argument list (without the ssh binary) for one connection.
147
+ *
148
+ * `-tt` is mandatory: the terminal needs a tty even though a command is given,
149
+ * otherwise the shell comes up non-interactive and every key press is ignored.
150
+ * Options are pushed in order and never spliced between an `-o` and its value —
151
+ * an inserted `-J` there once reached ssh as the value of `-o`, which aborted
152
+ * every connection that used a jump host (issue #21).
153
+ *
154
+ * @param {object} target - `{ host, port, username, alias, remotePath }`
155
+ * @param {object} [machine] - saved connection, for the key and transport hints
156
+ * @returns {string[]}
157
+ */
158
+ function buildSshArgs(target, machine) {
159
+ const args = ['-tt']
160
+ const alias = target.alias || (machine && machine.useSshConfig ? machine.host : '')
161
+ if (alias) {
162
+ args.push(String(alias))
163
+ } else {
164
+ const port = Number(target.port || (machine && machine.port) || 22)
165
+ if (port !== 22) args.push('-p', String(port))
166
+ const key = machine && machine.privateKeyPath
167
+ if (key && !machine.useAgent) args.push('-i', String(key))
168
+ const user = target.username || (machine && machine.username) || ''
169
+ args.push(user ? `${user}@${target.host}` : String(target.host))
170
+ }
171
+ // A Windows workspace cannot be reached with the POSIX line: the remote's
172
+ // default shell may be cmd or PowerShell, and picking one would be a guess.
173
+ // Opening ssh with no command leaves the remote's own default shell in charge,
174
+ // so the terminal still works; only the automatic `cd` is given up.
175
+ if (!isWindowsRemotePath(target.remotePath)) args.push(remoteCommand(target.remotePath))
176
+ return args
177
+ }
178
+
179
+ /**
180
+ * Prefer the OS OpenSSH binary on Windows. A PATH lookup there can reach an
181
+ * MSYS2/git-bash `ssh`, which resolves `~/.ssh` against a different home and
182
+ * makes keys saved by the host half look missing.
183
+ * @param {string} [platform]
184
+ * @param {object} [env]
185
+ * @param {(p: string) => boolean} [exists]
186
+ * @returns {string}
187
+ */
188
+ function sshBinary(platform = process.platform, env = process.env, exists = existsSync) {
189
+ if (platform === 'win32') {
190
+ const system = env.SystemRoot || env.windir || 'C:\\Windows'
191
+ const native = path.join(system, 'System32', 'OpenSSH', 'ssh.exe')
192
+ if (exists(native)) return native
193
+ }
194
+ return 'ssh'
195
+ }
196
+
197
+ /**
198
+ * The shell to fall back to when this directory is not a remote checkout.
199
+ * @param {string} [platform]
200
+ * @param {object} [env]
201
+ * @returns {string}
202
+ */
203
+ function localShell(platform = process.platform, env = process.env) {
204
+ if (platform === 'win32') return env.ComSpec || 'cmd.exe'
205
+ return env.SHELL || '/bin/sh'
206
+ }
207
+
208
+ /**
209
+ * Parse the arguments the launcher passes.
210
+ * @param {string[]} argv
211
+ * @returns {{ machines?: string }}
212
+ */
213
+ function parseArgs(argv) {
214
+ const out = {}
215
+ for (let i = 0; i < argv.length; i += 1) {
216
+ if (argv[i] === '--machines' && argv[i + 1]) {
217
+ out.machines = argv[i + 1]
218
+ i += 1
219
+ }
220
+ }
221
+ return out
222
+ }
223
+
224
+ /**
225
+ * Resolve everything needed to connect from a working directory.
226
+ * @param {{ cwd?: string, machines?: string, exists?: Function, readJsonFile?: Function }} input
227
+ * @returns {{ target?: object, machine?: object, found: boolean }}
228
+ */
229
+ function resolveTarget(input = {}) {
230
+ const cwd = input.cwd || process.cwd()
231
+ const mirror = findMirror(cwd, input)
232
+ if (!mirror) return { found: false }
233
+ const registry = input.machines ? (input.readJsonFile || readJson)(input.machines) : undefined
234
+ const machine = matchMachine(mirror.meta, registry)
235
+ const target = {
236
+ host: mirror.meta.host,
237
+ port: mirror.meta.port || (machine && machine.port) || 22,
238
+ username: mirror.meta.username || (machine && machine.username) || '',
239
+ alias: mirror.meta.alias || '',
240
+ remotePath: mirror.meta.remotePath || (machine && machine.workspace) || '',
241
+ }
242
+ return { found: true, target, machine, dir: mirror.dir }
243
+ }
244
+
245
+ /**
246
+ * Hand the current process over to `file args…`, propagating the exit code.
247
+ * @param {string} file
248
+ * @param {string[]} args
249
+ * @returns {import('node:child_process').ChildProcess}
250
+ */
251
+ function handover(file, args) {
252
+ const child = spawn(file, args, { stdio: 'inherit' })
253
+ child.on('error', (error) => {
254
+ process.stderr.write(`[dsh-remote] cannot run ${file}: ${error && error.message}\n`)
255
+ process.exit(127)
256
+ })
257
+ child.on('exit', (code, signal) => {
258
+ if (signal) process.kill(process.pid, signal)
259
+ else process.exit(code == null ? 0 : code)
260
+ })
261
+ return child
262
+ }
263
+
264
+ /**
265
+ * Entry point: connect, or explain why a local shell was used instead.
266
+ * @param {string[]} [argv]
267
+ * @param {{ cwd?: string, platform?: string, env?: object }} [deps]
268
+ */
269
+ function main(argv = process.argv.slice(2), deps = {}) {
270
+ const platform = deps.platform || process.platform
271
+ const env = deps.env || process.env
272
+ const options = parseArgs(argv)
273
+ const resolved = resolveTarget({ cwd: deps.cwd || process.cwd(), machines: options.machines })
274
+ if (!resolved.found) {
275
+ process.stderr.write('[dsh-remote] this directory is not a remote workspace; opening a local shell.\n')
276
+ process.stderr.write('[dsh-remote] 当前目录不是远程工作区,已打开本地终端。\n')
277
+ return handover(localShell(platform, env), platform === 'win32' ? [] : ['-l'])
278
+ }
279
+ const ssh = sshBinary(platform, env)
280
+ const args = buildSshArgs(resolved.target, resolved.machine)
281
+ const user = resolved.target.username || (resolved.machine && resolved.machine.username) || ''
282
+ process.stderr.write(`[dsh-remote] connecting to ${user ? user + '@' : ''}${resolved.target.host}…\n`)
283
+ if (isWindowsRemotePath(resolved.target.remotePath)) {
284
+ process.stderr.write('[dsh-remote] the remote workspace is a Windows path; opening the remote default shell without changing directory.\n')
285
+ process.stderr.write('[dsh-remote] 远端工作区是 Windows 路径,已打开默认 shell(未自动切换目录)。\n')
286
+ }
287
+ return handover(ssh, args)
288
+ }
289
+
290
+ module.exports = {
291
+ META_FILE,
292
+ buildSshArgs,
293
+ findMirror,
294
+ isWindowsRemotePath,
295
+ localShell,
296
+ main,
297
+ matchMachine,
298
+ parseArgs,
299
+ remoteCd,
300
+ remoteCommand,
301
+ resolveTarget,
302
+ sshBinary,
303
+ }
304
+
305
+ if (require.main === module) main()