@cad0p/pi-usage 0.11.3 → 0.11.4-20261103.1
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 +28 -0
- package/README.md +353 -20
- package/bin/piquota.js +60 -4
- package/extensions/quota-panel.ts +1594 -109
- package/omarchy/cad0p.pi-usage/Agent.qml +33 -0
- package/omarchy/cad0p.pi-usage/Main.qml +333 -0
- package/omarchy/cad0p.pi-usage/Panel.qml +136 -0
- package/omarchy/cad0p.pi-usage/README.md +40 -0
- package/omarchy/cad0p.pi-usage/UsageContent.qml +1001 -0
- package/omarchy/cad0p.pi-usage/UsageLogic.js +608 -0
- package/omarchy/cad0p.pi-usage/assets/antigravity.svg +3 -0
- package/omarchy/cad0p.pi-usage/assets/claude.svg +1 -0
- package/omarchy/cad0p.pi-usage/assets/codex-light.svg +1 -0
- package/omarchy/cad0p.pi-usage/assets/codex.svg +1 -0
- package/omarchy/cad0p.pi-usage/assets/fireworks.svg +7 -0
- package/omarchy/cad0p.pi-usage/assets/github-actions.svg +3 -0
- package/omarchy/cad0p.pi-usage/assets/opencode-go.svg +3 -0
- package/omarchy/cad0p.pi-usage/manifest.json +56 -0
- package/package.json +2 -1
- package/src/auth/pi-auth.js +3 -0
- package/src/cli/args.js +18 -0
- package/src/cli/commands/stats.js +224 -0
- package/src/engine.js +125 -23
- package/src/http.js +34 -1
- package/src/local/history.js +1206 -0
- package/src/local/pi-sessions.js +1527 -0
- package/src/omarchy/publish.js +1 -65
- package/src/omarchy/record.js +100 -18
- package/src/providers/opencode-go.js +4 -3
- package/src/render/panel.js +28 -7
package/bin/piquota.js
CHANGED
|
@@ -19,6 +19,7 @@ import { parseArgs } from "../src/cli/args.js";
|
|
|
19
19
|
import { runAuthCommand } from "../src/cli/commands/auth.js";
|
|
20
20
|
import { runGentlePiCommand } from "../src/cli/commands/gentle-pi.js";
|
|
21
21
|
import { runOmarchyCommand } from "../src/cli/commands/omarchy.js";
|
|
22
|
+
import { runStatsCommand } from "../src/cli/commands/stats.js";
|
|
22
23
|
import { explainLines, resolveFamilies } from "../src/cli/explain.js";
|
|
23
24
|
import { err, out } from "../src/cli/output.js";
|
|
24
25
|
import { collectQuota, enabledFamilies, normalizeClaudeSourceMode } from "../src/engine.js";
|
|
@@ -35,6 +36,20 @@ const VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.u
|
|
|
35
36
|
*/
|
|
36
37
|
const CACHE_KEY = `claude-source:${normalizeClaudeSourceMode(process.env.PI_QUOTA_CLAUDE_SOURCE)}`;
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Local token statistics from Pi's session files are on for the CLI: the Omarchy
|
|
41
|
+
* records and /usage both show them. `PI_QUOTA_LOCAL_STATS=0` turns the scan
|
|
42
|
+
* off (e.g. on a machine where the session store is huge and network quota is
|
|
43
|
+
* all that matters), and the budget keeps a first full scan from delaying a
|
|
44
|
+
* report past the 30 s the /usage extension allows.
|
|
45
|
+
*/
|
|
46
|
+
const LOCAL_STATS_BUDGET_MS = Number(process.env.PI_QUOTA_LOCAL_STATS_BUDGET_MS);
|
|
47
|
+
const LOCAL_STATS = process.env.PI_QUOTA_LOCAL_STATS === "0"
|
|
48
|
+
? false
|
|
49
|
+
: LOCAL_STATS_BUDGET_MS > 0
|
|
50
|
+
? { budgetMs: LOCAL_STATS_BUDGET_MS }
|
|
51
|
+
: {};
|
|
52
|
+
|
|
38
53
|
const HELP = `piquota ${VERSION} — read-only quota from Pi's provider credentials
|
|
39
54
|
|
|
40
55
|
Usage:
|
|
@@ -42,6 +57,7 @@ Usage:
|
|
|
42
57
|
piquota auth <opencode|status> [flags]
|
|
43
58
|
piquota gentle-pi <status|apply|revert>
|
|
44
59
|
piquota omarchy
|
|
60
|
+
piquota stats [--json] [--month YYYY-MM] [--rebuild-totals]
|
|
45
61
|
|
|
46
62
|
Quota:
|
|
47
63
|
--json Emit the normalized report as JSON (for rp-host and automations)
|
|
@@ -56,6 +72,8 @@ Quota:
|
|
|
56
72
|
--no-refresh Never refresh Antigravity's token in memory
|
|
57
73
|
--explain Show which stores/fields are read (names only)
|
|
58
74
|
--clear-cache Delete the local cache and exit
|
|
75
|
+
--rebuild-totals With \`stats\`: rebuild the token-history totals from its month files
|
|
76
|
+
--month YYYY-MM With \`stats\`: read one month (default: the current local month)
|
|
59
77
|
--version Print the version and exit
|
|
60
78
|
|
|
61
79
|
Auth (OpenCode Go session, the only credential Pi does not store):
|
|
@@ -66,18 +84,35 @@ Auth (OpenCode Go session, the only credential Pi does not store):
|
|
|
66
84
|
piquota auth opencode --wait <s> how long to wait for the login (default 180)
|
|
67
85
|
piquota auth status report every credential source
|
|
68
86
|
|
|
87
|
+
Stats:
|
|
88
|
+
piquota stats summarise the durable token history
|
|
89
|
+
(dir: \${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-usage)
|
|
90
|
+
piquota stats --json [--month] read-only JSON: months (the live month always),
|
|
91
|
+
one month's days per family/slot/model, all-time
|
|
92
|
+
totals, notes
|
|
93
|
+
piquota stats --rebuild-totals recompute totals.json from the frozen month files
|
|
94
|
+
|
|
69
95
|
Omarchy:
|
|
70
96
|
piquota omarchy write pi-<family>.json records for Omarchy's Agents bar panel
|
|
71
97
|
(dir: $PI_QUOTA_OMARCHY_DIR or $XDG_STATE_HOME/omarchy/agents/usage)
|
|
72
98
|
run it on a timer: ./install.sh --omarchy-timer
|
|
73
99
|
|
|
100
|
+
Environment:
|
|
101
|
+
PI_QUOTA_LOCAL_STATS=0 skip the token scan of Pi's session files
|
|
102
|
+
PI_QUOTA_LOCAL_STATS_BUDGET_MS wall-clock budget for that scan (default 12000)
|
|
103
|
+
PI_QUOTA_ACCOUNT_CONCURRENCY accounts of one provider queried at once (1-32, default 8)
|
|
104
|
+
|
|
74
105
|
Guarantees:
|
|
75
106
|
* ~/.pi/agent/auth.json is opened read-only. Never written, synced or refreshed.
|
|
107
|
+
* Pi's session files are opened read-only too; the token scan keeps only
|
|
108
|
+
aggregate counts per day and model, never prompt text or session paths.
|
|
76
109
|
* Antigravity's access token may be refreshed in memory; it is never persisted.
|
|
77
110
|
* Browser cookie databases are copied and opened read-only; values are never logged.
|
|
78
|
-
* Only percentages, window labels, reset times
|
|
111
|
+
* Only percentages, window labels, reset times, plan names and aggregate token
|
|
112
|
+
counts leave this machine.
|
|
79
113
|
* \`omarchy\` (opt-in) writes only pi-*.json records, atomically, into Omarchy's usage dir;
|
|
80
|
-
records hold plan names, percentages, window labels
|
|
114
|
+
records hold plan names, percentages, window labels, reset times and aggregate
|
|
115
|
+
token counts, never prompt text or accounts.
|
|
81
116
|
* \`gentle-pi\` is the one file this tool edits outside its own state: it appends
|
|
82
117
|
piQuota's part to gentle-pi's rail allowlist so the card can be painted there.
|
|
83
118
|
The edit is one array literal, it is reversible with \`piquota gentle-pi revert\`,
|
|
@@ -122,10 +157,30 @@ async function main() {
|
|
|
122
157
|
return runGentlePiCommand(sub);
|
|
123
158
|
}
|
|
124
159
|
|
|
160
|
+
if (args.rebuildTotals && command !== "stats") {
|
|
161
|
+
// The flag repairs one thing (the all-time rollup) and reads nothing else,
|
|
162
|
+
// so running it beside `piquota` or `piquota omarchy` would silently skip
|
|
163
|
+
// the command the user asked for.
|
|
164
|
+
err("--rebuild-totals only works with `piquota stats`\n");
|
|
165
|
+
process.stdout.write(HELP);
|
|
166
|
+
return 2;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (args.month && command !== "stats") {
|
|
170
|
+
err("--month only works with \`piquota stats\`\n");
|
|
171
|
+
process.stdout.write(HELP);
|
|
172
|
+
return 2;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (command === "stats") {
|
|
176
|
+
return runStatsCommand({ rebuild: args.rebuildTotals, json: args.json, month: args.month, env: process.env });
|
|
177
|
+
}
|
|
178
|
+
|
|
125
179
|
if (command === "omarchy") {
|
|
126
180
|
const load = async () => {
|
|
127
181
|
const everyFamily = enabledFamilies({ env: process.env });
|
|
128
|
-
const loadFresh = () =>
|
|
182
|
+
const loadFresh = () =>
|
|
183
|
+
collectQuota({ families: everyFamily, timeoutMs: args.timeoutMs, refresh, force: args.force, localStats: LOCAL_STATS });
|
|
129
184
|
const fresh = args.noCache
|
|
130
185
|
? await loadFresh()
|
|
131
186
|
: (await withCache({ ttlMs: args.ttlMs, force: args.force, families: everyFamily, key: CACHE_KEY }, loadFresh)).report;
|
|
@@ -149,7 +204,8 @@ async function main() {
|
|
|
149
204
|
requested: families.length > 0 ? families : undefined,
|
|
150
205
|
explicit,
|
|
151
206
|
});
|
|
152
|
-
const load = () =>
|
|
207
|
+
const load = () =>
|
|
208
|
+
collectQuota({ families: selected, explicit, timeoutMs: args.timeoutMs, refresh, force: args.force, localStats: LOCAL_STATS });
|
|
153
209
|
|
|
154
210
|
let report;
|
|
155
211
|
let cached = false;
|