@kubb/cli 5.0.0-beta.1 → 5.0.0-beta.11

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-DB8Fr0U8.cjs +70 -0
  3. package/dist/agent-DB8Fr0U8.cjs.map +1 -0
  4. package/dist/agent-DcsBatCv.js +68 -0
  5. package/dist/agent-DcsBatCv.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-TL8zY_IT.cjs → generate-DVe4vPXT.cjs} +10 -4
  22. package/dist/generate-DVe4vPXT.cjs.map +1 -0
  23. package/dist/{generate-BaJRhbCS.js → generate-dhgVXAZM.js} +12 -6
  24. package/dist/generate-dhgVXAZM.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-DDBAAtNw.cjs +53 -0
  31. package/dist/init-DDBAAtNw.cjs.map +1 -0
  32. package/dist/init-DalNYdKX.js +53 -0
  33. package/dist/init-DalNYdKX.js.map +1 -0
  34. package/dist/mcp-CjLC0gfa.cjs +39 -0
  35. package/dist/mcp-CjLC0gfa.cjs.map +1 -0
  36. package/dist/mcp-qo6oTY1b.js +39 -0
  37. package/dist/mcp-qo6oTY1b.js.map +1 -0
  38. package/dist/package-BS53bjcw.js +6 -0
  39. package/dist/package-BS53bjcw.js.map +1 -0
  40. package/dist/{package-Cdo6lNjF.cjs → package-Dwr7GtJx.cjs} +2 -2
  41. package/dist/package-Dwr7GtJx.cjs.map +1 -0
  42. package/dist/{agent-Ev5hU5hH.js → run-BzpYYOQs.js} +53 -44
  43. package/dist/run-BzpYYOQs.js.map +1 -0
  44. package/dist/run-CCZ24VKk.js +51 -0
  45. package/dist/run-CCZ24VKk.js.map +1 -0
  46. package/dist/{init-eNRlotJK.js → run-CF97BWVa.js} +102 -147
  47. package/dist/run-CF97BWVa.js.map +1 -0
  48. package/dist/run-CQbj3ley.cjs +52 -0
  49. package/dist/run-CQbj3ley.cjs.map +1 -0
  50. package/dist/{generate-CuxArvEk.js → run-CdRxfPGM.js} +324 -341
  51. package/dist/run-CdRxfPGM.js.map +1 -0
  52. package/dist/{generate-UCP0qpDp.cjs → run-CqN9CaCO.cjs} +321 -338
  53. package/dist/run-CqN9CaCO.cjs.map +1 -0
  54. package/dist/run-D0hmRpHy.js +49 -0
  55. package/dist/run-D0hmRpHy.js.map +1 -0
  56. package/dist/{agent-B_pirbeB.cjs → run-DwdAwnLG.cjs} +51 -42
  57. package/dist/run-DwdAwnLG.cjs.map +1 -0
  58. package/dist/run-Lr0Ctnu0.cjs +50 -0
  59. package/dist/run-Lr0Ctnu0.cjs.map +1 -0
  60. package/dist/{init-CZ5Xq2Hd.cjs → run-YsoCk5we.cjs} +100 -145
  61. package/dist/run-YsoCk5we.cjs.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-C00u0BgS.js +26 -0
  70. package/dist/validate-C00u0BgS.js.map +1 -0
  71. package/dist/validate-D5HeJjHB.cjs +26 -0
  72. package/dist/validate-D5HeJjHB.cjs.map +1 -0
  73. package/package.json +22 -14
  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 +45 -43
  83. package/src/loggers/fileSystemLogger.ts +26 -13
  84. package/src/loggers/githubActionsLogger.ts +13 -25
  85. package/src/loggers/plainLogger.ts +12 -23
  86. package/src/loggers/types.ts +6 -0
  87. package/src/loggers/utils.ts +155 -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 +276 -0
  91. package/src/runners/generate/utils.ts +209 -0
  92. package/src/runners/init/run.ts +211 -0
  93. package/src/{utils/packageManager.ts → runners/init/utils.ts} +10 -0
  94. package/src/runners/mcp/run.ts +55 -0
  95. package/src/runners/validate/run.ts +63 -0
  96. package/src/{utils/telemetry.ts → telemetry.ts} +12 -5
  97. package/dist/agent-B_pirbeB.cjs.map +0 -1
  98. package/dist/agent-CUmEyiqY.cjs +0 -58
  99. package/dist/agent-CUmEyiqY.cjs.map +0 -1
  100. package/dist/agent-Ev5hU5hH.js.map +0 -1
  101. package/dist/agent-v_2S-bnN.js +0 -56
  102. package/dist/agent-v_2S-bnN.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-BaJRhbCS.js.map +0 -1
  108. package/dist/generate-CuxArvEk.js.map +0 -1
  109. package/dist/generate-TL8zY_IT.cjs.map +0 -1
  110. package/dist/generate-UCP0qpDp.cjs.map +0 -1
  111. package/dist/init-CZ5Xq2Hd.cjs.map +0 -1
  112. package/dist/init-DRR_YWIq.cjs +0 -25
  113. package/dist/init-DRR_YWIq.cjs.map +0 -1
  114. package/dist/init-DSnRd1RJ.js +0 -25
  115. package/dist/init-DSnRd1RJ.js.map +0 -1
  116. package/dist/init-eNRlotJK.js.map +0 -1
  117. package/dist/mcp-CLcDV4Jm.cjs +0 -41
  118. package/dist/mcp-CLcDV4Jm.cjs.map +0 -1
  119. package/dist/mcp-D7EIR9fR.js +0 -40
  120. package/dist/mcp-D7EIR9fR.js.map +0 -1
  121. package/dist/mcp-Dakxi9CL.js +0 -16
  122. package/dist/mcp-Dakxi9CL.js.map +0 -1
  123. package/dist/mcp-Dr_RY-hd.cjs +0 -16
  124. package/dist/mcp-Dr_RY-hd.cjs.map +0 -1
  125. package/dist/package-Cdo6lNjF.cjs.map +0 -1
  126. package/dist/package-DPooAj2l.js +0 -6
  127. package/dist/package-DPooAj2l.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-B1o-rY9o.js +0 -25
  131. package/dist/validate-B1o-rY9o.js.map +0 -1
  132. package/dist/validate-CXFY-mHL.cjs +0 -25
  133. package/dist/validate-CXFY-mHL.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-DPooAj2l.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-BS53bjcw.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,10 @@ 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
17
  import { Writable } from "node:stream";
19
18
  import { cosmiconfig } from "cosmiconfig";
20
- import { unrun } from "unrun";
19
+ import { createJiti } from "jiti";
20
+ import { NonZeroExitError, x } from "tinyexec";
21
21
  //#region ../../internals/utils/src/asyncEventEmitter.ts
22
22
  /**
23
23
  * Typed `EventEmitter` that awaits all async listeners before resolving.
@@ -486,100 +486,11 @@ async function detectLinter() {
486
486
  return null;
487
487
  }
488
488
  //#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
489
+ //#region src/loggers/clackLogger.ts
528
490
  /**
529
- * Executes a hook command, emits debug and completion events, and forwards output to an optional sink.
491
+ * Node.js `Writable` stream that forwards each chunk to a clack `taskLog` message.
492
+ * Used to pipe hook subprocess output into the clack task log UI.
530
493
  */
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
494
  var ClackWritable = class extends Writable {
584
495
  taskLog;
585
496
  constructor(taskLog, opts) {
@@ -591,8 +502,6 @@ var ClackWritable = class extends Writable {
591
502
  callback();
592
503
  }
593
504
  };
594
- //#endregion
595
- //#region src/loggers/clackLogger.ts
596
505
  /**
597
506
  * TTY logger with beautiful UI and progress indicators for local development.
598
507
  */
@@ -818,40 +727,10 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
818
727
  const text = getMessage("Lint completed");
819
728
  clack.outro(text);
820
729
  });
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
- }
730
+ context.on("kubb:hook:start", ({ command, args }) => {
731
+ if (logLevel$8 <= logLevel.silent) return;
732
+ const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} started`);
839
733
  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
- }
854
- });
855
734
  });
856
735
  context.on("kubb:hook:end", ({ command, args }) => {
857
736
  if (logLevel$8 <= logLevel.silent) return;
@@ -887,13 +766,28 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
887
766
  context.on("kubb:lifecycle:end", () => {
888
767
  reset();
889
768
  });
769
+ return (commandWithArgs) => {
770
+ if (logLevel$8 <= logLevel.silent) return {
771
+ onStdout: (s) => console.log(s),
772
+ onStderr: (s) => console.error(s)
773
+ };
774
+ const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel$8 >= logLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
775
+ const writable = new ClackWritable(logger);
776
+ return {
777
+ stream: true,
778
+ onLine: (line) => writable.write(line),
779
+ onStdout: (s) => logger.message(s),
780
+ onStderr: (s) => logger.error(s)
781
+ };
782
+ };
890
783
  }
891
784
  });
892
785
  //#endregion
893
786
  //#region src/loggers/fileSystemLogger.ts
894
787
  /**
895
788
  * 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.
789
+ *
790
+ * @note Logs are written on `kubb:lifecycle:end` or process exit. Cached logs may be lost if the process crashes before either event.
897
791
  */
898
792
  const fileSystemLogger = defineLogger({
899
793
  name: "filesystem",
@@ -918,29 +812,31 @@ const fileSystemLogger = defineLogger({
918
812
  const pathName = resolve(process$1.cwd(), ".kubb", baseName);
919
813
  if (!files[pathName]) files[pathName] = [];
920
814
  if (log.logs.length > 0) {
921
- const timestamp = log.date.toLocaleString();
922
- files[pathName].push(`[${timestamp}]\n${log.logs.join("\n")}`);
815
+ const prefix = `[${log.date.toLocaleString()}] `;
816
+ const indent = " ".repeat(prefix.length);
817
+ const [first, ...rest] = log.logs;
818
+ files[pathName].push([prefix + first, ...rest.map((line) => indent + line)].join("\n"));
923
819
  }
924
820
  }
925
- for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n\n"));
821
+ for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n"));
926
822
  return Object.keys(files);
927
823
  }
928
824
  context.on("kubb:info", ({ message, info }) => {
929
825
  state.cachedLogs.add({
930
826
  date: /* @__PURE__ */ new Date(),
931
- logs: [`ℹ ${message} ${info}`]
827
+ logs: [`ℹ ${[message, info].filter(Boolean).join(" ")}`]
932
828
  });
933
829
  });
934
830
  context.on("kubb:success", ({ message, info }) => {
935
831
  state.cachedLogs.add({
936
832
  date: /* @__PURE__ */ new Date(),
937
- logs: [`✓ ${message} ${info}`]
833
+ logs: [`✓ ${[message, info].filter(Boolean).join(" ")}`]
938
834
  });
939
835
  });
940
836
  context.on("kubb:warn", ({ message, info }) => {
941
837
  state.cachedLogs.add({
942
838
  date: /* @__PURE__ */ new Date(),
943
- logs: [`⚠ ${message} ${info}`]
839
+ logs: [`⚠ ${[message, info].filter(Boolean).join(" ")}`]
944
840
  });
945
841
  });
946
842
  context.on("kubb:error", ({ error }) => {
@@ -949,29 +845,30 @@ const fileSystemLogger = defineLogger({
949
845
  logs: [`✗ ${error.message}`, error.stack || "unknown stack"]
950
846
  });
951
847
  });
952
- context.on("kubb:debug", (message) => {
848
+ context.on("kubb:debug", ({ date, fileName, logs }) => {
953
849
  state.cachedLogs.add({
954
- date: /* @__PURE__ */ new Date(),
955
- logs: message.logs
850
+ date,
851
+ fileName,
852
+ logs
956
853
  });
957
854
  });
958
855
  context.on("kubb:plugin:start", ({ plugin }) => {
959
856
  state.cachedLogs.add({
960
857
  date: /* @__PURE__ */ new Date(),
961
- logs: [`Generating ${plugin.name}`]
858
+ logs: [`► Generating ${plugin.name}`]
962
859
  });
963
860
  });
964
861
  context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
965
862
  const durationStr = formatMs(duration);
966
863
  state.cachedLogs.add({
967
864
  date: /* @__PURE__ */ new Date(),
968
- logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`]
865
+ logs: [success ? `✓ ${plugin.name} completed in ${durationStr}` : `✗ ${plugin.name} failed in ${durationStr}`]
969
866
  });
970
867
  });
971
868
  context.on("kubb:files:processing:start", ({ files }) => {
972
869
  state.cachedLogs.add({
973
870
  date: /* @__PURE__ */ new Date(),
974
- logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)]
871
+ logs: [`► Writing ${files.length} files`, ...files.map((file) => ` ${file.path}`)]
975
872
  });
976
873
  });
977
874
  context.on("kubb:generation:end", async ({ config }) => {
@@ -1164,25 +1061,12 @@ const githubActionsLogger = defineLogger({
1164
1061
  console.log(text);
1165
1062
  if (state.currentConfigs.length === 1) closeGroup("Linting");
1166
1063
  });
1167
- context.on("kubb:hook:start", async ({ id, command, args }) => {
1064
+ context.on("kubb:hook:start", ({ command, args }) => {
1065
+ if (logLevel$7 <= logLevel.silent) return;
1168
1066
  const commandWithArgs = formatCommandWithArgs(command, args);
1169
1067
  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
- });
1068
+ if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
1069
+ console.log(text);
1186
1070
  });
1187
1071
  context.on("kubb:hook:end", ({ command, args }) => {
1188
1072
  if (logLevel$7 <= logLevel.silent) return;
@@ -1202,6 +1086,10 @@ const githubActionsLogger = defineLogger({
1202
1086
  context.on("kubb:lifecycle:end", () => {
1203
1087
  reset();
1204
1088
  });
1089
+ return (_commandWithArgs) => ({
1090
+ onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0,
1091
+ onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
1092
+ });
1205
1093
  }
1206
1094
  });
1207
1095
  //#endregion
@@ -1324,22 +1212,10 @@ const plainLogger = defineLogger({
1324
1212
  const text = getMessage("Lint completed");
1325
1213
  console.log(text);
1326
1214
  });
1327
- context.on("kubb:hook:start", async ({ id, command, args }) => {
1328
- 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
- });
1215
+ context.on("kubb:hook:start", ({ command, args }) => {
1216
+ if (logLevel$6 <= logLevel.silent) return;
1217
+ const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} started`);
1218
+ console.log(text);
1343
1219
  });
1344
1220
  context.on("kubb:hook:end", ({ command, args }) => {
1345
1221
  if (logLevel$6 <= logLevel.silent) return;
@@ -1359,6 +1235,10 @@ const plainLogger = defineLogger({
1359
1235
  console.log(summary.join("\n"));
1360
1236
  console.log(SUMMARY_SEPARATOR);
1361
1237
  });
1238
+ return (_commandWithArgs) => ({
1239
+ onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0,
1240
+ onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0
1241
+ });
1362
1242
  }
1363
1243
  });
1364
1244
  //#endregion
@@ -1413,124 +1293,233 @@ async function setupLogger(context, { logLevel: logLevel$5 }) {
1413
1293
  const type = detectLogger();
1414
1294
  const logger = logMapper[type];
1415
1295
  if (!logger) throw new Error(`Unknown adapter type: ${type}`);
1416
- const cleanup = await logger.install(context, { logLevel: logLevel$5 });
1296
+ const makeSink = await logger.install(context, { logLevel: logLevel$5 });
1417
1297
  if (logLevel$5 >= logLevel.debug) await fileSystemLogger.install(context, { logLevel: logLevel$5 });
1418
- return cleanup;
1298
+ return typeof makeSink === "function" ? makeSink : void 0;
1419
1299
  }
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
1300
+ /**
1301
+ * Builds the generation summary lines rendered in the end-of-run box.
1302
+ * Returns an array of styled strings, one per summary row.
1303
+ */
1304
+ function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
1305
+ const duration = formatHrtime(hrStart);
1306
+ const pluginsCount = config.plugins?.length ?? 0;
1307
+ const successCount = pluginsCount - failedPlugins.size;
1308
+ const meta = {
1309
+ plugins: status === "success" ? `${styleText("green", `${successCount} successful`)}, ${pluginsCount} total` : `${styleText("green", `${successCount} successful`)}, ${styleText("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
1310
+ pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
1311
+ filesCreated,
1312
+ time: styleText("green", duration),
1313
+ output: path.resolve(config.root, config.output.path)
1314
+ };
1315
+ const labels = {
1316
+ plugins: "Plugins:",
1317
+ failed: "Failed:",
1318
+ generated: "Generated:",
1319
+ pluginTimings: "Plugin Timings:",
1320
+ output: "Output:"
1321
+ };
1322
+ const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
1323
+ const summaryLines = [];
1324
+ summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
1325
+ if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
1326
+ summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
1327
+ if (pluginTimings && pluginTimings.size > 0) {
1328
+ const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
1329
+ summaryLines.push(`${labels.pluginTimings}`);
1330
+ sortedTimings.forEach(([name, time]) => {
1331
+ const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
1332
+ const barLength = Math.min(Math.ceil(time / 100), 10);
1333
+ const bar = styleText("dim", "█".repeat(barLength));
1334
+ summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
1444
1335
  });
1445
- await hookEndPromise;
1446
1336
  }
1337
+ summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
1338
+ return summaryLines;
1447
1339
  }
1448
1340
  //#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, {
1341
+ //#region src/runners/generate/utils.ts
1342
+ const jiti = createJiti(import.meta.url, {
1343
+ jsx: {
1344
+ runtime: "automatic",
1345
+ importSource: "@kubb/renderer-jsx"
1346
+ },
1347
+ moduleCache: false
1348
+ });
1349
+ const tsLoader = (configFile) => jiti.import(configFile, { default: true });
1350
+ const MODULE_NAME = "kubb";
1351
+ const BASE_SEARCH_PLACES = [
1352
+ "package.json",
1353
+ `.${MODULE_NAME}rc`,
1354
+ `.${MODULE_NAME}rc.json`,
1355
+ `.${MODULE_NAME}rc.yaml`,
1356
+ `.${MODULE_NAME}rc.yml`,
1357
+ `.${MODULE_NAME}rc.ts`,
1358
+ `.${MODULE_NAME}rc.mts`,
1359
+ `.${MODULE_NAME}rc.cts`,
1360
+ `.${MODULE_NAME}rc.js`,
1361
+ `.${MODULE_NAME}rc.mjs`,
1362
+ `.${MODULE_NAME}rc.cjs`,
1363
+ `${MODULE_NAME}.config.ts`,
1364
+ `${MODULE_NAME}.config.mts`,
1365
+ `${MODULE_NAME}.config.cts`,
1366
+ `${MODULE_NAME}.config.js`,
1367
+ `${MODULE_NAME}.config.mjs`,
1368
+ `${MODULE_NAME}.config.cjs`
1369
+ ];
1370
+ const SEARCH_PLACES = [
1371
+ "",
1372
+ ".config/",
1373
+ "configs/"
1374
+ ].flatMap((prefix) => BASE_SEARCH_PLACES.map((p) => `${prefix}${p}`));
1375
+ async function getCosmiConfig(configFile) {
1376
+ const explorer = cosmiconfig(MODULE_NAME, {
1492
1377
  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
- ],
1378
+ searchPlaces: SEARCH_PLACES,
1502
1379
  loaders: {
1503
1380
  ".ts": tsLoader,
1504
1381
  ".mts": tsLoader,
1505
1382
  ".cts": tsLoader
1506
1383
  }
1507
1384
  });
1385
+ let result;
1508
1386
  try {
1509
- result = config ? await explorer.load(config) : await explorer.search();
1387
+ result = configFile ? await explorer.load(configFile) : await explorer.search();
1510
1388
  } catch (error) {
1511
1389
  throw new Error("Config failed loading", { cause: error });
1512
1390
  }
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");
1391
+ 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
1392
  return result;
1515
1393
  }
1516
- //#endregion
1517
- //#region src/utils/watcher.ts
1518
- async function startWatcher(path, cb) {
1394
+ /**
1395
+ * Discovers the Kubb config via cosmiconfig and resolves it into a normalized array of configs.
1396
+ * Every config in the result is guaranteed to have a `plugins` array.
1397
+ */
1398
+ async function getConfigs({ configPath, input }) {
1399
+ const result = await getCosmiConfig(configPath);
1400
+ const resolved = await (typeof result.config === "function" ? result.config({ input }) : result.config);
1401
+ const userConfigs = Array.isArray(resolved) ? resolved : [resolved];
1402
+ return {
1403
+ configPath: result.filepath,
1404
+ configs: userConfigs.map((item) => ({
1405
+ ...item,
1406
+ plugins: item.plugins ?? []
1407
+ }))
1408
+ };
1409
+ }
1410
+ /**
1411
+ * Runs the `done` hooks defined in a Kubb config in sequence.
1412
+ */
1413
+ async function executeHooks({ configHooks, hooks, makeSink }) {
1414
+ const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
1415
+ for (const command of commands) {
1416
+ const [cmd, ...args] = tokenize(command);
1417
+ if (!cmd) continue;
1418
+ const hookId = createHash("sha256").update(command).digest("hex");
1419
+ const commandWithArgs = [cmd, ...args].join(" ");
1420
+ await hooks.emit("kubb:hook:start", {
1421
+ id: hookId,
1422
+ command: cmd,
1423
+ args
1424
+ });
1425
+ const { stream = false, onLine, onStdout, onStderr } = makeSink?.(commandWithArgs) ?? {};
1426
+ await runHook({
1427
+ id: hookId,
1428
+ command: cmd,
1429
+ args,
1430
+ commandWithArgs,
1431
+ context: hooks,
1432
+ stream,
1433
+ sink: {
1434
+ onLine,
1435
+ onStdout,
1436
+ onStderr
1437
+ }
1438
+ });
1439
+ }
1440
+ }
1441
+ async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
1442
+ const emitEnd = (success, error) => context.emit("kubb:hook:end", {
1443
+ command,
1444
+ args,
1445
+ id,
1446
+ success,
1447
+ error
1448
+ });
1449
+ try {
1450
+ const proc = x(command, [...args ?? []], {
1451
+ nodeOptions: { detached: process.platform !== "win32" },
1452
+ throwOnError: true
1453
+ });
1454
+ if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
1455
+ const result = await proc;
1456
+ await context.emit("kubb:debug", {
1457
+ date: /* @__PURE__ */ new Date(),
1458
+ logs: [result.stdout.trimEnd()]
1459
+ });
1460
+ await context.emit("kubb:success", { message: `${styleText("dim", commandWithArgs)} successfully executed` });
1461
+ await emitEnd(true, null);
1462
+ } catch (err) {
1463
+ if (!(err instanceof NonZeroExitError)) {
1464
+ const error = toError(err);
1465
+ await emitEnd(false, error);
1466
+ await context.emit("kubb:error", { error });
1467
+ return;
1468
+ }
1469
+ const stderr = err.output?.stderr ?? "";
1470
+ const stdout = err.output?.stdout ?? "";
1471
+ await context.emit("kubb:debug", {
1472
+ date: /* @__PURE__ */ new Date(),
1473
+ logs: [stdout, stderr].filter(Boolean)
1474
+ });
1475
+ if (stderr) sink?.onStderr?.(stderr);
1476
+ if (stdout) sink?.onStdout?.(stdout);
1477
+ const error = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
1478
+ await emitEnd(false, error);
1479
+ await context.emit("kubb:error", { error });
1480
+ }
1481
+ }
1482
+ /**
1483
+ * Starts a file watcher on the given paths and calls `cb` on any change.
1484
+ * Ignores `.git` and `node_modules` directories.
1485
+ */
1486
+ async function startWatcher(path, cb, log = {
1487
+ info: console.log,
1488
+ error: console.log
1489
+ }) {
1519
1490
  const { watch } = await import("chokidar");
1520
1491
  watch(path, {
1521
1492
  ignorePermissionErrors: true,
1522
1493
  ignored: WATCHER_IGNORED_PATHS
1523
1494
  }).on("all", async (type, file) => {
1524
- console.log(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
1495
+ log.info(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
1525
1496
  try {
1526
1497
  await cb(path);
1527
1498
  } catch (_e) {
1528
- console.log(styleText("red", "Watcher failed"));
1499
+ log.error(styleText("red", "Watcher failed"));
1529
1500
  }
1530
1501
  });
1531
1502
  }
1532
1503
  //#endregion
1533
- //#region src/runners/generate.ts
1504
+ //#region src/runners/generate/run.ts
1505
+ /**
1506
+ * Registers a one-shot `kubb:hook:end` listener for `hookId` BEFORE the caller emits `kubb:hook:start`,
1507
+ * avoiding the race where a synchronous emitter fires end before the listener is attached.
1508
+ */
1509
+ function waitForHookEnd(hooks, hookId, onSuccess, fallbackErrorMessage) {
1510
+ return new Promise((resolve, reject) => {
1511
+ const handler = (ctx) => {
1512
+ if (ctx.id !== hookId) return;
1513
+ hooks.off("kubb:hook:end", handler);
1514
+ if (!ctx.success) {
1515
+ reject(ctx.error ?? new Error(fallbackErrorMessage));
1516
+ return;
1517
+ }
1518
+ onSuccess().then(resolve).catch(reject);
1519
+ };
1520
+ hooks.on("kubb:hook:end", handler);
1521
+ });
1522
+ }
1534
1523
  async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, hooks, onStart, onEnd }) {
1535
1524
  await onStart();
1536
1525
  let resolvedTool = toolValue;
@@ -1545,24 +1534,14 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
1545
1534
  let toolError;
1546
1535
  if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) {
1547
1536
  const toolConfig = toolMap[resolvedTool];
1537
+ const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1538
+ const successMessage = [
1539
+ `${successPrefix} with ${styleText("dim", resolvedTool)}`,
1540
+ logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
1541
+ "successfully"
1542
+ ].filter(Boolean).join(" ");
1548
1543
  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
- });
1544
+ const hookEndPromise = waitForHookEnd(hooks, hookId, () => hooks.emit("kubb:success", { message: successMessage }), toolConfig.errorMessage);
1566
1545
  await hooks.emit("kubb:hook:start", {
1567
1546
  id: hookId,
1568
1547
  command: toolConfig.command,
@@ -1579,9 +1558,9 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
1579
1558
  if (toolError) throw toolError;
1580
1559
  }
1581
1560
  async function generate(options) {
1582
- const { input, hooks, logLevel: logLevel$2 } = options;
1561
+ const { input, hooks, logLevel: logLevel$2, makeSink } = options;
1583
1562
  const hrStart = process$1.hrtime();
1584
- const inputPath = input ?? ("path" in options.config.input ? options.config.input.path : void 0);
1563
+ const inputPath = input ?? (options.config.input && "path" in options.config.input ? options.config.input.path : void 0);
1585
1564
  const config = {
1586
1565
  ...options.config,
1587
1566
  input: inputPath ? {
@@ -1603,13 +1582,24 @@ async function generate(options) {
1603
1582
  });
1604
1583
  const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild();
1605
1584
  await hooks.emit("kubb:info", { message: "Load summary" });
1585
+ const telemetryPlugins = Array.from(driver.plugins.values(), (p) => ({
1586
+ name: p.name,
1587
+ options: p.options
1588
+ }));
1589
+ const reportTelemetry = (status) => sendTelemetry(buildTelemetryEvent({
1590
+ command: "generate",
1591
+ kubbVersion: version,
1592
+ plugins: telemetryPlugins,
1593
+ hrStart,
1594
+ filesCreated: files.length,
1595
+ status
1596
+ }));
1606
1597
  if (failedPlugins.size > 0 || error) {
1607
- const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean);
1598
+ const allErrors = [error, ...Array.from(failedPlugins, (it) => it.error)].filter(Boolean);
1608
1599
  for (const err of allErrors) await hooks.emit("kubb:error", { error: err });
1609
1600
  await hooks.emit("kubb:generation:end", {
1610
1601
  config,
1611
- files,
1612
- sources: kubb.sources
1602
+ storage: kubb.storage
1613
1603
  });
1614
1604
  await hooks.emit("kubb:generation:summary", {
1615
1605
  config,
@@ -1619,62 +1609,50 @@ async function generate(options) {
1619
1609
  hrStart,
1620
1610
  pluginTimings: logLevel$2 >= logLevel.verbose ? pluginTimings : void 0
1621
1611
  });
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
- }));
1612
+ await reportTelemetry("failed");
1633
1613
  process$1.exit(1);
1634
1614
  }
1635
1615
  await hooks.emit("kubb:success", {
1636
- message: "Generation successfully",
1616
+ message: "Generation succeeded",
1637
1617
  info: inputPath
1638
1618
  });
1639
1619
  await hooks.emit("kubb:generation:end", {
1640
1620
  config,
1641
- files,
1642
- sources: kubb.sources
1621
+ storage: kubb.storage
1643
1622
  });
1644
1623
  const outputPath = path.resolve(config.root, config.output.path);
1645
- if (config.output.format) await runToolPass({
1624
+ const toolPasses = [config.output.format && {
1646
1625
  toolValue: config.output.format,
1647
1626
  detect: detectFormatter,
1648
1627
  toolMap: formatters,
1649
1628
  toolLabel: "formatter",
1650
1629
  successPrefix: "Formatting",
1651
1630
  noToolMessage: "No formatter found (oxfmt, biome, or prettier). Skipping formatting.",
1652
- configName: config.name,
1653
- outputPath,
1654
- logLevel: logLevel$2,
1655
- hooks,
1656
1631
  onStart: () => hooks.emit("kubb:format:start"),
1657
1632
  onEnd: () => hooks.emit("kubb:format:end")
1658
- });
1659
- if (config.output.lint) await runToolPass({
1633
+ }, config.output.lint && {
1660
1634
  toolValue: config.output.lint,
1661
1635
  detect: detectLinter,
1662
1636
  toolMap: linters,
1663
1637
  toolLabel: "linter",
1664
1638
  successPrefix: "Linting",
1665
1639
  noToolMessage: "No linter found (oxlint, biome, or eslint). Skipping linting.",
1640
+ onStart: () => hooks.emit("kubb:lint:start"),
1641
+ onEnd: () => hooks.emit("kubb:lint:end")
1642
+ }].filter(Boolean);
1643
+ for (const pass of toolPasses) await runToolPass({
1644
+ ...pass,
1666
1645
  configName: config.name,
1667
1646
  outputPath,
1668
1647
  logLevel: logLevel$2,
1669
- hooks,
1670
- onStart: () => hooks.emit("kubb:lint:start"),
1671
- onEnd: () => hooks.emit("kubb:lint:end")
1648
+ hooks
1672
1649
  });
1673
1650
  if (config.hooks) {
1674
1651
  await hooks.emit("kubb:hooks:start");
1675
1652
  await executeHooks({
1676
1653
  configHooks: config.hooks,
1677
- hooks
1654
+ hooks,
1655
+ makeSink
1678
1656
  });
1679
1657
  await hooks.emit("kubb:hooks:end");
1680
1658
  }
@@ -1686,42 +1664,42 @@ async function generate(options) {
1686
1664
  hrStart,
1687
1665
  pluginTimings
1688
1666
  });
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
- }));
1667
+ await reportTelemetry("success");
1700
1668
  }
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 });
1669
+ async function checkForUpdate(hooks) {
1705
1670
  await executeIfOnline(async () => {
1706
1671
  try {
1707
- const latestVersion = (await (await fetch(KUBB_NPM_PACKAGE_URL)).json()).version;
1708
- if (latestVersion && version < latestVersion) await hooks.emit("kubb:version:new", {
1672
+ const data = await (await fetch(KUBB_NPM_PACKAGE_URL)).json();
1673
+ if (data.version && version < data.version) await hooks.emit("kubb:version:new", {
1709
1674
  currentVersion: version,
1710
- latestVersion
1675
+ latestVersion: data.version
1711
1676
  });
1712
1677
  } catch {}
1713
1678
  });
1679
+ }
1680
+ /**
1681
+ * Runs the full Kubb generation lifecycle for the given CLI options.
1682
+ * Sets up the logger, checks for a newer version, loads configs, and calls `generate` for each config entry.
1683
+ */
1684
+ async function run({ input, configPath, logLevel: logLevelKey, watch }) {
1685
+ const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info;
1686
+ const hooks = new AsyncEventEmitter();
1687
+ const makeSink = await setupLogger(hooks, { logLevel: logLevel$3 });
1688
+ await checkForUpdate(hooks);
1714
1689
  try {
1715
- const result = await getCosmiConfig("kubb", configPath);
1716
- const configs = await getConfigs(result.config, { input });
1690
+ const { configs, configPath: resolvedConfigPath } = await getConfigs({
1691
+ configPath,
1692
+ input
1693
+ });
1694
+ const relativeConfigPath = path.relative(process$1.cwd(), resolvedConfigPath);
1717
1695
  await hooks.emit("kubb:config:start");
1718
1696
  await hooks.emit("kubb:info", {
1719
1697
  message: "Config loaded",
1720
- info: path.relative(process$1.cwd(), result.filepath)
1698
+ info: relativeConfigPath
1721
1699
  });
1722
1700
  await hooks.emit("kubb:success", {
1723
1701
  message: "Config loaded successfully",
1724
- info: path.relative(process$1.cwd(), result.filepath)
1702
+ info: relativeConfigPath
1725
1703
  });
1726
1704
  await hooks.emit("kubb:config:end", { configs });
1727
1705
  await hooks.emit("kubb:lifecycle:start", { version });
@@ -1731,15 +1709,20 @@ async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, wa
1731
1709
  input,
1732
1710
  config,
1733
1711
  logLevel: logLevel$3,
1734
- hooks
1712
+ hooks,
1713
+ makeSink
1735
1714
  });
1736
1715
  clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`));
1716
+ }, {
1717
+ info: (msg) => clack.log.info(msg),
1718
+ error: (msg) => clack.log.error(msg)
1737
1719
  });
1738
1720
  else await generate({
1739
1721
  input,
1740
1722
  config,
1741
1723
  logLevel: logLevel$3,
1742
- hooks
1724
+ hooks,
1725
+ makeSink
1743
1726
  });
1744
1727
  await hooks.emit("kubb:lifecycle:end");
1745
1728
  } catch (error) {
@@ -1748,6 +1731,6 @@ async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, wa
1748
1731
  }
1749
1732
  }
1750
1733
  //#endregion
1751
- export { runGenerateCommand };
1734
+ export { run };
1752
1735
 
1753
- //# sourceMappingURL=generate-CuxArvEk.js.map
1736
+ //# sourceMappingURL=run-CdRxfPGM.js.map