import assert from 'node:assert/strict'; import test from 'node:test'; import { buildCursorBillingTokenState, extractCursorAgentDisplayText, normalizeCursorAgentUsage, parseCursorAgentUsage, } from './cursor-agent-usage.mjs'; const SAMPLE_STREAM_JSON = [ '{"type":"system","subtype":"init","cwd":"/tmp","session_id":"abc","model":"Auto"}', '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"reply with exactly: ok"}]}}', '{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"ok"}]}}', '{"type":"result","subtype":"success","duration_ms":13064,"result":"ok","usage":{"inputTokens":7765,"outputTokens":64,"cacheReadTokens":5427,"cacheWriteTokens":0}}', ].join('\n'); test('parseCursorAgentUsage reads result usage from stream-json stdout', () => { const usage = parseCursorAgentUsage(SAMPLE_STREAM_JSON); assert.deepEqual(usage, { inputTokens: 7765, outputTokens: 64, cacheReadTokens: 5427, cacheWriteTokens: 0, }); }); test('normalizeCursorAgentUsage includes cache write tokens in billable input', () => { const usage = normalizeCursorAgentUsage({ inputTokens: 1000, outputTokens: 200, cacheWriteTokens: 300, }); assert.deepEqual(usage, { inputTokens: 1300, outputTokens: 200, cacheReadTokens: 0, cacheWriteTokens: 300, }); }); test('extractCursorAgentDisplayText prefers result text', () => { assert.equal(extractCursorAgentDisplayText(SAMPLE_STREAM_JSON), 'ok'); }); test('buildCursorBillingTokenState accumulates on prior session billing', () => { const tokenState = buildCursorBillingTokenState( { inputTokens: 1000, outputTokens: 200 }, { lastInputTokens: 5000, lastOutputTokens: 800 }, ); assert.deepEqual(tokenState, { accumulatedInputTokens: 6000, accumulatedOutputTokens: 1000, }); });