@wyxos/zephyr 0.5.0 → 0.7.4

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 CHANGED
@@ -40,12 +40,21 @@ Common workflows:
40
40
  # Deploy an app using the saved preset or the interactive prompts
41
41
  zephyr
42
42
 
43
- # Deploy an app and bump the local npm package version first
43
+ # Deploy an app with a local npm package version bump
44
44
  zephyr minor
45
45
 
46
+ # Deploy an app while bypassing Zephyr's built-in local checks
47
+ zephyr minor --skip-checks
48
+
46
49
  # Deploy a configured app non-interactively
47
50
  zephyr --non-interactive --preset wyxos-release --maintenance off
48
51
 
52
+ # Deploy a configured app non-interactively and auto-commit dirty changes
53
+ zephyr --non-interactive --preset wyxos-release --auto-commit
54
+
55
+ # Deploy without mutating the local package version
56
+ zephyr --non-interactive --preset wyxos-release --skip-versioning
57
+
49
58
  # Resume a pending non-interactive deployment
50
59
  zephyr --non-interactive --preset wyxos-release --resume-pending --maintenance off
51
60
 
@@ -60,6 +69,10 @@ zephyr --type node minor
60
69
 
61
70
  # Release a Packagist package
62
71
  zephyr --type packagist patch
72
+
73
+ # Release the current package/composer version without bumping version files
74
+ zephyr --type node --skip-versioning
75
+ zephyr --type packagist --skip-versioning
63
76
  ```
64
77
 
65
78
  When `--type node` or `--type vue` is used without a bump argument, Zephyr defaults to `patch`.
@@ -74,7 +87,7 @@ Non-interactive mode is strict and is intended for already-configured projects:
74
87
 
75
88
  - `--non-interactive` fails instead of prompting
76
89
  - app deployments require `--preset <name>`
77
- - Laravel app deployments require `--maintenance on|off` unless resuming a saved snapshot that already contains the choice
90
+ - Laravel app deployments require either a saved preset maintenance preference, `--maintenance on|off`, or a resumable snapshot that already contains the choice
78
91
  - pending deployment snapshots require either `--resume-pending` or `--discard-pending`
79
92
  - stale remote locks are never auto-removed in non-interactive mode
80
93
  - `--json` is only supported together with `--non-interactive`
@@ -91,7 +104,11 @@ If Zephyr would normally prompt to:
91
104
 
92
105
  then non-interactive mode stops immediately with a clear error instead.
93
106
 
94
- For Laravel app deployments, `--maintenance on|off` overrides the maintenance prompt when you want an explicit choice instead of an interactive confirm.
107
+ For Laravel app deployments, `--maintenance on|off` overrides both the saved preset preference and the maintenance prompt when you want an explicit choice for the current run.
108
+
109
+ `--auto-commit` is available for app deployments and tells Zephyr to let local Codex inspect the repo and generate the dirty-tree commit message instead of prompting for one.
110
+
111
+ `--skip-versioning` keeps Zephyr from mutating `package.json` or `composer.json`. On app deploys it skips the local npm version bump step. On package release workflows it releases the version already present in the manifest and creates the release tag from the current `HEAD`.
95
112
 
96
113
  ## AI Agents and Automation
97
114
 
@@ -155,6 +172,8 @@ npm run release
155
172
  - `npm run release` is the recommended app/package entrypoint once the release script has been installed.
156
173
  - For `--type node` workflows, Zephyr runs your project's `lint` script when present.
157
174
  - For `--type node` workflows, Zephyr runs `test:run` or `test` when present.
175
+ - For fresh Laravel app deploys, Zephyr runs local lint/test checks before creating the version-bump commit so failed checks do not force repeated bump retries.
176
+ - For critical app deploys, `--skip-checks` is shorthand for `--skip-lint --skip-tests`. It skips Zephyr's built-in local checks, but any local `pre-push` hook can still run its own checks during git push unless you also opt into `--skip-git-hooks`.
158
177
  - For non-interactive app deploys, use a saved preset name instead of relying on prompt fallback.
159
178
 
160
179
  ## Features
@@ -209,7 +228,15 @@ Deployment targets are stored per-project at `.zephyr/config.json`:
209
228
  {
210
229
  "name": "prod-main",
211
230
  "appId": "app_def456",
212
- "branch": "main"
231
+ "branch": "main",
232
+ "options": {
233
+ "maintenanceMode": true,
234
+ "skipGitHooks": false,
235
+ "skipTests": false,
236
+ "skipLint": false,
237
+ "skipVersioning": false,
238
+ "autoCommit": true
239
+ }
213
240
  }
214
241
  ],
215
242
  "apps": [
@@ -226,6 +253,8 @@ Deployment targets are stored per-project at `.zephyr/config.json`:
226
253
  }
227
254
  ```
228
255
 
256
+ Preset `options` capture repeatable deploy behavior so Zephyr can reuse the same maintenance, dirty-tree, and deploy-check preferences on later runs.
257
+
229
258
  ### Project Directory Structure
230
259
 
231
260
  Zephyr creates a `.zephyr/` directory in your project with:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wyxos/zephyr",
3
- "version": "0.5.0",
3
+ "version": "0.7.4",
4
4
  "description": "A streamlined deployment tool for web applications with intelligent Laravel project detection",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -23,12 +23,6 @@ export async function selectPreset({
23
23
  const branch = preset.branch || app.branch || 'unknown'
24
24
  displayName = `${preset.name} (${serverName} → ${app.projectPath} [${branch}])`
25
25
  }
26
- } else if (preset.key) {
27
- const keyParts = preset.key.split(':')
28
- const serverName = keyParts[0]
29
- const projectPath = keyParts[1]
30
- const branch = preset.branch || (keyParts.length === 3 ? keyParts[2] : 'unknown')
31
- displayName = `${preset.name} (${serverName} → ${projectPath} [${branch}])`
32
26
  }
33
27
 
34
28
  return {
@@ -1,6 +1,11 @@
1
1
  import {writeStdoutLine} from '../../utils/output.mjs'
2
2
  import {loadServers} from '../../config/servers.mjs'
3
3
  import {loadProjectConfig, removePreset, saveProjectConfig} from '../../config/project.mjs'
4
+ import {
5
+ buildPresetOptionsFromExecutionMode,
6
+ normalizePresetOptions,
7
+ presetOptionsEqual
8
+ } from '../../config/preset-options.mjs'
4
9
  import {ZephyrError} from '../../runtime/errors.mjs'
5
10
 
6
11
  function findPresetByName(projectConfig, presetName) {
@@ -8,6 +13,56 @@ function findPresetByName(projectConfig, presetName) {
8
13
  return presets.find((entry) => entry?.name === presetName) ?? null
9
14
  }
10
15
 
16
+ function createPresetState(rootDir, projectConfig, preset, {
17
+ logSuccess
18
+ } = {}) {
19
+ if (!preset) {
20
+ return null
21
+ }
22
+
23
+ return {
24
+ name: preset.name,
25
+ get options() {
26
+ return normalizePresetOptions(preset.options)
27
+ },
28
+ async saveOptions(nextOptions, {
29
+ message = null
30
+ } = {}) {
31
+ const normalizedOptions = normalizePresetOptions(nextOptions)
32
+
33
+ if (presetOptionsEqual(preset.options, normalizedOptions)) {
34
+ return false
35
+ }
36
+
37
+ preset.options = normalizedOptions
38
+ await saveProjectConfig(rootDir, projectConfig)
39
+
40
+ if (message) {
41
+ logSuccess?.(message)
42
+ }
43
+
44
+ return true
45
+ },
46
+ async applyExecutionMode(executionMode = {}) {
47
+ const nextOptions = buildPresetOptionsFromExecutionMode(executionMode, preset.options)
48
+ return await this.saveOptions(nextOptions)
49
+ }
50
+ }
51
+ }
52
+
53
+ async function promptPresetAutoCommit(runPrompt, enabledByDefault = false) {
54
+ const {autoCommitPreference} = await runPrompt([
55
+ {
56
+ type: 'input',
57
+ name: 'autoCommitPreference',
58
+ message: 'Enable auto-commit for dirty changes on this preset? Leave blank for manual commit prompts.',
59
+ default: enabledByDefault ? 'enabled' : ''
60
+ }
61
+ ])
62
+
63
+ return typeof autoCommitPreference === 'string' && autoCommitPreference.trim().length > 0
64
+ }
65
+
11
66
  function resolvePresetNonInteractive(projectConfig, servers, preset, presetName) {
12
67
  if (!preset) {
13
68
  throw new ZephyrError(
@@ -18,8 +73,8 @@ function resolvePresetNonInteractive(projectConfig, servers, preset, presetName)
18
73
 
19
74
  if (!preset.appId) {
20
75
  throw new ZephyrError(
21
- `Zephyr cannot run non-interactively because preset "${preset.name || presetName}" uses a legacy or invalid format. Rerun interactively once to repair .zephyr/config.json.`,
22
- {code: 'ZEPHYR_PRESET_REPAIR_REQUIRED'}
76
+ `Zephyr cannot run non-interactively because preset "${preset.name || presetName}" is invalid.`,
77
+ {code: 'ZEPHYR_PRESET_INVALID'}
23
78
  )
24
79
  }
25
80
 
@@ -72,6 +127,7 @@ export async function selectDeploymentTarget(rootDir, {
72
127
 
73
128
  let server = null
74
129
  let appConfig = null
130
+ let activePreset = null
75
131
  let isCreatingNewPreset = false
76
132
 
77
133
  const preset = nonInteractive
@@ -95,11 +151,11 @@ export async function selectDeploymentTarget(rootDir, {
95
151
  }
96
152
 
97
153
  if (nonInteractive) {
154
+ activePreset = preset
98
155
  const resolved = resolvePresetNonInteractive(projectConfig, servers, preset, executionMode.presetName)
99
156
  server = resolved.server
100
- appConfig = resolved.appConfig
101
157
  appConfig = {
102
- ...appConfig,
158
+ ...resolved.appConfig,
103
159
  branch: resolved.branch
104
160
  }
105
161
  } else if (preset === 'create') {
@@ -107,64 +163,29 @@ export async function selectDeploymentTarget(rootDir, {
107
163
  server = await configurationService.selectServer(servers)
108
164
  appConfig = await configurationService.selectApp(projectConfig, server, rootDir)
109
165
  } else if (preset) {
110
- if (preset.appId) {
111
- appConfig = projectConfig.apps?.find((app) => app.id === preset.appId)
166
+ activePreset = preset
167
+ appConfig = projectConfig.apps?.find((app) => app.id === preset.appId)
112
168
 
113
- if (!appConfig) {
114
- logWarning?.('Preset references an application that no longer exists. Creating a new configuration instead.')
115
- await removeInvalidPreset()
116
- server = await configurationService.selectServer(servers)
117
- appConfig = await configurationService.selectApp(projectConfig, server, rootDir)
118
- } else {
119
- server = servers.find((entry) => entry.id === appConfig.serverId || entry.serverName === appConfig.serverName)
120
-
121
- if (!server) {
122
- logWarning?.('Preset references a server that no longer exists. Creating a new configuration instead.')
123
- await removeInvalidPreset()
124
- server = await configurationService.selectServer(servers)
125
- appConfig = await configurationService.selectApp(projectConfig, server, rootDir)
126
- } else if (preset.branch && appConfig.branch !== preset.branch) {
127
- appConfig.branch = preset.branch
128
- await saveProjectConfig(rootDir, projectConfig)
129
- logSuccess?.(`Updated branch to ${preset.branch} from preset.`)
130
- }
131
- }
132
- } else if (preset.key) {
133
- const keyParts = preset.key.split(':')
134
- const serverName = keyParts[0]
135
- const projectPath = keyParts[1]
136
- const presetBranch = preset.branch || (keyParts.length === 3 ? keyParts[2] : null)
137
-
138
- server = servers.find((entry) => entry.serverName === serverName)
169
+ if (!appConfig) {
170
+ logWarning?.('Preset references an application that no longer exists. Creating a new configuration instead.')
171
+ await removeInvalidPreset()
172
+ activePreset = null
173
+ server = await configurationService.selectServer(servers)
174
+ appConfig = await configurationService.selectApp(projectConfig, server, rootDir)
175
+ } else {
176
+ server = servers.find((entry) => entry.id === appConfig.serverId || entry.serverName === appConfig.serverName)
139
177
 
140
178
  if (!server) {
141
- logWarning?.(`Preset references server "${serverName}" which no longer exists. Creating a new configuration instead.`)
179
+ logWarning?.('Preset references a server that no longer exists. Creating a new configuration instead.')
142
180
  await removeInvalidPreset()
181
+ activePreset = null
143
182
  server = await configurationService.selectServer(servers)
144
183
  appConfig = await configurationService.selectApp(projectConfig, server, rootDir)
145
- } else {
146
- appConfig = projectConfig.apps?.find(
147
- (app) => (app.serverId === server.id || app.serverName === serverName) && app.projectPath === projectPath
148
- )
149
-
150
- if (!appConfig) {
151
- logWarning?.('Preset references an application that no longer exists. Creating a new configuration instead.')
152
- await removeInvalidPreset()
153
- appConfig = await configurationService.selectApp(projectConfig, server, rootDir)
154
- } else {
155
- preset.appId = appConfig.id
156
- if (presetBranch && appConfig.branch !== presetBranch) {
157
- appConfig.branch = presetBranch
158
- }
159
- preset.branch = appConfig.branch
160
- await saveProjectConfig(rootDir, projectConfig)
161
- }
184
+ } else if (preset.branch && appConfig.branch !== preset.branch) {
185
+ appConfig.branch = preset.branch
186
+ await saveProjectConfig(rootDir, projectConfig)
187
+ logSuccess?.(`Updated branch to ${preset.branch} from preset.`)
162
188
  }
163
- } else {
164
- logWarning?.('Preset format is invalid. Creating a new configuration instead.')
165
- await removeInvalidPreset()
166
- server = await configurationService.selectServer(servers)
167
- appConfig = await configurationService.selectApp(projectConfig, server, rootDir)
168
189
  }
169
190
  } else {
170
191
  server = await configurationService.selectServer(servers)
@@ -173,7 +194,7 @@ export async function selectDeploymentTarget(rootDir, {
173
194
 
174
195
  if (nonInteractive && (!appConfig?.sshUser || !appConfig?.sshKey)) {
175
196
  throw new ZephyrError(
176
- `Zephyr cannot run non-interactively because preset "${preset?.name || executionMode.presetName}" is missing SSH details.`,
197
+ `Zephyr cannot run non-interactively because preset "${activePreset?.name || executionMode.presetName}" is missing SSH details.`,
177
198
  {code: 'ZEPHYR_SSH_DETAILS_REQUIRED'}
178
199
  )
179
200
  }
@@ -207,7 +228,7 @@ export async function selectDeploymentTarget(rootDir, {
207
228
  writeStdoutLine(JSON.stringify(deploymentConfig, null, 2))
208
229
  }
209
230
 
210
- if (!nonInteractive && (isCreatingNewPreset || !preset)) {
231
+ if (!nonInteractive && (isCreatingNewPreset || !activePreset)) {
211
232
  const {presetName} = await runPrompt([
212
233
  {
213
234
  type: 'input',
@@ -220,31 +241,47 @@ export async function selectDeploymentTarget(rootDir, {
220
241
  const trimmedName = presetName?.trim()
221
242
 
222
243
  if (trimmedName && trimmedName.length > 0) {
223
- const presets = projectConfig.presets ?? []
224
244
  const appId = appConfig.id
225
245
 
226
246
  if (!appId) {
227
247
  logWarning?.('Cannot save preset: app configuration missing ID.')
228
248
  } else {
229
- const existingIndex = presets.findIndex((entry) => entry.appId === appId)
230
-
231
- if (existingIndex >= 0) {
232
- presets[existingIndex].name = trimmedName
233
- presets[existingIndex].branch = deploymentConfig.branch
234
- } else {
235
- presets.push({
236
- name: trimmedName,
237
- appId,
238
- branch: deploymentConfig.branch
239
- })
249
+ const existingPreset = findPresetByName(projectConfig, trimmedName)
250
+ const autoCommitEnabled = await promptPresetAutoCommit(
251
+ runPrompt,
252
+ executionMode.autoCommit === true || existingPreset?.options?.autoCommit === true
253
+ )
254
+ const nextPreset = existingPreset ?? {
255
+ name: trimmedName,
256
+ appId,
257
+ branch: deploymentConfig.branch,
258
+ options: normalizePresetOptions()
259
+ }
260
+
261
+ nextPreset.name = trimmedName
262
+ nextPreset.appId = appId
263
+ nextPreset.branch = deploymentConfig.branch
264
+ nextPreset.options = normalizePresetOptions({
265
+ ...buildPresetOptionsFromExecutionMode(executionMode, nextPreset.options),
266
+ autoCommit: autoCommitEnabled
267
+ })
268
+
269
+ if (!existingPreset) {
270
+ projectConfig.presets = [...(projectConfig.presets ?? []), nextPreset]
240
271
  }
241
272
 
242
- projectConfig.presets = presets
243
273
  await saveProjectConfig(rootDir, projectConfig)
244
274
  logSuccess?.(`Saved preset "${trimmedName}" to .zephyr/config.json`)
275
+ activePreset = nextPreset
245
276
  }
246
277
  }
247
278
  }
248
279
 
249
- return {deploymentConfig, projectConfig}
280
+ return {
281
+ deploymentConfig,
282
+ projectConfig,
283
+ presetState: createPresetState(rootDir, projectConfig, activePreset, {
284
+ logSuccess
285
+ })
286
+ }
250
287
  }
@@ -235,6 +235,7 @@ async function resolveMaintenanceMode({
235
235
  snapshot,
236
236
  remoteIsLaravel,
237
237
  runPrompt,
238
+ persistPresetOptions,
238
239
  executionMode = {}
239
240
  } = {}) {
240
241
  if (!remoteIsLaravel) {
@@ -269,7 +270,14 @@ async function resolveMaintenanceMode({
269
270
  }
270
271
  ])
271
272
 
272
- return Boolean(answers?.enableMaintenanceMode)
273
+ const maintenanceModeEnabled = Boolean(answers?.enableMaintenanceMode)
274
+ await persistPresetOptions?.({
275
+ maintenanceMode: maintenanceModeEnabled
276
+ }, {
277
+ message: 'Saved maintenance mode preference to the selected preset.'
278
+ })
279
+
280
+ return maintenanceModeEnabled
273
281
  }
274
282
 
275
283
  async function resolveMaintenanceModePlan({
@@ -333,6 +341,7 @@ async function resolveMaintenanceModePlan({
333
341
  export async function resolveRemoteDeploymentState({
334
342
  snapshot,
335
343
  executionMode = {},
344
+ persistPresetOptions,
336
345
  ssh,
337
346
  remoteCwd,
338
347
  runPrompt,
@@ -351,6 +360,7 @@ export async function resolveRemoteDeploymentState({
351
360
  snapshot,
352
361
  remoteIsLaravel,
353
362
  runPrompt,
363
+ persistPresetOptions,
354
364
  executionMode
355
365
  })
356
366
 
@@ -365,6 +375,7 @@ export async function buildRemoteDeploymentPlan({
365
375
  snapshot = null,
366
376
  requiredPhpVersion = null,
367
377
  executionMode = {},
378
+ persistPresetOptions,
368
379
  remoteIsLaravel = null,
369
380
  maintenanceModeEnabled = null,
370
381
  ssh,
@@ -384,6 +395,7 @@ export async function buildRemoteDeploymentPlan({
384
395
  : await resolveRemoteDeploymentState({
385
396
  snapshot,
386
397
  executionMode,
398
+ persistPresetOptions,
387
399
  ssh,
388
400
  remoteCwd,
389
401
  runPrompt,
@@ -1,3 +1,24 @@
1
+ const FRONTEND_BUILD_EXTENSIONS = [
2
+ '.vue',
3
+ '.css',
4
+ '.scss',
5
+ '.js',
6
+ '.jsx',
7
+ '.mjs',
8
+ '.cjs',
9
+ '.ts',
10
+ '.tsx',
11
+ '.less',
12
+ '.svg',
13
+ '.png',
14
+ '.jpg',
15
+ '.jpeg',
16
+ '.gif',
17
+ '.webp',
18
+ '.avif',
19
+ '.ico'
20
+ ]
21
+
1
22
  export function planLaravelDeploymentTasks({
2
23
  branch,
3
24
  isLaravel,
@@ -39,7 +60,7 @@ export function planLaravelDeploymentTasks({
39
60
  const hasFrontendChanges =
40
61
  isLaravel &&
41
62
  safeChangedFiles.some((file) =>
42
- ['.vue', '.css', '.scss', '.js', '.ts', '.tsx', '.less'].some((ext) => file.endsWith(ext))
63
+ FRONTEND_BUILD_EXTENSIONS.some((ext) => file.endsWith(ext))
43
64
  )
44
65
 
45
66
  const shouldRunBuild = isLaravel && (hasFrontendChanges || shouldRunNpmInstall)
@@ -116,4 +137,4 @@ export function planLaravelDeploymentTasks({
116
137
  }
117
138
 
118
139
  return steps
119
- }
140
+ }
@@ -10,6 +10,10 @@ export async function prepareLocalDeployment(config, {
10
10
  rootDir = process.cwd(),
11
11
  versionArg = null,
12
12
  skipGitHooks = false,
13
+ skipTests = false,
14
+ skipLint = false,
15
+ skipVersioning = false,
16
+ autoCommit = false,
13
17
  runPrompt,
14
18
  runCommand,
15
19
  runCommandCapture,
@@ -24,26 +28,51 @@ export async function prepareLocalDeployment(config, {
24
28
  logProcessing,
25
29
  logSuccess,
26
30
  logWarning,
27
- skipGitHooks
31
+ skipGitHooks,
32
+ autoCommit
28
33
  })
29
34
 
30
35
  const context = await resolveLocalDeploymentContext(rootDir)
31
36
  const checkSupport = await resolveLocalDeploymentCheckSupport({
32
37
  rootDir,
33
38
  isLaravel: context.isLaravel,
39
+ skipTests,
40
+ skipLint,
34
41
  runCommandCapture
35
42
  })
36
43
 
37
44
  if (!snapshot && context.isLaravel) {
38
- await bumpLocalPackageVersion(rootDir, {
39
- versionArg,
45
+ await runLocalDeploymentChecks({
46
+ rootDir,
47
+ isLaravel: context.isLaravel,
48
+ hasHook: context.hasHook,
40
49
  skipGitHooks,
50
+ skipTests,
51
+ skipLint,
52
+ forceRunWhenHookPresent: true,
41
53
  runCommand,
54
+ runCommandCapture,
42
55
  logProcessing,
43
56
  logSuccess,
44
- logWarning
57
+ logWarning,
58
+ lintCommand: checkSupport.lintCommand,
59
+ buildCommand: checkSupport.buildCommand,
60
+ testCommand: checkSupport.testCommand
45
61
  })
46
62
 
63
+ if (skipVersioning) {
64
+ logWarning?.('Skipping deployment version update because --skip-versioning flag was provided.')
65
+ } else {
66
+ await bumpLocalPackageVersion(rootDir, {
67
+ versionArg,
68
+ skipGitHooks,
69
+ runCommand,
70
+ logProcessing,
71
+ logSuccess,
72
+ logWarning
73
+ })
74
+ }
75
+
47
76
  await ensureCommittedChangesPushed(config.branch, rootDir, {
48
77
  runCommand,
49
78
  runCommandCapture,
@@ -52,6 +81,8 @@ export async function prepareLocalDeployment(config, {
52
81
  logWarning,
53
82
  skipGitHooks
54
83
  })
84
+
85
+ return context
55
86
  }
56
87
 
57
88
  await runLocalDeploymentChecks({
@@ -59,12 +90,15 @@ export async function prepareLocalDeployment(config, {
59
90
  isLaravel: context.isLaravel,
60
91
  hasHook: context.hasHook,
61
92
  skipGitHooks,
93
+ skipTests,
94
+ skipLint,
62
95
  runCommand,
63
96
  runCommandCapture,
64
97
  logProcessing,
65
98
  logSuccess,
66
99
  logWarning,
67
100
  lintCommand: checkSupport.lintCommand,
101
+ buildCommand: checkSupport.buildCommand,
68
102
  testCommand: checkSupport.testCommand
69
103
  })
70
104
 
@@ -248,7 +248,8 @@ export async function runDeployment(config, options = {}) {
248
248
  snapshot = null,
249
249
  rootDir = process.cwd(),
250
250
  versionArg = null,
251
- context
251
+ context,
252
+ presetState = null
252
253
  } = options
253
254
 
254
255
  const {
@@ -366,6 +367,10 @@ export async function runDeployment(config, options = {}) {
366
367
  rootDir,
367
368
  versionArg,
368
369
  skipGitHooks: executionMode?.skipGitHooks === true,
370
+ skipTests: executionMode?.skipTests === true,
371
+ skipLint: executionMode?.skipLint === true,
372
+ skipVersioning: executionMode?.skipVersioning === true,
373
+ autoCommit: executionMode?.autoCommit === true,
369
374
  runPrompt,
370
375
  runCommand,
371
376
  runCommandCapture: context.runCommandCapture,
@@ -410,6 +415,7 @@ export async function runDeployment(config, options = {}) {
410
415
  rootDir,
411
416
  requiredPhpVersion,
412
417
  executionMode,
418
+ persistPresetOptions: presetState?.saveOptions,
413
419
  remoteIsLaravel: remoteState?.remoteIsLaravel,
414
420
  maintenanceModeEnabled: remoteState?.maintenanceModeEnabled,
415
421
  ssh,