@yhong91/vibetime 0.1.56 → 0.1.57

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 +1614 -335
  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 stat15, 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.57" : "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 stat16 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
5015
+ files.push({ path: filePath, modifiedAt: stat16.mtime.toISOString(), groupId: pidDir.name });
5016
5016
  } catch {
5017
5017
  }
5018
5018
  }
@@ -6168,95 +6168,1301 @@ function baseCopilotEvent(event) {
6168
6168
  ...event
6169
6169
  };
6170
6170
  }
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 [];
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 [];
6179
+ }
6180
+ for (const entry of entries) {
6181
+ if (entry.startsWith("pending-session")) {
6182
+ continue;
6183
+ }
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() });
6188
+ }
6189
+ }
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
+ `;
6198
+ }
6199
+ function copilotHome(home, env) {
6200
+ const override = env?.COPILOT_HOME;
6201
+ if (override && override.trim()) {
6202
+ return path12.resolve(override);
6203
+ }
6204
+ return path12.join(home, ".copilot");
6205
+ }
6206
+ function createCopilotAdapter() {
6207
+ return {
6208
+ id: "copilot",
6209
+ label: "GitHub Copilot",
6210
+ agentName: "copilot",
6211
+ kind: "agent",
6212
+ detectPath(home, env) {
6213
+ return copilotHome(home, env);
6214
+ },
6215
+ installedPath(home, env) {
6216
+ return path12.join(copilotHome(home, env), ".vibetime");
6217
+ },
6218
+ 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
+ }
6225
+ },
6226
+ installEntries(home, env) {
6227
+ return [{
6228
+ kind: "file",
6229
+ path: path12.join(copilotHome(home, env), ".vibetime"),
6230
+ content: copilotPluginContent()
6231
+ }];
6232
+ },
6233
+ sourcePaths(home, env) {
6234
+ return [path12.join(copilotHome(home, env), "session-state")];
6235
+ },
6236
+ parseSessionFile: parseCopilotSessionFile
6237
+ };
6238
+ }
6239
+
6240
+ // src/adapters/cursor.ts
6241
+ import { copyFile, readdir as readdir6, readFile as readFile8, stat as stat7 } from "node:fs/promises";
6242
+ import os6 from "node:os";
6243
+ import path13 from "node:path";
6244
+
6245
+ // src/lib/cursor-hooks.ts
6246
+ function isCursorHooksFile(value) {
6247
+ if (!isPlainObject(value)) {
6248
+ return false;
6249
+ }
6250
+ if (value.version !== 1 && value.version !== void 0) {
6251
+ return false;
6252
+ }
6253
+ return isPlainObject(value.hooks);
6254
+ }
6255
+ function hookCommandFromCursorEntry(entry) {
6256
+ if (!isPlainObject(entry) || typeof entry.command !== "string" || !entry.command) {
6257
+ return void 0;
6258
+ }
6259
+ return entry.command;
6260
+ }
6261
+ function hasCursorHookCommand(config, command) {
6262
+ if (!isCursorHooksFile(config)) {
6263
+ return false;
6264
+ }
6265
+ return Object.values(config.hooks).some(
6266
+ (entries) => Array.isArray(entries) && entries.some((entry) => hookCommandFromCursorEntry(entry) === command)
6267
+ );
6268
+ }
6269
+ function mergeCursorHooksJson(existing, addition) {
6270
+ const mergedHooks = {};
6271
+ const existingHooks = isCursorHooksFile(existing) ? existing.hooks : {};
6272
+ for (const [event, entries] of Object.entries(existingHooks)) {
6273
+ if (Array.isArray(entries)) {
6274
+ mergedHooks[event] = [...entries];
6275
+ }
6276
+ }
6277
+ for (const [event, entries] of Object.entries(addition.hooks)) {
6278
+ const current = mergedHooks[event] ? [...mergedHooks[event]] : [];
6279
+ for (const entry of entries) {
6280
+ const command = hookCommandFromCursorEntry(entry);
6281
+ if (!command) {
6282
+ continue;
6283
+ }
6284
+ const alreadyPresent = current.some(
6285
+ (existingEntry) => hookCommandFromCursorEntry(existingEntry) === command
6286
+ );
6287
+ if (!alreadyPresent) {
6288
+ current.push(entry);
6289
+ }
6290
+ }
6291
+ mergedHooks[event] = current;
6292
+ }
6293
+ const extra = isPlainObject(existing) ? Object.fromEntries(
6294
+ Object.entries(existing).filter(([key]) => key !== "version" && key !== "hooks")
6295
+ ) : {};
6296
+ return {
6297
+ ...extra,
6298
+ version: 1,
6299
+ hooks: mergedHooks
6300
+ };
6301
+ }
6302
+ function stripCursorHookCommands(existing, commands) {
6303
+ const next = structuredClone(isPlainObject(existing) ? existing : {});
6304
+ if (!isPlainObject(next.hooks)) {
6305
+ return { next, changed: false };
6306
+ }
6307
+ const hooks = { ...next.hooks };
6308
+ let changed = false;
6309
+ for (const [event, entries] of Object.entries(hooks)) {
6310
+ if (!Array.isArray(entries)) {
6311
+ continue;
6312
+ }
6313
+ const stripped = entries.filter((entry) => {
6314
+ const command = hookCommandFromCursorEntry(entry);
6315
+ return !command || !commands.has(command);
6316
+ });
6317
+ if (stripped.length !== entries.length) {
6318
+ changed = true;
6319
+ }
6320
+ if (stripped.length === 0) {
6321
+ delete hooks[event];
6322
+ } else {
6323
+ hooks[event] = stripped;
6324
+ }
6325
+ }
6326
+ if (Object.keys(hooks).length === 0) {
6327
+ delete next.hooks;
6328
+ changed = true;
6329
+ } else {
6330
+ next.hooks = hooks;
6331
+ }
6332
+ return { next, changed };
6333
+ }
6334
+ function collectCursorHookCommands(content) {
6335
+ const commands = /* @__PURE__ */ new Set();
6336
+ for (const entries of Object.values(content.hooks)) {
6337
+ for (const entry of entries) {
6338
+ const command = hookCommandFromCursorEntry(entry);
6339
+ if (command) {
6340
+ commands.add(command);
6341
+ }
6342
+ }
6343
+ }
6344
+ return [...commands];
6345
+ }
6346
+
6347
+ // src/adapters/cursor.ts
6348
+ init_fs();
6349
+ var SOURCE_ID = "cursor";
6350
+ var AGENT_NAME = "cursor";
6351
+ var HOOK_COMMAND = `vibetime hook --agent ${SOURCE_ID}`;
6352
+ var HOOK_TIMEOUT_SECONDS = 10;
6353
+ var BUBBLE_USER = 1;
6354
+ var CAPABILITY_TOOL = 15;
6355
+ var CURSOR_HOOK_EVENTS = [
6356
+ "sessionStart",
6357
+ "sessionEnd",
6358
+ "beforeSubmitPrompt",
6359
+ "preToolUse",
6360
+ "postToolUse",
6361
+ "postToolUseFailure",
6362
+ "subagentStart",
6363
+ "subagentStop",
6364
+ "stop",
6365
+ "afterFileEdit",
6366
+ "afterShellExecution",
6367
+ "preCompact"
6368
+ ];
6369
+ function cursorHome(home, env) {
6370
+ const override = env?.CURSOR_HOME;
6371
+ if (override && override.trim()) {
6372
+ return path13.resolve(override);
6373
+ }
6374
+ return path13.join(home, ".cursor");
6375
+ }
6376
+ function cursorHooksPath(home, env) {
6377
+ return path13.join(cursorHome(home, env), "hooks.json");
6378
+ }
6379
+ function cursorProjectsDir(home, env) {
6380
+ return path13.join(cursorHome(home, env), "projects");
6381
+ }
6382
+ function cursorChatsDir(home, env) {
6383
+ return path13.join(cursorHome(home, env), "chats");
6384
+ }
6385
+ function cursorUserDir(home, env) {
6386
+ const override = env?.CURSOR_USER_DIR;
6387
+ if (override && override.trim()) {
6388
+ return path13.resolve(override);
6389
+ }
6390
+ return void 0;
6391
+ }
6392
+ function cursorStateDbCandidates(home, env) {
6393
+ const candidates = [];
6394
+ const userDir = cursorUserDir(home, env);
6395
+ if (userDir) {
6396
+ candidates.push(path13.join(userDir, "globalStorage", "state.vscdb"));
6397
+ }
6398
+ const platform2 = process.platform;
6399
+ if (platform2 === "darwin") {
6400
+ candidates.push(path13.join(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb"));
6401
+ } else if (platform2 === "win32") {
6402
+ const appdata = env?.APPDATA;
6403
+ if (appdata && appdata.trim()) {
6404
+ candidates.push(path13.join(path13.resolve(appdata), "Cursor", "User", "globalStorage", "state.vscdb"));
6405
+ }
6406
+ candidates.push(path13.join(home, "AppData", "Roaming", "Cursor", "User", "globalStorage", "state.vscdb"));
6407
+ } else {
6408
+ const xdgConfig = env?.XDG_CONFIG_HOME;
6409
+ if (xdgConfig && xdgConfig.trim()) {
6410
+ candidates.push(path13.join(path13.resolve(xdgConfig), "Cursor", "User", "globalStorage", "state.vscdb"));
6411
+ }
6412
+ candidates.push(path13.join(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb"));
6413
+ }
6414
+ return candidates;
6415
+ }
6416
+ function decodeKv(value) {
6417
+ if (typeof value === "string") {
6418
+ return value;
6419
+ }
6420
+ if (value instanceof Uint8Array) {
6421
+ return new TextDecoder().decode(value);
6422
+ }
6423
+ return void 0;
6424
+ }
6425
+ function parseJsonObject(text) {
6426
+ if (!text) {
6427
+ return void 0;
6428
+ }
6429
+ try {
6430
+ const parsed = JSON.parse(text);
6431
+ return isPlainObject(parsed) ? parsed : void 0;
6432
+ } catch {
6433
+ return void 0;
6434
+ }
6435
+ }
6436
+ function parseMaybeJsonObject(value) {
6437
+ if (isPlainObject(value)) {
6438
+ return value;
6439
+ }
6440
+ if (typeof value === "string") {
6441
+ return parseJsonObject(value) || {};
6442
+ }
6443
+ return {};
6444
+ }
6445
+ function cleanId(value) {
6446
+ return value.replace(/\s+/g, "_").slice(0, 200);
6447
+ }
6448
+ async function openCursorDb(dbPath) {
6449
+ const { DatabaseSync } = await import("node:sqlite");
6450
+ try {
6451
+ return {
6452
+ db: new DatabaseSync(dbPath, { readOnly: true }),
6453
+ cleanup: async () => {
6454
+ }
6455
+ };
6456
+ } catch {
6457
+ const tmp = path13.join(os6.tmpdir(), `vibetime-cursor-${createStableHash(dbPath).slice(0, 12)}.db`);
6458
+ await copyFile(dbPath, tmp);
6459
+ for (const suffix of ["-wal", "-shm"]) {
6460
+ await copyFile(`${dbPath}${suffix}`, `${tmp}${suffix}`).catch(() => void 0);
6461
+ }
6462
+ return {
6463
+ db: new DatabaseSync(tmp, { readOnly: true }),
6464
+ cleanup: async () => {
6465
+ const { unlink } = await import("node:fs/promises");
6466
+ await unlink(tmp).catch(() => void 0);
6467
+ await unlink(`${tmp}-wal`).catch(() => void 0);
6468
+ await unlink(`${tmp}-shm`).catch(() => void 0);
6469
+ }
6470
+ };
6471
+ }
6472
+ }
6473
+ function listComposers(db) {
6474
+ const dataById = /* @__PURE__ */ new Map();
6475
+ const dataRows = db.prepare(
6476
+ "SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'"
6477
+ ).all();
6478
+ for (const row of dataRows) {
6479
+ const id = row.key.slice("composerData:".length);
6480
+ const data = parseJsonObject(decodeKv(row.value));
6481
+ if (id && data) {
6482
+ dataById.set(id, data);
6483
+ }
6484
+ }
6485
+ let headers = [];
6486
+ try {
6487
+ headers = db.prepare(
6488
+ "SELECT composerId, createdAt, lastUpdatedAt, isSubagent, value FROM composerHeaders"
6489
+ ).all();
6490
+ } catch {
6491
+ headers = [...dataById.entries()].map(([composerId, data]) => ({
6492
+ composerId,
6493
+ createdAt: numberField(data, "createdAt"),
6494
+ lastUpdatedAt: numberField(data, "lastUpdatedAt"),
6495
+ isSubagent: data.isBestOfNSubcomposer || data.isSubagent ? 1 : 0,
6496
+ value: JSON.stringify(data)
6497
+ }));
6498
+ }
6499
+ const composers = [];
6500
+ for (const headerRow of headers) {
6501
+ const composerId = headerRow.composerId;
6502
+ if (!composerId || composerId === "empty-state-draft") {
6503
+ continue;
6504
+ }
6505
+ const header = parseJsonObject(decodeKv(headerRow.value)) || parseMaybeJsonObject(headerRow.value);
6506
+ const data = dataById.get(composerId) || header;
6507
+ if (data.isDraft === true || data.isEphemeral === true || header.isDraft === true || header.isEphemeral === true) {
6508
+ continue;
6509
+ }
6510
+ composers.push({
6511
+ composerId,
6512
+ createdAt: headerRow.createdAt ?? numberField(data, "createdAt") ?? numberField(header, "createdAt"),
6513
+ lastUpdatedAt: headerRow.lastUpdatedAt ?? numberField(data, "lastUpdatedAt") ?? numberField(header, "lastUpdatedAt"),
6514
+ isSubagent: Boolean(headerRow.isSubagent) || data.isBestOfNSubcomposer === true,
6515
+ header,
6516
+ data
6517
+ });
6518
+ }
6519
+ return composers;
6520
+ }
6521
+ function loadBubbles(db, composerId) {
6522
+ const rows = db.prepare(
6523
+ "SELECT key, value FROM cursorDiskKV WHERE key LIKE ?"
6524
+ ).all(`bubbleId:${composerId}:%`);
6525
+ const bubbles = [];
6526
+ for (const row of rows) {
6527
+ const bubble = parseJsonObject(decodeKv(row.value));
6528
+ if (bubble) {
6529
+ bubbles.push(bubble);
6530
+ }
6531
+ }
6532
+ bubbles.sort((a, b) => {
6533
+ const aTs = stringField(a, "createdAt") || "";
6534
+ const bTs = stringField(b, "createdAt") || "";
6535
+ return aTs.localeCompare(bTs);
6536
+ });
6537
+ return bubbles;
6538
+ }
6539
+ function workspaceFromComposer(data) {
6540
+ const ident = objectField(data, "workspaceIdentifier");
6541
+ const uri = objectField(ident, "uri");
6542
+ const cwd = stringField(uri, "fsPath") || stringField(uri, "path");
6543
+ return {
6544
+ cwd,
6545
+ project: cwd ? path13.basename(cwd) : void 0
6546
+ };
6547
+ }
6548
+ function modelFromComposer(data) {
6549
+ const config = objectField(data, "modelConfig");
6550
+ return stringField(config, "modelName") || stringField(config, "modelId");
6551
+ }
6552
+ function bubbleTs(bubble, fallback) {
6553
+ return timestampFrom(bubble.createdAt) || stringField(bubble, "createdAt") || fallback;
6554
+ }
6555
+ function toolNameOf(raw) {
6556
+ if (!raw) {
6557
+ return "unknown";
6558
+ }
6559
+ return raw.replace(/_v\d+$/i, "");
6560
+ }
6561
+ function isShellTool(name) {
6562
+ const lower = name.toLowerCase();
6563
+ return lower === "shell" || lower === "bash" || lower === "run_terminal_cmd" || lower === "run_terminal_command";
6564
+ }
6565
+ function fileActivitiesFromCursorTool(toolName, input, ts, cwd) {
6566
+ const lower = toolName.toLowerCase();
6567
+ if (isShellTool(toolName)) {
6568
+ const command = stringField(input, "command") || stringField(input, "cmd");
6569
+ if (command) {
6570
+ return fileActivitiesFromShellCommand(command, ts, cwd, cwd);
6571
+ }
6572
+ return [];
6573
+ }
6574
+ const target = stringField(input, "path") || stringField(input, "targetFile") || stringField(input, "target_file") || stringField(input, "file_path") || stringField(input, "filePath");
6575
+ const display = target ? displayFilePath(target, cwd) : void 0;
6576
+ if (lower === "read" || lower === "read_file" || lower === "readfile") {
6577
+ if (!display) {
6578
+ return [];
6579
+ }
6580
+ return [{ ts, path: display, operation: "read", confidence: "exact" }];
6581
+ }
6582
+ if (lower === "grep" || lower === "grep_search" || lower === "ripgrep" || lower === "glob" || lower === "glob_file_search" || lower === "globfilesearch") {
6583
+ if (!display) {
6584
+ return [];
6585
+ }
6586
+ return [{ ts, path: display, operation: "search", confidence: "exact" }];
6587
+ }
6588
+ if (lower === "delete" || lower === "delete_file") {
6589
+ if (!display) {
6590
+ return [];
6591
+ }
6592
+ return [{ ts, path: display, operation: "delete", confidence: "exact" }];
6593
+ }
6594
+ if (lower === "write" || lower === "write_file") {
6595
+ if (!display) {
6596
+ return [];
6597
+ }
6598
+ const content = stringField(input, "contents") || stringField(input, "content");
6599
+ return [{
6600
+ ts,
6601
+ path: display,
6602
+ operation: "write",
6603
+ confidence: "exact",
6604
+ linesAdded: countTextLines(content),
6605
+ charsWritten: content?.length
6606
+ }];
6607
+ }
6608
+ if (lower === "search_replace" || lower === "strreplace" || lower === "edit" || lower === "edit_file" || lower === "apply_patch" || lower === "applypatch") {
6609
+ if (!display) {
6610
+ return [];
6611
+ }
6612
+ const oldString = stringField(input, "old_string") || stringField(input, "oldString") || stringField(input, "old_str");
6613
+ const newString = stringField(input, "new_string") || stringField(input, "newString") || stringField(input, "new_str") || stringField(input, "contents") || stringField(input, "content");
6614
+ return [{
6615
+ ts,
6616
+ path: display,
6617
+ operation: "edit",
6618
+ confidence: "exact",
6619
+ linesAdded: countTextLines(newString),
6620
+ linesRemoved: countTextLines(oldString),
6621
+ charsWritten: newString?.length
6622
+ }];
6623
+ }
6624
+ return [];
6625
+ }
6626
+ function usageMetrics(tokenCount) {
6627
+ const inputTokens = numberField(tokenCount, "inputTokens") || 0;
6628
+ const outputTokens = numberField(tokenCount, "outputTokens") || 0;
6629
+ const cached = numberField(tokenCount, "cacheReadTokens") || numberField(tokenCount, "cachedInputTokens") || 0;
6630
+ const cacheCreation = numberField(tokenCount, "cacheWriteTokens") || numberField(tokenCount, "cacheCreationTokens") || 0;
6631
+ if (inputTokens <= 0 && outputTokens <= 0 && cached <= 0 && cacheCreation <= 0) {
6632
+ return void 0;
6633
+ }
6634
+ return {
6635
+ tokensInput: inputTokens || void 0,
6636
+ tokensOutput: outputTokens || void 0,
6637
+ tokensCachedInput: cached + cacheCreation || void 0,
6638
+ tokensCacheReadInput: cached || void 0,
6639
+ tokensCacheCreationInput: cacheCreation || void 0,
6640
+ tokensTotal: inputTokens + outputTokens || void 0,
6641
+ modelCalls: 1
6642
+ };
6643
+ }
6644
+ var CURSOR_TIMESTAMP_RE = /<timestamp>\s*([^<]+?)\s*<\/timestamp>/i;
6645
+ var CURSOR_USER_QUERY_RE = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/i;
6646
+ var chatMetaIndexCache = /* @__PURE__ */ new Map();
6647
+ function isCursorTranscriptPath(filePath) {
6648
+ return filePath.split(path13.sep).includes("agent-transcripts") && filePath.endsWith(".jsonl");
6649
+ }
6650
+ function cursorHomeFromTranscript(filePath) {
6651
+ const parts = filePath.split(path13.sep);
6652
+ const at = parts.lastIndexOf("agent-transcripts");
6653
+ if (at >= 2 && parts[at - 2] === "projects") {
6654
+ return parts.slice(0, at - 2).join(path13.sep);
6655
+ }
6656
+ return void 0;
6657
+ }
6658
+ function parseCursorClock(raw) {
6659
+ const trimmed = raw.trim();
6660
+ const direct = timestampFrom(trimmed);
6661
+ if (direct) {
6662
+ return direct;
6663
+ }
6664
+ const withoutWeekday = trimmed.replace(/^[A-Za-z]{3,9},\s*/, "");
6665
+ const normalized = withoutWeekday.replace(/\((UTC[+-]\d{1,2}(?::\d{2})?)\)/i, "$1");
6666
+ for (const candidate of [normalized, withoutWeekday, trimmed]) {
6667
+ const parsed = Date.parse(candidate);
6668
+ if (!Number.isNaN(parsed)) {
6669
+ return new Date(parsed).toISOString();
6670
+ }
6671
+ }
6672
+ return void 0;
6673
+ }
6674
+ function latestTimestamp(...values) {
6675
+ let best;
6676
+ for (const value of values) {
6677
+ if (!value || Number.isNaN(Date.parse(value))) {
6678
+ continue;
6679
+ }
6680
+ if (!best || value > best) {
6681
+ best = value;
6682
+ }
6683
+ }
6684
+ return best;
6685
+ }
6686
+ function timestampBetween(start, end, index, count) {
6687
+ if (count <= 0 || index < 0) {
6688
+ return start;
6689
+ }
6690
+ const startMs = Date.parse(start);
6691
+ const endMs = Date.parse(end);
6692
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs <= startMs) {
6693
+ return start;
6694
+ }
6695
+ return new Date(startMs + Math.round((endMs - startMs) * (index + 1) / (count + 1))).toISOString();
6696
+ }
6697
+ function parseCursorUserText(text) {
6698
+ const tsMatch = text.match(CURSOR_TIMESTAMP_RE);
6699
+ const queryMatch = text.match(CURSOR_USER_QUERY_RE);
6700
+ return {
6701
+ ts: tsMatch?.[1] ? parseCursorClock(tsMatch[1]) : void 0,
6702
+ prompt: (queryMatch?.[1] || text.replace(CURSOR_TIMESTAMP_RE, "")).trim()
6703
+ };
6704
+ }
6705
+ function messageText(message) {
6706
+ const content = message.content;
6707
+ if (typeof content === "string") {
6708
+ return content;
6709
+ }
6710
+ if (!Array.isArray(content)) {
6711
+ return stringField(message, "text") || "";
6712
+ }
6713
+ const parts = [];
6714
+ for (const item of content) {
6715
+ if (isPlainObject(item) && stringField(item, "type") === "text") {
6716
+ const text = stringField(item, "text");
6717
+ if (text) {
6718
+ parts.push(text);
6719
+ }
6720
+ }
6721
+ }
6722
+ return parts.join("\n");
6723
+ }
6724
+ function messageToolUses(message) {
6725
+ const content = message.content;
6726
+ if (!Array.isArray(content)) {
6727
+ return [];
6728
+ }
6729
+ const tools = [];
6730
+ for (const item of content) {
6731
+ if (!isPlainObject(item) || stringField(item, "type") !== "tool_use") {
6732
+ continue;
6733
+ }
6734
+ tools.push({
6735
+ name: stringField(item, "name") || "unknown",
6736
+ id: stringField(item, "id"),
6737
+ input: isPlainObject(item.input) ? item.input : parseMaybeJsonObject(item.input)
6738
+ });
6739
+ }
6740
+ return tools;
6741
+ }
6742
+ async function indexCursorChatMeta(cursorHome2) {
6743
+ const cached = chatMetaIndexCache.get(cursorHome2);
6744
+ if (cached) {
6745
+ return cached;
6746
+ }
6747
+ const pending = buildCursorChatMetaIndex(cursorHome2);
6748
+ chatMetaIndexCache.set(cursorHome2, pending);
6749
+ return pending;
6750
+ }
6751
+ async function buildCursorChatMetaIndex(cursorHome2) {
6752
+ const index = /* @__PURE__ */ new Map();
6753
+ const chatsDir = path13.join(cursorHome2, "chats");
6754
+ const projectDirs = await readdir6(chatsDir, { withFileTypes: true }).catch(() => []);
6755
+ for (const project of projectDirs) {
6756
+ if (!project.isDirectory()) {
6757
+ continue;
6758
+ }
6759
+ const sessions = await readdir6(path13.join(chatsDir, project.name), { withFileTypes: true }).catch(() => []);
6760
+ for (const session of sessions) {
6761
+ if (!session.isDirectory()) {
6762
+ continue;
6763
+ }
6764
+ const sessionDir = path13.join(chatsDir, project.name, session.name);
6765
+ const meta = await readJsonIfExists(path13.join(sessionDir, "meta.json"));
6766
+ const fromMeta = isPlainObject(meta) ? meta : {};
6767
+ const fromStore = await readCursorStoreMeta(path13.join(sessionDir, "store.db"));
6768
+ const cwd = stringField(fromMeta, "cwd") || fromStore.cwd;
6769
+ index.set(session.name, {
6770
+ cwd,
6771
+ project: cwd ? path13.basename(cwd) : void 0,
6772
+ model: fromStore.model,
6773
+ startedAt: timestampFrom(fromMeta.createdAtMs) || fromStore.startedAt,
6774
+ endedAt: timestampFrom(fromMeta.updatedAtMs) || fromStore.endedAt
6775
+ });
6776
+ }
6777
+ }
6778
+ return index;
6779
+ }
6780
+ async function readCursorStoreMeta(storePath) {
6781
+ const info = await stat7(storePath).catch(() => null);
6782
+ if (!info) {
6783
+ return {};
6784
+ }
6785
+ try {
6786
+ const { DatabaseSync } = await import("node:sqlite");
6787
+ const db = new DatabaseSync(storePath, { readOnly: true });
6788
+ try {
6789
+ const row = db.prepare("SELECT value FROM meta LIMIT 1").get();
6790
+ const decoded = decodeStoreMetaValue(row?.value);
6791
+ if (!decoded) {
6792
+ return {};
6793
+ }
6794
+ const cwd = stringField(decoded, "cwd") || stringField(objectField(decoded, "workspace"), "path");
6795
+ return {
6796
+ cwd,
6797
+ project: cwd ? path13.basename(cwd) : void 0,
6798
+ model: stringField(decoded, "lastUsedModel") || stringField(decoded, "model"),
6799
+ startedAt: timestampFrom(decoded.createdAt),
6800
+ endedAt: timestampFrom(decoded.lastUpdatedAt) || timestampFrom(decoded.updatedAt)
6801
+ };
6802
+ } finally {
6803
+ db.close();
6804
+ }
6805
+ } catch {
6806
+ return {};
6807
+ }
6808
+ }
6809
+ function decodeStoreMetaValue(value) {
6810
+ if (typeof value !== "string" || !value) {
6811
+ return void 0;
6812
+ }
6813
+ try {
6814
+ const asJson = parseJsonObject(value);
6815
+ if (asJson) {
6816
+ return asJson;
6817
+ }
6818
+ return parseJsonObject(Buffer.from(value, "hex").toString("utf8"));
6819
+ } catch {
6820
+ return void 0;
6821
+ }
6822
+ }
6823
+ async function resolveTranscriptContext(filePath, sessionId) {
6824
+ const sibling = await readJsonIfExists(path13.join(path13.dirname(filePath), "meta.json"));
6825
+ if (isPlainObject(sibling)) {
6826
+ const cwd = stringField(sibling, "cwd");
6827
+ return {
6828
+ cwd,
6829
+ project: cwd ? path13.basename(cwd) : void 0,
6830
+ startedAt: timestampFrom(sibling.createdAtMs),
6831
+ endedAt: timestampFrom(sibling.updatedAtMs)
6832
+ };
6833
+ }
6834
+ const cursorHomePath = cursorHomeFromTranscript(filePath);
6835
+ if (!cursorHomePath) {
6836
+ return {};
6837
+ }
6838
+ const index = await indexCursorChatMeta(cursorHomePath);
6839
+ return index.get(sessionId) || {};
6840
+ }
6841
+ async function parseCursorTranscriptFile(filePath, options) {
6842
+ const text = await readFile8(filePath, "utf8").catch(() => "");
6843
+ if (!text) {
6844
+ return [];
6845
+ }
6846
+ const lines = text.split("\n").filter(Boolean);
6847
+ const parsed = lines.map(parseJsonLine);
6848
+ const hasConversation = parsed.some((raw) => raw && (raw.role === "user" || raw.role === "assistant"));
6849
+ if (!hasConversation) {
6850
+ return [];
6851
+ }
6852
+ const sessionId = path13.basename(filePath, ".jsonl");
6853
+ const context = await resolveTranscriptContext(filePath, sessionId);
6854
+ const fileInfo = await stat7(filePath).catch(() => null);
6855
+ let cwd = context.cwd;
6856
+ let project = context.project;
6857
+ let model = context.model;
6858
+ let lastTs = context.startedAt || (fileInfo ? fileInfo.mtime.toISOString() : void 0);
6859
+ const fileMtime = fileInfo ? fileInfo.mtime.toISOString() : void 0;
6860
+ const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
6861
+ const sourcePathHash = `sha256:${createStableHash(filePath)}`;
6862
+ const events = [];
6863
+ let lineNumber = 0;
6864
+ let currentTurnId;
6865
+ let currentTurnStartedAt;
6866
+ let turnIndex = 0;
6867
+ let sessionStarted = false;
6868
+ let pendingTurnSuccess = true;
6869
+ const pendingTools = [];
6870
+ const push = (partial, topType) => {
6871
+ lineNumber += 1;
6872
+ const event = {
6873
+ schemaVersion: AGENT_TIME_SCHEMA_VERSION,
6874
+ source: SOURCE_ID,
6875
+ agent: AGENT_NAME,
6876
+ workspaceId,
6877
+ project,
6878
+ cwd,
6879
+ model,
6880
+ sessionId,
6881
+ ...partial
6882
+ };
6883
+ events.push(withBackfillRefs(event, {
6884
+ filePath,
6885
+ sourcePathHash,
6886
+ lineNumber,
6887
+ topType,
6888
+ payloadType: event.type,
6889
+ options
6890
+ }));
6891
+ };
6892
+ const ensureSessionStarted = (ts) => {
6893
+ if (sessionStarted) {
6894
+ return;
6895
+ }
6896
+ sessionStarted = true;
6897
+ push({
6898
+ ts,
6899
+ type: "session.started",
6900
+ confidence: "partial",
6901
+ refs: stringRefs({ sourceId: `${sessionId}:started` })
6902
+ }, "transcript");
6903
+ };
6904
+ const closeTurn = (endTs, success = pendingTurnSuccess) => {
6905
+ if (!currentTurnId || !currentTurnStartedAt) {
6906
+ pendingTools.length = 0;
6907
+ pendingTurnSuccess = true;
6908
+ return;
6909
+ }
6910
+ const turnId = currentTurnId;
6911
+ const startedAt = currentTurnStartedAt;
6912
+ const finishedAt = latestTimestamp(startedAt, endTs) || startedAt;
6913
+ const toolCount = pendingTools.length;
6914
+ for (const [index, item] of pendingTools.entries()) {
6915
+ const ts = timestampBetween(startedAt, finishedAt, index, toolCount);
6916
+ const fileActivities = fileActivitiesFromCursorTool(item.tool, item.input, ts, cwd);
6917
+ push({
6918
+ ts,
6919
+ type: "tool.started",
6920
+ turnId,
6921
+ tool: item.tool,
6922
+ operation: `${item.tool} started`,
6923
+ model,
6924
+ confidence: "exact",
6925
+ fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
6926
+ refs: stringRefs({ sourceId: `${item.toolCallId}:started` })
6927
+ }, "tool");
6928
+ push({
6929
+ ts,
6930
+ type: "tool.completed",
6931
+ turnId,
6932
+ tool: item.tool,
6933
+ operation: `${item.tool} completed`,
6934
+ success,
6935
+ model,
6936
+ confidence: "exact",
6937
+ metrics: { toolCalls: 1 },
6938
+ refs: stringRefs({ sourceId: `${item.toolCallId}:completed` })
6939
+ }, "tool");
6940
+ if (item.command) {
6941
+ push({
6942
+ ts,
6943
+ type: "command.started",
6944
+ turnId,
6945
+ tool: item.tool,
6946
+ operation: "command started",
6947
+ confidence: "derived",
6948
+ refs: stringRefs({
6949
+ sourceId: `${item.toolCallId}:command:started`,
6950
+ commandHash: `sha256:${createStableHash(item.command)}`
6951
+ })
6952
+ }, "tool");
6953
+ push({
6954
+ ts,
6955
+ type: "command.completed",
6956
+ turnId,
6957
+ tool: item.tool,
6958
+ operation: "command completed",
6959
+ success,
6960
+ confidence: "derived",
6961
+ metrics: { commandCalls: 1 },
6962
+ refs: stringRefs({ sourceId: `${item.toolCallId}:command:completed` })
6963
+ }, "tool");
6964
+ }
6965
+ }
6966
+ pendingTools.length = 0;
6967
+ push({
6968
+ ts: finishedAt,
6969
+ type: "turn.completed",
6970
+ turnId,
6971
+ model,
6972
+ success,
6973
+ confidence: "derived",
6974
+ metrics: { durationMs: durationMsBetween(startedAt, finishedAt) },
6975
+ refs: stringRefs({ sourceId: `${sessionId}:${turnId}:completed` })
6976
+ }, "transcript");
6977
+ currentTurnId = void 0;
6978
+ currentTurnStartedAt = void 0;
6979
+ pendingTurnSuccess = true;
6980
+ };
6981
+ for (const raw of parsed) {
6982
+ if (!raw) {
6983
+ continue;
6984
+ }
6985
+ const role = stringField(raw, "role");
6986
+ const topType = stringField(raw, "type");
6987
+ const message = objectField(raw, "message");
6988
+ const body = Object.keys(message).length > 0 ? message : raw;
6989
+ const rawText = messageText(body);
6990
+ if (!cwd) {
6991
+ const workspaceMatch = rawText.match(/Workspace Path:\s*(.+)/);
6992
+ const found = workspaceMatch?.[1]?.trim();
6993
+ if (found) {
6994
+ cwd = found;
6995
+ project = path13.basename(found);
6996
+ }
6997
+ }
6998
+ if (role === "user") {
6999
+ const userBits = parseCursorUserText(rawText);
7000
+ const ts = timestampFrom(raw.timestamp) || userBits.ts;
7001
+ if (!ts) {
7002
+ continue;
7003
+ }
7004
+ lastTs = latestTimestamp(lastTs, ts) || ts;
7005
+ ensureSessionStarted(ts);
7006
+ closeTurn(ts);
7007
+ turnIndex += 1;
7008
+ currentTurnId = `turn_${turnIndex}`;
7009
+ currentTurnStartedAt = ts;
7010
+ pendingTurnSuccess = true;
7011
+ push({
7012
+ ts,
7013
+ type: "turn.started",
7014
+ turnId: currentTurnId,
7015
+ model,
7016
+ confidence: "partial",
7017
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:started` })
7018
+ }, "transcript");
7019
+ if (userBits.prompt) {
7020
+ push({
7021
+ ts,
7022
+ type: "prompt.submitted",
7023
+ turnId: currentTurnId,
7024
+ model,
7025
+ confidence: "partial",
7026
+ metrics: { prompts: 1, promptChars: userBits.prompt.length },
7027
+ refs: stringRefs({
7028
+ sourceId: `${sessionId}:${currentTurnId}:prompt`,
7029
+ promptHash: `sha256:${createStableHash(userBits.prompt)}`
7030
+ })
7031
+ }, "transcript");
7032
+ }
7033
+ continue;
7034
+ }
7035
+ if (role === "assistant") {
7036
+ if (!currentTurnId && lastTs) {
7037
+ ensureSessionStarted(lastTs);
7038
+ turnIndex += 1;
7039
+ currentTurnId = `turn_${turnIndex}`;
7040
+ currentTurnStartedAt = lastTs;
7041
+ }
7042
+ if (!currentTurnId) {
7043
+ continue;
7044
+ }
7045
+ for (const [index, toolUse] of messageToolUses(body).entries()) {
7046
+ const tool = toolNameOf(toolUse.name);
7047
+ const command = isShellTool(tool) ? stringField(toolUse.input, "command") || stringField(toolUse.input, "cmd") : void 0;
7048
+ pendingTools.push({
7049
+ tool,
7050
+ toolCallId: cleanId(
7051
+ toolUse.id || `${sessionId}:${currentTurnId}:${pendingTools.length}:${index}`
7052
+ ),
7053
+ input: toolUse.input,
7054
+ command
7055
+ });
7056
+ }
7057
+ continue;
7058
+ }
7059
+ if (topType === "turn_ended") {
7060
+ const status = (stringField(raw, "status") || "success").toLowerCase();
7061
+ pendingTurnSuccess = status !== "error" && status !== "failed" && status !== "cancelled";
7062
+ }
7063
+ }
7064
+ const endedAt = latestTimestamp(lastTs, context.endedAt, fileMtime);
7065
+ if (endedAt) {
7066
+ closeTurn(endedAt);
7067
+ if (sessionStarted) {
7068
+ push({
7069
+ ts: endedAt,
7070
+ type: "session.ended",
7071
+ confidence: "derived",
7072
+ refs: stringRefs({ sourceId: `${sessionId}:ended` })
7073
+ }, "transcript");
7074
+ }
7075
+ }
7076
+ return events;
7077
+ }
7078
+ async function listCursorComposerIds(dbPath) {
7079
+ const ids = /* @__PURE__ */ new Set();
7080
+ const info = await stat7(dbPath).catch(() => null);
7081
+ if (!info) {
7082
+ return ids;
7083
+ }
7084
+ try {
7085
+ const opened = await openCursorDb(dbPath);
7086
+ try {
7087
+ for (const composer of listComposers(opened.db)) {
7088
+ ids.add(composer.composerId);
7089
+ }
7090
+ } finally {
7091
+ opened.db.close();
7092
+ await opened.cleanup();
7093
+ }
7094
+ } catch {
7095
+ return ids;
7096
+ }
7097
+ return ids;
7098
+ }
7099
+ async function collectCursorTranscriptFiles(root, skipSessionIds) {
7100
+ const files = [];
7101
+ const seen = /* @__PURE__ */ new Set();
7102
+ for (const filePath of await listJsonlFiles(root)) {
7103
+ if (!isCursorTranscriptPath(filePath) && path13.basename(path13.dirname(filePath)) !== "agent-transcripts") {
7104
+ continue;
7105
+ }
7106
+ const sessionId = path13.basename(filePath, ".jsonl");
7107
+ if (!sessionId || seen.has(sessionId) || skipSessionIds?.has(sessionId)) {
7108
+ continue;
7109
+ }
7110
+ seen.add(sessionId);
7111
+ const info = await stat7(filePath).catch(() => null);
7112
+ if (!info) {
7113
+ continue;
7114
+ }
7115
+ files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
7116
+ }
7117
+ return files;
7118
+ }
7119
+ async function parseCursorSessionFile(filePath, options) {
7120
+ const base = path13.basename(filePath);
7121
+ if (base.endsWith(".jsonl")) {
7122
+ return parseCursorTranscriptFile(filePath, options);
7123
+ }
7124
+ if (base === "store.db") {
7125
+ return [];
7126
+ }
7127
+ if (base !== "state.vscdb" && !base.endsWith(".vscdb") && !base.endsWith(".db")) {
7128
+ return [];
7129
+ }
7130
+ const opened = await openCursorDb(filePath);
7131
+ const events = [];
7132
+ const sourcePathHash = `sha256:${createStableHash(filePath)}`;
7133
+ try {
7134
+ const composers = listComposers(opened.db);
7135
+ for (const composer of composers) {
7136
+ events.push(...parseComposer(opened.db, composer, filePath, sourcePathHash, options));
7137
+ }
7138
+ } finally {
7139
+ opened.db.close();
7140
+ await opened.cleanup();
7141
+ }
7142
+ return events;
7143
+ }
7144
+ function parseComposer(db, composer, filePath, sourcePathHash, options) {
7145
+ const sessionId = composer.composerId;
7146
+ const data = composer.data;
7147
+ const { cwd, project } = workspaceFromComposer(data);
7148
+ const model = modelFromComposer(data);
7149
+ const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
7150
+ const startedAt = timestampFrom(composer.createdAt) || timestampFrom(data.createdAt);
7151
+ const endedAt = timestampFrom(composer.lastUpdatedAt) || timestampFrom(data.lastUpdatedAt) || startedAt;
7152
+ if (!startedAt) {
7153
+ return [];
7154
+ }
7155
+ const bubbles = loadBubbles(db, sessionId);
7156
+ const events = [];
7157
+ let lineNumber = 0;
7158
+ let currentTurnId;
7159
+ let currentTurnStartedAt;
7160
+ let turnIndex = 0;
7161
+ let hasFileLineData = false;
7162
+ const push = (partial, topType) => {
7163
+ lineNumber += 1;
7164
+ const event = {
7165
+ schemaVersion: AGENT_TIME_SCHEMA_VERSION,
7166
+ source: SOURCE_ID,
7167
+ agent: AGENT_NAME,
7168
+ workspaceId,
7169
+ project,
7170
+ cwd,
7171
+ model,
7172
+ sessionId,
7173
+ ...partial
7174
+ };
7175
+ events.push(withBackfillRefs(event, {
7176
+ filePath,
7177
+ sourcePathHash,
7178
+ lineNumber,
7179
+ topType,
7180
+ payloadType: event.type,
7181
+ options
7182
+ }));
7183
+ };
7184
+ push({
7185
+ ts: startedAt,
7186
+ type: "session.started",
7187
+ confidence: "partial",
7188
+ refs: stringRefs({ sourceId: `${sessionId}:started` })
7189
+ }, "composer");
7190
+ for (const bubble of bubbles) {
7191
+ const ts = bubbleTs(bubble, startedAt);
7192
+ if (!ts) {
7193
+ continue;
7194
+ }
7195
+ const bubbleId = stringField(bubble, "bubbleId") || `bubble_${lineNumber}`;
7196
+ const bubbleType = numberField(bubble, "type");
7197
+ const capabilityType = numberField(bubble, "capabilityType");
7198
+ const toolFormer = objectField(bubble, "toolFormerData");
7199
+ const bubbleModel = stringField(objectField(bubble, "modelInfo"), "modelName") || model;
7200
+ if (bubbleType === BUBBLE_USER) {
7201
+ if (currentTurnId && currentTurnStartedAt) {
7202
+ push({
7203
+ ts,
7204
+ type: "turn.completed",
7205
+ turnId: currentTurnId,
7206
+ model: bubbleModel,
7207
+ success: true,
7208
+ confidence: "derived",
7209
+ metrics: { durationMs: durationMsBetween(currentTurnStartedAt, ts) },
7210
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:completed` })
7211
+ }, "bubble");
7212
+ }
7213
+ turnIndex += 1;
7214
+ currentTurnId = `turn_${turnIndex}`;
7215
+ currentTurnStartedAt = ts;
7216
+ const text = stringField(bubble, "text") || "";
7217
+ push({
7218
+ ts,
7219
+ type: "turn.started",
7220
+ turnId: currentTurnId,
7221
+ model: bubbleModel,
7222
+ confidence: "partial",
7223
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:started` })
7224
+ }, "bubble");
7225
+ if (text) {
7226
+ push({
7227
+ ts,
7228
+ type: "prompt.submitted",
7229
+ turnId: currentTurnId,
7230
+ model: bubbleModel,
7231
+ confidence: "partial",
7232
+ metrics: { prompts: 1, promptChars: text.length },
7233
+ refs: stringRefs({
7234
+ sourceId: `${sessionId}:${cleanId(bubbleId)}:prompt`,
7235
+ promptHash: `sha256:${createStableHash(text)}`
7236
+ })
7237
+ }, "bubble");
7238
+ }
7239
+ continue;
7240
+ }
7241
+ if (capabilityType === CAPABILITY_TOOL && Object.keys(toolFormer).length > 0) {
7242
+ const rawName = stringField(toolFormer, "name") || "unknown";
7243
+ const tool = toolNameOf(rawName);
7244
+ const toolCallId = cleanId(
7245
+ stringField(toolFormer, "toolCallId") || `${sessionId}:${cleanId(bubbleId)}`
7246
+ );
7247
+ const status = (stringField(toolFormer, "status") || "completed").toLowerCase();
7248
+ const success = status !== "error" && status !== "failed" && status !== "cancelled";
7249
+ const input = parseMaybeJsonObject(toolFormer.rawArgs);
7250
+ const params = parseMaybeJsonObject(toolFormer.params);
7251
+ const mergedInput = { ...params, ...input };
7252
+ const fileActivities = fileActivitiesFromCursorTool(tool, mergedInput, ts, cwd);
7253
+ if (fileActivities.some((file) => (file.linesAdded || 0) > 0 || (file.linesRemoved || 0) > 0)) {
7254
+ hasFileLineData = true;
7255
+ }
7256
+ push({
7257
+ ts,
7258
+ type: "tool.started",
7259
+ turnId: currentTurnId,
7260
+ tool,
7261
+ operation: `${tool} started`,
7262
+ model: bubbleModel,
7263
+ confidence: "exact",
7264
+ fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
7265
+ refs: stringRefs({ sourceId: `${toolCallId}:started` })
7266
+ }, "tool");
7267
+ push({
7268
+ ts,
7269
+ type: success ? "tool.completed" : "tool.failed",
7270
+ turnId: currentTurnId,
7271
+ tool,
7272
+ operation: `${tool} completed`,
7273
+ success,
7274
+ model: bubbleModel,
7275
+ confidence: "exact",
7276
+ metrics: { toolCalls: 1 },
7277
+ refs: stringRefs({ sourceId: `${toolCallId}:completed` })
7278
+ }, "tool");
7279
+ if (isShellTool(tool)) {
7280
+ const command = stringField(mergedInput, "command") || stringField(mergedInput, "cmd");
7281
+ if (command) {
7282
+ push({
7283
+ ts,
7284
+ type: "command.started",
7285
+ turnId: currentTurnId,
7286
+ tool,
7287
+ operation: "command started",
7288
+ confidence: "derived",
7289
+ refs: stringRefs({
7290
+ sourceId: `${toolCallId}:command:started`,
7291
+ commandHash: `sha256:${createStableHash(command)}`
7292
+ })
7293
+ }, "tool");
7294
+ push({
7295
+ ts,
7296
+ type: success ? "command.completed" : "command.failed",
7297
+ turnId: currentTurnId,
7298
+ tool,
7299
+ operation: "command completed",
7300
+ success,
7301
+ confidence: "derived",
7302
+ metrics: { commandCalls: 1 },
7303
+ refs: stringRefs({ sourceId: `${toolCallId}:command:completed` })
7304
+ }, "tool");
7305
+ }
7306
+ }
7307
+ }
7308
+ const metrics = usageMetrics(objectField(bubble, "tokenCount"));
7309
+ if (metrics) {
7310
+ push({
7311
+ ts,
7312
+ type: "model.usage",
7313
+ turnId: currentTurnId,
7314
+ model: bubbleModel,
7315
+ confidence: "partial",
7316
+ metrics,
7317
+ refs: stringRefs({ sourceId: `${sessionId}:${cleanId(bubbleId)}:usage` })
7318
+ }, "bubble");
7319
+ }
7320
+ }
7321
+ if (currentTurnId && endedAt) {
7322
+ push({
7323
+ ts: endedAt,
7324
+ type: "turn.completed",
7325
+ turnId: currentTurnId,
7326
+ success: true,
7327
+ confidence: "derived",
7328
+ metrics: { durationMs: durationMsBetween(currentTurnStartedAt, endedAt) },
7329
+ refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:completed` })
7330
+ }, "bubble");
7331
+ }
7332
+ const linesAdded = numberField(data, "totalLinesAdded");
7333
+ const linesRemoved = numberField(data, "totalLinesRemoved");
7334
+ if (!hasFileLineData && endedAt && ((linesAdded || 0) > 0 || (linesRemoved || 0) > 0)) {
7335
+ push({
7336
+ ts: endedAt,
7337
+ type: "file.changed",
7338
+ confidence: "partial",
7339
+ metrics: {
7340
+ linesAdded: linesAdded || void 0,
7341
+ linesRemoved: linesRemoved || void 0
7342
+ },
7343
+ refs: stringRefs({ sourceId: `${sessionId}:lines` })
7344
+ }, "composer");
7345
+ }
7346
+ if (endedAt) {
7347
+ push({
7348
+ ts: endedAt,
7349
+ type: "session.ended",
7350
+ confidence: "derived",
7351
+ refs: stringRefs({ sourceId: `${sessionId}:ended` })
7352
+ }, "composer");
7353
+ }
7354
+ return events;
7355
+ }
7356
+ async function cursorBackfillFiles(sourceRoot, home = os6.homedir(), env) {
7357
+ if (sourceRoot) {
7358
+ const info = await stat7(sourceRoot).catch(() => null);
7359
+ if (!info) {
7360
+ return [];
7361
+ }
7362
+ if (info.isDirectory()) {
7363
+ const files2 = [];
7364
+ for (const dbPath of await listFilesByExtensions(sourceRoot, [".vscdb", ".db"])) {
7365
+ const base = path13.basename(dbPath);
7366
+ if (base === "store.db" || base !== "state.vscdb" && !base.endsWith(".vscdb")) {
7367
+ continue;
7368
+ }
7369
+ const dbInfo = await stat7(dbPath).catch(() => null);
7370
+ if (dbInfo) {
7371
+ files2.push({ path: dbPath, modifiedAt: dbInfo.mtime.toISOString() });
7372
+ }
7373
+ }
7374
+ const skipIds2 = /* @__PURE__ */ new Set();
7375
+ for (const file of files2) {
7376
+ for (const id of await listCursorComposerIds(file.path)) {
7377
+ skipIds2.add(id);
7378
+ }
7379
+ }
7380
+ files2.push(...await collectCursorTranscriptFiles(sourceRoot, skipIds2));
7381
+ return files2;
7382
+ }
7383
+ if (path13.basename(sourceRoot) === "store.db") {
7384
+ return [];
7385
+ }
7386
+ return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
6179
7387
  }
6180
- for (const entry of entries) {
6181
- if (entry.startsWith("pending-session")) {
7388
+ const files = [];
7389
+ const skipIds = /* @__PURE__ */ new Set();
7390
+ for (const candidatePath of cursorStateDbCandidates(home, env)) {
7391
+ const info = await stat7(candidatePath).catch(() => null);
7392
+ if (!info) {
6182
7393
  continue;
6183
7394
  }
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() });
7395
+ files.push({ path: candidatePath, modifiedAt: info.mtime.toISOString() });
7396
+ for (const id of await listCursorComposerIds(candidatePath)) {
7397
+ skipIds.add(id);
6188
7398
  }
7399
+ break;
6189
7400
  }
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
- `;
7401
+ files.push(...await collectCursorTranscriptFiles(cursorProjectsDir(home, env), skipIds));
7402
+ return files;
6198
7403
  }
6199
- function copilotHome(home, env) {
6200
- const override = env?.COPILOT_HOME;
6201
- if (override && override.trim()) {
6202
- return path12.resolve(override);
7404
+ function cursorHookConfig() {
7405
+ const entry = { command: HOOK_COMMAND, timeout: HOOK_TIMEOUT_SECONDS };
7406
+ const hooks = {};
7407
+ for (const event of CURSOR_HOOK_EVENTS) {
7408
+ hooks[event] = [entry];
6203
7409
  }
6204
- return path12.join(home, ".copilot");
7410
+ return { version: 1, hooks };
6205
7411
  }
6206
- function createCopilotAdapter() {
7412
+ function createCursorAdapter() {
6207
7413
  return {
6208
- id: "copilot",
6209
- label: "GitHub Copilot",
6210
- agentName: "copilot",
6211
- kind: "agent",
7414
+ id: SOURCE_ID,
7415
+ label: "Cursor",
7416
+ agentName: AGENT_NAME,
7417
+ kind: "ide",
6212
7418
  detectPath(home, env) {
6213
- return copilotHome(home, env);
7419
+ return cursorHome(home, env);
6214
7420
  },
6215
7421
  installedPath(home, env) {
6216
- return path12.join(copilotHome(home, env), ".vibetime");
7422
+ return cursorHooksPath(home, env);
6217
7423
  },
6218
7424
  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
- }
7425
+ const config = await readJsonIfExists(cursorHooksPath(home, env));
7426
+ return hasCursorHookCommand(config, HOOK_COMMAND);
6225
7427
  },
6226
7428
  installEntries(home, env) {
6227
7429
  return [{
6228
- kind: "file",
6229
- path: path12.join(copilotHome(home, env), ".vibetime"),
6230
- content: copilotPluginContent()
7430
+ kind: "cursor-hooks-json",
7431
+ path: cursorHooksPath(home, env),
7432
+ content: cursorHookConfig()
6231
7433
  }];
6232
7434
  },
6233
7435
  sourcePaths(home, env) {
6234
- return [path12.join(copilotHome(home, env), "session-state")];
7436
+ return [
7437
+ ...cursorStateDbCandidates(home, env),
7438
+ cursorProjectsDir(home, env),
7439
+ cursorChatsDir(home, env)
7440
+ ];
6235
7441
  },
6236
- parseSessionFile: parseCopilotSessionFile
7442
+ parseSessionFile: parseCursorSessionFile
6237
7443
  };
6238
7444
  }
6239
7445
 
6240
7446
  // 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";
7447
+ import { readdir as readdir7, readFile as readFile9, stat as stat8 } from "node:fs/promises";
7448
+ import path14 from "node:path";
6243
7449
  init_fs();
6244
7450
  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}`;
7451
+ var SOURCE_ID2 = "grok-build";
7452
+ var AGENT_NAME2 = "grok-build";
7453
+ var HOOK_COMMAND2 = `vibetime hook --agent ${SOURCE_ID2}`;
6248
7454
  function grokHome(home, env) {
6249
7455
  const override = env?.GROK_HOME;
6250
7456
  if (override && override.trim()) {
6251
- return path13.resolve(override);
7457
+ return path14.resolve(override);
6252
7458
  }
6253
- return path13.join(home, ".grok");
7459
+ return path14.join(home, ".grok");
6254
7460
  }
6255
7461
  function grokHooksPath(home, env) {
6256
- return path13.join(grokHome(home, env), "hooks", "vibetime.json");
7462
+ return path14.join(grokHome(home, env), "hooks", "vibetime.json");
6257
7463
  }
6258
7464
  function grokSessionsDir(home, env) {
6259
- return path13.join(grokHome(home, env), "sessions");
7465
+ return path14.join(grokHome(home, env), "sessions");
6260
7466
  }
6261
7467
  async function grokBackfillFiles(sourceRoot, home, env) {
6262
7468
  const root = sourceRoot || grokSessionsDir(home, env);
@@ -6264,12 +7470,12 @@ async function grokBackfillFiles(sourceRoot, home, env) {
6264
7470
  async function walk(dir) {
6265
7471
  let entries;
6266
7472
  try {
6267
- entries = await readdir6(dir, { withFileTypes: true });
7473
+ entries = await readdir7(dir, { withFileTypes: true });
6268
7474
  } catch {
6269
7475
  return;
6270
7476
  }
6271
7477
  for (const entry of entries) {
6272
- const entryPath = path13.join(dir, entry.name);
7478
+ const entryPath = path14.join(dir, entry.name);
6273
7479
  if (entry.isDirectory()) {
6274
7480
  await walk(entryPath);
6275
7481
  continue;
@@ -6278,7 +7484,7 @@ async function grokBackfillFiles(sourceRoot, home, env) {
6278
7484
  continue;
6279
7485
  }
6280
7486
  try {
6281
- const info = await stat7(entryPath);
7487
+ const info = await stat8(entryPath);
6282
7488
  files.push({ path: entryPath, modifiedAt: info.mtime.toISOString() });
6283
7489
  } catch {
6284
7490
  }
@@ -6292,18 +7498,18 @@ async function parseGrokSessionFile(filePath, options) {
6292
7498
  if (!sessionDir) {
6293
7499
  return [];
6294
7500
  }
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");
7501
+ const summaryPath = path14.join(sessionDir, "summary.json");
7502
+ const eventsPath = path14.join(sessionDir, "events.jsonl");
7503
+ const signalsPath = path14.join(sessionDir, "signals.json");
7504
+ const updatesPath = path14.join(sessionDir, "updates.jsonl");
6299
7505
  const summary = await readJsonIfExists(summaryPath);
6300
7506
  if (!isPlainObject(summary)) {
6301
7507
  return [];
6302
7508
  }
6303
7509
  const info = objectField(summary, "info");
6304
- const sessionId = stringField(info, "id") || path13.basename(sessionDir);
7510
+ const sessionId = stringField(info, "id") || path14.basename(sessionDir);
6305
7511
  const cwd = stringField(info, "cwd");
6306
- const project = cwd ? path13.basename(cwd) : void 0;
7512
+ const project = cwd ? path14.basename(cwd) : void 0;
6307
7513
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
6308
7514
  const model = stringField(summary, "current_model_id");
6309
7515
  const createdAt = timestampFrom(summary.created_at) || timestampFrom(summary.createdAt);
@@ -6330,8 +7536,8 @@ async function parseGrokSessionFile(filePath, options) {
6330
7536
  };
6331
7537
  const base = (partial) => ({
6332
7538
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
6333
- source: SOURCE_ID,
6334
- agent: AGENT_NAME,
7539
+ source: SOURCE_ID2,
7540
+ agent: AGENT_NAME2,
6335
7541
  workspaceId,
6336
7542
  project,
6337
7543
  cwd,
@@ -6351,7 +7557,7 @@ async function parseGrokSessionFile(filePath, options) {
6351
7557
  const pendingTools = /* @__PURE__ */ new Map();
6352
7558
  let eventsText = "";
6353
7559
  try {
6354
- eventsText = await readFile8(eventsPath, "utf8");
7560
+ eventsText = await readFile9(eventsPath, "utf8");
6355
7561
  } catch {
6356
7562
  }
6357
7563
  const lines = eventsText.split("\n").filter(Boolean);
@@ -6429,7 +7635,7 @@ async function parseGrokSessionFile(filePath, options) {
6429
7635
  fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
6430
7636
  refs: stringRefs({ sourceId: `${toolId}:started` })
6431
7637
  }), lineNumber, type, "tool.started");
6432
- if (isShellTool(toolName)) {
7638
+ if (isShellTool2(toolName)) {
6433
7639
  const command = stringField(knownInput?.input || {}, "command");
6434
7640
  if (command) {
6435
7641
  push(base({
@@ -6470,7 +7676,7 @@ async function parseGrokSessionFile(filePath, options) {
6470
7676
  },
6471
7677
  refs: stringRefs({ sourceId: `${toolId}:completed` })
6472
7678
  }), lineNumber, type, "tool.completed");
6473
- if (isShellTool(pending?.name || toolName)) {
7679
+ if (isShellTool2(pending?.name || toolName)) {
6474
7680
  push(base({
6475
7681
  ts,
6476
7682
  type: success ? "command.completed" : "command.failed",
@@ -6527,7 +7733,7 @@ async function parseGrokSessionFile(filePath, options) {
6527
7733
  nextLine += 1;
6528
7734
  }
6529
7735
  }
6530
- const hunkPath = path13.join(sessionDir, "hunk_records.jsonl");
7736
+ const hunkPath = path14.join(sessionDir, "hunk_records.jsonl");
6531
7737
  const hunkActivities = await loadHunkFileActivities(hunkPath, cwd);
6532
7738
  if (hunkActivities.length > 0) {
6533
7739
  for (const event of events) {
@@ -6591,9 +7797,9 @@ async function parseGrokSessionFile(filePath, options) {
6591
7797
  return events;
6592
7798
  }
6593
7799
  function resolveSessionDir(filePath) {
6594
- const base = path13.basename(filePath);
7800
+ const base = path14.basename(filePath);
6595
7801
  if (base === "summary.json" || base === "events.jsonl" || base === "signals.json") {
6596
- return path13.dirname(filePath);
7802
+ return path14.dirname(filePath);
6597
7803
  }
6598
7804
  if (/^[0-9a-f]{8}-[0-9a-f-]{27,}$/i.test(base)) {
6599
7805
  return filePath;
@@ -6616,7 +7822,7 @@ function findPendingToolId(pending, toolName) {
6616
7822
  }
6617
7823
  return void 0;
6618
7824
  }
6619
- function isShellTool(name) {
7825
+ function isShellTool2(name) {
6620
7826
  if (!name) {
6621
7827
  return false;
6622
7828
  }
@@ -6625,7 +7831,7 @@ function isShellTool(name) {
6625
7831
  }
6626
7832
  function fileActivitiesFromTool(toolName, input, ts, cwd) {
6627
7833
  const lower = toolName.toLowerCase();
6628
- if (isShellTool(toolName)) {
7834
+ if (isShellTool2(toolName)) {
6629
7835
  const command = stringField(input, "command");
6630
7836
  if (command) {
6631
7837
  return fileActivitiesFromShellCommand(command, ts, cwd, cwd);
@@ -6679,17 +7885,17 @@ function fileActivitiesFromTool(toolName, input, ts, cwd) {
6679
7885
  return [];
6680
7886
  }
6681
7887
  function displayPath(filePath, cwd) {
6682
- if (!cwd || !path13.isAbsolute(filePath)) {
7888
+ if (!cwd || !path14.isAbsolute(filePath)) {
6683
7889
  return filePath;
6684
7890
  }
6685
- const relative = path13.relative(cwd, filePath);
6686
- return relative && !relative.startsWith("..") && !path13.isAbsolute(relative) ? relative : filePath;
7891
+ const relative = path14.relative(cwd, filePath);
7892
+ return relative && !relative.startsWith("..") && !path14.isAbsolute(relative) ? relative : filePath;
6687
7893
  }
6688
7894
  async function loadToolInputsFromUpdates(updatesPath) {
6689
7895
  const map = /* @__PURE__ */ new Map();
6690
7896
  let text = "";
6691
7897
  try {
6692
- text = await readFile8(updatesPath, "utf8");
7898
+ text = await readFile9(updatesPath, "utf8");
6693
7899
  } catch {
6694
7900
  return map;
6695
7901
  }
@@ -6760,7 +7966,7 @@ async function loadTurnUsagesFromUpdates(updatesPath) {
6760
7966
  const turns = [];
6761
7967
  let text = "";
6762
7968
  try {
6763
- text = await readFile8(updatesPath, "utf8");
7969
+ text = await readFile9(updatesPath, "utf8");
6764
7970
  } catch {
6765
7971
  return turns;
6766
7972
  }
@@ -6849,7 +8055,7 @@ async function loadHunkFileActivities(hunkPath, cwd) {
6849
8055
  const activities = [];
6850
8056
  let text = "";
6851
8057
  try {
6852
- text = await readFile8(hunkPath, "utf8");
8058
+ text = await readFile9(hunkPath, "utf8");
6853
8059
  } catch {
6854
8060
  return activities;
6855
8061
  }
@@ -6891,7 +8097,7 @@ async function loadHunkFileActivities(hunkPath, cwd) {
6891
8097
  }
6892
8098
  return activities;
6893
8099
  }
6894
- var grokHandler = (msg) => hookHandler(SOURCE_ID, msg);
8100
+ var grokHandler = (msg) => hookHandler(SOURCE_ID2, msg);
6895
8101
  function hookConfig5() {
6896
8102
  const anyTool = [{ matcher: ".*", hooks: [grokHandler("Reporting tool activity")] }];
6897
8103
  return {
@@ -6913,9 +8119,9 @@ function hookConfig5() {
6913
8119
  }
6914
8120
  function createGrokBuildAdapter() {
6915
8121
  return {
6916
- id: SOURCE_ID,
8122
+ id: SOURCE_ID2,
6917
8123
  label: "Grok Build",
6918
- agentName: AGENT_NAME,
8124
+ agentName: AGENT_NAME2,
6919
8125
  kind: "agent",
6920
8126
  detectPath(home, env) {
6921
8127
  return grokHome(home, env);
@@ -6924,7 +8130,7 @@ function createGrokBuildAdapter() {
6924
8130
  return grokHooksPath(home, env);
6925
8131
  },
6926
8132
  async isInstalled(home, env) {
6927
- return isHooksJsonInstalled(grokHooksPath(home, env), HOOK_COMMAND);
8133
+ return isHooksJsonInstalled(grokHooksPath(home, env), HOOK_COMMAND2);
6928
8134
  },
6929
8135
  installEntries(home, env) {
6930
8136
  return [{
@@ -6941,8 +8147,8 @@ function createGrokBuildAdapter() {
6941
8147
  }
6942
8148
 
6943
8149
  // src/adapters/kimi-code.ts
6944
- import { readFile as readFile9 } from "node:fs/promises";
6945
- import path14 from "node:path";
8150
+ import { readFile as readFile10 } from "node:fs/promises";
8151
+ import path15 from "node:path";
6946
8152
 
6947
8153
  // src/lib/toml-hooks.ts
6948
8154
  init_fs();
@@ -7089,20 +8295,20 @@ function tomlNumberField(body, key) {
7089
8295
  }
7090
8296
 
7091
8297
  // src/adapters/kimi-code.ts
7092
- var HOOK_COMMAND2 = "vibetime hook --agent kimi-code";
7093
- var HOOK_TIMEOUT_SECONDS = 10;
8298
+ var HOOK_COMMAND3 = "vibetime hook --agent kimi-code";
8299
+ var HOOK_TIMEOUT_SECONDS2 = 10;
7094
8300
  function kimiCodeHome(home, env) {
7095
8301
  const override = env?.KIMI_CODE_HOME || env?.KIMI_HOME;
7096
8302
  if (override && override.trim()) {
7097
- return path14.resolve(override);
8303
+ return path15.resolve(override);
7098
8304
  }
7099
- return path14.join(home, ".kimi-code");
8305
+ return path15.join(home, ".kimi-code");
7100
8306
  }
7101
8307
  function kimiCodeSessionsDir(home, env) {
7102
- return path14.join(kimiCodeHome(home, env), "sessions");
8308
+ return path15.join(kimiCodeHome(home, env), "sessions");
7103
8309
  }
7104
8310
  function kimiCodeConfigPath(home, env) {
7105
- return path14.join(kimiCodeHome(home, env), "config.toml");
8311
+ return path15.join(kimiCodeHome(home, env), "config.toml");
7106
8312
  }
7107
8313
  function kimiHookRules() {
7108
8314
  const events = [
@@ -7119,8 +8325,8 @@ function kimiHookRules() {
7119
8325
  ];
7120
8326
  return events.map((event) => ({
7121
8327
  event,
7122
- command: HOOK_COMMAND2,
7123
- timeout: HOOK_TIMEOUT_SECONDS
8328
+ command: HOOK_COMMAND3,
8329
+ timeout: HOOK_TIMEOUT_SECONDS2
7124
8330
  }));
7125
8331
  }
7126
8332
  function baseKimiEvent(event) {
@@ -7179,10 +8385,10 @@ function sessionIdFromWirePath(filePath) {
7179
8385
  return match?.[1];
7180
8386
  }
7181
8387
  async function readSessionState(filePath) {
7182
- const sessionDir = path14.dirname(path14.dirname(path14.dirname(filePath)));
7183
- const statePath = path14.join(sessionDir, "state.json");
8388
+ const sessionDir = path15.dirname(path15.dirname(path15.dirname(filePath)));
8389
+ const statePath = path15.join(sessionDir, "state.json");
7184
8390
  try {
7185
- const text = await readFile9(statePath, "utf8");
8391
+ const text = await readFile10(statePath, "utf8");
7186
8392
  const raw = JSON.parse(text);
7187
8393
  if (!isPlainObject(raw)) {
7188
8394
  return {};
@@ -7197,15 +8403,15 @@ async function readSessionState(filePath) {
7197
8403
  }
7198
8404
  }
7199
8405
  async function parseKimiCodeSessionFile(filePath, options) {
7200
- if (path14.basename(filePath) !== "wire.jsonl") {
8406
+ if (path15.basename(filePath) !== "wire.jsonl") {
7201
8407
  return [];
7202
8408
  }
7203
- const text = await readFile9(filePath, "utf8");
8409
+ const text = await readFile10(filePath, "utf8");
7204
8410
  const lines = text.split("\n").filter(Boolean);
7205
8411
  const stateMeta = await readSessionState(filePath);
7206
8412
  let sessionId = stateMeta.sessionId || sessionIdFromWirePath(filePath);
7207
8413
  let cwd = stateMeta.cwd;
7208
- let project = cwd ? path14.basename(cwd) : void 0;
8414
+ let project = cwd ? path15.basename(cwd) : void 0;
7209
8415
  let model;
7210
8416
  let provider;
7211
8417
  let reasoningEffort;
@@ -7251,7 +8457,7 @@ async function parseKimiCodeSessionFile(filePath, options) {
7251
8457
  const disclosedCwd = stringField(disclosure, "cwd");
7252
8458
  if (disclosedCwd) {
7253
8459
  cwd = disclosedCwd;
7254
- project = path14.basename(disclosedCwd);
8460
+ project = path15.basename(disclosedCwd);
7255
8461
  }
7256
8462
  continue;
7257
8463
  }
@@ -7565,7 +8771,7 @@ function createKimiCodeAdapter() {
7565
8771
  return kimiCodeConfigPath(home, env);
7566
8772
  },
7567
8773
  async isInstalled(home, env) {
7568
- return hasTomlHookCommand(kimiCodeConfigPath(home, env), HOOK_COMMAND2);
8774
+ return hasTomlHookCommand(kimiCodeConfigPath(home, env), HOOK_COMMAND3);
7569
8775
  },
7570
8776
  installEntries(home, env) {
7571
8777
  return [{
@@ -7582,8 +8788,8 @@ function createKimiCodeAdapter() {
7582
8788
  }
7583
8789
 
7584
8790
  // src/adapters/opencode.ts
7585
- import os6 from "node:os";
7586
- import path15 from "node:path";
8791
+ import os7 from "node:os";
8792
+ import path16 from "node:path";
7587
8793
  async function parseOpenCodeSessionFile(dbPath, options) {
7588
8794
  const { DatabaseSync } = await import("node:sqlite");
7589
8795
  if (!dbPath.endsWith(".db")) {
@@ -7642,7 +8848,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
7642
8848
  const isSubagent = sessionId !== rawSessionId;
7643
8849
  const sessionEventStart = events.length;
7644
8850
  const cwd = session.directory || session.path || void 0;
7645
- const project = cwd ? path15.basename(cwd) : void 0;
8851
+ const project = cwd ? path16.basename(cwd) : void 0;
7646
8852
  const sessionTs = msToIso(session.time_created);
7647
8853
  events.push(baseOpenCodeEvent({
7648
8854
  ts: sessionTs,
@@ -7750,7 +8956,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
7750
8956
  const provider = currentProvider;
7751
8957
  const pathObj = objectField(info, "path");
7752
8958
  const assistantCwd = stringField(pathObj, "cwd") || cwd;
7753
- const assistantProject = assistantCwd ? path15.basename(assistantCwd) : project;
8959
+ const assistantProject = assistantCwd ? path16.basename(assistantCwd) : project;
7754
8960
  const completedTs = numberField(objectField(info, "time"), "completed");
7755
8961
  const createdTs = timeCreated;
7756
8962
  const tokens = opencodeUsageFromInfo(info);
@@ -8024,33 +9230,33 @@ function opencodeUsageFromInfo(info) {
8024
9230
  function opencodeConfigDir(home, env) {
8025
9231
  const override = env?.OPENCODE_CONFIG_DIR;
8026
9232
  if (override && override.trim()) {
8027
- return path15.resolve(override);
9233
+ return path16.resolve(override);
8028
9234
  }
8029
9235
  const xdgConfig = env?.XDG_CONFIG_HOME;
8030
9236
  if (xdgConfig && xdgConfig.trim()) {
8031
- return path15.join(path15.resolve(xdgConfig), "opencode");
9237
+ return path16.join(path16.resolve(xdgConfig), "opencode");
8032
9238
  }
8033
- return path15.join(home, ".config", "opencode");
9239
+ return path16.join(home, ".config", "opencode");
8034
9240
  }
8035
9241
  function opencodeDataCandidates(home, env) {
8036
9242
  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")];
9243
+ const primary = xdgData && xdgData.trim() ? path16.join(path16.resolve(xdgData), "opencode", "opencode.db") : path16.join(home, ".local", "share", "opencode", "opencode.db");
9244
+ return [primary, path16.join(home, ".opencode", "opencode.db")];
8039
9245
  }
8040
- async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
8041
- const { stat: stat15 } = await import("node:fs/promises");
9246
+ async function opencodeBackfillFiles(sourceRoot, home = os7.homedir(), env) {
9247
+ const { stat: stat16 } = await import("node:fs/promises");
8042
9248
  if (sourceRoot) {
8043
9249
  if (!sourceRoot.endsWith(".db")) {
8044
9250
  return [];
8045
9251
  }
8046
- const info = await stat15(sourceRoot).catch(() => null);
9252
+ const info = await stat16(sourceRoot).catch(() => null);
8047
9253
  if (!info) {
8048
9254
  return [];
8049
9255
  }
8050
9256
  return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
8051
9257
  }
8052
9258
  for (const candidatePath of opencodeDataCandidates(home, env)) {
8053
- const info = await stat15(candidatePath).catch(() => null);
9259
+ const info = await stat16(candidatePath).catch(() => null);
8054
9260
  if (info) {
8055
9261
  return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
8056
9262
  }
@@ -8125,12 +9331,12 @@ function createOpenCodeAdapter() {
8125
9331
  return opencodeConfigDir(home, env);
8126
9332
  },
8127
9333
  installedPath(home, env) {
8128
- return path15.join(opencodeConfigDir(home, env), PLUGIN_PATH);
9334
+ return path16.join(opencodeConfigDir(home, env), PLUGIN_PATH);
8129
9335
  },
8130
9336
  async isInstalled(home, env) {
8131
9337
  try {
8132
9338
  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));
9339
+ return await pathExists2(path16.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path16.join(".opencode", PLUGIN_PATH));
8134
9340
  } catch {
8135
9341
  return false;
8136
9342
  }
@@ -8138,7 +9344,7 @@ function createOpenCodeAdapter() {
8138
9344
  installEntries(home, env) {
8139
9345
  return [{
8140
9346
  kind: "file",
8141
- path: path15.join(opencodeConfigDir(home, env), PLUGIN_PATH),
9347
+ path: path16.join(opencodeConfigDir(home, env), PLUGIN_PATH),
8142
9348
  content: opencodePluginContent()
8143
9349
  }];
8144
9350
  },
@@ -8150,9 +9356,9 @@ function createOpenCodeAdapter() {
8150
9356
  }
8151
9357
 
8152
9358
  // 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";
9359
+ import { readdir as readdir8, readFile as readFile11, stat as stat9 } from "node:fs/promises";
9360
+ import os8 from "node:os";
9361
+ import path17 from "node:path";
8156
9362
  init_fs();
8157
9363
  function piHostSessionIdFromBasename(basename) {
8158
9364
  const withoutExt = basename.endsWith(".jsonl") ? basename.slice(0, -".jsonl".length) : basename;
@@ -8167,7 +9373,7 @@ function piHostSessionIdFromBasename(basename) {
8167
9373
  }
8168
9374
  function resolvePiBackfillGroupId(filePath) {
8169
9375
  const normalized = filePath.replaceAll("\\", "/");
8170
- const base = path16.basename(filePath);
9376
+ const base = path17.basename(filePath);
8171
9377
  const nest = normalized.match(/([^/]+)\/[^/]+\/run-\d+\/session\.jsonl$/);
8172
9378
  if (nest) {
8173
9379
  return piHostSessionIdFromBasename(nest[1]);
@@ -8179,8 +9385,8 @@ function resolvePiBackfillGroupId(filePath) {
8179
9385
  }
8180
9386
  function parsePiSubagentLink(filePath, headerParentSession) {
8181
9387
  if (headerParentSession) {
8182
- const parentFile = path16.isAbsolute(headerParentSession) ? headerParentSession : void 0;
8183
- const parentSessionId2 = parentFile ? path16.basename(parentFile, ".jsonl") : headerParentSession;
9388
+ const parentFile = path17.isAbsolute(headerParentSession) ? headerParentSession : void 0;
9389
+ const parentSessionId2 = parentFile ? path17.basename(parentFile, ".jsonl") : headerParentSession;
8184
9390
  return { parentSessionId: parentSessionId2, parentSessionFile: parentFile, explicit: true };
8185
9391
  }
8186
9392
  const normalized = filePath.replaceAll("\\", "/");
@@ -8193,20 +9399,20 @@ function parsePiSubagentLink(filePath, headerParentSession) {
8193
9399
  return void 0;
8194
9400
  }
8195
9401
  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`);
9402
+ const parentDir = path17.dirname(path17.dirname(path17.dirname(filePath)));
9403
+ const parentSessionFile = path17.join(path17.dirname(parentDir), `${parentBasename}.jsonl`);
8198
9404
  return { parentSessionId, parentSessionFile, explicit: false };
8199
9405
  }
8200
9406
  async function resolveParentContext(link, options) {
8201
9407
  if (link.parentSessionFile) {
8202
9408
  try {
8203
- const text = await readFile10(link.parentSessionFile, "utf8");
9409
+ const text = await readFile11(link.parentSessionFile, "utf8");
8204
9410
  const firstLine = text.split("\n").find((line) => line.trim().length > 0);
8205
9411
  const raw = firstLine ? parseJsonLine(firstLine) : void 0;
8206
9412
  if (raw) {
8207
9413
  const id = stringField(raw, "id");
8208
9414
  const cwd = stringField(raw, "cwd");
8209
- const project = cwd ? path16.basename(cwd) : void 0;
9415
+ const project = cwd ? path17.basename(cwd) : void 0;
8210
9416
  if (id || cwd || project) {
8211
9417
  return { sessionId: id, cwd, project };
8212
9418
  }
@@ -8255,7 +9461,7 @@ function rebuildEventIdentity2(event) {
8255
9461
  };
8256
9462
  }
8257
9463
  async function parsePiSessionFile(filePath, options) {
8258
- const text = await readFile10(filePath, "utf8");
9464
+ const text = await readFile11(filePath, "utf8");
8259
9465
  const lines = text.split("\n").filter(Boolean);
8260
9466
  let sessionId;
8261
9467
  let cwd;
@@ -8287,7 +9493,7 @@ async function parsePiSessionFile(filePath, options) {
8287
9493
  sessionId = stringField(raw, "id") || state.sessionId;
8288
9494
  state.sessionId = sessionId || state.sessionId;
8289
9495
  cwd = stringField(raw, "cwd") || cwd;
8290
- project = cwd ? path16.basename(cwd) : project;
9496
+ project = cwd ? path17.basename(cwd) : project;
8291
9497
  headerParentSession = stringField(raw, "parentSession") || headerParentSession;
8292
9498
  continue;
8293
9499
  }
@@ -8494,7 +9700,7 @@ async function parsePiFile(filePath, options) {
8494
9700
  async function parsePiWorkflowRunFile(filePath, options) {
8495
9701
  let raw;
8496
9702
  try {
8497
- raw = JSON.parse(await readFile10(filePath, "utf8"));
9703
+ raw = JSON.parse(await readFile11(filePath, "utf8"));
8498
9704
  } catch {
8499
9705
  return [];
8500
9706
  }
@@ -8562,17 +9768,17 @@ async function parsePiWorkflowRunFile(filePath, options) {
8562
9768
  return state.events.filter((event) => matchesBackfillFilters(event, options));
8563
9769
  }
8564
9770
  async function findPiSessionFileById(sessionId, options) {
8565
- const sessionsDir = piSessionDir(path16.resolve(stringOption(options.home) || os7.homedir()));
9771
+ const sessionsDir = piSessionDir(path17.resolve(stringOption(options.home) || os8.homedir()));
8566
9772
  try {
8567
- const projectDirs = await readdir7(sessionsDir, { withFileTypes: true });
9773
+ const projectDirs = await readdir8(sessionsDir, { withFileTypes: true });
8568
9774
  for (const dir of projectDirs) {
8569
9775
  if (!dir.isDirectory()) {
8570
9776
  continue;
8571
9777
  }
8572
- const names = await readdir7(path16.join(sessionsDir, dir.name));
9778
+ const names = await readdir8(path17.join(sessionsDir, dir.name));
8573
9779
  const hit = names.find((name) => name.endsWith(`_${sessionId}.jsonl`));
8574
9780
  if (hit) {
8575
- return path16.join(sessionsDir, dir.name, hit);
9781
+ return path17.join(sessionsDir, dir.name, hit);
8576
9782
  }
8577
9783
  }
8578
9784
  } catch {
@@ -8814,23 +10020,23 @@ export default function (pi: ExtensionAPI) {
8814
10020
  function piAgentDir(home, env) {
8815
10021
  const override = env?.PI_CODING_AGENT_DIR;
8816
10022
  if (override && override.trim()) {
8817
- return path16.resolve(override);
10023
+ return path17.resolve(override);
8818
10024
  }
8819
- return path16.join(home, ".pi", "agent");
10025
+ return path17.join(home, ".pi", "agent");
8820
10026
  }
8821
10027
  function piSessionDir(home, env) {
8822
10028
  const override = env?.PI_CODING_AGENT_SESSION_DIR;
8823
10029
  if (override && override.trim()) {
8824
- return path16.resolve(override);
10030
+ return path17.resolve(override);
8825
10031
  }
8826
- return path16.join(piAgentDir(home, env), "sessions");
10032
+ return path17.join(piAgentDir(home, env), "sessions");
8827
10033
  }
8828
10034
  function piWorkflowProjectsDir(home) {
8829
- return path16.join(home, ".pi", "workflows", "projects");
10035
+ return path17.join(home, ".pi", "workflows", "projects");
8830
10036
  }
8831
10037
  async function workflowRunGroupId(filePath) {
8832
10038
  try {
8833
- const raw = JSON.parse(await readFile10(filePath, "utf8"));
10039
+ const raw = JSON.parse(await readFile11(filePath, "utf8"));
8834
10040
  if (!isPlainObject(raw)) {
8835
10041
  return void 0;
8836
10042
  }
@@ -8839,14 +10045,14 @@ async function workflowRunGroupId(filePath) {
8839
10045
  return void 0;
8840
10046
  }
8841
10047
  }
8842
- async function piBackfillFiles(sourceRoot, home = os7.homedir(), env) {
10048
+ async function piBackfillFiles(sourceRoot, home = os8.homedir(), env) {
8843
10049
  const lists = sourceRoot ? [await listFilesByExtensions(sourceRoot, [".jsonl", ".json"])] : await Promise.all([
8844
10050
  listFilesByExtensions(piSessionDir(home, env), [".jsonl"]),
8845
10051
  listFilesByExtensions(piWorkflowProjectsDir(home), [".json"])
8846
10052
  ]);
8847
10053
  const files = lists.flat().sort();
8848
10054
  return Promise.all(files.map(async (filePath) => {
8849
- const info = await stat8(filePath);
10055
+ const info = await stat9(filePath);
8850
10056
  let groupId = resolvePiBackfillGroupId(filePath);
8851
10057
  if (!groupId && filePath.endsWith(".json")) {
8852
10058
  groupId = await workflowRunGroupId(filePath);
@@ -8868,12 +10074,12 @@ function createPiAdapter() {
8868
10074
  return piAgentDir(home, env);
8869
10075
  },
8870
10076
  installedPath(home, env) {
8871
- return path16.join(piAgentDir(home, env), "extensions", "vibetime.ts");
10077
+ return path17.join(piAgentDir(home, env), "extensions", "vibetime.ts");
8872
10078
  },
8873
10079
  async isInstalled(home, env) {
8874
10080
  try {
8875
10081
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
8876
- return await pathExists2(path16.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
10082
+ return await pathExists2(path17.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
8877
10083
  } catch {
8878
10084
  return false;
8879
10085
  }
@@ -8881,7 +10087,7 @@ function createPiAdapter() {
8881
10087
  installEntries(home, env) {
8882
10088
  return [{
8883
10089
  kind: "file",
8884
- path: path16.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
10090
+ path: path17.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
8885
10091
  content: piExtensionContent()
8886
10092
  }];
8887
10093
  },
@@ -8893,14 +10099,14 @@ function createPiAdapter() {
8893
10099
  }
8894
10100
 
8895
10101
  // 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";
10102
+ import { readdir as readdir9, readFile as readFile12, stat as stat10 } from "node:fs/promises";
10103
+ import os10 from "node:os";
10104
+ import path19 from "node:path";
8899
10105
 
8900
10106
  // src/adapters/qoder-local-db.ts
8901
10107
  import { access } from "node:fs/promises";
8902
- import os8 from "node:os";
8903
- import path17 from "node:path";
10108
+ import os9 from "node:os";
10109
+ import path18 from "node:path";
8904
10110
  function takeQoderDbModelCall(calls, requestId, blockStart) {
8905
10111
  if (requestId) {
8906
10112
  const call = calls.byRequestId.get(requestId)?.shift();
@@ -8917,14 +10123,14 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
8917
10123
  }
8918
10124
  return calls.ordered.shift();
8919
10125
  }
8920
- function appDataRoot(appDirName, home = os8.homedir()) {
10126
+ function appDataRoot(appDirName, home = os9.homedir()) {
8921
10127
  if (process.platform === "darwin") {
8922
- return path17.join(home, "Library", "Application Support", appDirName);
10128
+ return path18.join(home, "Library", "Application Support", appDirName);
8923
10129
  }
8924
10130
  if (process.platform === "win32") {
8925
- return path17.join(process.env.APPDATA || path17.join(home, "AppData", "Roaming"), appDirName);
10131
+ return path18.join(process.env.APPDATA || path18.join(home, "AppData", "Roaming"), appDirName);
8926
10132
  }
8927
- return path17.join(home, ".config", appDirName);
10133
+ return path18.join(home, ".config", appDirName);
8928
10134
  }
8929
10135
  function qoderLocalDbCandidates(appDirName) {
8930
10136
  const candidates = [];
@@ -8934,8 +10140,8 @@ function qoderLocalDbCandidates(appDirName) {
8934
10140
  }
8935
10141
  const configRoot = appDataRoot(appDirName);
8936
10142
  candidates.push(
8937
- path17.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
8938
- path17.join(configRoot, "SharedClientCache", "db", "local.db")
10143
+ path18.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
10144
+ path18.join(configRoot, "SharedClientCache", "db", "local.db")
8939
10145
  );
8940
10146
  return candidates;
8941
10147
  }
@@ -8944,7 +10150,7 @@ async function loadQoderIdeModelCatalog(appDirName, home) {
8944
10150
  try {
8945
10151
  const { DatabaseSync } = await import("node:sqlite");
8946
10152
  const db = new DatabaseSync(
8947
- path17.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
10153
+ path18.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
8948
10154
  { readOnly: true }
8949
10155
  );
8950
10156
  try {
@@ -9086,7 +10292,7 @@ function resolveSessionPreferredModel(db, sessionId, modelMap) {
9086
10292
 
9087
10293
  // src/adapters/qoder-cn.ts
9088
10294
  function parseQoderCnPaths(filePath) {
9089
- const parts = filePath.split(path18.sep);
10295
+ const parts = filePath.split(path19.sep);
9090
10296
  const subagentsIdx = parts.lastIndexOf("subagents");
9091
10297
  let sessionId = "";
9092
10298
  let projectName = "";
@@ -9096,17 +10302,17 @@ function parseQoderCnPaths(filePath) {
9096
10302
  sessionId = parts[subagentsIdx - 1];
9097
10303
  projectName = parts[subagentsIdx - 2];
9098
10304
  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);
10305
+ configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
10306
+ mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path19.sep);
9101
10307
  } else {
9102
10308
  const filename = parts.at(-1) || "";
9103
- sessionId = path18.basename(filename, ".jsonl");
10309
+ sessionId = path19.basename(filename, ".jsonl");
9104
10310
  projectName = parts.at(-2) || "";
9105
10311
  if (projectName === "transcript") {
9106
10312
  projectName = parts.at(-3) || "";
9107
10313
  }
9108
10314
  const projectsIdx = parts.lastIndexOf("projects");
9109
- configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
10315
+ configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
9110
10316
  }
9111
10317
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
9112
10318
  }
@@ -9129,7 +10335,7 @@ function rebuildEventIdentity3(event) {
9129
10335
  }
9130
10336
  async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
9131
10337
  try {
9132
- const content = await readFile11(dynamicTextsPath, "utf8");
10338
+ const content = await readFile12(dynamicTextsPath, "utf8");
9133
10339
  const json = JSON.parse(content);
9134
10340
  const texts = json.texts || {};
9135
10341
  const map = {};
@@ -9145,10 +10351,10 @@ async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
9145
10351
  }
9146
10352
  }
9147
10353
  async function loadQoderCnModelNames(configDir2, home) {
9148
- const map = await parseModelNamesFromDynamicTexts(path18.join(configDir2, ".auth", "dynamic-texts.json"));
10354
+ const map = await parseModelNamesFromDynamicTexts(path19.join(configDir2, ".auth", "dynamic-texts.json"));
9149
10355
  const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
9150
10356
  if (siblingConfigDir !== configDir2) {
9151
- const siblingMap = await parseModelNamesFromDynamicTexts(path18.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
10357
+ const siblingMap = await parseModelNamesFromDynamicTexts(path19.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
9152
10358
  for (const [key, val] of Object.entries(siblingMap)) {
9153
10359
  if (!(key in map)) {
9154
10360
  map[key] = val;
@@ -9167,15 +10373,15 @@ async function loadQoderCnModelNames(configDir2, home) {
9167
10373
  }
9168
10374
  async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
9169
10375
  const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
9170
- const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
10376
+ const segmentsPath = path19.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
9171
10377
  const modelCalls = [];
9172
10378
  try {
9173
- const files = await readdir8(segmentsPath);
10379
+ const files = await readdir9(segmentsPath);
9174
10380
  for (const file of files) {
9175
10381
  if (!file.endsWith(".jsonl")) {
9176
10382
  continue;
9177
10383
  }
9178
- const content = await readFile11(path18.join(segmentsPath, file), "utf8");
10384
+ const content = await readFile12(path19.join(segmentsPath, file), "utf8");
9179
10385
  let currentTurnIsSubagent = false;
9180
10386
  for (const line of content.split("\n").filter(Boolean)) {
9181
10387
  const raw = parseJsonLine(line);
@@ -9209,7 +10415,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
9209
10415
  return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
9210
10416
  }
9211
10417
  async function parseQoderCnSessionFile(filePath, options) {
9212
- const text = await readFile11(filePath, "utf8");
10418
+ const text = await readFile12(filePath, "utf8");
9213
10419
  const lines = text.split("\n").filter(Boolean);
9214
10420
  const parsedPaths = parseQoderCnPaths(filePath);
9215
10421
  const { configDir: configDir2 } = parsedPaths;
@@ -9220,7 +10426,7 @@ async function parseQoderCnSessionFile(filePath, options) {
9220
10426
  let cwd;
9221
10427
  let project = projectContext.project;
9222
10428
  let model;
9223
- const home = path18.resolve(stringOption(options.home) || os9.homedir());
10429
+ const home = path19.resolve(stringOption(options.home) || os10.homedir());
9224
10430
  const modelMap = await loadQoderCnModelNames(configDir2, home);
9225
10431
  const isSubagentSession = filePath.includes("subagents");
9226
10432
  const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
@@ -9255,7 +10461,7 @@ async function parseQoderCnSessionFile(filePath, options) {
9255
10461
  sessionId = stringField(raw, "sessionId") || sessionId;
9256
10462
  state.sessionId = sessionId;
9257
10463
  cwd = stringField(raw, "cwd") || cwd;
9258
- project = projectContext.project || (cwd ? path18.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
10464
+ project = projectContext.project || (cwd ? path19.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
9259
10465
  if (!ts) {
9260
10466
  continue;
9261
10467
  }
@@ -9591,7 +10797,7 @@ async function parseQoderCnSessionFile(filePath, options) {
9591
10797
  }
9592
10798
  dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", parsedPaths.sessionId, modelMap);
9593
10799
  if (dbModelCalls.rootSessionId) {
9594
- const parentPath = path18.join(path18.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
10800
+ const parentPath = path19.join(path19.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
9595
10801
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
9596
10802
  return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity3({
9597
10803
  ...event,
@@ -9744,28 +10950,28 @@ function extractQoderAttachedPrompt(content) {
9744
10950
  }
9745
10951
  async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
9746
10952
  const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
9747
- const isSubagent = filePath.includes(`${path18.sep}subagents${path18.sep}`);
10953
+ const isSubagent = filePath.includes(`${path19.sep}subagents${path19.sep}`);
9748
10954
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
9749
10955
  let cwds = [];
9750
10956
  for (const line of lines) {
9751
10957
  const raw = parseJsonLine(line);
9752
10958
  const cwd = raw ? stringField(raw, "cwd") : void 0;
9753
- if (cwd && path18.isAbsolute(cwd)) {
10959
+ if (cwd && path19.isAbsolute(cwd)) {
9754
10960
  cwds.push(cwd);
9755
10961
  }
9756
10962
  }
9757
10963
  if (isSubagent) {
9758
- if (inherited?.cwd && path18.isAbsolute(inherited.cwd)) {
10964
+ if (inherited?.cwd && path19.isAbsolute(inherited.cwd)) {
9759
10965
  cwds = [inherited.cwd];
9760
10966
  } else {
9761
- const parentSessionPath = path18.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
10967
+ const parentSessionPath = path19.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
9762
10968
  try {
9763
- const parentText = await readFile11(parentSessionPath, "utf8");
10969
+ const parentText = await readFile12(parentSessionPath, "utf8");
9764
10970
  const parentCwds = [];
9765
10971
  for (const line of parentText.split("\n").filter(Boolean)) {
9766
10972
  const raw = parseJsonLine(line);
9767
10973
  const cwd = raw ? stringField(raw, "cwd") : void 0;
9768
- if (cwd && path18.isAbsolute(cwd)) {
10974
+ if (cwd && path19.isAbsolute(cwd)) {
9769
10975
  parentCwds.push(cwd);
9770
10976
  }
9771
10977
  }
@@ -9777,7 +10983,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
9777
10983
  }
9778
10984
  }
9779
10985
  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));
10986
+ const project = inherited?.project || (cwds.length > 0 ? path19.basename(cwds[0]) : root ? path19.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
9781
10987
  return {
9782
10988
  project,
9783
10989
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
@@ -9786,15 +10992,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
9786
10992
  async function gitRootFromCwds2(cwds) {
9787
10993
  const seen = /* @__PURE__ */ new Set();
9788
10994
  for (const cwd of cwds) {
9789
- let current = path18.resolve(cwd);
10995
+ let current = path19.resolve(cwd);
9790
10996
  while (!seen.has(current)) {
9791
10997
  seen.add(current);
9792
10998
  try {
9793
- await stat9(path18.join(current, ".git"));
10999
+ await stat10(path19.join(current, ".git"));
9794
11000
  return current;
9795
11001
  } catch {
9796
11002
  }
9797
- const parent = path18.dirname(current);
11003
+ const parent = path19.dirname(current);
9798
11004
  if (parent === current) {
9799
11005
  break;
9800
11006
  }
@@ -9805,12 +11011,12 @@ async function gitRootFromCwds2(cwds) {
9805
11011
  }
9806
11012
  function qoderCnProjectRootFromCwds(projectDir, cwds) {
9807
11013
  for (const cwd of cwds) {
9808
- let current = path18.resolve(cwd);
11014
+ let current = path19.resolve(cwd);
9809
11015
  while (true) {
9810
11016
  if (encodeQoderCnProjectPath(current) === projectDir) {
9811
11017
  return current;
9812
11018
  }
9813
- const parent = path18.dirname(current);
11019
+ const parent = path19.dirname(current);
9814
11020
  if (parent === current) {
9815
11021
  break;
9816
11022
  }
@@ -9820,14 +11026,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
9820
11026
  return void 0;
9821
11027
  }
9822
11028
  function encodeQoderCnProjectPath(value) {
9823
- return path18.resolve(value).split(path18.sep).join("-").replaceAll("_", "-");
11029
+ return path19.resolve(value).split(path19.sep).join("-").replaceAll("_", "-");
9824
11030
  }
9825
11031
  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();
11032
+ const projectDir = path19.basename(path19.dirname(filePath));
11033
+ const home = options ? path19.resolve(stringOption(options.home) || os10.homedir()) : os10.homedir();
9828
11034
  const resolved = await resolveQoderCnProjectPath(projectDir, home);
9829
11035
  if (resolved) {
9830
- return path18.basename(resolved);
11036
+ return path19.basename(resolved);
9831
11037
  }
9832
11038
  const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
9833
11039
  if (projectDir.startsWith(homePrefix)) {
@@ -9847,12 +11053,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
9847
11053
  while (projectDir.startsWith(`${currentEncoded}-`)) {
9848
11054
  let matchedChild;
9849
11055
  try {
9850
- const entries = await readdir8(current, { withFileTypes: true });
11056
+ const entries = await readdir9(current, { withFileTypes: true });
9851
11057
  for (const entry of entries) {
9852
11058
  if (!entry.isDirectory()) {
9853
11059
  continue;
9854
11060
  }
9855
- const candidate = path18.join(current, entry.name);
11061
+ const candidate = path19.join(current, entry.name);
9856
11062
  const encoded = encodeQoderCnProjectPath(candidate);
9857
11063
  if (encoded === projectDir) {
9858
11064
  return candidate;
@@ -9897,9 +11103,9 @@ function hookConfig6() {
9897
11103
  function qoderCnConfigDir(home, env) {
9898
11104
  const override = env?.QODER_CN_CONFIG_DIR;
9899
11105
  if (override && override.trim()) {
9900
- return path18.resolve(override);
11106
+ return path19.resolve(override);
9901
11107
  }
9902
- return path18.join(home, ".qoder-cn");
11108
+ return path19.join(home, ".qoder-cn");
9903
11109
  }
9904
11110
  function createQoderCnAdapter() {
9905
11111
  return {
@@ -9911,27 +11117,27 @@ function createQoderCnAdapter() {
9911
11117
  return qoderCnConfigDir(home, env);
9912
11118
  },
9913
11119
  installedPath(home, env) {
9914
- return path18.join(qoderCnConfigDir(home, env), "settings.json");
11120
+ return path19.join(qoderCnConfigDir(home, env), "settings.json");
9915
11121
  },
9916
11122
  async isInstalled(home, env) {
9917
11123
  return isHooksJsonInstalled(
9918
- path18.join(qoderCnConfigDir(home, env), "settings.json"),
11124
+ path19.join(qoderCnConfigDir(home, env), "settings.json"),
9919
11125
  "vibetime hook --agent qoder-cn"
9920
11126
  );
9921
11127
  },
9922
11128
  installEntries(home, env) {
9923
11129
  return [{
9924
11130
  kind: "hooks-json",
9925
- path: path18.join(qoderCnConfigDir(home, env), "settings.json"),
11131
+ path: path19.join(qoderCnConfigDir(home, env), "settings.json"),
9926
11132
  content: hookConfig6()
9927
11133
  }];
9928
11134
  },
9929
11135
  sourcePaths(home, env) {
9930
11136
  const base = qoderCnConfigDir(home, env);
9931
11137
  return [
9932
- path18.join(base, "projects"),
9933
- path18.join(base, ".qoder.json"),
9934
- path18.join(home, ".qoder.json")
11138
+ path19.join(base, "projects"),
11139
+ path19.join(base, ".qoder.json"),
11140
+ path19.join(home, ".qoder.json")
9935
11141
  ];
9936
11142
  },
9937
11143
  parseSessionFile: parseQoderCnSessionFile
@@ -9940,11 +11146,11 @@ function createQoderCnAdapter() {
9940
11146
 
9941
11147
  // src/adapters/qoder.ts
9942
11148
  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";
11149
+ import { readdir as readdir10, readFile as readFile13, stat as stat11 } from "node:fs/promises";
11150
+ import os11 from "node:os";
11151
+ import path20 from "node:path";
9946
11152
  function parseQoderPaths(filePath) {
9947
- const parts = filePath.split(path19.sep);
11153
+ const parts = filePath.split(path20.sep);
9948
11154
  const subagentsIdx = parts.lastIndexOf("subagents");
9949
11155
  let sessionId = "";
9950
11156
  let projectName = "";
@@ -9954,17 +11160,17 @@ function parseQoderPaths(filePath) {
9954
11160
  sessionId = parts[subagentsIdx - 1];
9955
11161
  projectName = parts[subagentsIdx - 2];
9956
11162
  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);
11163
+ configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
11164
+ mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path20.sep);
9959
11165
  } else {
9960
11166
  const filename = parts.at(-1) || "";
9961
- sessionId = path19.basename(filename, ".jsonl");
11167
+ sessionId = path20.basename(filename, ".jsonl");
9962
11168
  projectName = parts.at(-2) || "";
9963
11169
  if (projectName === "transcript") {
9964
11170
  projectName = parts.at(-3) || "";
9965
11171
  }
9966
11172
  const projectsIdx = parts.lastIndexOf("projects");
9967
- configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
11173
+ configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
9968
11174
  }
9969
11175
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
9970
11176
  }
@@ -9987,7 +11193,7 @@ function rebuildEventIdentity4(event) {
9987
11193
  }
9988
11194
  async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
9989
11195
  try {
9990
- const content = await readFile12(dynamicTextsPath, "utf8");
11196
+ const content = await readFile13(dynamicTextsPath, "utf8");
9991
11197
  const json = JSON.parse(content);
9992
11198
  const texts = json.texts || {};
9993
11199
  const map = {};
@@ -10003,10 +11209,10 @@ async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
10003
11209
  }
10004
11210
  }
10005
11211
  async function loadQoderModelNames(configDir2, home) {
10006
- const map = await parseModelNamesFromDynamicTexts2(path19.join(configDir2, ".auth", "dynamic-texts.json"));
11212
+ const map = await parseModelNamesFromDynamicTexts2(path20.join(configDir2, ".auth", "dynamic-texts.json"));
10007
11213
  const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
10008
11214
  if (siblingConfigDir !== configDir2) {
10009
- const siblingMap = await parseModelNamesFromDynamicTexts2(path19.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
11215
+ const siblingMap = await parseModelNamesFromDynamicTexts2(path20.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
10010
11216
  for (const [key, val] of Object.entries(siblingMap)) {
10011
11217
  if (!(key in map)) {
10012
11218
  map[key] = val;
@@ -10014,11 +11220,11 @@ async function loadQoderModelNames(configDir2, home) {
10014
11220
  }
10015
11221
  }
10016
11222
  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)) {
11223
+ for (const dir of [path20.join(home, ".qoder"), path20.join(home, ".qoder-cn")]) {
11224
+ if (path20.resolve(dir) === path20.resolve(configDir2)) {
10019
11225
  continue;
10020
11226
  }
10021
- const fallbackMap = await parseModelNamesFromDynamicTexts2(path19.join(dir, ".auth", "dynamic-texts.json"));
11227
+ const fallbackMap = await parseModelNamesFromDynamicTexts2(path20.join(dir, ".auth", "dynamic-texts.json"));
10022
11228
  for (const [key, val] of Object.entries(fallbackMap)) {
10023
11229
  if (!(key in map)) {
10024
11230
  map[key] = val;
@@ -10037,25 +11243,25 @@ async function loadQoderModelNames(configDir2, home) {
10037
11243
  return map;
10038
11244
  }
10039
11245
  function isQwenworkConfigRoot(configDir2) {
10040
- const name = path19.basename(path19.resolve(configDir2));
11246
+ const name = path20.basename(path20.resolve(configDir2));
10041
11247
  if (name === ".qwenworkcn" || name === ".qwenwork") {
10042
11248
  return true;
10043
11249
  }
10044
11250
  const override = process.env.QWENWORK_CONFIG_DIR;
10045
- return Boolean(override && override.trim() && path19.basename(path19.resolve(override)) === name);
11251
+ return Boolean(override && override.trim() && path20.basename(path20.resolve(override)) === name);
10046
11252
  }
10047
11253
  var FAILED_SEGMENT_STOP_REASONS = /* @__PURE__ */ new Set(["cancelled", "canceled", "error", "failed", "refusal"]);
10048
11254
  async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
10049
11255
  const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
10050
- const segmentsPath = path19.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
11256
+ const segmentsPath = path20.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
10051
11257
  const modelCalls = [];
10052
11258
  try {
10053
- const files = await readdir9(segmentsPath);
11259
+ const files = await readdir10(segmentsPath);
10054
11260
  for (const file of files) {
10055
11261
  if (!file.endsWith(".jsonl")) {
10056
11262
  continue;
10057
11263
  }
10058
- const content = await readFile12(path19.join(segmentsPath, file), "utf8");
11264
+ const content = await readFile13(path20.join(segmentsPath, file), "utf8");
10059
11265
  let currentTurnIsSubagent = false;
10060
11266
  for (const line of content.split("\n").filter(Boolean)) {
10061
11267
  const raw = parseJsonLine(line);
@@ -10089,7 +11295,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
10089
11295
  return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
10090
11296
  }
10091
11297
  async function parseQoderSessionFile(filePath, options) {
10092
- const text = await readFile12(filePath, "utf8");
11298
+ const text = await readFile13(filePath, "utf8");
10093
11299
  const lines = text.split("\n").filter(Boolean);
10094
11300
  const parsedPaths = parseQoderPaths(filePath);
10095
11301
  const { configDir: configDir2 } = parsedPaths;
@@ -10100,7 +11306,7 @@ async function parseQoderSessionFile(filePath, options) {
10100
11306
  let cwd;
10101
11307
  let project = projectContext.project;
10102
11308
  let model;
10103
- const home = path19.resolve(stringOption(options.home) || os10.homedir());
11309
+ const home = path20.resolve(stringOption(options.home) || os11.homedir());
10104
11310
  const modelMap = await loadQoderModelNames(configDir2, home);
10105
11311
  const qwenworkRoot = isQwenworkConfigRoot(configDir2);
10106
11312
  const isSubagentSession = filePath.includes("subagents");
@@ -10136,7 +11342,7 @@ async function parseQoderSessionFile(filePath, options) {
10136
11342
  sessionId = stringField(raw, "sessionId") || sessionId;
10137
11343
  state.sessionId = sessionId;
10138
11344
  cwd = stringField(raw, "cwd") || cwd;
10139
- project = projectContext.project || (cwd ? path19.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
11345
+ project = projectContext.project || (cwd ? path20.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
10140
11346
  if (!ts) {
10141
11347
  continue;
10142
11348
  }
@@ -10447,7 +11653,7 @@ async function parseQoderSessionFile(filePath, options) {
10447
11653
  }
10448
11654
  dbModelCalls ??= await loadQoderDbModelCalls("Qoder", parsedPaths.sessionId, modelMap);
10449
11655
  if (dbModelCalls.rootSessionId) {
10450
- const parentPath = path19.join(path19.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
11656
+ const parentPath = path20.join(path20.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
10451
11657
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
10452
11658
  return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity4({
10453
11659
  ...event,
@@ -10564,41 +11770,41 @@ function qoderExtractText(value) {
10564
11770
  }
10565
11771
  async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
10566
11772
  const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
10567
- const isSubagent = filePath.includes(`${path19.sep}subagents${path19.sep}`);
11773
+ const isSubagent = filePath.includes(`${path20.sep}subagents${path20.sep}`);
10568
11774
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
10569
11775
  let cwds = [];
10570
11776
  const workspaceDirs = [];
10571
11777
  for (const line of lines) {
10572
11778
  const raw = parseJsonLine(line);
10573
11779
  const cwd = raw ? stringField(raw, "cwd") : void 0;
10574
- if (cwd && path19.isAbsolute(cwd)) {
11780
+ if (cwd && path20.isAbsolute(cwd)) {
10575
11781
  cwds.push(cwd);
10576
11782
  }
10577
11783
  if (raw && stringField(raw, "type") === "workspace-directories") {
10578
11784
  for (const dir of arrayField5(raw, "directories")) {
10579
- if (typeof dir === "string" && path19.isAbsolute(dir)) {
11785
+ if (typeof dir === "string" && path20.isAbsolute(dir)) {
10580
11786
  workspaceDirs.push(dir);
10581
11787
  }
10582
11788
  }
10583
11789
  }
10584
11790
  }
10585
11791
  if (isSubagent) {
10586
- if (inherited?.cwd && path19.isAbsolute(inherited.cwd)) {
11792
+ if (inherited?.cwd && path20.isAbsolute(inherited.cwd)) {
10587
11793
  cwds = [inherited.cwd];
10588
11794
  } else {
10589
- const parentSessionPath = path19.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
11795
+ const parentSessionPath = path20.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
10590
11796
  try {
10591
- const parentText = await readFile12(parentSessionPath, "utf8");
11797
+ const parentText = await readFile13(parentSessionPath, "utf8");
10592
11798
  const parentCwds = [];
10593
11799
  for (const line of parentText.split("\n").filter(Boolean)) {
10594
11800
  const raw = parseJsonLine(line);
10595
11801
  const cwd = raw ? stringField(raw, "cwd") : void 0;
10596
- if (cwd && path19.isAbsolute(cwd)) {
11802
+ if (cwd && path20.isAbsolute(cwd)) {
10597
11803
  parentCwds.push(cwd);
10598
11804
  }
10599
11805
  if (workspaceDirs.length === 0 && raw && stringField(raw, "type") === "workspace-directories") {
10600
11806
  for (const dir of arrayField5(raw, "directories")) {
10601
- if (typeof dir === "string" && path19.isAbsolute(dir)) {
11807
+ if (typeof dir === "string" && path20.isAbsolute(dir)) {
10602
11808
  workspaceDirs.push(dir);
10603
11809
  }
10604
11810
  }
@@ -10618,29 +11824,29 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
10618
11824
  }
10619
11825
  }
10620
11826
  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));
11827
+ const project = inherited?.project || (cwds.length > 0 ? path20.basename(cwds[0]) : root ? path20.basename(root) : await qoderProjectFromFilePath(filePath, options));
10622
11828
  return {
10623
11829
  project,
10624
11830
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
10625
11831
  };
10626
11832
  }
10627
11833
  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}`);
11834
+ const resolvedDir = path20.resolve(dir);
11835
+ const resolved = path20.resolve(candidate);
11836
+ return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path20.sep}`);
10631
11837
  }
10632
11838
  async function gitRootFromCwds3(cwds) {
10633
11839
  const seen = /* @__PURE__ */ new Set();
10634
11840
  for (const cwd of cwds) {
10635
- let current = path19.resolve(cwd);
11841
+ let current = path20.resolve(cwd);
10636
11842
  while (!seen.has(current)) {
10637
11843
  seen.add(current);
10638
11844
  try {
10639
- await stat10(path19.join(current, ".git"));
11845
+ await stat11(path20.join(current, ".git"));
10640
11846
  return current;
10641
11847
  } catch {
10642
11848
  }
10643
- const parent = path19.dirname(current);
11849
+ const parent = path20.dirname(current);
10644
11850
  if (parent === current) {
10645
11851
  break;
10646
11852
  }
@@ -10651,12 +11857,12 @@ async function gitRootFromCwds3(cwds) {
10651
11857
  }
10652
11858
  function qoderProjectRootFromCwds(projectDir, cwds) {
10653
11859
  for (const cwd of cwds) {
10654
- let current = path19.resolve(cwd);
11860
+ let current = path20.resolve(cwd);
10655
11861
  while (true) {
10656
11862
  if (qoderEncodedVariants(current).includes(projectDir)) {
10657
11863
  return current;
10658
11864
  }
10659
- const parent = path19.dirname(current);
11865
+ const parent = path20.dirname(current);
10660
11866
  if (parent === current) {
10661
11867
  break;
10662
11868
  }
@@ -10666,7 +11872,7 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
10666
11872
  return void 0;
10667
11873
  }
10668
11874
  function rawQoderProjectPath(value) {
10669
- return path19.resolve(value).split(path19.sep).join("-");
11875
+ return path20.resolve(value).split(path20.sep).join("-");
10670
11876
  }
10671
11877
  function qoderEncodedVariants(value) {
10672
11878
  const raw = rawQoderProjectPath(value);
@@ -10687,11 +11893,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
10687
11893
  return void 0;
10688
11894
  }
10689
11895
  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();
11896
+ const projectDir = path20.basename(path20.dirname(filePath));
11897
+ const home = options ? path20.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
10692
11898
  const resolved = await resolveQoderProjectPath(projectDir, home);
10693
11899
  if (resolved) {
10694
- return path19.basename(resolved);
11900
+ return path20.basename(resolved);
10695
11901
  }
10696
11902
  const suffix = qoderEncodedProjectSuffix(projectDir, home);
10697
11903
  if (suffix) {
@@ -10712,12 +11918,12 @@ async function resolveQoderProjectPath(projectDir, home) {
10712
11918
  while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
10713
11919
  let matchedChild;
10714
11920
  try {
10715
- const entries = await readdir9(current, { withFileTypes: true });
11921
+ const entries = await readdir10(current, { withFileTypes: true });
10716
11922
  for (const entry of entries) {
10717
11923
  if (!entry.isDirectory()) {
10718
11924
  continue;
10719
11925
  }
10720
- const candidate = path19.join(current, entry.name);
11926
+ const candidate = path20.join(current, entry.name);
10721
11927
  const candidateVariants = qoderEncodedVariants(candidate);
10722
11928
  if (candidateVariants.includes(projectDir)) {
10723
11929
  return candidate;
@@ -10762,19 +11968,19 @@ function hookConfig7() {
10762
11968
  function qoderConfigDir(home, env) {
10763
11969
  const override = env?.QODER_CONFIG_DIR;
10764
11970
  if (override && override.trim()) {
10765
- return path19.resolve(override);
11971
+ return path20.resolve(override);
10766
11972
  }
10767
- return path19.join(home, ".qoder");
11973
+ return path20.join(home, ".qoder");
10768
11974
  }
10769
11975
  function qwenworkConfigDir(home, env) {
10770
11976
  const override = env?.QWENWORK_CONFIG_DIR;
10771
11977
  if (override && override.trim()) {
10772
- return path19.resolve(override);
11978
+ return path20.resolve(override);
10773
11979
  }
10774
- return path19.join(home, ".qwenworkcn");
11980
+ return path20.join(home, ".qwenworkcn");
10775
11981
  }
10776
11982
  function qoderConfigDirs(home, env) {
10777
- return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path19.resolve(dir)))];
11983
+ return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path20.resolve(dir)))];
10778
11984
  }
10779
11985
  function createQoderAdapter() {
10780
11986
  return {
@@ -10786,11 +11992,11 @@ function createQoderAdapter() {
10786
11992
  return qoderConfigDir(home, env);
10787
11993
  },
10788
11994
  installedPath(home, env) {
10789
- return path19.join(qoderConfigDir(home, env), "settings.json");
11995
+ return path20.join(qoderConfigDir(home, env), "settings.json");
10790
11996
  },
10791
11997
  async isInstalled(home, env) {
10792
11998
  return isHooksJsonInstalled(
10793
- path19.join(qoderConfigDir(home, env), "settings.json"),
11999
+ path20.join(qoderConfigDir(home, env), "settings.json"),
10794
12000
  "vibetime hook --agent qoder"
10795
12001
  );
10796
12002
  },
@@ -10799,16 +12005,16 @@ function createQoderAdapter() {
10799
12005
  const targets = [primary, ...variants.filter((dir) => existsSync(dir))];
10800
12006
  return targets.map((base) => ({
10801
12007
  kind: "hooks-json",
10802
- path: path19.join(base, "settings.json"),
12008
+ path: path20.join(base, "settings.json"),
10803
12009
  content: hookConfig7()
10804
12010
  }));
10805
12011
  },
10806
12012
  sourcePaths(home, env) {
10807
- const paths = qoderConfigDirs(home, env).map((base2) => path19.join(base2, "projects"));
12013
+ const paths = qoderConfigDirs(home, env).map((base2) => path20.join(base2, "projects"));
10808
12014
  const base = qoderConfigDir(home, env);
10809
12015
  paths.push(
10810
- path19.join(base, ".qoder.json"),
10811
- path19.join(home, ".qoder.json")
12016
+ path20.join(base, ".qoder.json"),
12017
+ path20.join(home, ".qoder.json")
10812
12018
  );
10813
12019
  return paths;
10814
12020
  },
@@ -10844,27 +12050,27 @@ function normalizeId(id) {
10844
12050
  }
10845
12051
 
10846
12052
  // 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";
12053
+ import { readdir as readdir11, readFile as readFile14, stat as stat12 } from "node:fs/promises";
12054
+ import path21 from "node:path";
10849
12055
  function workbuddyProjectsDir(home, env) {
10850
12056
  const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
10851
12057
  if (override && override.trim()) {
10852
- return path20.resolve(override, override.endsWith("projects") ? "" : "projects");
12058
+ return path21.resolve(override, override.endsWith("projects") ? "" : "projects");
10853
12059
  }
10854
- return path20.join(home, ".workbuddy", "projects");
12060
+ return path21.join(home, ".workbuddy", "projects");
10855
12061
  }
10856
12062
  function workbuddyBaseDir(home, env) {
10857
12063
  const override = env?.WORKBUDDY_HOME;
10858
12064
  if (override && override.trim()) {
10859
- return path20.resolve(override);
12065
+ return path21.resolve(override);
10860
12066
  }
10861
- return path20.join(home, ".workbuddy");
12067
+ return path21.join(home, ".workbuddy");
10862
12068
  }
10863
12069
  function projectFromCwd(cwd, fallback) {
10864
12070
  if (!cwd) {
10865
12071
  return fallback;
10866
12072
  }
10867
- return path20.basename(cwd) || fallback;
12073
+ return path21.basename(cwd) || fallback;
10868
12074
  }
10869
12075
  function sourceHash(filePath) {
10870
12076
  return `sha256:${createStableHash(filePath)}`;
@@ -10982,7 +12188,7 @@ function toolCallFailed(record) {
10982
12188
  return status === "failed" || status === "incomplete" || record.is_error === true || providerData.error != null || providerData.isError === true;
10983
12189
  }
10984
12190
  async function readWorkbuddyLines(filePath) {
10985
- const text = await readFile13(filePath, "utf8");
12191
+ const text = await readFile14(filePath, "utf8");
10986
12192
  return text.split(/\r?\n/).map((line, index) => {
10987
12193
  if (!line.trim()) {
10988
12194
  return void 0;
@@ -11002,8 +12208,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
11002
12208
  }
11003
12209
  const events = [];
11004
12210
  const first = lines[0].record;
11005
- const sessionId = stringField(first, "sessionId") || path20.basename(filePath, ".jsonl");
11006
- const fallbackProject = path20.basename(path20.dirname(filePath));
12211
+ const sessionId = stringField(first, "sessionId") || path21.basename(filePath, ".jsonl");
12212
+ const fallbackProject = path21.basename(path21.dirname(filePath));
11007
12213
  const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
11008
12214
  const project = projectFromCwd(cwd, fallbackProject);
11009
12215
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
@@ -11287,17 +12493,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
11287
12493
  const base = sourceRoot || workbuddyProjectsDir(home, env);
11288
12494
  const files = [];
11289
12495
  try {
11290
- const projects = await readdir10(base, { withFileTypes: true });
12496
+ const projects = await readdir11(base, { withFileTypes: true });
11291
12497
  for (const project of projects) {
11292
12498
  if (!project.isDirectory()) {
11293
12499
  continue;
11294
12500
  }
11295
- const projectDir = path20.join(base, project.name);
11296
- const entries = await readdir10(projectDir, { withFileTypes: true });
12501
+ const projectDir = path21.join(base, project.name);
12502
+ const entries = await readdir11(projectDir, { withFileTypes: true });
11297
12503
  for (const entry of entries) {
11298
12504
  if (entry.isFile() && entry.name.endsWith(".jsonl")) {
11299
- const filePath = path20.join(projectDir, entry.name);
11300
- const info = await stat11(filePath);
12505
+ const filePath = path21.join(projectDir, entry.name);
12506
+ const info = await stat12(filePath);
11301
12507
  files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
11302
12508
  }
11303
12509
  }
@@ -11334,18 +12540,18 @@ function createWorkbuddyAdapter() {
11334
12540
  return workbuddyProjectsDir(home, env);
11335
12541
  },
11336
12542
  installedPath(home, env) {
11337
- return path20.join(workbuddyBaseDir(home, env), "settings.json");
12543
+ return path21.join(workbuddyBaseDir(home, env), "settings.json");
11338
12544
  },
11339
12545
  async isInstalled(home, env) {
11340
12546
  return isHooksJsonInstalled(
11341
- path20.join(workbuddyBaseDir(home, env), "settings.json"),
12547
+ path21.join(workbuddyBaseDir(home, env), "settings.json"),
11342
12548
  "vibetime hook --agent workbuddy"
11343
12549
  );
11344
12550
  },
11345
12551
  installEntries(home, env) {
11346
12552
  return [{
11347
12553
  kind: "hooks-json",
11348
- path: path20.join(workbuddyBaseDir(home, env), "settings.json"),
12554
+ path: path21.join(workbuddyBaseDir(home, env), "settings.json"),
11349
12555
  content: hookConfig8()
11350
12556
  }];
11351
12557
  },
@@ -11358,26 +12564,26 @@ function createWorkbuddyAdapter() {
11358
12564
 
11359
12565
  // src/adapters/zcode.ts
11360
12566
  import { execFile } from "node:child_process";
11361
- import { readFile as readFile14, stat as stat12 } from "node:fs/promises";
11362
- import path21 from "node:path";
12567
+ import { readFile as readFile15, stat as stat13 } from "node:fs/promises";
12568
+ import path22 from "node:path";
11363
12569
  import { promisify as promisify2 } from "node:util";
11364
12570
  init_fs();
11365
12571
  var execFileAsync = promisify2(execFile);
11366
12572
  function zcodeCliDir(home, env) {
11367
12573
  const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
11368
12574
  if (override && override.trim()) {
11369
- return path21.resolve(override, override.endsWith("cli") ? "" : "cli");
12575
+ return path22.resolve(override, override.endsWith("cli") ? "" : "cli");
11370
12576
  }
11371
- return path21.join(home, ".zcode", "cli");
12577
+ return path22.join(home, ".zcode", "cli");
11372
12578
  }
11373
12579
  function zcodeDbPath(home, env) {
11374
- return path21.join(zcodeCliDir(home, env), "db", "db.sqlite");
12580
+ return path22.join(zcodeCliDir(home, env), "db", "db.sqlite");
11375
12581
  }
11376
12582
  var providerNameCache = null;
11377
12583
  async function loadProviderNames(configPath2) {
11378
12584
  let fileMtime = 0;
11379
12585
  try {
11380
- const info = await stat12(configPath2);
12586
+ const info = await stat13(configPath2);
11381
12587
  fileMtime = info.mtimeMs;
11382
12588
  } catch {
11383
12589
  return /* @__PURE__ */ new Map();
@@ -11387,7 +12593,7 @@ async function loadProviderNames(configPath2) {
11387
12593
  }
11388
12594
  const map = /* @__PURE__ */ new Map();
11389
12595
  try {
11390
- const raw = await readFile14(configPath2, "utf-8");
12596
+ const raw = await readFile15(configPath2, "utf-8");
11391
12597
  const config = JSON.parse(raw);
11392
12598
  const providers = config?.provider;
11393
12599
  if (isPlainObject(providers)) {
@@ -11405,7 +12611,7 @@ function sourceHash2(filePath) {
11405
12611
  return `sha256:${createStableHash(filePath)}`;
11406
12612
  }
11407
12613
  function projectFromDirectory(directory) {
11408
- return directory ? path21.basename(directory) || "zcode" : "zcode";
12614
+ return directory ? path22.basename(directory) || "zcode" : "zcode";
11409
12615
  }
11410
12616
  function isoFromMs(value) {
11411
12617
  return timestampFrom(typeof value === "number" ? value : Number(value));
@@ -11589,16 +12795,16 @@ async function parseZCodeDb(filePath, options) {
11589
12795
  if (rows.length === 0) {
11590
12796
  return [];
11591
12797
  }
11592
- let candidate = path21.resolve(filePath);
12798
+ let candidate = path22.resolve(filePath);
11593
12799
  let configPath2 = "";
11594
12800
  for (let i = 0; i < 12; i++) {
11595
- const probe = path21.join(candidate, ".zcode", "v2", "config.json");
12801
+ const probe = path22.join(candidate, ".zcode", "v2", "config.json");
11596
12802
  try {
11597
- await stat12(probe);
12803
+ await stat13(probe);
11598
12804
  configPath2 = probe;
11599
12805
  break;
11600
12806
  } catch {
11601
- const parent = path21.dirname(candidate);
12807
+ const parent = path22.dirname(candidate);
11602
12808
  if (parent === candidate) break;
11603
12809
  candidate = parent;
11604
12810
  }
@@ -11818,9 +13024,9 @@ async function parseZCodeDb(filePath, options) {
11818
13024
  }
11819
13025
  async function zcodeBackfillFiles(sourceRoot, home, env) {
11820
13026
  const candidate = sourceRoot || zcodeDbPath(home, env);
11821
- const filePath = candidate.endsWith(".sqlite") ? candidate : path21.join(candidate, "db", "db.sqlite");
13027
+ const filePath = candidate.endsWith(".sqlite") ? candidate : path22.join(candidate, "db", "db.sqlite");
11822
13028
  try {
11823
- const info = await stat12(filePath);
13029
+ const info = await stat13(filePath);
11824
13030
  return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
11825
13031
  } catch {
11826
13032
  return [];
@@ -11852,50 +13058,50 @@ function createZCodeAdapter() {
11852
13058
  }
11853
13059
 
11854
13060
  // src/adapters/zed.ts
11855
- import os11 from "node:os";
11856
- import path22 from "node:path";
13061
+ import os12 from "node:os";
13062
+ import path23 from "node:path";
11857
13063
  function zedThreadsCandidates(home, env) {
11858
13064
  const candidates = [];
11859
13065
  const platform2 = process.platform;
11860
13066
  if (platform2 === "darwin") {
11861
- candidates.push(path22.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
13067
+ candidates.push(path23.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
11862
13068
  } else if (platform2 === "win32") {
11863
13069
  const appdata = env?.APPDATA;
11864
13070
  if (appdata && appdata.trim()) {
11865
- candidates.push(path22.join(path22.resolve(appdata), "Zed", "threads", "threads.db"));
13071
+ candidates.push(path23.join(path23.resolve(appdata), "Zed", "threads", "threads.db"));
11866
13072
  }
11867
- candidates.push(path22.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
13073
+ candidates.push(path23.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
11868
13074
  } else {
11869
13075
  const xdgData = env?.XDG_DATA_HOME;
11870
13076
  if (xdgData && xdgData.trim()) {
11871
- candidates.push(path22.join(path22.resolve(xdgData), "zed", "threads", "threads.db"));
13077
+ candidates.push(path23.join(path23.resolve(xdgData), "zed", "threads", "threads.db"));
11872
13078
  }
11873
- candidates.push(path22.join(home, ".local", "share", "zed", "threads", "threads.db"));
13079
+ candidates.push(path23.join(home, ".local", "share", "zed", "threads", "threads.db"));
11874
13080
  const xdgConfig = env?.XDG_CONFIG_HOME;
11875
13081
  if (xdgConfig && xdgConfig.trim()) {
11876
- candidates.push(path22.join(path22.resolve(xdgConfig), "zed", "threads", "threads.db"));
13082
+ candidates.push(path23.join(path23.resolve(xdgConfig), "zed", "threads", "threads.db"));
11877
13083
  }
11878
- candidates.push(path22.join(home, ".config", "zed", "threads", "threads.db"));
13084
+ candidates.push(path23.join(home, ".config", "zed", "threads", "threads.db"));
11879
13085
  }
11880
13086
  return candidates;
11881
13087
  }
11882
13088
  function zedConfigDir(home, env) {
11883
13089
  const platform2 = process.platform;
11884
13090
  if (platform2 === "darwin") {
11885
- return path22.join(home, "Library", "Application Support", "Zed");
13091
+ return path23.join(home, "Library", "Application Support", "Zed");
11886
13092
  }
11887
13093
  if (platform2 === "win32") {
11888
13094
  const appdata = env?.APPDATA;
11889
13095
  if (appdata && appdata.trim()) {
11890
- return path22.join(path22.resolve(appdata), "Zed");
13096
+ return path23.join(path23.resolve(appdata), "Zed");
11891
13097
  }
11892
- return path22.join(home, "AppData", "Roaming", "Zed");
13098
+ return path23.join(home, "AppData", "Roaming", "Zed");
11893
13099
  }
11894
13100
  const xdgConfig = env?.XDG_CONFIG_HOME;
11895
13101
  if (xdgConfig && xdgConfig.trim()) {
11896
- return path22.join(path22.resolve(xdgConfig), "zed");
13102
+ return path23.join(path23.resolve(xdgConfig), "zed");
11897
13103
  }
11898
- return path22.join(home, ".config", "zed");
13104
+ return path23.join(home, ".config", "zed");
11899
13105
  }
11900
13106
  function baseZedEvent(event) {
11901
13107
  return {
@@ -11959,7 +13165,7 @@ async function parseZedSessionFile(dbPath, options) {
11959
13165
  const folderRaw = row.folder_paths || "";
11960
13166
  const folder = folderRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
11961
13167
  const cwd = folder || void 0;
11962
- const project = cwd ? path22.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
13168
+ const project = cwd ? path23.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
11963
13169
  let json;
11964
13170
  try {
11965
13171
  const bytes = row.data_type === "zstd" ? decompress2(new Uint8Array(row.data)) : new Uint8Array(row.data);
@@ -12204,20 +13410,20 @@ async function parseZedSessionFile(dbPath, options) {
12204
13410
  }
12205
13411
  return events.filter((event) => matchesBackfillFilters(event, options));
12206
13412
  }
12207
- async function zedBackfillFiles(sourceRoot, home = os11.homedir(), env) {
12208
- const { stat: stat15 } = await import("node:fs/promises");
13413
+ async function zedBackfillFiles(sourceRoot, home = os12.homedir(), env) {
13414
+ const { stat: stat16 } = await import("node:fs/promises");
12209
13415
  if (sourceRoot) {
12210
13416
  if (!sourceRoot.endsWith(".db")) {
12211
13417
  return [];
12212
13418
  }
12213
- const info = await stat15(sourceRoot).catch(() => null);
13419
+ const info = await stat16(sourceRoot).catch(() => null);
12214
13420
  if (!info) {
12215
13421
  return [];
12216
13422
  }
12217
13423
  return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
12218
13424
  }
12219
13425
  for (const candidatePath of zedThreadsCandidates(home, env)) {
12220
- const info = await stat15(candidatePath).catch(() => null);
13426
+ const info = await stat16(candidatePath).catch(() => null);
12221
13427
  if (info) {
12222
13428
  return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
12223
13429
  }
@@ -12234,7 +13440,7 @@ function createZedAdapter() {
12234
13440
  return zedConfigDir(home, env);
12235
13441
  },
12236
13442
  installedPath(home, env) {
12237
- return path22.join(zedConfigDir(home, env), "vibetime-marker");
13443
+ return path23.join(zedConfigDir(home, env), "vibetime-marker");
12238
13444
  },
12239
13445
  async isInstalled() {
12240
13446
  return false;
@@ -12609,6 +13815,10 @@ async function installEntry(entry, options) {
12609
13815
  await mergeHooksJson(entry.path, entry.content, options);
12610
13816
  return;
12611
13817
  }
13818
+ if (entry.kind === "cursor-hooks-json" && typeof entry.content === "object") {
13819
+ await mergeCursorHooksFile(entry.path, entry.content, options);
13820
+ return;
13821
+ }
12612
13822
  if (entry.kind === "hooks-toml" && typeof entry.content === "object") {
12613
13823
  await mergeHooksToml(entry.path, entry.content, options);
12614
13824
  return;
@@ -12623,6 +13833,10 @@ async function uninstallEntry(entry, options) {
12623
13833
  await uninstallHooksToml(entry.path, entry.content, options);
12624
13834
  return;
12625
13835
  }
13836
+ if (entry.kind === "cursor-hooks-json" && typeof entry.content === "object") {
13837
+ await uninstallCursorHooksFile(entry.path, entry.content, options);
13838
+ return;
13839
+ }
12626
13840
  if (entry.kind === "hooks-json" && typeof entry.content === "object") {
12627
13841
  await uninstallHooksJson(entry.path, entry.content, options);
12628
13842
  return;
@@ -12655,6 +13869,67 @@ async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
12655
13869
  await writeFile5(filePath, nextText, "utf8");
12656
13870
  onWrite(`Installed ${filePath}`);
12657
13871
  }
13872
+ async function mergeCursorHooksFile(filePath, content, { dryRun, force, onWrite }) {
13873
+ const { mkdir: mkdir6, writeFile: writeFile5 } = await import("node:fs/promises");
13874
+ const pathMod = await import("node:path");
13875
+ if (dryRun) {
13876
+ onWrite(`Would merge ${filePath}`);
13877
+ return;
13878
+ }
13879
+ const existingText = await readTextIfExists(filePath);
13880
+ const existing = existingText ? JSON.parse(existingText) : {};
13881
+ if (existingText !== null && !isPlainObject(existing) && !force) {
13882
+ throw new Error(
13883
+ `Refusing to update non-object JSON file: ${filePath}. Re-run with --force if this is intentional.`
13884
+ );
13885
+ }
13886
+ const merged = mergeCursorHooksJson(existing, content);
13887
+ const nextText = `${JSON.stringify(merged, null, 2)}
13888
+ `;
13889
+ if (existingText === nextText) {
13890
+ onWrite(`Already installed ${filePath}`);
13891
+ return;
13892
+ }
13893
+ await mkdir6(pathMod.dirname(filePath), { recursive: true });
13894
+ await writeFile5(filePath, nextText, "utf8");
13895
+ onWrite(`Installed ${filePath}`);
13896
+ }
13897
+ async function uninstallCursorHooksFile(filePath, content, { dryRun, onWrite }) {
13898
+ const existingText = await readTextIfExists(filePath);
13899
+ if (existingText === null) {
13900
+ onWrite(`Already uninstalled ${filePath}`);
13901
+ return;
13902
+ }
13903
+ let existing;
13904
+ try {
13905
+ existing = JSON.parse(existingText);
13906
+ } catch {
13907
+ onWrite(`Skipped non-JSON file ${filePath}`);
13908
+ return;
13909
+ }
13910
+ if (!isPlainObject(existing)) {
13911
+ onWrite(`Skipped non-object JSON file ${filePath}`);
13912
+ return;
13913
+ }
13914
+ const commands = new Set(collectCursorHookCommands(content));
13915
+ if (commands.size === 0) {
13916
+ onWrite(`Already uninstalled ${filePath}`);
13917
+ return;
13918
+ }
13919
+ const { next, changed } = stripCursorHookCommands(existing, commands);
13920
+ if (!changed) {
13921
+ onWrite(`Already uninstalled ${filePath}`);
13922
+ return;
13923
+ }
13924
+ if (dryRun) {
13925
+ onWrite(`Would uninstall ${filePath}`);
13926
+ return;
13927
+ }
13928
+ const { writeFile: writeFile5 } = await import("node:fs/promises");
13929
+ await writeFile5(filePath, `${JSON.stringify(next, null, 2)}
13930
+ `, "utf8");
13931
+ onWrite(`Uninstalled ${filePath}`);
13932
+ }
12658
13933
  function mergeAgyHooksJson(existing, addition) {
12659
13934
  const merged = structuredClone(isPlainObject(existing) ? existing : {});
12660
13935
  const additionObject = isPlainObject(addition) ? addition : {};
@@ -12942,15 +14217,15 @@ async function uninstallGeneratedFile(filePath, { dryRun, onWrite }) {
12942
14217
  import { randomUUID } from "node:crypto";
12943
14218
  import { existsSync as existsSync2, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
12944
14219
  import { homedir, hostname } from "node:os";
12945
- import path23 from "node:path";
14220
+ import path24 from "node:path";
12946
14221
  function configDir(home = homedir()) {
12947
- return path23.join(home, ".vibetime");
14222
+ return path24.join(home, ".vibetime");
12948
14223
  }
12949
14224
  function configPath(home = homedir()) {
12950
- return path23.join(configDir(home), "config.json");
14225
+ return path24.join(configDir(home), "config.json");
12951
14226
  }
12952
14227
  function machineIdPath(home = homedir()) {
12953
- return path23.join(configDir(home), "machine-id");
14228
+ return path24.join(configDir(home), "machine-id");
12954
14229
  }
12955
14230
  function readConfig(home = homedir()) {
12956
14231
  const file = configPath(home);
@@ -12997,15 +14272,15 @@ function defaultMachineName() {
12997
14272
  init_fs();
12998
14273
 
12999
14274
  // src/lib/logger.ts
13000
- import { appendFile, mkdir as mkdir4, rename, stat as stat13 } from "node:fs/promises";
14275
+ import { appendFile, mkdir as mkdir4, rename, stat as stat14 } from "node:fs/promises";
13001
14276
  import { homedir as homedir2 } from "node:os";
13002
- import path24 from "node:path";
14277
+ import path25 from "node:path";
13003
14278
  var MAX_BYTES = 1 * 1024 * 1024;
13004
14279
  function logDir(home = homedir2()) {
13005
- return path24.join(home, ".vibetime", "logs");
14280
+ return path25.join(home, ".vibetime", "logs");
13006
14281
  }
13007
14282
  function logPath(home = homedir2(), name = "cli.log") {
13008
- return path24.join(logDir(home), name);
14283
+ return path25.join(logDir(home), name);
13009
14284
  }
13010
14285
  function serializeError(error) {
13011
14286
  if (error instanceof Error) {
@@ -13015,7 +14290,7 @@ function serializeError(error) {
13015
14290
  }
13016
14291
  async function rotateIfNeeded(file) {
13017
14292
  try {
13018
- const info = await stat13(file);
14293
+ const info = await stat14(file);
13019
14294
  if (info.size > MAX_BYTES) {
13020
14295
  await rename(file, `${file}.1`).catch(() => {
13021
14296
  });
@@ -13180,8 +14455,8 @@ function buildHeaders(token, machine) {
13180
14455
  ...machine?.platform ? { "x-machine-platform": machine.platform } : {}
13181
14456
  };
13182
14457
  }
13183
- function joinUrl(base, path26) {
13184
- return new URL(path26, base.endsWith("/") ? base : `${base}/`).toString();
14458
+ function joinUrl(base, path27) {
14459
+ return new URL(path27, base.endsWith("/") ? base : `${base}/`).toString();
13185
14460
  }
13186
14461
  async function postRollupBatch(remote, rollups, options = {}) {
13187
14462
  const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
@@ -13271,6 +14546,7 @@ function createRegistry() {
13271
14546
  registry.register(createGrokBuildAdapter());
13272
14547
  registry.register(createZedAdapter());
13273
14548
  registry.register(createKimiCodeAdapter());
14549
+ registry.register(createCursorAdapter());
13274
14550
  return registry;
13275
14551
  }
13276
14552
  var defaultContext = {
@@ -13828,6 +15104,9 @@ async function listBackfillSourceFiles(source, options, ctx) {
13828
15104
  if (source.id === "zed") {
13829
15105
  return zedBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
13830
15106
  }
15107
+ if (source.id === "cursor") {
15108
+ return cursorBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
15109
+ }
13831
15110
  if (source.id === "pi") {
13832
15111
  return piBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
13833
15112
  }
@@ -13835,7 +15114,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
13835
15114
  const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
13836
15115
  const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
13837
15116
  return Promise.all(files.map(async (filePath) => {
13838
- const info = await stat14(filePath);
15117
+ const info = await stat15(filePath);
13839
15118
  return { path: filePath, modifiedAt: info.mtime.toISOString() };
13840
15119
  }));
13841
15120
  }
@@ -14167,13 +15446,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
14167
15446
  return picked;
14168
15447
  }
14169
15448
  function backfillIncrementalStatePath(home) {
14170
- return path25.join(home, ".vibetime", "backfill-state.json");
15449
+ return path26.join(home, ".vibetime", "backfill-state.json");
14171
15450
  }
14172
15451
  function syncLocalTriggerStatePath(home) {
14173
- return path25.join(home, ".vibetime", "sync-local-trigger.json");
15452
+ return path26.join(home, ".vibetime", "sync-local-trigger.json");
14174
15453
  }
14175
15454
  function syncLocalTriggerLockPath(home) {
14176
- return path25.join(home, ".vibetime", "sync-local-trigger.lock");
15455
+ return path26.join(home, ".vibetime", "sync-local-trigger.lock");
14177
15456
  }
14178
15457
  function backfillRemoteKey(baseUrl) {
14179
15458
  try {
@@ -14235,7 +15514,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
14235
15514
  }
14236
15515
  async function writeBackfillIncrementalStateFile(home, file) {
14237
15516
  const statePath = backfillIncrementalStatePath(home);
14238
- await mkdir5(path25.dirname(statePath), { recursive: true });
15517
+ await mkdir5(path26.dirname(statePath), { recursive: true });
14239
15518
  await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
14240
15519
  `, "utf8");
14241
15520
  }
@@ -14284,7 +15563,7 @@ async function readSyncLocalTriggerState(statePath) {
14284
15563
  return nextState;
14285
15564
  }
14286
15565
  async function writeSyncLocalTriggerState(statePath, state) {
14287
- await mkdir5(path25.dirname(statePath), { recursive: true });
15566
+ await mkdir5(path26.dirname(statePath), { recursive: true });
14288
15567
  await writeFile4(statePath, `${JSON.stringify(state, null, 2)}
14289
15568
  `, "utf8");
14290
15569
  }
@@ -14299,12 +15578,12 @@ async function readSyncLocalLock(lockPath) {
14299
15578
  return { pid: lock.pid, startedAt: lock.startedAt };
14300
15579
  }
14301
15580
  async function writeSyncLocalLock(lockPath, lock) {
14302
- await mkdir5(path25.dirname(lockPath), { recursive: true });
15581
+ await mkdir5(path26.dirname(lockPath), { recursive: true });
14303
15582
  await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
14304
15583
  `, "utf8");
14305
15584
  }
14306
15585
  async function acquireSyncLocalLock(lockPath, lock) {
14307
- await mkdir5(path25.dirname(lockPath), { recursive: true });
15586
+ await mkdir5(path26.dirname(lockPath), { recursive: true });
14308
15587
  try {
14309
15588
  const handle = await open(lockPath, "wx");
14310
15589
  try {
@@ -14384,10 +15663,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
14384
15663
  if (cliPath.endsWith(".ts")) {
14385
15664
  return ["--import", "tsx", cliPath];
14386
15665
  }
14387
- return [path25.resolve(path25.dirname(cliPath), "../bin/vibetime.mjs")];
15666
+ return [path26.resolve(path26.dirname(cliPath), "../bin/vibetime.mjs")];
14388
15667
  }
14389
15668
  function resolveHome3(options, ctx) {
14390
- return path25.resolve(stringOption(options.home) || ctx.env.HOME || os12.homedir());
15669
+ return path26.resolve(stringOption(options.home) || ctx.env.HOME || os13.homedir());
14391
15670
  }
14392
15671
  function requestedTargets(options) {
14393
15672
  const value = options.target || options.targets;