@yishiguji/tokenarena 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -226,6 +226,19 @@ function findJsonlFiles(dir) {
226
226
  }
227
227
  return results;
228
228
  }
229
+ function findJsonFiles(dir, pattern) {
230
+ const results = [];
231
+ if (!existsSync(dir)) return results;
232
+ try {
233
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
234
+ if (entry.isFile() && pattern.test(entry.name)) {
235
+ results.push(join(dir, entry.name));
236
+ }
237
+ }
238
+ } catch {
239
+ }
240
+ return results;
241
+ }
229
242
  function readFileSafe(filePath) {
230
243
  try {
231
244
  return readFileSync(filePath, "utf-8");
@@ -1318,24 +1331,263 @@ var MimocodeParser = class {
1318
1331
  };
1319
1332
  registerParser(new MimocodeParser());
1320
1333
 
1334
+ // src/parsers/mirasim.ts
1335
+ import { createHash as createHash2 } from "crypto";
1336
+ import { existsSync as existsSync8 } from "fs";
1337
+ import { homedir as homedir7, hostname as hostname3 } from "os";
1338
+ import { join as join8 } from "path";
1339
+ var TOOL_ID5 = "mirasim";
1340
+ var TOOL_NAME5 = "Mirasim";
1341
+ var DEFAULT_INSIGHTS_DIR = join8(homedir7(), ".mirasim", "insights");
1342
+ var USAGE_FILE_PATTERN = /^usage-\d{4}-\d{2}\.ndjson$/;
1343
+ var MIRASIM_OWN_AGENTS = ["gui", "pi-gui"];
1344
+ function getInsightsDirs(env = process.env) {
1345
+ const dirs = [
1346
+ env.TOKEN_ARENA_MIRASIM_DIR,
1347
+ env.MIRASIM_HOME ? join8(env.MIRASIM_HOME, "insights") : void 0,
1348
+ DEFAULT_INSIGHTS_DIR
1349
+ ].filter((value) => Boolean(value));
1350
+ return Array.from(new Set(dirs));
1351
+ }
1352
+ function toNonNegativeInteger(value) {
1353
+ const numberValue = Number(value);
1354
+ if (!Number.isFinite(numberValue) || numberValue <= 0) {
1355
+ return 0;
1356
+ }
1357
+ const rounded = Math.round(numberValue);
1358
+ return Number.isSafeInteger(rounded) ? rounded : 0;
1359
+ }
1360
+ function getString(value) {
1361
+ return typeof value === "string" && value.length > 0 ? value : null;
1362
+ }
1363
+ function normalizeAgent(value) {
1364
+ if (typeof value !== "string") {
1365
+ return null;
1366
+ }
1367
+ return value.trim().toLowerCase() || null;
1368
+ }
1369
+ function parseIsoDate(value) {
1370
+ const raw = getString(value);
1371
+ if (!raw) {
1372
+ return null;
1373
+ }
1374
+ const timestamp = new Date(raw);
1375
+ return Number.isNaN(timestamp.getTime()) ? null : timestamp;
1376
+ }
1377
+ function getPathLeaf3(value) {
1378
+ if (!value) {
1379
+ return "unknown";
1380
+ }
1381
+ const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
1382
+ const leaf = normalized.split("/").filter(Boolean).pop();
1383
+ return leaf || "unknown";
1384
+ }
1385
+ function buildSessionUsage2(entries) {
1386
+ const usageBySession = /* @__PURE__ */ new Map();
1387
+ for (const entry of entries) {
1388
+ if (!entry.sessionId || hasInvalidTokenCounts(entry)) {
1389
+ continue;
1390
+ }
1391
+ let byModel = usageBySession.get(entry.sessionId);
1392
+ if (!byModel) {
1393
+ byModel = /* @__PURE__ */ new Map();
1394
+ usageBySession.set(entry.sessionId, byModel);
1395
+ }
1396
+ const totalTokens = entry.inputTokens + entry.outputTokens + entry.reasoningTokens + entry.cachedTokens;
1397
+ const existing = byModel.get(entry.model);
1398
+ if (existing) {
1399
+ existing.inputTokens += entry.inputTokens;
1400
+ existing.outputTokens += entry.outputTokens;
1401
+ existing.reasoningTokens += entry.reasoningTokens;
1402
+ existing.cachedTokens += entry.cachedTokens;
1403
+ existing.totalTokens += totalTokens;
1404
+ continue;
1405
+ }
1406
+ byModel.set(entry.model, {
1407
+ model: entry.model,
1408
+ inputTokens: entry.inputTokens,
1409
+ outputTokens: entry.outputTokens,
1410
+ reasoningTokens: entry.reasoningTokens,
1411
+ cachedTokens: entry.cachedTokens,
1412
+ totalTokens
1413
+ });
1414
+ }
1415
+ return usageBySession;
1416
+ }
1417
+ function buildSessions(drafts, entries) {
1418
+ const usageBySession = buildSessionUsage2(entries);
1419
+ const host = hostname3().replace(/\.local$/, "");
1420
+ return Array.from(drafts.values()).map((draft) => {
1421
+ const modelUsages = Array.from(
1422
+ usageBySession.get(draft.sessionId)?.values() ?? []
1423
+ ).sort((left, right) => {
1424
+ if (right.totalTokens !== left.totalTokens) {
1425
+ return right.totalTokens - left.totalTokens;
1426
+ }
1427
+ return left.model.localeCompare(right.model);
1428
+ });
1429
+ const inputTokens = modelUsages.reduce(
1430
+ (sum, usage) => sum + usage.inputTokens,
1431
+ 0
1432
+ );
1433
+ const outputTokens = modelUsages.reduce(
1434
+ (sum, usage) => sum + usage.outputTokens,
1435
+ 0
1436
+ );
1437
+ const reasoningTokens = modelUsages.reduce(
1438
+ (sum, usage) => sum + usage.reasoningTokens,
1439
+ 0
1440
+ );
1441
+ const cachedTokens = modelUsages.reduce(
1442
+ (sum, usage) => sum + usage.cachedTokens,
1443
+ 0
1444
+ );
1445
+ const totalTokens = modelUsages.reduce(
1446
+ (sum, usage) => sum + usage.totalTokens,
1447
+ 0
1448
+ );
1449
+ const durationSeconds = Math.max(
1450
+ 0,
1451
+ Math.round(
1452
+ (draft.lastCallEndAt.getTime() - draft.firstCallAt.getTime()) / 1e3
1453
+ )
1454
+ );
1455
+ return {
1456
+ source: TOOL_ID5,
1457
+ project: draft.project,
1458
+ sessionHash: createHash2("sha256").update(draft.sessionId).digest("hex").slice(0, 16),
1459
+ hostname: host,
1460
+ firstMessageAt: draft.firstCallAt.toISOString(),
1461
+ lastMessageAt: draft.lastCallEndAt.toISOString(),
1462
+ durationSeconds,
1463
+ // Relay calls can overlap (parallel sub-agent work), so the sum of call
1464
+ // durations may exceed the session's wall-clock span.
1465
+ activeSeconds: Math.min(
1466
+ Math.round(draft.activeMs / 1e3),
1467
+ durationSeconds
1468
+ ),
1469
+ messageCount: draft.callCount,
1470
+ // Mirasim's own sub-agents are driven by the orchestrator, not by a
1471
+ // human at a prompt, so there are no user messages to attribute.
1472
+ userMessageCount: 0,
1473
+ userPromptHours: new Array(24).fill(0),
1474
+ inputTokens,
1475
+ outputTokens,
1476
+ reasoningTokens,
1477
+ cachedTokens,
1478
+ totalTokens,
1479
+ primaryModel: modelUsages[0]?.model ?? "",
1480
+ modelUsages
1481
+ };
1482
+ });
1483
+ }
1484
+ var MirasimParser = class {
1485
+ tool;
1486
+ insightsDirs;
1487
+ ownAgents;
1488
+ constructor(options = {}) {
1489
+ this.insightsDirs = options.insightsDir ? [options.insightsDir] : getInsightsDirs();
1490
+ this.ownAgents = new Set(options.ownAgents ?? MIRASIM_OWN_AGENTS);
1491
+ this.tool = {
1492
+ id: TOOL_ID5,
1493
+ name: TOOL_NAME5,
1494
+ dataDir: this.insightsDirs[0] ?? DEFAULT_INSIGHTS_DIR
1495
+ };
1496
+ }
1497
+ async parse() {
1498
+ const entries = [];
1499
+ const drafts = /* @__PURE__ */ new Map();
1500
+ const seenCallIds = /* @__PURE__ */ new Set();
1501
+ for (const insightsDir of this.insightsDirs) {
1502
+ for (const filePath of findJsonFiles(insightsDir, USAGE_FILE_PATTERN)) {
1503
+ const content = readFileSafe(filePath);
1504
+ if (!content) continue;
1505
+ for (const row of parseJsonl(content)) {
1506
+ const agent = normalizeAgent(row.agent);
1507
+ if (!agent || !this.ownAgents.has(agent)) continue;
1508
+ const timestamp = parseIsoDate(row.ts);
1509
+ if (!timestamp) continue;
1510
+ const model = getString(row.model) ?? "unknown";
1511
+ const inputTokens = toNonNegativeInteger(row.input);
1512
+ const reasoningTokens = toNonNegativeInteger(row.reasoning);
1513
+ const outputTokens = Math.max(
1514
+ 0,
1515
+ toNonNegativeInteger(row.output) - reasoningTokens
1516
+ );
1517
+ const cachedTokens = toNonNegativeInteger(row.cacheRead) + toNonNegativeInteger(row.cacheWrite);
1518
+ if (inputTokens + outputTokens + reasoningTokens + cachedTokens === 0) {
1519
+ continue;
1520
+ }
1521
+ const sessionId = getString(row.sessionId);
1522
+ const project = getPathLeaf3(getString(row.workspace));
1523
+ const callId = getString(row.id) ?? [sessionId ?? "", timestamp.toISOString(), agent, model].join("|");
1524
+ if (seenCallIds.has(callId)) continue;
1525
+ seenCallIds.add(callId);
1526
+ entries.push({
1527
+ sessionId: sessionId ?? void 0,
1528
+ source: TOOL_ID5,
1529
+ model,
1530
+ project,
1531
+ timestamp,
1532
+ inputTokens,
1533
+ outputTokens,
1534
+ reasoningTokens,
1535
+ cachedTokens
1536
+ });
1537
+ if (!sessionId) continue;
1538
+ const durationMs = toNonNegativeInteger(row.durationMs);
1539
+ const callEndAt = new Date(timestamp.getTime() + durationMs);
1540
+ const draft = drafts.get(sessionId);
1541
+ if (!draft) {
1542
+ drafts.set(sessionId, {
1543
+ sessionId,
1544
+ project,
1545
+ firstCallAt: timestamp,
1546
+ lastCallEndAt: callEndAt,
1547
+ activeMs: durationMs,
1548
+ callCount: 1
1549
+ });
1550
+ continue;
1551
+ }
1552
+ if (draft.project === "unknown" && project !== "unknown") {
1553
+ draft.project = project;
1554
+ }
1555
+ if (timestamp < draft.firstCallAt) draft.firstCallAt = timestamp;
1556
+ if (callEndAt > draft.lastCallEndAt) draft.lastCallEndAt = callEndAt;
1557
+ draft.activeMs += durationMs;
1558
+ draft.callCount += 1;
1559
+ }
1560
+ }
1561
+ }
1562
+ return {
1563
+ buckets: aggregateToBuckets(entries),
1564
+ sessions: buildSessions(drafts, entries)
1565
+ };
1566
+ }
1567
+ isInstalled() {
1568
+ return this.insightsDirs.some((dir) => existsSync8(dir));
1569
+ }
1570
+ };
1571
+ registerParser(new MirasimParser());
1572
+
1321
1573
  // src/parsers/copilot-cli.ts
1322
- import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync3 } from "fs";
1323
- import { homedir as homedir7 } from "os";
1324
- import { basename as basename3, dirname as dirname2, join as join8 } from "path";
1325
- var ROOT_DIR = join8(homedir7(), ".copilot");
1574
+ import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync3 } from "fs";
1575
+ import { homedir as homedir8 } from "os";
1576
+ import { basename as basename3, dirname as dirname2, join as join9 } from "path";
1577
+ var ROOT_DIR = join9(homedir8(), ".copilot");
1326
1578
  var TOOL3 = {
1327
1579
  id: "copilot-cli",
1328
1580
  name: "GitHub Copilot CLI",
1329
1581
  dataDir: ROOT_DIR
1330
1582
  };
1331
1583
  function collectEventFiles(dir, results, visited) {
1332
- if (!existsSync8(dir) || visited.has(dir)) {
1584
+ if (!existsSync9(dir) || visited.has(dir)) {
1333
1585
  return;
1334
1586
  }
1335
1587
  visited.add(dir);
1336
1588
  try {
1337
1589
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
1338
- const fullPath = join8(dir, entry.name);
1590
+ const fullPath = join9(dir, entry.name);
1339
1591
  if (entry.isDirectory()) {
1340
1592
  collectEventFiles(fullPath, results, visited);
1341
1593
  continue;
@@ -1439,22 +1691,22 @@ var CopilotCliParser = class {
1439
1691
  };
1440
1692
  }
1441
1693
  isInstalled() {
1442
- return existsSync8(ROOT_DIR);
1694
+ return existsSync9(ROOT_DIR);
1443
1695
  }
1444
1696
  };
1445
1697
  registerParser(new CopilotCliParser());
1446
1698
 
1447
1699
  // src/parsers/oh-my-pi.ts
1448
- import { existsSync as existsSync9 } from "fs";
1449
- import { homedir as homedir8 } from "os";
1450
- import { join as join9 } from "path";
1451
- var TOOL_ID5 = "oh-my-pi";
1452
- var TOOL_NAME5 = "omp";
1453
- var DEFAULT_SESSIONS_DIR2 = join9(homedir8(), ".omp", "agent", "sessions");
1700
+ import { existsSync as existsSync10 } from "fs";
1701
+ import { homedir as homedir9 } from "os";
1702
+ import { join as join10 } from "path";
1703
+ var TOOL_ID6 = "oh-my-pi";
1704
+ var TOOL_NAME6 = "omp";
1705
+ var DEFAULT_SESSIONS_DIR2 = join10(homedir9(), ".omp", "agent", "sessions");
1454
1706
  function createToolDefinition4(dataDir) {
1455
1707
  return {
1456
- id: TOOL_ID5,
1457
- name: TOOL_NAME5,
1708
+ id: TOOL_ID6,
1709
+ name: TOOL_NAME6,
1458
1710
  dataDir
1459
1711
  };
1460
1712
  }
@@ -1462,7 +1714,7 @@ function toSafeNumber5(value) {
1462
1714
  const numberValue = Number(value);
1463
1715
  return Number.isFinite(numberValue) ? numberValue : 0;
1464
1716
  }
1465
- function getPathLeaf3(value) {
1717
+ function getPathLeaf4(value) {
1466
1718
  const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
1467
1719
  const leaf = normalized.split("/").filter(Boolean).pop();
1468
1720
  return leaf || "unknown";
@@ -1481,7 +1733,7 @@ function getUsageNumber2(usage, ...keys) {
1481
1733
  return 0;
1482
1734
  }
1483
1735
  function extractOhMyPiProjectFromCwd(cwd) {
1484
- return getPathLeaf3(cwd);
1736
+ return getPathLeaf4(cwd);
1485
1737
  }
1486
1738
  function extractOhMyPiProjectFromDir(filePath, sessionsDir = DEFAULT_SESSIONS_DIR2) {
1487
1739
  const normalizedFilePath = normalizeForPrefix2(filePath);
@@ -1498,7 +1750,7 @@ function extractOhMyPiProjectFromDir(filePath, sessionsDir = DEFAULT_SESSIONS_DI
1498
1750
  try {
1499
1751
  const decoded = decodeURIComponent(firstSegment);
1500
1752
  if (decoded.includes("/") || decoded.includes("\\")) {
1501
- return getPathLeaf3(decoded);
1753
+ return getPathLeaf4(decoded);
1502
1754
  }
1503
1755
  } catch {
1504
1756
  }
@@ -1548,7 +1800,7 @@ var OhMyPiParser = class {
1548
1800
  if (message.role === "user" || message.role === "assistant") {
1549
1801
  sessionEvents.push({
1550
1802
  sessionId,
1551
- source: TOOL_ID5,
1803
+ source: TOOL_ID6,
1552
1804
  project,
1553
1805
  timestamp,
1554
1806
  role: message.role
@@ -1580,7 +1832,7 @@ var OhMyPiParser = class {
1580
1832
  }
1581
1833
  entries.push({
1582
1834
  sessionId,
1583
- source: TOOL_ID5,
1835
+ source: TOOL_ID6,
1584
1836
  model: message.model || "unknown",
1585
1837
  project,
1586
1838
  timestamp,
@@ -1597,17 +1849,17 @@ var OhMyPiParser = class {
1597
1849
  };
1598
1850
  }
1599
1851
  isInstalled() {
1600
- return existsSync9(this.sessionsDir);
1852
+ return existsSync10(this.sessionsDir);
1601
1853
  }
1602
1854
  };
1603
1855
  registerParser(new OhMyPiParser());
1604
1856
 
1605
1857
  // src/parsers/opencode.ts
1606
1858
  import { execFileSync as execFileSync2 } from "child_process";
1607
- import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync4 } from "fs";
1608
- import { homedir as homedir9 } from "os";
1609
- import { basename as basename4, join as join10 } from "path";
1610
- var DEFAULT_DATA_DIR2 = join10(homedir9(), ".local", "share", "opencode");
1859
+ import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync4 } from "fs";
1860
+ import { homedir as homedir10 } from "os";
1861
+ import { basename as basename4, join as join11 } from "path";
1862
+ var DEFAULT_DATA_DIR2 = join11(homedir10(), ".local", "share", "opencode");
1611
1863
  var TOOL4 = {
1612
1864
  id: "opencode",
1613
1865
  name: "OpenCode",
@@ -1616,10 +1868,10 @@ var TOOL4 = {
1616
1868
  function getOpenCodeDataDirs(env = process.env) {
1617
1869
  const dirs = [
1618
1870
  env.TOKEN_ARENA_OPENCODE_DIR,
1619
- env.XDG_DATA_HOME ? join10(env.XDG_DATA_HOME, "opencode") : void 0,
1871
+ env.XDG_DATA_HOME ? join11(env.XDG_DATA_HOME, "opencode") : void 0,
1620
1872
  DEFAULT_DATA_DIR2,
1621
- env.LOCALAPPDATA ? join10(env.LOCALAPPDATA, "opencode") : void 0,
1622
- env.APPDATA ? join10(env.APPDATA, "opencode") : void 0
1873
+ env.LOCALAPPDATA ? join11(env.LOCALAPPDATA, "opencode") : void 0,
1874
+ env.APPDATA ? join11(env.APPDATA, "opencode") : void 0
1623
1875
  ].filter((value) => Boolean(value));
1624
1876
  return Array.from(new Set(dirs));
1625
1877
  }
@@ -1713,12 +1965,12 @@ var OpenCodeParser = class {
1713
1965
  return { buckets, sessions };
1714
1966
  }
1715
1967
  isInstalled() {
1716
- return this.resolveRoots().some((dir) => existsSync10(dir));
1968
+ return this.resolveRoots().some((dir) => existsSync11(dir));
1717
1969
  }
1718
1970
  async parseRoot(rootDir) {
1719
- const dbPath = join10(rootDir, "opencode.db");
1720
- const messagesDir = join10(rootDir, "storage", "message");
1721
- if (existsSync10(dbPath)) {
1971
+ const dbPath = join11(rootDir, "opencode.db");
1972
+ const messagesDir = join11(rootDir, "storage", "message");
1973
+ if (existsSync11(dbPath)) {
1722
1974
  try {
1723
1975
  return await this.parseFromSqlite(dbPath);
1724
1976
  } catch (err) {
@@ -1785,7 +2037,7 @@ var OpenCodeParser = class {
1785
2037
  };
1786
2038
  }
1787
2039
  parseFromJson(messagesDir) {
1788
- if (!existsSync10(messagesDir)) return { buckets: [], sessions: [] };
2040
+ if (!existsSync11(messagesDir)) return { buckets: [], sessions: [] };
1789
2041
  const entries = [];
1790
2042
  const sessionEvents = [];
1791
2043
  let sessionDirs;
@@ -1797,7 +2049,7 @@ var OpenCodeParser = class {
1797
2049
  return { buckets: [], sessions: [] };
1798
2050
  }
1799
2051
  for (const sessionDir of sessionDirs) {
1800
- const sessionPath = join10(messagesDir, sessionDir.name);
2052
+ const sessionPath = join11(messagesDir, sessionDir.name);
1801
2053
  let messageFiles;
1802
2054
  try {
1803
2055
  messageFiles = readdirSync4(sessionPath).filter(
@@ -1807,7 +2059,7 @@ var OpenCodeParser = class {
1807
2059
  continue;
1808
2060
  }
1809
2061
  for (const file of messageFiles) {
1810
- const filePath = join10(sessionPath, file);
2062
+ const filePath = join11(sessionPath, file);
1811
2063
  let data;
1812
2064
  try {
1813
2065
  data = JSON.parse(readFileSync4(filePath, "utf-8"));
@@ -1853,16 +2105,16 @@ var OpenCodeParser = class {
1853
2105
  registerParser(new OpenCodeParser());
1854
2106
 
1855
2107
  // src/parsers/openclaw.ts
1856
- import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync5 } from "fs";
1857
- import { homedir as homedir10 } from "os";
1858
- import { join as join11 } from "path";
1859
- var TOOL_ID6 = "openclaw";
1860
- var TOOL_NAME6 = "OpenClaw";
1861
- var DEFAULT_DATA_DIR3 = join11(homedir10(), ".openclaw");
2108
+ import { existsSync as existsSync12, readdirSync as readdirSync5, readFileSync as readFileSync5 } from "fs";
2109
+ import { homedir as homedir11 } from "os";
2110
+ import { join as join12 } from "path";
2111
+ var TOOL_ID7 = "openclaw";
2112
+ var TOOL_NAME7 = "OpenClaw";
2113
+ var DEFAULT_DATA_DIR3 = join12(homedir11(), ".openclaw");
1862
2114
  var LEGACY_ROOT_NAMES = [".clawdbot", ".moltbot", ".moldbot"];
1863
2115
  var TOOL5 = {
1864
- id: TOOL_ID6,
1865
- name: TOOL_NAME6,
2116
+ id: TOOL_ID7,
2117
+ name: TOOL_NAME7,
1866
2118
  dataDir: DEFAULT_DATA_DIR3
1867
2119
  };
1868
2120
  function getTokens(usage, ...keys) {
@@ -1872,16 +2124,16 @@ function getTokens(usage, ...keys) {
1872
2124
  }
1873
2125
  return 0;
1874
2126
  }
1875
- function getOpenClawRoots(homeDir = homedir10()) {
1876
- const roots = [join11(homeDir, ".openclaw")];
2127
+ function getOpenClawRoots(homeDir = homedir11()) {
2128
+ const roots = [join12(homeDir, ".openclaw")];
1877
2129
  try {
1878
2130
  const profileRoots = readdirSync5(homeDir, { withFileTypes: true }).filter(
1879
2131
  (entry) => entry.isDirectory() && /^\.openclaw-.+/.test(entry.name)
1880
- ).map((entry) => join11(homeDir, entry.name)).sort((left, right) => left.localeCompare(right));
2132
+ ).map((entry) => join12(homeDir, entry.name)).sort((left, right) => left.localeCompare(right));
1881
2133
  roots.push(...profileRoots);
1882
2134
  } catch {
1883
2135
  }
1884
- roots.push(...LEGACY_ROOT_NAMES.map((name) => join11(homeDir, name)));
2136
+ roots.push(...LEGACY_ROOT_NAMES.map((name) => join12(homeDir, name)));
1885
2137
  return Array.from(new Set(roots));
1886
2138
  }
1887
2139
  var OpenClawParser = class {
@@ -1894,8 +2146,8 @@ var OpenClawParser = class {
1894
2146
  const entries = [];
1895
2147
  const sessionEvents = [];
1896
2148
  for (const root of this.resolveRoots()) {
1897
- const agentsDir = join11(root, "agents");
1898
- if (!existsSync11(agentsDir)) continue;
2149
+ const agentsDir = join12(root, "agents");
2150
+ if (!existsSync12(agentsDir)) continue;
1899
2151
  let agentDirs;
1900
2152
  try {
1901
2153
  agentDirs = readdirSync5(agentsDir, { withFileTypes: true }).filter(
@@ -1906,8 +2158,8 @@ var OpenClawParser = class {
1906
2158
  }
1907
2159
  for (const agentDir of agentDirs) {
1908
2160
  const project = agentDir.name;
1909
- const sessionsDir = join11(agentsDir, agentDir.name, "sessions");
1910
- if (!existsSync11(sessionsDir)) continue;
2161
+ const sessionsDir = join12(agentsDir, agentDir.name, "sessions");
2162
+ if (!existsSync12(sessionsDir)) continue;
1911
2163
  let files;
1912
2164
  try {
1913
2165
  files = readdirSync5(sessionsDir).filter((f) => f.endsWith(".jsonl"));
@@ -1915,7 +2167,7 @@ var OpenClawParser = class {
1915
2167
  continue;
1916
2168
  }
1917
2169
  for (const file of files) {
1918
- const filePath = join11(sessionsDir, file);
2170
+ const filePath = join12(sessionsDir, file);
1919
2171
  let content;
1920
2172
  try {
1921
2173
  content = readFileSync5(filePath, "utf-8");
@@ -1938,7 +2190,7 @@ var OpenClawParser = class {
1938
2190
  if (msg.role !== "user" && msg.role !== "assistant") continue;
1939
2191
  sessionEvents.push({
1940
2192
  sessionId: filePath,
1941
- source: TOOL_ID6,
2193
+ source: TOOL_ID7,
1942
2194
  project,
1943
2195
  timestamp: ts,
1944
2196
  role: msg.role === "user" ? "user" : "assistant"
@@ -1948,7 +2200,7 @@ var OpenClawParser = class {
1948
2200
  if (!usage) continue;
1949
2201
  entries.push({
1950
2202
  sessionId: filePath,
1951
- source: TOOL_ID6,
2203
+ source: TOOL_ID7,
1952
2204
  model: msg.model || obj.model || "unknown",
1953
2205
  project,
1954
2206
  timestamp: ts,
@@ -1988,22 +2240,22 @@ var OpenClawParser = class {
1988
2240
  };
1989
2241
  }
1990
2242
  isInstalled() {
1991
- return this.resolveRoots().some((root) => existsSync11(join11(root, "agents")));
2243
+ return this.resolveRoots().some((root) => existsSync12(join12(root, "agents")));
1992
2244
  }
1993
2245
  };
1994
2246
  registerParser(new OpenClawParser());
1995
2247
 
1996
2248
  // src/parsers/qwen-code.ts
1997
- import { existsSync as existsSync12, readdirSync as readdirSync6 } from "fs";
1998
- import { homedir as homedir11 } from "os";
1999
- import { join as join12 } from "path";
2000
- var TOOL_ID7 = "qwen-code";
2001
- var TOOL_NAME7 = "Qwen Code";
2002
- var DEFAULT_DATA_DIR4 = join12(homedir11(), ".qwen", "tmp");
2249
+ import { existsSync as existsSync13, readdirSync as readdirSync6 } from "fs";
2250
+ import { homedir as homedir12 } from "os";
2251
+ import { join as join13 } from "path";
2252
+ var TOOL_ID8 = "qwen-code";
2253
+ var TOOL_NAME8 = "Qwen Code";
2254
+ var DEFAULT_DATA_DIR4 = join13(homedir12(), ".qwen", "tmp");
2003
2255
  function createToolDefinition5(dataDir) {
2004
2256
  return {
2005
- id: TOOL_ID7,
2006
- name: TOOL_NAME7,
2257
+ id: TOOL_ID8,
2258
+ name: TOOL_NAME8,
2007
2259
  dataDir
2008
2260
  };
2009
2261
  }
@@ -2011,7 +2263,7 @@ function toSafeNumber6(value) {
2011
2263
  const numberValue = Number(value);
2012
2264
  return Number.isFinite(numberValue) ? numberValue : 0;
2013
2265
  }
2014
- function getPathLeaf4(value) {
2266
+ function getPathLeaf5(value) {
2015
2267
  const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
2016
2268
  const leaf = normalized.split("/").filter(Boolean).pop();
2017
2269
  return leaf || "unknown";
@@ -2021,16 +2273,16 @@ function normalizeForPrefix3(value) {
2021
2273
  }
2022
2274
  function findSessionFiles2(baseDir) {
2023
2275
  const results = [];
2024
- if (!existsSync12(baseDir)) return results;
2276
+ if (!existsSync13(baseDir)) return results;
2025
2277
  try {
2026
2278
  for (const entry of readdirSync6(baseDir, { withFileTypes: true })) {
2027
2279
  if (!entry.isDirectory()) continue;
2028
- const chatsDir = join12(baseDir, entry.name, "chats");
2029
- if (!existsSync12(chatsDir)) continue;
2280
+ const chatsDir = join13(baseDir, entry.name, "chats");
2281
+ if (!existsSync13(chatsDir)) continue;
2030
2282
  try {
2031
2283
  for (const file of readdirSync6(chatsDir)) {
2032
2284
  if (file.endsWith(".jsonl")) {
2033
- results.push(join12(chatsDir, file));
2285
+ results.push(join13(chatsDir, file));
2034
2286
  }
2035
2287
  }
2036
2288
  } catch {
@@ -2043,7 +2295,7 @@ function findSessionFiles2(baseDir) {
2043
2295
  }
2044
2296
  function resolveQwenProject(cwd, filePath, dataDir = DEFAULT_DATA_DIR4) {
2045
2297
  if (cwd) {
2046
- return getPathLeaf4(cwd);
2298
+ return getPathLeaf5(cwd);
2047
2299
  }
2048
2300
  const normalizedFilePath = normalizeForPrefix3(filePath);
2049
2301
  const normalizedDataDir = normalizeForPrefix3(dataDir);
@@ -2085,7 +2337,7 @@ var QwenCodeParser = class {
2085
2337
  if (obj.type === "user" || obj.type === "assistant") {
2086
2338
  sessionEvents.push({
2087
2339
  sessionId,
2088
- source: TOOL_ID7,
2340
+ source: TOOL_ID8,
2089
2341
  project,
2090
2342
  timestamp,
2091
2343
  role: obj.type
@@ -2107,7 +2359,7 @@ var QwenCodeParser = class {
2107
2359
  }
2108
2360
  entries.push({
2109
2361
  sessionId,
2110
- source: TOOL_ID7,
2362
+ source: TOOL_ID8,
2111
2363
  model: obj.model || "unknown",
2112
2364
  project,
2113
2365
  timestamp,
@@ -2126,19 +2378,19 @@ var QwenCodeParser = class {
2126
2378
  };
2127
2379
  }
2128
2380
  isInstalled() {
2129
- return existsSync12(this.dataDir);
2381
+ return existsSync13(this.dataDir);
2130
2382
  }
2131
2383
  };
2132
2384
  registerParser(new QwenCodeParser());
2133
2385
 
2134
2386
  // src/parsers/kimi-code.ts
2135
- import { existsSync as existsSync13, readdirSync as readdirSync7 } from "fs";
2136
- import { homedir as homedir12 } from "os";
2137
- import { join as join13 } from "path";
2138
- var TOOL_ID8 = "kimi-code";
2139
- var TOOL_NAME8 = "Kimi Code";
2140
- var DEFAULT_SESSIONS_DIR3 = join13(homedir12(), ".kimi-code", "sessions");
2141
- var DEFAULT_CONFIG_PATH = join13(homedir12(), ".kimi-code", "workspaces.json");
2387
+ import { existsSync as existsSync14, readdirSync as readdirSync7 } from "fs";
2388
+ import { homedir as homedir13 } from "os";
2389
+ import { join as join14 } from "path";
2390
+ var TOOL_ID9 = "kimi-code";
2391
+ var TOOL_NAME9 = "Kimi Code";
2392
+ var DEFAULT_SESSIONS_DIR3 = join14(homedir13(), ".kimi-code", "sessions");
2393
+ var DEFAULT_CONFIG_PATH = join14(homedir13(), ".kimi-code", "workspaces.json");
2142
2394
  var USER_EVENT_TYPES = /* @__PURE__ */ new Set([
2143
2395
  "UserMessage",
2144
2396
  "user_message",
@@ -2154,8 +2406,8 @@ var ASSISTANT_EVENT_TYPES = /* @__PURE__ */ new Set([
2154
2406
  ]);
2155
2407
  function createToolDefinition6(dataDir) {
2156
2408
  return {
2157
- id: TOOL_ID8,
2158
- name: TOOL_NAME8,
2409
+ id: TOOL_ID9,
2410
+ name: TOOL_NAME9,
2159
2411
  dataDir
2160
2412
  };
2161
2413
  }
@@ -2163,36 +2415,36 @@ function toSafeNumber7(value) {
2163
2415
  const numberValue = Number(value);
2164
2416
  return Number.isFinite(numberValue) ? numberValue : 0;
2165
2417
  }
2166
- function getPathLeaf5(value) {
2418
+ function getPathLeaf6(value) {
2167
2419
  const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
2168
2420
  const leaf = normalized.split("/").filter(Boolean).pop();
2169
2421
  return leaf || "unknown";
2170
2422
  }
2171
2423
  function findWireFiles(baseDir) {
2172
2424
  const results = [];
2173
- if (!existsSync13(baseDir)) return results;
2425
+ if (!existsSync14(baseDir)) return results;
2174
2426
  try {
2175
2427
  for (const workDir of readdirSync7(baseDir, { withFileTypes: true })) {
2176
2428
  if (!workDir.isDirectory()) continue;
2177
- const workDirPath = join13(baseDir, workDir.name);
2429
+ const workDirPath = join14(baseDir, workDir.name);
2178
2430
  try {
2179
2431
  for (const session of readdirSync7(workDirPath, {
2180
2432
  withFileTypes: true
2181
2433
  })) {
2182
2434
  if (!session.isDirectory()) continue;
2183
- const newWireFile = join13(
2435
+ const newWireFile = join14(
2184
2436
  workDirPath,
2185
2437
  session.name,
2186
2438
  "agents",
2187
2439
  "main",
2188
2440
  "wire.jsonl"
2189
2441
  );
2190
- if (existsSync13(newWireFile)) {
2442
+ if (existsSync14(newWireFile)) {
2191
2443
  results.push({ filePath: newWireFile, workDirHash: workDir.name });
2192
2444
  continue;
2193
2445
  }
2194
- const legacyWireFile = join13(workDirPath, session.name, "wire.jsonl");
2195
- if (existsSync13(legacyWireFile)) {
2446
+ const legacyWireFile = join14(workDirPath, session.name, "wire.jsonl");
2447
+ if (existsSync14(legacyWireFile)) {
2196
2448
  results.push({
2197
2449
  filePath: legacyWireFile,
2198
2450
  workDirHash: workDir.name
@@ -2242,7 +2494,7 @@ function loadProjectMap(configPath) {
2242
2494
  pathValue = info.root || info.path || info.dir || void 0;
2243
2495
  }
2244
2496
  if (!pathValue) continue;
2245
- const name = typeof info === "object" && info.name ? info.name : getPathLeaf5(pathValue);
2497
+ const name = typeof info === "object" && info.name ? info.name : getPathLeaf6(pathValue);
2246
2498
  projectMap.set(hash, name);
2247
2499
  }
2248
2500
  } catch {
@@ -2300,14 +2552,14 @@ var KimiCodeParser = class {
2300
2552
  }
2301
2553
  sessionEvents.push({
2302
2554
  sessionId,
2303
- source: TOOL_ID8,
2555
+ source: TOOL_ID9,
2304
2556
  project,
2305
2557
  timestamp: timestamp2,
2306
2558
  role: "assistant"
2307
2559
  });
2308
2560
  entries.push({
2309
2561
  sessionId,
2310
- source: TOOL_ID8,
2562
+ source: TOOL_ID9,
2311
2563
  model: obj.model || currentModel,
2312
2564
  project,
2313
2565
  timestamp: timestamp2,
@@ -2334,7 +2586,7 @@ var KimiCodeParser = class {
2334
2586
  if (role && timestamp) {
2335
2587
  sessionEvents.push({
2336
2588
  sessionId,
2337
- source: TOOL_ID8,
2589
+ source: TOOL_ID9,
2338
2590
  project,
2339
2591
  timestamp,
2340
2592
  role
@@ -2357,7 +2609,7 @@ var KimiCodeParser = class {
2357
2609
  if (!role) {
2358
2610
  sessionEvents.push({
2359
2611
  sessionId,
2360
- source: TOOL_ID8,
2612
+ source: TOOL_ID9,
2361
2613
  project,
2362
2614
  timestamp,
2363
2615
  role: "assistant"
@@ -2365,7 +2617,7 @@ var KimiCodeParser = class {
2365
2617
  }
2366
2618
  entries.push({
2367
2619
  sessionId,
2368
- source: TOOL_ID8,
2620
+ source: TOOL_ID9,
2369
2621
  model: currentModel,
2370
2622
  project,
2371
2623
  timestamp,
@@ -2382,23 +2634,23 @@ var KimiCodeParser = class {
2382
2634
  };
2383
2635
  }
2384
2636
  isInstalled() {
2385
- return existsSync13(this.sessionsDir);
2637
+ return existsSync14(this.sessionsDir);
2386
2638
  }
2387
2639
  };
2388
2640
  registerParser(new KimiCodeParser());
2389
2641
 
2390
2642
  // src/parsers/letcode.ts
2391
- import { existsSync as existsSync14 } from "fs";
2392
- import { homedir as homedir13 } from "os";
2393
- import { basename as basename5, join as join14 } from "path";
2394
- var TOOL_ID9 = "letcode";
2395
- var TOOL_NAME9 = "LetCode";
2396
- var DEFAULT_CONFIG_DIR = join14(homedir13(), ".config", "letcode");
2397
- var DEFAULT_SESSIONS_DIR4 = join14(DEFAULT_CONFIG_DIR, "sessions");
2643
+ import { existsSync as existsSync15 } from "fs";
2644
+ import { homedir as homedir14 } from "os";
2645
+ import { basename as basename5, join as join15 } from "path";
2646
+ var TOOL_ID10 = "letcode";
2647
+ var TOOL_NAME10 = "LetCode";
2648
+ var DEFAULT_CONFIG_DIR = join15(homedir14(), ".config", "letcode");
2649
+ var DEFAULT_SESSIONS_DIR4 = join15(DEFAULT_CONFIG_DIR, "sessions");
2398
2650
  function getLetcodeSessionsDirs(env = process.env) {
2399
2651
  const dirs = [
2400
2652
  env.TOKEN_ARENA_LETCODE_DIR,
2401
- env.XDG_CONFIG_HOME ? join14(env.XDG_CONFIG_HOME, "letcode", "sessions") : void 0,
2653
+ env.XDG_CONFIG_HOME ? join15(env.XDG_CONFIG_HOME, "letcode", "sessions") : void 0,
2402
2654
  DEFAULT_SESSIONS_DIR4
2403
2655
  ].filter((value) => Boolean(value));
2404
2656
  return Array.from(new Set(dirs));
@@ -2452,8 +2704,8 @@ var LetcodeParser = class {
2452
2704
  constructor(sessionsDir) {
2453
2705
  this.sessionsDirs = sessionsDir ? [sessionsDir] : getLetcodeSessionsDirs();
2454
2706
  this.tool = {
2455
- id: TOOL_ID9,
2456
- name: TOOL_NAME9,
2707
+ id: TOOL_ID10,
2708
+ name: TOOL_NAME10,
2457
2709
  dataDir: this.sessionsDirs[0] ?? DEFAULT_SESSIONS_DIR4
2458
2710
  };
2459
2711
  }
@@ -2476,7 +2728,7 @@ var LetcodeParser = class {
2476
2728
  if (role) {
2477
2729
  sessionEvents.push({
2478
2730
  sessionId,
2479
- source: TOOL_ID9,
2731
+ source: TOOL_ID10,
2480
2732
  project: "unknown",
2481
2733
  timestamp,
2482
2734
  role
@@ -2510,7 +2762,7 @@ var LetcodeParser = class {
2510
2762
  seenEntryKeys.add(entryKey);
2511
2763
  entries.push({
2512
2764
  sessionId,
2513
- source: TOOL_ID9,
2765
+ source: TOOL_ID10,
2514
2766
  model,
2515
2767
  project: "unknown",
2516
2768
  timestamp,
@@ -2528,31 +2780,31 @@ var LetcodeParser = class {
2528
2780
  };
2529
2781
  }
2530
2782
  isInstalled() {
2531
- return this.sessionsDirs.some((dir) => existsSync14(dir));
2783
+ return this.sessionsDirs.some((dir) => existsSync15(dir));
2532
2784
  }
2533
2785
  };
2534
2786
  registerParser(new LetcodeParser());
2535
2787
 
2536
2788
  // src/parsers/droid.ts
2537
- import { existsSync as existsSync15, readdirSync as readdirSync8 } from "fs";
2538
- import { homedir as homedir14 } from "os";
2539
- import { basename as basename6, dirname as dirname3, join as join15 } from "path";
2540
- var TOOL_ID10 = "droid";
2541
- var TOOL_NAME10 = "Droid";
2542
- var DEFAULT_DATA_DIR5 = join15(homedir14(), ".factory", "sessions");
2789
+ import { existsSync as existsSync16, readdirSync as readdirSync8 } from "fs";
2790
+ import { homedir as homedir15 } from "os";
2791
+ import { basename as basename6, dirname as dirname3, join as join16 } from "path";
2792
+ var TOOL_ID11 = "droid";
2793
+ var TOOL_NAME11 = "Droid";
2794
+ var DEFAULT_DATA_DIR5 = join16(homedir15(), ".factory", "sessions");
2543
2795
  function createToolDefinition7(dataDir) {
2544
2796
  return {
2545
- id: TOOL_ID10,
2546
- name: TOOL_NAME10,
2797
+ id: TOOL_ID11,
2798
+ name: TOOL_NAME11,
2547
2799
  dataDir
2548
2800
  };
2549
2801
  }
2550
2802
  function findSessionFiles3(dir) {
2551
2803
  const results = [];
2552
- if (!existsSync15(dir)) return results;
2804
+ if (!existsSync16(dir)) return results;
2553
2805
  try {
2554
2806
  for (const entry of readdirSync8(dir, { withFileTypes: true })) {
2555
- const fullPath = join15(dir, entry.name);
2807
+ const fullPath = join16(dir, entry.name);
2556
2808
  if (entry.isDirectory()) {
2557
2809
  results.push(...findSessionFiles3(fullPath));
2558
2810
  } else if (entry.isFile() && entry.name.endsWith(".jsonl") && !entry.name.endsWith(".settings.json")) {
@@ -2609,13 +2861,13 @@ var DroidParser = class {
2609
2861
  }
2610
2862
  sessionEvents.push({
2611
2863
  sessionId,
2612
- source: TOOL_ID10,
2864
+ source: TOOL_ID11,
2613
2865
  project,
2614
2866
  timestamp,
2615
2867
  role
2616
2868
  });
2617
2869
  }
2618
- const settingsPath = join15(
2870
+ const settingsPath = join16(
2619
2871
  dirname3(filePath),
2620
2872
  `${basename6(filePath, ".jsonl")}.settings.json`
2621
2873
  );
@@ -2644,7 +2896,7 @@ var DroidParser = class {
2644
2896
  }
2645
2897
  entries.push({
2646
2898
  sessionId,
2647
- source: TOOL_ID10,
2899
+ source: TOOL_ID11,
2648
2900
  model: settings.model || "unknown",
2649
2901
  project,
2650
2902
  timestamp: firstMessageTimestamp,
@@ -2660,22 +2912,22 @@ var DroidParser = class {
2660
2912
  };
2661
2913
  }
2662
2914
  isInstalled() {
2663
- return existsSync15(this.dataDir);
2915
+ return existsSync16(this.dataDir);
2664
2916
  }
2665
2917
  };
2666
2918
  registerParser(new DroidParser());
2667
2919
 
2668
2920
  // src/parsers/pi-coding-agent.ts
2669
- import { existsSync as existsSync16 } from "fs";
2670
- import { homedir as homedir15 } from "os";
2671
- import { join as join16 } from "path";
2672
- var TOOL_ID11 = "pi-coding-agent";
2673
- var TOOL_NAME11 = "pi";
2674
- var DEFAULT_SESSIONS_DIR5 = join16(homedir15(), ".pi", "agent", "sessions");
2921
+ import { existsSync as existsSync17 } from "fs";
2922
+ import { homedir as homedir16 } from "os";
2923
+ import { join as join17 } from "path";
2924
+ var TOOL_ID12 = "pi-coding-agent";
2925
+ var TOOL_NAME12 = "pi";
2926
+ var DEFAULT_SESSIONS_DIR5 = join17(homedir16(), ".pi", "agent", "sessions");
2675
2927
  function createToolDefinition8(dataDir) {
2676
2928
  return {
2677
- id: TOOL_ID11,
2678
- name: TOOL_NAME11,
2929
+ id: TOOL_ID12,
2930
+ name: TOOL_NAME12,
2679
2931
  dataDir
2680
2932
  };
2681
2933
  }
@@ -2683,7 +2935,7 @@ function toSafeNumber9(value) {
2683
2935
  const numberValue = Number(value);
2684
2936
  return Number.isFinite(numberValue) ? numberValue : 0;
2685
2937
  }
2686
- function getPathLeaf6(value) {
2938
+ function getPathLeaf7(value) {
2687
2939
  const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
2688
2940
  const leaf = normalized.split("/").filter(Boolean).pop();
2689
2941
  return leaf || "unknown";
@@ -2702,7 +2954,7 @@ function getUsageNumber3(usage, ...keys) {
2702
2954
  return 0;
2703
2955
  }
2704
2956
  function extractPiProjectFromCwd(cwd) {
2705
- return getPathLeaf6(cwd);
2957
+ return getPathLeaf7(cwd);
2706
2958
  }
2707
2959
  function extractPiProjectFromDir(filePath, sessionsDir = DEFAULT_SESSIONS_DIR5) {
2708
2960
  const normalizedFilePath = normalizeForPrefix4(filePath);
@@ -2719,7 +2971,7 @@ function extractPiProjectFromDir(filePath, sessionsDir = DEFAULT_SESSIONS_DIR5)
2719
2971
  try {
2720
2972
  const decoded = decodeURIComponent(firstSegment);
2721
2973
  if (decoded.includes("/") || decoded.includes("\\")) {
2722
- return getPathLeaf6(decoded);
2974
+ return getPathLeaf7(decoded);
2723
2975
  }
2724
2976
  } catch {
2725
2977
  }
@@ -2769,7 +3021,7 @@ var PiCodingAgentParser = class {
2769
3021
  if (message.role === "user" || message.role === "assistant") {
2770
3022
  sessionEvents.push({
2771
3023
  sessionId,
2772
- source: TOOL_ID11,
3024
+ source: TOOL_ID12,
2773
3025
  project,
2774
3026
  timestamp,
2775
3027
  role: message.role
@@ -2801,7 +3053,7 @@ var PiCodingAgentParser = class {
2801
3053
  }
2802
3054
  entries.push({
2803
3055
  sessionId,
2804
- source: TOOL_ID11,
3056
+ source: TOOL_ID12,
2805
3057
  model: message.model || "unknown",
2806
3058
  project,
2807
3059
  timestamp,
@@ -2818,23 +3070,23 @@ var PiCodingAgentParser = class {
2818
3070
  };
2819
3071
  }
2820
3072
  isInstalled() {
2821
- return existsSync16(this.sessionsDir);
3073
+ return existsSync17(this.sessionsDir);
2822
3074
  }
2823
3075
  };
2824
3076
  registerParser(new PiCodingAgentParser());
2825
3077
 
2826
3078
  // src/parsers/qwenpaw.ts
2827
- import { existsSync as existsSync17, readdirSync as readdirSync9 } from "fs";
2828
- import { homedir as homedir16, hostname as hostname3 } from "os";
2829
- import { join as join17 } from "path";
2830
- var TOOL_ID12 = "qwenpaw";
2831
- var TOOL_NAME12 = "QwenPaw";
2832
- var DEFAULT_USAGE_PATH = join17(homedir16(), ".qwenpaw", "token_usage.json");
2833
- var DEFAULT_WORKSPACE_PATH = join17(homedir16(), ".qwenpaw", "workspace");
3079
+ import { existsSync as existsSync18, readdirSync as readdirSync9 } from "fs";
3080
+ import { homedir as homedir17, hostname as hostname4 } from "os";
3081
+ import { join as join18 } from "path";
3082
+ var TOOL_ID13 = "qwenpaw";
3083
+ var TOOL_NAME13 = "QwenPaw";
3084
+ var DEFAULT_USAGE_PATH = join18(homedir17(), ".qwenpaw", "token_usage.json");
3085
+ var DEFAULT_WORKSPACE_PATH = join18(homedir17(), ".qwenpaw", "workspace");
2834
3086
  function createToolDefinition9(usagePath) {
2835
3087
  return {
2836
- id: TOOL_ID12,
2837
- name: TOOL_NAME12,
3088
+ id: TOOL_ID13,
3089
+ name: TOOL_NAME13,
2838
3090
  dataDir: usagePath
2839
3091
  };
2840
3092
  }
@@ -2849,12 +3101,12 @@ function parseUsageDate(value) {
2849
3101
  const timestamp = /* @__PURE__ */ new Date(`${value}T00:00:00.000Z`);
2850
3102
  return Number.isNaN(timestamp.getTime()) ? null : timestamp;
2851
3103
  }
2852
- function getString(value) {
3104
+ function getString2(value) {
2853
3105
  return typeof value === "string" && value.length > 0 ? value : null;
2854
3106
  }
2855
3107
  function resolveModel(recordKey, record) {
2856
- const providerId = getString(record.provider_id);
2857
- const modelName = getString(record.model_name);
3108
+ const providerId = getString2(record.provider_id);
3109
+ const modelName = getString2(record.model_name);
2858
3110
  if (providerId && modelName) {
2859
3111
  return `${providerId}:${modelName}`;
2860
3112
  }
@@ -2891,7 +3143,7 @@ var QwenPawParser = class {
2891
3143
  continue;
2892
3144
  }
2893
3145
  entries.push({
2894
- source: TOOL_ID12,
3146
+ source: TOOL_ID13,
2895
3147
  model: resolveModel(recordKey, record),
2896
3148
  project: "unknown",
2897
3149
  timestamp,
@@ -2914,15 +3166,15 @@ var QwenPawParser = class {
2914
3166
  }
2915
3167
  async parseWorkspaceSessions() {
2916
3168
  const events = [];
2917
- if (!existsSync17(this.workspacePath)) {
3169
+ if (!existsSync18(this.workspacePath)) {
2918
3170
  return events;
2919
3171
  }
2920
3172
  try {
2921
3173
  const workspaceDirs = readdirSync9(this.workspacePath);
2922
3174
  for (const workspaceDir of workspaceDirs) {
2923
- const workspacePath = join17(this.workspacePath, workspaceDir);
2924
- const chatsPath = join17(workspacePath, "chats.json");
2925
- const sessionsPath = join17(workspacePath, "sessions");
3175
+ const workspacePath = join18(this.workspacePath, workspaceDir);
3176
+ const chatsPath = join18(workspacePath, "chats.json");
3177
+ const sessionsPath = join18(workspacePath, "sessions");
2926
3178
  const chatsContent = readFileSafe(chatsPath);
2927
3179
  if (!chatsContent) {
2928
3180
  continue;
@@ -2950,7 +3202,7 @@ var QwenPawParser = class {
2950
3202
  for (const msg of sessionMessages) {
2951
3203
  events.push({
2952
3204
  sessionId: chat.session_id,
2953
- source: TOOL_ID12,
3205
+ source: TOOL_ID13,
2954
3206
  project: workspaceDir,
2955
3207
  timestamp: new Date(msg.timestamp),
2956
3208
  role: msg.role
@@ -2966,7 +3218,7 @@ var QwenPawParser = class {
2966
3218
  }
2967
3219
  getSessionFiles(sessionsPath) {
2968
3220
  const files = /* @__PURE__ */ new Map();
2969
- if (!existsSync17(sessionsPath)) {
3221
+ if (!existsSync18(sessionsPath)) {
2970
3222
  return files;
2971
3223
  }
2972
3224
  try {
@@ -2975,7 +3227,7 @@ var QwenPawParser = class {
2975
3227
  if (!fileName.endsWith(".json")) {
2976
3228
  continue;
2977
3229
  }
2978
- const filePath = join17(sessionsPath, fileName);
3230
+ const filePath = join18(sessionsPath, fileName);
2979
3231
  const content = readFileSafe(filePath);
2980
3232
  if (content) {
2981
3233
  const sessionId = fileName.replace(/^[^_]+_/, "").replace(".json", "");
@@ -3051,7 +3303,7 @@ var QwenPawParser = class {
3051
3303
  source: sessionData.source,
3052
3304
  project: sessionData.project,
3053
3305
  sessionHash,
3054
- hostname: hostname3().replace(/\.local$/, ""),
3306
+ hostname: hostname4().replace(/\.local$/, ""),
3055
3307
  firstMessageAt,
3056
3308
  lastMessageAt,
3057
3309
  durationSeconds,
@@ -3073,15 +3325,15 @@ var QwenPawParser = class {
3073
3325
  });
3074
3326
  }
3075
3327
  isInstalled() {
3076
- return existsSync17(this.usagePath) || existsSync17(this.workspacePath);
3328
+ return existsSync18(this.usagePath) || existsSync18(this.workspacePath);
3077
3329
  }
3078
3330
  };
3079
3331
  registerParser(new QwenPawParser());
3080
3332
 
3081
3333
  // src/parsers/cline.ts
3082
3334
  import { readFileSync as readFileSync6, statSync } from "fs";
3083
- import { homedir as homedir17 } from "os";
3084
- import { basename as basename7, join as join18 } from "path";
3335
+ import { homedir as homedir18 } from "os";
3336
+ import { basename as basename7, join as join19 } from "path";
3085
3337
  var EXTENSION_ID = "saoudrizwan.claude-dev";
3086
3338
  var HOSTS = [
3087
3339
  "Code",
@@ -3095,26 +3347,26 @@ var HOSTS = [
3095
3347
  var TOOL6 = {
3096
3348
  id: "cline",
3097
3349
  name: "Cline",
3098
- dataDir: join18(homedir17(), ".cline")
3350
+ dataDir: join19(homedir18(), ".cline")
3099
3351
  };
3100
3352
  function getHostRoots() {
3101
3353
  const out = [];
3102
3354
  if (process.platform === "darwin") {
3103
- const base = join18(homedir17(), "Library", "Application Support");
3104
- for (const h of HOSTS) out.push(join18(base, h));
3355
+ const base = join19(homedir18(), "Library", "Application Support");
3356
+ for (const h of HOSTS) out.push(join19(base, h));
3105
3357
  } else if (process.platform === "win32") {
3106
- const appData = process.env.APPDATA?.trim() || join18(homedir17(), "AppData", "Roaming");
3107
- for (const h of HOSTS) out.push(join18(appData, h));
3358
+ const appData = process.env.APPDATA?.trim() || join19(homedir18(), "AppData", "Roaming");
3359
+ for (const h of HOSTS) out.push(join19(appData, h));
3108
3360
  } else {
3109
- const xdg = process.env.XDG_CONFIG_HOME?.trim() || join18(homedir17(), ".config");
3110
- for (const h of HOSTS) out.push(join18(xdg, h));
3361
+ const xdg = process.env.XDG_CONFIG_HOME?.trim() || join19(homedir18(), ".config");
3362
+ for (const h of HOSTS) out.push(join19(xdg, h));
3111
3363
  }
3112
3364
  return out;
3113
3365
  }
3114
3366
  function findClineExtensionDirs() {
3115
3367
  const dirs = [];
3116
3368
  for (const root of getHostRoots()) {
3117
- const ext = join18(root, "User", "globalStorage", EXTENSION_ID);
3369
+ const ext = join19(root, "User", "globalStorage", EXTENSION_ID);
3118
3370
  try {
3119
3371
  if (statSync(ext).isDirectory()) dirs.push(ext);
3120
3372
  } catch {
@@ -3146,7 +3398,7 @@ var ClineParser = class {
3146
3398
  const entries = [];
3147
3399
  const sessionEvents = [];
3148
3400
  for (const extDir of extDirs) {
3149
- const history = readJsonSafe(join18(extDir, "state", "taskHistory.json"));
3401
+ const history = readJsonSafe(join19(extDir, "state", "taskHistory.json"));
3150
3402
  if (!Array.isArray(history)) continue;
3151
3403
  for (const item of history) {
3152
3404
  try {
@@ -3157,7 +3409,7 @@ var ClineParser = class {
3157
3409
  );
3158
3410
  const fallbackModel = item.modelId && String(item.modelId).trim() || "cline-unknown";
3159
3411
  const messages = readJsonSafe(
3160
- join18(extDir, "tasks", taskId, "ui_messages.json")
3412
+ join19(extDir, "tasks", taskId, "ui_messages.json")
3161
3413
  );
3162
3414
  if (!Array.isArray(messages)) continue;
3163
3415
  for (const msg of messages) {
@@ -3228,20 +3480,20 @@ registerParser(new ClineParser());
3228
3480
  import { execFileSync as execFileSync3 } from "child_process";
3229
3481
  import {
3230
3482
  copyFileSync,
3231
- existsSync as existsSync18,
3483
+ existsSync as existsSync19,
3232
3484
  mkdtempSync,
3233
3485
  readdirSync as readdirSync10,
3234
3486
  readFileSync as readFileSync7,
3235
3487
  rmSync,
3236
3488
  statSync as statSync2
3237
3489
  } from "fs";
3238
- import { homedir as homedir18, tmpdir } from "os";
3239
- import { join as join19, resolve } from "path";
3240
- var KIROAGENT_RELATIVE = join19("User", "globalStorage", "kiro.kiroagent");
3490
+ import { homedir as homedir19, tmpdir } from "os";
3491
+ import { join as join20, resolve } from "path";
3492
+ var KIROAGENT_RELATIVE = join20("User", "globalStorage", "kiro.kiroagent");
3241
3493
  function getDefaultBasePath() {
3242
3494
  if (process.platform === "darwin") {
3243
- return join19(
3244
- homedir18(),
3495
+ return join20(
3496
+ homedir19(),
3245
3497
  "Library",
3246
3498
  "Application Support",
3247
3499
  "Kiro",
@@ -3249,11 +3501,11 @@ function getDefaultBasePath() {
3249
3501
  );
3250
3502
  }
3251
3503
  if (process.platform === "win32") {
3252
- const appData = process.env.APPDATA?.trim() || join19(homedir18(), "AppData", "Roaming");
3253
- return join19(appData, "Kiro", KIROAGENT_RELATIVE);
3504
+ const appData = process.env.APPDATA?.trim() || join20(homedir19(), "AppData", "Roaming");
3505
+ return join20(appData, "Kiro", KIROAGENT_RELATIVE);
3254
3506
  }
3255
- const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() || join19(homedir18(), ".config");
3256
- return join19(xdgConfigHome, "Kiro", KIROAGENT_RELATIVE);
3507
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() || join20(homedir19(), ".config");
3508
+ return join20(xdgConfigHome, "Kiro", KIROAGENT_RELATIVE);
3257
3509
  }
3258
3510
  var TOOL7 = {
3259
3511
  id: "kiro",
@@ -3264,10 +3516,10 @@ function getKiroBasePath() {
3264
3516
  const explicit = process.env.KIRO_BASE_PATH?.trim();
3265
3517
  if (explicit) {
3266
3518
  const r = resolve(explicit);
3267
- return existsSync18(r) ? r : null;
3519
+ return existsSync19(r) ? r : null;
3268
3520
  }
3269
3521
  const def = getDefaultBasePath();
3270
- return existsSync18(def) ? def : null;
3522
+ return existsSync19(def) ? def : null;
3271
3523
  }
3272
3524
  function isLockError(err) {
3273
3525
  return err instanceof Error && typeof err.message === "string" && /database is locked/i.test(err.message);
@@ -3288,12 +3540,12 @@ function readDb(dbPath) {
3288
3540
  return queryDb(dbPath, TOKENS_SQL);
3289
3541
  } catch (err) {
3290
3542
  if (!isLockError(err)) throw err;
3291
- const snapshotDir = mkdtempSync(join19(tmpdir(), "vibe-usage-kiro-"));
3292
- const queryPath = join19(snapshotDir, "devdata.sqlite");
3543
+ const snapshotDir = mkdtempSync(join20(tmpdir(), "vibe-usage-kiro-"));
3544
+ const queryPath = join20(snapshotDir, "devdata.sqlite");
3293
3545
  copyFileSync(dbPath, queryPath);
3294
3546
  for (const suffix of ["-shm", "-wal"]) {
3295
3547
  const companion = `${dbPath}${suffix}`;
3296
- if (existsSync18(companion))
3548
+ if (existsSync19(companion))
3297
3549
  copyFileSync(companion, `${queryPath}${suffix}`);
3298
3550
  }
3299
3551
  try {
@@ -3345,7 +3597,7 @@ function buildModelTimeline(base) {
3345
3597
  }
3346
3598
  for (const entry of entries) {
3347
3599
  if (!entry.isDirectory() || entry.name === "dev_data") continue;
3348
- const dirPath = join19(base, entry.name);
3600
+ const dirPath = join20(base, entry.name);
3349
3601
  let files;
3350
3602
  try {
3351
3603
  files = readdirSync10(dirPath).filter((f) => f.endsWith(".chat"));
@@ -3354,7 +3606,7 @@ function buildModelTimeline(base) {
3354
3606
  }
3355
3607
  for (const file of files) {
3356
3608
  try {
3357
- const data = JSON.parse(readFileSync7(join19(dirPath, file), "utf-8"));
3609
+ const data = JSON.parse(readFileSync7(join20(dirPath, file), "utf-8"));
3358
3610
  const meta = data?.metadata;
3359
3611
  if (!meta?.modelId || !meta?.startTime) continue;
3360
3612
  const startMs = Number(meta.startTime);
@@ -3403,13 +3655,13 @@ var KiroParser = class {
3403
3655
  async parse() {
3404
3656
  const base = getKiroBasePath();
3405
3657
  if (!base) return { buckets: [], sessions: [] };
3406
- const dbPath = join19(base, "dev_data", "devdata.sqlite");
3407
- const jsonlPath = join19(base, "dev_data", "tokens_generated.jsonl");
3658
+ const dbPath = join20(base, "dev_data", "devdata.sqlite");
3659
+ const jsonlPath = join20(base, "dev_data", "tokens_generated.jsonl");
3408
3660
  let rows;
3409
3661
  try {
3410
- if (existsSync18(dbPath)) {
3662
+ if (existsSync19(dbPath)) {
3411
3663
  rows = readDb(dbPath);
3412
- } else if (existsSync18(jsonlPath)) {
3664
+ } else if (existsSync19(jsonlPath)) {
3413
3665
  rows = readJsonl(jsonlPath);
3414
3666
  } else {
3415
3667
  return { buckets: [], sessions: [] };
@@ -3460,8 +3712,8 @@ registerParser(new KiroParser());
3460
3712
 
3461
3713
  // src/parsers/roo-code.ts
3462
3714
  import { readdirSync as readdirSync11, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
3463
- import { homedir as homedir19 } from "os";
3464
- import { basename as basename8, join as join20 } from "path";
3715
+ import { homedir as homedir20 } from "os";
3716
+ import { basename as basename8, join as join21 } from "path";
3465
3717
  var EXTENSION_ID2 = "rooveterinaryinc.roo-cline";
3466
3718
  var HOSTS2 = [
3467
3719
  "Code",
@@ -3476,17 +3728,17 @@ function getHostRoots2() {
3476
3728
  const out = [];
3477
3729
  let roots;
3478
3730
  if (process.platform === "darwin") {
3479
- roots = [join20(homedir19(), "Library", "Application Support")];
3731
+ roots = [join21(homedir20(), "Library", "Application Support")];
3480
3732
  } else if (process.platform === "win32") {
3481
3733
  roots = [
3482
- process.env.APPDATA?.trim() || join20(homedir19(), "AppData", "Roaming")
3734
+ process.env.APPDATA?.trim() || join21(homedir20(), "AppData", "Roaming")
3483
3735
  ];
3484
3736
  } else {
3485
- roots = [process.env.XDG_CONFIG_HOME?.trim() || join20(homedir19(), ".config")];
3737
+ roots = [process.env.XDG_CONFIG_HOME?.trim() || join21(homedir20(), ".config")];
3486
3738
  }
3487
3739
  for (const root of roots) {
3488
3740
  for (const h of HOSTS2) {
3489
- out.push(join20(root, h));
3741
+ out.push(join21(root, h));
3490
3742
  }
3491
3743
  }
3492
3744
  return out;
@@ -3494,7 +3746,7 @@ function getHostRoots2() {
3494
3746
  function findExtensionDirs() {
3495
3747
  const dirs = [];
3496
3748
  for (const root of getHostRoots2()) {
3497
- const ext = join20(root, "User", "globalStorage", EXTENSION_ID2);
3749
+ const ext = join21(root, "User", "globalStorage", EXTENSION_ID2);
3498
3750
  try {
3499
3751
  if (statSync3(ext).isDirectory()) dirs.push(ext);
3500
3752
  } catch {
@@ -3516,9 +3768,9 @@ function projectFromPath2(absPath) {
3516
3768
  return name || "unknown";
3517
3769
  }
3518
3770
  function readHistoryItems(extDir) {
3519
- const tasksDir = join20(extDir, "tasks");
3771
+ const tasksDir = join21(extDir, "tasks");
3520
3772
  const index = readJsonSafe2(
3521
- join20(tasksDir, "_index.json")
3773
+ join21(tasksDir, "_index.json")
3522
3774
  );
3523
3775
  if (index?.entries && Array.isArray(index.entries)) return index.entries;
3524
3776
  const items = [];
@@ -3532,7 +3784,7 @@ function readHistoryItems(extDir) {
3532
3784
  if (!entry.isDirectory() || entry.name.startsWith("_") || entry.name.startsWith("."))
3533
3785
  continue;
3534
3786
  const item = readJsonSafe2(
3535
- join20(tasksDir, entry.name, "history_item.json")
3787
+ join21(tasksDir, entry.name, "history_item.json")
3536
3788
  );
3537
3789
  if (item && typeof item === "object") items.push(item);
3538
3790
  }
@@ -3559,7 +3811,7 @@ var RooCodeParser = class {
3559
3811
  const project = projectFromPath2(item.workspace);
3560
3812
  const fallbackModel = item.apiConfigName && String(item.apiConfigName).trim() || "roo-unknown";
3561
3813
  const messages = readJsonSafe2(
3562
- join20(extDir, "tasks", taskId, "ui_messages.json")
3814
+ join21(extDir, "tasks", taskId, "ui_messages.json")
3563
3815
  );
3564
3816
  if (!Array.isArray(messages)) continue;
3565
3817
  for (const msg of messages) {
@@ -3623,10 +3875,10 @@ var RooCodeParser = class {
3623
3875
  registerParser(new RooCodeParser());
3624
3876
 
3625
3877
  // src/parsers/snow.ts
3626
- import { existsSync as existsSync19 } from "fs";
3627
- import { homedir as homedir20 } from "os";
3628
- import { join as join21 } from "path";
3629
- var DEFAULT_DATA_DIR6 = join21(homedir20(), ".snow", "usage");
3878
+ import { existsSync as existsSync20 } from "fs";
3879
+ import { homedir as homedir21 } from "os";
3880
+ import { join as join22 } from "path";
3881
+ var DEFAULT_DATA_DIR6 = join22(homedir21(), ".snow", "usage");
3630
3882
  function toNonNegativeNumber2(value) {
3631
3883
  const numberValue = Number(value);
3632
3884
  return Number.isFinite(numberValue) && numberValue >= 0 ? numberValue : 0;
@@ -3673,26 +3925,26 @@ var SnowParser = class {
3673
3925
  return { buckets: aggregateToBuckets(entries), sessions: [] };
3674
3926
  }
3675
3927
  isInstalled() {
3676
- return existsSync19(this.dataDir);
3928
+ return existsSync20(this.dataDir);
3677
3929
  }
3678
3930
  };
3679
3931
  registerParser(new SnowParser());
3680
3932
 
3681
3933
  // src/parsers/cursor.ts
3682
3934
  import { execFileSync as execFileSync4 } from "child_process";
3683
- import { copyFileSync as copyFileSync2, existsSync as existsSync20, mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
3684
- import { homedir as homedir21, tmpdir as tmpdir2 } from "os";
3685
- import { dirname as dirname4, join as join22, resolve as resolve2 } from "path";
3686
- var TOOL_ID13 = "cursor";
3687
- var TOOL_NAME13 = "Cursor";
3688
- var STATE_DB_RELATIVE = join22("User", "globalStorage", "state.vscdb");
3935
+ import { copyFileSync as copyFileSync2, existsSync as existsSync21, mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
3936
+ import { homedir as homedir22, tmpdir as tmpdir2 } from "os";
3937
+ import { dirname as dirname4, join as join23, resolve as resolve2 } from "path";
3938
+ var TOOL_ID14 = "cursor";
3939
+ var TOOL_NAME14 = "Cursor";
3940
+ var STATE_DB_RELATIVE = join23("User", "globalStorage", "state.vscdb");
3689
3941
  var ACCESS_TOKEN_KEY = "cursorAuth/accessToken";
3690
3942
  var SESSION_COOKIE = "WorkosCursorSessionToken";
3691
3943
  var FETCH_TIMEOUT_MS = 1e4;
3692
3944
  function getDefaultStateDbPath() {
3693
3945
  if (process.platform === "darwin") {
3694
- return join22(
3695
- homedir21(),
3946
+ return join23(
3947
+ homedir22(),
3696
3948
  "Library",
3697
3949
  "Application Support",
3698
3950
  "Cursor",
@@ -3700,25 +3952,25 @@ function getDefaultStateDbPath() {
3700
3952
  );
3701
3953
  }
3702
3954
  if (process.platform === "win32") {
3703
- const appData = process.env.APPDATA?.trim() || join22(homedir21(), "AppData", "Roaming");
3704
- return join22(appData, "Cursor", STATE_DB_RELATIVE);
3955
+ const appData = process.env.APPDATA?.trim() || join23(homedir22(), "AppData", "Roaming");
3956
+ return join23(appData, "Cursor", STATE_DB_RELATIVE);
3705
3957
  }
3706
- const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() || join22(homedir21(), ".config");
3707
- return join22(xdgConfigHome, "Cursor", STATE_DB_RELATIVE);
3958
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() || join23(homedir22(), ".config");
3959
+ return join23(xdgConfigHome, "Cursor", STATE_DB_RELATIVE);
3708
3960
  }
3709
3961
  function getCursorStateDbPath() {
3710
3962
  const explicit = process.env.CURSOR_STATE_DB_PATH?.trim();
3711
3963
  if (explicit) {
3712
3964
  const resolved = resolve2(explicit);
3713
- return existsSync20(resolved) ? resolved : null;
3965
+ return existsSync21(resolved) ? resolved : null;
3714
3966
  }
3715
3967
  const configDirs = process.env.CURSOR_CONFIG_DIR?.trim();
3716
3968
  const candidates = configDirs ? configDirs.split(",").map((v) => v.trim()).filter(Boolean).map((v) => {
3717
3969
  const r = resolve2(v);
3718
- return r.endsWith(".vscdb") ? r : join22(r, STATE_DB_RELATIVE);
3970
+ return r.endsWith(".vscdb") ? r : join23(r, STATE_DB_RELATIVE);
3719
3971
  }) : [getDefaultStateDbPath()];
3720
3972
  for (const c of candidates) {
3721
- if (existsSync20(c)) return c;
3973
+ if (existsSync21(c)) return c;
3722
3974
  }
3723
3975
  return null;
3724
3976
  }
@@ -3758,13 +4010,13 @@ function readAccessToken(dbPath) {
3758
4010
  return queryAccessToken(dbPath);
3759
4011
  } catch (err) {
3760
4012
  if (!isLockError2(err)) throw err;
3761
- const snapshotDir = mkdtempSync2(join22(tmpdir2(), "tokenarena-cursor-"));
3762
- const queryPath = join22(snapshotDir, "state.vscdb");
4013
+ const snapshotDir = mkdtempSync2(join23(tmpdir2(), "tokenarena-cursor-"));
4014
+ const queryPath = join23(snapshotDir, "state.vscdb");
3763
4015
  try {
3764
4016
  copyFileSync2(dbPath, queryPath);
3765
4017
  for (const suffix of ["-shm", "-wal"]) {
3766
4018
  const companion = `${dbPath}${suffix}`;
3767
- if (existsSync20(companion))
4019
+ if (existsSync21(companion))
3768
4020
  copyFileSync2(companion, `${queryPath}${suffix}`);
3769
4021
  }
3770
4022
  return queryAccessToken(queryPath);
@@ -3892,8 +4144,8 @@ function parseInt0(value) {
3892
4144
  }
3893
4145
  function createToolDefinition10(dbPath) {
3894
4146
  return {
3895
- id: TOOL_ID13,
3896
- name: TOOL_NAME13,
4147
+ id: TOOL_ID14,
4148
+ name: TOOL_NAME14,
3897
4149
  dataDir: dirname4(dbPath)
3898
4150
  };
3899
4151
  }
@@ -3909,7 +4161,7 @@ var CursorParser = class {
3909
4161
  this.tool = createToolDefinition10(this.dbPath);
3910
4162
  }
3911
4163
  async parse() {
3912
- if (!this.dbPath || !existsSync20(this.dbPath)) {
4164
+ if (!this.dbPath || !existsSync21(this.dbPath)) {
3913
4165
  return { buckets: [], sessions: [] };
3914
4166
  }
3915
4167
  let token;
@@ -3956,7 +4208,7 @@ var CursorParser = class {
3956
4208
  const output = outputIdx >= 0 ? parseInt0(row[outputIdx]) : 0;
3957
4209
  if (inputCacheWrite + inputNoCache + cacheRead + output === 0) continue;
3958
4210
  entries.push({
3959
- source: TOOL_ID13,
4211
+ source: TOOL_ID14,
3960
4212
  model,
3961
4213
  project: "unknown",
3962
4214
  timestamp,
@@ -3972,19 +4224,19 @@ var CursorParser = class {
3972
4224
  };
3973
4225
  }
3974
4226
  isInstalled() {
3975
- return existsSync20(this.dbPath);
4227
+ return existsSync21(this.dbPath);
3976
4228
  }
3977
4229
  };
3978
4230
  registerParser(new CursorParser());
3979
4231
 
3980
4232
  // src/parsers/zcode.ts
3981
- import { createHash as createHash2 } from "crypto";
3982
- import { existsSync as existsSync21 } from "fs";
3983
- import { homedir as homedir22, hostname as hostname4 } from "os";
3984
- import { dirname as dirname5, join as join23 } from "path";
3985
- var TOOL_ID14 = "zcode";
3986
- var TOOL_NAME14 = "ZCode";
3987
- var DEFAULT_DB_PATH3 = join23(homedir22(), ".zcode", "cli", "db", "db.sqlite");
4233
+ import { createHash as createHash3 } from "crypto";
4234
+ import { existsSync as existsSync22 } from "fs";
4235
+ import { homedir as homedir23, hostname as hostname5 } from "os";
4236
+ import { dirname as dirname5, join as join24 } from "path";
4237
+ var TOOL_ID15 = "zcode";
4238
+ var TOOL_NAME15 = "ZCode";
4239
+ var DEFAULT_DB_PATH3 = join24(homedir23(), ".zcode", "cli", "db", "db.sqlite");
3988
4240
  var MODEL_USAGE_QUERY = `SELECT
3989
4241
  model_usage.session_id as sessionId,
3990
4242
  session.directory as directory,
@@ -4019,8 +4271,8 @@ var TURN_USAGE_QUERY = `SELECT
4019
4271
  WHERE duration_ms IS NOT NULL`;
4020
4272
  function createToolDefinition11(dbPath) {
4021
4273
  return {
4022
- id: TOOL_ID14,
4023
- name: TOOL_NAME14,
4274
+ id: TOOL_ID15,
4275
+ name: TOOL_NAME15,
4024
4276
  dataDir: dirname5(dbPath)
4025
4277
  };
4026
4278
  }
@@ -4028,7 +4280,7 @@ function toSafeNumber11(value) {
4028
4280
  const numberValue = Number(value);
4029
4281
  return Number.isFinite(numberValue) && numberValue > 0 ? numberValue : 0;
4030
4282
  }
4031
- function getString2(value) {
4283
+ function getString3(value) {
4032
4284
  return typeof value === "string" && value.length > 0 ? value : null;
4033
4285
  }
4034
4286
  function parseUnixMillis(value) {
@@ -4039,7 +4291,7 @@ function parseUnixMillis(value) {
4039
4291
  const timestamp = new Date(numberValue);
4040
4292
  return Number.isNaN(timestamp.getTime()) ? null : timestamp;
4041
4293
  }
4042
- function getPathLeaf7(value) {
4294
+ function getPathLeaf8(value) {
4043
4295
  if (!value) {
4044
4296
  return "unknown";
4045
4297
  }
@@ -4068,7 +4320,7 @@ function getOrCreateDraft(drafts, sessionId, project) {
4068
4320
  }
4069
4321
  const next = {
4070
4322
  sessionId,
4071
- source: TOOL_ID14,
4323
+ source: TOOL_ID15,
4072
4324
  project,
4073
4325
  firstMessageAt: null,
4074
4326
  lastMessageAt: null,
@@ -4082,7 +4334,7 @@ function getOrCreateDraft(drafts, sessionId, project) {
4082
4334
  drafts.set(sessionId, next);
4083
4335
  return next;
4084
4336
  }
4085
- function buildSessionUsage2(entries) {
4337
+ function buildSessionUsage3(entries) {
4086
4338
  const usageBySession = /* @__PURE__ */ new Map();
4087
4339
  for (const entry of entries) {
4088
4340
  if (!entry.sessionId || hasInvalidTokenCounts(entry)) {
@@ -4114,23 +4366,23 @@ function buildSessionUsage2(entries) {
4114
4366
  }
4115
4367
  return usageBySession;
4116
4368
  }
4117
- function buildSessions(input2) {
4369
+ function buildSessions2(input2) {
4118
4370
  const drafts = /* @__PURE__ */ new Map();
4119
4371
  for (const row of input2.sessionRows) {
4120
- const sessionId = getString2(row.id);
4372
+ const sessionId = getString3(row.id);
4121
4373
  if (!sessionId) {
4122
4374
  continue;
4123
4375
  }
4124
4376
  const draft = getOrCreateDraft(
4125
4377
  drafts,
4126
4378
  sessionId,
4127
- getPathLeaf7(getString2(row.directory))
4379
+ getPathLeaf8(getString3(row.directory))
4128
4380
  );
4129
4381
  draft.fallbackFirstAt = parseUnixMillis(row.timeCreated);
4130
4382
  draft.fallbackLastAt = parseUnixMillis(row.timeUpdated);
4131
4383
  }
4132
4384
  for (const row of input2.messageRows) {
4133
- const sessionId = getString2(row.sessionId);
4385
+ const sessionId = getString3(row.sessionId);
4134
4386
  if (!sessionId) {
4135
4387
  continue;
4136
4388
  }
@@ -4157,15 +4409,15 @@ function buildSessions(input2) {
4157
4409
  }
4158
4410
  }
4159
4411
  for (const row of input2.turnRows) {
4160
- const sessionId = getString2(row.sessionId);
4412
+ const sessionId = getString3(row.sessionId);
4161
4413
  if (!sessionId) {
4162
4414
  continue;
4163
4415
  }
4164
4416
  const draft = getOrCreateDraft(drafts, sessionId, "unknown");
4165
4417
  draft.activeSeconds += Math.round(toSafeNumber11(row.durationMs) / 1e3);
4166
4418
  }
4167
- const usageBySession = buildSessionUsage2(input2.entries);
4168
- const host = hostname4().replace(/\.local$/, "");
4419
+ const usageBySession = buildSessionUsage3(input2.entries);
4420
+ const host = hostname5().replace(/\.local$/, "");
4169
4421
  return Array.from(drafts.values()).map((draft) => {
4170
4422
  const firstMessageAt = draft.firstMessageAt ?? draft.fallbackFirstAt;
4171
4423
  const lastMessageAt = draft.lastMessageAt ?? draft.fallbackLastAt ?? firstMessageAt;
@@ -4207,7 +4459,7 @@ function buildSessions(input2) {
4207
4459
  return {
4208
4460
  source: draft.source,
4209
4461
  project: draft.project,
4210
- sessionHash: createHash2("sha256").update(draft.sessionId).digest("hex").slice(0, 16),
4462
+ sessionHash: createHash3("sha256").update(draft.sessionId).digest("hex").slice(0, 16),
4211
4463
  hostname: host,
4212
4464
  firstMessageAt: firstMessageAt.toISOString(),
4213
4465
  lastMessageAt: lastMessageAt.toISOString(),
@@ -4238,7 +4490,7 @@ var ZCodeParser = class {
4238
4490
  this.tool = createToolDefinition11(this.dbPath);
4239
4491
  }
4240
4492
  async parse() {
4241
- if (!existsSync21(this.dbPath)) {
4493
+ if (!existsSync22(this.dbPath)) {
4242
4494
  return { buckets: [], sessions: [] };
4243
4495
  }
4244
4496
  const usageRows = await this.queryRows(
@@ -4259,10 +4511,10 @@ var ZCodeParser = class {
4259
4511
  continue;
4260
4512
  }
4261
4513
  entries.push({
4262
- sessionId: getString2(row.sessionId) ?? void 0,
4263
- source: TOOL_ID14,
4264
- model: getString2(row.model) ?? "unknown",
4265
- project: getPathLeaf7(getString2(row.directory)),
4514
+ sessionId: getString3(row.sessionId) ?? void 0,
4515
+ source: TOOL_ID15,
4516
+ model: getString3(row.model) ?? "unknown",
4517
+ project: getPathLeaf8(getString3(row.directory)),
4266
4518
  timestamp,
4267
4519
  inputTokens,
4268
4520
  outputTokens,
@@ -4287,7 +4539,7 @@ var ZCodeParser = class {
4287
4539
  }
4288
4540
  return {
4289
4541
  buckets: aggregateToBuckets(entries),
4290
- sessions: buildSessions({
4542
+ sessions: buildSessions2({
4291
4543
  sessionRows,
4292
4544
  messageRows,
4293
4545
  turnRows,
@@ -4296,27 +4548,27 @@ var ZCodeParser = class {
4296
4548
  };
4297
4549
  }
4298
4550
  isInstalled() {
4299
- return existsSync21(this.dbPath);
4551
+ return existsSync22(this.dbPath);
4300
4552
  }
4301
4553
  };
4302
4554
  registerParser(new ZCodeParser());
4303
4555
 
4304
4556
  // src/parsers/qodercli.ts
4305
- import { existsSync as existsSync22, readdirSync as readdirSync12 } from "fs";
4306
- import { homedir as homedir23 } from "os";
4307
- import { basename as basename9, join as join24 } from "path";
4308
- var TOOL_ID15 = "qodercli";
4309
- var TOOL_NAME15 = "Qoder CLI";
4310
- var DEFAULT_PROJECTS_DIR = join24(homedir23(), ".qoder", "projects");
4311
- var DEFAULT_LOGS_DIR = join24(homedir23(), ".qoder", "logs", "sessions");
4312
- var DEFAULT_RUNS_DIR = join24(homedir23(), ".qoder", "logs", "runs");
4557
+ import { existsSync as existsSync23, readdirSync as readdirSync12 } from "fs";
4558
+ import { homedir as homedir24 } from "os";
4559
+ import { basename as basename9, join as join25 } from "path";
4560
+ var TOOL_ID16 = "qodercli";
4561
+ var TOOL_NAME16 = "Qoder CLI";
4562
+ var DEFAULT_PROJECTS_DIR = join25(homedir24(), ".qoder", "projects");
4563
+ var DEFAULT_LOGS_DIR = join25(homedir24(), ".qoder", "logs", "sessions");
4564
+ var DEFAULT_RUNS_DIR = join25(homedir24(), ".qoder", "logs", "runs");
4313
4565
  var CLI_ENTRYPOINT = "cli";
4314
4566
  var IDE_ENTRYPOINT = "acp";
4315
4567
  var CREDIT_MODEL_FALLBACK = "credits";
4316
4568
  function createToolDefinition12(projectsDir) {
4317
4569
  return {
4318
- id: TOOL_ID15,
4319
- name: TOOL_NAME15,
4570
+ id: TOOL_ID16,
4571
+ name: TOOL_NAME16,
4320
4572
  dataDir: projectsDir
4321
4573
  };
4322
4574
  }
@@ -4355,13 +4607,13 @@ function classifyQoderEntrypoint(content) {
4355
4607
  return "unknown";
4356
4608
  }
4357
4609
  function isQodercliBinaryPresent() {
4358
- const home = homedir23();
4610
+ const home = homedir24();
4359
4611
  const candidates = [
4360
- join24(home, ".local", "bin", "qodercli"),
4361
- join24(home, ".qoder", "bin", "qodercli"),
4362
- join24(home, ".qoder-cli")
4612
+ join25(home, ".local", "bin", "qodercli"),
4613
+ join25(home, ".qoder", "bin", "qodercli"),
4614
+ join25(home, ".qoder-cli")
4363
4615
  ];
4364
- return candidates.some((path) => existsSync22(path));
4616
+ return candidates.some((path) => existsSync23(path));
4365
4617
  }
4366
4618
  function projectFromEncodedSlug(slug) {
4367
4619
  const parts = slug.split("-").filter(Boolean);
@@ -4432,7 +4684,7 @@ function creditSnapshotsToEntries(snapshots) {
4432
4684
  if (creditDelta > 0) {
4433
4685
  entries.push({
4434
4686
  sessionId: snap.sessionId,
4435
- source: TOOL_ID15,
4687
+ source: TOOL_ID16,
4436
4688
  model: snap.model || CREDIT_MODEL_FALLBACK,
4437
4689
  project: snap.project,
4438
4690
  timestamp: snap.timestamp,
@@ -4470,7 +4722,7 @@ var QoderCliParser = class {
4470
4722
  };
4471
4723
  }
4472
4724
  parseProjectSessions(sessionEvents) {
4473
- if (!existsSync22(this.projectsDir)) return;
4725
+ if (!existsSync23(this.projectsDir)) return;
4474
4726
  for (const filePath of findJsonlFiles(this.projectsDir)) {
4475
4727
  if (basename9(filePath).startsWith("verified-")) continue;
4476
4728
  const content = readFileSafe(filePath);
@@ -4492,7 +4744,7 @@ var QoderCliParser = class {
4492
4744
  if (Number.isNaN(ts.getTime())) continue;
4493
4745
  sessionEvents.push({
4494
4746
  sessionId,
4495
- source: TOOL_ID15,
4747
+ source: TOOL_ID16,
4496
4748
  project,
4497
4749
  timestamp: ts,
4498
4750
  role: obj.type === "user" ? "user" : "assistant"
@@ -4507,7 +4759,7 @@ var QoderCliParser = class {
4507
4759
  * There is no token data here — only quota/usage credit totals.
4508
4760
  */
4509
4761
  parseCreditDeltas() {
4510
- if (!existsSync22(this.runsDir)) return [];
4762
+ if (!existsSync23(this.runsDir)) return [];
4511
4763
  let runDirs;
4512
4764
  try {
4513
4765
  runDirs = readdirSync12(this.runsDir, { withFileTypes: true }).filter(
@@ -4518,15 +4770,15 @@ var QoderCliParser = class {
4518
4770
  }
4519
4771
  const allSnapshots = [];
4520
4772
  for (const dir of runDirs) {
4521
- const runPath = join24(this.runsDir, dir.name);
4522
- const logPath = join24(runPath, "qodercli.log");
4523
- if (!existsSync22(logPath)) continue;
4773
+ const runPath = join25(this.runsDir, dir.name);
4774
+ const logPath = join25(runPath, "qodercli.log");
4775
+ if (!existsSync23(logPath)) continue;
4524
4776
  const logContent = readFileSafe(logPath);
4525
4777
  if (!logContent?.includes("quota/usage response:")) {
4526
4778
  continue;
4527
4779
  }
4528
4780
  const manifest = parseRunManifest(
4529
- readFileSafe(join24(runPath, "manifest.json"))
4781
+ readFileSafe(join25(runPath, "manifest.json"))
4530
4782
  );
4531
4783
  const project = manifest?.project_id ? projectFromEncodedSlug(manifest.project_id) : projectFromCwd(manifest?.cwd);
4532
4784
  const snapshots = extractCreditSnapshotsFromLog(logContent, {
@@ -4538,22 +4790,22 @@ var QoderCliParser = class {
4538
4790
  return creditSnapshotsToEntries(allSnapshots);
4539
4791
  }
4540
4792
  isInstalled() {
4541
- return isQodercliBinaryPresent() || existsSync22(this.runsDir) || existsSync22(this.logsDir) || existsSync22(this.projectsDir);
4793
+ return isQodercliBinaryPresent() || existsSync23(this.runsDir) || existsSync23(this.logsDir) || existsSync23(this.projectsDir);
4542
4794
  }
4543
4795
  };
4544
4796
  registerParser(new QoderCliParser());
4545
4797
 
4546
4798
  // src/parsers/grok-build.ts
4547
- import { existsSync as existsSync23, readdirSync as readdirSync13 } from "fs";
4548
- import { homedir as homedir24 } from "os";
4549
- import { basename as basename10, join as join25 } from "path";
4550
- var TOOL_ID16 = "grok-build";
4551
- var TOOL_NAME16 = "Grok Build";
4552
- var DEFAULT_DATA_DIR7 = join25(homedir24(), ".grok", "sessions");
4799
+ import { existsSync as existsSync24, readdirSync as readdirSync13 } from "fs";
4800
+ import { homedir as homedir25 } from "os";
4801
+ import { basename as basename10, join as join26 } from "path";
4802
+ var TOOL_ID17 = "grok-build";
4803
+ var TOOL_NAME17 = "Grok Build";
4804
+ var DEFAULT_DATA_DIR7 = join26(homedir25(), ".grok", "sessions");
4553
4805
  function createToolDefinition13(dataDir) {
4554
4806
  return {
4555
- id: TOOL_ID16,
4556
- name: TOOL_NAME16,
4807
+ id: TOOL_ID17,
4808
+ name: TOOL_NAME17,
4557
4809
  dataDir
4558
4810
  };
4559
4811
  }
@@ -4600,7 +4852,7 @@ function pushUsageEntries(entries, args) {
4600
4852
  }
4601
4853
  entries.push({
4602
4854
  sessionId,
4603
- source: TOOL_ID16,
4855
+ source: TOOL_ID17,
4604
4856
  model: model || fallbackModel || "unknown",
4605
4857
  project,
4606
4858
  timestamp,
@@ -4613,7 +4865,7 @@ function pushUsageEntries(entries, args) {
4613
4865
  }
4614
4866
  function findSessionDirs(dataDir) {
4615
4867
  const results = [];
4616
- if (!existsSync23(dataDir)) return results;
4868
+ if (!existsSync24(dataDir)) return results;
4617
4869
  let projectDirs;
4618
4870
  try {
4619
4871
  projectDirs = readdirSync13(dataDir, { withFileTypes: true });
@@ -4623,7 +4875,7 @@ function findSessionDirs(dataDir) {
4623
4875
  for (const projectEntry of projectDirs) {
4624
4876
  if (!projectEntry.isDirectory()) continue;
4625
4877
  if (projectEntry.name.endsWith(".sqlite")) continue;
4626
- const projectDir = join25(dataDir, projectEntry.name);
4878
+ const projectDir = join26(dataDir, projectEntry.name);
4627
4879
  const project = projectFromEncodedCwd(projectEntry.name);
4628
4880
  let sessionEntries;
4629
4881
  try {
@@ -4633,8 +4885,8 @@ function findSessionDirs(dataDir) {
4633
4885
  }
4634
4886
  for (const sessionEntry of sessionEntries) {
4635
4887
  if (!sessionEntry.isDirectory()) continue;
4636
- const sessionDir = join25(projectDir, sessionEntry.name);
4637
- if (!existsSync23(join25(sessionDir, "updates.jsonl"))) continue;
4888
+ const sessionDir = join26(projectDir, sessionEntry.name);
4889
+ if (!existsSync24(join26(sessionDir, "updates.jsonl"))) continue;
4638
4890
  results.push({
4639
4891
  sessionDir,
4640
4892
  project,
@@ -4645,7 +4897,7 @@ function findSessionDirs(dataDir) {
4645
4897
  return results;
4646
4898
  }
4647
4899
  function readFallbackModel(sessionDir) {
4648
- const summaryPath = join25(sessionDir, "summary.json");
4900
+ const summaryPath = join26(sessionDir, "summary.json");
4649
4901
  const content = readFileSafe(summaryPath);
4650
4902
  if (!content) return "unknown";
4651
4903
  try {
@@ -4667,7 +4919,7 @@ var GrokBuildParser = class {
4667
4919
  const sessionEvents = [];
4668
4920
  const sessions = findSessionDirs(this.dataDir);
4669
4921
  for (const { sessionDir, project, sessionId } of sessions) {
4670
- const updatesPath = join25(sessionDir, "updates.jsonl");
4922
+ const updatesPath = join26(sessionDir, "updates.jsonl");
4671
4923
  const content = readFileSafe(updatesPath);
4672
4924
  if (!content) continue;
4673
4925
  const fallbackModel = readFallbackModel(sessionDir);
@@ -4694,7 +4946,7 @@ var GrokBuildParser = class {
4694
4946
  seenUserPrompts.add(key);
4695
4947
  sessionEvents.push({
4696
4948
  sessionId: sid,
4697
- source: TOOL_ID16,
4949
+ source: TOOL_ID17,
4698
4950
  project,
4699
4951
  timestamp: ts,
4700
4952
  role: "user"
@@ -4705,7 +4957,7 @@ var GrokBuildParser = class {
4705
4957
  seenUserPrompts.delete(ANON_USER_OPEN);
4706
4958
  sessionEvents.push({
4707
4959
  sessionId: sid,
4708
- source: TOOL_ID16,
4960
+ source: TOOL_ID17,
4709
4961
  project,
4710
4962
  timestamp: ts,
4711
4963
  role: "assistant"
@@ -4727,22 +4979,22 @@ var GrokBuildParser = class {
4727
4979
  };
4728
4980
  }
4729
4981
  isInstalled() {
4730
- return existsSync23(this.dataDir) || existsSync23(join25(homedir24(), ".grok")) || existsSync23(join25(homedir24(), ".local", "bin", "grok"));
4982
+ return existsSync24(this.dataDir) || existsSync24(join26(homedir25(), ".grok")) || existsSync24(join26(homedir25(), ".local", "bin", "grok"));
4731
4983
  }
4732
4984
  };
4733
4985
  registerParser(new GrokBuildParser());
4734
4986
 
4735
4987
  // src/parsers/atomcode.ts
4736
- import { existsSync as existsSync24 } from "fs";
4737
- import { homedir as homedir25 } from "os";
4738
- import { basename as basename11, join as join26 } from "path";
4739
- var TOOL_ID17 = "atomcode";
4740
- var TOOL_NAME17 = "AtomCode";
4741
- var DEFAULT_SESSIONS_DIR6 = join26(homedir25(), ".atomcode", "sessions");
4988
+ import { existsSync as existsSync25 } from "fs";
4989
+ import { homedir as homedir26 } from "os";
4990
+ import { basename as basename11, join as join27 } from "path";
4991
+ var TOOL_ID18 = "atomcode";
4992
+ var TOOL_NAME18 = "AtomCode";
4993
+ var DEFAULT_SESSIONS_DIR6 = join27(homedir26(), ".atomcode", "sessions");
4742
4994
  function getAtomCodeSessionsDirs(env = process.env) {
4743
4995
  const dirs = [
4744
4996
  env.TOKEN_ARENA_ATOMCODE_DIR,
4745
- env.ATOMCODE_HOME ? join26(env.ATOMCODE_HOME, "sessions") : void 0,
4997
+ env.ATOMCODE_HOME ? join27(env.ATOMCODE_HOME, "sessions") : void 0,
4746
4998
  DEFAULT_SESSIONS_DIR6
4747
4999
  ].filter((value) => Boolean(value));
4748
5000
  return Array.from(new Set(dirs));
@@ -4800,8 +5052,8 @@ var AtomCodeParser = class {
4800
5052
  constructor(sessionsDir) {
4801
5053
  this.sessionsDirs = sessionsDir ? [sessionsDir] : getAtomCodeSessionsDirs();
4802
5054
  this.tool = {
4803
- id: TOOL_ID17,
4804
- name: TOOL_NAME17,
5055
+ id: TOOL_ID18,
5056
+ name: TOOL_NAME18,
4805
5057
  dataDir: this.sessionsDirs[0] ?? DEFAULT_SESSIONS_DIR6
4806
5058
  };
4807
5059
  }
@@ -4828,7 +5080,7 @@ var AtomCodeParser = class {
4828
5080
  if (row.user !== void 0 || row.assistant !== void 0) {
4829
5081
  sessionEvents.push({
4830
5082
  sessionId,
4831
- source: TOOL_ID17,
5083
+ source: TOOL_ID18,
4832
5084
  project,
4833
5085
  timestamp,
4834
5086
  role: row.user !== void 0 ? "user" : "assistant"
@@ -4857,7 +5109,7 @@ var AtomCodeParser = class {
4857
5109
  seenEntryKeys.add(entryKey);
4858
5110
  entries.push({
4859
5111
  sessionId,
4860
- source: TOOL_ID17,
5112
+ source: TOOL_ID18,
4861
5113
  model,
4862
5114
  project,
4863
5115
  timestamp,
@@ -4875,24 +5127,24 @@ var AtomCodeParser = class {
4875
5127
  };
4876
5128
  }
4877
5129
  isInstalled() {
4878
- return this.sessionsDirs.some((dir) => existsSync24(dir));
5130
+ return this.sessionsDirs.some((dir) => existsSync25(dir));
4879
5131
  }
4880
5132
  };
4881
5133
  registerParser(new AtomCodeParser());
4882
5134
 
4883
5135
  // src/parsers/dsh.ts
4884
- import { existsSync as existsSync25, readdirSync as readdirSync14, readFileSync as readFileSync9 } from "fs";
4885
- import { homedir as homedir26 } from "os";
4886
- import { basename as basename12, join as join27 } from "path";
5136
+ import { existsSync as existsSync26, readdirSync as readdirSync14, readFileSync as readFileSync9 } from "fs";
5137
+ import { homedir as homedir27 } from "os";
5138
+ import { basename as basename12, join as join28 } from "path";
4887
5139
  import * as zlib from "zlib";
4888
- var TOOL_ID18 = "dsh";
4889
- var TOOL_NAME18 = "DeepSeek Harness";
4890
- var DEFAULT_SESSIONS_DIR7 = join27(homedir26(), ".dsh", "sessions");
5140
+ var TOOL_ID19 = "dsh";
5141
+ var TOOL_NAME19 = "DeepSeek Harness";
5142
+ var DEFAULT_SESSIONS_DIR7 = join28(homedir27(), ".dsh", "sessions");
4891
5143
  var LOG_BASENAME = "session";
4892
5144
  function getDshSessionsDirs(env = process.env) {
4893
5145
  const dirs = [
4894
5146
  env.TOKEN_ARENA_DSH_DIR,
4895
- env.DSH_HOME ? join27(env.DSH_HOME, "sessions") : void 0,
5147
+ env.DSH_HOME ? join28(env.DSH_HOME, "sessions") : void 0,
4896
5148
  DEFAULT_SESSIONS_DIR7
4897
5149
  ].filter((value) => Boolean(value));
4898
5150
  return Array.from(new Set(dirs));
@@ -4981,10 +5233,10 @@ function readSessionLog(filePath) {
4981
5233
  }
4982
5234
  function findSessionLogs(dir) {
4983
5235
  const results = [];
4984
- if (!existsSync25(dir)) return results;
5236
+ if (!existsSync26(dir)) return results;
4985
5237
  try {
4986
5238
  for (const entry of readdirSync14(dir, { withFileTypes: true })) {
4987
- const fullPath = join27(dir, entry.name);
5239
+ const fullPath = join28(dir, entry.name);
4988
5240
  if (entry.isDirectory()) {
4989
5241
  results.push(...findSessionLogs(fullPath));
4990
5242
  } else if (entry.name === `${LOG_BASENAME}.jsonl` || entry.name === `${LOG_BASENAME}.jsonl.zstd`) {
@@ -5015,8 +5267,8 @@ var DshParser = class {
5015
5267
  constructor(sessionsDir) {
5016
5268
  this.sessionsDirs = sessionsDir ? [sessionsDir] : getDshSessionsDirs();
5017
5269
  this.tool = {
5018
- id: TOOL_ID18,
5019
- name: TOOL_NAME18,
5270
+ id: TOOL_ID19,
5271
+ name: TOOL_NAME19,
5020
5272
  dataDir: this.sessionsDirs[0] ?? DEFAULT_SESSIONS_DIR7
5021
5273
  };
5022
5274
  }
@@ -5053,7 +5305,7 @@ var DshParser = class {
5053
5305
  if (timestamp) {
5054
5306
  sessionEvents.push({
5055
5307
  sessionId,
5056
- source: TOOL_ID18,
5308
+ source: TOOL_ID19,
5057
5309
  project,
5058
5310
  timestamp,
5059
5311
  role: "user"
@@ -5066,7 +5318,7 @@ var DshParser = class {
5066
5318
  if (timestamp && !isCompaction) {
5067
5319
  sessionEvents.push({
5068
5320
  sessionId,
5069
- source: TOOL_ID18,
5321
+ source: TOOL_ID19,
5070
5322
  project,
5071
5323
  timestamp,
5072
5324
  role: "assistant"
@@ -5097,7 +5349,7 @@ var DshParser = class {
5097
5349
  seenEntryKeys.add(entryKey);
5098
5350
  entries.push({
5099
5351
  sessionId,
5100
- source: TOOL_ID18,
5352
+ source: TOOL_ID19,
5101
5353
  model,
5102
5354
  project,
5103
5355
  timestamp,
@@ -5115,42 +5367,210 @@ var DshParser = class {
5115
5367
  };
5116
5368
  }
5117
5369
  isInstalled() {
5118
- return this.sessionsDirs.some((dir) => existsSync25(dir));
5370
+ return this.sessionsDirs.some((dir) => existsSync26(dir));
5119
5371
  }
5120
5372
  };
5121
5373
  registerParser(new DshParser());
5122
5374
 
5375
+ // src/parsers/cherry-studio.ts
5376
+ import { existsSync as existsSync27 } from "fs";
5377
+ import { homedir as homedir28 } from "os";
5378
+ import { dirname as dirname6, join as join29, resolve as resolve3 } from "path";
5379
+ var TOOL_ID20 = "cherry-studio";
5380
+ var TOOL_NAME20 = "Cherry Studio";
5381
+ var DB_RELATIVE = join29("Data", "cherrystudio.sqlite");
5382
+ var USAGE_QUERY = `SELECT
5383
+ u.model_id as modelId,
5384
+ u.no_cache_tokens as noCacheTokens,
5385
+ u.input_tokens as inputTokens,
5386
+ u.output_tokens as outputTokens,
5387
+ u.reasoning_tokens as reasoningTokens,
5388
+ u.cache_read_tokens as cacheReadTokens,
5389
+ u.cache_write_tokens as cacheWriteTokens,
5390
+ u.created_at as createdAt,
5391
+ m.topic_id as sessionId
5392
+ FROM ai_usage_record u
5393
+ LEFT JOIN message m ON m.id = u.message_id`;
5394
+ var MESSAGES_QUERY3 = `SELECT
5395
+ topic_id as sessionId,
5396
+ role,
5397
+ created_at as createdAt
5398
+ FROM message
5399
+ WHERE role IN ('user', 'assistant')
5400
+ AND deleted_at IS NULL
5401
+ ORDER BY created_at`;
5402
+ function getDefaultUserDataDir(env = process.env) {
5403
+ if (process.platform === "darwin") {
5404
+ return join29(homedir28(), "Library", "Application Support", "CherryStudio");
5405
+ }
5406
+ if (process.platform === "win32") {
5407
+ const appData = env.APPDATA?.trim() || join29(homedir28(), "AppData", "Roaming");
5408
+ return join29(appData, "CherryStudio");
5409
+ }
5410
+ const xdgConfigHome = env.XDG_CONFIG_HOME?.trim() || join29(homedir28(), ".config");
5411
+ return join29(xdgConfigHome, "CherryStudio");
5412
+ }
5413
+ function getCherryStudioDbPaths(env = process.env) {
5414
+ const paths = [];
5415
+ const explicit = env.TOKEN_ARENA_CHERRY_STUDIO_DB?.trim();
5416
+ if (explicit) {
5417
+ const resolved = resolve3(explicit);
5418
+ paths.push(
5419
+ resolved.endsWith(".sqlite") ? resolved : join29(resolved, DB_RELATIVE)
5420
+ );
5421
+ }
5422
+ paths.push(join29(getDefaultUserDataDir(env), DB_RELATIVE));
5423
+ return Array.from(new Set(paths));
5424
+ }
5425
+ function resolveCherryStudioDbPath() {
5426
+ const candidates = getCherryStudioDbPaths();
5427
+ return candidates.find((candidate) => existsSync27(candidate)) ?? "";
5428
+ }
5429
+ function createToolDefinition14(dbPath) {
5430
+ return {
5431
+ id: TOOL_ID20,
5432
+ name: TOOL_NAME20,
5433
+ dataDir: dbPath ? dirname6(dbPath) : join29(getDefaultUserDataDir(), "Data")
5434
+ };
5435
+ }
5436
+ function toSafeCount(value) {
5437
+ const numberValue = Number(value);
5438
+ return Number.isFinite(numberValue) && numberValue > 0 ? Math.round(numberValue) : 0;
5439
+ }
5440
+ function toOptionalCount(value) {
5441
+ if (value === null || value === void 0) {
5442
+ return null;
5443
+ }
5444
+ const numberValue = Number(value);
5445
+ return Number.isFinite(numberValue) && numberValue >= 0 ? Math.round(numberValue) : null;
5446
+ }
5447
+ function parseEpochMillis(value) {
5448
+ const numberValue = Number(value);
5449
+ if (!Number.isFinite(numberValue) || numberValue <= 0) {
5450
+ return null;
5451
+ }
5452
+ const timestamp = new Date(numberValue);
5453
+ return Number.isNaN(timestamp.getTime()) ? null : timestamp;
5454
+ }
5455
+ function getNonEmptyString(value) {
5456
+ return typeof value === "string" && value.length > 0 ? value : null;
5457
+ }
5458
+ var CherryStudioParser = class {
5459
+ tool;
5460
+ dbPath;
5461
+ queryRows;
5462
+ constructor(options = {}) {
5463
+ this.dbPath = options.dbPath || resolveCherryStudioDbPath();
5464
+ this.queryRows = options.queryRows || readSqliteRows;
5465
+ this.tool = createToolDefinition14(this.dbPath);
5466
+ }
5467
+ async parse() {
5468
+ if (!this.dbPath || !existsSync27(this.dbPath)) {
5469
+ return { buckets: [], sessions: [] };
5470
+ }
5471
+ const usageRows = await this.queryRows(
5472
+ this.dbPath,
5473
+ USAGE_QUERY
5474
+ );
5475
+ const entries = [];
5476
+ for (const row of usageRows) {
5477
+ const timestamp = parseEpochMillis(row.createdAt);
5478
+ if (!timestamp) continue;
5479
+ const cachedTokens = toSafeCount(row.cacheReadTokens) + toSafeCount(row.cacheWriteTokens);
5480
+ const noCacheTokens = toOptionalCount(row.noCacheTokens);
5481
+ const inputTokens = noCacheTokens ?? Math.max(0, toSafeCount(row.inputTokens) - cachedTokens);
5482
+ const reasoningTokens = toSafeCount(row.reasoningTokens);
5483
+ const outputTokens = Math.max(
5484
+ 0,
5485
+ toSafeCount(row.outputTokens) - reasoningTokens
5486
+ );
5487
+ if (inputTokens + outputTokens + reasoningTokens + cachedTokens === 0) {
5488
+ continue;
5489
+ }
5490
+ entries.push({
5491
+ // Rows the topic join could not resolve still count toward buckets,
5492
+ // they just cannot take part in session timing.
5493
+ sessionId: getNonEmptyString(row.sessionId) ?? void 0,
5494
+ source: TOOL_ID20,
5495
+ model: getNonEmptyString(row.modelId) ?? "unknown",
5496
+ project: "unknown",
5497
+ timestamp,
5498
+ inputTokens,
5499
+ outputTokens,
5500
+ reasoningTokens,
5501
+ cachedTokens
5502
+ });
5503
+ }
5504
+ let messageRows;
5505
+ try {
5506
+ messageRows = await this.queryRows(
5507
+ this.dbPath,
5508
+ MESSAGES_QUERY3
5509
+ );
5510
+ } catch {
5511
+ return {
5512
+ buckets: aggregateToBuckets(entries),
5513
+ sessions: []
5514
+ };
5515
+ }
5516
+ const sessionEvents = [];
5517
+ for (const row of messageRows) {
5518
+ const sessionId = getNonEmptyString(row.sessionId);
5519
+ if (!sessionId) continue;
5520
+ const role = row.role === "user" || row.role === "assistant" ? row.role : null;
5521
+ if (!role) continue;
5522
+ const timestamp = parseEpochMillis(row.createdAt);
5523
+ if (!timestamp) continue;
5524
+ sessionEvents.push({
5525
+ sessionId,
5526
+ source: TOOL_ID20,
5527
+ project: "unknown",
5528
+ timestamp,
5529
+ role
5530
+ });
5531
+ }
5532
+ return {
5533
+ buckets: aggregateToBuckets(entries),
5534
+ sessions: extractSessions(sessionEvents, entries)
5535
+ };
5536
+ }
5537
+ isInstalled() {
5538
+ return Boolean(this.dbPath) && existsSync27(this.dbPath);
5539
+ }
5540
+ };
5541
+ registerParser(new CherryStudioParser());
5542
+
5123
5543
  // src/cli.ts
5124
5544
  import { Command, Option } from "commander";
5125
5545
 
5126
5546
  // src/infrastructure/config/manager.ts
5127
5547
  import { randomUUID } from "crypto";
5128
5548
  import {
5129
- existsSync as existsSync26,
5549
+ existsSync as existsSync28,
5130
5550
  mkdirSync,
5131
5551
  readFileSync as readFileSync10,
5132
5552
  unlinkSync,
5133
5553
  writeFileSync
5134
5554
  } from "fs";
5135
- import { join as join29 } from "path";
5555
+ import { join as join31 } from "path";
5136
5556
 
5137
5557
  // src/infrastructure/xdg.ts
5138
- import { homedir as homedir27 } from "os";
5139
- import { join as join28 } from "path";
5558
+ import { homedir as homedir29 } from "os";
5559
+ import { join as join30 } from "path";
5140
5560
  function getConfigHome() {
5141
- return process.env.XDG_CONFIG_HOME || join28(homedir27(), ".config");
5561
+ return process.env.XDG_CONFIG_HOME || join30(homedir29(), ".config");
5142
5562
  }
5143
5563
  function getStateHome() {
5144
- return process.env.XDG_STATE_HOME || join28(homedir27(), ".local", "state");
5564
+ return process.env.XDG_STATE_HOME || join30(homedir29(), ".local", "state");
5145
5565
  }
5146
5566
  function getRuntimeDir() {
5147
5567
  return process.env.XDG_RUNTIME_DIR || getStateHome();
5148
5568
  }
5149
5569
 
5150
5570
  // src/infrastructure/config/manager.ts
5151
- var CONFIG_DIR = join29(getConfigHome(), "tokenarena");
5571
+ var CONFIG_DIR = join31(getConfigHome(), "tokenarena");
5152
5572
  var isDev = process.env.TOKEN_ARENA_DEV === "1";
5153
- var CONFIG_FILE = join29(CONFIG_DIR, isDev ? "config.dev.json" : "config.json");
5573
+ var CONFIG_FILE = join31(CONFIG_DIR, isDev ? "config.dev.json" : "config.json");
5154
5574
  var DEFAULT_API_URL = "https://token.guji.uno";
5155
5575
  var VALID_CONFIG_KEYS = [
5156
5576
  "apiKey",
@@ -5166,7 +5586,7 @@ function getConfigDir() {
5166
5586
  return CONFIG_DIR;
5167
5587
  }
5168
5588
  function loadConfig() {
5169
- if (!existsSync26(CONFIG_FILE)) return null;
5589
+ if (!existsSync28(CONFIG_FILE)) return null;
5170
5590
  try {
5171
5591
  const raw = readFileSync10(CONFIG_FILE, "utf-8");
5172
5592
  const config = JSON.parse(raw);
@@ -5184,7 +5604,7 @@ function saveConfig(config) {
5184
5604
  `, "utf-8");
5185
5605
  }
5186
5606
  function deleteConfig() {
5187
- if (existsSync26(CONFIG_FILE)) {
5607
+ if (existsSync28(CONFIG_FILE)) {
5188
5608
  unlinkSync(CONFIG_FILE);
5189
5609
  }
5190
5610
  }
@@ -5644,7 +6064,7 @@ async function handleConfig(args) {
5644
6064
  }
5645
6065
 
5646
6066
  // src/services/sync-service.ts
5647
- import { hostname as hostname5 } from "os";
6067
+ import { hostname as hostname6 } from "os";
5648
6068
 
5649
6069
  // src/domain/project-identity.ts
5650
6070
  import { createHmac } from "crypto";
@@ -5663,11 +6083,11 @@ function toProjectIdentity(input2) {
5663
6083
  }
5664
6084
 
5665
6085
  // src/domain/upload-manifest.ts
5666
- import { createHash as createHash3 } from "crypto";
6086
+ import { createHash as createHash4 } from "crypto";
5667
6087
  var MANIFEST_VERSION = 1;
5668
6088
  var SNAPSHOT_PROTOCOL_VERSION = 1;
5669
6089
  function fingerprint(value) {
5670
- return createHash3("sha256").update(value).digest("hex").slice(0, 16);
6090
+ return createHash4("sha256").update(value).digest("hex").slice(0, 16);
5671
6091
  }
5672
6092
  function normalizeApiUrl(apiUrl) {
5673
6093
  let end = apiUrl.length;
@@ -5870,7 +6290,7 @@ var ApiClient = class {
5870
6290
  throw lastError;
5871
6291
  }
5872
6292
  sendIngest(device, buckets, sessions, onProgress, options) {
5873
- return new Promise((resolve4, reject) => {
6293
+ return new Promise((resolve5, reject) => {
5874
6294
  const url = new URL2("/api/usage/ingest", this.apiUrl);
5875
6295
  const body = Buffer.from(
5876
6296
  JSON.stringify(buildIngestPayload(device, buckets, sessions, options))
@@ -5908,7 +6328,7 @@ var ApiClient = class {
5908
6328
  }
5909
6329
  try {
5910
6330
  const response = JSON.parse(data);
5911
- resolve4({
6331
+ resolve5({
5912
6332
  ingested: response.bucketCount ?? response.ingested,
5913
6333
  sessions: response.sessionCount ?? response.sessions
5914
6334
  });
@@ -5946,7 +6366,7 @@ var ApiClient = class {
5946
6366
  * Fetch user settings from server
5947
6367
  */
5948
6368
  async fetchSettings() {
5949
- return new Promise((resolve4, reject) => {
6369
+ return new Promise((resolve5, reject) => {
5950
6370
  const url = new URL2("/api/usage/settings", this.apiUrl);
5951
6371
  const mod = url.protocol === "https:" ? https : http;
5952
6372
  const req = mod.request(
@@ -5969,32 +6389,32 @@ var ApiClient = class {
5969
6389
  return;
5970
6390
  }
5971
6391
  if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
5972
- resolve4(null);
6392
+ resolve5(null);
5973
6393
  return;
5974
6394
  }
5975
6395
  try {
5976
6396
  const settings = JSON.parse(data);
5977
6397
  if (settings.schemaVersion !== 2 || !settings.projectMode || !settings.projectHashSalt || !settings.timezone) {
5978
- resolve4(null);
6398
+ resolve5(null);
5979
6399
  return;
5980
6400
  }
5981
- resolve4(settings);
6401
+ resolve5(settings);
5982
6402
  } catch {
5983
- resolve4(null);
6403
+ resolve5(null);
5984
6404
  }
5985
6405
  });
5986
6406
  }
5987
6407
  );
5988
- req.on("error", () => resolve4(null));
6408
+ req.on("error", () => resolve5(null));
5989
6409
  req.on("timeout", () => {
5990
6410
  req.destroy();
5991
- resolve4(null);
6411
+ resolve5(null);
5992
6412
  });
5993
6413
  req.end();
5994
6414
  });
5995
6415
  }
5996
6416
  async deleteDeviceData(deviceId) {
5997
- return new Promise((resolve4, reject) => {
6417
+ return new Promise((resolve5, reject) => {
5998
6418
  const url = new URL2("/api/usage/ingest", this.apiUrl);
5999
6419
  url.searchParams.set("deviceId", deviceId);
6000
6420
  const mod = url.protocol === "https:" ? https : http;
@@ -6026,7 +6446,7 @@ var ApiClient = class {
6026
6446
  return;
6027
6447
  }
6028
6448
  try {
6029
- resolve4(JSON.parse(data));
6449
+ resolve5(JSON.parse(data));
6030
6450
  } catch {
6031
6451
  reject(new Error(`Invalid JSON response: ${data}`));
6032
6452
  }
@@ -6046,7 +6466,7 @@ var ApiClient = class {
6046
6466
  // src/infrastructure/runtime/lock.ts
6047
6467
  import {
6048
6468
  closeSync,
6049
- existsSync as existsSync27,
6469
+ existsSync as existsSync29,
6050
6470
  openSync,
6051
6471
  readFileSync as readFileSync11,
6052
6472
  rmSync as rmSync3,
@@ -6055,22 +6475,22 @@ import {
6055
6475
 
6056
6476
  // src/infrastructure/runtime/paths.ts
6057
6477
  import { mkdirSync as mkdirSync2 } from "fs";
6058
- import { join as join30 } from "path";
6478
+ import { join as join32 } from "path";
6059
6479
  var APP_NAME = "tokenarena";
6060
6480
  function getRuntimeDirPath() {
6061
- return join30(getRuntimeDir(), APP_NAME);
6481
+ return join32(getRuntimeDir(), APP_NAME);
6062
6482
  }
6063
6483
  function getStateDir() {
6064
- return join30(getStateHome(), APP_NAME);
6484
+ return join32(getStateHome(), APP_NAME);
6065
6485
  }
6066
6486
  function getSyncLockPath() {
6067
- return join30(getRuntimeDirPath(), "sync.lock");
6487
+ return join32(getRuntimeDirPath(), "sync.lock");
6068
6488
  }
6069
6489
  function getSyncStatePath() {
6070
- return join30(getStateDir(), "status.json");
6490
+ return join32(getStateDir(), "status.json");
6071
6491
  }
6072
6492
  function getUploadManifestPath() {
6073
- return join30(getStateDir(), "upload-manifest.json");
6493
+ return join32(getStateDir(), "upload-manifest.json");
6074
6494
  }
6075
6495
  function ensureAppDirs() {
6076
6496
  mkdirSync2(getRuntimeDirPath(), { recursive: true });
@@ -6088,7 +6508,7 @@ function isProcessAlive(pid) {
6088
6508
  }
6089
6509
  }
6090
6510
  function readLockMetadata(lockPath) {
6091
- if (!existsSync27(lockPath)) {
6511
+ if (!existsSync29(lockPath)) {
6092
6512
  return null;
6093
6513
  }
6094
6514
  try {
@@ -6162,13 +6582,13 @@ function describeExistingSyncLock() {
6162
6582
  }
6163
6583
 
6164
6584
  // src/infrastructure/runtime/state.ts
6165
- import { existsSync as existsSync28, readFileSync as readFileSync12, writeFileSync as writeFileSync3 } from "fs";
6585
+ import { existsSync as existsSync30, readFileSync as readFileSync12, writeFileSync as writeFileSync3 } from "fs";
6166
6586
  function getDefaultState() {
6167
6587
  return { status: "idle" };
6168
6588
  }
6169
6589
  function loadSyncState() {
6170
6590
  const path = getSyncStatePath();
6171
- if (!existsSync28(path)) {
6591
+ if (!existsSync30(path)) {
6172
6592
  return getDefaultState();
6173
6593
  }
6174
6594
  try {
@@ -6229,7 +6649,7 @@ function markSyncFailed(source, error, status) {
6229
6649
  }
6230
6650
 
6231
6651
  // src/infrastructure/runtime/upload-manifest.ts
6232
- import { existsSync as existsSync29, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
6652
+ import { existsSync as existsSync31, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
6233
6653
  function isRecordOfStrings(value) {
6234
6654
  if (!value || typeof value !== "object" || Array.isArray(value)) {
6235
6655
  return false;
@@ -6245,7 +6665,7 @@ function isUploadManifest(value) {
6245
6665
  }
6246
6666
  function loadUploadManifest() {
6247
6667
  const path = getUploadManifestPath();
6248
- if (!existsSync29(path)) {
6668
+ if (!existsSync31(path)) {
6249
6669
  return null;
6250
6670
  }
6251
6671
  try {
@@ -6367,7 +6787,7 @@ function persistUploadManifest(manifest, quiet) {
6367
6787
  function toDeviceMetadata(config) {
6368
6788
  return {
6369
6789
  deviceId: getOrCreateDeviceId(config),
6370
- hostname: hostname5().replace(/\.local$/, "")
6790
+ hostname: hostname6().replace(/\.local$/, "")
6371
6791
  };
6372
6792
  }
6373
6793
  function toUploadBuckets(buckets, settings, device) {
@@ -6785,18 +7205,18 @@ View your dashboard at: ${apiUrl}/usage`);
6785
7205
 
6786
7206
  // src/commands/init.ts
6787
7207
  import { execFileSync as execFileSync7, spawn } from "child_process";
6788
- import { existsSync as existsSync32 } from "fs";
7208
+ import { existsSync as existsSync34 } from "fs";
6789
7209
  import { appendFile, mkdir, readFile } from "fs/promises";
6790
- import { homedir as homedir30, platform as platform5 } from "os";
6791
- import { dirname as dirname6, join as join31, posix as posix3, win32 } from "path";
7210
+ import { homedir as homedir32, platform as platform5 } from "os";
7211
+ import { dirname as dirname7, join as join33, posix as posix3, win32 } from "path";
6792
7212
 
6793
7213
  // src/infrastructure/service/index.ts
6794
7214
  import { platform as platform4 } from "os";
6795
7215
 
6796
7216
  // src/infrastructure/service/linux-systemd.ts
6797
7217
  import { execFileSync as execFileSync5 } from "child_process";
6798
- import { existsSync as existsSync30, mkdirSync as mkdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
6799
- import { homedir as homedir28, platform as platform2 } from "os";
7218
+ import { existsSync as existsSync32, mkdirSync as mkdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
7219
+ import { homedir as homedir30, platform as platform2 } from "os";
6800
7220
  import { posix } from "path";
6801
7221
 
6802
7222
  // src/utils/command.ts
@@ -6865,10 +7285,10 @@ function escapeXml(value) {
6865
7285
 
6866
7286
  // src/infrastructure/service/linux-systemd.ts
6867
7287
  var SYSTEMD_SERVICE_NAME = "tokenarena";
6868
- function getLinuxSystemdServiceDir(homePath = homedir28()) {
7288
+ function getLinuxSystemdServiceDir(homePath = homedir30()) {
6869
7289
  return posix.join(homePath, ".config", "systemd", "user");
6870
7290
  }
6871
- function getLinuxSystemdServiceFile(homePath = homedir28()) {
7291
+ function getLinuxSystemdServiceFile(homePath = homedir30()) {
6872
7292
  return posix.join(
6873
7293
  getLinuxSystemdServiceDir(homePath),
6874
7294
  `${SYSTEMD_SERVICE_NAME}.service`
@@ -6925,7 +7345,7 @@ function ensureSystemdAvailable() {
6925
7345
  }
6926
7346
  function createLinuxSystemdServiceBackend() {
6927
7347
  function isInstalled() {
6928
- return existsSync30(getLinuxSystemdServiceFile());
7348
+ return existsSync32(getLinuxSystemdServiceFile());
6929
7349
  }
6930
7350
  async function setup(skipPrompt = false) {
6931
7351
  if (!ensureSystemdAvailable()) {
@@ -7050,7 +7470,7 @@ function createLinuxSystemdServiceBackend() {
7050
7470
  }
7051
7471
  async function uninstall(skipPrompt = false) {
7052
7472
  const serviceFile = getLinuxSystemdServiceFile();
7053
- if (!existsSync30(serviceFile)) {
7473
+ if (!existsSync32(serviceFile)) {
7054
7474
  logger.info(formatBullet("\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002", "warning"));
7055
7475
  return;
7056
7476
  }
@@ -7111,17 +7531,17 @@ function createLinuxSystemdServiceBackend() {
7111
7531
 
7112
7532
  // src/infrastructure/service/macos-launchd.ts
7113
7533
  import { execFileSync as execFileSync6 } from "child_process";
7114
- import { existsSync as existsSync31, mkdirSync as mkdirSync4, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
7115
- import { homedir as homedir29, platform as platform3 } from "os";
7534
+ import { existsSync as existsSync33, mkdirSync as mkdirSync4, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
7535
+ import { homedir as homedir31, platform as platform3 } from "os";
7116
7536
  import { posix as posix2 } from "path";
7117
7537
  var MACOS_LAUNCHD_LABEL = "com.guji.tokenarena";
7118
7538
  function getCurrentUid() {
7119
7539
  return typeof process.getuid === "function" ? process.getuid() : null;
7120
7540
  }
7121
- function getMacosLaunchAgentDir(homePath = homedir29()) {
7541
+ function getMacosLaunchAgentDir(homePath = homedir31()) {
7122
7542
  return posix2.join(homePath, "Library", "LaunchAgents");
7123
7543
  }
7124
- function getMacosLaunchAgentFile(homePath = homedir29()) {
7544
+ function getMacosLaunchAgentFile(homePath = homedir31()) {
7125
7545
  return posix2.join(
7126
7546
  getMacosLaunchAgentDir(homePath),
7127
7547
  `${MACOS_LAUNCHD_LABEL}.plist`
@@ -7248,7 +7668,7 @@ function writeLaunchAgentPlist() {
7248
7668
  label: MACOS_LAUNCHD_LABEL,
7249
7669
  programArguments: [command.execPath, ...command.args],
7250
7670
  environment: getManagedServiceEnvironment(),
7251
- workingDirectory: homedir29(),
7671
+ workingDirectory: homedir31(),
7252
7672
  standardOutPath: stdoutPath,
7253
7673
  standardErrorPath: stderrPath
7254
7674
  });
@@ -7273,7 +7693,7 @@ function bootstrapLaunchAgent() {
7273
7693
  }
7274
7694
  function createMacosLaunchdServiceBackend() {
7275
7695
  function isInstalled() {
7276
- return existsSync31(getMacosLaunchAgentFile());
7696
+ return existsSync33(getMacosLaunchAgentFile());
7277
7697
  }
7278
7698
  async function setup(skipPrompt = false) {
7279
7699
  if (!ensureLaunchctlAvailable()) {
@@ -7414,7 +7834,7 @@ function createMacosLaunchdServiceBackend() {
7414
7834
  }
7415
7835
  async function uninstall(skipPrompt = false) {
7416
7836
  const plistFile = getMacosLaunchAgentFile();
7417
- if (!existsSync31(plistFile)) {
7837
+ if (!existsSync33(plistFile)) {
7418
7838
  logger.info(formatBullet("\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002", "warning"));
7419
7839
  return;
7420
7840
  }
@@ -7525,7 +7945,7 @@ function resolvePowerShellProfilePath() {
7525
7945
  const systemRoot = process.env.SYSTEMROOT || "C:\\Windows";
7526
7946
  const candidates = [
7527
7947
  "pwsh.exe",
7528
- join31(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
7948
+ join33(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
7529
7949
  ];
7530
7950
  for (const command of candidates) {
7531
7951
  try {
@@ -7554,8 +7974,8 @@ function resolvePowerShellProfilePath() {
7554
7974
  function resolveShellAliasSetup(options = {}) {
7555
7975
  const currentPlatform = options.currentPlatform ?? platform5();
7556
7976
  const env = options.env ?? process.env;
7557
- const homeDir = options.homeDir ?? homedir30();
7558
- const pathExists = options.exists ?? existsSync32;
7977
+ const homeDir = options.homeDir ?? homedir32();
7978
+ const pathExists = options.exists ?? existsSync34;
7559
7979
  const shellFromEnv = env.SHELL ? basenameLikeShell(env.SHELL).toLowerCase() : "";
7560
7980
  const shellName = shellFromEnv || (currentPlatform === "win32" ? "powershell" : "");
7561
7981
  const aliasName = "ta";
@@ -7750,9 +8170,9 @@ async function setupShellAlias() {
7750
8170
  return;
7751
8171
  }
7752
8172
  try {
7753
- await mkdir(dirname6(setup.configFile), { recursive: true });
8173
+ await mkdir(dirname7(setup.configFile), { recursive: true });
7754
8174
  let existingContent = "";
7755
- if (existsSync32(setup.configFile)) {
8175
+ if (existsSync34(setup.configFile)) {
7756
8176
  existingContent = await readFile(setup.configFile, "utf-8");
7757
8177
  }
7758
8178
  const normalizedContent = existingContent.toLowerCase();
@@ -7794,7 +8214,7 @@ function log(msg) {
7794
8214
  `);
7795
8215
  }
7796
8216
  function sleep(ms) {
7797
- return new Promise((resolve4) => setTimeout(resolve4, ms));
8217
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
7798
8218
  }
7799
8219
  function getDaemonExitCode(opts = {}) {
7800
8220
  return opts.service ? 0 : 1;
@@ -8011,7 +8431,7 @@ function buildLocalUsageDashboardData(input2) {
8011
8431
 
8012
8432
  // src/infrastructure/runtime/cli-version.ts
8013
8433
  import { readFileSync as readFileSync14 } from "fs";
8014
- import { dirname as dirname7, join as join32 } from "path";
8434
+ import { dirname as dirname8, join as join34 } from "path";
8015
8435
  import { fileURLToPath } from "url";
8016
8436
  var FALLBACK_VERSION = "0.0.0";
8017
8437
  var cachedVersion;
@@ -8019,8 +8439,8 @@ function getCliVersion(metaUrl = import.meta.url) {
8019
8439
  if (cachedVersion) {
8020
8440
  return cachedVersion;
8021
8441
  }
8022
- const packageJsonPath = join32(
8023
- dirname7(fileURLToPath(metaUrl)),
8442
+ const packageJsonPath = join34(
8443
+ dirname8(fileURLToPath(metaUrl)),
8024
8444
  "..",
8025
8445
  "package.json"
8026
8446
  );
@@ -8256,7 +8676,7 @@ async function showLocalUsageDashboard(data) {
8256
8676
  const stdin = process.stdin;
8257
8677
  const stdout = process.stdout;
8258
8678
  const wasRaw = stdin.isRaw;
8259
- await new Promise((resolve4) => {
8679
+ await new Promise((resolve5) => {
8260
8680
  const render = () => {
8261
8681
  stdout.write("\x1B[?25l\x1B[2J\x1B[H");
8262
8682
  stdout.write(
@@ -8273,7 +8693,7 @@ async function showLocalUsageDashboard(data) {
8273
8693
  stdout.off("resize", render);
8274
8694
  if (stdin.isTTY) stdin.setRawMode(wasRaw);
8275
8695
  stdin.pause();
8276
- resolve4();
8696
+ resolve5();
8277
8697
  };
8278
8698
  const onData = (chunk) => {
8279
8699
  const value = chunk.toString("utf8");
@@ -8430,8 +8850,8 @@ async function runSyncCommand(opts = {}) {
8430
8850
  }
8431
8851
 
8432
8852
  // src/commands/uninstall.ts
8433
- import { existsSync as existsSync33, readFileSync as readFileSync15, rmSync as rmSync6, writeFileSync as writeFileSync7 } from "fs";
8434
- import { homedir as homedir31, platform as platform6 } from "os";
8853
+ import { existsSync as existsSync35, readFileSync as readFileSync15, rmSync as rmSync6, writeFileSync as writeFileSync7 } from "fs";
8854
+ import { homedir as homedir33, platform as platform6 } from "os";
8435
8855
  function removeShellAlias() {
8436
8856
  const shell = process.env.SHELL;
8437
8857
  if (!shell) return;
@@ -8440,22 +8860,22 @@ function removeShellAlias() {
8440
8860
  let configFile;
8441
8861
  switch (shellName) {
8442
8862
  case "zsh":
8443
- configFile = `${homedir31()}/.zshrc`;
8863
+ configFile = `${homedir33()}/.zshrc`;
8444
8864
  break;
8445
8865
  case "bash":
8446
- if (platform6() === "darwin" && existsSync33(`${homedir31()}/.bash_profile`)) {
8447
- configFile = `${homedir31()}/.bash_profile`;
8866
+ if (platform6() === "darwin" && existsSync35(`${homedir33()}/.bash_profile`)) {
8867
+ configFile = `${homedir33()}/.bash_profile`;
8448
8868
  } else {
8449
- configFile = `${homedir31()}/.bashrc`;
8869
+ configFile = `${homedir33()}/.bashrc`;
8450
8870
  }
8451
8871
  break;
8452
8872
  case "fish":
8453
- configFile = `${homedir31()}/.config/fish/config.fish`;
8873
+ configFile = `${homedir33()}/.config/fish/config.fish`;
8454
8874
  break;
8455
8875
  default:
8456
8876
  return;
8457
8877
  }
8458
- if (!existsSync33(configFile)) return;
8878
+ if (!existsSync35(configFile)) return;
8459
8879
  try {
8460
8880
  let content = readFileSync15(configFile, "utf-8");
8461
8881
  const aliasPatterns = [
@@ -8494,7 +8914,7 @@ async function runUninstall() {
8494
8914
  const runtimeDir = getRuntimeDirPath();
8495
8915
  const serviceBackend = getServiceBackend();
8496
8916
  const hasInstalledService = serviceBackend?.isInstalled() ?? false;
8497
- const hasLocalArtifacts = existsSync33(configPath) || existsSync33(configDir) || existsSync33(stateDir) || existsSync33(runtimeDir) || hasInstalledService;
8917
+ const hasLocalArtifacts = existsSync35(configPath) || existsSync35(configDir) || existsSync35(stateDir) || existsSync35(runtimeDir) || hasInstalledService;
8498
8918
  if (!hasLocalArtifacts) {
8499
8919
  logger.info(formatHeader("\u5378\u8F7D TokenArena"));
8500
8920
  logger.info(formatBullet("\u672A\u53D1\u73B0\u672C\u5730\u914D\u7F6E\uFF0C\u65E0\u9700\u5378\u8F7D\u3002"));
@@ -8538,22 +8958,22 @@ async function runUninstall() {
8538
8958
  }
8539
8959
  }
8540
8960
  logger.info(formatSection("\u6267\u884C\u7ED3\u679C"));
8541
- if (existsSync33(configPath)) {
8961
+ if (existsSync35(configPath)) {
8542
8962
  deleteConfig();
8543
8963
  logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u6587\u4EF6\u3002", "success"));
8544
8964
  }
8545
- if (existsSync33(configDir)) {
8965
+ if (existsSync35(configDir)) {
8546
8966
  try {
8547
8967
  rmSync6(configDir, { recursive: false, force: true });
8548
8968
  logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u76EE\u5F55\u3002", "success"));
8549
8969
  } catch {
8550
8970
  }
8551
8971
  }
8552
- if (existsSync33(stateDir)) {
8972
+ if (existsSync35(stateDir)) {
8553
8973
  rmSync6(stateDir, { recursive: true, force: true });
8554
8974
  logger.info(formatBullet("\u5DF2\u5220\u9664\u72B6\u6001\u6570\u636E\u3002", "success"));
8555
8975
  }
8556
- if (existsSync33(runtimeDir)) {
8976
+ if (existsSync35(runtimeDir)) {
8557
8977
  rmSync6(runtimeDir, { recursive: true, force: true });
8558
8978
  logger.info(formatBullet("\u5DF2\u5220\u9664\u8FD0\u884C\u65F6\u6570\u636E\u3002", "success"));
8559
8979
  }
@@ -8784,8 +9204,8 @@ function createCli() {
8784
9204
  }
8785
9205
 
8786
9206
  // src/infrastructure/runtime/main-module.ts
8787
- import { existsSync as existsSync34, realpathSync as realpathSync2 } from "fs";
8788
- import { resolve as resolve3 } from "path";
9207
+ import { existsSync as existsSync36, realpathSync as realpathSync2 } from "fs";
9208
+ import { resolve as resolve4 } from "path";
8789
9209
  import { fileURLToPath as fileURLToPath2 } from "url";
8790
9210
  function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
8791
9211
  if (!argvEntry) {
@@ -8795,10 +9215,10 @@ function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
8795
9215
  try {
8796
9216
  return realpathSync2(argvEntry) === realpathSync2(currentModulePath);
8797
9217
  } catch {
8798
- if (!existsSync34(argvEntry)) {
9218
+ if (!existsSync36(argvEntry)) {
8799
9219
  return false;
8800
9220
  }
8801
- return resolve3(argvEntry) === resolve3(currentModulePath);
9221
+ return resolve4(argvEntry) === resolve4(currentModulePath);
8802
9222
  }
8803
9223
  }
8804
9224