@kubb/cli 4.32.4 → 4.33.1

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 (133) hide show
  1. package/dist/agent-Bd1QdPVV.cjs +91 -0
  2. package/dist/agent-Bd1QdPVV.cjs.map +1 -0
  3. package/dist/agent-D83d9Pud.cjs +60 -0
  4. package/dist/agent-D83d9Pud.cjs.map +1 -0
  5. package/dist/agent-DgKQXSmR.js +57 -0
  6. package/dist/agent-DgKQXSmR.js.map +1 -0
  7. package/dist/agent-u_Ehwz6r.js +87 -0
  8. package/dist/agent-u_Ehwz6r.js.map +1 -0
  9. package/dist/constants-BTUap0zs.cjs +108 -0
  10. package/dist/constants-BTUap0zs.cjs.map +1 -0
  11. package/dist/constants-CM3dJzjK.js +67 -0
  12. package/dist/constants-CM3dJzjK.js.map +1 -0
  13. package/dist/define--M_JMcDC.js +25 -0
  14. package/dist/define--M_JMcDC.js.map +1 -0
  15. package/dist/define-D6Kfm7-Z.cjs +36 -0
  16. package/dist/define-D6Kfm7-Z.cjs.map +1 -0
  17. package/dist/errors-6mF_WKxg.js +27 -0
  18. package/dist/errors-6mF_WKxg.js.map +1 -0
  19. package/dist/errors-DBW0N9w4.cjs +44 -0
  20. package/dist/errors-DBW0N9w4.cjs.map +1 -0
  21. package/dist/generate-Bn8n4w1O.cjs +65 -0
  22. package/dist/generate-Bn8n4w1O.cjs.map +1 -0
  23. package/dist/{generate-CpWtSc45.js → generate-CAsV9wSx.js} +656 -689
  24. package/dist/generate-CAsV9wSx.js.map +1 -0
  25. package/dist/generate-D-59YK0L.js +66 -0
  26. package/dist/generate-D-59YK0L.js.map +1 -0
  27. package/dist/{generate-COj0aMS6.cjs → generate-JC65igQh.cjs} +662 -694
  28. package/dist/generate-JC65igQh.cjs.map +1 -0
  29. package/dist/index.cjs +226 -35
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.js +226 -35
  33. package/dist/index.js.map +1 -1
  34. package/dist/init-C-InrmSY.js +302 -0
  35. package/dist/init-C-InrmSY.js.map +1 -0
  36. package/dist/init-CXP8OfMe.js +25 -0
  37. package/dist/init-CXP8OfMe.js.map +1 -0
  38. package/dist/init-CbeE-L-0.cjs +25 -0
  39. package/dist/init-CbeE-L-0.cjs.map +1 -0
  40. package/dist/init-hmolV6B4.cjs +306 -0
  41. package/dist/init-hmolV6B4.cjs.map +1 -0
  42. package/dist/jiti-Cd3S0xwr.cjs +16 -0
  43. package/dist/jiti-Cd3S0xwr.cjs.map +1 -0
  44. package/dist/jiti-e08mD2Ph.js +11 -0
  45. package/dist/jiti-e08mD2Ph.js.map +1 -0
  46. package/dist/mcp-BDxg2oJm.cjs +16 -0
  47. package/dist/mcp-BDxg2oJm.cjs.map +1 -0
  48. package/dist/mcp-ChHFPRzD.cjs +42 -0
  49. package/dist/mcp-ChHFPRzD.cjs.map +1 -0
  50. package/dist/mcp-D2SHEg_d.js +41 -0
  51. package/dist/mcp-D2SHEg_d.js.map +1 -0
  52. package/dist/mcp-MSoE4vNA.js +16 -0
  53. package/dist/mcp-MSoE4vNA.js.map +1 -0
  54. package/dist/{package-aNQWvWbS.cjs → package-CUVyeIbt.cjs} +2 -2
  55. package/dist/package-CUVyeIbt.cjs.map +1 -0
  56. package/dist/package-Cbd8OC6q.js +6 -0
  57. package/dist/package-Cbd8OC6q.js.map +1 -0
  58. package/dist/shell-7HPrTCJ5.cjs +57 -0
  59. package/dist/shell-7HPrTCJ5.cjs.map +1 -0
  60. package/dist/shell-DqqWsHCD.js +46 -0
  61. package/dist/shell-DqqWsHCD.js.map +1 -0
  62. package/dist/{telemetry-BDSSqUiG.cjs → telemetry-Cn9X1I5B.cjs} +79 -9
  63. package/dist/telemetry-Cn9X1I5B.cjs.map +1 -0
  64. package/dist/{telemetry-DYWvlxqs.js → telemetry-DxiR7clS.js} +63 -11
  65. package/dist/telemetry-DxiR7clS.js.map +1 -0
  66. package/dist/validate-BG8A3aQS.cjs +25 -0
  67. package/dist/validate-BG8A3aQS.cjs.map +1 -0
  68. package/dist/validate-BZ1UFkwA.js +25 -0
  69. package/dist/validate-BZ1UFkwA.js.map +1 -0
  70. package/dist/validate-Bbrn3Q-A.cjs +42 -0
  71. package/dist/validate-Bbrn3Q-A.cjs.map +1 -0
  72. package/dist/validate-l8vLmwKA.js +41 -0
  73. package/dist/validate-l8vLmwKA.js.map +1 -0
  74. package/package.json +6 -6
  75. package/src/commands/agent/start.ts +27 -136
  76. package/src/commands/agent.ts +6 -25
  77. package/src/commands/generate.ts +26 -158
  78. package/src/commands/init.ts +9 -360
  79. package/src/commands/mcp.ts +7 -52
  80. package/src/commands/validate.ts +9 -60
  81. package/src/constants.ts +76 -0
  82. package/src/index.ts +36 -42
  83. package/src/loggers/clackLogger.ts +65 -165
  84. package/src/loggers/fileSystemLogger.ts +2 -14
  85. package/src/loggers/githubActionsLogger.ts +58 -125
  86. package/src/loggers/plainLogger.ts +44 -92
  87. package/src/loggers/utils.ts +67 -4
  88. package/src/runners/agent.ts +100 -0
  89. package/src/runners/generate.ts +223 -102
  90. package/src/runners/init.ts +323 -0
  91. package/src/runners/mcp.ts +32 -0
  92. package/src/runners/validate.ts +35 -0
  93. package/src/utils/Writables.ts +2 -2
  94. package/src/utils/executeHooks.ts +20 -8
  95. package/src/utils/getCosmiConfig.ts +10 -11
  96. package/src/utils/getIntro.ts +1 -81
  97. package/src/utils/getSummary.ts +12 -17
  98. package/src/utils/jiti.ts +9 -0
  99. package/src/utils/packageManager.ts +4 -4
  100. package/src/utils/runHook.ts +75 -0
  101. package/src/utils/telemetry.ts +8 -26
  102. package/src/utils/watcher.ts +2 -4
  103. package/dist/agent-6COck3B9.cjs +0 -20
  104. package/dist/agent-6COck3B9.cjs.map +0 -1
  105. package/dist/agent-DMm6c5Vg.js +0 -20
  106. package/dist/agent-DMm6c5Vg.js.map +0 -1
  107. package/dist/generate-COj0aMS6.cjs.map +0 -1
  108. package/dist/generate-CpWtSc45.js.map +0 -1
  109. package/dist/init-Bdn3_qir.js +0 -304
  110. package/dist/init-Bdn3_qir.js.map +0 -1
  111. package/dist/init-CFW2kWY8.cjs +0 -308
  112. package/dist/init-CFW2kWY8.cjs.map +0 -1
  113. package/dist/mcp-DkwtARfo.cjs +0 -57
  114. package/dist/mcp-DkwtARfo.cjs.map +0 -1
  115. package/dist/mcp-DrH93Vq4.js +0 -57
  116. package/dist/mcp-DrH93Vq4.js.map +0 -1
  117. package/dist/package-BnJbGmLm.js +0 -6
  118. package/dist/package-BnJbGmLm.js.map +0 -1
  119. package/dist/package-aNQWvWbS.cjs.map +0 -1
  120. package/dist/start-CqTUu14n.js +0 -131
  121. package/dist/start-CqTUu14n.js.map +0 -1
  122. package/dist/start-D-rsIJGo.cjs +0 -134
  123. package/dist/start-D-rsIJGo.cjs.map +0 -1
  124. package/dist/telemetry-BDSSqUiG.cjs.map +0 -1
  125. package/dist/telemetry-DYWvlxqs.js.map +0 -1
  126. package/dist/validate-BlV8L8gC.js +0 -66
  127. package/dist/validate-BlV8L8gC.js.map +0 -1
  128. package/dist/validate-COhZUXF8.cjs +0 -66
  129. package/dist/validate-COhZUXF8.cjs.map +0 -1
  130. package/src/loggers/envDetection.ts +0 -28
  131. package/src/loggers/index.ts +0 -5
  132. package/src/utils/formatMsWithColor.ts +0 -22
  133. package/src/utils/randomColor.ts +0 -23
@@ -1,366 +1,15 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import process from 'node:process'
4
- import { styleText } from 'node:util'
5
- import * as clack from '@clack/prompts'
6
- import { detectPackageManager, type PackageManagerInfo } from '@kubb/core'
7
- import { defineCommand } from 'citty'
1
+ import { defineCommand } from '@internals/utils'
8
2
  import { version } from '../../package.json'
9
- import { hasPackageJson, initPackageJson, installPackages } from '../utils/packageManager.ts'
10
3
 
11
- type PluginOption = {
12
- value: string
13
- label: string
14
- hint?: string
15
- packageName: string
16
- importName: string
17
- category: 'core' | 'typescript' | 'query' | 'validation' | 'testing' | 'mocking' | 'docs'
18
- }
19
-
20
- const plugins: PluginOption[] = [
21
- {
22
- value: 'plugin-oas',
23
- label: 'OpenAPI Parser',
24
- hint: 'Required',
25
- packageName: '@kubb/plugin-oas',
26
- importName: 'pluginOas',
27
- category: 'core',
28
- },
29
- {
30
- value: 'plugin-ts',
31
- label: 'TypeScript',
32
- hint: 'Recommended',
33
- packageName: '@kubb/plugin-ts',
34
- importName: 'pluginTs',
35
- category: 'typescript',
36
- },
37
- {
38
- value: 'plugin-client',
39
- label: 'Client (Fetch/Axios)',
40
- packageName: '@kubb/plugin-client',
41
- importName: 'pluginClient',
42
- category: 'typescript',
43
- },
44
- {
45
- value: 'plugin-react-query',
46
- label: 'React Query / TanStack Query',
47
- packageName: '@kubb/plugin-react-query',
48
- importName: 'pluginReactQuery',
49
- category: 'query',
50
- },
51
- {
52
- value: 'plugin-solid-query',
53
- label: 'Solid Query',
54
- packageName: '@kubb/plugin-solid-query',
55
- importName: 'pluginSolidQuery',
56
- category: 'query',
57
- },
58
- {
59
- value: 'plugin-svelte-query',
60
- label: 'Svelte Query',
61
- packageName: '@kubb/plugin-svelte-query',
62
- importName: 'pluginSvelteQuery',
63
- category: 'query',
64
- },
65
- {
66
- value: 'plugin-vue-query',
67
- label: 'Vue Query',
68
- packageName: '@kubb/plugin-vue-query',
69
- importName: 'pluginVueQuery',
70
- category: 'query',
71
- },
72
- {
73
- value: 'plugin-swr',
74
- label: 'SWR',
75
- packageName: '@kubb/plugin-swr',
76
- importName: 'pluginSwr',
77
- category: 'query',
78
- },
79
- {
80
- value: 'plugin-zod',
81
- label: 'Zod Schemas',
82
- packageName: '@kubb/plugin-zod',
83
- importName: 'pluginZod',
84
- category: 'validation',
85
- },
86
- {
87
- value: 'plugin-faker',
88
- label: 'Faker.js Mocks',
89
- packageName: '@kubb/plugin-faker',
90
- importName: 'pluginFaker',
91
- category: 'mocking',
92
- },
93
- {
94
- value: 'plugin-msw',
95
- label: 'MSW Handlers',
96
- packageName: '@kubb/plugin-msw',
97
- importName: 'pluginMsw',
98
- category: 'mocking',
99
- },
100
- {
101
- value: 'plugin-cypress',
102
- label: 'Cypress Tests',
103
- packageName: '@kubb/plugin-cypress',
104
- importName: 'pluginCypress',
105
- category: 'testing',
106
- },
107
- {
108
- value: 'plugin-redoc',
109
- label: 'ReDoc Documentation',
110
- packageName: '@kubb/plugin-redoc',
111
- importName: 'pluginRedoc',
112
- category: 'docs',
4
+ export const command = defineCommand({
5
+ name: 'init',
6
+ description: 'Initialize a new Kubb project with interactive setup',
7
+ options: {
8
+ yes: { type: 'boolean', description: 'Skip prompts and use default options', short: 'y', default: false },
113
9
  },
114
- ]
10
+ async run({ values }) {
11
+ const { runInit } = await import('../runners/init.ts')
115
12
 
116
- function generateConfigFile(selectedPlugins: PluginOption[], inputPath: string, outputPath: string): string {
117
- const imports = selectedPlugins.map((plugin) => `import { ${plugin.importName} } from '${plugin.packageName}'`).join('\n')
118
-
119
- const pluginConfigs = selectedPlugins
120
- .map((plugin) => {
121
- if (plugin.value === 'plugin-oas') {
122
- return ' pluginOas(),'
123
- }
124
- if (plugin.value === 'plugin-ts') {
125
- return ` pluginTs({\n output: {\n path: 'models',\n },\n }),`
126
- }
127
- if (plugin.value === 'plugin-client') {
128
- return ` pluginClient({\n output: {\n path: 'clients',\n },\n }),`
129
- }
130
- if (plugin.value === 'plugin-react-query') {
131
- return ` pluginReactQuery({\n output: {\n path: 'hooks',\n },\n }),`
132
- }
133
- if (plugin.value === 'plugin-zod') {
134
- return ` pluginZod({\n output: {\n path: 'zod',\n },\n }),`
135
- }
136
- if (plugin.value === 'plugin-faker') {
137
- return ` pluginFaker({\n output: {\n path: 'mocks',\n },\n }),`
138
- }
139
- if (plugin.value === 'plugin-msw') {
140
- return ` pluginMsw({\n output: {\n path: 'msw',\n },\n }),`
141
- }
142
- if (plugin.value === 'plugin-swr') {
143
- return ` pluginSwr({\n output: {\n path: 'hooks',\n },\n }),`
144
- }
145
- // Default config for other plugins
146
- return ` ${plugin.importName}(),`
147
- })
148
- .join('\n')
149
-
150
- return `import { defineConfig } from '@kubb/core'
151
- ${imports}
152
-
153
- export default defineConfig({
154
- root: '.',
155
- input: {
156
- path: '${inputPath}',
157
- },
158
- output: {
159
- path: '${outputPath}',
160
- clean: true,
13
+ await runInit({ yes: values.yes, version })
161
14
  },
162
- plugins: [
163
- ${pluginConfigs}
164
- ],
165
15
  })
166
- `
167
- }
168
-
169
- const DEFAULT_INPUT_PATH = './openapi.yaml'
170
- const DEFAULT_OUTPUT_PATH = './src/gen'
171
- const DEFAULT_PLUGINS = ['plugin-oas', 'plugin-ts']
172
-
173
- const command = defineCommand({
174
- meta: {
175
- name: 'init',
176
- description: 'Initialize a new Kubb project with interactive setup',
177
- },
178
- args: {
179
- yes: {
180
- type: 'boolean',
181
- alias: 'y',
182
- description: 'Skip prompts and use default options',
183
- default: false,
184
- },
185
- },
186
- async run({ args }) {
187
- const cwd = process.cwd()
188
- const yes = args.yes
189
-
190
- clack.intro(styleText('bgCyan', styleText('black', ' Kubb Init ')))
191
-
192
- try {
193
- // Check/create package.json
194
- let packageManager: PackageManagerInfo
195
- if (!hasPackageJson(cwd)) {
196
- if (!yes) {
197
- const shouldInit = await clack.confirm({
198
- message: 'No package.json found. Would you like to create one?',
199
- initialValue: true,
200
- })
201
-
202
- if (clack.isCancel(shouldInit) || !shouldInit) {
203
- clack.cancel('Operation cancelled.')
204
- process.exit(0)
205
- }
206
- }
207
-
208
- // Detect package manager before initializing
209
- packageManager = detectPackageManager(cwd)
210
-
211
- const spinner = clack.spinner()
212
- spinner.start(`Initializing package.json with ${packageManager.name}`)
213
-
214
- await initPackageJson(cwd, packageManager)
215
-
216
- spinner.stop(`Created package.json with ${packageManager.name}`)
217
- } else {
218
- packageManager = detectPackageManager(cwd)
219
- clack.log.info(`Detected package manager: ${styleText('cyan', packageManager.name)}`)
220
- }
221
-
222
- // Prompt for OpenAPI spec path
223
- let inputPath: string
224
- if (yes) {
225
- inputPath = DEFAULT_INPUT_PATH
226
- clack.log.info(`Using input path: ${styleText('cyan', inputPath)}`)
227
- } else {
228
- const inputPathResult = await clack.text({
229
- message: 'Where is your OpenAPI specification located?',
230
- placeholder: DEFAULT_INPUT_PATH,
231
- defaultValue: DEFAULT_INPUT_PATH,
232
- validate: (value) => {
233
- if (!value) return 'Input path is required'
234
- },
235
- })
236
-
237
- if (clack.isCancel(inputPathResult)) {
238
- clack.cancel('Operation cancelled.')
239
- process.exit(0)
240
- }
241
- inputPath = inputPathResult as string
242
- }
243
-
244
- // Prompt for output directory
245
- let outputPath: string
246
- if (yes) {
247
- outputPath = DEFAULT_OUTPUT_PATH
248
- clack.log.info(`Using output path: ${styleText('cyan', outputPath)}`)
249
- } else {
250
- const outputPathResult = await clack.text({
251
- message: 'Where should the generated files be output?',
252
- placeholder: DEFAULT_OUTPUT_PATH,
253
- defaultValue: DEFAULT_OUTPUT_PATH,
254
- validate: (value) => {
255
- if (!value) return 'Output path is required'
256
- },
257
- })
258
-
259
- if (clack.isCancel(outputPathResult)) {
260
- clack.cancel('Operation cancelled.')
261
- process.exit(0)
262
- }
263
- outputPath = outputPathResult as string
264
- }
265
-
266
- // Plugin selection
267
- let selectedPlugins: PluginOption[]
268
- if (yes) {
269
- selectedPlugins = plugins.filter((plugin) => DEFAULT_PLUGINS.includes(plugin.value))
270
- clack.log.info(`Using plugins: ${styleText('cyan', selectedPlugins.map((p) => p.label).join(', '))}`)
271
- } else {
272
- const selectedPluginValues = await clack.multiselect({
273
- message: 'Select plugins to use:',
274
- options: plugins.map((plugin) => ({
275
- value: plugin.value,
276
- label: plugin.label,
277
- hint: plugin.hint,
278
- })),
279
- initialValues: DEFAULT_PLUGINS,
280
- required: true,
281
- })
282
-
283
- if (clack.isCancel(selectedPluginValues)) {
284
- clack.cancel('Operation cancelled.')
285
- process.exit(0)
286
- }
287
-
288
- selectedPlugins = plugins.filter((plugin) => (selectedPluginValues as string[]).includes(plugin.value))
289
- }
290
-
291
- // Ensure plugin-oas is always included
292
- if (!selectedPlugins.find((p) => p.value === 'plugin-oas')) {
293
- selectedPlugins.unshift(plugins.find((p) => p.value === 'plugin-oas')!)
294
- }
295
-
296
- // Install packages
297
- const packagesToInstall = ['@kubb/core', '@kubb/cli', '@kubb/agent', ...selectedPlugins.map((p) => p.packageName)]
298
-
299
- const spinner = clack.spinner()
300
- spinner.start(`Installing ${packagesToInstall.length} packages with ${packageManager.name}`)
301
-
302
- try {
303
- await installPackages(packagesToInstall, packageManager, cwd)
304
- spinner.stop(`Installed ${packagesToInstall.length} packages`)
305
- } catch (error) {
306
- spinner.stop('Installation failed')
307
- throw error
308
- }
309
-
310
- // Generate config file
311
- const configSpinner = clack.spinner()
312
- configSpinner.start('Creating kubb.config.ts')
313
-
314
- const configContent = generateConfigFile(selectedPlugins, inputPath, outputPath)
315
- const configPath = path.join(cwd, 'kubb.config.ts')
316
-
317
- // Check if config already exists
318
- if (fs.existsSync(configPath)) {
319
- configSpinner.stop('kubb.config.ts already exists')
320
-
321
- if (!yes) {
322
- const shouldOverwrite = await clack.confirm({
323
- message: 'kubb.config.ts already exists. Overwrite?',
324
- initialValue: false,
325
- })
326
-
327
- if (clack.isCancel(shouldOverwrite) || !shouldOverwrite) {
328
- clack.cancel('Keeping existing configuration. Packages have been installed.')
329
- process.exit(0)
330
- }
331
- }
332
-
333
- configSpinner.start('Overwriting kubb.config.ts')
334
- }
335
-
336
- fs.writeFileSync(configPath, configContent, 'utf-8')
337
-
338
- configSpinner.stop('Created kubb.config.ts')
339
-
340
- // Success message
341
- clack.outro(
342
- styleText('green', '✓ All set!') +
343
- '\n\n' +
344
- styleText('dim', 'Next steps:') +
345
- '\n' +
346
- styleText('cyan', ` 1. Make sure your OpenAPI spec is at: ${inputPath}`) +
347
- '\n' +
348
- styleText('cyan', ' 2. Generate code with: npx kubb generate') +
349
- '\n' +
350
- styleText('cyan', ' Or start a stream server with: npx kubb start') +
351
- '\n' +
352
- styleText('cyan', ` 3. Find generated files in: ${outputPath}`) +
353
- '\n\n' +
354
- styleText('dim', `Using ${packageManager.name} • Kubb v${version}`),
355
- )
356
- } catch (error) {
357
- clack.log.error(styleText('red', 'An error occurred during initialization'))
358
- if (error instanceof Error) {
359
- clack.log.error(error.message)
360
- }
361
- process.exit(1)
362
- }
363
- },
364
- })
365
-
366
- export default command
@@ -1,57 +1,12 @@
1
- import process from 'node:process'
2
- import { styleText } from 'node:util'
3
- import type { ArgsDef } from 'citty'
4
- import { defineCommand, showUsage } from 'citty'
5
- import { createJiti } from 'jiti'
1
+ import { defineCommand } from '@internals/utils'
6
2
  import { version } from '../../package.json'
7
- import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
8
3
 
9
- const jiti = createJiti(import.meta.url, {
10
- sourceMaps: true,
11
- })
12
-
13
- const args = {
14
- help: {
15
- type: 'boolean',
16
- description: 'Show help',
17
- alias: 'h',
18
- default: false,
19
- },
20
- } as const satisfies ArgsDef
21
-
22
- const command = defineCommand({
23
- meta: {
24
- name: 'mcp',
25
- description: 'Start the server to enable the MCP client to interact with the LLM.',
26
- },
27
- args,
28
- async run(commandContext) {
29
- const { args } = commandContext
30
-
31
- if (args.help) {
32
- return showUsage(command)
33
- }
4
+ export const command = defineCommand({
5
+ name: 'mcp',
6
+ description: 'Start the server to enable the MCP client to interact with the LLM.',
7
+ async run() {
8
+ const { runMcp } = await import('../runners/mcp.ts')
34
9
 
35
- let mod: any
36
- try {
37
- mod = await jiti.import('@kubb/mcp', { default: true })
38
- } catch (_e) {
39
- console.error(`Import of '@kubb/mcp' is required to start the MCP server`)
40
- process.exit(1)
41
- }
42
-
43
- const { run } = mod
44
- const hrStart = process.hrtime()
45
- try {
46
- console.log('⏳ Starting MCP server...')
47
- console.warn(styleText('yellow', 'This feature is still under development — use with caution'))
48
- run()
49
- await sendTelemetry(buildTelemetryEvent({ command: 'mcp', kubbVersion: version, hrStart, status: 'success' }))
50
- } catch (error) {
51
- await sendTelemetry(buildTelemetryEvent({ command: 'mcp', kubbVersion: version, hrStart, status: 'failed' }))
52
- console.error((error as Error)?.message)
53
- }
10
+ await runMcp({ version })
54
11
  },
55
12
  })
56
-
57
- export default command
@@ -1,66 +1,15 @@
1
- import process from 'node:process'
2
- import type { ArgsDef } from 'citty'
3
- import { defineCommand, showUsage } from 'citty'
4
- import { createJiti } from 'jiti'
1
+ import { defineCommand } from '@internals/utils'
5
2
  import { version } from '../../package.json'
6
- import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
7
3
 
8
- const jiti = createJiti(import.meta.url, {
9
- sourceMaps: true,
10
- })
11
-
12
- const args = {
13
- input: {
14
- type: 'string',
15
- description: 'Path to Swagger/OpenAPI file',
16
- alias: 'i',
17
- },
18
- help: {
19
- type: 'boolean',
20
- description: 'Show help',
21
- alias: 'h',
22
- default: false,
4
+ export const command = defineCommand({
5
+ name: 'validate',
6
+ description: 'Validate a Swagger/OpenAPI file',
7
+ options: {
8
+ input: { type: 'string', description: 'Path to Swagger/OpenAPI file', short: 'i', required: true },
23
9
  },
24
- } as const satisfies ArgsDef
10
+ async run({ values }) {
11
+ const { runValidate } = await import('../runners/validate.ts')
25
12
 
26
- const command = defineCommand({
27
- meta: {
28
- name: 'validate',
29
- description: 'Validate a Swagger/OpenAPI file',
30
- },
31
- args,
32
- async run(commandContext) {
33
- const { args } = commandContext
34
-
35
- if (args.help) {
36
- return showUsage(command)
37
- }
38
-
39
- if (args.input) {
40
- let mod: any
41
- try {
42
- mod = await jiti.import('@kubb/oas', { default: true })
43
- } catch (_e) {
44
- console.error(`Import of '@kubb/oas' is required to do validation`)
45
- process.exit(1)
46
- }
47
-
48
- const { parse } = mod
49
- const hrStart = process.hrtime()
50
- try {
51
- const oas = await parse(args.input)
52
- await oas.validate()
53
-
54
- await sendTelemetry(buildTelemetryEvent({ command: 'validate', kubbVersion: version, hrStart, status: 'success' }))
55
- console.log('✅ Validation success')
56
- } catch (error) {
57
- await sendTelemetry(buildTelemetryEvent({ command: 'validate', kubbVersion: version, hrStart, status: 'failed' }))
58
- console.error('❌ Validation failed')
59
- console.log((error as Error)?.message)
60
- process.exit(1)
61
- }
62
- }
13
+ await runValidate({ input: values.input, version })
63
14
  },
64
15
  })
65
-
66
- export default command
@@ -0,0 +1,76 @@
1
+ /** NPM registry endpoint used to check for @kubb/cli updates. */
2
+ export const KUBB_NPM_PACKAGE_URL = 'https://registry.npmjs.org/@kubb/cli/latest' as const
3
+
4
+ /** OpenTelemetry ingestion endpoint for anonymous usage telemetry. */
5
+ export const OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const
6
+
7
+ /** Horizontal rule rendered above/below the plain-logger generation summary. */
8
+ export const SUMMARY_SEPARATOR = '─'.repeat(27)
9
+
10
+ /** Maximum number of █ characters in a plugin timing bar. */
11
+ export const SUMMARY_MAX_BAR_LENGTH = 10 as const
12
+
13
+ /** Divides elapsed milliseconds into bar-length units (1 block per 100 ms). */
14
+ export const SUMMARY_TIME_SCALE_DIVISOR = 100 as const
15
+
16
+ /** Glob pattern for paths the file watcher ignores. */
17
+ export const WATCHER_IGNORED_PATHS = '**/{.git,node_modules}/**' as const
18
+
19
+ /** Default runtime values for the `agent start` command. */
20
+ export const agentDefaults = {
21
+ port: '3000',
22
+ host: 'localhost',
23
+ configFile: 'kubb.config.ts',
24
+ retryTimeout: '30000',
25
+ studioUrl: 'https://studio.kubb.dev',
26
+ /** Relative path from the @kubb/agent package root to the server entry. */
27
+ serverEntryPath: '.output/server/index.mjs',
28
+ } as const
29
+
30
+ /** Default values used during interactive `init` scaffolding. */
31
+ export const initDefaults = {
32
+ inputPath: './openapi.yaml',
33
+ outputPath: './src/gen',
34
+ plugins: ['plugin-oas', 'plugin-ts'],
35
+ } as const
36
+
37
+ /**
38
+ * Maps each plugin value to the default config snippet inserted by `init`.
39
+ * The `satisfies` constraint ensures all values remain plain strings while
40
+ * `as const` keeps the object deeply immutable.
41
+ */
42
+ export const pluginDefaultConfigs = {
43
+ 'plugin-oas': 'pluginOas()',
44
+ 'plugin-ts': `pluginTs({
45
+ output: { path: 'models' },
46
+ })`,
47
+ 'plugin-client': `pluginClient({
48
+ output: { path: 'clients' },
49
+ })`,
50
+ 'plugin-react-query': `pluginReactQuery({
51
+ output: { path: 'hooks' },
52
+ })`,
53
+ 'plugin-solid-query': `pluginSolidQuery({
54
+ output: { path: 'hooks' },
55
+ })`,
56
+ 'plugin-svelte-query': `pluginSvelteQuery({
57
+ output: { path: 'hooks' },
58
+ })`,
59
+ 'plugin-vue-query': `pluginVueQuery({
60
+ output: { path: 'hooks' },
61
+ })`,
62
+ 'plugin-swr': `pluginSwr({
63
+ output: { path: 'hooks' },
64
+ })`,
65
+ 'plugin-zod': `pluginZod({
66
+ output: { path: 'zod' },
67
+ })`,
68
+ 'plugin-faker': `pluginFaker({
69
+ output: { path: 'mocks' },
70
+ })`,
71
+ 'plugin-msw': `pluginMsw({
72
+ output: { path: 'msw' },
73
+ })`,
74
+ } as const satisfies Record<string, string>
75
+
76
+ /** Color palette used by randomCliColor() for deterministic plugin name coloring. */
package/src/index.ts CHANGED
@@ -1,51 +1,45 @@
1
1
  import { styleText } from 'node:util'
2
- import { defineCommand, runCommand, runMain } from 'citty'
2
+ import { createCLI } from '@internals/utils'
3
3
  import { version } from '../package.json'
4
4
  import { isTelemetryDisabled } from './utils/telemetry.ts'
5
5
 
6
- const main = defineCommand({
7
- meta: {
8
- name: 'kubb',
9
- version,
10
- description: 'Kubb generation',
11
- },
12
- args: {
13
- version: {
14
- type: 'boolean',
15
- alias: 'v',
16
- description: 'Show version number',
17
- },
18
- },
19
- async setup({ rawArgs, args }) {
20
- if (args.version) {
21
- console.log(version)
22
- process.exit(0)
23
- }
24
-
25
- if (!isTelemetryDisabled()) {
26
- console.log(
27
- `${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`,
28
- )
29
- }
6
+ const cli = createCLI()
30
7
 
31
- if (!['generate', 'validate', 'mcp', 'agent', 'init'].includes(rawArgs[0] as string)) {
32
- // generate is not being used
33
- const generateCommand = await import('./commands/generate.ts').then((r) => r.default)
8
+ function shouldShowTelemetryNotice(argv: string[]): boolean {
9
+ if (isTelemetryDisabled()) {
10
+ return false
11
+ }
12
+ // Skip when the user is just asking for help or version info
13
+ const quietFlags = new Set(['--help', '-h', '--version', '-v'])
14
+ if (argv.some((arg) => quietFlags.has(arg))) {
15
+ return false
16
+ }
17
+ // Skip in non-interactive / scripting contexts
18
+ if (!process.stdout.isTTY) {
19
+ return false
20
+ }
21
+ return true
22
+ }
34
23
 
35
- await runCommand(generateCommand, { rawArgs })
24
+ export async function run(argv: string[] = process.argv): Promise<void> {
25
+ if (shouldShowTelemetryNotice(argv)) {
26
+ console.log(
27
+ `${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`,
28
+ )
29
+ }
36
30
 
37
- process.exit(0)
38
- }
39
- },
40
- subCommands: {
41
- generate: () => import('./commands/generate.ts').then((r) => r.default),
42
- validate: () => import('./commands/validate.ts').then((r) => r.default),
43
- mcp: () => import('./commands/mcp.ts').then((r) => r.default),
44
- agent: () => import('./commands/agent.ts').then((r) => r.default),
45
- init: () => import('./commands/init.ts').then((r) => r.default),
46
- },
47
- })
31
+ const [{ command: generateCommand }, { command: validateCommand }, { command: mcpCommand }, { command: agentCommand }, { command: initCommand }] =
32
+ await Promise.all([
33
+ import('./commands/generate.ts'),
34
+ import('./commands/validate.ts'),
35
+ import('./commands/mcp.ts'),
36
+ import('./commands/agent.ts'),
37
+ import('./commands/init.ts'),
38
+ ])
48
39
 
49
- export async function run(_argv?: string[]): Promise<void> {
50
- await runMain(main)
40
+ await cli.run([generateCommand, validateCommand, mcpCommand, agentCommand, initCommand], argv, {
41
+ programName: 'kubb',
42
+ defaultCommandName: 'generate',
43
+ version,
44
+ })
51
45
  }