@alexanderfortin/pi-usage-lib

Shared library for Pi usage monitoring extensions

Packages

Package details

extension

Install @alexanderfortin/pi-usage-lib from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@alexanderfortin/pi-usage-lib
Package
@alexanderfortin/pi-usage-lib
Version
0.2.0
Published
Jun 18, 2026
Downloads
1,143/mo · 494/wk
Author
alexanderfortin
License
MIT
Types
extension
Size
51.2 KB
Dependencies
1 dependency · 2 peers

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-usage-lib

Shared library for building Pi coding agent usage-monitoring extensions.

It absorbs all the boilerplate that most *-usage extension needs — Pi event registration, provider matching, API fetching with sandbox-aware auth, response caching, error handling, and themed footer rendering — so that each extension reduces to a single config object with two callbacks.

What's Included

Module Exports Purpose
pi-usage-lib createUsageExtension(), UsageCache, UsageError, buildAuthHeaders(), safeFetch(), safeParseJson() Factory + building blocks
pi-usage-lib/datetime formatInstantFromEpochMs(), formatTimeRemainingFromEpochMs() Temporal date/time helpers

Install

bun add @alexanderfortin/pi-usage-lib

Quick Start

import { createUsageExtension, buildAuthHeaders, safeFetch, safeParseJson } from "@alexanderfortin/pi-usage-lib"

export default createUsageExtension({
  providerPrefix: "myprovider",
  statusKey: "myprovider-usage",
  label: "MyProvider",

  async fetchUsage(modelRegistry) {
    const headers = await buildAuthHeaders(modelRegistry, "myprovider")
    const response = await safeFetch("https://api.myprovider.com/usage", { headers })
    const data = await safeParseJson(response)
    return { balance: data.balance }
  },

  renderStatus(data, theme) {
    return theme.fg("muted", "MyProvider:") + theme.fg("accent", `$${data.balance.toFixed(2)}`)
  },
})

That's it — one file, no other source files needed. The factory registers all Pi events, manages caching, handles errors, and shows a themed footer automatically.

API Reference

createUsageExtension<TData>(config)

Creates a Pi extension function from a configuration object.

interface UsageExtensionConfig<TData> {
  providerPrefix: string      // e.g. "zai", "deepseek"
  statusKey: string           // e.g. "zai-usage"
  label: string               // e.g. "MyProvider"
  cooldownMs?: number         // cache TTL (default: 30_000)
  fetchUsage: FetchUsageFn<TData>
  renderStatus: RenderStatusFn<TData>
  renderError?: RenderErrorFn // optional, defaults to themed <err:code> display
}

The returned function is a valid Pi extension — pass it as the default export or register it via pi.extensions.

buildAuthHeaders(modelRegistry, providerName, extra?)

Builds authenticated fetch headers using a 3-way sandbox-aware strategy:

  1. Real key → sends Authorization: Bearer <key>
  2. "proxy-managed" sentinel → skips auth header (Docker Sandbox proxy handles it)
  3. No key → skips auth header (API returns 401 → shown as <err:http401>)

Always sets Accept-Encoding: identity to work around Pi v0.75.0's undici gzip decompression issue.

safeFetch(url, init?)

Wraps fetch() with structured error handling:

  • Network errors (DNS, timeout, proxy) → throws UsageError with code "fetch"
  • HTTP errors (4xx, 5xx) → throws UsageError with code "http{status}"

safeParseJson<T>(response)

Parses response.json() with error handling:

  • Empty or malformed body → throws UsageError with code "badjson"

UsageError

class UsageError extends Error {
  readonly name = "UsageError"
  readonly code: string  // e.g. "fetch", "http401", "badjson", custom codes
}

Used by safeFetch, safeParseJson, and the default error renderer. Extensions can throw UsageError from their fetchUsage with custom codes — the default renderError will display them as <err:code> in the footer.

UsageCache<TData>

The generic cache class used internally by createUsageExtension. Available for advanced use cases where you need direct control over the cache lifecycle.

Color Thresholds (Configurable)

The library highlights usage values with color when they approach or exceed limits:

  • Percentage-based (e.g. Z.ai usage): warning above 80%, critical at 90%+
  • Credit-based (e.g. DeepSeek balance): warning below $5, critical at $1 or less

Overriding thresholds via settings file

You can override any or all of the default thresholds by creating a JSON file at ~/.pi/agent/usage-lib.json:

{
  "thresholds": {
    "percentage": { "warning": 70, "critical": 85 },
    "credit": { "warning": 5, "critical": 2 }
  }
}

All keys are optional — only the ones you specify are overridden; the rest keep their defaults. Unknown keys and non-numeric values are silently ignored. The file is read once per session and cached.

Overriding thresholds programmatically

The colorForPercentage() and colorForCredit() helpers accept an optional thresholds parameter:

import { colorForPercentage, type ColorThresholds } from "@alexanderfortin/pi-usage-lib"

const custom: ColorThresholds = {
  percentage: { warning: 60, critical: 75 },
  credit: { warning: 5, critical: 1 },
}

// In your renderStatus callback:
const color = colorForPercentage(data.percentage, theme, custom)

When no thresholds argument is passed, the functions fall back to the values loaded from the settings file (or the built-in defaults).

Color threshold API

Export Description
ColorThresholds Type describing the threshold structure
DEFAULT_COLOR_THRESHOLDS Built-in default thresholds
loadColorThresholds() Load & cache thresholds from the settings file
mergeThresholds(defaults, overrides) Merge partial overrides into defaults
getSettingsFilePath() Resolve the path to ~/.pi/agent/usage-lib.json

Error Display (Default Behavior)

By default, errors are shown in the footer using the following pattern:

MyProvider:<err:http401>
MyProvider:<err:fetch>
MyProvider:<err:badjson>

No console.error is called — the footer is the error channel. To customize, provide a renderError callback. Return undefined to clear the footer instead.

Date/Time Utilities (pi-usage-lib/datetime)

import { formatInstantFromEpochMs, formatTimeRemainingFromEpochMs } from "@alexanderfortin/pi-usage-lib/datetime"

formatInstantFromEpochMs(1705318245000)    // "Mon, 15 Jan 2024, 14:30:45 GMT"
formatTimeRemainingFromEpochMs(Date.now() + 3665000)  // "1h 1m 5s"

License

See LICENSE