import { isoToEpochMs, jsonBody, makeLimit, statusForPercent, unknownReport } from "../driver.js"; import { defineUsageFeed } from "../registry.js"; import type { UsageLimit, UsageReportBody, UsageRequest, UsageState, UsageStep } from "../types.js"; export const OPENCODE_GO_USAGE_URL = "https://opencode.ai/zen/go/v1/usage"; function asRecord(value: unknown): Record | undefined { return value && typeof value === "object" && !Array.isArray(value) ? (value as Record) : undefined; } function asNumber(value: unknown): number | undefined { if (typeof value === "number" && Number.isFinite(value)) return value; if (typeof value === "string" && value.trim()) { const parsed = Number(value); return Number.isFinite(parsed) ? parsed : undefined; } return undefined; } interface WindowDef { key: string; label: string; windowLabel: string; } const OPENCODE_WINDOWS: readonly WindowDef[] = [ { key: "rolling", label: "Session", windowLabel: "5h window" }, { key: "weekly", label: "Weekly", windowLabel: "7d window" }, { key: "monthly", label: "Monthly", windowLabel: "30d window" }, ]; export function parseOpenCodeGoUsage(payload: unknown): { planType?: string; limits: UsageLimit[]; notes?: string[] } { const root = asRecord(payload); const usage = asRecord(root?.usage); if (!usage) return { limits: [] }; const limits: UsageLimit[] = []; for (const win of OPENCODE_WINDOWS) { const rawWindow = asRecord(usage[win.key]); if (!rawWindow) continue; // Converted from: percentage (0..100) const usedPercent = asNumber(rawWindow.percent); // Converted from: ISO-8601 string (e.g. "2026-09-16T04:40:14.037Z") const resetsAt = isoToEpochMs(rawWindow.resetsAt); const rawStatus = typeof rawWindow.status === "string" ? rawWindow.status.toLowerCase() : undefined; const isRateLimited = rawStatus === "rate-limited" || rawStatus === "exhausted"; const status = isRateLimited || (usedPercent !== undefined && usedPercent >= 100) ? "exhausted" : statusForPercent(usedPercent); limits.push( makeLimit(win.label, usedPercent, { windowLabel: win.windowLabel, resetsAt, status, }), ); } return { planType: "Go", limits, notes: ["OpenCode Go unified models"], }; } export const opencodegoUsageFeed = defineUsageFeed({ provider: "opencode-go", providerName: "OpenCode Zen", credentialKinds: ["apiKey"], advance(state: UsageState, responses): UsageStep { const credential = state.credential; if (credential.kind !== "apiKey") return { report: unknownReport("opencode-go needs an apiKey credential") }; if (responses.length === 0) { const headers = { Authorization: `Bearer ${credential.apiKey}`, Accept: "application/json", "User-Agent": "OpenCode-Status-Plugin/1.0", }; const requests: UsageRequest[] = [{ kind: "http", method: "GET", url: OPENCODE_GO_USAGE_URL, headers }]; return { requests }; } const response = responses[0]; if (!response || response.status !== 200) return { report: unknownReport(`HTTP ${response?.status ?? "no response"}`) }; const payload = jsonBody(response); if (payload === undefined) return { report: unknownReport("usage body is not JSON") }; const parsed = parseOpenCodeGoUsage(payload); const body: UsageReportBody = { ...parsed, accountId: credential.accountId, email: credential.email, error: null, }; return { report: body }; }, });