@yhong91/vibetime 0.1.17 → 0.1.19

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 +611 -277
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -158,11 +158,11 @@ var init_fs = __esm({
158
158
  });
159
159
 
160
160
  // src/cli.ts
161
- import { spawn, spawnSync } from "node:child_process";
161
+ import { spawn as spawn2, spawnSync } from "node:child_process";
162
162
  import { randomUUID as randomUUID2 } from "node:crypto";
163
- import { mkdir as mkdir5, rename as rename2, rm, stat as stat11, writeFile as writeFile4 } from "node:fs/promises";
163
+ import { mkdir as mkdir5, open, rename as rename2, rm, stat as stat12, writeFile as writeFile4 } from "node:fs/promises";
164
164
  import os9 from "node:os";
165
- import path20 from "node:path";
165
+ import path21 from "node:path";
166
166
  import { fileURLToPath } from "node:url";
167
167
 
168
168
  // ../shared/src/index.ts
@@ -296,6 +296,12 @@ function validateMetricBag(value, errors, prefix) {
296
296
  }
297
297
  for (const key of Object.keys(value)) {
298
298
  const metric = value[key];
299
+ if (key === "reasoningEffort") {
300
+ if (metric !== void 0 && typeof metric !== "string") {
301
+ errors.push(`${prefix}.${key} must be a string`);
302
+ }
303
+ continue;
304
+ }
299
305
  if (metric !== void 0 && (typeof metric !== "number" || !Number.isFinite(metric))) {
300
306
  errors.push(`${prefix}.${key} must be a finite number`);
301
307
  }
@@ -978,10 +984,10 @@ var cac = (name = "") => new CAC(name);
978
984
 
979
985
  // src/adapters/agy.ts
980
986
  import { exec } from "node:child_process";
981
- import { readFile as readFile2, stat as stat2, mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
987
+ import { mkdir as mkdir2, readFile as readFile2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
982
988
  import * as https from "node:https";
983
989
  import * as os from "node:os";
984
- import path4 from "node:path";
990
+ import path5 from "node:path";
985
991
  import { promisify } from "node:util";
986
992
 
987
993
  // src/lib/activity.ts
@@ -1196,7 +1202,7 @@ function countTextLines(text) {
1196
1202
  }
1197
1203
 
1198
1204
  // src/lib/constants.ts
1199
- var PACKAGE_VERSION = true ? "0.1.17" : "0.1.1";
1205
+ var PACKAGE_VERSION = true ? "0.1.19" : "0.1.1";
1200
1206
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
1201
1207
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
1202
1208
  var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
@@ -1433,6 +1439,254 @@ var SessionParserState = class {
1433
1439
  }
1434
1440
  };
1435
1441
 
1442
+ // src/adapters/agy-legacy-db.ts
1443
+ import { spawn } from "node:child_process";
1444
+ import { stat as stat2 } from "node:fs/promises";
1445
+ import path4 from "node:path";
1446
+ function readVarint(buffer, offset) {
1447
+ let value = 0n;
1448
+ let shift = 0n;
1449
+ let cursor = offset;
1450
+ while (cursor < buffer.length && shift <= 63n) {
1451
+ const byte = buffer[cursor++];
1452
+ value |= BigInt(byte & 127) << shift;
1453
+ if ((byte & 128) === 0) {
1454
+ return { value, offset: cursor };
1455
+ }
1456
+ shift += 7n;
1457
+ }
1458
+ throw new TypeError("invalid protobuf varint");
1459
+ }
1460
+ function decodeFields(buffer) {
1461
+ const fields = [];
1462
+ let offset = 0;
1463
+ while (offset < buffer.length) {
1464
+ const key = readVarint(buffer, offset);
1465
+ offset = key.offset;
1466
+ const keyNumber = Number(key.value);
1467
+ if (!Number.isSafeInteger(keyNumber)) {
1468
+ throw new TypeError("protobuf key exceeds safe integer range");
1469
+ }
1470
+ const field = keyNumber >>> 3;
1471
+ const wire = keyNumber & 7;
1472
+ if (field === 0) {
1473
+ throw new Error("invalid protobuf field");
1474
+ }
1475
+ switch (wire) {
1476
+ case 0: {
1477
+ const decoded = readVarint(buffer, offset);
1478
+ offset = decoded.offset;
1479
+ fields.push({ field, wire, value: decoded.value });
1480
+ break;
1481
+ }
1482
+ case 1: {
1483
+ if (offset + 8 > buffer.length) {
1484
+ throw new TypeError("truncated protobuf fixed64");
1485
+ }
1486
+ fields.push({ field, wire, value: buffer.subarray(offset, offset + 8) });
1487
+ offset += 8;
1488
+ break;
1489
+ }
1490
+ case 2: {
1491
+ const decoded = readVarint(buffer, offset);
1492
+ offset = decoded.offset;
1493
+ const length = Number(decoded.value);
1494
+ if (!Number.isSafeInteger(length)) {
1495
+ throw new TypeError("protobuf byte length exceeds safe integer range");
1496
+ }
1497
+ const end = offset + length;
1498
+ if (end > buffer.length) {
1499
+ throw new TypeError("truncated protobuf bytes");
1500
+ }
1501
+ fields.push({ field, wire, value: buffer.subarray(offset, end) });
1502
+ offset = end;
1503
+ break;
1504
+ }
1505
+ case 5: {
1506
+ if (offset + 4 > buffer.length) {
1507
+ throw new TypeError("truncated protobuf fixed32");
1508
+ }
1509
+ fields.push({ field, wire, value: buffer.subarray(offset, offset + 4) });
1510
+ offset += 4;
1511
+ break;
1512
+ }
1513
+ default: {
1514
+ throw new TypeError(`unsupported protobuf wire type ${wire}`);
1515
+ }
1516
+ }
1517
+ }
1518
+ return fields;
1519
+ }
1520
+ function bytesField(fields, field) {
1521
+ const value = fields.find((item) => item.field === field && item.wire === 2)?.value;
1522
+ return value instanceof Uint8Array ? value : void 0;
1523
+ }
1524
+ function numberField2(fields, field) {
1525
+ const value = fields.find((item) => item.field === field && item.wire === 0)?.value;
1526
+ if (typeof value !== "bigint") {
1527
+ return void 0;
1528
+ }
1529
+ const number = Number(value);
1530
+ return Number.isSafeInteger(number) ? number : void 0;
1531
+ }
1532
+ function stringField2(fields, field) {
1533
+ const value = bytesField(fields, field);
1534
+ if (!value) {
1535
+ return void 0;
1536
+ }
1537
+ return new TextDecoder().decode(value);
1538
+ }
1539
+ function decodePackedVarints(buffer) {
1540
+ if (!buffer) {
1541
+ return [];
1542
+ }
1543
+ const values = [];
1544
+ let offset = 0;
1545
+ while (offset < buffer.length) {
1546
+ const decoded = readVarint(buffer, offset);
1547
+ const value = Number(decoded.value);
1548
+ if (!Number.isSafeInteger(value)) {
1549
+ throw new TypeError("packed protobuf varint exceeds safe integer range");
1550
+ }
1551
+ values.push(value);
1552
+ offset = decoded.offset;
1553
+ }
1554
+ return values;
1555
+ }
1556
+ function decodeTimestamp(buffer) {
1557
+ if (!buffer) {
1558
+ return void 0;
1559
+ }
1560
+ const fields = decodeFields(buffer);
1561
+ const seconds = numberField2(fields, 1);
1562
+ if (seconds === void 0) {
1563
+ return void 0;
1564
+ }
1565
+ const nanos = numberField2(fields, 2) ?? 0;
1566
+ const date = new Date(seconds * 1e3 + Math.floor(nanos / 1e6));
1567
+ return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
1568
+ }
1569
+ function decodeLegacyAgyGeneratorMetadata(data) {
1570
+ try {
1571
+ const fields = decodeFields(data);
1572
+ const stepIndices = decodePackedVarints(bytesField(fields, 2));
1573
+ const chatModelBytes = bytesField(fields, 1);
1574
+ if (stepIndices.length === 0 || !chatModelBytes) {
1575
+ return null;
1576
+ }
1577
+ const chatModelFields = decodeFields(chatModelBytes);
1578
+ const usageBytes = bytesField(chatModelFields, 4);
1579
+ if (!usageBytes) {
1580
+ return null;
1581
+ }
1582
+ const usageFields = decodeFields(usageBytes);
1583
+ const inputTokens = numberField2(usageFields, 2);
1584
+ const outputTokens = numberField2(usageFields, 3);
1585
+ if (inputTokens === void 0 || outputTokens === void 0) {
1586
+ return null;
1587
+ }
1588
+ const cacheReadTokens = numberField2(usageFields, 5);
1589
+ const thinkingOutputTokens = numberField2(usageFields, 9);
1590
+ const createdAt = decodeTimestamp(bytesField(
1591
+ decodeFields(bytesField(chatModelFields, 9) ?? new Uint8Array()),
1592
+ 4
1593
+ ));
1594
+ const modelDisplayName = stringField2(chatModelFields, 21);
1595
+ const responseModel = stringField2(chatModelFields, 19);
1596
+ return {
1597
+ stepIndices,
1598
+ chatModel: {
1599
+ usage: {
1600
+ inputTokens: String(inputTokens),
1601
+ outputTokens: String(outputTokens),
1602
+ ...cacheReadTokens === void 0 ? {} : { cacheReadTokens: String(cacheReadTokens) },
1603
+ ...thinkingOutputTokens === void 0 ? {} : { thinkingOutputTokens: String(thinkingOutputTokens) }
1604
+ },
1605
+ ...modelDisplayName ? { modelDisplayName } : {},
1606
+ ...responseModel ? { responseModel } : {},
1607
+ ...createdAt ? { chatStartMetadata: { createdAt } } : {}
1608
+ }
1609
+ };
1610
+ } catch {
1611
+ return null;
1612
+ }
1613
+ }
1614
+ async function readRowsWithNodeSqlite(dbPath) {
1615
+ try {
1616
+ const sqlite = await import("node:sqlite");
1617
+ const db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
1618
+ try {
1619
+ return db.prepare("SELECT data FROM gen_metadata ORDER BY idx").all().map(
1620
+ (row) => ({ data: row.data })
1621
+ );
1622
+ } finally {
1623
+ db.close();
1624
+ }
1625
+ } catch {
1626
+ return null;
1627
+ }
1628
+ }
1629
+ async function readRowsWithSqliteCli(dbPath) {
1630
+ return new Promise((resolve) => {
1631
+ const child = spawn("sqlite3", [
1632
+ "-readonly",
1633
+ dbPath,
1634
+ "SELECT hex(data) FROM gen_metadata ORDER BY idx;"
1635
+ ], {
1636
+ stdio: ["ignore", "pipe", "ignore"]
1637
+ });
1638
+ const rows = [];
1639
+ let pending = "";
1640
+ let failed = false;
1641
+ child.stdout.setEncoding("utf8");
1642
+ child.stdout.on("data", (chunk) => {
1643
+ pending += chunk;
1644
+ let newline = pending.indexOf("\n");
1645
+ while (newline >= 0) {
1646
+ const line = pending.slice(0, newline).trim();
1647
+ pending = pending.slice(newline + 1);
1648
+ if (line) {
1649
+ try {
1650
+ rows.push({ data: Buffer.from(line, "hex") });
1651
+ } catch {
1652
+ failed = true;
1653
+ child.kill();
1654
+ return;
1655
+ }
1656
+ }
1657
+ newline = pending.indexOf("\n");
1658
+ }
1659
+ });
1660
+ child.on("error", () => resolve(null));
1661
+ child.on("close", (code) => {
1662
+ if (!failed && code === 0) {
1663
+ const line = pending.trim();
1664
+ if (line) {
1665
+ rows.push({ data: Buffer.from(line, "hex") });
1666
+ }
1667
+ resolve(rows);
1668
+ } else {
1669
+ resolve(null);
1670
+ }
1671
+ });
1672
+ });
1673
+ }
1674
+ async function readLegacyAgyGeneratorMetadata(transcriptPath, sessionId) {
1675
+ const antigravityCliDir = path4.resolve(path4.dirname(transcriptPath), "../../../..");
1676
+ const dbPath = path4.join(antigravityCliDir, "conversations", `${sessionId}.db`);
1677
+ try {
1678
+ await stat2(dbPath);
1679
+ } catch {
1680
+ return null;
1681
+ }
1682
+ const rows = await readRowsWithNodeSqlite(dbPath) ?? await readRowsWithSqliteCli(dbPath);
1683
+ if (!rows || rows.length === 0) {
1684
+ return null;
1685
+ }
1686
+ const metadata = rows.map((row) => decodeLegacyAgyGeneratorMetadata(row.data)).filter((item) => item !== null);
1687
+ return metadata.length > 0 ? metadata : null;
1688
+ }
1689
+
1436
1690
  // src/adapters/agy.ts
1437
1691
  var execAsync = promisify(exec);
1438
1692
  var cachedRpcConnections = null;
@@ -1652,7 +1906,7 @@ function detectModel(content, currentModel) {
1652
1906
  return currentModel;
1653
1907
  }
1654
1908
  function resolveModelName(text) {
1655
- const cleaned = text.replace(/\s*\([^)]*\)\s*/g, " ").trim();
1909
+ const cleaned = text.replaceAll(/\s*\([^)]*\)\s*/g, " ").trim();
1656
1910
  if (cleaned.includes("Claude Opus 4.7") || cleaned.includes("claude-opus-4.7")) {
1657
1911
  return "claude-opus-4.7";
1658
1912
  }
@@ -1721,11 +1975,11 @@ function usageMetadataFromGenerator(item) {
1721
1975
  };
1722
1976
  }
1723
1977
  async function readAgyModelSetting(filePath) {
1724
- const settingsPath = path4.resolve(path4.dirname(filePath), "../../../..", "settings.json");
1978
+ const settingsPath = path5.resolve(path5.dirname(filePath), "../../../..", "settings.json");
1725
1979
  try {
1726
1980
  const [text, info] = await Promise.all([
1727
1981
  readFile2(settingsPath, "utf8"),
1728
- stat2(settingsPath)
1982
+ stat3(settingsPath)
1729
1983
  ]);
1730
1984
  const configured = JSON.parse(text)?.model;
1731
1985
  const rawModel = typeof configured === "string" ? configured : null;
@@ -1748,16 +2002,16 @@ function extractProjectContext(rawLines) {
1748
2002
  if (args.DirectoryPath) {
1749
2003
  candidate = normalizePath(args.DirectoryPath);
1750
2004
  } else if (args.AbsolutePath) {
1751
- candidate = path4.dirname(normalizePath(args.AbsolutePath));
2005
+ candidate = path5.dirname(normalizePath(args.AbsolutePath));
1752
2006
  } else if (args.SearchPath) {
1753
2007
  candidate = normalizePath(args.SearchPath);
1754
2008
  } else if (args.TargetFile) {
1755
- candidate = path4.dirname(normalizePath(args.TargetFile));
2009
+ candidate = path5.dirname(normalizePath(args.TargetFile));
1756
2010
  } else if (args.Cwd) {
1757
2011
  candidate = normalizePath(args.Cwd);
1758
2012
  }
1759
2013
  if (candidate) {
1760
- const norm = candidate.replace(/\\/g, "/").toLowerCase();
2014
+ const norm = candidate.replaceAll("\\", "/").toLowerCase();
1761
2015
  const isTemp = norm.startsWith("/var/") || norm.startsWith("/private/var/") || norm.startsWith("/tmp/") || norm.startsWith("/private/tmp/") || norm.includes("/tmp.");
1762
2016
  if (isTemp) {
1763
2017
  if (!fallbackCwd) {
@@ -1780,7 +2034,7 @@ function extractProjectContext(rawLines) {
1780
2034
  }
1781
2035
  if (cwd) {
1782
2036
  const match = cwd.match(/[/\\]projects[/\\]([^/\\]+)/i);
1783
- project = match && match[1] ? match[1] : path4.basename(cwd);
2037
+ project = match && match[1] ? match[1] : path5.basename(cwd);
1784
2038
  }
1785
2039
  return { cwd, project };
1786
2040
  }
@@ -1792,7 +2046,7 @@ function normalizePath(p) {
1792
2046
  if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
1793
2047
  cleaned = cleaned.slice(1, -1);
1794
2048
  }
1795
- return path4.normalize(cleaned);
2049
+ return path5.normalize(cleaned);
1796
2050
  }
1797
2051
  async function parseAgySessionFile(filePath, options) {
1798
2052
  const text = await readFile2(filePath, "utf8");
@@ -1811,8 +2065,8 @@ async function parseAgySessionFile(filePath, options) {
1811
2065
  const sessionId = getSessionId(filePath);
1812
2066
  const modelSetting = await readAgyModelSetting(filePath);
1813
2067
  let generatorMetadata = options?.mockTrajectoryMetadata || await getTrajectoryGeneratorMetadata(sessionId).catch(() => null);
1814
- const cacheDir = path4.join(path4.dirname(path4.dirname(filePath)), "cache");
1815
- const cacheFile = path4.join(cacheDir, "trajectory_metadata.json");
2068
+ const cacheDir = path5.join(path5.dirname(path5.dirname(filePath)), "cache");
2069
+ const cacheFile = path5.join(cacheDir, "trajectory_metadata.json");
1816
2070
  if (generatorMetadata) {
1817
2071
  try {
1818
2072
  await mkdir2(cacheDir, { recursive: true });
@@ -1828,6 +2082,16 @@ async function parseAgySessionFile(filePath, options) {
1828
2082
  } catch {
1829
2083
  }
1830
2084
  }
2085
+ if (!generatorMetadata) {
2086
+ generatorMetadata = await readLegacyAgyGeneratorMetadata(filePath, sessionId);
2087
+ if (generatorMetadata) {
2088
+ try {
2089
+ await mkdir2(cacheDir, { recursive: true });
2090
+ await writeFile2(cacheFile, JSON.stringify(generatorMetadata, null, 2), "utf8");
2091
+ } catch {
2092
+ }
2093
+ }
2094
+ }
1831
2095
  const usageMap = /* @__PURE__ */ new Map();
1832
2096
  const usageEntries = [];
1833
2097
  const matchedUsageEntries = /* @__PURE__ */ new Set();
@@ -1932,7 +2196,6 @@ async function parseAgySessionFile(filePath, options) {
1932
2196
  })
1933
2197
  }), lineNumber, raw.type);
1934
2198
  } else if (raw.type === "PLANNER_RESPONSE") {
1935
- const content = stringField(raw, "content") || "";
1936
2199
  const usageMetadata = usageMap.get(raw.step_index);
1937
2200
  if (usageMetadata) {
1938
2201
  matchedUsageEntries.add(usageMetadata);
@@ -2144,27 +2407,27 @@ async function parseAgySessionFile(filePath, options) {
2144
2407
  function agyDataDirs(home, env) {
2145
2408
  const override = env?.ANTIGRAVITY_DATA_DIR || env?.AGY_DATA_DIR;
2146
2409
  if (override && override.trim()) {
2147
- return override.split(",").map((entry) => entry.trim()).filter(Boolean).map((entry) => path4.resolve(entry));
2410
+ return override.split(",").map((entry) => entry.trim()).filter(Boolean).map((entry) => path5.resolve(entry));
2148
2411
  }
2149
- return [path4.join(home, ".gemini", "antigravity-cli", "brain")];
2412
+ return [path5.join(home, ".gemini", "antigravity-cli", "brain")];
2150
2413
  }
2151
2414
  async function agyBackfillFiles(sourceRoot, home, env) {
2152
- const roots = sourceRoot ? [path4.resolve(sourceRoot)] : agyDataDirs(home, env);
2415
+ const roots = sourceRoot ? [path5.resolve(sourceRoot)] : agyDataDirs(home, env);
2153
2416
  const fileLists = await Promise.all(roots.map((root) => listFilesByExtensions(root, [".jsonl"])));
2154
2417
  const files = fileLists.flat().filter((f) => f.endsWith("transcript.jsonl")).sort();
2155
2418
  return Promise.all(files.map(async (filePath) => {
2156
- const info = await stat2(filePath);
2419
+ const info = await stat3(filePath);
2157
2420
  return { path: filePath, modifiedAt: info.mtime.toISOString() };
2158
2421
  }));
2159
2422
  }
2160
- var agyHandler = (msg) => {
2423
+ function agyHandler(msg) {
2161
2424
  return {
2162
2425
  type: "command",
2163
2426
  command: "vibetime hook --agent agy",
2164
2427
  timeout: 10,
2165
2428
  statusMessage: msg
2166
2429
  };
2167
- };
2430
+ }
2168
2431
  function hookConfig() {
2169
2432
  const anyTool = [{ matcher: "", hooks: [agyHandler("Reporting tool activity")] }];
2170
2433
  const lifecycle = (msg) => [{ matcher: "", hooks: [agyHandler(msg)] }];
@@ -2229,18 +2492,18 @@ function createAgyAdapter() {
2229
2492
  return agyDataDirs(home, env)[0];
2230
2493
  },
2231
2494
  installedPath(home, env) {
2232
- return path4.join(path4.dirname(agyDataDirs(home, env)[0]), "hooks.json");
2495
+ return path5.join(path5.dirname(agyDataDirs(home, env)[0]), "hooks.json");
2233
2496
  },
2234
2497
  async isInstalled(home, env) {
2235
- const base = path4.dirname(agyDataDirs(home, env)[0]);
2236
- const settingsPath = path4.join(base, "settings.json");
2237
- const hooksPath = path4.join(base, "hooks.json");
2498
+ const base = path5.dirname(agyDataDirs(home, env)[0]);
2499
+ const settingsPath = path5.join(base, "settings.json");
2500
+ const hooksPath = path5.join(base, "hooks.json");
2238
2501
  return await checkEnableJsonHooks(settingsPath) && await isAgyHooksInstalled(hooksPath, "vibetime hook --agent agy");
2239
2502
  },
2240
2503
  installEntries(home, env) {
2241
- const base = path4.dirname(agyDataDirs(home, env)[0]);
2242
- const settingsPath = path4.join(base, "settings.json");
2243
- const hooksPath = path4.join(base, "hooks.json");
2504
+ const base = path5.dirname(agyDataDirs(home, env)[0]);
2505
+ const settingsPath = path5.join(base, "settings.json");
2506
+ const hooksPath = path5.join(base, "hooks.json");
2244
2507
  return [
2245
2508
  {
2246
2509
  kind: "hooks-json",
@@ -2262,12 +2525,12 @@ function createAgyAdapter() {
2262
2525
  }
2263
2526
 
2264
2527
  // src/adapters/claude-code.ts
2265
- import { readdir as readdir2, readFile as readFile3, stat as stat3 } from "node:fs/promises";
2528
+ import { readdir as readdir2, readFile as readFile3, stat as stat4 } from "node:fs/promises";
2266
2529
  import os2 from "node:os";
2267
- import path6 from "node:path";
2530
+ import path7 from "node:path";
2268
2531
 
2269
2532
  // src/lib/adapter-helpers.ts
2270
- import path5 from "node:path";
2533
+ import path6 from "node:path";
2271
2534
  var TURN_IDLE_MS = 6e4;
2272
2535
  function isTurnIdle(lastEventAt) {
2273
2536
  if (!lastEventAt) {
@@ -2280,7 +2543,7 @@ function isTurnIdle(lastEventAt) {
2280
2543
  return Date.now() - lastMs > TURN_IDLE_MS;
2281
2544
  }
2282
2545
  function sessionIdFromFilePath(filePath, prefix) {
2283
- const match = path5.basename(filePath).match(/([0-9a-f]{8}-[0-9a-f-]{27,})/);
2546
+ const match = path6.basename(filePath).match(/([0-9a-f]{8}-[0-9a-f-]{27,})/);
2284
2547
  return match?.[1] || `${prefix}_${createStableHash(filePath).slice(0, 24)}`;
2285
2548
  }
2286
2549
  function hookHandler(agentId, statusMessage) {
@@ -2344,7 +2607,7 @@ async function parseClaudeCodeSessionFile(filePath, options) {
2344
2607
  sessionId = stringField(raw, "sessionId") || sessionId;
2345
2608
  state.sessionId = sessionId;
2346
2609
  cwd = stringField(raw, "cwd") || cwd;
2347
- project = projectContext.project || (cwd ? path6.basename(cwd) : project || await claudeProjectFromFilePath(filePath, options));
2610
+ project = projectContext.project || (cwd ? path7.basename(cwd) : project || await claudeProjectFromFilePath(filePath, options));
2348
2611
  if (!ts) {
2349
2612
  continue;
2350
2613
  }
@@ -2716,17 +2979,17 @@ function claudeTextStats(value) {
2716
2979
  };
2717
2980
  }
2718
2981
  async function claudeProjectContextFromLines(filePath, lines, options) {
2719
- const projectDir = path6.basename(path6.dirname(filePath));
2982
+ const projectDir = path7.basename(path7.dirname(filePath));
2720
2983
  const cwds = [];
2721
2984
  for (const line of lines) {
2722
2985
  const raw = parseJsonLine(line);
2723
2986
  const cwd = raw ? stringField(raw, "cwd") : void 0;
2724
- if (cwd && path6.isAbsolute(cwd)) {
2987
+ if (cwd && path7.isAbsolute(cwd)) {
2725
2988
  cwds.push(cwd);
2726
2989
  }
2727
2990
  }
2728
2991
  const root = await gitRootFromCwds(cwds) || claudeProjectRootFromCwds(projectDir, cwds);
2729
- const project = cwds.length > 0 ? path6.basename(cwds[0]) : root ? path6.basename(root) : await claudeProjectFromFilePath(filePath, options);
2992
+ const project = cwds.length > 0 ? path7.basename(cwds[0]) : root ? path7.basename(root) : await claudeProjectFromFilePath(filePath, options);
2730
2993
  return {
2731
2994
  project,
2732
2995
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
@@ -2735,15 +2998,15 @@ async function claudeProjectContextFromLines(filePath, lines, options) {
2735
2998
  async function gitRootFromCwds(cwds) {
2736
2999
  const seen = /* @__PURE__ */ new Set();
2737
3000
  for (const cwd of cwds) {
2738
- let current = path6.resolve(cwd);
3001
+ let current = path7.resolve(cwd);
2739
3002
  while (!seen.has(current)) {
2740
3003
  seen.add(current);
2741
3004
  try {
2742
- await stat3(path6.join(current, ".git"));
3005
+ await stat4(path7.join(current, ".git"));
2743
3006
  return current;
2744
3007
  } catch {
2745
3008
  }
2746
- const parent = path6.dirname(current);
3009
+ const parent = path7.dirname(current);
2747
3010
  if (parent === current) {
2748
3011
  break;
2749
3012
  }
@@ -2754,12 +3017,12 @@ async function gitRootFromCwds(cwds) {
2754
3017
  }
2755
3018
  function claudeProjectRootFromCwds(projectDir, cwds) {
2756
3019
  for (const cwd of cwds) {
2757
- let current = path6.resolve(cwd);
3020
+ let current = path7.resolve(cwd);
2758
3021
  while (true) {
2759
3022
  if (encodeClaudeProjectPath(current) === projectDir) {
2760
3023
  return current;
2761
3024
  }
2762
- const parent = path6.dirname(current);
3025
+ const parent = path7.dirname(current);
2763
3026
  if (parent === current) {
2764
3027
  break;
2765
3028
  }
@@ -2769,10 +3032,10 @@ function claudeProjectRootFromCwds(projectDir, cwds) {
2769
3032
  return void 0;
2770
3033
  }
2771
3034
  function encodeClaudeProjectPath(value) {
2772
- return path6.resolve(value).split(path6.sep).join("-").replace(/_/g, "-");
3035
+ return path7.resolve(value).split(path7.sep).join("-").replace(/_/g, "-");
2773
3036
  }
2774
3037
  function rawClaudeProjectPath(value) {
2775
- return path6.resolve(value).split(path6.sep).join("-");
3038
+ return path7.resolve(value).split(path7.sep).join("-");
2776
3039
  }
2777
3040
  function claudeEncodedVariants(value) {
2778
3041
  const raw = rawClaudeProjectPath(value);
@@ -2788,11 +3051,11 @@ function claudeEncodedProjectSuffix(projectDir, home) {
2788
3051
  return void 0;
2789
3052
  }
2790
3053
  async function claudeProjectFromFilePath(filePath, options) {
2791
- const projectDir = path6.basename(path6.dirname(filePath));
2792
- const home = options ? path6.resolve(stringOption(options.home) || os2.homedir()) : os2.homedir();
3054
+ const projectDir = path7.basename(path7.dirname(filePath));
3055
+ const home = options ? path7.resolve(stringOption(options.home) || os2.homedir()) : os2.homedir();
2793
3056
  const resolved = await resolveClaudeProjectPath(projectDir, home);
2794
3057
  if (resolved) {
2795
- return path6.basename(resolved);
3058
+ return path7.basename(resolved);
2796
3059
  }
2797
3060
  const suffix = claudeEncodedProjectSuffix(projectDir, home);
2798
3061
  if (suffix) {
@@ -2818,7 +3081,7 @@ async function resolveClaudeProjectPath(projectDir, home) {
2818
3081
  if (!entry.isDirectory()) {
2819
3082
  continue;
2820
3083
  }
2821
- const candidate = path6.join(current, entry.name);
3084
+ const candidate = path7.join(current, entry.name);
2822
3085
  const candidateVariants = claudeEncodedVariants(candidate);
2823
3086
  if (candidateVariants.includes(projectDir)) {
2824
3087
  return candidate;
@@ -2863,9 +3126,9 @@ function hookConfig2() {
2863
3126
  function claudeConfigDir(home, env) {
2864
3127
  const override = env?.CLAUDE_CONFIG_DIR;
2865
3128
  if (override && override.trim()) {
2866
- return path6.resolve(override);
3129
+ return path7.resolve(override);
2867
3130
  }
2868
- return path6.join(home, ".claude");
3131
+ return path7.join(home, ".claude");
2869
3132
  }
2870
3133
  function createClaudeCodeAdapter() {
2871
3134
  return {
@@ -2877,27 +3140,27 @@ function createClaudeCodeAdapter() {
2877
3140
  return claudeConfigDir(home, env);
2878
3141
  },
2879
3142
  installedPath(home, env) {
2880
- return path6.join(claudeConfigDir(home, env), "settings.json");
3143
+ return path7.join(claudeConfigDir(home, env), "settings.json");
2881
3144
  },
2882
3145
  async isInstalled(home, env) {
2883
3146
  return isHooksJsonInstalled(
2884
- path6.join(claudeConfigDir(home, env), "settings.json"),
3147
+ path7.join(claudeConfigDir(home, env), "settings.json"),
2885
3148
  "vibetime hook --agent claude"
2886
3149
  );
2887
3150
  },
2888
3151
  installEntries(home, env) {
2889
3152
  return [{
2890
3153
  kind: "hooks-json",
2891
- path: path6.join(claudeConfigDir(home, env), "settings.json"),
3154
+ path: path7.join(claudeConfigDir(home, env), "settings.json"),
2892
3155
  content: hookConfig2()
2893
3156
  }];
2894
3157
  },
2895
3158
  sourcePaths(home, env) {
2896
3159
  const base = claudeConfigDir(home, env);
2897
3160
  return [
2898
- path6.join(base, "projects"),
2899
- path6.join(base, ".claude.json"),
2900
- path6.join(home, ".claude.json")
3161
+ path7.join(base, "projects"),
3162
+ path7.join(base, ".claude.json"),
3163
+ path7.join(home, ".claude.json")
2901
3164
  ];
2902
3165
  },
2903
3166
  parseSessionFile: parseClaudeCodeSessionFile
@@ -2905,21 +3168,21 @@ function createClaudeCodeAdapter() {
2905
3168
  }
2906
3169
 
2907
3170
  // src/adapters/claude-cowork.ts
2908
- import { readdir as readdir3, readFile as readFile4, stat as stat4 } from "node:fs/promises";
3171
+ import { readdir as readdir3, readFile as readFile4, stat as stat5 } from "node:fs/promises";
2909
3172
  import os3 from "node:os";
2910
- import path7 from "node:path";
3173
+ import path8 from "node:path";
2911
3174
  init_fs();
2912
3175
  var COWORK_PREFIX = "cowork:";
2913
3176
  function coworkDataDirs(home, env) {
2914
3177
  const override = env?.COWORK_DIR || env?.CLAUDE_COWORK_DIR;
2915
3178
  if (override && override.trim()) {
2916
- return override.split(",").map((item) => item.trim()).filter(Boolean).map((item) => path7.resolve(item));
3179
+ return override.split(",").map((item) => item.trim()).filter(Boolean).map((item) => path8.resolve(item));
2917
3180
  }
2918
3181
  return [
2919
- path7.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions"),
2920
- path7.join(home, ".config", "Claude", "local-agent-mode-sessions"),
2921
- path7.join(home, "AppData", "Local", "Packages", "Claude_pzs8sxrjxfjjc", "LocalCache", "Roaming", "Claude", "local-agent-mode-sessions"),
2922
- path7.join(home, "AppData", "Roaming", "Claude", "local-agent-mode-sessions")
3182
+ path8.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions"),
3183
+ path8.join(home, ".config", "Claude", "local-agent-mode-sessions"),
3184
+ path8.join(home, "AppData", "Local", "Packages", "Claude_pzs8sxrjxfjjc", "LocalCache", "Roaming", "Claude", "local-agent-mode-sessions"),
3185
+ path8.join(home, "AppData", "Roaming", "Claude", "local-agent-mode-sessions")
2923
3186
  ];
2924
3187
  }
2925
3188
  function isCoworkMetaFileName(name) {
@@ -2935,7 +3198,7 @@ async function readCoworkMeta(filePath) {
2935
3198
  }
2936
3199
  async function isRegularFile(filePath) {
2937
3200
  try {
2938
- return (await stat4(filePath)).isFile();
3201
+ return (await stat5(filePath)).isFile();
2939
3202
  } catch {
2940
3203
  return false;
2941
3204
  }
@@ -2944,7 +3207,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
2944
3207
  if (!sessionDir || !cliSessionId) {
2945
3208
  return void 0;
2946
3209
  }
2947
- const projectsDir = path7.join(sessionDir, ".claude", "projects");
3210
+ const projectsDir = path8.join(sessionDir, ".claude", "projects");
2948
3211
  let entries;
2949
3212
  try {
2950
3213
  entries = await readdir3(projectsDir, { withFileTypes: true });
@@ -2956,7 +3219,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
2956
3219
  if (!entry.isDirectory() && !entry.isSymbolicLink()) {
2957
3220
  continue;
2958
3221
  }
2959
- const candidate = path7.join(projectsDir, entry.name, target);
3222
+ const candidate = path8.join(projectsDir, entry.name, target);
2960
3223
  if (await isRegularFile(candidate)) {
2961
3224
  return candidate;
2962
3225
  }
@@ -2964,7 +3227,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
2964
3227
  return void 0;
2965
3228
  }
2966
3229
  async function coworkSubagentTranscripts(mainTranscript, cliSessionId) {
2967
- const root = path7.join(path7.dirname(mainTranscript), cliSessionId, "subagents");
3230
+ const root = path8.join(path8.dirname(mainTranscript), cliSessionId, "subagents");
2968
3231
  const out = [];
2969
3232
  async function walk(dir) {
2970
3233
  let entries;
@@ -2974,7 +3237,7 @@ async function coworkSubagentTranscripts(mainTranscript, cliSessionId) {
2974
3237
  return;
2975
3238
  }
2976
3239
  await Promise.all(entries.map(async (entry) => {
2977
- const entryPath = path7.join(dir, entry.name);
3240
+ const entryPath = path8.join(dir, entry.name);
2978
3241
  if (entry.isDirectory()) {
2979
3242
  await walk(entryPath);
2980
3243
  return;
@@ -2997,7 +3260,7 @@ async function discoverCoworkTranscripts(root) {
2997
3260
  return;
2998
3261
  }
2999
3262
  await Promise.all(entries.map(async (entry) => {
3000
- const entryPath = path7.join(dir, entry.name);
3263
+ const entryPath = path8.join(dir, entry.name);
3001
3264
  if (entry.isDirectory()) {
3002
3265
  if (entry.name.startsWith("local_") || entry.name === "skills-plugin" || entry.name === "node_modules" || entry.name === ".git") {
3003
3266
  return;
@@ -3027,7 +3290,7 @@ async function discoverCoworkTranscripts(root) {
3027
3290
  return transcripts.sort((a, b) => a.transcriptPath.localeCompare(b.transcriptPath));
3028
3291
  }
3029
3292
  function coworkMetaPathForTranscript(transcriptPath) {
3030
- const marker = `${path7.sep}.claude${path7.sep}projects${path7.sep}`;
3293
+ const marker = `${path8.sep}.claude${path8.sep}projects${path8.sep}`;
3031
3294
  const index = transcriptPath.indexOf(marker);
3032
3295
  if (index < 0) {
3033
3296
  return void 0;
@@ -3042,9 +3305,9 @@ function projectFromMeta(meta) {
3042
3305
  if (!folder) {
3043
3306
  return { project: "cowork" };
3044
3307
  }
3045
- const resolved = path7.resolve(folder);
3308
+ const resolved = path8.resolve(folder);
3046
3309
  return {
3047
- project: path7.basename(resolved).replace(/-/g, "_") || "cowork",
3310
+ project: path8.basename(resolved).replace(/-/g, "_") || "cowork",
3048
3311
  cwd: resolved
3049
3312
  };
3050
3313
  }
@@ -3104,13 +3367,13 @@ async function parseClaudeCoworkSessionFile(filePath, options) {
3104
3367
  });
3105
3368
  }
3106
3369
  async function claudeCoworkBackfillFiles(sourceRoot, home, env) {
3107
- const roots = sourceRoot ? [path7.resolve(sourceRoot)] : coworkDataDirs(home, env);
3370
+ const roots = sourceRoot ? [path8.resolve(sourceRoot)] : coworkDataDirs(home, env);
3108
3371
  const discovered = (await Promise.all(roots.map(discoverCoworkTranscripts))).flat();
3109
3372
  return Promise.all(discovered.map(async ({ transcriptPath, metadataPath }) => {
3110
- const transcriptInfo = await stat4(transcriptPath);
3373
+ const transcriptInfo = await stat5(transcriptPath);
3111
3374
  let modifiedAt = transcriptInfo.mtime;
3112
3375
  try {
3113
- const metaInfo = await stat4(metadataPath);
3376
+ const metaInfo = await stat5(metadataPath);
3114
3377
  if (metaInfo.mtime > modifiedAt) {
3115
3378
  modifiedAt = metaInfo.mtime;
3116
3379
  }
@@ -3126,7 +3389,7 @@ function createClaudeCoworkAdapter() {
3126
3389
  agentName: "claude-cowork",
3127
3390
  kind: "agent",
3128
3391
  detectPath(home, env) {
3129
- return coworkDataDirs(home, env)[0] || path7.join(os3.homedir(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
3392
+ return coworkDataDirs(home, env)[0] || path8.join(os3.homedir(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
3130
3393
  },
3131
3394
  installedPath(home, env) {
3132
3395
  return this.detectPath(home, env);
@@ -3151,7 +3414,7 @@ function createClaudeCoworkAdapter() {
3151
3414
 
3152
3415
  // src/adapters/codebuddy.ts
3153
3416
  import { readFile as readFile5, readdir as readdir4 } from "node:fs/promises";
3154
- import path8 from "node:path";
3417
+ import path9 from "node:path";
3155
3418
  var ENDPOINT_MODEL_ID_RE = /^(?:ep|endpoint)-/i;
3156
3419
  async function parseCodebuddyTraceFile(filePath, options) {
3157
3420
  const text = await readFile5(filePath, "utf8");
@@ -3168,8 +3431,9 @@ async function parseCodebuddyTraceFile(filePath, options) {
3168
3431
  }
3169
3432
  const trace = traceFile.trace;
3170
3433
  const spans = Array.isArray(traceFile.spans) ? traceFile.spans : [];
3434
+ const hasGenerationSpans = spans.some((s) => s.type === "generation");
3171
3435
  const hasFunctionSpans = spans.some((s) => s.type === "function");
3172
- const isTrivial = !trace.sessionId && !trace.modelInfo && spans.length <= 3 && !hasFunctionSpans;
3436
+ const isTrivial = !hasGenerationSpans && !hasFunctionSpans;
3173
3437
  if (isTrivial) {
3174
3438
  return [];
3175
3439
  }
@@ -3178,7 +3442,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
3178
3442
  if (!cwd && trace.startedAt) {
3179
3443
  cwd = await cwdFromHistoryFile(trace.startedAt, options);
3180
3444
  }
3181
- const project = cwd ? path8.basename(cwd) : void 0;
3445
+ const project = cwd ? path9.basename(cwd) : void 0;
3182
3446
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
3183
3447
  const model = resolveCodebuddyModel(trace, spans);
3184
3448
  const baseEvent = (event) => ({
@@ -3345,7 +3609,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
3345
3609
  }
3346
3610
  if (span.type === "generation") {
3347
3611
  generationCount++;
3348
- const usage = modelUsageFromTrace(trace, generationCount, totalGenerations);
3612
+ const usage = extractUsageFromGenerationSpan(span) ?? modelUsageFromTrace(trace, generationCount, totalGenerations);
3349
3613
  push(baseEvent({
3350
3614
  ts,
3351
3615
  type: "model.usage",
@@ -3524,6 +3788,32 @@ function normalizeModelCandidate(value) {
3524
3788
  }
3525
3789
  return trimmed;
3526
3790
  }
3791
+ function extractUsageFromGenerationSpan(span) {
3792
+ const parsed = parseEmbeddedJson(span.toolOutput);
3793
+ if (!Array.isArray(parsed) || parsed.length === 0) {
3794
+ return void 0;
3795
+ }
3796
+ const first = parsed[0];
3797
+ if (!isPlainObject(first)) {
3798
+ return void 0;
3799
+ }
3800
+ const usage = objectField(first, "usage");
3801
+ if (!isPlainObject(usage)) {
3802
+ return void 0;
3803
+ }
3804
+ const inputTokens = numberField(usage, "prompt_tokens");
3805
+ const outputTokens = numberField(usage, "completion_tokens");
3806
+ const totalTokens = numberField(usage, "total_tokens");
3807
+ const details = objectField(usage, "prompt_tokens_details");
3808
+ const cachedTokens = isPlainObject(details) ? numberField(details, "cached_tokens") : void 0;
3809
+ return {
3810
+ tokensInput: inputTokens || void 0,
3811
+ tokensCachedInput: cachedTokens || void 0,
3812
+ tokensOutput: outputTokens || void 0,
3813
+ tokensTotal: totalTokens || void 0,
3814
+ modelCalls: 1
3815
+ };
3816
+ }
3527
3817
  function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
3528
3818
  const info = trace.modelInfo;
3529
3819
  if (!info || !info.totalInputTokens && !info.totalOutputTokens && !trace.totalTokens) {
@@ -3545,11 +3835,11 @@ function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
3545
3835
  return { modelCalls: 1 };
3546
3836
  }
3547
3837
  function sessionIdFromTracePath(filePath) {
3548
- const match = path8.basename(filePath).match(/trace_([0-9a-f]{32})/);
3838
+ const match = path9.basename(filePath).match(/trace_([0-9a-f]{32})/);
3549
3839
  return match?.[1] ? `codebuddy_${match[1]}` : `codebuddy_${createStableHash(filePath).slice(0, 24)}`;
3550
3840
  }
3551
3841
  function resolveHome(options) {
3552
- return options.home ? path8.resolve(String(options.home)) : process.env.HOME || __require("node:os").homedir();
3842
+ return options.home ? path9.resolve(String(options.home)) : process.env.HOME || __require("node:os").homedir();
3553
3843
  }
3554
3844
  async function readCwdFromSession(sessionPath, matchSessionId) {
3555
3845
  try {
@@ -3570,9 +3860,9 @@ async function readCwdFromSession(sessionPath, matchSessionId) {
3570
3860
  }
3571
3861
  async function cwdFromSessionFile(pid, traceSessionId, options) {
3572
3862
  const home = resolveHome(options);
3573
- const sessionsDir = path8.join(home, ".codebuddy", "sessions");
3863
+ const sessionsDir = path9.join(home, ".codebuddy", "sessions");
3574
3864
  if (pid) {
3575
- const cwd = await readCwdFromSession(path8.join(sessionsDir, `${pid}.json`));
3865
+ const cwd = await readCwdFromSession(path9.join(sessionsDir, `${pid}.json`));
3576
3866
  if (cwd) {
3577
3867
  return cwd;
3578
3868
  }
@@ -3585,7 +3875,7 @@ async function cwdFromSessionFile(pid, traceSessionId, options) {
3585
3875
  continue;
3586
3876
  }
3587
3877
  const cwd = await readCwdFromSession(
3588
- path8.join(sessionsDir, f),
3878
+ path9.join(sessionsDir, f),
3589
3879
  traceSessionId
3590
3880
  );
3591
3881
  if (cwd) {
@@ -3599,7 +3889,7 @@ async function cwdFromSessionFile(pid, traceSessionId, options) {
3599
3889
  }
3600
3890
  async function cwdFromHistoryFile(traceStartedAt, options) {
3601
3891
  const home = resolveHome(options);
3602
- const historyPath = path8.join(home, ".codebuddy", "history.jsonl");
3892
+ const historyPath = path9.join(home, ".codebuddy", "history.jsonl");
3603
3893
  const traceMs = Date.parse(traceStartedAt);
3604
3894
  if (Number.isNaN(traceMs)) {
3605
3895
  return void 0;
@@ -3661,9 +3951,9 @@ function hookConfig3() {
3661
3951
  function codebuddyConfigDir(home, env) {
3662
3952
  const override = env?.CODEBUDDY_CONFIG_DIR;
3663
3953
  if (override && override.trim()) {
3664
- return path8.resolve(override);
3954
+ return path9.resolve(override);
3665
3955
  }
3666
- return path8.join(home, ".codebuddy");
3956
+ return path9.join(home, ".codebuddy");
3667
3957
  }
3668
3958
  function createCodebuddyAdapter() {
3669
3959
  return {
@@ -3675,32 +3965,32 @@ function createCodebuddyAdapter() {
3675
3965
  return codebuddyConfigDir(home, env);
3676
3966
  },
3677
3967
  installedPath(home, env) {
3678
- return path8.join(codebuddyConfigDir(home, env), "settings.json");
3968
+ return path9.join(codebuddyConfigDir(home, env), "settings.json");
3679
3969
  },
3680
3970
  async isInstalled(home, env) {
3681
3971
  return isHooksJsonInstalled(
3682
- path8.join(codebuddyConfigDir(home, env), "settings.json"),
3972
+ path9.join(codebuddyConfigDir(home, env), "settings.json"),
3683
3973
  "vibetime hook --agent codebuddy"
3684
3974
  );
3685
3975
  },
3686
3976
  installEntries(home, env) {
3687
3977
  return [{
3688
3978
  kind: "hooks-json",
3689
- path: path8.join(codebuddyConfigDir(home, env), "settings.json"),
3979
+ path: path9.join(codebuddyConfigDir(home, env), "settings.json"),
3690
3980
  content: hookConfig3()
3691
3981
  }];
3692
3982
  },
3693
3983
  sourcePaths(home, env) {
3694
3984
  const base = codebuddyConfigDir(home, env);
3695
3985
  return [
3696
- path8.join(base, "traces")
3986
+ path9.join(base, "traces")
3697
3987
  ];
3698
3988
  },
3699
3989
  parseSessionFile: parseCodebuddyTraceFile
3700
3990
  };
3701
3991
  }
3702
3992
  async function codebuddyBackfillFiles(sourceRoot, home, env) {
3703
- const base = sourceRoot || path8.join(codebuddyConfigDir(home, env), "traces");
3993
+ const base = sourceRoot || path9.join(codebuddyConfigDir(home, env), "traces");
3704
3994
  const files = [];
3705
3995
  try {
3706
3996
  const pidDirs = await readdir4(base, { withFileTypes: true });
@@ -3708,17 +3998,17 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
3708
3998
  if (!pidDir.isDirectory()) {
3709
3999
  continue;
3710
4000
  }
3711
- const traceDir = path8.join(base, pidDir.name);
4001
+ const traceDir = path9.join(base, pidDir.name);
3712
4002
  try {
3713
4003
  const entries = await readdir4(traceDir);
3714
4004
  for (const entry of entries) {
3715
4005
  if (!entry.endsWith(".json") || !entry.startsWith("trace_")) {
3716
4006
  continue;
3717
4007
  }
3718
- const filePath = path8.join(traceDir, entry);
4008
+ const filePath = path9.join(traceDir, entry);
3719
4009
  try {
3720
- const stat12 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
3721
- files.push({ path: filePath, modifiedAt: stat12.mtime.toISOString() });
4010
+ const stat13 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
4011
+ files.push({ path: filePath, modifiedAt: stat13.mtime.toISOString() });
3722
4012
  } catch {
3723
4013
  }
3724
4014
  }
@@ -3732,7 +4022,7 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
3732
4022
 
3733
4023
  // src/adapters/codex.ts
3734
4024
  import { readFile as readFile6 } from "node:fs/promises";
3735
- import path10 from "node:path";
4025
+ import path11 from "node:path";
3736
4026
 
3737
4027
  // src/lib/diff.ts
3738
4028
  function diffStats(diff) {
@@ -3781,16 +4071,16 @@ function fileActivitiesFromPatchChanges(changes, ts, cwd, displayFilePath3) {
3781
4071
  init_fs();
3782
4072
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
3783
4073
  import os4 from "node:os";
3784
- import path9 from "node:path";
4074
+ import path10 from "node:path";
3785
4075
  var SESSION_CONTEXT_VERSION = 1;
3786
4076
  function sessionContextDir(home) {
3787
- return path9.join(home, ".vibetime", "session-context");
4077
+ return path10.join(home, ".vibetime", "session-context");
3788
4078
  }
3789
4079
  function sessionContextPath(home, sessionId) {
3790
- return path9.join(sessionContextDir(home), `${encodeURIComponent(sessionId)}.json`);
4080
+ return path10.join(sessionContextDir(home), `${encodeURIComponent(sessionId)}.json`);
3791
4081
  }
3792
4082
  function resolveHome2(options) {
3793
- return options ? path9.resolve(stringOption(options.home) || os4.homedir()) : os4.homedir();
4083
+ return options ? path10.resolve(stringOption(options.home) || os4.homedir()) : os4.homedir();
3794
4084
  }
3795
4085
  async function readPersistedSessionContext(home, sessionId) {
3796
4086
  const raw = await readJsonIfExists(sessionContextPath(home, sessionId));
@@ -3816,10 +4106,10 @@ async function persistHookSessionContext(home, payload) {
3816
4106
  }
3817
4107
  const sessionId = typeof payload.session_id === "string" ? payload.session_id.trim() : typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
3818
4108
  const cwd = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
3819
- if (!sessionId || !cwd || !path9.isAbsolute(cwd)) {
4109
+ if (!sessionId || !cwd || !path10.isAbsolute(cwd)) {
3820
4110
  return;
3821
4111
  }
3822
- const project = path9.basename(cwd) || void 0;
4112
+ const project = path10.basename(cwd) || void 0;
3823
4113
  const context = {
3824
4114
  version: SESSION_CONTEXT_VERSION,
3825
4115
  sessionId,
@@ -3870,7 +4160,7 @@ async function parseCodexSessionFile(filePath, options) {
3870
4160
  const inherited = forkedFromId ? await readPersistedSessionContextFromOptions(options, forkedFromId) : void 0;
3871
4161
  sessionId = stringField(payload, "id") || sessionId;
3872
4162
  cwd = inherited?.cwd || stringField(payload, "cwd") || cwd;
3873
- project = inherited?.project || (cwd ? path10.basename(cwd) : project);
4163
+ project = inherited?.project || (cwd ? path11.basename(cwd) : project);
3874
4164
  model = stringField(payload, "model_provider") || model;
3875
4165
  events.push(withBackfillRefs({
3876
4166
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
@@ -3891,7 +4181,7 @@ async function parseCodexSessionFile(filePath, options) {
3891
4181
  if (topType === "turn_context") {
3892
4182
  currentTurnId = stringField(payload, "turn_id") || currentTurnId;
3893
4183
  cwd = stringField(payload, "cwd") || cwd;
3894
- project = cwd ? path10.basename(cwd) : project;
4184
+ project = cwd ? path11.basename(cwd) : project;
3895
4185
  model = stringField(payload, "model") || model;
3896
4186
  const effort = stringField(payload, "effort") || stringField(objectField(objectField(payload, "collaboration_mode"), "settings"), "reasoning_effort");
3897
4187
  if (effort) {
@@ -4338,11 +4628,11 @@ function functionCallArguments(payload) {
4338
4628
  }
4339
4629
  }
4340
4630
  function displayFilePath2(filePath, cwd) {
4341
- if (!cwd || !path10.isAbsolute(filePath)) {
4631
+ if (!cwd || !path11.isAbsolute(filePath)) {
4342
4632
  return filePath;
4343
4633
  }
4344
- const relative = path10.relative(cwd, filePath);
4345
- return relative && !relative.startsWith("..") && !path10.isAbsolute(relative) ? relative : filePath;
4634
+ const relative = path11.relative(cwd, filePath);
4635
+ return relative && !relative.startsWith("..") && !path11.isAbsolute(relative) ? relative : filePath;
4346
4636
  }
4347
4637
  var codexHandler = (msg) => hookHandler("codex", msg);
4348
4638
  function hookConfig4() {
@@ -4361,9 +4651,9 @@ function hookConfig4() {
4361
4651
  function codexHome(home, env) {
4362
4652
  const override = env?.CODEX_HOME;
4363
4653
  if (override && override.trim()) {
4364
- return path10.resolve(override);
4654
+ return path11.resolve(override);
4365
4655
  }
4366
- return path10.join(home, ".codex");
4656
+ return path11.join(home, ".codex");
4367
4657
  }
4368
4658
  function createCodexAdapter() {
4369
4659
  return {
@@ -4375,26 +4665,26 @@ function createCodexAdapter() {
4375
4665
  return codexHome(home, env);
4376
4666
  },
4377
4667
  installedPath(home, env) {
4378
- return path10.join(codexHome(home, env), "hooks.json");
4668
+ return path11.join(codexHome(home, env), "hooks.json");
4379
4669
  },
4380
4670
  async isInstalled(home, env) {
4381
4671
  return isHooksJsonInstalled(
4382
- path10.join(codexHome(home, env), "hooks.json"),
4672
+ path11.join(codexHome(home, env), "hooks.json"),
4383
4673
  "vibetime hook --agent codex"
4384
4674
  );
4385
4675
  },
4386
4676
  installEntries(home, env) {
4387
4677
  return [{
4388
4678
  kind: "hooks-json",
4389
- path: path10.join(codexHome(home, env), "hooks.json"),
4679
+ path: path11.join(codexHome(home, env), "hooks.json"),
4390
4680
  content: hookConfig4()
4391
4681
  }];
4392
4682
  },
4393
4683
  sourcePaths(home, env) {
4394
4684
  const base = codexHome(home, env);
4395
4685
  return [
4396
- path10.join(base, "sessions"),
4397
- path10.join(base, "history.jsonl")
4686
+ path11.join(base, "sessions"),
4687
+ path11.join(base, "history.jsonl")
4398
4688
  ];
4399
4689
  },
4400
4690
  parseSessionFile: parseCodexSessionFile
@@ -4402,9 +4692,9 @@ function createCodexAdapter() {
4402
4692
  }
4403
4693
 
4404
4694
  // src/adapters/copilot.ts
4405
- import { readdir as readdir5, readFile as readFile7, stat as stat5 } from "node:fs/promises";
4695
+ import { readdir as readdir5, readFile as readFile7, stat as stat6 } from "node:fs/promises";
4406
4696
  import os5 from "node:os";
4407
- import path11 from "node:path";
4697
+ import path12 from "node:path";
4408
4698
  async function parseCopilotSessionFile(filePath, options) {
4409
4699
  const text = await readFile7(filePath, "utf8");
4410
4700
  const lines = text.split("\n").filter(Boolean);
@@ -4440,7 +4730,7 @@ async function parseCopilotSessionFile(filePath, options) {
4440
4730
  }
4441
4731
  const context = objectField(data, "context");
4442
4732
  cwd = stringField(context, "cwd") || stringField(context, "gitRoot") || cwd;
4443
- project = stringField(context, "repository") || (cwd ? path11.basename(cwd) : void 0);
4733
+ project = stringField(context, "repository") || (cwd ? path12.basename(cwd) : void 0);
4444
4734
  sessionStartedAt = ts;
4445
4735
  events.push(baseCopilotEvent({
4446
4736
  ts,
@@ -4672,7 +4962,7 @@ function baseCopilotEvent(event) {
4672
4962
  };
4673
4963
  }
4674
4964
  async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
4675
- const sessionDir = sourceRoot || path11.join(home, ".copilot", "session-state");
4965
+ const sessionDir = sourceRoot || path12.join(home, ".copilot", "session-state");
4676
4966
  const results = [];
4677
4967
  let entries;
4678
4968
  try {
@@ -4684,8 +4974,8 @@ async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
4684
4974
  if (entry.startsWith("pending-session")) {
4685
4975
  continue;
4686
4976
  }
4687
- const eventsPath = path11.join(sessionDir, entry, "events.jsonl");
4688
- const info = await stat5(eventsPath).catch(() => null);
4977
+ const eventsPath = path12.join(sessionDir, entry, "events.jsonl");
4978
+ const info = await stat6(eventsPath).catch(() => null);
4689
4979
  if (info) {
4690
4980
  results.push({ path: eventsPath, modifiedAt: info.mtime.toISOString() });
4691
4981
  }
@@ -4702,9 +4992,9 @@ function copilotPluginContent() {
4702
4992
  function copilotHome(home, env) {
4703
4993
  const override = env?.COPILOT_HOME;
4704
4994
  if (override && override.trim()) {
4705
- return path11.resolve(override);
4995
+ return path12.resolve(override);
4706
4996
  }
4707
- return path11.join(home, ".copilot");
4997
+ return path12.join(home, ".copilot");
4708
4998
  }
4709
4999
  function createCopilotAdapter() {
4710
5000
  return {
@@ -4716,12 +5006,12 @@ function createCopilotAdapter() {
4716
5006
  return copilotHome(home, env);
4717
5007
  },
4718
5008
  installedPath(home, env) {
4719
- return path11.join(copilotHome(home, env), ".vibetime");
5009
+ return path12.join(copilotHome(home, env), ".vibetime");
4720
5010
  },
4721
5011
  async isInstalled(home, env) {
4722
5012
  try {
4723
5013
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
4724
- return await pathExists2(path11.join(copilotHome(home, env), ".vibetime"));
5014
+ return await pathExists2(path12.join(copilotHome(home, env), ".vibetime"));
4725
5015
  } catch {
4726
5016
  return false;
4727
5017
  }
@@ -4729,12 +5019,12 @@ function createCopilotAdapter() {
4729
5019
  installEntries(home, env) {
4730
5020
  return [{
4731
5021
  kind: "file",
4732
- path: path11.join(copilotHome(home, env), ".vibetime"),
5022
+ path: path12.join(copilotHome(home, env), ".vibetime"),
4733
5023
  content: copilotPluginContent()
4734
5024
  }];
4735
5025
  },
4736
5026
  sourcePaths(home, env) {
4737
- return [path11.join(copilotHome(home, env), "session-state")];
5027
+ return [path12.join(copilotHome(home, env), "session-state")];
4738
5028
  },
4739
5029
  parseSessionFile: parseCopilotSessionFile
4740
5030
  };
@@ -4742,7 +5032,7 @@ function createCopilotAdapter() {
4742
5032
 
4743
5033
  // src/adapters/opencode.ts
4744
5034
  import os6 from "node:os";
4745
- import path12 from "node:path";
5035
+ import path13 from "node:path";
4746
5036
  async function parseOpenCodeSessionFile(dbPath, options) {
4747
5037
  const { DatabaseSync } = await import("node:sqlite");
4748
5038
  if (!dbPath.endsWith(".db")) {
@@ -4773,7 +5063,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
4773
5063
  for (const session of sessions) {
4774
5064
  const sessionId = session.id;
4775
5065
  const cwd = session.directory || session.path || void 0;
4776
- const project = cwd ? path12.basename(cwd) : void 0;
5066
+ const project = cwd ? path13.basename(cwd) : void 0;
4777
5067
  const sessionTs = msToIso(session.time_created);
4778
5068
  events.push(baseOpenCodeEvent({
4779
5069
  ts: sessionTs,
@@ -4881,7 +5171,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
4881
5171
  const provider = currentProvider;
4882
5172
  const pathObj = objectField(info, "path");
4883
5173
  const assistantCwd = stringField(pathObj, "cwd") || cwd;
4884
- const assistantProject = assistantCwd ? path12.basename(assistantCwd) : project;
5174
+ const assistantProject = assistantCwd ? path13.basename(assistantCwd) : project;
4885
5175
  const completedTs = numberField(objectField(info, "time"), "completed");
4886
5176
  const createdTs = timeCreated;
4887
5177
  const tokens = opencodeUsageFromInfo(info);
@@ -5127,33 +5417,33 @@ function opencodeUsageFromInfo(info) {
5127
5417
  function opencodeConfigDir(home, env) {
5128
5418
  const override = env?.OPENCODE_CONFIG_DIR;
5129
5419
  if (override && override.trim()) {
5130
- return path12.resolve(override);
5420
+ return path13.resolve(override);
5131
5421
  }
5132
5422
  const xdgConfig = env?.XDG_CONFIG_HOME;
5133
5423
  if (xdgConfig && xdgConfig.trim()) {
5134
- return path12.join(path12.resolve(xdgConfig), "opencode");
5424
+ return path13.join(path13.resolve(xdgConfig), "opencode");
5135
5425
  }
5136
- return path12.join(home, ".config", "opencode");
5426
+ return path13.join(home, ".config", "opencode");
5137
5427
  }
5138
5428
  function opencodeDataCandidates(home, env) {
5139
5429
  const xdgData = env?.XDG_DATA_HOME;
5140
- const primary = xdgData && xdgData.trim() ? path12.join(path12.resolve(xdgData), "opencode", "opencode.db") : path12.join(home, ".local", "share", "opencode", "opencode.db");
5141
- return [primary, path12.join(home, ".opencode", "opencode.db")];
5430
+ const primary = xdgData && xdgData.trim() ? path13.join(path13.resolve(xdgData), "opencode", "opencode.db") : path13.join(home, ".local", "share", "opencode", "opencode.db");
5431
+ return [primary, path13.join(home, ".opencode", "opencode.db")];
5142
5432
  }
5143
5433
  async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
5144
- const { stat: stat12 } = await import("node:fs/promises");
5434
+ const { stat: stat13 } = await import("node:fs/promises");
5145
5435
  if (sourceRoot) {
5146
5436
  if (!sourceRoot.endsWith(".db")) {
5147
5437
  return [];
5148
5438
  }
5149
- const info = await stat12(sourceRoot).catch(() => null);
5439
+ const info = await stat13(sourceRoot).catch(() => null);
5150
5440
  if (!info) {
5151
5441
  return [];
5152
5442
  }
5153
5443
  return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
5154
5444
  }
5155
5445
  for (const candidatePath of opencodeDataCandidates(home, env)) {
5156
- const info = await stat12(candidatePath).catch(() => null);
5446
+ const info = await stat13(candidatePath).catch(() => null);
5157
5447
  if (info) {
5158
5448
  return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
5159
5449
  }
@@ -5228,12 +5518,12 @@ function createOpenCodeAdapter() {
5228
5518
  return opencodeConfigDir(home, env);
5229
5519
  },
5230
5520
  installedPath(home, env) {
5231
- return path12.join(opencodeConfigDir(home, env), PLUGIN_PATH);
5521
+ return path13.join(opencodeConfigDir(home, env), PLUGIN_PATH);
5232
5522
  },
5233
5523
  async isInstalled(home, env) {
5234
5524
  try {
5235
5525
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
5236
- return await pathExists2(path12.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path12.join(".opencode", PLUGIN_PATH));
5526
+ return await pathExists2(path13.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path13.join(".opencode", PLUGIN_PATH));
5237
5527
  } catch {
5238
5528
  return false;
5239
5529
  }
@@ -5241,7 +5531,7 @@ function createOpenCodeAdapter() {
5241
5531
  installEntries(home, env) {
5242
5532
  return [{
5243
5533
  kind: "file",
5244
- path: path12.join(opencodeConfigDir(home, env), PLUGIN_PATH),
5534
+ path: path13.join(opencodeConfigDir(home, env), PLUGIN_PATH),
5245
5535
  content: opencodePluginContent()
5246
5536
  }];
5247
5537
  },
@@ -5254,7 +5544,7 @@ function createOpenCodeAdapter() {
5254
5544
 
5255
5545
  // src/adapters/pi.ts
5256
5546
  import { readFile as readFile8 } from "node:fs/promises";
5257
- import path13 from "node:path";
5547
+ import path14 from "node:path";
5258
5548
  async function parsePiSessionFile(filePath, options) {
5259
5549
  const text = await readFile8(filePath, "utf8");
5260
5550
  const lines = text.split("\n").filter(Boolean);
@@ -5287,7 +5577,7 @@ async function parsePiSessionFile(filePath, options) {
5287
5577
  sessionId = stringField(raw, "id") || state.sessionId;
5288
5578
  state.sessionId = sessionId || state.sessionId;
5289
5579
  cwd = stringField(raw, "cwd") || cwd;
5290
- project = cwd ? path13.basename(cwd) : project;
5580
+ project = cwd ? path14.basename(cwd) : project;
5291
5581
  continue;
5292
5582
  }
5293
5583
  if (entryType === "model_change") {
@@ -5696,16 +5986,16 @@ export default function (pi: ExtensionAPI) {
5696
5986
  function piAgentDir(home, env) {
5697
5987
  const override = env?.PI_CODING_AGENT_DIR;
5698
5988
  if (override && override.trim()) {
5699
- return path13.resolve(override);
5989
+ return path14.resolve(override);
5700
5990
  }
5701
- return path13.join(home, ".pi", "agent");
5991
+ return path14.join(home, ".pi", "agent");
5702
5992
  }
5703
5993
  function piSessionDir(home, env) {
5704
5994
  const override = env?.PI_CODING_AGENT_SESSION_DIR;
5705
5995
  if (override && override.trim()) {
5706
- return path13.resolve(override);
5996
+ return path14.resolve(override);
5707
5997
  }
5708
- return path13.join(piAgentDir(home, env), "sessions");
5998
+ return path14.join(piAgentDir(home, env), "sessions");
5709
5999
  }
5710
6000
  function createPiAdapter() {
5711
6001
  return {
@@ -5717,12 +6007,12 @@ function createPiAdapter() {
5717
6007
  return piAgentDir(home, env);
5718
6008
  },
5719
6009
  installedPath(home, env) {
5720
- return path13.join(piAgentDir(home, env), "extensions", "vibetime.ts");
6010
+ return path14.join(piAgentDir(home, env), "extensions", "vibetime.ts");
5721
6011
  },
5722
6012
  async isInstalled(home, env) {
5723
6013
  try {
5724
6014
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
5725
- return await pathExists2(path13.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
6015
+ return await pathExists2(path14.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
5726
6016
  } catch {
5727
6017
  return false;
5728
6018
  }
@@ -5730,7 +6020,7 @@ function createPiAdapter() {
5730
6020
  installEntries(home, env) {
5731
6021
  return [{
5732
6022
  kind: "file",
5733
- path: path13.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
6023
+ path: path14.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
5734
6024
  content: piExtensionContent()
5735
6025
  }];
5736
6026
  },
@@ -5742,11 +6032,11 @@ function createPiAdapter() {
5742
6032
  }
5743
6033
 
5744
6034
  // src/adapters/qoder-cn.ts
5745
- import { readdir as readdir6, readFile as readFile9, stat as stat6 } from "node:fs/promises";
6035
+ import { readdir as readdir6, readFile as readFile9, stat as stat7 } from "node:fs/promises";
5746
6036
  import os7 from "node:os";
5747
- import path14 from "node:path";
6037
+ import path15 from "node:path";
5748
6038
  function parseQoderCnPaths(filePath) {
5749
- const parts = filePath.split(path14.sep);
6039
+ const parts = filePath.split(path15.sep);
5750
6040
  const subagentsIdx = parts.lastIndexOf("subagents");
5751
6041
  let sessionId = "";
5752
6042
  let projectName = "";
@@ -5755,19 +6045,19 @@ function parseQoderCnPaths(filePath) {
5755
6045
  sessionId = parts[subagentsIdx - 1];
5756
6046
  projectName = parts[subagentsIdx - 2];
5757
6047
  const projectsIdx = parts.lastIndexOf("projects");
5758
- configDir2 = parts.slice(0, projectsIdx).join(path14.sep);
6048
+ configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
5759
6049
  } else {
5760
6050
  const filename = parts.at(-1) || "";
5761
- sessionId = path14.basename(filename, ".jsonl");
6051
+ sessionId = path15.basename(filename, ".jsonl");
5762
6052
  projectName = parts.at(-2) || "";
5763
6053
  const projectsIdx = parts.lastIndexOf("projects");
5764
- configDir2 = parts.slice(0, projectsIdx).join(path14.sep);
6054
+ configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
5765
6055
  }
5766
6056
  return { configDir: configDir2, projectName, sessionId };
5767
6057
  }
5768
6058
  async function loadQoderCnModelNames(configDir2) {
5769
6059
  try {
5770
- const dynamicTextsPath = path14.join(configDir2, ".auth", "dynamic-texts.json");
6060
+ const dynamicTextsPath = path15.join(configDir2, ".auth", "dynamic-texts.json");
5771
6061
  const content = await readFile9(dynamicTextsPath, "utf8");
5772
6062
  const json = JSON.parse(content);
5773
6063
  const texts = json.texts || {};
@@ -5785,7 +6075,7 @@ async function loadQoderCnModelNames(configDir2) {
5785
6075
  }
5786
6076
  async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
5787
6077
  const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
5788
- const segmentsPath = path14.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
6078
+ const segmentsPath = path15.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
5789
6079
  const modelCalls = [];
5790
6080
  try {
5791
6081
  const files = await readdir6(segmentsPath);
@@ -5793,7 +6083,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
5793
6083
  if (!file.endsWith(".jsonl")) {
5794
6084
  continue;
5795
6085
  }
5796
- const content = await readFile9(path14.join(segmentsPath, file), "utf8");
6086
+ const content = await readFile9(path15.join(segmentsPath, file), "utf8");
5797
6087
  let currentTurnIsSubagent = false;
5798
6088
  for (const line of content.split("\n").filter(Boolean)) {
5799
6089
  const raw = parseJsonLine(line);
@@ -5861,7 +6151,7 @@ async function parseQoderCnSessionFile(filePath, options) {
5861
6151
  sessionId = stringField(raw, "sessionId") || sessionId;
5862
6152
  state.sessionId = sessionId;
5863
6153
  cwd = stringField(raw, "cwd") || cwd;
5864
- project = projectContext.project || (cwd ? path14.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
6154
+ project = projectContext.project || (cwd ? path15.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
5865
6155
  if (!ts) {
5866
6156
  continue;
5867
6157
  }
@@ -6290,28 +6580,28 @@ function isNoisePrompt(text) {
6290
6580
  }
6291
6581
  async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
6292
6582
  const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
6293
- const isSubagent = filePath.includes(`${path14.sep}subagents${path14.sep}`);
6583
+ const isSubagent = filePath.includes(`${path15.sep}subagents${path15.sep}`);
6294
6584
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
6295
6585
  let cwds = [];
6296
6586
  for (const line of lines) {
6297
6587
  const raw = parseJsonLine(line);
6298
6588
  const cwd = raw ? stringField(raw, "cwd") : void 0;
6299
- if (cwd && path14.isAbsolute(cwd)) {
6589
+ if (cwd && path15.isAbsolute(cwd)) {
6300
6590
  cwds.push(cwd);
6301
6591
  }
6302
6592
  }
6303
6593
  if (isSubagent) {
6304
- if (inherited?.cwd && path14.isAbsolute(inherited.cwd)) {
6594
+ if (inherited?.cwd && path15.isAbsolute(inherited.cwd)) {
6305
6595
  cwds = [inherited.cwd];
6306
6596
  } else {
6307
- const parentSessionPath = path14.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
6597
+ const parentSessionPath = path15.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
6308
6598
  try {
6309
6599
  const parentText = await readFile9(parentSessionPath, "utf8");
6310
6600
  const parentCwds = [];
6311
6601
  for (const line of parentText.split("\n").filter(Boolean)) {
6312
6602
  const raw = parseJsonLine(line);
6313
6603
  const cwd = raw ? stringField(raw, "cwd") : void 0;
6314
- if (cwd && path14.isAbsolute(cwd)) {
6604
+ if (cwd && path15.isAbsolute(cwd)) {
6315
6605
  parentCwds.push(cwd);
6316
6606
  }
6317
6607
  }
@@ -6323,7 +6613,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
6323
6613
  }
6324
6614
  }
6325
6615
  const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
6326
- const project = inherited?.project || (cwds.length > 0 ? path14.basename(cwds[0]) : root ? path14.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
6616
+ const project = inherited?.project || (cwds.length > 0 ? path15.basename(cwds[0]) : root ? path15.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
6327
6617
  return {
6328
6618
  project,
6329
6619
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
@@ -6332,15 +6622,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
6332
6622
  async function gitRootFromCwds2(cwds) {
6333
6623
  const seen = /* @__PURE__ */ new Set();
6334
6624
  for (const cwd of cwds) {
6335
- let current = path14.resolve(cwd);
6625
+ let current = path15.resolve(cwd);
6336
6626
  while (!seen.has(current)) {
6337
6627
  seen.add(current);
6338
6628
  try {
6339
- await stat6(path14.join(current, ".git"));
6629
+ await stat7(path15.join(current, ".git"));
6340
6630
  return current;
6341
6631
  } catch {
6342
6632
  }
6343
- const parent = path14.dirname(current);
6633
+ const parent = path15.dirname(current);
6344
6634
  if (parent === current) {
6345
6635
  break;
6346
6636
  }
@@ -6351,12 +6641,12 @@ async function gitRootFromCwds2(cwds) {
6351
6641
  }
6352
6642
  function qoderCnProjectRootFromCwds(projectDir, cwds) {
6353
6643
  for (const cwd of cwds) {
6354
- let current = path14.resolve(cwd);
6644
+ let current = path15.resolve(cwd);
6355
6645
  while (true) {
6356
6646
  if (encodeQoderCnProjectPath(current) === projectDir) {
6357
6647
  return current;
6358
6648
  }
6359
- const parent = path14.dirname(current);
6649
+ const parent = path15.dirname(current);
6360
6650
  if (parent === current) {
6361
6651
  break;
6362
6652
  }
@@ -6366,14 +6656,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
6366
6656
  return void 0;
6367
6657
  }
6368
6658
  function encodeQoderCnProjectPath(value) {
6369
- return path14.resolve(value).split(path14.sep).join("-").replace(/_/g, "-");
6659
+ return path15.resolve(value).split(path15.sep).join("-").replace(/_/g, "-");
6370
6660
  }
6371
6661
  async function qoderCnProjectFromFilePath(filePath, options) {
6372
- const projectDir = path14.basename(path14.dirname(filePath));
6373
- const home = options ? path14.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
6662
+ const projectDir = path15.basename(path15.dirname(filePath));
6663
+ const home = options ? path15.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
6374
6664
  const resolved = await resolveQoderCnProjectPath(projectDir, home);
6375
6665
  if (resolved) {
6376
- return path14.basename(resolved);
6666
+ return path15.basename(resolved);
6377
6667
  }
6378
6668
  const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
6379
6669
  if (projectDir.startsWith(homePrefix)) {
@@ -6398,7 +6688,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
6398
6688
  if (!entry.isDirectory()) {
6399
6689
  continue;
6400
6690
  }
6401
- const candidate = path14.join(current, entry.name);
6691
+ const candidate = path15.join(current, entry.name);
6402
6692
  const encoded = encodeQoderCnProjectPath(candidate);
6403
6693
  if (encoded === projectDir) {
6404
6694
  return candidate;
@@ -6443,9 +6733,9 @@ function hookConfig5() {
6443
6733
  function qoderCnConfigDir(home, env) {
6444
6734
  const override = env?.QODER_CN_CONFIG_DIR;
6445
6735
  if (override && override.trim()) {
6446
- return path14.resolve(override);
6736
+ return path15.resolve(override);
6447
6737
  }
6448
- return path14.join(home, ".qoder-cn");
6738
+ return path15.join(home, ".qoder-cn");
6449
6739
  }
6450
6740
  function createQoderCnAdapter() {
6451
6741
  return {
@@ -6457,27 +6747,27 @@ function createQoderCnAdapter() {
6457
6747
  return qoderCnConfigDir(home, env);
6458
6748
  },
6459
6749
  installedPath(home, env) {
6460
- return path14.join(qoderCnConfigDir(home, env), "settings.json");
6750
+ return path15.join(qoderCnConfigDir(home, env), "settings.json");
6461
6751
  },
6462
6752
  async isInstalled(home, env) {
6463
6753
  return isHooksJsonInstalled(
6464
- path14.join(qoderCnConfigDir(home, env), "settings.json"),
6754
+ path15.join(qoderCnConfigDir(home, env), "settings.json"),
6465
6755
  "vibetime hook --agent qoder-cn"
6466
6756
  );
6467
6757
  },
6468
6758
  installEntries(home, env) {
6469
6759
  return [{
6470
6760
  kind: "hooks-json",
6471
- path: path14.join(qoderCnConfigDir(home, env), "settings.json"),
6761
+ path: path15.join(qoderCnConfigDir(home, env), "settings.json"),
6472
6762
  content: hookConfig5()
6473
6763
  }];
6474
6764
  },
6475
6765
  sourcePaths(home, env) {
6476
6766
  const base = qoderCnConfigDir(home, env);
6477
6767
  return [
6478
- path14.join(base, "projects"),
6479
- path14.join(base, ".qoder.json"),
6480
- path14.join(home, ".qoder.json")
6768
+ path15.join(base, "projects"),
6769
+ path15.join(base, ".qoder.json"),
6770
+ path15.join(home, ".qoder.json")
6481
6771
  ];
6482
6772
  },
6483
6773
  parseSessionFile: parseQoderCnSessionFile
@@ -6485,11 +6775,11 @@ function createQoderCnAdapter() {
6485
6775
  }
6486
6776
 
6487
6777
  // src/adapters/qoder.ts
6488
- import { readdir as readdir7, readFile as readFile10, stat as stat7 } from "node:fs/promises";
6778
+ import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
6489
6779
  import os8 from "node:os";
6490
- import path15 from "node:path";
6780
+ import path16 from "node:path";
6491
6781
  function parseQoderPaths(filePath) {
6492
- const parts = filePath.split(path15.sep);
6782
+ const parts = filePath.split(path16.sep);
6493
6783
  const subagentsIdx = parts.lastIndexOf("subagents");
6494
6784
  let sessionId = "";
6495
6785
  let projectName = "";
@@ -6498,19 +6788,19 @@ function parseQoderPaths(filePath) {
6498
6788
  sessionId = parts[subagentsIdx - 1];
6499
6789
  projectName = parts[subagentsIdx - 2];
6500
6790
  const projectsIdx = parts.lastIndexOf("projects");
6501
- configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
6791
+ configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
6502
6792
  } else {
6503
6793
  const filename = parts.at(-1) || "";
6504
- sessionId = path15.basename(filename, ".jsonl");
6794
+ sessionId = path16.basename(filename, ".jsonl");
6505
6795
  projectName = parts.at(-2) || "";
6506
6796
  const projectsIdx = parts.lastIndexOf("projects");
6507
- configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
6797
+ configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
6508
6798
  }
6509
6799
  return { configDir: configDir2, projectName, sessionId };
6510
6800
  }
6511
6801
  async function loadQoderModelNames(configDir2) {
6512
6802
  try {
6513
- const dynamicTextsPath = path15.join(configDir2, ".auth", "dynamic-texts.json");
6803
+ const dynamicTextsPath = path16.join(configDir2, ".auth", "dynamic-texts.json");
6514
6804
  const content = await readFile10(dynamicTextsPath, "utf8");
6515
6805
  const json = JSON.parse(content);
6516
6806
  const texts = json.texts || {};
@@ -6528,7 +6818,7 @@ async function loadQoderModelNames(configDir2) {
6528
6818
  }
6529
6819
  async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
6530
6820
  const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
6531
- const segmentsPath = path15.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
6821
+ const segmentsPath = path16.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
6532
6822
  const modelCalls = [];
6533
6823
  try {
6534
6824
  const files = await readdir7(segmentsPath);
@@ -6536,7 +6826,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
6536
6826
  if (!file.endsWith(".jsonl")) {
6537
6827
  continue;
6538
6828
  }
6539
- const content = await readFile10(path15.join(segmentsPath, file), "utf8");
6829
+ const content = await readFile10(path16.join(segmentsPath, file), "utf8");
6540
6830
  let currentTurnIsSubagent = false;
6541
6831
  for (const line of content.split("\n").filter(Boolean)) {
6542
6832
  const raw = parseJsonLine(line);
@@ -6604,7 +6894,7 @@ async function parseQoderSessionFile(filePath, options) {
6604
6894
  sessionId = stringField(raw, "sessionId") || sessionId;
6605
6895
  state.sessionId = sessionId;
6606
6896
  cwd = stringField(raw, "cwd") || cwd;
6607
- project = projectContext.project || (cwd ? path15.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
6897
+ project = projectContext.project || (cwd ? path16.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
6608
6898
  if (!ts) {
6609
6899
  continue;
6610
6900
  }
@@ -6999,28 +7289,28 @@ function qoderExtractText(value) {
6999
7289
  }
7000
7290
  async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
7001
7291
  const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
7002
- const isSubagent = filePath.includes(`${path15.sep}subagents${path15.sep}`);
7292
+ const isSubagent = filePath.includes(`${path16.sep}subagents${path16.sep}`);
7003
7293
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
7004
7294
  let cwds = [];
7005
7295
  for (const line of lines) {
7006
7296
  const raw = parseJsonLine(line);
7007
7297
  const cwd = raw ? stringField(raw, "cwd") : void 0;
7008
- if (cwd && path15.isAbsolute(cwd)) {
7298
+ if (cwd && path16.isAbsolute(cwd)) {
7009
7299
  cwds.push(cwd);
7010
7300
  }
7011
7301
  }
7012
7302
  if (isSubagent) {
7013
- if (inherited?.cwd && path15.isAbsolute(inherited.cwd)) {
7303
+ if (inherited?.cwd && path16.isAbsolute(inherited.cwd)) {
7014
7304
  cwds = [inherited.cwd];
7015
7305
  } else {
7016
- const parentSessionPath = path15.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
7306
+ const parentSessionPath = path16.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
7017
7307
  try {
7018
7308
  const parentText = await readFile10(parentSessionPath, "utf8");
7019
7309
  const parentCwds = [];
7020
7310
  for (const line of parentText.split("\n").filter(Boolean)) {
7021
7311
  const raw = parseJsonLine(line);
7022
7312
  const cwd = raw ? stringField(raw, "cwd") : void 0;
7023
- if (cwd && path15.isAbsolute(cwd)) {
7313
+ if (cwd && path16.isAbsolute(cwd)) {
7024
7314
  parentCwds.push(cwd);
7025
7315
  }
7026
7316
  }
@@ -7032,7 +7322,7 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
7032
7322
  }
7033
7323
  }
7034
7324
  const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
7035
- const project = inherited?.project || (cwds.length > 0 ? path15.basename(cwds[0]) : root ? path15.basename(root) : await qoderProjectFromFilePath(filePath, options));
7325
+ const project = inherited?.project || (cwds.length > 0 ? path16.basename(cwds[0]) : root ? path16.basename(root) : await qoderProjectFromFilePath(filePath, options));
7036
7326
  return {
7037
7327
  project,
7038
7328
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
@@ -7041,15 +7331,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
7041
7331
  async function gitRootFromCwds3(cwds) {
7042
7332
  const seen = /* @__PURE__ */ new Set();
7043
7333
  for (const cwd of cwds) {
7044
- let current = path15.resolve(cwd);
7334
+ let current = path16.resolve(cwd);
7045
7335
  while (!seen.has(current)) {
7046
7336
  seen.add(current);
7047
7337
  try {
7048
- await stat7(path15.join(current, ".git"));
7338
+ await stat8(path16.join(current, ".git"));
7049
7339
  return current;
7050
7340
  } catch {
7051
7341
  }
7052
- const parent = path15.dirname(current);
7342
+ const parent = path16.dirname(current);
7053
7343
  if (parent === current) {
7054
7344
  break;
7055
7345
  }
@@ -7060,12 +7350,12 @@ async function gitRootFromCwds3(cwds) {
7060
7350
  }
7061
7351
  function qoderProjectRootFromCwds(projectDir, cwds) {
7062
7352
  for (const cwd of cwds) {
7063
- let current = path15.resolve(cwd);
7353
+ let current = path16.resolve(cwd);
7064
7354
  while (true) {
7065
7355
  if (encodeQoderProjectPath(current) === projectDir) {
7066
7356
  return current;
7067
7357
  }
7068
- const parent = path15.dirname(current);
7358
+ const parent = path16.dirname(current);
7069
7359
  if (parent === current) {
7070
7360
  break;
7071
7361
  }
@@ -7075,10 +7365,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
7075
7365
  return void 0;
7076
7366
  }
7077
7367
  function encodeQoderProjectPath(value) {
7078
- return path15.resolve(value).split(path15.sep).join("-").replace(/_/g, "-");
7368
+ return path16.resolve(value).split(path16.sep).join("-").replace(/_/g, "-");
7079
7369
  }
7080
7370
  function rawQoderProjectPath(value) {
7081
- return path15.resolve(value).split(path15.sep).join("-");
7371
+ return path16.resolve(value).split(path16.sep).join("-");
7082
7372
  }
7083
7373
  function qoderEncodedVariants(value) {
7084
7374
  const raw = rawQoderProjectPath(value);
@@ -7094,11 +7384,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
7094
7384
  return void 0;
7095
7385
  }
7096
7386
  async function qoderProjectFromFilePath(filePath, options) {
7097
- const projectDir = path15.basename(path15.dirname(filePath));
7098
- const home = options ? path15.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
7387
+ const projectDir = path16.basename(path16.dirname(filePath));
7388
+ const home = options ? path16.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
7099
7389
  const resolved = await resolveQoderProjectPath(projectDir, home);
7100
7390
  if (resolved) {
7101
- return path15.basename(resolved);
7391
+ return path16.basename(resolved);
7102
7392
  }
7103
7393
  const suffix = qoderEncodedProjectSuffix(projectDir, home);
7104
7394
  if (suffix) {
@@ -7124,7 +7414,7 @@ async function resolveQoderProjectPath(projectDir, home) {
7124
7414
  if (!entry.isDirectory()) {
7125
7415
  continue;
7126
7416
  }
7127
- const candidate = path15.join(current, entry.name);
7417
+ const candidate = path16.join(current, entry.name);
7128
7418
  const candidateVariants = qoderEncodedVariants(candidate);
7129
7419
  if (candidateVariants.includes(projectDir)) {
7130
7420
  return candidate;
@@ -7169,9 +7459,9 @@ function hookConfig6() {
7169
7459
  function qoderConfigDir(home, env) {
7170
7460
  const override = env?.QODER_CONFIG_DIR;
7171
7461
  if (override && override.trim()) {
7172
- return path15.resolve(override);
7462
+ return path16.resolve(override);
7173
7463
  }
7174
- return path15.join(home, ".qoder");
7464
+ return path16.join(home, ".qoder");
7175
7465
  }
7176
7466
  function createQoderAdapter() {
7177
7467
  return {
@@ -7183,27 +7473,27 @@ function createQoderAdapter() {
7183
7473
  return qoderConfigDir(home, env);
7184
7474
  },
7185
7475
  installedPath(home, env) {
7186
- return path15.join(qoderConfigDir(home, env), "settings.json");
7476
+ return path16.join(qoderConfigDir(home, env), "settings.json");
7187
7477
  },
7188
7478
  async isInstalled(home, env) {
7189
7479
  return isHooksJsonInstalled(
7190
- path15.join(qoderConfigDir(home, env), "settings.json"),
7480
+ path16.join(qoderConfigDir(home, env), "settings.json"),
7191
7481
  "vibetime hook --agent qoder"
7192
7482
  );
7193
7483
  },
7194
7484
  installEntries(home, env) {
7195
7485
  return [{
7196
7486
  kind: "hooks-json",
7197
- path: path15.join(qoderConfigDir(home, env), "settings.json"),
7487
+ path: path16.join(qoderConfigDir(home, env), "settings.json"),
7198
7488
  content: hookConfig6()
7199
7489
  }];
7200
7490
  },
7201
7491
  sourcePaths(home, env) {
7202
7492
  const base = qoderConfigDir(home, env);
7203
7493
  return [
7204
- path15.join(base, "projects"),
7205
- path15.join(base, ".qoder.json"),
7206
- path15.join(home, ".qoder.json")
7494
+ path16.join(base, "projects"),
7495
+ path16.join(base, ".qoder.json"),
7496
+ path16.join(home, ".qoder.json")
7207
7497
  ];
7208
7498
  },
7209
7499
  parseSessionFile: parseQoderSessionFile
@@ -7238,21 +7528,21 @@ function normalizeId(id) {
7238
7528
  }
7239
7529
 
7240
7530
  // src/adapters/workbuddy.ts
7241
- import { readFile as readFile11, readdir as readdir8, stat as stat8 } from "node:fs/promises";
7242
- import path16 from "node:path";
7531
+ import { readFile as readFile11, readdir as readdir8, stat as stat9 } from "node:fs/promises";
7532
+ import path17 from "node:path";
7243
7533
  init_fs();
7244
7534
  function workbuddyProjectsDir(home, env) {
7245
7535
  const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
7246
7536
  if (override && override.trim()) {
7247
- return path16.resolve(override, override.endsWith("projects") ? "" : "projects");
7537
+ return path17.resolve(override, override.endsWith("projects") ? "" : "projects");
7248
7538
  }
7249
- return path16.join(home, ".workbuddy", "projects");
7539
+ return path17.join(home, ".workbuddy", "projects");
7250
7540
  }
7251
7541
  function projectFromCwd(cwd, fallback) {
7252
7542
  if (!cwd) {
7253
7543
  return fallback;
7254
7544
  }
7255
- return path16.basename(cwd) || fallback;
7545
+ return path17.basename(cwd) || fallback;
7256
7546
  }
7257
7547
  function sourceHash(filePath) {
7258
7548
  return `sha256:${createStableHash(filePath)}`;
@@ -7354,8 +7644,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
7354
7644
  }
7355
7645
  const events = [];
7356
7646
  const first = lines[0].record;
7357
- const sessionId = stringField(first, "sessionId") || path16.basename(filePath, ".jsonl");
7358
- const fallbackProject = path16.basename(path16.dirname(filePath));
7647
+ const sessionId = stringField(first, "sessionId") || path17.basename(filePath, ".jsonl");
7648
+ const fallbackProject = path17.basename(path17.dirname(filePath));
7359
7649
  const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
7360
7650
  const project = projectFromCwd(cwd, fallbackProject);
7361
7651
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
@@ -7529,12 +7819,12 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
7529
7819
  if (!project.isDirectory()) {
7530
7820
  continue;
7531
7821
  }
7532
- const projectDir = path16.join(base, project.name);
7822
+ const projectDir = path17.join(base, project.name);
7533
7823
  const entries = await readdir8(projectDir, { withFileTypes: true });
7534
7824
  for (const entry of entries) {
7535
7825
  if (entry.isFile() && entry.name.endsWith(".jsonl")) {
7536
- const filePath = path16.join(projectDir, entry.name);
7537
- const info = await stat8(filePath);
7826
+ const filePath = path17.join(projectDir, entry.name);
7827
+ const info = await stat9(filePath);
7538
7828
  files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
7539
7829
  }
7540
7830
  }
@@ -7571,26 +7861,26 @@ function createWorkbuddyAdapter() {
7571
7861
 
7572
7862
  // src/adapters/zcode.ts
7573
7863
  import { execFile } from "node:child_process";
7574
- import { readFile as readFile12, stat as stat9 } from "node:fs/promises";
7575
- import path17 from "node:path";
7864
+ import { readFile as readFile12, stat as stat10 } from "node:fs/promises";
7865
+ import path18 from "node:path";
7576
7866
  import { promisify as promisify2 } from "node:util";
7577
7867
  init_fs();
7578
7868
  var execFileAsync = promisify2(execFile);
7579
7869
  function zcodeCliDir(home, env) {
7580
7870
  const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
7581
7871
  if (override && override.trim()) {
7582
- return path17.resolve(override, override.endsWith("cli") ? "" : "cli");
7872
+ return path18.resolve(override, override.endsWith("cli") ? "" : "cli");
7583
7873
  }
7584
- return path17.join(home, ".zcode", "cli");
7874
+ return path18.join(home, ".zcode", "cli");
7585
7875
  }
7586
7876
  function zcodeDbPath(home, env) {
7587
- return path17.join(zcodeCliDir(home, env), "db", "db.sqlite");
7877
+ return path18.join(zcodeCliDir(home, env), "db", "db.sqlite");
7588
7878
  }
7589
7879
  var providerNameCache = null;
7590
7880
  async function loadProviderNames(configPath2) {
7591
7881
  let fileMtime = 0;
7592
7882
  try {
7593
- const info = await stat9(configPath2);
7883
+ const info = await stat10(configPath2);
7594
7884
  fileMtime = info.mtimeMs;
7595
7885
  } catch {
7596
7886
  return /* @__PURE__ */ new Map();
@@ -7618,7 +7908,7 @@ function sourceHash2(filePath) {
7618
7908
  return `sha256:${createStableHash(filePath)}`;
7619
7909
  }
7620
7910
  function projectFromDirectory(directory) {
7621
- return directory ? path17.basename(directory) || "zcode" : "zcode";
7911
+ return directory ? path18.basename(directory) || "zcode" : "zcode";
7622
7912
  }
7623
7913
  function isoFromMs(value) {
7624
7914
  return timestampFrom(typeof value === "number" ? value : Number(value));
@@ -7774,16 +8064,16 @@ async function parseZCodeDb(filePath, options) {
7774
8064
  if (rows.length === 0) {
7775
8065
  return [];
7776
8066
  }
7777
- let candidate = path17.resolve(filePath);
8067
+ let candidate = path18.resolve(filePath);
7778
8068
  let configPath2 = "";
7779
8069
  for (let i = 0; i < 12; i++) {
7780
- const probe = path17.join(candidate, ".zcode", "v2", "config.json");
8070
+ const probe = path18.join(candidate, ".zcode", "v2", "config.json");
7781
8071
  try {
7782
- await stat9(probe);
8072
+ await stat10(probe);
7783
8073
  configPath2 = probe;
7784
8074
  break;
7785
8075
  } catch {
7786
- const parent = path17.dirname(candidate);
8076
+ const parent = path18.dirname(candidate);
7787
8077
  if (parent === candidate) break;
7788
8078
  candidate = parent;
7789
8079
  }
@@ -7999,9 +8289,9 @@ async function parseZCodeDb(filePath, options) {
7999
8289
  }
8000
8290
  async function zcodeBackfillFiles(sourceRoot, home, env) {
8001
8291
  const candidate = sourceRoot || zcodeDbPath(home, env);
8002
- const filePath = candidate.endsWith(".sqlite") ? candidate : path17.join(candidate, "db", "db.sqlite");
8292
+ const filePath = candidate.endsWith(".sqlite") ? candidate : path18.join(candidate, "db", "db.sqlite");
8003
8293
  try {
8004
- const info = await stat9(filePath);
8294
+ const info = await stat10(filePath);
8005
8295
  return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
8006
8296
  } catch {
8007
8297
  return [];
@@ -8473,15 +8763,15 @@ function hookCommandFromGroup(group) {
8473
8763
  import { randomUUID } from "node:crypto";
8474
8764
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8475
8765
  import { homedir, hostname } from "node:os";
8476
- import path18 from "node:path";
8766
+ import path19 from "node:path";
8477
8767
  function configDir(home = homedir()) {
8478
- return path18.join(home, ".vibetime");
8768
+ return path19.join(home, ".vibetime");
8479
8769
  }
8480
8770
  function configPath(home = homedir()) {
8481
- return path18.join(configDir(home), "config.json");
8771
+ return path19.join(configDir(home), "config.json");
8482
8772
  }
8483
8773
  function machineIdPath(home = homedir()) {
8484
- return path18.join(configDir(home), "machine-id");
8774
+ return path19.join(configDir(home), "machine-id");
8485
8775
  }
8486
8776
  function readConfig(home = homedir()) {
8487
8777
  const file = configPath(home);
@@ -8528,15 +8818,15 @@ function defaultMachineName() {
8528
8818
  init_fs();
8529
8819
 
8530
8820
  // src/lib/logger.ts
8531
- import { appendFile, mkdir as mkdir4, rename, stat as stat10 } from "node:fs/promises";
8821
+ import { appendFile, mkdir as mkdir4, rename, stat as stat11 } from "node:fs/promises";
8532
8822
  import { homedir as homedir2 } from "node:os";
8533
- import path19 from "node:path";
8823
+ import path20 from "node:path";
8534
8824
  var MAX_BYTES = 1 * 1024 * 1024;
8535
8825
  function logDir(home = homedir2()) {
8536
- return path19.join(home, ".vibetime", "logs");
8826
+ return path20.join(home, ".vibetime", "logs");
8537
8827
  }
8538
8828
  function logPath(home = homedir2(), name = "cli.log") {
8539
- return path19.join(logDir(home), name);
8829
+ return path20.join(logDir(home), name);
8540
8830
  }
8541
8831
  function serializeError(error) {
8542
8832
  if (error instanceof Error) {
@@ -8546,7 +8836,7 @@ function serializeError(error) {
8546
8836
  }
8547
8837
  async function rotateIfNeeded(file) {
8548
8838
  try {
8549
- const info = await stat10(file);
8839
+ const info = await stat11(file);
8550
8840
  if (info.size > MAX_BYTES) {
8551
8841
  await rename(file, `${file}.1`).catch(() => {
8552
8842
  });
@@ -8711,8 +9001,8 @@ function buildHeaders(token, machine) {
8711
9001
  ...machine?.platform ? { "x-machine-platform": machine.platform } : {}
8712
9002
  };
8713
9003
  }
8714
- function joinUrl(base, path21) {
8715
- return new URL(path21, base.endsWith("/") ? base : `${base}/`).toString();
9004
+ function joinUrl(base, path22) {
9005
+ return new URL(path22, base.endsWith("/") ? base : `${base}/`).toString();
8716
9006
  }
8717
9007
  async function postRollupBatch(remote, rollups, options = {}) {
8718
9008
  const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
@@ -8777,7 +9067,7 @@ async function deleteMachine(remote, id) {
8777
9067
  }
8778
9068
 
8779
9069
  // src/lib/types.ts
8780
- var BACKFILL_STATE_SCHEMA_VERSION = 5;
9070
+ var BACKFILL_STATE_SCHEMA_VERSION = 6;
8781
9071
 
8782
9072
  // src/cli.ts
8783
9073
  function createRegistry() {
@@ -8802,7 +9092,7 @@ var defaultContext = {
8802
9092
  stdout: process.stdout,
8803
9093
  stderr: process.stderr,
8804
9094
  fetch: globalThis.fetch,
8805
- spawn
9095
+ spawn: spawn2
8806
9096
  };
8807
9097
  async function run(argv, context = {}) {
8808
9098
  const ctx = { ...defaultContext, ...context };
@@ -8953,7 +9243,9 @@ async function fetchLatestVersion() {
8953
9243
  headers: { Accept: "application/json" },
8954
9244
  signal: AbortSignal.timeout(1e4)
8955
9245
  });
8956
- if (!response.ok) return null;
9246
+ if (!response.ok) {
9247
+ return null;
9248
+ }
8957
9249
  const data = await response.json();
8958
9250
  return typeof data.version === "string" ? data.version : null;
8959
9251
  } catch {
@@ -8966,8 +9258,12 @@ function compareVersions(a, b) {
8966
9258
  for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
8967
9259
  const na = pa[i] ?? 0;
8968
9260
  const nb = pb[i] ?? 0;
8969
- if (na > nb) return 1;
8970
- if (na < nb) return -1;
9261
+ if (na > nb) {
9262
+ return 1;
9263
+ }
9264
+ if (na < nb) {
9265
+ return -1;
9266
+ }
8971
9267
  }
8972
9268
  return 0;
8973
9269
  }
@@ -9070,15 +9366,35 @@ async function syncLocalTriggerCommand(options, ctx, _registry) {
9070
9366
  `);
9071
9367
  return 0;
9072
9368
  }
9073
- const child = spawnSyncLocalRunner({ options, ctx, home, lockPath, statePath, triggeredAt: now });
9074
- if (typeof child.pid !== "number") {
9075
- throw new TypeError("Could not start background sync-local runner");
9369
+ const acquired = await acquireSyncLocalLock(lockPath, {
9370
+ pid: process.pid,
9371
+ startedAt: now
9372
+ });
9373
+ if (!acquired) {
9374
+ const current = await readSyncLocalLock(lockPath);
9375
+ if (options.json) {
9376
+ write(ctx.stdout, `${JSON.stringify({
9377
+ status: "already-running",
9378
+ ...current ? { pid: current.pid, startedAt: current.startedAt } : {}
9379
+ }, null, 2)}
9380
+ `);
9381
+ }
9382
+ return 0;
9383
+ }
9384
+ try {
9385
+ const child = spawnSyncLocalRunner({ options, ctx, home, lockPath, statePath, triggeredAt: now });
9386
+ if (typeof child.pid !== "number") {
9387
+ throw new TypeError("Could not start background sync-local runner");
9388
+ }
9389
+ state.lastTriggeredAt = now;
9390
+ state.pid = child.pid;
9391
+ await writeSyncLocalTriggerState(statePath, state);
9392
+ await writeSyncLocalLock(lockPath, { pid: child.pid, startedAt: now });
9393
+ return 0;
9394
+ } catch (error) {
9395
+ await clearSyncLocalLock(lockPath);
9396
+ throw error;
9076
9397
  }
9077
- state.lastTriggeredAt = now;
9078
- state.pid = child.pid;
9079
- await writeSyncLocalTriggerState(statePath, state);
9080
- await writeSyncLocalLock(lockPath, { pid: child.pid, startedAt: now });
9081
- return 0;
9082
9398
  }
9083
9399
  async function syncLocalRunnerCommand(options, ctx, _registry) {
9084
9400
  const home = resolveHome3(options, ctx);
@@ -9284,7 +9600,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
9284
9600
  const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
9285
9601
  const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
9286
9602
  return Promise.all(files.map(async (filePath) => {
9287
- const info = await stat11(filePath);
9603
+ const info = await stat12(filePath);
9288
9604
  return { path: filePath, modifiedAt: info.mtime.toISOString() };
9289
9605
  }));
9290
9606
  }
@@ -9597,13 +9913,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
9597
9913
  });
9598
9914
  }
9599
9915
  function backfillIncrementalStatePath(home) {
9600
- return path20.join(home, ".vibetime", "backfill-state.json");
9916
+ return path21.join(home, ".vibetime", "backfill-state.json");
9601
9917
  }
9602
9918
  function syncLocalTriggerStatePath(home) {
9603
- return path20.join(home, ".vibetime", "sync-local-trigger.json");
9919
+ return path21.join(home, ".vibetime", "sync-local-trigger.json");
9604
9920
  }
9605
9921
  function syncLocalTriggerLockPath(home) {
9606
- return path20.join(home, ".vibetime", "sync-local-trigger.lock");
9922
+ return path21.join(home, ".vibetime", "sync-local-trigger.lock");
9607
9923
  }
9608
9924
  function backfillRemoteKey(baseUrl) {
9609
9925
  try {
@@ -9665,7 +9981,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
9665
9981
  }
9666
9982
  async function writeBackfillIncrementalStateFile(home, file) {
9667
9983
  const statePath = backfillIncrementalStatePath(home);
9668
- await mkdir5(path20.dirname(statePath), { recursive: true });
9984
+ await mkdir5(path21.dirname(statePath), { recursive: true });
9669
9985
  await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
9670
9986
  `, "utf8");
9671
9987
  }
@@ -9714,7 +10030,7 @@ async function readSyncLocalTriggerState(statePath) {
9714
10030
  return nextState;
9715
10031
  }
9716
10032
  async function writeSyncLocalTriggerState(statePath, state) {
9717
- await mkdir5(path20.dirname(statePath), { recursive: true });
10033
+ await mkdir5(path21.dirname(statePath), { recursive: true });
9718
10034
  const tmpPath = `${statePath}.${process.pid}.${randomUUID2()}.tmp`;
9719
10035
  await writeFile4(tmpPath, `${JSON.stringify(state, null, 2)}
9720
10036
  `, "utf8");
@@ -9731,10 +10047,28 @@ async function readSyncLocalLock(lockPath) {
9731
10047
  return { pid: lock.pid, startedAt: lock.startedAt };
9732
10048
  }
9733
10049
  async function writeSyncLocalLock(lockPath, lock) {
9734
- await mkdir5(path20.dirname(lockPath), { recursive: true });
10050
+ await mkdir5(path21.dirname(lockPath), { recursive: true });
9735
10051
  await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
9736
10052
  `, "utf8");
9737
10053
  }
10054
+ async function acquireSyncLocalLock(lockPath, lock) {
10055
+ await mkdir5(path21.dirname(lockPath), { recursive: true });
10056
+ try {
10057
+ const handle = await open(lockPath, "wx");
10058
+ try {
10059
+ await handle.writeFile(`${JSON.stringify(lock, null, 2)}
10060
+ `, "utf8");
10061
+ } finally {
10062
+ await handle.close();
10063
+ }
10064
+ return true;
10065
+ } catch (error) {
10066
+ if (error.code === "EEXIST") {
10067
+ return false;
10068
+ }
10069
+ throw error;
10070
+ }
10071
+ }
9738
10072
  async function clearSyncLocalLock(lockPath) {
9739
10073
  try {
9740
10074
  await rm(lockPath, { force: true });
@@ -9798,10 +10132,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
9798
10132
  if (cliPath.endsWith(".ts")) {
9799
10133
  return ["--import", "tsx", cliPath];
9800
10134
  }
9801
- return [path20.resolve(path20.dirname(cliPath), "../bin/vibetime.mjs")];
10135
+ return [path21.resolve(path21.dirname(cliPath), "../bin/vibetime.mjs")];
9802
10136
  }
9803
10137
  function resolveHome3(options, ctx) {
9804
- return path20.resolve(stringOption(options.home) || ctx.env.HOME || os9.homedir());
10138
+ return path21.resolve(stringOption(options.home) || ctx.env.HOME || os9.homedir());
9805
10139
  }
9806
10140
  function requestedTargets(options) {
9807
10141
  const value = options.target || options.targets;