1import {
2 EnvironmentId,
3 ProviderDriverKind,
4 ProviderInstanceId,
5 type ServerProvider,
6 UsageLimitSourceId,
7} from "@t3tools/contracts";
8import { describe, expect, it } from "vite-plus/test";
9
10import {
11 type LimitAccount,
12 isUsageLimitsCommand,
13 collectProviderUsageLimits,
14 sameUsageLimitCommandCoverage,
15 withUsageLimitsCommands,
16 collectLimitAccounts,
17 collectExternalUsageLinks,
18 collectLimitNotices,
19 collectLimitPools,
20 displayLimitWindows,
21 elapsedShare,
22 formatResetsIn,
23 limitsNotice,
24 paceOf,
25 providersWithLimits,
26 remainingPercent,
27 usesChatGptSharing,
28} from "./usageLimits.ts";
29
30const now = Date.parse("2026-09-03T12:00:00.000Z");
31
32const window = {
33 id: "five_hour",
34 kind: "session",
35 label: "Session",
36 usedPercent: 40,
37 windowDurationMins: 300,
38 resetsAt: "2026-09-03T14:00:00.000Z",
39} as const;
40
41function provider(overrides: Partial<ServerProvider>): ServerProvider {
42 return {
43 instanceId: ProviderInstanceId.make("codex"),
44 driver: ProviderDriverKind.make("codex"),
45 enabled: true,
46 installed: true,
47 version: null,
48 status: "ready",
49 auth: { status: "authenticated" },
50 checkedAt: "2026-09-03T11:00:00.000Z",
51 models: [],
52 slashCommands: [],
53 skills: [],
54 ...overrides,
55 };
56}
57
58describe("pace", () => {
59 it.each([
60 ["2026-09-03T12:01:00.000Z", "resets in 1m"],
61 ["2026-09-03T12:00:59.999Z", "Resets momentarily"],
62 ["2026-09-03T12:00:00.001Z", "Resets momentarily"],
63 ["2026-09-03T12:00:00.000Z", "resets now"],
64 ["2026-09-03T11:59:59.999Z", "resets now"],
65 ])("formats the reset boundary at %s", (resetsAt, label) => {
66 expect(formatResetsIn({ ...window, resetsAt }, now)).toBe(label);
67 });
68
69 it("ignores invalid reset timestamps", () => {
70 expect(formatResetsIn({ ...window, resetsAt: "invalid" }, now)).toBeNull();
71 });
72
73 it("places the clock three fifths through a five-hour window with two hours left", () => {
74 expect(elapsedShare(window, now)).toBeCloseTo(0.6);
75 expect(paceOf(window, now)).toBe("under");
76 expect(paceOf({ ...window, usedPercent: 62 }, now)).toBe("on");
77 expect(paceOf({ ...window, usedPercent: 80 }, now)).toBe("ahead");
78 });
79
80 it("has no pace without a reset or a duration", () => {
81 expect(paceOf({ ...window, resetsAt: undefined }, now)).toBeNull();
82 expect(paceOf({ ...window, windowDurationMins: undefined }, now)).toBeNull();
83 expect(formatResetsIn({ ...window, resetsAt: undefined }, now)).toBeNull();
84 });
85
86 it("phrases the reset as a countdown", () => {
87 expect(formatResetsIn(window, now)).toBe("resets in 2h 0m");
88 expect(formatResetsIn({ ...window, resetsAt: "2026-09-06T15:30:00.000Z" }, now)).toBe(
89 "resets in 3d 3h",
90 );
91 expect(formatResetsIn({ ...window, resetsAt: "2026-09-03T11:00:00.000Z" }, now)).toBe(
92 "resets now",
93 );
94 });
95});
96
97describe("limitsNotice", () => {
98 it("explains empty bars and passes provider messages through", () => {
99 const checkedAt = "2026-09-03T11:00:00.000Z";
100 expect(limitsNotice({ checkedAt, windows: [window] })).toBeNull();
101 expect(limitsNotice({ checkedAt, windows: [] })).toBe("No limits reported.");
102 expect(limitsNotice({ checkedAt, windows: [], unavailable: { reason: "unsupported" } })).toBe(
103 "This account has no subscription limits.",
104 );
105 expect(
106 limitsNotice({
107 checkedAt,
108 windows: [],
109 unavailable: { reason: "probeFailed", message: "Codex timed out." },
110 }),
111 ).toBe("Codex timed out.");
112 });
113});
114
115describe("providersWithLimits", () => {
116 it("keeps only usable providers whose driver reports limits at all", () => {
117 const limits = { checkedAt: "2026-09-03T11:00:00.000Z", windows: [window] };
118 const codex = provider({ usageLimits: limits });
119 expect(
120 providersWithLimits([
121 codex,
122 provider({
123 instanceId: ProviderInstanceId.make("cursor"),
124 driver: ProviderDriverKind.make("cursor"),
125 }),
126 provider({
127 instanceId: ProviderInstanceId.make("off"),
128 enabled: false,
129 usageLimits: limits,
130 }),
131 provider({
132 instanceId: ProviderInstanceId.make("gone"),
133 installed: false,
134 usageLimits: limits,
135 }),
136 provider({
137 instanceId: ProviderInstanceId.make("shadow"),
138 availability: "unavailable",
139 usageLimits: limits,
140 }),
141 ]),
142 ).toEqual([codex]);
143 });
144});
145
146describe("pools", () => {
147 const checkedAt = "2026-09-03T11:00:00.000Z";
148 const weekly = {
149 id: "seven_day",
150 kind: "weekly",
151 label: "Weekly",
152 windowDurationMins: 7 * 24 * 60,
153 resetsAt: "2026-09-06T12:00:00.000Z",
154 } as const;
155 const claude = ProviderDriverKind.make("claudeAgent");
156 const source = {
157 id: UsageLimitSourceId.make("hub"),
158 kind: "cliproxy" as const,
159 label: "hub",
160 checkedAt,
161 };
162 const laptop = { entry: { target: { label: "Laptop" } } };
163
164 it("can retain failed profiles without changing the default pooled accounts", () => {
165 const failed = provider({
166 usageLimits: { checkedAt, windows: [], unavailable: { reason: "probeFailed" } },
167 });
168 const input = new Map([
169 [EnvironmentId.make("env-a"), { ...laptop, serverConfig: { providers: [failed] } }],
170 ]);
171
172 expect(collectLimitAccounts(input)).toEqual([]);
173 expect(collectLimitAccounts(input, { includeUnavailable: true })).toMatchObject([
174 { key: "env-a:codex", limits: failed.usageLimits },
175 ]);
176 });
177
178 it.each([false, true])(
179 "prefers usable quotas to a newer failure, failure first: %s",
180 (failedFirst) => {
181 const healthy = provider({
182 auth: { status: "authenticated", email: "person@example.com" },
183 usageLimits: { checkedAt, windows: [window] },
184 });
185 const failed = {
186 ...healthy,
187 usageLimits: {
188 checkedAt: "2026-09-03T12:00:00.000Z",
189 windows: [],
190 unavailable: { reason: "probeFailed" as const },
191 },
192 };
193 const providers = failedFirst ? [failed, healthy] : [healthy, failed];
194 const input = new Map(
195 providers.map((provider, index) => [
196 EnvironmentId.make(`env-${index}`),
197 { ...laptop, serverConfig: { providers: [provider] } },
198 ]),
199 );
200
201 const accounts = collectLimitAccounts(input, { includeUnavailable: true });
202 expect(accounts).toHaveLength(1);
203 expect(accounts[0]?.limits).toEqual(healthy.usageLimits);
204 },
205 );
206
207 it("merges one account reported natively on two environments and by a hub into one entry", () => {
208 const native = provider({
209 driver: claude,
210 instanceId: ProviderInstanceId.make("claude"),
211 auth: { status: "authenticated", email: "Same@example.com" },
212 usageLimits: { checkedAt, windows: [{ ...window, usedPercent: 40 }] },
213 });
214 const input = new Map([
215 [EnvironmentId.make("env-a"), { ...laptop, serverConfig: { providers: [native] } }],
216 [
217 EnvironmentId.make("env-b"),
218 {
219 entry: { target: { label: "Desktop" } },
220 serverConfig: {
221 providers: [
222 {
223 ...native,
224 usageLimits: {
225 checkedAt: "2026-09-03T11:30:00.000Z",
226 windows: [{ ...window, usedPercent: 55 }],
227 },
228 },
229 ],
230 usageLimitSources: [
231 {
232 ...source,
233 accounts: [
234 {
235 id: "claude-same@example.com.json",
236 driver: claude,
237 email: "same@example.com",
238 plan: "Claude Subscription",
239 usageLimits: { checkedAt, windows: [{ ...window, usedPercent: 10 }] },
240 },
241 ],
242 },
243 ],
244 },
245 },
246 ],
247 ]);
248 const accounts = collectLimitAccounts(input);
249 expect(accounts).toHaveLength(1);
250 expect(accounts[0]).toMatchObject({
251 key: "env-a:claude",
252 sourceLabel: null,
253 // Desktop's read is fresher, so its credits and its redeem are the ones on show.
254 redeem: { environmentId: "env-b", input: { instanceId: "claude" } },
255 environments: [
256 { environmentId: "env-a", label: "Laptop" },
257 { environmentId: "env-b", label: "Desktop" },
258 ],
259 });
260 // The fresher native snapshot wins; the hub row is pre-filtered by email.
261 expect(accounts[0]?.limits.windows[0]?.usedPercent).toBe(55);
262 });
263
264 it("merges OpenCode Go limits from machines with the same API key", () => {
265 const go = provider({
266 driver: ProviderDriverKind.make("opencode"),
267 instanceId: ProviderInstanceId.make("opencode"),
268 auth: { status: "authenticated" },
269 usageLimits: {
270 checkedAt,
271 credentialFingerprint: "shared-go-key",
272 windows: [{ ...window, id: "go_rolling", usedPercent: 3 }],
273 },
274 });
275 const input = new Map([
276 [EnvironmentId.make("env-a"), { ...laptop, serverConfig: { providers: [go] } }],
277 [
278 EnvironmentId.make("env-b"),
279 {
280 entry: { target: { label: "Desktop" } },
281 serverConfig: {
282 providers: [
283 {
284 ...go,
285 usageLimits: {
286 ...go.usageLimits!,
287 checkedAt: "2026-09-03T11:30:00.000Z",
288 windows: [{ ...window, id: "go_rolling", usedPercent: 4 }],
289 },
290 },
291 ],
292 },
293 },
294 ],
295 ]);
296 const accounts = collectLimitAccounts(input);
297 expect(accounts).toHaveLength(1);
298 expect(accounts[0]?.environments).toEqual([
299 { environmentId: "env-a", label: "Laptop" },
300 { environmentId: "env-b", label: "Desktop" },
301 ]);
302 expect(collectLimitPools(accounts, now)[0]?.windows[0]?.members).toHaveLength(1);
303 expect(accounts[0]?.limits.windows[0]?.usedPercent).toBe(4);
304
305 const differentKey = {
306 ...go,
307 usageLimits: { ...go.usageLimits!, credentialFingerprint: "other-go-key" },
308 };
309 input.set(EnvironmentId.make("env-b"), {
310 entry: { target: { label: "Desktop" } },
311 serverConfig: { providers: [differentKey] },
312 });
313 expect(collectLimitAccounts(input)).toHaveLength(2);
314
315 input.set(EnvironmentId.make("env-a"), {
316 ...laptop,
317 serverConfig: {
318 providers: [{ ...go, auth: { status: "authenticated", email: "same@example.com" } }],
319 },
320 });
321 input.set(EnvironmentId.make("env-b"), {
322 entry: { target: { label: "Desktop" } },
323 serverConfig: {
324 providers: [
325 { ...differentKey, auth: { status: "authenticated", email: "SAME@example.com" } },
326 ],
327 },
328 });
329 expect(collectLimitAccounts(input)).toHaveLength(1);
330 });
331
332 it("takes windows from a fresher hub read but credits and redeem from the native instance", () => {
333 const native = provider({
334 driver: claude,
335 instanceId: ProviderInstanceId.make("claude"),
336 auth: { status: "authenticated", email: "same@example.com" },
337 usageLimits: {
338 checkedAt,
339 windows: [{ ...window, usedPercent: 40 }],
340 resetCredits: { availableCount: 2 },
341 },
342 });
343 const input = new Map([
344 [
345 EnvironmentId.make("env-a"),
346 {
347 ...laptop,
348 serverConfig: {
349 providers: [native],
350 usageLimitSources: [
351 {
352 ...source,
353 accounts: [
354 {
355 id: "claude-same@example.com.json",
356 driver: claude,
357 email: "same@example.com",
358 usageLimits: {
359 checkedAt: "2026-09-03T11:30:00.000Z",
360 windows: [{ ...window, usedPercent: 55 }],
361 },
362 },
363 ],
364 },
365 ],
366 },
367 },
368 ],
369 ]);
370 const [account] = collectLimitAccounts(input);
371 expect(account?.limits.windows[0]?.usedPercent).toBe(55);
372 expect(account?.limits.resetCredits?.availableCount).toBe(2);
373 expect(account?.redeem).toEqual({ environmentId: "env-a", input: { instanceId: "claude" } });
374 expect(account?.environments).toEqual([{ environmentId: "env-a", label: "Laptop" }]);
375 });
376
377 it("redeems through the hub when it holds a credit, even with a fresher native read", () => {
378 const native = provider({
379 driver: claude,
380 instanceId: ProviderInstanceId.make("claude"),
381 auth: { status: "authenticated", email: "same@example.com" },
382 usageLimits: {
383 checkedAt: "2026-09-03T11:30:00.000Z",
384 windows: [{ ...window, usedPercent: 40 }],
385 resetCredits: { availableCount: 3, nextCreditId: "native-credit" },
386 },
387 });
388 const input = new Map([
389 [
390 EnvironmentId.make("env-a"),
391 {
392 ...laptop,
393 serverConfig: {
394 providers: [native],
395 usageLimitSources: [
396 {
397 ...source,
398 accounts: [
399 {
400 id: "claude-same@example.com.json",
401 driver: claude,
402 email: "same@example.com",
403 usageLimits: {
404 checkedAt,
405 windows: [{ ...window, usedPercent: 55 }],
406 resetCredits: { availableCount: 2, nextCreditId: "hub-credit" },
407 },
408 },
409 ],
410 },
411 ],
412 },
413 },
414 ],
415 ]);
416 const [account] = collectLimitAccounts(input);
417 // Only the hub path clears the routing cooldown it holds for this account.
418 expect(account?.redeem).toEqual({
419 environmentId: "env-a",
420 input: { sourceId: "hub", accountId: "claude-same@example.com.json", creditId: "hub-credit" },
421 });
422 // The fresher native balance is still the one shown.
423 expect(account?.limits.resetCredits?.availableCount).toBe(3);
424 });
425
426 it("redeems on the environment whose snapshot supplied the credits on show", () => {
427 const stale = provider({
428 auth: { status: "authenticated", email: "same@example.com" },
429 usageLimits: {
430 checkedAt,
431 windows: [window],
432 resetCredits: { availableCount: 0 },
433 },
434 });
435 const fresh = {
436 ...stale,
437 usageLimits: {
438 checkedAt: "2026-09-03T11:30:00.000Z",
439 windows: [window],
440 resetCredits: { availableCount: 2 },
441 },
442 };
443 const input = new Map([
444 [EnvironmentId.make("env-a"), { ...laptop, serverConfig: { providers: [stale] } }],
445 [
446 EnvironmentId.make("env-b"),
447 { entry: { target: { label: "Desktop" } }, serverConfig: { providers: [fresh] } },
448 ],
449 ]);
450 const [account] = collectLimitAccounts(input);
451 expect(account?.limits.resetCredits?.availableCount).toBe(2);
452 expect(account?.redeem).toEqual({ environmentId: "env-b", input: { instanceId: "codex" } });
453 });
454
455 it("uses the freshest hub credit and its environment even when the account is also native", () => {
456 const native = provider({
457 auth: { status: "authenticated", email: "same@example.com" },
458 usageLimits: { checkedAt, windows: [window], resetCredits: { availableCount: 1 } },
459 });
460 const hubAccount = {
461 id: "codex-same.json",
462 driver: native.driver,
463 email: "same@example.com",
464 usageLimits: {
465 checkedAt: "2026-09-03T11:30:00.000Z",
466 windows: [window],
467 resetCredits: { availableCount: 2, nextCreditId: "credit-2" },
468 },
469 };
470 const input = new Map([
471 [EnvironmentId.make("env-a"), { ...laptop, serverConfig: { providers: [native] } }],
472 [
473 EnvironmentId.make("env-b"),
474 {
475 ...laptop,
476 serverConfig: {
477 providers: [],
478 usageLimitSources: [{ ...source, accounts: [hubAccount] }],
479 },
480 },
481 ],
482 ]);
483 const [account] = collectLimitAccounts(input);
484 expect(account?.limits.resetCredits?.availableCount).toBe(2);
485 expect(account?.redeem).toEqual({
486 environmentId: "env-b",
487 input: { sourceId: "hub", accountId: "codex-same.json", creditId: "credit-2" },
488 });
489 hubAccount.usageLimits.resetCredits.availableCount = 0;
490 expect(collectLimitAccounts(input)[0]?.limits.resetCredits?.availableCount).toBe(0);
491 });
492
493 it("keeps distinct hub accounts redeemable through their own source", () => {
494 const hubAccounts = ["first", "second"].map((id) => ({
495 id,
496 driver: ProviderDriverKind.make("codex"),
497 email: `${id}@example.com`,
498 usageLimits: {
499 checkedAt,
500 windows: [window],
501 resetCredits: { availableCount: 2, nextCreditId: `${id}-credit` },
502 },
503 }));
504 const input = new Map([
505 [
506 EnvironmentId.make("env-a"),
507 {
508 ...laptop,
509 serverConfig: {
510 providers: [],
511 usageLimitSources: [{ ...source, accounts: hubAccounts }],
512 },
513 },
514 ],
515 ]);
516 expect(collectLimitAccounts(input).map((account) => account.redeem)).toEqual(
517 hubAccounts.map((account) => ({
518 environmentId: "env-a",
519 input: { sourceId: "hub", accountId: account.id, creditId: `${account.id}-credit` },
520 })),
521 );
522 });
523
524 it("does not give old credits the timestamp of a newer window-only read", () => {
525 const snapshots = [
526 { checkedAt, windows: [window], resetCredits: { availableCount: 2 } },
527 { checkedAt: "2026-09-03T12:00:00.000Z", windows: [window] },
528 {
529 checkedAt: "2026-09-03T11:30:00.000Z",
530 windows: [window],
531 resetCredits: { availableCount: 1 },
532 },
533 ];
534 const input = new Map(
535 snapshots.map((usageLimits, i) => [
536 EnvironmentId.make(`env-${i}`),
537 {
538 ...laptop,
539 serverConfig: {
540 providers: [
541 provider({
542 auth: { status: "authenticated", email: "same@example.com" },
543 usageLimits,
544 }),
545 ],
546 },
547 },
548 ]),
549 );
550 const [account] = collectLimitAccounts(input);
551 expect(account?.limits.checkedAt).toBe("2026-09-03T12:00:00.000Z");
552 expect(account?.limits.resetCredits?.availableCount).toBe(1);
553 expect(account?.redeem?.environmentId).toBe("env-2");
554 });
555
556 it("keeps one email in two workspaces apart while merging each workspace's duplicates", () => {
557 const login = (instanceId: string, workspaceId: string, usedPercent: number) =>
558 provider({
559 instanceId: ProviderInstanceId.make(instanceId),
560 auth: { status: "authenticated", email: "same@example.com", workspaceId },
561 usageLimits: { checkedAt, windows: [{ ...weekly, usedPercent }] },
562 });
563 const hubAccount = (id: string, workspaceId?: string) => ({
564 id,
565 driver: ProviderDriverKind.make("codex"),
566 email: "same@example.com",
567 ...(workspaceId ? { workspaceId } : {}),
568 usageLimits: { checkedAt, windows: [{ ...weekly, usedPercent: 50 }] },
569 });
570 const input = new Map([
571 [
572 EnvironmentId.make("env-a"),
573 {
574 ...laptop,
575 serverConfig: {
576 providers: [login("business", "ws-business", 8), login("personal", "ws-plus", 26)],
577 usageLimitSources: [
578 // A hub that names the workspace joins it; one that does not
579 // cannot say which of the two it read, so it keeps its own row.
580 { ...source, accounts: [hubAccount("plus.json", "ws-plus"), hubAccount("x.json")] },
581 ],
582 },
583 },
584 ],
585 [
586 EnvironmentId.make("env-b"),
587 {
588 entry: { target: { label: "Desktop" } },
589 serverConfig: { providers: [login("personal", "ws-plus", 26)] },
590 },
591 ],
592 ]);
593 const accounts = collectLimitAccounts(input);
594 expect(accounts.map((account) => account.key)).toEqual([
595 "env-a:business",
596 "env-a:personal",
597 "hub:x.json",
598 ]);
599 expect(accounts[0]?.limits.windows[0]?.usedPercent).toBe(8);
600 // One hub file name in two workspaces stays two accounts, even without an
601 // email to tell them apart.
602 const withoutEmail = (id: string, workspaceId: string) => {
603 const { email: _email, ...account } = hubAccount(id, workspaceId);
604 return account;
605 };
606 const sameFile = new Map([
607 [
608 EnvironmentId.make("env-a"),
609 {
610 ...laptop,
611 serverConfig: {
612 usageLimitSources: [{ ...source, accounts: [withoutEmail("a.json", "ws-1")] }],
613 },
614 },
615 ],
616 [
617 EnvironmentId.make("env-b"),
618 {
619 ...laptop,
620 serverConfig: {
621 usageLimitSources: [{ ...source, accounts: [withoutEmail("a.json", "ws-2")] }],
622 },
623 },
624 ],
625 ]);
626 expect(collectLimitAccounts(sameFile).map((account) => account.key)).toEqual([
627 "hub:a.json:ws-1",
628 "hub:a.json:ws-2",
629 ]);
630 expect(accounts[1]?.environments.map((environment) => environment.label)).toEqual([
631 "Laptop",
632 "Desktop",
633 ]);
634 });
635
636 it("joins a report without a workspace to the only workspace signed in with its email", () => {
637 const native = provider({
638 driver: claude,
639 auth: { status: "authenticated", email: "same@example.com", workspaceId: "org-a" },
640 usageLimits: { checkedAt, windows: [window] },
641 });
642 const hubAccount = {
643 id: "claude.json",
644 driver: claude,
645 email: "same@example.com",
646 usageLimits: { checkedAt, windows: [window] },
647 };
648 const withOther = (other: ServerProvider) =>
649 new Map([
650 [
651 EnvironmentId.make("env-a"),
652 {
653 ...laptop,
654 serverConfig: {
655 providers: [native, other],
656 usageLimitSources: [{ ...source, accounts: [hubAccount] }],
657 },
658 },
659 ],
660 ]);
661 const unrelated = provider({ instanceId: ProviderInstanceId.make("codex-2") });
662 expect(collectLimitAccounts(withOther(unrelated)).map((account) => account.key)).toEqual([
663 "env-a:codex",
664 ]);
665 // A second org whose limits could not be read still makes the hub ambiguous.
666 const unreadable = provider({
667 ...native,
668 instanceId: ProviderInstanceId.make("team"),
669 auth: { ...native.auth, workspaceId: "org-b" },
670 usageLimits: { checkedAt, windows: [], unavailable: { reason: "probeFailed" } },
671 });
672 expect(collectLimitAccounts(withOther(unreadable)).map((account) => account.key)).toEqual([
673 "env-a:codex",
674 "hub:claude.json",
675 ]);
676 });
677
678 it("names an environment once however many of its instances share the account", () => {
679 const shared = provider({
680 auth: { status: "authenticated", email: "same@example.com" },
681 usageLimits: { checkedAt, windows: [window] },
682 });
683 const input = new Map([
684 [
685 EnvironmentId.make("env-a"),
686 {
687 ...laptop,
688 serverConfig: {
689 providers: [shared, { ...shared, instanceId: ProviderInstanceId.make("work") }],
690 },
691 },
692 ],
693 ]);
694 expect(collectLimitAccounts(input)[0]?.environments).toEqual([
695 { environmentId: "env-a", label: "Laptop" },
696 ]);
697 });
698
699 it("keys a hub account without an email by hub, so two environments on one hub share it", () => {
700 const seat = {
701 id: "claude-team-seat.json",
702 driver: claude,
703 usageLimits: { checkedAt, windows: [window] },
704 };
705 const hub = { ...source, accounts: [seat] };
706 const input = new Map([
707 [EnvironmentId.make("env-a"), { ...laptop, serverConfig: { usageLimitSources: [hub] } }],
708 [
709 EnvironmentId.make("env-b"),
710 { entry: { target: { label: "Desktop" } }, serverConfig: { usageLimitSources: [hub] } },
711 ],
712 ]);
713 const accounts = collectLimitAccounts(input);
714 expect(accounts.map((account) => account.key)).toEqual(["hub:claude-team-seat.json"]);
715 expect(accounts[0]?.displayName).toBe("claude-team-seat");
716 });
717
718 it("pools Codex windows by kind, whichever slot reported them", () => {
719 const codexAccount = (id: string, slots: readonly string[]) => ({
720 id,
721 driver: ProviderDriverKind.make("codex"),
722 usageLimits: {
723 checkedAt,
724 windows: slots.map((slot) => ({ ...weekly, id: slot, usedPercent: 50 })),
725 },
726 });
727 const pooled = (accounts: ReturnType<typeof codexAccount>[]) =>
728 collectLimitPools(
729 collectLimitAccounts(
730 new Map([
731 [
732 EnvironmentId.make("env-a"),
733 { ...laptop, serverConfig: { usageLimitSources: [{ ...source, accounts }] } },
734 ],
735 ]),
736 ),
737 now,
738 )[0]?.windows ?? [];
739 // A weekly-only plan reports weekly as `primary`. The pool keeps one id
740 // whichever account sorts first.
741 for (const order of [
742 [codexAccount("business", ["primary"]), codexAccount("plus", ["secondary"])],
743 [codexAccount("plus", ["secondary"]), codexAccount("business", ["primary"])],
744 ]) {
745 const windows = pooled(order);
746 expect(windows.map((window) => window.id)).toEqual(["weekly"]);
747 expect(windows[0]?.members).toHaveLength(2);
748 }
749 // A second window of the same kind on one account stays apart, with its own id.
750 expect(
751 pooled([codexAccount("a", ["secondary"]), codexAccount("b", ["primary", "secondary"])]).map(
752 (window) => window.id,
753 ),
754 ).toEqual(["weekly", "weekly:secondary"]);
755 });
756
757 it("pools windows by id across accounts and orders resets by when they land", () => {
758 const input = new Map([
759 [
760 EnvironmentId.make("env-a"),
761 {
762 ...laptop,
763 serverConfig: {
764 providers: [],
765 usageLimitSources: [
766 {
767 ...source,
768 accounts: [
769 {
770 id: "a",
771 driver: claude,
772 usageLimits: {
773 checkedAt,
774 windows: [
775 { ...window, usedPercent: 80, resetsAt: "2026-09-03T13:00:00.000Z" },
776 { ...weekly, usedPercent: 20 },
777 ],
778 },
779 },
780 {
781 id: "b",
782 driver: claude,
783 usageLimits: {
784 checkedAt,
785 windows: [{ ...window, usedPercent: 40 }],
786 },
787 },
788 {
789 id: "c",
790 driver: ProviderDriverKind.make("codex"),
791 usageLimits: { checkedAt, windows: [{ ...weekly, usedPercent: 50 }] },
792 },
793 {
794 id: "unsupported",
795 driver: claude,
796 usageLimits: {
797 checkedAt,
798 windows: [],
799 unavailable: { reason: "unsupported" as const },
800 },
801 },
802 ],
803 },
804 ],
805 },
806 },
807 ],
808 ]);
809 const pools = collectLimitPools(collectLimitAccounts(input), now);
810 expect(pools.map((pool) => [pool.driver, pool.accounts.length])).toEqual([
811 ["claudeAgent", 2],
812 ["codex", 1],
813 ]);
814 const [session, week] = pools[0]!.windows;
815 // A member with no reset has no clock, so it does not vote on pace.
816 const untimed = collectLimitPools(
817 collectLimitAccounts(input).map((account) =>
818 account.key === "hub:b"
819 ? {
820 ...account,
821 limits: {
822 ...account.limits,
823 windows: account.limits.windows.map((w) => ({ ...w, resetsAt: undefined })),
824 },
825 }
826 : account,
827 ),
828 now,
829 );
830 // Only a votes: 80% used, 80% elapsed.
831 expect(untimed[0]?.windows[0]?.pace).toBe("on");
832 // a is 80% through its window and b 60%: the pool is 70% elapsed, 60% used.
833 expect(session).toMatchObject({
834 id: "five_hour",
835 remainingPercent: 40,
836 usedPercent: 60,
837 pace: "under",
838 });
839 expect(
840 session?.resets.map((reset) => [reset.member.account.key, reset.restoresPercent]),
841 ).toEqual([
842 ["hub:a", 40],
843 ["hub:b", 20],
844 ]);
845 expect(week).toMatchObject({ id: "seven_day", remainingPercent: 80, members: [{}] });
846 // Codex reports `primary` for both its five-hour and (on Go) monthly window.
847 const mixed = collectLimitPools(
848 [
849 ...collectLimitAccounts(input),
850 {
851 key: "go",
852 driver: claude,
853 displayName: "Go",
854 email: undefined,
855 plan: undefined,
856 accentColor: undefined,
857 environments: [],
858 sourceLabel: null,
859 redeem: null,
860 limits: {
861 checkedAt,
862 windows: [
863 {
864 id: "five_hour",
865 kind: "monthly",
866 label: "Monthly",
867 usedPercent: 82,
868 windowDurationMins: 30 * 24 * 60,
869 resetsAt: "2026-09-14T12:00:00.000Z",
870 },
871 ],
872 },
873 },
874 ],
875 now,
876 );
877 expect(mixed[0]?.windows.map((window) => [window.kind, window.members.length])).toEqual([
878 ["session", 2],
879 ["weekly", 1],
880 ["monthly", 1],
881 ]);
882 // Session resets determine the account order for every row.
883 expect(session?.members.map((member) => member.account.key)).toEqual(["hub:a", "hub:b"]);
884 expect(pools[0]?.accounts.map((account) => account.key)).toEqual(["hub:a", "hub:b"]);
885 });
886});
887
888describe("pooled account columns", () => {
889 const weekly = {
890 ...window,
891 id: "seven_day",
892 kind: "weekly",
893 label: "Weekly",
894 windowDurationMins: 7 * 24 * 60,
895 } as const;
896 const account = (key: string, windows: LimitAccount["limits"]["windows"]): LimitAccount => ({
897 key,
898 driver: ProviderDriverKind.make("claudeAgent"),
899 displayName: key,
900 email: undefined,
901 plan: undefined,
902 accentColor: undefined,
903 environments: [],
904 sourceLabel: "Hub",
905 redeem: null,
906 limits: { checkedAt: "2026-09-03T11:00:00.000Z", windows },
907 });
908 const keys = (pool: ReturnType<typeof collectLimitPools>[number]) =>
909 pool.windows.map((row) =>
910 row.columns.map((member) => (member.window ? member.account.key : null)),
911 );
912
913 it("keeps session columns across rows with opposite reset and usage orders", () => {
914 const accounts = [
915 account("a", [
916 { ...weekly, usedPercent: 80, resetsAt: "2026-09-05T12:00:00.000Z" },
917 { ...window, usedPercent: 10, resetsAt: "2026-09-03T15:00:00.000Z" },
918 ]),
919 account("b", [
920 { ...weekly, usedPercent: 20, resetsAt: "2026-09-06T12:00:00.000Z" },
921 { ...window, usedPercent: 90, resetsAt: "2026-09-03T13:00:00.000Z" },
922 ]),
923 ];
924 const [pool] = collectLimitPools(accounts, now);
925 expect(pool!.accounts.map((account) => account.key)).toEqual(["b", "a"]);
926 expect(keys(pool!)).toEqual([
927 ["b", "a"],
928 ["b", "a"],
929 ]);
930 expect(pool!.windows[1]!.resets.map((reset) => reset.member.account.key)).toEqual(["a", "b"]);
931 expect(pool!.windows[1]!.remainingPercent).toBe(50);
932 expect(keys(collectLimitPools(accounts.toReversed(), now)[0]!)).toEqual(keys(pool!));
933 });
934
935 it("preserves gaps without counting missing windows toward pooled quota", () => {
936 const [pool] = collectLimitPools(
937 [
938 account("a", [window]),
939 account("b", [
940 { ...window, resetsAt: "2026-09-03T15:00:00.000Z" },
941 { ...weekly, usedPercent: 80 },
942 ]),
943 account("c", [weekly]),
944 ],
945 now,
946 );
947 expect(keys(pool!)).toEqual([
948 ["a", "b", null],
949 [null, "b", "c"],
950 ]);
951 expect(pool!.windows[1]!.members.map((member) => member.account.key)).toEqual(["b", "c"]);
952 expect(pool!.windows[1]!.remainingPercent).toBe(40);
953 expect(pool!.windows[1]!.resets.map((reset) => reset.restoresPercent)).toEqual([40, 20]);
954 });
955
956 it("falls back to weekly resets when no account reports a session", () => {
957 const [pool] = collectLimitPools(
958 [
959 account("a", [{ ...weekly, resetsAt: "2026-09-06T12:00:00.000Z" }]),
960 account("b", [{ ...weekly, resetsAt: "2026-09-05T12:00:00.000Z" }]),
961 ],
962 now,
963 );
964 expect(keys(pool!)).toEqual([["b", "a"]]);
965 });
966
967 it("sorts unknown resets last and breaks ties consistently", () => {
968 const accounts = [
969 account("z", [{ ...window, resetsAt: undefined }]),
970 account("b", [window]),
971 account("a", [window]),
972 account("y", [{ ...window, resetsAt: "invalid" }]),
973 ];
974 expect(keys(collectLimitPools(accounts, now)[0]!)).toEqual([["a", "b", "y", "z"]]);
975 expect(keys(collectLimitPools(accounts.toReversed(), now)[0]!)).toEqual([["a", "b", "y", "z"]]);
976 });
977});
978
979describe("Cursor limit presentation", () => {
980 const cursorAccount: LimitAccount = {
981 key: "cursor",
982 driver: ProviderDriverKind.make("cursor"),
983 displayName: "Cursor",
984 email: undefined,
985 plan: undefined,
986 accentColor: undefined,
987 environments: [],
988 sourceLabel: "Cursor",
989 redeem: null,
990 limits: {
991 checkedAt: "2026-09-03T11:00:00.000Z",
992 windows: [
993 { id: "apiPercentUsed", kind: "monthly", label: "Other Models", usedPercent: 49 },
994 { id: "autoPercentUsed", kind: "monthly", label: "Cursor Models", usedPercent: 9 },
995 { id: "totalPercentUsed", kind: "monthly", label: "Overall", usedPercent: 15 },
996 ],
997 },
998 };
999
1000 it("hides the combined percentage and orders the two pools", () => {
1001 const [pool] = collectLimitPools([cursorAccount], now);
1002 const display = displayLimitWindows(pool!);
1003 expect(display.map((window) => window.id)).toEqual(["autoPercentUsed", "apiPercentUsed"]);
1004 });
1005
1006 it("keeps the combined percentage as a card if either allowance is missing", () => {
1007 const [pool] = collectLimitPools(
1008 [
1009 {
1010 ...cursorAccount,
1011 limits: {
1012 ...cursorAccount.limits,
1013 windows: cursorAccount.limits.windows.filter(
1014 (window) => window.id !== "apiPercentUsed",
1015 ),
1016 },
1017 },
1018 ],
1019 now,
1020 );
1021 const display = displayLimitWindows(pool!);
1022 expect(display.map((window) => window.id)).toEqual(["totalPercentUsed", "autoPercentUsed"]);
1023 });
1024});
1025
1026describe("collectLimitNotices", () => {
1027 const checkedAt = "2026-09-03T11:00:00.000Z";
1028 const claude = ProviderDriverKind.make("claudeAgent");
1029 const laptop = { entry: { target: { label: "Laptop" } } };
1030 const hub = {
1031 id: UsageLimitSourceId.make("hub"),
1032 kind: "cliproxy" as const,
1033 label: "hub",
1034 checkedAt,
1035 accounts: [],
1036 };
1037
1038 it("names failures and silence, skips unsupported accounts, and labels environments only when several", () => {
1039 const failed = provider({
1040 instanceId: ProviderInstanceId.make("claude"),
1041 driver: claude,
1042 displayName: "Claude Max",
1043 usageLimits: { checkedAt, windows: [], unavailable: { reason: "probeFailed" } },
1044 });
1045 const apiKey = provider({
1046 instanceId: ProviderInstanceId.make("api"),
1047 driver: claude,
1048 usageLimits: { checkedAt, windows: [], unavailable: { reason: "unsupported" } },
1049 });
1050 const silent = provider({ usageLimits: { checkedAt, windows: [] } });
1051 const one = new Map([
1052 [
1053 EnvironmentId.make("env-a"),
1054 {
1055 ...laptop,
1056 serverConfig: {
1057 providers: [failed, apiKey, silent],
1058 usageLimitSources: [
1059 hub,
1060 { ...hub, id: UsageLimitSourceId.make("down"), label: "down", error: "ECONNREFUSED" },
1061 ],
1062 },
1063 },
1064 ],
1065 ]);
1066 expect(collectLimitNotices(one)).toEqual([
1067 "Claude Max: Could not read limits.",
1068 "codex: No limits reported.",
1069 "hub: No accounts reported.",
1070 "down: ECONNREFUSED",
1071 ]);
1072
1073 one.set(EnvironmentId.make("env-b"), {
1074 entry: { target: { label: "Desktop" } },
1075 serverConfig: { providers: [], usageLimitSources: [] },
1076 });
1077 expect(collectLimitNotices(one)[0]).toBe("Laptop · Claude Max: Could not read limits.");
1078 });
1079});
1080
1081describe("/usage-limits", () => {
1082 const limits = { checkedAt: "2026-09-03T11:00:00.000Z", windows: [window] };
1083 const selected = provider({
1084 usageLimits: limits,
1085 auth: { status: "authenticated", email: "same@example.com" },
1086 });
1087 const sources = [
1088 {
1089 id: UsageLimitSourceId.make("hub"),
1090 kind: "cliproxy" as const,
1091 label: "Accounts",
1092 checkedAt: limits.checkedAt,
1093 accounts: [
1094 {
1095 id: "duplicate",
1096 driver: selected.driver,
1097 email: "SAME@example.com",
1098 usageLimits: limits,
1099 },
1100 { id: "oss", driver: selected.driver, plan: "Codex OSS", usageLimits: limits },
1101 { id: "other-provider", driver: ProviderDriverKind.make("claude"), usageLimits: limits },
1102 ],
1103 },
1104 ];
1105
1106 it("uses hub credit balances and redemption targets in the composer, including native duplicates", () => {
1107 const hubs = sources.map((source) => ({
1108 ...source,
1109 accounts: source.accounts.map((account) => ({
1110 ...account,
1111 usageLimits: {
1112 ...account.usageLimits,
1113 resetCredits: { availableCount: 2, nextCreditId: `${account.id}-credit` },
1114 },
1115 })),
1116 }));
1117 const report = collectProviderUsageLimits(selected.instanceId, [selected], hubs, now);
1118 expect(report?.accounts[0]?.limits.resetCredits?.availableCount).toBe(2);
1119 expect(report?.accounts[0]?.resetCreditInput).toEqual({
1120 sourceId: "hub",
1121 accountId: "duplicate",
1122 creditId: "duplicate-credit",
1123 });
1124 expect(report?.accounts.find((account) => account.id === "hub:oss")?.resetCreditInput).toEqual({
1125 sourceId: "hub",
1126 accountId: "oss",
1127 creditId: "oss-credit",
1128 });
1129 });
1130
1131 it("gives a hub credit to no native row when its email is signed in to two workspaces", () => {
1132 const workspaces = ["ws-a", "ws-b"].map((workspaceId) =>
1133 provider({
1134 instanceId: ProviderInstanceId.make(workspaceId),
1135 usageLimits: limits,
1136 auth: { status: "authenticated", email: "same@example.com", workspaceId },
1137 }),
1138 );
1139 const hub = [
1140 {
1141 ...sources[0]!,
1142 accounts: [
1143 {
1144 id: "duplicate",
1145 driver: selected.driver,
1146 email: "same@example.com",
1147 usageLimits: { ...limits, resetCredits: { availableCount: 2, nextCreditId: "c" } },
1148 },
1149 ],
1150 },
1151 ];
1152 const report = collectProviderUsageLimits(workspaces[0]!.instanceId, workspaces, hub, now);
1153 expect(report?.accounts.map((account) => account.resetCreditInput)).toEqual([
1154 { instanceId: "ws-a" },
1155 { instanceId: "ws-b" },
1156 { sourceId: "hub", accountId: "duplicate", creditId: "c" },
1157 ]);
1158 });
1159
1160 it("redeems a native duplicate through the hub even when the native snapshot is fresher", () => {
1161 const fresher = provider({
1162 usageLimits: {
1163 checkedAt: "2026-09-03T11:30:00.000Z",
1164 windows: [window],
1165 resetCredits: { availableCount: 3, nextCreditId: "native-credit" },
1166 },
1167 auth: { status: "authenticated", email: "same@example.com" },
1168 });
1169 const stale = [
1170 {
1171 id: UsageLimitSourceId.make("hub"),
1172 kind: "cliproxy" as const,
1173 label: "Accounts",
1174 checkedAt: limits.checkedAt,
1175 accounts: [
1176 {
1177 id: "duplicate",
1178 driver: fresher.driver,
1179 email: "SAME@example.com",
1180 usageLimits: {
1181 ...limits,
1182 resetCredits: { availableCount: 2, nextCreditId: "hub-credit" },
1183 },
1184 },
1185 ],
1186 },
1187 ];
1188 const report = collectProviderUsageLimits(fresher.instanceId, [fresher], stale, now);
1189 // Only redeeming through the hub clears the routing cooldown it holds for
1190 // this account, so the hub wins the path even with a staler balance.
1191 expect(report?.accounts[0]?.resetCreditInput).toEqual({
1192 sourceId: "hub",
1193 accountId: "duplicate",
1194 creditId: "hub-credit",
1195 });
1196 // The fresher native balance is still the one shown.
1197 expect(report?.accounts[0]?.limits.resetCredits?.availableCount).toBe(3);
1198 });
1199
1200 it("keeps accounts and custom instances separate, filtering by driver", () => {
1201 const report = collectProviderUsageLimits(
1202 selected.instanceId,
1203 [
1204 selected,
1205 provider({
1206 instanceId: ProviderInstanceId.make("codex-work"),
1207 displayName: "Work",
1208 usageLimits: { ...limits, resetCredits: { availableCount: 2 } },
1209 }),
1210 provider({
1211 driver: ProviderDriverKind.make("claude"),
1212 instanceId: ProviderInstanceId.make("claude"),
1213 usageLimits: limits,
1214 }),
1215 ],
1216 sources,
1217 now,
1218 );
1219 expect(report?.createdAt).toBe("2026-09-03T12:00:00.000Z");
1220 expect(report?.accounts.map((account) => account.id)).toEqual([
1221 "codex",
1222 "codex-work",
1223 "hub:oss",
1224 ]);
1225 expect(report?.accounts[0]).toMatchObject({
1226 instanceId: selected.instanceId,
1227 email: selected.auth.email,
1228 });
1229 expect(report?.accounts[1]).toMatchObject({
1230 displayName: "Work",
1231 limits: { resetCredits: { availableCount: 2 } },
1232 });
1233 expect(report?.accounts[2]).toMatchObject({
1234 label: "Accounts · oss",
1235 sourceLabel: "CLI Proxy",
1236 plan: "Codex OSS",
1237 });
1238 expect(report?.notices).toEqual([]);
1239 });
1240
1241 it("supports a source-only provider and keeps duplicates when the native probe failed", () => {
1242 expect(
1243 collectProviderUsageLimits(selected.instanceId, [provider({})], sources, now)?.accounts.map(
1244 (account) => account.id,
1245 ),
1246 ).toEqual(["hub:duplicate", "hub:oss"]);
1247 const failed = provider({ usageLimits: { ...limits, unavailable: { reason: "probeFailed" } } });
1248 expect(
1249 collectProviderUsageLimits(selected.instanceId, [failed], sources, now)?.accounts.map(
1250 (account) => account.id,
1251 ),
1252 ).toEqual(["codex", "hub:duplicate", "hub:oss"]);
1253 expect(collectProviderUsageLimits(selected.instanceId, [provider({})], [], now)).toBeNull();
1254 expect(
1255 collectProviderUsageLimits(
1256 selected.instanceId,
1257 [provider({ enabled: false, usageLimits: limits })],
1258 [],
1259 now,
1260 ),
1261 ).toBeNull();
1262 });
1263
1264 it("surfaces source errors only for sources that carry the selected driver", () => {
1265 const failing = { ...sources[0]!, error: "token expired" };
1266 expect(
1267 collectProviderUsageLimits(selected.instanceId, [selected], [failing], now)?.notices,
1268 ).toEqual(["Accounts: token expired"]);
1269 const claudeOnly = { ...failing, accounts: failing.accounts.slice(2) };
1270 expect(
1271 collectProviderUsageLimits(selected.instanceId, [selected], [claudeOnly], now)?.notices,
1272 ).toEqual([]);
1273 // A read failure clears the accounts, so the error must not depend on a match.
1274 const unreadable = { ...failing, accounts: [] };
1275 expect(
1276 collectProviderUsageLimits(selected.instanceId, [selected], [unreadable], now)?.notices,
1277 ).toEqual(["Accounts: token expired"]);
1278 // A source-only provider still gets the report, carrying only the error.
1279 const sourceOnly = collectProviderUsageLimits(
1280 selected.instanceId,
1281 [provider({})],
1282 [unreadable],
1283 now,
1284 );
1285 expect(sourceOnly?.accounts).toEqual([]);
1286 expect(sourceOnly?.notices).toEqual(["Accounts: token expired"]);
1287 });
1288
1289 it("advertises global and workspace commands only for providers present in Limits", () => {
1290 const withWorkspace = provider({
1291 workspaceSnapshots: [
1292 { cwd: "/tmp/project", checkedAt: limits.checkedAt, slashCommands: [], skills: [] },
1293 ],
1294 });
1295 const [supported] = withUsageLimitsCommands([withWorkspace], sources);
1296 expect(supported?.slashCommands.map((command) => command.name)).toEqual(["usage-limits"]);
1297 expect(
1298 supported?.workspaceSnapshots?.[0]?.slashCommands.map((command) => command.name),
1299 ).toEqual(["usage-limits"]);
1300 expect(withUsageLimitsCommands([withWorkspace], [])[0]?.slashCommands).toEqual([]);
1301 // A provider's own command of the same name is left alone without coverage.
1302 const ownCommand = provider({
1303 slashCommands: [{ name: "usage-limits", description: "Provider's own" }],
1304 });
1305 expect(withUsageLimitsCommands([ownCommand], [])[0]?.slashCommands).toEqual([
1306 { name: "usage-limits", description: "Provider's own" },
1307 ]);
1308 const unreadable = { ...sources[0]!, accounts: [], error: "token expired" };
1309 expect(
1310 withUsageLimitsCommands([withWorkspace], [unreadable])[0]?.slashCommands.map(
1311 (command) => command.name,
1312 ),
1313 ).toEqual(["usage-limits"]);
1314 expect(
1315 withUsageLimitsCommands([selected], [])[0]?.slashCommands.map((command) => command.name),
1316 ).toEqual(["usage-limits"]);
1317 });
1318});
1319
1320describe("sameUsageLimitCommandCoverage", () => {
1321 const codexAccount = {
1322 id: "a",
1323 driver: ProviderDriverKind.make("codex"),
1324 usageLimits: { checkedAt: "2026-09-03T11:00:00.000Z", windows: [] },
1325 };
1326 const base = {
1327 id: UsageLimitSourceId.make("hub"),
1328 kind: "cliproxy" as const,
1329 label: "Accounts",
1330 checkedAt: "2026-09-03T11:00:00.000Z",
1331 };
1332 it("ignores quota movement but not the drivers offered the command", () => {
1333 const withCodex = [{ ...base, accounts: [codexAccount] }];
1334 const withCodexLater = [
1335 {
1336 ...base,
1337 accounts: [
1338 {
1339 ...codexAccount,
1340 usageLimits: { ...codexAccount.usageLimits, checkedAt: "2026-09-03T12:00:00.000Z" },
1341 },
1342 ],
1343 },
1344 ];
1345 expect(sameUsageLimitCommandCoverage(withCodex, withCodexLater)).toBe(true);
1346 expect(sameUsageLimitCommandCoverage(withCodex, [{ ...base, accounts: [] }])).toBe(false);
1347 });
1348 it("treats a failed read as a change in coverage, in both directions", () => {
1349 const empty = [{ ...base, accounts: [] }];
1350 const failed = [{ ...base, accounts: [], error: "token expired" }];
1351 expect(sameUsageLimitCommandCoverage(empty, failed)).toBe(false);
1352 expect(sameUsageLimitCommandCoverage(failed, empty)).toBe(false);
1353 expect(
1354 sameUsageLimitCommandCoverage(failed, [{ ...base, accounts: [], error: "still down" }]),
1355 ).toBe(true);
1356 });
1357});
1358
1359describe("remainingPercent", () => {
1360 it("inverts and clamps the reported usage", () => {
1361 expect(remainingPercent(window)).toBe(60);
1362 expect(remainingPercent({ ...window, usedPercent: 0 })).toBe(100);
1363 expect(remainingPercent({ ...window, usedPercent: 100 })).toBe(0);
1364 expect(remainingPercent({ ...window, usedPercent: 33.4 })).toBe(67);
1365 });
1366});
1367
1368describe("isUsageLimitsCommand", () => {
1369 it("recognizes only the standalone local action", () => {
1370 expect(isUsageLimitsCommand(" /USAGE-LIMITS\n")).toBe(true);
1371 expect(isUsageLimitsCommand("/usage-limits explain")).toBe(false);
1372 expect(isUsageLimitsCommand("Explain /usage-limits")).toBe(false);
1373 expect(isUsageLimitsCommand("/usage")).toBe(false);
1374 });
1375});
1376
1377describe("external usage settings", () => {
1378 it("deduplicates destinations across accounts and environments without inventing quota pools", () => {
1379 const managed = provider({
1380 usageLimits: {
1381 checkedAt: "2026-09-03T11:00:00.000Z",
1382 windows: [],
1383 unavailable: { reason: "unsupported", message: "Track usage in ChatGPT." },
1384 externalUsage: { label: "ChatGPT usage", url: "https://chatgpt.com/#settings/Usage" },
1385 },
1386 });
1387 const presentations = new Map([
1388 [
1389 EnvironmentId.make("a"),
1390 {
1391 entry: { target: { label: "A" } },
1392 serverConfig: {
1393 providers: [managed, { ...managed, instanceId: ProviderInstanceId.make("personal") }],
1394 },
1395 },
1396 ],
1397 [
1398 EnvironmentId.make("b"),
1399 { entry: { target: { label: "B" } }, serverConfig: { providers: [managed] } },
1400 ],
1401 ]);
1402 expect(collectExternalUsageLinks(presentations)).toEqual([
1403 {
1404 ...managed.usageLimits!.externalUsage,
1405 message: "Track usage in ChatGPT.",
1406 accounts: [`${managed.instanceId} on A`, "personal on A", `${managed.instanceId} on B`],
1407 },
1408 ]);
1409 expect(collectLimitAccounts(presentations)).toEqual([]);
1410 expect(collectLimitNotices(presentations)).toEqual([]);
1411 });
1412 it("omits disabled, uninstalled and signed-out providers", () => {
1413 const managed = provider({
1414 usageLimits: {
1415 checkedAt: "2026-09-03T11:00:00.000Z",
1416 windows: [],
1417 externalUsage: { label: "ChatGPT usage", url: "https://chatgpt.com/#settings/Usage" },
1418 },
1419 });
1420 const presentations = new Map([
1421 [
1422 EnvironmentId.make("a"),
1423 {
1424 entry: { target: { label: "A" } },
1425 serverConfig: {
1426 providers: [
1427 { ...managed, enabled: false },
1428 { ...managed, installed: false },
1429 { ...managed, auth: { status: "unauthenticated" as const } },
1430 provider({}),
1431 ],
1432 },
1433 },
1434 ],
1435 ]);
1436 expect(collectExternalUsageLinks(presentations)).toEqual([]);
1437 });
1438});
1439
1440describe("ChatGPT sharing presentation", () => {
1441 it("requires verified sharing metadata rather than the Codex driver or login type", () => {
1442 const codex = provider({ auth: { status: "authenticated", type: "chatgpt" } });
1443 expect(usesChatGptSharing(codex)).toBe(false);
1444 expect(
1445 usesChatGptSharing({ ...codex, auth: { ...codex.auth, subscriptionSharing: true } }),
1446 ).toBe(true);
1447 expect(
1448 usesChatGptSharing({
1449 ...codex,
1450 auth: { status: "unauthenticated", subscriptionSharing: true },
1451 }),
1452 ).toBe(false);
1453 });
1454});
1455
1456describe("Antigravity limit presentation", () => {
1457 it("keeps the shared Claude/GPT bucket separate from Gemini and pairs their windows", () => {
1458 const antigravity = provider({
1459 instanceId: ProviderInstanceId.make("antigravity"),
1460 driver: ProviderDriverKind.make("antigravity"),
1461 usageLimits: {
1462 checkedAt: "2026-10-09T12:00:00.000Z",
1463 windows: [
1464 { ...window, id: "3p-5h", label: "Claude & GPT (shared) · 5-hour", usedPercent: 90 },
1465 { ...window, id: "gemini-5h", label: "Gemini · 5-hour", usedPercent: 20 },
1466 {
1467 ...window,
1468 id: "3p-weekly",
1469 kind: "weekly",
1470 label: "Claude & GPT (shared) · Weekly",
1471 usedPercent: 100,
1472 },
1473 {
1474 ...window,
1475 id: "gemini-weekly",
1476 kind: "weekly",
1477 label: "Gemini · Weekly",
1478 usedPercent: 10,
1479 },
1480 ],
1481 },
1482 });
1483 const accounts = collectLimitAccounts(
1484 new Map([
1485 [
1486 EnvironmentId.make("a"),
1487 {
1488 entry: { target: { label: "Local" } },
1489 serverConfig: {
1490 providers: [
1491 provider({
1492 usageLimits: { checkedAt: "2026-10-09T12:00:00.000Z", windows: [window] },
1493 }),
1494 antigravity,
1495 ],
1496 },
1497 },
1498 ],
1499 ]),
1500 );
1501 const pools = collectLimitPools(accounts, now);
1502 expect(pools.map((pool) => pool.driver)).toEqual(["codex", "antigravity"]);
1503 const windows = displayLimitWindows(pools[1]!);
1504 expect(windows.map((window) => window.id)).toEqual([
1505 "gemini-5h",
1506 "gemini-weekly",
1507 "3p-5h",
1508 "3p-weekly",
1509 ]);
1510 expect(windows.map((window) => window.remainingPercent)).toEqual([80, 90, 10, 0]);
1511 });
1512});