@runtypelabs/cli 2.6.2 → 2.7.0
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/dist/index.js +255 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15401,8 +15401,8 @@ var require_provider_routing = __commonJS({
|
|
|
15401
15401
|
});
|
|
15402
15402
|
|
|
15403
15403
|
// src/index.ts
|
|
15404
|
-
import { Command as
|
|
15405
|
-
import
|
|
15404
|
+
import { Command as Command22 } from "commander";
|
|
15405
|
+
import chalk29 from "chalk";
|
|
15406
15406
|
import { config as loadEnv } from "dotenv";
|
|
15407
15407
|
|
|
15408
15408
|
// src/commands/auth.ts
|
|
@@ -32858,11 +32858,254 @@ flowVersionsCommand.command("publish <flowId>").description("Publish a version")
|
|
|
32858
32858
|
await waitUntilExit();
|
|
32859
32859
|
});
|
|
32860
32860
|
|
|
32861
|
+
// src/commands/tail.ts
|
|
32862
|
+
import { Command as Command21 } from "commander";
|
|
32863
|
+
import chalk27 from "chalk";
|
|
32864
|
+
function abbreviateId(id) {
|
|
32865
|
+
const underscoreIdx = id.lastIndexOf("_");
|
|
32866
|
+
if (underscoreIdx === -1) {
|
|
32867
|
+
return id.length > 8 ? `${id.slice(0, 8)}...` : id;
|
|
32868
|
+
}
|
|
32869
|
+
const prefix = id.slice(0, underscoreIdx);
|
|
32870
|
+
const suffix = id.slice(underscoreIdx + 1);
|
|
32871
|
+
return `${prefix}_${suffix.slice(0, 4)}...`;
|
|
32872
|
+
}
|
|
32873
|
+
function formatTime(ts) {
|
|
32874
|
+
const d = new Date(ts);
|
|
32875
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
32876
|
+
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
32877
|
+
const ss = String(d.getSeconds()).padStart(2, "0");
|
|
32878
|
+
const ms = String(d.getMilliseconds()).padStart(3, "0");
|
|
32879
|
+
return `${hh}:${mm}:${ss}.${ms}`;
|
|
32880
|
+
}
|
|
32881
|
+
var LEVEL_COLORS = {
|
|
32882
|
+
debug: chalk27.gray,
|
|
32883
|
+
info: chalk27.blue,
|
|
32884
|
+
warn: chalk27.yellow,
|
|
32885
|
+
error: chalk27.red
|
|
32886
|
+
};
|
|
32887
|
+
function levelBadge(level, useColor) {
|
|
32888
|
+
const tag = level.toUpperCase().padEnd(5);
|
|
32889
|
+
if (!useColor) return `[${tag}]`;
|
|
32890
|
+
const colorFn = LEVEL_COLORS[level] || chalk27.white;
|
|
32891
|
+
return colorFn(`[${tag}]`);
|
|
32892
|
+
}
|
|
32893
|
+
function categoryBadge(category, useColor) {
|
|
32894
|
+
if (!useColor) return `[${category}]`;
|
|
32895
|
+
return chalk27.magenta(`[${category}]`);
|
|
32896
|
+
}
|
|
32897
|
+
function formatTailData(data) {
|
|
32898
|
+
return Object.entries(data).map(([k, v]) => `${k}=${typeof v === "string" ? v : JSON.stringify(v)}`).join(" ");
|
|
32899
|
+
}
|
|
32900
|
+
function formatContextIds(event, useColor) {
|
|
32901
|
+
const ids = [];
|
|
32902
|
+
if (event.executionId) ids.push(`exec=${abbreviateId(event.executionId)}`);
|
|
32903
|
+
if (event.flowId) ids.push(`flow=${abbreviateId(event.flowId)}`);
|
|
32904
|
+
if (event.agentId) ids.push(`agent=${abbreviateId(event.agentId)}`);
|
|
32905
|
+
if (event.surfaceId) ids.push(`surface=${abbreviateId(event.surfaceId)}`);
|
|
32906
|
+
if (event.requestId) ids.push(`req=${abbreviateId(event.requestId)}`);
|
|
32907
|
+
if (event.conversationId) ids.push(`conv=${abbreviateId(event.conversationId)}`);
|
|
32908
|
+
if (ids.length === 0) return "";
|
|
32909
|
+
const text = ids.join(" ");
|
|
32910
|
+
return useColor ? chalk27.gray(` ${text}`) : ` ${text}`;
|
|
32911
|
+
}
|
|
32912
|
+
function formatEvent(event, useColor) {
|
|
32913
|
+
const time = useColor ? chalk27.gray(formatTime(event.timestamp)) : formatTime(event.timestamp);
|
|
32914
|
+
const level = levelBadge(event.level, useColor);
|
|
32915
|
+
const cat = categoryBadge(event.category, useColor);
|
|
32916
|
+
const ctx = formatContextIds(event, useColor);
|
|
32917
|
+
const data = event.tailData && Object.keys(event.tailData).length > 0 ? useColor ? chalk27.gray(` | ${formatTailData(event.tailData)}`) : ` | ${formatTailData(event.tailData)}` : "";
|
|
32918
|
+
return `${time} ${level} ${cat} ${event.message}${data}${ctx}`;
|
|
32919
|
+
}
|
|
32920
|
+
async function consumeSSEStream(reader, options, signal) {
|
|
32921
|
+
const decoder = new TextDecoder();
|
|
32922
|
+
let buffer = "";
|
|
32923
|
+
const useColor = options.color;
|
|
32924
|
+
while (!signal.aborted) {
|
|
32925
|
+
const { done, value } = await reader.read();
|
|
32926
|
+
if (done) return "eof";
|
|
32927
|
+
buffer += decoder.decode(value, { stream: true });
|
|
32928
|
+
let boundary;
|
|
32929
|
+
while ((boundary = buffer.indexOf("\n\n")) !== -1) {
|
|
32930
|
+
const chunk = buffer.slice(0, boundary);
|
|
32931
|
+
buffer = buffer.slice(boundary + 2);
|
|
32932
|
+
const dataLines = [];
|
|
32933
|
+
for (const line of chunk.split("\n")) {
|
|
32934
|
+
if (line.startsWith("data: ")) {
|
|
32935
|
+
dataLines.push(line.slice(6));
|
|
32936
|
+
}
|
|
32937
|
+
}
|
|
32938
|
+
if (dataLines.length === 0) continue;
|
|
32939
|
+
const raw = dataLines.join("\n");
|
|
32940
|
+
let msg;
|
|
32941
|
+
try {
|
|
32942
|
+
msg = JSON.parse(raw);
|
|
32943
|
+
} catch {
|
|
32944
|
+
continue;
|
|
32945
|
+
}
|
|
32946
|
+
switch (msg.type) {
|
|
32947
|
+
case "tail_event":
|
|
32948
|
+
if (options.json) {
|
|
32949
|
+
process.stdout.write(JSON.stringify(msg.event) + "\n");
|
|
32950
|
+
} else {
|
|
32951
|
+
process.stdout.write(formatEvent(msg.event, useColor) + "\n");
|
|
32952
|
+
}
|
|
32953
|
+
break;
|
|
32954
|
+
case "tail_gap":
|
|
32955
|
+
process.stderr.write(
|
|
32956
|
+
(useColor ? chalk27.yellow(`[warn] Dropped ${msg.droppedCount} event(s) between ${msg.fromTimestamp} and ${msg.toTimestamp}`) : `[warn] Dropped ${msg.droppedCount} event(s) between ${msg.fromTimestamp} and ${msg.toTimestamp}`) + "\n"
|
|
32957
|
+
);
|
|
32958
|
+
break;
|
|
32959
|
+
case "tail_connected":
|
|
32960
|
+
process.stderr.write(
|
|
32961
|
+
(useColor ? chalk27.green(`Connected to tail session ${msg.sessionId}`) : `Connected to tail session ${msg.sessionId}`) + "\n"
|
|
32962
|
+
);
|
|
32963
|
+
break;
|
|
32964
|
+
case "tail_error":
|
|
32965
|
+
process.stderr.write(
|
|
32966
|
+
(useColor ? chalk27.red(`[error] ${msg.error}`) : `[error] ${msg.error}`) + "\n"
|
|
32967
|
+
);
|
|
32968
|
+
break;
|
|
32969
|
+
}
|
|
32970
|
+
}
|
|
32971
|
+
}
|
|
32972
|
+
return "aborted";
|
|
32973
|
+
}
|
|
32974
|
+
async function createSession(apiUrl, apiKey, filters) {
|
|
32975
|
+
const filter = {};
|
|
32976
|
+
const arrayFields = {
|
|
32977
|
+
flowId: "flowIds",
|
|
32978
|
+
agentId: "agentIds",
|
|
32979
|
+
surfaceId: "surfaceIds",
|
|
32980
|
+
executionId: "executionIds",
|
|
32981
|
+
level: "levels",
|
|
32982
|
+
category: "categories"
|
|
32983
|
+
};
|
|
32984
|
+
for (const [k, v] of Object.entries(filters)) {
|
|
32985
|
+
if (v !== void 0 && arrayFields[k]) {
|
|
32986
|
+
filter[arrayFields[k]] = [v];
|
|
32987
|
+
}
|
|
32988
|
+
}
|
|
32989
|
+
const body = Object.keys(filter).length > 0 ? { filter } : {};
|
|
32990
|
+
const res = await fetch(`${apiUrl}/v1/tail/sessions`, {
|
|
32991
|
+
method: "POST",
|
|
32992
|
+
headers: {
|
|
32993
|
+
Authorization: `Bearer ${apiKey}`,
|
|
32994
|
+
"Content-Type": "application/json",
|
|
32995
|
+
"User-Agent": `Runtype-CLI/${getCliVersion()}`
|
|
32996
|
+
},
|
|
32997
|
+
body: JSON.stringify(body)
|
|
32998
|
+
});
|
|
32999
|
+
if (!res.ok) {
|
|
33000
|
+
const text = await res.text().catch(() => "");
|
|
33001
|
+
throw new Error(`Failed to create tail session: ${res.status} ${res.statusText}${text ? ` \u2014 ${text}` : ""}`);
|
|
33002
|
+
}
|
|
33003
|
+
return await res.json();
|
|
33004
|
+
}
|
|
33005
|
+
async function connectAndStream(sseUrl, apiKey, options, signal) {
|
|
33006
|
+
const res = await fetch(sseUrl, {
|
|
33007
|
+
headers: {
|
|
33008
|
+
Authorization: `Bearer ${apiKey}`,
|
|
33009
|
+
Accept: "text/event-stream",
|
|
33010
|
+
"User-Agent": `Runtype-CLI/${getCliVersion()}`
|
|
33011
|
+
},
|
|
33012
|
+
signal
|
|
33013
|
+
});
|
|
33014
|
+
if (!res.ok) {
|
|
33015
|
+
const text = await res.text().catch(() => "");
|
|
33016
|
+
throw new Error(`SSE connection failed: ${res.status} ${res.statusText}${text ? ` \u2014 ${text}` : ""}`);
|
|
33017
|
+
}
|
|
33018
|
+
if (!res.body) {
|
|
33019
|
+
throw new Error("SSE response has no body");
|
|
33020
|
+
}
|
|
33021
|
+
const reader = res.body.getReader();
|
|
33022
|
+
try {
|
|
33023
|
+
return await consumeSSEStream(reader, options, signal);
|
|
33024
|
+
} finally {
|
|
33025
|
+
reader.releaseLock();
|
|
33026
|
+
}
|
|
33027
|
+
}
|
|
33028
|
+
var BASE_DELAY_MS = 1e3;
|
|
33029
|
+
var MAX_DELAY_MS = 3e4;
|
|
33030
|
+
var MAX_ATTEMPTS = 10;
|
|
33031
|
+
async function runTail(options) {
|
|
33032
|
+
const apiKey = await ensureAuth();
|
|
33033
|
+
if (!apiKey) return;
|
|
33034
|
+
const apiUrl = getApiUrl();
|
|
33035
|
+
const filters = {
|
|
33036
|
+
flowId: options.flow,
|
|
33037
|
+
agentId: options.agent,
|
|
33038
|
+
surfaceId: options.surface,
|
|
33039
|
+
executionId: options.execution,
|
|
33040
|
+
level: options.level,
|
|
33041
|
+
category: options.category
|
|
33042
|
+
};
|
|
33043
|
+
const useColor = options.color;
|
|
33044
|
+
const activeFilters = Object.entries(filters).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${v}`);
|
|
33045
|
+
process.stderr.write(
|
|
33046
|
+
(useColor ? chalk27.gray(`Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) : `Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) + "\n"
|
|
33047
|
+
);
|
|
33048
|
+
const controller = new AbortController();
|
|
33049
|
+
let shuttingDown = false;
|
|
33050
|
+
const shutdown = () => {
|
|
33051
|
+
if (shuttingDown) return;
|
|
33052
|
+
shuttingDown = true;
|
|
33053
|
+
process.stderr.write(
|
|
33054
|
+
(useColor ? chalk27.gray("\nDisconnecting...") : "\nDisconnecting...") + "\n"
|
|
33055
|
+
);
|
|
33056
|
+
controller.abort();
|
|
33057
|
+
};
|
|
33058
|
+
process.on("SIGINT", shutdown);
|
|
33059
|
+
process.on("SIGTERM", shutdown);
|
|
33060
|
+
let attempt = 0;
|
|
33061
|
+
while (!shuttingDown && attempt < MAX_ATTEMPTS) {
|
|
33062
|
+
try {
|
|
33063
|
+
const session = await createSession(apiUrl, apiKey, filters);
|
|
33064
|
+
attempt = 0;
|
|
33065
|
+
const result = await connectAndStream(session.sseUrl, apiKey, options, controller.signal);
|
|
33066
|
+
if (result === "aborted" || shuttingDown) break;
|
|
33067
|
+
process.stderr.write(
|
|
33068
|
+
(useColor ? chalk27.yellow("Stream ended, reconnecting...") : "Stream ended, reconnecting...") + "\n"
|
|
33069
|
+
);
|
|
33070
|
+
} catch (err) {
|
|
33071
|
+
if (shuttingDown || controller.signal.aborted) break;
|
|
33072
|
+
attempt++;
|
|
33073
|
+
const delay = Math.min(BASE_DELAY_MS * Math.pow(2, attempt - 1), MAX_DELAY_MS);
|
|
33074
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
33075
|
+
process.stderr.write(
|
|
33076
|
+
(useColor ? chalk27.red(`Connection error: ${message}`) : `Connection error: ${message}`) + "\n"
|
|
33077
|
+
);
|
|
33078
|
+
if (attempt >= MAX_ATTEMPTS) {
|
|
33079
|
+
process.stderr.write(
|
|
33080
|
+
(useColor ? chalk27.red(`Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) : `Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) + "\n"
|
|
33081
|
+
);
|
|
33082
|
+
process.exit(1);
|
|
33083
|
+
}
|
|
33084
|
+
process.stderr.write(
|
|
33085
|
+
(useColor ? chalk27.gray(`Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) : `Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) + "\n"
|
|
33086
|
+
);
|
|
33087
|
+
await new Promise((resolve8) => {
|
|
33088
|
+
const timer = setTimeout(resolve8, delay);
|
|
33089
|
+
const onAbort = () => {
|
|
33090
|
+
clearTimeout(timer);
|
|
33091
|
+
resolve8();
|
|
33092
|
+
};
|
|
33093
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
33094
|
+
});
|
|
33095
|
+
}
|
|
33096
|
+
}
|
|
33097
|
+
process.removeListener("SIGINT", shutdown);
|
|
33098
|
+
process.removeListener("SIGTERM", shutdown);
|
|
33099
|
+
}
|
|
33100
|
+
var tailCommand = new Command21("tail").description("Stream live execution logs from the Runtype API").option("--flow <id>", "Filter by flow ID").option("--agent <id>", "Filter by agent ID").option("--surface <id>", "Filter by surface ID").option("--execution <id>", "Filter by execution ID").option("--level <level>", "Filter by level (debug/info/warn/error)").option("--category <category>", "Filter by category (execution/agent/tool/model/system/error)").option("--json", "Output raw JSON (one object per line)").option("--no-color", "Disable color output").action(async (options) => {
|
|
33101
|
+
await runTail(options);
|
|
33102
|
+
});
|
|
33103
|
+
|
|
32861
33104
|
// src/index.ts
|
|
32862
33105
|
init_credential_store();
|
|
32863
33106
|
|
|
32864
33107
|
// src/lib/update-check.ts
|
|
32865
|
-
import
|
|
33108
|
+
import chalk28 from "chalk";
|
|
32866
33109
|
import Conf3 from "conf";
|
|
32867
33110
|
var UPDATE_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1e3;
|
|
32868
33111
|
var UPDATE_NOTIFY_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -32956,7 +33199,7 @@ function notifyFromCachedCliUpdate(args, options = {}) {
|
|
|
32956
33199
|
console.error(message);
|
|
32957
33200
|
});
|
|
32958
33201
|
notify(
|
|
32959
|
-
`${
|
|
33202
|
+
`${chalk28.yellow("Update available:")} ${chalk28.red(currentVersion)} ${chalk28.gray("->")} ${chalk28.green(latestVersion)} ${chalk28.gray(`(${getUpgradeCommand()})`)}`
|
|
32960
33203
|
);
|
|
32961
33204
|
store.set("lastNotifiedAt", now.toISOString());
|
|
32962
33205
|
store.set("lastNotifiedVersion", latestVersion);
|
|
@@ -32998,7 +33241,7 @@ function maybeNotifyAboutCliUpdate(args, options = {}) {
|
|
|
32998
33241
|
// src/index.ts
|
|
32999
33242
|
loadEnv();
|
|
33000
33243
|
setCliTitle();
|
|
33001
|
-
var program = new
|
|
33244
|
+
var program = new Command22();
|
|
33002
33245
|
program.name("runtype").description("CLI for Runtype AI Platform").version(getCliVersion()).option("-v, --verbose", "Enable verbose output").option("--api-url <url>", "Override API URL").option("--json", "Output in JSON format");
|
|
33003
33246
|
program.addCommand(initCommand);
|
|
33004
33247
|
program.addCommand(loginCommand);
|
|
@@ -33021,6 +33264,7 @@ program.addCommand(analyticsCommand);
|
|
|
33021
33264
|
program.addCommand(billingCommand);
|
|
33022
33265
|
program.addCommand(flowVersionsCommand);
|
|
33023
33266
|
program.addCommand(createMarathonCommand());
|
|
33267
|
+
program.addCommand(tailCommand);
|
|
33024
33268
|
program.exitOverride();
|
|
33025
33269
|
try {
|
|
33026
33270
|
const userArgs = process.argv.slice(2);
|
|
@@ -33034,15 +33278,15 @@ try {
|
|
|
33034
33278
|
} catch (error) {
|
|
33035
33279
|
const commanderError = error;
|
|
33036
33280
|
if (commanderError.code === "commander.missingArgument") {
|
|
33037
|
-
console.error(
|
|
33281
|
+
console.error(chalk29.red(`Error: ${commanderError.message}`));
|
|
33038
33282
|
process.exit(1);
|
|
33039
33283
|
} else if (commanderError.code === "commander.unknownOption") {
|
|
33040
|
-
console.error(
|
|
33284
|
+
console.error(chalk29.red(`Error: ${commanderError.message}`));
|
|
33041
33285
|
process.exit(1);
|
|
33042
33286
|
} else if (commanderError.code === "commander.help" || commanderError.code === "commander.version") {
|
|
33043
33287
|
process.exit(0);
|
|
33044
33288
|
} else {
|
|
33045
|
-
console.error(
|
|
33289
|
+
console.error(chalk29.red("An unexpected error occurred:"));
|
|
33046
33290
|
console.error(error);
|
|
33047
33291
|
process.exit(1);
|
|
33048
33292
|
}
|
|
@@ -33051,12 +33295,12 @@ async function handleNoCommand() {
|
|
|
33051
33295
|
const store = new CredentialStore();
|
|
33052
33296
|
const hasCredentials = await store.hasCredentials();
|
|
33053
33297
|
if (!hasCredentials) {
|
|
33054
|
-
console.log(
|
|
33298
|
+
console.log(chalk29.cyan("\nWelcome to Runtype CLI!\n"));
|
|
33055
33299
|
console.log("It looks like this is your first time. Run the setup wizard:");
|
|
33056
|
-
console.log(` ${
|
|
33300
|
+
console.log(` ${chalk29.green("runtype init")}
|
|
33057
33301
|
`);
|
|
33058
33302
|
console.log("Or see all available commands:");
|
|
33059
|
-
console.log(` ${
|
|
33303
|
+
console.log(` ${chalk29.green("runtype --help")}
|
|
33060
33304
|
`);
|
|
33061
33305
|
} else {
|
|
33062
33306
|
try {
|