@anthonyhaussman/opencode-agy-auth 1.0.11-alpha.0 → 1.0.11-alpha.2

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/dist/index.js CHANGED
@@ -212,6 +212,23 @@ async function retrieveUserQuota(accessToken, projectId, userAgentModel) {
212
212
  return null;
213
213
  }
214
214
  }
215
+ async function retrieveUserQuotaSummary(accessToken, projectId, userAgentModel) {
216
+ const url2 = `${AGY_CODE_ASSIST_ENDPOINT}/v1internal:retrieveUserQuotaSummary`;
217
+ const headers = buildCodeAssistHeaders(accessToken, userAgentModel);
218
+ try {
219
+ const response = await agyFetch(url2, {
220
+ method: "POST",
221
+ headers,
222
+ body: JSON.stringify({ project: projectId })
223
+ });
224
+ if (!response.ok) {
225
+ return null;
226
+ }
227
+ return await response.json();
228
+ } catch {
229
+ return null;
230
+ }
231
+ }
215
232
  function buildCodeAssistHeaders(accessToken, userAgentModel) {
216
233
  const userAgent = buildAgyCliUserAgent(userAgentModel);
217
234
  return {
@@ -14142,6 +14159,65 @@ async function fetchTokenRefresh(refreshToken) {
14142
14159
  return agyFetch(tokenUrl, init);
14143
14160
  }
14144
14161
 
14162
+ // src/plugin/quota-utils.ts
14163
+ function clamp(value, min, max) {
14164
+ if (Number.isNaN(value)) {
14165
+ return min;
14166
+ }
14167
+ if (value < min) {
14168
+ return min;
14169
+ }
14170
+ if (value > max) {
14171
+ return max;
14172
+ }
14173
+ return value;
14174
+ }
14175
+ function pad(value, width) {
14176
+ if (value.length >= width) {
14177
+ return value;
14178
+ }
14179
+ return value.padEnd(width, " ");
14180
+ }
14181
+ function buildProgressBar(fraction, width = 20) {
14182
+ const clamped = clamp(fraction, 0, 1);
14183
+ const filled = clamped >= 1 ? width : Math.max(0, Math.min(width, Math.max(clamped > 0 ? 1 : 0, Math.floor(clamped * width))));
14184
+ const empty = width - filled;
14185
+ return `${"\u2593".repeat(filled)}${"\u2591".repeat(empty)}`;
14186
+ }
14187
+ function formatRemainingAmount(value) {
14188
+ if (!value) {
14189
+ return void 0;
14190
+ }
14191
+ const parsed = Number(value);
14192
+ if (!Number.isFinite(parsed)) {
14193
+ return value;
14194
+ }
14195
+ return parsed.toLocaleString("en-US");
14196
+ }
14197
+ function formatRelativeResetTime(resetTime) {
14198
+ if (!resetTime) {
14199
+ return void 0;
14200
+ }
14201
+ const resetAt = new Date(resetTime).getTime();
14202
+ if (Number.isNaN(resetAt)) {
14203
+ return void 0;
14204
+ }
14205
+ const diffMs = resetAt - Date.now();
14206
+ if (diffMs <= 0) {
14207
+ return "reset pending";
14208
+ }
14209
+ const totalMinutes = Math.ceil(diffMs / (1e3 * 60));
14210
+ const hours = Math.floor(totalMinutes / 60);
14211
+ const minutes = totalMinutes % 60;
14212
+ if (hours > 0 && minutes > 0) {
14213
+ return `resets in ${hours}h ${minutes}m`;
14214
+ }
14215
+ if (hours > 0) {
14216
+ return `resets in ${hours}h`;
14217
+ }
14218
+ return `resets in ${minutes}m`;
14219
+ }
14220
+
14145
14221
  // src/plugin/quota.ts
14146
14222
  var AGY_QUOTA_TOOL_NAME = "agy_quota";
14147
14223
  function createAgyQuotaTool({
@@ -14269,60 +14345,6 @@ function formatUsageRemaining(bucket) {
14269
14345
  }
14270
14346
  return "unknown";
14271
14347
  }
14272
- function formatRemainingAmount(value) {
14273
- if (!value) {
14274
- return void 0;
14275
- }
14276
- const parsed = Number.parseInt(value, 10);
14277
- if (!Number.isFinite(parsed)) {
14278
- return value;
14279
- }
14280
- return parsed.toLocaleString("en-US");
14281
- }
14282
- function formatRelativeResetTime(resetTime) {
14283
- if (!resetTime) {
14284
- return void 0;
14285
- }
14286
- const resetAt = new Date(resetTime).getTime();
14287
- if (Number.isNaN(resetAt)) {
14288
- return void 0;
14289
- }
14290
- const diffMs = resetAt - Date.now();
14291
- if (diffMs <= 0) {
14292
- return "reset pending";
14293
- }
14294
- const totalMinutes = Math.ceil(diffMs / (1e3 * 60));
14295
- const hours = Math.floor(totalMinutes / 60);
14296
- const minutes = totalMinutes % 60;
14297
- if (hours > 0 && minutes > 0) {
14298
- return `resets in ${hours}h ${minutes}m`;
14299
- }
14300
- if (hours > 0) {
14301
- return `resets in ${hours}h`;
14302
- }
14303
- return `resets in ${minutes}m`;
14304
- }
14305
- function buildProgressBar(fraction, width = 20) {
14306
- const clamped = clamp(fraction, 0, 1);
14307
- const filled = clamped >= 1 ? width : Math.max(0, Math.min(width, Math.max(clamped > 0 ? 1 : 0, Math.floor(clamped * width))));
14308
- const empty = width - filled;
14309
- return `${"\u2593".repeat(filled)}${"\u2591".repeat(empty)}`;
14310
- }
14311
- function pad(value, width) {
14312
- if (value.length >= width) {
14313
- return value;
14314
- }
14315
- return value.padEnd(width, " ");
14316
- }
14317
- function clamp(value, min, max) {
14318
- if (value < min) {
14319
- return min;
14320
- }
14321
- if (value > max) {
14322
- return max;
14323
- }
14324
- return value;
14325
- }
14326
14348
  function normalizeTokenType(bucket) {
14327
14349
  const value = bucket.tokenType?.trim();
14328
14350
  return value ? value.toUpperCase() : "REQUESTS";
@@ -14435,6 +14457,208 @@ function splitModelVariant(modelId) {
14435
14457
  };
14436
14458
  }
14437
14459
 
14460
+ // src/plugin/quota-summary.ts
14461
+ var AGY_QUOTA_SUMMARY_TOOL_NAME = "agy_quota_summary";
14462
+ function createAgyQuotaSummaryTool({
14463
+ client,
14464
+ getAuthResolver,
14465
+ getConfiguredProjectId,
14466
+ getUserAgentModel
14467
+ }) {
14468
+ return tool({
14469
+ description: "Retrieve Agy Code Assist quota summary with weekly and 5-hour limits grouped by model family.",
14470
+ args: {},
14471
+ async execute() {
14472
+ const getAuth = getAuthResolver();
14473
+ if (!getAuth) {
14474
+ return "Agy quota summary is unavailable before Google auth is initialized. Authenticate with the Google provider and retry.";
14475
+ }
14476
+ const auth = await getAuth();
14477
+ if (!isOAuthAuth(auth)) {
14478
+ return "Agy quota summary requires OAuth with Google. Run `opencode auth login` and choose `Google OAuth (Antigravity CLI)` or `Google OAuth (Gemini CLI)`.";
14479
+ }
14480
+ let authRecord = resolveCachedAuth(auth);
14481
+ if (accessTokenExpired(authRecord)) {
14482
+ const refreshed = await refreshAccessToken(authRecord, client);
14483
+ if (!refreshed?.access) {
14484
+ return "Agy quota summary lookup failed because the access token could not be refreshed. Re-authenticate and retry.";
14485
+ }
14486
+ authRecord = refreshed;
14487
+ }
14488
+ if (!authRecord.access) {
14489
+ return "Agy quota summary lookup failed because no access token is available. Re-authenticate and retry.";
14490
+ }
14491
+ try {
14492
+ const projectContext = await ensureProjectContext(
14493
+ authRecord,
14494
+ client,
14495
+ getConfiguredProjectId(),
14496
+ getUserAgentModel()
14497
+ );
14498
+ if (!projectContext.effectiveProjectId) {
14499
+ return "Agy quota summary lookup failed because no Google Cloud project could be resolved.";
14500
+ }
14501
+ const summary = await retrieveUserQuotaSummary(
14502
+ authRecord.access,
14503
+ projectContext.effectiveProjectId,
14504
+ getUserAgentModel()
14505
+ );
14506
+ if (!summary) {
14507
+ return `No Agy quota summary available for project \`${projectContext.effectiveProjectId}\`.`;
14508
+ }
14509
+ return formatAgyQuotaSummaryOutput(
14510
+ projectContext.effectiveProjectId,
14511
+ summary
14512
+ );
14513
+ } catch (error45) {
14514
+ const message = error45 instanceof Error ? error45.message : "unknown error";
14515
+ return `Agy quota summary lookup failed: ${message}`;
14516
+ }
14517
+ }
14518
+ });
14519
+ }
14520
+ var BAR_WIDTH = 50;
14521
+ function windowLabel(window) {
14522
+ switch (window?.toUpperCase()) {
14523
+ case "WEEKLY":
14524
+ return "Weekly Limit";
14525
+ case "FIVE_HOUR":
14526
+ return "Five Hour Limit";
14527
+ default:
14528
+ return "Other Limit";
14529
+ }
14530
+ }
14531
+ function formatSummaryBucket(bucket, indent) {
14532
+ if (bucket.disabled) {
14533
+ const defaultDesc = `${windowLabel(bucket.window).toLowerCase()} exhausted`;
14534
+ const desc = bucket.description?.trim() || defaultDesc;
14535
+ return [`${indent}Disabled: ${desc}`];
14536
+ }
14537
+ const lines = [];
14538
+ const fraction = bucket.remainingFraction;
14539
+ const hasFraction = typeof fraction === "number" && Number.isFinite(fraction);
14540
+ if (hasFraction) {
14541
+ const clamped = clamp(fraction, 0, 1);
14542
+ const percent = (clamped * 100).toFixed(2);
14543
+ const bar = buildProgressBar(clamped, BAR_WIDTH);
14544
+ lines.push(`${indent}[${bar}] ${percent}%`);
14545
+ const remaining = formatRemainingAmount(bucket.remainingAmount);
14546
+ if (remaining) {
14547
+ const pctWhole = (clamped * 100).toFixed(0);
14548
+ lines.push(`${indent}${pctWhole}% remaining \xB7 ${remaining} left`);
14549
+ } else {
14550
+ const pctWhole = (clamped * 100).toFixed(0);
14551
+ lines.push(`${indent}${pctWhole}% remaining`);
14552
+ }
14553
+ } else {
14554
+ const remaining = formatRemainingAmount(bucket.remainingAmount);
14555
+ lines.push(remaining ? `${indent}${remaining} remaining` : `${indent}unknown remaining`);
14556
+ }
14557
+ const resetLabel = formatRelativeResetTime(bucket.resetTime);
14558
+ if (resetLabel) {
14559
+ const formattedReset = resetLabel.startsWith("resets in ") ? resetLabel.replace("resets in ", "Refreshes in ") : resetLabel.charAt(0).toUpperCase() + resetLabel.slice(1);
14560
+ lines.push(`${indent}${formattedReset}`);
14561
+ }
14562
+ return lines;
14563
+ }
14564
+ function groupBucketsByWindow(buckets) {
14565
+ const groups = /* @__PURE__ */ new Map();
14566
+ const order = ["WEEKLY", "FIVE_HOUR"];
14567
+ for (const bucket of buckets) {
14568
+ const key = bucket.window?.toUpperCase() || "UNKNOWN";
14569
+ const existing = groups.get(key);
14570
+ if (existing) {
14571
+ existing.push(bucket);
14572
+ } else {
14573
+ groups.set(key, [bucket]);
14574
+ }
14575
+ }
14576
+ const sorted = /* @__PURE__ */ new Map();
14577
+ for (const key of order) {
14578
+ const group = groups.get(key);
14579
+ if (group) {
14580
+ sorted.set(key, group);
14581
+ }
14582
+ }
14583
+ for (const [key, group] of groups) {
14584
+ if (!sorted.has(key)) {
14585
+ sorted.set(key, group);
14586
+ }
14587
+ }
14588
+ return sorted;
14589
+ }
14590
+ function formatSummaryGroup(group) {
14591
+ const lines = [];
14592
+ const name = group.displayName?.trim();
14593
+ if (name) {
14594
+ lines.push(name);
14595
+ }
14596
+ const desc = group.description?.trim();
14597
+ if (desc) {
14598
+ lines.push(` Models within this group: ${desc}`);
14599
+ }
14600
+ const buckets = group.buckets;
14601
+ if (buckets?.length) {
14602
+ const windowGroups = groupBucketsByWindow(buckets);
14603
+ let firstWindow = true;
14604
+ for (const [, windowBuckets] of windowGroups) {
14605
+ if (!firstWindow) {
14606
+ lines.push("");
14607
+ }
14608
+ for (const bucket of windowBuckets) {
14609
+ const baseLabel = windowLabel(bucket.window);
14610
+ const label = bucket.displayName ? `${baseLabel} (${bucket.displayName})` : baseLabel;
14611
+ lines.push(` ${label}`);
14612
+ lines.push(...formatSummaryBucket(bucket, " "));
14613
+ firstWindow = false;
14614
+ }
14615
+ }
14616
+ }
14617
+ return lines;
14618
+ }
14619
+ function formatTopLevelBuckets(buckets) {
14620
+ const lines = [];
14621
+ const windowGroups = groupBucketsByWindow(buckets);
14622
+ let firstWindow = true;
14623
+ for (const [, windowBuckets] of windowGroups) {
14624
+ if (!firstWindow) {
14625
+ lines.push("");
14626
+ }
14627
+ for (const bucket of windowBuckets) {
14628
+ const baseLabel = windowLabel(bucket.window);
14629
+ const label = bucket.displayName ? `${baseLabel} (${bucket.displayName})` : baseLabel;
14630
+ lines.push(label);
14631
+ lines.push(...formatSummaryBucket(bucket, " "));
14632
+ firstWindow = false;
14633
+ }
14634
+ }
14635
+ return lines;
14636
+ }
14637
+ function formatAgyQuotaSummaryOutput(projectId, summary) {
14638
+ const lines = [
14639
+ `Agy quota summary for project \`${projectId}\``,
14640
+ ""
14641
+ ];
14642
+ const groups = summary.groups;
14643
+ if (groups?.length) {
14644
+ for (let i = 0; i < groups.length; i++) {
14645
+ const group = groups[i];
14646
+ if (!group) {
14647
+ continue;
14648
+ }
14649
+ if (i > 0) {
14650
+ lines.push("");
14651
+ }
14652
+ lines.push(...formatSummaryGroup(group));
14653
+ }
14654
+ } else if (summary.buckets?.length) {
14655
+ lines.push(...formatTopLevelBuckets(summary.buckets));
14656
+ } else {
14657
+ lines.push("No quota information available.");
14658
+ }
14659
+ return lines.join("\n");
14660
+ }
14661
+
14438
14662
  // src/plugin/notify.ts
14439
14663
  var MODEL_CAPACITY_TOAST_COOLDOWN_MS = 3e4;
14440
14664
  var modelCapacityToastCooldownByKey = /* @__PURE__ */ new Map();
@@ -17243,6 +17467,12 @@ var AGY_QUOTA_COMMAND_TEMPLATE = `Retrieve Agy Code Assist quota usage for the c
17243
17467
  Immediately call \`${AGY_QUOTA_TOOL_NAME}\` with no arguments and return its output verbatim.
17244
17468
  Do not call other tools.
17245
17469
  `;
17470
+ var AGY_QUOTA_SUMMARY_COMMAND = "agyquotasummary";
17471
+ var AGY_QUOTA_SUMMARY_COMMAND_TEMPLATE = `Retrieve Agy Code Assist quota summary (weekly and 5-hour limits by model group) for the current authenticated account.
17472
+
17473
+ Immediately call \`${AGY_QUOTA_SUMMARY_TOOL_NAME}\` with no arguments and return its output verbatim.
17474
+ Do not call other tools.
17475
+ `;
17246
17476
  var latestAgyAuthResolver;
17247
17477
  var latestAgyConfiguredProjectId;
17248
17478
  var latestAgyUserAgentModel;
@@ -17489,6 +17719,10 @@ var AgyCLIOAuthPlugin = async ({ client }) => {
17489
17719
  description: "Show Agy Code Assist quota usage",
17490
17720
  template: AGY_QUOTA_COMMAND_TEMPLATE
17491
17721
  };
17722
+ config2.command[AGY_QUOTA_SUMMARY_COMMAND] = {
17723
+ description: "Show Agy Code Assist quota summary with weekly and 5-hour limits",
17724
+ template: AGY_QUOTA_SUMMARY_COMMAND_TEMPLATE
17725
+ };
17492
17726
  config2.provider = config2.provider || {};
17493
17727
  config2.provider[AGY_PROVIDER_ID] = {
17494
17728
  npm: "@ai-sdk/google",
@@ -17505,6 +17739,12 @@ var AgyCLIOAuthPlugin = async ({ client }) => {
17505
17739
  getAuthResolver: () => latestAgyAuthResolver,
17506
17740
  getConfiguredProjectId: () => latestAgyConfiguredProjectId,
17507
17741
  getUserAgentModel: () => latestAgyUserAgentModel
17742
+ }),
17743
+ [AGY_QUOTA_SUMMARY_TOOL_NAME]: createAgyQuotaSummaryTool({
17744
+ client,
17745
+ getAuthResolver: () => latestAgyAuthResolver,
17746
+ getConfiguredProjectId: () => latestAgyConfiguredProjectId,
17747
+ getUserAgentModel: () => latestAgyUserAgentModel
17508
17748
  })
17509
17749
  },
17510
17750
  auth: {