@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 CHANGED
@@ -15401,8 +15401,8 @@ var require_provider_routing = __commonJS({
15401
15401
  });
15402
15402
 
15403
15403
  // src/index.ts
15404
- import { Command as Command21 } from "commander";
15405
- import chalk28 from "chalk";
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 chalk27 from "chalk";
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
- `${chalk27.yellow("Update available:")} ${chalk27.red(currentVersion)} ${chalk27.gray("->")} ${chalk27.green(latestVersion)} ${chalk27.gray(`(${getUpgradeCommand()})`)}`
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 Command21();
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(chalk28.red(`Error: ${commanderError.message}`));
33281
+ console.error(chalk29.red(`Error: ${commanderError.message}`));
33038
33282
  process.exit(1);
33039
33283
  } else if (commanderError.code === "commander.unknownOption") {
33040
- console.error(chalk28.red(`Error: ${commanderError.message}`));
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(chalk28.red("An unexpected error occurred:"));
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(chalk28.cyan("\nWelcome to Runtype CLI!\n"));
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(` ${chalk28.green("runtype init")}
33300
+ console.log(` ${chalk29.green("runtype init")}
33057
33301
  `);
33058
33302
  console.log("Or see all available commands:");
33059
- console.log(` ${chalk28.green("runtype --help")}
33303
+ console.log(` ${chalk29.green("runtype --help")}
33060
33304
  `);
33061
33305
  } else {
33062
33306
  try {