@kubb/cli 4.32.4 → 4.33.0

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.
Files changed (137) hide show
  1. package/dist/agent-CJ69TqoO.js +87 -0
  2. package/dist/agent-CJ69TqoO.js.map +1 -0
  3. package/dist/agent-CduUX7Ye.cjs +91 -0
  4. package/dist/agent-CduUX7Ye.cjs.map +1 -0
  5. package/dist/agent-D0A3RQho.js +57 -0
  6. package/dist/agent-D0A3RQho.js.map +1 -0
  7. package/dist/agent-DrnwQBZf.cjs +60 -0
  8. package/dist/agent-DrnwQBZf.cjs.map +1 -0
  9. package/dist/constants-CEKRremI.js +79 -0
  10. package/dist/constants-CEKRremI.js.map +1 -0
  11. package/dist/constants-CnPOlsJq.cjs +126 -0
  12. package/dist/constants-CnPOlsJq.cjs.map +1 -0
  13. package/dist/errors-BUjJsNoe.cjs +44 -0
  14. package/dist/errors-BUjJsNoe.cjs.map +1 -0
  15. package/dist/errors-bSLTEh4e.js +27 -0
  16. package/dist/errors-bSLTEh4e.js.map +1 -0
  17. package/dist/{generate-COj0aMS6.cjs → generate-ByMgAV76.cjs} +423 -577
  18. package/dist/generate-ByMgAV76.cjs.map +1 -0
  19. package/dist/generate-CiUPO5ds.cjs +65 -0
  20. package/dist/generate-CiUPO5ds.cjs.map +1 -0
  21. package/dist/generate-DIIxtkWT.js +66 -0
  22. package/dist/generate-DIIxtkWT.js.map +1 -0
  23. package/dist/{generate-CpWtSc45.js → generate-HP5ySfjV.js} +422 -577
  24. package/dist/generate-HP5ySfjV.js.map +1 -0
  25. package/dist/index.cjs +226 -35
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +226 -35
  29. package/dist/index.js.map +1 -1
  30. package/dist/init-Cd1hCb7q.cjs +296 -0
  31. package/dist/init-Cd1hCb7q.cjs.map +1 -0
  32. package/dist/init-DLNrkDF4.js +25 -0
  33. package/dist/init-DLNrkDF4.js.map +1 -0
  34. package/dist/init-Df_aXezV.cjs +24 -0
  35. package/dist/init-Df_aXezV.cjs.map +1 -0
  36. package/dist/init-DyKK2fTp.js +291 -0
  37. package/dist/init-DyKK2fTp.js.map +1 -0
  38. package/dist/jiti-BdskUHhD.cjs +16 -0
  39. package/dist/jiti-BdskUHhD.cjs.map +1 -0
  40. package/dist/jiti-Cl7t20dO.js +11 -0
  41. package/dist/jiti-Cl7t20dO.js.map +1 -0
  42. package/dist/mcp-B73FC8dF.cjs +42 -0
  43. package/dist/mcp-B73FC8dF.cjs.map +1 -0
  44. package/dist/mcp-Bd9LITaI.js +16 -0
  45. package/dist/mcp-Bd9LITaI.js.map +1 -0
  46. package/dist/mcp-Cf-1dsB-.js +41 -0
  47. package/dist/mcp-Cf-1dsB-.js.map +1 -0
  48. package/dist/mcp-Clg-Qnkr.cjs +15 -0
  49. package/dist/mcp-Clg-Qnkr.cjs.map +1 -0
  50. package/dist/package-681jTtCk.js +6 -0
  51. package/dist/package-681jTtCk.js.map +1 -0
  52. package/dist/{package-aNQWvWbS.cjs → package-aKgzEJtp.cjs} +2 -2
  53. package/dist/package-aKgzEJtp.cjs.map +1 -0
  54. package/dist/{telemetry-DYWvlxqs.js → telemetry-C4gOKX2x.js} +31 -10
  55. package/dist/telemetry-C4gOKX2x.js.map +1 -0
  56. package/dist/{telemetry-BDSSqUiG.cjs → telemetry-T5IA2dWA.cjs} +40 -7
  57. package/dist/telemetry-T5IA2dWA.cjs.map +1 -0
  58. package/dist/types-CLtz0jem.js +25 -0
  59. package/dist/types-CLtz0jem.js.map +1 -0
  60. package/dist/types-Ck2lzFON.cjs +36 -0
  61. package/dist/types-Ck2lzFON.cjs.map +1 -0
  62. package/dist/validate-Chjg23AE.js +41 -0
  63. package/dist/validate-Chjg23AE.js.map +1 -0
  64. package/dist/validate-Cr26q5xX.js +25 -0
  65. package/dist/validate-Cr26q5xX.js.map +1 -0
  66. package/dist/validate-DURmg-2Q.cjs +24 -0
  67. package/dist/validate-DURmg-2Q.cjs.map +1 -0
  68. package/dist/validate-Dqi9T_c4.cjs +42 -0
  69. package/dist/validate-Dqi9T_c4.cjs.map +1 -0
  70. package/package.json +5 -6
  71. package/src/cli/adapters/nodeAdapter.ts +159 -0
  72. package/src/cli/help.ts +36 -0
  73. package/src/cli/index.ts +16 -0
  74. package/src/cli/parse.ts +18 -0
  75. package/src/cli/schema.ts +38 -0
  76. package/src/cli/types.ts +95 -0
  77. package/src/commands/agent/start.ts +27 -136
  78. package/src/commands/agent.ts +6 -25
  79. package/src/commands/generate.ts +26 -158
  80. package/src/commands/init.ts +9 -360
  81. package/src/commands/mcp.ts +7 -52
  82. package/src/commands/validate.ts +9 -60
  83. package/src/constants.ts +77 -0
  84. package/src/index.ts +36 -42
  85. package/src/loggers/clackLogger.ts +42 -140
  86. package/src/loggers/fileSystemLogger.ts +1 -12
  87. package/src/loggers/githubActionsLogger.ts +36 -101
  88. package/src/loggers/plainLogger.ts +23 -70
  89. package/src/loggers/utils.ts +66 -2
  90. package/src/runners/agent.ts +100 -0
  91. package/src/runners/generate.ts +208 -100
  92. package/src/runners/init.ts +322 -0
  93. package/src/runners/mcp.ts +32 -0
  94. package/src/runners/validate.ts +35 -0
  95. package/src/utils/Writables.ts +2 -2
  96. package/src/utils/envDetection.ts +34 -0
  97. package/src/utils/errors.ts +23 -0
  98. package/src/utils/executeHooks.ts +18 -6
  99. package/src/utils/getCosmiConfig.ts +10 -11
  100. package/src/utils/getIntro.ts +17 -18
  101. package/src/utils/getSummary.ts +11 -15
  102. package/src/utils/jiti.ts +9 -0
  103. package/src/utils/packageManager.ts +3 -3
  104. package/src/utils/randomColor.ts +3 -12
  105. package/src/utils/runHook.ts +75 -0
  106. package/src/utils/spawnAsync.ts +47 -0
  107. package/src/utils/telemetry.ts +8 -25
  108. package/src/utils/watcher.ts +2 -4
  109. package/dist/agent-6COck3B9.cjs +0 -20
  110. package/dist/agent-6COck3B9.cjs.map +0 -1
  111. package/dist/agent-DMm6c5Vg.js +0 -20
  112. package/dist/agent-DMm6c5Vg.js.map +0 -1
  113. package/dist/generate-COj0aMS6.cjs.map +0 -1
  114. package/dist/generate-CpWtSc45.js.map +0 -1
  115. package/dist/init-Bdn3_qir.js +0 -304
  116. package/dist/init-Bdn3_qir.js.map +0 -1
  117. package/dist/init-CFW2kWY8.cjs +0 -308
  118. package/dist/init-CFW2kWY8.cjs.map +0 -1
  119. package/dist/mcp-DkwtARfo.cjs +0 -57
  120. package/dist/mcp-DkwtARfo.cjs.map +0 -1
  121. package/dist/mcp-DrH93Vq4.js +0 -57
  122. package/dist/mcp-DrH93Vq4.js.map +0 -1
  123. package/dist/package-BnJbGmLm.js +0 -6
  124. package/dist/package-BnJbGmLm.js.map +0 -1
  125. package/dist/package-aNQWvWbS.cjs.map +0 -1
  126. package/dist/start-CqTUu14n.js +0 -131
  127. package/dist/start-CqTUu14n.js.map +0 -1
  128. package/dist/start-D-rsIJGo.cjs +0 -134
  129. package/dist/start-D-rsIJGo.cjs.map +0 -1
  130. package/dist/telemetry-BDSSqUiG.cjs.map +0 -1
  131. package/dist/telemetry-DYWvlxqs.js.map +0 -1
  132. package/dist/validate-BlV8L8gC.js +0 -66
  133. package/dist/validate-BlV8L8gC.js.map +0 -1
  134. package/dist/validate-COhZUXF8.cjs +0 -66
  135. package/dist/validate-COhZUXF8.cjs.map +0 -1
  136. package/src/loggers/envDetection.ts +0 -28
  137. package/src/loggers/index.ts +0 -5
@@ -3,12 +3,14 @@ import process from 'node:process'
3
3
  import { styleText } from 'node:util'
4
4
  import * as clack from '@clack/prompts'
5
5
  import { defineLogger, LogLevel } from '@kubb/core'
6
- import { formatHrtime, formatMs } from '@kubb/core/utils'
7
- import { type NonZeroExitError, x } from 'tinyexec'
6
+ import { formatMs } from '@kubb/core/utils'
7
+ import { toCause } from '../utils/errors.ts'
8
8
  import { formatMsWithColor } from '../utils/formatMsWithColor.ts'
9
9
  import { getIntro } from '../utils/getIntro.ts'
10
10
  import { getSummary } from '../utils/getSummary.ts'
11
+ import { runHook } from '../utils/runHook.ts'
11
12
  import { ClackWritable } from '../utils/Writables.ts'
13
+ import { buildProgressLine, formatCommandWithArgs, formatMessage } from './utils.ts'
12
14
 
13
15
  /**
14
16
  * Clack adapter for local TTY environments
@@ -17,7 +19,7 @@ import { ClackWritable } from '../utils/Writables.ts'
17
19
  export const clackLogger = defineLogger({
18
20
  name: 'clack',
19
21
  install(context, options) {
20
- const logLevel = options?.logLevel || LogLevel.info
22
+ const logLevel = options?.logLevel ?? LogLevel.info
21
23
  const state = {
22
24
  totalPlugins: 0,
23
25
  completedPlugins: 0,
@@ -54,40 +56,14 @@ export const clackLogger = defineLogger({
54
56
  return
55
57
  }
56
58
 
57
- const parts: string[] = []
58
- const duration = formatHrtime(state.hrStart)
59
-
60
- if (state.totalPlugins > 0) {
61
- const pluginStr =
62
- state.failedPlugins > 0
63
- ? `Plugins ${styleText('green', state.completedPlugins.toString())}/${state.totalPlugins} ${styleText('red', `(${state.failedPlugins} failed)`)}`
64
- : `Plugins ${styleText('green', state.completedPlugins.toString())}/${state.totalPlugins}`
65
- parts.push(pluginStr)
66
- }
67
-
68
- if (state.totalFiles > 0) {
69
- parts.push(`Files ${styleText('green', state.processedFiles.toString())}/${state.totalFiles}`)
70
- }
71
-
72
- if (parts.length > 0) {
73
- parts.push(`${styleText('green', duration)} elapsed`)
74
- clack.log.step(getMessage(parts.join(styleText('dim', ' | '))))
59
+ const line = buildProgressLine(state)
60
+ if (line) {
61
+ clack.log.step(getMessage(line))
75
62
  }
76
63
  }
77
64
 
78
65
  function getMessage(message: string): string {
79
- if (logLevel >= LogLevel.verbose) {
80
- const timestamp = new Date().toLocaleTimeString('en-US', {
81
- hour12: false,
82
- hour: '2-digit',
83
- minute: '2-digit',
84
- second: '2-digit',
85
- })
86
-
87
- return [styleText('dim', `[${timestamp}]`), message].join(' ')
88
- }
89
-
90
- return message
66
+ return formatMessage(message, logLevel)
91
67
  }
92
68
 
93
69
  function startSpinner(text?: string) {
@@ -141,7 +117,7 @@ export const clackLogger = defineLogger({
141
117
  })
142
118
 
143
119
  context.on('error', (error) => {
144
- const caused = error.cause as Error | undefined
120
+ const caused = toCause(error)
145
121
 
146
122
  const text = [styleText('red', '✗'), error.message].join(' ')
147
123
 
@@ -217,13 +193,14 @@ Run \`npm install -g @kubb/cli\` to update`,
217
193
  })
218
194
 
219
195
  context.on('generation:start', (config) => {
220
- // Initialize progress tracking
221
- state.totalPlugins = config.plugins?.length || 0
196
+ reset()
197
+
198
+ // Initialize progress tracking for this generation
199
+ state.totalPlugins = config.plugins?.length ?? 0
222
200
 
223
201
  const text = getMessage(['Generation started', config.name ? `for ${styleText('dim', config.name)}` : undefined].filter(Boolean).join(' '))
224
202
 
225
203
  clack.intro(text)
226
- reset()
227
204
  })
228
205
 
229
206
  context.on('plugin:start', (plugin) => {
@@ -387,7 +364,7 @@ Run \`npm install -g @kubb/cli\` to update`,
387
364
  })
388
365
 
389
366
  context.on('hook:start', async ({ id, command, args }) => {
390
- const commandWithArgs = args?.length ? `${command} ${args.join(' ')}` : command
367
+ const commandWithArgs = formatCommandWithArgs(command, args)
391
368
  const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} started`)
392
369
 
393
370
  // Skip hook execution if no id is provided (e.g., during benchmarks or tests)
@@ -396,53 +373,17 @@ Run \`npm install -g @kubb/cli\` to update`,
396
373
  }
397
374
 
398
375
  if (logLevel <= LogLevel.silent) {
399
- try {
400
- const result = await x(command, [...(args ?? [])], {
401
- nodeOptions: { detached: true },
402
- throwOnError: true,
403
- })
404
-
405
- await context.emit('debug', {
406
- date: new Date(),
407
- logs: [result.stdout.trimEnd()],
408
- })
409
-
410
- await context.emit('hook:end', {
411
- command,
412
- args,
413
- id,
414
- success: true,
415
- error: null,
416
- })
417
- } catch (err) {
418
- const error = err as NonZeroExitError
419
- const stderr = error.output?.stderr ?? ''
420
- const stdout = error.output?.stdout ?? ''
421
-
422
- await context.emit('debug', {
423
- date: new Date(),
424
- logs: [stdout, stderr].filter(Boolean),
425
- })
426
-
427
- if (stderr) {
428
- console.error(stderr)
429
- }
430
- if (stdout) {
431
- console.log(stdout)
432
- }
433
-
434
- const errorMessage = new Error(`Hook execute failed: ${commandWithArgs}`)
435
-
436
- await context.emit('hook:end', {
437
- command,
438
- args,
439
- id,
440
- success: false,
441
- error: errorMessage,
442
- })
443
- await context.emit('error', errorMessage)
444
- }
445
-
376
+ await runHook({
377
+ id,
378
+ command,
379
+ args,
380
+ commandWithArgs,
381
+ context,
382
+ sink: {
383
+ onStderr: (s) => console.error(s),
384
+ onStdout: (s) => console.log(s),
385
+ },
386
+ })
446
387
  return
447
388
  }
448
389
 
@@ -454,46 +395,19 @@ Run \`npm install -g @kubb/cli\` to update`,
454
395
 
455
396
  const writable = new ClackWritable(logger)
456
397
 
457
- try {
458
- const proc = x(command, [...(args ?? [])], {
459
- nodeOptions: { detached: true },
460
- throwOnError: true,
461
- })
462
-
463
- for await (const line of proc) {
464
- writable.write(line)
465
- }
466
-
467
- const result = await proc
468
-
469
- await context.emit('debug', {
470
- date: new Date(),
471
- logs: [result.stdout.trimEnd()],
472
- })
473
-
474
- await context.emit('hook:end', { command, args, id, success: true, error: null })
475
- } catch (err) {
476
- const error = err as NonZeroExitError
477
- const stderr = error.output?.stderr ?? ''
478
- const stdout = error.output?.stdout ?? ''
479
-
480
- await context.emit('debug', {
481
- date: new Date(),
482
- logs: [stdout, stderr].filter(Boolean),
483
- })
484
-
485
- if (stderr) {
486
- logger.error(stderr)
487
- }
488
- if (stdout) {
489
- logger.message(stdout)
490
- }
491
-
492
- const errorMessage = new Error(`Hook execute failed: ${commandWithArgs}`)
493
-
494
- await context.emit('hook:end', { command, args, id, success: false, error: errorMessage })
495
- await context.emit('error', errorMessage)
496
- }
398
+ await runHook({
399
+ id,
400
+ command,
401
+ args,
402
+ commandWithArgs,
403
+ context,
404
+ stream: true,
405
+ sink: {
406
+ onLine: (line) => writable.write(line),
407
+ onStderr: (s) => logger.error(s),
408
+ onStdout: (s) => logger.message(s),
409
+ },
410
+ })
497
411
  })
498
412
 
499
413
  context.on('hook:end', ({ command, args }) => {
@@ -501,7 +415,7 @@ Run \`npm install -g @kubb/cli\` to update`,
501
415
  return
502
416
  }
503
417
 
504
- const commandWithArgs = args?.length ? `${command} ${args.join(' ')}` : command
418
+ const commandWithArgs = formatCommandWithArgs(command, args)
505
419
  const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} successfully executed`)
506
420
 
507
421
  clack.outro(text)
@@ -521,22 +435,10 @@ Run \`npm install -g @kubb/cli\` to update`,
521
435
  summary.unshift('\n')
522
436
  summary.push('\n')
523
437
 
524
- if (status === 'success') {
525
- clack.box(summary.join('\n'), getMessage(title), {
526
- width: 'auto',
527
- formatBorder: (s: string) => styleText('green', s),
528
- rounded: true,
529
- withGuide: false,
530
- contentAlign: 'left',
531
- titleAlign: 'center',
532
- })
533
-
534
- return
535
- }
536
-
438
+ const borderColor = status === 'success' ? 'green' : 'red'
537
439
  clack.box(summary.join('\n'), getMessage(title), {
538
440
  width: 'auto',
539
- formatBorder: (s: string) => styleText('red', s),
441
+ formatBorder: (s: string) => styleText(borderColor, s),
540
442
  rounded: true,
541
443
  withGuide: false,
542
444
  contentAlign: 'left',
@@ -1,4 +1,5 @@
1
1
  import { relative, resolve } from 'node:path'
2
+ import process from 'node:process'
2
3
  import { defineLogger } from '@kubb/core'
3
4
  import { write } from '@kubb/core/fs'
4
5
  import { formatMs } from '@kubb/core/utils'
@@ -63,7 +64,6 @@ export const fileSystemLogger = defineLogger({
63
64
  state.cachedLogs.add({
64
65
  date: new Date(),
65
66
  logs: [`ℹ ${message} ${info}`],
66
- fileName: undefined,
67
67
  })
68
68
  })
69
69
 
@@ -71,7 +71,6 @@ export const fileSystemLogger = defineLogger({
71
71
  state.cachedLogs.add({
72
72
  date: new Date(),
73
73
  logs: [`✓ ${message} ${info}`],
74
- fileName: undefined,
75
74
  })
76
75
  })
77
76
 
@@ -79,7 +78,6 @@ export const fileSystemLogger = defineLogger({
79
78
  state.cachedLogs.add({
80
79
  date: new Date(),
81
80
  logs: [`⚠ ${message} ${info}`],
82
- fileName: undefined,
83
81
  })
84
82
  })
85
83
 
@@ -87,7 +85,6 @@ export const fileSystemLogger = defineLogger({
87
85
  state.cachedLogs.add({
88
86
  date: new Date(),
89
87
  logs: [`✗ ${error.message}`, error.stack || 'unknown stack'],
90
- fileName: undefined,
91
88
  })
92
89
  })
93
90
 
@@ -95,7 +92,6 @@ export const fileSystemLogger = defineLogger({
95
92
  state.cachedLogs.add({
96
93
  date: new Date(),
97
94
  logs: message.logs,
98
- fileName: undefined,
99
95
  })
100
96
  })
101
97
 
@@ -103,7 +99,6 @@ export const fileSystemLogger = defineLogger({
103
99
  state.cachedLogs.add({
104
100
  date: new Date(),
105
101
  logs: [`Generating ${plugin.name}`],
106
- fileName: undefined,
107
102
  })
108
103
  })
109
104
 
@@ -113,7 +108,6 @@ export const fileSystemLogger = defineLogger({
113
108
  state.cachedLogs.add({
114
109
  date: new Date(),
115
110
  logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`],
116
- fileName: undefined,
117
111
  })
118
112
  })
119
113
 
@@ -121,7 +115,6 @@ export const fileSystemLogger = defineLogger({
121
115
  state.cachedLogs.add({
122
116
  date: new Date(),
123
117
  logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)],
124
- fileName: undefined,
125
118
  })
126
119
  })
127
120
 
@@ -134,10 +127,6 @@ export const fileSystemLogger = defineLogger({
134
127
  reset()
135
128
  })
136
129
 
137
- context.on('lifecycle:end', async () => {
138
- // lifecycle:end handler can be used for cleanup if needed in the future
139
- })
140
-
141
130
  // Fallback: Write logs on process exit to handle crashes
142
131
  const exitHandler = () => {
143
132
  // Synchronous write on exit - best effort
@@ -1,8 +1,10 @@
1
1
  import { styleText } from 'node:util'
2
2
  import { type Config, defineLogger, LogLevel } from '@kubb/core'
3
3
  import { formatHrtime, formatMs } from '@kubb/core/utils'
4
- import { type NonZeroExitError, x } from 'tinyexec'
4
+ import { toCause } from '../utils/errors.ts'
5
5
  import { formatMsWithColor } from '../utils/formatMsWithColor.ts'
6
+ import { runHook } from '../utils/runHook.ts'
7
+ import { buildProgressLine, formatCommandWithArgs, formatMessage } from './utils.ts'
6
8
 
7
9
  /**
8
10
  * GitHub Actions adapter for CI environments
@@ -11,7 +13,7 @@ import { formatMsWithColor } from '../utils/formatMsWithColor.ts'
11
13
  export const githubActionsLogger = defineLogger({
12
14
  name: 'github-actions',
13
15
  install(context, options) {
14
- const logLevel = options?.logLevel || LogLevel.info
16
+ const logLevel = options?.logLevel ?? LogLevel.info
15
17
  const state = {
16
18
  totalPlugins: 0,
17
19
  completedPlugins: 0,
@@ -29,6 +31,7 @@ export const githubActionsLogger = defineLogger({
29
31
  state.totalFiles = 0
30
32
  state.processedFiles = 0
31
33
  state.hrStart = process.hrtime()
34
+ state.currentConfigs = []
32
35
  }
33
36
 
34
37
  function showProgressStep() {
@@ -36,40 +39,14 @@ export const githubActionsLogger = defineLogger({
36
39
  return
37
40
  }
38
41
 
39
- const parts: string[] = []
40
- const duration = formatHrtime(state.hrStart)
41
-
42
- if (state.totalPlugins > 0) {
43
- const pluginStr =
44
- state.failedPlugins > 0
45
- ? `Plugins ${styleText('green', state.completedPlugins.toString())}/${state.totalPlugins} ${styleText('red', `(${state.failedPlugins} failed)`)}`
46
- : `Plugins ${styleText('green', state.completedPlugins.toString())}/${state.totalPlugins}`
47
- parts.push(pluginStr)
48
- }
49
-
50
- if (state.totalFiles > 0) {
51
- parts.push(`Files ${styleText('green', state.processedFiles.toString())}/${state.totalFiles}`)
52
- }
53
-
54
- if (parts.length > 0) {
55
- parts.push(`${styleText('green', duration)} elapsed`)
56
- console.log(getMessage(parts.join(styleText('dim', ' | '))))
42
+ const line = buildProgressLine(state)
43
+ if (line) {
44
+ console.log(getMessage(line))
57
45
  }
58
46
  }
59
47
 
60
48
  function getMessage(message: string): string {
61
- if (logLevel >= LogLevel.verbose) {
62
- const timestamp = new Date().toLocaleTimeString('en-US', {
63
- hour12: false,
64
- hour: '2-digit',
65
- minute: '2-digit',
66
- second: '2-digit',
67
- })
68
-
69
- return [styleText('dim', `[${timestamp}]`), message].join(' ')
70
- }
71
-
72
- return message
49
+ return formatMessage(message, logLevel)
73
50
  }
74
51
 
75
52
  function openGroup(name: string) {
@@ -111,7 +88,7 @@ export const githubActionsLogger = defineLogger({
111
88
  })
112
89
 
113
90
  context.on('error', (error) => {
114
- const caused = error.cause as Error | undefined
91
+ const caused = toCause(error)
115
92
 
116
93
  if (logLevel <= LogLevel.silent) {
117
94
  return
@@ -169,8 +146,10 @@ export const githubActionsLogger = defineLogger({
169
146
  })
170
147
 
171
148
  context.on('generation:start', (config) => {
172
- // Initialize progress tracking
173
- state.totalPlugins = config.plugins?.length || 0
149
+ reset()
150
+
151
+ // Initialize progress tracking for this generation
152
+ state.totalPlugins = config.plugins?.length ?? 0
174
153
 
175
154
  const text = config.name ? `Generation for ${styleText('bold', config.name)}` : 'Generation'
176
155
 
@@ -181,8 +160,6 @@ export const githubActionsLogger = defineLogger({
181
160
  if (state.currentConfigs.length === 1) {
182
161
  console.log(getMessage(text))
183
162
  }
184
-
185
- reset()
186
163
  })
187
164
 
188
165
  context.on('plugin:start', (plugin) => {
@@ -256,6 +233,9 @@ export const githubActionsLogger = defineLogger({
256
233
  if (state.currentConfigs.length === 1) {
257
234
  closeGroup('File Generation')
258
235
  }
236
+
237
+ // Show final progress step after files are written
238
+ showProgressStep()
259
239
  })
260
240
 
261
241
  context.on('file:processing:update', () => {
@@ -266,15 +246,6 @@ export const githubActionsLogger = defineLogger({
266
246
  state.processedFiles++
267
247
  })
268
248
 
269
- context.on('files:processing:end', () => {
270
- if (logLevel <= LogLevel.silent) {
271
- return
272
- }
273
-
274
- // Show final progress step after files are written
275
- showProgressStep()
276
- })
277
-
278
249
  context.on('generation:end', (config) => {
279
250
  const text = getMessage(
280
251
  config.name ? `${styleText('blue', '✓')} Generation completed for ${styleText('dim', config.name)}` : `${styleText('blue', '✓')} Generation completed`,
@@ -340,14 +311,13 @@ export const githubActionsLogger = defineLogger({
340
311
  })
341
312
 
342
313
  context.on('hook:start', async ({ id, command, args }) => {
343
- const commandWithArgs = args?.length ? `${command} ${args.join(' ')}` : command
314
+ const commandWithArgs = formatCommandWithArgs(command, args)
344
315
  const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} started`)
345
316
 
346
317
  if (logLevel > LogLevel.silent) {
347
318
  if (state.currentConfigs.length === 1) {
348
319
  openGroup(`Hook ${commandWithArgs}`)
349
320
  }
350
-
351
321
  console.log(text)
352
322
  }
353
323
 
@@ -356,57 +326,18 @@ export const githubActionsLogger = defineLogger({
356
326
  return
357
327
  }
358
328
 
359
- try {
360
- const result = await x(command, [...(args ?? [])], {
361
- nodeOptions: { detached: true },
362
- throwOnError: true,
363
- })
364
-
365
- await context.emit('debug', {
366
- date: new Date(),
367
- logs: [result.stdout.trimEnd()],
368
- })
369
-
370
- if (logLevel > LogLevel.silent) {
371
- console.log(result.stdout.trimEnd())
372
- }
373
-
374
- await context.emit('hook:end', {
375
- command,
376
- args,
377
- id,
378
- success: true,
379
- error: null,
380
- })
381
- } catch (err) {
382
- const error = err as NonZeroExitError
383
- const stderr = error.output?.stderr ?? ''
384
- const stdout = error.output?.stdout ?? ''
385
-
386
- await context.emit('debug', {
387
- date: new Date(),
388
- logs: [stdout, stderr].filter(Boolean),
389
- })
390
-
391
- // Display stderr/stdout in GitHub Actions format
392
- if (stderr) {
393
- console.error(`::error::${stderr}`)
394
- }
395
- if (stdout) {
396
- console.log(stdout)
397
- }
398
-
399
- const errorMessage = new Error(`Hook execute failed: ${commandWithArgs}`)
400
-
401
- await context.emit('hook:end', {
402
- command,
403
- args,
404
- id,
405
- success: false,
406
- error: errorMessage,
407
- })
408
- await context.emit('error', errorMessage)
409
- }
329
+ await runHook({
330
+ id,
331
+ command,
332
+ args,
333
+ commandWithArgs,
334
+ context,
335
+ sink: {
336
+ // GHA formats errors with the ::error:: annotation
337
+ onStdout: logLevel > LogLevel.silent ? (s) => console.log(s) : undefined,
338
+ onStderr: logLevel > LogLevel.silent ? (s) => console.error(`::error::${s}`) : undefined,
339
+ },
340
+ })
410
341
  })
411
342
 
412
343
  context.on('hook:end', ({ command, args }) => {
@@ -414,7 +345,7 @@ export const githubActionsLogger = defineLogger({
414
345
  return
415
346
  }
416
347
 
417
- const commandWithArgs = args?.length ? `${command} ${args.join(' ')}` : command
348
+ const commandWithArgs = formatCommandWithArgs(command, args)
418
349
  const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} completed`)
419
350
 
420
351
  console.log(text)
@@ -425,7 +356,7 @@ export const githubActionsLogger = defineLogger({
425
356
  })
426
357
 
427
358
  context.on('generation:summary', (config, { status, hrStart, failedPlugins }) => {
428
- const pluginsCount = config.plugins?.length || 0
359
+ const pluginsCount = config.plugins?.length ?? 0
429
360
  const successCount = pluginsCount - failedPlugins.size
430
361
  const duration = formatHrtime(hrStart)
431
362
 
@@ -443,5 +374,9 @@ export const githubActionsLogger = defineLogger({
443
374
  closeGroup(config.name ? `Generation for ${styleText('bold', config.name)}` : 'Generation')
444
375
  }
445
376
  })
377
+
378
+ context.on('lifecycle:end', () => {
379
+ reset()
380
+ })
446
381
  },
447
382
  })