aicp-tracker 1.3.3 → 1.3.4
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/package.json +1 -1
- package/src/log-parser.js +26 -15
package/package.json
CHANGED
package/src/log-parser.js
CHANGED
|
@@ -12,6 +12,17 @@ function extractTasksFromBranch(branch) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function sumUsage(entries) {
|
|
15
|
+
// Claude Code writes multiple JSONL lines per message.id (streaming snapshots).
|
|
16
|
+
// All snapshots for the same message.id have identical token counts, so we count
|
|
17
|
+
// only the LAST occurrence of each message.id to avoid double-counting.
|
|
18
|
+
// The last occurrence also has the most complete content (all tool calls present).
|
|
19
|
+
const lastIdxByMsgId = new Map();
|
|
20
|
+
for (let i = 0; i < entries.length; i++) {
|
|
21
|
+
const msgId = entries[i].message?.id;
|
|
22
|
+
if (msgId && entries[i].message?.usage) lastIdxByMsgId.set(msgId, i);
|
|
23
|
+
}
|
|
24
|
+
const countIdxSet = new Set(lastIdxByMsgId.values());
|
|
25
|
+
|
|
15
26
|
let input = 0, cc = 0, cr = 0, out = 0;
|
|
16
27
|
let ephUser = 0, ephAsst = 0, ephTool = 0;
|
|
17
28
|
let webSearch = 0, webFetch = 0;
|
|
@@ -19,8 +30,14 @@ function sumUsage(entries) {
|
|
|
19
30
|
const models = new Set();
|
|
20
31
|
const uuids = [];
|
|
21
32
|
|
|
22
|
-
for (
|
|
23
|
-
const
|
|
33
|
+
for (let i = 0; i < entries.length; i++) {
|
|
34
|
+
const e = entries[i];
|
|
35
|
+
const u = e.message?.usage;
|
|
36
|
+
if (!u) continue;
|
|
37
|
+
// Skip all but the last snapshot for each message.id
|
|
38
|
+
const msgId = e.message?.id;
|
|
39
|
+
if (msgId && !countIdxSet.has(i)) continue;
|
|
40
|
+
|
|
24
41
|
input += u.input_tokens || 0;
|
|
25
42
|
cc += u.cache_creation_input_tokens || 0;
|
|
26
43
|
cr += u.cache_read_input_tokens || 0;
|
|
@@ -227,10 +244,10 @@ function parseNewLines(filePath) {
|
|
|
227
244
|
fs.closeSync(fd);
|
|
228
245
|
state.setOffset(filePath, offset + read);
|
|
229
246
|
|
|
230
|
-
//
|
|
231
|
-
//
|
|
247
|
+
// Keep ALL entries — deduplication by message.id happens inside sumUsage.
|
|
248
|
+
// We must retain every line here because later snapshots of the same message.id
|
|
249
|
+
// contain the Edit/Write tool calls that earlier snapshots lack.
|
|
232
250
|
const entries = [];
|
|
233
|
-
const seenUsageMsgIds = new Set();
|
|
234
251
|
|
|
235
252
|
for (const raw of buf.slice(0, read).toString('utf8').split('\n')) {
|
|
236
253
|
const line = raw.trim();
|
|
@@ -238,12 +255,6 @@ function parseNewLines(filePath) {
|
|
|
238
255
|
let entry;
|
|
239
256
|
try { entry = JSON.parse(line); } catch { continue; }
|
|
240
257
|
if (!entry.uuid) continue;
|
|
241
|
-
|
|
242
|
-
const msgId = entry.message?.id;
|
|
243
|
-
if (msgId && entry.message?.usage) {
|
|
244
|
-
if (seenUsageMsgIds.has(msgId)) continue;
|
|
245
|
-
seenUsageMsgIds.add(msgId);
|
|
246
|
-
}
|
|
247
258
|
entries.push(entry);
|
|
248
259
|
}
|
|
249
260
|
|
|
@@ -270,11 +281,11 @@ function parseNewLines(filePath) {
|
|
|
270
281
|
if (entry.promptId) {
|
|
271
282
|
currentPromptId = entry.promptId;
|
|
272
283
|
latestPromptId = entry.promptId;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
ensureGroup(currentPromptId, entry);
|
|
276
|
-
groupAllEntries.get(currentPromptId).push(entry);
|
|
284
|
+
} else if (!currentPromptId) {
|
|
285
|
+
continue;
|
|
277
286
|
}
|
|
287
|
+
ensureGroup(currentPromptId, entry);
|
|
288
|
+
groupAllEntries.get(currentPromptId).push(entry);
|
|
278
289
|
}
|
|
279
290
|
|
|
280
291
|
if (latestPromptId) state.setLastPromptId(filePath, latestPromptId);
|