diff --git a/plugins/windsurf/plugin.js b/plugins/windsurf/plugin.js index 1b3e6999..eb167b60 100644 --- a/plugins/windsurf/plugin.js +++ b/plugins/windsurf/plugin.js @@ -97,6 +97,7 @@ function formatDollarsFromMicros(value) { var micros = readFiniteNumber(value) if (micros === null) return null + if (!Number.isFinite(micros)) return null if (micros < 0) micros = 0 return "$" + (micros / 1000000).toFixed(2) } @@ -119,7 +120,6 @@ return ( readFiniteNumber(planStatus && planStatus.dailyQuotaRemainingPercent) !== null && readFiniteNumber(planStatus && planStatus.weeklyQuotaRemainingPercent) !== null && - readFiniteNumber(planStatus && planStatus.overageBalanceMicros) !== null && readFiniteNumber(planStatus && planStatus.dailyQuotaResetAtUnix) !== null && readFiniteNumber(planStatus && planStatus.weeklyQuotaResetAtUnix) !== null ) @@ -138,20 +138,21 @@ var weeklyReset = unixSecondsToIso(ctx, planStatus.weeklyQuotaResetAtUnix) var extraUsageBalance = formatDollarsFromMicros(planStatus.overageBalanceMicros) - if (!dailyReset || !weeklyReset || !extraUsageBalance) throw QUOTA_HINT + if (!dailyReset || !weeklyReset) throw QUOTA_HINT var dailyLine = buildQuotaLine(ctx, "Daily quota", planStatus.dailyQuotaRemainingPercent, dailyReset, DAY_MS) var weeklyLine = buildQuotaLine(ctx, "Weekly quota", planStatus.weeklyQuotaRemainingPercent, weeklyReset, WEEK_MS) if (!dailyLine || !weeklyLine) throw QUOTA_HINT + var lines = [dailyLine, weeklyLine] + if (extraUsageBalance) { + lines.push(ctx.line.text({ label: "Extra usage balance", value: extraUsageBalance })) + } + return { plan: planName, - lines: [ - dailyLine, - weeklyLine, - ctx.line.text({ label: "Extra usage balance", value: extraUsageBalance }), - ], + lines: lines, } } diff --git a/plugins/windsurf/plugin.test.js b/plugins/windsurf/plugin.test.js index 1a4b98d0..49b25b6f 100644 --- a/plugins/windsurf/plugin.test.js +++ b/plugins/windsurf/plugin.test.js @@ -276,6 +276,26 @@ describe("windsurf plugin", () => { expect(result.lines.find((line) => line.label === "Extra usage balance")?.value).toBe("$0.00") }) + it("renders quota lines when Windsurf omits extra usage balance", async () => { + const ctx = makeCtx() + setupCloudMock(ctx, { + stableAuth: "sk-ws-01-stable", + stableResponse: { + status: 200, + bodyText: JSON.stringify(makeQuotaResponse({ overageBalanceMicros: undefined })), + }, + }) + + const plugin = await loadPlugin() + const result = plugin.probe(ctx) + + expect(result.plan).toBe("Teams") + expect(result.lines).toHaveLength(2) + expect(result.lines.find((line) => line.label === "Daily quota")?.used).toBe(0) + expect(result.lines.find((line) => line.label === "Weekly quota")?.used).toBe(0) + expect(result.lines.find((line) => line.label === "Extra usage balance")).toBeUndefined() + }) + it("falls back to Unknown plan when planInfo is null", async () => { const ctx = makeCtx() setupCloudMock(ctx, { @@ -687,7 +707,7 @@ describe("windsurf plugin", () => { finiteSpy.mockRestore() }) - it("throws quota unavailable when extra usage balance becomes invalid after contract validation", async () => { + it("omits extra usage balance when it becomes invalid after contract validation", async () => { const ctx = makeCtx() const originalTryParseJson = ctx.util.tryParseJson ctx.util.tryParseJson = vi.fn((text) => { @@ -723,7 +743,8 @@ describe("windsurf plugin", () => { }) const plugin = await loadPlugin() - expect(() => plugin.probe(ctx)).toThrow("Windsurf quota data unavailable. Try again later.") + const result = plugin.probe(ctx) + expect(result.lines.find((line) => line.label === "Extra usage balance")).toBeUndefined() finiteSpy.mockRestore() })