npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-footer-widget

v0.1.1

Published

Composer-agnostic footer widget surface for the pi coding agent. Bridges pi-statusbar, pi-powerline-footer, and the stock footer with a unified push/pull interface.

Readme

pi-footer-widget

A composer-agnostic footer-widget surface for the pi coding agent. A widget provider calls one function and the bridge adapts the widget to whichever footer "composer" is installed — pi-statusbar, pi-powerline-footer, or the stock pi footer — so providers don't replace the footer and don't hardcode against a single composer.

Goal: become pi's footer extension interface. Today this is a bridge over two third-party composers; when a core setFooterSegment API lands upstream, the bridge gains a first-class adapter and providers don't change.

Why

ctx.ui.setFooter() replaces the entire footer. Every extension that wants a footer widget either clobbers the default (losing session name, stats, provider prefix, thinking level, extension statuses) or fights other extensions for the one setFooter slot. Two composers already solve this, but with incompatible interfaces:

  • pi-statusbar — pull model: globalThis.__piStatusbarRegistry.register({ id, render(ctx) }) with lazy SectionAccessors. No extension_statuses line, so setStatus alone is invisible there.
  • pi-powerline-footer — push model: standard ctx.ui.setStatus(key, value) + a powerline.customItems config entry. Degrades to the stock footer's line 3 without the composer.

This library sits in the middle so a provider writes once and reaches both (and the stock footer).

Install

pi install npm:pi-footer-widget

Or as an npm dependency of your extension (recommended for providers):

{ "dependencies": { "pi-footer-widget": "^0.1.0" } }

Usage

import { registerFooterWidget } from "pi-footer-widget";

pi.on("session_start", (_event, ctx) => {
  if (!ctx.hasUI) return;
  let last = "5h ▕██░░░░░░▏ 0%";

  const reg = registerFooterWidget(ctx, {
    id: "ollama-cloud",
    render: () => last,        // pull: composer calls us each frame
    selfColorize: true,        // we embed ANSI; bridge strips if unsupported
    layout: { placement: "right", priority: 60, minWidth: 20 },
    refreshMs: 300_000,
  });

  // push a new value whenever your data changes:
  reg.update("5h ▕██████░░▏ 65%  7d ▕████████░▏ 94%");
});

Push vs pull — offer both

  • Pull (widget.render): the composer calls render(accessors) each frame. Required for pi-statusbar (pull-only). Best when the widget is cheap to compute or wants live accessors.
  • Push (reg.update(text)): the provider pushes a string when its data changes; the bridge re-emits via ctx.ui.setStatus. Works for pi-powerline-footer and the stock footer. If only render is provided on the push path, the bridge polls it at refreshMs and re-pushes.

You can provide both: render for pull composers, and call update() when your data changes for push composers.

What the composer reports back

interface RegisteredWidget {
  update(text: string): void;
  accessors: WidgetAccessors | null;     // null on pi-statusbar handle; live in render
  colorCapability: ColorCapability;
  dispose(): void;
}

interface ColorCapability {
  supportsAnsi: boolean;          // may embed ANSI; bridge strips if false
  supportsPerWidgetColor: boolean;// composer applies one color per widget
  themeColors?: string[];
  supportsThemeFg?: boolean;
}
  • Color fidelity: colorize blissfully via acc.getThemeFg()(color, text) (backed by pi-core ctx.ui.theme.fg). Every composer — and the stock footer's extension-statuses line — passes embedded ANSI through verbatim, so per-widget, per-threshold color (green/yellow/red) survives everywhere today. supportsAnsi and supportsThemeFg are always true. If you prefer a single composer-applied color, leave selfColorize false and let the composer theme / customItems.color decide.
  • Accessors: the bridge builds WidgetAccessors from ExtensionContext on the push path and from pi-statusbar's SectionAccessors on the pull path — so providers get accessors in both modes. getThemeFg() is non-null whenever ctx.ui.theme.fg is available (always, in practice).

Layout declaration (non-authoritative)

interface LayoutPrefs {
  placement?: "left" | "right" | "secondary" | "line1-right" | "line2-mid" | "line3";
  priority?: number;   // higher = more important
  minWidth?: number;
}

These are hints. The composer honors what it can:

| Placement | pi-statusbar | pi-powerline-footer | stock footer | |---|---|---|---| | left/right/secondary | — (single ordered line; user uses sections) | ✓ via customItems.position | — | | line1-right / line2-mid | — | — | — (needs core setFooterSegment) | | line3 | — | ✓ (extension_statuses) | ✓ (extension statuses) |

priority and minWidth are ignored by both composers today (no fit/truncation API) but are declared so a future core API or a richer composer can use them without providers changing.

Configuration per composer

  • pi-statusbar: add the widget id to the sections array in ~/.pi/agent/statusbar.json.
  • pi-powerline-footer: add a customItems entry in pi settings:
    { "powerline": { "customItems": [
      { "id": "ollama", "statusKey": "ollama-cloud", "position": "right", "color": "warning" }
    ]}}
  • Stock footer: nothing to configure; the widget appears on the extension-statuses line.

Limitations & follow-ups

  • Per-threshold color (green/yellow/red within one widget) is lost on the stock footer (one dim color). It is preserved on pi-statusbar and pi-powerline-footer when selfColorize is true, but both composers apply a single theme/item color unless they pass ANSI through. Filed:
  • Detection of pi-powerline-footer is best-effort (an internal symbol). If the symbol changes, the bridge falls back to "stock" — setStatus still works, only the color-capability report changes.
  • line1-right / line2-mid placements are not honored by any current composer; they're declared for the future core setFooterSegment API (see earendil-works/pi#6509).

API

See src/types.ts for the full interface.

Develop

npm install
npm test         # vitest
npm run typecheck

License

MIT