awarts 0.2.1 → 0.2.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.
Files changed (2) hide show
  1. package/dist/index.js +58 -52
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5879,11 +5879,14 @@ import fs8 from "node:fs/promises";
5879
5879
  import path4 from "node:path";
5880
5880
  import os5 from "node:os";
5881
5881
  var CLAUDE_DIR = path4.join(os5.homedir(), ".claude");
5882
- var USAGE_DIR = path4.join(CLAUDE_DIR, "usage");
5883
- var ALT_USAGE_DIR = path4.join(CLAUDE_DIR, "projects");
5884
- function dateFromFilename(filename) {
5885
- const match = filename.match(/^(\d{4}-\d{2}-\d{2})\.json$/);
5886
- return match ? match[1] : null;
5882
+ var STATS_CACHE = path4.join(CLAUDE_DIR, "stats-cache.json");
5883
+ async function fileExists(filePath) {
5884
+ try {
5885
+ const stat = await fs8.stat(filePath);
5886
+ return stat.isFile();
5887
+ } catch {
5888
+ return false;
5889
+ }
5887
5890
  }
5888
5891
  async function dirExists(dir) {
5889
5892
  try {
@@ -5893,40 +5896,46 @@ async function dirExists(dir) {
5893
5896
  return false;
5894
5897
  }
5895
5898
  }
5896
- async function readUsageDir(dir) {
5899
+ async function readStatsCache() {
5900
+ const raw = await fs8.readFile(STATS_CACHE, "utf-8");
5901
+ const cache = JSON.parse(raw);
5902
+ const dailyTokens = cache.dailyModelTokens;
5903
+ if (!dailyTokens || dailyTokens.length === 0)
5904
+ return [];
5905
+ let totalInputTokens = 0;
5906
+ let totalOutputTokens = 0;
5907
+ let totalCacheRead = 0;
5908
+ let totalCacheCreation = 0;
5909
+ let totalCost = 0;
5910
+ if (cache.modelUsage) {
5911
+ for (const usage of Object.values(cache.modelUsage)) {
5912
+ totalInputTokens += usage.inputTokens || 0;
5913
+ totalOutputTokens += usage.outputTokens || 0;
5914
+ totalCacheRead += usage.cacheReadInputTokens || 0;
5915
+ totalCacheCreation += usage.cacheCreationInputTokens || 0;
5916
+ totalCost += usage.costUSD || 0;
5917
+ }
5918
+ }
5919
+ const dailyOutputSum = dailyTokens.reduce((sum, day) => {
5920
+ return sum + Object.values(day.tokensByModel).reduce((s, t) => s + t, 0);
5921
+ }, 0);
5897
5922
  const entries = [];
5898
- let files;
5899
- try {
5900
- files = await fs8.readdir(dir);
5901
- } catch {
5902
- return entries;
5903
- }
5904
- const jsonFiles = files.filter((f) => f.endsWith(".json"));
5905
- for (const file of jsonFiles) {
5906
- try {
5907
- const filePath = path4.join(dir, file);
5908
- const raw = await fs8.readFile(filePath, "utf-8");
5909
- const data = JSON.parse(raw);
5910
- const date = data.date ?? dateFromFilename(file);
5911
- if (!date)
5912
- continue;
5913
- const costUsd = data.cost_usd ?? data.totalCost ?? 0;
5914
- const inputTokens = data.input_tokens ?? data.totalInputTokens ?? 0;
5915
- const outputTokens = data.output_tokens ?? data.totalOutputTokens ?? 0;
5916
- const cacheCreation = data.cache_creation_tokens ?? data.cacheCreationTokens ?? 0;
5917
- const cacheRead = data.cache_read_tokens ?? data.cacheReadTokens ?? 0;
5918
- const models = data.models ? data.models : data.model ? [data.model] : [];
5919
- entries.push({
5920
- date,
5921
- provider: "claude",
5922
- cost_usd: Number(costUsd) || 0,
5923
- input_tokens: Number(inputTokens) || 0,
5924
- output_tokens: Number(outputTokens) || 0,
5925
- cache_creation_tokens: Number(cacheCreation) || 0,
5926
- cache_read_tokens: Number(cacheRead) || 0,
5927
- models
5928
- });
5929
- } catch {}
5923
+ for (const day of dailyTokens) {
5924
+ const dayOutputTokens = Object.values(day.tokensByModel).reduce((s, t) => s + t, 0);
5925
+ if (dayOutputTokens === 0)
5926
+ continue;
5927
+ const share = dailyOutputSum > 0 ? dayOutputTokens / dailyOutputSum : 0;
5928
+ const models = Object.keys(day.tokensByModel).filter((m) => day.tokensByModel[m] > 0);
5929
+ entries.push({
5930
+ date: day.date,
5931
+ provider: "claude",
5932
+ output_tokens: dayOutputTokens,
5933
+ input_tokens: Math.round(totalInputTokens * share),
5934
+ cache_read_tokens: Math.round(totalCacheRead * share),
5935
+ cache_creation_tokens: Math.round(totalCacheCreation * share),
5936
+ cost_usd: Number((totalCost * share).toFixed(4)),
5937
+ models
5938
+ });
5930
5939
  }
5931
5940
  return entries;
5932
5941
  }
@@ -5934,21 +5943,18 @@ var claudeAdapter = {
5934
5943
  name: "claude",
5935
5944
  displayName: "Claude",
5936
5945
  async detect() {
5937
- if (await dirExists(USAGE_DIR))
5946
+ if (await fileExists(STATS_CACHE))
5938
5947
  return true;
5939
5948
  if (await dirExists(CLAUDE_DIR))
5940
5949
  return true;
5941
- if (await dirExists(ALT_USAGE_DIR))
5942
- return true;
5943
5950
  return false;
5944
5951
  },
5945
5952
  async read() {
5946
- const entries = [];
5947
- entries.push(...await readUsageDir(USAGE_DIR));
5948
- if (entries.length === 0) {
5949
- entries.push(...await readUsageDir(ALT_USAGE_DIR));
5953
+ try {
5954
+ return await readStatsCache();
5955
+ } catch {
5956
+ return [];
5950
5957
  }
5951
- return entries;
5952
5958
  }
5953
5959
  };
5954
5960
 
@@ -5962,7 +5968,7 @@ var CANDIDATE_DIRS = [
5962
5968
  path5.join(HOME, ".openai-codex", "usage"),
5963
5969
  path5.join(HOME, ".codex")
5964
5970
  ];
5965
- function dateFromFilename2(filename) {
5971
+ function dateFromFilename(filename) {
5966
5972
  const match = filename.match(/^(\d{4}-\d{2}-\d{2})\.json$/);
5967
5973
  return match ? match[1] : null;
5968
5974
  }
@@ -6004,7 +6010,7 @@ var codexAdapter = {
6004
6010
  const filePath = path5.join(dir, file);
6005
6011
  const raw = await fs9.readFile(filePath, "utf-8");
6006
6012
  const data = JSON.parse(raw);
6007
- const date = data.date ?? dateFromFilename2(file);
6013
+ const date = data.date ?? dateFromFilename(file);
6008
6014
  if (!date)
6009
6015
  continue;
6010
6016
  const costUsd = data.cost_usd ?? data.total_cost ?? 0;
@@ -6037,7 +6043,7 @@ var CANDIDATE_DIRS2 = [
6037
6043
  path6.join(HOME2, ".config", "gemini", "usage"),
6038
6044
  path6.join(HOME2, ".gemini")
6039
6045
  ];
6040
- function dateFromFilename3(filename) {
6046
+ function dateFromFilename2(filename) {
6041
6047
  const match = filename.match(/^(\d{4}-\d{2}-\d{2})\.json$/);
6042
6048
  return match ? match[1] : null;
6043
6049
  }
@@ -6079,7 +6085,7 @@ var geminiAdapter = {
6079
6085
  const filePath = path6.join(dir, file);
6080
6086
  const raw = await fs10.readFile(filePath, "utf-8");
6081
6087
  const data = JSON.parse(raw);
6082
- const date = data.date ?? dateFromFilename3(file);
6088
+ const date = data.date ?? dateFromFilename2(file);
6083
6089
  if (!date)
6084
6090
  continue;
6085
6091
  const costUsd = data.cost_usd ?? data.total_cost ?? 0;
@@ -6111,7 +6117,7 @@ var CANDIDATE_DIRS3 = [
6111
6117
  path7.join(HOME3, ".antigravity", "usage"),
6112
6118
  path7.join(HOME3, ".antigravity")
6113
6119
  ];
6114
- function dateFromFilename4(filename) {
6120
+ function dateFromFilename3(filename) {
6115
6121
  const match = filename.match(/^(\d{4}-\d{2}-\d{2})\.json$/);
6116
6122
  return match ? match[1] : null;
6117
6123
  }
@@ -6153,7 +6159,7 @@ var antigravityAdapter = {
6153
6159
  const filePath = path7.join(dir, file);
6154
6160
  const raw = await fs11.readFile(filePath, "utf-8");
6155
6161
  const data = JSON.parse(raw);
6156
- const date = data.date ?? dateFromFilename4(file);
6162
+ const date = data.date ?? dateFromFilename3(file);
6157
6163
  if (!date)
6158
6164
  continue;
6159
6165
  const costUsd = data.cost_usd ?? data.total_cost ?? 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "awarts",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Track your AI coding across Claude, Codex, Gemini & Antigravity",
5
5
  "type": "module",
6
6
  "bin": {