dsh-agy-link 0.4.14 → 0.4.15

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.15 (2026-08-24)
4
+
5
+ - **Quota Polling Risk-Exposure Minimization (root-cause follow-up).**
6
+ - **Poll Interval 5min → 15min (configurable)**: New `quotaPollIntervalMs` config (env `DSH_AGY_QUOTA_POLL_INTERVAL_MS`, clamped to >= 60s) cuts background `v1internal` polling volume by 3x — the poller was the last remaining high-frequency network surface after the CLI-level hardening.
7
+ - **Restricted-Account Poll Gating**: Automatic polling now skips disabled, auth-quarantined (`invalid_grant`) and 429-cooldown accounts (`shouldPollAccount`), so the poller never keeps probing Google endpoints for accounts already known to be limited. Manual UI force-refresh still refreshes everything.
8
+ - **Userinfo Endpoint Called Only When Email Unknown**: The primary account previously hit the OAuth userinfo endpoint on every poll cycle just to detect account switching; that detection now rides the local log scan (`detectEmailFromAgyLogs`, zero network), eliminating one network call per cycle.
9
+
3
10
  ## 0.4.14 (2026-08-24)
4
11
 
5
12
  - **Hardened 429 Rate Limit Cooldown & Circuit Breaker (Anti-Risk Control).**
package/dist/index.js CHANGED
@@ -90,7 +90,8 @@ function defaultConfig() {
90
90
  rateLimitPerMinute: 0,
91
91
  autoFallbackModel: false,
92
92
  logRetentionDays: 7,
93
- disableTelemetry: true
93
+ disableTelemetry: true,
94
+ quotaPollIntervalMs: 9e5
94
95
  };
95
96
  }
96
97
  const Err = {
@@ -225,7 +226,8 @@ function resolveConfig(entry, env = process.env, overrides = readOverrides()) {
225
226
  rateLimitPerMinute: asNum(get("rateLimitPerMinute")) ?? base.rateLimitPerMinute,
226
227
  autoFallbackModel: asBool(get("autoFallbackModel")) ?? base.autoFallbackModel,
227
228
  logRetentionDays: asNum(get("logRetentionDays")) ?? base.logRetentionDays,
228
- disableTelemetry: asBool(get("disableTelemetry")) ?? base.disableTelemetry
229
+ disableTelemetry: asBool(get("disableTelemetry")) ?? base.disableTelemetry,
230
+ quotaPollIntervalMs: asNum(get("quotaPollIntervalMs")) ?? base.quotaPollIntervalMs
229
231
  };
230
232
  if (env.DSH_AGY_ENABLED !== void 0) cfg.enabled = asBool(env.DSH_AGY_ENABLED) ?? cfg.enabled;
231
233
  if (env.DSH_AGY_BIN) cfg.agyBin = env.DSH_AGY_BIN;
@@ -271,6 +273,10 @@ function resolveConfig(entry, env = process.env, overrides = readOverrides()) {
271
273
  const dt = asBool(env.DSH_AGY_DISABLE_TELEMETRY);
272
274
  if (dt !== void 0) cfg.disableTelemetry = dt;
273
275
  }
276
+ if (env.DSH_AGY_QUOTA_POLL_INTERVAL_MS) {
277
+ const q = asNum(env.DSH_AGY_QUOTA_POLL_INTERVAL_MS);
278
+ if (q && q >= 6e4) cfg.quotaPollIntervalMs = q;
279
+ }
274
280
  return cfg;
275
281
  }
276
282
  //#endregion
@@ -284,6 +290,20 @@ function modelFamilyOf(modelId) {
284
290
  if (id.startsWith("gpt-") || id.startsWith("openai/") || id.includes("gpt-oss")) return "openai";
285
291
  return "unknown";
286
292
  }
293
+ /**
294
+ * Whether the background quota poller should touch this account at all.
295
+ * Disabled, auth-quarantined and cooldown accounts are skipped so automatic
296
+ * polling never hammers Google endpoints for accounts already known to be
297
+ * restricted (risk-control exposure minimization). Manual force refresh
298
+ * from the UI bypasses this gate.
299
+ */
300
+ function shouldPollAccount(account) {
301
+ if (!account.enabled) return false;
302
+ if (account.authRequired) return false;
303
+ const now = Date.now();
304
+ for (const cd of Object.values(account.cooldowns)) if (cd && cd.cooldownUntil > now) return false;
305
+ return true;
306
+ }
287
307
  function defaultPoolData() {
288
308
  return {
289
309
  version: 1,
@@ -27888,7 +27908,7 @@ var QuotaService = class {
27888
27908
  return null;
27889
27909
  }
27890
27910
  const [summary, discovered] = await Promise.all([this.fetchQuotaSummary(accessToken, account.proxyUrl), this.fetchAvailableModels(accessToken, account.proxyUrl)]);
27891
- if (account.systemHome || !email) {
27911
+ if (!email) {
27892
27912
  const info = await this.fetchUserInfo(accessToken, account.proxyUrl);
27893
27913
  if (info?.email) email = info.email;
27894
27914
  }
@@ -27964,9 +27984,13 @@ var QuotaService = class {
27964
27984
  }
27965
27985
  /**
27966
27986
  * Refresh quota statistics for all accounts in the pool.
27987
+ * Automatic polling (force=false) skips restricted accounts (disabled /
27988
+ * auth-quarantined / in cooldown) so the poller never keeps knocking on
27989
+ * Google endpoints for accounts already known to be limited. Manual force
27990
+ * refresh from the UI refreshes everything.
27967
27991
  */
27968
27992
  async refreshAllQuotas(force = false) {
27969
- const accounts = this.pool.getAccounts();
27993
+ const accounts = force ? this.pool.getAccounts() : this.pool.getAccounts().filter(shouldPollAccount);
27970
27994
  await Promise.allSettled(accounts.map((acc) => this.refreshAccountQuota(acc, force)));
27971
27995
  }
27972
27996
  };
@@ -28830,7 +28854,7 @@ function apply(ctx, entryConfig = {}) {
28830
28854
  quota.refreshAllQuotas().catch(() => void 0);
28831
28855
  };
28832
28856
  const boot = setTimeout(refresh, 5e3);
28833
- const timer = setInterval(refresh, 3e5);
28857
+ const timer = setInterval(refresh, Math.max(6e4, getConfig().quotaPollIntervalMs));
28834
28858
  return () => {
28835
28859
  clearTimeout(boot);
28836
28860
  clearInterval(timer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-agy-link",
3
- "version": "0.4.14",
3
+ "version": "0.4.15",
4
4
  "description": "Google Antigravity (agy CLI) models for DeepSeek Harness — stream Gemini/Claude/GPT-OSS subscriptions into DSH with thinking, tool activity, token usage and in-GUI Google OAuth login.",
5
5
  "type": "module",
6
6
  "license": "MIT",