autotel-terminal 17.0.2 → 17.0.4

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
@@ -130,6 +130,10 @@ function createTerminalSpanStream(processor) {
130
130
  }
131
131
 
132
132
  // src/lib/trace-model.ts
133
+ function spanServiceName(span) {
134
+ const svc = span.attributes?.["service.name"];
135
+ return typeof svc === "string" ? svc : "unknown";
136
+ }
133
137
  function buildTraceMap(spans, maxTraces = 50) {
134
138
  const byTrace = /* @__PURE__ */ new Map();
135
139
  for (const s of spans) {
@@ -153,6 +157,7 @@ function buildTraceSummaries(traceMap) {
153
157
  const durationMs = root ? root.durationMs : 0;
154
158
  const hasError = traceSpans.some((s) => s.status === "ERROR");
155
159
  const lastEndTime = Math.max(...traceSpans.map((s) => s.endTime));
160
+ const services = [...new Set(traceSpans.map((s) => spanServiceName(s)))];
156
161
  summaries.push({
157
162
  traceId,
158
163
  rootName: root?.name ?? "unknown",
@@ -160,7 +165,8 @@ function buildTraceSummaries(traceMap) {
160
165
  hasError,
161
166
  spanCount: traceSpans.length,
162
167
  lastEndTime,
163
- spans: traceSpans
168
+ spans: traceSpans,
169
+ services
164
170
  });
165
171
  }
166
172
  return summaries;
@@ -265,6 +271,56 @@ function truncate(s, width) {
265
271
  if (s.length <= width) return s;
266
272
  return s.slice(0, Math.max(0, width - 1)) + "\u2026";
267
273
  }
274
+ function buildWaterfallBar(spanStart, spanDuration, traceStart, traceDuration, width) {
275
+ if (traceDuration <= 0) return " ".repeat(width);
276
+ const offsetRatio = (spanStart - traceStart) / traceDuration;
277
+ const widthRatio = spanDuration / traceDuration;
278
+ const barStart = Math.max(0, Math.floor(offsetRatio * width));
279
+ const barLen = Math.max(1, Math.round(widthRatio * width));
280
+ const clampedStart = Math.min(barStart, width - 1);
281
+ const clampedLen = Math.min(barLen, width - clampedStart);
282
+ const trailing = Math.max(0, width - clampedStart - clampedLen);
283
+ return " ".repeat(clampedStart) + "\u2588".repeat(clampedLen) + " ".repeat(trailing);
284
+ }
285
+ function buildTimeRuler(totalMs, width) {
286
+ const left = "0ms";
287
+ const right = formatDurationMs(totalMs);
288
+ const mid = formatDurationMs(totalMs / 2);
289
+ const midPos = Math.floor(width / 2) - Math.floor(mid.length / 2);
290
+ const rightPos = width - right.length;
291
+ const chars = Array.from({ length: width }).fill(" ");
292
+ for (let i = 0; i < left.length && i < width; i++) chars[i] = left[i];
293
+ if (midPos > left.length + 1 && midPos + mid.length < rightPos - 1) {
294
+ for (let i = 0; i < mid.length; i++) chars[midPos + i] = mid[i];
295
+ }
296
+ for (let i = 0; i < right.length; i++) chars[rightPos + i] = right[i];
297
+ return chars.join("");
298
+ }
299
+
300
+ // src/lib/service-colors.ts
301
+ var SERVICE_COLORS = [
302
+ "cyan",
303
+ "magenta",
304
+ "blue",
305
+ "yellow",
306
+ "green",
307
+ "redBright",
308
+ "cyanBright",
309
+ "magentaBright",
310
+ "blueBright",
311
+ "yellowBright",
312
+ "greenBright"
313
+ ];
314
+ function hashString(s) {
315
+ let hash = 0;
316
+ for (let i = 0; i < s.length; i++) {
317
+ hash = Math.trunc((hash << 5) - hash + s.codePointAt(i));
318
+ }
319
+ return Math.abs(hash);
320
+ }
321
+ function getServiceColor(serviceName) {
322
+ return SERVICE_COLORS[hashString(serviceName) % SERVICE_COLORS.length];
323
+ }
268
324
 
269
325
  // src/lib/log-model.ts
270
326
  function filterLogsBySearch(logs, searchQuery, minLevel) {
@@ -846,6 +902,7 @@ var THROTTLE_MS = 50;
846
902
  var MAX_TRACES = 50;
847
903
  var NEW_ERROR_DISPLAY_MS = 2e3;
848
904
  var RECORD_LIMIT_DEFAULT = 200;
905
+ var LIST_HEIGHT = 20;
849
906
  function Dashboard({
850
907
  title,
851
908
  showStats,
@@ -868,6 +925,7 @@ function Dashboard({
868
925
  });
869
926
  const [drilldownTraceId, setDrilldownTraceId] = react.useState(null);
870
927
  const [drilldownSelectedIndex, setDrilldownSelectedIndex] = react.useState(0);
928
+ const [drilldownScrollOffset, setDrilldownScrollOffset] = react.useState(0);
871
929
  const [drilldownTab, setDrilldownTab] = react.useState("timeline");
872
930
  const [newErrorCount, setNewErrorCount] = react.useState(0);
873
931
  const [searchMode, setSearchMode] = react.useState(false);
@@ -1275,6 +1333,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1275
1333
  } else {
1276
1334
  setDrilldownTraceId(null);
1277
1335
  setDrilldownSelectedIndex(0);
1336
+ setDrilldownScrollOffset(0);
1278
1337
  setDrilldownTab("timeline");
1279
1338
  }
1280
1339
  return;
@@ -1289,6 +1348,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1289
1348
  const nextIdx = key.shift ? (currentIdx - 1 + tabs.length) % tabs.length : (currentIdx + 1) % tabs.length;
1290
1349
  setDrilldownTab(tabs[nextIdx]);
1291
1350
  setDrilldownSelectedIndex(0);
1351
+ setDrilldownScrollOffset(0);
1292
1352
  return;
1293
1353
  }
1294
1354
  if (key.return && drilldownTraceId == null) {
@@ -1320,6 +1380,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1320
1380
  if (targetTraceId) {
1321
1381
  setDrilldownTraceId(targetTraceId);
1322
1382
  setDrilldownSelectedIndex(preSelectIndex);
1383
+ setDrilldownScrollOffset(Math.max(0, preSelectIndex - LIST_HEIGHT + 1));
1323
1384
  setDrilldownTab("timeline");
1324
1385
  return;
1325
1386
  }
@@ -1328,9 +1389,19 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1328
1389
  if (drilldownTraceId != null) {
1329
1390
  const listLength = drilldownTab === "timeline" ? drilldownTimeline.length : drilldownTab === "spans" ? drilldownTree.length : drilldownLogs.length;
1330
1391
  if (key.upArrow) {
1331
- setDrilldownSelectedIndex((i) => Math.max(0, i - 1));
1392
+ setDrilldownSelectedIndex((prev) => {
1393
+ const next = Math.max(0, prev - 1);
1394
+ setDrilldownScrollOffset((off) => Math.min(next, off));
1395
+ return next;
1396
+ });
1332
1397
  } else {
1333
- setDrilldownSelectedIndex((i) => Math.min(listLength - 1, i + 1));
1398
+ setDrilldownSelectedIndex((prev) => {
1399
+ const next = Math.min(listLength - 1, prev + 1);
1400
+ setDrilldownScrollOffset(
1401
+ (off) => next >= off + LIST_HEIGHT ? next - LIST_HEIGHT + 1 : off
1402
+ );
1403
+ return next;
1404
+ });
1334
1405
  }
1335
1406
  return;
1336
1407
  }
@@ -1388,12 +1459,14 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1388
1459
  setSelected(0);
1389
1460
  setDrilldownTraceId(null);
1390
1461
  setDrilldownSelectedIndex(0);
1462
+ setDrilldownScrollOffset(0);
1391
1463
  }
1392
1464
  if (input === "l") {
1393
1465
  setViewMode((m) => m === "log" ? "trace" : "log");
1394
1466
  setSelected(0);
1395
1467
  setDrilldownTraceId(null);
1396
1468
  setDrilldownSelectedIndex(0);
1469
+ setDrilldownScrollOffset(0);
1397
1470
  }
1398
1471
  if (input === "v") {
1399
1472
  setViewMode(
@@ -1402,12 +1475,14 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1402
1475
  setSelected(0);
1403
1476
  setDrilldownTraceId(null);
1404
1477
  setDrilldownSelectedIndex(0);
1478
+ setDrilldownScrollOffset(0);
1405
1479
  }
1406
1480
  if (input === "E") {
1407
1481
  setViewMode((m) => m === "errors" ? "trace" : "errors");
1408
1482
  setSelected(0);
1409
1483
  setDrilldownTraceId(null);
1410
1484
  setDrilldownSelectedIndex(0);
1485
+ setDrilldownScrollOffset(0);
1411
1486
  }
1412
1487
  if (input === "c") {
1413
1488
  setSpans([]);
@@ -1415,6 +1490,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1415
1490
  setSelected(0);
1416
1491
  setDrilldownTraceId(null);
1417
1492
  setDrilldownSelectedIndex(0);
1493
+ setDrilldownScrollOffset(0);
1418
1494
  setNewErrorCount(0);
1419
1495
  setSpanFilters({ statusGroup: "all" });
1420
1496
  setRecording(false);
@@ -1426,6 +1502,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1426
1502
  setSelected(0);
1427
1503
  setDrilldownTraceId(null);
1428
1504
  setDrilldownSelectedIndex(0);
1505
+ setDrilldownScrollOffset(0);
1429
1506
  setNewErrorCount(0);
1430
1507
  setSpanFilters({ statusGroup: "all" });
1431
1508
  setPaused(false);
@@ -1436,6 +1513,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1436
1513
  setSelected(0);
1437
1514
  setDrilldownTraceId(null);
1438
1515
  setDrilldownSelectedIndex(0);
1516
+ setDrilldownScrollOffset(0);
1439
1517
  }
1440
1518
  if (input === "f") {
1441
1519
  setTraceIdMode(true);
@@ -1450,6 +1528,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1450
1528
  setSelected(0);
1451
1529
  setDrilldownTraceId(null);
1452
1530
  setDrilldownSelectedIndex(0);
1531
+ setDrilldownScrollOffset(0);
1453
1532
  }
1454
1533
  if (input === "S") {
1455
1534
  const svc = currentSpan?.attributes?.["service.name"];
@@ -1458,6 +1537,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1458
1537
  setSelected(0);
1459
1538
  setDrilldownTraceId(null);
1460
1539
  setDrilldownSelectedIndex(0);
1540
+ setDrilldownScrollOffset(0);
1461
1541
  }
1462
1542
  }
1463
1543
  if (input === "R") {
@@ -1467,6 +1547,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1467
1547
  setSelected(0);
1468
1548
  setDrilldownTraceId(null);
1469
1549
  setDrilldownSelectedIndex(0);
1550
+ setDrilldownScrollOffset(0);
1470
1551
  }
1471
1552
  }
1472
1553
  if (input === "T") {
@@ -1495,6 +1576,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1495
1576
  setSelected(0);
1496
1577
  setDrilldownTraceId(null);
1497
1578
  setDrilldownSelectedIndex(0);
1579
+ setDrilldownScrollOffset(0);
1498
1580
  setDrilldownTab("timeline");
1499
1581
  }
1500
1582
  return;
@@ -1525,6 +1607,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
1525
1607
  setSelected(0);
1526
1608
  setDrilldownTraceId(null);
1527
1609
  setDrilldownSelectedIndex(0);
1610
+ setDrilldownScrollOffset(0);
1528
1611
  setDrilldownTab("timeline");
1529
1612
  }
1530
1613
  return;
@@ -1547,15 +1630,25 @@ ${json}
1547
1630
  function renderTreeRow(node, index) {
1548
1631
  const isSel = drilldownTraceId != null && index === drilldownSelectedIndex;
1549
1632
  const prefix = node.depth === 0 ? "" : " ".repeat(node.depth) + (node.children.length > 0 ? "\u251C\u2500\u2500 " : "\u2514\u2500\u2500 ");
1633
+ const svcName = spanServiceName(node.span);
1634
+ const svcColor = getServiceColor(svcName);
1550
1635
  const statusColor = node.span.status === "ERROR" ? "red" : node.span.durationMs > 500 ? "yellow" : "green";
1551
1636
  return /* @__PURE__ */ jsxRuntime.jsxs(
1552
1637
  ink.Box,
1553
1638
  {
1554
1639
  flexDirection: "row",
1555
1640
  children: [
1556
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1641
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { backgroundColor: isSel ? "blue" : void 0, color: isSel ? "white" : void 0, children: isSel ? "\u25B8 " : " " }),
1557
1642
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: prefix }),
1558
1643
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: colors ? statusColor : void 0, children: truncate(node.span.name, 24) }),
1644
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: svcColor, children: [
1645
+ " ",
1646
+ truncate(svcName, 10)
1647
+ ] }),
1648
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1649
+ " ",
1650
+ node.span.kind ?? ""
1651
+ ] }),
1559
1652
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1560
1653
  " ",
1561
1654
  formatDurationMs(node.span.durationMs)
@@ -1582,9 +1675,7 @@ ${json}
1582
1675
  ink.Box,
1583
1676
  {
1584
1677
  flexDirection: "column",
1585
- borderStyle: "round",
1586
- padding: 1,
1587
- borderColor: colors ? "cyan" : void 0,
1678
+ paddingX: 1,
1588
1679
  children: [
1589
1680
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { justifyContent: "space-between", marginBottom: 1, children: [
1590
1681
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { bold: true, children: [
@@ -1598,69 +1689,283 @@ ${json}
1598
1689
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: paused ? "yellow" : "green", children: headerRight }, "status")
1599
1690
  ] })
1600
1691
  ] }),
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",
1692
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "column", children: [
1693
+ searchMode ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "cyan", children: [
1694
+ "Search: ",
1695
+ searchQuery || "(type to filter)",
1696
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: " (Tab: match traceId, Esc: cancel)" })
1697
+ ] }) : traceIdMode ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "yellow", children: [
1698
+ "TraceId: ",
1699
+ traceIdInput || "(type prefix, Tab to complete)",
1700
+ traceIdInput.length >= 2 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1701
+ " \u2192 ",
1702
+ traceSummaries.find(
1703
+ (t2) => t2.traceId.toLowerCase().startsWith(traceIdInput.toLowerCase())
1704
+ )?.traceId.slice(0, 16) ?? "no match",
1705
+ "\u2026"
1706
+ ] })
1707
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", justifyContent: "space-between", children: [
1708
+ /* @__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" }),
1709
+ /* @__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}` })
1710
+ ] }),
1711
+ 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" })
1712
+ ] }),
1713
+ /* @__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" }) }),
1714
+ drilldownTraceId != null ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, paddingY: 0, children: [
1715
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "column", children: [
1716
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { bold: true, children: [
1717
+ "Trace ",
1718
+ drilldownTraceId.slice(0, 16),
1719
+ "\u2026"
1720
+ ] }),
1721
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 1, children: [
1722
+ drilldownSummary?.services?.map((svc) => /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: getServiceColor(svc), children: svc }, svc)),
1723
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "\xB7" }),
1724
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: drilldownSummary?.rootName ?? "unknown" }),
1725
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "\xB7" }),
1726
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1727
+ drilldownSpans.length,
1728
+ " spans"
1729
+ ] }),
1730
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "\xB7" }),
1731
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1732
+ drilldownSummary?.services?.length ?? 0,
1733
+ " services"
1734
+ ] }),
1735
+ drilldownSummary?.hasError && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "red", children: [
1736
+ " ",
1737
+ "ERROR"
1738
+ ] })
1739
+ ] }),
1740
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
1741
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Duration: " }),
1742
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "green", children: formatDurationMs(drilldownSummary?.durationMs ?? 0) })
1743
+ ] })
1744
+ ] }),
1745
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "row", gap: 2, children: [
1746
+ /* @__PURE__ */ jsxRuntime.jsx(
1747
+ ink.Text,
1748
+ {
1749
+ color: drilldownTab === "timeline" ? "blue" : void 0,
1750
+ dimColor: drilldownTab !== "timeline",
1751
+ bold: drilldownTab === "timeline",
1752
+ children: "Timeline"
1753
+ }
1754
+ ),
1755
+ /* @__PURE__ */ jsxRuntime.jsxs(
1756
+ ink.Text,
1757
+ {
1758
+ color: drilldownTab === "spans" ? "blue" : void 0,
1759
+ dimColor: drilldownTab !== "spans",
1760
+ bold: drilldownTab === "spans",
1761
+ children: [
1762
+ "Spans (",
1763
+ drilldownSpans.length,
1764
+ ")"
1765
+ ]
1766
+ }
1767
+ ),
1768
+ /* @__PURE__ */ jsxRuntime.jsxs(
1769
+ ink.Text,
1770
+ {
1771
+ color: drilldownTab === "logs" ? "blue" : void 0,
1772
+ dimColor: drilldownTab !== "logs",
1773
+ bold: drilldownTab === "logs",
1774
+ children: [
1775
+ "Logs (",
1776
+ drilldownLogs.length,
1777
+ ")"
1778
+ ]
1779
+ }
1780
+ )
1781
+ ] }),
1782
+ drilldownTab === "timeline" && (() => {
1783
+ const NAME_COL = 28;
1784
+ const SERVICE_COL = 12;
1785
+ const KIND_COL = 10;
1786
+ let traceStartMs = Infinity;
1787
+ for (const s of drilldownSummary?.spans ?? []) {
1788
+ if (s.startTime < traceStartMs) traceStartMs = s.startTime;
1789
+ }
1790
+ if (traceStartMs === Infinity) traceStartMs = 0;
1791
+ const traceDurMs = drilldownSummary?.durationMs ?? 1;
1792
+ const WATERFALL_WIDTH = 44;
1793
+ const items = drilldownTimeline.slice(drilldownScrollOffset, drilldownScrollOffset + LIST_HEIGHT);
1794
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1795
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1796
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "".padEnd(NAME_COL + SERVICE_COL + KIND_COL + 2) }),
1797
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: buildTimeRuler(traceDurMs, WATERFALL_WIDTH) })
1798
+ ] }),
1799
+ items.map((item, i) => {
1800
+ const isSel = i + drilldownScrollOffset === drilldownSelectedIndex;
1801
+ if (item.type === "span" && item.span) {
1802
+ const s = item.span;
1803
+ const node = drilldownTree.find(
1804
+ (n) => n.span.spanId === s.spanId
1805
+ );
1806
+ const depth = node?.depth ?? 0;
1807
+ const indent = " ".repeat(Math.min(depth, 4));
1808
+ const nameWidth = NAME_COL - Math.min(depth, 4) * 2 - 1;
1809
+ const svcName = spanServiceName(s);
1810
+ const svcColor = getServiceColor(svcName);
1811
+ const kindStr = (s.kind ?? "").padEnd(KIND_COL);
1812
+ const svcStr = truncate(svcName, SERVICE_COL - 2).padEnd(SERVICE_COL);
1813
+ const namePart = `${indent}${truncate(s.name, nameWidth)}`.padEnd(NAME_COL);
1814
+ const bar = buildWaterfallBar(
1815
+ s.startTime,
1816
+ s.durationMs,
1817
+ traceStartMs,
1818
+ traceDurMs,
1819
+ WATERFALL_WIDTH
1820
+ );
1821
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1822
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { backgroundColor: isSel ? "blue" : void 0, color: isSel ? "white" : void 0, children: [
1823
+ isSel ? "\u25B8" : " ",
1824
+ namePart
1825
+ ] }),
1826
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: svcColor, children: [
1827
+ " ",
1828
+ svcStr
1829
+ ] }),
1830
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: kindStr }),
1831
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: s.status === "ERROR" ? "red" : svcColor, children: bar }),
1832
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: s.status === "ERROR" ? "red" : svcColor, children: [
1833
+ " ",
1834
+ formatDurationMs(s.durationMs)
1835
+ ] })
1836
+ ] }, `${s.spanId}-${i}`);
1837
+ } else if (item.type === "log" && item.log) {
1838
+ const l = item.log;
1839
+ const levelColor = l.level === "error" ? "red" : l.level === "warn" ? "yellow" : "blue";
1840
+ const relTime = drilldownSummary ? `+${formatDurationMs(l.time - traceStartMs)}` : "";
1841
+ const logName = ` ${l.level.toUpperCase()} ${truncate(l.message, NAME_COL - 8)}`.padEnd(NAME_COL);
1842
+ const logOffset = drilldownSummary ? Math.floor((l.time - traceStartMs) / traceDurMs * WATERFALL_WIDTH) : 0;
1843
+ const clampedOffset = Math.max(0, Math.min(logOffset, WATERFALL_WIDTH - 1));
1844
+ const logBar = " ".repeat(clampedOffset) + "\xB7" + " ".repeat(WATERFALL_WIDTH - clampedOffset - 1);
1845
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1846
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { backgroundColor: isSel ? "blue" : void 0, color: isSel ? "white" : void 0, children: [
1847
+ isSel ? "\u25B8" : " ",
1848
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: levelColor, children: logName })
1849
+ ] }),
1850
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: " ".padEnd(SERVICE_COL + KIND_COL + 1) }),
1851
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: logBar }),
1852
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1853
+ " ",
1854
+ relTime
1855
+ ] })
1856
+ ] }, `log-${i}`);
1857
+ }
1858
+ return null;
1859
+ }),
1860
+ 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}`))
1861
+ ] });
1862
+ })(),
1863
+ drilldownTab === "spans" && drilldownTree.slice(drilldownScrollOffset, drilldownScrollOffset + LIST_HEIGHT).map((node, i) => renderTreeRow(node, i + drilldownScrollOffset)),
1864
+ 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}`)),
1865
+ drilldownTab === "logs" && drilldownLogs.slice(drilldownScrollOffset, drilldownScrollOffset + LIST_HEIGHT).map((log, i) => {
1866
+ const isSel = i + drilldownScrollOffset === drilldownSelectedIndex;
1867
+ const levelColor = log.level === "error" ? "red" : log.level === "warn" ? "yellow" : log.level === "info" ? "green" : void 0;
1868
+ return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1869
+ ink.Text,
1870
+ {
1871
+ backgroundColor: isSel ? "blue" : void 0,
1872
+ color: isSel ? "white" : void 0,
1873
+ children: [
1874
+ isSel ? "\u25B8" : " ",
1875
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: levelColor, children: [
1876
+ " ",
1877
+ log.level.toUpperCase()
1878
+ ] }),
1639
1879
  " ",
1640
- traceSummaries.find(
1641
- (t2) => t2.traceId.toLowerCase().startsWith(traceIdInput.toLowerCase())
1642
- )?.traceId.slice(0, 16) ?? "no match",
1643
- "\u2026"
1880
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1881
+ "[",
1882
+ truncate(log.message, 50),
1883
+ "]"
1884
+ ] })
1885
+ ]
1886
+ }
1887
+ ) }, `log-${i}`);
1888
+ }),
1889
+ 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}`)),
1890
+ drilldownSelectedItem?.type === "span" && drilldownSelectedItem.span && (() => {
1891
+ const span = drilldownSelectedItem.span;
1892
+ const { key: keyAttrs, rest: restAttrs } = keyAttrsAndRest(span.attributes);
1893
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
1894
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
1895
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: span.name }),
1896
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: getServiceColor(spanServiceName(span)), children: spanServiceName(span) }),
1897
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: span.kind ?? "" }),
1898
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: span.status === "ERROR" ? "red" : "green", children: span.status }),
1899
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: formatDurationMs(span.durationMs) })
1900
+ ] }),
1901
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
1902
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1903
+ "Trace: ",
1904
+ span.traceId
1905
+ ] }),
1906
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1907
+ "Span: ",
1908
+ span.spanId
1909
+ ] }),
1910
+ span.parentSpanId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1911
+ "Parent: ",
1912
+ span.parentSpanId
1644
1913
  ] })
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
- ] }) }),
1657
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
1914
+ ] }),
1915
+ keyAttrs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
1916
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Key attributes" }),
1917
+ keyAttrs.slice(0, 6).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1918
+ truncate(k, 18),
1919
+ ": ",
1920
+ truncate(String(v), 28)
1921
+ ] }, k))
1922
+ ] }),
1923
+ restAttrs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
1924
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Attributes" }),
1925
+ restAttrs.slice(0, 8).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1926
+ truncate(k, 18),
1927
+ ": ",
1928
+ truncate(String(v), 28)
1929
+ ] }, k))
1930
+ ] })
1931
+ ] });
1932
+ })(),
1933
+ drilldownSelectedItem?.type === "log" && drilldownSelectedItem.log && (() => {
1934
+ const log = drilldownSelectedItem.log;
1935
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
1936
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
1937
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: log.level.toUpperCase() }),
1938
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: log.message })
1939
+ ] }),
1940
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
1941
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Time: " }),
1942
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: new Date(log.time).toISOString() })
1943
+ ] }),
1944
+ log.traceId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1945
+ "Trace: ",
1946
+ log.traceId
1947
+ ] }),
1948
+ log.spanId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1949
+ "Span: ",
1950
+ log.spanId
1951
+ ] }),
1952
+ log.attributes && Object.keys(log.attributes).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
1953
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Attributes" }),
1954
+ Object.entries(log.attributes).slice(0, 10).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1955
+ truncate(k, 18),
1956
+ ": ",
1957
+ truncate(String(v), 40)
1958
+ ] }, k))
1959
+ ] })
1960
+ ] });
1961
+ })()
1962
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
1658
1963
  /* @__PURE__ */ jsxRuntime.jsxs(
1659
1964
  ink.Box,
1660
1965
  {
1661
1966
  flexDirection: "column",
1662
1967
  width: "55%",
1663
- borderStyle: "single",
1968
+ borderStyle: "round",
1664
1969
  borderColor: "gray",
1665
1970
  paddingX: 1,
1666
1971
  paddingY: 0,
@@ -1677,250 +1982,153 @@ ${json}
1677
1982
  searchQuery
1678
1983
  ] }, "search-label")
1679
1984
  ] }),
1680
- drilldownTraceId != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1681
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "row", gap: 2, children: [
1682
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "yellow", children: drilldownSummary?.rootName ?? "unknown" }),
1683
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1684
- drilldownTraceId.slice(0, 16),
1685
- "\u2026"
1686
- ] }),
1687
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "green", children: drilldownSummary ? formatDurationMs(drilldownSummary.durationMs) : "?" }),
1688
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1689
- drilldownSpans.length,
1690
- " spans \u2022 ",
1691
- drilldownLogs.length,
1692
- " logs"
1693
- ] })
1985
+ /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: viewMode === "trace" ? filteredSummaries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1986
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1987
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No traces yet. Call a traced function or hit an endpoint to see them here." }),
1988
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: trace() your handlers with autotel to get spans." })
1694
1989
  ] }),
1695
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "row", gap: 2, children: [
1696
- /* @__PURE__ */ jsxRuntime.jsx(
1697
- ink.Text,
1698
- {
1699
- color: drilldownTab === "timeline" ? "yellow" : void 0,
1700
- dimColor: drilldownTab !== "timeline",
1701
- underline: drilldownTab === "timeline",
1702
- children: "Timeline"
1703
- }
1704
- ),
1705
- /* @__PURE__ */ jsxRuntime.jsxs(
1706
- ink.Text,
1707
- {
1708
- color: drilldownTab === "spans" ? "yellow" : void 0,
1709
- dimColor: drilldownTab !== "spans",
1710
- underline: drilldownTab === "spans",
1711
- children: [
1712
- "Spans (",
1713
- drilldownSpans.length,
1714
- ")"
1715
- ]
1716
- }
1717
- ),
1718
- /* @__PURE__ */ jsxRuntime.jsxs(
1719
- ink.Text,
1720
- {
1721
- color: drilldownTab === "logs" ? "yellow" : void 0,
1722
- dimColor: drilldownTab !== "logs",
1723
- underline: drilldownTab === "logs",
1724
- children: [
1725
- "Logs (",
1726
- drilldownLogs.length,
1727
- ")"
1728
- ]
1729
- }
1730
- )
1731
- ] })
1732
- ] }),
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,
1990
+ 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}`))
1991
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1992
+ filteredSummaries.slice(0, 20).map((t2, i) => {
1993
+ const isSel = i === selected;
1994
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
1995
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u25B8 " : " " }),
1996
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: t2.hasError ? "red" : "yellow", bold: isSel, children: truncate(t2.rootName, 28) }),
1997
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1998
+ " ",
1999
+ t2.spans.length,
2000
+ " spans"
2001
+ ] }),
2002
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "green", children: [
2003
+ " ",
2004
+ formatDurationMs(t2.durationMs)
2005
+ ] }),
2006
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2007
+ " ",
2008
+ formatRelative(t2.lastEndTime)
2009
+ ] }),
2010
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2011
+ " ",
2012
+ t2.traceId.slice(0, 12),
2013
+ "\u2026"
2014
+ ] }),
2015
+ t2.hasError && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "red", children: " \u25CF" })
2016
+ ] }, t2.traceId);
2017
+ }),
2018
+ 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}`))
2019
+ ] }) : viewMode === "span" ? filteredSpans.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2020
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
2021
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No spans yet. Call a traced function or hit an endpoint to see them here." }),
2022
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: trace() your handlers with autotel to get spans." })
2023
+ ] }),
2024
+ 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}`))
2025
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2026
+ filteredSpans.slice(0, 20).map((s, i) => {
2027
+ const isSel = i === selected;
2028
+ const svcName = spanServiceName(s);
2029
+ const svcColor = getServiceColor(svcName);
2030
+ const statusColor = s.status === "ERROR" ? "red" : s.durationMs > 500 ? "yellow" : "green";
2031
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2032
+ ink.Box,
1751
2033
  {
1752
- backgroundColor: isSel ? "gray" : void 0,
1753
- color: isSel ? "white" : void 0,
2034
+ flexDirection: "row",
1754
2035
  children: [
1755
- isSel ? "\u25B8" : " ",
1756
- " ",
1757
- indent,
1758
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "green", children: bar }),
1759
- " ",
1760
- s.name,
1761
- " ",
2036
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
2037
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: colors ? statusColor : void 0, children: truncate(s.name, 26) }),
2038
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: svcColor, children: [
2039
+ " ",
2040
+ truncate(svcName, 10)
2041
+ ] }),
1762
2042
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1763
- formatDurationMs(s.durationMs),
1764
- s.kind ? ` ${s.kind}` : ""
1765
- ] })
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()
2043
+ " ",
2044
+ formatDurationMs(s.durationMs)
1784
2045
  ] }),
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 })
2046
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2047
+ " ",
2048
+ formatRelative(s.endTime)
2049
+ ] })
1789
2050
  ]
1790
- }
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;
1798
- const levelColor = log.level === "error" ? "red" : log.level === "warn" ? "yellow" : log.level === "info" ? "green" : void 0;
1799
- return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1800
- ink.Text,
1801
- {
1802
- backgroundColor: isSel ? "gray" : void 0,
1803
- color: isSel ? "white" : void 0,
1804
- children: [
1805
- isSel ? "\u25B8" : " ",
1806
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: levelColor, children: [
1807
- " ",
1808
- log.level.toUpperCase()
1809
- ] }),
2051
+ },
2052
+ `${s.spanId}-${s.startTime}`
2053
+ );
2054
+ }),
2055
+ 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}`))
2056
+ ] }) : viewMode === "service-summary" ? serviceStats.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2057
+ /* @__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." }) }),
2058
+ 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}`))
2059
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2060
+ serviceStats.slice(0, 20).map((svc, i) => {
2061
+ const isSel = i === selected;
2062
+ const errorRate = svc.total ? svc.errors / svc.total * 100 : 0;
2063
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
2064
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
2065
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: truncate(svc.serviceName, 16) }),
2066
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1810
2067
  " ",
1811
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1812
- "[",
1813
- truncate(log.message, 50),
1814
- "]"
1815
- ] })
1816
- ]
1817
- }
1818
- ) }, `log-${i}`);
1819
- }),
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
- }) })
2068
+ svc.errors,
2069
+ "/",
2070
+ svc.total
2071
+ ] }),
2072
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2073
+ " ",
2074
+ errorRate.toFixed(0),
2075
+ "%"
2076
+ ] }),
2077
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2078
+ " p95 ",
2079
+ formatDurationMs(svc.p95Ms)
2080
+ ] })
2081
+ ] }, svc.serviceName);
2082
+ }),
2083
+ 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}`))
2084
+ ] }) : viewMode === "errors" ? filteredErrorSummaries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2085
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No errors yet." }) }),
2086
+ 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}`))
2087
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2088
+ filteredErrorSummaries.slice(0, 20).map((e, i) => {
2089
+ const isSel = i === selected;
2090
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
2091
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
2092
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "red", children: truncate(e.rootName, 16) }),
2093
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2094
+ " ",
2095
+ truncate(e.serviceName, 10)
2096
+ ] }),
2097
+ e.route && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2098
+ " ",
2099
+ truncate(e.route, 14)
2100
+ ] }),
2101
+ typeof e.statusCode === "number" && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2102
+ " ",
2103
+ e.statusCode
2104
+ ] }),
2105
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2106
+ " (",
2107
+ e.errorCount,
2108
+ ")"
2109
+ ] })
2110
+ ] }, e.traceId);
2111
+ }),
2112
+ 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}`))
2113
+ ] }) : filteredLogs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2114
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
2115
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No logs yet. Emit request logs or canonical log lines to see them here." }),
2116
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: hook getTerminalLogStream() into your canonical log line drain." })
2117
+ ] }),
2118
+ 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}`))
2119
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2120
+ filteredLogs.slice(0, 20).map((log, i) => {
2121
+ const isSel = i === selected;
2122
+ const levelColor = log.level === "error" ? "red" : log.level === "warn" ? "yellow" : log.level === "debug" ? "gray" : "green";
2123
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", children: [
2124
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
2125
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: colors ? levelColor : void 0, children: truncate(log.level.toUpperCase(), 5) }),
2126
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }),
2127
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: truncate(log.message, 32) })
2128
+ ] }, `${log.time}-${i}`);
2129
+ }),
2130
+ 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}`))
2131
+ ] }) })
1924
2132
  ]
1925
2133
  }
1926
2134
  ),
@@ -1929,7 +2137,7 @@ ${json}
1929
2137
  {
1930
2138
  flexDirection: "column",
1931
2139
  width: "45%",
1932
- borderStyle: "single",
2140
+ borderStyle: "round",
1933
2141
  borderColor: "gray",
1934
2142
  paddingX: 1,
1935
2143
  paddingY: 0,
@@ -1977,92 +2185,7 @@ ${json}
1977
2185
  ] })
1978
2186
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1979
2187
  /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginBottom: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Details" }) }),
1980
- drilldownTraceId != null && drilldownSelectedItem?.type === "span" && drilldownSelectedItem.span ? (() => {
1981
- const span = drilldownSelectedItem.span;
1982
- const { key: keyAttrs, rest: restAttrs } = keyAttrsAndRest(
1983
- span.attributes
1984
- );
1985
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1986
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
1987
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Name: " }),
1988
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: span.name })
1989
- ] }),
1990
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
1991
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Status: " }),
1992
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: span.status === "ERROR" ? "red" : "green", children: span.status })
1993
- ] }),
1994
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
1995
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Duration: " }),
1996
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: formatDurationMs(span.durationMs) })
1997
- ] }),
1998
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1999
- "Trace: ",
2000
- span.traceId
2001
- ] }),
2002
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2003
- "Span: ",
2004
- span.spanId
2005
- ] }),
2006
- span.parentSpanId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2007
- "Parent: ",
2008
- span.parentSpanId
2009
- ] }),
2010
- span.kind && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2011
- "Kind: ",
2012
- span.kind
2013
- ] }),
2014
- keyAttrs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
2015
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Key attributes" }),
2016
- keyAttrs.slice(0, 6).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2017
- truncate(k, 18),
2018
- ": ",
2019
- truncate(String(v), 28)
2020
- ] }, k))
2021
- ] }),
2022
- restAttrs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
2023
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Attributes" }),
2024
- restAttrs.slice(0, 8).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2025
- truncate(k, 18),
2026
- ": ",
2027
- truncate(String(v), 28)
2028
- ] }, k))
2029
- ] }),
2030
- keyAttrs.length === 0 && restAttrs.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "(no attributes)" })
2031
- ] });
2032
- })() : drilldownTraceId != null && drilldownSelectedItem?.type === "log" && drilldownSelectedItem.log ? (() => {
2033
- const log = drilldownSelectedItem.log;
2034
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2035
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2036
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Level: " }),
2037
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: log.level.toUpperCase() })
2038
- ] }),
2039
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2040
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Time: " }),
2041
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: new Date(log.time).toISOString() })
2042
- ] }),
2043
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2044
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Message: " }),
2045
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: log.message })
2046
- ] }),
2047
- log.traceId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2048
- "Trace: ",
2049
- log.traceId
2050
- ] }),
2051
- log.spanId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2052
- "Span: ",
2053
- log.spanId
2054
- ] }),
2055
- log.attributes && Object.keys(log.attributes).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
2056
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Attributes" }),
2057
- Object.entries(log.attributes).slice(0, 10).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2058
- truncate(k, 18),
2059
- ": ",
2060
- truncate(String(v), 40)
2061
- ] }, k))
2062
- ] })
2063
- ] });
2064
- })() : drilldownTraceId == null ? null : /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Select an item to view details." }),
2065
- drilldownTraceId == null && (viewMode === "errors" ? (() => {
2188
+ viewMode === "errors" ? (() => {
2066
2189
  const e = filteredErrorSummaries[selected] ?? null;
2067
2190
  if (!e)
2068
2191
  return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Select an error to view details." });
@@ -2280,12 +2403,12 @@ ${json}
2280
2403
  ] }, w.span.spanId);
2281
2404
  })
2282
2405
  ] })
2283
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Select a trace or span to view details." }))
2406
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Select a trace or span to view details." })
2284
2407
  ] })
2285
2408
  }
2286
2409
  )
2287
2410
  ] }),
2288
- showStats && /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2411
+ showStats && /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2289
2412
  "Spans: ",
2290
2413
  stats.total,
2291
2414
  " | Span errors: ",