autotel-terminal 17.0.3 → 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;
@@ -276,6 +282,45 @@ function buildWaterfallBar(spanStart, spanDuration, traceStart, traceDuration, w
276
282
  const trailing = Math.max(0, width - clampedStart - clampedLen);
277
283
  return " ".repeat(clampedStart) + "\u2588".repeat(clampedLen) + " ".repeat(trailing);
278
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
+ }
279
324
 
280
325
  // src/lib/log-model.ts
281
326
  function filterLogsBySearch(logs, searchQuery, minLevel) {
@@ -1585,15 +1630,25 @@ ${json}
1585
1630
  function renderTreeRow(node, index) {
1586
1631
  const isSel = drilldownTraceId != null && index === drilldownSelectedIndex;
1587
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);
1588
1635
  const statusColor = node.span.status === "ERROR" ? "red" : node.span.durationMs > 500 ? "yellow" : "green";
1589
1636
  return /* @__PURE__ */ jsxRuntime.jsxs(
1590
1637
  ink.Box,
1591
1638
  {
1592
1639
  flexDirection: "row",
1593
1640
  children: [
1594
- /* @__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 " : " " }),
1595
1642
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: prefix }),
1596
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
+ ] }),
1597
1652
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1598
1653
  " ",
1599
1654
  formatDurationMs(node.span.durationMs)
@@ -1656,13 +1711,261 @@ ${json}
1656
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" })
1657
1712
  ] }),
1658
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" }) }),
1659
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", gap: 2, children: [
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
+ ] }),
1879
+ " ",
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
1913
+ ] })
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: [
1660
1963
  /* @__PURE__ */ jsxRuntime.jsxs(
1661
1964
  ink.Box,
1662
1965
  {
1663
1966
  flexDirection: "column",
1664
1967
  width: "55%",
1665
- borderStyle: "single",
1968
+ borderStyle: "round",
1666
1969
  borderColor: "gray",
1667
1970
  paddingX: 1,
1668
1971
  paddingY: 0,
@@ -1679,156 +1982,7 @@ ${json}
1679
1982
  searchQuery
1680
1983
  ] }, "search-label")
1681
1984
  ] }),
1682
- drilldownTraceId != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1683
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "row", gap: 2, children: [
1684
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "yellow", children: drilldownSummary?.rootName ?? "unknown" }),
1685
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1686
- drilldownTraceId.slice(0, 16),
1687
- "\u2026"
1688
- ] }),
1689
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "green", children: drilldownSummary ? formatDurationMs(drilldownSummary.durationMs) : "?" }),
1690
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1691
- drilldownSpans.length,
1692
- " spans \u2022 ",
1693
- drilldownLogs.length,
1694
- " logs"
1695
- ] })
1696
- ] }),
1697
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "row", gap: 2, children: [
1698
- /* @__PURE__ */ jsxRuntime.jsx(
1699
- ink.Text,
1700
- {
1701
- color: drilldownTab === "timeline" ? "yellow" : void 0,
1702
- dimColor: drilldownTab !== "timeline",
1703
- underline: drilldownTab === "timeline",
1704
- children: "Timeline"
1705
- }
1706
- ),
1707
- /* @__PURE__ */ jsxRuntime.jsxs(
1708
- ink.Text,
1709
- {
1710
- color: drilldownTab === "spans" ? "yellow" : void 0,
1711
- dimColor: drilldownTab !== "spans",
1712
- underline: drilldownTab === "spans",
1713
- children: [
1714
- "Spans (",
1715
- drilldownSpans.length,
1716
- ")"
1717
- ]
1718
- }
1719
- ),
1720
- /* @__PURE__ */ jsxRuntime.jsxs(
1721
- ink.Text,
1722
- {
1723
- color: drilldownTab === "logs" ? "yellow" : void 0,
1724
- dimColor: drilldownTab !== "logs",
1725
- underline: drilldownTab === "logs",
1726
- children: [
1727
- "Logs (",
1728
- drilldownLogs.length,
1729
- ")"
1730
- ]
1731
- }
1732
- )
1733
- ] })
1734
- ] }),
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 }),
1770
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1771
- " ",
1772
- formatDurationMs(s.durationMs),
1773
- s.kind ? ` ${s.kind}` : ""
1774
- ] })
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)
1790
- ] }),
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}`);
1798
- }
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;
1808
- const levelColor = log.level === "error" ? "red" : log.level === "warn" ? "yellow" : log.level === "info" ? "green" : void 0;
1809
- return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1810
- ink.Text,
1811
- {
1812
- backgroundColor: isSel ? "gray" : void 0,
1813
- color: isSel ? "white" : void 0,
1814
- children: [
1815
- isSel ? "\u25B8" : " ",
1816
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: levelColor, children: [
1817
- " ",
1818
- log.level.toUpperCase()
1819
- ] }),
1820
- " ",
1821
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1822
- "[",
1823
- truncate(log.message, 50),
1824
- "]"
1825
- ] })
1826
- ]
1827
- }
1828
- ) }, `log-${i}`);
1829
- }),
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: [
1985
+ /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: viewMode === "trace" ? filteredSummaries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1832
1986
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
1833
1987
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No traces yet. Call a traced function or hit an endpoint to see them here." }),
1834
1988
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Tip: trace() your handlers with autotel to get spans." })
@@ -1853,6 +2007,11 @@ ${json}
1853
2007
  " ",
1854
2008
  formatRelative(t2.lastEndTime)
1855
2009
  ] }),
2010
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2011
+ " ",
2012
+ t2.traceId.slice(0, 12),
2013
+ "\u2026"
2014
+ ] }),
1856
2015
  t2.hasError && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "red", children: " \u25CF" })
1857
2016
  ] }, t2.traceId);
1858
2017
  }),
@@ -1866,6 +2025,8 @@ ${json}
1866
2025
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1867
2026
  filteredSpans.slice(0, 20).map((s, i) => {
1868
2027
  const isSel = i === selected;
2028
+ const svcName = spanServiceName(s);
2029
+ const svcColor = getServiceColor(svcName);
1869
2030
  const statusColor = s.status === "ERROR" ? "red" : s.durationMs > 500 ? "yellow" : "green";
1870
2031
  return /* @__PURE__ */ jsxRuntime.jsxs(
1871
2032
  ink.Box,
@@ -1874,6 +2035,10 @@ ${json}
1874
2035
  children: [
1875
2036
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: isSel ? "cyan" : void 0, children: isSel ? "\u203A " : " " }),
1876
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
+ ] }),
1877
2042
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
1878
2043
  " ",
1879
2044
  formatDurationMs(s.durationMs)
@@ -1972,7 +2137,7 @@ ${json}
1972
2137
  {
1973
2138
  flexDirection: "column",
1974
2139
  width: "45%",
1975
- borderStyle: "single",
2140
+ borderStyle: "round",
1976
2141
  borderColor: "gray",
1977
2142
  paddingX: 1,
1978
2143
  paddingY: 0,
@@ -2020,92 +2185,7 @@ ${json}
2020
2185
  ] })
2021
2186
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2022
2187
  /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginBottom: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Details" }) }),
2023
- drilldownTraceId != null && drilldownSelectedItem?.type === "span" && drilldownSelectedItem.span ? (() => {
2024
- const span = drilldownSelectedItem.span;
2025
- const { key: keyAttrs, rest: restAttrs } = keyAttrsAndRest(
2026
- span.attributes
2027
- );
2028
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2029
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2030
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Name: " }),
2031
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: span.name })
2032
- ] }),
2033
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2034
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Status: " }),
2035
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: span.status === "ERROR" ? "red" : "green", children: span.status })
2036
- ] }),
2037
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2038
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Duration: " }),
2039
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: formatDurationMs(span.durationMs) })
2040
- ] }),
2041
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2042
- "Trace: ",
2043
- span.traceId
2044
- ] }),
2045
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2046
- "Span: ",
2047
- span.spanId
2048
- ] }),
2049
- span.parentSpanId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2050
- "Parent: ",
2051
- span.parentSpanId
2052
- ] }),
2053
- span.kind && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2054
- "Kind: ",
2055
- span.kind
2056
- ] }),
2057
- keyAttrs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
2058
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Key attributes" }),
2059
- keyAttrs.slice(0, 6).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2060
- truncate(k, 18),
2061
- ": ",
2062
- truncate(String(v), 28)
2063
- ] }, k))
2064
- ] }),
2065
- restAttrs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
2066
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Attributes" }),
2067
- restAttrs.slice(0, 8).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2068
- truncate(k, 18),
2069
- ": ",
2070
- truncate(String(v), 28)
2071
- ] }, k))
2072
- ] }),
2073
- keyAttrs.length === 0 && restAttrs.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "(no attributes)" })
2074
- ] });
2075
- })() : drilldownTraceId != null && drilldownSelectedItem?.type === "log" && drilldownSelectedItem.log ? (() => {
2076
- const log = drilldownSelectedItem.log;
2077
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2078
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2079
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Level: " }),
2080
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: log.level.toUpperCase() })
2081
- ] }),
2082
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2083
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Time: " }),
2084
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: new Date(log.time).toISOString() })
2085
- ] }),
2086
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { children: [
2087
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Message: " }),
2088
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: log.message })
2089
- ] }),
2090
- log.traceId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2091
- "Trace: ",
2092
- log.traceId
2093
- ] }),
2094
- log.spanId && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2095
- "Span: ",
2096
- log.spanId
2097
- ] }),
2098
- log.attributes && Object.keys(log.attributes).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, flexDirection: "column", children: [
2099
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Attributes" }),
2100
- Object.entries(log.attributes).slice(0, 10).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { dimColor: true, children: [
2101
- truncate(k, 18),
2102
- ": ",
2103
- truncate(String(v), 40)
2104
- ] }, k))
2105
- ] })
2106
- ] });
2107
- })() : drilldownTraceId == null ? null : /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Select an item to view details." }),
2108
- drilldownTraceId == null && (viewMode === "errors" ? (() => {
2188
+ viewMode === "errors" ? (() => {
2109
2189
  const e = filteredErrorSummaries[selected] ?? null;
2110
2190
  if (!e)
2111
2191
  return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Select an error to view details." });
@@ -2323,12 +2403,12 @@ ${json}
2323
2403
  ] }, w.span.spanId);
2324
2404
  })
2325
2405
  ] })
2326
- ] }) : /* @__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." })
2327
2407
  ] })
2328
2408
  }
2329
2409
  )
2330
2410
  ] }),
2331
- 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: [
2332
2412
  "Spans: ",
2333
2413
  stats.total,
2334
2414
  " | Span errors: ",