@kortyx/cli 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.2](https://github.com/kortyx-io/kortyx/compare/cli-v0.11.1...cli-v0.11.2) (2026-09-22)
4
+
5
+
6
+ ### Dependencies
7
+
8
+ * The following workspace dependencies were updated
9
+ * dependencies
10
+ * @kortyx/agent bumped to 0.26.2
11
+ * @kortyx/core bumped to 0.11.0
12
+
13
+ ## [0.11.1](https://github.com/kortyx-io/kortyx/compare/cli-v0.11.0...cli-v0.11.1) (2026-09-21)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * preserve interrupt control flow and Studio compatibility ([#226](https://github.com/kortyx-io/kortyx/issues/226)) ([72ba7c2](https://github.com/kortyx-io/kortyx/commit/72ba7c2b9a467db0e54b5a4ab5844c8d7f895135))
19
+
20
+
21
+ ### Dependencies
22
+
23
+ * The following workspace dependencies were updated
24
+ * dependencies
25
+ * @kortyx/agent bumped to 0.26.1
26
+ * @kortyx/core bumped to 0.10.1
27
+ * @kortyx/telemetry-contracts bumped to 0.11.1
28
+
3
29
  ## [0.11.0](https://github.com/kortyx-io/kortyx/compare/cli-v0.10.1...cli-v0.11.0) (2026-09-21)
4
30
 
5
31
 
package/dist/index.js CHANGED
@@ -29,12 +29,12 @@ var import_node_os3 = require("os");
29
29
  var import_node_path4 = require("path");
30
30
  var import_agent = require("@kortyx/agent");
31
31
  var import_errors = require("@kortyx/core/errors");
32
- var import_telemetry_contracts4 = require("@kortyx/telemetry-contracts");
32
+ var import_telemetry_contracts6 = require("@kortyx/telemetry-contracts");
33
33
  var import_commander4 = require("commander");
34
34
  var import_api = require("tsx/cjs/api");
35
35
 
36
36
  // src/connections-command.ts
37
- var import_telemetry_contracts = require("@kortyx/telemetry-contracts");
37
+ var import_telemetry_contracts2 = require("@kortyx/telemetry-contracts");
38
38
  var import_commander = require("commander");
39
39
 
40
40
  // src/connections.ts
@@ -45,6 +45,7 @@ var import_node_path2 = require("path");
45
45
  var import_zod2 = require("zod");
46
46
 
47
47
  // src/studio/read-client.ts
48
+ var import_telemetry_contracts = require("@kortyx/telemetry-contracts");
48
49
  var StudioReadError = class extends Error {
49
50
  constructor(code, message, status, requestId) {
50
51
  super(message);
@@ -101,6 +102,10 @@ var StudioReadClient = class {
101
102
  apiKey;
102
103
  request;
103
104
  apiUrl;
105
+ compatibility = {
106
+ protocolVersion: null,
107
+ release: null
108
+ };
104
109
  async get(path, schema, query = {}) {
105
110
  if (!/^\/v1\/studio\/(?:context|catalogs|workflows|(?:runs|sessions|interrupts)(?:\/[^/?#]+)?)$/.test(
106
111
  path
@@ -119,7 +124,8 @@ var StudioReadClient = class {
119
124
  method: "GET",
120
125
  headers: {
121
126
  authorization: `Bearer ${this.apiKey}`,
122
- accept: "application/json"
127
+ accept: "application/json",
128
+ "x-kortyx-studio-api-version": import_telemetry_contracts.STUDIO_API_PROTOCOL_VERSION
123
129
  },
124
130
  redirect: "error",
125
131
  signal: AbortSignal.timeout(15e3)
@@ -131,6 +137,19 @@ var StudioReadClient = class {
131
137
  );
132
138
  }
133
139
  const requestId = response.headers.get("x-request-id") ?? void 0;
140
+ this.compatibility = {
141
+ protocolVersion: response.headers.get("x-kortyx-studio-api-version"),
142
+ release: response.headers.get("x-kortyx-studio-release")
143
+ };
144
+ if (this.compatibility.protocolVersion && this.compatibility.protocolVersion !== import_telemetry_contracts.STUDIO_API_PROTOCOL_VERSION) {
145
+ await response.body?.cancel();
146
+ throw new StudioReadError(
147
+ "incompatible_studio_api",
148
+ `This CLI supports Studio API v${import_telemetry_contracts.STUDIO_API_PROTOCOL_VERSION}, but the server reports v${this.compatibility.protocolVersion}${this.compatibility.release ? ` (${this.compatibility.release})` : ""}. Install a CLI and Studio release that use the same Studio API major.`,
149
+ response.status,
150
+ requestId
151
+ );
152
+ }
134
153
  if (!response.ok) {
135
154
  await response.body?.cancel();
136
155
  const message = response.status === 401 ? "Invalid, expired, or revoked Studio read key." : response.status === 403 ? "The API key lacks studio:read permission." : response.status === 404 ? "Entity not found in this connection's project. Check the URL and selected connection." : `Studio API returned HTTP ${response.status}.`;
@@ -180,9 +199,10 @@ var StudioReadClient = class {
180
199
  }
181
200
  const result = schema.safeParse(value);
182
201
  if (!result.success) {
202
+ const server = this.compatibility.protocolVersion ? `Studio API v${this.compatibility.protocolVersion}${this.compatibility.release ? ` (${this.compatibility.release})` : ""}` : "a server that did not report its Studio API version";
183
203
  throw new StudioReadError(
184
204
  "schema_mismatch",
185
- "Studio response does not match this CLI's contracts. Check API/CLI version compatibility.",
205
+ `Studio response does not match this CLI's Studio API v${import_telemetry_contracts.STUDIO_API_PROTOCOL_VERSION} contracts. The response came from ${server}. Upgrade both components if this server predates protocol negotiation; otherwise report this as an API compatibility regression.`,
186
206
  response.status,
187
207
  requestId
188
208
  );
@@ -245,6 +265,7 @@ services:
245
265
  NODE_ENV: production
246
266
  API_HOST: 0.0.0.0
247
267
  API_PORT: 6400
268
+ KORTYX_STUDIO_RELEASE: \${KORTYX_STUDIO_IMAGE_TAG:-latest}
248
269
  ports:
249
270
  - "127.0.0.1:\${API_PORT:-6400}:6400"
250
271
  depends_on:
@@ -447,6 +468,29 @@ var writePrivateFileAtomically = async (path, contents) => {
447
468
  }
448
469
  }
449
470
  };
471
+ var readOptionalFile = async (path) => {
472
+ try {
473
+ return await (0, import_promises.readFile)(path, "utf8");
474
+ } catch (error) {
475
+ if (isMissingFile(error)) return null;
476
+ throw error;
477
+ }
478
+ };
479
+ var captureStudioState = async (home) => ({
480
+ config: await readOptionalFile(studioConfigPath(home)),
481
+ environment: await readOptionalFile(studioEnvPath(home)),
482
+ compose: await readOptionalFile(studioComposePath(home))
483
+ });
484
+ var restoreStudioState = async (home, snapshot) => {
485
+ for (const [path, contents] of [
486
+ [studioConfigPath(home), snapshot.config],
487
+ [studioEnvPath(home), snapshot.environment],
488
+ [studioComposePath(home), snapshot.compose]
489
+ ]) {
490
+ if (contents === null) await (0, import_promises.unlink)(path).catch(() => void 0);
491
+ else await writePrivateFileAtomically(path, contents);
492
+ }
493
+ };
450
494
  var readStudioEnvironment = async (home) => {
451
495
  const path = studioEnvPath(home);
452
496
  return parseEnvironmentFile(await (0, import_promises.readFile)(path, "utf8"), path);
@@ -490,17 +534,15 @@ var ensureStudioState = async (options, runtime) => {
490
534
  await (0, import_promises.mkdir)((0, import_node_path.join)(options.home, ".updates"), { recursive: true, mode: 448 });
491
535
  const existing = await readStudioConfig(options.home);
492
536
  const config = resolveConfig(existing, options, runtime);
493
- await (0, import_promises.writeFile)(
537
+ await writePrivateFileAtomically(
494
538
  studioConfigPath(options.home),
495
539
  `${JSON.stringify(config, null, 2)}
496
- `,
497
- { mode: 384 }
540
+ `
541
+ );
542
+ await writePrivateFileAtomically(
543
+ studioComposePath(options.home),
544
+ STUDIO_COMPOSE_FILE
498
545
  );
499
- await (0, import_promises.chmod)(studioConfigPath(options.home), 384);
500
- await (0, import_promises.writeFile)(studioComposePath(options.home), STUDIO_COMPOSE_FILE, {
501
- mode: 384
502
- });
503
- await (0, import_promises.chmod)(studioComposePath(options.home), 384);
504
546
  let environment;
505
547
  try {
506
548
  environment = await readStudioEnvironment(options.home);
@@ -772,7 +814,7 @@ var createConnectionsCommand = (log = console.log, request = fetch) => {
772
814
  );
773
815
  const context = await client.get(
774
816
  "/v1/studio/context",
775
- import_telemetry_contracts.StudioContextResponseSchema
817
+ import_telemetry_contracts2.StudioContextResponseSchema
776
818
  );
777
819
  if (!context.apiKey.scopes.includes("studio:read"))
778
820
  throw new StudioReadError(
@@ -838,6 +880,7 @@ var import_commander3 = require("commander");
838
880
 
839
881
  // src/studio/local-stack.ts
840
882
  var import_promises3 = require("fs/promises");
883
+ var import_telemetry_contracts3 = require("@kortyx/telemetry-contracts");
841
884
  var composeArgs = (home, args) => [
842
885
  "compose",
843
886
  "--env-file",
@@ -980,45 +1023,63 @@ var rotateStudioCredentials = async (home, runtime) => {
980
1023
  };
981
1024
  var startStudio = async (options, runtime) => {
982
1025
  await preflightDocker(runtime);
983
- const config = await ensureStudioState(options, runtime);
984
- const environment = await readStudioEnvironment(options.home);
985
- const apiImage = String(
986
- environment.KORTYX_API_IMAGE_REF ?? `${environment.KORTYX_API_IMAGE ?? "ghcr.io/kortyx-io/kortyx-api"}:${config.imageTag}`
987
- );
988
- await runtime.run("docker", ["pull", apiImage], { inherit: true });
989
- const capability = await runtime.run(
990
- "docker",
991
- [
992
- "run",
993
- "--rm",
994
- "--entrypoint",
995
- "node",
996
- apiImage,
997
- "-e",
998
- 'if (require("node:fs").existsSync("/app/apps/api/dist/updater.js")) console.log("supported")'
999
- ],
1000
- { inherit: false }
1001
- );
1002
- await (0, import_promises3.writeFile)(
1003
- studioComposePath(options.home),
1004
- studioComposeFile(
1005
- process.platform !== "win32" && capability.stdout.trim() === "supported"
1006
- ),
1007
- { mode: 384 }
1008
- );
1009
- if (!await hasRunningServices(options.home, runtime)) {
1010
- await assertPortsAvailable(config, runtime);
1026
+ const snapshot = await captureStudioState(options.home);
1027
+ try {
1028
+ const config = await ensureStudioState(options, runtime);
1029
+ const environment = await readStudioEnvironment(options.home);
1030
+ const apiImage = String(
1031
+ environment.KORTYX_API_IMAGE_REF ?? `${environment.KORTYX_API_IMAGE ?? "ghcr.io/kortyx-io/kortyx-api"}:${config.imageTag}`
1032
+ );
1033
+ const studioImage = String(
1034
+ environment.KORTYX_STUDIO_IMAGE_REF ?? `${environment.KORTYX_STUDIO_IMAGE ?? "ghcr.io/kortyx-io/kortyx-studio"}:${config.imageTag}`
1035
+ );
1036
+ await runtime.run("docker", ["pull", apiImage], { inherit: true });
1037
+ if (studioImage !== apiImage)
1038
+ await runtime.run("docker", ["pull", studioImage], { inherit: true });
1039
+ const capability = await runtime.run(
1040
+ "docker",
1041
+ [
1042
+ "run",
1043
+ "--rm",
1044
+ "--entrypoint",
1045
+ "node",
1046
+ apiImage,
1047
+ "-e",
1048
+ 'if (require("node:fs").existsSync("/app/apps/api/dist/updater.js")) console.log("supported")'
1049
+ ],
1050
+ { inherit: false }
1051
+ );
1052
+ await (0, import_promises3.writeFile)(
1053
+ studioComposePath(options.home),
1054
+ studioComposeFile(
1055
+ process.platform !== "win32" && capability.stdout.trim() === "supported"
1056
+ ),
1057
+ { mode: 384 }
1058
+ );
1059
+ if (!await hasRunningServices(options.home, runtime)) {
1060
+ await assertPortsAvailable(config, runtime);
1061
+ }
1062
+ runtime.log(
1063
+ "Starting Kortyx Studio. The first image pull can take a few minutes."
1064
+ );
1065
+ await runCompose(
1066
+ options.home,
1067
+ ["up", "-d", "--remove-orphans", "--wait", "--wait-timeout", "180"],
1068
+ runtime
1069
+ );
1070
+ runtime.log("Kortyx Studio is ready.");
1071
+ await printStudioConnection(options.home, config, runtime);
1072
+ } catch (error) {
1073
+ try {
1074
+ await restoreStudioState(options.home, snapshot);
1075
+ } catch (rollbackError) {
1076
+ throw new AggregateError(
1077
+ [error, rollbackError],
1078
+ `Studio startup failed and the previous configuration could not be restored. Inspect "${options.home}" before retrying.`
1079
+ );
1080
+ }
1081
+ throw error;
1011
1082
  }
1012
- runtime.log(
1013
- "Starting Kortyx Studio. The first image pull can take a few minutes."
1014
- );
1015
- await runCompose(
1016
- options.home,
1017
- ["up", "-d", "--remove-orphans", "--wait", "--wait-timeout", "180"],
1018
- runtime
1019
- );
1020
- runtime.log("Kortyx Studio is ready.");
1021
- await printStudioConnection(options.home, config, runtime);
1022
1083
  };
1023
1084
  var stopStudio = async (home, runtime) => {
1024
1085
  await preflightDocker(runtime);
@@ -1046,6 +1107,24 @@ var showStudioStatus = async (home, runtime) => {
1046
1107
  runtime.log();
1047
1108
  runtime.log(`Studio: http://localhost:${config.studioPort}`);
1048
1109
  runtime.log(`API: http://localhost:${config.apiPort}`);
1110
+ if (runtime.request) {
1111
+ const environment = await readStudioEnvironment(home);
1112
+ const client = new StudioReadClient(
1113
+ `http://localhost:${config.apiPort}`,
1114
+ environment.KORTYX_STUDIO_API_KEY,
1115
+ runtime.request
1116
+ );
1117
+ try {
1118
+ await client.get("/v1/studio/context", import_telemetry_contracts3.StudioContextResponseSchema);
1119
+ runtime.log(
1120
+ client.compatibility.protocolVersion ? `Compatibility: Studio API v${client.compatibility.protocolVersion} (${client.compatibility.release ?? config.imageTag}) is compatible with CLI API v${import_telemetry_contracts3.STUDIO_API_PROTOCOL_VERSION}.` : `Compatibility: response is compatible with CLI API v${import_telemetry_contracts3.STUDIO_API_PROTOCOL_VERSION}; this older server does not report its protocol version.`
1121
+ );
1122
+ } catch (error) {
1123
+ runtime.log(
1124
+ `Compatibility: ${error instanceof StudioReadError ? error.message : "could not query the Studio API."}`
1125
+ );
1126
+ }
1127
+ }
1049
1128
  runtime.log(`State: ${home}`);
1050
1129
  };
1051
1130
  var showStudioLogs = async (home, follow, runtime) => {
@@ -1072,11 +1151,11 @@ var resetStudio = async (home, confirm, runtime) => {
1072
1151
  };
1073
1152
 
1074
1153
  // src/studio/read-command.ts
1075
- var import_telemetry_contracts3 = require("@kortyx/telemetry-contracts");
1154
+ var import_telemetry_contracts5 = require("@kortyx/telemetry-contracts");
1076
1155
  var import_commander2 = require("commander");
1077
1156
 
1078
1157
  // src/studio/read-analysis.ts
1079
- var import_telemetry_contracts2 = require("@kortyx/telemetry-contracts");
1158
+ var import_telemetry_contracts4 = require("@kortyx/telemetry-contracts");
1080
1159
  var stringValue = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
1081
1160
  var numberValue = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
1082
1161
  var recordValue = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -1192,7 +1271,7 @@ var focusStudioEvents = (events, target) => {
1192
1271
  "The URL has no event, trace, node, branch, or call selector to focus."
1193
1272
  );
1194
1273
  const callEventIds = new Set(
1195
- selection.call ? (0, import_telemetry_contracts2.projectWorkflowCalls)(events).filter(
1274
+ selection.call ? (0, import_telemetry_contracts4.projectWorkflowCalls)(events).filter(
1196
1275
  (call) => call.id === selection.call || call.callId === selection.call || call.invocationId === selection.call
1197
1276
  ).flatMap((call) => call.events.map((event) => event.id)) : []
1198
1277
  );
@@ -1480,8 +1559,12 @@ var sanitizeStudioData = (value, includeContent, key = "") => {
1480
1559
  var summarizeEvidence = (events) => {
1481
1560
  const findings = events.flatMap((event) => {
1482
1561
  const payload = event.payload;
1483
- const failed = /(?:failed|error|fault)/i.test(event.type) || payload.outcome === "fault" || payload.status === "failed";
1484
- const warning = /(?:retry|cancel|interrupt|limit_reached|denied|suspended|waiting)/i.test(
1562
+ const error = payload.error && typeof payload.error === "object" && !Array.isArray(payload.error) ? payload.error : {};
1563
+ const suspension = event.type === "span.failed" && (error.controlFlow === true || ["GraphInterrupt", "NodeInterrupt", "ParallelChildWaiting"].includes(
1564
+ String(error.name)
1565
+ ));
1566
+ const failed = !suspension && (/(?:failed|error|fault)/i.test(event.type) || payload.outcome === "fault" || payload.status === "failed");
1567
+ const warning = suspension || /(?:retry|cancel|interrupt|limit_reached|denied|suspended|waiting)/i.test(
1485
1568
  event.type
1486
1569
  ) || ["denied", "cancelled"].includes(String(payload.outcome));
1487
1570
  if (!failed && !warning) return [];
@@ -1567,10 +1650,10 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1567
1650
  const { connection, client } = await clientFor(options, target.url);
1568
1651
  const context = await client.get(
1569
1652
  "/v1/studio/context",
1570
- import_telemetry_contracts3.StudioContextResponseSchema
1653
+ import_telemetry_contracts5.StudioContextResponseSchema
1571
1654
  );
1572
1655
  const path = `/v1/studio/${target.entity}/${encodeURIComponent(target.id)}`;
1573
- const detail = target.entity === "runs" ? await client.get(path, import_telemetry_contracts3.StudioRunDetailResponseSchema) : target.entity === "sessions" ? await client.get(path, import_telemetry_contracts3.StudioSessionDetailResponseSchema) : await client.get(path, import_telemetry_contracts3.StudioInterruptDetailResponseSchema);
1656
+ const detail = target.entity === "runs" ? await client.get(path, import_telemetry_contracts5.StudioRunDetailResponseSchema) : target.entity === "sessions" ? await client.get(path, import_telemetry_contracts5.StudioSessionDetailResponseSchema) : await client.get(path, import_telemetry_contracts5.StudioInterruptDetailResponseSchema);
1574
1657
  const limit = options.eventLimit;
1575
1658
  const events = [...detail.events].sort(
1576
1659
  (a, b) => Date.parse(a.occurredAt) - Date.parse(b.occurredAt) || Date.parse(a.receivedAt) - Date.parse(b.receivedAt) || a.id.localeCompare(b.id)
@@ -1594,13 +1677,13 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1594
1677
  ),
1595
1678
  ...analyzedFindings
1596
1679
  ];
1597
- const calls = (0, import_telemetry_contracts3.projectWorkflowCalls)(selectedEvents);
1680
+ const calls = (0, import_telemetry_contracts5.projectWorkflowCalls)(selectedEvents);
1598
1681
  let catalog;
1599
1682
  if (target.entity === "runs" && run2) {
1600
1683
  try {
1601
1684
  const workflows2 = await client.get(
1602
1685
  "/v1/studio/workflows",
1603
- import_telemetry_contracts3.StudioWorkflowsResponseSchema,
1686
+ import_telemetry_contracts5.StudioWorkflowsResponseSchema,
1604
1687
  { range: "All time", workflow: run2.workflowId }
1605
1688
  );
1606
1689
  catalog = compareCatalogRuntime(run2, workflows2.workflows);
@@ -1685,7 +1768,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1685
1768
  const { connection, client } = await clientFor(options);
1686
1769
  const context = await client.get(
1687
1770
  "/v1/studio/context",
1688
- import_telemetry_contracts3.StudioContextResponseSchema
1771
+ import_telemetry_contracts5.StudioContextResponseSchema
1689
1772
  );
1690
1773
  print(
1691
1774
  {
@@ -1709,7 +1792,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1709
1792
  connection: connection.name,
1710
1793
  data: await client.get(
1711
1794
  "/v1/studio/catalogs",
1712
- import_telemetry_contracts3.StudioCatalogsResponseSchema
1795
+ import_telemetry_contracts5.StudioCatalogsResponseSchema
1713
1796
  )
1714
1797
  },
1715
1798
  options
@@ -1724,7 +1807,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1724
1807
  "Studio time range: 1h, 24h, 7d, 30d, all (or Studio preset name)."
1725
1808
  ).choices([
1726
1809
  ...Object.keys(rangeAliases),
1727
- ...import_telemetry_contracts3.StudioTimeRangeSchema.options
1810
+ ...import_telemetry_contracts5.StudioTimeRangeSchema.options
1728
1811
  ]).default("24h")
1729
1812
  ).option(
1730
1813
  "--started-after <iso>",
@@ -1736,7 +1819,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1736
1819
  const timeQuery = (options) => {
1737
1820
  const custom = Boolean(options.startedAfter || options.startedBefore);
1738
1821
  const range = custom ? "Custom range" : rangeAliases[options.range] ?? options.range;
1739
- const resolution = (0, import_telemetry_contracts3.resolveStudioTimeRange)({
1822
+ const resolution = (0, import_telemetry_contracts5.resolveStudioTimeRange)({
1740
1823
  range,
1741
1824
  startedAfter: options.startedAfter,
1742
1825
  startedBefore: options.startedBefore
@@ -1780,23 +1863,23 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1780
1863
  );
1781
1864
  const context = await client.get(
1782
1865
  "/v1/studio/context",
1783
- import_telemetry_contracts3.StudioContextResponseSchema
1866
+ import_telemetry_contracts5.StudioContextResponseSchema
1784
1867
  );
1785
1868
  const [leftDetail, rightDetail] = await Promise.all([
1786
1869
  client.get(
1787
1870
  `/v1/studio/runs/${encodeURIComponent(leftTarget.id)}`,
1788
- import_telemetry_contracts3.StudioRunDetailResponseSchema
1871
+ import_telemetry_contracts5.StudioRunDetailResponseSchema
1789
1872
  ),
1790
1873
  client.get(
1791
1874
  `/v1/studio/runs/${encodeURIComponent(rightTarget.id)}`,
1792
- import_telemetry_contracts3.StudioRunDetailResponseSchema
1875
+ import_telemetry_contracts5.StudioRunDetailResponseSchema
1793
1876
  )
1794
1877
  ]);
1795
1878
  const catalogFor = async (detail) => {
1796
1879
  try {
1797
1880
  const response = await client.get(
1798
1881
  "/v1/studio/workflows",
1799
- import_telemetry_contracts3.StudioWorkflowsResponseSchema,
1882
+ import_telemetry_contracts5.StudioWorkflowsResponseSchema,
1800
1883
  { range: "All time", workflow: detail.run.workflowId }
1801
1884
  );
1802
1885
  return compareCatalogRuntime(detail.run, response.workflows);
@@ -1902,7 +1985,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1902
1985
  query.cursor = String(options.cursor);
1903
1986
  if (options.includeChildren) query.includeChildren = "true";
1904
1987
  const path = `/v1/studio/${entity}`;
1905
- const data = entity === "runs" ? await client.get(path, import_telemetry_contracts3.StudioRunsResponseSchema, query) : entity === "sessions" ? await client.get(path, import_telemetry_contracts3.StudioSessionsResponseSchema, query) : await client.get(path, import_telemetry_contracts3.StudioInterruptsResponseSchema, query);
1988
+ const data = entity === "runs" ? await client.get(path, import_telemetry_contracts5.StudioRunsResponseSchema, query) : entity === "sessions" ? await client.get(path, import_telemetry_contracts5.StudioSessionsResponseSchema, query) : await client.get(path, import_telemetry_contracts5.StudioInterruptsResponseSchema, query);
1906
1989
  const items = "runs" in data ? data.runs : "sessions" in data ? data.sessions : data.interrupts;
1907
1990
  const next = options.cursor + items.length;
1908
1991
  print(
@@ -1939,7 +2022,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
1939
2022
  connection: connection.name,
1940
2023
  data: await client.get(
1941
2024
  "/v1/studio/workflows",
1942
- import_telemetry_contracts3.StudioWorkflowsResponseSchema,
2025
+ import_telemetry_contracts5.StudioWorkflowsResponseSchema,
1943
2026
  query
1944
2027
  ),
1945
2028
  note: "Workflow metrics span environments; connection environment defaults are not applied by this API."
@@ -1990,6 +2073,7 @@ var defaultStudioRuntime = {
1990
2073
  portAvailable,
1991
2074
  now: () => (/* @__PURE__ */ new Date()).toISOString(),
1992
2075
  random: (bytes) => (0, import_node_crypto2.randomBytes)(bytes).toString("base64url"),
2076
+ request: fetch,
1993
2077
  log: (message = "") => console.log(message),
1994
2078
  error: (message = "") => console.error(message)
1995
2079
  };
@@ -2748,7 +2832,7 @@ var pushSnapshot = async (apiUrl, apiKey, snapshot) => {
2748
2832
  }
2749
2833
  );
2750
2834
  }
2751
- return import_telemetry_contracts4.EnsureWorkflowTopologyResponseSchema.parse(await response.json());
2835
+ return import_telemetry_contracts6.EnsureWorkflowTopologyResponseSchema.parse(await response.json());
2752
2836
  };
2753
2837
  var printResults = (results, options) => {
2754
2838
  if (options.json) {
@@ -2828,7 +2912,7 @@ var runTopologyPush = async (rawOptions) => {
2828
2912
  }
2829
2913
  }
2830
2914
  const parsedSnapshots = snapshots.map(
2831
- (snapshot) => import_telemetry_contracts4.EnsureWorkflowTopologyRequestSchema.parse(snapshot)
2915
+ (snapshot) => import_telemetry_contracts6.EnsureWorkflowTopologyRequestSchema.parse(snapshot)
2832
2916
  );
2833
2917
  const results = [];
2834
2918
  for (const snapshot of parsedSnapshots) {