pi-bar 0.3.32 → 0.3.34
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 +25 -12
- package/extensions/status-footer.ts +288 -26
- package/package.json +2 -2
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
|
-

|
|
13
|
+

|
|
14
|
+

|
|
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
|
|
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
|
|
40
|
+
pi-bar works out of the box. Run `/bar` inside pi to choose which footer segments and extension statuses are shown:
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
```text
|
|
43
|
+
/bar
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Toggle `Model`, `Thinking level`, `Context usage`, `Progress update`, and `Extension statuses` between `shown` and `hidden`. If other extensions have published status badges, `/bar` also shows fine-grained `Status: <key>` rows plus a `New extension statuses` default. 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.
|
|
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` or `/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.
|
|
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
|
|
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"
|
|
@@ -110,6 +114,20 @@ const DEFAULT_SEGMENTS: SegmentName[] = [
|
|
|
110
114
|
"progress",
|
|
111
115
|
"extensions",
|
|
112
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
|
+
};
|
|
113
131
|
const DEFAULT_WARNING_THRESHOLD = 70;
|
|
114
132
|
const DEFAULT_ERROR_THRESHOLD = 90;
|
|
115
133
|
|
|
@@ -166,6 +184,10 @@ function contextColor(
|
|
|
166
184
|
return "success";
|
|
167
185
|
}
|
|
168
186
|
|
|
187
|
+
function isSegmentName(value: string): value is SegmentName {
|
|
188
|
+
return (ALL_SEGMENTS as readonly string[]).includes(value);
|
|
189
|
+
}
|
|
190
|
+
|
|
169
191
|
function parseSegments(): SegmentName[] {
|
|
170
192
|
const raw = process.env.PI_BAR_SHOW;
|
|
171
193
|
if (!raw) return DEFAULT_SEGMENTS;
|
|
@@ -173,9 +195,7 @@ function parseSegments(): SegmentName[] {
|
|
|
173
195
|
const requested = raw
|
|
174
196
|
.split(",")
|
|
175
197
|
.map((segment) => segment.trim().toLowerCase())
|
|
176
|
-
.filter(
|
|
177
|
-
["model", "thinking", "context", "progress", "extensions"].includes(segment),
|
|
178
|
-
);
|
|
198
|
+
.filter(isSegmentName);
|
|
179
199
|
|
|
180
200
|
return requested.length > 0 ? requested : DEFAULT_SEGMENTS;
|
|
181
201
|
}
|
|
@@ -1523,6 +1543,18 @@ function serializeStatusFilter(filter: StatusFilter): SerializedStatusFilter {
|
|
|
1523
1543
|
return { mode: "all", hidden: Array.from(filter.hidden).sort() };
|
|
1524
1544
|
}
|
|
1525
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
|
+
|
|
1526
1558
|
function parseSerializedStatusFilter(value: unknown): StatusFilter | null {
|
|
1527
1559
|
if (!value || typeof value !== "object") return null;
|
|
1528
1560
|
const data = value as Partial<SerializedStatusFilter>;
|
|
@@ -1543,6 +1575,18 @@ function splitStatusKeys(raw: string): string[] {
|
|
|
1543
1575
|
.filter(Boolean);
|
|
1544
1576
|
}
|
|
1545
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
|
+
|
|
1546
1590
|
function describeStatusFilter(filter: StatusFilter): string {
|
|
1547
1591
|
if (filter.mode === "only") {
|
|
1548
1592
|
const shown = Array.from(filter.shown).sort();
|
|
@@ -1553,29 +1597,45 @@ function describeStatusFilter(filter: StatusFilter): string {
|
|
|
1553
1597
|
return hidden.length > 0 ? `showing all except: ${hidden.join(", ")}` : "showing all";
|
|
1554
1598
|
}
|
|
1555
1599
|
|
|
1556
|
-
function
|
|
1600
|
+
function readGlobalConfig(): GlobalBarConfig {
|
|
1557
1601
|
try {
|
|
1558
|
-
const data = JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as
|
|
1559
|
-
|
|
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,
|
|
1560
1607
|
};
|
|
1561
|
-
return parseSerializedStatusFilter(data.statusFilter ?? data);
|
|
1562
1608
|
} catch {
|
|
1563
|
-
return
|
|
1609
|
+
return {};
|
|
1564
1610
|
}
|
|
1565
1611
|
}
|
|
1566
1612
|
|
|
1567
|
-
function
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
);
|
|
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);
|
|
1573
1623
|
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
1574
1624
|
const tmpPath = `${CONFIG_PATH}.${process.pid}.tmp`;
|
|
1575
1625
|
writeFileSync(tmpPath, `${data}\n`, "utf8");
|
|
1576
1626
|
renameSync(tmpPath, CONFIG_PATH);
|
|
1577
1627
|
}
|
|
1578
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
|
+
|
|
1579
1639
|
function getKnownStatusKeys(filter: StatusFilter, seenStatusKeys: Set<string>): string[] {
|
|
1580
1640
|
const keys = new Set(seenStatusKeys);
|
|
1581
1641
|
if (filter.mode === "only") {
|
|
@@ -1589,6 +1649,7 @@ function getKnownStatusKeys(filter: StatusFilter, seenStatusKeys: Set<string>):
|
|
|
1589
1649
|
export default function (pi: ExtensionAPI) {
|
|
1590
1650
|
let requestRender: (() => void) | undefined;
|
|
1591
1651
|
let statusFilter: StatusFilter = { mode: "all", hidden: new Set() };
|
|
1652
|
+
let visibleSegments: SegmentName[] = readGlobalSegments() ?? DEFAULT_SEGMENTS;
|
|
1592
1653
|
const seenStatusKeys = new Set<string>();
|
|
1593
1654
|
const refresh = () => requestRender?.();
|
|
1594
1655
|
const progress = new FooterProgressEngine(refresh);
|
|
@@ -1607,6 +1668,145 @@ export default function (pi: ExtensionAPI) {
|
|
|
1607
1668
|
writeGlobalStatusFilter(statusFilter);
|
|
1608
1669
|
refresh();
|
|
1609
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 knownStatusKeys = getKnownStatusKeys(statusFilter, seenStatusKeys);
|
|
1683
|
+
const segmentVisibility = new Map(
|
|
1684
|
+
ALL_SEGMENTS.map(
|
|
1685
|
+
(segment): [SegmentName, boolean] => [segment, visibleSegments.includes(segment)],
|
|
1686
|
+
),
|
|
1687
|
+
);
|
|
1688
|
+
let futureShown = statusFilter.mode === "all";
|
|
1689
|
+
const statusVisibility = new Map(
|
|
1690
|
+
knownStatusKeys.map((key): [string, boolean] => [
|
|
1691
|
+
key,
|
|
1692
|
+
shouldShowStatus(key, statusFilter),
|
|
1693
|
+
]),
|
|
1694
|
+
);
|
|
1695
|
+
const persistSegmentsFromVisibility = () => {
|
|
1696
|
+
setVisibleSegments(
|
|
1697
|
+
ALL_SEGMENTS.filter((segment) => segmentVisibility.get(segment)),
|
|
1698
|
+
ctx,
|
|
1699
|
+
);
|
|
1700
|
+
};
|
|
1701
|
+
const persistStatusesFromVisibility = () => {
|
|
1702
|
+
if (futureShown) {
|
|
1703
|
+
statusFilter = {
|
|
1704
|
+
mode: "all",
|
|
1705
|
+
hidden: new Set(
|
|
1706
|
+
knownStatusKeys.filter((key) => !statusVisibility.get(key)),
|
|
1707
|
+
),
|
|
1708
|
+
};
|
|
1709
|
+
} else {
|
|
1710
|
+
statusFilter = {
|
|
1711
|
+
mode: "only",
|
|
1712
|
+
shown: new Set(
|
|
1713
|
+
knownStatusKeys.filter((key) => statusVisibility.get(key)),
|
|
1714
|
+
),
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
persistStatusFilter();
|
|
1718
|
+
};
|
|
1719
|
+
|
|
1720
|
+
const segmentItems: SettingItem[] = ALL_SEGMENTS.map((segment): SettingItem => ({
|
|
1721
|
+
id: `segment:${segment}`,
|
|
1722
|
+
label: SEGMENT_LABELS[segment],
|
|
1723
|
+
description: "Footer segment visibility",
|
|
1724
|
+
currentValue: segmentVisibility.get(segment) ? "shown" : "hidden",
|
|
1725
|
+
values: ["shown", "hidden"],
|
|
1726
|
+
}));
|
|
1727
|
+
const statusItems: SettingItem[] = knownStatusKeys.length > 0
|
|
1728
|
+
? [
|
|
1729
|
+
{
|
|
1730
|
+
id: "status:__future",
|
|
1731
|
+
label: "New extension statuses",
|
|
1732
|
+
description: "Default visibility for status keys discovered later",
|
|
1733
|
+
currentValue: futureShown ? "shown" : "hidden",
|
|
1734
|
+
values: ["shown", "hidden"],
|
|
1735
|
+
},
|
|
1736
|
+
...knownStatusKeys.map((key): SettingItem => ({
|
|
1737
|
+
id: `status:${key}`,
|
|
1738
|
+
label: `Status: ${key}`,
|
|
1739
|
+
description: "Extension status visibility",
|
|
1740
|
+
currentValue: statusVisibility.get(key) ? "shown" : "hidden",
|
|
1741
|
+
values: ["shown", "hidden"],
|
|
1742
|
+
})),
|
|
1743
|
+
]
|
|
1744
|
+
: [];
|
|
1745
|
+
const items: SettingItem[] = [...segmentItems, ...statusItems];
|
|
1746
|
+
|
|
1747
|
+
const container = new Container();
|
|
1748
|
+
container.addChild(
|
|
1749
|
+
new (class {
|
|
1750
|
+
render(_width: number) {
|
|
1751
|
+
return [
|
|
1752
|
+
theme.fg("accent", theme.bold("pi-bar visibility")),
|
|
1753
|
+
theme.fg(
|
|
1754
|
+
"dim",
|
|
1755
|
+
knownStatusKeys.length > 0
|
|
1756
|
+
? "Footer segments + extension statuses · Enter/Space toggles · Esc closes"
|
|
1757
|
+
: "Footer segments · no extension statuses seen yet · Esc closes",
|
|
1758
|
+
),
|
|
1759
|
+
"",
|
|
1760
|
+
];
|
|
1761
|
+
}
|
|
1762
|
+
invalidate() {}
|
|
1763
|
+
})(),
|
|
1764
|
+
);
|
|
1765
|
+
|
|
1766
|
+
const settingsList = new SettingsList(
|
|
1767
|
+
items,
|
|
1768
|
+
Math.min(items.length + 2, 18),
|
|
1769
|
+
getSettingsListTheme(),
|
|
1770
|
+
(id, newValue) => {
|
|
1771
|
+
if (id.startsWith("segment:")) {
|
|
1772
|
+
const segment = id.slice("segment:".length);
|
|
1773
|
+
if (!isSegmentName(segment)) return;
|
|
1774
|
+
segmentVisibility.set(segment, newValue === "shown");
|
|
1775
|
+
persistSegmentsFromVisibility();
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
if (id === "status:__future") {
|
|
1780
|
+
futureShown = newValue === "shown";
|
|
1781
|
+
persistStatusesFromVisibility();
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
if (id.startsWith("status:")) {
|
|
1786
|
+
statusVisibility.set(id.slice("status:".length), newValue === "shown");
|
|
1787
|
+
persistStatusesFromVisibility();
|
|
1788
|
+
}
|
|
1789
|
+
},
|
|
1790
|
+
() => done(undefined),
|
|
1791
|
+
{ enableSearch: true },
|
|
1792
|
+
);
|
|
1793
|
+
|
|
1794
|
+
container.addChild(settingsList);
|
|
1795
|
+
|
|
1796
|
+
return {
|
|
1797
|
+
render(width: number) {
|
|
1798
|
+
return container.render(width);
|
|
1799
|
+
},
|
|
1800
|
+
invalidate() {
|
|
1801
|
+
container.invalidate();
|
|
1802
|
+
},
|
|
1803
|
+
handleInput(data: string) {
|
|
1804
|
+
settingsList.handleInput?.(data);
|
|
1805
|
+
tui.requestRender();
|
|
1806
|
+
},
|
|
1807
|
+
};
|
|
1808
|
+
});
|
|
1809
|
+
};
|
|
1610
1810
|
const openStatusConfigurator = async (ctx: ExtensionContext) => {
|
|
1611
1811
|
const knownStatusKeys = getKnownStatusKeys(statusFilter, seenStatusKeys);
|
|
1612
1812
|
if (knownStatusKeys.length === 0) {
|
|
@@ -1706,10 +1906,70 @@ export default function (pi: ExtensionAPI) {
|
|
|
1706
1906
|
};
|
|
1707
1907
|
|
|
1708
1908
|
pi.registerCommand("bar", {
|
|
1709
|
-
description: "Configure pi-bar footer
|
|
1909
|
+
description: "Configure pi-bar footer visibility",
|
|
1710
1910
|
handler: async (args, ctx) => {
|
|
1711
1911
|
const [section, action, ...rest] = args.trim().split(/\s+/).filter(Boolean);
|
|
1712
|
-
if (!section ||
|
|
1912
|
+
if (!section || section === "config" || section === "configure" || section === "edit") {
|
|
1913
|
+
await openSegmentConfigurator(ctx);
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
if (section === "list" || section === "ls") {
|
|
1917
|
+
ctx.ui.notify(`pi-bar footer: ${describeSegments(visibleSegments)}`, "info");
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
if (section === "segment" || section === "segments" || section === "footer") {
|
|
1922
|
+
const segments = splitSegmentNames(rest.join(" "));
|
|
1923
|
+
if ((action === "only" || action === "show" || action === "hide") && segments.length === 0) {
|
|
1924
|
+
ctx.ui.notify(
|
|
1925
|
+
`Segments: ${ALL_SEGMENTS.join(", ")}`,
|
|
1926
|
+
"warning",
|
|
1927
|
+
);
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
switch (action) {
|
|
1932
|
+
case undefined:
|
|
1933
|
+
case "config":
|
|
1934
|
+
case "configure":
|
|
1935
|
+
case "edit":
|
|
1936
|
+
await openSegmentConfigurator(ctx);
|
|
1937
|
+
return;
|
|
1938
|
+
case "list":
|
|
1939
|
+
case "ls":
|
|
1940
|
+
ctx.ui.notify(`pi-bar footer: ${describeSegments(visibleSegments)}`, "info");
|
|
1941
|
+
return;
|
|
1942
|
+
case "all":
|
|
1943
|
+
setVisibleSegments(ALL_SEGMENTS, ctx);
|
|
1944
|
+
break;
|
|
1945
|
+
case "none":
|
|
1946
|
+
setVisibleSegments([], ctx);
|
|
1947
|
+
break;
|
|
1948
|
+
case "only":
|
|
1949
|
+
setVisibleSegments(segments, ctx);
|
|
1950
|
+
break;
|
|
1951
|
+
case "hide":
|
|
1952
|
+
setVisibleSegments(
|
|
1953
|
+
visibleSegments.filter((segment) => !segments.includes(segment)),
|
|
1954
|
+
ctx,
|
|
1955
|
+
);
|
|
1956
|
+
break;
|
|
1957
|
+
case "show":
|
|
1958
|
+
setVisibleSegments([...visibleSegments, ...segments], ctx);
|
|
1959
|
+
break;
|
|
1960
|
+
default:
|
|
1961
|
+
ctx.ui.notify(
|
|
1962
|
+
"Usage: /bar [config] or /bar segments [list|all|none|only <segments>|show <segments>|hide <segments>]",
|
|
1963
|
+
"warning",
|
|
1964
|
+
);
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
ctx.ui.notify(`pi-bar footer: ${describeSegments(visibleSegments)}`, "info");
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
if ((section === "status" || section === "statuses") && !action) {
|
|
1713
1973
|
await openStatusConfigurator(ctx);
|
|
1714
1974
|
return;
|
|
1715
1975
|
}
|
|
@@ -1769,7 +2029,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1769
2029
|
}
|
|
1770
2030
|
|
|
1771
2031
|
ctx.ui.notify(
|
|
1772
|
-
"Usage: /bar status [list|all|none|only <keys>|show <keys>|hide <keys>]",
|
|
2032
|
+
"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>]",
|
|
1773
2033
|
"warning",
|
|
1774
2034
|
);
|
|
1775
2035
|
},
|
|
@@ -1779,37 +2039,39 @@ export default function (pi: ExtensionAPI) {
|
|
|
1779
2039
|
pi.on("thinking_level_select", async () => refresh());
|
|
1780
2040
|
pi.on("turn_end", async () => refresh());
|
|
1781
2041
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
1782
|
-
progress.recordUserMessage(ctx, event.prompt);
|
|
2042
|
+
if (visibleSegments.includes("progress")) progress.recordUserMessage(ctx, event.prompt);
|
|
1783
2043
|
});
|
|
1784
2044
|
pi.on("message_update", async (event, ctx) => {
|
|
1785
|
-
progress.recordAssistantUpdate(ctx, event.message);
|
|
2045
|
+
if (visibleSegments.includes("progress")) progress.recordAssistantUpdate(ctx, event.message);
|
|
1786
2046
|
});
|
|
1787
2047
|
pi.on("tool_call", async (event, ctx) => {
|
|
1788
|
-
progress.recordToolCall(ctx, event);
|
|
2048
|
+
if (visibleSegments.includes("progress")) progress.recordToolCall(ctx, event);
|
|
1789
2049
|
});
|
|
1790
2050
|
pi.on("tool_result", async (event, ctx) => {
|
|
1791
|
-
progress.recordToolResult(ctx, event);
|
|
2051
|
+
if (visibleSegments.includes("progress")) progress.recordToolResult(ctx, event);
|
|
1792
2052
|
});
|
|
1793
2053
|
pi.on("message_end", async (event, ctx) => {
|
|
1794
|
-
progress.recordMessageEnd(ctx, event.message);
|
|
2054
|
+
if (visibleSegments.includes("progress")) progress.recordMessageEnd(ctx, event.message);
|
|
1795
2055
|
refresh();
|
|
1796
2056
|
});
|
|
1797
2057
|
pi.on("session_before_tree", async () => {
|
|
1798
2058
|
progress.shutdown();
|
|
1799
2059
|
});
|
|
1800
2060
|
pi.on("session_tree", async (_event, ctx) => {
|
|
1801
|
-
progress.startSession(ctx.cwd);
|
|
2061
|
+
if (visibleSegments.includes("progress")) progress.startSession(ctx.cwd);
|
|
2062
|
+
else progress.shutdown();
|
|
1802
2063
|
restoreStatusFilter(ctx);
|
|
1803
2064
|
refresh();
|
|
1804
2065
|
});
|
|
1805
2066
|
|
|
1806
2067
|
pi.on("session_start", async (_event, ctx) => {
|
|
1807
|
-
|
|
2068
|
+
visibleSegments = readGlobalSegments() ?? DEFAULT_SEGMENTS;
|
|
2069
|
+
if (visibleSegments.includes("progress")) progress.startSession(ctx.cwd);
|
|
2070
|
+
else progress.shutdown();
|
|
1808
2071
|
restoreStatusFilter(ctx);
|
|
1809
2072
|
|
|
1810
2073
|
if (!ctx.hasUI) return;
|
|
1811
2074
|
|
|
1812
|
-
const visibleSegments = parseSegments();
|
|
1813
2075
|
const { warningThreshold, errorThreshold } = parseThresholds();
|
|
1814
2076
|
|
|
1815
2077
|
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.
|
|
3
|
+
"version": "0.3.34",
|
|
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": [
|
|
@@ -51,6 +51,6 @@
|
|
|
51
51
|
"extensions": [
|
|
52
52
|
"./extensions/status-footer.ts"
|
|
53
53
|
],
|
|
54
|
-
"image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.
|
|
54
|
+
"image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.34/assets/screenshot-yellow.png"
|
|
55
55
|
}
|
|
56
56
|
}
|