skydive-cli 0.1.0-beta.340 → 0.1.0-beta.341

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/js/bin.mjs CHANGED
@@ -16,7 +16,7 @@ import zlib from "node:zlib";
16
16
  import os from "node:os";
17
17
 
18
18
  //#region package.json
19
- var version$1 = "0.1.0-beta.340";
19
+ var version$1 = "0.1.0-beta.341";
20
20
 
21
21
  //#endregion
22
22
  //#region src/types.ts
@@ -2618,7 +2618,7 @@ const chatCommand = {
2618
2618
  printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
2619
2619
  process.exit(1);
2620
2620
  }
2621
- const { runChat } = await import("./boot-BQZrbJAh.mjs");
2621
+ const { runChat } = await import("./boot-Dr7pEKqB.mjs");
2622
2622
  await runChat({
2623
2623
  appUrl,
2624
2624
  sessionToken: session.value.sessionToken,
@@ -3411,7 +3411,7 @@ const switchCommand = {
3411
3411
  printError("The workspace picker needs the Bun runtime and it could not be set up automatically. Pass a workspace slug instead, or install Bun and retry.");
3412
3412
  process.exit(1);
3413
3413
  }
3414
- const { runWorkspacePicker } = await import("./boot-BQZrbJAh.mjs");
3414
+ const { runWorkspacePicker } = await import("./boot-Dr7pEKqB.mjs");
3415
3415
  await runWorkspacePicker(session);
3416
3416
  return;
3417
3417
  }
@@ -1329,6 +1329,132 @@ function WorkspacePicker({ appUrl, sessionToken, onSelect, onCancel }) {
1329
1329
  });
1330
1330
  }
1331
1331
 
1332
+ //#endregion
1333
+ //#region src/chat/tui/chunks/frame.tsx
1334
+ /** Status glyph + color for a tool's lifecycle state. */
1335
+ function toolGlyph(state) {
1336
+ switch (state) {
1337
+ case "streaming":
1338
+ case "input-ready": return {
1339
+ ch: "◐",
1340
+ color: theme.warning
1341
+ };
1342
+ case "output-ready": return {
1343
+ ch: "✓",
1344
+ color: theme.success
1345
+ };
1346
+ case "error": return {
1347
+ ch: "✗",
1348
+ color: theme.error
1349
+ };
1350
+ }
1351
+ }
1352
+ /** Truncate a single line with an ellipsis. */
1353
+ function truncate(line, maxLen) {
1354
+ return line.length > maxLen ? `${line.slice(0, maxLen - 1)}…` : line;
1355
+ }
1356
+ /**
1357
+ * Compact a block of tool output for the transcript: truncate over-long
1358
+ * lines (so a giant single-line JSON blob doesn't wrap to a wall) and cap
1359
+ * the line count, with a "+N more" tail that doubles as the click-to-expand
1360
+ * affordance. Expanded blocks render through `ExpandedLines` instead —
1361
+ * full content, word-wrapped, nothing clipped.
1362
+ */
1363
+ function clipLines(text, { maxLines, maxLineLen }) {
1364
+ const lines = text.replace(/\t/g, " ").split("\n");
1365
+ const out = lines.slice(0, maxLines).map((line) => truncate(line, maxLineLen));
1366
+ if (lines.length > maxLines) out.push(`… +${lines.length - maxLines} more lines · click to expand`);
1367
+ return out;
1368
+ }
1369
+ /**
1370
+ * Split a block for the expanded view: tabs normalised, no line cap, no
1371
+ * per-line truncation — rendering word-wraps instead. Blank lines become a
1372
+ * single space so they keep their row (an empty <text> collapses).
1373
+ */
1374
+ function expandLines(text) {
1375
+ return text.replace(/\t/g, " ").split("\n").map((line) => line.length === 0 ? " " : line);
1376
+ }
1377
+ /**
1378
+ * Full, untruncated block content for an expanded view: every line kept and
1379
+ * word-wrapped by the terminal instead of ellipsis-clipped.
1380
+ */
1381
+ function ExpandedLines({ text, fg }) {
1382
+ return /* @__PURE__ */ jsx("box", {
1383
+ style: { flexDirection: "column" },
1384
+ children: expandLines(text).map((line, idx) => /* @__PURE__ */ jsx("text", {
1385
+ fg,
1386
+ style: { wrapMode: "word" },
1387
+ children: line
1388
+ }, idx))
1389
+ });
1390
+ }
1391
+ /** Whether a block of text has lines hidden by the collapsed line cap. */
1392
+ function isClipped(text, maxLines) {
1393
+ let count = 1;
1394
+ for (let i = 0; i < text.length; i++) {
1395
+ if (text.charCodeAt(i) === 10) count++;
1396
+ if (count > maxLines) return true;
1397
+ }
1398
+ return false;
1399
+ }
1400
+ /** Dim tail line under an expanded block: click anywhere on it to fold. */
1401
+ function CollapseHint() {
1402
+ return /* @__PURE__ */ jsx("text", {
1403
+ fg: theme.dim,
1404
+ children: "· click to collapse"
1405
+ });
1406
+ }
1407
+ /** Indents tool output two columns under its header — no rule, just space. */
1408
+ function Indented({ children }) {
1409
+ return /* @__PURE__ */ jsx("box", {
1410
+ style: {
1411
+ flexDirection: "column",
1412
+ paddingLeft: 2
1413
+ },
1414
+ children
1415
+ });
1416
+ }
1417
+
1418
+ //#endregion
1419
+ //#region src/chat/tui/list-line.ts
1420
+ /**
1421
+ * Fit a row's title and trailing detail into `width` columns. The title
1422
+ * identifies the row so it gets the space first; the detail takes what is
1423
+ * left and is dropped when nothing is.
1424
+ */
1425
+ function fitRowText(title, detail, width) {
1426
+ if (width <= 0) return {
1427
+ title: "",
1428
+ detail: ""
1429
+ };
1430
+ if ((detail ? title.length + 1 + detail.length : title.length) <= width) return {
1431
+ title,
1432
+ detail
1433
+ };
1434
+ const room = width - title.length - 1;
1435
+ if (room < 2) return {
1436
+ title: truncate(title, width),
1437
+ detail: ""
1438
+ };
1439
+ return {
1440
+ title,
1441
+ detail: truncate(detail, room)
1442
+ };
1443
+ }
1444
+ /**
1445
+ * Join hint segments with " · ", dropping trailing segments that do not fit
1446
+ * rather than wrapping onto a second line — which would cost the list a row.
1447
+ * The first segment is always kept (truncated if it has to be).
1448
+ */
1449
+ function fitHintLine(segments, width) {
1450
+ const kept = [];
1451
+ for (const segment of segments) {
1452
+ if (kept.length > 0 && [...kept, segment].join(" · ").length > width) break;
1453
+ kept.push(segment);
1454
+ }
1455
+ return truncate(kept.join(" · "), width);
1456
+ }
1457
+
1332
1458
  //#endregion
1333
1459
  //#region src/chat/tui/screens/conversation-picker.tsx
1334
1460
  const humanChannels = [
@@ -1432,6 +1558,27 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
1432
1558
  kind: "conv",
1433
1559
  hit
1434
1560
  }))];
1561
+ const innerWidth = Math.max(1, width - 2);
1562
+ const rowWidth = Math.max(1, innerWidth - 2);
1563
+ const confirmConv = confirmId !== null ? list.find((c) => c.id === confirmId) : void 0;
1564
+ const status = confirmConv ? {
1565
+ fg: theme.error,
1566
+ text: truncate(`delete “${confirmConv.title ?? "(untitled)"}”? y/n`, innerWidth)
1567
+ } : error ? {
1568
+ fg: theme.error,
1569
+ text: truncate(`delete failed: ${error}`, innerWidth)
1570
+ } : {
1571
+ fg: theme.dim,
1572
+ text: fitHintLine([
1573
+ `${hits.length}/${list.length}${complete ? "" : " (loading…)"}`,
1574
+ showAutomated ? "incl. agent runs" : "yours",
1575
+ `tab ${showAutomated ? "hide" : "show"} agent runs`,
1576
+ "↑/↓ move",
1577
+ "↵ open",
1578
+ "ctrl+d delete",
1579
+ "esc back"
1580
+ ], innerWidth)
1581
+ };
1435
1582
  const clamped = Math.min(highlight, Math.max(0, rows.length - 1));
1436
1583
  const visibleRows = Math.max(3, height - 6);
1437
1584
  const start = windowStart(clamped, rows.length, visibleRows);
@@ -1487,7 +1634,6 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
1487
1634
  if (row) open(row);
1488
1635
  }
1489
1636
  });
1490
- const confirmConv = confirmId !== null ? list.find((c) => c.id === confirmId) : void 0;
1491
1637
  return /* @__PURE__ */ jsxs("box", {
1492
1638
  style: {
1493
1639
  flexDirection: "column",
@@ -1512,31 +1658,9 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
1512
1658
  }
1513
1659
  })]
1514
1660
  }),
1515
- confirmConv ? /* @__PURE__ */ jsxs("text", {
1516
- fg: theme.error,
1517
- children: [
1518
- "delete “",
1519
- confirmConv.title ?? "(untitled)",
1520
- "”? y/n"
1521
- ]
1522
- }) : error ? /* @__PURE__ */ jsxs("text", {
1523
- fg: theme.error,
1524
- children: ["delete failed: ", error]
1525
- }) : /* @__PURE__ */ jsxs("text", {
1526
- fg: theme.dim,
1527
- children: [
1528
- hits.length,
1529
- "/",
1530
- list.length,
1531
- complete ? "" : " (loading…)",
1532
- " ·",
1533
- " ",
1534
- showAutomated ? "incl. agent runs" : "yours",
1535
- " · tab",
1536
- " ",
1537
- showAutomated ? "hide" : "show",
1538
- " agent runs · ↑/↓ move · ↵ open · ctrl+d delete · esc back"
1539
- ]
1661
+ /* @__PURE__ */ jsx("text", {
1662
+ fg: status.fg,
1663
+ children: status.text
1540
1664
  }),
1541
1665
  /* @__PURE__ */ jsx("box", {
1542
1666
  style: {
@@ -1546,22 +1670,24 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
1546
1670
  children: windowed.map((row, i) => {
1547
1671
  const selected = start + i === clamped;
1548
1672
  const fg = selected ? theme.accent : theme.fg;
1673
+ const marker = selected ? "› " : " ";
1549
1674
  if (row.kind === "new") return /* @__PURE__ */ jsxs("text", {
1550
1675
  fg,
1551
- children: [selected ? "› " : " ", "+ new conversation"]
1676
+ children: [marker, truncate("+ new conversation", rowWidth)]
1552
1677
  }, "new");
1678
+ const { title, detail } = fitRowText(row.hit.item.title ?? "(untitled)", previewLine(row.hit.item), rowWidth);
1553
1679
  return /* @__PURE__ */ jsxs("text", {
1554
1680
  fg,
1555
1681
  children: [
1556
- selected ? "› " : " ",
1682
+ marker,
1557
1683
  /* @__PURE__ */ jsx(FuzzyText, {
1558
- text: row.hit.item.title ?? "(untitled)",
1684
+ text: title,
1559
1685
  indexes: row.hit.item.title ? row.hit.highlights[0] : null
1560
1686
  }),
1561
- /* @__PURE__ */ jsxs("span", {
1687
+ detail ? /* @__PURE__ */ jsxs("span", {
1562
1688
  fg: theme.dim,
1563
- children: [" ", previewLine(row.hit.item)]
1564
- })
1689
+ children: [" ", detail]
1690
+ }) : null
1565
1691
  ]
1566
1692
  }, row.hit.item.id);
1567
1693
  })
@@ -1718,92 +1844,6 @@ async function resolveDroppedFiles(paths) {
1718
1844
  }
1719
1845
  }
1720
1846
 
1721
- //#endregion
1722
- //#region src/chat/tui/chunks/frame.tsx
1723
- /** Status glyph + color for a tool's lifecycle state. */
1724
- function toolGlyph(state) {
1725
- switch (state) {
1726
- case "streaming":
1727
- case "input-ready": return {
1728
- ch: "◐",
1729
- color: theme.warning
1730
- };
1731
- case "output-ready": return {
1732
- ch: "✓",
1733
- color: theme.success
1734
- };
1735
- case "error": return {
1736
- ch: "✗",
1737
- color: theme.error
1738
- };
1739
- }
1740
- }
1741
- /** Truncate a single line with an ellipsis. */
1742
- function truncate(line, maxLen) {
1743
- return line.length > maxLen ? `${line.slice(0, maxLen - 1)}…` : line;
1744
- }
1745
- /**
1746
- * Compact a block of tool output for the transcript: truncate over-long
1747
- * lines (so a giant single-line JSON blob doesn't wrap to a wall) and cap
1748
- * the line count, with a "+N more" tail that doubles as the click-to-expand
1749
- * affordance. Expanded blocks render through `ExpandedLines` instead —
1750
- * full content, word-wrapped, nothing clipped.
1751
- */
1752
- function clipLines(text, { maxLines, maxLineLen }) {
1753
- const lines = text.replace(/\t/g, " ").split("\n");
1754
- const out = lines.slice(0, maxLines).map((line) => truncate(line, maxLineLen));
1755
- if (lines.length > maxLines) out.push(`… +${lines.length - maxLines} more lines · click to expand`);
1756
- return out;
1757
- }
1758
- /**
1759
- * Split a block for the expanded view: tabs normalised, no line cap, no
1760
- * per-line truncation — rendering word-wraps instead. Blank lines become a
1761
- * single space so they keep their row (an empty <text> collapses).
1762
- */
1763
- function expandLines(text) {
1764
- return text.replace(/\t/g, " ").split("\n").map((line) => line.length === 0 ? " " : line);
1765
- }
1766
- /**
1767
- * Full, untruncated block content for an expanded view: every line kept and
1768
- * word-wrapped by the terminal instead of ellipsis-clipped.
1769
- */
1770
- function ExpandedLines({ text, fg }) {
1771
- return /* @__PURE__ */ jsx("box", {
1772
- style: { flexDirection: "column" },
1773
- children: expandLines(text).map((line, idx) => /* @__PURE__ */ jsx("text", {
1774
- fg,
1775
- style: { wrapMode: "word" },
1776
- children: line
1777
- }, idx))
1778
- });
1779
- }
1780
- /** Whether a block of text has lines hidden by the collapsed line cap. */
1781
- function isClipped(text, maxLines) {
1782
- let count = 1;
1783
- for (let i = 0; i < text.length; i++) {
1784
- if (text.charCodeAt(i) === 10) count++;
1785
- if (count > maxLines) return true;
1786
- }
1787
- return false;
1788
- }
1789
- /** Dim tail line under an expanded block: click anywhere on it to fold. */
1790
- function CollapseHint() {
1791
- return /* @__PURE__ */ jsx("text", {
1792
- fg: theme.dim,
1793
- children: "· click to collapse"
1794
- });
1795
- }
1796
- /** Indents tool output two columns under its header — no rule, just space. */
1797
- function Indented({ children }) {
1798
- return /* @__PURE__ */ jsx("box", {
1799
- style: {
1800
- flexDirection: "column",
1801
- paddingLeft: 2
1802
- },
1803
- children
1804
- });
1805
- }
1806
-
1807
1847
  //#endregion
1808
1848
  //#region src/chat/tui/chunks/syntax.ts
1809
1849
  let cached = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.1.0-beta.340",
3
+ "version": "0.1.0-beta.341",
4
4
  "description": "Skydive CLI — manage AI agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",