@runtypelabs/cli 2.13.0 → 2.15.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.
Files changed (2) hide show
  1. package/dist/index.js +1045 -123
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -131,8 +131,8 @@ var init_credential_store = __esm({
131
131
  });
132
132
 
133
133
  // src/index.ts
134
- import { Command as Command24 } from "commander";
135
- import chalk31 from "chalk";
134
+ import { Command as Command25 } from "commander";
135
+ import chalk32 from "chalk";
136
136
 
137
137
  // src/lib/load-env.ts
138
138
  import { readFileSync } from "fs";
@@ -35408,15 +35408,17 @@ var FlowInputSchema = external_exports.object({
35408
35408
  id: external_exports.string().min(1).optional(),
35409
35409
  name: external_exports.string().min(1).optional(),
35410
35410
  description: external_exports.string().optional(),
35411
- steps: external_exports.array(external_exports.any()).optional()
35411
+ steps: external_exports.array(external_exports.any()).optional(),
35412
+ contentHash: external_exports.string().length(64).optional()
35412
35413
  }).refine(
35413
35414
  (data) => {
35414
35415
  const hasFlowId = !!data.id;
35415
35416
  const hasSteps = !!(data.name && data.steps && data.steps.length > 0);
35416
- return hasFlowId || hasSteps;
35417
+ const hasPersistedFlow = !!(data.name && data.contentHash);
35418
+ return hasFlowId || hasSteps || hasPersistedFlow;
35417
35419
  },
35418
35420
  {
35419
- message: "Either 'id' or flow definition with 'name' and 'steps' must be provided."
35421
+ message: "Either 'id', flow definition with 'name' and 'steps', or persisted flow with 'name' and 'contentHash' must be provided."
35420
35422
  }
35421
35423
  );
35422
35424
  var AgentLoopConfigSchema = external_exports.object({
@@ -52940,9 +52942,283 @@ flowVersionsCommand.command("publish <flowId>").description("Publish a version")
52940
52942
  await waitUntilExit();
52941
52943
  });
52942
52944
 
52943
- // src/commands/tail.ts
52945
+ // src/commands/agent-versions.ts
52944
52946
  import { Command as Command21 } from "commander";
52945
52947
  import chalk27 from "chalk";
52948
+ import React19 from "react";
52949
+ import { render as render19 } from "ink";
52950
+ import { useState as useState33, useEffect as useEffect30 } from "react";
52951
+ import { Text as Text35 } from "ink";
52952
+ var agentVersionsCommand = new Command21("agent-versions").description(
52953
+ "Manage agent versions"
52954
+ );
52955
+ agentVersionsCommand.command("list <agentId>").description("List all versions for an agent").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (agentId, options) => {
52956
+ const apiKey = await ensureAuth();
52957
+ if (!apiKey) return;
52958
+ const client = new ApiClient(apiKey);
52959
+ if (!isTTY(options) || options.json) {
52960
+ try {
52961
+ const data = await client.get(`/agent-versions/${agentId}`);
52962
+ if (options.json) {
52963
+ printJson(data);
52964
+ } else {
52965
+ const versions = data.versions ?? [];
52966
+ if (versions.length === 0) {
52967
+ console.log(chalk27.gray("No versions found"));
52968
+ return;
52969
+ }
52970
+ console.log(chalk27.cyan(`Versions for agent ${agentId}:`));
52971
+ for (const v of versions) {
52972
+ const isPublished = v.id === data.publishedVersionId;
52973
+ const liveTag = isPublished ? chalk27.green(" [live]") : "";
52974
+ const versionLabel = v.label || (v.versionNumber !== void 0 ? `v${v.versionNumber}` : v.id);
52975
+ const date5 = v.createdAt ? chalk27.gray(` ${v.createdAt}`) : "";
52976
+ console.log(` ${chalk27.green(v.id)} ${versionLabel}${liveTag}${date5}`);
52977
+ }
52978
+ }
52979
+ } catch (error51) {
52980
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
52981
+ console.error(chalk27.red("Failed to fetch versions"));
52982
+ console.error(chalk27.red(message));
52983
+ process.exit(1);
52984
+ }
52985
+ return;
52986
+ }
52987
+ const App = () => {
52988
+ const [loading, setLoading] = useState33(true);
52989
+ const [items, setItems] = useState33(null);
52990
+ const [publishedId, setPublishedId] = useState33(null);
52991
+ const [error51, setError] = useState33(null);
52992
+ useEffect30(() => {
52993
+ const run = async () => {
52994
+ try {
52995
+ const data = await client.get(`/agent-versions/${agentId}`);
52996
+ setItems(data.versions ?? []);
52997
+ setPublishedId(data.publishedVersionId ?? null);
52998
+ setLoading(false);
52999
+ } catch (err) {
53000
+ setError(err instanceof Error ? err : new Error(String(err)));
53001
+ setLoading(false);
53002
+ }
53003
+ };
53004
+ run();
53005
+ }, []);
53006
+ return React19.createElement(DataList, {
53007
+ title: `Versions for agent ${agentId}`,
53008
+ items,
53009
+ error: error51,
53010
+ loading,
53011
+ emptyMessage: "No versions found",
53012
+ renderCard: (item) => {
53013
+ const v = item;
53014
+ const liveTag = v.id === publishedId ? " [live]" : "";
53015
+ const versionLabel = v.label || (v.versionNumber !== void 0 ? `v${v.versionNumber}` : v.id);
53016
+ return React19.createElement(
53017
+ Text35,
53018
+ null,
53019
+ ` ${v.id} ${versionLabel}${liveTag}${v.createdAt ? ` ${v.createdAt}` : ""}`
53020
+ );
53021
+ }
53022
+ });
53023
+ };
53024
+ const { waitUntilExit } = render19(React19.createElement(App));
53025
+ await waitUntilExit();
53026
+ });
53027
+ agentVersionsCommand.command("get <agentId> <versionId>").description("Get a specific version").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
53028
+ async (agentId, versionId, options) => {
53029
+ const apiKey = await ensureAuth();
53030
+ if (!apiKey) return;
53031
+ const client = new ApiClient(apiKey);
53032
+ if (!isTTY(options) || options.json) {
53033
+ try {
53034
+ const data = await client.get(`/agent-versions/${agentId}/${versionId}`);
53035
+ if (options.json) {
53036
+ printJson(data);
53037
+ } else {
53038
+ printDetail("Agent Version", [
53039
+ { label: "ID", value: data.id },
53040
+ { label: "Agent ID", value: data.agentId },
53041
+ { label: "Version", value: data.versionNumber },
53042
+ { label: "Type", value: data.versionType },
53043
+ { label: "Label", value: data.label ?? void 0 },
53044
+ { label: "Notes", value: data.notes ?? void 0 },
53045
+ { label: "Created", value: data.createdAt }
53046
+ ]);
53047
+ }
53048
+ } catch (error51) {
53049
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
53050
+ console.error(chalk27.red("Failed to fetch version"));
53051
+ console.error(chalk27.red(message));
53052
+ process.exit(1);
53053
+ }
53054
+ return;
53055
+ }
53056
+ const App = () => {
53057
+ const [loading, setLoading] = useState33(true);
53058
+ const [success2, setSuccess] = useState33(null);
53059
+ const [error51, setError] = useState33(null);
53060
+ const [resultNode, setResultNode] = useState33(void 0);
53061
+ useEffect30(() => {
53062
+ const run = async () => {
53063
+ try {
53064
+ const data = await client.get(`/agent-versions/${agentId}/${versionId}`);
53065
+ setResultNode(
53066
+ React19.createElement(EntityCard, {
53067
+ fields: [
53068
+ { label: "ID", value: data.id },
53069
+ { label: "Agent ID", value: data.agentId },
53070
+ { label: "Version", value: data.versionNumber },
53071
+ { label: "Type", value: data.versionType },
53072
+ { label: "Label", value: data.label ?? void 0 },
53073
+ { label: "Notes", value: data.notes ?? void 0 },
53074
+ { label: "Created", value: data.createdAt }
53075
+ ]
53076
+ })
53077
+ );
53078
+ setSuccess(true);
53079
+ setLoading(false);
53080
+ } catch (err) {
53081
+ setError(err instanceof Error ? err : new Error(String(err)));
53082
+ setSuccess(false);
53083
+ setLoading(false);
53084
+ }
53085
+ };
53086
+ run();
53087
+ }, []);
53088
+ return React19.createElement(MutationResult, {
53089
+ loading,
53090
+ loadingLabel: "Fetching version...",
53091
+ success: success2,
53092
+ successMessage: "Agent Version",
53093
+ error: error51,
53094
+ result: resultNode
53095
+ });
53096
+ };
53097
+ const { waitUntilExit } = render19(React19.createElement(App));
53098
+ await waitUntilExit();
53099
+ }
53100
+ );
53101
+ agentVersionsCommand.command("published <agentId>").description("Get the published version for an agent").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (agentId, options) => {
53102
+ const apiKey = await ensureAuth();
53103
+ if (!apiKey) return;
53104
+ const client = new ApiClient(apiKey);
53105
+ if (!isTTY(options) || options.json) {
53106
+ try {
53107
+ const data = await client.get(`/agent-versions/${agentId}/published`);
53108
+ if (options.json) {
53109
+ printJson(data);
53110
+ } else {
53111
+ printDetail("Published Version", [
53112
+ { label: "ID", value: data.id },
53113
+ { label: "Version", value: data.versionNumber },
53114
+ { label: "Label", value: data.label ?? void 0 },
53115
+ { label: "Created", value: data.createdAt }
53116
+ ]);
53117
+ }
53118
+ } catch (error51) {
53119
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
53120
+ console.error(chalk27.red("Failed to fetch published version"));
53121
+ console.error(chalk27.red(message));
53122
+ process.exit(1);
53123
+ }
53124
+ return;
53125
+ }
53126
+ const App = () => {
53127
+ const [loading, setLoading] = useState33(true);
53128
+ const [success2, setSuccess] = useState33(null);
53129
+ const [error51, setError] = useState33(null);
53130
+ const [resultNode, setResultNode] = useState33(void 0);
53131
+ useEffect30(() => {
53132
+ const run = async () => {
53133
+ try {
53134
+ const data = await client.get(`/agent-versions/${agentId}/published`);
53135
+ setResultNode(
53136
+ React19.createElement(EntityCard, {
53137
+ fields: [
53138
+ { label: "ID", value: data.id },
53139
+ { label: "Version", value: data.versionNumber },
53140
+ { label: "Label", value: data.label ?? void 0 },
53141
+ { label: "Created", value: data.createdAt }
53142
+ ]
53143
+ })
53144
+ );
53145
+ setSuccess(true);
53146
+ setLoading(false);
53147
+ } catch (err) {
53148
+ setError(err instanceof Error ? err : new Error(String(err)));
53149
+ setSuccess(false);
53150
+ setLoading(false);
53151
+ }
53152
+ };
53153
+ run();
53154
+ }, []);
53155
+ return React19.createElement(MutationResult, {
53156
+ loading,
53157
+ loadingLabel: "Fetching published version...",
53158
+ success: success2,
53159
+ successMessage: "Published Version",
53160
+ error: error51,
53161
+ result: resultNode
53162
+ });
53163
+ };
53164
+ const { waitUntilExit } = render19(React19.createElement(App));
53165
+ await waitUntilExit();
53166
+ });
53167
+ agentVersionsCommand.command("publish <agentId>").description("Publish a version").requiredOption("-v, --version <versionId>", "Version ID to publish").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
53168
+ async (agentId, options) => {
53169
+ const apiKey = await ensureAuth();
53170
+ if (!apiKey) return;
53171
+ const client = new ApiClient(apiKey);
53172
+ if (!isTTY(options)) {
53173
+ try {
53174
+ await client.post(`/agent-versions/${agentId}/publish`, {
53175
+ versionId: options.version
53176
+ });
53177
+ console.log(chalk27.green("Version published"));
53178
+ } catch (error51) {
53179
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
53180
+ console.error(chalk27.red("Failed to publish version"));
53181
+ console.error(chalk27.red(message));
53182
+ process.exit(1);
53183
+ }
53184
+ return;
53185
+ }
53186
+ const App = () => {
53187
+ const [loading, setLoading] = useState33(true);
53188
+ const [success2, setSuccess] = useState33(null);
53189
+ const [error51, setError] = useState33(null);
53190
+ useEffect30(() => {
53191
+ const run = async () => {
53192
+ try {
53193
+ await client.post(`/agent-versions/${agentId}/publish`, {
53194
+ versionId: options.version
53195
+ });
53196
+ setSuccess(true);
53197
+ setLoading(false);
53198
+ } catch (err) {
53199
+ setError(err instanceof Error ? err : new Error(String(err)));
53200
+ setSuccess(false);
53201
+ setLoading(false);
53202
+ }
53203
+ };
53204
+ run();
53205
+ }, []);
53206
+ return React19.createElement(MutationResult, {
53207
+ loading,
53208
+ loadingLabel: "Publishing version...",
53209
+ success: success2,
53210
+ successMessage: "Version published",
53211
+ error: error51
53212
+ });
53213
+ };
53214
+ const { waitUntilExit } = render19(React19.createElement(App));
53215
+ await waitUntilExit();
53216
+ }
53217
+ );
53218
+
53219
+ // src/commands/tail.ts
53220
+ import { Command as Command22 } from "commander";
53221
+ import chalk28 from "chalk";
52946
53222
  function abbreviateId(id) {
52947
53223
  const underscoreIdx = id.lastIndexOf("_");
52948
53224
  if (underscoreIdx === -1) {
@@ -52961,20 +53237,20 @@ function formatTime(ts) {
52961
53237
  return `${hh}:${mm}:${ss}.${ms}`;
52962
53238
  }
52963
53239
  var LEVEL_COLORS = {
52964
- debug: chalk27.gray,
52965
- info: chalk27.blue,
52966
- warn: chalk27.yellow,
52967
- error: chalk27.red
53240
+ debug: chalk28.gray,
53241
+ info: chalk28.blue,
53242
+ warn: chalk28.yellow,
53243
+ error: chalk28.red
52968
53244
  };
52969
53245
  function levelBadge(level, useColor) {
52970
53246
  const tag = level.toUpperCase().padEnd(5);
52971
53247
  if (!useColor) return `[${tag}]`;
52972
- const colorFn = LEVEL_COLORS[level] || chalk27.white;
53248
+ const colorFn = LEVEL_COLORS[level] || chalk28.white;
52973
53249
  return colorFn(`[${tag}]`);
52974
53250
  }
52975
53251
  function categoryBadge(category, useColor) {
52976
53252
  if (!useColor) return `[${category}]`;
52977
- return chalk27.magenta(`[${category}]`);
53253
+ return chalk28.magenta(`[${category}]`);
52978
53254
  }
52979
53255
  function formatTailData(data) {
52980
53256
  return Object.entries(data).map(([k, v]) => `${k}=${typeof v === "string" ? v : JSON.stringify(v)}`).join(" ");
@@ -52989,14 +53265,14 @@ function formatContextIds(event, useColor) {
52989
53265
  if (event.conversationId) ids.push(`conv=${abbreviateId(event.conversationId)}`);
52990
53266
  if (ids.length === 0) return "";
52991
53267
  const text = ids.join(" ");
52992
- return useColor ? chalk27.gray(` ${text}`) : ` ${text}`;
53268
+ return useColor ? chalk28.gray(` ${text}`) : ` ${text}`;
52993
53269
  }
52994
53270
  function formatEvent(event, useColor) {
52995
- const time3 = useColor ? chalk27.gray(formatTime(event.timestamp)) : formatTime(event.timestamp);
53271
+ const time3 = useColor ? chalk28.gray(formatTime(event.timestamp)) : formatTime(event.timestamp);
52996
53272
  const level = levelBadge(event.level, useColor);
52997
53273
  const cat = categoryBadge(event.category, useColor);
52998
53274
  const ctx = formatContextIds(event, useColor);
52999
- const data = event.tailData && Object.keys(event.tailData).length > 0 ? useColor ? chalk27.gray(` | ${formatTailData(event.tailData)}`) : ` | ${formatTailData(event.tailData)}` : "";
53275
+ const data = event.tailData && Object.keys(event.tailData).length > 0 ? useColor ? chalk28.gray(` | ${formatTailData(event.tailData)}`) : ` | ${formatTailData(event.tailData)}` : "";
53000
53276
  return `${time3} ${level} ${cat} ${event.message}${data}${ctx}`;
53001
53277
  }
53002
53278
  async function consumeSSEStream(reader, options, signal) {
@@ -53035,17 +53311,17 @@ async function consumeSSEStream(reader, options, signal) {
53035
53311
  break;
53036
53312
  case "tail_gap":
53037
53313
  process.stderr.write(
53038
- (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"
53314
+ (useColor ? chalk28.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"
53039
53315
  );
53040
53316
  break;
53041
53317
  case "tail_connected":
53042
53318
  process.stderr.write(
53043
- (useColor ? chalk27.green(`Connected to tail session ${msg.sessionId}`) : `Connected to tail session ${msg.sessionId}`) + "\n"
53319
+ (useColor ? chalk28.green(`Connected to tail session ${msg.sessionId}`) : `Connected to tail session ${msg.sessionId}`) + "\n"
53044
53320
  );
53045
53321
  break;
53046
53322
  case "tail_error":
53047
53323
  process.stderr.write(
53048
- (useColor ? chalk27.red(`[error] ${msg.error}`) : `[error] ${msg.error}`) + "\n"
53324
+ (useColor ? chalk28.red(`[error] ${msg.error}`) : `[error] ${msg.error}`) + "\n"
53049
53325
  );
53050
53326
  break;
53051
53327
  }
@@ -53125,7 +53401,7 @@ async function runTail(options) {
53125
53401
  const useColor = options.color;
53126
53402
  const activeFilters = Object.entries(filters).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${v}`);
53127
53403
  process.stderr.write(
53128
- (useColor ? chalk27.gray(`Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) : `Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) + "\n"
53404
+ (useColor ? chalk28.gray(`Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) : `Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) + "\n"
53129
53405
  );
53130
53406
  const controller = new AbortController();
53131
53407
  let shuttingDown = false;
@@ -53133,7 +53409,7 @@ async function runTail(options) {
53133
53409
  if (shuttingDown) return;
53134
53410
  shuttingDown = true;
53135
53411
  process.stderr.write(
53136
- (useColor ? chalk27.gray("\nDisconnecting...") : "\nDisconnecting...") + "\n"
53412
+ (useColor ? chalk28.gray("\nDisconnecting...") : "\nDisconnecting...") + "\n"
53137
53413
  );
53138
53414
  controller.abort();
53139
53415
  };
@@ -53147,7 +53423,7 @@ async function runTail(options) {
53147
53423
  const result = await connectAndStream(session.sseUrl, apiKey, options, controller.signal);
53148
53424
  if (result === "aborted" || shuttingDown) break;
53149
53425
  process.stderr.write(
53150
- (useColor ? chalk27.yellow("Stream ended, reconnecting...") : "Stream ended, reconnecting...") + "\n"
53426
+ (useColor ? chalk28.yellow("Stream ended, reconnecting...") : "Stream ended, reconnecting...") + "\n"
53151
53427
  );
53152
53428
  } catch (err) {
53153
53429
  if (shuttingDown || controller.signal.aborted) break;
@@ -53155,16 +53431,16 @@ async function runTail(options) {
53155
53431
  const delay = Math.min(BASE_DELAY_MS * Math.pow(2, attempt - 1), MAX_DELAY_MS);
53156
53432
  const message = err instanceof Error ? err.message : String(err);
53157
53433
  process.stderr.write(
53158
- (useColor ? chalk27.red(`Connection error: ${message}`) : `Connection error: ${message}`) + "\n"
53434
+ (useColor ? chalk28.red(`Connection error: ${message}`) : `Connection error: ${message}`) + "\n"
53159
53435
  );
53160
53436
  if (attempt >= MAX_ATTEMPTS) {
53161
53437
  process.stderr.write(
53162
- (useColor ? chalk27.red(`Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) : `Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) + "\n"
53438
+ (useColor ? chalk28.red(`Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) : `Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) + "\n"
53163
53439
  );
53164
53440
  process.exit(1);
53165
53441
  }
53166
53442
  process.stderr.write(
53167
- (useColor ? chalk27.gray(`Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) : `Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) + "\n"
53443
+ (useColor ? chalk28.gray(`Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) : `Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) + "\n"
53168
53444
  );
53169
53445
  await new Promise((resolve10) => {
53170
53446
  const timer = setTimeout(resolve10, delay);
@@ -53179,16 +53455,16 @@ async function runTail(options) {
53179
53455
  process.removeListener("SIGINT", shutdown);
53180
53456
  process.removeListener("SIGTERM", shutdown);
53181
53457
  }
53182
- 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) => {
53458
+ var tailCommand = new Command22("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) => {
53183
53459
  await runTail(options);
53184
53460
  });
53185
53461
 
53186
53462
  // src/commands/validate-product.ts
53187
- import { Command as Command22, Option } from "commander";
53188
- import chalk28 from "chalk";
53463
+ import { Command as Command23, Option } from "commander";
53464
+ import chalk29 from "chalk";
53189
53465
  import { readFileSync as readFileSync15 } from "fs";
53190
53466
  function createValidateProductCommand() {
53191
- return new Command22("validate-product").description("Validate a product (FPO) or FPO template locally (no API call)").argument(
53467
+ return new Command23("validate-product").description("Validate a product (FPO) or FPO template locally (no API call)").argument(
53192
53468
  "[input]",
53193
53469
  'Path to JSON file, raw JSON string (starts with "{"), or "-" for stdin'
53194
53470
  ).option("--template", "Force FPO template validation").option("--fpo", "Force FPO (non-template) validation").addOption(
@@ -53212,7 +53488,7 @@ var validateProductCommand = createValidateProductCommand();
53212
53488
  async function runValidateAction(input, _options) {
53213
53489
  const options = this.optsWithGlobals();
53214
53490
  if (options.template && options.fpo) {
53215
- console.error(chalk28.red("Error: --template and --fpo are mutually exclusive"));
53491
+ console.error(chalk29.red("Error: --template and --fpo are mutually exclusive"));
53216
53492
  process.exit(1);
53217
53493
  }
53218
53494
  let raw;
@@ -53220,7 +53496,7 @@ async function runValidateAction(input, _options) {
53220
53496
  raw = await readInput(input);
53221
53497
  } catch (err) {
53222
53498
  const message = err instanceof Error ? err.message : String(err);
53223
- console.error(chalk28.red(`Failed to read input: ${message}`));
53499
+ console.error(chalk29.red(`Failed to read input: ${message}`));
53224
53500
  process.exit(1);
53225
53501
  return;
53226
53502
  }
@@ -53229,7 +53505,7 @@ async function runValidateAction(input, _options) {
53229
53505
  parsed = JSON.parse(raw);
53230
53506
  } catch (err) {
53231
53507
  const message = err instanceof Error ? err.message : String(err);
53232
- console.error(chalk28.red(`Invalid JSON: ${message}`));
53508
+ console.error(chalk29.red(`Invalid JSON: ${message}`));
53233
53509
  process.exit(1);
53234
53510
  return;
53235
53511
  }
@@ -53319,16 +53595,16 @@ function runValidation(body, kind) {
53319
53595
  function printHumanResult(kind, result) {
53320
53596
  const label = kind === "template" ? "FPO template" : "FPO";
53321
53597
  const overallValid = !hasAnyErrors(result);
53322
- const headline = overallValid ? chalk28.green(`\u2713 Valid ${label}`) : chalk28.red(`\u2717 Invalid ${label}`);
53598
+ const headline = overallValid ? chalk29.green(`\u2713 Valid ${label}`) : chalk29.red(`\u2717 Invalid ${label}`);
53323
53599
  console.log(headline);
53324
53600
  console.log(
53325
- chalk28.gray(
53601
+ chalk29.gray(
53326
53602
  ` ${result.errors.length} error(s), ${result.warnings.length} warning(s), ${result.recommendations.length} recommendation(s)`
53327
53603
  )
53328
53604
  );
53329
- printIssues("Errors", result.errors, chalk28.red);
53330
- printIssues("Warnings", result.warnings, chalk28.yellow);
53331
- printIssues("Recommendations", result.recommendations, chalk28.blue);
53605
+ printIssues("Errors", result.errors, chalk29.red);
53606
+ printIssues("Warnings", result.warnings, chalk29.yellow);
53607
+ printIssues("Recommendations", result.recommendations, chalk29.blue);
53332
53608
  if (result.kind === "template") {
53333
53609
  const defaults = result.defaultsValidation;
53334
53610
  const structuralErrors = defaults.errors.filter(
@@ -53340,22 +53616,22 @@ function printHumanResult(kind, result) {
53340
53616
  if (structuralErrors.length > 0) {
53341
53617
  console.log();
53342
53618
  console.log(
53343
- chalk28.red(
53619
+ chalk29.red(
53344
53620
  `Defaults validation: template defaults do not produce a valid FPO`
53345
53621
  )
53346
53622
  );
53347
- printIssues("Default-resolution errors", structuralErrors, chalk28.red);
53348
- printIssues("Default-resolution warnings", defaults.warnings, chalk28.yellow);
53623
+ printIssues("Default-resolution errors", structuralErrors, chalk29.red);
53624
+ printIssues("Default-resolution warnings", defaults.warnings, chalk29.yellow);
53349
53625
  }
53350
53626
  if (missingVars.length > 0) {
53351
53627
  console.log();
53352
53628
  console.log(
53353
- chalk28.gray(
53629
+ chalk29.gray(
53354
53630
  `Template variables needing deploy-time values (${missingVars.length}):`
53355
53631
  )
53356
53632
  );
53357
53633
  for (const issue2 of missingVars) {
53358
- console.log(chalk28.gray(` \u2022 ${issue2.path} \u2014 ${issue2.message}`));
53634
+ console.log(chalk29.gray(` \u2022 ${issue2.path} \u2014 ${issue2.message}`));
53359
53635
  }
53360
53636
  }
53361
53637
  }
@@ -53365,17 +53641,17 @@ function printIssues(title, issues, color) {
53365
53641
  console.log();
53366
53642
  console.log(color(`${title}:`));
53367
53643
  for (const issue2 of issues) {
53368
- const pathLabel = issue2.path ? chalk28.gray(` [${issue2.path}]`) : "";
53369
- console.log(` ${color("\u2022")} ${chalk28.bold(issue2.code)}${pathLabel} ${issue2.message}`);
53644
+ const pathLabel = issue2.path ? chalk29.gray(` [${issue2.path}]`) : "";
53645
+ console.log(` ${color("\u2022")} ${chalk29.bold(issue2.code)}${pathLabel} ${issue2.message}`);
53370
53646
  if (issue2.suggestedFix) {
53371
- console.log(` ${chalk28.gray("fix:")} ${issue2.suggestedFix}`);
53647
+ console.log(` ${chalk29.gray("fix:")} ${issue2.suggestedFix}`);
53372
53648
  }
53373
53649
  }
53374
53650
  }
53375
53651
 
53376
53652
  // src/commands/deploy.ts
53377
- import { Command as Command23 } from "commander";
53378
- import chalk29 from "chalk";
53653
+ import { Command as Command24 } from "commander";
53654
+ import chalk30 from "chalk";
53379
53655
  import * as fs14 from "fs";
53380
53656
  import * as path14 from "path";
53381
53657
  function bashSingleQuote(s) {
@@ -53696,6 +53972,612 @@ gcloud run deploy runtype-deploy \\
53696
53972
  \`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
53697
53973
  `;
53698
53974
  }
53975
+ function workerIndexTs(agentSlugs) {
53976
+ const imports = agentSlugs.map((slug, i) => `import agent${i}Json from '../agents/${slug}.json'`).join("\n");
53977
+ const agentFiles = agentSlugs.map((slug, i) => ` ['${slug}.json', agent${i}Json],`).join("\n");
53978
+ return `/**
53979
+ * Generated by \`runtype deploy --target cloudflare\`.
53980
+ *
53981
+ * Routes:
53982
+ * GET /health \u2014 liveness probe (lists registered agent names)
53983
+ * POST /agent/:name \u2014 SSE stream of the agent event schema
53984
+ *
53985
+ * Agent definitions are statically imported so Wrangler bundles them.
53986
+ * To add a new agent:
53987
+ * 1. Export it with \`runtype deploy --agent <id> --target cloudflare\`
53988
+ * 2. Or drop a JSON file under agents/ and add an import + entry below
53989
+ * 3. Run \`wrangler deploy\`
53990
+ */
53991
+ import {
53992
+ CloudflareAdapter,
53993
+ createRuntime,
53994
+ exportedAgentSchema,
53995
+ type ExportedAgent,
53996
+ } from '@runtypelabs/runtime'
53997
+
53998
+ // ---------------------------------------------------------------------------
53999
+ // Agent registry \u2014 static imports bundled by Wrangler at deploy time
54000
+ // ---------------------------------------------------------------------------
54001
+
54002
+ ${imports}
54003
+
54004
+ function parseAgent(json: unknown, filename: string): ExportedAgent {
54005
+ try {
54006
+ return exportedAgentSchema.parse(json)
54007
+ } catch (err) {
54008
+ throw new Error(
54009
+ \`[runtype] invalid agent JSON in \${filename}: \${
54010
+ err instanceof Error ? err.message : String(err)
54011
+ }\`
54012
+ )
54013
+ }
54014
+ }
54015
+
54016
+ const agentFiles: Array<[string, unknown]> = [
54017
+ ${agentFiles}
54018
+ ]
54019
+
54020
+ const agentRegistry: Record<string, ExportedAgent> = {}
54021
+ for (const [filename, json] of agentFiles) {
54022
+ const agent = parseAgent(json, filename)
54023
+ if (agentRegistry[agent.name]) {
54024
+ throw new Error(\`[runtype] duplicate agent name "\${agent.name}" in \${filename}\`)
54025
+ }
54026
+ agentRegistry[agent.name] = agent
54027
+ }
54028
+
54029
+ // ---------------------------------------------------------------------------
54030
+ // Env \u2014 Wrangler injects secrets + bindings here
54031
+ // ---------------------------------------------------------------------------
54032
+
54033
+ export interface Env {
54034
+ // Secrets \u2014 set via \`wrangler secret put <NAME>\`
54035
+ ANTHROPIC_API_KEY?: string
54036
+ OPENAI_API_KEY?: string
54037
+ GOOGLE_API_KEY?: string
54038
+ MIXLAYER_API_KEY?: string
54039
+ // Optional: narrow CORS from * to specific origins (comma-separated)
54040
+ ALLOWED_ORIGINS?: string
54041
+ // Optional: KV namespace binding for durable cross-request caching
54042
+ CACHE_KV?: KVNamespace
54043
+ }
54044
+
54045
+ // ---------------------------------------------------------------------------
54046
+ // Worker
54047
+ // ---------------------------------------------------------------------------
54048
+
54049
+ export default {
54050
+ async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
54051
+ const url = new URL(request.url)
54052
+ const cors = corsHeaders(request, env.ALLOWED_ORIGINS)
54053
+
54054
+ if (request.method === 'OPTIONS') {
54055
+ return new Response(null, { status: 204, headers: cors })
54056
+ }
54057
+
54058
+ if (request.method === 'GET' && url.pathname === '/health') {
54059
+ return json({ status: 'ok', agents: Object.keys(agentRegistry) }, 200, cors)
54060
+ }
54061
+
54062
+ const agentMatch = url.pathname.match(/^\\/agent\\/([^/]+)$/)
54063
+ if (request.method === 'POST' && agentMatch) {
54064
+ const name = decodeURIComponent(agentMatch[1])
54065
+ if (!agentRegistry[name]) {
54066
+ return json({ error: \`unknown agent: \${name}\` }, 404, cors)
54067
+ }
54068
+
54069
+ const runtime = createRuntime({
54070
+ agents: agentRegistry,
54071
+ keys: { mode: 'own' },
54072
+ adapter: new CloudflareAdapter(env, {
54073
+ kvNamespace: env.CACHE_KV,
54074
+ waitUntil: ctx.waitUntil.bind(ctx),
54075
+ }),
54076
+ })
54077
+
54078
+ let body: { messages?: Array<{ role: string; content: string }> } = {}
54079
+ try {
54080
+ body = (await request.json()) as typeof body
54081
+ } catch {
54082
+ return json({ error: 'request body must be JSON' }, 400, cors)
54083
+ }
54084
+ const messages = Array.isArray(body.messages) ? body.messages : []
54085
+
54086
+ try {
54087
+ const response = await runtime.executeAgent(name, {
54088
+ messages: messages as Array<{
54089
+ role: 'system' | 'user' | 'assistant'
54090
+ content: string
54091
+ }>,
54092
+ signal: request.signal,
54093
+ })
54094
+ const headers = new Headers(response.headers)
54095
+ for (const [k, v] of Object.entries(cors)) headers.set(k, v)
54096
+ return new Response(response.body, { status: response.status, headers })
54097
+ } catch (err) {
54098
+ return json({ error: err instanceof Error ? err.message : 'unknown error' }, 500, cors)
54099
+ }
54100
+ }
54101
+
54102
+ return json({ error: 'not found' }, 404, cors)
54103
+ },
54104
+ }
54105
+
54106
+ // ---------------------------------------------------------------------------
54107
+ // Helpers
54108
+ // ---------------------------------------------------------------------------
54109
+
54110
+ function json(body: unknown, status: number, extra: Record<string, string>): Response {
54111
+ return new Response(JSON.stringify(body), {
54112
+ status,
54113
+ headers: { 'Content-Type': 'application/json', ...extra },
54114
+ })
54115
+ }
54116
+
54117
+ function corsHeaders(request: Request, allowedOriginsEnv?: string): Record<string, string> {
54118
+ const origin = request.headers.get('Origin') ?? ''
54119
+ let allow = '*'
54120
+ if (allowedOriginsEnv) {
54121
+ const list = allowedOriginsEnv.split(',').map((o) => o.trim()).filter(Boolean)
54122
+ allow = list.includes(origin) ? origin : (list[0] ?? '*')
54123
+ }
54124
+ const headers: Record<string, string> = {
54125
+ 'Access-Control-Allow-Origin': allow,
54126
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
54127
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
54128
+ 'Access-Control-Max-Age': '86400',
54129
+ }
54130
+ if (allow !== '*') headers['Vary'] = 'Origin'
54131
+ return headers
54132
+ }
54133
+ `;
54134
+ }
54135
+ function wranglerToml(projectName) {
54136
+ return `name = "${projectName}"
54137
+ main = "src/index.ts"
54138
+ compatibility_date = "2025-01-01"
54139
+
54140
+ # Secrets \u2014 set via \`wrangler secret put <NAME>\`
54141
+ # Run this for each API key your agents need:
54142
+ # wrangler secret put ANTHROPIC_API_KEY
54143
+ # wrangler secret put OPENAI_API_KEY
54144
+ # wrangler secret put GOOGLE_API_KEY
54145
+ # wrangler secret put MIXLAYER_API_KEY
54146
+
54147
+ # Optional: KV namespace for durable cross-request caching.
54148
+ # Without this the adapter uses a per-isolate in-memory Map (ephemeral).
54149
+ # To enable:
54150
+ # 1. wrangler kv namespace create CACHE_KV
54151
+ # 2. Uncomment the block below and paste the generated id.
54152
+ # [[kv_namespaces]]
54153
+ # binding = "CACHE_KV"
54154
+ # id = "<paste your KV namespace id here>"
54155
+
54156
+ # Optional: Workers AI binding (for @cf/* and workers-ai/* model ids).
54157
+ # [ai]
54158
+ # binding = "AI"
54159
+
54160
+ # CORS: narrow from * to specific origins via ALLOWED_ORIGINS env var.
54161
+ # [vars]
54162
+ # ALLOWED_ORIGINS = "https://yourapp.com,https://persona-chat.dev"
54163
+ `;
54164
+ }
54165
+ function workerPackageJson(name, runtimeDep) {
54166
+ return JSON.stringify(
54167
+ {
54168
+ name,
54169
+ version: "0.0.0",
54170
+ private: true,
54171
+ scripts: {
54172
+ dev: "wrangler dev",
54173
+ deploy: "wrangler deploy",
54174
+ typecheck: "tsc --noEmit"
54175
+ },
54176
+ dependencies: {
54177
+ "@runtypelabs/runtime": runtimeDep
54178
+ },
54179
+ devDependencies: {
54180
+ "@cloudflare/workers-types": "^4.0.0",
54181
+ typescript: "^5.3.3",
54182
+ wrangler: "^4.0.0"
54183
+ }
54184
+ },
54185
+ null,
54186
+ 2
54187
+ );
54188
+ }
54189
+ function workerTsconfigJson() {
54190
+ return JSON.stringify(
54191
+ {
54192
+ compilerOptions: {
54193
+ target: "ES2022",
54194
+ module: "ES2022",
54195
+ moduleResolution: "bundler",
54196
+ strict: true,
54197
+ resolveJsonModule: true,
54198
+ types: ["@cloudflare/workers-types"]
54199
+ },
54200
+ include: ["src"]
54201
+ },
54202
+ null,
54203
+ 2
54204
+ );
54205
+ }
54206
+ function workerSetupSh(monorepoRoot) {
54207
+ return `#!/usr/bin/env bash
54208
+ # Generated by \`runtype deploy --target cloudflare\`.
54209
+ #
54210
+ # Builds and packs @runtypelabs/runtime from your local monorepo, then
54211
+ # installs all dependencies so you can run \`wrangler dev\` or deploy with
54212
+ # \`wrangler deploy\`.
54213
+ #
54214
+ # Usage (from this directory):
54215
+ # ./setup.sh
54216
+
54217
+ set -euo pipefail
54218
+
54219
+ DEPLOY_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
54220
+ MONOREPO_ROOT=${bashSingleQuote(monorepoRoot)}
54221
+ TARBALL_DIR="\${DEPLOY_DIR}/packages"
54222
+
54223
+ echo "[setup] building @runtypelabs/runtime..."
54224
+ pnpm --dir "\${MONOREPO_ROOT}" --filter @runtypelabs/runtime build
54225
+
54226
+ mkdir -p "\${TARBALL_DIR}"
54227
+
54228
+ echo "[setup] packing @runtypelabs/runtime tarball..."
54229
+ pnpm --dir "\${MONOREPO_ROOT}/packages/runtime" pack \\
54230
+ --pack-destination "\${TARBALL_DIR}"
54231
+
54232
+ RUNTIME_TGZ="$(ls "\${TARBALL_DIR}"/runtypelabs-runtime-*.tgz | head -n 1)"
54233
+ if [ -z "\${RUNTIME_TGZ}" ]; then
54234
+ echo "[setup] error: no tarball produced by pnpm pack" >&2
54235
+ exit 1
54236
+ fi
54237
+ RUNTIME_TGZ_NAME="$(basename "\${RUNTIME_TGZ}")"
54238
+
54239
+ echo "[setup] updating package.json with file: dependency..."
54240
+ node -e "
54241
+ const fs = require('fs');
54242
+ const pkg = JSON.parse(fs.readFileSync('\${DEPLOY_DIR}/package.json', 'utf8'));
54243
+ pkg.dependencies['@runtypelabs/runtime'] = 'file:./packages/\${RUNTIME_TGZ_NAME}';
54244
+ fs.writeFileSync('\${DEPLOY_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\\\\n');
54245
+ "
54246
+
54247
+ echo "[setup] installing dependencies..."
54248
+ npm install --no-audit --no-fund
54249
+
54250
+ echo ""
54251
+ echo "[setup] Done! Next steps:"
54252
+ echo " wrangler dev \u2014 preview locally"
54253
+ echo " wrangler deploy \u2014 deploy to Cloudflare Workers"
54254
+ `;
54255
+ }
54256
+ function workerReadme(agentNames, secretNames) {
54257
+ const agentList = agentNames.map((n) => ` - ${n}`).join("\n");
54258
+ const secretList = secretNames.length > 0 ? secretNames.map((s) => ` wrangler secret put ${s}`).join("\n") : " (none detected)";
54259
+ return `# Runtype Cloudflare Workers Deployment
54260
+
54261
+ Generated by \`runtype deploy --target cloudflare\`. Contains the following agents:
54262
+
54263
+ ${agentList}
54264
+
54265
+ ## Setup
54266
+
54267
+ \`\`\`bash
54268
+ chmod +x setup.sh && ./setup.sh # build runtime + install deps
54269
+ \`\`\`
54270
+
54271
+ ## Secrets
54272
+
54273
+ Set each API key your agents use:
54274
+
54275
+ \`\`\`bash
54276
+ ${secretList}
54277
+ \`\`\`
54278
+
54279
+ ## Run locally
54280
+
54281
+ \`\`\`bash
54282
+ wrangler dev
54283
+ \`\`\`
54284
+
54285
+ ## Deploy
54286
+
54287
+ \`\`\`bash
54288
+ wrangler deploy
54289
+ \`\`\`
54290
+
54291
+ ## Health check
54292
+
54293
+ \`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
54294
+
54295
+ ## Call an agent
54296
+
54297
+ \`\`\`bash
54298
+ curl https://<worker-subdomain>.workers.dev/agent/<name> \\
54299
+ -H 'Content-Type: application/json' \\
54300
+ -d '{"messages":[{"role":"user","content":"Hello"}]}'
54301
+ \`\`\`
54302
+ `;
54303
+ }
54304
+ function vercelRouteTs(agentSlugs) {
54305
+ const imports = agentSlugs.map((slug, i) => `import agent${i}Json from '../agents/${slug}.json'`).join("\n");
54306
+ const agentFiles = agentSlugs.map((slug, i) => ` ['${slug}.json', agent${i}Json],`).join("\n");
54307
+ return `/**
54308
+ * Generated by \`runtype deploy --target vercel\`.
54309
+ *
54310
+ * Catch-all Vercel Function. All traffic is rewritten here by vercel.json.
54311
+ * Routes:
54312
+ * GET /health \u2014 liveness probe (lists registered agent names)
54313
+ * POST /agent/:name \u2014 SSE stream of the agent event schema
54314
+ *
54315
+ * Agent definitions are statically imported and bundled by Vercel.
54316
+ * To add a new agent:
54317
+ * 1. Export it with \`runtype deploy --agent <id> --target vercel\`
54318
+ * 2. Or drop a JSON file under agents/ and add an import + entry below
54319
+ * 3. Run \`vercel deploy\`
54320
+ */
54321
+ import { Hono } from 'hono'
54322
+ import { handle } from 'hono/vercel'
54323
+ import { cors } from 'hono/cors'
54324
+ import {
54325
+ VercelAdapter,
54326
+ createRuntime,
54327
+ exportedAgentSchema,
54328
+ type ExportedAgent,
54329
+ } from '@runtypelabs/runtime'
54330
+
54331
+ // ---------------------------------------------------------------------------
54332
+ // Agent registry \u2014 built at module load, cached across warm invocations
54333
+ // ---------------------------------------------------------------------------
54334
+
54335
+ ${imports}
54336
+
54337
+ function parseAgent(json: unknown, filename: string): ExportedAgent {
54338
+ try {
54339
+ return exportedAgentSchema.parse(json)
54340
+ } catch (err) {
54341
+ throw new Error(
54342
+ \`[runtype] invalid agent JSON in \${filename}: \${
54343
+ err instanceof Error ? err.message : String(err)
54344
+ }\`
54345
+ )
54346
+ }
54347
+ }
54348
+
54349
+ const agentFiles: Array<[string, unknown]> = [
54350
+ ${agentFiles}
54351
+ ]
54352
+
54353
+ const agentRegistry: Record<string, ExportedAgent> = {}
54354
+ for (const [filename, json] of agentFiles) {
54355
+ const agent = parseAgent(json, filename)
54356
+ if (agentRegistry[agent.name]) {
54357
+ throw new Error(\`[runtype] duplicate agent name "\${agent.name}" in \${filename}\`)
54358
+ }
54359
+ agentRegistry[agent.name] = agent
54360
+ }
54361
+
54362
+ // ---------------------------------------------------------------------------
54363
+ // Runtime \u2014 constructed at module scope (warm across invocations)
54364
+ // ---------------------------------------------------------------------------
54365
+
54366
+ const runtime = createRuntime({
54367
+ agents: agentRegistry,
54368
+ keys: { mode: 'own' },
54369
+ adapter: new VercelAdapter(),
54370
+ })
54371
+
54372
+ // ---------------------------------------------------------------------------
54373
+ // Hono app
54374
+ // ---------------------------------------------------------------------------
54375
+
54376
+ const app = new Hono()
54377
+
54378
+ const allowedOriginsEnv = process.env.ALLOWED_ORIGINS?.trim()
54379
+ const allowedOrigins = allowedOriginsEnv
54380
+ ? allowedOriginsEnv.split(',').map((o) => o.trim()).filter(Boolean)
54381
+ : '*'
54382
+
54383
+ app.use(
54384
+ '*',
54385
+ cors({
54386
+ origin: allowedOrigins,
54387
+ allowMethods: ['GET', 'POST', 'OPTIONS'],
54388
+ allowHeaders: ['Content-Type', 'Authorization'],
54389
+ maxAge: 86400,
54390
+ })
54391
+ )
54392
+
54393
+ app.get('/health', (c) => c.json({ status: 'ok', agents: Object.keys(agentRegistry) }))
54394
+
54395
+ app.post('/agent/:name', async (c) => {
54396
+ const name = c.req.param('name')
54397
+ if (!runtime.getAgent(name)) {
54398
+ return c.json({ error: \`unknown agent: \${name}\` }, 404)
54399
+ }
54400
+
54401
+ let body: { messages?: Array<{ role: string; content: string }> } = {}
54402
+ try {
54403
+ body = (await c.req.json()) as typeof body
54404
+ } catch {
54405
+ return c.json({ error: 'request body must be JSON' }, 400)
54406
+ }
54407
+ const messages = Array.isArray(body.messages) ? body.messages : []
54408
+
54409
+ try {
54410
+ const response = await runtime.executeAgent(name, {
54411
+ messages: messages as Array<{
54412
+ role: 'system' | 'user' | 'assistant'
54413
+ content: string
54414
+ }>,
54415
+ signal: c.req.raw.signal,
54416
+ })
54417
+ return response
54418
+ } catch (err) {
54419
+ return c.json({ error: err instanceof Error ? err.message : 'unknown error' }, 500)
54420
+ }
54421
+ })
54422
+
54423
+ export const GET = handle(app)
54424
+ export const POST = handle(app)
54425
+ `;
54426
+ }
54427
+ function vercelJson() {
54428
+ return JSON.stringify(
54429
+ {
54430
+ rewrites: [{ source: "/(.*)", destination: "/api/[[...route]]" }],
54431
+ functions: {
54432
+ "api/[[...route]].ts": { maxDuration: 60 }
54433
+ }
54434
+ },
54435
+ null,
54436
+ 2
54437
+ );
54438
+ }
54439
+ function vercelPackageJson(name, runtimeDep) {
54440
+ return JSON.stringify(
54441
+ {
54442
+ name,
54443
+ version: "0.0.0",
54444
+ private: true,
54445
+ scripts: {
54446
+ dev: "vercel dev",
54447
+ deploy: "vercel deploy",
54448
+ typecheck: "tsc --noEmit"
54449
+ },
54450
+ dependencies: {
54451
+ "@runtypelabs/runtime": runtimeDep,
54452
+ hono: "^4.12.16"
54453
+ },
54454
+ devDependencies: {
54455
+ "@types/node": "^22.0.0",
54456
+ "@vercel/node": "^5.0.0",
54457
+ typescript: "^5.3.3",
54458
+ vercel: "^44.0.0"
54459
+ }
54460
+ },
54461
+ null,
54462
+ 2
54463
+ );
54464
+ }
54465
+ function vercelTsconfigJson() {
54466
+ return JSON.stringify(
54467
+ {
54468
+ compilerOptions: {
54469
+ target: "ES2022",
54470
+ module: "ESNext",
54471
+ moduleResolution: "bundler",
54472
+ strict: true,
54473
+ resolveJsonModule: true,
54474
+ esModuleInterop: true,
54475
+ skipLibCheck: true
54476
+ },
54477
+ include: ["api"]
54478
+ },
54479
+ null,
54480
+ 2
54481
+ );
54482
+ }
54483
+ function vercelSetupSh(monorepoRoot) {
54484
+ return `#!/usr/bin/env bash
54485
+ # Generated by \`runtype deploy --target vercel\`.
54486
+ #
54487
+ # Builds and packs @runtypelabs/runtime from your local monorepo, then
54488
+ # installs all dependencies so you can run \`vercel dev\` or deploy with
54489
+ # \`vercel deploy\`.
54490
+ #
54491
+ # Usage (from this directory):
54492
+ # ./setup.sh
54493
+
54494
+ set -euo pipefail
54495
+
54496
+ DEPLOY_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
54497
+ MONOREPO_ROOT=${bashSingleQuote(monorepoRoot)}
54498
+ TARBALL_DIR="\${DEPLOY_DIR}/packages"
54499
+
54500
+ echo "[setup] building @runtypelabs/runtime..."
54501
+ pnpm --dir "\${MONOREPO_ROOT}" --filter @runtypelabs/runtime build
54502
+
54503
+ mkdir -p "\${TARBALL_DIR}"
54504
+
54505
+ echo "[setup] packing @runtypelabs/runtime tarball..."
54506
+ pnpm --dir "\${MONOREPO_ROOT}/packages/runtime" pack \\
54507
+ --pack-destination "\${TARBALL_DIR}"
54508
+
54509
+ RUNTIME_TGZ="$(ls "\${TARBALL_DIR}"/runtypelabs-runtime-*.tgz | head -n 1)"
54510
+ if [ -z "\${RUNTIME_TGZ}" ]; then
54511
+ echo "[setup] error: no tarball produced by pnpm pack" >&2
54512
+ exit 1
54513
+ fi
54514
+ RUNTIME_TGZ_NAME="$(basename "\${RUNTIME_TGZ}")"
54515
+
54516
+ echo "[setup] updating package.json with file: dependency..."
54517
+ node -e "
54518
+ const fs = require('fs');
54519
+ const pkg = JSON.parse(fs.readFileSync('\${DEPLOY_DIR}/package.json', 'utf8'));
54520
+ pkg.dependencies['@runtypelabs/runtime'] = 'file:./packages/\${RUNTIME_TGZ_NAME}';
54521
+ fs.writeFileSync('\${DEPLOY_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\\\\n');
54522
+ "
54523
+
54524
+ echo "[setup] installing dependencies..."
54525
+ npm install --no-audit --no-fund
54526
+
54527
+ echo ""
54528
+ echo "[setup] Done! Next steps:"
54529
+ echo " vercel dev \u2014 preview locally"
54530
+ echo " vercel deploy \u2014 deploy to Vercel Functions"
54531
+ `;
54532
+ }
54533
+ function vercelReadme(agentNames, secretNames) {
54534
+ const agentList = agentNames.map((n) => ` - ${n}`).join("\n");
54535
+ const secretList = secretNames.length > 0 ? secretNames.map((s) => ` vercel env add ${s}`).join("\n") : " (none detected)";
54536
+ return `# Runtype Vercel Functions Deployment
54537
+
54538
+ Generated by \`runtype deploy --target vercel\`. Contains the following agents:
54539
+
54540
+ ${agentList}
54541
+
54542
+ ## Setup
54543
+
54544
+ \`\`\`bash
54545
+ chmod +x setup.sh && ./setup.sh # build runtime + install deps
54546
+ \`\`\`
54547
+
54548
+ ## Secrets
54549
+
54550
+ Set each API key your agents use via the Vercel dashboard or CLI:
54551
+
54552
+ \`\`\`bash
54553
+ ${secretList}
54554
+ \`\`\`
54555
+
54556
+ ## Run locally
54557
+
54558
+ \`\`\`bash
54559
+ vercel dev
54560
+ \`\`\`
54561
+
54562
+ ## Deploy
54563
+
54564
+ \`\`\`bash
54565
+ vercel deploy
54566
+ \`\`\`
54567
+
54568
+ ## Health check
54569
+
54570
+ \`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
54571
+
54572
+ ## Call an agent
54573
+
54574
+ \`\`\`bash
54575
+ curl https://<your-project>.vercel.app/agent/<name> \\
54576
+ -H 'Content-Type: application/json' \\
54577
+ -d '{"messages":[{"role":"user","content":"Hello"}]}'
54578
+ \`\`\`
54579
+ `;
54580
+ }
53699
54581
  function collectSecretNames(agentDef) {
53700
54582
  const names = /* @__PURE__ */ new Set();
53701
54583
  const model = agentDef.config?.model?.toLowerCase();
@@ -53718,18 +54600,23 @@ function collectSecretNames(agentDef) {
53718
54600
  function slugify2(s) {
53719
54601
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
53720
54602
  }
53721
- var deployCommand = new Command23("deploy").description("Export an agent or flow and scaffold a Cloud Run deployment").option("--agent <id>", "Agent ID to export (may be repeated)", (v, acc) => {
54603
+ var deployCommand = new Command24("deploy").description("Export an agent or flow and scaffold a deployment (cloud-run, cloudflare, or vercel)").option("--agent <id>", "Agent ID to export (may be repeated)", (v, acc) => {
53722
54604
  acc.push(v);
53723
54605
  return acc;
53724
54606
  }, []).option("--flow <id>", "Flow ID to export (may be repeated)", (v, acc) => {
53725
54607
  acc.push(v);
53726
54608
  return acc;
53727
- }, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").action(
54609
+ }, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").option("--target <target>", "Deployment target: cloud-run, cloudflare, or vercel (default: cloud-run)", "cloud-run").action(
53728
54610
  async (options) => {
53729
54611
  const agentIds = options.agent;
53730
54612
  const flowIds = options.flow;
53731
54613
  if (agentIds.length === 0 && flowIds.length === 0) {
53732
- console.error(chalk29.red("Error: provide at least one --agent <id> or --flow <id>"));
54614
+ console.error(chalk30.red("Error: provide at least one --agent <id> or --flow <id>"));
54615
+ process.exit(1);
54616
+ }
54617
+ const target = options.target;
54618
+ if (target !== "cloud-run" && target !== "cloudflare" && target !== "vercel") {
54619
+ console.error(chalk30.red(`Error: unknown --target "${target}". Must be one of: cloud-run, cloudflare, vercel`));
53733
54620
  process.exit(1);
53734
54621
  }
53735
54622
  const apiKey = await ensureAuth();
@@ -53737,30 +54624,30 @@ var deployCommand = new Command23("deploy").description("Export an agent or flow
53737
54624
  const client = new ApiClient(apiKey);
53738
54625
  const outDir = path14.resolve(options.output);
53739
54626
  const projectName = options.name ?? slugify2(path14.basename(outDir));
53740
- console.log(chalk29.cyan(`
53741
- Scaffolding deployment to ${outDir}
54627
+ console.log(chalk30.cyan(`
54628
+ Scaffolding ${target} deployment to ${outDir}
53742
54629
  `));
53743
54630
  const agentDefs = [];
53744
54631
  for (const id of agentIds) {
53745
- process.stdout.write(` Exporting agent ${chalk29.green(id)}... `);
54632
+ process.stdout.write(` Exporting agent ${chalk30.green(id)}... `);
53746
54633
  try {
53747
54634
  const def = await client.get(`/agents/${id}/export-runtime`);
53748
54635
  agentDefs.push({ id, name: String(def.name ?? id), def });
53749
- process.stdout.write(chalk29.green("\u2713\n"));
54636
+ process.stdout.write(chalk30.green("\u2713\n"));
53750
54637
  } catch (err) {
53751
54638
  const msg = err instanceof ApiError ? err.message : String(err);
53752
- process.stdout.write(chalk29.red(`\u2717
54639
+ process.stdout.write(chalk30.red(`\u2717
53753
54640
  `));
53754
- console.error(chalk29.red(` Failed to export agent ${id}: ${msg}`));
54641
+ console.error(chalk30.red(` Failed to export agent ${id}: ${msg}`));
53755
54642
  if (err instanceof ApiError && err.statusCode === 404) {
53756
- console.error(chalk29.yellow(" The export-runtime feature may not be enabled on your account or environment."));
53757
- console.error(chalk29.gray(" If you have your own environment, try: RUNTYPE_API_URL={API Base URI} runtype deploy ..."));
54643
+ console.error(chalk30.yellow(" The export-runtime feature may not be enabled on your account or environment."));
54644
+ console.error(chalk30.gray(" If you have your own environment, try: RUNTYPE_API_URL={API Base URI} runtype deploy ..."));
53758
54645
  }
53759
54646
  process.exit(1);
53760
54647
  }
53761
54648
  }
53762
54649
  for (const id of flowIds) {
53763
- process.stdout.write(` Exporting flow ${chalk29.green(id)}... `);
54650
+ process.stdout.write(` Exporting flow ${chalk30.green(id)}... `);
53764
54651
  try {
53765
54652
  const def = await client.get(`/flows/${id}/export-runtime`);
53766
54653
  const wrappedName = String(def.name ?? id);
@@ -53776,49 +54663,39 @@ Scaffolding deployment to ${outDir}
53776
54663
  primaryFlow: def
53777
54664
  }
53778
54665
  });
53779
- process.stdout.write(chalk29.green("\u2713\n"));
54666
+ process.stdout.write(chalk30.green("\u2713\n"));
53780
54667
  } catch (err) {
53781
54668
  const msg = err instanceof ApiError ? err.message : String(err);
53782
- process.stdout.write(chalk29.red(`\u2717
54669
+ process.stdout.write(chalk30.red(`\u2717
53783
54670
  `));
53784
- console.error(chalk29.red(` Failed to export flow ${id}: ${msg}`));
54671
+ console.error(chalk30.red(` Failed to export flow ${id}: ${msg}`));
53785
54672
  if (err instanceof ApiError && err.statusCode === 404) {
53786
- console.error(chalk29.yellow(" The export-runtime feature may not be enabled on your account or environment."));
53787
- console.error(chalk29.gray(" If you have your own environment, try: RUNTYPE_API_URL={API Base URI} runtype deploy ..."));
54673
+ console.error(chalk30.yellow(" The export-runtime feature may not be enabled on your account or environment."));
54674
+ console.error(chalk30.gray(" If you have your own environment, try: RUNTYPE_API_URL={API Base URI} runtype deploy ..."));
53788
54675
  }
53789
54676
  process.exit(1);
53790
54677
  }
53791
54678
  }
54679
+ const agentSlugs = agentDefs.map(({ name }) => slugify2(name));
54680
+ const slugSet = /* @__PURE__ */ new Set();
54681
+ for (let i = 0; i < agentSlugs.length; i++) {
54682
+ const slug = agentSlugs[i];
54683
+ if (slugSet.has(slug)) {
54684
+ const colliders = agentDefs.filter(({ name }) => slugify2(name) === slug).map(({ name }) => `"${name}"`).join(" and ");
54685
+ console.error(chalk30.red(`Error: agents ${colliders} produce the same slug "${slug}".`));
54686
+ console.error(chalk30.yellow(" Rename one of them in the Runtype dashboard to make slugs unique."));
54687
+ process.exit(1);
54688
+ }
54689
+ slugSet.add(slug);
54690
+ }
53792
54691
  fs14.mkdirSync(path14.join(outDir, "agents"), { recursive: true });
53793
54692
  fs14.mkdirSync(path14.join(outDir, "packages"), { recursive: true });
53794
54693
  for (const { name, def } of agentDefs) {
53795
54694
  const filename = `${slugify2(name)}.json`;
53796
- fs14.writeFileSync(
53797
- path14.join(outDir, "agents", filename),
53798
- JSON.stringify(def, null, 2)
53799
- );
54695
+ fs14.writeFileSync(path14.join(outDir, "agents", filename), JSON.stringify(def, null, 2));
53800
54696
  console.log(` Wrote agents/${filename}`);
53801
54697
  }
53802
- fs14.writeFileSync(
53803
- path14.join(outDir, "server.ts"),
53804
- serverTs()
53805
- );
53806
- fs14.writeFileSync(
53807
- path14.join(outDir, "Dockerfile"),
53808
- dockerfile()
53809
- );
53810
- fs14.writeFileSync(
53811
- path14.join(outDir, ".dockerignore"),
53812
- dockerignore()
53813
- );
53814
- fs14.writeFileSync(
53815
- path14.join(outDir, "tsconfig.json"),
53816
- tsconfigJson()
53817
- );
53818
- fs14.writeFileSync(
53819
- path14.join(outDir, "package.json"),
53820
- packageJson(projectName, "workspace:*")
53821
- );
54698
+ const agentNames = agentDefs.map((a) => a.name);
53822
54699
  let monorepoRoot = process.cwd();
53823
54700
  for (let i = 0; i < 8; i++) {
53824
54701
  if (fs14.existsSync(path14.join(monorepoRoot, "pnpm-workspace.yaml"))) break;
@@ -53826,46 +54703,90 @@ Scaffolding deployment to ${outDir}
53826
54703
  if (parent === monorepoRoot) break;
53827
54704
  monorepoRoot = parent;
53828
54705
  }
53829
- const setupScript = setupSh(monorepoRoot);
53830
- const setupPath = path14.join(outDir, "setup.sh");
53831
- fs14.writeFileSync(setupPath, setupScript);
53832
- fs14.chmodSync(setupPath, 493);
53833
54706
  const allSecrets = /* @__PURE__ */ new Set();
53834
54707
  for (const { def } of agentDefs) {
53835
54708
  for (const s of collectSecretNames(def)) allSecrets.add(s);
53836
54709
  }
53837
54710
  const secretNames = Array.from(allSecrets);
53838
- fs14.writeFileSync(
53839
- path14.join(outDir, "README.md"),
53840
- readme(
53841
- agentDefs.map((a) => a.name),
53842
- secretNames
53843
- )
53844
- );
54711
+ if (target === "cloudflare") {
54712
+ fs14.mkdirSync(path14.join(outDir, "src"), { recursive: true });
54713
+ fs14.writeFileSync(path14.join(outDir, "src", "index.ts"), workerIndexTs(agentSlugs));
54714
+ fs14.writeFileSync(path14.join(outDir, "wrangler.toml"), wranglerToml(projectName));
54715
+ fs14.writeFileSync(path14.join(outDir, "package.json"), workerPackageJson(projectName, "workspace:*"));
54716
+ fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), workerTsconfigJson());
54717
+ const setupPath = path14.join(outDir, "setup.sh");
54718
+ fs14.writeFileSync(setupPath, workerSetupSh(monorepoRoot));
54719
+ fs14.chmodSync(setupPath, 493);
54720
+ fs14.writeFileSync(path14.join(outDir, "README.md"), workerReadme(agentNames, secretNames));
54721
+ } else if (target === "vercel") {
54722
+ fs14.mkdirSync(path14.join(outDir, "api"), { recursive: true });
54723
+ fs14.writeFileSync(path14.join(outDir, "api", "[[...route]].ts"), vercelRouteTs(agentSlugs));
54724
+ fs14.writeFileSync(path14.join(outDir, "vercel.json"), vercelJson());
54725
+ fs14.writeFileSync(path14.join(outDir, "package.json"), vercelPackageJson(projectName, "workspace:*"));
54726
+ fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), vercelTsconfigJson());
54727
+ const setupPath = path14.join(outDir, "setup.sh");
54728
+ fs14.writeFileSync(setupPath, vercelSetupSh(monorepoRoot));
54729
+ fs14.chmodSync(setupPath, 493);
54730
+ fs14.writeFileSync(path14.join(outDir, "README.md"), vercelReadme(agentNames, secretNames));
54731
+ } else {
54732
+ fs14.writeFileSync(path14.join(outDir, "server.ts"), serverTs());
54733
+ fs14.writeFileSync(path14.join(outDir, "Dockerfile"), dockerfile());
54734
+ fs14.writeFileSync(path14.join(outDir, ".dockerignore"), dockerignore());
54735
+ fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), tsconfigJson());
54736
+ fs14.writeFileSync(path14.join(outDir, "package.json"), packageJson(projectName, "workspace:*"));
54737
+ const setupPath = path14.join(outDir, "setup.sh");
54738
+ fs14.writeFileSync(setupPath, setupSh(monorepoRoot));
54739
+ fs14.chmodSync(setupPath, 493);
54740
+ fs14.writeFileSync(path14.join(outDir, "README.md"), readme(agentNames, secretNames));
54741
+ }
53845
54742
  console.log("");
53846
- console.log(chalk29.green(`\u2713 Scaffold written to ${outDir}`));
54743
+ console.log(chalk30.green(`\u2713 Scaffold written to ${outDir}`));
53847
54744
  console.log("");
53848
- console.log(chalk29.bold("Next steps:"));
54745
+ console.log(chalk30.bold("Next steps:"));
53849
54746
  console.log(` cd ${options.output}`);
53850
54747
  console.log(" chmod +x setup.sh && ./setup.sh # pack runtime + install deps");
53851
- console.log(" npm run dev # test locally");
53852
- console.log("");
53853
- if (secretNames.length > 0) {
53854
- console.log(chalk29.yellow("Required secrets (set before deploying):"));
53855
- for (const s of secretNames) {
53856
- console.log(` ${chalk29.cyan(s)}`);
54748
+ if (target === "cloudflare") {
54749
+ console.log(" wrangler dev # test locally");
54750
+ console.log("");
54751
+ if (secretNames.length > 0) {
54752
+ console.log(chalk30.yellow("Required secrets (set via wrangler):"));
54753
+ for (const s of secretNames) {
54754
+ console.log(` wrangler secret put ${chalk30.cyan(s)}`);
54755
+ }
54756
+ console.log("");
53857
54757
  }
54758
+ console.log("Deploy to Cloudflare Workers:");
54759
+ console.log(" wrangler deploy");
54760
+ } else if (target === "vercel") {
54761
+ console.log(" vercel dev # test locally");
53858
54762
  console.log("");
53859
- console.log(" Set via Cloud Run: gcloud run deploy \u2026 --set-secrets KEY=NAME:latest");
53860
- console.log(" Or export locally: export KEY=<value>");
54763
+ if (secretNames.length > 0) {
54764
+ console.log(chalk30.yellow("Required secrets (set via Vercel):"));
54765
+ for (const s of secretNames) {
54766
+ console.log(` vercel env add ${chalk30.cyan(s)}`);
54767
+ }
54768
+ console.log("");
54769
+ }
54770
+ console.log("Deploy to Vercel Functions:");
54771
+ console.log(" vercel deploy");
54772
+ } else {
54773
+ console.log(" npm run dev # test locally");
53861
54774
  console.log("");
54775
+ if (secretNames.length > 0) {
54776
+ console.log(chalk30.yellow("Required secrets (set before deploying):"));
54777
+ for (const s of secretNames) {
54778
+ console.log(` ${chalk30.cyan(s)}`);
54779
+ }
54780
+ console.log("");
54781
+ console.log(" Set via Cloud Run: gcloud run deploy \u2026 --set-secrets KEY=NAME:latest");
54782
+ console.log(" Or export locally: export KEY=<value>");
54783
+ console.log("");
54784
+ }
54785
+ console.log("Deploy to Cloud Run:");
54786
+ console.log(` gcloud run deploy ${projectName} --source ${options.output} \\`);
54787
+ console.log(" --region us-central1 --platform managed \\");
54788
+ console.log(" --allow-unauthenticated --port 8080");
53862
54789
  }
53863
- console.log("Deploy to Cloud Run:");
53864
- console.log(
53865
- ` gcloud run deploy ${projectName} --source ${options.output} \\`
53866
- );
53867
- console.log(" --region us-central1 --platform managed \\");
53868
- console.log(" --allow-unauthenticated --port 8080");
53869
54790
  }
53870
54791
  );
53871
54792
 
@@ -53873,7 +54794,7 @@ Scaffolding deployment to ${outDir}
53873
54794
  init_credential_store();
53874
54795
 
53875
54796
  // src/lib/update-check.ts
53876
- import chalk30 from "chalk";
54797
+ import chalk31 from "chalk";
53877
54798
  import Conf3 from "conf";
53878
54799
  var UPDATE_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1e3;
53879
54800
  var UPDATE_NOTIFY_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -53967,7 +54888,7 @@ function notifyFromCachedCliUpdate(args, options = {}) {
53967
54888
  console.error(message);
53968
54889
  });
53969
54890
  notify(
53970
- `${chalk30.yellow("Update available:")} ${chalk30.red(currentVersion)} ${chalk30.gray("->")} ${chalk30.green(latestVersion)} ${chalk30.gray(`(${getUpgradeCommand()})`)}`
54891
+ `${chalk31.yellow("Update available:")} ${chalk31.red(currentVersion)} ${chalk31.gray("->")} ${chalk31.green(latestVersion)} ${chalk31.gray(`(${getUpgradeCommand()})`)}`
53971
54892
  );
53972
54893
  store.set("lastNotifiedAt", now.toISOString());
53973
54894
  store.set("lastNotifiedVersion", latestVersion);
@@ -54009,7 +54930,7 @@ function maybeNotifyAboutCliUpdate(args, options = {}) {
54009
54930
  // src/index.ts
54010
54931
  loadEnv();
54011
54932
  setCliTitle();
54012
- var program = new Command24();
54933
+ var program = new Command25();
54013
54934
  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");
54014
54935
  program.addCommand(initCommand);
54015
54936
  program.addCommand(loginCommand);
@@ -54031,6 +54952,7 @@ program.addCommand(personaCommand);
54031
54952
  program.addCommand(analyticsCommand);
54032
54953
  program.addCommand(billingCommand);
54033
54954
  program.addCommand(flowVersionsCommand);
54955
+ program.addCommand(agentVersionsCommand);
54034
54956
  program.addCommand(createMarathonCommand());
54035
54957
  program.addCommand(tailCommand);
54036
54958
  program.addCommand(validateProductCommand);
@@ -54048,15 +54970,15 @@ try {
54048
54970
  } catch (error51) {
54049
54971
  const commanderError = error51;
54050
54972
  if (commanderError.code === "commander.missingArgument") {
54051
- console.error(chalk31.red(`Error: ${commanderError.message}`));
54973
+ console.error(chalk32.red(`Error: ${commanderError.message}`));
54052
54974
  process.exit(1);
54053
54975
  } else if (commanderError.code === "commander.unknownOption") {
54054
- console.error(chalk31.red(`Error: ${commanderError.message}`));
54976
+ console.error(chalk32.red(`Error: ${commanderError.message}`));
54055
54977
  process.exit(1);
54056
54978
  } else if (commanderError.code === "commander.help" || commanderError.code === "commander.version") {
54057
54979
  process.exit(0);
54058
54980
  } else {
54059
- console.error(chalk31.red("An unexpected error occurred:"));
54981
+ console.error(chalk32.red("An unexpected error occurred:"));
54060
54982
  console.error(error51);
54061
54983
  process.exit(1);
54062
54984
  }
@@ -54065,12 +54987,12 @@ async function handleNoCommand() {
54065
54987
  const store = new CredentialStore();
54066
54988
  const hasCredentials = await store.hasCredentials();
54067
54989
  if (!hasCredentials) {
54068
- console.log(chalk31.cyan("\nWelcome to Runtype CLI!\n"));
54990
+ console.log(chalk32.cyan("\nWelcome to Runtype CLI!\n"));
54069
54991
  console.log("It looks like this is your first time. Run the setup wizard:");
54070
- console.log(` ${chalk31.green("runtype init")}
54992
+ console.log(` ${chalk32.green("runtype init")}
54071
54993
  `);
54072
54994
  console.log("Or see all available commands:");
54073
- console.log(` ${chalk31.green("runtype --help")}
54995
+ console.log(` ${chalk32.green("runtype --help")}
54074
54996
  `);
54075
54997
  } else {
54076
54998
  try {