@kud/gh-ink 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -24,6 +24,58 @@ type HealthPanelProps = {
24
24
  };
25
25
  declare const HealthPanel: ({ repo, number, data, error, reload, onOpenCheck, onMerged, }: HealthPanelProps) => React.JSX.Element;
26
26
 
27
+ /**
28
+ * One initiative in the rail — a container of work rather than a unit of it.
29
+ *
30
+ * Deliberately not a `TaskRow`. The list answers "what is in front of me today"
31
+ * and prices every row by stage; this answers "what am I building, over months",
32
+ * where a stage means nothing because an initiative's stage is only ever an
33
+ * aggregate of its children's. Sharing a shape would have meant carrying a
34
+ * `status` neither side agrees on.
35
+ */
36
+ type SidebarRow = {
37
+ /** Stable identity, and the left column: a ticket key, an id, a slug. */
38
+ key: string;
39
+ /** What it is, in words. Never omitted — a key alone cannot be read. */
40
+ label: string;
41
+ /**
42
+ * How much is moving under it right now. Absent draws nothing rather than a
43
+ * zero: "no live work" and "we did not count" are different claims, and a
44
+ * hard 0 asserts the first from evidence for neither.
45
+ */
46
+ live?: number;
47
+ /** Something under it is waiting on you. */
48
+ wantsYou?: boolean;
49
+ };
50
+ type Sidebar = {
51
+ /** Heading for the rail. The host's vocabulary, never ours. */
52
+ title: string;
53
+ rows: SidebarRow[];
54
+ };
55
+ /**
56
+ * The rail's width, INCLUDING its one-column gutter. Exported because the list
57
+ * beside it has to shrink by exactly this much: every row in that list truncates
58
+ * against a budget, and a budget that does not know the rail is there overflows
59
+ * by the rail's whole width — which in a frame sized to fill the terminal
60
+ * scrolls the panel rather than clipping a row.
61
+ */
62
+ declare const SIDEBAR_COLS = 30;
63
+ /**
64
+ * A right-hand rail of initiatives, standing beside the list.
65
+ *
66
+ * Two lines per row rather than one, because both halves are load-bearing and
67
+ * neither survives the other being cut: a key with no words cannot be read at a
68
+ * glance, and words with no key cannot be opened. Thirty columns is not enough
69
+ * for both on one line, so they stack.
70
+ *
71
+ * Presentational, like every other row renderer here — it takes no keyboard and
72
+ * holds no cursor. Whether the rail is shown at all is the host's state.
73
+ */
74
+ declare const SidePanel: ({ sidebar, height, }: {
75
+ sidebar: Sidebar;
76
+ height?: number;
77
+ }) => React.JSX.Element;
78
+
27
79
  declare const renderMarkdown: (raw: string, width: number, fileLink?: (path: string, line?: number) => string) => StyledLine[];
28
80
 
29
81
  declare const healthDisplay: Record<Health, {
@@ -493,6 +545,15 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
493
545
  * can decline to spend the last of it on a refresh nobody requested.
494
546
  */
495
547
  budget?: InboxBudget;
548
+ /**
549
+ * A rail of containers to stand beside the list — initiatives, epics,
550
+ * whatever this host groups its work under. Omit it and no rail exists: no
551
+ * key, no hint, no columns spent.
552
+ *
553
+ * Part of the fetch result rather than a static prop because it is data, and
554
+ * data that goes stale the same way the rows do.
555
+ */
556
+ sidebar?: Sidebar;
496
557
  }>;
497
558
  cacheKey?: string;
498
559
  title?: string;
@@ -615,4 +676,4 @@ declare const matchesFilter: (repo: string, filter: RepoFilter) => boolean;
615
676
  */
616
677
  declare const parsePatterns: (value: string) => string[];
617
678
 
618
- export { type Action, ActionMenu, type AnyItem, App, COLS, type CiStatus, CiStatusLine, type CiStatusState, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, type GHDetail, type GHItem, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxConfig, type InboxExtension, type JiraTransition, type OriginSplit, PIN_MARK, type RepoFilter, type RepoHeader, type RepoProfile, type Section, type ShowLess, type ShowMore, type Standing, type SubgroupHeader, type TaskRow, budgetNotice, buildActions, buildCheckoutCmd, checkoutDirs, clipboard, configureInbox, drillCmd, explainGhAction, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, inboxConfig, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, profileOf, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resetInboxConfig, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
679
+ export { type Action, ActionMenu, type AnyItem, App, COLS, type CiStatus, CiStatusLine, type CiStatusState, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, type GHDetail, type GHItem, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxConfig, type InboxExtension, type JiraTransition, type OriginSplit, PIN_MARK, type RepoFilter, type RepoHeader, type RepoProfile, SIDEBAR_COLS, type Section, type ShowLess, type ShowMore, SidePanel, type Sidebar, type SidebarRow, type Standing, type SubgroupHeader, type TaskRow, budgetNotice, buildActions, buildCheckoutCmd, checkoutDirs, clipboard, configureInbox, drillCmd, explainGhAction, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, inboxConfig, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, profileOf, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resetInboxConfig, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
package/dist/index.js CHANGED
@@ -583,6 +583,37 @@ var HealthPanel = ({
583
583
  ] }) }) : note ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.success, children: " " + note }) }) : null
584
584
  ] });
585
585
  };
586
+ var ACCENT = "#FF8700";
587
+ var SIDEBAR_COLS = 30;
588
+ var GUTTER = 1;
589
+ var CONTENT = SIDEBAR_COLS - GUTTER;
590
+ var truncate = (text, max) => [...text].length <= max ? text : [...text].slice(0, Math.max(0, max - 1)).join("") + "\u2026";
591
+ var SidePanel = ({
592
+ sidebar,
593
+ height
594
+ }) => /* @__PURE__ */ jsxs(
595
+ Box,
596
+ {
597
+ flexDirection: "column",
598
+ width: SIDEBAR_COLS,
599
+ flexShrink: 0,
600
+ height,
601
+ children: [
602
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, paddingLeft: GUTTER, children: [
603
+ /* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: "\xBB " }),
604
+ /* @__PURE__ */ jsx(Text, { bold: true, children: sidebar.title })
605
+ ] }),
606
+ sidebar.rows.length === 0 ? /* @__PURE__ */ jsx(Box, { paddingLeft: GUTTER + 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "nothing open" }) }) : sidebar.rows.map((row) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
607
+ /* @__PURE__ */ jsxs(Box, { paddingLeft: GUTTER, children: [
608
+ /* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: row.wantsYou ? "\u2190 " : " " }),
609
+ /* @__PURE__ */ jsx(Text, { color: ACCENT, children: row.key }),
610
+ row.live !== void 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${row.live} live` }) : null
611
+ ] }),
612
+ /* @__PURE__ */ jsx(Box, { paddingLeft: GUTTER + 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncate(row.label, CONTENT - 2) }) })
613
+ ] }, row.key))
614
+ ]
615
+ }
616
+ );
586
617
  var healthDisplay = {
587
618
  none: { glyph: " ", color: colors.muted },
588
619
  draft: { glyph: "~", color: colors.muted },
@@ -1215,7 +1246,7 @@ var withHeaders = (items, idx) => {
1215
1246
  start--;
1216
1247
  return start;
1217
1248
  };
1218
- var truncate = (str, max) => {
1249
+ var truncate2 = (str, max) => {
1219
1250
  if (str.length <= max) return str;
1220
1251
  const half = Math.floor((max - 1) / 2);
1221
1252
  return `${str.slice(0, half)}\u2026${str.slice(-half)}`;
@@ -1405,7 +1436,7 @@ var COLS = (process.stdout.columns ?? 120) - FRAME_CHROME_COLS;
1405
1436
  var MODAL_CHROME_COLS = 2 + 1 * 2;
1406
1437
  var OVERLAY_BG = "#22222e";
1407
1438
  var DimContext = createContext(false);
1408
- var Text2 = ({ children, ...props }) => {
1439
+ var Text3 = ({ children, ...props }) => {
1409
1440
  const dimmed = useContext(DimContext);
1410
1441
  return dimmed ? /* @__PURE__ */ jsx(Text, { ...props, bold: false, dimColor: true, children }) : /* @__PURE__ */ jsx(Text, { ...props, children });
1411
1442
  };
@@ -1784,13 +1815,13 @@ var InboxHeader = ({
1784
1815
  COLS - brand.length - countSeg.length - userSeg.length - workLabel.length - budgetSeg.length - statusSeg.length
1785
1816
  );
1786
1817
  return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
1787
- /* @__PURE__ */ jsx(Text2, { color: "#FF8700", bold: true, children: brand }),
1788
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: countSeg }),
1789
- userSeg ? /* @__PURE__ */ jsx(Text2, { children: userSeg }) : null,
1790
- scopeLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: workLabel }) : null,
1791
- budgetLabel ? /* @__PURE__ */ jsx(Text2, { bold: true, color: budgetCritical ? "#FF5F5F" : "#FF8700", children: budgetSeg }) : null,
1818
+ /* @__PURE__ */ jsx(Text3, { color: "#FF8700", bold: true, children: brand }),
1819
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: countSeg }),
1820
+ userSeg ? /* @__PURE__ */ jsx(Text3, { children: userSeg }) : null,
1821
+ scopeLabel ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: workLabel }) : null,
1822
+ budgetLabel ? /* @__PURE__ */ jsx(Text3, { bold: true, color: budgetCritical ? "#FF5F5F" : "#FF8700", children: budgetSeg }) : null,
1792
1823
  statusText ? /* @__PURE__ */ jsx(
1793
- Text2,
1824
+ Text3,
1794
1825
  {
1795
1826
  color: statusColor,
1796
1827
  dimColor: !statusColor,
@@ -1798,7 +1829,7 @@ var InboxHeader = ({
1798
1829
  children: statusSeg
1799
1830
  }
1800
1831
  ) : null,
1801
- /* @__PURE__ */ jsx(Text2, { color: "cyan", dimColor: true, children: "\u254C".repeat(fill) })
1832
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", dimColor: true, children: "\u254C".repeat(fill) })
1802
1833
  ] });
1803
1834
  };
1804
1835
  var toCiStatusState = (status) => status ? { kind: "ready", status } : { kind: "error" };
@@ -1821,24 +1852,24 @@ var CiStatusLine = ({
1821
1852
  const name = job ?? "ci";
1822
1853
  if (state.kind === "loading")
1823
1854
  return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
1824
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " \xB7 " }),
1825
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: `${name} loading\u2026` })
1855
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " \xB7 " }),
1856
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: `${name} loading\u2026` })
1826
1857
  ] });
1827
1858
  if (state.kind === "error")
1828
1859
  return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
1829
- /* @__PURE__ */ jsx(Text2, { color: "red", bold: true, children: " \u2717 " }),
1830
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: `${name} no build / not configured` })
1860
+ /* @__PURE__ */ jsx(Text3, { color: "red", bold: true, children: " \u2717 " }),
1861
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: `${name} no build / not configured` })
1831
1862
  ] });
1832
1863
  const { status } = state;
1833
1864
  const [, color] = jenkinsResultDisplay(status.result, status.building);
1834
1865
  const label = status.building ? "BUILDING" : status.result;
1835
1866
  return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
1836
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " }),
1837
- /* @__PURE__ */ jsx(Text2, { color, bold: true, children: "\u25CF " }),
1838
- /* @__PURE__ */ jsx(Text2, { bold: true, children: status.job }),
1839
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + label }),
1840
- /* @__PURE__ */ jsx(Text2, { color: "#FF8700", children: " #" + status.buildNumber }),
1841
- status.age ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + status.age }) : null
1867
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " " }),
1868
+ /* @__PURE__ */ jsx(Text3, { color, bold: true, children: "\u25CF " }),
1869
+ /* @__PURE__ */ jsx(Text3, { bold: true, children: status.job }),
1870
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " " + label }),
1871
+ /* @__PURE__ */ jsx(Text3, { color: "#FF8700", children: " #" + status.buildNumber }),
1872
+ status.age ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " " + status.age }) : null
1842
1873
  ] });
1843
1874
  };
1844
1875
  var FENCE_COLS = 46;
@@ -1851,10 +1882,10 @@ var RepoHeaderRow = ({
1851
1882
  const fill = Math.max(4, FENCE_COLS - label.length);
1852
1883
  const rule = "\u2500".repeat(fill);
1853
1884
  return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
1854
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: active ? "\u276F " : " " }),
1855
- /* @__PURE__ */ jsx(Text2, { dimColor: !active, children: "\u2500\u2500 " }),
1856
- /* @__PURE__ */ jsx(Text2, { dimColor: !active, bold: active, children: repo }),
1857
- /* @__PURE__ */ jsx(Text2, { dimColor: !active, children: " " + rule })
1885
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: active ? "\u276F " : " " }),
1886
+ /* @__PURE__ */ jsx(Text3, { dimColor: !active, children: "\u2500\u2500 " }),
1887
+ /* @__PURE__ */ jsx(Text3, { dimColor: !active, bold: active, children: repo }),
1888
+ /* @__PURE__ */ jsx(Text3, { dimColor: !active, children: " " + rule })
1858
1889
  ] });
1859
1890
  };
1860
1891
  var MERGED_HOLD_MS = 5e3;
@@ -1902,29 +1933,30 @@ var ItemRow = ({
1902
1933
  leaving,
1903
1934
  prefix = "",
1904
1935
  parent,
1905
- sparkFrame = 0
1936
+ sparkFrame = 0,
1937
+ cols = COLS
1906
1938
  }) => {
1907
1939
  const transient = leaving ? "out" : refreshMark;
1908
1940
  if (item.kind === "repo-header")
1909
1941
  return /* @__PURE__ */ jsx(RepoHeaderRow, { repo: item.repo, gap: gap ?? false, active });
1910
1942
  if (item.kind === "subgroup-header")
1911
1943
  return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
1912
- /* @__PURE__ */ jsx(Text2, { color: "#FF8700", bold: true, children: " \xBB " }),
1913
- /* @__PURE__ */ jsx(Text2, { bold: true, children: item.label })
1944
+ /* @__PURE__ */ jsx(Text3, { color: "#FF8700", bold: true, children: " \xBB " }),
1945
+ /* @__PURE__ */ jsx(Text3, { bold: true, children: item.label })
1914
1946
  ] });
1915
1947
  if (item.kind === "show-more")
1916
1948
  return /* @__PURE__ */ jsxs(Box, { children: [
1917
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: active ? "\u276F " : " " }),
1918
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: prefix }),
1919
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: active ? "\u21B5 " : " " }),
1920
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: `+${item.hidden.length} more` })
1949
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: active ? "\u276F " : " " }),
1950
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
1951
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: active ? "\u21B5 " : " " }),
1952
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: `+${item.hidden.length} more` })
1921
1953
  ] });
1922
1954
  if (item.kind === "show-less")
1923
1955
  return /* @__PURE__ */ jsxs(Box, { children: [
1924
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: active ? "\u276F " : " " }),
1925
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: prefix }),
1926
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: active ? "\u21B5 " : " " }),
1927
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "show less" })
1956
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: active ? "\u276F " : " " }),
1957
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
1958
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: active ? "\u21B5 " : " " }),
1959
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "show less" })
1928
1960
  ] });
1929
1961
  if (item.kind === "task") {
1930
1962
  const note = item.note ?? "";
@@ -1932,29 +1964,29 @@ var ItemRow = ({
1932
1964
  const transitLabel2 = transient ? TRANSIT_LABEL[transient] : "";
1933
1965
  const titleMax2 = Math.max(
1934
1966
  20,
1935
- COLS - item.key.length - note.length - (item.pill ? pillWidth(item.pill) + 1 : 0) - transitLabel2.length - prefix.length - 12
1967
+ cols - item.key.length - note.length - (item.pill ? pillWidth(item.pill) + 1 : 0) - transitLabel2.length - prefix.length - 12
1936
1968
  );
1937
1969
  return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
1938
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: active ? "\u276F " : " " }),
1939
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: prefix }),
1940
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: parent ? "\u252C " : " " }),
1941
- /* @__PURE__ */ jsx(Text2, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
1942
- /* @__PURE__ */ jsx(Text2, { color: "#FF8700", bold: active, children: item.key + " " }),
1970
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: active ? "\u276F " : " " }),
1971
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
1972
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: parent ? "\u252C " : " " }),
1973
+ /* @__PURE__ */ jsx(Text3, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
1974
+ /* @__PURE__ */ jsx(Text3, { color: "#FF8700", bold: active, children: item.key + " " }),
1943
1975
  /* @__PURE__ */ jsx(
1944
- Text2,
1976
+ Text3,
1945
1977
  {
1946
1978
  bold: active || !!transient && isArrival(transient),
1947
1979
  dimColor: !!transient && isDeparture(transient),
1948
1980
  strikethrough: transient === "out",
1949
- children: truncate(item.summary, titleMax2)
1981
+ children: truncate2(item.summary, titleMax2)
1950
1982
  }
1951
1983
  ),
1952
1984
  item.pill ? /* @__PURE__ */ jsxs(Fragment, { children: [
1953
- /* @__PURE__ */ jsx(Text2, { children: " " }),
1985
+ /* @__PURE__ */ jsx(Text3, { children: " " }),
1954
1986
  /* @__PURE__ */ jsx(Pill, { variant: item.pillVariant ?? "muted", children: item.pill })
1955
1987
  ] }) : null,
1956
- note ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: ` ${note}` }) : null,
1957
- transitLabel2 ? /* @__PURE__ */ jsx(Text2, { bold: true, color: TRANSIT_COLOUR[transient], children: " " + transitLabel2 }) : null
1988
+ note ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${note}` }) : null,
1989
+ transitLabel2 ? /* @__PURE__ */ jsx(Text3, { bold: true, color: TRANSIT_COLOUR[transient], children: " " + transitLabel2 }) : null
1958
1990
  ] });
1959
1991
  }
1960
1992
  const { glyph: healthIcon, color: healthColor2 } = healthDisplay[item.health];
@@ -1977,28 +2009,28 @@ var ItemRow = ({
1977
2009
  ].filter(Boolean).join(" ");
1978
2010
  const repoLabel = depthOf(item) > 0 ? item.repo : "";
1979
2011
  const fixedWidth = 2 + prefix.length + 2 + 2 + 7 + repoLabel.length + suffix.length + 6;
1980
- const titleMax = Math.max(20, COLS - fixedWidth);
2012
+ const titleMax = Math.max(20, cols - fixedWidth);
1981
2013
  return /* @__PURE__ */ jsxs(Box, { children: [
1982
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: active ? "\u276F " : " " }),
1983
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: prefix }),
1984
- /* @__PURE__ */ jsx(Text2, { color, bold: true, children: icon + " " }),
1985
- /* @__PURE__ */ jsx(Text2, { color: turnColor, bold: turnIcon === "\u2190", children: turnIcon + " " }),
1986
- /* @__PURE__ */ jsx(Text2, { color: "#FF8700", children: numStr }),
2014
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: active ? "\u276F " : " " }),
2015
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
2016
+ /* @__PURE__ */ jsx(Text3, { color, bold: true, children: icon + " " }),
2017
+ /* @__PURE__ */ jsx(Text3, { color: turnColor, bold: turnIcon === "\u2190", children: turnIcon + " " }),
2018
+ /* @__PURE__ */ jsx(Text3, { color: "#FF8700", children: numStr }),
1987
2019
  /* @__PURE__ */ jsx(
1988
- Text2,
2020
+ Text3,
1989
2021
  {
1990
2022
  bold: active || !!transient && isArrival(transient),
1991
2023
  dimColor: !!transient && isDeparture(transient),
1992
2024
  strikethrough: transient === "out",
1993
- children: truncate(item.title, titleMax) + " "
2025
+ children: truncate2(item.title, titleMax) + " "
1994
2026
  }
1995
2027
  ),
1996
- repoLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: repoLabel }) : null,
1997
- unresolvedLabel ? /* @__PURE__ */ jsx(Text2, { bold: !spokeLast, color: spokeLast ? "#888888" : "#FF8700", children: " " + unresolvedLabel }) : null,
1998
- showAuthor ? /* @__PURE__ */ jsx(Text2, { dimColor: true, italic: true, children: " by " + item.author }) : null,
1999
- ageLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + ageLabel }) : null,
2000
- mergedLabel ? /* @__PURE__ */ jsx(Text2, { bold: true, color: MERGED_COLOUR, children: " " + mergedLabel }) : null,
2001
- transitLabel ? /* @__PURE__ */ jsx(Text2, { bold: true, color: TRANSIT_COLOUR[transient], children: " " + transitLabel }) : null
2028
+ repoLabel ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: repoLabel }) : null,
2029
+ unresolvedLabel ? /* @__PURE__ */ jsx(Text3, { bold: !spokeLast, color: spokeLast ? "#888888" : "#FF8700", children: " " + unresolvedLabel }) : null,
2030
+ showAuthor ? /* @__PURE__ */ jsx(Text3, { dimColor: true, italic: true, children: " by " + item.author }) : null,
2031
+ ageLabel ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " " + ageLabel }) : null,
2032
+ mergedLabel ? /* @__PURE__ */ jsx(Text3, { bold: true, color: MERGED_COLOUR, children: " " + mergedLabel }) : null,
2033
+ transitLabel ? /* @__PURE__ */ jsx(Text3, { bold: true, color: TRANSIT_COLOUR[transient], children: " " + transitLabel }) : null
2002
2034
  ] });
2003
2035
  };
2004
2036
  var useActionMenu = () => {
@@ -2044,15 +2076,15 @@ var ActionMenu = ({
2044
2076
  paddingX: 1,
2045
2077
  marginTop: 1,
2046
2078
  children: [
2047
- /* @__PURE__ */ jsx(Text2, { color: "cyan", bold: true, children: title }),
2048
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "\u2500".repeat(32) }),
2079
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", bold: true, children: title }),
2080
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(32) }),
2049
2081
  actions.map((a, i) => /* @__PURE__ */ jsxs(Box, { children: [
2050
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: i === cursor ? "\u276F " : " " }),
2051
- /* @__PURE__ */ jsx(Text2, { bold: i === cursor, children: a.label }),
2052
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + a.hint })
2082
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: i === cursor ? "\u276F " : " " }),
2083
+ /* @__PURE__ */ jsx(Text3, { bold: i === cursor, children: a.label }),
2084
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " " + a.hint })
2053
2085
  ] }, a.label)),
2054
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "\u2500".repeat(32) }),
2055
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "\u2191\u2193 navigate \u21B5 confirm esc cancel" })
2086
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(32) }),
2087
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2191\u2193 navigate \u21B5 confirm esc cancel" })
2056
2088
  ]
2057
2089
  }
2058
2090
  );
@@ -2100,11 +2132,11 @@ var LegendGroup = ({
2100
2132
  width,
2101
2133
  marginRight
2102
2134
  }) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, marginRight, children: [
2103
- pinned !== void 0 ? /* @__PURE__ */ jsx(Text2, { bold: true, dimColor: true, children: pinned ?? " " }) : null,
2135
+ pinned !== void 0 ? /* @__PURE__ */ jsx(Text3, { bold: true, dimColor: true, children: pinned ?? " " }) : null,
2104
2136
  lines.map(
2105
- (line, index) => line.kind === "gap" ? /* @__PURE__ */ jsx(Text2, { children: " " }, index) : line.kind === "title" ? /* @__PURE__ */ jsx(Text2, { bold: true, dimColor: true, children: line.text }, index) : /* @__PURE__ */ jsxs(Box, { children: [
2106
- /* @__PURE__ */ jsx(Text2, { color: line.row.color, bold: line.row.bold, children: line.row.cell.padEnd(line.cellWidth) }),
2107
- /* @__PURE__ */ jsx(Text2, { wrap: "truncate-end", children: line.row.label })
2137
+ (line, index) => line.kind === "gap" ? /* @__PURE__ */ jsx(Text3, { children: " " }, index) : line.kind === "title" ? /* @__PURE__ */ jsx(Text3, { bold: true, dimColor: true, children: line.text }, index) : /* @__PURE__ */ jsxs(Box, { children: [
2138
+ /* @__PURE__ */ jsx(Text3, { color: line.row.color, bold: line.row.bold, children: line.row.cell.padEnd(line.cellWidth) }),
2139
+ /* @__PURE__ */ jsx(Text3, { wrap: "truncate-end", children: line.row.label })
2108
2140
  ] }, index)
2109
2141
  )
2110
2142
  ] });
@@ -2222,8 +2254,8 @@ var HelpModal = ({
2222
2254
  width: contentWidth + MODAL_CHROME_COLS,
2223
2255
  children: [
2224
2256
  /* @__PURE__ */ jsxs(Box, { children: [
2225
- /* @__PURE__ */ jsx(Text2, { color: "cyan", bold: true, children: "Legend" }),
2226
- scrollable ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: ` ${offset + 1}\u2013${offset + shown} of ${totalRows}` }) : null
2257
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", bold: true, children: "Legend" }),
2258
+ scrollable ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${offset + 1}\u2013${offset + shown} of ${totalRows}` }) : null
2227
2259
  ] }),
2228
2260
  /* @__PURE__ */ jsx(Box, { marginTop: 1, width: contentWidth, children: groups.map((group, index) => /* @__PURE__ */ jsx(
2229
2261
  LegendGroup,
@@ -2235,8 +2267,8 @@ var HelpModal = ({
2235
2267
  },
2236
2268
  group[0]?.title ?? index
2237
2269
  )) }),
2238
- tabHelp && !scrollable ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: LEGEND_FOOTNOTE }) : null,
2239
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: scrollable ? "\u2191\u2193 scroll \xB7 esc \xB7 ? close" : "esc \xB7 ? close" })
2270
+ tabHelp && !scrollable ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: LEGEND_FOOTNOTE }) : null,
2271
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: scrollable ? "\u2191\u2193 scroll \xB7 esc \xB7 ? close" : "esc \xB7 ? close" })
2240
2272
  ]
2241
2273
  }
2242
2274
  );
@@ -2251,13 +2283,13 @@ var ExplainModal = ({ item, login }) => /* @__PURE__ */ jsxs(
2251
2283
  paddingX: 1,
2252
2284
  width: Math.min(COLS, 78),
2253
2285
  children: [
2254
- /* @__PURE__ */ jsx(Text2, { color: "#FF8700", bold: true, children: `#${item.number} \xB7 ${item.repo}` }),
2255
- /* @__PURE__ */ jsx(Text2, { children: item.title }),
2286
+ /* @__PURE__ */ jsx(Text3, { color: "#FF8700", bold: true, children: `#${item.number} \xB7 ${item.repo}` }),
2287
+ /* @__PURE__ */ jsx(Text3, { children: item.title }),
2256
2288
  explainItem(item, login).map((section) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
2257
- /* @__PURE__ */ jsx(Text2, { bold: true, dimColor: true, children: section.heading }),
2258
- section.lines.map((line, i) => /* @__PURE__ */ jsx(Text2, { children: " " + line }, i))
2289
+ /* @__PURE__ */ jsx(Text3, { bold: true, dimColor: true, children: section.heading }),
2290
+ section.lines.map((line, i) => /* @__PURE__ */ jsx(Text3, { children: " " + line }, i))
2259
2291
  ] }, section.heading)),
2260
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "esc \xB7 e close" }) })
2292
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "esc \xB7 e close" }) })
2261
2293
  ]
2262
2294
  }
2263
2295
  );
@@ -2283,21 +2315,21 @@ var RepoPicker = ({
2283
2315
  paddingX: 1,
2284
2316
  minWidth: 42,
2285
2317
  children: [
2286
- /* @__PURE__ */ jsx(Text2, { color: "cyan", bold: true, children: `Filter by repo (${selected.size} on)` }),
2287
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "\u2500".repeat(36) }),
2318
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", bold: true, children: `Filter by repo (${selected.size} on)` }),
2319
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(36) }),
2288
2320
  visible.map((repo, i) => {
2289
2321
  const idx = start + i;
2290
2322
  const on = selected.has(repo);
2291
2323
  const active = idx === cursor;
2292
2324
  return /* @__PURE__ */ jsxs(Box, { children: [
2293
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: active ? "\u276F " : " " }),
2294
- /* @__PURE__ */ jsx(Text2, { color: on ? "green" : void 0, children: on ? "\u25C9 " : "\u25CB " }),
2295
- /* @__PURE__ */ jsx(Text2, { bold: active, children: repo })
2325
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: active ? "\u276F " : " " }),
2326
+ /* @__PURE__ */ jsx(Text3, { color: on ? "green" : void 0, children: on ? "\u25C9 " : "\u25CB " }),
2327
+ /* @__PURE__ */ jsx(Text3, { bold: active, children: repo })
2296
2328
  ] }, repo);
2297
2329
  }),
2298
- repos.length > budget ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: ` \u2026 ${repos.length} repos total` }) : null,
2299
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "\u2500".repeat(36) }),
2300
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: "space toggle \xB7 a clear all \xB7 \u21B5/esc done" })
2330
+ repos.length > budget ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` \u2026 ${repos.length} repos total` }) : null,
2331
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(36) }),
2332
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: "space toggle \xB7 a clear all \xB7 \u21B5/esc done" })
2301
2333
  ]
2302
2334
  }
2303
2335
  );
@@ -2334,7 +2366,8 @@ var BrowseScreen = ({
2334
2366
  leavingUrls,
2335
2367
  onLeave,
2336
2368
  transients,
2337
- onTabChange
2369
+ onTabChange,
2370
+ sidebar
2338
2371
  }) => {
2339
2372
  const { rows } = useWindowSize();
2340
2373
  const applyWork = (secs) => origin ? filterByOrigin(secs, origin.show, origin.match) : secs;
@@ -2434,6 +2467,9 @@ var BrowseScreen = ({
2434
2467
  out.add(s.id);
2435
2468
  return out;
2436
2469
  }, [localSections, transients]);
2470
+ const [railOpen, setRailOpen] = useState(false);
2471
+ const showRail = railOpen && !!sidebar;
2472
+ const listCols = showRail ? COLS - SIDEBAR_COLS : COLS;
2437
2473
  const [sparkFrame, setSparkFrame] = useState(0);
2438
2474
  const sparkling = (mergedUrls?.length ?? 0) > 0 || (leavingUrls?.length ?? 0) > 0 || !!transients?.size && section.items.some((item) => transientOf(transients, item, section.id));
2439
2475
  useEffect(() => {
@@ -2534,6 +2570,10 @@ var BrowseScreen = ({
2534
2570
  setRepoPicker(true);
2535
2571
  return;
2536
2572
  }
2573
+ if (input === "i" && sidebar) {
2574
+ setRailOpen((open) => !open);
2575
+ return;
2576
+ }
2537
2577
  if (key.escape && search != null) {
2538
2578
  setSearch(null);
2539
2579
  return;
@@ -2819,6 +2859,9 @@ var BrowseScreen = ({
2819
2859
  ["\u2190\u2192", "tab"],
2820
2860
  ["\u21B5/d", "open"],
2821
2861
  ["m", "actions"],
2862
+ // Advertised only where it does something, and named for what it
2863
+ // shows rather than for the furniture: nobody wants "a sidebar".
2864
+ ...sidebar ? [["i", railOpen ? "hide" : sidebar.title.toLowerCase()]] : [],
2822
2865
  ["?", "help"],
2823
2866
  ["q", "quit"]
2824
2867
  ];
@@ -2871,8 +2914,8 @@ var BrowseScreen = ({
2871
2914
  ),
2872
2915
  ciStatusState ? /* @__PURE__ */ jsx(CiStatusLine, { state: ciStatusState, job: ciJob }) : null,
2873
2916
  skippedForBudget ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
2874
- /* @__PURE__ */ jsx(Text2, { bold: true, color: "#FF8700", children: " \u26A1 auto-refresh paused to save API budget" }),
2875
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " r refreshes anyway" })
2917
+ /* @__PURE__ */ jsx(Text3, { bold: true, color: "#FF8700", children: " \u26A1 auto-refresh paused to save API budget" }),
2918
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " r refreshes anyway" })
2876
2919
  ] }) : null,
2877
2920
  /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(
2878
2921
  Tabs,
@@ -2886,52 +2929,65 @@ var BrowseScreen = ({
2886
2929
  }
2887
2930
  ) }),
2888
2931
  search != null ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
2889
- /* @__PURE__ */ jsx(Text2, { color: "cyan", children: " / " }),
2890
- /* @__PURE__ */ jsx(Text2, { children: search }),
2891
- searchInput ? /* @__PURE__ */ jsx(Text2, { color: "cyan", children: "\u258F" }) : null,
2892
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: ` ${matchCount} match${matchCount !== 1 ? "es" : ""}${searchInput ? " \u21B5 accept \xB7 esc clear" : " esc clear"}` })
2932
+ /* @__PURE__ */ jsx(Text3, { color: "cyan", children: " / " }),
2933
+ /* @__PURE__ */ jsx(Text3, { children: search }),
2934
+ searchInput ? /* @__PURE__ */ jsx(Text3, { color: "cyan", children: "\u258F" }) : null,
2935
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${matchCount} match${matchCount !== 1 ? "es" : ""}${searchInput ? " \u21B5 accept \xB7 esc clear" : " esc clear"}` })
2893
2936
  ] }) : repoFilter.size > 0 ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
2894
- /* @__PURE__ */ jsx(Text2, { color: "#FF8700", children: " \u25C9 " }),
2895
- /* @__PURE__ */ jsx(Text2, { children: `${repoFilter.size} repo${repoFilter.size !== 1 ? "s" : ""}` }),
2896
- /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " f edit \xB7 esc clear" })
2937
+ /* @__PURE__ */ jsx(Text3, { color: "#FF8700", children: " \u25C9 " }),
2938
+ /* @__PURE__ */ jsx(Text3, { children: `${repoFilter.size} repo${repoFilter.size !== 1 ? "s" : ""}` }),
2939
+ /* @__PURE__ */ jsx(Text3, { dimColor: true, children: " f edit \xB7 esc clear" })
2897
2940
  ] }) : null,
2898
- /* @__PURE__ */ jsxs(Box, { flexDirection: "column", minHeight: listHeight, children: [
2899
- /* @__PURE__ */ jsxs(Backdrop, { dimmed: !!overlay, absolute: !!overlay, height: listHeight, children: [
2900
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, children: visibleItems.map((item, i) => /* @__PURE__ */ jsx(
2901
- ItemRow,
2902
- {
2903
- item,
2904
- active: viewStart + i === cursor,
2905
- login,
2906
- merged: (item.kind === "pr" || item.kind === "issue") && !!mergedUrls?.includes(item.url),
2907
- leaving: (item.kind === "pr" || item.kind === "issue") && !!leavingUrls?.includes(item.url),
2908
- transient: transientOf(transients, item, section.id),
2909
- prefix: treePrefix(section.items, viewStart + i),
2910
- parent: item.kind === "task" && depthOf(section.items[viewStart + i + 1]) > depthOf(item),
2911
- sparkFrame,
2912
- gap: i > 0 && gapsAbove(section.items, viewStart + i)
2913
- },
2914
- `${viewStart + i}:${item.kind === "task" ? item.instanceKey ?? item.key : item.kind === "repo-header" ? `header:${item.repo}` : item.kind === "subgroup-header" ? `subgroup:${item.label}` : item.kind === "show-more" ? `show-more:${item.hidden[0]?.repo ?? i}` : item.kind === "show-less" ? `show-less:${item.toHide[0]?.repo ?? i}` : `${item.repo}/${item.number}`}`
2915
- )) }),
2916
- hasMore && /* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
2917
- " ",
2918
- "\u2193 ",
2919
- section.items.length - viewStart - visibleCount,
2920
- " more"
2921
- ] })
2922
- ] }),
2923
- overlay ? /* @__PURE__ */ jsx(
2941
+ /* @__PURE__ */ jsxs(Box, { children: [
2942
+ /* @__PURE__ */ jsxs(
2924
2943
  Box,
2925
2944
  {
2926
- flexGrow: 1,
2927
2945
  flexDirection: "column",
2928
- justifyContent: "center",
2929
- alignItems: "center",
2930
- children: overlay
2946
+ minHeight: listHeight,
2947
+ width: showRail ? listCols : void 0,
2948
+ flexShrink: 0,
2949
+ children: [
2950
+ /* @__PURE__ */ jsxs(Backdrop, { dimmed: !!overlay, absolute: !!overlay, height: listHeight, children: [
2951
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, children: visibleItems.map((item, i) => /* @__PURE__ */ jsx(
2952
+ ItemRow,
2953
+ {
2954
+ item,
2955
+ active: viewStart + i === cursor,
2956
+ login,
2957
+ merged: (item.kind === "pr" || item.kind === "issue") && !!mergedUrls?.includes(item.url),
2958
+ leaving: (item.kind === "pr" || item.kind === "issue") && !!leavingUrls?.includes(item.url),
2959
+ transient: transientOf(transients, item, section.id),
2960
+ prefix: treePrefix(section.items, viewStart + i),
2961
+ parent: item.kind === "task" && depthOf(section.items[viewStart + i + 1]) > depthOf(item),
2962
+ sparkFrame,
2963
+ cols: listCols,
2964
+ gap: i > 0 && gapsAbove(section.items, viewStart + i)
2965
+ },
2966
+ `${viewStart + i}:${item.kind === "task" ? item.instanceKey ?? item.key : item.kind === "repo-header" ? `header:${item.repo}` : item.kind === "subgroup-header" ? `subgroup:${item.label}` : item.kind === "show-more" ? `show-more:${item.hidden[0]?.repo ?? i}` : item.kind === "show-less" ? `show-less:${item.toHide[0]?.repo ?? i}` : `${item.repo}/${item.number}`}`
2967
+ )) }),
2968
+ hasMore && /* @__PURE__ */ jsxs(Text3, { dimColor: true, children: [
2969
+ " ",
2970
+ "\u2193 ",
2971
+ section.items.length - viewStart - visibleCount,
2972
+ " more"
2973
+ ] })
2974
+ ] }),
2975
+ overlay ? /* @__PURE__ */ jsx(
2976
+ Box,
2977
+ {
2978
+ flexGrow: 1,
2979
+ flexDirection: "column",
2980
+ justifyContent: "center",
2981
+ alignItems: "center",
2982
+ children: overlay
2983
+ }
2984
+ ) : null
2985
+ ]
2931
2986
  }
2932
- ) : null
2987
+ ),
2988
+ showRail && sidebar ? /* @__PURE__ */ jsx(SidePanel, { sidebar, height: listHeight }) : null
2933
2989
  ] }),
2934
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: flash ? /* @__PURE__ */ jsx(Text2, { color: "green", children: flash }) : /* @__PURE__ */ jsx(FooterHints, { hints }) })
2990
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: flash ? /* @__PURE__ */ jsx(Text3, { color: "green", children: flash }) : /* @__PURE__ */ jsx(FooterHints, { hints }) })
2935
2991
  ]
2936
2992
  }
2937
2993
  );
@@ -2947,7 +3003,7 @@ var NoRowsScreen = ({
2947
3003
  });
2948
3004
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
2949
3005
  /* @__PURE__ */ jsx(StatusMessage, { variant: reason === "empty" ? "info" : "error", children: reason === "empty" ? "Nothing open." : `Fetch failed \u2014 ${detail ?? "no reason reported"}` }),
2950
- reason === "empty" && detail ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text2, { dimColor: true, children: detail }) }) : null,
3006
+ reason === "empty" && detail ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text3, { dimColor: true, children: detail }) }) : null,
2951
3007
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
2952
3008
  FooterHints,
2953
3009
  {
@@ -3112,6 +3168,7 @@ var App = ({
3112
3168
  if (manual) setRefreshing(true);
3113
3169
  fetcher().then((fresh) => {
3114
3170
  if (fresh.budget) setBudget(fresh.budget);
3171
+ if (fresh.sidebar !== void 0) setSidebar(fresh.sidebar);
3115
3172
  if (cacheKey) writeCache(cacheKey, fresh);
3116
3173
  setRefreshing(false);
3117
3174
  setFetchedAt(Date.now());
@@ -3222,6 +3279,7 @@ var App = ({
3222
3279
  const [budget, setBudget] = useState(
3223
3280
  () => cacheKey ? readCache(cacheKey)?.budget ?? null : null
3224
3281
  );
3282
+ const [sidebar, setSidebar] = useState(void 0);
3225
3283
  const [skippedForBudget, setSkippedForBudget] = useState(false);
3226
3284
  const [mergedUrls, setMergedUrls] = useState([]);
3227
3285
  const [leavingUrls, setLeavingUrls] = useState([]);
@@ -3328,6 +3386,7 @@ var App = ({
3328
3386
  onLeave: markLeaving,
3329
3387
  transients,
3330
3388
  onTabChange: setVisibleTab,
3389
+ sidebar,
3331
3390
  ciStatusState: hasCiStatus ? ciStatusState : void 0,
3332
3391
  ciJob,
3333
3392
  tabHelp,
@@ -3380,4 +3439,4 @@ var matchesFilter = (repo, filter) => {
3380
3439
  };
3381
3440
  var parsePatterns = (value) => value.split(",").map((p) => p.trim()).filter(Boolean);
3382
3441
 
3383
- export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, PIN_MARK, budgetNotice, buildActions, buildCheckoutCmd, checkoutDirs, clipboard, configureInbox, drillCmd, explainGhAction, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, inboxConfig, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, profileOf, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resetInboxConfig, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
3442
+ export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, PIN_MARK, SIDEBAR_COLS, SidePanel, budgetNotice, buildActions, buildCheckoutCmd, checkoutDirs, clipboard, configureInbox, drillCmd, explainGhAction, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, inboxConfig, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, profileOf, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resetInboxConfig, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate2 as truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/gh-ink",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "Ink components for rendering GitHub PR review comments and health — controlled, presentation-only, built on @kud/ink-ui and fed by @kud/gh.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",