@runtypelabs/cli 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2259 -510
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -126,7 +126,7 @@ var init_credential_store = __esm({
|
|
|
126
126
|
|
|
127
127
|
// src/index.ts
|
|
128
128
|
import { Command as Command20 } from "commander";
|
|
129
|
-
import
|
|
129
|
+
import chalk22 from "chalk";
|
|
130
130
|
import { config as loadEnv } from "dotenv";
|
|
131
131
|
import { readFileSync as readFileSync6 } from "fs";
|
|
132
132
|
import { dirname as dirname2, join as join2 } from "path";
|
|
@@ -154,8 +154,8 @@ var CallbackServer = class {
|
|
|
154
154
|
expectedState;
|
|
155
155
|
constructor() {
|
|
156
156
|
this.app = express();
|
|
157
|
-
this.codePromise = new Promise((
|
|
158
|
-
this.codeResolve =
|
|
157
|
+
this.codePromise = new Promise((resolve2, reject) => {
|
|
158
|
+
this.codeResolve = resolve2;
|
|
159
159
|
this.codeReject = reject;
|
|
160
160
|
});
|
|
161
161
|
this.app.get("/callback", (req, res) => {
|
|
@@ -214,8 +214,14 @@ var CallbackServer = class {
|
|
|
214
214
|
}
|
|
215
215
|
stop() {
|
|
216
216
|
if (this.server) {
|
|
217
|
-
this.server
|
|
217
|
+
const s = this.server;
|
|
218
218
|
this.server = null;
|
|
219
|
+
s.unref();
|
|
220
|
+
if (typeof s.closeAllConnections === "function") {
|
|
221
|
+
;
|
|
222
|
+
s.closeAllConnections();
|
|
223
|
+
}
|
|
224
|
+
s.close();
|
|
219
225
|
}
|
|
220
226
|
}
|
|
221
227
|
successHTML() {
|
|
@@ -1324,7 +1330,7 @@ authCommand.command("whoami").description("Display current user information").op
|
|
|
1324
1330
|
|
|
1325
1331
|
// src/commands/flows.ts
|
|
1326
1332
|
import { Command as Command2 } from "commander";
|
|
1327
|
-
import
|
|
1333
|
+
import chalk5 from "chalk";
|
|
1328
1334
|
import React2 from "react";
|
|
1329
1335
|
import { render as render2 } from "ink";
|
|
1330
1336
|
import { useState as useState3, useEffect as useEffect4 } from "react";
|
|
@@ -1333,80 +1339,179 @@ import { processStream } from "@runtypelabs/sdk";
|
|
|
1333
1339
|
|
|
1334
1340
|
// src/lib/ensure-auth.ts
|
|
1335
1341
|
init_credential_store();
|
|
1336
|
-
import
|
|
1342
|
+
import readline2 from "readline";
|
|
1343
|
+
import chalk3 from "chalk";
|
|
1344
|
+
|
|
1345
|
+
// src/lib/select-prompt.ts
|
|
1337
1346
|
import chalk2 from "chalk";
|
|
1347
|
+
import readline from "readline";
|
|
1348
|
+
function canUseArrowKeySelect() {
|
|
1349
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true && typeof process.stdin.setRawMode === "function";
|
|
1350
|
+
}
|
|
1351
|
+
function clearRenderedLines(output, lineCount) {
|
|
1352
|
+
for (let index = 0; index < lineCount; index += 1) {
|
|
1353
|
+
readline.clearLine(output, 0);
|
|
1354
|
+
readline.cursorTo(output, 0);
|
|
1355
|
+
if (index < lineCount - 1) {
|
|
1356
|
+
readline.moveCursor(output, 0, -1);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
function formatChoice(choice, index, selectedIndex) {
|
|
1361
|
+
const prefix = index === selectedIndex ? chalk2.cyan("\u203A") : " ";
|
|
1362
|
+
const shortcut = index === selectedIndex ? chalk2.cyan(`${index + 1})`) : chalk2.gray(`${index + 1})`);
|
|
1363
|
+
const label = index === selectedIndex ? chalk2.bold(choice.label) : choice.label;
|
|
1364
|
+
const description = choice.description ? chalk2.gray(` - ${choice.description}`) : "";
|
|
1365
|
+
return ` ${prefix} ${shortcut} ${label}${description}`;
|
|
1366
|
+
}
|
|
1367
|
+
async function promptNumericSelect(choices, promptLabel) {
|
|
1368
|
+
choices.forEach((choice, index) => {
|
|
1369
|
+
const description = choice.description ? chalk2.gray(` - ${choice.description}`) : "";
|
|
1370
|
+
console.log(` ${chalk2.green(`${index + 1})`)} ${choice.label}${description}`);
|
|
1371
|
+
});
|
|
1372
|
+
const rl = readline.createInterface({
|
|
1373
|
+
input: process.stdin,
|
|
1374
|
+
output: process.stdout,
|
|
1375
|
+
terminal: true
|
|
1376
|
+
});
|
|
1377
|
+
return new Promise((resolve2) => {
|
|
1378
|
+
const ask = () => {
|
|
1379
|
+
rl.question(chalk2.cyan(`
|
|
1380
|
+
${promptLabel} (1-${choices.length}): `), (answer) => {
|
|
1381
|
+
const value = parseInt(answer.trim(), 10);
|
|
1382
|
+
if (value >= 1 && value <= choices.length) {
|
|
1383
|
+
rl.close();
|
|
1384
|
+
resolve2(choices[value - 1].value);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
console.log(chalk2.red(`Please enter a number between 1 and ${choices.length}.`));
|
|
1388
|
+
ask();
|
|
1389
|
+
});
|
|
1390
|
+
};
|
|
1391
|
+
ask();
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
async function promptSelect(message, choices, options) {
|
|
1395
|
+
if (message) {
|
|
1396
|
+
console.log(chalk2.cyan(`
|
|
1397
|
+
${message}`));
|
|
1398
|
+
}
|
|
1399
|
+
if (!canUseArrowKeySelect()) {
|
|
1400
|
+
return promptNumericSelect(choices, options?.promptLabel ?? "Select");
|
|
1401
|
+
}
|
|
1402
|
+
const input = process.stdin;
|
|
1403
|
+
const output = process.stdout;
|
|
1404
|
+
const promptLabel = options?.promptLabel ?? "Select";
|
|
1405
|
+
const shortcutRange = choices.length === 1 ? "1" : `1-${choices.length}`;
|
|
1406
|
+
const instructions = chalk2.gray(
|
|
1407
|
+
`Use ${chalk2.cyan("\u2191/\u2193")} to move, ${chalk2.cyan("Enter")} to select, or press ${shortcutRange}.`
|
|
1408
|
+
);
|
|
1409
|
+
const previousRawMode = input.isRaw === true;
|
|
1410
|
+
let selectedIndex = 0;
|
|
1411
|
+
let renderedLineCount = 0;
|
|
1412
|
+
return new Promise((resolve2) => {
|
|
1413
|
+
const renderMenu = () => {
|
|
1414
|
+
if (renderedLineCount > 0) {
|
|
1415
|
+
clearRenderedLines(output, renderedLineCount);
|
|
1416
|
+
}
|
|
1417
|
+
const lines = [
|
|
1418
|
+
...choices.map((choice, index) => formatChoice(choice, index, selectedIndex)),
|
|
1419
|
+
"",
|
|
1420
|
+
`${promptLabel}: ${instructions}`
|
|
1421
|
+
];
|
|
1422
|
+
output.write(`${lines.join("\n")}`);
|
|
1423
|
+
renderedLineCount = lines.length;
|
|
1424
|
+
};
|
|
1425
|
+
const cleanup = () => {
|
|
1426
|
+
input.off("keypress", onKeypress);
|
|
1427
|
+
if (typeof input.setRawMode === "function") {
|
|
1428
|
+
input.setRawMode(previousRawMode);
|
|
1429
|
+
}
|
|
1430
|
+
output.write("\n");
|
|
1431
|
+
};
|
|
1432
|
+
const finish = (value) => {
|
|
1433
|
+
cleanup();
|
|
1434
|
+
resolve2(value);
|
|
1435
|
+
};
|
|
1436
|
+
const onKeypress = (_, key) => {
|
|
1437
|
+
if (key.ctrl && key.name === "c") {
|
|
1438
|
+
cleanup();
|
|
1439
|
+
process.kill(process.pid, "SIGINT");
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
if (key.name === "up" || key.name === "k") {
|
|
1443
|
+
selectedIndex = (selectedIndex - 1 + choices.length) % choices.length;
|
|
1444
|
+
renderMenu();
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
if (key.name === "down" || key.name === "j") {
|
|
1448
|
+
selectedIndex = (selectedIndex + 1) % choices.length;
|
|
1449
|
+
renderMenu();
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
if (key.name === "return" || key.name === "enter") {
|
|
1453
|
+
finish(choices[selectedIndex].value);
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
if (/^[1-9]$/.test(key.sequence ?? "")) {
|
|
1457
|
+
const numericIndex = Number(key.sequence) - 1;
|
|
1458
|
+
if (numericIndex >= 0 && numericIndex < choices.length) {
|
|
1459
|
+
finish(choices[numericIndex].value);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
readline.emitKeypressEvents(input);
|
|
1464
|
+
input.on("keypress", onKeypress);
|
|
1465
|
+
input.resume();
|
|
1466
|
+
input.setRawMode?.(true);
|
|
1467
|
+
renderMenu();
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// src/lib/ensure-auth.ts
|
|
1338
1472
|
async function promptConfirm(message, options) {
|
|
1339
1473
|
const defaultYes = options?.default !== false;
|
|
1340
1474
|
const hint = defaultYes ? "Y/n" : "y/N";
|
|
1341
|
-
const rl =
|
|
1475
|
+
const rl = readline2.createInterface({
|
|
1342
1476
|
input: process.stdin,
|
|
1343
1477
|
output: process.stdout,
|
|
1344
1478
|
terminal: true
|
|
1345
1479
|
});
|
|
1346
|
-
return new Promise((
|
|
1347
|
-
rl.question(
|
|
1480
|
+
return new Promise((resolve2) => {
|
|
1481
|
+
rl.question(chalk3.cyan(`${message} (${hint}): `), (answer) => {
|
|
1348
1482
|
rl.close();
|
|
1349
1483
|
const trimmed = answer.trim().toLowerCase();
|
|
1350
1484
|
if (trimmed === "") {
|
|
1351
|
-
|
|
1485
|
+
resolve2(defaultYes);
|
|
1352
1486
|
} else {
|
|
1353
|
-
|
|
1487
|
+
resolve2(trimmed === "y" || trimmed === "yes");
|
|
1354
1488
|
}
|
|
1355
1489
|
});
|
|
1356
1490
|
});
|
|
1357
1491
|
}
|
|
1358
1492
|
async function promptText(message) {
|
|
1359
|
-
const rl =
|
|
1493
|
+
const rl = readline2.createInterface({
|
|
1360
1494
|
input: process.stdin,
|
|
1361
1495
|
output: process.stdout,
|
|
1362
1496
|
terminal: true
|
|
1363
1497
|
});
|
|
1364
|
-
return new Promise((
|
|
1365
|
-
rl.question(
|
|
1498
|
+
return new Promise((resolve2) => {
|
|
1499
|
+
rl.question(chalk3.cyan(`${message}: `), (answer) => {
|
|
1366
1500
|
rl.close();
|
|
1367
|
-
|
|
1501
|
+
resolve2(answer.trim());
|
|
1368
1502
|
});
|
|
1369
1503
|
});
|
|
1370
1504
|
}
|
|
1371
|
-
async function promptSelect(message, choices) {
|
|
1372
|
-
console.log(chalk2.cyan(`
|
|
1373
|
-
${message}`));
|
|
1374
|
-
choices.forEach((choice, index) => {
|
|
1375
|
-
const desc = choice.description ? chalk2.gray(` - ${choice.description}`) : "";
|
|
1376
|
-
console.log(` ${chalk2.green(`${index + 1})`)} ${choice.label}${desc}`);
|
|
1377
|
-
});
|
|
1378
|
-
const rl = readline.createInterface({
|
|
1379
|
-
input: process.stdin,
|
|
1380
|
-
output: process.stdout,
|
|
1381
|
-
terminal: true
|
|
1382
|
-
});
|
|
1383
|
-
return new Promise((resolve) => {
|
|
1384
|
-
const ask = () => {
|
|
1385
|
-
rl.question(chalk2.cyan(`
|
|
1386
|
-
Select (1-${choices.length}): `), (answer) => {
|
|
1387
|
-
const num = parseInt(answer.trim(), 10);
|
|
1388
|
-
if (num >= 1 && num <= choices.length) {
|
|
1389
|
-
rl.close();
|
|
1390
|
-
resolve(choices[num - 1].value);
|
|
1391
|
-
} else {
|
|
1392
|
-
console.log(chalk2.red(`Please enter a number between 1 and ${choices.length}`));
|
|
1393
|
-
ask();
|
|
1394
|
-
}
|
|
1395
|
-
});
|
|
1396
|
-
};
|
|
1397
|
-
ask();
|
|
1398
|
-
});
|
|
1399
|
-
}
|
|
1400
1505
|
async function ensureAuth(options) {
|
|
1401
1506
|
const store = new CredentialStore();
|
|
1402
1507
|
const apiKey = await store.getApiKey();
|
|
1403
1508
|
if (apiKey) {
|
|
1404
1509
|
return apiKey;
|
|
1405
1510
|
}
|
|
1406
|
-
console.log(
|
|
1511
|
+
console.log(chalk3.yellow("\nAuthentication required."));
|
|
1407
1512
|
const shouldLogin = await promptConfirm("Would you like to log in now?", { default: true });
|
|
1408
1513
|
if (!shouldLogin) {
|
|
1409
|
-
console.log(
|
|
1514
|
+
console.log(chalk3.gray(`Run "runtype auth login" when you're ready.`));
|
|
1410
1515
|
if (options?.exitOnFailure !== false) {
|
|
1411
1516
|
process.exit(1);
|
|
1412
1517
|
}
|
|
@@ -1424,15 +1529,15 @@ async function ensureAuth(options) {
|
|
|
1424
1529
|
async function handleApiKeyLogin(store, apiUrl) {
|
|
1425
1530
|
const key = await promptText("Enter your API key");
|
|
1426
1531
|
if (!key) {
|
|
1427
|
-
console.log(
|
|
1532
|
+
console.log(chalk3.red("No API key provided."));
|
|
1428
1533
|
return null;
|
|
1429
1534
|
}
|
|
1430
|
-
console.log(
|
|
1535
|
+
console.log(chalk3.gray("Validating API key..."));
|
|
1431
1536
|
try {
|
|
1432
1537
|
const apiKeyManager = new ApiKeyManager();
|
|
1433
1538
|
const isValid = await apiKeyManager.validateApiKey(key, apiUrl);
|
|
1434
1539
|
if (!isValid) {
|
|
1435
|
-
console.log(
|
|
1540
|
+
console.log(chalk3.red("Invalid API key"));
|
|
1436
1541
|
return null;
|
|
1437
1542
|
}
|
|
1438
1543
|
const userData = await apiKeyManager.getCurrentUser(key, apiUrl);
|
|
@@ -1444,43 +1549,43 @@ async function handleApiKeyLogin(store, apiUrl) {
|
|
|
1444
1549
|
orgId: userData.org_id ?? void 0,
|
|
1445
1550
|
apiUrl: apiUrl || getApiUrl()
|
|
1446
1551
|
});
|
|
1447
|
-
console.log(
|
|
1552
|
+
console.log(chalk3.green("Logged in successfully!"));
|
|
1448
1553
|
return key;
|
|
1449
1554
|
} catch (error) {
|
|
1450
1555
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1451
|
-
console.log(
|
|
1452
|
-
console.error(
|
|
1556
|
+
console.log(chalk3.red("Login failed"));
|
|
1557
|
+
console.error(chalk3.red(message));
|
|
1453
1558
|
return null;
|
|
1454
1559
|
}
|
|
1455
1560
|
}
|
|
1456
1561
|
async function handleBrowserLogin(store, apiUrl) {
|
|
1457
|
-
console.log(
|
|
1562
|
+
console.log(chalk3.gray("Initializing authentication..."));
|
|
1458
1563
|
try {
|
|
1459
1564
|
const oauth = new OAuthManager({
|
|
1460
1565
|
clerkPublishableKey: getClerkPublishableKey(),
|
|
1461
1566
|
dashboardUrl: getDashboardUrl()
|
|
1462
1567
|
});
|
|
1463
|
-
console.log(
|
|
1568
|
+
console.log(chalk3.gray("Waiting for browser authentication..."));
|
|
1464
1569
|
const sessionToken = await oauth.authenticate("sign-in");
|
|
1465
|
-
console.log(
|
|
1570
|
+
console.log(chalk3.gray("Getting API key..."));
|
|
1466
1571
|
const apiKeyManager = new ApiKeyManager();
|
|
1467
1572
|
const { key, userId, orgId } = await apiKeyManager.exchangeSessionForApiKey(
|
|
1468
1573
|
sessionToken,
|
|
1469
1574
|
apiUrl || getApiUrl()
|
|
1470
1575
|
);
|
|
1471
|
-
console.log(
|
|
1576
|
+
console.log(chalk3.gray("Storing credentials..."));
|
|
1472
1577
|
await store.saveCredentials({
|
|
1473
1578
|
apiKey: key,
|
|
1474
1579
|
userId,
|
|
1475
1580
|
orgId,
|
|
1476
1581
|
apiUrl: apiUrl || getApiUrl()
|
|
1477
1582
|
});
|
|
1478
|
-
console.log(
|
|
1583
|
+
console.log(chalk3.green("Logged in successfully!"));
|
|
1479
1584
|
return key;
|
|
1480
1585
|
} catch (error) {
|
|
1481
1586
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1482
|
-
console.log(
|
|
1483
|
-
console.error(
|
|
1587
|
+
console.log(chalk3.red("Login failed"));
|
|
1588
|
+
console.error(chalk3.red(message));
|
|
1484
1589
|
return null;
|
|
1485
1590
|
}
|
|
1486
1591
|
}
|
|
@@ -1604,14 +1709,14 @@ var ApiClient = class {
|
|
|
1604
1709
|
};
|
|
1605
1710
|
|
|
1606
1711
|
// src/lib/output.ts
|
|
1607
|
-
import
|
|
1712
|
+
import chalk4 from "chalk";
|
|
1608
1713
|
function printJson(data) {
|
|
1609
1714
|
console.log(JSON.stringify(data, null, 2));
|
|
1610
1715
|
}
|
|
1611
1716
|
function printList(items, options) {
|
|
1612
|
-
console.log(
|
|
1717
|
+
console.log(chalk4.cyan(`${options.title}:`));
|
|
1613
1718
|
if (items.length === 0) {
|
|
1614
|
-
console.log(
|
|
1719
|
+
console.log(chalk4.gray(` ${options.emptyMessage || "None found"}`));
|
|
1615
1720
|
return;
|
|
1616
1721
|
}
|
|
1617
1722
|
for (const item of items) {
|
|
@@ -1620,7 +1725,7 @@ function printList(items, options) {
|
|
|
1620
1725
|
const value = item[col.key];
|
|
1621
1726
|
if (value === void 0 || value === null) continue;
|
|
1622
1727
|
const str = String(value);
|
|
1623
|
-
const colorFn = col.color ?
|
|
1728
|
+
const colorFn = col.color ? chalk4[col.color] : (s) => s;
|
|
1624
1729
|
if (col.label) {
|
|
1625
1730
|
parts.push(`${col.label}: ${colorFn(str)}`);
|
|
1626
1731
|
} else {
|
|
@@ -1630,16 +1735,16 @@ function printList(items, options) {
|
|
|
1630
1735
|
console.log(` ${parts.join(" - ")}`);
|
|
1631
1736
|
}
|
|
1632
1737
|
if (options.total !== void 0) {
|
|
1633
|
-
console.log(
|
|
1738
|
+
console.log(chalk4.dim(`
|
|
1634
1739
|
Total: ${options.total}`));
|
|
1635
1740
|
}
|
|
1636
1741
|
}
|
|
1637
1742
|
function printDetail(title, fields) {
|
|
1638
|
-
console.log(
|
|
1743
|
+
console.log(chalk4.cyan(`${title}:`));
|
|
1639
1744
|
for (const field of fields) {
|
|
1640
1745
|
if (field.value === void 0 || field.value === null) continue;
|
|
1641
1746
|
const str = typeof field.value === "object" ? JSON.stringify(field.value) : String(field.value);
|
|
1642
|
-
console.log(` ${
|
|
1747
|
+
console.log(` ${chalk4.gray(field.label + ":")} ${str}`);
|
|
1643
1748
|
}
|
|
1644
1749
|
}
|
|
1645
1750
|
function getTotalCount(pagination) {
|
|
@@ -1671,7 +1776,7 @@ flowsCommand.command("list").description("List all flows").option("--json", "Out
|
|
|
1671
1776
|
});
|
|
1672
1777
|
} catch (error) {
|
|
1673
1778
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1674
|
-
console.error(
|
|
1779
|
+
console.error(chalk5.red(`Failed to fetch flows: ${message}`));
|
|
1675
1780
|
process.exit(1);
|
|
1676
1781
|
}
|
|
1677
1782
|
return;
|
|
@@ -1727,7 +1832,7 @@ flowsCommand.command("get <id>").description("Get flow details").option("--json"
|
|
|
1727
1832
|
]);
|
|
1728
1833
|
} catch (error) {
|
|
1729
1834
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1730
|
-
console.error(
|
|
1835
|
+
console.error(chalk5.red(`Failed to fetch flow: ${message}`));
|
|
1731
1836
|
process.exit(1);
|
|
1732
1837
|
}
|
|
1733
1838
|
return;
|
|
@@ -1774,7 +1879,7 @@ flowsCommand.command("run <id>").description("Execute a flow via dispatch").opti
|
|
|
1774
1879
|
payload.messages = [{ role: "user", content: options.message }];
|
|
1775
1880
|
}
|
|
1776
1881
|
if (options.stream) {
|
|
1777
|
-
console.log(
|
|
1882
|
+
console.log(chalk5.gray("Starting flow..."));
|
|
1778
1883
|
try {
|
|
1779
1884
|
const response = await client.stream("/dispatch", payload);
|
|
1780
1885
|
const callbacks = {
|
|
@@ -1788,7 +1893,7 @@ flowsCommand.command("run <id>").description("Execute a flow via dispatch").opti
|
|
|
1788
1893
|
}
|
|
1789
1894
|
},
|
|
1790
1895
|
onError: (err) => {
|
|
1791
|
-
console.error(
|
|
1896
|
+
console.error(chalk5.red(`
|
|
1792
1897
|
Error: ${err.message}`));
|
|
1793
1898
|
}
|
|
1794
1899
|
};
|
|
@@ -1796,19 +1901,19 @@ Error: ${err.message}`));
|
|
|
1796
1901
|
console.log();
|
|
1797
1902
|
} catch (error) {
|
|
1798
1903
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1799
|
-
console.error(
|
|
1904
|
+
console.error(chalk5.red(`Flow execution failed: ${message}`));
|
|
1800
1905
|
process.exit(1);
|
|
1801
1906
|
}
|
|
1802
1907
|
} else {
|
|
1803
|
-
console.log(
|
|
1908
|
+
console.log(chalk5.gray("Executing flow..."));
|
|
1804
1909
|
try {
|
|
1805
1910
|
payload.streamResponse = false;
|
|
1806
1911
|
const result = await client.post("/dispatch", payload);
|
|
1807
|
-
console.log(
|
|
1912
|
+
console.log(chalk5.green("Flow execution complete"));
|
|
1808
1913
|
printJson(result);
|
|
1809
1914
|
} catch (error) {
|
|
1810
1915
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1811
|
-
console.error(
|
|
1916
|
+
console.error(chalk5.red(`Flow execution failed: ${message}`));
|
|
1812
1917
|
process.exit(1);
|
|
1813
1918
|
}
|
|
1814
1919
|
}
|
|
@@ -1833,7 +1938,7 @@ flowsCommand.command("create").description("Create a new flow").requiredOption("
|
|
|
1833
1938
|
}
|
|
1834
1939
|
} catch (error) {
|
|
1835
1940
|
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
1836
|
-
console.error(
|
|
1941
|
+
console.error(chalk5.red(`Failed to read flow file: ${msg}`));
|
|
1837
1942
|
process.exit(1);
|
|
1838
1943
|
}
|
|
1839
1944
|
}
|
|
@@ -1844,11 +1949,11 @@ flowsCommand.command("create").description("Create a new flow").requiredOption("
|
|
|
1844
1949
|
printJson(data);
|
|
1845
1950
|
return;
|
|
1846
1951
|
}
|
|
1847
|
-
console.log(` ID: ${
|
|
1952
|
+
console.log(` ID: ${chalk5.green(data.id)}`);
|
|
1848
1953
|
console.log(` Name: ${data.name}`);
|
|
1849
1954
|
} catch (error) {
|
|
1850
1955
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1851
|
-
console.error(
|
|
1956
|
+
console.error(chalk5.red(`Failed to create flow: ${message}`));
|
|
1852
1957
|
process.exit(1);
|
|
1853
1958
|
}
|
|
1854
1959
|
return;
|
|
@@ -1897,7 +2002,7 @@ flowsCommand.command("delete <id>").description("Delete a flow").option("--tty",
|
|
|
1897
2002
|
console.log(JSON.stringify({ status: "deleted", id }, null, 2));
|
|
1898
2003
|
} catch (error) {
|
|
1899
2004
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1900
|
-
console.error(
|
|
2005
|
+
console.error(chalk5.red(`Failed to delete flow: ${message}`));
|
|
1901
2006
|
process.exit(1);
|
|
1902
2007
|
}
|
|
1903
2008
|
return;
|
|
@@ -1948,7 +2053,7 @@ flowsCommand.command("delete <id>").description("Delete a flow").option("--tty",
|
|
|
1948
2053
|
|
|
1949
2054
|
// src/commands/records.ts
|
|
1950
2055
|
import { Command as Command3 } from "commander";
|
|
1951
|
-
import
|
|
2056
|
+
import chalk6 from "chalk";
|
|
1952
2057
|
import React3 from "react";
|
|
1953
2058
|
import { render as render3 } from "ink";
|
|
1954
2059
|
import { useState as useState4, useEffect as useEffect5 } from "react";
|
|
@@ -1986,7 +2091,7 @@ recordsCommand.command("list").description("List all records").option("--type <t
|
|
|
1986
2091
|
}
|
|
1987
2092
|
} catch (error) {
|
|
1988
2093
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1989
|
-
console.error(
|
|
2094
|
+
console.error(chalk6.red(`Failed to fetch records: ${message}`));
|
|
1990
2095
|
process.exit(1);
|
|
1991
2096
|
}
|
|
1992
2097
|
return;
|
|
@@ -2047,7 +2152,7 @@ recordsCommand.command("get <id>").description("Get record details").option("--j
|
|
|
2047
2152
|
}
|
|
2048
2153
|
} catch (error) {
|
|
2049
2154
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2050
|
-
console.error(
|
|
2155
|
+
console.error(chalk6.red(`Failed to fetch record: ${message}`));
|
|
2051
2156
|
process.exit(1);
|
|
2052
2157
|
}
|
|
2053
2158
|
return;
|
|
@@ -2091,7 +2196,7 @@ recordsCommand.command("create").description("Create a new record").requiredOpti
|
|
|
2091
2196
|
try {
|
|
2092
2197
|
metadata = JSON.parse(options.metadata);
|
|
2093
2198
|
} catch {
|
|
2094
|
-
console.error(
|
|
2199
|
+
console.error(chalk6.red("Invalid JSON in metadata"));
|
|
2095
2200
|
process.exit(1);
|
|
2096
2201
|
}
|
|
2097
2202
|
}
|
|
@@ -2111,7 +2216,7 @@ recordsCommand.command("create").description("Create a new record").requiredOpti
|
|
|
2111
2216
|
console.log(` Type: ${data.type}`);
|
|
2112
2217
|
} catch (error) {
|
|
2113
2218
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2114
|
-
console.error(
|
|
2219
|
+
console.error(chalk6.red(`Failed to create record: ${message}`));
|
|
2115
2220
|
process.exit(1);
|
|
2116
2221
|
}
|
|
2117
2222
|
return;
|
|
@@ -2164,7 +2269,7 @@ recordsCommand.command("delete <id>").description("Delete a record").option("--t
|
|
|
2164
2269
|
console.log(JSON.stringify({ status: "deleted", id }, null, 2));
|
|
2165
2270
|
} catch (error) {
|
|
2166
2271
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2167
|
-
console.error(
|
|
2272
|
+
console.error(chalk6.red(`Failed to delete record: ${message}`));
|
|
2168
2273
|
process.exit(1);
|
|
2169
2274
|
}
|
|
2170
2275
|
return;
|
|
@@ -2216,7 +2321,7 @@ recordsCommand.command("export").description("Export records to a file").option(
|
|
|
2216
2321
|
async (options) => {
|
|
2217
2322
|
const apiKey = await ensureAuth();
|
|
2218
2323
|
if (!apiKey) return;
|
|
2219
|
-
console.log(
|
|
2324
|
+
console.log(chalk6.gray("Exporting records..."));
|
|
2220
2325
|
try {
|
|
2221
2326
|
const client = new ApiClient(apiKey);
|
|
2222
2327
|
const params = { limit: options.limit };
|
|
@@ -2224,7 +2329,7 @@ recordsCommand.command("export").description("Export records to a file").option(
|
|
|
2224
2329
|
const data = await client.get("/records", params);
|
|
2225
2330
|
const records = data.data ?? [];
|
|
2226
2331
|
if (records.length === 0) {
|
|
2227
|
-
console.log(
|
|
2332
|
+
console.log(chalk6.yellow("No records to export"));
|
|
2228
2333
|
return;
|
|
2229
2334
|
}
|
|
2230
2335
|
let content;
|
|
@@ -2242,10 +2347,10 @@ recordsCommand.command("export").description("Export records to a file").option(
|
|
|
2242
2347
|
}
|
|
2243
2348
|
const filename = options.output || `records-export-${Date.now()}.${options.format === "csv" ? "csv" : "json"}`;
|
|
2244
2349
|
writeFileSync(filename, content);
|
|
2245
|
-
console.log(
|
|
2350
|
+
console.log(chalk6.green(`Exported ${records.length} records to ${filename}`));
|
|
2246
2351
|
} catch (error) {
|
|
2247
2352
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2248
|
-
console.error(
|
|
2353
|
+
console.error(chalk6.red(`Failed to export records: ${message}`));
|
|
2249
2354
|
process.exit(1);
|
|
2250
2355
|
}
|
|
2251
2356
|
}
|
|
@@ -2259,7 +2364,7 @@ function csvEscape(value) {
|
|
|
2259
2364
|
|
|
2260
2365
|
// src/commands/prompts.ts
|
|
2261
2366
|
import { Command as Command4 } from "commander";
|
|
2262
|
-
import
|
|
2367
|
+
import chalk7 from "chalk";
|
|
2263
2368
|
import React4 from "react";
|
|
2264
2369
|
import { render as render4 } from "ink";
|
|
2265
2370
|
import { useState as useState5, useEffect as useEffect6 } from "react";
|
|
@@ -2297,7 +2402,7 @@ promptsCommand.command("list").description("List all prompts").option("--json",
|
|
|
2297
2402
|
}
|
|
2298
2403
|
} catch (error) {
|
|
2299
2404
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2300
|
-
console.error(
|
|
2405
|
+
console.error(chalk7.red(`Failed to fetch prompts: ${message}`));
|
|
2301
2406
|
process.exit(1);
|
|
2302
2407
|
}
|
|
2303
2408
|
return;
|
|
@@ -2354,7 +2459,7 @@ promptsCommand.command("get <id>").description("Get prompt details").option("--j
|
|
|
2354
2459
|
]);
|
|
2355
2460
|
} catch (error) {
|
|
2356
2461
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2357
|
-
console.error(
|
|
2462
|
+
console.error(chalk7.red(`Failed to fetch prompt: ${message}`));
|
|
2358
2463
|
process.exit(1);
|
|
2359
2464
|
}
|
|
2360
2465
|
return;
|
|
@@ -2409,7 +2514,7 @@ promptsCommand.command("test <id>").description("Test a prompt with input").opti
|
|
|
2409
2514
|
payload.messages = [{ role: "user", content: options.input }];
|
|
2410
2515
|
}
|
|
2411
2516
|
if (options.stream) {
|
|
2412
|
-
console.log(
|
|
2517
|
+
console.log(chalk7.gray("Testing prompt..."));
|
|
2413
2518
|
try {
|
|
2414
2519
|
const response = await client.stream("/dispatch", payload);
|
|
2415
2520
|
const callbacks = {
|
|
@@ -2417,7 +2522,7 @@ promptsCommand.command("test <id>").description("Test a prompt with input").opti
|
|
|
2417
2522
|
process.stdout.write(chunk);
|
|
2418
2523
|
},
|
|
2419
2524
|
onError: (err) => {
|
|
2420
|
-
console.error(
|
|
2525
|
+
console.error(chalk7.red(`
|
|
2421
2526
|
Error: ${err.message}`));
|
|
2422
2527
|
}
|
|
2423
2528
|
};
|
|
@@ -2425,15 +2530,15 @@ Error: ${err.message}`));
|
|
|
2425
2530
|
console.log();
|
|
2426
2531
|
} catch (error) {
|
|
2427
2532
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2428
|
-
console.error(
|
|
2533
|
+
console.error(chalk7.red(`Prompt test failed: ${message}`));
|
|
2429
2534
|
process.exit(1);
|
|
2430
2535
|
}
|
|
2431
2536
|
} else {
|
|
2432
|
-
console.log(
|
|
2537
|
+
console.log(chalk7.gray("Testing prompt..."));
|
|
2433
2538
|
try {
|
|
2434
2539
|
payload.streamResponse = false;
|
|
2435
2540
|
const result = await client.post("/dispatch", payload);
|
|
2436
|
-
console.log(
|
|
2541
|
+
console.log(chalk7.green("Prompt test complete"));
|
|
2437
2542
|
if (options.json) {
|
|
2438
2543
|
printJson(result);
|
|
2439
2544
|
} else {
|
|
@@ -2441,7 +2546,7 @@ Error: ${err.message}`));
|
|
|
2441
2546
|
}
|
|
2442
2547
|
} catch (error) {
|
|
2443
2548
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2444
|
-
console.error(
|
|
2549
|
+
console.error(chalk7.red(`Prompt test failed: ${message}`));
|
|
2445
2550
|
process.exit(1);
|
|
2446
2551
|
}
|
|
2447
2552
|
}
|
|
@@ -2450,7 +2555,7 @@ Error: ${err.message}`));
|
|
|
2450
2555
|
|
|
2451
2556
|
// src/commands/batch.ts
|
|
2452
2557
|
import { Command as Command5 } from "commander";
|
|
2453
|
-
import
|
|
2558
|
+
import chalk8 from "chalk";
|
|
2454
2559
|
import React5 from "react";
|
|
2455
2560
|
import { render as render5 } from "ink";
|
|
2456
2561
|
import { useState as useState6, useEffect as useEffect7 } from "react";
|
|
@@ -2466,7 +2571,7 @@ batchCommand.command("submit").description("Submit a batch job").requiredOption(
|
|
|
2466
2571
|
recordIds = Array.isArray(parsed) ? parsed : parsed.recordIds || parsed.records || [];
|
|
2467
2572
|
} catch (error) {
|
|
2468
2573
|
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
2469
|
-
console.error(
|
|
2574
|
+
console.error(chalk8.red(`Failed to read records file: ${msg}`));
|
|
2470
2575
|
process.exit(1);
|
|
2471
2576
|
}
|
|
2472
2577
|
const client = new ApiClient(apiKey);
|
|
@@ -2479,14 +2584,14 @@ batchCommand.command("submit").description("Submit a batch job").requiredOption(
|
|
|
2479
2584
|
if (options.json) {
|
|
2480
2585
|
printJson(data);
|
|
2481
2586
|
} else {
|
|
2482
|
-
console.log(
|
|
2483
|
-
console.log(` Batch ID: ${
|
|
2587
|
+
console.log(chalk8.green("Batch submitted"));
|
|
2588
|
+
console.log(` Batch ID: ${chalk8.green(data.id)}`);
|
|
2484
2589
|
console.log(` Status: ${data.status}`);
|
|
2485
2590
|
}
|
|
2486
2591
|
} catch (error) {
|
|
2487
2592
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2488
|
-
console.error(
|
|
2489
|
-
console.error(
|
|
2593
|
+
console.error(chalk8.red("Failed to submit batch"));
|
|
2594
|
+
console.error(chalk8.red(message));
|
|
2490
2595
|
process.exit(1);
|
|
2491
2596
|
}
|
|
2492
2597
|
return;
|
|
@@ -2541,20 +2646,20 @@ batchCommand.command("status <id>").description("Check batch job status").option
|
|
|
2541
2646
|
if (options.json) {
|
|
2542
2647
|
printJson(data);
|
|
2543
2648
|
} else {
|
|
2544
|
-
console.log(
|
|
2545
|
-
console.log(` Status: ${
|
|
2649
|
+
console.log(chalk8.cyan(`Batch Job: ${batchId}`));
|
|
2650
|
+
console.log(` Status: ${chalk8.green(data.status)}`);
|
|
2546
2651
|
console.log(` Progress: ${data.processedRecords}/${data.totalRecords}`);
|
|
2547
2652
|
if (data.failedRecords > 0) {
|
|
2548
|
-
console.log(` Failed: ${
|
|
2653
|
+
console.log(` Failed: ${chalk8.red(data.failedRecords)}`);
|
|
2549
2654
|
}
|
|
2550
2655
|
if (options.watch && data.status === "processing") {
|
|
2551
|
-
console.log(
|
|
2656
|
+
console.log(chalk8.gray("\nWatching for updates... (Ctrl+C to stop)"));
|
|
2552
2657
|
}
|
|
2553
2658
|
}
|
|
2554
2659
|
} catch (error) {
|
|
2555
2660
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2556
|
-
console.error(
|
|
2557
|
-
console.error(
|
|
2661
|
+
console.error(chalk8.red("Failed to fetch batch status"));
|
|
2662
|
+
console.error(chalk8.red(message));
|
|
2558
2663
|
process.exit(1);
|
|
2559
2664
|
}
|
|
2560
2665
|
return;
|
|
@@ -2606,11 +2711,11 @@ batchCommand.command("cancel <id>").description("Cancel a batch job").option("--
|
|
|
2606
2711
|
if (!isTTY(options)) {
|
|
2607
2712
|
try {
|
|
2608
2713
|
await client.post(`/batch/cancel/${batchId}`);
|
|
2609
|
-
console.log(
|
|
2714
|
+
console.log(chalk8.green("Batch job cancelled"));
|
|
2610
2715
|
} catch (error) {
|
|
2611
2716
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2612
|
-
console.error(
|
|
2613
|
-
console.error(
|
|
2717
|
+
console.error(chalk8.red("Failed to cancel batch job"));
|
|
2718
|
+
console.error(chalk8.red(message));
|
|
2614
2719
|
process.exit(1);
|
|
2615
2720
|
}
|
|
2616
2721
|
return;
|
|
@@ -2649,7 +2754,7 @@ batchCommand.command("cancel <id>").description("Cancel a batch job").option("--
|
|
|
2649
2754
|
import { Command as Command6 } from "commander";
|
|
2650
2755
|
import React8 from "react";
|
|
2651
2756
|
import { render as render6 } from "ink";
|
|
2652
|
-
import
|
|
2757
|
+
import chalk9 from "chalk";
|
|
2653
2758
|
import { processStream as processStream3 } from "@runtypelabs/sdk";
|
|
2654
2759
|
|
|
2655
2760
|
// src/chat/session-manager.ts
|
|
@@ -2898,14 +3003,14 @@ function formatRelativeTime(timestamp) {
|
|
|
2898
3003
|
return `${Math.floor(diff / 86400)}d ago`;
|
|
2899
3004
|
}
|
|
2900
3005
|
function useRelativeTime(timestamp) {
|
|
2901
|
-
const [
|
|
3006
|
+
const [relative2, setRelative] = useState8(() => formatRelativeTime(timestamp));
|
|
2902
3007
|
useEffect8(() => {
|
|
2903
3008
|
const interval = setInterval(() => {
|
|
2904
3009
|
setRelative(formatRelativeTime(timestamp));
|
|
2905
3010
|
}, 3e4);
|
|
2906
3011
|
return () => clearInterval(interval);
|
|
2907
3012
|
}, [timestamp]);
|
|
2908
|
-
return
|
|
3013
|
+
return relative2;
|
|
2909
3014
|
}
|
|
2910
3015
|
|
|
2911
3016
|
// src/ink/talk/MessageBubble.tsx
|
|
@@ -3480,10 +3585,10 @@ var talkCommand = new Command6("talk").description("Start an interactive chat se
|
|
|
3480
3585
|
if (options.continue) {
|
|
3481
3586
|
try {
|
|
3482
3587
|
await session.loadFromFile(options.continue);
|
|
3483
|
-
console.log(
|
|
3588
|
+
console.log(chalk9.green(`Loaded session from: ${options.continue}`));
|
|
3484
3589
|
} catch (error) {
|
|
3485
3590
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3486
|
-
console.error(
|
|
3591
|
+
console.error(chalk9.red(`Failed to load session: ${message}`));
|
|
3487
3592
|
process.exit(1);
|
|
3488
3593
|
}
|
|
3489
3594
|
}
|
|
@@ -3540,14 +3645,14 @@ var talkCommand = new Command6("talk").description("Start an interactive chat se
|
|
|
3540
3645
|
} catch (error) {
|
|
3541
3646
|
exitAltScreen();
|
|
3542
3647
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3543
|
-
console.error(
|
|
3648
|
+
console.error(chalk9.red(`Talk failed: ${message}`));
|
|
3544
3649
|
process.exit(1);
|
|
3545
3650
|
}
|
|
3546
3651
|
});
|
|
3547
3652
|
|
|
3548
3653
|
// src/commands/config.ts
|
|
3549
3654
|
import { Command as Command7 } from "commander";
|
|
3550
|
-
import
|
|
3655
|
+
import chalk10 from "chalk";
|
|
3551
3656
|
import Conf2 from "conf";
|
|
3552
3657
|
import path4 from "path";
|
|
3553
3658
|
import os3 from "os";
|
|
@@ -3571,31 +3676,31 @@ var config = new Conf2({
|
|
|
3571
3676
|
configCommand.command("get [key]").description("Get configuration value").action((key) => {
|
|
3572
3677
|
if (key) {
|
|
3573
3678
|
if (!isCliConfigKey(key)) {
|
|
3574
|
-
console.log(
|
|
3679
|
+
console.log(chalk10.yellow(`Configuration key '${key}' not found`));
|
|
3575
3680
|
return;
|
|
3576
3681
|
}
|
|
3577
3682
|
const value = config.get(key);
|
|
3578
3683
|
if (value !== void 0) {
|
|
3579
3684
|
console.log(value);
|
|
3580
3685
|
} else {
|
|
3581
|
-
console.log(
|
|
3686
|
+
console.log(chalk10.yellow(`Configuration key '${key}' not found`));
|
|
3582
3687
|
}
|
|
3583
3688
|
} else {
|
|
3584
3689
|
const allConfig = config.store;
|
|
3585
3690
|
if (Object.keys(allConfig).length > 0) {
|
|
3586
|
-
console.log(
|
|
3691
|
+
console.log(chalk10.cyan("Current Configuration:"));
|
|
3587
3692
|
for (const [k, v] of Object.entries(allConfig)) {
|
|
3588
|
-
console.log(` ${
|
|
3693
|
+
console.log(` ${chalk10.green(k)}: ${v}`);
|
|
3589
3694
|
}
|
|
3590
3695
|
} else {
|
|
3591
|
-
console.log(
|
|
3696
|
+
console.log(chalk10.gray("No configuration set"));
|
|
3592
3697
|
}
|
|
3593
3698
|
}
|
|
3594
3699
|
});
|
|
3595
3700
|
configCommand.command("set <key> <value>").description("Set configuration value").action((key, value) => {
|
|
3596
3701
|
if (!isCliConfigKey(key)) {
|
|
3597
|
-
console.log(
|
|
3598
|
-
console.log(
|
|
3702
|
+
console.log(chalk10.red(`Invalid configuration key: ${key}`));
|
|
3703
|
+
console.log(chalk10.gray(`Valid keys: ${CLI_CONFIG_KEYS.join(", ")}`));
|
|
3599
3704
|
process.exit(1);
|
|
3600
3705
|
}
|
|
3601
3706
|
let parsedValue;
|
|
@@ -3604,7 +3709,7 @@ configCommand.command("set <key> <value>").description("Set configuration value"
|
|
|
3604
3709
|
{
|
|
3605
3710
|
const temperature = parseFloat(value);
|
|
3606
3711
|
if (isNaN(temperature) || temperature < 0 || temperature > 1) {
|
|
3607
|
-
console.log(
|
|
3712
|
+
console.log(chalk10.red("Temperature must be a number between 0 and 1"));
|
|
3608
3713
|
process.exit(1);
|
|
3609
3714
|
}
|
|
3610
3715
|
parsedValue = temperature;
|
|
@@ -3615,7 +3720,7 @@ configCommand.command("set <key> <value>").description("Set configuration value"
|
|
|
3615
3720
|
break;
|
|
3616
3721
|
case "outputFormat":
|
|
3617
3722
|
if (!["table", "json", "plain"].includes(value)) {
|
|
3618
|
-
console.log(
|
|
3723
|
+
console.log(chalk10.red("Output format must be: table, json, or plain"));
|
|
3619
3724
|
process.exit(1);
|
|
3620
3725
|
}
|
|
3621
3726
|
parsedValue = value;
|
|
@@ -3625,11 +3730,11 @@ configCommand.command("set <key> <value>").description("Set configuration value"
|
|
|
3625
3730
|
break;
|
|
3626
3731
|
}
|
|
3627
3732
|
config.set(key, parsedValue);
|
|
3628
|
-
console.log(
|
|
3733
|
+
console.log(chalk10.green(`Configuration updated: ${key} = ${parsedValue}`));
|
|
3629
3734
|
});
|
|
3630
3735
|
configCommand.command("reset").description("Reset all configuration to defaults").action(() => {
|
|
3631
3736
|
config.clear();
|
|
3632
|
-
console.log(
|
|
3737
|
+
console.log(chalk10.green("Configuration reset to defaults"));
|
|
3633
3738
|
});
|
|
3634
3739
|
configCommand.command("path").description("Show configuration file path").action(() => {
|
|
3635
3740
|
console.log(config.path);
|
|
@@ -3637,13 +3742,13 @@ configCommand.command("path").description("Show configuration file path").action
|
|
|
3637
3742
|
|
|
3638
3743
|
// src/commands/products.ts
|
|
3639
3744
|
import { Command as Command8 } from "commander";
|
|
3640
|
-
import
|
|
3745
|
+
import chalk11 from "chalk";
|
|
3641
3746
|
import React9 from "react";
|
|
3642
3747
|
import { render as render7 } from "ink";
|
|
3643
3748
|
import { useState as useState11, useEffect as useEffect10 } from "react";
|
|
3644
3749
|
import open2 from "open";
|
|
3645
3750
|
function displayAgentCard(agentCard) {
|
|
3646
|
-
console.log(
|
|
3751
|
+
console.log(chalk11.cyan("\nAgent Details:"));
|
|
3647
3752
|
console.log(` Name: ${agentCard.name}`);
|
|
3648
3753
|
if (agentCard.description) {
|
|
3649
3754
|
console.log(` Description: ${agentCard.description}`);
|
|
@@ -3653,7 +3758,7 @@ function displayAgentCard(agentCard) {
|
|
|
3653
3758
|
console.log(" Skills:");
|
|
3654
3759
|
agentCard.skills.forEach((skill) => {
|
|
3655
3760
|
const desc = skill.description ? ` - ${skill.description}` : "";
|
|
3656
|
-
console.log(` ${
|
|
3761
|
+
console.log(` ${chalk11.cyan("\u2022")} ${skill.name}${desc}`);
|
|
3657
3762
|
});
|
|
3658
3763
|
}
|
|
3659
3764
|
}
|
|
@@ -3703,7 +3808,7 @@ function displayCreationSuccess(result, agentCard, dashboardBaseUrl, jsonOutput)
|
|
|
3703
3808
|
Product ID: ${result.product.id}`);
|
|
3704
3809
|
console.log(`Name: ${result.product.name}`);
|
|
3705
3810
|
console.log(`Dashboard: ${productUrl}`);
|
|
3706
|
-
console.log(
|
|
3811
|
+
console.log(chalk11.cyan("\nNext steps:"));
|
|
3707
3812
|
console.log(" 1. Visit the dashboard to configure surfaces");
|
|
3708
3813
|
console.log(" 2. Or run: runtype products init --from <another-url>");
|
|
3709
3814
|
}
|
|
@@ -3740,7 +3845,7 @@ productsCommand.command("init").description("Initialize a product from an extern
|
|
|
3740
3845
|
);
|
|
3741
3846
|
process.exit(1);
|
|
3742
3847
|
}
|
|
3743
|
-
console.error(
|
|
3848
|
+
console.error(chalk11.red("--from URL required in non-TTY mode"));
|
|
3744
3849
|
process.exit(1);
|
|
3745
3850
|
}
|
|
3746
3851
|
try {
|
|
@@ -3755,7 +3860,7 @@ productsCommand.command("init").description("Initialize a product from an extern
|
|
|
3755
3860
|
)
|
|
3756
3861
|
);
|
|
3757
3862
|
} else {
|
|
3758
|
-
console.error(
|
|
3863
|
+
console.error(chalk11.red(result.error));
|
|
3759
3864
|
}
|
|
3760
3865
|
process.exit(1);
|
|
3761
3866
|
}
|
|
@@ -3778,7 +3883,7 @@ productsCommand.command("init").description("Initialize a product from an extern
|
|
|
3778
3883
|
)
|
|
3779
3884
|
);
|
|
3780
3885
|
} else {
|
|
3781
|
-
console.log(
|
|
3886
|
+
console.log(chalk11.cyan("\nOpening browser to complete setup..."));
|
|
3782
3887
|
}
|
|
3783
3888
|
await open2(targetUrl);
|
|
3784
3889
|
return;
|
|
@@ -3801,14 +3906,14 @@ productsCommand.command("init").description("Initialize a product from an extern
|
|
|
3801
3906
|
)
|
|
3802
3907
|
);
|
|
3803
3908
|
} else {
|
|
3804
|
-
console.error(
|
|
3909
|
+
console.error(chalk11.red(createResult.error));
|
|
3805
3910
|
}
|
|
3806
3911
|
process.exit(1);
|
|
3807
3912
|
}
|
|
3808
3913
|
displayCreationSuccess(createResult, result.agentCard, getDashboardUrl(), isJsonMode);
|
|
3809
3914
|
} catch (error) {
|
|
3810
3915
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3811
|
-
console.error(
|
|
3916
|
+
console.error(chalk11.red(`Failed: ${message}`));
|
|
3812
3917
|
process.exit(1);
|
|
3813
3918
|
}
|
|
3814
3919
|
return;
|
|
@@ -4771,7 +4876,7 @@ var initCommand = new Command9("init").description("Set up Runtype CLI with guid
|
|
|
4771
4876
|
|
|
4772
4877
|
// src/commands/dispatch.ts
|
|
4773
4878
|
import { Command as Command10 } from "commander";
|
|
4774
|
-
import
|
|
4879
|
+
import chalk12 from "chalk";
|
|
4775
4880
|
import React11 from "react";
|
|
4776
4881
|
import { render as render9 } from "ink";
|
|
4777
4882
|
import { useState as useState13, useEffect as useEffect12 } from "react";
|
|
@@ -4779,7 +4884,7 @@ import { readFileSync as readFileSync3 } from "fs";
|
|
|
4779
4884
|
import { processStream as processStream4 } from "@runtypelabs/sdk";
|
|
4780
4885
|
var dispatchCommand = new Command10("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").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
|
|
4781
4886
|
if (!options.flow && !options.agent) {
|
|
4782
|
-
console.error(
|
|
4887
|
+
console.error(chalk12.red("Error: Either --flow or --agent is required"));
|
|
4783
4888
|
process.exit(1);
|
|
4784
4889
|
}
|
|
4785
4890
|
const apiKey = await ensureAuth();
|
|
@@ -4800,7 +4905,7 @@ var dispatchCommand = new Command10("dispatch").description("Execute a flow or a
|
|
|
4800
4905
|
payload.record = { metadata: data };
|
|
4801
4906
|
} catch (error) {
|
|
4802
4907
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
4803
|
-
console.error(
|
|
4908
|
+
console.error(chalk12.red(`Failed to read record JSON: ${message}`));
|
|
4804
4909
|
process.exit(1);
|
|
4805
4910
|
}
|
|
4806
4911
|
}
|
|
@@ -4825,18 +4930,18 @@ function collectVariables(value, previous) {
|
|
|
4825
4930
|
return previous.concat([value]);
|
|
4826
4931
|
}
|
|
4827
4932
|
async function handleStreaming(client, payload, options) {
|
|
4828
|
-
console.log(
|
|
4933
|
+
console.log(chalk12.gray("Starting execution..."));
|
|
4829
4934
|
try {
|
|
4830
4935
|
const response = await client.stream("/dispatch", payload);
|
|
4831
4936
|
const callbacks = {
|
|
4832
4937
|
onFlowStart: (event) => {
|
|
4833
4938
|
if (options.debug) {
|
|
4834
|
-
console.log(
|
|
4939
|
+
console.log(chalk12.cyan(`Flow: ${event.flowName} (${event.totalSteps} steps)`));
|
|
4835
4940
|
}
|
|
4836
4941
|
},
|
|
4837
4942
|
onStepStart: (event) => {
|
|
4838
4943
|
if (options.debug) {
|
|
4839
|
-
console.log(
|
|
4944
|
+
console.log(chalk12.gray(`
|
|
4840
4945
|
[${event.name}] Running...`));
|
|
4841
4946
|
}
|
|
4842
4947
|
},
|
|
@@ -4845,7 +4950,7 @@ async function handleStreaming(client, payload, options) {
|
|
|
4845
4950
|
},
|
|
4846
4951
|
onStepComplete: (_result, event) => {
|
|
4847
4952
|
if (options.debug) {
|
|
4848
|
-
console.log(
|
|
4953
|
+
console.log(chalk12.gray(`
|
|
4849
4954
|
[${event.name}] Complete`));
|
|
4850
4955
|
}
|
|
4851
4956
|
},
|
|
@@ -4856,7 +4961,7 @@ async function handleStreaming(client, payload, options) {
|
|
|
4856
4961
|
}
|
|
4857
4962
|
},
|
|
4858
4963
|
onError: (err) => {
|
|
4859
|
-
console.error(
|
|
4964
|
+
console.error(chalk12.red(`
|
|
4860
4965
|
Error: ${err.message}`));
|
|
4861
4966
|
}
|
|
4862
4967
|
};
|
|
@@ -4864,8 +4969,8 @@ Error: ${err.message}`));
|
|
|
4864
4969
|
console.log();
|
|
4865
4970
|
} catch (error) {
|
|
4866
4971
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
4867
|
-
console.error(
|
|
4868
|
-
console.error(
|
|
4972
|
+
console.error(chalk12.red("Execution failed"));
|
|
4973
|
+
console.error(chalk12.red(message));
|
|
4869
4974
|
process.exit(1);
|
|
4870
4975
|
}
|
|
4871
4976
|
}
|
|
@@ -4880,7 +4985,7 @@ async function handleNonStreaming(client, payload, options) {
|
|
|
4880
4985
|
const steps = result.steps;
|
|
4881
4986
|
if (steps) {
|
|
4882
4987
|
for (const step of steps) {
|
|
4883
|
-
console.log(
|
|
4988
|
+
console.log(chalk12.cyan(`
|
|
4884
4989
|
[${step.name}]`));
|
|
4885
4990
|
if (typeof step.result === "string") {
|
|
4886
4991
|
console.log(step.result);
|
|
@@ -4894,8 +4999,8 @@ async function handleNonStreaming(client, payload, options) {
|
|
|
4894
4999
|
}
|
|
4895
5000
|
} catch (error) {
|
|
4896
5001
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
4897
|
-
console.error(
|
|
4898
|
-
console.error(
|
|
5002
|
+
console.error(chalk12.red("Execution failed"));
|
|
5003
|
+
console.error(chalk12.red(message));
|
|
4899
5004
|
process.exit(1);
|
|
4900
5005
|
}
|
|
4901
5006
|
return;
|
|
@@ -4917,7 +5022,7 @@ async function handleNonStreaming(client, payload, options) {
|
|
|
4917
5022
|
const steps = result.steps;
|
|
4918
5023
|
if (steps) {
|
|
4919
5024
|
for (const step of steps) {
|
|
4920
|
-
console.log(
|
|
5025
|
+
console.log(chalk12.cyan(`
|
|
4921
5026
|
[${step.name}]`));
|
|
4922
5027
|
if (typeof step.result === "string") {
|
|
4923
5028
|
console.log(step.result);
|
|
@@ -4951,7 +5056,7 @@ async function handleNonStreaming(client, payload, options) {
|
|
|
4951
5056
|
|
|
4952
5057
|
// src/commands/agents.ts
|
|
4953
5058
|
import { Command as Command12 } from "commander";
|
|
4954
|
-
import
|
|
5059
|
+
import chalk14 from "chalk";
|
|
4955
5060
|
import React13 from "react";
|
|
4956
5061
|
import { render as render11 } from "ink";
|
|
4957
5062
|
import { useState as useState19, useEffect as useEffect17 } from "react";
|
|
@@ -4959,22 +5064,41 @@ import { processStream as processStream5 } from "@runtypelabs/sdk";
|
|
|
4959
5064
|
|
|
4960
5065
|
// src/commands/agents-task.ts
|
|
4961
5066
|
import { Command as Command11 } from "commander";
|
|
4962
|
-
import
|
|
5067
|
+
import chalk13 from "chalk";
|
|
4963
5068
|
import { render as render10 } from "ink";
|
|
4964
5069
|
import React12 from "react";
|
|
4965
5070
|
|
|
4966
5071
|
// src/ink/marathon/MarathonApp.tsx
|
|
4967
|
-
import { useState as useState18, useEffect as useEffect16, useRef as useRef7, useCallback as useCallback5 } from "react";
|
|
5072
|
+
import { useState as useState18, useEffect as useEffect16, useRef as useRef7, useCallback as useCallback5, useMemo as useMemo5 } from "react";
|
|
4968
5073
|
import { execSync } from "child_process";
|
|
4969
5074
|
import open3 from "open";
|
|
4970
|
-
import { Box as
|
|
4971
|
-
import { StreamOutput as StreamOutput3, StatusBar as StatusBar2, ErrorDisplay as ErrorDisplay4, theme as
|
|
5075
|
+
import { Box as Box23, useApp as useApp5, useInput as useInput9, useStdout as useStdout2 } from "ink";
|
|
5076
|
+
import { StreamOutput as StreamOutput3, StatusBar as StatusBar2, ErrorDisplay as ErrorDisplay4, theme as theme23 } from "@runtypelabs/ink-components";
|
|
5077
|
+
import { LoadingAnimation } from "@runtypelabs/terminal-animations";
|
|
4972
5078
|
|
|
4973
5079
|
// src/ink/marathon/useMarathonStream.ts
|
|
4974
5080
|
import { useState as useState14, useRef as useRef5, useMemo as useMemo2, useCallback as useCallback4 } from "react";
|
|
5081
|
+
|
|
5082
|
+
// src/ink/marathon/transcript-utils.ts
|
|
5083
|
+
function appendTranscriptText(content, delta, previousKind) {
|
|
5084
|
+
if (!content) return delta;
|
|
5085
|
+
const needsSeparator = previousKind === "tool" && !content.endsWith("\n") && !delta.startsWith("\n");
|
|
5086
|
+
return needsSeparator ? `${content}
|
|
5087
|
+
${delta}` : `${content}${delta}`;
|
|
5088
|
+
}
|
|
5089
|
+
function getVisibleReasoningLines(reasoning, maxLines) {
|
|
5090
|
+
if (maxLines <= 0) return [];
|
|
5091
|
+
const trimmed = reasoning.trimEnd();
|
|
5092
|
+
if (!trimmed) return [];
|
|
5093
|
+
return trimmed.split("\n").slice(-maxLines);
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
// src/ink/marathon/useMarathonStream.ts
|
|
4975
5097
|
var INITIAL_STATE2 = {
|
|
4976
5098
|
phase: "idle",
|
|
4977
5099
|
content: "",
|
|
5100
|
+
reasoning: "",
|
|
5101
|
+
lastTranscriptKind: null,
|
|
4978
5102
|
thinkingStartedAt: null,
|
|
4979
5103
|
tools: [],
|
|
4980
5104
|
sessionCount: 0,
|
|
@@ -4984,6 +5108,11 @@ var INITIAL_STATE2 = {
|
|
|
4984
5108
|
rawEvents: []
|
|
4985
5109
|
};
|
|
4986
5110
|
var MAX_RAW_EVENTS = 500;
|
|
5111
|
+
function appendContentLine(content, line) {
|
|
5112
|
+
if (!content) return line;
|
|
5113
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
5114
|
+
return `${content}${separator}${line}`;
|
|
5115
|
+
}
|
|
4987
5116
|
function pushRawEvent(prev, type, data) {
|
|
4988
5117
|
const event = { timestamp: Date.now(), type, data };
|
|
4989
5118
|
const events = [...prev.rawEvents, event];
|
|
@@ -5012,15 +5141,24 @@ function useMarathonStream() {
|
|
|
5012
5141
|
}));
|
|
5013
5142
|
},
|
|
5014
5143
|
onTurnDelta(event) {
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5144
|
+
setState((prev) => ({
|
|
5145
|
+
...prev,
|
|
5146
|
+
...event.contentType === "text" ? {
|
|
5018
5147
|
phase: "streaming",
|
|
5019
|
-
content: prev.content
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
}
|
|
5023
|
-
|
|
5148
|
+
content: appendTranscriptText(prev.content, event.delta, prev.lastTranscriptKind),
|
|
5149
|
+
lastTranscriptKind: "text",
|
|
5150
|
+
thinkingStartedAt: null
|
|
5151
|
+
} : {
|
|
5152
|
+
phase: "thinking",
|
|
5153
|
+
reasoning: prev.reasoning + event.delta,
|
|
5154
|
+
thinkingStartedAt: prev.thinkingStartedAt ?? Date.now()
|
|
5155
|
+
},
|
|
5156
|
+
rawEvents: pushRawEvent(prev, "agent_turn_delta", {
|
|
5157
|
+
contentType: event.contentType,
|
|
5158
|
+
delta: event.delta,
|
|
5159
|
+
deltaLength: event.delta.length
|
|
5160
|
+
})
|
|
5161
|
+
}));
|
|
5024
5162
|
},
|
|
5025
5163
|
onTurnComplete(event) {
|
|
5026
5164
|
setState((prev) => ({
|
|
@@ -5031,22 +5169,30 @@ function useMarathonStream() {
|
|
|
5031
5169
|
},
|
|
5032
5170
|
onToolStart(event) {
|
|
5033
5171
|
const uniqueId = `tool-${++toolCounter}`;
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5172
|
+
setState((prev) => {
|
|
5173
|
+
const sequence = prev.tools.length + 1;
|
|
5174
|
+
return {
|
|
5175
|
+
...prev,
|
|
5176
|
+
phase: "tool",
|
|
5177
|
+
thinkingStartedAt: null,
|
|
5178
|
+
content: appendContentLine(prev.content, `[${sequence}] ${event.toolName}`),
|
|
5179
|
+
lastTranscriptKind: "tool",
|
|
5180
|
+
tools: [
|
|
5181
|
+
...prev.tools,
|
|
5182
|
+
{
|
|
5183
|
+
id: uniqueId,
|
|
5184
|
+
sequence,
|
|
5185
|
+
sourceToolCallId: event.toolCallId,
|
|
5186
|
+
name: event.toolName,
|
|
5187
|
+
toolType: event.toolType,
|
|
5188
|
+
status: "running",
|
|
5189
|
+
parameters: event.parameters,
|
|
5190
|
+
startedAt: Date.now()
|
|
5191
|
+
}
|
|
5192
|
+
],
|
|
5193
|
+
rawEvents: pushRawEvent(prev, "agent_tool_start", { ...event })
|
|
5194
|
+
};
|
|
5195
|
+
});
|
|
5050
5196
|
},
|
|
5051
5197
|
onToolComplete(event) {
|
|
5052
5198
|
setState((prev) => {
|
|
@@ -5121,13 +5267,23 @@ function useMarathonStream() {
|
|
|
5121
5267
|
...prev,
|
|
5122
5268
|
phase: "idle",
|
|
5123
5269
|
content: "",
|
|
5270
|
+
reasoning: "",
|
|
5271
|
+
lastTranscriptKind: null,
|
|
5124
5272
|
thinkingStartedAt: null,
|
|
5125
5273
|
tools: [],
|
|
5126
5274
|
currentIteration: 0,
|
|
5127
5275
|
error: null
|
|
5128
5276
|
}));
|
|
5129
5277
|
}, []);
|
|
5130
|
-
|
|
5278
|
+
const showError = useCallback4((error) => {
|
|
5279
|
+
setState((prev) => ({
|
|
5280
|
+
...prev,
|
|
5281
|
+
phase: "error",
|
|
5282
|
+
error,
|
|
5283
|
+
rawEvents: pushRawEvent(prev, "agent_error", { message: error.message })
|
|
5284
|
+
}));
|
|
5285
|
+
}, []);
|
|
5286
|
+
return { state, callbacks, reset, setSteering, resetForNewSession, showError };
|
|
5131
5287
|
}
|
|
5132
5288
|
|
|
5133
5289
|
// src/ink/marathon/SessionHeader.tsx
|
|
@@ -5162,10 +5318,38 @@ function SessionHeader({
|
|
|
5162
5318
|
] });
|
|
5163
5319
|
}
|
|
5164
5320
|
|
|
5321
|
+
// src/ink/marathon/SessionTabs.tsx
|
|
5322
|
+
import { Box as Box15, Text as Text15 } from "ink";
|
|
5323
|
+
import { theme as theme15 } from "@runtypelabs/ink-components";
|
|
5324
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
5325
|
+
function getTabColor(tab) {
|
|
5326
|
+
if (tab.isSelected) return theme15.primary;
|
|
5327
|
+
if (tab.isUnread) return theme15.success;
|
|
5328
|
+
if (tab.isLive) return theme15.warning;
|
|
5329
|
+
return theme15.label;
|
|
5330
|
+
}
|
|
5331
|
+
function SessionTabs({ tabs, hiddenLeft, hiddenRight }) {
|
|
5332
|
+
if (tabs.length === 0) return null;
|
|
5333
|
+
return /* @__PURE__ */ jsxs15(Box15, { children: [
|
|
5334
|
+
hiddenLeft > 0 && /* @__PURE__ */ jsx16(Text15, { color: theme15.muted, children: `\u2039${hiddenLeft}` }),
|
|
5335
|
+
hiddenLeft > 0 && /* @__PURE__ */ jsx16(Text15, { children: " " }),
|
|
5336
|
+
tabs.map((tab, index) => {
|
|
5337
|
+
const unreadPrefix = tab.isUnread ? "\u2022 " : "";
|
|
5338
|
+
const shortcutPrefix = tab.shortcut != null ? `${tab.shortcut} ` : "";
|
|
5339
|
+
return /* @__PURE__ */ jsxs15(Box15, { children: [
|
|
5340
|
+
index > 0 && /* @__PURE__ */ jsx16(Text15, { children: " " }),
|
|
5341
|
+
/* @__PURE__ */ jsx16(Text15, { bold: tab.isSelected, inverse: tab.isSelected, color: getTabColor(tab), children: `${shortcutPrefix}${unreadPrefix}${tab.title}` })
|
|
5342
|
+
] }, tab.key);
|
|
5343
|
+
}),
|
|
5344
|
+
hiddenRight > 0 && /* @__PURE__ */ jsx16(Text15, { children: " " }),
|
|
5345
|
+
hiddenRight > 0 && /* @__PURE__ */ jsx16(Text15, { color: theme15.muted, children: `${hiddenRight}\u203A` })
|
|
5346
|
+
] });
|
|
5347
|
+
}
|
|
5348
|
+
|
|
5165
5349
|
// src/ink/marathon/ThinkingIndicator.tsx
|
|
5166
5350
|
import { useState as useState15, useEffect as useEffect13 } from "react";
|
|
5167
|
-
import { Spinner as Spinner5, theme as
|
|
5168
|
-
import { jsx as
|
|
5351
|
+
import { Spinner as Spinner5, theme as theme16 } from "@runtypelabs/ink-components";
|
|
5352
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
5169
5353
|
function ThinkingIndicator({ startedAt }) {
|
|
5170
5354
|
const [elapsed, setElapsed] = useState15(
|
|
5171
5355
|
() => startedAt ? Math.floor((Date.now() - startedAt) / 1e3) : 0
|
|
@@ -5178,62 +5362,108 @@ function ThinkingIndicator({ startedAt }) {
|
|
|
5178
5362
|
}, 1e3);
|
|
5179
5363
|
return () => clearInterval(interval);
|
|
5180
5364
|
}, [startedAt]);
|
|
5181
|
-
return /* @__PURE__ */
|
|
5365
|
+
return /* @__PURE__ */ jsx17(Spinner5, { label: `Thinking... ${elapsed}s`, color: theme16.muted });
|
|
5182
5366
|
}
|
|
5183
5367
|
|
|
5184
5368
|
// src/ink/marathon/ToolPanel.tsx
|
|
5185
5369
|
import { useState as useState16, useEffect as useEffect14, useMemo as useMemo3 } from "react";
|
|
5370
|
+
import { Box as Box18, Text as Text18 } from "ink";
|
|
5371
|
+
import { theme as theme18 } from "@runtypelabs/ink-components";
|
|
5372
|
+
|
|
5373
|
+
// src/ink/marathon/ReasoningBlock.tsx
|
|
5186
5374
|
import { Box as Box16, Text as Text16 } from "ink";
|
|
5187
|
-
import {
|
|
5375
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
5376
|
+
var REASONING_LABEL_COLOR = "cyan";
|
|
5377
|
+
var REASONING_TEXT_COLOR = "blueBright";
|
|
5378
|
+
var REASONING_HINT_COLOR = "gray";
|
|
5379
|
+
function renderReasoningLine(line) {
|
|
5380
|
+
return line ? `| ${line}` : "|";
|
|
5381
|
+
}
|
|
5382
|
+
function ReasoningBlock({
|
|
5383
|
+
lines,
|
|
5384
|
+
live = false,
|
|
5385
|
+
collapsed = false,
|
|
5386
|
+
compact = false,
|
|
5387
|
+
showToggleHint = false
|
|
5388
|
+
}) {
|
|
5389
|
+
const label = collapsed ? "Reasoning hidden" : "Reasoning";
|
|
5390
|
+
const hint = showToggleHint ? collapsed ? "r to show" : "r to hide" : null;
|
|
5391
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
5392
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
5393
|
+
/* @__PURE__ */ jsx18(Text16, { color: REASONING_LABEL_COLOR, children: label }),
|
|
5394
|
+
hint && /* @__PURE__ */ jsxs16(Text16, { color: REASONING_HINT_COLOR, children: [
|
|
5395
|
+
" (",
|
|
5396
|
+
hint,
|
|
5397
|
+
")"
|
|
5398
|
+
] })
|
|
5399
|
+
] }),
|
|
5400
|
+
!collapsed && lines.map((line, index) => /* @__PURE__ */ jsx18(
|
|
5401
|
+
Text16,
|
|
5402
|
+
{
|
|
5403
|
+
color: REASONING_TEXT_COLOR,
|
|
5404
|
+
wrap: compact ? "truncate" : void 0,
|
|
5405
|
+
children: renderReasoningLine(line)
|
|
5406
|
+
},
|
|
5407
|
+
`${index}:${line}`
|
|
5408
|
+
)),
|
|
5409
|
+
!collapsed && live && /* @__PURE__ */ jsx18(Text16, { color: REASONING_TEXT_COLOR, wrap: compact ? "truncate" : void 0, children: "| ..." })
|
|
5410
|
+
] });
|
|
5411
|
+
}
|
|
5188
5412
|
|
|
5189
5413
|
// src/ink/marathon/ToolEntry.tsx
|
|
5190
|
-
import { Box as
|
|
5191
|
-
import { Spinner as Spinner6, theme as
|
|
5192
|
-
import { Fragment, jsx as
|
|
5414
|
+
import { Box as Box17, Text as Text17 } from "ink";
|
|
5415
|
+
import { Spinner as Spinner6, theme as theme17 } from "@runtypelabs/ink-components";
|
|
5416
|
+
import { Fragment, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
5193
5417
|
function ToolEntry({ tool, now }) {
|
|
5194
5418
|
const elapsedLive = ((now - tool.startedAt) / 1e3).toFixed(1);
|
|
5195
5419
|
const elapsedFinal = tool.executionTime != null ? (tool.executionTime / 1e3).toFixed(1) : ((now - tool.startedAt) / 1e3).toFixed(1);
|
|
5196
5420
|
const paramsPreview = tool.parameters ? JSON.stringify(tool.parameters).slice(0, 60) : null;
|
|
5197
5421
|
const resultPreview = tool.result != null ? String(typeof tool.result === "object" ? JSON.stringify(tool.result) : tool.result).slice(0, 80) : null;
|
|
5198
|
-
return /* @__PURE__ */
|
|
5199
|
-
/* @__PURE__ */
|
|
5200
|
-
tool.status === "running" && /* @__PURE__ */
|
|
5201
|
-
/* @__PURE__ */
|
|
5202
|
-
/* @__PURE__ */
|
|
5203
|
-
" ",
|
|
5422
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", marginBottom: 1, children: [
|
|
5423
|
+
/* @__PURE__ */ jsxs17(Box17, { children: [
|
|
5424
|
+
tool.status === "running" && /* @__PURE__ */ jsxs17(Fragment, { children: [
|
|
5425
|
+
/* @__PURE__ */ jsx19(Spinner6, { label: "", color: theme17.spinner }),
|
|
5426
|
+
/* @__PURE__ */ jsxs17(Text17, { bold: true, children: [
|
|
5427
|
+
" [",
|
|
5428
|
+
tool.sequence,
|
|
5429
|
+
"] ",
|
|
5204
5430
|
tool.name
|
|
5205
5431
|
] }),
|
|
5206
|
-
/* @__PURE__ */
|
|
5432
|
+
/* @__PURE__ */ jsxs17(Text17, { color: theme17.muted, children: [
|
|
5207
5433
|
" ",
|
|
5208
5434
|
elapsedLive,
|
|
5209
5435
|
"s"
|
|
5210
5436
|
] })
|
|
5211
5437
|
] }),
|
|
5212
|
-
tool.status === "complete" && /* @__PURE__ */
|
|
5213
|
-
/* @__PURE__ */
|
|
5214
|
-
/* @__PURE__ */
|
|
5215
|
-
" ",
|
|
5438
|
+
tool.status === "complete" && /* @__PURE__ */ jsxs17(Fragment, { children: [
|
|
5439
|
+
/* @__PURE__ */ jsx19(Text17, { color: theme17.success, children: "\u2713" }),
|
|
5440
|
+
/* @__PURE__ */ jsxs17(Text17, { bold: true, children: [
|
|
5441
|
+
" [",
|
|
5442
|
+
tool.sequence,
|
|
5443
|
+
"] ",
|
|
5216
5444
|
tool.name
|
|
5217
5445
|
] }),
|
|
5218
|
-
/* @__PURE__ */
|
|
5446
|
+
/* @__PURE__ */ jsxs17(Text17, { color: theme17.muted, children: [
|
|
5219
5447
|
" ",
|
|
5220
5448
|
elapsedFinal,
|
|
5221
5449
|
"s"
|
|
5222
5450
|
] })
|
|
5223
5451
|
] }),
|
|
5224
|
-
tool.status === "error" && /* @__PURE__ */
|
|
5225
|
-
/* @__PURE__ */
|
|
5226
|
-
/* @__PURE__ */
|
|
5227
|
-
" ",
|
|
5452
|
+
tool.status === "error" && /* @__PURE__ */ jsxs17(Fragment, { children: [
|
|
5453
|
+
/* @__PURE__ */ jsx19(Text17, { color: theme17.error, children: "\u2717" }),
|
|
5454
|
+
/* @__PURE__ */ jsxs17(Text17, { bold: true, children: [
|
|
5455
|
+
" [",
|
|
5456
|
+
tool.sequence,
|
|
5457
|
+
"] ",
|
|
5228
5458
|
tool.name
|
|
5229
5459
|
] })
|
|
5230
5460
|
] })
|
|
5231
5461
|
] }),
|
|
5232
|
-
paramsPreview && /* @__PURE__ */
|
|
5462
|
+
paramsPreview && /* @__PURE__ */ jsxs17(Text17, { color: theme17.dimLabel, wrap: "truncate", children: [
|
|
5233
5463
|
" ",
|
|
5234
5464
|
paramsPreview
|
|
5235
5465
|
] }),
|
|
5236
|
-
tool.status === "complete" && resultPreview && /* @__PURE__ */
|
|
5466
|
+
tool.status === "complete" && resultPreview && /* @__PURE__ */ jsxs17(Text17, { color: theme17.dimLabel, wrap: "truncate", children: [
|
|
5237
5467
|
" ",
|
|
5238
5468
|
resultPreview
|
|
5239
5469
|
] })
|
|
@@ -5241,11 +5471,16 @@ function ToolEntry({ tool, now }) {
|
|
|
5241
5471
|
}
|
|
5242
5472
|
|
|
5243
5473
|
// src/ink/marathon/ToolPanel.tsx
|
|
5244
|
-
import { jsx as
|
|
5474
|
+
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
5245
5475
|
var ROWS_PER_TOOL = 3;
|
|
5246
|
-
|
|
5476
|
+
var REASONING_PREVIEW_LINES = 4;
|
|
5477
|
+
function ToolPanel({ tools, reasoning, maxHeight }) {
|
|
5247
5478
|
const [now, setNow] = useState16(Date.now());
|
|
5248
5479
|
const hasRunning = tools.some((t) => t.status === "running");
|
|
5480
|
+
const reasoningLines = useMemo3(
|
|
5481
|
+
() => getVisibleReasoningLines(reasoning || "", REASONING_PREVIEW_LINES),
|
|
5482
|
+
[reasoning]
|
|
5483
|
+
);
|
|
5249
5484
|
useEffect14(() => {
|
|
5250
5485
|
if (!hasRunning) return;
|
|
5251
5486
|
const interval = setInterval(() => {
|
|
@@ -5255,39 +5490,41 @@ function ToolPanel({ tools, maxHeight }) {
|
|
|
5255
5490
|
}, [hasRunning]);
|
|
5256
5491
|
const visibleTools = useMemo3(() => {
|
|
5257
5492
|
if (!maxHeight) return tools;
|
|
5258
|
-
const
|
|
5493
|
+
const reasoningRows = reasoningLines.length > 0 ? 1 + reasoningLines.length + 1 : 0;
|
|
5494
|
+
const availableRows = maxHeight - 1 - reasoningRows;
|
|
5259
5495
|
const maxTools = Math.max(1, Math.floor(availableRows / ROWS_PER_TOOL));
|
|
5260
5496
|
if (tools.length <= maxTools) return tools;
|
|
5261
5497
|
return tools.slice(-maxTools);
|
|
5262
|
-
}, [tools, maxHeight]);
|
|
5498
|
+
}, [tools, maxHeight, reasoningLines]);
|
|
5263
5499
|
const hiddenCount = tools.length - visibleTools.length;
|
|
5264
|
-
return /* @__PURE__ */
|
|
5265
|
-
/* @__PURE__ */
|
|
5266
|
-
|
|
5500
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
5501
|
+
reasoningLines.length > 0 && /* @__PURE__ */ jsx20(Box18, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx20(ReasoningBlock, { lines: reasoningLines, compact: true }) }),
|
|
5502
|
+
/* @__PURE__ */ jsx20(Text18, { bold: true, color: theme18.info, children: "Tools" }),
|
|
5503
|
+
hiddenCount > 0 && /* @__PURE__ */ jsxs18(Text18, { color: theme18.muted, dimColor: true, children: [
|
|
5267
5504
|
" ",
|
|
5268
5505
|
hiddenCount,
|
|
5269
5506
|
" earlier tools hidden"
|
|
5270
5507
|
] }),
|
|
5271
|
-
visibleTools.map((tool) => /* @__PURE__ */
|
|
5508
|
+
visibleTools.map((tool) => /* @__PURE__ */ jsx20(ToolEntry, { tool, now }, tool.id))
|
|
5272
5509
|
] });
|
|
5273
5510
|
}
|
|
5274
5511
|
|
|
5275
5512
|
// src/ink/marathon/EventStreamPanel.tsx
|
|
5276
5513
|
import { useMemo as useMemo4 } from "react";
|
|
5277
|
-
import { Box as
|
|
5278
|
-
import { theme as
|
|
5279
|
-
import { jsx as
|
|
5514
|
+
import { Box as Box19, Text as Text19 } from "ink";
|
|
5515
|
+
import { theme as theme19 } from "@runtypelabs/ink-components";
|
|
5516
|
+
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
5280
5517
|
var EVENT_COLORS = {
|
|
5281
|
-
agent_start:
|
|
5282
|
-
agent_complete:
|
|
5283
|
-
agent_error:
|
|
5284
|
-
agent_await:
|
|
5285
|
-
agent_iteration_start:
|
|
5286
|
-
agent_iteration_complete:
|
|
5287
|
-
agent_turn_delta:
|
|
5288
|
-
agent_turn_complete:
|
|
5289
|
-
agent_tool_start:
|
|
5290
|
-
agent_tool_complete:
|
|
5518
|
+
agent_start: theme19.success,
|
|
5519
|
+
agent_complete: theme19.success,
|
|
5520
|
+
agent_error: theme19.error,
|
|
5521
|
+
agent_await: theme19.warning,
|
|
5522
|
+
agent_iteration_start: theme19.info,
|
|
5523
|
+
agent_iteration_complete: theme19.info,
|
|
5524
|
+
agent_turn_delta: theme19.muted,
|
|
5525
|
+
agent_turn_complete: theme19.primary,
|
|
5526
|
+
agent_tool_start: theme19.warning,
|
|
5527
|
+
agent_tool_complete: theme19.warning
|
|
5291
5528
|
};
|
|
5292
5529
|
function formatTimestamp(ts, start) {
|
|
5293
5530
|
if (!start) return "0.000s";
|
|
@@ -5317,21 +5554,21 @@ function EventDetailView({
|
|
|
5317
5554
|
return { lines: allLines.slice(start, end), totalLines: total };
|
|
5318
5555
|
}, [event, maxVisibleLines, scrollOffset]);
|
|
5319
5556
|
const color = EVENT_COLORS[event.type] || "white";
|
|
5320
|
-
return /* @__PURE__ */
|
|
5321
|
-
/* @__PURE__ */
|
|
5322
|
-
/* @__PURE__ */
|
|
5557
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", paddingX: 1, children: [
|
|
5558
|
+
/* @__PURE__ */ jsxs19(Box19, { marginBottom: 1, children: [
|
|
5559
|
+
/* @__PURE__ */ jsxs19(Text19, { color: theme19.muted, children: [
|
|
5323
5560
|
formatTimestamp(event.timestamp, startTime),
|
|
5324
5561
|
" "
|
|
5325
5562
|
] }),
|
|
5326
|
-
/* @__PURE__ */
|
|
5327
|
-
/* @__PURE__ */
|
|
5328
|
-
totalLines > maxVisibleLines && /* @__PURE__ */
|
|
5563
|
+
/* @__PURE__ */ jsx21(Text19, { bold: true, color, children: event.type }),
|
|
5564
|
+
/* @__PURE__ */ jsx21(Text19, { color: theme19.muted, children: " \u2014 Esc to close" }),
|
|
5565
|
+
totalLines > maxVisibleLines && /* @__PURE__ */ jsxs19(Text19, { color: theme19.muted, children: [
|
|
5329
5566
|
" (",
|
|
5330
5567
|
totalLines,
|
|
5331
5568
|
" lines)"
|
|
5332
5569
|
] })
|
|
5333
5570
|
] }),
|
|
5334
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
5571
|
+
lines.map((line, i) => /* @__PURE__ */ jsx21(Text19, { color: theme19.label, children: line }, i))
|
|
5335
5572
|
] });
|
|
5336
5573
|
}
|
|
5337
5574
|
function EventStreamPanel({
|
|
@@ -5343,7 +5580,7 @@ function EventStreamPanel({
|
|
|
5343
5580
|
detailScrollOffset = 0
|
|
5344
5581
|
}) {
|
|
5345
5582
|
if (detailEvent) {
|
|
5346
|
-
return /* @__PURE__ */
|
|
5583
|
+
return /* @__PURE__ */ jsx21(
|
|
5347
5584
|
EventDetailView,
|
|
5348
5585
|
{
|
|
5349
5586
|
event: detailEvent,
|
|
@@ -5382,22 +5619,22 @@ function EventStreamPanel({
|
|
|
5382
5619
|
};
|
|
5383
5620
|
}, [events, startTime, maxVisibleLines, selectedIndex]);
|
|
5384
5621
|
if (events.length === 0) {
|
|
5385
|
-
return /* @__PURE__ */
|
|
5622
|
+
return /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx21(Text19, { color: theme19.muted, children: "Waiting for events..." }) });
|
|
5386
5623
|
}
|
|
5387
|
-
return /* @__PURE__ */
|
|
5388
|
-
/* @__PURE__ */
|
|
5389
|
-
/* @__PURE__ */
|
|
5390
|
-
/* @__PURE__ */
|
|
5624
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", paddingX: 1, children: [
|
|
5625
|
+
/* @__PURE__ */ jsxs19(Box19, { marginBottom: 0, children: [
|
|
5626
|
+
/* @__PURE__ */ jsx21(Text19, { bold: true, color: theme19.info, children: "Event Stream" }),
|
|
5627
|
+
/* @__PURE__ */ jsxs19(Text19, { color: theme19.muted, children: [
|
|
5391
5628
|
" (",
|
|
5392
5629
|
events.length,
|
|
5393
5630
|
" events)"
|
|
5394
5631
|
] }),
|
|
5395
|
-
hiddenAbove > 0 && /* @__PURE__ */
|
|
5632
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs19(Text19, { color: theme19.muted, children: [
|
|
5396
5633
|
" [",
|
|
5397
5634
|
hiddenAbove,
|
|
5398
5635
|
" above]"
|
|
5399
5636
|
] }),
|
|
5400
|
-
hiddenBelow > 0 && /* @__PURE__ */
|
|
5637
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs19(Text19, { color: theme19.muted, children: [
|
|
5401
5638
|
" [",
|
|
5402
5639
|
hiddenBelow,
|
|
5403
5640
|
" below]"
|
|
@@ -5405,11 +5642,11 @@ function EventStreamPanel({
|
|
|
5405
5642
|
] }),
|
|
5406
5643
|
rows.map((row) => {
|
|
5407
5644
|
const isSelected = row.globalIndex === selectedIndex;
|
|
5408
|
-
return /* @__PURE__ */
|
|
5409
|
-
/* @__PURE__ */
|
|
5410
|
-
/* @__PURE__ */
|
|
5411
|
-
/* @__PURE__ */
|
|
5412
|
-
/* @__PURE__ */
|
|
5645
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "row", flexWrap: "nowrap", children: [
|
|
5646
|
+
/* @__PURE__ */ jsx21(Box19, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx21(Text19, { color: theme19.info, children: isSelected ? ">" : " " }) }),
|
|
5647
|
+
/* @__PURE__ */ jsx21(Box19, { width: 9, flexShrink: 0, children: /* @__PURE__ */ jsx21(Text19, { color: theme19.muted, inverse: isSelected, children: row.time }) }),
|
|
5648
|
+
/* @__PURE__ */ jsx21(Box19, { width: 28, flexShrink: 0, children: /* @__PURE__ */ jsx21(Text19, { color: row.color, bold: true, inverse: isSelected, children: row.type }) }),
|
|
5649
|
+
/* @__PURE__ */ jsx21(Box19, { flexShrink: 1, children: /* @__PURE__ */ jsx21(Text19, { color: theme19.muted, wrap: "truncate", inverse: isSelected, children: row.data }) })
|
|
5413
5650
|
] }, row.key);
|
|
5414
5651
|
})
|
|
5415
5652
|
] });
|
|
@@ -5417,14 +5654,14 @@ function EventStreamPanel({
|
|
|
5417
5654
|
|
|
5418
5655
|
// src/ink/marathon/SteeringPrompt.tsx
|
|
5419
5656
|
import { useState as useState17, useEffect as useEffect15, useRef as useRef6 } from "react";
|
|
5420
|
-
import { Box as
|
|
5657
|
+
import { Box as Box21, Text as Text21 } from "ink";
|
|
5421
5658
|
import TextInput3 from "ink-text-input";
|
|
5422
|
-
import { theme as
|
|
5659
|
+
import { theme as theme21 } from "@runtypelabs/ink-components";
|
|
5423
5660
|
|
|
5424
5661
|
// src/ink/marathon/SteeringRecap.tsx
|
|
5425
|
-
import { Box as
|
|
5426
|
-
import { theme as
|
|
5427
|
-
import { jsx as
|
|
5662
|
+
import { Box as Box20, Text as Text20 } from "ink";
|
|
5663
|
+
import { theme as theme20 } from "@runtypelabs/ink-components";
|
|
5664
|
+
import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
5428
5665
|
function SteeringRecap({
|
|
5429
5666
|
sessionNumber,
|
|
5430
5667
|
toolCallsMade,
|
|
@@ -5434,9 +5671,9 @@ function SteeringRecap({
|
|
|
5434
5671
|
isTerminal
|
|
5435
5672
|
}) {
|
|
5436
5673
|
const label = isTerminal ? `\u2713 Session ${sessionNumber} complete` : `Session ${sessionNumber} complete`;
|
|
5437
|
-
return /* @__PURE__ */
|
|
5438
|
-
/* @__PURE__ */
|
|
5439
|
-
/* @__PURE__ */
|
|
5674
|
+
return /* @__PURE__ */ jsxs20(Box20, { borderStyle: "single", borderColor: theme20.muted, flexDirection: "column", paddingX: 1, children: [
|
|
5675
|
+
/* @__PURE__ */ jsx22(Text20, { color: theme20.label, children: label }),
|
|
5676
|
+
/* @__PURE__ */ jsxs20(Text20, { color: theme20.muted, children: [
|
|
5440
5677
|
"Tools: ",
|
|
5441
5678
|
toolCallsMade,
|
|
5442
5679
|
" | Tokens: ",
|
|
@@ -5463,7 +5700,7 @@ var MARATHON_STEER_COMMANDS = [
|
|
|
5463
5700
|
];
|
|
5464
5701
|
|
|
5465
5702
|
// src/ink/marathon/SteeringPrompt.tsx
|
|
5466
|
-
import { Fragment as Fragment2, jsx as
|
|
5703
|
+
import { Fragment as Fragment2, jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
5467
5704
|
function SteeringPrompt({
|
|
5468
5705
|
onSubmit,
|
|
5469
5706
|
timeout,
|
|
@@ -5558,19 +5795,19 @@ function SteeringPrompt({
|
|
|
5558
5795
|
if (isTyping) return "(paused)";
|
|
5559
5796
|
return `(${remaining}s)`;
|
|
5560
5797
|
})();
|
|
5561
|
-
return /* @__PURE__ */
|
|
5562
|
-
/* @__PURE__ */
|
|
5563
|
-
showModelPicker ? /* @__PURE__ */
|
|
5798
|
+
return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", flexShrink: 0, children: [
|
|
5799
|
+
/* @__PURE__ */ jsx23(SteeringRecap, { ...recap, isTerminal }),
|
|
5800
|
+
showModelPicker ? /* @__PURE__ */ jsx23(
|
|
5564
5801
|
ModelPicker,
|
|
5565
5802
|
{
|
|
5566
5803
|
currentModel,
|
|
5567
5804
|
onSelect: handleModelSelect,
|
|
5568
5805
|
onCancel: handleModelCancel
|
|
5569
5806
|
}
|
|
5570
|
-
) : /* @__PURE__ */
|
|
5571
|
-
/* @__PURE__ */
|
|
5572
|
-
/* @__PURE__ */
|
|
5573
|
-
/* @__PURE__ */
|
|
5807
|
+
) : /* @__PURE__ */ jsxs21(Fragment2, { children: [
|
|
5808
|
+
/* @__PURE__ */ jsxs21(Box21, { children: [
|
|
5809
|
+
/* @__PURE__ */ jsx23(Text21, { color: theme21.muted, children: "> " }),
|
|
5810
|
+
/* @__PURE__ */ jsx23(Box21, { flexGrow: 1, children: /* @__PURE__ */ jsx23(
|
|
5574
5811
|
TextInput3,
|
|
5575
5812
|
{
|
|
5576
5813
|
value,
|
|
@@ -5579,16 +5816,16 @@ function SteeringPrompt({
|
|
|
5579
5816
|
placeholder: isTerminal ? "Send new instructions to continue marathon, or press enter to exit..." : "Steer next iteration..."
|
|
5580
5817
|
}
|
|
5581
5818
|
) }),
|
|
5582
|
-
countdownText && /* @__PURE__ */
|
|
5819
|
+
countdownText && /* @__PURE__ */ jsxs21(Text21, { dimColor: true, children: [
|
|
5583
5820
|
" ",
|
|
5584
5821
|
countdownText
|
|
5585
5822
|
] })
|
|
5586
5823
|
] }),
|
|
5587
|
-
/* @__PURE__ */
|
|
5824
|
+
/* @__PURE__ */ jsxs21(Text21, { dimColor: true, children: [
|
|
5588
5825
|
isTerminal ? isTyping ? "Enter: send" : "Enter: exit" : "Enter: continue",
|
|
5589
5826
|
" | /model /tools /sandbox /stop /help"
|
|
5590
5827
|
] }),
|
|
5591
|
-
showHelp && /* @__PURE__ */
|
|
5828
|
+
showHelp && /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", marginTop: 1, children: MARATHON_STEER_COMMANDS.map((cmd) => /* @__PURE__ */ jsxs21(Text21, { dimColor: true, children: [
|
|
5592
5829
|
cmd.name.padEnd(12),
|
|
5593
5830
|
" ",
|
|
5594
5831
|
cmd.description
|
|
@@ -5597,16 +5834,249 @@ function SteeringPrompt({
|
|
|
5597
5834
|
] });
|
|
5598
5835
|
}
|
|
5599
5836
|
|
|
5837
|
+
// src/ink/marathon/UpgradeModal.tsx
|
|
5838
|
+
import { Box as Box22, Text as Text22 } from "ink";
|
|
5839
|
+
import { theme as theme22 } from "@runtypelabs/ink-components";
|
|
5840
|
+
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5841
|
+
function UpgradeModal({ prompt, width }) {
|
|
5842
|
+
return /* @__PURE__ */ jsxs22(
|
|
5843
|
+
Box22,
|
|
5844
|
+
{
|
|
5845
|
+
width,
|
|
5846
|
+
flexDirection: "column",
|
|
5847
|
+
borderStyle: "round",
|
|
5848
|
+
borderColor: theme22.warning,
|
|
5849
|
+
paddingX: 2,
|
|
5850
|
+
paddingY: 1,
|
|
5851
|
+
children: [
|
|
5852
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.warning, bold: true, children: "Upgrade available" }),
|
|
5853
|
+
/* @__PURE__ */ jsx24(Box22, { marginTop: 1, children: /* @__PURE__ */ jsx24(Text22, { color: theme22.label, children: prompt.message }) }),
|
|
5854
|
+
(prompt.code || prompt.limitType || prompt.retryAfter) && /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", marginTop: 1, children: [
|
|
5855
|
+
prompt.code && /* @__PURE__ */ jsxs22(Text22, { color: theme22.muted, children: [
|
|
5856
|
+
"Code: ",
|
|
5857
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.label, children: prompt.code })
|
|
5858
|
+
] }),
|
|
5859
|
+
prompt.limitType && /* @__PURE__ */ jsxs22(Text22, { color: theme22.muted, children: [
|
|
5860
|
+
"Limit: ",
|
|
5861
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.label, children: prompt.limitType })
|
|
5862
|
+
] }),
|
|
5863
|
+
prompt.retryAfter && /* @__PURE__ */ jsxs22(Text22, { color: theme22.muted, children: [
|
|
5864
|
+
"Retry after: ",
|
|
5865
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.label, children: prompt.retryAfter })
|
|
5866
|
+
] })
|
|
5867
|
+
] }),
|
|
5868
|
+
/* @__PURE__ */ jsxs22(Box22, { marginTop: 1, children: [
|
|
5869
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.info, children: "Enter" }),
|
|
5870
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.muted, children: " open billing " }),
|
|
5871
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.info, children: "Esc" }),
|
|
5872
|
+
/* @__PURE__ */ jsx24(Text22, { color: theme22.muted, children: " close" })
|
|
5873
|
+
] }),
|
|
5874
|
+
/* @__PURE__ */ jsx24(Box22, { marginTop: 1, children: /* @__PURE__ */ jsx24(Text22, { color: theme22.dimLabel, children: "Opens your dashboard billing page" }) })
|
|
5875
|
+
]
|
|
5876
|
+
}
|
|
5877
|
+
);
|
|
5878
|
+
}
|
|
5879
|
+
|
|
5880
|
+
// src/ink/marathon/upgrade-modal-utils.ts
|
|
5881
|
+
var UPGRADE_LIMIT_TYPES = /* @__PURE__ */ new Set([
|
|
5882
|
+
"slow_mode_hourly",
|
|
5883
|
+
"daily_limit",
|
|
5884
|
+
"monthly_limit",
|
|
5885
|
+
"spend_limit"
|
|
5886
|
+
]);
|
|
5887
|
+
var UPGRADE_CODES = /* @__PURE__ */ new Set([
|
|
5888
|
+
"SLOW_MODE_HOURLY_LIMIT_EXCEEDED",
|
|
5889
|
+
"DAILY_EXECUTION_LIMIT_EXCEEDED",
|
|
5890
|
+
"MONTHLY_EXECUTION_LIMIT_EXCEEDED",
|
|
5891
|
+
"SPEND_LIMIT_EXCEEDED"
|
|
5892
|
+
]);
|
|
5893
|
+
function trimPrefixedLine(line, prefix) {
|
|
5894
|
+
return line.startsWith(prefix) ? line.slice(prefix.length).trim() : void 0;
|
|
5895
|
+
}
|
|
5896
|
+
function parseMarathonUpgradePrompt(error) {
|
|
5897
|
+
const rawMessage = typeof error === "string" ? error : error instanceof Error ? error.message : "";
|
|
5898
|
+
if (!rawMessage.trim()) return void 0;
|
|
5899
|
+
const lines = rawMessage.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
5900
|
+
const messageLine = lines.find((line) => line.startsWith("Task failed: "));
|
|
5901
|
+
const statusLine = lines.find((line) => line.includes("429"));
|
|
5902
|
+
const code = lines.map((line) => trimPrefixedLine(line, "Code: ")).find((value) => Boolean(value));
|
|
5903
|
+
const limitType = lines.map((line) => trimPrefixedLine(line, "Limit type: ")).find((value) => Boolean(value));
|
|
5904
|
+
const retryAfter = lines.map((line) => trimPrefixedLine(line, "Retry after: ")).find((value) => Boolean(value));
|
|
5905
|
+
const message = messageLine?.replace(/^Task failed:\s*/, "").trim() ?? rawMessage.trim();
|
|
5906
|
+
const isUpgradeEligible = message.toLowerCase().includes("upgrade") || (code ? UPGRADE_CODES.has(code) : false) || (limitType ? UPGRADE_LIMIT_TYPES.has(limitType) : false);
|
|
5907
|
+
if (!statusLine || !isUpgradeEligible) {
|
|
5908
|
+
return void 0;
|
|
5909
|
+
}
|
|
5910
|
+
return {
|
|
5911
|
+
message,
|
|
5912
|
+
...code ? { code } : {},
|
|
5913
|
+
...limitType ? { limitType } : {},
|
|
5914
|
+
...retryAfter ? { retryAfter } : {}
|
|
5915
|
+
};
|
|
5916
|
+
}
|
|
5917
|
+
|
|
5918
|
+
// src/ink/marathon/session-tabs-utils.ts
|
|
5919
|
+
var MAX_VISIBLE_TAB_SHORTCUTS = 9;
|
|
5920
|
+
var TAB_PADDING = 4;
|
|
5921
|
+
var TAB_SEPARATOR_WIDTH = 1;
|
|
5922
|
+
var TAB_OVERFLOW_WIDTH = 2;
|
|
5923
|
+
function createSessionTabKey(sessionIndex, status = "snapshot") {
|
|
5924
|
+
return `${status}:${sessionIndex}`;
|
|
5925
|
+
}
|
|
5926
|
+
function getLatestSessionTabKey(sessionSnapshots, liveSnapshot) {
|
|
5927
|
+
if (liveSnapshot) return createSessionTabKey(liveSnapshot.sessionIndex, "live");
|
|
5928
|
+
const latestSnapshot = sessionSnapshots[sessionSnapshots.length - 1];
|
|
5929
|
+
return latestSnapshot ? createSessionTabKey(latestSnapshot.sessionIndex) : void 0;
|
|
5930
|
+
}
|
|
5931
|
+
function getSessionTabBaseTitle(snapshot) {
|
|
5932
|
+
return `Run ${snapshot.sessionIndex}${snapshot.status === "live" ? "*" : ""}`;
|
|
5933
|
+
}
|
|
5934
|
+
function estimateRenderedTabWidth(tab) {
|
|
5935
|
+
const shortcutPrefix = tab.shortcut != null ? `${tab.shortcut} ` : "";
|
|
5936
|
+
const unreadPrefix = tab.isUnread ? "\u2022 " : "";
|
|
5937
|
+
return shortcutPrefix.length + unreadPrefix.length + tab.title.length + TAB_PADDING;
|
|
5938
|
+
}
|
|
5939
|
+
function estimateWindowWidth(tabs, hiddenLeft, hiddenRight) {
|
|
5940
|
+
if (tabs.length === 0) return 0;
|
|
5941
|
+
const overflowWidth = (hiddenLeft > 0 ? TAB_OVERFLOW_WIDTH : 0) + (hiddenRight > 0 ? TAB_OVERFLOW_WIDTH : 0);
|
|
5942
|
+
return tabs.reduce((total, tab) => total + estimateRenderedTabWidth(tab), 0) + Math.max(0, tabs.length - 1) * TAB_SEPARATOR_WIDTH + overflowWidth;
|
|
5943
|
+
}
|
|
5944
|
+
function buildSessionTabs(sessionSnapshots, selectedKey, latestUnreadKey, liveSnapshot) {
|
|
5945
|
+
const orderedSnapshots = [...sessionSnapshots].sort((left, right) => left.sessionIndex - right.sessionIndex);
|
|
5946
|
+
const tabs = orderedSnapshots.map((snapshot) => {
|
|
5947
|
+
const key = createSessionTabKey(snapshot.sessionIndex);
|
|
5948
|
+
return {
|
|
5949
|
+
key,
|
|
5950
|
+
sessionIndex: snapshot.sessionIndex,
|
|
5951
|
+
title: getSessionTabBaseTitle(snapshot),
|
|
5952
|
+
isLive: false,
|
|
5953
|
+
isUnread: key === latestUnreadKey,
|
|
5954
|
+
isSelected: key === selectedKey,
|
|
5955
|
+
shortcut: null
|
|
5956
|
+
};
|
|
5957
|
+
});
|
|
5958
|
+
if (liveSnapshot) {
|
|
5959
|
+
const liveKey = createSessionTabKey(liveSnapshot.sessionIndex, "live");
|
|
5960
|
+
tabs.push({
|
|
5961
|
+
key: liveKey,
|
|
5962
|
+
sessionIndex: liveSnapshot.sessionIndex,
|
|
5963
|
+
title: getSessionTabBaseTitle(liveSnapshot),
|
|
5964
|
+
isLive: true,
|
|
5965
|
+
isUnread: liveKey === latestUnreadKey,
|
|
5966
|
+
isSelected: liveKey === selectedKey,
|
|
5967
|
+
shortcut: null
|
|
5968
|
+
});
|
|
5969
|
+
}
|
|
5970
|
+
return tabs;
|
|
5971
|
+
}
|
|
5972
|
+
function getVisibleSessionTabs(tabs, selectedKey, maxWidth) {
|
|
5973
|
+
if (tabs.length === 0) {
|
|
5974
|
+
return { tabs: [], hiddenLeft: 0, hiddenRight: 0 };
|
|
5975
|
+
}
|
|
5976
|
+
const maxTabCount = Math.min(MAX_VISIBLE_TAB_SHORTCUTS, tabs.length);
|
|
5977
|
+
const selectedIndex = tabs.findIndex((tab) => tab.key === selectedKey);
|
|
5978
|
+
let start = Math.max(0, tabs.length - maxTabCount);
|
|
5979
|
+
let end = tabs.length;
|
|
5980
|
+
if (selectedIndex >= 0 && selectedIndex < start) {
|
|
5981
|
+
start = selectedIndex;
|
|
5982
|
+
end = Math.min(tabs.length, start + maxTabCount);
|
|
5983
|
+
} else if (selectedIndex >= end) {
|
|
5984
|
+
end = Math.min(tabs.length, selectedIndex + 1);
|
|
5985
|
+
start = Math.max(0, end - maxTabCount);
|
|
5986
|
+
}
|
|
5987
|
+
const shrinkWindowToFit = () => {
|
|
5988
|
+
while (end - start > 1) {
|
|
5989
|
+
const slice = tabs.slice(start, end);
|
|
5990
|
+
const hiddenLeft2 = start;
|
|
5991
|
+
const hiddenRight2 = tabs.length - end;
|
|
5992
|
+
if (estimateWindowWidth(slice, hiddenLeft2, hiddenRight2) <= maxWidth) break;
|
|
5993
|
+
const dropLeftDistance = selectedIndex - start;
|
|
5994
|
+
const dropRightDistance = end - 1 - selectedIndex;
|
|
5995
|
+
if (dropLeftDistance >= dropRightDistance && start < selectedIndex) {
|
|
5996
|
+
start += 1;
|
|
5997
|
+
} else if (end - 1 > selectedIndex) {
|
|
5998
|
+
end -= 1;
|
|
5999
|
+
} else {
|
|
6000
|
+
start += 1;
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
6004
|
+
shrinkWindowToFit();
|
|
6005
|
+
const hiddenLeft = start;
|
|
6006
|
+
const hiddenRight = tabs.length - end;
|
|
6007
|
+
const visibleTabs = tabs.slice(start, end).map((tab, index) => ({
|
|
6008
|
+
...tab,
|
|
6009
|
+
shortcut: index < MAX_VISIBLE_TAB_SHORTCUTS ? index + 1 : null
|
|
6010
|
+
}));
|
|
6011
|
+
return { tabs: visibleTabs, hiddenLeft, hiddenRight };
|
|
6012
|
+
}
|
|
6013
|
+
function getAdjacentSessionTabKey(tabs, selectedKey, direction) {
|
|
6014
|
+
if (tabs.length === 0) return void 0;
|
|
6015
|
+
const currentIndex = tabs.findIndex((tab) => tab.key === selectedKey);
|
|
6016
|
+
const fallbackIndex = direction > 0 ? tabs.length - 1 : 0;
|
|
6017
|
+
const nextIndex = currentIndex < 0 ? fallbackIndex : Math.max(0, Math.min(tabs.length - 1, currentIndex + direction));
|
|
6018
|
+
return tabs[nextIndex]?.key;
|
|
6019
|
+
}
|
|
6020
|
+
function getSessionTabKeyForShortcut(visibleTabs, input) {
|
|
6021
|
+
if (!/^[1-9]$/.test(input)) return void 0;
|
|
6022
|
+
const slot = Number(input);
|
|
6023
|
+
return visibleTabs.find((tab) => tab.shortcut === slot)?.key;
|
|
6024
|
+
}
|
|
6025
|
+
|
|
5600
6026
|
// src/ink/marathon/MarathonApp.tsx
|
|
5601
|
-
import { jsx as
|
|
5602
|
-
var TOOL_PANEL_WIDE =
|
|
5603
|
-
var TOOL_PANEL_NARROW =
|
|
6027
|
+
import { Fragment as Fragment3, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
6028
|
+
var TOOL_PANEL_WIDE = 48;
|
|
6029
|
+
var TOOL_PANEL_NARROW = 36;
|
|
5604
6030
|
var NARROW_THRESHOLD = 100;
|
|
5605
6031
|
var STACKED_THRESHOLD = 80;
|
|
5606
6032
|
var CHROME_ROWS_BASE = 6;
|
|
5607
6033
|
var GOAL_ROW = 1;
|
|
5608
6034
|
var SCROLL_STEP2 = 3;
|
|
5609
6035
|
var STEERING_PROMPT_ROWS = 7;
|
|
6036
|
+
var SESSION_TABS_ROWS = 1;
|
|
6037
|
+
function cloneSessionSnapshot(snapshot) {
|
|
6038
|
+
return {
|
|
6039
|
+
...snapshot,
|
|
6040
|
+
tools: snapshot.tools.map((tool) => ({
|
|
6041
|
+
...tool,
|
|
6042
|
+
...tool.parameters ? { parameters: structuredClone(tool.parameters) } : {},
|
|
6043
|
+
...tool.result !== void 0 ? { result: structuredClone(tool.result) } : {}
|
|
6044
|
+
})),
|
|
6045
|
+
rawEvents: snapshot.rawEvents.map((event) => ({
|
|
6046
|
+
...event,
|
|
6047
|
+
data: structuredClone(event.data)
|
|
6048
|
+
}))
|
|
6049
|
+
};
|
|
6050
|
+
}
|
|
6051
|
+
function upsertSessionSnapshots(snapshots, nextSnapshot) {
|
|
6052
|
+
const bySessionIndex = /* @__PURE__ */ new Map();
|
|
6053
|
+
for (const snapshot of snapshots) {
|
|
6054
|
+
bySessionIndex.set(snapshot.sessionIndex, cloneSessionSnapshot(snapshot));
|
|
6055
|
+
}
|
|
6056
|
+
bySessionIndex.set(nextSnapshot.sessionIndex, cloneSessionSnapshot(nextSnapshot));
|
|
6057
|
+
return Array.from(bySessionIndex.values()).sort((left, right) => left.sessionIndex - right.sessionIndex);
|
|
6058
|
+
}
|
|
6059
|
+
function buildLiveSessionSnapshot(liveState, sessionIndex, model) {
|
|
6060
|
+
const hasLiveState = Boolean(liveState.content) || Boolean(liveState.reasoning) || liveState.tools.length > 0 || liveState.rawEvents.length > 0;
|
|
6061
|
+
if (!hasLiveState) return void 0;
|
|
6062
|
+
return {
|
|
6063
|
+
sessionIndex,
|
|
6064
|
+
status: "live",
|
|
6065
|
+
model,
|
|
6066
|
+
cost: liveState.totalCost,
|
|
6067
|
+
content: liveState.content,
|
|
6068
|
+
reasoning: liveState.reasoning,
|
|
6069
|
+
tools: liveState.tools.map((tool) => ({
|
|
6070
|
+
...tool,
|
|
6071
|
+
...tool.parameters ? { parameters: structuredClone(tool.parameters) } : {},
|
|
6072
|
+
...tool.result !== void 0 ? { result: structuredClone(tool.result) } : {}
|
|
6073
|
+
})),
|
|
6074
|
+
rawEvents: liveState.rawEvents.map((event) => ({
|
|
6075
|
+
...event,
|
|
6076
|
+
data: structuredClone(event.data)
|
|
6077
|
+
}))
|
|
6078
|
+
};
|
|
6079
|
+
}
|
|
5610
6080
|
function copyToClipboard(text) {
|
|
5611
6081
|
try {
|
|
5612
6082
|
if (process.platform === "darwin") {
|
|
@@ -5633,16 +6103,18 @@ function MarathonApp({
|
|
|
5633
6103
|
goal,
|
|
5634
6104
|
initialSessionCount,
|
|
5635
6105
|
initialCost,
|
|
6106
|
+
initialSessionSnapshots,
|
|
5636
6107
|
debug: _debug,
|
|
5637
6108
|
plainText,
|
|
5638
6109
|
noSteer: _noSteer,
|
|
5639
6110
|
steeringTimeout,
|
|
5640
6111
|
dashboardUrl,
|
|
6112
|
+
billingUrl,
|
|
5641
6113
|
onSaveState,
|
|
5642
6114
|
onComplete: _onComplete,
|
|
5643
6115
|
streamRef
|
|
5644
6116
|
}) {
|
|
5645
|
-
const { state, callbacks, reset: _reset, setSteering, resetForNewSession } = useMarathonStream();
|
|
6117
|
+
const { state, callbacks, reset: _reset, setSteering, resetForNewSession, showError } = useMarathonStream();
|
|
5646
6118
|
const { exit } = useApp5();
|
|
5647
6119
|
const { stdout } = useStdout2();
|
|
5648
6120
|
const steeringResolveRef = useRef7(null);
|
|
@@ -5650,6 +6122,12 @@ function MarathonApp({
|
|
|
5650
6122
|
const [currentModel, setCurrentModel] = useState18(model || "default");
|
|
5651
6123
|
const [currentSandbox, setCurrentSandbox] = useState18(sandbox);
|
|
5652
6124
|
const [isTerminalSteering, setIsTerminalSteering] = useState18(false);
|
|
6125
|
+
const [sessionSnapshots, setSessionSnapshots] = useState18(
|
|
6126
|
+
() => (initialSessionSnapshots || []).map((snapshot) => cloneSessionSnapshot(snapshot))
|
|
6127
|
+
);
|
|
6128
|
+
const [selectedSessionKey, setSelectedSessionKey] = useState18(void 0);
|
|
6129
|
+
const [followLatest, setFollowLatest] = useState18(true);
|
|
6130
|
+
const [latestUnreadKey, setLatestUnreadKey] = useState18(void 0);
|
|
5653
6131
|
const isTerminalSteeringRef = useRef7(false);
|
|
5654
6132
|
const handleSteeringSubmit = useCallback5(
|
|
5655
6133
|
(result) => {
|
|
@@ -5680,6 +6158,19 @@ function MarathonApp({
|
|
|
5680
6158
|
streamRef.current = {
|
|
5681
6159
|
getCallbacks: () => callbacks,
|
|
5682
6160
|
getState: () => state,
|
|
6161
|
+
appendSessionSnapshot: (snapshot) => {
|
|
6162
|
+
setSessionSnapshots((prev) => upsertSessionSnapshots(prev, snapshot));
|
|
6163
|
+
const snapshotKey = createSessionTabKey(snapshot.sessionIndex);
|
|
6164
|
+
if (followLatest) {
|
|
6165
|
+
setSelectedSessionKey(snapshotKey);
|
|
6166
|
+
setLatestUnreadKey(void 0);
|
|
6167
|
+
} else {
|
|
6168
|
+
setLatestUnreadKey(snapshotKey);
|
|
6169
|
+
}
|
|
6170
|
+
},
|
|
6171
|
+
hydrateSessionSnapshots: (snapshots) => {
|
|
6172
|
+
setSessionSnapshots(snapshots.map((snapshot) => cloneSessionSnapshot(snapshot)));
|
|
6173
|
+
},
|
|
5683
6174
|
requestSteering: async (recap, isTerminal) => {
|
|
5684
6175
|
setSteering();
|
|
5685
6176
|
setSteeringRecap(recap);
|
|
@@ -5687,14 +6178,24 @@ function MarathonApp({
|
|
|
5687
6178
|
setIsTerminalSteering(true);
|
|
5688
6179
|
isTerminalSteeringRef.current = true;
|
|
5689
6180
|
}
|
|
5690
|
-
return new Promise((
|
|
5691
|
-
steeringResolveRef.current =
|
|
6181
|
+
return new Promise((resolve2) => {
|
|
6182
|
+
steeringResolveRef.current = resolve2;
|
|
5692
6183
|
});
|
|
5693
6184
|
},
|
|
5694
6185
|
resetForNewSession,
|
|
6186
|
+
showError,
|
|
5695
6187
|
exit: () => exit()
|
|
5696
6188
|
};
|
|
5697
|
-
}
|
|
6189
|
+
}, [
|
|
6190
|
+
callbacks,
|
|
6191
|
+
exit,
|
|
6192
|
+
followLatest,
|
|
6193
|
+
setSteering,
|
|
6194
|
+
showError,
|
|
6195
|
+
state,
|
|
6196
|
+
streamRef,
|
|
6197
|
+
resetForNewSession
|
|
6198
|
+
]);
|
|
5698
6199
|
const terminalWidth = stdout?.columns ?? 120;
|
|
5699
6200
|
const terminalRows = stdout?.rows ?? 40;
|
|
5700
6201
|
const chromeRows = CHROME_ROWS_BASE + (goal ? GOAL_ROW : 0);
|
|
@@ -5705,33 +6206,135 @@ function MarathonApp({
|
|
|
5705
6206
|
const ctrlCTimeout = useRef7(null);
|
|
5706
6207
|
const [showEventStream, setShowEventStream] = useState18(false);
|
|
5707
6208
|
const [scrollOffset, setScrollOffset] = useState18(0);
|
|
6209
|
+
const [reasoningCollapsed, setReasoningCollapsed] = useState18(false);
|
|
5708
6210
|
const [eventCursor, setEventCursor] = useState18(-1);
|
|
5709
6211
|
const [detailEvent, setDetailEvent] = useState18(null);
|
|
5710
6212
|
const [detailScrollOffset, setDetailScrollOffset] = useState18(0);
|
|
5711
6213
|
const [goalExpanded, setGoalExpanded] = useState18(false);
|
|
6214
|
+
const [upgradeModalDismissed, setUpgradeModalDismissed] = useState18(false);
|
|
5712
6215
|
const [clipboardFlash, setClipboardFlash] = useState18(null);
|
|
5713
6216
|
const flashTimeout = useRef7(null);
|
|
6217
|
+
const billingPageUrl = billingUrl || `${(dashboardUrl || "https://use.runtype.com").replace(/\/$/, "")}/settings/billing`;
|
|
5714
6218
|
function showFlash(msg) {
|
|
5715
6219
|
setClipboardFlash(msg);
|
|
5716
6220
|
if (flashTimeout.current) clearTimeout(flashTimeout.current);
|
|
5717
6221
|
flashTimeout.current = setTimeout(() => setClipboardFlash(null), 2e3);
|
|
5718
6222
|
}
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
6223
|
+
const latestCompletedSessionIndex = sessionSnapshots[sessionSnapshots.length - 1]?.sessionIndex ?? initialSessionCount;
|
|
6224
|
+
const shouldShowLiveTab = state.phase !== "idle" && state.phase !== "steering" && state.phase !== "complete" && (Boolean(state.content) || Boolean(state.reasoning) || state.tools.length > 0 || state.rawEvents.length > 0 || state.phase === "thinking" || state.phase === "error");
|
|
6225
|
+
const liveSessionSnapshot = useMemo5(
|
|
6226
|
+
() => shouldShowLiveTab ? buildLiveSessionSnapshot(state, latestCompletedSessionIndex + 1, currentModel) : void 0,
|
|
6227
|
+
[currentModel, latestCompletedSessionIndex, shouldShowLiveTab, state]
|
|
6228
|
+
);
|
|
6229
|
+
const liveSessionKey = liveSessionSnapshot ? createSessionTabKey(liveSessionSnapshot.sessionIndex, "live") : void 0;
|
|
6230
|
+
const latestSessionKey = getLatestSessionTabKey(sessionSnapshots, liveSessionSnapshot);
|
|
6231
|
+
const allTabs = useMemo5(
|
|
6232
|
+
() => buildSessionTabs(sessionSnapshots, selectedSessionKey, latestUnreadKey, liveSessionSnapshot),
|
|
6233
|
+
[latestUnreadKey, liveSessionSnapshot, selectedSessionKey, sessionSnapshots]
|
|
6234
|
+
);
|
|
6235
|
+
const visibleTabs = useMemo5(
|
|
6236
|
+
() => getVisibleSessionTabs(allTabs, selectedSessionKey, terminalWidth),
|
|
6237
|
+
[allTabs, selectedSessionKey, terminalWidth]
|
|
6238
|
+
);
|
|
6239
|
+
const displayedSessionSnapshot = useMemo5(() => {
|
|
6240
|
+
if (!selectedSessionKey) return liveSessionSnapshot ?? sessionSnapshots[sessionSnapshots.length - 1];
|
|
6241
|
+
if (selectedSessionKey === liveSessionKey) return liveSessionSnapshot;
|
|
6242
|
+
return sessionSnapshots.find(
|
|
6243
|
+
(snapshot) => createSessionTabKey(snapshot.sessionIndex) === selectedSessionKey
|
|
6244
|
+
);
|
|
6245
|
+
}, [liveSessionKey, liveSessionSnapshot, selectedSessionKey, sessionSnapshots]);
|
|
6246
|
+
const selectedIsLive = displayedSessionSnapshot?.status === "live";
|
|
6247
|
+
const displayedContent = displayedSessionSnapshot?.content ?? state.content;
|
|
6248
|
+
const displayedReasoning = displayedSessionSnapshot?.reasoning ?? state.reasoning;
|
|
6249
|
+
const displayedTools = displayedSessionSnapshot?.tools ?? state.tools;
|
|
6250
|
+
const displayedEvents = displayedSessionSnapshot?.rawEvents ?? state.rawEvents;
|
|
6251
|
+
const latestLiveActivityRef = useRef7(void 0);
|
|
6252
|
+
const upgradePrompt = useMemo5(() => parseMarathonUpgradePrompt(state.error), [state.error]);
|
|
6253
|
+
const upgradePromptKey = useMemo5(
|
|
6254
|
+
() => upgradePrompt ? `${upgradePrompt.message}|${upgradePrompt.code ?? ""}|${upgradePrompt.limitType ?? ""}|${upgradePrompt.retryAfter ?? ""}` : void 0,
|
|
6255
|
+
[upgradePrompt]
|
|
6256
|
+
);
|
|
6257
|
+
const showUpgradeModal = Boolean(upgradePrompt && !upgradeModalDismissed);
|
|
6258
|
+
const canBrowseAfterUpgradeError = Boolean(upgradePrompt && !showUpgradeModal);
|
|
6259
|
+
const selectSessionTab = useCallback5(
|
|
6260
|
+
(nextKey, manual = true) => {
|
|
6261
|
+
if (!nextKey) return;
|
|
6262
|
+
setSelectedSessionKey(nextKey);
|
|
6263
|
+
setDetailEvent(null);
|
|
5725
6264
|
setDetailScrollOffset(0);
|
|
6265
|
+
setScrollOffset(0);
|
|
6266
|
+
setEventCursor(-1);
|
|
6267
|
+
if (nextKey === latestSessionKey) {
|
|
6268
|
+
setFollowLatest(true);
|
|
6269
|
+
setLatestUnreadKey(void 0);
|
|
6270
|
+
} else if (manual) {
|
|
6271
|
+
setFollowLatest(false);
|
|
6272
|
+
}
|
|
6273
|
+
},
|
|
6274
|
+
[latestSessionKey]
|
|
6275
|
+
);
|
|
6276
|
+
useEffect16(() => {
|
|
6277
|
+
if (!selectedSessionKey && latestSessionKey) {
|
|
6278
|
+
setSelectedSessionKey(latestSessionKey);
|
|
5726
6279
|
}
|
|
5727
|
-
}
|
|
6280
|
+
}, [latestSessionKey, selectedSessionKey]);
|
|
6281
|
+
useEffect16(() => {
|
|
6282
|
+
if (followLatest && latestSessionKey && selectedSessionKey !== latestSessionKey) {
|
|
6283
|
+
setSelectedSessionKey(latestSessionKey);
|
|
6284
|
+
}
|
|
6285
|
+
}, [followLatest, latestSessionKey, selectedSessionKey]);
|
|
6286
|
+
useEffect16(() => {
|
|
6287
|
+
if (selectedSessionKey && selectedSessionKey === latestSessionKey && latestUnreadKey) {
|
|
6288
|
+
setLatestUnreadKey(void 0);
|
|
6289
|
+
}
|
|
6290
|
+
}, [latestSessionKey, latestUnreadKey, selectedSessionKey]);
|
|
6291
|
+
useEffect16(() => {
|
|
6292
|
+
setUpgradeModalDismissed(false);
|
|
6293
|
+
}, [upgradePromptKey]);
|
|
5728
6294
|
useEffect16(() => {
|
|
5729
|
-
|
|
5730
|
-
|
|
6295
|
+
const liveActivityKey = liveSessionSnapshot ? `${liveSessionSnapshot.sessionIndex}:${state.phase}:${state.content.length}:${state.reasoning.length}:${state.tools.length}:${state.rawEvents.length}` : void 0;
|
|
6296
|
+
if (!liveActivityKey) {
|
|
6297
|
+
latestLiveActivityRef.current = void 0;
|
|
6298
|
+
return;
|
|
5731
6299
|
}
|
|
5732
|
-
|
|
6300
|
+
if (latestLiveActivityRef.current && latestLiveActivityRef.current !== liveActivityKey && !followLatest && latestSessionKey) {
|
|
6301
|
+
setLatestUnreadKey(latestSessionKey);
|
|
6302
|
+
}
|
|
6303
|
+
latestLiveActivityRef.current = liveActivityKey;
|
|
6304
|
+
}, [
|
|
6305
|
+
followLatest,
|
|
6306
|
+
latestSessionKey,
|
|
6307
|
+
liveSessionSnapshot,
|
|
6308
|
+
state.content.length,
|
|
6309
|
+
state.phase,
|
|
6310
|
+
state.rawEvents.length,
|
|
6311
|
+
state.reasoning.length,
|
|
6312
|
+
state.tools.length
|
|
6313
|
+
]);
|
|
6314
|
+
useEffect16(() => {
|
|
6315
|
+
if (showEventStream && displayedEvents.length > 0 && eventCursor === -1) {
|
|
6316
|
+
setEventCursor(displayedEvents.length - 1);
|
|
6317
|
+
}
|
|
6318
|
+
}, [displayedEvents.length, eventCursor, showEventStream]);
|
|
6319
|
+
const navigateToEvent = useCallback5(
|
|
6320
|
+
(index) => {
|
|
6321
|
+
const clamped = Math.max(0, Math.min(displayedEvents.length - 1, index));
|
|
6322
|
+
const evt = displayedEvents[clamped];
|
|
6323
|
+
if (evt) {
|
|
6324
|
+
setEventCursor(clamped);
|
|
6325
|
+
setDetailEvent(evt);
|
|
6326
|
+
setDetailScrollOffset(0);
|
|
6327
|
+
}
|
|
6328
|
+
},
|
|
6329
|
+
[displayedEvents]
|
|
6330
|
+
);
|
|
5733
6331
|
const agentPageUrl = agentId && dashboardUrl ? `${dashboardUrl.replace(/\/$/, "")}/agents/${agentId}` : null;
|
|
5734
6332
|
useInput9((_input, key) => {
|
|
6333
|
+
if (_input === "u" && upgradePrompt) {
|
|
6334
|
+
void open3(billingPageUrl);
|
|
6335
|
+
setUpgradeModalDismissed(true);
|
|
6336
|
+
return;
|
|
6337
|
+
}
|
|
5735
6338
|
if (_input === "o" && agentPageUrl && !(state.phase === "steering" && steeringRecap)) {
|
|
5736
6339
|
void open3(agentPageUrl);
|
|
5737
6340
|
return;
|
|
@@ -5741,7 +6344,13 @@ function MarathonApp({
|
|
|
5741
6344
|
if (ctrlCTimeout.current) {
|
|
5742
6345
|
clearTimeout(ctrlCTimeout.current);
|
|
5743
6346
|
}
|
|
5744
|
-
onSaveState(
|
|
6347
|
+
onSaveState({
|
|
6348
|
+
content: state.content,
|
|
6349
|
+
reasoning: state.reasoning,
|
|
6350
|
+
tools: state.tools,
|
|
6351
|
+
rawEvents: state.rawEvents,
|
|
6352
|
+
sessionSnapshots
|
|
6353
|
+
});
|
|
5745
6354
|
exit();
|
|
5746
6355
|
} else {
|
|
5747
6356
|
setCtrlCPressed(true);
|
|
@@ -5751,9 +6360,26 @@ function MarathonApp({
|
|
|
5751
6360
|
}
|
|
5752
6361
|
return;
|
|
5753
6362
|
}
|
|
5754
|
-
if (
|
|
5755
|
-
if (key.
|
|
5756
|
-
|
|
6363
|
+
if (showUpgradeModal) {
|
|
6364
|
+
if (key.escape) {
|
|
6365
|
+
setUpgradeModalDismissed(true);
|
|
6366
|
+
return;
|
|
6367
|
+
}
|
|
6368
|
+
if (key.return) {
|
|
6369
|
+
void open3(billingPageUrl);
|
|
6370
|
+
setUpgradeModalDismissed(true);
|
|
6371
|
+
return;
|
|
6372
|
+
}
|
|
6373
|
+
}
|
|
6374
|
+
if (state.phase === "error" && !canBrowseAfterUpgradeError) {
|
|
6375
|
+
if (key.return || key.escape) {
|
|
6376
|
+
exit();
|
|
6377
|
+
}
|
|
6378
|
+
return;
|
|
6379
|
+
}
|
|
6380
|
+
if (state.phase === "steering" && steeringRecap) {
|
|
6381
|
+
if (key.upArrow) {
|
|
6382
|
+
setScrollOffset((prev) => prev + SCROLL_STEP2);
|
|
5757
6383
|
return;
|
|
5758
6384
|
}
|
|
5759
6385
|
if (key.downArrow) {
|
|
@@ -5762,6 +6388,23 @@ function MarathonApp({
|
|
|
5762
6388
|
}
|
|
5763
6389
|
return;
|
|
5764
6390
|
}
|
|
6391
|
+
if (key.shift && key.leftArrow) {
|
|
6392
|
+
selectSessionTab(getAdjacentSessionTabKey(allTabs, selectedSessionKey, -1));
|
|
6393
|
+
return;
|
|
6394
|
+
}
|
|
6395
|
+
if (key.shift && key.rightArrow) {
|
|
6396
|
+
selectSessionTab(getAdjacentSessionTabKey(allTabs, selectedSessionKey, 1));
|
|
6397
|
+
return;
|
|
6398
|
+
}
|
|
6399
|
+
if (_input === "0") {
|
|
6400
|
+
selectSessionTab(latestSessionKey);
|
|
6401
|
+
return;
|
|
6402
|
+
}
|
|
6403
|
+
const shortcutTabKey = getSessionTabKeyForShortcut(visibleTabs.tabs, _input);
|
|
6404
|
+
if (shortcutTabKey) {
|
|
6405
|
+
selectSessionTab(shortcutTabKey);
|
|
6406
|
+
return;
|
|
6407
|
+
}
|
|
5765
6408
|
if (key.tab) {
|
|
5766
6409
|
setShowEventStream((prev) => !prev);
|
|
5767
6410
|
setScrollOffset(0);
|
|
@@ -5782,8 +6425,12 @@ function MarathonApp({
|
|
|
5782
6425
|
setGoalExpanded((prev) => !prev);
|
|
5783
6426
|
return;
|
|
5784
6427
|
}
|
|
6428
|
+
if (_input === "r" && !showEventStream && !detailEvent && displayedReasoning.trim()) {
|
|
6429
|
+
setReasoningCollapsed((prev) => !prev);
|
|
6430
|
+
return;
|
|
6431
|
+
}
|
|
5785
6432
|
if (_input === "c" && showEventStream) {
|
|
5786
|
-
const evt = detailEvent ??
|
|
6433
|
+
const evt = detailEvent ?? displayedEvents[eventCursor];
|
|
5787
6434
|
if (evt) {
|
|
5788
6435
|
const json = JSON.stringify(evt.data, null, 2);
|
|
5789
6436
|
const ok = copyToClipboard(json);
|
|
@@ -5792,7 +6439,7 @@ function MarathonApp({
|
|
|
5792
6439
|
return;
|
|
5793
6440
|
}
|
|
5794
6441
|
if (key.return && showEventStream && !detailEvent) {
|
|
5795
|
-
const evt =
|
|
6442
|
+
const evt = displayedEvents[eventCursor];
|
|
5796
6443
|
if (evt) {
|
|
5797
6444
|
setDetailEvent(evt);
|
|
5798
6445
|
setDetailScrollOffset(0);
|
|
@@ -5818,7 +6465,7 @@ function MarathonApp({
|
|
|
5818
6465
|
if (showEventStream && detailEvent) {
|
|
5819
6466
|
setDetailScrollOffset((prev) => Math.max(0, prev - SCROLL_STEP2));
|
|
5820
6467
|
} else if (showEventStream) {
|
|
5821
|
-
setEventCursor((prev) => Math.min(
|
|
6468
|
+
setEventCursor((prev) => Math.min(displayedEvents.length - 1, prev + 1));
|
|
5822
6469
|
} else {
|
|
5823
6470
|
setScrollOffset((prev) => Math.max(0, prev - SCROLL_STEP2));
|
|
5824
6471
|
}
|
|
@@ -5839,28 +6486,58 @@ function MarathonApp({
|
|
|
5839
6486
|
if (flashTimeout.current) clearTimeout(flashTimeout.current);
|
|
5840
6487
|
};
|
|
5841
6488
|
}, []);
|
|
5842
|
-
const sessionCount =
|
|
6489
|
+
const sessionCount = liveSessionSnapshot?.sessionIndex ?? latestCompletedSessionIndex;
|
|
5843
6490
|
const totalCost = initialCost + state.totalCost;
|
|
5844
|
-
const
|
|
6491
|
+
const hasTabs = allTabs.length > 0;
|
|
6492
|
+
const hasTools = displayedTools.length > 0;
|
|
6493
|
+
const hasReasoning = Boolean(displayedReasoning.trim());
|
|
6494
|
+
const showThinkingIndicator = selectedIsLive && state.phase === "thinking" && !hasReasoning;
|
|
6495
|
+
const showLoadingAnimation = !displayedContent.trim() && !displayedReasoning.trim() && displayedTools.length === 0 && (state.phase === "idle" || state.phase === "thinking");
|
|
5845
6496
|
const statusRight = (() => {
|
|
5846
6497
|
if (ctrlCPressed) return "Press Ctrl+C again to exit";
|
|
5847
6498
|
if (clipboardFlash) return clipboardFlash;
|
|
6499
|
+
if (showUpgradeModal) return "u: upgrade | Enter: upgrade | Esc: close | Ctrl+C";
|
|
6500
|
+
if (state.phase === "error" && !canBrowseAfterUpgradeError) return "Enter: exit | Ctrl+C";
|
|
5848
6501
|
if (state.phase === "steering" && steeringRecap) {
|
|
5849
6502
|
const scrollHint2 = scrollOffset > 0 ? ` | +${scrollOffset}` : "";
|
|
5850
6503
|
return `\u2191\u2193: scroll | Ctrl+C${scrollHint2}`;
|
|
5851
6504
|
}
|
|
5852
|
-
if (showEventStream && detailEvent)
|
|
5853
|
-
|
|
6505
|
+
if (showEventStream && detailEvent) {
|
|
6506
|
+
return `Shift+\u2190/\u2192: tabs | c: copy | \u2190\u2192: prev/next | Esc: back |${upgradePrompt ? " u: upgrade |" : ""} Ctrl+C`;
|
|
6507
|
+
}
|
|
6508
|
+
if (showEventStream) {
|
|
6509
|
+
return `Shift+\u2190/\u2192: tabs | 1-9: jump | 0: latest | Enter: detail |${upgradePrompt ? " u: upgrade |" : ""} Ctrl+C`;
|
|
6510
|
+
}
|
|
5854
6511
|
const scrollHint = scrollOffset > 0 ? ` | +${scrollOffset}` : "";
|
|
5855
6512
|
const dashboardHint = agentPageUrl ? "o: dashboard | " : "";
|
|
5856
|
-
|
|
6513
|
+
const upgradeHint = upgradePrompt ? " | u: upgrade" : "";
|
|
6514
|
+
return `${dashboardHint}Shift+\u2190/\u2192: tabs | 1-9: jump | 0: latest | Tab: events | Ctrl+C${scrollHint}${upgradeHint}`;
|
|
5857
6515
|
})();
|
|
5858
|
-
const detailCenter = detailEvent ? `EVENT DETAIL (${eventCursor + 1}/${
|
|
6516
|
+
const detailCenter = detailEvent ? `EVENT DETAIL (${eventCursor + 1}/${displayedEvents.length})` : "EVENT STREAM";
|
|
5859
6517
|
const goalText = goal || "";
|
|
5860
6518
|
const goalExpandedRows = goalExpanded && goalText.length > terminalWidth - 4 ? Math.ceil(goalText.length / (terminalWidth - 4)) - 1 : 0;
|
|
5861
|
-
const adjustedContentHeight = contentHeight - goalExpandedRows;
|
|
5862
|
-
|
|
5863
|
-
|
|
6519
|
+
const adjustedContentHeight = contentHeight - goalExpandedRows - (hasTabs ? SESSION_TABS_ROWS : 0);
|
|
6520
|
+
const reasoningHintRows = hasReasoning ? 1 : 0;
|
|
6521
|
+
const thinkingRows = showThinkingIndicator ? 2 : 0;
|
|
6522
|
+
const reasoningLiveRows = hasReasoning && !reasoningCollapsed && selectedIsLive && state.phase === "thinking" ? 1 : 0;
|
|
6523
|
+
const maxReasoningRows = Math.max(
|
|
6524
|
+
0,
|
|
6525
|
+
adjustedContentHeight - reasoningHintRows - reasoningLiveRows - thinkingRows - 3
|
|
6526
|
+
);
|
|
6527
|
+
const targetReasoningRows = hasReasoning && !reasoningCollapsed ? Math.min(maxReasoningRows, Math.max(3, Math.min(8, Math.floor(adjustedContentHeight * 0.3)))) : 0;
|
|
6528
|
+
const visibleReasoningLines = useMemo5(
|
|
6529
|
+
() => getVisibleReasoningLines(displayedReasoning, targetReasoningRows),
|
|
6530
|
+
[displayedReasoning, targetReasoningRows]
|
|
6531
|
+
);
|
|
6532
|
+
const reasoningBodyRows = reasoningCollapsed ? 0 : visibleReasoningLines.length;
|
|
6533
|
+
const transcriptRows = Math.max(
|
|
6534
|
+
3,
|
|
6535
|
+
adjustedContentHeight - reasoningHintRows - reasoningBodyRows - reasoningLiveRows - thinkingRows
|
|
6536
|
+
);
|
|
6537
|
+
const upgradeModalWidth = Math.max(24, Math.min(terminalWidth - 6, 88));
|
|
6538
|
+
const showUpgradeBrowseHint = canBrowseAfterUpgradeError && selectedIsLive && !displayedContent.trim() && !displayedReasoning.trim() && displayedTools.length === 0 && displayedEvents.length === 0;
|
|
6539
|
+
return /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", height: terminalRows, children: [
|
|
6540
|
+
/* @__PURE__ */ jsx25(
|
|
5864
6541
|
SessionHeader,
|
|
5865
6542
|
{
|
|
5866
6543
|
sessionName: taskName,
|
|
@@ -5871,18 +6548,26 @@ function MarathonApp({
|
|
|
5871
6548
|
goalExpanded
|
|
5872
6549
|
}
|
|
5873
6550
|
),
|
|
5874
|
-
|
|
5875
|
-
|
|
6551
|
+
hasTabs && /* @__PURE__ */ jsx25(
|
|
6552
|
+
SessionTabs,
|
|
6553
|
+
{
|
|
6554
|
+
tabs: visibleTabs.tabs,
|
|
6555
|
+
hiddenLeft: visibleTabs.hiddenLeft,
|
|
6556
|
+
hiddenRight: visibleTabs.hiddenRight
|
|
6557
|
+
}
|
|
6558
|
+
),
|
|
6559
|
+
state.phase === "steering" && steeringRecap ? /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", height: adjustedContentHeight, children: [
|
|
6560
|
+
/* @__PURE__ */ jsx25(Box23, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx25(
|
|
5876
6561
|
StreamOutput3,
|
|
5877
6562
|
{
|
|
5878
|
-
content:
|
|
6563
|
+
content: displayedContent,
|
|
5879
6564
|
isStreaming: false,
|
|
5880
6565
|
enableMarkdown: !plainText,
|
|
5881
6566
|
maxVisibleLines: adjustedContentHeight - STEERING_PROMPT_ROWS,
|
|
5882
6567
|
scrollOffset
|
|
5883
6568
|
}
|
|
5884
6569
|
) }),
|
|
5885
|
-
/* @__PURE__ */
|
|
6570
|
+
/* @__PURE__ */ jsx25(
|
|
5886
6571
|
SteeringPrompt,
|
|
5887
6572
|
{
|
|
5888
6573
|
onSubmit: handleSteeringSubmit,
|
|
@@ -5893,45 +6578,92 @@ function MarathonApp({
|
|
|
5893
6578
|
recap: steeringRecap
|
|
5894
6579
|
}
|
|
5895
6580
|
)
|
|
5896
|
-
] }) : showEventStream ? /* @__PURE__ */
|
|
6581
|
+
] }) : showEventStream ? /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", height: adjustedContentHeight, overflow: "hidden", children: /* @__PURE__ */ jsx25(
|
|
5897
6582
|
EventStreamPanel,
|
|
5898
6583
|
{
|
|
5899
|
-
events:
|
|
5900
|
-
startTime:
|
|
6584
|
+
events: displayedEvents,
|
|
6585
|
+
startTime: displayedEvents[0]?.timestamp ?? null,
|
|
5901
6586
|
maxVisibleLines: adjustedContentHeight - 1,
|
|
5902
6587
|
selectedIndex: eventCursor,
|
|
5903
6588
|
detailEvent,
|
|
5904
6589
|
detailScrollOffset
|
|
5905
6590
|
}
|
|
5906
|
-
) }) : /* @__PURE__ */
|
|
5907
|
-
/* @__PURE__ */
|
|
5908
|
-
|
|
5909
|
-
|
|
6591
|
+
) }) : /* @__PURE__ */ jsxs23(Box23, { flexDirection: isStacked ? "column" : "row", height: adjustedContentHeight, overflow: "hidden", children: [
|
|
6592
|
+
/* @__PURE__ */ jsx25(Box23, { flexDirection: "column", flexGrow: 1, flexShrink: 1, children: showLoadingAnimation ? /* @__PURE__ */ jsx25(
|
|
6593
|
+
Box23,
|
|
6594
|
+
{
|
|
6595
|
+
flexGrow: 1,
|
|
6596
|
+
justifyContent: "center",
|
|
6597
|
+
alignItems: "center",
|
|
6598
|
+
minHeight: adjustedContentHeight,
|
|
6599
|
+
children: /* @__PURE__ */ jsx25(LoadingAnimation, {})
|
|
6600
|
+
}
|
|
6601
|
+
) : /* @__PURE__ */ jsxs23(Fragment3, { children: [
|
|
6602
|
+
hasReasoning && /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", marginBottom: reasoningCollapsed ? 0 : 1, children: /* @__PURE__ */ jsx25(
|
|
6603
|
+
ReasoningBlock,
|
|
6604
|
+
{
|
|
6605
|
+
lines: visibleReasoningLines,
|
|
6606
|
+
live: selectedIsLive && state.phase === "thinking" && !reasoningCollapsed,
|
|
6607
|
+
collapsed: reasoningCollapsed,
|
|
6608
|
+
showToggleHint: true
|
|
6609
|
+
}
|
|
6610
|
+
) }),
|
|
6611
|
+
showThinkingIndicator && /* @__PURE__ */ jsx25(ThinkingIndicator, { startedAt: state.thinkingStartedAt }),
|
|
6612
|
+
showUpgradeBrowseHint && /* @__PURE__ */ jsx25(Box23, { marginBottom: 1, children: /* @__PURE__ */ jsx25(
|
|
6613
|
+
ReasoningBlock,
|
|
6614
|
+
{
|
|
6615
|
+
lines: [
|
|
6616
|
+
"Upgrade modal dismissed.",
|
|
6617
|
+
"Use Shift+Left/Right or 1-9 to review previous marathon runs."
|
|
6618
|
+
],
|
|
6619
|
+
compact: true
|
|
6620
|
+
}
|
|
6621
|
+
) }),
|
|
6622
|
+
/* @__PURE__ */ jsx25(
|
|
5910
6623
|
StreamOutput3,
|
|
5911
6624
|
{
|
|
5912
|
-
content:
|
|
5913
|
-
isStreaming: state.phase === "streaming",
|
|
6625
|
+
content: displayedContent,
|
|
6626
|
+
isStreaming: selectedIsLive && state.phase === "streaming",
|
|
5914
6627
|
enableMarkdown: !plainText,
|
|
5915
|
-
maxVisibleLines:
|
|
6628
|
+
maxVisibleLines: transcriptRows,
|
|
5916
6629
|
scrollOffset
|
|
5917
6630
|
}
|
|
5918
6631
|
),
|
|
5919
|
-
state.error && /* @__PURE__ */
|
|
5920
|
-
] }),
|
|
5921
|
-
hasTools && /* @__PURE__ */
|
|
5922
|
-
|
|
6632
|
+
selectedIsLive && state.error && !upgradePrompt && /* @__PURE__ */ jsx25(ErrorDisplay4, { error: state.error })
|
|
6633
|
+
] }) }),
|
|
6634
|
+
(hasTools || hasReasoning) && /* @__PURE__ */ jsx25(
|
|
6635
|
+
Box23,
|
|
5923
6636
|
{
|
|
5924
6637
|
flexDirection: "column",
|
|
5925
6638
|
width: isStacked ? void 0 : toolPanelWidth,
|
|
5926
6639
|
flexShrink: 0,
|
|
5927
6640
|
borderStyle: "single",
|
|
5928
|
-
borderColor:
|
|
6641
|
+
borderColor: theme23.muted,
|
|
5929
6642
|
paddingX: 1,
|
|
5930
|
-
children: /* @__PURE__ */
|
|
6643
|
+
children: /* @__PURE__ */ jsx25(
|
|
6644
|
+
ToolPanel,
|
|
6645
|
+
{
|
|
6646
|
+
tools: displayedTools,
|
|
6647
|
+
reasoning: displayedReasoning,
|
|
6648
|
+
maxHeight: adjustedContentHeight - 2
|
|
6649
|
+
}
|
|
6650
|
+
)
|
|
5931
6651
|
}
|
|
5932
6652
|
)
|
|
5933
6653
|
] }),
|
|
5934
|
-
/* @__PURE__ */
|
|
6654
|
+
showUpgradeModal && upgradePrompt && /* @__PURE__ */ jsx25(
|
|
6655
|
+
Box23,
|
|
6656
|
+
{
|
|
6657
|
+
marginTop: -adjustedContentHeight,
|
|
6658
|
+
marginBottom: -adjustedContentHeight,
|
|
6659
|
+
height: adjustedContentHeight,
|
|
6660
|
+
justifyContent: "center",
|
|
6661
|
+
alignItems: "center",
|
|
6662
|
+
flexShrink: 0,
|
|
6663
|
+
children: /* @__PURE__ */ jsx25(UpgradeModal, { prompt: upgradePrompt, width: upgradeModalWidth })
|
|
6664
|
+
}
|
|
6665
|
+
),
|
|
6666
|
+
/* @__PURE__ */ jsx25(
|
|
5935
6667
|
StatusBar2,
|
|
5936
6668
|
{
|
|
5937
6669
|
left: `Model: ${currentModel}`,
|
|
@@ -5943,24 +6675,285 @@ function MarathonApp({
|
|
|
5943
6675
|
}
|
|
5944
6676
|
|
|
5945
6677
|
// src/commands/agents-task.ts
|
|
6678
|
+
import { spawnSync } from "child_process";
|
|
5946
6679
|
import * as fs4 from "fs";
|
|
5947
6680
|
import * as path5 from "path";
|
|
5948
6681
|
import {
|
|
5949
6682
|
RuntypeClient,
|
|
6683
|
+
RuntypeApiError,
|
|
5950
6684
|
evaluateGeneratedRuntimeToolProposal
|
|
5951
6685
|
} from "@runtypelabs/sdk";
|
|
5952
6686
|
function defaultStateDir() {
|
|
5953
6687
|
return path5.join(process.cwd(), ".runtype", "marathons");
|
|
5954
6688
|
}
|
|
6689
|
+
function stateSafeName(name) {
|
|
6690
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
6691
|
+
}
|
|
5955
6692
|
function stateFilePath(name, stateDir) {
|
|
5956
6693
|
const dir = stateDir || defaultStateDir();
|
|
5957
|
-
|
|
5958
|
-
|
|
6694
|
+
return path5.join(dir, `${stateSafeName(name)}.json`);
|
|
6695
|
+
}
|
|
6696
|
+
function marathonArtifactsDir(taskName, stateDir) {
|
|
6697
|
+
return path5.join(stateDir || defaultStateDir(), stateSafeName(taskName));
|
|
6698
|
+
}
|
|
6699
|
+
function resolveMarathonCheckpointPath(taskName, targetPath, stateDir) {
|
|
6700
|
+
const normalizedTargetPath = path5.normalize(targetPath);
|
|
6701
|
+
const relativeTargetPath = path5.isAbsolute(normalizedTargetPath) ? path5.relative(process.cwd(), normalizedTargetPath) : normalizedTargetPath;
|
|
6702
|
+
return path5.join(
|
|
6703
|
+
marathonArtifactsDir(taskName, stateDir),
|
|
6704
|
+
"checkpoints",
|
|
6705
|
+
"original",
|
|
6706
|
+
relativeTargetPath
|
|
6707
|
+
);
|
|
6708
|
+
}
|
|
6709
|
+
function ensureMarathonFileCheckpoint(taskName, targetPath, stateDir) {
|
|
6710
|
+
const normalizedTargetPath = path5.resolve(targetPath);
|
|
6711
|
+
const relativeTargetPath = path5.relative(process.cwd(), normalizedTargetPath);
|
|
6712
|
+
if (!relativeTargetPath || relativeTargetPath.startsWith("..")) return void 0;
|
|
6713
|
+
if (!fs4.existsSync(normalizedTargetPath)) return void 0;
|
|
6714
|
+
if (!fs4.statSync(normalizedTargetPath).isFile()) return void 0;
|
|
6715
|
+
const normalizedRelativeTargetPath = relativeTargetPath.replace(/\\/g, "/");
|
|
6716
|
+
if (normalizedRelativeTargetPath.startsWith(".runtype/")) return void 0;
|
|
6717
|
+
const checkpointPath = resolveMarathonCheckpointPath(taskName, normalizedTargetPath, stateDir);
|
|
6718
|
+
if (fs4.existsSync(checkpointPath)) return checkpointPath;
|
|
6719
|
+
fs4.mkdirSync(path5.dirname(checkpointPath), { recursive: true });
|
|
6720
|
+
fs4.copyFileSync(normalizedTargetPath, checkpointPath);
|
|
6721
|
+
return checkpointPath;
|
|
6722
|
+
}
|
|
6723
|
+
function restoreMarathonFileCheckpoint(taskName, targetPath, stateDir) {
|
|
6724
|
+
const normalizedTargetPath = path5.resolve(targetPath);
|
|
6725
|
+
const relativeTargetPath = path5.relative(process.cwd(), normalizedTargetPath);
|
|
6726
|
+
if (!relativeTargetPath || relativeTargetPath.startsWith("..")) {
|
|
6727
|
+
return {
|
|
6728
|
+
restored: false,
|
|
6729
|
+
error: `Cannot restore checkpoint outside the current repository: ${normalizedTargetPath}`
|
|
6730
|
+
};
|
|
6731
|
+
}
|
|
6732
|
+
const checkpointPath = resolveMarathonCheckpointPath(taskName, normalizedTargetPath, stateDir);
|
|
6733
|
+
if (!fs4.existsSync(checkpointPath)) {
|
|
6734
|
+
return {
|
|
6735
|
+
restored: false,
|
|
6736
|
+
checkpointPath,
|
|
6737
|
+
error: `No checkpoint found for ${normalizedTargetPath}`
|
|
6738
|
+
};
|
|
6739
|
+
}
|
|
6740
|
+
fs4.mkdirSync(path5.dirname(normalizedTargetPath), { recursive: true });
|
|
6741
|
+
fs4.copyFileSync(checkpointPath, normalizedTargetPath);
|
|
6742
|
+
return { restored: true, checkpointPath };
|
|
6743
|
+
}
|
|
6744
|
+
var BLOCKED_VERIFICATION_PATTERNS = [
|
|
6745
|
+
/&&/,
|
|
6746
|
+
/\|\|/,
|
|
6747
|
+
/\|/,
|
|
6748
|
+
/;/,
|
|
6749
|
+
/>/,
|
|
6750
|
+
/</,
|
|
6751
|
+
/`/,
|
|
6752
|
+
/\$\(/,
|
|
6753
|
+
/\r|\n/,
|
|
6754
|
+
/\brm\b/i,
|
|
6755
|
+
/\bmv\b/i,
|
|
6756
|
+
/\bcp\b/i,
|
|
6757
|
+
/\bsudo\b/i,
|
|
6758
|
+
/\bchmod\b/i,
|
|
6759
|
+
/\bchown\b/i,
|
|
6760
|
+
/\bcurl\b/i,
|
|
6761
|
+
/\bwget\b/i,
|
|
6762
|
+
/\bssh\b/i,
|
|
6763
|
+
/\bscp\b/i,
|
|
6764
|
+
/\brsync\b/i,
|
|
6765
|
+
/\bgit\s+(?:reset|checkout|restore|clean|revert|commit|push)\b/i,
|
|
6766
|
+
/\b(?:npm|pnpm|yarn|bun)\s+(?:add|install|remove|unlink|publish)\b/i
|
|
6767
|
+
];
|
|
6768
|
+
var ALLOWED_VERIFICATION_COMMANDS = [
|
|
6769
|
+
/^(?:pnpm|npm|yarn|bun)\s+(?:test|lint|build|check|typecheck)\b/i,
|
|
6770
|
+
/^(?:pnpm|npm|yarn|bun)\s+exec\s+(?:tsc|vitest|eslint|prettier|jest)\b/i,
|
|
6771
|
+
/^(?:pnpm|npm|yarn|bun)\s+run\s+(?:test|lint|build|check|typecheck)\b/i,
|
|
6772
|
+
/^(?:vitest|jest|pytest|eslint|ruff|mypy|tsc)\b/i,
|
|
6773
|
+
/^(?:playwright\s+test|prettier\s+--check|cargo\s+(?:test|check)|go\s+test|deno\s+(?:test|check)|git\s+diff\s+--check)\b/i,
|
|
6774
|
+
/^(?:make|just)\s+(?:test|lint|build|check|typecheck)\b/i
|
|
6775
|
+
];
|
|
6776
|
+
function isSafeVerificationCommand(command) {
|
|
6777
|
+
const trimmed = command.trim();
|
|
6778
|
+
if (!trimmed) return false;
|
|
6779
|
+
if (BLOCKED_VERIFICATION_PATTERNS.some((pattern) => pattern.test(trimmed))) return false;
|
|
6780
|
+
return ALLOWED_VERIFICATION_COMMANDS.some((pattern) => pattern.test(trimmed));
|
|
6781
|
+
}
|
|
6782
|
+
function normalizeMarathonStatePath(candidatePath) {
|
|
6783
|
+
if (!candidatePath) return void 0;
|
|
6784
|
+
const normalized = candidatePath.trim().replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+/g, "/");
|
|
6785
|
+
return normalized || void 0;
|
|
6786
|
+
}
|
|
6787
|
+
function marathonStatePathExists(candidatePath) {
|
|
6788
|
+
if (!candidatePath) return false;
|
|
6789
|
+
return fs4.existsSync(path5.resolve(candidatePath));
|
|
6790
|
+
}
|
|
6791
|
+
function isMarathonArtifactStatePath(candidatePath) {
|
|
6792
|
+
if (!candidatePath) return false;
|
|
6793
|
+
const normalized = normalizeMarathonStatePath(candidatePath)?.toLowerCase();
|
|
6794
|
+
return normalized === ".runtype" || normalized?.startsWith(".runtype/") === true;
|
|
6795
|
+
}
|
|
6796
|
+
function scoreMarathonCandidatePath(candidatePath) {
|
|
6797
|
+
const normalized = candidatePath.toLowerCase();
|
|
6798
|
+
let score = 0;
|
|
6799
|
+
if (normalized.endsWith("/theme.html") || normalized.endsWith("theme.html")) score += 80;
|
|
6800
|
+
if (normalized.includes("agent")) score += 30;
|
|
6801
|
+
if (normalized.includes("editor")) score += 30;
|
|
6802
|
+
if (normalized.includes("theme")) score += 25;
|
|
6803
|
+
if (normalized.endsWith(".html")) score += 20;
|
|
6804
|
+
if (normalized.includes("/src/")) score += 10;
|
|
6805
|
+
if (normalized.includes("/app/")) score += 10;
|
|
6806
|
+
if (normalized.includes("index.html")) score -= 10;
|
|
6807
|
+
return score;
|
|
6808
|
+
}
|
|
6809
|
+
function dedupeNormalizedPaths(paths, options) {
|
|
6810
|
+
return Array.from(
|
|
6811
|
+
new Set(
|
|
6812
|
+
(paths || []).map((candidatePath) => normalizeMarathonStatePath(candidatePath)).filter((candidatePath) => {
|
|
6813
|
+
if (!candidatePath) return false;
|
|
6814
|
+
if (options?.allowArtifacts) return true;
|
|
6815
|
+
return !isMarathonArtifactStatePath(candidatePath);
|
|
6816
|
+
})
|
|
6817
|
+
)
|
|
6818
|
+
);
|
|
6819
|
+
}
|
|
6820
|
+
function normalizePersistedWorkflowPhase(state) {
|
|
6821
|
+
if (state.status === "complete") return "complete";
|
|
6822
|
+
if (state.planWritten) return "execution";
|
|
6823
|
+
return state.workflowPhase;
|
|
6824
|
+
}
|
|
6825
|
+
function mapRunTaskStatusToSnapshotStatus(status, fallback) {
|
|
6826
|
+
if (status === "complete") return "complete";
|
|
6827
|
+
if (status === "error") return "error";
|
|
6828
|
+
if (status === "budget_exceeded") return "budget_exceeded";
|
|
6829
|
+
return fallback;
|
|
6830
|
+
}
|
|
6831
|
+
function isMarathonResumableStatus(status) {
|
|
6832
|
+
return status === "paused" || status === "max_sessions" || status === "error";
|
|
6833
|
+
}
|
|
6834
|
+
function isRawStreamEvent(value) {
|
|
6835
|
+
return typeof value === "object" && value !== null && typeof value.timestamp === "number" && typeof value.type === "string" && typeof value.data === "object" && value.data !== null && !Array.isArray(value.data);
|
|
6836
|
+
}
|
|
6837
|
+
function isMarathonToolEntry(value) {
|
|
6838
|
+
return typeof value === "object" && value !== null && typeof value.id === "string" && typeof value.sequence === "number" && typeof value.sourceToolCallId === "string" && typeof value.name === "string" && typeof value.toolType === "string" && typeof value.status === "string" && typeof value.startedAt === "number";
|
|
6839
|
+
}
|
|
6840
|
+
function isMarathonSessionSnapshotStatus(value) {
|
|
6841
|
+
return value === "complete" || value === "error" || value === "budget_exceeded" || value === "stopped" || value === "live";
|
|
6842
|
+
}
|
|
6843
|
+
function cloneSessionSnapshot2(snapshot) {
|
|
6844
|
+
return {
|
|
6845
|
+
...snapshot,
|
|
6846
|
+
tools: snapshot.tools.map((tool) => ({
|
|
6847
|
+
...tool,
|
|
6848
|
+
...tool.parameters ? { parameters: structuredClone(tool.parameters) } : {},
|
|
6849
|
+
...tool.result !== void 0 ? { result: structuredClone(tool.result) } : {}
|
|
6850
|
+
})),
|
|
6851
|
+
rawEvents: snapshot.rawEvents.map((event) => ({
|
|
6852
|
+
...event,
|
|
6853
|
+
data: structuredClone(event.data)
|
|
6854
|
+
}))
|
|
6855
|
+
};
|
|
6856
|
+
}
|
|
6857
|
+
function sanitizeMarathonSessionSnapshots(snapshots) {
|
|
6858
|
+
if (!Array.isArray(snapshots)) return [];
|
|
6859
|
+
const bySessionIndex = /* @__PURE__ */ new Map();
|
|
6860
|
+
for (const snapshot of snapshots) {
|
|
6861
|
+
if (typeof snapshot !== "object" || snapshot === null || typeof snapshot.sessionIndex !== "number" || !isMarathonSessionSnapshotStatus(snapshot.status) || typeof snapshot.cost !== "number" || typeof snapshot.content !== "string" || typeof snapshot.reasoning !== "string" || !Array.isArray(snapshot.tools) || !Array.isArray(snapshot.rawEvents)) {
|
|
6862
|
+
continue;
|
|
6863
|
+
}
|
|
6864
|
+
const tools = snapshot.tools;
|
|
6865
|
+
const rawEvents = snapshot.rawEvents;
|
|
6866
|
+
if (!tools.every(isMarathonToolEntry) || !rawEvents.every(isRawStreamEvent)) continue;
|
|
6867
|
+
const sanitizedSnapshot = {
|
|
6868
|
+
sessionIndex: snapshot.sessionIndex,
|
|
6869
|
+
status: snapshot.status,
|
|
6870
|
+
cost: snapshot.cost,
|
|
6871
|
+
content: snapshot.content,
|
|
6872
|
+
reasoning: snapshot.reasoning,
|
|
6873
|
+
tools: tools.map((tool) => ({
|
|
6874
|
+
...tool,
|
|
6875
|
+
...tool.parameters ? { parameters: structuredClone(tool.parameters) } : {},
|
|
6876
|
+
...tool.result !== void 0 ? { result: structuredClone(tool.result) } : {}
|
|
6877
|
+
})),
|
|
6878
|
+
rawEvents: rawEvents.map((event) => ({
|
|
6879
|
+
...event,
|
|
6880
|
+
data: structuredClone(event.data)
|
|
6881
|
+
})),
|
|
6882
|
+
...typeof snapshot.stopReason === "string" ? { stopReason: snapshot.stopReason } : {},
|
|
6883
|
+
...typeof snapshot.completedAt === "string" ? { completedAt: snapshot.completedAt } : {},
|
|
6884
|
+
...typeof snapshot.model === "string" ? { model: snapshot.model } : {}
|
|
6885
|
+
};
|
|
6886
|
+
bySessionIndex.set(sanitizedSnapshot.sessionIndex, sanitizedSnapshot);
|
|
6887
|
+
}
|
|
6888
|
+
return Array.from(bySessionIndex.values()).sort((left, right) => left.sessionIndex - right.sessionIndex);
|
|
6889
|
+
}
|
|
6890
|
+
function upsertMarathonSessionSnapshot(snapshots, nextSnapshot) {
|
|
6891
|
+
const bySessionIndex = /* @__PURE__ */ new Map();
|
|
6892
|
+
for (const snapshot of snapshots) {
|
|
6893
|
+
bySessionIndex.set(snapshot.sessionIndex, cloneSessionSnapshot2(snapshot));
|
|
6894
|
+
}
|
|
6895
|
+
bySessionIndex.set(nextSnapshot.sessionIndex, cloneSessionSnapshot2(nextSnapshot));
|
|
6896
|
+
return Array.from(bySessionIndex.values()).sort((left, right) => left.sessionIndex - right.sessionIndex);
|
|
6897
|
+
}
|
|
6898
|
+
function mergeMarathonSessionSummaries(existingSessions, nextSessions, offset) {
|
|
6899
|
+
const byIndex = /* @__PURE__ */ new Map();
|
|
6900
|
+
for (const session of existingSessions) {
|
|
6901
|
+
byIndex.set(session.index, { ...session });
|
|
6902
|
+
}
|
|
6903
|
+
for (const session of nextSessions) {
|
|
6904
|
+
const absoluteIndex = offset + session.index;
|
|
6905
|
+
byIndex.set(absoluteIndex, { ...session, index: absoluteIndex });
|
|
6906
|
+
}
|
|
6907
|
+
return Array.from(byIndex.values()).sort((left, right) => left.index - right.index);
|
|
6908
|
+
}
|
|
6909
|
+
function buildMarathonSessionSnapshot(liveState, sessionSummary, model, status = "complete") {
|
|
6910
|
+
return {
|
|
6911
|
+
sessionIndex: sessionSummary.index,
|
|
6912
|
+
status,
|
|
6913
|
+
stopReason: sessionSummary.stopReason,
|
|
6914
|
+
cost: sessionSummary.cost,
|
|
6915
|
+
completedAt: sessionSummary.completedAt,
|
|
6916
|
+
model,
|
|
6917
|
+
content: liveState.content,
|
|
6918
|
+
reasoning: liveState.reasoning,
|
|
6919
|
+
tools: liveState.tools.map((tool) => ({
|
|
6920
|
+
...tool,
|
|
6921
|
+
...tool.parameters ? { parameters: structuredClone(tool.parameters) } : {},
|
|
6922
|
+
...tool.result !== void 0 ? { result: structuredClone(tool.result) } : {}
|
|
6923
|
+
})),
|
|
6924
|
+
rawEvents: liveState.rawEvents.map((event) => ({
|
|
6925
|
+
...event,
|
|
6926
|
+
data: structuredClone(event.data)
|
|
6927
|
+
}))
|
|
6928
|
+
};
|
|
6929
|
+
}
|
|
6930
|
+
function sanitizeLoadedMarathonState(state) {
|
|
6931
|
+
const planPath = normalizeMarathonStatePath(state.planPath) || state.planPath;
|
|
6932
|
+
const candidatePaths = dedupeNormalizedPaths(state.candidatePaths).filter(
|
|
6933
|
+
(candidatePath) => marathonStatePathExists(candidatePath)
|
|
6934
|
+
);
|
|
6935
|
+
const recentReadPaths = dedupeNormalizedPaths(state.recentReadPaths).filter(
|
|
6936
|
+
(candidatePath) => marathonStatePathExists(candidatePath)
|
|
6937
|
+
);
|
|
6938
|
+
const normalizedBestCandidate = normalizeMarathonStatePath(state.bestCandidatePath);
|
|
6939
|
+
const bestCandidatePath = normalizedBestCandidate && !isMarathonArtifactStatePath(normalizedBestCandidate) && marathonStatePathExists(normalizedBestCandidate) ? normalizedBestCandidate : [...candidatePaths, ...recentReadPaths].sort((left, right) => scoreMarathonCandidatePath(right) - scoreMarathonCandidatePath(left))[0];
|
|
6940
|
+
return {
|
|
6941
|
+
...state,
|
|
6942
|
+
workflowPhase: normalizePersistedWorkflowPhase(state),
|
|
6943
|
+
planPath,
|
|
6944
|
+
bestCandidatePath,
|
|
6945
|
+
bestCandidateReason: bestCandidatePath ? state.bestCandidateReason : void 0,
|
|
6946
|
+
candidatePaths,
|
|
6947
|
+
recentReadPaths,
|
|
6948
|
+
sessionSnapshots: sanitizeMarathonSessionSnapshots(
|
|
6949
|
+
state.sessionSnapshots
|
|
6950
|
+
)
|
|
6951
|
+
};
|
|
5959
6952
|
}
|
|
5960
6953
|
function loadState(filePath) {
|
|
5961
6954
|
try {
|
|
5962
6955
|
const raw = fs4.readFileSync(filePath, "utf-8");
|
|
5963
|
-
return JSON.parse(raw);
|
|
6956
|
+
return sanitizeLoadedMarathonState(JSON.parse(raw));
|
|
5964
6957
|
} catch {
|
|
5965
6958
|
return null;
|
|
5966
6959
|
}
|
|
@@ -5970,6 +6963,26 @@ function saveState(filePath, state) {
|
|
|
5970
6963
|
fs4.mkdirSync(dir, { recursive: true });
|
|
5971
6964
|
fs4.writeFileSync(filePath, JSON.stringify(state, null, 2));
|
|
5972
6965
|
}
|
|
6966
|
+
function extractRunTaskResumeState(state) {
|
|
6967
|
+
if (!state) return void 0;
|
|
6968
|
+
const sanitized = sanitizeLoadedMarathonState(state);
|
|
6969
|
+
return {
|
|
6970
|
+
...sanitized.originalMessage ? { originalMessage: sanitized.originalMessage } : {},
|
|
6971
|
+
...sanitized.bootstrapContext ? { bootstrapContext: sanitized.bootstrapContext } : {},
|
|
6972
|
+
...sanitized.workflowPhase ? { workflowPhase: sanitized.workflowPhase } : {},
|
|
6973
|
+
...sanitized.planPath ? { planPath: sanitized.planPath } : {},
|
|
6974
|
+
...sanitized.planWritten ? { planWritten: sanitized.planWritten } : {},
|
|
6975
|
+
...sanitized.bestCandidatePath ? { bestCandidatePath: sanitized.bestCandidatePath } : {},
|
|
6976
|
+
...sanitized.bestCandidateReason ? { bestCandidateReason: sanitized.bestCandidateReason } : {},
|
|
6977
|
+
...sanitized.candidatePaths ? { candidatePaths: sanitized.candidatePaths } : {},
|
|
6978
|
+
...sanitized.recentReadPaths ? { recentReadPaths: sanitized.recentReadPaths } : {},
|
|
6979
|
+
...sanitized.recentActionKeys ? { recentActionKeys: sanitized.recentActionKeys } : {},
|
|
6980
|
+
...sanitized.bestCandidateNeedsVerification ? { bestCandidateNeedsVerification: sanitized.bestCandidateNeedsVerification } : {},
|
|
6981
|
+
...sanitized.bestCandidateVerified ? { bestCandidateVerified: sanitized.bestCandidateVerified } : {},
|
|
6982
|
+
...sanitized.verificationRequired !== void 0 ? { verificationRequired: sanitized.verificationRequired } : {},
|
|
6983
|
+
...sanitized.lastVerificationPassed ? { lastVerificationPassed: sanitized.lastVerificationPassed } : {}
|
|
6984
|
+
};
|
|
6985
|
+
}
|
|
5973
6986
|
function findStateFile(name, stateDir) {
|
|
5974
6987
|
const newPath = stateFilePath(name, stateDir || path5.join(process.cwd(), ".runtype", "marathons"));
|
|
5975
6988
|
if (fs4.existsSync(newPath)) return newPath;
|
|
@@ -5996,6 +7009,175 @@ function findLatestStateFile(stateDir) {
|
|
|
5996
7009
|
}
|
|
5997
7010
|
return latest ? { name: latest.name, filePath: latest.filePath } : null;
|
|
5998
7011
|
}
|
|
7012
|
+
function readRateLimitHeader(headers, names) {
|
|
7013
|
+
for (const name of names) {
|
|
7014
|
+
const value = headers?.get(name);
|
|
7015
|
+
if (value) return value;
|
|
7016
|
+
}
|
|
7017
|
+
return void 0;
|
|
7018
|
+
}
|
|
7019
|
+
function extractInlineRateLimitPayload(error) {
|
|
7020
|
+
const match = error.message.match(/^API request failed:\s*429\s+[^-]+-\s*([\s\S]+)$/);
|
|
7021
|
+
if (!match?.[1]) return void 0;
|
|
7022
|
+
try {
|
|
7023
|
+
const parsed = JSON.parse(match[1]);
|
|
7024
|
+
return {
|
|
7025
|
+
message: typeof parsed.message === "string" ? parsed.message : typeof parsed.error === "string" ? parsed.error : error.message,
|
|
7026
|
+
...typeof parsed.code === "string" ? { code: parsed.code } : {},
|
|
7027
|
+
...typeof parsed.limitType === "string" ? { limitType: parsed.limitType } : {}
|
|
7028
|
+
};
|
|
7029
|
+
} catch {
|
|
7030
|
+
return { message: match[1].trim() || error.message };
|
|
7031
|
+
}
|
|
7032
|
+
}
|
|
7033
|
+
function describeMarathonApiError(error) {
|
|
7034
|
+
if (error instanceof RuntypeApiError && error.statusCode === 429) {
|
|
7035
|
+
const apiError = error;
|
|
7036
|
+
const errorData = apiError.data ?? {};
|
|
7037
|
+
const message = typeof errorData.message === "string" ? errorData.message : typeof errorData.error === "string" ? errorData.error : apiError.message;
|
|
7038
|
+
const retryAfter = readRateLimitHeader(apiError.headers, ["Retry-After", "retry-after"]) ?? (typeof errorData.retryAfter === "number" ? String(errorData.retryAfter) : void 0);
|
|
7039
|
+
const limit = readRateLimitHeader(apiError.headers, ["RateLimit-Limit", "X-RateLimit-Limit"]);
|
|
7040
|
+
const remaining = readRateLimitHeader(apiError.headers, ["RateLimit-Remaining", "X-RateLimit-Remaining"]);
|
|
7041
|
+
const reset = readRateLimitHeader(apiError.headers, ["RateLimit-Reset", "X-RateLimit-Reset"]);
|
|
7042
|
+
return [
|
|
7043
|
+
`Task failed: ${message}`,
|
|
7044
|
+
"API returned 429 Too Many Requests.",
|
|
7045
|
+
...errorData.code ? [`Code: ${errorData.code}`] : [],
|
|
7046
|
+
...errorData.limitType ? [`Limit type: ${errorData.limitType}`] : [],
|
|
7047
|
+
...retryAfter ? [`Retry after: ${retryAfter}s`] : [],
|
|
7048
|
+
...limit ? [`RateLimit-Limit: ${limit}`] : [],
|
|
7049
|
+
...remaining ? [`RateLimit-Remaining: ${remaining}`] : [],
|
|
7050
|
+
...reset ? [`RateLimit-Reset: ${reset}`] : []
|
|
7051
|
+
];
|
|
7052
|
+
}
|
|
7053
|
+
if (error instanceof Error) {
|
|
7054
|
+
const inlineRateLimitPayload = extractInlineRateLimitPayload(error);
|
|
7055
|
+
if (inlineRateLimitPayload) {
|
|
7056
|
+
return [
|
|
7057
|
+
`Task failed: ${inlineRateLimitPayload.message}`,
|
|
7058
|
+
"API returned 429 Too Many Requests.",
|
|
7059
|
+
...inlineRateLimitPayload.code ? [`Code: ${inlineRateLimitPayload.code}`] : [],
|
|
7060
|
+
...inlineRateLimitPayload.limitType ? [`Limit type: ${inlineRateLimitPayload.limitType}`] : []
|
|
7061
|
+
];
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
if (!(error instanceof Error)) {
|
|
7065
|
+
return ["Task failed: Unknown error"];
|
|
7066
|
+
}
|
|
7067
|
+
if (!(error instanceof RuntypeApiError) || error.statusCode !== 429) {
|
|
7068
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7069
|
+
return [`Task failed: ${message}`];
|
|
7070
|
+
}
|
|
7071
|
+
return [`Task failed: ${error.message}`];
|
|
7072
|
+
}
|
|
7073
|
+
function formatMarathonApiError(error) {
|
|
7074
|
+
return describeMarathonApiError(error).map((line, index) => {
|
|
7075
|
+
if (index === 0) return chalk13.red(line);
|
|
7076
|
+
if (index === 1 && line.includes("429")) return chalk13.yellow(line);
|
|
7077
|
+
return chalk13.gray(line);
|
|
7078
|
+
});
|
|
7079
|
+
}
|
|
7080
|
+
function canPromptForStateChoice(options) {
|
|
7081
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true && !options.json;
|
|
7082
|
+
}
|
|
7083
|
+
function buildStateSummary(taskName, filePath, state) {
|
|
7084
|
+
const lines = [`Task: ${taskName}`, `State file: ${filePath}`];
|
|
7085
|
+
if (!state) {
|
|
7086
|
+
lines.push("Saved state exists but could not be parsed cleanly.");
|
|
7087
|
+
return lines;
|
|
7088
|
+
}
|
|
7089
|
+
lines.push(`Status: ${state.status}`);
|
|
7090
|
+
lines.push(`Sessions: ${state.sessionCount}`);
|
|
7091
|
+
lines.push(`Cost: $${state.totalCost.toFixed(4)}`);
|
|
7092
|
+
if (state.workflowPhase) {
|
|
7093
|
+
lines.push(`Workflow phase: ${state.workflowPhase}`);
|
|
7094
|
+
}
|
|
7095
|
+
if (state.bestCandidatePath) {
|
|
7096
|
+
lines.push(`Best candidate: ${state.bestCandidatePath}`);
|
|
7097
|
+
}
|
|
7098
|
+
return lines;
|
|
7099
|
+
}
|
|
7100
|
+
async function promptMarathonStateChoice(context) {
|
|
7101
|
+
const title = context.reason === "latest-resume" ? "Found a saved marathon session to resume." : "Found saved local marathon state for this task.";
|
|
7102
|
+
console.log(chalk13.cyan(`
|
|
7103
|
+
${title}`));
|
|
7104
|
+
for (const line of buildStateSummary(context.taskName, context.filePath, context.existingState)) {
|
|
7105
|
+
console.log(chalk13.gray(` ${line}`));
|
|
7106
|
+
}
|
|
7107
|
+
console.log(
|
|
7108
|
+
chalk13.gray(
|
|
7109
|
+
context.reason === "latest-resume" ? " `--resume` without --name or --session would use this latest state." : " Starting without --resume would overwrite this saved local state."
|
|
7110
|
+
)
|
|
7111
|
+
);
|
|
7112
|
+
const choices = [
|
|
7113
|
+
{
|
|
7114
|
+
label: "Resume",
|
|
7115
|
+
value: "resume",
|
|
7116
|
+
description: "Continue from the saved marathon state."
|
|
7117
|
+
},
|
|
7118
|
+
{
|
|
7119
|
+
label: "Start fresh",
|
|
7120
|
+
value: "fresh",
|
|
7121
|
+
description: "Ignore the saved state and start a new marathon run."
|
|
7122
|
+
},
|
|
7123
|
+
{
|
|
7124
|
+
label: "Cancel",
|
|
7125
|
+
value: "cancel",
|
|
7126
|
+
description: "Exit without changing anything."
|
|
7127
|
+
}
|
|
7128
|
+
];
|
|
7129
|
+
console.log();
|
|
7130
|
+
return promptSelect("", choices);
|
|
7131
|
+
}
|
|
7132
|
+
async function resolveMarathonStateResolution(options, taskName, filePath, promptForChoice = promptMarathonStateChoice) {
|
|
7133
|
+
if (options.resume && options.fresh) {
|
|
7134
|
+
throw new Error("Cannot use --resume and --fresh together.");
|
|
7135
|
+
}
|
|
7136
|
+
const allowPrompt = canPromptForStateChoice(options);
|
|
7137
|
+
if (options.resume) {
|
|
7138
|
+
if (options.session || options.name) {
|
|
7139
|
+
return { action: "resume" };
|
|
7140
|
+
}
|
|
7141
|
+
const latest = findLatestStateFile(options.stateDir);
|
|
7142
|
+
if (!latest) {
|
|
7143
|
+
throw new Error("No state files found to resume. Run without --resume to start a new task.");
|
|
7144
|
+
}
|
|
7145
|
+
if (!allowPrompt) {
|
|
7146
|
+
throw new Error(
|
|
7147
|
+
`--resume without --name or --session is ambiguous in non-interactive mode. Re-run with --session "${latest.name}", --name "${latest.name}", or --fresh.`
|
|
7148
|
+
);
|
|
7149
|
+
}
|
|
7150
|
+
const choice2 = await promptForChoice({
|
|
7151
|
+
reason: "latest-resume",
|
|
7152
|
+
taskName: latest.name,
|
|
7153
|
+
filePath: latest.filePath,
|
|
7154
|
+
existingState: loadState(latest.filePath)
|
|
7155
|
+
});
|
|
7156
|
+
if (choice2 === "cancel") return { action: "cancel" };
|
|
7157
|
+
if (choice2 === "fresh") return { action: "fresh" };
|
|
7158
|
+
return { action: "resume", taskName: latest.name, filePath: latest.filePath };
|
|
7159
|
+
}
|
|
7160
|
+
if (options.fresh) {
|
|
7161
|
+
return { action: "fresh" };
|
|
7162
|
+
}
|
|
7163
|
+
if (!fs4.existsSync(filePath)) {
|
|
7164
|
+
return { action: "fresh" };
|
|
7165
|
+
}
|
|
7166
|
+
if (!allowPrompt) {
|
|
7167
|
+
throw new Error(
|
|
7168
|
+
`Local marathon state already exists at ${filePath}. Use --resume to continue it or --fresh to start over.`
|
|
7169
|
+
);
|
|
7170
|
+
}
|
|
7171
|
+
const choice = await promptForChoice({
|
|
7172
|
+
reason: "existing-state",
|
|
7173
|
+
taskName,
|
|
7174
|
+
filePath,
|
|
7175
|
+
existingState: loadState(filePath)
|
|
7176
|
+
});
|
|
7177
|
+
if (choice === "cancel") return { action: "cancel" };
|
|
7178
|
+
if (choice === "resume") return { action: "resume", taskName, filePath };
|
|
7179
|
+
return { action: "fresh" };
|
|
7180
|
+
}
|
|
5999
7181
|
function isRecord(value) {
|
|
6000
7182
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6001
7183
|
}
|
|
@@ -6047,6 +7229,185 @@ function parseDaytonaExecutionResult(value) {
|
|
|
6047
7229
|
}
|
|
6048
7230
|
}
|
|
6049
7231
|
}
|
|
7232
|
+
var IGNORED_REPO_DIRS = /* @__PURE__ */ new Set([
|
|
7233
|
+
".git",
|
|
7234
|
+
".next",
|
|
7235
|
+
".runtype",
|
|
7236
|
+
".turbo",
|
|
7237
|
+
"coverage",
|
|
7238
|
+
"dist",
|
|
7239
|
+
"node_modules"
|
|
7240
|
+
]);
|
|
7241
|
+
var DEFAULT_DISCOVERY_MAX_RESULTS = 50;
|
|
7242
|
+
var MAX_FILE_BYTES_TO_SCAN = 1024 * 1024;
|
|
7243
|
+
var LOW_SIGNAL_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
7244
|
+
".gitignore",
|
|
7245
|
+
"package-lock.json",
|
|
7246
|
+
"pnpm-lock.yaml",
|
|
7247
|
+
"yarn.lock"
|
|
7248
|
+
]);
|
|
7249
|
+
var LOW_SIGNAL_PATH_SEGMENTS = /* @__PURE__ */ new Set([".changeset", "coverage", "docs", "examples"]);
|
|
7250
|
+
var PREFERRED_CODE_PATH_SEGMENTS = [
|
|
7251
|
+
"apps",
|
|
7252
|
+
"packages",
|
|
7253
|
+
"src",
|
|
7254
|
+
"app",
|
|
7255
|
+
"components",
|
|
7256
|
+
"pages",
|
|
7257
|
+
"routes"
|
|
7258
|
+
];
|
|
7259
|
+
var PREFERRED_EXTENSIONS = /* @__PURE__ */ new Set([".html", ".tsx", ".ts", ".jsx", ".js"]);
|
|
7260
|
+
var SEARCH_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
7261
|
+
"a",
|
|
7262
|
+
"analyze",
|
|
7263
|
+
"and",
|
|
7264
|
+
"against",
|
|
7265
|
+
"the",
|
|
7266
|
+
"your",
|
|
7267
|
+
"progress",
|
|
7268
|
+
"through",
|
|
7269
|
+
"go",
|
|
7270
|
+
"with",
|
|
7271
|
+
"when",
|
|
7272
|
+
"make",
|
|
7273
|
+
"sure",
|
|
7274
|
+
"based",
|
|
7275
|
+
"best",
|
|
7276
|
+
"most",
|
|
7277
|
+
"loved",
|
|
7278
|
+
"products",
|
|
7279
|
+
"problem",
|
|
7280
|
+
"research",
|
|
7281
|
+
"first",
|
|
7282
|
+
"generate",
|
|
7283
|
+
"plan",
|
|
7284
|
+
"save",
|
|
7285
|
+
"markdown",
|
|
7286
|
+
"execute",
|
|
7287
|
+
"editing",
|
|
7288
|
+
"files",
|
|
7289
|
+
"exactly",
|
|
7290
|
+
"order",
|
|
7291
|
+
"task",
|
|
7292
|
+
"turn",
|
|
7293
|
+
"update",
|
|
7294
|
+
"goal",
|
|
7295
|
+
"follow",
|
|
7296
|
+
"following",
|
|
7297
|
+
"codebase",
|
|
7298
|
+
"web",
|
|
7299
|
+
"results",
|
|
7300
|
+
"it",
|
|
7301
|
+
"its",
|
|
7302
|
+
"to",
|
|
7303
|
+
"do"
|
|
7304
|
+
]);
|
|
7305
|
+
function normalizeToolPath(toolPath) {
|
|
7306
|
+
const resolved = path5.resolve(toolPath || ".");
|
|
7307
|
+
return path5.relative(process.cwd(), resolved) || ".";
|
|
7308
|
+
}
|
|
7309
|
+
function tokenizeSearchQuery(query) {
|
|
7310
|
+
return query.toLowerCase().split(/[^a-z0-9./_-]+/g).map((token) => token.trim()).filter((token) => token.length >= 2 && !SEARCH_STOP_WORDS.has(token));
|
|
7311
|
+
}
|
|
7312
|
+
function scoreSearchPath(relativePath) {
|
|
7313
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
7314
|
+
const segments = normalized.split("/");
|
|
7315
|
+
const fileName = segments[segments.length - 1] || normalized;
|
|
7316
|
+
const extension = path5.extname(fileName).toLowerCase();
|
|
7317
|
+
let score = 0;
|
|
7318
|
+
if (LOW_SIGNAL_FILE_NAMES.has(fileName)) score -= 50;
|
|
7319
|
+
if (segments.some((segment) => LOW_SIGNAL_PATH_SEGMENTS.has(segment))) score -= 15;
|
|
7320
|
+
if (segments.some((segment) => PREFERRED_CODE_PATH_SEGMENTS.includes(segment))) score += 10;
|
|
7321
|
+
if (PREFERRED_EXTENSIONS.has(extension)) score += 8;
|
|
7322
|
+
if (normalized.startsWith("apps/")) score += 10;
|
|
7323
|
+
if (normalized.startsWith("packages/")) score += 6;
|
|
7324
|
+
if (normalized.includes("/src/")) score += 6;
|
|
7325
|
+
if (normalized.includes("/app/")) score += 6;
|
|
7326
|
+
return score;
|
|
7327
|
+
}
|
|
7328
|
+
function shouldIgnoreRepoEntry(entryPath) {
|
|
7329
|
+
const normalized = normalizeToolPath(entryPath);
|
|
7330
|
+
if (normalized === ".") return false;
|
|
7331
|
+
return normalized.split(path5.sep).some((segment) => IGNORED_REPO_DIRS.has(segment));
|
|
7332
|
+
}
|
|
7333
|
+
function safeReadTextFile(filePath) {
|
|
7334
|
+
try {
|
|
7335
|
+
const stat = fs4.statSync(filePath);
|
|
7336
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES_TO_SCAN) return null;
|
|
7337
|
+
const buffer = fs4.readFileSync(filePath);
|
|
7338
|
+
if (buffer.includes(0)) return null;
|
|
7339
|
+
return buffer.toString("utf-8");
|
|
7340
|
+
} catch {
|
|
7341
|
+
return null;
|
|
7342
|
+
}
|
|
7343
|
+
}
|
|
7344
|
+
function walkRepo(startPath, visitor) {
|
|
7345
|
+
if (!fs4.existsSync(startPath) || !fs4.statSync(startPath).isDirectory()) return;
|
|
7346
|
+
const stack = [startPath];
|
|
7347
|
+
while (stack.length > 0) {
|
|
7348
|
+
const currentDir = stack.pop();
|
|
7349
|
+
if (!currentDir) continue;
|
|
7350
|
+
let entries;
|
|
7351
|
+
try {
|
|
7352
|
+
entries = fs4.readdirSync(currentDir, { withFileTypes: true });
|
|
7353
|
+
} catch {
|
|
7354
|
+
continue;
|
|
7355
|
+
}
|
|
7356
|
+
for (const entry of entries) {
|
|
7357
|
+
const entryPath = path5.join(currentDir, entry.name);
|
|
7358
|
+
if (shouldIgnoreRepoEntry(entryPath)) continue;
|
|
7359
|
+
const shouldStop = visitor(entryPath, entry);
|
|
7360
|
+
if (shouldStop === true) return;
|
|
7361
|
+
if (entry.isDirectory()) stack.push(entryPath);
|
|
7362
|
+
}
|
|
7363
|
+
}
|
|
7364
|
+
}
|
|
7365
|
+
function escapeRegExp(value) {
|
|
7366
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7367
|
+
}
|
|
7368
|
+
function globPatternToRegExp(pattern) {
|
|
7369
|
+
const normalized = pattern.replace(/\\/g, "/");
|
|
7370
|
+
let regex = "^";
|
|
7371
|
+
for (let i = 0; i < normalized.length; i += 1) {
|
|
7372
|
+
const char = normalized[i];
|
|
7373
|
+
const next = normalized[i + 1];
|
|
7374
|
+
if (char === "*") {
|
|
7375
|
+
if (next === "*") {
|
|
7376
|
+
regex += ".*";
|
|
7377
|
+
i += 1;
|
|
7378
|
+
} else {
|
|
7379
|
+
regex += "[^/]*";
|
|
7380
|
+
}
|
|
7381
|
+
continue;
|
|
7382
|
+
}
|
|
7383
|
+
if (char === "?") {
|
|
7384
|
+
regex += "[^/]";
|
|
7385
|
+
continue;
|
|
7386
|
+
}
|
|
7387
|
+
regex += escapeRegExp(char);
|
|
7388
|
+
}
|
|
7389
|
+
return new RegExp(`${regex}$`, "i");
|
|
7390
|
+
}
|
|
7391
|
+
function buildTree(dirPath, maxDepth, depth = 0) {
|
|
7392
|
+
if (depth > maxDepth || shouldIgnoreRepoEntry(dirPath)) return [];
|
|
7393
|
+
let entries;
|
|
7394
|
+
try {
|
|
7395
|
+
entries = fs4.readdirSync(dirPath, { withFileTypes: true });
|
|
7396
|
+
} catch (error) {
|
|
7397
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7398
|
+
return [`${" ".repeat(depth)}[error reading ${normalizeToolPath(dirPath)}: ${message}]`];
|
|
7399
|
+
}
|
|
7400
|
+
const lines = [];
|
|
7401
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7402
|
+
const entryPath = path5.join(dirPath, entry.name);
|
|
7403
|
+
if (shouldIgnoreRepoEntry(entryPath)) continue;
|
|
7404
|
+
lines.push(`${" ".repeat(depth)}- ${entry.name}${entry.isDirectory() ? "/" : ""}`);
|
|
7405
|
+
if (entry.isDirectory() && depth < maxDepth) {
|
|
7406
|
+
lines.push(...buildTree(entryPath, maxDepth, depth + 1));
|
|
7407
|
+
}
|
|
7408
|
+
}
|
|
7409
|
+
return lines;
|
|
7410
|
+
}
|
|
6050
7411
|
function createSandboxInstructions(provider) {
|
|
6051
7412
|
if (provider === "cloudflare-worker") {
|
|
6052
7413
|
return [
|
|
@@ -6199,7 +7560,7 @@ function createSandboxLocalTool(client, provider, debugMode) {
|
|
|
6199
7560
|
} catch (error) {
|
|
6200
7561
|
const message = error instanceof Error ? error.message : String(error);
|
|
6201
7562
|
if (debugMode) {
|
|
6202
|
-
console.log(
|
|
7563
|
+
console.log(chalk13.gray(` [sandbox:${provider}] execution error: ${message}`));
|
|
6203
7564
|
}
|
|
6204
7565
|
return {
|
|
6205
7566
|
success: false,
|
|
@@ -6262,12 +7623,268 @@ var defaultLocalTools = {
|
|
|
6262
7623
|
const dirPath = String(args.path || ".");
|
|
6263
7624
|
return fs4.readdirSync(dirPath).join("\n");
|
|
6264
7625
|
}
|
|
7626
|
+
},
|
|
7627
|
+
search_repo: {
|
|
7628
|
+
description: "Search the repository recursively for matching file paths and file contents before deciding what to edit",
|
|
7629
|
+
parametersSchema: {
|
|
7630
|
+
type: "object",
|
|
7631
|
+
properties: {
|
|
7632
|
+
query: {
|
|
7633
|
+
type: "string",
|
|
7634
|
+
description: "Text to search for in file paths and file contents"
|
|
7635
|
+
},
|
|
7636
|
+
path: {
|
|
7637
|
+
type: "string",
|
|
7638
|
+
description: 'Directory to search from (defaults to ".")'
|
|
7639
|
+
},
|
|
7640
|
+
maxResults: {
|
|
7641
|
+
type: "number",
|
|
7642
|
+
description: "Maximum number of matches to return (default 20, max 100)"
|
|
7643
|
+
}
|
|
7644
|
+
},
|
|
7645
|
+
required: ["query"]
|
|
7646
|
+
},
|
|
7647
|
+
execute: async (args) => {
|
|
7648
|
+
const query = String(args.query || "").trim();
|
|
7649
|
+
if (!query) return "Error: query is required";
|
|
7650
|
+
const startPath = path5.resolve(String(args.path || "."));
|
|
7651
|
+
if (!fs4.existsSync(startPath)) return `Error: path does not exist: ${startPath}`;
|
|
7652
|
+
const maxResults = Math.max(
|
|
7653
|
+
1,
|
|
7654
|
+
Math.min(100, Number.isFinite(Number(args.maxResults)) ? Math.floor(Number(args.maxResults)) : 20)
|
|
7655
|
+
);
|
|
7656
|
+
const needle = query.toLowerCase();
|
|
7657
|
+
const tokens = tokenizeSearchQuery(query);
|
|
7658
|
+
const candidates = [];
|
|
7659
|
+
walkRepo(startPath, (entryPath, dirent) => {
|
|
7660
|
+
const relativePath = normalizeToolPath(entryPath);
|
|
7661
|
+
const normalizedPath = relativePath.toLowerCase();
|
|
7662
|
+
const pathScoreBase = scoreSearchPath(relativePath);
|
|
7663
|
+
const pathTokenMatches = tokens.filter((token) => normalizedPath.includes(token)).length;
|
|
7664
|
+
if (normalizedPath.includes(needle) || tokens.length > 0 && pathTokenMatches >= Math.min(tokens.length, tokens.length > 2 ? 2 : tokens.length)) {
|
|
7665
|
+
const score = pathScoreBase + (normalizedPath.includes(needle) ? 80 : 0) + pathTokenMatches * 18;
|
|
7666
|
+
candidates.push({ score, text: `[path] ${relativePath}` });
|
|
7667
|
+
}
|
|
7668
|
+
if (!dirent.isFile()) return;
|
|
7669
|
+
const contents = safeReadTextFile(entryPath);
|
|
7670
|
+
if (!contents) return;
|
|
7671
|
+
const lines = contents.split("\n");
|
|
7672
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
7673
|
+
const line = lines[i];
|
|
7674
|
+
const normalizedLine = line?.toLowerCase() || "";
|
|
7675
|
+
const lineTokenMatches = tokens.filter((token) => normalizedLine.includes(token)).length;
|
|
7676
|
+
const exactPhraseMatch = normalizedLine.includes(needle);
|
|
7677
|
+
const hasUsefulMatch = exactPhraseMatch || tokens.length > 0 && lineTokenMatches >= Math.min(tokens.length, tokens.length > 2 ? 2 : tokens.length);
|
|
7678
|
+
if (!hasUsefulMatch) continue;
|
|
7679
|
+
const score = pathScoreBase + (exactPhraseMatch ? 70 : 0) + lineTokenMatches * 16 - i * 0.01;
|
|
7680
|
+
candidates.push({
|
|
7681
|
+
score,
|
|
7682
|
+
text: `[content] ${relativePath}:${i + 1}: ${line}`
|
|
7683
|
+
});
|
|
7684
|
+
}
|
|
7685
|
+
});
|
|
7686
|
+
const matches = candidates.sort((a, b) => b.score - a.score || a.text.localeCompare(b.text)).map((candidate) => candidate.text).filter((text, index, array) => array.indexOf(text) === index).slice(0, maxResults);
|
|
7687
|
+
return matches.length > 0 ? matches.join("\n") : `No matches found for "${query}" under ${normalizeToolPath(startPath)}`;
|
|
7688
|
+
}
|
|
7689
|
+
},
|
|
7690
|
+
glob_files: {
|
|
7691
|
+
description: 'Find repository files by path or filename pattern, e.g. "**/theme.html" or "**/*agent*"',
|
|
7692
|
+
parametersSchema: {
|
|
7693
|
+
type: "object",
|
|
7694
|
+
properties: {
|
|
7695
|
+
pattern: {
|
|
7696
|
+
type: "string",
|
|
7697
|
+
description: "Glob-like pattern using * and ** wildcards"
|
|
7698
|
+
},
|
|
7699
|
+
path: {
|
|
7700
|
+
type: "string",
|
|
7701
|
+
description: 'Directory to search from (defaults to ".")'
|
|
7702
|
+
},
|
|
7703
|
+
maxResults: {
|
|
7704
|
+
type: "number",
|
|
7705
|
+
description: "Maximum number of matching paths to return (default 50, max 200)"
|
|
7706
|
+
}
|
|
7707
|
+
},
|
|
7708
|
+
required: ["pattern"]
|
|
7709
|
+
},
|
|
7710
|
+
execute: async (args) => {
|
|
7711
|
+
const pattern = String(args.pattern || "").trim();
|
|
7712
|
+
if (!pattern) return "Error: pattern is required";
|
|
7713
|
+
const startPath = path5.resolve(String(args.path || "."));
|
|
7714
|
+
if (!fs4.existsSync(startPath)) return `Error: path does not exist: ${startPath}`;
|
|
7715
|
+
const maxResults = Math.max(
|
|
7716
|
+
1,
|
|
7717
|
+
Math.min(
|
|
7718
|
+
200,
|
|
7719
|
+
Number.isFinite(Number(args.maxResults)) ? Math.floor(Number(args.maxResults)) : DEFAULT_DISCOVERY_MAX_RESULTS
|
|
7720
|
+
)
|
|
7721
|
+
);
|
|
7722
|
+
const matcher = globPatternToRegExp(pattern);
|
|
7723
|
+
const matches = [];
|
|
7724
|
+
walkRepo(startPath, (entryPath) => {
|
|
7725
|
+
const relativePath = normalizeToolPath(entryPath).replace(/\\/g, "/");
|
|
7726
|
+
if (matcher.test(relativePath)) {
|
|
7727
|
+
matches.push({
|
|
7728
|
+
score: scoreSearchPath(relativePath),
|
|
7729
|
+
path: relativePath
|
|
7730
|
+
});
|
|
7731
|
+
}
|
|
7732
|
+
});
|
|
7733
|
+
const rankedMatches = matches.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path)).map((match) => match.path).slice(0, maxResults);
|
|
7734
|
+
return rankedMatches.length > 0 ? rankedMatches.join("\n") : `No files matched "${pattern}" under ${normalizeToolPath(startPath)}`;
|
|
7735
|
+
}
|
|
7736
|
+
},
|
|
7737
|
+
tree_directory: {
|
|
7738
|
+
description: "Show a recursive tree of files and folders so you can understand repository structure before editing",
|
|
7739
|
+
parametersSchema: {
|
|
7740
|
+
type: "object",
|
|
7741
|
+
properties: {
|
|
7742
|
+
path: {
|
|
7743
|
+
type: "string",
|
|
7744
|
+
description: 'Directory path (defaults to ".")'
|
|
7745
|
+
},
|
|
7746
|
+
maxDepth: {
|
|
7747
|
+
type: "number",
|
|
7748
|
+
description: "Maximum recursion depth (default 2, max 6)"
|
|
7749
|
+
}
|
|
7750
|
+
}
|
|
7751
|
+
},
|
|
7752
|
+
execute: async (args) => {
|
|
7753
|
+
const dirPath = path5.resolve(String(args.path || "."));
|
|
7754
|
+
if (!fs4.existsSync(dirPath)) return `Error: path does not exist: ${dirPath}`;
|
|
7755
|
+
if (!fs4.statSync(dirPath).isDirectory()) return `Error: path is not a directory: ${dirPath}`;
|
|
7756
|
+
const maxDepth = Math.max(
|
|
7757
|
+
0,
|
|
7758
|
+
Math.min(6, Number.isFinite(Number(args.maxDepth)) ? Math.floor(Number(args.maxDepth)) : 2)
|
|
7759
|
+
);
|
|
7760
|
+
const lines = [`${normalizeToolPath(dirPath)}/`, ...buildTree(dirPath, maxDepth)];
|
|
7761
|
+
return lines.join("\n");
|
|
7762
|
+
}
|
|
6265
7763
|
}
|
|
6266
7764
|
};
|
|
6267
|
-
function
|
|
7765
|
+
function createCheckpointedWriteFileTool(taskName, stateDir) {
|
|
7766
|
+
return {
|
|
7767
|
+
description: "Write content to a file, creating directories as needed and checkpointing original repo files",
|
|
7768
|
+
parametersSchema: {
|
|
7769
|
+
type: "object",
|
|
7770
|
+
properties: {
|
|
7771
|
+
path: { type: "string", description: "File path to write" },
|
|
7772
|
+
content: { type: "string", description: "Content to write" }
|
|
7773
|
+
},
|
|
7774
|
+
required: ["path", "content"]
|
|
7775
|
+
},
|
|
7776
|
+
execute: async (args) => {
|
|
7777
|
+
const toolFilePath = String(args.path || "");
|
|
7778
|
+
if (!toolFilePath) return "Error: path is required";
|
|
7779
|
+
const content = String(args.content || "");
|
|
7780
|
+
ensureMarathonFileCheckpoint(taskName, toolFilePath, stateDir);
|
|
7781
|
+
const dir = path5.dirname(toolFilePath);
|
|
7782
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
7783
|
+
fs4.writeFileSync(toolFilePath, content);
|
|
7784
|
+
return "ok";
|
|
7785
|
+
}
|
|
7786
|
+
};
|
|
7787
|
+
}
|
|
7788
|
+
function createRestoreFileCheckpointTool(taskName, stateDir) {
|
|
7789
|
+
return {
|
|
7790
|
+
description: "Restore the original checkpointed contents for a previously edited repo file if a change regresses behavior",
|
|
7791
|
+
parametersSchema: {
|
|
7792
|
+
type: "object",
|
|
7793
|
+
properties: {
|
|
7794
|
+
path: { type: "string", description: "File path to restore from its original checkpoint" }
|
|
7795
|
+
},
|
|
7796
|
+
required: ["path"]
|
|
7797
|
+
},
|
|
7798
|
+
execute: async (args) => {
|
|
7799
|
+
const toolFilePath = String(args.path || "");
|
|
7800
|
+
if (!toolFilePath) return "Error: path is required";
|
|
7801
|
+
const result = restoreMarathonFileCheckpoint(taskName, toolFilePath, stateDir);
|
|
7802
|
+
if (!result.restored) {
|
|
7803
|
+
return result.error || `No checkpoint found for ${toolFilePath}`;
|
|
7804
|
+
}
|
|
7805
|
+
return "ok";
|
|
7806
|
+
}
|
|
7807
|
+
};
|
|
7808
|
+
}
|
|
7809
|
+
function createRunCheckTool() {
|
|
7810
|
+
return {
|
|
7811
|
+
description: "Run a safe verification command such as lint, test, or typecheck to validate recent edits before completion",
|
|
7812
|
+
parametersSchema: {
|
|
7813
|
+
type: "object",
|
|
7814
|
+
properties: {
|
|
7815
|
+
command: {
|
|
7816
|
+
type: "string",
|
|
7817
|
+
description: 'Verification command to run, for example "pnpm lint" or "pnpm exec tsc --noEmit"'
|
|
7818
|
+
},
|
|
7819
|
+
timeoutMs: {
|
|
7820
|
+
type: "number",
|
|
7821
|
+
description: "Optional timeout in milliseconds (default 120000, max 600000)"
|
|
7822
|
+
}
|
|
7823
|
+
},
|
|
7824
|
+
required: ["command"]
|
|
7825
|
+
},
|
|
7826
|
+
execute: async (args) => {
|
|
7827
|
+
const command = String(args.command || "").trim();
|
|
7828
|
+
if (!command) {
|
|
7829
|
+
return JSON.stringify({
|
|
7830
|
+
success: false,
|
|
7831
|
+
command,
|
|
7832
|
+
error: "command is required"
|
|
7833
|
+
});
|
|
7834
|
+
}
|
|
7835
|
+
if (!isSafeVerificationCommand(command)) {
|
|
7836
|
+
return JSON.stringify({
|
|
7837
|
+
success: false,
|
|
7838
|
+
command,
|
|
7839
|
+
error: "Blocked unsafe verification command. Use a single non-destructive lint/test/typecheck/build command."
|
|
7840
|
+
});
|
|
7841
|
+
}
|
|
7842
|
+
const timeoutMs = Math.max(
|
|
7843
|
+
1e3,
|
|
7844
|
+
Math.min(
|
|
7845
|
+
6e5,
|
|
7846
|
+
Number.isFinite(Number(args.timeoutMs)) ? Math.floor(Number(args.timeoutMs)) : 12e4
|
|
7847
|
+
)
|
|
7848
|
+
);
|
|
7849
|
+
try {
|
|
7850
|
+
const result = spawnSync(command, {
|
|
7851
|
+
cwd: process.cwd(),
|
|
7852
|
+
encoding: "utf-8",
|
|
7853
|
+
shell: true,
|
|
7854
|
+
timeout: timeoutMs,
|
|
7855
|
+
maxBuffer: 1024 * 1024 * 4
|
|
7856
|
+
});
|
|
7857
|
+
const output = `${result.stdout || ""}${result.stderr || ""}`.trim().slice(0, 12e3);
|
|
7858
|
+
return JSON.stringify({
|
|
7859
|
+
success: result.status === 0 && !result.error,
|
|
7860
|
+
command,
|
|
7861
|
+
exitCode: result.status,
|
|
7862
|
+
timedOut: result.signal === "SIGTERM",
|
|
7863
|
+
output,
|
|
7864
|
+
...result.error ? { error: result.error.message } : {}
|
|
7865
|
+
});
|
|
7866
|
+
} catch (error) {
|
|
7867
|
+
return JSON.stringify({
|
|
7868
|
+
success: false,
|
|
7869
|
+
command,
|
|
7870
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7871
|
+
});
|
|
7872
|
+
}
|
|
7873
|
+
}
|
|
7874
|
+
};
|
|
7875
|
+
}
|
|
7876
|
+
function buildLocalTools(client, sandboxProvider, options, context) {
|
|
6268
7877
|
const enabledTools = {};
|
|
6269
7878
|
if (!options.noLocalTools) {
|
|
6270
7879
|
Object.assign(enabledTools, defaultLocalTools);
|
|
7880
|
+
if (context) {
|
|
7881
|
+
enabledTools.write_file = createCheckpointedWriteFileTool(context.taskName, context.stateDir);
|
|
7882
|
+
enabledTools.restore_file_checkpoint = createRestoreFileCheckpointTool(
|
|
7883
|
+
context.taskName,
|
|
7884
|
+
context.stateDir
|
|
7885
|
+
);
|
|
7886
|
+
enabledTools.run_check = createRunCheckTool();
|
|
7887
|
+
}
|
|
6271
7888
|
}
|
|
6272
7889
|
if (sandboxProvider) {
|
|
6273
7890
|
enabledTools.run_sandbox_code = createSandboxLocalTool(client, sandboxProvider, options.debug);
|
|
@@ -6276,8 +7893,8 @@ function buildLocalTools(client, sandboxProvider, options) {
|
|
|
6276
7893
|
}
|
|
6277
7894
|
async function taskAction(agent, options) {
|
|
6278
7895
|
if (!options.resume && !options.goal) {
|
|
6279
|
-
console.error(
|
|
6280
|
-
console.log(
|
|
7896
|
+
console.error(chalk13.red("Error: -g, --goal <text> is required for new tasks"));
|
|
7897
|
+
console.log(chalk13.gray(" Use --resume to continue an existing task without a new goal"));
|
|
6281
7898
|
process.exit(1);
|
|
6282
7899
|
}
|
|
6283
7900
|
const apiKey = await ensureAuth();
|
|
@@ -6288,12 +7905,12 @@ async function taskAction(agent, options) {
|
|
|
6288
7905
|
});
|
|
6289
7906
|
let parsedSandbox = parseSandboxProvider(options.sandbox);
|
|
6290
7907
|
if (options.sandbox && !parsedSandbox) {
|
|
6291
|
-
console.error(
|
|
7908
|
+
console.error(chalk13.red(`Invalid --sandbox value "${options.sandbox}". Use: cloudflare-worker, quickjs, or daytona`));
|
|
6292
7909
|
process.exit(1);
|
|
6293
7910
|
}
|
|
6294
7911
|
let agentId = agent;
|
|
6295
7912
|
if (!agent.startsWith("agent_")) {
|
|
6296
|
-
console.log(
|
|
7913
|
+
console.log(chalk13.gray("Looking up agent by name..."));
|
|
6297
7914
|
try {
|
|
6298
7915
|
const list = await client.agents.list();
|
|
6299
7916
|
const found = list.data.find(
|
|
@@ -6301,24 +7918,24 @@ async function taskAction(agent, options) {
|
|
|
6301
7918
|
);
|
|
6302
7919
|
if (found) {
|
|
6303
7920
|
agentId = found.id;
|
|
6304
|
-
console.log(
|
|
7921
|
+
console.log(chalk13.green(`Found agent: ${agentId}`));
|
|
6305
7922
|
} else {
|
|
6306
|
-
console.log(
|
|
7923
|
+
console.log(chalk13.gray(`Creating agent "${agent}"...`));
|
|
6307
7924
|
try {
|
|
6308
7925
|
const created = await client.agents.create({ name: agent });
|
|
6309
7926
|
agentId = created.id;
|
|
6310
|
-
console.log(
|
|
7927
|
+
console.log(chalk13.green(`Created agent: ${agentId}`));
|
|
6311
7928
|
} catch (createErr) {
|
|
6312
|
-
console.error(
|
|
7929
|
+
console.error(chalk13.red(`Failed to create agent "${agent}"`));
|
|
6313
7930
|
const errMsg = createErr instanceof Error ? createErr.message : String(createErr);
|
|
6314
|
-
console.error(
|
|
7931
|
+
console.error(chalk13.red(errMsg));
|
|
6315
7932
|
process.exit(1);
|
|
6316
7933
|
}
|
|
6317
7934
|
}
|
|
6318
7935
|
} catch (error) {
|
|
6319
|
-
console.error(
|
|
7936
|
+
console.error(chalk13.red("Failed to list agents"));
|
|
6320
7937
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
6321
|
-
console.error(
|
|
7938
|
+
console.error(chalk13.red(errMsg));
|
|
6322
7939
|
process.exit(1);
|
|
6323
7940
|
}
|
|
6324
7941
|
}
|
|
@@ -6326,6 +7943,30 @@ async function taskAction(agent, options) {
|
|
|
6326
7943
|
let filePath = stateFilePath(taskName, options.stateDir);
|
|
6327
7944
|
const maxSessions = parseInt(options.maxSessions, 10);
|
|
6328
7945
|
const maxCost = options.maxCost ? parseFloat(options.maxCost) : void 0;
|
|
7946
|
+
let resumeRequested = Boolean(options.resume);
|
|
7947
|
+
let forcedResumeTaskName;
|
|
7948
|
+
let forcedResumeFilePath;
|
|
7949
|
+
try {
|
|
7950
|
+
const stateResolution = await resolveMarathonStateResolution(options, taskName, filePath);
|
|
7951
|
+
if (stateResolution.action === "cancel") {
|
|
7952
|
+
console.log(chalk13.gray("Marathon start cancelled."));
|
|
7953
|
+
return;
|
|
7954
|
+
}
|
|
7955
|
+
if (stateResolution.action === "resume") {
|
|
7956
|
+
resumeRequested = true;
|
|
7957
|
+
forcedResumeTaskName = stateResolution.taskName;
|
|
7958
|
+
forcedResumeFilePath = stateResolution.filePath;
|
|
7959
|
+
} else {
|
|
7960
|
+
resumeRequested = false;
|
|
7961
|
+
if (options.fresh && fs4.existsSync(filePath)) {
|
|
7962
|
+
console.log(chalk13.gray(`Starting fresh and ignoring saved local state at ${filePath}`));
|
|
7963
|
+
}
|
|
7964
|
+
}
|
|
7965
|
+
} catch (error) {
|
|
7966
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7967
|
+
console.error(chalk13.red(message));
|
|
7968
|
+
process.exit(1);
|
|
7969
|
+
}
|
|
6329
7970
|
let priorSessionCount = 0;
|
|
6330
7971
|
let priorCost = 0;
|
|
6331
7972
|
let previousMessages = [];
|
|
@@ -6335,10 +7976,16 @@ async function taskAction(agent, options) {
|
|
|
6335
7976
|
let priorContinuations = [];
|
|
6336
7977
|
let priorCostByModel = {};
|
|
6337
7978
|
let priorOriginalMessage;
|
|
6338
|
-
|
|
7979
|
+
let persistedSessionSummaries = [];
|
|
7980
|
+
let persistedSessionSnapshots = [];
|
|
7981
|
+
let resumeState;
|
|
7982
|
+
if (resumeRequested) {
|
|
6339
7983
|
let resolvedFilePath;
|
|
6340
7984
|
let resolvedTaskName;
|
|
6341
|
-
if (
|
|
7985
|
+
if (forcedResumeFilePath && forcedResumeTaskName) {
|
|
7986
|
+
resolvedTaskName = forcedResumeTaskName;
|
|
7987
|
+
resolvedFilePath = forcedResumeFilePath;
|
|
7988
|
+
} else if (options.session) {
|
|
6342
7989
|
resolvedTaskName = options.session;
|
|
6343
7990
|
resolvedFilePath = findStateFile(options.session, options.stateDir);
|
|
6344
7991
|
} else if (options.name) {
|
|
@@ -6347,24 +7994,26 @@ async function taskAction(agent, options) {
|
|
|
6347
7994
|
} else {
|
|
6348
7995
|
const latest = findLatestStateFile(options.stateDir);
|
|
6349
7996
|
if (!latest) {
|
|
6350
|
-
console.error(
|
|
6351
|
-
console.log(
|
|
7997
|
+
console.error(chalk13.red("No state files found to resume"));
|
|
7998
|
+
console.log(chalk13.gray(" Run without --resume to start a new task."));
|
|
6352
7999
|
process.exit(1);
|
|
6353
8000
|
}
|
|
6354
8001
|
resolvedTaskName = latest.name;
|
|
6355
8002
|
resolvedFilePath = latest.filePath;
|
|
6356
|
-
console.log(
|
|
8003
|
+
console.log(chalk13.gray(` Auto-selected session: ${resolvedTaskName}`));
|
|
6357
8004
|
}
|
|
6358
8005
|
const existing = loadState(resolvedFilePath);
|
|
6359
8006
|
if (!existing) {
|
|
6360
|
-
console.error(
|
|
6361
|
-
console.log(
|
|
8007
|
+
console.error(chalk13.red(`No state file found at ${resolvedFilePath}`));
|
|
8008
|
+
console.log(chalk13.gray(" Run without --resume to start a new task."));
|
|
6362
8009
|
process.exit(1);
|
|
6363
8010
|
}
|
|
6364
8011
|
priorSessionCount = existing.sessionCount;
|
|
6365
8012
|
priorCost = existing.totalCost;
|
|
6366
8013
|
priorCostByModel = existing.costByModel ?? {};
|
|
6367
8014
|
priorOriginalMessage = existing.originalMessage;
|
|
8015
|
+
persistedSessionSummaries = existing.sessions ?? [];
|
|
8016
|
+
persistedSessionSnapshots = existing.sessionSnapshots ?? [];
|
|
6368
8017
|
const resumeMessage = typeof options.resume === "string" ? options.resume : options.goal;
|
|
6369
8018
|
const continuation = {
|
|
6370
8019
|
continuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -6385,27 +8034,33 @@ async function taskAction(agent, options) {
|
|
|
6385
8034
|
continuationMessage = resumeMessage;
|
|
6386
8035
|
useCompact = options.compact ?? false;
|
|
6387
8036
|
continuationIndex = continuations.length - 1;
|
|
8037
|
+
resumeState = extractRunTaskResumeState(existing);
|
|
6388
8038
|
filePath = resolvedFilePath;
|
|
6389
8039
|
taskName = resolvedTaskName;
|
|
6390
8040
|
console.log(
|
|
6391
|
-
|
|
8041
|
+
chalk13.cyan(
|
|
6392
8042
|
`Resuming "${resolvedTaskName}" from session ${priorSessionCount} (${existing.status}) \u2014 $${priorCost.toFixed(4)} spent`
|
|
6393
8043
|
)
|
|
6394
8044
|
);
|
|
6395
8045
|
}
|
|
6396
8046
|
const remainingSessions = maxSessions - priorSessionCount;
|
|
6397
8047
|
const remainingCost = maxCost ? maxCost - priorCost : void 0;
|
|
6398
|
-
const baseMessage = options.goal || (
|
|
8048
|
+
const baseMessage = options.goal || (resumeRequested ? "Continue the task." : "");
|
|
6399
8049
|
const sandboxPrompt = parsedSandbox ? createSandboxInstructions(parsedSandbox) : "";
|
|
6400
|
-
let localTools = buildLocalTools(client, parsedSandbox, options
|
|
8050
|
+
let localTools = buildLocalTools(client, parsedSandbox, options, {
|
|
8051
|
+
taskName,
|
|
8052
|
+
stateDir: options.stateDir
|
|
8053
|
+
});
|
|
6401
8054
|
let toolsEnabled = true;
|
|
6402
8055
|
let taskMessage = sandboxPrompt ? `${baseMessage}
|
|
6403
8056
|
|
|
6404
8057
|
${sandboxPrompt}` : baseMessage;
|
|
6405
8058
|
const streamRef = { current: null };
|
|
8059
|
+
let waitForUiExit;
|
|
6406
8060
|
let lastKnownState = null;
|
|
6407
8061
|
const exitAltScreen = enterAltScreen();
|
|
6408
8062
|
try {
|
|
8063
|
+
const marathonDashboardBaseUrl = getDashboardUrl().replace(/\/$/, "");
|
|
6409
8064
|
const { waitUntilExit } = render10(
|
|
6410
8065
|
React12.createElement(MarathonApp, {
|
|
6411
8066
|
taskName,
|
|
@@ -6415,24 +8070,28 @@ ${sandboxPrompt}` : baseMessage;
|
|
|
6415
8070
|
goal: baseMessage,
|
|
6416
8071
|
initialSessionCount: priorSessionCount,
|
|
6417
8072
|
initialCost: priorCost,
|
|
8073
|
+
initialSessionSnapshots: persistedSessionSnapshots,
|
|
6418
8074
|
debug: options.debug,
|
|
6419
8075
|
plainText: options.plainText ?? false,
|
|
6420
8076
|
noSteer: options.noSteer ?? false,
|
|
6421
8077
|
steeringTimeout: parseInt(options.steerTimeout || "10", 10),
|
|
6422
|
-
dashboardUrl:
|
|
6423
|
-
|
|
8078
|
+
dashboardUrl: marathonDashboardBaseUrl,
|
|
8079
|
+
billingUrl: `${marathonDashboardBaseUrl}/settings/billing`,
|
|
8080
|
+
onSaveState: (payload) => {
|
|
6424
8081
|
const partialState = {
|
|
8082
|
+
...lastKnownState ?? {},
|
|
6425
8083
|
agentId,
|
|
6426
8084
|
agentName: agentId,
|
|
6427
8085
|
taskName,
|
|
6428
8086
|
status: "paused",
|
|
6429
|
-
sessionCount: priorSessionCount,
|
|
6430
|
-
totalCost: priorCost,
|
|
6431
|
-
lastOutput: content || "",
|
|
6432
|
-
lastStopReason: "
|
|
6433
|
-
sessions:
|
|
6434
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8087
|
+
sessionCount: lastKnownState?.sessionCount ?? priorSessionCount,
|
|
8088
|
+
totalCost: lastKnownState?.totalCost ?? priorCost,
|
|
8089
|
+
lastOutput: payload.content || "",
|
|
8090
|
+
lastStopReason: "end_turn",
|
|
8091
|
+
sessions: persistedSessionSummaries,
|
|
8092
|
+
startedAt: lastKnownState?.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
6435
8093
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8094
|
+
...persistedSessionSnapshots.length > 0 || payload.sessionSnapshots.length > 0 ? { sessionSnapshots: payload.sessionSnapshots.length > 0 ? payload.sessionSnapshots : persistedSessionSnapshots } : {},
|
|
6436
8095
|
...priorContinuations.length > 0 ? { continuations: priorContinuations } : {},
|
|
6437
8096
|
...Object.keys(priorCostByModel).length > 0 ? { costByModel: priorCostByModel } : {},
|
|
6438
8097
|
...priorOriginalMessage ? { originalMessage: priorOriginalMessage } : {}
|
|
@@ -6447,13 +8106,17 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6447
8106
|
}),
|
|
6448
8107
|
{ exitOnCtrlC: false }
|
|
6449
8108
|
);
|
|
6450
|
-
|
|
8109
|
+
waitForUiExit = waitUntilExit;
|
|
8110
|
+
await new Promise((resolve2) => setTimeout(resolve2, 0));
|
|
6451
8111
|
const streamActions = streamRef.current;
|
|
6452
8112
|
if (!streamActions) {
|
|
6453
8113
|
exitAltScreen();
|
|
6454
|
-
console.error(
|
|
8114
|
+
console.error(chalk13.red("Failed to initialize marathon UI"));
|
|
6455
8115
|
process.exit(1);
|
|
6456
8116
|
}
|
|
8117
|
+
if (persistedSessionSnapshots.length > 0) {
|
|
8118
|
+
streamActions.hydrateSessionSnapshots(persistedSessionSnapshots);
|
|
8119
|
+
}
|
|
6457
8120
|
let shouldContinue = true;
|
|
6458
8121
|
let accumulatedSessions = 0;
|
|
6459
8122
|
let accumulatedCost = 0;
|
|
@@ -6462,8 +8125,9 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6462
8125
|
while (shouldContinue) {
|
|
6463
8126
|
shouldContinue = false;
|
|
6464
8127
|
const currentStreamCallbacks = streamActions.getCallbacks();
|
|
8128
|
+
const currentSessionOffset = priorSessionCount + accumulatedSessions;
|
|
6465
8129
|
const currentRemainingCost = remainingCost ? remainingCost - accumulatedCost : void 0;
|
|
6466
|
-
const
|
|
8130
|
+
const runTaskOptions = {
|
|
6467
8131
|
message: taskMessage,
|
|
6468
8132
|
maxSessions: remainingSessions - accumulatedSessions,
|
|
6469
8133
|
maxCost: currentRemainingCost,
|
|
@@ -6479,18 +8143,47 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6479
8143
|
continuationMessage,
|
|
6480
8144
|
compact: useCompact
|
|
6481
8145
|
} : {},
|
|
8146
|
+
...resumeState ? { resumeState } : {},
|
|
6482
8147
|
onSession: async (state) => {
|
|
8148
|
+
const currentActions = streamRef.current;
|
|
8149
|
+
persistedSessionSummaries = mergeMarathonSessionSummaries(
|
|
8150
|
+
persistedSessionSummaries,
|
|
8151
|
+
state.sessions,
|
|
8152
|
+
currentSessionOffset
|
|
8153
|
+
);
|
|
8154
|
+
const latestSessionSummary2 = persistedSessionSummaries[persistedSessionSummaries.length - 1];
|
|
8155
|
+
if (currentActions && latestSessionSummary2) {
|
|
8156
|
+
const liveState = currentActions.getState();
|
|
8157
|
+
const sessionSnapshot = buildMarathonSessionSnapshot(
|
|
8158
|
+
{
|
|
8159
|
+
content: liveState.content,
|
|
8160
|
+
reasoning: liveState.reasoning,
|
|
8161
|
+
tools: liveState.tools,
|
|
8162
|
+
rawEvents: liveState.rawEvents,
|
|
8163
|
+
sessionSnapshots: []
|
|
8164
|
+
},
|
|
8165
|
+
latestSessionSummary2,
|
|
8166
|
+
options.model
|
|
8167
|
+
);
|
|
8168
|
+
persistedSessionSnapshots = upsertMarathonSessionSnapshot(
|
|
8169
|
+
persistedSessionSnapshots,
|
|
8170
|
+
sessionSnapshot
|
|
8171
|
+
);
|
|
8172
|
+
currentActions.appendSessionSnapshot(sessionSnapshot);
|
|
8173
|
+
}
|
|
6483
8174
|
const adjustedState = {
|
|
6484
8175
|
...state,
|
|
6485
|
-
sessionCount:
|
|
6486
|
-
totalCost: priorCost + accumulatedCost + state.totalCost
|
|
8176
|
+
sessionCount: currentSessionOffset + state.sessionCount,
|
|
8177
|
+
totalCost: priorCost + accumulatedCost + state.totalCost,
|
|
8178
|
+
sessions: persistedSessionSummaries,
|
|
8179
|
+
...persistedSessionSnapshots.length > 0 ? { sessionSnapshots: persistedSessionSnapshots } : {}
|
|
6487
8180
|
};
|
|
6488
8181
|
lastKnownState = adjustedState;
|
|
8182
|
+
resumeState = extractRunTaskResumeState(adjustedState);
|
|
6489
8183
|
lastSessionMessages = state.messages ?? [];
|
|
6490
8184
|
saveState(filePath, adjustedState);
|
|
6491
8185
|
if (options.noSteer) return;
|
|
6492
8186
|
if (state.status !== "running") return;
|
|
6493
|
-
const currentActions = streamRef.current;
|
|
6494
8187
|
if (!currentActions) return;
|
|
6495
8188
|
const recap = {
|
|
6496
8189
|
sessionNumber: adjustedState.sessionCount,
|
|
@@ -6498,7 +8191,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6498
8191
|
tokensInput: 0,
|
|
6499
8192
|
tokensOutput: 0,
|
|
6500
8193
|
cost: state.totalCost,
|
|
6501
|
-
outputPreview:
|
|
8194
|
+
outputPreview: adjustedState.lastOutput.slice(0, 100)
|
|
6502
8195
|
};
|
|
6503
8196
|
const steeringResult = await currentActions.requestSteering(recap);
|
|
6504
8197
|
switch (steeringResult.action) {
|
|
@@ -6522,18 +8215,27 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6522
8215
|
if (!toolsEnabled) {
|
|
6523
8216
|
localTools = void 0;
|
|
6524
8217
|
} else {
|
|
6525
|
-
localTools = buildLocalTools(client, parsedSandbox, options
|
|
8218
|
+
localTools = buildLocalTools(client, parsedSandbox, options, {
|
|
8219
|
+
taskName,
|
|
8220
|
+
stateDir: options.stateDir
|
|
8221
|
+
});
|
|
6526
8222
|
}
|
|
6527
8223
|
break;
|
|
6528
8224
|
case "sandbox":
|
|
6529
8225
|
if (steeringResult.sandbox === false) {
|
|
6530
8226
|
parsedSandbox = void 0;
|
|
6531
|
-
localTools = buildLocalTools(client, void 0, options
|
|
8227
|
+
localTools = buildLocalTools(client, void 0, options, {
|
|
8228
|
+
taskName,
|
|
8229
|
+
stateDir: options.stateDir
|
|
8230
|
+
});
|
|
6532
8231
|
} else if (steeringResult.sandbox) {
|
|
6533
8232
|
const newSandbox = parseSandboxProvider(steeringResult.sandbox);
|
|
6534
8233
|
if (newSandbox) {
|
|
6535
8234
|
parsedSandbox = newSandbox;
|
|
6536
|
-
localTools = buildLocalTools(client, parsedSandbox, options
|
|
8235
|
+
localTools = buildLocalTools(client, parsedSandbox, options, {
|
|
8236
|
+
taskName,
|
|
8237
|
+
stateDir: options.stateDir
|
|
8238
|
+
});
|
|
6537
8239
|
}
|
|
6538
8240
|
}
|
|
6539
8241
|
break;
|
|
@@ -6542,7 +8244,29 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6542
8244
|
break;
|
|
6543
8245
|
}
|
|
6544
8246
|
}
|
|
6545
|
-
}
|
|
8247
|
+
};
|
|
8248
|
+
const result2 = await client.agents.runTask(agentId, runTaskOptions);
|
|
8249
|
+
persistedSessionSummaries = mergeMarathonSessionSummaries(
|
|
8250
|
+
persistedSessionSummaries,
|
|
8251
|
+
result2.sessions,
|
|
8252
|
+
currentSessionOffset
|
|
8253
|
+
);
|
|
8254
|
+
const latestSessionSummary = persistedSessionSummaries[persistedSessionSummaries.length - 1];
|
|
8255
|
+
if (latestSessionSummary) {
|
|
8256
|
+
const existingSnapshot = persistedSessionSnapshots.find(
|
|
8257
|
+
(snapshot) => snapshot.sessionIndex === latestSessionSummary.index
|
|
8258
|
+
);
|
|
8259
|
+
if (existingSnapshot) {
|
|
8260
|
+
persistedSessionSnapshots = upsertMarathonSessionSnapshot(persistedSessionSnapshots, {
|
|
8261
|
+
...existingSnapshot,
|
|
8262
|
+
status: mapRunTaskStatusToSnapshotStatus(result2.status, existingSnapshot.status),
|
|
8263
|
+
stopReason: latestSessionSummary.stopReason,
|
|
8264
|
+
cost: latestSessionSummary.cost,
|
|
8265
|
+
completedAt: latestSessionSummary.completedAt,
|
|
8266
|
+
model: options.model
|
|
8267
|
+
});
|
|
8268
|
+
}
|
|
8269
|
+
}
|
|
6546
8270
|
accumulatedSessions += result2.sessionCount;
|
|
6547
8271
|
accumulatedCost += result2.totalCost;
|
|
6548
8272
|
lastResult = result2;
|
|
@@ -6550,6 +8274,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6550
8274
|
previousMessages = lastSessionMessages;
|
|
6551
8275
|
continuationMessage = taskMessage;
|
|
6552
8276
|
useCompact = false;
|
|
8277
|
+
resumeState = extractRunTaskResumeState(lastKnownState);
|
|
6553
8278
|
}
|
|
6554
8279
|
if (result2.status === "complete" || result2.status === "budget_exceeded") {
|
|
6555
8280
|
if (options.noSteer) break;
|
|
@@ -6557,13 +8282,15 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6557
8282
|
if (!currentActions) break;
|
|
6558
8283
|
let exitTerminal = false;
|
|
6559
8284
|
while (!exitTerminal) {
|
|
8285
|
+
const knownState2 = lastKnownState;
|
|
8286
|
+
const terminalPreview = knownState2?.lastOutput ?? currentActions.getState().content;
|
|
6560
8287
|
const recap = {
|
|
6561
8288
|
sessionNumber: priorSessionCount + accumulatedSessions,
|
|
6562
8289
|
toolCallsMade: currentActions.getState().tools.length,
|
|
6563
8290
|
tokensInput: 0,
|
|
6564
8291
|
tokensOutput: 0,
|
|
6565
8292
|
cost: accumulatedCost,
|
|
6566
|
-
outputPreview:
|
|
8293
|
+
outputPreview: terminalPreview.slice(0, 100)
|
|
6567
8294
|
};
|
|
6568
8295
|
const steeringResult = await currentActions.requestSteering(recap, true);
|
|
6569
8296
|
switch (steeringResult.action) {
|
|
@@ -6573,17 +8300,26 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6573
8300
|
// re-show steering prompt
|
|
6574
8301
|
case "tools":
|
|
6575
8302
|
toolsEnabled = !toolsEnabled;
|
|
6576
|
-
localTools = toolsEnabled ? buildLocalTools(client, parsedSandbox, options
|
|
8303
|
+
localTools = toolsEnabled ? buildLocalTools(client, parsedSandbox, options, {
|
|
8304
|
+
taskName,
|
|
8305
|
+
stateDir: options.stateDir
|
|
8306
|
+
}) : void 0;
|
|
6577
8307
|
break;
|
|
6578
8308
|
case "sandbox":
|
|
6579
8309
|
if (steeringResult.sandbox === false) {
|
|
6580
8310
|
parsedSandbox = void 0;
|
|
6581
|
-
localTools = buildLocalTools(client, void 0, options
|
|
8311
|
+
localTools = buildLocalTools(client, void 0, options, {
|
|
8312
|
+
taskName,
|
|
8313
|
+
stateDir: options.stateDir
|
|
8314
|
+
});
|
|
6582
8315
|
} else if (steeringResult.sandbox) {
|
|
6583
8316
|
const newSandbox = parseSandboxProvider(steeringResult.sandbox);
|
|
6584
8317
|
if (newSandbox) {
|
|
6585
8318
|
parsedSandbox = newSandbox;
|
|
6586
|
-
localTools = buildLocalTools(client, parsedSandbox, options
|
|
8319
|
+
localTools = buildLocalTools(client, parsedSandbox, options, {
|
|
8320
|
+
taskName,
|
|
8321
|
+
stateDir: options.stateDir
|
|
8322
|
+
});
|
|
6587
8323
|
}
|
|
6588
8324
|
}
|
|
6589
8325
|
break;
|
|
@@ -6594,6 +8330,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6594
8330
|
previousMessages = lastSessionMessages;
|
|
6595
8331
|
continuationMessage = taskMessage;
|
|
6596
8332
|
useCompact = false;
|
|
8333
|
+
resumeState = extractRunTaskResumeState(lastKnownState);
|
|
6597
8334
|
shouldContinue = true;
|
|
6598
8335
|
}
|
|
6599
8336
|
exitTerminal = true;
|
|
@@ -6611,7 +8348,9 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6611
8348
|
}
|
|
6612
8349
|
}
|
|
6613
8350
|
const result = lastResult;
|
|
8351
|
+
const knownState = lastKnownState;
|
|
6614
8352
|
const finalState = {
|
|
8353
|
+
...knownState ?? {},
|
|
6615
8354
|
agentId,
|
|
6616
8355
|
agentName: result.sessions[0]?.stopReason ? agentId : agentId,
|
|
6617
8356
|
taskName,
|
|
@@ -6620,9 +8359,10 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6620
8359
|
totalCost: priorCost + accumulatedCost,
|
|
6621
8360
|
lastOutput: result.lastOutput,
|
|
6622
8361
|
lastStopReason: result.sessions[result.sessions.length - 1]?.stopReason || "complete",
|
|
6623
|
-
sessions:
|
|
6624
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8362
|
+
sessions: persistedSessionSummaries,
|
|
8363
|
+
startedAt: typeof knownState?.startedAt === "string" ? knownState.startedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
6625
8364
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8365
|
+
...persistedSessionSnapshots.length > 0 ? { sessionSnapshots: persistedSessionSnapshots } : {},
|
|
6626
8366
|
// Carry forward continuation-related fields
|
|
6627
8367
|
...priorContinuations.length > 0 ? { continuations: priorContinuations } : {},
|
|
6628
8368
|
...Object.keys(priorCostByModel).length > 0 ? { costByModel: priorCostByModel } : {},
|
|
@@ -6635,36 +8375,39 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
6635
8375
|
await waitUntilExit();
|
|
6636
8376
|
exitAltScreen();
|
|
6637
8377
|
console.log();
|
|
6638
|
-
const statusColor = result.status === "complete" ?
|
|
8378
|
+
const statusColor = result.status === "complete" ? chalk13.green : result.status === "budget_exceeded" || result.status === "error" ? chalk13.red : chalk13.yellow;
|
|
6639
8379
|
console.log(`Status: ${statusColor(result.status)}`);
|
|
6640
8380
|
console.log(`Sessions: ${finalState.sessionCount}`);
|
|
6641
|
-
console.log(`Total cost: ${
|
|
6642
|
-
console.log(`State: ${
|
|
8381
|
+
console.log(`Total cost: ${chalk13.yellow(`$${finalState.totalCost.toFixed(4)}`)}`);
|
|
8382
|
+
console.log(`State: ${chalk13.gray(filePath)}`);
|
|
8383
|
+
if (typeof finalState.lastError === "string" && finalState.lastError.trim()) {
|
|
8384
|
+
console.log(`Last error: ${chalk13.red(finalState.lastError)}`);
|
|
8385
|
+
}
|
|
6643
8386
|
const dashboardBaseUrl = getDashboardUrl();
|
|
6644
|
-
console.log(`Dashboard: ${
|
|
8387
|
+
console.log(`Dashboard: ${chalk13.cyan(`${dashboardBaseUrl}/agents/${agentId}`)}`);
|
|
6645
8388
|
if (result.recordId) {
|
|
6646
|
-
console.log(`Record: ${
|
|
8389
|
+
console.log(`Record: ${chalk13.gray(result.recordId)}`);
|
|
6647
8390
|
}
|
|
6648
8391
|
if (finalState.continuations && finalState.continuations.length > 0) {
|
|
6649
|
-
console.log(
|
|
8392
|
+
console.log(chalk13.dim("\nContinuation history:"));
|
|
6650
8393
|
for (let i = 0; i < finalState.continuations.length; i++) {
|
|
6651
8394
|
const c = finalState.continuations[i];
|
|
6652
8395
|
const msg = c.userMessage ? ` "${c.userMessage.slice(0, 50)}"` : " (no message)";
|
|
6653
8396
|
const modelName = c.model ? ` [${c.model}]` : "";
|
|
6654
8397
|
console.log(
|
|
6655
|
-
|
|
8398
|
+
chalk13.gray(` #${i + 1}: ${c.continuedAt}${modelName}${msg} \u2014 $${c.segmentCost.toFixed(4)}`)
|
|
6656
8399
|
);
|
|
6657
8400
|
}
|
|
6658
8401
|
}
|
|
6659
8402
|
if (finalState.costByModel && Object.keys(finalState.costByModel).length > 1) {
|
|
6660
|
-
console.log(
|
|
8403
|
+
console.log(chalk13.dim("\nCost by model:"));
|
|
6661
8404
|
for (const [modelName, cost] of Object.entries(finalState.costByModel)) {
|
|
6662
|
-
console.log(
|
|
8405
|
+
console.log(chalk13.gray(` ${modelName}: $${cost.toFixed(4)}`));
|
|
6663
8406
|
}
|
|
6664
8407
|
}
|
|
6665
|
-
if (result.status
|
|
8408
|
+
if (isMarathonResumableStatus(result.status)) {
|
|
6666
8409
|
console.log(
|
|
6667
|
-
|
|
8410
|
+
chalk13.gray(
|
|
6668
8411
|
`
|
|
6669
8412
|
Resume: ${buildResumeCommand(agent, options, parsedSandbox)}`
|
|
6670
8413
|
)
|
|
@@ -6675,21 +8418,27 @@ Resume: ${buildResumeCommand(agent, options, parsedSandbox)}`
|
|
|
6675
8418
|
printJson(finalState);
|
|
6676
8419
|
}
|
|
6677
8420
|
} catch (error) {
|
|
6678
|
-
exitAltScreen();
|
|
6679
8421
|
const stateAtError = lastKnownState;
|
|
6680
8422
|
if (stateAtError) {
|
|
6681
8423
|
stateAtError.status = "paused";
|
|
6682
8424
|
saveState(filePath, stateAtError);
|
|
6683
8425
|
}
|
|
6684
|
-
const
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
8426
|
+
const streamActions = streamRef.current;
|
|
8427
|
+
if (streamActions && waitForUiExit) {
|
|
8428
|
+
const uiError = new Error(describeMarathonApiError(error).join("\n"));
|
|
8429
|
+
streamActions.showError(uiError);
|
|
8430
|
+
await waitForUiExit();
|
|
8431
|
+
}
|
|
8432
|
+
exitAltScreen();
|
|
8433
|
+
for (const line of formatMarathonApiError(error)) {
|
|
8434
|
+
console.error(line);
|
|
8435
|
+
}
|
|
8436
|
+
console.log(chalk13.gray(`State saved to ${filePath} \u2014 resume with --resume`));
|
|
6688
8437
|
process.exit(1);
|
|
6689
8438
|
}
|
|
6690
8439
|
}
|
|
6691
8440
|
function applyTaskOptions(cmd) {
|
|
6692
|
-
return cmd.argument("<agent>", "Agent ID or name").option("-g, --goal <text>", "Goal message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--session <name>", "Resume a specific session by name").option("--state-dir <path>", "Directory for state files (default: .runtype/marathons/)").option("--resume [message]", "Resume from existing local state, optionally with a new message").option("--compact", "Use compact summary instead of full history on resume").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (cloudflare-worker, quickjs, or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").option("--plain-text", "Disable markdown rendering in output").option("--no-steer", "Run all iterations without steering pauses (fully autonomous)").option("--steer-timeout <seconds>", "Auto-continue timeout in seconds (default: 10)", "10").action(taskAction);
|
|
8441
|
+
return cmd.argument("<agent>", "Agent ID or name").option("-g, --goal <text>", "Goal message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--session <name>", "Resume a specific session by name").option("--state-dir <path>", "Directory for state files (default: .runtype/marathons/)").option("--resume [message]", "Resume from existing local state, optionally with a new message").option("--fresh", "Start a new run and ignore any existing local state for this task").option("--compact", "Use compact summary instead of full history on resume").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (cloudflare-worker, quickjs, or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").option("--plain-text", "Disable markdown rendering in output").option("--no-steer", "Run all iterations without steering pauses (fully autonomous)").option("--steer-timeout <seconds>", "Auto-continue timeout in seconds (default: 10)", "10").action(taskAction);
|
|
6693
8442
|
}
|
|
6694
8443
|
var taskCommand = applyTaskOptions(
|
|
6695
8444
|
new Command11("task").description("Run a multi-session agent task")
|
|
@@ -6733,7 +8482,7 @@ agentsCommand.command("list").description("List all agents").option("--json", "O
|
|
|
6733
8482
|
}
|
|
6734
8483
|
} catch (error) {
|
|
6735
8484
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
6736
|
-
console.error(
|
|
8485
|
+
console.error(chalk14.red(`Failed to fetch agents: ${message}`));
|
|
6737
8486
|
process.exit(1);
|
|
6738
8487
|
}
|
|
6739
8488
|
return;
|
|
@@ -6794,7 +8543,7 @@ agentsCommand.command("get <id>").description("Get agent details").option("--jso
|
|
|
6794
8543
|
]);
|
|
6795
8544
|
} catch (error) {
|
|
6796
8545
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
6797
|
-
console.error(
|
|
8546
|
+
console.error(chalk14.red(`Failed to fetch agent: ${message}`));
|
|
6798
8547
|
process.exit(1);
|
|
6799
8548
|
}
|
|
6800
8549
|
return;
|
|
@@ -6846,7 +8595,7 @@ agentsCommand.command("create").description("Create a new agent").requiredOption
|
|
|
6846
8595
|
console.log(` Name: ${data.name}`);
|
|
6847
8596
|
} catch (error) {
|
|
6848
8597
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
6849
|
-
console.error(
|
|
8598
|
+
console.error(chalk14.red(`Failed to create agent: ${message}`));
|
|
6850
8599
|
process.exit(1);
|
|
6851
8600
|
}
|
|
6852
8601
|
return;
|
|
@@ -6897,7 +8646,7 @@ agentsCommand.command("delete <id>").description("Delete an agent").option("--tt
|
|
|
6897
8646
|
console.log(JSON.stringify({ status: "deleted", id }, null, 2));
|
|
6898
8647
|
} catch (error) {
|
|
6899
8648
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
6900
|
-
console.error(
|
|
8649
|
+
console.error(chalk14.red(`Failed to delete agent: ${message}`));
|
|
6901
8650
|
process.exit(1);
|
|
6902
8651
|
}
|
|
6903
8652
|
return;
|
|
@@ -6953,7 +8702,7 @@ agentsCommand.command("execute <id>").description("Execute an agent").requiredOp
|
|
|
6953
8702
|
messages: [{ role: "user", content: options.message }]
|
|
6954
8703
|
};
|
|
6955
8704
|
if (options.stream) {
|
|
6956
|
-
console.log(
|
|
8705
|
+
console.log(chalk14.gray("Starting agent..."));
|
|
6957
8706
|
try {
|
|
6958
8707
|
const response = await client.stream(`/agents/${id}/execute`, payload);
|
|
6959
8708
|
const callbacks = {
|
|
@@ -6961,7 +8710,7 @@ agentsCommand.command("execute <id>").description("Execute an agent").requiredOp
|
|
|
6961
8710
|
process.stdout.write(chunk);
|
|
6962
8711
|
},
|
|
6963
8712
|
onError: (err) => {
|
|
6964
|
-
console.error(
|
|
8713
|
+
console.error(chalk14.red(`
|
|
6965
8714
|
Error: ${err.message}`));
|
|
6966
8715
|
}
|
|
6967
8716
|
};
|
|
@@ -6969,11 +8718,11 @@ Error: ${err.message}`));
|
|
|
6969
8718
|
console.log();
|
|
6970
8719
|
} catch (error) {
|
|
6971
8720
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
6972
|
-
console.error(
|
|
8721
|
+
console.error(chalk14.red(`Execution failed: ${message}`));
|
|
6973
8722
|
process.exit(1);
|
|
6974
8723
|
}
|
|
6975
8724
|
} else {
|
|
6976
|
-
console.log(
|
|
8725
|
+
console.log(chalk14.gray("Executing agent..."));
|
|
6977
8726
|
try {
|
|
6978
8727
|
const result = await client.post(`/agents/${id}/execute`, {
|
|
6979
8728
|
...payload,
|
|
@@ -6986,7 +8735,7 @@ Error: ${err.message}`));
|
|
|
6986
8735
|
}
|
|
6987
8736
|
} catch (error) {
|
|
6988
8737
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
6989
|
-
console.error(
|
|
8738
|
+
console.error(chalk14.red(`Execution failed: ${message}`));
|
|
6990
8739
|
process.exit(1);
|
|
6991
8740
|
}
|
|
6992
8741
|
}
|
|
@@ -6994,7 +8743,7 @@ Error: ${err.message}`));
|
|
|
6994
8743
|
|
|
6995
8744
|
// src/commands/models.ts
|
|
6996
8745
|
import { Command as Command13 } from "commander";
|
|
6997
|
-
import
|
|
8746
|
+
import chalk15 from "chalk";
|
|
6998
8747
|
import React14 from "react";
|
|
6999
8748
|
import { render as render12 } from "ink";
|
|
7000
8749
|
import { useState as useState20, useEffect as useEffect18 } from "react";
|
|
@@ -7028,7 +8777,7 @@ modelsCommand.command("list").description("List your enabled model configuration
|
|
|
7028
8777
|
}
|
|
7029
8778
|
} catch (error) {
|
|
7030
8779
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7031
|
-
console.error(
|
|
8780
|
+
console.error(chalk15.red(`Failed to fetch models: ${message}`));
|
|
7032
8781
|
process.exit(1);
|
|
7033
8782
|
}
|
|
7034
8783
|
return;
|
|
@@ -7093,7 +8842,7 @@ modelsCommand.command("available").description("List all available models groupe
|
|
|
7093
8842
|
}
|
|
7094
8843
|
} catch (error) {
|
|
7095
8844
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7096
|
-
console.error(
|
|
8845
|
+
console.error(chalk15.red(`Failed to fetch available models: ${message}`));
|
|
7097
8846
|
process.exit(1);
|
|
7098
8847
|
}
|
|
7099
8848
|
return;
|
|
@@ -7141,7 +8890,7 @@ modelsCommand.command("enable <modelId>").description("Enable a model by creatin
|
|
|
7141
8890
|
console.log(` Model: ${data.modelId}`);
|
|
7142
8891
|
} catch (error) {
|
|
7143
8892
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7144
|
-
console.error(
|
|
8893
|
+
console.error(chalk15.red(`Failed to enable model: ${message}`));
|
|
7145
8894
|
process.exit(1);
|
|
7146
8895
|
}
|
|
7147
8896
|
return;
|
|
@@ -7189,7 +8938,7 @@ modelsCommand.command("disable <id>").description("Disable a model configuration
|
|
|
7189
8938
|
console.log(JSON.stringify({ status: "disabled", id }, null, 2));
|
|
7190
8939
|
} catch (error) {
|
|
7191
8940
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7192
|
-
console.error(
|
|
8941
|
+
console.error(chalk15.red(`Failed to disable model: ${message}`));
|
|
7193
8942
|
process.exit(1);
|
|
7194
8943
|
}
|
|
7195
8944
|
return;
|
|
@@ -7229,7 +8978,7 @@ modelsCommand.command("default <id>").description("Set a model configuration as
|
|
|
7229
8978
|
console.log(JSON.stringify({ status: "updated", id }, null, 2));
|
|
7230
8979
|
} catch (error) {
|
|
7231
8980
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7232
|
-
console.error(
|
|
8981
|
+
console.error(chalk15.red(`Failed to set default model: ${message}`));
|
|
7233
8982
|
process.exit(1);
|
|
7234
8983
|
}
|
|
7235
8984
|
return;
|
|
@@ -7262,21 +9011,21 @@ modelsCommand.command("default <id>").description("Set a model configuration as
|
|
|
7262
9011
|
modelsCommand.command("usage").description("Show model usage statistics").option("--json", "Output as JSON").action(async () => {
|
|
7263
9012
|
const apiKey = await ensureAuth();
|
|
7264
9013
|
if (!apiKey) return;
|
|
7265
|
-
console.log(
|
|
9014
|
+
console.log(chalk15.gray("Fetching model usage..."));
|
|
7266
9015
|
try {
|
|
7267
9016
|
const client = new ApiClient(apiKey);
|
|
7268
9017
|
const data = await client.get("/model-configs/usage");
|
|
7269
9018
|
printJson(data);
|
|
7270
9019
|
} catch (error) {
|
|
7271
9020
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7272
|
-
console.error(
|
|
9021
|
+
console.error(chalk15.red(`Failed to fetch model usage: ${message}`));
|
|
7273
9022
|
process.exit(1);
|
|
7274
9023
|
}
|
|
7275
9024
|
});
|
|
7276
9025
|
|
|
7277
9026
|
// src/commands/schedules.ts
|
|
7278
9027
|
import { Command as Command14 } from "commander";
|
|
7279
|
-
import
|
|
9028
|
+
import chalk16 from "chalk";
|
|
7280
9029
|
import React15 from "react";
|
|
7281
9030
|
import { render as render13 } from "ink";
|
|
7282
9031
|
import { useState as useState21, useEffect as useEffect19 } from "react";
|
|
@@ -7317,7 +9066,7 @@ schedulesCommand.command("list").description("List all schedules").option("--jso
|
|
|
7317
9066
|
}
|
|
7318
9067
|
} catch (error) {
|
|
7319
9068
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7320
|
-
console.error(
|
|
9069
|
+
console.error(chalk16.red(`Failed to fetch schedules: ${message}`));
|
|
7321
9070
|
process.exit(1);
|
|
7322
9071
|
}
|
|
7323
9072
|
return;
|
|
@@ -7383,7 +9132,7 @@ schedulesCommand.command("get <id>").description("Get schedule details").option(
|
|
|
7383
9132
|
]);
|
|
7384
9133
|
} catch (error) {
|
|
7385
9134
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7386
|
-
console.error(
|
|
9135
|
+
console.error(chalk16.red(`Failed to fetch schedule: ${message}`));
|
|
7387
9136
|
process.exit(1);
|
|
7388
9137
|
}
|
|
7389
9138
|
return;
|
|
@@ -7439,7 +9188,7 @@ schedulesCommand.command("create").description("Create a new schedule").required
|
|
|
7439
9188
|
if (data.nextRunAt) console.log(` Next run: ${data.nextRunAt}`);
|
|
7440
9189
|
} catch (error) {
|
|
7441
9190
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7442
|
-
console.error(
|
|
9191
|
+
console.error(chalk16.red(`Failed to create schedule: ${message}`));
|
|
7443
9192
|
process.exit(1);
|
|
7444
9193
|
}
|
|
7445
9194
|
return;
|
|
@@ -7494,7 +9243,7 @@ function simpleMutationCommand(name, description, mutationFn, successMsg, loadin
|
|
|
7494
9243
|
console.log(JSON.stringify({ status: name, id }, null, 2));
|
|
7495
9244
|
} catch (error) {
|
|
7496
9245
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7497
|
-
console.error(
|
|
9246
|
+
console.error(chalk16.red(`Failed to ${name} schedule: ${message}`));
|
|
7498
9247
|
process.exit(1);
|
|
7499
9248
|
}
|
|
7500
9249
|
return;
|
|
@@ -7556,7 +9305,7 @@ schedulesCommand.command("delete <id>").description("Delete a schedule").option(
|
|
|
7556
9305
|
console.log(JSON.stringify({ status: "deleted", id }, null, 2));
|
|
7557
9306
|
} catch (error) {
|
|
7558
9307
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7559
|
-
console.error(
|
|
9308
|
+
console.error(chalk16.red(`Failed to delete schedule: ${message}`));
|
|
7560
9309
|
process.exit(1);
|
|
7561
9310
|
}
|
|
7562
9311
|
return;
|
|
@@ -7607,11 +9356,11 @@ schedulesCommand.command("delete <id>").description("Delete a schedule").option(
|
|
|
7607
9356
|
|
|
7608
9357
|
// src/commands/eval.ts
|
|
7609
9358
|
import { Command as Command15 } from "commander";
|
|
7610
|
-
import
|
|
9359
|
+
import chalk17 from "chalk";
|
|
7611
9360
|
import React16 from "react";
|
|
7612
9361
|
import { render as render14 } from "ink";
|
|
7613
9362
|
import { useState as useState22, useEffect as useEffect20 } from "react";
|
|
7614
|
-
import { Text as
|
|
9363
|
+
import { Text as Text23 } from "ink";
|
|
7615
9364
|
import { readFileSync as readFileSync5 } from "fs";
|
|
7616
9365
|
var evalCommand = new Command15("eval").description("Manage evaluations");
|
|
7617
9366
|
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").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
|
|
@@ -7624,7 +9373,7 @@ evalCommand.command("submit").description("Submit an eval batch").requiredOption
|
|
|
7624
9373
|
recordIds = Array.isArray(parsed) ? parsed : parsed.recordIds || parsed.records || [];
|
|
7625
9374
|
} catch (error) {
|
|
7626
9375
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7627
|
-
console.error(
|
|
9376
|
+
console.error(chalk17.red(`Failed to read records file: ${message}`));
|
|
7628
9377
|
process.exit(1);
|
|
7629
9378
|
return;
|
|
7630
9379
|
}
|
|
@@ -7639,8 +9388,8 @@ evalCommand.command("submit").description("Submit an eval batch").requiredOption
|
|
|
7639
9388
|
if (options.json) {
|
|
7640
9389
|
printJson(data);
|
|
7641
9390
|
} else {
|
|
7642
|
-
console.log(
|
|
7643
|
-
console.log(` Batch ID: ${
|
|
9391
|
+
console.log(chalk17.green("Eval submitted"));
|
|
9392
|
+
console.log(` Batch ID: ${chalk17.green(data.id)}`);
|
|
7644
9393
|
if (data.name) console.log(` Name: ${data.name}`);
|
|
7645
9394
|
console.log(` Status: ${data.status}`);
|
|
7646
9395
|
console.log(` Records: ${data.totalRecords}`);
|
|
@@ -7648,8 +9397,8 @@ evalCommand.command("submit").description("Submit an eval batch").requiredOption
|
|
|
7648
9397
|
}
|
|
7649
9398
|
} catch (error) {
|
|
7650
9399
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7651
|
-
console.error(
|
|
7652
|
-
console.error(
|
|
9400
|
+
console.error(chalk17.red("Failed to submit eval"));
|
|
9401
|
+
console.error(chalk17.red(message));
|
|
7653
9402
|
process.exit(1);
|
|
7654
9403
|
}
|
|
7655
9404
|
return;
|
|
@@ -7711,28 +9460,28 @@ evalCommand.command("list").description("List eval batches").option("--flow <id>
|
|
|
7711
9460
|
} else {
|
|
7712
9461
|
const batches = data.data ?? [];
|
|
7713
9462
|
if (batches.length === 0) {
|
|
7714
|
-
console.log(
|
|
9463
|
+
console.log(chalk17.gray("No eval batches found"));
|
|
7715
9464
|
return;
|
|
7716
9465
|
}
|
|
7717
|
-
console.log(
|
|
9466
|
+
console.log(chalk17.cyan("Eval Batches:"));
|
|
7718
9467
|
for (const batch of batches) {
|
|
7719
9468
|
const name = batch.name || batch.id;
|
|
7720
9469
|
const progress = batch.totalRecords ? `${batch.completedRecords ?? 0}/${batch.totalRecords}` : "";
|
|
7721
9470
|
const statusColor = batch.status === "completed" ? "green" : "yellow";
|
|
7722
9471
|
console.log(
|
|
7723
|
-
` ${
|
|
9472
|
+
` ${chalk17.green(batch.id)} ${name} ${chalk17[statusColor](`[${batch.status}]`)} ${chalk17.gray(progress)}`
|
|
7724
9473
|
);
|
|
7725
9474
|
}
|
|
7726
9475
|
const total = getTotalCount(data.pagination);
|
|
7727
9476
|
if (total !== void 0) {
|
|
7728
|
-
console.log(
|
|
9477
|
+
console.log(chalk17.dim(`
|
|
7729
9478
|
Total: ${total} batches`));
|
|
7730
9479
|
}
|
|
7731
9480
|
}
|
|
7732
9481
|
} catch (error) {
|
|
7733
9482
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7734
|
-
console.error(
|
|
7735
|
-
console.error(
|
|
9483
|
+
console.error(chalk17.red("Failed to fetch eval batches"));
|
|
9484
|
+
console.error(chalk17.red(message));
|
|
7736
9485
|
process.exit(1);
|
|
7737
9486
|
}
|
|
7738
9487
|
return;
|
|
@@ -7769,7 +9518,7 @@ evalCommand.command("list").description("List eval batches").option("--flow <id>
|
|
|
7769
9518
|
const progress = b.totalRecords ? `${b.completedRecords ?? 0}/${b.totalRecords}` : "";
|
|
7770
9519
|
const statusColor = b.status === "completed" ? "green" : "yellow";
|
|
7771
9520
|
return React16.createElement(
|
|
7772
|
-
|
|
9521
|
+
Text23,
|
|
7773
9522
|
{ color: statusColor },
|
|
7774
9523
|
` ${b.id} ${name} [${b.status}] ${progress}`
|
|
7775
9524
|
);
|
|
@@ -7790,29 +9539,29 @@ evalCommand.command("results <id>").description("Get eval batch results").option
|
|
|
7790
9539
|
printJson(data);
|
|
7791
9540
|
} else {
|
|
7792
9541
|
if (data.batch) {
|
|
7793
|
-
console.log(
|
|
9542
|
+
console.log(chalk17.cyan(`Eval: ${data.batch.name || data.batch.id}`));
|
|
7794
9543
|
console.log(` Status: ${data.batch.status}`);
|
|
7795
9544
|
console.log(` Progress: ${data.batch.completedRecords ?? 0}/${data.batch.totalRecords ?? 0}`);
|
|
7796
9545
|
console.log();
|
|
7797
9546
|
}
|
|
7798
9547
|
const results = data.data ?? [];
|
|
7799
9548
|
if (results.length === 0) {
|
|
7800
|
-
console.log(
|
|
9549
|
+
console.log(chalk17.gray("No results yet"));
|
|
7801
9550
|
return;
|
|
7802
9551
|
}
|
|
7803
|
-
console.log(
|
|
9552
|
+
console.log(chalk17.cyan("Results:"));
|
|
7804
9553
|
for (const result of results) {
|
|
7805
|
-
const scoreStr = result.score !== void 0 ?
|
|
9554
|
+
const scoreStr = result.score !== void 0 ? chalk17.blue(` score=${result.score}`) : "";
|
|
7806
9555
|
const statusColor = result.status === "completed" ? "green" : "red";
|
|
7807
9556
|
console.log(
|
|
7808
|
-
` ${
|
|
9557
|
+
` ${chalk17.gray(result.recordId)} ${chalk17[statusColor](`[${result.status}]`)}${scoreStr}`
|
|
7809
9558
|
);
|
|
7810
9559
|
}
|
|
7811
9560
|
}
|
|
7812
9561
|
} catch (error) {
|
|
7813
9562
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7814
|
-
console.error(
|
|
7815
|
-
console.error(
|
|
9563
|
+
console.error(chalk17.red("Failed to fetch eval results"));
|
|
9564
|
+
console.error(chalk17.red(message));
|
|
7816
9565
|
process.exit(1);
|
|
7817
9566
|
}
|
|
7818
9567
|
return;
|
|
@@ -7875,8 +9624,8 @@ evalCommand.command("compare <groupId>").description("Compare evals in a group")
|
|
|
7875
9624
|
printJson(data);
|
|
7876
9625
|
} catch (error) {
|
|
7877
9626
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7878
|
-
console.error(
|
|
7879
|
-
console.error(
|
|
9627
|
+
console.error(chalk17.red("Failed to compare evals"));
|
|
9628
|
+
console.error(chalk17.red(message));
|
|
7880
9629
|
process.exit(1);
|
|
7881
9630
|
}
|
|
7882
9631
|
return;
|
|
@@ -7914,11 +9663,11 @@ evalCommand.command("compare <groupId>").description("Compare evals in a group")
|
|
|
7914
9663
|
|
|
7915
9664
|
// src/commands/api-keys.ts
|
|
7916
9665
|
import { Command as Command16 } from "commander";
|
|
7917
|
-
import
|
|
9666
|
+
import chalk18 from "chalk";
|
|
7918
9667
|
import React17 from "react";
|
|
7919
9668
|
import { render as render15 } from "ink";
|
|
7920
9669
|
import { useState as useState23, useEffect as useEffect21 } from "react";
|
|
7921
|
-
import { Text as
|
|
9670
|
+
import { Text as Text24 } from "ink";
|
|
7922
9671
|
var apiKeysCommand = new Command16("api-keys").description("Manage API keys");
|
|
7923
9672
|
apiKeysCommand.command("list").description("List your API keys").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
|
|
7924
9673
|
const apiKey = await ensureAuth();
|
|
@@ -7932,25 +9681,25 @@ apiKeysCommand.command("list").description("List your API keys").option("--json"
|
|
|
7932
9681
|
} else {
|
|
7933
9682
|
const keys = data.data ?? [];
|
|
7934
9683
|
if (keys.length === 0) {
|
|
7935
|
-
console.log(
|
|
9684
|
+
console.log(chalk18.gray("No API keys found"));
|
|
7936
9685
|
return;
|
|
7937
9686
|
}
|
|
7938
|
-
console.log(
|
|
9687
|
+
console.log(chalk18.cyan("Your API Keys:"));
|
|
7939
9688
|
for (const key of keys) {
|
|
7940
|
-
const prefix = key.prefix ?
|
|
7941
|
-
const lastUsed = key.lastUsedAt ?
|
|
7942
|
-
console.log(` ${
|
|
9689
|
+
const prefix = key.prefix ? chalk18.gray(` (${key.prefix}...)`) : "";
|
|
9690
|
+
const lastUsed = key.lastUsedAt ? chalk18.gray(` last used: ${key.lastUsedAt}`) : "";
|
|
9691
|
+
console.log(` ${chalk18.green(key.id)} ${key.name}${prefix}${lastUsed}`);
|
|
7943
9692
|
}
|
|
7944
9693
|
const total = getTotalCount(data.pagination);
|
|
7945
9694
|
if (total !== void 0) {
|
|
7946
|
-
console.log(
|
|
9695
|
+
console.log(chalk18.dim(`
|
|
7947
9696
|
Total: ${total} keys`));
|
|
7948
9697
|
}
|
|
7949
9698
|
}
|
|
7950
9699
|
} catch (error) {
|
|
7951
9700
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7952
|
-
console.error(
|
|
7953
|
-
console.error(
|
|
9701
|
+
console.error(chalk18.red("Failed to fetch API keys"));
|
|
9702
|
+
console.error(chalk18.red(message));
|
|
7954
9703
|
process.exit(1);
|
|
7955
9704
|
}
|
|
7956
9705
|
return;
|
|
@@ -7985,7 +9734,7 @@ apiKeysCommand.command("list").description("List your API keys").option("--json"
|
|
|
7985
9734
|
const k = item;
|
|
7986
9735
|
const prefix = k.prefix ? ` (${k.prefix}...)` : "";
|
|
7987
9736
|
const lastUsed = k.lastUsedAt ? ` last used: ${k.lastUsedAt}` : "";
|
|
7988
|
-
return React17.createElement(
|
|
9737
|
+
return React17.createElement(Text24, null, ` ${k.id} ${k.name}${prefix}${lastUsed}`);
|
|
7989
9738
|
}
|
|
7990
9739
|
});
|
|
7991
9740
|
};
|
|
@@ -8013,8 +9762,8 @@ apiKeysCommand.command("get <id>").description("Get API key details").option("--
|
|
|
8013
9762
|
}
|
|
8014
9763
|
} catch (error) {
|
|
8015
9764
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8016
|
-
console.error(
|
|
8017
|
-
console.error(
|
|
9765
|
+
console.error(chalk18.red("Failed to fetch API key"));
|
|
9766
|
+
console.error(chalk18.red(message));
|
|
8018
9767
|
process.exit(1);
|
|
8019
9768
|
}
|
|
8020
9769
|
return;
|
|
@@ -8072,18 +9821,18 @@ apiKeysCommand.command("create").description("Create a new API key").requiredOpt
|
|
|
8072
9821
|
if (options.json) {
|
|
8073
9822
|
printJson(data);
|
|
8074
9823
|
} else {
|
|
8075
|
-
console.log(
|
|
8076
|
-
console.log(` ID: ${
|
|
9824
|
+
console.log(chalk18.green("API key created"));
|
|
9825
|
+
console.log(` ID: ${chalk18.green(data.id)}`);
|
|
8077
9826
|
console.log(` Name: ${data.name}`);
|
|
8078
9827
|
if (data.key) {
|
|
8079
|
-
console.log(` Key: ${
|
|
8080
|
-
console.log(
|
|
9828
|
+
console.log(` Key: ${chalk18.yellow(data.key)}`);
|
|
9829
|
+
console.log(chalk18.gray(" Save this key - it will not be shown again"));
|
|
8081
9830
|
}
|
|
8082
9831
|
}
|
|
8083
9832
|
} catch (error) {
|
|
8084
9833
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8085
|
-
console.error(
|
|
8086
|
-
console.error(
|
|
9834
|
+
console.error(chalk18.red("Failed to create API key"));
|
|
9835
|
+
console.error(chalk18.red(message));
|
|
8087
9836
|
process.exit(1);
|
|
8088
9837
|
}
|
|
8089
9838
|
return;
|
|
@@ -8137,11 +9886,11 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
|
|
|
8137
9886
|
if (!isTTY(options)) {
|
|
8138
9887
|
try {
|
|
8139
9888
|
await client.delete(`/api-keys/${id}`);
|
|
8140
|
-
console.log(
|
|
9889
|
+
console.log(chalk18.green("API key deleted"));
|
|
8141
9890
|
} catch (error) {
|
|
8142
9891
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8143
|
-
console.error(
|
|
8144
|
-
console.error(
|
|
9892
|
+
console.error(chalk18.red("Failed to delete API key"));
|
|
9893
|
+
console.error(chalk18.red(message));
|
|
8145
9894
|
process.exit(1);
|
|
8146
9895
|
}
|
|
8147
9896
|
return;
|
|
@@ -8177,13 +9926,13 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
|
|
|
8177
9926
|
await waitUntilExit2();
|
|
8178
9927
|
return;
|
|
8179
9928
|
}
|
|
8180
|
-
const confirmed = await new Promise((
|
|
9929
|
+
const confirmed = await new Promise((resolve2) => {
|
|
8181
9930
|
const { unmount } = render15(
|
|
8182
9931
|
React17.createElement(ConfirmPrompt, {
|
|
8183
9932
|
message: `Delete API key ${id}?`,
|
|
8184
9933
|
defaultValue: false,
|
|
8185
9934
|
onConfirm: (result) => {
|
|
8186
|
-
|
|
9935
|
+
resolve2(result);
|
|
8187
9936
|
unmount();
|
|
8188
9937
|
}
|
|
8189
9938
|
})
|
|
@@ -8229,16 +9978,16 @@ apiKeysCommand.command("regenerate <id>").description("Regenerate an API key").o
|
|
|
8229
9978
|
if (options.json) {
|
|
8230
9979
|
printJson(data);
|
|
8231
9980
|
} else {
|
|
8232
|
-
console.log(
|
|
9981
|
+
console.log(chalk18.green("API key regenerated"));
|
|
8233
9982
|
if (data.key) {
|
|
8234
|
-
console.log(` New Key: ${
|
|
8235
|
-
console.log(
|
|
9983
|
+
console.log(` New Key: ${chalk18.yellow(data.key)}`);
|
|
9984
|
+
console.log(chalk18.gray(" Save this key - it will not be shown again"));
|
|
8236
9985
|
}
|
|
8237
9986
|
}
|
|
8238
9987
|
} catch (error) {
|
|
8239
9988
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8240
|
-
console.error(
|
|
8241
|
-
console.error(
|
|
9989
|
+
console.error(chalk18.red("Failed to regenerate API key"));
|
|
9990
|
+
console.error(chalk18.red(message));
|
|
8242
9991
|
process.exit(1);
|
|
8243
9992
|
}
|
|
8244
9993
|
return;
|
|
@@ -8293,8 +10042,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
|
|
|
8293
10042
|
printJson(data);
|
|
8294
10043
|
} catch (error) {
|
|
8295
10044
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8296
|
-
console.error(
|
|
8297
|
-
console.error(
|
|
10045
|
+
console.error(chalk18.red("Failed to fetch analytics"));
|
|
10046
|
+
console.error(chalk18.red(message));
|
|
8298
10047
|
process.exit(1);
|
|
8299
10048
|
}
|
|
8300
10049
|
return;
|
|
@@ -8333,11 +10082,11 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
|
|
|
8333
10082
|
|
|
8334
10083
|
// src/commands/analytics.ts
|
|
8335
10084
|
import { Command as Command17 } from "commander";
|
|
8336
|
-
import
|
|
10085
|
+
import chalk19 from "chalk";
|
|
8337
10086
|
import React18 from "react";
|
|
8338
10087
|
import { render as render16 } from "ink";
|
|
8339
10088
|
import { useState as useState24, useEffect as useEffect22 } from "react";
|
|
8340
|
-
import { Text as
|
|
10089
|
+
import { Text as Text25 } from "ink";
|
|
8341
10090
|
var analyticsCommand = new Command17("analytics").description("View analytics and execution results");
|
|
8342
10091
|
analyticsCommand.command("stats").description("Show account statistics").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
|
|
8343
10092
|
const apiKey = await ensureAuth();
|
|
@@ -8358,8 +10107,8 @@ analyticsCommand.command("stats").description("Show account statistics").option(
|
|
|
8358
10107
|
}
|
|
8359
10108
|
} catch (error) {
|
|
8360
10109
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8361
|
-
console.error(
|
|
8362
|
-
console.error(
|
|
10110
|
+
console.error(chalk19.red("Failed to fetch stats"));
|
|
10111
|
+
console.error(chalk19.red(message));
|
|
8363
10112
|
process.exit(1);
|
|
8364
10113
|
}
|
|
8365
10114
|
return;
|
|
@@ -8423,27 +10172,27 @@ analyticsCommand.command("results").description("List execution results").option
|
|
|
8423
10172
|
} else {
|
|
8424
10173
|
const results = data.data ?? [];
|
|
8425
10174
|
if (results.length === 0) {
|
|
8426
|
-
console.log(
|
|
10175
|
+
console.log(chalk19.gray("No results found"));
|
|
8427
10176
|
return;
|
|
8428
10177
|
}
|
|
8429
|
-
console.log(
|
|
10178
|
+
console.log(chalk19.cyan("Execution Results:"));
|
|
8430
10179
|
for (const result of results) {
|
|
8431
10180
|
const statusColor = result.status === "completed" ? "green" : "red";
|
|
8432
|
-
const date = result.createdAt ?
|
|
10181
|
+
const date = result.createdAt ? chalk19.gray(` ${result.createdAt}`) : "";
|
|
8433
10182
|
console.log(
|
|
8434
|
-
` ${
|
|
10183
|
+
` ${chalk19.green(result.id)} ${chalk19[statusColor](`[${result.status}]`)} flow=${chalk19.gray(result.flowId)} record=${chalk19.gray(result.recordId)}${date}`
|
|
8435
10184
|
);
|
|
8436
10185
|
}
|
|
8437
10186
|
const total = getTotalCount(data.pagination);
|
|
8438
10187
|
if (total !== void 0) {
|
|
8439
|
-
console.log(
|
|
10188
|
+
console.log(chalk19.dim(`
|
|
8440
10189
|
Total: ${total} results`));
|
|
8441
10190
|
}
|
|
8442
10191
|
}
|
|
8443
10192
|
} catch (error) {
|
|
8444
10193
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8445
|
-
console.error(
|
|
8446
|
-
console.error(
|
|
10194
|
+
console.error(chalk19.red("Failed to fetch results"));
|
|
10195
|
+
console.error(chalk19.red(message));
|
|
8447
10196
|
process.exit(1);
|
|
8448
10197
|
}
|
|
8449
10198
|
return;
|
|
@@ -8481,7 +10230,7 @@ analyticsCommand.command("results").description("List execution results").option
|
|
|
8481
10230
|
const r = item;
|
|
8482
10231
|
const statusColor = r.status === "completed" ? "green" : "red";
|
|
8483
10232
|
return React18.createElement(
|
|
8484
|
-
|
|
10233
|
+
Text25,
|
|
8485
10234
|
{ color: statusColor },
|
|
8486
10235
|
` ${r.id} [${r.status}] flow=${r.flowId} record=${r.recordId}${r.createdAt ? ` ${r.createdAt}` : ""}`
|
|
8487
10236
|
);
|
|
@@ -8495,7 +10244,7 @@ analyticsCommand.command("results").description("List execution results").option
|
|
|
8495
10244
|
|
|
8496
10245
|
// src/commands/billing.ts
|
|
8497
10246
|
import { Command as Command18 } from "commander";
|
|
8498
|
-
import
|
|
10247
|
+
import chalk20 from "chalk";
|
|
8499
10248
|
import React19 from "react";
|
|
8500
10249
|
import { render as render17 } from "ink";
|
|
8501
10250
|
import { useState as useState25, useEffect as useEffect23 } from "react";
|
|
@@ -8537,8 +10286,8 @@ billingCommand.command("status").description("Show current plan and usage").opti
|
|
|
8537
10286
|
}
|
|
8538
10287
|
} catch (error) {
|
|
8539
10288
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8540
|
-
console.error(
|
|
8541
|
-
console.error(
|
|
10289
|
+
console.error(chalk20.red("Failed to fetch billing status"));
|
|
10290
|
+
console.error(chalk20.red(message));
|
|
8542
10291
|
process.exit(1);
|
|
8543
10292
|
}
|
|
8544
10293
|
return;
|
|
@@ -8608,8 +10357,8 @@ billingCommand.command("portal").description("Open the billing portal in your br
|
|
|
8608
10357
|
}
|
|
8609
10358
|
} catch (error) {
|
|
8610
10359
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8611
|
-
console.error(
|
|
8612
|
-
console.error(
|
|
10360
|
+
console.error(chalk20.red("Failed to open billing portal"));
|
|
10361
|
+
console.error(chalk20.red(message));
|
|
8613
10362
|
process.exit(1);
|
|
8614
10363
|
}
|
|
8615
10364
|
return;
|
|
@@ -8658,11 +10407,11 @@ billingCommand.command("refresh").description("Refresh plan data from billing pr
|
|
|
8658
10407
|
if (!isTTY(options)) {
|
|
8659
10408
|
try {
|
|
8660
10409
|
await client.post("/billing/refresh");
|
|
8661
|
-
console.log(
|
|
10410
|
+
console.log(chalk20.green("Plan data refreshed"));
|
|
8662
10411
|
} catch (error) {
|
|
8663
10412
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8664
|
-
console.error(
|
|
8665
|
-
console.error(
|
|
10413
|
+
console.error(chalk20.red("Failed to refresh plan data"));
|
|
10414
|
+
console.error(chalk20.red(message));
|
|
8666
10415
|
process.exit(1);
|
|
8667
10416
|
}
|
|
8668
10417
|
return;
|
|
@@ -8699,11 +10448,11 @@ billingCommand.command("refresh").description("Refresh plan data from billing pr
|
|
|
8699
10448
|
|
|
8700
10449
|
// src/commands/flow-versions.ts
|
|
8701
10450
|
import { Command as Command19 } from "commander";
|
|
8702
|
-
import
|
|
10451
|
+
import chalk21 from "chalk";
|
|
8703
10452
|
import React20 from "react";
|
|
8704
10453
|
import { render as render18 } from "ink";
|
|
8705
10454
|
import { useState as useState26, useEffect as useEffect24 } from "react";
|
|
8706
|
-
import { Text as
|
|
10455
|
+
import { Text as Text26 } from "ink";
|
|
8707
10456
|
var flowVersionsCommand = new Command19("flow-versions").description(
|
|
8708
10457
|
"Manage flow versions"
|
|
8709
10458
|
);
|
|
@@ -8719,21 +10468,21 @@ flowVersionsCommand.command("list <flowId>").description("List all versions for
|
|
|
8719
10468
|
} else {
|
|
8720
10469
|
const versions = data.data ?? [];
|
|
8721
10470
|
if (versions.length === 0) {
|
|
8722
|
-
console.log(
|
|
10471
|
+
console.log(chalk21.gray("No versions found"));
|
|
8723
10472
|
return;
|
|
8724
10473
|
}
|
|
8725
|
-
console.log(
|
|
10474
|
+
console.log(chalk21.cyan(`Versions for flow ${flowId}:`));
|
|
8726
10475
|
for (const v of versions) {
|
|
8727
|
-
const publishedTag = v.published ?
|
|
10476
|
+
const publishedTag = v.published ? chalk21.green(" [published]") : "";
|
|
8728
10477
|
const versionNum = v.version !== void 0 ? `v${v.version}` : v.id;
|
|
8729
|
-
const date = v.createdAt ?
|
|
8730
|
-
console.log(` ${
|
|
10478
|
+
const date = v.createdAt ? chalk21.gray(` ${v.createdAt}`) : "";
|
|
10479
|
+
console.log(` ${chalk21.green(v.id)} ${versionNum}${publishedTag}${date}`);
|
|
8731
10480
|
}
|
|
8732
10481
|
}
|
|
8733
10482
|
} catch (error) {
|
|
8734
10483
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8735
|
-
console.error(
|
|
8736
|
-
console.error(
|
|
10484
|
+
console.error(chalk21.red("Failed to fetch versions"));
|
|
10485
|
+
console.error(chalk21.red(message));
|
|
8737
10486
|
process.exit(1);
|
|
8738
10487
|
}
|
|
8739
10488
|
return;
|
|
@@ -8765,7 +10514,7 @@ flowVersionsCommand.command("list <flowId>").description("List all versions for
|
|
|
8765
10514
|
const v = item;
|
|
8766
10515
|
const publishedTag = v.published ? " [published]" : "";
|
|
8767
10516
|
const versionNum = v.version !== void 0 ? `v${v.version}` : v.id;
|
|
8768
|
-
return React20.createElement(
|
|
10517
|
+
return React20.createElement(Text26, null, ` ${v.id} ${versionNum}${publishedTag}${v.createdAt ? ` ${v.createdAt}` : ""}`);
|
|
8769
10518
|
}
|
|
8770
10519
|
});
|
|
8771
10520
|
};
|
|
@@ -8793,8 +10542,8 @@ flowVersionsCommand.command("get <flowId> <versionId>").description("Get a speci
|
|
|
8793
10542
|
}
|
|
8794
10543
|
} catch (error) {
|
|
8795
10544
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8796
|
-
console.error(
|
|
8797
|
-
console.error(
|
|
10545
|
+
console.error(chalk21.red("Failed to fetch version"));
|
|
10546
|
+
console.error(chalk21.red(message));
|
|
8798
10547
|
process.exit(1);
|
|
8799
10548
|
}
|
|
8800
10549
|
return;
|
|
@@ -8859,8 +10608,8 @@ flowVersionsCommand.command("published <flowId>").description("Get the published
|
|
|
8859
10608
|
}
|
|
8860
10609
|
} catch (error) {
|
|
8861
10610
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8862
|
-
console.error(
|
|
8863
|
-
console.error(
|
|
10611
|
+
console.error(chalk21.red("Failed to fetch published version"));
|
|
10612
|
+
console.error(chalk21.red(message));
|
|
8864
10613
|
process.exit(1);
|
|
8865
10614
|
}
|
|
8866
10615
|
return;
|
|
@@ -8913,11 +10662,11 @@ flowVersionsCommand.command("publish <flowId>").description("Publish a version")
|
|
|
8913
10662
|
await client.post(`/flow-versions/${flowId}/publish`, {
|
|
8914
10663
|
versionId: options.version
|
|
8915
10664
|
});
|
|
8916
|
-
console.log(
|
|
10665
|
+
console.log(chalk21.green("Version published"));
|
|
8917
10666
|
} catch (error) {
|
|
8918
10667
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
8919
|
-
console.error(
|
|
8920
|
-
console.error(
|
|
10668
|
+
console.error(chalk21.red("Failed to publish version"));
|
|
10669
|
+
console.error(chalk21.red(message));
|
|
8921
10670
|
process.exit(1);
|
|
8922
10671
|
}
|
|
8923
10672
|
return;
|
|
@@ -8999,15 +10748,15 @@ try {
|
|
|
8999
10748
|
} catch (error) {
|
|
9000
10749
|
const commanderError = error;
|
|
9001
10750
|
if (commanderError.code === "commander.missingArgument") {
|
|
9002
|
-
console.error(
|
|
10751
|
+
console.error(chalk22.red(`Error: ${commanderError.message}`));
|
|
9003
10752
|
process.exit(1);
|
|
9004
10753
|
} else if (commanderError.code === "commander.unknownOption") {
|
|
9005
|
-
console.error(
|
|
10754
|
+
console.error(chalk22.red(`Error: ${commanderError.message}`));
|
|
9006
10755
|
process.exit(1);
|
|
9007
10756
|
} else if (commanderError.code === "commander.help" || commanderError.code === "commander.version") {
|
|
9008
10757
|
process.exit(0);
|
|
9009
10758
|
} else {
|
|
9010
|
-
console.error(
|
|
10759
|
+
console.error(chalk22.red("An unexpected error occurred:"));
|
|
9011
10760
|
console.error(error);
|
|
9012
10761
|
process.exit(1);
|
|
9013
10762
|
}
|
|
@@ -9016,12 +10765,12 @@ async function handleNoCommand() {
|
|
|
9016
10765
|
const store = new CredentialStore();
|
|
9017
10766
|
const hasCredentials = await store.hasCredentials();
|
|
9018
10767
|
if (!hasCredentials) {
|
|
9019
|
-
console.log(
|
|
10768
|
+
console.log(chalk22.cyan("\nWelcome to Runtype CLI!\n"));
|
|
9020
10769
|
console.log("It looks like this is your first time. Run the setup wizard:");
|
|
9021
|
-
console.log(` ${
|
|
10770
|
+
console.log(` ${chalk22.green("runtype init")}
|
|
9022
10771
|
`);
|
|
9023
10772
|
console.log("Or see all available commands:");
|
|
9024
|
-
console.log(` ${
|
|
10773
|
+
console.log(` ${chalk22.green("runtype --help")}
|
|
9025
10774
|
`);
|
|
9026
10775
|
} else {
|
|
9027
10776
|
try {
|