@kubb/cli 5.3.7 → 5.3.9

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 (98) hide show
  1. package/dist/{Telemetry-CvHQevSK.cjs → Telemetry-B3kc9gFh.cjs} +3 -2
  2. package/dist/Telemetry-B3kc9gFh.cjs.map +1 -0
  3. package/dist/{Telemetry-CJcQkQOT.js → Telemetry-Dw5s6abr.js} +3 -2
  4. package/dist/Telemetry-Dw5s6abr.js.map +1 -0
  5. package/dist/connect-DFd7vS7_.js +11 -0
  6. package/dist/connect-DFd7vS7_.js.map +1 -0
  7. package/dist/connect-bCESn4L8.cjs +11 -0
  8. package/dist/connect-bCESn4L8.cjs.map +1 -0
  9. package/dist/{generate-CXozTFxt.cjs → generate-Cl5hFNdC.cjs} +5 -18
  10. package/dist/generate-Cl5hFNdC.cjs.map +1 -0
  11. package/dist/{generate-BhfKNqK4.js → generate-Del-D4hj.js} +5 -18
  12. package/dist/generate-Del-D4hj.js.map +1 -0
  13. package/dist/index.cjs +9 -18
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.js +9 -18
  16. package/dist/index.js.map +1 -1
  17. package/dist/{init-lhSbdp7u.cjs → init-C5trdwre.cjs} +3 -3
  18. package/dist/{init-lhSbdp7u.cjs.map → init-C5trdwre.cjs.map} +1 -1
  19. package/dist/{init-DrITcv-T.js → init-CBAmaPkc.js} +3 -3
  20. package/dist/{init-DrITcv-T.js.map → init-CBAmaPkc.js.map} +1 -1
  21. package/dist/login-5QXmUaQN.cjs +11 -0
  22. package/dist/login-5QXmUaQN.cjs.map +1 -0
  23. package/dist/login-D-1xSRxT.js +11 -0
  24. package/dist/login-D-1xSRxT.js.map +1 -0
  25. package/dist/logout-B2vHFyac.cjs +14 -0
  26. package/dist/logout-B2vHFyac.cjs.map +1 -0
  27. package/dist/logout-XB0v_SY-.js +14 -0
  28. package/dist/logout-XB0v_SY-.js.map +1 -0
  29. package/dist/output-CdnsdD1b.js +342 -0
  30. package/dist/output-CdnsdD1b.js.map +1 -0
  31. package/dist/output-DBBTlqPw.cjs +438 -0
  32. package/dist/output-DBBTlqPw.cjs.map +1 -0
  33. package/dist/{package-B955x8sl.cjs → package-BwIh-jWZ.cjs} +2 -2
  34. package/dist/package-BwIh-jWZ.cjs.map +1 -0
  35. package/dist/package-CDw1YdJ8.js +6 -0
  36. package/dist/package-CDw1YdJ8.js.map +1 -0
  37. package/dist/{run-DDgF_Z4A.js → run-Bd-IwEch.js} +48 -301
  38. package/dist/run-Bd-IwEch.js.map +1 -0
  39. package/dist/{run-DUzjWd_N.js → run-C5HkzCUt.js} +27 -23
  40. package/dist/run-C5HkzCUt.js.map +1 -0
  41. package/dist/{run-3DJ8CszL.cjs → run-CIonyF_t.cjs} +99 -299
  42. package/dist/run-CIonyF_t.cjs.map +1 -0
  43. package/dist/{run-BI8Fbzpd.js → run-CLhU86LM.js} +3 -3
  44. package/dist/{run-BI8Fbzpd.js.map → run-CLhU86LM.js.map} +1 -1
  45. package/dist/{run-kdxqOL8u.js → run-CeTu1eSk.js} +2 -2
  46. package/dist/{run-kdxqOL8u.js.map → run-CeTu1eSk.js.map} +1 -1
  47. package/dist/{run-CALspAGk.cjs → run-CxglY4u6.cjs} +27 -23
  48. package/dist/run-CxglY4u6.cjs.map +1 -0
  49. package/dist/{run-T7GVVdoF.cjs → run-DPuKGV20.cjs} +3 -3
  50. package/dist/{run-T7GVVdoF.cjs.map → run-DPuKGV20.cjs.map} +1 -1
  51. package/dist/{run-C5cKBTCX.js → run-Df4x0iX_.js} +3 -3
  52. package/dist/{run-C5cKBTCX.js.map → run-Df4x0iX_.js.map} +1 -1
  53. package/dist/{run-Ckw7BXJp.cjs → run-SybIXc6w.cjs} +3 -3
  54. package/dist/{run-Ckw7BXJp.cjs.map → run-SybIXc6w.cjs.map} +1 -1
  55. package/dist/{run-VK50TiB7.cjs → run-ZPt0Sw9r.cjs} +2 -2
  56. package/dist/{run-VK50TiB7.cjs.map → run-ZPt0Sw9r.cjs.map} +1 -1
  57. package/dist/shared-C5doIqKD.js +64 -0
  58. package/dist/shared-C5doIqKD.js.map +1 -0
  59. package/dist/shared-CaRlFkWL.cjs +87 -0
  60. package/dist/shared-CaRlFkWL.cjs.map +1 -0
  61. package/dist/snapshot-DWNiluEm.cjs +261 -0
  62. package/dist/snapshot-DWNiluEm.cjs.map +1 -0
  63. package/dist/snapshot-Dhwz_MpL.js +260 -0
  64. package/dist/snapshot-Dhwz_MpL.js.map +1 -0
  65. package/dist/status-Cc3wqN4l.js +11 -0
  66. package/dist/status-Cc3wqN4l.js.map +1 -0
  67. package/dist/status-CxMC5vAa.cjs +11 -0
  68. package/dist/status-CxMC5vAa.cjs.map +1 -0
  69. package/dist/studio-CQ24bwGz.cjs +155 -0
  70. package/dist/studio-CQ24bwGz.cjs.map +1 -0
  71. package/dist/studio-jqKsQP5_.js +155 -0
  72. package/dist/studio-jqKsQP5_.js.map +1 -0
  73. package/dist/{utils-s6yetN6W.js → utils-B1_SWa35.js} +356 -525
  74. package/dist/utils-B1_SWa35.js.map +1 -0
  75. package/dist/{utils-CMU1rLfY.cjs → utils-BP0xq5AK.cjs} +345 -508
  76. package/dist/utils-BP0xq5AK.cjs.map +1 -0
  77. package/package.json +9 -9
  78. package/dist/Telemetry-CJcQkQOT.js.map +0 -1
  79. package/dist/Telemetry-CvHQevSK.cjs.map +0 -1
  80. package/dist/generate-BhfKNqK4.js.map +0 -1
  81. package/dist/generate-CXozTFxt.cjs.map +0 -1
  82. package/dist/output-DH2Uoy4x.js +0 -118
  83. package/dist/output-DH2Uoy4x.js.map +0 -1
  84. package/dist/output-kmklyYIv.cjs +0 -172
  85. package/dist/output-kmklyYIv.cjs.map +0 -1
  86. package/dist/package-B955x8sl.cjs.map +0 -1
  87. package/dist/package-CE0Mgpd_.js +0 -6
  88. package/dist/package-CE0Mgpd_.js.map +0 -1
  89. package/dist/run-3DJ8CszL.cjs.map +0 -1
  90. package/dist/run-CALspAGk.cjs.map +0 -1
  91. package/dist/run-DDgF_Z4A.js.map +0 -1
  92. package/dist/run-DUzjWd_N.js.map +0 -1
  93. package/dist/studio-B33RIU3-.cjs +0 -111
  94. package/dist/studio-B33RIU3-.cjs.map +0 -1
  95. package/dist/studio-Cq_th0uM.js +0 -112
  96. package/dist/studio-Cq_th0uM.js.map +0 -1
  97. package/dist/utils-CMU1rLfY.cjs.map +0 -1
  98. package/dist/utils-s6yetN6W.js.map +0 -1
@@ -0,0 +1,342 @@
1
+ import "./rolldown-runtime-C0LytTxp.js";
2
+ import { n as isCIEnvironment, t as getAgentName } from "./agent-3JmkMghp.js";
3
+ import { styleText } from "node:util";
4
+ import * as prompts from "@clack/prompts";
5
+ //#region ../../internals/utils/src/time.ts
6
+ /**
7
+ * Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.
8
+ * Rounds to 2 decimal places for sub-millisecond precision without noise.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const start = process.hrtime()
13
+ * doWork()
14
+ * getElapsedMs(start) // 42.35
15
+ * ```
16
+ */
17
+ function getElapsedMs(hrStart) {
18
+ const [seconds, nanoseconds] = process.hrtime(hrStart);
19
+ const ms = seconds * 1e3 + nanoseconds / 1e6;
20
+ return Math.round(ms * 100) / 100;
21
+ }
22
+ /**
23
+ * Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * formatMs(250) // '250ms'
28
+ * formatMs(1500) // '1.50s'
29
+ * formatMs(90000) // '1m 30.0s'
30
+ * ```
31
+ */
32
+ function formatMs(ms) {
33
+ if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
34
+ if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
35
+ return `${Math.round(ms)}ms`;
36
+ }
37
+ //#endregion
38
+ //#region src/utils/env.ts
39
+ /**
40
+ * Returns `true` when the process has an interactive TTY with a valid terminal
41
+ * width and is not running in CI.
42
+ *
43
+ * Some IDE-embedded terminals report `isTTY = true` but set `columns` to `0`,
44
+ * which breaks clack's box-drawing helpers (they call `String.prototype.repeat`
45
+ * with a negative count and throw a `RangeError`). A positive column count is
46
+ * required before the TTY counts as usable.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * if (canUseTTY()) {
51
+ * renderProgressBar()
52
+ * }
53
+ * ```
54
+ */
55
+ function canUseTTY() {
56
+ return process.stdout.isTTY && (process.stdout.columns ?? 0) > 0 && !isCIEnvironment();
57
+ }
58
+ /**
59
+ * Returns `true` when output can carry spinners and clack's gutter: an interactive TTY that no AI
60
+ * coding agent is reading. Cursor-movement escapes are hard for an agent to parse even over a
61
+ * pseudo-TTY, so it gets the plain writer.
62
+ */
63
+ function isRichOutput() {
64
+ return canUseTTY() && !getAgentName();
65
+ }
66
+ //#endregion
67
+ //#region src/loggers/banner.ts
68
+ /**
69
+ * Parses a CSS hex color string (`#RGB`) into its RGB channels.
70
+ * Falls back to `255` for any channel that cannot be parsed.
71
+ */
72
+ function parseHex(color) {
73
+ const int = Number.parseInt(color.replace("#", ""), 16);
74
+ return Number.isNaN(int) ? {
75
+ r: 255,
76
+ g: 255,
77
+ b: 255
78
+ } : {
79
+ r: int >> 16 & 255,
80
+ g: int >> 8 & 255,
81
+ b: int & 255
82
+ };
83
+ }
84
+ /**
85
+ * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence
86
+ * for the given hex color.
87
+ */
88
+ function hex(color) {
89
+ const { r, g, b } = parseHex(color);
90
+ return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
91
+ }
92
+ function gradient(colorStops, text) {
93
+ const chars = text.split("");
94
+ return chars.map((char, i) => {
95
+ const t = chars.length <= 1 ? 0 : i / (chars.length - 1);
96
+ const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2);
97
+ const lt = t * (colorStops.length - 1) - seg;
98
+ const from = parseHex(colorStops[seg]);
99
+ const to = parseHex(colorStops[seg + 1]);
100
+ 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`;
101
+ }).join("");
102
+ }
103
+ /**
104
+ * ANSI color functions for each part of the Kubb mascot illustration.
105
+ */
106
+ const palette = {
107
+ /**
108
+ * Top cap of the skittle.
109
+ */
110
+ lid: hex("#F55A17"),
111
+ /**
112
+ * Upper wood body.
113
+ */
114
+ woodTop: hex("#F5A217"),
115
+ /**
116
+ * Middle wood body.
117
+ */
118
+ woodMid: hex("#F58517"),
119
+ /**
120
+ * Base wood body.
121
+ */
122
+ woodBase: hex("#B45309"),
123
+ /**
124
+ * Eye whites.
125
+ */
126
+ eye: hex("#FFFFFF"),
127
+ /**
128
+ * Highlight accent.
129
+ */
130
+ highlight: hex("#adadc6"),
131
+ /**
132
+ * Cheek blush.
133
+ */
134
+ blush: hex("#FDA4AF")
135
+ };
136
+ /**
137
+ * Generates the Kubb mascot welcome banner as an ANSI-colored string.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * console.log(getIntro({ title: 'kubb.config.ts', description: 'generating…', version: '5.0.0', areEyesOpen: true }))
142
+ * ```
143
+ */
144
+ function getIntro({ title, description, version, areEyesOpen }) {
145
+ const kubbVersion = gradient([
146
+ "#F58517",
147
+ "#F5A217",
148
+ "#F55A17"
149
+ ], `KUBB v${version}`);
150
+ const eyeTop = areEyesOpen ? palette.eye("█▀█") : palette.eye("───");
151
+ const eyeBottom = areEyesOpen ? palette.eye("▀▀▀") : palette.eye("───");
152
+ return [
153
+ ` ${palette.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")}`,
154
+ ` ${palette.woodTop("█ ")}${palette.highlight("▄▄")}${palette.woodTop(" ")}${palette.highlight("▄▄")}${palette.woodTop(" █")} ${kubbVersion}`,
155
+ ` ${palette.woodMid("█ ")}${eyeTop}${palette.woodMid(" ")}${eyeTop}${palette.woodMid(" █")} ${styleText("gray", title)}`,
156
+ ` ${palette.woodMid("█ ")}${eyeBottom}${palette.woodMid(" ")}${palette.blush("◡")}${palette.woodMid(" ")}${eyeBottom}${palette.woodMid(" █")} ${styleText("yellow", "➜")} ${styleText("white", description)}`,
157
+ ` ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")}`
158
+ ].join("\n");
159
+ }
160
+ /**
161
+ * Formats a millisecond duration with a threshold-based ANSI color.
162
+ * `≤ 500 ms` → green · `≤ 1 000 ms` → yellow · `> 1 000 ms` → red.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * formatMsWithColor(200) // '\x1b[32m200ms\x1b[39m'
167
+ * formatMsWithColor(800) // '\x1b[33m800ms\x1b[39m'
168
+ * formatMsWithColor(1500) // '\x1b[31m1.50s\x1b[39m'
169
+ * ```
170
+ */
171
+ function formatMsWithColor(ms) {
172
+ const formatted = formatMs(ms);
173
+ if (ms <= 500) return styleText("green", formatted);
174
+ if (ms <= 1e3) return styleText("yellow", formatted);
175
+ return styleText("red", formatted);
176
+ }
177
+ //#endregion
178
+ //#region src/loggers/output.ts
179
+ /**
180
+ * Prefixes the plain writers use, the same ones `plainLogger` prints, so a command's own output
181
+ * and the hook output around it read as one stream.
182
+ */
183
+ const SYMBOLS = {
184
+ info: "ℹ",
185
+ warn: "⚠",
186
+ error: "✗",
187
+ step: "◇"
188
+ };
189
+ const SPONSOR_TIPS = [
190
+ "Your sponsorship keeps Kubb codegen, plugins, and docs maintained",
191
+ "Sponsor faster generators and better Kubb Studio workflows",
192
+ "Help keep Kubb free for TypeScript teams building APIs",
193
+ "Support React Query, Zod, Faker, and MSW integrations",
194
+ "Back open-source tools that turn OpenAPI into TypeScript",
195
+ "Sponsor fixes, releases, and new plugins for your API workflow",
196
+ "Help Kubb stay independent and focused on developer tools"
197
+ ];
198
+ const SPONSOR_LINKS = [
199
+ "https://github.com/sponsors/stijnvanhulle",
200
+ "https://opencollective.com/kubb",
201
+ "https://kubb.dev/sponsors"
202
+ ];
203
+ const TIP_ROTATION_INTERVAL_MS = 3e4;
204
+ const MAX_ROTATING_TIPS = 1;
205
+ let tipIndex = Math.floor(Math.random() * SPONSOR_TIPS.length);
206
+ function nextTip() {
207
+ const tip = SPONSOR_TIPS[tipIndex];
208
+ tipIndex = (tipIndex + 1) % SPONSOR_TIPS.length;
209
+ return `${tip}: ${SPONSOR_LINKS[Math.floor(Math.random() * SPONSOR_LINKS.length)]}`;
210
+ }
211
+ function formatTip(tip) {
212
+ return styleText("magenta", " Tip ") + styleText("yellow", tip);
213
+ }
214
+ /**
215
+ * Prints the next rotating tip, without clack's gutter bar, since a tip sits outside every group.
216
+ * Skipped where the output is piped, captured by CI, or read by an agent.
217
+ */
218
+ function logTip() {
219
+ if (!isRichOutput()) return;
220
+ console.log(`${styleText("magenta", "✦")}${formatTip(nextTip())}`);
221
+ }
222
+ /**
223
+ * Rotates tips during an interactive long-running command. Returns the function that stops it.
224
+ *
225
+ * @example A session that tips every five minutes it sits idle
226
+ * ```ts
227
+ * const stop = startTipRotation({ intervalMs: 300_000, max: Number.POSITIVE_INFINITY, isIdle })
228
+ * ```
229
+ */
230
+ function startTipRotation({ intervalMs = TIP_ROTATION_INTERVAL_MS, max = MAX_ROTATING_TIPS, isIdle } = {}) {
231
+ if (!isRichOutput()) return () => {};
232
+ let shown = 0;
233
+ const timer = setInterval(() => {
234
+ if (isIdle && !isIdle()) return;
235
+ logTip();
236
+ shown++;
237
+ if (shown >= max) clearInterval(timer);
238
+ }, intervalMs);
239
+ timer.unref();
240
+ return () => clearInterval(timer);
241
+ }
242
+ function write(level, message) {
243
+ if (isRichOutput()) {
244
+ prompts.log[level](message);
245
+ return;
246
+ }
247
+ console.log(`${SYMBOLS[level]} ${message}`);
248
+ }
249
+ /**
250
+ * Opens a command's output with its title.
251
+ */
252
+ function logIntro({ title, warning, block = true }) {
253
+ if (block && isRichOutput()) {
254
+ if (title) prompts.intro(title);
255
+ if (warning) prompts.log.warn(warning);
256
+ return;
257
+ }
258
+ if (title) console.log(title);
259
+ if (warning) console.warn(warning);
260
+ if (title || warning) console.log();
261
+ }
262
+ /**
263
+ * Closes the block {@link logIntro} opened. The closing gutter is not a written line, so plain
264
+ * output prints the text on its own.
265
+ */
266
+ function logOutro(text) {
267
+ if (isRichOutput()) {
268
+ prompts.outro(text);
269
+ return;
270
+ }
271
+ console.log(text);
272
+ }
273
+ /**
274
+ * Prints one empty line between two groups, without clack's gutter bar, since the bar belongs to a
275
+ * group and a spacer sits outside every one.
276
+ */
277
+ function logSpacer() {
278
+ console.log("");
279
+ }
280
+ /**
281
+ * Opens the command with the Kubb mascot and version, or a single version line where the terminal
282
+ * cannot draw it.
283
+ */
284
+ function logBanner(version) {
285
+ if (isRichOutput()) {
286
+ console.log(`\n${getIntro({
287
+ title: "The meta framework for code generation",
288
+ description: "Ready to start",
289
+ version,
290
+ areEyesOpen: true
291
+ })}\n`);
292
+ return;
293
+ }
294
+ console.log(`Kubb CLI v${version}`);
295
+ }
296
+ /**
297
+ * Prints lines as one block, without a symbol in front of them.
298
+ */
299
+ function logBlock(lines) {
300
+ if (isRichOutput()) {
301
+ prompts.log.message(lines);
302
+ return;
303
+ }
304
+ console.log([lines].flat().join("\n"));
305
+ }
306
+ function logInfo(message) {
307
+ write("info", message);
308
+ }
309
+ function logWarn(message) {
310
+ write("warn", message);
311
+ }
312
+ function logError(message) {
313
+ write("error", message);
314
+ }
315
+ /**
316
+ * Reports a step the command is taking, rather than something it found.
317
+ */
318
+ function logStep(message) {
319
+ write("step", message);
320
+ }
321
+ /**
322
+ * A progress spinner, or a writer that prints each message it is given when the terminal cannot
323
+ * animate one. Callers drive both the same way, including the failure state.
324
+ */
325
+ function createSpinner() {
326
+ if (isRichOutput()) return prompts.spinner();
327
+ const print = (message) => {
328
+ if (message) console.log(message);
329
+ };
330
+ return {
331
+ start: print,
332
+ stop: print,
333
+ error: (message) => {
334
+ if (message) console.log(`${SYMBOLS.error} ${message}`);
335
+ },
336
+ message: print
337
+ };
338
+ }
339
+ //#endregion
340
+ export { logInfo as a, logSpacer as c, logWarn as d, startTipRotation as f, getElapsedMs as g, formatMs as h, logError as i, logStep as l, canUseTTY as m, logBanner as n, logIntro as o, formatMsWithColor as p, logBlock as r, logOutro as s, createSpinner as t, logTip as u };
341
+
342
+ //# sourceMappingURL=output-CdnsdD1b.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-CdnsdD1b.js","names":[],"sources":["../../../internals/utils/src/time.ts","../src/utils/env.ts","../src/loggers/banner.ts","../src/loggers/output.ts"],"sourcesContent":["/**\n * Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.\n * Rounds to 2 decimal places for sub-millisecond precision without noise.\n *\n * @example\n * ```ts\n * const start = process.hrtime()\n * doWork()\n * getElapsedMs(start) // 42.35\n * ```\n */\nexport function getElapsedMs(hrStart: [number, number]): number {\n const [seconds, nanoseconds] = process.hrtime(hrStart)\n const ms = seconds * 1000 + nanoseconds / 1e6\n return Math.round(ms * 100) / 100\n}\n\n/**\n * Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).\n *\n * @example\n * ```ts\n * formatMs(250) // '250ms'\n * formatMs(1500) // '1.50s'\n * formatMs(90000) // '1m 30.0s'\n * ```\n */\nexport function formatMs(ms: number): string {\n if (ms >= 60000) {\n const mins = Math.floor(ms / 60000)\n const secs = ((ms % 60000) / 1000).toFixed(1)\n return `${mins}m ${secs}s`\n }\n\n if (ms >= 1000) {\n return `${(ms / 1000).toFixed(2)}s`\n }\n return `${Math.round(ms)}ms`\n}\n","import { getAgentName } from '../agent.ts'\nimport { isCIEnvironment } from '@internals/utils'\n\n/**\n * Returns `true` when the process has an interactive TTY with a valid terminal\n * width and is not running in CI.\n *\n * Some IDE-embedded terminals report `isTTY = true` but set `columns` to `0`,\n * which breaks clack's box-drawing helpers (they call `String.prototype.repeat`\n * with a negative count and throw a `RangeError`). A positive column count is\n * required before the TTY counts as usable.\n *\n * @example\n * ```ts\n * if (canUseTTY()) {\n * renderProgressBar()\n * }\n * ```\n */\nexport function canUseTTY(): boolean {\n return process.stdout.isTTY && (process.stdout.columns ?? 0) > 0 && !isCIEnvironment()\n}\n\n/**\n * Returns `true` when output can carry spinners and clack's gutter: an interactive TTY that no AI\n * coding agent is reading. Cursor-movement escapes are hard for an agent to parse even over a\n * pseudo-TTY, so it gets the plain writer.\n */\nexport function isRichOutput(): boolean {\n return canUseTTY() && !getAgentName()\n}\n","import { styleText } from 'node:util'\nimport { formatMs } from '@internals/utils'\n\n/**\n * Parsed RGB channels from a CSS hex color string.\n */\ntype RGB = { r: number; g: number; b: number }\n\n/**\n * Parses a CSS hex color string (`#RGB`) into its RGB channels.\n * Falls back to `255` for any channel that cannot be parsed.\n */\nfunction parseHex(color: string): RGB {\n const int = Number.parseInt(color.replace('#', ''), 16)\n return Number.isNaN(int) ? { r: 255, g: 255, b: 255 } : { r: (int >> 16) & 0xff, g: (int >> 8) & 0xff, b: int & 0xff }\n}\n\n/**\n * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence\n * for the given hex color.\n */\nfunction hex(color: string): (text: string) => string {\n const { r, g, b } = parseHex(color)\n return (text: string) => `\\x1b[38;2;${r};${g};${b}m${text}\\x1b[0m`\n}\n\nfunction gradient(colorStops: Array<string>, text: string): string {\n const chars = text.split('')\n return chars\n .map((char, i) => {\n const t = chars.length <= 1 ? 0 : i / (chars.length - 1)\n const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2)\n const lt = t * (colorStops.length - 1) - seg\n const from = parseHex(colorStops[seg]!)\n const to = parseHex(colorStops[seg + 1]!)\n const r = Math.round(from.r + (to.r - from.r) * lt)\n const g = Math.round(from.g + (to.g - from.g) * lt)\n const b = Math.round(from.b + (to.b - from.b) * lt)\n return `\\x1b[38;2;${r};${g};${b}m${char}\\x1b[0m`\n })\n .join('')\n}\n\n/**\n * ANSI color functions for each part of the Kubb mascot illustration.\n */\nconst palette = {\n /**\n * Top cap of the skittle.\n */\n lid: hex('#F55A17'),\n /**\n * Upper wood body.\n */\n woodTop: hex('#F5A217'),\n /**\n * Middle wood body.\n */\n woodMid: hex('#F58517'),\n /**\n * Base wood body.\n */\n woodBase: hex('#B45309'),\n /**\n * Eye whites.\n */\n eye: hex('#FFFFFF'),\n /**\n * Highlight accent.\n */\n highlight: hex('#adadc6'),\n /**\n * Cheek blush.\n */\n blush: hex('#FDA4AF'),\n}\n\n/**\n * Generates the Kubb mascot welcome banner as an ANSI-colored string.\n *\n * @example\n * ```ts\n * console.log(getIntro({ title: 'kubb.config.ts', description: 'generating…', version: '5.0.0', areEyesOpen: true }))\n * ```\n */\nexport function getIntro({\n title,\n description,\n version,\n areEyesOpen,\n}: {\n /**\n * Name of the active configuration or tool being started.\n */\n title: string\n /**\n * Short subtitle shown next to the arrow prompt.\n */\n description: string\n /**\n * Kubb version string rendered in the gradient header.\n */\n version: string\n /**\n * When `false` the eyes are shown as closed dashes instead of open blocks.\n */\n areEyesOpen: boolean\n}): string {\n const kubbVersion = gradient(['#F58517', '#F5A217', '#F55A17'], `KUBB v${version}`)\n\n const eyeTop = areEyesOpen ? palette.eye('█▀█') : palette.eye('───')\n const eyeBottom = areEyesOpen ? palette.eye('▀▀▀') : palette.eye('───')\n\n return [\n ` ${palette.lid('▄▄▄▄▄▄▄▄▄▄▄▄▄')}`,\n ` ${palette.woodTop('█ ')}${palette.highlight('▄▄')}${palette.woodTop(' ')}${palette.highlight('▄▄')}${palette.woodTop(' █')} ${kubbVersion}`,\n ` ${palette.woodMid('█ ')}${eyeTop}${palette.woodMid(' ')}${eyeTop}${palette.woodMid(' █')} ${styleText('gray', title)}`,\n ` ${palette.woodMid('█ ')}${eyeBottom}${palette.woodMid(' ')}${palette.blush('◡')}${palette.woodMid(' ')}${eyeBottom}${palette.woodMid(' █')} ${styleText('yellow', '➜')} ${styleText('white', description)}`,\n ` ${palette.woodBase('▀▀▀▀▀▀▀▀▀▀▀▀▀')}`,\n ].join('\\n')\n}\n\n/**\n * Formats a millisecond duration with a threshold-based ANSI color.\n * `≤ 500 ms` → green · `≤ 1 000 ms` → yellow · `> 1 000 ms` → red.\n *\n * @example\n * ```ts\n * formatMsWithColor(200) // '\\x1b[32m200ms\\x1b[39m'\n * formatMsWithColor(800) // '\\x1b[33m800ms\\x1b[39m'\n * formatMsWithColor(1500) // '\\x1b[31m1.50s\\x1b[39m'\n * ```\n */\nexport function formatMsWithColor(ms: number): string {\n const formatted = formatMs(ms)\n if (ms <= 500) return styleText('green', formatted)\n if (ms <= 1000) return styleText('yellow', formatted)\n\n return styleText('red', formatted)\n}\n","import { styleText } from 'node:util'\nimport * as prompts from '@clack/prompts'\nimport { isRichOutput } from '../utils/env.ts'\nimport { getIntro } from './banner.ts'\n\n/**\n * Prefixes the plain writers use, the same ones `plainLogger` prints, so a command's own output\n * and the hook output around it read as one stream.\n */\nconst SYMBOLS = { info: 'ℹ', warn: '⚠', error: '✗', step: '◇' } as const\n\nconst SPONSOR_TIPS = [\n 'Your sponsorship keeps Kubb codegen, plugins, and docs maintained',\n 'Sponsor faster generators and better Kubb Studio workflows',\n 'Help keep Kubb free for TypeScript teams building APIs',\n 'Support React Query, Zod, Faker, and MSW integrations',\n 'Back open-source tools that turn OpenAPI into TypeScript',\n 'Sponsor fixes, releases, and new plugins for your API workflow',\n 'Help Kubb stay independent and focused on developer tools',\n] as const\n\nconst SPONSOR_LINKS = ['https://github.com/sponsors/stijnvanhulle', 'https://opencollective.com/kubb', 'https://kubb.dev/sponsors'] as const\n\nconst TIP_ROTATION_INTERVAL_MS = 30_000\nconst MAX_ROTATING_TIPS = 1\n\nlet tipIndex = Math.floor(Math.random() * SPONSOR_TIPS.length)\n\nfunction nextTip(): string {\n const tip = SPONSOR_TIPS[tipIndex]!\n tipIndex = (tipIndex + 1) % SPONSOR_TIPS.length\n\n return `${tip}: ${SPONSOR_LINKS[Math.floor(Math.random() * SPONSOR_LINKS.length)]}`\n}\n\nfunction formatTip(tip: string): string {\n return styleText('magenta', ' Tip ') + styleText('yellow', tip)\n}\n\n/**\n * Prints the next rotating tip, without clack's gutter bar, since a tip sits outside every group.\n * Skipped where the output is piped, captured by CI, or read by an agent.\n */\nexport function logTip(): void {\n if (!isRichOutput()) {\n return\n }\n\n console.log(`${styleText('magenta', '✦')}${formatTip(nextTip())}`)\n}\n\ntype TipRotationOptions = {\n intervalMs?: number\n /**\n * How many tips to show before the rotation stops on its own. Pass\n * `Number.POSITIVE_INFINITY` for a command that keeps running, such as a `kubb studio` session\n * waiting for jobs.\n *\n * @default 1\n */\n max?: number\n /**\n * Asked before each tip. A `false` answer skips that turn without stopping the rotation, so a tip\n * never lands in the middle of a run.\n */\n isIdle?: () => boolean\n}\n\n/**\n * Rotates tips during an interactive long-running command. Returns the function that stops it.\n *\n * @example A session that tips every five minutes it sits idle\n * ```ts\n * const stop = startTipRotation({ intervalMs: 300_000, max: Number.POSITIVE_INFINITY, isIdle })\n * ```\n */\nexport function startTipRotation({ intervalMs = TIP_ROTATION_INTERVAL_MS, max = MAX_ROTATING_TIPS, isIdle }: TipRotationOptions = {}): () => void {\n if (!isRichOutput()) return () => {}\n\n let shown = 0\n const timer = setInterval(() => {\n if (isIdle && !isIdle()) {\n return\n }\n\n logTip()\n shown++\n if (shown >= max) clearInterval(timer)\n }, intervalMs)\n timer.unref()\n\n return () => clearInterval(timer)\n}\n\ntype Level = keyof typeof SYMBOLS\n\nfunction write(level: Level, message: string): void {\n if (isRichOutput()) {\n prompts.log[level](message)\n\n return\n }\n\n console.log(`${SYMBOLS[level]} ${message}`)\n}\n\ntype IntroOptions = {\n title?: string\n /**\n * Printed under the title, for a command that has a caveat to lead with.\n */\n warning?: string\n /**\n * Whether to open a block a later {@link logOutro} closes. Pass `false` for a command that\n * prints and exits, since nothing would ever close the block.\n *\n * @default true\n */\n block?: boolean\n}\n\n/**\n * Opens a command's output with its title.\n */\nexport function logIntro({ title, warning, block = true }: IntroOptions): void {\n if (block && isRichOutput()) {\n if (title) {\n prompts.intro(title)\n }\n\n if (warning) {\n prompts.log.warn(warning)\n }\n\n return\n }\n\n if (title) {\n console.log(title)\n }\n\n if (warning) {\n console.warn(warning)\n }\n\n if (title || warning) {\n console.log()\n }\n}\n\n/**\n * Closes the block {@link logIntro} opened. The closing gutter is not a written line, so plain\n * output prints the text on its own.\n */\nexport function logOutro(text: string): void {\n if (isRichOutput()) {\n prompts.outro(text)\n\n return\n }\n\n console.log(text)\n}\n\n/**\n * Prints one empty line between two groups, without clack's gutter bar, since the bar belongs to a\n * group and a spacer sits outside every one.\n */\nexport function logSpacer(): void {\n console.log('')\n}\n\n/**\n * Opens the command with the Kubb mascot and version, or a single version line where the terminal\n * cannot draw it.\n */\nexport function logBanner(version: string): void {\n if (isRichOutput()) {\n console.log(`\\n${getIntro({ title: 'The meta framework for code generation', description: 'Ready to start', version, areEyesOpen: true })}\\n`)\n\n return\n }\n\n console.log(`Kubb CLI v${version}`)\n}\n\n/**\n * Prints lines as one block, without a symbol in front of them.\n */\nexport function logBlock(lines: string | Array<string>): void {\n if (isRichOutput()) {\n prompts.log.message(lines)\n\n return\n }\n\n console.log([lines].flat().join('\\n'))\n}\n\nexport function logInfo(message: string): void {\n write('info', message)\n}\n\nexport function logWarn(message: string): void {\n write('warn', message)\n}\n\nexport function logError(message: string): void {\n write('error', message)\n}\n\n/**\n * Reports a step the command is taking, rather than something it found.\n */\nexport function logStep(message: string): void {\n write('step', message)\n}\n\ntype Spinner = {\n start: (message?: string) => void\n stop: (message?: string) => void\n /**\n * Ends the step as failed, so a phase that went wrong does not read as finished.\n */\n error: (message?: string) => void\n message: (message?: string) => void\n}\n\n/**\n * A progress spinner, or a writer that prints each message it is given when the terminal cannot\n * animate one. Callers drive both the same way, including the failure state.\n */\nexport function createSpinner(): Spinner {\n if (isRichOutput()) {\n return prompts.spinner()\n }\n\n const print = (message?: string) => {\n if (message) {\n console.log(message)\n }\n }\n\n return {\n start: print,\n stop: print,\n error: (message?: string) => {\n if (message) {\n console.log(`${SYMBOLS.error} ${message}`)\n }\n },\n message: print,\n }\n}\n"],"mappings":"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"}