@kubb/cli 5.5.6 → 5.6.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 (146) hide show
  1. package/dist/{Telemetry-CMXOVUKB.js → Telemetry-RBcAjNxj.js} +18 -43
  2. package/dist/Telemetry-RBcAjNxj.js.map +1 -0
  3. package/dist/{Telemetry-DDHXBdEz.cjs → Telemetry-bGdFBaGt.cjs} +27 -89
  4. package/dist/Telemetry-bGdFBaGt.cjs.map +1 -0
  5. package/dist/agent-BPIqnEl2.js +59 -0
  6. package/dist/agent-BPIqnEl2.js.map +1 -0
  7. package/dist/agent-DElUuYuy.cjs +120 -0
  8. package/dist/agent-DElUuYuy.cjs.map +1 -0
  9. package/dist/{background-DxlRE9O5.js → background-0PMj56FJ.js} +6 -5
  10. package/dist/background-0PMj56FJ.js.map +1 -0
  11. package/dist/background-BqS01QDb.js +2 -0
  12. package/dist/{background-Bbcc2TdN.cjs → background-R0T_7Szu.cjs} +8 -7
  13. package/dist/background-R0T_7Szu.cjs.map +1 -0
  14. package/dist/commands-BAgGrcvc.js +65 -0
  15. package/dist/commands-BAgGrcvc.js.map +1 -0
  16. package/dist/commands-Si-RFAS6.cjs +71 -0
  17. package/dist/commands-Si-RFAS6.cjs.map +1 -0
  18. package/dist/config-8Xl4yZmw.js +146 -0
  19. package/dist/config-8Xl4yZmw.js.map +1 -0
  20. package/dist/config-ByfJSj3q.cjs +164 -0
  21. package/dist/config-ByfJSj3q.cjs.map +1 -0
  22. package/dist/constants-CdxpgX3_.cjs.map +1 -1
  23. package/dist/constants-DHRspBTo.js.map +1 -1
  24. package/dist/{errors-C-wEou02.cjs → errors-CMbMAwyW.cjs} +2 -2
  25. package/dist/{errors-C-wEou02.cjs.map → errors-CMbMAwyW.cjs.map} +1 -1
  26. package/dist/index.cjs +431 -22
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.js +429 -20
  29. package/dist/index.js.map +1 -1
  30. package/dist/output-B6Ondw0g.js +776 -0
  31. package/dist/output-B6Ondw0g.js.map +1 -0
  32. package/dist/output-i3s5c4Xu.cjs +878 -0
  33. package/dist/output-i3s5c4Xu.cjs.map +1 -0
  34. package/dist/run-3I2NPeXG.cjs +31 -0
  35. package/dist/run-3I2NPeXG.cjs.map +1 -0
  36. package/dist/{run-C-jBKNbI.cjs → run-BkLJ5mXn.cjs} +22 -43
  37. package/dist/run-BkLJ5mXn.cjs.map +1 -0
  38. package/dist/run-CZlkqkDc.js +30 -0
  39. package/dist/run-CZlkqkDc.js.map +1 -0
  40. package/dist/run-CmNDNEjR.js +346 -0
  41. package/dist/run-CmNDNEjR.js.map +1 -0
  42. package/dist/{run-BdTwxLCW.js → run-D5AeacqK.js} +9 -23
  43. package/dist/run-D5AeacqK.js.map +1 -0
  44. package/dist/{run-y6LRyWdS.cjs → run-D8Wz_17X.cjs} +41 -60
  45. package/dist/run-D8Wz_17X.cjs.map +1 -0
  46. package/dist/{run-Dn8HVjnM.js → run-DQoKTiGk.js} +23 -44
  47. package/dist/run-DQoKTiGk.js.map +1 -0
  48. package/dist/{run-BDaZPU-1.js → run-Dgph0WYk.js} +25 -49
  49. package/dist/run-Dgph0WYk.js.map +1 -0
  50. package/dist/run-t8nm7zcT.cjs +348 -0
  51. package/dist/run-t8nm7zcT.cjs.map +1 -0
  52. package/dist/{run-CZz_GbE4.cjs → run-yvuot2N9.cjs} +12 -26
  53. package/dist/run-yvuot2N9.cjs.map +1 -0
  54. package/dist/{snapshot-B5mc4gpC.js → snapshot-CkHXR0Nl.js} +5 -5
  55. package/dist/snapshot-CkHXR0Nl.js.map +1 -0
  56. package/dist/{snapshot-DnCxZfmM.cjs → snapshot-D4nKbwkw.cjs} +9 -9
  57. package/dist/snapshot-D4nKbwkw.cjs.map +1 -0
  58. package/dist/studioWorker.js +2 -2
  59. package/package.json +7 -7
  60. package/dist/Telemetry-CMXOVUKB.js.map +0 -1
  61. package/dist/Telemetry-DDHXBdEz.cjs.map +0 -1
  62. package/dist/agent-DiB4CRre.cjs +0 -38
  63. package/dist/agent-DiB4CRre.cjs.map +0 -1
  64. package/dist/agent-yA5vrXJB.js +0 -26
  65. package/dist/agent-yA5vrXJB.js.map +0 -1
  66. package/dist/background-Bbcc2TdN.cjs.map +0 -1
  67. package/dist/background-CFNncNYT.js +0 -2
  68. package/dist/background-DxlRE9O5.js.map +0 -1
  69. package/dist/connect-C9tTngda.js +0 -11
  70. package/dist/connect-C9tTngda.js.map +0 -1
  71. package/dist/connect-CJ7BhOcs.cjs +0 -11
  72. package/dist/connect-CJ7BhOcs.cjs.map +0 -1
  73. package/dist/generate-BUqZ_7GB.cjs +0 -92
  74. package/dist/generate-BUqZ_7GB.cjs.map +0 -1
  75. package/dist/generate-q2m01zRd.js +0 -92
  76. package/dist/generate-q2m01zRd.js.map +0 -1
  77. package/dist/gunshiDryRun-DdKJuVn1.js +0 -2
  78. package/dist/init-Ckpwkfvz.cjs +0 -58
  79. package/dist/init-Ckpwkfvz.cjs.map +0 -1
  80. package/dist/init-DukE9Uw4.js +0 -58
  81. package/dist/init-DukE9Uw4.js.map +0 -1
  82. package/dist/login-Bc19oiFE.cjs +0 -11
  83. package/dist/login-Bc19oiFE.cjs.map +0 -1
  84. package/dist/login-Do3nns0B.js +0 -11
  85. package/dist/login-Do3nns0B.js.map +0 -1
  86. package/dist/logout-BvHFvCeI.cjs +0 -16
  87. package/dist/logout-BvHFvCeI.cjs.map +0 -1
  88. package/dist/logout-COxoIMum.js +0 -16
  89. package/dist/logout-COxoIMum.js.map +0 -1
  90. package/dist/mcp-B-GxGgVr.js +0 -19
  91. package/dist/mcp-B-GxGgVr.js.map +0 -1
  92. package/dist/mcp-B3B-rE7W.cjs +0 -18
  93. package/dist/mcp-B3B-rE7W.cjs.map +0 -1
  94. package/dist/output-CVLosNZq.cjs +0 -411
  95. package/dist/output-CVLosNZq.cjs.map +0 -1
  96. package/dist/output-FDo-db-w.js +0 -321
  97. package/dist/output-FDo-db-w.js.map +0 -1
  98. package/dist/package-Ci2fcoOV.js +0 -6
  99. package/dist/package-Ci2fcoOV.js.map +0 -1
  100. package/dist/package-Do9rJ7D3.cjs +0 -11
  101. package/dist/package-Do9rJ7D3.cjs.map +0 -1
  102. package/dist/rolldown-runtime-qbf5tadS.cjs +0 -38
  103. package/dist/run-BDaZPU-1.js.map +0 -1
  104. package/dist/run-BdTwxLCW.js.map +0 -1
  105. package/dist/run-C-jBKNbI.cjs.map +0 -1
  106. package/dist/run-CAcQlhub.js +0 -295
  107. package/dist/run-CAcQlhub.js.map +0 -1
  108. package/dist/run-CSoFhDyK.cjs +0 -297
  109. package/dist/run-CSoFhDyK.cjs.map +0 -1
  110. package/dist/run-CZz_GbE4.cjs.map +0 -1
  111. package/dist/run-CaEbo-te.js +0 -40
  112. package/dist/run-CaEbo-te.js.map +0 -1
  113. package/dist/run-CihzLZmR.cjs +0 -41
  114. package/dist/run-CihzLZmR.cjs.map +0 -1
  115. package/dist/run-Dn8HVjnM.js.map +0 -1
  116. package/dist/run-y6LRyWdS.cjs.map +0 -1
  117. package/dist/shared-Cl-OLpNh.cjs +0 -81
  118. package/dist/shared-Cl-OLpNh.cjs.map +0 -1
  119. package/dist/shared-DaHA7QFQ.js +0 -58
  120. package/dist/shared-DaHA7QFQ.js.map +0 -1
  121. package/dist/snapshot-B5mc4gpC.js.map +0 -1
  122. package/dist/snapshot-DnCxZfmM.cjs.map +0 -1
  123. package/dist/start-B-GXO8tS.cjs +0 -12
  124. package/dist/start-B-GXO8tS.cjs.map +0 -1
  125. package/dist/start-Dbfx_8zG.js +0 -12
  126. package/dist/start-Dbfx_8zG.js.map +0 -1
  127. package/dist/status-DDajNc8w.js +0 -17
  128. package/dist/status-DDajNc8w.js.map +0 -1
  129. package/dist/status-DusS7DfO.cjs +0 -17
  130. package/dist/status-DusS7DfO.cjs.map +0 -1
  131. package/dist/stop-C5t7Yx0t.js +0 -11
  132. package/dist/stop-C5t7Yx0t.js.map +0 -1
  133. package/dist/stop-zmM3A0Re.cjs +0 -11
  134. package/dist/stop-zmM3A0Re.cjs.map +0 -1
  135. package/dist/studio--IOOl_VB.js +0 -174
  136. package/dist/studio--IOOl_VB.js.map +0 -1
  137. package/dist/studio-CJ2XhtRd.cjs +0 -174
  138. package/dist/studio-CJ2XhtRd.cjs.map +0 -1
  139. package/dist/utils-C3HZOWL_.js +0 -1107
  140. package/dist/utils-C3HZOWL_.js.map +0 -1
  141. package/dist/utils-ClRbJfxu.cjs +0 -1210
  142. package/dist/utils-ClRbJfxu.cjs.map +0 -1
  143. package/dist/validate-BcB0tFQ6.cjs +0 -19
  144. package/dist/validate-BcB0tFQ6.cjs.map +0 -1
  145. package/dist/validate-QpkCbIFJ.js +0 -20
  146. package/dist/validate-QpkCbIFJ.js.map +0 -1
@@ -0,0 +1,776 @@
1
+ import "./rolldown-runtime-CRm0XQPb.js";
2
+ import { i as isCIEnvironment, n as formatMs, r as getElapsedMs, t as getAgentName } from "./agent-BPIqnEl2.js";
3
+ import { styleText } from "node:util";
4
+ import process$1 from "node:process";
5
+ import { relative } from "node:path";
6
+ import * as clack from "@clack/prompts";
7
+ import { Diagnostics, logLevel } from "@kubb/core";
8
+ //#region src/loggers/banner.ts
9
+ /**
10
+ * Parses a CSS hex color string (`#RGB`) into its RGB channels.
11
+ * Falls back to `255` for any channel that cannot be parsed.
12
+ */
13
+ function parseHex(color) {
14
+ const int = Number.parseInt(color.replace("#", ""), 16);
15
+ return Number.isNaN(int) ? {
16
+ r: 255,
17
+ g: 255,
18
+ b: 255
19
+ } : {
20
+ r: int >> 16 & 255,
21
+ g: int >> 8 & 255,
22
+ b: int & 255
23
+ };
24
+ }
25
+ /**
26
+ * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence
27
+ * for the given hex color.
28
+ */
29
+ function hex(color) {
30
+ const { r, g, b } = parseHex(color);
31
+ return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
32
+ }
33
+ function gradient(colorStops, text) {
34
+ const chars = text.split("");
35
+ return chars.map((char, i) => {
36
+ const t = chars.length <= 1 ? 0 : i / (chars.length - 1);
37
+ const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2);
38
+ const lt = t * (colorStops.length - 1) - seg;
39
+ const from = parseHex(colorStops[seg]);
40
+ const to = parseHex(colorStops[seg + 1]);
41
+ return `\x1b[38;2;${Math.round(from.r + (to.r - from.r) * lt)};${Math.round(from.g + (to.g - from.g) * lt)};${Math.round(from.b + (to.b - from.b) * lt)}m${char}\x1b[0m`;
42
+ }).join("");
43
+ }
44
+ /**
45
+ * ANSI color functions for each part of the Kubb mascot illustration.
46
+ */
47
+ const palette = {
48
+ /**
49
+ * Top cap of the skittle.
50
+ */
51
+ lid: hex("#F55A17"),
52
+ /**
53
+ * Upper wood body.
54
+ */
55
+ woodTop: hex("#F5A217"),
56
+ /**
57
+ * Middle wood body.
58
+ */
59
+ woodMid: hex("#F58517"),
60
+ /**
61
+ * Base wood body.
62
+ */
63
+ woodBase: hex("#B45309"),
64
+ /**
65
+ * Eye whites.
66
+ */
67
+ eye: hex("#FFFFFF"),
68
+ /**
69
+ * Highlight accent.
70
+ */
71
+ highlight: hex("#adadc6"),
72
+ /**
73
+ * Cheek blush.
74
+ */
75
+ blush: hex("#FDA4AF")
76
+ };
77
+ /**
78
+ * Generates the Kubb mascot welcome banner as an ANSI-colored string.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * console.log(getIntro({ title: 'kubb.config.ts', description: 'generating…', version: '5.0.0', areEyesOpen: true }))
83
+ * ```
84
+ */
85
+ function getIntro({ title, description, version, areEyesOpen }) {
86
+ const kubbVersion = gradient([
87
+ "#F58517",
88
+ "#F5A217",
89
+ "#F55A17"
90
+ ], `KUBB v${version}`);
91
+ const eyeTop = areEyesOpen ? palette.eye("█▀█") : palette.eye("───");
92
+ const eyeBottom = areEyesOpen ? palette.eye("▀▀▀") : palette.eye("───");
93
+ return [
94
+ ` ${palette.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")}`,
95
+ ` ${palette.woodTop("█ ")}${palette.highlight("▄▄")}${palette.woodTop(" ")}${palette.highlight("▄▄")}${palette.woodTop(" █")} ${kubbVersion}`,
96
+ ` ${palette.woodMid("█ ")}${eyeTop}${palette.woodMid(" ")}${eyeTop}${palette.woodMid(" █")} ${styleText("gray", title)}`,
97
+ ` ${palette.woodMid("█ ")}${eyeBottom}${palette.woodMid(" ")}${palette.blush("◡")}${palette.woodMid(" ")}${eyeBottom}${palette.woodMid(" █")} ${styleText("yellow", "➜")} ${styleText("white", description)}`,
98
+ ` ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")}`
99
+ ].join("\n");
100
+ }
101
+ /**
102
+ * Formats a millisecond duration with a threshold-based ANSI color.
103
+ * `≤ 500 ms` → green · `≤ 1 000 ms` → yellow · `> 1 000 ms` → red.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * formatMsWithColor(200) // '\x1b[32m200ms\x1b[39m'
108
+ * formatMsWithColor(800) // '\x1b[33m800ms\x1b[39m'
109
+ * formatMsWithColor(1500) // '\x1b[31m1.50s\x1b[39m'
110
+ * ```
111
+ */
112
+ function formatMsWithColor(ms) {
113
+ const formatted = formatMs(ms);
114
+ if (ms <= 500) return styleText("green", formatted);
115
+ if (ms <= 1e3) return styleText("yellow", formatted);
116
+ return styleText("red", formatted);
117
+ }
118
+ //#endregion
119
+ //#region src/loggers/createLogger.ts
120
+ /** Display path for a config's input: the string form, or its `path` field when the input is an object. */
121
+ function getInputPath(config) {
122
+ const { input } = config;
123
+ if (typeof input === "string") return input;
124
+ return typeof input?.path === "string" ? input.path : void 0;
125
+ }
126
+ /** Counts a noun, so a message never reads `1 files`. */
127
+ function pluralize(count, noun) {
128
+ return `${count} ${count === 1 ? noun : `${noun}s`}`;
129
+ }
130
+ /** Prefixes a `[HH:MM:SS]` timestamp at verbose and above. */
131
+ function formatMessage(message, logLevel$1) {
132
+ if (logLevel$1 >= logLevel.verbose) {
133
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
134
+ hour12: false,
135
+ hour: "2-digit",
136
+ minute: "2-digit",
137
+ second: "2-digit"
138
+ });
139
+ return `${styleText("dim", `[${timestamp}]`)} ${message}`;
140
+ }
141
+ return message;
142
+ }
143
+ /** Renders a `studio:connected` event's versions: the runtime only when it differs from the host, Studio's only when it sent one. */
144
+ function formatVersions({ studio, kubb, agent }) {
145
+ return [
146
+ `v${agent}`,
147
+ kubb !== agent ? `runtime v${kubb}` : void 0,
148
+ studio ? `Studio v${studio}` : void 0
149
+ ].filter(Boolean).join(", ");
150
+ }
151
+ /** The first three frames of a stack, without the message line. */
152
+ function topFrames(stack) {
153
+ return stack.split("\n").slice(1, 4).map((frame) => frame.trim());
154
+ }
155
+ /** First stack frames for verbose error output, including an optional `cause` chain. */
156
+ function formatErrorFrames(error) {
157
+ if (!error.stack) return null;
158
+ const frames = topFrames(error.stack);
159
+ const caused = error.cause instanceof Error ? error.cause : void 0;
160
+ if (!caused?.stack) return { frames };
161
+ return {
162
+ frames,
163
+ cause: {
164
+ header: `└─ caused by ${caused.message}`,
165
+ frames: topFrames(caused.stack)
166
+ }
167
+ };
168
+ }
169
+ /** The progress summary line the clack logger shows, `null` when there is nothing to display. */
170
+ function buildProgressLine(state) {
171
+ const parts = [];
172
+ const duration = formatMs(getElapsedMs(state.hrStart));
173
+ if (state.totalPlugins > 0) {
174
+ const pluginStr = state.failedPlugins > 0 ? `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins} ${styleText("red", `(${state.failedPlugins} failed)`)}` : `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins}`;
175
+ parts.push(pluginStr);
176
+ }
177
+ if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`);
178
+ if (parts.length === 0) return null;
179
+ parts.push(`${styleText("green", duration)} elapsed`);
180
+ return parts.join(styleText("dim", " | "));
181
+ }
182
+ function createProgressCounters() {
183
+ return {
184
+ totalPlugins: 0,
185
+ completedPlugins: 0,
186
+ failedPlugins: 0,
187
+ totalFiles: 0,
188
+ processedFiles: 0,
189
+ hrStart: process$1.hrtime()
190
+ };
191
+ }
192
+ /**
193
+ * The three output phases, in the order the generate runner runs them.
194
+ */
195
+ const PHASES = {
196
+ format: {
197
+ running: "Formatting",
198
+ success: "Formatted",
199
+ failure: "Formatting failed"
200
+ },
201
+ lint: {
202
+ running: "Linting",
203
+ success: "Linted",
204
+ failure: "Linting failed"
205
+ },
206
+ hooks: {
207
+ running: "Running post-generate hooks",
208
+ success: "Post-generate hooks completed",
209
+ failure: "Post-generate hooks failed",
210
+ showHookResults: true
211
+ }
212
+ };
213
+ /**
214
+ * Drops the blank lines a subprocess leaves at either end of its output, so its block does not open
215
+ * or close on an empty row.
216
+ */
217
+ function trimBlankEdges(lines) {
218
+ const start = lines.findIndex((line) => line.trim());
219
+ if (start === -1) return [];
220
+ return lines.slice(start, lines.findLastIndex((line) => line.trim()) + 1);
221
+ }
222
+ /**
223
+ * Wires a {@link LoggerWriter} onto the run's hooks. This owns what a run says and in what order:
224
+ * one group per config, a step over the plugin work, a progress bar for the writes, one step per
225
+ * output phase, then the summary and the group's closing result. The writer only decides how each
226
+ * line looks, so every logger reports the same run the same way.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * export const plainLogger = createLogger(writer)
231
+ * ```
232
+ */
233
+ function createLogger(writer) {
234
+ return function install(context, { logLevel: logLevel$2 }) {
235
+ const silent = logLevel$2 <= logLevel.silent;
236
+ const state = {
237
+ ...createProgressCounters(),
238
+ spinner: null,
239
+ progress: null,
240
+ hooks: /* @__PURE__ */ new Map(),
241
+ /**
242
+ * Plugin results held back while the generation step owns the line.
243
+ */
244
+ pluginLines: [],
245
+ phase: null,
246
+ groupOpen: false
247
+ };
248
+ function text(message) {
249
+ return formatMessage(message, logLevel$2);
250
+ }
251
+ function startSpinner(message) {
252
+ if (silent) return;
253
+ state.spinner = writer.spinner();
254
+ state.spinner.start(text(message));
255
+ }
256
+ function stopSpinner(message, status = "success") {
257
+ const spinner = state.spinner;
258
+ if (!spinner) return;
259
+ state.spinner = null;
260
+ if (message === void 0) {
261
+ spinner.clear();
262
+ return;
263
+ }
264
+ if (status === "failed") {
265
+ spinner.error(text(message));
266
+ return;
267
+ }
268
+ spinner.stop(text(message));
269
+ }
270
+ function stopProgress(message) {
271
+ const progress = state.progress;
272
+ if (!progress) return;
273
+ state.progress = null;
274
+ progress.stop(message === void 0 ? "" : text(message));
275
+ }
276
+ function startPhase({ running, success, failure, showHookResults = false }) {
277
+ state.phase = {
278
+ successLabel: success,
279
+ failureLabel: failure,
280
+ showHookResults,
281
+ failed: false,
282
+ hrStart: process$1.hrtime(),
283
+ lines: [],
284
+ output: []
285
+ };
286
+ startSpinner(running);
287
+ }
288
+ function endPhase() {
289
+ const phase = state.phase;
290
+ state.phase = null;
291
+ if (!phase || silent) return;
292
+ const duration = formatMsWithColor(getElapsedMs(phase.hrStart));
293
+ stopSpinner(phase.failed ? `${phase.failureLabel} after ${duration}` : `${phase.successLabel} in ${duration}`, phase.failed ? "failed" : "success");
294
+ if (phase.lines.length) writer.block(phase.lines);
295
+ writeOutput(phase.output);
296
+ }
297
+ function writeOutput(lines) {
298
+ const output = trimBlankEdges(lines);
299
+ if (output.length) writer.raw(output);
300
+ }
301
+ function closeGroup(status) {
302
+ if (!state.groupOpen) return;
303
+ state.groupOpen = false;
304
+ stopSpinner();
305
+ stopProgress();
306
+ writer.groupEnd(status === "failed" ? styleText("red", "✗ Generation failed") : styleText("green", "✓ Generation succeeded"));
307
+ }
308
+ function reset() {
309
+ stopSpinner();
310
+ stopProgress();
311
+ Object.assign(state, createProgressCounters());
312
+ state.hooks.clear();
313
+ state.pluginLines = [];
314
+ state.phase = null;
315
+ state.groupOpen = false;
316
+ }
317
+ function formatLine(symbol, message, info) {
318
+ return text([
319
+ symbol,
320
+ message,
321
+ info && styleText("dim", info)
322
+ ].filter(Boolean).join(" "));
323
+ }
324
+ context.hook("kubb:warn", ({ message, info }) => {
325
+ if (logLevel$2 < logLevel.warn) return;
326
+ writer.warn(formatLine(styleText("yellow", "⚠"), message, logLevel$2 >= logLevel.info ? info : void 0));
327
+ });
328
+ context.hook("kubb:error", ({ error }) => {
329
+ if (state.phase) state.phase.failed = true;
330
+ if (state.spinner) stopSpinner(error.message, "failed");
331
+ else writer.error(text(error.message));
332
+ const frames = logLevel$2 >= logLevel.verbose ? formatErrorFrames(error) : null;
333
+ if (!frames) return;
334
+ writer.block(frames.frames.map((frame) => text(styleText("dim", frame))));
335
+ if (frames.cause) writer.block([styleText("dim", frames.cause.header), ...frames.cause.frames.map((frame) => text(` ${styleText("dim", frame)}`))]);
336
+ });
337
+ context.hook("kubb:diagnostic", ({ diagnostic }) => {
338
+ if (silent && diagnostic.severity !== "error") return;
339
+ stopSpinner();
340
+ stopProgress();
341
+ if (Diagnostics.isUpdate(diagnostic)) {
342
+ writer.update([`\`v${diagnostic.currentVersion}\` → \`v${diagnostic.latestVersion}\``, "Run `npm install -g @kubb/cli` to update"], "Update available for `Kubb`");
343
+ return;
344
+ }
345
+ const { headline, details } = Diagnostics.format(diagnostic);
346
+ writer.diagnostic([headline, ...details]);
347
+ });
348
+ context.hook("studio:connecting", ({ url }) => {
349
+ startSpinner(`Connecting to ${styleText("cyan", url)}`);
350
+ });
351
+ context.hook("studio:disconnected", ({ reason }) => {
352
+ if (logLevel$2 < logLevel.warn) return;
353
+ stopSpinner();
354
+ writer.warn(text(`⚠ Kubb Studio ended the session (${reason})`));
355
+ });
356
+ context.hook("studio:warn", ({ message, permission }) => {
357
+ if (logLevel$2 < logLevel.warn) return;
358
+ const remedy = permission ? `; pass --${permission.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)} to allow it` : "";
359
+ writer.warn(text(`⚠ ${message}${remedy}`));
360
+ });
361
+ context.hook("studio:error", ({ error }) => {
362
+ if (state.spinner) {
363
+ stopSpinner(error.message, "failed");
364
+ return;
365
+ }
366
+ writer.error(text(error.message));
367
+ });
368
+ context.hook("kubb:lifecycle:start", () => {
369
+ reset();
370
+ });
371
+ context.hook("kubb:generation:start", ({ config }) => {
372
+ closeGroup("failed");
373
+ reset();
374
+ state.totalPlugins = config.plugins?.length ?? 0;
375
+ if (silent) return;
376
+ const inputPath = getInputPath(config);
377
+ writer.group(text([styleText("bold", config.name ?? "kubb"), inputPath ? styleText("dim", inputPath) : void 0].filter(Boolean).join(" ")));
378
+ state.groupOpen = true;
379
+ startSpinner("Generating");
380
+ });
381
+ context.hook("kubb:format:start", () => startPhase(PHASES.format));
382
+ context.hook("kubb:format:end", endPhase);
383
+ context.hook("kubb:lint:start", () => startPhase(PHASES.lint));
384
+ context.hook("kubb:lint:end", endPhase);
385
+ context.hook("kubb:hooks:start", () => startPhase(PHASES.hooks));
386
+ context.hook("kubb:hooks:end", endPhase);
387
+ context.hook("kubb:hook:end", (ctx) => {
388
+ const { id, command, name, args, success, error } = ctx;
389
+ if (!id) return;
390
+ if (!success && state.phase) state.phase.failed = true;
391
+ if (silent) {
392
+ if (!ctx.success) {
393
+ if (ctx.stdout) console.log(ctx.stdout);
394
+ if (ctx.stderr) console.error(ctx.stderr);
395
+ }
396
+ return;
397
+ }
398
+ const active = state.hooks.get(id);
399
+ if (!active) return;
400
+ state.hooks.delete(id);
401
+ const label = styleText("dim", name ?? (args?.length ? `${command} ${args.join(" ")}` : command));
402
+ const reason = error?.message ? ` (${error.message})` : "";
403
+ const result = success ? `${styleText("green", "✓")} ${label} in ${formatMsWithColor(getElapsedMs(active.hrStart))}` : `${styleText("red", "✗")} ${label} failed${reason}`;
404
+ const phase = state.phase;
405
+ if (phase) {
406
+ if (phase.showHookResults || !success) phase.lines.push(result);
407
+ phase.output.push(...active.lines);
408
+ return;
409
+ }
410
+ stopSpinner();
411
+ writer.step(text(result));
412
+ writeOutput(active.lines);
413
+ });
414
+ context.hook("kubb:generation:end", () => {
415
+ stopSpinner();
416
+ stopProgress();
417
+ });
418
+ context.hook("kubb:lifecycle:end", () => {
419
+ closeGroup("failed");
420
+ reset();
421
+ });
422
+ if (!silent) {
423
+ context.hook("kubb:info", ({ message, info }) => {
424
+ const line = formatLine(styleText("blue", "ℹ"), message, info);
425
+ if (state.phase) {
426
+ state.phase.lines.push(line);
427
+ return;
428
+ }
429
+ if (state.spinner) {
430
+ state.spinner.message(line);
431
+ return;
432
+ }
433
+ writer.info(line);
434
+ });
435
+ context.hook("kubb:success", ({ message, info }) => {
436
+ const line = formatLine(styleText("green", "✓"), message, logLevel$2 >= logLevel.info ? info : void 0);
437
+ if (state.spinner) {
438
+ state.spinner.message(line);
439
+ return;
440
+ }
441
+ writer.success(line);
442
+ });
443
+ context.hook("studio:connected", ({ url, versions }) => {
444
+ const line = `Connected to ${styleText("cyan", url)} ${styleText("dim", `(${formatVersions(versions)})`)}`;
445
+ if (state.spinner) {
446
+ stopSpinner(line);
447
+ return;
448
+ }
449
+ writer.success(text(`✓ ${line}`));
450
+ });
451
+ context.hook("studio:ready", () => {
452
+ startSpinner("✓ Ready to receive jobs");
453
+ });
454
+ context.hook("studio:command:start", ({ command }) => {
455
+ stopSpinner();
456
+ writer.info(text(`Kubb Studio asked to ${styleText("bold", command)}`));
457
+ });
458
+ context.hook("studio:command:end", ({ command, info }) => {
459
+ writer.success(text(`✓ Finished ${command}${info ? ` ${styleText("dim", `(${info})`)}` : ""}`));
460
+ startSpinner("✓ Ready to receive jobs");
461
+ });
462
+ context.hook("studio:reconnecting", ({ delayMs }) => {
463
+ stopSpinner();
464
+ writer.info(text(styleText("dim", `Retrying connection to Kubb Studio in ${formatMs(delayMs)}`)));
465
+ });
466
+ context.hook("kubb:plugin:start", ({ plugin }) => {
467
+ state.spinner?.message(text(`Generating ${styleText("dim", plugin.name)}`));
468
+ });
469
+ context.hook("kubb:plugin:end", ({ plugin, duration, success }) => {
470
+ if (success) state.completedPlugins++;
471
+ if (!success) state.failedPlugins++;
472
+ state.pluginLines.push(text(`${plugin.name} ${success ? "completed" : "failed"} in ${formatMsWithColor(duration)}`));
473
+ });
474
+ context.hook("kubb:plugins:end", () => {
475
+ const failed = state.failedPlugins > 0;
476
+ stopSpinner(buildProgressLine(state) ?? "No plugins ran", failed ? "failed" : "success");
477
+ if (state.pluginLines.length) {
478
+ writer.block(state.pluginLines);
479
+ state.pluginLines = [];
480
+ }
481
+ });
482
+ context.hook("kubb:files:processing:start", ({ files }) => {
483
+ stopSpinner();
484
+ state.totalFiles = files.length;
485
+ state.processedFiles = 0;
486
+ state.progress = writer.progress(files.length);
487
+ state.progress.start(text(`Writing ${pluralize(files.length, "file")}`));
488
+ });
489
+ context.hook("kubb:files:processing:update", ({ files }) => {
490
+ for (const { file, config } of files) {
491
+ state.processedFiles++;
492
+ state.progress?.advance(`Writing ${relative(config.root, file.path)}`);
493
+ }
494
+ });
495
+ context.hook("kubb:files:processing:end", () => {
496
+ stopProgress(`Wrote ${pluralize(state.processedFiles, "file")}`);
497
+ });
498
+ context.hook("kubb:hook:start", ({ id }) => {
499
+ if (!id) return;
500
+ state.hooks.set(id, {
501
+ hrStart: process$1.hrtime(),
502
+ lines: []
503
+ });
504
+ });
505
+ context.hook("kubb:hook:line", ({ id, line }) => {
506
+ const active = state.hooks.get(id);
507
+ if (!active) return;
508
+ if (state.phase) {
509
+ active.lines.push(line);
510
+ return;
511
+ }
512
+ writer.raw([line]);
513
+ });
514
+ }
515
+ return { renderSummary(lines, { status }) {
516
+ if (silent || !state.groupOpen) return;
517
+ closeGroup(status);
518
+ writer.diagnostic([...lines]);
519
+ } };
520
+ };
521
+ }
522
+ //#endregion
523
+ //#region src/loggers/plainLogger.ts
524
+ /**
525
+ * Prefixes that stand in for the symbols clack draws, so plain output reads the same way.
526
+ */
527
+ const SYMBOLS = {
528
+ info: "ℹ",
529
+ warn: "⚠",
530
+ error: "✗",
531
+ step: "◇"
532
+ };
533
+ /** Draws with one `write` call per line. Nothing animates, so a step prints at start and end. */
534
+ function createWriter(write) {
535
+ return {
536
+ group: write,
537
+ groupEnd: write,
538
+ step: (text) => write(`${SYMBOLS.step} ${text}`),
539
+ info: write,
540
+ success: write,
541
+ warn: write,
542
+ error: (text) => write(`${SYMBOLS.error} ${text}`),
543
+ block: (lines) => write(lines.join("\n")),
544
+ raw: (lines) => write(lines.join("\n")),
545
+ diagnostic: (lines) => write(lines.join("\n")),
546
+ update: (lines, title) => write([title, ...lines].join("\n")),
547
+ spinner: () => ({
548
+ start: write,
549
+ message: write,
550
+ clear: () => {},
551
+ stop: (text) => text && write(text),
552
+ error: (text) => write(`${SYMBOLS.error} ${text}`)
553
+ }),
554
+ progress: () => ({
555
+ start: write,
556
+ advance: write,
557
+ stop: (text) => text && write(text)
558
+ })
559
+ };
560
+ }
561
+ /** The plain logger writing through `write`, e.g. `console.error` so stdout carries only JSON. */
562
+ function createPlainLogger(write) {
563
+ return createLogger(createWriter(write));
564
+ }
565
+ /** Draws on the console, for non-TTY environments and for an AI coding agent reading the output. */
566
+ const plainWriter = createWriter((line) => console.log(line));
567
+ /**
568
+ * Console adapter for non-TTY environments, and for an AI coding agent reading the output. Reports
569
+ * the same run in the same order as `clackLogger`, without the animation.
570
+ */
571
+ const plainLogger = createLogger(plainWriter);
572
+ //#endregion
573
+ //#region src/utils/env.ts
574
+ /**
575
+ * Returns `true` when the process has an interactive TTY with a valid terminal
576
+ * width and is not running in CI.
577
+ *
578
+ * Some IDE-embedded terminals report `isTTY = true` but set `columns` to `0`,
579
+ * which breaks clack's box-drawing helpers (they call `String.prototype.repeat`
580
+ * with a negative count and throw a `RangeError`). A positive column count is
581
+ * required before the TTY counts as usable.
582
+ *
583
+ * @example
584
+ * ```ts
585
+ * if (canUseTTY()) {
586
+ * renderProgressBar()
587
+ * }
588
+ * ```
589
+ */
590
+ function canUseTTY() {
591
+ return process.stdout.isTTY && (process.stdout.columns ?? 0) > 0 && !isCIEnvironment();
592
+ }
593
+ /**
594
+ * Returns `true` when output can carry spinners and clack's gutter: an interactive TTY that no AI
595
+ * coding agent is reading. Cursor-movement escapes are hard for an agent to parse even over a
596
+ * pseudo-TTY, so it gets the plain writer.
597
+ */
598
+ function isRichOutput() {
599
+ return canUseTTY() && !getAgentName();
600
+ }
601
+ //#endregion
602
+ //#region src/loggers/clackLogger.ts
603
+ /**
604
+ * Draws with clack: a gutter bar per group, animated steps, and a progress bar for the writes.
605
+ */
606
+ const clackWriter = {
607
+ group: (title) => clack.intro(title),
608
+ groupEnd: (text) => clack.outro(text),
609
+ step: (text) => clack.log.step(text, { spacing: 0 }),
610
+ info: (text) => clack.log.info(text),
611
+ success: (text) => clack.log.success(text),
612
+ warn: (text) => clack.log.warn(text),
613
+ error: (text) => clack.log.error(text),
614
+ block: (lines) => clack.log.message(lines, { spacing: 0 }),
615
+ raw: (lines) => console.log(styleText("dim", lines.join("\n"))),
616
+ diagnostic: (lines) => clack.log.message(lines, {
617
+ symbol: "",
618
+ secondarySymbol: ""
619
+ }),
620
+ update: (lines, title) => clack.box(lines.join("\n"), title, {
621
+ width: "auto",
622
+ formatBorder: (border) => styleText("yellow", border),
623
+ rounded: true,
624
+ withGuide: false,
625
+ contentAlign: "center",
626
+ titleAlign: "center"
627
+ }),
628
+ spinner() {
629
+ const spinner = clack.spinner();
630
+ return {
631
+ start: (text) => spinner.start(text),
632
+ message: (text) => spinner.message(text),
633
+ clear: () => spinner.clear(),
634
+ stop: (text) => spinner.stop(text),
635
+ error: (text) => spinner.error(text)
636
+ };
637
+ },
638
+ progress(max) {
639
+ const bar = clack.progress({
640
+ style: "block",
641
+ max,
642
+ size: 30
643
+ });
644
+ return {
645
+ start: (text) => bar.start(text),
646
+ advance: (text) => bar.advance(1, text),
647
+ stop: (text) => bar.stop(text)
648
+ };
649
+ }
650
+ };
651
+ /**
652
+ * TTY logger for local development, with animated steps and progress bars.
653
+ */
654
+ const clackLogger = createLogger(clackWriter);
655
+ //#endregion
656
+ //#region src/loggers/output.ts
657
+ const SPONSOR_TIPS = [
658
+ "Your sponsorship keeps Kubb codegen, plugins, and docs maintained",
659
+ "Sponsor faster generators and better Kubb Studio workflows",
660
+ "Help keep Kubb free for TypeScript teams building APIs",
661
+ "Support React Query, Zod, Faker, and MSW integrations",
662
+ "Back open-source tools that turn OpenAPI into TypeScript",
663
+ "Sponsor fixes, releases, and new plugins for your API workflow",
664
+ "Help Kubb stay independent and focused on developer tools"
665
+ ];
666
+ const SPONSOR_LINKS = [
667
+ "https://github.com/sponsors/stijnvanhulle",
668
+ "https://opencollective.com/kubb",
669
+ "https://kubb.dev/sponsors"
670
+ ];
671
+ /** The writer the loggers draw with on this terminal, so a command's own lines look like its run. */
672
+ function writer() {
673
+ return isRichOutput() ? clackWriter : plainWriter;
674
+ }
675
+ function nextTip() {
676
+ return `${SPONSOR_TIPS[Math.floor(Math.random() * SPONSOR_TIPS.length)]}: ${SPONSOR_LINKS[Math.floor(Math.random() * SPONSOR_LINKS.length)]}`;
677
+ }
678
+ function formatTip(tip) {
679
+ return styleText("magenta", " Tip ") + styleText("yellow", tip);
680
+ }
681
+ /**
682
+ * Prints one random tip outside every group. Rich terminals get the styled variant;
683
+ * plain/CI output gets a stable text-only line so the tip is still visible as final output.
684
+ */
685
+ function logTip() {
686
+ const tip = nextTip();
687
+ if (!isRichOutput()) {
688
+ console.log(`Tip: ${tip}`);
689
+ return;
690
+ }
691
+ console.log(`${styleText("magenta", "✦")}${formatTip(tip)}`);
692
+ }
693
+ function write(level, message) {
694
+ if (isRichOutput()) {
695
+ clack.log[level](message);
696
+ return;
697
+ }
698
+ console.log(`${SYMBOLS[level]} ${message}`);
699
+ }
700
+ /**
701
+ * Opens a command's output with its title.
702
+ */
703
+ function logIntro({ title, warning, block = true }) {
704
+ if (block && isRichOutput()) {
705
+ if (title) clack.intro(title);
706
+ if (warning) clack.log.warn(warning);
707
+ return;
708
+ }
709
+ if (title) console.log(title);
710
+ if (warning) console.warn(warning);
711
+ if (title || warning) console.log();
712
+ }
713
+ /**
714
+ * Closes the block {@link logIntro} opened. The closing gutter is not a written line, so plain
715
+ * output prints the text on its own.
716
+ */
717
+ function logOutro(text) {
718
+ writer().groupEnd(text);
719
+ }
720
+ /**
721
+ * Prints one empty line between two groups, without clack's gutter bar, since the bar belongs to a
722
+ * group and a spacer sits outside every one.
723
+ */
724
+ function logSpacer() {
725
+ console.log("");
726
+ }
727
+ /**
728
+ * Opens the command with the Kubb mascot and version, or a single version line where the terminal
729
+ * cannot draw it.
730
+ */
731
+ function logBanner(version) {
732
+ if (isRichOutput()) {
733
+ console.log(`\n${getIntro({
734
+ title: "Turn your API spec into type-safe code",
735
+ description: "Ready to start",
736
+ version,
737
+ areEyesOpen: true
738
+ })}\n`);
739
+ return;
740
+ }
741
+ console.log(`Kubb CLI v${version}`);
742
+ }
743
+ /** Prints lines as one block, without a symbol in front of them. Not the writer's block, which drops clack's spacing around it. */
744
+ function logBlock(lines) {
745
+ if (isRichOutput()) {
746
+ clack.log.message(lines);
747
+ return;
748
+ }
749
+ console.log([lines].flat().join("\n"));
750
+ }
751
+ function logInfo(message) {
752
+ write("info", message);
753
+ }
754
+ function logWarn(message) {
755
+ write("warn", message);
756
+ }
757
+ function logError(message) {
758
+ write("error", message);
759
+ }
760
+ /**
761
+ * Reports a step the command is taking, rather than something it found.
762
+ */
763
+ function logStep(message) {
764
+ write("step", message);
765
+ }
766
+ /**
767
+ * A progress spinner, or a writer that prints each message it is given when the terminal cannot
768
+ * animate one. Callers drive both the same way, including the failure state.
769
+ */
770
+ function createSpinner() {
771
+ return writer().spinner();
772
+ }
773
+ //#endregion
774
+ export { pluralize as _, logInfo as a, logSpacer as c, logWarn as d, clackLogger as f, plainLogger as g, createPlainLogger as h, logError as i, logStep as l, isRichOutput as m, logBanner as n, logIntro as o, canUseTTY as p, logBlock as r, logOutro as s, createSpinner as t, logTip as u };
775
+
776
+ //# sourceMappingURL=output-B6Ondw0g.js.map