@wrongstack/tui 0.298.2 → 0.298.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,15 @@
1
1
  import type React from 'react';
2
2
  export interface SidebarPanelFrameProps {
3
- /** Accent color for border + title (mirrors `theme.monitor.*` on bottom panels). */
3
+ /** Accent color for the rail, title, and separator. */
4
4
  accent: string;
5
5
  /** Header glyph, e.g. `glyphs.fleet` or `glyphs.sessions`. */
6
6
  icon: string;
7
7
  /** Uppercase title (e.g. "FLEET", "PLAN", "AGENTS"). */
8
8
  title: string;
9
9
  /**
10
- * Width allocated to this panel frame, including the frame's own border and
11
- * padding. When nested in RightSidebar, pass that shell's content width —
12
- * not the outer sidebar width — so both chrome layers remain in bounds.
10
+ * Width allocated to this routed panel inside RightSidebar. The outer shell
11
+ * owns the border and padding; this frame spends the full content width on
12
+ * hierarchy and data.
13
13
  */
14
14
  width: number;
15
15
  /** Optional quiet subtitle hidden on narrow terminals. */
@@ -18,14 +18,8 @@ export interface SidebarPanelFrameProps {
18
18
  right?: React.ReactNode | undefined;
19
19
  /** Footer content (key hints, footer note). Renders under the body. */
20
20
  footer?: React.ReactNode | undefined;
21
- /** Body content. Renders inside the scrollable region. */
21
+ /** Body content. The outer RightSidebar owns viewport clipping. */
22
22
  children?: React.ReactNode | undefined;
23
- /**
24
- * Body scroll offset (in rows). When the body exceeds the visible window,
25
- * older rows are clipped from the top and a "↑ N earlier" marker is shown.
26
- * Pass `0` when no scrolling is needed (single panel fits in viewport).
27
- */
28
- bodyScrollOffset?: number | undefined;
29
23
  }
30
24
  /**
31
25
  * Truncate a string to fit within `max` display columns, adding an ellipsis.
@@ -47,8 +41,9 @@ export declare function SidebarSectionHeader({ glyph, label, color, badge, badge
47
41
  badgeColor?: string | undefined;
48
42
  innerWidth: number;
49
43
  }): React.ReactElement;
50
- /** A raised "card" wrapper. On truecolor terminals it gets a subtle lifted
51
- * surface so sections read as stacked panels; otherwise it is a plain box. */
44
+ /** A raised content band sized for a narrow rail. Section headers provide the
45
+ * accent, while the lifted surface groups related data without spending any
46
+ * horizontal columns on nested chrome. */
52
47
  export declare function SidebarPanelCard({ innerWidth, marginBottom, children, }: {
53
48
  innerWidth: number;
54
49
  marginBottom?: number | undefined;
@@ -56,17 +51,12 @@ export declare function SidebarPanelCard({ innerWidth, marginBottom, children, }
56
51
  }): React.ReactElement;
57
52
  /**
58
53
  * SidebarPanelFrame — the standard chrome wrapper used by every sidebar
59
- * panel variant. Renders a round border in the panel's accent color with a
60
- * glyph + title header, optional kicker + right-aligned badge, a scrollable
61
- * body region, and an optional footer.
62
- *
63
- * Scrolling: the body itself doesn't scroll. The host (app-view / SidebarContent)
64
- * computes scroll offsets from the focused panel index. We accept a
65
- * `bodyScrollOffset` and a fixed body height so panels that exceed their
66
- * viewport can be paged with Shift+Tab + ↑↓ while focused. When the body
67
- * scrolls, a "↑ N earlier" indicator is shown at the top of the body region.
54
+ * panel variant. It renders an accent-led title and telemetry strip inside the
55
+ * existing RightSidebar shell, followed by a natural-height body and optional
56
+ * footer. Avoiding a second border preserves scarce horizontal space; the
57
+ * outer shell clips the combined routed-panel and persistent-content stack.
68
58
  */
69
- export declare function SidebarPanelFrame({ accent, icon, title, width, kicker, right, footer, children, bodyScrollOffset, }: SidebarPanelFrameProps): React.ReactElement;
59
+ export declare function SidebarPanelFrame({ accent, icon, title, width, kicker, right, footer, children, }: SidebarPanelFrameProps): React.ReactElement;
70
60
  /**
71
61
  * useSidebarPanelSize — returns a sensible default width / height for a
72
62
  * sidebar panel given the terminal dimensions. Width mirrors
package/dist/index.js CHANGED
@@ -35419,9 +35419,7 @@ function SidebarContent({
35419
35419
  import { useEffect as useEffect68, useState as useState41 } from "react";
35420
35420
  import { jsx as jsx76, jsxs as jsxs73 } from "react/jsx-runtime";
35421
35421
  function trunc3(s2, max) {
35422
- if (max <= 0) return "";
35423
- if (s2.length <= max) return s2;
35424
- return `${s2.slice(0, Math.max(1, max - 1))}\u2026`;
35422
+ return truncateDisplay(s2, max);
35425
35423
  }
35426
35424
  function SidebarSectionHeader({
35427
35425
  glyph: glyph2,
@@ -35469,46 +35467,24 @@ function SidebarPanelFrame({
35469
35467
  kicker,
35470
35468
  right,
35471
35469
  footer,
35472
- children,
35473
- bodyScrollOffset = 0
35470
+ children
35474
35471
  }) {
35475
- const innerWidth = Math.max(8, width - 4);
35476
- const { stdout } = useStdout();
35477
- const sidebarHeight = Math.max(1, (stdout?.rows ?? 32) - 2);
35478
- const bodyHeight = Math.max(1, sidebarHeight - 4);
35479
- return /* @__PURE__ */ jsxs73(
35480
- Box,
35481
- {
35482
- flexDirection: "column",
35483
- width,
35484
- height: sidebarHeight,
35485
- overflowY: "hidden",
35486
- borderStyle: "round",
35487
- borderColor: accent,
35488
- paddingX: 1,
35489
- flexShrink: 0,
35490
- children: [
35491
- /* @__PURE__ */ jsx76(Box, { height: 1, children: /* @__PURE__ */ jsx76(Text, { color: accent, bold: true, wrap: "truncate", children: trunc3(`${icon} ${title}${kicker ? ` / ${kicker}` : ""}`, innerWidth) }) }),
35492
- right ? /* @__PURE__ */ jsx76(Box, { height: 1, children: /* @__PURE__ */ jsx76(Text, { wrap: "truncate", children: right }) }) : null,
35493
- /* @__PURE__ */ jsxs73(Box, { flexDirection: "column", height: bodyHeight, overflowY: "hidden", flexShrink: 0, children: [
35494
- bodyScrollOffset > 0 ? /* @__PURE__ */ jsx76(Box, { children: /* @__PURE__ */ jsxs73(Text, { color: theme.textMuted, dimColor: true, children: [
35495
- "\u2191 ",
35496
- bodyScrollOffset,
35497
- " earlier"
35498
- ] }) }) : null,
35499
- /* @__PURE__ */ jsx76(
35500
- Box,
35501
- {
35502
- flexDirection: "column",
35503
- ...bodyScrollOffset > 0 ? { marginTop: -bodyScrollOffset } : {},
35504
- children
35505
- }
35506
- )
35507
- ] }),
35508
- footer ? /* @__PURE__ */ jsx76(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsx76(Text, { wrap: "truncate", dimColor: true, children: footer }) }) : null
35509
- ]
35510
- }
35511
- );
35472
+ const innerWidth = Math.max(8, width);
35473
+ const showKicker = !!kicker && innerWidth >= 24;
35474
+ return /* @__PURE__ */ jsxs73(Box, { flexDirection: "column", width, flexShrink: 0, children: [
35475
+ /* @__PURE__ */ jsxs73(Box, { height: 1, width: innerWidth, children: [
35476
+ /* @__PURE__ */ jsx76(Text, { color: accent, bold: true, children: "\u258C" }),
35477
+ /* @__PURE__ */ jsx76(Text, { color: accent, bold: true, wrap: "truncate", children: trunc3(` ${icon} ${title}`, Math.max(1, innerWidth - 1)) })
35478
+ ] }),
35479
+ showKicker || right ? /* @__PURE__ */ jsxs73(Box, { height: 1, width: innerWidth, children: [
35480
+ showKicker ? /* @__PURE__ */ jsx76(Text, { color: theme.textMuted, dimColor: true, wrap: "truncate", children: trunc3(kicker, Math.max(1, right ? Math.floor(innerWidth * 0.55) : innerWidth)) }) : null,
35481
+ /* @__PURE__ */ jsx76(Box, { flexGrow: 1 }),
35482
+ right ? /* @__PURE__ */ jsx76(Text, { wrap: "truncate", children: right }) : null
35483
+ ] }) : null,
35484
+ /* @__PURE__ */ jsx76(Text, { color: accent, wrap: "truncate", children: "\u2500".repeat(innerWidth) }),
35485
+ /* @__PURE__ */ jsx76(Box, { flexDirection: "column", children }),
35486
+ footer ? /* @__PURE__ */ jsx76(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsx76(Text, { wrap: "truncate", dimColor: true, children: footer }) }) : null
35487
+ ] });
35512
35488
  }
35513
35489
 
35514
35490
  // src/components/sidebar-panels.tsx
@@ -35575,7 +35551,7 @@ function ProjectPickerSidebar({
35575
35551
  currentProject,
35576
35552
  width
35577
35553
  }) {
35578
- const inner = Math.max(8, width - 4);
35554
+ const inner = Math.max(8, width);
35579
35555
  const projectCount = items.filter((item) => item.kind === "project").length;
35580
35556
  const selectableCount = items.filter((item) => item.key !== "__divider__").length;
35581
35557
  const start = Math.max(0, Math.min(selected - 2, Math.max(0, items.length - 5)));
@@ -35656,7 +35632,7 @@ function FleetPanelSidebar({
35656
35632
  runningCount,
35657
35633
  width
35658
35634
  }) {
35659
- const inner = Math.max(8, width - 4);
35635
+ const inner = Math.max(8, width);
35660
35636
  const all = Object.values(entries);
35661
35637
  const leader = all.find((e) => e.id === "leader");
35662
35638
  const subagents = all.filter((e) => e !== leader && e.status === "running");
@@ -35690,7 +35666,7 @@ function AgentsPanelSidebar({
35690
35666
  nowTick,
35691
35667
  width
35692
35668
  }) {
35693
- const inner = Math.max(8, width - 4);
35669
+ const inner = Math.max(8, width);
35694
35670
  const all = Object.values(entries);
35695
35671
  const running = all.filter((e) => e.status === "running");
35696
35672
  const done = all.filter((e) => e.status === "success");
@@ -35727,13 +35703,10 @@ function AgentsPanelSidebar({
35727
35703
  }
35728
35704
  ),
35729
35705
  /* @__PURE__ */ jsx77(Text, { color: theme.textPrimary, wrap: "truncate", bold: true, children: trunc3(hotAgent.name || hotAgent.id, inner - 4) }),
35730
- /* @__PURE__ */ jsxs74(Text, { color: theme.textMuted, children: [
35731
- "ctx ",
35732
- Math.round((hotAgent.ctxPct ?? 0) * 100),
35733
- "% \xB7",
35734
- " ",
35735
- hotAgent.currentTool?.name ?? "idle"
35736
- ] })
35706
+ /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, wrap: "truncate", children: trunc3(
35707
+ `ctx ${Math.round((hotAgent.ctxPct ?? 0) * 100)}% \xB7 ${hotAgent.currentTool?.name ?? "idle"}`,
35708
+ inner
35709
+ ) })
35737
35710
  ] }) : /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: "no live agents" }) }),
35738
35711
  /* @__PURE__ */ jsxs74(SidebarPanelCard, { innerWidth: inner, marginBottom: 0, children: [
35739
35712
  /* @__PURE__ */ jsx77(
@@ -35767,7 +35740,7 @@ function AgentsPanelSidebar({
35767
35740
  function worktreeStatusVisual(status) {
35768
35741
  switch (status) {
35769
35742
  case "active":
35770
- return { glyph: "\u25CF", color: theme.warn };
35743
+ return { glyph: "\u2022", color: theme.warn };
35771
35744
  case "committing":
35772
35745
  return { glyph: "\u25D0", color: theme.accent };
35773
35746
  case "merging":
@@ -35786,7 +35759,7 @@ function WorktreePanelSidebar({
35786
35759
  worktrees,
35787
35760
  width
35788
35761
  }) {
35789
- const inner = Math.max(8, width - 4);
35762
+ const inner = Math.max(8, width);
35790
35763
  const list = Object.values(worktrees);
35791
35764
  const active = list.filter(
35792
35765
  (w) => w.status === "active" || w.status === "committing" || w.status === "merging"
@@ -35803,18 +35776,18 @@ function WorktreePanelSidebar({
35803
35776
  kicker: "isolation",
35804
35777
  right: /* @__PURE__ */ jsxs74(Text, { children: [
35805
35778
  /* @__PURE__ */ jsxs74(Text, { color: theme.warn, children: [
35806
- "\u25B6",
35779
+ "A",
35807
35780
  active
35808
35781
  ] }),
35809
35782
  /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: " " }),
35810
35783
  /* @__PURE__ */ jsxs74(Text, { color: theme.success, children: [
35811
- glyphs.success,
35784
+ "D",
35812
35785
  merged
35813
35786
  ] }),
35814
35787
  failed > 0 ? /* @__PURE__ */ jsxs74(Fragment27, { children: [
35815
35788
  /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: " " }),
35816
35789
  /* @__PURE__ */ jsxs74(Text, { color: theme.error, children: [
35817
- "\u2717",
35790
+ "!",
35818
35791
  failed
35819
35792
  ] })
35820
35793
  ] }) : null
@@ -35822,18 +35795,22 @@ function WorktreePanelSidebar({
35822
35795
  footer: "F4 details",
35823
35796
  children: /* @__PURE__ */ jsx77(SidebarPanelCard, { innerWidth: inner, marginBottom: 0, children: list.length === 0 ? /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: "no worktrees" }) : list.slice(0, 10).map((w) => {
35824
35797
  const v = worktreeStatusVisual(w.status);
35825
- const branch = trunc3(w.branch.replace(/^wstack\/ap\//, ""), inner - 16);
35798
+ const diff = `+${w.insertions}/-${w.deletions}`;
35799
+ const showDiff = inner >= 24;
35800
+ const rowChrome = displayWidth(v.glyph) + 1;
35801
+ const diffWidth = showDiff ? displayWidth(diff) + 1 : 0;
35802
+ const branch = trunc3(
35803
+ w.branch.replace(/^wstack\/ap\//, ""),
35804
+ Math.max(4, inner - rowChrome - diffWidth)
35805
+ );
35826
35806
  return /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
35827
35807
  /* @__PURE__ */ jsx77(Text, { color: v.color, children: v.glyph }),
35828
35808
  /* @__PURE__ */ jsx77(Text, { color: theme.textPrimary, children: " " }),
35829
35809
  /* @__PURE__ */ jsx77(Text, { wrap: "truncate", children: branch }),
35830
- /* @__PURE__ */ jsx77(Box, { flexGrow: 1 }),
35831
- /* @__PURE__ */ jsxs74(Text, { color: theme.textMuted, children: [
35832
- "+",
35833
- w.insertions,
35834
- "/-",
35835
- w.deletions
35836
- ] })
35810
+ showDiff ? /* @__PURE__ */ jsxs74(Fragment27, { children: [
35811
+ /* @__PURE__ */ jsx77(Box, { flexGrow: 1 }),
35812
+ /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: diff })
35813
+ ] }) : null
35837
35814
  ] }, w.branch);
35838
35815
  }) })
35839
35816
  }
@@ -35847,7 +35824,7 @@ function PlanPanelSidebar({
35847
35824
  title,
35848
35825
  width
35849
35826
  }) {
35850
- const inner = Math.max(8, width - 4);
35827
+ const inner = Math.max(8, width);
35851
35828
  const total = openCount + inProgressCount + doneCount;
35852
35829
  const ratio = total > 0 ? doneCount / total : 0;
35853
35830
  const ordered = [
@@ -35893,8 +35870,8 @@ function PlanPanelSidebar({
35893
35870
  }
35894
35871
  ),
35895
35872
  /* @__PURE__ */ jsxs74(Box, { children: [
35896
- /* @__PURE__ */ jsx77(Text, { color: ratio === 1 && total > 0 ? theme.success : theme.accent, children: "\u2588".repeat(Math.round(ratio * (inner - 4))) }),
35897
- /* @__PURE__ */ jsx77(Text, { color: theme.borderSubtle, children: "\u2591".repeat(Math.max(0, inner - 4 - Math.round(ratio * (inner - 4)))) })
35873
+ /* @__PURE__ */ jsx77(Text, { color: ratio === 1 && total > 0 ? theme.success : theme.accent, children: "\u2588".repeat(Math.round(ratio * inner)) }),
35874
+ /* @__PURE__ */ jsx77(Text, { color: theme.borderSubtle, children: "\u2591".repeat(Math.max(0, inner - Math.round(ratio * inner))) })
35898
35875
  ] })
35899
35876
  ] }),
35900
35877
  /* @__PURE__ */ jsxs74(SidebarPanelCard, { innerWidth: inner, marginBottom: 0, children: [
@@ -35932,7 +35909,7 @@ function PlanPanelSidebar({
35932
35909
  );
35933
35910
  }
35934
35911
  function TodosPanelSidebar({ todos, width }) {
35935
- const inner = Math.max(8, width - 4);
35912
+ const inner = Math.max(8, width);
35936
35913
  const ordered = [...todos].sort((a, b) => {
35937
35914
  const rank = (t) => t.status === "in_progress" ? 0 : t.status === "pending" ? 1 : 2;
35938
35915
  return rank(a) - rank(b);
@@ -35977,7 +35954,7 @@ function TodosPanelSidebar({ todos, width }) {
35977
35954
  );
35978
35955
  }
35979
35956
  function QueuePanelSidebar({ items, width }) {
35980
- const inner = Math.max(8, width - 4);
35957
+ const inner = Math.max(8, width);
35981
35958
  return /* @__PURE__ */ jsx77(
35982
35959
  SidebarPanelFrame,
35983
35960
  {
@@ -36014,7 +35991,7 @@ function ProcessListPanelSidebar({
36014
35991
  processes,
36015
35992
  width
36016
35993
  }) {
36017
- const inner = Math.max(8, width - 4);
35994
+ const inner = Math.max(8, width);
36018
35995
  return /* @__PURE__ */ jsx77(
36019
35996
  SidebarPanelFrame,
36020
35997
  {
@@ -36046,7 +36023,7 @@ function GoalPanelSidebar({
36046
36023
  coordinatorRunning,
36047
36024
  width
36048
36025
  }) {
36049
- const inner = Math.max(8, width - 4);
36026
+ const inner = Math.max(8, width);
36050
36027
  const displayGoal = goal ? goal.refinedGoal || goal.goal : "";
36051
36028
  const stateIcon = goal?.goalState === "active" ? "\u{1F504}" : goal?.goalState === "paused" ? "\u23F8" : goal?.goalState === "completed" ? "\u2705" : "\u23F9";
36052
36029
  const progress = typeof goal?.progress === "number" ? goal.progress : 0;
@@ -36091,8 +36068,8 @@ function GoalPanelSidebar({
36091
36068
  }
36092
36069
  ),
36093
36070
  /* @__PURE__ */ jsxs74(Box, { children: [
36094
- /* @__PURE__ */ jsx77(Text, { color: theme.success, children: "\u2588".repeat(Math.round(progress / 100 * (inner - 4))) }),
36095
- /* @__PURE__ */ jsx77(Text, { color: theme.borderSubtle, children: "\u2591".repeat(Math.max(0, inner - 4 - Math.round(progress / 100 * (inner - 4)))) })
36071
+ /* @__PURE__ */ jsx77(Text, { color: theme.success, children: "\u2588".repeat(Math.round(progress / 100 * inner)) }),
36072
+ /* @__PURE__ */ jsx77(Text, { color: theme.borderSubtle, children: "\u2591".repeat(Math.max(0, inner - Math.round(progress / 100 * inner))) })
36096
36073
  ] })
36097
36074
  ] }),
36098
36075
  /* @__PURE__ */ jsxs74(SidebarPanelCard, { innerWidth: inner, marginBottom: 0, children: [
@@ -36134,7 +36111,7 @@ function SessionsPanelSidebar({
36134
36111
  currentSessionId,
36135
36112
  width
36136
36113
  }) {
36137
- const inner = Math.max(8, width - 4);
36114
+ const inner = Math.max(8, width);
36138
36115
  const live = liveSessions?.slice(0, 3) ?? [];
36139
36116
  const resume = resumeSessions?.slice(0, 3) ?? [];
36140
36117
  const total = (liveSessions?.length ?? 0) + (resumeSessions?.length ?? 0);
@@ -36226,7 +36203,7 @@ function CoordinatorPanelSidebar({
36226
36203
  elapsedMs,
36227
36204
  width
36228
36205
  }) {
36229
- const inner = Math.max(8, width - 4);
36206
+ const inner = Math.max(8, width);
36230
36207
  return /* @__PURE__ */ jsxs74(
36231
36208
  SidebarPanelFrame,
36232
36209
  {
@@ -36271,7 +36248,7 @@ function KanbanPanelSidebar({
36271
36248
  activeCardTitles,
36272
36249
  width
36273
36250
  }) {
36274
- const inner = Math.max(8, width - 4);
36251
+ const inner = Math.max(8, width);
36275
36252
  return /* @__PURE__ */ jsxs74(
36276
36253
  SidebarPanelFrame,
36277
36254
  {
@@ -36334,7 +36311,7 @@ function ConnectionsPanelSidebar({
36334
36311
  connections,
36335
36312
  width
36336
36313
  }) {
36337
- const inner = Math.max(8, width - 4);
36314
+ const inner = Math.max(8, width);
36338
36315
  const okCount = connections.filter((c) => c.status === "ok").length;
36339
36316
  const warnCount = connections.filter((c) => c.status === "warn").length;
36340
36317
  const downCount = connections.filter((c) => c.status === "down").length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/tui",
3
- "version": "0.298.2",
3
+ "version": "0.298.3",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack terminal UI: Ink-based interactive renderer with history, pickers, and slash menus.",
6
6
  "repository": {
@@ -28,12 +28,12 @@
28
28
  "dependencies": {
29
29
  "ink": "7.1.1",
30
30
  "react": "^19.2.8",
31
- "@wrongstack/kanban": "0.298.2",
32
- "@wrongstack/core": "0.298.2",
33
- "@wrongstack/tools": "0.298.2",
34
- "@wrongstack/runtime": "0.298.2",
35
- "@wrongstack/sage": "0.298.2",
36
- "@wrongstack/sdd": "0.298.2"
31
+ "@wrongstack/core": "0.298.3",
32
+ "@wrongstack/tools": "0.298.3",
33
+ "@wrongstack/kanban": "0.298.3",
34
+ "@wrongstack/runtime": "0.298.3",
35
+ "@wrongstack/sdd": "0.298.3",
36
+ "@wrongstack/sage": "0.298.3"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@testing-library/dom": "^10.4.1",