From d60934ebdc5391a76e9f2756ca3e9a5aea723d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Galiano=20Sandoval?= Date: Wed, 26 Aug 2026 09:29:59 -0600 Subject: [PATCH] feat(core): display quota renewal date Render subscription renewal dates and countdowns in quota output, normalize numeric period-end timestamps, and cover UTC and edge-case behavior. --- src/quota-format.ts | 38 ++++++++++++++++++++++++++++--- src/quota.ts | 11 +++++++-- tests/test-quota.ts | 55 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/src/quota-format.ts b/src/quota-format.ts index 9bed62c..3541ca9 100644 --- a/src/quota-format.ts +++ b/src/quota-format.ts @@ -49,10 +49,42 @@ function creditsDetail(credits: CommandCodeCredits | null): string | undefined { return `Sources: ${parts.join(" / ")}` } -function subscriptionLine(subscription: CommandCodeSubscription): string { +function parsePeriodEnd(value: string): Date | null { + const trimmed = value.trim() + const timestamp = /^\d+$/.test(trimmed) ? Number(trimmed) : Date.parse(trimmed) + if (!Number.isFinite(timestamp) || timestamp < 0) return null + const milliseconds = timestamp >= 1e12 ? timestamp : timestamp * 1000 + const date = new Date(milliseconds) + return Number.isNaN(date.getTime()) ? null : date +} + +function subscriptionLine( + subscription: CommandCodeSubscription, + now: () => number = Date.now, +): string { const plan = (subscription.planId ?? "Unknown").replace(/[_-]+/g, " ").trim() const status = subscription.status ? ` (${subscription.status})` : "" - return `Plan: ${plan}${status}` + let renewal = "" + if (subscription.currentPeriodEnd) { + const end = parsePeriodEnd(subscription.currentPeriodEnd) + if (end) { + const diffMs = end.getTime() - now() + const days = Math.ceil(diffMs / 86_400_000) + const dateStr = end.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + timeZone: "UTC", + }) + if (days > 0) { + renewal = ` · renews ${dateStr} (${days}d)` + } else if (days === 0) { + renewal = ` · renews ${dateStr} (today)` + } else { + renewal = ` · renewed ${dateStr}` + } + } + } + return `Plan: ${plan}${status}${renewal}` } function formatTokens(tokens: number): string { @@ -77,7 +109,7 @@ export function formatQuota(quota: CommandCodeQuota, now: () => number = Date.no const detail = creditsDetail(quota.credits) if (detail) lines.push(detail) - if (quota.subscription) lines.push(subscriptionLine(quota.subscription)) + if (quota.subscription) lines.push(subscriptionLine(quota.subscription, now)) if (quota.summary) { lines.push("") diff --git a/src/quota.ts b/src/quota.ts index e595b08..44bec78 100644 --- a/src/quota.ts +++ b/src/quota.ts @@ -43,6 +43,13 @@ function stringValue(value: unknown): string | undefined { return typeof value === "string" && value.length > 0 ? value : undefined } +function timestampValue(value: unknown): string | undefined { + const text = stringValue(value) + if (text) return text + const number = numberValue(value) + return number === undefined ? undefined : String(number) +} + function errorMessage(error: unknown): string { return error instanceof Error ? error.message : String(error) } @@ -100,8 +107,8 @@ function parseSubscription(value: unknown): CommandCodeSubscription | null { const data = value.data const planId = stringValue(data.planId) const status = stringValue(data.status) - const currentPeriodStart = stringValue(data.currentPeriodStart) - const currentPeriodEnd = stringValue(data.currentPeriodEnd) + const currentPeriodStart = timestampValue(data.currentPeriodStart) + const currentPeriodEnd = timestampValue(data.currentPeriodEnd) if (!planId && !status && !currentPeriodStart && !currentPeriodEnd) return null return { planId: planId ?? null, diff --git a/tests/test-quota.ts b/tests/test-quota.ts index 30f5a9c..23e1c5c 100644 --- a/tests/test-quota.ts +++ b/tests/test-quota.ts @@ -276,7 +276,13 @@ describe("Command Code quota", () => { const { fetchImpl } = okFetch({ whoami: { user: { userName: "alice", keyName: "Pi Agent" }, org: null }, credits: { credits: { monthlyCredits: 5, purchasedCredits: 0, freeCredits: 0 } }, - subscriptions: { data: { planId: "pro", status: "active" } }, + subscriptions: { + data: { + planId: "pro", + status: "active", + currentPeriodEnd: Date.parse("2026-02-01T00:00:00Z"), + }, + }, summary: { totalCost: 1.06, totalCount: 654, totalTokens: 74_200_000 }, }) const result = await fetchCommandCodeQuota({ apiKey: "cc_test_key", fetchImpl }) @@ -284,6 +290,7 @@ describe("Command Code quota", () => { if (!result.ok) return assert.equal(result.quota.summary?.totalTokens, 74_200_000) assert.equal(result.quota.account.keyName, "Pi Agent") + assert.equal(result.quota.subscription?.currentPeriodEnd, "1769904000000") }) it("rejects missing API keys as a config error", async () => { @@ -327,13 +334,13 @@ describe("Command Code quota", () => { summary: { totalCost: 12.34, totalCount: 1500 }, } - const output = formatQuota(quota, () => 1_700_000_000_000) + const output = formatQuota(quota, () => Date.parse("2026-01-15T00:00:00Z")) assert.doesNotMatch(output, /Command Code quota —/) assert.match(output, /Credits/) assert.match(output, /Remaining: \$55\.00 of \$67\.34/) assert.match(output, /Used: \$12\.34/) assert.match(output, /Sources: monthly \$40\.00 \/ purchased \$10\.00 \/ free \$5\.00/) - assert.match(output, /Plan: pro \(active\)/) + assert.match(output, /Plan: pro \(active\) · renews Feb 1 \(17d\)/) assert.match(output, /Usage \(billing period\)/) assert.match(output, /Cost: \$12\.34/) assert.match(output, /Requests: 1,500/) @@ -344,6 +351,48 @@ describe("Command Code quota", () => { assert.match(output, /https:\/\/commandcode\.ai\/usage/) }) + it("formats renewal dates in UTC and handles renewal edge cases", () => { + const baseQuota: CommandCodeQuota = { + account: { login: "alice", orgId: null }, + credits: null, + subscription: null, + summary: null, + } + const formatRenewal = (currentPeriodEnd: string | null, now: string) => + formatQuota( + { + ...baseQuota, + subscription: { + planId: "pro", + status: "active", + currentPeriodStart: null, + currentPeriodEnd, + }, + }, + () => Date.parse(now), + ) + + const beforeReset = formatRenewal("2026-02-01T00:00:00Z", "2026-01-31T12:00:00Z") + assert.match(beforeReset, /Plan: pro \(active\) · renews Feb 1 \(1d\)/) + + const numericTimestamp = formatRenewal( + String(Date.parse("2026-02-01T00:00:00Z")), + "2026-01-31T12:00:00Z", + ) + assert.match(numericTimestamp, /Plan: pro \(active\) · renews Feb 1 \(1d\)/) + + const today = formatRenewal("2026-01-31T12:00:00Z", "2026-01-31T12:00:00Z") + assert.match(today, /Plan: pro \(active\) · renews Jan 31 \(today\)/) + + const expired = formatRenewal("2026-01-30T00:00:00Z", "2026-01-31T12:00:00Z") + assert.match(expired, /Plan: pro \(active\) · renewed Jan 30/) + + for (const currentPeriodEnd of [null, "not-a-date"]) { + const output = formatRenewal(currentPeriodEnd, "2026-01-31T12:00:00Z") + assert.doesNotMatch(output, /renews|renewed/) + } + }) + it("redacts token-like values from error messages", () => { // 16+ char run after a credential key is redacted by the shared redactor. assert.equal(redactValue("api_key=abcdefghijklmnop123456"), "api_key=[redacted]")