invalidateProviderDays no longer skips when the build has no daily-cache file yet, so the first Cursor import clears the covered days. cursor joins the pending re-derive list at v71 so stuck caches repair once.
Cursor Agent transcripts dated every turn at the session's last write. A
synced usage export ends its coverage at its newest billed event, so a
session that started before it and finished after it kept all its local
estimates on top of the billed rows. Date transcript turns by their
prompt's <timestamp> tag instead, like store.db turns already are. On a
real account this removed 101 double-counted calls on the last synced day,
and 2,748 of the 2,767 calls stamped on 22 Sep moved back to 17-20 Sep,
where Cursor billed them.
Synced plan rows carry no dollars (Included, Free), and Auto and Grok Bot
rows never name the model that served them, so their list price is a
stand-in: mark them costIsEstimated. Named models stay exact.
Daily cache to v58; cursor-agent joins PENDING_REDERIVE at 58 since a day's
call count can drop when turns move to their prompt day.
* Sync Cursor usage from cursor.com automatically (#1545)
Reports that show Cursor dollars download the account's own usage export
with the Cursor app's session, at most every 15 minutes, and merge it into
the Cursor import store as source-tagged events. Manual CSV imports are
never replaced; synced rows dedupe against them by hash. codeburn import
cursor --sync forces one. Off with cursorSync: false or
CODEBURN_CURSOR_SYNC=0.
* Cursor sync: hourly with jitter, keep every account's history
The throttle is now an hour plus up to 5 minutes of jitter, and three
failed requests in a row back off 6 hours. After the first month, a sync
starts at the day of the newest synced event, and a quiet account
remembers that it synced, so closed days are downloaded once.
Synced rows and ranges carry the hashed account. An account change no
longer drops the earlier account's rows; the new account's window starts
after their coverage. A closed synced day stays in the daily cache when
a later sync fails or the store goes missing.
* Cursor sync: longer first backfill, safer merges, provider gate
The month-long first backfill gets 45s (it took 11-12.5s on a real
account and could hit the old 15s cap); incrementals keep 15s. The sync
heartbeats through the download for the app watchdogs. An incremental
starts the day before the newest synced event so late rows land, and
rows from before the window are ignored instead of failing the sync.
A manual import of a row a sync stored first turns it into a manual
row, so a later sync can never delete what manual coverage relies on.
The sidecar records the account only after the request. Commands
filtered to a non-Cursor provider no longer sync.
* Cursor sync: manual coverage wins inside its range
A sync skips rows dated inside a manual import's coverage, so a row
Cursor revised there is not priced twice. Rows after the manual
coverage end still land.
Cursor Agent transcript calls are priced from character counts but were not
flagged costIsEstimated like the store.db path. Flag them and bump the
cursor-agent parse version so cached sessions pick it up. Cost is unchanged.
The Cursor CSV import inferred coverage from UTC days and read a bare
--from/--to date as a UTC day. Reports bucket by local day, so outside UTC the
coverage spilled into neighbouring local days (dropping their local estimates
with no imported events to replace them), and an export of one local day was
rejected as outside its own --from/--to. Use local day bounds instead.
* feat(cursor): import Cursor's usage export to replace local estimates (#1545)
* Price Cursor-hosted grok-4.6-high like grok-4.6 in the Cursor import
* Skip no-op Cursor re-imports and price cursor-grok-4.6-high ids locally
* test(cursor-import): write agent fixtures under os.homedir() so Windows finds them