maxpool 1.13.2 → 1.14.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tui.js +45 -84
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxpool",
3
- "version": "1.13.2",
3
+ "version": "1.14.0",
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",
package/src/tui.js CHANGED
@@ -2030,120 +2030,81 @@ export class TUI {
2030
2030
  const win = this.capacityWindow === 'wk' ? 'wk' : 'ses';
2031
2031
  const ledger = this.am.capacity;
2032
2032
  const title = win === 'wk' ? 'Weekly (7d) capacity' : 'Session (5h) capacity';
2033
+ const windowLabel = win === 'wk' ? '7d windows' : '5h windows';
2033
2034
  out.push('');
2034
- out.push(` ${bold(title)} ${dim('— how many tokens each account can deliver per window')}`);
2035
+ out.push(` ${bold(title)} ${dim(`— tokens per ${windowLabel}, from completed cycles`)}`);
2035
2036
  out.push('');
2036
2037
 
2037
2038
  if (!ledger) { out.push(yellow(' Capacity ledger unavailable on this worker.')); return out; }
2038
2039
 
2039
- // Narrow terminals: drop trailing columns rather than let fitLine chop a number
2040
- // mid-digit (at W=80 the full 6-column row is 82+ chars — every row silently lost
2041
- // its last two cells). The dropped ones are the aggregates, not the observations.
2042
- // CAPACITY (tank) is the headline: tokens ÷ the vendor's own fullness at close,
2043
- // per cycle. That measures the PLAN. The delivered-token columns measure DEMAND —
2044
- // useful, but they were the headline before 2026-08-25 and read as capacity, which
2045
- // is why an account that simply went unused looked small.
2046
- const ALL_COLS = ['Capacity', 'Used now', 'Last cyc', 'Avg cyc'];
2047
- const CW = 10;
2040
+ // Owner-specified table (2026-08-26): the same shape for BOTH views —
2041
+ // Current cycle (tokens + % used) · Prev cycle · Avg across all cycles · N cycles.
2042
+ // Current is the live window (estimate while it runs; frozen into the columns at
2043
+ // close). Prev/Avg/N are the completed-cycle history. The no-weekly account's
2044
+ // weekly view approximates capacity as avg session tank × 33.6 (7×24/5h windows).
2045
+ const ALL_COLS = ['Current', 'Prev', 'Avg', 'N'];
2046
+ const CW = 11;
2048
2047
  const nameW = 12;
2049
2048
  let COLS = ALL_COLS;
2050
- while (COLS.length > 1 && (nameW + PROVIDER_W + 2 + COLS.length * CW + 16) > W) {
2049
+ while (COLS.length > 1 && (nameW + PROVIDER_W + 2 + COLS.length * CW + 14) > W) {
2051
2050
  COLS = COLS.slice(0, -1);
2052
2051
  }
2053
2052
  const header = ' ' + 'Account'.padEnd(nameW) + ' ' + 'Provider'.padEnd(PROVIDER_W) + ' '
2054
- + COLS.map(c => c.padStart(CW)).join('') + ' Basis';
2053
+ + COLS.map(c => c.padStart(CW)).join('');
2055
2054
  out.push(dimUnderline(fitLine(header, W)));
2056
2055
 
2057
- let anyData = false;
2058
2056
  for (const i of this._displayOrder()) {
2059
2057
  const a = this.am.accounts[i];
2060
2058
  if (!a) continue;
2061
2059
  if (this.hideDisabled && a.enabled === false) continue;
2062
- const noWeekly = win === 'wk' && a.type === 'provider' && a.quota?.weeklyAbsent;
2063
2060
  const name = truncate(a.name, nameW).padEnd(nameW);
2064
2061
  const prov = gray(providerLabel(a).padEnd(PROVIDER_W));
2065
- if (noWeekly) {
2066
- // No weekly limit — the favourite legacy plan. There is no weekly CAP, so a
2067
- // measured weekly capacity is a fiction; but there IS a real ceiling: the 5h
2068
- // session limit gates throughput, capping the week at (windows/wk × session
2069
- // capacity). 33.6 five-hour windows fit in 7 days — the user's own
2070
- // approximation ("from the session limits"), shipped as a ceiling, never a cap.
2071
- const t = ledger.rollingThroughput(a.name, 7);
2072
- const windowsPerWk = (7 * 24) / 5;
2073
- anyData = anyData || t.tokens > 0;
2074
- const vol = t.tokens > 0 ? formatTokens(t.tokens) : '--';
2075
- // The ceiling needs a measured session TANK (capacity, not avg delivery) —
2076
- // multiplying an old avg-delivery number understates a demand-limited account.
2062
+
2063
+ // The no-weekly plan has NO weekly window to complete — its weekly "capacity" is
2064
+ // derived: avg session tank × 33.6 (the number of 5h windows in 7 days). Shown as
2065
+ // ≈ to mark the derivation; N is the count of session cycles it rests on.
2066
+ if (win === 'wk' && a.type === 'provider' && a.quota?.weeklyAbsent) {
2077
2067
  const sesTank = this.am.capacityTank?.(i, 'ses');
2078
- const ceiling = sesTank
2079
- ? ` · ≈${formatTokens(Math.round(windowsPerWk * sesTank.avg))}/wk ceiling`
2080
- + dim(` (${windowsPerWk.toFixed(0)} × ${formatTokens(sesTank.avg)} per 5h)`)
2081
- : '';
2082
- // Always disclose the window's age boundary: today is unfinished, so the 7d
2083
- // figure grows through the day; a genuinely partial day adds the ≤-observed floor.
2084
- const note = t.partial
2085
- ? ' (≤ observed — maxpool was down part of the window; includes today, in progress)'
2086
- : ' (includes today, in progress)';
2068
+ const approx = sesTank && sesTank.n > 0
2069
+ ? `≈${formatTokens(Math.round(sesTank.avg * (7 * 24) / 5))}` : '--';
2070
+ const cellsByName = { Current: cyan(approx), Prev: '--', Avg: '--', N: sesTank?.n ? String(sesTank.n) : '--' };
2087
2071
  out.push(' ' + name + ' ' + prov + ' '
2088
- + cyan(`no weekly limit · 7d volume ${vol}`) + yellow(ceiling) + dim(note));
2072
+ + COLS.map(c => cellsByName[c].padStart(CW)).join('')
2073
+ + dim(' no weekly limit · avg 5h × 33.6'));
2089
2074
  continue;
2090
2075
  }
2091
- const st = ledger.windowStats(a.name, win);
2076
+
2092
2077
  const tank = this.am.capacityTank?.(i, win);
2093
- const nowOpen = ledger.openCycle(a.name, win);
2094
- const util = this.am._windowUtilization?.(a, win);
2095
2078
  // A reading we cannot prove is from THIS window may describe the previous one —
2096
- // the basis line says "unproven" instead of "live", but the number still renders:
2097
- // a restored reading after a restart is real data, and suppressing it would blank
2098
- // the page at exactly the moment the user opens it.
2099
- const unproven = tank?.source === 'live' && tank.fresh === false;
2100
-
2101
- // A row with NEITHER a tank nor any delivery has genuinely nothing to say. Say
2102
- // WHY in the account's own terms — "no completed cycle yet" was true and useless
2103
- // (reported 2026-08-25: an account sitting at 99% weekly rendered that line).
2104
- if (!tank && !st && !(nowOpen?.tokensSoFar > 0)) {
2105
- const why = util == null
2106
- ? 'no quota reading from this provider'
2107
- : util > 0
2108
- ? `${(util * 100).toFixed(0)}% used, but no traffic through maxpool to measure with`
2109
- : 'window empty — nothing used yet';
2110
- out.push(' ' + name + ' ' + prov + ' ' + dim(why));
2111
- continue;
2079
+ // keep the number but never mark it live; it becomes a proper column at close.
2080
+ const unprovenLive = tank?.source === 'live' && tank.fresh === false;
2081
+ const util = this.am._windowUtilization?.(a, win);
2082
+ const nowOpen = ledger.openCycle(a.name, win);
2083
+
2084
+ // Current = the live window: capacity estimate so far, tagged with how full the
2085
+ // vendor says it is. `~` estimate-from-open-window, `≥` lower bound (joined late).
2086
+ let cur = '--';
2087
+ if (tank && !(tank.source === 'live' && unprovenLive)) {
2088
+ cur = (tank.lowerBound ? '≥' : tank.source === 'live' ? '~' : '') + formatTokens(tank.avg);
2089
+ } else if (nowOpen?.tokensSoFar > 0 && util > 0) {
2090
+ cur = '~' + formatTokens(Math.round(nowOpen.tokensSoFar / util));
2112
2091
  }
2113
- anyData = true;
2114
-
2115
- // Capacity: measured tank, or the live in-window estimate. `~` = estimate from an
2116
- // open window; `≥` = we joined the window late, so the vendor's percentage counts
2117
- // spend maxpool never saw and the true tank is at least this.
2118
- const capCell = tank
2119
- ? (tank.lowerBound ? '≥' : tank.source === 'live' ? '~' : ' ') + formatTokens(tank.avg)
2120
- : '--';
2121
- const usedNow = nowOpen?.tokensSoFar > 0 ? formatTokens(nowOpen.tokensSoFar) : '--';
2092
+ const curPct = util != null && cur !== '--' ? dim(`${Math.round(util * 100)}%`) : '';
2093
+ const st = ledger.windowStats(a.name, win);
2122
2094
  const cellsByName = {
2123
- Capacity: capCell,
2124
- 'Used now': usedNow,
2125
- 'Last cyc': st ? formatTokens(st.last) : '--',
2126
- 'Avg cyc': st ? formatTokens(st.avg10) : '--',
2095
+ Current: cur.padStart(CW - (curPct ? curPct.length + 1 : 0)),
2096
+ Prev: (st?.prev != null ? formatTokens(st.prev) : '--'),
2097
+ Avg: (tank?.source === 'cycles' ? formatTokens(tank.avg) : '--'),
2098
+ N: (st ? String(st.cycles) : '--'),
2127
2099
  };
2128
- const cells = COLS.map(c => cellsByName[c].padStart(CW)).join('');
2129
-
2130
- // Basis: how the capacity number was arrived at, in one short phrase. Never a
2131
- // bare count — "3" told the reader nothing about what it was counting.
2132
- const basis = !tank ? dim('no capacity reading yet')
2133
- : tank.source === 'cycles'
2134
- ? dim(`${tank.n} full ${tank.n === 1 ? 'window' : 'windows'}`)
2135
- : dim(`${unproven ? 'from an older reading' : 'live'} · ${((tank.utilization ?? 0) * 100).toFixed(0)}% used`);
2136
- const pct = util != null && tank?.source !== 'live' ? dim(` (${(util * 100).toFixed(0)}% full now)`) : '';
2137
- out.push(' ' + name + ' ' + prov + ' ' + cyan(cells) + ' ' + basis + pct);
2100
+ const row = ' ' + name + ' ' + prov + ' '
2101
+ + COLS.map(c => cellsByName[c].padStart(CW)).join('');
2102
+ out.push(row + (curPct ? ' ' + curPct : ''));
2138
2103
  }
2139
2104
 
2140
2105
  out.push('');
2141
- if (!anyData) {
2142
- out.push(' ' + yellow('Nothing to measure yet.')
2143
- + dim(' Capacity needs traffic through maxpool plus a quota reading from the provider.'));
2144
- }
2145
- out.push(' ' + dim('Capacity = tokens delivered ÷ how full the provider said the window was.'));
2146
- out.push(' ' + dim('~ = from the window still running · ≥ = at least this (maxpool joined the window late).'));
2106
+ out.push(' ' + dim('Capacity = tokens ÷ how full the provider said the window was, at close.'));
2107
+ out.push(' ' + dim('~ = running estimate · ≥ = at least (maxpool joined late) · ≈ = avg 5h × 33.6.'));
2147
2108
  return out;
2148
2109
  }
2149
2110