pi-bar 0.3.14 → 0.3.17
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 -26
- package/extensions/status-footer.ts +171 -92
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
**Never accidentally run Opus on a typo again.** pi-bar keeps your model, thinking level, context pressure, extension status, and a live one-line TLDR visible in pi's footer.
|
|
7
7
|
|
|
8
8
|
```text
|
|
9
|
-
|
|
9
|
+
claude-opus-4.7 ❯ think:med ❯ 2.6% / 1.0M ❯ Inspecting package structure ❯ plan:active
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-

|
|
13
13
|
|
|
14
14
|
## Why use it?
|
|
15
15
|
|
|
@@ -48,7 +48,7 @@ Allowed segments are `model`, `thinking`, `context`, `tldr`, and `extensions`. T
|
|
|
48
48
|
|
|
49
49
|
### Configure live TLDR
|
|
50
50
|
|
|
51
|
-
pi-bar shows a concise live TLDR of the current task in the footer. It resets when you navigate the session tree so stale summaries do not follow you across branches. Set `PI_BAR_SHOW` without `tldr` to hide it.
|
|
51
|
+
pi-bar shows a concise live TLDR of the current task in the footer. It generates TLDRs from recent prompt, assistant, and deterministic code-compressed tool facts (for example `bash ... ok`, `grep ... 4 matches`, or `edit file`). It resets when you navigate the session tree so stale summaries do not follow you across branches. Set `PI_BAR_SHOW` without `tldr` to hide it.
|
|
52
52
|
|
|
53
53
|
Override the TLDR model with:
|
|
54
54
|
|
|
@@ -79,29 +79,6 @@ PI_BAR_THRESHOLDS=60,85 pi
|
|
|
79
79
|
|
|
80
80
|
The first number is the warning/yellow threshold. The second number is the danger/red threshold. Defaults are `70,90`.
|
|
81
81
|
|
|
82
|
-
### Change icon style
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
PI_BAR_ICONS=plain pi
|
|
86
|
-
PI_BAR_ICONS=emoji pi
|
|
87
|
-
PI_BAR_ICONS=nerdfont pi
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Supported presets:
|
|
91
|
-
|
|
92
|
-
- `unicode` — default, e.g. `◈ gpt-5.5 ❯ ✦ think:medium ❯ ◷ 42.7% / 272k ❯ Reading files ❯ ✧ plan:active`
|
|
93
|
-
- `plain` — maximum compatibility, e.g. `model:gpt-5.5 | think:medium | ctx:42.7% / 272k | Reading files | ext:plan:active`
|
|
94
|
-
- `emoji` — colorful emoji markers, e.g. `🤖 gpt-5.5 › ✨ think:medium › 🧭 42.7% / 272k › Reading files › 🧩 plan:active`
|
|
95
|
-
- `nerdfont` — icon-font glyphs for terminals configured with a Nerd Font, e.g. ` gpt-5.5 think:medium 42.7% / 272k Reading files plan:active`
|
|
96
|
-
|
|
97
|
-
## Compatibility
|
|
98
|
-
|
|
99
|
-
The default `unicode` preset uses common Unicode symbols that render well in most modern terminals. If your terminal shows boxes or misaligned glyphs, use:
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
PI_BAR_ICONS=plain pi
|
|
103
|
-
```
|
|
104
|
-
|
|
105
82
|
## Pairs well with
|
|
106
83
|
|
|
107
84
|
- **[pi-chrome](https://www.npmjs.com/package/pi-chrome)** — give your Pi agent your real, signed-in Chrome. Use pi-bar's red-context threshold as the signal to wrap up long browser scrapes before context overflows.
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* pi-bar — footer/statusline extension.
|
|
3
3
|
*
|
|
4
4
|
* Replaces the built-in footer with left-aligned segments:
|
|
5
|
-
*
|
|
5
|
+
* <model name> ❯ think:<level> ❯ <context% / window> ❯ <tldr> ❯ <extension statuses>
|
|
6
6
|
*
|
|
7
7
|
* Examples:
|
|
8
|
-
*
|
|
8
|
+
* claude-opus-4.7 ❯ think:med ❯ 2.6% / 1.0M
|
|
9
9
|
*
|
|
10
10
|
* Re-renders on model change, thinking-level change, status updates,
|
|
11
11
|
* and after each assistant turn so context usage stays current.
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
* Configuration env vars:
|
|
14
14
|
* PI_BAR_SHOW=model,thinking,context,tldr,extensions
|
|
15
15
|
* PI_BAR_THRESHOLDS=70,90
|
|
16
|
-
* PI_BAR_ICONS=unicode|plain|emoji|nerdfont
|
|
17
16
|
*/
|
|
18
17
|
|
|
19
18
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -35,7 +34,6 @@ import {
|
|
|
35
34
|
} from "@earendil-works/pi-tui";
|
|
36
35
|
|
|
37
36
|
type SegmentName = "model" | "thinking" | "context" | "tldr" | "extensions";
|
|
38
|
-
type IconPreset = "unicode" | "plain" | "emoji" | "nerdfont";
|
|
39
37
|
type StatusFilter =
|
|
40
38
|
| { mode: "all"; hidden: Set<string> }
|
|
41
39
|
| { mode: "only"; shown: Set<string> };
|
|
@@ -76,8 +74,14 @@ type FastModelAuth = {
|
|
|
76
74
|
const STATUS_FILTER_ENTRY_TYPE = "pi-bar-status-filter";
|
|
77
75
|
const SETTINGS_TLDR_KEY = "tldr";
|
|
78
76
|
const SETTINGS_BAR_KEY = "bar";
|
|
79
|
-
const MAX_ACTIVITY_TEXT_CHARS =
|
|
77
|
+
const MAX_ACTIVITY_TEXT_CHARS = 800;
|
|
78
|
+
const MAX_USER_TEXT_CHARS = 700;
|
|
79
|
+
const MAX_ASSISTANT_UPDATE_CHARS = 500;
|
|
80
|
+
const MAX_TOOL_RESULT_OK_CHARS = 160;
|
|
81
|
+
const MAX_TOOL_RESULT_ERROR_CHARS = 320;
|
|
82
|
+
const MAX_FINAL_TEXT_CHARS = 700;
|
|
80
83
|
const MAX_RETAINED_RAW_ACTIVITIES = 128;
|
|
84
|
+
const ANSI_PATTERN = /\x1B\[[0-?]*[ -/]*[@-~]/g;
|
|
81
85
|
const MAX_CONTEXT_CHECKPOINTS = 8;
|
|
82
86
|
const TLDR_MAX_TOKENS = 120;
|
|
83
87
|
const TLDR_REQUEST_TIMEOUT_MS = 2_000;
|
|
@@ -96,45 +100,7 @@ const DEFAULT_SEGMENTS: SegmentName[] = [
|
|
|
96
100
|
const DEFAULT_WARNING_THRESHOLD = 70;
|
|
97
101
|
const DEFAULT_ERROR_THRESHOLD = 90;
|
|
98
102
|
|
|
99
|
-
const
|
|
100
|
-
IconPreset,
|
|
101
|
-
{
|
|
102
|
-
model: string;
|
|
103
|
-
thinking: string;
|
|
104
|
-
context: string;
|
|
105
|
-
extensions: string;
|
|
106
|
-
separator: string;
|
|
107
|
-
}
|
|
108
|
-
> = {
|
|
109
|
-
unicode: {
|
|
110
|
-
model: "◈",
|
|
111
|
-
thinking: "✦",
|
|
112
|
-
context: "◷",
|
|
113
|
-
extensions: "✧",
|
|
114
|
-
separator: "❯",
|
|
115
|
-
},
|
|
116
|
-
plain: {
|
|
117
|
-
model: "model",
|
|
118
|
-
thinking: "think",
|
|
119
|
-
context: "ctx",
|
|
120
|
-
extensions: "ext",
|
|
121
|
-
separator: "|",
|
|
122
|
-
},
|
|
123
|
-
emoji: {
|
|
124
|
-
model: "🤖",
|
|
125
|
-
thinking: "✨",
|
|
126
|
-
context: "🧭",
|
|
127
|
-
extensions: "🧩",
|
|
128
|
-
separator: "›",
|
|
129
|
-
},
|
|
130
|
-
nerdfont: {
|
|
131
|
-
model: "",
|
|
132
|
-
thinking: "",
|
|
133
|
-
context: "",
|
|
134
|
-
extensions: "",
|
|
135
|
-
separator: "",
|
|
136
|
-
},
|
|
137
|
-
};
|
|
103
|
+
const SEGMENT_SEPARATOR = "❯";
|
|
138
104
|
|
|
139
105
|
function formatTokens(n: number): string {
|
|
140
106
|
if (n >= 1_000_000) {
|
|
@@ -229,12 +195,6 @@ function parseThresholds(): { warningThreshold: number; errorThreshold: number }
|
|
|
229
195
|
};
|
|
230
196
|
}
|
|
231
197
|
|
|
232
|
-
function parseIconPreset(): IconPreset {
|
|
233
|
-
const raw = process.env.PI_BAR_ICONS?.trim().toLowerCase();
|
|
234
|
-
if (raw === "plain" || raw === "emoji" || raw === "nerdfont") return raw;
|
|
235
|
-
return "unicode";
|
|
236
|
-
}
|
|
237
|
-
|
|
238
198
|
function parseTldrModelSpec(value: string): TldrModelPreference | undefined {
|
|
239
199
|
const trimmed = value.trim();
|
|
240
200
|
if (!trimmed || trimmed === "auto") return undefined;
|
|
@@ -324,6 +284,115 @@ function truncateText(text: string, maxChars: number): string {
|
|
|
324
284
|
return `${text.slice(0, maxChars - 1)}…`;
|
|
325
285
|
}
|
|
326
286
|
|
|
287
|
+
function tailText(text: string, maxChars: number): string {
|
|
288
|
+
if (text.length <= maxChars) return text;
|
|
289
|
+
return `…${text.slice(-(maxChars - 1))}`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function compactText(text: string): string {
|
|
293
|
+
return text.replace(ANSI_PATTERN, "").replace(/\s+/g, " ").trim();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function compactValue(value: unknown, maxChars: number): string | undefined {
|
|
297
|
+
if (value === undefined || value === null) return undefined;
|
|
298
|
+
let text: string;
|
|
299
|
+
if (typeof value === "string") {
|
|
300
|
+
text = value;
|
|
301
|
+
} else {
|
|
302
|
+
try {
|
|
303
|
+
text = JSON.stringify(value);
|
|
304
|
+
} catch {
|
|
305
|
+
text = String(value);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return text ? truncateText(compactText(text), maxChars) : undefined;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function compactToolInput(toolName: string, input: Record<string, unknown> | undefined): string {
|
|
312
|
+
if (!input) return toolName;
|
|
313
|
+
|
|
314
|
+
const path = compactValue(input.path ?? input.filePath ?? input.cwd, 120);
|
|
315
|
+
const command = compactValue(input.command, 180);
|
|
316
|
+
const pattern = compactValue(input.pattern ?? input.query, 120);
|
|
317
|
+
const include = compactValue(input.include ?? input.glob, 80);
|
|
318
|
+
|
|
319
|
+
switch (toolName) {
|
|
320
|
+
case "bash":
|
|
321
|
+
return command ? `bash ${command}` : "bash";
|
|
322
|
+
case "read":
|
|
323
|
+
return path ? `read ${path}` : "read";
|
|
324
|
+
case "edit":
|
|
325
|
+
return path ? `edit ${path}` : "edit";
|
|
326
|
+
case "write":
|
|
327
|
+
return path ? `write ${path}` : "write";
|
|
328
|
+
case "grep":
|
|
329
|
+
return ["grep", pattern, path, include ? `include ${include}` : undefined]
|
|
330
|
+
.filter(Boolean)
|
|
331
|
+
.join(" ");
|
|
332
|
+
case "find":
|
|
333
|
+
return ["find", path, pattern].filter(Boolean).join(" ");
|
|
334
|
+
case "ls":
|
|
335
|
+
return path ? `ls ${path}` : "ls";
|
|
336
|
+
default: {
|
|
337
|
+
const args = Object.entries(input)
|
|
338
|
+
.slice(0, 3)
|
|
339
|
+
.map(([key, value]) => {
|
|
340
|
+
const formatted = compactValue(value, 80);
|
|
341
|
+
return formatted ? `${key}=${formatted}` : undefined;
|
|
342
|
+
})
|
|
343
|
+
.filter(Boolean)
|
|
344
|
+
.join(" ");
|
|
345
|
+
return args ? `${toolName} ${args}` : toolName;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function usefulLineCount(text: string): number {
|
|
351
|
+
return text
|
|
352
|
+
.split("\n")
|
|
353
|
+
.map((line) => line.trim())
|
|
354
|
+
.filter(Boolean).length;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function errorSummary(text: string | undefined): string | undefined {
|
|
358
|
+
if (!text) return undefined;
|
|
359
|
+
const compacted = compactText(text);
|
|
360
|
+
const exitMatch = compacted.match(/Command exited with code \d+/);
|
|
361
|
+
if (exitMatch) return truncateText(exitMatch[0], MAX_TOOL_RESULT_ERROR_CHARS);
|
|
362
|
+
return truncateText(compacted, MAX_TOOL_RESULT_ERROR_CHARS);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function summarizeToolResult(
|
|
366
|
+
toolName: string,
|
|
367
|
+
input: Record<string, unknown> | undefined,
|
|
368
|
+
text: string | undefined,
|
|
369
|
+
isError: boolean,
|
|
370
|
+
): string | undefined {
|
|
371
|
+
if (isError) return errorSummary(text);
|
|
372
|
+
|
|
373
|
+
const lineCount = text ? usefulLineCount(text) : 0;
|
|
374
|
+
const path = compactValue(input?.path ?? input?.filePath ?? input?.cwd, 120);
|
|
375
|
+
|
|
376
|
+
switch (toolName) {
|
|
377
|
+
case "bash":
|
|
378
|
+
return undefined;
|
|
379
|
+
case "read":
|
|
380
|
+
return path ? `${lineCount || "file"} lines from ${path}` : undefined;
|
|
381
|
+
case "edit":
|
|
382
|
+
return path ? `edited ${path}` : undefined;
|
|
383
|
+
case "write":
|
|
384
|
+
return path ? `wrote ${path}` : undefined;
|
|
385
|
+
case "grep":
|
|
386
|
+
return lineCount ? `${lineCount} matches` : "no matches";
|
|
387
|
+
case "find":
|
|
388
|
+
return lineCount ? `${lineCount} paths` : "no paths";
|
|
389
|
+
case "ls":
|
|
390
|
+
return lineCount ? `${lineCount} entries` : undefined;
|
|
391
|
+
default:
|
|
392
|
+
return lineCount ? `${lineCount} output lines` : undefined;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
327
396
|
function extractTextContent(content: readonly unknown[] | undefined): string | undefined {
|
|
328
397
|
if (!content) return undefined;
|
|
329
398
|
const text = content
|
|
@@ -336,12 +405,8 @@ function extractTextContent(content: readonly unknown[] | undefined): string | u
|
|
|
336
405
|
})
|
|
337
406
|
.filter((part): part is string => Boolean(part))
|
|
338
407
|
.join("\n");
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
function prefixed(icon: string, text: string, preset: IconPreset): string {
|
|
343
|
-
if (preset === "plain") return `${icon}:${text}`;
|
|
344
|
-
return `${icon} ${text}`;
|
|
408
|
+
const compacted = compactText(text);
|
|
409
|
+
return compacted.length > 0 ? compacted : undefined;
|
|
345
410
|
}
|
|
346
411
|
|
|
347
412
|
class TldrFactCollector {
|
|
@@ -354,7 +419,11 @@ class TldrFactCollector {
|
|
|
354
419
|
}
|
|
355
420
|
|
|
356
421
|
recordUserMessage(prompt: string): TldrActivity {
|
|
357
|
-
return this.addActivity(
|
|
422
|
+
return this.addActivity(
|
|
423
|
+
"user_message",
|
|
424
|
+
"immediate",
|
|
425
|
+
`user: ${truncateText(compactText(prompt), MAX_USER_TEXT_CHARS)}`,
|
|
426
|
+
);
|
|
358
427
|
}
|
|
359
428
|
|
|
360
429
|
recordAssistantUpdate(message: unknown): TldrActivity | undefined {
|
|
@@ -363,27 +432,44 @@ class TldrFactCollector {
|
|
|
363
432
|
if (record.role !== "assistant") return undefined;
|
|
364
433
|
const text = extractTextContent(record.content as readonly unknown[] | undefined);
|
|
365
434
|
return text
|
|
366
|
-
? this.addActivity(
|
|
435
|
+
? this.addActivity(
|
|
436
|
+
"assistant_update",
|
|
437
|
+
"normal",
|
|
438
|
+
`assistant: ${tailText(text, MAX_ASSISTANT_UPDATE_CHARS)}`,
|
|
439
|
+
)
|
|
367
440
|
: undefined;
|
|
368
441
|
}
|
|
369
442
|
|
|
370
|
-
recordToolCall(event: { toolName: string }): TldrActivity {
|
|
371
|
-
return this.addActivity(
|
|
443
|
+
recordToolCall(event: { toolName: string; input?: Record<string, unknown> }): TldrActivity {
|
|
444
|
+
return this.addActivity(
|
|
445
|
+
"tool_call",
|
|
446
|
+
"normal",
|
|
447
|
+
`tool: ${compactToolInput(event.toolName, event.input)}`,
|
|
448
|
+
);
|
|
372
449
|
}
|
|
373
450
|
|
|
374
451
|
recordToolResult(event: {
|
|
375
452
|
toolName: string;
|
|
453
|
+
input?: Record<string, unknown>;
|
|
376
454
|
isError?: boolean;
|
|
377
455
|
content?: readonly unknown[];
|
|
456
|
+
details?: unknown;
|
|
378
457
|
}): TldrActivity {
|
|
379
|
-
const
|
|
380
|
-
const
|
|
458
|
+
const isError = Boolean(event.isError);
|
|
459
|
+
const resultText = summarizeToolResult(
|
|
460
|
+
event.toolName,
|
|
461
|
+
event.input,
|
|
462
|
+
extractTextContent(event.content),
|
|
463
|
+
isError,
|
|
464
|
+
);
|
|
465
|
+
const status = isError ? "error" : "ok";
|
|
466
|
+
const tool = compactToolInput(event.toolName, event.input);
|
|
381
467
|
return this.addActivity(
|
|
382
468
|
"tool_result",
|
|
383
469
|
"normal",
|
|
384
470
|
resultText
|
|
385
|
-
? `
|
|
386
|
-
: `
|
|
471
|
+
? `result: ${tool} ${status}; ${resultText}`
|
|
472
|
+
: `result: ${tool} ${status}`,
|
|
387
473
|
);
|
|
388
474
|
}
|
|
389
475
|
|
|
@@ -399,12 +485,12 @@ class TldrFactCollector {
|
|
|
399
485
|
if (stopReason === "stop") {
|
|
400
486
|
const finalText = extractTextContent(record.content as readonly unknown[] | undefined);
|
|
401
487
|
if (!finalText) return "emptyFinalStop";
|
|
402
|
-
text = `
|
|
488
|
+
text = `final: ${truncateText(finalText, MAX_FINAL_TEXT_CHARS)}`;
|
|
403
489
|
} else if (stopReason) {
|
|
404
|
-
const error = typeof record.errorMessage === "string" ? record.errorMessage : undefined;
|
|
490
|
+
const error = typeof record.errorMessage === "string" ? compactText(record.errorMessage) : undefined;
|
|
405
491
|
text = error
|
|
406
|
-
? `
|
|
407
|
-
: `
|
|
492
|
+
? `final: ${stopReason}; ${truncateText(error, MAX_FINAL_TEXT_CHARS)}`
|
|
493
|
+
: `final: ${stopReason}`;
|
|
408
494
|
}
|
|
409
495
|
|
|
410
496
|
return text
|
|
@@ -501,13 +587,22 @@ class FooterTldrEngine {
|
|
|
501
587
|
if (activity) this.enqueue(ctx, activity);
|
|
502
588
|
}
|
|
503
589
|
|
|
504
|
-
recordToolCall(
|
|
590
|
+
recordToolCall(
|
|
591
|
+
ctx: ExtensionContext,
|
|
592
|
+
event: { toolName: string; input?: Record<string, unknown> },
|
|
593
|
+
): void {
|
|
505
594
|
this.enqueue(ctx, this.facts.recordToolCall(event));
|
|
506
595
|
}
|
|
507
596
|
|
|
508
597
|
recordToolResult(
|
|
509
598
|
ctx: ExtensionContext,
|
|
510
|
-
event: {
|
|
599
|
+
event: {
|
|
600
|
+
toolName: string;
|
|
601
|
+
input?: Record<string, unknown>;
|
|
602
|
+
isError?: boolean;
|
|
603
|
+
content?: readonly unknown[];
|
|
604
|
+
details?: unknown;
|
|
605
|
+
},
|
|
511
606
|
): void {
|
|
512
607
|
this.enqueue(ctx, this.facts.recordToolResult(event));
|
|
513
608
|
}
|
|
@@ -762,7 +857,7 @@ function previousCheckpointLines(checkpoints: readonly TldrCheckpoint[]): string
|
|
|
762
857
|
}
|
|
763
858
|
|
|
764
859
|
function formatRawActivity(activity: TldrActivity): string {
|
|
765
|
-
return `[${activity.index}] ${activity.
|
|
860
|
+
return `[${activity.index}] ${activity.text}`;
|
|
766
861
|
}
|
|
767
862
|
|
|
768
863
|
function shouldShowStatus(key: string, filter: StatusFilter): boolean {
|
|
@@ -1080,8 +1175,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
1080
1175
|
if (!ctx.hasUI) return;
|
|
1081
1176
|
|
|
1082
1177
|
const visibleSegments = parseSegments();
|
|
1083
|
-
const iconPreset = parseIconPreset();
|
|
1084
|
-
const icons = ICON_PRESETS[iconPreset];
|
|
1085
1178
|
const { warningThreshold, errorThreshold } = parseThresholds();
|
|
1086
1179
|
|
|
1087
1180
|
ctx.ui.setFooter((tui, theme, footerData) => {
|
|
@@ -1113,28 +1206,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
1113
1206
|
const tldrText = tldr.text();
|
|
1114
1207
|
|
|
1115
1208
|
const segmentRenderers: Record<SegmentName, string | null> = {
|
|
1116
|
-
model: theme.fg(
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
),
|
|
1120
|
-
thinking: theme.fg(
|
|
1121
|
-
thinkingColor(thinkingLevel),
|
|
1122
|
-
prefixed(icons.thinking, `think:${thinkingLevel}`, iconPreset),
|
|
1123
|
-
),
|
|
1124
|
-
context: theme.fg(
|
|
1125
|
-
contextSegmentColor,
|
|
1126
|
-
prefixed(icons.context, contextText, iconPreset),
|
|
1127
|
-
),
|
|
1209
|
+
model: theme.fg("accent", modelName),
|
|
1210
|
+
thinking: theme.fg(thinkingColor(thinkingLevel), `think:${thinkingLevel}`),
|
|
1211
|
+
context: theme.fg(contextSegmentColor, contextText),
|
|
1128
1212
|
tldr: tldrText ? theme.fg("muted", tldrText) : null,
|
|
1129
|
-
extensions: extensionStatuses
|
|
1130
|
-
? theme.fg(
|
|
1131
|
-
"muted",
|
|
1132
|
-
prefixed(icons.extensions, extensionStatuses, iconPreset),
|
|
1133
|
-
)
|
|
1134
|
-
: null,
|
|
1213
|
+
extensions: extensionStatuses ? theme.fg("muted", extensionStatuses) : null,
|
|
1135
1214
|
};
|
|
1136
1215
|
|
|
1137
|
-
const separator = ` ${theme.fg("dim",
|
|
1216
|
+
const separator = ` ${theme.fg("dim", SEGMENT_SEPARATOR)} `;
|
|
1138
1217
|
const line = visibleSegments
|
|
1139
1218
|
.map((segment) => segmentRenderers[segment])
|
|
1140
1219
|
.filter((segment): segment is string => segment !== null)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-bar",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.17",
|
|
4
4
|
"description": "Pi footer/statusline showing active model, thinking level, context pressure, live TLDR, 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.17/assets/screenshot.png"
|
|
55
55
|
}
|
|
56
56
|
}
|