@kortyx/cli 0.14.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/index.js +91 -14
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.15.1](https://github.com/kortyx-io/kortyx/compare/cli-v0.15.0...cli-v0.15.1) (2026-10-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Dependencies
|
|
7
|
+
|
|
8
|
+
* The following workspace dependencies were updated
|
|
9
|
+
* dependencies
|
|
10
|
+
* @kortyx/agent bumped to 0.32.0
|
|
11
|
+
|
|
12
|
+
## [0.15.0](https://github.com/kortyx-io/kortyx/compare/cli-v0.14.0...cli-v0.15.0) (2026-10-08)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **telemetry:** preserve complete private error diagnostics ([#290](https://github.com/kortyx-io/kortyx/issues/290)) ([e1c5a88](https://github.com/kortyx-io/kortyx/commit/e1c5a88c494016fd84a1af40579412fcfde31271))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Dependencies
|
|
21
|
+
|
|
22
|
+
* The following workspace dependencies were updated
|
|
23
|
+
* dependencies
|
|
24
|
+
* @kortyx/agent bumped to 0.31.1
|
|
25
|
+
* @kortyx/core bumped to 0.12.0
|
|
26
|
+
* @kortyx/telemetry-contracts bumped to 0.15.0
|
|
27
|
+
|
|
3
28
|
## [0.14.0](https://github.com/kortyx-io/kortyx/compare/cli-v0.13.0...cli-v0.14.0) (2026-10-07)
|
|
4
29
|
|
|
5
30
|
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
|
|
25
25
|
// src/index.ts
|
|
26
|
-
var
|
|
26
|
+
var import_promises6 = require("fs/promises");
|
|
27
27
|
var import_node_module = __toESM(require("module"));
|
|
28
28
|
var import_node_os3 = require("os");
|
|
29
29
|
var import_node_path6 = require("path");
|
|
@@ -148,7 +148,7 @@ var StudioApiTransport = class {
|
|
|
148
148
|
}
|
|
149
149
|
if (!response.ok) {
|
|
150
150
|
await response.body?.cancel();
|
|
151
|
-
const message = response.status === 401 ? "Invalid, expired, or revoked Studio read key." : response.status === 403 ? "The API key lacks studio:read or the operation's required permission (eval:run for execution)." : response.status === 404 ? "Entity not found in this connection's project. Check the URL and selected connection." : `Studio API returned HTTP ${response.status}.`;
|
|
151
|
+
const message = response.status === 401 ? "Invalid, expired, or revoked Studio read key." : response.status === 403 ? "The API key lacks studio:read or the operation's required permission (diagnostics:read for diagnostics; eval:run for execution)." : response.status === 404 ? "Entity not found in this connection's project. Check the URL and selected connection." : `Studio API returned HTTP ${response.status}.`;
|
|
152
152
|
throw new StudioReadError(
|
|
153
153
|
"api_error",
|
|
154
154
|
message,
|
|
@@ -208,7 +208,7 @@ var StudioApiTransport = class {
|
|
|
208
208
|
};
|
|
209
209
|
var StudioReadClient = class extends StudioApiTransport {
|
|
210
210
|
async get(path, schema, query = {}) {
|
|
211
|
-
if (!/^\/v1\/studio\/(?:context|catalogs|workflows|(?:runs|sessions|interrupts)(?:\/[^/?#]+)
|
|
211
|
+
if (!/^\/v1\/studio\/(?:context|catalogs|workflows|(?:runs|sessions|interrupts)(?:\/[^/?#]+)?|diagnostics\/[a-f0-9-]{36})$/.test(
|
|
212
212
|
path
|
|
213
213
|
) || /(?:^|\/)(?:\.|\.\.|%2e(?:%2e)?)(?:\/|$)/i.test(path)) {
|
|
214
214
|
throw new StudioReadError(
|
|
@@ -236,6 +236,7 @@ x-api-env: &api-env
|
|
|
236
236
|
x-bootstrap-keys: &bootstrap-keys
|
|
237
237
|
KORTYX_TELEMETRY_API_KEY: \${KORTYX_TELEMETRY_API_KEY}
|
|
238
238
|
KORTYX_STUDIO_API_KEY: \${KORTYX_STUDIO_API_KEY}
|
|
239
|
+
KORTYX_STUDIO_ENABLE_DIAGNOSTICS: \${KORTYX_STUDIO_ENABLE_DIAGNOSTICS:-0}
|
|
239
240
|
KORTYX_STUDIO_ENABLE_EVALS: \${KORTYX_STUDIO_ENABLE_EVALS:-0}
|
|
240
241
|
KORTYX_STUDIO_ENABLE_REVIEWS: \${KORTYX_STUDIO_ENABLE_REVIEWS:-0}
|
|
241
242
|
|
|
@@ -2572,6 +2573,8 @@ var resetStudio = async (home, confirm, runtime) => {
|
|
|
2572
2573
|
};
|
|
2573
2574
|
|
|
2574
2575
|
// src/studio/read-command.ts
|
|
2576
|
+
var import_node_crypto2 = require("crypto");
|
|
2577
|
+
var import_promises5 = require("fs/promises");
|
|
2575
2578
|
var import_telemetry_contracts5 = require("@kortyx/telemetry-contracts");
|
|
2576
2579
|
var import_commander4 = require("commander");
|
|
2577
2580
|
|
|
@@ -2935,6 +2938,80 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
2935
2938
|
)
|
|
2936
2939
|
};
|
|
2937
2940
|
};
|
|
2941
|
+
const diagnostics = studio.command("diagnostics").description("Inspect or download a retained private error diagnostic.");
|
|
2942
|
+
for (const action of ["get", "download"]) {
|
|
2943
|
+
common(
|
|
2944
|
+
diagnostics.command(action).argument("<diagnostic-id>").option(
|
|
2945
|
+
"--environment <name>",
|
|
2946
|
+
"Diagnostic environment (or connection default)."
|
|
2947
|
+
).option(
|
|
2948
|
+
"--output <path>",
|
|
2949
|
+
"Write a diagnostic JSON file without overwriting an existing file."
|
|
2950
|
+
)
|
|
2951
|
+
).action(async (id, options) => {
|
|
2952
|
+
if (!/^[a-f0-9-]{36}$/i.test(id))
|
|
2953
|
+
throw new StudioReadError(
|
|
2954
|
+
"invalid_diagnostic_id",
|
|
2955
|
+
"Expected a diagnostic UUID."
|
|
2956
|
+
);
|
|
2957
|
+
const { connection, client } = await clientFor(options);
|
|
2958
|
+
const environment = options.environment ?? connection.environment;
|
|
2959
|
+
if (!environment)
|
|
2960
|
+
throw new StudioReadError(
|
|
2961
|
+
"environment_required",
|
|
2962
|
+
"Provide --environment for diagnostic retrieval."
|
|
2963
|
+
);
|
|
2964
|
+
const value = await client.get(
|
|
2965
|
+
`/v1/studio/diagnostics/${id}`,
|
|
2966
|
+
import_telemetry_contracts5.DiagnosticResponseSchema,
|
|
2967
|
+
{
|
|
2968
|
+
env: environment,
|
|
2969
|
+
...action === "download" ? { download: "1" } : {}
|
|
2970
|
+
}
|
|
2971
|
+
);
|
|
2972
|
+
if (action === "get") {
|
|
2973
|
+
const { content, ...summary2 } = value;
|
|
2974
|
+
print(
|
|
2975
|
+
{
|
|
2976
|
+
...summary2,
|
|
2977
|
+
capture: {
|
|
2978
|
+
status: content?.capture.status ?? value.manifest.captureStatus,
|
|
2979
|
+
omissions: content?.capture.omissions.length ?? 0,
|
|
2980
|
+
redactions: content?.capture.redactions.length ?? 0
|
|
2981
|
+
},
|
|
2982
|
+
...options.includeContent ? { content } : {},
|
|
2983
|
+
note: "Private diagnostic access requires diagnostics:read. Use download for the complete redacted artifact."
|
|
2984
|
+
},
|
|
2985
|
+
options
|
|
2986
|
+
);
|
|
2987
|
+
return;
|
|
2988
|
+
}
|
|
2989
|
+
if (value.state !== "available" || !value.content)
|
|
2990
|
+
throw new StudioReadError(
|
|
2991
|
+
"diagnostic_incomplete",
|
|
2992
|
+
`Diagnostic is ${value.state}; received ${value.receivedParts} of ${value.manifest.partCount} parts.`
|
|
2993
|
+
);
|
|
2994
|
+
const bytes = JSON.stringify(value.content);
|
|
2995
|
+
if ((0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex") !== value.contentChecksum || Buffer.byteLength(bytes) !== value.contentByteLength)
|
|
2996
|
+
throw new StudioReadError(
|
|
2997
|
+
"diagnostic_integrity_failed",
|
|
2998
|
+
"Diagnostic download failed integrity verification."
|
|
2999
|
+
);
|
|
3000
|
+
if (options.output) {
|
|
3001
|
+
await (0, import_promises5.writeFile)(options.output, bytes, { flag: "wx", mode: 384 });
|
|
3002
|
+
print(
|
|
3003
|
+
{
|
|
3004
|
+
diagnosticId: id,
|
|
3005
|
+
state: value.state,
|
|
3006
|
+
file: options.output,
|
|
3007
|
+
bytes: value.contentByteLength,
|
|
3008
|
+
checksum: value.contentChecksum
|
|
3009
|
+
},
|
|
3010
|
+
options
|
|
3011
|
+
);
|
|
3012
|
+
} else log(bytes);
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
2938
3015
|
const inspect = async (input, options, entity) => {
|
|
2939
3016
|
const target = parseStudioTarget(input, entity);
|
|
2940
3017
|
const { connection, client } = await clientFor(options, target.url);
|
|
@@ -3323,7 +3400,7 @@ var registerStudioReadCommands = (studio, log, request = fetch) => {
|
|
|
3323
3400
|
};
|
|
3324
3401
|
|
|
3325
3402
|
// src/studio/runtime.ts
|
|
3326
|
-
var
|
|
3403
|
+
var import_node_crypto3 = require("crypto");
|
|
3327
3404
|
var import_node_net = require("net");
|
|
3328
3405
|
var stringOutput = (value) => typeof value === "string" ? value : "";
|
|
3329
3406
|
var isCommandNotFound = (error) => error instanceof Error && ("code" in error && error.code === "ENOENT" || error.message.includes("ENOENT"));
|
|
@@ -3362,7 +3439,7 @@ var defaultStudioRuntime = {
|
|
|
3362
3439
|
run,
|
|
3363
3440
|
portAvailable,
|
|
3364
3441
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
3365
|
-
random: (bytes) => (0,
|
|
3442
|
+
random: (bytes) => (0, import_node_crypto3.randomBytes)(bytes).toString("base64url"),
|
|
3366
3443
|
request: fetch,
|
|
3367
3444
|
log: (message = "") => console.log(message),
|
|
3368
3445
|
error: (message = "") => console.error(message)
|
|
@@ -3898,7 +3975,7 @@ var readPackageName = async (cwd) => {
|
|
|
3898
3975
|
let current = cwd;
|
|
3899
3976
|
for (; ; ) {
|
|
3900
3977
|
try {
|
|
3901
|
-
const raw = await (0,
|
|
3978
|
+
const raw = await (0, import_promises6.readFile)((0, import_node_path6.join)(current, "package.json"), "utf8");
|
|
3902
3979
|
const parsed = JSON.parse(raw);
|
|
3903
3980
|
if (isRecord(parsed) && typeof parsed.name === "string") {
|
|
3904
3981
|
return parsed.name;
|
|
@@ -3915,7 +3992,7 @@ var loadEnvFiles = async (cwd) => {
|
|
|
3915
3992
|
const path = (0, import_node_path6.join)(cwd, filename);
|
|
3916
3993
|
let raw;
|
|
3917
3994
|
try {
|
|
3918
|
-
raw = await (0,
|
|
3995
|
+
raw = await (0, import_promises6.readFile)(path, "utf8");
|
|
3919
3996
|
} catch {
|
|
3920
3997
|
continue;
|
|
3921
3998
|
}
|
|
@@ -3955,12 +4032,12 @@ var resolveOptions = async (options) => {
|
|
|
3955
4032
|
};
|
|
3956
4033
|
};
|
|
3957
4034
|
var createFrameworkMarkerStubs = async () => {
|
|
3958
|
-
const root = await (0,
|
|
4035
|
+
const root = await (0, import_promises6.mkdtemp)((0, import_node_path6.join)((0, import_node_os3.tmpdir)(), "kortyx-cli-stubs-"));
|
|
3959
4036
|
for (const moduleName of ["server-only", "client-only"]) {
|
|
3960
4037
|
const directory = (0, import_node_path6.join)(root, moduleName);
|
|
3961
|
-
await (0,
|
|
3962
|
-
await (0,
|
|
3963
|
-
await (0,
|
|
4038
|
+
await (0, import_promises6.mkdir)(directory, { recursive: true });
|
|
4039
|
+
await (0, import_promises6.writeFile)((0, import_node_path6.join)(directory, "index.js"), "", "utf8");
|
|
4040
|
+
await (0, import_promises6.writeFile)(
|
|
3964
4041
|
(0, import_node_path6.join)(directory, "package.json"),
|
|
3965
4042
|
JSON.stringify({ name: moduleName, version: "0.0.0", main: "index.js" }),
|
|
3966
4043
|
"utf8"
|
|
@@ -3975,7 +4052,7 @@ var createFrameworkMarkerStubs = async () => {
|
|
|
3975
4052
|
if (previousNodePath === void 0) delete process.env.NODE_PATH;
|
|
3976
4053
|
else process.env.NODE_PATH = previousNodePath;
|
|
3977
4054
|
moduleWithPrivateInit._initPaths?.();
|
|
3978
|
-
await (0,
|
|
4055
|
+
await (0, import_promises6.rm)(root, { recursive: true, force: true });
|
|
3979
4056
|
}
|
|
3980
4057
|
};
|
|
3981
4058
|
};
|
|
@@ -4017,7 +4094,7 @@ var findNearestFile = async (startDirectory, filename) => {
|
|
|
4017
4094
|
for (; ; ) {
|
|
4018
4095
|
const candidate = (0, import_node_path6.join)(current, filename);
|
|
4019
4096
|
try {
|
|
4020
|
-
await (0,
|
|
4097
|
+
await (0, import_promises6.access)(candidate);
|
|
4021
4098
|
return candidate;
|
|
4022
4099
|
} catch {
|
|
4023
4100
|
const parent = (0, import_node_path6.dirname)(current);
|
|
@@ -4029,7 +4106,7 @@ var findNearestFile = async (startDirectory, filename) => {
|
|
|
4029
4106
|
var registerTsconfigPaths = async (tsconfigPath) => {
|
|
4030
4107
|
const parsed = import_typescript2.default.parseConfigFileTextToJson(
|
|
4031
4108
|
tsconfigPath,
|
|
4032
|
-
await (0,
|
|
4109
|
+
await (0, import_promises6.readFile)(tsconfigPath, "utf8")
|
|
4033
4110
|
);
|
|
4034
4111
|
if (parsed.error)
|
|
4035
4112
|
throw new Error(`Invalid TypeScript configuration: ${tsconfigPath}`);
|