codebuddy-stats 1.3.6 → 1.4.0

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
@@ -195,9 +195,10 @@ async function main() {
195
195
  function updateContent() {
196
196
  const t0 = prof ? performance.now() : 0;
197
197
  const width = Number(screen.width) || 80;
198
+ const estimatedRate = formatPercent(state.data.ideEstimatedCacheHitRate ?? 0.9);
198
199
  const note = state.currentSource === 'code'
199
200
  ? `针对 CodeBuddy Code < 2.20.0 版本产生的数据,由于没有请求级别的 model ID,用量是基于当前 CodeBuddy Code 设置的 model ID(${state.data.defaultModelId})计算价格的`
200
- : 'IDE usage 不包含缓存 token 明细,成本默认按 60% 缓存命中率估算';
201
+ : `IDE 的数据有缺,成本根据 Code 最近 90 天的平均缓存命中率估算(当前为 ${estimatedRate})`;
201
202
  const screenHeight = Number(screen.height) || 24;
202
203
  const contentBoxHeight = Math.max(1, screenHeight - 5); // 对应 contentBox: height = '100%-5'
203
204
  const paddingTop = Number(contentBox.padding?.top ?? 0);
@@ -12,6 +12,8 @@ import { compareByCostThenTokens } 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();
15
+ const IDE_CACHE_HIT_RATE_LOOKBACK_DAYS = 90;
16
+ const IDE_CACHE_HIT_RATE_FALLBACK = 0.9;
15
17
  function getCacheKey(source, days) {
16
18
  return `${source}:${days ?? 'all'}`;
17
19
  }
@@ -461,6 +463,23 @@ async function loadCodeUsageData(options = {}) {
461
463
  }
462
464
  return data;
463
465
  }
466
+ async function resolveIdeEstimatedCacheHitRate() {
467
+ try {
468
+ const codeData = await loadCodeUsageData({ days: IDE_CACHE_HIT_RATE_LOOKBACK_DAYS });
469
+ const hitTokens = codeData.grandTotal.cacheHitTokens;
470
+ const missTokens = codeData.grandTotal.cacheMissTokens;
471
+ const totalTokens = hitTokens + missTokens;
472
+ if (totalTokens <= 0)
473
+ return IDE_CACHE_HIT_RATE_FALLBACK;
474
+ const rate = hitTokens / totalTokens;
475
+ if (!Number.isFinite(rate))
476
+ return IDE_CACHE_HIT_RATE_FALLBACK;
477
+ return Math.min(1, Math.max(0, rate));
478
+ }
479
+ catch {
480
+ return IDE_CACHE_HIT_RATE_FALLBACK;
481
+ }
482
+ }
464
483
  async function findIdeHistoryDirs() {
465
484
  const root = getIdeDataDir();
466
485
  const out = new Set();
@@ -565,6 +584,7 @@ async function loadIdeUsageData(options = {}) {
565
584
  const t0 = prof ? performance.now() : 0;
566
585
  const defaultModelId = await loadModelFromSettings();
567
586
  const minDate = computeMinDate(options.days);
587
+ const estimatedCacheHitRate = await resolveIdeEstimatedCacheHitRate();
568
588
  // 加载工作区映射
569
589
  const workspaceMappings = await loadWorkspaceMappings();
570
590
  const dailyData = {};
@@ -581,7 +601,7 @@ async function loadIdeUsageData(options = {}) {
581
601
  // 同进程内存缓存(不落盘):refresh 时如果 IDE 索引未变,直接复用结果
582
602
  const sortedHistoryDirs = [...historyDirs].sort();
583
603
  const ideHash = createHash('sha1');
584
- ideHash.update(`ide|defaultModelId=${defaultModelId}|minDate=${minDate ?? ''}|historyDirs=${sortedHistoryDirs.length}\n`);
604
+ ideHash.update(`ide|defaultModelId=${defaultModelId}|minDate=${minDate ?? ''}|historyDirs=${sortedHistoryDirs.length}|ideEstimatedCacheHitRate=${estimatedCacheHitRate.toFixed(6)}|lookbackDays=${IDE_CACHE_HIT_RATE_LOOKBACK_DAYS}\n`);
585
605
  const mappingKeys = [...workspaceMappings.keys()].sort();
586
606
  ideHash.update(`mappings=${mappingKeys.length}\n`);
587
607
  for (const k of mappingKeys) {
@@ -682,9 +702,9 @@ async function loadIdeUsageData(options = {}) {
682
702
  continue;
683
703
  const inferredModelId = await inferIdeModelIdForRequest(conversationDir, req, messageModelCache);
684
704
  const usedModelId = inferredModelId || defaultModelId;
685
- // IDE 的 usage 不包含缓存 token 明细,按默认 60% 缓存命中率估算
705
+ // IDE 的 usage 不包含缓存 token 明细,按 CBC 最近 90 天平均命中率估算(无数据回退 90%)
686
706
  const safeInput = Math.max(0, inputTokens);
687
- const estimatedCacheHit = Math.round(safeInput * 0.6);
707
+ const estimatedCacheHit = Math.round(safeInput * estimatedCacheHitRate);
688
708
  const estimatedCacheMiss = safeInput - estimatedCacheHit;
689
709
  const rawUsage = {
690
710
  prompt_tokens: safeInput,
@@ -721,6 +741,7 @@ async function loadIdeUsageData(options = {}) {
721
741
  }
722
742
  }
723
743
  const data = finalizeAnalysis(defaultModelId, dailyData, modelTotals, projectTotals, grandTotal, workspaceMappings);
744
+ data.ideEstimatedCacheHitRate = estimatedCacheHitRate;
724
745
  cacheSet('ide', options.days, { fingerprint, data });
725
746
  if (profLog) {
726
747
  const ms = performance.now() - t0;
@@ -25,6 +25,7 @@ export const MODEL_PRICING = {
25
25
  "gpt-5-nano": createPricing(0.05, 0.005, 0.4),
26
26
  "gpt-5.1-chat-latest": createPricing(1.25, 0.125, 10.0),
27
27
  "gpt-5-chat-latest": createPricing(1.25, 0.125, 10.0),
28
+ "gpt-5.3-codex": createPricing(1.75, 0.175, 14.0),
28
29
  "gpt-5.2-codex": createPricing(1.75, 0.175, 14.0),
29
30
  "gpt-5.1-codex": createPricing(1.25, 0.125, 10.0),
30
31
  "gpt-5.1-codex-max": createPricing(1.25, 0.125, 10.0),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebuddy-stats",
3
- "version": "1.3.6",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "files": [