@howaboua/opencode-usage-plugin 0.1.5 → 0.1.6

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,KAAK,EAAgF,WAAW,EAAE,MAAM,aAAa,CAAA;AAK5H,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA4B5C;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,MAAM,GAAG,IAAI,CAoBf;AAqLD,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,IAAI,CAwB7C,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,KAAK,EAAgF,WAAW,EAAE,MAAM,aAAa,CAAA;AAK5H,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA4B5C;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,MAAM,GAAG,IAAI,CAoBf;AAyND,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,IAAI,CAwB7C,CAAA"}
@@ -63,6 +63,25 @@ function normalizeTier(tier) {
63
63
  return "paid";
64
64
  return "free";
65
65
  }
66
+ function pickPreferredResetTime(current, incoming) {
67
+ if (!incoming)
68
+ return current ?? null;
69
+ if (!current)
70
+ return incoming;
71
+ const now = Date.now();
72
+ const currentTs = new Date(current).getTime();
73
+ const incomingTs = new Date(incoming).getTime();
74
+ const currentFuture = currentTs > now;
75
+ const incomingFuture = incomingTs > now;
76
+ if (currentFuture && incomingFuture) {
77
+ return incomingTs < currentTs ? incoming : current;
78
+ }
79
+ if (incomingFuture)
80
+ return incoming;
81
+ if (currentFuture)
82
+ return current;
83
+ return incomingTs > currentTs ? incoming : current;
84
+ }
66
85
  function parseQuotaGroupsFromAggregation(quotaGroups, config) {
67
86
  if (!quotaGroups)
68
87
  return [];
@@ -147,10 +166,9 @@ function parseQuotaGroupsFromCredential(groupUsage, config) {
147
166
  return Array.from(result.values());
148
167
  }
149
168
  function aggregateByProvider(provider, config) {
150
- // Try aggregated quota groups first
151
- if (provider.quota_groups && Object.keys(provider.quota_groups).length > 0) {
152
- return parseQuotaGroupsFromAggregation(provider.quota_groups, config);
153
- }
169
+ const aggregated = provider.quota_groups && Object.keys(provider.quota_groups).length > 0
170
+ ? parseQuotaGroupsFromAggregation(provider.quota_groups, config)
171
+ : [];
154
172
  // Fallback to manual aggregation of credentials
155
173
  const tiers = {
156
174
  paid: new Map(),
@@ -165,9 +183,7 @@ function aggregateByProvider(provider, config) {
165
183
  if (existing) {
166
184
  existing.remaining += group.remaining;
167
185
  existing.max += group.max;
168
- if (group.resetTime && (!existing.resetTime || new Date(group.resetTime) > new Date(existing.resetTime))) {
169
- existing.resetTime = group.resetTime;
170
- }
186
+ existing.resetTime = pickPreferredResetTime(existing.resetTime, group.resetTime);
171
187
  }
172
188
  else {
173
189
  tiers[tier].set(group.name, { ...group });
@@ -175,6 +191,20 @@ function aggregateByProvider(provider, config) {
175
191
  }
176
192
  }
177
193
  }
194
+ if (aggregated.length > 0) {
195
+ const resetLookup = new Map();
196
+ for (const tierInfo of Object.values(tiers)) {
197
+ for (const group of tierInfo.values()) {
198
+ resetLookup.set(group.name, pickPreferredResetTime(resetLookup.get(group.name), group.resetTime));
199
+ }
200
+ }
201
+ for (const tier of aggregated) {
202
+ for (const group of tier.quotaGroups) {
203
+ group.resetTime = pickPreferredResetTime(group.resetTime, resetLookup.get(group.name));
204
+ }
205
+ }
206
+ return aggregated;
207
+ }
178
208
  for (const tierGroups of Object.values(tiers)) {
179
209
  for (const group of tierGroups.values()) {
180
210
  group.remainingPct = group.max > 0 ? Math.round((group.remaining / group.max) * 100) : 0;
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAcrE"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAOhD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAcrE"}
@@ -22,10 +22,16 @@ function formatProxyProvider(provider) {
22
22
  if (!tier.quotaGroups?.length)
23
23
  continue;
24
24
  lines.push(` ${tier.tier === "paid" ? "Paid" : "Free"}:`);
25
- for (const group of tier.quotaGroups) {
26
- const reset = group.resetTime ? formatResetSuffixISO(group.resetTime) : "";
27
- lines.push(` ${group.name.padEnd(9)} ${formatBar(group.remainingPct)} ${group.remaining}/${group.max}${reset}`);
28
- }
25
+ lines.push(...formatTierGroups(tier.quotaGroups));
29
26
  }
30
27
  return lines;
31
28
  }
29
+ function formatTierGroups(groups) {
30
+ const nameWidth = Math.max(...groups.map(group => group.name.length), 9);
31
+ const quotaWidth = Math.max(...groups.map(group => `${group.remaining}/${group.max}`.length), 7);
32
+ return groups.map(group => {
33
+ const reset = group.resetTime ? formatResetSuffixISO(group.resetTime) : "";
34
+ const quota = `${group.remaining}/${group.max}`.padStart(quotaWidth);
35
+ return ` ${group.name.padEnd(nameWidth)} ${formatBar(group.remainingPct)} ${quota}${reset}`;
36
+ });
37
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK7C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGhE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKxD;AAaD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAgBvE"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK7C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIhE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMxD;AAwBD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAgBvE"}
@@ -13,12 +13,14 @@ export function formatBar(pct) {
13
13
  export function formatResetSuffix(resetAt) {
14
14
  if (!resetAt)
15
15
  return "";
16
- return ` (resets in ${formatTimeDelta(resetAt)})`;
16
+ const delta = formatTimeDelta(resetAt);
17
+ return delta === "just refreshed" ? ` (${delta})` : ` (resets in ${delta})`;
17
18
  }
18
19
  export function formatResetSuffixISO(iso) {
19
20
  try {
20
21
  const at = Math.floor(new Date(iso).getTime() / 1000);
21
- return ` (resets in ${formatTimeDelta(at)})`;
22
+ const delta = formatTimeDelta(at);
23
+ return delta === "just refreshed" ? ` (${delta})` : ` (resets in ${delta})`;
22
24
  }
23
25
  catch {
24
26
  return "";
@@ -28,14 +30,19 @@ function formatTimeDelta(at) {
28
30
  const atSeconds = at > 1e11 ? Math.floor(at / 1000) : at;
29
31
  const diff = atSeconds - Math.floor(Date.now() / 1000);
30
32
  if (diff <= 0)
31
- return "now";
32
- if (diff < 60)
33
- return `${diff}s`;
34
- if (diff < 3600)
35
- return `${Math.ceil(diff / 60)}m`;
36
- if (diff < 86400)
37
- return `${Math.round(diff / 3600)}h`;
38
- return `${Math.round(diff / 86400)}d`;
33
+ return "just refreshed";
34
+ const days = Math.floor(diff / 86400);
35
+ const hours = Math.floor((diff % 86400) / 3600);
36
+ const minutes = Math.floor((diff % 3600) / 60);
37
+ if (days > 0) {
38
+ return hours > 0 ? `${days}d${hours}hrs` : `${days}d`;
39
+ }
40
+ if (hours > 0) {
41
+ return minutes > 0 ? `${hours}hrs${minutes}m` : `${hours}hrs`;
42
+ }
43
+ if (minutes > 0)
44
+ return `${minutes}m`;
45
+ return `${diff}s`;
39
46
  }
40
47
  export function formatMissingSnapshot(snapshot) {
41
48
  const { provider } = snapshot;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howaboua/opencode-usage-plugin",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "opencode plugin for tracking AI provider usage, rate limits, and quotas",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",