@kubb/cli 5.0.0-beta.2 → 5.0.0-beta.21

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 (151) hide show
  1. package/README.md +177 -26
  2. package/dist/agent-B1y251-b.cjs +70 -0
  3. package/dist/agent-B1y251-b.cjs.map +1 -0
  4. package/dist/agent-jGZu4zRF.js +68 -0
  5. package/dist/agent-jGZu4zRF.js.map +1 -0
  6. package/dist/{chunk--u3MIqq1.js → chunk-BvFE5Tac.js} +1 -0
  7. package/dist/constants-B2JTeRBb.js +42 -0
  8. package/dist/constants-B2JTeRBb.js.map +1 -0
  9. package/dist/constants-BINTA5VZ.cjs +77 -0
  10. package/dist/constants-BINTA5VZ.cjs.map +1 -0
  11. package/dist/constants-BYGmiFs0.cjs +139 -0
  12. package/dist/constants-BYGmiFs0.cjs.map +1 -0
  13. package/dist/constants-DSJ-Xrbv.js +116 -0
  14. package/dist/constants-DSJ-Xrbv.js.map +1 -0
  15. package/dist/define-Bdn8j5VM.cjs.map +1 -1
  16. package/dist/{define-Ctii4bel.js → define-m_fp-Aqm.js} +2 -2
  17. package/dist/{define-Ctii4bel.js.map → define-m_fp-Aqm.js.map} +1 -1
  18. package/dist/{errors-CjPmyZHy.js → errors-CINO1EIv.js} +2 -2
  19. package/dist/{errors-CjPmyZHy.js.map → errors-CINO1EIv.js.map} +1 -1
  20. package/dist/errors-CLCjoSg0.cjs.map +1 -1
  21. package/dist/{generate-DL_7a7Wd.cjs → generate-CszBbEx_.cjs} +10 -4
  22. package/dist/generate-CszBbEx_.cjs.map +1 -0
  23. package/dist/{generate-B3PZ6Dp-.js → generate-Dqk3rinP.js} +12 -6
  24. package/dist/generate-Dqk3rinP.js.map +1 -0
  25. package/dist/index.cjs +20 -11
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +22 -13
  29. package/dist/index.js.map +1 -1
  30. package/dist/init-BSfLyes_.js +53 -0
  31. package/dist/init-BSfLyes_.js.map +1 -0
  32. package/dist/init-JrYOUBes.cjs +53 -0
  33. package/dist/init-JrYOUBes.cjs.map +1 -0
  34. package/dist/mcp-BiLUSMgD.js +39 -0
  35. package/dist/mcp-BiLUSMgD.js.map +1 -0
  36. package/dist/mcp-DY_TKMoS.cjs +39 -0
  37. package/dist/mcp-DY_TKMoS.cjs.map +1 -0
  38. package/dist/package-C_LGzz8A.js +6 -0
  39. package/dist/package-C_LGzz8A.js.map +1 -0
  40. package/dist/{package-D8wlStAg.cjs → package-CyNXMTr8.cjs} +2 -2
  41. package/dist/package-CyNXMTr8.cjs.map +1 -0
  42. package/dist/run-B11-UaUs.cjs +33 -0
  43. package/dist/run-B11-UaUs.cjs.map +1 -0
  44. package/dist/{init-eNRlotJK.js → run-BNqMQygv.js} +107 -149
  45. package/dist/run-BNqMQygv.js.map +1 -0
  46. package/dist/{init-CZ5Xq2Hd.cjs → run-BnGfi7Cp.cjs} +105 -147
  47. package/dist/run-BnGfi7Cp.cjs.map +1 -0
  48. package/dist/{generate-Dt_r0ELY.js → run-BryUpjjc.js} +484 -410
  49. package/dist/run-BryUpjjc.js.map +1 -0
  50. package/dist/{agent-Ev5hU5hH.js → run-BzpYYOQs.js} +53 -44
  51. package/dist/run-BzpYYOQs.js.map +1 -0
  52. package/dist/run-CCZ24VKk.js +51 -0
  53. package/dist/run-CCZ24VKk.js.map +1 -0
  54. package/dist/run-CQbj3ley.cjs +52 -0
  55. package/dist/run-CQbj3ley.cjs.map +1 -0
  56. package/dist/{generate-B3jl4ukb.cjs → run-CmiuJkLG.cjs} +481 -407
  57. package/dist/run-CmiuJkLG.cjs.map +1 -0
  58. package/dist/{agent-B_pirbeB.cjs → run-DwdAwnLG.cjs} +51 -42
  59. package/dist/run-DwdAwnLG.cjs.map +1 -0
  60. package/dist/run-PSA9X7ci.js +32 -0
  61. package/dist/run-PSA9X7ci.js.map +1 -0
  62. package/dist/shell-475fQKaX.cjs.map +1 -1
  63. package/dist/{shell-DLzN4fRo.js → shell-CN6DNqeC.js} +2 -2
  64. package/dist/{shell-DLzN4fRo.js.map → shell-CN6DNqeC.js.map} +1 -1
  65. package/dist/{telemetry-DN95_2pF.cjs → telemetry-B2iWkY5e.cjs} +5 -7
  66. package/dist/telemetry-B2iWkY5e.cjs.map +1 -0
  67. package/dist/{telemetry-LgT_sdPe.js → telemetry-BkektVz6.js} +6 -8
  68. package/dist/telemetry-BkektVz6.js.map +1 -0
  69. package/dist/validate-8VIogDlj.cjs +26 -0
  70. package/dist/validate-8VIogDlj.cjs.map +1 -0
  71. package/dist/validate-KufVWuQ1.js +26 -0
  72. package/dist/validate-KufVWuQ1.js.map +1 -0
  73. package/package.json +23 -15
  74. package/src/commands/agent/start.ts +10 -7
  75. package/src/commands/agent.ts +3 -1
  76. package/src/commands/generate.ts +5 -3
  77. package/src/commands/init.ts +34 -3
  78. package/src/commands/mcp.ts +28 -4
  79. package/src/commands/validate.ts +6 -4
  80. package/src/constants.ts +2 -58
  81. package/src/index.ts +5 -3
  82. package/src/loggers/clackLogger.ts +72 -81
  83. package/src/loggers/fileSystemLogger.ts +26 -13
  84. package/src/loggers/githubActionsLogger.ts +74 -28
  85. package/src/loggers/plainLogger.ts +55 -30
  86. package/src/loggers/types.ts +6 -0
  87. package/src/loggers/utils.ts +158 -9
  88. package/src/runners/agent/run.ts +113 -0
  89. package/src/runners/agent/utils.ts +98 -0
  90. package/src/runners/generate/run.ts +316 -0
  91. package/src/runners/generate/utils.ts +216 -0
  92. package/src/runners/init/run.ts +212 -0
  93. package/src/{utils/packageManager.ts → runners/init/utils.ts} +10 -0
  94. package/src/runners/mcp/run.ts +37 -0
  95. package/src/runners/validate/run.ts +63 -0
  96. package/src/{utils/telemetry.ts → telemetry.ts} +12 -5
  97. package/dist/agent-0Nk--lcr.cjs +0 -58
  98. package/dist/agent-0Nk--lcr.cjs.map +0 -1
  99. package/dist/agent-B_pirbeB.cjs.map +0 -1
  100. package/dist/agent-DKeVuiUC.js +0 -56
  101. package/dist/agent-DKeVuiUC.js.map +0 -1
  102. package/dist/agent-Ev5hU5hH.js.map +0 -1
  103. package/dist/constants-CnDXa1R6.cjs +0 -148
  104. package/dist/constants-CnDXa1R6.cjs.map +0 -1
  105. package/dist/constants-aL3CP_Wq.js +0 -95
  106. package/dist/constants-aL3CP_Wq.js.map +0 -1
  107. package/dist/generate-B3PZ6Dp-.js.map +0 -1
  108. package/dist/generate-B3jl4ukb.cjs.map +0 -1
  109. package/dist/generate-DL_7a7Wd.cjs.map +0 -1
  110. package/dist/generate-Dt_r0ELY.js.map +0 -1
  111. package/dist/init-Bj94Nvt8.js +0 -25
  112. package/dist/init-Bj94Nvt8.js.map +0 -1
  113. package/dist/init-CZ5Xq2Hd.cjs.map +0 -1
  114. package/dist/init-CyN1oyTF.cjs +0 -25
  115. package/dist/init-CyN1oyTF.cjs.map +0 -1
  116. package/dist/init-eNRlotJK.js.map +0 -1
  117. package/dist/mcp-BzW703d7.js +0 -16
  118. package/dist/mcp-BzW703d7.js.map +0 -1
  119. package/dist/mcp-CLcDV4Jm.cjs +0 -41
  120. package/dist/mcp-CLcDV4Jm.cjs.map +0 -1
  121. package/dist/mcp-D7EIR9fR.js +0 -40
  122. package/dist/mcp-D7EIR9fR.js.map +0 -1
  123. package/dist/mcp-ZY-ONTOp.cjs +0 -16
  124. package/dist/mcp-ZY-ONTOp.cjs.map +0 -1
  125. package/dist/package-D8wlStAg.cjs.map +0 -1
  126. package/dist/package-Yo-9_m5C.js +0 -6
  127. package/dist/package-Yo-9_m5C.js.map +0 -1
  128. package/dist/telemetry-DN95_2pF.cjs.map +0 -1
  129. package/dist/telemetry-LgT_sdPe.js.map +0 -1
  130. package/dist/validate-Dplr99xO.js +0 -25
  131. package/dist/validate-Dplr99xO.js.map +0 -1
  132. package/dist/validate-_8mBa63G.cjs +0 -25
  133. package/dist/validate-_8mBa63G.cjs.map +0 -1
  134. package/dist/validate-kLJoT_hi.js +0 -33
  135. package/dist/validate-kLJoT_hi.js.map +0 -1
  136. package/dist/validate-yKKzqEZ5.cjs +0 -34
  137. package/dist/validate-yKKzqEZ5.cjs.map +0 -1
  138. package/src/runners/agent.ts +0 -149
  139. package/src/runners/generate.ts +0 -333
  140. package/src/runners/init.ts +0 -296
  141. package/src/runners/mcp.ts +0 -45
  142. package/src/runners/validate.ts +0 -39
  143. package/src/types.ts +0 -11
  144. package/src/utils/Writables.ts +0 -17
  145. package/src/utils/executeHooks.ts +0 -45
  146. package/src/utils/flags.ts +0 -9
  147. package/src/utils/getConfig.ts +0 -10
  148. package/src/utils/getCosmiConfig.ts +0 -80
  149. package/src/utils/getSummary.ts +0 -68
  150. package/src/utils/runHook.ts +0 -91
  151. package/src/utils/watcher.ts +0 -19
@@ -1,9 +1,9 @@
1
- import "./chunk--u3MIqq1.js";
2
- import { n as toCause, r as toError } from "./errors-CjPmyZHy.js";
3
- import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-LgT_sdPe.js";
4
- import { n as tokenize } from "./shell-DLzN4fRo.js";
5
- import { t as version } from "./package-Yo-9_m5C.js";
6
- import { a as SUMMARY_SEPARATOR, n as KUBB_NPM_PACKAGE_URL, o as WATCHER_IGNORED_PATHS } from "./constants-aL3CP_Wq.js";
1
+ import "./chunk-BvFE5Tac.js";
2
+ import { n as toCause, r as toError } from "./errors-CINO1EIv.js";
3
+ import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-BkektVz6.js";
4
+ import { n as tokenize } from "./shell-CN6DNqeC.js";
5
+ import { t as version } from "./package-C_LGzz8A.js";
6
+ import { a as WATCHER_IGNORED_PATHS, i as SUMMARY_SEPARATOR, t as KUBB_NPM_PACKAGE_URL } from "./constants-B2JTeRBb.js";
7
7
  import { styleText } from "node:util";
8
8
  import { EventEmitter } from "node:events";
9
9
  import { createHash } from "node:crypto";
@@ -14,10 +14,9 @@ import path, { dirname, relative, resolve } from "node:path";
14
14
  import process$1 from "node:process";
15
15
  import * as clack from "@clack/prompts";
16
16
  import { createKubb, defineLogger, isInputPath, logLevel } from "@kubb/core";
17
- import { NonZeroExitError, x } from "tinyexec";
18
- import { Writable } from "node:stream";
19
17
  import { cosmiconfig } from "cosmiconfig";
20
- import { unrun } from "unrun";
18
+ import { createJiti } from "jiti";
19
+ import { NonZeroExitError, x } from "tinyexec";
21
20
  //#region ../../internals/utils/src/asyncEventEmitter.ts
22
21
  /**
23
22
  * Typed `EventEmitter` that awaits all async listeners before resolving.
@@ -48,9 +47,12 @@ var AsyncEventEmitter = class {
48
47
  * await emitter.emit('build', 'petstore')
49
48
  * ```
50
49
  */
51
- async emit(eventName, ...eventArgs) {
50
+ emit(eventName, ...eventArgs) {
52
51
  const listeners = this.#emitter.listeners(eventName);
53
52
  if (listeners.length === 0) return;
53
+ return this.#emitAll(eventName, listeners, eventArgs);
54
+ }
55
+ async #emitAll(eventName, listeners, eventArgs) {
54
56
  for (const listener of listeners) try {
55
57
  await listener(...eventArgs);
56
58
  } catch (err) {
@@ -486,112 +488,6 @@ async function detectLinter() {
486
488
  return null;
487
489
  }
488
490
  //#endregion
489
- //#region src/utils/getSummary.ts
490
- function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
491
- const duration = formatHrtime(hrStart);
492
- const pluginsCount = config.plugins?.length ?? 0;
493
- const successCount = pluginsCount - failedPlugins.size;
494
- const meta = {
495
- plugins: status === "success" ? `${styleText("green", `${successCount} successful`)}, ${pluginsCount} total` : `${styleText("green", `${successCount} successful`)}, ${styleText("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
496
- pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
497
- filesCreated,
498
- time: styleText("green", duration),
499
- output: path.resolve(config.root, config.output.path)
500
- };
501
- const labels = {
502
- plugins: "Plugins:",
503
- failed: "Failed:",
504
- generated: "Generated:",
505
- pluginTimings: "Plugin Timings:",
506
- output: "Output:"
507
- };
508
- const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
509
- const summaryLines = [];
510
- summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
511
- if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
512
- summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
513
- if (pluginTimings && pluginTimings.size > 0) {
514
- const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
515
- summaryLines.push(`${labels.pluginTimings}`);
516
- sortedTimings.forEach(([name, time]) => {
517
- const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
518
- const barLength = Math.min(Math.ceil(time / 100), 10);
519
- const bar = styleText("dim", "█".repeat(barLength));
520
- summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
521
- });
522
- }
523
- summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
524
- return summaryLines;
525
- }
526
- //#endregion
527
- //#region src/utils/runHook.ts
528
- /**
529
- * Executes a hook command, emits debug and completion events, and forwards output to an optional sink.
530
- */
531
- async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
532
- try {
533
- const proc = x(command, [...args ?? []], {
534
- nodeOptions: { detached: process.platform !== "win32" },
535
- throwOnError: true
536
- });
537
- if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
538
- const result = await proc;
539
- await context.emit("kubb:debug", {
540
- date: /* @__PURE__ */ new Date(),
541
- logs: [result.stdout.trimEnd()]
542
- });
543
- await context.emit("kubb:hook:end", {
544
- command,
545
- args,
546
- id,
547
- success: true,
548
- error: null
549
- });
550
- } catch (err) {
551
- if (!(err instanceof NonZeroExitError)) {
552
- await context.emit("kubb:hook:end", {
553
- command,
554
- args,
555
- id,
556
- success: false,
557
- error: toError(err)
558
- });
559
- await context.emit("kubb:error", { error: toError(err) });
560
- return;
561
- }
562
- const stderr = err.output?.stderr ?? "";
563
- const stdout = err.output?.stdout ?? "";
564
- await context.emit("kubb:debug", {
565
- date: /* @__PURE__ */ new Date(),
566
- logs: [stdout, stderr].filter(Boolean)
567
- });
568
- if (stderr) sink?.onStderr?.(stderr);
569
- if (stdout) sink?.onStdout?.(stdout);
570
- const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
571
- await context.emit("kubb:hook:end", {
572
- command,
573
- args,
574
- id,
575
- success: false,
576
- error: errorMessage
577
- });
578
- await context.emit("kubb:error", { error: errorMessage });
579
- }
580
- }
581
- //#endregion
582
- //#region src/utils/Writables.ts
583
- var ClackWritable = class extends Writable {
584
- taskLog;
585
- constructor(taskLog, opts) {
586
- super(opts);
587
- this.taskLog = taskLog;
588
- }
589
- _write(chunk, _encoding, callback) {
590
- this.taskLog.message(`${styleText("dim", chunk.toString())}`);
591
- callback();
592
- }
593
- };
594
- //#endregion
595
491
  //#region src/loggers/clackLogger.ts
596
492
  /**
597
493
  * TTY logger with beautiful UI and progress indicators for local development.
@@ -609,7 +505,8 @@ const clackLogger = defineLogger({
609
505
  hrStart: process$1.hrtime(),
610
506
  spinner: clack.spinner(),
611
507
  isSpinning: false,
612
- activeProgress: /* @__PURE__ */ new Map()
508
+ activeProgress: /* @__PURE__ */ new Map(),
509
+ activeHookLogs: /* @__PURE__ */ new Map()
613
510
  };
614
511
  function reset() {
615
512
  for (const [_key, active] of state.activeProgress) {
@@ -625,6 +522,7 @@ const clackLogger = defineLogger({
625
522
  state.spinner = clack.spinner();
626
523
  state.isSpinning = false;
627
524
  state.activeProgress.clear();
525
+ state.activeHookLogs.clear();
628
526
  }
629
527
  function showProgressStep() {
630
528
  if (logLevel$8 <= logLevel.silent) return;
@@ -639,6 +537,7 @@ const clackLogger = defineLogger({
639
537
  state.isSpinning = true;
640
538
  }
641
539
  function stopSpinner(text) {
540
+ if (!state.isSpinning) return;
642
541
  state.spinner.stop(text);
643
542
  state.isSpinning = false;
644
543
  }
@@ -649,8 +548,11 @@ const clackLogger = defineLogger({
649
548
  message,
650
549
  styleText("dim", info)
651
550
  ].join(" "));
652
- if (state.isSpinning) state.spinner.message(text);
653
- else clack.log.info(text);
551
+ if (state.isSpinning) {
552
+ state.spinner.message(text);
553
+ return;
554
+ }
555
+ clack.log.info(text);
654
556
  });
655
557
  context.on("kubb:success", ({ message, info = "" }) => {
656
558
  if (logLevel$8 <= logLevel.silent) return;
@@ -659,8 +561,11 @@ const clackLogger = defineLogger({
659
561
  message,
660
562
  logLevel$8 >= logLevel.info ? styleText("dim", info) : void 0
661
563
  ].filter(Boolean).join(" "));
662
- if (state.isSpinning) stopSpinner(text);
663
- else clack.log.success(text);
564
+ if (state.isSpinning) {
565
+ stopSpinner(text);
566
+ return;
567
+ }
568
+ clack.log.success(text);
664
569
  });
665
570
  context.on("kubb:warn", ({ message, info }) => {
666
571
  if (logLevel$8 < logLevel.warn) return;
@@ -674,8 +579,11 @@ const clackLogger = defineLogger({
674
579
  context.on("kubb:error", ({ error }) => {
675
580
  const caused = toCause(error);
676
581
  const text = [styleText("red", "✗"), error.message].join(" ");
677
- if (state.isSpinning) stopSpinner(getMessage(text));
678
- else clack.log.error(getMessage(text));
582
+ if (state.isSpinning) {
583
+ stopSpinner(getMessage(text));
584
+ return;
585
+ }
586
+ clack.log.error(getMessage(text));
679
587
  if (logLevel$8 >= logLevel.debug && error.stack) {
680
588
  const frames = error.stack.split("\n").slice(1, 4);
681
589
  for (const frame of frames) clack.log.message(getMessage(styleText("dim", frame.trim())));
@@ -726,6 +634,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
726
634
  context.on("kubb:generation:start", ({ config }) => {
727
635
  reset();
728
636
  state.totalPlugins = config.plugins?.length ?? 0;
637
+ if (logLevel$8 <= logLevel.silent) return;
729
638
  const text = getMessage(["Generation started", config.name ? `for ${styleText("dim", config.name)}` : void 0].filter(Boolean).join(" "));
730
639
  clack.intro(text);
731
640
  });
@@ -775,14 +684,14 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
775
684
  progressBar.start(getMessage(text));
776
685
  state.activeProgress.set("files", { progressBar });
777
686
  });
778
- context.on("kubb:file:processing:update", ({ file, config }) => {
687
+ context.on("kubb:files:processing:update", ({ files }) => {
779
688
  if (logLevel$8 <= logLevel.silent) return;
780
689
  stopSpinner();
781
- state.processedFiles++;
782
- const text = `Writing ${relative(config.root, file.path)}`;
783
690
  const active = state.activeProgress.get("files");
784
- if (!active) return;
785
- active.progressBar.advance(void 0, text);
691
+ for (const { file, config } of files) {
692
+ state.processedFiles++;
693
+ if (active) active.progressBar.advance(void 0, `Writing ${relative(config.root, file.path)}`);
694
+ }
786
695
  });
787
696
  context.on("kubb:files:processing:end", () => {
788
697
  if (logLevel$8 <= logLevel.silent) return;
@@ -795,68 +704,44 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
795
704
  showProgressStep();
796
705
  });
797
706
  context.on("kubb:generation:end", ({ config }) => {
707
+ stopSpinner();
798
708
  const text = getMessage(config.name ? `Generation completed for ${styleText("dim", config.name)}` : "Generation completed");
799
709
  clack.outro(text);
800
710
  });
801
711
  context.on("kubb:format:start", () => {
802
712
  if (logLevel$8 <= logLevel.silent) return;
803
- const text = getMessage("Format started");
804
- clack.intro(text);
805
- });
806
- context.on("kubb:format:end", () => {
807
- if (logLevel$8 <= logLevel.silent) return;
808
- const text = getMessage("Format completed");
809
- clack.outro(text);
713
+ clack.log.step(getMessage("Formatting"));
810
714
  });
811
715
  context.on("kubb:lint:start", () => {
812
716
  if (logLevel$8 <= logLevel.silent) return;
813
- const text = getMessage("Lint started");
814
- clack.intro(text);
717
+ clack.log.step(getMessage("Linting"));
815
718
  });
816
- context.on("kubb:lint:end", () => {
719
+ context.on("kubb:hooks:start", () => {
817
720
  if (logLevel$8 <= logLevel.silent) return;
818
- const text = getMessage("Lint completed");
819
- clack.outro(text);
721
+ clack.log.step(getMessage("Running hooks"));
820
722
  });
821
- context.on("kubb:hook:start", async ({ id, command, args }) => {
822
- const commandWithArgs = formatCommandWithArgs(command, args);
823
- const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`);
824
- if (!id) return;
825
- if (logLevel$8 <= logLevel.silent) {
826
- await runHook({
827
- id,
828
- command,
829
- args,
830
- commandWithArgs,
831
- context,
832
- sink: {
833
- onStderr: (s) => console.error(s),
834
- onStdout: (s) => console.log(s)
835
- }
836
- });
837
- return;
838
- }
839
- clack.intro(text);
840
- const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel$8 >= logLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
841
- const writable = new ClackWritable(logger);
842
- await runHook({
843
- id,
844
- command,
845
- args,
846
- commandWithArgs,
847
- context,
848
- stream: true,
849
- sink: {
850
- onLine: (line) => writable.write(line),
851
- onStderr: (s) => logger.error(s),
852
- onStdout: (s) => logger.message(s)
853
- }
723
+ context.on("kubb:hook:start", ({ id, command, args }) => {
724
+ if (logLevel$8 <= logLevel.silent || !id) return;
725
+ stopSpinner();
726
+ const title = getMessage(`Running ${styleText("dim", formatCommandWithArgs(command, args))}`);
727
+ const taskLog = clack.taskLog({ title });
728
+ state.activeHookLogs.set(id, {
729
+ taskLog,
730
+ hrStart: process$1.hrtime()
854
731
  });
855
732
  });
856
- context.on("kubb:hook:end", ({ command, args }) => {
857
- if (logLevel$8 <= logLevel.silent) return;
858
- const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} successfully executed`);
859
- clack.outro(text);
733
+ context.on("kubb:hook:end", ({ id, command, args, success, error }) => {
734
+ if (logLevel$8 <= logLevel.silent || !id) return;
735
+ const active = state.activeHookLogs.get(id);
736
+ if (!active) return;
737
+ state.activeHookLogs.delete(id);
738
+ const commandWithArgs = formatCommandWithArgs(command, args);
739
+ const duration = formatMsWithColor(getElapsedMs(active.hrStart));
740
+ if (success) active.taskLog.success(getMessage(`${styleText("dim", commandWithArgs)} completed in ${duration}`));
741
+ else {
742
+ const reason = error?.message ? ` (${error.message})` : "";
743
+ active.taskLog.error(getMessage(`${styleText("dim", commandWithArgs)} failed${reason}`), { showLog: true });
744
+ }
860
745
  });
861
746
  context.on("kubb:generation:summary", ({ config, pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
862
747
  const summary = getSummary({
@@ -887,13 +772,29 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
887
772
  context.on("kubb:lifecycle:end", () => {
888
773
  reset();
889
774
  });
775
+ return (_commandWithArgs, hookId) => {
776
+ if (logLevel$8 <= logLevel.silent) return {
777
+ onStdout: (s) => console.log(s),
778
+ onStderr: (s) => console.error(s)
779
+ };
780
+ const active = state.activeHookLogs.get(hookId);
781
+ if (!active) return null;
782
+ const { taskLog } = active;
783
+ return {
784
+ stream: true,
785
+ onLine: (line) => taskLog.message(styleText("dim", line)),
786
+ onStdout: (s) => taskLog.message(s),
787
+ onStderr: (s) => taskLog.message(styleText("red", s))
788
+ };
789
+ };
890
790
  }
891
791
  });
892
792
  //#endregion
893
793
  //#region src/loggers/fileSystemLogger.ts
894
794
  /**
895
795
  * FileSystem logger that captures debug events and writes them to `.kubb` directory files.
896
- * Note: Logs write on `lifecycle:end` or process exit. Cached logs may be lost if the process crashes before these events.
796
+ *
797
+ * @note Logs are written on `kubb:lifecycle:end` or process exit. Cached logs may be lost if the process crashes before either event.
897
798
  */
898
799
  const fileSystemLogger = defineLogger({
899
800
  name: "filesystem",
@@ -918,29 +819,31 @@ const fileSystemLogger = defineLogger({
918
819
  const pathName = resolve(process$1.cwd(), ".kubb", baseName);
919
820
  if (!files[pathName]) files[pathName] = [];
920
821
  if (log.logs.length > 0) {
921
- const timestamp = log.date.toLocaleString();
922
- files[pathName].push(`[${timestamp}]\n${log.logs.join("\n")}`);
822
+ const prefix = `[${log.date.toLocaleString()}] `;
823
+ const indent = " ".repeat(prefix.length);
824
+ const [first, ...rest] = log.logs;
825
+ files[pathName].push([prefix + first, ...rest.map((line) => indent + line)].join("\n"));
923
826
  }
924
827
  }
925
- for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n\n"));
828
+ for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n"));
926
829
  return Object.keys(files);
927
830
  }
928
831
  context.on("kubb:info", ({ message, info }) => {
929
832
  state.cachedLogs.add({
930
833
  date: /* @__PURE__ */ new Date(),
931
- logs: [`ℹ ${message} ${info}`]
834
+ logs: [`ℹ ${[message, info].filter(Boolean).join(" ")}`]
932
835
  });
933
836
  });
934
837
  context.on("kubb:success", ({ message, info }) => {
935
838
  state.cachedLogs.add({
936
839
  date: /* @__PURE__ */ new Date(),
937
- logs: [`✓ ${message} ${info}`]
840
+ logs: [`✓ ${[message, info].filter(Boolean).join(" ")}`]
938
841
  });
939
842
  });
940
843
  context.on("kubb:warn", ({ message, info }) => {
941
844
  state.cachedLogs.add({
942
845
  date: /* @__PURE__ */ new Date(),
943
- logs: [`⚠ ${message} ${info}`]
846
+ logs: [`⚠ ${[message, info].filter(Boolean).join(" ")}`]
944
847
  });
945
848
  });
946
849
  context.on("kubb:error", ({ error }) => {
@@ -949,29 +852,30 @@ const fileSystemLogger = defineLogger({
949
852
  logs: [`✗ ${error.message}`, error.stack || "unknown stack"]
950
853
  });
951
854
  });
952
- context.on("kubb:debug", (message) => {
855
+ context.on("kubb:debug", ({ date, fileName, logs }) => {
953
856
  state.cachedLogs.add({
954
- date: /* @__PURE__ */ new Date(),
955
- logs: message.logs
857
+ date,
858
+ fileName,
859
+ logs
956
860
  });
957
861
  });
958
862
  context.on("kubb:plugin:start", ({ plugin }) => {
959
863
  state.cachedLogs.add({
960
864
  date: /* @__PURE__ */ new Date(),
961
- logs: [`Generating ${plugin.name}`]
865
+ logs: [`► Generating ${plugin.name}`]
962
866
  });
963
867
  });
964
868
  context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
965
869
  const durationStr = formatMs(duration);
966
870
  state.cachedLogs.add({
967
871
  date: /* @__PURE__ */ new Date(),
968
- logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`]
872
+ logs: [success ? `✓ ${plugin.name} completed in ${durationStr}` : `✗ ${plugin.name} failed in ${durationStr}`]
969
873
  });
970
874
  });
971
875
  context.on("kubb:files:processing:start", ({ files }) => {
972
876
  state.cachedLogs.add({
973
877
  date: /* @__PURE__ */ new Date(),
974
- logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)]
878
+ logs: [`► Writing ${files.length} files`, ...files.map((file) => ` ${file.path}`)]
975
879
  });
976
880
  });
977
881
  context.on("kubb:generation:end", async ({ config }) => {
@@ -1008,17 +912,21 @@ const githubActionsLogger = defineLogger({
1008
912
  failedPlugins: 0,
1009
913
  totalFiles: 0,
1010
914
  processedFiles: 0,
1011
- hrStart: process.hrtime(),
1012
- currentConfigs: []
915
+ hrStart: process$1.hrtime(),
916
+ currentConfigs: [],
917
+ hookStarts: /* @__PURE__ */ new Map(),
918
+ openGroupDepth: 0
1013
919
  };
1014
920
  function reset() {
921
+ closeAllGroups();
1015
922
  state.totalPlugins = 0;
1016
923
  state.completedPlugins = 0;
1017
924
  state.failedPlugins = 0;
1018
925
  state.totalFiles = 0;
1019
926
  state.processedFiles = 0;
1020
- state.hrStart = process.hrtime();
927
+ state.hrStart = process$1.hrtime();
1021
928
  state.currentConfigs = [];
929
+ state.hookStarts.clear();
1022
930
  }
1023
931
  function showProgressStep() {
1024
932
  if (logLevel$7 <= logLevel.silent) return;
@@ -1030,9 +938,17 @@ const githubActionsLogger = defineLogger({
1030
938
  }
1031
939
  function openGroup(name) {
1032
940
  console.log(`::group::${name}`);
941
+ state.openGroupDepth++;
1033
942
  }
1034
943
  function closeGroup(_name) {
1035
944
  console.log("::endgroup::");
945
+ if (state.openGroupDepth > 0) state.openGroupDepth--;
946
+ }
947
+ function closeAllGroups() {
948
+ while (state.openGroupDepth > 0) {
949
+ console.log("::endgroup::");
950
+ state.openGroupDepth--;
951
+ }
1036
952
  }
1037
953
  context.on("kubb:info", ({ message, info = "" }) => {
1038
954
  if (logLevel$7 <= logLevel.silent) return;
@@ -1063,6 +979,7 @@ const githubActionsLogger = defineLogger({
1063
979
  });
1064
980
  context.on("kubb:error", ({ error }) => {
1065
981
  const caused = toCause(error);
982
+ closeAllGroups();
1066
983
  if (logLevel$7 <= logLevel.silent) return;
1067
984
  const message = error.message || String(error);
1068
985
  console.error(`::error::${message}`);
@@ -1080,6 +997,9 @@ const githubActionsLogger = defineLogger({
1080
997
  console.log(styleText("yellow", `Kubb ${version} 🧩`));
1081
998
  reset();
1082
999
  });
1000
+ context.on("kubb:version:new", ({ currentVersion, latestVersion }) => {
1001
+ console.log(`::notice::Update available for Kubb: v${currentVersion} → v${latestVersion}. Run \`npm install -g @kubb/cli\` to update.`);
1002
+ });
1083
1003
  context.on("kubb:config:start", () => {
1084
1004
  if (logLevel$7 <= logLevel.silent) return;
1085
1005
  const text = getMessage("Configuration started");
@@ -1132,9 +1052,9 @@ const githubActionsLogger = defineLogger({
1132
1052
  if (state.currentConfigs.length === 1) closeGroup("File Generation");
1133
1053
  showProgressStep();
1134
1054
  });
1135
- context.on("kubb:file:processing:update", () => {
1055
+ context.on("kubb:files:processing:update", ({ files }) => {
1136
1056
  if (logLevel$7 <= logLevel.silent) return;
1137
- state.processedFiles++;
1057
+ state.processedFiles += files.length;
1138
1058
  });
1139
1059
  context.on("kubb:generation:end", ({ config }) => {
1140
1060
  const text = getMessage(config.name ? `${styleText("blue", "✓")} Generation completed for ${styleText("dim", config.name)}` : `${styleText("blue", "✓")} Generation completed`);
@@ -1164,31 +1084,35 @@ const githubActionsLogger = defineLogger({
1164
1084
  console.log(text);
1165
1085
  if (state.currentConfigs.length === 1) closeGroup("Linting");
1166
1086
  });
1167
- context.on("kubb:hook:start", async ({ id, command, args }) => {
1087
+ context.on("kubb:hooks:start", () => {
1088
+ if (logLevel$7 <= logLevel.silent) return;
1089
+ if (state.currentConfigs.length === 1) openGroup("Hooks");
1090
+ console.log(getMessage("Hooks started"));
1091
+ });
1092
+ context.on("kubb:hooks:end", () => {
1093
+ if (logLevel$7 <= logLevel.silent) return;
1094
+ console.log(getMessage("Hooks completed"));
1095
+ if (state.currentConfigs.length === 1) closeGroup("Hooks");
1096
+ });
1097
+ context.on("kubb:hook:start", ({ id, command, args }) => {
1098
+ if (logLevel$7 <= logLevel.silent) return;
1099
+ if (id) state.hookStarts.set(id, process$1.hrtime());
1168
1100
  const commandWithArgs = formatCommandWithArgs(command, args);
1169
1101
  const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`);
1170
- if (logLevel$7 > logLevel.silent) {
1171
- if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
1172
- console.log(text);
1173
- }
1174
- if (!id) return;
1175
- await runHook({
1176
- id,
1177
- command,
1178
- args,
1179
- commandWithArgs,
1180
- context,
1181
- sink: {
1182
- onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0,
1183
- onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
1184
- }
1185
- });
1102
+ if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
1103
+ console.log(text);
1186
1104
  });
1187
- context.on("kubb:hook:end", ({ command, args }) => {
1105
+ context.on("kubb:hook:end", ({ id, command, args, success, error }) => {
1188
1106
  if (logLevel$7 <= logLevel.silent) return;
1107
+ const hrStart = id ? state.hookStarts.get(id) : void 0;
1108
+ if (id) state.hookStarts.delete(id);
1109
+ const durationStr = hrStart ? ` in ${formatMsWithColor(getElapsedMs(hrStart))}` : "";
1189
1110
  const commandWithArgs = formatCommandWithArgs(command, args);
1190
- const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} completed`);
1191
- console.log(text);
1111
+ if (success) console.log(getMessage(`${styleText("green", "✓")} Hook ${styleText("dim", commandWithArgs)} completed${durationStr}`));
1112
+ else {
1113
+ const reason = error?.message ? ` (${error.message})` : "";
1114
+ console.log(`::error::Hook ${commandWithArgs} failed${durationStr}${reason}`);
1115
+ }
1192
1116
  if (state.currentConfigs.length === 1) closeGroup(`Hook ${commandWithArgs}`);
1193
1117
  });
1194
1118
  context.on("kubb:generation:summary", ({ config, status, hrStart, failedPlugins }) => {
@@ -1202,6 +1126,10 @@ const githubActionsLogger = defineLogger({
1202
1126
  context.on("kubb:lifecycle:end", () => {
1203
1127
  reset();
1204
1128
  });
1129
+ return (_commandWithArgs, _hookId) => ({
1130
+ onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0,
1131
+ onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
1132
+ });
1205
1133
  }
1206
1134
  });
1207
1135
  //#endregion
@@ -1213,6 +1141,7 @@ const plainLogger = defineLogger({
1213
1141
  name: "plain",
1214
1142
  install(context, options) {
1215
1143
  const logLevel$6 = options?.logLevel ?? logLevel.info;
1144
+ const hookStarts = /* @__PURE__ */ new Map();
1216
1145
  function getMessage(message) {
1217
1146
  return formatMessage(message, logLevel$6);
1218
1147
  }
@@ -1257,8 +1186,12 @@ const plainLogger = defineLogger({
1257
1186
  }
1258
1187
  }
1259
1188
  });
1260
- context.on("kubb:lifecycle:start", () => {
1261
- console.log("Kubb CLI 🧩");
1189
+ context.on("kubb:lifecycle:start", ({ version }) => {
1190
+ console.log(`Kubb CLI v${version}`);
1191
+ });
1192
+ context.on("kubb:version:new", ({ currentVersion, latestVersion }) => {
1193
+ if (logLevel$6 <= logLevel.silent) return;
1194
+ console.log(getMessage(`Update available: v${currentVersion} → v${latestVersion}. Run \`npm install -g @kubb/cli\` to update.`));
1262
1195
  });
1263
1196
  context.on("kubb:config:start", () => {
1264
1197
  if (logLevel$6 <= logLevel.silent) return;
@@ -1290,10 +1223,9 @@ const plainLogger = defineLogger({
1290
1223
  const text = getMessage(`Writing ${files.length} files`);
1291
1224
  console.log(text);
1292
1225
  });
1293
- context.on("kubb:file:processing:update", ({ file, config }) => {
1226
+ context.on("kubb:files:processing:update", ({ files }) => {
1294
1227
  if (logLevel$6 <= logLevel.silent) return;
1295
- const text = getMessage(`Writing ${relative(config.root, file.path)}`);
1296
- console.log(text);
1228
+ for (const { file, config } of files) console.log(getMessage(`Writing ${relative(config.root, file.path)}`));
1297
1229
  });
1298
1230
  context.on("kubb:files:processing:end", () => {
1299
1231
  if (logLevel$6 <= logLevel.silent) return;
@@ -1324,27 +1256,31 @@ const plainLogger = defineLogger({
1324
1256
  const text = getMessage("Lint completed");
1325
1257
  console.log(text);
1326
1258
  });
1327
- context.on("kubb:hook:start", async ({ id, command, args }) => {
1259
+ context.on("kubb:hooks:start", () => {
1260
+ if (logLevel$6 <= logLevel.silent) return;
1261
+ console.log(getMessage("Hooks started"));
1262
+ });
1263
+ context.on("kubb:hooks:end", () => {
1264
+ if (logLevel$6 <= logLevel.silent) return;
1265
+ console.log(getMessage("Hooks completed"));
1266
+ });
1267
+ context.on("kubb:hook:start", ({ id, command, args }) => {
1268
+ if (logLevel$6 <= logLevel.silent) return;
1269
+ if (id) hookStarts.set(id, process$1.hrtime());
1328
1270
  const commandWithArgs = formatCommandWithArgs(command, args);
1329
- const text = getMessage(`Hook ${commandWithArgs} started`);
1330
- if (logLevel$6 > logLevel.silent) console.log(text);
1331
- if (!id) return;
1332
- await runHook({
1333
- id,
1334
- command,
1335
- args,
1336
- commandWithArgs,
1337
- context,
1338
- sink: {
1339
- onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0,
1340
- onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0
1341
- }
1342
- });
1271
+ console.log(getMessage(`Hook ${commandWithArgs} started`));
1343
1272
  });
1344
- context.on("kubb:hook:end", ({ command, args }) => {
1273
+ context.on("kubb:hook:end", ({ id, command, args, success, error }) => {
1345
1274
  if (logLevel$6 <= logLevel.silent) return;
1346
- const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} completed`);
1347
- console.log(text);
1275
+ const hrStart = id ? hookStarts.get(id) : void 0;
1276
+ if (id) hookStarts.delete(id);
1277
+ const durationStr = hrStart ? ` in ${formatMs(getElapsedMs(hrStart))}` : "";
1278
+ const commandWithArgs = formatCommandWithArgs(command, args);
1279
+ if (success) console.log(getMessage(`✓ Hook ${commandWithArgs} completed${durationStr}`));
1280
+ else {
1281
+ const reason = error?.message ? ` (${error.message})` : "";
1282
+ console.log(getMessage(`✗ Hook ${commandWithArgs} failed${durationStr}${reason}`));
1283
+ }
1348
1284
  });
1349
1285
  context.on("kubb:generation:summary", ({ config, pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
1350
1286
  const summary = getSummary({
@@ -1359,6 +1295,10 @@ const plainLogger = defineLogger({
1359
1295
  console.log(summary.join("\n"));
1360
1296
  console.log(SUMMARY_SEPARATOR);
1361
1297
  });
1298
+ return (_commandWithArgs, _hookId) => ({
1299
+ onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0,
1300
+ onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0
1301
+ });
1362
1302
  }
1363
1303
  });
1364
1304
  //#endregion
@@ -1413,125 +1353,241 @@ async function setupLogger(context, { logLevel: logLevel$5 }) {
1413
1353
  const type = detectLogger();
1414
1354
  const logger = logMapper[type];
1415
1355
  if (!logger) throw new Error(`Unknown adapter type: ${type}`);
1416
- const cleanup = await logger.install(context, { logLevel: logLevel$5 });
1356
+ const makeSink = await logger.install(context, { logLevel: logLevel$5 });
1417
1357
  if (logLevel$5 >= logLevel.debug) await fileSystemLogger.install(context, { logLevel: logLevel$5 });
1418
- return cleanup;
1358
+ return typeof makeSink === "function" ? makeSink : null;
1419
1359
  }
1420
- //#endregion
1421
- //#region src/utils/executeHooks.ts
1422
- async function executeHooks({ configHooks, hooks }) {
1423
- const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
1424
- for (const command of commands) {
1425
- const [cmd, ...args] = tokenize(command);
1426
- if (!cmd) continue;
1427
- const hookId = createHash("sha256").update(command).digest("hex");
1428
- const hookEndPromise = new Promise((resolve, reject) => {
1429
- const handler = (ctx) => {
1430
- if (ctx.id !== hookId) return;
1431
- hooks.off("kubb:hook:end", handler);
1432
- if (!ctx.success) {
1433
- reject(ctx.error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`));
1434
- return;
1435
- }
1436
- hooks.emit("kubb:success", { message: `${styleText("dim", command)} successfully executed` }).then(resolve).catch(reject);
1437
- };
1438
- hooks.on("kubb:hook:end", handler);
1439
- });
1440
- await hooks.emit("kubb:hook:start", {
1441
- id: hookId,
1442
- command: cmd,
1443
- args
1360
+ /**
1361
+ * Builds the generation summary lines rendered in the end-of-run box.
1362
+ * Returns an array of styled strings, one per summary row.
1363
+ */
1364
+ function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
1365
+ const duration = formatHrtime(hrStart);
1366
+ const pluginsCount = config.plugins?.length ?? 0;
1367
+ const successCount = pluginsCount - failedPlugins.size;
1368
+ const meta = {
1369
+ plugins: status === "success" ? `${styleText("green", `${successCount} successful`)}, ${pluginsCount} total` : `${styleText("green", `${successCount} successful`)}, ${styleText("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
1370
+ pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
1371
+ filesCreated,
1372
+ time: styleText("green", duration),
1373
+ output: path.resolve(config.root, config.output.path)
1374
+ };
1375
+ const labels = {
1376
+ plugins: "Plugins:",
1377
+ failed: "Failed:",
1378
+ generated: "Generated:",
1379
+ pluginTimings: "Plugin Timings:",
1380
+ output: "Output:"
1381
+ };
1382
+ const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
1383
+ const summaryLines = [];
1384
+ summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
1385
+ if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
1386
+ summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
1387
+ if (pluginTimings && pluginTimings.size > 0) {
1388
+ const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
1389
+ summaryLines.push(`${labels.pluginTimings}`);
1390
+ sortedTimings.forEach(([name, time]) => {
1391
+ const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
1392
+ const barLength = Math.min(Math.ceil(time / 100), 10);
1393
+ const bar = styleText("dim", "█".repeat(barLength));
1394
+ summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
1444
1395
  });
1445
- await hookEndPromise;
1446
1396
  }
1397
+ summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
1398
+ return summaryLines;
1447
1399
  }
1448
1400
  //#endregion
1449
- //#region src/utils/getConfig.ts
1450
- async function getConfigs(config, args) {
1451
- const resolved = await (typeof config === "function" ? config(args) : config);
1452
- return (Array.isArray(resolved) ? resolved : [resolved]).map((item) => ({
1453
- ...item,
1454
- plugins: item.plugins ?? []
1455
- }));
1456
- }
1457
- //#endregion
1458
- //#region src/utils/getCosmiConfig.ts
1459
- const unrunInputOptions = { transform: { jsx: {
1460
- runtime: "automatic",
1461
- importSource: "@kubb/renderer-jsx"
1462
- } } };
1463
- const tsLoader = async (configFile) => {
1464
- const { module } = await unrun({
1465
- path: configFile,
1466
- inputOptions: unrunInputOptions
1467
- });
1468
- return module;
1469
- };
1470
- async function getCosmiConfig(moduleName, config) {
1471
- let result;
1472
- const searchPlaces = [
1473
- "package.json",
1474
- `.${moduleName}rc`,
1475
- `.${moduleName}rc.json`,
1476
- `.${moduleName}rc.yaml`,
1477
- `.${moduleName}rc.yml`,
1478
- `.${moduleName}rc.ts`,
1479
- `.${moduleName}rc.mts`,
1480
- `.${moduleName}rc.cts`,
1481
- `.${moduleName}rc.js`,
1482
- `.${moduleName}rc.mjs`,
1483
- `.${moduleName}rc.cjs`,
1484
- `${moduleName}.config.ts`,
1485
- `${moduleName}.config.mts`,
1486
- `${moduleName}.config.cts`,
1487
- `${moduleName}.config.js`,
1488
- `${moduleName}.config.mjs`,
1489
- `${moduleName}.config.cjs`
1490
- ];
1491
- const explorer = cosmiconfig(moduleName, {
1401
+ //#region src/runners/generate/utils.ts
1402
+ const jiti = createJiti(import.meta.url, {
1403
+ jsx: {
1404
+ runtime: "automatic",
1405
+ importSource: "@kubb/renderer-jsx"
1406
+ },
1407
+ moduleCache: false
1408
+ });
1409
+ const tsLoader = (configFile) => jiti.import(configFile, { default: true });
1410
+ const MODULE_NAME = "kubb";
1411
+ const BASE_SEARCH_PLACES = [
1412
+ "package.json",
1413
+ `.${MODULE_NAME}rc`,
1414
+ `.${MODULE_NAME}rc.json`,
1415
+ `.${MODULE_NAME}rc.yaml`,
1416
+ `.${MODULE_NAME}rc.yml`,
1417
+ `.${MODULE_NAME}rc.ts`,
1418
+ `.${MODULE_NAME}rc.mts`,
1419
+ `.${MODULE_NAME}rc.cts`,
1420
+ `.${MODULE_NAME}rc.js`,
1421
+ `.${MODULE_NAME}rc.mjs`,
1422
+ `.${MODULE_NAME}rc.cjs`,
1423
+ `${MODULE_NAME}.config.ts`,
1424
+ `${MODULE_NAME}.config.mts`,
1425
+ `${MODULE_NAME}.config.cts`,
1426
+ `${MODULE_NAME}.config.js`,
1427
+ `${MODULE_NAME}.config.mjs`,
1428
+ `${MODULE_NAME}.config.cjs`
1429
+ ];
1430
+ const SEARCH_PLACES = [
1431
+ "",
1432
+ ".config/",
1433
+ "configs/"
1434
+ ].flatMap((prefix) => BASE_SEARCH_PLACES.map((p) => `${prefix}${p}`));
1435
+ async function getCosmiConfig(configFile) {
1436
+ const explorer = cosmiconfig(MODULE_NAME, {
1492
1437
  cache: false,
1493
- searchPlaces: [
1494
- ...searchPlaces.map((searchPlace) => {
1495
- return `.config/${searchPlace}`;
1496
- }),
1497
- ...searchPlaces.map((searchPlace) => {
1498
- return `configs/${searchPlace}`;
1499
- }),
1500
- ...searchPlaces
1501
- ],
1438
+ searchPlaces: SEARCH_PLACES,
1502
1439
  loaders: {
1503
1440
  ".ts": tsLoader,
1504
1441
  ".mts": tsLoader,
1505
1442
  ".cts": tsLoader
1506
1443
  }
1507
1444
  });
1445
+ let result;
1508
1446
  try {
1509
- result = config ? await explorer.load(config) : await explorer.search();
1447
+ result = configFile ? await explorer.load(configFile) : await explorer.search();
1510
1448
  } catch (error) {
1511
1449
  throw new Error("Config failed loading", { cause: error });
1512
1450
  }
1513
- 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");
1451
+ if (!result?.config || result.isEmpty) throw new Error("Config not defined, create a kubb.config.js or pass through your config with the option --config");
1514
1452
  return result;
1515
1453
  }
1516
- //#endregion
1517
- //#region src/utils/watcher.ts
1518
- async function startWatcher(path, cb) {
1454
+ /**
1455
+ * Discovers the Kubb config via cosmiconfig and resolves it into a normalized array of configs.
1456
+ * Every config in the result is guaranteed to have a `plugins` array.
1457
+ */
1458
+ async function getConfigs({ configPath, input }) {
1459
+ const result = await getCosmiConfig(configPath);
1460
+ const resolved = await (typeof result.config === "function" ? result.config({ input }) : result.config);
1461
+ const userConfigs = Array.isArray(resolved) ? resolved : [resolved];
1462
+ return {
1463
+ configPath: result.filepath,
1464
+ configs: userConfigs.map((item) => ({
1465
+ ...item,
1466
+ plugins: item.plugins ?? []
1467
+ }))
1468
+ };
1469
+ }
1470
+ /**
1471
+ * Runs the `done` hooks defined in a Kubb config in sequence.
1472
+ */
1473
+ async function executeHooks({ configHooks, hooks, makeSink }) {
1474
+ const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
1475
+ for (const command of commands) {
1476
+ const [cmd, ...args] = tokenize(command);
1477
+ if (!cmd) continue;
1478
+ const hookId = createHash("sha256").update(command).digest("hex");
1479
+ const commandWithArgs = [cmd, ...args].join(" ");
1480
+ await hooks.emit("kubb:hook:start", {
1481
+ id: hookId,
1482
+ command: cmd,
1483
+ args
1484
+ });
1485
+ const { stream = false, onLine, onStdout, onStderr } = makeSink?.(commandWithArgs, hookId) ?? {};
1486
+ await runHook({
1487
+ id: hookId,
1488
+ command: cmd,
1489
+ args,
1490
+ commandWithArgs,
1491
+ context: hooks,
1492
+ stream,
1493
+ sink: {
1494
+ onLine,
1495
+ onStdout,
1496
+ onStderr
1497
+ }
1498
+ });
1499
+ }
1500
+ }
1501
+ async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
1502
+ const emitEnd = (success, error) => context.emit("kubb:hook:end", {
1503
+ command,
1504
+ args,
1505
+ id,
1506
+ success,
1507
+ error
1508
+ });
1509
+ try {
1510
+ const proc = x(command, [...args ?? []], {
1511
+ nodeOptions: { detached: process.platform !== "win32" },
1512
+ throwOnError: true
1513
+ });
1514
+ if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
1515
+ const result = await proc;
1516
+ await context.emit("kubb:debug", {
1517
+ date: /* @__PURE__ */ new Date(),
1518
+ logs: [result.stdout.trimEnd()]
1519
+ });
1520
+ await context.emit("kubb:success", { message: `${styleText("dim", commandWithArgs)} successfully executed` });
1521
+ await emitEnd(true, null);
1522
+ } catch (err) {
1523
+ if (!(err instanceof NonZeroExitError)) {
1524
+ const error = toError(err);
1525
+ await emitEnd(false, error);
1526
+ await context.emit("kubb:error", { error });
1527
+ return;
1528
+ }
1529
+ const stderr = err.output?.stderr ?? "";
1530
+ const stdout = err.output?.stdout ?? "";
1531
+ await context.emit("kubb:debug", {
1532
+ date: /* @__PURE__ */ new Date(),
1533
+ logs: [stdout, stderr].filter(Boolean)
1534
+ });
1535
+ if (stderr) sink?.onStderr?.(stderr);
1536
+ if (stdout) sink?.onStdout?.(stdout);
1537
+ const error = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
1538
+ await emitEnd(false, error);
1539
+ await context.emit("kubb:error", { error });
1540
+ }
1541
+ }
1542
+ /**
1543
+ * Starts a file watcher on the given paths and calls `cb` on any change.
1544
+ * Ignores `.git` and `node_modules` directories.
1545
+ */
1546
+ async function startWatcher(path, cb, log = {
1547
+ info: console.log,
1548
+ error: console.log
1549
+ }) {
1519
1550
  const { watch } = await import("chokidar");
1520
- watch(path, {
1551
+ const watcher = watch(path, {
1521
1552
  ignorePermissionErrors: true,
1522
1553
  ignored: WATCHER_IGNORED_PATHS
1523
- }).on("all", async (type, file) => {
1524
- console.log(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
1554
+ });
1555
+ process.once("SIGINT", () => {
1556
+ watcher.close();
1557
+ });
1558
+ process.once("SIGTERM", () => {
1559
+ watcher.close();
1560
+ });
1561
+ watcher.on("all", async (type, file) => {
1562
+ log.info(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
1525
1563
  try {
1526
1564
  await cb(path);
1527
1565
  } catch (_e) {
1528
- console.log(styleText("red", "Watcher failed"));
1566
+ log.error(styleText("red", "Watcher failed"));
1529
1567
  }
1530
1568
  });
1531
1569
  }
1532
1570
  //#endregion
1533
- //#region src/runners/generate.ts
1534
- async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, hooks, onStart, onEnd }) {
1571
+ //#region src/runners/generate/run.ts
1572
+ /**
1573
+ * Registers a one-shot `kubb:hook:end` listener for `hookId` BEFORE the caller emits `kubb:hook:start`,
1574
+ * avoiding the race where a synchronous emitter fires end before the listener is attached.
1575
+ */
1576
+ function waitForHookEnd(hooks, hookId, onSuccess, fallbackErrorMessage) {
1577
+ return new Promise((resolve, reject) => {
1578
+ const handler = (ctx) => {
1579
+ if (ctx.id !== hookId) return;
1580
+ hooks.off("kubb:hook:end", handler);
1581
+ if (!ctx.success) {
1582
+ reject(ctx.error ?? new Error(fallbackErrorMessage));
1583
+ return;
1584
+ }
1585
+ Promise.resolve(onSuccess()).then(resolve).catch(reject);
1586
+ };
1587
+ hooks.on("kubb:hook:end", handler);
1588
+ });
1589
+ }
1590
+ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, hooks, makeSink, onStart, onEnd }) {
1535
1591
  await onStart();
1536
1592
  let resolvedTool = toolValue;
1537
1593
  if (resolvedTool === "auto") {
@@ -1545,29 +1601,35 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
1545
1601
  let toolError;
1546
1602
  if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) {
1547
1603
  const toolConfig = toolMap[resolvedTool];
1604
+ const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1605
+ const successMessage = [
1606
+ `${successPrefix} with ${styleText("dim", resolvedTool)}`,
1607
+ logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
1608
+ "successfully"
1609
+ ].filter(Boolean).join(" ");
1548
1610
  try {
1549
- const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1550
- const hookEndPromise = new Promise((resolve, reject) => {
1551
- const handler = (ctx) => {
1552
- if (ctx.id !== hookId) return;
1553
- hooks.off("kubb:hook:end", handler);
1554
- if (!ctx.success) {
1555
- reject(ctx.error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`));
1556
- return;
1557
- }
1558
- hooks.emit("kubb:success", { message: [
1559
- `${successPrefix} with ${styleText("dim", resolvedTool)}`,
1560
- logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
1561
- "successfully"
1562
- ].filter(Boolean).join(" ") }).then(resolve).catch(reject);
1563
- };
1564
- hooks.on("kubb:hook:end", handler);
1565
- });
1611
+ const hookArgs = toolConfig.args(outputPath);
1612
+ const commandWithArgs = [toolConfig.command, ...hookArgs].join(" ");
1613
+ const hookEndPromise = waitForHookEnd(hooks, hookId, () => hooks.emit("kubb:success", { message: successMessage }), toolConfig.errorMessage);
1566
1614
  await hooks.emit("kubb:hook:start", {
1567
1615
  id: hookId,
1568
1616
  command: toolConfig.command,
1569
- args: toolConfig.args(outputPath)
1617
+ args: hookArgs
1570
1618
  });
1619
+ const { stream = false, onLine, onStdout, onStderr } = makeSink?.(commandWithArgs, hookId) ?? {};
1620
+ runHook({
1621
+ id: hookId,
1622
+ command: toolConfig.command,
1623
+ args: hookArgs,
1624
+ commandWithArgs,
1625
+ context: hooks,
1626
+ stream,
1627
+ sink: {
1628
+ onLine,
1629
+ onStdout,
1630
+ onStderr
1631
+ }
1632
+ }).catch(() => {});
1571
1633
  await hookEndPromise;
1572
1634
  } catch (caughtError) {
1573
1635
  const err = toError(caughtError);
@@ -1579,9 +1641,9 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
1579
1641
  if (toolError) throw toolError;
1580
1642
  }
1581
1643
  async function generate(options) {
1582
- const { input, hooks, logLevel: logLevel$2 } = options;
1644
+ const { input, hooks, logLevel: logLevel$2, makeSink } = options;
1583
1645
  const hrStart = process$1.hrtime();
1584
- const inputPath = input ?? ("path" in options.config.input ? options.config.input.path : void 0);
1646
+ const inputPath = input ?? (options.config.input && "path" in options.config.input ? options.config.input.path : void 0);
1585
1647
  const config = {
1586
1648
  ...options.config,
1587
1649
  input: inputPath ? {
@@ -1591,25 +1653,36 @@ async function generate(options) {
1591
1653
  ...options.config.output
1592
1654
  };
1593
1655
  const kubb = createKubb(config, { hooks });
1594
- await kubb.setup();
1595
1656
  await hooks.emit("kubb:generation:start", { config });
1596
1657
  await hooks.emit("kubb:info", {
1597
1658
  message: config.name ? `Setup generation ${styleText("bold", config.name)}` : "Setup generation",
1598
1659
  info: inputPath
1599
1660
  });
1661
+ await kubb.setup();
1600
1662
  await hooks.emit("kubb:info", {
1601
1663
  message: config.name ? `Build generation ${styleText("bold", config.name)}` : "Build generation",
1602
1664
  info: inputPath
1603
1665
  });
1604
1666
  const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild();
1605
1667
  await hooks.emit("kubb:info", { message: "Load summary" });
1668
+ const telemetryPlugins = Array.from(driver.plugins.values(), (p) => ({
1669
+ name: p.name,
1670
+ options: p.options
1671
+ }));
1672
+ const reportTelemetry = (status) => sendTelemetry(buildTelemetryEvent({
1673
+ command: "generate",
1674
+ kubbVersion: version,
1675
+ plugins: telemetryPlugins,
1676
+ hrStart,
1677
+ filesCreated: files.length,
1678
+ status
1679
+ }));
1606
1680
  if (failedPlugins.size > 0 || error) {
1607
- const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean);
1681
+ const allErrors = [error, ...Array.from(failedPlugins, (it) => it.error)].filter(Boolean);
1608
1682
  for (const err of allErrors) await hooks.emit("kubb:error", { error: err });
1609
1683
  await hooks.emit("kubb:generation:end", {
1610
1684
  config,
1611
- files,
1612
- sources: kubb.sources
1685
+ storage: kubb.storage
1613
1686
  });
1614
1687
  await hooks.emit("kubb:generation:summary", {
1615
1688
  config,
@@ -1619,62 +1692,51 @@ async function generate(options) {
1619
1692
  hrStart,
1620
1693
  pluginTimings: logLevel$2 >= logLevel.verbose ? pluginTimings : void 0
1621
1694
  });
1622
- await sendTelemetry(buildTelemetryEvent({
1623
- command: "generate",
1624
- kubbVersion: version,
1625
- plugins: Array.from(driver.plugins.values(), (p) => ({
1626
- name: p.name,
1627
- options: p.options
1628
- })),
1629
- hrStart,
1630
- filesCreated: files.length,
1631
- status: "failed"
1632
- }));
1633
- process$1.exit(1);
1695
+ await reportTelemetry("failed");
1696
+ return false;
1634
1697
  }
1635
1698
  await hooks.emit("kubb:success", {
1636
- message: "Generation successfully",
1699
+ message: "Generation succeeded",
1637
1700
  info: inputPath
1638
1701
  });
1639
1702
  await hooks.emit("kubb:generation:end", {
1640
1703
  config,
1641
- files,
1642
- sources: kubb.sources
1704
+ storage: kubb.storage
1643
1705
  });
1644
1706
  const outputPath = path.resolve(config.root, config.output.path);
1645
- if (config.output.format) await runToolPass({
1707
+ const toolPasses = [config.output.format && {
1646
1708
  toolValue: config.output.format,
1647
1709
  detect: detectFormatter,
1648
1710
  toolMap: formatters,
1649
1711
  toolLabel: "formatter",
1650
1712
  successPrefix: "Formatting",
1651
1713
  noToolMessage: "No formatter found (oxfmt, biome, or prettier). Skipping formatting.",
1652
- configName: config.name,
1653
- outputPath,
1654
- logLevel: logLevel$2,
1655
- hooks,
1656
1714
  onStart: () => hooks.emit("kubb:format:start"),
1657
1715
  onEnd: () => hooks.emit("kubb:format:end")
1658
- });
1659
- if (config.output.lint) await runToolPass({
1716
+ }, config.output.lint && {
1660
1717
  toolValue: config.output.lint,
1661
1718
  detect: detectLinter,
1662
1719
  toolMap: linters,
1663
1720
  toolLabel: "linter",
1664
1721
  successPrefix: "Linting",
1665
1722
  noToolMessage: "No linter found (oxlint, biome, or eslint). Skipping linting.",
1723
+ onStart: () => hooks.emit("kubb:lint:start"),
1724
+ onEnd: () => hooks.emit("kubb:lint:end")
1725
+ }].filter(Boolean);
1726
+ for (const pass of toolPasses) await runToolPass({
1727
+ ...pass,
1666
1728
  configName: config.name,
1667
1729
  outputPath,
1668
1730
  logLevel: logLevel$2,
1669
1731
  hooks,
1670
- onStart: () => hooks.emit("kubb:lint:start"),
1671
- onEnd: () => hooks.emit("kubb:lint:end")
1732
+ makeSink
1672
1733
  });
1673
1734
  if (config.hooks) {
1674
1735
  await hooks.emit("kubb:hooks:start");
1675
1736
  await executeHooks({
1676
1737
  configHooks: config.hooks,
1677
- hooks
1738
+ hooks,
1739
+ makeSink
1678
1740
  });
1679
1741
  await hooks.emit("kubb:hooks:end");
1680
1742
  }
@@ -1686,68 +1748,80 @@ async function generate(options) {
1686
1748
  hrStart,
1687
1749
  pluginTimings
1688
1750
  });
1689
- await sendTelemetry(buildTelemetryEvent({
1690
- command: "generate",
1691
- kubbVersion: version,
1692
- plugins: Array.from(driver.plugins.values(), (p) => ({
1693
- name: p.name,
1694
- options: p.options
1695
- })),
1696
- hrStart,
1697
- filesCreated: files.length,
1698
- status: "success"
1699
- }));
1751
+ await reportTelemetry("success");
1752
+ return true;
1700
1753
  }
1701
- async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) {
1702
- const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info;
1703
- const hooks = new AsyncEventEmitter();
1704
- await setupLogger(hooks, { logLevel: logLevel$3 });
1754
+ async function checkForUpdate(hooks) {
1705
1755
  await executeIfOnline(async () => {
1706
1756
  try {
1707
- const latestVersion = (await (await fetch(KUBB_NPM_PACKAGE_URL)).json()).version;
1708
- if (latestVersion && version < latestVersion) await hooks.emit("kubb:version:new", {
1757
+ const data = await (await fetch(KUBB_NPM_PACKAGE_URL)).json();
1758
+ if (data.version && version < data.version) await hooks.emit("kubb:version:new", {
1709
1759
  currentVersion: version,
1710
- latestVersion
1760
+ latestVersion: data.version
1711
1761
  });
1712
1762
  } catch {}
1713
1763
  });
1764
+ }
1765
+ /**
1766
+ * Runs the full Kubb generation lifecycle for the given CLI options.
1767
+ * Sets up the logger, checks for a newer version, loads configs, and calls `generate` for each config entry.
1768
+ */
1769
+ async function run({ input, configPath, logLevel: logLevelKey, watch }) {
1770
+ const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info;
1771
+ const hooks = new AsyncEventEmitter();
1772
+ const makeSink = await setupLogger(hooks, { logLevel: logLevel$3 });
1773
+ await hooks.emit("kubb:lifecycle:start", { version });
1774
+ await checkForUpdate(hooks);
1714
1775
  try {
1715
- const result = await getCosmiConfig("kubb", configPath);
1716
- const configs = await getConfigs(result.config, { input });
1717
1776
  await hooks.emit("kubb:config:start");
1777
+ const { configs, configPath: resolvedConfigPath } = await getConfigs({
1778
+ configPath,
1779
+ input
1780
+ });
1781
+ const relativeConfigPath = path.relative(process$1.cwd(), resolvedConfigPath);
1718
1782
  await hooks.emit("kubb:info", {
1719
1783
  message: "Config loaded",
1720
- info: path.relative(process$1.cwd(), result.filepath)
1784
+ info: relativeConfigPath
1721
1785
  });
1722
1786
  await hooks.emit("kubb:success", {
1723
1787
  message: "Config loaded successfully",
1724
- info: path.relative(process$1.cwd(), result.filepath)
1788
+ info: relativeConfigPath
1725
1789
  });
1726
1790
  await hooks.emit("kubb:config:end", { configs });
1727
- await hooks.emit("kubb:lifecycle:start", { version });
1791
+ let anyFailed = false;
1728
1792
  for (const config of configs) if (isInputPath(config) && watch) await startWatcher([input || config.input.path], async (paths) => {
1729
- hooks.removeAll();
1730
1793
  await generate({
1731
1794
  input,
1732
1795
  config,
1733
1796
  logLevel: logLevel$3,
1734
- hooks
1797
+ hooks,
1798
+ makeSink
1735
1799
  });
1736
1800
  clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`));
1801
+ }, {
1802
+ info: (msg) => clack.log.info(msg),
1803
+ error: (msg) => clack.log.error(msg)
1737
1804
  });
1738
- else await generate({
1739
- input,
1740
- config,
1741
- logLevel: logLevel$3,
1742
- hooks
1743
- });
1805
+ else try {
1806
+ if (!await generate({
1807
+ input,
1808
+ config,
1809
+ logLevel: logLevel$3,
1810
+ hooks,
1811
+ makeSink
1812
+ })) anyFailed = true;
1813
+ } catch (configError) {
1814
+ await hooks.emit("kubb:error", { error: toError(configError) });
1815
+ anyFailed = true;
1816
+ }
1744
1817
  await hooks.emit("kubb:lifecycle:end");
1818
+ if (anyFailed) process$1.exit(1);
1745
1819
  } catch (error) {
1746
1820
  await hooks.emit("kubb:error", { error: toError(error) });
1747
1821
  process$1.exit(1);
1748
1822
  }
1749
1823
  }
1750
1824
  //#endregion
1751
- export { runGenerateCommand };
1825
+ export { run };
1752
1826
 
1753
- //# sourceMappingURL=generate-Dt_r0ELY.js.map
1827
+ //# sourceMappingURL=run-BryUpjjc.js.map