@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 CHANGED
@@ -15,13 +15,9 @@ pi install npm:@bacnh85/pi-sub
15
15
  From this repository checkout:
16
16
 
17
17
  ```bash
18
- cd extensions/pi-sub
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 ./extensions/pi-sub
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
- interface SubscriptionProviderAdapter {
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<{ key?: string; accountId?: string; account: SubscriptionAccountSnapshot }> {
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
- const account = authAccountSnapshot("OpenCode Go", entry, { plan: "Go" });
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 { account } = await readOpenCodeGoAuth();
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
- return adapters.find((adapter) => adapter.isModelSupported(model));
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 && !hasMonthly) {
661
+ if (!hasFiveHour && !hasWeekly) {
718
662
  lines.push("", `${snapshot.providerDisplayName} does not expose usage windows.`);
719
663
  }
720
664
  return lines.join("\n");
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-sub",
3
- "version": "0.1.9",
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/skills#readme",
10
+ "homepage": "https://github.com/bacnh85/pi-extensions#readme",
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "git+https://github.com/bacnh85/skills.git",
14
- "directory": "extensions/pi-sub"
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/skills/issues"
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
- "index.ts"
29
+ "extensions/"
30
30
  ],
31
31
  "pi": {
32
32
  "extensions": [
33
- "./index.ts"
33
+ "./extensions/index.ts"
34
34
  ]
35
35
  },
36
36
  "engines": {