@wyxos/zephyr 0.2.9 → 0.2.11

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.
@@ -5,14 +5,24 @@ import { readFile } from 'node:fs/promises'
5
5
  import fs from 'node:fs'
6
6
  import path from 'node:path'
7
7
  import process from 'node:process'
8
- import chalk from 'chalk'
8
+
9
+ const STEP_PREFIX = '→'
10
+ const OK_PREFIX = '✔'
11
+ const WARN_PREFIX = '⚠'
9
12
 
10
13
  const IS_WINDOWS = process.platform === 'win32'
11
14
 
12
- const logProcessing = (message = '') => console.log(chalk.yellow(message))
13
- const logSuccess = (message = '') => console.log(chalk.green(message))
14
- const logWarning = (message = '') => console.warn(chalk.yellow(message))
15
- const logError = (message = '') => console.error(chalk.red(message))
15
+ function logStep(message) {
16
+ console.log(`${STEP_PREFIX} ${message}`)
17
+ }
18
+
19
+ function logSuccess(message) {
20
+ console.log(`${OK_PREFIX} ${message}`)
21
+ }
22
+
23
+ function logWarning(message) {
24
+ console.warn(`${WARN_PREFIX} ${message}`)
25
+ }
16
26
 
17
27
  function runCommand(command, args, { cwd = process.cwd(), capture = false, useShell = false } = {}) {
18
28
  return new Promise((resolve, reject) => {
@@ -104,12 +114,12 @@ async function ensureUpToDateWithUpstream(branch, upstreamRef, rootDir = process
104
114
  const remoteBranch = branchParts.join('/')
105
115
 
106
116
  if (remoteName && remoteBranch) {
107
- logProcessing(`Fetching latest updates from ${remoteName}/${remoteBranch}...`)
117
+ logStep(`Fetching latest updates from ${remoteName}/${remoteBranch}...`)
108
118
  try {
109
119
  await runCommand('git', ['fetch', remoteName, remoteBranch], { capture: true, cwd: rootDir })
110
120
  } catch (error) {
111
121
  if (error.stderr) {
112
- logError(error.stderr)
122
+ console.error(error.stderr)
113
123
  }
114
124
  throw new Error(`Failed to fetch ${upstreamRef}: ${error.message}`)
115
125
  }
@@ -129,13 +139,13 @@ async function ensureUpToDateWithUpstream(branch, upstreamRef, rootDir = process
129
139
 
130
140
  if (Number.isFinite(behind) && behind > 0) {
131
141
  if (remoteName && remoteBranch) {
132
- logProcessing(`Fast-forwarding ${branch} with ${upstreamRef}...`)
142
+ logStep(`Fast-forwarding ${branch} with ${upstreamRef}...`)
133
143
 
134
144
  try {
135
145
  await runCommand('git', ['pull', '--ff-only', remoteName, remoteBranch], { capture: true, cwd: rootDir })
136
146
  } catch (error) {
137
147
  if (error.stderr) {
138
- logError(error.stderr)
148
+ console.error(error.stderr)
139
149
  }
140
150
  throw new Error(
141
151
  `Unable to fast-forward ${branch} with ${upstreamRef}. Resolve conflicts manually, then rerun the release.\n${error.message}`
@@ -194,13 +204,43 @@ async function runLint(skipLint, pkg, rootDir = process.cwd()) {
194
204
  }
195
205
 
196
206
  if (!hasScript(pkg, 'lint')) {
197
- logProcessing('Skipping lint (no lint script found in package.json).')
207
+ logStep('Skipping lint (no lint script found in package.json).')
198
208
  return
199
209
  }
200
210
 
201
- logProcessing('Running lint...')
202
- await runCommand('npm', ['run', 'lint'], { cwd: rootDir })
203
- logSuccess('Lint passed.')
211
+ logStep('Running lint...')
212
+
213
+ let dotInterval = null
214
+ try {
215
+ // Capture output and show dots as progress
216
+ process.stdout.write(' ')
217
+ dotInterval = setInterval(() => {
218
+ process.stdout.write('.')
219
+ }, 200)
220
+
221
+ await runCommand('npm', ['run', 'lint'], { capture: true, cwd: rootDir })
222
+
223
+ if (dotInterval) {
224
+ clearInterval(dotInterval)
225
+ dotInterval = null
226
+ }
227
+ process.stdout.write('\n')
228
+ logSuccess('Lint passed.')
229
+ } catch (error) {
230
+ // Clear dots and show error output
231
+ if (dotInterval) {
232
+ clearInterval(dotInterval)
233
+ dotInterval = null
234
+ }
235
+ process.stdout.write('\n')
236
+ if (error.stdout) {
237
+ console.error(error.stdout)
238
+ }
239
+ if (error.stderr) {
240
+ console.error(error.stderr)
241
+ }
242
+ throw error
243
+ }
204
244
  }
205
245
 
206
246
  async function runTests(skipTests, pkg, rootDir = process.cwd()) {
@@ -211,11 +251,11 @@ async function runTests(skipTests, pkg, rootDir = process.cwd()) {
211
251
 
212
252
  // Check for test:run or test script
213
253
  if (!hasScript(pkg, 'test:run') && !hasScript(pkg, 'test')) {
214
- logProcessing('Skipping tests (no test or test:run script found in package.json).')
254
+ logStep('Skipping tests (no test or test:run script found in package.json).')
215
255
  return
216
256
  }
217
257
 
218
- logProcessing('Running test suite...')
258
+ logStep('Running test suite...')
219
259
 
220
260
  let dotInterval = null
221
261
  try {
@@ -247,10 +287,10 @@ async function runTests(skipTests, pkg, rootDir = process.cwd()) {
247
287
  }
248
288
  process.stdout.write('\n')
249
289
  if (error.stdout) {
250
- logError(error.stdout)
290
+ console.error(error.stdout)
251
291
  }
252
292
  if (error.stderr) {
253
- logError(error.stderr)
293
+ console.error(error.stderr)
254
294
  }
255
295
  throw error
256
296
  }
@@ -263,13 +303,43 @@ async function runBuild(skipBuild, pkg, rootDir = process.cwd()) {
263
303
  }
264
304
 
265
305
  if (!hasScript(pkg, 'build')) {
266
- logProcessing('Skipping build (no build script found in package.json).')
306
+ logStep('Skipping build (no build script found in package.json).')
267
307
  return
268
308
  }
269
309
 
270
- logProcessing('Building project...')
271
- await runCommand('npm', ['run', 'build'], { cwd: rootDir })
272
- logSuccess('Build completed.')
310
+ logStep('Building project...')
311
+
312
+ let dotInterval = null
313
+ try {
314
+ // Capture output and show dots as progress
315
+ process.stdout.write(' ')
316
+ dotInterval = setInterval(() => {
317
+ process.stdout.write('.')
318
+ }, 200)
319
+
320
+ await runCommand('npm', ['run', 'build'], { capture: true, cwd: rootDir })
321
+
322
+ if (dotInterval) {
323
+ clearInterval(dotInterval)
324
+ dotInterval = null
325
+ }
326
+ process.stdout.write('\n')
327
+ logSuccess('Build completed.')
328
+ } catch (error) {
329
+ // Clear dots and show error output
330
+ if (dotInterval) {
331
+ clearInterval(dotInterval)
332
+ dotInterval = null
333
+ }
334
+ process.stdout.write('\n')
335
+ if (error.stdout) {
336
+ console.error(error.stdout)
337
+ }
338
+ if (error.stderr) {
339
+ console.error(error.stderr)
340
+ }
341
+ throw error
342
+ }
273
343
  }
274
344
 
275
345
  async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
@@ -279,13 +349,43 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
279
349
  }
280
350
 
281
351
  if (!hasScript(pkg, 'build:lib')) {
282
- logProcessing('Skipping library build (no build:lib script found in package.json).')
352
+ logStep('Skipping library build (no build:lib script found in package.json).')
283
353
  return false
284
354
  }
285
355
 
286
- logProcessing('Building library...')
287
- await runCommand('npm', ['run', 'build:lib'], { cwd: rootDir })
288
- logSuccess('Library built.')
356
+ logStep('Building library...')
357
+
358
+ let dotInterval = null
359
+ try {
360
+ // Capture output and show dots as progress
361
+ process.stdout.write(' ')
362
+ dotInterval = setInterval(() => {
363
+ process.stdout.write('.')
364
+ }, 200)
365
+
366
+ await runCommand('npm', ['run', 'build:lib'], { capture: true, cwd: rootDir })
367
+
368
+ if (dotInterval) {
369
+ clearInterval(dotInterval)
370
+ dotInterval = null
371
+ }
372
+ process.stdout.write('\n')
373
+ logSuccess('Library built.')
374
+ } catch (error) {
375
+ // Clear dots and show error output
376
+ if (dotInterval) {
377
+ clearInterval(dotInterval)
378
+ dotInterval = null
379
+ }
380
+ process.stdout.write('\n')
381
+ if (error.stdout) {
382
+ console.error(error.stdout)
383
+ }
384
+ if (error.stderr) {
385
+ console.error(error.stderr)
386
+ }
387
+ throw error
388
+ }
289
389
 
290
390
  // Check for lib changes and commit them if any
291
391
  const { stdout: statusAfterBuild } = await runCommand('git', ['status', '--porcelain'], { capture: true, cwd: rootDir })
@@ -295,7 +395,7 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
295
395
  })
296
396
 
297
397
  if (hasLibChanges) {
298
- logProcessing('Committing lib build artifacts...')
398
+ logStep('Committing lib build artifacts...')
299
399
  await runCommand('git', ['add', 'lib/'], { capture: true, cwd: rootDir })
300
400
  await runCommand('git', ['commit', '-m', 'chore: build lib artifacts'], { capture: true, cwd: rootDir })
301
401
  logSuccess('Lib build artifacts committed.')
@@ -305,7 +405,7 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
305
405
  }
306
406
 
307
407
  async function ensureNpmAuth(rootDir = process.cwd()) {
308
- logProcessing('Confirming npm authentication...')
408
+ logStep('Confirming npm authentication...')
309
409
  try {
310
410
  const result = await runCommand('npm', ['whoami'], { capture: true, cwd: rootDir })
311
411
  // Only show username if we captured it, otherwise just show success
@@ -315,14 +415,14 @@ async function ensureNpmAuth(rootDir = process.cwd()) {
315
415
  logSuccess('npm authenticated.')
316
416
  } catch (error) {
317
417
  if (error.stderr) {
318
- logError(error.stderr)
418
+ console.error(error.stderr)
319
419
  }
320
420
  throw error
321
421
  }
322
422
  }
323
423
 
324
424
  async function bumpVersion(releaseType, rootDir = process.cwd()) {
325
- logProcessing(`Bumping package version...`)
425
+ logStep(`Bumping package version...`)
326
426
 
327
427
  // Lib changes should already be committed by runLibBuild, but check anyway
328
428
  const { stdout: statusBefore } = await runCommand('git', ['status', '--porcelain'], { capture: true, cwd: rootDir })
@@ -332,7 +432,7 @@ async function bumpVersion(releaseType, rootDir = process.cwd()) {
332
432
  })
333
433
 
334
434
  if (hasLibChanges) {
335
- logProcessing('Stashing lib build artifacts...')
435
+ logStep('Stashing lib build artifacts...')
336
436
  await runCommand('git', ['stash', 'push', '-u', '-m', 'temp: lib build artifacts', 'lib/'], { capture: true, cwd: rootDir })
337
437
  }
338
438
 
@@ -349,7 +449,7 @@ async function bumpVersion(releaseType, rootDir = process.cwd()) {
349
449
  } finally {
350
450
  // Restore lib changes and ensure they're in the commit
351
451
  if (hasLibChanges) {
352
- logProcessing('Restoring lib build artifacts...')
452
+ logStep('Restoring lib build artifacts...')
353
453
  await runCommand('git', ['stash', 'pop'], { capture: true, cwd: rootDir })
354
454
  await runCommand('git', ['add', 'lib/'], { capture: true, cwd: rootDir })
355
455
  const { stdout: statusAfter } = await runCommand('git', ['status', '--porcelain'], { capture: true, cwd: rootDir })
@@ -370,16 +470,16 @@ async function bumpVersion(releaseType, rootDir = process.cwd()) {
370
470
  }
371
471
 
372
472
  async function pushChanges(rootDir = process.cwd()) {
373
- logProcessing('Pushing commits and tags to origin...')
473
+ logStep('Pushing commits and tags to origin...')
374
474
  try {
375
475
  await runCommand('git', ['push', '--follow-tags'], { capture: true, cwd: rootDir })
376
476
  logSuccess('Git push completed.')
377
477
  } catch (error) {
378
478
  if (error.stdout) {
379
- logError(error.stdout)
479
+ console.error(error.stdout)
380
480
  }
381
481
  if (error.stderr) {
382
- logError(error.stderr)
482
+ console.error(error.stderr)
383
483
  }
384
484
  throw error
385
485
  }
@@ -395,16 +495,16 @@ async function publishPackage(pkg, rootDir = process.cwd()) {
395
495
  publishArgs.push('--access', access)
396
496
  }
397
497
 
398
- logProcessing(`Publishing ${pkg.name}@${pkg.version} to npm...`)
498
+ logStep(`Publishing ${pkg.name}@${pkg.version} to npm...`)
399
499
  try {
400
500
  await runCommand('npm', publishArgs, { capture: true, cwd: rootDir })
401
501
  logSuccess('npm publish completed.')
402
502
  } catch (error) {
403
503
  if (error.stdout) {
404
- logError(error.stdout)
504
+ console.error(error.stdout)
405
505
  }
406
506
  if (error.stderr) {
407
- logError(error.stderr)
507
+ console.error(error.stderr)
408
508
  }
409
509
  throw error
410
510
  }
@@ -439,11 +539,11 @@ async function deployGHPages(skipDeploy, pkg, rootDir = process.cwd()) {
439
539
  }
440
540
 
441
541
  if (!distExists) {
442
- logProcessing('Skipping GitHub Pages deployment (no dist directory found).')
542
+ logStep('Skipping GitHub Pages deployment (no dist directory found).')
443
543
  return
444
544
  }
445
545
 
446
- logProcessing('Deploying to GitHub Pages...')
546
+ logStep('Deploying to GitHub Pages...')
447
547
 
448
548
  // Write CNAME file to dist if homepage is set
449
549
  const cnamePath = path.join(distPath, 'CNAME')
@@ -462,34 +562,62 @@ async function deployGHPages(skipDeploy, pkg, rootDir = process.cwd()) {
462
562
 
463
563
  const worktreeDir = path.resolve(rootDir, '.gh-pages')
464
564
 
565
+ let dotInterval = null
465
566
  try {
466
- await runCommand('git', ['worktree', 'remove', worktreeDir, '-f'], { cwd: rootDir })
467
- } catch { }
567
+ // Capture output and show dots as progress
568
+ process.stdout.write(' ')
569
+ dotInterval = setInterval(() => {
570
+ process.stdout.write('.')
571
+ }, 200)
468
572
 
469
- try {
470
- await runCommand('git', ['worktree', 'add', worktreeDir, 'gh-pages'], { cwd: rootDir })
471
- } catch {
472
- await runCommand('git', ['worktree', 'add', worktreeDir, '-b', 'gh-pages'], { cwd: rootDir })
473
- }
573
+ try {
574
+ await runCommand('git', ['worktree', 'remove', worktreeDir, '-f'], { capture: true, cwd: rootDir })
575
+ } catch { }
474
576
 
475
- await runCommand('git', ['-C', worktreeDir, 'config', 'user.name', 'wyxos'])
476
- await runCommand('git', ['-C', worktreeDir, 'config', 'user.email', 'github@wyxos.com'])
577
+ try {
578
+ await runCommand('git', ['worktree', 'add', worktreeDir, 'gh-pages'], { capture: true, cwd: rootDir })
579
+ } catch {
580
+ await runCommand('git', ['worktree', 'add', worktreeDir, '-b', 'gh-pages'], { capture: true, cwd: rootDir })
581
+ }
477
582
 
478
- // Clear worktree directory
479
- for (const entry of fs.readdirSync(worktreeDir)) {
480
- if (entry === '.git') continue
481
- const target = path.join(worktreeDir, entry)
482
- fs.rmSync(target, { recursive: true, force: true })
483
- }
583
+ await runCommand('git', ['-C', worktreeDir, 'config', 'user.name', 'wyxos'], { capture: true })
584
+ await runCommand('git', ['-C', worktreeDir, 'config', 'user.email', 'github@wyxos.com'], { capture: true })
585
+
586
+ // Clear worktree directory
587
+ for (const entry of fs.readdirSync(worktreeDir)) {
588
+ if (entry === '.git') continue
589
+ const target = path.join(worktreeDir, entry)
590
+ fs.rmSync(target, { recursive: true, force: true })
591
+ }
484
592
 
485
- // Copy dist to worktree
486
- fs.cpSync(distPath, worktreeDir, { recursive: true })
593
+ // Copy dist to worktree
594
+ fs.cpSync(distPath, worktreeDir, { recursive: true })
487
595
 
488
- await runCommand('git', ['-C', worktreeDir, 'add', '-A'])
489
- await runCommand('git', ['-C', worktreeDir, 'commit', '-m', `deploy: demo ${new Date().toISOString()}`, '--allow-empty'])
490
- await runCommand('git', ['-C', worktreeDir, 'push', '-f', 'origin', 'gh-pages'])
596
+ await runCommand('git', ['-C', worktreeDir, 'add', '-A'], { capture: true })
597
+ await runCommand('git', ['-C', worktreeDir, 'commit', '-m', `deploy: demo ${new Date().toISOString()}`, '--allow-empty'], { capture: true })
598
+ await runCommand('git', ['-C', worktreeDir, 'push', '-f', 'origin', 'gh-pages'], { capture: true })
491
599
 
492
- logSuccess('GitHub Pages deployment completed.')
600
+ if (dotInterval) {
601
+ clearInterval(dotInterval)
602
+ dotInterval = null
603
+ }
604
+ process.stdout.write('\n')
605
+ logSuccess('GitHub Pages deployment completed.')
606
+ } catch (error) {
607
+ // Clear dots and show error output
608
+ if (dotInterval) {
609
+ clearInterval(dotInterval)
610
+ dotInterval = null
611
+ }
612
+ process.stdout.write('\n')
613
+ if (error.stdout) {
614
+ console.error(error.stdout)
615
+ }
616
+ if (error.stderr) {
617
+ console.error(error.stderr)
618
+ }
619
+ throw error
620
+ }
493
621
  }
494
622
 
495
623
  export async function releaseNode() {
@@ -497,10 +625,10 @@ export async function releaseNode() {
497
625
  const { releaseType, skipTests, skipLint, skipBuild, skipDeploy } = parseArgs()
498
626
  const rootDir = process.cwd()
499
627
 
500
- logProcessing('Reading package metadata...')
628
+ logStep('Reading package metadata...')
501
629
  const pkg = await readPackage(rootDir)
502
630
 
503
- logProcessing('Checking working tree status...')
631
+ logStep('Checking working tree status...')
504
632
  await ensureCleanWorkingTree(rootDir)
505
633
 
506
634
  const branch = await getCurrentBranch(rootDir)
@@ -508,7 +636,7 @@ export async function releaseNode() {
508
636
  throw new Error('Unable to determine current branch.')
509
637
  }
510
638
 
511
- logProcessing(`Current branch: ${branch}`)
639
+ logStep(`Current branch: ${branch}`)
512
640
  const upstreamRef = await getUpstreamRef(rootDir)
513
641
  await ensureUpToDateWithUpstream(branch, upstreamRef, rootDir)
514
642
 
@@ -525,8 +653,8 @@ export async function releaseNode() {
525
653
 
526
654
  logSuccess(`Release workflow completed for ${updatedPkg.name}@${updatedPkg.version}.`)
527
655
  } catch (error) {
528
- logError('\nRelease failed:')
529
- logError(error.message)
656
+ console.error('\nRelease failed:')
657
+ console.error(error.message)
530
658
  throw error
531
659
  }
532
660
  }
@@ -230,8 +230,38 @@ async function runLint(skipLint, rootDir = process.cwd()) {
230
230
 
231
231
  logStep('Running Laravel Pint...')
232
232
  const pintPath = IS_WINDOWS ? 'vendor\\bin\\pint' : 'vendor/bin/pint'
233
- await runCommand('php', [pintPath], { cwd: rootDir })
234
- logSuccess('Lint passed.')
233
+
234
+ let dotInterval = null
235
+ try {
236
+ // Capture output and show dots as progress
237
+ process.stdout.write(' ')
238
+ dotInterval = setInterval(() => {
239
+ process.stdout.write('.')
240
+ }, 200)
241
+
242
+ await runCommand('php', [pintPath], { capture: true, cwd: rootDir })
243
+
244
+ if (dotInterval) {
245
+ clearInterval(dotInterval)
246
+ dotInterval = null
247
+ }
248
+ process.stdout.write('\n')
249
+ logSuccess('Lint passed.')
250
+ } catch (error) {
251
+ // Clear dots and show error output
252
+ if (dotInterval) {
253
+ clearInterval(dotInterval)
254
+ dotInterval = null
255
+ }
256
+ process.stdout.write('\n')
257
+ if (error.stdout) {
258
+ console.error(error.stdout)
259
+ }
260
+ if (error.stderr) {
261
+ console.error(error.stderr)
262
+ }
263
+ throw error
264
+ }
235
265
  }
236
266
 
237
267
  async function runTests(skipTests, composer, rootDir = process.cwd()) {
@@ -250,13 +280,41 @@ async function runTests(skipTests, composer, rootDir = process.cwd()) {
250
280
 
251
281
  logStep('Running test suite...')
252
282
 
253
- if (hasArtisanFile) {
254
- await runCommand('php', ['artisan', 'test'], { cwd: rootDir })
255
- } else if (hasTestScript) {
256
- await runCommand('composer', ['test'], { cwd: rootDir })
257
- }
283
+ let dotInterval = null
284
+ try {
285
+ // Capture output and show dots as progress
286
+ process.stdout.write(' ')
287
+ dotInterval = setInterval(() => {
288
+ process.stdout.write('.')
289
+ }, 200)
290
+
291
+ if (hasArtisanFile) {
292
+ await runCommand('php', ['artisan', 'test'], { capture: true, cwd: rootDir })
293
+ } else if (hasTestScript) {
294
+ await runCommand('composer', ['test'], { capture: true, cwd: rootDir })
295
+ }
258
296
 
259
- logSuccess('Tests passed.')
297
+ if (dotInterval) {
298
+ clearInterval(dotInterval)
299
+ dotInterval = null
300
+ }
301
+ process.stdout.write('\n')
302
+ logSuccess('Tests passed.')
303
+ } catch (error) {
304
+ // Clear dots and show error output
305
+ if (dotInterval) {
306
+ clearInterval(dotInterval)
307
+ dotInterval = null
308
+ }
309
+ process.stdout.write('\n')
310
+ if (error.stdout) {
311
+ console.error(error.stdout)
312
+ }
313
+ if (error.stderr) {
314
+ console.error(error.stderr)
315
+ }
316
+ throw error
317
+ }
260
318
  }
261
319
 
262
320
  async function bumpVersion(releaseType, rootDir = process.cwd()) {