@yhong91/vibetime 0.1.27 → 0.1.29

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 +191 -65
  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.27" : "0.1.1";
1931
+ var PACKAGE_VERSION = true ? "0.1.29" : "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;
@@ -4069,6 +4069,19 @@ function prefixCoworkId(value) {
4069
4069
  }
4070
4070
  return value.startsWith(COWORK_PREFIX) ? value : `${COWORK_PREFIX}${value}`;
4071
4071
  }
4072
+ function parseCoworkSubagentPath(filePath) {
4073
+ const parts = filePath.split(path8.sep);
4074
+ const subagentsIdx = parts.lastIndexOf("subagents");
4075
+ if (subagentsIdx < 2) {
4076
+ return void 0;
4077
+ }
4078
+ const cliSessionId = parts[subagentsIdx - 1];
4079
+ if (!cliSessionId) {
4080
+ return void 0;
4081
+ }
4082
+ const mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${cliSessionId}.jsonl`].join(path8.sep);
4083
+ return { cliSessionId, mainTranscriptPath };
4084
+ }
4072
4085
  function rebuildEventIdentity(event) {
4073
4086
  const importKey = createImportKey([
4074
4087
  event.source,
@@ -4094,15 +4107,21 @@ async function parseClaudeCoworkSessionFile(filePath, options) {
4094
4107
  if (!parser) {
4095
4108
  return [];
4096
4109
  }
4110
+ const subagentInfo = parseCoworkSubagentPath(filePath);
4111
+ const parentSourcePathHash = subagentInfo ? `sha256:${createStableHash(subagentInfo.mainTranscriptPath)}` : void 0;
4112
+ const parentSessionId = subagentInfo ? prefixCoworkId(subagentInfo.cliSessionId) : void 0;
4097
4113
  const events = await parser(filePath, options);
4098
4114
  return events.map((event) => {
4099
- const sessionId = prefixCoworkId(event.sessionId);
4115
+ const sessionId = parentSessionId || prefixCoworkId(event.sessionId);
4100
4116
  const turnId = prefixCoworkId(event.turnId);
4101
4117
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
4102
4118
  const refs2 = { ...event.refs };
4103
4119
  if (metadata.title) {
4104
4120
  refs2.coworkTitleHash = `sha256:${createStableHash(metadata.title)}`;
4105
4121
  }
4122
+ if (parentSourcePathHash) {
4123
+ refs2.sourcePathHash = parentSourcePathHash;
4124
+ }
4106
4125
  const mapped = {
4107
4126
  ...event,
4108
4127
  schemaVersion: event.schemaVersion || AGENT_TIME_SCHEMA_VERSION,
@@ -4894,7 +4913,8 @@ async function parseCodexSessionFile(filePath, options) {
4894
4913
  let lastTurnIdForComplete;
4895
4914
  let turnIdAtLastUserMessage;
4896
4915
  let sessionMetaLocked = false;
4897
- let lastTokenUsageKey;
4916
+ let lastTotalTokenUsage;
4917
+ let lastPerCallUsageKey;
4898
4918
  const pendingToolCalls = /* @__PURE__ */ new Map();
4899
4919
  for (const [index, line] of lines.entries()) {
4900
4920
  const lineNumber = index + 1;
@@ -5042,32 +5062,79 @@ async function parseCodexSessionFile(filePath, options) {
5042
5062
  }
5043
5063
  const usage = tokenUsageFromPayload(payload);
5044
5064
  if (usage) {
5045
- const metrics = { ...usage, reasoningEffort };
5046
- const usageKey = [
5047
- usage.tokensInput,
5048
- usage.tokensCachedInput,
5049
- usage.tokensOutput,
5050
- usage.tokensReasoningOutput,
5051
- usage.tokensTotal
5052
- ].join(":");
5053
- if (usageKey === lastTokenUsageKey) {
5065
+ const input = usage.tokensInput ?? 0;
5066
+ const cached = usage.tokensCachedInput ?? 0;
5067
+ const output = usage.tokensOutput ?? 0;
5068
+ const reasoning = usage.tokensReasoningOutput ?? 0;
5069
+ const total = usage.tokensTotal ?? 0;
5070
+ const hasCumulativeUsage = Object.keys(objectField(info, "total_token_usage")).length > 0;
5071
+ const usageKey = [input, cached, output, reasoning, total].join(":");
5072
+ if (!hasCumulativeUsage) {
5073
+ if (usageKey !== lastPerCallUsageKey) {
5074
+ events.push(withBackfillRefs(baseCodexEvent({
5075
+ ts,
5076
+ type: "model.usage",
5077
+ sessionId,
5078
+ turnId: currentTurnId,
5079
+ cwd,
5080
+ project,
5081
+ model: rewriteCodexModelForTier(model, serviceTier),
5082
+ confidence: "partial",
5083
+ metrics: usage
5084
+ }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5085
+ lastPerCallUsageKey = usageKey;
5086
+ }
5054
5087
  break;
5055
5088
  }
5056
- lastTokenUsageKey = usageKey;
5057
- events.push(withBackfillRefs(baseCodexEvent({
5058
- ts,
5059
- type: "model.usage",
5060
- sessionId,
5061
- turnId: currentTurnId,
5062
- cwd,
5063
- project,
5064
- // Only the model.usage event carries the -fast suffix; tool and
5065
- // turn events keep the bare model so other queries (e.g. "what
5066
- // model was the user on") don't show tier-specific names.
5067
- model: rewriteCodexModelForTier(model, serviceTier),
5068
- confidence: "partial",
5069
- metrics
5070
- }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5089
+ if (lastTotalTokenUsage && total >= lastTotalTokenUsage.total) {
5090
+ const deltaInput = input - lastTotalTokenUsage.input;
5091
+ const deltaCached = cached - lastTotalTokenUsage.cached;
5092
+ const deltaOutput = output - lastTotalTokenUsage.output;
5093
+ const deltaReasoning = reasoning - lastTotalTokenUsage.reasoning;
5094
+ const deltaTotal = total - lastTotalTokenUsage.total;
5095
+ if (deltaInput > 0 || deltaOutput > 0 || deltaTotal > 0) {
5096
+ events.push(withBackfillRefs(baseCodexEvent({
5097
+ ts,
5098
+ type: "model.usage",
5099
+ sessionId,
5100
+ turnId: currentTurnId,
5101
+ cwd,
5102
+ project,
5103
+ model: rewriteCodexModelForTier(model, serviceTier),
5104
+ confidence: "partial",
5105
+ metrics: {
5106
+ tokensInput: deltaInput > 0 ? deltaInput : void 0,
5107
+ tokensCachedInput: deltaCached > 0 ? deltaCached : void 0,
5108
+ tokensOutput: deltaOutput > 0 ? deltaOutput : void 0,
5109
+ tokensReasoningOutput: deltaReasoning > 0 ? deltaReasoning : void 0,
5110
+ tokensTotal: deltaTotal > 0 ? deltaTotal : void 0,
5111
+ modelContextWindow: usage.modelContextWindow,
5112
+ reasoningEffort
5113
+ }
5114
+ }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5115
+ }
5116
+ } else {
5117
+ events.push(withBackfillRefs(baseCodexEvent({
5118
+ ts,
5119
+ type: "model.usage",
5120
+ sessionId,
5121
+ turnId: currentTurnId,
5122
+ cwd,
5123
+ project,
5124
+ model: rewriteCodexModelForTier(model, serviceTier),
5125
+ confidence: "partial",
5126
+ metrics: {
5127
+ tokensInput: input,
5128
+ tokensCachedInput: cached,
5129
+ tokensOutput: output,
5130
+ tokensReasoningOutput: reasoning,
5131
+ tokensTotal: total,
5132
+ modelContextWindow: usage.modelContextWindow,
5133
+ reasoningEffort
5134
+ }
5135
+ }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5136
+ }
5137
+ lastTotalTokenUsage = { input, cached, output, reasoning, total };
5071
5138
  }
5072
5139
  break;
5073
5140
  }
@@ -5284,7 +5351,7 @@ function headlessCodexUsage(raw) {
5284
5351
  const cached = numberField(usage, "cached_input_tokens") ?? numberField(usage, "cache_read_input_tokens") ?? numberField(usage, "cached_tokens") ?? 0;
5285
5352
  const reasoning = numberField(usage, "reasoning_output_tokens") ?? numberField(usage, "reasoning_tokens") ?? 0;
5286
5353
  const totalField = numberField(usage, "total_tokens");
5287
- const total = totalField !== void 0 && (totalField > 0 || input + output + reasoning === 0) ? totalField : input + output + reasoning;
5354
+ const total = totalField !== void 0 && (totalField > 0 || input + output === 0) ? totalField : input + output;
5288
5355
  if (input === 0 && cached === 0 && output === 0 && reasoning === 0 && total === 0) {
5289
5356
  return;
5290
5357
  }
@@ -5293,7 +5360,7 @@ function headlessCodexUsage(raw) {
5293
5360
  tokensCachedInput: cached || void 0,
5294
5361
  tokensOutput: output || void 0,
5295
5362
  tokensReasoningOutput: reasoning || void 0,
5296
- tokensTotal: total,
5363
+ tokensTotal: total || void 0,
5297
5364
  modelCalls: 1
5298
5365
  };
5299
5366
  }
@@ -5320,16 +5387,26 @@ function headlessCodexTimestamp(raw) {
5320
5387
  }
5321
5388
  function tokenUsageFromPayload(payload) {
5322
5389
  const info = objectField(payload, "info");
5323
- const usage = objectField(info, "last_token_usage");
5390
+ const totalUsage = objectField(info, "total_token_usage");
5391
+ const usage = Object.keys(totalUsage).length > 0 ? totalUsage : objectField(info, "last_token_usage");
5324
5392
  if (Object.keys(usage).length === 0) {
5325
5393
  return;
5326
5394
  }
5395
+ const input = numberField(usage, "input_tokens") ?? 0;
5396
+ const cached = numberField(usage, "cached_input_tokens") ?? 0;
5397
+ const output = numberField(usage, "output_tokens") ?? 0;
5398
+ const reasoning = numberField(usage, "reasoning_output_tokens") ?? 0;
5399
+ const totalField = numberField(usage, "total_tokens");
5400
+ const total = totalField !== void 0 && (totalField > 0 || input + output === 0) ? totalField : input + output;
5401
+ if (input === 0 && cached === 0 && output === 0 && reasoning === 0 && total === 0) {
5402
+ return;
5403
+ }
5327
5404
  return {
5328
- tokensInput: numberField(usage, "input_tokens"),
5329
- tokensCachedInput: numberField(usage, "cached_input_tokens"),
5330
- tokensOutput: numberField(usage, "output_tokens"),
5331
- tokensReasoningOutput: numberField(usage, "reasoning_output_tokens"),
5332
- tokensTotal: numberField(usage, "total_tokens"),
5405
+ tokensInput: input || void 0,
5406
+ tokensCachedInput: cached || void 0,
5407
+ tokensOutput: output || void 0,
5408
+ tokensReasoningOutput: reasoning || void 0,
5409
+ tokensTotal: total || void 0,
5333
5410
  modelContextWindow: numberField(info, "model_context_window")
5334
5411
  };
5335
5412
  }
@@ -5666,8 +5743,7 @@ async function parseCopilotSessionFile(filePath, options) {
5666
5743
  const cacheReadTokens = numberField(usage, "cacheReadTokens") || 0;
5667
5744
  const cacheWriteTokens = numberField(usage, "cacheWriteTokens") || 0;
5668
5745
  const reasoningTokens = numberField(usage, "reasoningTokens") || 0;
5669
- const totalInput = inputTokens + cacheReadTokens + cacheWriteTokens;
5670
- const total = totalInput + outputTokens + reasoningTokens;
5746
+ const total = inputTokens + outputTokens;
5671
5747
  if (total <= 0) {
5672
5748
  continue;
5673
5749
  }
@@ -5682,7 +5758,7 @@ async function parseCopilotSessionFile(filePath, options) {
5682
5758
  model: modelName,
5683
5759
  confidence: "exact",
5684
5760
  metrics: {
5685
- tokensInput: totalInput || void 0,
5761
+ tokensInput: inputTokens || void 0,
5686
5762
  tokensOutput: outputTokens || void 0,
5687
5763
  tokensCachedInput: cacheReadTokens + cacheWriteTokens || void 0,
5688
5764
  tokensCacheReadInput: cacheReadTokens || void 0,
@@ -6199,20 +6275,15 @@ async function loadToolInputsFromUpdates(updatesPath) {
6199
6275
  return map;
6200
6276
  }
6201
6277
  function metricsFromSignals(signals) {
6202
- const contextTokens = numberField(signals, "contextTokensUsed");
6203
6278
  const toolCallCount = numberField(signals, "toolCallCount");
6204
6279
  const turnCount = numberField(signals, "turnCount");
6205
6280
  const durationSec = numberField(signals, "sessionDurationSeconds");
6206
6281
  const linesAdded = numberField(signals, "agentLinesAdded");
6207
6282
  const linesRemoved = numberField(signals, "agentLinesRemoved");
6208
- if (contextTokens === void 0 && toolCallCount === void 0 && turnCount === void 0 && durationSec === void 0) {
6283
+ if (toolCallCount === void 0 && turnCount === void 0 && durationSec === void 0) {
6209
6284
  return void 0;
6210
6285
  }
6211
6286
  const metrics = {};
6212
- if (contextTokens !== void 0 && contextTokens > 0) {
6213
- metrics.tokensTotal = contextTokens;
6214
- metrics.tokensInput = contextTokens;
6215
- }
6216
6287
  if (toolCallCount !== void 0) {
6217
6288
  metrics.toolCalls = toolCallCount;
6218
6289
  }
@@ -6296,6 +6367,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
6296
6367
  const hasDirectory = sessionCols.has("directory");
6297
6368
  const hasPath = sessionCols.has("path");
6298
6369
  const hasArchived = sessionCols.has("time_archived");
6370
+ const hasParentId = sessionCols.has("parent_id");
6299
6371
  const selectCols = ["id", "title", "time_created"];
6300
6372
  if (hasDirectory) {
6301
6373
  selectCols.push("directory");
@@ -6306,11 +6378,36 @@ async function parseOpenCodeSessionFile(dbPath, options) {
6306
6378
  if (hasArchived) {
6307
6379
  selectCols.push("time_archived");
6308
6380
  }
6381
+ if (hasParentId) {
6382
+ selectCols.push("parent_id");
6383
+ }
6309
6384
  const sessions = db.prepare(
6310
6385
  `SELECT ${selectCols.join(", ")} FROM session WHERE time_created IS NOT NULL ORDER BY time_created`
6311
6386
  ).all();
6387
+ const rootIdByRawId = /* @__PURE__ */ new Map();
6388
+ if (hasParentId) {
6389
+ const byId = new Map(sessions.map((s) => [s.id, s]));
6390
+ for (const session of sessions) {
6391
+ let current = session.id;
6392
+ const visited = /* @__PURE__ */ new Set();
6393
+ while (true) {
6394
+ if (visited.has(current)) {
6395
+ break;
6396
+ }
6397
+ visited.add(current);
6398
+ const node = byId.get(current);
6399
+ const parentId = node?.parent_id || void 0;
6400
+ if (!parentId || !byId.has(parentId)) {
6401
+ break;
6402
+ }
6403
+ current = parentId;
6404
+ }
6405
+ rootIdByRawId.set(session.id, current);
6406
+ }
6407
+ }
6312
6408
  for (const session of sessions) {
6313
- const sessionId = session.id;
6409
+ const rawSessionId = session.id;
6410
+ const sessionId = rootIdByRawId.get(rawSessionId) || rawSessionId;
6314
6411
  const cwd = session.directory || session.path || void 0;
6315
6412
  const project = cwd ? path14.basename(cwd) : void 0;
6316
6413
  const sessionTs = msToIso(session.time_created);
@@ -6324,14 +6421,14 @@ async function parseOpenCodeSessionFile(dbPath, options) {
6324
6421
  }));
6325
6422
  const messages = db.prepare(
6326
6423
  "SELECT id, data FROM message WHERE session_id = ? ORDER BY time_created"
6327
- ).all(sessionId);
6424
+ ).all(rawSessionId);
6328
6425
  let currentTurnId;
6329
6426
  let currentProvider;
6330
6427
  let turnTs;
6331
6428
  let reasoningEffort;
6332
6429
  const modelSwitchedEvents = db.prepare(
6333
6430
  "SELECT data FROM event WHERE aggregate_id = ? AND type = 'session.next.model.switched.1' ORDER BY seq"
6334
- ).all(sessionId);
6431
+ ).all(rawSessionId);
6335
6432
  for (const evt of modelSwitchedEvents) {
6336
6433
  try {
6337
6434
  const evtData = JSON.parse(evt.data);
@@ -6651,13 +6748,14 @@ function opencodeUsageFromInfo(info) {
6651
6748
  const cacheRead = Math.max(0, numberField(cache, "read") || 0);
6652
6749
  const cacheWrite = Math.max(0, numberField(cache, "write") || 0);
6653
6750
  const totalInput = input + cacheRead + cacheWrite;
6654
- const total = Math.max(0, numberField(tokensObj, "total") || totalInput + output + reasoning);
6751
+ const totalOutput = output + reasoning;
6752
+ const total = Math.max(0, numberField(tokensObj, "total") || totalInput + totalOutput);
6655
6753
  if (total <= 0) {
6656
6754
  return void 0;
6657
6755
  }
6658
6756
  return {
6659
6757
  tokensInput: totalInput || void 0,
6660
- tokensOutput: output || void 0,
6758
+ tokensOutput: totalOutput || void 0,
6661
6759
  tokensReasoningOutput: reasoning || void 0,
6662
6760
  tokensCachedInput: cacheRead + cacheWrite || void 0,
6663
6761
  tokensCacheReadInput: cacheRead || void 0,
@@ -8825,28 +8923,29 @@ function workbuddyUsageMetrics(record) {
8825
8923
  if (!input && !output && !total && !cacheRead && !cacheCreate && !reasoning) {
8826
8924
  return void 0;
8827
8925
  }
8926
+ const alignedTotal = total || input + output;
8828
8927
  return {
8829
- tokensInput: input,
8928
+ tokensInput: input || void 0,
8830
8929
  tokensOutput: output,
8831
8930
  tokensCachedInput: cacheRead + cacheCreate,
8832
8931
  tokensCacheCreationInput: cacheCreate,
8833
8932
  tokensCacheReadInput: cacheRead,
8834
8933
  tokensReasoningOutput: reasoning,
8835
- tokensTotal: total || input + output,
8934
+ tokensTotal: alignedTotal,
8836
8935
  modelCalls: 1
8837
8936
  };
8838
8937
  }
8839
8938
  function workbuddyCachedTokens(usage, rawUsage) {
8840
- const rawCache = numberField(rawUsage, "cache_read_input_tokens") ?? numberField(rawUsage, "prompt_cache_hit_tokens") ?? numberField(rawUsage, "cached_tokens");
8841
- if (rawCache !== void 0) {
8842
- return rawCache;
8843
- }
8844
8939
  const details = usage.inputTokensDetails;
8845
- if (Array.isArray(details) && isPlainObject(details[0])) {
8846
- return numberField(details[0], "cached_tokens") || 0;
8847
- }
8848
8940
  const rawDetails = objectField(rawUsage, "prompt_tokens_details");
8849
- return numberField(rawDetails, "cached_tokens") || 0;
8941
+ return Math.max(
8942
+ 0,
8943
+ numberField(rawUsage, "cache_read_input_tokens") || 0,
8944
+ numberField(rawUsage, "prompt_cache_hit_tokens") || 0,
8945
+ numberField(rawUsage, "cached_tokens") || 0,
8946
+ Array.isArray(details) && isPlainObject(details[0]) ? numberField(details[0], "cached_tokens") || 0 : 0,
8947
+ numberField(rawDetails, "cached_tokens") || 0
8948
+ );
8850
8949
  }
8851
8950
  function workbuddyReasoningTokens(usage, rawUsage) {
8852
8951
  const completionDetails = objectField(rawUsage, "completion_tokens_details");
@@ -9249,6 +9348,7 @@ async function readZCodeRows(dbPath) {
9249
9348
  'reasoning_tokens',reasoning_tokens,
9250
9349
  'cache_creation_input_tokens',cache_creation_input_tokens,
9251
9350
  'cache_read_input_tokens',cache_read_input_tokens,
9351
+ 'provider_total_tokens',provider_total_tokens,
9252
9352
  'computed_total_tokens',computed_total_tokens,
9253
9353
  'tool_call_count',tool_call_count
9254
9354
  ) from model_usage order by started_at, id;`,
@@ -9280,30 +9380,56 @@ function modelMetrics(row) {
9280
9380
  const reasoning = numberField(row, "reasoning_tokens") || 0;
9281
9381
  const cacheCreation = numberField(row, "cache_creation_input_tokens") || 0;
9282
9382
  const cacheRead = numberField(row, "cache_read_input_tokens") || 0;
9283
- const total = numberField(row, "computed_total_tokens") || input + output + reasoning;
9383
+ const cached = cacheCreation + cacheRead;
9384
+ const providerTotal = numberField(row, "provider_total_tokens");
9385
+ const computedTotal = numberField(row, "computed_total_tokens");
9386
+ const totalWithoutSeparateCache = input + output;
9387
+ const totalWithSeparateCache = input + cached + output;
9388
+ const comparisonTotal = providerTotal ?? computedTotal ?? 0;
9389
+ const cacheIsSeparate = comparisonTotal > 0 && Math.abs(comparisonTotal - totalWithSeparateCache) < Math.abs(comparisonTotal - totalWithoutSeparateCache);
9390
+ const alignedInput = input > 0 ? input + (cacheIsSeparate ? cached : 0) : cached;
9391
+ const alignedTotal = alignedInput + output;
9284
9392
  const durationMs = numberField(row, "duration_ms");
9285
9393
  return {
9286
- tokensInput: input,
9394
+ tokensInput: alignedInput || void 0,
9287
9395
  tokensOutput: output,
9288
9396
  tokensReasoningOutput: reasoning,
9289
- tokensCachedInput: cacheCreation + cacheRead,
9397
+ tokensCachedInput: cached,
9290
9398
  tokensCacheCreationInput: cacheCreation,
9291
9399
  tokensCacheReadInput: cacheRead,
9292
- tokensTotal: total,
9400
+ tokensTotal: alignedTotal,
9293
9401
  modelDurationMs: durationMs,
9294
9402
  durationMs,
9295
9403
  modelCalls: 1,
9296
9404
  toolCalls: numberField(row, "tool_call_count")
9297
9405
  };
9298
9406
  }
9407
+ function resolveRootSessionId(sessionId, sessions) {
9408
+ let current = sessionId;
9409
+ const visited = /* @__PURE__ */ new Set();
9410
+ while (true) {
9411
+ if (visited.has(current)) {
9412
+ break;
9413
+ }
9414
+ visited.add(current);
9415
+ const session = sessions.get(current);
9416
+ const parentId = stringField(session, "parent_id");
9417
+ if (!parentId || !sessions.has(parentId)) {
9418
+ break;
9419
+ }
9420
+ current = parentId;
9421
+ }
9422
+ return current;
9423
+ }
9299
9424
  function sessionContext(row, sessions) {
9300
9425
  const sessionId = stringField(row, "session_id") || stringField(row, "id") || "unknown";
9301
9426
  const session = sessions.get(sessionId);
9302
9427
  const cwd = stringField(session, "directory");
9303
9428
  const project = projectFromDirectory(cwd);
9429
+ const rootSessionId = resolveRootSessionId(sessionId, sessions);
9304
9430
  return {
9305
9431
  rawSessionId: sessionId,
9306
- sessionId: `zcode:${sessionId}`,
9432
+ sessionId: `zcode:${rootSessionId}`,
9307
9433
  cwd,
9308
9434
  project,
9309
9435
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: cwd }),
@@ -10284,7 +10410,7 @@ function totalTokensFromEvent(event) {
10284
10410
  if (typeof explicit === "number" && explicit > 0) {
10285
10411
  return explicit;
10286
10412
  }
10287
- return Math.max(0, event.metrics?.tokensInput || 0) + Math.max(0, event.metrics?.tokensOutput || 0) + Math.max(0, event.metrics?.tokensReasoningOutput || 0);
10413
+ return Math.max(0, event.metrics?.tokensInput || 0) + Math.max(0, event.metrics?.tokensOutput || 0);
10288
10414
  }
10289
10415
  function lineStatsFromEvent(event) {
10290
10416
  const files = event.fileActivities || [];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.27",
4
+ "version": "0.1.29",
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": {