@kubb/cli 5.0.0-beta.4 → 5.0.0-beta.40

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 (155) hide show
  1. package/README.md +198 -36
  2. package/dist/agent-DQerNyd8.cjs +70 -0
  3. package/dist/agent-DQerNyd8.cjs.map +1 -0
  4. package/dist/agent-ZKJkTTGN.js +68 -0
  5. package/dist/agent-ZKJkTTGN.js.map +1 -0
  6. package/dist/{chunk--u3MIqq1.js → chunk-CRm0XQPb.js} +1 -0
  7. package/dist/constants-84a47qA-.js +35 -0
  8. package/dist/constants-84a47qA-.js.map +1 -0
  9. package/dist/constants-AHhyFH15.cjs +139 -0
  10. package/dist/constants-AHhyFH15.cjs.map +1 -0
  11. package/dist/constants-BtmponZ3.cjs +58 -0
  12. package/dist/constants-BtmponZ3.cjs.map +1 -0
  13. package/dist/constants-C94RKp3A.js +116 -0
  14. package/dist/constants-C94RKp3A.js.map +1 -0
  15. package/dist/{define-Bdn8j5VM.cjs → define-C4AB3POr.cjs} +2 -2
  16. package/dist/{define-Bdn8j5VM.cjs.map → define-C4AB3POr.cjs.map} +1 -1
  17. package/dist/{define-Ctii4bel.js → define-DNG1U8ha.js} +2 -2
  18. package/dist/{define-Ctii4bel.js.map → define-DNG1U8ha.js.map} +1 -1
  19. package/dist/{errors-CjPmyZHy.js → errors-CoxrNXaA.js} +2 -2
  20. package/dist/{errors-CjPmyZHy.js.map → errors-CoxrNXaA.js.map} +1 -1
  21. package/dist/{errors-CLCjoSg0.cjs → errors-DykI11xo.cjs} +2 -2
  22. package/dist/{errors-CLCjoSg0.cjs.map → errors-DykI11xo.cjs.map} +1 -1
  23. package/dist/generate-40x9PP4o.js +77 -0
  24. package/dist/generate-40x9PP4o.js.map +1 -0
  25. package/dist/generate-DQLvFw4z.cjs +76 -0
  26. package/dist/generate-DQLvFw4z.cjs.map +1 -0
  27. package/dist/index.cjs +23 -14
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.js +23 -14
  31. package/dist/index.js.map +1 -1
  32. package/dist/init-CT9RChdK.js +53 -0
  33. package/dist/init-CT9RChdK.js.map +1 -0
  34. package/dist/init-sEaUN7Dj.cjs +53 -0
  35. package/dist/init-sEaUN7Dj.cjs.map +1 -0
  36. package/dist/mcp-Siyb6fTT.cjs +39 -0
  37. package/dist/mcp-Siyb6fTT.cjs.map +1 -0
  38. package/dist/mcp-cjPrOeot.js +39 -0
  39. package/dist/mcp-cjPrOeot.js.map +1 -0
  40. package/dist/{package-BapVyQ-w.cjs → package-BJ6qam2Y.cjs} +2 -2
  41. package/dist/package-BJ6qam2Y.cjs.map +1 -0
  42. package/dist/package-CR5vEK4K.js +6 -0
  43. package/dist/package-CR5vEK4K.js.map +1 -0
  44. package/dist/{agent-sdYBBgrd.js → run-BQ3Qj0xB.js} +46 -43
  45. package/dist/run-BQ3Qj0xB.js.map +1 -0
  46. package/dist/run-BQzoaxjR.js +32 -0
  47. package/dist/run-BQzoaxjR.js.map +1 -0
  48. package/dist/run-CGf0KEts.js +51 -0
  49. package/dist/run-CGf0KEts.js.map +1 -0
  50. package/dist/{generate-CNrRLY4n.js → run-CHZKHTv0.js} +832 -828
  51. package/dist/run-CHZKHTv0.js.map +1 -0
  52. package/dist/{init-CZ5Xq2Hd.cjs → run-C_NMctua.cjs} +107 -149
  53. package/dist/run-C_NMctua.cjs.map +1 -0
  54. package/dist/{generate-B1Pa2ho-.cjs → run-CcQawFNK.cjs} +784 -780
  55. package/dist/run-CcQawFNK.cjs.map +1 -0
  56. package/dist/run-CkTpemme.cjs +52 -0
  57. package/dist/run-CkTpemme.cjs.map +1 -0
  58. package/dist/run-Cl4SrSob.cjs +33 -0
  59. package/dist/run-Cl4SrSob.cjs.map +1 -0
  60. package/dist/{agent-B4cAAab2.cjs → run-D-s2LdlW.cjs} +46 -43
  61. package/dist/run-D-s2LdlW.cjs.map +1 -0
  62. package/dist/{init-eNRlotJK.js → run-D8dCWepS.js} +107 -149
  63. package/dist/run-D8dCWepS.js.map +1 -0
  64. package/dist/{shell-DLzN4fRo.js → shell-BrqyJdB7.js} +2 -2
  65. package/dist/{shell-DLzN4fRo.js.map → shell-BrqyJdB7.js.map} +1 -1
  66. package/dist/{shell-475fQKaX.cjs → shell-Lh-vLWwH.cjs} +2 -2
  67. package/dist/{shell-475fQKaX.cjs.map → shell-Lh-vLWwH.cjs.map} +1 -1
  68. package/dist/validate-8pgfxUTy.js +26 -0
  69. package/dist/validate-8pgfxUTy.js.map +1 -0
  70. package/dist/validate-CstV7Pc2.cjs +26 -0
  71. package/dist/validate-CstV7Pc2.cjs.map +1 -0
  72. package/package.json +16 -15
  73. package/src/commands/agent/start.ts +10 -7
  74. package/src/commands/agent.ts +3 -1
  75. package/src/commands/generate.ts +21 -13
  76. package/src/commands/init.ts +34 -3
  77. package/src/commands/mcp.ts +28 -4
  78. package/src/commands/validate.ts +6 -4
  79. package/src/constants.ts +3 -74
  80. package/src/index.ts +6 -4
  81. package/src/loggers/clackLogger.ts +143 -181
  82. package/src/loggers/githubActionsLogger.ts +119 -121
  83. package/src/loggers/plainLogger.ts +50 -100
  84. package/src/loggers/types.ts +6 -0
  85. package/src/loggers/utils.ts +190 -18
  86. package/src/runners/agent/run.ts +113 -0
  87. package/src/runners/agent/utils.ts +98 -0
  88. package/src/runners/generate/run.ts +411 -0
  89. package/src/runners/generate/utils.ts +222 -0
  90. package/src/runners/init/run.ts +212 -0
  91. package/src/{utils/packageManager.ts → runners/init/utils.ts} +12 -2
  92. package/src/runners/mcp/run.ts +37 -0
  93. package/src/runners/validate/run.ts +63 -0
  94. package/dist/agent-B4cAAab2.cjs.map +0 -1
  95. package/dist/agent-CR6Z96og.js +0 -56
  96. package/dist/agent-CR6Z96og.js.map +0 -1
  97. package/dist/agent-Dmxzqg4d.cjs +0 -58
  98. package/dist/agent-Dmxzqg4d.cjs.map +0 -1
  99. package/dist/agent-sdYBBgrd.js.map +0 -1
  100. package/dist/constants-CnDXa1R6.cjs +0 -148
  101. package/dist/constants-CnDXa1R6.cjs.map +0 -1
  102. package/dist/constants-aL3CP_Wq.js +0 -95
  103. package/dist/constants-aL3CP_Wq.js.map +0 -1
  104. package/dist/generate-B1Pa2ho-.cjs.map +0 -1
  105. package/dist/generate-BDGOOsBM.cjs +0 -65
  106. package/dist/generate-BDGOOsBM.cjs.map +0 -1
  107. package/dist/generate-CNrRLY4n.js.map +0 -1
  108. package/dist/generate-DuhxPLGr.js +0 -66
  109. package/dist/generate-DuhxPLGr.js.map +0 -1
  110. package/dist/init-CZ5Xq2Hd.cjs.map +0 -1
  111. package/dist/init-CnZXHrbq.js +0 -25
  112. package/dist/init-CnZXHrbq.js.map +0 -1
  113. package/dist/init-NYJSZJSb.cjs +0 -25
  114. package/dist/init-NYJSZJSb.cjs.map +0 -1
  115. package/dist/init-eNRlotJK.js.map +0 -1
  116. package/dist/mcp-CYOgxB82.cjs +0 -47
  117. package/dist/mcp-CYOgxB82.cjs.map +0 -1
  118. package/dist/mcp-CdFWyrwi.cjs +0 -16
  119. package/dist/mcp-CdFWyrwi.cjs.map +0 -1
  120. package/dist/mcp-DhSxuDMD.js +0 -16
  121. package/dist/mcp-DhSxuDMD.js.map +0 -1
  122. package/dist/mcp-DmJm3TrU.js +0 -46
  123. package/dist/mcp-DmJm3TrU.js.map +0 -1
  124. package/dist/package-BapVyQ-w.cjs.map +0 -1
  125. package/dist/package-DyJE-qNq.js +0 -6
  126. package/dist/package-DyJE-qNq.js.map +0 -1
  127. package/dist/telemetry-DN95_2pF.cjs +0 -282
  128. package/dist/telemetry-DN95_2pF.cjs.map +0 -1
  129. package/dist/telemetry-LgT_sdPe.js +0 -245
  130. package/dist/telemetry-LgT_sdPe.js.map +0 -1
  131. package/dist/validate-C6npXzel.cjs +0 -25
  132. package/dist/validate-C6npXzel.cjs.map +0 -1
  133. package/dist/validate-kLJoT_hi.js +0 -33
  134. package/dist/validate-kLJoT_hi.js.map +0 -1
  135. package/dist/validate-n38Rh-Y7.js +0 -25
  136. package/dist/validate-n38Rh-Y7.js.map +0 -1
  137. package/dist/validate-yKKzqEZ5.cjs +0 -34
  138. package/dist/validate-yKKzqEZ5.cjs.map +0 -1
  139. package/src/loggers/fileSystemLogger.ts +0 -138
  140. package/src/runners/agent.ts +0 -155
  141. package/src/runners/generate.ts +0 -333
  142. package/src/runners/init.ts +0 -296
  143. package/src/runners/mcp.ts +0 -51
  144. package/src/runners/validate.ts +0 -39
  145. package/src/types.ts +0 -11
  146. package/src/utils/Writables.ts +0 -17
  147. package/src/utils/executeHooks.ts +0 -45
  148. package/src/utils/flags.ts +0 -9
  149. package/src/utils/getConfig.ts +0 -10
  150. package/src/utils/getCosmiConfig.ts +0 -80
  151. package/src/utils/getSummary.ts +0 -68
  152. package/src/utils/runHook.ts +0 -91
  153. package/src/utils/telemetry.ts +0 -273
  154. package/src/utils/watcher.ts +0 -19
  155. /package/dist/{chunk-ByKO4r7w.cjs → chunk-Bx3C2hgW.cjs} +0 -0
@@ -1,8 +1,15 @@
1
1
  import { styleText } from 'node:util'
2
- import { formatHrtime, formatMs, formatMsWithColor, toCause } from '@internals/utils'
3
- import { type Config, defineLogger, logLevel as logLevelMap } from '@kubb/core'
4
- import { runHook } from '../utils/runHook.ts'
5
- import { buildProgressLine, formatCommandWithArgs, formatMessage } from './utils.ts'
2
+ import { formatMs, formatMsWithColor, toCause } from '@internals/utils'
3
+ import { type Config, defineLogger, Diagnostics, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
4
+ import {
5
+ buildProgressLine,
6
+ createHookTimer,
7
+ createProgressCounters,
8
+ formatCommandWithArgs,
9
+ formatMessage,
10
+ recordPluginResult,
11
+ resetProgressCounters,
12
+ } from './utils.ts'
6
13
 
7
14
  /**
8
15
  * GitHub Actions logger using group annotations for collapsible sections in CI.
@@ -12,23 +19,17 @@ export const githubActionsLogger = defineLogger({
12
19
  install(context, options) {
13
20
  const logLevel = options?.logLevel ?? logLevelMap.info
14
21
  const state = {
15
- totalPlugins: 0,
16
- completedPlugins: 0,
17
- failedPlugins: 0,
18
- totalFiles: 0,
19
- processedFiles: 0,
20
- hrStart: process.hrtime(),
22
+ ...createProgressCounters(),
21
23
  currentConfigs: [] as Array<Config>,
24
+ openGroupDepth: 0,
22
25
  }
26
+ const hookTimer = createHookTimer()
23
27
 
24
28
  function reset() {
25
- state.totalPlugins = 0
26
- state.completedPlugins = 0
27
- state.failedPlugins = 0
28
- state.totalFiles = 0
29
- state.processedFiles = 0
30
- state.hrStart = process.hrtime()
29
+ closeAllGroups()
30
+ resetProgressCounters(state)
31
31
  state.currentConfigs = []
32
+ hookTimer.clear()
32
33
  }
33
34
 
34
35
  function showProgressStep() {
@@ -48,10 +49,45 @@ export const githubActionsLogger = defineLogger({
48
49
 
49
50
  function openGroup(name: string) {
50
51
  console.log(`::group::${name}`)
52
+ state.openGroupDepth++
51
53
  }
52
54
 
53
55
  function closeGroup(_name: string) {
54
56
  console.log('::endgroup::')
57
+ if (state.openGroupDepth > 0) state.openGroupDepth--
58
+ }
59
+
60
+ function closeAllGroups() {
61
+ while (state.openGroupDepth > 0) {
62
+ console.log('::endgroup::')
63
+ state.openGroupDepth--
64
+ }
65
+ }
66
+
67
+ // Opens a group (only for single-config runs) then logs the step message.
68
+ function onGroupStart<E extends keyof KubbHooks>(event: E, message: string, group: string): void {
69
+ context.on(event, () => {
70
+ if (logLevel <= logLevelMap.silent) {
71
+ return
72
+ }
73
+ if (state.currentConfigs.length === 1) {
74
+ openGroup(group)
75
+ }
76
+ console.log(getMessage(message))
77
+ })
78
+ }
79
+
80
+ // Logs the step message then closes the matching group (single-config runs).
81
+ function onGroupEnd<E extends keyof KubbHooks>(event: E, message: string, group: string): void {
82
+ context.on(event, () => {
83
+ if (logLevel <= logLevelMap.silent) {
84
+ return
85
+ }
86
+ console.log(getMessage(message))
87
+ if (state.currentConfigs.length === 1) {
88
+ closeGroup(group)
89
+ }
90
+ })
55
91
  }
56
92
 
57
93
  context.on('kubb:info', ({ message, info = '' }) => {
@@ -87,14 +123,16 @@ export const githubActionsLogger = defineLogger({
87
123
  context.on('kubb:error', ({ error }) => {
88
124
  const caused = toCause(error)
89
125
 
90
- if (logLevel <= logLevelMap.silent) {
91
- return
92
- }
126
+ // Always release any unclosed groups so a thrown :start without a matching :end
127
+ // (e.g., when getConfigs or kubb.setup throws) doesn't leak an open section.
128
+ closeAllGroups()
129
+
130
+ // Errors are always surfaced, even at silent, so failures stay visible.
93
131
  const message = error.message || String(error)
94
132
  console.error(`::error::${message}`)
95
133
 
96
- // Show stack trace in debug mode (first 3 frames)
97
- if (logLevel >= logLevelMap.debug && error.stack) {
134
+ // Show stack trace in verbose mode (first 3 frames)
135
+ if (logLevel >= logLevelMap.verbose && error.stack) {
98
136
  const frames = error.stack.split('\n').slice(1, 4)
99
137
  for (const frame of frames) {
100
138
  console.log(getMessage(styleText('dim', frame.trim())))
@@ -111,6 +149,35 @@ export const githubActionsLogger = defineLogger({
111
149
  }
112
150
  })
113
151
 
152
+ context.on('kubb:diagnostic', ({ diagnostic }) => {
153
+ closeAllGroups()
154
+
155
+ // Silent still surfaces errors so failures stay visible. It drops warnings and info.
156
+ if (logLevel <= logLevelMap.silent && diagnostic.severity !== 'error') {
157
+ return
158
+ }
159
+
160
+ if (!Diagnostics.isProblem(diagnostic)) {
161
+ console.log(`::notice::${diagnostic.message}`)
162
+ return
163
+ }
164
+
165
+ const parts = [`${diagnostic.code} ${diagnostic.message}`]
166
+ if (diagnostic.location && 'pointer' in diagnostic.location) {
167
+ parts.push(`(at ${diagnostic.location.pointer})`)
168
+ }
169
+ if (diagnostic.plugin) {
170
+ parts.push(`[plugin: ${diagnostic.plugin}]`)
171
+ }
172
+ if (diagnostic.help) {
173
+ parts.push(`help: ${diagnostic.help}`)
174
+ }
175
+ if (diagnostic.code !== Diagnostics.code.unknown) {
176
+ parts.push(`docs: ${Diagnostics.docsUrl(diagnostic.code)}`)
177
+ }
178
+ console.error(`::error::${parts.join(' ')}`)
179
+ })
180
+
114
181
  context.on('kubb:lifecycle:start', ({ version }) => {
115
182
  console.log(styleText('yellow', `Kubb ${version} 🧩`))
116
183
  reset()
@@ -177,11 +244,7 @@ export const githubActionsLogger = defineLogger({
177
244
  return
178
245
  }
179
246
 
180
- if (success) {
181
- state.completedPlugins++
182
- } else {
183
- state.failedPlugins++
184
- }
247
+ recordPluginResult(state, success)
185
248
 
186
249
  const durationStr = formatMsWithColor(duration)
187
250
  const text = getMessage(
@@ -235,12 +298,12 @@ export const githubActionsLogger = defineLogger({
235
298
  showProgressStep()
236
299
  })
237
300
 
238
- context.on('kubb:file:processing:update', () => {
301
+ context.on('kubb:files:processing:update', ({ files }) => {
239
302
  if (logLevel <= logLevelMap.silent) {
240
303
  return
241
304
  }
242
305
 
243
- state.processedFiles++
306
+ state.processedFiles += files.length
244
307
  })
245
308
 
246
309
  context.on('kubb:generation:end', ({ config }) => {
@@ -249,131 +312,66 @@ export const githubActionsLogger = defineLogger({
249
312
  )
250
313
 
251
314
  console.log(text)
252
- })
253
315
 
254
- context.on('kubb:format:start', () => {
255
- if (logLevel <= logLevelMap.silent) {
256
- return
257
- }
258
-
259
- const text = getMessage('Format started')
260
-
261
- if (state.currentConfigs.length === 1) {
262
- openGroup('Formatting')
316
+ if (state.currentConfigs.length > 1) {
317
+ closeGroup(config.name ? `Generation for ${styleText('bold', config.name)}` : 'Generation')
263
318
  }
264
-
265
- console.log(text)
266
319
  })
267
320
 
268
- context.on('kubb:format:end', () => {
321
+ onGroupStart('kubb:format:start', 'Format started', 'Formatting')
322
+ onGroupEnd('kubb:format:end', 'Format completed', 'Formatting')
323
+ onGroupStart('kubb:lint:start', 'Lint started', 'Linting')
324
+ onGroupEnd('kubb:lint:end', 'Lint completed', 'Linting')
325
+ onGroupStart('kubb:hooks:start', 'Hooks started', 'Hooks')
326
+ onGroupEnd('kubb:hooks:end', 'Hooks completed', 'Hooks')
327
+
328
+ context.on('kubb:hook:start', ({ id, command, args }) => {
269
329
  if (logLevel <= logLevelMap.silent) {
270
330
  return
271
331
  }
272
332
 
273
- const text = getMessage('Format completed')
274
-
275
- console.log(text)
276
-
277
- if (state.currentConfigs.length === 1) {
278
- closeGroup('Formatting')
279
- }
280
- })
281
-
282
- context.on('kubb:lint:start', () => {
283
- if (logLevel <= logLevelMap.silent) {
284
- return
333
+ if (id) {
334
+ hookTimer.start(id)
285
335
  }
286
336
 
287
- const text = getMessage('Lint started')
337
+ const commandWithArgs = formatCommandWithArgs(command, args)
338
+ const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} started`)
288
339
 
289
340
  if (state.currentConfigs.length === 1) {
290
- openGroup('Linting')
341
+ openGroup(`Hook ${commandWithArgs}`)
291
342
  }
292
-
293
343
  console.log(text)
294
344
  })
295
345
 
296
- context.on('kubb:lint:end', () => {
346
+ context.on('kubb:hook:end', ({ id, command, args, success, error }) => {
297
347
  if (logLevel <= logLevelMap.silent) {
298
348
  return
299
349
  }
300
350
 
301
- const text = getMessage('Lint completed')
351
+ const ms = id ? hookTimer.end(id) : undefined
352
+ const durationStr = ms !== undefined ? ` in ${formatMsWithColor(ms)}` : ''
302
353
 
303
- console.log(text)
304
-
305
- if (state.currentConfigs.length === 1) {
306
- closeGroup('Linting')
307
- }
308
- })
309
-
310
- context.on('kubb:hook:start', async ({ id, command, args }) => {
311
354
  const commandWithArgs = formatCommandWithArgs(command, args)
312
- const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} started`)
313
-
314
- if (logLevel > logLevelMap.silent) {
315
- if (state.currentConfigs.length === 1) {
316
- openGroup(`Hook ${commandWithArgs}`)
317
- }
318
- console.log(text)
319
- }
320
-
321
- // Skip hook execution if no id is provided (e.g., during benchmarks or tests)
322
- if (!id) {
323
- return
324
- }
325
355
 
326
- await runHook({
327
- id,
328
- command,
329
- args,
330
- commandWithArgs,
331
- context,
332
- sink: {
333
- // GHA formats errors with the ::error:: annotation
334
- onStdout: logLevel > logLevelMap.silent ? (s) => console.log(s) : undefined,
335
- onStderr: logLevel > logLevelMap.silent ? (s) => console.error(`::error::${s}`) : undefined,
336
- },
337
- })
338
- })
339
-
340
- context.on('kubb:hook:end', ({ command, args }) => {
341
- if (logLevel <= logLevelMap.silent) {
342
- return
356
+ if (success) {
357
+ console.log(getMessage(`${styleText('green', '✓')} Hook ${styleText('dim', commandWithArgs)} completed${durationStr}`))
358
+ } else {
359
+ const reason = error?.message ? ` (${error.message})` : ''
360
+ console.log(`::error::Hook ${commandWithArgs} failed${durationStr}${reason}`)
343
361
  }
344
362
 
345
- const commandWithArgs = formatCommandWithArgs(command, args)
346
- const text = getMessage(`Hook ${styleText('dim', commandWithArgs)} completed`)
347
-
348
- console.log(text)
349
-
350
363
  if (state.currentConfigs.length === 1) {
351
364
  closeGroup(`Hook ${commandWithArgs}`)
352
365
  }
353
366
  })
354
367
 
355
- context.on('kubb:generation:summary', ({ config, status, hrStart, failedPlugins }) => {
356
- const pluginsCount = config.plugins?.length ?? 0
357
- const successCount = pluginsCount - failedPlugins.size
358
- const duration = formatHrtime(hrStart)
359
-
360
- if (state.currentConfigs.length > 1) {
361
- console.log(' ')
362
- }
363
-
364
- console.log(
365
- status === 'success'
366
- ? `Kubb Summary: ${styleText('blue', '✓')} ${`${successCount} successful`}, ${pluginsCount} total, ${styleText('green', duration)}`
367
- : `Kubb Summary: ${styleText('blue', '✓')} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total, ${styleText('green', duration)}`,
368
- )
369
-
370
- if (state.currentConfigs.length > 1) {
371
- closeGroup(config.name ? `Generation for ${styleText('bold', config.name)}` : 'Generation')
372
- }
373
- })
374
-
375
368
  context.on('kubb:lifecycle:end', () => {
376
369
  reset()
377
370
  })
371
+
372
+ return (_commandWithArgs: string, _hookId: string) => ({
373
+ onStdout: logLevel > logLevelMap.silent ? (s: string) => console.log(s) : undefined,
374
+ onStderr: logLevel > logLevelMap.silent ? (s: string) => console.error(`::error::${s}`) : undefined,
375
+ })
378
376
  },
379
377
  })
@@ -1,10 +1,7 @@
1
1
  import { relative } from 'node:path'
2
2
  import { formatMs, toCause } from '@internals/utils'
3
- import { defineLogger, logLevel as logLevelMap } from '@kubb/core'
4
- import { SUMMARY_SEPARATOR } from '../constants.ts'
5
- import { getSummary } from '../utils/getSummary.ts'
6
- import { runHook } from '../utils/runHook.ts'
7
- import { formatCommandWithArgs, formatMessage } from './utils.ts'
3
+ import { defineLogger, Diagnostics, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
4
+ import { createHookTimer, formatCommandWithArgs, formatMessage } from './utils.ts'
8
5
 
9
6
  /**
10
7
  * Plain console adapter for non-TTY environments with simple `console.log` output.
@@ -13,11 +10,22 @@ export const plainLogger = defineLogger({
13
10
  name: 'plain',
14
11
  install(context, options) {
15
12
  const logLevel = options?.logLevel ?? logLevelMap.info
13
+ const hookTimer = createHookTimer()
16
14
 
17
15
  function getMessage(message: string): string {
18
16
  return formatMessage(message, logLevel)
19
17
  }
20
18
 
19
+ // Registers a handler that logs a fixed message, skipped at silent level.
20
+ function onStep<E extends keyof KubbHooks>(event: E, message: string): void {
21
+ context.on(event, () => {
22
+ if (logLevel <= logLevelMap.silent) {
23
+ return
24
+ }
25
+ console.log(getMessage(message))
26
+ })
27
+ }
28
+
21
29
  context.on('kubb:info', ({ message, info }) => {
22
30
  if (logLevel <= logLevelMap.silent) {
23
31
  return
@@ -55,8 +63,8 @@ export const plainLogger = defineLogger({
55
63
 
56
64
  console.log(text)
57
65
 
58
- // Show stack trace in debug mode (first 3 frames)
59
- if (logLevel >= logLevelMap.debug && error.stack) {
66
+ // Show stack trace in verbose mode (first 3 frames)
67
+ if (logLevel >= logLevelMap.verbose && error.stack) {
60
68
  const frames = error.stack.split('\n').slice(1, 4)
61
69
  for (const frame of frames) {
62
70
  console.log(getMessage(frame.trim()))
@@ -73,30 +81,21 @@ export const plainLogger = defineLogger({
73
81
  }
74
82
  })
75
83
 
76
- context.on('kubb:lifecycle:start', () => {
77
- console.log('Kubb CLI 🧩')
78
- })
79
-
80
- context.on('kubb:config:start', () => {
81
- if (logLevel <= logLevelMap.silent) {
84
+ context.on('kubb:diagnostic', ({ diagnostic }) => {
85
+ // Silent still surfaces errors so failures stay visible. It drops warnings and info.
86
+ if (logLevel <= logLevelMap.silent && diagnostic.severity !== 'error') {
82
87
  return
83
88
  }
84
-
85
- const text = getMessage('Configuration started')
86
-
87
- console.log(text)
89
+ console.log(getMessage(Diagnostics.formatLines(diagnostic).join('\n')))
88
90
  })
89
91
 
90
- context.on('kubb:config:end', () => {
91
- if (logLevel <= logLevelMap.silent) {
92
- return
93
- }
94
-
95
- const text = getMessage('Configuration completed')
96
-
97
- console.log(text)
92
+ context.on('kubb:lifecycle:start', ({ version }) => {
93
+ console.log(`Kubb CLI v${version}`)
98
94
  })
99
95
 
96
+ onStep('kubb:config:start', 'Configuration started')
97
+ onStep('kubb:config:end', 'Configuration completed')
98
+
100
99
  context.on('kubb:generation:start', () => {
101
100
  const text = getMessage('Generation started')
102
101
 
@@ -133,14 +132,14 @@ export const plainLogger = defineLogger({
133
132
  console.log(text)
134
133
  })
135
134
 
136
- context.on('kubb:file:processing:update', ({ file, config }) => {
135
+ context.on('kubb:files:processing:update', ({ files }) => {
137
136
  if (logLevel <= logLevelMap.silent) {
138
137
  return
139
138
  }
140
139
 
141
- const text = getMessage(`Writing ${relative(config.root, file.path)}`)
142
-
143
- console.log(text)
140
+ for (const { file, config } of files) {
141
+ console.log(getMessage(`Writing ${relative(config.root, file.path)}`))
142
+ }
144
143
  })
145
144
 
146
145
  context.on('kubb:files:processing:end', () => {
@@ -159,96 +158,47 @@ export const plainLogger = defineLogger({
159
158
  console.log(text)
160
159
  })
161
160
 
162
- context.on('kubb:format:start', () => {
163
- if (logLevel <= logLevelMap.silent) {
164
- return
165
- }
166
-
167
- const text = getMessage('Format started')
161
+ onStep('kubb:format:start', 'Format started')
162
+ onStep('kubb:format:end', 'Format completed')
163
+ onStep('kubb:lint:start', 'Lint started')
164
+ onStep('kubb:lint:end', 'Lint completed')
165
+ onStep('kubb:hooks:start', 'Hooks started')
166
+ onStep('kubb:hooks:end', 'Hooks completed')
168
167
 
169
- console.log(text)
170
- })
171
-
172
- context.on('kubb:format:end', () => {
168
+ context.on('kubb:hook:start', ({ id, command, args }) => {
173
169
  if (logLevel <= logLevelMap.silent) {
174
170
  return
175
171
  }
176
172
 
177
- const text = getMessage('Format completed')
178
-
179
- console.log(text)
180
- })
181
-
182
- context.on('kubb:lint:start', () => {
183
- if (logLevel <= logLevelMap.silent) {
184
- return
173
+ if (id) {
174
+ hookTimer.start(id)
185
175
  }
186
176
 
187
- const text = getMessage('Lint started')
188
-
189
- console.log(text)
177
+ const commandWithArgs = formatCommandWithArgs(command, args)
178
+ console.log(getMessage(`Hook ${commandWithArgs} started`))
190
179
  })
191
180
 
192
- context.on('kubb:lint:end', () => {
181
+ context.on('kubb:hook:end', ({ id, command, args, success, error }) => {
193
182
  if (logLevel <= logLevelMap.silent) {
194
183
  return
195
184
  }
196
185
 
197
- const text = getMessage('Lint completed')
198
-
199
- console.log(text)
200
- })
186
+ const ms = id ? hookTimer.end(id) : undefined
187
+ const durationStr = ms !== undefined ? ` in ${formatMs(ms)}` : ''
201
188
 
202
- context.on('kubb:hook:start', async ({ id, command, args }) => {
203
189
  const commandWithArgs = formatCommandWithArgs(command, args)
204
- const text = getMessage(`Hook ${commandWithArgs} started`)
205
190
 
206
- if (logLevel > logLevelMap.silent) {
207
- console.log(text)
208
- }
209
-
210
- // Skip hook execution if no id is provided (e.g., during benchmarks or tests)
211
- if (!id) {
212
- return
191
+ if (success) {
192
+ console.log(getMessage(`✓ Hook ${commandWithArgs} completed${durationStr}`))
193
+ } else {
194
+ const reason = error?.message ? ` (${error.message})` : ''
195
+ console.log(getMessage(`✗ Hook ${commandWithArgs} failed${durationStr}${reason}`))
213
196
  }
214
-
215
- await runHook({
216
- id,
217
- command,
218
- args,
219
- commandWithArgs,
220
- context,
221
- sink: {
222
- onStdout: logLevel > logLevelMap.silent ? (s) => console.log(s) : undefined,
223
- onStderr: logLevel > logLevelMap.silent ? (s) => console.error(s) : undefined,
224
- },
225
- })
226
197
  })
227
198
 
228
- context.on('kubb:hook:end', ({ command, args }) => {
229
- if (logLevel <= logLevelMap.silent) {
230
- return
231
- }
232
-
233
- const commandWithArgs = formatCommandWithArgs(command, args)
234
- const text = getMessage(`Hook ${commandWithArgs} completed`)
235
-
236
- console.log(text)
237
- })
238
-
239
- context.on('kubb:generation:summary', ({ config, pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
240
- const summary = getSummary({
241
- failedPlugins,
242
- filesCreated,
243
- config,
244
- status,
245
- hrStart,
246
- pluginTimings: logLevel >= logLevelMap.verbose ? pluginTimings : undefined,
247
- })
248
-
249
- console.log(SUMMARY_SEPARATOR)
250
- console.log(summary.join('\n'))
251
- console.log(SUMMARY_SEPARATOR)
199
+ return (_commandWithArgs: string, _hookId: string) => ({
200
+ onStdout: logLevel > logLevelMap.silent ? (s: string) => console.log(s) : undefined,
201
+ onStderr: logLevel > logLevelMap.silent ? (s: string) => console.error(s) : undefined,
252
202
  })
253
203
  },
254
204
  })
@@ -1 +1,7 @@
1
+ /**
2
+ * Logger adapter selected by `setupReporters` 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'