@kubb/cli 4.32.4 → 4.33.1

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 (133) hide show
  1. package/dist/agent-Bd1QdPVV.cjs +91 -0
  2. package/dist/agent-Bd1QdPVV.cjs.map +1 -0
  3. package/dist/agent-D83d9Pud.cjs +60 -0
  4. package/dist/agent-D83d9Pud.cjs.map +1 -0
  5. package/dist/agent-DgKQXSmR.js +57 -0
  6. package/dist/agent-DgKQXSmR.js.map +1 -0
  7. package/dist/agent-u_Ehwz6r.js +87 -0
  8. package/dist/agent-u_Ehwz6r.js.map +1 -0
  9. package/dist/constants-BTUap0zs.cjs +108 -0
  10. package/dist/constants-BTUap0zs.cjs.map +1 -0
  11. package/dist/constants-CM3dJzjK.js +67 -0
  12. package/dist/constants-CM3dJzjK.js.map +1 -0
  13. package/dist/define--M_JMcDC.js +25 -0
  14. package/dist/define--M_JMcDC.js.map +1 -0
  15. package/dist/define-D6Kfm7-Z.cjs +36 -0
  16. package/dist/define-D6Kfm7-Z.cjs.map +1 -0
  17. package/dist/errors-6mF_WKxg.js +27 -0
  18. package/dist/errors-6mF_WKxg.js.map +1 -0
  19. package/dist/errors-DBW0N9w4.cjs +44 -0
  20. package/dist/errors-DBW0N9w4.cjs.map +1 -0
  21. package/dist/generate-Bn8n4w1O.cjs +65 -0
  22. package/dist/generate-Bn8n4w1O.cjs.map +1 -0
  23. package/dist/{generate-CpWtSc45.js → generate-CAsV9wSx.js} +656 -689
  24. package/dist/generate-CAsV9wSx.js.map +1 -0
  25. package/dist/generate-D-59YK0L.js +66 -0
  26. package/dist/generate-D-59YK0L.js.map +1 -0
  27. package/dist/{generate-COj0aMS6.cjs → generate-JC65igQh.cjs} +662 -694
  28. package/dist/generate-JC65igQh.cjs.map +1 -0
  29. package/dist/index.cjs +226 -35
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.js +226 -35
  33. package/dist/index.js.map +1 -1
  34. package/dist/init-C-InrmSY.js +302 -0
  35. package/dist/init-C-InrmSY.js.map +1 -0
  36. package/dist/init-CXP8OfMe.js +25 -0
  37. package/dist/init-CXP8OfMe.js.map +1 -0
  38. package/dist/init-CbeE-L-0.cjs +25 -0
  39. package/dist/init-CbeE-L-0.cjs.map +1 -0
  40. package/dist/init-hmolV6B4.cjs +306 -0
  41. package/dist/init-hmolV6B4.cjs.map +1 -0
  42. package/dist/jiti-Cd3S0xwr.cjs +16 -0
  43. package/dist/jiti-Cd3S0xwr.cjs.map +1 -0
  44. package/dist/jiti-e08mD2Ph.js +11 -0
  45. package/dist/jiti-e08mD2Ph.js.map +1 -0
  46. package/dist/mcp-BDxg2oJm.cjs +16 -0
  47. package/dist/mcp-BDxg2oJm.cjs.map +1 -0
  48. package/dist/mcp-ChHFPRzD.cjs +42 -0
  49. package/dist/mcp-ChHFPRzD.cjs.map +1 -0
  50. package/dist/mcp-D2SHEg_d.js +41 -0
  51. package/dist/mcp-D2SHEg_d.js.map +1 -0
  52. package/dist/mcp-MSoE4vNA.js +16 -0
  53. package/dist/mcp-MSoE4vNA.js.map +1 -0
  54. package/dist/{package-aNQWvWbS.cjs → package-CUVyeIbt.cjs} +2 -2
  55. package/dist/package-CUVyeIbt.cjs.map +1 -0
  56. package/dist/package-Cbd8OC6q.js +6 -0
  57. package/dist/package-Cbd8OC6q.js.map +1 -0
  58. package/dist/shell-7HPrTCJ5.cjs +57 -0
  59. package/dist/shell-7HPrTCJ5.cjs.map +1 -0
  60. package/dist/shell-DqqWsHCD.js +46 -0
  61. package/dist/shell-DqqWsHCD.js.map +1 -0
  62. package/dist/{telemetry-BDSSqUiG.cjs → telemetry-Cn9X1I5B.cjs} +79 -9
  63. package/dist/telemetry-Cn9X1I5B.cjs.map +1 -0
  64. package/dist/{telemetry-DYWvlxqs.js → telemetry-DxiR7clS.js} +63 -11
  65. package/dist/telemetry-DxiR7clS.js.map +1 -0
  66. package/dist/validate-BG8A3aQS.cjs +25 -0
  67. package/dist/validate-BG8A3aQS.cjs.map +1 -0
  68. package/dist/validate-BZ1UFkwA.js +25 -0
  69. package/dist/validate-BZ1UFkwA.js.map +1 -0
  70. package/dist/validate-Bbrn3Q-A.cjs +42 -0
  71. package/dist/validate-Bbrn3Q-A.cjs.map +1 -0
  72. package/dist/validate-l8vLmwKA.js +41 -0
  73. package/dist/validate-l8vLmwKA.js.map +1 -0
  74. package/package.json +6 -6
  75. package/src/commands/agent/start.ts +27 -136
  76. package/src/commands/agent.ts +6 -25
  77. package/src/commands/generate.ts +26 -158
  78. package/src/commands/init.ts +9 -360
  79. package/src/commands/mcp.ts +7 -52
  80. package/src/commands/validate.ts +9 -60
  81. package/src/constants.ts +76 -0
  82. package/src/index.ts +36 -42
  83. package/src/loggers/clackLogger.ts +65 -165
  84. package/src/loggers/fileSystemLogger.ts +2 -14
  85. package/src/loggers/githubActionsLogger.ts +58 -125
  86. package/src/loggers/plainLogger.ts +44 -92
  87. package/src/loggers/utils.ts +67 -4
  88. package/src/runners/agent.ts +100 -0
  89. package/src/runners/generate.ts +223 -102
  90. package/src/runners/init.ts +323 -0
  91. package/src/runners/mcp.ts +32 -0
  92. package/src/runners/validate.ts +35 -0
  93. package/src/utils/Writables.ts +2 -2
  94. package/src/utils/executeHooks.ts +20 -8
  95. package/src/utils/getCosmiConfig.ts +10 -11
  96. package/src/utils/getIntro.ts +1 -81
  97. package/src/utils/getSummary.ts +12 -17
  98. package/src/utils/jiti.ts +9 -0
  99. package/src/utils/packageManager.ts +4 -4
  100. package/src/utils/runHook.ts +75 -0
  101. package/src/utils/telemetry.ts +8 -26
  102. package/src/utils/watcher.ts +2 -4
  103. package/dist/agent-6COck3B9.cjs +0 -20
  104. package/dist/agent-6COck3B9.cjs.map +0 -1
  105. package/dist/agent-DMm6c5Vg.js +0 -20
  106. package/dist/agent-DMm6c5Vg.js.map +0 -1
  107. package/dist/generate-COj0aMS6.cjs.map +0 -1
  108. package/dist/generate-CpWtSc45.js.map +0 -1
  109. package/dist/init-Bdn3_qir.js +0 -304
  110. package/dist/init-Bdn3_qir.js.map +0 -1
  111. package/dist/init-CFW2kWY8.cjs +0 -308
  112. package/dist/init-CFW2kWY8.cjs.map +0 -1
  113. package/dist/mcp-DkwtARfo.cjs +0 -57
  114. package/dist/mcp-DkwtARfo.cjs.map +0 -1
  115. package/dist/mcp-DrH93Vq4.js +0 -57
  116. package/dist/mcp-DrH93Vq4.js.map +0 -1
  117. package/dist/package-BnJbGmLm.js +0 -6
  118. package/dist/package-BnJbGmLm.js.map +0 -1
  119. package/dist/package-aNQWvWbS.cjs.map +0 -1
  120. package/dist/start-CqTUu14n.js +0 -131
  121. package/dist/start-CqTUu14n.js.map +0 -1
  122. package/dist/start-D-rsIJGo.cjs +0 -134
  123. package/dist/start-D-rsIJGo.cjs.map +0 -1
  124. package/dist/telemetry-BDSSqUiG.cjs.map +0 -1
  125. package/dist/telemetry-DYWvlxqs.js.map +0 -1
  126. package/dist/validate-BlV8L8gC.js +0 -66
  127. package/dist/validate-BlV8L8gC.js.map +0 -1
  128. package/dist/validate-COhZUXF8.cjs +0 -66
  129. package/dist/validate-COhZUXF8.cjs.map +0 -1
  130. package/src/loggers/envDetection.ts +0 -28
  131. package/src/loggers/index.ts +0 -5
  132. package/src/utils/formatMsWithColor.ts +0 -22
  133. package/src/utils/randomColor.ts +0 -23
@@ -1,76 +1,143 @@
1
1
  import "./chunk--u3MIqq1.js";
2
- import { t as version } from "./package-BnJbGmLm.js";
3
- import { r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-DYWvlxqs.js";
2
+ import { n as toCause, r as toError } from "./errors-6mF_WKxg.js";
3
+ import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-DxiR7clS.js";
4
+ import { n as tokenize } from "./shell-DqqWsHCD.js";
5
+ import { t as version } from "./package-Cbd8OC6q.js";
6
+ import { i as WATCHER_IGNORED_PATHS, r as SUMMARY_SEPARATOR, t as KUBB_NPM_PACKAGE_URL } from "./constants-CM3dJzjK.js";
4
7
  import { styleText } from "node:util";
5
- import { defineCommand, showUsage } from "citty";
8
+ import { EventEmitter } from "node:events";
6
9
  import { createHash } from "node:crypto";
7
- import * as process$2 from "node:process";
10
+ import "node:fs";
11
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
12
+ import path, { dirname, relative, resolve } from "node:path";
8
13
  import process$1 from "node:process";
9
- import { AsyncEventEmitter, detectFormatter, detectLinter, executeIfOnline, formatHrtime, formatMs, formatters, getConfigs, linters, tokenize } from "@kubb/core/utils";
10
- import path, { relative, resolve } from "node:path";
11
14
  import * as clack from "@clack/prompts";
12
- import { LogLevel, PromiseManager, defineLogger, isInputPath, safeBuild, setup } from "@kubb/core";
13
- import { x } from "tinyexec";
15
+ import { PromiseManager, defineLogger, detectFormatter, detectLinter, formatters, getConfigs, isInputPath, linters, logLevel, safeBuild, setup } from "@kubb/core";
16
+ import { NonZeroExitError, x } from "tinyexec";
14
17
  import { Writable } from "node:stream";
15
- import { write } from "@kubb/core/fs";
16
18
  import { cosmiconfig } from "cosmiconfig";
17
19
  import { createJiti } from "jiti";
18
- //#region src/utils/formatMsWithColor.ts
20
+ //#region ../../internals/utils/src/asyncEventEmitter.ts
19
21
  /**
20
- * Formats milliseconds with color based on duration thresholds:
21
- * - Green: <= 500ms
22
- * - Yellow: > 500ms and <= 1000ms
23
- * - Red: > 1000ms
22
+ * A typed EventEmitter that awaits all async listeners before resolving.
23
+ * Wraps Node's `EventEmitter` with full TypeScript event-map inference.
24
24
  */
25
- function formatMsWithColor(ms) {
26
- const formatted = formatMs(ms);
27
- if (ms <= 500) return styleText("green", formatted);
28
- if (ms <= 1e3) return styleText("yellow", formatted);
29
- return styleText("red", formatted);
30
- }
25
+ var AsyncEventEmitter = class {
26
+ /**
27
+ * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning.
28
+ * @default 10
29
+ */
30
+ constructor(maxListener = 10) {
31
+ this.#emitter.setMaxListeners(maxListener);
32
+ }
33
+ #emitter = new EventEmitter();
34
+ /**
35
+ * Emits an event and awaits all registered listeners in parallel.
36
+ * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
37
+ */
38
+ async emit(eventName, ...eventArgs) {
39
+ const listeners = this.#emitter.listeners(eventName);
40
+ if (listeners.length === 0) return;
41
+ await Promise.all(listeners.map(async (listener) => {
42
+ try {
43
+ return await listener(...eventArgs);
44
+ } catch (err) {
45
+ let serializedArgs;
46
+ try {
47
+ serializedArgs = JSON.stringify(eventArgs);
48
+ } catch {
49
+ serializedArgs = String(eventArgs);
50
+ }
51
+ throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
52
+ }
53
+ }));
54
+ }
55
+ /** Registers a persistent listener for the given event. */
56
+ on(eventName, handler) {
57
+ this.#emitter.on(eventName, handler);
58
+ }
59
+ /** Registers a one-shot listener that removes itself after the first invocation. */
60
+ onOnce(eventName, handler) {
61
+ const wrapper = (...args) => {
62
+ this.off(eventName, wrapper);
63
+ return handler(...args);
64
+ };
65
+ this.on(eventName, wrapper);
66
+ }
67
+ /** Removes a previously registered listener. */
68
+ off(eventName, handler) {
69
+ this.#emitter.off(eventName, handler);
70
+ }
71
+ /** Removes all listeners from every event channel. */
72
+ removeAll() {
73
+ this.#emitter.removeAllListeners();
74
+ }
75
+ };
31
76
  //#endregion
32
- //#region src/utils/getIntro.ts
77
+ //#region ../../internals/utils/src/time.ts
78
+ /**
79
+ * Calculates elapsed time in milliseconds from a high-resolution start time.
80
+ * Rounds to 2 decimal places to provide sub-millisecond precision without noise.
81
+ */
82
+ function getElapsedMs(hrStart) {
83
+ const [seconds, nanoseconds] = process.hrtime(hrStart);
84
+ const ms = seconds * 1e3 + nanoseconds / 1e6;
85
+ return Math.round(ms * 100) / 100;
86
+ }
33
87
  /**
34
- * ANSI True Color (24-bit) utilities for terminal output
35
- * Supports hex color codes without external dependencies like chalk
88
+ * Converts a millisecond duration into a human-readable string.
89
+ * Adjusts units (ms, s, m s) based on the magnitude of the duration.
36
90
  */
91
+ function formatMs(ms) {
92
+ if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
93
+ if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
94
+ return `${Math.round(ms)}ms`;
95
+ }
37
96
  /**
38
- * Convert hex color to ANSI 24-bit true color escape sequence
39
- * @param color - Hex color code (with or without #), e.g., '#FF5500' or 'FF5500'
40
- * @returns Function that wraps text with the color
97
+ * Convenience helper: formats the elapsed time since `hrStart` in one step.
41
98
  */
42
- function hex(color) {
43
- const cleanHex = color.replace("#", "");
44
- const r = Number.parseInt(cleanHex.slice(0, 2), 16);
45
- const g = Number.parseInt(cleanHex.slice(2, 4), 16);
46
- const b = Number.parseInt(cleanHex.slice(4, 6), 16);
47
- const safeR = Number.isNaN(r) ? 255 : r;
48
- const safeG = Number.isNaN(g) ? 255 : g;
49
- const safeB = Number.isNaN(b) ? 255 : b;
50
- return (text) => `\x1b[38;2;${safeR};${safeG};${safeB}m${text}\x1b[0m`;
99
+ function formatHrtime(hrStart) {
100
+ return formatMs(getElapsedMs(hrStart));
51
101
  }
52
- function hexToRgb(color) {
53
- const c = color.replace("#", "");
54
- return {
55
- r: Number.parseInt(c.slice(0, 2), 16),
56
- g: Number.parseInt(c.slice(2, 4), 16),
57
- b: Number.parseInt(c.slice(4, 6), 16)
102
+ //#endregion
103
+ //#region ../../internals/utils/src/colors.ts
104
+ /**
105
+ * Parses a CSS hex color string (`#RGB`) into its RGB channels.
106
+ * Falls back to `255` for any channel that cannot be parsed.
107
+ */
108
+ function parseHex(color) {
109
+ const int = Number.parseInt(color.replace("#", ""), 16);
110
+ return Number.isNaN(int) ? {
111
+ r: 255,
112
+ g: 255,
113
+ b: 255
114
+ } : {
115
+ r: int >> 16 & 255,
116
+ g: int >> 8 & 255,
117
+ b: int & 255
58
118
  };
59
119
  }
60
- function gradient(colors) {
61
- return (text) => {
62
- const chars = [...text];
63
- return chars.map((char, i) => {
64
- const t = chars.length <= 1 ? 0 : i / (chars.length - 1);
65
- const seg = Math.min(Math.floor(t * (colors.length - 1)), colors.length - 2);
66
- const lt = t * (colors.length - 1) - seg;
67
- const from = hexToRgb(colors[seg]);
68
- const to = hexToRgb(colors[seg + 1]);
69
- 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`;
70
- }).join("");
71
- };
120
+ /**
121
+ * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence
122
+ * for the given hex color.
123
+ */
124
+ function hex(color) {
125
+ const { r, g, b } = parseHex(color);
126
+ return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
72
127
  }
73
- const colors = {
128
+ function gradient(colorStops, text) {
129
+ const chars = text.split("");
130
+ return chars.map((char, i) => {
131
+ const t = chars.length <= 1 ? 0 : i / (chars.length - 1);
132
+ const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2);
133
+ const lt = t * (colorStops.length - 1) - seg;
134
+ const from = parseHex(colorStops[seg]);
135
+ const to = parseHex(colorStops[seg + 1]);
136
+ 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`;
137
+ }).join("");
138
+ }
139
+ /** ANSI color functions for each part of the Kubb mascot illustration. */
140
+ const palette = {
74
141
  lid: hex("#F55A17"),
75
142
  woodTop: hex("#F5A217"),
76
143
  woodMid: hex("#F58517"),
@@ -80,57 +147,94 @@ const colors = {
80
147
  blush: hex("#FDA4AF")
81
148
  };
82
149
  /**
83
- * Generates the Kubb mascot face welcome message
84
- * @param version - The version string to display
85
- * @returns Formatted mascot face string
150
+ * Generates the Kubb mascot welcome banner.
86
151
  */
87
152
  function getIntro({ title, description, version, areEyesOpen }) {
88
153
  const kubbVersion = gradient([
89
154
  "#F58517",
90
155
  "#F5A217",
91
156
  "#F55A17"
92
- ])(`KUBB v${version}`);
93
- const eyeTop = areEyesOpen ? colors.eye("█▀█") : colors.eye("───");
94
- const eyeBottom = areEyesOpen ? colors.eye("▀▀▀") : colors.eye("───");
157
+ ], `KUBB v${version}`);
158
+ const eyeTop = areEyesOpen ? palette.eye("█▀█") : palette.eye("───");
159
+ const eyeBottom = areEyesOpen ? palette.eye("▀▀▀") : palette.eye("───");
95
160
  return `
96
- ${colors.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")}
97
- ${colors.woodTop("█ ")}${colors.highlight("▄▄")}${colors.woodTop(" ")}${colors.highlight("▄▄")}${colors.woodTop(" █")} ${kubbVersion}
98
- ${colors.woodMid("█ ")}${eyeTop}${colors.woodMid(" ")}${eyeTop}${colors.woodMid(" █")} ${styleText("gray", title)}
99
- ${colors.woodMid("█ ")}${eyeBottom}${colors.woodMid(" ")}${colors.blush("◡")}${colors.woodMid(" ")}${eyeBottom}${colors.woodMid(" █")} ${styleText("yellow", "➜")} ${styleText("white", description)}
100
- ${colors.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")}
161
+ ${palette.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")}
162
+ ${palette.woodTop("█ ")}${palette.highlight("▄▄")}${palette.woodTop(" ")}${palette.highlight("▄▄")}${palette.woodTop(" █")} ${kubbVersion}
163
+ ${palette.woodMid("█ ")}${eyeTop}${palette.woodMid(" ")}${eyeTop}${palette.woodMid(" █")} ${styleText("gray", title)}
164
+ ${palette.woodMid("█ ")}${eyeBottom}${palette.woodMid(" ")}${palette.blush("◡")}${palette.woodMid(" ")}${eyeBottom}${palette.woodMid(" █")} ${styleText("yellow", "➜")} ${styleText("white", description)}
165
+ ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")}
101
166
  `;
102
167
  }
103
- //#endregion
104
- //#region src/utils/randomColor.ts
105
- function randomColor(text) {
106
- if (!text) return "white";
107
- const defaultColors = [
108
- "black",
109
- "red",
110
- "green",
111
- "yellow",
112
- "blue",
113
- "red",
114
- "green",
115
- "magenta",
116
- "cyan",
117
- "gray"
118
- ];
119
- return defaultColors[createHash("sha256").update(text).digest().readUInt32BE(0) % defaultColors.length] ?? "white";
120
- }
168
+ /** ANSI color names available for terminal output. */
169
+ const randomColors = [
170
+ "black",
171
+ "red",
172
+ "green",
173
+ "yellow",
174
+ "blue",
175
+ "white",
176
+ "magenta",
177
+ "cyan",
178
+ "gray"
179
+ ];
180
+ /**
181
+ * Returns the text wrapped in a deterministic ANSI color derived from the text's SHA-256 hash.
182
+ */
121
183
  function randomCliColor(text) {
122
184
  if (!text) return "";
123
- return styleText(randomColor(text), text);
185
+ return styleText(randomColors[createHash("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text);
186
+ }
187
+ /**
188
+ * Formats a millisecond duration with an ANSI color based on thresholds:
189
+ * green ≤ 500 ms · yellow ≤ 1 000 ms · red > 1 000 ms
190
+ */
191
+ function formatMsWithColor(ms) {
192
+ const formatted = formatMs(ms);
193
+ if (ms <= 500) return styleText("green", formatted);
194
+ if (ms <= 1e3) return styleText("yellow", formatted);
195
+ return styleText("red", formatted);
196
+ }
197
+ //#endregion
198
+ //#region ../../internals/utils/src/fs.ts
199
+ /**
200
+ * Writes `data` to `path`, trimming leading/trailing whitespace before saving.
201
+ * Skips the write and returns `undefined` when the trimmed content is empty or
202
+ * identical to what is already on disk.
203
+ * Creates any missing parent directories automatically.
204
+ * When `sanity` is `true`, re-reads the file after writing and throws if the
205
+ * content does not match — useful for catching write failures on unreliable file systems.
206
+ */
207
+ async function write(path, data, options = {}) {
208
+ const trimmed = data.trim();
209
+ if (trimmed === "") return void 0;
210
+ const resolved = resolve(path);
211
+ if (typeof Bun !== "undefined") {
212
+ const file = Bun.file(resolved);
213
+ if ((await file.exists() ? await file.text() : null) === trimmed) return void 0;
214
+ await Bun.write(resolved, trimmed);
215
+ return trimmed;
216
+ }
217
+ try {
218
+ if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return void 0;
219
+ } catch {}
220
+ await mkdir(dirname(resolved), { recursive: true });
221
+ await writeFile(resolved, trimmed, { encoding: "utf-8" });
222
+ if (options.sanity) {
223
+ const savedData = await readFile(resolved, { encoding: "utf-8" });
224
+ if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`);
225
+ return savedData;
226
+ }
227
+ return trimmed;
124
228
  }
125
229
  //#endregion
126
230
  //#region src/utils/getSummary.ts
127
231
  function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
128
232
  const duration = formatHrtime(hrStart);
129
- const pluginsCount = config.plugins?.length || 0;
233
+ const pluginsCount = config.plugins?.length ?? 0;
130
234
  const successCount = pluginsCount - failedPlugins.size;
131
235
  const meta = {
132
236
  plugins: status === "success" ? `${styleText("green", `${successCount} successful`)}, ${pluginsCount} total` : `${styleText("green", `${successCount} successful`)}, ${styleText("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
133
- pluginsFailed: status === "failed" ? [...failedPlugins]?.map(({ plugin }) => randomCliColor(plugin.name))?.join(", ") : void 0,
237
+ pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
134
238
  filesCreated,
135
239
  time: styleText("green", duration),
136
240
  output: path.isAbsolute(config.root) ? path.resolve(config.root, config.output.path) : config.root
@@ -148,23 +252,76 @@ function getSummary({ failedPlugins, filesCreated, status, hrStart, config, plug
148
252
  if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
149
253
  summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
150
254
  if (pluginTimings && pluginTimings.size > 0) {
151
- const TIME_SCALE_DIVISOR = 100;
152
- const MAX_BAR_LENGTH = 10;
153
255
  const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
154
- if (sortedTimings.length > 0) {
155
- summaryLines.push(`${labels.pluginTimings}`);
156
- sortedTimings.forEach(([name, time]) => {
157
- const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
158
- const barLength = Math.min(Math.ceil(time / TIME_SCALE_DIVISOR), MAX_BAR_LENGTH);
159
- const bar = styleText("dim", "".repeat(barLength));
160
- summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
161
- });
162
- }
256
+ summaryLines.push(`${labels.pluginTimings}`);
257
+ sortedTimings.forEach(([name, time]) => {
258
+ const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
259
+ const barLength = Math.min(Math.ceil(time / 100), 10);
260
+ const bar = styleText("dim", "█".repeat(barLength));
261
+ summaryLines.push(`${styleText("dim", "")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
262
+ });
163
263
  }
164
264
  summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
165
265
  return summaryLines;
166
266
  }
167
267
  //#endregion
268
+ //#region src/utils/runHook.ts
269
+ /**
270
+ * Execute a hook command, emit debug/hook:end events, and forward output to
271
+ * an optional HookOutputSink. All three logger adapters share this function
272
+ * so the process-spawning logic lives in exactly one place.
273
+ */
274
+ async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
275
+ try {
276
+ const proc = x(command, [...args ?? []], {
277
+ nodeOptions: { detached: true },
278
+ throwOnError: true
279
+ });
280
+ if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
281
+ const result = await proc;
282
+ await context.emit("debug", {
283
+ date: /* @__PURE__ */ new Date(),
284
+ logs: [result.stdout.trimEnd()]
285
+ });
286
+ await context.emit("hook:end", {
287
+ command,
288
+ args,
289
+ id,
290
+ success: true,
291
+ error: null
292
+ });
293
+ } catch (err) {
294
+ if (!(err instanceof NonZeroExitError)) {
295
+ await context.emit("hook:end", {
296
+ command,
297
+ args,
298
+ id,
299
+ success: false,
300
+ error: toError(err)
301
+ });
302
+ await context.emit("error", toError(err));
303
+ return;
304
+ }
305
+ const stderr = err.output?.stderr ?? "";
306
+ const stdout = err.output?.stdout ?? "";
307
+ await context.emit("debug", {
308
+ date: /* @__PURE__ */ new Date(),
309
+ logs: [stdout, stderr].filter(Boolean)
310
+ });
311
+ if (stderr) sink?.onStderr?.(stderr);
312
+ if (stdout) sink?.onStdout?.(stdout);
313
+ const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
314
+ await context.emit("hook:end", {
315
+ command,
316
+ args,
317
+ id,
318
+ success: false,
319
+ error: errorMessage
320
+ });
321
+ await context.emit("error", errorMessage);
322
+ }
323
+ }
324
+ //#endregion
168
325
  //#region src/utils/Writables.ts
169
326
  var ClackWritable = class extends Writable {
170
327
  taskLog;
@@ -173,7 +330,7 @@ var ClackWritable = class extends Writable {
173
330
  this.taskLog = taskLog;
174
331
  }
175
332
  _write(chunk, _encoding, callback) {
176
- this.taskLog.message(`${styleText("dim", chunk?.toString())}`);
333
+ this.taskLog.message(`${styleText("dim", chunk.toString())}`);
177
334
  callback();
178
335
  }
179
336
  };
@@ -186,7 +343,7 @@ var ClackWritable = class extends Writable {
186
343
  const clackLogger = defineLogger({
187
344
  name: "clack",
188
345
  install(context, options) {
189
- const logLevel = options?.logLevel || LogLevel.info;
346
+ const logLevel$8 = options?.logLevel ?? logLevel.info;
190
347
  const state = {
191
348
  totalPlugins: 0,
192
349
  completedPlugins: 0,
@@ -214,27 +371,12 @@ const clackLogger = defineLogger({
214
371
  state.activeProgress.clear();
215
372
  }
216
373
  function showProgressStep() {
217
- if (logLevel <= LogLevel.silent) return;
218
- const parts = [];
219
- const duration = formatHrtime(state.hrStart);
220
- if (state.totalPlugins > 0) {
221
- 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}`;
222
- parts.push(pluginStr);
223
- }
224
- if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`);
225
- if (parts.length > 0) {
226
- parts.push(`${styleText("green", duration)} elapsed`);
227
- clack.log.step(getMessage(parts.join(styleText("dim", " | "))));
228
- }
374
+ if (logLevel$8 <= logLevel.silent) return;
375
+ const line = buildProgressLine(state);
376
+ if (line) clack.log.step(getMessage(line));
229
377
  }
230
378
  function getMessage(message) {
231
- if (logLevel >= LogLevel.verbose) return [styleText("dim", `[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
232
- hour12: false,
233
- hour: "2-digit",
234
- minute: "2-digit",
235
- second: "2-digit"
236
- })}]`), message].join(" ");
237
- return message;
379
+ return formatMessage(message, logLevel$8);
238
380
  }
239
381
  function startSpinner(text) {
240
382
  state.spinner.start(text);
@@ -245,7 +387,7 @@ const clackLogger = defineLogger({
245
387
  state.isSpinning = false;
246
388
  }
247
389
  context.on("info", (message, info = "") => {
248
- if (logLevel <= LogLevel.silent) return;
390
+ if (logLevel$8 <= logLevel.silent) return;
249
391
  const text = getMessage([
250
392
  styleText("blue", "ℹ"),
251
393
  message,
@@ -255,30 +397,30 @@ const clackLogger = defineLogger({
255
397
  else clack.log.info(text);
256
398
  });
257
399
  context.on("success", (message, info = "") => {
258
- if (logLevel <= LogLevel.silent) return;
400
+ if (logLevel$8 <= logLevel.silent) return;
259
401
  const text = getMessage([
260
402
  styleText("blue", "✓"),
261
403
  message,
262
- logLevel >= LogLevel.info ? styleText("dim", info) : void 0
404
+ logLevel$8 >= logLevel.info ? styleText("dim", info) : void 0
263
405
  ].filter(Boolean).join(" "));
264
406
  if (state.isSpinning) stopSpinner(text);
265
407
  else clack.log.success(text);
266
408
  });
267
409
  context.on("warn", (message, info) => {
268
- if (logLevel < LogLevel.warn) return;
410
+ if (logLevel$8 < logLevel.warn) return;
269
411
  const text = getMessage([
270
412
  styleText("yellow", "⚠"),
271
413
  message,
272
- logLevel >= LogLevel.info && info ? styleText("dim", info) : void 0
414
+ logLevel$8 >= logLevel.info && info ? styleText("dim", info) : void 0
273
415
  ].filter(Boolean).join(" "));
274
416
  clack.log.warn(text);
275
417
  });
276
418
  context.on("error", (error) => {
277
- const caused = error.cause;
419
+ const caused = toCause(error);
278
420
  const text = [styleText("red", "✗"), error.message].join(" ");
279
421
  if (state.isSpinning) stopSpinner(getMessage(text));
280
422
  else clack.log.error(getMessage(text));
281
- if (logLevel >= LogLevel.debug && error.stack) {
423
+ if (logLevel$8 >= logLevel.debug && error.stack) {
282
424
  const frames = error.stack.split("\n").slice(1, 4);
283
425
  for (const frame of frames) clack.log.message(getMessage(styleText("dim", frame.trim())));
284
426
  if (caused?.stack) {
@@ -289,7 +431,7 @@ const clackLogger = defineLogger({
289
431
  }
290
432
  });
291
433
  context.on("version:new", (version, latestVersion) => {
292
- if (logLevel <= LogLevel.silent) return;
434
+ if (logLevel$8 <= logLevel.silent) return;
293
435
  clack.box(`\`v${version}\` → \`v${latestVersion}\`
294
436
  Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
295
437
  width: "auto",
@@ -310,24 +452,24 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
310
452
  reset();
311
453
  });
312
454
  context.on("config:start", () => {
313
- if (logLevel <= LogLevel.silent) return;
455
+ if (logLevel$8 <= logLevel.silent) return;
314
456
  const text = getMessage("Configuration started");
315
457
  clack.intro(text);
316
458
  startSpinner(getMessage("Configuration loading"));
317
459
  });
318
460
  context.on("config:end", (_configs) => {
319
- if (logLevel <= LogLevel.silent) return;
461
+ if (logLevel$8 <= logLevel.silent) return;
320
462
  const text = getMessage("Configuration completed");
321
463
  clack.outro(text);
322
464
  });
323
465
  context.on("generation:start", (config) => {
324
- state.totalPlugins = config.plugins?.length || 0;
466
+ reset();
467
+ state.totalPlugins = config.plugins?.length ?? 0;
325
468
  const text = getMessage(["Generation started", config.name ? `for ${styleText("dim", config.name)}` : void 0].filter(Boolean).join(" "));
326
469
  clack.intro(text);
327
- reset();
328
470
  });
329
471
  context.on("plugin:start", (plugin) => {
330
- if (logLevel <= LogLevel.silent) return;
472
+ if (logLevel$8 <= logLevel.silent) return;
331
473
  stopSpinner();
332
474
  const progressBar = clack.progress({
333
475
  style: "block",
@@ -347,7 +489,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
347
489
  context.on("plugin:end", (plugin, { duration, success }) => {
348
490
  stopSpinner();
349
491
  const active = state.activeProgress.get(plugin.name);
350
- if (!active || logLevel === LogLevel.silent) return;
492
+ if (!active || logLevel$8 === logLevel.silent) return;
351
493
  clearInterval(active.interval);
352
494
  if (success) state.completedPlugins++;
353
495
  else state.failedPlugins++;
@@ -358,7 +500,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
358
500
  showProgressStep();
359
501
  });
360
502
  context.on("files:processing:start", (files) => {
361
- if (logLevel <= LogLevel.silent) return;
503
+ if (logLevel$8 <= logLevel.silent) return;
362
504
  stopSpinner();
363
505
  state.totalFiles = files.length;
364
506
  state.processedFiles = 0;
@@ -373,7 +515,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
373
515
  state.activeProgress.set("files", { progressBar });
374
516
  });
375
517
  context.on("file:processing:update", ({ file, config }) => {
376
- if (logLevel <= LogLevel.silent) return;
518
+ if (logLevel$8 <= logLevel.silent) return;
377
519
  stopSpinner();
378
520
  state.processedFiles++;
379
521
  const text = `Writing ${relative(config.root, file.path)}`;
@@ -382,7 +524,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
382
524
  active.progressBar.advance(void 0, text);
383
525
  });
384
526
  context.on("files:processing:end", () => {
385
- if (logLevel <= LogLevel.silent) return;
527
+ if (logLevel$8 <= logLevel.silent) return;
386
528
  stopSpinner();
387
529
  const text = getMessage("Files written successfully");
388
530
  const active = state.activeProgress.get("files");
@@ -396,113 +538,63 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
396
538
  clack.outro(text);
397
539
  });
398
540
  context.on("format:start", () => {
399
- if (logLevel <= LogLevel.silent) return;
541
+ if (logLevel$8 <= logLevel.silent) return;
400
542
  const text = getMessage("Format started");
401
543
  clack.intro(text);
402
544
  });
403
545
  context.on("format:end", () => {
404
- if (logLevel <= LogLevel.silent) return;
546
+ if (logLevel$8 <= logLevel.silent) return;
405
547
  const text = getMessage("Format completed");
406
548
  clack.outro(text);
407
549
  });
408
550
  context.on("lint:start", () => {
409
- if (logLevel <= LogLevel.silent) return;
551
+ if (logLevel$8 <= logLevel.silent) return;
410
552
  const text = getMessage("Lint started");
411
553
  clack.intro(text);
412
554
  });
413
555
  context.on("lint:end", () => {
414
- if (logLevel <= LogLevel.silent) return;
556
+ if (logLevel$8 <= logLevel.silent) return;
415
557
  const text = getMessage("Lint completed");
416
558
  clack.outro(text);
417
559
  });
418
560
  context.on("hook:start", async ({ id, command, args }) => {
419
- const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
561
+ const commandWithArgs = formatCommandWithArgs(command, args);
420
562
  const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`);
421
563
  if (!id) return;
422
- if (logLevel <= LogLevel.silent) {
423
- try {
424
- const result = await x(command, [...args ?? []], {
425
- nodeOptions: { detached: true },
426
- throwOnError: true
427
- });
428
- await context.emit("debug", {
429
- date: /* @__PURE__ */ new Date(),
430
- logs: [result.stdout.trimEnd()]
431
- });
432
- await context.emit("hook:end", {
433
- command,
434
- args,
435
- id,
436
- success: true,
437
- error: null
438
- });
439
- } catch (err) {
440
- const error = err;
441
- const stderr = error.output?.stderr ?? "";
442
- const stdout = error.output?.stdout ?? "";
443
- await context.emit("debug", {
444
- date: /* @__PURE__ */ new Date(),
445
- logs: [stdout, stderr].filter(Boolean)
446
- });
447
- if (stderr) console.error(stderr);
448
- if (stdout) console.log(stdout);
449
- const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
450
- await context.emit("hook:end", {
451
- command,
452
- args,
453
- id,
454
- success: false,
455
- error: errorMessage
456
- });
457
- await context.emit("error", errorMessage);
458
- }
459
- return;
460
- }
461
- clack.intro(text);
462
- const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel >= LogLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
463
- const writable = new ClackWritable(logger);
464
- try {
465
- const proc = x(command, [...args ?? []], {
466
- nodeOptions: { detached: true },
467
- throwOnError: true
468
- });
469
- for await (const line of proc) writable.write(line);
470
- const result = await proc;
471
- await context.emit("debug", {
472
- date: /* @__PURE__ */ new Date(),
473
- logs: [result.stdout.trimEnd()]
474
- });
475
- await context.emit("hook:end", {
476
- command,
477
- args,
564
+ if (logLevel$8 <= logLevel.silent) {
565
+ await runHook({
478
566
  id,
479
- success: true,
480
- error: null
481
- });
482
- } catch (err) {
483
- const error = err;
484
- const stderr = error.output?.stderr ?? "";
485
- const stdout = error.output?.stdout ?? "";
486
- await context.emit("debug", {
487
- date: /* @__PURE__ */ new Date(),
488
- logs: [stdout, stderr].filter(Boolean)
489
- });
490
- if (stderr) logger.error(stderr);
491
- if (stdout) logger.message(stdout);
492
- const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
493
- await context.emit("hook:end", {
494
567
  command,
495
568
  args,
496
- id,
497
- success: false,
498
- error: errorMessage
569
+ commandWithArgs,
570
+ context,
571
+ sink: {
572
+ onStderr: (s) => console.error(s),
573
+ onStdout: (s) => console.log(s)
574
+ }
499
575
  });
500
- await context.emit("error", errorMessage);
576
+ return;
501
577
  }
578
+ clack.intro(text);
579
+ const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel$8 >= logLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
580
+ const writable = new ClackWritable(logger);
581
+ await runHook({
582
+ id,
583
+ command,
584
+ args,
585
+ commandWithArgs,
586
+ context,
587
+ stream: true,
588
+ sink: {
589
+ onLine: (line) => writable.write(line),
590
+ onStderr: (s) => logger.error(s),
591
+ onStdout: (s) => logger.message(s)
592
+ }
593
+ });
502
594
  });
503
595
  context.on("hook:end", ({ command, args }) => {
504
- if (logLevel <= LogLevel.silent) return;
505
- const text = getMessage(`Hook ${styleText("dim", args?.length ? `${command} ${args.join(" ")}` : command)} successfully executed`);
596
+ if (logLevel$8 <= logLevel.silent) return;
597
+ const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} successfully executed`);
506
598
  clack.outro(text);
507
599
  });
508
600
  context.on("generation:summary", (config, { pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
@@ -512,25 +604,15 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
512
604
  config,
513
605
  status,
514
606
  hrStart,
515
- pluginTimings: logLevel >= LogLevel.verbose ? pluginTimings : void 0
607
+ pluginTimings: logLevel$8 >= logLevel.verbose ? pluginTimings : void 0
516
608
  });
517
609
  const title = config.name || "";
518
610
  summary.unshift("\n");
519
611
  summary.push("\n");
520
- if (status === "success") {
521
- clack.box(summary.join("\n"), getMessage(title), {
522
- width: "auto",
523
- formatBorder: (s) => styleText("green", s),
524
- rounded: true,
525
- withGuide: false,
526
- contentAlign: "left",
527
- titleAlign: "center"
528
- });
529
- return;
530
- }
612
+ const borderColor = status === "success" ? "green" : "red";
531
613
  clack.box(summary.join("\n"), getMessage(title), {
532
614
  width: "auto",
533
- formatBorder: (s) => styleText("red", s),
615
+ formatBorder: (s) => styleText(borderColor, s),
534
616
  rounded: true,
535
617
  withGuide: false,
536
618
  contentAlign: "left",
@@ -543,26 +625,6 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
543
625
  }
544
626
  });
545
627
  //#endregion
546
- //#region src/loggers/envDetection.ts
547
- /**
548
- * Check if running in GitHub Actions environment
549
- */
550
- function isGitHubActions() {
551
- return !!process.env.GITHUB_ACTIONS;
552
- }
553
- /**
554
- * Check if running in any CI environment
555
- */
556
- function isCIEnvironment() {
557
- return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.TRAVIS || process.env.JENKINS_URL || process.env.BUILDKITE);
558
- }
559
- /**
560
- * Check if TTY is available for interactive output
561
- */
562
- function canUseTTY() {
563
- return !!process.stdout.isTTY && !isCIEnvironment();
564
- }
565
- //#endregion
566
628
  //#region src/loggers/fileSystemLogger.ts
567
629
  /**
568
630
  * FileSystem logger for debug log persistence
@@ -591,7 +653,7 @@ const fileSystemLogger = defineLogger({
591
653
  name,
592
654
  state.startDate
593
655
  ].filter(Boolean).join("-")}.log`;
594
- const pathName = resolve(process.cwd(), ".kubb", baseName);
656
+ const pathName = resolve(process$1.cwd(), ".kubb", baseName);
595
657
  if (!files[pathName]) files[pathName] = [];
596
658
  if (log.logs.length > 0) {
597
659
  const timestamp = log.date.toLocaleString();
@@ -606,75 +668,66 @@ const fileSystemLogger = defineLogger({
606
668
  context.on("info", (message, info) => {
607
669
  state.cachedLogs.add({
608
670
  date: /* @__PURE__ */ new Date(),
609
- logs: [`ℹ ${message} ${info}`],
610
- fileName: void 0
671
+ logs: [`ℹ ${message} ${info}`]
611
672
  });
612
673
  });
613
674
  context.on("success", (message, info) => {
614
675
  state.cachedLogs.add({
615
676
  date: /* @__PURE__ */ new Date(),
616
- logs: [`✓ ${message} ${info}`],
617
- fileName: void 0
677
+ logs: [`✓ ${message} ${info}`]
618
678
  });
619
679
  });
620
680
  context.on("warn", (message, info) => {
621
681
  state.cachedLogs.add({
622
682
  date: /* @__PURE__ */ new Date(),
623
- logs: [`⚠ ${message} ${info}`],
624
- fileName: void 0
683
+ logs: [`⚠ ${message} ${info}`]
625
684
  });
626
685
  });
627
686
  context.on("error", (error) => {
628
687
  state.cachedLogs.add({
629
688
  date: /* @__PURE__ */ new Date(),
630
- logs: [`✗ ${error.message}`, error.stack || "unknown stack"],
631
- fileName: void 0
689
+ logs: [`✗ ${error.message}`, error.stack || "unknown stack"]
632
690
  });
633
691
  });
634
692
  context.on("debug", (message) => {
635
693
  state.cachedLogs.add({
636
694
  date: /* @__PURE__ */ new Date(),
637
- logs: message.logs,
638
- fileName: void 0
695
+ logs: message.logs
639
696
  });
640
697
  });
641
698
  context.on("plugin:start", (plugin) => {
642
699
  state.cachedLogs.add({
643
700
  date: /* @__PURE__ */ new Date(),
644
- logs: [`Generating ${plugin.name}`],
645
- fileName: void 0
701
+ logs: [`Generating ${plugin.name}`]
646
702
  });
647
703
  });
648
704
  context.on("plugin:end", (plugin, { duration, success }) => {
649
705
  const durationStr = formatMs(duration);
650
706
  state.cachedLogs.add({
651
707
  date: /* @__PURE__ */ new Date(),
652
- logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`],
653
- fileName: void 0
708
+ logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`]
654
709
  });
655
710
  });
656
711
  context.on("files:processing:start", (files) => {
657
712
  state.cachedLogs.add({
658
713
  date: /* @__PURE__ */ new Date(),
659
- logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)],
660
- fileName: void 0
714
+ logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)]
661
715
  });
662
716
  });
663
717
  context.on("generation:end", async (config) => {
664
718
  const writtenFilePaths = await writeLogs(config.name);
665
719
  if (writtenFilePaths.length > 0) {
666
- const files = writtenFilePaths.map((f) => relative(process.cwd(), f));
720
+ const files = writtenFilePaths.map((f) => relative(process$1.cwd(), f));
667
721
  await context.emit("info", "Debug files written to:", files.join(", "));
668
722
  }
669
723
  reset();
670
724
  });
671
- context.on("lifecycle:end", async () => {});
672
725
  const exitHandler = () => {
673
726
  if (state.cachedLogs.size > 0) writeLogs().catch(() => {});
674
727
  };
675
- process.once("exit", exitHandler);
676
- process.once("SIGINT", exitHandler);
677
- process.once("SIGTERM", exitHandler);
728
+ process$1.once("exit", exitHandler);
729
+ process$1.once("SIGINT", exitHandler);
730
+ process$1.once("SIGTERM", exitHandler);
678
731
  }
679
732
  });
680
733
  //#endregion
@@ -686,7 +739,7 @@ const fileSystemLogger = defineLogger({
686
739
  const githubActionsLogger = defineLogger({
687
740
  name: "github-actions",
688
741
  install(context, options) {
689
- const logLevel = options?.logLevel || LogLevel.info;
742
+ const logLevel$7 = options?.logLevel ?? logLevel.info;
690
743
  const state = {
691
744
  totalPlugins: 0,
692
745
  completedPlugins: 0,
@@ -703,29 +756,15 @@ const githubActionsLogger = defineLogger({
703
756
  state.totalFiles = 0;
704
757
  state.processedFiles = 0;
705
758
  state.hrStart = process.hrtime();
759
+ state.currentConfigs = [];
706
760
  }
707
761
  function showProgressStep() {
708
- if (logLevel <= LogLevel.silent) return;
709
- const parts = [];
710
- const duration = formatHrtime(state.hrStart);
711
- if (state.totalPlugins > 0) {
712
- 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}`;
713
- parts.push(pluginStr);
714
- }
715
- if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`);
716
- if (parts.length > 0) {
717
- parts.push(`${styleText("green", duration)} elapsed`);
718
- console.log(getMessage(parts.join(styleText("dim", " | "))));
719
- }
762
+ if (logLevel$7 <= logLevel.silent) return;
763
+ const line = buildProgressLine(state);
764
+ if (line) console.log(getMessage(line));
720
765
  }
721
766
  function getMessage(message) {
722
- if (logLevel >= LogLevel.verbose) return [styleText("dim", `[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
723
- hour12: false,
724
- hour: "2-digit",
725
- minute: "2-digit",
726
- second: "2-digit"
727
- })}]`), message].join(" ");
728
- return message;
767
+ return formatMessage(message, logLevel$7);
729
768
  }
730
769
  function openGroup(name) {
731
770
  console.log(`::group::${name}`);
@@ -734,7 +773,7 @@ const githubActionsLogger = defineLogger({
734
773
  console.log("::endgroup::");
735
774
  }
736
775
  context.on("info", (message, info = "") => {
737
- if (logLevel <= LogLevel.silent) return;
776
+ if (logLevel$7 <= logLevel.silent) return;
738
777
  const text = getMessage([
739
778
  styleText("blue", "ℹ"),
740
779
  message,
@@ -743,29 +782,29 @@ const githubActionsLogger = defineLogger({
743
782
  console.log(text);
744
783
  });
745
784
  context.on("success", (message, info = "") => {
746
- if (logLevel <= LogLevel.silent) return;
785
+ if (logLevel$7 <= logLevel.silent) return;
747
786
  const text = getMessage([
748
787
  styleText("blue", "✓"),
749
788
  message,
750
- logLevel >= LogLevel.info ? styleText("dim", info) : void 0
789
+ logLevel$7 >= logLevel.info ? styleText("dim", info) : void 0
751
790
  ].filter(Boolean).join(" "));
752
791
  console.log(text);
753
792
  });
754
793
  context.on("warn", (message, info = "") => {
755
- if (logLevel <= LogLevel.silent) return;
794
+ if (logLevel$7 <= logLevel.silent) return;
756
795
  const text = getMessage([
757
796
  styleText("yellow", "⚠"),
758
797
  message,
759
- logLevel >= LogLevel.info ? styleText("dim", info) : void 0
798
+ logLevel$7 >= logLevel.info ? styleText("dim", info) : void 0
760
799
  ].filter(Boolean).join(" "));
761
800
  console.warn(`::warning::${text}`);
762
801
  });
763
802
  context.on("error", (error) => {
764
- const caused = error.cause;
765
- if (logLevel <= LogLevel.silent) return;
803
+ const caused = toCause(error);
804
+ if (logLevel$7 <= logLevel.silent) return;
766
805
  const message = error.message || String(error);
767
806
  console.error(`::error::${message}`);
768
- if (logLevel >= LogLevel.debug && error.stack) {
807
+ if (logLevel$7 >= logLevel.debug && error.stack) {
769
808
  const frames = error.stack.split("\n").slice(1, 4);
770
809
  for (const frame of frames) console.log(getMessage(styleText("dim", frame.trim())));
771
810
  if (caused?.stack) {
@@ -780,33 +819,33 @@ const githubActionsLogger = defineLogger({
780
819
  reset();
781
820
  });
782
821
  context.on("config:start", () => {
783
- if (logLevel <= LogLevel.silent) return;
822
+ if (logLevel$7 <= logLevel.silent) return;
784
823
  const text = getMessage("Configuration started");
785
824
  openGroup("Configuration");
786
825
  console.log(text);
787
826
  });
788
827
  context.on("config:end", (configs) => {
789
828
  state.currentConfigs = configs;
790
- if (logLevel <= LogLevel.silent) return;
829
+ if (logLevel$7 <= logLevel.silent) return;
791
830
  const text = getMessage("Configuration completed");
792
831
  console.log(text);
793
832
  closeGroup("Configuration");
794
833
  });
795
834
  context.on("generation:start", (config) => {
796
- state.totalPlugins = config.plugins?.length || 0;
835
+ reset();
836
+ state.totalPlugins = config.plugins?.length ?? 0;
797
837
  const text = config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation";
798
838
  if (state.currentConfigs.length > 1) openGroup(text);
799
839
  if (state.currentConfigs.length === 1) console.log(getMessage(text));
800
- reset();
801
840
  });
802
841
  context.on("plugin:start", (plugin) => {
803
- if (logLevel <= LogLevel.silent) return;
842
+ if (logLevel$7 <= logLevel.silent) return;
804
843
  const text = getMessage(`Generating ${styleText("bold", plugin.name)}`);
805
844
  if (state.currentConfigs.length === 1) openGroup(`Plugin: ${plugin.name}`);
806
845
  console.log(text);
807
846
  });
808
847
  context.on("plugin:end", (plugin, { duration, success }) => {
809
- if (logLevel <= LogLevel.silent) return;
848
+ if (logLevel$7 <= logLevel.silent) return;
810
849
  if (success) state.completedPlugins++;
811
850
  else state.failedPlugins++;
812
851
  const durationStr = formatMsWithColor(duration);
@@ -817,7 +856,7 @@ const githubActionsLogger = defineLogger({
817
856
  showProgressStep();
818
857
  });
819
858
  context.on("files:processing:start", (files) => {
820
- if (logLevel <= LogLevel.silent) return;
859
+ if (logLevel$7 <= logLevel.silent) return;
821
860
  state.totalFiles = files.length;
822
861
  state.processedFiles = 0;
823
862
  if (state.currentConfigs.length === 1) openGroup("File Generation");
@@ -825,108 +864,82 @@ const githubActionsLogger = defineLogger({
825
864
  console.log(text);
826
865
  });
827
866
  context.on("files:processing:end", () => {
828
- if (logLevel <= LogLevel.silent) return;
867
+ if (logLevel$7 <= logLevel.silent) return;
829
868
  const text = getMessage("Files written successfully");
830
869
  console.log(text);
831
870
  if (state.currentConfigs.length === 1) closeGroup("File Generation");
871
+ showProgressStep();
832
872
  });
833
873
  context.on("file:processing:update", () => {
834
- if (logLevel <= LogLevel.silent) return;
874
+ if (logLevel$7 <= logLevel.silent) return;
835
875
  state.processedFiles++;
836
876
  });
837
- context.on("files:processing:end", () => {
838
- if (logLevel <= LogLevel.silent) return;
839
- showProgressStep();
840
- });
841
877
  context.on("generation:end", (config) => {
842
878
  const text = getMessage(config.name ? `${styleText("blue", "✓")} Generation completed for ${styleText("dim", config.name)}` : `${styleText("blue", "✓")} Generation completed`);
843
879
  console.log(text);
844
880
  });
845
881
  context.on("format:start", () => {
846
- if (logLevel <= LogLevel.silent) return;
882
+ if (logLevel$7 <= logLevel.silent) return;
847
883
  const text = getMessage("Format started");
848
884
  if (state.currentConfigs.length === 1) openGroup("Formatting");
849
885
  console.log(text);
850
886
  });
851
887
  context.on("format:end", () => {
852
- if (logLevel <= LogLevel.silent) return;
888
+ if (logLevel$7 <= logLevel.silent) return;
853
889
  const text = getMessage("Format completed");
854
890
  console.log(text);
855
891
  if (state.currentConfigs.length === 1) closeGroup("Formatting");
856
892
  });
857
893
  context.on("lint:start", () => {
858
- if (logLevel <= LogLevel.silent) return;
894
+ if (logLevel$7 <= logLevel.silent) return;
859
895
  const text = getMessage("Lint started");
860
896
  if (state.currentConfigs.length === 1) openGroup("Linting");
861
897
  console.log(text);
862
898
  });
863
899
  context.on("lint:end", () => {
864
- if (logLevel <= LogLevel.silent) return;
900
+ if (logLevel$7 <= logLevel.silent) return;
865
901
  const text = getMessage("Lint completed");
866
902
  console.log(text);
867
903
  if (state.currentConfigs.length === 1) closeGroup("Linting");
868
904
  });
869
905
  context.on("hook:start", async ({ id, command, args }) => {
870
- const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
906
+ const commandWithArgs = formatCommandWithArgs(command, args);
871
907
  const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`);
872
- if (logLevel > LogLevel.silent) {
908
+ if (logLevel$7 > logLevel.silent) {
873
909
  if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
874
910
  console.log(text);
875
911
  }
876
912
  if (!id) return;
877
- try {
878
- const result = await x(command, [...args ?? []], {
879
- nodeOptions: { detached: true },
880
- throwOnError: true
881
- });
882
- await context.emit("debug", {
883
- date: /* @__PURE__ */ new Date(),
884
- logs: [result.stdout.trimEnd()]
885
- });
886
- if (logLevel > LogLevel.silent) console.log(result.stdout.trimEnd());
887
- await context.emit("hook:end", {
888
- command,
889
- args,
890
- id,
891
- success: true,
892
- error: null
893
- });
894
- } catch (err) {
895
- const error = err;
896
- const stderr = error.output?.stderr ?? "";
897
- const stdout = error.output?.stdout ?? "";
898
- await context.emit("debug", {
899
- date: /* @__PURE__ */ new Date(),
900
- logs: [stdout, stderr].filter(Boolean)
901
- });
902
- if (stderr) console.error(`::error::${stderr}`);
903
- if (stdout) console.log(stdout);
904
- const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
905
- await context.emit("hook:end", {
906
- command,
907
- args,
908
- id,
909
- success: false,
910
- error: errorMessage
911
- });
912
- await context.emit("error", errorMessage);
913
- }
913
+ await runHook({
914
+ id,
915
+ command,
916
+ args,
917
+ commandWithArgs,
918
+ context,
919
+ sink: {
920
+ onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0,
921
+ onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
922
+ }
923
+ });
914
924
  });
915
925
  context.on("hook:end", ({ command, args }) => {
916
- if (logLevel <= LogLevel.silent) return;
917
- const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
926
+ if (logLevel$7 <= logLevel.silent) return;
927
+ const commandWithArgs = formatCommandWithArgs(command, args);
918
928
  const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} completed`);
919
929
  console.log(text);
920
930
  if (state.currentConfigs.length === 1) closeGroup(`Hook ${commandWithArgs}`);
921
931
  });
922
932
  context.on("generation:summary", (config, { status, hrStart, failedPlugins }) => {
923
- const pluginsCount = config.plugins?.length || 0;
933
+ const pluginsCount = config.plugins?.length ?? 0;
924
934
  const successCount = pluginsCount - failedPlugins.size;
925
935
  const duration = formatHrtime(hrStart);
926
936
  if (state.currentConfigs.length > 1) console.log(" ");
927
937
  console.log(status === "success" ? `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ${pluginsCount} total, ${styleText("green", duration)}` : `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total, ${styleText("green", duration)}`);
928
938
  if (state.currentConfigs.length > 1) closeGroup(config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation");
929
939
  });
940
+ context.on("lifecycle:end", () => {
941
+ reset();
942
+ });
930
943
  }
931
944
  });
932
945
  //#endregion
@@ -938,18 +951,12 @@ const githubActionsLogger = defineLogger({
938
951
  const plainLogger = defineLogger({
939
952
  name: "plain",
940
953
  install(context, options) {
941
- const logLevel = options?.logLevel || 3;
954
+ const logLevel$6 = options?.logLevel ?? logLevel.info;
942
955
  function getMessage(message) {
943
- if (logLevel >= LogLevel.verbose) return [`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
944
- hour12: false,
945
- hour: "2-digit",
946
- minute: "2-digit",
947
- second: "2-digit"
948
- })}]`, message].join(" ");
949
- return message;
956
+ return formatMessage(message, logLevel$6);
950
957
  }
951
958
  context.on("info", (message, info) => {
952
- if (logLevel <= LogLevel.silent) return;
959
+ if (logLevel$6 <= logLevel.silent) return;
953
960
  const text = getMessage([
954
961
  "ℹ",
955
962
  message,
@@ -958,28 +965,28 @@ const plainLogger = defineLogger({
958
965
  console.log(text);
959
966
  });
960
967
  context.on("success", (message, info = "") => {
961
- if (logLevel <= LogLevel.silent) return;
968
+ if (logLevel$6 <= logLevel.silent) return;
962
969
  const text = getMessage([
963
970
  "✓",
964
971
  message,
965
- logLevel >= LogLevel.info ? info : void 0
972
+ logLevel$6 >= logLevel.info ? info : void 0
966
973
  ].filter(Boolean).join(" "));
967
974
  console.log(text);
968
975
  });
969
976
  context.on("warn", (message, info) => {
970
- if (logLevel < LogLevel.warn) return;
977
+ if (logLevel$6 < logLevel.warn) return;
971
978
  const text = getMessage([
972
979
  "⚠",
973
980
  message,
974
- logLevel >= LogLevel.info ? info : void 0
981
+ logLevel$6 >= logLevel.info ? info : void 0
975
982
  ].filter(Boolean).join(" "));
976
983
  console.log(text);
977
984
  });
978
985
  context.on("error", (error) => {
979
- const caused = error.cause;
986
+ const caused = toCause(error);
980
987
  const text = getMessage(["✗", error.message].join(" "));
981
988
  console.log(text);
982
- if (logLevel >= LogLevel.debug && error.stack) {
989
+ if (logLevel$6 >= logLevel.debug && error.stack) {
983
990
  const frames = error.stack.split("\n").slice(1, 4);
984
991
  for (const frame of frames) console.log(getMessage(frame.trim()));
985
992
  if (caused?.stack) {
@@ -993,42 +1000,42 @@ const plainLogger = defineLogger({
993
1000
  console.log("Kubb CLI 🧩");
994
1001
  });
995
1002
  context.on("config:start", () => {
996
- if (logLevel <= LogLevel.silent) return;
1003
+ if (logLevel$6 <= logLevel.silent) return;
997
1004
  const text = getMessage("Configuration started");
998
1005
  console.log(text);
999
1006
  });
1000
1007
  context.on("config:end", () => {
1001
- if (logLevel <= LogLevel.silent) return;
1008
+ if (logLevel$6 <= logLevel.silent) return;
1002
1009
  const text = getMessage("Configuration completed");
1003
1010
  console.log(text);
1004
1011
  });
1005
1012
  context.on("generation:start", () => {
1006
- const text = getMessage("Configuration started");
1013
+ const text = getMessage("Generation started");
1007
1014
  console.log(text);
1008
1015
  });
1009
1016
  context.on("plugin:start", (plugin) => {
1010
- if (logLevel <= LogLevel.silent) return;
1017
+ if (logLevel$6 <= logLevel.silent) return;
1011
1018
  const text = getMessage(`Generating ${plugin.name}`);
1012
1019
  console.log(text);
1013
1020
  });
1014
1021
  context.on("plugin:end", (plugin, { duration, success }) => {
1015
- if (logLevel <= LogLevel.silent) return;
1022
+ if (logLevel$6 <= logLevel.silent) return;
1016
1023
  const durationStr = formatMs(duration);
1017
1024
  const text = getMessage(success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`);
1018
1025
  console.log(text);
1019
1026
  });
1020
1027
  context.on("files:processing:start", (files) => {
1021
- if (logLevel <= LogLevel.silent) return;
1028
+ if (logLevel$6 <= logLevel.silent) return;
1022
1029
  const text = getMessage(`Writing ${files.length} files`);
1023
1030
  console.log(text);
1024
1031
  });
1025
1032
  context.on("file:processing:update", ({ file, config }) => {
1026
- if (logLevel <= LogLevel.silent) return;
1033
+ if (logLevel$6 <= logLevel.silent) return;
1027
1034
  const text = getMessage(`Writing ${relative(config.root, file.path)}`);
1028
1035
  console.log(text);
1029
1036
  });
1030
1037
  context.on("files:processing:end", () => {
1031
- if (logLevel <= LogLevel.silent) return;
1038
+ if (logLevel$6 <= logLevel.silent) return;
1032
1039
  const text = getMessage("Files written successfully");
1033
1040
  console.log(text);
1034
1041
  });
@@ -1037,71 +1044,45 @@ const plainLogger = defineLogger({
1037
1044
  console.log(text);
1038
1045
  });
1039
1046
  context.on("format:start", () => {
1040
- if (logLevel <= LogLevel.silent) return;
1047
+ if (logLevel$6 <= logLevel.silent) return;
1041
1048
  const text = getMessage("Format started");
1042
1049
  console.log(text);
1043
1050
  });
1044
1051
  context.on("format:end", () => {
1045
- if (logLevel <= LogLevel.silent) return;
1052
+ if (logLevel$6 <= logLevel.silent) return;
1046
1053
  const text = getMessage("Format completed");
1047
1054
  console.log(text);
1048
1055
  });
1049
1056
  context.on("lint:start", () => {
1050
- if (logLevel <= LogLevel.silent) return;
1057
+ if (logLevel$6 <= logLevel.silent) return;
1051
1058
  const text = getMessage("Lint started");
1052
1059
  console.log(text);
1053
1060
  });
1054
1061
  context.on("lint:end", () => {
1055
- if (logLevel <= LogLevel.silent) return;
1062
+ if (logLevel$6 <= logLevel.silent) return;
1056
1063
  const text = getMessage("Lint completed");
1057
1064
  console.log(text);
1058
1065
  });
1059
1066
  context.on("hook:start", async ({ id, command, args }) => {
1060
- const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
1067
+ const commandWithArgs = formatCommandWithArgs(command, args);
1061
1068
  const text = getMessage(`Hook ${commandWithArgs} started`);
1062
- if (logLevel > LogLevel.silent) console.log(text);
1069
+ if (logLevel$6 > logLevel.silent) console.log(text);
1063
1070
  if (!id) return;
1064
- try {
1065
- const result = await x(command, [...args ?? []], {
1066
- nodeOptions: { detached: true },
1067
- throwOnError: true
1068
- });
1069
- await context.emit("debug", {
1070
- date: /* @__PURE__ */ new Date(),
1071
- logs: [result.stdout.trimEnd()]
1072
- });
1073
- if (logLevel > LogLevel.silent) console.log(result.stdout.trimEnd());
1074
- await context.emit("hook:end", {
1075
- command,
1076
- args,
1077
- id,
1078
- success: true,
1079
- error: null
1080
- });
1081
- } catch (err) {
1082
- const error = err;
1083
- const stderr = error.output?.stderr ?? "";
1084
- const stdout = error.output?.stdout ?? "";
1085
- await context.emit("debug", {
1086
- date: /* @__PURE__ */ new Date(),
1087
- logs: [stdout, stderr].filter(Boolean)
1088
- });
1089
- if (stderr) console.error(stderr);
1090
- if (stdout) console.log(stdout);
1091
- const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
1092
- await context.emit("hook:end", {
1093
- command,
1094
- args,
1095
- id,
1096
- success: false,
1097
- error: errorMessage
1098
- });
1099
- await context.emit("error", errorMessage);
1100
- }
1071
+ await runHook({
1072
+ id,
1073
+ command,
1074
+ args,
1075
+ commandWithArgs,
1076
+ context,
1077
+ sink: {
1078
+ onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0,
1079
+ onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0
1080
+ }
1081
+ });
1101
1082
  });
1102
1083
  context.on("hook:end", ({ command, args }) => {
1103
- if (logLevel <= LogLevel.silent) return;
1104
- const text = getMessage(`Hook ${args?.length ? `${command} ${args.join(" ")}` : command} completed`);
1084
+ if (logLevel$6 <= logLevel.silent) return;
1085
+ const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} completed`);
1105
1086
  console.log(text);
1106
1087
  });
1107
1088
  context.on("generation:summary", (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
@@ -1111,16 +1092,52 @@ const plainLogger = defineLogger({
1111
1092
  config,
1112
1093
  status,
1113
1094
  hrStart,
1114
- pluginTimings: logLevel >= LogLevel.verbose ? pluginTimings : void 0
1095
+ pluginTimings: logLevel$6 >= logLevel.verbose ? pluginTimings : void 0
1115
1096
  });
1116
- console.log("---------------------------");
1097
+ console.log(SUMMARY_SEPARATOR);
1117
1098
  console.log(summary.join("\n"));
1118
- console.log("---------------------------");
1099
+ console.log(SUMMARY_SEPARATOR);
1119
1100
  });
1120
1101
  }
1121
1102
  });
1122
1103
  //#endregion
1123
1104
  //#region src/loggers/utils.ts
1105
+ /**
1106
+ * Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose.
1107
+ * Shared across all logger adapters to avoid duplication.
1108
+ */
1109
+ function formatMessage(message, logLevel$4) {
1110
+ if (logLevel$4 >= logLevel.verbose) return `${styleText("dim", `[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
1111
+ hour12: false,
1112
+ hour: "2-digit",
1113
+ minute: "2-digit",
1114
+ second: "2-digit"
1115
+ })}]`)} ${message}`;
1116
+ return message;
1117
+ }
1118
+ /**
1119
+ * Build the progress summary line shared by clack and GitHub Actions loggers.
1120
+ * Returns null when there is nothing to display.
1121
+ */
1122
+ function buildProgressLine(state) {
1123
+ const parts = [];
1124
+ const duration = formatHrtime(state.hrStart);
1125
+ if (state.totalPlugins > 0) {
1126
+ 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}`;
1127
+ parts.push(pluginStr);
1128
+ }
1129
+ if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`);
1130
+ if (parts.length === 0) return null;
1131
+ parts.push(`${styleText("green", duration)} elapsed`);
1132
+ return parts.join(styleText("dim", " | "));
1133
+ }
1134
+ /**
1135
+ * Join a command and its optional args into a single display string.
1136
+ * e.g. ("prettier", ["--write", "."]) → "prettier --write ."
1137
+ */
1138
+ function formatCommandWithArgs(command, args) {
1139
+ return args?.length ? `${command} ${args.join(" ")}` : command;
1140
+ }
1124
1141
  function detectLogger() {
1125
1142
  if (isGitHubActions()) return "github-actions";
1126
1143
  if (canUseTTY()) return "clack";
@@ -1131,12 +1148,12 @@ const logMapper = {
1131
1148
  plain: plainLogger,
1132
1149
  "github-actions": githubActionsLogger
1133
1150
  };
1134
- async function setupLogger(context, { logLevel }) {
1151
+ async function setupLogger(context, { logLevel: logLevel$5 }) {
1135
1152
  const type = detectLogger();
1136
1153
  const logger = logMapper[type];
1137
1154
  if (!logger) throw new Error(`Unknown adapter type: ${type}`);
1138
- const cleanup = await logger.install(context, { logLevel });
1139
- if (logLevel >= LogLevel.debug) await fileSystemLogger.install(context, { logLevel });
1155
+ const cleanup = await logger.install(context, { logLevel: logLevel$5 });
1156
+ if (logLevel$5 >= logLevel.debug) await fileSystemLogger.install(context, { logLevel: logLevel$5 });
1140
1157
  return cleanup;
1141
1158
  }
1142
1159
  //#endregion
@@ -1147,20 +1164,141 @@ async function executeHooks({ hooks, events }) {
1147
1164
  const [cmd, ...args] = tokenize(command);
1148
1165
  if (!cmd) continue;
1149
1166
  const hookId = createHash("sha256").update(command).digest("hex");
1167
+ const hookEndPromise = new Promise((resolve, reject) => {
1168
+ const handler = ({ id, success, error }) => {
1169
+ if (id !== hookId) return;
1170
+ events.off("hook:end", handler);
1171
+ if (!success) {
1172
+ reject(error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`));
1173
+ return;
1174
+ }
1175
+ events.emit("success", `${styleText("dim", command)} successfully executed`).then(resolve).catch(reject);
1176
+ };
1177
+ events.on("hook:end", handler);
1178
+ });
1150
1179
  await events.emit("hook:start", {
1151
1180
  id: hookId,
1152
1181
  command: cmd,
1153
1182
  args
1154
1183
  });
1155
- await events.onOnce("hook:end", async ({ success, error }) => {
1156
- if (!success) throw error;
1157
- await events.emit("success", `${styleText("dim", command)} successfully executed`);
1158
- });
1184
+ await hookEndPromise;
1159
1185
  }
1160
1186
  }
1161
1187
  //#endregion
1188
+ //#region src/utils/getCosmiConfig.ts
1189
+ const jiti = createJiti(import.meta.url, {
1190
+ jsx: {
1191
+ runtime: "automatic",
1192
+ importSource: "@kubb/react-fabric"
1193
+ },
1194
+ sourceMaps: true,
1195
+ interopDefault: true
1196
+ });
1197
+ const tsLoader = async (configFile) => {
1198
+ return await jiti.import(configFile, { default: true });
1199
+ };
1200
+ async function getCosmiConfig(moduleName, config) {
1201
+ let result;
1202
+ const searchPlaces = [
1203
+ "package.json",
1204
+ `.${moduleName}rc`,
1205
+ `.${moduleName}rc.json`,
1206
+ `.${moduleName}rc.yaml`,
1207
+ `.${moduleName}rc.yml`,
1208
+ `.${moduleName}rc.ts`,
1209
+ `.${moduleName}rc.js`,
1210
+ `.${moduleName}rc.mjs`,
1211
+ `.${moduleName}rc.cjs`,
1212
+ `${moduleName}.config.ts`,
1213
+ `${moduleName}.config.js`,
1214
+ `${moduleName}.config.mjs`,
1215
+ `${moduleName}.config.cjs`
1216
+ ];
1217
+ const explorer = cosmiconfig(moduleName, {
1218
+ cache: false,
1219
+ searchPlaces: [
1220
+ ...searchPlaces.map((searchPlace) => {
1221
+ return `.config/${searchPlace}`;
1222
+ }),
1223
+ ...searchPlaces.map((searchPlace) => {
1224
+ return `configs/${searchPlace}`;
1225
+ }),
1226
+ ...searchPlaces
1227
+ ],
1228
+ loaders: { ".ts": tsLoader }
1229
+ });
1230
+ try {
1231
+ result = config ? await explorer.load(config) : await explorer.search();
1232
+ } catch (error) {
1233
+ throw new Error("Config failed loading", { cause: error });
1234
+ }
1235
+ if (result?.isEmpty || !result || !result.config) throw new Error("Config not defined, create a kubb.config.js or pass through your config with the option --config");
1236
+ return result;
1237
+ }
1238
+ //#endregion
1239
+ //#region src/utils/watcher.ts
1240
+ async function startWatcher(path, cb) {
1241
+ const { watch } = await import("chokidar");
1242
+ watch(path, {
1243
+ ignorePermissionErrors: true,
1244
+ ignored: WATCHER_IGNORED_PATHS
1245
+ }).on("all", async (type, file) => {
1246
+ console.log(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
1247
+ try {
1248
+ await cb(path);
1249
+ } catch (_e) {
1250
+ console.log(styleText("red", "Watcher failed"));
1251
+ }
1252
+ });
1253
+ }
1254
+ //#endregion
1162
1255
  //#region src/runners/generate.ts
1163
- async function generate({ input, config: userConfig, events, logLevel }) {
1256
+ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, events, onStart, onEnd }) {
1257
+ await onStart();
1258
+ let resolvedTool = toolValue;
1259
+ if (resolvedTool === "auto") {
1260
+ const detected = await detect();
1261
+ if (!detected) await events.emit("warn", noToolMessage);
1262
+ else {
1263
+ resolvedTool = detected;
1264
+ await events.emit("info", `Auto-detected ${toolLabel}: ${styleText("dim", resolvedTool)}`);
1265
+ }
1266
+ }
1267
+ if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) {
1268
+ const toolConfig = toolMap[resolvedTool];
1269
+ try {
1270
+ const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1271
+ const hookEndPromise = new Promise((resolve, reject) => {
1272
+ const handler = ({ id, success, error }) => {
1273
+ if (id !== hookId) return;
1274
+ events.off("hook:end", handler);
1275
+ if (!success) {
1276
+ reject(error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`));
1277
+ return;
1278
+ }
1279
+ events.emit("success", [
1280
+ `${successPrefix} with ${styleText("dim", resolvedTool)}`,
1281
+ logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
1282
+ "successfully"
1283
+ ].filter(Boolean).join(" ")).then(resolve).catch(reject);
1284
+ };
1285
+ events.on("hook:end", handler);
1286
+ });
1287
+ await events.emit("hook:start", {
1288
+ id: hookId,
1289
+ command: toolConfig.command,
1290
+ args: toolConfig.args(outputPath)
1291
+ });
1292
+ await hookEndPromise;
1293
+ } catch (caughtError) {
1294
+ const err = new Error(toolConfig.errorMessage);
1295
+ err.cause = caughtError;
1296
+ await events.emit("error", err);
1297
+ }
1298
+ }
1299
+ await onEnd();
1300
+ }
1301
+ async function generate({ input, config: userConfig, events, logLevel: logLevel$2 }) {
1164
1302
  const inputPath = input ?? ("path" in userConfig.input ? userConfig.input.path : void 0);
1165
1303
  const hrStart = process$1.hrtime();
1166
1304
  const config = {
@@ -1196,16 +1334,15 @@ async function generate({ input, config: userConfig, events, logLevel }) {
1196
1334
  });
1197
1335
  await events.emit("info", "Load summary");
1198
1336
  if (failedPlugins.size > 0 || error) {
1199
- [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean).forEach((err) => {
1200
- events.emit("error", err);
1201
- });
1337
+ const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean);
1338
+ for (const err of allErrors) await events.emit("error", err);
1202
1339
  await events.emit("generation:end", config, files, sources);
1203
1340
  await events.emit("generation:summary", config, {
1204
1341
  failedPlugins,
1205
1342
  filesCreated: files.length,
1206
1343
  status: "failed",
1207
1344
  hrStart,
1208
- pluginTimings: logLevel >= LogLevel.verbose ? pluginTimings : void 0
1345
+ pluginTimings: logLevel$2 >= logLevel.verbose ? pluginTimings : void 0
1209
1346
  });
1210
1347
  await sendTelemetry(buildTelemetryEvent({
1211
1348
  command: "generate",
@@ -1222,80 +1359,35 @@ async function generate({ input, config: userConfig, events, logLevel }) {
1222
1359
  }
1223
1360
  await events.emit("success", "Generation successfully", inputPath);
1224
1361
  await events.emit("generation:end", config, files, sources);
1225
- if (config.output.format) {
1226
- await events.emit("format:start");
1227
- let formatter = config.output.format;
1228
- if (formatter === "auto") {
1229
- const detectedFormatter = await detectFormatter();
1230
- if (!detectedFormatter) await events.emit("warn", "No formatter found (biome, prettier, or oxfmt). Skipping formatting.");
1231
- else {
1232
- formatter = detectedFormatter;
1233
- await events.emit("info", `Auto-detected formatter: ${styleText("dim", formatter)}`);
1234
- }
1235
- }
1236
- if (formatter && formatter !== "auto" && formatter in formatters) {
1237
- const formatterConfig = formatters[formatter];
1238
- const outputPath = path.resolve(config.root, config.output.path);
1239
- try {
1240
- const hookId = createHash("sha256").update([config.name, formatter].filter(Boolean).join("-")).digest("hex");
1241
- await events.emit("hook:start", {
1242
- id: hookId,
1243
- command: formatterConfig.command,
1244
- args: formatterConfig.args(outputPath)
1245
- });
1246
- await events.onOnce("hook:end", async ({ success, error }) => {
1247
- if (!success) throw error;
1248
- await events.emit("success", [
1249
- `Formatting with ${styleText("dim", formatter)}`,
1250
- logLevel >= LogLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
1251
- "successfully"
1252
- ].filter(Boolean).join(" "));
1253
- });
1254
- } catch (caughtError) {
1255
- const error = new Error(formatterConfig.errorMessage);
1256
- error.cause = caughtError;
1257
- await events.emit("error", error);
1258
- }
1259
- }
1260
- await events.emit("format:end");
1261
- }
1262
- if (config.output.lint) {
1263
- await events.emit("lint:start");
1264
- let linter = config.output.lint;
1265
- if (linter === "auto") {
1266
- const detectedLinter = await detectLinter();
1267
- if (!detectedLinter) await events.emit("warn", "No linter found (biome, oxlint, or eslint). Skipping linting.");
1268
- else {
1269
- linter = detectedLinter;
1270
- await events.emit("info", `Auto-detected linter: ${styleText("dim", linter)}`);
1271
- }
1272
- }
1273
- if (linter && linter !== "auto" && linter in linters) {
1274
- const linterConfig = linters[linter];
1275
- const outputPath = path.resolve(config.root, config.output.path);
1276
- try {
1277
- const hookId = createHash("sha256").update([config.name, linter].filter(Boolean).join("-")).digest("hex");
1278
- await events.emit("hook:start", {
1279
- id: hookId,
1280
- command: linterConfig.command,
1281
- args: linterConfig.args(outputPath)
1282
- });
1283
- await events.onOnce("hook:end", async ({ success, error }) => {
1284
- if (!success) throw error;
1285
- await events.emit("success", [
1286
- `Linting with ${styleText("dim", linter)}`,
1287
- logLevel >= LogLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
1288
- "successfully"
1289
- ].filter(Boolean).join(" "));
1290
- });
1291
- } catch (caughtError) {
1292
- const error = new Error(linterConfig.errorMessage);
1293
- error.cause = caughtError;
1294
- await events.emit("error", error);
1295
- }
1296
- }
1297
- await events.emit("lint:end");
1298
- }
1362
+ const outputPath = path.resolve(config.root, config.output.path);
1363
+ if (config.output.format) await runToolPass({
1364
+ toolValue: config.output.format,
1365
+ detect: detectFormatter,
1366
+ toolMap: formatters,
1367
+ toolLabel: "formatter",
1368
+ successPrefix: "Formatting",
1369
+ noToolMessage: "No formatter found (biome, prettier, or oxfmt). Skipping formatting.",
1370
+ configName: config.name,
1371
+ outputPath,
1372
+ logLevel: logLevel$2,
1373
+ events,
1374
+ onStart: () => events.emit("format:start"),
1375
+ onEnd: () => events.emit("format:end")
1376
+ });
1377
+ if (config.output.lint) await runToolPass({
1378
+ toolValue: config.output.lint,
1379
+ detect: detectLinter,
1380
+ toolMap: linters,
1381
+ toolLabel: "linter",
1382
+ successPrefix: "Linting",
1383
+ noToolMessage: "No linter found (biome, oxlint, or eslint). Skipping linting.",
1384
+ configName: config.name,
1385
+ outputPath,
1386
+ logLevel: logLevel$2,
1387
+ events,
1388
+ onStart: () => events.emit("lint:start"),
1389
+ onEnd: () => events.emit("lint:end")
1390
+ });
1299
1391
  if (config.hooks) {
1300
1392
  await events.emit("hooks:start");
1301
1393
  await executeHooks({
@@ -1304,11 +1396,10 @@ async function generate({ input, config: userConfig, events, logLevel }) {
1304
1396
  });
1305
1397
  await events.emit("hooks:end");
1306
1398
  }
1307
- const generationStatus = failedPlugins.size > 0 || error ? "failed" : "success";
1308
1399
  await events.emit("generation:summary", config, {
1309
1400
  failedPlugins,
1310
1401
  filesCreated: files.length,
1311
- status: generationStatus,
1402
+ status: "success",
1312
1403
  hrStart,
1313
1404
  pluginTimings
1314
1405
  });
@@ -1321,183 +1412,59 @@ async function generate({ input, config: userConfig, events, logLevel }) {
1321
1412
  })),
1322
1413
  hrStart,
1323
1414
  filesCreated: files.length,
1324
- status: generationStatus
1415
+ status: "success"
1325
1416
  }));
1326
1417
  }
1327
- //#endregion
1328
- //#region src/utils/getCosmiConfig.ts
1329
- const tsLoader = async (configFile) => {
1330
- return await createJiti(import.meta.url, {
1331
- jsx: {
1332
- runtime: "automatic",
1333
- importSource: "@kubb/react-fabric"
1334
- },
1335
- sourceMaps: true,
1336
- interopDefault: true
1337
- }).import(configFile, { default: true });
1338
- };
1339
- async function getCosmiConfig(moduleName, config) {
1340
- let result;
1341
- const searchPlaces = [
1342
- "package.json",
1343
- `.${moduleName}rc`,
1344
- `.${moduleName}rc.json`,
1345
- `.${moduleName}rc.yaml`,
1346
- `.${moduleName}rc.yml`,
1347
- `.${moduleName}rc.ts`,
1348
- `.${moduleName}rc.js`,
1349
- `.${moduleName}rc.mjs`,
1350
- `.${moduleName}rc.cjs`,
1351
- `${moduleName}.config.ts`,
1352
- `${moduleName}.config.js`,
1353
- `${moduleName}.config.mjs`,
1354
- `${moduleName}.config.cjs`
1355
- ];
1356
- const explorer = cosmiconfig(moduleName, {
1357
- cache: false,
1358
- searchPlaces: [
1359
- ...searchPlaces.map((searchPlace) => {
1360
- return `.config/${searchPlace}`;
1361
- }),
1362
- ...searchPlaces.map((searchPlace) => {
1363
- return `configs/${searchPlace}`;
1364
- }),
1365
- ...searchPlaces
1366
- ],
1367
- loaders: { ".ts": tsLoader }
1368
- });
1369
- try {
1370
- result = config ? await explorer.load(config) : await explorer.search();
1371
- } catch (error) {
1372
- throw new Error("Config failed loading", { cause: error });
1373
- }
1374
- if (result?.isEmpty || !result || !result.config) throw new Error("Config not defined, create a kubb.config.js or pass through your config with the option --config");
1375
- return result;
1376
- }
1377
- //#endregion
1378
- //#region src/utils/watcher.ts
1379
- async function startWatcher(path, cb) {
1380
- const { watch } = await import("chokidar");
1381
- watch(path, {
1382
- ignorePermissionErrors: true,
1383
- ignored: "**/{.git,node_modules}/**"
1384
- }).on("all", async (type, file) => {
1385
- console.log(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
1418
+ async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) {
1419
+ const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info;
1420
+ const events = new AsyncEventEmitter();
1421
+ const promiseManager = new PromiseManager();
1422
+ await setupLogger(events, { logLevel: logLevel$3 });
1423
+ await executeIfOnline(async () => {
1386
1424
  try {
1387
- await cb(path);
1388
- } catch (_e) {
1389
- console.log(styleText("red", "Watcher failed"));
1390
- }
1425
+ const latestVersion = (await (await fetch(KUBB_NPM_PACKAGE_URL)).json()).version;
1426
+ if (latestVersion && version < latestVersion) await events.emit("version:new", version, latestVersion);
1427
+ } catch {}
1391
1428
  });
1392
- }
1393
- //#endregion
1394
- //#region src/commands/generate.ts
1395
- const command = defineCommand({
1396
- meta: {
1397
- name: "generate",
1398
- description: "[input] Generate files based on a 'kubb.config.ts' file"
1399
- },
1400
- args: {
1401
- config: {
1402
- type: "string",
1403
- description: "Path to the Kubb config",
1404
- alias: "c"
1405
- },
1406
- logLevel: {
1407
- type: "string",
1408
- description: "Info, silent, verbose or debug",
1409
- alias: "l",
1410
- default: "info",
1411
- valueHint: "silent|info|verbose|debug"
1412
- },
1413
- watch: {
1414
- type: "boolean",
1415
- description: "Watch mode based on the input file",
1416
- alias: "w",
1417
- default: false
1418
- },
1419
- debug: {
1420
- type: "boolean",
1421
- description: "Override logLevel to debug",
1422
- alias: "d",
1423
- default: false
1424
- },
1425
- verbose: {
1426
- type: "boolean",
1427
- description: "Override logLevel to verbose",
1428
- alias: "v",
1429
- default: false
1430
- },
1431
- silent: {
1432
- type: "boolean",
1433
- description: "Override logLevel to silent",
1434
- alias: "s",
1435
- default: false
1436
- },
1437
- help: {
1438
- type: "boolean",
1439
- description: "Show help",
1440
- alias: "h",
1441
- default: false
1442
- }
1443
- },
1444
- async run(commandContext) {
1445
- const { args } = commandContext;
1446
- const input = args._[0];
1447
- const events = new AsyncEventEmitter();
1448
- const promiseManager = new PromiseManager();
1449
- if (args.help) return showUsage(command);
1450
- if (args.debug) args.logLevel = "debug";
1451
- if (args.verbose) args.logLevel = "verbose";
1452
- if (args.silent) args.logLevel = "silent";
1453
- const logLevel = LogLevel[args.logLevel] || 3;
1454
- await setupLogger(events, { logLevel });
1455
- await executeIfOnline(async () => {
1456
- try {
1457
- const latestVersion = (await (await fetch("https://registry.npmjs.org/@kubb/cli/latest")).json()).version;
1458
- if (latestVersion && version < latestVersion) await events.emit("version:new", version, latestVersion);
1459
- } catch {}
1460
- });
1461
- try {
1462
- const result = await getCosmiConfig("kubb", args.config);
1463
- const configs = await getConfigs(result.config, args);
1464
- await events.emit("config:start");
1465
- await events.emit("info", "Config loaded", path.relative(process$2.cwd(), result.filepath));
1466
- await events.emit("success", "Config loaded successfully", path.relative(process$2.cwd(), result.filepath));
1467
- await events.emit("config:end", configs);
1468
- await events.emit("lifecycle:start", version);
1469
- const promises = configs.map((config) => {
1470
- return async () => {
1471
- if (isInputPath(config) && args.watch) {
1472
- await startWatcher([input || config.input.path], async (paths) => {
1473
- events.removeAll();
1474
- await generate({
1475
- input,
1476
- config,
1477
- logLevel,
1478
- events
1479
- });
1480
- clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`));
1429
+ try {
1430
+ const result = await getCosmiConfig("kubb", configPath);
1431
+ const configs = await getConfigs(result.config, { input });
1432
+ await events.emit("config:start");
1433
+ await events.emit("info", "Config loaded", path.relative(process$1.cwd(), result.filepath));
1434
+ await events.emit("success", "Config loaded successfully", path.relative(process$1.cwd(), result.filepath));
1435
+ await events.emit("config:end", configs);
1436
+ await events.emit("lifecycle:start", version);
1437
+ const promises = configs.map((config) => {
1438
+ return async () => {
1439
+ if (isInputPath(config) && watch) {
1440
+ await startWatcher([input || config.input.path], async (paths) => {
1441
+ events.removeAll();
1442
+ await generate({
1443
+ input,
1444
+ config,
1445
+ logLevel: logLevel$3,
1446
+ events
1481
1447
  });
1482
- return;
1483
- }
1484
- await generate({
1485
- input,
1486
- config,
1487
- logLevel,
1488
- events
1448
+ clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`));
1489
1449
  });
1490
- };
1491
- });
1492
- await promiseManager.run("seq", promises);
1493
- await events.emit("lifecycle:end");
1494
- } catch (error) {
1495
- await events.emit("error", error);
1496
- process$2.exit(1);
1497
- }
1450
+ return;
1451
+ }
1452
+ await generate({
1453
+ input,
1454
+ config,
1455
+ logLevel: logLevel$3,
1456
+ events
1457
+ });
1458
+ };
1459
+ });
1460
+ await promiseManager.run("seq", promises);
1461
+ await events.emit("lifecycle:end");
1462
+ } catch (error) {
1463
+ await events.emit("error", toError(error));
1464
+ process$1.exit(1);
1498
1465
  }
1499
- });
1466
+ }
1500
1467
  //#endregion
1501
- export { command as default };
1468
+ export { runGenerateCommand };
1502
1469
 
1503
- //# sourceMappingURL=generate-CpWtSc45.js.map
1470
+ //# sourceMappingURL=generate-CAsV9wSx.js.map