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 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 ❯ think:med ❯ 2.6% / 1.0M ❯ Reviewing package structure ❯ Plan active ❯ Queue: 2
9
+ claude-opus-4.7 ❯ med ❯ 2.6% / 1.0M ❯ Reviewing package structure ❯ Plan active ❯ Queue: 2
10
10
  ```
11
11
 
12
12
  ![pi-bar with low context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.38/assets/screenshot-green.png)
@@ -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 ❯ think:med ❯ 2.6% / 1.0M ❯ ~/projects/pi-bar
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 ❯ think:med ❯ 2.6% / 1.0M ❯ CH:84% ❯ ≈$0.123 ❯ ↑12k ↓3k
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> ❯ think:<level> ❯ <context% / window> ❯ [metrics] ❯ [cwd] ❯ <progress> ❯ <extensions>
5
+ * <model> ❯ <level> ❯ <context% / window> ❯ [metrics] ❯ [cwd] ❯ <progress> ❯ <extensions>
6
6
  *
7
7
  * Example:
8
- * claude-opus-4.7 ❯ think:med ❯ 2.6% / 1.0M ❯ Reviewing package structure
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
- recordUserMessage(ctx: ExtensionContext, prompt: string): void {
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")) progress.recordUserMessage(ctx, event.prompt);
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), `think:${thinkingLevel}`),
2561
- alternatives: [theme.fg(thinkingColor(thinkingLevel), `think:${shortThinking}`)],
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-bar",
3
- "version": "0.3.45",
3
+ "version": "0.3.47",
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": [