@kubb/cli 5.0.0-beta.5 → 5.0.0-beta.51

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 (148) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +171 -51
  3. package/dist/Telemetry-BG80bcoQ.cjs +350 -0
  4. package/dist/Telemetry-BG80bcoQ.cjs.map +1 -0
  5. package/dist/Telemetry-CyBqvgcj.js +313 -0
  6. package/dist/Telemetry-CyBqvgcj.js.map +1 -0
  7. package/dist/{define-Bdn8j5VM.cjs → define-C4AB3POr.cjs} +2 -2
  8. package/dist/{define-Bdn8j5VM.cjs.map → define-C4AB3POr.cjs.map} +1 -1
  9. package/dist/{define-Ctii4bel.js → define-C63T4jp6.js} +2 -2
  10. package/dist/{define-Ctii4bel.js.map → define-C63T4jp6.js.map} +1 -1
  11. package/dist/{errors-CjPmyZHy.js → errors-BsemQCMn.js} +2 -2
  12. package/dist/{errors-CjPmyZHy.js.map → errors-BsemQCMn.js.map} +1 -1
  13. package/dist/{errors-CLCjoSg0.cjs → errors-DykI11xo.cjs} +2 -2
  14. package/dist/{errors-CLCjoSg0.cjs.map → errors-DykI11xo.cjs.map} +1 -1
  15. package/dist/generate-BRpukupe.cjs +82 -0
  16. package/dist/generate-BRpukupe.cjs.map +1 -0
  17. package/dist/generate-XeCSLYWp.js +83 -0
  18. package/dist/generate-XeCSLYWp.js.map +1 -0
  19. package/dist/index.cjs +22 -16
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +21 -15
  23. package/dist/index.js.map +1 -1
  24. package/dist/init-C156kkn3.cjs +53 -0
  25. package/dist/init-C156kkn3.cjs.map +1 -0
  26. package/dist/init-Djx-xXm2.js +53 -0
  27. package/dist/init-Djx-xXm2.js.map +1 -0
  28. package/dist/mcp--t_K4yMF.js +39 -0
  29. package/dist/mcp--t_K4yMF.js.map +1 -0
  30. package/dist/mcp-D4ZwcNDD.cjs +39 -0
  31. package/dist/mcp-D4ZwcNDD.cjs.map +1 -0
  32. package/dist/package-_PDiS5qW.js +6 -0
  33. package/dist/package-_PDiS5qW.js.map +1 -0
  34. package/dist/{package-BmYRU2hz.cjs → package-aN3cIOkh.cjs} +2 -2
  35. package/dist/package-aN3cIOkh.cjs.map +1 -0
  36. package/dist/run-7yQQ3lIR.js +51 -0
  37. package/dist/run-7yQQ3lIR.js.map +1 -0
  38. package/dist/{init-C5sZulT6.cjs → run-BtjzfTz3.cjs} +155 -85
  39. package/dist/run-BtjzfTz3.cjs.map +1 -0
  40. package/dist/{init-Cag3082g.js → run-C-omuksC.js} +147 -77
  41. package/dist/run-C-omuksC.js.map +1 -0
  42. package/dist/run-CDs_ebOt.cjs +1458 -0
  43. package/dist/run-CDs_ebOt.cjs.map +1 -0
  44. package/dist/run-CZEf3B3A.cjs +33 -0
  45. package/dist/run-CZEf3B3A.cjs.map +1 -0
  46. package/dist/run-CsBW0NRp.js +32 -0
  47. package/dist/run-CsBW0NRp.js.map +1 -0
  48. package/dist/run-YYlwMdeu.cjs +52 -0
  49. package/dist/run-YYlwMdeu.cjs.map +1 -0
  50. package/dist/run-aODbKkaY.js +1455 -0
  51. package/dist/run-aODbKkaY.js.map +1 -0
  52. package/dist/{shell-DLzN4fRo.js → shell-DsgkfUSW.js} +2 -2
  53. package/dist/{shell-DLzN4fRo.js.map → shell-DsgkfUSW.js.map} +1 -1
  54. package/dist/{shell-475fQKaX.cjs → shell-Lh-vLWwH.cjs} +2 -2
  55. package/dist/{shell-475fQKaX.cjs.map → shell-Lh-vLWwH.cjs.map} +1 -1
  56. package/dist/validate-DWdTJLGF.js +26 -0
  57. package/dist/validate-DWdTJLGF.js.map +1 -0
  58. package/dist/validate-sOD68Kma.cjs +26 -0
  59. package/dist/validate-sOD68Kma.cjs.map +1 -0
  60. package/package.json +14 -24
  61. package/src/Telemetry.ts +290 -0
  62. package/src/commands/generate.ts +27 -13
  63. package/src/commands/init.ts +34 -3
  64. package/src/commands/mcp.ts +28 -4
  65. package/src/commands/validate.ts +6 -4
  66. package/src/constants.ts +1 -81
  67. package/src/index.ts +7 -6
  68. package/src/loggers/clackLogger.ts +135 -201
  69. package/src/loggers/defineLogger.ts +59 -0
  70. package/src/loggers/plainLogger.ts +47 -102
  71. package/src/loggers/types.ts +6 -1
  72. package/src/loggers/utils.ts +164 -23
  73. package/src/runners/generate/run.ts +403 -0
  74. package/src/runners/generate/utils.ts +228 -0
  75. package/src/runners/init/run.ts +210 -0
  76. package/src/{utils/packageManager.ts → runners/init/utils.ts} +12 -2
  77. package/src/runners/mcp/run.ts +37 -0
  78. package/src/runners/validate/run.ts +63 -0
  79. package/dist/agent-BcUEl9yB.js +0 -56
  80. package/dist/agent-BcUEl9yB.js.map +0 -1
  81. package/dist/agent-CS45W0kL.cjs +0 -122
  82. package/dist/agent-CS45W0kL.cjs.map +0 -1
  83. package/dist/agent-CsMvXeqI.cjs +0 -58
  84. package/dist/agent-CsMvXeqI.cjs.map +0 -1
  85. package/dist/agent-IP0eLV3C.js +0 -118
  86. package/dist/agent-IP0eLV3C.js.map +0 -1
  87. package/dist/constants-B4iBDvCe.cjs +0 -148
  88. package/dist/constants-B4iBDvCe.cjs.map +0 -1
  89. package/dist/constants-DmPrkaz8.js +0 -95
  90. package/dist/constants-DmPrkaz8.js.map +0 -1
  91. package/dist/generate-7td_hs73.cjs +0 -65
  92. package/dist/generate-7td_hs73.cjs.map +0 -1
  93. package/dist/generate-BqeFFQGD.js +0 -66
  94. package/dist/generate-BqeFFQGD.js.map +0 -1
  95. package/dist/generate-CUd1dUY5.cjs +0 -1755
  96. package/dist/generate-CUd1dUY5.cjs.map +0 -1
  97. package/dist/generate-DVmGtwWe.js +0 -1752
  98. package/dist/generate-DVmGtwWe.js.map +0 -1
  99. package/dist/init-C5sZulT6.cjs.map +0 -1
  100. package/dist/init-Cag3082g.js.map +0 -1
  101. package/dist/init-CfAn19gC.js +0 -25
  102. package/dist/init-CfAn19gC.js.map +0 -1
  103. package/dist/init-CfsYoyGe.cjs +0 -25
  104. package/dist/init-CfsYoyGe.cjs.map +0 -1
  105. package/dist/mcp-BfORW-mY.cjs +0 -47
  106. package/dist/mcp-BfORW-mY.cjs.map +0 -1
  107. package/dist/mcp-BtOV6acy.js +0 -16
  108. package/dist/mcp-BtOV6acy.js.map +0 -1
  109. package/dist/mcp-CIbuLGMx.cjs +0 -16
  110. package/dist/mcp-CIbuLGMx.cjs.map +0 -1
  111. package/dist/mcp-DtQ5o0On.js +0 -46
  112. package/dist/mcp-DtQ5o0On.js.map +0 -1
  113. package/dist/package-BmYRU2hz.cjs.map +0 -1
  114. package/dist/package-DBU5ii-k.js +0 -6
  115. package/dist/package-DBU5ii-k.js.map +0 -1
  116. package/dist/telemetry-BU25EoI-.cjs +0 -282
  117. package/dist/telemetry-BU25EoI-.cjs.map +0 -1
  118. package/dist/telemetry-CaNU4-Bf.js +0 -245
  119. package/dist/telemetry-CaNU4-Bf.js.map +0 -1
  120. package/dist/validate-CQqM9siF.js +0 -25
  121. package/dist/validate-CQqM9siF.js.map +0 -1
  122. package/dist/validate-DBXLaLIn.cjs +0 -34
  123. package/dist/validate-DBXLaLIn.cjs.map +0 -1
  124. package/dist/validate-DI23zgmL.js +0 -33
  125. package/dist/validate-DI23zgmL.js.map +0 -1
  126. package/dist/validate-DwX4LzYq.cjs +0 -25
  127. package/dist/validate-DwX4LzYq.cjs.map +0 -1
  128. package/src/commands/agent/start.ts +0 -47
  129. package/src/commands/agent.ts +0 -8
  130. package/src/loggers/fileSystemLogger.ts +0 -138
  131. package/src/loggers/githubActionsLogger.ts +0 -379
  132. package/src/runners/agent.ts +0 -155
  133. package/src/runners/generate.ts +0 -333
  134. package/src/runners/init.ts +0 -296
  135. package/src/runners/mcp.ts +0 -51
  136. package/src/runners/validate.ts +0 -39
  137. package/src/types.ts +0 -11
  138. package/src/utils/Writables.ts +0 -17
  139. package/src/utils/executeHooks.ts +0 -45
  140. package/src/utils/flags.ts +0 -9
  141. package/src/utils/getConfig.ts +0 -10
  142. package/src/utils/getCosmiConfig.ts +0 -75
  143. package/src/utils/getSummary.ts +0 -68
  144. package/src/utils/runHook.ts +0 -91
  145. package/src/utils/telemetry.ts +0 -273
  146. package/src/utils/watcher.ts +0 -19
  147. /package/dist/{chunk-ByKO4r7w.cjs → chunk-Bx3C2hgW.cjs} +0 -0
  148. /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
@@ -0,0 +1,290 @@
1
+ import { randomBytes } from 'node:crypto'
2
+ import os from 'node:os'
3
+ import process from 'node:process'
4
+ import { executeIfOnline, getRuntimeName, getRuntimeVersion, isCIEnvironment, type RuntimeName } from '@internals/utils'
5
+ import { OTLP_ENDPOINT } from './constants.ts'
6
+
7
+ // OpenTelemetry OTLP JSON types
8
+ // https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto
9
+ // https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/common/v1/common.proto
10
+
11
+ type OtlpStringValue = { stringValue: string }
12
+ type OtlpBoolValue = { boolValue: boolean }
13
+ type OtlpIntValue = { intValue: number }
14
+ type OtlpDoubleValue = { doubleValue: number }
15
+ type OtlpBytesValue = { bytesValue: string }
16
+ type OtlpArrayValue = { arrayValue: { values: Array<OtlpAnyValue> } }
17
+ type OtlpKvListValue = { kvlistValue: { values: Array<OtlpKeyValue> } }
18
+
19
+ type OtlpAnyValue = OtlpStringValue | OtlpBoolValue | OtlpIntValue | OtlpDoubleValue | OtlpBytesValue | OtlpArrayValue | OtlpKvListValue
20
+
21
+ type OtlpKeyValue = {
22
+ key: string
23
+ value: OtlpAnyValue
24
+ }
25
+
26
+ type OtlpResource = {
27
+ attributes: Array<OtlpKeyValue>
28
+ droppedAttributesCount?: number
29
+ }
30
+
31
+ type OtlpInstrumentationScope = {
32
+ name: string
33
+ version?: string
34
+ attributes?: Array<OtlpKeyValue>
35
+ droppedAttributesCount?: number
36
+ }
37
+
38
+ /** https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto#L103 */
39
+ type OtlpSpanKind = 0 | 1 | 2 | 3 | 4 | 5
40
+
41
+ /** 0 = STATUS_CODE_UNSET, 1 = STATUS_CODE_OK, 2 = STATUS_CODE_ERROR */
42
+ type OtlpStatusCode = 0 | 1 | 2
43
+
44
+ type OtlpStatus = {
45
+ code: OtlpStatusCode
46
+ message?: string
47
+ }
48
+
49
+ type OtlpSpan = {
50
+ traceId: string
51
+ spanId: string
52
+ traceState?: string
53
+ parentSpanId?: string
54
+ name: string
55
+ kind: OtlpSpanKind
56
+ startTimeUnixNano: string
57
+ endTimeUnixNano: string
58
+ attributes?: Array<OtlpKeyValue>
59
+ droppedAttributesCount?: number
60
+ events?: Array<OtlpSpanEvent>
61
+ droppedEventsCount?: number
62
+ links?: Array<OtlpSpanLink>
63
+ droppedLinksCount?: number
64
+ status?: OtlpStatus
65
+ }
66
+
67
+ type OtlpSpanEvent = {
68
+ timeUnixNano: string
69
+ name: string
70
+ attributes?: Array<OtlpKeyValue>
71
+ droppedAttributesCount?: number
72
+ }
73
+
74
+ type OtlpSpanLink = {
75
+ traceId: string
76
+ spanId: string
77
+ traceState?: string
78
+ attributes?: Array<OtlpKeyValue>
79
+ droppedAttributesCount?: number
80
+ }
81
+
82
+ type OtlpScopeSpans = {
83
+ scope: OtlpInstrumentationScope
84
+ spans: Array<OtlpSpan>
85
+ schemaUrl?: string
86
+ }
87
+
88
+ type OtlpResourceSpans = {
89
+ resource: OtlpResource
90
+ scopeSpans: Array<OtlpScopeSpans>
91
+ schemaUrl?: string
92
+ }
93
+
94
+ /** Root payload sent to POST /v1/traces */
95
+ type OtlpExportTraceServiceRequest = {
96
+ resourceSpans: Array<OtlpResourceSpans>
97
+ }
98
+
99
+ /**
100
+ * Anonymous plugin name and options snapshot sent with each telemetry event.
101
+ */
102
+ export type TelemetryPlugin = {
103
+ /**
104
+ * Plugin name as registered in the Kubb config, e.g. `'@kubb/plugin-ts'`.
105
+ */
106
+ name: string
107
+ /**
108
+ * anonymized plugin options snapshot, values are included but cannot be traced back to the user.
109
+ */
110
+ options: Record<string, unknown>
111
+ }
112
+
113
+ export type TelemetryEvent = {
114
+ command: string
115
+ kubbVersion: string
116
+ nodeVersion: string
117
+ /**
118
+ * Name of the JavaScript runtime that executed the run, `'bun'`, `'deno'`, or `'node'`.
119
+ */
120
+ runtime: RuntimeName
121
+ /**
122
+ * Major version of the active runtime, e.g. `'1'` under Bun or `'22'` under Node.
123
+ */
124
+ runtimeVersion: string
125
+ platform: string
126
+ ci: boolean
127
+ plugins: Array<TelemetryPlugin>
128
+ duration: number
129
+ filesCreated: number
130
+ status: 'success' | 'failed'
131
+ }
132
+
133
+ /**
134
+ * Anonymous OTLP usage telemetry for the Kubb run. All methods are static, so call them as
135
+ * `Telemetry.build(...)`, `Telemetry.send(...)`, and `Telemetry.isDisabled()`. No file paths,
136
+ * OpenAPI specs, or secrets are ever included, and sending fails silently to never break a run.
137
+ */
138
+ export class Telemetry {
139
+ /**
140
+ * Returns `true` when telemetry is disabled via `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY`.
141
+ */
142
+ static isDisabled(): boolean {
143
+ return (
144
+ process.env['DO_NOT_TRACK'] === '1' ||
145
+ process.env['DO_NOT_TRACK'] === 'true' ||
146
+ process.env['KUBB_DISABLE_TELEMETRY'] === '1' ||
147
+ process.env['KUBB_DISABLE_TELEMETRY'] === 'true'
148
+ )
149
+ }
150
+
151
+ /**
152
+ * Build an anonymous telemetry payload from a completed generation run.
153
+ */
154
+ static build(options: {
155
+ command: 'generate' | 'mcp' | 'validate' | 'agent'
156
+ kubbVersion: string
157
+ plugins?: Array<TelemetryPlugin>
158
+ hrStart: [number, number]
159
+ filesCreated?: number
160
+ status: 'success' | 'failed'
161
+ }): TelemetryEvent {
162
+ const [seconds, nanoseconds] = process.hrtime(options.hrStart)
163
+ const duration = Math.round(seconds * 1000 + nanoseconds / 1e6)
164
+
165
+ return {
166
+ command: options.command,
167
+ kubbVersion: options.kubbVersion,
168
+ nodeVersion: process.versions.node.split('.')[0] as string,
169
+ runtime: getRuntimeName(),
170
+ runtimeVersion: getRuntimeVersion().split('.')[0] as string,
171
+ platform: os.platform(),
172
+ ci: isCIEnvironment(),
173
+ plugins: options.plugins ?? [],
174
+ duration,
175
+ filesCreated: options.filesCreated ?? 0,
176
+ status: options.status,
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Convert a {@link TelemetryEvent} into an OTLP-compatible JSON trace payload.
182
+ * See https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/
183
+ */
184
+ static buildOtlpPayload(event: TelemetryEvent): OtlpExportTraceServiceRequest {
185
+ const traceId = randomBytes(16).toString('hex')
186
+ const spanId = randomBytes(8).toString('hex')
187
+ const endTimeNs = BigInt(Date.now()) * 1_000_000n
188
+ const startTimeNs = endTimeNs - BigInt(event.duration) * 1_000_000n
189
+
190
+ const attributes: Array<OtlpKeyValue> = [
191
+ { key: 'kubb.command', value: { stringValue: event.command } },
192
+ { key: 'kubb.version', value: { stringValue: event.kubbVersion } },
193
+ { key: 'kubb.node_version', value: { stringValue: event.nodeVersion } },
194
+ { key: 'kubb.runtime', value: { stringValue: event.runtime } },
195
+ { key: 'kubb.runtime_version', value: { stringValue: event.runtimeVersion } },
196
+ { key: 'kubb.platform', value: { stringValue: event.platform } },
197
+ { key: 'kubb.ci', value: { boolValue: event.ci } },
198
+ { key: 'kubb.files_created', value: { intValue: event.filesCreated } },
199
+ { key: 'kubb.status', value: { stringValue: event.status } },
200
+ {
201
+ key: 'kubb.plugins',
202
+ value: {
203
+ arrayValue: {
204
+ values: event.plugins.map(
205
+ (p): OtlpKvListValue => ({
206
+ kvlistValue: {
207
+ values: [
208
+ { key: 'name', value: { stringValue: p.name } },
209
+ {
210
+ key: 'options',
211
+ value: {
212
+ stringValue: JSON.stringify({
213
+ ...p.options,
214
+ usedEnumNames: undefined,
215
+ }),
216
+ },
217
+ },
218
+ ],
219
+ },
220
+ }),
221
+ ),
222
+ },
223
+ },
224
+ },
225
+ ]
226
+
227
+ return {
228
+ resourceSpans: [
229
+ {
230
+ resource: {
231
+ attributes: [
232
+ { key: 'service.name', value: { stringValue: 'kubb-core' } },
233
+ {
234
+ key: 'service.version',
235
+ value: { stringValue: event.kubbVersion },
236
+ },
237
+ { key: 'telemetry.sdk.language', value: { stringValue: 'nodejs' } },
238
+ ],
239
+ },
240
+ scopeSpans: [
241
+ {
242
+ scope: { name: 'kubb-core', version: event.kubbVersion },
243
+ spans: [
244
+ {
245
+ traceId,
246
+ spanId,
247
+ name: event.command,
248
+ kind: 1 satisfies OtlpSpanKind,
249
+ startTimeUnixNano: String(startTimeNs),
250
+ endTimeUnixNano: String(endTimeNs),
251
+ attributes,
252
+ status: {
253
+ code: (event.status === 'success' ? 1 : 2) satisfies OtlpStatusCode,
254
+ },
255
+ },
256
+ ],
257
+ },
258
+ ],
259
+ },
260
+ ],
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Send an anonymous telemetry event to the Kubb OTLP endpoint. Respects `DO_NOT_TRACK` and
266
+ * `KUBB_DISABLE_TELEMETRY`, and fails silently so telemetry never interrupts a run.
267
+ */
268
+ static async send(event: TelemetryEvent): Promise<void> {
269
+ if (Telemetry.isDisabled()) {
270
+ return
271
+ }
272
+
273
+ await executeIfOnline(async () => {
274
+ try {
275
+ await fetch(`${OTLP_ENDPOINT}/v1/traces`, {
276
+ method: 'POST',
277
+ headers: {
278
+ 'Content-Type': 'application/json',
279
+ 'Kubb-Telemetry-Version': '1',
280
+ 'Kubb-Telemetry-Source': 'kubb-core',
281
+ },
282
+ body: JSON.stringify(Telemetry.buildOtlpPayload(event)),
283
+ signal: AbortSignal.timeout(5_000),
284
+ })
285
+ } catch (_e) {
286
+ // Fail silently, telemetry must never break the run
287
+ }
288
+ })
289
+ }
290
+ }
@@ -1,9 +1,12 @@
1
1
  import { defineCommand } from '@internals/utils'
2
+ import type { ReporterName } from '@kubb/core'
2
3
 
3
4
  export const command = defineCommand({
4
5
  name: 'generate',
5
- description: "[input] Generate files based on a 'kubb.config.ts' file",
6
+ description:
7
+ '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.',
6
8
  arguments: ['[input]'],
9
+ examples: ['kubb generate', 'kubb generate ./openapi.yaml', 'kubb generate --config kubb.config.ts', 'kubb generate --watch'],
7
10
  options: {
8
11
  config: {
9
12
  type: 'string',
@@ -12,11 +15,11 @@ export const command = defineCommand({
12
15
  },
13
16
  logLevel: {
14
17
  type: 'string',
15
- description: 'Info, silent, verbose or debug',
18
+ description: 'Info, silent or verbose',
16
19
  short: 'l',
17
20
  default: 'info',
18
- hint: 'silent|info|verbose|debug',
19
- enum: ['silent', 'info', 'verbose', 'debug'],
21
+ hint: 'silent|info|verbose',
22
+ enum: ['silent', 'info', 'verbose'],
20
23
  },
21
24
  watch: {
22
25
  type: 'boolean',
@@ -24,12 +27,6 @@ export const command = defineCommand({
24
27
  short: 'w',
25
28
  default: false,
26
29
  },
27
- debug: {
28
- type: 'boolean',
29
- description: 'Override logLevel to debug',
30
- short: 'd',
31
- default: false,
32
- },
33
30
  verbose: {
34
31
  type: 'boolean',
35
32
  description: 'Override logLevel to verbose',
@@ -42,16 +39,33 @@ export const command = defineCommand({
42
39
  short: 's',
43
40
  default: false,
44
41
  },
42
+ reporter: {
43
+ type: 'string',
44
+ description: 'Reporters that render the run, comma-separated. Overrides config.reporters',
45
+ hint: 'cli|json|file',
46
+ enum: ['cli', 'json', 'file'],
47
+ },
48
+ 'no-cache': {
49
+ type: 'boolean',
50
+ description: 'Disable the incremental build cache and force a full regeneration',
51
+ default: false,
52
+ },
45
53
  },
46
54
  async run({ values, positionals }) {
47
- const logLevel = values.debug ? 'debug' : values.verbose ? 'verbose' : values.silent ? 'silent' : values.logLevel
48
- const { runGenerateCommand } = await import('../runners/generate.ts')
55
+ const logLevel = values.verbose ? 'verbose' : values.silent ? 'silent' : values.logLevel
56
+ const reporters = values.reporter
57
+ ?.split(',')
58
+ .map((name) => name.trim())
59
+ .filter(Boolean) as Array<ReporterName> | undefined
60
+ const { run } = await import('../runners/generate/run.ts')
49
61
 
50
- await runGenerateCommand({
62
+ await run({
51
63
  input: positionals[0],
52
64
  configPath: values.config,
53
65
  logLevel,
54
66
  watch: values.watch,
67
+ reporters,
68
+ noCache: values['no-cache'],
55
69
  })
56
70
  },
57
71
  })
@@ -3,7 +3,14 @@ import { version } from '../../package.json'
3
3
 
4
4
  export const command = defineCommand({
5
5
  name: 'init',
6
- description: 'Initialize a new Kubb project with interactive setup',
6
+ description:
7
+ '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.',
8
+ examples: [
9
+ 'kubb init',
10
+ 'kubb init --yes',
11
+ 'kubb init --input ./openapi.yaml --output ./src/gen --plugins plugin-ts,plugin-zod',
12
+ 'kubb init --plugins plugin-ts,plugin-client,plugin-react-query',
13
+ ],
7
14
  options: {
8
15
  yes: {
9
16
  type: 'boolean',
@@ -11,10 +18,34 @@ export const command = defineCommand({
11
18
  short: 'y',
12
19
  default: false,
13
20
  },
21
+ input: {
22
+ type: 'string',
23
+ description: 'Path to the OpenAPI specification',
24
+ short: 'i',
25
+ hint: 'path',
26
+ },
27
+ output: {
28
+ type: 'string',
29
+ description: 'Output directory for generated files',
30
+ short: 'o',
31
+ hint: 'path',
32
+ },
33
+ plugins: {
34
+ type: 'string',
35
+ description:
36
+ 'Comma-separated list of plugins to use (plugin-ts, plugin-client, plugin-react-query, plugin-vue-query, plugin-zod, plugin-faker, plugin-msw, plugin-cypress, plugin-mcp, plugin-redoc)',
37
+ hint: 'plugin-ts,plugin-zod,...',
38
+ },
14
39
  },
15
40
  async run({ values }) {
16
- const { runInit } = await import('../runners/init.ts')
41
+ const { run } = await import('../runners/init/run.ts')
17
42
 
18
- await runInit({ yes: values.yes, version })
43
+ await run({
44
+ yes: values.yes,
45
+ version,
46
+ input: values.input,
47
+ output: values.output,
48
+ plugins: values.plugins,
49
+ })
19
50
  },
20
51
  })
@@ -3,10 +3,34 @@ import { version } from '../../package.json'
3
3
 
4
4
  export const command = defineCommand({
5
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')
6
+ description:
7
+ '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.',
8
+ examples: [
9
+ 'kubb mcp',
10
+ 'kubb mcp --port 3001',
11
+ '# Then add to your MCP client config:',
12
+ '# { "mcpServers": { "kubb": { "command": "npx", "args": ["kubb", "mcp"] } } }',
13
+ ],
14
+ options: {
15
+ port: {
16
+ type: 'string',
17
+ short: 'p',
18
+ description: 'Port for HTTP MCP server (omit for stdio)',
19
+ hint: 'number',
20
+ },
21
+ host: {
22
+ type: 'string',
23
+ description: 'Hostname to bind to (HTTP mode only)',
24
+ default: 'localhost',
25
+ },
26
+ },
27
+ async run({ values }) {
28
+ const { run } = await import('../runners/mcp/run.ts')
9
29
 
10
- await runMcp({ version })
30
+ await run({
31
+ version,
32
+ port: values.port,
33
+ host: values.host,
34
+ })
11
35
  },
12
36
  })
@@ -3,18 +3,20 @@ import { version } from '../../package.json'
3
3
 
4
4
  export const command = defineCommand({
5
5
  name: 'validate',
6
- description: 'Validate a Swagger/OpenAPI file',
6
+ description:
7
+ '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.',
8
+ examples: ['kubb validate --input ./openapi.yaml', 'kubb validate --input https://petstore3.swagger.io/api/v3/openapi.json'],
7
9
  options: {
8
10
  input: {
9
11
  type: 'string',
10
- description: 'Path to Swagger/OpenAPI file',
12
+ description: 'Path or URL to the OpenAPI/Swagger file to validate',
11
13
  short: 'i',
12
14
  required: true,
13
15
  },
14
16
  },
15
17
  async run({ values }) {
16
- const { runValidate } = await import('../runners/validate.ts')
18
+ const { run } = await import('../runners/validate/run.ts')
17
19
 
18
- await runValidate({ input: values.input, version })
20
+ await run({ input: values.input, version })
19
21
  },
20
22
  })
package/src/constants.ts CHANGED
@@ -1,10 +1,3 @@
1
- /**
2
- * Default filename for the Kubb configuration file.
3
- *
4
- * Used by the `init` command when scaffolding new projects and by the `agent` default config.
5
- */
6
- export const KUBB_CONFIG_FILENAME = 'kubb.config.ts' as const
7
-
8
1
  /**
9
2
  * NPM registry endpoint used to check for @kubb/cli updates.
10
3
  */
@@ -20,85 +13,12 @@ export const OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const
20
13
  */
21
14
  export const SUMMARY_SEPARATOR = '─'.repeat(27)
22
15
 
23
- /**
24
- * Maximum number of █ characters in a plugin timing bar.
25
- */
26
- export const SUMMARY_MAX_BAR_LENGTH = 10 as const
27
-
28
- /**
29
- * Divides elapsed milliseconds into bar-length units (1 block per 100 ms).
30
- */
31
- export const SUMMARY_TIME_SCALE_DIVISOR = 100 as const
32
-
33
16
  /**
34
17
  * Glob pattern for paths the file watcher ignores.
35
18
  */
36
19
  export const WATCHER_IGNORED_PATHS = '**/{.git,node_modules}/**' as const
37
20
 
38
21
  /**
39
- * Flags that short-circuit execution (help/version) no telemetry notice is shown.
22
+ * Flags that short-circuit execution (help/version), no telemetry notice is shown.
40
23
  */
41
24
  export const QUIET_FLAGS = new Set(['--help', '-h', '--version', '-v'] as const)
42
-
43
- export const agentDefaults = {
44
- port: '3000',
45
- host: 'localhost',
46
- configFile: KUBB_CONFIG_FILENAME,
47
- retryTimeout: '30000',
48
- studioUrl: 'https://kubb.studio',
49
- /**
50
- * Relative path from the @kubb/agent package root to the server entry.
51
- */
52
- serverEntryPath: '.output/server/index.mjs',
53
- } as const
54
-
55
- /**
56
- * Default values used during interactive `init` scaffolding.
57
- */
58
- export const initDefaults = {
59
- inputPath: './openapi.yaml',
60
- outputPath: './src/gen',
61
- plugins: ['plugin-ts'],
62
- } as const
63
-
64
- /**
65
- * Maps each plugin value to the default config snippet inserted by `init`.
66
- * The `satisfies` constraint ensures all values remain plain strings while
67
- * `as const` keeps the object deeply immutable.
68
- */
69
- export const pluginDefaultConfigs = {
70
- 'plugin-ts': `pluginTs({
71
- output: { path: 'models' },
72
- })`,
73
- 'plugin-client': `pluginClient({
74
- output: { path: 'clients' },
75
- })`,
76
- 'plugin-react-query': `pluginReactQuery({
77
- output: { path: 'hooks' },
78
- })`,
79
- 'plugin-vue-query': `pluginVueQuery({
80
- output: { path: 'hooks' },
81
- })`,
82
- 'plugin-zod': `pluginZod({
83
- output: { path: 'zod' },
84
- })`,
85
- 'plugin-faker': `pluginFaker({
86
- output: { path: 'mocks' },
87
- })`,
88
- 'plugin-msw': `pluginMsw({
89
- output: { path: 'msw' },
90
- })`,
91
- 'plugin-cypress': `pluginCypress({
92
- output: { path: 'cypress' },
93
- })`,
94
- 'plugin-mcp': `pluginMcp({
95
- output: { path: 'mcp' },
96
- })`,
97
- 'plugin-redoc': `pluginRedoc({
98
- output: { path: 'redoc' },
99
- })`,
100
- } as const satisfies Record<string, string>
101
-
102
- /**
103
- * Color palette used by randomCliColor() for deterministic plugin name coloring.
104
- */
package/src/index.ts CHANGED
@@ -1,24 +1,26 @@
1
1
  import { styleText } from 'node:util'
2
- import { createCLI } from '@internals/utils'
2
+ import { createCLI, isFlag } from '@internals/utils'
3
+ import { Telemetry } from './Telemetry.ts'
3
4
  import { version } from '../package.json'
4
5
  import { QUIET_FLAGS } from './constants.ts'
5
- import { isFlag } from './utils/flags.ts'
6
- import { isTelemetryDisabled } from './utils/telemetry.ts'
7
6
 
8
7
  const cli = createCLI()
9
8
 
10
9
  function shouldShowTelemetryNotice(argv: Array<string>): boolean {
11
- if (isTelemetryDisabled()) {
10
+ if (Telemetry.isDisabled()) {
12
11
  return false
13
12
  }
13
+
14
14
  // Skip when the user is just asking for help or version info
15
15
  if (argv.some((arg) => isFlag(QUIET_FLAGS, arg))) {
16
16
  return false
17
17
  }
18
+
18
19
  // Skip in non-interactive / scripting contexts
19
20
  if (!process.stdout.isTTY) {
20
21
  return false
21
22
  }
23
+
22
24
  return true
23
25
  }
24
26
 
@@ -32,10 +34,9 @@ export async function run(argv: Array<string> = process.argv): Promise<void> {
32
34
  const { command: generateCommand } = await import('./commands/generate.ts')
33
35
  const { command: validateCommand } = await import('./commands/validate.ts')
34
36
  const { command: mcpCommand } = await import('./commands/mcp.ts')
35
- const { command: agentCommand } = await import('./commands/agent.ts')
36
37
  const { command: initCommand } = await import('./commands/init.ts')
37
38
 
38
- await cli.run([generateCommand, validateCommand, mcpCommand, agentCommand, initCommand], argv, {
39
+ await cli.run([generateCommand, validateCommand, mcpCommand, initCommand], argv, {
39
40
  programName: 'kubb',
40
41
  defaultCommandName: 'generate',
41
42
  version,