@kubb/cli 5.9.2 → 5.9.4

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