@runtypelabs/cli 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
9
16
  var __copyProps = (to, from, except, desc) => {
10
17
  if (from && typeof from === "object" || typeof from === "function") {
11
18
  for (let key of __getOwnPropNames(from))
@@ -23,59 +30,196 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
30
  mod
24
31
  ));
25
32
 
33
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js
34
+ var init_cjs_shims = __esm({
35
+ "../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js"() {
36
+ "use strict";
37
+ }
38
+ });
39
+
40
+ // src/auth/credential-store.ts
41
+ var credential_store_exports = {};
42
+ __export(credential_store_exports, {
43
+ CredentialStore: () => CredentialStore
44
+ });
45
+ function createConf(encryptionKey) {
46
+ return new import_conf.default({
47
+ projectName: "runtype-cli",
48
+ projectSuffix: "",
49
+ configName: "credentials",
50
+ encryptionKey,
51
+ cwd: CREDENTIALS_DIR
52
+ });
53
+ }
54
+ function isCorruptStoreError(error) {
55
+ if (error instanceof SyntaxError) return true;
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ return typeof message === "string" && message.includes("JSON");
58
+ }
59
+ var import_conf, import_crypto2, import_fs, import_os, import_path, CREDENTIALS_DIR, CREDENTIALS_FILENAME, CREDENTIALS_PATH, CredentialStore;
60
+ var init_credential_store = __esm({
61
+ "src/auth/credential-store.ts"() {
62
+ "use strict";
63
+ init_cjs_shims();
64
+ import_conf = __toESM(require("conf"));
65
+ import_crypto2 = __toESM(require("crypto"));
66
+ import_fs = __toESM(require("fs"));
67
+ import_os = __toESM(require("os"));
68
+ import_path = __toESM(require("path"));
69
+ CREDENTIALS_DIR = import_path.default.join(import_os.default.homedir(), ".runtype");
70
+ CREDENTIALS_FILENAME = "credentials.json";
71
+ CREDENTIALS_PATH = import_path.default.join(CREDENTIALS_DIR, CREDENTIALS_FILENAME);
72
+ CredentialStore = class {
73
+ config;
74
+ encryptionKey;
75
+ constructor() {
76
+ this.encryptionKey = this.getMachineKey();
77
+ try {
78
+ this.config = createConf(this.encryptionKey);
79
+ } catch (error) {
80
+ if (isCorruptStoreError(error)) {
81
+ try {
82
+ if (import_fs.default.existsSync(CREDENTIALS_PATH)) {
83
+ import_fs.default.unlinkSync(CREDENTIALS_PATH);
84
+ }
85
+ } catch {
86
+ }
87
+ this.config = createConf(this.encryptionKey);
88
+ } else {
89
+ throw error;
90
+ }
91
+ }
92
+ }
93
+ getMachineKey() {
94
+ const hostname = import_os.default.hostname();
95
+ const username = import_os.default.userInfo().username;
96
+ return import_crypto2.default.createHash("sha256").update(`runtype-cli-${hostname}-${username}`).digest("hex").substring(0, 32);
97
+ }
98
+ async saveCredentials(credentials) {
99
+ const configData = {
100
+ apiKey: this.encrypt(credentials.apiKey),
101
+ userId: credentials.userId,
102
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
103
+ lastUsed: (/* @__PURE__ */ new Date()).toISOString()
104
+ };
105
+ if (credentials.orgId !== void 0) {
106
+ configData.orgId = credentials.orgId;
107
+ }
108
+ if (credentials.apiUrl !== void 0) {
109
+ configData.apiUrl = credentials.apiUrl;
110
+ }
111
+ this.config.set(configData);
112
+ }
113
+ async getApiKey() {
114
+ const encrypted = this.config.get("apiKey");
115
+ if (!encrypted) return null;
116
+ this.config.set("lastUsed", (/* @__PURE__ */ new Date()).toISOString());
117
+ return this.decrypt(encrypted);
118
+ }
119
+ async getCredentials() {
120
+ const stored = this.config.store;
121
+ if (!stored.apiKey) return null;
122
+ return {
123
+ ...stored,
124
+ apiKey: this.decrypt(stored.apiKey)
125
+ };
126
+ }
127
+ async clearCredentials() {
128
+ this.config.clear();
129
+ }
130
+ async hasCredentials() {
131
+ return !!this.config.get("apiKey");
132
+ }
133
+ encrypt(text) {
134
+ const algorithm = "aes-256-cbc";
135
+ const key = Buffer.from(this.encryptionKey);
136
+ const iv = import_crypto2.default.randomBytes(16);
137
+ const cipher = import_crypto2.default.createCipheriv(algorithm, key, iv);
138
+ let encrypted = cipher.update(text, "utf8", "hex");
139
+ encrypted += cipher.final("hex");
140
+ return iv.toString("hex") + ":" + encrypted;
141
+ }
142
+ decrypt(text) {
143
+ const algorithm = "aes-256-cbc";
144
+ const key = Buffer.from(this.encryptionKey);
145
+ const [ivHex, encrypted] = text.split(":");
146
+ const iv = Buffer.from(ivHex, "hex");
147
+ const decipher = import_crypto2.default.createDecipheriv(algorithm, key, iv);
148
+ let decrypted = decipher.update(encrypted, "hex", "utf8");
149
+ decrypted += decipher.final("utf8");
150
+ return decrypted;
151
+ }
152
+ };
153
+ }
154
+ });
155
+
26
156
  // src/index.ts
27
- var import_commander9 = require("commander");
28
- var import_chalk10 = __toESM(require("chalk"));
157
+ init_cjs_shims();
158
+ var import_commander20 = require("commander");
159
+ var import_chalk24 = __toESM(require("chalk"));
29
160
  var import_dotenv = require("dotenv");
30
161
 
31
162
  // src/commands/auth.ts
163
+ init_cjs_shims();
32
164
  var import_commander = require("commander");
33
165
  var import_chalk = __toESM(require("chalk"));
34
166
  var import_ora = __toESM(require("ora"));
35
167
 
36
168
  // src/auth/oauth-manager.ts
169
+ init_cjs_shims();
37
170
  var import_open = __toESM(require("open"));
38
171
  var import_crypto = __toESM(require("crypto"));
39
172
 
40
173
  // src/auth/callback-server.ts
174
+ init_cjs_shims();
41
175
  var import_express = __toESM(require("express"));
42
176
  var CallbackServer = class {
43
177
  server = null;
44
178
  app;
179
+ codeResolve;
180
+ codeReject;
181
+ codePromise;
45
182
  constructor() {
46
183
  this.app = (0, import_express.default)();
184
+ this.codePromise = new Promise((resolve, reject) => {
185
+ this.codeResolve = resolve;
186
+ this.codeReject = reject;
187
+ });
188
+ this.app.get("/callback", (req, res) => {
189
+ const { code, error } = req.query;
190
+ if (error) {
191
+ res.send(this.errorHTML(error));
192
+ this.codeReject(new Error(error));
193
+ return;
194
+ }
195
+ if (!code) {
196
+ res.send(this.errorHTML("No authorization code received"));
197
+ this.codeReject(new Error("No authorization code received"));
198
+ return;
199
+ }
200
+ res.send(this.successHTML());
201
+ this.codeResolve(code);
202
+ setTimeout(() => this.stop(), 1e3);
203
+ });
204
+ this.app.get("/health", (_req, res) => {
205
+ res.json({ status: "ok" });
206
+ });
47
207
  }
48
208
  async start(port = 8765) {
49
- return new Promise((resolve, reject) => {
50
- this.app.get("/callback", (req, res) => {
51
- const { code, error } = req.query;
52
- if (error) {
53
- res.send(this.errorHTML(error));
54
- reject(new Error(error));
55
- return;
56
- }
57
- if (!code) {
58
- res.send(this.errorHTML("No authorization code received"));
59
- reject(new Error("No authorization code received"));
60
- return;
61
- }
62
- res.send(this.successHTML());
63
- resolve(code);
64
- setTimeout(() => this.stop(), 1e3);
65
- });
66
- this.app.get("/health", (_req, res) => {
67
- res.json({ status: "ok" });
68
- });
209
+ return new Promise((resolveStart, rejectStart) => {
69
210
  this.server = this.app.listen(port, () => {
70
- console.log(`Callback server listening on port ${port}`);
211
+ const address = this.server?.address();
212
+ const actualPort = address && typeof address === "object" && "port" in address ? address.port : port;
213
+ console.log(`Callback server listening on port ${actualPort}`);
214
+ resolveStart({ actualPort, codePromise: this.codePromise });
71
215
  });
72
216
  this.server.on("error", (error) => {
73
217
  if (error.code === "EADDRINUSE") {
74
218
  console.log(`Port ${port} is in use, trying ${port + 1}...`);
75
219
  this.server = null;
76
- this.start(port + 1).then(resolve).catch(reject);
220
+ this.start(port + 1).then(resolveStart).catch(rejectStart);
77
221
  } else {
78
- reject(error);
222
+ rejectStart(error);
79
223
  }
80
224
  });
81
225
  });
@@ -252,9 +396,9 @@ var OAuthManager = class {
252
396
  const codeVerifier = import_crypto.default.randomBytes(32).toString("base64url");
253
397
  const codeChallenge = import_crypto.default.createHash("sha256").update(codeVerifier).digest("base64url");
254
398
  const callbackServer = new CallbackServer();
255
- const port = await this.findAvailablePort();
256
- const codePromise = callbackServer.start(port);
257
- const redirectUri = `http://localhost:${port}/callback`;
399
+ const requestedPort = await this.findAvailablePort();
400
+ const { actualPort, codePromise } = await callbackServer.start(requestedPort);
401
+ const redirectUri = `http://localhost:${actualPort}/callback`;
258
402
  const authUrl = new URL(`${this.dashboardUrl.replace(/\/$/, "")}/${mode}`);
259
403
  authUrl.searchParams.set("redirect_uri", redirectUri);
260
404
  authUrl.searchParams.set("cli", "true");
@@ -266,7 +410,7 @@ var OAuthManager = class {
266
410
  console.log(`If the browser doesn't open, visit: ${authUrl}`);
267
411
  try {
268
412
  await (0, import_open.default)(authUrl.toString());
269
- } catch (error) {
413
+ } catch (_error) {
270
414
  console.log("Failed to open browser automatically. Please visit the URL above.");
271
415
  }
272
416
  console.log("\u23F3 Waiting for authentication...");
@@ -284,7 +428,11 @@ var OAuthManager = class {
284
428
  }
285
429
  };
286
430
 
431
+ // src/auth/api-key-manager.ts
432
+ init_cjs_shims();
433
+
287
434
  // src/config/env.ts
435
+ init_cjs_shims();
288
436
  function getApiUrl() {
289
437
  return process.env.RUNTYPE_API_URL || "https://api.runtype.com";
290
438
  }
@@ -363,7 +511,7 @@ var ApiKeyManager = class {
363
511
  }
364
512
  async getCurrentUser(apiKey, apiUrl) {
365
513
  const baseUrl = apiUrl || getApiUrl();
366
- const response = await fetch(`${baseUrl}/auth/me`, {
514
+ const response = await fetch(`${baseUrl}/${getApiVersion()}/auth/me`, {
367
515
  headers: {
368
516
  Authorization: `Bearer ${apiKey}`,
369
517
  "Content-Type": "application/json"
@@ -380,86 +528,8 @@ var ApiKeyManager = class {
380
528
  }
381
529
  };
382
530
 
383
- // src/auth/credential-store.ts
384
- var import_conf = __toESM(require("conf"));
385
- var import_crypto2 = __toESM(require("crypto"));
386
- var import_os = __toESM(require("os"));
387
- var import_path = __toESM(require("path"));
388
- var CredentialStore = class {
389
- config;
390
- encryptionKey;
391
- constructor() {
392
- this.encryptionKey = this.getMachineKey();
393
- this.config = new import_conf.default({
394
- projectName: "runtype-cli",
395
- projectSuffix: "",
396
- configName: "credentials",
397
- encryptionKey: this.encryptionKey,
398
- cwd: import_path.default.join(import_os.default.homedir(), ".runtype")
399
- });
400
- }
401
- getMachineKey() {
402
- const hostname = import_os.default.hostname();
403
- const username = import_os.default.userInfo().username;
404
- return import_crypto2.default.createHash("sha256").update(`runtype-cli-${hostname}-${username}`).digest("hex").substring(0, 32);
405
- }
406
- async saveCredentials(credentials) {
407
- const configData = {
408
- apiKey: this.encrypt(credentials.apiKey),
409
- userId: credentials.userId,
410
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
411
- lastUsed: (/* @__PURE__ */ new Date()).toISOString()
412
- };
413
- if (credentials.orgId !== void 0) {
414
- configData.orgId = credentials.orgId;
415
- }
416
- if (credentials.apiUrl !== void 0) {
417
- configData.apiUrl = credentials.apiUrl;
418
- }
419
- this.config.set(configData);
420
- }
421
- async getApiKey() {
422
- const encrypted = this.config.get("apiKey");
423
- if (!encrypted) return null;
424
- this.config.set("lastUsed", (/* @__PURE__ */ new Date()).toISOString());
425
- return this.decrypt(encrypted);
426
- }
427
- async getCredentials() {
428
- const stored = this.config.store;
429
- if (!stored.apiKey) return null;
430
- return {
431
- ...stored,
432
- apiKey: this.decrypt(stored.apiKey)
433
- };
434
- }
435
- async clearCredentials() {
436
- this.config.clear();
437
- }
438
- async hasCredentials() {
439
- return !!this.config.get("apiKey");
440
- }
441
- encrypt(text) {
442
- const algorithm = "aes-256-cbc";
443
- const key = Buffer.from(this.encryptionKey);
444
- const iv = import_crypto2.default.randomBytes(16);
445
- const cipher = import_crypto2.default.createCipheriv(algorithm, key, iv);
446
- let encrypted = cipher.update(text, "utf8", "hex");
447
- encrypted += cipher.final("hex");
448
- return iv.toString("hex") + ":" + encrypted;
449
- }
450
- decrypt(text) {
451
- const algorithm = "aes-256-cbc";
452
- const key = Buffer.from(this.encryptionKey);
453
- const [ivHex, encrypted] = text.split(":");
454
- const iv = Buffer.from(ivHex, "hex");
455
- const decipher = import_crypto2.default.createDecipheriv(algorithm, key, iv);
456
- let decrypted = decipher.update(encrypted, "hex", "utf8");
457
- decrypted += decipher.final("utf8");
458
- return decrypted;
459
- }
460
- };
461
-
462
531
  // src/commands/auth.ts
532
+ init_credential_store();
463
533
  var authCommand = new import_commander.Command("auth").description("Manage authentication");
464
534
  authCommand.command("signup").description("Create a new Runtype account").option("--api-url <url>", "Custom API URL").action(async (options) => {
465
535
  const spinner = (0, import_ora.default)("Initializing authentication...").start();
@@ -492,8 +562,9 @@ authCommand.command("signup").description("Create a new Runtype account").option
492
562
  console.log(" runtype records create --help");
493
563
  console.log(" runtype talk");
494
564
  } catch (error) {
565
+ const message = error instanceof Error ? error.message : "Unknown error";
495
566
  spinner.fail("Authentication failed");
496
- console.error(import_chalk.default.red(error.message));
567
+ console.error(import_chalk.default.red(message));
497
568
  process.exit(1);
498
569
  }
499
570
  });
@@ -512,14 +583,17 @@ authCommand.command("login").description("Login to existing account").option("--
512
583
  await store.saveCredentials({
513
584
  apiKey: options.apiKey,
514
585
  userId: userData.user_id,
586
+ // @snake-case-ok: API auth/me response
515
587
  orgId: userData.org_id ?? void 0,
588
+ // @snake-case-ok: API auth/me response
516
589
  apiUrl: options.apiUrl || getApiUrl()
517
590
  });
518
591
  spinner2.succeed("Logged in successfully!");
519
592
  console.log(import_chalk.default.green(`Welcome back! User ID: ${userData.user_id}`));
520
593
  } catch (error) {
594
+ const message = error instanceof Error ? error.message : "Unknown error";
521
595
  spinner2.fail("Login failed");
522
- console.error(import_chalk.default.red(error.message));
596
+ console.error(import_chalk.default.red(message));
523
597
  process.exit(1);
524
598
  }
525
599
  return;
@@ -548,8 +622,9 @@ authCommand.command("login").description("Login to existing account").option("--
548
622
  spinner.succeed("Logged in successfully!");
549
623
  console.log(import_chalk.default.green(`Welcome back! User ID: ${userId}`));
550
624
  } catch (error) {
625
+ const message = error instanceof Error ? error.message : "Unknown error";
551
626
  spinner.fail("Login failed");
552
- console.error(import_chalk.default.red(error.message));
627
+ console.error(import_chalk.default.red(message));
553
628
  process.exit(1);
554
629
  }
555
630
  });
@@ -573,7 +648,8 @@ authCommand.command("status").description("Show authentication status").action(a
573
648
  console.log(`Org ID: ${credentials.orgId || "none"}`);
574
649
  }
575
650
  } catch (error) {
576
- console.error(import_chalk.default.red("Error checking auth status:"), error.message);
651
+ const message = error instanceof Error ? error.message : "Unknown error";
652
+ console.error(import_chalk.default.red("Error checking auth status:"), message);
577
653
  }
578
654
  });
579
655
  authCommand.command("logout").description("Remove stored credentials").action(async () => {
@@ -586,7 +662,7 @@ authCommand.command("logout").description("Remove stored credentials").action(as
586
662
  await store.clearCredentials();
587
663
  console.log(import_chalk.default.green("\u2713 Logged out successfully"));
588
664
  });
589
- authCommand.command("whoami").description("Display current user information").action(async () => {
665
+ authCommand.command("whoami").description("Display current user information").option("--json", "Output as JSON").action(async (options) => {
590
666
  const store = new CredentialStore();
591
667
  const credentials = await store.getCredentials();
592
668
  if (!credentials || !credentials.apiKey) {
@@ -598,7 +674,38 @@ authCommand.command("whoami").description("Display current user information").ac
598
674
  try {
599
675
  const apiKeyManager = new ApiKeyManager();
600
676
  const user = await apiKeyManager.getCurrentUser(credentials.apiKey, credentials.apiUrl);
677
+ let billingInfo = null;
678
+ try {
679
+ const baseUrl = credentials.apiUrl || getApiUrl();
680
+ const billingResponse = await fetch(`${baseUrl}/${getApiVersion()}/billing/status`, {
681
+ headers: {
682
+ Authorization: `Bearer ${credentials.apiKey}`,
683
+ "Content-Type": "application/json"
684
+ }
685
+ });
686
+ if (billingResponse.ok) {
687
+ billingInfo = await billingResponse.json();
688
+ }
689
+ } catch {
690
+ }
601
691
  spinner.stop();
692
+ if (options.json) {
693
+ console.log(
694
+ JSON.stringify(
695
+ {
696
+ // @snake-case-ok: API auth/me response uses snake_case
697
+ userId: user.user_id,
698
+ // @snake-case-ok: API auth/me response uses snake_case
699
+ orgId: user.org_id,
700
+ apiUrl: credentials.apiUrl || getApiUrl(),
701
+ billing: billingInfo
702
+ },
703
+ null,
704
+ 2
705
+ )
706
+ );
707
+ return;
708
+ }
602
709
  console.log(import_chalk.default.cyan("Current User:"));
603
710
  console.log(` User ID: ${user.user_id}`);
604
711
  console.log(` Organization: ${user.org_id || "Personal"}`);
@@ -606,207 +713,609 @@ authCommand.command("whoami").description("Display current user information").ac
606
713
  console.log(` API URL: ${credentials.apiUrl || getApiUrl()}`);
607
714
  console.log(` Created: ${credentials.createdAt}`);
608
715
  console.log(` Last Used: ${credentials.lastUsed}`);
716
+ if (billingInfo) {
717
+ const plan = billingInfo.planName || billingInfo.plan;
718
+ if (plan) {
719
+ console.log(` Plan: ${import_chalk.default.green(plan)}`);
720
+ }
721
+ const usage = billingInfo.usage;
722
+ if (usage) {
723
+ const limit = usage.executionsLimit ? `/${usage.executionsLimit}` : "";
724
+ console.log(` Executions: ${usage.executionsUsed ?? 0}${limit}`);
725
+ }
726
+ }
609
727
  } catch (error) {
728
+ const message = error instanceof Error ? error.message : "Unknown error";
610
729
  spinner.fail("Failed to get user information");
611
- console.error(import_chalk.default.red(error.message));
730
+ console.error(import_chalk.default.red(message));
612
731
  console.log("\nYou may need to login again: runtype auth login");
613
732
  process.exit(1);
614
733
  }
615
734
  });
616
735
 
617
736
  // src/commands/flows.ts
737
+ init_cjs_shims();
618
738
  var import_commander2 = require("commander");
619
- var import_chalk2 = __toESM(require("chalk"));
739
+ var import_chalk5 = __toESM(require("chalk"));
740
+ var import_ora3 = __toESM(require("ora"));
741
+ var import_fs2 = require("fs");
742
+ var import_sdk = require("@runtypelabs/sdk");
743
+
744
+ // src/lib/ensure-auth.ts
745
+ init_cjs_shims();
746
+ var import_chalk3 = __toESM(require("chalk"));
620
747
  var import_ora2 = __toESM(require("ora"));
621
- var isFlowSummary = (value) => {
622
- if (!value || typeof value !== "object") {
623
- return false;
624
- }
625
- const record = value;
626
- return typeof record.id === "string" && typeof record.name === "string";
627
- };
628
- var isFlowListResponse = (value) => {
629
- if (!value || typeof value !== "object") {
630
- return false;
748
+ init_credential_store();
749
+
750
+ // src/lib/interactive.ts
751
+ init_cjs_shims();
752
+ var import_readline = __toESM(require("readline"));
753
+ var import_chalk2 = __toESM(require("chalk"));
754
+ async function promptText(message, options) {
755
+ const rl = import_readline.default.createInterface({
756
+ input: process.stdin,
757
+ output: process.stdout,
758
+ terminal: true
759
+ });
760
+ const suffix = options?.default ? ` (${options.default})` : "";
761
+ return new Promise((resolve) => {
762
+ rl.question(import_chalk2.default.cyan(`${message}${suffix}: `), (answer) => {
763
+ rl.close();
764
+ const trimmed = answer.trim();
765
+ resolve(trimmed || options?.default || "");
766
+ });
767
+ });
768
+ }
769
+ async function promptConfirm(message, options) {
770
+ const defaultYes = options?.default !== false;
771
+ const hint = defaultYes ? "Y/n" : "y/N";
772
+ const rl = import_readline.default.createInterface({
773
+ input: process.stdin,
774
+ output: process.stdout,
775
+ terminal: true
776
+ });
777
+ return new Promise((resolve) => {
778
+ rl.question(import_chalk2.default.cyan(`${message} (${hint}): `), (answer) => {
779
+ rl.close();
780
+ const trimmed = answer.trim().toLowerCase();
781
+ if (trimmed === "") {
782
+ resolve(defaultYes);
783
+ } else {
784
+ resolve(trimmed === "y" || trimmed === "yes");
785
+ }
786
+ });
787
+ });
788
+ }
789
+ async function promptSelect(message, choices) {
790
+ console.log(import_chalk2.default.cyan(`
791
+ ${message}`));
792
+ choices.forEach((choice, index) => {
793
+ const desc = choice.description ? import_chalk2.default.gray(` - ${choice.description}`) : "";
794
+ console.log(` ${import_chalk2.default.green(`${index + 1})`)} ${choice.label}${desc}`);
795
+ });
796
+ const rl = import_readline.default.createInterface({
797
+ input: process.stdin,
798
+ output: process.stdout,
799
+ terminal: true
800
+ });
801
+ return new Promise((resolve) => {
802
+ const ask = () => {
803
+ rl.question(import_chalk2.default.cyan(`
804
+ Select (1-${choices.length}): `), (answer) => {
805
+ const num = parseInt(answer.trim(), 10);
806
+ if (num >= 1 && num <= choices.length) {
807
+ rl.close();
808
+ resolve(choices[num - 1].value);
809
+ } else {
810
+ console.log(import_chalk2.default.red(`Please enter a number between 1 and ${choices.length}`));
811
+ ask();
812
+ }
813
+ });
814
+ };
815
+ ask();
816
+ });
817
+ }
818
+
819
+ // src/lib/ensure-auth.ts
820
+ async function ensureAuth(options) {
821
+ const store = new CredentialStore();
822
+ const apiKey = await store.getApiKey();
823
+ if (apiKey) {
824
+ return apiKey;
631
825
  }
632
- const record = value;
633
- if (record.data !== void 0) {
634
- if (!Array.isArray(record.data) || !record.data.every(isFlowSummary)) {
635
- return false;
826
+ console.log(import_chalk3.default.yellow("\nAuthentication required."));
827
+ const shouldLogin = await promptConfirm("Would you like to log in now?", { default: true });
828
+ if (!shouldLogin) {
829
+ console.log(import_chalk3.default.gray(`Run "runtype auth login" when you're ready.`));
830
+ if (options?.exitOnFailure !== false) {
831
+ process.exit(1);
636
832
  }
833
+ return null;
637
834
  }
638
- if (record.pagination !== void 0 && (typeof record.pagination !== "object" || record.pagination === null)) {
639
- return false;
835
+ const method = await promptSelect("How would you like to authenticate?", [
836
+ { label: "Browser login", value: "browser", description: "Sign in via your browser" },
837
+ { label: "API key", value: "apikey", description: "Paste an existing API key" }
838
+ ]);
839
+ if (method === "apikey") {
840
+ return handleApiKeyLogin(store, options?.apiUrl);
640
841
  }
641
- return true;
642
- };
643
- var flowsCommand = new import_commander2.Command("flows").description("Manage flows");
644
- flowsCommand.command("list").description("List all flows").option("--json", "Output as JSON").action(async (options) => {
645
- const store = new CredentialStore();
646
- const apiKey = await store.getApiKey();
647
- if (!apiKey) {
648
- console.log(import_chalk2.default.yellow("Not authenticated. Please run: runtype auth login"));
649
- process.exit(1);
842
+ return handleBrowserLogin(store, options?.apiUrl);
843
+ }
844
+ async function handleApiKeyLogin(store, apiUrl) {
845
+ const key = await promptText("Enter your API key");
846
+ if (!key) {
847
+ console.log(import_chalk3.default.red("No API key provided."));
848
+ return null;
650
849
  }
651
- const spinner = (0, import_ora2.default)("Fetching flows...").start();
850
+ const spinner = (0, import_ora2.default)("Validating API key...").start();
652
851
  try {
653
- const response = await fetch(`${getApiUrl()}/flows`, {
654
- headers: {
655
- Authorization: `Bearer ${apiKey}`,
656
- "Content-Type": "application/json"
657
- }
658
- });
659
- if (!response.ok) {
660
- throw new Error(`Failed to fetch flows: ${response.statusText}`);
661
- }
662
- const data = await response.json();
663
- spinner.stop();
664
- if (options.json) {
665
- console.log(JSON.stringify(data, null, 2));
666
- } else {
667
- if (!isFlowListResponse(data)) {
668
- throw new Error("Unexpected flows response format");
669
- }
670
- console.log(import_chalk2.default.cyan("Your Flows:"));
671
- const flowsArray = data.data ?? [];
672
- if (flowsArray.length > 0) {
673
- flowsArray.forEach((flow) => {
674
- console.log(` ${import_chalk2.default.green(flow.id)} - ${flow.name}`);
675
- if (flow.description) {
676
- console.log(` ${import_chalk2.default.gray(flow.description)}`);
677
- }
678
- });
679
- const total = data.pagination?.total_count ?? data.pagination?.total;
680
- if (typeof total === "number") {
681
- console.log(import_chalk2.default.dim(`
682
- Total: ${total} flows`));
683
- }
684
- } else {
685
- console.log(import_chalk2.default.gray(" No flows found"));
686
- }
852
+ const apiKeyManager = new ApiKeyManager();
853
+ const isValid = await apiKeyManager.validateApiKey(key, apiUrl);
854
+ if (!isValid) {
855
+ spinner.fail("Invalid API key");
856
+ return null;
687
857
  }
858
+ const userData = await apiKeyManager.getCurrentUser(key, apiUrl);
859
+ await store.saveCredentials({
860
+ apiKey: key,
861
+ // @snake-case-ok: API auth/me response uses snake_case
862
+ userId: userData.user_id,
863
+ // @snake-case-ok: API auth/me response uses snake_case
864
+ orgId: userData.org_id ?? void 0,
865
+ apiUrl: apiUrl || getApiUrl()
866
+ });
867
+ spinner.succeed("Logged in successfully!");
868
+ return key;
688
869
  } catch (error) {
689
870
  const message = error instanceof Error ? error.message : "Unknown error";
690
- spinner.fail("Failed to fetch flows");
691
- console.error(import_chalk2.default.red(message));
692
- process.exit(1);
871
+ spinner.fail("Login failed");
872
+ console.error(import_chalk3.default.red(message));
873
+ return null;
693
874
  }
694
- });
695
- flowsCommand.command("run <id>").description("Execute a flow").option("-r, --record <id>", "Record ID to run with").option("--stream", "Stream the response", true).action(async (flowId, options) => {
696
- void options;
697
- const store = new CredentialStore();
698
- const apiKey = await store.getApiKey();
699
- if (!apiKey) {
700
- console.log(import_chalk2.default.yellow("Not authenticated. Please run: runtype auth login"));
701
- process.exit(1);
875
+ }
876
+ async function handleBrowserLogin(store, apiUrl) {
877
+ const spinner = (0, import_ora2.default)("Initializing authentication...").start();
878
+ try {
879
+ const oauth = new OAuthManager({
880
+ clerkPublishableKey: getClerkPublishableKey(),
881
+ dashboardUrl: getDashboardUrl()
882
+ });
883
+ spinner.text = "Waiting for browser authentication...";
884
+ const sessionToken = await oauth.authenticate("sign-in");
885
+ spinner.text = "Getting API key...";
886
+ const apiKeyManager = new ApiKeyManager();
887
+ const { key, userId, orgId } = await apiKeyManager.exchangeSessionForApiKey(
888
+ sessionToken,
889
+ apiUrl || getApiUrl()
890
+ );
891
+ spinner.text = "Storing credentials...";
892
+ await store.saveCredentials({
893
+ apiKey: key,
894
+ userId,
895
+ orgId,
896
+ apiUrl: apiUrl || getApiUrl()
897
+ });
898
+ spinner.succeed("Logged in successfully!");
899
+ return key;
900
+ } catch (error) {
901
+ const message = error instanceof Error ? error.message : "Unknown error";
902
+ spinner.fail("Login failed");
903
+ console.error(import_chalk3.default.red(message));
904
+ return null;
702
905
  }
703
- console.log(import_chalk2.default.cyan(`Running flow ${flowId}...`));
704
- console.log(import_chalk2.default.gray("Implementation coming soon"));
705
- });
706
- flowsCommand.command("create").description("Create a new flow").action(async () => {
707
- console.log(import_chalk2.default.cyan("Interactive flow creation coming soon"));
708
- });
709
- flowsCommand.command("delete <id>").description("Delete a flow").action(async (flowId) => {
710
- console.log(import_chalk2.default.cyan(`Deleting flow ${flowId}...`));
711
- console.log(import_chalk2.default.gray("Implementation coming soon"));
712
- });
906
+ }
713
907
 
714
- // src/commands/records.ts
715
- var import_commander3 = require("commander");
716
- var import_chalk3 = __toESM(require("chalk"));
717
- var import_ora3 = __toESM(require("ora"));
718
- var isRecordSummary = (value) => {
719
- if (!value || typeof value !== "object") {
720
- return false;
908
+ // src/lib/api-client.ts
909
+ init_cjs_shims();
910
+ var ApiError = class extends Error {
911
+ constructor(statusCode, message) {
912
+ super(message);
913
+ this.statusCode = statusCode;
914
+ this.name = "ApiError";
721
915
  }
722
- const record = value;
723
- return typeof record.id === "string" && typeof record.name === "string" && typeof record.type === "string";
724
916
  };
725
- var isRecordListResponse = (value) => {
726
- if (!value || typeof value !== "object") {
727
- return false;
917
+ var ApiClient = class {
918
+ baseUrl;
919
+ apiKey;
920
+ constructor(apiKey, baseUrl) {
921
+ this.apiKey = apiKey;
922
+ this.baseUrl = baseUrl || getApiUrl();
728
923
  }
729
- const record = value;
730
- if (record.data !== void 0) {
731
- if (!Array.isArray(record.data) || !record.data.every(isRecordSummary)) {
732
- return false;
924
+ /** Prefix path with API version (e.g. /v1) so all requests hit versioned routes. */
925
+ path(path5) {
926
+ const version = getApiVersion();
927
+ const p = path5.startsWith("/") ? path5 : `/${path5}`;
928
+ return p.startsWith(`/${version}/`) ? p : `/${version}${p}`;
929
+ }
930
+ headers(extra) {
931
+ return {
932
+ Authorization: `Bearer ${this.apiKey}`,
933
+ "Content-Type": "application/json",
934
+ ...extra
935
+ };
936
+ }
937
+ async handleResponse(response) {
938
+ if (!response.ok) {
939
+ let message = `${response.status} ${response.statusText}`;
940
+ try {
941
+ const contentType = response.headers.get("content-type") || "";
942
+ if (contentType.includes("application/json")) {
943
+ const body = await response.json();
944
+ message = body.error || body.message || message;
945
+ } else {
946
+ const text = await response.text();
947
+ if (text) message = text;
948
+ }
949
+ } catch {
950
+ }
951
+ throw new ApiError(response.status, message);
733
952
  }
953
+ return response.json();
734
954
  }
735
- if (record.pagination !== void 0 && (typeof record.pagination !== "object" || record.pagination === null)) {
736
- return false;
955
+ async get(path5, params) {
956
+ const url = new URL(this.path(path5), this.baseUrl);
957
+ if (params) {
958
+ for (const [key, value] of Object.entries(params)) {
959
+ if (value !== void 0 && value !== "") {
960
+ url.searchParams.append(key, value);
961
+ }
962
+ }
963
+ }
964
+ const response = await fetch(url.toString(), {
965
+ headers: this.headers()
966
+ });
967
+ return this.handleResponse(response);
737
968
  }
738
- return true;
739
- };
740
- var isRecordCreateResponse = (value) => {
741
- if (!value || typeof value !== "object") {
742
- return false;
969
+ async post(path5, body) {
970
+ const response = await fetch(new URL(this.path(path5), this.baseUrl).toString(), {
971
+ method: "POST",
972
+ headers: this.headers(),
973
+ body: body !== void 0 ? JSON.stringify(body) : void 0
974
+ });
975
+ return this.handleResponse(response);
743
976
  }
744
- const record = value;
745
- return typeof record.id === "string" && typeof record.name === "string" && typeof record.type === "string";
746
- };
747
- var recordsCommand = new import_commander3.Command("records").description("Manage records");
748
- recordsCommand.command("list").description("List all records").option("--type <type>", "Filter by record type").option("--limit <n>", "Limit number of results", "20").option("--json", "Output as JSON").action(async (options) => {
749
- const store = new CredentialStore();
750
- const apiKey = await store.getApiKey();
751
- if (!apiKey) {
752
- console.log(import_chalk3.default.yellow("Not authenticated. Please run: runtype auth login"));
753
- process.exit(1);
977
+ async put(path5, body) {
978
+ const response = await fetch(new URL(this.path(path5), this.baseUrl).toString(), {
979
+ method: "PUT",
980
+ headers: this.headers(),
981
+ body: body !== void 0 ? JSON.stringify(body) : void 0
982
+ });
983
+ return this.handleResponse(response);
754
984
  }
755
- const spinner = (0, import_ora3.default)("Fetching records...").start();
756
- try {
757
- const params = new URLSearchParams();
758
- if (options.type) params.append("type", options.type);
759
- params.append("limit", options.limit);
760
- const response = await fetch(`${getApiUrl()}/${getApiVersion()}/records?${params}`, {
761
- headers: {
762
- Authorization: `Bearer ${apiKey}`,
763
- "Content-Type": "application/json"
985
+ async patch(path5, body) {
986
+ const response = await fetch(new URL(this.path(path5), this.baseUrl).toString(), {
987
+ method: "PATCH",
988
+ headers: this.headers(),
989
+ body: body !== void 0 ? JSON.stringify(body) : void 0
990
+ });
991
+ return this.handleResponse(response);
992
+ }
993
+ async delete(path5) {
994
+ const response = await fetch(new URL(this.path(path5), this.baseUrl).toString(), {
995
+ method: "DELETE",
996
+ headers: this.headers()
997
+ });
998
+ if (!response.ok) {
999
+ let message = `${response.status} ${response.statusText}`;
1000
+ try {
1001
+ const body = await response.json();
1002
+ message = body.error || body.message || message;
1003
+ } catch {
764
1004
  }
1005
+ throw new ApiError(response.status, message);
1006
+ }
1007
+ }
1008
+ async stream(path5, body) {
1009
+ const response = await fetch(new URL(this.path(path5), this.baseUrl).toString(), {
1010
+ method: "POST",
1011
+ headers: this.headers({ Accept: "text/event-stream" }),
1012
+ body: body !== void 0 ? JSON.stringify(body) : void 0
765
1013
  });
766
1014
  if (!response.ok) {
767
- throw new Error(`Failed to fetch records: ${response.statusText}`);
1015
+ let message = `${response.status} ${response.statusText}`;
1016
+ try {
1017
+ const text = await response.text();
1018
+ if (text) message = text;
1019
+ } catch {
1020
+ }
1021
+ throw new ApiError(response.status, message);
768
1022
  }
769
- const data = await response.json();
1023
+ return response;
1024
+ }
1025
+ };
1026
+
1027
+ // src/lib/output.ts
1028
+ init_cjs_shims();
1029
+ var import_chalk4 = __toESM(require("chalk"));
1030
+ function printJson(data) {
1031
+ console.log(JSON.stringify(data, null, 2));
1032
+ }
1033
+ function printList(items, options) {
1034
+ console.log(import_chalk4.default.cyan(`${options.title}:`));
1035
+ if (items.length === 0) {
1036
+ console.log(import_chalk4.default.gray(` ${options.emptyMessage || "None found"}`));
1037
+ return;
1038
+ }
1039
+ for (const item of items) {
1040
+ const parts = [];
1041
+ for (const col of options.columns) {
1042
+ const value = item[col.key];
1043
+ if (value === void 0 || value === null) continue;
1044
+ const str = String(value);
1045
+ const colorFn = col.color ? import_chalk4.default[col.color] : (s) => s;
1046
+ if (col.label) {
1047
+ parts.push(`${col.label}: ${colorFn(str)}`);
1048
+ } else {
1049
+ parts.push(colorFn(str));
1050
+ }
1051
+ }
1052
+ console.log(` ${parts.join(" - ")}`);
1053
+ }
1054
+ if (options.total !== void 0) {
1055
+ console.log(import_chalk4.default.dim(`
1056
+ Total: ${options.total}`));
1057
+ }
1058
+ }
1059
+ function printDetail(title, fields) {
1060
+ console.log(import_chalk4.default.cyan(`${title}:`));
1061
+ for (const field of fields) {
1062
+ if (field.value === void 0 || field.value === null) continue;
1063
+ const str = typeof field.value === "object" ? JSON.stringify(field.value) : String(field.value);
1064
+ console.log(` ${import_chalk4.default.gray(field.label + ":")} ${str}`);
1065
+ }
1066
+ }
1067
+ function getTotalCount(pagination) {
1068
+ return pagination?.totalCount ?? pagination?.total ?? void 0;
1069
+ }
1070
+
1071
+ // src/commands/flows.ts
1072
+ var flowsCommand = new import_commander2.Command("flows").description("Manage flows");
1073
+ flowsCommand.command("list").description("List all flows").option("--json", "Output as JSON").action(async (options) => {
1074
+ const apiKey = await ensureAuth();
1075
+ if (!apiKey) return;
1076
+ const spinner = (0, import_ora3.default)("Fetching flows...").start();
1077
+ try {
1078
+ const client = new ApiClient(apiKey);
1079
+ const data = await client.get("/flows");
1080
+ spinner.stop();
1081
+ if (options.json) {
1082
+ printJson(data);
1083
+ } else {
1084
+ const flows = data.data ?? [];
1085
+ printList(flows, {
1086
+ title: "Your Flows",
1087
+ columns: [
1088
+ { key: "id", color: "green" },
1089
+ { key: "name" },
1090
+ { key: "description", color: "gray" }
1091
+ ],
1092
+ emptyMessage: "No flows found",
1093
+ total: getTotalCount(data.pagination)
1094
+ });
1095
+ }
1096
+ } catch (error) {
1097
+ const message = error instanceof Error ? error.message : "Unknown error";
1098
+ spinner.fail("Failed to fetch flows");
1099
+ console.error(import_chalk5.default.red(message));
1100
+ process.exit(1);
1101
+ }
1102
+ });
1103
+ flowsCommand.command("get <id>").description("Get flow details").option("--json", "Output as JSON").action(async (id, options) => {
1104
+ const apiKey = await ensureAuth();
1105
+ if (!apiKey) return;
1106
+ const spinner = (0, import_ora3.default)("Fetching flow...").start();
1107
+ try {
1108
+ const client = new ApiClient(apiKey);
1109
+ const data = await client.get(`/flows/${id}`);
770
1110
  spinner.stop();
771
1111
  if (options.json) {
772
- console.log(JSON.stringify(data, null, 2));
1112
+ printJson(data);
773
1113
  } else {
774
- if (!isRecordListResponse(data)) {
775
- throw new Error("Unexpected records response format");
776
- }
777
- console.log(import_chalk3.default.cyan("Your Records:"));
778
- const recordsArray = data.data ?? [];
779
- if (recordsArray.length > 0) {
780
- recordsArray.forEach((record) => {
781
- console.log(` ${import_chalk3.default.green(record.id)} - ${record.name} (${record.type})`);
782
- if (record.metadata && Object.keys(record.metadata).length > 0) {
783
- console.log(` ${import_chalk3.default.gray(JSON.stringify(record.metadata))}`);
1114
+ printDetail("Flow", [
1115
+ { label: "ID", value: data.id },
1116
+ { label: "Name", value: data.name },
1117
+ { label: "Description", value: data.description },
1118
+ { label: "Steps", value: data.steps?.length }
1119
+ ]);
1120
+ }
1121
+ } catch (error) {
1122
+ const message = error instanceof Error ? error.message : "Unknown error";
1123
+ spinner.fail("Failed to fetch flow");
1124
+ console.error(import_chalk5.default.red(message));
1125
+ process.exit(1);
1126
+ }
1127
+ });
1128
+ flowsCommand.command("run <id>").description("Execute a flow via dispatch").option("-r, --record <id>", "Record ID to run with").option("-m, --message <text>", "Message to send").option("--stream", "Stream the response (default)", true).option("--no-stream", "Wait for complete response").option("--json", "Output as JSON").action(
1129
+ async (flowId, options) => {
1130
+ const apiKey = await ensureAuth();
1131
+ if (!apiKey) return;
1132
+ const client = new ApiClient(apiKey);
1133
+ const payload = {
1134
+ flow: { id: flowId }
1135
+ };
1136
+ if (options.record) {
1137
+ payload.record = { id: options.record };
1138
+ }
1139
+ if (options.message) {
1140
+ payload.messages = [{ role: "user", content: options.message }];
1141
+ }
1142
+ if (options.stream) {
1143
+ const spinner = (0, import_ora3.default)("Starting flow...").start();
1144
+ try {
1145
+ const response = await client.stream("/dispatch", payload);
1146
+ spinner.stop();
1147
+ const callbacks = {
1148
+ onStepChunk: (chunk) => {
1149
+ process.stdout.write(chunk);
1150
+ },
1151
+ onFlowComplete: (event) => {
1152
+ if (options.json) {
1153
+ console.log();
1154
+ printJson(event);
1155
+ }
1156
+ },
1157
+ onError: (err) => {
1158
+ console.error(import_chalk5.default.red(`
1159
+ Error: ${err.message}`));
784
1160
  }
785
- });
786
- const total = data.pagination?.total_count ?? data.pagination?.total;
787
- if (typeof total === "number") {
788
- console.log(import_chalk3.default.dim(`
789
- Total: ${total} records`));
1161
+ };
1162
+ await (0, import_sdk.processStream)(response, callbacks);
1163
+ console.log();
1164
+ } catch (error) {
1165
+ spinner.fail("Flow execution failed");
1166
+ const message = error instanceof Error ? error.message : "Unknown error";
1167
+ console.error(import_chalk5.default.red(message));
1168
+ process.exit(1);
1169
+ }
1170
+ } else {
1171
+ const spinner = (0, import_ora3.default)("Executing flow...").start();
1172
+ try {
1173
+ payload.streamResponse = false;
1174
+ const result = await client.post("/dispatch", payload);
1175
+ spinner.succeed("Flow execution complete");
1176
+ printJson(result);
1177
+ } catch (error) {
1178
+ spinner.fail("Flow execution failed");
1179
+ const message = error instanceof Error ? error.message : "Unknown error";
1180
+ console.error(import_chalk5.default.red(message));
1181
+ process.exit(1);
1182
+ }
1183
+ }
1184
+ }
1185
+ );
1186
+ flowsCommand.command("create").description("Create a new flow").requiredOption("-n, --name <name>", "Flow name").option("-d, --description <desc>", "Flow description").option("--from-file <file>", "Import flow from JSON file").option("--json", "Output as JSON").action(
1187
+ async (options) => {
1188
+ const apiKey = await ensureAuth();
1189
+ if (!apiKey) return;
1190
+ const spinner = (0, import_ora3.default)("Creating flow...").start();
1191
+ try {
1192
+ const client = new ApiClient(apiKey);
1193
+ let body = {
1194
+ name: options.name,
1195
+ description: options.description
1196
+ };
1197
+ if (options.fromFile) {
1198
+ try {
1199
+ const fileContent = JSON.parse((0, import_fs2.readFileSync)(options.fromFile, "utf-8"));
1200
+ if (fileContent.flow) {
1201
+ body = { ...fileContent.flow, name: options.name || fileContent.flow.name };
1202
+ } else {
1203
+ body = { ...fileContent, name: options.name || fileContent.name };
1204
+ }
1205
+ } catch (error) {
1206
+ const msg = error instanceof Error ? error.message : "Unknown error";
1207
+ spinner.fail("Failed to read flow file");
1208
+ console.error(import_chalk5.default.red(msg));
1209
+ process.exit(1);
790
1210
  }
1211
+ }
1212
+ const data = await client.post("/flows", body);
1213
+ spinner.succeed("Flow created");
1214
+ if (options.json) {
1215
+ printJson(data);
791
1216
  } else {
792
- console.log(import_chalk3.default.gray(" No records found"));
1217
+ console.log(` ID: ${import_chalk5.default.green(data.id)}`);
1218
+ console.log(` Name: ${data.name}`);
1219
+ }
1220
+ } catch (error) {
1221
+ const message = error instanceof Error ? error.message : "Unknown error";
1222
+ spinner.fail("Failed to create flow");
1223
+ console.error(import_chalk5.default.red(message));
1224
+ process.exit(1);
1225
+ }
1226
+ }
1227
+ );
1228
+ flowsCommand.command("delete <id>").description("Delete a flow").action(async (id) => {
1229
+ const apiKey = await ensureAuth();
1230
+ if (!apiKey) return;
1231
+ const spinner = (0, import_ora3.default)("Deleting flow...").start();
1232
+ try {
1233
+ const client = new ApiClient(apiKey);
1234
+ await client.delete(`/flows/${id}`);
1235
+ spinner.succeed("Flow deleted");
1236
+ } catch (error) {
1237
+ const message = error instanceof Error ? error.message : "Unknown error";
1238
+ spinner.fail("Failed to delete flow");
1239
+ console.error(import_chalk5.default.red(message));
1240
+ process.exit(1);
1241
+ }
1242
+ });
1243
+
1244
+ // src/commands/records.ts
1245
+ init_cjs_shims();
1246
+ var import_commander3 = require("commander");
1247
+ var import_chalk6 = __toESM(require("chalk"));
1248
+ var import_ora4 = __toESM(require("ora"));
1249
+ var import_fs3 = require("fs");
1250
+ var recordsCommand = new import_commander3.Command("records").description("Manage records");
1251
+ recordsCommand.command("list").description("List all records").option("--type <type>", "Filter by record type").option("--limit <n>", "Limit number of results", "20").option("--json", "Output as JSON").action(async (options) => {
1252
+ const apiKey = await ensureAuth();
1253
+ if (!apiKey) return;
1254
+ const spinner = (0, import_ora4.default)("Fetching records...").start();
1255
+ try {
1256
+ const client = new ApiClient(apiKey);
1257
+ const params = { limit: options.limit };
1258
+ if (options.type) params.type = options.type;
1259
+ const data = await client.get("/records", params);
1260
+ spinner.stop();
1261
+ if (options.json) {
1262
+ printJson(data);
1263
+ } else {
1264
+ const records = data.data ?? [];
1265
+ if (records.length === 0) {
1266
+ console.log(import_chalk6.default.gray("No records found"));
1267
+ return;
1268
+ }
1269
+ console.log(import_chalk6.default.cyan("Your Records:"));
1270
+ for (const record of records) {
1271
+ console.log(` ${import_chalk6.default.green(record.id)} - ${record.name} (${record.type})`);
1272
+ if (record.metadata && Object.keys(record.metadata).length > 0) {
1273
+ console.log(` ${import_chalk6.default.gray(JSON.stringify(record.metadata))}`);
1274
+ }
1275
+ }
1276
+ const total = getTotalCount(data.pagination);
1277
+ if (total !== void 0) {
1278
+ console.log(import_chalk6.default.dim(`
1279
+ Total: ${total} records`));
793
1280
  }
794
1281
  }
795
1282
  } catch (error) {
796
1283
  const message = error instanceof Error ? error.message : "Unknown error";
797
1284
  spinner.fail("Failed to fetch records");
798
- console.error(import_chalk3.default.red(message));
1285
+ console.error(import_chalk6.default.red(message));
799
1286
  process.exit(1);
800
1287
  }
801
1288
  });
802
- recordsCommand.command("create").description("Create a new record").requiredOption("-n, --name <name>", "Record name").requiredOption("-t, --type <type>", "Record type").option("-m, --metadata <json>", "Metadata as JSON string").action(async (options) => {
803
- const store = new CredentialStore();
804
- const apiKey = await store.getApiKey();
805
- if (!apiKey) {
806
- console.log(import_chalk3.default.yellow("Not authenticated. Please run: runtype auth login"));
1289
+ recordsCommand.command("get <id>").description("Get record details").option("--json", "Output as JSON").action(async (id, options) => {
1290
+ const apiKey = await ensureAuth();
1291
+ if (!apiKey) return;
1292
+ const spinner = (0, import_ora4.default)("Fetching record...").start();
1293
+ try {
1294
+ const client = new ApiClient(apiKey);
1295
+ const data = await client.get(`/records/${id}`);
1296
+ spinner.stop();
1297
+ if (options.json) {
1298
+ printJson(data);
1299
+ } else {
1300
+ console.log(import_chalk6.default.cyan("Record:"));
1301
+ console.log(` ID: ${import_chalk6.default.green(data.id)}`);
1302
+ console.log(` Name: ${data.name}`);
1303
+ console.log(` Type: ${data.type}`);
1304
+ if (data.metadata) {
1305
+ console.log(` Metadata: ${JSON.stringify(data.metadata, null, 2)}`);
1306
+ }
1307
+ }
1308
+ } catch (error) {
1309
+ const message = error instanceof Error ? error.message : "Unknown error";
1310
+ spinner.fail("Failed to fetch record");
1311
+ console.error(import_chalk6.default.red(message));
807
1312
  process.exit(1);
808
1313
  }
809
- const spinner = (0, import_ora3.default)("Creating record...").start();
1314
+ });
1315
+ recordsCommand.command("create").description("Create a new record").requiredOption("-n, --name <name>", "Record name").requiredOption("-t, --type <type>", "Record type").option("-m, --metadata <json>", "Metadata as JSON string").option("--json", "Output as JSON").action(async (options) => {
1316
+ const apiKey = await ensureAuth();
1317
+ if (!apiKey) return;
1318
+ const spinner = (0, import_ora4.default)("Creating record...").start();
810
1319
  try {
811
1320
  let metadata = {};
812
1321
  if (options.metadata) {
@@ -816,235 +1325,317 @@ recordsCommand.command("create").description("Create a new record").requiredOpti
816
1325
  throw new Error("Invalid JSON in metadata");
817
1326
  }
818
1327
  }
819
- const response = await fetch(`${getApiUrl()}/${getApiVersion()}/records`, {
820
- method: "POST",
821
- headers: {
822
- Authorization: `Bearer ${apiKey}`,
823
- "Content-Type": "application/json"
824
- },
825
- body: JSON.stringify({
826
- name: options.name,
827
- type: options.type,
828
- metadata
829
- })
1328
+ const client = new ApiClient(apiKey);
1329
+ const data = await client.post("/records", {
1330
+ name: options.name,
1331
+ type: options.type,
1332
+ metadata
830
1333
  });
831
- if (!response.ok) {
832
- const error = await response.text();
833
- throw new Error(`Failed to create record: ${error}`);
834
- }
835
- const data = await response.json();
836
- if (!isRecordCreateResponse(data)) {
837
- throw new Error("Unexpected create record response format");
1334
+ spinner.succeed("Record created");
1335
+ if (options.json) {
1336
+ printJson(data);
1337
+ } else {
1338
+ console.log(` ID: ${import_chalk6.default.green(data.id)}`);
1339
+ console.log(` Name: ${data.name}`);
1340
+ console.log(` Type: ${data.type}`);
838
1341
  }
839
- spinner.succeed("Record created successfully!");
840
- console.log(import_chalk3.default.green(`Record ID: ${data.id}`));
841
- console.log(import_chalk3.default.gray(`Name: ${data.name}`));
842
- console.log(import_chalk3.default.gray(`Type: ${data.type}`));
843
1342
  } catch (error) {
844
1343
  const message = error instanceof Error ? error.message : "Unknown error";
845
1344
  spinner.fail("Failed to create record");
846
- console.error(import_chalk3.default.red(message));
1345
+ console.error(import_chalk6.default.red(message));
847
1346
  process.exit(1);
848
1347
  }
849
1348
  });
850
- recordsCommand.command("bulk").description("Bulk operations on records").action(async () => {
851
- console.log(import_chalk3.default.cyan("Bulk operations coming soon"));
852
- });
853
- recordsCommand.command("export").description("Export records").option("--format <format>", "Export format (json, csv)", "json").action(async (options) => {
854
- console.log(import_chalk3.default.cyan(`Exporting records as ${options.format}...`));
855
- console.log(import_chalk3.default.gray("Implementation coming soon"));
856
- });
857
-
858
- // src/commands/prompts.ts
859
- var import_commander4 = require("commander");
860
- var import_chalk4 = __toESM(require("chalk"));
861
- var import_ora4 = __toESM(require("ora"));
862
- var isPromptSummary = (value) => {
863
- if (!value || typeof value !== "object") {
864
- return false;
865
- }
866
- const record = value;
867
- return typeof record.id === "string" && typeof record.name === "string";
868
- };
869
- var isPromptListResponse = (value) => {
870
- if (!value || typeof value !== "object") {
871
- return false;
1349
+ recordsCommand.command("delete <id>").description("Delete a record").action(async (id) => {
1350
+ const apiKey = await ensureAuth();
1351
+ if (!apiKey) return;
1352
+ const spinner = (0, import_ora4.default)("Deleting record...").start();
1353
+ try {
1354
+ const client = new ApiClient(apiKey);
1355
+ await client.delete(`/records/${id}`);
1356
+ spinner.succeed("Record deleted");
1357
+ } catch (error) {
1358
+ const message = error instanceof Error ? error.message : "Unknown error";
1359
+ spinner.fail("Failed to delete record");
1360
+ console.error(import_chalk6.default.red(message));
1361
+ process.exit(1);
872
1362
  }
873
- const record = value;
874
- if (record.data !== void 0) {
875
- if (!Array.isArray(record.data) || !record.data.every(isPromptSummary)) {
876
- return false;
1363
+ });
1364
+ recordsCommand.command("export").description("Export records to a file").option("--type <type>", "Filter by record type").option("--limit <n>", "Maximum records to export", "100").option("-o, --output <file>", "Output file path").option("--format <format>", "Export format (json, csv)", "json").action(
1365
+ async (options) => {
1366
+ const apiKey = await ensureAuth();
1367
+ if (!apiKey) return;
1368
+ const spinner = (0, import_ora4.default)("Exporting records...").start();
1369
+ try {
1370
+ const client = new ApiClient(apiKey);
1371
+ const params = { limit: options.limit };
1372
+ if (options.type) params.type = options.type;
1373
+ const data = await client.get("/records", params);
1374
+ const records = data.data ?? [];
1375
+ if (records.length === 0) {
1376
+ spinner.warn("No records to export");
1377
+ return;
1378
+ }
1379
+ let content;
1380
+ if (options.format === "csv") {
1381
+ const headers = ["id", "name", "type", "metadata"];
1382
+ const rows = records.map((r) => [
1383
+ r.id,
1384
+ r.name,
1385
+ r.type,
1386
+ r.metadata ? JSON.stringify(r.metadata) : ""
1387
+ ]);
1388
+ content = [headers.join(","), ...rows.map((r) => r.map(csvEscape).join(","))].join("\n");
1389
+ } else {
1390
+ content = JSON.stringify(records, null, 2);
1391
+ }
1392
+ const filename = options.output || `records-export-${Date.now()}.${options.format === "csv" ? "csv" : "json"}`;
1393
+ (0, import_fs3.writeFileSync)(filename, content);
1394
+ spinner.succeed(`Exported ${records.length} records to ${filename}`);
1395
+ } catch (error) {
1396
+ const message = error instanceof Error ? error.message : "Unknown error";
1397
+ spinner.fail("Failed to export records");
1398
+ console.error(import_chalk6.default.red(message));
1399
+ process.exit(1);
877
1400
  }
878
1401
  }
879
- if (record.pagination !== void 0 && (typeof record.pagination !== "object" || record.pagination === null)) {
880
- return false;
1402
+ );
1403
+ function csvEscape(value) {
1404
+ if (value.includes(",") || value.includes('"') || value.includes("\n")) {
1405
+ return `"${value.replace(/"/g, '""')}"`;
881
1406
  }
882
- return true;
883
- };
1407
+ return value;
1408
+ }
1409
+
1410
+ // src/commands/prompts.ts
1411
+ init_cjs_shims();
1412
+ var import_commander4 = require("commander");
1413
+ var import_chalk7 = __toESM(require("chalk"));
1414
+ var import_ora5 = __toESM(require("ora"));
1415
+ var import_sdk2 = require("@runtypelabs/sdk");
884
1416
  var promptsCommand = new import_commander4.Command("prompts").description("Manage prompts");
885
1417
  promptsCommand.command("list").description("List all prompts").option("--json", "Output as JSON").action(async (options) => {
886
- const store = new CredentialStore();
887
- const apiKey = await store.getApiKey();
888
- if (!apiKey) {
889
- console.log(import_chalk4.default.yellow("Not authenticated. Please run: runtype auth login"));
890
- process.exit(1);
891
- }
892
- const spinner = (0, import_ora4.default)("Fetching prompts...").start();
1418
+ const apiKey = await ensureAuth();
1419
+ if (!apiKey) return;
1420
+ const spinner = (0, import_ora5.default)("Fetching prompts...").start();
893
1421
  try {
894
- const response = await fetch(`${getApiUrl()}/prompts`, {
895
- headers: {
896
- Authorization: `Bearer ${apiKey}`,
897
- "Content-Type": "application/json"
898
- }
899
- });
900
- if (!response.ok) {
901
- throw new Error(`Failed to fetch prompts: ${response.statusText}`);
902
- }
903
- const data = await response.json();
1422
+ const client = new ApiClient(apiKey);
1423
+ const data = await client.get("/prompts");
904
1424
  spinner.stop();
905
1425
  if (options.json) {
906
- console.log(JSON.stringify(data, null, 2));
1426
+ printJson(data);
907
1427
  } else {
908
- if (!isPromptListResponse(data)) {
909
- throw new Error("Unexpected prompts response format");
910
- }
911
- console.log(import_chalk4.default.cyan("Your Prompts:"));
912
- const promptsArray = data.data ?? [];
913
- if (promptsArray.length > 0) {
914
- promptsArray.forEach((prompt) => {
915
- console.log(` ${import_chalk4.default.green(prompt.id)} - ${prompt.name}`);
916
- if (prompt.description) {
917
- console.log(` ${import_chalk4.default.gray(prompt.description)}`);
918
- }
919
- if (prompt.model) {
920
- console.log(` Model: ${import_chalk4.default.blue(prompt.model)}`);
921
- }
922
- });
923
- const total = data.pagination?.total_count;
924
- if (typeof total === "number") {
925
- console.log(import_chalk4.default.dim(`
926
- Total: ${total} prompts`));
1428
+ const prompts = data.data ?? [];
1429
+ if (prompts.length === 0) {
1430
+ console.log(import_chalk7.default.gray("No prompts found"));
1431
+ return;
1432
+ }
1433
+ console.log(import_chalk7.default.cyan("Your Prompts:"));
1434
+ for (const prompt of prompts) {
1435
+ console.log(` ${import_chalk7.default.green(prompt.id)} - ${prompt.name}`);
1436
+ if (prompt.description) {
1437
+ console.log(` ${import_chalk7.default.gray(prompt.description)}`);
1438
+ }
1439
+ if (prompt.model) {
1440
+ console.log(` Model: ${import_chalk7.default.blue(prompt.model)}`);
927
1441
  }
928
- } else {
929
- console.log(import_chalk4.default.gray(" No prompts found"));
1442
+ }
1443
+ const total = getTotalCount(data.pagination);
1444
+ if (total !== void 0) {
1445
+ console.log(import_chalk7.default.dim(`
1446
+ Total: ${total} prompts`));
930
1447
  }
931
1448
  }
932
1449
  } catch (error) {
933
1450
  const message = error instanceof Error ? error.message : "Unknown error";
934
1451
  spinner.fail("Failed to fetch prompts");
935
- console.error(import_chalk4.default.red(message));
1452
+ console.error(import_chalk7.default.red(message));
936
1453
  process.exit(1);
937
1454
  }
938
1455
  });
939
- promptsCommand.command("test <id>").description("Test a prompt").option("-i, --input <text>", "Input text for the prompt").action(async (promptId, options) => {
940
- void options;
941
- const store = new CredentialStore();
942
- const apiKey = await store.getApiKey();
943
- if (!apiKey) {
944
- console.log(import_chalk4.default.yellow("Not authenticated. Please run: runtype auth login"));
1456
+ promptsCommand.command("get <id>").description("Get prompt details").option("--json", "Output as JSON").action(async (id, options) => {
1457
+ const apiKey = await ensureAuth();
1458
+ if (!apiKey) return;
1459
+ const spinner = (0, import_ora5.default)("Fetching prompt...").start();
1460
+ try {
1461
+ const client = new ApiClient(apiKey);
1462
+ const data = await client.get(`/prompts/${id}`);
1463
+ spinner.stop();
1464
+ if (options.json) {
1465
+ printJson(data);
1466
+ } else {
1467
+ printDetail("Prompt", [
1468
+ { label: "ID", value: data.id },
1469
+ { label: "Name", value: data.name },
1470
+ { label: "Description", value: data.description },
1471
+ { label: "Model", value: data.model }
1472
+ ]);
1473
+ }
1474
+ } catch (error) {
1475
+ const message = error instanceof Error ? error.message : "Unknown error";
1476
+ spinner.fail("Failed to fetch prompt");
1477
+ console.error(import_chalk7.default.red(message));
945
1478
  process.exit(1);
946
1479
  }
947
- console.log(import_chalk4.default.cyan(`Testing prompt ${promptId}...`));
948
- console.log(import_chalk4.default.gray("Implementation coming soon"));
949
1480
  });
1481
+ promptsCommand.command("test <id>").description("Test a prompt with input").option("-i, --input <text>", "Input text for the prompt").option("--stream", "Stream the response (default)", true).option("--no-stream", "Wait for complete response").option("--json", "Output as JSON").action(
1482
+ async (promptId, options) => {
1483
+ const apiKey = await ensureAuth();
1484
+ if (!apiKey) return;
1485
+ const client = new ApiClient(apiKey);
1486
+ const payload = {
1487
+ flow: {
1488
+ steps: [
1489
+ {
1490
+ name: "test",
1491
+ type: "prompt",
1492
+ config: {
1493
+ promptId,
1494
+ text: options.input || ""
1495
+ }
1496
+ }
1497
+ ]
1498
+ }
1499
+ };
1500
+ if (options.input) {
1501
+ payload.messages = [{ role: "user", content: options.input }];
1502
+ }
1503
+ if (options.stream) {
1504
+ const spinner = (0, import_ora5.default)("Testing prompt...").start();
1505
+ try {
1506
+ const response = await client.stream("/dispatch", payload);
1507
+ spinner.stop();
1508
+ const callbacks = {
1509
+ onStepChunk: (chunk) => {
1510
+ process.stdout.write(chunk);
1511
+ },
1512
+ onError: (err) => {
1513
+ console.error(import_chalk7.default.red(`
1514
+ Error: ${err.message}`));
1515
+ }
1516
+ };
1517
+ await (0, import_sdk2.processStream)(response, callbacks);
1518
+ console.log();
1519
+ } catch (error) {
1520
+ spinner.fail("Prompt test failed");
1521
+ const message = error instanceof Error ? error.message : "Unknown error";
1522
+ console.error(import_chalk7.default.red(message));
1523
+ process.exit(1);
1524
+ }
1525
+ } else {
1526
+ const spinner = (0, import_ora5.default)("Testing prompt...").start();
1527
+ try {
1528
+ payload.streamResponse = false;
1529
+ const result = await client.post("/dispatch", payload);
1530
+ spinner.succeed("Prompt test complete");
1531
+ if (options.json) {
1532
+ printJson(result);
1533
+ } else {
1534
+ printJson(result);
1535
+ }
1536
+ } catch (error) {
1537
+ spinner.fail("Prompt test failed");
1538
+ const message = error instanceof Error ? error.message : "Unknown error";
1539
+ console.error(import_chalk7.default.red(message));
1540
+ process.exit(1);
1541
+ }
1542
+ }
1543
+ }
1544
+ );
950
1545
 
951
1546
  // src/commands/batch.ts
1547
+ init_cjs_shims();
952
1548
  var import_commander5 = require("commander");
953
- var import_chalk5 = __toESM(require("chalk"));
954
- var import_ora5 = __toESM(require("ora"));
955
- var isBatchStatusResponse = (value) => {
956
- if (!value || typeof value !== "object") {
957
- return false;
958
- }
959
- const record = value;
960
- return typeof record.status === "string" && typeof record.processed_count === "number" && typeof record.total_count === "number" && typeof record.failed_count === "number";
961
- };
1549
+ var import_chalk8 = __toESM(require("chalk"));
1550
+ var import_ora6 = __toESM(require("ora"));
1551
+ var import_fs4 = require("fs");
962
1552
  var batchCommand = new import_commander5.Command("batch").description("Manage batch operations");
963
- batchCommand.command("submit").description("Submit a batch job").requiredOption("-f, --flow <id>", "Flow ID to execute").requiredOption("-r, --records <file>", "JSON file with record IDs").action(async (options) => {
964
- const store = new CredentialStore();
965
- const apiKey = await store.getApiKey();
966
- if (!apiKey) {
967
- console.log(import_chalk5.default.yellow("Not authenticated. Please run: runtype auth login"));
968
- process.exit(1);
969
- }
970
- console.log(import_chalk5.default.cyan("Submitting batch job..."));
971
- console.log(import_chalk5.default.gray(`Flow: ${options.flow}`));
972
- console.log(import_chalk5.default.gray(`Records file: ${options.records}`));
973
- console.log(import_chalk5.default.gray("Implementation coming soon"));
974
- });
975
- batchCommand.command("status <id>").description("Check batch job status").option("--watch", "Watch for updates").action(async (batchId, options) => {
976
- const store = new CredentialStore();
977
- const apiKey = await store.getApiKey();
978
- if (!apiKey) {
979
- console.log(import_chalk5.default.yellow("Not authenticated. Please run: runtype auth login"));
1553
+ batchCommand.command("submit").description("Submit a batch job").requiredOption("-f, --flow <id>", "Flow ID to execute").requiredOption("-r, --records <file>", "JSON file with record IDs").option("--json", "Output as JSON").action(async (options) => {
1554
+ const apiKey = await ensureAuth();
1555
+ if (!apiKey) return;
1556
+ let recordIds;
1557
+ try {
1558
+ const content = (0, import_fs4.readFileSync)(options.records, "utf-8");
1559
+ const parsed = JSON.parse(content);
1560
+ recordIds = Array.isArray(parsed) ? parsed : parsed.recordIds || parsed.records || [];
1561
+ } catch (error) {
1562
+ const msg = error instanceof Error ? error.message : "Unknown error";
1563
+ console.error(import_chalk8.default.red(`Failed to read records file: ${msg}`));
980
1564
  process.exit(1);
981
1565
  }
982
- const spinner = (0, import_ora5.default)("Fetching batch status...").start();
1566
+ const spinner = (0, import_ora6.default)(`Submitting batch with ${recordIds.length} records...`).start();
983
1567
  try {
984
- const response = await fetch(`${getApiUrl()}/${getApiVersion()}/batch/status/${batchId}`, {
985
- headers: {
986
- Authorization: `Bearer ${apiKey}`,
987
- "Content-Type": "application/json"
988
- }
1568
+ const client = new ApiClient(apiKey);
1569
+ const data = await client.post("/batch/submit", {
1570
+ flowId: options.flow,
1571
+ recordIds
989
1572
  });
990
- if (!response.ok) {
991
- throw new Error(`Failed to fetch batch status: ${response.statusText}`);
992
- }
993
- const data = await response.json();
994
- if (!isBatchStatusResponse(data)) {
995
- throw new Error("Invalid batch status response received from the API");
1573
+ spinner.succeed("Batch submitted");
1574
+ if (options.json) {
1575
+ printJson(data);
1576
+ } else {
1577
+ console.log(` Batch ID: ${import_chalk8.default.green(data.id)}`);
1578
+ console.log(` Status: ${data.status}`);
996
1579
  }
1580
+ } catch (error) {
1581
+ const message = error instanceof Error ? error.message : "Unknown error";
1582
+ spinner.fail("Failed to submit batch");
1583
+ console.error(import_chalk8.default.red(message));
1584
+ process.exit(1);
1585
+ }
1586
+ });
1587
+ batchCommand.command("status <id>").description("Check batch job status").option("--watch", "Watch for updates").option("--json", "Output as JSON").action(async (batchId, options) => {
1588
+ const apiKey = await ensureAuth();
1589
+ if (!apiKey) return;
1590
+ const spinner = (0, import_ora6.default)("Fetching batch status...").start();
1591
+ try {
1592
+ const client = new ApiClient(apiKey);
1593
+ const data = await client.get(`/batch/status/${batchId}`);
997
1594
  spinner.stop();
998
- console.log(import_chalk5.default.cyan(`Batch Job: ${batchId}`));
999
- console.log(` Status: ${import_chalk5.default.green(data.status)}`);
1000
- console.log(` Progress: ${data.processed_count}/${data.total_count}`);
1001
- if (data.failed_count > 0) {
1002
- console.log(` Failed: ${import_chalk5.default.red(data.failed_count)}`);
1003
- }
1004
- if (options.watch && data.status === "processing") {
1005
- console.log(import_chalk5.default.gray("\nWatching for updates... (Ctrl+C to stop)"));
1595
+ if (options.json) {
1596
+ printJson(data);
1597
+ } else {
1598
+ console.log(import_chalk8.default.cyan(`Batch Job: ${batchId}`));
1599
+ console.log(` Status: ${import_chalk8.default.green(data.status)}`);
1600
+ console.log(` Progress: ${data.processedRecords}/${data.totalRecords}`);
1601
+ if (data.failedRecords > 0) {
1602
+ console.log(` Failed: ${import_chalk8.default.red(data.failedRecords)}`);
1603
+ }
1604
+ if (options.watch && data.status === "processing") {
1605
+ console.log(import_chalk8.default.gray("\nWatching for updates... (Ctrl+C to stop)"));
1606
+ }
1006
1607
  }
1007
1608
  } catch (error) {
1008
1609
  const message = error instanceof Error ? error.message : "Unknown error";
1009
1610
  spinner.fail("Failed to fetch batch status");
1010
- console.error(import_chalk5.default.red(message));
1611
+ console.error(import_chalk8.default.red(message));
1011
1612
  process.exit(1);
1012
1613
  }
1013
1614
  });
1014
1615
  batchCommand.command("cancel <id>").description("Cancel a batch job").action(async (batchId) => {
1015
- const store = new CredentialStore();
1016
- const apiKey = await store.getApiKey();
1017
- if (!apiKey) {
1018
- console.log(import_chalk5.default.yellow("Not authenticated. Please run: runtype auth login"));
1019
- process.exit(1);
1020
- }
1021
- const spinner = (0, import_ora5.default)("Cancelling batch job...").start();
1616
+ const apiKey = await ensureAuth();
1617
+ if (!apiKey) return;
1618
+ const spinner = (0, import_ora6.default)("Cancelling batch job...").start();
1022
1619
  try {
1023
- const response = await fetch(`${getApiUrl()}/${getApiVersion()}/batch/cancel/${batchId}`, {
1024
- method: "POST",
1025
- headers: {
1026
- Authorization: `Bearer ${apiKey}`,
1027
- "Content-Type": "application/json"
1028
- }
1029
- });
1030
- if (!response.ok) {
1031
- throw new Error(`Failed to cancel batch: ${response.statusText}`);
1032
- }
1033
- spinner.succeed("Batch job cancelled successfully");
1620
+ const client = new ApiClient(apiKey);
1621
+ await client.post(`/batch/cancel/${batchId}`);
1622
+ spinner.succeed("Batch job cancelled");
1034
1623
  } catch (error) {
1035
1624
  const message = error instanceof Error ? error.message : "Unknown error";
1036
1625
  spinner.fail("Failed to cancel batch job");
1037
- console.error(import_chalk5.default.red(message));
1626
+ console.error(import_chalk8.default.red(message));
1038
1627
  process.exit(1);
1039
1628
  }
1040
1629
  });
1041
1630
 
1042
1631
  // src/commands/talk.ts
1632
+ init_cjs_shims();
1043
1633
  var import_commander6 = require("commander");
1044
- var import_readline = __toESM(require("readline"));
1045
- var import_chalk7 = __toESM(require("chalk"));
1634
+ var import_readline2 = __toESM(require("readline"));
1635
+ var import_chalk10 = __toESM(require("chalk"));
1046
1636
 
1047
1637
  // src/chat/session-manager.ts
1638
+ init_cjs_shims();
1048
1639
  var import_uuid = require("uuid");
1049
1640
  var import_promises = __toESM(require("fs/promises"));
1050
1641
  var import_path2 = __toESM(require("path"));
@@ -1104,7 +1695,6 @@ var ChatSession = class {
1104
1695
  flow: {
1105
1696
  name: "Chat Flow",
1106
1697
  description: "",
1107
- mode: "standalone",
1108
1698
  steps: [
1109
1699
  {
1110
1700
  id: "1",
@@ -1115,22 +1705,16 @@ var ChatSession = class {
1115
1705
  config: {
1116
1706
  text: this.buildPrompt(userInput),
1117
1707
  model: this.modelConfig.model,
1118
- output_format: "text",
1119
- output_variable: "chat_result",
1120
- response_format: "text"
1121
- },
1122
- prompt_id: null,
1123
- context_template_id: null,
1124
- item_type: "prompt",
1125
- prompt: null,
1126
- context_template: null
1708
+ outputVariable: "chatResult",
1709
+ responseFormat: "text"
1710
+ }
1127
1711
  }
1128
1712
  ]
1129
1713
  },
1130
1714
  options: {
1131
- stream_response: true,
1132
- record_mode: "virtual",
1133
- flow_mode: "virtual"
1715
+ streamResponse: true,
1716
+ recordMode: "virtual",
1717
+ flowMode: "virtual"
1134
1718
  }
1135
1719
  };
1136
1720
  }
@@ -1219,15 +1803,16 @@ ${userInput}`;
1219
1803
  id: this.sessionId,
1220
1804
  messageCount: this.messages.length,
1221
1805
  model: this.modelConfig.model,
1222
- temperature: this.modelConfig.temperature || 0.7,
1806
+ temperature: this.modelConfig.temperature ?? 0.7,
1223
1807
  duration
1224
1808
  };
1225
1809
  }
1226
1810
  };
1227
1811
 
1228
1812
  // src/chat/stream-handler.ts
1229
- var import_chalk6 = __toESM(require("chalk"));
1230
- var import_sdk = require("@runtypelabs/sdk");
1813
+ init_cjs_shims();
1814
+ var import_chalk9 = __toESM(require("chalk"));
1815
+ var import_sdk3 = require("@runtypelabs/sdk");
1231
1816
  var StreamHandler = class {
1232
1817
  buffer = "";
1233
1818
  isStreaming = false;
@@ -1243,17 +1828,17 @@ var StreamHandler = class {
1243
1828
  this.appendOutput(chunk);
1244
1829
  },
1245
1830
  onError: (error) => {
1246
- console.error(import_chalk6.default.red(`
1831
+ console.error(import_chalk9.default.red(`
1247
1832
  Error: ${error.message}`));
1248
1833
  }
1249
1834
  // All other events (step_start, step_complete, flow_start, etc.) are
1250
1835
  // silently ignored - processStream handles them but we don't need to display them
1251
1836
  };
1252
1837
  try {
1253
- await (0, import_sdk.processStream)(response, callbacks);
1838
+ await (0, import_sdk3.processStream)(response, callbacks);
1254
1839
  } catch (error) {
1255
1840
  const message = error instanceof Error ? error.message : "Unknown error";
1256
- console.error(import_chalk6.default.red(`
1841
+ console.error(import_chalk9.default.red(`
1257
1842
  Stream error: ${message}`));
1258
1843
  throw error;
1259
1844
  } finally {
@@ -1299,12 +1884,8 @@ var CHAT_COMMANDS = {
1299
1884
  "/exit": "Exit chat session"
1300
1885
  };
1301
1886
  var talkCommand = new import_commander6.Command("talk").description("Start an interactive chat session").option("-m, --model <model>", "AI model to use", getDefaultModel()).option("-t, --temperature <temp>", "Temperature (0-1)", getDefaultTemperature().toString()).option("--max-tokens <tokens>", "Max response tokens", "2000").option("--system <prompt>", "System prompt to prepend").option("--no-markdown", "Disable markdown rendering").option("--continue <file>", "Continue from saved session").action(async (options) => {
1302
- const store = new CredentialStore();
1303
- const apiKey = await store.getApiKey();
1304
- if (!apiKey) {
1305
- console.log(import_chalk7.default.yellow("Not authenticated. Please run: runtype auth login"));
1306
- process.exit(1);
1307
- }
1887
+ const apiKey = await ensureAuth();
1888
+ if (!apiKey) return;
1308
1889
  const session = new ChatSession({
1309
1890
  model: options.model,
1310
1891
  temperature: parseFloat(options.temperature),
@@ -1314,9 +1895,10 @@ var talkCommand = new import_commander6.Command("talk").description("Start an in
1314
1895
  if (options.continue) {
1315
1896
  try {
1316
1897
  await session.loadFromFile(options.continue);
1317
- console.log(import_chalk7.default.green(`Loaded session from: ${options.continue}`));
1898
+ console.log(import_chalk10.default.green(`Loaded session from: ${options.continue}`));
1318
1899
  } catch (error) {
1319
- console.error(import_chalk7.default.red(`Failed to load session: ${error.message}`));
1900
+ const message = error instanceof Error ? error.message : "Unknown error";
1901
+ console.error(import_chalk10.default.red(`Failed to load session: ${message}`));
1320
1902
  process.exit(1);
1321
1903
  }
1322
1904
  }
@@ -1324,17 +1906,17 @@ var talkCommand = new import_commander6.Command("talk").description("Start an in
1324
1906
  const streamHandler = new StreamHandler({
1325
1907
  enableMarkdown: options.markdown !== false
1326
1908
  });
1327
- const rl = import_readline.default.createInterface({
1909
+ const rl = import_readline2.default.createInterface({
1328
1910
  input: process.stdin,
1329
1911
  output: process.stdout,
1330
- prompt: import_chalk7.default.cyan("You> "),
1912
+ prompt: import_chalk10.default.cyan("You> "),
1331
1913
  terminal: true,
1332
1914
  historySize: 100
1333
1915
  });
1334
1916
  console.clear();
1335
- console.log(import_chalk7.default.green("\u{1F916} Runtype Chat Session Started"));
1336
- console.log(import_chalk7.default.gray(`Model: ${options.model} | Temperature: ${options.temperature}`));
1337
- console.log(import_chalk7.default.gray('Type "/help" for commands or "exit" to quit\n'));
1917
+ console.log(import_chalk10.default.green("\u{1F916} Runtype Chat Session Started"));
1918
+ console.log(import_chalk10.default.gray(`Model: ${options.model} | Temperature: ${options.temperature}`));
1919
+ console.log(import_chalk10.default.gray('Type "/help" for commands or "exit" to quit\n'));
1338
1920
  if (options.system) {
1339
1921
  session.addMessage("system", options.system);
1340
1922
  }
@@ -1344,67 +1926,71 @@ var talkCommand = new import_commander6.Command("talk").description("Start an in
1344
1926
  const args = parts.slice(1).join(" ");
1345
1927
  switch (command) {
1346
1928
  case "/help":
1347
- console.log(import_chalk7.default.cyan("\nAvailable commands:"));
1929
+ console.log(import_chalk10.default.cyan("\nAvailable commands:"));
1348
1930
  for (const [cmd, desc] of Object.entries(CHAT_COMMANDS)) {
1349
- console.log(` ${import_chalk7.default.green(cmd)} - ${desc}`);
1931
+ console.log(` ${import_chalk10.default.green(cmd)} - ${desc}`);
1350
1932
  }
1351
1933
  console.log();
1352
1934
  return true;
1353
1935
  case "/clear":
1354
1936
  session.clearHistory();
1355
1937
  console.clear();
1356
- console.log(import_chalk7.default.green("\u{1F916} Chat history cleared"));
1938
+ console.log(import_chalk10.default.green("\u{1F916} Chat history cleared"));
1357
1939
  return true;
1358
1940
  case "/save":
1359
1941
  try {
1360
1942
  const filepath = await session.saveToFile(args || void 0);
1361
- console.log(import_chalk7.default.green(`Session saved to: ${filepath}`));
1943
+ console.log(import_chalk10.default.green(`Session saved to: ${filepath}`));
1362
1944
  } catch (error) {
1363
- console.error(import_chalk7.default.red(`Failed to save: ${error.message}`));
1945
+ const message = error instanceof Error ? error.message : "Unknown error";
1946
+ console.error(import_chalk10.default.red(`Failed to save: ${message}`));
1364
1947
  }
1365
1948
  return true;
1366
1949
  case "/load":
1367
1950
  if (!args) {
1368
- console.log(import_chalk7.default.red("Please specify a filename"));
1951
+ console.log(import_chalk10.default.red("Please specify a filename"));
1369
1952
  return true;
1370
1953
  }
1371
1954
  try {
1372
1955
  await session.loadFromFile(args);
1373
- console.log(import_chalk7.default.green(`Session loaded from: ${args}`));
1956
+ console.log(import_chalk10.default.green(`Session loaded from: ${args}`));
1374
1957
  } catch (error) {
1375
- console.error(import_chalk7.default.red(`Failed to load: ${error.message}`));
1958
+ const message = error instanceof Error ? error.message : "Unknown error";
1959
+ console.error(import_chalk10.default.red(`Failed to load: ${message}`));
1376
1960
  }
1377
1961
  return true;
1378
1962
  case "/export":
1379
1963
  try {
1380
1964
  const filepath = await session.exportAsMarkdown();
1381
- console.log(import_chalk7.default.green(`Conversation exported to: ${filepath}`));
1965
+ console.log(import_chalk10.default.green(`Conversation exported to: ${filepath}`));
1382
1966
  } catch (error) {
1383
- console.error(import_chalk7.default.red(`Failed to export: ${error.message}`));
1967
+ const message = error instanceof Error ? error.message : "Unknown error";
1968
+ console.error(import_chalk10.default.red(`Failed to export: ${message}`));
1384
1969
  }
1385
1970
  return true;
1386
1971
  case "/model":
1387
1972
  if (!args) {
1388
- console.log(import_chalk7.default.yellow("Please specify a model"));
1973
+ console.log(import_chalk10.default.yellow("Please specify a model"));
1389
1974
  return true;
1390
1975
  }
1391
1976
  session.setModel(args);
1392
1977
  return true;
1393
- case "/temp":
1978
+ case "/temp": {
1394
1979
  if (!args) {
1395
- console.log(import_chalk7.default.yellow("Please specify a temperature (0-1)"));
1980
+ console.log(import_chalk10.default.yellow("Please specify a temperature (0-1)"));
1396
1981
  return true;
1397
1982
  }
1398
1983
  const temp = parseFloat(args);
1399
1984
  if (isNaN(temp) || temp < 0 || temp > 1) {
1400
- console.log(import_chalk7.default.red("Temperature must be between 0 and 1"));
1985
+ console.log(import_chalk10.default.red("Temperature must be between 0 and 1"));
1401
1986
  return true;
1402
1987
  }
1403
1988
  session.setTemperature(temp);
1404
1989
  return true;
1405
- case "/info":
1990
+ }
1991
+ case "/info": {
1406
1992
  const info = session.getSessionInfo();
1407
- console.log(import_chalk7.default.cyan("\nSession Information:"));
1993
+ console.log(import_chalk10.default.cyan("\nSession Information:"));
1408
1994
  console.log(` Session ID: ${info.id}`);
1409
1995
  console.log(` Messages: ${info.messageCount}`);
1410
1996
  console.log(` Model: ${info.model}`);
@@ -1412,12 +1998,13 @@ var talkCommand = new import_commander6.Command("talk").description("Start an in
1412
1998
  console.log(` Duration: ${info.duration}`);
1413
1999
  console.log();
1414
2000
  return true;
2001
+ }
1415
2002
  case "/exit":
1416
2003
  return false;
1417
2004
  default:
1418
2005
  if (input.startsWith("/")) {
1419
- console.log(import_chalk7.default.red(`Unknown command: ${command}`));
1420
- console.log(import_chalk7.default.gray('Type "/help" for available commands'));
2006
+ console.log(import_chalk10.default.red(`Unknown command: ${command}`));
2007
+ console.log(import_chalk10.default.gray('Type "/help" for available commands'));
1421
2008
  return true;
1422
2009
  }
1423
2010
  return false;
@@ -1427,7 +2014,7 @@ var talkCommand = new import_commander6.Command("talk").description("Start an in
1427
2014
  rl.on("line", async (input) => {
1428
2015
  const trimmed = input.trim();
1429
2016
  if (trimmed.toLowerCase() === "exit" || trimmed.toLowerCase() === "quit") {
1430
- console.log(import_chalk7.default.green("\n\u{1F44B} Goodbye!"));
2017
+ console.log(import_chalk10.default.green("\n\u{1F44B} Goodbye!"));
1431
2018
  rl.close();
1432
2019
  process.exit(0);
1433
2020
  }
@@ -1438,14 +2025,14 @@ var talkCommand = new import_commander6.Command("talk").description("Start an in
1438
2025
  if (trimmed.startsWith("/")) {
1439
2026
  const shouldContinue = await handleCommand(trimmed);
1440
2027
  if (!shouldContinue) {
1441
- console.log(import_chalk7.default.green("\n\u{1F44B} Goodbye!"));
2028
+ console.log(import_chalk10.default.green("\n\u{1F44B} Goodbye!"));
1442
2029
  rl.close();
1443
2030
  process.exit(0);
1444
2031
  }
1445
2032
  rl.prompt();
1446
2033
  return;
1447
2034
  }
1448
- console.log(import_chalk7.default.gray("\nAssistant> ") + import_chalk7.default.gray("Thinking..."));
2035
+ console.log(import_chalk10.default.gray("\nAssistant> ") + import_chalk10.default.gray("Thinking..."));
1449
2036
  try {
1450
2037
  const payload = session.buildDispatchPayload(trimmed);
1451
2038
  const response = await fetch(`${apiUrl}/dispatch`, {
@@ -1462,34 +2049,36 @@ var talkCommand = new import_commander6.Command("talk").description("Start an in
1462
2049
  throw new Error(`API error: ${response.status} - ${error}`);
1463
2050
  }
1464
2051
  process.stdout.write("\x1B[1A\x1B[2K");
1465
- process.stdout.write(import_chalk7.default.gray("Assistant> "));
2052
+ process.stdout.write(import_chalk10.default.gray("Assistant> "));
1466
2053
  const fullResponse = await streamHandler.handleStream(response);
1467
2054
  session.addMessage("assistant", fullResponse);
1468
2055
  console.log();
1469
2056
  rl.prompt();
1470
2057
  } catch (error) {
1471
2058
  process.stdout.write("\x1B[1A\x1B[2K");
1472
- console.error(import_chalk7.default.red(`Error: ${error.message}`));
2059
+ const message = error instanceof Error ? error.message : "Unknown error";
2060
+ console.error(import_chalk10.default.red(`Error: ${message}`));
1473
2061
  rl.prompt();
1474
2062
  }
1475
2063
  });
1476
2064
  rl.on("SIGINT", () => {
1477
- console.log(import_chalk7.default.green("\n\n\u{1F44B} Goodbye!"));
2065
+ console.log(import_chalk10.default.green("\n\n\u{1F44B} Goodbye!"));
1478
2066
  const info = session.getSessionInfo();
1479
2067
  if (info.messageCount > 0) {
1480
- console.log(import_chalk7.default.gray('Tip: Use "/save" to save your conversation before exiting'));
2068
+ console.log(import_chalk10.default.gray('Tip: Use "/save" to save your conversation before exiting'));
1481
2069
  }
1482
2070
  process.exit(0);
1483
2071
  });
1484
2072
  rl.on("error", (error) => {
1485
- console.error(import_chalk7.default.red(`Readline error: ${error.message}`));
2073
+ console.error(import_chalk10.default.red(`Readline error: ${error.message}`));
1486
2074
  process.exit(1);
1487
2075
  });
1488
2076
  });
1489
2077
 
1490
2078
  // src/commands/config.ts
2079
+ init_cjs_shims();
1491
2080
  var import_commander7 = require("commander");
1492
- var import_chalk8 = __toESM(require("chalk"));
2081
+ var import_chalk11 = __toESM(require("chalk"));
1493
2082
  var import_conf2 = __toESM(require("conf"));
1494
2083
  var import_path3 = __toESM(require("path"));
1495
2084
  var import_os3 = __toESM(require("os"));
@@ -1513,31 +2102,31 @@ var config = new import_conf2.default({
1513
2102
  configCommand.command("get [key]").description("Get configuration value").action((key) => {
1514
2103
  if (key) {
1515
2104
  if (!isCliConfigKey(key)) {
1516
- console.log(import_chalk8.default.yellow(`Configuration key '${key}' not found`));
2105
+ console.log(import_chalk11.default.yellow(`Configuration key '${key}' not found`));
1517
2106
  return;
1518
2107
  }
1519
2108
  const value = config.get(key);
1520
2109
  if (value !== void 0) {
1521
2110
  console.log(value);
1522
2111
  } else {
1523
- console.log(import_chalk8.default.yellow(`Configuration key '${key}' not found`));
2112
+ console.log(import_chalk11.default.yellow(`Configuration key '${key}' not found`));
1524
2113
  }
1525
2114
  } else {
1526
2115
  const allConfig = config.store;
1527
2116
  if (Object.keys(allConfig).length > 0) {
1528
- console.log(import_chalk8.default.cyan("Current Configuration:"));
2117
+ console.log(import_chalk11.default.cyan("Current Configuration:"));
1529
2118
  for (const [k, v] of Object.entries(allConfig)) {
1530
- console.log(` ${import_chalk8.default.green(k)}: ${v}`);
2119
+ console.log(` ${import_chalk11.default.green(k)}: ${v}`);
1531
2120
  }
1532
2121
  } else {
1533
- console.log(import_chalk8.default.gray("No configuration set"));
2122
+ console.log(import_chalk11.default.gray("No configuration set"));
1534
2123
  }
1535
2124
  }
1536
2125
  });
1537
2126
  configCommand.command("set <key> <value>").description("Set configuration value").action((key, value) => {
1538
2127
  if (!isCliConfigKey(key)) {
1539
- console.log(import_chalk8.default.red(`Invalid configuration key: ${key}`));
1540
- console.log(import_chalk8.default.gray(`Valid keys: ${CLI_CONFIG_KEYS.join(", ")}`));
2128
+ console.log(import_chalk11.default.red(`Invalid configuration key: ${key}`));
2129
+ console.log(import_chalk11.default.gray(`Valid keys: ${CLI_CONFIG_KEYS.join(", ")}`));
1541
2130
  process.exit(1);
1542
2131
  }
1543
2132
  let parsedValue;
@@ -1546,7 +2135,7 @@ configCommand.command("set <key> <value>").description("Set configuration value"
1546
2135
  {
1547
2136
  const temperature = parseFloat(value);
1548
2137
  if (isNaN(temperature) || temperature < 0 || temperature > 1) {
1549
- console.log(import_chalk8.default.red("Temperature must be a number between 0 and 1"));
2138
+ console.log(import_chalk11.default.red("Temperature must be a number between 0 and 1"));
1550
2139
  process.exit(1);
1551
2140
  }
1552
2141
  parsedValue = temperature;
@@ -1557,7 +2146,7 @@ configCommand.command("set <key> <value>").description("Set configuration value"
1557
2146
  break;
1558
2147
  case "outputFormat":
1559
2148
  if (!["table", "json", "plain"].includes(value)) {
1560
- console.log(import_chalk8.default.red("Output format must be: table, json, or plain"));
2149
+ console.log(import_chalk11.default.red("Output format must be: table, json, or plain"));
1561
2150
  process.exit(1);
1562
2151
  }
1563
2152
  parsedValue = value;
@@ -1567,33 +2156,34 @@ configCommand.command("set <key> <value>").description("Set configuration value"
1567
2156
  break;
1568
2157
  }
1569
2158
  config.set(key, parsedValue);
1570
- console.log(import_chalk8.default.green(`Configuration updated: ${key} = ${parsedValue}`));
2159
+ console.log(import_chalk11.default.green(`Configuration updated: ${key} = ${parsedValue}`));
1571
2160
  });
1572
2161
  configCommand.command("reset").description("Reset all configuration to defaults").action(() => {
1573
2162
  config.clear();
1574
- console.log(import_chalk8.default.green("Configuration reset to defaults"));
2163
+ console.log(import_chalk11.default.green("Configuration reset to defaults"));
1575
2164
  });
1576
2165
  configCommand.command("path").description("Show configuration file path").action(() => {
1577
2166
  console.log(config.path);
1578
2167
  });
1579
2168
 
1580
2169
  // src/commands/products.ts
2170
+ init_cjs_shims();
1581
2171
  var import_commander8 = require("commander");
1582
- var import_chalk9 = __toESM(require("chalk"));
1583
- var import_ora6 = __toESM(require("ora"));
2172
+ var import_chalk12 = __toESM(require("chalk"));
2173
+ var import_ora7 = __toESM(require("ora"));
1584
2174
  var import_open2 = __toESM(require("open"));
1585
2175
  function displayAgentCard(agentCard) {
1586
- console.log(`
1587
- Name: ${agentCard.name}`);
2176
+ console.log(import_chalk12.default.cyan("\nAgent Details:"));
2177
+ console.log(` Name: ${agentCard.name}`);
1588
2178
  if (agentCard.description) {
1589
- console.log(`Description: ${agentCard.description}`);
2179
+ console.log(` Description: ${agentCard.description}`);
1590
2180
  }
1591
- console.log(`URL: ${agentCard.url}`);
2181
+ console.log(` URL: ${agentCard.url}`);
1592
2182
  if (agentCard.skills && agentCard.skills.length > 0) {
1593
- console.log("Skills:");
2183
+ console.log(" Skills:");
1594
2184
  agentCard.skills.forEach((skill) => {
1595
2185
  const desc = skill.description ? ` - ${skill.description}` : "";
1596
- console.log(` ${import_chalk9.default.cyan("\u2022")} ${skill.name}${desc}`);
2186
+ console.log(` ${import_chalk12.default.cyan("\u2022")} ${skill.name}${desc}`);
1597
2187
  });
1598
2188
  }
1599
2189
  }
@@ -1643,7 +2233,7 @@ function displayCreationSuccess(result, agentCard, dashboardBaseUrl, jsonOutput)
1643
2233
  Product ID: ${result.product.id}`);
1644
2234
  console.log(`Name: ${result.product.name}`);
1645
2235
  console.log(`Dashboard: ${productUrl}`);
1646
- console.log(import_chalk9.default.cyan("\nNext steps:"));
2236
+ console.log(import_chalk12.default.cyan("\nNext steps:"));
1647
2237
  console.log(" 1. Visit the dashboard to configure surfaces");
1648
2238
  console.log(" 2. Or run: runtype products init --from <another-url>");
1649
2239
  }
@@ -1665,59 +2255,61 @@ async function validateUrl(url, apiUrl) {
1665
2255
  return response.json();
1666
2256
  }
1667
2257
  var productsCommand = new import_commander8.Command("products").description("Manage products");
1668
- productsCommand.command("init").description("Initialize a product from an external resource").requiredOption("--from <url>", "URL to validate and import").option("--name <name>", "Custom product name (defaults to agent name)").option("--open", "Open browser to dashboard instead of creating via API").option("--json", "Output in JSON format").option("--api-url <url>", "Override API URL").action(async (options) => {
1669
- const spinner = (0, import_ora6.default)("Validating URL...").start();
2258
+ productsCommand.command("init").description("Initialize a product from an external resource").option("--from <url>", "URL to validate and import").option("--name <name>", "Custom product name (defaults to agent name)").option("--open", "Open browser to dashboard instead of creating via API").option("--json", "Output in JSON format").option("--api-url <url>", "Override API URL").action(async (options) => {
2259
+ const isJsonMode = !!options.json;
2260
+ let sourceUrl = options.from;
2261
+ if (!sourceUrl) {
2262
+ if (isJsonMode) {
2263
+ console.log(JSON.stringify({ status: "error", error: "Missing --from URL", code: "MISSING_URL" }, null, 2));
2264
+ process.exit(1);
2265
+ }
2266
+ console.log(import_chalk12.default.cyan("Create a product from an A2A agent URL.\n"));
2267
+ sourceUrl = await promptText("Enter the agent URL");
2268
+ if (!sourceUrl) {
2269
+ console.log(import_chalk12.default.red("A URL is required to create a product."));
2270
+ process.exit(1);
2271
+ }
2272
+ }
2273
+ const spinner = (0, import_ora7.default)("Validating URL...").start();
1670
2274
  try {
1671
- const result = await validateUrl(options.from, options.apiUrl);
2275
+ const result = await validateUrl(sourceUrl, options.apiUrl);
1672
2276
  if (!result.valid) {
1673
2277
  spinner.fail("Validation failed");
1674
- if (options.json) {
2278
+ if (isJsonMode) {
1675
2279
  console.log(
1676
2280
  JSON.stringify(
1677
- {
1678
- status: "error",
1679
- error: result.error,
1680
- code: result.code
1681
- },
2281
+ { status: "error", error: result.error, code: result.code },
1682
2282
  null,
1683
2283
  2
1684
2284
  )
1685
2285
  );
1686
2286
  } else {
1687
- console.error(import_chalk9.default.red(result.error));
2287
+ console.error(import_chalk12.default.red(result.error));
1688
2288
  }
1689
2289
  process.exit(1);
1690
2290
  }
1691
2291
  spinner.succeed("A2A Agent Detected");
1692
2292
  displayAgentCard(result.agentCard);
1693
- const store = new CredentialStore();
1694
- const apiKey = await store.getApiKey();
1695
- if (!apiKey) {
1696
- if (options.json) {
1697
- console.log(
1698
- JSON.stringify(
1699
- {
1700
- status: "unauthenticated",
1701
- agentCard: result.agentCard,
1702
- message: "Authentication required to create product"
1703
- },
1704
- null,
1705
- 2
1706
- )
1707
- );
1708
- } else {
1709
- console.log(import_chalk9.default.yellow("\nAuthentication required to create product."));
1710
- console.log("Run: runtype auth login");
1711
- console.log(`
1712
- Then retry: runtype products init --from ${options.from}`);
2293
+ if (!isJsonMode) {
2294
+ const shouldCreate = await promptConfirm("\nCreate a product from this agent?", { default: true });
2295
+ if (!shouldCreate) {
2296
+ console.log(import_chalk12.default.gray("Product creation cancelled."));
2297
+ return;
1713
2298
  }
1714
- process.exit(0);
2299
+ }
2300
+ let productName = options.name;
2301
+ if (!productName && !isJsonMode) {
2302
+ productName = await promptText("Product name", { default: result.agentCard.name });
2303
+ }
2304
+ const apiKey = isJsonMode ? await getApiKeyOrExit(isJsonMode, result.agentCard) : await ensureAuth({ apiUrl: options.apiUrl });
2305
+ if (!apiKey) {
2306
+ process.exit(1);
1715
2307
  }
1716
2308
  if (options.open) {
1717
2309
  const dashboardUrl = getDashboardUrl();
1718
- const encodedUrl = encodeURIComponent(options.from);
2310
+ const encodedUrl = encodeURIComponent(sourceUrl);
1719
2311
  const targetUrl = `${dashboardUrl}/now?from=${encodedUrl}&cli=true`;
1720
- if (options.json) {
2312
+ if (isJsonMode) {
1721
2313
  console.log(
1722
2314
  JSON.stringify(
1723
2315
  {
@@ -1730,38 +2322,34 @@ Then retry: runtype products init --from ${options.from}`);
1730
2322
  )
1731
2323
  );
1732
2324
  } else {
1733
- console.log(import_chalk9.default.cyan("\nOpening browser to complete setup..."));
1734
- console.log(import_chalk9.default.gray(targetUrl));
2325
+ console.log(import_chalk12.default.cyan("\nOpening browser to complete setup..."));
2326
+ console.log(import_chalk12.default.gray(targetUrl));
1735
2327
  }
1736
2328
  await (0, import_open2.default)(targetUrl);
1737
2329
  return;
1738
2330
  }
1739
- const createSpinner = (0, import_ora6.default)("Creating product...").start();
2331
+ const createSpinner = (0, import_ora7.default)("Creating product...").start();
1740
2332
  try {
1741
2333
  const createResult = await createProduct(
1742
2334
  apiKey,
1743
2335
  result.templateId,
1744
2336
  result.agentCard,
1745
- options.from,
1746
- options.name,
2337
+ sourceUrl,
2338
+ productName,
1747
2339
  options.apiUrl
1748
2340
  );
1749
2341
  if (!createResult.success) {
1750
2342
  createSpinner.fail("Failed to create product");
1751
- if (options.json) {
2343
+ if (isJsonMode) {
1752
2344
  console.log(
1753
2345
  JSON.stringify(
1754
- {
1755
- status: "error",
1756
- error: createResult.error,
1757
- code: createResult.code
1758
- },
2346
+ { status: "error", error: createResult.error, code: createResult.code },
1759
2347
  null,
1760
2348
  2
1761
2349
  )
1762
2350
  );
1763
2351
  } else {
1764
- console.error(import_chalk9.default.red(createResult.error));
2352
+ console.error(import_chalk12.default.red(createResult.error));
1765
2353
  }
1766
2354
  process.exit(1);
1767
2355
  }
@@ -1770,60 +2358,1769 @@ Then retry: runtype products init --from ${options.from}`);
1770
2358
  createResult,
1771
2359
  result.agentCard,
1772
2360
  getDashboardUrl(),
1773
- options.json || false
2361
+ isJsonMode
1774
2362
  );
1775
2363
  } catch (error) {
1776
2364
  const message = error instanceof Error ? error.message : "Unknown error";
1777
2365
  createSpinner.fail("Failed to create product");
1778
- console.error(import_chalk9.default.red(message));
2366
+ console.error(import_chalk12.default.red(message));
1779
2367
  process.exit(1);
1780
2368
  }
1781
2369
  } catch (error) {
1782
2370
  const message = error instanceof Error ? error.message : "Unknown error";
1783
2371
  spinner.fail("Failed to validate URL");
1784
- console.error(import_chalk9.default.red(message));
2372
+ console.error(import_chalk12.default.red(message));
1785
2373
  process.exit(1);
1786
2374
  }
1787
2375
  });
2376
+ async function getApiKeyOrExit(isJsonMode, agentCard) {
2377
+ const { CredentialStore: CredentialStore2 } = await Promise.resolve().then(() => (init_credential_store(), credential_store_exports));
2378
+ const store = new CredentialStore2();
2379
+ const apiKey = await store.getApiKey();
2380
+ if (!apiKey) {
2381
+ if (isJsonMode) {
2382
+ console.log(
2383
+ JSON.stringify(
2384
+ {
2385
+ status: "unauthenticated",
2386
+ agentCard,
2387
+ message: "Authentication required to create product"
2388
+ },
2389
+ null,
2390
+ 2
2391
+ )
2392
+ );
2393
+ }
2394
+ return null;
2395
+ }
2396
+ return apiKey;
2397
+ }
1788
2398
 
1789
- // src/index.ts
1790
- (0, import_dotenv.config)();
1791
- var program = new import_commander9.Command();
1792
- program.name("runtype").description("CLI for Runtype AI Platform").version("0.1.0").option("-v, --verbose", "Enable verbose output").option("--api-url <url>", "Override API URL").option("--json", "Output in JSON format");
1793
- program.addCommand(authCommand);
1794
- program.addCommand(flowsCommand);
1795
- program.addCommand(recordsCommand);
1796
- program.addCommand(promptsCommand);
1797
- program.addCommand(batchCommand);
1798
- program.addCommand(talkCommand);
1799
- program.addCommand(configCommand);
1800
- program.addCommand(productsCommand);
1801
- program.exitOverride();
1802
- try {
1803
- program.parse(process.argv);
1804
- } catch (error) {
1805
- if (error.code === "commander.missingArgument") {
1806
- console.error(import_chalk10.default.red(`Error: ${error.message}`));
2399
+ // src/commands/init.ts
2400
+ init_cjs_shims();
2401
+ var import_commander9 = require("commander");
2402
+ var import_chalk13 = __toESM(require("chalk"));
2403
+ var import_ora8 = __toESM(require("ora"));
2404
+ init_credential_store();
2405
+ var initCommand = new import_commander9.Command("init").description("Set up Runtype CLI with guided onboarding").option("--api-url <url>", "Custom API URL").action(async (options) => {
2406
+ console.log(import_chalk13.default.cyan("\nWelcome to Runtype!\n"));
2407
+ console.log("This will walk you through setting up the CLI.\n");
2408
+ const store = new CredentialStore();
2409
+ const existingKey = await store.getApiKey();
2410
+ if (existingKey) {
2411
+ console.log(import_chalk13.default.green("You are already authenticated."));
2412
+ const apiKeyManager = new ApiKeyManager();
2413
+ try {
2414
+ const isValid = await apiKeyManager.validateApiKey(existingKey, options.apiUrl);
2415
+ if (isValid) {
2416
+ console.log(import_chalk13.default.green("Your credentials are valid.\n"));
2417
+ const continueSetup = await promptConfirm("Continue with product setup?", { default: true });
2418
+ if (!continueSetup) {
2419
+ showNextSteps();
2420
+ return;
2421
+ }
2422
+ await productSetupFlow(existingKey, options.apiUrl);
2423
+ return;
2424
+ } else {
2425
+ console.log(import_chalk13.default.yellow("Your stored credentials are no longer valid."));
2426
+ console.log(import_chalk13.default.gray("Let's set up fresh credentials.\n"));
2427
+ }
2428
+ } catch {
2429
+ console.log(import_chalk13.default.yellow("Could not validate stored credentials."));
2430
+ console.log(import_chalk13.default.gray("Let's set up fresh credentials.\n"));
2431
+ }
2432
+ }
2433
+ console.log(import_chalk13.default.cyan("Step 1: Authentication\n"));
2434
+ const authMethod = await promptSelect("How would you like to get started?", [
2435
+ { label: "Create a new account", value: "signup", description: "Sign up via browser" },
2436
+ { label: "Log in to existing account", value: "login", description: "Sign in via browser" },
2437
+ { label: "Use an API key", value: "apikey", description: "Paste an existing API key" }
2438
+ ]);
2439
+ let apiKey = null;
2440
+ if (authMethod === "apikey") {
2441
+ apiKey = await handleApiKeyAuth(store, options.apiUrl);
2442
+ } else {
2443
+ const mode = authMethod === "signup" ? "sign-up" : "sign-in";
2444
+ apiKey = await handleBrowserAuth(store, mode, options.apiUrl);
2445
+ }
2446
+ if (!apiKey) {
2447
+ console.log(import_chalk13.default.red('\nAuthentication was not completed. Run "runtype init" to try again.'));
1807
2448
  process.exit(1);
1808
- } else if (error.code === "commander.unknownOption") {
1809
- console.error(import_chalk10.default.red(`Error: ${error.message}`));
2449
+ }
2450
+ console.log();
2451
+ const wantsProduct = await promptConfirm("Would you like to create a product now?", { default: true });
2452
+ if (wantsProduct) {
2453
+ await productSetupFlow(apiKey, options.apiUrl);
2454
+ } else {
2455
+ showNextSteps();
2456
+ }
2457
+ });
2458
+ async function handleApiKeyAuth(store, apiUrl) {
2459
+ const key = await promptText("Enter your API key");
2460
+ if (!key) {
2461
+ console.log(import_chalk13.default.red("No API key provided."));
2462
+ return null;
2463
+ }
2464
+ const spinner = (0, import_ora8.default)("Validating API key...").start();
2465
+ try {
2466
+ const apiKeyManager = new ApiKeyManager();
2467
+ const isValid = await apiKeyManager.validateApiKey(key, apiUrl);
2468
+ if (!isValid) {
2469
+ spinner.fail("Invalid API key");
2470
+ return null;
2471
+ }
2472
+ const userData = await apiKeyManager.getCurrentUser(key, apiUrl);
2473
+ await store.saveCredentials({
2474
+ apiKey: key,
2475
+ // @snake-case-ok: API auth/me response uses snake_case
2476
+ userId: userData.user_id,
2477
+ // @snake-case-ok: API auth/me response uses snake_case
2478
+ orgId: userData.org_id ?? void 0,
2479
+ apiUrl: apiUrl || getApiUrl()
2480
+ });
2481
+ spinner.succeed("Authenticated successfully!");
2482
+ return key;
2483
+ } catch (error) {
2484
+ const message = error instanceof Error ? error.message : "Unknown error";
2485
+ spinner.fail("Authentication failed");
2486
+ console.error(import_chalk13.default.red(message));
2487
+ return null;
2488
+ }
2489
+ }
2490
+ async function handleBrowserAuth(store, mode, apiUrl) {
2491
+ const spinner = (0, import_ora8.default)("Opening browser for authentication...").start();
2492
+ try {
2493
+ const oauth = new OAuthManager({
2494
+ clerkPublishableKey: getClerkPublishableKey(),
2495
+ dashboardUrl: getDashboardUrl()
2496
+ });
2497
+ spinner.text = "Waiting for browser authentication...";
2498
+ const sessionToken = await oauth.authenticate(mode);
2499
+ spinner.text = "Exchanging credentials...";
2500
+ const apiKeyManager = new ApiKeyManager();
2501
+ const { key, userId, orgId } = await apiKeyManager.exchangeSessionForApiKey(
2502
+ sessionToken,
2503
+ apiUrl || getApiUrl()
2504
+ );
2505
+ await store.saveCredentials({
2506
+ apiKey: key,
2507
+ userId,
2508
+ orgId,
2509
+ apiUrl: apiUrl || getApiUrl()
2510
+ });
2511
+ spinner.succeed("Authenticated successfully!");
2512
+ return key;
2513
+ } catch (error) {
2514
+ const message = error instanceof Error ? error.message : "Unknown error";
2515
+ spinner.fail("Authentication failed");
2516
+ console.error(import_chalk13.default.red(message));
2517
+ return null;
2518
+ }
2519
+ }
2520
+ async function productSetupFlow(apiKey, apiUrl) {
2521
+ console.log(import_chalk13.default.cyan("\nStep 2: Create a product\n"));
2522
+ const sourceType = await promptSelect("What would you like to import?", [
2523
+ { label: "A2A agent URL", value: "url", description: "Import from an agent endpoint" },
2524
+ { label: "Skip for now", value: "skip", description: "Set up a product later" }
2525
+ ]);
2526
+ if (sourceType === "skip") {
2527
+ showNextSteps();
2528
+ return;
2529
+ }
2530
+ const url = await promptText("Enter the agent URL");
2531
+ if (!url) {
2532
+ console.log(import_chalk13.default.yellow("No URL provided. You can create a product later with:"));
2533
+ console.log(import_chalk13.default.gray(" runtype products init"));
2534
+ return;
2535
+ }
2536
+ const spinner = (0, import_ora8.default)("Validating URL...").start();
2537
+ try {
2538
+ const baseUrl = apiUrl || getApiUrl();
2539
+ const response = await fetch(`${baseUrl}/${getApiVersion()}/quick-start/validate`, {
2540
+ method: "POST",
2541
+ headers: { "Content-Type": "application/json" },
2542
+ body: JSON.stringify({ url })
2543
+ });
2544
+ const contentType = response.headers.get("content-type") || "";
2545
+ if (!contentType.includes("application/json")) {
2546
+ spinner.fail("Validation failed");
2547
+ console.error(import_chalk13.default.red(`API error: ${response.status} ${response.statusText}`));
2548
+ return;
2549
+ }
2550
+ const result = await response.json();
2551
+ if (!result.valid) {
2552
+ spinner.fail("Validation failed");
2553
+ console.error(import_chalk13.default.red(result.error));
2554
+ return;
2555
+ }
2556
+ spinner.succeed("A2A Agent Detected");
2557
+ console.log(import_chalk13.default.cyan("\nAgent Details:"));
2558
+ console.log(` Name: ${result.agentCard.name}`);
2559
+ if (result.agentCard.description) {
2560
+ console.log(` Description: ${result.agentCard.description}`);
2561
+ }
2562
+ console.log(` URL: ${result.agentCard.url}`);
2563
+ if (result.agentCard.skills?.length > 0) {
2564
+ console.log(" Skills:");
2565
+ for (const skill of result.agentCard.skills) {
2566
+ const desc = skill.description ? ` - ${skill.description}` : "";
2567
+ console.log(` ${import_chalk13.default.cyan("\u2022")} ${skill.name}${desc}`);
2568
+ }
2569
+ }
2570
+ const shouldCreate = await promptConfirm("\nCreate this product?", { default: true });
2571
+ if (!shouldCreate) {
2572
+ console.log(import_chalk13.default.gray("Product creation cancelled."));
2573
+ showNextSteps();
2574
+ return;
2575
+ }
2576
+ const productName = await promptText("Product name", { default: result.agentCard.name });
2577
+ const createSpinner = (0, import_ora8.default)("Creating product...").start();
2578
+ const createResponse = await fetch(`${baseUrl}/${getApiVersion()}/quick-start/create`, {
2579
+ method: "POST",
2580
+ headers: {
2581
+ Authorization: `Bearer ${apiKey}`,
2582
+ "Content-Type": "application/json"
2583
+ },
2584
+ body: JSON.stringify({
2585
+ templateId: result.templateId,
2586
+ agentCard: result.agentCard,
2587
+ productName,
2588
+ sourceUrl: url
2589
+ })
2590
+ });
2591
+ const createContentType = createResponse.headers.get("content-type") || "";
2592
+ if (!createContentType.includes("application/json")) {
2593
+ createSpinner.fail("Failed to create product");
2594
+ console.error(import_chalk13.default.red(`API error: ${createResponse.status} ${createResponse.statusText}`));
2595
+ return;
2596
+ }
2597
+ const createResult = await createResponse.json();
2598
+ if (!createResult.success) {
2599
+ createSpinner.fail("Failed to create product");
2600
+ console.error(import_chalk13.default.red(createResult.error));
2601
+ return;
2602
+ }
2603
+ createSpinner.succeed("Product Created");
2604
+ const dashboardUrl = getDashboardUrl();
2605
+ const productUrl = `${dashboardUrl}/products/${createResult.product.id}?launch=true`;
2606
+ console.log(`
2607
+ Product ID: ${createResult.product.id}`);
2608
+ console.log(`Name: ${createResult.product.name}`);
2609
+ console.log(`Dashboard: ${productUrl}`);
2610
+ console.log(import_chalk13.default.green("\nSetup complete!"));
2611
+ showNextSteps();
2612
+ } catch (error) {
2613
+ const message = error instanceof Error ? error.message : "Unknown error";
2614
+ spinner.fail("Failed to validate URL");
2615
+ console.error(import_chalk13.default.red(message));
2616
+ }
2617
+ }
2618
+ function showNextSteps() {
2619
+ console.log(import_chalk13.default.cyan("\nWhat you can do next:"));
2620
+ console.log(` ${import_chalk13.default.green("runtype products init")} Create a product from an agent URL`);
2621
+ console.log(` ${import_chalk13.default.green("runtype flows list")} List your flows`);
2622
+ console.log(` ${import_chalk13.default.green("runtype dispatch -f <id>")} Execute a flow`);
2623
+ console.log(` ${import_chalk13.default.green("runtype agents list")} List your agents`);
2624
+ console.log(` ${import_chalk13.default.green("runtype models list")} View enabled models`);
2625
+ console.log(` ${import_chalk13.default.green("runtype talk")} Start an interactive chat session`);
2626
+ console.log(` ${import_chalk13.default.green("runtype --help")} See all available commands`);
2627
+ }
2628
+
2629
+ // src/commands/dispatch.ts
2630
+ init_cjs_shims();
2631
+ var import_commander10 = require("commander");
2632
+ var import_chalk14 = __toESM(require("chalk"));
2633
+ var import_ora9 = __toESM(require("ora"));
2634
+ var import_fs5 = require("fs");
2635
+ var import_sdk4 = require("@runtypelabs/sdk");
2636
+ var dispatchCommand = new import_commander10.Command("dispatch").description("Execute a flow or agent via the dispatch API").option("-f, --flow <id>", "Flow ID to execute").option("-a, --agent <id>", "Agent ID to execute").option("-r, --record <id>", "Existing record ID").option("--record-json <file>", "JSON file with record data").option("-m, --message <text>", "Message to send").option("-v, --variable <key=value>", "Set a variable (repeatable)", collectVariables, []).option("--stream", "Stream the response (default)", true).option("--no-stream", "Wait for complete response").option("--json", "Output as JSON").option("--debug", "Show step-level details").action(async (options) => {
2637
+ if (!options.flow && !options.agent) {
2638
+ console.error(import_chalk14.default.red("Error: Either --flow or --agent is required"));
1810
2639
  process.exit(1);
1811
- } else if (error.code === "commander.help") {
1812
- process.exit(0);
2640
+ }
2641
+ const apiKey = await ensureAuth();
2642
+ if (!apiKey) return;
2643
+ const client = new ApiClient(apiKey);
2644
+ const payload = {};
2645
+ if (options.flow) {
2646
+ payload.flow = { id: options.flow };
2647
+ }
2648
+ if (options.agent) {
2649
+ payload.agent = { id: options.agent };
2650
+ }
2651
+ if (options.record) {
2652
+ payload.record = { id: options.record };
2653
+ } else if (options.recordJson) {
2654
+ try {
2655
+ const data = JSON.parse((0, import_fs5.readFileSync)(options.recordJson, "utf-8"));
2656
+ payload.record = { metadata: data };
2657
+ } catch (error) {
2658
+ const message = error instanceof Error ? error.message : "Unknown error";
2659
+ console.error(import_chalk14.default.red(`Failed to read record JSON: ${message}`));
2660
+ process.exit(1);
2661
+ }
2662
+ }
2663
+ if (options.message) {
2664
+ payload.messages = [{ role: "user", content: options.message }];
2665
+ }
2666
+ if (options.variable && options.variable.length > 0) {
2667
+ const variables = {};
2668
+ for (const v of options.variable) {
2669
+ const [key, ...rest] = v.split("=");
2670
+ variables[key] = rest.join("=");
2671
+ }
2672
+ payload.variables = variables;
2673
+ }
2674
+ if (options.stream) {
2675
+ await handleStreaming(client, payload, options);
1813
2676
  } else {
1814
- console.error(import_chalk10.default.red("An unexpected error occurred:"));
1815
- console.error(error);
2677
+ await handleNonStreaming(client, payload, options);
2678
+ }
2679
+ });
2680
+ function collectVariables(value, previous) {
2681
+ return previous.concat([value]);
2682
+ }
2683
+ async function handleStreaming(client, payload, options) {
2684
+ const spinner = (0, import_ora9.default)("Starting execution...").start();
2685
+ let spinnerStopped = false;
2686
+ try {
2687
+ const response = await client.stream("/dispatch", payload);
2688
+ const callbacks = {
2689
+ onFlowStart: (event) => {
2690
+ if (!spinnerStopped) {
2691
+ spinner.stop();
2692
+ spinnerStopped = true;
2693
+ }
2694
+ if (options.debug) {
2695
+ console.log(import_chalk14.default.cyan(`Flow: ${event.flowName} (${event.totalSteps} steps)`));
2696
+ }
2697
+ },
2698
+ onStepStart: (event) => {
2699
+ if (!spinnerStopped) {
2700
+ spinner.stop();
2701
+ spinnerStopped = true;
2702
+ }
2703
+ if (options.debug) {
2704
+ console.log(import_chalk14.default.gray(`
2705
+ [${event.name}] Running...`));
2706
+ }
2707
+ },
2708
+ onStepChunk: (chunk) => {
2709
+ if (!spinnerStopped) {
2710
+ spinner.stop();
2711
+ spinnerStopped = true;
2712
+ }
2713
+ process.stdout.write(chunk);
2714
+ },
2715
+ onStepComplete: (_result, event) => {
2716
+ if (options.debug) {
2717
+ console.log(import_chalk14.default.gray(`
2718
+ [${event.name}] Complete`));
2719
+ }
2720
+ },
2721
+ onFlowComplete: (event) => {
2722
+ if (options.json) {
2723
+ console.log();
2724
+ printJson(event);
2725
+ }
2726
+ },
2727
+ onError: (err) => {
2728
+ if (!spinnerStopped) {
2729
+ spinner.fail("Execution failed");
2730
+ spinnerStopped = true;
2731
+ }
2732
+ console.error(import_chalk14.default.red(`
2733
+ Error: ${err.message}`));
2734
+ }
2735
+ };
2736
+ await (0, import_sdk4.processStream)(response, callbacks);
2737
+ console.log();
2738
+ } catch (error) {
2739
+ if (!spinnerStopped) {
2740
+ spinner.fail("Execution failed");
2741
+ }
2742
+ const message = error instanceof Error ? error.message : "Unknown error";
2743
+ console.error(import_chalk14.default.red(message));
1816
2744
  process.exit(1);
1817
2745
  }
1818
2746
  }
1819
- if (!process.argv.slice(2).length) {
2747
+ async function handleNonStreaming(client, payload, options) {
2748
+ const spinner = (0, import_ora9.default)("Executing...").start();
1820
2749
  try {
1821
- program.outputHelp();
2750
+ payload.streamResponse = false;
2751
+ const result = await client.post("/dispatch", payload);
2752
+ spinner.succeed("Execution complete");
2753
+ if (options.json) {
2754
+ printJson(result);
2755
+ } else {
2756
+ const steps = result.steps;
2757
+ if (steps) {
2758
+ for (const step of steps) {
2759
+ console.log(import_chalk14.default.cyan(`
2760
+ [${step.name}]`));
2761
+ if (typeof step.result === "string") {
2762
+ console.log(step.result);
2763
+ } else {
2764
+ console.log(JSON.stringify(step.result, null, 2));
2765
+ }
2766
+ }
2767
+ } else {
2768
+ printJson(result);
2769
+ }
2770
+ }
1822
2771
  } catch (error) {
1823
- if (error.code === "commander.help") {
1824
- process.exit(0);
2772
+ spinner.fail("Execution failed");
2773
+ const message = error instanceof Error ? error.message : "Unknown error";
2774
+ console.error(import_chalk14.default.red(message));
2775
+ process.exit(1);
2776
+ }
2777
+ }
2778
+
2779
+ // src/commands/agents.ts
2780
+ init_cjs_shims();
2781
+ var import_commander12 = require("commander");
2782
+ var import_chalk16 = __toESM(require("chalk"));
2783
+ var import_ora11 = __toESM(require("ora"));
2784
+ var import_sdk6 = require("@runtypelabs/sdk");
2785
+
2786
+ // src/commands/agents-run-task.ts
2787
+ init_cjs_shims();
2788
+ var import_commander11 = require("commander");
2789
+ var import_chalk15 = __toESM(require("chalk"));
2790
+ var import_ora10 = __toESM(require("ora"));
2791
+ var fs3 = __toESM(require("fs"));
2792
+ var path4 = __toESM(require("path"));
2793
+ var import_sdk5 = require("@runtypelabs/sdk");
2794
+ function defaultStateDir() {
2795
+ return path4.join(process.cwd(), ".runtype", "tasks");
2796
+ }
2797
+ function stateFilePath(name, stateDir) {
2798
+ const dir = stateDir || defaultStateDir();
2799
+ const safeName = name.replace(/[^a-zA-Z0-9_-]/g, "_");
2800
+ return path4.join(dir, `${safeName}.json`);
2801
+ }
2802
+ function loadState(filePath) {
2803
+ try {
2804
+ const raw = fs3.readFileSync(filePath, "utf-8");
2805
+ return JSON.parse(raw);
2806
+ } catch {
2807
+ return null;
2808
+ }
2809
+ }
2810
+ function saveState(filePath, state) {
2811
+ const dir = path4.dirname(filePath);
2812
+ fs3.mkdirSync(dir, { recursive: true });
2813
+ state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2814
+ fs3.writeFileSync(filePath, JSON.stringify(state, null, 2));
2815
+ }
2816
+ var runTaskCommand = new import_commander11.Command("run-task").description("Run a long-task agent with local state persistence").argument("<agent>", "Agent ID or name").requiredOption("-m, --message <text>", "Task message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--name <name>", "Task name (used for state file, defaults to agent ID)").option("--state-dir <path>", "Directory for state files (default: .runtype/tasks/)").option("--resume", "Resume from existing local state").option("--track-progress", "Also sync progress to the Runtype dashboard").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").action(
2817
+ async (agent, options) => {
2818
+ const apiKey = await ensureAuth();
2819
+ if (!apiKey) return;
2820
+ const client = new import_sdk5.RuntypeClient({
2821
+ apiKey,
2822
+ baseUrl: getApiUrl()
2823
+ });
2824
+ let agentId = agent;
2825
+ if (!agent.startsWith("agent_")) {
2826
+ const spinner = (0, import_ora10.default)("Looking up agent by name...").start();
2827
+ try {
2828
+ const list = await client.agents.list();
2829
+ const found = list.data.find(
2830
+ (a) => a.name.toLowerCase() === agent.toLowerCase()
2831
+ );
2832
+ if (found) {
2833
+ agentId = found.id;
2834
+ spinner.succeed(`Found agent: ${import_chalk15.default.green(agentId)}`);
2835
+ } else {
2836
+ spinner.fail(`No agent found with name "${agent}"`);
2837
+ console.log(import_chalk15.default.gray(` Create one with: runtype agents create -n "${agent}"`));
2838
+ process.exit(1);
2839
+ }
2840
+ } catch (error) {
2841
+ spinner.fail("Failed to look up agent");
2842
+ const message = error instanceof Error ? error.message : "Unknown error";
2843
+ console.error(import_chalk15.default.red(message));
2844
+ process.exit(1);
2845
+ }
2846
+ }
2847
+ const taskName = options.name || agentId;
2848
+ const filePath = stateFilePath(taskName, options.stateDir);
2849
+ const maxSessions = parseInt(options.maxSessions, 10);
2850
+ const maxCost = options.maxCost ? parseFloat(options.maxCost) : void 0;
2851
+ let localState;
2852
+ let priorSessionCount = 0;
2853
+ let priorCost = 0;
2854
+ if (options.resume) {
2855
+ const existing = loadState(filePath);
2856
+ if (!existing) {
2857
+ console.error(import_chalk15.default.red(`No state file found at ${filePath}`));
2858
+ console.log(import_chalk15.default.gray(" Run without --resume to start a new task."));
2859
+ process.exit(1);
2860
+ }
2861
+ if (existing.status === "complete") {
2862
+ console.log(import_chalk15.default.yellow("This task already completed."));
2863
+ if (options.json) printJson(existing);
2864
+ return;
2865
+ }
2866
+ localState = existing;
2867
+ localState.status = "running";
2868
+ priorSessionCount = localState.sessionCount;
2869
+ priorCost = localState.totalCost;
2870
+ console.log(
2871
+ import_chalk15.default.cyan(
2872
+ `Resuming from session ${priorSessionCount} ($${priorCost.toFixed(4)} spent)`
2873
+ )
2874
+ );
1825
2875
  } else {
1826
- throw error;
2876
+ localState = {
2877
+ agentId,
2878
+ taskName,
2879
+ message: options.message,
2880
+ status: "running",
2881
+ sessionCount: 0,
2882
+ totalCost: 0,
2883
+ context: {},
2884
+ lastOutput: "",
2885
+ sessions: [],
2886
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2887
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2888
+ };
2889
+ }
2890
+ let interrupted = false;
2891
+ const onSigint = () => {
2892
+ if (interrupted) process.exit(1);
2893
+ interrupted = true;
2894
+ console.log(import_chalk15.default.yellow("\n\nInterrupted \u2014 saving state..."));
2895
+ localState.status = "paused";
2896
+ saveState(filePath, localState);
2897
+ console.log(import_chalk15.default.green(`State saved to ${filePath}`));
2898
+ console.log(
2899
+ import_chalk15.default.gray(
2900
+ ` Resume with: runtype agents run-task ${agent} -m "${options.message}" --resume${options.name ? ` --name ${options.name}` : ""}`
2901
+ )
2902
+ );
2903
+ process.exit(0);
2904
+ };
2905
+ process.on("SIGINT", onSigint);
2906
+ const remainingSessions = maxSessions - priorSessionCount;
2907
+ console.log(import_chalk15.default.cyan(`
2908
+ Running task "${taskName}" on ${agentId}`));
2909
+ console.log(
2910
+ import_chalk15.default.gray(
2911
+ ` Sessions: ${priorSessionCount > 0 ? `${priorSessionCount} done, ` : ""}${remainingSessions} remaining${maxCost ? ` | Budget: $${maxCost.toFixed(2)}` : ""}`
2912
+ )
2913
+ );
2914
+ console.log(import_chalk15.default.gray(` State: ${filePath}
2915
+ `));
2916
+ try {
2917
+ const result = await client.agents.runTask(agentId, {
2918
+ buildMessages: (state) => {
2919
+ const merged = { ...localState.context, ...state.context };
2920
+ const isFirstSession = state.sessionCount === 1;
2921
+ const totalSession = priorSessionCount + state.sessionCount;
2922
+ if (isFirstSession && !options.resume) {
2923
+ return [{ role: "user", content: options.message }];
2924
+ }
2925
+ const progress = merged.progressNotes || merged.progress;
2926
+ const progressStr = progress ? typeof progress === "string" ? progress : JSON.stringify(progress) : "No structured progress captured yet";
2927
+ const resumeCtx = options.resume && isFirstSession ? `
2928
+
2929
+ Resuming from session ${priorSessionCount}. Previous context: ${JSON.stringify(localState.context)}` : "";
2930
+ return [
2931
+ {
2932
+ role: "user",
2933
+ content: `${options.message}${resumeCtx}
2934
+
2935
+ Progress so far: ${progressStr}
2936
+ Session ${totalSession} of ${maxSessions}.`
2937
+ }
2938
+ ];
2939
+ },
2940
+ maxSessions: remainingSessions,
2941
+ maxCost,
2942
+ trackProgress: options.trackProgress ? taskName : void 0,
2943
+ debugMode: options.debug,
2944
+ onSession: (session) => {
2945
+ const sessionCost = session.sessionCount > 1 ? session.totalCost - localState.sessions.slice(-session.sessionCount + 1).reduce((s, e) => s + e.cost, 0) : session.totalCost;
2946
+ const thisCost = sessionCost > 0 ? sessionCost : session.totalCost / session.sessionCount;
2947
+ localState.sessionCount = priorSessionCount + session.sessionCount;
2948
+ localState.totalCost = priorCost + session.totalCost;
2949
+ Object.assign(localState.context, session.context);
2950
+ localState.lastOutput = session.lastOutput;
2951
+ localState.status = session.status;
2952
+ localState.sessions.push({
2953
+ index: localState.sessionCount,
2954
+ cost: thisCost,
2955
+ stopReason: session.lastStopReason,
2956
+ outputPreview: session.lastOutput.slice(0, 200),
2957
+ at: (/* @__PURE__ */ new Date()).toISOString()
2958
+ });
2959
+ saveState(filePath, localState);
2960
+ const total = localState.sessionCount;
2961
+ const costStr = import_chalk15.default.yellow(`$${localState.totalCost.toFixed(4)}`);
2962
+ const reasonColor = session.lastStopReason === "complete" ? import_chalk15.default.green : import_chalk15.default.gray;
2963
+ console.log(
2964
+ ` ${import_chalk15.default.dim(`[${total}/${maxSessions}]`)} ${reasonColor(session.lastStopReason)} | total: ${costStr}`
2965
+ );
2966
+ if (session.lastOutput) {
2967
+ const preview = session.lastOutput.slice(0, 120).replace(/\n/g, " ");
2968
+ console.log(
2969
+ ` ${import_chalk15.default.dim(preview)}${session.lastOutput.length > 120 ? "..." : ""}`
2970
+ );
2971
+ }
2972
+ }
2973
+ });
2974
+ localState.status = result.status;
2975
+ localState.totalCost = priorCost + result.totalCost;
2976
+ Object.assign(localState.context, result.context);
2977
+ saveState(filePath, localState);
2978
+ process.removeListener("SIGINT", onSigint);
2979
+ console.log();
2980
+ const statusColor = result.status === "complete" ? import_chalk15.default.green : result.status === "budget_exceeded" ? import_chalk15.default.red : import_chalk15.default.yellow;
2981
+ console.log(`Status: ${statusColor(localState.status)}`);
2982
+ console.log(`Sessions: ${localState.sessionCount}`);
2983
+ console.log(`Total cost: ${import_chalk15.default.yellow(`$${localState.totalCost.toFixed(4)}`)}`);
2984
+ console.log(`State: ${import_chalk15.default.gray(filePath)}`);
2985
+ if (localState.status === "paused" || localState.status === "max_sessions") {
2986
+ console.log(
2987
+ import_chalk15.default.gray(
2988
+ `
2989
+ Resume: runtype agents run-task ${agent} -m "${options.message}" --resume${options.name ? ` --name ${options.name}` : ""}`
2990
+ )
2991
+ );
2992
+ }
2993
+ if (options.json) {
2994
+ console.log();
2995
+ printJson(localState);
2996
+ }
2997
+ } catch (error) {
2998
+ localState.status = "paused";
2999
+ saveState(filePath, localState);
3000
+ process.removeListener("SIGINT", onSigint);
3001
+ const message = error instanceof Error ? error.message : "Unknown error";
3002
+ console.error(import_chalk15.default.red(`
3003
+ Task failed: ${message}`));
3004
+ console.log(import_chalk15.default.gray(`State saved to ${filePath} \u2014 resume with --resume`));
3005
+ process.exit(1);
3006
+ }
3007
+ }
3008
+ );
3009
+
3010
+ // src/commands/agents.ts
3011
+ var agentsCommand = new import_commander12.Command("agents").description("Manage agents");
3012
+ agentsCommand.addCommand(runTaskCommand);
3013
+ agentsCommand.command("list").description("List all agents").option("--json", "Output as JSON").option("--limit <n>", "Limit results", "20").action(async (options) => {
3014
+ const apiKey = await ensureAuth();
3015
+ if (!apiKey) return;
3016
+ const spinner = (0, import_ora11.default)("Fetching agents...").start();
3017
+ try {
3018
+ const client = new ApiClient(apiKey);
3019
+ const data = await client.get("/agents", {
3020
+ limit: options.limit
3021
+ });
3022
+ spinner.stop();
3023
+ if (options.json) {
3024
+ printJson(data);
3025
+ } else {
3026
+ const agents = data.data ?? [];
3027
+ if (agents.length === 0) {
3028
+ console.log(import_chalk16.default.gray("No agents found"));
3029
+ return;
3030
+ }
3031
+ console.log(import_chalk16.default.cyan("Your Agents:"));
3032
+ for (const agent of agents) {
3033
+ const desc = agent.description ? import_chalk16.default.gray(` - ${agent.description}`) : "";
3034
+ console.log(` ${import_chalk16.default.green(agent.id)} ${agent.name}${desc}`);
3035
+ }
3036
+ const total = getTotalCount(data.pagination);
3037
+ if (total !== void 0) {
3038
+ console.log(import_chalk16.default.dim(`
3039
+ Total: ${total} agents`));
3040
+ }
3041
+ }
3042
+ } catch (error) {
3043
+ const message = error instanceof Error ? error.message : "Unknown error";
3044
+ spinner.fail("Failed to fetch agents");
3045
+ console.error(import_chalk16.default.red(message));
3046
+ process.exit(1);
3047
+ }
3048
+ });
3049
+ agentsCommand.command("get <id>").description("Get agent details").option("--json", "Output as JSON").action(async (id, options) => {
3050
+ const apiKey = await ensureAuth();
3051
+ if (!apiKey) return;
3052
+ const spinner = (0, import_ora11.default)("Fetching agent...").start();
3053
+ try {
3054
+ const client = new ApiClient(apiKey);
3055
+ const data = await client.get(
3056
+ `/agents/${id}`
3057
+ );
3058
+ spinner.stop();
3059
+ if (options.json) {
3060
+ printJson(data);
3061
+ } else {
3062
+ printDetail("Agent", [
3063
+ { label: "ID", value: data.id },
3064
+ { label: "Name", value: data.name },
3065
+ { label: "Description", value: data.description },
3066
+ { label: "Status", value: data.status },
3067
+ { label: "Model", value: data.model }
3068
+ ]);
3069
+ if (data.capabilities && data.capabilities.length > 0) {
3070
+ console.log(import_chalk16.default.cyan("\n Capabilities:"));
3071
+ for (const cap of data.capabilities) {
3072
+ console.log(` ${import_chalk16.default.gray("-")} ${cap.name || cap.type || cap.id}`);
3073
+ }
3074
+ }
3075
+ }
3076
+ } catch (error) {
3077
+ const message = error instanceof Error ? error.message : "Unknown error";
3078
+ spinner.fail("Failed to fetch agent");
3079
+ console.error(import_chalk16.default.red(message));
3080
+ process.exit(1);
3081
+ }
3082
+ });
3083
+ agentsCommand.command("create").description("Create a new agent").requiredOption("-n, --name <name>", "Agent name").option("-d, --description <desc>", "Agent description").option("--json", "Output as JSON").action(async (options) => {
3084
+ const apiKey = await ensureAuth();
3085
+ if (!apiKey) return;
3086
+ const spinner = (0, import_ora11.default)("Creating agent...").start();
3087
+ try {
3088
+ const client = new ApiClient(apiKey);
3089
+ const data = await client.post("/agents", {
3090
+ name: options.name,
3091
+ description: options.description
3092
+ });
3093
+ spinner.succeed("Agent created");
3094
+ if (options.json) {
3095
+ printJson(data);
3096
+ } else {
3097
+ console.log(` ID: ${import_chalk16.default.green(data.id)}`);
3098
+ console.log(` Name: ${data.name}`);
3099
+ }
3100
+ } catch (error) {
3101
+ const message = error instanceof Error ? error.message : "Unknown error";
3102
+ spinner.fail("Failed to create agent");
3103
+ console.error(import_chalk16.default.red(message));
3104
+ process.exit(1);
3105
+ }
3106
+ });
3107
+ agentsCommand.command("delete <id>").description("Delete an agent").action(async (id) => {
3108
+ const apiKey = await ensureAuth();
3109
+ if (!apiKey) return;
3110
+ const spinner = (0, import_ora11.default)("Deleting agent...").start();
3111
+ try {
3112
+ const client = new ApiClient(apiKey);
3113
+ await client.delete(`/agents/${id}`);
3114
+ spinner.succeed("Agent deleted");
3115
+ } catch (error) {
3116
+ const message = error instanceof Error ? error.message : "Unknown error";
3117
+ spinner.fail("Failed to delete agent");
3118
+ console.error(import_chalk16.default.red(message));
3119
+ process.exit(1);
3120
+ }
3121
+ });
3122
+ agentsCommand.command("execute <id>").description("Execute an agent").requiredOption("-m, --message <text>", "Message to send").option("--stream", "Stream the response (default)", true).option("--no-stream", "Wait for complete response").option("--json", "Output as JSON").action(async (id, options) => {
3123
+ const apiKey = await ensureAuth();
3124
+ if (!apiKey) return;
3125
+ const client = new ApiClient(apiKey);
3126
+ const payload = {
3127
+ messages: [{ role: "user", content: options.message }]
3128
+ };
3129
+ if (options.stream) {
3130
+ const spinner = (0, import_ora11.default)("Starting agent...").start();
3131
+ try {
3132
+ const response = await client.stream(`/agents/${id}/execute`, payload);
3133
+ spinner.stop();
3134
+ const callbacks = {
3135
+ onStepChunk: (chunk) => {
3136
+ process.stdout.write(chunk);
3137
+ },
3138
+ onError: (err) => {
3139
+ console.error(import_chalk16.default.red(`
3140
+ Error: ${err.message}`));
3141
+ }
3142
+ };
3143
+ await (0, import_sdk6.processStream)(response, callbacks);
3144
+ console.log();
3145
+ } catch (error) {
3146
+ spinner.fail("Execution failed");
3147
+ const message = error instanceof Error ? error.message : "Unknown error";
3148
+ console.error(import_chalk16.default.red(message));
3149
+ process.exit(1);
3150
+ }
3151
+ } else {
3152
+ const spinner = (0, import_ora11.default)("Executing agent...").start();
3153
+ try {
3154
+ const result = await client.post(`/agents/${id}/execute`, {
3155
+ ...payload,
3156
+ streamResponse: false
3157
+ });
3158
+ spinner.succeed("Execution complete");
3159
+ if (options.json) {
3160
+ printJson(result);
3161
+ } else {
3162
+ printJson(result);
3163
+ }
3164
+ } catch (error) {
3165
+ spinner.fail("Execution failed");
3166
+ const message = error instanceof Error ? error.message : "Unknown error";
3167
+ console.error(import_chalk16.default.red(message));
3168
+ process.exit(1);
3169
+ }
3170
+ }
3171
+ });
3172
+
3173
+ // src/commands/models.ts
3174
+ init_cjs_shims();
3175
+ var import_commander13 = require("commander");
3176
+ var import_chalk17 = __toESM(require("chalk"));
3177
+ var import_ora12 = __toESM(require("ora"));
3178
+ var modelsCommand = new import_commander13.Command("models").description("Manage model configurations");
3179
+ modelsCommand.command("list").description("List your enabled model configurations").option("--json", "Output as JSON").action(async (options) => {
3180
+ const apiKey = await ensureAuth();
3181
+ if (!apiKey) return;
3182
+ const spinner = (0, import_ora12.default)("Fetching model configurations...").start();
3183
+ try {
3184
+ const client = new ApiClient(apiKey);
3185
+ const data = await client.get("/model-configs");
3186
+ spinner.stop();
3187
+ if (options.json) {
3188
+ printJson(data);
3189
+ } else {
3190
+ const models = data.data ?? [];
3191
+ if (models.length === 0) {
3192
+ console.log(import_chalk17.default.gray("No model configurations found"));
3193
+ return;
3194
+ }
3195
+ console.log(import_chalk17.default.cyan("Your Models:"));
3196
+ for (const model of models) {
3197
+ const defaultTag = model.isDefault ? import_chalk17.default.yellow(" (default)") : "";
3198
+ const statusTag = model.enabled === false ? import_chalk17.default.red(" [disabled]") : "";
3199
+ console.log(` ${import_chalk17.default.green(model.id)} ${model.modelId}${defaultTag}${statusTag}`);
3200
+ }
3201
+ const total = getTotalCount(data.pagination);
3202
+ if (total !== void 0) {
3203
+ console.log(import_chalk17.default.dim(`
3204
+ Total: ${total} models`));
3205
+ }
3206
+ }
3207
+ } catch (error) {
3208
+ const message = error instanceof Error ? error.message : "Unknown error";
3209
+ spinner.fail("Failed to fetch models");
3210
+ console.error(import_chalk17.default.red(message));
3211
+ process.exit(1);
3212
+ }
3213
+ });
3214
+ modelsCommand.command("available").description("List all available models grouped by provider").option("--json", "Output as JSON").action(async (options) => {
3215
+ const apiKey = await ensureAuth();
3216
+ if (!apiKey) return;
3217
+ const spinner = (0, import_ora12.default)("Fetching available models...").start();
3218
+ try {
3219
+ const client = new ApiClient(apiKey);
3220
+ const data = await client.get("/model-configs/grouped");
3221
+ spinner.stop();
3222
+ if (options.json) {
3223
+ printJson(data);
3224
+ } else {
3225
+ const groups = data.data ?? [];
3226
+ if (groups.length === 0) {
3227
+ console.log(import_chalk17.default.gray("No models available"));
3228
+ return;
3229
+ }
3230
+ console.log(import_chalk17.default.cyan("Available Models:"));
3231
+ for (const group of groups) {
3232
+ console.log(`
3233
+ ${import_chalk17.default.blue(group.provider)} / ${import_chalk17.default.green(group.baseModel)}`);
3234
+ for (const variant of group.variants) {
3235
+ const configuredTag = variant.configured ? import_chalk17.default.green(" [configured]") : "";
3236
+ console.log(` ${variant.modelId}${configuredTag}`);
3237
+ }
3238
+ }
3239
+ }
3240
+ } catch (error) {
3241
+ const message = error instanceof Error ? error.message : "Unknown error";
3242
+ spinner.fail("Failed to fetch available models");
3243
+ console.error(import_chalk17.default.red(message));
3244
+ process.exit(1);
3245
+ }
3246
+ });
3247
+ modelsCommand.command("enable <modelId>").description("Enable a model by creating a configuration").option("--json", "Output as JSON").action(async (modelId, options) => {
3248
+ const apiKey = await ensureAuth();
3249
+ if (!apiKey) return;
3250
+ const spinner = (0, import_ora12.default)(`Enabling model ${modelId}...`).start();
3251
+ try {
3252
+ const client = new ApiClient(apiKey);
3253
+ const data = await client.post("/model-configs", { modelId });
3254
+ spinner.succeed("Model enabled");
3255
+ if (options.json) {
3256
+ printJson(data);
3257
+ } else {
3258
+ console.log(` Config ID: ${import_chalk17.default.green(data.id)}`);
3259
+ console.log(` Model: ${data.modelId}`);
3260
+ }
3261
+ } catch (error) {
3262
+ const message = error instanceof Error ? error.message : "Unknown error";
3263
+ spinner.fail("Failed to enable model");
3264
+ console.error(import_chalk17.default.red(message));
3265
+ process.exit(1);
3266
+ }
3267
+ });
3268
+ modelsCommand.command("disable <id>").description("Disable a model configuration").action(async (id) => {
3269
+ const apiKey = await ensureAuth();
3270
+ if (!apiKey) return;
3271
+ const spinner = (0, import_ora12.default)("Disabling model...").start();
3272
+ try {
3273
+ const client = new ApiClient(apiKey);
3274
+ await client.patch(`/model-configs/${id}/status`, { enabled: false });
3275
+ spinner.succeed("Model disabled");
3276
+ } catch (error) {
3277
+ const message = error instanceof Error ? error.message : "Unknown error";
3278
+ spinner.fail("Failed to disable model");
3279
+ console.error(import_chalk17.default.red(message));
3280
+ process.exit(1);
3281
+ }
3282
+ });
3283
+ modelsCommand.command("default <id>").description("Set a model configuration as default").action(async (id) => {
3284
+ const apiKey = await ensureAuth();
3285
+ if (!apiKey) return;
3286
+ const spinner = (0, import_ora12.default)("Setting default model...").start();
3287
+ try {
3288
+ const client = new ApiClient(apiKey);
3289
+ await client.patch(`/model-configs/${id}/default`, {});
3290
+ spinner.succeed("Default model updated");
3291
+ } catch (error) {
3292
+ const message = error instanceof Error ? error.message : "Unknown error";
3293
+ spinner.fail("Failed to set default model");
3294
+ console.error(import_chalk17.default.red(message));
3295
+ process.exit(1);
3296
+ }
3297
+ });
3298
+ modelsCommand.command("usage").description("Show model usage statistics").option("--json", "Output as JSON").action(async (options) => {
3299
+ const apiKey = await ensureAuth();
3300
+ if (!apiKey) return;
3301
+ const spinner = (0, import_ora12.default)("Fetching model usage...").start();
3302
+ try {
3303
+ const client = new ApiClient(apiKey);
3304
+ const data = await client.get("/model-configs/usage");
3305
+ spinner.stop();
3306
+ if (options.json) {
3307
+ printJson(data);
3308
+ } else {
3309
+ printJson(data);
3310
+ }
3311
+ } catch (error) {
3312
+ const message = error instanceof Error ? error.message : "Unknown error";
3313
+ spinner.fail("Failed to fetch model usage");
3314
+ console.error(import_chalk17.default.red(message));
3315
+ process.exit(1);
3316
+ }
3317
+ });
3318
+
3319
+ // src/commands/schedules.ts
3320
+ init_cjs_shims();
3321
+ var import_commander14 = require("commander");
3322
+ var import_chalk18 = __toESM(require("chalk"));
3323
+ var import_ora13 = __toESM(require("ora"));
3324
+ var schedulesCommand = new import_commander14.Command("schedules").description("Manage schedules");
3325
+ schedulesCommand.command("list").description("List all schedules").option("--json", "Output as JSON").action(async (options) => {
3326
+ const apiKey = await ensureAuth();
3327
+ if (!apiKey) return;
3328
+ const spinner = (0, import_ora13.default)("Fetching schedules...").start();
3329
+ try {
3330
+ const client = new ApiClient(apiKey);
3331
+ const data = await client.get("/schedules");
3332
+ spinner.stop();
3333
+ if (options.json) {
3334
+ printJson(data);
3335
+ } else {
3336
+ const schedules = data.data ?? [];
3337
+ if (schedules.length === 0) {
3338
+ console.log(import_chalk18.default.gray("No schedules found"));
3339
+ return;
3340
+ }
3341
+ console.log(import_chalk18.default.cyan("Your Schedules:"));
3342
+ for (const s of schedules) {
3343
+ const name = s.name || s.id;
3344
+ const statusColor = s.status === "active" ? "green" : "yellow";
3345
+ const statusTag = s.status ? import_chalk18.default[statusColor](` [${s.status}]`) : "";
3346
+ console.log(` ${import_chalk18.default.green(s.id)} ${name}${statusTag}`);
3347
+ console.log(` Flow: ${import_chalk18.default.gray(s.flowId)}`);
3348
+ if (s.cronExpression) {
3349
+ console.log(` Cron: ${import_chalk18.default.gray(s.cronExpression)}`);
3350
+ }
3351
+ if (s.nextRunAt) {
3352
+ console.log(` Next run: ${import_chalk18.default.gray(s.nextRunAt)}`);
3353
+ }
3354
+ }
3355
+ const total = getTotalCount(data.pagination);
3356
+ if (total !== void 0) {
3357
+ console.log(import_chalk18.default.dim(`
3358
+ Total: ${total} schedules`));
3359
+ }
3360
+ }
3361
+ } catch (error) {
3362
+ const message = error instanceof Error ? error.message : "Unknown error";
3363
+ spinner.fail("Failed to fetch schedules");
3364
+ console.error(import_chalk18.default.red(message));
3365
+ process.exit(1);
3366
+ }
3367
+ });
3368
+ schedulesCommand.command("get <id>").description("Get schedule details").option("--json", "Output as JSON").action(async (id, options) => {
3369
+ const apiKey = await ensureAuth();
3370
+ if (!apiKey) return;
3371
+ const spinner = (0, import_ora13.default)("Fetching schedule...").start();
3372
+ try {
3373
+ const client = new ApiClient(apiKey);
3374
+ const data = await client.get(`/schedules/${id}`);
3375
+ spinner.stop();
3376
+ if (options.json) {
3377
+ printJson(data);
3378
+ } else {
3379
+ printDetail("Schedule", [
3380
+ { label: "ID", value: data.id },
3381
+ { label: "Name", value: data.name },
3382
+ { label: "Flow ID", value: data.flowId },
3383
+ { label: "Cron", value: data.cronExpression },
3384
+ { label: "Status", value: data.status },
3385
+ { label: "Next run", value: data.nextRunAt },
3386
+ { label: "Last run", value: data.lastRunAt }
3387
+ ]);
3388
+ }
3389
+ } catch (error) {
3390
+ const message = error instanceof Error ? error.message : "Unknown error";
3391
+ spinner.fail("Failed to fetch schedule");
3392
+ console.error(import_chalk18.default.red(message));
3393
+ process.exit(1);
3394
+ }
3395
+ });
3396
+ schedulesCommand.command("create").description("Create a new schedule").requiredOption("-f, --flow <id>", "Flow ID to schedule").requiredOption("-c, --cron <expression>", 'Cron expression (e.g. "0 9 * * *")').option("-n, --name <name>", "Schedule name").option("--json", "Output as JSON").action(async (options) => {
3397
+ const apiKey = await ensureAuth();
3398
+ if (!apiKey) return;
3399
+ const spinner = (0, import_ora13.default)("Creating schedule...").start();
3400
+ try {
3401
+ const client = new ApiClient(apiKey);
3402
+ const data = await client.post("/schedules", {
3403
+ flowId: options.flow,
3404
+ cronExpression: options.cron,
3405
+ name: options.name
3406
+ });
3407
+ spinner.succeed("Schedule created");
3408
+ if (options.json) {
3409
+ printJson(data);
3410
+ } else {
3411
+ console.log(` ID: ${import_chalk18.default.green(data.id)}`);
3412
+ if (data.name) console.log(` Name: ${data.name}`);
3413
+ console.log(` Cron: ${data.cronExpression}`);
3414
+ if (data.nextRunAt) console.log(` Next run: ${data.nextRunAt}`);
3415
+ }
3416
+ } catch (error) {
3417
+ const message = error instanceof Error ? error.message : "Unknown error";
3418
+ spinner.fail("Failed to create schedule");
3419
+ console.error(import_chalk18.default.red(message));
3420
+ process.exit(1);
3421
+ }
3422
+ });
3423
+ schedulesCommand.command("pause <id>").description("Pause a schedule").action(async (id) => {
3424
+ const apiKey = await ensureAuth();
3425
+ if (!apiKey) return;
3426
+ const spinner = (0, import_ora13.default)("Pausing schedule...").start();
3427
+ try {
3428
+ const client = new ApiClient(apiKey);
3429
+ await client.post(`/schedules/${id}/pause`);
3430
+ spinner.succeed("Schedule paused");
3431
+ } catch (error) {
3432
+ const message = error instanceof Error ? error.message : "Unknown error";
3433
+ spinner.fail("Failed to pause schedule");
3434
+ console.error(import_chalk18.default.red(message));
3435
+ process.exit(1);
3436
+ }
3437
+ });
3438
+ schedulesCommand.command("resume <id>").description("Resume a paused schedule").action(async (id) => {
3439
+ const apiKey = await ensureAuth();
3440
+ if (!apiKey) return;
3441
+ const spinner = (0, import_ora13.default)("Resuming schedule...").start();
3442
+ try {
3443
+ const client = new ApiClient(apiKey);
3444
+ await client.post(`/schedules/${id}/resume`);
3445
+ spinner.succeed("Schedule resumed");
3446
+ } catch (error) {
3447
+ const message = error instanceof Error ? error.message : "Unknown error";
3448
+ spinner.fail("Failed to resume schedule");
3449
+ console.error(import_chalk18.default.red(message));
3450
+ process.exit(1);
3451
+ }
3452
+ });
3453
+ schedulesCommand.command("run-now <id>").description("Trigger a schedule to run immediately").action(async (id) => {
3454
+ const apiKey = await ensureAuth();
3455
+ if (!apiKey) return;
3456
+ const spinner = (0, import_ora13.default)("Triggering schedule...").start();
3457
+ try {
3458
+ const client = new ApiClient(apiKey);
3459
+ await client.post(`/schedules/${id}/run-now`);
3460
+ spinner.succeed("Schedule triggered");
3461
+ } catch (error) {
3462
+ const message = error instanceof Error ? error.message : "Unknown error";
3463
+ spinner.fail("Failed to trigger schedule");
3464
+ console.error(import_chalk18.default.red(message));
3465
+ process.exit(1);
3466
+ }
3467
+ });
3468
+ schedulesCommand.command("delete <id>").description("Delete a schedule").action(async (id) => {
3469
+ const apiKey = await ensureAuth();
3470
+ if (!apiKey) return;
3471
+ const spinner = (0, import_ora13.default)("Deleting schedule...").start();
3472
+ try {
3473
+ const client = new ApiClient(apiKey);
3474
+ await client.delete(`/schedules/${id}`);
3475
+ spinner.succeed("Schedule deleted");
3476
+ } catch (error) {
3477
+ const message = error instanceof Error ? error.message : "Unknown error";
3478
+ spinner.fail("Failed to delete schedule");
3479
+ console.error(import_chalk18.default.red(message));
3480
+ process.exit(1);
3481
+ }
3482
+ });
3483
+
3484
+ // src/commands/eval.ts
3485
+ init_cjs_shims();
3486
+ var import_commander15 = require("commander");
3487
+ var import_chalk19 = __toESM(require("chalk"));
3488
+ var import_ora14 = __toESM(require("ora"));
3489
+ var import_fs6 = require("fs");
3490
+ var evalCommand = new import_commander15.Command("eval").description("Manage evaluations");
3491
+ evalCommand.command("submit").description("Submit an eval batch").requiredOption("-f, --flow <id>", "Flow ID to evaluate").requiredOption("-r, --records <file>", "JSON file with record IDs").option("-n, --name <name>", "Eval batch name").option("--json", "Output as JSON").action(async (options) => {
3492
+ const apiKey = await ensureAuth();
3493
+ if (!apiKey) return;
3494
+ let recordIds;
3495
+ try {
3496
+ const content = (0, import_fs6.readFileSync)(options.records, "utf-8");
3497
+ const parsed = JSON.parse(content);
3498
+ recordIds = Array.isArray(parsed) ? parsed : parsed.recordIds || parsed.records || [];
3499
+ } catch (error) {
3500
+ const message = error instanceof Error ? error.message : "Unknown error";
3501
+ console.error(import_chalk19.default.red(`Failed to read records file: ${message}`));
3502
+ process.exit(1);
3503
+ return;
3504
+ }
3505
+ const spinner = (0, import_ora14.default)(`Submitting eval with ${recordIds.length} records...`).start();
3506
+ try {
3507
+ const client = new ApiClient(apiKey);
3508
+ const data = await client.post("/eval/submit", {
3509
+ flowId: options.flow,
3510
+ recordIds,
3511
+ name: options.name
3512
+ });
3513
+ spinner.succeed("Eval submitted");
3514
+ if (options.json) {
3515
+ printJson(data);
3516
+ } else {
3517
+ console.log(` Batch ID: ${import_chalk19.default.green(data.id)}`);
3518
+ if (data.name) console.log(` Name: ${data.name}`);
3519
+ console.log(` Status: ${data.status}`);
3520
+ console.log(` Records: ${data.totalRecords}`);
3521
+ if (data.groupId) console.log(` Group: ${data.groupId}`);
3522
+ }
3523
+ } catch (error) {
3524
+ const message = error instanceof Error ? error.message : "Unknown error";
3525
+ spinner.fail("Failed to submit eval");
3526
+ console.error(import_chalk19.default.red(message));
3527
+ process.exit(1);
3528
+ }
3529
+ });
3530
+ evalCommand.command("list").description("List eval batches").option("--flow <id>", "Filter by flow ID").option("--limit <n>", "Limit results", "20").option("--json", "Output as JSON").action(async (options) => {
3531
+ const apiKey = await ensureAuth();
3532
+ if (!apiKey) return;
3533
+ const spinner = (0, import_ora14.default)("Fetching eval batches...").start();
3534
+ try {
3535
+ const client = new ApiClient(apiKey);
3536
+ const params = { limit: options.limit };
3537
+ if (options.flow) params.flowId = options.flow;
3538
+ const data = await client.get("/eval/batches", params);
3539
+ spinner.stop();
3540
+ if (options.json) {
3541
+ printJson(data);
3542
+ } else {
3543
+ const batches = data.data ?? [];
3544
+ if (batches.length === 0) {
3545
+ console.log(import_chalk19.default.gray("No eval batches found"));
3546
+ return;
3547
+ }
3548
+ console.log(import_chalk19.default.cyan("Eval Batches:"));
3549
+ for (const batch of batches) {
3550
+ const name = batch.name || batch.id;
3551
+ const progress = batch.totalRecords ? `${batch.completedRecords ?? 0}/${batch.totalRecords}` : "";
3552
+ const statusColor = batch.status === "completed" ? "green" : "yellow";
3553
+ console.log(
3554
+ ` ${import_chalk19.default.green(batch.id)} ${name} ${import_chalk19.default[statusColor](`[${batch.status}]`)} ${import_chalk19.default.gray(progress)}`
3555
+ );
3556
+ }
3557
+ const total = getTotalCount(data.pagination);
3558
+ if (total !== void 0) {
3559
+ console.log(import_chalk19.default.dim(`
3560
+ Total: ${total} batches`));
3561
+ }
3562
+ }
3563
+ } catch (error) {
3564
+ const message = error instanceof Error ? error.message : "Unknown error";
3565
+ spinner.fail("Failed to fetch eval batches");
3566
+ console.error(import_chalk19.default.red(message));
3567
+ process.exit(1);
3568
+ }
3569
+ });
3570
+ evalCommand.command("results <id>").description("Get eval batch results").option("--json", "Output as JSON").action(async (id, options) => {
3571
+ const apiKey = await ensureAuth();
3572
+ if (!apiKey) return;
3573
+ const spinner = (0, import_ora14.default)("Fetching eval results...").start();
3574
+ try {
3575
+ const client = new ApiClient(apiKey);
3576
+ const data = await client.get(`/eval/${id}/results`);
3577
+ spinner.stop();
3578
+ if (options.json) {
3579
+ printJson(data);
3580
+ } else {
3581
+ if (data.batch) {
3582
+ console.log(import_chalk19.default.cyan(`Eval: ${data.batch.name || data.batch.id}`));
3583
+ console.log(` Status: ${data.batch.status}`);
3584
+ console.log(` Progress: ${data.batch.completedRecords ?? 0}/${data.batch.totalRecords ?? 0}`);
3585
+ console.log();
3586
+ }
3587
+ const results = data.data ?? [];
3588
+ if (results.length === 0) {
3589
+ console.log(import_chalk19.default.gray("No results yet"));
3590
+ return;
3591
+ }
3592
+ console.log(import_chalk19.default.cyan("Results:"));
3593
+ for (const result of results) {
3594
+ const scoreStr = result.score !== void 0 ? import_chalk19.default.blue(` score=${result.score}`) : "";
3595
+ const statusColor = result.status === "completed" ? "green" : "red";
3596
+ console.log(
3597
+ ` ${import_chalk19.default.gray(result.recordId)} ${import_chalk19.default[statusColor](`[${result.status}]`)}${scoreStr}`
3598
+ );
3599
+ }
3600
+ }
3601
+ } catch (error) {
3602
+ const message = error instanceof Error ? error.message : "Unknown error";
3603
+ spinner.fail("Failed to fetch eval results");
3604
+ console.error(import_chalk19.default.red(message));
3605
+ process.exit(1);
3606
+ }
3607
+ });
3608
+ evalCommand.command("compare <groupId>").description("Compare evals in a group").option("--json", "Output as JSON").action(async (groupId, options) => {
3609
+ const apiKey = await ensureAuth();
3610
+ if (!apiKey) return;
3611
+ const spinner = (0, import_ora14.default)("Comparing evals...").start();
3612
+ try {
3613
+ const client = new ApiClient(apiKey);
3614
+ const data = await client.post("/eval/compare", { groupId });
3615
+ spinner.stop();
3616
+ if (options.json) {
3617
+ printJson(data);
3618
+ } else {
3619
+ printJson(data);
3620
+ }
3621
+ } catch (error) {
3622
+ const message = error instanceof Error ? error.message : "Unknown error";
3623
+ spinner.fail("Failed to compare evals");
3624
+ console.error(import_chalk19.default.red(message));
3625
+ process.exit(1);
3626
+ }
3627
+ });
3628
+
3629
+ // src/commands/api-keys.ts
3630
+ init_cjs_shims();
3631
+ var import_commander16 = require("commander");
3632
+ var import_chalk20 = __toESM(require("chalk"));
3633
+ var import_ora15 = __toESM(require("ora"));
3634
+ var apiKeysCommand = new import_commander16.Command("api-keys").description("Manage API keys");
3635
+ apiKeysCommand.command("list").description("List your API keys").option("--json", "Output as JSON").action(async (options) => {
3636
+ const apiKey = await ensureAuth();
3637
+ if (!apiKey) return;
3638
+ const spinner = (0, import_ora15.default)("Fetching API keys...").start();
3639
+ try {
3640
+ const client = new ApiClient(apiKey);
3641
+ const data = await client.get("/api-keys");
3642
+ spinner.stop();
3643
+ if (options.json) {
3644
+ printJson(data);
3645
+ } else {
3646
+ const keys = data.data ?? [];
3647
+ if (keys.length === 0) {
3648
+ console.log(import_chalk20.default.gray("No API keys found"));
3649
+ return;
3650
+ }
3651
+ console.log(import_chalk20.default.cyan("Your API Keys:"));
3652
+ for (const key of keys) {
3653
+ const prefix = key.prefix ? import_chalk20.default.gray(` (${key.prefix}...)`) : "";
3654
+ const lastUsed = key.lastUsedAt ? import_chalk20.default.gray(` last used: ${key.lastUsedAt}`) : "";
3655
+ console.log(` ${import_chalk20.default.green(key.id)} ${key.name}${prefix}${lastUsed}`);
3656
+ }
3657
+ const total = getTotalCount(data.pagination);
3658
+ if (total !== void 0) {
3659
+ console.log(import_chalk20.default.dim(`
3660
+ Total: ${total} keys`));
3661
+ }
3662
+ }
3663
+ } catch (error) {
3664
+ const message = error instanceof Error ? error.message : "Unknown error";
3665
+ spinner.fail("Failed to fetch API keys");
3666
+ console.error(import_chalk20.default.red(message));
3667
+ process.exit(1);
3668
+ }
3669
+ });
3670
+ apiKeysCommand.command("get <id>").description("Get API key details").option("--json", "Output as JSON").action(async (id, options) => {
3671
+ const apiKey = await ensureAuth();
3672
+ if (!apiKey) return;
3673
+ const spinner = (0, import_ora15.default)("Fetching API key...").start();
3674
+ try {
3675
+ const client = new ApiClient(apiKey);
3676
+ const data = await client.get(`/api-keys/${id}`);
3677
+ spinner.stop();
3678
+ if (options.json) {
3679
+ printJson(data);
3680
+ } else {
3681
+ printDetail("API Key", [
3682
+ { label: "ID", value: data.id },
3683
+ { label: "Name", value: data.name },
3684
+ { label: "Prefix", value: data.prefix },
3685
+ { label: "Scopes", value: data.scopes?.join(", ") },
3686
+ { label: "Last used", value: data.lastUsedAt },
3687
+ { label: "Created", value: data.createdAt }
3688
+ ]);
3689
+ }
3690
+ } catch (error) {
3691
+ const message = error instanceof Error ? error.message : "Unknown error";
3692
+ spinner.fail("Failed to fetch API key");
3693
+ console.error(import_chalk20.default.red(message));
3694
+ process.exit(1);
3695
+ }
3696
+ });
3697
+ apiKeysCommand.command("create").description("Create a new API key").requiredOption("-n, --name <name>", "Key name").option("--json", "Output as JSON").action(async (options) => {
3698
+ const apiKey = await ensureAuth();
3699
+ if (!apiKey) return;
3700
+ const spinner = (0, import_ora15.default)("Creating API key...").start();
3701
+ try {
3702
+ const client = new ApiClient(apiKey);
3703
+ const data = await client.post("/api-keys", {
3704
+ name: options.name
3705
+ });
3706
+ spinner.succeed("API key created");
3707
+ if (options.json) {
3708
+ printJson(data);
3709
+ } else {
3710
+ console.log(` ID: ${import_chalk20.default.green(data.id)}`);
3711
+ console.log(` Name: ${data.name}`);
3712
+ if (data.key) {
3713
+ console.log(` Key: ${import_chalk20.default.yellow(data.key)}`);
3714
+ console.log(import_chalk20.default.gray(" Save this key - it will not be shown again"));
3715
+ }
3716
+ }
3717
+ } catch (error) {
3718
+ const message = error instanceof Error ? error.message : "Unknown error";
3719
+ spinner.fail("Failed to create API key");
3720
+ console.error(import_chalk20.default.red(message));
3721
+ process.exit(1);
3722
+ }
3723
+ });
3724
+ apiKeysCommand.command("delete <id>").description("Delete an API key").action(async (id) => {
3725
+ const apiKey = await ensureAuth();
3726
+ if (!apiKey) return;
3727
+ const spinner = (0, import_ora15.default)("Deleting API key...").start();
3728
+ try {
3729
+ const client = new ApiClient(apiKey);
3730
+ await client.delete(`/api-keys/${id}`);
3731
+ spinner.succeed("API key deleted");
3732
+ } catch (error) {
3733
+ const message = error instanceof Error ? error.message : "Unknown error";
3734
+ spinner.fail("Failed to delete API key");
3735
+ console.error(import_chalk20.default.red(message));
3736
+ process.exit(1);
3737
+ }
3738
+ });
3739
+ apiKeysCommand.command("regenerate <id>").description("Regenerate an API key").option("--json", "Output as JSON").action(async (id, options) => {
3740
+ const apiKey = await ensureAuth();
3741
+ if (!apiKey) return;
3742
+ const spinner = (0, import_ora15.default)("Regenerating API key...").start();
3743
+ try {
3744
+ const client = new ApiClient(apiKey);
3745
+ const data = await client.post(`/api-keys/${id}/regenerate`);
3746
+ spinner.succeed("API key regenerated");
3747
+ if (options.json) {
3748
+ printJson(data);
3749
+ } else {
3750
+ if (data.key) {
3751
+ console.log(` New Key: ${import_chalk20.default.yellow(data.key)}`);
3752
+ console.log(import_chalk20.default.gray(" Save this key - it will not be shown again"));
3753
+ }
3754
+ }
3755
+ } catch (error) {
3756
+ const message = error instanceof Error ? error.message : "Unknown error";
3757
+ spinner.fail("Failed to regenerate API key");
3758
+ console.error(import_chalk20.default.red(message));
3759
+ process.exit(1);
3760
+ }
3761
+ });
3762
+ apiKeysCommand.command("analytics").description("Show API key usage analytics").option("--key <id>", "Specific key ID (defaults to all keys)").option("--json", "Output as JSON").action(async (options) => {
3763
+ const apiKey = await ensureAuth();
3764
+ if (!apiKey) return;
3765
+ const spinner = (0, import_ora15.default)("Fetching analytics...").start();
3766
+ try {
3767
+ const client = new ApiClient(apiKey);
3768
+ const path5 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
3769
+ const data = await client.get(path5);
3770
+ spinner.stop();
3771
+ if (options.json) {
3772
+ printJson(data);
3773
+ } else {
3774
+ printJson(data);
3775
+ }
3776
+ } catch (error) {
3777
+ const message = error instanceof Error ? error.message : "Unknown error";
3778
+ spinner.fail("Failed to fetch analytics");
3779
+ console.error(import_chalk20.default.red(message));
3780
+ process.exit(1);
3781
+ }
3782
+ });
3783
+
3784
+ // src/commands/analytics.ts
3785
+ init_cjs_shims();
3786
+ var import_commander17 = require("commander");
3787
+ var import_chalk21 = __toESM(require("chalk"));
3788
+ var import_ora16 = __toESM(require("ora"));
3789
+ var analyticsCommand = new import_commander17.Command("analytics").description("View analytics and execution results");
3790
+ analyticsCommand.command("stats").description("Show account statistics").option("--json", "Output as JSON").action(async (options) => {
3791
+ const apiKey = await ensureAuth();
3792
+ if (!apiKey) return;
3793
+ const spinner = (0, import_ora16.default)("Fetching stats...").start();
3794
+ try {
3795
+ const client = new ApiClient(apiKey);
3796
+ const data = await client.get("/analytics/stats");
3797
+ spinner.stop();
3798
+ if (options.json) {
3799
+ printJson(data);
3800
+ } else {
3801
+ printDetail("Account Statistics", [
3802
+ { label: "Flows", value: data.flows },
3803
+ { label: "Prompts", value: data.prompts },
3804
+ { label: "Records", value: data.records },
3805
+ { label: "Executions", value: data.executions }
3806
+ ]);
3807
+ }
3808
+ } catch (error) {
3809
+ const message = error instanceof Error ? error.message : "Unknown error";
3810
+ spinner.fail("Failed to fetch stats");
3811
+ console.error(import_chalk21.default.red(message));
3812
+ process.exit(1);
3813
+ }
3814
+ });
3815
+ analyticsCommand.command("results").description("List execution results").option("--flow <id>", "Filter by flow ID").option("--record <id>", "Filter by record ID").option("--status <status>", "Filter by status").option("--limit <n>", "Limit results", "20").option("--json", "Output as JSON").action(
3816
+ async (options) => {
3817
+ const apiKey = await ensureAuth();
3818
+ if (!apiKey) return;
3819
+ const spinner = (0, import_ora16.default)("Fetching results...").start();
3820
+ try {
3821
+ const client = new ApiClient(apiKey);
3822
+ const params = { limit: options.limit };
3823
+ if (options.flow) params.flowId = options.flow;
3824
+ if (options.record) params.recordId = options.record;
3825
+ if (options.status) params.status = options.status;
3826
+ const data = await client.get(
3827
+ "/analytics/record-results",
3828
+ params
3829
+ );
3830
+ spinner.stop();
3831
+ if (options.json) {
3832
+ printJson(data);
3833
+ } else {
3834
+ const results = data.data ?? [];
3835
+ if (results.length === 0) {
3836
+ console.log(import_chalk21.default.gray("No results found"));
3837
+ return;
3838
+ }
3839
+ console.log(import_chalk21.default.cyan("Execution Results:"));
3840
+ for (const result of results) {
3841
+ const statusColor = result.status === "completed" ? "green" : "red";
3842
+ const date = result.createdAt ? import_chalk21.default.gray(` ${result.createdAt}`) : "";
3843
+ console.log(
3844
+ ` ${import_chalk21.default.green(result.id)} ${import_chalk21.default[statusColor](`[${result.status}]`)} flow=${import_chalk21.default.gray(result.flowId)} record=${import_chalk21.default.gray(result.recordId)}${date}`
3845
+ );
3846
+ }
3847
+ const total = getTotalCount(data.pagination);
3848
+ if (total !== void 0) {
3849
+ console.log(import_chalk21.default.dim(`
3850
+ Total: ${total} results`));
3851
+ }
3852
+ }
3853
+ } catch (error) {
3854
+ const message = error instanceof Error ? error.message : "Unknown error";
3855
+ spinner.fail("Failed to fetch results");
3856
+ console.error(import_chalk21.default.red(message));
3857
+ process.exit(1);
3858
+ }
3859
+ }
3860
+ );
3861
+
3862
+ // src/commands/billing.ts
3863
+ init_cjs_shims();
3864
+ var import_commander18 = require("commander");
3865
+ var import_chalk22 = __toESM(require("chalk"));
3866
+ var import_ora17 = __toESM(require("ora"));
3867
+ var import_open3 = __toESM(require("open"));
3868
+ var billingCommand = new import_commander18.Command("billing").description("View billing and subscription info");
3869
+ billingCommand.command("status").description("Show current plan and usage").option("--json", "Output as JSON").action(async (options) => {
3870
+ const apiKey = await ensureAuth();
3871
+ if (!apiKey) return;
3872
+ const spinner = (0, import_ora17.default)("Fetching billing status...").start();
3873
+ try {
3874
+ const client = new ApiClient(apiKey);
3875
+ const data = await client.get("/billing/status");
3876
+ spinner.stop();
3877
+ if (options.json) {
3878
+ printJson(data);
3879
+ } else {
3880
+ printDetail("Billing Status", [
3881
+ { label: "Plan", value: data.planName || data.plan },
3882
+ { label: "Status", value: data.status },
3883
+ { label: "Period start", value: data.currentPeriodStart },
3884
+ { label: "Period end", value: data.currentPeriodEnd }
3885
+ ]);
3886
+ if (data.usage) {
3887
+ console.log();
3888
+ const limit = data.usage.executionsLimit;
3889
+ const used = data.usage.executionsUsed ?? 0;
3890
+ const limitStr = limit ? `/${limit}` : "";
3891
+ printDetail("Usage", [
3892
+ { label: "Executions", value: `${used}${limitStr}` }
3893
+ ]);
3894
+ }
3895
+ if (data.limits) {
3896
+ console.log();
3897
+ printDetail("Limits", [
3898
+ { label: "Daily", value: data.limits.dailyLimit },
3899
+ { label: "Monthly", value: data.limits.monthlyLimit },
3900
+ { label: "Rate limit", value: data.limits.rateLimit }
3901
+ ]);
3902
+ }
3903
+ }
3904
+ } catch (error) {
3905
+ const message = error instanceof Error ? error.message : "Unknown error";
3906
+ spinner.fail("Failed to fetch billing status");
3907
+ console.error(import_chalk22.default.red(message));
3908
+ process.exit(1);
3909
+ }
3910
+ });
3911
+ billingCommand.command("portal").description("Open the billing portal in your browser").action(async () => {
3912
+ const apiKey = await ensureAuth();
3913
+ if (!apiKey) return;
3914
+ const spinner = (0, import_ora17.default)("Generating portal link...").start();
3915
+ try {
3916
+ const client = new ApiClient(apiKey);
3917
+ const data = await client.post("/billing/portal");
3918
+ spinner.stop();
3919
+ if (data.url) {
3920
+ console.log(import_chalk22.default.cyan("Opening billing portal..."));
3921
+ await (0, import_open3.default)(data.url);
3922
+ } else {
3923
+ console.log(import_chalk22.default.yellow("No portal URL returned. You may need to set up billing first."));
3924
+ }
3925
+ } catch (error) {
3926
+ const message = error instanceof Error ? error.message : "Unknown error";
3927
+ spinner.fail("Failed to open billing portal");
3928
+ console.error(import_chalk22.default.red(message));
3929
+ process.exit(1);
3930
+ }
3931
+ });
3932
+ billingCommand.command("refresh").description("Refresh plan data from billing provider").action(async () => {
3933
+ const apiKey = await ensureAuth();
3934
+ if (!apiKey) return;
3935
+ const spinner = (0, import_ora17.default)("Refreshing plan data...").start();
3936
+ try {
3937
+ const client = new ApiClient(apiKey);
3938
+ await client.post("/billing/refresh");
3939
+ spinner.succeed("Plan data refreshed");
3940
+ } catch (error) {
3941
+ const message = error instanceof Error ? error.message : "Unknown error";
3942
+ spinner.fail("Failed to refresh plan data");
3943
+ console.error(import_chalk22.default.red(message));
3944
+ process.exit(1);
3945
+ }
3946
+ });
3947
+
3948
+ // src/commands/flow-versions.ts
3949
+ init_cjs_shims();
3950
+ var import_commander19 = require("commander");
3951
+ var import_chalk23 = __toESM(require("chalk"));
3952
+ var import_ora18 = __toESM(require("ora"));
3953
+ var flowVersionsCommand = new import_commander19.Command("flow-versions").description(
3954
+ "Manage flow versions"
3955
+ );
3956
+ flowVersionsCommand.command("list <flowId>").description("List all versions for a flow").option("--json", "Output as JSON").action(async (flowId, options) => {
3957
+ const apiKey = await ensureAuth();
3958
+ if (!apiKey) return;
3959
+ const spinner = (0, import_ora18.default)("Fetching versions...").start();
3960
+ try {
3961
+ const client = new ApiClient(apiKey);
3962
+ const data = await client.get(`/flow-versions/${flowId}`);
3963
+ spinner.stop();
3964
+ if (options.json) {
3965
+ printJson(data);
3966
+ } else {
3967
+ const versions = data.data ?? [];
3968
+ if (versions.length === 0) {
3969
+ console.log(import_chalk23.default.gray("No versions found"));
3970
+ return;
3971
+ }
3972
+ console.log(import_chalk23.default.cyan(`Versions for flow ${flowId}:`));
3973
+ for (const v of versions) {
3974
+ const publishedTag = v.published ? import_chalk23.default.green(" [published]") : "";
3975
+ const versionNum = v.version !== void 0 ? `v${v.version}` : v.id;
3976
+ const date = v.createdAt ? import_chalk23.default.gray(` ${v.createdAt}`) : "";
3977
+ console.log(` ${import_chalk23.default.green(v.id)} ${versionNum}${publishedTag}${date}`);
3978
+ }
3979
+ }
3980
+ } catch (error) {
3981
+ const message = error instanceof Error ? error.message : "Unknown error";
3982
+ spinner.fail("Failed to fetch versions");
3983
+ console.error(import_chalk23.default.red(message));
3984
+ process.exit(1);
3985
+ }
3986
+ });
3987
+ flowVersionsCommand.command("get <flowId> <versionId>").description("Get a specific version").option("--json", "Output as JSON").action(async (flowId, versionId, options) => {
3988
+ const apiKey = await ensureAuth();
3989
+ if (!apiKey) return;
3990
+ const spinner = (0, import_ora18.default)("Fetching version...").start();
3991
+ try {
3992
+ const client = new ApiClient(apiKey);
3993
+ const data = await client.get(`/flow-versions/${flowId}/${versionId}`);
3994
+ spinner.stop();
3995
+ if (options.json) {
3996
+ printJson(data);
3997
+ } else {
3998
+ printDetail("Flow Version", [
3999
+ { label: "ID", value: data.id },
4000
+ { label: "Flow ID", value: data.flowId },
4001
+ { label: "Version", value: data.version },
4002
+ { label: "Published", value: data.published },
4003
+ { label: "Created", value: data.createdAt },
4004
+ { label: "Steps", value: data.steps?.length }
4005
+ ]);
4006
+ }
4007
+ } catch (error) {
4008
+ const message = error instanceof Error ? error.message : "Unknown error";
4009
+ spinner.fail("Failed to fetch version");
4010
+ console.error(import_chalk23.default.red(message));
4011
+ process.exit(1);
4012
+ }
4013
+ });
4014
+ flowVersionsCommand.command("published <flowId>").description("Get the published version for a flow").option("--json", "Output as JSON").action(async (flowId, options) => {
4015
+ const apiKey = await ensureAuth();
4016
+ if (!apiKey) return;
4017
+ const spinner = (0, import_ora18.default)("Fetching published version...").start();
4018
+ try {
4019
+ const client = new ApiClient(apiKey);
4020
+ const data = await client.get(`/flow-versions/${flowId}/published`);
4021
+ spinner.stop();
4022
+ if (options.json) {
4023
+ printJson(data);
4024
+ } else {
4025
+ printDetail("Published Version", [
4026
+ { label: "ID", value: data.id },
4027
+ { label: "Version", value: data.version },
4028
+ { label: "Created", value: data.createdAt },
4029
+ { label: "Steps", value: data.steps?.length }
4030
+ ]);
4031
+ }
4032
+ } catch (error) {
4033
+ const message = error instanceof Error ? error.message : "Unknown error";
4034
+ spinner.fail("Failed to fetch published version");
4035
+ console.error(import_chalk23.default.red(message));
4036
+ process.exit(1);
4037
+ }
4038
+ });
4039
+ flowVersionsCommand.command("publish <flowId>").description("Publish a version").requiredOption("-v, --version <versionId>", "Version ID to publish").action(async (flowId, options) => {
4040
+ const apiKey = await ensureAuth();
4041
+ if (!apiKey) return;
4042
+ const spinner = (0, import_ora18.default)("Publishing version...").start();
4043
+ try {
4044
+ const client = new ApiClient(apiKey);
4045
+ await client.post(`/flow-versions/${flowId}/publish`, {
4046
+ versionId: options.version
4047
+ });
4048
+ spinner.succeed("Version published");
4049
+ } catch (error) {
4050
+ const message = error instanceof Error ? error.message : "Unknown error";
4051
+ spinner.fail("Failed to publish version");
4052
+ console.error(import_chalk23.default.red(message));
4053
+ process.exit(1);
4054
+ }
4055
+ });
4056
+
4057
+ // src/index.ts
4058
+ init_credential_store();
4059
+ (0, import_dotenv.config)();
4060
+ var program = new import_commander20.Command();
4061
+ program.name("runtype").description("CLI for Runtype AI Platform").version("0.1.0").option("-v, --verbose", "Enable verbose output").option("--api-url <url>", "Override API URL").option("--json", "Output in JSON format");
4062
+ program.addCommand(initCommand);
4063
+ program.addCommand(authCommand);
4064
+ program.addCommand(flowsCommand);
4065
+ program.addCommand(recordsCommand);
4066
+ program.addCommand(promptsCommand);
4067
+ program.addCommand(batchCommand);
4068
+ program.addCommand(talkCommand);
4069
+ program.addCommand(configCommand);
4070
+ program.addCommand(productsCommand);
4071
+ program.addCommand(dispatchCommand);
4072
+ program.addCommand(agentsCommand);
4073
+ program.addCommand(modelsCommand);
4074
+ program.addCommand(schedulesCommand);
4075
+ program.addCommand(evalCommand);
4076
+ program.addCommand(apiKeysCommand);
4077
+ program.addCommand(analyticsCommand);
4078
+ program.addCommand(billingCommand);
4079
+ program.addCommand(flowVersionsCommand);
4080
+ program.exitOverride();
4081
+ try {
4082
+ if (!process.argv.slice(2).length) {
4083
+ handleNoCommand();
4084
+ } else {
4085
+ program.parse(process.argv);
4086
+ }
4087
+ } catch (error) {
4088
+ const commanderError = error;
4089
+ if (commanderError.code === "commander.missingArgument") {
4090
+ console.error(import_chalk24.default.red(`Error: ${commanderError.message}`));
4091
+ process.exit(1);
4092
+ } else if (commanderError.code === "commander.unknownOption") {
4093
+ console.error(import_chalk24.default.red(`Error: ${commanderError.message}`));
4094
+ process.exit(1);
4095
+ } else if (commanderError.code === "commander.help") {
4096
+ process.exit(0);
4097
+ } else {
4098
+ console.error(import_chalk24.default.red("An unexpected error occurred:"));
4099
+ console.error(error);
4100
+ process.exit(1);
4101
+ }
4102
+ }
4103
+ async function handleNoCommand() {
4104
+ const store = new CredentialStore();
4105
+ const hasCredentials = await store.hasCredentials();
4106
+ if (!hasCredentials) {
4107
+ console.log(import_chalk24.default.cyan("\nWelcome to Runtype CLI!\n"));
4108
+ console.log("It looks like this is your first time. Run the setup wizard:");
4109
+ console.log(` ${import_chalk24.default.green("runtype init")}
4110
+ `);
4111
+ console.log("Or see all available commands:");
4112
+ console.log(` ${import_chalk24.default.green("runtype --help")}
4113
+ `);
4114
+ } else {
4115
+ try {
4116
+ program.outputHelp();
4117
+ } catch (error) {
4118
+ const commanderError = error;
4119
+ if (commanderError.code === "commander.help") {
4120
+ process.exit(0);
4121
+ } else {
4122
+ throw error;
4123
+ }
1827
4124
  }
1828
4125
  }
1829
4126
  }