@zhafron/opencode-kiro-auth 1.1.2 → 1.1.3

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.
@@ -6,11 +6,13 @@ export declare class AccountManager {
6
6
  private cursor;
7
7
  private strategy;
8
8
  private lastToastTime;
9
+ private lastUsageToastTime;
9
10
  constructor(accounts: ManagedAccount[], usage: Record<string, UsageMetadata>, strategy?: AccountSelectionStrategy);
10
11
  static loadFromDisk(strategy?: AccountSelectionStrategy): Promise<AccountManager>;
11
12
  getAccountCount(): number;
12
13
  getAccounts(): ManagedAccount[];
13
14
  shouldShowToast(debounce?: number): boolean;
15
+ shouldShowUsageToast(debounce?: number): boolean;
14
16
  getMinWaitTime(): number;
15
17
  getCurrentOrNext(): ManagedAccount | null;
16
18
  updateUsage(id: string, meta: {
@@ -11,6 +11,7 @@ export class AccountManager {
11
11
  cursor;
12
12
  strategy;
13
13
  lastToastTime = 0;
14
+ lastUsageToastTime = 0;
14
15
  constructor(accounts, usage, strategy = 'sticky') {
15
16
  this.accounts = accounts;
16
17
  this.usage = usage;
@@ -46,6 +47,12 @@ export class AccountManager {
46
47
  this.lastToastTime = Date.now();
47
48
  return true;
48
49
  }
50
+ shouldShowUsageToast(debounce = 30000) {
51
+ if (Date.now() - this.lastUsageToastTime < debounce)
52
+ return false;
53
+ this.lastUsageToastTime = Date.now();
54
+ return true;
55
+ }
49
56
  getMinWaitTime() {
50
57
  const now = Date.now();
51
58
  const waits = this.accounts.map((a) => (a.rateLimitResetTime || 0) - now).filter((t) => t > 0);
package/dist/plugin.js CHANGED
@@ -16,6 +16,13 @@ const KIRO_API_PATTERN = /^(https?:\/\/)?q\.[a-z0-9-]+\.amazonaws\.com/;
16
16
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
17
17
  const isNetworkError = (e) => e instanceof Error && /econnreset|etimedout|enotfound|network|fetch failed/i.test(e.message);
18
18
  const extractModel = (url) => url.match(/models\/([^/:]+)/)?.[1] || null;
19
+ const formatUsageMessage = (usedCount, limitCount, email) => {
20
+ if (limitCount > 0) {
21
+ const percentage = Math.round((usedCount / limitCount) * 100);
22
+ return `Usage (${email}): ${usedCount}/${limitCount} (${percentage}%)`;
23
+ }
24
+ return `Usage (${email}): ${usedCount}`;
25
+ };
19
26
  export const createKiroPlugin = (id) => async ({ client, directory }) => {
20
27
  const config = loadConfig(directory);
21
28
  const showToast = (message, variant) => {
@@ -51,18 +58,25 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
51
58
  continue;
52
59
  }
53
60
  if (count > 1 && am.shouldShowToast())
54
- showToast(`Using ${acc.email} (${am.getAccounts().indexOf(acc) + 1}/${count})`, 'info');
61
+ showToast(`Using ${acc.realEmail || acc.email} (${am.getAccounts().indexOf(acc) + 1}/${count})`, 'info');
62
+ if (am.shouldShowUsageToast() &&
63
+ acc.usedCount !== undefined &&
64
+ acc.limitCount !== undefined) {
65
+ const percentage = acc.limitCount > 0 ? (acc.usedCount / acc.limitCount) * 100 : 0;
66
+ const variant = percentage >= 80 ? 'warning' : 'info';
67
+ showToast(formatUsageMessage(acc.usedCount, acc.limitCount, acc.realEmail || acc.email), variant);
68
+ }
55
69
  let auth = am.toAuthDetails(acc);
56
70
  if (accessTokenExpired(auth)) {
57
71
  try {
58
- logger.log(`Refreshing token for ${acc.email}`);
72
+ logger.log(`Refreshing token for ${acc.realEmail || acc.email}`);
59
73
  auth = await refreshAccessToken(auth);
60
74
  am.updateFromAuth(acc, auth);
61
75
  await am.saveToDisk();
62
76
  }
63
77
  catch (e) {
64
78
  const msg = e instanceof KiroTokenRefreshError ? e.message : String(e);
65
- showToast(`Refresh failed for ${acc.email}: ${msg}`, 'error');
79
+ showToast(`Refresh failed for ${acc.realEmail || acc.email}: ${msg}`, 'error');
66
80
  if (e instanceof KiroTokenRefreshError && e.code === 'invalid_grant') {
67
81
  am.removeAccount(acc);
68
82
  await am.saveToDisk();
@@ -114,7 +128,7 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
114
128
  updateAccountQuota(acc, u, am);
115
129
  am.saveToDisk();
116
130
  })
117
- .catch((e) => logger.warn(`Usage sync failed for ${acc.email}: ${e.message}`));
131
+ .catch((e) => logger.warn(`Usage sync failed for ${acc.realEmail || acc.email}: ${e.message}`));
118
132
  if (prep.streaming) {
119
133
  const s = transformKiroStream(res, model, prep.conversationId);
120
134
  return new Response(new ReadableStream({
@@ -164,7 +178,7 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
164
178
  });
165
179
  }
166
180
  if (res.status === 401 && retry < config.rate_limit_max_retries) {
167
- logger.warn(`Unauthorized (401) on ${acc.email}, retrying...`);
181
+ logger.warn(`Unauthorized (401) on ${acc.realEmail || acc.email}, retrying...`);
168
182
  retry++;
169
183
  continue;
170
184
  }
@@ -173,7 +187,7 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
173
187
  am.markRateLimited(acc, wait);
174
188
  await am.saveToDisk();
175
189
  if (count > 1) {
176
- showToast(`Rate limited on ${acc.email}. Switching account...`, 'warning');
190
+ showToast(`Rate limited on ${acc.realEmail || acc.email}. Switching account...`, 'warning');
177
191
  continue;
178
192
  }
179
193
  else {
@@ -183,7 +197,7 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
183
197
  }
184
198
  }
185
199
  if ((res.status === 402 || res.status === 403) && count > 1) {
186
- showToast(`${res.status === 402 ? 'Quota exhausted' : 'Forbidden'} on ${acc.email}. Switching...`, 'warning');
200
+ showToast(`${res.status === 402 ? 'Quota exhausted' : 'Forbidden'} on ${acc.realEmail || acc.email}. Switching...`, 'warning');
187
201
  am.markUnhealthy(acc, res.status === 402 ? 'Quota' : 'Forbidden');
188
202
  await am.saveToDisk();
189
203
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhafron/opencode-kiro-auth",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",