@kubb/cli 5.11.4 → 5.11.5

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 (100) hide show
  1. package/dist/{Telemetry-CwaVQsvD.js → Telemetry-BlAR8vxu.js} +3 -31
  2. package/dist/Telemetry-BlAR8vxu.js.map +1 -0
  3. package/dist/{Telemetry-Be1nltUh.cjs → Telemetry-CF1YNdR-.cjs} +2 -42
  4. package/dist/Telemetry-CF1YNdR-.cjs.map +1 -0
  5. package/dist/{background-mKdZ5HRx.cjs → background-CaZZul1n.cjs} +5 -4
  6. package/dist/background-CaZZul1n.cjs.map +1 -0
  7. package/dist/{background-CQPyCSn0.js → background-DKyMPeHm.js} +7 -5
  8. package/dist/background-DKyMPeHm.js.map +1 -0
  9. package/dist/{background-aTbwrgui.js → background-DUHqYiuQ.js} +1 -1
  10. package/dist/config-Bh00Hwpw.js +132 -0
  11. package/dist/config-Bh00Hwpw.js.map +1 -0
  12. package/dist/config-D63Gum4F.cjs +169 -0
  13. package/dist/config-D63Gum4F.cjs.map +1 -0
  14. package/dist/config-iVdOcpro.js +1 -0
  15. package/dist/credentials-CZK6zPLv.js.map +1 -1
  16. package/dist/credentials-DDaKqtJn.cjs.map +1 -1
  17. package/dist/errors-Cl69p_vI.cjs +43 -0
  18. package/dist/errors-Cl69p_vI.cjs.map +1 -0
  19. package/dist/errors-DmC83ALX.js +32 -0
  20. package/dist/errors-DmC83ALX.js.map +1 -0
  21. package/dist/index.cjs +872 -307
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.js +863 -298
  24. package/dist/index.js.map +1 -1
  25. package/dist/registry-CfYNeyOc.cjs +272 -0
  26. package/dist/registry-CfYNeyOc.cjs.map +1 -0
  27. package/dist/registry-D688-8EH.js +200 -0
  28. package/dist/registry-D688-8EH.js.map +1 -0
  29. package/dist/reporters-BHyW4d5Q.js +817 -0
  30. package/dist/reporters-BHyW4d5Q.js.map +1 -0
  31. package/dist/reporters-DrQJfnU2.cjs +829 -0
  32. package/dist/reporters-DrQJfnU2.cjs.map +1 -0
  33. package/dist/run-B4SKmzAG.js +1 -0
  34. package/dist/{run-Bczs5vbI.cjs → run-BldagXO-.cjs} +4 -3
  35. package/dist/{run-Bczs5vbI.cjs.map → run-BldagXO-.cjs.map} +1 -1
  36. package/dist/{run-B6VxJ_VM.js → run-C1FHgzNR.js} +3 -2
  37. package/dist/{run-B6VxJ_VM.js.map → run-C1FHgzNR.js.map} +1 -1
  38. package/dist/run-CYHpe0V_.cjs +227 -0
  39. package/dist/run-CYHpe0V_.cjs.map +1 -0
  40. package/dist/run-CaJbZO-f.cjs +94 -0
  41. package/dist/run-CaJbZO-f.cjs.map +1 -0
  42. package/dist/run-Cj-HJxYW.js +93 -0
  43. package/dist/run-Cj-HJxYW.js.map +1 -0
  44. package/dist/{run-BWRmQxtE.cjs → run-DkBJkKor.cjs} +172 -76
  45. package/dist/run-DkBJkKor.cjs.map +1 -0
  46. package/dist/run-S3xKq4bj.js +224 -0
  47. package/dist/run-S3xKq4bj.js.map +1 -0
  48. package/dist/{run-YHth5Afz.js → run-vBNko5TH.js} +166 -70
  49. package/dist/run-vBNko5TH.js.map +1 -0
  50. package/dist/{snapshot-D_rXnnMH.cjs → snapshot-CsIJRKEL.cjs} +50 -63
  51. package/dist/snapshot-CsIJRKEL.cjs.map +1 -0
  52. package/dist/{snapshot-Cilp10vE.js → snapshot-Cvo94y5d.js} +48 -61
  53. package/dist/snapshot-Cvo94y5d.js.map +1 -0
  54. package/dist/status-C-NPN63r.cjs +78 -0
  55. package/dist/status-C-NPN63r.cjs.map +1 -0
  56. package/dist/status-DTsZxa5Y.js +77 -0
  57. package/dist/status-DTsZxa5Y.js.map +1 -0
  58. package/dist/studioWorker.js +2 -2
  59. package/dist/summary-C22oNZu_.cjs +46 -0
  60. package/dist/summary-C22oNZu_.cjs.map +1 -0
  61. package/dist/summary-F11HQput.js +41 -0
  62. package/dist/summary-F11HQput.js.map +1 -0
  63. package/dist/text-28DwO_5A.cjs +341 -0
  64. package/dist/text-28DwO_5A.cjs.map +1 -0
  65. package/dist/text-BThr2r0T.js +239 -0
  66. package/dist/text-BThr2r0T.js.map +1 -0
  67. package/dist/utils-BLXM2UkN.cjs +727 -0
  68. package/dist/utils-BLXM2UkN.cjs.map +1 -0
  69. package/dist/utils-Cv3YUnSi.js +612 -0
  70. package/dist/utils-Cv3YUnSi.js.map +1 -0
  71. package/package.json +7 -7
  72. package/dist/Telemetry-Be1nltUh.cjs.map +0 -1
  73. package/dist/Telemetry-CwaVQsvD.js.map +0 -1
  74. package/dist/background-CQPyCSn0.js.map +0 -1
  75. package/dist/background-mKdZ5HRx.cjs.map +0 -1
  76. package/dist/config-B56ZuVhi.js +0 -95
  77. package/dist/config-B56ZuVhi.js.map +0 -1
  78. package/dist/config-Cs4N79Fm.cjs +0 -113
  79. package/dist/config-Cs4N79Fm.cjs.map +0 -1
  80. package/dist/output-HgzJqkSF.cjs +0 -1076
  81. package/dist/output-HgzJqkSF.cjs.map +0 -1
  82. package/dist/output-PhkPtNP7.js +0 -937
  83. package/dist/output-PhkPtNP7.js.map +0 -1
  84. package/dist/registry-DYUhC7rH.js +0 -115
  85. package/dist/registry-DYUhC7rH.js.map +0 -1
  86. package/dist/registry-tk-v78fd.cjs +0 -157
  87. package/dist/registry-tk-v78fd.cjs.map +0 -1
  88. package/dist/run-AfjIBtiL.js +0 -39
  89. package/dist/run-AfjIBtiL.js.map +0 -1
  90. package/dist/run-BWRmQxtE.cjs.map +0 -1
  91. package/dist/run-B_Gr9TJ4.cjs +0 -345
  92. package/dist/run-B_Gr9TJ4.cjs.map +0 -1
  93. package/dist/run-CwrI0wRy.js +0 -1
  94. package/dist/run-DDoJGjWT.cjs +0 -40
  95. package/dist/run-DDoJGjWT.cjs.map +0 -1
  96. package/dist/run-SYKj8-Q5.js +0 -343
  97. package/dist/run-SYKj8-Q5.js.map +0 -1
  98. package/dist/run-YHth5Afz.js.map +0 -1
  99. package/dist/snapshot-Cilp10vE.js.map +0 -1
  100. package/dist/snapshot-D_rXnnMH.cjs.map +0 -1
@@ -0,0 +1,93 @@
1
+ import "./rolldown-runtime-CRm0XQPb.js";
2
+ import { n as toError } from "./errors-DmC83ALX.js";
3
+ import { n as trackRun } from "./Telemetry-BlAR8vxu.js";
4
+ import { t as pluralize } from "./text-BThr2r0T.js";
5
+ import { n as findConfigFile, t as getConfigs } from "./config-Bh00Hwpw.js";
6
+ import { t as logCommandSummary } from "./summary-F11HQput.js";
7
+ import { styleText } from "node:util";
8
+ import process from "node:process";
9
+ import { resolve } from "node:path";
10
+ //#region src/runners/validate/run.ts
11
+ /**
12
+ * Validates `input` with the configured adapters, falling back to OpenAPI when no config exists.
13
+ * Exits the process with code 1 on validation failure or missing dependency.
14
+ */
15
+ async function run({ input, configPath }) {
16
+ const hrStart = process.hrtime();
17
+ const report = trackRun({
18
+ command: "validate",
19
+ hrStart
20
+ });
21
+ let adapterName;
22
+ try {
23
+ const configFile = configPath ?? findConfigFile();
24
+ const loaded = configFile ? await getConfigs({
25
+ configPath: configFile,
26
+ input
27
+ }).catch((error) => {
28
+ if (configPath) throw error;
29
+ }) : void 0;
30
+ const fallback = async () => {
31
+ adapterName = "@kubb/adapter-oas";
32
+ const { adapterOas } = await import("@kubb/adapter-oas");
33
+ return [{
34
+ adapter: adapterOas(),
35
+ input
36
+ }];
37
+ };
38
+ const unique = new Map((loaded?.configs ?? []).map((config) => {
39
+ const resolved = URL.canParse(input) ? input : resolve(config.root || process.cwd(), input);
40
+ return [`${config.adapter?.name}\0${resolved}`, {
41
+ adapter: config.adapter,
42
+ input: resolved
43
+ }];
44
+ }));
45
+ const targets = loaded ? [...unique.values()] : await fallback();
46
+ if (!targets.length) throw new Error("The Kubb config contains no configurations to validate.");
47
+ for (const target of targets) {
48
+ adapterName = target.adapter?.name;
49
+ if (!target.adapter) throw new Error("No adapter is configured. Set adapter in your Kubb config to validate this specification.");
50
+ await target.adapter.validate(target.input, { throwOnError: true });
51
+ }
52
+ const specifications = new Set(targets.map((target) => target.input)).size;
53
+ const adapterNames = [...new Set(targets.flatMap((target) => target.adapter?.name ?? []))];
54
+ await report({ status: "success" });
55
+ logCommandSummary({
56
+ title: "Validation passed",
57
+ status: "success",
58
+ hrStart,
59
+ lines: [
60
+ ` ${styleText("bold", `${pluralize(specifications, "specification")} validated`)}`,
61
+ ` ${styleText("dim", "Input")} ${styleText("cyan", input)}`,
62
+ ` ${styleText("dim", adapterNames.length === 1 ? "Adapter" : "Adapters")} ${adapterNames.join(", ")}`
63
+ ]
64
+ });
65
+ } catch (error) {
66
+ await report({ status: "failed" });
67
+ const message = toError(error).message;
68
+ const missingAdapter = adapterName === "@kubb/adapter-oas" && /(?:Cannot find|Cannot resolve|not found)[\s\S]*@kubb\/adapter-oas/.test(message);
69
+ logCommandSummary({
70
+ title: missingAdapter ? "Could not validate" : "Validation failed",
71
+ status: "failed",
72
+ hrStart,
73
+ lines: [
74
+ ` ${styleText("dim", "Input")} ${styleText("cyan", input)}`,
75
+ ` ${styleText("dim", "Adapter")} ${adapterName ?? "not configured"}${missingAdapter ? " · not installed" : ""}`,
76
+ "",
77
+ styleText("bold", missingAdapter ? "Required package" : "Validation error"),
78
+ ` ${styleText("red", message)}`,
79
+ ...missingAdapter ? [
80
+ "",
81
+ "Install it with:",
82
+ styleText("cyan", " npm install @kubb/adapter-oas"),
83
+ styleText("cyan", " pnpm add @kubb/adapter-oas")
84
+ ] : []
85
+ ]
86
+ });
87
+ process.exit(1);
88
+ }
89
+ }
90
+ //#endregion
91
+ export { run };
92
+
93
+ //# sourceMappingURL=run-Cj-HJxYW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-Cj-HJxYW.js","names":[],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { resolve } from 'node:path'\nimport { styleText } from 'node:util'\nimport { findConfigFile } from '@internals/shared'\nimport { toError } from '@internals/utils'\nimport type { Config } from '@kubb/core'\nimport { trackRun } from '../../Telemetry.ts'\nimport { getConfigs } from '../../config.ts'\nimport { pluralize } from '../../ui/text.ts'\nimport { logCommandSummary } from '../../ui/summary.ts'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the specification to validate.\n */\n input: string\n configPath?: string\n}\n\n/**\n * Validates `input` with the configured adapters, falling back to OpenAPI when no config exists.\n * Exits the process with code 1 on validation failure or missing dependency.\n */\nexport async function run({ input, configPath }: ValidateOptions): Promise<void> {\n const hrStart = process.hrtime()\n const report = trackRun({ command: 'validate', hrStart })\n let adapterName: string | undefined\n\n try {\n const configFile = configPath ?? findConfigFile()\n // A config found by search that does not load must not block validating a file; an explicit `--config` still fails.\n const loaded = configFile\n ? await getConfigs({ configPath: configFile, input }).catch((error) => {\n if (configPath) throw error\n })\n : undefined\n const fallback = async () => {\n adapterName = '@kubb/adapter-oas'\n const { adapterOas } = await import('@kubb/adapter-oas')\n return [{ adapter: adapterOas(), input }]\n }\n // An array config often repeats one adapter, so each adapter and input pair is validated once.\n const unique = new Map(\n (loaded?.configs ?? []).map((config) => {\n const resolved = URL.canParse(input) ? input : resolve(config.root || process.cwd(), input)\n return [`${config.adapter?.name}\\0${resolved}`, { adapter: config.adapter, input: resolved }] as const\n }),\n )\n const targets: Array<{ adapter: Config['adapter']; input: string }> = loaded ? [...unique.values()] : await fallback()\n if (!targets.length) throw new Error('The Kubb config contains no configurations to validate.')\n for (const target of targets) {\n adapterName = target.adapter?.name\n if (!target.adapter) throw new Error('No adapter is configured. Set adapter in your Kubb config to validate this specification.')\n await target.adapter.validate(target.input, { throwOnError: true })\n }\n const specifications = new Set(targets.map((target) => target.input)).size\n const adapterNames = [...new Set(targets.flatMap((target) => target.adapter?.name ?? []))]\n await report({ status: 'success' })\n\n logCommandSummary({\n title: 'Validation passed',\n status: 'success',\n hrStart,\n lines: [\n ` ${styleText('bold', `${pluralize(specifications, 'specification')} validated`)}`,\n ` ${styleText('dim', 'Input')} ${styleText('cyan', input)}`,\n ` ${styleText('dim', adapterNames.length === 1 ? 'Adapter' : 'Adapters')} ${adapterNames.join(', ')}`,\n ],\n })\n } catch (error) {\n await report({ status: 'failed' })\n const message = toError(error).message\n const missingAdapter = adapterName === '@kubb/adapter-oas' && /(?:Cannot find|Cannot resolve|not found)[\\s\\S]*@kubb\\/adapter-oas/.test(message)\n logCommandSummary({\n title: missingAdapter ? 'Could not validate' : 'Validation failed',\n status: 'failed',\n hrStart,\n lines: [\n ` ${styleText('dim', 'Input')} ${styleText('cyan', input)}`,\n ` ${styleText('dim', 'Adapter')} ${adapterName ?? 'not configured'}${missingAdapter ? ' · not installed' : ''}`,\n '',\n styleText('bold', missingAdapter ? 'Required package' : 'Validation error'),\n ` ${styleText('red', message)}`,\n ...(missingAdapter\n ? ['', 'Install it with:', styleText('cyan', ' npm install @kubb/adapter-oas'), styleText('cyan', ' pnpm add @kubb/adapter-oas')]\n : []),\n ],\n })\n\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAuBA,eAAsB,IAAI,EAAE,OAAO,cAA8C;CAC/E,MAAM,UAAU,QAAQ,OAAO;CAC/B,MAAM,SAAS,SAAS;EAAE,SAAS;EAAY;CAAQ,CAAC;CACxD,IAAI;CAEJ,IAAI;EACF,MAAM,aAAa,cAAc,eAAe;EAEhD,MAAM,SAAS,aACX,MAAM,WAAW;GAAE,YAAY;GAAY;EAAM,CAAC,CAAC,CAAC,OAAO,UAAU;GACnE,IAAI,YAAY,MAAM;EACxB,CAAC,IACD,KAAA;EACJ,MAAM,WAAW,YAAY;GAC3B,cAAc;GACd,MAAM,EAAE,eAAe,MAAM,OAAO;GACpC,OAAO,CAAC;IAAE,SAAS,WAAW;IAAG;GAAM,CAAC;EAC1C;EAEA,MAAM,SAAS,IAAI,KAChB,QAAQ,WAAW,CAAC,EAAA,CAAG,KAAK,WAAW;GACtC,MAAM,WAAW,IAAI,SAAS,KAAK,IAAI,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,IAAI,GAAG,KAAK;GAC1F,OAAO,CAAC,GAAG,OAAO,SAAS,KAAK,IAAI,YAAY;IAAE,SAAS,OAAO;IAAS,OAAO;GAAS,CAAC;EAC9F,CAAC,CACH;EACA,MAAM,UAAgE,SAAS,CAAC,GAAG,OAAO,OAAO,CAAC,IAAI,MAAM,SAAS;EACrH,IAAI,CAAC,QAAQ,QAAQ,MAAM,IAAI,MAAM,yDAAyD;EAC9F,KAAK,MAAM,UAAU,SAAS;GAC5B,cAAc,OAAO,SAAS;GAC9B,IAAI,CAAC,OAAO,SAAS,MAAM,IAAI,MAAM,2FAA2F;GAChI,MAAM,OAAO,QAAQ,SAAS,OAAO,OAAO,EAAE,cAAc,KAAK,CAAC;EACpE;EACA,MAAM,iBAAiB,IAAI,IAAI,QAAQ,KAAK,WAAW,OAAO,KAAK,CAAC,CAAC,CAAC;EACtE,MAAM,eAAe,CAAC,GAAG,IAAI,IAAI,QAAQ,SAAS,WAAW,OAAO,SAAS,QAAQ,CAAC,CAAC,CAAC,CAAC;EACzF,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;EAElC,kBAAkB;GAChB,OAAO;GACP,QAAQ;GACR;GACA,OAAO;IACL,KAAK,UAAU,QAAQ,GAAG,UAAU,gBAAgB,eAAe,EAAE,WAAW;IAChF,KAAK,UAAU,OAAO,OAAO,EAAE,MAAM,UAAU,QAAQ,KAAK;IAC5D,KAAK,UAAU,OAAO,aAAa,WAAW,IAAI,YAAY,UAAU,EAAE,IAAI,aAAa,KAAK,IAAI;GACtG;EACF,CAAC;CACH,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,MAAM,UAAU,QAAQ,KAAK,CAAC,CAAC;EAC/B,MAAM,iBAAiB,gBAAgB,uBAAuB,oEAAoE,KAAK,OAAO;EAC9I,kBAAkB;GAChB,OAAO,iBAAiB,uBAAuB;GAC/C,QAAQ;GACR;GACA,OAAO;IACL,KAAK,UAAU,OAAO,OAAO,EAAE,MAAM,UAAU,QAAQ,KAAK;IAC5D,KAAK,UAAU,OAAO,SAAS,EAAE,IAAI,eAAe,mBAAmB,iBAAiB,qBAAqB;IAC7G;IACA,UAAU,QAAQ,iBAAiB,qBAAqB,kBAAkB;IAC1E,KAAK,UAAU,OAAO,OAAO;IAC7B,GAAI,iBACA;KAAC;KAAI;KAAoB,UAAU,QAAQ,iCAAiC;KAAG,UAAU,QAAQ,8BAA8B;IAAC,IAChI,CAAC;GACP;EACF,CAAC;EAED,QAAQ,KAAK,CAAC;CAChB;AACF"}
@@ -1,7 +1,10 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-CPE0t6oh.cjs");
2
- const require_Telemetry = require("./Telemetry-Be1nltUh.cjs");
3
- const require_output = require("./output-HgzJqkSF.cjs");
4
- const require_config = require("./config-Cs4N79Fm.cjs");
2
+ const require_errors = require("./errors-Cl69p_vI.cjs");
3
+ const require_Telemetry = require("./Telemetry-CF1YNdR-.cjs");
4
+ const require_utils = require("./utils-BLXM2UkN.cjs");
5
+ const require_text = require("./text-28DwO_5A.cjs");
6
+ const require_config = require("./config-D63Gum4F.cjs");
7
+ const require_reporters = require("./reporters-DrQJfnU2.cjs");
5
8
  const require_credentials = require("./credentials-DDaKqtJn.cjs");
6
9
  let node_util = require("node:util");
7
10
  let node_os = require("node:os");
@@ -10,11 +13,42 @@ node_process = require_rolldown_runtime.__toESM(node_process, 1);
10
13
  let tinyexec = require("tinyexec");
11
14
  let node_path = require("node:path");
12
15
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
13
- let _kubb_core = require("@kubb/core");
14
16
  let _clack_prompts = require("@clack/prompts");
15
17
  _clack_prompts = require_rolldown_runtime.__toESM(_clack_prompts, 1);
18
+ let _kubb_core = require("@kubb/core");
16
19
  let _kubb_studio = require("@kubb/studio");
17
20
  let _kubb_studio_protocol = require("@kubb/studio/protocol");
21
+ //#region ../../internals/utils/src/copyToClipboard.ts
22
+ const COMMANDS = {
23
+ darwin: ["pbcopy"],
24
+ win32: ["clip.exe"],
25
+ linux: [
26
+ "xclip",
27
+ "-selection",
28
+ "clipboard"
29
+ ]
30
+ };
31
+ /**
32
+ * Copies text to the system clipboard with the platform's own tool. Resolves `false` in CI, on a
33
+ * platform without a known tool, or when the tool is missing or fails.
34
+ */
35
+ async function copyToClipboard(text) {
36
+ const command = node_process.default.platform === "linux" && node_process.default.env.WAYLAND_DISPLAY ? ["wl-copy"] : COMMANDS[node_process.default.platform];
37
+ if (!command || require_Telemetry.isCIEnvironment()) return false;
38
+ const [name, ...args] = command;
39
+ const run = (0, tinyexec.x)(name, args, {
40
+ timeout: 2e3,
41
+ nodeOptions: { stdio: [
42
+ "pipe",
43
+ "ignore",
44
+ "ignore"
45
+ ] }
46
+ });
47
+ run.process?.stdin?.once("error", () => {});
48
+ run.process?.stdin?.end(text);
49
+ return run.then(({ exitCode }) => exitCode === 0, () => false);
50
+ }
51
+ //#endregion
18
52
  //#region ../../internals/utils/src/openInBrowser.ts
19
53
  const ignore = () => {};
20
54
  /**
@@ -43,8 +77,10 @@ function openInBrowser(target) {
43
77
  * server log, or a `Referer` header.
44
78
  */
45
79
  async function login({ studioUrl, autoOpen }, { signal, previousCredentials } = {}) {
46
- const spinner = require_output.createSpinner();
80
+ const spinner = require_utils.createSpinner();
81
+ let retryUntil = 0;
47
82
  let waiting = false;
83
+ let countdown;
48
84
  try {
49
85
  const { token, agent } = await (0, _kubb_studio.pairAgent)({
50
86
  studioUrl,
@@ -54,99 +90,123 @@ async function login({ studioUrl, autoOpen }, { signal, previousCredentials } =
54
90
  machineId: await require_credentials.getMachineId(),
55
91
  signal,
56
92
  onCode: (session) => {
57
- console.log(`\nOpen ${(0, node_util.styleText)("cyan", session.verification_uri)} and approve the code ${(0, node_util.styleText)("bold", session.user_code)}`);
93
+ require_text.logStep([
94
+ "Pair this machine",
95
+ `${(0, node_util.styleText)("dim", "Open")} ${(0, node_util.styleText)("cyan", session.verification_uri)}`,
96
+ `${(0, node_util.styleText)("dim", "Code")} ${(0, node_util.styleText)("bold", session.user_code)}`
97
+ ].join("\n"));
58
98
  if (autoOpen) openInBrowser(session.verification_uri_complete);
59
- spinner.start("Waiting for approval");
99
+ const deadline = Date.now() + (session.expires_in > 0 ? session.expires_in : 600) * 1e3;
100
+ let copied = false;
101
+ const waitingText = () => `Waiting for approval ${(0, node_util.styleText)("dim", `expires in ${formatCountdown(deadline - Date.now())}${copied ? " · code copied" : ""} · ctrl+c to cancel`)}`;
102
+ clearInterval(countdown);
103
+ spinner.start(waitingText());
60
104
  waiting = true;
105
+ if (require_text.isRichOutput()) countdown = setInterval(() => Date.now() > retryUntil && spinner.message(waitingText()), 1e3);
106
+ copyToClipboard(session.user_code).then((done) => {
107
+ copied = done;
108
+ });
61
109
  },
62
- onRetry: (error) => spinner.message(`Could not reach Kubb Studio, retrying: ${error.message}`)
110
+ onRetry: (error) => {
111
+ retryUntil = Date.now() + 5e3;
112
+ spinner.message(`Could not reach Kubb Studio, retrying: ${error.message}`);
113
+ }
63
114
  });
64
- spinner.stop(`Paired as ${agent.name}`);
115
+ clearInterval(countdown);
116
+ spinner.stop(`Paired as ${agent.name}${agent.organizationSlug ? ` · org ${agent.organizationSlug}` : ""}`);
65
117
  const keepsIdentity = previousCredentials?.studioUrl === studioUrl && previousCredentials.agentId === agent.id;
66
118
  const credentials = {
67
119
  studioUrl,
68
120
  token,
69
121
  agentId: agent.id,
70
122
  agentSlug: agent.slug,
123
+ ...agent.organizationSlug ? { organizationSlug: agent.organizationSlug } : {},
71
124
  ...keepsIdentity && previousCredentials?.projects ? { projects: previousCredentials.projects } : {}
72
125
  };
73
126
  await require_credentials.writeCredentials(credentials);
74
127
  console.log(`Credentials stored in ${require_credentials.getCredentialsPath()}`);
75
128
  return credentials;
76
129
  } catch (error) {
130
+ clearInterval(countdown);
77
131
  if (waiting) spinner.stop(error instanceof _kubb_studio.PairingCanceledError ? "Pairing canceled" : "Pairing failed");
78
132
  throw error;
79
133
  }
80
134
  }
135
+ /** Time left on a pairing code as `m:ss`, never below `0:00`. */
136
+ function formatCountdown(ms) {
137
+ const seconds = Math.max(0, Math.ceil(ms / 1e3));
138
+ return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
139
+ }
81
140
  /**
82
- * What each permission is asked as, in the order the questions appear.
141
+ * What each permission is asked as, in the order the list shows them.
83
142
  */
84
143
  const PERMISSIONS = [
85
144
  {
86
145
  key: _kubb_studio_protocol.AgentPermission.READ,
87
- label: "read generated files",
88
- question: () => "Let Kubb Studio read the files a generation produced?"
146
+ label: "read source",
147
+ title: () => "Read generated files",
148
+ hint: "show code in the browser"
89
149
  },
90
150
  {
91
151
  key: _kubb_studio_protocol.AgentPermission.READ_AST,
92
- label: "read parsed spec",
93
- question: () => "Let Kubb Studio read the parsed spec (the Kubb AST)?"
152
+ label: "read spec",
153
+ title: () => "Read the parsed spec",
154
+ hint: "browse schemas and operations"
94
155
  },
95
156
  {
96
157
  key: _kubb_studio_protocol.AgentPermission.WRITE,
97
- label: "write generated files",
98
- question: (project) => `Let Kubb Studio write generated files into ${project}?`
158
+ label: "write files",
159
+ title: () => "Write files to disk",
160
+ hint: "generate from the browser"
99
161
  },
100
162
  {
101
163
  key: _kubb_studio_protocol.AgentPermission.CONFIG_EDIT,
102
- label: "edit kubb.config.ts",
103
- question: (_project, configPath) => `Let Kubb Studio change plugin options in ${configPath}?`
164
+ label: "edit config",
165
+ title: (configPath) => `Change ${configPath}`,
166
+ hint: "edit plugin options"
104
167
  },
105
168
  {
106
169
  key: _kubb_studio_protocol.AgentPermission.EXEC,
107
- label: "run formatter, linter, postGenerate",
108
- question: () => "Let Kubb Studio run the formatter, the linter, and output.postGenerate?"
170
+ label: "run tools",
171
+ title: () => "Run the formatter, linter, and postGenerate",
172
+ hint: "after each generation"
109
173
  }
110
174
  ];
111
175
  /**
112
- * One row per permission, for the connect banner and `kubb studio status`. A list rather than a
113
- * joined line: four labels this long read as one run-on sentence side by side.
176
+ * Two permissions per row, each marked granted or not, with the flags that grant the missing ones
177
+ * after the last row. For `kubb studio status`.
114
178
  */
115
179
  function formatPermissionRows(granted) {
116
- return PERMISSIONS.map(({ key, label }) => `${granted[key] ? (0, node_util.styleText)("green", "✔") : (0, node_util.styleText)("red", "✘")} ${label}`);
180
+ const width = Math.max(...PERMISSIONS.map(({ label }) => label.length));
181
+ const cells = PERMISSIONS.map(({ key, label }) => `${granted[key] ? (0, node_util.styleText)("green", "✓") : (0, node_util.styleText)("red", "✖")} ${label.padEnd(width)}`);
182
+ const rows = Array.from({ length: Math.ceil(cells.length / 2) }, (_, index) => cells.slice(index * 2, index * 2 + 2).join(" "));
183
+ const flags = PERMISSIONS.filter(({ key }) => !granted[key]).map(({ key }) => require_text.toPermissionFlag(key)).join(" ");
184
+ return flags ? [...rows.slice(0, -1), `${rows.at(-1)} ${(0, node_util.styleText)("dim", flags)}`] : rows;
117
185
  }
118
186
  /**
119
187
  * Resolves Studio permissions for the current project.
120
- * Flags win, saved answers are reused, and new answers are stored in `~/.kubb/credentials.json`.
188
+ * Flags win, saved answers are reused, and the rest are asked in one list whose answers are stored
189
+ * in `~/.kubb/credentials.json`.
121
190
  */
122
- async function resolvePermissions(options, credentials, configPath = require_output.KUBB_CONFIG_FILENAME) {
191
+ async function resolvePermissions(options, credentials, configPath = require_config.KUBB_CONFIG_FILENAME) {
123
192
  const project = node_process.default.cwd();
124
193
  const remembered = credentials.projects?.[project];
125
- const granted = {
126
- allowRead: false,
127
- allowReadAst: false,
128
- allowWrite: false,
129
- allowConfigEdit: false,
130
- allowExec: false
131
- };
132
- const answers = {};
194
+ const granted = Object.fromEntries(PERMISSIONS.map(({ key }) => [key, options.permission[key] || remembered?.[key] === true]));
195
+ const pending = PERMISSIONS.filter(({ key }) => !options.permission[key] && typeof remembered?.[key] !== "boolean");
196
+ if (!pending.length || require_Telemetry.isCIEnvironment() || !require_text.canUseTTY()) return granted;
133
197
  _clack_prompts.updateSettings({ withGuide: true });
134
- for (const { key, question } of PERMISSIONS) {
135
- if (options.permission[key] || typeof remembered?.[key] === "boolean") {
136
- granted[key] = options.permission[key] || remembered?.[key] === true;
137
- continue;
138
- }
139
- if (require_Telemetry.isCIEnvironment() || !require_output.canUseTTY()) {
140
- granted[key] = false;
141
- continue;
142
- }
143
- granted[key] = await _clack_prompts.confirm({
144
- message: question(project, configPath),
145
- initialValue: false
146
- }) === true;
147
- answers[key] = granted[key];
148
- }
149
- if (Object.keys(answers).length) await require_credentials.writeCredentials({
198
+ const selected = await _clack_prompts.multiselect({
199
+ message: "What may Kubb Studio do in this project?",
200
+ options: pending.map(({ key, title, hint }) => ({
201
+ value: key,
202
+ label: title(configPath),
203
+ hint
204
+ })),
205
+ required: false
206
+ });
207
+ if (_clack_prompts.isCancel(selected)) return granted;
208
+ const answers = Object.fromEntries(pending.map(({ key }) => [key, selected.includes(key)]));
209
+ await require_credentials.writeCredentials({
150
210
  ...credentials,
151
211
  projects: {
152
212
  ...credentials.projects,
@@ -156,7 +216,10 @@ async function resolvePermissions(options, credentials, configPath = require_out
156
216
  }
157
217
  }
158
218
  });
159
- return granted;
219
+ return {
220
+ ...granted,
221
+ ...answers
222
+ };
160
223
  }
161
224
  /**
162
225
  * Loads the project's Kubb config the same way `kubb generate` does.
@@ -178,14 +241,6 @@ async function loadConfigs(options) {
178
241
  config
179
242
  };
180
243
  }
181
- /**
182
- * Explains a rejected token to the operator. Builds the error and nothing else, so each caller
183
- * decides what happens to the credentials.
184
- */
185
- function explainRejectedToken(error, reason) {
186
- if (reason === "reauthExhausted") return /* @__PURE__ */ new Error(`${error.message} Studio rejected the newly approved token too. Run \`kubb studio login\` and try again.`);
187
- return /* @__PURE__ */ new Error(`${error.message} Run \`kubb studio login\` to pair again.`);
188
- }
189
244
  /** Validates the project and resolves pairing and permissions before starting its worker. */
190
245
  async function prepareConnection(options, signal) {
191
246
  const { configPath } = await loadConfigs(options);
@@ -215,9 +270,10 @@ async function connect(options, context = {}) {
215
270
  events.once("SIGINT", stop);
216
271
  events.once("SIGTERM", stop);
217
272
  }
273
+ let unwatch;
218
274
  try {
219
275
  if (!context.prepared) {
220
- const { getWorkerStatus } = await Promise.resolve().then(() => require("./background-mKdZ5HRx.cjs"));
276
+ const { getWorkerStatus } = await Promise.resolve().then(() => require("./background-CaZZul1n.cjs"));
221
277
  if ((await getWorkerStatus()).running) throw new _kubb_core.Diagnostics.Error({
222
278
  code: _kubb_core.Diagnostics.code.unknown,
223
279
  severity: "error",
@@ -230,18 +286,27 @@ async function connect(options, context = {}) {
230
286
  let hinted = false;
231
287
  let pairedAgain = false;
232
288
  const hooks = new _kubb_core.Hookable();
233
- require_config.setupReporters(hooks, {
289
+ require_reporters.setupReporters(hooks, {
234
290
  logLevel: _kubb_core.logLevel[options.logLevel ?? "info"],
235
291
  reporters: [_kubb_core.cliReporter],
236
- ...context.onState ? { logger: require_output.plainLogger } : {}
292
+ ...context.onState ? { writer: require_text.plainWriter } : {}
237
293
  });
294
+ const listens = !context.onState && node_process.default.stdin.isTTY === true && require_text.canUseTTY();
295
+ let background = false;
238
296
  hooks.hook("studio:connected", async () => {
239
297
  pairedAgain = false;
240
298
  await context.onState?.("connected");
299
+ if (listens && !unwatch) unwatch = watchKeys({
300
+ onBackground: () => {
301
+ background = true;
302
+ stop();
303
+ },
304
+ onStop: stop
305
+ });
241
306
  if (hinted || context.onState || options.logLevel === "silent") return;
242
307
  hinted = true;
243
- require_output.logBlock((0, node_util.styleText)("dim", "Press Ctrl+C to disconnect"));
244
- require_output.logTip();
308
+ require_text.logBlock([`${(0, node_util.styleText)("dim", "Project")} ${node_path.default.basename(node_process.default.cwd())} ${(0, node_util.styleText)("dim", PERMISSIONS.filter(({ key }) => permissions[key]).map(({ label }) => label).join(" · ") || "no permissions")}`, (0, node_util.styleText)("dim", listens ? "Press b to keep running in the background, Ctrl+C to disconnect" : "Press Ctrl+C to disconnect")]);
309
+ require_text.logTip();
245
310
  });
246
311
  hooks.hook("studio:reconnecting", () => context.onState?.("reconnecting"));
247
312
  for (;;) try {
@@ -261,8 +326,10 @@ async function connect(options, context = {}) {
261
326
  if (!(error instanceof _kubb_studio.InvalidAgentTokenError)) throw error;
262
327
  await context.onState?.("authentication required");
263
328
  await require_credentials.clearCredentials();
264
- if (pairedAgain) throw explainRejectedToken(error, "reauthExhausted");
265
- if (context.onState || require_Telemetry.isCIEnvironment() || !require_output.canUseTTY()) throw explainRejectedToken(error, "nonInteractive");
329
+ if (pairedAgain) throw new Error(`${error.message} Studio rejected the newly approved token too. Run \`kubb studio login\` and try again.`);
330
+ if (context.onState || require_Telemetry.isCIEnvironment() || !require_text.canUseTTY()) throw new Error(`${error.message} Run \`kubb studio login\` to pair again.`);
331
+ unwatch?.();
332
+ unwatch = void 0;
266
333
  console.log((0, node_util.styleText)("yellow", `${error.message} Pairing again...`));
267
334
  credentials = await login(options, {
268
335
  signal,
@@ -271,15 +338,50 @@ async function connect(options, context = {}) {
271
338
  pairedAgain = true;
272
339
  permissions = await resolvePermissions(options, credentials, configPath);
273
340
  }
274
- if (!context.onState && signal.aborted && options.logLevel !== "silent") require_output.logOutro("Disconnected");
341
+ await hooks.callHook("kubb:lifecycle:end");
342
+ unwatch?.();
343
+ if (background) {
344
+ const { startWorker } = await Promise.resolve().then(() => require("./background-CaZZul1n.cjs"));
345
+ await startWorker(options);
346
+ if (options.logLevel !== "silent") require_text.logOutro("Running in the background · kubb studio stop");
347
+ return;
348
+ }
349
+ if (!context.onState && signal.aborted && options.logLevel !== "silent") require_text.logOutro("Disconnected");
275
350
  } catch (error) {
276
351
  if (!(error instanceof _kubb_studio.PairingCanceledError)) throw error;
277
352
  } finally {
353
+ unwatch?.();
278
354
  events.off("SIGINT", stop);
279
355
  events.off("SIGTERM", stop);
280
356
  }
281
357
  }
282
358
  /**
359
+ * Listens for single keys on a TTY stdin. Raw mode turns Ctrl+C into a key instead of SIGINT, so it
360
+ * is handled here too. Returns the function that restores the terminal, safe to call twice.
361
+ */
362
+ function watchKeys({ onBackground, onStop }) {
363
+ const stdin = node_process.default.stdin;
364
+ const onData = (data) => {
365
+ const key = data.toString();
366
+ if (key === "b" || key === "B") onBackground();
367
+ if (key === "") onStop();
368
+ };
369
+ const cancelAlias = _clack_prompts.settings.aliases.get("");
370
+ _clack_prompts.settings.aliases.delete("");
371
+ stdin.setRawMode(true);
372
+ stdin.on("data", onData);
373
+ stdin.resume();
374
+ let restored = false;
375
+ return () => {
376
+ if (restored) return;
377
+ restored = true;
378
+ if (cancelAlias) _clack_prompts.settings.aliases.set("", cancelAlias);
379
+ stdin.off("data", onData);
380
+ stdin.setRawMode(false);
381
+ stdin.pause();
382
+ };
383
+ }
384
+ /**
283
385
  * Runs a Studio command from its parsed flags: builds the {@link StudioOptions}, prints the intro,
284
386
  * and reports the run to telemetry. A failure is printed and sets the exit code instead of throwing.
285
387
  */
@@ -288,13 +390,7 @@ async function runStudio(values, action, { block = false, json = false } = {}) {
288
390
  version: require_Telemetry.version,
289
391
  configPath: values.config,
290
392
  studioUrl: values.url ?? _kubb_studio.defaultStudioUrl,
291
- permission: {
292
- allowRead: values.allowRead ?? false,
293
- allowReadAst: values.allowReadAst ?? false,
294
- allowWrite: values.allowWrite ?? false,
295
- allowConfigEdit: values.allowConfigEdit ?? false,
296
- allowExec: values.allowExec ?? false
297
- },
393
+ permission: Object.fromEntries(Object.values(_kubb_studio_protocol.AgentPermission).map((key) => [key, values[key] ?? false])),
298
394
  autoOpen: values.open ?? true,
299
395
  logLevel: values.logLevel
300
396
  };
@@ -303,7 +399,7 @@ async function runStudio(values, action, { block = false, json = false } = {}) {
303
399
  hrStart: node_process.default.hrtime()
304
400
  });
305
401
  try {
306
- if (options.logLevel !== "silent" && !json) require_output.logIntro({
402
+ if (options.logLevel !== "silent" && !json) require_text.logIntro({
307
403
  warning: (0, node_util.styleText)("yellow", "This feature is still under development, use with caution"),
308
404
  block
309
405
  });
@@ -311,7 +407,7 @@ async function runStudio(values, action, { block = false, json = false } = {}) {
311
407
  await report({ status: "success" });
312
408
  } catch (error) {
313
409
  await report({ status: "failed" });
314
- console.error(require_Telemetry.toError(error).message);
410
+ console.error(require_errors.toError(error).message);
315
411
  node_process.default.exitCode = 1;
316
412
  }
317
413
  }
@@ -323,4 +419,4 @@ exports.login = login;
323
419
  exports.prepareConnection = prepareConnection;
324
420
  exports.runStudio = runStudio;
325
421
 
326
- //# sourceMappingURL=run-BWRmQxtE.cjs.map
422
+ //# sourceMappingURL=run-DkBJkKor.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-DkBJkKor.cjs","names":["process","isCIEnvironment","x","isCIEnvironment","process","createSpinner","pairAgent","path","process","hostname","getMachineId","styleText","isRichOutput","writeCredentials","getCredentialsPath","PairingCanceledError","AgentPermission","toPermissionFlag","KUBB_CONFIG_FILENAME","isCIEnvironment","canUseTTY","prompts","getConfigs","Diagnostics","readCredentials","Hookable","logLevelMap","cliReporter","plainWriter","connectAgent","InvalidAgentTokenError","clearCredentials","defaultStudioUrl","trackRun","toError"],"sources":["../../../internals/utils/src/copyToClipboard.ts","../../../internals/utils/src/openInBrowser.ts","../src/runners/studio/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { x } from 'tinyexec'\nimport { isCIEnvironment } from './isCIEnvironment.ts'\n\nconst COMMANDS: Partial<Record<NodeJS.Platform, [string, ...Array<string>]>> = {\n darwin: ['pbcopy'],\n win32: ['clip.exe'],\n linux: ['xclip', '-selection', 'clipboard'],\n}\n\n/**\n * Copies text to the system clipboard with the platform's own tool. Resolves `false` in CI, on a\n * platform without a known tool, or when the tool is missing or fails.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n // Wayland sessions have no X selection for xclip to serve, so they use `wl-copy`.\n const command = process.platform === 'linux' && process.env.WAYLAND_DISPLAY ? (['wl-copy'] as const) : COMMANDS[process.platform]\n if (!command || isCIEnvironment()) return false\n\n const [name, ...args] = command\n // stdout and stderr are ignored: xclip and wl-copy stay alive to serve the selection and would hold open pipes until the timeout.\n const run = x(name, args, { timeout: 2_000, nodeOptions: { stdio: ['pipe', 'ignore', 'ignore'] } })\n // A missing tool closes stdin before the write lands; the rejection below reports it.\n run.process?.stdin?.once('error', () => {})\n run.process?.stdin?.end(text)\n\n return run.then(\n ({ exitCode }) => exitCode === 0,\n () => false,\n )\n}\n","import process from 'node:process'\nimport { x } from 'tinyexec'\nimport { isCIEnvironment } from './isCIEnvironment.ts'\n\nconst ignore = () => {}\n\n/**\n * Opens a URL or local file in the default browser, unless running in CI.\n */\nexport function openInBrowser(target: string): void {\n if (isCIEnvironment()) return\n\n if (process.platform === 'win32') {\n x('cmd', ['/c', 'start', '', target]).then(ignore, ignore)\n return\n }\n x(process.platform === 'darwin' ? 'open' : 'xdg-open', [target]).then(ignore, ignore)\n}\n","import { hostname } from 'node:os'\nimport { toPermissionFlag } from '../../ui/text.ts'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as prompts from '@clack/prompts'\nimport { KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { copyToClipboard, isCIEnvironment, openInBrowser, toError } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\nimport { cliReporter, Diagnostics, Hookable, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'\nimport { connectAgent, defaultStudioUrl, InvalidAgentTokenError, pairAgent, PairingCanceledError } from '@kubb/studio'\nimport { AgentPermission } from '@kubb/studio/protocol'\nimport { trackRun } from '../../Telemetry.ts'\nimport { plainWriter } from '../../loggers/plainWriter.ts'\nimport setupReporters from '../../loggers/reporters.ts'\nimport { logIntro, logOutro, logTip } from '../../ui/intro.ts'\nimport { logBlock, logStep } from '../../ui/log.ts'\nimport { createSpinner } from '../../ui/spinner.ts'\nimport { canUseTTY, isRichOutput } from '../../utils/env.ts'\nimport { getConfigs } from '../../config.ts'\nimport { clearCredentials, type Credentials, getCredentialsPath, getMachineId, readCredentials, writeCredentials } from './credentials.ts'\nimport { version } from '../../../package.json'\n\nexport type StudioOptions = {\n /**\n * Current `@kubb/cli` version, reported to Studio and used for the telemetry payload.\n */\n version: string\n configPath?: string\n /**\n * Base URL of the Studio instance, for a self-hosted deployment. Resolved before it reaches here,\n * since stored credentials are bound to it.\n */\n studioUrl: string\n /**\n * What Studio may do in this project. Each flag grants outright; the rest are asked once per\n * project through {@link resolvePermissions}.\n */\n permission: Record<AgentPermission, boolean>\n /**\n * Whether to open the approval page in a browser during pairing.\n */\n autoOpen: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\nexport type SnapshotOptions = Pick<StudioOptions, 'configPath' | 'studioUrl' | 'logLevel'> & {\n /**\n * Organization CI API key. Falls back to `KUBB_TOKEN`.\n */\n token?: string\n /**\n * Stable identity for the CI agent. Falls back to CI auto-detection.\n */\n id?: string\n /** Identity of another CI agent to also compare with. Falls back to CI auto-detection. */\n baseId?: string\n /**\n * Package name for the generated tarball. Falls back to the nearest package.json.\n */\n name?: string\n /**\n * Package version for the generated tarball. Falls back to the nearest package.json.\n */\n packageVersion?: string\n /**\n * Print the result as one JSON object instead of a summary.\n */\n json?: boolean\n}\n\n/** The flags a `kubb studio` subcommand parsed; each one is optional since a subcommand declares only the flags it uses. */\nexport type StudioValues = {\n config?: string\n url?: string\n allowRead?: boolean\n allowReadAst?: boolean\n allowWrite?: boolean\n allowConfigEdit?: boolean\n allowExec?: boolean\n open?: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\ntype LoginOptions = {\n /**\n * Aborting this cancels an in-flight pairing request or poll and rejects with\n * {@link PairingCanceledError}. Wired to `kubb studio`'s shutdown signal, so Ctrl+C during\n * pairing cancels it instead of leaving the poll running.\n */\n signal?: AbortSignal\n /**\n * Credentials from before this login. When the fresh pairing resolves to the same agent on the\n * same Studio, its saved project permissions carry forward instead of being asked again.\n * Left out for an explicitly requested `kubb studio login`, which always starts clean.\n */\n previousCredentials?: Credentials | null\n}\n\n/**\n * Pairs this machine with Studio and stores the resulting token.\n *\n * The CLI holds a code and the browser approves it, rather than the user copying a token out of\n * the UI. The token comes back over the CLI's own HTTPS POST, so it never lands in a URL, a\n * server log, or a `Referer` header.\n */\nexport async function login({ studioUrl, autoOpen }: StudioOptions, { signal, previousCredentials }: LoginOptions = {}): Promise<Credentials> {\n const spinner = createSpinner()\n // A retry notice stays on screen a while before the countdown takes the line back.\n let retryUntil = 0\n // The spinner only starts once a code is shown.\n let waiting = false\n let countdown: NodeJS.Timeout | undefined\n\n try {\n const { token, agent } = await pairAgent({\n studioUrl,\n type: 'cli',\n name: path.basename(process.cwd()),\n hostname: hostname(),\n machineId: await getMachineId(),\n signal,\n onCode: (session) => {\n logStep(\n [\n 'Pair this machine',\n `${styleText('dim', 'Open')} ${styleText('cyan', session.verification_uri)}`,\n `${styleText('dim', 'Code')} ${styleText('bold', session.user_code)}`,\n ].join('\\n'),\n )\n\n if (autoOpen) {\n openInBrowser(session.verification_uri_complete)\n }\n\n // Same fallback as the poll in `@kubb/studio`, so the countdown ends when polling does.\n const deadline = Date.now() + (session.expires_in > 0 ? session.expires_in : 600) * 1000\n let copied = false\n const waitingText = () =>\n `Waiting for approval ${styleText('dim', `expires in ${formatCountdown(deadline - Date.now())}${copied ? ' · code copied' : ''} · ctrl+c to cancel`)}`\n clearInterval(countdown)\n spinner.start(waitingText())\n waiting = true\n // Plain output prints every message, so only an animated spinner ticks.\n if (isRichOutput()) countdown = setInterval(() => Date.now() > retryUntil && spinner.message(waitingText()), 1000)\n // Not awaited: the code shows at once, and the spinner picks up the copy when it lands.\n void copyToClipboard(session.user_code).then((done) => {\n copied = done\n })\n },\n onRetry: (error) => {\n retryUntil = Date.now() + 5000\n spinner.message(`Could not reach Kubb Studio, retrying: ${error.message}`)\n },\n })\n clearInterval(countdown)\n spinner.stop(`Paired as ${agent.name}${agent.organizationSlug ? ` · org ${agent.organizationSlug}` : ''}`)\n\n const keepsIdentity = previousCredentials?.studioUrl === studioUrl && previousCredentials.agentId === agent.id\n const credentials: Credentials = {\n studioUrl,\n token,\n agentId: agent.id,\n agentSlug: agent.slug,\n ...(agent.organizationSlug ? { organizationSlug: agent.organizationSlug } : {}),\n ...(keepsIdentity && previousCredentials?.projects ? { projects: previousCredentials.projects } : {}),\n }\n await writeCredentials(credentials)\n\n console.log(`Credentials stored in ${getCredentialsPath()}`)\n\n return credentials\n } catch (error) {\n clearInterval(countdown)\n if (waiting) {\n spinner.stop(error instanceof PairingCanceledError ? 'Pairing canceled' : 'Pairing failed')\n }\n throw error\n }\n}\n\n/** Time left on a pairing code as `m:ss`, never below `0:00`. */\nexport function formatCountdown(ms: number): string {\n const seconds = Math.max(0, Math.ceil(ms / 1000))\n\n return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`\n}\n\n/**\n * What each permission is asked as, in the order the list shows them.\n */\nconst PERMISSIONS: ReadonlyArray<{\n key: AgentPermission\n /**\n * Short label for status output and the connect summary.\n */\n label: string\n title: (configPath: string) => string\n hint: string\n}> = [\n { key: AgentPermission.READ, label: 'read source', title: () => 'Read generated files', hint: 'show code in the browser' },\n { key: AgentPermission.READ_AST, label: 'read spec', title: () => 'Read the parsed spec', hint: 'browse schemas and operations' },\n { key: AgentPermission.WRITE, label: 'write files', title: () => 'Write files to disk', hint: 'generate from the browser' },\n { key: AgentPermission.CONFIG_EDIT, label: 'edit config', title: (configPath) => `Change ${configPath}`, hint: 'edit plugin options' },\n { key: AgentPermission.EXEC, label: 'run tools', title: () => 'Run the formatter, linter, and postGenerate', hint: 'after each generation' },\n]\n\n/**\n * Two permissions per row, each marked granted or not, with the flags that grant the missing ones\n * after the last row. For `kubb studio status`.\n */\nexport function formatPermissionRows(granted: Partial<Record<AgentPermission, boolean>>): Array<string> {\n const width = Math.max(...PERMISSIONS.map(({ label }) => label.length))\n const cells = PERMISSIONS.map(({ key, label }) => `${granted[key] ? styleText('green', '✓') : styleText('red', '✖')} ${label.padEnd(width)}`)\n const rows = Array.from({ length: Math.ceil(cells.length / 2) }, (_, index) => cells.slice(index * 2, index * 2 + 2).join(' '))\n const flags = PERMISSIONS.filter(({ key }) => !granted[key])\n .map(({ key }) => toPermissionFlag(key))\n .join(' ')\n\n return flags ? [...rows.slice(0, -1), `${rows.at(-1)} ${styleText('dim', flags)}`] : rows\n}\n\n/**\n * Resolves Studio permissions for the current project.\n * Flags win, saved answers are reused, and the rest are asked in one list whose answers are stored\n * in `~/.kubb/credentials.json`.\n */\nexport async function resolvePermissions(\n options: StudioOptions,\n credentials: Credentials,\n configPath: string = KUBB_CONFIG_FILENAME,\n): Promise<Record<AgentPermission, boolean>> {\n const project = process.cwd()\n const remembered = credentials.projects?.[project]\n const granted = Object.fromEntries(PERMISSIONS.map(({ key }) => [key, options.permission[key] || remembered?.[key] === true])) as Record<\n AgentPermission,\n boolean\n >\n const pending = PERMISSIONS.filter(({ key }) => !options.permission[key] && typeof remembered?.[key] !== 'boolean')\n\n if (!pending.length || isCIEnvironment() || !canUseTTY()) return granted\n\n prompts.updateSettings({ withGuide: true })\n const selected = await prompts.multiselect({\n message: 'What may Kubb Studio do in this project?',\n options: pending.map(({ key, title, hint }) => ({ value: key, label: title(configPath), hint })),\n required: false,\n })\n // A canceled list grants nothing and saves nothing, so the next run asks again.\n if (prompts.isCancel(selected)) return granted\n\n const answers = Object.fromEntries(pending.map(({ key }) => [key, selected.includes(key)]))\n await writeCredentials({\n ...credentials,\n projects: { ...credentials.projects, [project]: { ...remembered, ...answers } },\n })\n\n return { ...granted, ...answers }\n}\n\n/**\n * Loads the project's Kubb config the same way `kubb generate` does.\n * Returns the first config.\n */\nexport async function loadConfigs(options: Pick<StudioOptions, 'configPath' | 'logLevel'>): Promise<{ configPath: string; config: Config }> {\n const { configPath, configs } = await getConfigs({ configPath: options.configPath, logLevel: options.logLevel })\n const [config] = configs\n\n if (!config) {\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'Config not defined, create a kubb.config.ts or pass it with --config',\n })\n }\n\n // `getConfigs` resolves this to an absolute path. Relativized here, once, so the permission\n // prompt and the path Studio receives over the wire both show the project-relative form instead\n // of leaking the local filesystem layout.\n return { configPath: path.relative(process.cwd(), configPath) || configPath, config }\n}\n\nexport type PreparedConnection = {\n configPath: string\n credentials: Credentials\n permissions: StudioOptions['permission']\n}\n\n/** Validates the project and resolves pairing and permissions before starting its worker. */\nexport async function prepareConnection(options: StudioOptions, signal?: AbortSignal): Promise<PreparedConnection> {\n const { configPath } = await loadConfigs(options)\n const stored = await readCredentials()\n const credentials = await (async () => {\n if (stored?.studioUrl === options.studioUrl) return stored\n if (isCIEnvironment()) {\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: `Not paired with ${options.studioUrl}. In CI, run \\`kubb studio snapshot\\` instead, or run \\`kubb studio login\\` on a machine with a browser.`,\n })\n }\n return login(options, { signal })\n })()\n const permissions = await resolvePermissions(options, credentials, configPath)\n return { configPath, credentials, permissions }\n}\n\nexport type WorkerState = 'starting' | 'connected' | 'reconnecting' | 'authentication required' | 'stopped'\n\n/** Runs the same project connection in the foreground or in a background worker. */\nexport async function connect(\n options: StudioOptions,\n context: {\n prepared?: PreparedConnection\n signal?: AbortSignal\n onState?: (state: WorkerState) => void | Promise<void>\n } = {},\n): Promise<void> {\n const shutdown = new AbortController()\n const signal = context.signal ?? shutdown.signal\n const stop = () => shutdown.abort()\n const events = process as unknown as NodeJS.EventEmitter\n if (!context.signal) {\n events.once('SIGINT', stop)\n events.once('SIGTERM', stop)\n }\n let unwatch: (() => void) | undefined\n try {\n if (!context.prepared) {\n const { getWorkerStatus } = await import('./background.ts')\n const worker = await getWorkerStatus()\n if (worker.running)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'This project is running in the background. Run `kubb studio stop` first.',\n })\n }\n const prepared = context.prepared ?? (await prepareConnection(options, signal))\n let { credentials, permissions } = prepared\n const { configPath } = prepared\n let hinted = false\n // Set by a fresh pairing until it connects, so a token rejected right after approval fails the run instead of looping.\n let pairedAgain = false\n\n // The background worker writes to a log file, so it gets the plain logger rather than the\n // animated one. The logger also covers the `studio:*` events and each generation run.\n const hooks = new Hookable<KubbHooks>()\n setupReporters(hooks, {\n logLevel: logLevelMap[options.logLevel ?? 'info'],\n reporters: [cliReporter],\n ...(context.onState ? { writer: plainWriter } : {}),\n })\n // `b` hands the session to the background worker; only a foreground run in a terminal listens.\n const listens = !context.onState && process.stdin.isTTY === true && canUseTTY()\n let background = false\n hooks.hook('studio:connected', async () => {\n pairedAgain = false\n await context.onState?.('connected')\n if (listens && !unwatch) {\n unwatch = watchKeys({\n onBackground: () => {\n background = true\n stop()\n },\n onStop: stop,\n })\n }\n if (hinted || context.onState || options.logLevel === 'silent') return\n hinted = true\n logBlock([\n `${styleText('dim', 'Project')} ${path.basename(process.cwd())} ${styleText(\n 'dim',\n PERMISSIONS.filter(({ key }) => permissions[key])\n .map(({ label }) => label)\n .join(' · ') || 'no permissions',\n )}`,\n styleText('dim', listens ? 'Press b to keep running in the background, Ctrl+C to disconnect' : 'Press Ctrl+C to disconnect'),\n ])\n logTip()\n })\n hooks.hook('studio:reconnecting', () => context.onState?.('reconnecting'))\n\n for (;;) {\n try {\n await connectAgent({\n token: credentials.token,\n studioUrl: options.studioUrl,\n configPath,\n version: options.version,\n root: process.cwd(),\n permissions,\n loadConfig: async () => (await loadConfigs(options)).config,\n hooks,\n signal,\n })\n break\n } catch (error) {\n if (!(error instanceof InvalidAgentTokenError)) throw error\n await context.onState?.('authentication required')\n await clearCredentials()\n if (pairedAgain) throw new Error(`${error.message} Studio rejected the newly approved token too. Run \\`kubb studio login\\` and try again.`)\n if (context.onState || isCIEnvironment() || !canUseTTY()) throw new Error(`${error.message} Run \\`kubb studio login\\` to pair again.`)\n\n // The pairing prompts need stdin back.\n unwatch?.()\n unwatch = undefined\n console.log(styleText('yellow', `${error.message} Pairing again...`))\n credentials = await login(options, { signal, previousCredentials: credentials })\n pairedAgain = true\n permissions = await resolvePermissions(options, credentials, configPath)\n }\n }\n // Stops the \"Ready for jobs\" spinner, which would otherwise keep drawing under the closing line.\n await hooks.callHook('kubb:lifecycle:end')\n unwatch?.()\n if (background) {\n const { startWorker } = await import('./background.ts')\n await startWorker(options)\n if (options.logLevel !== 'silent') logOutro('Running in the background · kubb studio stop')\n return\n }\n if (!context.onState && signal.aborted && options.logLevel !== 'silent') logOutro('Disconnected')\n } catch (error) {\n if (!(error instanceof PairingCanceledError)) throw error\n } finally {\n unwatch?.()\n events.off('SIGINT', stop)\n events.off('SIGTERM', stop)\n }\n}\n\n/**\n * Listens for single keys on a TTY stdin. Raw mode turns Ctrl+C into a key instead of SIGINT, so it\n * is handled here too. Returns the function that restores the terminal, safe to call twice.\n */\nexport function watchKeys({ onBackground, onStop }: { onBackground: () => void; onStop: () => void }): () => void {\n const stdin = process.stdin\n const onData = (data: Buffer) => {\n const key = data.toString()\n if (key === 'b' || key === 'B') onBackground()\n if (key === '\\u0003') onStop()\n }\n // A clack spinner reads stdin too and exits the process on Ctrl+C, before the session can close\n // its socket, so its Ctrl+C alias is lifted while these keys are read.\n const cancelAlias = prompts.settings.aliases.get('\\u0003')\n prompts.settings.aliases.delete('\\u0003')\n stdin.setRawMode(true)\n stdin.on('data', onData)\n stdin.resume()\n let restored = false\n\n return () => {\n if (restored) return\n restored = true\n if (cancelAlias) prompts.settings.aliases.set('\\u0003', cancelAlias)\n stdin.off('data', onData)\n stdin.setRawMode(false)\n stdin.pause()\n }\n}\n\n/**\n * Runs a Studio command from its parsed flags: builds the {@link StudioOptions}, prints the intro,\n * and reports the run to telemetry. A failure is printed and sets the exit code instead of throwing.\n */\nexport async function runStudio(\n values: StudioValues,\n action: (options: StudioOptions) => Promise<unknown>,\n { block = false, json = false }: { block?: boolean; json?: boolean } = {},\n): Promise<void> {\n const options: StudioOptions = {\n version,\n configPath: values.config,\n studioUrl: values.url ?? defaultStudioUrl,\n permission: Object.fromEntries(Object.values(AgentPermission).map((key) => [key, values[key] ?? false])) as Record<AgentPermission, boolean>,\n autoOpen: values.open ?? true,\n logLevel: values.logLevel,\n }\n const report = trackRun({ command: 'studio', hrStart: process.hrtime() })\n\n try {\n if (options.logLevel !== 'silent' && !json) {\n logIntro({\n warning: styleText('yellow', 'This feature is still under development, use with caution'),\n block,\n })\n }\n\n await action(options)\n\n await report({ status: 'success' })\n } catch (error) {\n await report({ status: 'failed' })\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,WAAyE;CAC7E,QAAQ,CAAC,QAAQ;CACjB,OAAO,CAAC,UAAU;CAClB,OAAO;EAAC;EAAS;EAAc;CAAW;AAC5C;;;;;AAMA,eAAsB,gBAAgB,MAAgC;CAEpE,MAAM,UAAUA,aAAAA,QAAQ,aAAa,WAAWA,aAAAA,QAAQ,IAAI,kBAAmB,CAAC,SAAS,IAAc,SAASA,aAAAA,QAAQ;CACxH,IAAI,CAAC,WAAWC,kBAAAA,gBAAgB,GAAG,OAAO;CAE1C,MAAM,CAAC,MAAM,GAAG,QAAQ;CAExB,MAAM,OAAA,GAAMC,SAAAA,EAAAA,CAAE,MAAM,MAAM;EAAE,SAAS;EAAO,aAAa,EAAE,OAAO;GAAC;GAAQ;GAAU;EAAQ,EAAE;CAAE,CAAC;CAElG,IAAI,SAAS,OAAO,KAAK,eAAe,CAAC,CAAC;CAC1C,IAAI,SAAS,OAAO,IAAI,IAAI;CAE5B,OAAO,IAAI,MACR,EAAE,eAAe,aAAa,SACzB,KACR;AACF;;;AC1BA,MAAM,eAAe,CAAC;;;;AAKtB,SAAgB,cAAc,QAAsB;CAClD,IAAIC,kBAAAA,gBAAgB,GAAG;CAEvB,IAAIC,aAAAA,QAAQ,aAAa,SAAS;EAChC,CAAA,GAAA,SAAA,EAAA,CAAE,OAAO;GAAC;GAAM;GAAS;GAAI;EAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,MAAM;EACzD;CACF;CACA,CAAA,GAAA,SAAA,EAAA,CAAEA,aAAAA,QAAQ,aAAa,WAAW,SAAS,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,MAAM;AACtF;;;;;;;;;;ACyFA,eAAsB,MAAM,EAAE,WAAW,YAA2B,EAAE,QAAQ,wBAAsC,CAAC,GAAyB;CAC5I,MAAM,UAAUC,cAAAA,cAAc;CAE9B,IAAI,aAAa;CAEjB,IAAI,UAAU;CACd,IAAI;CAEJ,IAAI;EACF,MAAM,EAAE,OAAO,UAAU,OAAA,GAAMC,aAAAA,UAAAA,CAAU;GACvC;GACA,MAAM;GACN,MAAMC,UAAAA,QAAK,SAASC,aAAAA,QAAQ,IAAI,CAAC;GACjC,WAAA,GAAUC,QAAAA,SAAAA,CAAS;GACnB,WAAW,MAAMC,oBAAAA,aAAa;GAC9B;GACA,SAAS,YAAY;IACnB,aAAA,QACE;KACE;KACA,IAAA,GAAGC,UAAAA,UAAAA,CAAU,OAAO,MAAM,EAAE,MAAA,GAAKA,UAAAA,UAAAA,CAAU,QAAQ,QAAQ,gBAAgB;KAC3E,IAAA,GAAGA,UAAAA,UAAAA,CAAU,OAAO,MAAM,EAAE,MAAA,GAAKA,UAAAA,UAAAA,CAAU,QAAQ,QAAQ,SAAS;IACtE,CAAC,CAAC,KAAK,IAAI,CACb;IAEA,IAAI,UACF,cAAc,QAAQ,yBAAyB;IAIjD,MAAM,WAAW,KAAK,IAAI,KAAK,QAAQ,aAAa,IAAI,QAAQ,aAAa,OAAO;IACpF,IAAI,SAAS;IACb,MAAM,oBACJ,0BAAA,GAAyBA,UAAAA,UAAAA,CAAU,OAAO,cAAc,gBAAgB,WAAW,KAAK,IAAI,CAAC,IAAI,SAAS,mBAAmB,GAAG,oBAAoB;IACtJ,cAAc,SAAS;IACvB,QAAQ,MAAM,YAAY,CAAC;IAC3B,UAAU;IAEV,IAAIC,aAAAA,aAAa,GAAG,YAAY,kBAAkB,KAAK,IAAI,IAAI,cAAc,QAAQ,QAAQ,YAAY,CAAC,GAAG,GAAI;IAEjH,gBAAqB,QAAQ,SAAS,CAAC,CAAC,MAAM,SAAS;KACrD,SAAS;IACX,CAAC;GACH;GACA,UAAU,UAAU;IAClB,aAAa,KAAK,IAAI,IAAI;IAC1B,QAAQ,QAAQ,0CAA0C,MAAM,SAAS;GAC3E;EACF,CAAC;EACD,cAAc,SAAS;EACvB,QAAQ,KAAK,aAAa,MAAM,OAAO,MAAM,mBAAmB,UAAU,MAAM,qBAAqB,IAAI;EAEzG,MAAM,gBAAgB,qBAAqB,cAAc,aAAa,oBAAoB,YAAY,MAAM;EAC5G,MAAM,cAA2B;GAC/B;GACA;GACA,SAAS,MAAM;GACf,WAAW,MAAM;GACjB,GAAI,MAAM,mBAAmB,EAAE,kBAAkB,MAAM,iBAAiB,IAAI,CAAC;GAC7E,GAAI,iBAAiB,qBAAqB,WAAW,EAAE,UAAU,oBAAoB,SAAS,IAAI,CAAC;EACrG;EACA,MAAMC,oBAAAA,iBAAiB,WAAW;EAElC,QAAQ,IAAI,yBAAyBC,oBAAAA,mBAAmB,GAAG;EAE3D,OAAO;CACT,SAAS,OAAO;EACd,cAAc,SAAS;EACvB,IAAI,SACF,QAAQ,KAAK,iBAAiBC,aAAAA,uBAAuB,qBAAqB,gBAAgB;EAE5F,MAAM;CACR;AACF;;AAGA,SAAgB,gBAAgB,IAAoB;CAClD,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,GAAI,CAAC;CAEhD,OAAO,GAAG,KAAK,MAAM,UAAU,EAAE,EAAE,GAAG,OAAO,UAAU,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG;AAC5E;;;;AAKA,MAAM,cAQD;CACH;EAAE,KAAKC,sBAAAA,gBAAgB;EAAM,OAAO;EAAe,aAAa;EAAwB,MAAM;CAA2B;CACzH;EAAE,KAAKA,sBAAAA,gBAAgB;EAAU,OAAO;EAAa,aAAa;EAAwB,MAAM;CAAgC;CAChI;EAAE,KAAKA,sBAAAA,gBAAgB;EAAO,OAAO;EAAe,aAAa;EAAuB,MAAM;CAA4B;CAC1H;EAAE,KAAKA,sBAAAA,gBAAgB;EAAa,OAAO;EAAe,QAAQ,eAAe,UAAU;EAAc,MAAM;CAAsB;CACrI;EAAE,KAAKA,sBAAAA,gBAAgB;EAAM,OAAO;EAAa,aAAa;EAA+C,MAAM;CAAwB;AAC7I;;;;;AAMA,SAAgB,qBAAqB,SAAmE;CACtG,MAAM,QAAQ,KAAK,IAAI,GAAG,YAAY,KAAK,EAAE,YAAY,MAAM,MAAM,CAAC;CACtE,MAAM,QAAQ,YAAY,KAAK,EAAE,KAAK,YAAY,GAAG,QAAQ,QAAA,GAAOL,UAAAA,UAAAA,CAAU,SAAS,GAAG,KAAA,GAAIA,UAAAA,UAAAA,CAAU,OAAO,GAAG,EAAE,GAAG,MAAM,OAAO,KAAK,GAAG;CAC5I,MAAM,OAAO,MAAM,KAAK,EAAE,QAAQ,KAAK,KAAK,MAAM,SAAS,CAAC,EAAE,IAAI,GAAG,UAAU,MAAM,MAAM,QAAQ,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC/H,MAAM,QAAQ,YAAY,QAAQ,EAAE,UAAU,CAAC,QAAQ,IAAI,CAAC,CACzD,KAAK,EAAE,UAAUM,aAAAA,iBAAiB,GAAG,CAAC,CAAC,CACvC,KAAK,GAAG;CAEX,OAAO,QAAQ,CAAC,GAAG,KAAK,MAAM,GAAG,EAAE,GAAG,GAAG,KAAK,GAAG,EAAE,EAAE,MAAA,GAAKN,UAAAA,UAAAA,CAAU,OAAO,KAAK,GAAG,IAAI;AACzF;;;;;;AAOA,eAAsB,mBACpB,SACA,aACA,aAAqBO,eAAAA,sBACsB;CAC3C,MAAM,UAAUV,aAAAA,QAAQ,IAAI;CAC5B,MAAM,aAAa,YAAY,WAAW;CAC1C,MAAM,UAAU,OAAO,YAAY,YAAY,KAAK,EAAE,UAAU,CAAC,KAAK,QAAQ,WAAW,QAAQ,aAAa,SAAS,IAAI,CAAC,CAAC;CAI7H,MAAM,UAAU,YAAY,QAAQ,EAAE,UAAU,CAAC,QAAQ,WAAW,QAAQ,OAAO,aAAa,SAAS,SAAS;CAElH,IAAI,CAAC,QAAQ,UAAUW,kBAAAA,gBAAgB,KAAK,CAACC,aAAAA,UAAU,GAAG,OAAO;CAEjE,eAAQ,eAAe,EAAE,WAAW,KAAK,CAAC;CAC1C,MAAM,WAAW,MAAMC,eAAQ,YAAY;EACzC,SAAS;EACT,SAAS,QAAQ,KAAK,EAAE,KAAK,OAAO,YAAY;GAAE,OAAO;GAAK,OAAO,MAAM,UAAU;GAAG;EAAK,EAAE;EAC/F,UAAU;CACZ,CAAC;CAED,IAAIA,eAAQ,SAAS,QAAQ,GAAG,OAAO;CAEvC,MAAM,UAAU,OAAO,YAAY,QAAQ,KAAK,EAAE,UAAU,CAAC,KAAK,SAAS,SAAS,GAAG,CAAC,CAAC,CAAC;CAC1F,MAAMR,oBAAAA,iBAAiB;EACrB,GAAG;EACH,UAAU;GAAE,GAAG,YAAY;IAAW,UAAU;IAAE,GAAG;IAAY,GAAG;GAAQ;EAAE;CAChF,CAAC;CAED,OAAO;EAAE,GAAG;EAAS,GAAG;CAAQ;AAClC;;;;;AAMA,eAAsB,YAAY,SAA0G;CAC1I,MAAM,EAAE,YAAY,YAAY,MAAMS,eAAAA,WAAW;EAAE,YAAY,QAAQ;EAAY,UAAU,QAAQ;CAAS,CAAC;CAC/G,MAAM,CAAC,UAAU;CAEjB,IAAI,CAAC,QACH,MAAM,IAAIC,WAAAA,YAAY,MAAM;EAC1B,MAAMA,WAAAA,YAAY,KAAK;EACvB,UAAU;EACV,SAAS;CACX,CAAC;CAMH,OAAO;EAAE,YAAYhB,UAAAA,QAAK,SAASC,aAAAA,QAAQ,IAAI,GAAG,UAAU,KAAK;EAAY;CAAO;AACtF;;AASA,eAAsB,kBAAkB,SAAwB,QAAmD;CACjH,MAAM,EAAE,eAAe,MAAM,YAAY,OAAO;CAChD,MAAM,SAAS,MAAMgB,oBAAAA,gBAAgB;CACrC,MAAM,cAAc,OAAO,YAAY;EACrC,IAAI,QAAQ,cAAc,QAAQ,WAAW,OAAO;EACpD,IAAIL,kBAAAA,gBAAgB,GAClB,MAAM,IAAII,WAAAA,YAAY,MAAM;GAC1B,MAAMA,WAAAA,YAAY,KAAK;GACvB,UAAU;GACV,SAAS,mBAAmB,QAAQ,UAAU;EAChD,CAAC;EAEH,OAAO,MAAM,SAAS,EAAE,OAAO,CAAC;CAClC,EAAA,CAAG;CAEH,OAAO;EAAE;EAAY;EAAa,aAAA,MADR,mBAAmB,SAAS,aAAa,UAAU;CAC/B;AAChD;;AAKA,eAAsB,QACpB,SACA,UAII,CAAC,GACU;CACf,MAAM,WAAW,IAAI,gBAAgB;CACrC,MAAM,SAAS,QAAQ,UAAU,SAAS;CAC1C,MAAM,aAAa,SAAS,MAAM;CAClC,MAAM,SAASf,aAAAA;CACf,IAAI,CAAC,QAAQ,QAAQ;EACnB,OAAO,KAAK,UAAU,IAAI;EAC1B,OAAO,KAAK,WAAW,IAAI;CAC7B;CACA,IAAI;CACJ,IAAI;EACF,IAAI,CAAC,QAAQ,UAAU;GACrB,MAAM,EAAE,oBAAoB,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,QAAM,2BAAA,CAAA;GAElC,KAAI,MADiB,gBAAgB,EAAA,CAC1B,SACT,MAAM,IAAIe,WAAAA,YAAY,MAAM;IAC1B,MAAMA,WAAAA,YAAY,KAAK;IACvB,UAAU;IACV,SAAS;GACX,CAAC;EACL;EACA,MAAM,WAAW,QAAQ,YAAa,MAAM,kBAAkB,SAAS,MAAM;EAC7E,IAAI,EAAE,aAAa,gBAAgB;EACnC,MAAM,EAAE,eAAe;EACvB,IAAI,SAAS;EAEb,IAAI,cAAc;EAIlB,MAAM,QAAQ,IAAIE,WAAAA,SAAoB;EACtC,kBAAA,eAAe,OAAO;GACpB,UAAUC,WAAAA,SAAY,QAAQ,YAAY;GAC1C,WAAW,CAACC,WAAAA,WAAW;GACvB,GAAI,QAAQ,UAAU,EAAE,QAAQC,aAAAA,YAAY,IAAI,CAAC;EACnD,CAAC;EAED,MAAM,UAAU,CAAC,QAAQ,WAAWpB,aAAAA,QAAQ,MAAM,UAAU,QAAQY,aAAAA,UAAU;EAC9E,IAAI,aAAa;EACjB,MAAM,KAAK,oBAAoB,YAAY;GACzC,cAAc;GACd,MAAM,QAAQ,UAAU,WAAW;GACnC,IAAI,WAAW,CAAC,SACd,UAAU,UAAU;IAClB,oBAAoB;KAClB,aAAa;KACb,KAAK;IACP;IACA,QAAQ;GACV,CAAC;GAEH,IAAI,UAAU,QAAQ,WAAW,QAAQ,aAAa,UAAU;GAChE,SAAS;GACT,aAAA,SAAS,CACP,IAAA,GAAGT,UAAAA,UAAAA,CAAU,OAAO,SAAS,EAAE,IAAIJ,UAAAA,QAAK,SAASC,aAAAA,QAAQ,IAAI,CAAC,EAAE,MAAA,GAAKG,UAAAA,UAAAA,CACnE,OACA,YAAY,QAAQ,EAAE,UAAU,YAAY,IAAI,CAAC,CAC9C,KAAK,EAAE,YAAY,KAAK,CAAC,CACzB,KAAK,KAAK,KAAK,gBACpB,MAAA,GACAA,UAAAA,UAAAA,CAAU,OAAO,UAAU,oEAAoE,4BAA4B,CAC7H,CAAC;GACD,aAAA,OAAO;EACT,CAAC;EACD,MAAM,KAAK,6BAA6B,QAAQ,UAAU,cAAc,CAAC;EAEzE,SACE,IAAI;GACF,OAAA,GAAMkB,aAAAA,aAAAA,CAAa;IACjB,OAAO,YAAY;IACnB,WAAW,QAAQ;IACnB;IACA,SAAS,QAAQ;IACjB,MAAMrB,aAAAA,QAAQ,IAAI;IAClB;IACA,YAAY,aAAa,MAAM,YAAY,OAAO,EAAA,CAAG;IACrD;IACA;GACF,CAAC;GACD;EACF,SAAS,OAAO;GACd,IAAI,EAAE,iBAAiBsB,aAAAA,yBAAyB,MAAM;GACtD,MAAM,QAAQ,UAAU,yBAAyB;GACjD,MAAMC,oBAAAA,iBAAiB;GACvB,IAAI,aAAa,MAAM,IAAI,MAAM,GAAG,MAAM,QAAQ,wFAAwF;GAC1I,IAAI,QAAQ,WAAWZ,kBAAAA,gBAAgB,KAAK,CAACC,aAAAA,UAAU,GAAG,MAAM,IAAI,MAAM,GAAG,MAAM,QAAQ,0CAA0C;GAGrI,UAAU;GACV,UAAU,KAAA;GACV,QAAQ,KAAA,GAAIT,UAAAA,UAAAA,CAAU,UAAU,GAAG,MAAM,QAAQ,kBAAkB,CAAC;GACpE,cAAc,MAAM,MAAM,SAAS;IAAE;IAAQ,qBAAqB;GAAY,CAAC;GAC/E,cAAc;GACd,cAAc,MAAM,mBAAmB,SAAS,aAAa,UAAU;EACzE;EAGF,MAAM,MAAM,SAAS,oBAAoB;EACzC,UAAU;EACV,IAAI,YAAY;GACd,MAAM,EAAE,gBAAgB,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,QAAM,2BAAA,CAAA;GAC9B,MAAM,YAAY,OAAO;GACzB,IAAI,QAAQ,aAAa,UAAU,aAAA,SAAS,8CAA8C;GAC1F;EACF;EACA,IAAI,CAAC,QAAQ,WAAW,OAAO,WAAW,QAAQ,aAAa,UAAU,aAAA,SAAS,cAAc;CAClG,SAAS,OAAO;EACd,IAAI,EAAE,iBAAiBI,aAAAA,uBAAuB,MAAM;CACtD,UAAU;EACR,UAAU;EACV,OAAO,IAAI,UAAU,IAAI;EACzB,OAAO,IAAI,WAAW,IAAI;CAC5B;AACF;;;;;AAMA,SAAgB,UAAU,EAAE,cAAc,UAAwE;CAChH,MAAM,QAAQP,aAAAA,QAAQ;CACtB,MAAM,UAAU,SAAiB;EAC/B,MAAM,MAAM,KAAK,SAAS;EAC1B,IAAI,QAAQ,OAAO,QAAQ,KAAK,aAAa;EAC7C,IAAI,QAAQ,KAAU,OAAO;CAC/B;CAGA,MAAM,cAAca,eAAQ,SAAS,QAAQ,IAAI,GAAQ;CACzD,eAAQ,SAAS,QAAQ,OAAO,GAAQ;CACxC,MAAM,WAAW,IAAI;CACrB,MAAM,GAAG,QAAQ,MAAM;CACvB,MAAM,OAAO;CACb,IAAI,WAAW;CAEf,aAAa;EACX,IAAI,UAAU;EACd,WAAW;EACX,IAAI,aAAa,eAAQ,SAAS,QAAQ,IAAI,KAAU,WAAW;EACnE,MAAM,IAAI,QAAQ,MAAM;EACxB,MAAM,WAAW,KAAK;EACtB,MAAM,MAAM;CACd;AACF;;;;;AAMA,eAAsB,UACpB,QACA,QACA,EAAE,QAAQ,OAAO,OAAO,UAA+C,CAAC,GACzD;CACf,MAAM,UAAyB;EAC7B,SAAA,kBAAA;EACA,YAAY,OAAO;EACnB,WAAW,OAAO,OAAOW,aAAAA;EACzB,YAAY,OAAO,YAAY,OAAO,OAAOhB,sBAAAA,eAAe,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,OAAO,QAAQ,KAAK,CAAC,CAAC;EACvG,UAAU,OAAO,QAAQ;EACzB,UAAU,OAAO;CACnB;CACA,MAAM,SAASiB,kBAAAA,SAAS;EAAE,SAAS;EAAU,SAASzB,aAAAA,QAAQ,OAAO;CAAE,CAAC;CAExE,IAAI;EACF,IAAI,QAAQ,aAAa,YAAY,CAAC,MACpC,aAAA,SAAS;GACP,UAAA,GAASG,UAAAA,UAAAA,CAAU,UAAU,2DAA2D;GACxF;EACF,CAAC;EAGH,MAAM,OAAO,OAAO;EAEpB,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,QAAQ,MAAMuB,eAAAA,QAAQ,KAAK,CAAC,CAAC,OAAO;EACpC,aAAA,QAAA,WAAmB;CACrB;AACF"}