@bacnh85/pi-sub 0.1.9 → 0.1.10
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 +2 -6
- package/{index.ts → extensions/index.ts} +10 -66
- package/extensions/package.json +3 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -15,13 +15,9 @@ pi install npm:@bacnh85/pi-sub
|
|
|
15
15
|
From this repository checkout:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
|
|
19
|
-
npm install
|
|
20
|
-
cd ../..
|
|
21
|
-
|
|
22
|
-
pi install ./extensions/pi-sub
|
|
18
|
+
pi install ./pi-sub
|
|
23
19
|
# or test directly
|
|
24
|
-
pi -e ./
|
|
20
|
+
pi -e ./pi-sub
|
|
25
21
|
```
|
|
26
22
|
|
|
27
23
|
## What it shows
|
|
@@ -20,7 +20,6 @@ type ModelLike = { provider?: string; id?: string } | undefined;
|
|
|
20
20
|
|
|
21
21
|
type UsageApiWindow = {
|
|
22
22
|
used_percent?: number;
|
|
23
|
-
limit_window_seconds?: number;
|
|
24
23
|
reset_at?: number;
|
|
25
24
|
};
|
|
26
25
|
|
|
@@ -46,14 +45,10 @@ type PiAuthEntry = {
|
|
|
46
45
|
};
|
|
47
46
|
|
|
48
47
|
interface UsageWindow {
|
|
49
|
-
used?: number;
|
|
50
|
-
limit?: number;
|
|
51
48
|
percent?: number;
|
|
52
49
|
remaining?: number;
|
|
53
50
|
remainingLabel?: string;
|
|
54
51
|
resetLabel?: string;
|
|
55
|
-
resetsAt?: string | number | Date;
|
|
56
|
-
label?: string;
|
|
57
52
|
}
|
|
58
53
|
|
|
59
54
|
interface SubscriptionAccountSnapshot {
|
|
@@ -63,12 +58,10 @@ interface SubscriptionAccountSnapshot {
|
|
|
63
58
|
plan?: string;
|
|
64
59
|
fiveHour?: UsageWindow;
|
|
65
60
|
weekly?: UsageWindow;
|
|
66
|
-
monthly?: UsageWindow;
|
|
67
61
|
lastActivity?: string;
|
|
68
62
|
}
|
|
69
63
|
|
|
70
64
|
interface SubscriptionUsageSnapshot {
|
|
71
|
-
providerId: string;
|
|
72
65
|
providerDisplayName: string;
|
|
73
66
|
accounts: SubscriptionAccountSnapshot[];
|
|
74
67
|
activeAccount?: SubscriptionAccountSnapshot;
|
|
@@ -77,12 +70,11 @@ interface SubscriptionUsageSnapshot {
|
|
|
77
70
|
cost?: number;
|
|
78
71
|
}
|
|
79
72
|
|
|
80
|
-
|
|
73
|
+
type SubscriptionProviderAdapter = {
|
|
81
74
|
id: string;
|
|
82
75
|
displayName: string;
|
|
83
|
-
isModelSupported(model: ModelLike): boolean;
|
|
84
76
|
fetchUsage(signal?: AbortSignal): Promise<SubscriptionUsageSnapshot>;
|
|
85
|
-
}
|
|
77
|
+
};
|
|
86
78
|
|
|
87
79
|
interface State {
|
|
88
80
|
model?: ModelLike;
|
|
@@ -246,8 +238,6 @@ function usageWindowFromApi(window: UsageApiWindow | undefined): UsageWindow | u
|
|
|
246
238
|
remaining,
|
|
247
239
|
remainingLabel,
|
|
248
240
|
resetLabel,
|
|
249
|
-
resetsAt: window.reset_at,
|
|
250
|
-
label: remainingLabel ? `${remaining}% (${remainingLabel})` : `${remaining}%`,
|
|
251
241
|
};
|
|
252
242
|
}
|
|
253
243
|
|
|
@@ -270,7 +260,6 @@ function parseUsageResponse(body: unknown): UsageApiSnapshot | undefined {
|
|
|
270
260
|
if (!window || typeof window !== "object" || typeof window.used_percent !== "number") return undefined;
|
|
271
261
|
return {
|
|
272
262
|
used_percent: window.used_percent,
|
|
273
|
-
limit_window_seconds: typeof window.limit_window_seconds === "number" ? window.limit_window_seconds : undefined,
|
|
274
263
|
reset_at: typeof window.reset_at === "number" ? window.reset_at : undefined,
|
|
275
264
|
};
|
|
276
265
|
};
|
|
@@ -289,13 +278,11 @@ async function readPiCodexAuth(): Promise<PiAuthEntry & { accountId: string }> {
|
|
|
289
278
|
return { ...entry, accountId };
|
|
290
279
|
}
|
|
291
280
|
|
|
292
|
-
async function readOpenCodeGoAuth(): Promise<
|
|
281
|
+
async function readOpenCodeGoAuth(): Promise<SubscriptionAccountSnapshot> {
|
|
293
282
|
const auth = await readJsonFile<PiAuthFile>(piAuthPath());
|
|
294
283
|
const entry = auth[OPC_PROVIDER];
|
|
295
284
|
if (!entry?.key && !entry?.accountId) throw new Error("Missing opencode-go API key or accountId in Pi auth");
|
|
296
|
-
|
|
297
|
-
if (typeof entry.key === "string") return { key: entry.key, account };
|
|
298
|
-
return { accountId: typeof entry.accountId === "string" ? entry.accountId : undefined, account };
|
|
285
|
+
return authAccountSnapshot("OpenCode Go", entry, { plan: "Go" });
|
|
299
286
|
}
|
|
300
287
|
|
|
301
288
|
async function readZaiAuth(): Promise<{ key: string; account: SubscriptionAccountSnapshot }> {
|
|
@@ -341,7 +328,6 @@ async function fetchCodexUsage(signal?: AbortSignal): Promise<SubscriptionUsageS
|
|
|
341
328
|
const usage = await fetchUsageFromPiAuth(entry, signal);
|
|
342
329
|
activeAccount = mergeUsageIntoAccount(activeAccount, usage);
|
|
343
330
|
return {
|
|
344
|
-
providerId: CODEX_PROVIDER,
|
|
345
331
|
providerDisplayName: "Codex",
|
|
346
332
|
accounts: [activeAccount],
|
|
347
333
|
activeAccount,
|
|
@@ -349,7 +335,6 @@ async function fetchCodexUsage(signal?: AbortSignal): Promise<SubscriptionUsageS
|
|
|
349
335
|
};
|
|
350
336
|
} catch (error) {
|
|
351
337
|
return {
|
|
352
|
-
providerId: CODEX_PROVIDER,
|
|
353
338
|
providerDisplayName: "Codex",
|
|
354
339
|
accounts: [],
|
|
355
340
|
fetchedAt: Date.now(),
|
|
@@ -360,9 +345,8 @@ async function fetchCodexUsage(signal?: AbortSignal): Promise<SubscriptionUsageS
|
|
|
360
345
|
|
|
361
346
|
async function fetchOpenCodeGoUsage(_signal?: AbortSignal): Promise<SubscriptionUsageSnapshot> {
|
|
362
347
|
try {
|
|
363
|
-
const
|
|
348
|
+
const account = await readOpenCodeGoAuth();
|
|
364
349
|
return {
|
|
365
|
-
providerId: OPC_PROVIDER,
|
|
366
350
|
providerDisplayName: "OpenCode Go",
|
|
367
351
|
accounts: [account],
|
|
368
352
|
activeAccount: account,
|
|
@@ -370,7 +354,6 @@ async function fetchOpenCodeGoUsage(_signal?: AbortSignal): Promise<Subscription
|
|
|
370
354
|
};
|
|
371
355
|
} catch (error) {
|
|
372
356
|
return {
|
|
373
|
-
providerId: OPC_PROVIDER,
|
|
374
357
|
providerDisplayName: "OpenCode Go",
|
|
375
358
|
accounts: [],
|
|
376
359
|
fetchedAt: Date.now(),
|
|
@@ -418,8 +401,6 @@ function zaiLimitToUsageWindow(limit: ZaiLimitEntry): UsageWindow | undefined {
|
|
|
418
401
|
remaining,
|
|
419
402
|
remainingLabel,
|
|
420
403
|
resetLabel,
|
|
421
|
-
resetsAt: limit.nextResetTime,
|
|
422
|
-
label: remainingLabel ? `${remaining}% (${remainingLabel})` : `${remaining}%`,
|
|
423
404
|
};
|
|
424
405
|
}
|
|
425
406
|
|
|
@@ -473,7 +454,6 @@ async function fetchZaiUsage(signal?: AbortSignal): Promise<SubscriptionUsageSna
|
|
|
473
454
|
};
|
|
474
455
|
|
|
475
456
|
return {
|
|
476
|
-
providerId: ZAI_PROVIDER,
|
|
477
457
|
providerDisplayName: "Z.ai",
|
|
478
458
|
accounts: [account],
|
|
479
459
|
activeAccount: account,
|
|
@@ -481,7 +461,6 @@ async function fetchZaiUsage(signal?: AbortSignal): Promise<SubscriptionUsageSna
|
|
|
481
461
|
};
|
|
482
462
|
} catch (error) {
|
|
483
463
|
return {
|
|
484
|
-
providerId: ZAI_PROVIDER,
|
|
485
464
|
providerDisplayName: "Z.ai",
|
|
486
465
|
accounts: [],
|
|
487
466
|
fetchedAt: Date.now(),
|
|
@@ -490,31 +469,11 @@ async function fetchZaiUsage(signal?: AbortSignal): Promise<SubscriptionUsageSna
|
|
|
490
469
|
}
|
|
491
470
|
}
|
|
492
471
|
|
|
493
|
-
const codexAdapter: SubscriptionProviderAdapter = {
|
|
494
|
-
id: CODEX_PROVIDER,
|
|
495
|
-
displayName: "Codex",
|
|
496
|
-
isModelSupported: isCodexModel,
|
|
497
|
-
fetchUsage: fetchCodexUsage,
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
const openCodeGoAdapter: SubscriptionProviderAdapter = {
|
|
501
|
-
id: OPC_PROVIDER,
|
|
502
|
-
displayName: "OpenCode Go",
|
|
503
|
-
isModelSupported: isOpenCodeGoModel,
|
|
504
|
-
fetchUsage: fetchOpenCodeGoUsage,
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
const zaiAdapter: SubscriptionProviderAdapter = {
|
|
508
|
-
id: ZAI_PROVIDER,
|
|
509
|
-
displayName: "Z.ai",
|
|
510
|
-
isModelSupported: isZaiModel,
|
|
511
|
-
fetchUsage: fetchZaiUsage,
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
const adapters = [codexAdapter, openCodeGoAdapter, zaiAdapter];
|
|
515
|
-
|
|
516
472
|
function supportedAdapter(model: ModelLike): SubscriptionProviderAdapter | undefined {
|
|
517
|
-
|
|
473
|
+
if (isCodexModel(model)) return { id: CODEX_PROVIDER, displayName: "Codex", fetchUsage: fetchCodexUsage };
|
|
474
|
+
if (isOpenCodeGoModel(model)) return { id: OPC_PROVIDER, displayName: "OpenCode Go", fetchUsage: fetchOpenCodeGoUsage };
|
|
475
|
+
if (isZaiModel(model)) return { id: ZAI_PROVIDER, displayName: "Z.ai", fetchUsage: fetchZaiUsage };
|
|
476
|
+
return undefined;
|
|
518
477
|
}
|
|
519
478
|
|
|
520
479
|
function formatRemaining(window: UsageWindow | undefined): string {
|
|
@@ -525,20 +484,10 @@ function formatRemaining(window: UsageWindow | undefined): string {
|
|
|
525
484
|
return "?";
|
|
526
485
|
}
|
|
527
486
|
|
|
528
|
-
function formatWindow(window: UsageWindow | undefined, _compact = true): string {
|
|
529
|
-
if (!window) return "?";
|
|
530
|
-
if (window.percent !== undefined && window.resetLabel) return `${window.percent}% (${window.resetLabel})`;
|
|
531
|
-
if (window.label) return window.label;
|
|
532
|
-
if (window.percent !== undefined) return `${window.percent}%`;
|
|
533
|
-
if (window.used !== undefined && window.limit !== undefined) return `${window.used}/${window.limit}`;
|
|
534
|
-
return "?";
|
|
535
|
-
}
|
|
536
|
-
|
|
537
487
|
function minRemaining(account: SubscriptionAccountSnapshot | undefined): number {
|
|
538
488
|
const values: number[] = [];
|
|
539
489
|
if (account?.fiveHour?.remaining !== undefined) values.push(account.fiveHour.remaining);
|
|
540
490
|
if (account?.weekly?.remaining !== undefined) values.push(account.weekly.remaining);
|
|
541
|
-
if (account?.monthly?.remaining !== undefined) values.push(account.monthly.remaining);
|
|
542
491
|
if (values.length === 0) return 100;
|
|
543
492
|
return Math.min(...values);
|
|
544
493
|
}
|
|
@@ -548,7 +497,6 @@ function windowSegments(account: SubscriptionAccountSnapshot | undefined): strin
|
|
|
548
497
|
const segments: string[] = [];
|
|
549
498
|
if (account.fiveHour) segments.push(`R:${formatRemaining(account.fiveHour)}`);
|
|
550
499
|
if (account.weekly) segments.push(`W:${formatRemaining(account.weekly)}`);
|
|
551
|
-
if (account.monthly) segments.push(`M:${formatRemaining(account.monthly)}`);
|
|
552
500
|
return segments;
|
|
553
501
|
}
|
|
554
502
|
|
|
@@ -688,12 +636,8 @@ function buildDetails(snapshot: SubscriptionUsageSnapshot | undefined, state: St
|
|
|
688
636
|
|
|
689
637
|
const hasFiveHour = snapshot.accounts.some((a) => a.fiveHour);
|
|
690
638
|
const hasWeekly = snapshot.accounts.some((a) => a.weekly);
|
|
691
|
-
const hasMonthly = snapshot.accounts.some((a) => a.monthly);
|
|
692
|
-
|
|
693
639
|
if (hasFiveHour) columns.push({ key: "five", label: "ROLLING", get: (a) => formatRemaining(a.fiveHour) });
|
|
694
640
|
if (hasWeekly) columns.push({ key: "weekly", label: "WEEKLY", get: (a) => formatRemaining(a.weekly) });
|
|
695
|
-
if (hasMonthly) columns.push({ key: "monthly", label: "MONTHLY", get: (a) => formatRemaining(a.monthly) });
|
|
696
|
-
|
|
697
641
|
const rows = snapshot.accounts.map((account) => ({
|
|
698
642
|
active: account.isActive ? "*" : " ",
|
|
699
643
|
snapshot: account,
|
|
@@ -714,7 +658,7 @@ function buildDetails(snapshot: SubscriptionUsageSnapshot | undefined, state: St
|
|
|
714
658
|
|
|
715
659
|
const costLine = snapshot.cost !== undefined ? `\nSession cost: $${snapshot.cost.toFixed(2)}` : "";
|
|
716
660
|
const lines = [`Provider: ${snapshot.providerDisplayName} · Model: ${state.model?.id ?? "unknown-model"} · Fetched: ${new Date(snapshot.fetchedAt).toLocaleTimeString()}${costLine}`, "", header, sep, ...body];
|
|
717
|
-
if (!hasFiveHour && !hasWeekly
|
|
661
|
+
if (!hasFiveHour && !hasWeekly) {
|
|
718
662
|
lines.push("", `${snapshot.providerDisplayName} does not expose usage windows.`);
|
|
719
663
|
}
|
|
720
664
|
return lines.join("\n");
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bacnh85/pi-sub",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Pi extension showing subscription usage for supported model providers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
10
|
-
"homepage": "https://github.com/bacnh85/
|
|
10
|
+
"homepage": "https://github.com/bacnh85/pi-extensions#readme",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/bacnh85/
|
|
14
|
-
"directory": "
|
|
13
|
+
"url": "git+https://github.com/bacnh85/pi-extensions.git",
|
|
14
|
+
"directory": "pi-sub"
|
|
15
15
|
},
|
|
16
16
|
"bugs": {
|
|
17
|
-
"url": "https://github.com/bacnh85/
|
|
17
|
+
"url": "https://github.com/bacnh85/pi-extensions/issues"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
20
20
|
"pi-package",
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
],
|
|
27
27
|
"files": [
|
|
28
28
|
"README.md",
|
|
29
|
-
"
|
|
29
|
+
"extensions/"
|
|
30
30
|
],
|
|
31
31
|
"pi": {
|
|
32
32
|
"extensions": [
|
|
33
|
-
"./index.ts"
|
|
33
|
+
"./extensions/index.ts"
|
|
34
34
|
]
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|