@kubb/cli 5.0.0-beta.75 → 5.0.0-beta.8

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-DPLjUza1.cjs +70 -0
  3. package/dist/agent-DPLjUza1.cjs.map +1 -0
  4. package/dist/agent-DTeGTNl7.js +68 -0
  5. package/dist/agent-DTeGTNl7.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-DDCwNQNo.cjs → generate-CiBa5UMJ.cjs} +10 -4
  22. package/dist/generate-CiBa5UMJ.cjs.map +1 -0
  23. package/dist/{generate-YPtfjsg4.js → generate-DzC1brc9.js} +12 -6
  24. package/dist/generate-DzC1brc9.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-BVYkUQ-b.cjs +53 -0
  31. package/dist/init-BVYkUQ-b.cjs.map +1 -0
  32. package/dist/init-BYlb-ua0.js +53 -0
  33. package/dist/init-BYlb-ua0.js.map +1 -0
  34. package/dist/mcp-Bm2Q7YdS.js +39 -0
  35. package/dist/mcp-Bm2Q7YdS.js.map +1 -0
  36. package/dist/mcp-CiNoagVX.cjs +39 -0
  37. package/dist/mcp-CiNoagVX.cjs.map +1 -0
  38. package/dist/{package-D5arPDnh.cjs → package-BvBzYG6c.cjs} +2 -2
  39. package/dist/package-BvBzYG6c.cjs.map +1 -0
  40. package/dist/package-s8PvCnk-.js +6 -0
  41. package/dist/package-s8PvCnk-.js.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-Cg8yufrw.js → run-CXTVu3Wl.js} +322 -337
  51. package/dist/run-CXTVu3Wl.js.map +1 -0
  52. package/dist/run-D0hmRpHy.js +49 -0
  53. package/dist/run-D0hmRpHy.js.map +1 -0
  54. package/dist/{agent-B_pirbeB.cjs → run-DwdAwnLG.cjs} +51 -42
  55. package/dist/run-DwdAwnLG.cjs.map +1 -0
  56. package/dist/run-Lr0Ctnu0.cjs +50 -0
  57. package/dist/run-Lr0Ctnu0.cjs.map +1 -0
  58. package/dist/{generate-K8MJ9aQF.cjs → run-QyqW2rPC.cjs} +319 -334
  59. package/dist/run-QyqW2rPC.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-BYuHYBhg.cjs +26 -0
  70. package/dist/validate-BYuHYBhg.cjs.map +1 -0
  71. package/dist/validate-Da2LIDVc.js +26 -0
  72. package/dist/validate-Da2LIDVc.js.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-BEgI2HXH.cjs +0 -58
  98. package/dist/agent-BEgI2HXH.cjs.map +0 -1
  99. package/dist/agent-B_pirbeB.cjs.map +0 -1
  100. package/dist/agent-CTdJEHEs.js +0 -56
  101. package/dist/agent-CTdJEHEs.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-Cg8yufrw.js.map +0 -1
  108. package/dist/generate-DDCwNQNo.cjs.map +0 -1
  109. package/dist/generate-K8MJ9aQF.cjs.map +0 -1
  110. package/dist/generate-YPtfjsg4.js.map +0 -1
  111. package/dist/init-Bu95ML_u.cjs +0 -25
  112. package/dist/init-Bu95ML_u.cjs.map +0 -1
  113. package/dist/init-CZ5Xq2Hd.cjs.map +0 -1
  114. package/dist/init-eNRlotJK.js.map +0 -1
  115. package/dist/init-ooJeOBGt.js +0 -25
  116. package/dist/init-ooJeOBGt.js.map +0 -1
  117. package/dist/mcp-C-d5N1wZ.js +0 -16
  118. package/dist/mcp-C-d5N1wZ.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-Dpu8vzzj.cjs +0 -16
  124. package/dist/mcp-Dpu8vzzj.cjs.map +0 -1
  125. package/dist/package-D5arPDnh.cjs.map +0 -1
  126. package/dist/package-DqZsMLZ9.js +0 -6
  127. package/dist/package-DqZsMLZ9.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-CIR3_lZI.js +0 -25
  131. package/dist/validate-CIR3_lZI.js.map +0 -1
  132. package/dist/validate-DcqUb4DM.cjs +0 -25
  133. package/dist/validate-DcqUb4DM.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
1
  const require_chunk = require("./chunk-ByKO4r7w.cjs");
2
2
  const require_errors = require("./errors-CLCjoSg0.cjs");
3
- const require_telemetry = require("./telemetry-DN95_2pF.cjs");
3
+ const require_telemetry = require("./telemetry-B2iWkY5e.cjs");
4
4
  const require_shell = require("./shell-475fQKaX.cjs");
5
- const require_package = require("./package-D5arPDnh.cjs");
6
- const require_constants = require("./constants-CnDXa1R6.cjs");
5
+ const require_package = require("./package-BvBzYG6c.cjs");
6
+ const require_constants = require("./constants-BINTA5VZ.cjs");
7
7
  let node_util = require("node:util");
8
8
  let node_events = require("node:events");
9
9
  let node_crypto = require("node:crypto");
@@ -17,10 +17,10 @@ node_process = require_chunk.__toESM(node_process, 1);
17
17
  let _clack_prompts = require("@clack/prompts");
18
18
  _clack_prompts = require_chunk.__toESM(_clack_prompts, 1);
19
19
  let _kubb_core = require("@kubb/core");
20
- let tinyexec = require("tinyexec");
21
20
  let node_stream = require("node:stream");
22
21
  let cosmiconfig = require("cosmiconfig");
23
- let unrun = require("unrun");
22
+ let jiti = require("jiti");
23
+ let tinyexec = require("tinyexec");
24
24
  //#region ../../internals/utils/src/asyncEventEmitter.ts
25
25
  /**
26
26
  * Typed `EventEmitter` that awaits all async listeners before resolving.
@@ -489,100 +489,11 @@ async function detectLinter() {
489
489
  return null;
490
490
  }
491
491
  //#endregion
492
- //#region src/utils/getSummary.ts
493
- function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
494
- const duration = formatHrtime(hrStart);
495
- const pluginsCount = config.plugins?.length ?? 0;
496
- const successCount = pluginsCount - failedPlugins.size;
497
- const meta = {
498
- plugins: status === "success" ? `${(0, node_util.styleText)("green", `${successCount} successful`)}, ${pluginsCount} total` : `${(0, node_util.styleText)("green", `${successCount} successful`)}, ${(0, node_util.styleText)("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
499
- pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
500
- filesCreated,
501
- time: (0, node_util.styleText)("green", duration),
502
- output: node_path.default.resolve(config.root, config.output.path)
503
- };
504
- const labels = {
505
- plugins: "Plugins:",
506
- failed: "Failed:",
507
- generated: "Generated:",
508
- pluginTimings: "Plugin Timings:",
509
- output: "Output:"
510
- };
511
- const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
512
- const summaryLines = [];
513
- summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
514
- if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
515
- summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
516
- if (pluginTimings && pluginTimings.size > 0) {
517
- const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
518
- summaryLines.push(`${labels.pluginTimings}`);
519
- sortedTimings.forEach(([name, time]) => {
520
- const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
521
- const barLength = Math.min(Math.ceil(time / 100), 10);
522
- const bar = (0, node_util.styleText)("dim", "█".repeat(barLength));
523
- summaryLines.push(`${(0, node_util.styleText)("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
524
- });
525
- }
526
- summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
527
- return summaryLines;
528
- }
529
- //#endregion
530
- //#region src/utils/runHook.ts
492
+ //#region src/loggers/clackLogger.ts
531
493
  /**
532
- * Executes a hook command, emits debug and completion events, and forwards output to an optional sink.
494
+ * Node.js `Writable` stream that forwards each chunk to a clack `taskLog` message.
495
+ * Used to pipe hook subprocess output into the clack task log UI.
533
496
  */
534
- async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
535
- try {
536
- const proc = (0, tinyexec.x)(command, [...args ?? []], {
537
- nodeOptions: { detached: process.platform !== "win32" },
538
- throwOnError: true
539
- });
540
- if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
541
- const result = await proc;
542
- await context.emit("kubb:debug", {
543
- date: /* @__PURE__ */ new Date(),
544
- logs: [result.stdout.trimEnd()]
545
- });
546
- await context.emit("kubb:hook:end", {
547
- command,
548
- args,
549
- id,
550
- success: true,
551
- error: null
552
- });
553
- } catch (err) {
554
- if (!(err instanceof tinyexec.NonZeroExitError)) {
555
- await context.emit("kubb:hook:end", {
556
- command,
557
- args,
558
- id,
559
- success: false,
560
- error: require_errors.toError(err)
561
- });
562
- await context.emit("kubb:error", { error: require_errors.toError(err) });
563
- return;
564
- }
565
- const stderr = err.output?.stderr ?? "";
566
- const stdout = err.output?.stdout ?? "";
567
- await context.emit("kubb:debug", {
568
- date: /* @__PURE__ */ new Date(),
569
- logs: [stdout, stderr].filter(Boolean)
570
- });
571
- if (stderr) sink?.onStderr?.(stderr);
572
- if (stdout) sink?.onStdout?.(stdout);
573
- const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
574
- await context.emit("kubb:hook:end", {
575
- command,
576
- args,
577
- id,
578
- success: false,
579
- error: errorMessage
580
- });
581
- await context.emit("kubb:error", { error: errorMessage });
582
- }
583
- }
584
- //#endregion
585
- //#region src/utils/Writables.ts
586
497
  var ClackWritable = class extends node_stream.Writable {
587
498
  taskLog;
588
499
  constructor(taskLog, opts) {
@@ -594,8 +505,6 @@ var ClackWritable = class extends node_stream.Writable {
594
505
  callback();
595
506
  }
596
507
  };
597
- //#endregion
598
- //#region src/loggers/clackLogger.ts
599
508
  /**
600
509
  * TTY logger with beautiful UI and progress indicators for local development.
601
510
  */
@@ -821,40 +730,10 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
821
730
  const text = getMessage("Lint completed");
822
731
  _clack_prompts.outro(text);
823
732
  });
824
- context.on("kubb:hook:start", async ({ id, command, args }) => {
825
- const commandWithArgs = formatCommandWithArgs(command, args);
826
- const text = getMessage(`Hook ${(0, node_util.styleText)("dim", commandWithArgs)} started`);
827
- if (!id) return;
828
- if (logLevel <= _kubb_core.logLevel.silent) {
829
- await runHook({
830
- id,
831
- command,
832
- args,
833
- commandWithArgs,
834
- context,
835
- sink: {
836
- onStderr: (s) => console.error(s),
837
- onStdout: (s) => console.log(s)
838
- }
839
- });
840
- return;
841
- }
733
+ context.on("kubb:hook:start", ({ command, args }) => {
734
+ if (logLevel <= _kubb_core.logLevel.silent) return;
735
+ const text = getMessage(`Hook ${(0, node_util.styleText)("dim", formatCommandWithArgs(command, args))} started`);
842
736
  _clack_prompts.intro(text);
843
- const logger = _clack_prompts.taskLog({ title: getMessage(["Executing hook", logLevel >= _kubb_core.logLevel.info ? (0, node_util.styleText)("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
844
- const writable = new ClackWritable(logger);
845
- await runHook({
846
- id,
847
- command,
848
- args,
849
- commandWithArgs,
850
- context,
851
- stream: true,
852
- sink: {
853
- onLine: (line) => writable.write(line),
854
- onStderr: (s) => logger.error(s),
855
- onStdout: (s) => logger.message(s)
856
- }
857
- });
858
737
  });
859
738
  context.on("kubb:hook:end", ({ command, args }) => {
860
739
  if (logLevel <= _kubb_core.logLevel.silent) return;
@@ -890,13 +769,28 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
890
769
  context.on("kubb:lifecycle:end", () => {
891
770
  reset();
892
771
  });
772
+ return (commandWithArgs) => {
773
+ if (logLevel <= _kubb_core.logLevel.silent) return {
774
+ onStdout: (s) => console.log(s),
775
+ onStderr: (s) => console.error(s)
776
+ };
777
+ const logger = _clack_prompts.taskLog({ title: getMessage(["Executing hook", logLevel >= _kubb_core.logLevel.info ? (0, node_util.styleText)("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
778
+ const writable = new ClackWritable(logger);
779
+ return {
780
+ stream: true,
781
+ onLine: (line) => writable.write(line),
782
+ onStdout: (s) => logger.message(s),
783
+ onStderr: (s) => logger.error(s)
784
+ };
785
+ };
893
786
  }
894
787
  });
895
788
  //#endregion
896
789
  //#region src/loggers/fileSystemLogger.ts
897
790
  /**
898
791
  * FileSystem logger that captures debug events and writes them to `.kubb` directory files.
899
- * Note: Logs write on `lifecycle:end` or process exit. Cached logs may be lost if the process crashes before these events.
792
+ *
793
+ * @note Logs are written on `kubb:lifecycle:end` or process exit. Cached logs may be lost if the process crashes before either event.
900
794
  */
901
795
  const fileSystemLogger = (0, _kubb_core.defineLogger)({
902
796
  name: "filesystem",
@@ -921,29 +815,31 @@ const fileSystemLogger = (0, _kubb_core.defineLogger)({
921
815
  const pathName = (0, node_path.resolve)(node_process.default.cwd(), ".kubb", baseName);
922
816
  if (!files[pathName]) files[pathName] = [];
923
817
  if (log.logs.length > 0) {
924
- const timestamp = log.date.toLocaleString();
925
- files[pathName].push(`[${timestamp}]\n${log.logs.join("\n")}`);
818
+ const prefix = `[${log.date.toLocaleString()}] `;
819
+ const indent = " ".repeat(prefix.length);
820
+ const [first, ...rest] = log.logs;
821
+ files[pathName].push([prefix + first, ...rest.map((line) => indent + line)].join("\n"));
926
822
  }
927
823
  }
928
- for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n\n"));
824
+ for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n"));
929
825
  return Object.keys(files);
930
826
  }
931
827
  context.on("kubb:info", ({ message, info }) => {
932
828
  state.cachedLogs.add({
933
829
  date: /* @__PURE__ */ new Date(),
934
- logs: [`ℹ ${message} ${info}`]
830
+ logs: [`ℹ ${[message, info].filter(Boolean).join(" ")}`]
935
831
  });
936
832
  });
937
833
  context.on("kubb:success", ({ message, info }) => {
938
834
  state.cachedLogs.add({
939
835
  date: /* @__PURE__ */ new Date(),
940
- logs: [`✓ ${message} ${info}`]
836
+ logs: [`✓ ${[message, info].filter(Boolean).join(" ")}`]
941
837
  });
942
838
  });
943
839
  context.on("kubb:warn", ({ message, info }) => {
944
840
  state.cachedLogs.add({
945
841
  date: /* @__PURE__ */ new Date(),
946
- logs: [`⚠ ${message} ${info}`]
842
+ logs: [`⚠ ${[message, info].filter(Boolean).join(" ")}`]
947
843
  });
948
844
  });
949
845
  context.on("kubb:error", ({ error }) => {
@@ -952,29 +848,30 @@ const fileSystemLogger = (0, _kubb_core.defineLogger)({
952
848
  logs: [`✗ ${error.message}`, error.stack || "unknown stack"]
953
849
  });
954
850
  });
955
- context.on("kubb:debug", (message) => {
851
+ context.on("kubb:debug", ({ date, fileName, logs }) => {
956
852
  state.cachedLogs.add({
957
- date: /* @__PURE__ */ new Date(),
958
- logs: message.logs
853
+ date,
854
+ fileName,
855
+ logs
959
856
  });
960
857
  });
961
858
  context.on("kubb:plugin:start", ({ plugin }) => {
962
859
  state.cachedLogs.add({
963
860
  date: /* @__PURE__ */ new Date(),
964
- logs: [`Generating ${plugin.name}`]
861
+ logs: [`► Generating ${plugin.name}`]
965
862
  });
966
863
  });
967
864
  context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
968
865
  const durationStr = formatMs(duration);
969
866
  state.cachedLogs.add({
970
867
  date: /* @__PURE__ */ new Date(),
971
- logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`]
868
+ logs: [success ? `✓ ${plugin.name} completed in ${durationStr}` : `✗ ${plugin.name} failed in ${durationStr}`]
972
869
  });
973
870
  });
974
871
  context.on("kubb:files:processing:start", ({ files }) => {
975
872
  state.cachedLogs.add({
976
873
  date: /* @__PURE__ */ new Date(),
977
- logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)]
874
+ logs: [`► Writing ${files.length} files`, ...files.map((file) => ` ${file.path}`)]
978
875
  });
979
876
  });
980
877
  context.on("kubb:generation:end", async ({ config }) => {
@@ -1167,25 +1064,12 @@ const githubActionsLogger = (0, _kubb_core.defineLogger)({
1167
1064
  console.log(text);
1168
1065
  if (state.currentConfigs.length === 1) closeGroup("Linting");
1169
1066
  });
1170
- context.on("kubb:hook:start", async ({ id, command, args }) => {
1067
+ context.on("kubb:hook:start", ({ command, args }) => {
1068
+ if (logLevel <= _kubb_core.logLevel.silent) return;
1171
1069
  const commandWithArgs = formatCommandWithArgs(command, args);
1172
1070
  const text = getMessage(`Hook ${(0, node_util.styleText)("dim", commandWithArgs)} started`);
1173
- if (logLevel > _kubb_core.logLevel.silent) {
1174
- if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
1175
- console.log(text);
1176
- }
1177
- if (!id) return;
1178
- await runHook({
1179
- id,
1180
- command,
1181
- args,
1182
- commandWithArgs,
1183
- context,
1184
- sink: {
1185
- onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0,
1186
- onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
1187
- }
1188
- });
1071
+ if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
1072
+ console.log(text);
1189
1073
  });
1190
1074
  context.on("kubb:hook:end", ({ command, args }) => {
1191
1075
  if (logLevel <= _kubb_core.logLevel.silent) return;
@@ -1205,6 +1089,10 @@ const githubActionsLogger = (0, _kubb_core.defineLogger)({
1205
1089
  context.on("kubb:lifecycle:end", () => {
1206
1090
  reset();
1207
1091
  });
1092
+ return (_commandWithArgs) => ({
1093
+ onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0,
1094
+ onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
1095
+ });
1208
1096
  }
1209
1097
  });
1210
1098
  //#endregion
@@ -1327,22 +1215,10 @@ const plainLogger = (0, _kubb_core.defineLogger)({
1327
1215
  const text = getMessage("Lint completed");
1328
1216
  console.log(text);
1329
1217
  });
1330
- context.on("kubb:hook:start", async ({ id, command, args }) => {
1331
- const commandWithArgs = formatCommandWithArgs(command, args);
1332
- const text = getMessage(`Hook ${commandWithArgs} started`);
1333
- if (logLevel > _kubb_core.logLevel.silent) console.log(text);
1334
- if (!id) return;
1335
- await runHook({
1336
- id,
1337
- command,
1338
- args,
1339
- commandWithArgs,
1340
- context,
1341
- sink: {
1342
- onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0,
1343
- onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(s) : void 0
1344
- }
1345
- });
1218
+ context.on("kubb:hook:start", ({ command, args }) => {
1219
+ if (logLevel <= _kubb_core.logLevel.silent) return;
1220
+ const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} started`);
1221
+ console.log(text);
1346
1222
  });
1347
1223
  context.on("kubb:hook:end", ({ command, args }) => {
1348
1224
  if (logLevel <= _kubb_core.logLevel.silent) return;
@@ -1362,6 +1238,10 @@ const plainLogger = (0, _kubb_core.defineLogger)({
1362
1238
  console.log(summary.join("\n"));
1363
1239
  console.log(require_constants.SUMMARY_SEPARATOR);
1364
1240
  });
1241
+ return (_commandWithArgs) => ({
1242
+ onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0,
1243
+ onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(s) : void 0
1244
+ });
1365
1245
  }
1366
1246
  });
1367
1247
  //#endregion
@@ -1416,124 +1296,233 @@ async function setupLogger(context, { logLevel }) {
1416
1296
  const type = detectLogger();
1417
1297
  const logger = logMapper[type];
1418
1298
  if (!logger) throw new Error(`Unknown adapter type: ${type}`);
1419
- const cleanup = await logger.install(context, { logLevel });
1299
+ const makeSink = await logger.install(context, { logLevel });
1420
1300
  if (logLevel >= _kubb_core.logLevel.debug) await fileSystemLogger.install(context, { logLevel });
1421
- return cleanup;
1301
+ return typeof makeSink === "function" ? makeSink : void 0;
1422
1302
  }
1423
- //#endregion
1424
- //#region src/utils/executeHooks.ts
1425
- async function executeHooks({ configHooks, hooks }) {
1426
- const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
1427
- for (const command of commands) {
1428
- const [cmd, ...args] = require_shell.tokenize(command);
1429
- if (!cmd) continue;
1430
- const hookId = (0, node_crypto.createHash)("sha256").update(command).digest("hex");
1431
- const hookEndPromise = new Promise((resolve, reject) => {
1432
- const handler = (ctx) => {
1433
- if (ctx.id !== hookId) return;
1434
- hooks.off("kubb:hook:end", handler);
1435
- if (!ctx.success) {
1436
- reject(ctx.error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`));
1437
- return;
1438
- }
1439
- hooks.emit("kubb:success", { message: `${(0, node_util.styleText)("dim", command)} successfully executed` }).then(resolve).catch(reject);
1440
- };
1441
- hooks.on("kubb:hook:end", handler);
1442
- });
1443
- await hooks.emit("kubb:hook:start", {
1444
- id: hookId,
1445
- command: cmd,
1446
- args
1303
+ /**
1304
+ * Builds the generation summary lines rendered in the end-of-run box.
1305
+ * Returns an array of styled strings, one per summary row.
1306
+ */
1307
+ function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
1308
+ const duration = formatHrtime(hrStart);
1309
+ const pluginsCount = config.plugins?.length ?? 0;
1310
+ const successCount = pluginsCount - failedPlugins.size;
1311
+ const meta = {
1312
+ plugins: status === "success" ? `${(0, node_util.styleText)("green", `${successCount} successful`)}, ${pluginsCount} total` : `${(0, node_util.styleText)("green", `${successCount} successful`)}, ${(0, node_util.styleText)("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
1313
+ pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
1314
+ filesCreated,
1315
+ time: (0, node_util.styleText)("green", duration),
1316
+ output: node_path.default.resolve(config.root, config.output.path)
1317
+ };
1318
+ const labels = {
1319
+ plugins: "Plugins:",
1320
+ failed: "Failed:",
1321
+ generated: "Generated:",
1322
+ pluginTimings: "Plugin Timings:",
1323
+ output: "Output:"
1324
+ };
1325
+ const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
1326
+ const summaryLines = [];
1327
+ summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
1328
+ if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
1329
+ summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
1330
+ if (pluginTimings && pluginTimings.size > 0) {
1331
+ const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
1332
+ summaryLines.push(`${labels.pluginTimings}`);
1333
+ sortedTimings.forEach(([name, time]) => {
1334
+ const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
1335
+ const barLength = Math.min(Math.ceil(time / 100), 10);
1336
+ const bar = (0, node_util.styleText)("dim", "█".repeat(barLength));
1337
+ summaryLines.push(`${(0, node_util.styleText)("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
1447
1338
  });
1448
- await hookEndPromise;
1449
1339
  }
1340
+ summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
1341
+ return summaryLines;
1450
1342
  }
1451
1343
  //#endregion
1452
- //#region src/utils/getConfig.ts
1453
- async function getConfigs(config, args) {
1454
- const resolved = await (typeof config === "function" ? config(args) : config);
1455
- return (Array.isArray(resolved) ? resolved : [resolved]).map((item) => ({
1456
- ...item,
1457
- plugins: item.plugins ?? []
1458
- }));
1459
- }
1460
- //#endregion
1461
- //#region src/utils/getCosmiConfig.ts
1462
- const unrunInputOptions = { transform: { jsx: {
1463
- runtime: "automatic",
1464
- importSource: "@kubb/renderer-jsx"
1465
- } } };
1466
- const tsLoader = async (configFile) => {
1467
- const { module } = await (0, unrun.unrun)({
1468
- path: configFile,
1469
- inputOptions: unrunInputOptions
1470
- });
1471
- return module;
1472
- };
1473
- async function getCosmiConfig(moduleName, config) {
1474
- let result;
1475
- const searchPlaces = [
1476
- "package.json",
1477
- `.${moduleName}rc`,
1478
- `.${moduleName}rc.json`,
1479
- `.${moduleName}rc.yaml`,
1480
- `.${moduleName}rc.yml`,
1481
- `.${moduleName}rc.ts`,
1482
- `.${moduleName}rc.mts`,
1483
- `.${moduleName}rc.cts`,
1484
- `.${moduleName}rc.js`,
1485
- `.${moduleName}rc.mjs`,
1486
- `.${moduleName}rc.cjs`,
1487
- `${moduleName}.config.ts`,
1488
- `${moduleName}.config.mts`,
1489
- `${moduleName}.config.cts`,
1490
- `${moduleName}.config.js`,
1491
- `${moduleName}.config.mjs`,
1492
- `${moduleName}.config.cjs`
1493
- ];
1494
- const explorer = (0, cosmiconfig.cosmiconfig)(moduleName, {
1344
+ //#region src/runners/generate/utils.ts
1345
+ const jiti$1 = (0, jiti.createJiti)(require("url").pathToFileURL(__filename).href, {
1346
+ jsx: {
1347
+ runtime: "automatic",
1348
+ importSource: "@kubb/renderer-jsx"
1349
+ },
1350
+ moduleCache: false
1351
+ });
1352
+ const tsLoader = (configFile) => jiti$1.import(configFile, { default: true });
1353
+ const MODULE_NAME = "kubb";
1354
+ const BASE_SEARCH_PLACES = [
1355
+ "package.json",
1356
+ `.${MODULE_NAME}rc`,
1357
+ `.${MODULE_NAME}rc.json`,
1358
+ `.${MODULE_NAME}rc.yaml`,
1359
+ `.${MODULE_NAME}rc.yml`,
1360
+ `.${MODULE_NAME}rc.ts`,
1361
+ `.${MODULE_NAME}rc.mts`,
1362
+ `.${MODULE_NAME}rc.cts`,
1363
+ `.${MODULE_NAME}rc.js`,
1364
+ `.${MODULE_NAME}rc.mjs`,
1365
+ `.${MODULE_NAME}rc.cjs`,
1366
+ `${MODULE_NAME}.config.ts`,
1367
+ `${MODULE_NAME}.config.mts`,
1368
+ `${MODULE_NAME}.config.cts`,
1369
+ `${MODULE_NAME}.config.js`,
1370
+ `${MODULE_NAME}.config.mjs`,
1371
+ `${MODULE_NAME}.config.cjs`
1372
+ ];
1373
+ const SEARCH_PLACES = [
1374
+ "",
1375
+ ".config/",
1376
+ "configs/"
1377
+ ].flatMap((prefix) => BASE_SEARCH_PLACES.map((p) => `${prefix}${p}`));
1378
+ async function getCosmiConfig(configFile) {
1379
+ const explorer = (0, cosmiconfig.cosmiconfig)(MODULE_NAME, {
1495
1380
  cache: false,
1496
- searchPlaces: [
1497
- ...searchPlaces.map((searchPlace) => {
1498
- return `.config/${searchPlace}`;
1499
- }),
1500
- ...searchPlaces.map((searchPlace) => {
1501
- return `configs/${searchPlace}`;
1502
- }),
1503
- ...searchPlaces
1504
- ],
1381
+ searchPlaces: SEARCH_PLACES,
1505
1382
  loaders: {
1506
1383
  ".ts": tsLoader,
1507
1384
  ".mts": tsLoader,
1508
1385
  ".cts": tsLoader
1509
1386
  }
1510
1387
  });
1388
+ let result;
1511
1389
  try {
1512
- result = config ? await explorer.load(config) : await explorer.search();
1390
+ result = configFile ? await explorer.load(configFile) : await explorer.search();
1513
1391
  } catch (error) {
1514
1392
  throw new Error("Config failed loading", { cause: error });
1515
1393
  }
1516
- 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");
1394
+ 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");
1517
1395
  return result;
1518
1396
  }
1519
- //#endregion
1520
- //#region src/utils/watcher.ts
1521
- async function startWatcher(path, cb) {
1397
+ /**
1398
+ * Discovers the Kubb config via cosmiconfig and resolves it into a normalized array of configs.
1399
+ * Every config in the result is guaranteed to have a `plugins` array.
1400
+ */
1401
+ async function getConfigs({ configPath, input }) {
1402
+ const result = await getCosmiConfig(configPath);
1403
+ const resolved = await (typeof result.config === "function" ? result.config({ input }) : result.config);
1404
+ const userConfigs = Array.isArray(resolved) ? resolved : [resolved];
1405
+ return {
1406
+ configPath: result.filepath,
1407
+ configs: userConfigs.map((item) => ({
1408
+ ...item,
1409
+ plugins: item.plugins ?? []
1410
+ }))
1411
+ };
1412
+ }
1413
+ /**
1414
+ * Runs the `done` hooks defined in a Kubb config in sequence.
1415
+ */
1416
+ async function executeHooks({ configHooks, hooks, makeSink }) {
1417
+ const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
1418
+ for (const command of commands) {
1419
+ const [cmd, ...args] = require_shell.tokenize(command);
1420
+ if (!cmd) continue;
1421
+ const hookId = (0, node_crypto.createHash)("sha256").update(command).digest("hex");
1422
+ const commandWithArgs = [cmd, ...args].join(" ");
1423
+ await hooks.emit("kubb:hook:start", {
1424
+ id: hookId,
1425
+ command: cmd,
1426
+ args
1427
+ });
1428
+ const { stream = false, onLine, onStdout, onStderr } = makeSink?.(commandWithArgs) ?? {};
1429
+ await runHook({
1430
+ id: hookId,
1431
+ command: cmd,
1432
+ args,
1433
+ commandWithArgs,
1434
+ context: hooks,
1435
+ stream,
1436
+ sink: {
1437
+ onLine,
1438
+ onStdout,
1439
+ onStderr
1440
+ }
1441
+ });
1442
+ }
1443
+ }
1444
+ async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
1445
+ const emitEnd = (success, error) => context.emit("kubb:hook:end", {
1446
+ command,
1447
+ args,
1448
+ id,
1449
+ success,
1450
+ error
1451
+ });
1452
+ try {
1453
+ const proc = (0, tinyexec.x)(command, [...args ?? []], {
1454
+ nodeOptions: { detached: process.platform !== "win32" },
1455
+ throwOnError: true
1456
+ });
1457
+ if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
1458
+ const result = await proc;
1459
+ await context.emit("kubb:debug", {
1460
+ date: /* @__PURE__ */ new Date(),
1461
+ logs: [result.stdout.trimEnd()]
1462
+ });
1463
+ await context.emit("kubb:success", { message: `${(0, node_util.styleText)("dim", commandWithArgs)} successfully executed` });
1464
+ await emitEnd(true, null);
1465
+ } catch (err) {
1466
+ if (!(err instanceof tinyexec.NonZeroExitError)) {
1467
+ const error = require_errors.toError(err);
1468
+ await emitEnd(false, error);
1469
+ await context.emit("kubb:error", { error });
1470
+ return;
1471
+ }
1472
+ const stderr = err.output?.stderr ?? "";
1473
+ const stdout = err.output?.stdout ?? "";
1474
+ await context.emit("kubb:debug", {
1475
+ date: /* @__PURE__ */ new Date(),
1476
+ logs: [stdout, stderr].filter(Boolean)
1477
+ });
1478
+ if (stderr) sink?.onStderr?.(stderr);
1479
+ if (stdout) sink?.onStdout?.(stdout);
1480
+ const error = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
1481
+ await emitEnd(false, error);
1482
+ await context.emit("kubb:error", { error });
1483
+ }
1484
+ }
1485
+ /**
1486
+ * Starts a file watcher on the given paths and calls `cb` on any change.
1487
+ * Ignores `.git` and `node_modules` directories.
1488
+ */
1489
+ async function startWatcher(path, cb, log = {
1490
+ info: console.log,
1491
+ error: console.log
1492
+ }) {
1522
1493
  const { watch } = await import("chokidar");
1523
1494
  watch(path, {
1524
1495
  ignorePermissionErrors: true,
1525
1496
  ignored: require_constants.WATCHER_IGNORED_PATHS
1526
1497
  }).on("all", async (type, file) => {
1527
- console.log((0, node_util.styleText)("yellow", (0, node_util.styleText)("bold", `Change detected: ${type} ${file}`)));
1498
+ log.info((0, node_util.styleText)("yellow", (0, node_util.styleText)("bold", `Change detected: ${type} ${file}`)));
1528
1499
  try {
1529
1500
  await cb(path);
1530
1501
  } catch (_e) {
1531
- console.log((0, node_util.styleText)("red", "Watcher failed"));
1502
+ log.error((0, node_util.styleText)("red", "Watcher failed"));
1532
1503
  }
1533
1504
  });
1534
1505
  }
1535
1506
  //#endregion
1536
- //#region src/runners/generate.ts
1507
+ //#region src/runners/generate/run.ts
1508
+ /**
1509
+ * Registers a one-shot `kubb:hook:end` listener for `hookId` BEFORE the caller emits `kubb:hook:start`,
1510
+ * avoiding the race where a synchronous emitter fires end before the listener is attached.
1511
+ */
1512
+ function waitForHookEnd(hooks, hookId, onSuccess, fallbackErrorMessage) {
1513
+ return new Promise((resolve, reject) => {
1514
+ const handler = (ctx) => {
1515
+ if (ctx.id !== hookId) return;
1516
+ hooks.off("kubb:hook:end", handler);
1517
+ if (!ctx.success) {
1518
+ reject(ctx.error ?? new Error(fallbackErrorMessage));
1519
+ return;
1520
+ }
1521
+ onSuccess().then(resolve).catch(reject);
1522
+ };
1523
+ hooks.on("kubb:hook:end", handler);
1524
+ });
1525
+ }
1537
1526
  async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel, hooks, onStart, onEnd }) {
1538
1527
  await onStart();
1539
1528
  let resolvedTool = toolValue;
@@ -1548,24 +1537,14 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
1548
1537
  let toolError;
1549
1538
  if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) {
1550
1539
  const toolConfig = toolMap[resolvedTool];
1540
+ const hookId = (0, node_crypto.createHash)("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1541
+ const successMessage = [
1542
+ `${successPrefix} with ${(0, node_util.styleText)("dim", resolvedTool)}`,
1543
+ logLevel >= _kubb_core.logLevel.info ? `on ${(0, node_util.styleText)("dim", outputPath)}` : void 0,
1544
+ "successfully"
1545
+ ].filter(Boolean).join(" ");
1551
1546
  try {
1552
- const hookId = (0, node_crypto.createHash)("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
1553
- const hookEndPromise = new Promise((resolve, reject) => {
1554
- const handler = (ctx) => {
1555
- if (ctx.id !== hookId) return;
1556
- hooks.off("kubb:hook:end", handler);
1557
- if (!ctx.success) {
1558
- reject(ctx.error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`));
1559
- return;
1560
- }
1561
- hooks.emit("kubb:success", { message: [
1562
- `${successPrefix} with ${(0, node_util.styleText)("dim", resolvedTool)}`,
1563
- logLevel >= _kubb_core.logLevel.info ? `on ${(0, node_util.styleText)("dim", outputPath)}` : void 0,
1564
- "successfully"
1565
- ].filter(Boolean).join(" ") }).then(resolve).catch(reject);
1566
- };
1567
- hooks.on("kubb:hook:end", handler);
1568
- });
1547
+ const hookEndPromise = waitForHookEnd(hooks, hookId, () => hooks.emit("kubb:success", { message: successMessage }), toolConfig.errorMessage);
1569
1548
  await hooks.emit("kubb:hook:start", {
1570
1549
  id: hookId,
1571
1550
  command: toolConfig.command,
@@ -1582,9 +1561,9 @@ async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefi
1582
1561
  if (toolError) throw toolError;
1583
1562
  }
1584
1563
  async function generate(options) {
1585
- const { input, hooks, logLevel } = options;
1564
+ const { input, hooks, logLevel, makeSink } = options;
1586
1565
  const hrStart = node_process.default.hrtime();
1587
- const inputPath = input ?? ("path" in options.config.input ? options.config.input.path : void 0);
1566
+ const inputPath = input ?? (options.config.input && "path" in options.config.input ? options.config.input.path : void 0);
1588
1567
  const config = {
1589
1568
  ...options.config,
1590
1569
  input: inputPath ? {
@@ -1606,8 +1585,20 @@ async function generate(options) {
1606
1585
  });
1607
1586
  const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild();
1608
1587
  await hooks.emit("kubb:info", { message: "Load summary" });
1588
+ const telemetryPlugins = Array.from(driver.plugins.values(), (p) => ({
1589
+ name: p.name,
1590
+ options: p.options
1591
+ }));
1592
+ const reportTelemetry = (status) => require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({
1593
+ command: "generate",
1594
+ kubbVersion: require_package.version,
1595
+ plugins: telemetryPlugins,
1596
+ hrStart,
1597
+ filesCreated: files.length,
1598
+ status
1599
+ }));
1609
1600
  if (failedPlugins.size > 0 || error) {
1610
- const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean);
1601
+ const allErrors = [error, ...Array.from(failedPlugins, (it) => it.error)].filter(Boolean);
1611
1602
  for (const err of allErrors) await hooks.emit("kubb:error", { error: err });
1612
1603
  await hooks.emit("kubb:generation:end", {
1613
1604
  config,
@@ -1622,21 +1613,11 @@ async function generate(options) {
1622
1613
  hrStart,
1623
1614
  pluginTimings: logLevel >= _kubb_core.logLevel.verbose ? pluginTimings : void 0
1624
1615
  });
1625
- await require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({
1626
- command: "generate",
1627
- kubbVersion: require_package.version,
1628
- plugins: Array.from(driver.plugins.values(), (p) => ({
1629
- name: p.name,
1630
- options: p.options
1631
- })),
1632
- hrStart,
1633
- filesCreated: files.length,
1634
- status: "failed"
1635
- }));
1616
+ await reportTelemetry("failed");
1636
1617
  node_process.default.exit(1);
1637
1618
  }
1638
1619
  await hooks.emit("kubb:success", {
1639
- message: "Generation successfully",
1620
+ message: "Generation succeeded",
1640
1621
  info: inputPath
1641
1622
  });
1642
1623
  await hooks.emit("kubb:generation:end", {
@@ -1645,39 +1626,38 @@ async function generate(options) {
1645
1626
  sources: kubb.sources
1646
1627
  });
1647
1628
  const outputPath = node_path.default.resolve(config.root, config.output.path);
1648
- if (config.output.format) await runToolPass({
1629
+ const toolPasses = [config.output.format && {
1649
1630
  toolValue: config.output.format,
1650
1631
  detect: detectFormatter,
1651
1632
  toolMap: formatters,
1652
1633
  toolLabel: "formatter",
1653
1634
  successPrefix: "Formatting",
1654
1635
  noToolMessage: "No formatter found (oxfmt, biome, or prettier). Skipping formatting.",
1655
- configName: config.name,
1656
- outputPath,
1657
- logLevel,
1658
- hooks,
1659
1636
  onStart: () => hooks.emit("kubb:format:start"),
1660
1637
  onEnd: () => hooks.emit("kubb:format:end")
1661
- });
1662
- if (config.output.lint) await runToolPass({
1638
+ }, config.output.lint && {
1663
1639
  toolValue: config.output.lint,
1664
1640
  detect: detectLinter,
1665
1641
  toolMap: linters,
1666
1642
  toolLabel: "linter",
1667
1643
  successPrefix: "Linting",
1668
1644
  noToolMessage: "No linter found (oxlint, biome, or eslint). Skipping linting.",
1645
+ onStart: () => hooks.emit("kubb:lint:start"),
1646
+ onEnd: () => hooks.emit("kubb:lint:end")
1647
+ }].filter(Boolean);
1648
+ for (const pass of toolPasses) await runToolPass({
1649
+ ...pass,
1669
1650
  configName: config.name,
1670
1651
  outputPath,
1671
1652
  logLevel,
1672
- hooks,
1673
- onStart: () => hooks.emit("kubb:lint:start"),
1674
- onEnd: () => hooks.emit("kubb:lint:end")
1653
+ hooks
1675
1654
  });
1676
1655
  if (config.hooks) {
1677
1656
  await hooks.emit("kubb:hooks:start");
1678
1657
  await executeHooks({
1679
1658
  configHooks: config.hooks,
1680
- hooks
1659
+ hooks,
1660
+ makeSink
1681
1661
  });
1682
1662
  await hooks.emit("kubb:hooks:end");
1683
1663
  }
@@ -1689,42 +1669,42 @@ async function generate(options) {
1689
1669
  hrStart,
1690
1670
  pluginTimings
1691
1671
  });
1692
- await require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({
1693
- command: "generate",
1694
- kubbVersion: require_package.version,
1695
- plugins: Array.from(driver.plugins.values(), (p) => ({
1696
- name: p.name,
1697
- options: p.options
1698
- })),
1699
- hrStart,
1700
- filesCreated: files.length,
1701
- status: "success"
1702
- }));
1672
+ await reportTelemetry("success");
1703
1673
  }
1704
- async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) {
1705
- const logLevel = _kubb_core.logLevel[logLevelKey] ?? _kubb_core.logLevel.info;
1706
- const hooks = new AsyncEventEmitter();
1707
- await setupLogger(hooks, { logLevel });
1674
+ async function checkForUpdate(hooks) {
1708
1675
  await require_telemetry.executeIfOnline(async () => {
1709
1676
  try {
1710
- const latestVersion = (await (await fetch(require_constants.KUBB_NPM_PACKAGE_URL)).json()).version;
1711
- if (latestVersion && require_package.version < latestVersion) await hooks.emit("kubb:version:new", {
1677
+ const data = await (await fetch(require_constants.KUBB_NPM_PACKAGE_URL)).json();
1678
+ if (data.version && require_package.version < data.version) await hooks.emit("kubb:version:new", {
1712
1679
  currentVersion: require_package.version,
1713
- latestVersion
1680
+ latestVersion: data.version
1714
1681
  });
1715
1682
  } catch {}
1716
1683
  });
1684
+ }
1685
+ /**
1686
+ * Runs the full Kubb generation lifecycle for the given CLI options.
1687
+ * Sets up the logger, checks for a newer version, loads configs, and calls `generate` for each config entry.
1688
+ */
1689
+ async function run({ input, configPath, logLevel: logLevelKey, watch }) {
1690
+ const logLevel = _kubb_core.logLevel[logLevelKey] ?? _kubb_core.logLevel.info;
1691
+ const hooks = new AsyncEventEmitter();
1692
+ const makeSink = await setupLogger(hooks, { logLevel });
1693
+ await checkForUpdate(hooks);
1717
1694
  try {
1718
- const result = await getCosmiConfig("kubb", configPath);
1719
- const configs = await getConfigs(result.config, { input });
1695
+ const { configs, configPath: resolvedConfigPath } = await getConfigs({
1696
+ configPath,
1697
+ input
1698
+ });
1699
+ const relativeConfigPath = node_path.default.relative(node_process.default.cwd(), resolvedConfigPath);
1720
1700
  await hooks.emit("kubb:config:start");
1721
1701
  await hooks.emit("kubb:info", {
1722
1702
  message: "Config loaded",
1723
- info: node_path.default.relative(node_process.default.cwd(), result.filepath)
1703
+ info: relativeConfigPath
1724
1704
  });
1725
1705
  await hooks.emit("kubb:success", {
1726
1706
  message: "Config loaded successfully",
1727
- info: node_path.default.relative(node_process.default.cwd(), result.filepath)
1707
+ info: relativeConfigPath
1728
1708
  });
1729
1709
  await hooks.emit("kubb:config:end", { configs });
1730
1710
  await hooks.emit("kubb:lifecycle:start", { version: require_package.version });
@@ -1734,15 +1714,20 @@ async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, wa
1734
1714
  input,
1735
1715
  config,
1736
1716
  logLevel,
1737
- hooks
1717
+ hooks,
1718
+ makeSink
1738
1719
  });
1739
1720
  _clack_prompts.log.step((0, node_util.styleText)("yellow", `Watching for changes in ${paths.join(" and ")}`));
1721
+ }, {
1722
+ info: (msg) => _clack_prompts.log.info(msg),
1723
+ error: (msg) => _clack_prompts.log.error(msg)
1740
1724
  });
1741
1725
  else await generate({
1742
1726
  input,
1743
1727
  config,
1744
1728
  logLevel,
1745
- hooks
1729
+ hooks,
1730
+ makeSink
1746
1731
  });
1747
1732
  await hooks.emit("kubb:lifecycle:end");
1748
1733
  } catch (error) {
@@ -1751,6 +1736,6 @@ async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, wa
1751
1736
  }
1752
1737
  }
1753
1738
  //#endregion
1754
- exports.runGenerateCommand = runGenerateCommand;
1739
+ exports.run = run;
1755
1740
 
1756
- //# sourceMappingURL=generate-K8MJ9aQF.cjs.map
1741
+ //# sourceMappingURL=run-QyqW2rPC.cjs.map