pi-bar 0.3.31 → 0.3.33

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/README.md CHANGED
@@ -9,9 +9,9 @@
9
9
  claude-opus-4.7 ❯ think:med ❯ 2.6% / 1.0M ❯ Reviewing package structure ❯ plan:active
10
10
  ```
11
11
 
12
- ![pi-bar with low context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.31/assets/screenshot-green.png)
13
- ![pi-bar with medium context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.31/assets/screenshot-yellow.png)
14
- ![pi-bar with high context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.31/assets/screenshot-red.png)
12
+ ![pi-bar with low context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.33/assets/screenshot-green.png)
13
+ ![pi-bar with medium context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.33/assets/screenshot-yellow.png)
14
+ ![pi-bar with high context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.33/assets/screenshot-red.png)
15
15
 
16
16
  ## Why use it?
17
17
 
@@ -21,7 +21,7 @@ claude-opus-4.7 ❯ think:med ❯ 2.6% / 1.0M ❯ Reviewing package struct
21
21
  - **Follow what pi is doing** — a one-line progress update keeps the current task visible without scrolling.
22
22
  - **Keep extension statuses visible** — statuses other extensions set still appear in the footer.
23
23
 
24
- pi-bar is intentionally tiny: one small extension, no broad behavior changes, and no commands to learn. It replaces pi's built-in footer with a compact model / thinking / context / progress / extension-status line.
24
+ pi-bar is intentionally tiny: one small extension and no broad behavior changes. It replaces pi's built-in footer with a compact model / thinking / context / progress / extension-status line.
25
25
 
26
26
  ## Install
27
27
 
@@ -37,20 +37,33 @@ If pi is already running after install, reload resources:
37
37
 
38
38
  ## Customization
39
39
 
40
- pi-bar works out of the box, but you can tune it with environment variables before launching pi.
40
+ pi-bar works out of the box. Run `/bar` inside pi to choose which footer segments are shown:
41
41
 
42
- ### Show or hide segments
42
+ ```text
43
+ /bar
44
+ ```
45
+
46
+ Toggle `Model`, `Thinking level`, `Context usage`, `Progress update`, and `Extension statuses` between `shown` and `hidden`. You can also use commands:
47
+
48
+ ```text
49
+ /bar segments list
50
+ /bar segments only model context
51
+ /bar segments hide progress
52
+ /bar segments show thinking
53
+ ```
54
+
55
+ Allowed segments are `model`, `thinking`, `context`, `progress`, and `extensions`. The `progress` segment stays hidden until pi-bar has a current update. The `extensions` segment stays hidden when no extension has set a status.
56
+
57
+ You can also set startup defaults with environment variables before launching pi:
43
58
 
44
59
  ```bash
45
60
  PI_BAR_SHOW=model,thinking,context,progress,extensions pi
46
61
  PI_BAR_SHOW=model,context pi
47
62
  ```
48
63
 
49
- Allowed segments are `model`, `thinking`, `context`, `progress`, and `extensions`. The `progress` segment stays hidden until pi-bar has a current update. The `extensions` segment stays hidden when no extension has set a status.
50
-
51
64
  ### Configure live progress updates
52
65
 
53
- pi-bar shows a short, plain-English description of what pi is working on right now. It refreshes as pi works and resets when you switch branches in the session tree, so stale updates never follow you across tasks. Set `PI_BAR_SHOW` without `progress` to hide it.
66
+ pi-bar shows a short, plain-English description of what pi is working on right now. It refreshes as pi works and resets when you switch branches in the session tree, so stale updates never follow you across tasks. Hide `Progress update` in `/bar`, run `/bar segments hide progress`, or set `PI_BAR_SHOW` without `progress` to disable it.
54
67
 
55
68
  Pick a specific model for the update by setting the env var or pi settings:
56
69
 
@@ -62,10 +75,10 @@ Or in pi settings: `bar.progressModel`. Otherwise pi-bar picks a fast model you
62
75
 
63
76
  ### Configure extension statuses
64
77
 
65
- Other pi extensions can publish small status badges. Pi-bar collects them into the `extensions` segment. Run `/bar` inside pi to pick which ones to show:
78
+ Other pi extensions can publish small status badges. Pi-bar collects them into the `extensions` segment. Run `/bar status` inside pi to pick which ones to show:
66
79
 
67
80
  ```text
68
- /bar
81
+ /bar status
69
82
  ```
70
83
 
71
84
  Toggle each status between `shown` and `hidden`. The `New statuses` row controls the default for badges that appear later.
@@ -89,4 +102,4 @@ The first number is the warning/yellow threshold. The second number is the dange
89
102
 
90
103
  Pi extensions run with your local user permissions. Review any pi package source before installing it.
91
104
 
92
- Progress updates send short snippets of your session activity to the selected model provider. Disable the `progress` segment with `PI_BAR_SHOW` if that is not acceptable.
105
+ Progress updates send short snippets of your session activity to the selected model provider. Hide `Progress update` in `/bar` or disable the `progress` segment with `PI_BAR_SHOW` if that is not acceptable.
@@ -14,7 +14,7 @@
14
14
  * PI_BAR_SHOW comma-separated list of segments to show
15
15
  * PI_BAR_THRESHOLDS warning,danger context-usage percentages
16
16
  * PI_BAR_PROGRESS_MODEL provider/id for the progress update model
17
- * PI_BAR_CONFIG override the persisted status-filter config path
17
+ * PI_BAR_CONFIG override the persisted pi-bar config path
18
18
  */
19
19
 
20
20
  import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
@@ -42,6 +42,10 @@ type StatusFilter =
42
42
  type SerializedStatusFilter =
43
43
  | { mode: "all"; hidden: string[] }
44
44
  | { mode: "only"; shown: string[] };
45
+ type GlobalBarConfig = {
46
+ statusFilter?: SerializedStatusFilter;
47
+ segments?: SegmentName[];
48
+ };
45
49
  type ProgressActivityType =
46
50
  | "user_message"
47
51
  | "assistant_update"
@@ -76,9 +80,6 @@ type FastModelAuth = {
76
80
 
77
81
  const STATUS_FILTER_ENTRY_TYPE = "pi-bar-status-filter";
78
82
  const SETTINGS_PROGRESS_KEY = "progress";
79
- // Legacy settings/env names. The `tldr` keys remain accepted so existing user
80
- // configs continue to work after the rename to "progress updates".
81
- const LEGACY_SETTINGS_TLDR_KEY = "tldr";
82
83
  const SETTINGS_BAR_KEY = "bar";
83
84
  const MAX_ACTIVITY_TEXT_CHARS = 800;
84
85
  const MAX_USER_TEXT_CHARS = 700;
@@ -113,6 +114,20 @@ const DEFAULT_SEGMENTS: SegmentName[] = [
113
114
  "progress",
114
115
  "extensions",
115
116
  ];
117
+ const ALL_SEGMENTS: readonly SegmentName[] = [
118
+ "model",
119
+ "thinking",
120
+ "context",
121
+ "progress",
122
+ "extensions",
123
+ ];
124
+ const SEGMENT_LABELS: Record<SegmentName, string> = {
125
+ model: "Model",
126
+ thinking: "Thinking level",
127
+ context: "Context usage",
128
+ progress: "Progress update",
129
+ extensions: "Extension statuses",
130
+ };
116
131
  const DEFAULT_WARNING_THRESHOLD = 70;
117
132
  const DEFAULT_ERROR_THRESHOLD = 90;
118
133
 
@@ -169,19 +184,18 @@ function contextColor(
169
184
  return "success";
170
185
  }
171
186
 
187
+ function isSegmentName(value: string): value is SegmentName {
188
+ return (ALL_SEGMENTS as readonly string[]).includes(value);
189
+ }
190
+
172
191
  function parseSegments(): SegmentName[] {
173
192
  const raw = process.env.PI_BAR_SHOW;
174
193
  if (!raw) return DEFAULT_SEGMENTS;
175
194
 
176
- // `tldr` is the legacy segment name, kept working as an alias so existing
177
- // PI_BAR_SHOW configs do not break after the rename to "progress".
178
195
  const requested = raw
179
196
  .split(",")
180
197
  .map((segment) => segment.trim().toLowerCase())
181
- .map((segment) => (segment === "tldr" ? "progress" : segment))
182
- .filter((segment): segment is SegmentName =>
183
- ["model", "thinking", "context", "progress", "extensions"].includes(segment),
184
- );
198
+ .filter(isSegmentName);
185
199
 
186
200
  return requested.length > 0 ? requested : DEFAULT_SEGMENTS;
187
201
  }
@@ -225,11 +239,8 @@ function parseProgressModelSpec(value: string): ProgressModelPreference | undefi
225
239
  function settingsModelValue(settings: Record<string, unknown>): string | undefined {
226
240
  const bar = settings[SETTINGS_BAR_KEY];
227
241
  if (bar && typeof bar === "object" && !Array.isArray(bar)) {
228
- const record = bar as Record<string, unknown>;
229
- // Canonical key after rename. Falls through to legacy `tldrModel` so old
230
- // settings still work without manual migration.
231
- if (typeof record.progressModel === "string") return record.progressModel;
232
- if (typeof record.tldrModel === "string") return record.tldrModel;
242
+ const value = (bar as Record<string, unknown>).progressModel;
243
+ if (typeof value === "string") return value;
233
244
  }
234
245
 
235
246
  const progressSection = settings[SETTINGS_PROGRESS_KEY];
@@ -238,20 +249,11 @@ function settingsModelValue(settings: Record<string, unknown>): string | undefin
238
249
  if (typeof value === "string") return value;
239
250
  }
240
251
 
241
- const legacy = settings[LEGACY_SETTINGS_TLDR_KEY];
242
- if (legacy && typeof legacy === "object" && !Array.isArray(legacy)) {
243
- const value = (legacy as Record<string, unknown>).model;
244
- if (typeof value === "string") return value;
245
- }
246
-
247
252
  return undefined;
248
253
  }
249
254
 
250
255
  function resolveProgressModelPreference(cwd: string): ProgressModelPreference | undefined {
251
- // PI_BAR_PROGRESS_MODEL is the canonical env var. PI_BAR_TLDR_MODEL is
252
- // honored as a backwards-compat alias for users who set it before the
253
- // rename.
254
- const envModel = process.env.PI_BAR_PROGRESS_MODEL ?? process.env.PI_BAR_TLDR_MODEL;
256
+ const envModel = process.env.PI_BAR_PROGRESS_MODEL;
255
257
  if (envModel) return parseProgressModelSpec(envModel);
256
258
 
257
259
  const settings = SettingsManager.create(cwd);
@@ -1541,6 +1543,18 @@ function serializeStatusFilter(filter: StatusFilter): SerializedStatusFilter {
1541
1543
  return { mode: "all", hidden: Array.from(filter.hidden).sort() };
1542
1544
  }
1543
1545
 
1546
+ function serializeSegments(segments: readonly SegmentName[]): SegmentName[] {
1547
+ return ALL_SEGMENTS.filter((segment) => segments.includes(segment));
1548
+ }
1549
+
1550
+ function parseSerializedSegments(value: unknown): SegmentName[] | null {
1551
+ if (!Array.isArray(value)) return null;
1552
+ const segments = value.filter(
1553
+ (segment): segment is SegmentName => typeof segment === "string" && isSegmentName(segment),
1554
+ );
1555
+ return serializeSegments(segments);
1556
+ }
1557
+
1544
1558
  function parseSerializedStatusFilter(value: unknown): StatusFilter | null {
1545
1559
  if (!value || typeof value !== "object") return null;
1546
1560
  const data = value as Partial<SerializedStatusFilter>;
@@ -1561,6 +1575,18 @@ function splitStatusKeys(raw: string): string[] {
1561
1575
  .filter(Boolean);
1562
1576
  }
1563
1577
 
1578
+ function splitSegmentNames(raw: string): SegmentName[] {
1579
+ return raw
1580
+ .split(/[\s,]+/)
1581
+ .map((segment) => segment.trim().toLowerCase())
1582
+ .filter(isSegmentName);
1583
+ }
1584
+
1585
+ function describeSegments(segments: readonly SegmentName[]): string {
1586
+ if (segments.length === 0) return "showing none";
1587
+ return `showing: ${segments.map((segment) => SEGMENT_LABELS[segment]).join(", ")}`;
1588
+ }
1589
+
1564
1590
  function describeStatusFilter(filter: StatusFilter): string {
1565
1591
  if (filter.mode === "only") {
1566
1592
  const shown = Array.from(filter.shown).sort();
@@ -1571,29 +1597,45 @@ function describeStatusFilter(filter: StatusFilter): string {
1571
1597
  return hidden.length > 0 ? `showing all except: ${hidden.join(", ")}` : "showing all";
1572
1598
  }
1573
1599
 
1574
- function readGlobalStatusFilter(): StatusFilter | null {
1600
+ function readGlobalConfig(): GlobalBarConfig {
1575
1601
  try {
1576
- const data = JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as {
1577
- statusFilter?: unknown;
1602
+ const data = JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as Record<string, unknown>;
1603
+ const statusFilter = parseSerializedStatusFilter(data.statusFilter ?? data);
1604
+ return {
1605
+ statusFilter: statusFilter ? serializeStatusFilter(statusFilter) : undefined,
1606
+ segments: parseSerializedSegments(data.segments) ?? undefined,
1578
1607
  };
1579
- return parseSerializedStatusFilter(data.statusFilter ?? data);
1580
1608
  } catch {
1581
- return null;
1609
+ return {};
1582
1610
  }
1583
1611
  }
1584
1612
 
1585
- function writeGlobalStatusFilter(filter: StatusFilter): void {
1586
- const data = JSON.stringify(
1587
- { statusFilter: serializeStatusFilter(filter) },
1588
- null,
1589
- 2,
1590
- );
1613
+ function readGlobalStatusFilter(): StatusFilter | null {
1614
+ return parseSerializedStatusFilter(readGlobalConfig().statusFilter);
1615
+ }
1616
+
1617
+ function readGlobalSegments(): SegmentName[] | null {
1618
+ return process.env.PI_BAR_SHOW ? parseSegments() : readGlobalConfig().segments ?? null;
1619
+ }
1620
+
1621
+ function writeGlobalConfig(config: GlobalBarConfig): void {
1622
+ const data = JSON.stringify(config, null, 2);
1591
1623
  mkdirSync(dirname(CONFIG_PATH), { recursive: true });
1592
1624
  const tmpPath = `${CONFIG_PATH}.${process.pid}.tmp`;
1593
1625
  writeFileSync(tmpPath, `${data}\n`, "utf8");
1594
1626
  renameSync(tmpPath, CONFIG_PATH);
1595
1627
  }
1596
1628
 
1629
+ function writeGlobalStatusFilter(filter: StatusFilter): void {
1630
+ const existing = readGlobalConfig();
1631
+ writeGlobalConfig({ ...existing, statusFilter: serializeStatusFilter(filter) });
1632
+ }
1633
+
1634
+ function writeGlobalSegments(segments: readonly SegmentName[]): void {
1635
+ const existing = readGlobalConfig();
1636
+ writeGlobalConfig({ ...existing, segments: serializeSegments(segments) });
1637
+ }
1638
+
1597
1639
  function getKnownStatusKeys(filter: StatusFilter, seenStatusKeys: Set<string>): string[] {
1598
1640
  const keys = new Set(seenStatusKeys);
1599
1641
  if (filter.mode === "only") {
@@ -1607,6 +1649,7 @@ function getKnownStatusKeys(filter: StatusFilter, seenStatusKeys: Set<string>):
1607
1649
  export default function (pi: ExtensionAPI) {
1608
1650
  let requestRender: (() => void) | undefined;
1609
1651
  let statusFilter: StatusFilter = { mode: "all", hidden: new Set() };
1652
+ let visibleSegments: SegmentName[] = readGlobalSegments() ?? DEFAULT_SEGMENTS;
1610
1653
  const seenStatusKeys = new Set<string>();
1611
1654
  const refresh = () => requestRender?.();
1612
1655
  const progress = new FooterProgressEngine(refresh);
@@ -1625,6 +1668,81 @@ export default function (pi: ExtensionAPI) {
1625
1668
  writeGlobalStatusFilter(statusFilter);
1626
1669
  refresh();
1627
1670
  };
1671
+ const setVisibleSegments = (segments: readonly SegmentName[], ctx?: ExtensionContext) => {
1672
+ const previousProgressVisible = visibleSegments.includes("progress");
1673
+ visibleSegments = serializeSegments(segments);
1674
+ writeGlobalSegments(visibleSegments);
1675
+ const nextProgressVisible = visibleSegments.includes("progress");
1676
+ if (previousProgressVisible && !nextProgressVisible) progress.shutdown();
1677
+ if (!previousProgressVisible && nextProgressVisible && ctx) progress.startSession(ctx.cwd);
1678
+ refresh();
1679
+ };
1680
+ const openSegmentConfigurator = async (ctx: ExtensionContext) => {
1681
+ await ctx.ui.custom((tui, theme, _kb, done) => {
1682
+ const segmentVisibility = new Map(
1683
+ ALL_SEGMENTS.map(
1684
+ (segment): [SegmentName, boolean] => [segment, visibleSegments.includes(segment)],
1685
+ ),
1686
+ );
1687
+ const persistFromVisibility = () => {
1688
+ setVisibleSegments(
1689
+ ALL_SEGMENTS.filter((segment) => segmentVisibility.get(segment)),
1690
+ ctx,
1691
+ );
1692
+ };
1693
+
1694
+ const items: SettingItem[] = ALL_SEGMENTS.map((segment): SettingItem => ({
1695
+ id: segment,
1696
+ label: SEGMENT_LABELS[segment],
1697
+ description: "Footer segment visibility",
1698
+ currentValue: segmentVisibility.get(segment) ? "shown" : "hidden",
1699
+ values: ["shown", "hidden"],
1700
+ }));
1701
+
1702
+ const container = new Container();
1703
+ container.addChild(
1704
+ new (class {
1705
+ render(_width: number) {
1706
+ return [
1707
+ theme.fg("accent", theme.bold("pi-bar footer visibility")),
1708
+ theme.fg("dim", "Enter/Space toggles · Esc closes"),
1709
+ "",
1710
+ ];
1711
+ }
1712
+ invalidate() {}
1713
+ })(),
1714
+ );
1715
+
1716
+ const settingsList = new SettingsList(
1717
+ items,
1718
+ Math.min(items.length + 2, 15),
1719
+ getSettingsListTheme(),
1720
+ (id, newValue) => {
1721
+ if (isSegmentName(id)) {
1722
+ segmentVisibility.set(id, newValue === "shown");
1723
+ persistFromVisibility();
1724
+ }
1725
+ },
1726
+ () => done(undefined),
1727
+ { enableSearch: true },
1728
+ );
1729
+
1730
+ container.addChild(settingsList);
1731
+
1732
+ return {
1733
+ render(width: number) {
1734
+ return container.render(width);
1735
+ },
1736
+ invalidate() {
1737
+ container.invalidate();
1738
+ },
1739
+ handleInput(data: string) {
1740
+ settingsList.handleInput?.(data);
1741
+ tui.requestRender();
1742
+ },
1743
+ };
1744
+ });
1745
+ };
1628
1746
  const openStatusConfigurator = async (ctx: ExtensionContext) => {
1629
1747
  const knownStatusKeys = getKnownStatusKeys(statusFilter, seenStatusKeys);
1630
1748
  if (knownStatusKeys.length === 0) {
@@ -1724,10 +1842,70 @@ export default function (pi: ExtensionAPI) {
1724
1842
  };
1725
1843
 
1726
1844
  pi.registerCommand("bar", {
1727
- description: "Configure pi-bar footer status segments",
1845
+ description: "Configure pi-bar footer visibility",
1728
1846
  handler: async (args, ctx) => {
1729
1847
  const [section, action, ...rest] = args.trim().split(/\s+/).filter(Boolean);
1730
- if (!section || ((section === "status" || section === "statuses") && !action)) {
1848
+ if (!section || section === "config" || section === "configure" || section === "edit") {
1849
+ await openSegmentConfigurator(ctx);
1850
+ return;
1851
+ }
1852
+ if (section === "list" || section === "ls") {
1853
+ ctx.ui.notify(`pi-bar footer: ${describeSegments(visibleSegments)}`, "info");
1854
+ return;
1855
+ }
1856
+
1857
+ if (section === "segment" || section === "segments" || section === "footer") {
1858
+ const segments = splitSegmentNames(rest.join(" "));
1859
+ if ((action === "only" || action === "show" || action === "hide") && segments.length === 0) {
1860
+ ctx.ui.notify(
1861
+ `Segments: ${ALL_SEGMENTS.join(", ")}`,
1862
+ "warning",
1863
+ );
1864
+ return;
1865
+ }
1866
+
1867
+ switch (action) {
1868
+ case undefined:
1869
+ case "config":
1870
+ case "configure":
1871
+ case "edit":
1872
+ await openSegmentConfigurator(ctx);
1873
+ return;
1874
+ case "list":
1875
+ case "ls":
1876
+ ctx.ui.notify(`pi-bar footer: ${describeSegments(visibleSegments)}`, "info");
1877
+ return;
1878
+ case "all":
1879
+ setVisibleSegments(ALL_SEGMENTS, ctx);
1880
+ break;
1881
+ case "none":
1882
+ setVisibleSegments([], ctx);
1883
+ break;
1884
+ case "only":
1885
+ setVisibleSegments(segments, ctx);
1886
+ break;
1887
+ case "hide":
1888
+ setVisibleSegments(
1889
+ visibleSegments.filter((segment) => !segments.includes(segment)),
1890
+ ctx,
1891
+ );
1892
+ break;
1893
+ case "show":
1894
+ setVisibleSegments([...visibleSegments, ...segments], ctx);
1895
+ break;
1896
+ default:
1897
+ ctx.ui.notify(
1898
+ "Usage: /bar [config] or /bar segments [list|all|none|only <segments>|show <segments>|hide <segments>]",
1899
+ "warning",
1900
+ );
1901
+ return;
1902
+ }
1903
+
1904
+ ctx.ui.notify(`pi-bar footer: ${describeSegments(visibleSegments)}`, "info");
1905
+ return;
1906
+ }
1907
+
1908
+ if ((section === "status" || section === "statuses") && !action) {
1731
1909
  await openStatusConfigurator(ctx);
1732
1910
  return;
1733
1911
  }
@@ -1787,7 +1965,7 @@ export default function (pi: ExtensionAPI) {
1787
1965
  }
1788
1966
 
1789
1967
  ctx.ui.notify(
1790
- "Usage: /bar status [list|all|none|only <keys>|show <keys>|hide <keys>]",
1968
+ "Usage: /bar [config] or /bar segments [list|all|none|only <segments>|show <segments>|hide <segments>] or /bar status [list|all|none|only <keys>|show <keys>|hide <keys>]",
1791
1969
  "warning",
1792
1970
  );
1793
1971
  },
@@ -1797,37 +1975,39 @@ export default function (pi: ExtensionAPI) {
1797
1975
  pi.on("thinking_level_select", async () => refresh());
1798
1976
  pi.on("turn_end", async () => refresh());
1799
1977
  pi.on("before_agent_start", async (event, ctx) => {
1800
- progress.recordUserMessage(ctx, event.prompt);
1978
+ if (visibleSegments.includes("progress")) progress.recordUserMessage(ctx, event.prompt);
1801
1979
  });
1802
1980
  pi.on("message_update", async (event, ctx) => {
1803
- progress.recordAssistantUpdate(ctx, event.message);
1981
+ if (visibleSegments.includes("progress")) progress.recordAssistantUpdate(ctx, event.message);
1804
1982
  });
1805
1983
  pi.on("tool_call", async (event, ctx) => {
1806
- progress.recordToolCall(ctx, event);
1984
+ if (visibleSegments.includes("progress")) progress.recordToolCall(ctx, event);
1807
1985
  });
1808
1986
  pi.on("tool_result", async (event, ctx) => {
1809
- progress.recordToolResult(ctx, event);
1987
+ if (visibleSegments.includes("progress")) progress.recordToolResult(ctx, event);
1810
1988
  });
1811
1989
  pi.on("message_end", async (event, ctx) => {
1812
- progress.recordMessageEnd(ctx, event.message);
1990
+ if (visibleSegments.includes("progress")) progress.recordMessageEnd(ctx, event.message);
1813
1991
  refresh();
1814
1992
  });
1815
1993
  pi.on("session_before_tree", async () => {
1816
1994
  progress.shutdown();
1817
1995
  });
1818
1996
  pi.on("session_tree", async (_event, ctx) => {
1819
- progress.startSession(ctx.cwd);
1997
+ if (visibleSegments.includes("progress")) progress.startSession(ctx.cwd);
1998
+ else progress.shutdown();
1820
1999
  restoreStatusFilter(ctx);
1821
2000
  refresh();
1822
2001
  });
1823
2002
 
1824
2003
  pi.on("session_start", async (_event, ctx) => {
1825
- progress.startSession(ctx.cwd);
2004
+ visibleSegments = readGlobalSegments() ?? DEFAULT_SEGMENTS;
2005
+ if (visibleSegments.includes("progress")) progress.startSession(ctx.cwd);
2006
+ else progress.shutdown();
1826
2007
  restoreStatusFilter(ctx);
1827
2008
 
1828
2009
  if (!ctx.hasUI) return;
1829
2010
 
1830
- const visibleSegments = parseSegments();
1831
2011
  const { warningThreshold, errorThreshold } = parseThresholds();
1832
2012
 
1833
2013
  ctx.ui.setFooter((tui, theme, footerData) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-bar",
3
- "version": "0.3.31",
3
+ "version": "0.3.33",
4
4
  "description": "Pi footer/statusline showing active model, thinking level, context pressure, live progress updates, and extension statuses.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -14,8 +14,7 @@
14
14
  "thinking",
15
15
  "context",
16
16
  "context-window",
17
- "progress",
18
- "tldr"
17
+ "progress"
19
18
  ],
20
19
  "license": "MIT",
21
20
  "repository": {
@@ -52,6 +51,6 @@
52
51
  "extensions": [
53
52
  "./extensions/status-footer.ts"
54
53
  ],
55
- "image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.31/assets/screenshot-yellow.png"
54
+ "image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.33/assets/screenshot-yellow.png"
56
55
  }
57
56
  }