@kubb/cli 5.0.0-alpha.9 → 5.0.0-beta.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.
Files changed (173) hide show
  1. package/README.md +180 -27
  2. package/bin/kubb.js +6 -0
  3. package/dist/agent-Bx2yllmS.js +68 -0
  4. package/dist/agent-Bx2yllmS.js.map +1 -0
  5. package/dist/agent-CeLwj5im.cjs +70 -0
  6. package/dist/agent-CeLwj5im.cjs.map +1 -0
  7. package/dist/{chunk--u3MIqq1.js → chunk-BvFE5Tac.js} +1 -0
  8. package/dist/constants-B2JTeRBb.js +42 -0
  9. package/dist/constants-B2JTeRBb.js.map +1 -0
  10. package/dist/constants-BINTA5VZ.cjs +77 -0
  11. package/dist/constants-BINTA5VZ.cjs.map +1 -0
  12. package/dist/constants-BYGmiFs0.cjs +139 -0
  13. package/dist/constants-BYGmiFs0.cjs.map +1 -0
  14. package/dist/constants-DSJ-Xrbv.js +116 -0
  15. package/dist/constants-DSJ-Xrbv.js.map +1 -0
  16. package/dist/define-Bdn8j5VM.cjs +54 -0
  17. package/dist/define-Bdn8j5VM.cjs.map +1 -0
  18. package/dist/define-m_fp-Aqm.js +43 -0
  19. package/dist/define-m_fp-Aqm.js.map +1 -0
  20. package/dist/errors-CINO1EIv.js +43 -0
  21. package/dist/errors-CINO1EIv.js.map +1 -0
  22. package/dist/{errors-DBW0N9w4.cjs → errors-CLCjoSg0.cjs} +22 -6
  23. package/dist/errors-CLCjoSg0.cjs.map +1 -0
  24. package/dist/{generate-Rly1EXBN.js → generate-BLvcvoIj.js} +12 -6
  25. package/dist/generate-BLvcvoIj.js.map +1 -0
  26. package/dist/{generate-DU5zzc54.cjs → generate-drLxTAnz.cjs} +11 -5
  27. package/dist/generate-drLxTAnz.cjs.map +1 -0
  28. package/dist/index.cjs +52 -21
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.js +53 -22
  32. package/dist/index.js.map +1 -1
  33. package/dist/init-CGu7JZEF.js +53 -0
  34. package/dist/init-CGu7JZEF.js.map +1 -0
  35. package/dist/init-CyCjvIEF.cjs +53 -0
  36. package/dist/init-CyCjvIEF.cjs.map +1 -0
  37. package/dist/mcp-Cq2sylQC.js +39 -0
  38. package/dist/mcp-Cq2sylQC.js.map +1 -0
  39. package/dist/mcp-DSF5gpI-.cjs +39 -0
  40. package/dist/mcp-DSF5gpI-.cjs.map +1 -0
  41. package/dist/{package-BJ6ionm6.cjs → package-DZ-6zAIO.cjs} +2 -2
  42. package/dist/package-DZ-6zAIO.cjs.map +1 -0
  43. package/dist/package-OLYIpjqw.js +6 -0
  44. package/dist/package-OLYIpjqw.js.map +1 -0
  45. package/dist/{generate-BHNyeQXl.js → run-Bfbr3RaM.js} +781 -502
  46. package/dist/run-Bfbr3RaM.js.map +1 -0
  47. package/dist/run-BzpYYOQs.js +121 -0
  48. package/dist/run-BzpYYOQs.js.map +1 -0
  49. package/dist/run-CCZ24VKk.js +51 -0
  50. package/dist/run-CCZ24VKk.js.map +1 -0
  51. package/dist/run-CF97BWVa.js +244 -0
  52. package/dist/run-CF97BWVa.js.map +1 -0
  53. package/dist/run-CQbj3ley.cjs +52 -0
  54. package/dist/run-CQbj3ley.cjs.map +1 -0
  55. package/dist/{generate-Cq5RDTBL.cjs → run-CVlrIZoW.cjs} +786 -507
  56. package/dist/run-CVlrIZoW.cjs.map +1 -0
  57. package/dist/run-D0hmRpHy.js +49 -0
  58. package/dist/run-D0hmRpHy.js.map +1 -0
  59. package/dist/run-DwdAwnLG.cjs +125 -0
  60. package/dist/run-DwdAwnLG.cjs.map +1 -0
  61. package/dist/run-Lr0Ctnu0.cjs +50 -0
  62. package/dist/run-Lr0Ctnu0.cjs.map +1 -0
  63. package/dist/run-YsoCk5we.cjs +248 -0
  64. package/dist/run-YsoCk5we.cjs.map +1 -0
  65. package/dist/{shell-7HPrTCJ5.cjs → shell-475fQKaX.cjs} +8 -3
  66. package/dist/shell-475fQKaX.cjs.map +1 -0
  67. package/dist/{shell-DqqWsHCD.js → shell-CN6DNqeC.js} +9 -4
  68. package/dist/shell-CN6DNqeC.js.map +1 -0
  69. package/dist/{telemetry-DZ7IrLAU.cjs → telemetry-B2iWkY5e.cjs} +53 -13
  70. package/dist/telemetry-B2iWkY5e.cjs.map +1 -0
  71. package/dist/{telemetry-BF3SMlH6.js → telemetry-BkektVz6.js} +52 -12
  72. package/dist/telemetry-BkektVz6.js.map +1 -0
  73. package/dist/validate-CAUqLaGt.js +26 -0
  74. package/dist/validate-CAUqLaGt.js.map +1 -0
  75. package/dist/validate-J6AEd5zK.cjs +26 -0
  76. package/dist/validate-J6AEd5zK.cjs.map +1 -0
  77. package/package.json +57 -48
  78. package/src/commands/agent/start.ts +27 -8
  79. package/src/commands/agent.ts +3 -1
  80. package/src/commands/generate.ts +39 -8
  81. package/src/commands/init.ts +40 -4
  82. package/src/commands/mcp.ts +28 -4
  83. package/src/commands/validate.ts +11 -4
  84. package/src/constants.ts +5 -80
  85. package/src/index.ts +12 -13
  86. package/src/loggers/clackLogger.ts +98 -88
  87. package/src/loggers/fileSystemLogger.ts +37 -25
  88. package/src/loggers/githubActionsLogger.ts +35 -48
  89. package/src/loggers/plainLogger.ts +33 -45
  90. package/src/loggers/types.ts +6 -0
  91. package/src/loggers/utils.ts +155 -9
  92. package/src/runners/agent/run.ts +113 -0
  93. package/src/runners/agent/utils.ts +98 -0
  94. package/src/runners/generate/run.ts +276 -0
  95. package/src/runners/generate/utils.ts +209 -0
  96. package/src/runners/init/run.ts +211 -0
  97. package/src/{utils/packageManager.ts → runners/init/utils.ts} +10 -0
  98. package/src/runners/mcp/run.ts +55 -0
  99. package/src/runners/validate/run.ts +63 -0
  100. package/src/{utils/telemetry.ts → telemetry.ts} +28 -8
  101. package/bin/kubb.cjs +0 -18
  102. package/dist/agent-5mmp7QzF.js +0 -56
  103. package/dist/agent-5mmp7QzF.js.map +0 -1
  104. package/dist/agent-BKphjOIF.cjs +0 -58
  105. package/dist/agent-BKphjOIF.cjs.map +0 -1
  106. package/dist/agent-BapvKB4r.cjs +0 -92
  107. package/dist/agent-BapvKB4r.cjs.map +0 -1
  108. package/dist/agent-CBrpIMMU.js +0 -88
  109. package/dist/agent-CBrpIMMU.js.map +0 -1
  110. package/dist/constants-D0XHAHeZ.cjs +0 -178
  111. package/dist/constants-D0XHAHeZ.cjs.map +0 -1
  112. package/dist/constants-DJM9zCXm.js +0 -131
  113. package/dist/constants-DJM9zCXm.js.map +0 -1
  114. package/dist/define--M_JMcDC.js +0 -25
  115. package/dist/define--M_JMcDC.js.map +0 -1
  116. package/dist/define-D6Kfm7-Z.cjs +0 -36
  117. package/dist/define-D6Kfm7-Z.cjs.map +0 -1
  118. package/dist/errors-6mF_WKxg.js +0 -27
  119. package/dist/errors-6mF_WKxg.js.map +0 -1
  120. package/dist/errors-DBW0N9w4.cjs.map +0 -1
  121. package/dist/generate-BHNyeQXl.js.map +0 -1
  122. package/dist/generate-Cq5RDTBL.cjs.map +0 -1
  123. package/dist/generate-DU5zzc54.cjs.map +0 -1
  124. package/dist/generate-Rly1EXBN.js.map +0 -1
  125. package/dist/init-BK6inBTR.cjs +0 -306
  126. package/dist/init-BK6inBTR.cjs.map +0 -1
  127. package/dist/init-BQ6zfsnw.js +0 -302
  128. package/dist/init-BQ6zfsnw.js.map +0 -1
  129. package/dist/init-CN1JFyGX.cjs +0 -25
  130. package/dist/init-CN1JFyGX.cjs.map +0 -1
  131. package/dist/init-iN7e1XwI.js +0 -25
  132. package/dist/init-iN7e1XwI.js.map +0 -1
  133. package/dist/jiti-Cd3S0xwr.cjs +0 -16
  134. package/dist/jiti-Cd3S0xwr.cjs.map +0 -1
  135. package/dist/jiti-e08mD2Ph.js +0 -11
  136. package/dist/jiti-e08mD2Ph.js.map +0 -1
  137. package/dist/mcp-BiGUvbWP.js +0 -41
  138. package/dist/mcp-BiGUvbWP.js.map +0 -1
  139. package/dist/mcp-CONmm_xT.cjs +0 -42
  140. package/dist/mcp-CONmm_xT.cjs.map +0 -1
  141. package/dist/mcp-T7Q4nWbT.cjs +0 -16
  142. package/dist/mcp-T7Q4nWbT.cjs.map +0 -1
  143. package/dist/mcp-eP1S40LZ.js +0 -16
  144. package/dist/mcp-eP1S40LZ.js.map +0 -1
  145. package/dist/package-BJ6ionm6.cjs.map +0 -1
  146. package/dist/package-BKZ0H3Zf.js +0 -6
  147. package/dist/package-BKZ0H3Zf.js.map +0 -1
  148. package/dist/shell-7HPrTCJ5.cjs.map +0 -1
  149. package/dist/shell-DqqWsHCD.js.map +0 -1
  150. package/dist/telemetry-BF3SMlH6.js.map +0 -1
  151. package/dist/telemetry-DZ7IrLAU.cjs.map +0 -1
  152. package/dist/validate-BImbbx1t.js +0 -41
  153. package/dist/validate-BImbbx1t.js.map +0 -1
  154. package/dist/validate-DAZdX_0i.js +0 -25
  155. package/dist/validate-DAZdX_0i.js.map +0 -1
  156. package/dist/validate-DucFMytl.cjs +0 -25
  157. package/dist/validate-DucFMytl.cjs.map +0 -1
  158. package/dist/validate-ujLCYSWU.cjs +0 -42
  159. package/dist/validate-ujLCYSWU.cjs.map +0 -1
  160. package/src/runners/agent.ts +0 -102
  161. package/src/runners/generate.ts +0 -343
  162. package/src/runners/init.ts +0 -323
  163. package/src/runners/mcp.ts +0 -32
  164. package/src/runners/validate.ts +0 -35
  165. package/src/types.ts +0 -11
  166. package/src/utils/Writables.ts +0 -17
  167. package/src/utils/executeHooks.ts +0 -45
  168. package/src/utils/flags.ts +0 -10
  169. package/src/utils/getCosmiConfig.ts +0 -71
  170. package/src/utils/getSummary.ts +0 -68
  171. package/src/utils/jiti.ts +0 -9
  172. package/src/utils/runHook.ts +0 -75
  173. package/src/utils/watcher.ts +0 -19
@@ -1,12 +1,10 @@
1
1
  import { styleText } from 'node:util'
2
2
  import { formatHrtime, formatMs, formatMsWithColor, toCause } from '@internals/utils'
3
3
  import { type Config, defineLogger, logLevel as logLevelMap } from '@kubb/core'
4
- import { runHook } from '../utils/runHook.ts'
5
4
  import { buildProgressLine, formatCommandWithArgs, formatMessage } from './utils.ts'
6
5
 
7
6
  /**
8
- * GitHub Actions adapter for CI environments
9
- * Uses Github group annotations for collapsible sections
7
+ * GitHub Actions logger using group annotations for collapsible sections in CI.
10
8
  */
11
9
  export const githubActionsLogger = defineLogger({
12
10
  name: 'github-actions',
@@ -55,7 +53,7 @@ export const githubActionsLogger = defineLogger({
55
53
  console.log('::endgroup::')
56
54
  }
57
55
 
58
- context.on('info', (message, info = '') => {
56
+ context.on('kubb:info', ({ message, info = '' }) => {
59
57
  if (logLevel <= logLevelMap.silent) {
60
58
  return
61
59
  }
@@ -65,7 +63,7 @@ export const githubActionsLogger = defineLogger({
65
63
  console.log(text)
66
64
  })
67
65
 
68
- context.on('success', (message, info = '') => {
66
+ context.on('kubb:success', ({ message, info = '' }) => {
69
67
  if (logLevel <= logLevelMap.silent) {
70
68
  return
71
69
  }
@@ -75,7 +73,7 @@ export const githubActionsLogger = defineLogger({
75
73
  console.log(text)
76
74
  })
77
75
 
78
- context.on('warn', (message, info = '') => {
76
+ context.on('kubb:warn', ({ message, info = '' }) => {
79
77
  if (logLevel <= logLevelMap.silent) {
80
78
  return
81
79
  }
@@ -85,7 +83,7 @@ export const githubActionsLogger = defineLogger({
85
83
  console.warn(`::warning::${text}`)
86
84
  })
87
85
 
88
- context.on('error', (error) => {
86
+ context.on('kubb:error', ({ error }) => {
89
87
  const caused = toCause(error)
90
88
 
91
89
  if (logLevel <= logLevelMap.silent) {
@@ -112,12 +110,12 @@ export const githubActionsLogger = defineLogger({
112
110
  }
113
111
  })
114
112
 
115
- context.on('lifecycle:start', (version) => {
113
+ context.on('kubb:lifecycle:start', ({ version }) => {
116
114
  console.log(styleText('yellow', `Kubb ${version} 🧩`))
117
115
  reset()
118
116
  })
119
117
 
120
- context.on('config:start', () => {
118
+ context.on('kubb:config:start', () => {
121
119
  if (logLevel <= logLevelMap.silent) {
122
120
  return
123
121
  }
@@ -129,7 +127,7 @@ export const githubActionsLogger = defineLogger({
129
127
  console.log(text)
130
128
  })
131
129
 
132
- context.on('config:end', (configs) => {
130
+ context.on('kubb:config:end', ({ configs }) => {
133
131
  state.currentConfigs = configs
134
132
 
135
133
  if (logLevel <= logLevelMap.silent) {
@@ -143,7 +141,7 @@ export const githubActionsLogger = defineLogger({
143
141
  closeGroup('Configuration')
144
142
  })
145
143
 
146
- context.on('generation:start', (config) => {
144
+ context.on('kubb:generation:start', ({ config }) => {
147
145
  reset()
148
146
 
149
147
  // Initialize progress tracking for this generation
@@ -160,7 +158,7 @@ export const githubActionsLogger = defineLogger({
160
158
  }
161
159
  })
162
160
 
163
- context.on('plugin:start', (plugin) => {
161
+ context.on('kubb:plugin:start', ({ plugin }) => {
164
162
  if (logLevel <= logLevelMap.silent) {
165
163
  return
166
164
  }
@@ -173,7 +171,7 @@ export const githubActionsLogger = defineLogger({
173
171
  console.log(text)
174
172
  })
175
173
 
176
- context.on('plugin:end', (plugin, { duration, success }) => {
174
+ context.on('kubb:plugin:end', ({ plugin, duration, success }) => {
177
175
  if (logLevel <= logLevelMap.silent) {
178
176
  return
179
177
  }
@@ -204,7 +202,7 @@ export const githubActionsLogger = defineLogger({
204
202
  showProgressStep()
205
203
  })
206
204
 
207
- context.on('files:processing:start', (files) => {
205
+ context.on('kubb:files:processing:start', ({ files }) => {
208
206
  if (logLevel <= logLevelMap.silent) {
209
207
  return
210
208
  }
@@ -220,7 +218,7 @@ export const githubActionsLogger = defineLogger({
220
218
  console.log(text)
221
219
  })
222
220
 
223
- context.on('files:processing:end', () => {
221
+ context.on('kubb:files:processing:end', () => {
224
222
  if (logLevel <= logLevelMap.silent) {
225
223
  return
226
224
  }
@@ -236,7 +234,7 @@ export const githubActionsLogger = defineLogger({
236
234
  showProgressStep()
237
235
  })
238
236
 
239
- context.on('file:processing:update', () => {
237
+ context.on('kubb:file:processing:update', () => {
240
238
  if (logLevel <= logLevelMap.silent) {
241
239
  return
242
240
  }
@@ -244,7 +242,7 @@ export const githubActionsLogger = defineLogger({
244
242
  state.processedFiles++
245
243
  })
246
244
 
247
- context.on('generation:end', (config) => {
245
+ context.on('kubb:generation:end', ({ config }) => {
248
246
  const text = getMessage(
249
247
  config.name ? `${styleText('blue', '✓')} Generation completed for ${styleText('dim', config.name)}` : `${styleText('blue', '✓')} Generation completed`,
250
248
  )
@@ -252,7 +250,7 @@ export const githubActionsLogger = defineLogger({
252
250
  console.log(text)
253
251
  })
254
252
 
255
- context.on('format:start', () => {
253
+ context.on('kubb:format:start', () => {
256
254
  if (logLevel <= logLevelMap.silent) {
257
255
  return
258
256
  }
@@ -266,7 +264,7 @@ export const githubActionsLogger = defineLogger({
266
264
  console.log(text)
267
265
  })
268
266
 
269
- context.on('format:end', () => {
267
+ context.on('kubb:format:end', () => {
270
268
  if (logLevel <= logLevelMap.silent) {
271
269
  return
272
270
  }
@@ -280,7 +278,7 @@ export const githubActionsLogger = defineLogger({
280
278
  }
281
279
  })
282
280
 
283
- context.on('lint:start', () => {
281
+ context.on('kubb:lint:start', () => {
284
282
  if (logLevel <= logLevelMap.silent) {
285
283
  return
286
284
  }
@@ -294,7 +292,7 @@ export const githubActionsLogger = defineLogger({
294
292
  console.log(text)
295
293
  })
296
294
 
297
- context.on('lint:end', () => {
295
+ context.on('kubb:lint:end', () => {
298
296
  if (logLevel <= logLevelMap.silent) {
299
297
  return
300
298
  }
@@ -308,37 +306,21 @@ export const githubActionsLogger = defineLogger({
308
306
  }
309
307
  })
310
308
 
311
- context.on('hook:start', async ({ id, command, args }) => {
309
+ context.on('kubb:hook:start', ({ command, args }) => {
310
+ if (logLevel <= logLevelMap.silent) {
311
+ return
312
+ }
313
+
312
314
  const commandWithArgs = formatCommandWithArgs(command, args)
313
315
  const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} started`)
314
316
 
315
- if (logLevel > logLevelMap.silent) {
316
- if (state.currentConfigs.length === 1) {
317
- openGroup(`Hook ${commandWithArgs}`)
318
- }
319
- console.log(text)
320
- }
321
-
322
- // Skip hook execution if no id is provided (e.g., during benchmarks or tests)
323
- if (!id) {
324
- return
317
+ if (state.currentConfigs.length === 1) {
318
+ openGroup(`Hook ${commandWithArgs}`)
325
319
  }
326
-
327
- await runHook({
328
- id,
329
- command,
330
- args,
331
- commandWithArgs,
332
- context,
333
- sink: {
334
- // GHA formats errors with the ::error:: annotation
335
- onStdout: logLevel > logLevelMap.silent ? (s) => console.log(s) : undefined,
336
- onStderr: logLevel > logLevelMap.silent ? (s) => console.error(`::error::${s}`) : undefined,
337
- },
338
- })
320
+ console.log(text)
339
321
  })
340
322
 
341
- context.on('hook:end', ({ command, args }) => {
323
+ context.on('kubb:hook:end', ({ command, args }) => {
342
324
  if (logLevel <= logLevelMap.silent) {
343
325
  return
344
326
  }
@@ -353,7 +335,7 @@ export const githubActionsLogger = defineLogger({
353
335
  }
354
336
  })
355
337
 
356
- context.on('generation:summary', (config, { status, hrStart, failedPlugins }) => {
338
+ context.on('kubb:generation:summary', ({ config, status, hrStart, failedPlugins }) => {
357
339
  const pluginsCount = config.plugins?.length ?? 0
358
340
  const successCount = pluginsCount - failedPlugins.size
359
341
  const duration = formatHrtime(hrStart)
@@ -373,8 +355,13 @@ export const githubActionsLogger = defineLogger({
373
355
  }
374
356
  })
375
357
 
376
- context.on('lifecycle:end', () => {
358
+ context.on('kubb:lifecycle:end', () => {
377
359
  reset()
378
360
  })
361
+
362
+ return (_commandWithArgs: string) => ({
363
+ onStdout: logLevel > logLevelMap.silent ? (s: string) => console.log(s) : undefined,
364
+ onStderr: logLevel > logLevelMap.silent ? (s: string) => console.error(`::error::${s}`) : undefined,
365
+ })
379
366
  },
380
367
  })
@@ -2,13 +2,11 @@ import { relative } from 'node:path'
2
2
  import { formatMs, toCause } from '@internals/utils'
3
3
  import { defineLogger, logLevel as logLevelMap } from '@kubb/core'
4
4
  import { SUMMARY_SEPARATOR } from '../constants.ts'
5
- import { getSummary } from '../utils/getSummary.ts'
6
- import { runHook } from '../utils/runHook.ts'
5
+ import { getSummary } from './utils.ts'
7
6
  import { formatCommandWithArgs, formatMessage } from './utils.ts'
8
7
 
9
8
  /**
10
- * Plain console adapter for non-TTY environments
11
- * Simple console.log output with indentation
9
+ * Plain console adapter for non-TTY environments with simple `console.log` output.
12
10
  */
13
11
  export const plainLogger = defineLogger({
14
12
  name: 'plain',
@@ -19,7 +17,7 @@ export const plainLogger = defineLogger({
19
17
  return formatMessage(message, logLevel)
20
18
  }
21
19
 
22
- context.on('info', (message, info) => {
20
+ context.on('kubb:info', ({ message, info }) => {
23
21
  if (logLevel <= logLevelMap.silent) {
24
22
  return
25
23
  }
@@ -29,7 +27,7 @@ export const plainLogger = defineLogger({
29
27
  console.log(text)
30
28
  })
31
29
 
32
- context.on('success', (message, info = '') => {
30
+ context.on('kubb:success', ({ message, info = '' }) => {
33
31
  if (logLevel <= logLevelMap.silent) {
34
32
  return
35
33
  }
@@ -39,7 +37,7 @@ export const plainLogger = defineLogger({
39
37
  console.log(text)
40
38
  })
41
39
 
42
- context.on('warn', (message, info) => {
40
+ context.on('kubb:warn', ({ message, info }) => {
43
41
  if (logLevel < logLevelMap.warn) {
44
42
  return
45
43
  }
@@ -49,7 +47,7 @@ export const plainLogger = defineLogger({
49
47
  console.log(text)
50
48
  })
51
49
 
52
- context.on('error', (error) => {
50
+ context.on('kubb:error', ({ error }) => {
53
51
  const caused = toCause(error)
54
52
 
55
53
  const text = getMessage(['✗', error.message].join(' '))
@@ -74,11 +72,11 @@ export const plainLogger = defineLogger({
74
72
  }
75
73
  })
76
74
 
77
- context.on('lifecycle:start', () => {
75
+ context.on('kubb:lifecycle:start', () => {
78
76
  console.log('Kubb CLI 🧩')
79
77
  })
80
78
 
81
- context.on('config:start', () => {
79
+ context.on('kubb:config:start', () => {
82
80
  if (logLevel <= logLevelMap.silent) {
83
81
  return
84
82
  }
@@ -88,7 +86,7 @@ export const plainLogger = defineLogger({
88
86
  console.log(text)
89
87
  })
90
88
 
91
- context.on('config:end', () => {
89
+ context.on('kubb:config:end', () => {
92
90
  if (logLevel <= logLevelMap.silent) {
93
91
  return
94
92
  }
@@ -98,13 +96,13 @@ export const plainLogger = defineLogger({
98
96
  console.log(text)
99
97
  })
100
98
 
101
- context.on('generation:start', () => {
99
+ context.on('kubb:generation:start', () => {
102
100
  const text = getMessage('Generation started')
103
101
 
104
102
  console.log(text)
105
103
  })
106
104
 
107
- context.on('plugin:start', (plugin) => {
105
+ context.on('kubb:plugin:start', ({ plugin }) => {
108
106
  if (logLevel <= logLevelMap.silent) {
109
107
  return
110
108
  }
@@ -113,7 +111,7 @@ export const plainLogger = defineLogger({
113
111
  console.log(text)
114
112
  })
115
113
 
116
- context.on('plugin:end', (plugin, { duration, success }) => {
114
+ context.on('kubb:plugin:end', ({ plugin, duration, success }) => {
117
115
  if (logLevel <= logLevelMap.silent) {
118
116
  return
119
117
  }
@@ -124,7 +122,7 @@ export const plainLogger = defineLogger({
124
122
  console.log(text)
125
123
  })
126
124
 
127
- context.on('files:processing:start', (files) => {
125
+ context.on('kubb:files:processing:start', ({ files }) => {
128
126
  if (logLevel <= logLevelMap.silent) {
129
127
  return
130
128
  }
@@ -134,7 +132,7 @@ export const plainLogger = defineLogger({
134
132
  console.log(text)
135
133
  })
136
134
 
137
- context.on('file:processing:update', ({ file, config }) => {
135
+ context.on('kubb:file:processing:update', ({ file, config }) => {
138
136
  if (logLevel <= logLevelMap.silent) {
139
137
  return
140
138
  }
@@ -144,7 +142,7 @@ export const plainLogger = defineLogger({
144
142
  console.log(text)
145
143
  })
146
144
 
147
- context.on('files:processing:end', () => {
145
+ context.on('kubb:files:processing:end', () => {
148
146
  if (logLevel <= logLevelMap.silent) {
149
147
  return
150
148
  }
@@ -154,13 +152,13 @@ export const plainLogger = defineLogger({
154
152
  console.log(text)
155
153
  })
156
154
 
157
- context.on('generation:end', (config) => {
155
+ context.on('kubb:generation:end', ({ config }) => {
158
156
  const text = getMessage(config.name ? `Generation completed for ${config.name}` : 'Generation completed')
159
157
 
160
158
  console.log(text)
161
159
  })
162
160
 
163
- context.on('format:start', () => {
161
+ context.on('kubb:format:start', () => {
164
162
  if (logLevel <= logLevelMap.silent) {
165
163
  return
166
164
  }
@@ -170,7 +168,7 @@ export const plainLogger = defineLogger({
170
168
  console.log(text)
171
169
  })
172
170
 
173
- context.on('format:end', () => {
171
+ context.on('kubb:format:end', () => {
174
172
  if (logLevel <= logLevelMap.silent) {
175
173
  return
176
174
  }
@@ -180,7 +178,7 @@ export const plainLogger = defineLogger({
180
178
  console.log(text)
181
179
  })
182
180
 
183
- context.on('lint:start', () => {
181
+ context.on('kubb:lint:start', () => {
184
182
  if (logLevel <= logLevelMap.silent) {
185
183
  return
186
184
  }
@@ -190,7 +188,7 @@ export const plainLogger = defineLogger({
190
188
  console.log(text)
191
189
  })
192
190
 
193
- context.on('lint:end', () => {
191
+ context.on('kubb:lint:end', () => {
194
192
  if (logLevel <= logLevelMap.silent) {
195
193
  return
196
194
  }
@@ -200,33 +198,18 @@ export const plainLogger = defineLogger({
200
198
  console.log(text)
201
199
  })
202
200
 
203
- context.on('hook:start', async ({ id, command, args }) => {
204
- const commandWithArgs = formatCommandWithArgs(command, args)
205
- const text = getMessage(`Hook ${commandWithArgs} started`)
206
-
207
- if (logLevel > logLevelMap.silent) {
208
- console.log(text)
209
- }
210
-
211
- // Skip hook execution if no id is provided (e.g., during benchmarks or tests)
212
- if (!id) {
201
+ context.on('kubb:hook:start', ({ command, args }) => {
202
+ if (logLevel <= logLevelMap.silent) {
213
203
  return
214
204
  }
215
205
 
216
- await runHook({
217
- id,
218
- command,
219
- args,
220
- commandWithArgs,
221
- context,
222
- sink: {
223
- onStdout: logLevel > logLevelMap.silent ? (s) => console.log(s) : undefined,
224
- onStderr: logLevel > logLevelMap.silent ? (s) => console.error(s) : undefined,
225
- },
226
- })
206
+ const commandWithArgs = formatCommandWithArgs(command, args)
207
+ const text = getMessage(`Hook ${commandWithArgs} started`)
208
+
209
+ console.log(text)
227
210
  })
228
211
 
229
- context.on('hook:end', ({ command, args }) => {
212
+ context.on('kubb:hook:end', ({ command, args }) => {
230
213
  if (logLevel <= logLevelMap.silent) {
231
214
  return
232
215
  }
@@ -237,7 +220,7 @@ export const plainLogger = defineLogger({
237
220
  console.log(text)
238
221
  })
239
222
 
240
- context.on('generation:summary', (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
223
+ context.on('kubb:generation:summary', ({ config, pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
241
224
  const summary = getSummary({
242
225
  failedPlugins,
243
226
  filesCreated,
@@ -251,5 +234,10 @@ export const plainLogger = defineLogger({
251
234
  console.log(summary.join('\n'))
252
235
  console.log(SUMMARY_SEPARATOR)
253
236
  })
237
+
238
+ return (_commandWithArgs: string) => ({
239
+ onStdout: logLevel > logLevelMap.silent ? (s: string) => console.log(s) : undefined,
240
+ onStderr: logLevel > logLevelMap.silent ? (s: string) => console.error(s) : undefined,
241
+ })
254
242
  },
255
243
  })
@@ -1 +1,7 @@
1
+ /**
2
+ * Logger adapter selected by `setupLogger` based on the runtime environment.
3
+ * - `'clack'`: TTY-aware output with spinners and progress bars.
4
+ * - `'github-actions'`: CI output using `::group::` annotations.
5
+ * - `'plain'`: Plain `console.log` output for non-TTY environments.
6
+ */
1
7
  export type LoggerType = 'clack' | 'github-actions' | 'plain'
@@ -1,13 +1,57 @@
1
+ import path from 'node:path'
1
2
  import { styleText } from 'node:util'
2
- import { canUseTTY, formatHrtime, isGitHubActions } from '@internals/utils'
3
- import type { Logger, LoggerContext, LoggerOptions } from '@kubb/core'
3
+ import { canUseTTY, formatHrtime, isGitHubActions, randomCliColor } from '@internals/utils'
4
+ import type { Config, Logger, LoggerContext, LoggerOptions, Plugin } from '@kubb/core'
4
5
  import { logLevel as logLevelMap } from '@kubb/core'
6
+ import { SUMMARY_MAX_BAR_LENGTH, SUMMARY_TIME_SCALE_DIVISOR } from '../constants.ts'
5
7
  import { clackLogger } from './clackLogger.ts'
6
8
  import { fileSystemLogger } from './fileSystemLogger.ts'
7
9
  import { githubActionsLogger } from './githubActionsLogger.ts'
8
10
  import { plainLogger } from './plainLogger.ts'
9
11
  import type { LoggerType } from './types.ts'
10
12
 
13
+ /**
14
+ * Output sink for a hook subprocess, controlling how streamed lines and exit output are forwarded.
15
+ */
16
+ type HookOutputSink = {
17
+ /**
18
+ * Called for each streamed stdout line while the hook runs.
19
+ */
20
+ onLine?: (line: string) => void
21
+ /**
22
+ * Called with stderr content after the hook exits with a non-zero code.
23
+ */
24
+ onStderr?: (text: string) => void
25
+ /**
26
+ * Called with stdout content after the hook exits with a non-zero code.
27
+ */
28
+ onStdout?: (text: string) => void
29
+ }
30
+
31
+ /**
32
+ * Output sink combined with stream control for a hook subprocess.
33
+ */
34
+ export type HookSinkOptions = HookOutputSink & {
35
+ /**
36
+ * When `true`, streams process output line-by-line via `onLine`.
37
+ *
38
+ * @default false
39
+ */
40
+ stream?: boolean
41
+ }
42
+
43
+ /**
44
+ * Factory called once per hook command to build the output sink and streaming flag.
45
+ * The function should set up any logger UI (e.g., spinner) and return callbacks that forward subprocess output to it.
46
+ */
47
+ export type HookSinkFactory = (commandWithArgs: string) => HookSinkOptions | undefined
48
+
49
+ /**
50
+ * Logger variant that may return a {@link HookSinkFactory} from `install`.
51
+ * The factory is forwarded to hook execution so the logger controls subprocess output routing.
52
+ */
53
+ type CLILogger = Logger<LoggerOptions, HookSinkFactory | void>
54
+
11
55
  /**
12
56
  * Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose.
13
57
  * Shared across all logger adapters to avoid duplication.
@@ -26,11 +70,29 @@ export function formatMessage(message: string, logLevel: number): string {
26
70
  }
27
71
 
28
72
  type ProgressState = {
73
+ /**
74
+ * Total number of plugins scheduled for this generation run.
75
+ */
29
76
  totalPlugins: number
77
+ /**
78
+ * Number of plugins that have finished without error.
79
+ */
30
80
  completedPlugins: number
81
+ /**
82
+ * Number of plugins that exited with an error.
83
+ */
31
84
  failedPlugins: number
85
+ /**
86
+ * Total number of files expected to be written.
87
+ */
32
88
  totalFiles: number
89
+ /**
90
+ * Number of files written so far.
91
+ */
33
92
  processedFiles: number
93
+ /**
94
+ * `process.hrtime()` snapshot taken at the start of generation, used to compute elapsed time.
95
+ */
34
96
  hrStart: [number, number]
35
97
  }
36
98
 
@@ -80,27 +142,111 @@ function detectLogger(): LoggerType {
80
142
  return 'plain'
81
143
  }
82
144
 
83
- const logMapper = {
145
+ const logMapper: Record<LoggerType, CLILogger> = {
84
146
  clack: clackLogger,
85
147
  plain: plainLogger,
86
148
  'github-actions': githubActionsLogger,
87
- } as const satisfies Record<LoggerType, Logger>
149
+ }
88
150
 
89
- export async function setupLogger(context: LoggerContext, { logLevel }: LoggerOptions): Promise<void> {
151
+ export async function setupLogger(context: LoggerContext, { logLevel }: LoggerOptions): Promise<HookSinkFactory | undefined> {
90
152
  const type = detectLogger()
91
153
 
92
- const logger = logMapper[type] as Logger
154
+ const logger = logMapper[type]
93
155
 
94
156
  if (!logger) {
95
157
  throw new Error(`Unknown adapter type: ${type}`)
96
158
  }
97
159
 
98
- // Install primary logger
99
- const cleanup = await logger.install(context, { logLevel })
160
+ const makeSink = await logger.install(context, { logLevel })
100
161
 
101
162
  if (logLevel >= logLevelMap.debug) {
102
163
  await fileSystemLogger.install(context, { logLevel })
103
164
  }
104
165
 
105
- return cleanup
166
+ return typeof makeSink === 'function' ? makeSink : undefined
167
+ }
168
+
169
+ type SummaryProps = {
170
+ /**
171
+ * Set of plugins that failed during this generation run, each with its error.
172
+ */
173
+ failedPlugins: Set<{ plugin: Plugin; error: Error }>
174
+ /**
175
+ * Overall generation status used to choose success or failure formatting.
176
+ */
177
+ status: 'success' | 'failed'
178
+ /**
179
+ * `process.hrtime()` snapshot taken at the start of generation, used to compute elapsed time.
180
+ */
181
+ hrStart: [number, number]
182
+ /**
183
+ * Total number of files written during this generation run.
184
+ */
185
+ filesCreated: number
186
+ /**
187
+ * Resolved Kubb config for this generation entry, used to read plugin count and output path.
188
+ */
189
+ config: Config
190
+ /**
191
+ * Per-plugin timing map (plugin name → duration in ms). When provided, a timing bar chart is appended.
192
+ */
193
+ pluginTimings?: Map<string, number>
194
+ }
195
+
196
+ /**
197
+ * Builds the generation summary lines rendered in the end-of-run box.
198
+ * Returns an array of styled strings, one per summary row.
199
+ */
200
+ export function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }: SummaryProps): string[] {
201
+ const duration = formatHrtime(hrStart)
202
+
203
+ const pluginsCount = config.plugins?.length ?? 0
204
+ const successCount = pluginsCount - failedPlugins.size
205
+
206
+ const meta = {
207
+ plugins:
208
+ status === 'success'
209
+ ? `${styleText('green', `${successCount} successful`)}, ${pluginsCount} total`
210
+ : `${styleText('green', `${successCount} successful`)}, ${styleText('red', `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
211
+ pluginsFailed: status === 'failed' ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(', ') : undefined,
212
+ filesCreated,
213
+ time: styleText('green', duration),
214
+ output: path.resolve(config.root, config.output.path),
215
+ } as const
216
+
217
+ const labels = {
218
+ plugins: 'Plugins:',
219
+ failed: 'Failed:',
220
+ generated: 'Generated:',
221
+ pluginTimings: 'Plugin Timings:',
222
+ output: 'Output:',
223
+ }
224
+ const maxLength = Math.max(0, ...[...Object.values(labels), ...(pluginTimings ? Array.from(pluginTimings.keys()) : [])].map((s) => s.length))
225
+
226
+ const summaryLines: string[] = []
227
+ summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`)
228
+
229
+ if (meta.pluginsFailed) {
230
+ summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`)
231
+ }
232
+
233
+ summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`)
234
+
235
+ if (pluginTimings && pluginTimings.size > 0) {
236
+ const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1])
237
+
238
+ summaryLines.push(`${labels.pluginTimings}`)
239
+
240
+ sortedTimings.forEach(([name, time]) => {
241
+ const timeStr = time >= 1000 ? `${(time / 1000).toFixed(2)}s` : `${Math.round(time)}ms`
242
+ const barLength = Math.min(Math.ceil(time / SUMMARY_TIME_SCALE_DIVISOR), SUMMARY_MAX_BAR_LENGTH)
243
+ const bar = styleText('dim', '█'.repeat(barLength))
244
+
245
+ summaryLines.push(`${styleText('dim', '•')} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`)
246
+ })
247
+ }
248
+
249
+ summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`)
250
+
251
+ return summaryLines
106
252
  }