| author | |
| committer | |
| log | 2625327090115a630d97ff61257758c577589de7 |
| tree | 5f7d1822dc44127644ae6abf88f98f309089cf6c |
| parent | ed0f7b908b2e7b3a22e6fd82a73794c2fe6ee06e |
| signature | Signed by PGP key B5690EEEBB952194 |
3 files changed, 20 insertions(+), 3 deletions(-)
apps/mobile/src/features/usage/UsageLimitsPooled.tsx+3-2| ... | ... | @@ -8,7 +8,6 @@ import { |
| 8 | 8 | collectLimitPools, |
| 9 | 9 | cursorUsageWindowDetails, |
| 10 | 10 | displayLimitWindows, |
| 11 | formatDuration, | |
| 12 | 11 | formatResetsIn, |
| 13 | 12 | remainingPercent, |
| 14 | 13 | type LimitAccount, |
| ... | ... | @@ -123,7 +122,9 @@ function PoolWindowCard({ |
| 123 | 122 | {nextRefill ? ( |
| 124 | 123 | <Text className="text-xs tabular-nums text-foreground-muted"> |
| 125 | 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 | 128 | </Text> |
| 128 | 129 | ) : null} |
| 129 | 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 | 56 | } |
| 57 | 57 | |
| 58 | 58 | describe("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 | 73 | it("places the clock three fifths through a five-hour window with two hours left", () => { |
| 60 | 74 | expect(elapsedShare(window, now)).toBeCloseTo(0.6); |
| 61 | 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 | 607 | export function formatResetsIn(window: ServerProviderUsageWindow, now: number): string | null { |
| 608 | 608 | const resetsAt = resetMillis(window); |
| 609 | 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 | } |
| 612 | 614 | |
| 613 | 615 | /** Limit commands are served by T3 from the same snapshots as Usage → Limits. */ |