@poco-ai/tokenarena 0.2.0 → 0.2.2-beta.2
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 +678 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -211,6 +211,17 @@ function readFileSafe(filePath) {
|
|
|
211
211
|
return null;
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
|
+
function parseJsonl(content) {
|
|
215
|
+
const results = [];
|
|
216
|
+
for (const line of content.split("\n")) {
|
|
217
|
+
if (!line.trim()) continue;
|
|
218
|
+
try {
|
|
219
|
+
results.push(JSON.parse(line));
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return results;
|
|
224
|
+
}
|
|
214
225
|
function extractSessionId(filePath) {
|
|
215
226
|
return basename(filePath, ".jsonl");
|
|
216
227
|
}
|
|
@@ -1098,37 +1109,657 @@ var OpenClawParser = class {
|
|
|
1098
1109
|
};
|
|
1099
1110
|
registerParser(new OpenClawParser());
|
|
1100
1111
|
|
|
1112
|
+
// src/parsers/qwen-code.ts
|
|
1113
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6 } from "fs";
|
|
1114
|
+
import { homedir as homedir7 } from "os";
|
|
1115
|
+
import { join as join8 } from "path";
|
|
1116
|
+
var TOOL_ID = "qwen-code";
|
|
1117
|
+
var TOOL_NAME = "Qwen Code";
|
|
1118
|
+
var DEFAULT_DATA_DIR2 = join8(homedir7(), ".qwen", "tmp");
|
|
1119
|
+
function createToolDefinition(dataDir) {
|
|
1120
|
+
return {
|
|
1121
|
+
id: TOOL_ID,
|
|
1122
|
+
name: TOOL_NAME,
|
|
1123
|
+
dataDir
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
function toSafeNumber(value) {
|
|
1127
|
+
const numberValue = Number(value);
|
|
1128
|
+
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
1129
|
+
}
|
|
1130
|
+
function getPathLeaf2(value) {
|
|
1131
|
+
const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1132
|
+
const leaf = normalized.split("/").filter(Boolean).pop();
|
|
1133
|
+
return leaf || "unknown";
|
|
1134
|
+
}
|
|
1135
|
+
function normalizeForPrefix(value) {
|
|
1136
|
+
return value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1137
|
+
}
|
|
1138
|
+
function findSessionFiles2(baseDir) {
|
|
1139
|
+
const results = [];
|
|
1140
|
+
if (!existsSync8(baseDir)) return results;
|
|
1141
|
+
try {
|
|
1142
|
+
for (const entry of readdirSync6(baseDir, { withFileTypes: true })) {
|
|
1143
|
+
if (!entry.isDirectory()) continue;
|
|
1144
|
+
const chatsDir = join8(baseDir, entry.name, "chats");
|
|
1145
|
+
if (!existsSync8(chatsDir)) continue;
|
|
1146
|
+
try {
|
|
1147
|
+
for (const file of readdirSync6(chatsDir)) {
|
|
1148
|
+
if (file.endsWith(".jsonl")) {
|
|
1149
|
+
results.push(join8(chatsDir, file));
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
} catch {
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
} catch {
|
|
1156
|
+
return results;
|
|
1157
|
+
}
|
|
1158
|
+
return results;
|
|
1159
|
+
}
|
|
1160
|
+
function resolveQwenProject(cwd, filePath, dataDir = DEFAULT_DATA_DIR2) {
|
|
1161
|
+
if (cwd) {
|
|
1162
|
+
return getPathLeaf2(cwd);
|
|
1163
|
+
}
|
|
1164
|
+
const normalizedFilePath = normalizeForPrefix(filePath);
|
|
1165
|
+
const normalizedDataDir = normalizeForPrefix(dataDir);
|
|
1166
|
+
const prefix = `${normalizedDataDir}/`;
|
|
1167
|
+
if (!normalizedFilePath.startsWith(prefix)) {
|
|
1168
|
+
return "unknown";
|
|
1169
|
+
}
|
|
1170
|
+
const relativePath = normalizedFilePath.slice(prefix.length);
|
|
1171
|
+
const projectId = relativePath.split("/")[0];
|
|
1172
|
+
return projectId || "unknown";
|
|
1173
|
+
}
|
|
1174
|
+
var QwenCodeParser = class {
|
|
1175
|
+
constructor(dataDir = DEFAULT_DATA_DIR2) {
|
|
1176
|
+
this.dataDir = dataDir;
|
|
1177
|
+
this.tool = createToolDefinition(dataDir);
|
|
1178
|
+
}
|
|
1179
|
+
tool;
|
|
1180
|
+
async parse() {
|
|
1181
|
+
const sessionFiles = findSessionFiles2(this.dataDir);
|
|
1182
|
+
if (sessionFiles.length === 0) {
|
|
1183
|
+
return { buckets: [], sessions: [] };
|
|
1184
|
+
}
|
|
1185
|
+
const entries = [];
|
|
1186
|
+
const sessionEvents = [];
|
|
1187
|
+
const seenUuids = /* @__PURE__ */ new Set();
|
|
1188
|
+
for (const filePath of sessionFiles) {
|
|
1189
|
+
const content = readFileSafe(filePath);
|
|
1190
|
+
if (!content) continue;
|
|
1191
|
+
const sessionId = filePath;
|
|
1192
|
+
for (const line of content.split("\n")) {
|
|
1193
|
+
if (!line.trim()) continue;
|
|
1194
|
+
try {
|
|
1195
|
+
const obj = JSON.parse(line);
|
|
1196
|
+
if (!obj.timestamp) continue;
|
|
1197
|
+
const timestamp = new Date(obj.timestamp);
|
|
1198
|
+
if (Number.isNaN(timestamp.getTime())) continue;
|
|
1199
|
+
const project = resolveQwenProject(obj.cwd, filePath, this.dataDir);
|
|
1200
|
+
if (obj.type === "user" || obj.type === "assistant") {
|
|
1201
|
+
sessionEvents.push({
|
|
1202
|
+
sessionId,
|
|
1203
|
+
source: TOOL_ID,
|
|
1204
|
+
project,
|
|
1205
|
+
timestamp,
|
|
1206
|
+
role: obj.type
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
if (obj.type !== "assistant") continue;
|
|
1210
|
+
const usage = obj.usageMetadata || obj.usage;
|
|
1211
|
+
if (!usage) continue;
|
|
1212
|
+
const totalInput = toSafeNumber(usage.promptTokenCount) || toSafeNumber(usage.input_tokens);
|
|
1213
|
+
const totalOutput = toSafeNumber(usage.candidatesTokenCount) || toSafeNumber(usage.output_tokens);
|
|
1214
|
+
const cachedTokens = toSafeNumber(usage.cachedContentTokenCount);
|
|
1215
|
+
const reasoningTokens = toSafeNumber(usage.thoughtsTokenCount);
|
|
1216
|
+
if (totalInput === 0 && totalOutput === 0 && cachedTokens === 0 && reasoningTokens === 0) {
|
|
1217
|
+
continue;
|
|
1218
|
+
}
|
|
1219
|
+
if (obj.uuid) {
|
|
1220
|
+
if (seenUuids.has(obj.uuid)) continue;
|
|
1221
|
+
seenUuids.add(obj.uuid);
|
|
1222
|
+
}
|
|
1223
|
+
entries.push({
|
|
1224
|
+
sessionId,
|
|
1225
|
+
source: TOOL_ID,
|
|
1226
|
+
model: obj.model || "unknown",
|
|
1227
|
+
project,
|
|
1228
|
+
timestamp,
|
|
1229
|
+
inputTokens: Math.max(0, totalInput - cachedTokens),
|
|
1230
|
+
outputTokens: Math.max(0, totalOutput - reasoningTokens),
|
|
1231
|
+
reasoningTokens,
|
|
1232
|
+
cachedTokens
|
|
1233
|
+
});
|
|
1234
|
+
} catch {
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
return {
|
|
1239
|
+
buckets: aggregateToBuckets(entries),
|
|
1240
|
+
sessions: extractSessions(sessionEvents, entries)
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
isInstalled() {
|
|
1244
|
+
return existsSync8(this.dataDir);
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
registerParser(new QwenCodeParser());
|
|
1248
|
+
|
|
1249
|
+
// src/parsers/kimi-code.ts
|
|
1250
|
+
import { existsSync as existsSync9, readdirSync as readdirSync7 } from "fs";
|
|
1251
|
+
import { homedir as homedir8 } from "os";
|
|
1252
|
+
import { join as join9 } from "path";
|
|
1253
|
+
var TOOL_ID2 = "kimi-code";
|
|
1254
|
+
var TOOL_NAME2 = "Kimi Code";
|
|
1255
|
+
var DEFAULT_SESSIONS_DIR = join9(homedir8(), ".kimi", "sessions");
|
|
1256
|
+
var DEFAULT_CONFIG_PATH = join9(homedir8(), ".kimi", "kimi.json");
|
|
1257
|
+
var USER_EVENT_TYPES = /* @__PURE__ */ new Set(["UserMessage", "user_message", "Input"]);
|
|
1258
|
+
var ASSISTANT_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
1259
|
+
"AssistantMessage",
|
|
1260
|
+
"assistant_message",
|
|
1261
|
+
"Output",
|
|
1262
|
+
"ModelOutput",
|
|
1263
|
+
"AssistantOutput"
|
|
1264
|
+
]);
|
|
1265
|
+
function createToolDefinition2(dataDir) {
|
|
1266
|
+
return {
|
|
1267
|
+
id: TOOL_ID2,
|
|
1268
|
+
name: TOOL_NAME2,
|
|
1269
|
+
dataDir
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
function toSafeNumber2(value) {
|
|
1273
|
+
const numberValue = Number(value);
|
|
1274
|
+
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
1275
|
+
}
|
|
1276
|
+
function getPathLeaf3(value) {
|
|
1277
|
+
const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1278
|
+
const leaf = normalized.split("/").filter(Boolean).pop();
|
|
1279
|
+
return leaf || "unknown";
|
|
1280
|
+
}
|
|
1281
|
+
function findWireFiles(baseDir) {
|
|
1282
|
+
const results = [];
|
|
1283
|
+
if (!existsSync9(baseDir)) return results;
|
|
1284
|
+
try {
|
|
1285
|
+
for (const workDir of readdirSync7(baseDir, { withFileTypes: true })) {
|
|
1286
|
+
if (!workDir.isDirectory()) continue;
|
|
1287
|
+
const workDirPath = join9(baseDir, workDir.name);
|
|
1288
|
+
try {
|
|
1289
|
+
for (const session of readdirSync7(workDirPath, {
|
|
1290
|
+
withFileTypes: true
|
|
1291
|
+
})) {
|
|
1292
|
+
if (!session.isDirectory()) continue;
|
|
1293
|
+
const wireFile = join9(workDirPath, session.name, "wire.jsonl");
|
|
1294
|
+
if (existsSync9(wireFile)) {
|
|
1295
|
+
results.push({ filePath: wireFile, workDirHash: workDir.name });
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
} catch {
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
} catch {
|
|
1302
|
+
return results;
|
|
1303
|
+
}
|
|
1304
|
+
return results;
|
|
1305
|
+
}
|
|
1306
|
+
function parseTimestamp(value) {
|
|
1307
|
+
if (value == null) return null;
|
|
1308
|
+
const timestamp = new Date(value);
|
|
1309
|
+
return Number.isNaN(timestamp.getTime()) ? null : timestamp;
|
|
1310
|
+
}
|
|
1311
|
+
function classifyKimiRole(type, payload) {
|
|
1312
|
+
if (payload?.role === "user" || payload?.role === "assistant") {
|
|
1313
|
+
return payload.role;
|
|
1314
|
+
}
|
|
1315
|
+
if (type && USER_EVENT_TYPES.has(type)) {
|
|
1316
|
+
return "user";
|
|
1317
|
+
}
|
|
1318
|
+
if (type && ASSISTANT_EVENT_TYPES.has(type)) {
|
|
1319
|
+
return "assistant";
|
|
1320
|
+
}
|
|
1321
|
+
if (type?.toLowerCase().includes("assistant")) {
|
|
1322
|
+
return "assistant";
|
|
1323
|
+
}
|
|
1324
|
+
return null;
|
|
1325
|
+
}
|
|
1326
|
+
function loadProjectMap(configPath) {
|
|
1327
|
+
const projectMap = /* @__PURE__ */ new Map();
|
|
1328
|
+
const content = readFileSafe(configPath);
|
|
1329
|
+
if (!content) return projectMap;
|
|
1330
|
+
try {
|
|
1331
|
+
const config = JSON.parse(content);
|
|
1332
|
+
const workspaces = config.workspaces || config.projects || {};
|
|
1333
|
+
for (const [hash, info] of Object.entries(workspaces)) {
|
|
1334
|
+
const pathValue = typeof info === "string" ? info : info.path || info.dir || void 0;
|
|
1335
|
+
if (!pathValue) continue;
|
|
1336
|
+
projectMap.set(hash, getPathLeaf3(pathValue));
|
|
1337
|
+
}
|
|
1338
|
+
} catch {
|
|
1339
|
+
}
|
|
1340
|
+
return projectMap;
|
|
1341
|
+
}
|
|
1342
|
+
var KimiCodeParser = class {
|
|
1343
|
+
tool;
|
|
1344
|
+
sessionsDir;
|
|
1345
|
+
configPath;
|
|
1346
|
+
constructor(options = {}) {
|
|
1347
|
+
this.sessionsDir = options.sessionsDir || DEFAULT_SESSIONS_DIR;
|
|
1348
|
+
this.configPath = options.configPath || DEFAULT_CONFIG_PATH;
|
|
1349
|
+
this.tool = createToolDefinition2(this.sessionsDir);
|
|
1350
|
+
}
|
|
1351
|
+
async parse() {
|
|
1352
|
+
const wireFiles = findWireFiles(this.sessionsDir);
|
|
1353
|
+
if (wireFiles.length === 0) {
|
|
1354
|
+
return { buckets: [], sessions: [] };
|
|
1355
|
+
}
|
|
1356
|
+
const projectMap = loadProjectMap(this.configPath);
|
|
1357
|
+
const entries = [];
|
|
1358
|
+
const sessionEvents = [];
|
|
1359
|
+
const seenMessageIds = /* @__PURE__ */ new Set();
|
|
1360
|
+
for (const { filePath, workDirHash } of wireFiles) {
|
|
1361
|
+
const content = readFileSafe(filePath);
|
|
1362
|
+
if (!content) continue;
|
|
1363
|
+
const sessionId = filePath;
|
|
1364
|
+
const project = projectMap.get(workDirHash) || workDirHash;
|
|
1365
|
+
let currentModel = "unknown";
|
|
1366
|
+
let lastTimestampRaw;
|
|
1367
|
+
for (const line of content.split("\n")) {
|
|
1368
|
+
if (!line.trim()) continue;
|
|
1369
|
+
let obj;
|
|
1370
|
+
try {
|
|
1371
|
+
obj = JSON.parse(line);
|
|
1372
|
+
} catch {
|
|
1373
|
+
continue;
|
|
1374
|
+
}
|
|
1375
|
+
const payload = obj.payload;
|
|
1376
|
+
if (!payload) continue;
|
|
1377
|
+
if (payload.model) {
|
|
1378
|
+
currentModel = payload.model;
|
|
1379
|
+
}
|
|
1380
|
+
const timestampValue = payload.timestamp ?? obj.timestamp ?? lastTimestampRaw;
|
|
1381
|
+
const timestamp = parseTimestamp(timestampValue);
|
|
1382
|
+
if (payload.timestamp != null) {
|
|
1383
|
+
lastTimestampRaw = payload.timestamp;
|
|
1384
|
+
} else if (obj.timestamp != null) {
|
|
1385
|
+
lastTimestampRaw = obj.timestamp;
|
|
1386
|
+
}
|
|
1387
|
+
const role = classifyKimiRole(obj.type, payload);
|
|
1388
|
+
if (role && timestamp) {
|
|
1389
|
+
sessionEvents.push({
|
|
1390
|
+
sessionId,
|
|
1391
|
+
source: TOOL_ID2,
|
|
1392
|
+
project,
|
|
1393
|
+
timestamp,
|
|
1394
|
+
role
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
if (obj.type !== "StatusUpdate") continue;
|
|
1398
|
+
const tokenUsage = payload.token_usage;
|
|
1399
|
+
if (!tokenUsage || !timestamp) continue;
|
|
1400
|
+
const inputTokens = toSafeNumber2(tokenUsage.input_other);
|
|
1401
|
+
const outputTokens = toSafeNumber2(tokenUsage.output);
|
|
1402
|
+
const cachedTokens = toSafeNumber2(tokenUsage.input_cache_read);
|
|
1403
|
+
const cacheCreateTokens = toSafeNumber2(tokenUsage.input_cache_creation);
|
|
1404
|
+
if (inputTokens === 0 && outputTokens === 0 && cachedTokens === 0 && cacheCreateTokens === 0) {
|
|
1405
|
+
continue;
|
|
1406
|
+
}
|
|
1407
|
+
if (payload.message_id) {
|
|
1408
|
+
if (seenMessageIds.has(payload.message_id)) continue;
|
|
1409
|
+
seenMessageIds.add(payload.message_id);
|
|
1410
|
+
}
|
|
1411
|
+
if (!role) {
|
|
1412
|
+
sessionEvents.push({
|
|
1413
|
+
sessionId,
|
|
1414
|
+
source: TOOL_ID2,
|
|
1415
|
+
project,
|
|
1416
|
+
timestamp,
|
|
1417
|
+
role: "assistant"
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
entries.push({
|
|
1421
|
+
sessionId,
|
|
1422
|
+
source: TOOL_ID2,
|
|
1423
|
+
model: currentModel,
|
|
1424
|
+
project,
|
|
1425
|
+
timestamp,
|
|
1426
|
+
inputTokens,
|
|
1427
|
+
outputTokens,
|
|
1428
|
+
reasoningTokens: 0,
|
|
1429
|
+
cachedTokens
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
return {
|
|
1434
|
+
buckets: aggregateToBuckets(entries),
|
|
1435
|
+
sessions: extractSessions(sessionEvents, entries)
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
isInstalled() {
|
|
1439
|
+
return existsSync9(this.sessionsDir);
|
|
1440
|
+
}
|
|
1441
|
+
};
|
|
1442
|
+
registerParser(new KimiCodeParser());
|
|
1443
|
+
|
|
1444
|
+
// src/parsers/droid.ts
|
|
1445
|
+
import { existsSync as existsSync10, readdirSync as readdirSync8 } from "fs";
|
|
1446
|
+
import { homedir as homedir9 } from "os";
|
|
1447
|
+
import { basename as basename4, dirname as dirname2, join as join10 } from "path";
|
|
1448
|
+
var TOOL_ID3 = "droid";
|
|
1449
|
+
var TOOL_NAME3 = "Droid";
|
|
1450
|
+
var DEFAULT_DATA_DIR3 = join10(homedir9(), ".factory", "sessions");
|
|
1451
|
+
function createToolDefinition3(dataDir) {
|
|
1452
|
+
return {
|
|
1453
|
+
id: TOOL_ID3,
|
|
1454
|
+
name: TOOL_NAME3,
|
|
1455
|
+
dataDir
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
function findSessionFiles3(dir) {
|
|
1459
|
+
const results = [];
|
|
1460
|
+
if (!existsSync10(dir)) return results;
|
|
1461
|
+
try {
|
|
1462
|
+
for (const entry of readdirSync8(dir, { withFileTypes: true })) {
|
|
1463
|
+
const fullPath = join10(dir, entry.name);
|
|
1464
|
+
if (entry.isDirectory()) {
|
|
1465
|
+
results.push(...findSessionFiles3(fullPath));
|
|
1466
|
+
} else if (entry.isFile() && entry.name.endsWith(".jsonl") && !entry.name.endsWith(".settings.json")) {
|
|
1467
|
+
results.push(fullPath);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
} catch {
|
|
1471
|
+
}
|
|
1472
|
+
return results;
|
|
1473
|
+
}
|
|
1474
|
+
function extractDroidProject(slug) {
|
|
1475
|
+
const parts = slug.split("-").filter(Boolean);
|
|
1476
|
+
return parts.length > 0 ? parts[parts.length - 1] : "unknown";
|
|
1477
|
+
}
|
|
1478
|
+
function toSafeNumber3(value) {
|
|
1479
|
+
const numberValue = Number(value);
|
|
1480
|
+
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
1481
|
+
}
|
|
1482
|
+
var DroidParser = class {
|
|
1483
|
+
constructor(dataDir = DEFAULT_DATA_DIR3) {
|
|
1484
|
+
this.dataDir = dataDir;
|
|
1485
|
+
this.tool = createToolDefinition3(dataDir);
|
|
1486
|
+
}
|
|
1487
|
+
tool;
|
|
1488
|
+
async parse() {
|
|
1489
|
+
const sessionFiles = findSessionFiles3(this.dataDir);
|
|
1490
|
+
if (sessionFiles.length === 0) {
|
|
1491
|
+
return { buckets: [], sessions: [] };
|
|
1492
|
+
}
|
|
1493
|
+
const entries = [];
|
|
1494
|
+
const sessionEvents = [];
|
|
1495
|
+
for (const filePath of sessionFiles) {
|
|
1496
|
+
const sessionId = filePath;
|
|
1497
|
+
const project = extractDroidProject(basename4(dirname2(filePath)));
|
|
1498
|
+
let firstMessageTimestamp = null;
|
|
1499
|
+
const content = readFileSafe(filePath);
|
|
1500
|
+
if (!content) continue;
|
|
1501
|
+
for (const line of content.split("\n")) {
|
|
1502
|
+
if (!line.trim()) continue;
|
|
1503
|
+
let obj;
|
|
1504
|
+
try {
|
|
1505
|
+
obj = JSON.parse(line);
|
|
1506
|
+
} catch {
|
|
1507
|
+
continue;
|
|
1508
|
+
}
|
|
1509
|
+
if (obj.type !== "message" || !obj.timestamp) continue;
|
|
1510
|
+
const timestamp = new Date(obj.timestamp);
|
|
1511
|
+
if (Number.isNaN(timestamp.getTime())) continue;
|
|
1512
|
+
const role = obj.message?.role;
|
|
1513
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
1514
|
+
if (firstMessageTimestamp === null) {
|
|
1515
|
+
firstMessageTimestamp = timestamp;
|
|
1516
|
+
}
|
|
1517
|
+
sessionEvents.push({
|
|
1518
|
+
sessionId,
|
|
1519
|
+
source: TOOL_ID3,
|
|
1520
|
+
project,
|
|
1521
|
+
timestamp,
|
|
1522
|
+
role
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
const settingsPath = join10(
|
|
1526
|
+
dirname2(filePath),
|
|
1527
|
+
`${basename4(filePath, ".jsonl")}.settings.json`
|
|
1528
|
+
);
|
|
1529
|
+
const settingsContent = readFileSafe(settingsPath);
|
|
1530
|
+
if (!settingsContent || firstMessageTimestamp === null) continue;
|
|
1531
|
+
let settings;
|
|
1532
|
+
try {
|
|
1533
|
+
settings = JSON.parse(settingsContent);
|
|
1534
|
+
} catch {
|
|
1535
|
+
continue;
|
|
1536
|
+
}
|
|
1537
|
+
const tokenUsage = settings.tokenUsage;
|
|
1538
|
+
if (!tokenUsage) continue;
|
|
1539
|
+
const cachedTokens = toSafeNumber3(tokenUsage.cacheReadTokens);
|
|
1540
|
+
const reasoningTokens = toSafeNumber3(tokenUsage.thinkingTokens);
|
|
1541
|
+
const inputTokens = Math.max(
|
|
1542
|
+
0,
|
|
1543
|
+
toSafeNumber3(tokenUsage.inputTokens) - cachedTokens
|
|
1544
|
+
);
|
|
1545
|
+
const outputTokens = Math.max(
|
|
1546
|
+
0,
|
|
1547
|
+
toSafeNumber3(tokenUsage.outputTokens) - reasoningTokens
|
|
1548
|
+
);
|
|
1549
|
+
if (inputTokens === 0 && outputTokens === 0 && cachedTokens === 0 && reasoningTokens === 0) {
|
|
1550
|
+
continue;
|
|
1551
|
+
}
|
|
1552
|
+
entries.push({
|
|
1553
|
+
sessionId,
|
|
1554
|
+
source: TOOL_ID3,
|
|
1555
|
+
model: settings.model || "unknown",
|
|
1556
|
+
project,
|
|
1557
|
+
timestamp: firstMessageTimestamp,
|
|
1558
|
+
inputTokens,
|
|
1559
|
+
outputTokens,
|
|
1560
|
+
reasoningTokens,
|
|
1561
|
+
cachedTokens
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
return {
|
|
1565
|
+
buckets: aggregateToBuckets(entries),
|
|
1566
|
+
sessions: extractSessions(sessionEvents, entries)
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
isInstalled() {
|
|
1570
|
+
return existsSync10(this.dataDir);
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
registerParser(new DroidParser());
|
|
1574
|
+
|
|
1575
|
+
// src/parsers/pi-coding-agent.ts
|
|
1576
|
+
import { existsSync as existsSync11 } from "fs";
|
|
1577
|
+
import { homedir as homedir10 } from "os";
|
|
1578
|
+
import { join as join11 } from "path";
|
|
1579
|
+
var TOOL_ID4 = "pi-coding-agent";
|
|
1580
|
+
var TOOL_NAME4 = "pi";
|
|
1581
|
+
var DEFAULT_SESSIONS_DIR2 = join11(homedir10(), ".pi", "agent", "sessions");
|
|
1582
|
+
function createToolDefinition4(dataDir) {
|
|
1583
|
+
return {
|
|
1584
|
+
id: TOOL_ID4,
|
|
1585
|
+
name: TOOL_NAME4,
|
|
1586
|
+
dataDir
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
function toSafeNumber4(value) {
|
|
1590
|
+
const numberValue = Number(value);
|
|
1591
|
+
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
1592
|
+
}
|
|
1593
|
+
function getPathLeaf4(value) {
|
|
1594
|
+
const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1595
|
+
const leaf = normalized.split("/").filter(Boolean).pop();
|
|
1596
|
+
return leaf || "unknown";
|
|
1597
|
+
}
|
|
1598
|
+
function normalizeForPrefix2(value) {
|
|
1599
|
+
return value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1600
|
+
}
|
|
1601
|
+
function getUsageNumber(usage, ...keys) {
|
|
1602
|
+
for (const key of keys) {
|
|
1603
|
+
const value = usage[key];
|
|
1604
|
+
const numberValue = toSafeNumber4(value);
|
|
1605
|
+
if (numberValue > 0) {
|
|
1606
|
+
return numberValue;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
return 0;
|
|
1610
|
+
}
|
|
1611
|
+
function extractPiProjectFromCwd(cwd) {
|
|
1612
|
+
return getPathLeaf4(cwd);
|
|
1613
|
+
}
|
|
1614
|
+
function extractPiProjectFromDir(filePath, sessionsDir = DEFAULT_SESSIONS_DIR2) {
|
|
1615
|
+
const normalizedFilePath = normalizeForPrefix2(filePath);
|
|
1616
|
+
const normalizedSessionsDir = normalizeForPrefix2(sessionsDir);
|
|
1617
|
+
const prefix = `${normalizedSessionsDir}/`;
|
|
1618
|
+
if (!normalizedFilePath.startsWith(prefix)) {
|
|
1619
|
+
return "unknown";
|
|
1620
|
+
}
|
|
1621
|
+
const relativePath = normalizedFilePath.slice(prefix.length);
|
|
1622
|
+
const firstSegment = relativePath.split("/")[0];
|
|
1623
|
+
if (!firstSegment) {
|
|
1624
|
+
return "unknown";
|
|
1625
|
+
}
|
|
1626
|
+
try {
|
|
1627
|
+
const decoded = decodeURIComponent(firstSegment);
|
|
1628
|
+
if (decoded.includes("/") || decoded.includes("\\")) {
|
|
1629
|
+
return getPathLeaf4(decoded);
|
|
1630
|
+
}
|
|
1631
|
+
} catch {
|
|
1632
|
+
}
|
|
1633
|
+
const slugParts = firstSegment.split("-").filter(Boolean);
|
|
1634
|
+
return slugParts.length > 0 ? slugParts[slugParts.length - 1] : "unknown";
|
|
1635
|
+
}
|
|
1636
|
+
var PiCodingAgentParser = class {
|
|
1637
|
+
constructor(sessionsDir = DEFAULT_SESSIONS_DIR2) {
|
|
1638
|
+
this.sessionsDir = sessionsDir;
|
|
1639
|
+
this.tool = createToolDefinition4(sessionsDir);
|
|
1640
|
+
}
|
|
1641
|
+
tool;
|
|
1642
|
+
async parse() {
|
|
1643
|
+
const sessionFiles = findJsonlFiles(this.sessionsDir);
|
|
1644
|
+
if (sessionFiles.length === 0) {
|
|
1645
|
+
return { buckets: [], sessions: [] };
|
|
1646
|
+
}
|
|
1647
|
+
const entries = [];
|
|
1648
|
+
const sessionEvents = [];
|
|
1649
|
+
const seenEntryIds = /* @__PURE__ */ new Set();
|
|
1650
|
+
for (const filePath of sessionFiles) {
|
|
1651
|
+
const content = readFileSafe(filePath);
|
|
1652
|
+
if (!content) continue;
|
|
1653
|
+
const rows = parseJsonl(content);
|
|
1654
|
+
if (rows.length === 0) continue;
|
|
1655
|
+
let sessionId = filePath;
|
|
1656
|
+
let project = extractPiProjectFromDir(filePath, this.sessionsDir);
|
|
1657
|
+
for (const row of rows) {
|
|
1658
|
+
if (row.type !== "session") continue;
|
|
1659
|
+
if (row.id) {
|
|
1660
|
+
sessionId = row.id;
|
|
1661
|
+
}
|
|
1662
|
+
if (row.cwd) {
|
|
1663
|
+
project = extractPiProjectFromCwd(row.cwd);
|
|
1664
|
+
}
|
|
1665
|
+
break;
|
|
1666
|
+
}
|
|
1667
|
+
for (const row of rows) {
|
|
1668
|
+
if (row.type !== "message") continue;
|
|
1669
|
+
const message = row.message;
|
|
1670
|
+
if (!message) continue;
|
|
1671
|
+
const rawTimestamp = row.timestamp || message.timestamp;
|
|
1672
|
+
if (!rawTimestamp) continue;
|
|
1673
|
+
const timestamp = new Date(rawTimestamp);
|
|
1674
|
+
if (Number.isNaN(timestamp.getTime())) continue;
|
|
1675
|
+
if (message.role === "user" || message.role === "assistant") {
|
|
1676
|
+
sessionEvents.push({
|
|
1677
|
+
sessionId,
|
|
1678
|
+
source: TOOL_ID4,
|
|
1679
|
+
project,
|
|
1680
|
+
timestamp,
|
|
1681
|
+
role: message.role
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
if (message.role !== "assistant") continue;
|
|
1685
|
+
const usage = message.usage;
|
|
1686
|
+
if (!usage) continue;
|
|
1687
|
+
const inputTokens = getUsageNumber(usage, "input", "inputTokens");
|
|
1688
|
+
const outputTokens = getUsageNumber(usage, "output", "outputTokens");
|
|
1689
|
+
const cachedTokens = getUsageNumber(
|
|
1690
|
+
usage,
|
|
1691
|
+
"cacheRead",
|
|
1692
|
+
"cacheReadTokens",
|
|
1693
|
+
"cache_read"
|
|
1694
|
+
);
|
|
1695
|
+
const reasoningTokens = getUsageNumber(
|
|
1696
|
+
usage,
|
|
1697
|
+
"reasoningOutputTokens",
|
|
1698
|
+
"thinkingTokens",
|
|
1699
|
+
"thoughts"
|
|
1700
|
+
);
|
|
1701
|
+
if (inputTokens === 0 && outputTokens === 0 && cachedTokens === 0 && reasoningTokens === 0) {
|
|
1702
|
+
continue;
|
|
1703
|
+
}
|
|
1704
|
+
if (row.id) {
|
|
1705
|
+
if (seenEntryIds.has(row.id)) continue;
|
|
1706
|
+
seenEntryIds.add(row.id);
|
|
1707
|
+
}
|
|
1708
|
+
entries.push({
|
|
1709
|
+
sessionId,
|
|
1710
|
+
source: TOOL_ID4,
|
|
1711
|
+
model: message.model || "unknown",
|
|
1712
|
+
project,
|
|
1713
|
+
timestamp,
|
|
1714
|
+
inputTokens,
|
|
1715
|
+
outputTokens,
|
|
1716
|
+
reasoningTokens,
|
|
1717
|
+
cachedTokens
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
return {
|
|
1722
|
+
buckets: aggregateToBuckets(entries),
|
|
1723
|
+
sessions: extractSessions(sessionEvents, entries)
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
isInstalled() {
|
|
1727
|
+
return existsSync11(this.sessionsDir);
|
|
1728
|
+
}
|
|
1729
|
+
};
|
|
1730
|
+
registerParser(new PiCodingAgentParser());
|
|
1731
|
+
|
|
1101
1732
|
// src/cli.ts
|
|
1102
1733
|
import { Command, Option } from "commander";
|
|
1103
1734
|
|
|
1104
1735
|
// src/infrastructure/config/manager.ts
|
|
1105
1736
|
import { randomUUID } from "crypto";
|
|
1106
1737
|
import {
|
|
1107
|
-
existsSync as
|
|
1738
|
+
existsSync as existsSync12,
|
|
1108
1739
|
mkdirSync,
|
|
1109
1740
|
readFileSync as readFileSync6,
|
|
1110
1741
|
unlinkSync,
|
|
1111
1742
|
writeFileSync
|
|
1112
1743
|
} from "fs";
|
|
1113
|
-
import { join as
|
|
1744
|
+
import { join as join13 } from "path";
|
|
1114
1745
|
|
|
1115
1746
|
// src/infrastructure/xdg.ts
|
|
1116
|
-
import { homedir as
|
|
1117
|
-
import { join as
|
|
1747
|
+
import { homedir as homedir11 } from "os";
|
|
1748
|
+
import { join as join12 } from "path";
|
|
1118
1749
|
function getConfigHome() {
|
|
1119
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
1750
|
+
return process.env.XDG_CONFIG_HOME || join12(homedir11(), ".config");
|
|
1120
1751
|
}
|
|
1121
1752
|
function getStateHome() {
|
|
1122
|
-
return process.env.XDG_STATE_HOME ||
|
|
1753
|
+
return process.env.XDG_STATE_HOME || join12(homedir11(), ".local", "state");
|
|
1123
1754
|
}
|
|
1124
1755
|
function getRuntimeDir() {
|
|
1125
1756
|
return process.env.XDG_RUNTIME_DIR || getStateHome();
|
|
1126
1757
|
}
|
|
1127
1758
|
|
|
1128
1759
|
// src/infrastructure/config/manager.ts
|
|
1129
|
-
var CONFIG_DIR =
|
|
1760
|
+
var CONFIG_DIR = join13(getConfigHome(), "tokenarena");
|
|
1130
1761
|
var isDev = process.env.TOKEN_ARENA_DEV === "1";
|
|
1131
|
-
var CONFIG_FILE =
|
|
1762
|
+
var CONFIG_FILE = join13(CONFIG_DIR, isDev ? "config.dev.json" : "config.json");
|
|
1132
1763
|
var DEFAULT_API_URL = "https://token.poco-ai.com";
|
|
1133
1764
|
var VALID_CONFIG_KEYS = [
|
|
1134
1765
|
"apiKey",
|
|
@@ -1144,7 +1775,7 @@ function getConfigDir() {
|
|
|
1144
1775
|
return CONFIG_DIR;
|
|
1145
1776
|
}
|
|
1146
1777
|
function loadConfig() {
|
|
1147
|
-
if (!
|
|
1778
|
+
if (!existsSync12(CONFIG_FILE)) return null;
|
|
1148
1779
|
try {
|
|
1149
1780
|
const raw = readFileSync6(CONFIG_FILE, "utf-8");
|
|
1150
1781
|
const config = JSON.parse(raw);
|
|
@@ -1162,7 +1793,7 @@ function saveConfig(config) {
|
|
|
1162
1793
|
`, "utf-8");
|
|
1163
1794
|
}
|
|
1164
1795
|
function deleteConfig() {
|
|
1165
|
-
if (
|
|
1796
|
+
if (existsSync12(CONFIG_FILE)) {
|
|
1166
1797
|
unlinkSync(CONFIG_FILE);
|
|
1167
1798
|
}
|
|
1168
1799
|
}
|
|
@@ -2019,7 +2650,7 @@ var ApiClient = class {
|
|
|
2019
2650
|
// src/infrastructure/runtime/lock.ts
|
|
2020
2651
|
import {
|
|
2021
2652
|
closeSync,
|
|
2022
|
-
existsSync as
|
|
2653
|
+
existsSync as existsSync13,
|
|
2023
2654
|
openSync,
|
|
2024
2655
|
readFileSync as readFileSync7,
|
|
2025
2656
|
rmSync,
|
|
@@ -2028,22 +2659,22 @@ import {
|
|
|
2028
2659
|
|
|
2029
2660
|
// src/infrastructure/runtime/paths.ts
|
|
2030
2661
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
2031
|
-
import { join as
|
|
2662
|
+
import { join as join14 } from "path";
|
|
2032
2663
|
var APP_NAME = "tokenarena";
|
|
2033
2664
|
function getRuntimeDirPath() {
|
|
2034
|
-
return
|
|
2665
|
+
return join14(getRuntimeDir(), APP_NAME);
|
|
2035
2666
|
}
|
|
2036
2667
|
function getStateDir() {
|
|
2037
|
-
return
|
|
2668
|
+
return join14(getStateHome(), APP_NAME);
|
|
2038
2669
|
}
|
|
2039
2670
|
function getSyncLockPath() {
|
|
2040
|
-
return
|
|
2671
|
+
return join14(getRuntimeDirPath(), "sync.lock");
|
|
2041
2672
|
}
|
|
2042
2673
|
function getSyncStatePath() {
|
|
2043
|
-
return
|
|
2674
|
+
return join14(getStateDir(), "status.json");
|
|
2044
2675
|
}
|
|
2045
2676
|
function getUploadManifestPath() {
|
|
2046
|
-
return
|
|
2677
|
+
return join14(getStateDir(), "upload-manifest.json");
|
|
2047
2678
|
}
|
|
2048
2679
|
function ensureAppDirs() {
|
|
2049
2680
|
mkdirSync2(getRuntimeDirPath(), { recursive: true });
|
|
@@ -2061,7 +2692,7 @@ function isProcessAlive(pid) {
|
|
|
2061
2692
|
}
|
|
2062
2693
|
}
|
|
2063
2694
|
function readLockMetadata(lockPath) {
|
|
2064
|
-
if (!
|
|
2695
|
+
if (!existsSync13(lockPath)) {
|
|
2065
2696
|
return null;
|
|
2066
2697
|
}
|
|
2067
2698
|
try {
|
|
@@ -2135,13 +2766,13 @@ function describeExistingSyncLock() {
|
|
|
2135
2766
|
}
|
|
2136
2767
|
|
|
2137
2768
|
// src/infrastructure/runtime/state.ts
|
|
2138
|
-
import { existsSync as
|
|
2769
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "fs";
|
|
2139
2770
|
function getDefaultState() {
|
|
2140
2771
|
return { status: "idle" };
|
|
2141
2772
|
}
|
|
2142
2773
|
function loadSyncState() {
|
|
2143
2774
|
const path = getSyncStatePath();
|
|
2144
|
-
if (!
|
|
2775
|
+
if (!existsSync14(path)) {
|
|
2145
2776
|
return getDefaultState();
|
|
2146
2777
|
}
|
|
2147
2778
|
try {
|
|
@@ -2202,7 +2833,7 @@ function markSyncFailed(source, error, status) {
|
|
|
2202
2833
|
}
|
|
2203
2834
|
|
|
2204
2835
|
// src/infrastructure/runtime/upload-manifest.ts
|
|
2205
|
-
import { existsSync as
|
|
2836
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
|
|
2206
2837
|
function isRecordOfStrings(value) {
|
|
2207
2838
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2208
2839
|
return false;
|
|
@@ -2218,7 +2849,7 @@ function isUploadManifest(value) {
|
|
|
2218
2849
|
}
|
|
2219
2850
|
function loadUploadManifest() {
|
|
2220
2851
|
const path = getUploadManifestPath();
|
|
2221
|
-
if (!
|
|
2852
|
+
if (!existsSync15(path)) {
|
|
2222
2853
|
return null;
|
|
2223
2854
|
}
|
|
2224
2855
|
try {
|
|
@@ -2646,10 +3277,10 @@ View your dashboard at: ${apiUrl}/usage`);
|
|
|
2646
3277
|
|
|
2647
3278
|
// src/commands/init.ts
|
|
2648
3279
|
import { execFileSync as execFileSync2, spawn } from "child_process";
|
|
2649
|
-
import { existsSync as
|
|
3280
|
+
import { existsSync as existsSync16 } from "fs";
|
|
2650
3281
|
import { appendFile, mkdir, readFile } from "fs/promises";
|
|
2651
|
-
import { homedir as
|
|
2652
|
-
import { dirname as
|
|
3282
|
+
import { homedir as homedir12, platform } from "os";
|
|
3283
|
+
import { dirname as dirname3, join as join15, posix, win32 } from "path";
|
|
2653
3284
|
function joinForPlatform(currentPlatform, ...parts) {
|
|
2654
3285
|
return currentPlatform === "win32" ? win32.join(...parts) : posix.join(...parts);
|
|
2655
3286
|
}
|
|
@@ -2693,7 +3324,7 @@ function resolvePowerShellProfilePath() {
|
|
|
2693
3324
|
const systemRoot = process.env.SYSTEMROOT || "C:\\Windows";
|
|
2694
3325
|
const candidates = [
|
|
2695
3326
|
"pwsh.exe",
|
|
2696
|
-
|
|
3327
|
+
join15(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
2697
3328
|
];
|
|
2698
3329
|
for (const command of candidates) {
|
|
2699
3330
|
try {
|
|
@@ -2722,8 +3353,8 @@ function resolvePowerShellProfilePath() {
|
|
|
2722
3353
|
function resolveShellAliasSetup(options = {}) {
|
|
2723
3354
|
const currentPlatform = options.currentPlatform ?? platform();
|
|
2724
3355
|
const env = options.env ?? process.env;
|
|
2725
|
-
const homeDir = options.homeDir ??
|
|
2726
|
-
const pathExists = options.exists ??
|
|
3356
|
+
const homeDir = options.homeDir ?? homedir12();
|
|
3357
|
+
const pathExists = options.exists ?? existsSync16;
|
|
2727
3358
|
const shellFromEnv = env.SHELL ? basenameLikeShell(env.SHELL).toLowerCase() : "";
|
|
2728
3359
|
const shellName = shellFromEnv || (currentPlatform === "win32" ? "powershell" : "");
|
|
2729
3360
|
const aliasName = "ta";
|
|
@@ -2894,9 +3525,9 @@ async function setupShellAlias() {
|
|
|
2894
3525
|
return;
|
|
2895
3526
|
}
|
|
2896
3527
|
try {
|
|
2897
|
-
await mkdir(
|
|
3528
|
+
await mkdir(dirname3(setup.configFile), { recursive: true });
|
|
2898
3529
|
let existingContent = "";
|
|
2899
|
-
if (
|
|
3530
|
+
if (existsSync16(setup.configFile)) {
|
|
2900
3531
|
existingContent = await readFile(setup.configFile, "utf-8");
|
|
2901
3532
|
}
|
|
2902
3533
|
const normalizedContent = existingContent.toLowerCase();
|
|
@@ -3089,8 +3720,8 @@ async function runSyncCommand(opts = {}) {
|
|
|
3089
3720
|
}
|
|
3090
3721
|
|
|
3091
3722
|
// src/commands/uninstall.ts
|
|
3092
|
-
import { existsSync as
|
|
3093
|
-
import { homedir as
|
|
3723
|
+
import { existsSync as existsSync17, readFileSync as readFileSync10, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
3724
|
+
import { homedir as homedir13, platform as platform2 } from "os";
|
|
3094
3725
|
function removeShellAlias() {
|
|
3095
3726
|
const shell = process.env.SHELL;
|
|
3096
3727
|
if (!shell) return;
|
|
@@ -3099,22 +3730,22 @@ function removeShellAlias() {
|
|
|
3099
3730
|
let configFile;
|
|
3100
3731
|
switch (shellName) {
|
|
3101
3732
|
case "zsh":
|
|
3102
|
-
configFile = `${
|
|
3733
|
+
configFile = `${homedir13()}/.zshrc`;
|
|
3103
3734
|
break;
|
|
3104
3735
|
case "bash":
|
|
3105
|
-
if (platform2() === "darwin" &&
|
|
3106
|
-
configFile = `${
|
|
3736
|
+
if (platform2() === "darwin" && existsSync17(`${homedir13()}/.bash_profile`)) {
|
|
3737
|
+
configFile = `${homedir13()}/.bash_profile`;
|
|
3107
3738
|
} else {
|
|
3108
|
-
configFile = `${
|
|
3739
|
+
configFile = `${homedir13()}/.bashrc`;
|
|
3109
3740
|
}
|
|
3110
3741
|
break;
|
|
3111
3742
|
case "fish":
|
|
3112
|
-
configFile = `${
|
|
3743
|
+
configFile = `${homedir13()}/.config/fish/config.fish`;
|
|
3113
3744
|
break;
|
|
3114
3745
|
default:
|
|
3115
3746
|
return;
|
|
3116
3747
|
}
|
|
3117
|
-
if (!
|
|
3748
|
+
if (!existsSync17(configFile)) return;
|
|
3118
3749
|
try {
|
|
3119
3750
|
let content = readFileSync10(configFile, "utf-8");
|
|
3120
3751
|
const aliasPatterns = [
|
|
@@ -3149,7 +3780,7 @@ function removeShellAlias() {
|
|
|
3149
3780
|
async function runUninstall() {
|
|
3150
3781
|
const configPath = getConfigPath();
|
|
3151
3782
|
const configDir = getConfigDir();
|
|
3152
|
-
if (!
|
|
3783
|
+
if (!existsSync17(configPath)) {
|
|
3153
3784
|
logger.info(formatHeader("\u5378\u8F7D TokenArena"));
|
|
3154
3785
|
logger.info(formatBullet("\u672A\u53D1\u73B0\u672C\u5730\u914D\u7F6E\uFF0C\u65E0\u9700\u5378\u8F7D\u3002"));
|
|
3155
3786
|
return;
|
|
@@ -3178,7 +3809,7 @@ async function runUninstall() {
|
|
|
3178
3809
|
deleteConfig();
|
|
3179
3810
|
logger.info(formatSection("\u6267\u884C\u7ED3\u679C"));
|
|
3180
3811
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u6587\u4EF6\u3002", "success"));
|
|
3181
|
-
if (
|
|
3812
|
+
if (existsSync17(configDir)) {
|
|
3182
3813
|
try {
|
|
3183
3814
|
rmSync2(configDir, { recursive: false, force: true });
|
|
3184
3815
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u76EE\u5F55\u3002", "success"));
|
|
@@ -3186,12 +3817,12 @@ async function runUninstall() {
|
|
|
3186
3817
|
}
|
|
3187
3818
|
}
|
|
3188
3819
|
const stateDir = getStateDir();
|
|
3189
|
-
if (
|
|
3820
|
+
if (existsSync17(stateDir)) {
|
|
3190
3821
|
rmSync2(stateDir, { recursive: true, force: true });
|
|
3191
3822
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u72B6\u6001\u6570\u636E\u3002", "success"));
|
|
3192
3823
|
}
|
|
3193
3824
|
const runtimeDir = getRuntimeDirPath();
|
|
3194
|
-
if (
|
|
3825
|
+
if (existsSync17(runtimeDir)) {
|
|
3195
3826
|
rmSync2(runtimeDir, { recursive: true, force: true });
|
|
3196
3827
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u8FD0\u884C\u65F6\u6570\u636E\u3002", "success"));
|
|
3197
3828
|
}
|
|
@@ -3316,7 +3947,7 @@ async function runHome(program) {
|
|
|
3316
3947
|
|
|
3317
3948
|
// src/infrastructure/runtime/cli-version.ts
|
|
3318
3949
|
import { readFileSync as readFileSync11 } from "fs";
|
|
3319
|
-
import { dirname as
|
|
3950
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
3320
3951
|
import { fileURLToPath } from "url";
|
|
3321
3952
|
var FALLBACK_VERSION = "0.0.0";
|
|
3322
3953
|
var cachedVersion;
|
|
@@ -3324,8 +3955,8 @@ function getCliVersion(metaUrl = import.meta.url) {
|
|
|
3324
3955
|
if (cachedVersion) {
|
|
3325
3956
|
return cachedVersion;
|
|
3326
3957
|
}
|
|
3327
|
-
const packageJsonPath =
|
|
3328
|
-
|
|
3958
|
+
const packageJsonPath = join16(
|
|
3959
|
+
dirname4(fileURLToPath(metaUrl)),
|
|
3329
3960
|
"..",
|
|
3330
3961
|
"package.json"
|
|
3331
3962
|
);
|
|
@@ -3380,7 +4011,7 @@ function createCli() {
|
|
|
3380
4011
|
}
|
|
3381
4012
|
|
|
3382
4013
|
// src/infrastructure/runtime/main-module.ts
|
|
3383
|
-
import { existsSync as
|
|
4014
|
+
import { existsSync as existsSync18, realpathSync } from "fs";
|
|
3384
4015
|
import { resolve } from "path";
|
|
3385
4016
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3386
4017
|
function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
|
|
@@ -3391,7 +4022,7 @@ function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
|
|
|
3391
4022
|
try {
|
|
3392
4023
|
return realpathSync(argvEntry) === realpathSync(currentModulePath);
|
|
3393
4024
|
} catch {
|
|
3394
|
-
if (!
|
|
4025
|
+
if (!existsSync18(argvEntry)) {
|
|
3395
4026
|
return false;
|
|
3396
4027
|
}
|
|
3397
4028
|
return resolve(argvEntry) === resolve(currentModulePath);
|