authorgravatar for 118054752+extoci@users.noreply.github.comExotic <118054752+extoci@users.noreply.github.com> 2026-10-11 19:28:09+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-11 16:28:09+00:00
log2625327090115a630d97ff61257758c577589de7
tree5f7d1822dc44127644ae6abf88f98f309089cf6c
parented0f7b908b2e7b3a22e6fd82a73794c2fe6ee06e
signature Signed by PGP key B5690EEEBB952194

fix(usage): say resets momentarily in the final minute (#17869)


3 files changed, 20 insertions(+), 3 deletions(-)

apps/mobile/src/features/usage/UsageLimitsPooled.tsx+3-2
...@@ -8,7 +8,6 @@ import {...@@ -8,7 +8,6 @@ import {
8 collectLimitPools,8 collectLimitPools,
9 cursorUsageWindowDetails,9 cursorUsageWindowDetails,
10 displayLimitWindows,10 displayLimitWindows,
11 formatDuration,
12 formatResetsIn,11 formatResetsIn,
13 remainingPercent,12 remainingPercent,
14 type LimitAccount,13 type LimitAccount,
...@@ -123,7 +122,9 @@ function PoolWindowCard({...@@ -123,7 +122,9 @@ function PoolWindowCard({
123 {nextRefill ? (122 {nextRefill ? (
124 <Text className="text-xs tabular-nums text-foreground-muted">123 <Text className="text-xs tabular-nums text-foreground-muted">
125 ↻ +{nextRefill.restoresPercent}%{" "}124 ↻ +{nextRefill.restoresPercent}%{" "}
126 {nextRefill.at <= now ? "now" : `in ${formatDuration(nextRefill.at - now)}`}125 {formatResetsIn(nextRefill.member.window, now)
126 ?.replace("resets in ", "in ")
127 .replace("resets now", "now")}
127 </Text>128 </Text>
128 ) : null}129 ) : null}
129 <View className="flex-row gap-1">130 <View className="flex-row gap-1">
packages/shared/src/usageLimits.test.ts+14
...@@ -56,6 +56,20 @@ function provider(overrides: Partial<ServerProvider>): ServerProvider {...@@ -56,6 +56,20 @@ function provider(overrides: Partial<ServerProvider>): ServerProvider {
56}56}
5757
58describe("pace", () => {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
59 it("places the clock three fifths through a five-hour window with two hours left", () => {73 it("places the clock three fifths through a five-hour window with two hours left", () => {
60 expect(elapsedShare(window, now)).toBeCloseTo(0.6);74 expect(elapsedShare(window, now)).toBeCloseTo(0.6);
61 expect(paceOf(window, now)).toBe("under");75 expect(paceOf(window, now)).toBe("under");
packages/shared/src/usageLimits.ts+3-1
...@@ -607,7 +607,9 @@ export function formatDuration(ms: number): string {...@@ -607,7 +607,9 @@ export function formatDuration(ms: number): string {
607export function formatResetsIn(window: ServerProviderUsageWindow, now: number): string | null {607export function formatResetsIn(window: ServerProviderUsageWindow, now: number): string | null {
608 const resetsAt = resetMillis(window);608 const resetsAt = resetMillis(window);
609 if (resetsAt === null) return null;609 if (resetsAt === null) return null;
610 return resetsAt <= now ? "resets now" : `resets in ${formatDuration(resetsAt - now)}`;610 if (resetsAt <= now) return "resets now";
611 if (resetsAt - now < MINUTE) return "Resets momentarily";
612 return `resets in ${formatDuration(resetsAt - now)}`;
611}613}
612614
613/** Limit commands are served by T3 from the same snapshots as Usage → Limits. */615/** Limit commands are served by T3 from the same snapshots as Usage → Limits. */