@wyxos/zephyr 0.6.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/src/main.mjs CHANGED
@@ -11,6 +11,7 @@ import * as bootstrap from './project/bootstrap.mjs'
11
11
  import {getErrorCode, ZephyrError} from './runtime/errors.mjs'
12
12
  import {PROJECT_CONFIG_DIR} from './utils/paths.mjs'
13
13
  import {writeStderrLine} from './utils/output.mjs'
14
+ import {mergeDeployOptions} from './config/preset-options.mjs'
14
15
  import {createAppContext} from './runtime/app-context.mjs'
15
16
  import {createConfigurationService} from './application/configuration/service.mjs'
16
17
  import {selectDeploymentTarget} from './application/configuration/select-deployment-target.mjs'
@@ -35,12 +36,21 @@ function normalizeMainOptions(firstArg = null, secondArg = null) {
35
36
  resumePending: firstArg.resumePending === true,
36
37
  discardPending: firstArg.discardPending === true,
37
38
  maintenanceMode: firstArg.maintenanceMode ?? null,
39
+ autoCommit: firstArg.autoCommit === true,
40
+ skipVersioning: firstArg.skipVersioning === true,
38
41
  skipGitHooks: firstArg.skipGitHooks === true,
39
42
  skipChecks: firstArg.skipChecks === true,
40
43
  skipTests: firstArg.skipTests === true || firstArg.skipChecks === true,
41
44
  skipLint: firstArg.skipLint === true || firstArg.skipChecks === true,
42
45
  skipBuild: firstArg.skipBuild === true,
43
46
  skipDeploy: firstArg.skipDeploy === true,
47
+ explicitMaintenanceMode: firstArg.explicitMaintenanceMode === true || 'maintenanceMode' in firstArg,
48
+ explicitAutoCommit: firstArg.explicitAutoCommit === true || 'autoCommit' in firstArg,
49
+ explicitSkipVersioning: firstArg.explicitSkipVersioning === true || 'skipVersioning' in firstArg,
50
+ explicitSkipGitHooks: firstArg.explicitSkipGitHooks === true || 'skipGitHooks' in firstArg,
51
+ explicitSkipChecks: firstArg.explicitSkipChecks === true || 'skipChecks' in firstArg,
52
+ explicitSkipTests: firstArg.explicitSkipTests === true || 'skipTests' in firstArg || 'skipChecks' in firstArg,
53
+ explicitSkipLint: firstArg.explicitSkipLint === true || 'skipLint' in firstArg || 'skipChecks' in firstArg,
44
54
  context: firstArg.context ?? null
45
55
  }
46
56
  }
@@ -54,12 +64,21 @@ function normalizeMainOptions(firstArg = null, secondArg = null) {
54
64
  resumePending: false,
55
65
  discardPending: false,
56
66
  maintenanceMode: null,
67
+ autoCommit: false,
68
+ skipVersioning: false,
57
69
  skipGitHooks: false,
58
70
  skipChecks: false,
59
71
  skipTests: false,
60
72
  skipLint: false,
61
73
  skipBuild: false,
62
74
  skipDeploy: false,
75
+ explicitMaintenanceMode: false,
76
+ explicitAutoCommit: false,
77
+ explicitSkipVersioning: false,
78
+ explicitSkipGitHooks: false,
79
+ explicitSkipChecks: false,
80
+ explicitSkipTests: false,
81
+ explicitSkipLint: false,
63
82
  context: null
64
83
  }
65
84
  }
@@ -110,12 +129,21 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
110
129
  workflow: resolveWorkflowName(options.workflowType),
111
130
  presetName: options.presetName,
112
131
  maintenanceMode: options.maintenanceMode,
132
+ autoCommit: options.autoCommit === true,
133
+ skipVersioning: options.skipVersioning === true,
113
134
  skipGitHooks: options.skipGitHooks === true,
114
135
  skipChecks: options.skipChecks === true,
115
136
  skipTests: options.skipTests === true,
116
137
  skipLint: options.skipLint === true,
117
138
  resumePending: options.resumePending,
118
- discardPending: options.discardPending
139
+ discardPending: options.discardPending,
140
+ explicitMaintenanceMode: options.explicitMaintenanceMode === true,
141
+ explicitAutoCommit: options.explicitAutoCommit === true,
142
+ explicitSkipVersioning: options.explicitSkipVersioning === true,
143
+ explicitSkipGitHooks: options.explicitSkipGitHooks === true,
144
+ explicitSkipChecks: options.explicitSkipChecks === true,
145
+ explicitSkipTests: options.explicitSkipTests === true,
146
+ explicitSkipLint: options.explicitSkipLint === true
119
147
  }
120
148
  const appContext = options.context ?? createAppContext({executionMode})
121
149
  const {
@@ -127,7 +155,11 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
127
155
  runCommand,
128
156
  emitEvent
129
157
  } = appContext
130
- const currentExecutionMode = appContext.executionMode ?? executionMode
158
+ let currentExecutionMode = {
159
+ ...executionMode,
160
+ ...(appContext.executionMode ?? {})
161
+ }
162
+ appContext.executionMode = currentExecutionMode
131
163
  const configurationService = createConfigurationService(appContext)
132
164
 
133
165
  try {
@@ -142,6 +174,8 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
142
174
  nonInteractive: currentExecutionMode.interactive === false,
143
175
  presetName: currentExecutionMode.presetName,
144
176
  maintenanceMode: currentExecutionMode.maintenanceMode,
177
+ autoCommit: currentExecutionMode.autoCommit === true,
178
+ skipVersioning: currentExecutionMode.skipVersioning === true,
145
179
  skipGitHooks: currentExecutionMode.skipGitHooks === true,
146
180
  skipChecks: currentExecutionMode.skipChecks === true,
147
181
  skipTests: currentExecutionMode.skipTests === true,
@@ -170,6 +204,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
170
204
  skipGitHooks: options.skipGitHooks,
171
205
  skipTests: options.skipTests,
172
206
  skipLint: options.skipLint,
207
+ skipVersioning: options.skipVersioning,
173
208
  skipBuild: options.skipBuild,
174
209
  skipDeploy: options.skipDeploy,
175
210
  context: appContext
@@ -198,6 +233,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
198
233
  skipGitHooks: options.skipGitHooks,
199
234
  skipTests: options.skipTests,
200
235
  skipLint: options.skipLint,
236
+ skipVersioning: options.skipVersioning,
201
237
  context: appContext
202
238
  })
203
239
  emitEvent?.('run_completed', {
@@ -249,7 +285,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
249
285
  })
250
286
  }
251
287
 
252
- const {deploymentConfig} = await selectDeploymentTarget(rootDir, {
288
+ const {deploymentConfig, presetState} = await selectDeploymentTarget(rootDir, {
253
289
  configurationService,
254
290
  runPrompt,
255
291
  logProcessing,
@@ -259,6 +295,19 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
259
295
  executionMode: currentExecutionMode
260
296
  })
261
297
 
298
+ if (presetState) {
299
+ const effectiveDeployOptions = mergeDeployOptions(currentExecutionMode, presetState.options)
300
+ currentExecutionMode = {
301
+ ...currentExecutionMode,
302
+ presetName: presetState.name,
303
+ ...effectiveDeployOptions,
304
+ skipChecks: currentExecutionMode.skipChecks === true ||
305
+ (effectiveDeployOptions.skipTests === true && effectiveDeployOptions.skipLint === true)
306
+ }
307
+ appContext.executionMode = currentExecutionMode
308
+ await presetState.applyExecutionMode(currentExecutionMode)
309
+ }
310
+
262
311
  const snapshotToUse = await resolvePendingSnapshot(rootDir, deploymentConfig, {
263
312
  runPrompt,
264
313
  logProcessing,
@@ -270,7 +319,8 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
270
319
  rootDir,
271
320
  snapshot: snapshotToUse,
272
321
  versionArg: options.versionArg,
273
- context: appContext
322
+ context: appContext,
323
+ presetState
274
324
  })
275
325
 
276
326
  emitEvent?.('run_completed', {
@@ -24,8 +24,6 @@ const GENERIC_SUBJECT_PATTERNS = [
24
24
  /^(improve|update|adjust|refine|align|support|enable)\s+.+\s+(workflow|process|flow)$/i
25
25
  ]
26
26
  const MAX_WORKING_TREE_PREVIEW = 20
27
- const MAX_DIFF_EXCERPT_LINES = 60
28
- const MAX_DIFF_EXCERPT_CHARS = 4000
29
27
  const STATUS_LABELS = {
30
28
  A: 'added',
31
29
  C: 'copied',
@@ -35,59 +33,6 @@ const STATUS_LABELS = {
35
33
  T: 'type-changed',
36
34
  U: 'conflicted'
37
35
  }
38
- const TOPIC_STOP_WORDS = new Set([
39
- 'src',
40
- 'test',
41
- 'tests',
42
- '__tests__',
43
- 'spec',
44
- 'specs',
45
- 'app',
46
- 'lib',
47
- 'dist',
48
- 'packages',
49
- 'package',
50
- 'application',
51
- 'shared',
52
- 'index',
53
- 'main',
54
- 'local',
55
- 'repo',
56
- 'prepare',
57
- 'commit',
58
- 'message',
59
- 'js',
60
- 'jsx',
61
- 'ts',
62
- 'tsx',
63
- 'mjs',
64
- 'cjs',
65
- 'php',
66
- 'json',
67
- 'yaml',
68
- 'yml',
69
- 'md',
70
- 'toml',
71
- 'lock'
72
- ])
73
-
74
- function buildTargetedFallbackCommitMessage(statusEntries = []) {
75
- const paths = statusEntries.map((entry) => entry.path.toLowerCase())
76
- const touchesDeployPrep = paths.some((pathValue) => pathValue.includes('prepare-local-deployment'))
77
- const touchesLocalRepo = paths.some((pathValue) => pathValue.includes('local-repo'))
78
- const touchesCommitMessage = paths.some((pathValue) => pathValue.includes('commit-message'))
79
- const touchesReleaseFlow = paths.some((pathValue) => pathValue.includes('/release/') || pathValue.includes('release-'))
80
-
81
- if (touchesDeployPrep && touchesLocalRepo) {
82
- return 'fix: prompt for dirty deploy changes before version bump'
83
- }
84
-
85
- if (touchesCommitMessage && touchesReleaseFlow) {
86
- return 'fix: tighten release commit suggestions'
87
- }
88
-
89
- return null
90
- }
91
36
 
92
37
  function resolveWorkingTreeEntryLabel(entry) {
93
38
  if (entry.indexStatus === '?' && entry.worktreeStatus === '?') {
@@ -108,32 +53,6 @@ function resolveWorkingTreeEntryLabel(entry) {
108
53
  return 'changed'
109
54
  }
110
55
 
111
- function tokenizePath(pathValue = '') {
112
- return pathValue
113
- .split(/[\\/]/)
114
- .flatMap((segment) => segment.split(/[^a-zA-Z0-9]+/))
115
- .map((token) => token.toLowerCase())
116
- .filter((token) => token.length >= 3 && !TOPIC_STOP_WORDS.has(token))
117
- }
118
-
119
- function inferCommitTypeFromEntries(statusEntries = []) {
120
- const paths = statusEntries.map((entry) => entry.path.toLowerCase())
121
-
122
- if (paths.every((pathValue) => pathValue.endsWith('.md') || pathValue.includes('/docs/') || pathValue.startsWith('docs/'))) {
123
- return 'docs'
124
- }
125
-
126
- if (paths.every((pathValue) => /\.test\.[^.]+$/.test(pathValue) || pathValue.includes('/tests/'))) {
127
- return 'test'
128
- }
129
-
130
- if (paths.some((pathValue) => pathValue.includes('.github/workflows/') || pathValue.includes('/ci/'))) {
131
- return 'ci'
132
- }
133
-
134
- return 'chore'
135
- }
136
-
137
56
  export function parseWorkingTreeStatus(stdout = '') {
138
57
  return stdout
139
58
  .split(/\r?\n/)
@@ -228,148 +147,11 @@ export function sanitizeSuggestedCommitMessage(message) {
228
147
  return normalized
229
148
  }
230
149
 
231
- export function buildFallbackCommitMessage(statusEntries = []) {
232
- const targetedFallback = buildTargetedFallbackCommitMessage(statusEntries)
233
- if (targetedFallback) {
234
- return targetedFallback
235
- }
236
-
237
- const tokenCounts = new Map()
238
-
239
- for (const entry of statusEntries) {
240
- for (const token of tokenizePath(entry.path)) {
241
- tokenCounts.set(token, (tokenCounts.get(token) ?? 0) + 1)
242
- }
243
- }
244
-
245
- const orderedTokens = Array.from(tokenCounts.entries())
246
- .sort((left, right) => {
247
- if (right[1] !== left[1]) {
248
- return right[1] - left[1]
249
- }
250
-
251
- return left[0].localeCompare(right[0])
252
- })
253
- .map(([token]) => token)
254
-
255
- const primaryTopic = orderedTokens[0] ?? 'release'
256
- const commitType = inferCommitTypeFromEntries(statusEntries)
257
-
258
- if (commitType === 'docs') {
259
- return `docs: update ${primaryTopic} documentation`
260
- }
261
-
262
- if (commitType === 'test') {
263
- return `test: expand ${primaryTopic} coverage`
264
- }
265
-
266
- if (commitType === 'ci') {
267
- return `ci: update ${primaryTopic} pipeline`
268
- }
269
-
270
- return `chore: update ${primaryTopic} handling`
271
- }
272
-
273
- async function collectDiffNumstat(rootDir, {runCommand} = {}) {
274
- try {
275
- const {stdout} = await runCommand('git', ['diff', '--numstat', 'HEAD', '--'], {
276
- capture: true,
277
- cwd: rootDir
278
- })
279
-
280
- return stdout
281
- .split(/\r?\n/)
282
- .map((line) => line.trim())
283
- .filter(Boolean)
284
- .reduce((map, line) => {
285
- const [addedRaw, deletedRaw, filePath] = line.split('\t')
286
- if (!filePath) {
287
- return map
288
- }
289
-
290
- const added = Number.parseInt(addedRaw, 10)
291
- const deleted = Number.parseInt(deletedRaw, 10)
292
- map.set(filePath, {
293
- added: Number.isFinite(added) ? added : 0,
294
- deleted: Number.isFinite(deleted) ? deleted : 0
295
- })
296
- return map
297
- }, new Map())
298
- } catch {
299
- return new Map()
300
- }
301
- }
302
-
303
- function shouldIncludeDiffExcerptLine(line = '') {
304
- if (line.startsWith('diff --git ')) {
305
- return true
306
- }
307
-
308
- if (line.startsWith('@@')) {
309
- return true
310
- }
311
-
312
- return (line.startsWith('+') || line.startsWith('-')) && !line.startsWith('+++') && !line.startsWith('---')
313
- }
314
-
315
- function trimDiffExcerpt(diffText = '') {
316
- const selectedLines = []
317
- let totalChars = 0
318
-
319
- for (const rawLine of diffText.split(/\r?\n/)) {
320
- const line = rawLine.trimEnd()
321
-
322
- if (!shouldIncludeDiffExcerptLine(line)) {
323
- continue
324
- }
325
-
326
- const truncatedLine = line.length > 180 ? `${line.slice(0, 177)}...` : line
327
- const nextTotal = totalChars + truncatedLine.length + 1
328
-
329
- if (selectedLines.length >= MAX_DIFF_EXCERPT_LINES || nextTotal > MAX_DIFF_EXCERPT_CHARS) {
330
- break
331
- }
332
-
333
- selectedLines.push(truncatedLine)
334
- totalChars = nextTotal
335
- }
336
-
337
- return selectedLines.join('\n')
338
- }
339
-
340
- async function collectDiffExcerpt(rootDir, {runCommand} = {}) {
341
- try {
342
- const {stdout} = await runCommand('git', ['diff', '--unified=0', '--no-color', 'HEAD', '--'], {
343
- capture: true,
344
- cwd: rootDir
345
- })
346
-
347
- return trimDiffExcerpt(stdout)
348
- } catch {
349
- return ''
350
- }
351
- }
352
-
353
- async function buildCommitMessageContext(rootDir, {
354
- runCommand,
355
- statusEntries = []
356
- } = {}) {
357
- const changeCountsByPath = await collectDiffNumstat(rootDir, {runCommand})
358
- const summary = statusEntries.map((entry) => `- ${summarizeWorkingTreeEntry(entry, {changeCountsByPath})}`).join('\n')
359
- const diffExcerpt = await collectDiffExcerpt(rootDir, {runCommand})
360
-
361
- return {
362
- summary,
363
- diffExcerpt
364
- }
365
- }
366
-
367
150
  export async function suggestCommitMessage(rootDir = process.cwd(), {
368
151
  runCommand,
369
152
  commandExistsImpl = commandExists,
370
153
  logStep,
371
- logWarning,
372
- statusEntries = []
154
+ logWarning
373
155
  } = {}) {
374
156
  if (!commandExistsImpl('codex')) {
375
157
  return null
@@ -380,28 +162,9 @@ export async function suggestCommitMessage(rootDir = process.cwd(), {
380
162
  try {
381
163
  tempDir = await mkdtemp(path.join(tmpdir(), 'zephyr-release-commit-'))
382
164
  const outputPath = path.join(tempDir, 'codex-last-message.txt')
383
- const commitContext = await buildCommitMessageContext(rootDir, {
384
- runCommand,
385
- statusEntries
386
- })
387
165
 
388
166
  logStep?.('Generating a suggested commit message with Codex...')
389
167
 
390
- const promptSections = [
391
- 'Write exactly one short conventional commit message for these pending changes.',
392
- 'Use the exact format "<type>: <subject>" with no scope, no exclamation mark, and no extra text.',
393
- 'Choose the most appropriate type from: fix, feat, chore, docs, refactor, test, style, perf, build, ci, revert.',
394
- 'Base the subject on the actual behavior, safeguard, bug fix, feature, or API change shown below.',
395
- 'Avoid generic nouns like "workflow", "process", "flow", "changes", or "updates" unless the diff truly changes CI or docs.',
396
- 'Do not describe the commit itself, staging, or "pending changes"; describe the underlying code or product change.',
397
- 'Pending change summary:',
398
- commitContext.summary || '- changed files present'
399
- ]
400
-
401
- if (commitContext.diffExcerpt) {
402
- promptSections.push('Diff excerpt:', commitContext.diffExcerpt)
403
- }
404
-
405
168
  await runCommand('codex', [
406
169
  'exec',
407
170
  '--ephemeral',
@@ -412,7 +175,13 @@ export async function suggestCommitMessage(rootDir = process.cwd(), {
412
175
  '--skip-git-repo-check',
413
176
  '--output-last-message',
414
177
  outputPath,
415
- promptSections.join('\n\n')
178
+ [
179
+ 'Inspect the current repository and decide the best conventional commit message for the pending changes.',
180
+ 'Use whatever read-only inspection you need.',
181
+ 'Reply with exactly one line in the format "<type>: <subject>".',
182
+ 'Do not use scopes like "fix(scope): ...".',
183
+ 'Do not include extra text.'
184
+ ].join('\n\n')
416
185
  ], {
417
186
  capture: true,
418
187
  cwd: rootDir
@@ -9,6 +9,7 @@ function hasExplicitReleaseOptions(options = {}) {
9
9
  'skipGitHooks',
10
10
  'skipTests',
11
11
  'skipLint',
12
+ 'skipVersioning',
12
13
  'skipBuild',
13
14
  'skipDeploy'
14
15
  ].some((key) => key in options)
@@ -21,12 +22,17 @@ export async function releaseNode(options = {}) {
21
22
  skipGitHooks: options.skipGitHooks === true,
22
23
  skipTests: options.skipTests === true,
23
24
  skipLint: options.skipLint === true,
25
+ skipVersioning: options.skipVersioning === true,
24
26
  skipBuild: options.skipBuild === true,
25
27
  skipDeploy: options.skipDeploy === true
26
28
  }
27
29
  : parseReleaseArgs({
28
- booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint', '--skip-build', '--skip-deploy']
30
+ booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint', '--skip-versioning', '--skip-build', '--skip-deploy']
29
31
  })
32
+
33
+ if (parsed.skipVersioning && parsed.releaseType) {
34
+ throw new Error('--skip-versioning cannot be used together with an explicit version or bump argument.')
35
+ }
30
36
  const rootDir = options.rootDir ?? process.cwd()
31
37
  const context = options.context ?? createAppContext({
32
38
  executionMode: {
@@ -42,6 +48,7 @@ export async function releaseNode(options = {}) {
42
48
  skipGitHooks: parsed.skipGitHooks === true || executionMode?.skipGitHooks === true,
43
49
  skipTests: parsed.skipTests === true,
44
50
  skipLint: parsed.skipLint === true,
51
+ skipVersioning: parsed.skipVersioning === true,
45
52
  skipBuild: parsed.skipBuild === true,
46
53
  skipDeploy: parsed.skipDeploy === true,
47
54
  rootDir,
@@ -8,7 +8,8 @@ function hasExplicitReleaseOptions(options = {}) {
8
8
  'releaseType',
9
9
  'skipGitHooks',
10
10
  'skipTests',
11
- 'skipLint'
11
+ 'skipLint',
12
+ 'skipVersioning'
12
13
  ].some((key) => key in options)
13
14
  }
14
15
 
@@ -18,11 +19,16 @@ export async function releasePackagist(options = {}) {
18
19
  releaseType: 'releaseType' in options ? (options.releaseType ?? null) : null,
19
20
  skipGitHooks: options.skipGitHooks === true,
20
21
  skipTests: options.skipTests === true,
21
- skipLint: options.skipLint === true
22
+ skipLint: options.skipLint === true,
23
+ skipVersioning: options.skipVersioning === true
22
24
  }
23
25
  : parseReleaseArgs({
24
- booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint']
26
+ booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint', '--skip-versioning']
25
27
  })
28
+
29
+ if (parsed.skipVersioning && parsed.releaseType) {
30
+ throw new Error('--skip-versioning cannot be used together with an explicit version or bump argument.')
31
+ }
26
32
  const rootDir = options.rootDir ?? process.cwd()
27
33
  const context = options.context ?? createAppContext({
28
34
  executionMode: {
@@ -38,6 +44,7 @@ export async function releasePackagist(options = {}) {
38
44
  skipGitHooks: parsed.skipGitHooks === true || executionMode?.skipGitHooks === true,
39
45
  skipTests: parsed.skipTests === true,
40
46
  skipLint: parsed.skipLint === true,
47
+ skipVersioning: parsed.skipVersioning === true,
41
48
  rootDir,
42
49
  logStep,
43
50
  logSuccess,
@@ -24,12 +24,21 @@ export function createAppContext({
24
24
  workflow: executionMode.workflow ?? 'deploy',
25
25
  presetName: executionMode.presetName ?? null,
26
26
  maintenanceMode: executionMode.maintenanceMode ?? null,
27
+ autoCommit: executionMode.autoCommit === true,
28
+ skipVersioning: executionMode.skipVersioning === true,
27
29
  skipGitHooks: executionMode.skipGitHooks === true,
28
30
  skipChecks: executionMode.skipChecks === true,
29
31
  skipTests: executionMode.skipTests === true || executionMode.skipChecks === true,
30
32
  skipLint: executionMode.skipLint === true || executionMode.skipChecks === true,
31
33
  resumePending: executionMode.resumePending === true,
32
- discardPending: executionMode.discardPending === true
34
+ discardPending: executionMode.discardPending === true,
35
+ explicitMaintenanceMode: executionMode.explicitMaintenanceMode === true,
36
+ explicitAutoCommit: executionMode.explicitAutoCommit === true,
37
+ explicitSkipVersioning: executionMode.explicitSkipVersioning === true,
38
+ explicitSkipGitHooks: executionMode.explicitSkipGitHooks === true,
39
+ explicitSkipChecks: executionMode.explicitSkipChecks === true,
40
+ explicitSkipTests: executionMode.explicitSkipTests === true || executionMode.explicitSkipChecks === true,
41
+ explicitSkipLint: executionMode.explicitSkipLint === true || executionMode.explicitSkipChecks === true
33
42
  }
34
43
  const emitEvent = normalizedExecutionMode.json
35
44
  ? createJsonEventEmitter({workflow: normalizedExecutionMode.workflow})