@wyxos/zephyr 0.2.8 → 0.2.10

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,10 +114,13 @@ 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
- await runCommand('git', ['fetch', remoteName, remoteBranch], { cwd: rootDir })
119
+ await runCommand('git', ['fetch', remoteName, remoteBranch], { capture: true, cwd: rootDir })
110
120
  } catch (error) {
121
+ if (error.stderr) {
122
+ console.error(error.stderr)
123
+ }
111
124
  throw new Error(`Failed to fetch ${upstreamRef}: ${error.message}`)
112
125
  }
113
126
  }
@@ -126,11 +139,14 @@ async function ensureUpToDateWithUpstream(branch, upstreamRef, rootDir = process
126
139
 
127
140
  if (Number.isFinite(behind) && behind > 0) {
128
141
  if (remoteName && remoteBranch) {
129
- logProcessing(`Fast-forwarding ${branch} with ${upstreamRef}...`)
142
+ logStep(`Fast-forwarding ${branch} with ${upstreamRef}...`)
130
143
 
131
144
  try {
132
- await runCommand('git', ['pull', '--ff-only', remoteName, remoteBranch], { cwd: rootDir })
145
+ await runCommand('git', ['pull', '--ff-only', remoteName, remoteBranch], { capture: true, cwd: rootDir })
133
146
  } catch (error) {
147
+ if (error.stderr) {
148
+ console.error(error.stderr)
149
+ }
134
150
  throw new Error(
135
151
  `Unable to fast-forward ${branch} with ${upstreamRef}. Resolve conflicts manually, then rerun the release.\n${error.message}`
136
152
  )
@@ -188,13 +204,43 @@ async function runLint(skipLint, pkg, rootDir = process.cwd()) {
188
204
  }
189
205
 
190
206
  if (!hasScript(pkg, 'lint')) {
191
- logProcessing('Skipping lint (no lint script found in package.json).')
207
+ logStep('Skipping lint (no lint script found in package.json).')
192
208
  return
193
209
  }
194
210
 
195
- logProcessing('Running lint...')
196
- await runCommand('npm', ['run', 'lint'], { cwd: rootDir })
197
- 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
+ }
198
244
  }
199
245
 
200
246
  async function runTests(skipTests, pkg, rootDir = process.cwd()) {
@@ -205,11 +251,11 @@ async function runTests(skipTests, pkg, rootDir = process.cwd()) {
205
251
 
206
252
  // Check for test:run or test script
207
253
  if (!hasScript(pkg, 'test:run') && !hasScript(pkg, 'test')) {
208
- 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).')
209
255
  return
210
256
  }
211
257
 
212
- logProcessing('Running test suite...')
258
+ logStep('Running test suite...')
213
259
 
214
260
  let dotInterval = null
215
261
  try {
@@ -241,10 +287,10 @@ async function runTests(skipTests, pkg, rootDir = process.cwd()) {
241
287
  }
242
288
  process.stdout.write('\n')
243
289
  if (error.stdout) {
244
- logError(error.stdout)
290
+ console.error(error.stdout)
245
291
  }
246
292
  if (error.stderr) {
247
- logError(error.stderr)
293
+ console.error(error.stderr)
248
294
  }
249
295
  throw error
250
296
  }
@@ -257,11 +303,11 @@ async function runBuild(skipBuild, pkg, rootDir = process.cwd()) {
257
303
  }
258
304
 
259
305
  if (!hasScript(pkg, 'build')) {
260
- logProcessing('Skipping build (no build script found in package.json).')
306
+ logStep('Skipping build (no build script found in package.json).')
261
307
  return
262
308
  }
263
309
 
264
- logProcessing('Building project...')
310
+ logStep('Building project...')
265
311
  await runCommand('npm', ['run', 'build'], { cwd: rootDir })
266
312
  logSuccess('Build completed.')
267
313
  }
@@ -273,11 +319,11 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
273
319
  }
274
320
 
275
321
  if (!hasScript(pkg, 'build:lib')) {
276
- logProcessing('Skipping library build (no build:lib script found in package.json).')
322
+ logStep('Skipping library build (no build:lib script found in package.json).')
277
323
  return false
278
324
  }
279
325
 
280
- logProcessing('Building library...')
326
+ logStep('Building library...')
281
327
  await runCommand('npm', ['run', 'build:lib'], { cwd: rootDir })
282
328
  logSuccess('Library built.')
283
329
 
@@ -289,9 +335,9 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
289
335
  })
290
336
 
291
337
  if (hasLibChanges) {
292
- logProcessing('Committing lib build artifacts...')
293
- await runCommand('git', ['add', 'lib/'], { cwd: rootDir })
294
- await runCommand('git', ['commit', '-m', 'chore: build lib artifacts'], { cwd: rootDir })
338
+ logStep('Committing lib build artifacts...')
339
+ await runCommand('git', ['add', 'lib/'], { capture: true, cwd: rootDir })
340
+ await runCommand('git', ['commit', '-m', 'chore: build lib artifacts'], { capture: true, cwd: rootDir })
295
341
  logSuccess('Lib build artifacts committed.')
296
342
  }
297
343
 
@@ -299,13 +345,24 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
299
345
  }
300
346
 
301
347
  async function ensureNpmAuth(rootDir = process.cwd()) {
302
- logProcessing('Confirming npm authentication...')
303
- await runCommand('npm', ['whoami'], { cwd: rootDir })
304
- logSuccess('npm authenticated.')
348
+ logStep('Confirming npm authentication...')
349
+ try {
350
+ const result = await runCommand('npm', ['whoami'], { capture: true, cwd: rootDir })
351
+ // Only show username if we captured it, otherwise just show success
352
+ if (result?.stdout) {
353
+ // Silently authenticated - we don't need to show the username
354
+ }
355
+ logSuccess('npm authenticated.')
356
+ } catch (error) {
357
+ if (error.stderr) {
358
+ console.error(error.stderr)
359
+ }
360
+ throw error
361
+ }
305
362
  }
306
363
 
307
364
  async function bumpVersion(releaseType, rootDir = process.cwd()) {
308
- logProcessing(`Bumping package version...`)
365
+ logStep(`Bumping package version...`)
309
366
 
310
367
  // Lib changes should already be committed by runLibBuild, but check anyway
311
368
  const { stdout: statusBefore } = await runCommand('git', ['status', '--porcelain'], { capture: true, cwd: rootDir })
@@ -315,22 +372,29 @@ async function bumpVersion(releaseType, rootDir = process.cwd()) {
315
372
  })
316
373
 
317
374
  if (hasLibChanges) {
318
- logProcessing('Stashing lib build artifacts...')
319
- await runCommand('git', ['stash', 'push', '-u', '-m', 'temp: lib build artifacts', 'lib/'], { cwd: rootDir })
375
+ logStep('Stashing lib build artifacts...')
376
+ await runCommand('git', ['stash', 'push', '-u', '-m', 'temp: lib build artifacts', 'lib/'], { capture: true, cwd: rootDir })
320
377
  }
321
378
 
322
379
  try {
323
380
  // npm version will update package.json and create a commit with default message
324
- await runCommand('npm', ['version', releaseType], { cwd: rootDir })
381
+ const result = await runCommand('npm', ['version', releaseType], { capture: true, cwd: rootDir })
382
+ // Extract version from output (e.g., "v0.2.8" or "0.2.8")
383
+ if (result?.stdout) {
384
+ const versionMatch = result.stdout.match(/v?(\d+\.\d+\.\d+)/)
385
+ if (versionMatch) {
386
+ // Version is shown in the logSuccess message below, no need to show it here
387
+ }
388
+ }
325
389
  } finally {
326
390
  // Restore lib changes and ensure they're in the commit
327
391
  if (hasLibChanges) {
328
- logProcessing('Restoring lib build artifacts...')
329
- await runCommand('git', ['stash', 'pop'], { cwd: rootDir })
330
- await runCommand('git', ['add', 'lib/'], { cwd: rootDir })
392
+ logStep('Restoring lib build artifacts...')
393
+ await runCommand('git', ['stash', 'pop'], { capture: true, cwd: rootDir })
394
+ await runCommand('git', ['add', 'lib/'], { capture: true, cwd: rootDir })
331
395
  const { stdout: statusAfter } = await runCommand('git', ['status', '--porcelain'], { capture: true, cwd: rootDir })
332
396
  if (statusAfter.includes('lib/')) {
333
- await runCommand('git', ['commit', '--amend', '--no-edit'], { cwd: rootDir })
397
+ await runCommand('git', ['commit', '--amend', '--no-edit'], { capture: true, cwd: rootDir })
334
398
  }
335
399
  }
336
400
  }
@@ -339,16 +403,26 @@ async function bumpVersion(releaseType, rootDir = process.cwd()) {
339
403
  const commitMessage = `chore: release ${pkg.version}`
340
404
 
341
405
  // Amend the commit message to use our custom format
342
- await runCommand('git', ['commit', '--amend', '-m', commitMessage], { cwd: rootDir })
406
+ await runCommand('git', ['commit', '--amend', '-m', commitMessage], { capture: true, cwd: rootDir })
343
407
 
344
408
  logSuccess(`Version updated to ${pkg.version}.`)
345
409
  return pkg
346
410
  }
347
411
 
348
412
  async function pushChanges(rootDir = process.cwd()) {
349
- logProcessing('Pushing commits and tags to origin...')
350
- await runCommand('git', ['push', '--follow-tags'], { cwd: rootDir })
351
- logSuccess('Git push completed.')
413
+ logStep('Pushing commits and tags to origin...')
414
+ try {
415
+ await runCommand('git', ['push', '--follow-tags'], { capture: true, cwd: rootDir })
416
+ logSuccess('Git push completed.')
417
+ } catch (error) {
418
+ if (error.stdout) {
419
+ console.error(error.stdout)
420
+ }
421
+ if (error.stderr) {
422
+ console.error(error.stderr)
423
+ }
424
+ throw error
425
+ }
352
426
  }
353
427
 
354
428
  async function publishPackage(pkg, rootDir = process.cwd()) {
@@ -361,9 +435,19 @@ async function publishPackage(pkg, rootDir = process.cwd()) {
361
435
  publishArgs.push('--access', access)
362
436
  }
363
437
 
364
- logProcessing(`Publishing ${pkg.name}@${pkg.version} to npm...`)
365
- await runCommand('npm', publishArgs, { cwd: rootDir })
366
- logSuccess('npm publish completed.')
438
+ logStep(`Publishing ${pkg.name}@${pkg.version} to npm...`)
439
+ try {
440
+ await runCommand('npm', publishArgs, { capture: true, cwd: rootDir })
441
+ logSuccess('npm publish completed.')
442
+ } catch (error) {
443
+ if (error.stdout) {
444
+ console.error(error.stdout)
445
+ }
446
+ if (error.stderr) {
447
+ console.error(error.stderr)
448
+ }
449
+ throw error
450
+ }
367
451
  }
368
452
 
369
453
  function extractDomainFromHomepage(homepage) {
@@ -395,11 +479,11 @@ async function deployGHPages(skipDeploy, pkg, rootDir = process.cwd()) {
395
479
  }
396
480
 
397
481
  if (!distExists) {
398
- logProcessing('Skipping GitHub Pages deployment (no dist directory found).')
482
+ logStep('Skipping GitHub Pages deployment (no dist directory found).')
399
483
  return
400
484
  }
401
485
 
402
- logProcessing('Deploying to GitHub Pages...')
486
+ logStep('Deploying to GitHub Pages...')
403
487
 
404
488
  // Write CNAME file to dist if homepage is set
405
489
  const cnamePath = path.join(distPath, 'CNAME')
@@ -453,10 +537,10 @@ export async function releaseNode() {
453
537
  const { releaseType, skipTests, skipLint, skipBuild, skipDeploy } = parseArgs()
454
538
  const rootDir = process.cwd()
455
539
 
456
- logProcessing('Reading package metadata...')
540
+ logStep('Reading package metadata...')
457
541
  const pkg = await readPackage(rootDir)
458
542
 
459
- logProcessing('Checking working tree status...')
543
+ logStep('Checking working tree status...')
460
544
  await ensureCleanWorkingTree(rootDir)
461
545
 
462
546
  const branch = await getCurrentBranch(rootDir)
@@ -464,7 +548,7 @@ export async function releaseNode() {
464
548
  throw new Error('Unable to determine current branch.')
465
549
  }
466
550
 
467
- logProcessing(`Current branch: ${branch}`)
551
+ logStep(`Current branch: ${branch}`)
468
552
  const upstreamRef = await getUpstreamRef(rootDir)
469
553
  await ensureUpToDateWithUpstream(branch, upstreamRef, rootDir)
470
554
 
@@ -481,8 +565,8 @@ export async function releaseNode() {
481
565
 
482
566
  logSuccess(`Release workflow completed for ${updatedPkg.name}@${updatedPkg.version}.`)
483
567
  } catch (error) {
484
- logError('\nRelease failed:')
485
- logError(error.message)
568
+ console.error('\nRelease failed:')
569
+ console.error(error.message)
486
570
  throw error
487
571
  }
488
572
  }
@@ -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()) {