@yhong91/vibetime 0.1.56 → 0.1.58

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 +1764 -345
  2. package/package.json +2 -2
package/bin/vibetime.mjs CHANGED
@@ -884,9 +884,9 @@ 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 mkdir5, open, rm, stat as stat14, writeFile as writeFile4 } from "node:fs/promises";
888
- import os12 from "node:os";
889
- import path25 from "node:path";
887
+ import { mkdir as mkdir5, open, rm, stat as stat16, writeFile as writeFile4 } from "node:fs/promises";
888
+ import os13 from "node:os";
889
+ import path26 from "node:path";
890
890
  import { fileURLToPath } from "node:url";
891
891
 
892
892
  // ../shared/src/index.ts
@@ -924,7 +924,7 @@ var TELEMETRY_EVENT_TYPES = [
924
924
  "agent.operation"
925
925
  ];
926
926
  var FILE_ACTIVITY_OPERATIONS = ["read", "search", "create", "write", "edit", "delete"];
927
- var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode", "grok-build", "zed", "kimi-code"];
927
+ var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode", "grok-build", "zed", "kimi-code", "cursor"];
928
928
  function createWorkspaceId(input) {
929
929
  const basis = input.repoUrl || input.repoRoot || input.projectName || "unknown";
930
930
  return `workspace_${fnv1a(basis)}`;
@@ -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.56" : "0.1.1";
2050
+ var PACKAGE_VERSION = true ? "0.1.58" : "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;
@@ -5011,8 +5011,8 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
5011
5011
  }
5012
5012
  const filePath = path9.join(traceDir, entry);
5013
5013
  try {
5014
- const stat15 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
5015
- files.push({ path: filePath, modifiedAt: stat15.mtime.toISOString(), groupId: pidDir.name });
5014
+ const stat17 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
5015
+ files.push({ path: filePath, modifiedAt: stat17.mtime.toISOString(), groupId: pidDir.name });
5016
5016
  } catch {
5017
5017
  }
5018
5018
  }
@@ -5099,7 +5099,7 @@ function fileActivitiesFromPatchChanges(changes, ts, cwd, displayFilePath3) {
5099
5099
  }
5100
5100
 
5101
5101
  // src/lib/session-context.ts
5102
- import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
5102
+ import { mkdir as mkdir3, stat as stat6, writeFile as writeFile3 } from "node:fs/promises";
5103
5103
  import os4 from "node:os";
5104
5104
  import path10 from "node:path";
5105
5105
  init_fs();
@@ -5126,32 +5126,86 @@ async function readPersistedSessionContext(home, sessionId) {
5126
5126
  }
5127
5127
  const cwd = typeof raw.cwd === "string" && raw.cwd.length > 0 ? raw.cwd : void 0;
5128
5128
  const project = typeof raw.project === "string" && raw.project.length > 0 ? raw.project : void 0;
5129
- return { version: SESSION_CONTEXT_VERSION, sessionId, cwd, project, updatedAt: raw.updatedAt };
5129
+ const usage = Array.isArray(raw.usage) ? raw.usage.filter((item) => {
5130
+ return isPlainObject(item) && typeof item.generationId === "string" && item.generationId.length > 0 && typeof item.ts === "string";
5131
+ }) : void 0;
5132
+ return { version: SESSION_CONTEXT_VERSION, sessionId, cwd, project, updatedAt: raw.updatedAt, usage };
5130
5133
  }
5131
5134
  async function readPersistedSessionContextFromOptions(options, sessionId) {
5132
5135
  return readPersistedSessionContext(resolveHome2(options), sessionId);
5133
5136
  }
5137
+ async function persistedSessionContextModifiedAt(home, sessionId) {
5138
+ const info = await stat6(sessionContextPath(home, sessionId)).catch(() => null);
5139
+ return info?.isFile() ? info.mtime : void 0;
5140
+ }
5134
5141
  async function persistHookSessionContext(home, payload) {
5135
5142
  if (!isPlainObject(payload)) {
5136
5143
  return;
5137
5144
  }
5138
- const sessionId = typeof payload.session_id === "string" ? payload.session_id.trim() : typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
5139
- const cwd = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
5140
- if (!sessionId || !cwd || !path10.isAbsolute(cwd)) {
5145
+ const sessionId = hookSessionId(payload);
5146
+ const cwdRaw = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
5147
+ const cwd = cwdRaw && path10.isAbsolute(cwdRaw) ? cwdRaw : void 0;
5148
+ const usage = hookUsageFromPayload(payload);
5149
+ if (!sessionId || !cwd && !usage) {
5141
5150
  return;
5142
5151
  }
5143
- const project = path10.basename(cwd) || void 0;
5152
+ const existing = await readPersistedSessionContext(home, sessionId);
5153
+ const nextUsage = mergeHookUsage(existing?.usage, usage);
5154
+ const nextCwd = cwd || existing?.cwd;
5144
5155
  const context = {
5145
5156
  version: SESSION_CONTEXT_VERSION,
5146
5157
  sessionId,
5147
- cwd,
5148
- project,
5149
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5158
+ cwd: nextCwd,
5159
+ project: nextCwd ? path10.basename(nextCwd) : existing?.project,
5160
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
5161
+ usage: nextUsage
5150
5162
  };
5151
5163
  await mkdir3(sessionContextDir(home), { recursive: true });
5152
5164
  await writeFile3(sessionContextPath(home, sessionId), `${JSON.stringify(context, null, 2)}
5153
5165
  `, "utf8");
5154
5166
  }
5167
+ function hookSessionId(payload) {
5168
+ for (const key of ["session_id", "sessionId", "conversation_id", "conversationId"]) {
5169
+ const value = stringField(payload, key)?.trim();
5170
+ if (value) {
5171
+ return value;
5172
+ }
5173
+ }
5174
+ return "";
5175
+ }
5176
+ function hookUsageFromPayload(payload) {
5177
+ const nested = objectField(payload, "token_usage").inputTokens !== void 0 || objectField(payload, "tokenUsage").inputTokens !== void 0 ? { ...objectField(payload, "token_usage"), ...objectField(payload, "tokenUsage") } : payload;
5178
+ const tokensInput = numberField(nested, "input_tokens") ?? numberField(nested, "inputTokens") ?? numberField(payload, "input_tokens") ?? numberField(payload, "inputTokens");
5179
+ const tokensOutput = numberField(nested, "output_tokens") ?? numberField(nested, "outputTokens") ?? numberField(payload, "output_tokens") ?? numberField(payload, "outputTokens");
5180
+ const tokensCacheReadInput = numberField(nested, "cache_read_tokens") ?? numberField(nested, "cacheReadTokens") ?? numberField(payload, "cache_read_tokens") ?? numberField(payload, "cacheReadTokens");
5181
+ const tokensCacheCreationInput = numberField(nested, "cache_write_tokens") ?? numberField(nested, "cacheWriteTokens") ?? numberField(payload, "cache_write_tokens") ?? numberField(payload, "cacheWriteTokens");
5182
+ if (!tokensInput && !tokensOutput && !tokensCacheReadInput && !tokensCacheCreationInput) {
5183
+ return void 0;
5184
+ }
5185
+ const generationId = stringField(payload, "generation_id")?.trim() || stringField(payload, "generationId")?.trim() || stringField(payload, "request_id")?.trim() || stringField(payload, "requestId")?.trim() || `${tokensInput || 0}:${tokensOutput || 0}:${tokensCacheReadInput || 0}:${tokensCacheCreationInput || 0}`;
5186
+ return {
5187
+ generationId,
5188
+ ts: stringField(payload, "timestamp") || (/* @__PURE__ */ new Date()).toISOString(),
5189
+ model: stringField(payload, "model") || stringField(payload, "model_name"),
5190
+ tokensInput: tokensInput || void 0,
5191
+ tokensOutput: tokensOutput || void 0,
5192
+ tokensCacheReadInput: tokensCacheReadInput || void 0,
5193
+ tokensCacheCreationInput: tokensCacheCreationInput || void 0
5194
+ };
5195
+ }
5196
+ function mergeHookUsage(existing, next) {
5197
+ if (!next) {
5198
+ return existing;
5199
+ }
5200
+ const current = existing ? [...existing] : [];
5201
+ const index = current.findIndex((item) => item.generationId === next.generationId);
5202
+ if (index >= 0) {
5203
+ current[index] = next;
5204
+ } else {
5205
+ current.push(next);
5206
+ }
5207
+ return current;
5208
+ }
5155
5209
 
5156
5210
  // src/adapters/codex.ts
5157
5211
  async function parseCodexSessionFile(filePath, options) {
@@ -5841,7 +5895,7 @@ function createCodexAdapter() {
5841
5895
  }
5842
5896
 
5843
5897
  // src/adapters/copilot.ts
5844
- import { readdir as readdir5, readFile as readFile7, stat as stat6 } from "node:fs/promises";
5898
+ import { readdir as readdir5, readFile as readFile7, stat as stat7 } from "node:fs/promises";
5845
5899
  import os5 from "node:os";
5846
5900
  import path12 from "node:path";
5847
5901
  async function parseCopilotSessionFile(filePath, options) {
@@ -6168,95 +6222,1387 @@ function baseCopilotEvent(event) {
6168
6222
  ...event
6169
6223
  };
6170
6224
  }
6171
- async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
6172
- const sessionDir = sourceRoot || path12.join(home, ".copilot", "session-state");
6173
- const results = [];
6174
- let entries;
6175
- try {
6176
- entries = await readdir5(sessionDir);
6177
- } catch {
6178
- return [];
6225
+ async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
6226
+ const sessionDir = sourceRoot || path12.join(home, ".copilot", "session-state");
6227
+ const results = [];
6228
+ let entries;
6229
+ try {
6230
+ entries = await readdir5(sessionDir);
6231
+ } catch {
6232
+ return [];
6233
+ }
6234
+ for (const entry of entries) {
6235
+ if (entry.startsWith("pending-session")) {
6236
+ continue;
6237
+ }
6238
+ const eventsPath = path12.join(sessionDir, entry, "events.jsonl");
6239
+ const info = await stat7(eventsPath).catch(() => null);
6240
+ if (info) {
6241
+ results.push({ path: eventsPath, modifiedAt: info.mtime.toISOString() });
6242
+ }
6243
+ }
6244
+ return results;
6245
+ }
6246
+ function copilotPluginContent() {
6247
+ return `// Agent Time plugin for GitHub Copilot CLI
6248
+ // Generated by vibetime.
6249
+ // Copilot does not support hooks \u2014 this file is a placeholder for detection.
6250
+ // Backfill reads session data from ~/.copilot/session-state/*/events.jsonl.
6251
+ `;
6252
+ }
6253
+ function copilotHome(home, env) {
6254
+ const override = env?.COPILOT_HOME;
6255
+ if (override && override.trim()) {
6256
+ return path12.resolve(override);
6257
+ }
6258
+ return path12.join(home, ".copilot");
6259
+ }
6260
+ function createCopilotAdapter() {
6261
+ return {
6262
+ id: "copilot",
6263
+ label: "GitHub Copilot",
6264
+ agentName: "copilot",
6265
+ kind: "agent",
6266
+ detectPath(home, env) {
6267
+ return copilotHome(home, env);
6268
+ },
6269
+ installedPath(home, env) {
6270
+ return path12.join(copilotHome(home, env), ".vibetime");
6271
+ },
6272
+ async isInstalled(home, env) {
6273
+ try {
6274
+ const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
6275
+ return await pathExists2(path12.join(copilotHome(home, env), ".vibetime"));
6276
+ } catch {
6277
+ return false;
6278
+ }
6279
+ },
6280
+ installEntries(home, env) {
6281
+ return [{
6282
+ kind: "file",
6283
+ path: path12.join(copilotHome(home, env), ".vibetime"),
6284
+ content: copilotPluginContent()
6285
+ }];
6286
+ },
6287
+ sourcePaths(home, env) {
6288
+ return [path12.join(copilotHome(home, env), "session-state")];
6289
+ },
6290
+ parseSessionFile: parseCopilotSessionFile
6291
+ };
6292
+ }
6293
+
6294
+ // src/adapters/cursor.ts
6295
+ import { copyFile, readdir as readdir6, readFile as readFile8, stat as stat8 } from "node:fs/promises";
6296
+ import os6 from "node:os";
6297
+ import path13 from "node:path";
6298
+
6299
+ // src/lib/cursor-hooks.ts
6300
+ function isCursorHooksFile(value) {
6301
+ if (!isPlainObject(value)) {
6302
+ return false;
6303
+ }
6304
+ if (value.version !== 1 && value.version !== void 0) {
6305
+ return false;
6306
+ }
6307
+ return isPlainObject(value.hooks);
6308
+ }
6309
+ function hookCommandFromCursorEntry(entry) {
6310
+ if (!isPlainObject(entry) || typeof entry.command !== "string" || !entry.command) {
6311
+ return void 0;
6312
+ }
6313
+ return entry.command;
6314
+ }
6315
+ function hasCursorHookCommand(config, command) {
6316
+ if (!isCursorHooksFile(config)) {
6317
+ return false;
6318
+ }
6319
+ return Object.values(config.hooks).some(
6320
+ (entries) => Array.isArray(entries) && entries.some((entry) => hookCommandFromCursorEntry(entry) === command)
6321
+ );
6322
+ }
6323
+ function mergeCursorHooksJson(existing, addition) {
6324
+ const mergedHooks = {};
6325
+ const existingHooks = isCursorHooksFile(existing) ? existing.hooks : {};
6326
+ for (const [event, entries] of Object.entries(existingHooks)) {
6327
+ if (Array.isArray(entries)) {
6328
+ mergedHooks[event] = [...entries];
6329
+ }
6330
+ }
6331
+ for (const [event, entries] of Object.entries(addition.hooks)) {
6332
+ const current = mergedHooks[event] ? [...mergedHooks[event]] : [];
6333
+ for (const entry of entries) {
6334
+ const command = hookCommandFromCursorEntry(entry);
6335
+ if (!command) {
6336
+ continue;
6337
+ }
6338
+ const alreadyPresent = current.some(
6339
+ (existingEntry) => hookCommandFromCursorEntry(existingEntry) === command
6340
+ );
6341
+ if (!alreadyPresent) {
6342
+ current.push(entry);
6343
+ }
6344
+ }
6345
+ mergedHooks[event] = current;
6346
+ }
6347
+ const extra = isPlainObject(existing) ? Object.fromEntries(
6348
+ Object.entries(existing).filter(([key]) => key !== "version" && key !== "hooks")
6349
+ ) : {};
6350
+ return {
6351
+ ...extra,
6352
+ version: 1,
6353
+ hooks: mergedHooks
6354
+ };
6355
+ }
6356
+ function stripCursorHookCommands(existing, commands) {
6357
+ const next = structuredClone(isPlainObject(existing) ? existing : {});
6358
+ if (!isPlainObject(next.hooks)) {
6359
+ return { next, changed: false };
6360
+ }
6361
+ const hooks = { ...next.hooks };
6362
+ let changed = false;
6363
+ for (const [event, entries] of Object.entries(hooks)) {
6364
+ if (!Array.isArray(entries)) {
6365
+ continue;
6366
+ }
6367
+ const stripped = entries.filter((entry) => {
6368
+ const command = hookCommandFromCursorEntry(entry);
6369
+ return !command || !commands.has(command);
6370
+ });
6371
+ if (stripped.length !== entries.length) {
6372
+ changed = true;
6373
+ }
6374
+ if (stripped.length === 0) {
6375
+ delete hooks[event];
6376
+ } else {
6377
+ hooks[event] = stripped;
6378
+ }
6379
+ }
6380
+ if (Object.keys(hooks).length === 0) {
6381
+ delete next.hooks;
6382
+ changed = true;
6383
+ } else {
6384
+ next.hooks = hooks;
6385
+ }
6386
+ return { next, changed };
6387
+ }
6388
+ function collectCursorHookCommands(content) {
6389
+ const commands = /* @__PURE__ */ new Set();
6390
+ for (const entries of Object.values(content.hooks)) {
6391
+ for (const entry of entries) {
6392
+ const command = hookCommandFromCursorEntry(entry);
6393
+ if (command) {
6394
+ commands.add(command);
6395
+ }
6396
+ }
6397
+ }
6398
+ return [...commands];
6399
+ }
6400
+
6401
+ // src/adapters/cursor.ts
6402
+ init_fs();
6403
+ var SOURCE_ID = "cursor";
6404
+ var AGENT_NAME = "cursor";
6405
+ var HOOK_COMMAND = `vibetime hook --agent ${SOURCE_ID}`;
6406
+ var HOOK_TIMEOUT_SECONDS = 10;
6407
+ var BUBBLE_USER = 1;
6408
+ var CAPABILITY_TOOL = 15;
6409
+ var CURSOR_HOOK_EVENTS = [
6410
+ "sessionStart",
6411
+ "sessionEnd",
6412
+ "beforeSubmitPrompt",
6413
+ "preToolUse",
6414
+ "postToolUse",
6415
+ "postToolUseFailure",
6416
+ "subagentStart",
6417
+ "subagentStop",
6418
+ "stop",
6419
+ "afterAgentResponse",
6420
+ "afterFileEdit",
6421
+ "afterShellExecution",
6422
+ "preCompact"
6423
+ ];
6424
+ function cursorHome(home, env) {
6425
+ const override = env?.CURSOR_HOME;
6426
+ if (override && override.trim()) {
6427
+ return path13.resolve(override);
6428
+ }
6429
+ return path13.join(home, ".cursor");
6430
+ }
6431
+ function cursorHooksPath(home, env) {
6432
+ return path13.join(cursorHome(home, env), "hooks.json");
6433
+ }
6434
+ function cursorProjectsDir(home, env) {
6435
+ return path13.join(cursorHome(home, env), "projects");
6436
+ }
6437
+ function cursorChatsDir(home, env) {
6438
+ return path13.join(cursorHome(home, env), "chats");
6439
+ }
6440
+ function cursorUserDir(home, env) {
6441
+ const override = env?.CURSOR_USER_DIR;
6442
+ if (override && override.trim()) {
6443
+ return path13.resolve(override);
6444
+ }
6445
+ return void 0;
6446
+ }
6447
+ function cursorStateDbCandidates(home, env) {
6448
+ const candidates = [];
6449
+ const userDir = cursorUserDir(home, env);
6450
+ if (userDir) {
6451
+ candidates.push(path13.join(userDir, "globalStorage", "state.vscdb"));
6452
+ }
6453
+ const platform2 = process.platform;
6454
+ if (platform2 === "darwin") {
6455
+ candidates.push(path13.join(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb"));
6456
+ } else if (platform2 === "win32") {
6457
+ const appdata = env?.APPDATA;
6458
+ if (appdata && appdata.trim()) {
6459
+ candidates.push(path13.join(path13.resolve(appdata), "Cursor", "User", "globalStorage", "state.vscdb"));
6460
+ }
6461
+ candidates.push(path13.join(home, "AppData", "Roaming", "Cursor", "User", "globalStorage", "state.vscdb"));
6462
+ } else {
6463
+ const xdgConfig = env?.XDG_CONFIG_HOME;
6464
+ if (xdgConfig && xdgConfig.trim()) {
6465
+ candidates.push(path13.join(path13.resolve(xdgConfig), "Cursor", "User", "globalStorage", "state.vscdb"));
6466
+ }
6467
+ candidates.push(path13.join(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb"));
6468
+ }
6469
+ return candidates;
6470
+ }
6471
+ function decodeKv(value) {
6472
+ if (typeof value === "string") {
6473
+ return value;
6474
+ }
6475
+ if (value instanceof Uint8Array) {
6476
+ return new TextDecoder().decode(value);
6477
+ }
6478
+ return void 0;
6479
+ }
6480
+ function parseJsonObject(text) {
6481
+ if (!text) {
6482
+ return void 0;
6483
+ }
6484
+ try {
6485
+ const parsed = JSON.parse(text);
6486
+ return isPlainObject(parsed) ? parsed : void 0;
6487
+ } catch {
6488
+ return void 0;
6489
+ }
6490
+ }
6491
+ function parseMaybeJsonObject(value) {
6492
+ if (isPlainObject(value)) {
6493
+ return value;
6494
+ }
6495
+ if (typeof value === "string") {
6496
+ return parseJsonObject(value) || {};
6497
+ }
6498
+ return {};
6499
+ }
6500
+ function cleanId(value) {
6501
+ return value.replace(/\s+/g, "_").slice(0, 200);
6502
+ }
6503
+ async function openCursorDb(dbPath) {
6504
+ const { DatabaseSync } = await import("node:sqlite");
6505
+ try {
6506
+ return {
6507
+ db: new DatabaseSync(dbPath, { readOnly: true }),
6508
+ cleanup: async () => {
6509
+ }
6510
+ };
6511
+ } catch {
6512
+ const tmp = path13.join(os6.tmpdir(), `vibetime-cursor-${createStableHash(dbPath).slice(0, 12)}.db`);
6513
+ await copyFile(dbPath, tmp);
6514
+ for (const suffix of ["-wal", "-shm"]) {
6515
+ await copyFile(`${dbPath}${suffix}`, `${tmp}${suffix}`).catch(() => void 0);
6516
+ }
6517
+ return {
6518
+ db: new DatabaseSync(tmp, { readOnly: true }),
6519
+ cleanup: async () => {
6520
+ const { unlink } = await import("node:fs/promises");
6521
+ await unlink(tmp).catch(() => void 0);
6522
+ await unlink(`${tmp}-wal`).catch(() => void 0);
6523
+ await unlink(`${tmp}-shm`).catch(() => void 0);
6524
+ }
6525
+ };
6526
+ }
6527
+ }
6528
+ function listComposers(db) {
6529
+ const dataById = /* @__PURE__ */ new Map();
6530
+ const dataRows = db.prepare(
6531
+ "SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'"
6532
+ ).all();
6533
+ for (const row of dataRows) {
6534
+ const id = row.key.slice("composerData:".length);
6535
+ const data = parseJsonObject(decodeKv(row.value));
6536
+ if (id && data) {
6537
+ dataById.set(id, data);
6538
+ }
6539
+ }
6540
+ let headers = [];
6541
+ try {
6542
+ headers = db.prepare(
6543
+ "SELECT composerId, createdAt, lastUpdatedAt, isSubagent, value FROM composerHeaders"
6544
+ ).all();
6545
+ } catch {
6546
+ headers = [...dataById.entries()].map(([composerId, data]) => ({
6547
+ composerId,
6548
+ createdAt: numberField(data, "createdAt"),
6549
+ lastUpdatedAt: numberField(data, "lastUpdatedAt"),
6550
+ isSubagent: data.isBestOfNSubcomposer || data.isSubagent ? 1 : 0,
6551
+ value: JSON.stringify(data)
6552
+ }));
6553
+ }
6554
+ const composers = [];
6555
+ for (const headerRow of headers) {
6556
+ const composerId = headerRow.composerId;
6557
+ if (!composerId || composerId === "empty-state-draft") {
6558
+ continue;
6559
+ }
6560
+ const header = parseJsonObject(decodeKv(headerRow.value)) || parseMaybeJsonObject(headerRow.value);
6561
+ const data = dataById.get(composerId) || header;
6562
+ if (data.isDraft === true || data.isEphemeral === true || header.isDraft === true || header.isEphemeral === true) {
6563
+ continue;
6564
+ }
6565
+ composers.push({
6566
+ composerId,
6567
+ createdAt: headerRow.createdAt ?? numberField(data, "createdAt") ?? numberField(header, "createdAt"),
6568
+ lastUpdatedAt: headerRow.lastUpdatedAt ?? numberField(data, "lastUpdatedAt") ?? numberField(header, "lastUpdatedAt"),
6569
+ isSubagent: Boolean(headerRow.isSubagent) || data.isBestOfNSubcomposer === true,
6570
+ header,
6571
+ data
6572
+ });
6573
+ }
6574
+ return composers;
6575
+ }
6576
+ function loadBubbles(db, composerId) {
6577
+ const rows = db.prepare(
6578
+ "SELECT key, value FROM cursorDiskKV WHERE key LIKE ?"
6579
+ ).all(`bubbleId:${composerId}:%`);
6580
+ const bubbles = [];
6581
+ for (const row of rows) {
6582
+ const bubble = parseJsonObject(decodeKv(row.value));
6583
+ if (bubble) {
6584
+ bubbles.push(bubble);
6585
+ }
6586
+ }
6587
+ bubbles.sort((a, b) => {
6588
+ const aTs = stringField(a, "createdAt") || "";
6589
+ const bTs = stringField(b, "createdAt") || "";
6590
+ return aTs.localeCompare(bTs);
6591
+ });
6592
+ return bubbles;
6593
+ }
6594
+ function workspaceFromComposer(data) {
6595
+ const ident = objectField(data, "workspaceIdentifier");
6596
+ const uri = objectField(ident, "uri");
6597
+ const cwd = stringField(uri, "fsPath") || stringField(uri, "path");
6598
+ return {
6599
+ cwd,
6600
+ project: cwd ? path13.basename(cwd) : void 0
6601
+ };
6602
+ }
6603
+ function modelFromComposer(data) {
6604
+ const config = objectField(data, "modelConfig");
6605
+ return stringField(config, "modelName") || stringField(config, "modelId");
6606
+ }
6607
+ function bubbleTs(bubble, fallback) {
6608
+ return timestampFrom(bubble.createdAt) || stringField(bubble, "createdAt") || fallback;
6609
+ }
6610
+ function toolNameOf(raw) {
6611
+ if (!raw) {
6612
+ return "unknown";
6613
+ }
6614
+ return raw.replace(/_v\d+$/i, "");
6615
+ }
6616
+ function isShellTool(name) {
6617
+ const lower = name.toLowerCase();
6618
+ return lower === "shell" || lower === "bash" || lower === "run_terminal_cmd" || lower === "run_terminal_command";
6619
+ }
6620
+ function fileActivitiesFromCursorTool(toolName, input, ts, cwd) {
6621
+ const lower = toolName.toLowerCase();
6622
+ if (isShellTool(toolName)) {
6623
+ const command = stringField(input, "command") || stringField(input, "cmd");
6624
+ if (command) {
6625
+ return fileActivitiesFromShellCommand(command, ts, cwd, cwd);
6626
+ }
6627
+ return [];
6628
+ }
6629
+ const target = stringField(input, "path") || stringField(input, "targetFile") || stringField(input, "target_file") || stringField(input, "file_path") || stringField(input, "filePath");
6630
+ const display = target ? displayFilePath(target, cwd) : void 0;
6631
+ if (lower === "read" || lower === "read_file" || lower === "readfile") {
6632
+ if (!display) {
6633
+ return [];
6634
+ }
6635
+ return [{ ts, path: display, operation: "read", confidence: "exact" }];
6636
+ }
6637
+ if (lower === "grep" || lower === "grep_search" || lower === "ripgrep" || lower === "glob" || lower === "glob_file_search" || lower === "globfilesearch") {
6638
+ if (!display) {
6639
+ return [];
6640
+ }
6641
+ return [{ ts, path: display, operation: "search", confidence: "exact" }];
6642
+ }
6643
+ if (lower === "delete" || lower === "delete_file") {
6644
+ if (!display) {
6645
+ return [];
6646
+ }
6647
+ return [{ ts, path: display, operation: "delete", confidence: "exact" }];
6648
+ }
6649
+ if (lower === "write" || lower === "write_file") {
6650
+ if (!display) {
6651
+ return [];
6652
+ }
6653
+ const content = stringField(input, "contents") || stringField(input, "content");
6654
+ return [{
6655
+ ts,
6656
+ path: display,
6657
+ operation: "write",
6658
+ confidence: "exact",
6659
+ linesAdded: countTextLines(content),
6660
+ charsWritten: content?.length
6661
+ }];
6662
+ }
6663
+ if (lower === "search_replace" || lower === "strreplace" || lower === "edit" || lower === "edit_file" || lower === "apply_patch" || lower === "applypatch") {
6664
+ if (!display) {
6665
+ return [];
6666
+ }
6667
+ const oldString = stringField(input, "old_string") || stringField(input, "oldString") || stringField(input, "old_str");
6668
+ const newString = stringField(input, "new_string") || stringField(input, "newString") || stringField(input, "new_str") || stringField(input, "contents") || stringField(input, "content");
6669
+ return [{
6670
+ ts,
6671
+ path: display,
6672
+ operation: "edit",
6673
+ confidence: "exact",
6674
+ linesAdded: countTextLines(newString),
6675
+ linesRemoved: countTextLines(oldString),
6676
+ charsWritten: newString?.length
6677
+ }];
6678
+ }
6679
+ return [];
6680
+ }
6681
+ function usageMetrics(tokenCount) {
6682
+ const inputTokens = numberField(tokenCount, "inputTokens") || 0;
6683
+ const outputTokens = numberField(tokenCount, "outputTokens") || 0;
6684
+ const cached = numberField(tokenCount, "cacheReadTokens") || numberField(tokenCount, "cachedInputTokens") || 0;
6685
+ const cacheCreation = numberField(tokenCount, "cacheWriteTokens") || numberField(tokenCount, "cacheCreationTokens") || 0;
6686
+ if (inputTokens <= 0 && outputTokens <= 0 && cached <= 0 && cacheCreation <= 0) {
6687
+ return void 0;
6688
+ }
6689
+ return {
6690
+ tokensInput: inputTokens || void 0,
6691
+ tokensOutput: outputTokens || void 0,
6692
+ tokensCachedInput: cached + cacheCreation || void 0,
6693
+ tokensCacheReadInput: cached || void 0,
6694
+ tokensCacheCreationInput: cacheCreation || void 0,
6695
+ tokensTotal: inputTokens + outputTokens || void 0,
6696
+ modelCalls: 1
6697
+ };
6698
+ }
6699
+ var CURSOR_TIMESTAMP_RE = /<timestamp>\s*([^<]+?)\s*<\/timestamp>/i;
6700
+ var CURSOR_USER_QUERY_RE = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/i;
6701
+ var chatMetaIndexCache = /* @__PURE__ */ new Map();
6702
+ function isCursorTranscriptPath(filePath) {
6703
+ return filePath.split(path13.sep).includes("agent-transcripts") && filePath.endsWith(".jsonl");
6704
+ }
6705
+ function cursorHomeFromTranscript(filePath) {
6706
+ const parts = filePath.split(path13.sep);
6707
+ const at = parts.lastIndexOf("agent-transcripts");
6708
+ if (at >= 2 && parts[at - 2] === "projects") {
6709
+ return parts.slice(0, at - 2).join(path13.sep);
6710
+ }
6711
+ return void 0;
6712
+ }
6713
+ function parseCursorClock(raw) {
6714
+ const trimmed = raw.trim();
6715
+ const direct = timestampFrom(trimmed);
6716
+ if (direct) {
6717
+ return direct;
6718
+ }
6719
+ const withoutWeekday = trimmed.replace(/^[A-Za-z]{3,9},\s*/, "");
6720
+ const normalized = withoutWeekday.replace(/\((UTC[+-]\d{1,2}(?::\d{2})?)\)/i, "$1");
6721
+ for (const candidate of [normalized, withoutWeekday, trimmed]) {
6722
+ const parsed = Date.parse(candidate);
6723
+ if (!Number.isNaN(parsed)) {
6724
+ return new Date(parsed).toISOString();
6725
+ }
6726
+ }
6727
+ return void 0;
6728
+ }
6729
+ function latestTimestamp(...values) {
6730
+ let best;
6731
+ for (const value of values) {
6732
+ if (!value || Number.isNaN(Date.parse(value))) {
6733
+ continue;
6734
+ }
6735
+ if (!best || value > best) {
6736
+ best = value;
6737
+ }
6738
+ }
6739
+ return best;
6740
+ }
6741
+ function timestampBetween(start, end, index, count) {
6742
+ if (count <= 0 || index < 0) {
6743
+ return start;
6744
+ }
6745
+ const startMs = Date.parse(start);
6746
+ const endMs = Date.parse(end);
6747
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs <= startMs) {
6748
+ return start;
6749
+ }
6750
+ return new Date(startMs + Math.round((endMs - startMs) * (index + 1) / (count + 1))).toISOString();
6751
+ }
6752
+ function parseCursorUserText(text) {
6753
+ const tsMatch = text.match(CURSOR_TIMESTAMP_RE);
6754
+ const queryMatch = text.match(CURSOR_USER_QUERY_RE);
6755
+ return {
6756
+ ts: tsMatch?.[1] ? parseCursorClock(tsMatch[1]) : void 0,
6757
+ prompt: (queryMatch?.[1] || text.replace(CURSOR_TIMESTAMP_RE, "")).trim()
6758
+ };
6759
+ }
6760
+ function messageText(message) {
6761
+ const content = message.content;
6762
+ if (typeof content === "string") {
6763
+ return content;
6764
+ }
6765
+ if (!Array.isArray(content)) {
6766
+ return stringField(message, "text") || "";
6767
+ }
6768
+ const parts = [];
6769
+ for (const item of content) {
6770
+ if (isPlainObject(item) && stringField(item, "type") === "text") {
6771
+ const text = stringField(item, "text");
6772
+ if (text) {
6773
+ parts.push(text);
6774
+ }
6775
+ }
6776
+ }
6777
+ return parts.join("\n");
6778
+ }
6779
+ function messageToolUses(message) {
6780
+ const content = message.content;
6781
+ if (!Array.isArray(content)) {
6782
+ return [];
6783
+ }
6784
+ const tools = [];
6785
+ for (const item of content) {
6786
+ if (!isPlainObject(item) || stringField(item, "type") !== "tool_use") {
6787
+ continue;
6788
+ }
6789
+ tools.push({
6790
+ name: stringField(item, "name") || "unknown",
6791
+ id: stringField(item, "id"),
6792
+ input: isPlainObject(item.input) ? item.input : parseMaybeJsonObject(item.input)
6793
+ });
6794
+ }
6795
+ return tools;
6796
+ }
6797
+ async function indexCursorChatMeta(cursorHome2) {
6798
+ const cached = chatMetaIndexCache.get(cursorHome2);
6799
+ if (cached) {
6800
+ return cached;
6801
+ }
6802
+ const pending = buildCursorChatMetaIndex(cursorHome2);
6803
+ chatMetaIndexCache.set(cursorHome2, pending);
6804
+ return pending;
6805
+ }
6806
+ async function buildCursorChatMetaIndex(cursorHome2) {
6807
+ const index = /* @__PURE__ */ new Map();
6808
+ const chatsDir = path13.join(cursorHome2, "chats");
6809
+ const projectDirs = await readdir6(chatsDir, { withFileTypes: true }).catch(() => []);
6810
+ for (const project of projectDirs) {
6811
+ if (!project.isDirectory()) {
6812
+ continue;
6813
+ }
6814
+ const sessions = await readdir6(path13.join(chatsDir, project.name), { withFileTypes: true }).catch(() => []);
6815
+ for (const session of sessions) {
6816
+ if (!session.isDirectory()) {
6817
+ continue;
6818
+ }
6819
+ const sessionDir = path13.join(chatsDir, project.name, session.name);
6820
+ const meta = await readJsonIfExists(path13.join(sessionDir, "meta.json"));
6821
+ const fromMeta = isPlainObject(meta) ? meta : {};
6822
+ const fromStore = await readCursorStoreMeta(path13.join(sessionDir, "store.db"));
6823
+ const cwd = stringField(fromMeta, "cwd") || fromStore.cwd;
6824
+ index.set(session.name, {
6825
+ cwd,
6826
+ project: cwd ? path13.basename(cwd) : void 0,
6827
+ model: fromStore.model,
6828
+ startedAt: timestampFrom(fromMeta.createdAtMs) || fromStore.startedAt,
6829
+ endedAt: timestampFrom(fromMeta.updatedAtMs) || fromStore.endedAt
6830
+ });
6831
+ }
6832
+ }
6833
+ return index;
6834
+ }
6835
+ async function readCursorStoreMeta(storePath) {
6836
+ const info = await stat8(storePath).catch(() => null);
6837
+ if (!info) {
6838
+ return {};
6839
+ }
6840
+ try {
6841
+ const { DatabaseSync } = await import("node:sqlite");
6842
+ const db = new DatabaseSync(storePath, { readOnly: true });
6843
+ try {
6844
+ const row = db.prepare("SELECT value FROM meta LIMIT 1").get();
6845
+ const decoded = decodeStoreMetaValue(row?.value);
6846
+ if (!decoded) {
6847
+ return {};
6848
+ }
6849
+ const cwd = stringField(decoded, "cwd") || stringField(objectField(decoded, "workspace"), "path");
6850
+ return {
6851
+ cwd,
6852
+ project: cwd ? path13.basename(cwd) : void 0,
6853
+ model: stringField(decoded, "lastUsedModel") || stringField(decoded, "model"),
6854
+ startedAt: timestampFrom(decoded.createdAt),
6855
+ endedAt: timestampFrom(decoded.lastUpdatedAt) || timestampFrom(decoded.updatedAt)
6856
+ };
6857
+ } finally {
6858
+ db.close();
6859
+ }
6860
+ } catch {
6861
+ return {};
6862
+ }
6863
+ }
6864
+ function decodeStoreMetaValue(value) {
6865
+ if (typeof value !== "string" || !value) {
6866
+ return void 0;
6867
+ }
6868
+ try {
6869
+ const asJson = parseJsonObject(value);
6870
+ if (asJson) {
6871
+ return asJson;
6872
+ }
6873
+ return parseJsonObject(Buffer.from(value, "hex").toString("utf8"));
6874
+ } catch {
6875
+ return void 0;
6876
+ }
6877
+ }
6878
+ async function resolveTranscriptContext(filePath, sessionId) {
6879
+ const sibling = await readJsonIfExists(path13.join(path13.dirname(filePath), "meta.json"));
6880
+ if (isPlainObject(sibling)) {
6881
+ const cwd = stringField(sibling, "cwd");
6882
+ return {
6883
+ cwd,
6884
+ project: cwd ? path13.basename(cwd) : void 0,
6885
+ startedAt: timestampFrom(sibling.createdAtMs),
6886
+ endedAt: timestampFrom(sibling.updatedAtMs)
6887
+ };
6888
+ }
6889
+ const cursorHomePath = cursorHomeFromTranscript(filePath);
6890
+ if (!cursorHomePath) {
6891
+ return {};
6892
+ }
6893
+ const index = await indexCursorChatMeta(cursorHomePath);
6894
+ return index.get(sessionId) || {};
6895
+ }
6896
+ async function parseCursorTranscriptFile(filePath, options) {
6897
+ const text = await readFile8(filePath, "utf8").catch(() => "");
6898
+ if (!text) {
6899
+ return [];
6900
+ }
6901
+ const lines = text.split("\n").filter(Boolean);
6902
+ const parsed = lines.map(parseJsonLine);
6903
+ const hasConversation = parsed.some((raw) => raw && (raw.role === "user" || raw.role === "assistant"));
6904
+ if (!hasConversation) {
6905
+ return [];
6906
+ }
6907
+ const sessionId = path13.basename(filePath, ".jsonl");
6908
+ const context = await resolveTranscriptContext(filePath, sessionId);
6909
+ const fileInfo = await stat8(filePath).catch(() => null);
6910
+ let cwd = context.cwd;
6911
+ let project = context.project;
6912
+ let model = context.model;
6913
+ let lastTs = context.startedAt || (fileInfo ? fileInfo.mtime.toISOString() : void 0);
6914
+ const fileMtime = fileInfo ? fileInfo.mtime.toISOString() : void 0;
6915
+ const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
6916
+ const sourcePathHash = `sha256:${createStableHash(filePath)}`;
6917
+ const events = [];
6918
+ let lineNumber = 0;
6919
+ let currentTurnId;
6920
+ let currentTurnStartedAt;
6921
+ let turnIndex = 0;
6922
+ let sessionStarted = false;
6923
+ let pendingTurnSuccess = true;
6924
+ const pendingTools = [];
6925
+ const push = (partial, topType) => {
6926
+ lineNumber += 1;
6927
+ const event = {
6928
+ schemaVersion: AGENT_TIME_SCHEMA_VERSION,
6929
+ source: SOURCE_ID,
6930
+ agent: AGENT_NAME,
6931
+ workspaceId,
6932
+ project,
6933
+ cwd,
6934
+ model,
6935
+ sessionId,
6936
+ ...partial
6937
+ };
6938
+ events.push(withBackfillRefs(event, {
6939
+ filePath,
6940
+ sourcePathHash,
6941
+ lineNumber,
6942
+ topType,
6943
+ payloadType: event.type,
6944
+ options
6945
+ }));
6946
+ };
6947
+ const ensureSessionStarted = (ts) => {
6948
+ if (sessionStarted) {
6949
+ return;
6950
+ }
6951
+ sessionStarted = true;
6952
+ push({
6953
+ ts,
6954
+ type: "session.started",
6955
+ confidence: "partial",
6956
+ refs: stringRefs({ sourceId: `${sessionId}:started` })
6957
+ }, "transcript");
6958
+ };
6959
+ const closeTurn = (endTs, success = pendingTurnSuccess) => {
6960
+ if (!currentTurnId || !currentTurnStartedAt) {
6961
+ pendingTools.length = 0;
6962
+ pendingTurnSuccess = true;
6963
+ return;
6964
+ }
6965
+ const turnId = currentTurnId;
6966
+ const startedAt = currentTurnStartedAt;
6967
+ const finishedAt = latestTimestamp(startedAt, endTs) || startedAt;
6968
+ const toolCount = pendingTools.length;
6969
+ for (const [index, item] of pendingTools.entries()) {
6970
+ const ts = timestampBetween(startedAt, finishedAt, index, toolCount);
6971
+ const fileActivities = fileActivitiesFromCursorTool(item.tool, item.input, ts, cwd);
6972
+ push({
6973
+ ts,
6974
+ type: "tool.started",
6975
+ turnId,
6976
+ tool: item.tool,
6977
+ operation: `${item.tool} started`,
6978
+ model,
6979
+ confidence: "exact",
6980
+ fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
6981
+ refs: stringRefs({ sourceId: `${item.toolCallId}:started` })
6982
+ }, "tool");
6983
+ push({
6984
+ ts,
6985
+ type: "tool.completed",
6986
+ turnId,
6987
+ tool: item.tool,
6988
+ operation: `${item.tool} completed`,
6989
+ success,
6990
+ model,
6991
+ confidence: "exact",
6992
+ metrics: { toolCalls: 1 },
6993
+ refs: stringRefs({ sourceId: `${item.toolCallId}:completed` })
6994
+ }, "tool");
6995
+ if (item.command) {
6996
+ push({
6997
+ ts,
6998
+ type: "command.started",
6999
+ turnId,
7000
+ tool: item.tool,
7001
+ operation: "command started",
7002
+ confidence: "derived",
7003
+ refs: stringRefs({
7004
+ sourceId: `${item.toolCallId}:command:started`,
7005
+ commandHash: `sha256:${createStableHash(item.command)}`
7006
+ })
7007
+ }, "tool");
7008
+ push({
7009
+ ts,
7010
+ type: "command.completed",
7011
+ turnId,
7012
+ tool: item.tool,
7013
+ operation: "command completed",
7014
+ success,
7015
+ confidence: "derived",
7016
+ metrics: { commandCalls: 1 },
7017
+ refs: stringRefs({ sourceId: `${item.toolCallId}:command:completed` })
7018
+ }, "tool");
7019
+ }
7020
+ }
7021
+ pendingTools.length = 0;
7022
+ push({
7023
+ ts: finishedAt,
7024
+ type: "turn.completed",
7025
+ turnId,
7026
+ model,
7027
+ success,
7028
+ confidence: "derived",
7029
+ metrics: { durationMs: durationMsBetween(startedAt, finishedAt) },
7030
+ refs: stringRefs({ sourceId: `${sessionId}:${turnId}:completed` })
7031
+ }, "transcript");
7032
+ currentTurnId = void 0;
7033
+ currentTurnStartedAt = void 0;
7034
+ pendingTurnSuccess = true;
7035
+ };
7036
+ for (const raw of parsed) {
7037
+ if (!raw) {
7038
+ continue;
7039
+ }
7040
+ const role = stringField(raw, "role");
7041
+ const topType = stringField(raw, "type");
7042
+ const message = objectField(raw, "message");
7043
+ const body = Object.keys(message).length > 0 ? message : raw;
7044
+ const rawText = messageText(body);
7045
+ if (!cwd) {
7046
+ const workspaceMatch = rawText.match(/Workspace Path:\s*(.+)/);
7047
+ const found = workspaceMatch?.[1]?.trim();
7048
+ if (found) {
7049
+ cwd = found;
7050
+ project = path13.basename(found);
7051
+ }
7052
+ }
7053
+ if (role === "user") {
7054
+ const userBits = parseCursorUserText(rawText);
7055
+ const ts = timestampFrom(raw.timestamp) || userBits.ts;
7056
+ if (!ts) {
7057
+ continue;
7058
+ }
7059
+ lastTs = latestTimestamp(lastTs, ts) || ts;
7060
+ ensureSessionStarted(ts);
7061
+ closeTurn(ts);
7062
+ turnIndex += 1;
7063
+ currentTurnId = `turn_${turnIndex}`;
7064
+ currentTurnStartedAt = ts;
7065
+ pendingTurnSuccess = true;
7066
+ push({
7067
+ ts,
7068
+ type: "turn.started",
7069
+ turnId: currentTurnId,
7070
+ model,
7071
+ confidence: "partial",
7072
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:started` })
7073
+ }, "transcript");
7074
+ if (userBits.prompt) {
7075
+ push({
7076
+ ts,
7077
+ type: "prompt.submitted",
7078
+ turnId: currentTurnId,
7079
+ model,
7080
+ confidence: "partial",
7081
+ metrics: { prompts: 1, promptChars: userBits.prompt.length },
7082
+ refs: stringRefs({
7083
+ sourceId: `${sessionId}:${currentTurnId}:prompt`,
7084
+ promptHash: `sha256:${createStableHash(userBits.prompt)}`
7085
+ })
7086
+ }, "transcript");
7087
+ }
7088
+ continue;
7089
+ }
7090
+ if (role === "assistant") {
7091
+ if (!currentTurnId && lastTs) {
7092
+ ensureSessionStarted(lastTs);
7093
+ turnIndex += 1;
7094
+ currentTurnId = `turn_${turnIndex}`;
7095
+ currentTurnStartedAt = lastTs;
7096
+ }
7097
+ if (!currentTurnId) {
7098
+ continue;
7099
+ }
7100
+ for (const [index, toolUse] of messageToolUses(body).entries()) {
7101
+ const tool = toolNameOf(toolUse.name);
7102
+ const command = isShellTool(tool) ? stringField(toolUse.input, "command") || stringField(toolUse.input, "cmd") : void 0;
7103
+ pendingTools.push({
7104
+ tool,
7105
+ toolCallId: cleanId(
7106
+ toolUse.id || `${sessionId}:${currentTurnId}:${pendingTools.length}:${index}`
7107
+ ),
7108
+ input: toolUse.input,
7109
+ command
7110
+ });
7111
+ }
7112
+ continue;
7113
+ }
7114
+ if (topType === "turn_ended") {
7115
+ const status = (stringField(raw, "status") || "success").toLowerCase();
7116
+ pendingTurnSuccess = status !== "error" && status !== "failed" && status !== "cancelled";
7117
+ }
7118
+ }
7119
+ const endedAt = latestTimestamp(lastTs, context.endedAt, fileMtime);
7120
+ const lastTurnId = currentTurnId;
7121
+ if (endedAt) {
7122
+ closeTurn(endedAt);
7123
+ if (sessionStarted) {
7124
+ push({
7125
+ ts: endedAt,
7126
+ type: "session.ended",
7127
+ confidence: "derived",
7128
+ refs: stringRefs({ sourceId: `${sessionId}:ended` })
7129
+ }, "transcript");
7130
+ }
7131
+ }
7132
+ await appendPersistedCursorUsage({
7133
+ push,
7134
+ sessionId,
7135
+ options,
7136
+ fallbackTs: endedAt || lastTs,
7137
+ lastTurnId,
7138
+ model,
7139
+ skip: events.some((event) => event.type === "model.usage")
7140
+ });
7141
+ return events;
7142
+ }
7143
+ async function appendPersistedCursorUsage(args) {
7144
+ if (args.skip) {
7145
+ return;
7146
+ }
7147
+ const persisted = await readPersistedSessionContextFromOptions(args.options, args.sessionId);
7148
+ emitPersistedCursorUsage(
7149
+ args.push,
7150
+ persisted?.usage,
7151
+ args.fallbackTs,
7152
+ args.lastTurnId,
7153
+ args.model,
7154
+ args.sessionId
7155
+ );
7156
+ }
7157
+ function emitPersistedCursorUsage(push, usage, fallbackTs, lastTurnId, model, sessionId, skip = false) {
7158
+ if (skip || !usage?.length || !fallbackTs) {
7159
+ return;
7160
+ }
7161
+ for (const item of usage) {
7162
+ const metrics = usageMetrics({
7163
+ inputTokens: item.tokensInput,
7164
+ outputTokens: item.tokensOutput,
7165
+ cacheReadTokens: item.tokensCacheReadInput,
7166
+ cacheWriteTokens: item.tokensCacheCreationInput
7167
+ });
7168
+ if (!metrics) {
7169
+ continue;
7170
+ }
7171
+ push({
7172
+ ts: timestampFrom(item.ts) || fallbackTs,
7173
+ type: "model.usage",
7174
+ turnId: lastTurnId,
7175
+ model: item.model || model,
7176
+ confidence: "exact",
7177
+ metrics,
7178
+ refs: stringRefs({ sourceId: `${sessionId}:${item.generationId}:usage` })
7179
+ }, "hook-usage");
7180
+ }
7181
+ }
7182
+ async function listCursorComposerIds(dbPath) {
7183
+ const ids = /* @__PURE__ */ new Set();
7184
+ const info = await stat8(dbPath).catch(() => null);
7185
+ if (!info) {
7186
+ return ids;
7187
+ }
7188
+ try {
7189
+ const opened = await openCursorDb(dbPath);
7190
+ try {
7191
+ for (const composer of listComposers(opened.db)) {
7192
+ ids.add(composer.composerId);
7193
+ }
7194
+ } finally {
7195
+ opened.db.close();
7196
+ await opened.cleanup();
7197
+ }
7198
+ } catch {
7199
+ return ids;
7200
+ }
7201
+ return ids;
7202
+ }
7203
+ async function modifiedAtWithHookUsage(fileMtime, home, sessionIds) {
7204
+ let latest = fileMtime.getTime();
7205
+ for (const sessionId of sessionIds) {
7206
+ const extra = await persistedSessionContextModifiedAt(home, sessionId);
7207
+ if (extra && extra.getTime() > latest) {
7208
+ latest = extra.getTime();
7209
+ }
7210
+ }
7211
+ return new Date(latest).toISOString();
7212
+ }
7213
+ async function collectCursorTranscriptFiles(root, home, skipSessionIds) {
7214
+ const files = [];
7215
+ const seen = /* @__PURE__ */ new Set();
7216
+ for (const filePath of await listJsonlFiles(root)) {
7217
+ if (!isCursorTranscriptPath(filePath) && path13.basename(path13.dirname(filePath)) !== "agent-transcripts") {
7218
+ continue;
7219
+ }
7220
+ const sessionId = path13.basename(filePath, ".jsonl");
7221
+ if (!sessionId || seen.has(sessionId) || skipSessionIds?.has(sessionId)) {
7222
+ continue;
7223
+ }
7224
+ seen.add(sessionId);
7225
+ const info = await stat8(filePath).catch(() => null);
7226
+ if (!info) {
7227
+ continue;
7228
+ }
7229
+ files.push({
7230
+ path: filePath,
7231
+ modifiedAt: await modifiedAtWithHookUsage(info.mtime, home, [sessionId])
7232
+ });
7233
+ }
7234
+ return files;
7235
+ }
7236
+ async function parseCursorSessionFile(filePath, options) {
7237
+ const base = path13.basename(filePath);
7238
+ if (base.endsWith(".jsonl")) {
7239
+ return parseCursorTranscriptFile(filePath, options);
7240
+ }
7241
+ if (base === "store.db") {
7242
+ return [];
7243
+ }
7244
+ if (base !== "state.vscdb" && !base.endsWith(".vscdb") && !base.endsWith(".db")) {
7245
+ return [];
7246
+ }
7247
+ const opened = await openCursorDb(filePath);
7248
+ const events = [];
7249
+ const sourcePathHash = `sha256:${createStableHash(filePath)}`;
7250
+ try {
7251
+ const composers = listComposers(opened.db);
7252
+ for (const composer of composers) {
7253
+ const persisted = await readPersistedSessionContextFromOptions(options, composer.composerId);
7254
+ events.push(...parseComposer(opened.db, composer, filePath, sourcePathHash, options, persisted?.usage));
7255
+ }
7256
+ } finally {
7257
+ opened.db.close();
7258
+ await opened.cleanup();
7259
+ }
7260
+ return events;
7261
+ }
7262
+ function parseComposer(db, composer, filePath, sourcePathHash, options, persistedUsage) {
7263
+ const sessionId = composer.composerId;
7264
+ const data = composer.data;
7265
+ const { cwd, project } = workspaceFromComposer(data);
7266
+ const model = modelFromComposer(data);
7267
+ const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
7268
+ const startedAt = timestampFrom(composer.createdAt) || timestampFrom(data.createdAt);
7269
+ const endedAt = timestampFrom(composer.lastUpdatedAt) || timestampFrom(data.lastUpdatedAt) || startedAt;
7270
+ if (!startedAt) {
7271
+ return [];
7272
+ }
7273
+ const bubbles = loadBubbles(db, sessionId);
7274
+ const events = [];
7275
+ let lineNumber = 0;
7276
+ let currentTurnId;
7277
+ let currentTurnStartedAt;
7278
+ let turnIndex = 0;
7279
+ let hasFileLineData = false;
7280
+ const push = (partial, topType) => {
7281
+ lineNumber += 1;
7282
+ const event = {
7283
+ schemaVersion: AGENT_TIME_SCHEMA_VERSION,
7284
+ source: SOURCE_ID,
7285
+ agent: AGENT_NAME,
7286
+ workspaceId,
7287
+ project,
7288
+ cwd,
7289
+ model,
7290
+ sessionId,
7291
+ ...partial
7292
+ };
7293
+ events.push(withBackfillRefs(event, {
7294
+ filePath,
7295
+ sourcePathHash,
7296
+ lineNumber,
7297
+ topType,
7298
+ payloadType: event.type,
7299
+ options
7300
+ }));
7301
+ };
7302
+ push({
7303
+ ts: startedAt,
7304
+ type: "session.started",
7305
+ confidence: "partial",
7306
+ refs: stringRefs({ sourceId: `${sessionId}:started` })
7307
+ }, "composer");
7308
+ for (const bubble of bubbles) {
7309
+ const ts = bubbleTs(bubble, startedAt);
7310
+ if (!ts) {
7311
+ continue;
7312
+ }
7313
+ const bubbleId = stringField(bubble, "bubbleId") || `bubble_${lineNumber}`;
7314
+ const bubbleType = numberField(bubble, "type");
7315
+ const capabilityType = numberField(bubble, "capabilityType");
7316
+ const toolFormer = objectField(bubble, "toolFormerData");
7317
+ const bubbleModel = stringField(objectField(bubble, "modelInfo"), "modelName") || model;
7318
+ if (bubbleType === BUBBLE_USER) {
7319
+ if (currentTurnId && currentTurnStartedAt) {
7320
+ push({
7321
+ ts,
7322
+ type: "turn.completed",
7323
+ turnId: currentTurnId,
7324
+ model: bubbleModel,
7325
+ success: true,
7326
+ confidence: "derived",
7327
+ metrics: { durationMs: durationMsBetween(currentTurnStartedAt, ts) },
7328
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:completed` })
7329
+ }, "bubble");
7330
+ }
7331
+ turnIndex += 1;
7332
+ currentTurnId = `turn_${turnIndex}`;
7333
+ currentTurnStartedAt = ts;
7334
+ const text = stringField(bubble, "text") || "";
7335
+ push({
7336
+ ts,
7337
+ type: "turn.started",
7338
+ turnId: currentTurnId,
7339
+ model: bubbleModel,
7340
+ confidence: "partial",
7341
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:started` })
7342
+ }, "bubble");
7343
+ if (text) {
7344
+ push({
7345
+ ts,
7346
+ type: "prompt.submitted",
7347
+ turnId: currentTurnId,
7348
+ model: bubbleModel,
7349
+ confidence: "partial",
7350
+ metrics: { prompts: 1, promptChars: text.length },
7351
+ refs: stringRefs({
7352
+ sourceId: `${sessionId}:${cleanId(bubbleId)}:prompt`,
7353
+ promptHash: `sha256:${createStableHash(text)}`
7354
+ })
7355
+ }, "bubble");
7356
+ }
7357
+ continue;
7358
+ }
7359
+ if (capabilityType === CAPABILITY_TOOL && Object.keys(toolFormer).length > 0) {
7360
+ const rawName = stringField(toolFormer, "name") || "unknown";
7361
+ const tool = toolNameOf(rawName);
7362
+ const toolCallId = cleanId(
7363
+ stringField(toolFormer, "toolCallId") || `${sessionId}:${cleanId(bubbleId)}`
7364
+ );
7365
+ const status = (stringField(toolFormer, "status") || "completed").toLowerCase();
7366
+ const success = status !== "error" && status !== "failed" && status !== "cancelled";
7367
+ const input = parseMaybeJsonObject(toolFormer.rawArgs);
7368
+ const params = parseMaybeJsonObject(toolFormer.params);
7369
+ const mergedInput = { ...params, ...input };
7370
+ const fileActivities = fileActivitiesFromCursorTool(tool, mergedInput, ts, cwd);
7371
+ if (fileActivities.some((file) => (file.linesAdded || 0) > 0 || (file.linesRemoved || 0) > 0)) {
7372
+ hasFileLineData = true;
7373
+ }
7374
+ push({
7375
+ ts,
7376
+ type: "tool.started",
7377
+ turnId: currentTurnId,
7378
+ tool,
7379
+ operation: `${tool} started`,
7380
+ model: bubbleModel,
7381
+ confidence: "exact",
7382
+ fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
7383
+ refs: stringRefs({ sourceId: `${toolCallId}:started` })
7384
+ }, "tool");
7385
+ push({
7386
+ ts,
7387
+ type: success ? "tool.completed" : "tool.failed",
7388
+ turnId: currentTurnId,
7389
+ tool,
7390
+ operation: `${tool} completed`,
7391
+ success,
7392
+ model: bubbleModel,
7393
+ confidence: "exact",
7394
+ metrics: { toolCalls: 1 },
7395
+ refs: stringRefs({ sourceId: `${toolCallId}:completed` })
7396
+ }, "tool");
7397
+ if (isShellTool(tool)) {
7398
+ const command = stringField(mergedInput, "command") || stringField(mergedInput, "cmd");
7399
+ if (command) {
7400
+ push({
7401
+ ts,
7402
+ type: "command.started",
7403
+ turnId: currentTurnId,
7404
+ tool,
7405
+ operation: "command started",
7406
+ confidence: "derived",
7407
+ refs: stringRefs({
7408
+ sourceId: `${toolCallId}:command:started`,
7409
+ commandHash: `sha256:${createStableHash(command)}`
7410
+ })
7411
+ }, "tool");
7412
+ push({
7413
+ ts,
7414
+ type: success ? "command.completed" : "command.failed",
7415
+ turnId: currentTurnId,
7416
+ tool,
7417
+ operation: "command completed",
7418
+ success,
7419
+ confidence: "derived",
7420
+ metrics: { commandCalls: 1 },
7421
+ refs: stringRefs({ sourceId: `${toolCallId}:command:completed` })
7422
+ }, "tool");
7423
+ }
7424
+ }
7425
+ }
7426
+ const metrics = usageMetrics(objectField(bubble, "tokenCount"));
7427
+ if (metrics) {
7428
+ push({
7429
+ ts,
7430
+ type: "model.usage",
7431
+ turnId: currentTurnId,
7432
+ model: bubbleModel,
7433
+ confidence: "partial",
7434
+ metrics,
7435
+ refs: stringRefs({ sourceId: `${sessionId}:${cleanId(bubbleId)}:usage` })
7436
+ }, "bubble");
7437
+ }
7438
+ }
7439
+ if (currentTurnId && endedAt) {
7440
+ push({
7441
+ ts: endedAt,
7442
+ type: "turn.completed",
7443
+ turnId: currentTurnId,
7444
+ success: true,
7445
+ confidence: "derived",
7446
+ metrics: { durationMs: durationMsBetween(currentTurnStartedAt, endedAt) },
7447
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:completed` })
7448
+ }, "bubble");
7449
+ }
7450
+ const linesAdded = numberField(data, "totalLinesAdded");
7451
+ const linesRemoved = numberField(data, "totalLinesRemoved");
7452
+ if (!hasFileLineData && endedAt && ((linesAdded || 0) > 0 || (linesRemoved || 0) > 0)) {
7453
+ push({
7454
+ ts: endedAt,
7455
+ type: "file.changed",
7456
+ confidence: "partial",
7457
+ metrics: {
7458
+ linesAdded: linesAdded || void 0,
7459
+ linesRemoved: linesRemoved || void 0
7460
+ },
7461
+ refs: stringRefs({ sourceId: `${sessionId}:lines` })
7462
+ }, "composer");
7463
+ }
7464
+ if (endedAt) {
7465
+ push({
7466
+ ts: endedAt,
7467
+ type: "session.ended",
7468
+ confidence: "derived",
7469
+ refs: stringRefs({ sourceId: `${sessionId}:ended` })
7470
+ }, "composer");
7471
+ }
7472
+ emitPersistedCursorUsage(push, persistedUsage, endedAt || startedAt, currentTurnId, model, sessionId, events.some((event) => event.type === "model.usage"));
7473
+ return events;
7474
+ }
7475
+ async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env) {
7476
+ if (sourceRoot) {
7477
+ const info = await stat8(sourceRoot).catch(() => null);
7478
+ if (!info) {
7479
+ return [];
7480
+ }
7481
+ if (info.isDirectory()) {
7482
+ const files2 = [];
7483
+ const skipIds2 = /* @__PURE__ */ new Set();
7484
+ for (const dbPath of await listFilesByExtensions(sourceRoot, [".vscdb", ".db"])) {
7485
+ const base = path13.basename(dbPath);
7486
+ if (base === "store.db" || base !== "state.vscdb" && !base.endsWith(".vscdb")) {
7487
+ continue;
7488
+ }
7489
+ const dbInfo = await stat8(dbPath).catch(() => null);
7490
+ if (!dbInfo) {
7491
+ continue;
7492
+ }
7493
+ const composerIds2 = await listCursorComposerIds(dbPath);
7494
+ for (const id of composerIds2) {
7495
+ skipIds2.add(id);
7496
+ }
7497
+ files2.push({
7498
+ path: dbPath,
7499
+ modifiedAt: await modifiedAtWithHookUsage(dbInfo.mtime, home, composerIds2)
7500
+ });
7501
+ }
7502
+ files2.push(...await collectCursorTranscriptFiles(sourceRoot, home, skipIds2));
7503
+ return files2;
7504
+ }
7505
+ if (path13.basename(sourceRoot) === "store.db") {
7506
+ return [];
7507
+ }
7508
+ if (sourceRoot.endsWith(".jsonl")) {
7509
+ return [{
7510
+ path: sourceRoot,
7511
+ modifiedAt: await modifiedAtWithHookUsage(
7512
+ info.mtime,
7513
+ home,
7514
+ [path13.basename(sourceRoot, ".jsonl")]
7515
+ )
7516
+ }];
7517
+ }
7518
+ const composerIds = await listCursorComposerIds(sourceRoot);
7519
+ return [{
7520
+ path: sourceRoot,
7521
+ modifiedAt: await modifiedAtWithHookUsage(info.mtime, home, composerIds)
7522
+ }];
6179
7523
  }
6180
- for (const entry of entries) {
6181
- if (entry.startsWith("pending-session")) {
7524
+ const files = [];
7525
+ const skipIds = /* @__PURE__ */ new Set();
7526
+ for (const candidatePath of cursorStateDbCandidates(home, env)) {
7527
+ const info = await stat8(candidatePath).catch(() => null);
7528
+ if (!info) {
6182
7529
  continue;
6183
7530
  }
6184
- const eventsPath = path12.join(sessionDir, entry, "events.jsonl");
6185
- const info = await stat6(eventsPath).catch(() => null);
6186
- if (info) {
6187
- results.push({ path: eventsPath, modifiedAt: info.mtime.toISOString() });
7531
+ const composerIds = await listCursorComposerIds(candidatePath);
7532
+ for (const id of composerIds) {
7533
+ skipIds.add(id);
6188
7534
  }
7535
+ files.push({
7536
+ path: candidatePath,
7537
+ modifiedAt: await modifiedAtWithHookUsage(info.mtime, home, composerIds)
7538
+ });
7539
+ break;
6189
7540
  }
6190
- return results;
6191
- }
6192
- function copilotPluginContent() {
6193
- return `// Agent Time plugin for GitHub Copilot CLI
6194
- // Generated by vibetime.
6195
- // Copilot does not support hooks \u2014 this file is a placeholder for detection.
6196
- // Backfill reads session data from ~/.copilot/session-state/*/events.jsonl.
6197
- `;
7541
+ files.push(...await collectCursorTranscriptFiles(cursorProjectsDir(home, env), home, skipIds));
7542
+ return files;
6198
7543
  }
6199
- function copilotHome(home, env) {
6200
- const override = env?.COPILOT_HOME;
6201
- if (override && override.trim()) {
6202
- return path12.resolve(override);
7544
+ function cursorHookConfig() {
7545
+ const entry = { command: HOOK_COMMAND, timeout: HOOK_TIMEOUT_SECONDS };
7546
+ const hooks = {};
7547
+ for (const event of CURSOR_HOOK_EVENTS) {
7548
+ hooks[event] = [entry];
6203
7549
  }
6204
- return path12.join(home, ".copilot");
7550
+ return { version: 1, hooks };
6205
7551
  }
6206
- function createCopilotAdapter() {
7552
+ function createCursorAdapter() {
6207
7553
  return {
6208
- id: "copilot",
6209
- label: "GitHub Copilot",
6210
- agentName: "copilot",
6211
- kind: "agent",
7554
+ id: SOURCE_ID,
7555
+ label: "Cursor",
7556
+ agentName: AGENT_NAME,
7557
+ kind: "ide",
6212
7558
  detectPath(home, env) {
6213
- return copilotHome(home, env);
7559
+ return cursorHome(home, env);
6214
7560
  },
6215
7561
  installedPath(home, env) {
6216
- return path12.join(copilotHome(home, env), ".vibetime");
7562
+ return cursorHooksPath(home, env);
6217
7563
  },
6218
7564
  async isInstalled(home, env) {
6219
- try {
6220
- const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
6221
- return await pathExists2(path12.join(copilotHome(home, env), ".vibetime"));
6222
- } catch {
6223
- return false;
6224
- }
7565
+ const config = await readJsonIfExists(cursorHooksPath(home, env));
7566
+ return hasCursorHookCommand(config, HOOK_COMMAND);
6225
7567
  },
6226
7568
  installEntries(home, env) {
6227
7569
  return [{
6228
- kind: "file",
6229
- path: path12.join(copilotHome(home, env), ".vibetime"),
6230
- content: copilotPluginContent()
7570
+ kind: "cursor-hooks-json",
7571
+ path: cursorHooksPath(home, env),
7572
+ content: cursorHookConfig()
6231
7573
  }];
6232
7574
  },
6233
7575
  sourcePaths(home, env) {
6234
- return [path12.join(copilotHome(home, env), "session-state")];
7576
+ return [
7577
+ ...cursorStateDbCandidates(home, env),
7578
+ cursorProjectsDir(home, env),
7579
+ cursorChatsDir(home, env)
7580
+ ];
6235
7581
  },
6236
- parseSessionFile: parseCopilotSessionFile
7582
+ parseSessionFile: parseCursorSessionFile
6237
7583
  };
6238
7584
  }
6239
7585
 
6240
7586
  // src/adapters/grok-build.ts
6241
- import { readdir as readdir6, readFile as readFile8, stat as stat7 } from "node:fs/promises";
6242
- import path13 from "node:path";
7587
+ import { readdir as readdir7, readFile as readFile9, stat as stat9 } from "node:fs/promises";
7588
+ import path14 from "node:path";
6243
7589
  init_fs();
6244
7590
  var GROK_COST_TICKS_PER_USD = 1e9;
6245
- var SOURCE_ID = "grok-build";
6246
- var AGENT_NAME = "grok-build";
6247
- var HOOK_COMMAND = `vibetime hook --agent ${SOURCE_ID}`;
7591
+ var SOURCE_ID2 = "grok-build";
7592
+ var AGENT_NAME2 = "grok-build";
7593
+ var HOOK_COMMAND2 = `vibetime hook --agent ${SOURCE_ID2}`;
6248
7594
  function grokHome(home, env) {
6249
7595
  const override = env?.GROK_HOME;
6250
7596
  if (override && override.trim()) {
6251
- return path13.resolve(override);
7597
+ return path14.resolve(override);
6252
7598
  }
6253
- return path13.join(home, ".grok");
7599
+ return path14.join(home, ".grok");
6254
7600
  }
6255
7601
  function grokHooksPath(home, env) {
6256
- return path13.join(grokHome(home, env), "hooks", "vibetime.json");
7602
+ return path14.join(grokHome(home, env), "hooks", "vibetime.json");
6257
7603
  }
6258
7604
  function grokSessionsDir(home, env) {
6259
- return path13.join(grokHome(home, env), "sessions");
7605
+ return path14.join(grokHome(home, env), "sessions");
6260
7606
  }
6261
7607
  async function grokBackfillFiles(sourceRoot, home, env) {
6262
7608
  const root = sourceRoot || grokSessionsDir(home, env);
@@ -6264,12 +7610,12 @@ async function grokBackfillFiles(sourceRoot, home, env) {
6264
7610
  async function walk(dir) {
6265
7611
  let entries;
6266
7612
  try {
6267
- entries = await readdir6(dir, { withFileTypes: true });
7613
+ entries = await readdir7(dir, { withFileTypes: true });
6268
7614
  } catch {
6269
7615
  return;
6270
7616
  }
6271
7617
  for (const entry of entries) {
6272
- const entryPath = path13.join(dir, entry.name);
7618
+ const entryPath = path14.join(dir, entry.name);
6273
7619
  if (entry.isDirectory()) {
6274
7620
  await walk(entryPath);
6275
7621
  continue;
@@ -6278,7 +7624,7 @@ async function grokBackfillFiles(sourceRoot, home, env) {
6278
7624
  continue;
6279
7625
  }
6280
7626
  try {
6281
- const info = await stat7(entryPath);
7627
+ const info = await stat9(entryPath);
6282
7628
  files.push({ path: entryPath, modifiedAt: info.mtime.toISOString() });
6283
7629
  } catch {
6284
7630
  }
@@ -6292,18 +7638,18 @@ async function parseGrokSessionFile(filePath, options) {
6292
7638
  if (!sessionDir) {
6293
7639
  return [];
6294
7640
  }
6295
- const summaryPath = path13.join(sessionDir, "summary.json");
6296
- const eventsPath = path13.join(sessionDir, "events.jsonl");
6297
- const signalsPath = path13.join(sessionDir, "signals.json");
6298
- const updatesPath = path13.join(sessionDir, "updates.jsonl");
7641
+ const summaryPath = path14.join(sessionDir, "summary.json");
7642
+ const eventsPath = path14.join(sessionDir, "events.jsonl");
7643
+ const signalsPath = path14.join(sessionDir, "signals.json");
7644
+ const updatesPath = path14.join(sessionDir, "updates.jsonl");
6299
7645
  const summary = await readJsonIfExists(summaryPath);
6300
7646
  if (!isPlainObject(summary)) {
6301
7647
  return [];
6302
7648
  }
6303
7649
  const info = objectField(summary, "info");
6304
- const sessionId = stringField(info, "id") || path13.basename(sessionDir);
7650
+ const sessionId = stringField(info, "id") || path14.basename(sessionDir);
6305
7651
  const cwd = stringField(info, "cwd");
6306
- const project = cwd ? path13.basename(cwd) : void 0;
7652
+ const project = cwd ? path14.basename(cwd) : void 0;
6307
7653
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
6308
7654
  const model = stringField(summary, "current_model_id");
6309
7655
  const createdAt = timestampFrom(summary.created_at) || timestampFrom(summary.createdAt);
@@ -6330,8 +7676,8 @@ async function parseGrokSessionFile(filePath, options) {
6330
7676
  };
6331
7677
  const base = (partial) => ({
6332
7678
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
6333
- source: SOURCE_ID,
6334
- agent: AGENT_NAME,
7679
+ source: SOURCE_ID2,
7680
+ agent: AGENT_NAME2,
6335
7681
  workspaceId,
6336
7682
  project,
6337
7683
  cwd,
@@ -6351,7 +7697,7 @@ async function parseGrokSessionFile(filePath, options) {
6351
7697
  const pendingTools = /* @__PURE__ */ new Map();
6352
7698
  let eventsText = "";
6353
7699
  try {
6354
- eventsText = await readFile8(eventsPath, "utf8");
7700
+ eventsText = await readFile9(eventsPath, "utf8");
6355
7701
  } catch {
6356
7702
  }
6357
7703
  const lines = eventsText.split("\n").filter(Boolean);
@@ -6429,7 +7775,7 @@ async function parseGrokSessionFile(filePath, options) {
6429
7775
  fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
6430
7776
  refs: stringRefs({ sourceId: `${toolId}:started` })
6431
7777
  }), lineNumber, type, "tool.started");
6432
- if (isShellTool(toolName)) {
7778
+ if (isShellTool2(toolName)) {
6433
7779
  const command = stringField(knownInput?.input || {}, "command");
6434
7780
  if (command) {
6435
7781
  push(base({
@@ -6470,7 +7816,7 @@ async function parseGrokSessionFile(filePath, options) {
6470
7816
  },
6471
7817
  refs: stringRefs({ sourceId: `${toolId}:completed` })
6472
7818
  }), lineNumber, type, "tool.completed");
6473
- if (isShellTool(pending?.name || toolName)) {
7819
+ if (isShellTool2(pending?.name || toolName)) {
6474
7820
  push(base({
6475
7821
  ts,
6476
7822
  type: success ? "command.completed" : "command.failed",
@@ -6527,7 +7873,7 @@ async function parseGrokSessionFile(filePath, options) {
6527
7873
  nextLine += 1;
6528
7874
  }
6529
7875
  }
6530
- const hunkPath = path13.join(sessionDir, "hunk_records.jsonl");
7876
+ const hunkPath = path14.join(sessionDir, "hunk_records.jsonl");
6531
7877
  const hunkActivities = await loadHunkFileActivities(hunkPath, cwd);
6532
7878
  if (hunkActivities.length > 0) {
6533
7879
  for (const event of events) {
@@ -6591,9 +7937,9 @@ async function parseGrokSessionFile(filePath, options) {
6591
7937
  return events;
6592
7938
  }
6593
7939
  function resolveSessionDir(filePath) {
6594
- const base = path13.basename(filePath);
7940
+ const base = path14.basename(filePath);
6595
7941
  if (base === "summary.json" || base === "events.jsonl" || base === "signals.json") {
6596
- return path13.dirname(filePath);
7942
+ return path14.dirname(filePath);
6597
7943
  }
6598
7944
  if (/^[0-9a-f]{8}-[0-9a-f-]{27,}$/i.test(base)) {
6599
7945
  return filePath;
@@ -6616,7 +7962,7 @@ function findPendingToolId(pending, toolName) {
6616
7962
  }
6617
7963
  return void 0;
6618
7964
  }
6619
- function isShellTool(name) {
7965
+ function isShellTool2(name) {
6620
7966
  if (!name) {
6621
7967
  return false;
6622
7968
  }
@@ -6625,7 +7971,7 @@ function isShellTool(name) {
6625
7971
  }
6626
7972
  function fileActivitiesFromTool(toolName, input, ts, cwd) {
6627
7973
  const lower = toolName.toLowerCase();
6628
- if (isShellTool(toolName)) {
7974
+ if (isShellTool2(toolName)) {
6629
7975
  const command = stringField(input, "command");
6630
7976
  if (command) {
6631
7977
  return fileActivitiesFromShellCommand(command, ts, cwd, cwd);
@@ -6679,17 +8025,17 @@ function fileActivitiesFromTool(toolName, input, ts, cwd) {
6679
8025
  return [];
6680
8026
  }
6681
8027
  function displayPath(filePath, cwd) {
6682
- if (!cwd || !path13.isAbsolute(filePath)) {
8028
+ if (!cwd || !path14.isAbsolute(filePath)) {
6683
8029
  return filePath;
6684
8030
  }
6685
- const relative = path13.relative(cwd, filePath);
6686
- return relative && !relative.startsWith("..") && !path13.isAbsolute(relative) ? relative : filePath;
8031
+ const relative = path14.relative(cwd, filePath);
8032
+ return relative && !relative.startsWith("..") && !path14.isAbsolute(relative) ? relative : filePath;
6687
8033
  }
6688
8034
  async function loadToolInputsFromUpdates(updatesPath) {
6689
8035
  const map = /* @__PURE__ */ new Map();
6690
8036
  let text = "";
6691
8037
  try {
6692
- text = await readFile8(updatesPath, "utf8");
8038
+ text = await readFile9(updatesPath, "utf8");
6693
8039
  } catch {
6694
8040
  return map;
6695
8041
  }
@@ -6760,7 +8106,7 @@ async function loadTurnUsagesFromUpdates(updatesPath) {
6760
8106
  const turns = [];
6761
8107
  let text = "";
6762
8108
  try {
6763
- text = await readFile8(updatesPath, "utf8");
8109
+ text = await readFile9(updatesPath, "utf8");
6764
8110
  } catch {
6765
8111
  return turns;
6766
8112
  }
@@ -6849,7 +8195,7 @@ async function loadHunkFileActivities(hunkPath, cwd) {
6849
8195
  const activities = [];
6850
8196
  let text = "";
6851
8197
  try {
6852
- text = await readFile8(hunkPath, "utf8");
8198
+ text = await readFile9(hunkPath, "utf8");
6853
8199
  } catch {
6854
8200
  return activities;
6855
8201
  }
@@ -6891,7 +8237,7 @@ async function loadHunkFileActivities(hunkPath, cwd) {
6891
8237
  }
6892
8238
  return activities;
6893
8239
  }
6894
- var grokHandler = (msg) => hookHandler(SOURCE_ID, msg);
8240
+ var grokHandler = (msg) => hookHandler(SOURCE_ID2, msg);
6895
8241
  function hookConfig5() {
6896
8242
  const anyTool = [{ matcher: ".*", hooks: [grokHandler("Reporting tool activity")] }];
6897
8243
  return {
@@ -6913,9 +8259,9 @@ function hookConfig5() {
6913
8259
  }
6914
8260
  function createGrokBuildAdapter() {
6915
8261
  return {
6916
- id: SOURCE_ID,
8262
+ id: SOURCE_ID2,
6917
8263
  label: "Grok Build",
6918
- agentName: AGENT_NAME,
8264
+ agentName: AGENT_NAME2,
6919
8265
  kind: "agent",
6920
8266
  detectPath(home, env) {
6921
8267
  return grokHome(home, env);
@@ -6924,7 +8270,7 @@ function createGrokBuildAdapter() {
6924
8270
  return grokHooksPath(home, env);
6925
8271
  },
6926
8272
  async isInstalled(home, env) {
6927
- return isHooksJsonInstalled(grokHooksPath(home, env), HOOK_COMMAND);
8273
+ return isHooksJsonInstalled(grokHooksPath(home, env), HOOK_COMMAND2);
6928
8274
  },
6929
8275
  installEntries(home, env) {
6930
8276
  return [{
@@ -6941,8 +8287,8 @@ function createGrokBuildAdapter() {
6941
8287
  }
6942
8288
 
6943
8289
  // src/adapters/kimi-code.ts
6944
- import { readFile as readFile9 } from "node:fs/promises";
6945
- import path14 from "node:path";
8290
+ import { readFile as readFile10 } from "node:fs/promises";
8291
+ import path15 from "node:path";
6946
8292
 
6947
8293
  // src/lib/toml-hooks.ts
6948
8294
  init_fs();
@@ -7089,20 +8435,20 @@ function tomlNumberField(body, key) {
7089
8435
  }
7090
8436
 
7091
8437
  // src/adapters/kimi-code.ts
7092
- var HOOK_COMMAND2 = "vibetime hook --agent kimi-code";
7093
- var HOOK_TIMEOUT_SECONDS = 10;
8438
+ var HOOK_COMMAND3 = "vibetime hook --agent kimi-code";
8439
+ var HOOK_TIMEOUT_SECONDS2 = 10;
7094
8440
  function kimiCodeHome(home, env) {
7095
8441
  const override = env?.KIMI_CODE_HOME || env?.KIMI_HOME;
7096
8442
  if (override && override.trim()) {
7097
- return path14.resolve(override);
8443
+ return path15.resolve(override);
7098
8444
  }
7099
- return path14.join(home, ".kimi-code");
8445
+ return path15.join(home, ".kimi-code");
7100
8446
  }
7101
8447
  function kimiCodeSessionsDir(home, env) {
7102
- return path14.join(kimiCodeHome(home, env), "sessions");
8448
+ return path15.join(kimiCodeHome(home, env), "sessions");
7103
8449
  }
7104
8450
  function kimiCodeConfigPath(home, env) {
7105
- return path14.join(kimiCodeHome(home, env), "config.toml");
8451
+ return path15.join(kimiCodeHome(home, env), "config.toml");
7106
8452
  }
7107
8453
  function kimiHookRules() {
7108
8454
  const events = [
@@ -7119,8 +8465,8 @@ function kimiHookRules() {
7119
8465
  ];
7120
8466
  return events.map((event) => ({
7121
8467
  event,
7122
- command: HOOK_COMMAND2,
7123
- timeout: HOOK_TIMEOUT_SECONDS
8468
+ command: HOOK_COMMAND3,
8469
+ timeout: HOOK_TIMEOUT_SECONDS2
7124
8470
  }));
7125
8471
  }
7126
8472
  function baseKimiEvent(event) {
@@ -7179,10 +8525,10 @@ function sessionIdFromWirePath(filePath) {
7179
8525
  return match?.[1];
7180
8526
  }
7181
8527
  async function readSessionState(filePath) {
7182
- const sessionDir = path14.dirname(path14.dirname(path14.dirname(filePath)));
7183
- const statePath = path14.join(sessionDir, "state.json");
8528
+ const sessionDir = path15.dirname(path15.dirname(path15.dirname(filePath)));
8529
+ const statePath = path15.join(sessionDir, "state.json");
7184
8530
  try {
7185
- const text = await readFile9(statePath, "utf8");
8531
+ const text = await readFile10(statePath, "utf8");
7186
8532
  const raw = JSON.parse(text);
7187
8533
  if (!isPlainObject(raw)) {
7188
8534
  return {};
@@ -7197,15 +8543,15 @@ async function readSessionState(filePath) {
7197
8543
  }
7198
8544
  }
7199
8545
  async function parseKimiCodeSessionFile(filePath, options) {
7200
- if (path14.basename(filePath) !== "wire.jsonl") {
8546
+ if (path15.basename(filePath) !== "wire.jsonl") {
7201
8547
  return [];
7202
8548
  }
7203
- const text = await readFile9(filePath, "utf8");
8549
+ const text = await readFile10(filePath, "utf8");
7204
8550
  const lines = text.split("\n").filter(Boolean);
7205
8551
  const stateMeta = await readSessionState(filePath);
7206
8552
  let sessionId = stateMeta.sessionId || sessionIdFromWirePath(filePath);
7207
8553
  let cwd = stateMeta.cwd;
7208
- let project = cwd ? path14.basename(cwd) : void 0;
8554
+ let project = cwd ? path15.basename(cwd) : void 0;
7209
8555
  let model;
7210
8556
  let provider;
7211
8557
  let reasoningEffort;
@@ -7251,7 +8597,7 @@ async function parseKimiCodeSessionFile(filePath, options) {
7251
8597
  const disclosedCwd = stringField(disclosure, "cwd");
7252
8598
  if (disclosedCwd) {
7253
8599
  cwd = disclosedCwd;
7254
- project = path14.basename(disclosedCwd);
8600
+ project = path15.basename(disclosedCwd);
7255
8601
  }
7256
8602
  continue;
7257
8603
  }
@@ -7565,7 +8911,7 @@ function createKimiCodeAdapter() {
7565
8911
  return kimiCodeConfigPath(home, env);
7566
8912
  },
7567
8913
  async isInstalled(home, env) {
7568
- return hasTomlHookCommand(kimiCodeConfigPath(home, env), HOOK_COMMAND2);
8914
+ return hasTomlHookCommand(kimiCodeConfigPath(home, env), HOOK_COMMAND3);
7569
8915
  },
7570
8916
  installEntries(home, env) {
7571
8917
  return [{
@@ -7582,8 +8928,8 @@ function createKimiCodeAdapter() {
7582
8928
  }
7583
8929
 
7584
8930
  // src/adapters/opencode.ts
7585
- import os6 from "node:os";
7586
- import path15 from "node:path";
8931
+ import os7 from "node:os";
8932
+ import path16 from "node:path";
7587
8933
  async function parseOpenCodeSessionFile(dbPath, options) {
7588
8934
  const { DatabaseSync } = await import("node:sqlite");
7589
8935
  if (!dbPath.endsWith(".db")) {
@@ -7642,7 +8988,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
7642
8988
  const isSubagent = sessionId !== rawSessionId;
7643
8989
  const sessionEventStart = events.length;
7644
8990
  const cwd = session.directory || session.path || void 0;
7645
- const project = cwd ? path15.basename(cwd) : void 0;
8991
+ const project = cwd ? path16.basename(cwd) : void 0;
7646
8992
  const sessionTs = msToIso(session.time_created);
7647
8993
  events.push(baseOpenCodeEvent({
7648
8994
  ts: sessionTs,
@@ -7750,7 +9096,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
7750
9096
  const provider = currentProvider;
7751
9097
  const pathObj = objectField(info, "path");
7752
9098
  const assistantCwd = stringField(pathObj, "cwd") || cwd;
7753
- const assistantProject = assistantCwd ? path15.basename(assistantCwd) : project;
9099
+ const assistantProject = assistantCwd ? path16.basename(assistantCwd) : project;
7754
9100
  const completedTs = numberField(objectField(info, "time"), "completed");
7755
9101
  const createdTs = timeCreated;
7756
9102
  const tokens = opencodeUsageFromInfo(info);
@@ -8024,33 +9370,33 @@ function opencodeUsageFromInfo(info) {
8024
9370
  function opencodeConfigDir(home, env) {
8025
9371
  const override = env?.OPENCODE_CONFIG_DIR;
8026
9372
  if (override && override.trim()) {
8027
- return path15.resolve(override);
9373
+ return path16.resolve(override);
8028
9374
  }
8029
9375
  const xdgConfig = env?.XDG_CONFIG_HOME;
8030
9376
  if (xdgConfig && xdgConfig.trim()) {
8031
- return path15.join(path15.resolve(xdgConfig), "opencode");
9377
+ return path16.join(path16.resolve(xdgConfig), "opencode");
8032
9378
  }
8033
- return path15.join(home, ".config", "opencode");
9379
+ return path16.join(home, ".config", "opencode");
8034
9380
  }
8035
9381
  function opencodeDataCandidates(home, env) {
8036
9382
  const xdgData = env?.XDG_DATA_HOME;
8037
- const primary = xdgData && xdgData.trim() ? path15.join(path15.resolve(xdgData), "opencode", "opencode.db") : path15.join(home, ".local", "share", "opencode", "opencode.db");
8038
- return [primary, path15.join(home, ".opencode", "opencode.db")];
9383
+ const primary = xdgData && xdgData.trim() ? path16.join(path16.resolve(xdgData), "opencode", "opencode.db") : path16.join(home, ".local", "share", "opencode", "opencode.db");
9384
+ return [primary, path16.join(home, ".opencode", "opencode.db")];
8039
9385
  }
8040
- async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
8041
- const { stat: stat15 } = await import("node:fs/promises");
9386
+ async function opencodeBackfillFiles(sourceRoot, home = os7.homedir(), env) {
9387
+ const { stat: stat17 } = await import("node:fs/promises");
8042
9388
  if (sourceRoot) {
8043
9389
  if (!sourceRoot.endsWith(".db")) {
8044
9390
  return [];
8045
9391
  }
8046
- const info = await stat15(sourceRoot).catch(() => null);
9392
+ const info = await stat17(sourceRoot).catch(() => null);
8047
9393
  if (!info) {
8048
9394
  return [];
8049
9395
  }
8050
9396
  return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
8051
9397
  }
8052
9398
  for (const candidatePath of opencodeDataCandidates(home, env)) {
8053
- const info = await stat15(candidatePath).catch(() => null);
9399
+ const info = await stat17(candidatePath).catch(() => null);
8054
9400
  if (info) {
8055
9401
  return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
8056
9402
  }
@@ -8125,12 +9471,12 @@ function createOpenCodeAdapter() {
8125
9471
  return opencodeConfigDir(home, env);
8126
9472
  },
8127
9473
  installedPath(home, env) {
8128
- return path15.join(opencodeConfigDir(home, env), PLUGIN_PATH);
9474
+ return path16.join(opencodeConfigDir(home, env), PLUGIN_PATH);
8129
9475
  },
8130
9476
  async isInstalled(home, env) {
8131
9477
  try {
8132
9478
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
8133
- return await pathExists2(path15.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path15.join(".opencode", PLUGIN_PATH));
9479
+ return await pathExists2(path16.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path16.join(".opencode", PLUGIN_PATH));
8134
9480
  } catch {
8135
9481
  return false;
8136
9482
  }
@@ -8138,7 +9484,7 @@ function createOpenCodeAdapter() {
8138
9484
  installEntries(home, env) {
8139
9485
  return [{
8140
9486
  kind: "file",
8141
- path: path15.join(opencodeConfigDir(home, env), PLUGIN_PATH),
9487
+ path: path16.join(opencodeConfigDir(home, env), PLUGIN_PATH),
8142
9488
  content: opencodePluginContent()
8143
9489
  }];
8144
9490
  },
@@ -8150,9 +9496,9 @@ function createOpenCodeAdapter() {
8150
9496
  }
8151
9497
 
8152
9498
  // src/adapters/pi.ts
8153
- import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
8154
- import os7 from "node:os";
8155
- import path16 from "node:path";
9499
+ import { readdir as readdir8, readFile as readFile11, stat as stat10 } from "node:fs/promises";
9500
+ import os8 from "node:os";
9501
+ import path17 from "node:path";
8156
9502
  init_fs();
8157
9503
  function piHostSessionIdFromBasename(basename) {
8158
9504
  const withoutExt = basename.endsWith(".jsonl") ? basename.slice(0, -".jsonl".length) : basename;
@@ -8167,7 +9513,7 @@ function piHostSessionIdFromBasename(basename) {
8167
9513
  }
8168
9514
  function resolvePiBackfillGroupId(filePath) {
8169
9515
  const normalized = filePath.replaceAll("\\", "/");
8170
- const base = path16.basename(filePath);
9516
+ const base = path17.basename(filePath);
8171
9517
  const nest = normalized.match(/([^/]+)\/[^/]+\/run-\d+\/session\.jsonl$/);
8172
9518
  if (nest) {
8173
9519
  return piHostSessionIdFromBasename(nest[1]);
@@ -8179,8 +9525,8 @@ function resolvePiBackfillGroupId(filePath) {
8179
9525
  }
8180
9526
  function parsePiSubagentLink(filePath, headerParentSession) {
8181
9527
  if (headerParentSession) {
8182
- const parentFile = path16.isAbsolute(headerParentSession) ? headerParentSession : void 0;
8183
- const parentSessionId2 = parentFile ? path16.basename(parentFile, ".jsonl") : headerParentSession;
9528
+ const parentFile = path17.isAbsolute(headerParentSession) ? headerParentSession : void 0;
9529
+ const parentSessionId2 = parentFile ? path17.basename(parentFile, ".jsonl") : headerParentSession;
8184
9530
  return { parentSessionId: parentSessionId2, parentSessionFile: parentFile, explicit: true };
8185
9531
  }
8186
9532
  const normalized = filePath.replaceAll("\\", "/");
@@ -8193,20 +9539,20 @@ function parsePiSubagentLink(filePath, headerParentSession) {
8193
9539
  return void 0;
8194
9540
  }
8195
9541
  const parentSessionId = parentBasename.endsWith(".jsonl") ? parentBasename.slice(0, -".jsonl".length) : parentBasename;
8196
- const parentDir = path16.dirname(path16.dirname(path16.dirname(filePath)));
8197
- const parentSessionFile = path16.join(path16.dirname(parentDir), `${parentBasename}.jsonl`);
9542
+ const parentDir = path17.dirname(path17.dirname(path17.dirname(filePath)));
9543
+ const parentSessionFile = path17.join(path17.dirname(parentDir), `${parentBasename}.jsonl`);
8198
9544
  return { parentSessionId, parentSessionFile, explicit: false };
8199
9545
  }
8200
9546
  async function resolveParentContext(link, options) {
8201
9547
  if (link.parentSessionFile) {
8202
9548
  try {
8203
- const text = await readFile10(link.parentSessionFile, "utf8");
9549
+ const text = await readFile11(link.parentSessionFile, "utf8");
8204
9550
  const firstLine = text.split("\n").find((line) => line.trim().length > 0);
8205
9551
  const raw = firstLine ? parseJsonLine(firstLine) : void 0;
8206
9552
  if (raw) {
8207
9553
  const id = stringField(raw, "id");
8208
9554
  const cwd = stringField(raw, "cwd");
8209
- const project = cwd ? path16.basename(cwd) : void 0;
9555
+ const project = cwd ? path17.basename(cwd) : void 0;
8210
9556
  if (id || cwd || project) {
8211
9557
  return { sessionId: id, cwd, project };
8212
9558
  }
@@ -8255,7 +9601,7 @@ function rebuildEventIdentity2(event) {
8255
9601
  };
8256
9602
  }
8257
9603
  async function parsePiSessionFile(filePath, options) {
8258
- const text = await readFile10(filePath, "utf8");
9604
+ const text = await readFile11(filePath, "utf8");
8259
9605
  const lines = text.split("\n").filter(Boolean);
8260
9606
  let sessionId;
8261
9607
  let cwd;
@@ -8287,7 +9633,7 @@ async function parsePiSessionFile(filePath, options) {
8287
9633
  sessionId = stringField(raw, "id") || state.sessionId;
8288
9634
  state.sessionId = sessionId || state.sessionId;
8289
9635
  cwd = stringField(raw, "cwd") || cwd;
8290
- project = cwd ? path16.basename(cwd) : project;
9636
+ project = cwd ? path17.basename(cwd) : project;
8291
9637
  headerParentSession = stringField(raw, "parentSession") || headerParentSession;
8292
9638
  continue;
8293
9639
  }
@@ -8494,7 +9840,7 @@ async function parsePiFile(filePath, options) {
8494
9840
  async function parsePiWorkflowRunFile(filePath, options) {
8495
9841
  let raw;
8496
9842
  try {
8497
- raw = JSON.parse(await readFile10(filePath, "utf8"));
9843
+ raw = JSON.parse(await readFile11(filePath, "utf8"));
8498
9844
  } catch {
8499
9845
  return [];
8500
9846
  }
@@ -8562,17 +9908,17 @@ async function parsePiWorkflowRunFile(filePath, options) {
8562
9908
  return state.events.filter((event) => matchesBackfillFilters(event, options));
8563
9909
  }
8564
9910
  async function findPiSessionFileById(sessionId, options) {
8565
- const sessionsDir = piSessionDir(path16.resolve(stringOption(options.home) || os7.homedir()));
9911
+ const sessionsDir = piSessionDir(path17.resolve(stringOption(options.home) || os8.homedir()));
8566
9912
  try {
8567
- const projectDirs = await readdir7(sessionsDir, { withFileTypes: true });
9913
+ const projectDirs = await readdir8(sessionsDir, { withFileTypes: true });
8568
9914
  for (const dir of projectDirs) {
8569
9915
  if (!dir.isDirectory()) {
8570
9916
  continue;
8571
9917
  }
8572
- const names = await readdir7(path16.join(sessionsDir, dir.name));
9918
+ const names = await readdir8(path17.join(sessionsDir, dir.name));
8573
9919
  const hit = names.find((name) => name.endsWith(`_${sessionId}.jsonl`));
8574
9920
  if (hit) {
8575
- return path16.join(sessionsDir, dir.name, hit);
9921
+ return path17.join(sessionsDir, dir.name, hit);
8576
9922
  }
8577
9923
  }
8578
9924
  } catch {
@@ -8814,23 +10160,23 @@ export default function (pi: ExtensionAPI) {
8814
10160
  function piAgentDir(home, env) {
8815
10161
  const override = env?.PI_CODING_AGENT_DIR;
8816
10162
  if (override && override.trim()) {
8817
- return path16.resolve(override);
10163
+ return path17.resolve(override);
8818
10164
  }
8819
- return path16.join(home, ".pi", "agent");
10165
+ return path17.join(home, ".pi", "agent");
8820
10166
  }
8821
10167
  function piSessionDir(home, env) {
8822
10168
  const override = env?.PI_CODING_AGENT_SESSION_DIR;
8823
10169
  if (override && override.trim()) {
8824
- return path16.resolve(override);
10170
+ return path17.resolve(override);
8825
10171
  }
8826
- return path16.join(piAgentDir(home, env), "sessions");
10172
+ return path17.join(piAgentDir(home, env), "sessions");
8827
10173
  }
8828
10174
  function piWorkflowProjectsDir(home) {
8829
- return path16.join(home, ".pi", "workflows", "projects");
10175
+ return path17.join(home, ".pi", "workflows", "projects");
8830
10176
  }
8831
10177
  async function workflowRunGroupId(filePath) {
8832
10178
  try {
8833
- const raw = JSON.parse(await readFile10(filePath, "utf8"));
10179
+ const raw = JSON.parse(await readFile11(filePath, "utf8"));
8834
10180
  if (!isPlainObject(raw)) {
8835
10181
  return void 0;
8836
10182
  }
@@ -8839,14 +10185,14 @@ async function workflowRunGroupId(filePath) {
8839
10185
  return void 0;
8840
10186
  }
8841
10187
  }
8842
- async function piBackfillFiles(sourceRoot, home = os7.homedir(), env) {
10188
+ async function piBackfillFiles(sourceRoot, home = os8.homedir(), env) {
8843
10189
  const lists = sourceRoot ? [await listFilesByExtensions(sourceRoot, [".jsonl", ".json"])] : await Promise.all([
8844
10190
  listFilesByExtensions(piSessionDir(home, env), [".jsonl"]),
8845
10191
  listFilesByExtensions(piWorkflowProjectsDir(home), [".json"])
8846
10192
  ]);
8847
10193
  const files = lists.flat().sort();
8848
10194
  return Promise.all(files.map(async (filePath) => {
8849
- const info = await stat8(filePath);
10195
+ const info = await stat10(filePath);
8850
10196
  let groupId = resolvePiBackfillGroupId(filePath);
8851
10197
  if (!groupId && filePath.endsWith(".json")) {
8852
10198
  groupId = await workflowRunGroupId(filePath);
@@ -8868,12 +10214,12 @@ function createPiAdapter() {
8868
10214
  return piAgentDir(home, env);
8869
10215
  },
8870
10216
  installedPath(home, env) {
8871
- return path16.join(piAgentDir(home, env), "extensions", "vibetime.ts");
10217
+ return path17.join(piAgentDir(home, env), "extensions", "vibetime.ts");
8872
10218
  },
8873
10219
  async isInstalled(home, env) {
8874
10220
  try {
8875
10221
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
8876
- return await pathExists2(path16.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
10222
+ return await pathExists2(path17.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
8877
10223
  } catch {
8878
10224
  return false;
8879
10225
  }
@@ -8881,7 +10227,7 @@ function createPiAdapter() {
8881
10227
  installEntries(home, env) {
8882
10228
  return [{
8883
10229
  kind: "file",
8884
- path: path16.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
10230
+ path: path17.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
8885
10231
  content: piExtensionContent()
8886
10232
  }];
8887
10233
  },
@@ -8893,14 +10239,14 @@ function createPiAdapter() {
8893
10239
  }
8894
10240
 
8895
10241
  // src/adapters/qoder-cn.ts
8896
- import { readdir as readdir8, readFile as readFile11, stat as stat9 } from "node:fs/promises";
8897
- import os9 from "node:os";
8898
- import path18 from "node:path";
10242
+ import { readdir as readdir9, readFile as readFile12, stat as stat11 } from "node:fs/promises";
10243
+ import os10 from "node:os";
10244
+ import path19 from "node:path";
8899
10245
 
8900
10246
  // src/adapters/qoder-local-db.ts
8901
10247
  import { access } from "node:fs/promises";
8902
- import os8 from "node:os";
8903
- import path17 from "node:path";
10248
+ import os9 from "node:os";
10249
+ import path18 from "node:path";
8904
10250
  function takeQoderDbModelCall(calls, requestId, blockStart) {
8905
10251
  if (requestId) {
8906
10252
  const call = calls.byRequestId.get(requestId)?.shift();
@@ -8917,14 +10263,14 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
8917
10263
  }
8918
10264
  return calls.ordered.shift();
8919
10265
  }
8920
- function appDataRoot(appDirName, home = os8.homedir()) {
10266
+ function appDataRoot(appDirName, home = os9.homedir()) {
8921
10267
  if (process.platform === "darwin") {
8922
- return path17.join(home, "Library", "Application Support", appDirName);
10268
+ return path18.join(home, "Library", "Application Support", appDirName);
8923
10269
  }
8924
10270
  if (process.platform === "win32") {
8925
- return path17.join(process.env.APPDATA || path17.join(home, "AppData", "Roaming"), appDirName);
10271
+ return path18.join(process.env.APPDATA || path18.join(home, "AppData", "Roaming"), appDirName);
8926
10272
  }
8927
- return path17.join(home, ".config", appDirName);
10273
+ return path18.join(home, ".config", appDirName);
8928
10274
  }
8929
10275
  function qoderLocalDbCandidates(appDirName) {
8930
10276
  const candidates = [];
@@ -8934,8 +10280,8 @@ function qoderLocalDbCandidates(appDirName) {
8934
10280
  }
8935
10281
  const configRoot = appDataRoot(appDirName);
8936
10282
  candidates.push(
8937
- path17.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
8938
- path17.join(configRoot, "SharedClientCache", "db", "local.db")
10283
+ path18.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
10284
+ path18.join(configRoot, "SharedClientCache", "db", "local.db")
8939
10285
  );
8940
10286
  return candidates;
8941
10287
  }
@@ -8944,7 +10290,7 @@ async function loadQoderIdeModelCatalog(appDirName, home) {
8944
10290
  try {
8945
10291
  const { DatabaseSync } = await import("node:sqlite");
8946
10292
  const db = new DatabaseSync(
8947
- path17.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
10293
+ path18.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
8948
10294
  { readOnly: true }
8949
10295
  );
8950
10296
  try {
@@ -9086,7 +10432,7 @@ function resolveSessionPreferredModel(db, sessionId, modelMap) {
9086
10432
 
9087
10433
  // src/adapters/qoder-cn.ts
9088
10434
  function parseQoderCnPaths(filePath) {
9089
- const parts = filePath.split(path18.sep);
10435
+ const parts = filePath.split(path19.sep);
9090
10436
  const subagentsIdx = parts.lastIndexOf("subagents");
9091
10437
  let sessionId = "";
9092
10438
  let projectName = "";
@@ -9096,17 +10442,17 @@ function parseQoderCnPaths(filePath) {
9096
10442
  sessionId = parts[subagentsIdx - 1];
9097
10443
  projectName = parts[subagentsIdx - 2];
9098
10444
  const projectsIdx = parts.lastIndexOf("projects");
9099
- configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
9100
- mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path18.sep);
10445
+ configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
10446
+ mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path19.sep);
9101
10447
  } else {
9102
10448
  const filename = parts.at(-1) || "";
9103
- sessionId = path18.basename(filename, ".jsonl");
10449
+ sessionId = path19.basename(filename, ".jsonl");
9104
10450
  projectName = parts.at(-2) || "";
9105
10451
  if (projectName === "transcript") {
9106
10452
  projectName = parts.at(-3) || "";
9107
10453
  }
9108
10454
  const projectsIdx = parts.lastIndexOf("projects");
9109
- configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
10455
+ configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
9110
10456
  }
9111
10457
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
9112
10458
  }
@@ -9129,7 +10475,7 @@ function rebuildEventIdentity3(event) {
9129
10475
  }
9130
10476
  async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
9131
10477
  try {
9132
- const content = await readFile11(dynamicTextsPath, "utf8");
10478
+ const content = await readFile12(dynamicTextsPath, "utf8");
9133
10479
  const json = JSON.parse(content);
9134
10480
  const texts = json.texts || {};
9135
10481
  const map = {};
@@ -9145,10 +10491,10 @@ async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
9145
10491
  }
9146
10492
  }
9147
10493
  async function loadQoderCnModelNames(configDir2, home) {
9148
- const map = await parseModelNamesFromDynamicTexts(path18.join(configDir2, ".auth", "dynamic-texts.json"));
10494
+ const map = await parseModelNamesFromDynamicTexts(path19.join(configDir2, ".auth", "dynamic-texts.json"));
9149
10495
  const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
9150
10496
  if (siblingConfigDir !== configDir2) {
9151
- const siblingMap = await parseModelNamesFromDynamicTexts(path18.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
10497
+ const siblingMap = await parseModelNamesFromDynamicTexts(path19.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
9152
10498
  for (const [key, val] of Object.entries(siblingMap)) {
9153
10499
  if (!(key in map)) {
9154
10500
  map[key] = val;
@@ -9167,15 +10513,15 @@ async function loadQoderCnModelNames(configDir2, home) {
9167
10513
  }
9168
10514
  async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
9169
10515
  const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
9170
- const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
10516
+ const segmentsPath = path19.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
9171
10517
  const modelCalls = [];
9172
10518
  try {
9173
- const files = await readdir8(segmentsPath);
10519
+ const files = await readdir9(segmentsPath);
9174
10520
  for (const file of files) {
9175
10521
  if (!file.endsWith(".jsonl")) {
9176
10522
  continue;
9177
10523
  }
9178
- const content = await readFile11(path18.join(segmentsPath, file), "utf8");
10524
+ const content = await readFile12(path19.join(segmentsPath, file), "utf8");
9179
10525
  let currentTurnIsSubagent = false;
9180
10526
  for (const line of content.split("\n").filter(Boolean)) {
9181
10527
  const raw = parseJsonLine(line);
@@ -9209,7 +10555,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
9209
10555
  return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
9210
10556
  }
9211
10557
  async function parseQoderCnSessionFile(filePath, options) {
9212
- const text = await readFile11(filePath, "utf8");
10558
+ const text = await readFile12(filePath, "utf8");
9213
10559
  const lines = text.split("\n").filter(Boolean);
9214
10560
  const parsedPaths = parseQoderCnPaths(filePath);
9215
10561
  const { configDir: configDir2 } = parsedPaths;
@@ -9220,7 +10566,7 @@ async function parseQoderCnSessionFile(filePath, options) {
9220
10566
  let cwd;
9221
10567
  let project = projectContext.project;
9222
10568
  let model;
9223
- const home = path18.resolve(stringOption(options.home) || os9.homedir());
10569
+ const home = path19.resolve(stringOption(options.home) || os10.homedir());
9224
10570
  const modelMap = await loadQoderCnModelNames(configDir2, home);
9225
10571
  const isSubagentSession = filePath.includes("subagents");
9226
10572
  const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
@@ -9255,7 +10601,7 @@ async function parseQoderCnSessionFile(filePath, options) {
9255
10601
  sessionId = stringField(raw, "sessionId") || sessionId;
9256
10602
  state.sessionId = sessionId;
9257
10603
  cwd = stringField(raw, "cwd") || cwd;
9258
- project = projectContext.project || (cwd ? path18.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
10604
+ project = projectContext.project || (cwd ? path19.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
9259
10605
  if (!ts) {
9260
10606
  continue;
9261
10607
  }
@@ -9591,7 +10937,7 @@ async function parseQoderCnSessionFile(filePath, options) {
9591
10937
  }
9592
10938
  dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", parsedPaths.sessionId, modelMap);
9593
10939
  if (dbModelCalls.rootSessionId) {
9594
- const parentPath = path18.join(path18.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
10940
+ const parentPath = path19.join(path19.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
9595
10941
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
9596
10942
  return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity3({
9597
10943
  ...event,
@@ -9744,28 +11090,28 @@ function extractQoderAttachedPrompt(content) {
9744
11090
  }
9745
11091
  async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
9746
11092
  const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
9747
- const isSubagent = filePath.includes(`${path18.sep}subagents${path18.sep}`);
11093
+ const isSubagent = filePath.includes(`${path19.sep}subagents${path19.sep}`);
9748
11094
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
9749
11095
  let cwds = [];
9750
11096
  for (const line of lines) {
9751
11097
  const raw = parseJsonLine(line);
9752
11098
  const cwd = raw ? stringField(raw, "cwd") : void 0;
9753
- if (cwd && path18.isAbsolute(cwd)) {
11099
+ if (cwd && path19.isAbsolute(cwd)) {
9754
11100
  cwds.push(cwd);
9755
11101
  }
9756
11102
  }
9757
11103
  if (isSubagent) {
9758
- if (inherited?.cwd && path18.isAbsolute(inherited.cwd)) {
11104
+ if (inherited?.cwd && path19.isAbsolute(inherited.cwd)) {
9759
11105
  cwds = [inherited.cwd];
9760
11106
  } else {
9761
- const parentSessionPath = path18.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
11107
+ const parentSessionPath = path19.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
9762
11108
  try {
9763
- const parentText = await readFile11(parentSessionPath, "utf8");
11109
+ const parentText = await readFile12(parentSessionPath, "utf8");
9764
11110
  const parentCwds = [];
9765
11111
  for (const line of parentText.split("\n").filter(Boolean)) {
9766
11112
  const raw = parseJsonLine(line);
9767
11113
  const cwd = raw ? stringField(raw, "cwd") : void 0;
9768
- if (cwd && path18.isAbsolute(cwd)) {
11114
+ if (cwd && path19.isAbsolute(cwd)) {
9769
11115
  parentCwds.push(cwd);
9770
11116
  }
9771
11117
  }
@@ -9777,7 +11123,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
9777
11123
  }
9778
11124
  }
9779
11125
  const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
9780
- const project = inherited?.project || (cwds.length > 0 ? path18.basename(cwds[0]) : root ? path18.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
11126
+ const project = inherited?.project || (cwds.length > 0 ? path19.basename(cwds[0]) : root ? path19.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
9781
11127
  return {
9782
11128
  project,
9783
11129
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
@@ -9786,15 +11132,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
9786
11132
  async function gitRootFromCwds2(cwds) {
9787
11133
  const seen = /* @__PURE__ */ new Set();
9788
11134
  for (const cwd of cwds) {
9789
- let current = path18.resolve(cwd);
11135
+ let current = path19.resolve(cwd);
9790
11136
  while (!seen.has(current)) {
9791
11137
  seen.add(current);
9792
11138
  try {
9793
- await stat9(path18.join(current, ".git"));
11139
+ await stat11(path19.join(current, ".git"));
9794
11140
  return current;
9795
11141
  } catch {
9796
11142
  }
9797
- const parent = path18.dirname(current);
11143
+ const parent = path19.dirname(current);
9798
11144
  if (parent === current) {
9799
11145
  break;
9800
11146
  }
@@ -9805,12 +11151,12 @@ async function gitRootFromCwds2(cwds) {
9805
11151
  }
9806
11152
  function qoderCnProjectRootFromCwds(projectDir, cwds) {
9807
11153
  for (const cwd of cwds) {
9808
- let current = path18.resolve(cwd);
11154
+ let current = path19.resolve(cwd);
9809
11155
  while (true) {
9810
11156
  if (encodeQoderCnProjectPath(current) === projectDir) {
9811
11157
  return current;
9812
11158
  }
9813
- const parent = path18.dirname(current);
11159
+ const parent = path19.dirname(current);
9814
11160
  if (parent === current) {
9815
11161
  break;
9816
11162
  }
@@ -9820,14 +11166,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
9820
11166
  return void 0;
9821
11167
  }
9822
11168
  function encodeQoderCnProjectPath(value) {
9823
- return path18.resolve(value).split(path18.sep).join("-").replaceAll("_", "-");
11169
+ return path19.resolve(value).split(path19.sep).join("-").replaceAll("_", "-");
9824
11170
  }
9825
11171
  async function qoderCnProjectFromFilePath(filePath, options) {
9826
- const projectDir = path18.basename(path18.dirname(filePath));
9827
- const home = options ? path18.resolve(stringOption(options.home) || os9.homedir()) : os9.homedir();
11172
+ const projectDir = path19.basename(path19.dirname(filePath));
11173
+ const home = options ? path19.resolve(stringOption(options.home) || os10.homedir()) : os10.homedir();
9828
11174
  const resolved = await resolveQoderCnProjectPath(projectDir, home);
9829
11175
  if (resolved) {
9830
- return path18.basename(resolved);
11176
+ return path19.basename(resolved);
9831
11177
  }
9832
11178
  const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
9833
11179
  if (projectDir.startsWith(homePrefix)) {
@@ -9847,12 +11193,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
9847
11193
  while (projectDir.startsWith(`${currentEncoded}-`)) {
9848
11194
  let matchedChild;
9849
11195
  try {
9850
- const entries = await readdir8(current, { withFileTypes: true });
11196
+ const entries = await readdir9(current, { withFileTypes: true });
9851
11197
  for (const entry of entries) {
9852
11198
  if (!entry.isDirectory()) {
9853
11199
  continue;
9854
11200
  }
9855
- const candidate = path18.join(current, entry.name);
11201
+ const candidate = path19.join(current, entry.name);
9856
11202
  const encoded = encodeQoderCnProjectPath(candidate);
9857
11203
  if (encoded === projectDir) {
9858
11204
  return candidate;
@@ -9897,9 +11243,9 @@ function hookConfig6() {
9897
11243
  function qoderCnConfigDir(home, env) {
9898
11244
  const override = env?.QODER_CN_CONFIG_DIR;
9899
11245
  if (override && override.trim()) {
9900
- return path18.resolve(override);
11246
+ return path19.resolve(override);
9901
11247
  }
9902
- return path18.join(home, ".qoder-cn");
11248
+ return path19.join(home, ".qoder-cn");
9903
11249
  }
9904
11250
  function createQoderCnAdapter() {
9905
11251
  return {
@@ -9911,27 +11257,27 @@ function createQoderCnAdapter() {
9911
11257
  return qoderCnConfigDir(home, env);
9912
11258
  },
9913
11259
  installedPath(home, env) {
9914
- return path18.join(qoderCnConfigDir(home, env), "settings.json");
11260
+ return path19.join(qoderCnConfigDir(home, env), "settings.json");
9915
11261
  },
9916
11262
  async isInstalled(home, env) {
9917
11263
  return isHooksJsonInstalled(
9918
- path18.join(qoderCnConfigDir(home, env), "settings.json"),
11264
+ path19.join(qoderCnConfigDir(home, env), "settings.json"),
9919
11265
  "vibetime hook --agent qoder-cn"
9920
11266
  );
9921
11267
  },
9922
11268
  installEntries(home, env) {
9923
11269
  return [{
9924
11270
  kind: "hooks-json",
9925
- path: path18.join(qoderCnConfigDir(home, env), "settings.json"),
11271
+ path: path19.join(qoderCnConfigDir(home, env), "settings.json"),
9926
11272
  content: hookConfig6()
9927
11273
  }];
9928
11274
  },
9929
11275
  sourcePaths(home, env) {
9930
11276
  const base = qoderCnConfigDir(home, env);
9931
11277
  return [
9932
- path18.join(base, "projects"),
9933
- path18.join(base, ".qoder.json"),
9934
- path18.join(home, ".qoder.json")
11278
+ path19.join(base, "projects"),
11279
+ path19.join(base, ".qoder.json"),
11280
+ path19.join(home, ".qoder.json")
9935
11281
  ];
9936
11282
  },
9937
11283
  parseSessionFile: parseQoderCnSessionFile
@@ -9940,11 +11286,11 @@ function createQoderCnAdapter() {
9940
11286
 
9941
11287
  // src/adapters/qoder.ts
9942
11288
  import { existsSync } from "node:fs";
9943
- import { readdir as readdir9, readFile as readFile12, stat as stat10 } from "node:fs/promises";
9944
- import os10 from "node:os";
9945
- import path19 from "node:path";
11289
+ import { readdir as readdir10, readFile as readFile13, stat as stat12 } from "node:fs/promises";
11290
+ import os11 from "node:os";
11291
+ import path20 from "node:path";
9946
11292
  function parseQoderPaths(filePath) {
9947
- const parts = filePath.split(path19.sep);
11293
+ const parts = filePath.split(path20.sep);
9948
11294
  const subagentsIdx = parts.lastIndexOf("subagents");
9949
11295
  let sessionId = "";
9950
11296
  let projectName = "";
@@ -9954,17 +11300,17 @@ function parseQoderPaths(filePath) {
9954
11300
  sessionId = parts[subagentsIdx - 1];
9955
11301
  projectName = parts[subagentsIdx - 2];
9956
11302
  const projectsIdx = parts.lastIndexOf("projects");
9957
- configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
9958
- mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path19.sep);
11303
+ configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
11304
+ mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path20.sep);
9959
11305
  } else {
9960
11306
  const filename = parts.at(-1) || "";
9961
- sessionId = path19.basename(filename, ".jsonl");
11307
+ sessionId = path20.basename(filename, ".jsonl");
9962
11308
  projectName = parts.at(-2) || "";
9963
11309
  if (projectName === "transcript") {
9964
11310
  projectName = parts.at(-3) || "";
9965
11311
  }
9966
11312
  const projectsIdx = parts.lastIndexOf("projects");
9967
- configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
11313
+ configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
9968
11314
  }
9969
11315
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
9970
11316
  }
@@ -9987,7 +11333,7 @@ function rebuildEventIdentity4(event) {
9987
11333
  }
9988
11334
  async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
9989
11335
  try {
9990
- const content = await readFile12(dynamicTextsPath, "utf8");
11336
+ const content = await readFile13(dynamicTextsPath, "utf8");
9991
11337
  const json = JSON.parse(content);
9992
11338
  const texts = json.texts || {};
9993
11339
  const map = {};
@@ -10003,10 +11349,10 @@ async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
10003
11349
  }
10004
11350
  }
10005
11351
  async function loadQoderModelNames(configDir2, home) {
10006
- const map = await parseModelNamesFromDynamicTexts2(path19.join(configDir2, ".auth", "dynamic-texts.json"));
11352
+ const map = await parseModelNamesFromDynamicTexts2(path20.join(configDir2, ".auth", "dynamic-texts.json"));
10007
11353
  const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
10008
11354
  if (siblingConfigDir !== configDir2) {
10009
- const siblingMap = await parseModelNamesFromDynamicTexts2(path19.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
11355
+ const siblingMap = await parseModelNamesFromDynamicTexts2(path20.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
10010
11356
  for (const [key, val] of Object.entries(siblingMap)) {
10011
11357
  if (!(key in map)) {
10012
11358
  map[key] = val;
@@ -10014,11 +11360,11 @@ async function loadQoderModelNames(configDir2, home) {
10014
11360
  }
10015
11361
  }
10016
11362
  if (isQwenworkConfigRoot(configDir2)) {
10017
- for (const dir of [path19.join(home, ".qoder"), path19.join(home, ".qoder-cn")]) {
10018
- if (path19.resolve(dir) === path19.resolve(configDir2)) {
11363
+ for (const dir of [path20.join(home, ".qoder"), path20.join(home, ".qoder-cn")]) {
11364
+ if (path20.resolve(dir) === path20.resolve(configDir2)) {
10019
11365
  continue;
10020
11366
  }
10021
- const fallbackMap = await parseModelNamesFromDynamicTexts2(path19.join(dir, ".auth", "dynamic-texts.json"));
11367
+ const fallbackMap = await parseModelNamesFromDynamicTexts2(path20.join(dir, ".auth", "dynamic-texts.json"));
10022
11368
  for (const [key, val] of Object.entries(fallbackMap)) {
10023
11369
  if (!(key in map)) {
10024
11370
  map[key] = val;
@@ -10037,25 +11383,25 @@ async function loadQoderModelNames(configDir2, home) {
10037
11383
  return map;
10038
11384
  }
10039
11385
  function isQwenworkConfigRoot(configDir2) {
10040
- const name = path19.basename(path19.resolve(configDir2));
11386
+ const name = path20.basename(path20.resolve(configDir2));
10041
11387
  if (name === ".qwenworkcn" || name === ".qwenwork") {
10042
11388
  return true;
10043
11389
  }
10044
11390
  const override = process.env.QWENWORK_CONFIG_DIR;
10045
- return Boolean(override && override.trim() && path19.basename(path19.resolve(override)) === name);
11391
+ return Boolean(override && override.trim() && path20.basename(path20.resolve(override)) === name);
10046
11392
  }
10047
11393
  var FAILED_SEGMENT_STOP_REASONS = /* @__PURE__ */ new Set(["cancelled", "canceled", "error", "failed", "refusal"]);
10048
11394
  async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
10049
11395
  const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
10050
- const segmentsPath = path19.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
11396
+ const segmentsPath = path20.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
10051
11397
  const modelCalls = [];
10052
11398
  try {
10053
- const files = await readdir9(segmentsPath);
11399
+ const files = await readdir10(segmentsPath);
10054
11400
  for (const file of files) {
10055
11401
  if (!file.endsWith(".jsonl")) {
10056
11402
  continue;
10057
11403
  }
10058
- const content = await readFile12(path19.join(segmentsPath, file), "utf8");
11404
+ const content = await readFile13(path20.join(segmentsPath, file), "utf8");
10059
11405
  let currentTurnIsSubagent = false;
10060
11406
  for (const line of content.split("\n").filter(Boolean)) {
10061
11407
  const raw = parseJsonLine(line);
@@ -10089,7 +11435,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
10089
11435
  return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
10090
11436
  }
10091
11437
  async function parseQoderSessionFile(filePath, options) {
10092
- const text = await readFile12(filePath, "utf8");
11438
+ const text = await readFile13(filePath, "utf8");
10093
11439
  const lines = text.split("\n").filter(Boolean);
10094
11440
  const parsedPaths = parseQoderPaths(filePath);
10095
11441
  const { configDir: configDir2 } = parsedPaths;
@@ -10100,7 +11446,7 @@ async function parseQoderSessionFile(filePath, options) {
10100
11446
  let cwd;
10101
11447
  let project = projectContext.project;
10102
11448
  let model;
10103
- const home = path19.resolve(stringOption(options.home) || os10.homedir());
11449
+ const home = path20.resolve(stringOption(options.home) || os11.homedir());
10104
11450
  const modelMap = await loadQoderModelNames(configDir2, home);
10105
11451
  const qwenworkRoot = isQwenworkConfigRoot(configDir2);
10106
11452
  const isSubagentSession = filePath.includes("subagents");
@@ -10136,7 +11482,7 @@ async function parseQoderSessionFile(filePath, options) {
10136
11482
  sessionId = stringField(raw, "sessionId") || sessionId;
10137
11483
  state.sessionId = sessionId;
10138
11484
  cwd = stringField(raw, "cwd") || cwd;
10139
- project = projectContext.project || (cwd ? path19.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
11485
+ project = projectContext.project || (cwd ? path20.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
10140
11486
  if (!ts) {
10141
11487
  continue;
10142
11488
  }
@@ -10447,7 +11793,7 @@ async function parseQoderSessionFile(filePath, options) {
10447
11793
  }
10448
11794
  dbModelCalls ??= await loadQoderDbModelCalls("Qoder", parsedPaths.sessionId, modelMap);
10449
11795
  if (dbModelCalls.rootSessionId) {
10450
- const parentPath = path19.join(path19.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
11796
+ const parentPath = path20.join(path20.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
10451
11797
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
10452
11798
  return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity4({
10453
11799
  ...event,
@@ -10564,41 +11910,41 @@ function qoderExtractText(value) {
10564
11910
  }
10565
11911
  async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
10566
11912
  const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
10567
- const isSubagent = filePath.includes(`${path19.sep}subagents${path19.sep}`);
11913
+ const isSubagent = filePath.includes(`${path20.sep}subagents${path20.sep}`);
10568
11914
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
10569
11915
  let cwds = [];
10570
11916
  const workspaceDirs = [];
10571
11917
  for (const line of lines) {
10572
11918
  const raw = parseJsonLine(line);
10573
11919
  const cwd = raw ? stringField(raw, "cwd") : void 0;
10574
- if (cwd && path19.isAbsolute(cwd)) {
11920
+ if (cwd && path20.isAbsolute(cwd)) {
10575
11921
  cwds.push(cwd);
10576
11922
  }
10577
11923
  if (raw && stringField(raw, "type") === "workspace-directories") {
10578
11924
  for (const dir of arrayField5(raw, "directories")) {
10579
- if (typeof dir === "string" && path19.isAbsolute(dir)) {
11925
+ if (typeof dir === "string" && path20.isAbsolute(dir)) {
10580
11926
  workspaceDirs.push(dir);
10581
11927
  }
10582
11928
  }
10583
11929
  }
10584
11930
  }
10585
11931
  if (isSubagent) {
10586
- if (inherited?.cwd && path19.isAbsolute(inherited.cwd)) {
11932
+ if (inherited?.cwd && path20.isAbsolute(inherited.cwd)) {
10587
11933
  cwds = [inherited.cwd];
10588
11934
  } else {
10589
- const parentSessionPath = path19.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
11935
+ const parentSessionPath = path20.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
10590
11936
  try {
10591
- const parentText = await readFile12(parentSessionPath, "utf8");
11937
+ const parentText = await readFile13(parentSessionPath, "utf8");
10592
11938
  const parentCwds = [];
10593
11939
  for (const line of parentText.split("\n").filter(Boolean)) {
10594
11940
  const raw = parseJsonLine(line);
10595
11941
  const cwd = raw ? stringField(raw, "cwd") : void 0;
10596
- if (cwd && path19.isAbsolute(cwd)) {
11942
+ if (cwd && path20.isAbsolute(cwd)) {
10597
11943
  parentCwds.push(cwd);
10598
11944
  }
10599
11945
  if (workspaceDirs.length === 0 && raw && stringField(raw, "type") === "workspace-directories") {
10600
11946
  for (const dir of arrayField5(raw, "directories")) {
10601
- if (typeof dir === "string" && path19.isAbsolute(dir)) {
11947
+ if (typeof dir === "string" && path20.isAbsolute(dir)) {
10602
11948
  workspaceDirs.push(dir);
10603
11949
  }
10604
11950
  }
@@ -10618,29 +11964,29 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
10618
11964
  }
10619
11965
  }
10620
11966
  const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
10621
- const project = inherited?.project || (cwds.length > 0 ? path19.basename(cwds[0]) : root ? path19.basename(root) : await qoderProjectFromFilePath(filePath, options));
11967
+ const project = inherited?.project || (cwds.length > 0 ? path20.basename(cwds[0]) : root ? path20.basename(root) : await qoderProjectFromFilePath(filePath, options));
10622
11968
  return {
10623
11969
  project,
10624
11970
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
10625
11971
  };
10626
11972
  }
10627
11973
  function pathInsideDir(candidate, dir) {
10628
- const resolvedDir = path19.resolve(dir);
10629
- const resolved = path19.resolve(candidate);
10630
- return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path19.sep}`);
11974
+ const resolvedDir = path20.resolve(dir);
11975
+ const resolved = path20.resolve(candidate);
11976
+ return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path20.sep}`);
10631
11977
  }
10632
11978
  async function gitRootFromCwds3(cwds) {
10633
11979
  const seen = /* @__PURE__ */ new Set();
10634
11980
  for (const cwd of cwds) {
10635
- let current = path19.resolve(cwd);
11981
+ let current = path20.resolve(cwd);
10636
11982
  while (!seen.has(current)) {
10637
11983
  seen.add(current);
10638
11984
  try {
10639
- await stat10(path19.join(current, ".git"));
11985
+ await stat12(path20.join(current, ".git"));
10640
11986
  return current;
10641
11987
  } catch {
10642
11988
  }
10643
- const parent = path19.dirname(current);
11989
+ const parent = path20.dirname(current);
10644
11990
  if (parent === current) {
10645
11991
  break;
10646
11992
  }
@@ -10651,12 +11997,12 @@ async function gitRootFromCwds3(cwds) {
10651
11997
  }
10652
11998
  function qoderProjectRootFromCwds(projectDir, cwds) {
10653
11999
  for (const cwd of cwds) {
10654
- let current = path19.resolve(cwd);
12000
+ let current = path20.resolve(cwd);
10655
12001
  while (true) {
10656
12002
  if (qoderEncodedVariants(current).includes(projectDir)) {
10657
12003
  return current;
10658
12004
  }
10659
- const parent = path19.dirname(current);
12005
+ const parent = path20.dirname(current);
10660
12006
  if (parent === current) {
10661
12007
  break;
10662
12008
  }
@@ -10666,7 +12012,7 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
10666
12012
  return void 0;
10667
12013
  }
10668
12014
  function rawQoderProjectPath(value) {
10669
- return path19.resolve(value).split(path19.sep).join("-");
12015
+ return path20.resolve(value).split(path20.sep).join("-");
10670
12016
  }
10671
12017
  function qoderEncodedVariants(value) {
10672
12018
  const raw = rawQoderProjectPath(value);
@@ -10687,11 +12033,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
10687
12033
  return void 0;
10688
12034
  }
10689
12035
  async function qoderProjectFromFilePath(filePath, options) {
10690
- const projectDir = path19.basename(path19.dirname(filePath));
10691
- const home = options ? path19.resolve(stringOption(options.home) || os10.homedir()) : os10.homedir();
12036
+ const projectDir = path20.basename(path20.dirname(filePath));
12037
+ const home = options ? path20.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
10692
12038
  const resolved = await resolveQoderProjectPath(projectDir, home);
10693
12039
  if (resolved) {
10694
- return path19.basename(resolved);
12040
+ return path20.basename(resolved);
10695
12041
  }
10696
12042
  const suffix = qoderEncodedProjectSuffix(projectDir, home);
10697
12043
  if (suffix) {
@@ -10712,12 +12058,12 @@ async function resolveQoderProjectPath(projectDir, home) {
10712
12058
  while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
10713
12059
  let matchedChild;
10714
12060
  try {
10715
- const entries = await readdir9(current, { withFileTypes: true });
12061
+ const entries = await readdir10(current, { withFileTypes: true });
10716
12062
  for (const entry of entries) {
10717
12063
  if (!entry.isDirectory()) {
10718
12064
  continue;
10719
12065
  }
10720
- const candidate = path19.join(current, entry.name);
12066
+ const candidate = path20.join(current, entry.name);
10721
12067
  const candidateVariants = qoderEncodedVariants(candidate);
10722
12068
  if (candidateVariants.includes(projectDir)) {
10723
12069
  return candidate;
@@ -10762,19 +12108,19 @@ function hookConfig7() {
10762
12108
  function qoderConfigDir(home, env) {
10763
12109
  const override = env?.QODER_CONFIG_DIR;
10764
12110
  if (override && override.trim()) {
10765
- return path19.resolve(override);
12111
+ return path20.resolve(override);
10766
12112
  }
10767
- return path19.join(home, ".qoder");
12113
+ return path20.join(home, ".qoder");
10768
12114
  }
10769
12115
  function qwenworkConfigDir(home, env) {
10770
12116
  const override = env?.QWENWORK_CONFIG_DIR;
10771
12117
  if (override && override.trim()) {
10772
- return path19.resolve(override);
12118
+ return path20.resolve(override);
10773
12119
  }
10774
- return path19.join(home, ".qwenworkcn");
12120
+ return path20.join(home, ".qwenworkcn");
10775
12121
  }
10776
12122
  function qoderConfigDirs(home, env) {
10777
- return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path19.resolve(dir)))];
12123
+ return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path20.resolve(dir)))];
10778
12124
  }
10779
12125
  function createQoderAdapter() {
10780
12126
  return {
@@ -10786,11 +12132,11 @@ function createQoderAdapter() {
10786
12132
  return qoderConfigDir(home, env);
10787
12133
  },
10788
12134
  installedPath(home, env) {
10789
- return path19.join(qoderConfigDir(home, env), "settings.json");
12135
+ return path20.join(qoderConfigDir(home, env), "settings.json");
10790
12136
  },
10791
12137
  async isInstalled(home, env) {
10792
12138
  return isHooksJsonInstalled(
10793
- path19.join(qoderConfigDir(home, env), "settings.json"),
12139
+ path20.join(qoderConfigDir(home, env), "settings.json"),
10794
12140
  "vibetime hook --agent qoder"
10795
12141
  );
10796
12142
  },
@@ -10799,16 +12145,16 @@ function createQoderAdapter() {
10799
12145
  const targets = [primary, ...variants.filter((dir) => existsSync(dir))];
10800
12146
  return targets.map((base) => ({
10801
12147
  kind: "hooks-json",
10802
- path: path19.join(base, "settings.json"),
12148
+ path: path20.join(base, "settings.json"),
10803
12149
  content: hookConfig7()
10804
12150
  }));
10805
12151
  },
10806
12152
  sourcePaths(home, env) {
10807
- const paths = qoderConfigDirs(home, env).map((base2) => path19.join(base2, "projects"));
12153
+ const paths = qoderConfigDirs(home, env).map((base2) => path20.join(base2, "projects"));
10808
12154
  const base = qoderConfigDir(home, env);
10809
12155
  paths.push(
10810
- path19.join(base, ".qoder.json"),
10811
- path19.join(home, ".qoder.json")
12156
+ path20.join(base, ".qoder.json"),
12157
+ path20.join(home, ".qoder.json")
10812
12158
  );
10813
12159
  return paths;
10814
12160
  },
@@ -10844,27 +12190,27 @@ function normalizeId(id) {
10844
12190
  }
10845
12191
 
10846
12192
  // src/adapters/workbuddy.ts
10847
- import { readdir as readdir10, readFile as readFile13, stat as stat11 } from "node:fs/promises";
10848
- import path20 from "node:path";
12193
+ import { readdir as readdir11, readFile as readFile14, stat as stat13 } from "node:fs/promises";
12194
+ import path21 from "node:path";
10849
12195
  function workbuddyProjectsDir(home, env) {
10850
12196
  const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
10851
12197
  if (override && override.trim()) {
10852
- return path20.resolve(override, override.endsWith("projects") ? "" : "projects");
12198
+ return path21.resolve(override, override.endsWith("projects") ? "" : "projects");
10853
12199
  }
10854
- return path20.join(home, ".workbuddy", "projects");
12200
+ return path21.join(home, ".workbuddy", "projects");
10855
12201
  }
10856
12202
  function workbuddyBaseDir(home, env) {
10857
12203
  const override = env?.WORKBUDDY_HOME;
10858
12204
  if (override && override.trim()) {
10859
- return path20.resolve(override);
12205
+ return path21.resolve(override);
10860
12206
  }
10861
- return path20.join(home, ".workbuddy");
12207
+ return path21.join(home, ".workbuddy");
10862
12208
  }
10863
12209
  function projectFromCwd(cwd, fallback) {
10864
12210
  if (!cwd) {
10865
12211
  return fallback;
10866
12212
  }
10867
- return path20.basename(cwd) || fallback;
12213
+ return path21.basename(cwd) || fallback;
10868
12214
  }
10869
12215
  function sourceHash(filePath) {
10870
12216
  return `sha256:${createStableHash(filePath)}`;
@@ -10982,7 +12328,7 @@ function toolCallFailed(record) {
10982
12328
  return status === "failed" || status === "incomplete" || record.is_error === true || providerData.error != null || providerData.isError === true;
10983
12329
  }
10984
12330
  async function readWorkbuddyLines(filePath) {
10985
- const text = await readFile13(filePath, "utf8");
12331
+ const text = await readFile14(filePath, "utf8");
10986
12332
  return text.split(/\r?\n/).map((line, index) => {
10987
12333
  if (!line.trim()) {
10988
12334
  return void 0;
@@ -11002,8 +12348,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
11002
12348
  }
11003
12349
  const events = [];
11004
12350
  const first = lines[0].record;
11005
- const sessionId = stringField(first, "sessionId") || path20.basename(filePath, ".jsonl");
11006
- const fallbackProject = path20.basename(path20.dirname(filePath));
12351
+ const sessionId = stringField(first, "sessionId") || path21.basename(filePath, ".jsonl");
12352
+ const fallbackProject = path21.basename(path21.dirname(filePath));
11007
12353
  const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
11008
12354
  const project = projectFromCwd(cwd, fallbackProject);
11009
12355
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
@@ -11287,17 +12633,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
11287
12633
  const base = sourceRoot || workbuddyProjectsDir(home, env);
11288
12634
  const files = [];
11289
12635
  try {
11290
- const projects = await readdir10(base, { withFileTypes: true });
12636
+ const projects = await readdir11(base, { withFileTypes: true });
11291
12637
  for (const project of projects) {
11292
12638
  if (!project.isDirectory()) {
11293
12639
  continue;
11294
12640
  }
11295
- const projectDir = path20.join(base, project.name);
11296
- const entries = await readdir10(projectDir, { withFileTypes: true });
12641
+ const projectDir = path21.join(base, project.name);
12642
+ const entries = await readdir11(projectDir, { withFileTypes: true });
11297
12643
  for (const entry of entries) {
11298
12644
  if (entry.isFile() && entry.name.endsWith(".jsonl")) {
11299
- const filePath = path20.join(projectDir, entry.name);
11300
- const info = await stat11(filePath);
12645
+ const filePath = path21.join(projectDir, entry.name);
12646
+ const info = await stat13(filePath);
11301
12647
  files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
11302
12648
  }
11303
12649
  }
@@ -11334,18 +12680,18 @@ function createWorkbuddyAdapter() {
11334
12680
  return workbuddyProjectsDir(home, env);
11335
12681
  },
11336
12682
  installedPath(home, env) {
11337
- return path20.join(workbuddyBaseDir(home, env), "settings.json");
12683
+ return path21.join(workbuddyBaseDir(home, env), "settings.json");
11338
12684
  },
11339
12685
  async isInstalled(home, env) {
11340
12686
  return isHooksJsonInstalled(
11341
- path20.join(workbuddyBaseDir(home, env), "settings.json"),
12687
+ path21.join(workbuddyBaseDir(home, env), "settings.json"),
11342
12688
  "vibetime hook --agent workbuddy"
11343
12689
  );
11344
12690
  },
11345
12691
  installEntries(home, env) {
11346
12692
  return [{
11347
12693
  kind: "hooks-json",
11348
- path: path20.join(workbuddyBaseDir(home, env), "settings.json"),
12694
+ path: path21.join(workbuddyBaseDir(home, env), "settings.json"),
11349
12695
  content: hookConfig8()
11350
12696
  }];
11351
12697
  },
@@ -11358,26 +12704,26 @@ function createWorkbuddyAdapter() {
11358
12704
 
11359
12705
  // src/adapters/zcode.ts
11360
12706
  import { execFile } from "node:child_process";
11361
- import { readFile as readFile14, stat as stat12 } from "node:fs/promises";
11362
- import path21 from "node:path";
12707
+ import { readFile as readFile15, stat as stat14 } from "node:fs/promises";
12708
+ import path22 from "node:path";
11363
12709
  import { promisify as promisify2 } from "node:util";
11364
12710
  init_fs();
11365
12711
  var execFileAsync = promisify2(execFile);
11366
12712
  function zcodeCliDir(home, env) {
11367
12713
  const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
11368
12714
  if (override && override.trim()) {
11369
- return path21.resolve(override, override.endsWith("cli") ? "" : "cli");
12715
+ return path22.resolve(override, override.endsWith("cli") ? "" : "cli");
11370
12716
  }
11371
- return path21.join(home, ".zcode", "cli");
12717
+ return path22.join(home, ".zcode", "cli");
11372
12718
  }
11373
12719
  function zcodeDbPath(home, env) {
11374
- return path21.join(zcodeCliDir(home, env), "db", "db.sqlite");
12720
+ return path22.join(zcodeCliDir(home, env), "db", "db.sqlite");
11375
12721
  }
11376
12722
  var providerNameCache = null;
11377
12723
  async function loadProviderNames(configPath2) {
11378
12724
  let fileMtime = 0;
11379
12725
  try {
11380
- const info = await stat12(configPath2);
12726
+ const info = await stat14(configPath2);
11381
12727
  fileMtime = info.mtimeMs;
11382
12728
  } catch {
11383
12729
  return /* @__PURE__ */ new Map();
@@ -11387,7 +12733,7 @@ async function loadProviderNames(configPath2) {
11387
12733
  }
11388
12734
  const map = /* @__PURE__ */ new Map();
11389
12735
  try {
11390
- const raw = await readFile14(configPath2, "utf-8");
12736
+ const raw = await readFile15(configPath2, "utf-8");
11391
12737
  const config = JSON.parse(raw);
11392
12738
  const providers = config?.provider;
11393
12739
  if (isPlainObject(providers)) {
@@ -11405,7 +12751,7 @@ function sourceHash2(filePath) {
11405
12751
  return `sha256:${createStableHash(filePath)}`;
11406
12752
  }
11407
12753
  function projectFromDirectory(directory) {
11408
- return directory ? path21.basename(directory) || "zcode" : "zcode";
12754
+ return directory ? path22.basename(directory) || "zcode" : "zcode";
11409
12755
  }
11410
12756
  function isoFromMs(value) {
11411
12757
  return timestampFrom(typeof value === "number" ? value : Number(value));
@@ -11589,16 +12935,16 @@ async function parseZCodeDb(filePath, options) {
11589
12935
  if (rows.length === 0) {
11590
12936
  return [];
11591
12937
  }
11592
- let candidate = path21.resolve(filePath);
12938
+ let candidate = path22.resolve(filePath);
11593
12939
  let configPath2 = "";
11594
12940
  for (let i = 0; i < 12; i++) {
11595
- const probe = path21.join(candidate, ".zcode", "v2", "config.json");
12941
+ const probe = path22.join(candidate, ".zcode", "v2", "config.json");
11596
12942
  try {
11597
- await stat12(probe);
12943
+ await stat14(probe);
11598
12944
  configPath2 = probe;
11599
12945
  break;
11600
12946
  } catch {
11601
- const parent = path21.dirname(candidate);
12947
+ const parent = path22.dirname(candidate);
11602
12948
  if (parent === candidate) break;
11603
12949
  candidate = parent;
11604
12950
  }
@@ -11818,9 +13164,9 @@ async function parseZCodeDb(filePath, options) {
11818
13164
  }
11819
13165
  async function zcodeBackfillFiles(sourceRoot, home, env) {
11820
13166
  const candidate = sourceRoot || zcodeDbPath(home, env);
11821
- const filePath = candidate.endsWith(".sqlite") ? candidate : path21.join(candidate, "db", "db.sqlite");
13167
+ const filePath = candidate.endsWith(".sqlite") ? candidate : path22.join(candidate, "db", "db.sqlite");
11822
13168
  try {
11823
- const info = await stat12(filePath);
13169
+ const info = await stat14(filePath);
11824
13170
  return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
11825
13171
  } catch {
11826
13172
  return [];
@@ -11852,50 +13198,50 @@ function createZCodeAdapter() {
11852
13198
  }
11853
13199
 
11854
13200
  // src/adapters/zed.ts
11855
- import os11 from "node:os";
11856
- import path22 from "node:path";
13201
+ import os12 from "node:os";
13202
+ import path23 from "node:path";
11857
13203
  function zedThreadsCandidates(home, env) {
11858
13204
  const candidates = [];
11859
13205
  const platform2 = process.platform;
11860
13206
  if (platform2 === "darwin") {
11861
- candidates.push(path22.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
13207
+ candidates.push(path23.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
11862
13208
  } else if (platform2 === "win32") {
11863
13209
  const appdata = env?.APPDATA;
11864
13210
  if (appdata && appdata.trim()) {
11865
- candidates.push(path22.join(path22.resolve(appdata), "Zed", "threads", "threads.db"));
13211
+ candidates.push(path23.join(path23.resolve(appdata), "Zed", "threads", "threads.db"));
11866
13212
  }
11867
- candidates.push(path22.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
13213
+ candidates.push(path23.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
11868
13214
  } else {
11869
13215
  const xdgData = env?.XDG_DATA_HOME;
11870
13216
  if (xdgData && xdgData.trim()) {
11871
- candidates.push(path22.join(path22.resolve(xdgData), "zed", "threads", "threads.db"));
13217
+ candidates.push(path23.join(path23.resolve(xdgData), "zed", "threads", "threads.db"));
11872
13218
  }
11873
- candidates.push(path22.join(home, ".local", "share", "zed", "threads", "threads.db"));
13219
+ candidates.push(path23.join(home, ".local", "share", "zed", "threads", "threads.db"));
11874
13220
  const xdgConfig = env?.XDG_CONFIG_HOME;
11875
13221
  if (xdgConfig && xdgConfig.trim()) {
11876
- candidates.push(path22.join(path22.resolve(xdgConfig), "zed", "threads", "threads.db"));
13222
+ candidates.push(path23.join(path23.resolve(xdgConfig), "zed", "threads", "threads.db"));
11877
13223
  }
11878
- candidates.push(path22.join(home, ".config", "zed", "threads", "threads.db"));
13224
+ candidates.push(path23.join(home, ".config", "zed", "threads", "threads.db"));
11879
13225
  }
11880
13226
  return candidates;
11881
13227
  }
11882
13228
  function zedConfigDir(home, env) {
11883
13229
  const platform2 = process.platform;
11884
13230
  if (platform2 === "darwin") {
11885
- return path22.join(home, "Library", "Application Support", "Zed");
13231
+ return path23.join(home, "Library", "Application Support", "Zed");
11886
13232
  }
11887
13233
  if (platform2 === "win32") {
11888
13234
  const appdata = env?.APPDATA;
11889
13235
  if (appdata && appdata.trim()) {
11890
- return path22.join(path22.resolve(appdata), "Zed");
13236
+ return path23.join(path23.resolve(appdata), "Zed");
11891
13237
  }
11892
- return path22.join(home, "AppData", "Roaming", "Zed");
13238
+ return path23.join(home, "AppData", "Roaming", "Zed");
11893
13239
  }
11894
13240
  const xdgConfig = env?.XDG_CONFIG_HOME;
11895
13241
  if (xdgConfig && xdgConfig.trim()) {
11896
- return path22.join(path22.resolve(xdgConfig), "zed");
13242
+ return path23.join(path23.resolve(xdgConfig), "zed");
11897
13243
  }
11898
- return path22.join(home, ".config", "zed");
13244
+ return path23.join(home, ".config", "zed");
11899
13245
  }
11900
13246
  function baseZedEvent(event) {
11901
13247
  return {
@@ -11959,7 +13305,7 @@ async function parseZedSessionFile(dbPath, options) {
11959
13305
  const folderRaw = row.folder_paths || "";
11960
13306
  const folder = folderRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
11961
13307
  const cwd = folder || void 0;
11962
- const project = cwd ? path22.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
13308
+ const project = cwd ? path23.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
11963
13309
  let json;
11964
13310
  try {
11965
13311
  const bytes = row.data_type === "zstd" ? decompress2(new Uint8Array(row.data)) : new Uint8Array(row.data);
@@ -12204,20 +13550,20 @@ async function parseZedSessionFile(dbPath, options) {
12204
13550
  }
12205
13551
  return events.filter((event) => matchesBackfillFilters(event, options));
12206
13552
  }
12207
- async function zedBackfillFiles(sourceRoot, home = os11.homedir(), env) {
12208
- const { stat: stat15 } = await import("node:fs/promises");
13553
+ async function zedBackfillFiles(sourceRoot, home = os12.homedir(), env) {
13554
+ const { stat: stat17 } = await import("node:fs/promises");
12209
13555
  if (sourceRoot) {
12210
13556
  if (!sourceRoot.endsWith(".db")) {
12211
13557
  return [];
12212
13558
  }
12213
- const info = await stat15(sourceRoot).catch(() => null);
13559
+ const info = await stat17(sourceRoot).catch(() => null);
12214
13560
  if (!info) {
12215
13561
  return [];
12216
13562
  }
12217
13563
  return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
12218
13564
  }
12219
13565
  for (const candidatePath of zedThreadsCandidates(home, env)) {
12220
- const info = await stat15(candidatePath).catch(() => null);
13566
+ const info = await stat17(candidatePath).catch(() => null);
12221
13567
  if (info) {
12222
13568
  return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
12223
13569
  }
@@ -12234,7 +13580,7 @@ function createZedAdapter() {
12234
13580
  return zedConfigDir(home, env);
12235
13581
  },
12236
13582
  installedPath(home, env) {
12237
- return path22.join(zedConfigDir(home, env), "vibetime-marker");
13583
+ return path23.join(zedConfigDir(home, env), "vibetime-marker");
12238
13584
  },
12239
13585
  async isInstalled() {
12240
13586
  return false;
@@ -12609,6 +13955,10 @@ async function installEntry(entry, options) {
12609
13955
  await mergeHooksJson(entry.path, entry.content, options);
12610
13956
  return;
12611
13957
  }
13958
+ if (entry.kind === "cursor-hooks-json" && typeof entry.content === "object") {
13959
+ await mergeCursorHooksFile(entry.path, entry.content, options);
13960
+ return;
13961
+ }
12612
13962
  if (entry.kind === "hooks-toml" && typeof entry.content === "object") {
12613
13963
  await mergeHooksToml(entry.path, entry.content, options);
12614
13964
  return;
@@ -12623,6 +13973,10 @@ async function uninstallEntry(entry, options) {
12623
13973
  await uninstallHooksToml(entry.path, entry.content, options);
12624
13974
  return;
12625
13975
  }
13976
+ if (entry.kind === "cursor-hooks-json" && typeof entry.content === "object") {
13977
+ await uninstallCursorHooksFile(entry.path, entry.content, options);
13978
+ return;
13979
+ }
12626
13980
  if (entry.kind === "hooks-json" && typeof entry.content === "object") {
12627
13981
  await uninstallHooksJson(entry.path, entry.content, options);
12628
13982
  return;
@@ -12655,6 +14009,67 @@ async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
12655
14009
  await writeFile5(filePath, nextText, "utf8");
12656
14010
  onWrite(`Installed ${filePath}`);
12657
14011
  }
14012
+ async function mergeCursorHooksFile(filePath, content, { dryRun, force, onWrite }) {
14013
+ const { mkdir: mkdir6, writeFile: writeFile5 } = await import("node:fs/promises");
14014
+ const pathMod = await import("node:path");
14015
+ if (dryRun) {
14016
+ onWrite(`Would merge ${filePath}`);
14017
+ return;
14018
+ }
14019
+ const existingText = await readTextIfExists(filePath);
14020
+ const existing = existingText ? JSON.parse(existingText) : {};
14021
+ if (existingText !== null && !isPlainObject(existing) && !force) {
14022
+ throw new Error(
14023
+ `Refusing to update non-object JSON file: ${filePath}. Re-run with --force if this is intentional.`
14024
+ );
14025
+ }
14026
+ const merged = mergeCursorHooksJson(existing, content);
14027
+ const nextText = `${JSON.stringify(merged, null, 2)}
14028
+ `;
14029
+ if (existingText === nextText) {
14030
+ onWrite(`Already installed ${filePath}`);
14031
+ return;
14032
+ }
14033
+ await mkdir6(pathMod.dirname(filePath), { recursive: true });
14034
+ await writeFile5(filePath, nextText, "utf8");
14035
+ onWrite(`Installed ${filePath}`);
14036
+ }
14037
+ async function uninstallCursorHooksFile(filePath, content, { dryRun, onWrite }) {
14038
+ const existingText = await readTextIfExists(filePath);
14039
+ if (existingText === null) {
14040
+ onWrite(`Already uninstalled ${filePath}`);
14041
+ return;
14042
+ }
14043
+ let existing;
14044
+ try {
14045
+ existing = JSON.parse(existingText);
14046
+ } catch {
14047
+ onWrite(`Skipped non-JSON file ${filePath}`);
14048
+ return;
14049
+ }
14050
+ if (!isPlainObject(existing)) {
14051
+ onWrite(`Skipped non-object JSON file ${filePath}`);
14052
+ return;
14053
+ }
14054
+ const commands = new Set(collectCursorHookCommands(content));
14055
+ if (commands.size === 0) {
14056
+ onWrite(`Already uninstalled ${filePath}`);
14057
+ return;
14058
+ }
14059
+ const { next, changed } = stripCursorHookCommands(existing, commands);
14060
+ if (!changed) {
14061
+ onWrite(`Already uninstalled ${filePath}`);
14062
+ return;
14063
+ }
14064
+ if (dryRun) {
14065
+ onWrite(`Would uninstall ${filePath}`);
14066
+ return;
14067
+ }
14068
+ const { writeFile: writeFile5 } = await import("node:fs/promises");
14069
+ await writeFile5(filePath, `${JSON.stringify(next, null, 2)}
14070
+ `, "utf8");
14071
+ onWrite(`Uninstalled ${filePath}`);
14072
+ }
12658
14073
  function mergeAgyHooksJson(existing, addition) {
12659
14074
  const merged = structuredClone(isPlainObject(existing) ? existing : {});
12660
14075
  const additionObject = isPlainObject(addition) ? addition : {};
@@ -12942,15 +14357,15 @@ async function uninstallGeneratedFile(filePath, { dryRun, onWrite }) {
12942
14357
  import { randomUUID } from "node:crypto";
12943
14358
  import { existsSync as existsSync2, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
12944
14359
  import { homedir, hostname } from "node:os";
12945
- import path23 from "node:path";
14360
+ import path24 from "node:path";
12946
14361
  function configDir(home = homedir()) {
12947
- return path23.join(home, ".vibetime");
14362
+ return path24.join(home, ".vibetime");
12948
14363
  }
12949
14364
  function configPath(home = homedir()) {
12950
- return path23.join(configDir(home), "config.json");
14365
+ return path24.join(configDir(home), "config.json");
12951
14366
  }
12952
14367
  function machineIdPath(home = homedir()) {
12953
- return path23.join(configDir(home), "machine-id");
14368
+ return path24.join(configDir(home), "machine-id");
12954
14369
  }
12955
14370
  function readConfig(home = homedir()) {
12956
14371
  const file = configPath(home);
@@ -12997,15 +14412,15 @@ function defaultMachineName() {
12997
14412
  init_fs();
12998
14413
 
12999
14414
  // src/lib/logger.ts
13000
- import { appendFile, mkdir as mkdir4, rename, stat as stat13 } from "node:fs/promises";
14415
+ import { appendFile, mkdir as mkdir4, rename, stat as stat15 } from "node:fs/promises";
13001
14416
  import { homedir as homedir2 } from "node:os";
13002
- import path24 from "node:path";
14417
+ import path25 from "node:path";
13003
14418
  var MAX_BYTES = 1 * 1024 * 1024;
13004
14419
  function logDir(home = homedir2()) {
13005
- return path24.join(home, ".vibetime", "logs");
14420
+ return path25.join(home, ".vibetime", "logs");
13006
14421
  }
13007
14422
  function logPath(home = homedir2(), name = "cli.log") {
13008
- return path24.join(logDir(home), name);
14423
+ return path25.join(logDir(home), name);
13009
14424
  }
13010
14425
  function serializeError(error) {
13011
14426
  if (error instanceof Error) {
@@ -13015,7 +14430,7 @@ function serializeError(error) {
13015
14430
  }
13016
14431
  async function rotateIfNeeded(file) {
13017
14432
  try {
13018
- const info = await stat13(file);
14433
+ const info = await stat15(file);
13019
14434
  if (info.size > MAX_BYTES) {
13020
14435
  await rename(file, `${file}.1`).catch(() => {
13021
14436
  });
@@ -13180,8 +14595,8 @@ function buildHeaders(token, machine) {
13180
14595
  ...machine?.platform ? { "x-machine-platform": machine.platform } : {}
13181
14596
  };
13182
14597
  }
13183
- function joinUrl(base, path26) {
13184
- return new URL(path26, base.endsWith("/") ? base : `${base}/`).toString();
14598
+ function joinUrl(base, path27) {
14599
+ return new URL(path27, base.endsWith("/") ? base : `${base}/`).toString();
13185
14600
  }
13186
14601
  async function postRollupBatch(remote, rollups, options = {}) {
13187
14602
  const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
@@ -13271,6 +14686,7 @@ function createRegistry() {
13271
14686
  registry.register(createGrokBuildAdapter());
13272
14687
  registry.register(createZedAdapter());
13273
14688
  registry.register(createKimiCodeAdapter());
14689
+ registry.register(createCursorAdapter());
13274
14690
  return registry;
13275
14691
  }
13276
14692
  var defaultContext = {
@@ -13828,6 +15244,9 @@ async function listBackfillSourceFiles(source, options, ctx) {
13828
15244
  if (source.id === "zed") {
13829
15245
  return zedBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
13830
15246
  }
15247
+ if (source.id === "cursor") {
15248
+ return cursorBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
15249
+ }
13831
15250
  if (source.id === "pi") {
13832
15251
  return piBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
13833
15252
  }
@@ -13835,7 +15254,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
13835
15254
  const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
13836
15255
  const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
13837
15256
  return Promise.all(files.map(async (filePath) => {
13838
- const info = await stat14(filePath);
15257
+ const info = await stat16(filePath);
13839
15258
  return { path: filePath, modifiedAt: info.mtime.toISOString() };
13840
15259
  }));
13841
15260
  }
@@ -14167,13 +15586,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
14167
15586
  return picked;
14168
15587
  }
14169
15588
  function backfillIncrementalStatePath(home) {
14170
- return path25.join(home, ".vibetime", "backfill-state.json");
15589
+ return path26.join(home, ".vibetime", "backfill-state.json");
14171
15590
  }
14172
15591
  function syncLocalTriggerStatePath(home) {
14173
- return path25.join(home, ".vibetime", "sync-local-trigger.json");
15592
+ return path26.join(home, ".vibetime", "sync-local-trigger.json");
14174
15593
  }
14175
15594
  function syncLocalTriggerLockPath(home) {
14176
- return path25.join(home, ".vibetime", "sync-local-trigger.lock");
15595
+ return path26.join(home, ".vibetime", "sync-local-trigger.lock");
14177
15596
  }
14178
15597
  function backfillRemoteKey(baseUrl) {
14179
15598
  try {
@@ -14235,7 +15654,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
14235
15654
  }
14236
15655
  async function writeBackfillIncrementalStateFile(home, file) {
14237
15656
  const statePath = backfillIncrementalStatePath(home);
14238
- await mkdir5(path25.dirname(statePath), { recursive: true });
15657
+ await mkdir5(path26.dirname(statePath), { recursive: true });
14239
15658
  await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
14240
15659
  `, "utf8");
14241
15660
  }
@@ -14284,7 +15703,7 @@ async function readSyncLocalTriggerState(statePath) {
14284
15703
  return nextState;
14285
15704
  }
14286
15705
  async function writeSyncLocalTriggerState(statePath, state) {
14287
- await mkdir5(path25.dirname(statePath), { recursive: true });
15706
+ await mkdir5(path26.dirname(statePath), { recursive: true });
14288
15707
  await writeFile4(statePath, `${JSON.stringify(state, null, 2)}
14289
15708
  `, "utf8");
14290
15709
  }
@@ -14299,12 +15718,12 @@ async function readSyncLocalLock(lockPath) {
14299
15718
  return { pid: lock.pid, startedAt: lock.startedAt };
14300
15719
  }
14301
15720
  async function writeSyncLocalLock(lockPath, lock) {
14302
- await mkdir5(path25.dirname(lockPath), { recursive: true });
15721
+ await mkdir5(path26.dirname(lockPath), { recursive: true });
14303
15722
  await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
14304
15723
  `, "utf8");
14305
15724
  }
14306
15725
  async function acquireSyncLocalLock(lockPath, lock) {
14307
- await mkdir5(path25.dirname(lockPath), { recursive: true });
15726
+ await mkdir5(path26.dirname(lockPath), { recursive: true });
14308
15727
  try {
14309
15728
  const handle = await open(lockPath, "wx");
14310
15729
  try {
@@ -14384,10 +15803,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
14384
15803
  if (cliPath.endsWith(".ts")) {
14385
15804
  return ["--import", "tsx", cliPath];
14386
15805
  }
14387
- return [path25.resolve(path25.dirname(cliPath), "../bin/vibetime.mjs")];
15806
+ return [path26.resolve(path26.dirname(cliPath), "../bin/vibetime.mjs")];
14388
15807
  }
14389
15808
  function resolveHome3(options, ctx) {
14390
- return path25.resolve(stringOption(options.home) || ctx.env.HOME || os12.homedir());
15809
+ return path26.resolve(stringOption(options.home) || ctx.env.HOME || os13.homedir());
14391
15810
  }
14392
15811
  function requestedTargets(options) {
14393
15812
  const value = options.target || options.targets;