@kubb/cli 5.15.0 → 5.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/{Telemetry-COWGqYmh.cjs → Telemetry-B52pKz9i.cjs} +2 -2
  2. package/dist/{Telemetry-COWGqYmh.cjs.map → Telemetry-B52pKz9i.cjs.map} +1 -1
  3. package/dist/{Telemetry-B3edcFoB.js → Telemetry-C7Qwy2s7.js} +2 -2
  4. package/dist/{Telemetry-B3edcFoB.js.map → Telemetry-C7Qwy2s7.js.map} +1 -1
  5. package/dist/{background-_dKcGjM7.js → background-BJCuXYuB.js} +2 -2
  6. package/dist/{background-_dKcGjM7.js.map → background-BJCuXYuB.js.map} +1 -1
  7. package/dist/{background-B24lIehn.cjs → background-CK2gQtTU.cjs} +2 -2
  8. package/dist/{background-B24lIehn.cjs.map → background-CK2gQtTU.cjs.map} +1 -1
  9. package/dist/{background-D-7OGjvg.js → background-D4mZCg-4.js} +1 -1
  10. package/dist/index.cjs +9 -9
  11. package/dist/index.js +9 -9
  12. package/dist/{mcp-CYPOFKnP.cjs → mcp-CcseJJwh.cjs} +2 -2
  13. package/dist/{mcp-CYPOFKnP.cjs.map → mcp-CcseJJwh.cjs.map} +1 -1
  14. package/dist/{mcp-CxeZR5vb.js → mcp-DUTsS8tR.js} +2 -2
  15. package/dist/{mcp-CxeZR5vb.js.map → mcp-DUTsS8tR.js.map} +1 -1
  16. package/dist/{package-aX0q9SZr.cjs → package-B1hUUjio.cjs} +2 -2
  17. package/dist/package-B1hUUjio.cjs.map +1 -0
  18. package/dist/package-MYPMnnTX.js +5 -0
  19. package/dist/package-MYPMnnTX.js.map +1 -0
  20. package/dist/{run-CCLPt4hr.js → run-Bq6gcfkS.js} +1 -1
  21. package/dist/{run-RN_31Q4u.js → run-BsrNfFIl.js} +2 -2
  22. package/dist/{run-RN_31Q4u.js.map → run-BsrNfFIl.js.map} +1 -1
  23. package/dist/{run-C0KI-NE3.js → run-CLiHI99L.js} +2 -2
  24. package/dist/{run-C0KI-NE3.js.map → run-CLiHI99L.js.map} +1 -1
  25. package/dist/{run-Bb19PlwV.cjs → run-CQORv7Gq.cjs} +5 -5
  26. package/dist/{run-Bb19PlwV.cjs.map → run-CQORv7Gq.cjs.map} +1 -1
  27. package/dist/{run-CbX6tpqB.js → run-CXVhxFfC.js} +3 -3
  28. package/dist/{run-CbX6tpqB.js.map → run-CXVhxFfC.js.map} +1 -1
  29. package/dist/{run-BoO7H8RA.cjs → run-CyzKy-0p.cjs} +3 -3
  30. package/dist/{run-BoO7H8RA.cjs.map → run-CyzKy-0p.cjs.map} +1 -1
  31. package/dist/{run-DgGZOC_x.cjs → run-DBnSbwtU.cjs} +2 -2
  32. package/dist/{run-DgGZOC_x.cjs.map → run-DBnSbwtU.cjs.map} +1 -1
  33. package/dist/{run-DFXhBS64.js → run-DTqMrPS9.js} +2 -2
  34. package/dist/{run-DFXhBS64.js.map → run-DTqMrPS9.js.map} +1 -1
  35. package/dist/{run-KqdudiWQ.js → run-DUwX6Icx.js} +5 -5
  36. package/dist/{run-KqdudiWQ.js.map → run-DUwX6Icx.js.map} +1 -1
  37. package/dist/{run-CCsdLz3X.js → run-FEiyv6_U.js} +2 -2
  38. package/dist/{run-CCsdLz3X.js.map → run-FEiyv6_U.js.map} +1 -1
  39. package/dist/{run-B4zvF9WY.cjs → run-LY_UAYyM.cjs} +2 -2
  40. package/dist/{run-B4zvF9WY.cjs.map → run-LY_UAYyM.cjs.map} +1 -1
  41. package/dist/{run-DCqmf5W1.cjs → run-dMTJfs4_.cjs} +2 -2
  42. package/dist/{run-DCqmf5W1.cjs.map → run-dMTJfs4_.cjs.map} +1 -1
  43. package/dist/{run-D5Z6nfzK.cjs → run-uPA5s3rI.cjs} +2 -2
  44. package/dist/{run-D5Z6nfzK.cjs.map → run-uPA5s3rI.cjs.map} +1 -1
  45. package/dist/{snapshot-D7Ytw8S0.cjs → snapshot-CPF9zyZj.cjs} +2 -2
  46. package/dist/{snapshot-D7Ytw8S0.cjs.map → snapshot-CPF9zyZj.cjs.map} +1 -1
  47. package/dist/{snapshot-n7dJGCWv.js → snapshot-CiV08NJr.js} +2 -2
  48. package/dist/{snapshot-n7dJGCWv.js.map → snapshot-CiV08NJr.js.map} +1 -1
  49. package/dist/{status-Bc0_4T41.cjs → status-C066YA-4.cjs} +2 -2
  50. package/dist/{status-Bc0_4T41.cjs.map → status-C066YA-4.cjs.map} +1 -1
  51. package/dist/{status-DxSkp1cH.js → status-Dj8tivag.js} +2 -2
  52. package/dist/{status-DxSkp1cH.js.map → status-Dj8tivag.js.map} +1 -1
  53. package/dist/{studio-mw6HaPkr.js → studio-B4XsXgKj.js} +11 -11
  54. package/dist/{studio-mw6HaPkr.js.map → studio-B4XsXgKj.js.map} +1 -1
  55. package/dist/{studio-BpYwgFb0.cjs → studio-D9_-mKee.cjs} +11 -11
  56. package/dist/{studio-BpYwgFb0.cjs.map → studio-D9_-mKee.cjs.map} +1 -1
  57. package/dist/studioWorker.js +2 -2
  58. package/dist/{validate-CMSeDpGT.cjs → validate-B3tLWYJU.cjs} +2 -2
  59. package/dist/{validate-CMSeDpGT.cjs.map → validate-B3tLWYJU.cjs.map} +1 -1
  60. package/dist/{validate-8ZcWXfMt.js → validate-C5fyNF4v.js} +2 -2
  61. package/dist/{validate-8ZcWXfMt.js.map → validate-C5fyNF4v.js.map} +1 -1
  62. package/package.json +7 -7
  63. package/dist/package-D3Yss9Bb.js +0 -5
  64. package/dist/package-D3Yss9Bb.js.map +0 -1
  65. package/dist/package-aX0q9SZr.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C3-Zg-KD.cjs");
2
2
  const require_isCIEnvironment = require("./isCIEnvironment-DiVOMI5Q.cjs");
3
3
  const require_time = require("./time-3BKoci3G.cjs");
4
- const require_package = require("./package-aX0q9SZr.cjs");
4
+ const require_package = require("./package-B1hUUjio.cjs");
5
5
  let node_crypto = require("node:crypto");
6
6
  let node_os = require("node:os");
7
7
  node_os = require_rolldown_runtime.__toESM(node_os, 1);
@@ -175,4 +175,4 @@ Object.defineProperty(exports, "trackRun", {
175
175
  }
176
176
  });
177
177
 
178
- //# sourceMappingURL=Telemetry-COWGqYmh.cjs.map
178
+ //# sourceMappingURL=Telemetry-B52pKz9i.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Telemetry-COWGqYmh.cjs","names":["process","getElapsedMs","randomBytes","getAgentProfile","version","runtime","os","isCIEnvironment"],"sources":["../src/Telemetry.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport os from 'node:os'\nimport process from 'node:process'\nimport { getElapsedMs, isCIEnvironment, runtime } from '@internals/utils'\nimport { getAgentProfile } from 'gunshi/agent'\nimport { version } from '../package.json'\n\n/** OpenTelemetry ingestion endpoint for anonymous usage telemetry. */\nconst OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const\n\ntype TelemetryCommand = 'generate' | 'mcp' | 'studio' | 'validate'\n\n/**\n * Anonymous plugin name and options snapshot sent with each telemetry event.\n */\nexport type TelemetryPlugin = {\n /**\n * Plugin name as registered in the Kubb config, e.g. `'@kubb/plugin-ts'`.\n */\n name: string\n /**\n * Anonymized snapshot of the plugin options. Values are included but cannot be traced back to a user.\n */\n options: Record<string, unknown>\n}\n\n/** How a command run ended, as the command reports it to the function {@link trackRun} returned. */\ntype RunResult = {\n status: 'success' | 'failed'\n plugins?: Array<TelemetryPlugin>\n filesCreated?: number\n /**\n * Name the MCP client sends in its `initialize` request, e.g. `'claude-code'`. Only set for `kubb mcp`.\n */\n mcpClient?: string\n}\n\n/**\n * Returns `true` when telemetry is disabled via `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY`.\n */\nexport function isDisabled(): boolean {\n return ['DO_NOT_TRACK', 'KUBB_DISABLE_TELEMETRY'].some((name) => ['1', 'true'].includes(process.env[name] ?? ''))\n}\n\n/** Tracks one command run for the running CLI version; returns the reporter the command calls once it knows how it ended. */\nexport function trackRun({ command, hrStart }: { command: TelemetryCommand; hrStart: [number, number] }): (result: RunResult) => Promise<void> {\n return (result) => sendTelemetry(buildOtlpPayload({ command, duration: Math.round(getElapsedMs(hrStart)), ...result }))\n}\n\n/**\n * The OTLP trace payload for one run: a span named after the command whose attributes are the\n * anonymous run facts. The attribute keys are the contract with otlp.kubb.dev.\n *\n * @see https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/\n */\nexport function buildOtlpPayload({\n command,\n duration,\n status,\n plugins = [],\n filesCreated = 0,\n mcpClient,\n}: RunResult & { command: TelemetryCommand; duration: number }) {\n const traceId = randomBytes(16).toString('hex')\n const spanId = randomBytes(8).toString('hex')\n const endTimeNs = BigInt(Date.now()) * 1_000_000n\n const startTimeNs = endTimeNs - BigInt(duration) * 1_000_000n\n const pluginNames = [...new Set(plugins.map((plugin) => plugin.name))].sort()\n const agent = getAgentProfile()\n\n const attributes = [\n { key: 'kubb.command', value: { stringValue: command } },\n { key: 'kubb.version', value: { stringValue: version } },\n { key: 'kubb.node_version', value: { stringValue: process.versions.node.split('.')[0] as string } },\n { key: 'kubb.runtime', value: { stringValue: runtime.name } },\n { key: 'kubb.runtime_version', value: { stringValue: runtime.version.split('.')[0] as string } },\n { key: 'kubb.platform', value: { stringValue: os.platform() } },\n { key: 'kubb.ci', value: { boolValue: isCIEnvironment() } },\n // A terminal on stdin means a person typed the command; agents, scripts, and CI pipe it.\n { key: 'kubb.tty', value: { boolValue: process.stdin.isTTY === true } },\n ...(agent.isAgent && agent.name ? [{ key: 'kubb.agent', value: { stringValue: agent.name } }] : []),\n // The client picks this name, so cap its length before it leaves the machine.\n ...(mcpClient ? [{ key: 'kubb.mcp_client', value: { stringValue: mcpClient.slice(0, 64) } }] : []),\n { key: 'kubb.files_created', value: { intValue: filesCreated } },\n { key: 'kubb.status', value: { stringValue: status } },\n {\n key: 'kubb.plugins',\n value: { arrayValue: { values: pluginNames.map((name) => ({ stringValue: name })) } },\n },\n ...pluginNames.map((name) => ({ key: `kubb.plugin.${name}`, value: { boolValue: true } })),\n {\n key: 'kubb.plugin_options',\n value: {\n arrayValue: {\n values: plugins.map((p) => ({\n kvlistValue: {\n values: [\n { key: 'name', value: { stringValue: p.name } },\n {\n key: 'options',\n value: {\n stringValue: JSON.stringify({\n ...p.options,\n usedEnumNames: undefined,\n }),\n },\n },\n ],\n },\n })),\n },\n },\n },\n ]\n\n return {\n resourceSpans: [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: 'kubb' } },\n { key: 'service.version', value: { stringValue: version } },\n { key: 'telemetry.sdk.language', value: { stringValue: 'nodejs' } },\n ],\n },\n scopeSpans: [\n {\n scope: { name: 'kubb-core', version },\n spans: [\n {\n traceId,\n spanId,\n name: command,\n kind: 1,\n startTimeUnixNano: String(startTimeNs),\n endTimeUnixNano: String(endTimeNs),\n attributes,\n status: {\n code: status === 'success' ? 1 : 2,\n },\n },\n ],\n },\n ],\n },\n ],\n }\n}\n\n/**\n * Send an OTLP payload to the Kubb endpoint. Respects `DO_NOT_TRACK` and\n * `KUBB_DISABLE_TELEMETRY`, and fails silently so telemetry never interrupts a run. No file\n * paths, OpenAPI specs, or secrets are sent.\n */\nexport async function sendTelemetry(payload: ReturnType<typeof buildOtlpPayload>): Promise<void> {\n if (isDisabled()) {\n return\n }\n\n try {\n await fetch(`${OTLP_ENDPOINT}/v1/traces`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Kubb-Telemetry-Version': '1',\n 'Kubb-Telemetry-Source': 'kubb-cli',\n },\n body: JSON.stringify(payload),\n // Short, since an unfinished request keeps the process alive after the run.\n signal: AbortSignal.timeout(1_000),\n })\n } catch (_e) {\n // Fail silently, telemetry must never break the run\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Telemetry-B52pKz9i.cjs","names":["process","getElapsedMs","randomBytes","getAgentProfile","version","runtime","os","isCIEnvironment"],"sources":["../src/Telemetry.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport os from 'node:os'\nimport process from 'node:process'\nimport { getElapsedMs, isCIEnvironment, runtime } from '@internals/utils'\nimport { getAgentProfile } from 'gunshi/agent'\nimport { version } from '../package.json'\n\n/** OpenTelemetry ingestion endpoint for anonymous usage telemetry. */\nconst OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const\n\ntype TelemetryCommand = 'generate' | 'mcp' | 'studio' | 'validate'\n\n/**\n * Anonymous plugin name and options snapshot sent with each telemetry event.\n */\nexport type TelemetryPlugin = {\n /**\n * Plugin name as registered in the Kubb config, e.g. `'@kubb/plugin-ts'`.\n */\n name: string\n /**\n * Anonymized snapshot of the plugin options. Values are included but cannot be traced back to a user.\n */\n options: Record<string, unknown>\n}\n\n/** How a command run ended, as the command reports it to the function {@link trackRun} returned. */\ntype RunResult = {\n status: 'success' | 'failed'\n plugins?: Array<TelemetryPlugin>\n filesCreated?: number\n /**\n * Name the MCP client sends in its `initialize` request, e.g. `'claude-code'`. Only set for `kubb mcp`.\n */\n mcpClient?: string\n}\n\n/**\n * Returns `true` when telemetry is disabled via `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY`.\n */\nexport function isDisabled(): boolean {\n return ['DO_NOT_TRACK', 'KUBB_DISABLE_TELEMETRY'].some((name) => ['1', 'true'].includes(process.env[name] ?? ''))\n}\n\n/** Tracks one command run for the running CLI version; returns the reporter the command calls once it knows how it ended. */\nexport function trackRun({ command, hrStart }: { command: TelemetryCommand; hrStart: [number, number] }): (result: RunResult) => Promise<void> {\n return (result) => sendTelemetry(buildOtlpPayload({ command, duration: Math.round(getElapsedMs(hrStart)), ...result }))\n}\n\n/**\n * The OTLP trace payload for one run: a span named after the command whose attributes are the\n * anonymous run facts. The attribute keys are the contract with otlp.kubb.dev.\n *\n * @see https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/\n */\nexport function buildOtlpPayload({\n command,\n duration,\n status,\n plugins = [],\n filesCreated = 0,\n mcpClient,\n}: RunResult & { command: TelemetryCommand; duration: number }) {\n const traceId = randomBytes(16).toString('hex')\n const spanId = randomBytes(8).toString('hex')\n const endTimeNs = BigInt(Date.now()) * 1_000_000n\n const startTimeNs = endTimeNs - BigInt(duration) * 1_000_000n\n const pluginNames = [...new Set(plugins.map((plugin) => plugin.name))].sort()\n const agent = getAgentProfile()\n\n const attributes = [\n { key: 'kubb.command', value: { stringValue: command } },\n { key: 'kubb.version', value: { stringValue: version } },\n { key: 'kubb.node_version', value: { stringValue: process.versions.node.split('.')[0] as string } },\n { key: 'kubb.runtime', value: { stringValue: runtime.name } },\n { key: 'kubb.runtime_version', value: { stringValue: runtime.version.split('.')[0] as string } },\n { key: 'kubb.platform', value: { stringValue: os.platform() } },\n { key: 'kubb.ci', value: { boolValue: isCIEnvironment() } },\n // A terminal on stdin means a person typed the command; agents, scripts, and CI pipe it.\n { key: 'kubb.tty', value: { boolValue: process.stdin.isTTY === true } },\n ...(agent.isAgent && agent.name ? [{ key: 'kubb.agent', value: { stringValue: agent.name } }] : []),\n // The client picks this name, so cap its length before it leaves the machine.\n ...(mcpClient ? [{ key: 'kubb.mcp_client', value: { stringValue: mcpClient.slice(0, 64) } }] : []),\n { key: 'kubb.files_created', value: { intValue: filesCreated } },\n { key: 'kubb.status', value: { stringValue: status } },\n {\n key: 'kubb.plugins',\n value: { arrayValue: { values: pluginNames.map((name) => ({ stringValue: name })) } },\n },\n ...pluginNames.map((name) => ({ key: `kubb.plugin.${name}`, value: { boolValue: true } })),\n {\n key: 'kubb.plugin_options',\n value: {\n arrayValue: {\n values: plugins.map((p) => ({\n kvlistValue: {\n values: [\n { key: 'name', value: { stringValue: p.name } },\n {\n key: 'options',\n value: {\n stringValue: JSON.stringify({\n ...p.options,\n usedEnumNames: undefined,\n }),\n },\n },\n ],\n },\n })),\n },\n },\n },\n ]\n\n return {\n resourceSpans: [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: 'kubb' } },\n { key: 'service.version', value: { stringValue: version } },\n { key: 'telemetry.sdk.language', value: { stringValue: 'nodejs' } },\n ],\n },\n scopeSpans: [\n {\n scope: { name: 'kubb-core', version },\n spans: [\n {\n traceId,\n spanId,\n name: command,\n kind: 1,\n startTimeUnixNano: String(startTimeNs),\n endTimeUnixNano: String(endTimeNs),\n attributes,\n status: {\n code: status === 'success' ? 1 : 2,\n },\n },\n ],\n },\n ],\n },\n ],\n }\n}\n\n/**\n * Send an OTLP payload to the Kubb endpoint. Respects `DO_NOT_TRACK` and\n * `KUBB_DISABLE_TELEMETRY`, and fails silently so telemetry never interrupts a run. No file\n * paths, OpenAPI specs, or secrets are sent.\n */\nexport async function sendTelemetry(payload: ReturnType<typeof buildOtlpPayload>): Promise<void> {\n if (isDisabled()) {\n return\n }\n\n try {\n await fetch(`${OTLP_ENDPOINT}/v1/traces`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Kubb-Telemetry-Version': '1',\n 'Kubb-Telemetry-Source': 'kubb-cli',\n },\n body: JSON.stringify(payload),\n // Short, since an unfinished request keeps the process alive after the run.\n signal: AbortSignal.timeout(1_000),\n })\n } catch (_e) {\n // Fail silently, telemetry must never break the run\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import "./rolldown-runtime-xo6NMXYd.js";
2
2
  import { t as isCIEnvironment } from "./isCIEnvironment-D6xtAAZ2.js";
3
3
  import { n as getElapsedMs, r as runtime } from "./time-C-wU7VhC.js";
4
- import { t as version } from "./package-D3Yss9Bb.js";
4
+ import { t as version } from "./package-MYPMnnTX.js";
5
5
  import { randomBytes } from "node:crypto";
6
6
  import os from "node:os";
7
7
  import process from "node:process";
@@ -162,4 +162,4 @@ async function sendTelemetry(payload) {
162
162
  }
163
163
  export { trackRun as n, isDisabled as t };
164
164
 
165
- //# sourceMappingURL=Telemetry-B3edcFoB.js.map
165
+ //# sourceMappingURL=Telemetry-C7Qwy2s7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Telemetry-B3edcFoB.js","names":[],"sources":["../src/Telemetry.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport os from 'node:os'\nimport process from 'node:process'\nimport { getElapsedMs, isCIEnvironment, runtime } from '@internals/utils'\nimport { getAgentProfile } from 'gunshi/agent'\nimport { version } from '../package.json'\n\n/** OpenTelemetry ingestion endpoint for anonymous usage telemetry. */\nconst OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const\n\ntype TelemetryCommand = 'generate' | 'mcp' | 'studio' | 'validate'\n\n/**\n * Anonymous plugin name and options snapshot sent with each telemetry event.\n */\nexport type TelemetryPlugin = {\n /**\n * Plugin name as registered in the Kubb config, e.g. `'@kubb/plugin-ts'`.\n */\n name: string\n /**\n * Anonymized snapshot of the plugin options. Values are included but cannot be traced back to a user.\n */\n options: Record<string, unknown>\n}\n\n/** How a command run ended, as the command reports it to the function {@link trackRun} returned. */\ntype RunResult = {\n status: 'success' | 'failed'\n plugins?: Array<TelemetryPlugin>\n filesCreated?: number\n /**\n * Name the MCP client sends in its `initialize` request, e.g. `'claude-code'`. Only set for `kubb mcp`.\n */\n mcpClient?: string\n}\n\n/**\n * Returns `true` when telemetry is disabled via `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY`.\n */\nexport function isDisabled(): boolean {\n return ['DO_NOT_TRACK', 'KUBB_DISABLE_TELEMETRY'].some((name) => ['1', 'true'].includes(process.env[name] ?? ''))\n}\n\n/** Tracks one command run for the running CLI version; returns the reporter the command calls once it knows how it ended. */\nexport function trackRun({ command, hrStart }: { command: TelemetryCommand; hrStart: [number, number] }): (result: RunResult) => Promise<void> {\n return (result) => sendTelemetry(buildOtlpPayload({ command, duration: Math.round(getElapsedMs(hrStart)), ...result }))\n}\n\n/**\n * The OTLP trace payload for one run: a span named after the command whose attributes are the\n * anonymous run facts. The attribute keys are the contract with otlp.kubb.dev.\n *\n * @see https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/\n */\nexport function buildOtlpPayload({\n command,\n duration,\n status,\n plugins = [],\n filesCreated = 0,\n mcpClient,\n}: RunResult & { command: TelemetryCommand; duration: number }) {\n const traceId = randomBytes(16).toString('hex')\n const spanId = randomBytes(8).toString('hex')\n const endTimeNs = BigInt(Date.now()) * 1_000_000n\n const startTimeNs = endTimeNs - BigInt(duration) * 1_000_000n\n const pluginNames = [...new Set(plugins.map((plugin) => plugin.name))].sort()\n const agent = getAgentProfile()\n\n const attributes = [\n { key: 'kubb.command', value: { stringValue: command } },\n { key: 'kubb.version', value: { stringValue: version } },\n { key: 'kubb.node_version', value: { stringValue: process.versions.node.split('.')[0] as string } },\n { key: 'kubb.runtime', value: { stringValue: runtime.name } },\n { key: 'kubb.runtime_version', value: { stringValue: runtime.version.split('.')[0] as string } },\n { key: 'kubb.platform', value: { stringValue: os.platform() } },\n { key: 'kubb.ci', value: { boolValue: isCIEnvironment() } },\n // A terminal on stdin means a person typed the command; agents, scripts, and CI pipe it.\n { key: 'kubb.tty', value: { boolValue: process.stdin.isTTY === true } },\n ...(agent.isAgent && agent.name ? [{ key: 'kubb.agent', value: { stringValue: agent.name } }] : []),\n // The client picks this name, so cap its length before it leaves the machine.\n ...(mcpClient ? [{ key: 'kubb.mcp_client', value: { stringValue: mcpClient.slice(0, 64) } }] : []),\n { key: 'kubb.files_created', value: { intValue: filesCreated } },\n { key: 'kubb.status', value: { stringValue: status } },\n {\n key: 'kubb.plugins',\n value: { arrayValue: { values: pluginNames.map((name) => ({ stringValue: name })) } },\n },\n ...pluginNames.map((name) => ({ key: `kubb.plugin.${name}`, value: { boolValue: true } })),\n {\n key: 'kubb.plugin_options',\n value: {\n arrayValue: {\n values: plugins.map((p) => ({\n kvlistValue: {\n values: [\n { key: 'name', value: { stringValue: p.name } },\n {\n key: 'options',\n value: {\n stringValue: JSON.stringify({\n ...p.options,\n usedEnumNames: undefined,\n }),\n },\n },\n ],\n },\n })),\n },\n },\n },\n ]\n\n return {\n resourceSpans: [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: 'kubb' } },\n { key: 'service.version', value: { stringValue: version } },\n { key: 'telemetry.sdk.language', value: { stringValue: 'nodejs' } },\n ],\n },\n scopeSpans: [\n {\n scope: { name: 'kubb-core', version },\n spans: [\n {\n traceId,\n spanId,\n name: command,\n kind: 1,\n startTimeUnixNano: String(startTimeNs),\n endTimeUnixNano: String(endTimeNs),\n attributes,\n status: {\n code: status === 'success' ? 1 : 2,\n },\n },\n ],\n },\n ],\n },\n ],\n }\n}\n\n/**\n * Send an OTLP payload to the Kubb endpoint. Respects `DO_NOT_TRACK` and\n * `KUBB_DISABLE_TELEMETRY`, and fails silently so telemetry never interrupts a run. No file\n * paths, OpenAPI specs, or secrets are sent.\n */\nexport async function sendTelemetry(payload: ReturnType<typeof buildOtlpPayload>): Promise<void> {\n if (isDisabled()) {\n return\n }\n\n try {\n await fetch(`${OTLP_ENDPOINT}/v1/traces`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Kubb-Telemetry-Version': '1',\n 'Kubb-Telemetry-Source': 'kubb-cli',\n },\n body: JSON.stringify(payload),\n // Short, since an unfinished request keeps the process alive after the run.\n signal: AbortSignal.timeout(1_000),\n })\n } catch (_e) {\n // Fail silently, telemetry must never break the run\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Telemetry-C7Qwy2s7.js","names":[],"sources":["../src/Telemetry.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport os from 'node:os'\nimport process from 'node:process'\nimport { getElapsedMs, isCIEnvironment, runtime } from '@internals/utils'\nimport { getAgentProfile } from 'gunshi/agent'\nimport { version } from '../package.json'\n\n/** OpenTelemetry ingestion endpoint for anonymous usage telemetry. */\nconst OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const\n\ntype TelemetryCommand = 'generate' | 'mcp' | 'studio' | 'validate'\n\n/**\n * Anonymous plugin name and options snapshot sent with each telemetry event.\n */\nexport type TelemetryPlugin = {\n /**\n * Plugin name as registered in the Kubb config, e.g. `'@kubb/plugin-ts'`.\n */\n name: string\n /**\n * Anonymized snapshot of the plugin options. Values are included but cannot be traced back to a user.\n */\n options: Record<string, unknown>\n}\n\n/** How a command run ended, as the command reports it to the function {@link trackRun} returned. */\ntype RunResult = {\n status: 'success' | 'failed'\n plugins?: Array<TelemetryPlugin>\n filesCreated?: number\n /**\n * Name the MCP client sends in its `initialize` request, e.g. `'claude-code'`. Only set for `kubb mcp`.\n */\n mcpClient?: string\n}\n\n/**\n * Returns `true` when telemetry is disabled via `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY`.\n */\nexport function isDisabled(): boolean {\n return ['DO_NOT_TRACK', 'KUBB_DISABLE_TELEMETRY'].some((name) => ['1', 'true'].includes(process.env[name] ?? ''))\n}\n\n/** Tracks one command run for the running CLI version; returns the reporter the command calls once it knows how it ended. */\nexport function trackRun({ command, hrStart }: { command: TelemetryCommand; hrStart: [number, number] }): (result: RunResult) => Promise<void> {\n return (result) => sendTelemetry(buildOtlpPayload({ command, duration: Math.round(getElapsedMs(hrStart)), ...result }))\n}\n\n/**\n * The OTLP trace payload for one run: a span named after the command whose attributes are the\n * anonymous run facts. The attribute keys are the contract with otlp.kubb.dev.\n *\n * @see https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/\n */\nexport function buildOtlpPayload({\n command,\n duration,\n status,\n plugins = [],\n filesCreated = 0,\n mcpClient,\n}: RunResult & { command: TelemetryCommand; duration: number }) {\n const traceId = randomBytes(16).toString('hex')\n const spanId = randomBytes(8).toString('hex')\n const endTimeNs = BigInt(Date.now()) * 1_000_000n\n const startTimeNs = endTimeNs - BigInt(duration) * 1_000_000n\n const pluginNames = [...new Set(plugins.map((plugin) => plugin.name))].sort()\n const agent = getAgentProfile()\n\n const attributes = [\n { key: 'kubb.command', value: { stringValue: command } },\n { key: 'kubb.version', value: { stringValue: version } },\n { key: 'kubb.node_version', value: { stringValue: process.versions.node.split('.')[0] as string } },\n { key: 'kubb.runtime', value: { stringValue: runtime.name } },\n { key: 'kubb.runtime_version', value: { stringValue: runtime.version.split('.')[0] as string } },\n { key: 'kubb.platform', value: { stringValue: os.platform() } },\n { key: 'kubb.ci', value: { boolValue: isCIEnvironment() } },\n // A terminal on stdin means a person typed the command; agents, scripts, and CI pipe it.\n { key: 'kubb.tty', value: { boolValue: process.stdin.isTTY === true } },\n ...(agent.isAgent && agent.name ? [{ key: 'kubb.agent', value: { stringValue: agent.name } }] : []),\n // The client picks this name, so cap its length before it leaves the machine.\n ...(mcpClient ? [{ key: 'kubb.mcp_client', value: { stringValue: mcpClient.slice(0, 64) } }] : []),\n { key: 'kubb.files_created', value: { intValue: filesCreated } },\n { key: 'kubb.status', value: { stringValue: status } },\n {\n key: 'kubb.plugins',\n value: { arrayValue: { values: pluginNames.map((name) => ({ stringValue: name })) } },\n },\n ...pluginNames.map((name) => ({ key: `kubb.plugin.${name}`, value: { boolValue: true } })),\n {\n key: 'kubb.plugin_options',\n value: {\n arrayValue: {\n values: plugins.map((p) => ({\n kvlistValue: {\n values: [\n { key: 'name', value: { stringValue: p.name } },\n {\n key: 'options',\n value: {\n stringValue: JSON.stringify({\n ...p.options,\n usedEnumNames: undefined,\n }),\n },\n },\n ],\n },\n })),\n },\n },\n },\n ]\n\n return {\n resourceSpans: [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: 'kubb' } },\n { key: 'service.version', value: { stringValue: version } },\n { key: 'telemetry.sdk.language', value: { stringValue: 'nodejs' } },\n ],\n },\n scopeSpans: [\n {\n scope: { name: 'kubb-core', version },\n spans: [\n {\n traceId,\n spanId,\n name: command,\n kind: 1,\n startTimeUnixNano: String(startTimeNs),\n endTimeUnixNano: String(endTimeNs),\n attributes,\n status: {\n code: status === 'success' ? 1 : 2,\n },\n },\n ],\n },\n ],\n },\n ],\n }\n}\n\n/**\n * Send an OTLP payload to the Kubb endpoint. Respects `DO_NOT_TRACK` and\n * `KUBB_DISABLE_TELEMETRY`, and fails silently so telemetry never interrupts a run. No file\n * paths, OpenAPI specs, or secrets are sent.\n */\nexport async function sendTelemetry(payload: ReturnType<typeof buildOtlpPayload>): Promise<void> {\n if (isDisabled()) {\n return\n }\n\n try {\n await fetch(`${OTLP_ENDPOINT}/v1/traces`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Kubb-Telemetry-Version': '1',\n 'Kubb-Telemetry-Source': 'kubb-cli',\n },\n body: JSON.stringify(payload),\n // Short, since an unfinished request keeps the process alive after the run.\n signal: AbortSignal.timeout(1_000),\n })\n } catch (_e) {\n // Fail silently, telemetry must never break the run\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import "./rolldown-runtime-xo6NMXYd.js";
2
- import { o as prepareConnection } from "./run-KqdudiWQ.js";
2
+ import { o as prepareConnection } from "./run-DUwX6Icx.js";
3
3
  import { i as getProjectKubbHome } from "./credentials-osgjujE_.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { hash, randomBytes } from "node:crypto";
@@ -271,4 +271,4 @@ async function startWorker(options) {
271
271
  }
272
272
  export { stopWorker as a, startWorker as i, getWorkerStatus as n, serveWorker as r, getWorkerLogPath as t };
273
273
 
274
- //# sourceMappingURL=background-_dKcGjM7.js.map
274
+ //# sourceMappingURL=background-BJCuXYuB.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"background-_dKcGjM7.js","names":["connectSocket","delay"],"sources":["../src/runners/studio/background.ts"],"sourcesContent":["import { hash, randomBytes } from 'node:crypto'\nimport { readFile, rename, writeFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { connect as connectSocket, createServer } from 'node:net'\nimport path from 'node:path'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { Diagnostics } from '@kubb/core'\nimport { x } from 'tinyexec'\nimport { getProjectKubbHome } from './credentials.ts'\nimport { prepareConnection, type PreparedConnection, type StudioOptions, type WorkerState } from './run.ts'\n\nexport type WorkerRecord = {\n id: string\n pid: number\n port: number\n state: WorkerState\n /**\n * When the worker started, in epoch milliseconds. Absent in a record from an older CLI.\n */\n startedAt?: number\n}\nconst states: Array<WorkerState> = ['starting', 'connected', 'reconnecting', 'authentication required', 'stopped']\nexport const getWorkerLogPath = () => path.join(getProjectKubbHome(), 'worker.log')\nconst statePath = () => path.join(getProjectKubbHome(), 'worker.json')\n\nasync function readWorker(): Promise<WorkerRecord | null> {\n try {\n const value: unknown = JSON.parse(await readFile(statePath(), 'utf8'))\n if (!value || typeof value !== 'object') return null\n const record = value as Partial<WorkerRecord>\n return typeof record.id === 'string' &&\n /^[a-f0-9]{32}$/.test(record.id) &&\n Number.isInteger(record.pid) &&\n (record.pid ?? 0) > 1 &&\n Number.isInteger(record.port) &&\n (record.port ?? 0) > 0 &&\n (record.port ?? 0) <= 65535 &&\n states.includes(record.state as WorkerState)\n ? (record as WorkerRecord)\n : null\n } catch {\n return null\n }\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\n/** Authenticated loopback IPC; a stored PID never authorizes sending a process signal. */\nfunction requestWorker(record: WorkerRecord, command: 'status' | 'stop'): Promise<WorkerRecord> {\n return new Promise((resolve, reject) => {\n const socket = connectSocket({ host: '127.0.0.1', port: record.port })\n let received = ''\n socket.setTimeout(2_000, () => socket.destroy(new Error('Worker control timed out')))\n socket.once('error', reject)\n socket.once('connect', () => socket.write(JSON.stringify({ id: record.id, command }) + '\\n'))\n socket.on('data', (chunk: Buffer) => {\n received += chunk.toString()\n if (received.length > 4096) socket.destroy(new Error('Invalid worker response'))\n })\n socket.once('end', () => {\n try {\n const response = JSON.parse(received) as WorkerRecord\n if (response.id !== record.id || response.pid !== record.pid || !states.includes(response.state))\n throw new Diagnostics.Error({ code: Diagnostics.code.internalError, severity: 'error', message: 'Worker identity changed' })\n resolve(response)\n } catch (error) {\n reject(error)\n }\n })\n })\n}\n\nexport async function getWorkerStatus(): Promise<{ running: boolean; state: WorkerState; pid?: number; startedAt?: number }> {\n const record = await readWorker()\n if (!record) return { running: false, state: 'stopped' }\n try {\n const response = await requestWorker(record, 'status')\n return { running: true, state: response.state, pid: response.pid, startedAt: Number.isFinite(response.startedAt) ? response.startedAt : undefined }\n } catch {\n return { running: false, state: record.state === 'authentication required' ? record.state : 'stopped' }\n }\n}\n\nexport async function stopWorker(): Promise<void> {\n const record = await readWorker()\n if (!record) return\n try {\n await requestWorker(record, 'stop')\n } catch (error) {\n if (\n (error as NodeJS.ErrnoException).code !== 'ECONNREFUSED' &&\n isAlive(record.pid) &&\n record.state !== 'stopped' &&\n record.state !== 'authentication required'\n ) {\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Cannot verify the background worker. No process was signaled.',\n help: 'Check `worker.log`, then stop the process by hand if it is still running.',\n })\n }\n return\n }\n const deadline = Date.now() + 15_000\n while (Date.now() < deadline) {\n try {\n await requestWorker(record, 'status')\n } catch {\n return\n }\n await delay(100)\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The worker has not finished shutting down. Check worker.log and try again.',\n })\n}\n\n/** The listening port is the project lock, so stale state never needs a PID-based takeover. */\nexport async function serveWorker(shutdown: AbortController) {\n const record: WorkerRecord = { id: randomBytes(16).toString('hex'), pid: process.pid, port: 0, state: 'starting', startedAt: Date.now() }\n const server = createServer((socket) => {\n let input = ''\n socket.setTimeout(2_000, () => socket.destroy())\n socket.on('error', () => {})\n socket.on('data', (chunk: Buffer) => {\n input += chunk.toString()\n if (input.length > 4096) {\n socket.destroy()\n return\n }\n if (!input.includes('\\n')) return\n try {\n const request = JSON.parse(input) as { id?: unknown; command?: unknown }\n if (request.id !== record.id || !['status', 'stop'].includes(String(request.command))) {\n socket.destroy()\n return\n }\n socket.end(JSON.stringify(record))\n if (request.command === 'stop') shutdown.abort()\n } catch {\n socket.destroy()\n }\n })\n })\n // Hash the project directory to choose its loopback port; fail on collisions.\n const port = 20_000 + (Number.parseInt(hash('sha256', getProjectKubbHome()).slice(0, 8), 16) % 30_000)\n try {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, '127.0.0.1', resolve)\n })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EADDRINUSE') throw error\n // Let a simultaneous starter finish writing its record before checking ownership.\n await delay(100)\n const existing = await readWorker()\n if (existing?.port === port) {\n try {\n return { existing: await requestWorker(existing, 'status') }\n } catch {\n /* Refuse an unverified listener. */\n }\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The project control port is occupied or another worker is starting. Try again after stopping that listener.',\n })\n }\n record.port = port\n let saving = Promise.resolve()\n const save = () => {\n const value = JSON.stringify(record)\n saving = saving.then(async () => {\n const temporary = `${statePath()}.${record.id}`\n await writeFile(temporary, value, { mode: 0o600 })\n await rename(temporary, statePath())\n })\n return saving\n }\n try {\n await save()\n } catch (error) {\n server.close()\n throw error\n }\n return {\n async state(state: WorkerState) {\n record.state = state\n await save()\n },\n async close() {\n try {\n if (record.state !== 'authentication required') {\n record.state = 'stopped'\n await save()\n }\n } finally {\n await new Promise<void>((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())))\n }\n },\n }\n}\n\nexport type WorkerLaunch = { options: StudioOptions; prepared: PreparedConnection }\n\nexport async function startWorker(options: StudioOptions): Promise<void> {\n const current = await getWorkerStatus()\n if (current.running) {\n console.log(`Already running (${current.state}, PID ${current.pid}).`)\n return\n }\n const prepared = await prepareConnection(options)\n const entry = path.join(path.dirname(createRequire(import.meta.url).resolve('@kubb/cli/package.json')), 'dist', 'studioWorker.js')\n const child = x(process.execPath, [...process.execArgv, entry], {\n nodeOptions: { cwd: process.cwd(), detached: true, stdio: ['ignore', 'ignore', 'ignore', 'ipc'] },\n }).process\n if (!child)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Background worker failed to start',\n help: 'Run `kubb studio` in the foreground to see why it fails.',\n })\n try {\n const started = new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => done(new Error('Background worker startup timed out')), 20_000)\n const done = (error?: Error) => {\n clearTimeout(timer)\n child.removeListener('error', failed)\n child.removeListener('exit', exited)\n child.removeListener('message', ready)\n if (error) reject(error)\n else resolve()\n }\n const failed = (error: Error) => done(error)\n const exited = () => done(new Error(`Background worker exited during startup. Check ${getWorkerLogPath()}`))\n child.once('error', failed)\n child.once('exit', exited)\n const ready = (message: unknown) => {\n if (!message || typeof message !== 'object' || !('started' in message) || message.started !== true)\n return done(new Error('Invalid worker startup response'))\n done()\n }\n child.once('message', ready)\n child.send({ options: { ...options, autoOpen: false }, prepared } satisfies WorkerLaunch, (error) => {\n if (error) done(error)\n })\n })\n await started\n if (child.connected) child.disconnect()\n child.unref()\n const status = await getWorkerStatus()\n console.log(`Background worker ${status.state} (PID ${status.pid ?? child.pid}). Logs: ${getWorkerLogPath()}`)\n } catch (error) {\n // This is the child we just spawned, not a PID recovered from disk.\n child.kill('SIGTERM')\n throw error\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"background-BJCuXYuB.js","names":["connectSocket","delay"],"sources":["../src/runners/studio/background.ts"],"sourcesContent":["import { hash, randomBytes } from 'node:crypto'\nimport { readFile, rename, writeFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { connect as connectSocket, createServer } from 'node:net'\nimport path from 'node:path'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { Diagnostics } from '@kubb/core'\nimport { x } from 'tinyexec'\nimport { getProjectKubbHome } from './credentials.ts'\nimport { prepareConnection, type PreparedConnection, type StudioOptions, type WorkerState } from './run.ts'\n\nexport type WorkerRecord = {\n id: string\n pid: number\n port: number\n state: WorkerState\n /**\n * When the worker started, in epoch milliseconds. Absent in a record from an older CLI.\n */\n startedAt?: number\n}\nconst states: Array<WorkerState> = ['starting', 'connected', 'reconnecting', 'authentication required', 'stopped']\nexport const getWorkerLogPath = () => path.join(getProjectKubbHome(), 'worker.log')\nconst statePath = () => path.join(getProjectKubbHome(), 'worker.json')\n\nasync function readWorker(): Promise<WorkerRecord | null> {\n try {\n const value: unknown = JSON.parse(await readFile(statePath(), 'utf8'))\n if (!value || typeof value !== 'object') return null\n const record = value as Partial<WorkerRecord>\n return typeof record.id === 'string' &&\n /^[a-f0-9]{32}$/.test(record.id) &&\n Number.isInteger(record.pid) &&\n (record.pid ?? 0) > 1 &&\n Number.isInteger(record.port) &&\n (record.port ?? 0) > 0 &&\n (record.port ?? 0) <= 65535 &&\n states.includes(record.state as WorkerState)\n ? (record as WorkerRecord)\n : null\n } catch {\n return null\n }\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\n/** Authenticated loopback IPC; a stored PID never authorizes sending a process signal. */\nfunction requestWorker(record: WorkerRecord, command: 'status' | 'stop'): Promise<WorkerRecord> {\n return new Promise((resolve, reject) => {\n const socket = connectSocket({ host: '127.0.0.1', port: record.port })\n let received = ''\n socket.setTimeout(2_000, () => socket.destroy(new Error('Worker control timed out')))\n socket.once('error', reject)\n socket.once('connect', () => socket.write(JSON.stringify({ id: record.id, command }) + '\\n'))\n socket.on('data', (chunk: Buffer) => {\n received += chunk.toString()\n if (received.length > 4096) socket.destroy(new Error('Invalid worker response'))\n })\n socket.once('end', () => {\n try {\n const response = JSON.parse(received) as WorkerRecord\n if (response.id !== record.id || response.pid !== record.pid || !states.includes(response.state))\n throw new Diagnostics.Error({ code: Diagnostics.code.internalError, severity: 'error', message: 'Worker identity changed' })\n resolve(response)\n } catch (error) {\n reject(error)\n }\n })\n })\n}\n\nexport async function getWorkerStatus(): Promise<{ running: boolean; state: WorkerState; pid?: number; startedAt?: number }> {\n const record = await readWorker()\n if (!record) return { running: false, state: 'stopped' }\n try {\n const response = await requestWorker(record, 'status')\n return { running: true, state: response.state, pid: response.pid, startedAt: Number.isFinite(response.startedAt) ? response.startedAt : undefined }\n } catch {\n return { running: false, state: record.state === 'authentication required' ? record.state : 'stopped' }\n }\n}\n\nexport async function stopWorker(): Promise<void> {\n const record = await readWorker()\n if (!record) return\n try {\n await requestWorker(record, 'stop')\n } catch (error) {\n if (\n (error as NodeJS.ErrnoException).code !== 'ECONNREFUSED' &&\n isAlive(record.pid) &&\n record.state !== 'stopped' &&\n record.state !== 'authentication required'\n ) {\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Cannot verify the background worker. No process was signaled.',\n help: 'Check `worker.log`, then stop the process by hand if it is still running.',\n })\n }\n return\n }\n const deadline = Date.now() + 15_000\n while (Date.now() < deadline) {\n try {\n await requestWorker(record, 'status')\n } catch {\n return\n }\n await delay(100)\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The worker has not finished shutting down. Check worker.log and try again.',\n })\n}\n\n/** The listening port is the project lock, so stale state never needs a PID-based takeover. */\nexport async function serveWorker(shutdown: AbortController) {\n const record: WorkerRecord = { id: randomBytes(16).toString('hex'), pid: process.pid, port: 0, state: 'starting', startedAt: Date.now() }\n const server = createServer((socket) => {\n let input = ''\n socket.setTimeout(2_000, () => socket.destroy())\n socket.on('error', () => {})\n socket.on('data', (chunk: Buffer) => {\n input += chunk.toString()\n if (input.length > 4096) {\n socket.destroy()\n return\n }\n if (!input.includes('\\n')) return\n try {\n const request = JSON.parse(input) as { id?: unknown; command?: unknown }\n if (request.id !== record.id || !['status', 'stop'].includes(String(request.command))) {\n socket.destroy()\n return\n }\n socket.end(JSON.stringify(record))\n if (request.command === 'stop') shutdown.abort()\n } catch {\n socket.destroy()\n }\n })\n })\n // Hash the project directory to choose its loopback port; fail on collisions.\n const port = 20_000 + (Number.parseInt(hash('sha256', getProjectKubbHome()).slice(0, 8), 16) % 30_000)\n try {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, '127.0.0.1', resolve)\n })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EADDRINUSE') throw error\n // Let a simultaneous starter finish writing its record before checking ownership.\n await delay(100)\n const existing = await readWorker()\n if (existing?.port === port) {\n try {\n return { existing: await requestWorker(existing, 'status') }\n } catch {\n /* Refuse an unverified listener. */\n }\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The project control port is occupied or another worker is starting. Try again after stopping that listener.',\n })\n }\n record.port = port\n let saving = Promise.resolve()\n const save = () => {\n const value = JSON.stringify(record)\n saving = saving.then(async () => {\n const temporary = `${statePath()}.${record.id}`\n await writeFile(temporary, value, { mode: 0o600 })\n await rename(temporary, statePath())\n })\n return saving\n }\n try {\n await save()\n } catch (error) {\n server.close()\n throw error\n }\n return {\n async state(state: WorkerState) {\n record.state = state\n await save()\n },\n async close() {\n try {\n if (record.state !== 'authentication required') {\n record.state = 'stopped'\n await save()\n }\n } finally {\n await new Promise<void>((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())))\n }\n },\n }\n}\n\nexport type WorkerLaunch = { options: StudioOptions; prepared: PreparedConnection }\n\nexport async function startWorker(options: StudioOptions): Promise<void> {\n const current = await getWorkerStatus()\n if (current.running) {\n console.log(`Already running (${current.state}, PID ${current.pid}).`)\n return\n }\n const prepared = await prepareConnection(options)\n const entry = path.join(path.dirname(createRequire(import.meta.url).resolve('@kubb/cli/package.json')), 'dist', 'studioWorker.js')\n const child = x(process.execPath, [...process.execArgv, entry], {\n nodeOptions: { cwd: process.cwd(), detached: true, stdio: ['ignore', 'ignore', 'ignore', 'ipc'] },\n }).process\n if (!child)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Background worker failed to start',\n help: 'Run `kubb studio` in the foreground to see why it fails.',\n })\n try {\n const started = new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => done(new Error('Background worker startup timed out')), 20_000)\n const done = (error?: Error) => {\n clearTimeout(timer)\n child.removeListener('error', failed)\n child.removeListener('exit', exited)\n child.removeListener('message', ready)\n if (error) reject(error)\n else resolve()\n }\n const failed = (error: Error) => done(error)\n const exited = () => done(new Error(`Background worker exited during startup. Check ${getWorkerLogPath()}`))\n child.once('error', failed)\n child.once('exit', exited)\n const ready = (message: unknown) => {\n if (!message || typeof message !== 'object' || !('started' in message) || message.started !== true)\n return done(new Error('Invalid worker startup response'))\n done()\n }\n child.once('message', ready)\n child.send({ options: { ...options, autoOpen: false }, prepared } satisfies WorkerLaunch, (error) => {\n if (error) done(error)\n })\n })\n await started\n if (child.connected) child.disconnect()\n child.unref()\n const status = await getWorkerStatus()\n console.log(`Background worker ${status.state} (PID ${status.pid ?? child.pid}). Logs: ${getWorkerLogPath()}`)\n } catch (error) {\n // This is the child we just spawned, not a PID recovered from disk.\n child.kill('SIGTERM')\n throw error\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C3-Zg-KD.cjs");
2
2
  const require_credentials = require("./credentials-DEsGwcGD.cjs");
3
- const require_run = require("./run-Bb19PlwV.cjs");
3
+ const require_run = require("./run-CQORv7Gq.cjs");
4
4
  require("node:crypto");
5
5
  let tinyexec = require("tinyexec");
6
6
  let node_fs_promises = require("node:fs/promises");
@@ -189,4 +189,4 @@ exports.getWorkerStatus = getWorkerStatus;
189
189
  exports.startWorker = startWorker;
190
190
  exports.stopWorker = stopWorker;
191
191
 
192
- //# sourceMappingURL=background-B24lIehn.cjs.map
192
+ //# sourceMappingURL=background-CK2gQtTU.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"background-B24lIehn.cjs","names":["path","getProjectKubbHome","readFile","connectSocket","Diagnostics","delay","prepareConnection","createRequire","x"],"sources":["../src/runners/studio/background.ts"],"sourcesContent":["import { hash, randomBytes } from 'node:crypto'\nimport { readFile, rename, writeFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { connect as connectSocket, createServer } from 'node:net'\nimport path from 'node:path'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { Diagnostics } from '@kubb/core'\nimport { x } from 'tinyexec'\nimport { getProjectKubbHome } from './credentials.ts'\nimport { prepareConnection, type PreparedConnection, type StudioOptions, type WorkerState } from './run.ts'\n\nexport type WorkerRecord = {\n id: string\n pid: number\n port: number\n state: WorkerState\n /**\n * When the worker started, in epoch milliseconds. Absent in a record from an older CLI.\n */\n startedAt?: number\n}\nconst states: Array<WorkerState> = ['starting', 'connected', 'reconnecting', 'authentication required', 'stopped']\nexport const getWorkerLogPath = () => path.join(getProjectKubbHome(), 'worker.log')\nconst statePath = () => path.join(getProjectKubbHome(), 'worker.json')\n\nasync function readWorker(): Promise<WorkerRecord | null> {\n try {\n const value: unknown = JSON.parse(await readFile(statePath(), 'utf8'))\n if (!value || typeof value !== 'object') return null\n const record = value as Partial<WorkerRecord>\n return typeof record.id === 'string' &&\n /^[a-f0-9]{32}$/.test(record.id) &&\n Number.isInteger(record.pid) &&\n (record.pid ?? 0) > 1 &&\n Number.isInteger(record.port) &&\n (record.port ?? 0) > 0 &&\n (record.port ?? 0) <= 65535 &&\n states.includes(record.state as WorkerState)\n ? (record as WorkerRecord)\n : null\n } catch {\n return null\n }\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\n/** Authenticated loopback IPC; a stored PID never authorizes sending a process signal. */\nfunction requestWorker(record: WorkerRecord, command: 'status' | 'stop'): Promise<WorkerRecord> {\n return new Promise((resolve, reject) => {\n const socket = connectSocket({ host: '127.0.0.1', port: record.port })\n let received = ''\n socket.setTimeout(2_000, () => socket.destroy(new Error('Worker control timed out')))\n socket.once('error', reject)\n socket.once('connect', () => socket.write(JSON.stringify({ id: record.id, command }) + '\\n'))\n socket.on('data', (chunk: Buffer) => {\n received += chunk.toString()\n if (received.length > 4096) socket.destroy(new Error('Invalid worker response'))\n })\n socket.once('end', () => {\n try {\n const response = JSON.parse(received) as WorkerRecord\n if (response.id !== record.id || response.pid !== record.pid || !states.includes(response.state))\n throw new Diagnostics.Error({ code: Diagnostics.code.internalError, severity: 'error', message: 'Worker identity changed' })\n resolve(response)\n } catch (error) {\n reject(error)\n }\n })\n })\n}\n\nexport async function getWorkerStatus(): Promise<{ running: boolean; state: WorkerState; pid?: number; startedAt?: number }> {\n const record = await readWorker()\n if (!record) return { running: false, state: 'stopped' }\n try {\n const response = await requestWorker(record, 'status')\n return { running: true, state: response.state, pid: response.pid, startedAt: Number.isFinite(response.startedAt) ? response.startedAt : undefined }\n } catch {\n return { running: false, state: record.state === 'authentication required' ? record.state : 'stopped' }\n }\n}\n\nexport async function stopWorker(): Promise<void> {\n const record = await readWorker()\n if (!record) return\n try {\n await requestWorker(record, 'stop')\n } catch (error) {\n if (\n (error as NodeJS.ErrnoException).code !== 'ECONNREFUSED' &&\n isAlive(record.pid) &&\n record.state !== 'stopped' &&\n record.state !== 'authentication required'\n ) {\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Cannot verify the background worker. No process was signaled.',\n help: 'Check `worker.log`, then stop the process by hand if it is still running.',\n })\n }\n return\n }\n const deadline = Date.now() + 15_000\n while (Date.now() < deadline) {\n try {\n await requestWorker(record, 'status')\n } catch {\n return\n }\n await delay(100)\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The worker has not finished shutting down. Check worker.log and try again.',\n })\n}\n\n/** The listening port is the project lock, so stale state never needs a PID-based takeover. */\nexport async function serveWorker(shutdown: AbortController) {\n const record: WorkerRecord = { id: randomBytes(16).toString('hex'), pid: process.pid, port: 0, state: 'starting', startedAt: Date.now() }\n const server = createServer((socket) => {\n let input = ''\n socket.setTimeout(2_000, () => socket.destroy())\n socket.on('error', () => {})\n socket.on('data', (chunk: Buffer) => {\n input += chunk.toString()\n if (input.length > 4096) {\n socket.destroy()\n return\n }\n if (!input.includes('\\n')) return\n try {\n const request = JSON.parse(input) as { id?: unknown; command?: unknown }\n if (request.id !== record.id || !['status', 'stop'].includes(String(request.command))) {\n socket.destroy()\n return\n }\n socket.end(JSON.stringify(record))\n if (request.command === 'stop') shutdown.abort()\n } catch {\n socket.destroy()\n }\n })\n })\n // Hash the project directory to choose its loopback port; fail on collisions.\n const port = 20_000 + (Number.parseInt(hash('sha256', getProjectKubbHome()).slice(0, 8), 16) % 30_000)\n try {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, '127.0.0.1', resolve)\n })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EADDRINUSE') throw error\n // Let a simultaneous starter finish writing its record before checking ownership.\n await delay(100)\n const existing = await readWorker()\n if (existing?.port === port) {\n try {\n return { existing: await requestWorker(existing, 'status') }\n } catch {\n /* Refuse an unverified listener. */\n }\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The project control port is occupied or another worker is starting. Try again after stopping that listener.',\n })\n }\n record.port = port\n let saving = Promise.resolve()\n const save = () => {\n const value = JSON.stringify(record)\n saving = saving.then(async () => {\n const temporary = `${statePath()}.${record.id}`\n await writeFile(temporary, value, { mode: 0o600 })\n await rename(temporary, statePath())\n })\n return saving\n }\n try {\n await save()\n } catch (error) {\n server.close()\n throw error\n }\n return {\n async state(state: WorkerState) {\n record.state = state\n await save()\n },\n async close() {\n try {\n if (record.state !== 'authentication required') {\n record.state = 'stopped'\n await save()\n }\n } finally {\n await new Promise<void>((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())))\n }\n },\n }\n}\n\nexport type WorkerLaunch = { options: StudioOptions; prepared: PreparedConnection }\n\nexport async function startWorker(options: StudioOptions): Promise<void> {\n const current = await getWorkerStatus()\n if (current.running) {\n console.log(`Already running (${current.state}, PID ${current.pid}).`)\n return\n }\n const prepared = await prepareConnection(options)\n const entry = path.join(path.dirname(createRequire(import.meta.url).resolve('@kubb/cli/package.json')), 'dist', 'studioWorker.js')\n const child = x(process.execPath, [...process.execArgv, entry], {\n nodeOptions: { cwd: process.cwd(), detached: true, stdio: ['ignore', 'ignore', 'ignore', 'ipc'] },\n }).process\n if (!child)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Background worker failed to start',\n help: 'Run `kubb studio` in the foreground to see why it fails.',\n })\n try {\n const started = new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => done(new Error('Background worker startup timed out')), 20_000)\n const done = (error?: Error) => {\n clearTimeout(timer)\n child.removeListener('error', failed)\n child.removeListener('exit', exited)\n child.removeListener('message', ready)\n if (error) reject(error)\n else resolve()\n }\n const failed = (error: Error) => done(error)\n const exited = () => done(new Error(`Background worker exited during startup. Check ${getWorkerLogPath()}`))\n child.once('error', failed)\n child.once('exit', exited)\n const ready = (message: unknown) => {\n if (!message || typeof message !== 'object' || !('started' in message) || message.started !== true)\n return done(new Error('Invalid worker startup response'))\n done()\n }\n child.once('message', ready)\n child.send({ options: { ...options, autoOpen: false }, prepared } satisfies WorkerLaunch, (error) => {\n if (error) done(error)\n })\n })\n await started\n if (child.connected) child.disconnect()\n child.unref()\n const status = await getWorkerStatus()\n console.log(`Background worker ${status.state} (PID ${status.pid ?? child.pid}). Logs: ${getWorkerLogPath()}`)\n } catch (error) {\n // This is the child we just spawned, not a PID recovered from disk.\n child.kill('SIGTERM')\n throw error\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"background-CK2gQtTU.cjs","names":["path","getProjectKubbHome","readFile","connectSocket","Diagnostics","delay","prepareConnection","createRequire","x"],"sources":["../src/runners/studio/background.ts"],"sourcesContent":["import { hash, randomBytes } from 'node:crypto'\nimport { readFile, rename, writeFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { connect as connectSocket, createServer } from 'node:net'\nimport path from 'node:path'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { Diagnostics } from '@kubb/core'\nimport { x } from 'tinyexec'\nimport { getProjectKubbHome } from './credentials.ts'\nimport { prepareConnection, type PreparedConnection, type StudioOptions, type WorkerState } from './run.ts'\n\nexport type WorkerRecord = {\n id: string\n pid: number\n port: number\n state: WorkerState\n /**\n * When the worker started, in epoch milliseconds. Absent in a record from an older CLI.\n */\n startedAt?: number\n}\nconst states: Array<WorkerState> = ['starting', 'connected', 'reconnecting', 'authentication required', 'stopped']\nexport const getWorkerLogPath = () => path.join(getProjectKubbHome(), 'worker.log')\nconst statePath = () => path.join(getProjectKubbHome(), 'worker.json')\n\nasync function readWorker(): Promise<WorkerRecord | null> {\n try {\n const value: unknown = JSON.parse(await readFile(statePath(), 'utf8'))\n if (!value || typeof value !== 'object') return null\n const record = value as Partial<WorkerRecord>\n return typeof record.id === 'string' &&\n /^[a-f0-9]{32}$/.test(record.id) &&\n Number.isInteger(record.pid) &&\n (record.pid ?? 0) > 1 &&\n Number.isInteger(record.port) &&\n (record.port ?? 0) > 0 &&\n (record.port ?? 0) <= 65535 &&\n states.includes(record.state as WorkerState)\n ? (record as WorkerRecord)\n : null\n } catch {\n return null\n }\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\n/** Authenticated loopback IPC; a stored PID never authorizes sending a process signal. */\nfunction requestWorker(record: WorkerRecord, command: 'status' | 'stop'): Promise<WorkerRecord> {\n return new Promise((resolve, reject) => {\n const socket = connectSocket({ host: '127.0.0.1', port: record.port })\n let received = ''\n socket.setTimeout(2_000, () => socket.destroy(new Error('Worker control timed out')))\n socket.once('error', reject)\n socket.once('connect', () => socket.write(JSON.stringify({ id: record.id, command }) + '\\n'))\n socket.on('data', (chunk: Buffer) => {\n received += chunk.toString()\n if (received.length > 4096) socket.destroy(new Error('Invalid worker response'))\n })\n socket.once('end', () => {\n try {\n const response = JSON.parse(received) as WorkerRecord\n if (response.id !== record.id || response.pid !== record.pid || !states.includes(response.state))\n throw new Diagnostics.Error({ code: Diagnostics.code.internalError, severity: 'error', message: 'Worker identity changed' })\n resolve(response)\n } catch (error) {\n reject(error)\n }\n })\n })\n}\n\nexport async function getWorkerStatus(): Promise<{ running: boolean; state: WorkerState; pid?: number; startedAt?: number }> {\n const record = await readWorker()\n if (!record) return { running: false, state: 'stopped' }\n try {\n const response = await requestWorker(record, 'status')\n return { running: true, state: response.state, pid: response.pid, startedAt: Number.isFinite(response.startedAt) ? response.startedAt : undefined }\n } catch {\n return { running: false, state: record.state === 'authentication required' ? record.state : 'stopped' }\n }\n}\n\nexport async function stopWorker(): Promise<void> {\n const record = await readWorker()\n if (!record) return\n try {\n await requestWorker(record, 'stop')\n } catch (error) {\n if (\n (error as NodeJS.ErrnoException).code !== 'ECONNREFUSED' &&\n isAlive(record.pid) &&\n record.state !== 'stopped' &&\n record.state !== 'authentication required'\n ) {\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Cannot verify the background worker. No process was signaled.',\n help: 'Check `worker.log`, then stop the process by hand if it is still running.',\n })\n }\n return\n }\n const deadline = Date.now() + 15_000\n while (Date.now() < deadline) {\n try {\n await requestWorker(record, 'status')\n } catch {\n return\n }\n await delay(100)\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The worker has not finished shutting down. Check worker.log and try again.',\n })\n}\n\n/** The listening port is the project lock, so stale state never needs a PID-based takeover. */\nexport async function serveWorker(shutdown: AbortController) {\n const record: WorkerRecord = { id: randomBytes(16).toString('hex'), pid: process.pid, port: 0, state: 'starting', startedAt: Date.now() }\n const server = createServer((socket) => {\n let input = ''\n socket.setTimeout(2_000, () => socket.destroy())\n socket.on('error', () => {})\n socket.on('data', (chunk: Buffer) => {\n input += chunk.toString()\n if (input.length > 4096) {\n socket.destroy()\n return\n }\n if (!input.includes('\\n')) return\n try {\n const request = JSON.parse(input) as { id?: unknown; command?: unknown }\n if (request.id !== record.id || !['status', 'stop'].includes(String(request.command))) {\n socket.destroy()\n return\n }\n socket.end(JSON.stringify(record))\n if (request.command === 'stop') shutdown.abort()\n } catch {\n socket.destroy()\n }\n })\n })\n // Hash the project directory to choose its loopback port; fail on collisions.\n const port = 20_000 + (Number.parseInt(hash('sha256', getProjectKubbHome()).slice(0, 8), 16) % 30_000)\n try {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, '127.0.0.1', resolve)\n })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EADDRINUSE') throw error\n // Let a simultaneous starter finish writing its record before checking ownership.\n await delay(100)\n const existing = await readWorker()\n if (existing?.port === port) {\n try {\n return { existing: await requestWorker(existing, 'status') }\n } catch {\n /* Refuse an unverified listener. */\n }\n }\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The project control port is occupied or another worker is starting. Try again after stopping that listener.',\n })\n }\n record.port = port\n let saving = Promise.resolve()\n const save = () => {\n const value = JSON.stringify(record)\n saving = saving.then(async () => {\n const temporary = `${statePath()}.${record.id}`\n await writeFile(temporary, value, { mode: 0o600 })\n await rename(temporary, statePath())\n })\n return saving\n }\n try {\n await save()\n } catch (error) {\n server.close()\n throw error\n }\n return {\n async state(state: WorkerState) {\n record.state = state\n await save()\n },\n async close() {\n try {\n if (record.state !== 'authentication required') {\n record.state = 'stopped'\n await save()\n }\n } finally {\n await new Promise<void>((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())))\n }\n },\n }\n}\n\nexport type WorkerLaunch = { options: StudioOptions; prepared: PreparedConnection }\n\nexport async function startWorker(options: StudioOptions): Promise<void> {\n const current = await getWorkerStatus()\n if (current.running) {\n console.log(`Already running (${current.state}, PID ${current.pid}).`)\n return\n }\n const prepared = await prepareConnection(options)\n const entry = path.join(path.dirname(createRequire(import.meta.url).resolve('@kubb/cli/package.json')), 'dist', 'studioWorker.js')\n const child = x(process.execPath, [...process.execArgv, entry], {\n nodeOptions: { cwd: process.cwd(), detached: true, stdio: ['ignore', 'ignore', 'ignore', 'ipc'] },\n }).process\n if (!child)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Background worker failed to start',\n help: 'Run `kubb studio` in the foreground to see why it fails.',\n })\n try {\n const started = new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => done(new Error('Background worker startup timed out')), 20_000)\n const done = (error?: Error) => {\n clearTimeout(timer)\n child.removeListener('error', failed)\n child.removeListener('exit', exited)\n child.removeListener('message', ready)\n if (error) reject(error)\n else resolve()\n }\n const failed = (error: Error) => done(error)\n const exited = () => done(new Error(`Background worker exited during startup. Check ${getWorkerLogPath()}`))\n child.once('error', failed)\n child.once('exit', exited)\n const ready = (message: unknown) => {\n if (!message || typeof message !== 'object' || !('started' in message) || message.started !== true)\n return done(new Error('Invalid worker startup response'))\n done()\n }\n child.once('message', ready)\n child.send({ options: { ...options, autoOpen: false }, prepared } satisfies WorkerLaunch, (error) => {\n if (error) done(error)\n })\n })\n await started\n if (child.connected) child.disconnect()\n child.unref()\n const status = await getWorkerStatus()\n console.log(`Background worker ${status.state} (PID ${status.pid ?? child.pid}). Logs: ${getWorkerLogPath()}`)\n } catch (error) {\n // This is the child we just spawned, not a PID recovered from disk.\n child.kill('SIGTERM')\n throw error\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- export { t as getWorkerLogPath, n as getWorkerStatus, i as startWorker, a as stopWorker } from "./background-_dKcGjM7.js";
1
+ export { t as getWorkerLogPath, n as getWorkerStatus, i as startWorker, a as stopWorker } from "./background-BJCuXYuB.js";
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./rolldown-runtime-C3-Zg-KD.cjs");
3
- const require_package = require("./package-aX0q9SZr.cjs");
4
- const require_Telemetry = require("./Telemetry-COWGqYmh.cjs");
3
+ const require_package = require("./package-B1hUUjio.cjs");
4
+ const require_Telemetry = require("./Telemetry-B52pKz9i.cjs");
5
5
  const require_mascot = require("./mascot-JSA0j3Q_.cjs");
6
6
  const require_shared = require("./shared-C0EtrdUm.cjs");
7
7
  let node_util = require("node:util");
@@ -88,7 +88,7 @@ const command = (0, gunshi.defineWithTypes)()({
88
88
  async run(ctx) {
89
89
  const { values } = ctx;
90
90
  const logLevel = resolveLogLevel(values);
91
- const { run } = await Promise.resolve().then(() => require("./run-BoO7H8RA.cjs"));
91
+ const { run } = await Promise.resolve().then(() => require("./run-CyzKy-0p.cjs"));
92
92
  await run({
93
93
  input: values.input,
94
94
  configPath: values.config,
@@ -134,12 +134,12 @@ function resolveDeprecatedFlags(args) {
134
134
  // src/index.ts
135
135
  /** The subcommands besides `generate`, imported only when the run needs them, so `kubb generate` never loads their code. */
136
136
  const commandLoaders = {
137
- init: () => Promise.resolve().then(() => require("./run-DgGZOC_x.cjs")),
138
- validate: () => Promise.resolve().then(() => require("./validate-CMSeDpGT.cjs")),
139
- mcp: () => Promise.resolve().then(() => require("./mcp-CYPOFKnP.cjs")),
140
- studio: () => Promise.resolve().then(() => require("./studio-BpYwgFb0.cjs")),
137
+ init: () => Promise.resolve().then(() => require("./run-DBnSbwtU.cjs")),
138
+ validate: () => Promise.resolve().then(() => require("./validate-B3tLWYJU.cjs")),
139
+ mcp: () => Promise.resolve().then(() => require("./mcp-CcseJJwh.cjs")),
140
+ studio: () => Promise.resolve().then(() => require("./studio-D9_-mKee.cjs")),
141
141
  add: () => Promise.resolve().then(() => require("./run-BYP_t9dR.cjs")),
142
- update: () => Promise.resolve().then(() => require("./run-B4zvF9WY.cjs")),
142
+ update: () => Promise.resolve().then(() => require("./run-LY_UAYyM.cjs")),
143
143
  remove: () => Promise.resolve().then(() => require("./run-CvFakE3B.cjs")),
144
144
  list: () => Promise.resolve().then(() => require("./run-CrM4jsix.cjs"))
145
145
  };
@@ -164,7 +164,7 @@ async function run(argv = process.argv.slice(2)) {
164
164
  if (Object.hasOwn(commandLoaders, name)) names = [name];
165
165
  if (!names.length && resolvedArgs.some((arg) => HELP_FLAGS.has(arg))) names = Object.keys(commandLoaders);
166
166
  const modules = Object.fromEntries(await Promise.all(names.map(async (key) => [key, await commandLoaders[key]()])));
167
- const args = name === "studio" ? (await Promise.resolve().then(() => require("./studio-BpYwgFb0.cjs"))).routeStudioFlags(resolvedArgs) : resolvedArgs;
167
+ const args = name === "studio" ? (await Promise.resolve().then(() => require("./studio-D9_-mKee.cjs"))).routeStudioFlags(resolvedArgs) : resolvedArgs;
168
168
  const isQuietFlag = args.some((arg) => QUIET_FLAGS.has(arg));
169
169
  const isJsonOutput = args.includes("--json") || args.some((arg, index) => /^--reporter=.*\bjson\b/.test(arg) || arg === "--reporter" && /\bjson\b/.test(args[index + 1] ?? ""));
170
170
  if (!require_Telemetry.isDisabled() && !isQuietFlag) console.error(`${(0, node_util.styleText)("yellow", "Notice:")} Kubb collects anonymous telemetry data to help improve the tool. No personal data or file contents are collected. \nTo disable, set ${(0, node_util.styleText)("cyan", "KUBB_DISABLE_TELEMETRY=1")}.\n`);
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./rolldown-runtime-xo6NMXYd.js";
2
- import { t as version } from "./package-D3Yss9Bb.js";
3
- import { t as isDisabled } from "./Telemetry-B3edcFoB.js";
2
+ import { t as version } from "./package-MYPMnnTX.js";
3
+ import { t as isDisabled } from "./Telemetry-C7Qwy2s7.js";
4
4
  import { r as wantsMascot, t as getBanner } from "./mascot--q1xjKw1.js";
5
5
  import { n as dryRunId, r as logLevelArg, t as configArg } from "./shared-Ct9stKpp.js";
6
6
  import { styleText } from "node:util";
@@ -86,7 +86,7 @@ const command = defineWithTypes()({
86
86
  async run(ctx) {
87
87
  const { values } = ctx;
88
88
  const logLevel = resolveLogLevel(values);
89
- const { run } = await import("./run-CbX6tpqB.js");
89
+ const { run } = await import("./run-CXVhxFfC.js");
90
90
  await run({
91
91
  input: values.input,
92
92
  configPath: values.config,
@@ -132,12 +132,12 @@ function resolveDeprecatedFlags(args) {
132
132
  // src/index.ts
133
133
  /** The subcommands besides `generate`, imported only when the run needs them, so `kubb generate` never loads their code. */
134
134
  const commandLoaders = {
135
- init: () => import("./run-CCsdLz3X.js"),
136
- validate: () => import("./validate-8ZcWXfMt.js"),
137
- mcp: () => import("./mcp-CxeZR5vb.js"),
138
- studio: () => import("./studio-mw6HaPkr.js"),
135
+ init: () => import("./run-FEiyv6_U.js"),
136
+ validate: () => import("./validate-C5fyNF4v.js"),
137
+ mcp: () => import("./mcp-DUTsS8tR.js"),
138
+ studio: () => import("./studio-B4XsXgKj.js"),
139
139
  add: () => import("./run-D-nn9-Wq.js"),
140
- update: () => import("./run-RN_31Q4u.js"),
140
+ update: () => import("./run-BsrNfFIl.js"),
141
141
  remove: () => import("./run-BrM7-NSV.js"),
142
142
  list: () => import("./run-1H9TGT8v.js")
143
143
  };
@@ -162,7 +162,7 @@ async function run(argv = process.argv.slice(2)) {
162
162
  if (Object.hasOwn(commandLoaders, name)) names = [name];
163
163
  if (!names.length && resolvedArgs.some((arg) => HELP_FLAGS.has(arg))) names = Object.keys(commandLoaders);
164
164
  const modules = Object.fromEntries(await Promise.all(names.map(async (key) => [key, await commandLoaders[key]()])));
165
- const args = name === "studio" ? (await import("./studio-mw6HaPkr.js")).routeStudioFlags(resolvedArgs) : resolvedArgs;
165
+ const args = name === "studio" ? (await import("./studio-B4XsXgKj.js")).routeStudioFlags(resolvedArgs) : resolvedArgs;
166
166
  const isQuietFlag = args.some((arg) => QUIET_FLAGS.has(arg));
167
167
  const isJsonOutput = args.includes("--json") || args.some((arg, index) => /^--reporter=.*\bjson\b/.test(arg) || arg === "--reporter" && /\bjson\b/.test(args[index + 1] ?? ""));
168
168
  if (!isDisabled() && !isQuietFlag) console.error(`${styleText("yellow", "Notice:")} Kubb collects anonymous telemetry data to help improve the tool. No personal data or file contents are collected. \nTo disable, set ${styleText("cyan", "KUBB_DISABLE_TELEMETRY=1")}.\n`);
@@ -11,10 +11,10 @@ const command = (0, require("gunshi").define)({
11
11
  ].join("\n"),
12
12
  rendering: { header: null },
13
13
  async run() {
14
- const { run } = await Promise.resolve().then(() => require("./run-D5Z6nfzK.cjs"));
14
+ const { run } = await Promise.resolve().then(() => require("./run-uPA5s3rI.cjs"));
15
15
  await run();
16
16
  }
17
17
  });
18
18
  exports.command = command;
19
19
 
20
- //# sourceMappingURL=mcp-CYPOFKnP.cjs.map
20
+ //# sourceMappingURL=mcp-CcseJJwh.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-CYPOFKnP.cjs","names":["define"],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { define } from 'gunshi'\n\n/** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/mcp`. */\nexport const command = define({\n name: 'mcp',\n description: 'Start an MCP server for code generation from an AI assistant.',\n examples: ['kubb mcp', '# Then add to your MCP client config:', '# { \"mcpServers\": { \"kubb\": { \"command\": \"npx\", \"args\": [\"kubb\", \"mcp\"] } } }'].join('\\n'),\n // gunshi prints the header to stdout, which the MCP stdio transport owns.\n rendering: { header: null },\n async run() {\n const { run } = await import('../runners/mcp/run.ts')\n await run()\n },\n})\n"],"mappings":";;;AAGA,MAAa,WAAA,G,gBAAUA,CAAAA,CAAAA,OAAAA,CAAO;CAC5B,MAAM;CACN,aAAa;CACb,UAAU;EAAC;EAAY;EAAyC;CAA+E,CAAC,CAAC,KAAK,IAAI;CAE1J,WAAW,EAAE,QAAQ,KAAK;CAC1B,MAAM,MAAM;EACV,MAAM,EAAE,QAAQ,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,QAAM,oBAAA,CAAA;EACtB,MAAM,IAAI;CACZ;AACF,CAAC"}
1
+ {"version":3,"file":"mcp-CcseJJwh.cjs","names":["define"],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { define } from 'gunshi'\n\n/** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/mcp`. */\nexport const command = define({\n name: 'mcp',\n description: 'Start an MCP server for code generation from an AI assistant.',\n examples: ['kubb mcp', '# Then add to your MCP client config:', '# { \"mcpServers\": { \"kubb\": { \"command\": \"npx\", \"args\": [\"kubb\", \"mcp\"] } } }'].join('\\n'),\n // gunshi prints the header to stdout, which the MCP stdio transport owns.\n rendering: { header: null },\n async run() {\n const { run } = await import('../runners/mcp/run.ts')\n await run()\n },\n})\n"],"mappings":";;;AAGA,MAAa,WAAA,G,gBAAUA,CAAAA,CAAAA,OAAAA,CAAO;CAC5B,MAAM;CACN,aAAa;CACb,UAAU;EAAC;EAAY;EAAyC;CAA+E,CAAC,CAAC,KAAK,IAAI;CAE1J,WAAW,EAAE,QAAQ,KAAK;CAC1B,MAAM,MAAM;EACV,MAAM,EAAE,QAAQ,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,QAAM,oBAAA,CAAA;EACtB,MAAM,IAAI;CACZ;AACF,CAAC"}
@@ -12,10 +12,10 @@ const command = define({
12
12
  ].join("\n"),
13
13
  rendering: { header: null },
14
14
  async run() {
15
- const { run } = await import("./run-DFXhBS64.js");
15
+ const { run } = await import("./run-DTqMrPS9.js");
16
16
  await run();
17
17
  }
18
18
  });
19
19
  export { command };
20
20
 
21
- //# sourceMappingURL=mcp-CxeZR5vb.js.map
21
+ //# sourceMappingURL=mcp-DUTsS8tR.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-CxeZR5vb.js","names":[],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { define } from 'gunshi'\n\n/** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/mcp`. */\nexport const command = define({\n name: 'mcp',\n description: 'Start an MCP server for code generation from an AI assistant.',\n examples: ['kubb mcp', '# Then add to your MCP client config:', '# { \"mcpServers\": { \"kubb\": { \"command\": \"npx\", \"args\": [\"kubb\", \"mcp\"] } } }'].join('\\n'),\n // gunshi prints the header to stdout, which the MCP stdio transport owns.\n rendering: { header: null },\n async run() {\n const { run } = await import('../runners/mcp/run.ts')\n await run()\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,OAAO;CAC5B,MAAM;CACN,aAAa;CACb,UAAU;EAAC;EAAY;EAAyC;CAA+E,CAAC,CAAC,KAAK,IAAI;CAE1J,WAAW,EAAE,QAAQ,KAAK;CAC1B,MAAM,MAAM;EACV,MAAM,EAAE,QAAQ,MAAM,OAAO;EAC7B,MAAM,IAAI;CACZ;AACF,CAAC"}
1
+ {"version":3,"file":"mcp-DUTsS8tR.js","names":[],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { define } from 'gunshi'\n\n/** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/mcp`. */\nexport const command = define({\n name: 'mcp',\n description: 'Start an MCP server for code generation from an AI assistant.',\n examples: ['kubb mcp', '# Then add to your MCP client config:', '# { \"mcpServers\": { \"kubb\": { \"command\": \"npx\", \"args\": [\"kubb\", \"mcp\"] } } }'].join('\\n'),\n // gunshi prints the header to stdout, which the MCP stdio transport owns.\n rendering: { header: null },\n async run() {\n const { run } = await import('../runners/mcp/run.ts')\n await run()\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,OAAO;CAC5B,MAAM;CACN,aAAa;CACb,UAAU;EAAC;EAAY;EAAyC;CAA+E,CAAC,CAAC,KAAK,IAAI;CAE1J,WAAW,EAAE,QAAQ,KAAK;CAC1B,MAAM,MAAM;EACV,MAAM,EAAE,QAAQ,MAAM,OAAO;EAC7B,MAAM,IAAI;CACZ;AACF,CAAC"}
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "5.15.0";
2
+ var version = "5.15.1";
3
3
  Object.defineProperty(exports, "version", {
4
4
  enumerable: true,
5
5
  get: function() {
@@ -7,4 +7,4 @@ Object.defineProperty(exports, "version", {
7
7
  }
8
8
  });
9
9
 
10
- //# sourceMappingURL=package-aX0q9SZr.cjs.map
10
+ //# sourceMappingURL=package-B1hUUjio.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-B1hUUjio.cjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
@@ -0,0 +1,5 @@
1
+ // package.json
2
+ var version = "5.15.1";
3
+ export { version as t };
4
+
5
+ //# sourceMappingURL=package-MYPMnnTX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-MYPMnnTX.js","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
@@ -1 +1 @@
1
- export { t as connect, a as login, s as resolvePermissions, c as runStudio } from "./run-KqdudiWQ.js";
1
+ export { t as connect, a as login, s as resolvePermissions, c as runStudio } from "./run-DUwX6Icx.js";
@@ -27,7 +27,7 @@ async function regenerate({ cwd, configPath }) {
27
27
  const spinner = createSpinner();
28
28
  spinner.start("Generating with the new versions");
29
29
  try {
30
- const [{ getConfigs }, { generate }] = await Promise.all([import("./config-BL3HnFhb.js"), import("./run-CbX6tpqB.js")]);
30
+ const [{ getConfigs }, { generate }] = await Promise.all([import("./config-BL3HnFhb.js"), import("./run-CXVhxFfC.js")]);
31
31
  const { configs } = await getConfigs({ configPath });
32
32
  const dirs = configs.map((config) => path.resolve(config.root ?? cwd, config.output.path));
33
33
  const before = new Map((await Promise.all(dirs.map(readOutputFiles))).flatMap((files) => [...files]));
@@ -225,4 +225,4 @@ const command = defineWithTypes()({
225
225
  });
226
226
  export { command, run };
227
227
 
228
- //# sourceMappingURL=run-RN_31Q4u.js.map
228
+ //# sourceMappingURL=run-BsrNfFIl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-RN_31Q4u.js","names":[],"sources":["../src/runners/update/run.ts"],"sourcesContent":["import path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as clack from '@clack/prompts'\nimport { defineWithTypes } from 'gunshi'\nimport { findConfigFile } from '@internals/shared'\nimport { getErrorMessage } from '@internals/utils'\nimport { Hookable, type KubbHooks, readInstalledPackages, type RegistryEntry } from '@kubb/core'\nimport { pluralize } from '../../ui/text.ts'\nimport { dryRunId, type DryRunExtensions, yesArg } from '../../commands/shared.ts'\nimport { isInteractiveRun, logIntro } from '../../ui/intro.ts'\nimport { logBlock, logError, logStep, logWarn } from '../../ui/log.ts'\nimport { createSpinner, withSpinner } from '../../ui/spinner.ts'\nimport { logCommandSummary } from '../../ui/summary.ts'\nimport { formatTable } from '../../ui/table.ts'\nimport { bumpOf, fetchRegistryIndex, incompatibility, installSpec, isOutdated, registryUrl, toRegistryId, toShortId } from '../../utils/registry.ts'\nimport { detectPackageManager } from '../init/utils.ts'\nimport { installWithSpinner } from '../installWithSpinner.ts'\nimport { diffFiles, type FileChange, readOutputFiles } from '../generate/utils.ts'\n\nexport type UpdateOptions = {\n /**\n * Registry ids to update. Empty updates every installed extension the registry lists.\n */\n ids: Array<string>\n /**\n * List the updates without installing anything.\n */\n dryRun: boolean\n yes: boolean\n}\n\n/**\n * Generates every config in this process, the way `kubb generate` does, and returns the output files\n * it changed. Runs after the install, so the config loads the new versions. `undefined` when the\n * config fails to load or a build fails.\n */\nasync function regenerate({\n cwd,\n configPath,\n}: {\n cwd: string\n configPath: string\n}): Promise<{ files: Array<FileChange>; unchanged: number; output: string } | undefined> {\n const spinner = createSpinner()\n spinner.start('Generating with the new versions')\n try {\n // Imported here, so the config loader and the generate path never slow down `kubb --help`.\n const [{ getConfigs }, { generate }] = await Promise.all([import('../../config.ts'), import('../generate/run.ts')])\n const { configs } = await getConfigs({ configPath })\n const dirs = configs.map((config) => path.resolve(config.root ?? cwd, config.output.path))\n const before = new Map((await Promise.all(dirs.map(readOutputFiles))).flatMap((files) => [...files]))\n const hooks = new Hookable<KubbHooks>()\n for (const config of configs) {\n if (!(await generate({ config, hooks }))) throw new Error('Generation failed')\n }\n const after = new Map((await Promise.all(dirs.map(readOutputFiles))).flatMap((files) => [...files]))\n const diff = diffFiles(before, after)\n spinner.stop(diff.files.length ? `Generated: ${pluralize(diff.files.length, 'file')} changed` : 'Generated: no files changed')\n return { ...diff, output: dirs.map((dir) => path.relative(cwd, dir) || '.').join(', ') }\n } catch (error) {\n spinner.error(`Generation failed: ${getErrorMessage(error)}`)\n return undefined\n }\n}\n\n/**\n * Moves installed extensions to the version the registry pins. Shows each version change with its\n * bump, asks which to install with majors left out, installs them, and regenerates to show which\n * files changed. With `dryRun`, only lists the updates and installs nothing.\n */\nexport async function run({ ids, dryRun, yes }: UpdateOptions): Promise<void> {\n const cwd = process.cwd()\n const hrStart = process.hrtime()\n const installedPackages: Array<string> = []\n const summary = (title: string, status: Parameters<typeof logCommandSummary>[0]['status'], lines: ReadonlyArray<string>) =>\n logCommandSummary({ title, status, hrStart, block: true, lines })\n logIntro({ title: isInteractiveRun({ yes, dryRun }) ? undefined : styleText('bgCyan', styleText('black', ' Kubb Update ')) })\n\n try {\n const wanted = new Set(ids.map(toRegistryId))\n const [entries, installed] = await withSpinner({\n message: 'Checking the registry',\n promise: Promise.all([fetchRegistryIndex({ registry: registryUrl() }), readInstalledPackages({ root: cwd })]),\n })\n const versions = new Map(installed.map((item) => [item.package, item.version]))\n\n const tracked = entries.filter((entry) => versions.has(entry.artifact.package) && (!wanted.size || wanted.has(entry.id)))\n for (const id of wanted) {\n if (tracked.some((entry) => entry.id === id)) continue\n logWarn(`${id} is not installed, or not in the registry.`)\n // A caller that named it, such as Studio, must not read the run as a successful update.\n process.exitCode = 1\n }\n\n const current = ({ artifact }: RegistryEntry) => versions.get(artifact.package)\n const isMajor = (entry: RegistryEntry) => bumpOf({ installed: current(entry), latest: entry.artifact.version }) === 'major'\n const outdated = tracked.filter((entry) => isOutdated({ installed: current(entry), latest: entry.artifact.version }))\n const proposals = outdated.filter((entry) => {\n const problem = incompatibility(entry.manifest)\n if (problem) {\n logWarn(`Skipped ${entry.id}: ${problem}`)\n // Same as a missing id: Studio would report an update that installed nothing.\n if (wanted.has(entry.id)) process.exitCode = 1\n }\n return !problem\n })\n\n if (!proposals.length) {\n const title = outdated.length ? 'No compatible updates available' : 'Already up to date'\n summary(tracked.length ? title : 'No installed extensions to update', outdated.length ? 'warning' : 'success', [\n ` ${tracked.length - outdated.length} of ${tracked.length} up to date`,\n ...(ids.length ? ['', `No updates for ${ids.join(', ')}.`] : []),\n ])\n return\n }\n\n if (tracked.length) {\n const header = ['Extension', 'Current', 'Latest', '']\n const rows = tracked.map((entry) => {\n if (!outdated.includes(entry)) return [entry.artifact.package, current(entry) ?? '-', 'up to date', '']\n const bump = bumpOf({ installed: current(entry), latest: entry.artifact.version }) ?? ''\n return [entry.artifact.package, current(entry) ?? 'not installed', entry.artifact.version, bump === 'major' ? 'major · breaking' : bump]\n })\n const lines = formatTable([header, ...rows])\n logStep(`Checked ${pluralize(tracked.length, 'extension')} against the registry`)\n logBlock([\n styleText('dim', lines[0]!),\n ...lines.slice(1).map((line, index) => {\n if (!outdated.includes(tracked[index]!)) return styleText('dim', line)\n return line.endsWith('major · breaking') ? styleText('yellow', line) : line\n }),\n ])\n }\n\n if (dryRun) {\n summary('Updates available', 'planned', [`Dry run: nothing was installed. Run kubb update to install ${proposals.length === 1 ? 'it' : 'them'}.`])\n return\n }\n\n // A major can break the generated code, so it is only picked for you when you named it.\n const defaults = proposals.filter((entry) => wanted.has(entry.id) || !isMajor(entry))\n const chosen = yes\n ? defaults.map((entry) => entry.id)\n : await clack.multiselect({\n message: 'Select the updates to install',\n options: proposals.map((entry) => ({\n value: entry.id,\n label: entry.artifact.package,\n hint: `${current(entry) ?? 'not installed'} → ${entry.artifact.version}`,\n })),\n initialValues: defaults.map((entry) => entry.id),\n required: false,\n })\n if (clack.isCancel(chosen)) {\n summary('Update canceled', 'canceled', [' No changes made'])\n return\n }\n const selected = proposals.filter((entry) => chosen.includes(entry.id))\n\n const skipped = proposals\n .filter((entry) => !selected.includes(entry))\n .map((entry) => {\n const kind = entry.manifest.kind.charAt(0).toUpperCase() + entry.manifest.kind.slice(1)\n return ` ${styleText('dim', 'Skipped')} ${kind} ${entry.artifact.package} ${entry.artifact.version} ${styleText('dim', `run kubb update ${toShortId(entry.id)} later`)}`\n })\n if (!selected.length) {\n summary('No updates installed', 'canceled', [' No updates selected.', ...skipped])\n return\n }\n\n const packageManager = detectPackageManager(cwd)\n const names = selected.map(({ artifact }) => artifact.package).join(', ')\n await installWithSpinner({\n packages: selected.map(({ artifact }) => installSpec(artifact)),\n names,\n packageManager,\n cwd,\n })\n installedPackages.push(...selected.map((entry) => entry.artifact.package))\n\n // Regenerating rewrites output files, so it is asked for. `--yes` only accepts the install.\n const foundConfig = findConfigFile(cwd)\n const regenerateNow =\n foundConfig && !yes && (await clack.confirm({ message: 'Regenerate now? This rewrites the generated files.', initialValue: true })) === true\n const configPath = regenerateNow ? foundConfig : undefined\n const changed = configPath ? await regenerate({ cwd, configPath }) : undefined\n\n const generationFailed = Boolean(configPath && !changed)\n const fileCounts = { A: 0, M: 0, D: 0 }\n for (const file of changed?.files ?? []) fileCounts[file.status]++\n summary(generationFailed ? 'Extensions updated; generation failed' : 'Update complete', generationFailed ? 'warning' : 'success', [\n ` Packages ${selected.length} installed with ${packageManager.name}${skipped.length ? ` · ${skipped.length} skipped` : ''}`,\n ...skipped,\n ...(changed ? [` Files ${fileCounts.A} added · ${fileCounts.M} modified · ${fileCounts.D} deleted`] : []),\n ...(!configPath ? [' Regeneration not run'] : []),\n ...(generationFailed ? ['', 'Fix the generation error, then run kubb generate.'] : []),\n ])\n } catch (error) {\n logError(getErrorMessage(error))\n summary('Update failed', 'failed', installedPackages.length ? [` Packages ${installedPackages.join(', ')} installed`] : [' No changes made'])\n process.exitCode = 1\n }\n}\n\nexport const command = defineWithTypes<{ extensions: DryRunExtensions }>()({\n name: 'update',\n description: 'Update installed extensions, regenerate, and summarize file changes.',\n examples: ['kubb update', 'kubb update --dry-run', 'kubb update plugin-zod plugin-ts --yes'].join('\\n'),\n args: {\n ids: {\n type: 'positional',\n description: 'Registry ids to update, all installed extensions when omitted',\n multiple: true,\n },\n ...yesArg,\n },\n run: ({ values, extensions }) => run({ ids: values.ids ?? [], dryRun: extensions[dryRunId].enabled, yes: values.yes }),\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-BsrNfFIl.js","names":[],"sources":["../src/runners/update/run.ts"],"sourcesContent":["import path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as clack from '@clack/prompts'\nimport { defineWithTypes } from 'gunshi'\nimport { findConfigFile } from '@internals/shared'\nimport { getErrorMessage } from '@internals/utils'\nimport { Hookable, type KubbHooks, readInstalledPackages, type RegistryEntry } from '@kubb/core'\nimport { pluralize } from '../../ui/text.ts'\nimport { dryRunId, type DryRunExtensions, yesArg } from '../../commands/shared.ts'\nimport { isInteractiveRun, logIntro } from '../../ui/intro.ts'\nimport { logBlock, logError, logStep, logWarn } from '../../ui/log.ts'\nimport { createSpinner, withSpinner } from '../../ui/spinner.ts'\nimport { logCommandSummary } from '../../ui/summary.ts'\nimport { formatTable } from '../../ui/table.ts'\nimport { bumpOf, fetchRegistryIndex, incompatibility, installSpec, isOutdated, registryUrl, toRegistryId, toShortId } from '../../utils/registry.ts'\nimport { detectPackageManager } from '../init/utils.ts'\nimport { installWithSpinner } from '../installWithSpinner.ts'\nimport { diffFiles, type FileChange, readOutputFiles } from '../generate/utils.ts'\n\nexport type UpdateOptions = {\n /**\n * Registry ids to update. Empty updates every installed extension the registry lists.\n */\n ids: Array<string>\n /**\n * List the updates without installing anything.\n */\n dryRun: boolean\n yes: boolean\n}\n\n/**\n * Generates every config in this process, the way `kubb generate` does, and returns the output files\n * it changed. Runs after the install, so the config loads the new versions. `undefined` when the\n * config fails to load or a build fails.\n */\nasync function regenerate({\n cwd,\n configPath,\n}: {\n cwd: string\n configPath: string\n}): Promise<{ files: Array<FileChange>; unchanged: number; output: string } | undefined> {\n const spinner = createSpinner()\n spinner.start('Generating with the new versions')\n try {\n // Imported here, so the config loader and the generate path never slow down `kubb --help`.\n const [{ getConfigs }, { generate }] = await Promise.all([import('../../config.ts'), import('../generate/run.ts')])\n const { configs } = await getConfigs({ configPath })\n const dirs = configs.map((config) => path.resolve(config.root ?? cwd, config.output.path))\n const before = new Map((await Promise.all(dirs.map(readOutputFiles))).flatMap((files) => [...files]))\n const hooks = new Hookable<KubbHooks>()\n for (const config of configs) {\n if (!(await generate({ config, hooks }))) throw new Error('Generation failed')\n }\n const after = new Map((await Promise.all(dirs.map(readOutputFiles))).flatMap((files) => [...files]))\n const diff = diffFiles(before, after)\n spinner.stop(diff.files.length ? `Generated: ${pluralize(diff.files.length, 'file')} changed` : 'Generated: no files changed')\n return { ...diff, output: dirs.map((dir) => path.relative(cwd, dir) || '.').join(', ') }\n } catch (error) {\n spinner.error(`Generation failed: ${getErrorMessage(error)}`)\n return undefined\n }\n}\n\n/**\n * Moves installed extensions to the version the registry pins. Shows each version change with its\n * bump, asks which to install with majors left out, installs them, and regenerates to show which\n * files changed. With `dryRun`, only lists the updates and installs nothing.\n */\nexport async function run({ ids, dryRun, yes }: UpdateOptions): Promise<void> {\n const cwd = process.cwd()\n const hrStart = process.hrtime()\n const installedPackages: Array<string> = []\n const summary = (title: string, status: Parameters<typeof logCommandSummary>[0]['status'], lines: ReadonlyArray<string>) =>\n logCommandSummary({ title, status, hrStart, block: true, lines })\n logIntro({ title: isInteractiveRun({ yes, dryRun }) ? undefined : styleText('bgCyan', styleText('black', ' Kubb Update ')) })\n\n try {\n const wanted = new Set(ids.map(toRegistryId))\n const [entries, installed] = await withSpinner({\n message: 'Checking the registry',\n promise: Promise.all([fetchRegistryIndex({ registry: registryUrl() }), readInstalledPackages({ root: cwd })]),\n })\n const versions = new Map(installed.map((item) => [item.package, item.version]))\n\n const tracked = entries.filter((entry) => versions.has(entry.artifact.package) && (!wanted.size || wanted.has(entry.id)))\n for (const id of wanted) {\n if (tracked.some((entry) => entry.id === id)) continue\n logWarn(`${id} is not installed, or not in the registry.`)\n // A caller that named it, such as Studio, must not read the run as a successful update.\n process.exitCode = 1\n }\n\n const current = ({ artifact }: RegistryEntry) => versions.get(artifact.package)\n const isMajor = (entry: RegistryEntry) => bumpOf({ installed: current(entry), latest: entry.artifact.version }) === 'major'\n const outdated = tracked.filter((entry) => isOutdated({ installed: current(entry), latest: entry.artifact.version }))\n const proposals = outdated.filter((entry) => {\n const problem = incompatibility(entry.manifest)\n if (problem) {\n logWarn(`Skipped ${entry.id}: ${problem}`)\n // Same as a missing id: Studio would report an update that installed nothing.\n if (wanted.has(entry.id)) process.exitCode = 1\n }\n return !problem\n })\n\n if (!proposals.length) {\n const title = outdated.length ? 'No compatible updates available' : 'Already up to date'\n summary(tracked.length ? title : 'No installed extensions to update', outdated.length ? 'warning' : 'success', [\n ` ${tracked.length - outdated.length} of ${tracked.length} up to date`,\n ...(ids.length ? ['', `No updates for ${ids.join(', ')}.`] : []),\n ])\n return\n }\n\n if (tracked.length) {\n const header = ['Extension', 'Current', 'Latest', '']\n const rows = tracked.map((entry) => {\n if (!outdated.includes(entry)) return [entry.artifact.package, current(entry) ?? '-', 'up to date', '']\n const bump = bumpOf({ installed: current(entry), latest: entry.artifact.version }) ?? ''\n return [entry.artifact.package, current(entry) ?? 'not installed', entry.artifact.version, bump === 'major' ? 'major · breaking' : bump]\n })\n const lines = formatTable([header, ...rows])\n logStep(`Checked ${pluralize(tracked.length, 'extension')} against the registry`)\n logBlock([\n styleText('dim', lines[0]!),\n ...lines.slice(1).map((line, index) => {\n if (!outdated.includes(tracked[index]!)) return styleText('dim', line)\n return line.endsWith('major · breaking') ? styleText('yellow', line) : line\n }),\n ])\n }\n\n if (dryRun) {\n summary('Updates available', 'planned', [`Dry run: nothing was installed. Run kubb update to install ${proposals.length === 1 ? 'it' : 'them'}.`])\n return\n }\n\n // A major can break the generated code, so it is only picked for you when you named it.\n const defaults = proposals.filter((entry) => wanted.has(entry.id) || !isMajor(entry))\n const chosen = yes\n ? defaults.map((entry) => entry.id)\n : await clack.multiselect({\n message: 'Select the updates to install',\n options: proposals.map((entry) => ({\n value: entry.id,\n label: entry.artifact.package,\n hint: `${current(entry) ?? 'not installed'} → ${entry.artifact.version}`,\n })),\n initialValues: defaults.map((entry) => entry.id),\n required: false,\n })\n if (clack.isCancel(chosen)) {\n summary('Update canceled', 'canceled', [' No changes made'])\n return\n }\n const selected = proposals.filter((entry) => chosen.includes(entry.id))\n\n const skipped = proposals\n .filter((entry) => !selected.includes(entry))\n .map((entry) => {\n const kind = entry.manifest.kind.charAt(0).toUpperCase() + entry.manifest.kind.slice(1)\n return ` ${styleText('dim', 'Skipped')} ${kind} ${entry.artifact.package} ${entry.artifact.version} ${styleText('dim', `run kubb update ${toShortId(entry.id)} later`)}`\n })\n if (!selected.length) {\n summary('No updates installed', 'canceled', [' No updates selected.', ...skipped])\n return\n }\n\n const packageManager = detectPackageManager(cwd)\n const names = selected.map(({ artifact }) => artifact.package).join(', ')\n await installWithSpinner({\n packages: selected.map(({ artifact }) => installSpec(artifact)),\n names,\n packageManager,\n cwd,\n })\n installedPackages.push(...selected.map((entry) => entry.artifact.package))\n\n // Regenerating rewrites output files, so it is asked for. `--yes` only accepts the install.\n const foundConfig = findConfigFile(cwd)\n const regenerateNow =\n foundConfig && !yes && (await clack.confirm({ message: 'Regenerate now? This rewrites the generated files.', initialValue: true })) === true\n const configPath = regenerateNow ? foundConfig : undefined\n const changed = configPath ? await regenerate({ cwd, configPath }) : undefined\n\n const generationFailed = Boolean(configPath && !changed)\n const fileCounts = { A: 0, M: 0, D: 0 }\n for (const file of changed?.files ?? []) fileCounts[file.status]++\n summary(generationFailed ? 'Extensions updated; generation failed' : 'Update complete', generationFailed ? 'warning' : 'success', [\n ` Packages ${selected.length} installed with ${packageManager.name}${skipped.length ? ` · ${skipped.length} skipped` : ''}`,\n ...skipped,\n ...(changed ? [` Files ${fileCounts.A} added · ${fileCounts.M} modified · ${fileCounts.D} deleted`] : []),\n ...(!configPath ? [' Regeneration not run'] : []),\n ...(generationFailed ? ['', 'Fix the generation error, then run kubb generate.'] : []),\n ])\n } catch (error) {\n logError(getErrorMessage(error))\n summary('Update failed', 'failed', installedPackages.length ? [` Packages ${installedPackages.join(', ')} installed`] : [' No changes made'])\n process.exitCode = 1\n }\n}\n\nexport const command = defineWithTypes<{ extensions: DryRunExtensions }>()({\n name: 'update',\n description: 'Update installed extensions, regenerate, and summarize file changes.',\n examples: ['kubb update', 'kubb update --dry-run', 'kubb update plugin-zod plugin-ts --yes'].join('\\n'),\n args: {\n ids: {\n type: 'positional',\n description: 'Registry ids to update, all installed extensions when omitted',\n multiple: true,\n },\n ...yesArg,\n },\n run: ({ values, extensions }) => run({ ids: values.ids ?? [], dryRun: extensions[dryRunId].enabled, yes: values.yes }),\n})\n"],"mappings":"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"}