@kortyx/cli 0.10.1 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/dist/index.js +165 -73
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.11.1](https://github.com/kortyx-io/kortyx/compare/cli-v0.11.0...cli-v0.11.1) (2026-09-21)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* 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))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @kortyx/agent bumped to 0.26.1
|
|
16
|
+
* @kortyx/core bumped to 0.10.1
|
|
17
|
+
* @kortyx/telemetry-contracts bumped to 0.11.1
|
|
18
|
+
|
|
19
|
+
## [0.11.0](https://github.com/kortyx-io/kortyx/compare/cli-v0.10.1...cli-v0.11.0) (2026-09-21)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* **hooks:** add model-driven interrupt contracts to useReason ([#224](https://github.com/kortyx-io/kortyx/issues/224)) ([e0147d5](https://github.com/kortyx-io/kortyx/commit/e0147d5234ca38d450d452af924b242f8cbdeb16))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Dependencies
|
|
28
|
+
|
|
29
|
+
* The following workspace dependencies were updated
|
|
30
|
+
* dependencies
|
|
31
|
+
* @kortyx/agent bumped to 0.26.0
|
|
32
|
+
* @kortyx/core bumped to 0.10.0
|
|
33
|
+
* @kortyx/telemetry-contracts bumped to 0.11.0
|
|
34
|
+
|
|
3
35
|
## [0.10.1](https://github.com/kortyx-io/kortyx/compare/cli-v0.10.0...cli-v0.10.1) (2026-09-21)
|
|
4
36
|
|
|
5
37
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
537
|
+
await writePrivateFileAtomically(
|
|
494
538
|
studioConfigPath(options.home),
|
|
495
539
|
`${JSON.stringify(config, null, 2)}
|
|
496
|
-
|
|
497
|
-
|
|
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
|
-
|
|
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
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
environment
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
"
|
|
996
|
-
|
|
997
|
-
"
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
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
|
|
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
|
|
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 : {};
|
|
@@ -1137,6 +1216,12 @@ var buildStudioTimeline = (events, interrupts = []) => {
|
|
|
1137
1216
|
...interrupt?.interactionMode || stringValue(payload.interactionMode) ? {
|
|
1138
1217
|
interactionMode: interrupt?.interactionMode ?? stringValue(payload.interactionMode)
|
|
1139
1218
|
} : {},
|
|
1219
|
+
...interrupt?.contract || stringValue(payload.contract) ? { contract: interrupt?.contract ?? stringValue(payload.contract) } : {},
|
|
1220
|
+
...interrupt?.schemaId || stringValue(payload.schemaId) ? { schemaId: interrupt?.schemaId ?? stringValue(payload.schemaId) } : {},
|
|
1221
|
+
...interrupt?.schemaVersion || stringValue(payload.schemaVersion) ? {
|
|
1222
|
+
schemaVersion: interrupt?.schemaVersion ?? stringValue(payload.schemaVersion)
|
|
1223
|
+
} : {},
|
|
1224
|
+
...payload.request !== void 0 ? { request: payload.request } : {},
|
|
1140
1225
|
...interrupt?.question !== void 0 && interrupt.question !== null ? { question: interrupt.question } : payload.question !== void 0 ? { question: payload.question } : {}
|
|
1141
1226
|
});
|
|
1142
1227
|
continue;
|
|
@@ -1146,7 +1231,9 @@ var buildStudioTimeline = (events, interrupts = []) => {
|
|
|
1146
1231
|
...base,
|
|
1147
1232
|
kind: "resume",
|
|
1148
1233
|
...stringValue(payload.interruptId) ? { interruptId: stringValue(payload.interruptId) } : {},
|
|
1149
|
-
...stringValue(payload.resumeOutcome) ? { resumeOutcome: stringValue(payload.resumeOutcome) } : {}
|
|
1234
|
+
...stringValue(payload.resumeOutcome) ? { resumeOutcome: stringValue(payload.resumeOutcome) } : {},
|
|
1235
|
+
...stringValue(payload.contract) ? { contract: stringValue(payload.contract) } : {},
|
|
1236
|
+
...payload.responseValue !== void 0 ? { response: payload.responseValue } : payload.response !== void 0 ? { response: payload.response } : {}
|
|
1150
1237
|
});
|
|
1151
1238
|
continue;
|
|
1152
1239
|
}
|
|
@@ -1184,7 +1271,7 @@ var focusStudioEvents = (events, target) => {
|
|
|
1184
1271
|
"The URL has no event, trace, node, branch, or call selector to focus."
|
|
1185
1272
|
);
|
|
1186
1273
|
const callEventIds = new Set(
|
|
1187
|
-
selection.call ? (0,
|
|
1274
|
+
selection.call ? (0, import_telemetry_contracts4.projectWorkflowCalls)(events).filter(
|
|
1188
1275
|
(call) => call.id === selection.call || call.callId === selection.call || call.invocationId === selection.call
|
|
1189
1276
|
).flatMap((call) => call.events.map((event) => event.id)) : []
|
|
1190
1277
|
);
|
|
@@ -1472,8 +1559,12 @@ var sanitizeStudioData = (value, includeContent, key = "") => {
|
|
|
1472
1559
|
var summarizeEvidence = (events) => {
|
|
1473
1560
|
const findings = events.flatMap((event) => {
|
|
1474
1561
|
const payload = event.payload;
|
|
1475
|
-
const
|
|
1476
|
-
const
|
|
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(
|
|
1477
1568
|
event.type
|
|
1478
1569
|
) || ["denied", "cancelled"].includes(String(payload.outcome));
|
|
1479
1570
|
if (!failed && !warning) return [];
|
|
@@ -1559,10 +1650,10 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1559
1650
|
const { connection, client } = await clientFor(options, target.url);
|
|
1560
1651
|
const context = await client.get(
|
|
1561
1652
|
"/v1/studio/context",
|
|
1562
|
-
|
|
1653
|
+
import_telemetry_contracts5.StudioContextResponseSchema
|
|
1563
1654
|
);
|
|
1564
1655
|
const path = `/v1/studio/${target.entity}/${encodeURIComponent(target.id)}`;
|
|
1565
|
-
const detail = target.entity === "runs" ? await client.get(path,
|
|
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);
|
|
1566
1657
|
const limit = options.eventLimit;
|
|
1567
1658
|
const events = [...detail.events].sort(
|
|
1568
1659
|
(a, b) => Date.parse(a.occurredAt) - Date.parse(b.occurredAt) || Date.parse(a.receivedAt) - Date.parse(b.receivedAt) || a.id.localeCompare(b.id)
|
|
@@ -1586,13 +1677,13 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1586
1677
|
),
|
|
1587
1678
|
...analyzedFindings
|
|
1588
1679
|
];
|
|
1589
|
-
const calls = (0,
|
|
1680
|
+
const calls = (0, import_telemetry_contracts5.projectWorkflowCalls)(selectedEvents);
|
|
1590
1681
|
let catalog;
|
|
1591
1682
|
if (target.entity === "runs" && run2) {
|
|
1592
1683
|
try {
|
|
1593
1684
|
const workflows2 = await client.get(
|
|
1594
1685
|
"/v1/studio/workflows",
|
|
1595
|
-
|
|
1686
|
+
import_telemetry_contracts5.StudioWorkflowsResponseSchema,
|
|
1596
1687
|
{ range: "All time", workflow: run2.workflowId }
|
|
1597
1688
|
);
|
|
1598
1689
|
catalog = compareCatalogRuntime(run2, workflows2.workflows);
|
|
@@ -1677,7 +1768,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1677
1768
|
const { connection, client } = await clientFor(options);
|
|
1678
1769
|
const context = await client.get(
|
|
1679
1770
|
"/v1/studio/context",
|
|
1680
|
-
|
|
1771
|
+
import_telemetry_contracts5.StudioContextResponseSchema
|
|
1681
1772
|
);
|
|
1682
1773
|
print(
|
|
1683
1774
|
{
|
|
@@ -1701,7 +1792,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1701
1792
|
connection: connection.name,
|
|
1702
1793
|
data: await client.get(
|
|
1703
1794
|
"/v1/studio/catalogs",
|
|
1704
|
-
|
|
1795
|
+
import_telemetry_contracts5.StudioCatalogsResponseSchema
|
|
1705
1796
|
)
|
|
1706
1797
|
},
|
|
1707
1798
|
options
|
|
@@ -1716,7 +1807,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1716
1807
|
"Studio time range: 1h, 24h, 7d, 30d, all (or Studio preset name)."
|
|
1717
1808
|
).choices([
|
|
1718
1809
|
...Object.keys(rangeAliases),
|
|
1719
|
-
...
|
|
1810
|
+
...import_telemetry_contracts5.StudioTimeRangeSchema.options
|
|
1720
1811
|
]).default("24h")
|
|
1721
1812
|
).option(
|
|
1722
1813
|
"--started-after <iso>",
|
|
@@ -1728,7 +1819,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1728
1819
|
const timeQuery = (options) => {
|
|
1729
1820
|
const custom = Boolean(options.startedAfter || options.startedBefore);
|
|
1730
1821
|
const range = custom ? "Custom range" : rangeAliases[options.range] ?? options.range;
|
|
1731
|
-
const resolution = (0,
|
|
1822
|
+
const resolution = (0, import_telemetry_contracts5.resolveStudioTimeRange)({
|
|
1732
1823
|
range,
|
|
1733
1824
|
startedAfter: options.startedAfter,
|
|
1734
1825
|
startedBefore: options.startedBefore
|
|
@@ -1772,23 +1863,23 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1772
1863
|
);
|
|
1773
1864
|
const context = await client.get(
|
|
1774
1865
|
"/v1/studio/context",
|
|
1775
|
-
|
|
1866
|
+
import_telemetry_contracts5.StudioContextResponseSchema
|
|
1776
1867
|
);
|
|
1777
1868
|
const [leftDetail, rightDetail] = await Promise.all([
|
|
1778
1869
|
client.get(
|
|
1779
1870
|
`/v1/studio/runs/${encodeURIComponent(leftTarget.id)}`,
|
|
1780
|
-
|
|
1871
|
+
import_telemetry_contracts5.StudioRunDetailResponseSchema
|
|
1781
1872
|
),
|
|
1782
1873
|
client.get(
|
|
1783
1874
|
`/v1/studio/runs/${encodeURIComponent(rightTarget.id)}`,
|
|
1784
|
-
|
|
1875
|
+
import_telemetry_contracts5.StudioRunDetailResponseSchema
|
|
1785
1876
|
)
|
|
1786
1877
|
]);
|
|
1787
1878
|
const catalogFor = async (detail) => {
|
|
1788
1879
|
try {
|
|
1789
1880
|
const response = await client.get(
|
|
1790
1881
|
"/v1/studio/workflows",
|
|
1791
|
-
|
|
1882
|
+
import_telemetry_contracts5.StudioWorkflowsResponseSchema,
|
|
1792
1883
|
{ range: "All time", workflow: detail.run.workflowId }
|
|
1793
1884
|
);
|
|
1794
1885
|
return compareCatalogRuntime(detail.run, response.workflows);
|
|
@@ -1894,7 +1985,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1894
1985
|
query.cursor = String(options.cursor);
|
|
1895
1986
|
if (options.includeChildren) query.includeChildren = "true";
|
|
1896
1987
|
const path = `/v1/studio/${entity}`;
|
|
1897
|
-
const data = entity === "runs" ? await client.get(path,
|
|
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);
|
|
1898
1989
|
const items = "runs" in data ? data.runs : "sessions" in data ? data.sessions : data.interrupts;
|
|
1899
1990
|
const next = options.cursor + items.length;
|
|
1900
1991
|
print(
|
|
@@ -1931,7 +2022,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
1931
2022
|
connection: connection.name,
|
|
1932
2023
|
data: await client.get(
|
|
1933
2024
|
"/v1/studio/workflows",
|
|
1934
|
-
|
|
2025
|
+
import_telemetry_contracts5.StudioWorkflowsResponseSchema,
|
|
1935
2026
|
query
|
|
1936
2027
|
),
|
|
1937
2028
|
note: "Workflow metrics span environments; connection environment defaults are not applied by this API."
|
|
@@ -1982,6 +2073,7 @@ var defaultStudioRuntime = {
|
|
|
1982
2073
|
portAvailable,
|
|
1983
2074
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
1984
2075
|
random: (bytes) => (0, import_node_crypto2.randomBytes)(bytes).toString("base64url"),
|
|
2076
|
+
request: fetch,
|
|
1985
2077
|
log: (message = "") => console.log(message),
|
|
1986
2078
|
error: (message = "") => console.error(message)
|
|
1987
2079
|
};
|
|
@@ -2740,7 +2832,7 @@ var pushSnapshot = async (apiUrl, apiKey, snapshot) => {
|
|
|
2740
2832
|
}
|
|
2741
2833
|
);
|
|
2742
2834
|
}
|
|
2743
|
-
return
|
|
2835
|
+
return import_telemetry_contracts6.EnsureWorkflowTopologyResponseSchema.parse(await response.json());
|
|
2744
2836
|
};
|
|
2745
2837
|
var printResults = (results, options) => {
|
|
2746
2838
|
if (options.json) {
|
|
@@ -2820,7 +2912,7 @@ var runTopologyPush = async (rawOptions) => {
|
|
|
2820
2912
|
}
|
|
2821
2913
|
}
|
|
2822
2914
|
const parsedSnapshots = snapshots.map(
|
|
2823
|
-
(snapshot) =>
|
|
2915
|
+
(snapshot) => import_telemetry_contracts6.EnsureWorkflowTopologyRequestSchema.parse(snapshot)
|
|
2824
2916
|
);
|
|
2825
2917
|
const results = [];
|
|
2826
2918
|
for (const snapshot of parsedSnapshots) {
|