@kubb/cli 5.9.3 → 5.9.5

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 (108) hide show
  1. package/dist/Telemetry-BFKg5ZFx.js +259 -0
  2. package/dist/Telemetry-BFKg5ZFx.js.map +1 -0
  3. package/dist/Telemetry-iUSXePwR.cjs +314 -0
  4. package/dist/Telemetry-iUSXePwR.cjs.map +1 -0
  5. package/dist/{background-BcRoKru0.cjs → background-BA5mxYa1.cjs} +7 -6
  6. package/dist/{background-BcRoKru0.cjs.map → background-BA5mxYa1.cjs.map} +1 -1
  7. package/dist/{background-CCex47-d.js → background-Dtk2M5B8.js} +3 -2
  8. package/dist/{background-CCex47-d.js.map → background-Dtk2M5B8.js.map} +1 -1
  9. package/dist/background-uX93zloA.js +1 -0
  10. package/dist/{reporters-H21Jvrff.js → config-66zh0aCP.js} +29 -3
  11. package/dist/config-66zh0aCP.js.map +1 -0
  12. package/dist/{reporters-B4rZOlo8.cjs → config-cb2nhvBt.cjs} +36 -4
  13. package/dist/config-cb2nhvBt.cjs.map +1 -0
  14. package/dist/credentials-C8tjAhTo.js +1 -0
  15. package/dist/credentials-CZK6zPLv.js +62 -0
  16. package/dist/credentials-CZK6zPLv.js.map +1 -0
  17. package/dist/credentials-DDaKqtJn.cjs +113 -0
  18. package/dist/credentials-DDaKqtJn.cjs.map +1 -0
  19. package/dist/index.cjs +702 -208
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.js +697 -207
  22. package/dist/index.js.map +1 -1
  23. package/dist/{output-qFt4vV7K.js → output-CCiHzIPS.js} +173 -129
  24. package/dist/output-CCiHzIPS.js.map +1 -0
  25. package/dist/{output-BnK0scpX.cjs → output-DOC3zu6i.cjs} +141 -66
  26. package/dist/output-DOC3zu6i.cjs.map +1 -0
  27. package/dist/{registry-DER9aRyg.cjs → registry-DTPOQwZN.cjs} +6 -6
  28. package/dist/{registry-DER9aRyg.cjs.map → registry-DTPOQwZN.cjs.map} +1 -1
  29. package/dist/{registry-B7BvdrGE.js → registry-O3AelRfj.js} +2 -2
  30. package/dist/{registry-B7BvdrGE.js.map → registry-O3AelRfj.js.map} +1 -1
  31. package/dist/rolldown-runtime-CPE0t6oh.cjs +53 -0
  32. package/dist/{run-CIvFRMLt.cjs → run--pbGQ3Rm.cjs} +5 -6
  33. package/dist/{run-CIvFRMLt.cjs.map → run--pbGQ3Rm.cjs.map} +1 -1
  34. package/dist/{run-Co732JNO.cjs → run-BehbQsS7.cjs} +5 -6
  35. package/dist/{run-Co732JNO.cjs.map → run-BehbQsS7.cjs.map} +1 -1
  36. package/dist/{run-B1jaQu6Q.js → run-BzoydGZo.js} +2 -3
  37. package/dist/{run-B1jaQu6Q.js.map → run-BzoydGZo.js.map} +1 -1
  38. package/dist/{run-DunTcXOS.js → run-CB3YAq5e.js} +2 -3
  39. package/dist/{run-DunTcXOS.js.map → run-CB3YAq5e.js.map} +1 -1
  40. package/dist/run-CWWSCB8I.js +1 -0
  41. package/dist/{run-DxGkjzRm.cjs → run-CfBk4wgw.cjs} +47 -159
  42. package/dist/run-CfBk4wgw.cjs.map +1 -0
  43. package/dist/{run-DFos0eOY.cjs → run-DIeXldF6.cjs} +16 -18
  44. package/dist/{run-DFos0eOY.cjs.map → run-DIeXldF6.cjs.map} +1 -1
  45. package/dist/{run-QPsBYkq_.js → run-Dut1ksMl.js} +5 -7
  46. package/dist/{run-QPsBYkq_.js.map → run-Dut1ksMl.js.map} +1 -1
  47. package/dist/{run-BRUwQ5Y7.js → run-S-4lnViv.js} +26 -85
  48. package/dist/run-S-4lnViv.js.map +1 -0
  49. package/dist/{snapshot-DUJU70H_.cjs → snapshot-CFyEQsu-.cjs} +17 -26
  50. package/dist/snapshot-CFyEQsu-.cjs.map +1 -0
  51. package/dist/{snapshot-CkpJr-gr.js → snapshot-Cv_SImjr.js} +15 -24
  52. package/dist/snapshot-Cv_SImjr.js.map +1 -0
  53. package/dist/studioWorker.js +2 -2
  54. package/package.json +7 -8
  55. package/dist/Telemetry-C9gmBTr0.cjs +0 -231
  56. package/dist/Telemetry-C9gmBTr0.cjs.map +0 -1
  57. package/dist/Telemetry-CSc7OVsv.js +0 -207
  58. package/dist/Telemetry-CSc7OVsv.js.map +0 -1
  59. package/dist/agent-BPIqnEl2.js +0 -59
  60. package/dist/agent-BPIqnEl2.js.map +0 -1
  61. package/dist/agent-DElUuYuy.cjs +0 -120
  62. package/dist/agent-DElUuYuy.cjs.map +0 -1
  63. package/dist/background-1AFVK_yN.js +0 -1
  64. package/dist/commands-BuY0nrlU.cjs +0 -87
  65. package/dist/commands-BuY0nrlU.cjs.map +0 -1
  66. package/dist/commands-atq2z0Bo.js +0 -81
  67. package/dist/commands-atq2z0Bo.js.map +0 -1
  68. package/dist/config-B6UIKcl1.js +0 -117
  69. package/dist/config-B6UIKcl1.js.map +0 -1
  70. package/dist/config-Bo9ro7vg.cjs +0 -129
  71. package/dist/config-Bo9ro7vg.cjs.map +0 -1
  72. package/dist/constants-Cii4HX64.js +0 -12
  73. package/dist/constants-Cii4HX64.js.map +0 -1
  74. package/dist/constants-Df449N47.cjs +0 -29
  75. package/dist/constants-Df449N47.cjs.map +0 -1
  76. package/dist/errors-BdA8M78q.cjs +0 -43
  77. package/dist/errors-BdA8M78q.cjs.map +0 -1
  78. package/dist/errors-DmC83ALX.js +0 -32
  79. package/dist/errors-DmC83ALX.js.map +0 -1
  80. package/dist/output-BnK0scpX.cjs.map +0 -1
  81. package/dist/output-qFt4vV7K.js.map +0 -1
  82. package/dist/reporters-B4rZOlo8.cjs.map +0 -1
  83. package/dist/reporters-H21Jvrff.js.map +0 -1
  84. package/dist/run-BGTUbY2h.cjs +0 -130
  85. package/dist/run-BGTUbY2h.cjs.map +0 -1
  86. package/dist/run-BPQzGEIs.js +0 -178
  87. package/dist/run-BPQzGEIs.js.map +0 -1
  88. package/dist/run-BRUwQ5Y7.js.map +0 -1
  89. package/dist/run-BYff_byB.js +0 -71
  90. package/dist/run-BYff_byB.js.map +0 -1
  91. package/dist/run-Bhs7mJ1f.cjs +0 -79
  92. package/dist/run-Bhs7mJ1f.cjs.map +0 -1
  93. package/dist/run-CH48n-MJ.js +0 -1
  94. package/dist/run-DfEoWJuy.js +0 -126
  95. package/dist/run-DfEoWJuy.js.map +0 -1
  96. package/dist/run-Dm9OZUkQ.cjs +0 -182
  97. package/dist/run-Dm9OZUkQ.cjs.map +0 -1
  98. package/dist/run-DpAMfkm5.cjs +0 -72
  99. package/dist/run-DpAMfkm5.cjs.map +0 -1
  100. package/dist/run-DxGkjzRm.cjs.map +0 -1
  101. package/dist/run-DxxYCqEo.js +0 -77
  102. package/dist/run-DxxYCqEo.js.map +0 -1
  103. package/dist/snapshot-CkpJr-gr.js.map +0 -1
  104. package/dist/snapshot-DUJU70H_.cjs.map +0 -1
  105. package/dist/utils-BHW8kA8P.js +0 -83
  106. package/dist/utils-BHW8kA8P.js.map +0 -1
  107. package/dist/utils-BzQ46pgd.cjs +0 -109
  108. package/dist/utils-BzQ46pgd.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,8 +1,16 @@
1
- import "./rolldown-runtime-CRm0XQPb.js";
2
- import { r as version, t as isDisabled } from "./Telemetry-CSc7OVsv.js";
1
+ import { t as __name } from "./rolldown-runtime-CRm0XQPb.js";
2
+ import { c as getErrorMessage, r as version, t as isDisabled } from "./Telemetry-BFKg5ZFx.js";
3
+ import { S as initDefaults, a as logInfo, b as KUBB_CONFIG_FILENAME, d as logWarn, i as logError, l as logStep, o as logIntro, r as logBlock, s as logOutro, t as createSpinner, v as findConfigFile, x as KUBB_PACKAGE_NAME } from "./output-CCiHzIPS.js";
4
+ import { a as isOutdated, i as installSpec, n as fetchRegistryIndex, o as registryUrl, r as incompatibility, s as toRegistryId, t as fetchRegistryDetail } from "./registry-O3AelRfj.js";
3
5
  import { styleText } from "node:util";
4
6
  import dryrun, { pluginId as dryRunId } from "@gunshi/plugin-dryrun";
5
7
  import { cli, define, defineWithTypes } from "gunshi";
8
+ import process$1 from "node:process";
9
+ import { x } from "tinyexec";
10
+ import path from "node:path";
11
+ import * as clack from "@clack/prompts";
12
+ import fs from "node:fs";
13
+ import { readInstalledPackages } from "@kubb/core";
6
14
  //#region src/commands/shared.ts
7
15
  const configArg = { config: {
8
16
  type: "string",
@@ -64,44 +72,6 @@ const studioPermissionArgs = {
64
72
  }
65
73
  };
66
74
  //#endregion
67
- //#region src/commands/add.ts
68
- const command$13 = define({
69
- name: "add",
70
- description: "Install a plugin, adapter, or parser from the Kubb registry at its reviewed version. Without an id, pick one from the registry. A plugin is added to kubb.config.ts, an adapter or parser prints the code to add. Reads KUBB_REGISTRY to use another registry.",
71
- examples: [
72
- "kubb add",
73
- "kubb add plugin-zod",
74
- "kubb add kubb-labs/plugin-react-query",
75
- "kubb add acme/plugin-x --yes",
76
- "kubb add plugin-zod --no-install"
77
- ].join("\n"),
78
- toKebab: true,
79
- args: {
80
- id: {
81
- type: "positional",
82
- description: "Registry id: owner/slug, or a slug for an official extension. Asked for when omitted",
83
- required: false
84
- },
85
- ...configArg,
86
- ...yesArg,
87
- install: {
88
- type: "boolean",
89
- description: "Install the package. Pass --no-install to only edit the config",
90
- negatable: true,
91
- default: true
92
- }
93
- },
94
- async run({ values }) {
95
- const { run } = await import("./run-CH48n-MJ.js");
96
- await run({
97
- id: values.id,
98
- configPath: values.config,
99
- yes: values.yes,
100
- install: values.install
101
- });
102
- }
103
- });
104
- //#endregion
105
75
  //#region src/commands/generate.ts
106
76
  const REPORTER_NAMES = [
107
77
  "cli",
@@ -125,7 +95,7 @@ function resolveLogLevel({ verbose, silent, logLevel }) {
125
95
  if (silent) return "silent";
126
96
  return logLevel;
127
97
  }
128
- const command$12 = defineWithTypes()({
98
+ const command$13 = defineWithTypes()({
129
99
  name: "generate",
130
100
  description: "Generate TypeScript types, API clients, React Query hooks, Zod schemas, and more from an OpenAPI specification. Reads kubb.config.ts by default. Pass an OpenAPI file path as the first argument to override the input without editing the config.",
131
101
  examples: [
@@ -175,7 +145,7 @@ const command$12 = defineWithTypes()({
175
145
  async run(ctx) {
176
146
  const { values } = ctx;
177
147
  const logLevel = resolveLogLevel(values);
178
- const { run } = await import("./run-QPsBYkq_.js");
148
+ const { run } = await import("./run-Dut1ksMl.js");
179
149
  await run({
180
150
  input: values.input,
181
151
  configPath: values.config,
@@ -187,71 +157,9 @@ const command$12 = defineWithTypes()({
187
157
  }
188
158
  });
189
159
  //#endregion
190
- //#region src/commands/init.ts
191
- const command$11 = defineWithTypes()({
192
- name: "init",
193
- description: "Scaffold a kubb.config.ts and install plugins for code generation from an OpenAPI spec. Run without flags for interactive setup, or pass --input, --output, and --plugins to skip the prompts.",
194
- examples: [
195
- "kubb init",
196
- "kubb init --yes",
197
- "kubb init --input ./openapi.yaml --output ./src/gen --plugins plugin-ts,plugin-zod",
198
- "kubb init --plugins plugin-ts,plugin-axios,plugin-react-query",
199
- "kubb init --yes --dry-run"
200
- ].join("\n"),
201
- toKebab: true,
202
- args: {
203
- yes: {
204
- type: "boolean",
205
- description: "Skip prompts and use default options",
206
- short: "y",
207
- default: false
208
- },
209
- input: {
210
- type: "string",
211
- description: "Path to the OpenAPI specification",
212
- short: "i",
213
- metavar: "path"
214
- },
215
- output: {
216
- type: "string",
217
- description: "Output directory for generated files",
218
- short: "o",
219
- metavar: "path"
220
- },
221
- plugins: {
222
- type: "string",
223
- description: "Comma-separated Kubb registry ids of the plugins to add, the same ids `kubb add` takes (plugin-ts, plugin-zod, acme/plugin-x)",
224
- metavar: "plugin-ts,plugin-zod,..."
225
- }
226
- },
227
- async run(ctx) {
228
- const { values } = ctx;
229
- const { run } = await import("./run-BPQzGEIs.js");
230
- await run({
231
- yes: values.yes,
232
- version,
233
- input: values.input,
234
- output: values.output,
235
- plugins: values.plugins,
236
- dryRun: ctx.extensions[dryRunId]
237
- });
238
- }
239
- });
240
- //#endregion
241
- //#region src/commands/list.ts
242
- const command$10 = define({
243
- name: "list",
244
- description: "List the installed Kubb extensions: their registry id, package, installed version, the version the Kubb registry pins, and whether an update exists.",
245
- examples: "kubb list",
246
- async run() {
247
- const { run } = await import("./run-BYff_byB.js");
248
- await run();
249
- }
250
- });
251
- //#endregion
252
160
  //#region src/commands/mcp.ts
253
161
  /** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/mcp`. */
254
- const command$9 = define({
162
+ const command$12 = define({
255
163
  name: "mcp",
256
164
  description: "Start a Model Context Protocol (MCP) server that exposes Kubb code generation as tools for AI assistants. Once running, configure your AI client (Claude, Cursor, Windsurf, etc.) to connect to it — the assistant can then call kubb generate directly without leaving the chat.",
257
165
  examples: [
@@ -261,13 +169,29 @@ const command$9 = define({
261
169
  ].join("\n"),
262
170
  rendering: { header: null },
263
171
  async run() {
264
- const { run } = await import("./run-B1jaQu6Q.js");
172
+ const { run } = await import("./run-BzoydGZo.js");
265
173
  await run();
266
174
  }
267
175
  });
268
176
  //#endregion
177
+ //#region src/commands/studio/studioCommand.ts
178
+ /**
179
+ * Defines a `kubb studio` subcommand. The runner, and with it `@kubb/studio`, loads only when the
180
+ * command runs, so `kubb --help` never does.
181
+ */
182
+ function studioCommand({ action, block, ...definition }) {
183
+ return define({
184
+ ...definition,
185
+ toKebab: true,
186
+ async run({ values }) {
187
+ const { runStudio } = await import("./run-CWWSCB8I.js");
188
+ await runStudio(values, action, { block });
189
+ }
190
+ });
191
+ }
192
+ //#endregion
269
193
  //#region src/commands/studio/connect.ts
270
- const command$8 = define({
194
+ const command$11 = studioCommand({
271
195
  name: "connect",
272
196
  description: "Connect this project to Kubb Studio and generate from the browser.",
273
197
  examples: [
@@ -276,7 +200,6 @@ const command$8 = define({
276
200
  "kubb studio connect --allow-write --allow-exec",
277
201
  "kubb studio connect --url http://localhost:3000"
278
202
  ].join("\n"),
279
- toKebab: true,
280
203
  args: {
281
204
  ...configArg,
282
205
  ...studioConnectionArgs,
@@ -289,45 +212,42 @@ const command$8 = define({
289
212
  },
290
213
  ...logLevelArg
291
214
  },
292
- async run(ctx) {
293
- const { connectRunner } = await import("./commands-atq2z0Bo.js");
294
- await connectRunner(ctx);
215
+ block: true,
216
+ async action(options) {
217
+ const { connect } = await import("./run-CWWSCB8I.js");
218
+ await connect(options);
295
219
  }
296
220
  });
297
221
  //#endregion
298
222
  //#region src/commands/studio/login.ts
299
- const command$7 = define({
223
+ const command$10 = studioCommand({
300
224
  name: "login",
301
225
  description: "Pair this machine with Kubb Studio without connecting.",
302
226
  examples: ["kubb studio login", "kubb studio login --url http://localhost:3000"].join("\n"),
303
- toKebab: true,
304
- args: command$8.args,
305
- async run(ctx) {
306
- const { loginRunner } = await import("./commands-atq2z0Bo.js");
307
- await loginRunner(ctx);
227
+ args: command$11.args,
228
+ async action(options) {
229
+ const { login } = await import("./run-CWWSCB8I.js");
230
+ await login(options);
308
231
  }
309
232
  });
310
233
  //#endregion
311
234
  //#region src/commands/studio/logout.ts
312
- const command$6 = define({
235
+ const command$9 = studioCommand({
313
236
  name: "logout",
314
237
  description: "Forget the stored Kubb Studio token.",
315
- examples: ["kubb studio logout"].join("\n"),
316
- toKebab: true,
317
- args: {
318
- ...configArg,
319
- ...studioConnectionArgs,
320
- ...studioPermissionArgs,
321
- ...logLevelArg
322
- },
323
- async run(ctx) {
324
- const { logoutRunner } = await import("./commands-atq2z0Bo.js");
325
- await logoutRunner(ctx);
238
+ examples: "kubb studio logout",
239
+ args: {},
240
+ async action() {
241
+ const { stopWorker } = await import("./background-uX93zloA.js");
242
+ const { clearCredentials } = await import("./credentials-C8tjAhTo.js");
243
+ await stopWorker();
244
+ await clearCredentials();
245
+ console.log("Signed out of Kubb Studio.");
326
246
  }
327
247
  });
328
248
  //#endregion
329
249
  //#region src/commands/studio/snapshot.ts
330
- const command$5 = define({
250
+ const command$8 = define({
331
251
  name: "snapshot",
332
252
  description: "Generate and publish a Kubb Studio snapshot from CI.",
333
253
  examples: ["kubb studio snapshot", "kubb studio snapshot --json"].join("\n"),
@@ -361,51 +281,69 @@ const command$5 = define({
361
281
  ...logLevelArg
362
282
  },
363
283
  async run(ctx) {
364
- const { runner } = await import("./snapshot-CkpJr-gr.js");
284
+ const { runner } = await import("./snapshot-Cv_SImjr.js");
365
285
  await runner(ctx);
366
286
  }
367
287
  });
368
288
  //#endregion
369
289
  //#region src/commands/studio/background.ts
370
- const command$4 = define({
290
+ const command$7 = studioCommand({
371
291
  name: "start",
372
292
  description: "Keep this project connected to Kubb Studio in the background.",
373
- toKebab: true,
374
- args: command$8.args,
375
- async run(ctx) {
376
- const { startRunner } = await import("./commands-atq2z0Bo.js");
377
- await startRunner(ctx);
293
+ args: command$11.args,
294
+ async action(options) {
295
+ const { startWorker } = await import("./background-uX93zloA.js");
296
+ await startWorker(options);
378
297
  }
379
298
  });
380
299
  const stopCommand = define({
381
300
  name: "stop",
382
301
  description: "Stop this project's background connection and keep its pairing.",
383
302
  async run() {
384
- const { stopRunner } = await import("./commands-atq2z0Bo.js");
385
- await stopRunner();
303
+ const { stopWorker } = await import("./background-uX93zloA.js");
304
+ await stopWorker();
305
+ console.log("Background connection stopped.");
386
306
  }
387
307
  });
388
308
  //#endregion
389
309
  //#region src/commands/studio/status.ts
390
- const command$3 = define({
310
+ const command$6 = studioCommand({
391
311
  name: "status",
392
312
  description: "Show the project worker, Kubb Studio pairing, and saved permissions.",
393
- examples: ["kubb studio status"].join("\n"),
394
- toKebab: true,
395
- args: {
396
- ...configArg,
397
- ...studioConnectionArgs,
398
- ...studioPermissionArgs,
399
- ...logLevelArg
400
- },
401
- async run(ctx) {
402
- const { statusRunner } = await import("./commands-atq2z0Bo.js");
403
- await statusRunner(ctx);
313
+ examples: "kubb studio status",
314
+ args: { url: studioConnectionArgs.url },
315
+ async action(options) {
316
+ const { getWorkerLogPath, getWorkerStatus } = await import("./background-uX93zloA.js");
317
+ const { readCredentials } = await import("./credentials-C8tjAhTo.js");
318
+ const { formatPermissionRows } = await import("./run-CWWSCB8I.js");
319
+ const worker = await getWorkerStatus();
320
+ console.log(`Background connection: ${worker.state}${worker.running ? ` (PID ${worker.pid})` : ""}`);
321
+ console.log(`Logs: ${getWorkerLogPath()}`);
322
+ const credentials = await readCredentials();
323
+ if (!credentials) {
324
+ console.log("Not paired. Run `kubb studio login`.");
325
+ return;
326
+ }
327
+ console.log(`Paired with ${credentials.studioUrl} as ${styleText("cyan", credentials.agentSlug || credentials.agentId)}`);
328
+ if (credentials.studioUrl !== options.studioUrl) console.log(styleText("yellow", `Connecting to ${options.studioUrl} needs pairing again.`));
329
+ const remembered = credentials.projects?.[process$1.cwd()];
330
+ if (!remembered) {
331
+ console.log(styleText("dim", "No saved permissions for this project. Run `kubb studio` to connect and choose."));
332
+ return;
333
+ }
334
+ console.log(styleText("dim", "Saved permissions"));
335
+ for (const row of formatPermissionRows({
336
+ allowRead: remembered.allowRead === true,
337
+ allowWrite: remembered.allowWrite === true,
338
+ allowConfigEdit: remembered.allowConfigEdit === true,
339
+ allowExec: remembered.allowExec === true
340
+ })) console.log(row);
404
341
  }
405
342
  });
406
343
  //#endregion
407
344
  //#region src/commands/studio/index.ts
408
- const command$2 = define({
345
+ const command$5 = define({
346
+ ...command$11,
409
347
  name: "studio",
410
348
  description: "Connect this project to Kubb Studio, or manage its pairing and snapshots.",
411
349
  examples: [
@@ -416,20 +354,14 @@ const command$2 = define({
416
354
  "kubb studio logout",
417
355
  "kubb studio snapshot"
418
356
  ].join("\n"),
419
- toKebab: true,
420
- args: command$8.args,
421
- async run(ctx) {
422
- const { connectRunner } = await import("./commands-atq2z0Bo.js");
423
- await connectRunner(ctx);
424
- },
425
357
  subCommands: {
426
- start: command$4,
358
+ start: command$7,
427
359
  stop: stopCommand,
428
- connect: command$8,
429
- login: command$7,
430
- logout: command$6,
431
- status: command$3,
432
- snapshot: command$5
360
+ connect: command$11,
361
+ login: command$10,
362
+ logout: command$9,
363
+ status: command$6,
364
+ snapshot: command$8
433
365
  }
434
366
  });
435
367
  /**
@@ -446,41 +378,9 @@ function routeStudioFlags(args) {
446
378
  ];
447
379
  }
448
380
  //#endregion
449
- //#region src/commands/update.ts
450
- const command$1 = define({
451
- name: "update",
452
- description: "Update installed extensions to the version the Kubb registry pins. Pass ids to update only those, or --check to list the updates without installing.",
453
- examples: [
454
- "kubb update",
455
- "kubb update --check",
456
- "kubb update plugin-zod plugin-ts --yes"
457
- ].join("\n"),
458
- args: {
459
- ids: {
460
- type: "positional",
461
- description: "Registry ids to update, all installed extensions when omitted",
462
- multiple: true
463
- },
464
- check: {
465
- type: "boolean",
466
- description: "List the available updates without installing them",
467
- default: false
468
- },
469
- ...yesArg
470
- },
471
- async run({ values }) {
472
- const { run } = await import("./run-DxxYCqEo.js");
473
- await run({
474
- ids: values.ids ?? [],
475
- check: values.check,
476
- yes: values.yes
477
- });
478
- }
479
- });
480
- //#endregion
481
381
  //#region src/commands/validate.ts
482
382
  /** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/adapter-oas`. */
483
- const command = define({
383
+ const command$4 = define({
484
384
  name: "validate",
485
385
  description: "Parse and validate an OpenAPI/Swagger file for structural correctness. Reports schema errors, missing required fields, and malformed references. Use this before running generate to catch spec issues early.",
486
386
  examples: ["kubb validate ./openapi.yaml", "kubb validate https://petstore3.swagger.io/api/v3/openapi.json"].join("\n"),
@@ -490,7 +390,7 @@ const command = define({
490
390
  required: true
491
391
  } },
492
392
  async run({ values }) {
493
- const { run } = await import("./run-DunTcXOS.js");
393
+ const { run } = await import("./run-CB3YAq5e.js");
494
394
  await run({ input: values.input });
495
395
  }
496
396
  });
@@ -525,6 +425,596 @@ function resolveDeprecatedFlags(args) {
525
425
  });
526
426
  }
527
427
  //#endregion
428
+ //#region ../../internals/shared/src/init.ts
429
+ /** The `kubb.config.ts` `kubb init` writes before `kubb add` puts each plugin in. */
430
+ function generateConfigFile({ inputPath, outputPath }) {
431
+ return `import { defineConfig } from 'kubb/config'
432
+
433
+ export default defineConfig({
434
+ input: '${inputPath}',
435
+ output: {
436
+ path: '${outputPath}',
437
+ clean: true,
438
+ },
439
+ plugins: [],
440
+ })
441
+ `;
442
+ }
443
+ //#endregion
444
+ //#region src/runners/init/utils.ts
445
+ /** Metadata for each supported package manager, keyed by its short name. */
446
+ const packageManagers = {
447
+ pnpm: {
448
+ name: "pnpm",
449
+ lockFiles: ["pnpm-lock.yaml"],
450
+ initCommand: ["init"],
451
+ installCommand: ["add", "-D"]
452
+ },
453
+ yarn: {
454
+ name: "yarn",
455
+ lockFiles: ["yarn.lock"],
456
+ initCommand: ["init", "-y"],
457
+ installCommand: ["add", "-D"]
458
+ },
459
+ bun: {
460
+ name: "bun",
461
+ lockFiles: ["bun.lock", "bun.lockb"],
462
+ initCommand: ["init", "-y"],
463
+ installCommand: ["add", "-d"]
464
+ },
465
+ npm: {
466
+ name: "npm",
467
+ lockFiles: ["package-lock.json"],
468
+ initCommand: ["init", "-y"],
469
+ installCommand: ["install", "--save-dev"]
470
+ }
471
+ };
472
+ /** Detects the package manager for `cwd`: the `packageManager` field in `package.json`, then a lock file, then `npm`. */
473
+ function detectPackageManager(cwd = process$1.cwd()) {
474
+ const packageJsonPath = path.join(cwd, "package.json");
475
+ if (fs.existsSync(packageJsonPath)) try {
476
+ const pmField = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")).packageManager;
477
+ if (typeof pmField === "string") {
478
+ const name = pmField.split("@")[0];
479
+ if (name && name in packageManagers) return packageManagers[name];
480
+ }
481
+ } catch {}
482
+ for (const pm of Object.values(packageManagers)) if (pm.lockFiles.some((lockFile) => fs.existsSync(path.join(cwd, lockFile)))) return pm;
483
+ return packageManagers.npm;
484
+ }
485
+ /**
486
+ * Initializes a new `package.json` at `cwd` using the detected package manager.
487
+ */
488
+ async function initPackageJson(cwd, packageManager) {
489
+ await x(packageManager.name, [...packageManager.initCommand], {
490
+ nodeOptions: {
491
+ cwd,
492
+ stdio: "inherit"
493
+ },
494
+ throwOnError: true
495
+ });
496
+ }
497
+ /**
498
+ * Installs the given packages at `cwd` using the detected package manager.
499
+ */
500
+ async function installPackages(packages, packageManager, cwd = process$1.cwd()) {
501
+ await x(packageManager.name, [...packageManager.installCommand, ...packages], {
502
+ nodeOptions: {
503
+ cwd,
504
+ stdio: "inherit"
505
+ },
506
+ throwOnError: true
507
+ });
508
+ }
509
+ /**
510
+ * What the installed manifests of the `selected` plugins say is missing from the selection: a
511
+ * `dependencies` entry, or a `client` plugin next to a `consumer`. Empty when nothing is missing.
512
+ * `optionalDependencies` are skipped, since `kubb init` writes the default options.
513
+ */
514
+ function missingPluginDependencies({ selected, manifests }) {
515
+ const hasClient = manifests.some((manifest) => manifest.role === "client");
516
+ return manifests.flatMap((manifest) => [...(manifest.dependencies ?? []).filter((name) => !selected.includes(name)).map((name) => `${manifest.name} needs ${name}.`), ...manifest.role === "consumer" && !hasClient ? [`${manifest.name} needs a client plugin, such as plugin-axios or plugin-fetch.`] : []]);
517
+ }
518
+ //#endregion
519
+ //#region src/runners/add/run.ts
520
+ /** The import and the `defineConfig` property to merge into `kubb.config.ts` by hand. */
521
+ function toSnippet({ artifact, manifest }) {
522
+ const call = `${manifest.export}()`;
523
+ const property = {
524
+ plugin: `plugins: [..., ${call}],`,
525
+ adapter: `adapter: ${call},`,
526
+ parser: `parsers: [..., ${call}],`
527
+ };
528
+ return [
529
+ `import { ${manifest.export} } from '${artifact.package}'`,
530
+ "",
531
+ property[manifest.kind]
532
+ ].join("\n");
533
+ }
534
+ /** Adds the plugin call and its import to the config file. Returns why it could not, or `undefined`. */
535
+ async function addToConfig({ detail, configFile }) {
536
+ const { artifact, manifest } = detail;
537
+ try {
538
+ const { writeConfigEdits } = await import("@kubb/studio");
539
+ const { outcomes } = await writeConfigEdits({
540
+ filePath: configFile,
541
+ edits: [{
542
+ operation: "add-plugin",
543
+ plugin: artifact.package
544
+ }],
545
+ extensions: /* @__PURE__ */ new Map([[artifact.package, {
546
+ package: artifact.package,
547
+ version: artifact.version,
548
+ manifest
549
+ }]])
550
+ });
551
+ return outcomes[0]?.applied ? void 0 : outcomes[0]?.reason ?? "the config file was not changed";
552
+ } catch (error) {
553
+ return getErrorMessage(error);
554
+ }
555
+ }
556
+ async function selectExtension(registry) {
557
+ const options = (await fetchRegistryIndex({ registry })).toSorted((a, b) => a.id.localeCompare(b.id)).map((entry) => ({
558
+ value: entry.id,
559
+ label: entry.manifest.displayName,
560
+ hint: `${entry.id} · ${entry.kind} ${entry.artifact.version} · ${entry.manifest.description}`
561
+ }));
562
+ if (!options.length) throw new Error(`The registry at ${registry} lists no extensions.`);
563
+ const id = await clack.autocomplete({
564
+ message: "Select an extension to add:",
565
+ options,
566
+ filter: (search, option) => `${option.label} ${option.hint}`.toLowerCase().includes(search.toLowerCase())
567
+ });
568
+ return clack.isCancel(id) ? void 0 : id;
569
+ }
570
+ /**
571
+ * Installs an extension from the Kubb registry at its reviewed version and, for a plugin, adds it to
572
+ * `kubb.config.ts`. Without an id, asks which one. Refuses when the running Kubb or Node.js version
573
+ * is outside its compatibility.
574
+ */
575
+ async function run$4({ id: input, configPath, yes, install }) {
576
+ const cwd = process$1.cwd();
577
+ logIntro({ title: styleText("bgCyan", styleText("black", " Kubb Add ")) });
578
+ try {
579
+ const registry = registryUrl();
580
+ if (!input && yes) throw new Error("Pass a registry id, such as plugin-zod, when using --yes.");
581
+ const id = input ? toRegistryId(input) : await selectExtension(registry);
582
+ if (!id) {
583
+ clack.cancel("Operation canceled.");
584
+ return;
585
+ }
586
+ const detail = await fetchRegistryDetail({
587
+ id,
588
+ registry
589
+ });
590
+ const { artifact, manifest } = detail;
591
+ const problem = incompatibility(manifest);
592
+ if (problem) throw new Error(problem);
593
+ const spec = installSpec(artifact);
594
+ const configFile = manifest.kind === "plugin" ? configPath ? path.resolve(configPath) : findConfigFile(cwd) : void 0;
595
+ if (manifest.kind === "plugin" && !configFile) throw new Error("No kubb.config.ts found. Run `kubb init` first, or pass --config.");
596
+ logInfo(`${styleText("cyan", manifest.displayName)} (${manifest.kind}): ${manifest.description}`);
597
+ logBlock([install ? `Install ${styleText("cyan", spec)} as a dev dependency` : `Skip installing ${spec}`, configFile ? `Add ${styleText("cyan", `${manifest.export}()`)} to ${path.relative(cwd, configFile) || configFile}` : `Print the ${manifest.kind} snippet to add`]);
598
+ const confirmed = yes || await clack.confirm({
599
+ message: "Continue?",
600
+ initialValue: true
601
+ });
602
+ if (clack.isCancel(confirmed) || !confirmed) {
603
+ clack.cancel("Operation canceled.");
604
+ return;
605
+ }
606
+ if (install) {
607
+ const packageManager = detectPackageManager(cwd);
608
+ logStep(`Installing ${spec} with ${packageManager.name}`);
609
+ await installPackages([spec], packageManager, cwd);
610
+ }
611
+ const reason = configFile ? await addToConfig({
612
+ detail,
613
+ configFile
614
+ }) : `add the ${manifest.kind} to your config`;
615
+ if (!reason) {
616
+ logOutro(styleText("green", install ? `Added ${spec}` : `Added ${manifest.export}() to the config. Install ${spec} to use it.`));
617
+ return;
618
+ }
619
+ if (configFile) logWarn(`Could not edit ${configFile}: ${reason}`);
620
+ logBlock([
621
+ "Add the import to your Kubb config and merge the property into its defineConfig call:",
622
+ "",
623
+ toSnippet(detail)
624
+ ]);
625
+ logOutro(styleText("green", install ? `Installed ${spec}. Add it with the snippet above.` : `Install ${spec} and add the snippet above.`));
626
+ } catch (error) {
627
+ logError(getErrorMessage(error));
628
+ process$1.exitCode = 1;
629
+ }
630
+ }
631
+ __name(run$4, "run");
632
+ const command$3 = define({
633
+ name: "add",
634
+ description: "Install a plugin, adapter, or parser from the Kubb registry at its reviewed version. Without an id, pick one from the registry. A plugin is added to kubb.config.ts, an adapter or parser prints the code to add. Reads KUBB_REGISTRY to use another registry.",
635
+ examples: [
636
+ "kubb add",
637
+ "kubb add plugin-zod",
638
+ "kubb add kubb-labs/plugin-react-query",
639
+ "kubb add acme/plugin-x --yes",
640
+ "kubb add plugin-zod --no-install"
641
+ ].join("\n"),
642
+ toKebab: true,
643
+ args: {
644
+ id: {
645
+ type: "positional",
646
+ description: "Registry id: owner/slug, or a slug for an official extension. Asked for when omitted",
647
+ required: false
648
+ },
649
+ ...configArg,
650
+ ...yesArg,
651
+ install: {
652
+ type: "boolean",
653
+ description: "Install the package. Pass --no-install to only edit the config",
654
+ negatable: true,
655
+ default: true
656
+ }
657
+ },
658
+ run: ({ values }) => run$4({
659
+ id: values.id,
660
+ configPath: values.config,
661
+ yes: values.yes,
662
+ install: values.install
663
+ })
664
+ });
665
+ //#endregion
666
+ //#region src/runners/init/run.ts
667
+ function cancelAndExit(message = "Operation canceled.") {
668
+ clack.cancel(message);
669
+ process$1.exit(0);
670
+ }
671
+ /**
672
+ * Runs the interactive Kubb scaffolding wizard.
673
+ * Detects the package manager, prompts for input/output paths and plugins, installs packages, and writes `kubb.config.ts`.
674
+ * Pass `yes: true` to skip all prompts and use defaults.
675
+ */
676
+ async function run$3({ yes, input: inputFlag, output: outputFlag, plugins: pluginsFlag, dryRun }) {
677
+ const cwd = process$1.cwd();
678
+ logIntro({ title: styleText("bgCyan", styleText("black", " Kubb Init ")) });
679
+ /**
680
+ * Returns `flag` when provided, the `defaultValue` when `yes` is set,
681
+ * or calls `prompt()` for interactive input. Exits on cancellation.
682
+ */
683
+ async function resolveOrPrompt(flag, defaultValue, logLabel, prompt) {
684
+ if (flag !== void 0) {
685
+ logInfo(`${logLabel}: ${styleText("cyan", String(flag))}`);
686
+ return flag;
687
+ }
688
+ if (yes) {
689
+ logInfo(`${logLabel}: ${styleText("cyan", String(defaultValue))}`);
690
+ return defaultValue;
691
+ }
692
+ const result = await prompt();
693
+ if (clack.isCancel(result)) cancelAndExit();
694
+ return result;
695
+ }
696
+ try {
697
+ const plugins = (await fetchRegistryIndex({ registry: registryUrl() })).filter((entry) => entry.kind === "plugin" && !incompatibility(entry.manifest));
698
+ const byId = new Map(plugins.map((entry) => [entry.id, entry]));
699
+ if (!fs.existsSync(path.join(cwd, "package.json"))) {
700
+ if (!yes) {
701
+ const shouldInit = await clack.confirm({
702
+ message: "No package.json found. Would you like to create one?",
703
+ initialValue: true
704
+ });
705
+ if (clack.isCancel(shouldInit) || !shouldInit) cancelAndExit();
706
+ }
707
+ const packageManager = detectPackageManager(cwd);
708
+ const spinner = createSpinner();
709
+ spinner.start(`Initializing package.json with ${packageManager.name}`);
710
+ await initPackageJson(cwd, packageManager);
711
+ spinner.stop(`Created package.json with ${packageManager.name}`);
712
+ }
713
+ const packageManager = detectPackageManager(cwd);
714
+ logInfo(`Detected package manager: ${styleText("cyan", packageManager.name)}`);
715
+ const inputPath = await resolveOrPrompt(inputFlag, initDefaults.inputPath, "Using input path", () => clack.text({
716
+ message: "Where is your OpenAPI specification located?",
717
+ placeholder: initDefaults.inputPath,
718
+ defaultValue: initDefaults.inputPath,
719
+ validate: (value) => {
720
+ if (!value) return "Input path is required";
721
+ }
722
+ }));
723
+ const outputPath = await resolveOrPrompt(outputFlag, initDefaults.outputPath, "Using output path", () => clack.text({
724
+ message: "Where should the generated files be output?",
725
+ placeholder: initDefaults.outputPath,
726
+ defaultValue: initDefaults.outputPath,
727
+ validate: (value) => {
728
+ if (!value) return "Output path is required";
729
+ }
730
+ }));
731
+ const defaultPlugins = initDefaults.plugins.flatMap((slug) => byId.get(toRegistryId(slug)) ?? []);
732
+ const pluginLabel = (entries) => styleText("cyan", entries.map((entry) => entry.manifest.displayName).join(", "));
733
+ const selectedPlugins = await (async () => {
734
+ if (pluginsFlag) {
735
+ const ids = pluginsFlag.split(",").map((id) => id.trim()).filter(Boolean);
736
+ const unknown = ids.filter((id) => !byId.has(toRegistryId(id)));
737
+ if (unknown.length) throw new Error(`Not in the Kubb registry: ${unknown.join(", ")}. Browse the plugins at https://kubb.dev/extensions.`);
738
+ const entries = ids.map((id) => byId.get(toRegistryId(id)));
739
+ logInfo(`Using plugins: ${pluginLabel(entries)}`);
740
+ return entries;
741
+ }
742
+ if (yes) {
743
+ logInfo(`Using plugins: ${pluginLabel(defaultPlugins)}`);
744
+ return defaultPlugins;
745
+ }
746
+ const values = await clack.multiselect({
747
+ message: "Select plugins to use:",
748
+ options: plugins.map(({ id, manifest }) => ({
749
+ value: id,
750
+ label: manifest.displayName,
751
+ hint: manifest.category
752
+ })),
753
+ initialValues: defaultPlugins.map((entry) => entry.id),
754
+ required: true
755
+ });
756
+ if (clack.isCancel(values)) cancelAndExit();
757
+ return plugins.filter((entry) => values.includes(entry.id));
758
+ })();
759
+ const missing = missingPluginDependencies({
760
+ selected: selectedPlugins.map((entry) => entry.manifest.name),
761
+ manifests: selectedPlugins.map((entry) => entry.manifest)
762
+ });
763
+ if (missing.length) throw new Error(`${missing.join("\n")}\nAdd the missing plugins and run kubb init again.`);
764
+ const packagesToInstall = [`${KUBB_PACKAGE_NAME}@${version}`, ...selectedPlugins.map((entry) => installSpec(entry.artifact))];
765
+ const spinner = createSpinner();
766
+ spinner.start(`Installing ${packagesToInstall.length} packages with ${packageManager.name}`);
767
+ try {
768
+ await dryRun.run(() => installPackages(packagesToInstall, packageManager, cwd), { message: `install ${packagesToInstall.length} packages with ${packageManager.name}` });
769
+ spinner.stop(`Installed ${packagesToInstall.length} packages`);
770
+ } catch (error) {
771
+ spinner.stop("Installation failed");
772
+ throw error;
773
+ }
774
+ const configSpinner = createSpinner();
775
+ configSpinner.start(`Creating ${KUBB_CONFIG_FILENAME}`);
776
+ const configContent = generateConfigFile({
777
+ inputPath,
778
+ outputPath
779
+ });
780
+ const configPath = path.join(cwd, KUBB_CONFIG_FILENAME);
781
+ if (fs.existsSync(configPath)) {
782
+ configSpinner.stop(`${KUBB_CONFIG_FILENAME} already exists`);
783
+ if (!yes) {
784
+ const shouldOverwrite = await clack.confirm({
785
+ message: `${KUBB_CONFIG_FILENAME} already exists. Overwrite?`,
786
+ initialValue: false
787
+ });
788
+ if (clack.isCancel(shouldOverwrite) || !shouldOverwrite) cancelAndExit("Keeping existing configuration. Packages have been installed.");
789
+ }
790
+ configSpinner.start(`Overwriting ${KUBB_CONFIG_FILENAME}`);
791
+ }
792
+ await dryRun.run(() => fs.promises.writeFile(configPath, configContent, "utf-8"), { message: `write ${KUBB_CONFIG_FILENAME}` });
793
+ for (const entry of selectedPlugins) {
794
+ const reason = await dryRun.run(() => addToConfig({
795
+ detail: entry,
796
+ configFile: configPath
797
+ }), {
798
+ message: `add ${entry.manifest.export}() to ${KUBB_CONFIG_FILENAME}`,
799
+ resolve: () => void 0
800
+ });
801
+ if (reason) throw new Error(`Could not add ${entry.manifest.export}() to ${KUBB_CONFIG_FILENAME}: ${reason}`);
802
+ }
803
+ configSpinner.stop(`Created ${KUBB_CONFIG_FILENAME}`);
804
+ logOutro(styleText("green", "✓ All set!") + "\n\n" + styleText("dim", "Next steps:") + "\n" + styleText("cyan", ` 1. Make sure your OpenAPI spec is at: ${inputPath}`) + "\n" + styleText("cyan", " 2. Generate code with: npx kubb generate") + "\n" + styleText("cyan", ` 3. Find generated files in: ${outputPath}`) + "\n\n" + styleText("dim", `Using ${packageManager.name} • Kubb v${version}`));
805
+ } catch (error) {
806
+ logError(styleText("red", "An error occurred during initialization"));
807
+ if (error instanceof Error) logError(error.message);
808
+ process$1.exit(1);
809
+ }
810
+ }
811
+ __name(run$3, "run");
812
+ const command$2 = defineWithTypes()({
813
+ name: "init",
814
+ description: "Scaffold a kubb.config.ts and install plugins for code generation from an OpenAPI spec. Run without flags for interactive setup, or pass --input, --output, and --plugins to skip the prompts.",
815
+ examples: [
816
+ "kubb init",
817
+ "kubb init --yes",
818
+ "kubb init --input ./openapi.yaml --output ./src/gen --plugins plugin-ts,plugin-zod",
819
+ "kubb init --plugins plugin-ts,plugin-axios,plugin-react-query",
820
+ "kubb init --yes --dry-run"
821
+ ].join("\n"),
822
+ toKebab: true,
823
+ args: {
824
+ yes: {
825
+ type: "boolean",
826
+ description: "Skip prompts and use default options",
827
+ short: "y",
828
+ default: false
829
+ },
830
+ input: {
831
+ type: "string",
832
+ description: "Path to the OpenAPI specification",
833
+ short: "i",
834
+ metavar: "path"
835
+ },
836
+ output: {
837
+ type: "string",
838
+ description: "Output directory for generated files",
839
+ short: "o",
840
+ metavar: "path"
841
+ },
842
+ plugins: {
843
+ type: "string",
844
+ description: "Comma-separated Kubb registry ids of the plugins to add, the same ids `kubb add` takes (plugin-ts, plugin-zod, acme/plugin-x)",
845
+ metavar: "plugin-ts,plugin-zod,..."
846
+ }
847
+ },
848
+ run: ({ values, extensions }) => run$3({
849
+ yes: values.yes,
850
+ input: values.input,
851
+ output: values.output,
852
+ plugins: values.plugins,
853
+ dryRun: extensions[dryRunId]
854
+ })
855
+ });
856
+ //#endregion
857
+ //#region src/runners/list/run.ts
858
+ /**
859
+ * The installed packages that ship a `kubb-extension.json` or have a registry entry, with the
860
+ * version the registry pins.
861
+ */
862
+ async function listExtensions({ cwd, registry }) {
863
+ const [installed, entries] = await Promise.all([readInstalledPackages({ root: cwd }), fetchRegistryIndex({ registry }).catch((error) => {
864
+ logWarn(`Showing installed extensions only: ${getErrorMessage(error)}`);
865
+ return [];
866
+ })]);
867
+ const byPackage = new Map(entries.map((entry) => [entry.artifact.package, entry]));
868
+ return installed.flatMap(({ package: name, version, manifest }) => {
869
+ const entry = byPackage.get(name);
870
+ if (!entry && !manifest) return [];
871
+ const latest = entry?.artifact.version;
872
+ return [{
873
+ id: entry?.id,
874
+ package: name,
875
+ installed: version,
876
+ registry: latest,
877
+ update: !!latest && isOutdated({
878
+ installed: version,
879
+ latest
880
+ })
881
+ }];
882
+ });
883
+ }
884
+ /** Prints the installed extensions as a table. */
885
+ async function run$2() {
886
+ try {
887
+ const rows = await listExtensions({
888
+ cwd: process$1.cwd(),
889
+ registry: registryUrl()
890
+ });
891
+ if (!rows.length) {
892
+ logOutro("No installed extensions found.");
893
+ return;
894
+ }
895
+ const header = [
896
+ "ID",
897
+ "PACKAGE",
898
+ "INSTALLED",
899
+ "REGISTRY",
900
+ "UPDATE"
901
+ ];
902
+ const cells = rows.map((row) => [
903
+ row.id ?? "-",
904
+ row.package,
905
+ row.installed ?? "-",
906
+ row.registry ?? "-",
907
+ row.update ? "yes" : "no"
908
+ ]);
909
+ const widths = header.map((title, index) => Math.max(title.length, ...cells.map((cell) => cell[index].length)));
910
+ const line = (cell) => cell.map((value, index) => value.padEnd(widths[index])).join(" ").trimEnd();
911
+ logBlock([styleText("dim", line(header)), ...cells.map(line)]);
912
+ } catch (error) {
913
+ logError(getErrorMessage(error));
914
+ process$1.exitCode = 1;
915
+ }
916
+ }
917
+ __name(run$2, "run");
918
+ const command$1 = define({
919
+ name: "list",
920
+ description: "List the installed Kubb extensions: their registry id, package, installed version, the version the Kubb registry pins, and whether an update exists.",
921
+ examples: "kubb list",
922
+ run: () => run$2()
923
+ });
924
+ //#endregion
925
+ //#region src/runners/update/run.ts
926
+ /**
927
+ * Moves installed extensions to the version the registry pins. Lists the proposals, asks, then
928
+ * installs them. With `check`, only lists them.
929
+ */
930
+ async function run$1({ ids, check, yes }) {
931
+ const cwd = process$1.cwd();
932
+ logIntro({ title: styleText("bgCyan", styleText("black", " Kubb Update ")) });
933
+ try {
934
+ const wanted = new Set(ids.map(toRegistryId));
935
+ const [entries, installed] = await Promise.all([fetchRegistryIndex({ registry: registryUrl() }), readInstalledPackages({ root: cwd })]);
936
+ const versions = new Map(installed.map((item) => [item.package, item.version]));
937
+ const tracked = entries.filter((entry) => versions.has(entry.artifact.package) && (!wanted.size || wanted.has(entry.id)));
938
+ for (const id of wanted) if (!tracked.some((entry) => entry.id === id)) logWarn(`${id} is not installed, or not in the registry.`);
939
+ const proposals = tracked.filter((entry) => {
940
+ if (!isOutdated({
941
+ installed: versions.get(entry.artifact.package),
942
+ latest: entry.artifact.version
943
+ })) return false;
944
+ const problem = incompatibility(entry.manifest);
945
+ if (problem) logWarn(`Skipped ${entry.id}: ${problem}`);
946
+ return !problem;
947
+ });
948
+ if (!proposals.length) {
949
+ logOutro(ids.length ? `No updates for ${ids.join(", ")}.` : "Every installed extension is up to date.");
950
+ return;
951
+ }
952
+ const change = ({ kind, artifact }) => `${kind} ${versions.get(artifact.package) ?? "not installed"} -> ${styleText("green", artifact.version)}`;
953
+ logBlock(proposals.map((entry) => `${entry.artifact.package} ${change(entry)}`));
954
+ if (check) {
955
+ const plural = proposals.length === 1 ? "" : "s";
956
+ logOutro(`${proposals.length} update${plural} available. Run \`kubb update\` to install.`);
957
+ return;
958
+ }
959
+ let selected = proposals;
960
+ if (!yes) {
961
+ const chosen = await clack.multiselect({
962
+ message: "Select the updates to install:",
963
+ options: proposals.map((entry) => ({
964
+ value: entry.id,
965
+ label: entry.artifact.package,
966
+ hint: change(entry)
967
+ })),
968
+ initialValues: proposals.map((entry) => entry.id),
969
+ required: true
970
+ });
971
+ if (clack.isCancel(chosen)) {
972
+ clack.cancel("Operation canceled.");
973
+ return;
974
+ }
975
+ selected = proposals.filter((entry) => chosen.includes(entry.id));
976
+ }
977
+ const plural = selected.length === 1 ? "" : "s";
978
+ const packageManager = detectPackageManager(cwd);
979
+ const specs = selected.map(({ artifact }) => installSpec(artifact));
980
+ logStep(`Installing ${specs.join(", ")} with ${packageManager.name}`);
981
+ await installPackages(specs, packageManager, cwd);
982
+ logInfo(`Updated ${specs.length} extension${plural}`);
983
+ logOutro(styleText("green", "Done"));
984
+ } catch (error) {
985
+ logError(getErrorMessage(error));
986
+ process$1.exitCode = 1;
987
+ }
988
+ }
989
+ __name(run$1, "run");
990
+ const command = define({
991
+ name: "update",
992
+ description: "Update installed extensions to the version the Kubb registry pins. Pass ids to update only those, or --check to list the updates without installing.",
993
+ examples: [
994
+ "kubb update",
995
+ "kubb update --check",
996
+ "kubb update plugin-zod plugin-ts --yes"
997
+ ].join("\n"),
998
+ args: {
999
+ ids: {
1000
+ type: "positional",
1001
+ description: "Registry ids to update, all installed extensions when omitted",
1002
+ multiple: true
1003
+ },
1004
+ check: {
1005
+ type: "boolean",
1006
+ description: "List the available updates without installing them",
1007
+ default: false
1008
+ },
1009
+ ...yesArg
1010
+ },
1011
+ run: ({ values }) => run$1({
1012
+ ids: values.ids ?? [],
1013
+ check: values.check,
1014
+ yes: values.yes
1015
+ })
1016
+ });
1017
+ //#endregion
528
1018
  //#region src/index.ts
529
1019
  /** Flags that short-circuit execution (help and version). The telemetry notice is suppressed for these. */
530
1020
  const QUIET_FLAGS = /* @__PURE__ */ new Set([
@@ -542,19 +1032,19 @@ async function run(argv = process.argv.slice(2)) {
542
1032
  const args = routeStudioFlags(resolveDeprecatedFlags(argv));
543
1033
  const isQuietFlag = args.some((arg) => QUIET_FLAGS.has(arg));
544
1034
  if (!isDisabled() && !isQuietFlag) console.error(`${styleText("yellow", "Notice:")} Kubb collects anonymous telemetry data to help improve the tool. No personal data or file contents are collected. \nTo disable, set ${styleText("cyan", "KUBB_DISABLE_TELEMETRY=1")}.\n`);
545
- await cli(args, command$12, {
1035
+ await cli(args, command$13, {
546
1036
  name: "kubb",
547
1037
  version,
548
1038
  description: "Generate code from an OpenAPI specification, manage Kubb extensions, or connect the project to Kubb Studio.",
549
1039
  subCommands: {
550
- generate: command$12,
551
- init: command$11,
552
- validate: command,
553
- mcp: command$9,
554
- studio: command$2,
555
- add: command$13,
556
- update: command$1,
557
- list: command$10
1040
+ generate: command$13,
1041
+ init: command$2,
1042
+ validate: command$4,
1043
+ mcp: command$12,
1044
+ studio: command$5,
1045
+ add: command$3,
1046
+ update: command,
1047
+ list: command$1
558
1048
  },
559
1049
  fallbackToEntry: true,
560
1050
  strict: true,