@ohgodtamit/pi-usage 0.1.0-alpha.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prices.d.ts","sourceRoot":"","sources":["../src/prices.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAuC3D,CAAC"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Active-provider detection and live quota fetching.
3
+ *
4
+ * The usage panel surfaces TWO independent signals about your active provider:
5
+ *
6
+ * 1. Live money quota — fetched from the provider's billing API when it has
7
+ * one (OpenRouter credits, OpenAI costs). This is the
8
+ * provider's own view of your account.
9
+ * 2. Rate-limit headers — captured from every provider HTTP response via the
10
+ * `after_provider_response` event. These are universal
11
+ * (Anthropic, OpenAI, OpenRouter, Google, … all return
12
+ * them) and reflect the live per-window limits applied
13
+ * to your current API key.
14
+ *
15
+ * API keys are resolved through the session's model registry, the same path pi
16
+ * uses for request-time credentials and OAuth refresh.
17
+ */
18
+ import type { Api, Model } from "@earendil-works/pi-ai";
19
+ import { type ModelRegistry } from "@earendil-works/pi-coding-agent";
20
+ /** Resolve a provider's current request credential, including refreshed OAuth. */
21
+ export declare function resolveApiKey(modelRegistry: ModelRegistry, provider: string): Promise<string | undefined>;
22
+ /** Check whether pi can currently resolve authentication for a provider. */
23
+ export declare function hasProviderKey(modelRegistry: ModelRegistry, provider: string): Promise<boolean>;
24
+ export interface ActiveProvider {
25
+ provider: string;
26
+ modelId: string;
27
+ baseUrl: string;
28
+ api: string;
29
+ /** True when an API key for this provider is resolvable from the environment. */
30
+ hasKey: boolean;
31
+ }
32
+ /** Detect the currently active provider/model from the session context. */
33
+ export declare function detectActiveProvider(modelRegistry: ModelRegistry, model: Model<Api> | undefined): Promise<ActiveProvider | null>;
34
+ export interface RateLimitWindow {
35
+ /** "requests" | "tokens" | "input-tokens" | "output-tokens" */
36
+ resource: string;
37
+ /** Approximate window label, e.g. "tokens/min". Heuristic per provider tier. */
38
+ window: string;
39
+ limit: number;
40
+ remaining: number;
41
+ /** Epoch ms when the window resets, or 0 if unknown. */
42
+ resetMs: number;
43
+ }
44
+ export interface ProviderQuota {
45
+ active: ActiveProvider | null;
46
+ fetchedAt: number;
47
+ /** Live account credits (OpenRouter). Undefined when not applicable/available. */
48
+ credits?: {
49
+ total: number;
50
+ used: number;
51
+ remaining: number;
52
+ };
53
+ /** Live provider spend in USD (OpenAI organization/costs API). Best-effort. */
54
+ spend5h?: number;
55
+ spend7d?: number;
56
+ monthlyLimit?: number;
57
+ /**
58
+ * Provider-native plan quotas (ZAI GLM coding plans, OpenAI Codex subscription):
59
+ * session (5h) and weekly (7d) windows reported directly by the upstream as a
60
+ * used percentage with a live reset countdown. These replace the session-derived bars.
61
+ */
62
+ planQuota?: {
63
+ plan: string;
64
+ session5h?: {
65
+ usedPct: number;
66
+ resetMs: number;
67
+ };
68
+ weekly?: {
69
+ usedPct: number;
70
+ resetMs: number;
71
+ };
72
+ webSearches?: {
73
+ used: number;
74
+ limit: number;
75
+ resetMs: number;
76
+ };
77
+ /** Purchased credits balance (OpenAI Codex), when reported. */
78
+ credits?: {
79
+ balance: number;
80
+ unlimited: boolean;
81
+ };
82
+ };
83
+ /** Rate-limit windows captured from the most recent provider response. */
84
+ rateLimits: RateLimitWindow[];
85
+ /** "live" if a billing API responded, "headers" if only rate-limit headers, "none" otherwise. */
86
+ source: "live" | "headers" | "none";
87
+ /** Human hints (e.g. why live quota is unavailable). */
88
+ notes: string[];
89
+ error?: string;
90
+ }
91
+ /**
92
+ * Parse provider rate-limit headers into structured windows.
93
+ *
94
+ * Recognizes three conventions and de-dupes by resource:
95
+ * - Anthropic: `anthropic-ratelimit-{resource}-{limit|remaining|reset}`
96
+ * - OpenAI: `x-ratelimit-{limit|remaining|reset}-{resource}`
97
+ * - Generic: `x-ratelimit-{limit|remaining|reset}` (older/simpler APIs)
98
+ *
99
+ * Pi lowercases all header keys, so matching is case-insensitive by contract.
100
+ */
101
+ export declare function parseRateLimits(headers: Record<string, string>, now?: number): RateLimitWindow[];
102
+ /**
103
+ * Parse a reset value into an epoch-ms timestamp.
104
+ *
105
+ * Handles ISO-8601 timestamps ("2024-01-01T12:00:00Z"), OpenAI-style durations
106
+ * ("6m0s", "500ms", "2h"), and bare-seconds integers.
107
+ */
108
+ export declare function parseReset(value: string | undefined, now: number): number;
109
+ /**
110
+ * Parse OpenAI Codex subscription quota from response headers captured via
111
+ * `after_provider_response`. This is the reliable path: the headers come fresh
112
+ * from pi's own authenticated Codex request, so there is no token/refresh
113
+ * management (unlike the `/wham/usage` REST endpoint, whose OAuth token in
114
+ * `~/.codex/auth.json` is frequently stale/rotated).
115
+ *
116
+ * Header families (authoritative: openai/codex rate_limits.rs):
117
+ * x-codex-primary-used-percent — 5h rolling window used % (0-100)
118
+ * x-codex-primary-reset-at — unix SECONDS of next reset
119
+ * x-codex-secondary-used-percent — 7-day rolling window used %
120
+ * x-codex-secondary-reset-at — unix SECONDS
121
+ * x-codex-credits-has-credits / -unlimited / -balance — purchased credits
122
+ * x-codex-limit-name — plan/limit display name
123
+ *
124
+ * Returns the planQuota shape (shared with ZAI) when any Codex window is present.
125
+ */
126
+ export declare function parseCodexQuota(headers: Record<string, string>): NonNullable<ProviderQuota["planQuota"]> | undefined;
127
+ /**
128
+ * Fetch OpenAI Codex subscription quota from the REST endpoint using pi's
129
+ * request-time credential resolver, which refreshes OAuth before returning.
130
+ */
131
+ export declare function fetchCodexQuota(modelRegistry: ModelRegistry, provider?: string, signal?: AbortSignal): Promise<{
132
+ quota: NonNullable<ProviderQuota["planQuota"]>;
133
+ error?: string;
134
+ } | {
135
+ quota: undefined;
136
+ error: string;
137
+ } | undefined>;
138
+ /**
139
+ * Build a full provider quota snapshot: merge already-captured rate-limit
140
+ * headers with a fresh live fetch from the provider's billing API (if any).
141
+ *
142
+ * `capturedRateLimits` comes from the `after_provider_response` event in the
143
+ * orchestrator (index.ts), so it reflects the most recent real request made by
144
+ * the active provider.
145
+ */
146
+ export declare function fetchProviderQuota(modelRegistry: ModelRegistry, active: ActiveProvider | null, capturedRateLimits: RateLimitWindow[], capturedHeaders?: Record<string, string>, signal?: AbortSignal): Promise<ProviderQuota>;
147
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
package/dist/view.d.ts ADDED
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Interactive usage panel TUI component.
3
+ *
4
+ * Rendered via ctx.ui.custom(). Mirrors Claude Code's `/usage` screen:
5
+ * always-visible 5-hour and weekly quota bars, a selectable time window, and
6
+ * independent-characteristic breakdowns by model / skill / plugin / tool /
7
+ * project. Supports vertical scrolling for small terminals.
8
+ */
9
+ import type { Theme } from "@earendil-works/pi-coding-agent";
10
+ import type { TUI } from "@earendil-works/pi-tui";
11
+ import { type AttributionMaps, type Report, type StatsRange, type WindowKey } from "./aggregate.ts";
12
+ import { type ViewKey } from "./mascot.ts";
13
+ import type { ProviderQuota } from "./provider.ts";
14
+ export type { ViewKey } from "./mascot.ts";
15
+ /** Sort field for the Models table. */
16
+ type SortKey = "value" | "name";
17
+ /** Sort field + direction for the Daily table. */
18
+ type DailySortField = "tokens" | "cost" | "date";
19
+ /** Semantic controls shared by terminal key handling and portable UI clients. */
20
+ export type UsageAction = {
21
+ type: "view";
22
+ view: ViewKey;
23
+ } | {
24
+ type: "window";
25
+ window: WindowKey;
26
+ } | {
27
+ type: "modelSort";
28
+ sort: SortKey;
29
+ } | {
30
+ type: "dailySort";
31
+ sort: DailySortField;
32
+ } | {
33
+ type: "statsRange";
34
+ range: StatsRange;
35
+ } | {
36
+ type: "providerSort";
37
+ sort: SortKey;
38
+ } | {
39
+ type: "wrappedYear";
40
+ year: number;
41
+ } | {
42
+ type: "wrappedYearDelta";
43
+ delta: number;
44
+ } | {
45
+ type: "refresh";
46
+ } | {
47
+ type: "configure";
48
+ } | {
49
+ type: "close";
50
+ };
51
+ export interface UsageViewDeps {
52
+ theme: Theme;
53
+ tui: TUI | undefined;
54
+ maps: AttributionMaps;
55
+ home: string;
56
+ getConfig: () => {
57
+ fiveHourLimit?: number;
58
+ weeklyLimit?: number;
59
+ fiveHourTokenLimit?: number;
60
+ weeklyTokenLimit?: number;
61
+ };
62
+ onClose: () => void;
63
+ onRefresh: () => void;
64
+ onConfigure: () => void;
65
+ }
66
+ export declare class UsageView {
67
+ private readonly deps;
68
+ private portableRendering;
69
+ private state;
70
+ constructor(deps: UsageViewDeps);
71
+ /** Set the initial view (used by /usage-models, /usage-daily, … shortcuts). */
72
+ setInitialView(view: ViewKey): void;
73
+ get activeView(): ViewKey;
74
+ get wrappedYears(): number[];
75
+ /** Apply a UI-independent dashboard action. */
76
+ applyAction(action: UsageAction): void;
77
+ /** Re-bind the TUI/theme/close callback once pi's custom() factory runs. */
78
+ bind(tui: TUI, theme: Theme, onClose: () => void): void;
79
+ setReport(report: Report): void;
80
+ setScanning(loaded: number, total: number): void;
81
+ setError(message: string): void;
82
+ setProviderQuota(quota: ProviderQuota): void;
83
+ handleInput(data: string): void;
84
+ render(width: number): string[];
85
+ /** Render all lines without terminal viewport assumptions or key-based instructions. */
86
+ renderPortable(width: number): string[];
87
+ /** Final width clamp so one long line can never break the TUI layout. */
88
+ private clampLine;
89
+ invalidate(): void;
90
+ private availableHeight;
91
+ private setWindow;
92
+ private setView;
93
+ private cycleView;
94
+ private setStatsRange;
95
+ /** Set the Daily sort field; pressing the same field again flips direction. */
96
+ private setDailySort;
97
+ private cycleWrappedYear;
98
+ private scrollBy;
99
+ private scrollTo;
100
+ private clampScroll;
101
+ private buildLines;
102
+ /**
103
+ * Subscription-aware breakdown unit: token-priced providers (Codex, ZAI
104
+ * plans) always show tokens; otherwise USD when the window has real cost.
105
+ */
106
+ private unitForWindow;
107
+ private renderOverview;
108
+ /** Render the always-on quota bars (plan quota or session-derived budget). */
109
+ private renderQuotaBlock;
110
+ private renderModels;
111
+ /**
112
+ * Models table styled like the Skills section (name · % · bar · value), with
113
+ * an extra column for the average generation speed (estimated tok/s).
114
+ */
115
+ private appendModelTable;
116
+ private renderDelegation;
117
+ private windowDuration;
118
+ private zeroBucket;
119
+ private addUsageToBucket;
120
+ private renderDaily;
121
+ private renderHourly;
122
+ private renderProviders;
123
+ private renderWrapped;
124
+ /** Hairline section label — matches Stats/Daily report rhythm. */
125
+ private wrappedSectionHeader;
126
+ /** Pi-chan footer card — character accent, professional tone. */
127
+ private wrappedInsightBox;
128
+ /** Side-by-side mascot + content when the terminal is wide enough. */
129
+ private appendMascotBlock;
130
+ private wrappedBannerLine;
131
+ private appendWrappedHero;
132
+ private appendWrappedMonthly;
133
+ /**
134
+ * Claude Code / Stats-style vertical month columns: graded blocks, month
135
+ * labels, Less→More legend, and a peak-month callout.
136
+ */
137
+ private appendWrappedMonthlyHeatmap;
138
+ /** Narrow-terminal fallback: horizontal share bars (same geometry as Rankings). */
139
+ private appendWrappedMonthlyRows;
140
+ private appendWrappedHighlights;
141
+ private appendWrappedTops;
142
+ private renderStats;
143
+ /** Interactive range selector for the Stats view (All / 7d / 30d). */
144
+ private statsRangeLine;
145
+ /** Render stat pairs in two aligned columns. */
146
+ private appendStatGrid;
147
+ /** A playful one-liner comparing total usage to a familiar reference. */
148
+ private statsFunFact;
149
+ /**
150
+ * GitHub-style contribution heatmap: a month-label header row, then 7 day
151
+ * rows (Sun..Sat) of graded square cells, then a Less→More legend.
152
+ */
153
+ private heatmapColor;
154
+ /** Map a 0–1 usage ratio to heatmap intensity (matches Stats view). */
155
+ private heatmapLevel;
156
+ private appendContribGraph;
157
+ /** Sparkline of the last 30 active-window days (Overview trend strip). */
158
+ private appendTrendSparkline;
159
+ private portableMenuLines;
160
+ private menuLines;
161
+ private titleLineRaw;
162
+ private windowTabs;
163
+ private subheaderLine;
164
+ private quotaLine;
165
+ /**
166
+ * Render an upstream-reported percentage quota bar (e.g. ZAI 5h/weekly).
167
+ * The provider only exposes `usedPct` (0-100) + a reset countdown, so the bar
168
+ * shows used%, remaining%, and when the window resets.
169
+ */
170
+ private percentLine;
171
+ /**
172
+ * Build a context-aware hint explaining why the subscription quota isn't
173
+ * shown yet. Subscriptions (OpenAI Codex, ZAI coding plans) get their quota
174
+ * from the upstream — the panel must never suggest `/usage-config` for
175
+ * these, because that would be wrong (it would just aggregate session
176
+ * history, not the real plan quota).
177
+ */
178
+ private buildSubscriptionHint;
179
+ private appendTokenComposition;
180
+ private statsLine;
181
+ private topConsumer;
182
+ /** Render the active-provider banner + live quota + rate-limit windows. */
183
+ private appendProviderSection;
184
+ /** Compact single-line bar: `[label] ██████░░░░ right` */
185
+ private miniBar;
186
+ /**
187
+ * One aligned table-header row: the section title fills the label column and
188
+ * the column labels (`%`, value unit, optional extra) sit directly above
189
+ * their data columns. Keeps every breakdown section visually consistent.
190
+ */
191
+ private tableHeader;
192
+ private appendToolsSection;
193
+ private appendSection;
194
+ /**
195
+ * Plugin usage section: ranks plugins by their attributed usage and shows the
196
+ * specific skills/tools that drove each one, plus the "core" remainder
197
+ * (turns with only builtin tools and no skill — i.e. plain pi usage).
198
+ *
199
+ * Plugins are independent characteristics: a single turn can credit several
200
+ * plugins, so the percentages need not sum to 100. The core line is the
201
+ * complement (turns attributed to NO plugin).
202
+ */
203
+ private appendPluginUsageSection;
204
+ private portableFooterLine;
205
+ private footerLine;
206
+ }
207
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
package/dist/zai.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Pure ZAI (Zhipu / GLM coding plans) quota-limit classification.
3
+ *
4
+ * Extracted from provider.ts into its own module so it has ZERO pi / pi-ai
5
+ * runtime dependencies and is unit-testable without network or auth. The
6
+ * network layer (provider.ts) imports `classifyZaiLimits` from here.
7
+ *
8
+ * The return shape is structurally compatible with the `planQuota` field on
9
+ * provider.ts's `ProviderQuota` (a subset: ZAI never reports purchased
10
+ * credits, only the 5h/weekly windows + web searches), so it can be returned
11
+ * directly from `fetchZaiPlanQuota`.
12
+ */
13
+ /** A single quota window in ZAI's /quota/limit response. */
14
+ export interface ZaiQuotaLimit {
15
+ type?: string;
16
+ unit?: number;
17
+ number?: number;
18
+ usage?: number;
19
+ currentValue?: number;
20
+ remaining?: number;
21
+ percentage?: number;
22
+ nextResetTime?: number;
23
+ }
24
+ /** Provider-native plan quota fragment produced from a ZAI limits array. */
25
+ export interface ZaiPlanQuota {
26
+ plan: string;
27
+ session5h?: {
28
+ usedPct: number;
29
+ resetMs: number;
30
+ };
31
+ weekly?: {
32
+ usedPct: number;
33
+ resetMs: number;
34
+ };
35
+ webSearches?: {
36
+ used: number;
37
+ limit: number;
38
+ resetMs: number;
39
+ };
40
+ }
41
+ /**
42
+ * Classify a ZAI /quota/limit `limits[]` into the planQuota shape.
43
+ *
44
+ * PURE function (no network). Detection strategy (robust across ZAI plan
45
+ * tiers and regions):
46
+ * 1. Prefer the documented exact identifiers verified on the "max" plan:
47
+ * session 5h = (unit 3, number 5), weekly 7d = (unit 6, number 1).
48
+ * 2. Fall back to positional pairing: ZAI only ever reports these two
49
+ * token windows, so the window that is NOT the session is the weekly.
50
+ * This keeps weekly resolving when other plans/regions encode the window
51
+ * with different unit/number values — the production bug where only the
52
+ * 5h bar appeared for non-"max" accounts.
53
+ * 3. When neither exact code matches, assign by reset-window length: the
54
+ * shorter countdown maps to the 5h session, the longer to weekly.
55
+ */
56
+ export declare function classifyZaiLimits(limits: ZaiQuotaLimit[], level: string): ZaiPlanQuota | undefined;
57
+ //# sourceMappingURL=zai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zai.d.ts","sourceRoot":"","sources":["../src/zai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAChE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,aAAa,EAAE,EACvB,KAAK,EAAE,MAAM,GACZ,YAAY,GAAG,SAAS,CAiD1B"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@ohgodtamit/pi-usage",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Usage dashboards, attribution, and live provider quotas for Pi",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/GodTamIt/pi-mono.git",
8
+ "directory": "packages/pi-usage"
9
+ },
10
+ "homepage": "https://github.com/GodTamIt/pi-mono/tree/master/packages/pi-usage#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/GodTamIt/pi-mono/issues"
13
+ },
14
+ "license": "MIT",
15
+ "type": "module",
16
+ "keywords": [
17
+ "pi-package"
18
+ ],
19
+ "engines": {
20
+ "node": ">=22.22.2"
21
+ },
22
+ "files": [
23
+ "src",
24
+ "dist",
25
+ "README.md",
26
+ "CHANGELOG.md",
27
+ "LICENSE",
28
+ "THIRD_PARTY_NOTICES.md"
29
+ ],
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./src/index.ts"
34
+ }
35
+ },
36
+ "pi": {
37
+ "extensions": [
38
+ "./src/index.ts"
39
+ ]
40
+ },
41
+ "scripts": {
42
+ "typecheck": "tsc --noEmit --declaration false --declarationMap false",
43
+ "unit": "vitest run",
44
+ "test": "npm run unit",
45
+ "declarations": "node --input-type=module -e \"import { rmSync } from 'node:fs'; rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.declarations.json",
46
+ "prepack": "npm run declarations",
47
+ "pack:inspect": "node ./scripts/inspect-package.mjs",
48
+ "smoke:installed": "node ./test/installed/smoke.mjs"
49
+ },
50
+ "peerDependencies": {
51
+ "@earendil-works/pi-coding-agent": ">=0.84.3 <0.85.0",
52
+ "@earendil-works/pi-ai": ">=0.84.3 <0.85.0",
53
+ "@earendil-works/pi-tui": ">=0.84.3 <0.85.0"
54
+ },
55
+ "devDependencies": {
56
+ "@earendil-works/pi-coding-agent": "0.84.3",
57
+ "@earendil-works/pi-ai": "0.84.3",
58
+ "@earendil-works/pi-tui": "0.84.3"
59
+ }
60
+ }