@yhong91/vibetime 0.1.8 → 0.1.10

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 +49 -1
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -1195,7 +1195,7 @@ function countTextLines(text) {
1195
1195
  }
1196
1196
 
1197
1197
  // src/lib/constants.ts
1198
- var PACKAGE_VERSION = true ? "0.1.8" : "0.1.1";
1198
+ var PACKAGE_VERSION = true ? "0.1.10" : "0.1.1";
1199
1199
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
1200
1200
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
1201
1201
  var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
@@ -1701,6 +1701,20 @@ function usageMetadataFromGenerator(item) {
1701
1701
  occurredAt: Number.isFinite(occurredAt) ? occurredAt : null
1702
1702
  };
1703
1703
  }
1704
+ async function readAgyModelSetting(filePath) {
1705
+ const settingsPath = path4.resolve(path4.dirname(filePath), "../../../..", "settings.json");
1706
+ try {
1707
+ const [text, info] = await Promise.all([
1708
+ readFile2(settingsPath, "utf8"),
1709
+ stat2(settingsPath)
1710
+ ]);
1711
+ const configured = JSON.parse(text)?.model;
1712
+ const model = typeof configured === "string" ? resolveModelName(configured) : null;
1713
+ return model ? { model, changedAt: info.mtimeMs } : null;
1714
+ } catch {
1715
+ return null;
1716
+ }
1717
+ }
1704
1718
  function extractProjectContext(rawLines) {
1705
1719
  let cwd;
1706
1720
  let project;
@@ -1775,6 +1789,7 @@ async function parseAgySessionFile(filePath, options) {
1775
1789
  }
1776
1790
  const { cwd: detectedCwd, project: detectedProject } = extractProjectContext(rawEvents);
1777
1791
  const sessionId = getSessionId(filePath);
1792
+ const modelSetting = await readAgyModelSetting(filePath);
1778
1793
  let generatorMetadata = options?.mockTrajectoryMetadata || await getTrajectoryGeneratorMetadata(sessionId).catch(() => null);
1779
1794
  const cacheDir = path4.join(path4.dirname(path4.dirname(filePath)), "cache");
1780
1795
  const cacheFile = path4.join(cacheDir, "trajectory_metadata.json");
@@ -1795,6 +1810,7 @@ async function parseAgySessionFile(filePath, options) {
1795
1810
  }
1796
1811
  const usageMap = /* @__PURE__ */ new Map();
1797
1812
  const usageEntries = [];
1813
+ const matchedUsageEntries = /* @__PURE__ */ new Set();
1798
1814
  if (generatorMetadata) {
1799
1815
  for (const item of generatorMetadata) {
1800
1816
  const metadata = usageMetadataFromGenerator(item);
@@ -1814,6 +1830,7 @@ async function parseAgySessionFile(filePath, options) {
1814
1830
  const exact = usageMap.get(planner.step_index);
1815
1831
  if (exact) {
1816
1832
  used.add(exact);
1833
+ matchedUsageEntries.add(exact);
1817
1834
  continue;
1818
1835
  }
1819
1836
  const plannerAt = Date.parse(planner.created_at ?? planner.timestamp ?? "");
@@ -1835,6 +1852,7 @@ async function parseAgySessionFile(filePath, options) {
1835
1852
  if (closest && closestDelta <= AGY_USAGE_TIME_MATCH_TOLERANCE_MS) {
1836
1853
  usageMap.set(planner.step_index, closest);
1837
1854
  used.add(closest);
1855
+ matchedUsageEntries.add(closest);
1838
1856
  }
1839
1857
  }
1840
1858
  }
@@ -1862,6 +1880,9 @@ async function parseAgySessionFile(filePath, options) {
1862
1880
  if (!ts) {
1863
1881
  continue;
1864
1882
  }
1883
+ if (modelSetting && Date.parse(ts) >= modelSetting.changedAt) {
1884
+ model = modelSetting.model;
1885
+ }
1865
1886
  state.ensureSessionStarted(ts, lineNumber, raw.type);
1866
1887
  if (raw.type === "USER_INPUT") {
1867
1888
  const content = stringField(raw, "content") || "";
@@ -1894,6 +1915,7 @@ async function parseAgySessionFile(filePath, options) {
1894
1915
  const content = stringField(raw, "content") || "";
1895
1916
  const usageMetadata = usageMap.get(raw.step_index);
1896
1917
  if (usageMetadata) {
1918
+ matchedUsageEntries.add(usageMetadata);
1897
1919
  const usage = usageMetadata.usage;
1898
1920
  const inputTokens = Number.parseInt(usage.inputTokens, 10) || 0;
1899
1921
  const outputTokens = Number.parseInt(usage.outputTokens, 10) || 0;
@@ -2054,6 +2076,32 @@ async function parseAgySessionFile(filePath, options) {
2054
2076
  }
2055
2077
  }
2056
2078
  }
2079
+ for (const [index, usageMetadata] of usageEntries.entries()) {
2080
+ if (matchedUsageEntries.has(usageMetadata) || usageMetadata.occurredAt === null) {
2081
+ continue;
2082
+ }
2083
+ const usage = usageMetadata.usage;
2084
+ const inputTokens = Number.parseInt(usage.inputTokens, 10) || 0;
2085
+ const outputTokens = Number.parseInt(usage.outputTokens, 10) || 0;
2086
+ const cacheRead = Number.parseInt(usage.cacheReadTokens, 10) || 0;
2087
+ const reasoning = Number.parseInt(usage.thinkingOutputTokens, 10) || 0;
2088
+ state.push(baseAgyEvent({
2089
+ ts: new Date(usageMetadata.occurredAt).toISOString(),
2090
+ type: "model.usage",
2091
+ sessionId,
2092
+ model: usageMetadata.model ?? "unknown",
2093
+ confidence: "exact",
2094
+ metrics: {
2095
+ modelCalls: 1,
2096
+ tokensInput: inputTokens + cacheRead,
2097
+ tokensOutput: outputTokens,
2098
+ tokensTotal: inputTokens + cacheRead + outputTokens,
2099
+ tokensCachedInput: cacheRead || void 0,
2100
+ tokensCacheReadInput: cacheRead || void 0,
2101
+ tokensReasoningOutput: reasoning || void 0
2102
+ }
2103
+ }), rawEvents.length + index + 1, "trajectory_metadata");
2104
+ }
2057
2105
  if (state.currentTurnLastEventAt) {
2058
2106
  state.closeTurn(state.currentTurnLastEventAt, rawEvents.length, "session_end");
2059
2107
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.8",
4
+ "version": "0.1.10",
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": {