pi-session-footer0.4.0
Render a compact Pi status footer without blocking the UI.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-session-footer
A compact Pi footer showing the current directory, git branch and PR number, changed-file and untracked-file counts, context usage, response speed, model display name, and other extensions' published status. Git status and PR lookups refresh in the background; the PR result, including no PR, is cached for the branch, and rendering reads cached state.
Install
pi install npm:pi-session-footer
Development
From this package directory, run its tests with:
node --test test/render.test.mjs
node --test test/git-status.test.mjs
node --test test/pr-lookup.test.mjs
node --test test/owner-status.test.mjs
External contract
One status row, then one line per extension that publishes a status:
dir │ branch (#pr) (+added,-deleted) 1M 2? 5↑ 2↓ │ ██░░░░ 34% · 262k │ 27.4 tps │ (provider) Model [high]
│ pi-lens · Searching the index
│ perms · yolo
When the pane is narrower than the row, whole segments move to extra rows rather than being cut. A segment is never split, so this footer still shows every part in full:
my-project
██░░░░ 34% · 262k
27.4 tps
(provider) Model [high]
│ pi-lens · Searching the index
- Rendering never blocks the terminal.
render()returns strings built from cached state only. It launches no child process, so a slowgitorghcannot stall a redraw. - Segments wrap; only impossible ones are trimmed. The main row packs whole segments (directory, git, context, speed, model) into as many rows as the width requires: a segment that does not fit the rest of the row moves whole to the next row, and its text is never split. Every returned line fits the requested width — only a segment wider than the entire terminal, or an owner line whose status text exceeds the width, falls back to a
…cut, because Pi's main-screen renderer rejects an over-width line. - Git and PR data arrive asynchronously.
git status --porcelain,git diff HEAD --numstatandgit rev-list --left-right --count @{upstream}...HEADrun throughexecFilewith a 2500 ms timeout;gh pr viewuses the same bound. The third query supplies the ahead/behind commit counts shown as5↑ 2↓. The first query is split into tracked modifications (1M) and untracked entries (2?), so a file created during the session is visible even thoughgit diff HEADignores it. Each count is omitted at zero, and only the untracked count is dimmed, so a new file reads differently from an edit. Failures are swallowed and the footer keeps rendering its last known state. - Refreshes are serialized. At most one refresh runs at a time, bursts coalesce into a single queued follow-up with a 1000 ms floor, and every request advances a generation counter so a stale result can never overwrite a newer one.
- The PR number is cached per branch. A "no PR" answer is remembered for that branch, so a normal refresh does not call
ghagain; only a branch change or a forced refresh re-asks. - Speed is the session average, not the current turn's rate. Tokens from each completed assistant turn are accumulated with that turn's wall-clock time, so a fast final turn does not report a rate the session never sustained.
- Owner lines come from other extensions. Each entry in
footerData.getExtensionStatuses()renders as│ label · text, with the pipe and label dimmed, known keys shown under friendly names (pi-lens-lsp→pi-lens,pi-permission-system→perms), and continuation lines indented under the label. An extension that publishes nothing contributes no line. - The model segment is
(provider) display name [thinking]. Thinking shows the active level,Twhen the model supports reasoning but thinking is off, and–otherwise; the provider is omitted when Pi does not report one.
Settings
This package has no settings file and no configuration keys. It reads only what Pi and other extensions already expose.
Limitations
- The footer shows whatever
footerData.getGitBranch()reports; outside a git repository it shows the directory, context and model segments only. - Ahead/behind arrows appear only for a branch with an upstream; a local-only or detached branch shows none.
(+added,-deleted)counts uncommitted line changes and is omitted when the tree is clean. Untracked files never contribute to(+added,-deleted)becausegit diff HEADdoes not see them; they are counted byN?instead.git status --porcelaincollapses a new directory into one?? dir/entry, soN?counts entries, not files inside them. - Speed is the average over the whole session: output tokens from every completed assistant turn divided by their combined elapsed time, plus the live output so far while a turn is running. It stays blank (
-- tps) until there is enough output over enough elapsed time to compute a rate. - A failed or unresponsive
git/ghlookup keeps the last known values: previously fetched counts and PR numbers stay visible, and a segment is omitted only when no value was ever obtained. The footer itself keeps rendering throughout. - There is no periodic refresh when nothing happens: git state updates when a turn or tool result ends, or on a branch change.
If the contract is unmet
- A line wider than the terminal, or a redraw that stalls: the non-blocking guarantee is broken. Capture the session's width and the rendered line, then run
node --test test/owner-status.test.mjs— the width suite fails if any returned line overflows. - Stale git data replacing newer data: run
node --test test/git-status.test.mjs; the coalescing and generation suites fail if two refreshes overlap or an invalidated result is published. - The same PR answer appearing after switching branches: run
node --test test/pr-lookup.test.mjs; the branch-cache suite fails if the per-branch cache is not cleared. - The untracked count missing or not dimmed: run
node --test test/git-status.test.mjs; the colour suite fails if theN?span is not the only dimmed part of the git segment. - Owner lines missing or not indented: run
node --test test/owner-status.test.mjs. - If the suites pass but the footer still misbehaves in a real session, the passing tests only narrow which paths were exercised: they do not show that this package is correct under every input or lifecycle (the suites drive mocked Pi contexts). Report the terminal width, the footer rows from the pane, the extension list Pi reports, and the event sequence that preceded the misbehaviour, so the cause can be located in this package or in its consumer.