@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,147 +1,147 @@
|
|
|
1
|
-
import fs from 'node:fs/promises'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
|
|
4
|
-
export async function ensureGitignoreEntry(rootDir, {
|
|
5
|
-
projectConfigDir = '.zephyr',
|
|
6
|
-
runCommand,
|
|
7
|
-
logSuccess,
|
|
8
|
-
logWarning
|
|
9
|
-
} = {}) {
|
|
10
|
-
const gitignorePath = path.join(rootDir, '.gitignore')
|
|
11
|
-
const targetEntry = `${projectConfigDir}/`
|
|
12
|
-
let existingContent = ''
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
existingContent = await fs.readFile(gitignorePath, 'utf8')
|
|
16
|
-
} catch (error) {
|
|
17
|
-
if (error.code !== 'ENOENT') {
|
|
18
|
-
throw error
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const hasEntry = existingContent
|
|
23
|
-
.split(/\r?\n/)
|
|
24
|
-
.some((line) => line.trim() === targetEntry)
|
|
25
|
-
|
|
26
|
-
if (hasEntry) {
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const updatedContent = existingContent
|
|
31
|
-
? `${existingContent.replace(/\s*$/, '')}\n${targetEntry}\n`
|
|
32
|
-
: `${targetEntry}\n`
|
|
33
|
-
|
|
34
|
-
await fs.writeFile(gitignorePath, updatedContent)
|
|
35
|
-
logSuccess?.('Added .zephyr/ to .gitignore')
|
|
36
|
-
|
|
37
|
-
let isGitRepo = false
|
|
38
|
-
try {
|
|
39
|
-
await runCommand('git', ['rev-parse', '--is-inside-work-tree'], {
|
|
40
|
-
silent: true,
|
|
41
|
-
cwd: rootDir
|
|
42
|
-
})
|
|
43
|
-
isGitRepo = true
|
|
44
|
-
} catch (_error) {
|
|
45
|
-
logWarning?.('Not a git repository; skipping commit for .gitignore update.')
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!isGitRepo) {
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
await runCommand('git', ['add', '.gitignore'], { cwd: rootDir })
|
|
54
|
-
await runCommand('git', ['commit', '-m', 'chore: ignore zephyr config'], { cwd: rootDir })
|
|
55
|
-
} catch (error) {
|
|
56
|
-
if (error.exitCode === 1) {
|
|
57
|
-
logWarning?.('Git commit skipped: nothing to commit or pre-commit hook prevented commit.')
|
|
58
|
-
} else {
|
|
59
|
-
throw error
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export async function ensureProjectReleaseScript(rootDir, {
|
|
65
|
-
runPrompt,
|
|
66
|
-
runCommand,
|
|
67
|
-
logSuccess,
|
|
68
|
-
logWarning,
|
|
69
|
-
releaseScriptName = 'release',
|
|
70
|
-
releaseScriptCommand = 'npx @wyxos/zephyr@latest'
|
|
71
|
-
} = {}) {
|
|
72
|
-
const packageJsonPath = path.join(rootDir, 'package.json')
|
|
73
|
-
|
|
74
|
-
let raw
|
|
75
|
-
try {
|
|
76
|
-
raw = await fs.readFile(packageJsonPath, 'utf8')
|
|
77
|
-
} catch (error) {
|
|
78
|
-
if (error.code === 'ENOENT') {
|
|
79
|
-
return false
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
throw error
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let packageJson
|
|
86
|
-
try {
|
|
87
|
-
packageJson = JSON.parse(raw)
|
|
88
|
-
} catch (_error) {
|
|
89
|
-
logWarning?.('Unable to parse package.json; skipping release script injection.')
|
|
90
|
-
return false
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const currentCommand = packageJson?.scripts?.[releaseScriptName]
|
|
94
|
-
|
|
95
|
-
if (currentCommand && currentCommand.includes('@wyxos/zephyr')) {
|
|
96
|
-
return false
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const { installReleaseScript } = await runPrompt([
|
|
100
|
-
{
|
|
101
|
-
type: 'confirm',
|
|
102
|
-
name: 'installReleaseScript',
|
|
103
|
-
message: 'Add "release" script to package.json that runs "npx @wyxos/zephyr@latest"?',
|
|
104
|
-
default: true
|
|
105
|
-
}
|
|
106
|
-
])
|
|
107
|
-
|
|
108
|
-
if (!installReleaseScript) {
|
|
109
|
-
return false
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (!packageJson.scripts || typeof packageJson.scripts !== 'object') {
|
|
113
|
-
packageJson.scripts = {}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
packageJson.scripts[releaseScriptName] = releaseScriptCommand
|
|
117
|
-
|
|
118
|
-
const updatedPayload = `${JSON.stringify(packageJson, null, 2)}\n`
|
|
119
|
-
await fs.writeFile(packageJsonPath, updatedPayload)
|
|
120
|
-
logSuccess?.('Added release script to package.json.')
|
|
121
|
-
|
|
122
|
-
let isGitRepo = false
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
await runCommand('git', ['rev-parse', '--is-inside-work-tree'], { cwd: rootDir, silent: true })
|
|
126
|
-
isGitRepo = true
|
|
127
|
-
} catch (_error) {
|
|
128
|
-
logWarning?.('Not a git repository; skipping commit for release script addition.')
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (isGitRepo) {
|
|
132
|
-
try {
|
|
133
|
-
await runCommand('git', ['add', 'package.json'], { cwd: rootDir, silent: true })
|
|
134
|
-
await runCommand('git', ['commit', '-m', 'chore: add zephyr release script'], { cwd: rootDir, silent: true })
|
|
135
|
-
logSuccess?.('Committed package.json release script addition.')
|
|
136
|
-
} catch (error) {
|
|
137
|
-
if (error.exitCode === 1) {
|
|
138
|
-
logWarning?.('Git commit skipped: nothing to commit or pre-commit hook prevented commit.')
|
|
139
|
-
} else {
|
|
140
|
-
throw error
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return true
|
|
146
|
-
}
|
|
147
|
-
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
export async function ensureGitignoreEntry(rootDir, {
|
|
5
|
+
projectConfigDir = '.zephyr',
|
|
6
|
+
runCommand,
|
|
7
|
+
logSuccess,
|
|
8
|
+
logWarning
|
|
9
|
+
} = {}) {
|
|
10
|
+
const gitignorePath = path.join(rootDir, '.gitignore')
|
|
11
|
+
const targetEntry = `${projectConfigDir}/`
|
|
12
|
+
let existingContent = ''
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
existingContent = await fs.readFile(gitignorePath, 'utf8')
|
|
16
|
+
} catch (error) {
|
|
17
|
+
if (error.code !== 'ENOENT') {
|
|
18
|
+
throw error
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const hasEntry = existingContent
|
|
23
|
+
.split(/\r?\n/)
|
|
24
|
+
.some((line) => line.trim() === targetEntry)
|
|
25
|
+
|
|
26
|
+
if (hasEntry) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const updatedContent = existingContent
|
|
31
|
+
? `${existingContent.replace(/\s*$/, '')}\n${targetEntry}\n`
|
|
32
|
+
: `${targetEntry}\n`
|
|
33
|
+
|
|
34
|
+
await fs.writeFile(gitignorePath, updatedContent)
|
|
35
|
+
logSuccess?.('Added .zephyr/ to .gitignore')
|
|
36
|
+
|
|
37
|
+
let isGitRepo = false
|
|
38
|
+
try {
|
|
39
|
+
await runCommand('git', ['rev-parse', '--is-inside-work-tree'], {
|
|
40
|
+
silent: true,
|
|
41
|
+
cwd: rootDir
|
|
42
|
+
})
|
|
43
|
+
isGitRepo = true
|
|
44
|
+
} catch (_error) {
|
|
45
|
+
logWarning?.('Not a git repository; skipping commit for .gitignore update.')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!isGitRepo) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
await runCommand('git', ['add', '.gitignore'], { cwd: rootDir })
|
|
54
|
+
await runCommand('git', ['commit', '-m', 'chore: ignore zephyr config'], { cwd: rootDir })
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error.exitCode === 1) {
|
|
57
|
+
logWarning?.('Git commit skipped: nothing to commit or pre-commit hook prevented commit.')
|
|
58
|
+
} else {
|
|
59
|
+
throw error
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function ensureProjectReleaseScript(rootDir, {
|
|
65
|
+
runPrompt,
|
|
66
|
+
runCommand,
|
|
67
|
+
logSuccess,
|
|
68
|
+
logWarning,
|
|
69
|
+
releaseScriptName = 'release',
|
|
70
|
+
releaseScriptCommand = 'npx @wyxos/zephyr@latest'
|
|
71
|
+
} = {}) {
|
|
72
|
+
const packageJsonPath = path.join(rootDir, 'package.json')
|
|
73
|
+
|
|
74
|
+
let raw
|
|
75
|
+
try {
|
|
76
|
+
raw = await fs.readFile(packageJsonPath, 'utf8')
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error.code === 'ENOENT') {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
throw error
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let packageJson
|
|
86
|
+
try {
|
|
87
|
+
packageJson = JSON.parse(raw)
|
|
88
|
+
} catch (_error) {
|
|
89
|
+
logWarning?.('Unable to parse package.json; skipping release script injection.')
|
|
90
|
+
return false
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const currentCommand = packageJson?.scripts?.[releaseScriptName]
|
|
94
|
+
|
|
95
|
+
if (currentCommand && currentCommand.includes('@wyxos/zephyr')) {
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const { installReleaseScript } = await runPrompt([
|
|
100
|
+
{
|
|
101
|
+
type: 'confirm',
|
|
102
|
+
name: 'installReleaseScript',
|
|
103
|
+
message: 'Add "release" script to package.json that runs "npx @wyxos/zephyr@latest"?',
|
|
104
|
+
default: true
|
|
105
|
+
}
|
|
106
|
+
])
|
|
107
|
+
|
|
108
|
+
if (!installReleaseScript) {
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!packageJson.scripts || typeof packageJson.scripts !== 'object') {
|
|
113
|
+
packageJson.scripts = {}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
packageJson.scripts[releaseScriptName] = releaseScriptCommand
|
|
117
|
+
|
|
118
|
+
const updatedPayload = `${JSON.stringify(packageJson, null, 2)}\n`
|
|
119
|
+
await fs.writeFile(packageJsonPath, updatedPayload)
|
|
120
|
+
logSuccess?.('Added release script to package.json.')
|
|
121
|
+
|
|
122
|
+
let isGitRepo = false
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
await runCommand('git', ['rev-parse', '--is-inside-work-tree'], { cwd: rootDir, silent: true })
|
|
126
|
+
isGitRepo = true
|
|
127
|
+
} catch (_error) {
|
|
128
|
+
logWarning?.('Not a git repository; skipping commit for release script addition.')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (isGitRepo) {
|
|
132
|
+
try {
|
|
133
|
+
await runCommand('git', ['add', 'package.json'], { cwd: rootDir, silent: true })
|
|
134
|
+
await runCommand('git', ['commit', '-m', 'chore: add zephyr release script'], { cwd: rootDir, silent: true })
|
|
135
|
+
logSuccess?.('Committed package.json release script addition.')
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error.exitCode === 1) {
|
|
138
|
+
logWarning?.('Git commit skipped: nothing to commit or pre-commit hook prevented commit.')
|
|
139
|
+
} else {
|
|
140
|
+
throw error
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
export function createLocalCommandRunners({ runCommandBase, runCommandCaptureBase }) {
|
|
2
|
-
if (!runCommandBase || !runCommandCaptureBase) {
|
|
3
|
-
throw new Error('createLocalCommandRunners requires runCommandBase and runCommandCaptureBase')
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const runCommand = async (command, args, { silent = false, cwd } = {}) => {
|
|
7
|
-
const stdio = silent ? 'ignore' : 'inherit'
|
|
8
|
-
return runCommandBase(command, args, { cwd, stdio })
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const runCommandCapture = async (command, args, { cwd } = {}) => {
|
|
12
|
-
const { stdout } = await runCommandCaptureBase(command, args, { cwd })
|
|
13
|
-
return stdout
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return { runCommand, runCommandCapture }
|
|
17
|
-
}
|
|
18
|
-
|
|
1
|
+
export function createLocalCommandRunners({ runCommandBase, runCommandCaptureBase }) {
|
|
2
|
+
if (!runCommandBase || !runCommandCaptureBase) {
|
|
3
|
+
throw new Error('createLocalCommandRunners requires runCommandBase and runCommandCaptureBase')
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const runCommand = async (command, args, { silent = false, cwd } = {}) => {
|
|
7
|
+
const stdio = silent ? 'ignore' : 'inherit'
|
|
8
|
+
return runCommandBase(command, args, { cwd, stdio })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const runCommandCapture = async (command, args, { cwd } = {}) => {
|
|
12
|
+
const { stdout } = await runCommandCaptureBase(command, args, { cwd })
|
|
13
|
+
return stdout
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return { runCommand, runCommandCapture }
|
|
17
|
+
}
|
|
18
|
+
|
package/src/runtime/prompt.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export function createRunPrompt({ inquirer }) {
|
|
2
|
-
if (!inquirer) {
|
|
3
|
-
throw new Error('createRunPrompt requires inquirer')
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
return async function runPrompt(questions) {
|
|
7
|
-
if (typeof globalThis !== 'undefined' && globalThis.__zephyrPrompt) {
|
|
8
|
-
return globalThis.__zephyrPrompt(questions)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return inquirer.prompt(questions)
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
1
|
+
export function createRunPrompt({ inquirer }) {
|
|
2
|
+
if (!inquirer) {
|
|
3
|
+
throw new Error('createRunPrompt requires inquirer')
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return async function runPrompt(questions) {
|
|
7
|
+
if (typeof globalThis !== 'undefined' && globalThis.__zephyrPrompt) {
|
|
8
|
+
return globalThis.__zephyrPrompt(questions)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return inquirer.prompt(questions)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export function createSshClientFactory({ NodeSSH }) {
|
|
2
|
-
if (!NodeSSH) {
|
|
3
|
-
throw new Error('createSshClientFactory requires NodeSSH')
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
return function createSshClient() {
|
|
7
|
-
if (typeof globalThis !== 'undefined' && globalThis.__zephyrSSHFactory) {
|
|
8
|
-
return globalThis.__zephyrSSHFactory()
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return new NodeSSH()
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
1
|
+
export function createSshClientFactory({ NodeSSH }) {
|
|
2
|
+
if (!NodeSSH) {
|
|
3
|
+
throw new Error('createSshClientFactory requires NodeSSH')
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return function createSshClient() {
|
|
7
|
+
if (typeof globalThis !== 'undefined' && globalThis.__zephyrSSHFactory) {
|
|
8
|
+
return globalThis.__zephyrSSHFactory()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return new NodeSSH()
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
package/src/ssh/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export {
|
|
2
|
-
connectToServer,
|
|
3
|
-
executeRemoteCommand,
|
|
4
|
-
readRemoteFile,
|
|
5
|
-
downloadRemoteFile,
|
|
6
|
-
deleteRemoteFile
|
|
7
|
-
} from './ssh.mjs'
|
|
8
|
-
|
|
1
|
+
export {
|
|
2
|
+
connectToServer,
|
|
3
|
+
executeRemoteCommand,
|
|
4
|
+
readRemoteFile,
|
|
5
|
+
downloadRemoteFile,
|
|
6
|
+
deleteRemoteFile
|
|
7
|
+
} from './ssh.mjs'
|
|
8
|
+
|