pi-minimal-footer 0.5.0 → 0.5.2

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 CHANGED
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.2] - 2026-10-07
11
+
12
+ ### Added
13
+
14
+ - Publish the same extension as the official scoped mirror `@ryu-cz/pi-minimal-footer`, while retaining `pi-minimal-footer` as the original release path
15
+ - Document both installation names and warn users to install only one
16
+
17
+ ## [0.5.1] - 2026-10-07
18
+
19
+ ### Changed
20
+
21
+ - Keep the whole Git section in normal text foreground while commits remain to push or pull, returning to dim when synced
22
+ - Bold changed Git divergence arrows/counts for two user submissions; further changes restart the highlight, while tool turns and extension prompts do not consume it
23
+
10
24
  ## [0.5.0] - 2026-10-07
11
25
 
12
26
  ### Added
@@ -196,7 +210,10 @@ First npm-ready release.
196
210
 
197
211
  - Project scaffold — `extensions/index.ts` with basic footer structure, `package.json` with pi extension manifest, `README.md`, `LICENSE` (MIT)
198
212
 
199
- [Unreleased]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.4.2...HEAD
213
+ [Unreleased]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.5.2...HEAD
214
+ [0.5.2]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.5.1...v0.5.2
215
+ [0.5.1]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.5.0...v0.5.1
216
+ [0.5.0]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.4.2...v0.5.0
200
217
  [0.4.2]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.4.1...v0.4.2
201
218
  [0.4.1]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.4.0...v0.4.1
202
219
  [0.4.0]: https://github.com/Ryu-CZ/pi-minimal-footer/compare/v0.3.3...v0.4.0
package/README.md CHANGED
@@ -7,14 +7,14 @@
7
7
  <a href="https://pi.dev/packages/pi-minimal-footer"><img src="https://img.shields.io/badge/pi-package-1a1a2e" alt="pi package"></a>
8
8
  </p>
9
9
 
10
- An opinionated, compact one-line footer for [Pi](https://github.com/earendil-works/pi).
10
+ Pi minimal footer is an opinionated, compact, one-line status bar for [Pi](https://github.com/earendil-works/pi).
11
11
 
12
12
  ![Footer preview: ~/git/project   main  🧠 Karpathy  🪽 Icarus  model · 42/200k · [⣿⣿⣿⣤⠀⠀⠀⠀⠀⠀]↻1d8h](media/github-preview.png)
13
13
 
14
14
  **Left**
15
15
 
16
16
  - Working directory: `~/git/project`
17
- - Git branch and upstream divergence: ` main ↑2 ↓1` (`↑` to push, `↓` to pull); counts appear when an upstream is configured
17
+ - Git branch: ` main ↑2 ↓1` (`↑` to push, `↓` to pull)
18
18
 
19
19
  **Right**
20
20
 
@@ -27,10 +27,19 @@ An opinionated, compact one-line footer for [Pi](https://github.com/earendil-wor
27
27
 
28
28
  Requires Node.js >=22.19.0. Interactive terminal UI only.
29
29
 
30
+ Choose one npm name (they contain the same extension; do not install both):
31
+
30
32
  ```bash
31
33
  pi install npm:pi-minimal-footer
34
+ # or
35
+ pi install npm:@ryu-cz/pi-minimal-footer
32
36
  ```
33
37
 
38
+ `pi-minimal-footer` remains the original, unscoped release path. The scoped
39
+ `@ryu-cz/pi-minimal-footer` package is an official mirror intended to improve
40
+ package indexing; it is not a separate extension. The scoped name is an
41
+ indexing workaround, not a guaranteed fix for pi.dev catalog search.
42
+
34
43
  ## Commands
35
44
 
36
45
  | Command | Action |
@@ -60,11 +69,14 @@ Edit `minFooter` in Pi's agent `settings.json` (normally `~/.pi/agent/settings.j
60
69
 
61
70
  - `showSkills` shows **extension status text**, not installed skills. The footer does not add the example statuses itself.
62
71
  - Set `powerlineSeparator` to `false` for plain spaces instead of `` / `` if your font lacks those glyphs. The git icon `` and sync arrows also need compatible glyphs; hide Git data with `showGitBranch: false` if needed.
63
- - Git sync counts are omitted for branches without an upstream, detached HEADs, and non-Git directories.
64
72
  - `maxUsageBarCells` caps the Braille bar length (excluding brackets and reset time). Use a positive integer, e.g. `4` for a compact bar; invalid values fall back to `10`.
65
73
 
66
74
  ## Reading the footer
67
75
 
76
+ ### Git
77
+
78
+ Counts require a configured upstream. Unsynced branches use the theme's normal foreground; synced branches are dim. Changed counts stay bold until two subsequent user messages; further changes restart the highlight.
79
+
68
80
  ### Context
69
81
 
70
82
  `42/200k` means tokens used / context window. `?` means Pi has not reported usage yet, including immediately after compaction.
package/VISION.md CHANGED
@@ -8,12 +8,11 @@ The [README](README.md) is the user manual. This document records current design
8
8
 
9
9
  ## Layout contract
10
10
 
11
- - Directory and git branch form the left group, separated by ``. Pi supplies the branch name; the extension asynchronously runs `git rev-list --left-right --count HEAD...@{upstream}` to append local/upstream divergence as `↑N`/`↓N` (push/pull). The counts are omitted when no upstream is configured, and Git work stays outside synchronous rendering so a slow repository cannot block the TUI.
11
+ - Directory and Git branch form the left group, separated by ``.
12
12
  - Each extension status is its own `` tab. Preserve the supplied text; do not invent status labels, parentheses, or pipes.
13
13
  - Model, context, and subscription usage form the rightmost group, separated by ` · `. Model identifies the running engine; context describes its usage; the usage bar stays anchored at the right edge.
14
14
  - Powerline separators are dim. `powerlineSeparator: false` replaces them with a single space. Font availability cannot be detected reliably.
15
15
  - Measure terminal columns with `visibleWidth`, not string length. Preserve ANSI styling and wide-character accounting when truncating.
16
- - Git divergence refreshes on Pi's branch-change signal and normal footer state refreshes; it is best-effort and never allowed to prevent the footer from loading.
17
16
 
18
17
  ### Space allocation
19
18
 
@@ -37,6 +36,14 @@ Two cells give 6.25% steps; ten give 1.25%. Fill rounds to the nearest eighth-ce
37
36
 
38
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.
39
38
 
39
+ ## Git contract
40
+
41
+ - 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; never fetch automatically.
42
+ - Query outside rendering with a one-second timeout so Git cannot block the TUI. Missing upstreams and command failures omit counts.
43
+ - Refresh on branch-change signals and footer state updates. Ignore older query results to prevent stale counts from restarting highlights.
44
+ - Use the theme's normal text foreground while unsynced, otherwise dim. A count change bolds the arrows/counts until two subsequent user submissions; further changes restart the window. Tool turns and extension prompts do not consume it.
45
+ - Initial loading and working-directory changes establish an unhighlighted baseline. Zero counts hide the arrows entirely.
46
+
40
47
  ## Subscription usage contract
41
48
 
42
49
  Display only the selected provider's shortest applicable window. Subscription usage and model context usage are separate measurements.
@@ -96,12 +103,18 @@ For a manual install, copy `extensions/*` into `~/.pi/agent/extensions/`.
96
103
  - `extensions/index.ts`: settings, state refresh, layout, footer lifecycle, and `/minfooter`.
97
104
  - `extensions/lib/usage-limits.ts`: usage refresh, cache, cancellation, and bar/reset rendering.
98
105
  - `extensions/lib/usage-providers.ts`: authentication, endpoint selection, and response normalization.
99
- - `tests/`: loader-based lifecycle/layout regression tests and usage parsing tests.
106
+ - `tests/`: lifecycle/layout regressions, Git highlighting with a temporary repository, and usage parsing tests.
100
107
 
101
108
  Settings live under `minFooter` in Pi's configured agent directory. Read them at session start or explicit toggle; ordinary refreshes use cached settings. Preserve unrelated settings on writes. Only install the footer in interactive terminal mode.
102
109
 
103
110
  ### Checking changes
104
111
 
105
- For behavior changes, run `npm run check` and `npm test`. Layout tests should cover narrow widths, ANSI text, wide Unicode, field priority, and both separator modes. Subscription usage changes should cover provider switches, timeouts, stale cache, partial updates, and malformed/missing metadata as applicable. Preview in a real terminal for font-dependent appearance; automated width checks cannot prove glyph availability.
112
+ Run `npm run check` and `npm test` for behavior changes. Cover relevant cases:
113
+
114
+ - Layout: narrow widths, ANSI/wide Unicode, field priority, and separator modes.
115
+ - Git: divergence, synced styling, highlight expiry/restart, and user submissions versus tool turns.
116
+ - Subscription usage: provider switches, timeouts, stale cache, partial updates, and malformed/missing metadata.
117
+
118
+ Preview font-dependent appearance in a real terminal; width checks cannot prove glyph availability.
106
119
 
107
120
  Keep release notes in [CHANGELOG.md](CHANGELOG.md), and keep the README focused on installation and daily use. Preserve [upstream MIT attribution](extensions/lib/LICENSE) when changing adapted provider code.
@@ -116,6 +116,9 @@ interface FooterState {
116
116
  model: string;
117
117
  context: string;
118
118
  gitSync: string;
119
+ gitInitialized: boolean;
120
+ gitHighlightInputs: number;
121
+ gitRequest: number;
119
122
  }
120
123
 
121
124
  async function getGitSync(cwd: string): Promise<string> {
@@ -139,12 +142,23 @@ async function getGitSync(cwd: string): Promise<string> {
139
142
 
140
143
  async function updateGitSync(state: FooterState): Promise<void> {
141
144
  const cwd = state.cwd;
145
+ const request = ++state.gitRequest;
142
146
  const gitSync = await getGitSync(cwd);
143
- if (state.cwd === cwd) state.gitSync = gitSync;
147
+ // Refresh events can overlap; an older result must not restart the highlight.
148
+ if (state.cwd !== cwd || request !== state.gitRequest) return;
149
+ if (state.gitInitialized && state.gitSync !== gitSync) state.gitHighlightInputs = 2;
150
+ state.gitSync = gitSync;
151
+ state.gitInitialized = true;
144
152
  }
145
153
 
146
154
  function updateState(ctx: ExtensionContext, state: FooterState): void {
147
- state.cwd = ctx.cwd ?? process.cwd();
155
+ const cwd = ctx.cwd ?? process.cwd();
156
+ if (state.cwd !== cwd) {
157
+ state.gitSync = "";
158
+ state.gitInitialized = false;
159
+ state.gitHighlightInputs = 0;
160
+ }
161
+ state.cwd = cwd;
148
162
  state.model = ctx.model?.id ?? "no-model";
149
163
  const usage = ctx.getContextUsage();
150
164
  if (usage) {
@@ -233,7 +247,10 @@ function buildLine(
233
247
  export default function (pi: ExtensionAPI) {
234
248
  let config = readConfig();
235
249
  let enabled = config.enabled !== false;
236
- const state: FooterState = { cwd: process.cwd(), model: "no-model", context: "?", gitSync: "" };
250
+ const state: FooterState = {
251
+ cwd: process.cwd(), model: "no-model", context: "?", gitSync: "",
252
+ gitInitialized: false, gitHighlightInputs: 0, gitRequest: 0,
253
+ };
237
254
  let requestRender: (() => void) | null = null;
238
255
  let disposeFooter: (() => void) | null = null;
239
256
  const usageLimits = new UsageLimits(() => requestRender?.());
@@ -284,13 +301,15 @@ export default function (pi: ExtensionAPI) {
284
301
  ? [...footerData.getExtensionStatuses().values()].filter((s) => s.trim())
285
302
  : [];
286
303
  const branch = config.showGitBranch ? footerData.getGitBranch() : null;
287
- const branchText = branch ? `${branch}${state.gitSync}` : "";
304
+ const syncText = state.gitHighlightInputs > 0 ? theme.bold(state.gitSync) : state.gitSync;
305
+ const branchText = branch ? `${branch}${syncText}` : "";
288
306
  const statusSeparator = config.powerlineSeparator ? theme.fg("dim", "  ") : " ";
289
307
  const line = buildLine(
290
308
  width,
291
309
  config.showPath ? theme.fg("dim", abbreviateHome(state.cwd, homedir())) : "",
292
310
  statuses.length ? statusSeparator + statuses.map((status) => theme.fg("dim", status)).join(statusSeparator) : "",
293
- branchText ? theme.fg("dim", ` ${branchText}`) : "",
311
+ // Keep unsynced branches readable; bold counts separately mark recent changes.
312
+ branchText ? theme.fg(state.gitSync ? "text" : "dim", ` ${branchText}`) : "",
294
313
  config.showModel ? theme.bold(state.model) : "",
295
314
  config.showContext ? theme.fg("dim", theme.bold(state.context)) : "",
296
315
  (available, maxCells = BASE_BAR_CELLS) => usageLimits.line(available, theme, maxCells),
@@ -322,6 +341,13 @@ export default function (pi: ExtensionAPI) {
322
341
  install(ctx);
323
342
  });
324
343
 
344
+ // Count user submissions, not turn_end: one prompt can trigger many tool turns.
345
+ // Extension-generated prompts do not consume the user's highlight window.
346
+ pi.on("input", (event, ctx) => {
347
+ if (event.source !== "extension" && state.gitHighlightInputs > 0) state.gitHighlightInputs--;
348
+ refresh(ctx);
349
+ });
350
+
325
351
  pi.on("model_select", async (_event, ctx) => {
326
352
  selectUsage(ctx);
327
353
  refresh(ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-minimal-footer",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "An opinionated minimal footer extension for Pi — clean status line with path, extension statuses, model, and context usage.",
5
5
  "keywords": [
6
6
  "pi-package",