@astrosheep/pi-quota 0.5.4 → 0.5.6
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/README.md +5 -5
- package/package.json +1 -1
- package/src/bar/card.ts +1 -1
- package/src/extension.ts +10 -5
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @astrosheep/pi-quota
|
|
2
2
|
|
|
3
|
-
Compact quota status for Pi: Codex, Kimi
|
|
3
|
+
Compact quota status for Pi: Codex, Kimi, OpenCode Go and DeepSeek work out of the box; new-api and Sub2API use explicit provider bindings.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
pi install npm:@astrosheep/pi-quota
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Reload Pi after installing or changing settings. Use `/usage` for a persistent, context-free snapshot
|
|
9
|
+
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.
|
|
10
10
|
|
|
11
11
|
## What it shows
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ Reload Pi after installing or changing settings. Use `/usage` for a persistent,
|
|
|
18
18
|
|
|
19
19
|
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.
|
|
20
20
|
|
|
21
|
-
The footer shows at most two windows and `+N` for additional ones, for the current provider only. `/usage` queries all configured supported providers and
|
|
21
|
+
The footer shows at most two windows and `+N` for additional ones, for the current provider only. `/usage` queries all configured supported providers and shows successful results with all windows, grouped by provider; it does not open a modal or send messages to the model. Snapshots remain frozen at capture time. Query failures replace stale values in the footer and appear in `/usage --all`.
|
|
22
22
|
|
|
23
23
|
## Configure providers
|
|
24
24
|
|
|
@@ -36,7 +36,7 @@ Add bindings in global `~/.pi/agent/settings.json` under `quotaUsage` (not proje
|
|
|
36
36
|
}
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Use the **exact Pi provider ID**.
|
|
39
|
+
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`.
|
|
40
40
|
|
|
41
41
|
| Adapter | Endpoint | Result |
|
|
42
42
|
|---|---|---|
|
|
@@ -63,7 +63,7 @@ Pi model/auth → adapter → QuotaSnapshot → controller → footer / /usage /
|
|
|
63
63
|
|
|
64
64
|
`QuotaSnapshot` separates `balance` (wallet), `allowance` (finite key quota), `windows` (renewable limits), and optional `spend` (Today/Lifetime actual charge). This prevents unrelated amounts from sharing an ambiguous `Used` label. Custom adapters can be passed to `createQuotaExtension({ adapters: [...] })`; see `examples/custom-provider.ts`. Provider aliases are never inferred.
|
|
65
65
|
|
|
66
|
-
The extension publishes structured state on `quota-bar:state:v1`. 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. Switching provider discards old footer values immediately.
|
|
66
|
+
The extension publishes structured state on `quota-bar:state:v1`. 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.
|
|
67
67
|
|
|
68
68
|
## Development
|
|
69
69
|
|
package/package.json
CHANGED
package/src/bar/card.ts
CHANGED
|
@@ -24,7 +24,7 @@ export function captureAllUsage(states: readonly QuotaState[], now = Date.now())
|
|
|
24
24
|
|
|
25
25
|
export function usageLines(card: UsageCard, paint?: Paint, barWidth = 20): string[] {
|
|
26
26
|
if (card.version === 1) return renderUsage(card.state, paint, card.capturedAt, barWidth);
|
|
27
|
-
if (card.states.length === 0) return ['No
|
|
27
|
+
if (card.states.length === 0) return ['No quota data available. Run /usage --all for details.'];
|
|
28
28
|
return card.states.flatMap((state, index) => [
|
|
29
29
|
...(index ? ['', ''] : []), ...renderUsage(state, paint, card.capturedAt, barWidth),
|
|
30
30
|
]);
|
package/src/extension.ts
CHANGED
|
@@ -85,8 +85,11 @@ export function createQuotaExtension(options: QuotaExtensionOptions = {}) {
|
|
|
85
85
|
if (typeof value === 'string') headers[name] = value;
|
|
86
86
|
}
|
|
87
87
|
const auth: ProviderAuth = { ...resolved.auth, headers };
|
|
88
|
-
//
|
|
89
|
-
|
|
88
|
+
// Provider auth often has no endpoint. /usage also queries providers other
|
|
89
|
+
// than the selected model, so resolve their configured model URL as well.
|
|
90
|
+
const model = ctx.model?.provider === provider ? ctx.model
|
|
91
|
+
: ctx.modelRegistry.getAll().find(model => model.provider === provider);
|
|
92
|
+
if (model?.baseUrl) auth.baseUrl = model.baseUrl;
|
|
90
93
|
return auth;
|
|
91
94
|
};
|
|
92
95
|
|
|
@@ -167,8 +170,8 @@ export function createQuotaExtension(options: QuotaExtensionOptions = {}) {
|
|
|
167
170
|
});
|
|
168
171
|
|
|
169
172
|
pi.registerCommand('usage', {
|
|
170
|
-
description: '
|
|
171
|
-
handler: async (
|
|
173
|
+
description: 'Show available quotas; use /usage --all to include provider errors',
|
|
174
|
+
handler: async (args, ctx) => {
|
|
172
175
|
if (!ctx.hasUI) return;
|
|
173
176
|
bind(ctx);
|
|
174
177
|
const generation = ++commandGeneration;
|
|
@@ -180,7 +183,9 @@ export function createQuotaExtension(options: QuotaExtensionOptions = {}) {
|
|
|
180
183
|
// Never append via a stale Pi runtime, or label a replacement model's data
|
|
181
184
|
// as the result of the original command. A newer command owns its result.
|
|
182
185
|
if (!current || generation !== commandGeneration) return;
|
|
183
|
-
const
|
|
186
|
+
const visibleStates = args.trim() === '--all'
|
|
187
|
+
? states : states.filter(state => state.kind === 'ready');
|
|
188
|
+
const card = captureAllUsage(visibleStates);
|
|
184
189
|
pi.appendEntry<UsageCard>(USAGE_ENTRY, card);
|
|
185
190
|
// Custom entry renderers are TUI-only; RPC clients still get readable output.
|
|
186
191
|
if (ctx.mode !== 'tui') {
|