@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/README.md +38 -6
- package/dist/index.js +2887 -590
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
28
|
-
var
|
|
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((
|
|
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
|
-
|
|
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(
|
|
220
|
+
this.start(port + 1).then(resolveStart).catch(rejectStart);
|
|
77
221
|
} else {
|
|
78
|
-
|
|
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
|
|
256
|
-
const codePromise = callbackServer.start(
|
|
257
|
-
const redirectUri = `http://localhost:${
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
-
|
|
639
|
-
|
|
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
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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)("
|
|
850
|
+
const spinner = (0, import_ora2.default)("Validating API key...").start();
|
|
652
851
|
try {
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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("
|
|
691
|
-
console.error(
|
|
692
|
-
|
|
871
|
+
spinner.fail("Login failed");
|
|
872
|
+
console.error(import_chalk3.default.red(message));
|
|
873
|
+
return null;
|
|
693
874
|
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
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
|
-
|
|
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/
|
|
715
|
-
|
|
716
|
-
var
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
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
|
|
726
|
-
|
|
727
|
-
|
|
917
|
+
var ApiClient = class {
|
|
918
|
+
baseUrl;
|
|
919
|
+
apiKey;
|
|
920
|
+
constructor(apiKey, baseUrl) {
|
|
921
|
+
this.apiKey = apiKey;
|
|
922
|
+
this.baseUrl = baseUrl || getApiUrl();
|
|
728
923
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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
|
-
|
|
736
|
-
|
|
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
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1112
|
+
printJson(data);
|
|
773
1113
|
} else {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
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
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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(
|
|
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(
|
|
1285
|
+
console.error(import_chalk6.default.red(message));
|
|
799
1286
|
process.exit(1);
|
|
800
1287
|
}
|
|
801
1288
|
});
|
|
802
|
-
recordsCommand.command("
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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
|
-
|
|
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
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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(
|
|
1345
|
+
console.error(import_chalk6.default.red(message));
|
|
847
1346
|
process.exit(1);
|
|
848
1347
|
}
|
|
849
1348
|
});
|
|
850
|
-
recordsCommand.command("
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
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
|
-
|
|
880
|
-
|
|
1402
|
+
);
|
|
1403
|
+
function csvEscape(value) {
|
|
1404
|
+
if (value.includes(",") || value.includes('"') || value.includes("\n")) {
|
|
1405
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
881
1406
|
}
|
|
882
|
-
return
|
|
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
|
|
887
|
-
|
|
888
|
-
|
|
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
|
|
895
|
-
|
|
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
|
-
|
|
1426
|
+
printJson(data);
|
|
907
1427
|
} else {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
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
|
-
}
|
|
929
|
-
|
|
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(
|
|
1452
|
+
console.error(import_chalk7.default.red(message));
|
|
936
1453
|
process.exit(1);
|
|
937
1454
|
}
|
|
938
1455
|
});
|
|
939
|
-
promptsCommand.command("
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
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
|
|
954
|
-
var
|
|
955
|
-
var
|
|
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
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
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,
|
|
1566
|
+
const spinner = (0, import_ora6.default)(`Submitting batch with ${recordIds.length} records...`).start();
|
|
983
1567
|
try {
|
|
984
|
-
const
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
}
|
|
1568
|
+
const client = new ApiClient(apiKey);
|
|
1569
|
+
const data = await client.post("/batch/submit", {
|
|
1570
|
+
flowId: options.flow,
|
|
1571
|
+
recordIds
|
|
989
1572
|
});
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
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
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
console.log(`
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
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(
|
|
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
|
|
1016
|
-
|
|
1017
|
-
|
|
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
|
|
1024
|
-
|
|
1025
|
-
|
|
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(
|
|
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
|
|
1045
|
-
var
|
|
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
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
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
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
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
|
|
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
|
-
|
|
1230
|
-
var
|
|
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(
|
|
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,
|
|
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(
|
|
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
|
|
1303
|
-
|
|
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(
|
|
1898
|
+
console.log(import_chalk10.default.green(`Loaded session from: ${options.continue}`));
|
|
1318
1899
|
} catch (error) {
|
|
1319
|
-
|
|
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 =
|
|
1909
|
+
const rl = import_readline2.default.createInterface({
|
|
1328
1910
|
input: process.stdin,
|
|
1329
1911
|
output: process.stdout,
|
|
1330
|
-
prompt:
|
|
1912
|
+
prompt: import_chalk10.default.cyan("You> "),
|
|
1331
1913
|
terminal: true,
|
|
1332
1914
|
historySize: 100
|
|
1333
1915
|
});
|
|
1334
1916
|
console.clear();
|
|
1335
|
-
console.log(
|
|
1336
|
-
console.log(
|
|
1337
|
-
console.log(
|
|
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(
|
|
1929
|
+
console.log(import_chalk10.default.cyan("\nAvailable commands:"));
|
|
1348
1930
|
for (const [cmd, desc] of Object.entries(CHAT_COMMANDS)) {
|
|
1349
|
-
console.log(` ${
|
|
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(
|
|
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(
|
|
1943
|
+
console.log(import_chalk10.default.green(`Session saved to: ${filepath}`));
|
|
1362
1944
|
} catch (error) {
|
|
1363
|
-
|
|
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(
|
|
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(
|
|
1956
|
+
console.log(import_chalk10.default.green(`Session loaded from: ${args}`));
|
|
1374
1957
|
} catch (error) {
|
|
1375
|
-
|
|
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(
|
|
1965
|
+
console.log(import_chalk10.default.green(`Conversation exported to: ${filepath}`));
|
|
1382
1966
|
} catch (error) {
|
|
1383
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
1990
|
+
}
|
|
1991
|
+
case "/info": {
|
|
1406
1992
|
const info = session.getSessionInfo();
|
|
1407
|
-
console.log(
|
|
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(
|
|
1420
|
-
console.log(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
2117
|
+
console.log(import_chalk11.default.cyan("Current Configuration:"));
|
|
1529
2118
|
for (const [k, v] of Object.entries(allConfig)) {
|
|
1530
|
-
console.log(` ${
|
|
2119
|
+
console.log(` ${import_chalk11.default.green(k)}: ${v}`);
|
|
1531
2120
|
}
|
|
1532
2121
|
} else {
|
|
1533
|
-
console.log(
|
|
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(
|
|
1540
|
-
console.log(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
1583
|
-
var
|
|
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(`
|
|
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(
|
|
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").
|
|
1669
|
-
const
|
|
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(
|
|
2275
|
+
const result = await validateUrl(sourceUrl, options.apiUrl);
|
|
1672
2276
|
if (!result.valid) {
|
|
1673
2277
|
spinner.fail("Validation failed");
|
|
1674
|
-
if (
|
|
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(
|
|
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
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
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
|
-
|
|
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(
|
|
2310
|
+
const encodedUrl = encodeURIComponent(sourceUrl);
|
|
1719
2311
|
const targetUrl = `${dashboardUrl}/now?from=${encodedUrl}&cli=true`;
|
|
1720
|
-
if (
|
|
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(
|
|
1734
|
-
console.log(
|
|
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,
|
|
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
|
-
|
|
1746
|
-
|
|
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 (
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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/
|
|
1790
|
-
(
|
|
1791
|
-
var
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
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
|
-
}
|
|
1809
|
-
|
|
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
|
-
}
|
|
1812
|
-
|
|
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
|
-
|
|
1815
|
-
|
|
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
|
-
|
|
2747
|
+
async function handleNonStreaming(client, payload, options) {
|
|
2748
|
+
const spinner = (0, import_ora9.default)("Executing...").start();
|
|
1820
2749
|
try {
|
|
1821
|
-
|
|
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
|
-
|
|
1824
|
-
|
|
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
|
-
|
|
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
|
}
|