@kubb/cli 5.5.1 → 5.5.2

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 (73) hide show
  1. package/dist/background-CZuTWCy0.js +2 -0
  2. package/dist/{background-BHibcUDK.cjs → background-DUJO9lqp.cjs} +2 -2
  3. package/dist/{background-BHibcUDK.cjs.map → background-DUJO9lqp.cjs.map} +1 -1
  4. package/dist/{background-DcpW8Jt8.js → background-b3ec0X42.js} +2 -2
  5. package/dist/{background-DcpW8Jt8.js.map → background-b3ec0X42.js.map} +1 -1
  6. package/dist/{connect-p1EzlAh3.js → connect-BSN9mNt_.js} +2 -2
  7. package/dist/{connect-p1EzlAh3.js.map → connect-BSN9mNt_.js.map} +1 -1
  8. package/dist/{connect-C2Huv3eu.cjs → connect-_W1N8mi7.cjs} +2 -2
  9. package/dist/{connect-C2Huv3eu.cjs.map → connect-_W1N8mi7.cjs.map} +1 -1
  10. package/dist/{generate-Cwso-T3K.cjs → generate-Dp0XRNH2.cjs} +2 -2
  11. package/dist/{generate-Cwso-T3K.cjs.map → generate-Dp0XRNH2.cjs.map} +1 -1
  12. package/dist/{generate-AaJEmH-4.js → generate-Y4iSiFAh.js} +2 -2
  13. package/dist/{generate-AaJEmH-4.js.map → generate-Y4iSiFAh.js.map} +1 -1
  14. package/dist/index.cjs +7 -7
  15. package/dist/index.js +7 -7
  16. package/dist/{init-DAuNBWCu.cjs → init-DbgeeViU.cjs} +2 -2
  17. package/dist/{init-DAuNBWCu.cjs.map → init-DbgeeViU.cjs.map} +1 -1
  18. package/dist/{init-r-VNmyDG.js → init-aIf8EBRW.js} +2 -2
  19. package/dist/{init-r-VNmyDG.js.map → init-aIf8EBRW.js.map} +1 -1
  20. package/dist/{login-CYX3xWkR.cjs → login-CA_mjtz4.cjs} +2 -2
  21. package/dist/{login-CYX3xWkR.cjs.map → login-CA_mjtz4.cjs.map} +1 -1
  22. package/dist/{login-CbhAtRyZ.js → login-rq_qEFoy.js} +2 -2
  23. package/dist/{login-CbhAtRyZ.js.map → login-rq_qEFoy.js.map} +1 -1
  24. package/dist/{logout-mwCPN69X.js → logout-B1J5c86y.js} +3 -3
  25. package/dist/{logout-mwCPN69X.js.map → logout-B1J5c86y.js.map} +1 -1
  26. package/dist/{logout-cJ1Z7o2a.cjs → logout-DOMpoFGT.cjs} +3 -3
  27. package/dist/{logout-cJ1Z7o2a.cjs.map → logout-DOMpoFGT.cjs.map} +1 -1
  28. package/dist/package-CWi7augV.js +6 -0
  29. package/dist/package-CWi7augV.js.map +1 -0
  30. package/dist/{package-BgCML9qr.cjs → package-DTQG_XnR.cjs} +2 -2
  31. package/dist/package-DTQG_XnR.cjs.map +1 -0
  32. package/dist/{run-CdPrp4Lu.cjs → run-B4Za6HxI.cjs} +2 -2
  33. package/dist/{run-CdPrp4Lu.cjs.map → run-B4Za6HxI.cjs.map} +1 -1
  34. package/dist/{run-CDNCL7Rq.cjs → run-C0lN0_dx.cjs} +2 -2
  35. package/dist/{run-CDNCL7Rq.cjs.map → run-C0lN0_dx.cjs.map} +1 -1
  36. package/dist/{run-CfpFOmPH.js → run-C1NcWnFi.js} +2 -2
  37. package/dist/{run-CfpFOmPH.js.map → run-C1NcWnFi.js.map} +1 -1
  38. package/dist/{run-bakr1FvL.cjs → run-C3hTDMfs.cjs} +2 -2
  39. package/dist/{run-bakr1FvL.cjs.map → run-C3hTDMfs.cjs.map} +1 -1
  40. package/dist/{run-ev2SVzT3.js → run-Cb78U4HC.js} +2 -2
  41. package/dist/{run-ev2SVzT3.js.map → run-Cb78U4HC.js.map} +1 -1
  42. package/dist/{run-LMAru4TP.js → run-D9nqSLXW.js} +2 -2
  43. package/dist/{run-LMAru4TP.js.map → run-D9nqSLXW.js.map} +1 -1
  44. package/dist/{run-DI26m-2b.js → run-DBMVTeYc.js} +3 -3
  45. package/dist/{run-DI26m-2b.js.map → run-DBMVTeYc.js.map} +1 -1
  46. package/dist/{run-CZXyo8RD.cjs → run-DcxxL66g.cjs} +3 -3
  47. package/dist/{run-CZXyo8RD.cjs.map → run-DcxxL66g.cjs.map} +1 -1
  48. package/dist/{snapshot-DKUizqOM.cjs → snapshot-DA8yQlOl.cjs} +2 -2
  49. package/dist/{snapshot-DKUizqOM.cjs.map → snapshot-DA8yQlOl.cjs.map} +1 -1
  50. package/dist/{snapshot-z16ljPYs.js → snapshot-rP4XpT9w.js} +2 -2
  51. package/dist/{snapshot-z16ljPYs.js.map → snapshot-rP4XpT9w.js.map} +1 -1
  52. package/dist/{start-Bih15t7V.cjs → start-BLKEsPUc.cjs} +3 -3
  53. package/dist/{start-Bih15t7V.cjs.map → start-BLKEsPUc.cjs.map} +1 -1
  54. package/dist/{start-Dt-m6fct.js → start-DMXfSS7t.js} +3 -3
  55. package/dist/{start-Dt-m6fct.js.map → start-DMXfSS7t.js.map} +1 -1
  56. package/dist/{status-k9Sch6rY.js → status-gcJj6O3t.js} +3 -3
  57. package/dist/{status-k9Sch6rY.js.map → status-gcJj6O3t.js.map} +1 -1
  58. package/dist/{status-Dt0k603e.cjs → status-s8YBdmMW.cjs} +3 -3
  59. package/dist/{status-Dt0k603e.cjs.map → status-s8YBdmMW.cjs.map} +1 -1
  60. package/dist/{stop-BGyspZY0.cjs → stop-C1e8G7Dq.cjs} +2 -2
  61. package/dist/{stop-BGyspZY0.cjs.map → stop-C1e8G7Dq.cjs.map} +1 -1
  62. package/dist/{stop-Bm0D-Gre.js → stop-Dx4_298O.js} +2 -2
  63. package/dist/{stop-Bm0D-Gre.js.map → stop-Dx4_298O.js.map} +1 -1
  64. package/dist/{studio-B7O4GH3P.js → studio-D4FYZGwK.js} +9 -9
  65. package/dist/{studio-B7O4GH3P.js.map → studio-D4FYZGwK.js.map} +1 -1
  66. package/dist/{studio-BOpBx5Z_.cjs → studio-D7hfq4EP.cjs} +9 -9
  67. package/dist/{studio-BOpBx5Z_.cjs.map → studio-D7hfq4EP.cjs.map} +1 -1
  68. package/dist/studioWorker.js +2 -2
  69. package/package.json +7 -7
  70. package/dist/background-iLjxcrns.js +0 -2
  71. package/dist/package-BgCML9qr.cjs.map +0 -1
  72. package/dist/package-CW_5mbRf.js +0 -6
  73. package/dist/package-CW_5mbRf.js.map +0 -1
@@ -3,7 +3,7 @@ const require_errors = require("./errors-C-wEou02.cjs");
3
3
  const require_Telemetry = require("./Telemetry-B3kc9gFh.cjs");
4
4
  const require_utils = require("./utils-Dcw3l4Wz.cjs");
5
5
  const require_output = require("./output-9qUFmWFq.cjs");
6
- const require_package = require("./package-BgCML9qr.cjs");
6
+ const require_package = require("./package-DTQG_XnR.cjs");
7
7
  let node_util = require("node:util");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_process = require("node:process");
@@ -288,4 +288,4 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
288
288
  //#endregion
289
289
  exports.run = run;
290
290
 
291
- //# sourceMappingURL=run-CDNCL7Rq.cjs.map
291
+ //# sourceMappingURL=run-C0lN0_dx.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-CDNCL7Rq.cjs","names":["styleText","existsSync","logLevelMap","randomUUID","runHook","toError","process","memoryStorage","Diagnostics","formatters","detectTool","FORMATTER_PREFERENCE","linters","LINTER_PREFERENCE","runPostGenerate","createKubb","sendTelemetry","buildTelemetryEvent","version","KUBB_NPM_PACKAGE_URL","UPDATE_CHECK_TIMEOUT_MS","isNewerVersion","Hookable","createSpinner","getConfigs","path","setupReporters","cliReporter","selectReporters","pluralize","getInputKind","fetchUrlBody","logInfo","logError","startWatcher"],"sources":["../src/runners/generate/run.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport {\n Hookable,\n type CLIOptions,\n cliReporter,\n type Config,\n createKubb,\n type Diagnostic,\n Diagnostics,\n getInputKind,\n type KubbHooks,\n logLevel as logLevelMap,\n memoryStorage,\n type ProblemDiagnostic,\n type ReporterName,\n} from '@kubb/core'\nimport { version } from '../../../package.json'\nimport { KUBB_NPM_PACKAGE_URL, UPDATE_CHECK_TIMEOUT_MS } from '../../constants.ts'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport setupReporters, { pluralize, selectReporters } from '../../loggers/utils.ts'\nimport { createSpinner, logBanner, logError, logInfo, logIntro, logOutro, logSpacer, logStep, logTip } from '../../loggers/output.ts'\nimport { fetchUrlBody, getConfigs, isNewerVersion, runHook, runPostGenerate, startUrlWatcher, startWatcher } from './utils.ts'\nimport { FORMATTER_PREFERENCE, LINTER_PREFERENCE } from '@internals/utils'\nimport { detectTool, formatters, linters } from '../../tools.ts'\n\ntype GenerateProps = {\n input?: string\n config: Config\n hooks: Hookable<KubbHooks>\n logLevel: number\n /**\n * When `true`, generates in memory instead of writing to disk, and skips formatting, linting,\n * and post-generate commands.\n */\n dryRun?: boolean\n}\n\ntype ToolMap = typeof formatters | typeof linters\n\n/**\n * Static description of one output tool: its command table, the label and messages the pass logs,\n * and how to auto-detect it. Format and lint differ only in these values.\n */\ntype Tool = {\n label: string\n map: ToolMap\n detect: () => Promise<string | null>\n successPrefix: string\n noToolMessage: string\n}\n\ntype RunToolPassOptions = {\n toolValue: string\n tool: Tool\n outputPath: string\n logLevel: number\n hooks: Hookable<KubbHooks>\n onStart: () => Promise<void> | void\n onEnd: () => Promise<void> | void\n}\n\n/**\n * Runs one formatter or linter pass over the output directory. Returns the failure instead of\n * throwing, so the caller can turn it into a coded diagnostic. Failures never render here:\n * the caller emits them through `Diagnostics.emit`, like every other diagnostic.\n */\nasync function runToolPass({ toolValue, tool, outputPath, logLevel, hooks, onStart, onEnd }: RunToolPassOptions): Promise<Error | null> {\n await onStart()\n\n let resolvedTool = toolValue\n if (resolvedTool === 'auto') {\n const detected = await tool.detect()\n if (!detected) {\n await hooks.callHook('kubb:warn', { message: tool.noToolMessage })\n } else {\n resolvedTool = detected\n await hooks.callHook('kubb:info', { message: `Auto-detected ${tool.label}: ${styleText('dim', resolvedTool)}` })\n }\n }\n\n let toolError: Error | null = null\n\n // Nothing to lint or format when the output dir was never written. Skip so the tool\n // (e.g. oxlint with --no-ignore) doesn't fail with \"No files found to lint\".\n if (resolvedTool && resolvedTool !== 'auto' && resolvedTool in tool.map && existsSync(outputPath)) {\n const toolConfig = tool.map[resolvedTool as keyof ToolMap]\n\n const successMessage = [\n `${tool.successPrefix} with ${styleText('dim', resolvedTool)}`,\n logLevel >= logLevelMap.info ? `on ${styleText('dim', outputPath)}` : undefined,\n 'successfully',\n ]\n .filter(Boolean)\n .join(' ')\n\n try {\n const hookId = randomUUID()\n const hookArgs = toolConfig.args(outputPath)\n const commandWithArgs = [toolConfig.command, ...hookArgs].join(' ')\n\n await hooks.callHook('kubb:hook:start', { id: hookId, command: toolConfig.command, args: hookArgs })\n\n const result = await runHook({ id: hookId, command: toolConfig.command, args: hookArgs, commandWithArgs, hooks })\n\n if (result.success) {\n await hooks.callHook('kubb:success', { message: successMessage })\n } else {\n toolError = result.error ?? new Error(toolConfig.errorMessage)\n }\n } catch (caughtError) {\n toolError = toError(caughtError)\n }\n }\n\n await onEnd()\n\n return toolError\n}\n\nasync function generate(options: GenerateProps): Promise<boolean> {\n const { input, hooks, logLevel, dryRun = false } = options\n\n const hrStart = process.hrtime()\n\n const config: Config = {\n ...options.config,\n input: input ?? options.config.input,\n // Dry-run never touches disk, regardless of the config's own storage driver.\n storage: dryRun ? memoryStorage() : options.config.storage,\n // Also keeps core's `hasOutputPasses` false, so dry-run skips the output manifest write too.\n output: dryRun ? { ...options.config.output, format: false, lint: false, postGenerate: [] } : options.config.output,\n }\n\n // The formatter, linter, and post-generate commands run after a successful build. Collect their\n // failures as coded diagnostics so they reach the summary, the json report, and the exit code.\n const processOutput = async ({ config: resolvedConfig, outputPath }: { config: Config; outputPath: string }): Promise<Array<Diagnostic>> => {\n if (dryRun) return []\n\n const outputDiagnostics: Array<Diagnostic> = []\n const reportOutputFailure = async (code: ProblemDiagnostic['code'], label: string, error: Error) => {\n const diagnostic = outputDiagnostic(code, label, error)\n outputDiagnostics.push(diagnostic)\n await Diagnostics.emit(hooks, diagnostic)\n }\n\n // Format and lint are the same pass over the output directory, differing only in the tool\n // table and the hooks they announce themselves with, so run them from one descriptor list.\n const toolPasses = [\n {\n value: resolvedConfig.output.format,\n code: Diagnostics.code.formatFailed,\n tool: {\n label: 'formatter',\n map: formatters,\n detect: () => detectTool(FORMATTER_PREFERENCE),\n successPrefix: 'Formatting',\n noToolMessage: `No formatter found (${FORMATTER_PREFERENCE.join(', ')}). Skipping formatting.`,\n },\n onStart: () => hooks.callHook('kubb:format:start'),\n onEnd: () => hooks.callHook('kubb:format:end'),\n },\n {\n value: resolvedConfig.output.lint,\n code: Diagnostics.code.lintFailed,\n tool: {\n label: 'linter',\n map: linters,\n detect: () => detectTool(LINTER_PREFERENCE),\n successPrefix: 'Linting',\n noToolMessage: `No linter found (${LINTER_PREFERENCE.join(', ')}). Skipping linting.`,\n },\n onStart: () => hooks.callHook('kubb:lint:start'),\n onEnd: () => hooks.callHook('kubb:lint:end'),\n },\n ]\n\n for (const pass of toolPasses) {\n if (!pass.value) continue\n const error = await runToolPass({\n toolValue: pass.value,\n tool: pass.tool,\n onStart: pass.onStart,\n onEnd: pass.onEnd,\n outputPath,\n logLevel,\n hooks,\n })\n if (error) await reportOutputFailure(pass.code, pass.tool.label, error)\n }\n\n if (resolvedConfig.output.postGenerate?.length) {\n await hooks.callHook('kubb:hooks:start')\n const hookResults = await runPostGenerate({ commands: resolvedConfig.output.postGenerate, hooks })\n for (const hookResult of hookResults) {\n if (hookResult.success) continue\n await reportOutputFailure(Diagnostics.code.postGenerateFailed, 'Post-generate command', hookResult.error ?? new Error('Post-generate command failed'))\n }\n await hooks.callHook('kubb:hooks:end')\n }\n\n return outputDiagnostics\n }\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate({ processOutput })\n\n if (dryRun) {\n await hooks.callHook('kubb:info', { message: 'Dry run: no files were written', info: `${result.files.length} file(s) would be generated` })\n }\n\n const telemetryPlugins = Array.from(kubb.driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> }))\n await sendTelemetry(\n buildTelemetryEvent({\n command: 'generate',\n kubbVersion: version,\n plugins: telemetryPlugins,\n hrStart,\n filesCreated: result.files.length,\n status: result.success ? 'success' : 'failed',\n }),\n )\n\n return result.success\n}\n\n/**\n * Builds a coded diagnostic for an output-phase failure (formatter, linter, or `done` hook).\n */\nfunction outputDiagnostic(code: ProblemDiagnostic['code'], label: string, caughtError: unknown): ProblemDiagnostic {\n const error = toError(caughtError)\n return {\n code,\n severity: 'error',\n message: `${label} failed: ${error.message}`,\n help: 'Check that the tool is installed and that the command and its config are correct.',\n location: { kind: 'config' },\n cause: error,\n }\n}\n\ntype GenerateCommandOptions = {\n input?: string\n configPath?: string\n logLevel: string\n watch: boolean\n reporters?: Array<ReporterName>\n dryRun?: boolean\n}\n\nasync function checkForUpdate(hooks: Hookable<KubbHooks>): Promise<void> {\n try {\n const res = await fetch(KUBB_NPM_PACKAGE_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) })\n const data = (await res.json()) as { version: string }\n if (data.version && isNewerVersion(version, data.version)) {\n await Diagnostics.emit(hooks, Diagnostics.update({ currentVersion: version, latestVersion: data.version }))\n }\n } catch {\n // Ignore network errors\n }\n}\n\n/**\n * Runs the full Kubb generation lifecycle for the given CLI options.\n * Loads configs, sets up the reporters (CLI `--reporter` picks which of `config.reporters` to trigger),\n * checks for a newer version, and calls `generate` for each config entry.\n */\nexport async function run({ input, configPath, logLevel: logLevelKey, watch, reporters: cliReporters, dryRun }: GenerateCommandOptions): Promise<void> {\n const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info\n const hooks = new Hookable<KubbHooks>()\n\n // CLI `--reporter` selects which reporters to trigger by name, defaulting to `cli`. The config\n // always carries the available reporters (defineConfig registers the built-ins).\n const requestedNames: Array<ReporterName> = cliReporters?.length ? cliReporters : ['cli']\n\n // The `json` reporter owns stdout, so the command writes nothing of its own around it.\n const quiet = logLevel <= logLevelMap.silent || requestedNames.includes('json')\n\n if (!quiet) {\n logBanner(version)\n logIntro({ title: 'Configuration' })\n }\n\n // Load the config first so `config.reporters` can pick the reporters. A failure here has no\n // reporter installed yet, so fall back to the default `cli` reporter to surface it.\n const configSpinner = createSpinner()\n let configs: Array<Config>\n let resolvedConfigPath: string\n try {\n if (!quiet) configSpinner.start('Loading config')\n\n const loaded = await getConfigs({\n configPath,\n input,\n watch,\n logLevel: logLevelKey as CLIOptions['logLevel'],\n })\n configs = loaded.configs\n resolvedConfigPath = loaded.configPath\n\n if (!quiet) configSpinner.stop(`Loaded ${styleText('dim', path.relative(process.cwd(), resolvedConfigPath))}`)\n } catch (error) {\n if (!quiet) configSpinner.error('Config failed loading')\n\n await setupReporters(hooks, { logLevel, reporters: [cliReporter] })\n await hooks.callHook('kubb:error', { error: toError(error) })\n\n if (!quiet) logOutro(styleText('red', '✗ Configuration failed'))\n process.exit(1)\n }\n\n const reporters = selectReporters(configs[0]?.reporters ?? [], requestedNames)\n await setupReporters(hooks, { logLevel, reporters })\n\n await hooks.callHook('kubb:lifecycle:start', { version })\n\n // Inside the bootstrap group, so an update notice reads as part of the setup rather than as part\n // of the first config's generation.\n await checkForUpdate(hooks)\n\n if (!quiet) logOutro(`${pluralize(configs.length, 'config')} ready`)\n\n try {\n let anyFailed = false\n for (const config of configs) {\n const effectiveInput = input ?? config.input\n const inputKind = typeof effectiveInput === 'string' ? getInputKind(effectiveInput) : undefined\n const watchPath = inputKind === 'file' || inputKind === 'url' ? (effectiveInput as string) : undefined\n if (watchPath && watch) {\n const watchedPaths = [watchPath]\n // Don't removeAll() between builds, that would also drop logger and lifecycle\n // listeners. Plugin listeners are already disposed by safeBuild's dispose()\n // in its finally block, so re-running generate() on the same hooks emitter is safe.\n const build = async (paths: Array<string>) => {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n logStep(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))\n if (succeeded) {\n logSpacer()\n logTip()\n }\n }\n\n // For a URL input, capture the document before the build: it becomes the watcher's\n // change-detection baseline, so an edit landing before the first poll still rebuilds.\n // When the server is down the baseline stays undefined and the watcher rebuilds on its\n // first successful poll, so recovery with an unchanged document still generates output.\n const initialBody = inputKind === 'url' ? await fetchUrlBody(watchPath) : undefined\n\n // The watchers ignore their startup state (chokidar's initial events, the baseline\n // above), so run the first build here. A failing first build keeps watching, since\n // the user can fix the input and save.\n try {\n await build(watchedPaths)\n } catch (buildError) {\n await hooks.callHook('kubb:error', { error: toError(buildError) })\n }\n\n if (inputKind === 'url') {\n startUrlWatcher(watchPath, build, { log: { info: logInfo, error: logError }, initialBody })\n } else {\n await startWatcher(watchedPaths, build, { info: logInfo, error: logError })\n }\n } else {\n try {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n if (!succeeded) anyFailed = true\n } catch (configError) {\n await hooks.callHook('kubb:error', { error: toError(configError) })\n anyFailed = true\n }\n }\n }\n\n await hooks.callHook('kubb:lifecycle:end')\n\n // Watch mode prints a tip after each successful build. Regular generate commands need to\n // print one explicitly after the lifecycle group has closed so it stays outside the group.\n if (!quiet && !watch && !anyFailed) {\n logTip()\n }\n\n if (anyFailed) {\n process.exit(1)\n }\n } catch (error) {\n await hooks.callHook('kubb:error', { error: toError(error) })\n process.exit(1)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-C0lN0_dx.cjs","names":["styleText","existsSync","logLevelMap","randomUUID","runHook","toError","process","memoryStorage","Diagnostics","formatters","detectTool","FORMATTER_PREFERENCE","linters","LINTER_PREFERENCE","runPostGenerate","createKubb","sendTelemetry","buildTelemetryEvent","version","KUBB_NPM_PACKAGE_URL","UPDATE_CHECK_TIMEOUT_MS","isNewerVersion","Hookable","createSpinner","getConfigs","path","setupReporters","cliReporter","selectReporters","pluralize","getInputKind","fetchUrlBody","logInfo","logError","startWatcher"],"sources":["../src/runners/generate/run.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport {\n Hookable,\n type CLIOptions,\n cliReporter,\n type Config,\n createKubb,\n type Diagnostic,\n Diagnostics,\n getInputKind,\n type KubbHooks,\n logLevel as logLevelMap,\n memoryStorage,\n type ProblemDiagnostic,\n type ReporterName,\n} from '@kubb/core'\nimport { version } from '../../../package.json'\nimport { KUBB_NPM_PACKAGE_URL, UPDATE_CHECK_TIMEOUT_MS } from '../../constants.ts'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport setupReporters, { pluralize, selectReporters } from '../../loggers/utils.ts'\nimport { createSpinner, logBanner, logError, logInfo, logIntro, logOutro, logSpacer, logStep, logTip } from '../../loggers/output.ts'\nimport { fetchUrlBody, getConfigs, isNewerVersion, runHook, runPostGenerate, startUrlWatcher, startWatcher } from './utils.ts'\nimport { FORMATTER_PREFERENCE, LINTER_PREFERENCE } from '@internals/utils'\nimport { detectTool, formatters, linters } from '../../tools.ts'\n\ntype GenerateProps = {\n input?: string\n config: Config\n hooks: Hookable<KubbHooks>\n logLevel: number\n /**\n * When `true`, generates in memory instead of writing to disk, and skips formatting, linting,\n * and post-generate commands.\n */\n dryRun?: boolean\n}\n\ntype ToolMap = typeof formatters | typeof linters\n\n/**\n * Static description of one output tool: its command table, the label and messages the pass logs,\n * and how to auto-detect it. Format and lint differ only in these values.\n */\ntype Tool = {\n label: string\n map: ToolMap\n detect: () => Promise<string | null>\n successPrefix: string\n noToolMessage: string\n}\n\ntype RunToolPassOptions = {\n toolValue: string\n tool: Tool\n outputPath: string\n logLevel: number\n hooks: Hookable<KubbHooks>\n onStart: () => Promise<void> | void\n onEnd: () => Promise<void> | void\n}\n\n/**\n * Runs one formatter or linter pass over the output directory. Returns the failure instead of\n * throwing, so the caller can turn it into a coded diagnostic. Failures never render here:\n * the caller emits them through `Diagnostics.emit`, like every other diagnostic.\n */\nasync function runToolPass({ toolValue, tool, outputPath, logLevel, hooks, onStart, onEnd }: RunToolPassOptions): Promise<Error | null> {\n await onStart()\n\n let resolvedTool = toolValue\n if (resolvedTool === 'auto') {\n const detected = await tool.detect()\n if (!detected) {\n await hooks.callHook('kubb:warn', { message: tool.noToolMessage })\n } else {\n resolvedTool = detected\n await hooks.callHook('kubb:info', { message: `Auto-detected ${tool.label}: ${styleText('dim', resolvedTool)}` })\n }\n }\n\n let toolError: Error | null = null\n\n // Nothing to lint or format when the output dir was never written. Skip so the tool\n // (e.g. oxlint with --no-ignore) doesn't fail with \"No files found to lint\".\n if (resolvedTool && resolvedTool !== 'auto' && resolvedTool in tool.map && existsSync(outputPath)) {\n const toolConfig = tool.map[resolvedTool as keyof ToolMap]\n\n const successMessage = [\n `${tool.successPrefix} with ${styleText('dim', resolvedTool)}`,\n logLevel >= logLevelMap.info ? `on ${styleText('dim', outputPath)}` : undefined,\n 'successfully',\n ]\n .filter(Boolean)\n .join(' ')\n\n try {\n const hookId = randomUUID()\n const hookArgs = toolConfig.args(outputPath)\n const commandWithArgs = [toolConfig.command, ...hookArgs].join(' ')\n\n await hooks.callHook('kubb:hook:start', { id: hookId, command: toolConfig.command, args: hookArgs })\n\n const result = await runHook({ id: hookId, command: toolConfig.command, args: hookArgs, commandWithArgs, hooks })\n\n if (result.success) {\n await hooks.callHook('kubb:success', { message: successMessage })\n } else {\n toolError = result.error ?? new Error(toolConfig.errorMessage)\n }\n } catch (caughtError) {\n toolError = toError(caughtError)\n }\n }\n\n await onEnd()\n\n return toolError\n}\n\nasync function generate(options: GenerateProps): Promise<boolean> {\n const { input, hooks, logLevel, dryRun = false } = options\n\n const hrStart = process.hrtime()\n\n const config: Config = {\n ...options.config,\n input: input ?? options.config.input,\n // Dry-run never touches disk, regardless of the config's own storage driver.\n storage: dryRun ? memoryStorage() : options.config.storage,\n // Also keeps core's `hasOutputPasses` false, so dry-run skips the output manifest write too.\n output: dryRun ? { ...options.config.output, format: false, lint: false, postGenerate: [] } : options.config.output,\n }\n\n // The formatter, linter, and post-generate commands run after a successful build. Collect their\n // failures as coded diagnostics so they reach the summary, the json report, and the exit code.\n const processOutput = async ({ config: resolvedConfig, outputPath }: { config: Config; outputPath: string }): Promise<Array<Diagnostic>> => {\n if (dryRun) return []\n\n const outputDiagnostics: Array<Diagnostic> = []\n const reportOutputFailure = async (code: ProblemDiagnostic['code'], label: string, error: Error) => {\n const diagnostic = outputDiagnostic(code, label, error)\n outputDiagnostics.push(diagnostic)\n await Diagnostics.emit(hooks, diagnostic)\n }\n\n // Format and lint are the same pass over the output directory, differing only in the tool\n // table and the hooks they announce themselves with, so run them from one descriptor list.\n const toolPasses = [\n {\n value: resolvedConfig.output.format,\n code: Diagnostics.code.formatFailed,\n tool: {\n label: 'formatter',\n map: formatters,\n detect: () => detectTool(FORMATTER_PREFERENCE),\n successPrefix: 'Formatting',\n noToolMessage: `No formatter found (${FORMATTER_PREFERENCE.join(', ')}). Skipping formatting.`,\n },\n onStart: () => hooks.callHook('kubb:format:start'),\n onEnd: () => hooks.callHook('kubb:format:end'),\n },\n {\n value: resolvedConfig.output.lint,\n code: Diagnostics.code.lintFailed,\n tool: {\n label: 'linter',\n map: linters,\n detect: () => detectTool(LINTER_PREFERENCE),\n successPrefix: 'Linting',\n noToolMessage: `No linter found (${LINTER_PREFERENCE.join(', ')}). Skipping linting.`,\n },\n onStart: () => hooks.callHook('kubb:lint:start'),\n onEnd: () => hooks.callHook('kubb:lint:end'),\n },\n ]\n\n for (const pass of toolPasses) {\n if (!pass.value) continue\n const error = await runToolPass({\n toolValue: pass.value,\n tool: pass.tool,\n onStart: pass.onStart,\n onEnd: pass.onEnd,\n outputPath,\n logLevel,\n hooks,\n })\n if (error) await reportOutputFailure(pass.code, pass.tool.label, error)\n }\n\n if (resolvedConfig.output.postGenerate?.length) {\n await hooks.callHook('kubb:hooks:start')\n const hookResults = await runPostGenerate({ commands: resolvedConfig.output.postGenerate, hooks })\n for (const hookResult of hookResults) {\n if (hookResult.success) continue\n await reportOutputFailure(Diagnostics.code.postGenerateFailed, 'Post-generate command', hookResult.error ?? new Error('Post-generate command failed'))\n }\n await hooks.callHook('kubb:hooks:end')\n }\n\n return outputDiagnostics\n }\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate({ processOutput })\n\n if (dryRun) {\n await hooks.callHook('kubb:info', { message: 'Dry run: no files were written', info: `${result.files.length} file(s) would be generated` })\n }\n\n const telemetryPlugins = Array.from(kubb.driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> }))\n await sendTelemetry(\n buildTelemetryEvent({\n command: 'generate',\n kubbVersion: version,\n plugins: telemetryPlugins,\n hrStart,\n filesCreated: result.files.length,\n status: result.success ? 'success' : 'failed',\n }),\n )\n\n return result.success\n}\n\n/**\n * Builds a coded diagnostic for an output-phase failure (formatter, linter, or `done` hook).\n */\nfunction outputDiagnostic(code: ProblemDiagnostic['code'], label: string, caughtError: unknown): ProblemDiagnostic {\n const error = toError(caughtError)\n return {\n code,\n severity: 'error',\n message: `${label} failed: ${error.message}`,\n help: 'Check that the tool is installed and that the command and its config are correct.',\n location: { kind: 'config' },\n cause: error,\n }\n}\n\ntype GenerateCommandOptions = {\n input?: string\n configPath?: string\n logLevel: string\n watch: boolean\n reporters?: Array<ReporterName>\n dryRun?: boolean\n}\n\nasync function checkForUpdate(hooks: Hookable<KubbHooks>): Promise<void> {\n try {\n const res = await fetch(KUBB_NPM_PACKAGE_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) })\n const data = (await res.json()) as { version: string }\n if (data.version && isNewerVersion(version, data.version)) {\n await Diagnostics.emit(hooks, Diagnostics.update({ currentVersion: version, latestVersion: data.version }))\n }\n } catch {\n // Ignore network errors\n }\n}\n\n/**\n * Runs the full Kubb generation lifecycle for the given CLI options.\n * Loads configs, sets up the reporters (CLI `--reporter` picks which of `config.reporters` to trigger),\n * checks for a newer version, and calls `generate` for each config entry.\n */\nexport async function run({ input, configPath, logLevel: logLevelKey, watch, reporters: cliReporters, dryRun }: GenerateCommandOptions): Promise<void> {\n const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info\n const hooks = new Hookable<KubbHooks>()\n\n // CLI `--reporter` selects which reporters to trigger by name, defaulting to `cli`. The config\n // always carries the available reporters (defineConfig registers the built-ins).\n const requestedNames: Array<ReporterName> = cliReporters?.length ? cliReporters : ['cli']\n\n // The `json` reporter owns stdout, so the command writes nothing of its own around it.\n const quiet = logLevel <= logLevelMap.silent || requestedNames.includes('json')\n\n if (!quiet) {\n logBanner(version)\n logIntro({ title: 'Configuration' })\n }\n\n // Load the config first so `config.reporters` can pick the reporters. A failure here has no\n // reporter installed yet, so fall back to the default `cli` reporter to surface it.\n const configSpinner = createSpinner()\n let configs: Array<Config>\n let resolvedConfigPath: string\n try {\n if (!quiet) configSpinner.start('Loading config')\n\n const loaded = await getConfigs({\n configPath,\n input,\n watch,\n logLevel: logLevelKey as CLIOptions['logLevel'],\n })\n configs = loaded.configs\n resolvedConfigPath = loaded.configPath\n\n if (!quiet) configSpinner.stop(`Loaded ${styleText('dim', path.relative(process.cwd(), resolvedConfigPath))}`)\n } catch (error) {\n if (!quiet) configSpinner.error('Config failed loading')\n\n await setupReporters(hooks, { logLevel, reporters: [cliReporter] })\n await hooks.callHook('kubb:error', { error: toError(error) })\n\n if (!quiet) logOutro(styleText('red', '✗ Configuration failed'))\n process.exit(1)\n }\n\n const reporters = selectReporters(configs[0]?.reporters ?? [], requestedNames)\n await setupReporters(hooks, { logLevel, reporters })\n\n await hooks.callHook('kubb:lifecycle:start', { version })\n\n // Inside the bootstrap group, so an update notice reads as part of the setup rather than as part\n // of the first config's generation.\n await checkForUpdate(hooks)\n\n if (!quiet) logOutro(`${pluralize(configs.length, 'config')} ready`)\n\n try {\n let anyFailed = false\n for (const config of configs) {\n const effectiveInput = input ?? config.input\n const inputKind = typeof effectiveInput === 'string' ? getInputKind(effectiveInput) : undefined\n const watchPath = inputKind === 'file' || inputKind === 'url' ? (effectiveInput as string) : undefined\n if (watchPath && watch) {\n const watchedPaths = [watchPath]\n // Don't removeAll() between builds, that would also drop logger and lifecycle\n // listeners. Plugin listeners are already disposed by safeBuild's dispose()\n // in its finally block, so re-running generate() on the same hooks emitter is safe.\n const build = async (paths: Array<string>) => {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n logStep(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))\n if (succeeded) {\n logSpacer()\n logTip()\n }\n }\n\n // For a URL input, capture the document before the build: it becomes the watcher's\n // change-detection baseline, so an edit landing before the first poll still rebuilds.\n // When the server is down the baseline stays undefined and the watcher rebuilds on its\n // first successful poll, so recovery with an unchanged document still generates output.\n const initialBody = inputKind === 'url' ? await fetchUrlBody(watchPath) : undefined\n\n // The watchers ignore their startup state (chokidar's initial events, the baseline\n // above), so run the first build here. A failing first build keeps watching, since\n // the user can fix the input and save.\n try {\n await build(watchedPaths)\n } catch (buildError) {\n await hooks.callHook('kubb:error', { error: toError(buildError) })\n }\n\n if (inputKind === 'url') {\n startUrlWatcher(watchPath, build, { log: { info: logInfo, error: logError }, initialBody })\n } else {\n await startWatcher(watchedPaths, build, { info: logInfo, error: logError })\n }\n } else {\n try {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n if (!succeeded) anyFailed = true\n } catch (configError) {\n await hooks.callHook('kubb:error', { error: toError(configError) })\n anyFailed = true\n }\n }\n }\n\n await hooks.callHook('kubb:lifecycle:end')\n\n // Watch mode prints a tip after each successful build. Regular generate commands need to\n // print one explicitly after the lifecycle group has closed so it stays outside the group.\n if (!quiet && !watch && !anyFailed) {\n logTip()\n }\n\n if (anyFailed) {\n process.exit(1)\n }\n } catch (error) {\n await hooks.callHook('kubb:error', { error: toError(error) })\n process.exit(1)\n }\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { t as toError } from "./errors-BQJzaUwP.js";
3
3
  import { i as KUBB_NPM_PACKAGE_URL, o as UPDATE_CHECK_TIMEOUT_MS, r as sendTelemetry, t as buildTelemetryEvent } from "./Telemetry-cHHOzBW8.js";
4
4
  import { _ as linters, a as runPostGenerate, d as selectReporters, f as setupReporters, g as formatters, h as detectTool, i as runHook, m as LINTER_PREFERENCE, n as getConfigs, o as startUrlWatcher, p as FORMATTER_PREFERENCE, r as isNewerVersion, s as startWatcher, t as fetchUrlBody, u as pluralize } from "./utils-BYY3_cyq.js";
5
5
  import { a as logInfo, c as logSpacer, i as logError, l as logStep, n as logBanner, o as logIntro, s as logOutro, t as createSpinner, u as logTip } from "./output-Dkoh9Ig6.js";
6
- import { t as version } from "./package-CW_5mbRf.js";
6
+ import { t as version } from "./package-CWi7augV.js";
7
7
  import { styleText } from "node:util";
8
8
  import { randomUUID } from "node:crypto";
9
9
  import process from "node:process";
@@ -286,4 +286,4 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
286
286
  //#endregion
287
287
  export { run };
288
288
 
289
- //# sourceMappingURL=run-CfpFOmPH.js.map
289
+ //# sourceMappingURL=run-C1NcWnFi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-CfpFOmPH.js","names":["logLevel","logLevelMap"],"sources":["../src/runners/generate/run.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport {\n Hookable,\n type CLIOptions,\n cliReporter,\n type Config,\n createKubb,\n type Diagnostic,\n Diagnostics,\n getInputKind,\n type KubbHooks,\n logLevel as logLevelMap,\n memoryStorage,\n type ProblemDiagnostic,\n type ReporterName,\n} from '@kubb/core'\nimport { version } from '../../../package.json'\nimport { KUBB_NPM_PACKAGE_URL, UPDATE_CHECK_TIMEOUT_MS } from '../../constants.ts'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport setupReporters, { pluralize, selectReporters } from '../../loggers/utils.ts'\nimport { createSpinner, logBanner, logError, logInfo, logIntro, logOutro, logSpacer, logStep, logTip } from '../../loggers/output.ts'\nimport { fetchUrlBody, getConfigs, isNewerVersion, runHook, runPostGenerate, startUrlWatcher, startWatcher } from './utils.ts'\nimport { FORMATTER_PREFERENCE, LINTER_PREFERENCE } from '@internals/utils'\nimport { detectTool, formatters, linters } from '../../tools.ts'\n\ntype GenerateProps = {\n input?: string\n config: Config\n hooks: Hookable<KubbHooks>\n logLevel: number\n /**\n * When `true`, generates in memory instead of writing to disk, and skips formatting, linting,\n * and post-generate commands.\n */\n dryRun?: boolean\n}\n\ntype ToolMap = typeof formatters | typeof linters\n\n/**\n * Static description of one output tool: its command table, the label and messages the pass logs,\n * and how to auto-detect it. Format and lint differ only in these values.\n */\ntype Tool = {\n label: string\n map: ToolMap\n detect: () => Promise<string | null>\n successPrefix: string\n noToolMessage: string\n}\n\ntype RunToolPassOptions = {\n toolValue: string\n tool: Tool\n outputPath: string\n logLevel: number\n hooks: Hookable<KubbHooks>\n onStart: () => Promise<void> | void\n onEnd: () => Promise<void> | void\n}\n\n/**\n * Runs one formatter or linter pass over the output directory. Returns the failure instead of\n * throwing, so the caller can turn it into a coded diagnostic. Failures never render here:\n * the caller emits them through `Diagnostics.emit`, like every other diagnostic.\n */\nasync function runToolPass({ toolValue, tool, outputPath, logLevel, hooks, onStart, onEnd }: RunToolPassOptions): Promise<Error | null> {\n await onStart()\n\n let resolvedTool = toolValue\n if (resolvedTool === 'auto') {\n const detected = await tool.detect()\n if (!detected) {\n await hooks.callHook('kubb:warn', { message: tool.noToolMessage })\n } else {\n resolvedTool = detected\n await hooks.callHook('kubb:info', { message: `Auto-detected ${tool.label}: ${styleText('dim', resolvedTool)}` })\n }\n }\n\n let toolError: Error | null = null\n\n // Nothing to lint or format when the output dir was never written. Skip so the tool\n // (e.g. oxlint with --no-ignore) doesn't fail with \"No files found to lint\".\n if (resolvedTool && resolvedTool !== 'auto' && resolvedTool in tool.map && existsSync(outputPath)) {\n const toolConfig = tool.map[resolvedTool as keyof ToolMap]\n\n const successMessage = [\n `${tool.successPrefix} with ${styleText('dim', resolvedTool)}`,\n logLevel >= logLevelMap.info ? `on ${styleText('dim', outputPath)}` : undefined,\n 'successfully',\n ]\n .filter(Boolean)\n .join(' ')\n\n try {\n const hookId = randomUUID()\n const hookArgs = toolConfig.args(outputPath)\n const commandWithArgs = [toolConfig.command, ...hookArgs].join(' ')\n\n await hooks.callHook('kubb:hook:start', { id: hookId, command: toolConfig.command, args: hookArgs })\n\n const result = await runHook({ id: hookId, command: toolConfig.command, args: hookArgs, commandWithArgs, hooks })\n\n if (result.success) {\n await hooks.callHook('kubb:success', { message: successMessage })\n } else {\n toolError = result.error ?? new Error(toolConfig.errorMessage)\n }\n } catch (caughtError) {\n toolError = toError(caughtError)\n }\n }\n\n await onEnd()\n\n return toolError\n}\n\nasync function generate(options: GenerateProps): Promise<boolean> {\n const { input, hooks, logLevel, dryRun = false } = options\n\n const hrStart = process.hrtime()\n\n const config: Config = {\n ...options.config,\n input: input ?? options.config.input,\n // Dry-run never touches disk, regardless of the config's own storage driver.\n storage: dryRun ? memoryStorage() : options.config.storage,\n // Also keeps core's `hasOutputPasses` false, so dry-run skips the output manifest write too.\n output: dryRun ? { ...options.config.output, format: false, lint: false, postGenerate: [] } : options.config.output,\n }\n\n // The formatter, linter, and post-generate commands run after a successful build. Collect their\n // failures as coded diagnostics so they reach the summary, the json report, and the exit code.\n const processOutput = async ({ config: resolvedConfig, outputPath }: { config: Config; outputPath: string }): Promise<Array<Diagnostic>> => {\n if (dryRun) return []\n\n const outputDiagnostics: Array<Diagnostic> = []\n const reportOutputFailure = async (code: ProblemDiagnostic['code'], label: string, error: Error) => {\n const diagnostic = outputDiagnostic(code, label, error)\n outputDiagnostics.push(diagnostic)\n await Diagnostics.emit(hooks, diagnostic)\n }\n\n // Format and lint are the same pass over the output directory, differing only in the tool\n // table and the hooks they announce themselves with, so run them from one descriptor list.\n const toolPasses = [\n {\n value: resolvedConfig.output.format,\n code: Diagnostics.code.formatFailed,\n tool: {\n label: 'formatter',\n map: formatters,\n detect: () => detectTool(FORMATTER_PREFERENCE),\n successPrefix: 'Formatting',\n noToolMessage: `No formatter found (${FORMATTER_PREFERENCE.join(', ')}). Skipping formatting.`,\n },\n onStart: () => hooks.callHook('kubb:format:start'),\n onEnd: () => hooks.callHook('kubb:format:end'),\n },\n {\n value: resolvedConfig.output.lint,\n code: Diagnostics.code.lintFailed,\n tool: {\n label: 'linter',\n map: linters,\n detect: () => detectTool(LINTER_PREFERENCE),\n successPrefix: 'Linting',\n noToolMessage: `No linter found (${LINTER_PREFERENCE.join(', ')}). Skipping linting.`,\n },\n onStart: () => hooks.callHook('kubb:lint:start'),\n onEnd: () => hooks.callHook('kubb:lint:end'),\n },\n ]\n\n for (const pass of toolPasses) {\n if (!pass.value) continue\n const error = await runToolPass({\n toolValue: pass.value,\n tool: pass.tool,\n onStart: pass.onStart,\n onEnd: pass.onEnd,\n outputPath,\n logLevel,\n hooks,\n })\n if (error) await reportOutputFailure(pass.code, pass.tool.label, error)\n }\n\n if (resolvedConfig.output.postGenerate?.length) {\n await hooks.callHook('kubb:hooks:start')\n const hookResults = await runPostGenerate({ commands: resolvedConfig.output.postGenerate, hooks })\n for (const hookResult of hookResults) {\n if (hookResult.success) continue\n await reportOutputFailure(Diagnostics.code.postGenerateFailed, 'Post-generate command', hookResult.error ?? new Error('Post-generate command failed'))\n }\n await hooks.callHook('kubb:hooks:end')\n }\n\n return outputDiagnostics\n }\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate({ processOutput })\n\n if (dryRun) {\n await hooks.callHook('kubb:info', { message: 'Dry run: no files were written', info: `${result.files.length} file(s) would be generated` })\n }\n\n const telemetryPlugins = Array.from(kubb.driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> }))\n await sendTelemetry(\n buildTelemetryEvent({\n command: 'generate',\n kubbVersion: version,\n plugins: telemetryPlugins,\n hrStart,\n filesCreated: result.files.length,\n status: result.success ? 'success' : 'failed',\n }),\n )\n\n return result.success\n}\n\n/**\n * Builds a coded diagnostic for an output-phase failure (formatter, linter, or `done` hook).\n */\nfunction outputDiagnostic(code: ProblemDiagnostic['code'], label: string, caughtError: unknown): ProblemDiagnostic {\n const error = toError(caughtError)\n return {\n code,\n severity: 'error',\n message: `${label} failed: ${error.message}`,\n help: 'Check that the tool is installed and that the command and its config are correct.',\n location: { kind: 'config' },\n cause: error,\n }\n}\n\ntype GenerateCommandOptions = {\n input?: string\n configPath?: string\n logLevel: string\n watch: boolean\n reporters?: Array<ReporterName>\n dryRun?: boolean\n}\n\nasync function checkForUpdate(hooks: Hookable<KubbHooks>): Promise<void> {\n try {\n const res = await fetch(KUBB_NPM_PACKAGE_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) })\n const data = (await res.json()) as { version: string }\n if (data.version && isNewerVersion(version, data.version)) {\n await Diagnostics.emit(hooks, Diagnostics.update({ currentVersion: version, latestVersion: data.version }))\n }\n } catch {\n // Ignore network errors\n }\n}\n\n/**\n * Runs the full Kubb generation lifecycle for the given CLI options.\n * Loads configs, sets up the reporters (CLI `--reporter` picks which of `config.reporters` to trigger),\n * checks for a newer version, and calls `generate` for each config entry.\n */\nexport async function run({ input, configPath, logLevel: logLevelKey, watch, reporters: cliReporters, dryRun }: GenerateCommandOptions): Promise<void> {\n const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info\n const hooks = new Hookable<KubbHooks>()\n\n // CLI `--reporter` selects which reporters to trigger by name, defaulting to `cli`. The config\n // always carries the available reporters (defineConfig registers the built-ins).\n const requestedNames: Array<ReporterName> = cliReporters?.length ? cliReporters : ['cli']\n\n // The `json` reporter owns stdout, so the command writes nothing of its own around it.\n const quiet = logLevel <= logLevelMap.silent || requestedNames.includes('json')\n\n if (!quiet) {\n logBanner(version)\n logIntro({ title: 'Configuration' })\n }\n\n // Load the config first so `config.reporters` can pick the reporters. A failure here has no\n // reporter installed yet, so fall back to the default `cli` reporter to surface it.\n const configSpinner = createSpinner()\n let configs: Array<Config>\n let resolvedConfigPath: string\n try {\n if (!quiet) configSpinner.start('Loading config')\n\n const loaded = await getConfigs({\n configPath,\n input,\n watch,\n logLevel: logLevelKey as CLIOptions['logLevel'],\n })\n configs = loaded.configs\n resolvedConfigPath = loaded.configPath\n\n if (!quiet) configSpinner.stop(`Loaded ${styleText('dim', path.relative(process.cwd(), resolvedConfigPath))}`)\n } catch (error) {\n if (!quiet) configSpinner.error('Config failed loading')\n\n await setupReporters(hooks, { logLevel, reporters: [cliReporter] })\n await hooks.callHook('kubb:error', { error: toError(error) })\n\n if (!quiet) logOutro(styleText('red', '✗ Configuration failed'))\n process.exit(1)\n }\n\n const reporters = selectReporters(configs[0]?.reporters ?? [], requestedNames)\n await setupReporters(hooks, { logLevel, reporters })\n\n await hooks.callHook('kubb:lifecycle:start', { version })\n\n // Inside the bootstrap group, so an update notice reads as part of the setup rather than as part\n // of the first config's generation.\n await checkForUpdate(hooks)\n\n if (!quiet) logOutro(`${pluralize(configs.length, 'config')} ready`)\n\n try {\n let anyFailed = false\n for (const config of configs) {\n const effectiveInput = input ?? config.input\n const inputKind = typeof effectiveInput === 'string' ? getInputKind(effectiveInput) : undefined\n const watchPath = inputKind === 'file' || inputKind === 'url' ? (effectiveInput as string) : undefined\n if (watchPath && watch) {\n const watchedPaths = [watchPath]\n // Don't removeAll() between builds, that would also drop logger and lifecycle\n // listeners. Plugin listeners are already disposed by safeBuild's dispose()\n // in its finally block, so re-running generate() on the same hooks emitter is safe.\n const build = async (paths: Array<string>) => {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n logStep(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))\n if (succeeded) {\n logSpacer()\n logTip()\n }\n }\n\n // For a URL input, capture the document before the build: it becomes the watcher's\n // change-detection baseline, so an edit landing before the first poll still rebuilds.\n // When the server is down the baseline stays undefined and the watcher rebuilds on its\n // first successful poll, so recovery with an unchanged document still generates output.\n const initialBody = inputKind === 'url' ? await fetchUrlBody(watchPath) : undefined\n\n // The watchers ignore their startup state (chokidar's initial events, the baseline\n // above), so run the first build here. A failing first build keeps watching, since\n // the user can fix the input and save.\n try {\n await build(watchedPaths)\n } catch (buildError) {\n await hooks.callHook('kubb:error', { error: toError(buildError) })\n }\n\n if (inputKind === 'url') {\n startUrlWatcher(watchPath, build, { log: { info: logInfo, error: logError }, initialBody })\n } else {\n await startWatcher(watchedPaths, build, { info: logInfo, error: logError })\n }\n } else {\n try {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n if (!succeeded) anyFailed = true\n } catch (configError) {\n await hooks.callHook('kubb:error', { error: toError(configError) })\n anyFailed = true\n }\n }\n }\n\n await hooks.callHook('kubb:lifecycle:end')\n\n // Watch mode prints a tip after each successful build. Regular generate commands need to\n // print one explicitly after the lifecycle group has closed so it stays outside the group.\n if (!quiet && !watch && !anyFailed) {\n logTip()\n }\n\n if (anyFailed) {\n process.exit(1)\n }\n } catch (error) {\n await hooks.callHook('kubb:error', { error: toError(error) })\n process.exit(1)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-C1NcWnFi.js","names":["logLevel","logLevelMap"],"sources":["../src/runners/generate/run.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport {\n Hookable,\n type CLIOptions,\n cliReporter,\n type Config,\n createKubb,\n type Diagnostic,\n Diagnostics,\n getInputKind,\n type KubbHooks,\n logLevel as logLevelMap,\n memoryStorage,\n type ProblemDiagnostic,\n type ReporterName,\n} from '@kubb/core'\nimport { version } from '../../../package.json'\nimport { KUBB_NPM_PACKAGE_URL, UPDATE_CHECK_TIMEOUT_MS } from '../../constants.ts'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport setupReporters, { pluralize, selectReporters } from '../../loggers/utils.ts'\nimport { createSpinner, logBanner, logError, logInfo, logIntro, logOutro, logSpacer, logStep, logTip } from '../../loggers/output.ts'\nimport { fetchUrlBody, getConfigs, isNewerVersion, runHook, runPostGenerate, startUrlWatcher, startWatcher } from './utils.ts'\nimport { FORMATTER_PREFERENCE, LINTER_PREFERENCE } from '@internals/utils'\nimport { detectTool, formatters, linters } from '../../tools.ts'\n\ntype GenerateProps = {\n input?: string\n config: Config\n hooks: Hookable<KubbHooks>\n logLevel: number\n /**\n * When `true`, generates in memory instead of writing to disk, and skips formatting, linting,\n * and post-generate commands.\n */\n dryRun?: boolean\n}\n\ntype ToolMap = typeof formatters | typeof linters\n\n/**\n * Static description of one output tool: its command table, the label and messages the pass logs,\n * and how to auto-detect it. Format and lint differ only in these values.\n */\ntype Tool = {\n label: string\n map: ToolMap\n detect: () => Promise<string | null>\n successPrefix: string\n noToolMessage: string\n}\n\ntype RunToolPassOptions = {\n toolValue: string\n tool: Tool\n outputPath: string\n logLevel: number\n hooks: Hookable<KubbHooks>\n onStart: () => Promise<void> | void\n onEnd: () => Promise<void> | void\n}\n\n/**\n * Runs one formatter or linter pass over the output directory. Returns the failure instead of\n * throwing, so the caller can turn it into a coded diagnostic. Failures never render here:\n * the caller emits them through `Diagnostics.emit`, like every other diagnostic.\n */\nasync function runToolPass({ toolValue, tool, outputPath, logLevel, hooks, onStart, onEnd }: RunToolPassOptions): Promise<Error | null> {\n await onStart()\n\n let resolvedTool = toolValue\n if (resolvedTool === 'auto') {\n const detected = await tool.detect()\n if (!detected) {\n await hooks.callHook('kubb:warn', { message: tool.noToolMessage })\n } else {\n resolvedTool = detected\n await hooks.callHook('kubb:info', { message: `Auto-detected ${tool.label}: ${styleText('dim', resolvedTool)}` })\n }\n }\n\n let toolError: Error | null = null\n\n // Nothing to lint or format when the output dir was never written. Skip so the tool\n // (e.g. oxlint with --no-ignore) doesn't fail with \"No files found to lint\".\n if (resolvedTool && resolvedTool !== 'auto' && resolvedTool in tool.map && existsSync(outputPath)) {\n const toolConfig = tool.map[resolvedTool as keyof ToolMap]\n\n const successMessage = [\n `${tool.successPrefix} with ${styleText('dim', resolvedTool)}`,\n logLevel >= logLevelMap.info ? `on ${styleText('dim', outputPath)}` : undefined,\n 'successfully',\n ]\n .filter(Boolean)\n .join(' ')\n\n try {\n const hookId = randomUUID()\n const hookArgs = toolConfig.args(outputPath)\n const commandWithArgs = [toolConfig.command, ...hookArgs].join(' ')\n\n await hooks.callHook('kubb:hook:start', { id: hookId, command: toolConfig.command, args: hookArgs })\n\n const result = await runHook({ id: hookId, command: toolConfig.command, args: hookArgs, commandWithArgs, hooks })\n\n if (result.success) {\n await hooks.callHook('kubb:success', { message: successMessage })\n } else {\n toolError = result.error ?? new Error(toolConfig.errorMessage)\n }\n } catch (caughtError) {\n toolError = toError(caughtError)\n }\n }\n\n await onEnd()\n\n return toolError\n}\n\nasync function generate(options: GenerateProps): Promise<boolean> {\n const { input, hooks, logLevel, dryRun = false } = options\n\n const hrStart = process.hrtime()\n\n const config: Config = {\n ...options.config,\n input: input ?? options.config.input,\n // Dry-run never touches disk, regardless of the config's own storage driver.\n storage: dryRun ? memoryStorage() : options.config.storage,\n // Also keeps core's `hasOutputPasses` false, so dry-run skips the output manifest write too.\n output: dryRun ? { ...options.config.output, format: false, lint: false, postGenerate: [] } : options.config.output,\n }\n\n // The formatter, linter, and post-generate commands run after a successful build. Collect their\n // failures as coded diagnostics so they reach the summary, the json report, and the exit code.\n const processOutput = async ({ config: resolvedConfig, outputPath }: { config: Config; outputPath: string }): Promise<Array<Diagnostic>> => {\n if (dryRun) return []\n\n const outputDiagnostics: Array<Diagnostic> = []\n const reportOutputFailure = async (code: ProblemDiagnostic['code'], label: string, error: Error) => {\n const diagnostic = outputDiagnostic(code, label, error)\n outputDiagnostics.push(diagnostic)\n await Diagnostics.emit(hooks, diagnostic)\n }\n\n // Format and lint are the same pass over the output directory, differing only in the tool\n // table and the hooks they announce themselves with, so run them from one descriptor list.\n const toolPasses = [\n {\n value: resolvedConfig.output.format,\n code: Diagnostics.code.formatFailed,\n tool: {\n label: 'formatter',\n map: formatters,\n detect: () => detectTool(FORMATTER_PREFERENCE),\n successPrefix: 'Formatting',\n noToolMessage: `No formatter found (${FORMATTER_PREFERENCE.join(', ')}). Skipping formatting.`,\n },\n onStart: () => hooks.callHook('kubb:format:start'),\n onEnd: () => hooks.callHook('kubb:format:end'),\n },\n {\n value: resolvedConfig.output.lint,\n code: Diagnostics.code.lintFailed,\n tool: {\n label: 'linter',\n map: linters,\n detect: () => detectTool(LINTER_PREFERENCE),\n successPrefix: 'Linting',\n noToolMessage: `No linter found (${LINTER_PREFERENCE.join(', ')}). Skipping linting.`,\n },\n onStart: () => hooks.callHook('kubb:lint:start'),\n onEnd: () => hooks.callHook('kubb:lint:end'),\n },\n ]\n\n for (const pass of toolPasses) {\n if (!pass.value) continue\n const error = await runToolPass({\n toolValue: pass.value,\n tool: pass.tool,\n onStart: pass.onStart,\n onEnd: pass.onEnd,\n outputPath,\n logLevel,\n hooks,\n })\n if (error) await reportOutputFailure(pass.code, pass.tool.label, error)\n }\n\n if (resolvedConfig.output.postGenerate?.length) {\n await hooks.callHook('kubb:hooks:start')\n const hookResults = await runPostGenerate({ commands: resolvedConfig.output.postGenerate, hooks })\n for (const hookResult of hookResults) {\n if (hookResult.success) continue\n await reportOutputFailure(Diagnostics.code.postGenerateFailed, 'Post-generate command', hookResult.error ?? new Error('Post-generate command failed'))\n }\n await hooks.callHook('kubb:hooks:end')\n }\n\n return outputDiagnostics\n }\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate({ processOutput })\n\n if (dryRun) {\n await hooks.callHook('kubb:info', { message: 'Dry run: no files were written', info: `${result.files.length} file(s) would be generated` })\n }\n\n const telemetryPlugins = Array.from(kubb.driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> }))\n await sendTelemetry(\n buildTelemetryEvent({\n command: 'generate',\n kubbVersion: version,\n plugins: telemetryPlugins,\n hrStart,\n filesCreated: result.files.length,\n status: result.success ? 'success' : 'failed',\n }),\n )\n\n return result.success\n}\n\n/**\n * Builds a coded diagnostic for an output-phase failure (formatter, linter, or `done` hook).\n */\nfunction outputDiagnostic(code: ProblemDiagnostic['code'], label: string, caughtError: unknown): ProblemDiagnostic {\n const error = toError(caughtError)\n return {\n code,\n severity: 'error',\n message: `${label} failed: ${error.message}`,\n help: 'Check that the tool is installed and that the command and its config are correct.',\n location: { kind: 'config' },\n cause: error,\n }\n}\n\ntype GenerateCommandOptions = {\n input?: string\n configPath?: string\n logLevel: string\n watch: boolean\n reporters?: Array<ReporterName>\n dryRun?: boolean\n}\n\nasync function checkForUpdate(hooks: Hookable<KubbHooks>): Promise<void> {\n try {\n const res = await fetch(KUBB_NPM_PACKAGE_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) })\n const data = (await res.json()) as { version: string }\n if (data.version && isNewerVersion(version, data.version)) {\n await Diagnostics.emit(hooks, Diagnostics.update({ currentVersion: version, latestVersion: data.version }))\n }\n } catch {\n // Ignore network errors\n }\n}\n\n/**\n * Runs the full Kubb generation lifecycle for the given CLI options.\n * Loads configs, sets up the reporters (CLI `--reporter` picks which of `config.reporters` to trigger),\n * checks for a newer version, and calls `generate` for each config entry.\n */\nexport async function run({ input, configPath, logLevel: logLevelKey, watch, reporters: cliReporters, dryRun }: GenerateCommandOptions): Promise<void> {\n const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info\n const hooks = new Hookable<KubbHooks>()\n\n // CLI `--reporter` selects which reporters to trigger by name, defaulting to `cli`. The config\n // always carries the available reporters (defineConfig registers the built-ins).\n const requestedNames: Array<ReporterName> = cliReporters?.length ? cliReporters : ['cli']\n\n // The `json` reporter owns stdout, so the command writes nothing of its own around it.\n const quiet = logLevel <= logLevelMap.silent || requestedNames.includes('json')\n\n if (!quiet) {\n logBanner(version)\n logIntro({ title: 'Configuration' })\n }\n\n // Load the config first so `config.reporters` can pick the reporters. A failure here has no\n // reporter installed yet, so fall back to the default `cli` reporter to surface it.\n const configSpinner = createSpinner()\n let configs: Array<Config>\n let resolvedConfigPath: string\n try {\n if (!quiet) configSpinner.start('Loading config')\n\n const loaded = await getConfigs({\n configPath,\n input,\n watch,\n logLevel: logLevelKey as CLIOptions['logLevel'],\n })\n configs = loaded.configs\n resolvedConfigPath = loaded.configPath\n\n if (!quiet) configSpinner.stop(`Loaded ${styleText('dim', path.relative(process.cwd(), resolvedConfigPath))}`)\n } catch (error) {\n if (!quiet) configSpinner.error('Config failed loading')\n\n await setupReporters(hooks, { logLevel, reporters: [cliReporter] })\n await hooks.callHook('kubb:error', { error: toError(error) })\n\n if (!quiet) logOutro(styleText('red', '✗ Configuration failed'))\n process.exit(1)\n }\n\n const reporters = selectReporters(configs[0]?.reporters ?? [], requestedNames)\n await setupReporters(hooks, { logLevel, reporters })\n\n await hooks.callHook('kubb:lifecycle:start', { version })\n\n // Inside the bootstrap group, so an update notice reads as part of the setup rather than as part\n // of the first config's generation.\n await checkForUpdate(hooks)\n\n if (!quiet) logOutro(`${pluralize(configs.length, 'config')} ready`)\n\n try {\n let anyFailed = false\n for (const config of configs) {\n const effectiveInput = input ?? config.input\n const inputKind = typeof effectiveInput === 'string' ? getInputKind(effectiveInput) : undefined\n const watchPath = inputKind === 'file' || inputKind === 'url' ? (effectiveInput as string) : undefined\n if (watchPath && watch) {\n const watchedPaths = [watchPath]\n // Don't removeAll() between builds, that would also drop logger and lifecycle\n // listeners. Plugin listeners are already disposed by safeBuild's dispose()\n // in its finally block, so re-running generate() on the same hooks emitter is safe.\n const build = async (paths: Array<string>) => {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n logStep(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))\n if (succeeded) {\n logSpacer()\n logTip()\n }\n }\n\n // For a URL input, capture the document before the build: it becomes the watcher's\n // change-detection baseline, so an edit landing before the first poll still rebuilds.\n // When the server is down the baseline stays undefined and the watcher rebuilds on its\n // first successful poll, so recovery with an unchanged document still generates output.\n const initialBody = inputKind === 'url' ? await fetchUrlBody(watchPath) : undefined\n\n // The watchers ignore their startup state (chokidar's initial events, the baseline\n // above), so run the first build here. A failing first build keeps watching, since\n // the user can fix the input and save.\n try {\n await build(watchedPaths)\n } catch (buildError) {\n await hooks.callHook('kubb:error', { error: toError(buildError) })\n }\n\n if (inputKind === 'url') {\n startUrlWatcher(watchPath, build, { log: { info: logInfo, error: logError }, initialBody })\n } else {\n await startWatcher(watchedPaths, build, { info: logInfo, error: logError })\n }\n } else {\n try {\n const succeeded = await generate({ input, config, logLevel, hooks, dryRun })\n if (!succeeded) anyFailed = true\n } catch (configError) {\n await hooks.callHook('kubb:error', { error: toError(configError) })\n anyFailed = true\n }\n }\n }\n\n await hooks.callHook('kubb:lifecycle:end')\n\n // Watch mode prints a tip after each successful build. Regular generate commands need to\n // print one explicitly after the lifecycle group has closed so it stays outside the group.\n if (!quiet && !watch && !anyFailed) {\n logTip()\n }\n\n if (anyFailed) {\n process.exit(1)\n }\n } catch (error) {\n await hooks.callHook('kubb:error', { error: toError(error) })\n process.exit(1)\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-qbf5tadS.cjs");
2
2
  const require_errors = require("./errors-C-wEou02.cjs");
3
3
  const require_Telemetry = require("./Telemetry-B3kc9gFh.cjs");
4
- const require_package = require("./package-BgCML9qr.cjs");
4
+ const require_package = require("./package-DTQG_XnR.cjs");
5
5
  let node_util = require("node:util");
6
6
  let node_process = require("node:process");
7
7
  node_process = require_rolldown_runtime.__toESM(node_process, 1);
@@ -38,4 +38,4 @@ const runner = async () => {
38
38
  //#endregion
39
39
  exports.runner = runner;
40
40
 
41
- //# sourceMappingURL=run-bakr1FvL.cjs.map
41
+ //# sourceMappingURL=run-C3hTDMfs.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-bakr1FvL.cjs","names":["process","sendTelemetry","buildTelemetryEvent","styleText","toError"],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type * as McpModule from '@kubb/mcp'\nimport type { CommandRunner } from 'gunshi'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { version } from '../../../package.json'\nimport type { definition } from '../../commands/mcp.ts'\n\ntype McpOptions = {\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\n/**\n * Starts the `@kubb/mcp` server over stdio and reports the outcome to telemetry.\n */\nexport async function run({ version }: McpOptions): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'mcp', kubbVersion: version, hrStart, status }))\n\n try {\n console.log(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer()\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n\n/**\n * Loaded on demand by `index.ts`, so `@kubb/mcp` stays out of the process for every other command.\n */\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async () => {\n await run({ version })\n}\n"],"mappings":";;;;;;;;;;;AAmBA,eAAsB,IAAI,EAAE,WAAsC;CAChE,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAE9C,MAAM,UAAUA,aAAAA,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiCC,kBAAAA,cAAcC,kBAAAA,oBAAoB;EAAE,SAAS;EAAO,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAE7I,IAAI;EACF,QAAQ,KAAA,GAAIC,UAAAA,UAAAA,CAAU,QAAQ,0BAA0B,CAAC;EACzD,QAAQ,MAAA,GAAKA,UAAAA,UAAAA,CAAU,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe;EACrB,MAAM,OAAO,SAAS;CACxB,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,QAAQ,MAAMC,eAAAA,QAAQ,KAAK,CAAC,CAAC,OAAO;EACpC,aAAA,QAAA,WAAmB;CACrB;AACF;;;;AAKA,MAAa,SAA0E,YAAY;CACjG,MAAM,IAAI,EAAE,SAAA,gBAAA,QAAQ,CAAC;AACvB"}
1
+ {"version":3,"file":"run-C3hTDMfs.cjs","names":["process","sendTelemetry","buildTelemetryEvent","styleText","toError"],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type * as McpModule from '@kubb/mcp'\nimport type { CommandRunner } from 'gunshi'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { version } from '../../../package.json'\nimport type { definition } from '../../commands/mcp.ts'\n\ntype McpOptions = {\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\n/**\n * Starts the `@kubb/mcp` server over stdio and reports the outcome to telemetry.\n */\nexport async function run({ version }: McpOptions): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'mcp', kubbVersion: version, hrStart, status }))\n\n try {\n console.log(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer()\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n\n/**\n * Loaded on demand by `index.ts`, so `@kubb/mcp` stays out of the process for every other command.\n */\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async () => {\n await run({ version })\n}\n"],"mappings":";;;;;;;;;;;AAmBA,eAAsB,IAAI,EAAE,WAAsC;CAChE,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAE9C,MAAM,UAAUA,aAAAA,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiCC,kBAAAA,cAAcC,kBAAAA,oBAAoB;EAAE,SAAS;EAAO,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAE7I,IAAI;EACF,QAAQ,KAAA,GAAIC,UAAAA,UAAAA,CAAU,QAAQ,0BAA0B,CAAC;EACzD,QAAQ,MAAA,GAAKA,UAAAA,UAAAA,CAAU,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe;EACrB,MAAM,OAAO,SAAS;CACxB,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,QAAQ,MAAMC,eAAAA,QAAQ,KAAK,CAAC,CAAC,OAAO;EACpC,aAAA,QAAA,WAAmB;CACrB;AACF;;;;AAKA,MAAa,SAA0E,YAAY;CACjG,MAAM,IAAI,EAAE,SAAA,gBAAA,QAAQ,CAAC;AACvB"}
@@ -1,7 +1,7 @@
1
1
  import "./rolldown-runtime-CRm0XQPb.js";
2
2
  import { t as toError } from "./errors-BQJzaUwP.js";
3
3
  import { r as sendTelemetry, t as buildTelemetryEvent } from "./Telemetry-cHHOzBW8.js";
4
- import { t as version } from "./package-CW_5mbRf.js";
4
+ import { t as version } from "./package-CWi7augV.js";
5
5
  import { styleText } from "node:util";
6
6
  import process from "node:process";
7
7
  //#region src/runners/validate/run.ts
@@ -53,4 +53,4 @@ const runner = async ({ values }) => {
53
53
  //#endregion
54
54
  export { runner };
55
55
 
56
- //# sourceMappingURL=run-ev2SVzT3.js.map
56
+ //# sourceMappingURL=run-Cb78U4HC.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-ev2SVzT3.js","names":[],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type { CommandRunner } from 'gunshi'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { version } from '../../../package.json'\nimport type { definition } from '../../commands/validate.ts'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\n/**\n * Validates an OpenAPI/Swagger file at `input` using `@kubb/adapter-oas`.\n * Exits the process with code 1 on validation failure or missing dependency.\n */\nexport async function run({ input, version }: ValidateOptions): Promise<void> {\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'validate', kubbVersion: version, hrStart, status }))\n\n try {\n const { adapterOas } = await import('@kubb/adapter-oas')\n\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n\n await adapter.validate(input, { throwOnError: true })\n await report('success')\n\n console.log('✅ Validation success')\n } catch (error) {\n await report('failed')\n if (error instanceof Error && /@kubb\\/adapter-oas/.test(error.message)) {\n console.error(styleText('red', 'The @kubb/adapter-oas package is not installed.'))\n console.error('')\n console.error('Install it with:')\n console.error(styleText('cyan', ' npm install @kubb/adapter-oas'))\n console.error(styleText('cyan', ' # or'))\n console.error(styleText('cyan', ' pnpm install @kubb/adapter-oas'))\n console.error('')\n }\n console.error('❌ Validation failed')\n console.error(toError(error).message)\n\n process.exit(1)\n }\n}\n\n/**\n * Loaded on demand by `index.ts`, so `@kubb/adapter-oas` stays out of the process for every other\n * command.\n */\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async ({ values }) => {\n await run({ input: values.input, version })\n}\n"],"mappings":";;;;;;;;;;;AAuBA,eAAsB,IAAI,EAAE,OAAO,WAA2C;CAC5E,MAAM,UAAU,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiC,cAAc,oBAAoB;EAAE,SAAS;EAAY,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAElJ,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,OAAO;EAEpC,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,SAAS;EAEtB,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,IAAI,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,OAAO,GAAG;GACtE,QAAQ,MAAM,UAAU,OAAO,iDAAiD,CAAC;GACjF,QAAQ,MAAM,EAAE;GAChB,QAAQ,MAAM,kBAAkB;GAChC,QAAQ,MAAM,UAAU,QAAQ,iCAAiC,CAAC;GAClE,QAAQ,MAAM,UAAU,QAAQ,QAAQ,CAAC;GACzC,QAAQ,MAAM,UAAU,QAAQ,kCAAkC,CAAC;GACnE,QAAQ,MAAM,EAAE;EAClB;EACA,QAAQ,MAAM,qBAAqB;EACnC,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EAEpC,QAAQ,KAAK,CAAC;CAChB;AACF;;;;;AAMA,MAAa,SAA0E,OAAO,EAAE,aAAa;CAC3G,MAAM,IAAI;EAAE,OAAO,OAAO;EAAO;CAAQ,CAAC;AAC5C"}
1
+ {"version":3,"file":"run-Cb78U4HC.js","names":[],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type { CommandRunner } from 'gunshi'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { version } from '../../../package.json'\nimport type { definition } from '../../commands/validate.ts'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\n/**\n * Validates an OpenAPI/Swagger file at `input` using `@kubb/adapter-oas`.\n * Exits the process with code 1 on validation failure or missing dependency.\n */\nexport async function run({ input, version }: ValidateOptions): Promise<void> {\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'validate', kubbVersion: version, hrStart, status }))\n\n try {\n const { adapterOas } = await import('@kubb/adapter-oas')\n\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n\n await adapter.validate(input, { throwOnError: true })\n await report('success')\n\n console.log('✅ Validation success')\n } catch (error) {\n await report('failed')\n if (error instanceof Error && /@kubb\\/adapter-oas/.test(error.message)) {\n console.error(styleText('red', 'The @kubb/adapter-oas package is not installed.'))\n console.error('')\n console.error('Install it with:')\n console.error(styleText('cyan', ' npm install @kubb/adapter-oas'))\n console.error(styleText('cyan', ' # or'))\n console.error(styleText('cyan', ' pnpm install @kubb/adapter-oas'))\n console.error('')\n }\n console.error('❌ Validation failed')\n console.error(toError(error).message)\n\n process.exit(1)\n }\n}\n\n/**\n * Loaded on demand by `index.ts`, so `@kubb/adapter-oas` stays out of the process for every other\n * command.\n */\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async ({ values }) => {\n await run({ input: values.input, version })\n}\n"],"mappings":";;;;;;;;;;;AAuBA,eAAsB,IAAI,EAAE,OAAO,WAA2C;CAC5E,MAAM,UAAU,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiC,cAAc,oBAAoB;EAAE,SAAS;EAAY,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAElJ,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,OAAO;EAEpC,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,SAAS;EAEtB,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,IAAI,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,OAAO,GAAG;GACtE,QAAQ,MAAM,UAAU,OAAO,iDAAiD,CAAC;GACjF,QAAQ,MAAM,EAAE;GAChB,QAAQ,MAAM,kBAAkB;GAChC,QAAQ,MAAM,UAAU,QAAQ,iCAAiC,CAAC;GAClE,QAAQ,MAAM,UAAU,QAAQ,QAAQ,CAAC;GACzC,QAAQ,MAAM,UAAU,QAAQ,kCAAkC,CAAC;GACnE,QAAQ,MAAM,EAAE;EAClB;EACA,QAAQ,MAAM,qBAAqB;EACnC,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EAEpC,QAAQ,KAAK,CAAC;CAChB;AACF;;;;;AAMA,MAAa,SAA0E,OAAO,EAAE,aAAa;CAC3G,MAAM,IAAI;EAAE,OAAO,OAAO;EAAO;CAAQ,CAAC;AAC5C"}
@@ -1,7 +1,7 @@
1
1
  import "./rolldown-runtime-CRm0XQPb.js";
2
2
  import { t as toError } from "./errors-BQJzaUwP.js";
3
3
  import { r as sendTelemetry, t as buildTelemetryEvent } from "./Telemetry-cHHOzBW8.js";
4
- import { t as version } from "./package-CW_5mbRf.js";
4
+ import { t as version } from "./package-CWi7augV.js";
5
5
  import { styleText } from "node:util";
6
6
  import process from "node:process";
7
7
  //#region src/runners/mcp/run.ts
@@ -37,4 +37,4 @@ const runner = async () => {
37
37
  //#endregion
38
38
  export { runner };
39
39
 
40
- //# sourceMappingURL=run-LMAru4TP.js.map
40
+ //# sourceMappingURL=run-D9nqSLXW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-LMAru4TP.js","names":[],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type * as McpModule from '@kubb/mcp'\nimport type { CommandRunner } from 'gunshi'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { version } from '../../../package.json'\nimport type { definition } from '../../commands/mcp.ts'\n\ntype McpOptions = {\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\n/**\n * Starts the `@kubb/mcp` server over stdio and reports the outcome to telemetry.\n */\nexport async function run({ version }: McpOptions): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'mcp', kubbVersion: version, hrStart, status }))\n\n try {\n console.log(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer()\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n\n/**\n * Loaded on demand by `index.ts`, so `@kubb/mcp` stays out of the process for every other command.\n */\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async () => {\n await run({ version })\n}\n"],"mappings":";;;;;;;;;;AAmBA,eAAsB,IAAI,EAAE,WAAsC;CAChE,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAE9C,MAAM,UAAU,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiC,cAAc,oBAAoB;EAAE,SAAS;EAAO,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAE7I,IAAI;EACF,QAAQ,IAAI,UAAU,QAAQ,0BAA0B,CAAC;EACzD,QAAQ,KAAK,UAAU,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe;EACrB,MAAM,OAAO,SAAS;CACxB,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EACpC,QAAQ,WAAW;CACrB;AACF;;;;AAKA,MAAa,SAA0E,YAAY;CACjG,MAAM,IAAI,EAAE,QAAQ,CAAC;AACvB"}
1
+ {"version":3,"file":"run-D9nqSLXW.js","names":[],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type * as McpModule from '@kubb/mcp'\nimport type { CommandRunner } from 'gunshi'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { version } from '../../../package.json'\nimport type { definition } from '../../commands/mcp.ts'\n\ntype McpOptions = {\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\n/**\n * Starts the `@kubb/mcp` server over stdio and reports the outcome to telemetry.\n */\nexport async function run({ version }: McpOptions): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'mcp', kubbVersion: version, hrStart, status }))\n\n try {\n console.log(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer()\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n\n/**\n * Loaded on demand by `index.ts`, so `@kubb/mcp` stays out of the process for every other command.\n */\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async () => {\n await run({ version })\n}\n"],"mappings":";;;;;;;;;;AAmBA,eAAsB,IAAI,EAAE,WAAsC;CAChE,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAE9C,MAAM,UAAU,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiC,cAAc,oBAAoB;EAAE,SAAS;EAAO,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAE7I,IAAI;EACF,QAAQ,IAAI,UAAU,QAAQ,0BAA0B,CAAC;EACzD,QAAQ,KAAK,UAAU,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe;EACrB,MAAM,OAAO,SAAS;CACxB,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EACpC,QAAQ,WAAW;CACrB;AACF;;;;AAKA,MAAa,SAA0E,YAAY;CACjG,MAAM,IAAI,EAAE,QAAQ,CAAC;AACvB"}
@@ -4,7 +4,7 @@ import { n as isCIEnvironment } from "./agent-w0Hlq4mG.js";
4
4
  import { r as sendTelemetry, t as buildTelemetryEvent, u as runtime } from "./Telemetry-cHHOzBW8.js";
5
5
  import { f as setupReporters, l as plainLogger, n as getConfigs } from "./utils-BYY3_cyq.js";
6
6
  import { f as canUseTTY, o as logIntro, r as logBlock, s as logOutro, t as createSpinner, u as logTip } from "./output-Dkoh9Ig6.js";
7
- import { t as version } from "./package-CW_5mbRf.js";
7
+ import { t as version } from "./package-CWi7augV.js";
8
8
  import { t as KUBB_CONFIG_FILENAME } from "./constants-DHRspBTo.js";
9
9
  import { styleText } from "node:util";
10
10
  import { hash } from "node:crypto";
@@ -327,7 +327,7 @@ async function connect(options, context = {}) {
327
327
  let reauthenticated = false;
328
328
  try {
329
329
  if (!context.prepared) {
330
- const { getWorkerStatus } = await import("./background-iLjxcrns.js");
330
+ const { getWorkerStatus } = await import("./background-CZuTWCy0.js");
331
331
  if ((await getWorkerStatus()).running) throw new Error("This project is running in the background. Run `kubb studio stop` first.");
332
332
  }
333
333
  const prepared = context.prepared ?? await prepareConnection(options, signal);
@@ -445,4 +445,4 @@ async function run(options, action, { block = false, json = false } = {}) {
445
445
  //#endregion
446
446
  export { prepareConnection as a, clearCredentials as c, read as d, login as i, getProjectKubbHome as l, createStudioOptions as n, run as o, loadConfigs as r, status as s, connect as t, exists as u };
447
447
 
448
- //# sourceMappingURL=run-DI26m-2b.js.map
448
+ //# sourceMappingURL=run-DBMVTeYc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-DI26m-2b.js","names":["logLevelMap"],"sources":["../../../internals/utils/src/openInBrowser.ts","../../../internals/utils/src/fs.ts","../src/runners/studio/credentials.ts","../src/runners/studio/run.ts"],"sourcesContent":["import { execFile } from 'node:child_process'\nimport process from 'node:process'\nimport { isCIEnvironment } from './isCIEnvironment.ts'\n\n/**\n * Opens a URL or local file in the default browser, unless running in CI.\n */\nexport function openInBrowser(target: string): void {\n if (isCIEnvironment()) return\n\n if (process.platform === 'win32') {\n execFile('cmd', ['/c', 'start', '', target], () => {})\n } else {\n execFile(process.platform === 'darwin' ? 'open' : 'xdg-open', [target], () => {})\n }\n}\n","import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return content\n }\n\n // Creating the directory up front costs a syscall per file, and every file after the first in a\n // directory pays it for nothing. Write first and only fall back when the directory is missing,\n // which also stays correct when something removed it mid-run.\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n\n if (options.sanity) {\n const savedData = await readFile(resolved, { encoding: 'utf-8' })\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Recursively removes `path`. Silently succeeds when `path` does not exist.\n *\n * @example\n * ```ts\n * await clean('./dist')\n * ```\n */\nexport async function clean(path: string): Promise<void> {\n return rm(path, { recursive: true, force: true })\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { hash } from 'node:crypto'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { clean, read } from '@internals/utils'\n\n/**\n * Root for everything the CLI persists between runs: the paired credential, the machine secret,\n * the last Studio config, and the live-session registry. `KUBB_HOME` relocates all of it.\n */\nfunction getKubbHome(): string {\n return process.env.KUBB_HOME ?? path.join(homedir(), '.kubb')\n}\n\n/**\n * Root for the credential and machine identity of the current project.\n *\n * Studio agents are project connections, so two projects on one machine must not share the same\n * persisted token or machine secret.\n */\nexport function getProjectKubbHome(project = process.cwd()): string {\n const projectId = hash('sha256', project)\n return path.join(getKubbHome(), 'projects', projectId)\n}\n\nconst CREDENTIALS_FILENAME = 'credentials.json'\n\n/**\n * Absolute path of the stored credential, so callers can name it in output without rebuilding it.\n */\nexport function getCredentialsPath(): string {\n return path.join(getProjectKubbHome(), CREDENTIALS_FILENAME)\n}\n\nexport type Credentials = {\n /**\n * The Studio instance this machine paired with. A different `--url` means re-pairing.\n */\n studioUrl: string\n /**\n * Bearer token for this machine. Never logged, never printed.\n */\n token: string\n agentId: string\n agentSlug: string\n /**\n * Permissions the user has already granted, keyed by absolute project path, so the CLI asks\n * once per project instead of on every run.\n */\n projects?: Record<string, { allowRead?: boolean; allowWrite?: boolean; allowConfigEdit?: boolean; allowExec?: boolean }>\n}\n\n/**\n * Reads the stored credential, or null when this machine has not paired yet or the file is\n * unreadable or corrupt. A bad file is treated as \"not paired\" so `kubb studio login` can\n * overwrite it rather than the CLI dying on it.\n */\nexport async function readCredentials(): Promise<Credentials | null> {\n const raw = await read(getCredentialsPath()).catch(() => null)\n if (!raw) {\n return null\n }\n\n try {\n return JSON.parse(raw) as Credentials\n } catch {\n return null\n }\n}\n\n/**\n * Writes the credential with owner-only permissions. The file holds a bearer token, so the mode\n * is set at creation time rather than left to the process umask or fixed up afterward, which\n * would leave the token briefly readable under the umask's default mode.\n */\nexport async function writeCredentials(credentials: Credentials): Promise<void> {\n const file = getCredentialsPath()\n\n await mkdir(path.dirname(file), { recursive: true, mode: 0o700 })\n await writeFile(file, JSON.stringify(credentials, null, 2), { mode: 0o600 })\n}\n\n/**\n * Forgets the stored credential. Succeeds when there was nothing to forget.\n */\nexport async function clearCredentials(): Promise<void> {\n await clean(getCredentialsPath())\n}\n","import { hostname } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as prompts from '@clack/prompts'\nimport { KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { isCIEnvironment, openInBrowser, toError } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\nimport { cliReporter, logLevel as logLevelMap } from '@kubb/core'\nimport {\n createFileStorage,\n type ClientOptions,\n defaultStudioUrl,\n type InvalidAgentTokenError,\n pairAgent,\n PairingCanceledError,\n runConnection,\n setStorage,\n} from '@kubb/studio'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { plainLogger } from '../../loggers/plainLogger.ts'\nimport setupReporters from '../../loggers/utils.ts'\nimport { createSpinner, logBlock, logIntro, logOutro, logTip } from '../../loggers/output.ts'\nimport { canUseTTY } from '../../utils/env.ts'\nimport { getConfigs } from '../generate/utils.ts'\nimport { clearCredentials, type Credentials, getCredentialsPath, getProjectKubbHome, readCredentials, writeCredentials } from './credentials.ts'\nimport { version } from '../../../package.json'\n\ntype Permission = 'allowRead' | 'allowWrite' | 'allowConfigEdit' | 'allowExec'\n\nexport type StudioOptions = {\n /**\n * Current `@kubb/cli` version, reported to Studio and used for the telemetry payload.\n */\n version: string\n configPath?: string\n /**\n * Base URL of the Studio instance, for a self-hosted deployment. Resolved before it reaches here,\n * since stored credentials are bound to it.\n */\n studioUrl: string\n /**\n * What Studio may do in this project. Each flag grants outright; the rest are asked once per\n * project through {@link resolvePermissions}.\n */\n permission: Record<Permission, boolean>\n /**\n * Whether to open the approval page in a browser during pairing.\n */\n autoOpen: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\nexport type SnapshotOptions = StudioOptions & {\n /**\n * Organization CI API key. Falls back to `KUBB_TOKEN`.\n */\n token?: string\n /**\n * Stable identity for the CI agent. Falls back to CI auto-detection.\n */\n id?: string\n /** Identity of another CI agent to also compare with. Falls back to CI auto-detection. */\n baseId?: string\n /**\n * Package name for the generated tarball. Falls back to the nearest package.json.\n */\n name?: string\n /**\n * Package version for the generated tarball. Falls back to the nearest package.json.\n */\n packageVersion?: string\n /**\n * Seconds to wait for the job to finish.\n */\n timeout?: number\n /**\n * Print the result as one JSON object instead of a summary.\n */\n json?: boolean\n}\n\ntype StudioValues = {\n config?: string\n url?: string\n allowRead: boolean\n allowWrite: boolean\n allowConfigEdit: boolean\n allowExec: boolean\n open?: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\nexport function createStudioOptions(values: StudioValues): StudioOptions {\n return {\n version,\n configPath: values.config,\n studioUrl: values.url ?? defaultStudioUrl,\n permission: {\n allowRead: values.allowRead,\n allowWrite: values.allowWrite,\n allowConfigEdit: values.allowConfigEdit,\n allowExec: values.allowExec,\n },\n autoOpen: values.open ?? true,\n logLevel: values.logLevel,\n }\n}\n\ntype LoginOptions = {\n /**\n * Aborting this cancels an in-flight pairing request or poll and rejects with\n * {@link PairingCanceledError}. Wired to `kubb studio`'s shutdown signal, so Ctrl+C during\n * pairing cancels it instead of leaving the poll running.\n */\n signal?: AbortSignal\n /**\n * Credentials from before this login. When the fresh pairing resolves to the same agent on the\n * same Studio, its saved project permissions carry forward instead of being asked again.\n * Left out for an explicitly requested `kubb studio login`, which always starts clean.\n */\n previousCredentials?: Credentials | null\n}\n\n/**\n * Pairs this machine with Studio and stores the resulting token.\n *\n * The CLI holds a code and the browser approves it, rather than the user copying a token out of\n * the UI. The token comes back over the CLI's own HTTPS POST, so it never lands in a URL, a\n * server log, or a `Referer` header.\n */\nexport async function login({ studioUrl, autoOpen }: StudioOptions, { signal, previousCredentials }: LoginOptions = {}): Promise<Credentials> {\n const spinner = createSpinner()\n // The spinner only starts once a code is shown.\n let waiting = false\n\n try {\n const { token, agent } = await pairAgent({\n studioUrl,\n type: 'cli',\n name: path.basename(process.cwd()),\n hostname: hostname(),\n signal,\n onCode: (session) => {\n console.log(`\\nOpen ${styleText('cyan', session.verification_uri)} and approve the code ${styleText('bold', session.user_code)}`)\n\n if (autoOpen) {\n openInBrowser(session.verification_uri_complete)\n }\n\n spinner.start('Waiting for approval')\n waiting = true\n },\n onRetry: (error) => spinner.message(`Could not reach Kubb Studio, retrying: ${error.message}`),\n })\n spinner.stop(`Paired as ${agent.name}`)\n\n const keepsIdentity = previousCredentials?.studioUrl === studioUrl && previousCredentials.agentId === agent.id\n const credentials: Credentials = {\n studioUrl,\n token,\n agentId: agent.id,\n agentSlug: agent.slug,\n ...(keepsIdentity && previousCredentials?.projects ? { projects: previousCredentials.projects } : {}),\n }\n await writeCredentials(credentials)\n\n console.log(`Credentials stored in ${getCredentialsPath()}`)\n\n return credentials\n } catch (error) {\n if (waiting) {\n spinner.stop(error instanceof PairingCanceledError ? 'Pairing canceled' : 'Pairing failed')\n }\n throw error\n }\n}\n\n/**\n * What each permission is asked as, in the order the questions appear.\n */\nconst PERMISSIONS: ReadonlyArray<{\n key: Permission\n /**\n * Short label for status output and the connect summary.\n */\n label: string\n question: (project: string, configPath: string) => string\n}> = [\n {\n key: 'allowRead',\n label: 'read generated files',\n question: () => 'Let Kubb Studio read the files a generation produced?',\n },\n { key: 'allowWrite', label: 'write generated files', question: (project) => `Let Kubb Studio write generated files into ${project}?` },\n {\n key: 'allowConfigEdit',\n label: 'edit kubb.config.ts',\n question: (_project, configPath) => `Let Kubb Studio change plugin options in ${configPath}?`,\n },\n {\n key: 'allowExec',\n label: 'run formatter, linter, postGenerate',\n question: () => 'Let Kubb Studio run the formatter, the linter, and output.postGenerate?',\n },\n]\n\n/**\n * One row per permission, for the connect banner and `kubb studio status`. A list rather than a\n * joined line: four labels this long read as one run-on sentence side by side.\n */\nexport function formatPermissionRows(granted: Record<Permission, boolean>): Array<string> {\n return PERMISSIONS.map(({ key, label }) => `${granted[key] ? styleText('green', '✔') : styleText('red', '✘')} ${label}`)\n}\n\n/**\n * Resolves Studio permissions for the current project.\n * Flags win, saved answers are reused, and new answers are stored unless `persist` is false.\n */\nexport async function resolvePermissions(\n options: StudioOptions,\n credentials: Credentials,\n configPath: string = KUBB_CONFIG_FILENAME,\n /**\n * Stores new answers in `~/.kubb/credentials.json`.\n * Pass `false` for `KUBB_AGENT_TOKEN` sessions so a temporary token is not written back to disk.\n */\n persist = true,\n): Promise<Record<Permission, boolean>> {\n const project = process.cwd()\n const remembered = credentials.projects?.[project]\n const granted: Record<Permission, boolean> = { allowRead: false, allowWrite: false, allowConfigEdit: false, allowExec: false }\n const answers: Partial<Record<Permission, boolean>> = {}\n prompts.updateSettings({ withGuide: true })\n\n for (const { key, question } of PERMISSIONS) {\n if (options.permission[key] || typeof remembered?.[key] === 'boolean') {\n granted[key] = options.permission[key] || remembered?.[key] === true\n continue\n }\n\n if (isCIEnvironment() || !canUseTTY()) {\n granted[key] = false\n continue\n }\n\n granted[key] = (await prompts.confirm({ message: question(project, configPath), initialValue: false })) === true\n answers[key] = granted[key]\n }\n if (persist && Object.keys(answers).length) {\n await writeCredentials({\n ...credentials,\n projects: { ...credentials.projects, [project]: { ...remembered, ...answers } },\n })\n }\n\n return granted\n}\n\n/**\n * Loads the project's Kubb config the same way `kubb generate` does.\n * Returns the first config.\n */\nexport async function loadConfigs(options: StudioOptions): Promise<{ configPath: string; config: Config }> {\n const { configPath, configs } = await getConfigs({ configPath: options.configPath, logLevel: options.logLevel })\n const [config] = configs\n\n if (!config) {\n throw new Error('Config not defined, create a kubb.config.ts or pass it with --config')\n }\n\n // `getConfigs` resolves this to an absolute path. Relativized here, once, so the permission\n // prompt and the path Studio receives over the wire both show the project-relative form instead\n // of leaking the local filesystem layout.\n return { configPath: path.relative(process.cwd(), configPath) || configPath, config }\n}\n\n/**\n * Why a rejected token could not be recovered automatically: it came from `KUBB_AGENT_TOKEN`, no\n * browser is available to re-pair with, or the token this run already re-paired for was rejected\n * again.\n */\ntype RejectedTokenReason = 'envToken' | 'nonInteractive' | 'reauthExhausted'\n\n/**\n * Explains a rejected token to the operator. Builds the error and nothing else, so each caller\n * decides what happens to the credentials.\n */\nfunction explainRejectedToken(error: InvalidAgentTokenError, reason: RejectedTokenReason): Error {\n if (reason === 'envToken') {\n return new Error(`${error.message} Pair again and update KUBB_AGENT_TOKEN.`)\n }\n\n if (reason === 'reauthExhausted') {\n return new Error(`${error.message} Studio rejected the newly approved token too. Run \\`kubb studio login\\` and try again.`)\n }\n\n return new Error(`${error.message} Run \\`kubb studio login\\` to pair again.`)\n}\n\nexport type PreparedConnection = {\n configPath: string\n credentials: Credentials\n permissions: StudioOptions['permission']\n}\n\n/** Validates the project and resolves pairing and permissions before starting its worker. */\nexport async function prepareConnection(options: StudioOptions, signal?: AbortSignal): Promise<PreparedConnection> {\n const { configPath } = await loadConfigs(options)\n const envToken = process.env.KUBB_AGENT_TOKEN\n const stored = envToken ? null : await readCredentials()\n const credentials = await (async () => {\n if (envToken) return { studioUrl: options.studioUrl, token: envToken, agentId: '', agentSlug: '' }\n if (stored?.studioUrl === options.studioUrl) return stored\n if (isCIEnvironment()) {\n throw new Error(`Not paired with ${options.studioUrl}. Set KUBB_AGENT_TOKEN, or run \\`kubb studio login\\` on a machine with a browser.`)\n }\n return login(options, { signal })\n })()\n const permissions = await resolvePermissions(options, credentials, configPath, !envToken)\n return { configPath, credentials, permissions }\n}\n\nexport type WorkerState = 'starting' | 'connected' | 'reconnecting' | 'authentication required' | 'stopped'\n\n/** Runs the same project connection in the foreground or in a background worker. */\nexport async function connect(\n options: StudioOptions,\n context: {\n prepared?: PreparedConnection\n signal?: AbortSignal\n onState?: (state: WorkerState) => void | Promise<void>\n } = {},\n): Promise<void> {\n const shutdown = new AbortController()\n const signal = context.signal ?? shutdown.signal\n const stop = () => shutdown.abort()\n const events = process as unknown as NodeJS.EventEmitter\n if (!context.signal) {\n events.once('SIGINT', stop)\n events.once('SIGTERM', stop)\n }\n let hinted = false\n let reauthenticated = false\n try {\n if (!context.prepared) {\n const { getWorkerStatus } = await import('./background.ts')\n const worker = await getWorkerStatus()\n if (worker.running) throw new Error('This project is running in the background. Run `kubb studio stop` first.')\n }\n const prepared = context.prepared ?? (await prepareConnection(options, signal))\n let { credentials, permissions } = prepared\n const { configPath } = prepared\n await runConnection({\n credentials,\n signal,\n clientOptions: (): Omit<ClientOptions, 'token' | 'onAuthRequired'> => ({\n studioUrl: options.studioUrl,\n configPath,\n version: options.version,\n root: process.cwd(),\n permissions,\n loadConfig: async () => (await loadConfigs(options)).config,\n installLogger: async (hooks) => {\n // The background worker writes to a log file, so it gets the plain logger rather than the\n // animated one. The logger also covers the `studio:*` events and each generation run.\n await setupReporters(hooks, {\n logLevel: logLevelMap[options.logLevel ?? 'info'],\n reporters: [cliReporter],\n ...(context.onState ? { logger: plainLogger } : {}),\n })\n hooks.hook('studio:connected', () => {\n if (!hinted && !context.onState && options.logLevel !== 'silent') logBlock(styleText('dim', 'Press Ctrl+C to disconnect'))\n hinted = true\n })\n hooks.hook('studio:ready', async () => {\n await context.onState?.('connected')\n if (!context.onState) logTip()\n })\n hooks.hook('studio:reconnecting', () => context.onState?.('reconnecting'))\n },\n }),\n onTokenRejected: async ({ error, live }) => {\n await context.onState?.('authentication required')\n if (process.env.KUBB_AGENT_TOKEN) throw explainRejectedToken(error, 'envToken')\n if (!live) await clearCredentials()\n if (reauthenticated) throw explainRejectedToken(error, 'reauthExhausted')\n if (context.onState || isCIEnvironment() || !canUseTTY()) throw explainRejectedToken(error, 'nonInteractive')\n console.log(styleText('yellow', live ? `${error.message} Studio needs you to approve access again.` : `${error.message} Pairing again...`))\n if (live) await clearCredentials()\n try {\n credentials = await login(options, { signal, previousCredentials: credentials })\n } catch (error) {\n if (error instanceof PairingCanceledError) {\n if (live && options.logLevel !== 'silent') logOutro('Disconnected')\n return null\n }\n throw error\n }\n reauthenticated = true\n permissions = await resolvePermissions(options, credentials, configPath, !process.env.KUBB_AGENT_TOKEN)\n return credentials\n },\n })\n if (!context.onState && signal.aborted && options.logLevel !== 'silent') logOutro('Disconnected')\n } catch (error) {\n if (!(error instanceof PairingCanceledError)) throw error\n } finally {\n events.off('SIGINT', stop)\n events.off('SIGTERM', stop)\n }\n}\n\n/**\n * Reports the paired agent and any saved permissions for the current project.\n */\nexport async function status(options: StudioOptions): Promise<void> {\n const credentials = await readCredentials()\n\n if (!credentials) {\n console.log('Not paired. Run `kubb studio login`.')\n\n return\n }\n\n console.log(`Paired with ${credentials.studioUrl} as ${styleText('cyan', credentials.agentSlug || credentials.agentId)}`)\n\n if (credentials.studioUrl !== options.studioUrl) {\n console.log(styleText('yellow', `Connecting to ${options.studioUrl} needs pairing again.`))\n }\n\n const remembered = credentials.projects?.[process.cwd()]\n\n if (!remembered) {\n console.log(styleText('dim', 'No saved permissions for this project. Run `kubb studio` to connect and choose.'))\n\n return\n }\n\n console.log(styleText('dim', 'Saved permissions'))\n\n for (const row of formatPermissionRows({\n allowRead: remembered.allowRead === true,\n allowWrite: remembered.allowWrite === true,\n allowConfigEdit: remembered.allowConfigEdit === true,\n allowExec: remembered.allowExec === true,\n })) {\n console.log(row)\n }\n}\n\n/**\n * Runs a Studio command with shared setup and telemetry reporting.\n */\nexport async function run(options: StudioOptions, action: () => Promise<unknown>, { block = false, json = false } = {}): Promise<void> {\n // The machine secret lives here and pairing binds it, so storage is installed before anything\n // reads `getMachineToken()`, which `startPairing` does, before any client exists.\n setStorage(createFileStorage(getProjectKubbHome()))\n\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'studio', kubbVersion: options.version, hrStart, status }))\n\n try {\n if (options.logLevel !== 'silent' && !json) {\n logIntro({\n warning: styleText('yellow', 'This feature is still under development, use with caution'),\n block,\n })\n }\n\n await action()\n\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-DBMVTeYc.js","names":["logLevelMap"],"sources":["../../../internals/utils/src/openInBrowser.ts","../../../internals/utils/src/fs.ts","../src/runners/studio/credentials.ts","../src/runners/studio/run.ts"],"sourcesContent":["import { execFile } from 'node:child_process'\nimport process from 'node:process'\nimport { isCIEnvironment } from './isCIEnvironment.ts'\n\n/**\n * Opens a URL or local file in the default browser, unless running in CI.\n */\nexport function openInBrowser(target: string): void {\n if (isCIEnvironment()) return\n\n if (process.platform === 'win32') {\n execFile('cmd', ['/c', 'start', '', target], () => {})\n } else {\n execFile(process.platform === 'darwin' ? 'open' : 'xdg-open', [target], () => {})\n }\n}\n","import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return content\n }\n\n // Creating the directory up front costs a syscall per file, and every file after the first in a\n // directory pays it for nothing. Write first and only fall back when the directory is missing,\n // which also stays correct when something removed it mid-run.\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n\n if (options.sanity) {\n const savedData = await readFile(resolved, { encoding: 'utf-8' })\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Recursively removes `path`. Silently succeeds when `path` does not exist.\n *\n * @example\n * ```ts\n * await clean('./dist')\n * ```\n */\nexport async function clean(path: string): Promise<void> {\n return rm(path, { recursive: true, force: true })\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { hash } from 'node:crypto'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { clean, read } from '@internals/utils'\n\n/**\n * Root for everything the CLI persists between runs: the paired credential, the machine secret,\n * the last Studio config, and the live-session registry. `KUBB_HOME` relocates all of it.\n */\nfunction getKubbHome(): string {\n return process.env.KUBB_HOME ?? path.join(homedir(), '.kubb')\n}\n\n/**\n * Root for the credential and machine identity of the current project.\n *\n * Studio agents are project connections, so two projects on one machine must not share the same\n * persisted token or machine secret.\n */\nexport function getProjectKubbHome(project = process.cwd()): string {\n const projectId = hash('sha256', project)\n return path.join(getKubbHome(), 'projects', projectId)\n}\n\nconst CREDENTIALS_FILENAME = 'credentials.json'\n\n/**\n * Absolute path of the stored credential, so callers can name it in output without rebuilding it.\n */\nexport function getCredentialsPath(): string {\n return path.join(getProjectKubbHome(), CREDENTIALS_FILENAME)\n}\n\nexport type Credentials = {\n /**\n * The Studio instance this machine paired with. A different `--url` means re-pairing.\n */\n studioUrl: string\n /**\n * Bearer token for this machine. Never logged, never printed.\n */\n token: string\n agentId: string\n agentSlug: string\n /**\n * Permissions the user has already granted, keyed by absolute project path, so the CLI asks\n * once per project instead of on every run.\n */\n projects?: Record<string, { allowRead?: boolean; allowWrite?: boolean; allowConfigEdit?: boolean; allowExec?: boolean }>\n}\n\n/**\n * Reads the stored credential, or null when this machine has not paired yet or the file is\n * unreadable or corrupt. A bad file is treated as \"not paired\" so `kubb studio login` can\n * overwrite it rather than the CLI dying on it.\n */\nexport async function readCredentials(): Promise<Credentials | null> {\n const raw = await read(getCredentialsPath()).catch(() => null)\n if (!raw) {\n return null\n }\n\n try {\n return JSON.parse(raw) as Credentials\n } catch {\n return null\n }\n}\n\n/**\n * Writes the credential with owner-only permissions. The file holds a bearer token, so the mode\n * is set at creation time rather than left to the process umask or fixed up afterward, which\n * would leave the token briefly readable under the umask's default mode.\n */\nexport async function writeCredentials(credentials: Credentials): Promise<void> {\n const file = getCredentialsPath()\n\n await mkdir(path.dirname(file), { recursive: true, mode: 0o700 })\n await writeFile(file, JSON.stringify(credentials, null, 2), { mode: 0o600 })\n}\n\n/**\n * Forgets the stored credential. Succeeds when there was nothing to forget.\n */\nexport async function clearCredentials(): Promise<void> {\n await clean(getCredentialsPath())\n}\n","import { hostname } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as prompts from '@clack/prompts'\nimport { KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { isCIEnvironment, openInBrowser, toError } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\nimport { cliReporter, logLevel as logLevelMap } from '@kubb/core'\nimport {\n createFileStorage,\n type ClientOptions,\n defaultStudioUrl,\n type InvalidAgentTokenError,\n pairAgent,\n PairingCanceledError,\n runConnection,\n setStorage,\n} from '@kubb/studio'\nimport { buildTelemetryEvent, sendTelemetry } from '../../Telemetry.ts'\nimport { plainLogger } from '../../loggers/plainLogger.ts'\nimport setupReporters from '../../loggers/utils.ts'\nimport { createSpinner, logBlock, logIntro, logOutro, logTip } from '../../loggers/output.ts'\nimport { canUseTTY } from '../../utils/env.ts'\nimport { getConfigs } from '../generate/utils.ts'\nimport { clearCredentials, type Credentials, getCredentialsPath, getProjectKubbHome, readCredentials, writeCredentials } from './credentials.ts'\nimport { version } from '../../../package.json'\n\ntype Permission = 'allowRead' | 'allowWrite' | 'allowConfigEdit' | 'allowExec'\n\nexport type StudioOptions = {\n /**\n * Current `@kubb/cli` version, reported to Studio and used for the telemetry payload.\n */\n version: string\n configPath?: string\n /**\n * Base URL of the Studio instance, for a self-hosted deployment. Resolved before it reaches here,\n * since stored credentials are bound to it.\n */\n studioUrl: string\n /**\n * What Studio may do in this project. Each flag grants outright; the rest are asked once per\n * project through {@link resolvePermissions}.\n */\n permission: Record<Permission, boolean>\n /**\n * Whether to open the approval page in a browser during pairing.\n */\n autoOpen: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\nexport type SnapshotOptions = StudioOptions & {\n /**\n * Organization CI API key. Falls back to `KUBB_TOKEN`.\n */\n token?: string\n /**\n * Stable identity for the CI agent. Falls back to CI auto-detection.\n */\n id?: string\n /** Identity of another CI agent to also compare with. Falls back to CI auto-detection. */\n baseId?: string\n /**\n * Package name for the generated tarball. Falls back to the nearest package.json.\n */\n name?: string\n /**\n * Package version for the generated tarball. Falls back to the nearest package.json.\n */\n packageVersion?: string\n /**\n * Seconds to wait for the job to finish.\n */\n timeout?: number\n /**\n * Print the result as one JSON object instead of a summary.\n */\n json?: boolean\n}\n\ntype StudioValues = {\n config?: string\n url?: string\n allowRead: boolean\n allowWrite: boolean\n allowConfigEdit: boolean\n allowExec: boolean\n open?: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\nexport function createStudioOptions(values: StudioValues): StudioOptions {\n return {\n version,\n configPath: values.config,\n studioUrl: values.url ?? defaultStudioUrl,\n permission: {\n allowRead: values.allowRead,\n allowWrite: values.allowWrite,\n allowConfigEdit: values.allowConfigEdit,\n allowExec: values.allowExec,\n },\n autoOpen: values.open ?? true,\n logLevel: values.logLevel,\n }\n}\n\ntype LoginOptions = {\n /**\n * Aborting this cancels an in-flight pairing request or poll and rejects with\n * {@link PairingCanceledError}. Wired to `kubb studio`'s shutdown signal, so Ctrl+C during\n * pairing cancels it instead of leaving the poll running.\n */\n signal?: AbortSignal\n /**\n * Credentials from before this login. When the fresh pairing resolves to the same agent on the\n * same Studio, its saved project permissions carry forward instead of being asked again.\n * Left out for an explicitly requested `kubb studio login`, which always starts clean.\n */\n previousCredentials?: Credentials | null\n}\n\n/**\n * Pairs this machine with Studio and stores the resulting token.\n *\n * The CLI holds a code and the browser approves it, rather than the user copying a token out of\n * the UI. The token comes back over the CLI's own HTTPS POST, so it never lands in a URL, a\n * server log, or a `Referer` header.\n */\nexport async function login({ studioUrl, autoOpen }: StudioOptions, { signal, previousCredentials }: LoginOptions = {}): Promise<Credentials> {\n const spinner = createSpinner()\n // The spinner only starts once a code is shown.\n let waiting = false\n\n try {\n const { token, agent } = await pairAgent({\n studioUrl,\n type: 'cli',\n name: path.basename(process.cwd()),\n hostname: hostname(),\n signal,\n onCode: (session) => {\n console.log(`\\nOpen ${styleText('cyan', session.verification_uri)} and approve the code ${styleText('bold', session.user_code)}`)\n\n if (autoOpen) {\n openInBrowser(session.verification_uri_complete)\n }\n\n spinner.start('Waiting for approval')\n waiting = true\n },\n onRetry: (error) => spinner.message(`Could not reach Kubb Studio, retrying: ${error.message}`),\n })\n spinner.stop(`Paired as ${agent.name}`)\n\n const keepsIdentity = previousCredentials?.studioUrl === studioUrl && previousCredentials.agentId === agent.id\n const credentials: Credentials = {\n studioUrl,\n token,\n agentId: agent.id,\n agentSlug: agent.slug,\n ...(keepsIdentity && previousCredentials?.projects ? { projects: previousCredentials.projects } : {}),\n }\n await writeCredentials(credentials)\n\n console.log(`Credentials stored in ${getCredentialsPath()}`)\n\n return credentials\n } catch (error) {\n if (waiting) {\n spinner.stop(error instanceof PairingCanceledError ? 'Pairing canceled' : 'Pairing failed')\n }\n throw error\n }\n}\n\n/**\n * What each permission is asked as, in the order the questions appear.\n */\nconst PERMISSIONS: ReadonlyArray<{\n key: Permission\n /**\n * Short label for status output and the connect summary.\n */\n label: string\n question: (project: string, configPath: string) => string\n}> = [\n {\n key: 'allowRead',\n label: 'read generated files',\n question: () => 'Let Kubb Studio read the files a generation produced?',\n },\n { key: 'allowWrite', label: 'write generated files', question: (project) => `Let Kubb Studio write generated files into ${project}?` },\n {\n key: 'allowConfigEdit',\n label: 'edit kubb.config.ts',\n question: (_project, configPath) => `Let Kubb Studio change plugin options in ${configPath}?`,\n },\n {\n key: 'allowExec',\n label: 'run formatter, linter, postGenerate',\n question: () => 'Let Kubb Studio run the formatter, the linter, and output.postGenerate?',\n },\n]\n\n/**\n * One row per permission, for the connect banner and `kubb studio status`. A list rather than a\n * joined line: four labels this long read as one run-on sentence side by side.\n */\nexport function formatPermissionRows(granted: Record<Permission, boolean>): Array<string> {\n return PERMISSIONS.map(({ key, label }) => `${granted[key] ? styleText('green', '✔') : styleText('red', '✘')} ${label}`)\n}\n\n/**\n * Resolves Studio permissions for the current project.\n * Flags win, saved answers are reused, and new answers are stored unless `persist` is false.\n */\nexport async function resolvePermissions(\n options: StudioOptions,\n credentials: Credentials,\n configPath: string = KUBB_CONFIG_FILENAME,\n /**\n * Stores new answers in `~/.kubb/credentials.json`.\n * Pass `false` for `KUBB_AGENT_TOKEN` sessions so a temporary token is not written back to disk.\n */\n persist = true,\n): Promise<Record<Permission, boolean>> {\n const project = process.cwd()\n const remembered = credentials.projects?.[project]\n const granted: Record<Permission, boolean> = { allowRead: false, allowWrite: false, allowConfigEdit: false, allowExec: false }\n const answers: Partial<Record<Permission, boolean>> = {}\n prompts.updateSettings({ withGuide: true })\n\n for (const { key, question } of PERMISSIONS) {\n if (options.permission[key] || typeof remembered?.[key] === 'boolean') {\n granted[key] = options.permission[key] || remembered?.[key] === true\n continue\n }\n\n if (isCIEnvironment() || !canUseTTY()) {\n granted[key] = false\n continue\n }\n\n granted[key] = (await prompts.confirm({ message: question(project, configPath), initialValue: false })) === true\n answers[key] = granted[key]\n }\n if (persist && Object.keys(answers).length) {\n await writeCredentials({\n ...credentials,\n projects: { ...credentials.projects, [project]: { ...remembered, ...answers } },\n })\n }\n\n return granted\n}\n\n/**\n * Loads the project's Kubb config the same way `kubb generate` does.\n * Returns the first config.\n */\nexport async function loadConfigs(options: StudioOptions): Promise<{ configPath: string; config: Config }> {\n const { configPath, configs } = await getConfigs({ configPath: options.configPath, logLevel: options.logLevel })\n const [config] = configs\n\n if (!config) {\n throw new Error('Config not defined, create a kubb.config.ts or pass it with --config')\n }\n\n // `getConfigs` resolves this to an absolute path. Relativized here, once, so the permission\n // prompt and the path Studio receives over the wire both show the project-relative form instead\n // of leaking the local filesystem layout.\n return { configPath: path.relative(process.cwd(), configPath) || configPath, config }\n}\n\n/**\n * Why a rejected token could not be recovered automatically: it came from `KUBB_AGENT_TOKEN`, no\n * browser is available to re-pair with, or the token this run already re-paired for was rejected\n * again.\n */\ntype RejectedTokenReason = 'envToken' | 'nonInteractive' | 'reauthExhausted'\n\n/**\n * Explains a rejected token to the operator. Builds the error and nothing else, so each caller\n * decides what happens to the credentials.\n */\nfunction explainRejectedToken(error: InvalidAgentTokenError, reason: RejectedTokenReason): Error {\n if (reason === 'envToken') {\n return new Error(`${error.message} Pair again and update KUBB_AGENT_TOKEN.`)\n }\n\n if (reason === 'reauthExhausted') {\n return new Error(`${error.message} Studio rejected the newly approved token too. Run \\`kubb studio login\\` and try again.`)\n }\n\n return new Error(`${error.message} Run \\`kubb studio login\\` to pair again.`)\n}\n\nexport type PreparedConnection = {\n configPath: string\n credentials: Credentials\n permissions: StudioOptions['permission']\n}\n\n/** Validates the project and resolves pairing and permissions before starting its worker. */\nexport async function prepareConnection(options: StudioOptions, signal?: AbortSignal): Promise<PreparedConnection> {\n const { configPath } = await loadConfigs(options)\n const envToken = process.env.KUBB_AGENT_TOKEN\n const stored = envToken ? null : await readCredentials()\n const credentials = await (async () => {\n if (envToken) return { studioUrl: options.studioUrl, token: envToken, agentId: '', agentSlug: '' }\n if (stored?.studioUrl === options.studioUrl) return stored\n if (isCIEnvironment()) {\n throw new Error(`Not paired with ${options.studioUrl}. Set KUBB_AGENT_TOKEN, or run \\`kubb studio login\\` on a machine with a browser.`)\n }\n return login(options, { signal })\n })()\n const permissions = await resolvePermissions(options, credentials, configPath, !envToken)\n return { configPath, credentials, permissions }\n}\n\nexport type WorkerState = 'starting' | 'connected' | 'reconnecting' | 'authentication required' | 'stopped'\n\n/** Runs the same project connection in the foreground or in a background worker. */\nexport async function connect(\n options: StudioOptions,\n context: {\n prepared?: PreparedConnection\n signal?: AbortSignal\n onState?: (state: WorkerState) => void | Promise<void>\n } = {},\n): Promise<void> {\n const shutdown = new AbortController()\n const signal = context.signal ?? shutdown.signal\n const stop = () => shutdown.abort()\n const events = process as unknown as NodeJS.EventEmitter\n if (!context.signal) {\n events.once('SIGINT', stop)\n events.once('SIGTERM', stop)\n }\n let hinted = false\n let reauthenticated = false\n try {\n if (!context.prepared) {\n const { getWorkerStatus } = await import('./background.ts')\n const worker = await getWorkerStatus()\n if (worker.running) throw new Error('This project is running in the background. Run `kubb studio stop` first.')\n }\n const prepared = context.prepared ?? (await prepareConnection(options, signal))\n let { credentials, permissions } = prepared\n const { configPath } = prepared\n await runConnection({\n credentials,\n signal,\n clientOptions: (): Omit<ClientOptions, 'token' | 'onAuthRequired'> => ({\n studioUrl: options.studioUrl,\n configPath,\n version: options.version,\n root: process.cwd(),\n permissions,\n loadConfig: async () => (await loadConfigs(options)).config,\n installLogger: async (hooks) => {\n // The background worker writes to a log file, so it gets the plain logger rather than the\n // animated one. The logger also covers the `studio:*` events and each generation run.\n await setupReporters(hooks, {\n logLevel: logLevelMap[options.logLevel ?? 'info'],\n reporters: [cliReporter],\n ...(context.onState ? { logger: plainLogger } : {}),\n })\n hooks.hook('studio:connected', () => {\n if (!hinted && !context.onState && options.logLevel !== 'silent') logBlock(styleText('dim', 'Press Ctrl+C to disconnect'))\n hinted = true\n })\n hooks.hook('studio:ready', async () => {\n await context.onState?.('connected')\n if (!context.onState) logTip()\n })\n hooks.hook('studio:reconnecting', () => context.onState?.('reconnecting'))\n },\n }),\n onTokenRejected: async ({ error, live }) => {\n await context.onState?.('authentication required')\n if (process.env.KUBB_AGENT_TOKEN) throw explainRejectedToken(error, 'envToken')\n if (!live) await clearCredentials()\n if (reauthenticated) throw explainRejectedToken(error, 'reauthExhausted')\n if (context.onState || isCIEnvironment() || !canUseTTY()) throw explainRejectedToken(error, 'nonInteractive')\n console.log(styleText('yellow', live ? `${error.message} Studio needs you to approve access again.` : `${error.message} Pairing again...`))\n if (live) await clearCredentials()\n try {\n credentials = await login(options, { signal, previousCredentials: credentials })\n } catch (error) {\n if (error instanceof PairingCanceledError) {\n if (live && options.logLevel !== 'silent') logOutro('Disconnected')\n return null\n }\n throw error\n }\n reauthenticated = true\n permissions = await resolvePermissions(options, credentials, configPath, !process.env.KUBB_AGENT_TOKEN)\n return credentials\n },\n })\n if (!context.onState && signal.aborted && options.logLevel !== 'silent') logOutro('Disconnected')\n } catch (error) {\n if (!(error instanceof PairingCanceledError)) throw error\n } finally {\n events.off('SIGINT', stop)\n events.off('SIGTERM', stop)\n }\n}\n\n/**\n * Reports the paired agent and any saved permissions for the current project.\n */\nexport async function status(options: StudioOptions): Promise<void> {\n const credentials = await readCredentials()\n\n if (!credentials) {\n console.log('Not paired. Run `kubb studio login`.')\n\n return\n }\n\n console.log(`Paired with ${credentials.studioUrl} as ${styleText('cyan', credentials.agentSlug || credentials.agentId)}`)\n\n if (credentials.studioUrl !== options.studioUrl) {\n console.log(styleText('yellow', `Connecting to ${options.studioUrl} needs pairing again.`))\n }\n\n const remembered = credentials.projects?.[process.cwd()]\n\n if (!remembered) {\n console.log(styleText('dim', 'No saved permissions for this project. Run `kubb studio` to connect and choose.'))\n\n return\n }\n\n console.log(styleText('dim', 'Saved permissions'))\n\n for (const row of formatPermissionRows({\n allowRead: remembered.allowRead === true,\n allowWrite: remembered.allowWrite === true,\n allowConfigEdit: remembered.allowConfigEdit === true,\n allowExec: remembered.allowExec === true,\n })) {\n console.log(row)\n }\n}\n\n/**\n * Runs a Studio command with shared setup and telemetry reporting.\n */\nexport async function run(options: StudioOptions, action: () => Promise<unknown>, { block = false, json = false } = {}): Promise<void> {\n // The machine secret lives here and pairing binds it, so storage is installed before anything\n // reads `getMachineToken()`, which `startPairing` does, before any client exists.\n setStorage(createFileStorage(getProjectKubbHome()))\n\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => sendTelemetry(buildTelemetryEvent({ command: 'studio', kubbVersion: options.version, hrStart, status }))\n\n try {\n if (options.logLevel !== 'silent' && !json) {\n logIntro({\n warning: styleText('yellow', 'This feature is still under development, use with caution'),\n block,\n })\n }\n\n await action()\n\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ const require_agent = require("./agent-BPqs9VRj.cjs");
4
4
  const require_Telemetry = require("./Telemetry-B3kc9gFh.cjs");
5
5
  const require_utils = require("./utils-Dcw3l4Wz.cjs");
6
6
  const require_output = require("./output-9qUFmWFq.cjs");
7
- const require_package = require("./package-BgCML9qr.cjs");
7
+ const require_package = require("./package-DTQG_XnR.cjs");
8
8
  const require_constants = require("./constants-CdxpgX3_.cjs");
9
9
  let node_util = require("node:util");
10
10
  let node_crypto = require("node:crypto");
@@ -330,7 +330,7 @@ async function connect(options, context = {}) {
330
330
  let reauthenticated = false;
331
331
  try {
332
332
  if (!context.prepared) {
333
- const { getWorkerStatus } = await Promise.resolve().then(() => require("./background-BHibcUDK.cjs"));
333
+ const { getWorkerStatus } = await Promise.resolve().then(() => require("./background-DUJO9lqp.cjs"));
334
334
  if ((await getWorkerStatus()).running) throw new Error("This project is running in the background. Run `kubb studio stop` first.");
335
335
  }
336
336
  const prepared = context.prepared ?? await prepareConnection(options, signal);
@@ -513,4 +513,4 @@ Object.defineProperty(exports, "status", {
513
513
  }
514
514
  });
515
515
 
516
- //# sourceMappingURL=run-CZXyo8RD.cjs.map
516
+ //# sourceMappingURL=run-DcxxL66g.cjs.map