autotel-terminal 17.0.2 → 17.0.3

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/cli.cjs CHANGED
@@ -265,6 +265,17 @@ function truncate(s, width) {
265
265
  if (s.length <= width) return s;
266
266
  return s.slice(0, Math.max(0, width - 1)) + "\u2026";
267
267
  }
268
+ function buildWaterfallBar(spanStart, spanDuration, traceStart, traceDuration, width) {
269
+ if (traceDuration <= 0) return " ".repeat(width);
270
+ const offsetRatio = (spanStart - traceStart) / traceDuration;
271
+ const widthRatio = spanDuration / traceDuration;
272
+ const barStart = Math.max(0, Math.floor(offsetRatio * width));
273
+ const barLen = Math.max(1, Math.round(widthRatio * width));
274
+ const clampedStart = Math.min(barStart, width - 1);
275
+ const clampedLen = Math.min(barLen, width - clampedStart);
276
+ const trailing = Math.max(0, width - clampedStart - clampedLen);
277
+ return " ".repeat(clampedStart) + "\u2588".repeat(clampedLen) + " ".repeat(trailing);
278
+ }
268
279
 
269
280
  // src/lib/log-model.ts
270
281
  function filterLogsBySearch(logs, searchQuery, minLevel) {
@@ -846,6 +857,7 @@ var THROTTLE_MS = 50;
846
857
  var MAX_TRACES = 50;
847
858
  var NEW_ERROR_DISPLAY_MS = 2e3;
848
859
  var RECORD_LIMIT_DEFAULT = 200;
860
+ var LIST_HEIGHT = 20;
849
861
  function Dashboard({
850
862
  title,
851
863
  showStats,
@@ -868,6 +880,7 @@ function Dashboard({
868
880
  });
869
881
  const [drilldownTraceId, setDrilldownTraceId] = react.useState(null);
870
882
  const [drilldownSelectedIndex, setDrilldownSelectedIndex] = react.useState(0);
883
+ const [drilldownScrollOffset, setDrilldownScrollOffset] = react.useState(0);
871
884
  const [drilldownTab, setDrilldownTab] = react.useState("timeline");
872
885
  const [newErrorCount, setNewErrorCount] = react.useState(0);
873
886
  const [searchMode, setSearchMode] = react.useState(false);
@@ -1275,6 +1288,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1275
1288
  } else {
1276
1289
  setDrilldownTraceId(null);
1277
1290
  setDrilldownSelectedIndex(0);
1291
+ setDrilldownScrollOffset(0);
1278
1292
  setDrilldownTab("timeline");
1279
1293
  }
1280
1294
  return;
@@ -1289,6 +1303,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1289
1303
  const nextIdx = key.shift ? (currentIdx - 1 + tabs.length) % tabs.length : (currentIdx + 1) % tabs.length;
1290
1304
  setDrilldownTab(tabs[nextIdx]);
1291
1305
  setDrilldownSelectedIndex(0);
1306
+ setDrilldownScrollOffset(0);
1292
1307
  return;
1293
1308
  }
1294
1309
  if (key.return && drilldownTraceId == null) {
@@ -1320,6 +1335,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1320
1335
  if (targetTraceId) {
1321
1336
  setDrilldownTraceId(targetTraceId);
1322
1337
  setDrilldownSelectedIndex(preSelectIndex);
1338
+ setDrilldownScrollOffset(Math.max(0, preSelectIndex - LIST_HEIGHT + 1));
1323
1339
  setDrilldownTab("timeline");
1324
1340
  return;
1325
1341
  }
@@ -1328,9 +1344,19 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1328
1344
  if (drilldownTraceId != null) {
1329
1345
  const listLength = drilldownTab === "timeline" ? drilldownTimeline.length : drilldownTab === "spans" ? drilldownTree.length : drilldownLogs.length;
1330
1346
  if (key.upArrow) {
1331
- setDrilldownSelectedIndex((i) => Math.max(0, i - 1));
1347
+ setDrilldownSelectedIndex((prev) => {
1348
+ const next = Math.max(0, prev - 1);
1349
+ setDrilldownScrollOffset((off) => Math.min(next, off));
1350
+ return next;
1351
+ });
1332
1352
  } else {
1333
- setDrilldownSelectedIndex((i) => Math.min(listLength - 1, i + 1));
1353
+ setDrilldownSelectedIndex((prev) => {
1354
+ const next = Math.min(listLength - 1, prev + 1);
1355
+ setDrilldownScrollOffset(
1356
+ (off) => next >= off + LIST_HEIGHT ? next - LIST_HEIGHT + 1 : off
1357
+ );
1358
+ return next;
1359
+ });
1334
1360
  }
1335
1361
  return;
1336
1362
  }
@@ -1388,12 +1414,14 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1388
1414
  setSelected(0);
1389
1415
  setDrilldownTraceId(null);
1390
1416
  setDrilldownSelectedIndex(0);
1417
+ setDrilldownScrollOffset(0);
1391
1418
  }
1392
1419
  if (input === "l") {
1393
1420
  setViewMode((m) => m === "log" ? "trace" : "log");
1394
1421
  setSelected(0);
1395
1422
  setDrilldownTraceId(null);
1396
1423
  setDrilldownSelectedIndex(0);
1424
+ setDrilldownScrollOffset(0);
1397
1425
  }
1398
1426
  if (input === "v") {
1399
1427
  setViewMode(
@@ -1402,12 +1430,14 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1402
1430
  setSelected(0);
1403
1431
  setDrilldownTraceId(null);
1404
1432
  setDrilldownSelectedIndex(0);
1433
+ setDrilldownScrollOffset(0);
1405
1434
  }
1406
1435
  if (input === "E") {
1407
1436
  setViewMode((m) => m === "errors" ? "trace" : "errors");
1408
1437
  setSelected(0);
1409
1438
  setDrilldownTraceId(null);
1410
1439
  setDrilldownSelectedIndex(0);
1440
+ setDrilldownScrollOffset(0);
1411
1441
  }
1412
1442
  if (input === "c") {
1413
1443
  setSpans([]);
@@ -1415,6 +1445,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1415
1445
  setSelected(0);
1416
1446
  setDrilldownTraceId(null);
1417
1447
  setDrilldownSelectedIndex(0);
1448
+ setDrilldownScrollOffset(0);
1418
1449
  setNewErrorCount(0);
1419
1450
  setSpanFilters({ statusGroup: "all" });
1420
1451
  setRecording(false);
@@ -1426,6 +1457,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1426
1457
  setSelected(0);
1427
1458
  setDrilldownTraceId(null);
1428
1459
  setDrilldownSelectedIndex(0);
1460
+ setDrilldownScrollOffset(0);
1429
1461
  setNewErrorCount(0);
1430
1462
  setSpanFilters({ statusGroup: "all" });
1431
1463
  setPaused(false);
@@ -1436,6 +1468,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1436
1468
  setSelected(0);
1437
1469
  setDrilldownTraceId(null);
1438
1470
  setDrilldownSelectedIndex(0);
1471
+ setDrilldownScrollOffset(0);
1439
1472
  }
1440
1473
  if (input === "f") {
1441
1474
  setTraceIdMode(true);
@@ -1450,6 +1483,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1450
1483
  setSelected(0);
1451
1484
  setDrilldownTraceId(null);
1452
1485
  setDrilldownSelectedIndex(0);
1486
+ setDrilldownScrollOffset(0);
1453
1487
  }
1454
1488
  if (input === "S") {
1455
1489
  const svc = currentSpan?.attributes?.["service.name"];
@@ -1458,6 +1492,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1458
1492
  setSelected(0);
1459
1493
  setDrilldownTraceId(null);
1460
1494
  setDrilldownSelectedIndex(0);
1495
+ setDrilldownScrollOffset(0);
1461
1496
  }
1462
1497
  }
1463
1498
  if (input === "R") {
@@ -1467,6 +1502,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1467
1502
  setSelected(0);
1468
1503
  setDrilldownTraceId(null);
1469
1504
  setDrilldownSelectedIndex(0);
1505
+ setDrilldownScrollOffset(0);
1470
1506
  }
1471
1507
  }
1472
1508
  if (input === "T") {
@@ -1495,6 +1531,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1495
1531
  setSelected(0);
1496
1532
  setDrilldownTraceId(null);
1497
1533
  setDrilldownSelectedIndex(0);
1534
+ setDrilldownScrollOffset(0);
1498
1535
  setDrilldownTab("timeline");
1499
1536
  }
1500
1537
  return;
@@ -1525,6 +1562,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1525
1562
  setSelected(0);
1526
1563
  setDrilldownTraceId(null);
1527
1564
  setDrilldownSelectedIndex(0);
1565
+ setDrilldownScrollOffset(0);
1528
1566
  setDrilldownTab("timeline");
1529
1567
  }
1530
1568
  return;
@@ -1582,9 +1620,7 @@ ${json}
1582
1620
  ink.Box,
1583
1621
  {
1584
1622
  flexDirection: "column",
1585
- borderStyle: "round",
1586
- padding: 1,
1587
- borderColor: colors ? "cyan" : void 0,
1623
+ paddingX: 1,
1588
1624
  children: [
1589
1625
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { justifyContent: "space-between", marginBottom: 1, children: [
1590
1626
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { bold: true, children: [
@@ -1598,62 +1634,28 @@ ${json}
1598
1634
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: paused ? "yellow" : "green", children: headerRight }, "status")
1599
1635
  ] })
1600
1636
  ] }),
1601
- showHelp ? /* @__PURE__ */ jsxRuntime.jsxs(
1602
- ink.Box,
1603
- {
1604
- flexDirection: "column",
1605
- borderStyle: "single",
1606
- borderColor: "gray",
1607
- paddingX: 1,
1608
- marginBottom: 1,
1609
- children: [
1610
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Shortcuts" }),
1611
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Navigation: \u2191/\u2193, Enter, Esc" }),
1612
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Views: t (trace/spans), l (logs), v (services), E (errors)" }),
1613
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Search: / (Tab autocompletes traceId)" }),
1614
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Filters: e (errors-only), S (service), R (route), H (status), f (traceId), x (clear)" }),
1615
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Capture: p (pause), r (record snapshot), J (export trace JSON)" }),
1616
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "AI: a (toggle AI panel)" }),
1617
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Jump: T (trace for item), L (logs for item)" }),
1618
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Drill-down: Enter (open trace), Tab (cycle tabs), Esc (back)" }),
1619
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Other: c (clear), ? (help), Ctrl+C (exit)" })
1620
- ]
1621
- }
1622
- ) : /* @__PURE__ */ jsxRuntime.jsxs(
1623
- ink.Box,
1624
- {
1625
- marginBottom: 1,
1626
- flexDirection: "row",
1627
- justifyContent: "space-between",
1628
- children: [
1629
- searchMode ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "cyan", children: [
1630
- "Search: ",
1631
- searchQuery || "(type to filter)",
1632
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: " (Tab: match traceId, Esc: cancel)" })
1633
- ] }, "search") : traceIdMode ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "yellow", children: [
1634
- "TraceId: ",
1635
- traceIdInput || "(type prefix, Tab to complete)",
1636
- traceIdInput.length >= 2 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1637
- " ",
1638
- "\u2192",
1639
- " ",
1640
- traceSummaries.find(
1641
- (t2) => t2.traceId.toLowerCase().startsWith(traceIdInput.toLowerCase())
1642
- )?.traceId.slice(0, 16) ?? "no match",
1643
- "\u2026"
1644
- ] })
1645
- ] }, "traceid-input") : drilldownTraceId == null ? /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "\u2191/\u2193 select \u2022 Enter open \u2022 Esc back \u2022 t spans \u2022 l logs \u2022 v svc \u2022 E errors \u2022 T trace \u2022 L logs \u2022 / search \u2022 f traceId \u2022 p pause \u2022 r record \u2022 e errors \u2022 c clear \u2022 ? help" }, "controls") : /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "\u2191/\u2193 select \u2022 Tab cycle tabs \u2022 Esc back \u2022 T trace \u2022 L logs \u2022 a AI \u2022 ? help" }, "controls"),
1646
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: viewMode === "trace" ? `traces ${filteredSummaries.length}/${traceSummaries.length}` : viewMode === "span" ? `spans ${filteredSpans.length}/${spans.length}` : viewMode === "service-summary" ? `services ${serviceStats.length}/${serviceStats.length}` : viewMode === "errors" ? `errors ${filteredErrorSummaries.length}/${errorSummaries.length}` : `logs ${filteredLogs.length}/${logs.length}` }, "count")
1647
- ]
1648
- }
1649
- ),
1650
- (spanFilters.serviceName || spanFilters.route || spanFilters.statusGroup !== "all" || spanFilters.traceId) && /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginBottom: 1, children: /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1651
- "filters:",
1652
- spanFilters.serviceName ? ` service=${spanFilters.serviceName}` : "",
1653
- spanFilters.route ? ` route=${spanFilters.route}` : "",
1654
- spanFilters.statusGroup && spanFilters.statusGroup !== "all" ? ` status=${spanFilters.statusGroup}` : "",
1655
- spanFilters.traceId ? ` trace=${spanFilters.traceId.slice(0, 8)}\u2026` : ""
1656
- ] }) }),
1637
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "column", children: [
1638
+ searchMode ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "cyan", children: [
1639
+ "Search: ",
1640
+ searchQuery || "(type to filter)",
1641
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: " (Tab: match traceId, Esc: cancel)" })
1642
+ ] }) : traceIdMode ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "yellow", children: [
1643
+ "TraceId: ",
1644
+ traceIdInput || "(type prefix, Tab to complete)",
1645
+ traceIdInput.length >= 2 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1646
+ " \u2192 ",
1647
+ traceSummaries.find(
1648
+ (t2) => t2.traceId.toLowerCase().startsWith(traceIdInput.toLowerCase())
1649
+ )?.traceId.slice(0, 16) ?? "no match",
1650
+ "\u2026"
1651
+ ] })
1652
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", justifyContent: "space-between", children: [
1653
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: drilldownTraceId == null ? "\u2191/\u2193 select \u2022 Enter open \u2022 Tab cycle tabs \u2022 Esc back \u2022 T trace \u2022 L logs \u2022 a AI \u2022 ? help" : "\u2191/\u2193 select \u2022 Tab cycle tabs \u2022 Esc back \u2022 T trace \u2022 L logs \u2022 a AI \u2022 ? help" }),
1654
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: viewMode === "trace" ? `traces ${filteredSummaries.length}/${traceSummaries.length}` : viewMode === "span" ? `spans ${filteredSpans.length}/${spans.length}` : viewMode === "service-summary" ? `services ${serviceStats.length}` : viewMode === "errors" ? `errors ${filteredErrorSummaries.length}/${errorSummaries.length}` : `logs ${filteredLogs.length}/${logs.length}` })
1655
+ ] }),
1656
+ showHelp && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Views: t/l/v/E \u2022 Search: / \u2022 Filters: e/S/R/H/f/x \u2022 Capture: p/r/J \u2022 AI: a \u2022 Clear: c" })
1657
+ ] }),
1658
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginBottom: 0, children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: spanFilters.serviceName || spanFilters.route || spanFilters.statusGroup !== "all" || spanFilters.traceId ? `filters:${spanFilters.serviceName ? ` service=${spanFilters.serviceName}` : ""}${spanFilters.route ? ` route=${spanFilters.route}` : ""}${spanFilters.statusGroup && spanFilters.statusGroup !== "all" ? ` status=${spanFilters.statusGroup}` : ""}${spanFilters.traceId ? ` trace=${spanFilters.traceId.slice(0, 8)}\u2026` : ""}` : "filters: none" }) }),
1657
1659
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
1658
1660
  /* @__PURE__ */ jsxRuntime.jsxs(
1659
1661
  ink.Box,
@@ -1730,71 +1732,79 @@ ${json}
1730
1732
  )
1731
1733
  ] })
1732
1734
  ] }),
1733
- drilldownTraceId != null && drilldownTab === "timeline" && drilldownTimeline.map((item, i) => {
1734
- const isSel = i === drilldownSelectedIndex;
1735
- if (item.type === "span" && item.span) {
1736
- const s = item.span;
1737
- const node = drilldownTree.find(
1738
- (n) => n.span.spanId === s.spanId
1739
- );
1740
- const depth = node?.depth ?? 0;
1741
- const indent = " ".repeat(depth);
1742
- const barLen = Math.max(
1743
- 1,
1744
- Math.round(
1745
- s.durationMs / Math.max(1, drilldownSummary?.durationMs ?? 1) * 10
1746
- )
1747
- );
1748
- const bar = "\u2588".repeat(barLen);
1749
- return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1750
- ink.Text,
1751
- {
1752
- backgroundColor: isSel ? "gray" : void 0,
1753
- color: isSel ? "white" : void 0,
1754
- children: [
1755
- isSel ? "\u25B8" : " ",
1756
- " ",
1757
- indent,
1758
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "green", children: bar }),
1759
- " ",
1760
- s.name,
1761
- " ",
1735
+ drilldownTraceId != null && drilldownTab === "timeline" && (() => {
1736
+ let traceStartMs = Infinity;
1737
+ for (const s of drilldownSummary?.spans ?? []) {
1738
+ if (s.startTime < traceStartMs) traceStartMs = s.startTime;
1739
+ }
1740
+ if (traceStartMs === Infinity) traceStartMs = 0;
1741
+ const traceDurMs = drilldownSummary?.durationMs ?? 1;
1742
+ const WATERFALL_WIDTH = 24;
1743
+ const items = drilldownTimeline.slice(drilldownScrollOffset, drilldownScrollOffset + LIST_HEIGHT);
1744
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1745
+ items.map((item, i) => {
1746
+ const isSel = i + drilldownScrollOffset === drilldownSelectedIndex;
1747
+ if (item.type === "span" && item.span) {
1748
+ const s = item.span;
1749
+ const node = drilldownTree.find(
1750
+ (n) => n.span.spanId === s.spanId
1751
+ );
1752
+ const depth = node?.depth ?? 0;
1753
+ const indent = " ".repeat(Math.min(depth, 4));
1754
+ const nameWidth = 24 - Math.min(depth, 4) * 2;
1755
+ const bar = buildWaterfallBar(
1756
+ s.startTime,
1757
+ s.durationMs,
1758
+ traceStartMs,
1759
+ traceDurMs,
1760
+ WATERFALL_WIDTH
1761
+ );
1762
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1763
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { backgroundColor: isSel ? "gray" : void 0, color: isSel ? "white" : void 0, children: [
1764
+ isSel ? "\u25B8" : " ",
1765
+ indent,
1766
+ truncate(s.name, nameWidth)
1767
+ ] }),
1768
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }),
1769
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: s.status === "ERROR" ? "red" : "green", children: bar }),
1762
1770
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1771
+ " ",
1763
1772
  formatDurationMs(s.durationMs),
1764
1773
  s.kind ? ` ${s.kind}` : ""
1765
1774
  ] })
1766
- ]
1767
- }
1768
- ) }, `${s.spanId}-${i}`);
1769
- } else if (item.type === "log" && item.log) {
1770
- const l = item.log;
1771
- const levelColor = l.level === "error" ? "red" : l.level === "warn" ? "yellow" : "blue";
1772
- const relTime = drilldownSummary ? `+${formatDurationMs(l.time - (drilldownSummary.spans[0]?.startTime ?? l.time))}` : "";
1773
- return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1774
- ink.Text,
1775
- {
1776
- backgroundColor: isSel ? "gray" : void 0,
1777
- color: isSel ? "white" : void 0,
1778
- children: [
1779
- isSel ? "\u25B8" : " ",
1780
- " ",
1781
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: levelColor, children: [
1782
- "\u2139 ",
1783
- l.level.toUpperCase()
1775
+ ] }, `${s.spanId}-${i}`);
1776
+ } else if (item.type === "log" && item.log) {
1777
+ const l = item.log;
1778
+ const levelColor = l.level === "error" ? "red" : l.level === "warn" ? "yellow" : "blue";
1779
+ const relTime = drilldownSummary ? `+${formatDurationMs(l.time - traceStartMs)}` : "";
1780
+ const logOffset = drilldownSummary ? Math.floor((l.time - traceStartMs) / traceDurMs * WATERFALL_WIDTH) : 0;
1781
+ const clampedOffset = Math.max(0, Math.min(logOffset, WATERFALL_WIDTH - 1));
1782
+ const logBar = " ".repeat(clampedOffset) + "\xB7" + " ".repeat(WATERFALL_WIDTH - clampedOffset - 1);
1783
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1784
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { backgroundColor: isSel ? "gray" : void 0, color: isSel ? "white" : void 0, children: [
1785
+ isSel ? "\u25B8" : " ",
1786
+ " ",
1787
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: levelColor, children: l.level.toUpperCase() }),
1788
+ " ",
1789
+ truncate(l.message, 18)
1784
1790
  ] }),
1785
- " ",
1786
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: truncate(l.message, 40) }),
1787
- " ",
1788
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: relTime })
1789
- ]
1791
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }),
1792
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: logBar }),
1793
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1794
+ " ",
1795
+ relTime
1796
+ ] })
1797
+ ] }, `log-${i}`);
1790
1798
  }
1791
- ) }, `log-${i}`);
1792
- }
1793
- return null;
1794
- }),
1795
- drilldownTraceId != null && drilldownTab === "spans" && drilldownTree.map((node, i) => renderTreeRow(node, i)),
1796
- drilldownTraceId != null && drilldownTab === "logs" && drilldownLogs.map((log, i) => {
1797
- const isSel = i === drilldownSelectedIndex;
1799
+ return null;
1800
+ }),
1801
+ Array.from({ length: Math.max(0, LIST_HEIGHT - items.length) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1802
+ ] });
1803
+ })(),
1804
+ drilldownTraceId != null && drilldownTab === "spans" && drilldownTree.slice(drilldownScrollOffset, drilldownScrollOffset + LIST_HEIGHT).map((node, i) => renderTreeRow(node, i + drilldownScrollOffset)),
1805
+ drilldownTraceId != null && drilldownTab === "spans" && Array.from({ length: Math.max(0, LIST_HEIGHT - Math.min(drilldownTree.length, LIST_HEIGHT)) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`)),
1806
+ drilldownTraceId != null && drilldownTab === "logs" && drilldownLogs.slice(drilldownScrollOffset, drilldownScrollOffset + LIST_HEIGHT).map((log, i) => {
1807
+ const isSel = i + drilldownScrollOffset === drilldownSelectedIndex;
1798
1808
  const levelColor = log.level === "error" ? "red" : log.level === "warn" ? "yellow" : log.level === "info" ? "green" : void 0;
1799
1809
  return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1800
1810
  ink.Text,
@@ -1817,110 +1827,143 @@ ${json}
1817
1827
  }
1818
1828
  ) }, `log-${i}`);
1819
1829
  }),
1820
- drilldownTraceId == null && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: viewMode === "trace" ? filteredSummaries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1821
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No traces yet. Call a traced function or hit an endpoint to see them here." }),
1822
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: trace() your handlers with autotel to get spans." })
1823
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: drilldownTraceId == null ? filteredSummaries.slice(0, 20).map((t2, i) => {
1824
- const isSel = i === selected;
1825
- return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1826
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1827
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: t2.hasError ? "red" : void 0, children: truncate(t2.rootName, 20) }),
1828
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1829
- " ",
1830
- formatDurationMs(t2.durationMs)
1831
- ] }),
1832
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1833
- " ",
1834
- truncate(t2.traceId, 8)
1835
- ] }),
1836
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1837
- " ",
1838
- formatRelative(t2.lastEndTime)
1839
- ] })
1840
- ] }, t2.traceId);
1841
- }) : traceTree.slice(0, 20).map((node, i) => renderTreeRow(node, i)) }) : viewMode === "span" ? filteredSpans.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1842
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No spans yet. Call a traced function or hit an endpoint to see them here." }),
1843
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: trace() your handlers with autotel to get spans." })
1844
- ] }) : filteredSpans.slice(0, 20).map((s, i) => {
1845
- const isSel = i === selected;
1846
- const statusColor = s.status === "ERROR" ? "red" : s.durationMs > 500 ? "yellow" : "green";
1847
- return /* @__PURE__ */ jsxRuntime.jsxs(
1848
- ink.Box,
1849
- {
1850
- flexDirection: "row",
1851
- children: [
1852
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1853
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: colors ? statusColor : void 0, children: truncate(s.name, 26) }),
1854
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1855
- " ",
1856
- formatDurationMs(s.durationMs)
1857
- ] }),
1858
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1859
- " ",
1860
- formatRelative(s.endTime)
1861
- ] })
1862
- ]
1863
- },
1864
- `${s.spanId}-${s.startTime}`
1865
- );
1866
- }) : viewMode === "service-summary" ? serviceStats.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No service stats yet. Add `service.name` attributes to spans." }) }) : serviceStats.slice(0, 20).map((svc, i) => {
1867
- const isSel = i === selected;
1868
- const errorRate = svc.total ? svc.errors / svc.total * 100 : 0;
1869
- return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1870
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1871
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: truncate(svc.serviceName, 16) }),
1872
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1873
- " ",
1874
- svc.errors,
1875
- "/",
1876
- svc.total
1877
- ] }),
1878
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1879
- " ",
1880
- errorRate.toFixed(0),
1881
- "%"
1882
- ] }),
1883
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1884
- " p95 ",
1885
- formatDurationMs(svc.p95Ms)
1886
- ] })
1887
- ] }, svc.serviceName);
1888
- }) : viewMode === "errors" ? filteredErrorSummaries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No errors yet." }) }) : filteredErrorSummaries.slice(0, 20).map((e, i) => {
1889
- const isSel = i === selected;
1890
- return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1891
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1892
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "red", children: truncate(e.rootName, 16) }),
1893
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1894
- " ",
1895
- truncate(e.serviceName, 10)
1896
- ] }),
1897
- e.route && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1898
- " ",
1899
- truncate(e.route, 14)
1900
- ] }),
1901
- typeof e.statusCode === "number" && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1902
- " ",
1903
- e.statusCode
1904
- ] }),
1905
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1906
- " (",
1907
- e.errorCount,
1908
- ")"
1909
- ] })
1910
- ] }, e.traceId);
1911
- }) : filteredLogs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1912
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No logs yet. Emit request logs or canonical log lines to see them here." }),
1913
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: hook getTerminalLogStream() into your canonical log line drain." })
1914
- ] }) : filteredLogs.slice(0, 20).map((log, i) => {
1915
- const isSel = i === selected;
1916
- const levelColor = log.level === "error" ? "red" : log.level === "warn" ? "yellow" : log.level === "debug" ? "gray" : "green";
1917
- return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1918
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1919
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: colors ? levelColor : void 0, children: truncate(log.level.toUpperCase(), 5) }),
1920
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }),
1921
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: truncate(log.message, 32) })
1922
- ] }, `${log.time}-${i}`);
1923
- }) })
1830
+ drilldownTraceId != null && drilldownTab === "logs" && Array.from({ length: Math.max(0, LIST_HEIGHT - Math.min(drilldownLogs.length, LIST_HEIGHT)) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`)),
1831
+ drilldownTraceId == null && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: viewMode === "trace" ? filteredSummaries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1832
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1833
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No traces yet. Call a traced function or hit an endpoint to see them here." }),
1834
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: trace() your handlers with autotel to get spans." })
1835
+ ] }),
1836
+ Array.from({ length: Math.max(0, LIST_HEIGHT - 2) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1837
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1838
+ filteredSummaries.slice(0, 20).map((t2, i) => {
1839
+ const isSel = i === selected;
1840
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1841
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u25B8 " : " " }),
1842
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: t2.hasError ? "red" : "yellow", bold: isSel, children: truncate(t2.rootName, 28) }),
1843
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1844
+ " ",
1845
+ t2.spans.length,
1846
+ " spans"
1847
+ ] }),
1848
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "green", children: [
1849
+ " ",
1850
+ formatDurationMs(t2.durationMs)
1851
+ ] }),
1852
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1853
+ " ",
1854
+ formatRelative(t2.lastEndTime)
1855
+ ] }),
1856
+ t2.hasError && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "red", children: " \u25CF" })
1857
+ ] }, t2.traceId);
1858
+ }),
1859
+ Array.from({ length: Math.max(0, LIST_HEIGHT - Math.min(filteredSummaries.length, 20)) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1860
+ ] }) : viewMode === "span" ? filteredSpans.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1861
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1862
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No spans yet. Call a traced function or hit an endpoint to see them here." }),
1863
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: trace() your handlers with autotel to get spans." })
1864
+ ] }),
1865
+ Array.from({ length: Math.max(0, LIST_HEIGHT - 2) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1866
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1867
+ filteredSpans.slice(0, 20).map((s, i) => {
1868
+ const isSel = i === selected;
1869
+ const statusColor = s.status === "ERROR" ? "red" : s.durationMs > 500 ? "yellow" : "green";
1870
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1871
+ ink.Box,
1872
+ {
1873
+ flexDirection: "row",
1874
+ children: [
1875
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1876
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: colors ? statusColor : void 0, children: truncate(s.name, 26) }),
1877
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1878
+ " ",
1879
+ formatDurationMs(s.durationMs)
1880
+ ] }),
1881
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1882
+ " ",
1883
+ formatRelative(s.endTime)
1884
+ ] })
1885
+ ]
1886
+ },
1887
+ `${s.spanId}-${s.startTime}`
1888
+ );
1889
+ }),
1890
+ Array.from({ length: Math.max(0, LIST_HEIGHT - Math.min(filteredSpans.length, 20)) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1891
+ ] }) : viewMode === "service-summary" ? serviceStats.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1892
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No service stats yet. Add `service.name` attributes to spans." }) }),
1893
+ Array.from({ length: Math.max(0, LIST_HEIGHT - 1) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1894
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1895
+ serviceStats.slice(0, 20).map((svc, i) => {
1896
+ const isSel = i === selected;
1897
+ const errorRate = svc.total ? svc.errors / svc.total * 100 : 0;
1898
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1899
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1900
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: truncate(svc.serviceName, 16) }),
1901
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1902
+ " ",
1903
+ svc.errors,
1904
+ "/",
1905
+ svc.total
1906
+ ] }),
1907
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1908
+ " ",
1909
+ errorRate.toFixed(0),
1910
+ "%"
1911
+ ] }),
1912
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1913
+ " p95 ",
1914
+ formatDurationMs(svc.p95Ms)
1915
+ ] })
1916
+ ] }, svc.serviceName);
1917
+ }),
1918
+ Array.from({ length: Math.max(0, LIST_HEIGHT - Math.min(serviceStats.length, 20)) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1919
+ ] }) : viewMode === "errors" ? filteredErrorSummaries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1920
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No errors yet." }) }),
1921
+ Array.from({ length: Math.max(0, LIST_HEIGHT - 1) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1922
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1923
+ filteredErrorSummaries.slice(0, 20).map((e, i) => {
1924
+ const isSel = i === selected;
1925
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1926
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1927
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "red", children: truncate(e.rootName, 16) }),
1928
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1929
+ " ",
1930
+ truncate(e.serviceName, 10)
1931
+ ] }),
1932
+ e.route && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1933
+ " ",
1934
+ truncate(e.route, 14)
1935
+ ] }),
1936
+ typeof e.statusCode === "number" && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1937
+ " ",
1938
+ e.statusCode
1939
+ ] }),
1940
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1941
+ " (",
1942
+ e.errorCount,
1943
+ ")"
1944
+ ] })
1945
+ ] }, e.traceId);
1946
+ }),
1947
+ Array.from({ length: Math.max(0, LIST_HEIGHT - Math.min(filteredErrorSummaries.length, 20)) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1948
+ ] }) : filteredLogs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1949
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1950
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No logs yet. Emit request logs or canonical log lines to see them here." }),
1951
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: hook getTerminalLogStream() into your canonical log line drain." })
1952
+ ] }),
1953
+ Array.from({ length: Math.max(0, LIST_HEIGHT - 2) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1954
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1955
+ filteredLogs.slice(0, 20).map((log, i) => {
1956
+ const isSel = i === selected;
1957
+ const levelColor = log.level === "error" ? "red" : log.level === "warn" ? "yellow" : log.level === "debug" ? "gray" : "green";
1958
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1959
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1960
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: colors ? levelColor : void 0, children: truncate(log.level.toUpperCase(), 5) }),
1961
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }),
1962
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: truncate(log.message, 32) })
1963
+ ] }, `${log.time}-${i}`);
1964
+ }),
1965
+ Array.from({ length: Math.max(0, LIST_HEIGHT - Math.min(filteredLogs.length, 20)) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }) }, `pad-${i}`))
1966
+ ] }) })
1924
1967
  ]
1925
1968
  }
1926
1969
  ),