@runtypelabs/cli 1.3.0 → 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 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 chalk21 from "chalk";
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((resolve, reject) => {
158
- this.codeResolve = resolve;
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.close();
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 chalk4 from "chalk";
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 readline from "readline";
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 = readline.createInterface({
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((resolve) => {
1347
- rl.question(chalk2.cyan(`${message} (${hint}): `), (answer) => {
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
- resolve(defaultYes);
1485
+ resolve2(defaultYes);
1352
1486
  } else {
1353
- resolve(trimmed === "y" || trimmed === "yes");
1487
+ resolve2(trimmed === "y" || trimmed === "yes");
1354
1488
  }
1355
1489
  });
1356
1490
  });
1357
1491
  }
1358
1492
  async function promptText(message) {
1359
- const rl = readline.createInterface({
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((resolve) => {
1365
- rl.question(chalk2.cyan(`${message}: `), (answer) => {
1498
+ return new Promise((resolve2) => {
1499
+ rl.question(chalk3.cyan(`${message}: `), (answer) => {
1366
1500
  rl.close();
1367
- resolve(answer.trim());
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(chalk2.yellow("\nAuthentication required."));
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(chalk2.gray(`Run "runtype auth login" when you're ready.`));
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(chalk2.red("No API key provided."));
1532
+ console.log(chalk3.red("No API key provided."));
1428
1533
  return null;
1429
1534
  }
1430
- console.log(chalk2.gray("Validating API key..."));
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(chalk2.red("Invalid API key"));
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(chalk2.green("Logged in successfully!"));
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(chalk2.red("Login failed"));
1452
- console.error(chalk2.red(message));
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(chalk2.gray("Initializing authentication..."));
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(chalk2.gray("Waiting for browser authentication..."));
1568
+ console.log(chalk3.gray("Waiting for browser authentication..."));
1464
1569
  const sessionToken = await oauth.authenticate("sign-in");
1465
- console.log(chalk2.gray("Getting API key..."));
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(chalk2.gray("Storing credentials..."));
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(chalk2.green("Logged in successfully!"));
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(chalk2.red("Login failed"));
1483
- console.error(chalk2.red(message));
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 chalk3 from "chalk";
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(chalk3.cyan(`${options.title}:`));
1717
+ console.log(chalk4.cyan(`${options.title}:`));
1613
1718
  if (items.length === 0) {
1614
- console.log(chalk3.gray(` ${options.emptyMessage || "None found"}`));
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 ? chalk3[col.color] : (s) => s;
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(chalk3.dim(`
1738
+ console.log(chalk4.dim(`
1634
1739
  Total: ${options.total}`));
1635
1740
  }
1636
1741
  }
1637
1742
  function printDetail(title, fields) {
1638
- console.log(chalk3.cyan(`${title}:`));
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(` ${chalk3.gray(field.label + ":")} ${str}`);
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(chalk4.red(`Failed to fetch flows: ${message}`));
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(chalk4.red(`Failed to fetch flow: ${message}`));
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(chalk4.gray("Starting flow..."));
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(chalk4.red(`
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(chalk4.red(`Flow execution failed: ${message}`));
1904
+ console.error(chalk5.red(`Flow execution failed: ${message}`));
1800
1905
  process.exit(1);
1801
1906
  }
1802
1907
  } else {
1803
- console.log(chalk4.gray("Executing flow..."));
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(chalk4.green("Flow execution complete"));
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(chalk4.red(`Flow execution failed: ${message}`));
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(chalk4.red(`Failed to read flow file: ${msg}`));
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: ${chalk4.green(data.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(chalk4.red(`Failed to create flow: ${message}`));
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(chalk4.red(`Failed to delete flow: ${message}`));
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 chalk5 from "chalk";
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(chalk5.red(`Failed to fetch records: ${message}`));
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(chalk5.red(`Failed to fetch record: ${message}`));
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(chalk5.red("Invalid JSON in metadata"));
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(chalk5.red(`Failed to create record: ${message}`));
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(chalk5.red(`Failed to delete record: ${message}`));
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(chalk5.gray("Exporting records..."));
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(chalk5.yellow("No records to export"));
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(chalk5.green(`Exported ${records.length} records to ${filename}`));
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(chalk5.red(`Failed to export records: ${message}`));
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 chalk6 from "chalk";
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(chalk6.red(`Failed to fetch prompts: ${message}`));
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(chalk6.red(`Failed to fetch prompt: ${message}`));
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(chalk6.gray("Testing prompt..."));
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(chalk6.red(`
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(chalk6.red(`Prompt test failed: ${message}`));
2533
+ console.error(chalk7.red(`Prompt test failed: ${message}`));
2429
2534
  process.exit(1);
2430
2535
  }
2431
2536
  } else {
2432
- console.log(chalk6.gray("Testing prompt..."));
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(chalk6.green("Prompt test complete"));
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(chalk6.red(`Prompt test failed: ${message}`));
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 chalk7 from "chalk";
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(chalk7.red(`Failed to read records file: ${msg}`));
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(chalk7.green("Batch submitted"));
2483
- console.log(` Batch ID: ${chalk7.green(data.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(chalk7.red("Failed to submit batch"));
2489
- console.error(chalk7.red(message));
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(chalk7.cyan(`Batch Job: ${batchId}`));
2545
- console.log(` Status: ${chalk7.green(data.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: ${chalk7.red(data.failedRecords)}`);
2653
+ console.log(` Failed: ${chalk8.red(data.failedRecords)}`);
2549
2654
  }
2550
2655
  if (options.watch && data.status === "processing") {
2551
- console.log(chalk7.gray("\nWatching for updates... (Ctrl+C to stop)"));
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(chalk7.red("Failed to fetch batch status"));
2557
- console.error(chalk7.red(message));
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(chalk7.green("Batch job cancelled"));
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(chalk7.red("Failed to cancel batch job"));
2613
- console.error(chalk7.red(message));
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 chalk8 from "chalk";
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 [relative, setRelative] = useState8(() => formatRelativeTime(timestamp));
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 relative;
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(chalk8.green(`Loaded session from: ${options.continue}`));
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(chalk8.red(`Failed to load session: ${message}`));
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(chalk8.red(`Talk failed: ${message}`));
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 chalk9 from "chalk";
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(chalk9.yellow(`Configuration key '${key}' not found`));
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(chalk9.yellow(`Configuration key '${key}' not found`));
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(chalk9.cyan("Current Configuration:"));
3691
+ console.log(chalk10.cyan("Current Configuration:"));
3587
3692
  for (const [k, v] of Object.entries(allConfig)) {
3588
- console.log(` ${chalk9.green(k)}: ${v}`);
3693
+ console.log(` ${chalk10.green(k)}: ${v}`);
3589
3694
  }
3590
3695
  } else {
3591
- console.log(chalk9.gray("No configuration set"));
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(chalk9.red(`Invalid configuration key: ${key}`));
3598
- console.log(chalk9.gray(`Valid keys: ${CLI_CONFIG_KEYS.join(", ")}`));
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(chalk9.red("Temperature must be a number between 0 and 1"));
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(chalk9.red("Output format must be: table, json, or plain"));
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(chalk9.green(`Configuration updated: ${key} = ${parsedValue}`));
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(chalk9.green("Configuration reset to defaults"));
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 chalk10 from "chalk";
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(chalk10.cyan("\nAgent Details:"));
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(` ${chalk10.cyan("\u2022")} ${skill.name}${desc}`);
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(chalk10.cyan("\nNext steps:"));
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(chalk10.red("--from URL required in non-TTY mode"));
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(chalk10.red(result.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(chalk10.cyan("\nOpening browser to complete setup..."));
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(chalk10.red(createResult.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(chalk10.red(`Failed: ${message}`));
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 chalk11 from "chalk";
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(chalk11.red("Error: Either --flow or --agent is required"));
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(chalk11.red(`Failed to read record JSON: ${message}`));
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(chalk11.gray("Starting execution..."));
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(chalk11.cyan(`Flow: ${event.flowName} (${event.totalSteps} steps)`));
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(chalk11.gray(`
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(chalk11.gray(`
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(chalk11.red(`
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(chalk11.red("Execution failed"));
4868
- console.error(chalk11.red(message));
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(chalk11.cyan(`
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(chalk11.red("Execution failed"));
4898
- console.error(chalk11.red(message));
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(chalk11.cyan(`
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 chalk13 from "chalk";
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 chalk12 from "chalk";
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 Box20, useApp as useApp5, useInput as useInput9, useStdout as useStdout2 } from "ink";
4971
- import { StreamOutput as StreamOutput3, StatusBar as StatusBar2, ErrorDisplay as ErrorDisplay4, theme as theme21 } from "@runtypelabs/ink-components";
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
- if (event.contentType === "text") {
5016
- setState((prev) => ({
5017
- ...prev,
5144
+ setState((prev) => ({
5145
+ ...prev,
5146
+ ...event.contentType === "text" ? {
5018
5147
  phase: "streaming",
5019
- content: prev.content + event.delta,
5020
- thinkingStartedAt: null,
5021
- rawEvents: pushRawEvent(prev, "agent_turn_delta", { contentType: event.contentType, deltaLength: event.delta.length })
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
- const newTool = {
5035
- id: uniqueId,
5036
- sourceToolCallId: event.toolCallId,
5037
- name: event.toolName,
5038
- toolType: event.toolType,
5039
- status: "running",
5040
- parameters: event.parameters,
5041
- startedAt: Date.now()
5042
- };
5043
- setState((prev) => ({
5044
- ...prev,
5045
- phase: "tool",
5046
- thinkingStartedAt: null,
5047
- tools: [...prev.tools, newTool],
5048
- rawEvents: pushRawEvent(prev, "agent_tool_start", { ...event })
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
- return { state, callbacks, reset, setSteering, resetForNewSession };
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 theme15 } from "@runtypelabs/ink-components";
5168
- import { jsx as jsx16 } from "react/jsx-runtime";
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__ */ jsx16(Spinner5, { label: `Thinking... ${elapsed}s`, color: theme15.muted });
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 { theme as theme17 } from "@runtypelabs/ink-components";
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 Box15, Text as Text15 } from "ink";
5191
- import { Spinner as Spinner6, theme as theme16 } from "@runtypelabs/ink-components";
5192
- import { Fragment, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
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__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
5199
- /* @__PURE__ */ jsxs15(Box15, { children: [
5200
- tool.status === "running" && /* @__PURE__ */ jsxs15(Fragment, { children: [
5201
- /* @__PURE__ */ jsx17(Spinner6, { label: "", color: theme16.spinner }),
5202
- /* @__PURE__ */ jsxs15(Text15, { bold: true, children: [
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__ */ jsxs15(Text15, { color: theme16.muted, children: [
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__ */ jsxs15(Fragment, { children: [
5213
- /* @__PURE__ */ jsx17(Text15, { color: theme16.success, children: "\u2713" }),
5214
- /* @__PURE__ */ jsxs15(Text15, { bold: true, children: [
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__ */ jsxs15(Text15, { color: theme16.muted, children: [
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__ */ jsxs15(Fragment, { children: [
5225
- /* @__PURE__ */ jsx17(Text15, { color: theme16.error, children: "\u2717" }),
5226
- /* @__PURE__ */ jsxs15(Text15, { bold: true, children: [
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__ */ jsxs15(Text15, { color: theme16.dimLabel, wrap: "truncate", children: [
5462
+ paramsPreview && /* @__PURE__ */ jsxs17(Text17, { color: theme17.dimLabel, wrap: "truncate", children: [
5233
5463
  " ",
5234
5464
  paramsPreview
5235
5465
  ] }),
5236
- tool.status === "complete" && resultPreview && /* @__PURE__ */ jsxs15(Text15, { color: theme16.dimLabel, wrap: "truncate", children: [
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 jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
5474
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
5245
5475
  var ROWS_PER_TOOL = 3;
5246
- function ToolPanel({ tools, maxHeight }) {
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 availableRows = maxHeight - 1;
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__ */ jsxs16(Box16, { flexDirection: "column", children: [
5265
- /* @__PURE__ */ jsx18(Text16, { bold: true, color: theme17.info, children: "Tools" }),
5266
- hiddenCount > 0 && /* @__PURE__ */ jsxs16(Text16, { color: theme17.muted, dimColor: true, children: [
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__ */ jsx18(ToolEntry, { tool, now }, tool.id))
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 Box17, Text as Text17 } from "ink";
5278
- import { theme as theme18 } from "@runtypelabs/ink-components";
5279
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
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: theme18.success,
5282
- agent_complete: theme18.success,
5283
- agent_error: theme18.error,
5284
- agent_await: theme18.warning,
5285
- agent_iteration_start: theme18.info,
5286
- agent_iteration_complete: theme18.info,
5287
- agent_turn_delta: theme18.muted,
5288
- agent_turn_complete: theme18.primary,
5289
- agent_tool_start: theme18.warning,
5290
- agent_tool_complete: theme18.warning
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__ */ jsxs17(Box17, { flexDirection: "column", paddingX: 1, children: [
5321
- /* @__PURE__ */ jsxs17(Box17, { marginBottom: 1, children: [
5322
- /* @__PURE__ */ jsxs17(Text17, { color: theme18.muted, children: [
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__ */ jsx19(Text17, { bold: true, color, children: event.type }),
5327
- /* @__PURE__ */ jsx19(Text17, { color: theme18.muted, children: " \u2014 Esc to close" }),
5328
- totalLines > maxVisibleLines && /* @__PURE__ */ jsxs17(Text17, { color: theme18.muted, children: [
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__ */ jsx19(Text17, { color: theme18.label, children: line }, i))
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__ */ jsx19(
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__ */ jsx19(Box17, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx19(Text17, { color: theme18.muted, children: "Waiting for events..." }) });
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__ */ jsxs17(Box17, { flexDirection: "column", paddingX: 1, children: [
5388
- /* @__PURE__ */ jsxs17(Box17, { marginBottom: 0, children: [
5389
- /* @__PURE__ */ jsx19(Text17, { bold: true, color: theme18.info, children: "Event Stream" }),
5390
- /* @__PURE__ */ jsxs17(Text17, { color: theme18.muted, children: [
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__ */ jsxs17(Text17, { color: theme18.muted, children: [
5632
+ hiddenAbove > 0 && /* @__PURE__ */ jsxs19(Text19, { color: theme19.muted, children: [
5396
5633
  " [",
5397
5634
  hiddenAbove,
5398
5635
  " above]"
5399
5636
  ] }),
5400
- hiddenBelow > 0 && /* @__PURE__ */ jsxs17(Text17, { color: theme18.muted, children: [
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__ */ jsxs17(Box17, { flexDirection: "row", flexWrap: "nowrap", children: [
5409
- /* @__PURE__ */ jsx19(Box17, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx19(Text17, { color: theme18.info, children: isSelected ? ">" : " " }) }),
5410
- /* @__PURE__ */ jsx19(Box17, { width: 9, flexShrink: 0, children: /* @__PURE__ */ jsx19(Text17, { color: theme18.muted, inverse: isSelected, children: row.time }) }),
5411
- /* @__PURE__ */ jsx19(Box17, { width: 28, flexShrink: 0, children: /* @__PURE__ */ jsx19(Text17, { color: row.color, bold: true, inverse: isSelected, children: row.type }) }),
5412
- /* @__PURE__ */ jsx19(Box17, { flexShrink: 1, children: /* @__PURE__ */ jsx19(Text17, { color: theme18.muted, wrap: "truncate", inverse: isSelected, children: row.data }) })
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 Box19, Text as Text19 } from "ink";
5657
+ import { Box as Box21, Text as Text21 } from "ink";
5421
5658
  import TextInput3 from "ink-text-input";
5422
- import { theme as theme20 } from "@runtypelabs/ink-components";
5659
+ import { theme as theme21 } from "@runtypelabs/ink-components";
5423
5660
 
5424
5661
  // src/ink/marathon/SteeringRecap.tsx
5425
- import { Box as Box18, Text as Text18 } from "ink";
5426
- import { theme as theme19 } from "@runtypelabs/ink-components";
5427
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
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__ */ jsxs18(Box18, { borderStyle: "single", borderColor: theme19.muted, flexDirection: "column", paddingX: 1, children: [
5438
- /* @__PURE__ */ jsx20(Text18, { color: theme19.label, children: label }),
5439
- /* @__PURE__ */ jsxs18(Text18, { color: theme19.muted, children: [
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 jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
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__ */ jsxs19(Box19, { flexDirection: "column", flexShrink: 0, children: [
5562
- /* @__PURE__ */ jsx21(SteeringRecap, { ...recap, isTerminal }),
5563
- showModelPicker ? /* @__PURE__ */ jsx21(
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__ */ jsxs19(Fragment2, { children: [
5571
- /* @__PURE__ */ jsxs19(Box19, { children: [
5572
- /* @__PURE__ */ jsx21(Text19, { color: theme20.muted, children: "> " }),
5573
- /* @__PURE__ */ jsx21(Box19, { flexGrow: 1, children: /* @__PURE__ */ jsx21(
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__ */ jsxs19(Text19, { dimColor: true, children: [
5819
+ countdownText && /* @__PURE__ */ jsxs21(Text21, { dimColor: true, children: [
5583
5820
  " ",
5584
5821
  countdownText
5585
5822
  ] })
5586
5823
  ] }),
5587
- /* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
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__ */ jsx21(Box19, { flexDirection: "column", marginTop: 1, children: MARATHON_STEER_COMMANDS.map((cmd) => /* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
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 jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
5602
- var TOOL_PANEL_WIDE = 40;
5603
- var TOOL_PANEL_NARROW = 30;
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((resolve) => {
5691
- steeringResolveRef.current = resolve;
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
- function navigateToEvent(index) {
5720
- const clamped = Math.max(0, Math.min(state.rawEvents.length - 1, index));
5721
- const evt = state.rawEvents[clamped];
5722
- if (evt) {
5723
- setEventCursor(clamped);
5724
- setDetailEvent(evt);
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
- if (showEventStream && eventCursor === -1 && state.rawEvents.length > 0) {
5730
- setEventCursor(state.rawEvents.length - 1);
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
- }, [showEventStream, eventCursor, state.rawEvents.length]);
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(state.content, state.tools);
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 (state.phase === "steering" && steeringRecap) {
5755
- if (key.upArrow) {
5756
- setScrollOffset((prev) => prev + SCROLL_STEP2);
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 ?? state.rawEvents[eventCursor];
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 = state.rawEvents[eventCursor];
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(state.rawEvents.length - 1, prev + 1));
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 = initialSessionCount + state.sessionCount;
6489
+ const sessionCount = liveSessionSnapshot?.sessionIndex ?? latestCompletedSessionIndex;
5843
6490
  const totalCost = initialCost + state.totalCost;
5844
- const hasTools = state.tools.length > 0;
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) return "c: copy | \u2190\u2192: prev/next | Esc: back | Tab: chat";
5853
- if (showEventStream) return "Enter: detail | c: copy | Tab: chat | Ctrl+C";
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
- return `${dashboardHint}Tab: events | Ctrl+C${scrollHint}`;
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}/${state.rawEvents.length})` : "EVENT STREAM";
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
- return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", height: terminalRows, children: [
5863
- /* @__PURE__ */ jsx22(
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
- state.phase === "steering" && steeringRecap ? /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", height: adjustedContentHeight, children: [
5875
- /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx22(
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: state.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__ */ jsx22(
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__ */ jsx22(Box20, { flexDirection: "column", height: adjustedContentHeight, overflow: "hidden", children: /* @__PURE__ */ jsx22(
6581
+ ] }) : showEventStream ? /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", height: adjustedContentHeight, overflow: "hidden", children: /* @__PURE__ */ jsx25(
5897
6582
  EventStreamPanel,
5898
6583
  {
5899
- events: state.rawEvents,
5900
- startTime: state.rawEvents[0]?.timestamp ?? null,
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__ */ jsxs20(Box20, { flexDirection: isStacked ? "column" : "row", height: adjustedContentHeight, overflow: "hidden", children: [
5907
- /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", flexGrow: 1, flexShrink: 1, children: [
5908
- state.phase === "thinking" && /* @__PURE__ */ jsx22(ThinkingIndicator, { startedAt: state.thinkingStartedAt }),
5909
- /* @__PURE__ */ jsx22(
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: state.content,
5913
- isStreaming: state.phase === "streaming",
6625
+ content: displayedContent,
6626
+ isStreaming: selectedIsLive && state.phase === "streaming",
5914
6627
  enableMarkdown: !plainText,
5915
- maxVisibleLines: adjustedContentHeight - (state.phase === "thinking" ? 2 : 1),
6628
+ maxVisibleLines: transcriptRows,
5916
6629
  scrollOffset
5917
6630
  }
5918
6631
  ),
5919
- state.error && /* @__PURE__ */ jsx22(ErrorDisplay4, { error: state.error })
5920
- ] }),
5921
- hasTools && /* @__PURE__ */ jsx22(
5922
- Box20,
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: theme21.muted,
6641
+ borderColor: theme23.muted,
5929
6642
  paddingX: 1,
5930
- children: /* @__PURE__ */ jsx22(ToolPanel, { tools: state.tools, maxHeight: adjustedContentHeight - 2 })
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__ */ jsx22(
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
- const safeName = name.replace(/[^a-zA-Z0-9_-]/g, "_");
5958
- return path5.join(dir, `${safeName}.json`);
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(chalk12.gray(` [sandbox:${provider}] execution error: ${message}`));
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 buildLocalTools(client, sandboxProvider, options) {
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(chalk12.red("Error: -g, --goal <text> is required for new tasks"));
6280
- console.log(chalk12.gray(" Use --resume to continue an existing task without a new goal"));
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(chalk12.red(`Invalid --sandbox value "${options.sandbox}". Use: cloudflare-worker, quickjs, or daytona`));
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(chalk12.gray("Looking up agent by name..."));
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(chalk12.green(`Found agent: ${agentId}`));
7921
+ console.log(chalk13.green(`Found agent: ${agentId}`));
6305
7922
  } else {
6306
- console.log(chalk12.gray(`Creating agent "${agent}"...`));
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(chalk12.green(`Created agent: ${agentId}`));
7927
+ console.log(chalk13.green(`Created agent: ${agentId}`));
6311
7928
  } catch (createErr) {
6312
- console.error(chalk12.red(`Failed to create agent "${agent}"`));
7929
+ console.error(chalk13.red(`Failed to create agent "${agent}"`));
6313
7930
  const errMsg = createErr instanceof Error ? createErr.message : String(createErr);
6314
- console.error(chalk12.red(errMsg));
7931
+ console.error(chalk13.red(errMsg));
6315
7932
  process.exit(1);
6316
7933
  }
6317
7934
  }
6318
7935
  } catch (error) {
6319
- console.error(chalk12.red("Failed to list agents"));
7936
+ console.error(chalk13.red("Failed to list agents"));
6320
7937
  const errMsg = error instanceof Error ? error.message : String(error);
6321
- console.error(chalk12.red(errMsg));
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
- if (options.resume) {
7979
+ let persistedSessionSummaries = [];
7980
+ let persistedSessionSnapshots = [];
7981
+ let resumeState;
7982
+ if (resumeRequested) {
6339
7983
  let resolvedFilePath;
6340
7984
  let resolvedTaskName;
6341
- if (options.session) {
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(chalk12.red("No state files found to resume"));
6351
- console.log(chalk12.gray(" Run without --resume to start a new task."));
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(chalk12.gray(` Auto-selected session: ${resolvedTaskName}`));
8003
+ console.log(chalk13.gray(` Auto-selected session: ${resolvedTaskName}`));
6357
8004
  }
6358
8005
  const existing = loadState(resolvedFilePath);
6359
8006
  if (!existing) {
6360
- console.error(chalk12.red(`No state file found at ${resolvedFilePath}`));
6361
- console.log(chalk12.gray(" Run without --resume to start a new task."));
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
- chalk12.cyan(
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 || (options.resume ? "Continue the task." : "");
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: getDashboardUrl(),
6423
- onSaveState: (content, _tools) => {
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: "paused",
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
- await new Promise((resolve) => setTimeout(resolve, 0));
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(chalk12.red("Failed to initialize marathon UI"));
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 result2 = await client.agents.runTask(agentId, {
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: priorSessionCount + accumulatedSessions + state.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: currentActions.getState().content.slice(0, 100)
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: currentActions.getState().content.slice(0, 100)
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) : void 0;
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: result.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" ? chalk12.green : result.status === "budget_exceeded" ? chalk12.red : chalk12.yellow;
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: ${chalk12.yellow(`$${finalState.totalCost.toFixed(4)}`)}`);
6642
- console.log(`State: ${chalk12.gray(filePath)}`);
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: ${chalk12.cyan(`${dashboardBaseUrl}/agents/${agentId}`)}`);
8387
+ console.log(`Dashboard: ${chalk13.cyan(`${dashboardBaseUrl}/agents/${agentId}`)}`);
6645
8388
  if (result.recordId) {
6646
- console.log(`Record: ${chalk12.gray(result.recordId)}`);
8389
+ console.log(`Record: ${chalk13.gray(result.recordId)}`);
6647
8390
  }
6648
8391
  if (finalState.continuations && finalState.continuations.length > 0) {
6649
- console.log(chalk12.dim("\nContinuation history:"));
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
- chalk12.gray(` #${i + 1}: ${c.continuedAt}${modelName}${msg} \u2014 $${c.segmentCost.toFixed(4)}`)
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(chalk12.dim("\nCost by model:"));
8403
+ console.log(chalk13.dim("\nCost by model:"));
6661
8404
  for (const [modelName, cost] of Object.entries(finalState.costByModel)) {
6662
- console.log(chalk12.gray(` ${modelName}: $${cost.toFixed(4)}`));
8405
+ console.log(chalk13.gray(` ${modelName}: $${cost.toFixed(4)}`));
6663
8406
  }
6664
8407
  }
6665
- if (result.status === "paused" || result.status === "max_sessions") {
8408
+ if (isMarathonResumableStatus(result.status)) {
6666
8409
  console.log(
6667
- chalk12.gray(
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 errMsg = error instanceof Error ? error.message : "Unknown error";
6685
- console.error(chalk12.red(`
6686
- Task failed: ${errMsg}`));
6687
- console.log(chalk12.gray(`State saved to ${filePath} \u2014 resume with --resume`));
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(chalk13.red(`Failed to fetch agents: ${message}`));
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(chalk13.red(`Failed to fetch agent: ${message}`));
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(chalk13.red(`Failed to create agent: ${message}`));
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(chalk13.red(`Failed to delete agent: ${message}`));
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(chalk13.gray("Starting agent..."));
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(chalk13.red(`
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(chalk13.red(`Execution failed: ${message}`));
8721
+ console.error(chalk14.red(`Execution failed: ${message}`));
6973
8722
  process.exit(1);
6974
8723
  }
6975
8724
  } else {
6976
- console.log(chalk13.gray("Executing agent..."));
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(chalk13.red(`Execution failed: ${message}`));
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 chalk14 from "chalk";
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(chalk14.red(`Failed to fetch models: ${message}`));
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(chalk14.red(`Failed to fetch available models: ${message}`));
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(chalk14.red(`Failed to enable model: ${message}`));
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(chalk14.red(`Failed to disable model: ${message}`));
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(chalk14.red(`Failed to set default model: ${message}`));
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(chalk14.gray("Fetching model usage..."));
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(chalk14.red(`Failed to fetch model usage: ${message}`));
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 chalk15 from "chalk";
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(chalk15.red(`Failed to fetch schedules: ${message}`));
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(chalk15.red(`Failed to fetch schedule: ${message}`));
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(chalk15.red(`Failed to create schedule: ${message}`));
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(chalk15.red(`Failed to ${name} schedule: ${message}`));
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(chalk15.red(`Failed to delete schedule: ${message}`));
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 chalk16 from "chalk";
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 Text20 } from "ink";
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(chalk16.red(`Failed to read records file: ${message}`));
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(chalk16.green("Eval submitted"));
7643
- console.log(` Batch ID: ${chalk16.green(data.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(chalk16.red("Failed to submit eval"));
7652
- console.error(chalk16.red(message));
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(chalk16.gray("No eval batches found"));
9463
+ console.log(chalk17.gray("No eval batches found"));
7715
9464
  return;
7716
9465
  }
7717
- console.log(chalk16.cyan("Eval Batches:"));
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
- ` ${chalk16.green(batch.id)} ${name} ${chalk16[statusColor](`[${batch.status}]`)} ${chalk16.gray(progress)}`
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(chalk16.dim(`
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(chalk16.red("Failed to fetch eval batches"));
7735
- console.error(chalk16.red(message));
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
- Text20,
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(chalk16.cyan(`Eval: ${data.batch.name || data.batch.id}`));
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(chalk16.gray("No results yet"));
9549
+ console.log(chalk17.gray("No results yet"));
7801
9550
  return;
7802
9551
  }
7803
- console.log(chalk16.cyan("Results:"));
9552
+ console.log(chalk17.cyan("Results:"));
7804
9553
  for (const result of results) {
7805
- const scoreStr = result.score !== void 0 ? chalk16.blue(` score=${result.score}`) : "";
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
- ` ${chalk16.gray(result.recordId)} ${chalk16[statusColor](`[${result.status}]`)}${scoreStr}`
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(chalk16.red("Failed to fetch eval results"));
7815
- console.error(chalk16.red(message));
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(chalk16.red("Failed to compare evals"));
7879
- console.error(chalk16.red(message));
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 chalk17 from "chalk";
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 Text21 } from "ink";
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(chalk17.gray("No API keys found"));
9684
+ console.log(chalk18.gray("No API keys found"));
7936
9685
  return;
7937
9686
  }
7938
- console.log(chalk17.cyan("Your API Keys:"));
9687
+ console.log(chalk18.cyan("Your API Keys:"));
7939
9688
  for (const key of keys) {
7940
- const prefix = key.prefix ? chalk17.gray(` (${key.prefix}...)`) : "";
7941
- const lastUsed = key.lastUsedAt ? chalk17.gray(` last used: ${key.lastUsedAt}`) : "";
7942
- console.log(` ${chalk17.green(key.id)} ${key.name}${prefix}${lastUsed}`);
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(chalk17.dim(`
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(chalk17.red("Failed to fetch API keys"));
7953
- console.error(chalk17.red(message));
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(Text21, null, ` ${k.id} ${k.name}${prefix}${lastUsed}`);
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(chalk17.red("Failed to fetch API key"));
8017
- console.error(chalk17.red(message));
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(chalk17.green("API key created"));
8076
- console.log(` ID: ${chalk17.green(data.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: ${chalk17.yellow(data.key)}`);
8080
- console.log(chalk17.gray(" Save this key - it will not be shown again"));
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(chalk17.red("Failed to create API key"));
8086
- console.error(chalk17.red(message));
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(chalk17.green("API key deleted"));
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(chalk17.red("Failed to delete API key"));
8144
- console.error(chalk17.red(message));
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((resolve) => {
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
- resolve(result);
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(chalk17.green("API key regenerated"));
9981
+ console.log(chalk18.green("API key regenerated"));
8233
9982
  if (data.key) {
8234
- console.log(` New Key: ${chalk17.yellow(data.key)}`);
8235
- console.log(chalk17.gray(" Save this key - it will not be shown again"));
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(chalk17.red("Failed to regenerate API key"));
8241
- console.error(chalk17.red(message));
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(chalk17.red("Failed to fetch analytics"));
8297
- console.error(chalk17.red(message));
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 chalk18 from "chalk";
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 Text22 } from "ink";
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(chalk18.red("Failed to fetch stats"));
8362
- console.error(chalk18.red(message));
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(chalk18.gray("No results found"));
10175
+ console.log(chalk19.gray("No results found"));
8427
10176
  return;
8428
10177
  }
8429
- console.log(chalk18.cyan("Execution Results:"));
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 ? chalk18.gray(` ${result.createdAt}`) : "";
10181
+ const date = result.createdAt ? chalk19.gray(` ${result.createdAt}`) : "";
8433
10182
  console.log(
8434
- ` ${chalk18.green(result.id)} ${chalk18[statusColor](`[${result.status}]`)} flow=${chalk18.gray(result.flowId)} record=${chalk18.gray(result.recordId)}${date}`
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(chalk18.dim(`
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(chalk18.red("Failed to fetch results"));
8446
- console.error(chalk18.red(message));
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
- Text22,
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 chalk19 from "chalk";
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(chalk19.red("Failed to fetch billing status"));
8541
- console.error(chalk19.red(message));
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(chalk19.red("Failed to open billing portal"));
8612
- console.error(chalk19.red(message));
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(chalk19.green("Plan data refreshed"));
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(chalk19.red("Failed to refresh plan data"));
8665
- console.error(chalk19.red(message));
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 chalk20 from "chalk";
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 Text23 } from "ink";
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(chalk20.gray("No versions found"));
10471
+ console.log(chalk21.gray("No versions found"));
8723
10472
  return;
8724
10473
  }
8725
- console.log(chalk20.cyan(`Versions for flow ${flowId}:`));
10474
+ console.log(chalk21.cyan(`Versions for flow ${flowId}:`));
8726
10475
  for (const v of versions) {
8727
- const publishedTag = v.published ? chalk20.green(" [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 ? chalk20.gray(` ${v.createdAt}`) : "";
8730
- console.log(` ${chalk20.green(v.id)} ${versionNum}${publishedTag}${date}`);
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(chalk20.red("Failed to fetch versions"));
8736
- console.error(chalk20.red(message));
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(Text23, null, ` ${v.id} ${versionNum}${publishedTag}${v.createdAt ? ` ${v.createdAt}` : ""}`);
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(chalk20.red("Failed to fetch version"));
8797
- console.error(chalk20.red(message));
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(chalk20.red("Failed to fetch published version"));
8863
- console.error(chalk20.red(message));
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(chalk20.green("Version published"));
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(chalk20.red("Failed to publish version"));
8920
- console.error(chalk20.red(message));
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(chalk21.red(`Error: ${commanderError.message}`));
10751
+ console.error(chalk22.red(`Error: ${commanderError.message}`));
9003
10752
  process.exit(1);
9004
10753
  } else if (commanderError.code === "commander.unknownOption") {
9005
- console.error(chalk21.red(`Error: ${commanderError.message}`));
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(chalk21.red("An unexpected error occurred:"));
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(chalk21.cyan("\nWelcome to Runtype CLI!\n"));
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(` ${chalk21.green("runtype init")}
10770
+ console.log(` ${chalk22.green("runtype init")}
9022
10771
  `);
9023
10772
  console.log("Or see all available commands:");
9024
- console.log(` ${chalk21.green("runtype --help")}
10773
+ console.log(` ${chalk22.green("runtype --help")}
9025
10774
  `);
9026
10775
  } else {
9027
10776
  try {