codebuddy-stats 1.4.1 → 1.4.2

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.
@@ -4,6 +4,7 @@ import path from 'node:path';
4
4
  import { createInterface } from 'node:readline';
5
5
  import { parentPort, workerData } from 'node:worker_threads';
6
6
  import { DEFAULT_MODEL_ID, getPricingForModel, tokensToCost } from './pricing.js';
7
+ import { normalizeUsageFromRecord } from './utils.js';
7
8
  function getProjectName(filePath) {
8
9
  const parts = filePath.split(path.sep);
9
10
  const projectsIndex = parts.lastIndexOf('projects');
@@ -80,7 +81,7 @@ async function main() {
80
81
  for await (const line of rl) {
81
82
  try {
82
83
  const record = JSON.parse(line);
83
- const usage = record?.providerData?.rawUsage;
84
+ const usage = normalizeUsageFromRecord(record);
84
85
  const timestamp = record?.timestamp;
85
86
  if (!usage || timestamp == null)
86
87
  continue;
@@ -8,7 +8,7 @@ import { createInterface } from 'node:readline';
8
8
  import { Worker } from 'node:worker_threads';
9
9
  import { getIdeDataDir, getProjectsDir, getSettingsPath } from './paths.js';
10
10
  import { DEFAULT_MODEL_ID, getPricingForModel, tokensToCost } from './pricing.js';
11
- import { compareByCostThenTokens } from './utils.js';
11
+ import { compareByCostThenTokens, normalizeUsageFromRecord, } from './utils.js';
12
12
  import { loadWorkspaceMappings, resolveProjectName } from './workspace-resolver.js';
13
13
  export const BASE_DIR = getProjectsDir();
14
14
  const memoryCache = new Map();
@@ -411,7 +411,7 @@ async function loadCodeUsageData(options = {}) {
411
411
  for await (const line of rl) {
412
412
  try {
413
413
  const record = JSON.parse(line);
414
- const usage = record?.providerData?.rawUsage;
414
+ const usage = normalizeUsageFromRecord(record);
415
415
  const timestamp = record?.timestamp;
416
416
  if (!usage || timestamp == null)
417
417
  continue;
package/dist/lib/utils.js CHANGED
@@ -65,3 +65,55 @@ export function compareByCostThenTokens(a, b) {
65
65
  return costDiff;
66
66
  return b[1].tokens - a[1].tokens;
67
67
  }
68
+ function toNonNegativeNumber(value) {
69
+ if (typeof value !== 'number' || !Number.isFinite(value))
70
+ return null;
71
+ return Math.max(0, value);
72
+ }
73
+ function sumCachedTokensFromDetails(details) {
74
+ if (!Array.isArray(details))
75
+ return 0;
76
+ let total = 0;
77
+ for (const item of details) {
78
+ if (!item || typeof item !== 'object')
79
+ continue;
80
+ const maybeCachedTokens = item.cached_tokens ??
81
+ item.cachedTokens;
82
+ const cachedTokens = toNonNegativeNumber(maybeCachedTokens);
83
+ if (cachedTokens != null)
84
+ total += cachedTokens;
85
+ }
86
+ return total;
87
+ }
88
+ /**
89
+ * 统一将不同来源的 usage 结构归一为 RawUsage
90
+ * 优先使用 providerData.rawUsage,否则回退到 providerData.usage / message.usage
91
+ */
92
+ export function normalizeUsageFromRecord(record) {
93
+ const rawUsage = record?.providerData?.rawUsage;
94
+ if (rawUsage)
95
+ return rawUsage;
96
+ const usage = (record?.providerData?.usage ?? record?.message?.usage);
97
+ if (!usage || typeof usage !== 'object')
98
+ return null;
99
+ const inputTokens = toNonNegativeNumber(usage.inputTokens);
100
+ const outputTokens = toNonNegativeNumber(usage.outputTokens);
101
+ const totalTokens = toNonNegativeNumber(usage.totalTokens);
102
+ const cacheHitTokens = sumCachedTokensFromDetails(usage.inputTokensDetails);
103
+ if (inputTokens == null && outputTokens == null && totalTokens == null && cacheHitTokens <= 0) {
104
+ return null;
105
+ }
106
+ const normalizedPromptTokens = inputTokens ?? Math.max((totalTokens ?? 0) - (outputTokens ?? 0), 0);
107
+ const normalizedCompletionTokens = outputTokens ?? Math.max((totalTokens ?? 0) - normalizedPromptTokens, 0);
108
+ const normalizedTotalTokens = totalTokens ?? normalizedPromptTokens + normalizedCompletionTokens;
109
+ const normalizedCacheHitTokens = Math.min(cacheHitTokens, normalizedPromptTokens);
110
+ const normalizedCacheMissTokens = Math.max(normalizedPromptTokens - normalizedCacheHitTokens, 0);
111
+ return {
112
+ prompt_tokens: normalizedPromptTokens,
113
+ completion_tokens: normalizedCompletionTokens,
114
+ total_tokens: normalizedTotalTokens,
115
+ prompt_cache_hit_tokens: normalizedCacheHitTokens,
116
+ prompt_cache_miss_tokens: normalizedCacheMissTokens,
117
+ cache_creation_input_tokens: 0,
118
+ };
119
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebuddy-stats",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "files": [