Skip to content

Cursor provider reports $0 / "No usage data" — hardcoded 35-day lookback drops bubbles, NULL createdAt rows are filtered out #163

@zsoltcs1123

Description

@zsoltcs1123

Version: Latest npm install (npm install -g codeburn), bundle at dist/cli.js
OS: Windows 11 (also affects macOS/Linux per code path inspection)
Cursor: current version, SQLite at %APPDATA%\Cursor\User\globalStorage\state.vscdb

Symptom

$ codeburn report --provider cursor -p all
   Today     7 Days     30 Days     This Month   [ All Time ]
╭──────────────────────────────────────────────────────────────────────────────╮
│ CodeBurn                                                                     │
│ No usage data found for All Time.                                            │
╰──────────────────────────────────────────────────────────────────────────────╯

Even --period all shows nothing despite a Cursor SQLite containing 1,919 token-bearing bubbles totaling 106.8M input + 4.9M output tokens (~$362 of usage).

Root cause

Two compounding bugs in the Cursor provider (parseBubbles / BUBBLE_QUERY_SINCE in the bundled dist/cli.js):

  1. Hardcoded 35-day lookback even for --period all.
    parseBubbles defines DEFAULT_LOOKBACK_DAYS = 35 and computes timeFloor = now - 35d, then passes it as a SQL bind param. There is no path that disables this floor — --period all does not bypass parseBubbles's own internal floor.

  2. SQL filter drops every bubble whose createdAt is NULL.
    The query contains:

    AND json_extract(value, '$.createdAt') > ?

    On current Cursor versions, the vast majority of bubbleId:* rows have no createdAt field at all (json_extract returns NULL, comparison is false, row is dropped).

    In my DB:

    • 1,919 token-bearing bubbles total
    • Only 701 have createdAt populated (oldest 2025-09-23, newest 2026-02-13)
    • 1,218 have NULL createdAt — these are silently discarded
    • 0 of the 701 with createdAt fall inside the hardcoded 35-day window → empty result
  3. Downstream filter in parseProviderSources also drops calls without a timestamp (if (!call.timestamp) continue; when dateRange is set), so even if the SQL is fixed, NULL-createdAt calls still get filtered out by the period filter — including --period all, because the "all" preset still produces a dateRange of (epoch 0, now) rather than undefined.

Reproduction

  1. Use Cursor recently enough that most bubbles are written without a createdAt field.
  2. npm install -g codeburn
  3. codeburn report --provider cursor -p all

Diagnostic queries against state.vscdb:

SELECT COUNT(*) FROM cursorDiskKV
 WHERE key LIKE 'bubbleId:%'
   AND json_extract(value, '$.tokenCount.inputTokens') > 0;
-- e.g. 1919

SELECT COUNT(*) FROM cursorDiskKV
 WHERE key LIKE 'bubbleId:%'
   AND json_extract(value, '$.tokenCount.inputTokens') > 0
   AND json_extract(value, '$.createdAt') IS NULL;
-- e.g. 1218

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions