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 +25 -12
- package/extensions/status-footer.ts +227 -47
- package/package.json +3 -4
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 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`. 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 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"
|
|
@@ -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
|
-
.
|
|
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
|
|
229
|
-
|
|
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
|
-
|
|
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
|
|
1600
|
+
function readGlobalConfig(): GlobalBarConfig {
|
|
1575
1601
|
try {
|
|
1576
|
-
const data = JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as
|
|
1577
|
-
|
|
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
|
|
1609
|
+
return {};
|
|
1582
1610
|
}
|
|
1583
1611
|
}
|
|
1584
1612
|
|
|
1585
|
-
function
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
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
|
|
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 ||
|
|
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
|
-
|
|
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.
|
|
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.
|
|
54
|
+
"image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.33/assets/screenshot-yellow.png"
|
|
56
55
|
}
|
|
57
56
|
}
|