@yhong91/vibetime 0.1.39 → 0.1.40

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/bin/vibetime.mjs +74 -27
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -1928,7 +1928,7 @@ function countTextLines(text) {
1928
1928
  }
1929
1929
 
1930
1930
  // src/lib/constants.ts
1931
- var PACKAGE_VERSION = true ? "0.1.39" : "0.1.1";
1931
+ var PACKAGE_VERSION = true ? "0.1.40" : "0.1.1";
1932
1932
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
1933
1933
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
1934
1934
  var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
@@ -4565,48 +4565,71 @@ function normalizeModelCandidate(value) {
4565
4565
  }
4566
4566
  return trimmed;
4567
4567
  }
4568
- function extractUsageFromGenerationSpan(span) {
4569
- const parsed = parseEmbeddedJson(span.toolOutput);
4570
- if (!Array.isArray(parsed) || parsed.length === 0) {
4571
- return void 0;
4572
- }
4573
- const first = parsed[0];
4574
- if (!isPlainObject(first)) {
4575
- return void 0;
4576
- }
4577
- const usage = objectField(first, "usage");
4578
- if (!isPlainObject(usage)) {
4568
+ function finitePositive(value) {
4569
+ if (typeof value !== "number" && typeof value !== "string") {
4579
4570
  return void 0;
4580
4571
  }
4572
+ const parsed = Number(value);
4573
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
4574
+ }
4575
+ function extractUsageFromGenerationSpan(span) {
4576
+ const parsed = parseEmbeddedJson(span.toolOutput);
4577
+ const first = Array.isArray(parsed) ? parsed[0] : void 0;
4578
+ const usage = isPlainObject(first) ? objectField(first, "usage") : {};
4581
4579
  const inputTokens = numberField(usage, "prompt_tokens");
4582
4580
  const outputTokens = numberField(usage, "completion_tokens");
4583
4581
  const totalTokens = numberField(usage, "total_tokens");
4584
4582
  const details = objectField(usage, "prompt_tokens_details");
4585
4583
  const cachedTokens = isPlainObject(details) ? numberField(details, "cached_tokens") : void 0;
4584
+ const otelAttributes = span.attributes || {};
4585
+ const otelInputTokens = finitePositive(otelAttributes["gen_ai.usage.input_tokens"]);
4586
+ const otelOutputTokens = finitePositive(otelAttributes["gen_ai.usage.output_tokens"]);
4587
+ const otelCacheReadTokens = finitePositive(otelAttributes["gen_ai.usage.cache_read_input_tokens"]);
4588
+ const otelCacheCreationTokens = finitePositive(otelAttributes["gen_ai.usage.cache_creation_input_tokens"]);
4589
+ const otelReasoningTokens = finitePositive(otelAttributes["gen_ai.usage.reasoning_output_tokens"]);
4590
+ const tokensInput = otelInputTokens ?? inputTokens;
4591
+ const tokensOutput = otelOutputTokens ?? outputTokens;
4592
+ const tokensCacheReadInput = otelCacheReadTokens ?? cachedTokens;
4593
+ const tokensCachedInput = (tokensCacheReadInput ?? 0) + (otelCacheCreationTokens ?? 0);
4594
+ const tokensTotal = totalTokens || (tokensInput ?? 0) + (tokensOutput ?? 0);
4595
+ if (!tokensInput && !tokensOutput && !tokensCachedInput && !otelReasoningTokens && !tokensTotal) {
4596
+ return void 0;
4597
+ }
4586
4598
  return {
4587
- tokensInput: inputTokens || void 0,
4588
- tokensCachedInput: cachedTokens || void 0,
4589
- tokensCacheReadInput: cachedTokens || void 0,
4590
- tokensOutput: outputTokens || void 0,
4591
- tokensTotal: totalTokens || void 0,
4599
+ tokensInput: tokensInput || void 0,
4600
+ tokensOutput: tokensOutput || void 0,
4601
+ tokensCachedInput: tokensCachedInput || void 0,
4602
+ tokensCacheReadInput: tokensCacheReadInput || void 0,
4603
+ tokensCacheCreationInput: otelCacheCreationTokens,
4604
+ tokensReasoningOutput: otelReasoningTokens,
4605
+ tokensTotal: tokensTotal || void 0,
4592
4606
  modelCalls: 1
4593
4607
  };
4594
4608
  }
4595
4609
  function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
4596
4610
  const info = trace.modelInfo;
4597
- if (!info || !info.totalInputTokens && !info.totalOutputTokens && !trace.totalTokens) {
4611
+ const otelAttributes = trace.attributes || {};
4612
+ const otelInputTokens = finitePositive(otelAttributes["gen_ai.usage.input_tokens"]);
4613
+ const otelOutputTokens = finitePositive(otelAttributes["gen_ai.usage.output_tokens"]);
4614
+ const otelCacheReadTokens = finitePositive(otelAttributes["gen_ai.usage.cache_read_input_tokens"]);
4615
+ const otelCacheCreationTokens = finitePositive(otelAttributes["gen_ai.usage.cache_creation_input_tokens"]);
4616
+ const otelReasoningTokens = finitePositive(otelAttributes["gen_ai.usage.reasoning_output_tokens"]);
4617
+ if (!info && !trace.totalTokens && !otelInputTokens && !otelOutputTokens && !otelCacheReadTokens && !otelCacheCreationTokens && !otelReasoningTokens) {
4598
4618
  return void 0;
4599
4619
  }
4620
+ const inputTokens = otelInputTokens ?? (info?.totalInputTokens || 0);
4621
+ const outputTokens = otelOutputTokens ?? (info?.totalOutputTokens || 0);
4622
+ const cacheReadTokens = otelCacheReadTokens ?? info?.totalCachedTokens;
4623
+ const cachedTokens = (cacheReadTokens ?? 0) + (otelCacheCreationTokens ?? 0);
4624
+ const totalTokens = trace.totalTokens || inputTokens + outputTokens;
4600
4625
  if (generationIndex === 1) {
4601
- const inputTokens = info.totalInputTokens || 0;
4602
- const outputTokens = info.totalOutputTokens || 0;
4603
- const cachedTokens = info.totalCachedTokens || 0;
4604
- const totalTokens = trace.totalTokens || inputTokens + outputTokens;
4605
4626
  return {
4606
4627
  tokensInput: inputTokens || void 0,
4607
4628
  tokensCachedInput: cachedTokens || void 0,
4608
- tokensCacheReadInput: cachedTokens || void 0,
4629
+ tokensCacheReadInput: cacheReadTokens,
4630
+ tokensCacheCreationInput: otelCacheCreationTokens || void 0,
4609
4631
  tokensOutput: outputTokens || void 0,
4632
+ tokensReasoningOutput: otelReasoningTokens || void 0,
4610
4633
  tokensTotal: totalTokens || void 0,
4611
4634
  modelCalls: totalGenerations || 1
4612
4635
  };
@@ -7617,9 +7640,8 @@ function rebuildEventIdentity2(event) {
7617
7640
  }
7618
7641
  };
7619
7642
  }
7620
- async function loadQoderCnModelNames(configDir2) {
7643
+ async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
7621
7644
  try {
7622
- const dynamicTextsPath = path17.join(configDir2, ".auth", "dynamic-texts.json");
7623
7645
  const content = await readFile10(dynamicTextsPath, "utf8");
7624
7646
  const json = JSON.parse(content);
7625
7647
  const texts = json.texts || {};
@@ -7635,6 +7657,19 @@ async function loadQoderCnModelNames(configDir2) {
7635
7657
  return {};
7636
7658
  }
7637
7659
  }
7660
+ async function loadQoderCnModelNames(configDir2) {
7661
+ const map = await parseModelNamesFromDynamicTexts(path17.join(configDir2, ".auth", "dynamic-texts.json"));
7662
+ const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
7663
+ if (siblingConfigDir !== configDir2) {
7664
+ const siblingMap = await parseModelNamesFromDynamicTexts(path17.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
7665
+ for (const [key, val] of Object.entries(siblingMap)) {
7666
+ if (!(key in map)) {
7667
+ map[key] = val;
7668
+ }
7669
+ }
7670
+ }
7671
+ return map;
7672
+ }
7638
7673
  async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
7639
7674
  const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
7640
7675
  const segmentsPath = path17.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
@@ -8420,9 +8455,8 @@ function rebuildEventIdentity3(event) {
8420
8455
  }
8421
8456
  };
8422
8457
  }
8423
- async function loadQoderModelNames(configDir2) {
8458
+ async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
8424
8459
  try {
8425
- const dynamicTextsPath = path18.join(configDir2, ".auth", "dynamic-texts.json");
8426
8460
  const content = await readFile11(dynamicTextsPath, "utf8");
8427
8461
  const json = JSON.parse(content);
8428
8462
  const texts = json.texts || {};
@@ -8438,6 +8472,19 @@ async function loadQoderModelNames(configDir2) {
8438
8472
  return {};
8439
8473
  }
8440
8474
  }
8475
+ async function loadQoderModelNames(configDir2) {
8476
+ const map = await parseModelNamesFromDynamicTexts2(path18.join(configDir2, ".auth", "dynamic-texts.json"));
8477
+ const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
8478
+ if (siblingConfigDir !== configDir2) {
8479
+ const siblingMap = await parseModelNamesFromDynamicTexts2(path18.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
8480
+ for (const [key, val] of Object.entries(siblingMap)) {
8481
+ if (!(key in map)) {
8482
+ map[key] = val;
8483
+ }
8484
+ }
8485
+ }
8486
+ return map;
8487
+ }
8441
8488
  async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
8442
8489
  const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
8443
8490
  const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.39",
4
+ "version": "0.1.40",
5
5
  "description": "vibetime CLI — install AI-agent hooks (Claude Code, Codex, OpenCode, Pi) and report activity to vibetime.",
6
6
  "license": "MIT",
7
7
  "publishConfig": {