@wyxos/zephyr 0.2.21 → 0.2.23
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 +144 -144
- package/bin/zephyr.mjs +29 -29
- package/package.json +58 -58
- package/src/config/project.mjs +118 -118
- package/src/config/servers.mjs +57 -57
- package/src/dependency-scanner.mjs +412 -433
- package/src/deploy/local-repo.mjs +215 -215
- package/src/deploy/locks.mjs +171 -171
- package/src/deploy/preflight.mjs +117 -117
- package/src/deploy/remote-exec.mjs +99 -99
- package/src/deploy/snapshots.mjs +35 -35
- package/src/index.mjs +91 -91
- package/src/main.mjs +677 -652
- package/src/project/bootstrap.mjs +147 -147
- package/src/runtime/local-command.mjs +18 -18
- package/src/runtime/prompt.mjs +14 -14
- package/src/runtime/ssh-client.mjs +14 -14
- package/src/ssh/index.mjs +8 -8
- package/src/ssh/keys.mjs +146 -146
- package/src/ssh/ssh.mjs +134 -134
- package/src/utils/command.mjs +92 -92
- package/src/utils/config-flow.mjs +284 -284
- package/src/utils/git.mjs +91 -91
- package/src/utils/id.mjs +6 -6
- package/src/utils/log-file.mjs +76 -76
- package/src/utils/output.mjs +29 -29
- package/src/utils/paths.mjs +28 -28
- package/src/utils/php-version.mjs +137 -0
- package/src/utils/remote-path.mjs +23 -23
- package/src/utils/task-planner.mjs +99 -96
- package/src/version-checker.mjs +162 -162
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
function escapeForDoubleQuotes(value) {
|
|
2
|
-
return value.replace(/(["\\$`])/g, '\\$1')
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
function escapeForSingleQuotes(value) {
|
|
6
|
-
return value.replace(/'/g, "'\\''")
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function createProfileBootstrap() {
|
|
10
|
-
return [
|
|
11
|
-
'if [ -f "$HOME/.profile" ]; then . "$HOME/.profile"; fi',
|
|
12
|
-
'if [ -f "$HOME/.bash_profile" ]; then . "$HOME/.bash_profile"; fi',
|
|
13
|
-
'if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc"; fi',
|
|
14
|
-
'if [ -f "$HOME/.zprofile" ]; then . "$HOME/.zprofile"; fi',
|
|
15
|
-
'if [ -f "$HOME/.zshrc" ]; then . "$HOME/.zshrc"; fi',
|
|
16
|
-
'if [ -s "$HOME/.nvm/nvm.sh" ]; then . "$HOME/.nvm/nvm.sh"; fi',
|
|
17
|
-
'if [ -s "$HOME/.config/nvm/nvm.sh" ]; then . "$HOME/.config/nvm/nvm.sh"; fi',
|
|
18
|
-
'if [ -s "/usr/local/opt/nvm/nvm.sh" ]; then . "/usr/local/opt/nvm/nvm.sh"; fi',
|
|
19
|
-
'if command -v npm >/dev/null 2>&1; then :',
|
|
20
|
-
'elif [ -d "$HOME/.nvm/versions/node" ]; then NODE_VERSION=$(ls -1 "$HOME/.nvm/versions/node" | tail -1) && export PATH="$HOME/.nvm/versions/node/$NODE_VERSION/bin:$PATH"',
|
|
21
|
-
'elif [ -d "/usr/local/lib/node_modules/npm/bin" ]; then export PATH="/usr/local/lib/node_modules/npm/bin:$PATH"',
|
|
22
|
-
'elif [ -d "/opt/homebrew/bin" ] && [ -f "/opt/homebrew/bin/npm" ]; then export PATH="/opt/homebrew/bin:$PATH"',
|
|
23
|
-
'elif [ -d "/usr/local/bin" ] && [ -f "/usr/local/bin/npm" ]; then export PATH="/usr/local/bin:$PATH"',
|
|
24
|
-
'elif [ -d "$HOME/.local/bin" ] && [ -f "$HOME/.local/bin/npm" ]; then export PATH="$HOME/.local/bin:$PATH"',
|
|
25
|
-
'fi'
|
|
26
|
-
].join('; ')
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function createRemoteExecutor({ ssh, rootDir, remoteCwd, writeToLogFile, logProcessing, logSuccess, logError }) {
|
|
30
|
-
const profileBootstrap = createProfileBootstrap()
|
|
31
|
-
|
|
32
|
-
return async function executeRemote(label, command, options = {}) {
|
|
33
|
-
const {
|
|
34
|
-
cwd = remoteCwd,
|
|
35
|
-
allowFailure = false,
|
|
36
|
-
bootstrapEnv = true,
|
|
37
|
-
env = {}
|
|
38
|
-
// printStdout: legacy option, intentionally ignored (we log to file)
|
|
39
|
-
} = options
|
|
40
|
-
|
|
41
|
-
logProcessing?.(`\n→ ${label}`)
|
|
42
|
-
|
|
43
|
-
let wrappedCommand = command
|
|
44
|
-
let execOptions = { cwd }
|
|
45
|
-
|
|
46
|
-
let envExports = ''
|
|
47
|
-
if (env && Object.keys(env).length > 0) {
|
|
48
|
-
envExports = Object.entries(env)
|
|
49
|
-
.map(([key, value]) => `${key}='${escapeForSingleQuotes(String(value))}'`)
|
|
50
|
-
.join(' ') + ' '
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (bootstrapEnv && cwd) {
|
|
54
|
-
const cwdForShell = escapeForDoubleQuotes(cwd)
|
|
55
|
-
wrappedCommand = `${profileBootstrap}; cd "${cwdForShell}" && ${envExports}${command}`
|
|
56
|
-
execOptions = {}
|
|
57
|
-
} else if (envExports) {
|
|
58
|
-
wrappedCommand = `${envExports}${command}`
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const result = await ssh.execCommand(wrappedCommand, execOptions)
|
|
62
|
-
|
|
63
|
-
if (result.stdout && result.stdout.trim()) {
|
|
64
|
-
await writeToLogFile(rootDir, `[${label}] STDOUT:\n${result.stdout.trim()}`)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (result.stderr && result.stderr.trim()) {
|
|
68
|
-
await writeToLogFile(rootDir, `[${label}] STDERR:\n${result.stderr.trim()}`)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (result.code !== 0) {
|
|
72
|
-
if (result.stdout && result.stdout.trim()) {
|
|
73
|
-
logError?.(`\n[${label}] Output:\n${result.stdout.trim()}`)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (result.stderr && result.stderr.trim()) {
|
|
77
|
-
logError?.(`\n[${label}] Error:\n${result.stderr.trim()}`)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (result.code !== 0 && !allowFailure) {
|
|
82
|
-
const stderr = result.stderr?.trim() ?? ''
|
|
83
|
-
if (/command not found/.test(stderr) || /is not recognized/.test(stderr)) {
|
|
84
|
-
throw new Error(
|
|
85
|
-
`Command failed: ${command}. Ensure the remote environment loads required tools for non-interactive shells (e.g. export PATH in profile scripts).`
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
throw new Error(`Command failed: ${command}`)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (result.code === 0) {
|
|
93
|
-
logSuccess?.(`✓ ${command}`)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return result
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
1
|
+
function escapeForDoubleQuotes(value) {
|
|
2
|
+
return value.replace(/(["\\$`])/g, '\\$1')
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function escapeForSingleQuotes(value) {
|
|
6
|
+
return value.replace(/'/g, "'\\''")
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function createProfileBootstrap() {
|
|
10
|
+
return [
|
|
11
|
+
'if [ -f "$HOME/.profile" ]; then . "$HOME/.profile"; fi',
|
|
12
|
+
'if [ -f "$HOME/.bash_profile" ]; then . "$HOME/.bash_profile"; fi',
|
|
13
|
+
'if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc"; fi',
|
|
14
|
+
'if [ -f "$HOME/.zprofile" ]; then . "$HOME/.zprofile"; fi',
|
|
15
|
+
'if [ -f "$HOME/.zshrc" ]; then . "$HOME/.zshrc"; fi',
|
|
16
|
+
'if [ -s "$HOME/.nvm/nvm.sh" ]; then . "$HOME/.nvm/nvm.sh"; fi',
|
|
17
|
+
'if [ -s "$HOME/.config/nvm/nvm.sh" ]; then . "$HOME/.config/nvm/nvm.sh"; fi',
|
|
18
|
+
'if [ -s "/usr/local/opt/nvm/nvm.sh" ]; then . "/usr/local/opt/nvm/nvm.sh"; fi',
|
|
19
|
+
'if command -v npm >/dev/null 2>&1; then :',
|
|
20
|
+
'elif [ -d "$HOME/.nvm/versions/node" ]; then NODE_VERSION=$(ls -1 "$HOME/.nvm/versions/node" | tail -1) && export PATH="$HOME/.nvm/versions/node/$NODE_VERSION/bin:$PATH"',
|
|
21
|
+
'elif [ -d "/usr/local/lib/node_modules/npm/bin" ]; then export PATH="/usr/local/lib/node_modules/npm/bin:$PATH"',
|
|
22
|
+
'elif [ -d "/opt/homebrew/bin" ] && [ -f "/opt/homebrew/bin/npm" ]; then export PATH="/opt/homebrew/bin:$PATH"',
|
|
23
|
+
'elif [ -d "/usr/local/bin" ] && [ -f "/usr/local/bin/npm" ]; then export PATH="/usr/local/bin:$PATH"',
|
|
24
|
+
'elif [ -d "$HOME/.local/bin" ] && [ -f "$HOME/.local/bin/npm" ]; then export PATH="$HOME/.local/bin:$PATH"',
|
|
25
|
+
'fi'
|
|
26
|
+
].join('; ')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function createRemoteExecutor({ ssh, rootDir, remoteCwd, writeToLogFile, logProcessing, logSuccess, logError }) {
|
|
30
|
+
const profileBootstrap = createProfileBootstrap()
|
|
31
|
+
|
|
32
|
+
return async function executeRemote(label, command, options = {}) {
|
|
33
|
+
const {
|
|
34
|
+
cwd = remoteCwd,
|
|
35
|
+
allowFailure = false,
|
|
36
|
+
bootstrapEnv = true,
|
|
37
|
+
env = {}
|
|
38
|
+
// printStdout: legacy option, intentionally ignored (we log to file)
|
|
39
|
+
} = options
|
|
40
|
+
|
|
41
|
+
logProcessing?.(`\n→ ${label}`)
|
|
42
|
+
|
|
43
|
+
let wrappedCommand = command
|
|
44
|
+
let execOptions = { cwd }
|
|
45
|
+
|
|
46
|
+
let envExports = ''
|
|
47
|
+
if (env && Object.keys(env).length > 0) {
|
|
48
|
+
envExports = Object.entries(env)
|
|
49
|
+
.map(([key, value]) => `${key}='${escapeForSingleQuotes(String(value))}'`)
|
|
50
|
+
.join(' ') + ' '
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (bootstrapEnv && cwd) {
|
|
54
|
+
const cwdForShell = escapeForDoubleQuotes(cwd)
|
|
55
|
+
wrappedCommand = `${profileBootstrap}; cd "${cwdForShell}" && ${envExports}${command}`
|
|
56
|
+
execOptions = {}
|
|
57
|
+
} else if (envExports) {
|
|
58
|
+
wrappedCommand = `${envExports}${command}`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const result = await ssh.execCommand(wrappedCommand, execOptions)
|
|
62
|
+
|
|
63
|
+
if (result.stdout && result.stdout.trim()) {
|
|
64
|
+
await writeToLogFile(rootDir, `[${label}] STDOUT:\n${result.stdout.trim()}`)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (result.stderr && result.stderr.trim()) {
|
|
68
|
+
await writeToLogFile(rootDir, `[${label}] STDERR:\n${result.stderr.trim()}`)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (result.code !== 0) {
|
|
72
|
+
if (result.stdout && result.stdout.trim()) {
|
|
73
|
+
logError?.(`\n[${label}] Output:\n${result.stdout.trim()}`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (result.stderr && result.stderr.trim()) {
|
|
77
|
+
logError?.(`\n[${label}] Error:\n${result.stderr.trim()}`)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (result.code !== 0 && !allowFailure) {
|
|
82
|
+
const stderr = result.stderr?.trim() ?? ''
|
|
83
|
+
if (/command not found/.test(stderr) || /is not recognized/.test(stderr)) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Command failed: ${command}. Ensure the remote environment loads required tools for non-interactive shells (e.g. export PATH in profile scripts).`
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
throw new Error(`Command failed: ${command}`)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (result.code === 0) {
|
|
93
|
+
logSuccess?.(`✓ ${command}`)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
package/src/deploy/snapshots.mjs
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import fs from 'node:fs/promises'
|
|
2
|
-
import { ensureDirectory, getPendingTasksPath, getProjectConfigDir } from '../utils/paths.mjs'
|
|
3
|
-
|
|
4
|
-
export async function loadPendingTasksSnapshot(rootDir) {
|
|
5
|
-
const snapshotPath = getPendingTasksPath(rootDir)
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const raw = await fs.readFile(snapshotPath, 'utf8')
|
|
9
|
-
return JSON.parse(raw)
|
|
10
|
-
} catch (error) {
|
|
11
|
-
if (error.code === 'ENOENT') {
|
|
12
|
-
return null
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
throw error
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function savePendingTasksSnapshot(rootDir, snapshot) {
|
|
20
|
-
const configDir = getProjectConfigDir(rootDir)
|
|
21
|
-
await ensureDirectory(configDir)
|
|
22
|
-
const payload = `${JSON.stringify(snapshot, null, 2)}\n`
|
|
23
|
-
await fs.writeFile(getPendingTasksPath(rootDir), payload)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function clearPendingTasksSnapshot(rootDir) {
|
|
27
|
-
try {
|
|
28
|
-
await fs.unlink(getPendingTasksPath(rootDir))
|
|
29
|
-
} catch (error) {
|
|
30
|
-
if (error.code !== 'ENOENT') {
|
|
31
|
-
throw error
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import { ensureDirectory, getPendingTasksPath, getProjectConfigDir } from '../utils/paths.mjs'
|
|
3
|
+
|
|
4
|
+
export async function loadPendingTasksSnapshot(rootDir) {
|
|
5
|
+
const snapshotPath = getPendingTasksPath(rootDir)
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
const raw = await fs.readFile(snapshotPath, 'utf8')
|
|
9
|
+
return JSON.parse(raw)
|
|
10
|
+
} catch (error) {
|
|
11
|
+
if (error.code === 'ENOENT') {
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
throw error
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function savePendingTasksSnapshot(rootDir, snapshot) {
|
|
20
|
+
const configDir = getProjectConfigDir(rootDir)
|
|
21
|
+
await ensureDirectory(configDir)
|
|
22
|
+
const payload = `${JSON.stringify(snapshot, null, 2)}\n`
|
|
23
|
+
await fs.writeFile(getPendingTasksPath(rootDir), payload)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function clearPendingTasksSnapshot(rootDir) {
|
|
27
|
+
try {
|
|
28
|
+
await fs.unlink(getPendingTasksPath(rootDir))
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.code !== 'ENOENT') {
|
|
31
|
+
throw error
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
package/src/index.mjs
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
|
-
import inquirer from 'inquirer'
|
|
3
|
-
import { NodeSSH } from 'node-ssh'
|
|
4
|
-
|
|
5
|
-
import { createChalkLogger } from './utils/output.mjs'
|
|
6
|
-
import { runCommand as runCommandBase, runCommandCapture as runCommandCaptureBase } from './utils/command.mjs'
|
|
7
|
-
import { createLocalCommandRunners } from './runtime/local-command.mjs'
|
|
8
|
-
import { createRunPrompt } from './runtime/prompt.mjs'
|
|
9
|
-
import { createSshClientFactory } from './runtime/ssh-client.mjs'
|
|
10
|
-
import { generateId } from './utils/id.mjs'
|
|
11
|
-
|
|
12
|
-
import { loadServers as loadServersImpl, saveServers } from './config/servers.mjs'
|
|
13
|
-
import { loadProjectConfig as loadProjectConfigImpl, saveProjectConfig } from './config/project.mjs'
|
|
14
|
-
import * as configFlow from './utils/config-flow.mjs'
|
|
15
|
-
import * as sshKeys from './ssh/keys.mjs'
|
|
16
|
-
import { writeToLogFile } from './utils/log-file.mjs'
|
|
17
|
-
|
|
18
|
-
export { main, runRemoteTasks } from './main.mjs'
|
|
19
|
-
export { connectToServer, executeRemoteCommand, readRemoteFile, downloadRemoteFile, deleteRemoteFile } from './ssh/index.mjs'
|
|
20
|
-
|
|
21
|
-
const { logProcessing, logSuccess, logWarning, logError } = createChalkLogger(chalk)
|
|
22
|
-
const runPrompt = createRunPrompt({ inquirer })
|
|
23
|
-
const { runCommand, runCommandCapture } = createLocalCommandRunners({
|
|
24
|
-
runCommandBase,
|
|
25
|
-
runCommandCaptureBase
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
// Keep this aligned with main's test injection behavior
|
|
29
|
-
const createSshClient = createSshClientFactory({ NodeSSH })
|
|
30
|
-
|
|
31
|
-
export { logProcessing, logSuccess, logWarning, logError, runCommand, runCommandCapture, writeToLogFile, createSshClient }
|
|
32
|
-
|
|
33
|
-
export async function loadServers() {
|
|
34
|
-
return await loadServersImpl({ logSuccess, logWarning })
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function loadProjectConfig(rootDir, servers) {
|
|
38
|
-
return await loadProjectConfigImpl(rootDir, servers, { logSuccess, logWarning })
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function defaultProjectPath(currentDir) {
|
|
42
|
-
return configFlow.defaultProjectPath(currentDir)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export async function listGitBranches(currentDir) {
|
|
46
|
-
return await configFlow.listGitBranches(currentDir, { runCommandCapture, logWarning })
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function promptSshDetails(currentDir, existing = {}) {
|
|
50
|
-
return await sshKeys.promptSshDetails(currentDir, existing, { runPrompt })
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function promptServerDetails(existingServers = []) {
|
|
54
|
-
return await configFlow.promptServerDetails(existingServers, { runPrompt, generateId })
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export async function selectServer(servers) {
|
|
58
|
-
return await configFlow.selectServer(servers, {
|
|
59
|
-
runPrompt,
|
|
60
|
-
logProcessing,
|
|
61
|
-
logSuccess,
|
|
62
|
-
saveServers,
|
|
63
|
-
promptServerDetails
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function promptAppDetails(currentDir, existing = {}) {
|
|
68
|
-
return await configFlow.promptAppDetails(currentDir, existing, {
|
|
69
|
-
runPrompt,
|
|
70
|
-
listGitBranches,
|
|
71
|
-
defaultProjectPath,
|
|
72
|
-
promptSshDetails
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export async function selectApp(projectConfig, server, currentDir) {
|
|
77
|
-
return await configFlow.selectApp(projectConfig, server, currentDir, {
|
|
78
|
-
runPrompt,
|
|
79
|
-
logWarning,
|
|
80
|
-
logProcessing,
|
|
81
|
-
logSuccess,
|
|
82
|
-
saveProjectConfig,
|
|
83
|
-
generateId,
|
|
84
|
-
promptAppDetails
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export async function selectPreset(projectConfig, servers) {
|
|
89
|
-
return await configFlow.selectPreset(projectConfig, servers, { runPrompt })
|
|
90
|
-
}
|
|
91
|
-
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import inquirer from 'inquirer'
|
|
3
|
+
import { NodeSSH } from 'node-ssh'
|
|
4
|
+
|
|
5
|
+
import { createChalkLogger } from './utils/output.mjs'
|
|
6
|
+
import { runCommand as runCommandBase, runCommandCapture as runCommandCaptureBase } from './utils/command.mjs'
|
|
7
|
+
import { createLocalCommandRunners } from './runtime/local-command.mjs'
|
|
8
|
+
import { createRunPrompt } from './runtime/prompt.mjs'
|
|
9
|
+
import { createSshClientFactory } from './runtime/ssh-client.mjs'
|
|
10
|
+
import { generateId } from './utils/id.mjs'
|
|
11
|
+
|
|
12
|
+
import { loadServers as loadServersImpl, saveServers } from './config/servers.mjs'
|
|
13
|
+
import { loadProjectConfig as loadProjectConfigImpl, saveProjectConfig } from './config/project.mjs'
|
|
14
|
+
import * as configFlow from './utils/config-flow.mjs'
|
|
15
|
+
import * as sshKeys from './ssh/keys.mjs'
|
|
16
|
+
import { writeToLogFile } from './utils/log-file.mjs'
|
|
17
|
+
|
|
18
|
+
export { main, runRemoteTasks } from './main.mjs'
|
|
19
|
+
export { connectToServer, executeRemoteCommand, readRemoteFile, downloadRemoteFile, deleteRemoteFile } from './ssh/index.mjs'
|
|
20
|
+
|
|
21
|
+
const { logProcessing, logSuccess, logWarning, logError } = createChalkLogger(chalk)
|
|
22
|
+
const runPrompt = createRunPrompt({ inquirer })
|
|
23
|
+
const { runCommand, runCommandCapture } = createLocalCommandRunners({
|
|
24
|
+
runCommandBase,
|
|
25
|
+
runCommandCaptureBase
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Keep this aligned with main's test injection behavior
|
|
29
|
+
const createSshClient = createSshClientFactory({ NodeSSH })
|
|
30
|
+
|
|
31
|
+
export { logProcessing, logSuccess, logWarning, logError, runCommand, runCommandCapture, writeToLogFile, createSshClient }
|
|
32
|
+
|
|
33
|
+
export async function loadServers() {
|
|
34
|
+
return await loadServersImpl({ logSuccess, logWarning })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function loadProjectConfig(rootDir, servers) {
|
|
38
|
+
return await loadProjectConfigImpl(rootDir, servers, { logSuccess, logWarning })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function defaultProjectPath(currentDir) {
|
|
42
|
+
return configFlow.defaultProjectPath(currentDir)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function listGitBranches(currentDir) {
|
|
46
|
+
return await configFlow.listGitBranches(currentDir, { runCommandCapture, logWarning })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function promptSshDetails(currentDir, existing = {}) {
|
|
50
|
+
return await sshKeys.promptSshDetails(currentDir, existing, { runPrompt })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function promptServerDetails(existingServers = []) {
|
|
54
|
+
return await configFlow.promptServerDetails(existingServers, { runPrompt, generateId })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function selectServer(servers) {
|
|
58
|
+
return await configFlow.selectServer(servers, {
|
|
59
|
+
runPrompt,
|
|
60
|
+
logProcessing,
|
|
61
|
+
logSuccess,
|
|
62
|
+
saveServers,
|
|
63
|
+
promptServerDetails
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function promptAppDetails(currentDir, existing = {}) {
|
|
68
|
+
return await configFlow.promptAppDetails(currentDir, existing, {
|
|
69
|
+
runPrompt,
|
|
70
|
+
listGitBranches,
|
|
71
|
+
defaultProjectPath,
|
|
72
|
+
promptSshDetails
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function selectApp(projectConfig, server, currentDir) {
|
|
77
|
+
return await configFlow.selectApp(projectConfig, server, currentDir, {
|
|
78
|
+
runPrompt,
|
|
79
|
+
logWarning,
|
|
80
|
+
logProcessing,
|
|
81
|
+
logSuccess,
|
|
82
|
+
saveProjectConfig,
|
|
83
|
+
generateId,
|
|
84
|
+
promptAppDetails
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function selectPreset(projectConfig, servers) {
|
|
89
|
+
return await configFlow.selectPreset(projectConfig, servers, { runPrompt })
|
|
90
|
+
}
|
|
91
|
+
|