cursor-usage-analyzer 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +5 -1
- package/analyze.js +48 -8
- package/cursor-usage-analyzer-0.2.1.tgz +0 -0
- package/package.json +1 -1
package/analyze.js
CHANGED
|
@@ -363,8 +363,33 @@ function extractConversations(startTime, endTime, apiCalls = []) {
|
|
|
363
363
|
filesChangedCount: composer.filesChangedCount || 0
|
|
364
364
|
};
|
|
365
365
|
|
|
366
|
-
|
|
367
|
-
|
|
366
|
+
conversations.push(conv);
|
|
367
|
+
} catch (e) {
|
|
368
|
+
// Silently skip invalid composers
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Match API calls to conversations WITHOUT double-counting
|
|
373
|
+
// Each API call should only be matched to ONE conversation
|
|
374
|
+
if (apiCalls.length > 0) {
|
|
375
|
+
const usedApiCallIndices = new Set();
|
|
376
|
+
|
|
377
|
+
for (const conv of conversations) {
|
|
378
|
+
const availableApiCalls = apiCalls.filter((_, idx) => !usedApiCallIndices.has(idx));
|
|
379
|
+
const matchedCalls = matchAPICallsToConversation(conv, availableApiCalls);
|
|
380
|
+
|
|
381
|
+
// Mark these API calls as used
|
|
382
|
+
matchedCalls.forEach(call => {
|
|
383
|
+
const originalIndex = apiCalls.findIndex(c =>
|
|
384
|
+
c.timestamp === call.timestamp &&
|
|
385
|
+
c.model === call.model &&
|
|
386
|
+
c.totalTokens === call.totalTokens
|
|
387
|
+
);
|
|
388
|
+
if (originalIndex !== -1) {
|
|
389
|
+
usedApiCallIndices.add(originalIndex);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
368
393
|
conv.apiCalls = matchedCalls;
|
|
369
394
|
conv.apiCallCount = matchedCalls.length;
|
|
370
395
|
|
|
@@ -377,11 +402,21 @@ function extractConversations(startTime, endTime, apiCalls = []) {
|
|
|
377
402
|
totalTokens: matchedCalls.reduce((sum, c) => sum + c.totalTokens, 0),
|
|
378
403
|
cost: matchedCalls.reduce((sum, c) => sum + c.cost, 0)
|
|
379
404
|
};
|
|
380
|
-
|
|
381
|
-
conversations.push(conv);
|
|
382
|
-
} catch (e) {
|
|
383
|
-
// Silently skip invalid composers
|
|
384
405
|
}
|
|
406
|
+
} else {
|
|
407
|
+
// No API calls to match
|
|
408
|
+
conversations.forEach(conv => {
|
|
409
|
+
conv.apiCalls = [];
|
|
410
|
+
conv.apiCallCount = 0;
|
|
411
|
+
conv.apiTokens = {
|
|
412
|
+
inputWithCache: 0,
|
|
413
|
+
inputWithoutCache: 0,
|
|
414
|
+
cacheRead: 0,
|
|
415
|
+
outputTokens: 0,
|
|
416
|
+
totalTokens: 0,
|
|
417
|
+
cost: 0
|
|
418
|
+
};
|
|
419
|
+
});
|
|
385
420
|
}
|
|
386
421
|
|
|
387
422
|
db.close();
|
|
@@ -560,8 +595,13 @@ async function main() {
|
|
|
560
595
|
let apiCalls = [];
|
|
561
596
|
if (csvPath) {
|
|
562
597
|
console.log(`CSV file: ${csvPath}`);
|
|
563
|
-
|
|
564
|
-
|
|
598
|
+
const allApiCalls = parseCSVUsage(csvPath);
|
|
599
|
+
// Filter API calls to only those within the date range
|
|
600
|
+
apiCalls = allApiCalls.filter(call =>
|
|
601
|
+
call.timestamp >= startOfDay && call.timestamp <= endOfDay
|
|
602
|
+
);
|
|
603
|
+
console.log(`Parsed ${allApiCalls.length} API calls from CSV`);
|
|
604
|
+
console.log(`Filtered to ${apiCalls.length} API calls within date range\n`);
|
|
565
605
|
} else {
|
|
566
606
|
console.log('No CSV file provided (use --csv path/to/file.csv to include API token data)\n');
|
|
567
607
|
}
|
|
Binary file
|
package/package.json
CHANGED