@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 +828 -408
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
1323
|
-
import { homedir as
|
|
1324
|
-
import { basename as basename3, dirname as dirname2, join as
|
|
1325
|
-
var ROOT_DIR =
|
|
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 (!
|
|
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 =
|
|
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
|
|
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
|
|
1449
|
-
import { homedir as
|
|
1450
|
-
import { join as
|
|
1451
|
-
var
|
|
1452
|
-
var
|
|
1453
|
-
var DEFAULT_SESSIONS_DIR2 =
|
|
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:
|
|
1457
|
-
name:
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
1608
|
-
import { homedir as
|
|
1609
|
-
import { basename as basename4, join as
|
|
1610
|
-
var DEFAULT_DATA_DIR2 =
|
|
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 ?
|
|
1871
|
+
env.XDG_DATA_HOME ? join11(env.XDG_DATA_HOME, "opencode") : void 0,
|
|
1620
1872
|
DEFAULT_DATA_DIR2,
|
|
1621
|
-
env.LOCALAPPDATA ?
|
|
1622
|
-
env.APPDATA ?
|
|
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) =>
|
|
1968
|
+
return this.resolveRoots().some((dir) => existsSync11(dir));
|
|
1717
1969
|
}
|
|
1718
1970
|
async parseRoot(rootDir) {
|
|
1719
|
-
const dbPath =
|
|
1720
|
-
const messagesDir =
|
|
1721
|
-
if (
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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
|
|
1857
|
-
import { homedir as
|
|
1858
|
-
import { join as
|
|
1859
|
-
var
|
|
1860
|
-
var
|
|
1861
|
-
var DEFAULT_DATA_DIR3 =
|
|
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:
|
|
1865
|
-
name:
|
|
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 =
|
|
1876
|
-
const roots = [
|
|
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) =>
|
|
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) =>
|
|
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 =
|
|
1898
|
-
if (!
|
|
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 =
|
|
1910
|
-
if (!
|
|
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 =
|
|
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:
|
|
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:
|
|
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) =>
|
|
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
|
|
1998
|
-
import { homedir as
|
|
1999
|
-
import { join as
|
|
2000
|
-
var
|
|
2001
|
-
var
|
|
2002
|
-
var DEFAULT_DATA_DIR4 =
|
|
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:
|
|
2006
|
-
name:
|
|
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
|
|
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 (!
|
|
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 =
|
|
2029
|
-
if (!
|
|
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(
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
2136
|
-
import { homedir as
|
|
2137
|
-
import { join as
|
|
2138
|
-
var
|
|
2139
|
-
var
|
|
2140
|
-
var DEFAULT_SESSIONS_DIR3 =
|
|
2141
|
-
var DEFAULT_CONFIG_PATH =
|
|
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:
|
|
2158
|
-
name:
|
|
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
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 (
|
|
2442
|
+
if (existsSync14(newWireFile)) {
|
|
2191
2443
|
results.push({ filePath: newWireFile, workDirHash: workDir.name });
|
|
2192
2444
|
continue;
|
|
2193
2445
|
}
|
|
2194
|
-
const legacyWireFile =
|
|
2195
|
-
if (
|
|
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 :
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
2392
|
-
import { homedir as
|
|
2393
|
-
import { basename as basename5, join as
|
|
2394
|
-
var
|
|
2395
|
-
var
|
|
2396
|
-
var DEFAULT_CONFIG_DIR =
|
|
2397
|
-
var DEFAULT_SESSIONS_DIR4 =
|
|
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 ?
|
|
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:
|
|
2456
|
-
name:
|
|
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:
|
|
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:
|
|
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) =>
|
|
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
|
|
2538
|
-
import { homedir as
|
|
2539
|
-
import { basename as basename6, dirname as dirname3, join as
|
|
2540
|
-
var
|
|
2541
|
-
var
|
|
2542
|
-
var DEFAULT_DATA_DIR5 =
|
|
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:
|
|
2546
|
-
name:
|
|
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 (!
|
|
2804
|
+
if (!existsSync16(dir)) return results;
|
|
2553
2805
|
try {
|
|
2554
2806
|
for (const entry of readdirSync8(dir, { withFileTypes: true })) {
|
|
2555
|
-
const fullPath =
|
|
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:
|
|
2864
|
+
source: TOOL_ID11,
|
|
2613
2865
|
project,
|
|
2614
2866
|
timestamp,
|
|
2615
2867
|
role
|
|
2616
2868
|
});
|
|
2617
2869
|
}
|
|
2618
|
-
const settingsPath =
|
|
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:
|
|
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
|
|
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
|
|
2670
|
-
import { homedir as
|
|
2671
|
-
import { join as
|
|
2672
|
-
var
|
|
2673
|
-
var
|
|
2674
|
-
var DEFAULT_SESSIONS_DIR5 =
|
|
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:
|
|
2678
|
-
name:
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
2828
|
-
import { homedir as
|
|
2829
|
-
import { join as
|
|
2830
|
-
var
|
|
2831
|
-
var
|
|
2832
|
-
var DEFAULT_USAGE_PATH =
|
|
2833
|
-
var DEFAULT_WORKSPACE_PATH =
|
|
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:
|
|
2837
|
-
name:
|
|
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
|
|
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 =
|
|
2857
|
-
const modelName =
|
|
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:
|
|
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 (!
|
|
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 =
|
|
2924
|
-
const chatsPath =
|
|
2925
|
-
const sessionsPath =
|
|
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:
|
|
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 (!
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
|
3084
|
-
import { basename as basename7, join as
|
|
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:
|
|
3350
|
+
dataDir: join19(homedir18(), ".cline")
|
|
3099
3351
|
};
|
|
3100
3352
|
function getHostRoots() {
|
|
3101
3353
|
const out = [];
|
|
3102
3354
|
if (process.platform === "darwin") {
|
|
3103
|
-
const base =
|
|
3104
|
-
for (const h of HOSTS) out.push(
|
|
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() ||
|
|
3107
|
-
for (const h of HOSTS) out.push(
|
|
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() ||
|
|
3110
|
-
for (const h of HOSTS) out.push(
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
3239
|
-
import { join as
|
|
3240
|
-
var KIROAGENT_RELATIVE =
|
|
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
|
|
3244
|
-
|
|
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() ||
|
|
3253
|
-
return
|
|
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() ||
|
|
3256
|
-
return
|
|
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
|
|
3519
|
+
return existsSync19(r) ? r : null;
|
|
3268
3520
|
}
|
|
3269
3521
|
const def = getDefaultBasePath();
|
|
3270
|
-
return
|
|
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(
|
|
3292
|
-
const queryPath =
|
|
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 (
|
|
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 =
|
|
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(
|
|
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 =
|
|
3407
|
-
const jsonlPath =
|
|
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 (
|
|
3662
|
+
if (existsSync19(dbPath)) {
|
|
3411
3663
|
rows = readDb(dbPath);
|
|
3412
|
-
} else if (
|
|
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
|
|
3464
|
-
import { basename as basename8, join as
|
|
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 = [
|
|
3731
|
+
roots = [join21(homedir20(), "Library", "Application Support")];
|
|
3480
3732
|
} else if (process.platform === "win32") {
|
|
3481
3733
|
roots = [
|
|
3482
|
-
process.env.APPDATA?.trim() ||
|
|
3734
|
+
process.env.APPDATA?.trim() || join21(homedir20(), "AppData", "Roaming")
|
|
3483
3735
|
];
|
|
3484
3736
|
} else {
|
|
3485
|
-
roots = [process.env.XDG_CONFIG_HOME?.trim() ||
|
|
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(
|
|
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 =
|
|
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 =
|
|
3771
|
+
const tasksDir = join21(extDir, "tasks");
|
|
3520
3772
|
const index = readJsonSafe2(
|
|
3521
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3627
|
-
import { homedir as
|
|
3628
|
-
import { join as
|
|
3629
|
-
var DEFAULT_DATA_DIR6 =
|
|
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
|
|
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
|
|
3684
|
-
import { homedir as
|
|
3685
|
-
import { dirname as dirname4, join as
|
|
3686
|
-
var
|
|
3687
|
-
var
|
|
3688
|
-
var STATE_DB_RELATIVE =
|
|
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
|
|
3695
|
-
|
|
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() ||
|
|
3704
|
-
return
|
|
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() ||
|
|
3707
|
-
return
|
|
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
|
|
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 :
|
|
3970
|
+
return r.endsWith(".vscdb") ? r : join23(r, STATE_DB_RELATIVE);
|
|
3719
3971
|
}) : [getDefaultStateDbPath()];
|
|
3720
3972
|
for (const c of candidates) {
|
|
3721
|
-
if (
|
|
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(
|
|
3762
|
-
const queryPath =
|
|
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 (
|
|
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:
|
|
3896
|
-
name:
|
|
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 || !
|
|
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:
|
|
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
|
|
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
|
|
3982
|
-
import { existsSync as
|
|
3983
|
-
import { homedir as
|
|
3984
|
-
import { dirname as dirname5, join as
|
|
3985
|
-
var
|
|
3986
|
-
var
|
|
3987
|
-
var DEFAULT_DB_PATH3 =
|
|
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:
|
|
4023
|
-
name:
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
4369
|
+
function buildSessions2(input2) {
|
|
4118
4370
|
const drafts = /* @__PURE__ */ new Map();
|
|
4119
4371
|
for (const row of input2.sessionRows) {
|
|
4120
|
-
const sessionId =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
4168
|
-
const host =
|
|
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:
|
|
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 (!
|
|
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:
|
|
4263
|
-
source:
|
|
4264
|
-
model:
|
|
4265
|
-
project:
|
|
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:
|
|
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
|
|
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
|
|
4306
|
-
import { homedir as
|
|
4307
|
-
import { basename as basename9, join as
|
|
4308
|
-
var
|
|
4309
|
-
var
|
|
4310
|
-
var DEFAULT_PROJECTS_DIR =
|
|
4311
|
-
var DEFAULT_LOGS_DIR =
|
|
4312
|
-
var DEFAULT_RUNS_DIR =
|
|
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:
|
|
4319
|
-
name:
|
|
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 =
|
|
4610
|
+
const home = homedir24();
|
|
4359
4611
|
const candidates = [
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4612
|
+
join25(home, ".local", "bin", "qodercli"),
|
|
4613
|
+
join25(home, ".qoder", "bin", "qodercli"),
|
|
4614
|
+
join25(home, ".qoder-cli")
|
|
4363
4615
|
];
|
|
4364
|
-
return candidates.some((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:
|
|
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 (!
|
|
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:
|
|
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 (!
|
|
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 =
|
|
4522
|
-
const logPath =
|
|
4523
|
-
if (!
|
|
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(
|
|
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() ||
|
|
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
|
|
4548
|
-
import { homedir as
|
|
4549
|
-
import { basename as basename10, join as
|
|
4550
|
-
var
|
|
4551
|
-
var
|
|
4552
|
-
var DEFAULT_DATA_DIR7 =
|
|
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:
|
|
4556
|
-
name:
|
|
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:
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
4637
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
4737
|
-
import { homedir as
|
|
4738
|
-
import { basename as basename11, join as
|
|
4739
|
-
var
|
|
4740
|
-
var
|
|
4741
|
-
var DEFAULT_SESSIONS_DIR6 =
|
|
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 ?
|
|
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:
|
|
4804
|
-
name:
|
|
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:
|
|
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:
|
|
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) =>
|
|
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
|
|
4885
|
-
import { homedir as
|
|
4886
|
-
import { basename as basename12, join as
|
|
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
|
|
4889
|
-
var
|
|
4890
|
-
var DEFAULT_SESSIONS_DIR7 =
|
|
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 ?
|
|
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 (!
|
|
5236
|
+
if (!existsSync26(dir)) return results;
|
|
4985
5237
|
try {
|
|
4986
5238
|
for (const entry of readdirSync14(dir, { withFileTypes: true })) {
|
|
4987
|
-
const fullPath =
|
|
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:
|
|
5019
|
-
name:
|
|
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:
|
|
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:
|
|
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:
|
|
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) =>
|
|
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
|
|
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
|
|
5555
|
+
import { join as join31 } from "path";
|
|
5136
5556
|
|
|
5137
5557
|
// src/infrastructure/xdg.ts
|
|
5138
|
-
import { homedir as
|
|
5139
|
-
import { join as
|
|
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 ||
|
|
5561
|
+
return process.env.XDG_CONFIG_HOME || join30(homedir29(), ".config");
|
|
5142
5562
|
}
|
|
5143
5563
|
function getStateHome() {
|
|
5144
|
-
return process.env.XDG_STATE_HOME ||
|
|
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 =
|
|
5571
|
+
var CONFIG_DIR = join31(getConfigHome(), "tokenarena");
|
|
5152
5572
|
var isDev = process.env.TOKEN_ARENA_DEV === "1";
|
|
5153
|
-
var CONFIG_FILE =
|
|
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 (!
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
6398
|
+
resolve5(null);
|
|
5979
6399
|
return;
|
|
5980
6400
|
}
|
|
5981
|
-
|
|
6401
|
+
resolve5(settings);
|
|
5982
6402
|
} catch {
|
|
5983
|
-
|
|
6403
|
+
resolve5(null);
|
|
5984
6404
|
}
|
|
5985
6405
|
});
|
|
5986
6406
|
}
|
|
5987
6407
|
);
|
|
5988
|
-
req.on("error", () =>
|
|
6408
|
+
req.on("error", () => resolve5(null));
|
|
5989
6409
|
req.on("timeout", () => {
|
|
5990
6410
|
req.destroy();
|
|
5991
|
-
|
|
6411
|
+
resolve5(null);
|
|
5992
6412
|
});
|
|
5993
6413
|
req.end();
|
|
5994
6414
|
});
|
|
5995
6415
|
}
|
|
5996
6416
|
async deleteDeviceData(deviceId) {
|
|
5997
|
-
return new Promise((
|
|
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
|
-
|
|
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
|
|
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
|
|
6478
|
+
import { join as join32 } from "path";
|
|
6059
6479
|
var APP_NAME = "tokenarena";
|
|
6060
6480
|
function getRuntimeDirPath() {
|
|
6061
|
-
return
|
|
6481
|
+
return join32(getRuntimeDir(), APP_NAME);
|
|
6062
6482
|
}
|
|
6063
6483
|
function getStateDir() {
|
|
6064
|
-
return
|
|
6484
|
+
return join32(getStateHome(), APP_NAME);
|
|
6065
6485
|
}
|
|
6066
6486
|
function getSyncLockPath() {
|
|
6067
|
-
return
|
|
6487
|
+
return join32(getRuntimeDirPath(), "sync.lock");
|
|
6068
6488
|
}
|
|
6069
6489
|
function getSyncStatePath() {
|
|
6070
|
-
return
|
|
6490
|
+
return join32(getStateDir(), "status.json");
|
|
6071
6491
|
}
|
|
6072
6492
|
function getUploadManifestPath() {
|
|
6073
|
-
return
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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:
|
|
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
|
|
7208
|
+
import { existsSync as existsSync34 } from "fs";
|
|
6789
7209
|
import { appendFile, mkdir, readFile } from "fs/promises";
|
|
6790
|
-
import { homedir as
|
|
6791
|
-
import { dirname as
|
|
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
|
|
6799
|
-
import { homedir as
|
|
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 =
|
|
7288
|
+
function getLinuxSystemdServiceDir(homePath = homedir30()) {
|
|
6869
7289
|
return posix.join(homePath, ".config", "systemd", "user");
|
|
6870
7290
|
}
|
|
6871
|
-
function getLinuxSystemdServiceFile(homePath =
|
|
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
|
|
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 (!
|
|
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
|
|
7115
|
-
import { homedir as
|
|
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 =
|
|
7541
|
+
function getMacosLaunchAgentDir(homePath = homedir31()) {
|
|
7122
7542
|
return posix2.join(homePath, "Library", "LaunchAgents");
|
|
7123
7543
|
}
|
|
7124
|
-
function getMacosLaunchAgentFile(homePath =
|
|
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:
|
|
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
|
|
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 (!
|
|
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
|
-
|
|
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 ??
|
|
7558
|
-
const pathExists = options.exists ??
|
|
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(
|
|
8173
|
+
await mkdir(dirname7(setup.configFile), { recursive: true });
|
|
7754
8174
|
let existingContent = "";
|
|
7755
|
-
if (
|
|
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((
|
|
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
|
|
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 =
|
|
8023
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
8434
|
-
import { homedir as
|
|
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 = `${
|
|
8863
|
+
configFile = `${homedir33()}/.zshrc`;
|
|
8444
8864
|
break;
|
|
8445
8865
|
case "bash":
|
|
8446
|
-
if (platform6() === "darwin" &&
|
|
8447
|
-
configFile = `${
|
|
8866
|
+
if (platform6() === "darwin" && existsSync35(`${homedir33()}/.bash_profile`)) {
|
|
8867
|
+
configFile = `${homedir33()}/.bash_profile`;
|
|
8448
8868
|
} else {
|
|
8449
|
-
configFile = `${
|
|
8869
|
+
configFile = `${homedir33()}/.bashrc`;
|
|
8450
8870
|
}
|
|
8451
8871
|
break;
|
|
8452
8872
|
case "fish":
|
|
8453
|
-
configFile = `${
|
|
8873
|
+
configFile = `${homedir33()}/.config/fish/config.fish`;
|
|
8454
8874
|
break;
|
|
8455
8875
|
default:
|
|
8456
8876
|
return;
|
|
8457
8877
|
}
|
|
8458
|
-
if (!
|
|
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 =
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
8788
|
-
import { resolve as
|
|
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 (!
|
|
9218
|
+
if (!existsSync36(argvEntry)) {
|
|
8799
9219
|
return false;
|
|
8800
9220
|
}
|
|
8801
|
-
return
|
|
9221
|
+
return resolve4(argvEntry) === resolve4(currentModulePath);
|
|
8802
9222
|
}
|
|
8803
9223
|
}
|
|
8804
9224
|
|