maxpool 1.5.32 → 1.5.34

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxpool",
3
- "version": "1.5.32",
3
+ "version": "1.5.34",
4
4
  "description": "Multi-account Claude Code proxy with adaptive, rate-aware load balancing across Claude accounts",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -62,6 +62,11 @@ function emptyQuota() {
62
62
  lastProbeError: null, // string
63
63
  lastProbeErrorAt: null, // ms
64
64
  lastProbeErrorStatus: null, // http status (429, 500, …) or null
65
+ // Last time the DISPLAYED bars (unified5h/7d for OAuth, tokens/requests for
66
+ // API-key) were refreshed from a RESPONSE HEADER (updateQuota). Lets the TUI
67
+ // staleness marker tell "probe stale but bars fresh from live traffic" (a busy
68
+ // account — NOT stale) from "genuinely nothing refreshed it" (idle — stale).
69
+ lastHeaderQuotaAt: null, // ms
65
70
  };
66
71
  }
67
72
 
@@ -2118,6 +2123,15 @@ export class AccountManager {
2118
2123
  if (genericRemaining != null) account.quota.genericRemaining = genericRemaining;
2119
2124
  if (genericReset != null) account.quota.genericReset = genericReset;
2120
2125
 
2126
+ // Stamp header-freshness ONLY when a real quota header actually arrived — so a
2127
+ // header-less response never falsely marks the bars fresh. Drives the TUI's
2128
+ // "busy account isn't stale even if its background probe is 429-throttled".
2129
+ const gotQuotaHeader = !isNaN(u5h) || !isNaN(u7d)
2130
+ || !isNaN(tokensLimit) || !isNaN(tokensRemaining)
2131
+ || !isNaN(requestsLimit) || !isNaN(requestsRemaining)
2132
+ || genericLimit != null || genericRemaining != null;
2133
+ if (gotQuotaHeader) account.quota.lastHeaderQuotaAt = Date.now();
2134
+
2121
2135
  account.usage.totalRequests++;
2122
2136
  account.usage.lastUsed = new Date().toISOString();
2123
2137
 
package/src/tui.js CHANGED
@@ -985,7 +985,7 @@ export class TUI {
985
985
  // Glossary FOOTER (expands the abbreviations the header + inline labels can't
986
986
  // spell out). Below the rows so it never breaks the header↔column alignment.
987
987
  if (W >= 88) {
988
- lines.push(' ' + dim('Ses 5h · Wk 7d · Now in-flight (weight) · 15m/1h served (avg · f fails)'));
988
+ lines.push(' ' + dim('Legend Ses = 5h · Wk = 7d · Now = in-flight (weight) · 15m/1h = served (avg · f = fails)'));
989
989
  }
990
990
  }
991
991
 
@@ -1040,13 +1040,16 @@ export class TUI {
1040
1040
 
1041
1041
  _renderAcct(idx, bw, showBoth) {
1042
1042
  const a = this.am.accounts[idx];
1043
- // Highlight the currently-active account. In manual mode that's the
1044
- // preferred account; in automatic mode it's the one most recently routed
1045
- // to (currentIndex). Previously only manual mode highlighted anything, so
1046
- // in automatic load-balancing no row was ever marked current.
1043
+ // Highlight the ACTIVE account(s) — drives BOTH the ► marker and the green
1044
+ // "active" status color. In manual mode that's the single pinned account (all
1045
+ // traffic goes there). In automatic load-balancing there is no single "current"
1046
+ // account, so mark every account SERVING a request right now (inFlight > 0) —
1047
+ // an honest live view of what's working. When idle, nothing is marked; a
1048
+ // throttled/idle provider is never falsely flagged (the old "most recently
1049
+ // routed to" currentIndex could land the marker on an idle fallback).
1047
1050
  const isCur = this.am.routingMode === 'preferred'
1048
1051
  ? a.name === this.am.preferredAccountName
1049
- : idx === this.am.currentIndex;
1052
+ : a.inFlight > 0;
1050
1053
  const isSel = this.mode === 'select' && idx === this.selIdx;
1051
1054
 
1052
1055
  // Prefix: selection marker + current marker
@@ -1174,8 +1177,24 @@ export class TUI {
1174
1177
  // Only annotate probe-staleness for LIVE accounts, where a failing probe
1175
1178
  // (e.g. a 429) is a real, actionable signal.
1176
1179
  if (a?.refreshDead || a?.enabled === false) return '';
1177
- if (!this.am._quotaProbeStale?.(a)) return '';
1178
- const s = a?.quota?.lastProbeErrorStatus;
1180
+ if (!this.am._quotaProbeStale?.(a)) return ''; // probe fresh (or off) → nothing to flag; interval>0 after this
1181
+ // The background probe IS stale — but only flag it if something DISPLAYED is
1182
+ // actually stale. An OAuth account's Ses/Wk bars come from unified5h/7d, which
1183
+ // response headers refresh on every served request (updateQuota → lastHeaderQuotaAt);
1184
+ // so a BUSY oauth account with a header-fresh reading and no probe-only scoped
1185
+ // cap is NOT stale, even if its background probe is 429-throttled. Provider bars
1186
+ // and per-model scoped caps ARE probe-only, so for those a stale probe genuinely
1187
+ // means stale data → keep flagging.
1188
+ const q = a.quota || {};
1189
+ const reserveFloor = this.am.scheduler?.weeklyReserveThreshold ?? 0.85; // mirrors _renderAcct's scoped-tag gate
1190
+ const hasDisplayedScopedCap = Object.values(q.scopedWeekly || {}).some(
1191
+ e => e && e.isActive !== false && e.utilization != null && e.utilization >= reserveFloor);
1192
+ if (a.type !== 'provider' && !hasDisplayedScopedCap) {
1193
+ const interval = this.am.quotaProbeIntervalMs; // > 0 here (else _quotaProbeStale returned false)
1194
+ const headerFresh = q.lastHeaderQuotaAt && (Date.now() - q.lastHeaderQuotaAt) <= Math.max(3 * interval, 180_000);
1195
+ if (headerFresh) return '';
1196
+ }
1197
+ const s = q.lastProbeErrorStatus;
1179
1198
  if (s === 429) return ` ${yellow('stale·rate-limited')}`;
1180
1199
  if (s) return ` ${yellow('stale·probe ' + s)}`;
1181
1200
  return ` ${dim('stale')}`;