pi-minimal-footer 0.7.1 → 0.8.0
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/CHANGELOG.md +12 -1
- package/README.md +4 -3
- package/VISION.md +7 -0
- package/extensions/index.ts +17 -18
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-10-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Optional percentage context display, e.g. `24.7%/500k`, enabled with `minFooter.contextAsPercentage`
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Clearer default context counts, e.g. `0.78k/500k`, `1.0k/500k`, and `124k/500k`, with explicit units on both values
|
|
19
|
+
|
|
10
20
|
## [0.7.1] - 2026-10-16
|
|
11
21
|
|
|
12
22
|
### Fixed
|
|
@@ -263,7 +273,8 @@ First npm-ready release.
|
|
|
263
273
|
|
|
264
274
|
- Project scaffold — `extensions/index.ts` with basic footer structure, `package.json` with pi extension manifest, `README.md`, `LICENSE` (MIT)
|
|
265
275
|
|
|
266
|
-
[Unreleased]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.
|
|
276
|
+
[Unreleased]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.8.0...HEAD
|
|
277
|
+
[0.8.0]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.7.1...v0.8.0
|
|
267
278
|
[0.7.1]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.7.0...v0.7.1
|
|
268
279
|
[0.7.0]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.6.0...v0.7.0
|
|
269
280
|
[0.6.0]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.5.3...v0.6.0
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
An opinionated, compact, one-line status bar for [Pi](https://github.com/earendil-works/pi).
|
|
11
11
|
|
|
12
|
-
![Footer preview: ~/git/project main 🧠 Karpathy 🪽 Icarus model ·
|
|
12
|
+
![Footer preview: ~/git/project main 🧠 Karpathy 🪽 Icarus model · 42k/200k · [⣿⣿⣿⣤⠀⠀⠀⠀⠀⠀]↻1d8h](media/preview.png)
|
|
13
13
|
|
|
14
14
|
**Left**
|
|
15
15
|
|
|
@@ -20,7 +20,7 @@ An opinionated, compact, one-line status bar for [Pi](https://github.com/earendi
|
|
|
20
20
|
|
|
21
21
|
- Extension statuses: ` 🧠 Karpathy 🪽 Icarus`
|
|
22
22
|
- Model: `model`
|
|
23
|
-
- Context usage: `
|
|
23
|
+
- Context usage: `42k/200k` (default), or `21.0%/200k` with `contextAsPercentage: true`
|
|
24
24
|
- Subscription usage bar with reset time: `[⣿⣿⣿⣤⠀⠀⠀⠀⠀⠀]↻1d8h`
|
|
25
25
|
|
|
26
26
|
## Install
|
|
@@ -58,6 +58,7 @@ Edit `minFooter` in Pi's agent `settings.json` (normally `~/.pi/agent/settings.j
|
|
|
58
58
|
"showPath": true,
|
|
59
59
|
"showModel": true,
|
|
60
60
|
"showContext": true,
|
|
61
|
+
"contextAsPercentage": false,
|
|
61
62
|
"powerlineSeparator": true,
|
|
62
63
|
"gitRefreshSeconds": 91,
|
|
63
64
|
"gitFetch": false,
|
|
@@ -82,7 +83,7 @@ Counts require a configured upstream. Unsynced branches use normal text color; s
|
|
|
82
83
|
|
|
83
84
|
### Context
|
|
84
85
|
|
|
85
|
-
`
|
|
86
|
+
`42k/200k` means tokens used / context window. Set `"contextAsPercentage": true` under `minFooter` to show `21.0%/200k` instead. Unknown usage shows `?`.
|
|
86
87
|
|
|
87
88
|
### Subscription usage
|
|
88
89
|
|
package/VISION.md
CHANGED
|
@@ -36,6 +36,13 @@ Two cells give 6.25% steps; ten give 1.25%. Fill rounds to the nearest eighth-ce
|
|
|
36
36
|
|
|
37
37
|
The bar and reset label have no intervening space. Reset formatting uses local clock time through 24 hours, remaining whole days/hours above 24 hours, and whole days above 10 days. Exactly 24 hours stays clock time; exactly 10 days is `↻10d0h`. Missing reset metadata leaves the bar visible without a label.
|
|
38
38
|
|
|
39
|
+
## Context display contract
|
|
40
|
+
|
|
41
|
+
- Default to tokens used / context window, with an explicit `k` suffix on both values. Never deduplicate units across the slash.
|
|
42
|
+
- Always use kilos, including for million-token windows (`1000k`, not `1M`). Below 10k, use two significant digits where one-token resolution permits, capped at three decimal places in kilos: `0.001k`, `0.012k`, `0.11k`, `0.78k`, `0.99k`, `1.0k`, `9.0k`. At and above 10k, round to whole kilos: `10k`, `124k`, `1000k`. Zero is `0k`; rounding can promote `9.999k` to `10k`.
|
|
43
|
+
- `minFooter.contextAsPercentage` defaults to `false`. Opting in replaces only the numerator with percentage used to one decimal place, e.g. `24.7%/500k`. Keep context distinct from the subscription usage bar.
|
|
44
|
+
- Unknown token usage is `?/500k` in either mode; absent context usage is `?`. Never present unknown usage as zero.
|
|
45
|
+
|
|
39
46
|
## Git contract
|
|
40
47
|
|
|
41
48
|
- Pi supplies the branch name. Query `git rev-list --left-right --count HEAD...@{upstream}` for `↑N` local-only and `↓N` upstream-only commits. Use local refs; no remote fetch by default.
|
package/extensions/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Minimal footer — replaces pi's default footer with a clean status line:
|
|
3
3
|
*
|
|
4
|
-
* ~/path/to/dir main status1 status2 sonnet ·
|
|
4
|
+
* ~/path/to/dir main status1 status2 sonnet · 12k/128k · [⣿⣶⠀⠀⠀]↻16:40
|
|
5
5
|
*
|
|
6
6
|
* Settings are persisted in the agent directory (usually ~/.pi/agent)
|
|
7
7
|
* settings.json under "minFooter".
|
|
@@ -31,6 +31,7 @@ interface Settings {
|
|
|
31
31
|
showPath?: boolean;
|
|
32
32
|
showModel?: boolean;
|
|
33
33
|
showContext?: boolean;
|
|
34
|
+
contextAsPercentage?: boolean;
|
|
34
35
|
powerlineSeparator?: boolean;
|
|
35
36
|
gitRefreshSeconds?: number;
|
|
36
37
|
gitFetch?: boolean;
|
|
@@ -52,6 +53,7 @@ const DEFAULT_SETTINGS: FooterSettings = {
|
|
|
52
53
|
showPath: true,
|
|
53
54
|
showModel: true,
|
|
54
55
|
showContext: true,
|
|
56
|
+
contextAsPercentage: false,
|
|
55
57
|
powerlineSeparator: true,
|
|
56
58
|
gitRefreshSeconds: 91,
|
|
57
59
|
gitFetch: false,
|
|
@@ -111,9 +113,11 @@ function writeEnabled(v: boolean): void {
|
|
|
111
113
|
|
|
112
114
|
function formatSize(n: number | null | undefined): string {
|
|
113
115
|
if (n == null) return "?";
|
|
114
|
-
|
|
115
|
-
if (n >=
|
|
116
|
-
|
|
116
|
+
const kilos = n / 1_000;
|
|
117
|
+
if (n === 0 || n >= 10_000) return `${Math.round(kilos)}k`;
|
|
118
|
+
const rounded = Number(kilos.toPrecision(2));
|
|
119
|
+
const decimals = Math.min(3, Math.max(0, 1 - Math.floor(Math.log10(rounded))));
|
|
120
|
+
return `${rounded.toFixed(decimals)}k`;
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
/** Abbreviate only an exact home match or a boundary-prefixed child path. */
|
|
@@ -166,7 +170,7 @@ async function updateGitSync(state: FooterState): Promise<boolean> {
|
|
|
166
170
|
return changed;
|
|
167
171
|
}
|
|
168
172
|
|
|
169
|
-
function updateState(ctx: ExtensionContext, state: FooterState): void {
|
|
173
|
+
function updateState(ctx: ExtensionContext, state: FooterState, config: FooterSettings): void {
|
|
170
174
|
const cwd = ctx.cwd ?? process.cwd();
|
|
171
175
|
if (state.cwd !== cwd) {
|
|
172
176
|
state.gitSync = "";
|
|
@@ -177,16 +181,11 @@ function updateState(ctx: ExtensionContext, state: FooterState): void {
|
|
|
177
181
|
state.model = ctx.model?.id ?? "no-model";
|
|
178
182
|
const usage = ctx.getContextUsage();
|
|
179
183
|
if (usage) {
|
|
180
|
-
const fTokens =
|
|
184
|
+
const fTokens = config.contextAsPercentage === true
|
|
185
|
+
? (usage.tokens == null || usage.contextWindow <= 0 ? "?" : `${(usage.tokens / usage.contextWindow * 100).toFixed(1)}%`)
|
|
186
|
+
: formatSize(usage.tokens);
|
|
181
187
|
const fWindow = formatSize(usage.contextWindow);
|
|
182
|
-
|
|
183
|
-
const lastW = fWindow[fWindow.length - 1];
|
|
184
|
-
// Deduplicate k/M suffix: show suffix only on denominator when both use the same unit
|
|
185
|
-
if ((lastT === "k" || lastT === "M") && lastT === lastW) {
|
|
186
|
-
state.context = `${fTokens.slice(0, -1)}/${fWindow}`;
|
|
187
|
-
} else {
|
|
188
|
-
state.context = `${fTokens}/${fWindow}`;
|
|
189
|
-
}
|
|
188
|
+
state.context = `${fTokens}/${fWindow}`;
|
|
190
189
|
} else {
|
|
191
190
|
state.context = "?";
|
|
192
191
|
}
|
|
@@ -420,7 +419,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
420
419
|
}
|
|
421
420
|
|
|
422
421
|
function refresh(ctx: ExtensionContext): void {
|
|
423
|
-
updateState(ctx, state);
|
|
422
|
+
updateState(ctx, state, config);
|
|
424
423
|
refreshFooter();
|
|
425
424
|
}
|
|
426
425
|
|
|
@@ -431,7 +430,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
431
430
|
!("enabled" in data) || typeof data.enabled !== "boolean") return;
|
|
432
431
|
if (enabled === data.enabled && (!enabled || disposeFooter !== null)) return;
|
|
433
432
|
enabled = data.enabled;
|
|
434
|
-
updateState(currentCtx, state);
|
|
433
|
+
updateState(currentCtx, state, config);
|
|
435
434
|
install(currentCtx);
|
|
436
435
|
refreshFooter();
|
|
437
436
|
});
|
|
@@ -440,7 +439,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
440
439
|
currentCtx = ctx;
|
|
441
440
|
enabled = readConfig().enabled !== false;
|
|
442
441
|
usageLimits.stop();
|
|
443
|
-
updateState(ctx, state);
|
|
442
|
+
updateState(ctx, state, config);
|
|
444
443
|
install(ctx);
|
|
445
444
|
refreshFooter();
|
|
446
445
|
});
|
|
@@ -493,7 +492,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
493
492
|
else if (args === "off") enabled = false;
|
|
494
493
|
else enabled = !enabled;
|
|
495
494
|
writeEnabled(enabled);
|
|
496
|
-
updateState(ctx, state);
|
|
495
|
+
updateState(ctx, state, config);
|
|
497
496
|
install(ctx);
|
|
498
497
|
refreshFooter();
|
|
499
498
|
ctx.ui.notify(`Minimal footer ${enabled ? "enabled" : "disabled"}`, "info");
|
package/package.json
CHANGED