@yhong91/vibetime 0.1.66 → 0.1.67

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 +109 -12
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -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.66" : "0.1.1";
2050
+ var PACKAGE_VERSION = true ? "0.1.67" : "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;
@@ -6291,6 +6291,7 @@ function createCopilotAdapter() {
6291
6291
  }
6292
6292
 
6293
6293
  // src/adapters/cursor.ts
6294
+ import { readFileSync } from "node:fs";
6294
6295
  import { copyFile, mkdir as mkdir4, readdir as readdir6, readFile as readFile8, stat as stat8, writeFile as writeFile4 } from "node:fs/promises";
6295
6296
  import os6 from "node:os";
6296
6297
  import path13 from "node:path";
@@ -6873,9 +6874,18 @@ function cloudUsageToPersisted(row, index = 0) {
6873
6874
  tokensCacheCreationInput: row.tokensCacheCreationInput || void 0
6874
6875
  };
6875
6876
  }
6876
- async function resolveCursorSessionUsage(options, sessionId) {
6877
+ async function resolveCursorSessionUsage(options, sessionId, filePath) {
6877
6878
  const persisted = await readPersistedSessionContextFromOptions(options, sessionId);
6878
- return persisted?.usage ?? [];
6879
+ const hookUsage = persisted?.usage ?? [];
6880
+ if (hookUsage.length > 0) {
6881
+ return hookUsage;
6882
+ }
6883
+ const cloudMap = await loadCursorCloudUsageMap(options, filePath);
6884
+ const cloudEvents = cloudMap.get(sessionId);
6885
+ if (!cloudEvents?.length) {
6886
+ return [];
6887
+ }
6888
+ return cloudEvents.map((event, index) => cloudUsageToPersisted(event, index));
6879
6889
  }
6880
6890
  function cursorCloudUsageCachePath(home) {
6881
6891
  return path13.join(home, ".vibetime", CURSOR_CLOUD_USAGE_FILENAME);
@@ -7146,13 +7156,99 @@ function loadBubbles(db, composerId) {
7146
7156
  });
7147
7157
  return bubbles;
7148
7158
  }
7159
+ function pathFromCursorResource(value) {
7160
+ const trimmed = value.trim();
7161
+ if (!trimmed) {
7162
+ return void 0;
7163
+ }
7164
+ const remote = trimmed.match(/^vscode-remote:\/\/[^/]+(\/.*)$/i);
7165
+ if (remote?.[1]) {
7166
+ try {
7167
+ return decodeURIComponent(remote[1]);
7168
+ } catch {
7169
+ return remote[1];
7170
+ }
7171
+ }
7172
+ if (trimmed.startsWith("file:")) {
7173
+ const rest = trimmed.slice("file://".length);
7174
+ try {
7175
+ return decodeURIComponent(rest);
7176
+ } catch {
7177
+ return rest;
7178
+ }
7179
+ }
7180
+ if (path13.isAbsolute(trimmed) || trimmed.startsWith("/")) {
7181
+ return trimmed;
7182
+ }
7183
+ return void 0;
7184
+ }
7185
+ function projectFromFolderPaths(folders, fallback) {
7186
+ const names = [...new Set(
7187
+ folders.map((folder) => path13.basename(folder.replace(/[\\/]+$/, ""))).filter(Boolean)
7188
+ )];
7189
+ if (names.length === 1) {
7190
+ return names[0];
7191
+ }
7192
+ if (names.length > 1) {
7193
+ return names.join("+");
7194
+ }
7195
+ return fallback;
7196
+ }
7197
+ function projectFallbackFromWorkspaceFile(filePath) {
7198
+ const base = path13.basename(filePath, ".code-workspace");
7199
+ const stripped = base.replace(/-workspace$/i, "").trim();
7200
+ return stripped || void 0;
7201
+ }
7202
+ function folderPathsFromCodeWorkspace(workspacePath) {
7203
+ let parsed;
7204
+ try {
7205
+ parsed = JSON.parse(readFileSync(workspacePath, "utf8"));
7206
+ } catch {
7207
+ return [];
7208
+ }
7209
+ if (!isPlainObject(parsed) || !Array.isArray(parsed.folders)) {
7210
+ return [];
7211
+ }
7212
+ const root = path13.dirname(workspacePath);
7213
+ const folders = [];
7214
+ for (const folder of parsed.folders) {
7215
+ if (!isPlainObject(folder)) {
7216
+ continue;
7217
+ }
7218
+ const uri = stringField(folder, "uri");
7219
+ if (uri) {
7220
+ const resolved = pathFromCursorResource(uri);
7221
+ if (resolved) {
7222
+ folders.push(resolved);
7223
+ }
7224
+ continue;
7225
+ }
7226
+ const relative = stringField(folder, "path");
7227
+ if (relative) {
7228
+ folders.push(path13.resolve(root, relative));
7229
+ }
7230
+ }
7231
+ return folders;
7232
+ }
7149
7233
  function workspaceFromComposer(data) {
7150
7234
  const ident = objectField(data, "workspaceIdentifier");
7151
7235
  const uri = objectField(ident, "uri");
7152
- const cwd = stringField(uri, "fsPath") || stringField(uri, "path");
7236
+ const fromUri = stringField(uri, "fsPath") || stringField(uri, "path") || (stringField(uri, "external") ? pathFromCursorResource(stringField(uri, "external")) : void 0);
7237
+ if (fromUri) {
7238
+ return {
7239
+ cwd: fromUri,
7240
+ project: path13.basename(fromUri.replace(/[\\/]+$/, "")) || void 0
7241
+ };
7242
+ }
7243
+ const configPath2 = objectField(ident, "configPath");
7244
+ const workspaceFile = stringField(configPath2, "fsPath") || stringField(configPath2, "path") || (stringField(configPath2, "external") ? pathFromCursorResource(stringField(configPath2, "external")) : void 0);
7245
+ if (!workspaceFile) {
7246
+ return {};
7247
+ }
7248
+ const folders = folderPathsFromCodeWorkspace(workspaceFile);
7153
7249
  return {
7154
- cwd,
7155
- project: cwd ? path13.basename(cwd) : void 0
7250
+ cwd: folders[0],
7251
+ project: projectFromFolderPaths(folders, projectFallbackFromWorkspaceFile(workspaceFile))
7156
7252
  };
7157
7253
  }
7158
7254
  function modelFromComposer(data) {
@@ -7688,6 +7784,7 @@ async function parseCursorTranscriptFile(filePath, options) {
7688
7784
  push,
7689
7785
  sessionId,
7690
7786
  options,
7787
+ filePath,
7691
7788
  fallbackTs: endedAt || lastTs,
7692
7789
  lastTurnId,
7693
7790
  model,
@@ -7701,7 +7798,7 @@ async function appendPersistedCursorUsage(args) {
7701
7798
  }
7702
7799
  emitPersistedCursorUsage(
7703
7800
  args.push,
7704
- await resolveCursorSessionUsage(args.options, args.sessionId),
7801
+ await resolveCursorSessionUsage(args.options, args.sessionId, args.filePath),
7705
7802
  args.fallbackTs,
7706
7803
  args.lastTurnId,
7707
7804
  args.model,
@@ -7805,7 +7902,7 @@ async function parseCursorSessionFile(filePath, options) {
7805
7902
  try {
7806
7903
  const composers = listComposers(opened.db);
7807
7904
  for (const composer of composers) {
7808
- const usage = await resolveCursorSessionUsage(options, composer.composerId);
7905
+ const usage = await resolveCursorSessionUsage(options, composer.composerId, filePath);
7809
7906
  events.push(...parseComposer(opened.db, composer, filePath, sourcePathHash, options, usage));
7810
7907
  }
7811
7908
  } finally {
@@ -8180,7 +8277,7 @@ async function grokBotBackfillFiles(sourceRoot, home = os7.homedir(), env, optio
8180
8277
  function createGrokBotAdapter() {
8181
8278
  return {
8182
8279
  id: SOURCE_ID2,
8183
- label: "Grok Bot",
8280
+ label: "Cloud Agent",
8184
8281
  agentName: AGENT_NAME2,
8185
8282
  kind: "agent",
8186
8283
  // No hooks to install — data arrives via the Cursor dashboard API.
@@ -15100,7 +15197,7 @@ async function uninstallGeneratedFile(filePath, { dryRun, onWrite }) {
15100
15197
 
15101
15198
  // src/lib/config.ts
15102
15199
  import { randomUUID } from "node:crypto";
15103
- import { existsSync as existsSync2, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
15200
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "node:fs";
15104
15201
  import { homedir, hostname } from "node:os";
15105
15202
  import path24 from "node:path";
15106
15203
  function disabledBackfillSourceSet(config) {
@@ -15122,7 +15219,7 @@ function readConfig(home = homedir()) {
15122
15219
  return {};
15123
15220
  }
15124
15221
  try {
15125
- const parsed = JSON.parse(readFileSync(file, "utf8"));
15222
+ const parsed = JSON.parse(readFileSync2(file, "utf8"));
15126
15223
  return parsed && typeof parsed === "object" ? parsed : {};
15127
15224
  } catch {
15128
15225
  return {};
@@ -15139,7 +15236,7 @@ function writeConfig(config, home = homedir()) {
15139
15236
  function ensureLocalMachineId(home = homedir()) {
15140
15237
  const file = machineIdPath(home);
15141
15238
  if (existsSync2(file)) {
15142
- const value = readFileSync(file, "utf8").trim();
15239
+ const value = readFileSync2(file, "utf8").trim();
15143
15240
  if (value.length > 0) {
15144
15241
  return value;
15145
15242
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.66",
4
+ "version": "0.1.67",
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": {