@runtypelabs/cli 2.12.8 → 2.14.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 +1224 -174
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -131,15 +131,15 @@ var init_credential_store = __esm({
131
131
  });
132
132
 
133
133
  // src/index.ts
134
- import { Command as Command23 } from "commander";
135
- import chalk30 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";
139
139
  import { resolve } from "path";
140
- function loadEnv(path14 = resolve(process.cwd(), ".env")) {
140
+ function loadEnv(path15 = resolve(process.cwd(), ".env")) {
141
141
  try {
142
- const content = readFileSync(path14, "utf8").replace(/\r\n?/g, "\n");
142
+ const content = readFileSync(path15, "utf8").replace(/\r\n?/g, "\n");
143
143
  for (const line of content.split("\n")) {
144
144
  if (!line.trim() || line.trimStart().startsWith("#")) continue;
145
145
  const match = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/);
@@ -174,8 +174,8 @@ var CallbackServer = class {
174
174
  expectedState;
175
175
  constructor() {
176
176
  this.app = express();
177
- this.codePromise = new Promise((resolve9, reject) => {
178
- this.codeResolve = resolve9;
177
+ this.codePromise = new Promise((resolve10, reject) => {
178
+ this.codeResolve = resolve10;
179
179
  this.codeReject = reject;
180
180
  });
181
181
  this.app.get("/callback", (req, res) => {
@@ -1304,10 +1304,10 @@ function mergeDefs(...defs) {
1304
1304
  function cloneDef(schema) {
1305
1305
  return mergeDefs(schema._zod.def);
1306
1306
  }
1307
- function getElementAtPath(obj, path14) {
1308
- if (!path14)
1307
+ function getElementAtPath(obj, path15) {
1308
+ if (!path15)
1309
1309
  return obj;
1310
- return path14.reduce((acc, key) => acc?.[key], obj);
1310
+ return path15.reduce((acc, key) => acc?.[key], obj);
1311
1311
  }
1312
1312
  function promiseAllObject(promisesObj) {
1313
1313
  const keys = Object.keys(promisesObj);
@@ -1716,11 +1716,11 @@ function explicitlyAborted(x, startIndex = 0) {
1716
1716
  }
1717
1717
  return false;
1718
1718
  }
1719
- function prefixIssues(path14, issues) {
1719
+ function prefixIssues(path15, issues) {
1720
1720
  return issues.map((iss) => {
1721
1721
  var _a3;
1722
1722
  (_a3 = iss).path ?? (_a3.path = []);
1723
- iss.path.unshift(path14);
1723
+ iss.path.unshift(path15);
1724
1724
  return iss;
1725
1725
  });
1726
1726
  }
@@ -1867,16 +1867,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1867
1867
  }
1868
1868
  function formatError(error51, mapper = (issue2) => issue2.message) {
1869
1869
  const fieldErrors = { _errors: [] };
1870
- const processError = (error52, path14 = []) => {
1870
+ const processError = (error52, path15 = []) => {
1871
1871
  for (const issue2 of error52.issues) {
1872
1872
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1873
- issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
1873
+ issue2.errors.map((issues) => processError({ issues }, [...path15, ...issue2.path]));
1874
1874
  } else if (issue2.code === "invalid_key") {
1875
- processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1875
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
1876
1876
  } else if (issue2.code === "invalid_element") {
1877
- processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1877
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
1878
1878
  } else {
1879
- const fullpath = [...path14, ...issue2.path];
1879
+ const fullpath = [...path15, ...issue2.path];
1880
1880
  if (fullpath.length === 0) {
1881
1881
  fieldErrors._errors.push(mapper(issue2));
1882
1882
  } else {
@@ -1903,17 +1903,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1903
1903
  }
1904
1904
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1905
1905
  const result = { errors: [] };
1906
- const processError = (error52, path14 = []) => {
1906
+ const processError = (error52, path15 = []) => {
1907
1907
  var _a3, _b;
1908
1908
  for (const issue2 of error52.issues) {
1909
1909
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1910
- issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
1910
+ issue2.errors.map((issues) => processError({ issues }, [...path15, ...issue2.path]));
1911
1911
  } else if (issue2.code === "invalid_key") {
1912
- processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1912
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
1913
1913
  } else if (issue2.code === "invalid_element") {
1914
- processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1914
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
1915
1915
  } else {
1916
- const fullpath = [...path14, ...issue2.path];
1916
+ const fullpath = [...path15, ...issue2.path];
1917
1917
  if (fullpath.length === 0) {
1918
1918
  result.errors.push(mapper(issue2));
1919
1919
  continue;
@@ -1945,8 +1945,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1945
1945
  }
1946
1946
  function toDotPath(_path) {
1947
1947
  const segs = [];
1948
- const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1949
- for (const seg of path14) {
1948
+ const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1949
+ for (const seg of path15) {
1950
1950
  if (typeof seg === "number")
1951
1951
  segs.push(`[${seg}]`);
1952
1952
  else if (typeof seg === "symbol")
@@ -14632,13 +14632,13 @@ function resolveRef(ref, ctx) {
14632
14632
  if (!ref.startsWith("#")) {
14633
14633
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14634
14634
  }
14635
- const path14 = ref.slice(1).split("/").filter(Boolean);
14636
- if (path14.length === 0) {
14635
+ const path15 = ref.slice(1).split("/").filter(Boolean);
14636
+ if (path15.length === 0) {
14637
14637
  return ctx.rootSchema;
14638
14638
  }
14639
14639
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14640
- if (path14[0] === defsKey) {
14641
- const key = path14[1];
14640
+ if (path15[0] === defsKey) {
14641
+ const key = path15[1];
14642
14642
  if (!key || !ctx.defs[key]) {
14643
14643
  throw new Error(`Reference not found: ${ref}`);
14644
14644
  }
@@ -15423,6 +15423,97 @@ var CONTEXT_STEP_TYPES = [
15423
15423
  "generate-pdf"
15424
15424
  ];
15425
15425
  var FLOW_STEP_TYPES = ["prompt", ...CONTEXT_STEP_TYPES];
15426
+ var PROVIDER_SECRET_SPECS = [
15427
+ // ----- Explicit-prefix providers -----
15428
+ {
15429
+ providerId: "google-vertex-anthropic",
15430
+ // Must come before google-vertex (shares vertex prefix) and anthropic (matches */claude-*).
15431
+ matches: (m) => m.startsWith("vertex-anthropic/"),
15432
+ secretNames: ["GOOGLE_VERTEX_PROJECT", "GOOGLE_VERTEX_LOCATION", "GOOGLE_VERTEX_CREDENTIALS"]
15433
+ },
15434
+ {
15435
+ providerId: "google-vertex",
15436
+ // Must come before google (matches */gemini-*).
15437
+ matches: (m) => m.startsWith("vertex/"),
15438
+ secretNames: ["GOOGLE_VERTEX_PROJECT", "GOOGLE_VERTEX_LOCATION", "GOOGLE_VERTEX_CREDENTIALS"]
15439
+ },
15440
+ {
15441
+ providerId: "vercel-gateway",
15442
+ // Must come before openai — vercel/openai/gpt-4o would otherwise match openai.
15443
+ matches: (m) => m.startsWith("vercel/") || m.startsWith("vercel."),
15444
+ secretNames: ["VERCEL_AI_GATEWAY_API_KEY"]
15445
+ },
15446
+ {
15447
+ providerId: "cloudflare-gateway",
15448
+ // Must come before workers-ai — cloudflare/<provider>/<model> needs gateway routing.
15449
+ matches: (m) => m.startsWith("cloudflare/") || m.startsWith("cloudflare:"),
15450
+ secretNames: ["CF_ACCOUNT_ID", "CF_AI_GATEWAY_ID"]
15451
+ },
15452
+ {
15453
+ providerId: "bedrock",
15454
+ matches: (m) => m.startsWith("bedrock/"),
15455
+ secretNames: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"]
15456
+ },
15457
+ {
15458
+ providerId: "tinfoil",
15459
+ matches: (m) => m.startsWith("tinfoil/") || m.startsWith("tinfoil:"),
15460
+ secretNames: ["TINFOIL_API_KEY"]
15461
+ },
15462
+ {
15463
+ providerId: "generic-openai",
15464
+ // Must come before openai — shares the openai substring in its prefix.
15465
+ matches: (m) => m.startsWith("generic-openai/") || m.startsWith("generic-openai:"),
15466
+ secretNames: ["GENERIC_OPENAI_API_KEY", "GENERIC_OPENAI_BASE_URL"]
15467
+ },
15468
+ {
15469
+ providerId: "workers-ai",
15470
+ // Uses a CF platform binding, not a secret — secretNames is intentionally empty.
15471
+ matches: (m) => m.startsWith("@cf/") || m.startsWith("workers-ai/"),
15472
+ secretNames: []
15473
+ },
15474
+ {
15475
+ providerId: "togetherai",
15476
+ matches: (m) => m.startsWith("together/") || m.startsWith("togetherai/"),
15477
+ secretNames: ["TOGETHER_API_KEY"]
15478
+ },
15479
+ // ----- Base providers (broader patterns — must come last) -----
15480
+ {
15481
+ providerId: "anthropic",
15482
+ matches: (m) => m.startsWith("anthropic/") || m.startsWith("claude-") || m.includes("/claude-"),
15483
+ secretNames: ["ANTHROPIC_API_KEY"]
15484
+ },
15485
+ {
15486
+ providerId: "openai",
15487
+ matches: (m) => m.startsWith("openai/") || m.startsWith("gpt-") || m.startsWith("o1-") || m.startsWith("o3-") || m.startsWith("o4-") || m.includes("/gpt-"),
15488
+ secretNames: ["OPENAI_API_KEY"]
15489
+ },
15490
+ {
15491
+ providerId: "google",
15492
+ matches: (m) => m.startsWith("google/") || m.startsWith("gemini-") || m.includes("/gemini-"),
15493
+ secretNames: ["GOOGLE_API_KEY"]
15494
+ },
15495
+ {
15496
+ providerId: "mixlayer",
15497
+ // Matches open-weight models Mixlayer hosts (Qwen 3.5 family, Kimi) plus
15498
+ // explicit prefixes. Does NOT match closed Alibaba models (qwen3.5-flash/plus)
15499
+ // which route through Vercel Gateway. See mixlayer-executor.ts for the
15500
+ // canonical predicate mirrored here.
15501
+ matches: (m) => m.startsWith("mixlayer/") || m.startsWith("modelsocket/") || m.startsWith("qwen/") || m.startsWith("kimi-") || m.includes("/kimi-") || /(?:^|\/)qwen3[.-]5-\d+b(?:-a\d+b)?$/i.test(m),
15502
+ secretNames: ["MIXLAYER_API_KEY"]
15503
+ },
15504
+ {
15505
+ providerId: "xai",
15506
+ matches: (m) => m.startsWith("grok-") || m.startsWith("xai/"),
15507
+ secretNames: ["XAI_API_KEY"]
15508
+ }
15509
+ ];
15510
+ function resolveModelSecretNames(model) {
15511
+ const lower = model.toLowerCase();
15512
+ for (const spec of PROVIDER_SECRET_SPECS) {
15513
+ if (spec.matches(lower)) return [...spec.secretNames];
15514
+ }
15515
+ return [];
15516
+ }
15426
15517
  var MCPServerCategory = {
15427
15518
  COMMUNICATION: "communication",
15428
15519
  PRODUCTIVITY: "productivity",
@@ -30326,12 +30417,162 @@ var TELEGRAM_INTEGRATION = {
30326
30417
  }
30327
30418
  ]
30328
30419
  };
30420
+ var IMESSAGE_INTEGRATION = {
30421
+ id: "imessage",
30422
+ name: "iMessage",
30423
+ description: "Send iMessage / SMS messages, read conversation history, and react to messages via Sendblue.",
30424
+ transport: "http",
30425
+ url: "",
30426
+ // Credentials live on the iMessage productSurface, not in
30427
+ // organization_integrations. The handler reads them on-demand.
30428
+ requiredCredentials: [],
30429
+ category: MCPServerCategory.COMMUNICATION,
30430
+ documentationUrl: "https://docs.sendblue.com/",
30431
+ icon: "message",
30432
+ // A single agent can register multiple iMessage tool instances pinned to
30433
+ // different surfaces (i.e. different phone numbers) via
30434
+ // `toolConfig.surfaceId`.
30435
+ multiInstance: true,
30436
+ tools: [
30437
+ {
30438
+ name: "send_message",
30439
+ description: "Send an iMessage to a phone number. Falls back to SMS automatically when the recipient is not on iMessage (was_downgraded). Long messages are bubble-split.",
30440
+ parametersSchema: {
30441
+ type: "object",
30442
+ properties: {
30443
+ to: {
30444
+ type: "string",
30445
+ description: "Recipient phone number in E.164 format (e.g. +14155550100)."
30446
+ },
30447
+ text: {
30448
+ type: "string",
30449
+ description: "Message text to send. Markdown is converted to plain iMessage formatting."
30450
+ },
30451
+ // @snake-case-ok: tool input fields use snake_case for LLM ergonomics
30452
+ media_url: {
30453
+ type: "string",
30454
+ description: "Optional public URL of an image/video attachment."
30455
+ }
30456
+ },
30457
+ required: ["to", "text"]
30458
+ }
30459
+ },
30460
+ {
30461
+ name: "send_group_message",
30462
+ description: "Send a message to an iMessage group chat. Provide either group_id (preferred \u2014 preserves the existing thread) or a numbers array (creates an ad-hoc group).",
30463
+ parametersSchema: {
30464
+ type: "object",
30465
+ properties: {
30466
+ // @snake-case-ok-start: Sendblue API uses snake_case for group identifiers
30467
+ group_id: {
30468
+ type: "string",
30469
+ description: "Sendblue group identifier. Required for replying to an existing group; obtain via list_conversations or get_group_info."
30470
+ },
30471
+ numbers: {
30472
+ type: "array",
30473
+ description: "Recipient phone numbers in E.164 format. Used when group_id is not yet known (creates an ad-hoc group). Ignored when group_id is set.",
30474
+ items: { type: "string" }
30475
+ },
30476
+ text: { type: "string", description: "Message text to send." },
30477
+ media_url: {
30478
+ type: "string",
30479
+ description: "Optional public URL of an image/video attachment."
30480
+ }
30481
+ // @snake-case-ok-end
30482
+ },
30483
+ required: ["text"]
30484
+ }
30485
+ },
30486
+ {
30487
+ name: "list_conversations",
30488
+ description: "List recent iMessage conversations (1:1 and group) the bot has participated in, ordered by most recent activity.",
30489
+ parametersSchema: {
30490
+ type: "object",
30491
+ properties: {
30492
+ limit: {
30493
+ type: "number",
30494
+ description: "Maximum number of conversations to return (default 25, max 100).",
30495
+ minimum: 1,
30496
+ maximum: 100
30497
+ },
30498
+ before: {
30499
+ type: "string",
30500
+ description: "ISO 8601 timestamp; only return conversations whose lastMessageAt is earlier."
30501
+ }
30502
+ },
30503
+ required: []
30504
+ }
30505
+ },
30506
+ {
30507
+ name: "get_conversation_history",
30508
+ description: "Read the recent message history of an iMessage conversation. Useful for catching up on context before replying.",
30509
+ parametersSchema: {
30510
+ type: "object",
30511
+ properties: {
30512
+ // @snake-case-ok: tool input fields use snake_case for LLM ergonomics
30513
+ conversation_id: {
30514
+ type: "string",
30515
+ description: "Runtype messaging conversation ID (returned by list_conversations)."
30516
+ },
30517
+ limit: {
30518
+ type: "number",
30519
+ description: "Maximum number of messages to return (default 50, max 200).",
30520
+ minimum: 1,
30521
+ maximum: 200
30522
+ },
30523
+ before: {
30524
+ type: "string",
30525
+ description: "ISO 8601 timestamp; only return messages created before this."
30526
+ }
30527
+ },
30528
+ required: ["conversation_id"]
30529
+ }
30530
+ },
30531
+ {
30532
+ name: "get_group_info",
30533
+ description: "Look up display name and participant phone numbers for an iMessage group, sourced from the most recent inbound webhook for that group.",
30534
+ parametersSchema: {
30535
+ type: "object",
30536
+ properties: {
30537
+ // @snake-case-ok: tool input fields use snake_case for LLM ergonomics
30538
+ group_id: {
30539
+ type: "string",
30540
+ description: "Sendblue group identifier."
30541
+ }
30542
+ },
30543
+ required: ["group_id"]
30544
+ }
30545
+ },
30546
+ {
30547
+ name: "send_reaction",
30548
+ description: "Send a tapback reaction (\u{1F44D} \u2764\uFE0F \u{1F602} \u203C\uFE0F \u2753 \u{1F44E}) to a previous iMessage. iMessage-only \u2014 has no effect on SMS recipients.",
30549
+ parametersSchema: {
30550
+ type: "object",
30551
+ properties: {
30552
+ // @snake-case-ok-start: Sendblue API uses snake_case for message identifiers
30553
+ message_handle: {
30554
+ type: "string",
30555
+ description: "The Sendblue message_handle of the message you are reacting to (from inbound webhooks or earlier outbound responses)."
30556
+ },
30557
+ reaction: {
30558
+ type: "string",
30559
+ enum: ["love", "like", "dislike", "laugh", "emphasize", "question"],
30560
+ description: "Tapback type. love=\u2764\uFE0F, like=\u{1F44D}, dislike=\u{1F44E}, laugh=\u{1F602}, emphasize=\u203C\uFE0F, question=\u2753."
30561
+ }
30562
+ // @snake-case-ok-end
30563
+ },
30564
+ required: ["message_handle", "reaction"]
30565
+ }
30566
+ }
30567
+ ]
30568
+ };
30329
30569
  var INTEGRATIONS_REGISTRY = [
30330
30570
  SLACK_INTEGRATION,
30331
30571
  GOOGLE_INTEGRATION,
30332
30572
  LINEAR_INTEGRATION,
30333
30573
  GITHUB_INTEGRATION,
30334
- TELEGRAM_INTEGRATION
30574
+ TELEGRAM_INTEGRATION,
30575
+ IMESSAGE_INTEGRATION
30335
30576
  ];
30336
30577
  function getAllIntegrations() {
30337
30578
  return INTEGRATIONS_REGISTRY;
@@ -32417,6 +32658,38 @@ var SLACK_MANIFEST_BOT_SCOPES = [
32417
32658
  ...SLACK_REQUIRED_BOT_SCOPES,
32418
32659
  ...SLACK_OPTIONAL_BOT_SCOPES
32419
32660
  ];
32661
+ var SECRET_REF_PATTERN = /\{\{secret:([A-Z][A-Z0-9_]*[A-Z0-9])\}\}/g;
32662
+ function extractSecretReferences(template) {
32663
+ const keys = /* @__PURE__ */ new Set();
32664
+ let match;
32665
+ const regex = new RegExp(SECRET_REF_PATTERN.source, "g");
32666
+ while ((match = regex.exec(template)) !== null) {
32667
+ const key = match[1];
32668
+ if (key) keys.add(key);
32669
+ }
32670
+ return Array.from(keys);
32671
+ }
32672
+ function extractSecretReferencesFromAnyValue(value, maxDepth = 10) {
32673
+ const keys = /* @__PURE__ */ new Set();
32674
+ walk(value, 0);
32675
+ return Array.from(keys);
32676
+ function walk(v, depth) {
32677
+ if (depth > maxDepth) return;
32678
+ if (typeof v === "string") {
32679
+ for (const key of extractSecretReferences(v)) keys.add(key);
32680
+ return;
32681
+ }
32682
+ if (Array.isArray(v)) {
32683
+ for (const item of v) walk(item, depth + 1);
32684
+ return;
32685
+ }
32686
+ if (v && typeof v === "object") {
32687
+ for (const inner of Object.values(v)) {
32688
+ walk(inner, depth + 1);
32689
+ }
32690
+ }
32691
+ }
32692
+ }
32420
32693
  var FULL_PRODUCT_OBJECT_VERSION_1_0 = "1.0";
32421
32694
  var FULL_PRODUCT_OBJECT_VERSION_1_1 = "1.1";
32422
32695
  var createPolicySchema = external_exports.enum(["create", "skip", "manual"]).optional();
@@ -32679,6 +32952,7 @@ var surfaceSchema = external_exports.object({
32679
32952
  "slack",
32680
32953
  "schedule",
32681
32954
  "sms",
32955
+ "imessage",
32682
32956
  "discord",
32683
32957
  "whatsapp",
32684
32958
  "messaging",
@@ -32832,8 +33106,8 @@ var fullProductObjectSchema = external_exports.object({
32832
33106
  }
32833
33107
  }
32834
33108
  });
32835
- function createIssue(severity, code, message, path14, suggestedFix) {
32836
- return { code, message, path: path14, severity, ...suggestedFix ? { suggestedFix } : {} };
33109
+ function createIssue(severity, code, message, path15, suggestedFix) {
33110
+ return { code, message, path: path15, severity, ...suggestedFix ? { suggestedFix } : {} };
32837
33111
  }
32838
33112
  function emptyResult() {
32839
33113
  return { valid: true, errors: [], warnings: [], recommendations: [] };
@@ -33003,38 +33277,6 @@ function validateCapability(cap, index, context) {
33003
33277
  }
33004
33278
  return mergeResults(result, subResult);
33005
33279
  }
33006
- var SECRET_REF_PATTERN = /\{\{secret:([A-Z][A-Z0-9_]*[A-Z0-9])\}\}/g;
33007
- function extractSecretReferences(template) {
33008
- const keys = /* @__PURE__ */ new Set();
33009
- let match;
33010
- const regex = new RegExp(SECRET_REF_PATTERN.source, "g");
33011
- while ((match = regex.exec(template)) !== null) {
33012
- const key = match[1];
33013
- if (key) keys.add(key);
33014
- }
33015
- return Array.from(keys);
33016
- }
33017
- function extractSecretReferencesFromAnyValue(value, maxDepth = 10) {
33018
- const keys = /* @__PURE__ */ new Set();
33019
- walk(value, 0);
33020
- return Array.from(keys);
33021
- function walk(v, depth) {
33022
- if (depth > maxDepth) return;
33023
- if (typeof v === "string") {
33024
- for (const key of extractSecretReferences(v)) keys.add(key);
33025
- return;
33026
- }
33027
- if (Array.isArray(v)) {
33028
- for (const item of v) walk(item, depth + 1);
33029
- return;
33030
- }
33031
- if (v && typeof v === "object") {
33032
- for (const inner of Object.values(v)) {
33033
- walk(inner, depth + 1);
33034
- }
33035
- }
33036
- }
33037
- }
33038
33280
  function validateToolDefinition(tool, index) {
33039
33281
  const result = emptyResult();
33040
33282
  const base = `tools[${index}]`;
@@ -33113,6 +33355,7 @@ var VALID_SURFACE_TYPES = /* @__PURE__ */ new Set([
33113
33355
  "slack",
33114
33356
  "schedule",
33115
33357
  "sms",
33358
+ "imessage",
33116
33359
  "discord",
33117
33360
  "whatsapp",
33118
33361
  "telegram",
@@ -33448,16 +33691,16 @@ var fullProductObjectTemplateSchema = external_exports.object({
33448
33691
  });
33449
33692
  var FLOW_PREFIX = "flow:";
33450
33693
  var SECRET_PREFIX = "secret:";
33451
- function collectStringLeafPaths(value, path14 = []) {
33694
+ function collectStringLeafPaths(value, path15 = []) {
33452
33695
  if (typeof value === "string") {
33453
- return [{ path: path14, value }];
33696
+ return [{ path: path15, value }];
33454
33697
  }
33455
33698
  if (Array.isArray(value)) {
33456
- return value.flatMap((item, index) => collectStringLeafPaths(item, [...path14, String(index)]));
33699
+ return value.flatMap((item, index) => collectStringLeafPaths(item, [...path15, String(index)]));
33457
33700
  }
33458
33701
  if (value && typeof value === "object") {
33459
33702
  return Object.entries(value).flatMap(
33460
- ([key, nestedValue]) => collectStringLeafPaths(nestedValue, [...path14, key])
33703
+ ([key, nestedValue]) => collectStringLeafPaths(nestedValue, [...path15, key])
33461
33704
  );
33462
33705
  }
33463
33706
  return [];
@@ -33512,8 +33755,8 @@ function getVariableReferences(template) {
33512
33755
  }
33513
33756
  return references;
33514
33757
  }
33515
- function normalizeValidationPath(path14) {
33516
- return path14.map(String).join(".");
33758
+ function normalizeValidationPath(path15) {
33759
+ return path15.map(String).join(".");
33517
33760
  }
33518
33761
  function coerceFPOTemplateVariableValue(variable, rawValue) {
33519
33762
  if (rawValue === void 0 || rawValue === null || rawValue === "") {
@@ -33743,6 +33986,7 @@ var ARCHITECTURE_PREVIEW_SURFACE_TYPES = [
33743
33986
  "email",
33744
33987
  "slack",
33745
33988
  "sms",
33989
+ "imessage",
33746
33990
  "discord",
33747
33991
  "whatsapp",
33748
33992
  "telegram",
@@ -34033,6 +34277,7 @@ var PLATFORM_CATALOG = {
34033
34277
  "slack",
34034
34278
  "schedule",
34035
34279
  "sms",
34280
+ "imessage",
34036
34281
  "discord",
34037
34282
  "whatsapp",
34038
34283
  "messaging",
@@ -34274,6 +34519,39 @@ var SURFACE_TYPE_METADATA = {
34274
34519
  executionHint: "You are responding via SMS. Be extremely brief \u2014 ideally one or two short sentences. Plain text only, no markdown, no lists. Get straight to the point. Do not include reasoning traces or process narration."
34275
34520
  }
34276
34521
  },
34522
+ imessage: {
34523
+ description: "iMessage messaging via Sendblue for Apple ecosystem interactions",
34524
+ useCases: ["customer support", "appointment reminders", "rich messaging", "two-way texting"],
34525
+ examples: ["iMessage support agent", "Appointment reminder bot", "Rich media messaging bot"],
34526
+ traits: {
34527
+ streaming: "none",
34528
+ messagesMutable: false,
34529
+ deliveryModel: "async",
34530
+ mediaSupport: "images",
34531
+ interactiveUI: "none",
34532
+ inboundMediaSupport: true,
34533
+ consumerType: "human",
34534
+ reasoningVisibility: "always_strip",
34535
+ markdownDialect: "none",
34536
+ threadModel: "flat",
34537
+ senderIdentity: "verified",
34538
+ // ~4 short bubbles' worth of headroom. The adapter splits on paragraph
34539
+ // boundaries before sending; this cap signals to the model that long is
34540
+ // wrong without imposing a hard truncate that would clip mid-thought.
34541
+ maxResponseLength: 1200,
34542
+ executionHint: [
34543
+ "You are responding via iMessage. Hard rules:",
34544
+ "- Plain text only. No markdown \u2014 no **bold**, no # headings, no - bullets, no `code`, no > quotes, no fenced code blocks.",
34545
+ "- 1\u20133 sentences per reply, under 300 characters total when possible.",
34546
+ "- Texting tone: conversational, lowercase is fine, contractions welcome.",
34547
+ '- No greetings ("Hi!", "Hey there!") and no closings ("Let me know!", "Hope this helps!").',
34548
+ `- No AI disclaimers ("As an AI...", "I cannot...", "I'd be happy to help").`,
34549
+ "- One emoji max, only when it fits naturally.",
34550
+ "- For multi-part replies, separate logical chunks with a blank line \u2014 each chunk becomes its own bubble.",
34551
+ "- Do not include reasoning traces or process narration."
34552
+ ].join("\n")
34553
+ }
34554
+ },
34277
34555
  discord: {
34278
34556
  description: "Discord bot for community engagement",
34279
34557
  useCases: ["community support", "moderation", "server management"],
@@ -35085,7 +35363,7 @@ function buildDashboardUrl(opts) {
35085
35363
  while (base.endsWith("/")) {
35086
35364
  base = base.slice(0, -1);
35087
35365
  }
35088
- const path14 = opts.path.startsWith("/") ? opts.path : `/${opts.path}`;
35366
+ const path15 = opts.path.startsWith("/") ? opts.path : `/${opts.path}`;
35089
35367
  const params = new URLSearchParams();
35090
35368
  if (isValidAccountId(opts.account)) {
35091
35369
  params.set(ACCOUNT_QUERY_PARAM, opts.account);
@@ -35098,7 +35376,7 @@ function buildDashboardUrl(opts) {
35098
35376
  }
35099
35377
  }
35100
35378
  const qs = params.toString();
35101
- return qs ? `${base}${path14}?${qs}` : `${base}${path14}`;
35379
+ return qs ? `${base}${path15}?${qs}` : `${base}${path15}`;
35102
35380
  }
35103
35381
  function parseAccountId(value) {
35104
35382
  if (!value) return null;
@@ -36147,14 +36425,14 @@ async function promptConfirm(message, options) {
36147
36425
  output: process.stdout,
36148
36426
  terminal: true
36149
36427
  });
36150
- return new Promise((resolve9) => {
36428
+ return new Promise((resolve10) => {
36151
36429
  rl.question(chalk2.cyan(`${message} (${hint}): `), (answer) => {
36152
36430
  rl.close();
36153
36431
  const trimmed = answer.trim().toLowerCase();
36154
36432
  if (trimmed === "") {
36155
- resolve9(defaultYes);
36433
+ resolve10(defaultYes);
36156
36434
  } else {
36157
- resolve9(trimmed === "y" || trimmed === "yes");
36435
+ resolve10(trimmed === "y" || trimmed === "yes");
36158
36436
  }
36159
36437
  });
36160
36438
  });
@@ -36266,9 +36544,9 @@ var ApiClient = class {
36266
36544
  this.baseUrl = baseUrl || getApiUrl();
36267
36545
  }
36268
36546
  /** Prefix path with API version (e.g. /v1) so all requests hit versioned routes. */
36269
- path(path14) {
36547
+ path(path15) {
36270
36548
  const version2 = getApiVersion();
36271
- const p = path14.startsWith("/") ? path14 : `/${path14}`;
36549
+ const p = path15.startsWith("/") ? path15 : `/${path15}`;
36272
36550
  return p.startsWith(`/${version2}/`) ? p : `/${version2}${p}`;
36273
36551
  }
36274
36552
  headers(extra) {
@@ -36301,8 +36579,8 @@ var ApiClient = class {
36301
36579
  }
36302
36580
  return response.json();
36303
36581
  }
36304
- async get(path14, params) {
36305
- const url2 = new URL(this.path(path14), this.baseUrl);
36582
+ async get(path15, params) {
36583
+ const url2 = new URL(this.path(path15), this.baseUrl);
36306
36584
  if (params) {
36307
36585
  for (const [key, value] of Object.entries(params)) {
36308
36586
  if (value !== void 0 && value !== "") {
@@ -36315,32 +36593,32 @@ var ApiClient = class {
36315
36593
  });
36316
36594
  return this.handleResponse(response);
36317
36595
  }
36318
- async post(path14, body) {
36319
- const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
36596
+ async post(path15, body) {
36597
+ const response = await fetch(new URL(this.path(path15), this.baseUrl).toString(), {
36320
36598
  method: "POST",
36321
36599
  headers: this.headers(),
36322
36600
  body: body !== void 0 ? JSON.stringify(body) : void 0
36323
36601
  });
36324
36602
  return this.handleResponse(response);
36325
36603
  }
36326
- async put(path14, body) {
36327
- const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
36604
+ async put(path15, body) {
36605
+ const response = await fetch(new URL(this.path(path15), this.baseUrl).toString(), {
36328
36606
  method: "PUT",
36329
36607
  headers: this.headers(),
36330
36608
  body: body !== void 0 ? JSON.stringify(body) : void 0
36331
36609
  });
36332
36610
  return this.handleResponse(response);
36333
36611
  }
36334
- async patch(path14, body) {
36335
- const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
36612
+ async patch(path15, body) {
36613
+ const response = await fetch(new URL(this.path(path15), this.baseUrl).toString(), {
36336
36614
  method: "PATCH",
36337
36615
  headers: this.headers(),
36338
36616
  body: body !== void 0 ? JSON.stringify(body) : void 0
36339
36617
  });
36340
36618
  return this.handleResponse(response);
36341
36619
  }
36342
- async delete(path14) {
36343
- const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
36620
+ async delete(path15) {
36621
+ const response = await fetch(new URL(this.path(path15), this.baseUrl).toString(), {
36344
36622
  method: "DELETE",
36345
36623
  headers: this.headers()
36346
36624
  });
@@ -36354,8 +36632,8 @@ var ApiClient = class {
36354
36632
  throw new ApiError(response.status, message);
36355
36633
  }
36356
36634
  }
36357
- async stream(path14, body) {
36358
- const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
36635
+ async stream(path15, body) {
36636
+ const response = await fetch(new URL(this.path(path15), this.baseUrl).toString(), {
36359
36637
  method: "POST",
36360
36638
  headers: this.headers({ Accept: "text/event-stream" }),
36361
36639
  body: body !== void 0 ? JSON.stringify(body) : void 0
@@ -43846,8 +44124,8 @@ function MarathonApp({
43846
44124
  setIsTerminalCheckpoint(true);
43847
44125
  isTerminalCheckpointRef.current = true;
43848
44126
  }
43849
- return new Promise((resolve9) => {
43850
- checkpointResolveRef.current = resolve9;
44127
+ return new Promise((resolve10) => {
44128
+ checkpointResolveRef.current = resolve10;
43851
44129
  });
43852
44130
  },
43853
44131
  updateMilestone: (milestone) => {
@@ -45174,16 +45452,16 @@ function MarathonStartupShell({
45174
45452
  latestAppPropsRef.current = marathonAppProps;
45175
45453
  useEffect20(() => {
45176
45454
  if (scene !== "app" || !appReadyResolverRef.current) return;
45177
- const resolve9 = appReadyResolverRef.current;
45455
+ const resolve10 = appReadyResolverRef.current;
45178
45456
  appReadyResolverRef.current = null;
45179
- resolve9();
45457
+ resolve10();
45180
45458
  }, [scene]);
45181
45459
  const beginTransition = (target) => {
45182
45460
  if (transitionPromiseRef.current) return transitionPromiseRef.current;
45183
45461
  if (target === "app" && !latestAppPropsRef.current) {
45184
45462
  throw new Error("Cannot complete startup before marathon app props are ready.");
45185
45463
  }
45186
- const promise2 = new Promise((resolve9) => {
45464
+ const promise2 = new Promise((resolve10) => {
45187
45465
  globalThis.setTimeout(() => {
45188
45466
  setPrompt(null);
45189
45467
  setModelChoices(null);
@@ -45204,12 +45482,12 @@ function MarathonStartupShell({
45204
45482
  if (target === "app") {
45205
45483
  appReadyResolverRef.current = () => {
45206
45484
  transitionPromiseRef.current = null;
45207
- resolve9();
45485
+ resolve10();
45208
45486
  };
45209
45487
  } else {
45210
45488
  dismissResolverRef.current = () => {
45211
45489
  transitionPromiseRef.current = null;
45212
- resolve9();
45490
+ resolve10();
45213
45491
  };
45214
45492
  }
45215
45493
  }, Math.max(0, MIN_HOLD_MS - (Date.now() - mountedAtRef.current)));
@@ -45226,8 +45504,8 @@ function MarathonStartupShell({
45226
45504
  setModelChoices(null);
45227
45505
  setPrompt(nextPrompt);
45228
45506
  setSelectedPromptIndex(0);
45229
- return new Promise((resolve9) => {
45230
- promptResolverRef.current = resolve9;
45507
+ return new Promise((resolve10) => {
45508
+ promptResolverRef.current = resolve10;
45231
45509
  });
45232
45510
  },
45233
45511
  requestModelChoice: async (nextCurrentModel, models) => {
@@ -45235,8 +45513,8 @@ function MarathonStartupShell({
45235
45513
  setPlaybookConfirm(null);
45236
45514
  setCurrentModel(nextCurrentModel);
45237
45515
  setModelChoices(models);
45238
- return new Promise((resolve9) => {
45239
- modelResolverRef.current = resolve9;
45516
+ return new Promise((resolve10) => {
45517
+ modelResolverRef.current = resolve10;
45240
45518
  });
45241
45519
  },
45242
45520
  requestPlaybookModelConfirm: async (playbookName, milestoneModels) => {
@@ -45251,8 +45529,8 @@ function MarathonStartupShell({
45251
45529
  // Default selection is the "Confirm" action (first item after milestones)
45252
45530
  selectedIndex: names.length
45253
45531
  });
45254
- return new Promise((resolve9) => {
45255
- playbookConfirmResolverRef.current = resolve9;
45532
+ return new Promise((resolve10) => {
45533
+ playbookConfirmResolverRef.current = resolve10;
45256
45534
  });
45257
45535
  },
45258
45536
  completeStartup: () => beginTransition("app"),
@@ -45750,7 +46028,7 @@ async function retryOnNetworkError(fn, opts = {}) {
45750
46028
  }
45751
46029
  const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
45752
46030
  opts.onRetry?.(attempt + 1, delay, error51);
45753
- await new Promise((resolve9) => setTimeout(resolve9, delay));
46031
+ await new Promise((resolve10) => setTimeout(resolve10, delay));
45754
46032
  }
45755
46033
  }
45756
46034
  throw lastError;
@@ -46010,14 +46288,14 @@ async function promptNumericSelect(choices, promptLabel) {
46010
46288
  output: process.stdout,
46011
46289
  terminal: true
46012
46290
  });
46013
- return new Promise((resolve9) => {
46291
+ return new Promise((resolve10) => {
46014
46292
  const ask = () => {
46015
46293
  rl.question(chalk14.cyan(`
46016
46294
  ${promptLabel} (1-${choices.length}): `), (answer) => {
46017
46295
  const value = parseInt(answer.trim(), 10);
46018
46296
  if (value >= 1 && value <= choices.length) {
46019
46297
  rl.close();
46020
- resolve9(choices[value - 1].value);
46298
+ resolve10(choices[value - 1].value);
46021
46299
  return;
46022
46300
  }
46023
46301
  console.log(chalk14.red(`Please enter a number between 1 and ${choices.length}.`));
@@ -46045,7 +46323,7 @@ ${message}`));
46045
46323
  const previousRawMode = input.isRaw === true;
46046
46324
  let selectedIndex = 0;
46047
46325
  let renderedLineCount = 0;
46048
- return new Promise((resolve9) => {
46326
+ return new Promise((resolve10) => {
46049
46327
  const renderMenu = () => {
46050
46328
  if (renderedLineCount > 0) {
46051
46329
  clearRenderedLines(output, renderedLineCount);
@@ -46067,7 +46345,7 @@ ${message}`));
46067
46345
  };
46068
46346
  const finish = (value) => {
46069
46347
  cleanup();
46070
- resolve9(value);
46348
+ resolve10(value);
46071
46349
  };
46072
46350
  const onKeypress = (_, key) => {
46073
46351
  if (key.ctrl && key.name === "c") {
@@ -48277,7 +48555,7 @@ async function taskAction(agent, options) {
48277
48555
  waitForUiExit = renderedShell.waitUntilExit;
48278
48556
  rerenderUi = renderedShell.rerender;
48279
48557
  unmountUi = renderedShell.unmount;
48280
- await new Promise((resolve9) => setTimeout(resolve9, 0));
48558
+ await new Promise((resolve10) => setTimeout(resolve10, 0));
48281
48559
  if (!startupShellRef.current) {
48282
48560
  exitAltScreen();
48283
48561
  unmountUi?.();
@@ -48823,7 +49101,7 @@ Saving state... done. Session saved to ${filePath}`);
48823
49101
  waitForUiExit = renderedApp.waitUntilExit;
48824
49102
  unmountUi = renderedApp.unmount;
48825
49103
  }
48826
- await new Promise((resolve9) => setTimeout(resolve9, 0));
49104
+ await new Promise((resolve10) => setTimeout(resolve10, 0));
48827
49105
  const streamActions = streamRef.current;
48828
49106
  if (!streamActions) {
48829
49107
  exitAltScreen();
@@ -48948,7 +49226,7 @@ Saving state... done. Session saved to ${filePath}`);
48948
49226
  };
48949
49227
  if (event.phase === "start") {
48950
49228
  currentActions.startContextCompaction(absoluteEvent);
48951
- await new Promise((resolve9) => setTimeout(resolve9, 0));
49229
+ await new Promise((resolve10) => setTimeout(resolve10, 0));
48952
49230
  return;
48953
49231
  }
48954
49232
  currentActions.finishContextCompaction(absoluteEvent);
@@ -50927,13 +51205,13 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
50927
51205
  await waitUntilExit2();
50928
51206
  return;
50929
51207
  }
50930
- const confirmed = await new Promise((resolve9) => {
51208
+ const confirmed = await new Promise((resolve10) => {
50931
51209
  const { unmount } = render14(
50932
51210
  React14.createElement(ConfirmPrompt, {
50933
51211
  message: `Delete API key ${id}?`,
50934
51212
  defaultValue: false,
50935
51213
  onConfirm: (result) => {
50936
- resolve9(result);
51214
+ resolve10(result);
50937
51215
  unmount();
50938
51216
  }
50939
51217
  })
@@ -51038,8 +51316,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
51038
51316
  const client = new ApiClient(apiKey);
51039
51317
  if (!isTTY(options) || options.json) {
51040
51318
  try {
51041
- const path14 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
51042
- const data = await client.get(path14);
51319
+ const path15 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
51320
+ const data = await client.get(path15);
51043
51321
  printJson(data);
51044
51322
  } catch (error51) {
51045
51323
  const message = error51 instanceof Error ? error51.message : "Unknown error";
@@ -51056,8 +51334,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
51056
51334
  useEffect25(() => {
51057
51335
  const run = async () => {
51058
51336
  try {
51059
- const path14 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
51060
- const data = await client.get(path14);
51337
+ const path15 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
51338
+ const data = await client.get(path15);
51061
51339
  printJson(data);
51062
51340
  setSuccess(true);
51063
51341
  setLoading(false);
@@ -51399,13 +51677,13 @@ clientTokensCommand.command("delete <id>").description("Delete a client token").
51399
51677
  await waitUntilExit2();
51400
51678
  return;
51401
51679
  }
51402
- const confirmed = await new Promise((resolve9) => {
51680
+ const confirmed = await new Promise((resolve10) => {
51403
51681
  const { unmount } = render15(
51404
51682
  React15.createElement(ConfirmPrompt, {
51405
51683
  message: `Delete client token ${id}?`,
51406
51684
  defaultValue: false,
51407
51685
  onConfirm: (result) => {
51408
- resolve9(result);
51686
+ resolve10(result);
51409
51687
  unmount();
51410
51688
  }
51411
51689
  })
@@ -51710,8 +51988,8 @@ function defaultTokenName(agentName) {
51710
51988
  }
51711
51989
  async function promptLine(rl, question, defaultValue) {
51712
51990
  const hint = defaultValue ? chalk23.dim(` (${defaultValue})`) : "";
51713
- const answer = await new Promise((resolve9) => {
51714
- rl.question(`${question}${hint}: `, resolve9);
51991
+ const answer = await new Promise((resolve10) => {
51992
+ rl.question(`${question}${hint}: `, resolve10);
51715
51993
  });
51716
51994
  const trimmed = answer.trim();
51717
51995
  if (!trimmed && defaultValue !== void 0) {
@@ -51721,8 +51999,8 @@ async function promptLine(rl, question, defaultValue) {
51721
51999
  }
51722
52000
  async function promptConfirm2(rl, message, defaultYes = false) {
51723
52001
  const hint = defaultYes ? chalk23.dim(" (Y/n)") : chalk23.dim(" (y/N)");
51724
- const answer = await new Promise((resolve9) => {
51725
- rl.question(`${message}${hint}: `, resolve9);
52002
+ const answer = await new Promise((resolve10) => {
52003
+ rl.question(`${message}${hint}: `, resolve10);
51726
52004
  });
51727
52005
  const t = answer.trim().toLowerCase();
51728
52006
  if (t === "") return defaultYes;
@@ -51791,18 +52069,18 @@ Dashboard: ${initial.dashboardUrl}`));
51791
52069
  process.stdin.removeAllListeners("keypress");
51792
52070
  process.stdin.pause();
51793
52071
  };
51794
- await new Promise((resolve9) => {
52072
+ await new Promise((resolve10) => {
51795
52073
  const onKeypress = async (_str, key) => {
51796
52074
  if (!key) return;
51797
52075
  if (key.ctrl && key.name === "c") {
51798
52076
  cleanup();
51799
- resolve9();
52077
+ resolve10();
51800
52078
  process.exit(0);
51801
52079
  }
51802
52080
  const name = key.name;
51803
52081
  if (name === "q" || name === "escape") {
51804
52082
  cleanup();
51805
- resolve9();
52083
+ resolve10();
51806
52084
  return;
51807
52085
  }
51808
52086
  if (name === "c") {
@@ -52662,9 +52940,283 @@ flowVersionsCommand.command("publish <flowId>").description("Publish a version")
52662
52940
  await waitUntilExit();
52663
52941
  });
52664
52942
 
52665
- // src/commands/tail.ts
52943
+ // src/commands/agent-versions.ts
52666
52944
  import { Command as Command21 } from "commander";
52667
52945
  import chalk27 from "chalk";
52946
+ import React19 from "react";
52947
+ import { render as render19 } from "ink";
52948
+ import { useState as useState33, useEffect as useEffect30 } from "react";
52949
+ import { Text as Text35 } from "ink";
52950
+ var agentVersionsCommand = new Command21("agent-versions").description(
52951
+ "Manage agent versions"
52952
+ );
52953
+ 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) => {
52954
+ const apiKey = await ensureAuth();
52955
+ if (!apiKey) return;
52956
+ const client = new ApiClient(apiKey);
52957
+ if (!isTTY(options) || options.json) {
52958
+ try {
52959
+ const data = await client.get(`/agent-versions/${agentId}`);
52960
+ if (options.json) {
52961
+ printJson(data);
52962
+ } else {
52963
+ const versions = data.versions ?? [];
52964
+ if (versions.length === 0) {
52965
+ console.log(chalk27.gray("No versions found"));
52966
+ return;
52967
+ }
52968
+ console.log(chalk27.cyan(`Versions for agent ${agentId}:`));
52969
+ for (const v of versions) {
52970
+ const isPublished = v.id === data.publishedVersionId;
52971
+ const liveTag = isPublished ? chalk27.green(" [live]") : "";
52972
+ const versionLabel = v.label || (v.versionNumber !== void 0 ? `v${v.versionNumber}` : v.id);
52973
+ const date5 = v.createdAt ? chalk27.gray(` ${v.createdAt}`) : "";
52974
+ console.log(` ${chalk27.green(v.id)} ${versionLabel}${liveTag}${date5}`);
52975
+ }
52976
+ }
52977
+ } catch (error51) {
52978
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
52979
+ console.error(chalk27.red("Failed to fetch versions"));
52980
+ console.error(chalk27.red(message));
52981
+ process.exit(1);
52982
+ }
52983
+ return;
52984
+ }
52985
+ const App = () => {
52986
+ const [loading, setLoading] = useState33(true);
52987
+ const [items, setItems] = useState33(null);
52988
+ const [publishedId, setPublishedId] = useState33(null);
52989
+ const [error51, setError] = useState33(null);
52990
+ useEffect30(() => {
52991
+ const run = async () => {
52992
+ try {
52993
+ const data = await client.get(`/agent-versions/${agentId}`);
52994
+ setItems(data.versions ?? []);
52995
+ setPublishedId(data.publishedVersionId ?? null);
52996
+ setLoading(false);
52997
+ } catch (err) {
52998
+ setError(err instanceof Error ? err : new Error(String(err)));
52999
+ setLoading(false);
53000
+ }
53001
+ };
53002
+ run();
53003
+ }, []);
53004
+ return React19.createElement(DataList, {
53005
+ title: `Versions for agent ${agentId}`,
53006
+ items,
53007
+ error: error51,
53008
+ loading,
53009
+ emptyMessage: "No versions found",
53010
+ renderCard: (item) => {
53011
+ const v = item;
53012
+ const liveTag = v.id === publishedId ? " [live]" : "";
53013
+ const versionLabel = v.label || (v.versionNumber !== void 0 ? `v${v.versionNumber}` : v.id);
53014
+ return React19.createElement(
53015
+ Text35,
53016
+ null,
53017
+ ` ${v.id} ${versionLabel}${liveTag}${v.createdAt ? ` ${v.createdAt}` : ""}`
53018
+ );
53019
+ }
53020
+ });
53021
+ };
53022
+ const { waitUntilExit } = render19(React19.createElement(App));
53023
+ await waitUntilExit();
53024
+ });
53025
+ 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(
53026
+ async (agentId, versionId, options) => {
53027
+ const apiKey = await ensureAuth();
53028
+ if (!apiKey) return;
53029
+ const client = new ApiClient(apiKey);
53030
+ if (!isTTY(options) || options.json) {
53031
+ try {
53032
+ const data = await client.get(`/agent-versions/${agentId}/${versionId}`);
53033
+ if (options.json) {
53034
+ printJson(data);
53035
+ } else {
53036
+ printDetail("Agent Version", [
53037
+ { label: "ID", value: data.id },
53038
+ { label: "Agent ID", value: data.agentId },
53039
+ { label: "Version", value: data.versionNumber },
53040
+ { label: "Type", value: data.versionType },
53041
+ { label: "Label", value: data.label ?? void 0 },
53042
+ { label: "Notes", value: data.notes ?? void 0 },
53043
+ { label: "Created", value: data.createdAt }
53044
+ ]);
53045
+ }
53046
+ } catch (error51) {
53047
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
53048
+ console.error(chalk27.red("Failed to fetch version"));
53049
+ console.error(chalk27.red(message));
53050
+ process.exit(1);
53051
+ }
53052
+ return;
53053
+ }
53054
+ const App = () => {
53055
+ const [loading, setLoading] = useState33(true);
53056
+ const [success2, setSuccess] = useState33(null);
53057
+ const [error51, setError] = useState33(null);
53058
+ const [resultNode, setResultNode] = useState33(void 0);
53059
+ useEffect30(() => {
53060
+ const run = async () => {
53061
+ try {
53062
+ const data = await client.get(`/agent-versions/${agentId}/${versionId}`);
53063
+ setResultNode(
53064
+ React19.createElement(EntityCard, {
53065
+ fields: [
53066
+ { label: "ID", value: data.id },
53067
+ { label: "Agent ID", value: data.agentId },
53068
+ { label: "Version", value: data.versionNumber },
53069
+ { label: "Type", value: data.versionType },
53070
+ { label: "Label", value: data.label ?? void 0 },
53071
+ { label: "Notes", value: data.notes ?? void 0 },
53072
+ { label: "Created", value: data.createdAt }
53073
+ ]
53074
+ })
53075
+ );
53076
+ setSuccess(true);
53077
+ setLoading(false);
53078
+ } catch (err) {
53079
+ setError(err instanceof Error ? err : new Error(String(err)));
53080
+ setSuccess(false);
53081
+ setLoading(false);
53082
+ }
53083
+ };
53084
+ run();
53085
+ }, []);
53086
+ return React19.createElement(MutationResult, {
53087
+ loading,
53088
+ loadingLabel: "Fetching version...",
53089
+ success: success2,
53090
+ successMessage: "Agent Version",
53091
+ error: error51,
53092
+ result: resultNode
53093
+ });
53094
+ };
53095
+ const { waitUntilExit } = render19(React19.createElement(App));
53096
+ await waitUntilExit();
53097
+ }
53098
+ );
53099
+ 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) => {
53100
+ const apiKey = await ensureAuth();
53101
+ if (!apiKey) return;
53102
+ const client = new ApiClient(apiKey);
53103
+ if (!isTTY(options) || options.json) {
53104
+ try {
53105
+ const data = await client.get(`/agent-versions/${agentId}/published`);
53106
+ if (options.json) {
53107
+ printJson(data);
53108
+ } else {
53109
+ printDetail("Published Version", [
53110
+ { label: "ID", value: data.id },
53111
+ { label: "Version", value: data.versionNumber },
53112
+ { label: "Label", value: data.label ?? void 0 },
53113
+ { label: "Created", value: data.createdAt }
53114
+ ]);
53115
+ }
53116
+ } catch (error51) {
53117
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
53118
+ console.error(chalk27.red("Failed to fetch published version"));
53119
+ console.error(chalk27.red(message));
53120
+ process.exit(1);
53121
+ }
53122
+ return;
53123
+ }
53124
+ const App = () => {
53125
+ const [loading, setLoading] = useState33(true);
53126
+ const [success2, setSuccess] = useState33(null);
53127
+ const [error51, setError] = useState33(null);
53128
+ const [resultNode, setResultNode] = useState33(void 0);
53129
+ useEffect30(() => {
53130
+ const run = async () => {
53131
+ try {
53132
+ const data = await client.get(`/agent-versions/${agentId}/published`);
53133
+ setResultNode(
53134
+ React19.createElement(EntityCard, {
53135
+ fields: [
53136
+ { label: "ID", value: data.id },
53137
+ { label: "Version", value: data.versionNumber },
53138
+ { label: "Label", value: data.label ?? void 0 },
53139
+ { label: "Created", value: data.createdAt }
53140
+ ]
53141
+ })
53142
+ );
53143
+ setSuccess(true);
53144
+ setLoading(false);
53145
+ } catch (err) {
53146
+ setError(err instanceof Error ? err : new Error(String(err)));
53147
+ setSuccess(false);
53148
+ setLoading(false);
53149
+ }
53150
+ };
53151
+ run();
53152
+ }, []);
53153
+ return React19.createElement(MutationResult, {
53154
+ loading,
53155
+ loadingLabel: "Fetching published version...",
53156
+ success: success2,
53157
+ successMessage: "Published Version",
53158
+ error: error51,
53159
+ result: resultNode
53160
+ });
53161
+ };
53162
+ const { waitUntilExit } = render19(React19.createElement(App));
53163
+ await waitUntilExit();
53164
+ });
53165
+ 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(
53166
+ async (agentId, options) => {
53167
+ const apiKey = await ensureAuth();
53168
+ if (!apiKey) return;
53169
+ const client = new ApiClient(apiKey);
53170
+ if (!isTTY(options)) {
53171
+ try {
53172
+ await client.post(`/agent-versions/${agentId}/publish`, {
53173
+ versionId: options.version
53174
+ });
53175
+ console.log(chalk27.green("Version published"));
53176
+ } catch (error51) {
53177
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
53178
+ console.error(chalk27.red("Failed to publish version"));
53179
+ console.error(chalk27.red(message));
53180
+ process.exit(1);
53181
+ }
53182
+ return;
53183
+ }
53184
+ const App = () => {
53185
+ const [loading, setLoading] = useState33(true);
53186
+ const [success2, setSuccess] = useState33(null);
53187
+ const [error51, setError] = useState33(null);
53188
+ useEffect30(() => {
53189
+ const run = async () => {
53190
+ try {
53191
+ await client.post(`/agent-versions/${agentId}/publish`, {
53192
+ versionId: options.version
53193
+ });
53194
+ setSuccess(true);
53195
+ setLoading(false);
53196
+ } catch (err) {
53197
+ setError(err instanceof Error ? err : new Error(String(err)));
53198
+ setSuccess(false);
53199
+ setLoading(false);
53200
+ }
53201
+ };
53202
+ run();
53203
+ }, []);
53204
+ return React19.createElement(MutationResult, {
53205
+ loading,
53206
+ loadingLabel: "Publishing version...",
53207
+ success: success2,
53208
+ successMessage: "Version published",
53209
+ error: error51
53210
+ });
53211
+ };
53212
+ const { waitUntilExit } = render19(React19.createElement(App));
53213
+ await waitUntilExit();
53214
+ }
53215
+ );
53216
+
53217
+ // src/commands/tail.ts
53218
+ import { Command as Command22 } from "commander";
53219
+ import chalk28 from "chalk";
52668
53220
  function abbreviateId(id) {
52669
53221
  const underscoreIdx = id.lastIndexOf("_");
52670
53222
  if (underscoreIdx === -1) {
@@ -52683,20 +53235,20 @@ function formatTime(ts) {
52683
53235
  return `${hh}:${mm}:${ss}.${ms}`;
52684
53236
  }
52685
53237
  var LEVEL_COLORS = {
52686
- debug: chalk27.gray,
52687
- info: chalk27.blue,
52688
- warn: chalk27.yellow,
52689
- error: chalk27.red
53238
+ debug: chalk28.gray,
53239
+ info: chalk28.blue,
53240
+ warn: chalk28.yellow,
53241
+ error: chalk28.red
52690
53242
  };
52691
53243
  function levelBadge(level, useColor) {
52692
53244
  const tag = level.toUpperCase().padEnd(5);
52693
53245
  if (!useColor) return `[${tag}]`;
52694
- const colorFn = LEVEL_COLORS[level] || chalk27.white;
53246
+ const colorFn = LEVEL_COLORS[level] || chalk28.white;
52695
53247
  return colorFn(`[${tag}]`);
52696
53248
  }
52697
53249
  function categoryBadge(category, useColor) {
52698
53250
  if (!useColor) return `[${category}]`;
52699
- return chalk27.magenta(`[${category}]`);
53251
+ return chalk28.magenta(`[${category}]`);
52700
53252
  }
52701
53253
  function formatTailData(data) {
52702
53254
  return Object.entries(data).map(([k, v]) => `${k}=${typeof v === "string" ? v : JSON.stringify(v)}`).join(" ");
@@ -52711,14 +53263,14 @@ function formatContextIds(event, useColor) {
52711
53263
  if (event.conversationId) ids.push(`conv=${abbreviateId(event.conversationId)}`);
52712
53264
  if (ids.length === 0) return "";
52713
53265
  const text = ids.join(" ");
52714
- return useColor ? chalk27.gray(` ${text}`) : ` ${text}`;
53266
+ return useColor ? chalk28.gray(` ${text}`) : ` ${text}`;
52715
53267
  }
52716
53268
  function formatEvent(event, useColor) {
52717
- const time3 = useColor ? chalk27.gray(formatTime(event.timestamp)) : formatTime(event.timestamp);
53269
+ const time3 = useColor ? chalk28.gray(formatTime(event.timestamp)) : formatTime(event.timestamp);
52718
53270
  const level = levelBadge(event.level, useColor);
52719
53271
  const cat = categoryBadge(event.category, useColor);
52720
53272
  const ctx = formatContextIds(event, useColor);
52721
- const data = event.tailData && Object.keys(event.tailData).length > 0 ? useColor ? chalk27.gray(` | ${formatTailData(event.tailData)}`) : ` | ${formatTailData(event.tailData)}` : "";
53273
+ const data = event.tailData && Object.keys(event.tailData).length > 0 ? useColor ? chalk28.gray(` | ${formatTailData(event.tailData)}`) : ` | ${formatTailData(event.tailData)}` : "";
52722
53274
  return `${time3} ${level} ${cat} ${event.message}${data}${ctx}`;
52723
53275
  }
52724
53276
  async function consumeSSEStream(reader, options, signal) {
@@ -52757,17 +53309,17 @@ async function consumeSSEStream(reader, options, signal) {
52757
53309
  break;
52758
53310
  case "tail_gap":
52759
53311
  process.stderr.write(
52760
- (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"
53312
+ (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"
52761
53313
  );
52762
53314
  break;
52763
53315
  case "tail_connected":
52764
53316
  process.stderr.write(
52765
- (useColor ? chalk27.green(`Connected to tail session ${msg.sessionId}`) : `Connected to tail session ${msg.sessionId}`) + "\n"
53317
+ (useColor ? chalk28.green(`Connected to tail session ${msg.sessionId}`) : `Connected to tail session ${msg.sessionId}`) + "\n"
52766
53318
  );
52767
53319
  break;
52768
53320
  case "tail_error":
52769
53321
  process.stderr.write(
52770
- (useColor ? chalk27.red(`[error] ${msg.error}`) : `[error] ${msg.error}`) + "\n"
53322
+ (useColor ? chalk28.red(`[error] ${msg.error}`) : `[error] ${msg.error}`) + "\n"
52771
53323
  );
52772
53324
  break;
52773
53325
  }
@@ -52847,7 +53399,7 @@ async function runTail(options) {
52847
53399
  const useColor = options.color;
52848
53400
  const activeFilters = Object.entries(filters).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${v}`);
52849
53401
  process.stderr.write(
52850
- (useColor ? chalk27.gray(`Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) : `Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) + "\n"
53402
+ (useColor ? chalk28.gray(`Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) : `Connecting to ${apiUrl}...${activeFilters.length ? ` filters: ${activeFilters.join(", ")}` : ""}`) + "\n"
52851
53403
  );
52852
53404
  const controller = new AbortController();
52853
53405
  let shuttingDown = false;
@@ -52855,7 +53407,7 @@ async function runTail(options) {
52855
53407
  if (shuttingDown) return;
52856
53408
  shuttingDown = true;
52857
53409
  process.stderr.write(
52858
- (useColor ? chalk27.gray("\nDisconnecting...") : "\nDisconnecting...") + "\n"
53410
+ (useColor ? chalk28.gray("\nDisconnecting...") : "\nDisconnecting...") + "\n"
52859
53411
  );
52860
53412
  controller.abort();
52861
53413
  };
@@ -52869,7 +53421,7 @@ async function runTail(options) {
52869
53421
  const result = await connectAndStream(session.sseUrl, apiKey, options, controller.signal);
52870
53422
  if (result === "aborted" || shuttingDown) break;
52871
53423
  process.stderr.write(
52872
- (useColor ? chalk27.yellow("Stream ended, reconnecting...") : "Stream ended, reconnecting...") + "\n"
53424
+ (useColor ? chalk28.yellow("Stream ended, reconnecting...") : "Stream ended, reconnecting...") + "\n"
52873
53425
  );
52874
53426
  } catch (err) {
52875
53427
  if (shuttingDown || controller.signal.aborted) break;
@@ -52877,22 +53429,22 @@ async function runTail(options) {
52877
53429
  const delay = Math.min(BASE_DELAY_MS * Math.pow(2, attempt - 1), MAX_DELAY_MS);
52878
53430
  const message = err instanceof Error ? err.message : String(err);
52879
53431
  process.stderr.write(
52880
- (useColor ? chalk27.red(`Connection error: ${message}`) : `Connection error: ${message}`) + "\n"
53432
+ (useColor ? chalk28.red(`Connection error: ${message}`) : `Connection error: ${message}`) + "\n"
52881
53433
  );
52882
53434
  if (attempt >= MAX_ATTEMPTS) {
52883
53435
  process.stderr.write(
52884
- (useColor ? chalk27.red(`Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) : `Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) + "\n"
53436
+ (useColor ? chalk28.red(`Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) : `Max reconnect attempts (${MAX_ATTEMPTS}) reached. Exiting.`) + "\n"
52885
53437
  );
52886
53438
  process.exit(1);
52887
53439
  }
52888
53440
  process.stderr.write(
52889
- (useColor ? chalk27.gray(`Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) : `Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) + "\n"
53441
+ (useColor ? chalk28.gray(`Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) : `Retrying in ${delay / 1e3}s (attempt ${attempt}/${MAX_ATTEMPTS})...`) + "\n"
52890
53442
  );
52891
- await new Promise((resolve9) => {
52892
- const timer = setTimeout(resolve9, delay);
53443
+ await new Promise((resolve10) => {
53444
+ const timer = setTimeout(resolve10, delay);
52893
53445
  const onAbort = () => {
52894
53446
  clearTimeout(timer);
52895
- resolve9();
53447
+ resolve10();
52896
53448
  };
52897
53449
  controller.signal.addEventListener("abort", onAbort, { once: true });
52898
53450
  });
@@ -52901,16 +53453,16 @@ async function runTail(options) {
52901
53453
  process.removeListener("SIGINT", shutdown);
52902
53454
  process.removeListener("SIGTERM", shutdown);
52903
53455
  }
52904
- 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) => {
53456
+ 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) => {
52905
53457
  await runTail(options);
52906
53458
  });
52907
53459
 
52908
53460
  // src/commands/validate-product.ts
52909
- import { Command as Command22, Option } from "commander";
52910
- import chalk28 from "chalk";
53461
+ import { Command as Command23, Option } from "commander";
53462
+ import chalk29 from "chalk";
52911
53463
  import { readFileSync as readFileSync15 } from "fs";
52912
53464
  function createValidateProductCommand() {
52913
- return new Command22("validate-product").description("Validate a product (FPO) or FPO template locally (no API call)").argument(
53465
+ return new Command23("validate-product").description("Validate a product (FPO) or FPO template locally (no API call)").argument(
52914
53466
  "[input]",
52915
53467
  'Path to JSON file, raw JSON string (starts with "{"), or "-" for stdin'
52916
53468
  ).option("--template", "Force FPO template validation").option("--fpo", "Force FPO (non-template) validation").addOption(
@@ -52934,7 +53486,7 @@ var validateProductCommand = createValidateProductCommand();
52934
53486
  async function runValidateAction(input, _options) {
52935
53487
  const options = this.optsWithGlobals();
52936
53488
  if (options.template && options.fpo) {
52937
- console.error(chalk28.red("Error: --template and --fpo are mutually exclusive"));
53489
+ console.error(chalk29.red("Error: --template and --fpo are mutually exclusive"));
52938
53490
  process.exit(1);
52939
53491
  }
52940
53492
  let raw;
@@ -52942,7 +53494,7 @@ async function runValidateAction(input, _options) {
52942
53494
  raw = await readInput(input);
52943
53495
  } catch (err) {
52944
53496
  const message = err instanceof Error ? err.message : String(err);
52945
- console.error(chalk28.red(`Failed to read input: ${message}`));
53497
+ console.error(chalk29.red(`Failed to read input: ${message}`));
52946
53498
  process.exit(1);
52947
53499
  return;
52948
53500
  }
@@ -52951,7 +53503,7 @@ async function runValidateAction(input, _options) {
52951
53503
  parsed = JSON.parse(raw);
52952
53504
  } catch (err) {
52953
53505
  const message = err instanceof Error ? err.message : String(err);
52954
- console.error(chalk28.red(`Invalid JSON: ${message}`));
53506
+ console.error(chalk29.red(`Invalid JSON: ${message}`));
52955
53507
  process.exit(1);
52956
53508
  return;
52957
53509
  }
@@ -53041,16 +53593,16 @@ function runValidation(body, kind) {
53041
53593
  function printHumanResult(kind, result) {
53042
53594
  const label = kind === "template" ? "FPO template" : "FPO";
53043
53595
  const overallValid = !hasAnyErrors(result);
53044
- const headline = overallValid ? chalk28.green(`\u2713 Valid ${label}`) : chalk28.red(`\u2717 Invalid ${label}`);
53596
+ const headline = overallValid ? chalk29.green(`\u2713 Valid ${label}`) : chalk29.red(`\u2717 Invalid ${label}`);
53045
53597
  console.log(headline);
53046
53598
  console.log(
53047
- chalk28.gray(
53599
+ chalk29.gray(
53048
53600
  ` ${result.errors.length} error(s), ${result.warnings.length} warning(s), ${result.recommendations.length} recommendation(s)`
53049
53601
  )
53050
53602
  );
53051
- printIssues("Errors", result.errors, chalk28.red);
53052
- printIssues("Warnings", result.warnings, chalk28.yellow);
53053
- printIssues("Recommendations", result.recommendations, chalk28.blue);
53603
+ printIssues("Errors", result.errors, chalk29.red);
53604
+ printIssues("Warnings", result.warnings, chalk29.yellow);
53605
+ printIssues("Recommendations", result.recommendations, chalk29.blue);
53054
53606
  if (result.kind === "template") {
53055
53607
  const defaults = result.defaultsValidation;
53056
53608
  const structuralErrors = defaults.errors.filter(
@@ -53062,22 +53614,22 @@ function printHumanResult(kind, result) {
53062
53614
  if (structuralErrors.length > 0) {
53063
53615
  console.log();
53064
53616
  console.log(
53065
- chalk28.red(
53617
+ chalk29.red(
53066
53618
  `Defaults validation: template defaults do not produce a valid FPO`
53067
53619
  )
53068
53620
  );
53069
- printIssues("Default-resolution errors", structuralErrors, chalk28.red);
53070
- printIssues("Default-resolution warnings", defaults.warnings, chalk28.yellow);
53621
+ printIssues("Default-resolution errors", structuralErrors, chalk29.red);
53622
+ printIssues("Default-resolution warnings", defaults.warnings, chalk29.yellow);
53071
53623
  }
53072
53624
  if (missingVars.length > 0) {
53073
53625
  console.log();
53074
53626
  console.log(
53075
- chalk28.gray(
53627
+ chalk29.gray(
53076
53628
  `Template variables needing deploy-time values (${missingVars.length}):`
53077
53629
  )
53078
53630
  );
53079
53631
  for (const issue2 of missingVars) {
53080
- console.log(chalk28.gray(` \u2022 ${issue2.path} \u2014 ${issue2.message}`));
53632
+ console.log(chalk29.gray(` \u2022 ${issue2.path} \u2014 ${issue2.message}`));
53081
53633
  }
53082
53634
  }
53083
53635
  }
@@ -53087,19 +53639,515 @@ function printIssues(title, issues, color) {
53087
53639
  console.log();
53088
53640
  console.log(color(`${title}:`));
53089
53641
  for (const issue2 of issues) {
53090
- const pathLabel = issue2.path ? chalk28.gray(` [${issue2.path}]`) : "";
53091
- console.log(` ${color("\u2022")} ${chalk28.bold(issue2.code)}${pathLabel} ${issue2.message}`);
53642
+ const pathLabel = issue2.path ? chalk29.gray(` [${issue2.path}]`) : "";
53643
+ console.log(` ${color("\u2022")} ${chalk29.bold(issue2.code)}${pathLabel} ${issue2.message}`);
53092
53644
  if (issue2.suggestedFix) {
53093
- console.log(` ${chalk28.gray("fix:")} ${issue2.suggestedFix}`);
53645
+ console.log(` ${chalk29.gray("fix:")} ${issue2.suggestedFix}`);
53646
+ }
53647
+ }
53648
+ }
53649
+
53650
+ // src/commands/deploy.ts
53651
+ import { Command as Command24 } from "commander";
53652
+ import chalk30 from "chalk";
53653
+ import * as fs14 from "fs";
53654
+ import * as path14 from "path";
53655
+ function bashSingleQuote(s) {
53656
+ return "'" + s.replace(/'/g, "'\\''") + "'";
53657
+ }
53658
+ function serverTs() {
53659
+ return `/**
53660
+ * Generated by \`runtype deploy\`.
53661
+ *
53662
+ * Boots a Hono server that loads every agent JSON file under ./agents/ and
53663
+ * registers a streaming POST /agent/:name endpoint for each.
53664
+ *
53665
+ * See README.md for startup and deploy instructions.
53666
+ */
53667
+ import { readFile, readdir } from 'node:fs/promises'
53668
+ import { resolve } from 'node:path'
53669
+ import { Hono } from 'hono'
53670
+ import { cors } from 'hono/cors'
53671
+ import { serve } from '@hono/node-server'
53672
+ import {
53673
+ CloudRunAdapter,
53674
+ createRuntime,
53675
+ exportedAgentSchema,
53676
+ type ExportedAgent,
53677
+ } from '@runtypelabs/runtime'
53678
+
53679
+ async function loadAgent(filePath: string): Promise<ExportedAgent> {
53680
+ const raw = await readFile(filePath, 'utf-8')
53681
+ return exportedAgentSchema.parse(JSON.parse(raw))
53682
+ }
53683
+
53684
+ async function loadAgentsDir(dir: string): Promise<Record<string, ExportedAgent>> {
53685
+ let entries: string[]
53686
+ try {
53687
+ entries = await readdir(dir)
53688
+ } catch (err) {
53689
+ throw new Error(
53690
+ \`[runtype] could not read agents directory at \${dir}: \${err instanceof Error ? err.message : String(err)}\`
53691
+ )
53692
+ }
53693
+ const jsonFiles = entries.filter((f) => f.endsWith('.json')).sort()
53694
+ if (jsonFiles.length === 0) {
53695
+ throw new Error(\`[runtype] no agents found in \${dir} (expected one or more *.json files)\`)
53696
+ }
53697
+
53698
+ const agents: Record<string, ExportedAgent> = {}
53699
+ for (const file of jsonFiles) {
53700
+ const agent = await loadAgent(resolve(dir, file))
53701
+ if (agents[agent.name]) {
53702
+ throw new Error(
53703
+ \`[runtype] duplicate agent name "\${agent.name}" in \${file} \u2014 already defined by an earlier file\`
53704
+ )
53094
53705
  }
53706
+ agents[agent.name] = agent
53707
+ console.log(\`[runtype] loaded agent id=\${agent.id} name=\${agent.name}\`)
53095
53708
  }
53709
+ return agents
53710
+ }
53711
+
53712
+ async function main(): Promise<void> {
53713
+ const agentsDir = resolve(process.cwd(), 'agents')
53714
+ const agents = await loadAgentsDir(agentsDir)
53715
+
53716
+ const runtime = createRuntime({
53717
+ agents,
53718
+ keys: { mode: 'own' },
53719
+ adapter: new CloudRunAdapter(),
53720
+ })
53721
+
53722
+ const app = new Hono()
53723
+
53724
+ const allowedOriginsEnv = process.env.ALLOWED_ORIGINS?.trim()
53725
+ const allowedOrigins = allowedOriginsEnv
53726
+ ? allowedOriginsEnv.split(',').map((o) => o.trim()).filter(Boolean)
53727
+ : '*'
53728
+ app.use(
53729
+ '*',
53730
+ cors({
53731
+ origin: allowedOrigins,
53732
+ allowMethods: ['GET', 'POST', 'OPTIONS'],
53733
+ allowHeaders: ['Content-Type', 'Authorization'],
53734
+ credentials: false,
53735
+ maxAge: 86400,
53736
+ })
53737
+ )
53738
+
53739
+ app.get('/health', (c) => c.json({ status: 'ok', agents: Object.keys(agents) }))
53740
+
53741
+ app.post('/agent/:name', async (c) => {
53742
+ const name = c.req.param('name')
53743
+ if (!runtime.getAgent(name)) {
53744
+ return c.json({ error: \`unknown agent: \${name}\` }, 404)
53745
+ }
53746
+
53747
+ let body: { messages?: Array<{ role: string; content: string }> } = {}
53748
+ try {
53749
+ body = (await c.req.json()) as typeof body
53750
+ } catch {
53751
+ return c.json({ error: 'request body must be JSON' }, 400)
53752
+ }
53753
+ const messages = Array.isArray(body.messages) ? body.messages : []
53754
+
53755
+ try {
53756
+ const response = await runtime.executeAgent(name, {
53757
+ messages: messages as Array<{ role: 'system' | 'user' | 'assistant'; content: string }>,
53758
+ signal: c.req.raw.signal,
53759
+ })
53760
+ return response
53761
+ } catch (err) {
53762
+ return c.json({ error: err instanceof Error ? err.message : 'unknown error' }, 500)
53763
+ }
53764
+ })
53765
+
53766
+ const port = Number(process.env.PORT ?? 8080)
53767
+ serve({ fetch: app.fetch, port, hostname: '0.0.0.0' })
53768
+ console.log(\`[runtype] listening on 0.0.0.0:\${port} \u2014 agents: \${Object.keys(agents).join(', ')}\`)
53769
+ }
53770
+
53771
+ main().catch((err) => {
53772
+ console.error('[runtype] fatal: failed to start server', err)
53773
+ process.exit(1)
53774
+ })
53775
+ `;
53096
53776
  }
53777
+ function dockerfile() {
53778
+ return `FROM node:22-bookworm-slim AS builder
53779
+
53780
+ WORKDIR /app
53781
+
53782
+ COPY package.json ./
53783
+ COPY packages ./packages
53784
+ RUN npm install --omit=dev --no-audit --no-fund
53785
+
53786
+ COPY tsconfig.json server.ts ./
53787
+ COPY agents ./agents
53788
+ RUN npm install --no-save --no-audit --no-fund typescript @types/node \\
53789
+ && npx tsc -p tsconfig.json
53790
+
53791
+ FROM node:22-bookworm-slim AS runner
53792
+
53793
+ WORKDIR /app
53794
+ ENV NODE_ENV=production
53795
+ ENV PORT=8080
53796
+ EXPOSE 8080
53797
+
53798
+ COPY --from=builder /app/node_modules ./node_modules
53799
+ COPY --from=builder /app/dist ./dist
53800
+ COPY --from=builder /app/agents ./agents
53801
+ COPY --from=builder /app/package.json ./package.json
53802
+
53803
+ CMD ["node", "dist/server.js"]
53804
+ `;
53805
+ }
53806
+ function dockerignore() {
53807
+ return `node_modules
53808
+ dist
53809
+ *.log
53810
+ `;
53811
+ }
53812
+ function tsconfigJson() {
53813
+ return JSON.stringify(
53814
+ {
53815
+ compilerOptions: {
53816
+ target: "ES2022",
53817
+ module: "ESNext",
53818
+ moduleResolution: "bundler",
53819
+ lib: ["ES2022", "DOM"],
53820
+ strict: true,
53821
+ esModuleInterop: true,
53822
+ forceConsistentCasingInFileNames: true,
53823
+ resolveJsonModule: true,
53824
+ skipLibCheck: true,
53825
+ outDir: "dist",
53826
+ declaration: false,
53827
+ sourceMap: true,
53828
+ noEmit: false
53829
+ },
53830
+ include: ["*.ts"],
53831
+ exclude: ["node_modules", "dist"]
53832
+ },
53833
+ null,
53834
+ 2
53835
+ );
53836
+ }
53837
+ function packageJson(name, runtimeDep) {
53838
+ return JSON.stringify(
53839
+ {
53840
+ name,
53841
+ version: "0.0.0",
53842
+ private: true,
53843
+ type: "module",
53844
+ scripts: {
53845
+ start: "node dist/server.js",
53846
+ dev: "tsx server.ts",
53847
+ build: "tsc -p tsconfig.json",
53848
+ typecheck: "tsc -p tsconfig.json --noEmit"
53849
+ },
53850
+ dependencies: {
53851
+ "@hono/node-server": "^2.0.0",
53852
+ "@runtypelabs/runtime": runtimeDep,
53853
+ hono: "^4.12.16"
53854
+ },
53855
+ devDependencies: {
53856
+ "@types/node": "^22.10.5",
53857
+ tsx: "^4.19.2",
53858
+ typescript: "^5.3.3"
53859
+ },
53860
+ engines: {
53861
+ node: ">=22.0.0"
53862
+ }
53863
+ },
53864
+ null,
53865
+ 2
53866
+ );
53867
+ }
53868
+ function setupSh(monorepoRoot) {
53869
+ return `#!/usr/bin/env bash
53870
+ # Generated by \`runtype deploy\`.
53871
+ #
53872
+ # Builds and packs @runtypelabs/runtime from your local monorepo, then
53873
+ # installs all dependencies so you can run \`npm start\` or deploy to
53874
+ # Cloud Run with \`gcloud run deploy --source .\`.
53875
+ #
53876
+ # Usage (from this directory):
53877
+ # ./setup.sh
53878
+ # # then: npm run dev OR gcloud run deploy \u2026
53879
+
53880
+ set -euo pipefail
53881
+
53882
+ DEPLOY_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
53883
+ MONOREPO_ROOT=${bashSingleQuote(monorepoRoot)}
53884
+ TARBALL_DIR="\${DEPLOY_DIR}/packages"
53885
+
53886
+ echo "[setup] building @runtypelabs/runtime..."
53887
+ pnpm --dir "\${MONOREPO_ROOT}" --filter @runtypelabs/runtime build
53888
+
53889
+ mkdir -p "\${TARBALL_DIR}"
53890
+
53891
+ echo "[setup] packing @runtypelabs/runtime tarball..."
53892
+ pnpm --dir "\${MONOREPO_ROOT}/packages/runtime" pack \\
53893
+ --pack-destination "\${TARBALL_DIR}"
53894
+
53895
+ RUNTIME_TGZ="$(ls "\${TARBALL_DIR}"/runtypelabs-runtime-*.tgz | head -n 1)"
53896
+ if [ -z "\${RUNTIME_TGZ}" ]; then
53897
+ echo "[setup] error: no tarball produced by pnpm pack" >&2
53898
+ exit 1
53899
+ fi
53900
+ RUNTIME_TGZ_NAME="$(basename "\${RUNTIME_TGZ}")"
53901
+
53902
+ echo "[setup] updating package.json with file: dependency..."
53903
+ node -e "
53904
+ const fs = require('fs');
53905
+ const pkg = JSON.parse(fs.readFileSync('\${DEPLOY_DIR}/package.json', 'utf8'));
53906
+ pkg.dependencies['@runtypelabs/runtime'] = 'file:./packages/\${RUNTIME_TGZ_NAME}';
53907
+ fs.writeFileSync('\${DEPLOY_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\\\\n');
53908
+ "
53909
+
53910
+ echo "[setup] installing dependencies..."
53911
+ npm install --no-audit --no-fund
53912
+
53913
+ echo ""
53914
+ echo "[setup] Done! Next steps:"
53915
+ echo " npm run dev \u2014 start locally"
53916
+ echo " npm run build \u2014 compile TypeScript"
53917
+ echo " gcloud run deploy --source . --region us-central1 --allow-unauthenticated --port 8080"
53918
+ `;
53919
+ }
53920
+ function readme(agentNames, secretNames) {
53921
+ const agentList = agentNames.map((n) => ` - ${n}`).join("\n");
53922
+ const secretList = secretNames.length > 0 ? secretNames.map((s) => ` gcloud secrets create ${s} --data-file=-`).join("\n") : " (none detected)";
53923
+ return `# Runtype Deployment
53924
+
53925
+ Generated by \`runtype deploy\`. Contains the following agents:
53926
+
53927
+ ${agentList}
53928
+
53929
+ ## Setup
53930
+
53931
+ Run \`./setup.sh\` to build the runtime and install dependencies:
53932
+
53933
+ \`\`\`bash
53934
+ chmod +x setup.sh
53935
+ ./setup.sh
53936
+ \`\`\`
53937
+
53938
+ ## Local development
53939
+
53940
+ \`\`\`bash
53941
+ npm run dev
53942
+ \`\`\`
53943
+
53944
+ Test with:
53945
+ \`\`\`bash
53946
+ curl -X POST http://localhost:8080/agent/${agentNames[0] ?? "my-agent"} \\
53947
+ -H "Content-Type: application/json" \\
53948
+ -d '{"messages":[{"role":"user","content":"Hello!"}]}'
53949
+ \`\`\`
53950
+
53951
+ ## Required secrets
53952
+
53953
+ Set these before deploying to Cloud Run:
53954
+
53955
+ ${secretList}
53956
+
53957
+ ## Deploy to Cloud Run
53958
+
53959
+ \`\`\`bash
53960
+ gcloud run deploy runtype-deploy \\
53961
+ --source . \\
53962
+ --region us-central1 \\
53963
+ --platform managed \\
53964
+ --allow-unauthenticated \\
53965
+ --port 8080
53966
+ \`\`\`
53967
+
53968
+ ## Health check
53969
+
53970
+ \`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
53971
+ `;
53972
+ }
53973
+ function collectSecretNames(agentDef) {
53974
+ const names = /* @__PURE__ */ new Set();
53975
+ const model = agentDef.config?.model?.toLowerCase();
53976
+ if (model) {
53977
+ for (const s of resolveModelSecretNames(model)) names.add(s);
53978
+ }
53979
+ const toolsCfg = agentDef.config?.tools;
53980
+ const mcpServers = toolsCfg?.mcpServers;
53981
+ if (mcpServers) {
53982
+ for (const srv of mcpServers) {
53983
+ const auth = srv.auth;
53984
+ if (auth?.tokenSecretName) names.add(String(auth.tokenSecretName));
53985
+ if (auth?.usernameSecretName) names.add(String(auth.usernameSecretName));
53986
+ if (auth?.passwordSecretName) names.add(String(auth.passwordSecretName));
53987
+ }
53988
+ }
53989
+ for (const s of extractSecretReferencesFromAnyValue(agentDef)) names.add(s);
53990
+ return Array.from(names);
53991
+ }
53992
+ function slugify2(s) {
53993
+ return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
53994
+ }
53995
+ var deployCommand = new Command24("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) => {
53996
+ acc.push(v);
53997
+ return acc;
53998
+ }, []).option("--flow <id>", "Flow ID to export (may be repeated)", (v, acc) => {
53999
+ acc.push(v);
54000
+ return acc;
54001
+ }, []).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(
54002
+ async (options) => {
54003
+ const agentIds = options.agent;
54004
+ const flowIds = options.flow;
54005
+ if (agentIds.length === 0 && flowIds.length === 0) {
54006
+ console.error(chalk30.red("Error: provide at least one --agent <id> or --flow <id>"));
54007
+ process.exit(1);
54008
+ }
54009
+ const apiKey = await ensureAuth();
54010
+ if (!apiKey) return;
54011
+ const client = new ApiClient(apiKey);
54012
+ const outDir = path14.resolve(options.output);
54013
+ const projectName = options.name ?? slugify2(path14.basename(outDir));
54014
+ console.log(chalk30.cyan(`
54015
+ Scaffolding deployment to ${outDir}
54016
+ `));
54017
+ const agentDefs = [];
54018
+ for (const id of agentIds) {
54019
+ process.stdout.write(` Exporting agent ${chalk30.green(id)}... `);
54020
+ try {
54021
+ const def = await client.get(`/agents/${id}/export-runtime`);
54022
+ agentDefs.push({ id, name: String(def.name ?? id), def });
54023
+ process.stdout.write(chalk30.green("\u2713\n"));
54024
+ } catch (err) {
54025
+ const msg = err instanceof ApiError ? err.message : String(err);
54026
+ process.stdout.write(chalk30.red(`\u2717
54027
+ `));
54028
+ console.error(chalk30.red(` Failed to export agent ${id}: ${msg}`));
54029
+ if (err instanceof ApiError && err.statusCode === 404) {
54030
+ console.error(chalk30.yellow(" The export-runtime feature may not be enabled on your account or environment."));
54031
+ console.error(chalk30.gray(" If you have your own environment, try: RUNTYPE_API_URL={API Base URI} runtype deploy ..."));
54032
+ }
54033
+ process.exit(1);
54034
+ }
54035
+ }
54036
+ for (const id of flowIds) {
54037
+ process.stdout.write(` Exporting flow ${chalk30.green(id)}... `);
54038
+ try {
54039
+ const def = await client.get(`/flows/${id}/export-runtime`);
54040
+ const wrappedName = String(def.name ?? id);
54041
+ agentDefs.push({
54042
+ id,
54043
+ name: wrappedName,
54044
+ def: {
54045
+ id: def.id,
54046
+ name: wrappedName,
54047
+ description: def.description ?? null,
54048
+ agentType: "runtype",
54049
+ config: {},
54050
+ primaryFlow: def
54051
+ }
54052
+ });
54053
+ process.stdout.write(chalk30.green("\u2713\n"));
54054
+ } catch (err) {
54055
+ const msg = err instanceof ApiError ? err.message : String(err);
54056
+ process.stdout.write(chalk30.red(`\u2717
54057
+ `));
54058
+ console.error(chalk30.red(` Failed to export flow ${id}: ${msg}`));
54059
+ if (err instanceof ApiError && err.statusCode === 404) {
54060
+ console.error(chalk30.yellow(" The export-runtime feature may not be enabled on your account or environment."));
54061
+ console.error(chalk30.gray(" If you have your own environment, try: RUNTYPE_API_URL={API Base URI} runtype deploy ..."));
54062
+ }
54063
+ process.exit(1);
54064
+ }
54065
+ }
54066
+ fs14.mkdirSync(path14.join(outDir, "agents"), { recursive: true });
54067
+ fs14.mkdirSync(path14.join(outDir, "packages"), { recursive: true });
54068
+ for (const { name, def } of agentDefs) {
54069
+ const filename = `${slugify2(name)}.json`;
54070
+ fs14.writeFileSync(
54071
+ path14.join(outDir, "agents", filename),
54072
+ JSON.stringify(def, null, 2)
54073
+ );
54074
+ console.log(` Wrote agents/${filename}`);
54075
+ }
54076
+ fs14.writeFileSync(
54077
+ path14.join(outDir, "server.ts"),
54078
+ serverTs()
54079
+ );
54080
+ fs14.writeFileSync(
54081
+ path14.join(outDir, "Dockerfile"),
54082
+ dockerfile()
54083
+ );
54084
+ fs14.writeFileSync(
54085
+ path14.join(outDir, ".dockerignore"),
54086
+ dockerignore()
54087
+ );
54088
+ fs14.writeFileSync(
54089
+ path14.join(outDir, "tsconfig.json"),
54090
+ tsconfigJson()
54091
+ );
54092
+ fs14.writeFileSync(
54093
+ path14.join(outDir, "package.json"),
54094
+ packageJson(projectName, "workspace:*")
54095
+ );
54096
+ let monorepoRoot = process.cwd();
54097
+ for (let i = 0; i < 8; i++) {
54098
+ if (fs14.existsSync(path14.join(monorepoRoot, "pnpm-workspace.yaml"))) break;
54099
+ const parent = path14.dirname(monorepoRoot);
54100
+ if (parent === monorepoRoot) break;
54101
+ monorepoRoot = parent;
54102
+ }
54103
+ const setupScript = setupSh(monorepoRoot);
54104
+ const setupPath = path14.join(outDir, "setup.sh");
54105
+ fs14.writeFileSync(setupPath, setupScript);
54106
+ fs14.chmodSync(setupPath, 493);
54107
+ const allSecrets = /* @__PURE__ */ new Set();
54108
+ for (const { def } of agentDefs) {
54109
+ for (const s of collectSecretNames(def)) allSecrets.add(s);
54110
+ }
54111
+ const secretNames = Array.from(allSecrets);
54112
+ fs14.writeFileSync(
54113
+ path14.join(outDir, "README.md"),
54114
+ readme(
54115
+ agentDefs.map((a) => a.name),
54116
+ secretNames
54117
+ )
54118
+ );
54119
+ console.log("");
54120
+ console.log(chalk30.green(`\u2713 Scaffold written to ${outDir}`));
54121
+ console.log("");
54122
+ console.log(chalk30.bold("Next steps:"));
54123
+ console.log(` cd ${options.output}`);
54124
+ console.log(" chmod +x setup.sh && ./setup.sh # pack runtime + install deps");
54125
+ console.log(" npm run dev # test locally");
54126
+ console.log("");
54127
+ if (secretNames.length > 0) {
54128
+ console.log(chalk30.yellow("Required secrets (set before deploying):"));
54129
+ for (const s of secretNames) {
54130
+ console.log(` ${chalk30.cyan(s)}`);
54131
+ }
54132
+ console.log("");
54133
+ console.log(" Set via Cloud Run: gcloud run deploy \u2026 --set-secrets KEY=NAME:latest");
54134
+ console.log(" Or export locally: export KEY=<value>");
54135
+ console.log("");
54136
+ }
54137
+ console.log("Deploy to Cloud Run:");
54138
+ console.log(
54139
+ ` gcloud run deploy ${projectName} --source ${options.output} \\`
54140
+ );
54141
+ console.log(" --region us-central1 --platform managed \\");
54142
+ console.log(" --allow-unauthenticated --port 8080");
54143
+ }
54144
+ );
53097
54145
 
53098
54146
  // src/index.ts
53099
54147
  init_credential_store();
53100
54148
 
53101
54149
  // src/lib/update-check.ts
53102
- import chalk29 from "chalk";
54150
+ import chalk31 from "chalk";
53103
54151
  import Conf3 from "conf";
53104
54152
  var UPDATE_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1e3;
53105
54153
  var UPDATE_NOTIFY_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -53193,7 +54241,7 @@ function notifyFromCachedCliUpdate(args, options = {}) {
53193
54241
  console.error(message);
53194
54242
  });
53195
54243
  notify(
53196
- `${chalk29.yellow("Update available:")} ${chalk29.red(currentVersion)} ${chalk29.gray("->")} ${chalk29.green(latestVersion)} ${chalk29.gray(`(${getUpgradeCommand()})`)}`
54244
+ `${chalk31.yellow("Update available:")} ${chalk31.red(currentVersion)} ${chalk31.gray("->")} ${chalk31.green(latestVersion)} ${chalk31.gray(`(${getUpgradeCommand()})`)}`
53197
54245
  );
53198
54246
  store.set("lastNotifiedAt", now.toISOString());
53199
54247
  store.set("lastNotifiedVersion", latestVersion);
@@ -53235,7 +54283,7 @@ function maybeNotifyAboutCliUpdate(args, options = {}) {
53235
54283
  // src/index.ts
53236
54284
  loadEnv();
53237
54285
  setCliTitle();
53238
- var program = new Command23();
54286
+ var program = new Command25();
53239
54287
  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");
53240
54288
  program.addCommand(initCommand);
53241
54289
  program.addCommand(loginCommand);
@@ -53257,9 +54305,11 @@ program.addCommand(personaCommand);
53257
54305
  program.addCommand(analyticsCommand);
53258
54306
  program.addCommand(billingCommand);
53259
54307
  program.addCommand(flowVersionsCommand);
54308
+ program.addCommand(agentVersionsCommand);
53260
54309
  program.addCommand(createMarathonCommand());
53261
54310
  program.addCommand(tailCommand);
53262
54311
  program.addCommand(validateProductCommand);
54312
+ program.addCommand(deployCommand);
53263
54313
  program.exitOverride();
53264
54314
  try {
53265
54315
  const userArgs = process.argv.slice(2);
@@ -53273,15 +54323,15 @@ try {
53273
54323
  } catch (error51) {
53274
54324
  const commanderError = error51;
53275
54325
  if (commanderError.code === "commander.missingArgument") {
53276
- console.error(chalk30.red(`Error: ${commanderError.message}`));
54326
+ console.error(chalk32.red(`Error: ${commanderError.message}`));
53277
54327
  process.exit(1);
53278
54328
  } else if (commanderError.code === "commander.unknownOption") {
53279
- console.error(chalk30.red(`Error: ${commanderError.message}`));
54329
+ console.error(chalk32.red(`Error: ${commanderError.message}`));
53280
54330
  process.exit(1);
53281
54331
  } else if (commanderError.code === "commander.help" || commanderError.code === "commander.version") {
53282
54332
  process.exit(0);
53283
54333
  } else {
53284
- console.error(chalk30.red("An unexpected error occurred:"));
54334
+ console.error(chalk32.red("An unexpected error occurred:"));
53285
54335
  console.error(error51);
53286
54336
  process.exit(1);
53287
54337
  }
@@ -53290,12 +54340,12 @@ async function handleNoCommand() {
53290
54340
  const store = new CredentialStore();
53291
54341
  const hasCredentials = await store.hasCredentials();
53292
54342
  if (!hasCredentials) {
53293
- console.log(chalk30.cyan("\nWelcome to Runtype CLI!\n"));
54343
+ console.log(chalk32.cyan("\nWelcome to Runtype CLI!\n"));
53294
54344
  console.log("It looks like this is your first time. Run the setup wizard:");
53295
- console.log(` ${chalk30.green("runtype init")}
54345
+ console.log(` ${chalk32.green("runtype init")}
53296
54346
  `);
53297
54347
  console.log("Or see all available commands:");
53298
- console.log(` ${chalk30.green("runtype --help")}
54348
+ console.log(` ${chalk32.green("runtype --help")}
53299
54349
  `);
53300
54350
  } else {
53301
54351
  try {