@yhong91/vibetime 0.1.73 → 0.1.75

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 +161 -166
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -884,8 +884,8 @@ var init_esm = __esm({
884
884
 
885
885
  // src/cli.ts
886
886
  import { spawn as spawn2, spawnSync } from "node:child_process";
887
- import { mkdir as mkdir6, open, rm, stat as stat18, writeFile as writeFile5 } from "node:fs/promises";
888
- import os14 from "node:os";
887
+ import { mkdir as mkdir6, open, rm, stat as stat17, writeFile as writeFile5 } from "node:fs/promises";
888
+ import os13 from "node:os";
889
889
  import path27 from "node:path";
890
890
  import { fileURLToPath } from "node:url";
891
891
 
@@ -2047,7 +2047,7 @@ function claudeStyleFileMetrics(tool, input) {
2047
2047
  }
2048
2048
 
2049
2049
  // src/lib/constants.ts
2050
- var PACKAGE_VERSION = true ? "0.1.73" : "0.1.1";
2050
+ var PACKAGE_VERSION = true ? "0.1.75" : "0.1.1";
2051
2051
  var GENERATED_MARKER = "Generated by vibetime.";
2052
2052
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
2053
2053
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
@@ -2103,6 +2103,9 @@ function msToIso(ms) {
2103
2103
  }
2104
2104
 
2105
2105
  // src/lib/backfill.ts
2106
+ function rollupKeyForSourceSession(source, sessionId) {
2107
+ return createImportKey(["rollup", source, sessionId]);
2108
+ }
2106
2109
  function withBackfillRefs(event, context) {
2107
2110
  const importKey = createImportKey([
2108
2111
  event.source,
@@ -4936,8 +4939,8 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
4936
4939
  }
4937
4940
  const filePath = path9.join(traceDir, entry);
4938
4941
  try {
4939
- const stat19 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
4940
- files.push({ path: filePath, modifiedAt: stat19.mtime.toISOString(), groupId: pidDir.name });
4942
+ const stat18 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
4943
+ files.push({ path: filePath, modifiedAt: stat18.mtime.toISOString(), groupId: pidDir.name });
4941
4944
  } catch {
4942
4945
  }
4943
4946
  }
@@ -5163,7 +5166,6 @@ async function parseCodexSessionFile(filePath, options) {
5163
5166
  let lastTurnIdForComplete;
5164
5167
  let turnIdAtLastUserMessage;
5165
5168
  let sessionMetaLocked = false;
5166
- let forkedSession = false;
5167
5169
  let lastTotalTokenUsage;
5168
5170
  let lastPerCallUsageKey;
5169
5171
  let compactionPending = false;
@@ -5184,7 +5186,6 @@ async function parseCodexSessionFile(filePath, options) {
5184
5186
  }
5185
5187
  sessionMetaLocked = true;
5186
5188
  const forkedFromId = stringField(payload, "forked_from_id");
5187
- forkedSession = Boolean(forkedFromId);
5188
5189
  const inherited = forkedFromId ? await readPersistedSessionContextFromOptions(options, forkedFromId) : void 0;
5189
5190
  sessionId = stringField(payload, "id") || sessionId;
5190
5191
  cwd = inherited?.cwd || stringField(payload, "cwd") || cwd;
@@ -5336,7 +5337,7 @@ async function parseCodexSessionFile(filePath, options) {
5336
5337
  project,
5337
5338
  model: rewriteCodexModelForTier(model, serviceTier),
5338
5339
  confidence: "partial",
5339
- metrics: excludeForkInheritedCache(usage, forkedSession)
5340
+ metrics: usage
5340
5341
  }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5341
5342
  lastPerCallUsageKey = usageKey;
5342
5343
  }
@@ -5354,7 +5355,7 @@ async function parseCodexSessionFile(filePath, options) {
5354
5355
  project,
5355
5356
  model: rewriteCodexModelForTier(model, serviceTier),
5356
5357
  confidence: "partial",
5357
- metrics: excludeForkInheritedCache({ ...lastUsage, reasoningEffort }, forkedSession)
5358
+ metrics: { ...lastUsage, reasoningEffort }
5358
5359
  }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5359
5360
  }
5360
5361
  lastTotalTokenUsage = { input, cached, output, reasoning, total };
@@ -5378,7 +5379,7 @@ async function parseCodexSessionFile(filePath, options) {
5378
5379
  project,
5379
5380
  model: rewriteCodexModelForTier(model, serviceTier),
5380
5381
  confidence: "partial",
5381
- metrics: excludeForkInheritedCache({
5382
+ metrics: {
5382
5383
  tokensInput: deltaInput > 0 ? deltaInput : void 0,
5383
5384
  tokensCachedInput: deltaCached > 0 ? deltaCached : void 0,
5384
5385
  tokensOutput: deltaOutput > 0 ? deltaOutput : void 0,
@@ -5386,7 +5387,7 @@ async function parseCodexSessionFile(filePath, options) {
5386
5387
  tokensTotal: deltaTotal > 0 ? deltaTotal : void 0,
5387
5388
  modelContextWindow: usage.modelContextWindow,
5388
5389
  reasoningEffort
5389
- }, forkedSession)
5390
+ }
5390
5391
  }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5391
5392
  }
5392
5393
  } else {
@@ -5399,7 +5400,7 @@ async function parseCodexSessionFile(filePath, options) {
5399
5400
  project,
5400
5401
  model: rewriteCodexModelForTier(model, serviceTier),
5401
5402
  confidence: "partial",
5402
- metrics: excludeForkInheritedCache({
5403
+ metrics: {
5403
5404
  tokensInput: input,
5404
5405
  tokensCachedInput: cached,
5405
5406
  tokensOutput: output,
@@ -5407,7 +5408,7 @@ async function parseCodexSessionFile(filePath, options) {
5407
5408
  tokensTotal: total,
5408
5409
  modelContextWindow: usage.modelContextWindow,
5409
5410
  reasoningEffort
5410
- }, forkedSession)
5411
+ }
5411
5412
  }), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
5412
5413
  }
5413
5414
  lastTotalTokenUsage = { input, cached, output, reasoning, total };
@@ -5708,18 +5709,6 @@ function tokenUsageFromRecord(usage, info) {
5708
5709
  modelContextWindow: numberField(info, "model_context_window")
5709
5710
  };
5710
5711
  }
5711
- function excludeForkInheritedCache(usage, forked) {
5712
- if (!forked || !usage) {
5713
- return usage;
5714
- }
5715
- const cached = usage.tokensCachedInput ?? 0;
5716
- return {
5717
- ...usage,
5718
- tokensInput: Math.max(0, (usage.tokensInput ?? 0) - cached) || void 0,
5719
- tokensCachedInput: void 0,
5720
- tokensTotal: Math.max(0, (usage.tokensTotal ?? 0) - cached) || void 0
5721
- };
5722
- }
5723
5712
  function toolNameFromPayload(payload, payloadType) {
5724
5713
  if (payloadType === "web_search_call") {
5725
5714
  return "web_search";
@@ -6514,10 +6503,10 @@ function cloudAgentSessionFromEvents(conversationId, events) {
6514
6503
  };
6515
6504
  }
6516
6505
  function hookUncachedInputTokens(turn) {
6517
- return Math.max(0, (turn.tokensInput || 0) - (turn.tokensCacheReadInput || 0));
6506
+ return Math.max(0, (turn.tokensInput || 0) - (turn.tokensCacheReadInput || 0) - (turn.tokensCacheCreationInput || 0));
6518
6507
  }
6519
6508
  function cloudEventMatchesHookTurn(event, turn) {
6520
- return event.tokensInput === hookUncachedInputTokens(turn) && event.tokensOutput === (turn.tokensOutput || 0) && event.tokensCacheReadInput === (turn.tokensCacheReadInput || 0);
6509
+ return event.tokensInput === hookUncachedInputTokens(turn) && event.tokensOutput === (turn.tokensOutput || 0) && event.tokensCacheReadInput === (turn.tokensCacheReadInput || 0) && event.tokensCacheCreationInput === (turn.tokensCacheCreationInput || 0);
6521
6510
  }
6522
6511
  function unmatchedCloudEvents(events, turns) {
6523
6512
  const used = /* @__PURE__ */ new Set();
@@ -6860,6 +6849,11 @@ async function loadCursorCloudUsageMap(options, filePath) {
6860
6849
  return cached;
6861
6850
  }
6862
6851
  const home = stringOption(options.home) || os6.homedir();
6852
+ if (options.skipCursorCloud) {
6853
+ return cloudUsageMapFromSessions(
6854
+ parseCursorCloudUsageCache(await readJsonIfExists(cursorCloudUsageCachePath(home)))
6855
+ );
6856
+ }
6863
6857
  const intervalSeconds = cursorCloudFetchIntervalSeconds();
6864
6858
  if (intervalSeconds > 0 && !options.force) {
6865
6859
  const lastFetchedMs = await readLastCloudFetchAt(home);
@@ -6981,7 +6975,7 @@ async function writeCursorCloudUsageCache(cachePath, sessions) {
6981
6975
  const info = await stat8(cachePath);
6982
6976
  return info.mtime.toISOString();
6983
6977
  }
6984
- function parseCursorCloudAgentSessions(filePath, options, sessions, localIds, identity) {
6978
+ function parseCursorCloudAgentSessions(filePath, options, sessions, localIds) {
6985
6979
  const events = [];
6986
6980
  const sourcePathHash = `sha256:${createStableHash(filePath)}`;
6987
6981
  const project = CURSOR_CLOUD_AGENT_PROJECT;
@@ -6998,8 +6992,8 @@ function parseCursorCloudAgentSessions(filePath, options, sessions, localIds, id
6998
6992
  lineNumber += 1;
6999
6993
  const event = {
7000
6994
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
7001
- source: identity.source,
7002
- agent: identity.agent,
6995
+ source: SOURCE_ID,
6996
+ agent: AGENT_NAME,
7003
6997
  workspaceId,
7004
6998
  project,
7005
6999
  model: lastModel,
@@ -7056,7 +7050,7 @@ function parseCursorCloudAgentSessions(filePath, options, sessions, localIds, id
7056
7050
  }
7057
7051
  return events;
7058
7052
  }
7059
- async function parseCursorCloudAgentFile(filePath, options, identity) {
7053
+ async function parseCursorCloudAgentFile(filePath, options) {
7060
7054
  const home = stringOption(options.home) || os6.homedir();
7061
7055
  const env = {
7062
7056
  CURSOR_HOME: process.env.CURSOR_HOME,
@@ -7068,7 +7062,7 @@ async function parseCursorCloudAgentFile(filePath, options, identity) {
7068
7062
  return session ? [session] : [];
7069
7063
  }) : parseCursorCloudUsageCache(await readJsonIfExists(filePath));
7070
7064
  const localIds = await listLocalCursorSessionIds(home, env);
7071
- return parseCursorCloudAgentSessions(filePath, options, sessions, localIds, identity);
7065
+ return parseCursorCloudAgentSessions(filePath, options, sessions, localIds);
7072
7066
  }
7073
7067
  function decodeKv(value) {
7074
7068
  if (typeof value === "string") {
@@ -7927,6 +7921,9 @@ async function parseCursorSessionFile(filePath, options) {
7927
7921
  if (base.endsWith(".jsonl")) {
7928
7922
  return parseCursorTranscriptFile(filePath, options);
7929
7923
  }
7924
+ if (base === CURSOR_CLOUD_USAGE_FILENAME) {
7925
+ return parseCursorCloudAgentFile(filePath, options);
7926
+ }
7930
7927
  if (base === "store.db") {
7931
7928
  return [];
7932
7929
  }
@@ -8161,7 +8158,36 @@ function parseComposer(db, composer, filePath, sourcePathHash, options, persiste
8161
8158
  emitPersistedCursorUsage(push, persistedUsage, endedAt || startedAt, currentTurnId, model, sessionId, events.some((event) => event.type === "model.usage"));
8162
8159
  return events;
8163
8160
  }
8164
- async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env) {
8161
+ async function cursorCloudUsageBackfillFiles(home, options) {
8162
+ if (options?.skipCursorCloud || cursorCloudUsageDisabled()) {
8163
+ return [];
8164
+ }
8165
+ const cachePath = cursorCloudUsageCachePath(home);
8166
+ if (!options) {
8167
+ const info = await stat8(cachePath).catch(() => null);
8168
+ return info ? [{ path: cachePath, modifiedAt: info.mtime.toISOString() }] : [];
8169
+ }
8170
+ const map = await loadCursorCloudUsageMap(options);
8171
+ if (map.size === 0) {
8172
+ const info = await stat8(cachePath).catch(() => null);
8173
+ return info ? [{ path: cachePath, modifiedAt: info.mtime.toISOString() }] : [];
8174
+ }
8175
+ const sessions = [];
8176
+ for (const [conversationId, events] of map) {
8177
+ const session = cloudAgentSessionFromEvents(conversationId, events);
8178
+ if (session) {
8179
+ sessions.push(session);
8180
+ }
8181
+ }
8182
+ if (sessions.length === 0) {
8183
+ return [];
8184
+ }
8185
+ return [{
8186
+ path: cachePath,
8187
+ modifiedAt: await writeCursorCloudUsageCache(cachePath, sessions)
8188
+ }];
8189
+ }
8190
+ async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env, options) {
8165
8191
  if (sourceRoot) {
8166
8192
  const info = await stat8(sourceRoot).catch(() => null);
8167
8193
  if (!info) {
@@ -8191,6 +8217,9 @@ async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env) {
8191
8217
  files2.push(...await collectCursorTranscriptFiles(sourceRoot, home, skipIds2));
8192
8218
  return files2;
8193
8219
  }
8220
+ if (path13.basename(sourceRoot) === CURSOR_CLOUD_USAGE_FILENAME) {
8221
+ return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
8222
+ }
8194
8223
  if (path13.basename(sourceRoot) === "store.db") {
8195
8224
  return [];
8196
8225
  }
@@ -8228,6 +8257,7 @@ async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env) {
8228
8257
  break;
8229
8258
  }
8230
8259
  files.push(...await collectCursorTranscriptFiles(cursorProjectsDir(home, env), home, skipIds));
8260
+ files.push(...await cursorCloudUsageBackfillFiles(home, options));
8231
8261
  return files;
8232
8262
  }
8233
8263
  function cursorHookConfig() {
@@ -8265,85 +8295,22 @@ function createCursorAdapter() {
8265
8295
  return [
8266
8296
  ...cursorStateDbCandidates(home, env),
8267
8297
  cursorProjectsDir(home, env),
8268
- cursorChatsDir(home, env)
8298
+ cursorChatsDir(home, env),
8299
+ cursorCloudUsageCachePath(home)
8269
8300
  ];
8270
8301
  },
8271
8302
  parseSessionFile: parseCursorSessionFile
8272
8303
  };
8273
8304
  }
8274
8305
 
8275
- // src/adapters/grok-bot.ts
8276
- import { stat as stat9 } from "node:fs/promises";
8277
- import os7 from "node:os";
8278
- var SOURCE_ID2 = "grok-bot";
8279
- var AGENT_NAME2 = "grok-bot";
8280
- var IDENTITY = { source: SOURCE_ID2, agent: AGENT_NAME2 };
8281
- async function grokBotBackfillFiles(sourceRoot, home = os7.homedir(), _env, options) {
8282
- if (sourceRoot) {
8283
- const info = await stat9(sourceRoot).catch(() => null);
8284
- return info ? [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }] : [];
8285
- }
8286
- if (!options) {
8287
- return [];
8288
- }
8289
- const cachePath = cursorCloudUsageCachePath(home);
8290
- const map = await loadCursorCloudUsageMap(options);
8291
- if (map.size === 0) {
8292
- const info = await stat9(cachePath).catch(() => null);
8293
- return info ? [{ path: cachePath, modifiedAt: info.mtime.toISOString() }] : [];
8294
- }
8295
- const sessions = [];
8296
- for (const [conversationId, events] of map) {
8297
- const session = cloudAgentSessionFromEvents(conversationId, events);
8298
- if (session) {
8299
- sessions.push(session);
8300
- }
8301
- }
8302
- if (sessions.length === 0) {
8303
- return [];
8304
- }
8305
- return [{
8306
- path: cachePath,
8307
- modifiedAt: await writeCursorCloudUsageCache(cachePath, sessions)
8308
- }];
8309
- }
8310
- function createGrokBotAdapter() {
8311
- return {
8312
- id: SOURCE_ID2,
8313
- label: "Grok Bot",
8314
- agentName: AGENT_NAME2,
8315
- kind: "agent",
8316
- // No hooks to install — data arrives via the Cursor dashboard API.
8317
- // The cache file stands in as the detect/install marker.
8318
- detectPath(home) {
8319
- return cursorCloudUsageCachePath(home);
8320
- },
8321
- installedPath(home) {
8322
- return cursorCloudUsageCachePath(home);
8323
- },
8324
- async isInstalled() {
8325
- return false;
8326
- },
8327
- installEntries() {
8328
- return [];
8329
- },
8330
- sourcePaths(home) {
8331
- return [cursorCloudUsageCachePath(home)];
8332
- },
8333
- parseSessionFile(filePath, options) {
8334
- return parseCursorCloudAgentFile(filePath, options, IDENTITY);
8335
- }
8336
- };
8337
- }
8338
-
8339
8306
  // src/adapters/grok-build.ts
8340
- import { readdir as readdir7, readFile as readFile9, stat as stat10 } from "node:fs/promises";
8307
+ import { readdir as readdir7, readFile as readFile9, stat as stat9 } from "node:fs/promises";
8341
8308
  import path14 from "node:path";
8342
8309
  init_fs();
8343
8310
  var GROK_COST_TICKS_PER_USD = 1e9;
8344
- var SOURCE_ID3 = "grok-build";
8345
- var AGENT_NAME3 = "grok-build";
8346
- var HOOK_COMMAND2 = `vibetime hook --agent ${SOURCE_ID3}`;
8311
+ var SOURCE_ID2 = "grok-build";
8312
+ var AGENT_NAME2 = "grok-build";
8313
+ var HOOK_COMMAND2 = `vibetime hook --agent ${SOURCE_ID2}`;
8347
8314
  function grokHome(home, env) {
8348
8315
  const override = env?.GROK_HOME;
8349
8316
  if (override && override.trim()) {
@@ -8377,7 +8344,7 @@ async function grokBackfillFiles(sourceRoot, home, env) {
8377
8344
  continue;
8378
8345
  }
8379
8346
  try {
8380
- const info = await stat10(entryPath);
8347
+ const info = await stat9(entryPath);
8381
8348
  files.push({ path: entryPath, modifiedAt: info.mtime.toISOString() });
8382
8349
  } catch {
8383
8350
  }
@@ -8429,8 +8396,8 @@ async function parseGrokSessionFile(filePath, options) {
8429
8396
  };
8430
8397
  const base = (partial) => ({
8431
8398
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
8432
- source: SOURCE_ID3,
8433
- agent: AGENT_NAME3,
8399
+ source: SOURCE_ID2,
8400
+ agent: AGENT_NAME2,
8434
8401
  workspaceId,
8435
8402
  project,
8436
8403
  cwd,
@@ -8990,7 +8957,7 @@ async function loadHunkFileActivities(hunkPath, cwd) {
8990
8957
  }
8991
8958
  return activities;
8992
8959
  }
8993
- var grokHandler = (msg) => hookHandler(SOURCE_ID3, msg);
8960
+ var grokHandler = (msg) => hookHandler(SOURCE_ID2, msg);
8994
8961
  function hookConfig5() {
8995
8962
  const anyTool = [{ matcher: ".*", hooks: [grokHandler("Reporting tool activity")] }];
8996
8963
  return {
@@ -9012,9 +8979,9 @@ function hookConfig5() {
9012
8979
  }
9013
8980
  function createGrokBuildAdapter() {
9014
8981
  return {
9015
- id: SOURCE_ID3,
8982
+ id: SOURCE_ID2,
9016
8983
  label: "Grok Build",
9017
- agentName: AGENT_NAME3,
8984
+ agentName: AGENT_NAME2,
9018
8985
  kind: "agent",
9019
8986
  detectPath(home, env) {
9020
8987
  return grokHome(home, env);
@@ -9040,7 +9007,7 @@ function createGrokBuildAdapter() {
9040
9007
  }
9041
9008
 
9042
9009
  // src/adapters/hermes.ts
9043
- import { readdir as readdir8, stat as stat11 } from "node:fs/promises";
9010
+ import { readdir as readdir8, stat as stat10 } from "node:fs/promises";
9044
9011
  import path15 from "node:path";
9045
9012
  init_fs();
9046
9013
  var SOURCE = "hermes";
@@ -9333,11 +9300,11 @@ function hermesToolAlias(tool) {
9333
9300
  }
9334
9301
  async function sqliteMtime(filePath) {
9335
9302
  try {
9336
- const info = await stat11(filePath);
9303
+ const info = await stat10(filePath);
9337
9304
  let modifiedMs = info.mtimeMs;
9338
9305
  for (const suffix of ["-wal", "-shm"]) {
9339
9306
  try {
9340
- const sidecar = await stat11(`${filePath}${suffix}`);
9307
+ const sidecar = await stat10(`${filePath}${suffix}`);
9341
9308
  modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
9342
9309
  } catch {
9343
9310
  }
@@ -10630,7 +10597,7 @@ function createKimiCodeAdapter() {
10630
10597
  }
10631
10598
 
10632
10599
  // src/adapters/opencode.ts
10633
- import os8 from "node:os";
10600
+ import os7 from "node:os";
10634
10601
  import path17 from "node:path";
10635
10602
  async function parseOpenCodeSessionFile(dbPath, options) {
10636
10603
  const { DatabaseSync } = await import("node:sqlite");
@@ -11085,20 +11052,20 @@ function opencodeDataCandidates(home, env) {
11085
11052
  const primary = xdgData && xdgData.trim() ? path17.join(path17.resolve(xdgData), "opencode", "opencode.db") : path17.join(home, ".local", "share", "opencode", "opencode.db");
11086
11053
  return [primary, path17.join(home, ".opencode", "opencode.db")];
11087
11054
  }
11088
- async function opencodeBackfillFiles(sourceRoot, home = os8.homedir(), env) {
11089
- const { stat: stat19 } = await import("node:fs/promises");
11055
+ async function opencodeBackfillFiles(sourceRoot, home = os7.homedir(), env) {
11056
+ const { stat: stat18 } = await import("node:fs/promises");
11090
11057
  if (sourceRoot) {
11091
11058
  if (!sourceRoot.endsWith(".db")) {
11092
11059
  return [];
11093
11060
  }
11094
- const info = await stat19(sourceRoot).catch(() => null);
11061
+ const info = await stat18(sourceRoot).catch(() => null);
11095
11062
  if (!info) {
11096
11063
  return [];
11097
11064
  }
11098
11065
  return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
11099
11066
  }
11100
11067
  for (const candidatePath of opencodeDataCandidates(home, env)) {
11101
- const info = await stat19(candidatePath).catch(() => null);
11068
+ const info = await stat18(candidatePath).catch(() => null);
11102
11069
  if (info) {
11103
11070
  return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
11104
11071
  }
@@ -11198,8 +11165,8 @@ function createOpenCodeAdapter() {
11198
11165
  }
11199
11166
 
11200
11167
  // src/adapters/pi.ts
11201
- import { readdir as readdir9, readFile as readFile11, stat as stat12 } from "node:fs/promises";
11202
- import os9 from "node:os";
11168
+ import { readdir as readdir9, readFile as readFile11, stat as stat11 } from "node:fs/promises";
11169
+ import os8 from "node:os";
11203
11170
  import path18 from "node:path";
11204
11171
  init_fs();
11205
11172
  function piHostSessionIdFromBasename(basename) {
@@ -11610,7 +11577,7 @@ async function parsePiWorkflowRunFile(filePath, options) {
11610
11577
  return state.events.filter((event) => matchesBackfillFilters(event, options));
11611
11578
  }
11612
11579
  async function findPiSessionFileById(sessionId, options) {
11613
- const sessionsDir = piSessionDir(path18.resolve(stringOption(options.home) || os9.homedir()));
11580
+ const sessionsDir = piSessionDir(path18.resolve(stringOption(options.home) || os8.homedir()));
11614
11581
  try {
11615
11582
  const projectDirs = await readdir9(sessionsDir, { withFileTypes: true });
11616
11583
  for (const dir of projectDirs) {
@@ -11887,14 +11854,14 @@ async function workflowRunGroupId(filePath) {
11887
11854
  return void 0;
11888
11855
  }
11889
11856
  }
11890
- async function piBackfillFiles(sourceRoot, home = os9.homedir(), env) {
11857
+ async function piBackfillFiles(sourceRoot, home = os8.homedir(), env) {
11891
11858
  const lists = sourceRoot ? [await listFilesByExtensions(sourceRoot, [".jsonl", ".json"])] : await Promise.all([
11892
11859
  listFilesByExtensions(piSessionDir(home, env), [".jsonl"]),
11893
11860
  listFilesByExtensions(piWorkflowProjectsDir(home), [".json"])
11894
11861
  ]);
11895
11862
  const files = lists.flat().sort();
11896
11863
  return Promise.all(files.map(async (filePath) => {
11897
- const info = await stat12(filePath);
11864
+ const info = await stat11(filePath);
11898
11865
  let groupId = resolvePiBackfillGroupId(filePath);
11899
11866
  if (!groupId && filePath.endsWith(".json")) {
11900
11867
  groupId = await workflowRunGroupId(filePath);
@@ -11941,13 +11908,13 @@ function createPiAdapter() {
11941
11908
  }
11942
11909
 
11943
11910
  // src/adapters/qoder-cn.ts
11944
- import { readdir as readdir10, readFile as readFile12, stat as stat13 } from "node:fs/promises";
11945
- import os11 from "node:os";
11911
+ import { readdir as readdir10, readFile as readFile12, stat as stat12 } from "node:fs/promises";
11912
+ import os10 from "node:os";
11946
11913
  import path20 from "node:path";
11947
11914
 
11948
11915
  // src/adapters/qoder-local-db.ts
11949
11916
  import { access } from "node:fs/promises";
11950
- import os10 from "node:os";
11917
+ import os9 from "node:os";
11951
11918
  import path19 from "node:path";
11952
11919
  function takeQoderDbModelCall(calls, requestId, blockStart) {
11953
11920
  if (requestId) {
@@ -11965,7 +11932,7 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
11965
11932
  }
11966
11933
  return calls.ordered.shift();
11967
11934
  }
11968
- function appDataRoot(appDirName, home = os10.homedir()) {
11935
+ function appDataRoot(appDirName, home = os9.homedir()) {
11969
11936
  if (process.platform === "darwin") {
11970
11937
  return path19.join(home, "Library", "Application Support", appDirName);
11971
11938
  }
@@ -12274,7 +12241,7 @@ async function parseQoderCnSessionFile(filePath, options) {
12274
12241
  let cwd;
12275
12242
  let project = projectContext.project;
12276
12243
  let model;
12277
- const home = path20.resolve(stringOption(options.home) || os11.homedir());
12244
+ const home = path20.resolve(stringOption(options.home) || os10.homedir());
12278
12245
  const modelMap = await loadQoderCnModelNames(configDir2, home);
12279
12246
  const isSubagentSession = filePath.includes("subagents");
12280
12247
  const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
@@ -12844,7 +12811,7 @@ async function gitRootFromCwds2(cwds) {
12844
12811
  while (!seen.has(current)) {
12845
12812
  seen.add(current);
12846
12813
  try {
12847
- await stat13(path20.join(current, ".git"));
12814
+ await stat12(path20.join(current, ".git"));
12848
12815
  return current;
12849
12816
  } catch {
12850
12817
  }
@@ -12878,7 +12845,7 @@ function encodeQoderCnProjectPath(value) {
12878
12845
  }
12879
12846
  async function qoderCnProjectFromFilePath(filePath, options) {
12880
12847
  const projectDir = path20.basename(path20.dirname(filePath));
12881
- const home = options ? path20.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
12848
+ const home = options ? path20.resolve(stringOption(options.home) || os10.homedir()) : os10.homedir();
12882
12849
  const resolved = await resolveQoderCnProjectPath(projectDir, home);
12883
12850
  if (resolved) {
12884
12851
  return path20.basename(resolved);
@@ -12994,8 +12961,8 @@ function createQoderCnAdapter() {
12994
12961
 
12995
12962
  // src/adapters/qoder.ts
12996
12963
  import { existsSync } from "node:fs";
12997
- import { readdir as readdir11, readFile as readFile13, stat as stat14 } from "node:fs/promises";
12998
- import os12 from "node:os";
12964
+ import { readdir as readdir11, readFile as readFile13, stat as stat13 } from "node:fs/promises";
12965
+ import os11 from "node:os";
12999
12966
  import path21 from "node:path";
13000
12967
  function parseQoderPaths(filePath) {
13001
12968
  const parts = filePath.split(path21.sep);
@@ -13160,7 +13127,7 @@ async function parseQoderSessionFile(filePath, options) {
13160
13127
  let cwd;
13161
13128
  let project = projectContext.project;
13162
13129
  let model;
13163
- const home = path21.resolve(stringOption(options.home) || os12.homedir());
13130
+ const home = path21.resolve(stringOption(options.home) || os11.homedir());
13164
13131
  const modelMap = await loadQoderModelNames(configDir2, home);
13165
13132
  const qwenworkRoot = isQwenworkConfigRoot(configDir2);
13166
13133
  const isSubagentSession = filePath.includes("subagents");
@@ -13696,7 +13663,7 @@ async function gitRootFromCwds3(cwds) {
13696
13663
  while (!seen.has(current)) {
13697
13664
  seen.add(current);
13698
13665
  try {
13699
- await stat14(path21.join(current, ".git"));
13666
+ await stat13(path21.join(current, ".git"));
13700
13667
  return current;
13701
13668
  } catch {
13702
13669
  }
@@ -13748,7 +13715,7 @@ function qoderEncodedProjectSuffix(projectDir, home) {
13748
13715
  }
13749
13716
  async function qoderProjectFromFilePath(filePath, options) {
13750
13717
  const projectDir = path21.basename(path21.dirname(filePath));
13751
- const home = options ? path21.resolve(stringOption(options.home) || os12.homedir()) : os12.homedir();
13718
+ const home = options ? path21.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
13752
13719
  const resolved = await resolveQoderProjectPath(projectDir, home);
13753
13720
  if (resolved) {
13754
13721
  return path21.basename(resolved);
@@ -13900,11 +13867,14 @@ function normalizeId(id) {
13900
13867
  if (id === "claude") {
13901
13868
  return "claude-code";
13902
13869
  }
13870
+ if (id === "grok-bot") {
13871
+ return "cursor";
13872
+ }
13903
13873
  return id;
13904
13874
  }
13905
13875
 
13906
13876
  // src/adapters/workbuddy.ts
13907
- import { readdir as readdir12, readFile as readFile14, stat as stat15 } from "node:fs/promises";
13877
+ import { readdir as readdir12, readFile as readFile14, stat as stat14 } from "node:fs/promises";
13908
13878
  import path22 from "node:path";
13909
13879
  function workbuddyProjectsDir(home, env) {
13910
13880
  const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
@@ -14357,7 +14327,7 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
14357
14327
  for (const entry of entries) {
14358
14328
  if (entry.isFile() && entry.name.endsWith(".jsonl")) {
14359
14329
  const filePath = path22.join(projectDir, entry.name);
14360
- const info = await stat15(filePath);
14330
+ const info = await stat14(filePath);
14361
14331
  files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
14362
14332
  }
14363
14333
  }
@@ -14418,7 +14388,7 @@ function createWorkbuddyAdapter() {
14418
14388
 
14419
14389
  // src/adapters/zcode.ts
14420
14390
  import { execFile } from "node:child_process";
14421
- import { readFile as readFile15, stat as stat16 } from "node:fs/promises";
14391
+ import { readFile as readFile15, stat as stat15 } from "node:fs/promises";
14422
14392
  import path23 from "node:path";
14423
14393
  import { promisify as promisify2 } from "node:util";
14424
14394
  var execFileAsync = promisify2(execFile);
@@ -14457,7 +14427,7 @@ var providerNameCache = null;
14457
14427
  async function loadProviderNames(configPath2) {
14458
14428
  let fileMtime = 0;
14459
14429
  try {
14460
- const info = await stat16(configPath2);
14430
+ const info = await stat15(configPath2);
14461
14431
  fileMtime = info.mtimeMs;
14462
14432
  } catch {
14463
14433
  return /* @__PURE__ */ new Map();
@@ -14685,7 +14655,7 @@ async function parseZCodeDb(filePath, options) {
14685
14655
  for (let i = 0; i < 12; i++) {
14686
14656
  const probe = path23.join(candidate, ".zcode", "v2", "config.json");
14687
14657
  try {
14688
- await stat16(probe);
14658
+ await stat15(probe);
14689
14659
  configPath2 = probe;
14690
14660
  break;
14691
14661
  } catch {
@@ -14919,11 +14889,11 @@ async function zcodeBackfillFiles(sourceRoot, home, env) {
14919
14889
  const candidate = sourceRoot || zcodeDbPath(home, env);
14920
14890
  const filePath = candidate.endsWith(".sqlite") ? candidate : path23.join(candidate, "db", "db.sqlite");
14921
14891
  try {
14922
- const info = await stat16(filePath);
14892
+ const info = await stat15(filePath);
14923
14893
  let modifiedMs = info.mtimeMs;
14924
14894
  for (const suffix of ["-wal", "-shm"]) {
14925
14895
  try {
14926
- const sidecar = await stat16(`${filePath}${suffix}`);
14896
+ const sidecar = await stat15(`${filePath}${suffix}`);
14927
14897
  modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
14928
14898
  } catch {
14929
14899
  }
@@ -14966,7 +14936,7 @@ function createZCodeAdapter() {
14966
14936
  }
14967
14937
 
14968
14938
  // src/adapters/zed.ts
14969
- import os13 from "node:os";
14939
+ import os12 from "node:os";
14970
14940
  import path24 from "node:path";
14971
14941
  function zedThreadsCandidates(home, env) {
14972
14942
  const candidates = [];
@@ -15318,20 +15288,20 @@ async function parseZedSessionFile(dbPath, options) {
15318
15288
  }
15319
15289
  return events.filter((event) => matchesBackfillFilters(event, options));
15320
15290
  }
15321
- async function zedBackfillFiles(sourceRoot, home = os13.homedir(), env) {
15322
- const { stat: stat19 } = await import("node:fs/promises");
15291
+ async function zedBackfillFiles(sourceRoot, home = os12.homedir(), env) {
15292
+ const { stat: stat18 } = await import("node:fs/promises");
15323
15293
  if (sourceRoot) {
15324
15294
  if (!sourceRoot.endsWith(".db")) {
15325
15295
  return [];
15326
15296
  }
15327
- const info = await stat19(sourceRoot).catch(() => null);
15297
+ const info = await stat18(sourceRoot).catch(() => null);
15328
15298
  if (!info) {
15329
15299
  return [];
15330
15300
  }
15331
15301
  return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
15332
15302
  }
15333
15303
  for (const candidatePath of zedThreadsCandidates(home, env)) {
15334
- const info = await stat19(candidatePath).catch(() => null);
15304
+ const info = await stat18(candidatePath).catch(() => null);
15335
15305
  if (info) {
15336
15306
  return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
15337
15307
  }
@@ -16222,7 +16192,7 @@ function defaultMachineName() {
16222
16192
  init_fs();
16223
16193
 
16224
16194
  // src/lib/logger.ts
16225
- import { appendFile, mkdir as mkdir5, rename as rename2, stat as stat17 } from "node:fs/promises";
16195
+ import { appendFile, mkdir as mkdir5, rename as rename2, stat as stat16 } from "node:fs/promises";
16226
16196
  import { homedir as homedir2 } from "node:os";
16227
16197
  import path26 from "node:path";
16228
16198
  var MAX_BYTES = 1 * 1024 * 1024;
@@ -16240,7 +16210,7 @@ function serializeError(error) {
16240
16210
  }
16241
16211
  async function rotateIfNeeded(file) {
16242
16212
  try {
16243
- const info = await stat17(file);
16213
+ const info = await stat16(file);
16244
16214
  if (info.size > MAX_BYTES) {
16245
16215
  await rename2(file, `${file}.1`).catch(() => {
16246
16216
  });
@@ -16476,7 +16446,7 @@ async function deleteMachine(remote, id) {
16476
16446
  }
16477
16447
 
16478
16448
  // src/lib/types.ts
16479
- var BACKFILL_STATE_SCHEMA_VERSION = 10;
16449
+ var BACKFILL_STATE_SCHEMA_VERSION = 11;
16480
16450
 
16481
16451
  // src/cli.ts
16482
16452
  function createRegistry() {
@@ -16497,7 +16467,6 @@ function createRegistry() {
16497
16467
  registry.register(createZedAdapter());
16498
16468
  registry.register(createKimiCodeAdapter());
16499
16469
  registry.register(createCursorAdapter());
16500
- registry.register(createGrokBotAdapter());
16501
16470
  registry.register(createHermesAdapter());
16502
16471
  return registry;
16503
16472
  }
@@ -17058,10 +17027,14 @@ async function listBackfillSourceFiles(source, options, ctx) {
17058
17027
  return zedBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
17059
17028
  }
17060
17029
  if (source.id === "cursor") {
17061
- return cursorBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
17062
- }
17063
- if (source.id === "grok-bot") {
17064
- return grokBotBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env, options);
17030
+ const requested = normalizeBackfillSource(stringOption(options.source) || "all");
17031
+ const skipCursorCloud = requested === "all" && disabledBackfillSourceSet(readConfig(resolveHome3(options, ctx))).has("grok-bot");
17032
+ return cursorBackfillFiles(
17033
+ stringOption(options["source-root"]),
17034
+ resolveHome3(options, ctx),
17035
+ ctx.env,
17036
+ { ...options, skipCursorCloud }
17037
+ );
17065
17038
  }
17066
17039
  if (source.id === "hermes") {
17067
17040
  return hermesBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
@@ -17073,7 +17046,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
17073
17046
  const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
17074
17047
  const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
17075
17048
  return Promise.all(files.map(async (filePath) => {
17076
- const info = await stat18(filePath);
17049
+ const info = await stat17(filePath);
17077
17050
  return { path: filePath, modifiedAt: info.mtime.toISOString() };
17078
17051
  }));
17079
17052
  }
@@ -17324,20 +17297,36 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
17324
17297
  machine,
17325
17298
  allowHistoricalRewrite: options.force === true
17326
17299
  });
17327
- if (options.force && result.conflicts === 0) {
17328
- for (const rollup of rollups) {
17329
- for (const sessionId of rollup.supersededSessionIds ?? []) {
17330
- try {
17331
- await deleteRollupsBySource(remote, rollup.source, machine, {
17332
- rollupKey: createImportKey(["rollup", rollup.source, sessionId]),
17333
- allowHistoricalRewrite: options.force === true
17334
- });
17335
- } catch (error) {
17336
- debug(ctx, `Failed to delete superseded ${rollup.source} session ${sessionId}: ${error.message}
17300
+ if (result.conflicts === 0) {
17301
+ if (options.force) {
17302
+ for (const rollup of rollups) {
17303
+ for (const sessionId of rollup.supersededSessionIds ?? []) {
17304
+ try {
17305
+ await deleteRollupsBySource(remote, rollup.source, machine, {
17306
+ rollupKey: rollupKeyForSourceSession(rollup.source, sessionId),
17307
+ allowHistoricalRewrite: true
17308
+ });
17309
+ } catch (error) {
17310
+ debug(ctx, `Failed to delete superseded ${rollup.source} session ${sessionId}: ${error.message}
17337
17311
  `);
17312
+ }
17338
17313
  }
17339
17314
  }
17340
17315
  }
17316
+ for (const rollup of rollups) {
17317
+ if (rollup.source !== "cursor") {
17318
+ continue;
17319
+ }
17320
+ try {
17321
+ await deleteRollupsBySource(remote, "grok-bot", machine, {
17322
+ rollupKey: rollupKeyForSourceSession("grok-bot", rollup.sessionId),
17323
+ allowHistoricalRewrite: true
17324
+ });
17325
+ } catch (error) {
17326
+ debug(ctx, `Failed to delete grok-bot twin of cursor session ${rollup.sessionId}: ${error.message}
17327
+ `);
17328
+ }
17329
+ }
17341
17330
  }
17342
17331
  return result;
17343
17332
  }
@@ -17625,7 +17614,7 @@ function syncLocalRunnerEntryArgs(cliPath) {
17625
17614
  return [path27.resolve(path27.dirname(cliPath), "../bin/vibetime.mjs")];
17626
17615
  }
17627
17616
  function resolveHome3(options, ctx) {
17628
- return path27.resolve(stringOption(options.home) || ctx.env.HOME || os14.homedir());
17617
+ return path27.resolve(stringOption(options.home) || ctx.env.HOME || os13.homedir());
17629
17618
  }
17630
17619
  function requestedTargets(options) {
17631
17620
  const value = options.target || options.targets;
@@ -17635,7 +17624,13 @@ function requestedTargets(options) {
17635
17624
  return valuesOption(value).flatMap((item) => item.split(",")).map((t) => t.trim()).filter(Boolean);
17636
17625
  }
17637
17626
  function normalizeBackfillSource(source) {
17638
- return source === "claude" ? "claude-code" : source;
17627
+ if (source === "claude") {
17628
+ return "claude-code";
17629
+ }
17630
+ if (source === "grok-bot") {
17631
+ return "cursor";
17632
+ }
17633
+ return source;
17639
17634
  }
17640
17635
  function requiredOption(options, name) {
17641
17636
  const value = stringOption(options[name]);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.73",
4
+ "version": "0.1.75",
5
5
  "description": "vibetime CLI — install AI-agent hooks (Claude Code, Codex, OpenCode, Pi, Cursor) and report activity to vibetime.",
6
6
  "license": "MIT",
7
7
  "publishConfig": {