@yishiguji/tokenarena 0.12.0 → 0.12.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/dist/index.js CHANGED
@@ -486,6 +486,8 @@ var CodexParser = class {
486
486
  if (files.length === 0) {
487
487
  return { buckets: [], sessions: [] };
488
488
  }
489
+ const seenTotalStates = /* @__PURE__ */ new Set();
490
+ const seenLastOnly = /* @__PURE__ */ new Set();
489
491
  for (const filePath of files) {
490
492
  const content = readFileSafe(filePath);
491
493
  if (!content) continue;
@@ -532,13 +534,28 @@ var CodexParser = class {
532
534
  if (!info) continue;
533
535
  const timestamp = obj.timestamp ? new Date(obj.timestamp) : null;
534
536
  if (!timestamp || Number.isNaN(timestamp.getTime())) continue;
535
- sessionEvents.push({
536
- sessionId: filePath,
537
- source: TOOL_ID,
538
- project: sessionProject,
539
- timestamp,
540
- role: "assistant"
541
- });
537
+ const model = info.model || payload.model || turnContextModel || sessionModel;
538
+ let isDuplicate = false;
539
+ if (info.total_token_usage) {
540
+ const curr = info.total_token_usage;
541
+ const stateKey = `${model}|${toSafeNumber(curr.input_tokens)}|${toSafeNumber(curr.output_tokens)}|${toSafeNumber(curr.cached_input_tokens)}|${toSafeNumber(curr.reasoning_output_tokens)}`;
542
+ isDuplicate = seenTotalStates.has(stateKey);
543
+ if (!isDuplicate) seenTotalStates.add(stateKey);
544
+ } else if (info.last_token_usage) {
545
+ const u = info.last_token_usage;
546
+ const lastKey = `${obj.timestamp}|${toSafeNumber(u.input_tokens)}|${toSafeNumber(u.output_tokens)}|${toSafeNumber(u.cached_input_tokens)}|${toSafeNumber(u.reasoning_output_tokens)}`;
547
+ isDuplicate = seenLastOnly.has(lastKey);
548
+ if (!isDuplicate) seenLastOnly.add(lastKey);
549
+ }
550
+ if (!isDuplicate) {
551
+ sessionEvents.push({
552
+ sessionId: filePath,
553
+ source: TOOL_ID,
554
+ project: sessionProject,
555
+ timestamp,
556
+ role: "assistant"
557
+ });
558
+ }
542
559
  let usage = info.last_token_usage;
543
560
  if (!usage && info.total_token_usage) {
544
561
  const totalKey = `${info.model || payload.model || turnContextModel || ""}`;
@@ -569,7 +586,7 @@ var CodexParser = class {
569
586
  prevTotal.set(totalKey, { ...curr });
570
587
  }
571
588
  if (!usage) continue;
572
- const model = info.model || payload.model || turnContextModel || sessionModel;
589
+ if (isDuplicate) continue;
573
590
  const cachedInput = toSafeNumber(usage.cached_input_tokens);
574
591
  const reasoningTokens = toSafeNumber(usage.reasoning_output_tokens);
575
592
  const inputTokens = Math.max(
@@ -4195,7 +4212,9 @@ function buildSessions(input2) {
4195
4212
  firstMessageAt: firstMessageAt.toISOString(),
4196
4213
  lastMessageAt: lastMessageAt.toISOString(),
4197
4214
  durationSeconds,
4198
- activeSeconds: draft.activeSeconds,
4215
+ // Turn durations can overlap (parallel tool calls), so the sum may
4216
+ // exceed the wall-clock span of the session.
4217
+ activeSeconds: Math.min(draft.activeSeconds, durationSeconds),
4199
4218
  messageCount: draft.messageCount,
4200
4219
  userMessageCount: draft.userMessageCount,
4201
4220
  userPromptHours: draft.userPromptHours,