@astrosheep/pi-quota

中文文档
0.13.2发布于 2026/10/28TypeScriptES Module零依赖近 30 天下载 2669

Composable quota bar with Codex, Kimi, OpenCode Go, new-api, DeepSeek, Sub2API and YesCode adapters

原始使用文档
文档目录6 节
  1. What it shows
  2. Configure providers
  3. Architecture
  4. Snapshot schema
  5. Standalone query layer
  6. Development

@astrosheep/pi-quota

Compact quota status for Pi: Codex, Kimi, OpenCode Go and DeepSeek work out of the box; new-api, Sub2API and YesCode use explicit provider bindings.

pi install npm:@astrosheep/pi-quota

Reload Pi after installing or changing settings. Use /usage for a persistent, context-free snapshot of providers with available quota data, including the current one. Use /usage --all to inspect provider errors. Automatic footer polling never adds chat items.

What it shows

KindFooter/usage
Usage limit with a known period5h [▆] 72% ↺ 2h15mHorizontal bar, remaining percentage, reset, exact amounts if available
WalletBal $12.34Each finite balance, separately from limits and spend
Amount-based limit without a supplied periodKey quota [▇] $85.00Remaining percentage plus exact remaining/used/cap amounts
Unlimited limitKey quota ∞Unlimited, without fake money or a percentage
SpendingNot shownToday expenses; Lifetime is retained in data, not displayed

A percentage always means remaining, not used. Unknown is [?] ?; an expired reset is ↺ due with the stale percentage hidden until the next successful query. A wallet balance never becomes a percentage. Historical spend is not a quota.

The footer shows every balance, then limits in adapter order, capped at two by default — set quotaUsage.footerWindows to a positive integer or "all" to show more — followed by +N for limits it did not show, for the current provider only. Shared limits are preferred over scoped ones, so a scoped limit can be counted in +N. /usage queries all configured supported providers and shows every balance, limit and Today spending entry, grouped by provider; it does not open a modal or send messages to the model. Snapshots remain frozen at capture time. Transient query failures (network, timeout, rate limit or service errors) keep the last successful values in the footer. A dim ? appears only once that snapshot is at least five minutes old, and disappears after a successful refresh. Failures without cached data, or auth/config/schema errors, show an error instead. /usage --all still reports query failures.

Configure providers

Add bindings in global ~/.pi/agent/settings.json under quotaUsage (not project settings):

{
  "quotaUsage": {
    "providers": {
      "my-sub2api": { "adapter": "sub2api" },
      "my-new-api": { "adapter": "new-api", "quotaPerUnit": 500000, "currency": "USD" },
      "deepseek": { "adapter": "deepseek" },
      "opencode-go-2": { "adapter": "opencode-go" },
      "yes-vg": { "adapter": "yescode", "username": "[email protected]", "password": "..." },
      "my-script": { "adapter": "exec", "command": ["my-quota-cli", "--json"], "label": "My Script" },
      "my-alias": { "adapter": "alias", "of": "my-sub2api" }
    }
  }
}

Use the exact Pi provider ID. Built-in providers and explicitly bound providers are queried; explicit bindings replace a built-in adapter with the same ID. Unknown keys or adapter options are rejected. The API key comes from Pi's provider auth, and the endpoint comes from the provider's registered model; do not put model API keys in quotaUsage.

AdapterEndpointResult
sub2api{baseUrl}/usageWallet, key quota, rate windows or subscription day/week/month windows; API-key Today/Lifetime actual spend
new-apiAccount PAT /api/user/self, falling back to key-native billing/token endpointsAccount balance + lifetime spend; key limits (finite or unlimited), with no invented renewal
deepseekOfficial /user/balanceAll reported currency balances; no invented spend
opencode-goOfficial https://opencode.ai/zen/go/v1/usage5h/1w/30d windows, same as the built-in opencode-go adapter
yescodeco.yes.vg login → session → /api/v1/auth/profile + /api/v1/user/balanceSeparate subscription/pay-as-you-go balances plus scoped subscription limits
execRuns command as argv (no shell), parses stdout as a QuotaSnapshot JSONWhatever the command reports; fetchedAt is stamped by the adapter, never by the command
aliasNo endpoint — delegates to the of binding (built-in or explicit)Shares the target account's quota; one folded row in /usage

Bind opencode-go to a second OpenCode Go account: register it as its own Pi provider in models.json with its own apiKey (e.g. opencode-go-2), then bind that ID here. The built-in opencode-go binding is implicit and needs no entry; the reserved IDs openai-codex, kimi-coding and opencode-go cannot be rebound.

Sub2API accepts no extra settings; it preserves deployment subpaths. Rate-only keys need not expose a top-level currency (rates are USD). Unknown rate-window durations and invalid limits fail rather than inventing a 1d window. Subscription periods without a cap are omitted. Weekly resets use the reported weekly_window_start plus seven days; daily/monthly resets stay unknown because this endpoint supplies no corresponding anchors or server timezone. Its dashboard /api/v1/usage is a separate, JWT-authenticated paginated request log; the adapter uses the API-key /v1/usage instead.

For new-api, quotaPerUnit defaults to 500000, currency to USD. Optionally add dashboardAccessToken (console system access token) and dashboardUserId (positive numeric ID required by some old forks) to that provider. This PAT is the only optional secret kept in settings. The account endpoint takes precedence; failures fall back to the key-native billing and token usage paths. Without a PAT, an API key cannot read the dashboard account quota. A finite key reports a known percentage only when total_granted is present and consistent with used plus remaining; otherwise its limit retains exact used/remaining with amounts.limit: null and an unknown percentage. It never becomes a wallet. unlimited_quota and legacy billing's unlimited sentinel become unlimited limits, not infinite balances. Values in settings and server error bodies are never logged.

For YesCode, username is the account email and password the account password; both stay in global settings.json, which is the trade-off of this adapter. YesCode rejects API keys on account endpoints ("requires a user session or JWT"), so the adapter logs in via /api/v1/auth/login, caches the issued cookie/JWT in memory for ~23 hours, and re-logs in once on an auth failure. The model cr_ key is never sent to account endpoints; it only pins the provider to the official co.yes.vg origin. Subscription and pay-as-you-go balances remain separate; daily/weekly limits appear only when the account actually has those caps. Only an explicitly reported next reset is preserved; last_*_reset does not establish a future schedule.

Exec runs the configured argv without a shell and parses stdout as a JSON object with required balances, limits and spending arrays — the same schema every adapter produces, enforced by the controller. This is a breaking query/exec contract migration: legacy windows, balance, allowance and spend fields are rejected, not converted. fetchedAt is stamped by the adapter; a value from the command is ignored. The controller bounds every query (10s default) and kills the child on timeout; non-zero exits, unreadable JSON and output over 256KB become errors, and command output is never logged. The child inherits Pi's environment, so keep secrets in env vars, not in quotaUsage.

Alias binds a second provider ID to the same account: "of" names the real binding, which may be a built-in or an explicit adapter. The alias never queries on its own — a session on the alias shows the target's quota in the footer, queried under the target's identity and credentials, and /usage folds the alias into the target's single row with the session pin (and ★) following the fold. Aliases are one hop: of must not itself be an alias, and an alias whose target is not configured fails visibly instead of vanishing.

Authenticated quota URLs must use HTTPS, except HTTP loopback for local deployments. URL userinfo, query strings, fragments and HTTP redirects are rejected; credentials never follow redirects. Fixed official endpoints reject custom origins. No browser cookie scraping or credential discovery.

Architecture

Pi model/auth → adapter → QuotaSnapshot → controller → footer / /usage / state event
  • src/query/: protocol-specific parsing, credential resolution, safe URLs, bounded GET client, state validation and controller. No Pi/TUI imports.
  • src/config.ts: strict global provider bindings.
  • src/bar/: pure compact rendering and persistent multi-provider chat card.
  • src/extension.ts and src/index.ts: Pi lifecycle and auth bridge.

QuotaSnapshot preserves three independent concepts: balances (owned money), limits (periodic and non-periodic allowances), and spending (reported expenses, not necessarily wallet debit or limit consumption). Pi providers only select/bind adapters; the model adds no inferred owner/account graph. Custom adapters can be passed to createQuotaExtension({ adapters: [...] }); see examples/custom-provider.ts. Provider aliases are never inferred.

The extension publishes structured state on quota-bar:state:v2 and saves usage cards under quota-bar:usage:v2; old contract events/cards are not migrated. Use createQuotaExtension({ footer: false }) to consume it without this extension's footer. Normal queries are throttled, cancellable, timeout-bounded and backed off after errors. /usage forces a fresh query for every configured supported provider, then omits failed results from its default view. Switching provider discards old footer values immediately.

Snapshot schema

All types below are named exports of @astrosheep/pi-quota/query:

interface Balance {
  id: string;
  label: string;
  currency: string;
  remaining: number;
}
interface LimitAmounts {
  unit: string;
  limit: number | null;
  used: number;
  remaining: number;
}
interface UsageLimit {
  id: string;
  label: string;
  scope?: string;
  remainingPercent: number | null;
  resetAt: number | null;
  durationSeconds?: number;
  amounts?: LimitAmounts;
  unlimited?: true;
}
interface Spending {
  id: string;
  label: string;
  currency: string;
  amount: number;
  period: 'today' | 'lifetime';
}
interface QuotaSnapshot {
  balances: Balance[];
  limits: UsageLimit[];
  spending: Spending[];
  fetchedAt: number;
}
  • All three arrays are required, with at most 64 entries each. Spend-only snapshots are valid; all-empty snapshots are not.
  • IDs are nonblank, control-free strings of at most 64 characters, unique within each category. They are opaque and preserved exactly, never derived from duration: two 5h limits with different IDs remain distinct. Labels/scopes/units are sanitized for terminal safety, trimmed and bounded to 64 characters; blank values are rejected.
  • Currency is a three-letter uppercase code. Balances are finite, including zero and negative debt. They cannot be unlimited.
  • Percentages are finite values in [0, 100], always remaining; null means unknown. Exact amounts and provider percentages need not agree after rounding or provider-specific accounting. limit is nonnegative or null (cap not reported); used is nonnegative; remaining is finite and may be negative. Amount units can be currencies or counts such as tokens/requests; counts are not formatted as money.
  • Unlimited limits use unlimited: true, remainingPercent: null, and no amounts. Unknown cap (amounts.limit: null) does not mean unlimited.
  • fetchedAt and resetAt are epoch milliseconds; resetAt is positive or null. A supplied duration must be positive. Missing duration/reset is unknown, not proof of no renewal. No fixed/rolling classification or future reset schedule is inferred.
  • Spending amounts are finite and nonnegative. today means the provider-defined day, with no inferred timezone. Both periods are retained in snapshots, but the footer omits spending and /usage displays only Today.

For example, an exec command can emit this (no fetchedAt required):

{
  "balances": [{ "id": "wallet", "label": "Balance", "currency": "USD", "remaining": 12.34 }],
  "limits": [{
    "id": "requests", "label": "Requests", "remainingPercent": 80, "resetAt": null,
    "amounts": { "unit": "requests", "limit": 100, "used": 20, "remaining": 80 }
  }],
  "spending": [{ "id": "today", "label": "Reported spend", "currency": "USD", "amount": 2.5, "period": "today" }]
}

Standalone query layer

Non-Pi consumers (bridges, plugins, scripts) can import the query layer without pulling in the Pi extension or its peer dependencies:

import {
  AdapterRegistry, codexAdapter, createJsonClient, createPostJsonClient,
} from '@astrosheep/pi-quota/query';

const registry = new AdapterRegistry([codexAdapter]);
const snapshot = await registry.get('openai-codex')!.query({
  provider: 'openai-codex',
  signal: AbortSignal.timeout(10_000),
  now: () => Date.now(),
  getAuth: myAuthResolver,      // you supply credentials
  getJson: createJsonClient(),
  postJson: createPostJsonClient(),
});

The subpath exports every adapter, the registry/controller, option validators, HTTP/exec plumbing, and all query types. Peer dependencies are marked optional, so installing for the query layer alone stays light.

Development

Requires Node ≥22.18 and a compatible Pi installation.

npm install --ignore-scripts
npm test
npm run typecheck
npm run build
npm run demo

版本与发布记录

@astrosheep/pi-quota 共发布 20 个版本,首次发布于 2026/09/23;过去 12 个月发布了 20 个版本。

版本发布日期距今
0.13.2latest2026/10/2810 天前
0.13.12026/10/2810 天前
0.13.02026/10/1424 天前
0.12.22026/10/1425 天前
0.12.12026/10/1325 天前
0.12.02026/10/1325 天前

关于 @astrosheep/pi-quota 的常见问题

@astrosheep/pi-quota 是什么?

Composable quota bar with Codex, Kimi, OpenCode Go, new-api, DeepSeek, Sub2API and YesCode adapters

如何安装 @astrosheep/pi-quota?

在项目目录运行 npm install @astrosheep/pi-quota,或使用 pnpm add / yarn add / bun add。

@astrosheep/pi-quota 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@astrosheep/pi-quota 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@astrosheep/pi-quota 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@astrosheep/pi-quota 可以商用吗?

@astrosheep/pi-quota 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@astrosheep/pi-quota 的下载量有多少?

根据 npm 官方下载统计,@astrosheep/pi-quota 在 2026/10/07 – 2026/11/05 这 30 天内被下载 2,669 次,日均约 89 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@astrosheep/pi-quota 还在维护吗?

最新版本 0.13.2 发布于 2026/10/28(10 天前);至今共发布 20 个版本,其中过去 12 个月发布了 20 个;首次发布于 2026/09/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。