@kubb/cli 5.3.15 → 5.3.17

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 (70) hide show
  1. package/dist/{connect-CgkbDN1-.js → connect-DQWYjheY.js} +2 -2
  2. package/dist/{connect-CgkbDN1-.js.map → connect-DQWYjheY.js.map} +1 -1
  3. package/dist/{connect-B4NIfpxC.cjs → connect-c9W1razJ.cjs} +2 -2
  4. package/dist/{connect-B4NIfpxC.cjs.map → connect-c9W1razJ.cjs.map} +1 -1
  5. package/dist/{generate-D3l-s7Vh.js → generate-BSnIzFH0.js} +2 -2
  6. package/dist/{generate-D3l-s7Vh.js.map → generate-BSnIzFH0.js.map} +1 -1
  7. package/dist/{generate-CGVdHu45.cjs → generate-BoamktRp.cjs} +2 -2
  8. package/dist/{generate-CGVdHu45.cjs.map → generate-BoamktRp.cjs.map} +1 -1
  9. package/dist/index.cjs +7 -7
  10. package/dist/index.js +7 -7
  11. package/dist/{init-B40Y8E7d.cjs → init--iLsTi1X.cjs} +2 -2
  12. package/dist/{init-B40Y8E7d.cjs.map → init--iLsTi1X.cjs.map} +1 -1
  13. package/dist/{init-BtNySVze.js → init-C6AZG9IZ.js} +2 -2
  14. package/dist/{init-BtNySVze.js.map → init-C6AZG9IZ.js.map} +1 -1
  15. package/dist/{login-VlfI9Xcv.js → login-Bkm0Bcwh.js} +2 -2
  16. package/dist/{login-VlfI9Xcv.js.map → login-Bkm0Bcwh.js.map} +1 -1
  17. package/dist/{login-CcYnvzn9.cjs → login-DICKtsMS.cjs} +2 -2
  18. package/dist/{login-CcYnvzn9.cjs.map → login-DICKtsMS.cjs.map} +1 -1
  19. package/dist/{logout-BNlPXi-7.js → logout-CCAt5yNI.js} +2 -2
  20. package/dist/{logout-BNlPXi-7.js.map → logout-CCAt5yNI.js.map} +1 -1
  21. package/dist/{logout-Bzlys_F2.cjs → logout-Cq_SjOQf.cjs} +2 -2
  22. package/dist/{logout-Bzlys_F2.cjs.map → logout-Cq_SjOQf.cjs.map} +1 -1
  23. package/dist/{package-Bd8xo-XX.cjs → package-Bpz2OqOp.cjs} +2 -2
  24. package/dist/package-Bpz2OqOp.cjs.map +1 -0
  25. package/dist/package-CO6hZYJK.js +6 -0
  26. package/dist/package-CO6hZYJK.js.map +1 -0
  27. package/dist/{run-CmB0Bnby.cjs → run-CHG7Y4OF.cjs} +2 -2
  28. package/dist/{run-CmB0Bnby.cjs.map → run-CHG7Y4OF.cjs.map} +1 -1
  29. package/dist/{run-DyXw4hZU.js → run-CQmDghzm.js} +3 -3
  30. package/dist/{run-DyXw4hZU.js.map → run-CQmDghzm.js.map} +1 -1
  31. package/dist/{run-Dcv_CGTV.cjs → run-Cx_Biqws.cjs} +2 -2
  32. package/dist/{run-Dcv_CGTV.cjs.map → run-Cx_Biqws.cjs.map} +1 -1
  33. package/dist/{run-CqNGsZW4.js → run-D5DrRIpE.js} +2 -2
  34. package/dist/{run-CqNGsZW4.js.map → run-D5DrRIpE.js.map} +1 -1
  35. package/dist/{run-BHMnPdul.js → run-DgJoQeWU.js} +18 -19
  36. package/dist/run-DgJoQeWU.js.map +1 -0
  37. package/dist/{run-2VumfVcx.js → run-Dq11mN4W.js} +2 -2
  38. package/dist/{run-2VumfVcx.js.map → run-Dq11mN4W.js.map} +1 -1
  39. package/dist/{run-DqZ334j3.cjs → run-QtVt-csj.cjs} +3 -3
  40. package/dist/{run-DqZ334j3.cjs.map → run-QtVt-csj.cjs.map} +1 -1
  41. package/dist/{run-DYmx4BUd.cjs → run-fLBpH170.cjs} +17 -18
  42. package/dist/run-fLBpH170.cjs.map +1 -0
  43. package/dist/{snapshot-C2dbvseU.cjs → snapshot-BTM3dE9L.cjs} +126 -64
  44. package/dist/snapshot-BTM3dE9L.cjs.map +1 -0
  45. package/dist/{snapshot-CWZAiRmb.js → snapshot-Bxlj-1OJ.js} +129 -67
  46. package/dist/snapshot-Bxlj-1OJ.js.map +1 -0
  47. package/dist/{status-D9O6D20d.cjs → status-BxUqzCGT.cjs} +2 -2
  48. package/dist/{status-D9O6D20d.cjs.map → status-BxUqzCGT.cjs.map} +1 -1
  49. package/dist/{status-CKhgk59o.js → status-QnFiAJK0.js} +2 -2
  50. package/dist/{status-CKhgk59o.js.map → status-QnFiAJK0.js.map} +1 -1
  51. package/dist/{studio-D_bRD3nc.cjs → studio-BeOQYXoh.cjs} +12 -7
  52. package/dist/studio-BeOQYXoh.cjs.map +1 -0
  53. package/dist/{studio-DFZKPTAs.js → studio-C2FsZ4zt.js} +12 -7
  54. package/dist/studio-C2FsZ4zt.js.map +1 -0
  55. package/dist/{utils-CyfAlK9G.cjs → utils-DqUNntyL.cjs} +34 -17
  56. package/dist/utils-DqUNntyL.cjs.map +1 -0
  57. package/dist/{utils-LvEYQf9I.js → utils-TpILNAy7.js} +29 -18
  58. package/dist/utils-TpILNAy7.js.map +1 -0
  59. package/package.json +7 -7
  60. package/dist/package-79jTR7nF.js +0 -6
  61. package/dist/package-79jTR7nF.js.map +0 -1
  62. package/dist/package-Bd8xo-XX.cjs.map +0 -1
  63. package/dist/run-BHMnPdul.js.map +0 -1
  64. package/dist/run-DYmx4BUd.cjs.map +0 -1
  65. package/dist/snapshot-C2dbvseU.cjs.map +0 -1
  66. package/dist/snapshot-CWZAiRmb.js.map +0 -1
  67. package/dist/studio-DFZKPTAs.js.map +0 -1
  68. package/dist/studio-D_bRD3nc.cjs.map +0 -1
  69. package/dist/utils-CyfAlK9G.cjs.map +0 -1
  70. package/dist/utils-LvEYQf9I.js.map +0 -1
@@ -1,22 +1,27 @@
1
1
  import "./rolldown-runtime-C0LytTxp.js";
2
- import { a as run, c as exists, l as read, n as createStudioOptions, r as loadConfigs } from "./run-BHMnPdul.js";
3
- import { r as logBlock, t as createSpinner } from "./output-C_Gk4p-8.js";
2
+ import { a as run, c as exists, l as read, n as createStudioOptions, r as loadConfigs } from "./run-DgJoQeWU.js";
3
+ import { d as createPlainLogger, u as setupReporters } from "./utils-TpILNAy7.js";
4
+ import { r as logBlock } from "./output-C_Gk4p-8.js";
4
5
  import { styleText } from "node:util";
5
6
  import process from "node:process";
6
7
  import { dirname, join } from "node:path";
7
8
  import { readFileSync } from "node:fs";
8
- import { logLevel } from "@kubb/core";
9
- import { createAgent, createClient, createJob, machineTokenFrom, waitForJob } from "@kubb/studio";
9
+ import { cliReporter, logLevel } from "@kubb/core";
10
+ import { createAgent, createJob, machineTokenFrom, runConnection, waitForJob } from "@kubb/studio";
10
11
  //#region src/runners/studio/ci.ts
11
- function readGithubPullRequestNumber(eventPath) {
12
+ function readGithubPullRequest(eventPath) {
12
13
  if (!eventPath) return;
13
14
  try {
14
15
  const event = JSON.parse(readFileSync(eventPath, "utf8"));
15
- return event.pull_request?.number ? String(event.pull_request.number) : void 0;
16
+ return event.pull_request?.number ? event.pull_request : void 0;
16
17
  } catch {
17
18
  return;
18
19
  }
19
20
  }
21
+ /** Reproduces GitLab's `CI_COMMIT_REF_SLUG` for a branch it gives no slug of, like a merge request's target. */
22
+ function gitlabRefSlug(ref) {
23
+ return ref.toLowerCase().replace(/[^a-z0-9]/gu, "-").slice(0, 63).replace(/^-+|-+$/g, "");
24
+ }
20
25
  /**
21
26
  * Detects the CI provider from its environment variables and derives a stable identity from it.
22
27
  * The GitHub row reproduces `gh:<repositoryId>:<prNumber>`, the identity `kubb-labs/action` has
@@ -24,26 +29,40 @@ function readGithubPullRequestNumber(eventPath) {
24
29
  */
25
30
  function detectCi(env = process.env) {
26
31
  if (env.GITHUB_ACTIONS) {
27
- const pullRequestNumber = readGithubPullRequestNumber(env.GITHUB_EVENT_PATH);
32
+ const pullRequest = readGithubPullRequest(env.GITHUB_EVENT_PATH);
28
33
  const repositoryId = env.GITHUB_REPOSITORY_ID ?? env.GITHUB_REPOSITORY ?? "";
29
- const scope = pullRequestNumber ?? env.GITHUB_RUN_ID ?? "";
34
+ const branch = env.GITHUB_REF?.startsWith("refs/heads/") ? env.GITHUB_REF.slice(11) : void 0;
35
+ const scope = pullRequest?.number ?? (branch ? `refs/heads/${branch}` : env.GITHUB_RUN_ID) ?? "";
36
+ const baseBranch = pullRequest?.base?.ref;
30
37
  return {
31
38
  id: `gh:${repositoryId}:${scope}`,
32
- name: `${env.GITHUB_REPOSITORY ?? "github"}#${scope}`
39
+ name: `${env.GITHUB_REPOSITORY ?? "github"}#${pullRequest?.number ?? branch ?? scope}`,
40
+ commit: pullRequest?.head?.sha ?? env.GITHUB_SHA,
41
+ base: baseBranch ? {
42
+ branch: baseBranch,
43
+ id: `gh:${repositoryId}:refs/heads/${baseBranch}`
44
+ } : void 0
33
45
  };
34
46
  }
35
47
  if (env.GITLAB_CI) {
36
48
  const scope = env.CI_MERGE_REQUEST_IID ?? env.CI_COMMIT_REF_SLUG ?? "";
49
+ const baseBranch = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
37
50
  return {
38
51
  id: `gl:${env.CI_PROJECT_ID ?? ""}:${scope}`,
39
- name: `${env.CI_PROJECT_PATH ?? "gitlab"}#${scope}`
52
+ name: `${env.CI_PROJECT_PATH ?? "gitlab"}#${scope}`,
53
+ commit: env.CI_MERGE_REQUEST_SOURCE_BRANCH_SHA || env.CI_COMMIT_SHA,
54
+ base: baseBranch ? {
55
+ branch: baseBranch,
56
+ id: `gl:${env.CI_PROJECT_ID ?? ""}:${gitlabRefSlug(baseBranch)}`
57
+ } : void 0
40
58
  };
41
59
  }
42
60
  if (env.BITBUCKET_BUILD_NUMBER) {
43
61
  const scope = env.BITBUCKET_PR_ID ?? env.BITBUCKET_BRANCH ?? "";
44
62
  return {
45
63
  id: `bb:${env.BITBUCKET_REPO_UUID ?? ""}:${scope}`,
46
- name: `${env.BITBUCKET_REPO_FULL_NAME ?? "bitbucket"}#${scope}`
64
+ name: `${env.BITBUCKET_REPO_FULL_NAME ?? "bitbucket"}#${scope}`,
65
+ commit: env.BITBUCKET_COMMIT
47
66
  };
48
67
  }
49
68
  if (env.CIRCLECI) {
@@ -52,7 +71,8 @@ function detectCi(env = process.env) {
52
71
  const scope = env.CIRCLE_PR_NUMBER ?? env.CIRCLE_BRANCH ?? "";
53
72
  return {
54
73
  id: `circle:${owner}:${project}:${scope}`,
55
- name: `${owner ? `${owner}/` : ""}${project}#${scope}`
74
+ name: `${owner ? `${owner}/` : ""}${project}#${scope}`,
75
+ commit: env.CIRCLE_SHA1
56
76
  };
57
77
  }
58
78
  return null;
@@ -109,12 +129,20 @@ function resolveToken(options) {
109
129
  }
110
130
  function resolveCiIdentity(options) {
111
131
  const detected = detectCi();
112
- if (options.id) return {
132
+ const ci = options.id ? {
113
133
  id: options.id,
114
- name: detected?.name ?? options.id
134
+ name: detected?.name ?? options.id,
135
+ commit: detected?.commit
136
+ } : detected;
137
+ if (!ci) throw new Error("Could not detect a supported CI provider (GitHub Actions, GitLab CI, Bitbucket Pipelines, CircleCI). Pass --id.");
138
+ const base = options.baseId ? {
139
+ branch: options.baseId,
140
+ id: options.baseId
141
+ } : ci.base;
142
+ return {
143
+ ...ci,
144
+ base: base?.id === ci.id ? void 0 : base
115
145
  };
116
- if (!detected) throw new Error("Could not detect a supported CI provider (GitHub Actions, GitLab CI, Bitbucket Pipelines, CircleCI). Pass --id.");
117
- return detected;
118
146
  }
119
147
  /** Rejects a bad `--timeout` up front instead of letting it reach `waitForJob` as NaN or <= 0. */
120
148
  function resolveTimeoutMs(options) {
@@ -130,7 +158,7 @@ function assertSecureStudioUrl(studioUrl) {
130
158
  function absoluteUrl(studioUrl, path) {
131
159
  return new URL(path, `${studioUrl}/`).toString();
132
160
  }
133
- function toResult(studioUrl, snapshot, agentSlug) {
161
+ function toResult(studioUrl, snapshot, agentSlug, ci) {
134
162
  return {
135
163
  id: snapshot.id,
136
164
  name: snapshot.name,
@@ -139,14 +167,35 @@ function toResult(studioUrl, snapshot, agentSlug) {
139
167
  url: absoluteUrl(studioUrl, snapshot.url),
140
168
  snapshotIdUrl: absoluteUrl(studioUrl, snapshot.snapshotIdUrl),
141
169
  expiresAt: snapshot.expiresAt,
142
- agentUrl: absoluteUrl(studioUrl, `/agents/${agentSlug}`)
170
+ agentUrl: absoluteUrl(studioUrl, `/agents/${agentSlug}`),
171
+ changes: snapshot.changes,
172
+ branchChanges: snapshot.branchChanges && ci.base ? {
173
+ ...snapshot.branchChanges,
174
+ branch: ci.base.branch
175
+ } : void 0
143
176
  };
144
177
  }
178
+ /** How many files differ, `against` what. */
179
+ function describeChanges(changes, against) {
180
+ const { added, changed, removed } = changes;
181
+ return added.length + changed.length + removed.length ? `${added.length} added, ${changed.length} changed, ${removed.length} removed ${against}` : `No changes ${against}`;
182
+ }
183
+ /** One summary line: how many files changed, and since which run. */
184
+ function formatChanges(changes) {
185
+ if (!changes.base) return "First snapshot";
186
+ return describeChanges(changes, `since ${changes.base.commit?.slice(0, 7) ?? changes.base.createdAt}`);
187
+ }
188
+ /** One summary line: how the snapshot differs from the base branch's latest one. */
189
+ function formatBranchChanges(changes) {
190
+ return changes.base ? describeChanges(changes, `against ${changes.branch}`) : `No snapshot of ${changes.branch} to compare with`;
191
+ }
145
192
  function printSummary(result) {
146
193
  logBlock([
147
194
  `${styleText("dim", "Package".padEnd(10))} ${result.name ?? "(unnamed)"}@${result.version ?? "0.0.0"}`,
148
195
  `${styleText("dim", "Tarball".padEnd(10))} ${styleText("cyan", result.url)}`,
149
196
  `${styleText("dim", "Agent".padEnd(10))} ${result.agentUrl}`,
197
+ ...result.branchChanges ? [`${styleText("dim", "Branch".padEnd(10))} ${formatBranchChanges(result.branchChanges)}`] : [],
198
+ ...result.changes ? [`${styleText("dim", "Changes".padEnd(10))} ${formatChanges(result.changes)}`] : [],
150
199
  `${styleText("dim", "Expires".padEnd(10))} ${result.expiresAt}`
151
200
  ]);
152
201
  }
@@ -162,84 +211,96 @@ async function snapshot(options) {
162
211
  const { configPath } = await loadConfigs(options);
163
212
  const ci = resolveCiIdentity(options);
164
213
  const { name, version: packageVersion } = await resolvePackageMetadata(options);
214
+ const logLevel$1 = logLevel[options.logLevel ?? "info"];
165
215
  process.env.KUBB_AGENT_SECRET = ci.id;
166
- const spinner = options.json ? null : createSpinner();
167
- const log = (message) => {
168
- if (options.json) {
169
- console.error(message);
170
- return;
171
- }
172
- spinner?.message(message);
216
+ const write = options.json ? (line) => console.error(line) : (line) => console.log(line);
217
+ const logger = createPlainLogger(write);
218
+ const step = (message) => {
219
+ if (logLevel$1 > logLevel.silent) write(message);
173
220
  };
174
- if (options.json) log("Creating Kubb Studio agent");
175
- if (!options.json) spinner?.start("Creating Kubb Studio agent");
221
+ step("Creating Kubb Studio agent");
176
222
  const agent = await createAgent({
177
223
  studioUrl: options.studioUrl,
178
224
  token,
179
225
  name: ci.name,
180
226
  machineToken: machineTokenFrom(ci.id)
181
227
  });
182
- const { promise: ready, reject: markFailed, resolve: markReady } = Promise.withResolvers();
183
- const client = createClient({
184
- studioUrl: options.studioUrl,
185
- token: agent.token,
186
- configPath,
187
- root: process.cwd(),
188
- version: options.version,
189
- client: { kind: "cli" },
190
- logLevel: logLevel[options.logLevel ?? "info"],
191
- loadConfig: async () => (await loadConfigs(options)).config,
192
- installLogger: (hooks) => {
193
- hooks.hook("studio:connecting", ({ url }) => log(`Connecting to Kubb Studio at ${url}`));
194
- hooks.hook("studio:connected", ({ url }) => log(`Connected to Kubb Studio at ${url}`));
195
- hooks.hook("studio:ready", () => {
196
- log("Kubb Studio connection ready");
197
- markReady();
198
- });
199
- hooks.hook("studio:warn", ({ message }) => log(`Kubb Studio warning: ${message}`));
200
- hooks.hook("studio:error", ({ error }) => markFailed(error));
201
- }
228
+ const { promise: ready, resolve: markReady } = Promise.withResolvers();
229
+ const shutdown = new AbortController();
230
+ const connection = runConnection({
231
+ credentials: { token: agent.token },
232
+ signal: shutdown.signal,
233
+ clientOptions: () => ({
234
+ studioUrl: options.studioUrl,
235
+ configPath,
236
+ root: process.cwd(),
237
+ version: options.version,
238
+ permissions: options.permission,
239
+ loadConfig: async () => (await loadConfigs(options)).config,
240
+ installLogger: async (hooks) => {
241
+ await setupReporters(hooks, {
242
+ logLevel: logLevel$1,
243
+ reporters: [cliReporter],
244
+ logger
245
+ });
246
+ hooks.hook("studio:ready", () => markReady());
247
+ }
248
+ }),
249
+ onTokenRejected: ({ error }) => Promise.reject(error)
202
250
  });
203
- await client.connect();
251
+ const connectionLost = new AbortController();
252
+ const connectionEnded = /* @__PURE__ */ new Error("The Kubb Studio connection ended before the snapshot finished");
253
+ connection.then(() => connectionLost.abort(connectionEnded), (error) => connectionLost.abort(error));
254
+ const lost = connection.then(() => Promise.reject(connectionEnded), (error) => Promise.reject(error));
255
+ lost.catch(() => {});
204
256
  try {
205
- let readyTimeoutHandle;
257
+ let readyTimeout;
206
258
  try {
207
- await Promise.race([ready, new Promise((_, reject) => {
208
- readyTimeoutHandle = setTimeout(() => reject(/* @__PURE__ */ new Error("Timed out waiting for Kubb Studio to confirm the agent was ready")), READY_TIMEOUT_MS);
209
- })]);
259
+ await Promise.race([
260
+ ready,
261
+ lost,
262
+ new Promise((_, reject) => {
263
+ readyTimeout = setTimeout(() => reject(/* @__PURE__ */ new Error("Timed out waiting for Kubb Studio to confirm the agent was ready")), READY_TIMEOUT_MS);
264
+ })
265
+ ]);
210
266
  } finally {
211
- clearTimeout(readyTimeoutHandle);
267
+ clearTimeout(readyTimeout);
212
268
  }
213
- log("Creating snapshot job");
269
+ step("Creating snapshot job");
270
+ const snapshotDeadline = Date.now() + timeoutMs;
271
+ const snapshotTimeoutMs = () => Math.max(snapshotDeadline - Date.now(), 1);
214
272
  const job = await createJob({
215
273
  studioUrl: options.studioUrl,
216
274
  token,
217
275
  type: "snapshot",
218
276
  agentId: agent.id,
219
277
  name,
220
- version: packageVersion
278
+ version: packageVersion,
279
+ commit: ci.commit,
280
+ baseId: ci.base?.id,
281
+ timeoutMs: snapshotTimeoutMs(),
282
+ signal: connectionLost.signal
221
283
  });
222
- log(`Snapshot job queued: ${job.id}`);
223
- const finished = await waitForJob({
284
+ step(`Snapshot job queued: ${job.id}`);
285
+ const finished = await Promise.race([waitForJob({
224
286
  studioUrl: options.studioUrl,
225
287
  token,
226
288
  id: job.id,
227
- timeoutMs
228
- });
289
+ timeoutMs: snapshotTimeoutMs(),
290
+ signal: connectionLost.signal
291
+ }), lost]);
229
292
  if (finished.status === "failed") throw new Error(finished.error ?? "Snapshot job failed");
230
293
  if (!finished.snapshot) throw new Error("Snapshot job succeeded without a snapshot");
231
- const result = toResult(options.studioUrl, finished.snapshot, agent.slug);
232
- if (options.json) log("Snapshot published");
233
- if (!options.json) spinner?.stop("Snapshot published");
294
+ const result = toResult(options.studioUrl, finished.snapshot, agent.slug, ci);
295
+ step("Snapshot published");
234
296
  if (options.json) console.log(JSON.stringify(result));
235
297
  if (!options.json) printSummary(result);
236
298
  } catch (error) {
237
- if (options.json) log("Snapshot failed");
238
- if (!options.json) spinner?.stop("Snapshot failed");
299
+ step("Snapshot failed");
239
300
  throw error;
240
301
  } finally {
241
- if (options.json) log("Disconnecting from Kubb Studio");
242
- client.disconnect();
302
+ step("Disconnecting from Kubb Studio");
303
+ shutdown.abort();
243
304
  }
244
305
  }
245
306
  const runner = async ({ values }) => {
@@ -247,6 +308,7 @@ const runner = async ({ values }) => {
247
308
  ...createStudioOptions(values),
248
309
  token: values.token,
249
310
  id: values.id,
311
+ baseId: values.baseId,
250
312
  name: values.name,
251
313
  packageVersion: values.packageVersion,
252
314
  timeout: values.timeout,
@@ -257,4 +319,4 @@ const runner = async ({ values }) => {
257
319
  //#endregion
258
320
  export { runner };
259
321
 
260
- //# sourceMappingURL=snapshot-CWZAiRmb.js.map
322
+ //# sourceMappingURL=snapshot-Bxlj-1OJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-Bxlj-1OJ.js","names":["logLevel","logLevelMap"],"sources":["../src/runners/studio/ci.ts","../src/runners/studio/snapshot.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport process from 'node:process'\n\n/**\n * Stable identity for the CI agent a snapshot run registers or reuses.\n */\nexport type CiContext = {\n /**\n * Fed into the machine token, so the same merge or pull request reuses one agent.\n */\n id: string\n /**\n * Agent display name shown in Studio.\n */\n name: string\n /** The commit this run builds, so the next snapshot can diff against it. */\n commit?: string\n /** The branch a pull request merges into, and the `id` runs on that branch register under. */\n base?: { branch: string; id: string }\n}\n\ntype GithubPullRequest = { number: number; head?: { sha?: string }; base?: { ref?: string } }\n\nfunction readGithubPullRequest(eventPath: string | undefined): GithubPullRequest | undefined {\n if (!eventPath) {\n return undefined\n }\n\n try {\n const event = JSON.parse(readFileSync(eventPath, 'utf8')) as { pull_request?: GithubPullRequest }\n return event.pull_request?.number ? event.pull_request : undefined\n } catch {\n return undefined\n }\n}\n\n/** Reproduces GitLab's `CI_COMMIT_REF_SLUG` for a branch it gives no slug of, like a merge request's target. */\nexport function gitlabRefSlug(ref: string): string {\n return ref\n .toLowerCase()\n .replace(/[^a-z0-9]/gu, '-')\n .slice(0, 63)\n .replace(/^-+|-+$/g, '')\n}\n\n/**\n * Detects the CI provider from its environment variables and derives a stable identity from it.\n * The GitHub row reproduces `gh:<repositoryId>:<prNumber>`, the identity `kubb-labs/action` has\n * always registered agents under, so an existing repository keeps reusing its agent.\n */\nexport function detectCi(env: Record<string, string | undefined> = process.env): CiContext | null {\n if (env.GITHUB_ACTIONS) {\n const pullRequest = readGithubPullRequest(env.GITHUB_EVENT_PATH)\n const repositoryId = env.GITHUB_REPOSITORY_ID ?? env.GITHUB_REPOSITORY ?? ''\n const branch = env.GITHUB_REF?.startsWith('refs/heads/') ? env.GITHUB_REF.slice('refs/heads/'.length) : undefined\n // A branch run is scoped by its ref, which a pull request number never collides with.\n const scope = pullRequest?.number ?? (branch ? `refs/heads/${branch}` : env.GITHUB_RUN_ID) ?? ''\n const baseBranch = pullRequest?.base?.ref\n\n return {\n id: `gh:${repositoryId}:${scope}`,\n name: `${env.GITHUB_REPOSITORY ?? 'github'}#${pullRequest?.number ?? branch ?? scope}`,\n // The head commit, not the merge commit a pull request run checks out.\n commit: pullRequest?.head?.sha ?? env.GITHUB_SHA,\n base: baseBranch ? { branch: baseBranch, id: `gh:${repositoryId}:refs/heads/${baseBranch}` } : undefined,\n }\n }\n\n if (env.GITLAB_CI) {\n const scope = env.CI_MERGE_REQUEST_IID ?? env.CI_COMMIT_REF_SLUG ?? ''\n const baseBranch = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME\n\n return {\n id: `gl:${env.CI_PROJECT_ID ?? ''}:${scope}`,\n name: `${env.CI_PROJECT_PATH ?? 'gitlab'}#${scope}`,\n commit: env.CI_MERGE_REQUEST_SOURCE_BRANCH_SHA || env.CI_COMMIT_SHA,\n base: baseBranch ? { branch: baseBranch, id: `gl:${env.CI_PROJECT_ID ?? ''}:${gitlabRefSlug(baseBranch)}` } : undefined,\n }\n }\n\n if (env.BITBUCKET_BUILD_NUMBER) {\n const scope = env.BITBUCKET_PR_ID ?? env.BITBUCKET_BRANCH ?? ''\n\n return { id: `bb:${env.BITBUCKET_REPO_UUID ?? ''}:${scope}`, name: `${env.BITBUCKET_REPO_FULL_NAME ?? 'bitbucket'}#${scope}`, commit: env.BITBUCKET_COMMIT }\n }\n\n if (env.CIRCLECI) {\n // Owner-qualified: two projects with the same name under different CircleCI orgs must not\n // collide on one agent, since registering it purges the other project's live sessions.\n const owner = env.CIRCLE_PROJECT_USERNAME ?? ''\n const project = env.CIRCLE_PROJECT_REPONAME ?? 'circleci'\n const scope = env.CIRCLE_PR_NUMBER ?? env.CIRCLE_BRANCH ?? ''\n\n return { id: `circle:${owner}:${project}:${scope}`, name: `${owner ? `${owner}/` : ''}${project}#${scope}`, commit: env.CIRCLE_SHA1 }\n }\n\n return null\n}\n","import { dirname, join } from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { exists, read } from '@internals/utils'\nimport { cliReporter, logLevel as logLevelMap } from '@kubb/core'\nimport { createAgent, createJob, machineTokenFrom, runConnection, waitForJob, type StudioSnapshot, type StudioSnapshotChanges } from '@kubb/studio'\nimport { logBlock } from '../../loggers/output.ts'\nimport { createPlainLogger } from '../../loggers/plainLogger.ts'\nimport setupReporters from '../../loggers/utils.ts'\nimport { type CiContext, detectCi } from './ci.ts'\nimport { createStudioOptions, loadConfigs, run, type SnapshotOptions } from './run.ts'\nimport type { definition } from '../../commands/studio/snapshot.ts'\nimport type { CommandRunner } from 'gunshi'\n\n/**\n * How long to wait for Studio's `studio:ready` acknowledgement, above the client's own 10s\n * handshake-ack timeout.\n */\nconst READY_TIMEOUT_MS = 15_000\n\n/**\n * Longest `--timeout` accepted. Job records expire from Studio's storage after an hour.\n */\nconst MAX_TIMEOUT_SECONDS = 3600\n\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1'])\n\nasync function findPackageJson(startDirectory: string): Promise<{ name: string; version: string }> {\n let directory = startDirectory\n\n for (;;) {\n const file = join(directory, 'package.json')\n\n if (await exists(file)) {\n const packageJson = JSON.parse(await read(file)) as Partial<{ name: string; version: string }>\n\n if (packageJson.name && packageJson.version) {\n return { name: packageJson.name, version: packageJson.version }\n }\n }\n\n const parent = dirname(directory)\n\n if (parent === directory) {\n break\n }\n\n directory = parent\n }\n\n throw new Error(`No package.json with a name and a version found above ${startDirectory}`)\n}\n\n/** Reads package.json only for whichever of name/version --name and --version did not supply. */\nasync function resolvePackageMetadata(options: SnapshotOptions): Promise<{ name: string; version: string }> {\n if (options.name && options.packageVersion) {\n return { name: options.name, version: options.packageVersion }\n }\n\n const packageMetadata = await findPackageJson(process.cwd())\n\n return { name: options.name ?? packageMetadata.name, version: options.packageVersion ?? packageMetadata.version }\n}\n\nfunction resolveToken(options: SnapshotOptions): string {\n const token = options.token ?? process.env.KUBB_TOKEN\n\n if (!token) {\n throw new Error('An organization CI API key is required. Pass --token or set KUBB_TOKEN.')\n }\n\n return token\n}\n\nfunction resolveCiIdentity(options: SnapshotOptions): CiContext {\n const detected = detectCi()\n // A custom --id drops the detected base, since runs on that branch may use a custom id too.\n const ci = options.id ? { id: options.id, name: detected?.name ?? options.id, commit: detected?.commit } : detected\n\n if (!ci) {\n throw new Error('Could not detect a supported CI provider (GitHub Actions, GitLab CI, Bitbucket Pipelines, CircleCI). Pass --id.')\n }\n\n // An explicit --base-id may not name a branch, so it labels the comparison itself.\n const base = options.baseId ? { branch: options.baseId, id: options.baseId } : ci.base\n\n return { ...ci, base: base?.id === ci.id ? undefined : base }\n}\n\n/** Rejects a bad `--timeout` up front instead of letting it reach `waitForJob` as NaN or <= 0. */\nfunction resolveTimeoutMs(options: SnapshotOptions): number {\n const seconds = options.timeout ?? 600\n\n if (!Number.isFinite(seconds) || seconds <= 0) {\n throw new Error('--timeout must be a positive number of seconds')\n }\n\n return Math.min(seconds, MAX_TIMEOUT_SECONDS) * 1000\n}\n\n/** The CI key is a credential, so refuse to send it anywhere but HTTPS or a loopback dev host. */\nfunction assertSecureStudioUrl(studioUrl: string): void {\n const url = new URL(studioUrl)\n\n if (url.protocol !== 'https:' && !LOOPBACK_HOSTS.has(url.hostname)) {\n throw new Error(`Refusing to send the CI API key to ${studioUrl}. Use an https:// Studio URL, or a loopback host for local development.`)\n }\n}\n\nfunction absoluteUrl(studioUrl: string, path: string): string {\n return new URL(path, `${studioUrl}/`).toString()\n}\n\ntype SnapshotResult = {\n id: string\n name: string | null\n version: string | null\n integrity: string | null\n url: string\n snapshotIdUrl: string\n expiresAt: string\n agentUrl: string\n /** What changed since the previous snapshot of this package on this agent. */\n changes?: StudioSnapshotChanges\n /** What differs from the latest snapshot of the base branch, named by `branch`. */\n branchChanges?: StudioSnapshotChanges & { branch: string }\n}\n\nfunction toResult(studioUrl: string, snapshot: StudioSnapshot, agentSlug: string, ci: CiContext): SnapshotResult {\n return {\n id: snapshot.id,\n name: snapshot.name,\n version: snapshot.version,\n integrity: snapshot.integrity,\n url: absoluteUrl(studioUrl, snapshot.url),\n snapshotIdUrl: absoluteUrl(studioUrl, snapshot.snapshotIdUrl),\n expiresAt: snapshot.expiresAt,\n agentUrl: absoluteUrl(studioUrl, `/agents/${agentSlug}`),\n changes: snapshot.changes,\n branchChanges: snapshot.branchChanges && ci.base ? { ...snapshot.branchChanges, branch: ci.base.branch } : undefined,\n }\n}\n\n/** How many files differ, `against` what. */\nfunction describeChanges(changes: StudioSnapshotChanges, against: string): string {\n const { added, changed, removed } = changes\n\n return added.length + changed.length + removed.length\n ? `${added.length} added, ${changed.length} changed, ${removed.length} removed ${against}`\n : `No changes ${against}`\n}\n\n/** One summary line: how many files changed, and since which run. */\nexport function formatChanges(changes: StudioSnapshotChanges): string {\n if (!changes.base) {\n return 'First snapshot'\n }\n\n return describeChanges(changes, `since ${changes.base.commit?.slice(0, 7) ?? changes.base.createdAt}`)\n}\n\n/** One summary line: how the snapshot differs from the base branch's latest one. */\nexport function formatBranchChanges(changes: StudioSnapshotChanges & { branch: string }): string {\n return changes.base ? describeChanges(changes, `against ${changes.branch}`) : `No snapshot of ${changes.branch} to compare with`\n}\n\nfunction printSummary(result: SnapshotResult): void {\n logBlock([\n `${styleText('dim', 'Package'.padEnd(10))} ${result.name ?? '(unnamed)'}@${result.version ?? '0.0.0'}`,\n `${styleText('dim', 'Tarball'.padEnd(10))} ${styleText('cyan', result.url)}`,\n `${styleText('dim', 'Agent'.padEnd(10))} ${result.agentUrl}`,\n ...(result.branchChanges ? [`${styleText('dim', 'Branch'.padEnd(10))} ${formatBranchChanges(result.branchChanges)}`] : []),\n ...(result.changes ? [`${styleText('dim', 'Changes'.padEnd(10))} ${formatChanges(result.changes)}`] : []),\n `${styleText('dim', 'Expires'.padEnd(10))} ${result.expiresAt}`,\n ])\n}\n\n/**\n * Generates a Kubb Studio snapshot from a script: registers or reuses a CI agent, connects it,\n * queues a snapshot job, and polls until the tarball is ready. A snapshot job runs generation and\n * packs the tarball in one step, so this needs no separate generation run.\n */\nexport async function snapshot(options: SnapshotOptions): Promise<void> {\n const timeoutMs = resolveTimeoutMs(options)\n const token = resolveToken(options)\n assertSecureStudioUrl(options.studioUrl)\n const { configPath } = await loadConfigs(options)\n const ci = resolveCiIdentity(options)\n const { name, version: packageVersion } = await resolvePackageMetadata(options)\n const logLevel = logLevelMap[options.logLevel ?? 'info']\n\n // Set before the first `getMachineToken()` call (inside the connection), so the WebSocket\n // session registers under the same machine token `createAgent` just registered with Studio.\n process.env.KUBB_AGENT_SECRET = ci.id\n\n const write = options.json ? (line: string) => console.error(line) : (line: string) => console.log(line)\n const logger = createPlainLogger(write)\n const step = (message: string) => {\n if (logLevel > logLevelMap.silent) {\n write(message)\n }\n }\n\n step('Creating Kubb Studio agent')\n\n const agent = await createAgent({ studioUrl: options.studioUrl, token, name: ci.name, machineToken: machineTokenFrom(ci.id) })\n\n const { promise: ready, resolve: markReady } = Promise.withResolvers<void>()\n const shutdown = new AbortController()\n\n const connection = runConnection({\n credentials: { token: agent.token },\n signal: shutdown.signal,\n clientOptions: () => ({\n studioUrl: options.studioUrl,\n configPath,\n root: process.cwd(),\n version: options.version,\n // Flags only: a script is never prompted and never reuses a saved answer.\n permissions: options.permission,\n loadConfig: async () => (await loadConfigs(options)).config,\n installLogger: async (hooks) => {\n await setupReporters(hooks, { logLevel, reporters: [cliReporter], logger })\n hooks.hook('studio:ready', () => markReady())\n },\n }),\n // A CI agent's token comes from the organization key, so there is no pairing to fall back to.\n onTokenRejected: ({ error }) => Promise.reject(error),\n })\n const connectionLost = new AbortController()\n const connectionEnded = new Error('The Kubb Studio connection ended before the snapshot finished')\n void connection.then(\n () => connectionLost.abort(connectionEnded),\n (error) => connectionLost.abort(error),\n )\n const lost = connection.then(\n () => Promise.reject(connectionEnded),\n (error) => Promise.reject(error),\n )\n void lost.catch(() => {})\n\n try {\n let readyTimeout: ReturnType<typeof setTimeout> | undefined\n try {\n await Promise.race([\n ready,\n lost,\n new Promise<never>((_, reject) => {\n readyTimeout = setTimeout(() => reject(new Error('Timed out waiting for Kubb Studio to confirm the agent was ready')), READY_TIMEOUT_MS)\n }),\n ])\n } finally {\n clearTimeout(readyTimeout)\n }\n\n step('Creating snapshot job')\n\n const snapshotDeadline = Date.now() + timeoutMs\n const snapshotTimeoutMs = () => Math.max(snapshotDeadline - Date.now(), 1)\n\n const job = await createJob({\n studioUrl: options.studioUrl,\n token,\n type: 'snapshot',\n agentId: agent.id,\n name,\n version: packageVersion,\n commit: ci.commit,\n baseId: ci.base?.id,\n timeoutMs: snapshotTimeoutMs(),\n signal: connectionLost.signal,\n })\n step(`Snapshot job queued: ${job.id}`)\n const finished = await Promise.race([\n waitForJob({\n studioUrl: options.studioUrl,\n token,\n id: job.id,\n timeoutMs: snapshotTimeoutMs(),\n signal: connectionLost.signal,\n }),\n lost,\n ])\n\n if (finished.status === 'failed') {\n throw new Error(finished.error ?? 'Snapshot job failed')\n }\n\n if (!finished.snapshot) {\n throw new Error('Snapshot job succeeded without a snapshot')\n }\n\n const result = toResult(options.studioUrl, finished.snapshot, agent.slug, ci)\n\n step('Snapshot published')\n\n if (options.json) {\n console.log(JSON.stringify(result))\n }\n if (!options.json) {\n printSummary(result)\n }\n } catch (error) {\n step('Snapshot failed')\n throw error\n } finally {\n step('Disconnecting from Kubb Studio')\n // Not awaited: a half-open socket must not hold the run open.\n shutdown.abort()\n }\n}\n\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async ({ values }) => {\n const options: SnapshotOptions = {\n ...createStudioOptions(values),\n token: values.token,\n id: values.id,\n baseId: values.baseId,\n name: values.name,\n packageVersion: values.packageVersion,\n timeout: values.timeout,\n json: values.json,\n }\n await run(options, () => snapshot(options), { json: options.json })\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  require("./rolldown-runtime-qbf5tadS.cjs");
2
- const require_run = require("./run-DYmx4BUd.cjs");
2
+ const require_run = require("./run-fLBpH170.cjs");
3
3
  //#region src/runners/studio/status.ts
4
4
  const runner = async ({ values }) => {
5
5
  const options = require_run.createStudioOptions(values);
@@ -8,4 +8,4 @@ const runner = async ({ values }) => {
8
8
  //#endregion
9
9
  exports.runner = runner;
10
10
 
11
- //# sourceMappingURL=status-D9O6D20d.cjs.map
11
+ //# sourceMappingURL=status-BxUqzCGT.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"status-D9O6D20d.cjs","names":["createStudioOptions","run","status"],"sources":["../src/runners/studio/status.ts"],"sourcesContent":["import type { CommandRunner } from 'gunshi'\nimport type { definition } from '../../commands/studio/status.ts'\nimport { createStudioOptions, run, status } from './run.ts'\n\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async ({ values }) => {\n const options = createStudioOptions(values)\n await run(options, () => status(options))\n}\n"],"mappings":";;;AAIA,MAAa,SAA0E,OAAO,EAAE,aAAa;CAC3G,MAAM,UAAUA,YAAAA,oBAAoB,MAAM;CAC1C,MAAMC,YAAAA,IAAI,eAAeC,YAAAA,OAAO,OAAO,CAAC;AAC1C"}
1
+ {"version":3,"file":"status-BxUqzCGT.cjs","names":["createStudioOptions","run","status"],"sources":["../src/runners/studio/status.ts"],"sourcesContent":["import type { CommandRunner } from 'gunshi'\nimport type { definition } from '../../commands/studio/status.ts'\nimport { createStudioOptions, run, status } from './run.ts'\n\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async ({ values }) => {\n const options = createStudioOptions(values)\n await run(options, () => status(options))\n}\n"],"mappings":";;;AAIA,MAAa,SAA0E,OAAO,EAAE,aAAa;CAC3G,MAAM,UAAUA,YAAAA,oBAAoB,MAAM;CAC1C,MAAMC,YAAAA,IAAI,eAAeC,YAAAA,OAAO,OAAO,CAAC;AAC1C"}
@@ -1,5 +1,5 @@
1
1
  import "./rolldown-runtime-C0LytTxp.js";
2
- import { a as run, n as createStudioOptions, o as status } from "./run-BHMnPdul.js";
2
+ import { a as run, n as createStudioOptions, o as status } from "./run-DgJoQeWU.js";
3
3
  //#region src/runners/studio/status.ts
4
4
  const runner = async ({ values }) => {
5
5
  const options = createStudioOptions(values);
@@ -8,4 +8,4 @@ const runner = async ({ values }) => {
8
8
  //#endregion
9
9
  export { runner };
10
10
 
11
- //# sourceMappingURL=status-CKhgk59o.js.map
11
+ //# sourceMappingURL=status-QnFiAJK0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"status-CKhgk59o.js","names":[],"sources":["../src/runners/studio/status.ts"],"sourcesContent":["import type { CommandRunner } from 'gunshi'\nimport type { definition } from '../../commands/studio/status.ts'\nimport { createStudioOptions, run, status } from './run.ts'\n\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async ({ values }) => {\n const options = createStudioOptions(values)\n await run(options, () => status(options))\n}\n"],"mappings":";;;AAIA,MAAa,SAA0E,OAAO,EAAE,aAAa;CAC3G,MAAM,UAAU,oBAAoB,MAAM;CAC1C,MAAM,IAAI,eAAe,OAAO,OAAO,CAAC;AAC1C"}
1
+ {"version":3,"file":"status-QnFiAJK0.js","names":[],"sources":["../src/runners/studio/status.ts"],"sourcesContent":["import type { CommandRunner } from 'gunshi'\nimport type { definition } from '../../commands/studio/status.ts'\nimport { createStudioOptions, run, status } from './run.ts'\n\nexport const runner: CommandRunner<{ args: typeof definition.args; extensions: {} }> = async ({ values }) => {\n const options = createStudioOptions(values)\n await run(options, () => status(options))\n}\n"],"mappings":";;;AAIA,MAAa,SAA0E,OAAO,EAAE,aAAa;CAC3G,MAAM,UAAU,oBAAoB,MAAM;CAC1C,MAAM,IAAI,eAAe,OAAO,OAAO,CAAC;AAC1C"}
@@ -75,6 +75,11 @@ const definition$2 = (0, gunshi.define)({
75
75
  type: "string",
76
76
  description: "Stable identity for the CI agent, such as a pull request. Auto-detected on GitHub Actions, GitLab CI, Bitbucket Pipelines and CircleCI"
77
77
  },
78
+ baseId: {
79
+ type: "string",
80
+ description: "Identity of another CI agent, such as the base branch's, to also compare this snapshot with. Auto-detected on GitHub pull requests and GitLab merge requests",
81
+ toKebab: true
82
+ },
78
83
  name: {
79
84
  type: "string",
80
85
  description: "Package name for the generated tarball. Defaults to the name in package.json"
@@ -138,18 +143,18 @@ const definition = (0, gunshi.define)({
138
143
  ...require_shared.logLevelArg
139
144
  },
140
145
  async run(ctx) {
141
- const { runner } = await Promise.resolve().then(() => require("./connect-B4NIfpxC.cjs"));
146
+ const { runner } = await Promise.resolve().then(() => require("./connect-c9W1razJ.cjs"));
142
147
  await runner(ctx);
143
148
  },
144
149
  subCommands: {
145
- connect: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./connect-B4NIfpxC.cjs"))).runner, definition$5),
146
- login: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./login-CcYnvzn9.cjs"))).runner, definition$4),
147
- logout: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./logout-Bzlys_F2.cjs"))).runner, definition$3),
148
- status: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./status-D9O6D20d.cjs"))).runner, definition$1),
149
- snapshot: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./snapshot-C2dbvseU.cjs"))).runner, definition$2)
150
+ connect: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./connect-c9W1razJ.cjs"))).runner, definition$5),
151
+ login: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./login-DICKtsMS.cjs"))).runner, definition$4),
152
+ logout: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./logout-Cq_SjOQf.cjs"))).runner, definition$3),
153
+ status: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./status-BxUqzCGT.cjs"))).runner, definition$1),
154
+ snapshot: (0, gunshi.lazy)(async () => (await Promise.resolve().then(() => require("./snapshot-BTM3dE9L.cjs"))).runner, definition$2)
150
155
  }
151
156
  });
152
157
  //#endregion
153
158
  exports.definition = definition;
154
159
 
155
- //# sourceMappingURL=studio-D_bRD3nc.cjs.map
160
+ //# sourceMappingURL=studio-BeOQYXoh.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-BeOQYXoh.cjs","names":["definition","define","configArg","studioConnectionArgs","studioPermissionArgs","logLevelArg","definition","define","configArg","studioConnectionArgs","studioPermissionArgs","logLevelArg","definition","define","configArg","studioConnectionArgs","studioPermissionArgs","logLevelArg","definition","define","configArg","studioConnectionArgs","studioPermissionArgs","logLevelArg","definition","define","configArg","studioConnectionArgs","studioPermissionArgs","logLevelArg","define","configArg","studioConnectionArgs","studioPermissionArgs","logLevelArg","lazy","connectDefinition","loginDefinition","logoutDefinition","statusDefinition","snapshotDefinition"],"sources":["../src/commands/studio/connect.ts","../src/commands/studio/login.ts","../src/commands/studio/logout.ts","../src/commands/studio/snapshot.ts","../src/commands/studio/status.ts","../src/commands/studio/index.ts"],"sourcesContent":["import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'connect',\n description: 'Connect this project to Kubb Studio and generate from the browser.',\n examples: [\n 'kubb studio connect',\n 'kubb studio connect --allow-read',\n 'kubb studio connect --allow-write --allow-exec',\n 'kubb studio connect --url http://localhost:3000',\n ].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n open: {\n type: 'boolean',\n description: 'Open the approval page in a browser while pairing',\n default: true,\n negatable: true,\n },\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'login',\n description: 'Pair this machine with Kubb Studio without connecting.',\n examples: ['kubb studio login', 'kubb studio login --url http://localhost:3000'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n open: {\n type: 'boolean',\n description: 'Open the approval page in a browser while pairing',\n default: true,\n negatable: true,\n },\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'logout',\n description: 'Forget the stored Kubb Studio token.',\n examples: ['kubb studio logout'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'snapshot',\n description: 'Generate and publish a Kubb Studio snapshot from CI.',\n examples: ['kubb studio snapshot', 'kubb studio snapshot --json'].join('\\n'),\n toKebab: true,\n rendering: {\n header: null,\n },\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n id: {\n type: 'string',\n description: 'Stable identity for the CI agent, such as a pull request. Auto-detected on GitHub Actions, GitLab CI, Bitbucket Pipelines and CircleCI',\n },\n baseId: {\n type: 'string',\n description:\n \"Identity of another CI agent, such as the base branch's, to also compare this snapshot with. Auto-detected on GitHub pull requests and GitLab merge requests\",\n toKebab: true,\n },\n name: {\n type: 'string',\n description: 'Package name for the generated tarball. Defaults to the name in package.json',\n },\n packageVersion: {\n type: 'string',\n description: 'Package version for the generated tarball. Defaults to the version in package.json',\n toKebab: true,\n },\n timeout: {\n type: 'number',\n description: 'Seconds to wait for the job to finish',\n default: 600,\n },\n json: {\n type: 'boolean',\n description: 'Print the result as one JSON object instead of a summary',\n default: false,\n },\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'status',\n description: 'Show the machine’s Kubb Studio pairing and saved project permissions.',\n examples: ['kubb studio status'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n ...logLevelArg,\n },\n})\n","import { define, lazy } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\nimport { definition as connectDefinition } from './connect.ts'\nimport { definition as loginDefinition } from './login.ts'\nimport { definition as logoutDefinition } from './logout.ts'\nimport { definition as snapshotDefinition } from './snapshot.ts'\nimport { definition as statusDefinition } from './status.ts'\n\nexport const definition = define({\n name: 'studio',\n description: 'Connect this project to Kubb Studio, or manage its pairing and snapshots.',\n examples: ['kubb studio', 'kubb studio --allow-read', 'kubb studio login', 'kubb studio status', 'kubb studio logout', 'kubb studio snapshot'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n open: {\n type: 'boolean',\n description: 'Open the approval page in a browser while pairing',\n default: true,\n negatable: true,\n },\n ...logLevelArg,\n },\n async run(ctx) {\n const { runner } = await import('../../runners/studio/connect.ts')\n await runner(ctx)\n },\n subCommands: {\n connect: lazy(async () => (await import('../../runners/studio/connect.ts')).runner, connectDefinition),\n login: lazy(async () => (await import('../../runners/studio/login.ts')).runner, loginDefinition),\n logout: lazy(async () => (await import('../../runners/studio/logout.ts')).runner, logoutDefinition),\n status: lazy(async () => (await import('../../runners/studio/status.ts')).runner, statusDefinition),\n snapshot: lazy(async () => (await import('../../runners/studio/snapshot.ts')).runner, snapshotDefinition),\n },\n})\n"],"mappings":"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"}
@@ -75,6 +75,11 @@ const definition$2 = define({
75
75
  type: "string",
76
76
  description: "Stable identity for the CI agent, such as a pull request. Auto-detected on GitHub Actions, GitLab CI, Bitbucket Pipelines and CircleCI"
77
77
  },
78
+ baseId: {
79
+ type: "string",
80
+ description: "Identity of another CI agent, such as the base branch's, to also compare this snapshot with. Auto-detected on GitHub pull requests and GitLab merge requests",
81
+ toKebab: true
82
+ },
78
83
  name: {
79
84
  type: "string",
80
85
  description: "Package name for the generated tarball. Defaults to the name in package.json"
@@ -138,18 +143,18 @@ const definition = define({
138
143
  ...logLevelArg
139
144
  },
140
145
  async run(ctx) {
141
- const { runner } = await import("./connect-CgkbDN1-.js");
146
+ const { runner } = await import("./connect-DQWYjheY.js");
142
147
  await runner(ctx);
143
148
  },
144
149
  subCommands: {
145
- connect: lazy(async () => (await import("./connect-CgkbDN1-.js")).runner, definition$5),
146
- login: lazy(async () => (await import("./login-VlfI9Xcv.js")).runner, definition$4),
147
- logout: lazy(async () => (await import("./logout-BNlPXi-7.js")).runner, definition$3),
148
- status: lazy(async () => (await import("./status-CKhgk59o.js")).runner, definition$1),
149
- snapshot: lazy(async () => (await import("./snapshot-CWZAiRmb.js")).runner, definition$2)
150
+ connect: lazy(async () => (await import("./connect-DQWYjheY.js")).runner, definition$5),
151
+ login: lazy(async () => (await import("./login-Bkm0Bcwh.js")).runner, definition$4),
152
+ logout: lazy(async () => (await import("./logout-CCAt5yNI.js")).runner, definition$3),
153
+ status: lazy(async () => (await import("./status-QnFiAJK0.js")).runner, definition$1),
154
+ snapshot: lazy(async () => (await import("./snapshot-Bxlj-1OJ.js")).runner, definition$2)
150
155
  }
151
156
  });
152
157
  //#endregion
153
158
  export { definition };
154
159
 
155
- //# sourceMappingURL=studio-DFZKPTAs.js.map
160
+ //# sourceMappingURL=studio-C2FsZ4zt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-C2FsZ4zt.js","names":["definition","definition","definition","definition","definition","connectDefinition","loginDefinition","logoutDefinition","statusDefinition","snapshotDefinition"],"sources":["../src/commands/studio/connect.ts","../src/commands/studio/login.ts","../src/commands/studio/logout.ts","../src/commands/studio/snapshot.ts","../src/commands/studio/status.ts","../src/commands/studio/index.ts"],"sourcesContent":["import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'connect',\n description: 'Connect this project to Kubb Studio and generate from the browser.',\n examples: [\n 'kubb studio connect',\n 'kubb studio connect --allow-read',\n 'kubb studio connect --allow-write --allow-exec',\n 'kubb studio connect --url http://localhost:3000',\n ].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n open: {\n type: 'boolean',\n description: 'Open the approval page in a browser while pairing',\n default: true,\n negatable: true,\n },\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'login',\n description: 'Pair this machine with Kubb Studio without connecting.',\n examples: ['kubb studio login', 'kubb studio login --url http://localhost:3000'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n open: {\n type: 'boolean',\n description: 'Open the approval page in a browser while pairing',\n default: true,\n negatable: true,\n },\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'logout',\n description: 'Forget the stored Kubb Studio token.',\n examples: ['kubb studio logout'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'snapshot',\n description: 'Generate and publish a Kubb Studio snapshot from CI.',\n examples: ['kubb studio snapshot', 'kubb studio snapshot --json'].join('\\n'),\n toKebab: true,\n rendering: {\n header: null,\n },\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n id: {\n type: 'string',\n description: 'Stable identity for the CI agent, such as a pull request. Auto-detected on GitHub Actions, GitLab CI, Bitbucket Pipelines and CircleCI',\n },\n baseId: {\n type: 'string',\n description:\n \"Identity of another CI agent, such as the base branch's, to also compare this snapshot with. Auto-detected on GitHub pull requests and GitLab merge requests\",\n toKebab: true,\n },\n name: {\n type: 'string',\n description: 'Package name for the generated tarball. Defaults to the name in package.json',\n },\n packageVersion: {\n type: 'string',\n description: 'Package version for the generated tarball. Defaults to the version in package.json',\n toKebab: true,\n },\n timeout: {\n type: 'number',\n description: 'Seconds to wait for the job to finish',\n default: 600,\n },\n json: {\n type: 'boolean',\n description: 'Print the result as one JSON object instead of a summary',\n default: false,\n },\n ...logLevelArg,\n },\n})\n","import { define } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\n\nexport const definition = define({\n name: 'status',\n description: 'Show the machine’s Kubb Studio pairing and saved project permissions.',\n examples: ['kubb studio status'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n ...logLevelArg,\n },\n})\n","import { define, lazy } from 'gunshi'\nimport { configArg, logLevelArg, studioConnectionArgs, studioPermissionArgs } from '../shared.ts'\nimport { definition as connectDefinition } from './connect.ts'\nimport { definition as loginDefinition } from './login.ts'\nimport { definition as logoutDefinition } from './logout.ts'\nimport { definition as snapshotDefinition } from './snapshot.ts'\nimport { definition as statusDefinition } from './status.ts'\n\nexport const definition = define({\n name: 'studio',\n description: 'Connect this project to Kubb Studio, or manage its pairing and snapshots.',\n examples: ['kubb studio', 'kubb studio --allow-read', 'kubb studio login', 'kubb studio status', 'kubb studio logout', 'kubb studio snapshot'].join('\\n'),\n toKebab: true,\n args: {\n ...configArg,\n ...studioConnectionArgs,\n ...studioPermissionArgs,\n open: {\n type: 'boolean',\n description: 'Open the approval page in a browser while pairing',\n default: true,\n negatable: true,\n },\n ...logLevelArg,\n },\n async run(ctx) {\n const { runner } = await import('../../runners/studio/connect.ts')\n await runner(ctx)\n },\n subCommands: {\n connect: lazy(async () => (await import('../../runners/studio/connect.ts')).runner, connectDefinition),\n login: lazy(async () => (await import('../../runners/studio/login.ts')).runner, loginDefinition),\n logout: lazy(async () => (await import('../../runners/studio/logout.ts')).runner, logoutDefinition),\n status: lazy(async () => (await import('../../runners/studio/status.ts')).runner, statusDefinition),\n snapshot: lazy(async () => (await import('../../runners/studio/snapshot.ts')).runner, snapshotDefinition),\n },\n})\n"],"mappings":";;;;AAGA,MAAaA,eAAa,OAAO;CAC/B,MAAM;CACN,aAAa;CACb,UAAU;EACR;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,SAAS;CACT,MAAM;EACJ,GAAG;EACH,GAAG;EACH,GAAG;EACH,MAAM;GACJ,MAAM;GACN,aAAa;GACb,SAAS;GACT,WAAW;EACb;EACA,GAAG;CACL;AACF,CAAC;;;ACtBD,MAAaC,eAAa,OAAO;CAC/B,MAAM;CACN,aAAa;CACb,UAAU,CAAC,qBAAqB,+CAA+C,CAAC,CAAC,KAAK,IAAI;CAC1F,SAAS;CACT,MAAM;EACJ,GAAG;EACH,GAAG;EACH,GAAG;EACH,MAAM;GACJ,MAAM;GACN,aAAa;GACb,SAAS;GACT,WAAW;EACb;EACA,GAAG;CACL;AACF,CAAC;;;ACjBD,MAAaC,eAAa,OAAO;CAC/B,MAAM;CACN,aAAa;CACb,UAAU,CAAC,oBAAoB,CAAC,CAAC,KAAK,IAAI;CAC1C,SAAS;CACT,MAAM;EACJ,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;CACL;AACF,CAAC;;;ACXD,MAAaC,eAAa,OAAO;CAC/B,MAAM;CACN,aAAa;CACb,UAAU,CAAC,wBAAwB,6BAA6B,CAAC,CAAC,KAAK,IAAI;CAC3E,SAAS;CACT,WAAW,EACT,QAAQ,KACV;CACA,MAAM;EACJ,GAAG;EACH,GAAG;EACH,GAAG;EACH,IAAI;GACF,MAAM;GACN,aAAa;EACf;EACA,QAAQ;GACN,MAAM;GACN,aACE;GACF,SAAS;EACX;EACA,MAAM;GACJ,MAAM;GACN,aAAa;EACf;EACA,gBAAgB;GACd,MAAM;GACN,aAAa;GACb,SAAS;EACX;EACA,SAAS;GACP,MAAM;GACN,aAAa;GACb,SAAS;EACX;EACA,MAAM;GACJ,MAAM;GACN,aAAa;GACb,SAAS;EACX;EACA,GAAG;CACL;AACF,CAAC;;;AC3CD,MAAaC,eAAa,OAAO;CAC/B,MAAM;CACN,aAAa;CACb,UAAU,CAAC,oBAAoB,CAAC,CAAC,KAAK,IAAI;CAC1C,SAAS;CACT,MAAM;EACJ,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;CACL;AACF,CAAC;;;ACND,MAAa,aAAa,OAAO;CAC/B,MAAM;CACN,aAAa;CACb,UAAU;EAAC;EAAe;EAA4B;EAAqB;EAAsB;EAAsB;CAAsB,CAAC,CAAC,KAAK,IAAI;CACxJ,SAAS;CACT,MAAM;EACJ,GAAG;EACH,GAAG;EACH,GAAG;EACH,MAAM;GACJ,MAAM;GACN,aAAa;GACb,SAAS;GACT,WAAW;EACb;EACA,GAAG;CACL;CACA,MAAM,IAAI,KAAK;EACb,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,OAAO,GAAG;CAClB;CACA,aAAa;EACX,SAAS,KAAK,aAAa,MAAM,OAAO,yBAAA,CAAoC,QAAQC,YAAiB;EACrG,OAAO,KAAK,aAAa,MAAM,OAAO,uBAAA,CAAkC,QAAQC,YAAe;EAC/F,QAAQ,KAAK,aAAa,MAAM,OAAO,wBAAA,CAAmC,QAAQC,YAAgB;EAClG,QAAQ,KAAK,aAAa,MAAM,OAAO,wBAAA,CAAmC,QAAQC,YAAgB;EAClG,UAAU,KAAK,aAAa,MAAM,OAAO,0BAAA,CAAqC,QAAQC,YAAkB;CAC1G;AACF,CAAC"}
@@ -340,9 +340,15 @@ function createLogger(writer) {
340
340
  writer.success(text(`✓ Finished ${command}${info ? ` ${(0, node_util.styleText)("dim", `(${info})`)}` : ""}`));
341
341
  startSpinner("✓ Ready to receive jobs");
342
342
  });
343
- context.hook("studio:warn", ({ message }) => {
343
+ context.hook("studio:reconnecting", ({ delayMs }) => {
344
+ if (silent) return;
345
+ stopSpinner();
346
+ writer.info(text((0, node_util.styleText)("dim", `Retrying connection to Kubb Studio in ${require_output.formatMs(delayMs)}`)));
347
+ });
348
+ context.hook("studio:warn", ({ message, permission }) => {
344
349
  if (logLevel < _kubb_core.logLevel.warn) return;
345
- writer.warn(text(`⚠ ${message}`));
350
+ const remedy = permission ? `; pass --${permission.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)} to allow it` : "";
351
+ writer.warn(text(`⚠ ${message}${remedy}`));
346
352
  });
347
353
  context.hook("studio:error", ({ error }) => {
348
354
  const line = `✗ ${error.message}`;
@@ -527,16 +533,9 @@ const SYMBOLS = {
527
533
  error: "✗",
528
534
  step: "◇"
529
535
  };
530
- function write(line) {
531
- console.log(line);
532
- }
533
- /**
534
- * Console adapter for non-TTY environments, and for an AI coding agent reading the output. Reports
535
- * the same run in the same order as `clackLogger`, without the animation.
536
- */
537
- const plainLogger = {
538
- name: "plain",
539
- install: createLogger({
536
+ /** Draws with one `write` call per line. Nothing animates, so a step prints at start and end. */
537
+ function createWriter(write) {
538
+ return {
540
539
  group: write,
541
540
  groupEnd: write,
542
541
  step: (text) => write(`${SYMBOLS.step} ${text}`),
@@ -560,8 +559,20 @@ const plainLogger = {
560
559
  advance: write,
561
560
  stop: (text) => text && write(text)
562
561
  })
563
- })
564
- };
562
+ };
563
+ }
564
+ /** The plain logger writing through `write`, e.g. `console.error` so stdout carries only JSON. */
565
+ function createPlainLogger(write) {
566
+ return {
567
+ name: "plain",
568
+ install: createLogger(createWriter(write))
569
+ };
570
+ }
571
+ /**
572
+ * Console adapter for non-TTY environments, and for an AI coding agent reading the output. Reports
573
+ * the same run in the same order as `clackLogger`, without the animation.
574
+ */
575
+ const plainLogger = createPlainLogger((line) => console.log(line));
565
576
  //#endregion
566
577
  //#region src/loggers/utils.ts
567
578
  /**
@@ -730,7 +741,7 @@ function installReporter(context, reporter, ctx) {
730
741
  * `cli` reporter (live logger and summary) is skipped whenever `json` is among the reporters, even
731
742
  * if `cli` is also listed.
732
743
  */
733
- async function setupReporters(context, { logLevel, reporters }) {
744
+ async function setupReporters(context, { logLevel, reporters, logger: forcedLogger }) {
734
745
  let cliHandle;
735
746
  const hasJson = reporters.some((reporter) => reporter.name === "json");
736
747
  const ctx = { logLevel };
@@ -740,7 +751,7 @@ async function setupReporters(context, { logLevel, reporters }) {
740
751
  continue;
741
752
  }
742
753
  if (hasJson) continue;
743
- const handle = await (require_output.canUseTTY() && !require_agent.getAgentName() ? clackLogger : plainLogger).install(context, { logLevel });
754
+ const handle = await (forcedLogger ?? (require_output.canUseTTY() && !require_agent.getAgentName() ? clackLogger : plainLogger)).install(context, { logLevel }) ?? void 0;
744
755
  cliHandle = handle;
745
756
  installReporter(context, (0, _kubb_core.createCliReporter)({ render: handle?.renderSummary }), ctx);
746
757
  }
@@ -1107,6 +1118,12 @@ Object.defineProperty(exports, "LINTER_PREFERENCE", {
1107
1118
  return LINTER_PREFERENCE;
1108
1119
  }
1109
1120
  });
1121
+ Object.defineProperty(exports, "createPlainLogger", {
1122
+ enumerable: true,
1123
+ get: function() {
1124
+ return createPlainLogger;
1125
+ }
1126
+ });
1110
1127
  Object.defineProperty(exports, "detectTool", {
1111
1128
  enumerable: true,
1112
1129
  get: function() {
@@ -1186,4 +1203,4 @@ Object.defineProperty(exports, "startWatcher", {
1186
1203
  }
1187
1204
  });
1188
1205
 
1189
- //# sourceMappingURL=utils-CyfAlK9G.cjs.map
1206
+ //# sourceMappingURL=utils-DqUNntyL.cjs.map