pi-bar 0.3.45 → 0.3.47
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 +3 -3
- package/extensions/status-footer.ts +60 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
**Never accidentally run Opus on a typo again.** pi-bar keeps your model, thinking level, context pressure, a live progress update, and any extension statuses visible in pi's footer.
|
|
7
7
|
|
|
8
8
|
```text
|
|
9
|
-
claude-opus-4.7 ❯
|
|
9
|
+
claude-opus-4.7 ❯ med ❯ 2.6% / 1.0M ❯ Reviewing package structure ❯ Plan active ❯ Queue: 2
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|

|
|
@@ -106,7 +106,7 @@ Enable the optional `cwd` segment to distinguish projects and sessions:
|
|
|
106
106
|
Or set startup segments with `PI_BAR_SHOW=model,thinking,context,cwd,progress,extensions`.
|
|
107
107
|
|
|
108
108
|
```text
|
|
109
|
-
claude-opus-4.7 ❯
|
|
109
|
+
claude-opus-4.7 ❯ med ❯ 2.6% / 1.0M ❯ ~/projects/pi-bar
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
Your home directory becomes `~`. Long paths omit middle directories, retaining trailing directory names where possible. The segment is capped at 36 terminal columns, including wide Unicode characters. Override the cap before starting pi:
|
|
@@ -148,7 +148,7 @@ Enable any of the optional metrics through `/bar` or the quick visibility comman
|
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
```text
|
|
151
|
-
claude-opus-4.7 ❯
|
|
151
|
+
claude-opus-4.7 ❯ med ❯ 2.6% / 1.0M ❯ CH:84% ❯ ≈$0.123 ❯ ↑12k ↓3k
|
|
152
152
|
```
|
|
153
153
|
|
|
154
154
|
| Segment | Meaning |
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* pi-bar — footer / statusline extension.
|
|
3
3
|
*
|
|
4
4
|
* Replaces pi's built-in footer with left-aligned segments:
|
|
5
|
-
* <model> ❯
|
|
5
|
+
* <model> ❯ <level> ❯ <context% / window> ❯ [metrics] ❯ [cwd] ❯ <progress> ❯ <extensions>
|
|
6
6
|
*
|
|
7
7
|
* Example:
|
|
8
|
-
* claude-opus-4.7 ❯
|
|
8
|
+
* claude-opus-4.7 ❯ med ❯ 2.6% / 1.0M ❯ Reviewing package structure
|
|
9
9
|
*
|
|
10
10
|
* Re-renders on model change, thinking-level change, status updates, and after
|
|
11
11
|
* each assistant turn so context usage stays current.
|
|
@@ -613,6 +613,7 @@ function tailText(text: string, maxChars: number): string {
|
|
|
613
613
|
}
|
|
614
614
|
|
|
615
615
|
function compactText(text: string): string {
|
|
616
|
+
if (typeof text !== "string") return "";
|
|
616
617
|
return text.replace(ANSI_PATTERN, "").replace(/\s+/g, " ").trim();
|
|
617
618
|
}
|
|
618
619
|
|
|
@@ -749,6 +750,16 @@ function extractTextContent(content: readonly unknown[] | undefined): string | u
|
|
|
749
750
|
return compacted.length > 0 ? compacted : undefined;
|
|
750
751
|
}
|
|
751
752
|
|
|
753
|
+
function customMessageText(message: unknown): string | undefined {
|
|
754
|
+
if (!message || typeof message !== "object") return undefined;
|
|
755
|
+
const record = message as Record<string, unknown>;
|
|
756
|
+
if (typeof record.content === "string") {
|
|
757
|
+
const compacted = compactText(record.content);
|
|
758
|
+
return compacted.length > 0 ? compacted : undefined;
|
|
759
|
+
}
|
|
760
|
+
return extractTextContent(record.content as readonly unknown[] | undefined);
|
|
761
|
+
}
|
|
762
|
+
|
|
752
763
|
class ProgressFactCollector {
|
|
753
764
|
private nextIndex = 1;
|
|
754
765
|
private readonly activities: ProgressActivity[] = [];
|
|
@@ -766,6 +777,18 @@ class ProgressFactCollector {
|
|
|
766
777
|
);
|
|
767
778
|
}
|
|
768
779
|
|
|
780
|
+
recordCustomMessage(message: unknown): ProgressActivity | undefined {
|
|
781
|
+
const text = customMessageText(message);
|
|
782
|
+
if (!text) return undefined;
|
|
783
|
+
const record = (message ?? {}) as { customType?: unknown };
|
|
784
|
+
const customType = typeof record.customType === "string" ? record.customType : "custom";
|
|
785
|
+
return this.addActivity(
|
|
786
|
+
"user_message",
|
|
787
|
+
"immediate",
|
|
788
|
+
`custom (${customType}): ${truncateText(text, MAX_USER_TEXT_CHARS)}`,
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
|
|
769
792
|
recordAssistantUpdate(message: unknown): ProgressActivity | undefined {
|
|
770
793
|
if (!message || typeof message !== "object") return undefined;
|
|
771
794
|
const record = message as Record<string, unknown>;
|
|
@@ -957,7 +980,7 @@ class FooterProgressEngine {
|
|
|
957
980
|
this.startFreshRun();
|
|
958
981
|
}
|
|
959
982
|
|
|
960
|
-
|
|
983
|
+
beginUserTurn(ctx: ExtensionContext): void {
|
|
961
984
|
// A new user turn replaces the entire visible progress update context, so wipe both
|
|
962
985
|
// the rendered text and the prior-turn checkpoint context that feeds the
|
|
963
986
|
// model. Carrying old checkpoints biased the next turn's phrasing toward
|
|
@@ -967,9 +990,24 @@ class FooterProgressEngine {
|
|
|
967
990
|
this.acceptedCheckpoints.splice(0);
|
|
968
991
|
this.latestAcceptedActivityIndex = 0;
|
|
969
992
|
this.requestRender();
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
recordUserMessage(ctx: ExtensionContext, prompt: string): void {
|
|
996
|
+
this.beginUserTurn(ctx);
|
|
970
997
|
this.enqueue(ctx, this.facts.recordUserMessage(prompt));
|
|
971
998
|
}
|
|
972
999
|
|
|
1000
|
+
// Custom messages (e.g. subagent results handed back to the main session via
|
|
1001
|
+
// sendMessage with triggerTurn) also start a run, so reset progress the same
|
|
1002
|
+
// way a user turn does. A text-less custom message (empty or image-only
|
|
1003
|
+
// content) still resets the turn — a blank footer is preferable to stale
|
|
1004
|
+
// progress from the previous run — it just records no activity.
|
|
1005
|
+
recordCustomMessage(ctx: ExtensionContext, message: unknown): void {
|
|
1006
|
+
this.beginUserTurn(ctx);
|
|
1007
|
+
const activity = this.facts.recordCustomMessage(message);
|
|
1008
|
+
if (activity) this.enqueue(ctx, activity);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
973
1011
|
recordAssistantUpdate(ctx: ExtensionContext, message: unknown): void {
|
|
974
1012
|
const activity = this.facts.recordAssistantUpdate(message);
|
|
975
1013
|
if (activity) this.enqueue(ctx, activity);
|
|
@@ -2465,7 +2503,23 @@ export default function (pi: ExtensionAPI) {
|
|
|
2465
2503
|
pi.on("agent_end", async (_event, ctx) => { syncUsage(ctx); refresh(); });
|
|
2466
2504
|
pi.on("session_compact", async (_event, ctx) => { syncUsage(ctx); refresh(); });
|
|
2467
2505
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
2468
|
-
if (visibleSegments.includes("progress"))
|
|
2506
|
+
if (!visibleSegments.includes("progress")) return;
|
|
2507
|
+
// Newer pi versions fire before_agent_start as a discriminated union: runs
|
|
2508
|
+
// started via sendMessage(..., { triggerTurn: true }) (e.g. subagent results
|
|
2509
|
+
// handed back to the main session) carry a custom `message` instead of a
|
|
2510
|
+
// `prompt`. Handle both shapes so custom-message runs do not crash.
|
|
2511
|
+
const record = event as unknown as { messageType?: unknown; message?: unknown; prompt?: string };
|
|
2512
|
+
if (record.messageType === "custom") {
|
|
2513
|
+
progress.recordCustomMessage(ctx, record.message);
|
|
2514
|
+
return;
|
|
2515
|
+
}
|
|
2516
|
+
if (typeof record.prompt === "string") {
|
|
2517
|
+
progress.recordUserMessage(ctx, record.prompt);
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
// Future event variants without a prompt still start a fresh run; they just
|
|
2521
|
+
// have no user text to record.
|
|
2522
|
+
progress.beginUserTurn(ctx);
|
|
2469
2523
|
});
|
|
2470
2524
|
pi.on("message_update", async (event, ctx) => {
|
|
2471
2525
|
if (visibleSegments.includes("progress")) progress.recordAssistantUpdate(ctx, event.message);
|
|
@@ -2557,8 +2611,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
2557
2611
|
alternatives: showProvider ? [theme.fg("accent", formatModelName(ctx.model))] : [],
|
|
2558
2612
|
},
|
|
2559
2613
|
thinking: {
|
|
2560
|
-
text: theme.fg(thinkingColor(thinkingLevel),
|
|
2561
|
-
alternatives: [theme.fg(thinkingColor(thinkingLevel),
|
|
2614
|
+
text: theme.fg(thinkingColor(thinkingLevel), thinkingLevel),
|
|
2615
|
+
alternatives: [theme.fg(thinkingColor(thinkingLevel), shortThinking)],
|
|
2562
2616
|
},
|
|
2563
2617
|
context: {
|
|
2564
2618
|
text: theme.fg(contextSegmentColor, contextText),
|
package/package.json
CHANGED