@wyxos/zephyr 0.2.21 → 0.2.22

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.
@@ -1,96 +1,99 @@
1
- export function planLaravelDeploymentTasks({
2
- branch,
3
- isLaravel,
4
- changedFiles,
5
- horizonConfigured = false
6
- }) {
7
- const safeChangedFiles = Array.isArray(changedFiles) ? changedFiles : []
8
-
9
- const shouldRunComposer =
10
- isLaravel &&
11
- safeChangedFiles.some(
12
- (file) =>
13
- file === 'composer.json' ||
14
- file === 'composer.lock' ||
15
- file.endsWith('/composer.json') ||
16
- file.endsWith('/composer.lock')
17
- )
18
-
19
- const shouldRunMigrations =
20
- isLaravel &&
21
- safeChangedFiles.some((file) => file.startsWith('database/migrations/') && file.endsWith('.php'))
22
-
23
- const hasPhpChanges = isLaravel && safeChangedFiles.some((file) => file.endsWith('.php'))
24
-
25
- const shouldRunNpmInstall =
26
- isLaravel &&
27
- safeChangedFiles.some(
28
- (file) =>
29
- file === 'package.json' ||
30
- file === 'package-lock.json' ||
31
- file.endsWith('/package.json') ||
32
- file.endsWith('/package-lock.json')
33
- )
34
-
35
- const hasFrontendChanges =
36
- isLaravel &&
37
- safeChangedFiles.some((file) =>
38
- ['.vue', '.css', '.scss', '.js', '.ts', '.tsx', '.less'].some((ext) => file.endsWith(ext))
39
- )
40
-
41
- const shouldRunBuild = isLaravel && (hasFrontendChanges || shouldRunNpmInstall)
42
- const shouldClearCaches = hasPhpChanges
43
- const shouldRestartQueues = hasPhpChanges
44
-
45
- const steps = [
46
- {
47
- label: `Pull latest changes for ${branch}`,
48
- command: `git pull origin ${branch}`
49
- }
50
- ]
51
-
52
- if (shouldRunComposer) {
53
- steps.push({
54
- label: 'Update Composer dependencies',
55
- command: 'composer update --no-dev --no-interaction --prefer-dist'
56
- })
57
- }
58
-
59
- if (shouldRunMigrations) {
60
- steps.push({
61
- label: 'Run database migrations',
62
- command: 'php artisan migrate --force'
63
- })
64
- }
65
-
66
- if (shouldRunNpmInstall) {
67
- steps.push({
68
- label: 'Install Node dependencies',
69
- command: 'npm install'
70
- })
71
- }
72
-
73
- if (shouldRunBuild) {
74
- steps.push({
75
- label: 'Compile frontend assets',
76
- command: 'npm run build'
77
- })
78
- }
79
-
80
- if (shouldClearCaches) {
81
- steps.push({
82
- label: 'Clear Laravel caches',
83
- command: 'php artisan cache:clear && php artisan config:clear && php artisan view:clear'
84
- })
85
- }
86
-
87
- if (shouldRestartQueues) {
88
- steps.push({
89
- label: horizonConfigured ? 'Restart Horizon workers' : 'Restart queue workers',
90
- command: horizonConfigured ? 'php artisan horizon:terminate' : 'php artisan queue:restart'
91
- })
92
- }
93
-
94
- return steps
95
- }
96
-
1
+ export function planLaravelDeploymentTasks({
2
+ branch,
3
+ isLaravel,
4
+ changedFiles,
5
+ horizonConfigured = false,
6
+ phpCommand = 'php'
7
+ }) {
8
+ const safeChangedFiles = Array.isArray(changedFiles) ? changedFiles : []
9
+
10
+ const shouldRunComposer =
11
+ isLaravel &&
12
+ safeChangedFiles.some(
13
+ (file) =>
14
+ file === 'composer.json' ||
15
+ file === 'composer.lock' ||
16
+ file.endsWith('/composer.json') ||
17
+ file.endsWith('/composer.lock')
18
+ )
19
+
20
+ const shouldRunMigrations =
21
+ isLaravel &&
22
+ safeChangedFiles.some((file) => file.startsWith('database/migrations/') && file.endsWith('.php'))
23
+
24
+ const hasPhpChanges = isLaravel && safeChangedFiles.some((file) => file.endsWith('.php'))
25
+
26
+ const shouldRunNpmInstall =
27
+ isLaravel &&
28
+ safeChangedFiles.some(
29
+ (file) =>
30
+ file === 'package.json' ||
31
+ file === 'package-lock.json' ||
32
+ file.endsWith('/package.json') ||
33
+ file.endsWith('/package-lock.json')
34
+ )
35
+
36
+ const hasFrontendChanges =
37
+ isLaravel &&
38
+ safeChangedFiles.some((file) =>
39
+ ['.vue', '.css', '.scss', '.js', '.ts', '.tsx', '.less'].some((ext) => file.endsWith(ext))
40
+ )
41
+
42
+ const shouldRunBuild = isLaravel && (hasFrontendChanges || shouldRunNpmInstall)
43
+ const shouldClearCaches = hasPhpChanges
44
+ const shouldRestartQueues = hasPhpChanges
45
+
46
+ const steps = [
47
+ {
48
+ label: `Pull latest changes for ${branch}`,
49
+ command: `git pull origin ${branch}`
50
+ }
51
+ ]
52
+
53
+ if (shouldRunComposer) {
54
+ // Composer is a PHP script, so we need to run it with the correct PHP version
55
+ // Try composer.phar first, then system composer, ensuring it uses the correct PHP
56
+ steps.push({
57
+ label: 'Update Composer dependencies',
58
+ command: `COMPOSER_ALLOW_SUPERUSER=1 if [ -f composer.phar ]; then ${phpCommand} composer.phar update --no-dev --no-interaction --prefer-dist; elif command -v composer >/dev/null 2>&1; then ${phpCommand} $(command -v composer) update --no-dev --no-interaction --prefer-dist; else ${phpCommand} composer update --no-dev --no-interaction --prefer-dist; fi`
59
+ })
60
+ }
61
+
62
+ if (shouldRunMigrations) {
63
+ steps.push({
64
+ label: 'Run database migrations',
65
+ command: `${phpCommand} artisan migrate --force`
66
+ })
67
+ }
68
+
69
+ if (shouldRunNpmInstall) {
70
+ steps.push({
71
+ label: 'Install Node dependencies',
72
+ command: 'npm install'
73
+ })
74
+ }
75
+
76
+ if (shouldRunBuild) {
77
+ steps.push({
78
+ label: 'Compile frontend assets',
79
+ command: 'npm run build'
80
+ })
81
+ }
82
+
83
+ if (shouldClearCaches) {
84
+ steps.push({
85
+ label: 'Clear Laravel caches',
86
+ command: `${phpCommand} artisan cache:clear && ${phpCommand} artisan config:clear && ${phpCommand} artisan view:clear`
87
+ })
88
+ }
89
+
90
+ if (shouldRestartQueues) {
91
+ steps.push({
92
+ label: horizonConfigured ? 'Restart Horizon workers' : 'Restart queue workers',
93
+ command: horizonConfigured ? `${phpCommand} artisan horizon:terminate` : `${phpCommand} artisan queue:restart`
94
+ })
95
+ }
96
+
97
+ return steps
98
+ }
99
+
@@ -1,162 +1,162 @@
1
- import { readFile } from 'node:fs/promises'
2
- import { fileURLToPath } from 'node:url'
3
- import path from 'node:path'
4
- import { spawn } from 'node:child_process'
5
- import process from 'node:process'
6
- import https from 'node:https'
7
- import semver from 'semver'
8
-
9
- const IS_WINDOWS = process.platform === 'win32'
10
- const ZEPHYR_SKIP_VERSION_CHECK_ENV = 'ZEPHYR_SKIP_VERSION_CHECK'
11
-
12
- async function getCurrentVersion() {
13
- try {
14
- // Try to get version from package.json
15
- // When running via npx, the package.json is in the installed package directory
16
- const packageJsonPath = path.resolve(
17
- path.dirname(fileURLToPath(import.meta.url)),
18
- '..',
19
- 'package.json'
20
- )
21
- const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'))
22
- return packageJson.version
23
- } catch (_error) {
24
- // If we can't read package.json, return null
25
- return null
26
- }
27
- }
28
-
29
- function httpsGetJson(url) {
30
- return new Promise((resolve, reject) => {
31
- const request = https.get(
32
- url,
33
- {
34
- headers: {
35
- accept: 'application/json'
36
- }
37
- },
38
- (response) => {
39
- const { statusCode } = response
40
- if (!statusCode || statusCode < 200 || statusCode >= 300) {
41
- response.resume()
42
- resolve(null)
43
- return
44
- }
45
-
46
- response.setEncoding('utf8')
47
- let raw = ''
48
- response.on('data', (chunk) => {
49
- raw += chunk
50
- })
51
- response.on('end', () => {
52
- try {
53
- resolve(JSON.parse(raw))
54
- } catch (error) {
55
- reject(error)
56
- }
57
- })
58
- }
59
- )
60
-
61
- request.on('error', reject)
62
- request.end()
63
- })
64
- }
65
-
66
- async function getLatestVersion() {
67
- try {
68
- const data = await httpsGetJson('https://registry.npmjs.org/@wyxos/zephyr/latest')
69
- if (!data) {
70
- return null
71
- }
72
- return data.version || null
73
- } catch (_error) {
74
- return null
75
- }
76
- }
77
-
78
- function isNewerVersionAvailable(current, latest) {
79
- if (!current || !latest) {
80
- return false
81
- }
82
-
83
- // Use semver to properly compare versions
84
- try {
85
- return semver.gt(latest, current)
86
- } catch (_error) {
87
- // If semver comparison fails, fall back to simple string comparison
88
- return latest !== current
89
- }
90
- }
91
-
92
- async function reExecuteWithLatest(args) {
93
- // Re-execute with npx @wyxos/zephyr@latest
94
- const command = IS_WINDOWS ? 'npx.cmd' : 'npx'
95
- const npxArgs = ['@wyxos/zephyr@latest', ...args]
96
-
97
- return new Promise((resolve, reject) => {
98
- const child = spawn(command, npxArgs, {
99
- stdio: 'inherit',
100
- env: {
101
- ...process.env,
102
- [ZEPHYR_SKIP_VERSION_CHECK_ENV]: '1'
103
- }
104
- })
105
-
106
- child.on('error', reject)
107
- child.on('close', (code) => {
108
- if (code === 0) {
109
- resolve()
110
- } else {
111
- reject(new Error(`Command exited with code ${code}`))
112
- }
113
- })
114
- })
115
- }
116
-
117
- export async function checkAndUpdateVersion(promptFn, args) {
118
- try {
119
- if (process.env[ZEPHYR_SKIP_VERSION_CHECK_ENV] === '1') {
120
- return false
121
- }
122
-
123
- const currentVersion = await getCurrentVersion()
124
- if (!currentVersion) {
125
- // Can't determine current version, skip check
126
- return false
127
- }
128
-
129
- const latestVersion = await getLatestVersion()
130
- if (!latestVersion) {
131
- // Can't fetch latest version, skip check
132
- return false
133
- }
134
-
135
- if (!isNewerVersionAvailable(currentVersion, latestVersion)) {
136
- // Already on latest or newer
137
- return false
138
- }
139
-
140
- // Newer version available, prompt user
141
- const { shouldUpdate } = await promptFn([
142
- {
143
- type: 'confirm',
144
- name: 'shouldUpdate',
145
- message: `A new version of @wyxos/zephyr is available (${latestVersion}). You are currently on ${currentVersion}. Update and continue?`,
146
- default: true
147
- }
148
- ])
149
-
150
- if (!shouldUpdate) {
151
- return false
152
- }
153
-
154
- // User confirmed, re-execute with latest version
155
- await reExecuteWithLatest(args)
156
- return true // Indicates we've re-executed, so the current process should exit
157
- } catch (_error) {
158
- // If version check fails, just continue with current version
159
- // Don't block the user from using the tool
160
- return false
161
- }
162
- }
1
+ import { readFile } from 'node:fs/promises'
2
+ import { fileURLToPath } from 'node:url'
3
+ import path from 'node:path'
4
+ import { spawn } from 'node:child_process'
5
+ import process from 'node:process'
6
+ import https from 'node:https'
7
+ import semver from 'semver'
8
+
9
+ const IS_WINDOWS = process.platform === 'win32'
10
+ const ZEPHYR_SKIP_VERSION_CHECK_ENV = 'ZEPHYR_SKIP_VERSION_CHECK'
11
+
12
+ async function getCurrentVersion() {
13
+ try {
14
+ // Try to get version from package.json
15
+ // When running via npx, the package.json is in the installed package directory
16
+ const packageJsonPath = path.resolve(
17
+ path.dirname(fileURLToPath(import.meta.url)),
18
+ '..',
19
+ 'package.json'
20
+ )
21
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'))
22
+ return packageJson.version
23
+ } catch (_error) {
24
+ // If we can't read package.json, return null
25
+ return null
26
+ }
27
+ }
28
+
29
+ function httpsGetJson(url) {
30
+ return new Promise((resolve, reject) => {
31
+ const request = https.get(
32
+ url,
33
+ {
34
+ headers: {
35
+ accept: 'application/json'
36
+ }
37
+ },
38
+ (response) => {
39
+ const { statusCode } = response
40
+ if (!statusCode || statusCode < 200 || statusCode >= 300) {
41
+ response.resume()
42
+ resolve(null)
43
+ return
44
+ }
45
+
46
+ response.setEncoding('utf8')
47
+ let raw = ''
48
+ response.on('data', (chunk) => {
49
+ raw += chunk
50
+ })
51
+ response.on('end', () => {
52
+ try {
53
+ resolve(JSON.parse(raw))
54
+ } catch (error) {
55
+ reject(error)
56
+ }
57
+ })
58
+ }
59
+ )
60
+
61
+ request.on('error', reject)
62
+ request.end()
63
+ })
64
+ }
65
+
66
+ async function getLatestVersion() {
67
+ try {
68
+ const data = await httpsGetJson('https://registry.npmjs.org/@wyxos/zephyr/latest')
69
+ if (!data) {
70
+ return null
71
+ }
72
+ return data.version || null
73
+ } catch (_error) {
74
+ return null
75
+ }
76
+ }
77
+
78
+ function isNewerVersionAvailable(current, latest) {
79
+ if (!current || !latest) {
80
+ return false
81
+ }
82
+
83
+ // Use semver to properly compare versions
84
+ try {
85
+ return semver.gt(latest, current)
86
+ } catch (_error) {
87
+ // If semver comparison fails, fall back to simple string comparison
88
+ return latest !== current
89
+ }
90
+ }
91
+
92
+ async function reExecuteWithLatest(args) {
93
+ // Re-execute with npx @wyxos/zephyr@latest
94
+ const command = IS_WINDOWS ? 'npx.cmd' : 'npx'
95
+ const npxArgs = ['@wyxos/zephyr@latest', ...args]
96
+
97
+ return new Promise((resolve, reject) => {
98
+ const child = spawn(command, npxArgs, {
99
+ stdio: 'inherit',
100
+ env: {
101
+ ...process.env,
102
+ [ZEPHYR_SKIP_VERSION_CHECK_ENV]: '1'
103
+ }
104
+ })
105
+
106
+ child.on('error', reject)
107
+ child.on('close', (code) => {
108
+ if (code === 0) {
109
+ resolve()
110
+ } else {
111
+ reject(new Error(`Command exited with code ${code}`))
112
+ }
113
+ })
114
+ })
115
+ }
116
+
117
+ export async function checkAndUpdateVersion(promptFn, args) {
118
+ try {
119
+ if (process.env[ZEPHYR_SKIP_VERSION_CHECK_ENV] === '1') {
120
+ return false
121
+ }
122
+
123
+ const currentVersion = await getCurrentVersion()
124
+ if (!currentVersion) {
125
+ // Can't determine current version, skip check
126
+ return false
127
+ }
128
+
129
+ const latestVersion = await getLatestVersion()
130
+ if (!latestVersion) {
131
+ // Can't fetch latest version, skip check
132
+ return false
133
+ }
134
+
135
+ if (!isNewerVersionAvailable(currentVersion, latestVersion)) {
136
+ // Already on latest or newer
137
+ return false
138
+ }
139
+
140
+ // Newer version available, prompt user
141
+ const { shouldUpdate } = await promptFn([
142
+ {
143
+ type: 'confirm',
144
+ name: 'shouldUpdate',
145
+ message: `A new version of @wyxos/zephyr is available (${latestVersion}). You are currently on ${currentVersion}. Update and continue?`,
146
+ default: true
147
+ }
148
+ ])
149
+
150
+ if (!shouldUpdate) {
151
+ return false
152
+ }
153
+
154
+ // User confirmed, re-execute with latest version
155
+ await reExecuteWithLatest(args)
156
+ return true // Indicates we've re-executed, so the current process should exit
157
+ } catch (_error) {
158
+ // If version check fails, just continue with current version
159
+ // Don't block the user from using the tool
160
+ return false
161
+ }
162
+ }