zcode-acp-server 0.70.0 → 0.72.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.
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Cross-account aggregation for the CLIProxy card.
3
+ *
4
+ * Each antigravity subscription has its own quota pools; CLIProxy rotates
5
+ * requests across them, so the actionable numbers are POOL-WIDE: total used
6
+ * over total capacity (the average of the per-account used fractions — the
7
+ * sum divided by the number of subscriptions reporting that family+window),
8
+ * plus the earliest reset among the contributing buckets (when capacity
9
+ * starts coming back). The per-account detail stays in
10
+ * {@link ./types.js CpAccountQuota} for ACP consumers.
11
+ */
12
+ /**
13
+ * Aggregate every account's families into pool-wide rows. Families are keyed
14
+ * by name (accounts report the same family set); a window reported by only
15
+ * some accounts still divides by the reporting count — a subscription that
16
+ * reports nothing for a family contributes neither usage nor capacity.
17
+ */
18
+ export function aggregateCpFamilies(accounts) {
19
+ // family name → window → {usedSum, count, resetAt?}
20
+ const families = new Map();
21
+ for (const account of accounts) {
22
+ for (const model of account.models) {
23
+ let windows = families.get(model.name);
24
+ if (!windows) {
25
+ windows = new Map();
26
+ families.set(model.name, windows);
27
+ }
28
+ for (const w of model.windows) {
29
+ const agg = windows.get(w.window) ?? { usedSum: 0, count: 0 };
30
+ agg.usedSum += w.used;
31
+ agg.count += 1;
32
+ if (w.resetAt !== undefined && (agg.resetAt === undefined || w.resetAt < agg.resetAt)) {
33
+ agg.resetAt = w.resetAt;
34
+ }
35
+ windows.set(w.window, agg);
36
+ }
37
+ }
38
+ }
39
+ const out = [];
40
+ for (const [name, windows] of families) {
41
+ const rows = [];
42
+ for (const [window, agg] of windows) {
43
+ rows.push({
44
+ window,
45
+ used: Math.min(1, agg.usedSum / agg.count),
46
+ ...(agg.resetAt !== undefined && { resetAt: agg.resetAt }),
47
+ });
48
+ }
49
+ // Tightest window first; ties keep the 5h-then-week display order.
50
+ rows.sort((a, b) => b.used - a.used || windowOrder(a.window) - windowOrder(b.window));
51
+ out.push({ name, windows: rows });
52
+ }
53
+ // Most-used family leads the card.
54
+ return out.sort((a, b) => maxUsed(b) - maxUsed(a));
55
+ }
56
+ function windowOrder(window) {
57
+ return window === "5h" ? 0 : 1;
58
+ }
59
+ function maxUsed(family) {
60
+ return family.windows.length > 0 ? family.windows[0].used : 0;
61
+ }
62
+ /**
63
+ * The pool-wide binding row across ALL families: the single (window, used,
64
+ * earliest reset) the dock and the ACP `combined` field report. The window is
65
+ * whichever is fullest (max aggregated used over every family×window); the
66
+ * reset is the earliest among that window's family rows — capacity starts
67
+ * returning then even though the pool refills gradually.
68
+ */
69
+ export function bindingCpWindow(families) {
70
+ let binding = null;
71
+ for (const family of families) {
72
+ for (const w of family.windows) {
73
+ if (!binding || w.used > binding.used)
74
+ binding = { ...w };
75
+ }
76
+ }
77
+ if (!binding)
78
+ return null;
79
+ // Earliest reset across every family reporting the SAME window.
80
+ let earliest;
81
+ for (const family of families) {
82
+ for (const w of family.windows) {
83
+ if (w.window === binding.window && w.resetAt !== undefined) {
84
+ earliest = earliest === undefined ? w.resetAt : Math.min(earliest, w.resetAt);
85
+ }
86
+ }
87
+ }
88
+ return { ...binding, ...(earliest !== undefined && { resetAt: earliest }) };
89
+ }
90
+ /**
91
+ * Per-window pool-wide rows for compact consumers (ACP `combined`): for each
92
+ * window, the fullest family's aggregated used plus that window's earliest
93
+ * reset. Families are separate pools, so a per-window sum would double-count
94
+ * capacity; the fullest family is the binding constraint for that window.
95
+ */
96
+ export function combinedCpWindows(families) {
97
+ const rows = new Map();
98
+ const earliest = {};
99
+ for (const family of families) {
100
+ for (const w of family.windows) {
101
+ if (w.resetAt !== undefined) {
102
+ earliest[w.window] =
103
+ earliest[w.window] === undefined ? w.resetAt : Math.min(earliest[w.window], w.resetAt);
104
+ }
105
+ const prev = rows.get(w.window);
106
+ if (!prev || w.used > prev.used)
107
+ rows.set(w.window, { ...w });
108
+ }
109
+ }
110
+ const out = [...rows.values()].map((w) => ({
111
+ window: w.window,
112
+ used: w.used,
113
+ ...(earliest[w.window] !== undefined && { resetAt: earliest[w.window] }),
114
+ }));
115
+ out.sort((a, b) => b.used - a.used || windowOrder(a.window) - windowOrder(b.window));
116
+ return out;
117
+ }
118
+ //# sourceMappingURL=aggregate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../../../src/quota/cliproxy/aggregate.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  /**
2
- * CLIProxyAPI quota rendering — one row per (account, model), tightest model
3
- * first, in the same bar style as the other sections so the combined card
4
- * reads as one piece. Only Gemini (`antigravity`) accounts render rows today;
5
- * other providers the proxy routes are summarised in a single trailing count
6
- * line (their passive quota fields follow a different, header-observed shape
7
- * and can join later without changing this layout).
2
+ * CLIProxyAPI quota rendering — pool-wide rows: every Gemini subscription's
3
+ * usage aggregated per model family and window (`5h` / `Week`), each row
4
+ * stamped with that window's EARLIEST reset across accounts (when capacity
5
+ * starts coming back). Same bar style as the other sections so the combined
6
+ * card reads as one piece. Non-Gemini providers the proxy routes are
7
+ * summarised in a single trailing count line.
8
8
  */
9
9
  import type { CpQueryResult } from "./types.js";
10
10
  export declare function formatCpSection(result: CpQueryResult, color?: boolean,
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAShD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,KAAK,UAAQ;AACb,2EAA2E;AAC3E,aAAa,SAAI;AACjB,wEAAwE;AACxE,GAAG,GAAE,MAAM,MAAyB,GACnC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAwCpC"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAahD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,KAAK,UAAQ;AACb,2EAA2E;AAC3E,aAAa,SAAI;AACjB,wEAAwE;AACxE,GAAG,GAAE,MAAM,MAAyB,GACnC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CA2CpC"}
@@ -1,11 +1,12 @@
1
1
  /**
2
- * CLIProxyAPI quota rendering — one row per (account, model), tightest model
3
- * first, in the same bar style as the other sections so the combined card
4
- * reads as one piece. Only Gemini (`antigravity`) accounts render rows today;
5
- * other providers the proxy routes are summarised in a single trailing count
6
- * line (their passive quota fields follow a different, header-observed shape
7
- * and can join later without changing this layout).
2
+ * CLIProxyAPI quota rendering — pool-wide rows: every Gemini subscription's
3
+ * usage aggregated per model family and window (`5h` / `Week`), each row
4
+ * stamped with that window's EARLIEST reset across accounts (when capacity
5
+ * starts coming back). Same bar style as the other sections so the combined
6
+ * card reads as one piece. Non-Gemini providers the proxy routes are
7
+ * summarised in a single trailing count line.
8
8
  */
9
+ import { aggregateCpFamilies } from "./aggregate.js";
9
10
  import { pickOverlay, renderColorBar } from "../color.js";
10
11
  import { formatResetTime, renderBar } from "../format.js";
11
12
  import { roundTenth } from "../rounding.js";
@@ -16,6 +17,9 @@ function formatAge(ms) {
16
17
  return `${Math.floor(minutes / 60)}h${minutes % 60 || ""}`;
17
18
  return `${minutes}m`;
18
19
  }
20
+ function windowLabel(window) {
21
+ return window === "5h" ? "5h" : "Week";
22
+ }
19
23
  export function formatCpSection(result, color = false,
20
24
  /** Count of non-Gemini accounts routed by the proxy, for the tail line. */
21
25
  otherAccounts = 0,
@@ -38,18 +42,21 @@ now = () => Date.now()) {
38
42
  return { header, body: ["no Gemini accounts on this proxy"] };
39
43
  }
40
44
  const body = [];
41
- for (const account of result.accounts) {
42
- for (const model of account.models) {
43
- const pct = roundTenth(model.used * 100);
44
- const reset = formatResetTime(model.resetAt);
45
+ for (const family of aggregateCpFamilies(result.accounts)) {
46
+ const label = family.name.slice(0, 22);
47
+ for (const [index, w] of family.windows.entries()) {
48
+ const pct = roundTenth(w.used * 100);
49
+ // Continuation rows (2nd window, 2nd family…) indent under the label.
50
+ const name = index === 0 ? label.padEnd(22) : " ".repeat(22);
51
+ const window = windowLabel(w.window).padEnd(5);
52
+ const reset = formatResetTime(w.resetAt);
45
53
  const trailing = reset ? ` · ${reset}` : "";
46
- const label = `${account.label} ${model.name}`.slice(0, 26);
47
54
  if (color) {
48
55
  const bar = renderColorBar(pct, { overlay: pickOverlay({ usedPercent: pct }) });
49
- body.push(`${label.padEnd(27)} ${bar}${trailing}`);
56
+ body.push(`${name}${window}${bar}${trailing}`);
50
57
  }
51
58
  else {
52
- body.push(`${label.padEnd(27)} ${renderBar(pct)} ${String(pct).padStart(2)}%${trailing}`);
59
+ body.push(`${name}${window}${renderBar(pct)} ${String(pct).padStart(2)}%${trailing}`);
53
60
  }
54
61
  }
55
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/quota/cliproxy/format.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/quota/cliproxy/format.ts"],"names":[],"mappings":"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"}
@@ -30,5 +30,5 @@ export declare function queryCpUsage(): Promise<CpQueryOutcome>;
30
30
  export { formatCpSection } from "./format.js";
31
31
  export { loadCpConfig, ENV_KEY, ENV_URL } from "./config.js";
32
32
  export { ANTIGRAVITY_PROVIDER, parseCredentialEntries, parseQuotaSummary } from "./parse.js";
33
- export type { CpAccountQuota, CpModelQuota, CpQueryResult } from "./types.js";
33
+ export type { CpAccountQuota, CpModelQuota, CpQueryResult, CpWindow, CpWindowQuota } from "./types.js";
34
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhE,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAeD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAEnC;AAsBD;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAkD5D;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC7F,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhE,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAeD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAEnC;AAsBD;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAkD5D;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC7F,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -5,7 +5,7 @@
5
5
  * throw. The management API accepts both camelCase and snake_case INPUT, but
6
6
  * its OUTPUT spelling is not contractual, so both variants are read.
7
7
  */
8
- import type { CpAccountQuota, CpModelQuota } from "./types.js";
8
+ import type { CpModelQuota, CpWindow, CpWindowQuota } from "./types.js";
9
9
  /** Antigravity accounts' provider id in the credentials listing (CPAMC's own
10
10
  * quota support is antigravity-only — there is no separate gemini provider). */
11
11
  export declare const ANTIGRAVITY_PROVIDER = "antigravity";
@@ -26,23 +26,21 @@ export interface CpCredentialEntry {
26
26
  */
27
27
  export declare function parseCredentialEntries(text: string): CpCredentialEntry[];
28
28
  /**
29
- * Parse one relayed `retrieveUserQuotaSummary` body into per-model rows.
29
+ * Parse one relayed `retrieveUserQuotaSummary` body into per-family windowed
30
+ * rows.
30
31
  *
31
- * Two shapes, both read defensively (missing/odd fields degrade to empty,
32
- * never throw):
33
- * - antigravity (the shape live servers answer, CPAMC `builders.ts`):
34
- * `{groups: [{displayName, buckets: [{window, remainingFraction,
35
- * resetTime, …}]}]}` — each group is a model family ("Gemini Models",
36
- * "Claude and GPT models") with one bucket per window.
37
- * - legacy flat `{models: [{name, buckets […]}]}` kept as a fallback.
38
- *
39
- * Each row carries several buckets (windows); we surface only the TIGHTEST
40
- * (lowest remaining) as `used`, the one the user actually hits first.
32
+ * Shape (live-verified 2026-10, CPAMC `builders.ts`): `{groups: [{displayName,
33
+ * buckets: [{window, remainingFraction, resetTime, …}]}]}` — each group is a
34
+ * model family ("Gemini Models", "Claude and GPT models") with one bucket per
35
+ * window. Bucket `window` spellings normalize to `5h` / `week` (CPAMC's
36
+ * accepted spellings); buckets with an unknown window or an out-of-range
37
+ * fraction are dropped. Multiple buckets sharing a window keep the TIGHTEST.
38
+ * Missing/odd fields degrade to empty, never throw.
41
39
  */
42
40
  export declare function parseQuotaSummary(bodyText: string): CpModelQuota[];
43
41
  /** Convenience: the relay envelope's upstream status (200 unless malformed). */
44
42
  export declare function relayUpstreamStatus(text: string): number;
45
43
  /** Convenience: the relay envelope's upstream body (a STRING inside). */
46
44
  export declare function relayUpstreamBody(text: string): string | undefined;
47
- export type { CpAccountQuota, CpModelQuota };
45
+ export type { CpModelQuota, CpWindow, CpWindowQuota };
48
46
  //# sourceMappingURL=parse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/parse.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/D;iFACiF;AACjF,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAgBlD,wEAAwE;AACxE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA4CxE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAYlE;AAgED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOlE;AAED,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/parse.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAExE;iFACiF;AACjF,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAgBlD,wEAAwE;AACxE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA4CxE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAuClE;AAoBD,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOlE;AAED,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC"}
@@ -75,18 +75,16 @@ export function parseCredentialEntries(text) {
75
75
  return entries;
76
76
  }
77
77
  /**
78
- * Parse one relayed `retrieveUserQuotaSummary` body into per-model rows.
78
+ * Parse one relayed `retrieveUserQuotaSummary` body into per-family windowed
79
+ * rows.
79
80
  *
80
- * Two shapes, both read defensively (missing/odd fields degrade to empty,
81
- * never throw):
82
- * - antigravity (the shape live servers answer, CPAMC `builders.ts`):
83
- * `{groups: [{displayName, buckets: [{window, remainingFraction,
84
- * resetTime, …}]}]}` — each group is a model family ("Gemini Models",
85
- * "Claude and GPT models") with one bucket per window.
86
- * - legacy flat `{models: [{name, buckets […]}]}` kept as a fallback.
87
- *
88
- * Each row carries several buckets (windows); we surface only the TIGHTEST
89
- * (lowest remaining) as `used`, the one the user actually hits first.
81
+ * Shape (live-verified 2026-10, CPAMC `builders.ts`): `{groups: [{displayName,
82
+ * buckets: [{window, remainingFraction, resetTime, …}]}]}` — each group is a
83
+ * model family ("Gemini Models", "Claude and GPT models") with one bucket per
84
+ * window. Bucket `window` spellings normalize to `5h` / `week` (CPAMC's
85
+ * accepted spellings); buckets with an unknown window or an out-of-range
86
+ * fraction are dropped. Multiple buckets sharing a window keep the TIGHTEST.
87
+ * Missing/odd fields degrade to empty, never throw.
90
88
  */
91
89
  export function parseQuotaSummary(bodyText) {
92
90
  let parsed;
@@ -97,78 +95,63 @@ export function parseQuotaSummary(bodyText) {
97
95
  return [];
98
96
  }
99
97
  const doc = asRecord(parsed);
100
- if (!doc)
98
+ if (!doc || !Array.isArray(doc.groups))
101
99
  return [];
102
- if (Array.isArray(doc.groups))
103
- return rowsFromGroups(doc.groups);
104
- if (Array.isArray(doc.models))
105
- return rowsFromModels(doc.models);
106
- return [];
107
- }
108
- /** The tightest (max used) valid bucket, or null when none parses. */
109
- function tightestBucket(bucketsRaw) {
110
- if (!Array.isArray(bucketsRaw))
111
- return null;
112
- let tightest = null;
113
- for (const bRaw of bucketsRaw) {
114
- const b = asRecord(bRaw);
115
- if (!b)
116
- continue;
117
- const remaining = num(b.remainingFraction ?? b.remaining_fraction);
118
- if (remaining === undefined || remaining < 0 || remaining > 1)
119
- continue;
120
- const used = 1 - remaining;
121
- if (!tightest || used > tightest.used) {
122
- const resetRaw = str(b.resetTime ?? b.reset_time);
123
- const resetAt = resetRaw !== undefined ? Date.parse(resetRaw) : Number.NaN;
124
- tightest = {
125
- used,
126
- ...(Number.isFinite(resetAt) && { resetAt }),
127
- };
128
- }
129
- }
130
- return tightest;
131
- }
132
- /** Antigravity shape: one row per group, named by its display name. */
133
- function rowsFromGroups(groupsRaw) {
134
100
  const models = [];
135
- for (const [index, gRaw] of groupsRaw.entries()) {
101
+ for (const [index, gRaw] of doc.groups.entries()) {
136
102
  const g = asRecord(gRaw);
137
103
  if (!g)
138
104
  continue;
139
105
  const name = str(g.displayName ?? g.display_name) ?? `Quota Group ${index + 1}`;
140
- const tightest = tightestBucket(g.buckets);
141
- if (tightest) {
142
- models.push({
143
- name,
144
- used: tightest.used,
145
- ...("resetAt" in tightest && { resetAt: tightest.resetAt }),
146
- });
106
+ // window → tightest bucket seen for it
107
+ const tightest = new Map();
108
+ if (Array.isArray(g.buckets)) {
109
+ for (const bRaw of g.buckets) {
110
+ const b = asRecord(bRaw);
111
+ if (!b)
112
+ continue;
113
+ const window = windowOf(b.window);
114
+ if (window === null)
115
+ continue;
116
+ const remaining = num(b.remainingFraction ?? b.remaining_fraction);
117
+ if (remaining === undefined || remaining < 0 || remaining > 1)
118
+ continue;
119
+ const used = 1 - remaining;
120
+ const prev = tightest.get(window);
121
+ if (prev && prev.used >= used)
122
+ continue;
123
+ const resetRaw = str(b.resetTime ?? b.reset_time);
124
+ const resetAt = resetRaw !== undefined ? Date.parse(resetRaw) : Number.NaN;
125
+ tightest.set(window, {
126
+ used,
127
+ ...(Number.isFinite(resetAt) && { resetAt }),
128
+ });
129
+ }
147
130
  }
131
+ if (tightest.size === 0)
132
+ continue;
133
+ models.push({ name, windows: orderWindows(tightest) });
148
134
  }
149
- return models.sort((a, b) => b.used - a.used);
135
+ return models;
150
136
  }
151
- /** Legacy flat shape: one row per model entry. */
152
- function rowsFromModels(modelsRaw) {
153
- const models = [];
154
- for (const mRaw of modelsRaw) {
155
- const m = asRecord(mRaw);
156
- if (!m)
157
- continue;
158
- const name = str(m.name ?? m.model ?? m.model_id ?? m.modelId);
159
- if (!name)
160
- continue;
161
- const tightest = tightestBucket(m.buckets);
162
- if (tightest) {
163
- models.push({
164
- name,
165
- used: tightest.used,
166
- ...("resetAt" in tightest && { resetAt: tightest.resetAt }),
167
- });
168
- }
137
+ /** Bucket window spellings → canonical window (mirrors CPAMC's
138
+ * `antigravityPeriodHours` accepted spellings; anything else is dropped). */
139
+ function windowOf(raw) {
140
+ const v = typeof raw === "string" ? raw.trim().toLowerCase() : "";
141
+ if (v === "5h" || v === "five-hour" || v === "five_hour")
142
+ return "5h";
143
+ if (v === "weekly" || v === "week")
144
+ return "week";
145
+ return null;
146
+ }
147
+ function orderWindows(tightest) {
148
+ const out = [];
149
+ for (const window of ["5h", "week"]) {
150
+ const hit = tightest.get(window);
151
+ if (hit)
152
+ out.push({ window, ...hit });
169
153
  }
170
- // Tightest models first — the constraint the user hits next leads the card.
171
- return models.sort((a, b) => b.used - a.used);
154
+ return out;
172
155
  }
173
156
  /** Convenience: the relay envelope's upstream status (200 unless malformed). */
174
157
  export function relayUpstreamStatus(text) {
@@ -1 +1 @@
1
- {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/quota/cliproxy/parse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/quota/cliproxy/parse.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;iFACiF;AACjF,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAAC;AAElD,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAE,CAA6B;QAChC,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC;AAED,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrE,CAAC;AAUD;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,GAAG,GAAqB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAClE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7B,IAAI,GAAG,EAAE,CAAC;YACR,KAAK,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;gBACjE,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBAC5B,GAAG,GAAG,GAAG,CAAC,GAAG,CAAc,CAAC;oBAC5B,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,GACT,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACrF,OAAO,CAAC,IAAI,CAAC;YACX,SAAS;YACT,QAAQ;YACR,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,SAAS;YAC/C,SAAS,EACP,GAAG,CAAC,IAAI,EAAE,UAAU,IAAI,IAAI,EAAE,SAAS,CAAC;gBACxC,GAAG,CAAC,QAAQ,EAAE,UAAU,IAAI,QAAQ,EAAE,SAAS,CAAC;gBAChD,GAAG,CAAC,UAAU,EAAE,UAAU,IAAI,UAAU,EAAE,SAAS,CAAC;gBACpD,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC;SACnC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAClD,MAAM,MAAM,GAAmB,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,YAAY,CAAC,IAAI,eAAe,KAAK,GAAG,CAAC,EAAE,CAAC;QAChF,uCAAuC;QACvC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAgD,CAAC;QACzE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC7B,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACzB,IAAI,CAAC,CAAC;oBAAE,SAAS;gBACjB,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBAClC,IAAI,MAAM,KAAK,IAAI;oBAAE,SAAS;gBAC9B,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,kBAAkB,CAAC,CAAC;gBACnE,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,GAAG,CAAC,IAAI,SAAS,GAAG,CAAC;oBAAE,SAAS;gBACxE,MAAM,IAAI,GAAG,CAAC,GAAG,SAAS,CAAC;gBAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAClC,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI;oBAAE,SAAS;gBACxC,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC;gBAClD,MAAM,OAAO,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;gBAC3E,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE;oBACnB,IAAI;oBACJ,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;iBAC7C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;YAAE,SAAS;QAClC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;8EAC8E;AAC9E,SAAS,QAAQ,CAAC,GAAY;IAC5B,MAAM,CAAC,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IACtE,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IAClD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,QAA2D;IAC/E,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,EAAE,MAAM,CAAU,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,GAAG;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,OAAO,GAAG,CAAC,GAAG,EAAE,WAAW,IAAI,GAAG,EAAE,UAAU,CAAC,IAAI,GAAG,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -29,15 +29,23 @@
29
29
  * Everything here is undocumented/best-effort: parse failures degrade to
30
30
  * `unavailable`, never a crash.
31
31
  */
32
- /** One model's quota row: the tightest bucket of that model's set. */
33
- export interface CpModelQuota {
34
- /** Model display name (e.g. "gemini-3-pro"). */
35
- name: string;
36
- /** Used fraction [0, 1] — 1 minus the model's LOWEST remainingFraction. */
32
+ /** Canonical quota window — bucket spellings normalize to these at parse time. */
33
+ export type CpWindow = "5h" | "week";
34
+ /** One window of one model family. */
35
+ export interface CpWindowQuota {
36
+ window: CpWindow;
37
+ /** Used fraction [0, 1] — 1 minus the bucket's remainingFraction. */
37
38
  used: number;
38
- /** Reset moment of that tightest bucket (epoch ms), when reported. */
39
+ /** Reset moment of that window's tightest bucket (epoch ms), when reported. */
39
40
  resetAt?: number;
40
41
  }
42
+ /** One model family's quota rows — one per reported window. */
43
+ export interface CpModelQuota {
44
+ /** Family display name (e.g. "Gemini Models"). */
45
+ name: string;
46
+ /** Per-window rows, `5h` before `week`. */
47
+ windows: CpWindowQuota[];
48
+ }
41
49
  /** One upstream account's quota block. */
42
50
  export interface CpAccountQuota {
43
51
  /** Short account label (email local-part, or the auth index). */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAE5B,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/quota/cliproxy/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,kFAAkF;AAClF,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC;AAErC,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,QAAQ,CAAC;IACjB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAE5B,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -139,12 +139,11 @@ export declare function formatOcDockSegment(oc: OcQueryResult): string | null;
139
139
  /** Join the dock segments; `null` when all are absent. */
140
140
  export declare function composeQuotaDock(...segments: (string | null)[]): string | null;
141
141
  /**
142
- * Compact CLIProxy segment for the dock: the single TIGHTEST Gemini model
143
- * across all proxy accounts, as `cp 63% 10-15` — percent plus the reset date
144
- * (Gemini quota windows reset within a day, so a clock time adds nothing the
145
- * date doesn't). With several accounts the maximum is the actionable number;
146
- * the full per-account breakdown lives in the card. `null` when the proxy is
147
- * not usable (not configured, auth error, unavailable) or has no models.
142
+ * Compact CLIProxy segment for the dock: the POOL-WIDE binding window — every
143
+ * Gemini subscription's usage aggregated (total used over total capacity),
144
+ * as `cp 13.2% 10-18` — percent plus the earliest reset date of that window
145
+ * across accounts (when capacity starts coming back). `null` when the proxy
146
+ * is not usable (not configured, auth error, unavailable) or reports nothing.
148
147
  */
149
148
  export declare function formatCpDockSegment(cp: CpQueryResult): string | null;
150
149
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/quota/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,YAAY,CAAC;AAiBzD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASrE;AAyCD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAgDD;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,kBAAkB,CA+B9F;AAeD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAU7E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAGlF;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAgBlE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAUpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAmBpE;AAED,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,GAAG,QAAQ,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,GAAG,IAAI,CAG9E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAepE"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/quota/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,YAAY,CAAC;AAiBzD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASrE;AAyCD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAgDD;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,kBAAkB,CA+B9F;AAeD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAU7E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAGlF;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAgBlE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAUpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAmBpE;AAED,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,GAAG,QAAQ,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,GAAG,IAAI,CAG9E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAQpE"}
@@ -15,6 +15,7 @@
15
15
  * fill for used quota, with the light shade marking the remainder.
16
16
  */
17
17
  import { pickOverlay, renderColorBar } from "./color.js";
18
+ import { aggregateCpFamilies, bindingCpWindow } from "./cliproxy/aggregate.js";
18
19
  import { roundTenth } from "./rounding.js";
19
20
  /**
20
21
  * Progress-bar cell count. 20 cells = 5% granularity, fine enough to read
@@ -304,29 +305,21 @@ export function composeQuotaDock(...segments) {
304
305
  return parts.length > 0 ? parts.join(" · ") : null;
305
306
  }
306
307
  /**
307
- * Compact CLIProxy segment for the dock: the single TIGHTEST Gemini model
308
- * across all proxy accounts, as `cp 63% 10-15` — percent plus the reset date
309
- * (Gemini quota windows reset within a day, so a clock time adds nothing the
310
- * date doesn't). With several accounts the maximum is the actionable number;
311
- * the full per-account breakdown lives in the card. `null` when the proxy is
312
- * not usable (not configured, auth error, unavailable) or has no models.
308
+ * Compact CLIProxy segment for the dock: the POOL-WIDE binding window — every
309
+ * Gemini subscription's usage aggregated (total used over total capacity),
310
+ * as `cp 13.2% 10-18` — percent plus the earliest reset date of that window
311
+ * across accounts (when capacity starts coming back). `null` when the proxy
312
+ * is not usable (not configured, auth error, unavailable) or reports nothing.
313
313
  */
314
314
  export function formatCpDockSegment(cp) {
315
315
  if (cp.kind !== "success")
316
316
  return null;
317
- let worst = null;
318
- for (const account of cp.accounts) {
319
- for (const model of account.models) {
320
- if (!worst || model.used > worst.used) {
321
- worst = { used: model.used, resetAt: model.resetAt };
322
- }
323
- }
324
- }
325
- if (!worst)
317
+ const binding = bindingCpWindow(aggregateCpFamilies(cp.accounts));
318
+ if (!binding)
326
319
  return null;
327
- const pct = roundTenth(Math.max(0, Math.min(100, worst.used * 100)));
320
+ const pct = roundTenth(Math.max(0, Math.min(100, binding.used * 100)));
328
321
  const label = Number.isInteger(pct) ? String(pct) : pct.toFixed(1);
329
- const date = formatResetDate(worst.resetAt);
322
+ const date = formatResetDate(binding.resetAt);
330
323
  return `cp ${label}%${date ? ` ${date}` : ""}`;
331
324
  }
332
325
  /**