@yhong91/vibetime 0.1.74 → 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.
- package/bin/vibetime.mjs +155 -146
- 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
|
|
888
|
-
import
|
|
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.
|
|
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
|
|
4940
|
-
files.push({ path: filePath, modifiedAt:
|
|
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
|
}
|
|
@@ -6500,10 +6503,10 @@ function cloudAgentSessionFromEvents(conversationId, events) {
|
|
|
6500
6503
|
};
|
|
6501
6504
|
}
|
|
6502
6505
|
function hookUncachedInputTokens(turn) {
|
|
6503
|
-
return Math.max(0, (turn.tokensInput || 0) - (turn.tokensCacheReadInput || 0));
|
|
6506
|
+
return Math.max(0, (turn.tokensInput || 0) - (turn.tokensCacheReadInput || 0) - (turn.tokensCacheCreationInput || 0));
|
|
6504
6507
|
}
|
|
6505
6508
|
function cloudEventMatchesHookTurn(event, turn) {
|
|
6506
|
-
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);
|
|
6507
6510
|
}
|
|
6508
6511
|
function unmatchedCloudEvents(events, turns) {
|
|
6509
6512
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -6846,6 +6849,11 @@ async function loadCursorCloudUsageMap(options, filePath) {
|
|
|
6846
6849
|
return cached;
|
|
6847
6850
|
}
|
|
6848
6851
|
const home = stringOption(options.home) || os6.homedir();
|
|
6852
|
+
if (options.skipCursorCloud) {
|
|
6853
|
+
return cloudUsageMapFromSessions(
|
|
6854
|
+
parseCursorCloudUsageCache(await readJsonIfExists(cursorCloudUsageCachePath(home)))
|
|
6855
|
+
);
|
|
6856
|
+
}
|
|
6849
6857
|
const intervalSeconds = cursorCloudFetchIntervalSeconds();
|
|
6850
6858
|
if (intervalSeconds > 0 && !options.force) {
|
|
6851
6859
|
const lastFetchedMs = await readLastCloudFetchAt(home);
|
|
@@ -6967,7 +6975,7 @@ async function writeCursorCloudUsageCache(cachePath, sessions) {
|
|
|
6967
6975
|
const info = await stat8(cachePath);
|
|
6968
6976
|
return info.mtime.toISOString();
|
|
6969
6977
|
}
|
|
6970
|
-
function parseCursorCloudAgentSessions(filePath, options, sessions, localIds
|
|
6978
|
+
function parseCursorCloudAgentSessions(filePath, options, sessions, localIds) {
|
|
6971
6979
|
const events = [];
|
|
6972
6980
|
const sourcePathHash = `sha256:${createStableHash(filePath)}`;
|
|
6973
6981
|
const project = CURSOR_CLOUD_AGENT_PROJECT;
|
|
@@ -6984,8 +6992,8 @@ function parseCursorCloudAgentSessions(filePath, options, sessions, localIds, id
|
|
|
6984
6992
|
lineNumber += 1;
|
|
6985
6993
|
const event = {
|
|
6986
6994
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6987
|
-
source:
|
|
6988
|
-
agent:
|
|
6995
|
+
source: SOURCE_ID,
|
|
6996
|
+
agent: AGENT_NAME,
|
|
6989
6997
|
workspaceId,
|
|
6990
6998
|
project,
|
|
6991
6999
|
model: lastModel,
|
|
@@ -7042,7 +7050,7 @@ function parseCursorCloudAgentSessions(filePath, options, sessions, localIds, id
|
|
|
7042
7050
|
}
|
|
7043
7051
|
return events;
|
|
7044
7052
|
}
|
|
7045
|
-
async function parseCursorCloudAgentFile(filePath, options
|
|
7053
|
+
async function parseCursorCloudAgentFile(filePath, options) {
|
|
7046
7054
|
const home = stringOption(options.home) || os6.homedir();
|
|
7047
7055
|
const env = {
|
|
7048
7056
|
CURSOR_HOME: process.env.CURSOR_HOME,
|
|
@@ -7054,7 +7062,7 @@ async function parseCursorCloudAgentFile(filePath, options, identity) {
|
|
|
7054
7062
|
return session ? [session] : [];
|
|
7055
7063
|
}) : parseCursorCloudUsageCache(await readJsonIfExists(filePath));
|
|
7056
7064
|
const localIds = await listLocalCursorSessionIds(home, env);
|
|
7057
|
-
return parseCursorCloudAgentSessions(filePath, options, sessions, localIds
|
|
7065
|
+
return parseCursorCloudAgentSessions(filePath, options, sessions, localIds);
|
|
7058
7066
|
}
|
|
7059
7067
|
function decodeKv(value) {
|
|
7060
7068
|
if (typeof value === "string") {
|
|
@@ -7913,6 +7921,9 @@ async function parseCursorSessionFile(filePath, options) {
|
|
|
7913
7921
|
if (base.endsWith(".jsonl")) {
|
|
7914
7922
|
return parseCursorTranscriptFile(filePath, options);
|
|
7915
7923
|
}
|
|
7924
|
+
if (base === CURSOR_CLOUD_USAGE_FILENAME) {
|
|
7925
|
+
return parseCursorCloudAgentFile(filePath, options);
|
|
7926
|
+
}
|
|
7916
7927
|
if (base === "store.db") {
|
|
7917
7928
|
return [];
|
|
7918
7929
|
}
|
|
@@ -8147,7 +8158,36 @@ function parseComposer(db, composer, filePath, sourcePathHash, options, persiste
|
|
|
8147
8158
|
emitPersistedCursorUsage(push, persistedUsage, endedAt || startedAt, currentTurnId, model, sessionId, events.some((event) => event.type === "model.usage"));
|
|
8148
8159
|
return events;
|
|
8149
8160
|
}
|
|
8150
|
-
async function
|
|
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) {
|
|
8151
8191
|
if (sourceRoot) {
|
|
8152
8192
|
const info = await stat8(sourceRoot).catch(() => null);
|
|
8153
8193
|
if (!info) {
|
|
@@ -8177,6 +8217,9 @@ async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env) {
|
|
|
8177
8217
|
files2.push(...await collectCursorTranscriptFiles(sourceRoot, home, skipIds2));
|
|
8178
8218
|
return files2;
|
|
8179
8219
|
}
|
|
8220
|
+
if (path13.basename(sourceRoot) === CURSOR_CLOUD_USAGE_FILENAME) {
|
|
8221
|
+
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
8222
|
+
}
|
|
8180
8223
|
if (path13.basename(sourceRoot) === "store.db") {
|
|
8181
8224
|
return [];
|
|
8182
8225
|
}
|
|
@@ -8214,6 +8257,7 @@ async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env) {
|
|
|
8214
8257
|
break;
|
|
8215
8258
|
}
|
|
8216
8259
|
files.push(...await collectCursorTranscriptFiles(cursorProjectsDir(home, env), home, skipIds));
|
|
8260
|
+
files.push(...await cursorCloudUsageBackfillFiles(home, options));
|
|
8217
8261
|
return files;
|
|
8218
8262
|
}
|
|
8219
8263
|
function cursorHookConfig() {
|
|
@@ -8251,85 +8295,22 @@ function createCursorAdapter() {
|
|
|
8251
8295
|
return [
|
|
8252
8296
|
...cursorStateDbCandidates(home, env),
|
|
8253
8297
|
cursorProjectsDir(home, env),
|
|
8254
|
-
cursorChatsDir(home, env)
|
|
8298
|
+
cursorChatsDir(home, env),
|
|
8299
|
+
cursorCloudUsageCachePath(home)
|
|
8255
8300
|
];
|
|
8256
8301
|
},
|
|
8257
8302
|
parseSessionFile: parseCursorSessionFile
|
|
8258
8303
|
};
|
|
8259
8304
|
}
|
|
8260
8305
|
|
|
8261
|
-
// src/adapters/grok-bot.ts
|
|
8262
|
-
import { stat as stat9 } from "node:fs/promises";
|
|
8263
|
-
import os7 from "node:os";
|
|
8264
|
-
var SOURCE_ID2 = "grok-bot";
|
|
8265
|
-
var AGENT_NAME2 = "grok-bot";
|
|
8266
|
-
var IDENTITY = { source: SOURCE_ID2, agent: AGENT_NAME2 };
|
|
8267
|
-
async function grokBotBackfillFiles(sourceRoot, home = os7.homedir(), _env, options) {
|
|
8268
|
-
if (sourceRoot) {
|
|
8269
|
-
const info = await stat9(sourceRoot).catch(() => null);
|
|
8270
|
-
return info ? [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }] : [];
|
|
8271
|
-
}
|
|
8272
|
-
if (!options) {
|
|
8273
|
-
return [];
|
|
8274
|
-
}
|
|
8275
|
-
const cachePath = cursorCloudUsageCachePath(home);
|
|
8276
|
-
const map = await loadCursorCloudUsageMap(options);
|
|
8277
|
-
if (map.size === 0) {
|
|
8278
|
-
const info = await stat9(cachePath).catch(() => null);
|
|
8279
|
-
return info ? [{ path: cachePath, modifiedAt: info.mtime.toISOString() }] : [];
|
|
8280
|
-
}
|
|
8281
|
-
const sessions = [];
|
|
8282
|
-
for (const [conversationId, events] of map) {
|
|
8283
|
-
const session = cloudAgentSessionFromEvents(conversationId, events);
|
|
8284
|
-
if (session) {
|
|
8285
|
-
sessions.push(session);
|
|
8286
|
-
}
|
|
8287
|
-
}
|
|
8288
|
-
if (sessions.length === 0) {
|
|
8289
|
-
return [];
|
|
8290
|
-
}
|
|
8291
|
-
return [{
|
|
8292
|
-
path: cachePath,
|
|
8293
|
-
modifiedAt: await writeCursorCloudUsageCache(cachePath, sessions)
|
|
8294
|
-
}];
|
|
8295
|
-
}
|
|
8296
|
-
function createGrokBotAdapter() {
|
|
8297
|
-
return {
|
|
8298
|
-
id: SOURCE_ID2,
|
|
8299
|
-
label: "Grok Bot",
|
|
8300
|
-
agentName: AGENT_NAME2,
|
|
8301
|
-
kind: "agent",
|
|
8302
|
-
// No hooks to install — data arrives via the Cursor dashboard API.
|
|
8303
|
-
// The cache file stands in as the detect/install marker.
|
|
8304
|
-
detectPath(home) {
|
|
8305
|
-
return cursorCloudUsageCachePath(home);
|
|
8306
|
-
},
|
|
8307
|
-
installedPath(home) {
|
|
8308
|
-
return cursorCloudUsageCachePath(home);
|
|
8309
|
-
},
|
|
8310
|
-
async isInstalled() {
|
|
8311
|
-
return false;
|
|
8312
|
-
},
|
|
8313
|
-
installEntries() {
|
|
8314
|
-
return [];
|
|
8315
|
-
},
|
|
8316
|
-
sourcePaths(home) {
|
|
8317
|
-
return [cursorCloudUsageCachePath(home)];
|
|
8318
|
-
},
|
|
8319
|
-
parseSessionFile(filePath, options) {
|
|
8320
|
-
return parseCursorCloudAgentFile(filePath, options, IDENTITY);
|
|
8321
|
-
}
|
|
8322
|
-
};
|
|
8323
|
-
}
|
|
8324
|
-
|
|
8325
8306
|
// src/adapters/grok-build.ts
|
|
8326
|
-
import { readdir as readdir7, readFile as readFile9, stat as
|
|
8307
|
+
import { readdir as readdir7, readFile as readFile9, stat as stat9 } from "node:fs/promises";
|
|
8327
8308
|
import path14 from "node:path";
|
|
8328
8309
|
init_fs();
|
|
8329
8310
|
var GROK_COST_TICKS_PER_USD = 1e9;
|
|
8330
|
-
var
|
|
8331
|
-
var
|
|
8332
|
-
var HOOK_COMMAND2 = `vibetime hook --agent ${
|
|
8311
|
+
var SOURCE_ID2 = "grok-build";
|
|
8312
|
+
var AGENT_NAME2 = "grok-build";
|
|
8313
|
+
var HOOK_COMMAND2 = `vibetime hook --agent ${SOURCE_ID2}`;
|
|
8333
8314
|
function grokHome(home, env) {
|
|
8334
8315
|
const override = env?.GROK_HOME;
|
|
8335
8316
|
if (override && override.trim()) {
|
|
@@ -8363,7 +8344,7 @@ async function grokBackfillFiles(sourceRoot, home, env) {
|
|
|
8363
8344
|
continue;
|
|
8364
8345
|
}
|
|
8365
8346
|
try {
|
|
8366
|
-
const info = await
|
|
8347
|
+
const info = await stat9(entryPath);
|
|
8367
8348
|
files.push({ path: entryPath, modifiedAt: info.mtime.toISOString() });
|
|
8368
8349
|
} catch {
|
|
8369
8350
|
}
|
|
@@ -8415,8 +8396,8 @@ async function parseGrokSessionFile(filePath, options) {
|
|
|
8415
8396
|
};
|
|
8416
8397
|
const base = (partial) => ({
|
|
8417
8398
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
8418
|
-
source:
|
|
8419
|
-
agent:
|
|
8399
|
+
source: SOURCE_ID2,
|
|
8400
|
+
agent: AGENT_NAME2,
|
|
8420
8401
|
workspaceId,
|
|
8421
8402
|
project,
|
|
8422
8403
|
cwd,
|
|
@@ -8976,7 +8957,7 @@ async function loadHunkFileActivities(hunkPath, cwd) {
|
|
|
8976
8957
|
}
|
|
8977
8958
|
return activities;
|
|
8978
8959
|
}
|
|
8979
|
-
var grokHandler = (msg) => hookHandler(
|
|
8960
|
+
var grokHandler = (msg) => hookHandler(SOURCE_ID2, msg);
|
|
8980
8961
|
function hookConfig5() {
|
|
8981
8962
|
const anyTool = [{ matcher: ".*", hooks: [grokHandler("Reporting tool activity")] }];
|
|
8982
8963
|
return {
|
|
@@ -8998,9 +8979,9 @@ function hookConfig5() {
|
|
|
8998
8979
|
}
|
|
8999
8980
|
function createGrokBuildAdapter() {
|
|
9000
8981
|
return {
|
|
9001
|
-
id:
|
|
8982
|
+
id: SOURCE_ID2,
|
|
9002
8983
|
label: "Grok Build",
|
|
9003
|
-
agentName:
|
|
8984
|
+
agentName: AGENT_NAME2,
|
|
9004
8985
|
kind: "agent",
|
|
9005
8986
|
detectPath(home, env) {
|
|
9006
8987
|
return grokHome(home, env);
|
|
@@ -9026,7 +9007,7 @@ function createGrokBuildAdapter() {
|
|
|
9026
9007
|
}
|
|
9027
9008
|
|
|
9028
9009
|
// src/adapters/hermes.ts
|
|
9029
|
-
import { readdir as readdir8, stat as
|
|
9010
|
+
import { readdir as readdir8, stat as stat10 } from "node:fs/promises";
|
|
9030
9011
|
import path15 from "node:path";
|
|
9031
9012
|
init_fs();
|
|
9032
9013
|
var SOURCE = "hermes";
|
|
@@ -9319,11 +9300,11 @@ function hermesToolAlias(tool) {
|
|
|
9319
9300
|
}
|
|
9320
9301
|
async function sqliteMtime(filePath) {
|
|
9321
9302
|
try {
|
|
9322
|
-
const info = await
|
|
9303
|
+
const info = await stat10(filePath);
|
|
9323
9304
|
let modifiedMs = info.mtimeMs;
|
|
9324
9305
|
for (const suffix of ["-wal", "-shm"]) {
|
|
9325
9306
|
try {
|
|
9326
|
-
const sidecar = await
|
|
9307
|
+
const sidecar = await stat10(`${filePath}${suffix}`);
|
|
9327
9308
|
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
9328
9309
|
} catch {
|
|
9329
9310
|
}
|
|
@@ -10616,7 +10597,7 @@ function createKimiCodeAdapter() {
|
|
|
10616
10597
|
}
|
|
10617
10598
|
|
|
10618
10599
|
// src/adapters/opencode.ts
|
|
10619
|
-
import
|
|
10600
|
+
import os7 from "node:os";
|
|
10620
10601
|
import path17 from "node:path";
|
|
10621
10602
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
10622
10603
|
const { DatabaseSync } = await import("node:sqlite");
|
|
@@ -11071,20 +11052,20 @@ function opencodeDataCandidates(home, env) {
|
|
|
11071
11052
|
const primary = xdgData && xdgData.trim() ? path17.join(path17.resolve(xdgData), "opencode", "opencode.db") : path17.join(home, ".local", "share", "opencode", "opencode.db");
|
|
11072
11053
|
return [primary, path17.join(home, ".opencode", "opencode.db")];
|
|
11073
11054
|
}
|
|
11074
|
-
async function opencodeBackfillFiles(sourceRoot, home =
|
|
11075
|
-
const { stat:
|
|
11055
|
+
async function opencodeBackfillFiles(sourceRoot, home = os7.homedir(), env) {
|
|
11056
|
+
const { stat: stat18 } = await import("node:fs/promises");
|
|
11076
11057
|
if (sourceRoot) {
|
|
11077
11058
|
if (!sourceRoot.endsWith(".db")) {
|
|
11078
11059
|
return [];
|
|
11079
11060
|
}
|
|
11080
|
-
const info = await
|
|
11061
|
+
const info = await stat18(sourceRoot).catch(() => null);
|
|
11081
11062
|
if (!info) {
|
|
11082
11063
|
return [];
|
|
11083
11064
|
}
|
|
11084
11065
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
11085
11066
|
}
|
|
11086
11067
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
11087
|
-
const info = await
|
|
11068
|
+
const info = await stat18(candidatePath).catch(() => null);
|
|
11088
11069
|
if (info) {
|
|
11089
11070
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
11090
11071
|
}
|
|
@@ -11184,8 +11165,8 @@ function createOpenCodeAdapter() {
|
|
|
11184
11165
|
}
|
|
11185
11166
|
|
|
11186
11167
|
// src/adapters/pi.ts
|
|
11187
|
-
import { readdir as readdir9, readFile as readFile11, stat as
|
|
11188
|
-
import
|
|
11168
|
+
import { readdir as readdir9, readFile as readFile11, stat as stat11 } from "node:fs/promises";
|
|
11169
|
+
import os8 from "node:os";
|
|
11189
11170
|
import path18 from "node:path";
|
|
11190
11171
|
init_fs();
|
|
11191
11172
|
function piHostSessionIdFromBasename(basename) {
|
|
@@ -11596,7 +11577,7 @@ async function parsePiWorkflowRunFile(filePath, options) {
|
|
|
11596
11577
|
return state.events.filter((event) => matchesBackfillFilters(event, options));
|
|
11597
11578
|
}
|
|
11598
11579
|
async function findPiSessionFileById(sessionId, options) {
|
|
11599
|
-
const sessionsDir = piSessionDir(path18.resolve(stringOption(options.home) ||
|
|
11580
|
+
const sessionsDir = piSessionDir(path18.resolve(stringOption(options.home) || os8.homedir()));
|
|
11600
11581
|
try {
|
|
11601
11582
|
const projectDirs = await readdir9(sessionsDir, { withFileTypes: true });
|
|
11602
11583
|
for (const dir of projectDirs) {
|
|
@@ -11873,14 +11854,14 @@ async function workflowRunGroupId(filePath) {
|
|
|
11873
11854
|
return void 0;
|
|
11874
11855
|
}
|
|
11875
11856
|
}
|
|
11876
|
-
async function piBackfillFiles(sourceRoot, home =
|
|
11857
|
+
async function piBackfillFiles(sourceRoot, home = os8.homedir(), env) {
|
|
11877
11858
|
const lists = sourceRoot ? [await listFilesByExtensions(sourceRoot, [".jsonl", ".json"])] : await Promise.all([
|
|
11878
11859
|
listFilesByExtensions(piSessionDir(home, env), [".jsonl"]),
|
|
11879
11860
|
listFilesByExtensions(piWorkflowProjectsDir(home), [".json"])
|
|
11880
11861
|
]);
|
|
11881
11862
|
const files = lists.flat().sort();
|
|
11882
11863
|
return Promise.all(files.map(async (filePath) => {
|
|
11883
|
-
const info = await
|
|
11864
|
+
const info = await stat11(filePath);
|
|
11884
11865
|
let groupId = resolvePiBackfillGroupId(filePath);
|
|
11885
11866
|
if (!groupId && filePath.endsWith(".json")) {
|
|
11886
11867
|
groupId = await workflowRunGroupId(filePath);
|
|
@@ -11927,13 +11908,13 @@ function createPiAdapter() {
|
|
|
11927
11908
|
}
|
|
11928
11909
|
|
|
11929
11910
|
// src/adapters/qoder-cn.ts
|
|
11930
|
-
import { readdir as readdir10, readFile as readFile12, stat as
|
|
11931
|
-
import
|
|
11911
|
+
import { readdir as readdir10, readFile as readFile12, stat as stat12 } from "node:fs/promises";
|
|
11912
|
+
import os10 from "node:os";
|
|
11932
11913
|
import path20 from "node:path";
|
|
11933
11914
|
|
|
11934
11915
|
// src/adapters/qoder-local-db.ts
|
|
11935
11916
|
import { access } from "node:fs/promises";
|
|
11936
|
-
import
|
|
11917
|
+
import os9 from "node:os";
|
|
11937
11918
|
import path19 from "node:path";
|
|
11938
11919
|
function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
11939
11920
|
if (requestId) {
|
|
@@ -11951,7 +11932,7 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
|
11951
11932
|
}
|
|
11952
11933
|
return calls.ordered.shift();
|
|
11953
11934
|
}
|
|
11954
|
-
function appDataRoot(appDirName, home =
|
|
11935
|
+
function appDataRoot(appDirName, home = os9.homedir()) {
|
|
11955
11936
|
if (process.platform === "darwin") {
|
|
11956
11937
|
return path19.join(home, "Library", "Application Support", appDirName);
|
|
11957
11938
|
}
|
|
@@ -12260,7 +12241,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
12260
12241
|
let cwd;
|
|
12261
12242
|
let project = projectContext.project;
|
|
12262
12243
|
let model;
|
|
12263
|
-
const home = path20.resolve(stringOption(options.home) ||
|
|
12244
|
+
const home = path20.resolve(stringOption(options.home) || os10.homedir());
|
|
12264
12245
|
const modelMap = await loadQoderCnModelNames(configDir2, home);
|
|
12265
12246
|
const isSubagentSession = filePath.includes("subagents");
|
|
12266
12247
|
const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
|
|
@@ -12830,7 +12811,7 @@ async function gitRootFromCwds2(cwds) {
|
|
|
12830
12811
|
while (!seen.has(current)) {
|
|
12831
12812
|
seen.add(current);
|
|
12832
12813
|
try {
|
|
12833
|
-
await
|
|
12814
|
+
await stat12(path20.join(current, ".git"));
|
|
12834
12815
|
return current;
|
|
12835
12816
|
} catch {
|
|
12836
12817
|
}
|
|
@@ -12864,7 +12845,7 @@ function encodeQoderCnProjectPath(value) {
|
|
|
12864
12845
|
}
|
|
12865
12846
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
12866
12847
|
const projectDir = path20.basename(path20.dirname(filePath));
|
|
12867
|
-
const home = options ? path20.resolve(stringOption(options.home) ||
|
|
12848
|
+
const home = options ? path20.resolve(stringOption(options.home) || os10.homedir()) : os10.homedir();
|
|
12868
12849
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
12869
12850
|
if (resolved) {
|
|
12870
12851
|
return path20.basename(resolved);
|
|
@@ -12980,8 +12961,8 @@ function createQoderCnAdapter() {
|
|
|
12980
12961
|
|
|
12981
12962
|
// src/adapters/qoder.ts
|
|
12982
12963
|
import { existsSync } from "node:fs";
|
|
12983
|
-
import { readdir as readdir11, readFile as readFile13, stat as
|
|
12984
|
-
import
|
|
12964
|
+
import { readdir as readdir11, readFile as readFile13, stat as stat13 } from "node:fs/promises";
|
|
12965
|
+
import os11 from "node:os";
|
|
12985
12966
|
import path21 from "node:path";
|
|
12986
12967
|
function parseQoderPaths(filePath) {
|
|
12987
12968
|
const parts = filePath.split(path21.sep);
|
|
@@ -13146,7 +13127,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
13146
13127
|
let cwd;
|
|
13147
13128
|
let project = projectContext.project;
|
|
13148
13129
|
let model;
|
|
13149
|
-
const home = path21.resolve(stringOption(options.home) ||
|
|
13130
|
+
const home = path21.resolve(stringOption(options.home) || os11.homedir());
|
|
13150
13131
|
const modelMap = await loadQoderModelNames(configDir2, home);
|
|
13151
13132
|
const qwenworkRoot = isQwenworkConfigRoot(configDir2);
|
|
13152
13133
|
const isSubagentSession = filePath.includes("subagents");
|
|
@@ -13682,7 +13663,7 @@ async function gitRootFromCwds3(cwds) {
|
|
|
13682
13663
|
while (!seen.has(current)) {
|
|
13683
13664
|
seen.add(current);
|
|
13684
13665
|
try {
|
|
13685
|
-
await
|
|
13666
|
+
await stat13(path21.join(current, ".git"));
|
|
13686
13667
|
return current;
|
|
13687
13668
|
} catch {
|
|
13688
13669
|
}
|
|
@@ -13734,7 +13715,7 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
13734
13715
|
}
|
|
13735
13716
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
13736
13717
|
const projectDir = path21.basename(path21.dirname(filePath));
|
|
13737
|
-
const home = options ? path21.resolve(stringOption(options.home) ||
|
|
13718
|
+
const home = options ? path21.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
|
|
13738
13719
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
13739
13720
|
if (resolved) {
|
|
13740
13721
|
return path21.basename(resolved);
|
|
@@ -13886,11 +13867,14 @@ function normalizeId(id) {
|
|
|
13886
13867
|
if (id === "claude") {
|
|
13887
13868
|
return "claude-code";
|
|
13888
13869
|
}
|
|
13870
|
+
if (id === "grok-bot") {
|
|
13871
|
+
return "cursor";
|
|
13872
|
+
}
|
|
13889
13873
|
return id;
|
|
13890
13874
|
}
|
|
13891
13875
|
|
|
13892
13876
|
// src/adapters/workbuddy.ts
|
|
13893
|
-
import { readdir as readdir12, readFile as readFile14, stat as
|
|
13877
|
+
import { readdir as readdir12, readFile as readFile14, stat as stat14 } from "node:fs/promises";
|
|
13894
13878
|
import path22 from "node:path";
|
|
13895
13879
|
function workbuddyProjectsDir(home, env) {
|
|
13896
13880
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
@@ -14343,7 +14327,7 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
14343
14327
|
for (const entry of entries) {
|
|
14344
14328
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
14345
14329
|
const filePath = path22.join(projectDir, entry.name);
|
|
14346
|
-
const info = await
|
|
14330
|
+
const info = await stat14(filePath);
|
|
14347
14331
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
14348
14332
|
}
|
|
14349
14333
|
}
|
|
@@ -14404,7 +14388,7 @@ function createWorkbuddyAdapter() {
|
|
|
14404
14388
|
|
|
14405
14389
|
// src/adapters/zcode.ts
|
|
14406
14390
|
import { execFile } from "node:child_process";
|
|
14407
|
-
import { readFile as readFile15, stat as
|
|
14391
|
+
import { readFile as readFile15, stat as stat15 } from "node:fs/promises";
|
|
14408
14392
|
import path23 from "node:path";
|
|
14409
14393
|
import { promisify as promisify2 } from "node:util";
|
|
14410
14394
|
var execFileAsync = promisify2(execFile);
|
|
@@ -14443,7 +14427,7 @@ var providerNameCache = null;
|
|
|
14443
14427
|
async function loadProviderNames(configPath2) {
|
|
14444
14428
|
let fileMtime = 0;
|
|
14445
14429
|
try {
|
|
14446
|
-
const info = await
|
|
14430
|
+
const info = await stat15(configPath2);
|
|
14447
14431
|
fileMtime = info.mtimeMs;
|
|
14448
14432
|
} catch {
|
|
14449
14433
|
return /* @__PURE__ */ new Map();
|
|
@@ -14671,7 +14655,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
14671
14655
|
for (let i = 0; i < 12; i++) {
|
|
14672
14656
|
const probe = path23.join(candidate, ".zcode", "v2", "config.json");
|
|
14673
14657
|
try {
|
|
14674
|
-
await
|
|
14658
|
+
await stat15(probe);
|
|
14675
14659
|
configPath2 = probe;
|
|
14676
14660
|
break;
|
|
14677
14661
|
} catch {
|
|
@@ -14905,11 +14889,11 @@ async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
|
14905
14889
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
14906
14890
|
const filePath = candidate.endsWith(".sqlite") ? candidate : path23.join(candidate, "db", "db.sqlite");
|
|
14907
14891
|
try {
|
|
14908
|
-
const info = await
|
|
14892
|
+
const info = await stat15(filePath);
|
|
14909
14893
|
let modifiedMs = info.mtimeMs;
|
|
14910
14894
|
for (const suffix of ["-wal", "-shm"]) {
|
|
14911
14895
|
try {
|
|
14912
|
-
const sidecar = await
|
|
14896
|
+
const sidecar = await stat15(`${filePath}${suffix}`);
|
|
14913
14897
|
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
14914
14898
|
} catch {
|
|
14915
14899
|
}
|
|
@@ -14952,7 +14936,7 @@ function createZCodeAdapter() {
|
|
|
14952
14936
|
}
|
|
14953
14937
|
|
|
14954
14938
|
// src/adapters/zed.ts
|
|
14955
|
-
import
|
|
14939
|
+
import os12 from "node:os";
|
|
14956
14940
|
import path24 from "node:path";
|
|
14957
14941
|
function zedThreadsCandidates(home, env) {
|
|
14958
14942
|
const candidates = [];
|
|
@@ -15304,20 +15288,20 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
15304
15288
|
}
|
|
15305
15289
|
return events.filter((event) => matchesBackfillFilters(event, options));
|
|
15306
15290
|
}
|
|
15307
|
-
async function zedBackfillFiles(sourceRoot, home =
|
|
15308
|
-
const { stat:
|
|
15291
|
+
async function zedBackfillFiles(sourceRoot, home = os12.homedir(), env) {
|
|
15292
|
+
const { stat: stat18 } = await import("node:fs/promises");
|
|
15309
15293
|
if (sourceRoot) {
|
|
15310
15294
|
if (!sourceRoot.endsWith(".db")) {
|
|
15311
15295
|
return [];
|
|
15312
15296
|
}
|
|
15313
|
-
const info = await
|
|
15297
|
+
const info = await stat18(sourceRoot).catch(() => null);
|
|
15314
15298
|
if (!info) {
|
|
15315
15299
|
return [];
|
|
15316
15300
|
}
|
|
15317
15301
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
15318
15302
|
}
|
|
15319
15303
|
for (const candidatePath of zedThreadsCandidates(home, env)) {
|
|
15320
|
-
const info = await
|
|
15304
|
+
const info = await stat18(candidatePath).catch(() => null);
|
|
15321
15305
|
if (info) {
|
|
15322
15306
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
15323
15307
|
}
|
|
@@ -16208,7 +16192,7 @@ function defaultMachineName() {
|
|
|
16208
16192
|
init_fs();
|
|
16209
16193
|
|
|
16210
16194
|
// src/lib/logger.ts
|
|
16211
|
-
import { appendFile, mkdir as mkdir5, rename as rename2, stat as
|
|
16195
|
+
import { appendFile, mkdir as mkdir5, rename as rename2, stat as stat16 } from "node:fs/promises";
|
|
16212
16196
|
import { homedir as homedir2 } from "node:os";
|
|
16213
16197
|
import path26 from "node:path";
|
|
16214
16198
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
@@ -16226,7 +16210,7 @@ function serializeError(error) {
|
|
|
16226
16210
|
}
|
|
16227
16211
|
async function rotateIfNeeded(file) {
|
|
16228
16212
|
try {
|
|
16229
|
-
const info = await
|
|
16213
|
+
const info = await stat16(file);
|
|
16230
16214
|
if (info.size > MAX_BYTES) {
|
|
16231
16215
|
await rename2(file, `${file}.1`).catch(() => {
|
|
16232
16216
|
});
|
|
@@ -16462,7 +16446,7 @@ async function deleteMachine(remote, id) {
|
|
|
16462
16446
|
}
|
|
16463
16447
|
|
|
16464
16448
|
// src/lib/types.ts
|
|
16465
|
-
var BACKFILL_STATE_SCHEMA_VERSION =
|
|
16449
|
+
var BACKFILL_STATE_SCHEMA_VERSION = 11;
|
|
16466
16450
|
|
|
16467
16451
|
// src/cli.ts
|
|
16468
16452
|
function createRegistry() {
|
|
@@ -16483,7 +16467,6 @@ function createRegistry() {
|
|
|
16483
16467
|
registry.register(createZedAdapter());
|
|
16484
16468
|
registry.register(createKimiCodeAdapter());
|
|
16485
16469
|
registry.register(createCursorAdapter());
|
|
16486
|
-
registry.register(createGrokBotAdapter());
|
|
16487
16470
|
registry.register(createHermesAdapter());
|
|
16488
16471
|
return registry;
|
|
16489
16472
|
}
|
|
@@ -17044,10 +17027,14 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
17044
17027
|
return zedBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
17045
17028
|
}
|
|
17046
17029
|
if (source.id === "cursor") {
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
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
|
+
);
|
|
17051
17038
|
}
|
|
17052
17039
|
if (source.id === "hermes") {
|
|
17053
17040
|
return hermesBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
@@ -17059,7 +17046,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
17059
17046
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
17060
17047
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
17061
17048
|
return Promise.all(files.map(async (filePath) => {
|
|
17062
|
-
const info = await
|
|
17049
|
+
const info = await stat17(filePath);
|
|
17063
17050
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
17064
17051
|
}));
|
|
17065
17052
|
}
|
|
@@ -17310,20 +17297,36 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
|
|
|
17310
17297
|
machine,
|
|
17311
17298
|
allowHistoricalRewrite: options.force === true
|
|
17312
17299
|
});
|
|
17313
|
-
if (
|
|
17314
|
-
|
|
17315
|
-
for (const
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
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}
|
|
17323
17311
|
`);
|
|
17312
|
+
}
|
|
17324
17313
|
}
|
|
17325
17314
|
}
|
|
17326
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
|
+
}
|
|
17327
17330
|
}
|
|
17328
17331
|
return result;
|
|
17329
17332
|
}
|
|
@@ -17611,7 +17614,7 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
17611
17614
|
return [path27.resolve(path27.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
17612
17615
|
}
|
|
17613
17616
|
function resolveHome3(options, ctx) {
|
|
17614
|
-
return path27.resolve(stringOption(options.home) || ctx.env.HOME ||
|
|
17617
|
+
return path27.resolve(stringOption(options.home) || ctx.env.HOME || os13.homedir());
|
|
17615
17618
|
}
|
|
17616
17619
|
function requestedTargets(options) {
|
|
17617
17620
|
const value = options.target || options.targets;
|
|
@@ -17621,7 +17624,13 @@ function requestedTargets(options) {
|
|
|
17621
17624
|
return valuesOption(value).flatMap((item) => item.split(",")).map((t) => t.trim()).filter(Boolean);
|
|
17622
17625
|
}
|
|
17623
17626
|
function normalizeBackfillSource(source) {
|
|
17624
|
-
|
|
17627
|
+
if (source === "claude") {
|
|
17628
|
+
return "claude-code";
|
|
17629
|
+
}
|
|
17630
|
+
if (source === "grok-bot") {
|
|
17631
|
+
return "cursor";
|
|
17632
|
+
}
|
|
17633
|
+
return source;
|
|
17625
17634
|
}
|
|
17626
17635
|
function requiredOption(options, name) {
|
|
17627
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.
|
|
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": {
|