@cad0p/pi-usage 0.11.2-20261102.0 → 0.11.3-20261102.0
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/CHANGELOG.md +20 -0
- package/README.md +6 -5
- package/extensions/quota-panel.ts +48 -8
- package/package.json +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.11.3] - 2026-11-02
|
|
6
|
+
|
|
7
|
+
<!-- USER-EDITABLE SECTION START -->
|
|
8
|
+
First fix release of the fork. With Claude Code uninstalled, Claude now reads Pi's own login instead of a dead Claude Code store, and `/usage` shows every OpenCode Go account.
|
|
9
|
+
|
|
10
|
+
- **Claude source:** `auto` passes over an expired Claude Code token when Pi's `anthropic` login is fresh, and adds a warning naming the switch. `PI_QUOTA_CLAUDE_SOURCE=claude-code` still pins the CLI store. The report cache is keyed by the Claude source setting, so a switch refetches.
|
|
11
|
+
- **Multi-account panel:** a provider with several accounts is one header plus one line per account (its fullest window, or `key rejected` / `no Go plan`), rendered as a component so Pi's ten-line widget cap no longer truncates it.
|
|
12
|
+
- **Summary:** `OP-Go: 7/14 ok · lowest 24% (#7)` instead of account #1's number.
|
|
13
|
+
- `piquota --version` reads `package.json`.
|
|
14
|
+
<!-- USER-EDITABLE SECTION END -->
|
|
15
|
+
|
|
16
|
+
### 🐛 Bug Fixes
|
|
17
|
+
|
|
18
|
+
- /usage live bugs — dead Claude store, truncated panel, account-#1 summary (closes #5)
|
|
19
|
+
|
|
20
|
+
|
package/README.md
CHANGED
|
@@ -230,10 +230,10 @@ Inside Pi:
|
|
|
230
230
|
|
|
231
231
|
| Command | Effect |
|
|
232
232
|
| --- | --- |
|
|
233
|
-
| `/usage` | one on-demand refresh, show the full panel, notify a one-line summary |
|
|
233
|
+
| `/usage` | one on-demand refresh, show the full panel until the next prompt (or a second `/usage`), notify a one-line summary |
|
|
234
234
|
| `/usage box` | pin the five-row box above the editor |
|
|
235
235
|
| `/usage line` | pin the compact line above the editor, in its own row |
|
|
236
|
-
| `/usage panel` | full
|
|
236
|
+
| `/usage panel` | full panel above the editor, pinned across prompts |
|
|
237
237
|
| `/usage hide` | hide the panel/line and stop background refresh until a surface is on again |
|
|
238
238
|
| `/usage status` / `nostatus` | enable/disable the footer status |
|
|
239
239
|
| `/usage refresh` | refresh only |
|
|
@@ -248,8 +248,9 @@ it fresh with a background refresh (and a gentle refresh after each agent turn).
|
|
|
248
248
|
`/usage hide` gives the row back.
|
|
249
249
|
|
|
250
250
|
A provider with several accounts is shown as one header (`OP-Go · 7 of 14 accounts
|
|
251
|
-
ok`) plus one line per account
|
|
252
|
-
|
|
251
|
+
ok`) plus one line per account with every window and its reset, e.g.
|
|
252
|
+
`#2 ● session 2% (10m) · week 10% (6d) · month 90% (19d)`, or the reason it failed
|
|
253
|
+
(`key rejected`, `no Go plan`). The leading glyph is the fullest window's band. The panel is rendered as a component, so Pi's ten-line
|
|
253
254
|
cap on plain widgets never truncates it, and the summary names the account with the
|
|
254
255
|
most room: `OP-Go: 7/14 ok · lowest 24% (#7)`.
|
|
255
256
|
|
|
@@ -498,7 +499,7 @@ extensions/quota-panel.ts Pi TUI line and /usage
|
|
|
498
499
|
## Tests
|
|
499
500
|
|
|
500
501
|
```bash
|
|
501
|
-
node --test tests/*.test.mjs #
|
|
502
|
+
node --test tests/*.test.mjs # 266 tests, fake tokens only, no network
|
|
502
503
|
```
|
|
503
504
|
|
|
504
505
|
Modules covered: `auth.json` parsing and de-duplication, the Claude Code store
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pi quota line — read-only quota for the providers Pi already owns.
|
|
3
3
|
*
|
|
4
|
-
* Surface: nothing at session start. /usage
|
|
4
|
+
* Surface: nothing at session start. Bare /usage shows the panel until the next
|
|
5
|
+
* prompt or a second /usage. /usage box, /usage line or /usage panel pins
|
|
5
6
|
* a surface above the editor, /usage status enables the footer, and /usage hide
|
|
6
7
|
* removes it. No timer or post-turn refresh runs until a surface is on.
|
|
7
8
|
*
|
|
@@ -550,6 +551,18 @@ function summarize(report: QuotaReport): string {
|
|
|
550
551
|
.join(" · ");
|
|
551
552
|
}
|
|
552
553
|
|
|
554
|
+
/** Window names for the one-line account rows (same words as the Omarchy panel). */
|
|
555
|
+
const WINDOW_TAG: Record<string, string> = { "5h": "session", weekly: "week", monthly: "month" };
|
|
556
|
+
|
|
557
|
+
/** A reset countdown in its largest unit, so a row of three stays narrow. */
|
|
558
|
+
function shortDuration(seconds: number | null): string {
|
|
559
|
+
if (seconds === null || !Number.isFinite(seconds)) return "";
|
|
560
|
+
if (seconds <= 0) return "now";
|
|
561
|
+
if (seconds >= 86400) return `${Math.floor(seconds / 86400)}d`;
|
|
562
|
+
if (seconds >= 3600) return `${Math.floor(seconds / 3600)}h`;
|
|
563
|
+
return `${Math.max(1, Math.floor(seconds / 60))}m`;
|
|
564
|
+
}
|
|
565
|
+
|
|
553
566
|
/** The account's fullest window: the one that stops its next prompt. */
|
|
554
567
|
function bindingWindow(provider: QuotaProvider): QuotaWindow | null {
|
|
555
568
|
let best: QuotaWindow | null = null;
|
|
@@ -600,13 +613,17 @@ function renderAccountRows(accounts: QuotaProvider[], theme: Theme): string[] {
|
|
|
600
613
|
lines.push(` ${label} ${theme.fg("dim", "no rate-limit windows reported")}`);
|
|
601
614
|
continue;
|
|
602
615
|
}
|
|
616
|
+
// Every window on one line, each in its own band colour; the leading glyph
|
|
617
|
+
// is the fullest window's, so the column still sorts the accounts by eye.
|
|
603
618
|
const band = bandFor(used);
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
619
|
+
const cells = account.windows
|
|
620
|
+
.filter((each) => usedOf(each) !== null)
|
|
621
|
+
.map((each) => {
|
|
622
|
+
const pct = usedOf(each) as number;
|
|
623
|
+
const reset = each.resetsInSec === null ? "" : ` ${theme.fg("dim", `(${shortDuration(each.resetsInSec)})`.padEnd(5))}`;
|
|
624
|
+
return `${theme.fg("dim", WINDOW_TAG[each.id] ?? each.id)} ${paint(bandFor(pct).color, `${Math.round(pct)}%`.padStart(4))}${reset}`;
|
|
625
|
+
});
|
|
626
|
+
lines.push(` ${label} ${paint(band.color, band.glyph)} ${cells.join(theme.fg("dim", " · "))}`);
|
|
610
627
|
}
|
|
611
628
|
return lines;
|
|
612
629
|
}
|
|
@@ -686,6 +703,11 @@ export default function quotaPanelExtension(pi: ExtensionAPI): void {
|
|
|
686
703
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
687
704
|
let agentEndTimer: ReturnType<typeof setTimeout> | null = null;
|
|
688
705
|
let panelVisible = false;
|
|
706
|
+
/**
|
|
707
|
+
* The panel bare `/usage` opens is a glance, not a pin: it goes away when the
|
|
708
|
+
* next prompt starts or when `/usage` is run again. `/usage panel` pins it.
|
|
709
|
+
*/
|
|
710
|
+
let transientPanel = false;
|
|
689
711
|
/**
|
|
690
712
|
* Nothing is pinned by default. A box or line above the editor is a persistent
|
|
691
713
|
* surface, and a quota command should not claim a row until asked.
|
|
@@ -933,7 +955,17 @@ export default function quotaPanelExtension(pi: ExtensionAPI): void {
|
|
|
933
955
|
paintUi(ui);
|
|
934
956
|
});
|
|
935
957
|
|
|
936
|
-
|
|
958
|
+
function dismissTransientPanel(ui: UiContext): void {
|
|
959
|
+
panelVisible = false;
|
|
960
|
+
transientPanel = false;
|
|
961
|
+
if (!surfaceActive()) stopPolling();
|
|
962
|
+
paintUi(ui);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
pi.on("agent_start", (_event, ctx) => {
|
|
966
|
+
// SAFETY: Pi's agent_start context implements UiContext when hasUI is true.
|
|
967
|
+
const ui = ctx as unknown as UiContext;
|
|
968
|
+
if (transientPanel && panelVisible && ui?.hasUI && !disposed) dismissTransientPanel(ui);
|
|
937
969
|
if (agentEndTimer) {
|
|
938
970
|
clearTimeout(agentEndTimer);
|
|
939
971
|
agentEndTimer = null;
|
|
@@ -1002,6 +1034,7 @@ export default function quotaPanelExtension(pi: ExtensionAPI): void {
|
|
|
1002
1034
|
return;
|
|
1003
1035
|
case "panel":
|
|
1004
1036
|
panelVisible = true;
|
|
1037
|
+
transientPanel = false;
|
|
1005
1038
|
lineVisible = false;
|
|
1006
1039
|
boxVisible = false;
|
|
1007
1040
|
explicitBox = false;
|
|
@@ -1048,8 +1081,15 @@ export default function quotaPanelExtension(pi: ExtensionAPI): void {
|
|
|
1048
1081
|
break;
|
|
1049
1082
|
}
|
|
1050
1083
|
|
|
1084
|
+
// Bare /usage again while its glance is open closes it.
|
|
1085
|
+
if (panelVisible && transientPanel) {
|
|
1086
|
+
dismissTransientPanel(ctx);
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1051
1090
|
// Bare /usage: one on-demand refresh, show the panel, report the percentages.
|
|
1052
1091
|
panelVisible = true;
|
|
1092
|
+
transientPanel = true;
|
|
1053
1093
|
lineVisible = false;
|
|
1054
1094
|
boxVisible = false;
|
|
1055
1095
|
await refresh(ctx, true);
|