fix(commandcode): show the monthly window (#1734)

Command Code's credits endpoint only reports monthly credits left, so the
monthly window was dropped. For an active subscription on a known plan the
plan price now comes from a small table (the API has no monthly cap field):
pool = max(plan, left), used = pool - left, reset = currentPeriodEnd.
Unknown plans and purchased/free credits stay out. CLI and menubar mirrored.
This commit is contained in:
Resham Joshi 2026-10-10 21:40:43 +02:00 • committed by GitHub
parent 48773459ab
commit 4c779ef301
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 133 additions and 23 deletions

View file

@ -4,12 +4,23 @@ import Foundation
/// Command Code CLI keeps in ~/.commandcode/auth.json (read-only, never logged).
/// GET /alpha/billing/credits carries the 5-hour and weekly windows as USD
/// credits used of a cap (resetAt epoch ms, 0 while no window is open) plus
/// the remaining credits; GET /alpha/billing/subscriptions carries the plan id.
/// Mirrors src/quota/commandcode.ts.
/// the remaining credits; GET /alpha/billing/subscriptions carries the plan id,
/// status and period end. Mirrors src/quota/commandcode.ts.
enum CommandCodeSubscriptionService {
static let creditsURL = URL(string: "https://api.commandcode.ai/alpha/billing/credits")!
static let subscriptionsURL = URL(string: "https://api.commandcode.ai/alpha/billing/subscriptions")!
private static let timeoutSeconds: TimeInterval = 15
// Command Code's API gives no monthly cap, so the plan price comes from this table.
static let planMonthlyUSD: [String: Double] = [
"individual-go": 10, "individual-go-v1": 10, "individual-goat": 70, "individual-pro": 30, "individual-pro-v1": 80,
"individual-provider": 15, "individual-max": 150, "individual-ultra": 300, "teams-pro": 40,
]
struct Subscription: Equatable, Sendable {
var planID: String?
var status: String?
var currentPeriodEnd: String?
}
enum FetchError: Error, Equatable, LocalizedError, Sendable {
case noCredentials
@ -117,29 +128,34 @@ enum CommandCodeSubscriptionService {
default: throw FetchError.parseFailure
}
var planID: String?
var plan = Subscription()
if let (body, http) = await subscription, http.statusCode == 200,
let root = try? JSONSerialization.jsonObject(with: body) as? [String: Any] {
planID = (root["data"] as? [String: Any])?["planId"] as? String
let root = try? JSONSerialization.jsonObject(with: body) as? [String: Any],
let row = root["data"] as? [String: Any] {
plan = Subscription(
planID: row["planId"] as? String,
status: row["status"] as? String,
currentPeriodEnd: row["currentPeriodEnd"] as? String
)
}
return try decode(data, planID: planID)
return try decode(data, subscription: plan)
}
static func decode(_ data: Data, planID: String? = nil) throws -> QuotaSummary {
static func decode(_ data: Data, subscription: Subscription = Subscription()) throws -> QuotaSummary {
guard let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
throw FetchError.parseFailure
}
let limits = root["windowLimits"] as? [String: Any] ?? [:]
let fiveHour = window("5-hour", limits["fiveHour"])
let weekly = window("Weekly", limits["weekly"])
let details = [fiveHour, weekly].compactMap { $0 }
guard !details.isEmpty else { throw FetchError.parseFailure }
guard fiveHour != nil || weekly != nil else { throw FetchError.parseFailure }
let details = [fiveHour, weekly, monthlyWindow(root["credits"], subscription)].compactMap { $0 }
return QuotaSummary(
providerFilter: .all,
connection: .connected,
primary: weekly ?? fiveHour,
details: details,
planLabel: planLabel(planID),
planLabel: planLabel(subscription.planID),
footerLines: creditsLine(root["credits"]).map { [$0] } ?? []
)
}
@ -164,6 +180,27 @@ enum CommandCodeSubscriptionService {
)
}
/// Monthly credits used of the plan price; purchased and free credits are not part of the plan.
private static func monthlyWindow(_ credits: Any?, _ subscription: Subscription) -> QuotaSummary.Window? {
guard subscription.status == "active",
let planID = subscription.planID, let plan = planMonthlyUSD[planID],
let left = number((credits as? [String: Any])?["monthlyCredits"]) else { return nil }
let pool = max(plan, left)
return QuotaSummary.Window(
label: "Monthly",
percent: min(1, max(0, (pool - left) / pool)),
resetsAt: subscription.currentPeriodEnd.flatMap(parseDate)
)
}
private static func parseDate(_ raw: String) -> Date? {
let iso = ISO8601DateFormatter()
iso.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
if let date = iso.date(from: raw) { return date }
iso.formatOptions = [.withInternetDateTime]
return iso.date(from: raw)
}
private static func creditsLine(_ raw: Any?) -> String? {
guard let credits = raw as? [String: Any] else { return nil }
let parts = [("monthlyCredits", "monthly"), ("purchasedCredits", "purchased"), ("freeCredits", "free")]

View file

@ -16,7 +16,7 @@ struct CommandCodeQuotaTests {
"fiveHour":{"used":0.75,"cap":3,"exceeded":false,"resetAt":0},
"weekly":{"used":6.0293354601,"cap":6,"exceeded":true,"resetAt":1791653049551}}}
"""
nonisolated private static let subscriptionBody = #"{"success":true,"data":{"status":"active","planId":"individual-go-v1"}}"#
nonisolated private static let subscriptionBody = #"{"success":true,"data":{"status":"active","planId":"individual-go-v1","currentPeriodEnd":"2026-11-01T10:38:29.000Z"}}"#
nonisolated private static func response(_ request: URLRequest, _ status: Int) -> HTTPURLResponse {
HTTPURLResponse(url: request.url!, statusCode: status, httpVersion: nil, headerFields: nil)!
@ -43,10 +43,13 @@ struct CommandCodeQuotaTests {
let body = request.url == CommandCodeSubscriptionService.creditsURL ? Self.creditsBody : Self.subscriptionBody
return (Data(body.utf8), Self.response(request, 200))
})
#expect(summary.details.map(\.label) == ["5-hour", "Weekly"])
#expect(summary.details.map(\.percent) == [0.25, 1])
#expect(summary.details.map(\.label) == ["5-hour", "Weekly", "Monthly"])
#expect(summary.details[0].percent == 0.25)
#expect(summary.details[1].percent == 1)
#expect(abs(summary.details[2].percent - 0.6029) < 0.0001)
#expect(summary.details[0].resetsAt == nil)
#expect(summary.details[1].resetsAt == Date(timeIntervalSince1970: 1_791_653_049.551))
#expect(summary.details[2].resetsAt == Date(timeIntervalSince1970: 1_793_529_509))
#expect(summary.primary?.label == "Weekly")
#expect(summary.planLabel == "Go")
#expect(summary.footerLines == ["Credits left: $3.97 monthly"])
@ -57,6 +60,23 @@ struct CommandCodeQuotaTests {
}
}
@Test("the monthly window needs an active subscription on a known plan")
func monthlyNeedsKnownActivePlan() throws {
let body = Data(Self.creditsBody.utf8)
let known = CommandCodeSubscriptionService.Subscription(
planID: "individual-go-v1", status: "active", currentPeriodEnd: "2026-11-01T10:38:29Z")
let go = try CommandCodeSubscriptionService.decode(body, subscription: known)
#expect(go.details.last?.label == "Monthly")
#expect(go.details.last?.resetsAt == Date(timeIntervalSince1970: 1_793_529_509))
#expect(go.primary?.label == "Weekly")
var unknown = known
unknown.planID = "individual-mystery"
#expect(try CommandCodeSubscriptionService.decode(body, subscription: unknown).details.map(\.label) == ["5-hour", "Weekly"])
var inactive = known
inactive.status = "canceled"
#expect(try CommandCodeSubscriptionService.decode(body, subscription: inactive).details.map(\.label) == ["5-hour", "Weekly"])
}
@Test("a failed subscription call only drops the plan label")
func subscriptionFailureKeepsWindows() async throws {
let summary = try await CommandCodeSubscriptionService.refresh(deps: Self.deps { request in

View file

@ -5,7 +5,8 @@
// the window's cap; resetAt is epoch ms, 0 while no window is open.
// credits.{monthlyCredits,purchasedCredits,freeCredits}: USD remaining.
// - GET https://api.commandcode.ai/alpha/billing/subscriptions
// data.planId for the plan label; optional, a failure only drops the label.
// data.{planId,status,currentPeriodEnd} for the plan label and the monthly
// window; optional, a failure only drops both.
//
// Credential: the CLI's own ~/.commandcode/auth.json `apiKey`, read-only.
// The API refuses requests without a User-Agent, so one is always sent.
@ -20,6 +21,11 @@ const EXPIRED_FOOTER = ['Command Code session expired. Sign in with the Command
const RATE_LIMITED_FOOTER = ['Command Code rate-limited the quota request.']
const UNAVAILABLE_FOOTER = ['Command Code is temporarily unavailable.']
const PARSE_FOOTER = ['Command Code quota response was malformed.']
// Command Code's API gives no monthly cap, so the plan price comes from this table.
const PLAN_MONTHLY_USD: Record<string, number> = {
'individual-go': 10, 'individual-go-v1': 10, 'individual-goat': 70, 'individual-pro': 30, 'individual-pro-v1': 80,
'individual-provider': 15, 'individual-max': 150, 'individual-ultra': 300, 'teams-pro': 40,
}
export type CommandCodeDeps = {
fetch: typeof fetch
@ -73,8 +79,25 @@ function creditsNote(raw: unknown): string | null {
return `Credits left: ${shown.map(part => `$${part.value.toFixed(2)} ${part.name}`).join(', ')}`
}
/** `null` when neither window is readable. */
export function decodeCommandCodeCredits(body: unknown, planId?: unknown): QuotaProvider | null {
export type CommandCodeSubscription = { planId?: unknown; status?: unknown; currentPeriodEnd?: unknown }
/** Monthly credits used of the plan price; purchased and free credits are not part of the plan. */
function monthlyWindow(credits: unknown, subscription: CommandCodeSubscription): QuotaWindow | null {
if (subscription.status !== 'active' || typeof subscription.planId !== 'string') return null
const plan = Object.hasOwn(PLAN_MONTHLY_USD, subscription.planId) ? PLAN_MONTHLY_USD[subscription.planId]! : null
const left = credits && typeof credits === 'object' ? num((credits as Record<string, unknown>)['monthlyCredits']) : null
if (plan === null || left === null) return null
const pool = Math.max(plan, left)
const end = typeof subscription.currentPeriodEnd === 'string' ? Date.parse(subscription.currentPeriodEnd) : NaN
return {
label: 'Monthly',
percent: fraction((pool - left) / pool * 100)!,
resetsAt: Number.isFinite(end) ? new Date(end).toISOString() : null,
}
}
/** `null` when neither the 5-hour nor the weekly window is readable. */
export function decodeCommandCodeCredits(body: unknown, subscription: CommandCodeSubscription = {}): QuotaProvider | null {
if (!body || typeof body !== 'object') return null
const root = body as Record<string, unknown>
const limits = root['windowLimits'] && typeof root['windowLimits'] === 'object'
@ -82,14 +105,15 @@ export function decodeCommandCodeCredits(body: unknown, planId?: unknown): Quota
: {}
const fiveHour = windowOf('5-hour', limits['fiveHour'])
const weekly = windowOf('Weekly', limits['weekly'])
const details = [fiveHour, weekly].filter((row): row is QuotaWindow => row !== null)
if (details.length === 0) return null
if (!fiveHour && !weekly) return null
const details = [fiveHour, weekly, monthlyWindow(root['credits'], subscription)]
.filter((row): row is QuotaWindow => row !== null)
const note = creditsNote(root['credits'])
return {
provider: 'commandcode', connection: 'connected',
primary: weekly ?? fiveHour!,
details,
planLabel: commandCodePlanLabel(planId),
planLabel: commandCodePlanLabel(subscription.planId),
footerLines: note ? [note] : [],
...(note ? { notes: [note] } : {}),
}
@ -128,10 +152,10 @@ export async function fetchCommandCodeQuota(options: Partial<CommandCodeDeps> &
if (credits.status >= 500) return { quota: empty('transientFailure', UNAVAILABLE_FOOTER) }
if (!credits.ok) return { quota: empty('transientFailure', PARSE_FOOTER) }
// Never log either body - they carry account data.
const planId = subscription?.ok
? await subscription.json().then(body => (body as { data?: { planId?: unknown } })?.data?.planId, () => undefined)
const plan = subscription?.ok
? await subscription.json().then(body => (body as { data?: CommandCodeSubscription })?.data, () => undefined)
: undefined
const quota = decodeCommandCodeCredits(await credits.json(), planId)
const quota = decodeCommandCodeCredits(await credits.json(), plan && typeof plan === 'object' ? plan : {})
return { quota: quota ?? empty('transientFailure', PARSE_FOOTER) }
} catch (error) {
console.warn(`Command Code quota unavailable: ${sanitizeError(error)}`)

View file

@ -25,7 +25,7 @@ function jsonResponse(body: unknown, status = 200): Response {
describe('Command Code quota decoding', () => {
it('maps the 5-hour and weekly windows as used of cap, clamped', () => {
const quota = decodeCommandCodeCredits(creditsBody, 'individual-go-v1')
const quota = decodeCommandCodeCredits(creditsBody, { planId: 'individual-go-v1' })
expect(quota?.connection).toBe('connected')
expect(quota?.details).toEqual([
{ label: '5-hour', percent: 0.25, resetsAt: null },
@ -36,6 +36,33 @@ describe('Command Code quota decoding', () => {
expect(quota?.notes).toEqual(['Credits left: $3.97 monthly'])
})
it('adds the monthly window from the plan price for an active known plan', () => {
const body = { ...creditsBody, windowLimits: { ...creditsBody.windowLimits, fiveHour: { used: 0, cap: 3, exceeded: false, resetAt: 0 } } }
const quota = decodeCommandCodeCredits(body, subscriptionBody.data)
expect(quota?.details.map(row => [row.label, row.resetsAt])).toEqual([
['5-hour', null],
['Weekly', '2026-10-10T17:24:09.551Z'],
['Monthly', new Date('2026-11-01T10:38:29.000Z').toISOString()],
])
expect(quota?.details[0]!.percent).toBe(0)
expect(quota?.details[1]!.percent).toBe(1)
expect(quota?.details[2]!.percent).toBeCloseTo(0.6029, 4)
expect(quota?.primary?.label).toBe('Weekly')
})
it('leaves out the monthly window for an unknown plan or an inactive subscription', () => {
const labels = (subscription: object) => decodeCommandCodeCredits(creditsBody, subscription)?.details.map(row => row.label)
expect(labels({ ...subscriptionBody.data, planId: 'individual-mystery' })).toEqual(['5-hour', 'Weekly'])
expect(labels({ ...subscriptionBody.data, planId: 'toString' })).toEqual(['5-hour', 'Weekly'])
expect(labels({ ...subscriptionBody.data, status: 'canceled' })).toEqual(['5-hour', 'Weekly'])
expect(labels({})).toEqual(['5-hour', 'Weekly'])
})
it('uses the larger of plan price and credits left as the pool', () => {
const body = { ...creditsBody, credits: { monthlyCredits: 12 } }
expect(decodeCommandCodeCredits(body, subscriptionBody.data)?.details[2]).toMatchObject({ label: 'Monthly', percent: 0 })
})
it('skips an unreadable window and rejects a body with none', () => {
const quota = decodeCommandCodeCredits({ windowLimits: { fiveHour: { used: 1, cap: 0 }, weekly: { used: 3, cap: 6, resetAt: 0 } } })
expect(quota?.details).toEqual([{ label: 'Weekly', percent: 0.5, resetsAt: null }])
@ -70,6 +97,7 @@ describe('Command Code quota fetch', () => {
})
expect(result.quota.connection).toBe('connected')
expect(result.quota.planLabel).toBe('Go')
expect(result.quota.details.map(row => row.label)).toEqual(['5-hour', 'Weekly', 'Monthly'])
expect(seen.map(row => row.url).sort()).toEqual([
'https://api.commandcode.ai/alpha/billing/credits',
'https://api.commandcode.ai/alpha/billing/subscriptions',
@ -87,6 +115,7 @@ describe('Command Code quota fetch', () => {
})
expect(result.quota.connection).toBe('connected')
expect(result.quota.planLabel).toBeNull()
expect(result.quota.details.map(row => row.label)).toEqual(['5-hour', 'Weekly'])
})
it('maps HTTP failures', async () => {