@yishiguji/tokenarena 0.8.8 → 0.10.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 +774 -197
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2370,26 +2370,172 @@ var KimiCodeParser = class {
|
|
|
2370
2370
|
};
|
|
2371
2371
|
registerParser(new KimiCodeParser());
|
|
2372
2372
|
|
|
2373
|
-
// src/parsers/
|
|
2374
|
-
import { existsSync as existsSync14
|
|
2373
|
+
// src/parsers/letcode.ts
|
|
2374
|
+
import { existsSync as existsSync14 } from "fs";
|
|
2375
2375
|
import { homedir as homedir13 } from "os";
|
|
2376
|
-
import { basename as basename5,
|
|
2377
|
-
var TOOL_ID9 = "
|
|
2378
|
-
var TOOL_NAME9 = "
|
|
2379
|
-
var
|
|
2376
|
+
import { basename as basename5, join as join14 } from "path";
|
|
2377
|
+
var TOOL_ID9 = "letcode";
|
|
2378
|
+
var TOOL_NAME9 = "LetCode";
|
|
2379
|
+
var DEFAULT_CONFIG_DIR = join14(homedir13(), ".config", "letcode");
|
|
2380
|
+
var DEFAULT_SESSIONS_DIR4 = join14(DEFAULT_CONFIG_DIR, "sessions");
|
|
2381
|
+
function getLetcodeSessionsDirs(env = process.env) {
|
|
2382
|
+
const dirs = [
|
|
2383
|
+
env.TOKEN_ARENA_LETCODE_DIR,
|
|
2384
|
+
env.XDG_CONFIG_HOME ? join14(env.XDG_CONFIG_HOME, "letcode", "sessions") : void 0,
|
|
2385
|
+
DEFAULT_SESSIONS_DIR4
|
|
2386
|
+
].filter((value) => Boolean(value));
|
|
2387
|
+
return Array.from(new Set(dirs));
|
|
2388
|
+
}
|
|
2389
|
+
function toNonNegativeNumber(value) {
|
|
2390
|
+
const numberValue = Number(value);
|
|
2391
|
+
return Number.isFinite(numberValue) && numberValue >= 0 ? numberValue : 0;
|
|
2392
|
+
}
|
|
2393
|
+
function parseTimestamp2(value) {
|
|
2394
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2395
|
+
const timestamp = new Date(value);
|
|
2396
|
+
return Number.isNaN(timestamp.getTime()) ? null : timestamp;
|
|
2397
|
+
}
|
|
2398
|
+
if (typeof value === "string" && value.trim()) {
|
|
2399
|
+
const asNumber = Number(value);
|
|
2400
|
+
if (Number.isFinite(asNumber)) {
|
|
2401
|
+
const timestamp2 = new Date(asNumber);
|
|
2402
|
+
if (!Number.isNaN(timestamp2.getTime())) {
|
|
2403
|
+
return timestamp2;
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
const timestamp = new Date(value);
|
|
2407
|
+
return Number.isNaN(timestamp.getTime()) ? null : timestamp;
|
|
2408
|
+
}
|
|
2409
|
+
return null;
|
|
2410
|
+
}
|
|
2411
|
+
function shouldCountTelemetry(event) {
|
|
2412
|
+
if (event.kind !== "llm_request_telemetry") {
|
|
2413
|
+
return false;
|
|
2414
|
+
}
|
|
2415
|
+
if (event.phase !== "completed") {
|
|
2416
|
+
return false;
|
|
2417
|
+
}
|
|
2418
|
+
if (event.usage_completeness === "usage_missing") {
|
|
2419
|
+
return false;
|
|
2420
|
+
}
|
|
2421
|
+
return true;
|
|
2422
|
+
}
|
|
2423
|
+
function toSessionRole(kind) {
|
|
2424
|
+
if (kind === "user_message") {
|
|
2425
|
+
return "user";
|
|
2426
|
+
}
|
|
2427
|
+
if (kind === "assistant_message") {
|
|
2428
|
+
return "assistant";
|
|
2429
|
+
}
|
|
2430
|
+
return null;
|
|
2431
|
+
}
|
|
2432
|
+
var LetcodeParser = class {
|
|
2433
|
+
tool;
|
|
2434
|
+
sessionsDirs;
|
|
2435
|
+
constructor(sessionsDir) {
|
|
2436
|
+
this.sessionsDirs = sessionsDir ? [sessionsDir] : getLetcodeSessionsDirs();
|
|
2437
|
+
this.tool = {
|
|
2438
|
+
id: TOOL_ID9,
|
|
2439
|
+
name: TOOL_NAME9,
|
|
2440
|
+
dataDir: this.sessionsDirs[0] ?? DEFAULT_SESSIONS_DIR4
|
|
2441
|
+
};
|
|
2442
|
+
}
|
|
2443
|
+
async parse() {
|
|
2444
|
+
const entries = [];
|
|
2445
|
+
const sessionEvents = [];
|
|
2446
|
+
const seenEntryKeys = /* @__PURE__ */ new Set();
|
|
2447
|
+
for (const sessionsDir of this.sessionsDirs) {
|
|
2448
|
+
for (const filePath of findJsonlFiles(sessionsDir)) {
|
|
2449
|
+
const content = readFileSafe(filePath);
|
|
2450
|
+
if (!content) continue;
|
|
2451
|
+
const rows = parseJsonl(content);
|
|
2452
|
+
if (rows.length === 0) continue;
|
|
2453
|
+
const fallbackSessionId = extractSessionId(filePath) || basename5(filePath);
|
|
2454
|
+
for (const row of rows) {
|
|
2455
|
+
const sessionId = typeof row.session_id === "string" && row.session_id ? row.session_id : fallbackSessionId;
|
|
2456
|
+
const timestamp = parseTimestamp2(row.timestamp_ms);
|
|
2457
|
+
if (!timestamp) continue;
|
|
2458
|
+
const role = toSessionRole(row.kind);
|
|
2459
|
+
if (role) {
|
|
2460
|
+
sessionEvents.push({
|
|
2461
|
+
sessionId,
|
|
2462
|
+
source: TOOL_ID9,
|
|
2463
|
+
project: "unknown",
|
|
2464
|
+
timestamp,
|
|
2465
|
+
role
|
|
2466
|
+
});
|
|
2467
|
+
}
|
|
2468
|
+
if (!shouldCountTelemetry(row)) {
|
|
2469
|
+
continue;
|
|
2470
|
+
}
|
|
2471
|
+
const inputTokens = toNonNegativeNumber(row.provider_input_tokens);
|
|
2472
|
+
const outputTokens = toNonNegativeNumber(row.provider_output_tokens);
|
|
2473
|
+
const cachedTokens = toNonNegativeNumber(row.provider_cached_tokens);
|
|
2474
|
+
const reasoningTokens = toNonNegativeNumber(
|
|
2475
|
+
row.provider_reasoning_tokens
|
|
2476
|
+
);
|
|
2477
|
+
if (inputTokens + outputTokens + cachedTokens + reasoningTokens === 0) {
|
|
2478
|
+
continue;
|
|
2479
|
+
}
|
|
2480
|
+
const model = typeof row.model === "string" && row.model ? row.model : "unknown";
|
|
2481
|
+
const entryKey = [
|
|
2482
|
+
sessionId,
|
|
2483
|
+
timestamp.toISOString(),
|
|
2484
|
+
model,
|
|
2485
|
+
inputTokens,
|
|
2486
|
+
outputTokens,
|
|
2487
|
+
cachedTokens,
|
|
2488
|
+
reasoningTokens
|
|
2489
|
+
].join("|");
|
|
2490
|
+
if (seenEntryKeys.has(entryKey)) {
|
|
2491
|
+
continue;
|
|
2492
|
+
}
|
|
2493
|
+
seenEntryKeys.add(entryKey);
|
|
2494
|
+
entries.push({
|
|
2495
|
+
sessionId,
|
|
2496
|
+
source: TOOL_ID9,
|
|
2497
|
+
model,
|
|
2498
|
+
project: "unknown",
|
|
2499
|
+
timestamp,
|
|
2500
|
+
inputTokens,
|
|
2501
|
+
outputTokens,
|
|
2502
|
+
reasoningTokens,
|
|
2503
|
+
cachedTokens
|
|
2504
|
+
});
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
return {
|
|
2509
|
+
buckets: aggregateToBuckets(entries),
|
|
2510
|
+
sessions: extractSessions(sessionEvents, entries)
|
|
2511
|
+
};
|
|
2512
|
+
}
|
|
2513
|
+
isInstalled() {
|
|
2514
|
+
return this.sessionsDirs.some((dir) => existsSync14(dir));
|
|
2515
|
+
}
|
|
2516
|
+
};
|
|
2517
|
+
registerParser(new LetcodeParser());
|
|
2518
|
+
|
|
2519
|
+
// src/parsers/droid.ts
|
|
2520
|
+
import { existsSync as existsSync15, readdirSync as readdirSync8 } from "fs";
|
|
2521
|
+
import { homedir as homedir14 } from "os";
|
|
2522
|
+
import { basename as basename6, dirname as dirname3, join as join15 } from "path";
|
|
2523
|
+
var TOOL_ID10 = "droid";
|
|
2524
|
+
var TOOL_NAME10 = "Droid";
|
|
2525
|
+
var DEFAULT_DATA_DIR5 = join15(homedir14(), ".factory", "sessions");
|
|
2380
2526
|
function createToolDefinition7(dataDir) {
|
|
2381
2527
|
return {
|
|
2382
|
-
id:
|
|
2383
|
-
name:
|
|
2528
|
+
id: TOOL_ID10,
|
|
2529
|
+
name: TOOL_NAME10,
|
|
2384
2530
|
dataDir
|
|
2385
2531
|
};
|
|
2386
2532
|
}
|
|
2387
2533
|
function findSessionFiles3(dir) {
|
|
2388
2534
|
const results = [];
|
|
2389
|
-
if (!
|
|
2535
|
+
if (!existsSync15(dir)) return results;
|
|
2390
2536
|
try {
|
|
2391
2537
|
for (const entry of readdirSync8(dir, { withFileTypes: true })) {
|
|
2392
|
-
const fullPath =
|
|
2538
|
+
const fullPath = join15(dir, entry.name);
|
|
2393
2539
|
if (entry.isDirectory()) {
|
|
2394
2540
|
results.push(...findSessionFiles3(fullPath));
|
|
2395
2541
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl") && !entry.name.endsWith(".settings.json")) {
|
|
@@ -2424,7 +2570,7 @@ var DroidParser = class {
|
|
|
2424
2570
|
const sessionEvents = [];
|
|
2425
2571
|
for (const filePath of sessionFiles) {
|
|
2426
2572
|
const sessionId = filePath;
|
|
2427
|
-
const project = extractDroidProject(
|
|
2573
|
+
const project = extractDroidProject(basename6(dirname3(filePath)));
|
|
2428
2574
|
let firstMessageTimestamp = null;
|
|
2429
2575
|
const content = readFileSafe(filePath);
|
|
2430
2576
|
if (!content) continue;
|
|
@@ -2446,15 +2592,15 @@ var DroidParser = class {
|
|
|
2446
2592
|
}
|
|
2447
2593
|
sessionEvents.push({
|
|
2448
2594
|
sessionId,
|
|
2449
|
-
source:
|
|
2595
|
+
source: TOOL_ID10,
|
|
2450
2596
|
project,
|
|
2451
2597
|
timestamp,
|
|
2452
2598
|
role
|
|
2453
2599
|
});
|
|
2454
2600
|
}
|
|
2455
|
-
const settingsPath =
|
|
2601
|
+
const settingsPath = join15(
|
|
2456
2602
|
dirname3(filePath),
|
|
2457
|
-
`${
|
|
2603
|
+
`${basename6(filePath, ".jsonl")}.settings.json`
|
|
2458
2604
|
);
|
|
2459
2605
|
const settingsContent = readFileSafe(settingsPath);
|
|
2460
2606
|
if (!settingsContent || firstMessageTimestamp === null) continue;
|
|
@@ -2481,7 +2627,7 @@ var DroidParser = class {
|
|
|
2481
2627
|
}
|
|
2482
2628
|
entries.push({
|
|
2483
2629
|
sessionId,
|
|
2484
|
-
source:
|
|
2630
|
+
source: TOOL_ID10,
|
|
2485
2631
|
model: settings.model || "unknown",
|
|
2486
2632
|
project,
|
|
2487
2633
|
timestamp: firstMessageTimestamp,
|
|
@@ -2497,22 +2643,22 @@ var DroidParser = class {
|
|
|
2497
2643
|
};
|
|
2498
2644
|
}
|
|
2499
2645
|
isInstalled() {
|
|
2500
|
-
return
|
|
2646
|
+
return existsSync15(this.dataDir);
|
|
2501
2647
|
}
|
|
2502
2648
|
};
|
|
2503
2649
|
registerParser(new DroidParser());
|
|
2504
2650
|
|
|
2505
2651
|
// src/parsers/pi-coding-agent.ts
|
|
2506
|
-
import { existsSync as
|
|
2507
|
-
import { homedir as
|
|
2508
|
-
import { join as
|
|
2509
|
-
var
|
|
2510
|
-
var
|
|
2511
|
-
var
|
|
2652
|
+
import { existsSync as existsSync16 } from "fs";
|
|
2653
|
+
import { homedir as homedir15 } from "os";
|
|
2654
|
+
import { join as join16 } from "path";
|
|
2655
|
+
var TOOL_ID11 = "pi-coding-agent";
|
|
2656
|
+
var TOOL_NAME11 = "pi";
|
|
2657
|
+
var DEFAULT_SESSIONS_DIR5 = join16(homedir15(), ".pi", "agent", "sessions");
|
|
2512
2658
|
function createToolDefinition8(dataDir) {
|
|
2513
2659
|
return {
|
|
2514
|
-
id:
|
|
2515
|
-
name:
|
|
2660
|
+
id: TOOL_ID11,
|
|
2661
|
+
name: TOOL_NAME11,
|
|
2516
2662
|
dataDir
|
|
2517
2663
|
};
|
|
2518
2664
|
}
|
|
@@ -2541,7 +2687,7 @@ function getUsageNumber3(usage, ...keys) {
|
|
|
2541
2687
|
function extractPiProjectFromCwd(cwd) {
|
|
2542
2688
|
return getPathLeaf6(cwd);
|
|
2543
2689
|
}
|
|
2544
|
-
function extractPiProjectFromDir(filePath, sessionsDir =
|
|
2690
|
+
function extractPiProjectFromDir(filePath, sessionsDir = DEFAULT_SESSIONS_DIR5) {
|
|
2545
2691
|
const normalizedFilePath = normalizeForPrefix4(filePath);
|
|
2546
2692
|
const normalizedSessionsDir = normalizeForPrefix4(sessionsDir);
|
|
2547
2693
|
const prefix = `${normalizedSessionsDir}/`;
|
|
@@ -2564,7 +2710,7 @@ function extractPiProjectFromDir(filePath, sessionsDir = DEFAULT_SESSIONS_DIR4)
|
|
|
2564
2710
|
return slugParts.length > 0 ? slugParts[slugParts.length - 1] : "unknown";
|
|
2565
2711
|
}
|
|
2566
2712
|
var PiCodingAgentParser = class {
|
|
2567
|
-
constructor(sessionsDir =
|
|
2713
|
+
constructor(sessionsDir = DEFAULT_SESSIONS_DIR5) {
|
|
2568
2714
|
this.sessionsDir = sessionsDir;
|
|
2569
2715
|
this.tool = createToolDefinition8(sessionsDir);
|
|
2570
2716
|
}
|
|
@@ -2606,7 +2752,7 @@ var PiCodingAgentParser = class {
|
|
|
2606
2752
|
if (message.role === "user" || message.role === "assistant") {
|
|
2607
2753
|
sessionEvents.push({
|
|
2608
2754
|
sessionId,
|
|
2609
|
-
source:
|
|
2755
|
+
source: TOOL_ID11,
|
|
2610
2756
|
project,
|
|
2611
2757
|
timestamp,
|
|
2612
2758
|
role: message.role
|
|
@@ -2638,7 +2784,7 @@ var PiCodingAgentParser = class {
|
|
|
2638
2784
|
}
|
|
2639
2785
|
entries.push({
|
|
2640
2786
|
sessionId,
|
|
2641
|
-
source:
|
|
2787
|
+
source: TOOL_ID11,
|
|
2642
2788
|
model: message.model || "unknown",
|
|
2643
2789
|
project,
|
|
2644
2790
|
timestamp,
|
|
@@ -2655,23 +2801,23 @@ var PiCodingAgentParser = class {
|
|
|
2655
2801
|
};
|
|
2656
2802
|
}
|
|
2657
2803
|
isInstalled() {
|
|
2658
|
-
return
|
|
2804
|
+
return existsSync16(this.sessionsDir);
|
|
2659
2805
|
}
|
|
2660
2806
|
};
|
|
2661
2807
|
registerParser(new PiCodingAgentParser());
|
|
2662
2808
|
|
|
2663
2809
|
// src/parsers/qwenpaw.ts
|
|
2664
|
-
import { existsSync as
|
|
2665
|
-
import { homedir as
|
|
2666
|
-
import { join as
|
|
2667
|
-
var
|
|
2668
|
-
var
|
|
2669
|
-
var DEFAULT_USAGE_PATH =
|
|
2670
|
-
var DEFAULT_WORKSPACE_PATH =
|
|
2810
|
+
import { existsSync as existsSync17, readdirSync as readdirSync9 } from "fs";
|
|
2811
|
+
import { homedir as homedir16, hostname as hostname3 } from "os";
|
|
2812
|
+
import { join as join17 } from "path";
|
|
2813
|
+
var TOOL_ID12 = "qwenpaw";
|
|
2814
|
+
var TOOL_NAME12 = "QwenPaw";
|
|
2815
|
+
var DEFAULT_USAGE_PATH = join17(homedir16(), ".qwenpaw", "token_usage.json");
|
|
2816
|
+
var DEFAULT_WORKSPACE_PATH = join17(homedir16(), ".qwenpaw", "workspace");
|
|
2671
2817
|
function createToolDefinition9(usagePath) {
|
|
2672
2818
|
return {
|
|
2673
|
-
id:
|
|
2674
|
-
name:
|
|
2819
|
+
id: TOOL_ID12,
|
|
2820
|
+
name: TOOL_NAME12,
|
|
2675
2821
|
dataDir: usagePath
|
|
2676
2822
|
};
|
|
2677
2823
|
}
|
|
@@ -2728,7 +2874,7 @@ var QwenPawParser = class {
|
|
|
2728
2874
|
continue;
|
|
2729
2875
|
}
|
|
2730
2876
|
entries.push({
|
|
2731
|
-
source:
|
|
2877
|
+
source: TOOL_ID12,
|
|
2732
2878
|
model: resolveModel(recordKey, record),
|
|
2733
2879
|
project: "unknown",
|
|
2734
2880
|
timestamp,
|
|
@@ -2751,15 +2897,15 @@ var QwenPawParser = class {
|
|
|
2751
2897
|
}
|
|
2752
2898
|
async parseWorkspaceSessions() {
|
|
2753
2899
|
const events = [];
|
|
2754
|
-
if (!
|
|
2900
|
+
if (!existsSync17(this.workspacePath)) {
|
|
2755
2901
|
return events;
|
|
2756
2902
|
}
|
|
2757
2903
|
try {
|
|
2758
2904
|
const workspaceDirs = readdirSync9(this.workspacePath);
|
|
2759
2905
|
for (const workspaceDir of workspaceDirs) {
|
|
2760
|
-
const workspacePath =
|
|
2761
|
-
const chatsPath =
|
|
2762
|
-
const sessionsPath =
|
|
2906
|
+
const workspacePath = join17(this.workspacePath, workspaceDir);
|
|
2907
|
+
const chatsPath = join17(workspacePath, "chats.json");
|
|
2908
|
+
const sessionsPath = join17(workspacePath, "sessions");
|
|
2763
2909
|
const chatsContent = readFileSafe(chatsPath);
|
|
2764
2910
|
if (!chatsContent) {
|
|
2765
2911
|
continue;
|
|
@@ -2787,7 +2933,7 @@ var QwenPawParser = class {
|
|
|
2787
2933
|
for (const msg of sessionMessages) {
|
|
2788
2934
|
events.push({
|
|
2789
2935
|
sessionId: chat.session_id,
|
|
2790
|
-
source:
|
|
2936
|
+
source: TOOL_ID12,
|
|
2791
2937
|
project: workspaceDir,
|
|
2792
2938
|
timestamp: new Date(msg.timestamp),
|
|
2793
2939
|
role: msg.role
|
|
@@ -2803,7 +2949,7 @@ var QwenPawParser = class {
|
|
|
2803
2949
|
}
|
|
2804
2950
|
getSessionFiles(sessionsPath) {
|
|
2805
2951
|
const files = /* @__PURE__ */ new Map();
|
|
2806
|
-
if (!
|
|
2952
|
+
if (!existsSync17(sessionsPath)) {
|
|
2807
2953
|
return files;
|
|
2808
2954
|
}
|
|
2809
2955
|
try {
|
|
@@ -2812,7 +2958,7 @@ var QwenPawParser = class {
|
|
|
2812
2958
|
if (!fileName.endsWith(".json")) {
|
|
2813
2959
|
continue;
|
|
2814
2960
|
}
|
|
2815
|
-
const filePath =
|
|
2961
|
+
const filePath = join17(sessionsPath, fileName);
|
|
2816
2962
|
const content = readFileSafe(filePath);
|
|
2817
2963
|
if (content) {
|
|
2818
2964
|
const sessionId = fileName.replace(/^[^_]+_/, "").replace(".json", "");
|
|
@@ -2910,15 +3056,15 @@ var QwenPawParser = class {
|
|
|
2910
3056
|
});
|
|
2911
3057
|
}
|
|
2912
3058
|
isInstalled() {
|
|
2913
|
-
return
|
|
3059
|
+
return existsSync17(this.usagePath) || existsSync17(this.workspacePath);
|
|
2914
3060
|
}
|
|
2915
3061
|
};
|
|
2916
3062
|
registerParser(new QwenPawParser());
|
|
2917
3063
|
|
|
2918
3064
|
// src/parsers/cline.ts
|
|
2919
3065
|
import { readFileSync as readFileSync6, statSync } from "fs";
|
|
2920
|
-
import { homedir as
|
|
2921
|
-
import { basename as
|
|
3066
|
+
import { homedir as homedir17 } from "os";
|
|
3067
|
+
import { basename as basename7, join as join18 } from "path";
|
|
2922
3068
|
var EXTENSION_ID = "saoudrizwan.claude-dev";
|
|
2923
3069
|
var HOSTS = [
|
|
2924
3070
|
"Code",
|
|
@@ -2932,26 +3078,26 @@ var HOSTS = [
|
|
|
2932
3078
|
var TOOL6 = {
|
|
2933
3079
|
id: "cline",
|
|
2934
3080
|
name: "Cline",
|
|
2935
|
-
dataDir:
|
|
3081
|
+
dataDir: join18(homedir17(), ".cline")
|
|
2936
3082
|
};
|
|
2937
3083
|
function getHostRoots() {
|
|
2938
3084
|
const out = [];
|
|
2939
3085
|
if (process.platform === "darwin") {
|
|
2940
|
-
const base =
|
|
2941
|
-
for (const h of HOSTS) out.push(
|
|
3086
|
+
const base = join18(homedir17(), "Library", "Application Support");
|
|
3087
|
+
for (const h of HOSTS) out.push(join18(base, h));
|
|
2942
3088
|
} else if (process.platform === "win32") {
|
|
2943
|
-
const appData = process.env.APPDATA?.trim() ||
|
|
2944
|
-
for (const h of HOSTS) out.push(
|
|
3089
|
+
const appData = process.env.APPDATA?.trim() || join18(homedir17(), "AppData", "Roaming");
|
|
3090
|
+
for (const h of HOSTS) out.push(join18(appData, h));
|
|
2945
3091
|
} else {
|
|
2946
|
-
const xdg = process.env.XDG_CONFIG_HOME?.trim() ||
|
|
2947
|
-
for (const h of HOSTS) out.push(
|
|
3092
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim() || join18(homedir17(), ".config");
|
|
3093
|
+
for (const h of HOSTS) out.push(join18(xdg, h));
|
|
2948
3094
|
}
|
|
2949
3095
|
return out;
|
|
2950
3096
|
}
|
|
2951
3097
|
function findClineExtensionDirs() {
|
|
2952
3098
|
const dirs = [];
|
|
2953
3099
|
for (const root of getHostRoots()) {
|
|
2954
|
-
const ext =
|
|
3100
|
+
const ext = join18(root, "User", "globalStorage", EXTENSION_ID);
|
|
2955
3101
|
try {
|
|
2956
3102
|
if (statSync(ext).isDirectory()) dirs.push(ext);
|
|
2957
3103
|
} catch {
|
|
@@ -2969,7 +3115,7 @@ function readJsonSafe(path) {
|
|
|
2969
3115
|
function projectFromPath(absPath) {
|
|
2970
3116
|
if (!absPath || typeof absPath !== "string") return "unknown";
|
|
2971
3117
|
const trimmed = absPath.replace(/[\\/]+$/, "");
|
|
2972
|
-
const name =
|
|
3118
|
+
const name = basename7(trimmed);
|
|
2973
3119
|
return name || "unknown";
|
|
2974
3120
|
}
|
|
2975
3121
|
var ClineParser = class {
|
|
@@ -2983,7 +3129,7 @@ var ClineParser = class {
|
|
|
2983
3129
|
const entries = [];
|
|
2984
3130
|
const sessionEvents = [];
|
|
2985
3131
|
for (const extDir of extDirs) {
|
|
2986
|
-
const history = readJsonSafe(
|
|
3132
|
+
const history = readJsonSafe(join18(extDir, "state", "taskHistory.json"));
|
|
2987
3133
|
if (!Array.isArray(history)) continue;
|
|
2988
3134
|
for (const item of history) {
|
|
2989
3135
|
try {
|
|
@@ -2994,7 +3140,7 @@ var ClineParser = class {
|
|
|
2994
3140
|
);
|
|
2995
3141
|
const fallbackModel = item.modelId && String(item.modelId).trim() || "cline-unknown";
|
|
2996
3142
|
const messages = readJsonSafe(
|
|
2997
|
-
|
|
3143
|
+
join18(extDir, "tasks", taskId, "ui_messages.json")
|
|
2998
3144
|
);
|
|
2999
3145
|
if (!Array.isArray(messages)) continue;
|
|
3000
3146
|
for (const msg of messages) {
|
|
@@ -3065,20 +3211,20 @@ registerParser(new ClineParser());
|
|
|
3065
3211
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
3066
3212
|
import {
|
|
3067
3213
|
copyFileSync,
|
|
3068
|
-
existsSync as
|
|
3214
|
+
existsSync as existsSync18,
|
|
3069
3215
|
mkdtempSync,
|
|
3070
3216
|
readdirSync as readdirSync10,
|
|
3071
3217
|
readFileSync as readFileSync7,
|
|
3072
3218
|
rmSync,
|
|
3073
3219
|
statSync as statSync2
|
|
3074
3220
|
} from "fs";
|
|
3075
|
-
import { homedir as
|
|
3076
|
-
import { join as
|
|
3077
|
-
var KIROAGENT_RELATIVE =
|
|
3221
|
+
import { homedir as homedir18, tmpdir } from "os";
|
|
3222
|
+
import { join as join19, resolve } from "path";
|
|
3223
|
+
var KIROAGENT_RELATIVE = join19("User", "globalStorage", "kiro.kiroagent");
|
|
3078
3224
|
function getDefaultBasePath() {
|
|
3079
3225
|
if (process.platform === "darwin") {
|
|
3080
|
-
return
|
|
3081
|
-
|
|
3226
|
+
return join19(
|
|
3227
|
+
homedir18(),
|
|
3082
3228
|
"Library",
|
|
3083
3229
|
"Application Support",
|
|
3084
3230
|
"Kiro",
|
|
@@ -3086,11 +3232,11 @@ function getDefaultBasePath() {
|
|
|
3086
3232
|
);
|
|
3087
3233
|
}
|
|
3088
3234
|
if (process.platform === "win32") {
|
|
3089
|
-
const appData = process.env.APPDATA?.trim() ||
|
|
3090
|
-
return
|
|
3235
|
+
const appData = process.env.APPDATA?.trim() || join19(homedir18(), "AppData", "Roaming");
|
|
3236
|
+
return join19(appData, "Kiro", KIROAGENT_RELATIVE);
|
|
3091
3237
|
}
|
|
3092
|
-
const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() ||
|
|
3093
|
-
return
|
|
3238
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() || join19(homedir18(), ".config");
|
|
3239
|
+
return join19(xdgConfigHome, "Kiro", KIROAGENT_RELATIVE);
|
|
3094
3240
|
}
|
|
3095
3241
|
var TOOL7 = {
|
|
3096
3242
|
id: "kiro",
|
|
@@ -3101,10 +3247,10 @@ function getKiroBasePath() {
|
|
|
3101
3247
|
const explicit = process.env.KIRO_BASE_PATH?.trim();
|
|
3102
3248
|
if (explicit) {
|
|
3103
3249
|
const r = resolve(explicit);
|
|
3104
|
-
return
|
|
3250
|
+
return existsSync18(r) ? r : null;
|
|
3105
3251
|
}
|
|
3106
3252
|
const def = getDefaultBasePath();
|
|
3107
|
-
return
|
|
3253
|
+
return existsSync18(def) ? def : null;
|
|
3108
3254
|
}
|
|
3109
3255
|
function isLockError(err) {
|
|
3110
3256
|
return err instanceof Error && typeof err.message === "string" && /database is locked/i.test(err.message);
|
|
@@ -3125,12 +3271,12 @@ function readDb(dbPath) {
|
|
|
3125
3271
|
return queryDb(dbPath, TOKENS_SQL);
|
|
3126
3272
|
} catch (err) {
|
|
3127
3273
|
if (!isLockError(err)) throw err;
|
|
3128
|
-
const snapshotDir = mkdtempSync(
|
|
3129
|
-
const queryPath =
|
|
3274
|
+
const snapshotDir = mkdtempSync(join19(tmpdir(), "vibe-usage-kiro-"));
|
|
3275
|
+
const queryPath = join19(snapshotDir, "devdata.sqlite");
|
|
3130
3276
|
copyFileSync(dbPath, queryPath);
|
|
3131
3277
|
for (const suffix of ["-shm", "-wal"]) {
|
|
3132
3278
|
const companion = `${dbPath}${suffix}`;
|
|
3133
|
-
if (
|
|
3279
|
+
if (existsSync18(companion))
|
|
3134
3280
|
copyFileSync(companion, `${queryPath}${suffix}`);
|
|
3135
3281
|
}
|
|
3136
3282
|
try {
|
|
@@ -3182,7 +3328,7 @@ function buildModelTimeline(base) {
|
|
|
3182
3328
|
}
|
|
3183
3329
|
for (const entry of entries) {
|
|
3184
3330
|
if (!entry.isDirectory() || entry.name === "dev_data") continue;
|
|
3185
|
-
const dirPath =
|
|
3331
|
+
const dirPath = join19(base, entry.name);
|
|
3186
3332
|
let files;
|
|
3187
3333
|
try {
|
|
3188
3334
|
files = readdirSync10(dirPath).filter((f) => f.endsWith(".chat"));
|
|
@@ -3191,7 +3337,7 @@ function buildModelTimeline(base) {
|
|
|
3191
3337
|
}
|
|
3192
3338
|
for (const file of files) {
|
|
3193
3339
|
try {
|
|
3194
|
-
const data = JSON.parse(readFileSync7(
|
|
3340
|
+
const data = JSON.parse(readFileSync7(join19(dirPath, file), "utf-8"));
|
|
3195
3341
|
const meta = data?.metadata;
|
|
3196
3342
|
if (!meta?.modelId || !meta?.startTime) continue;
|
|
3197
3343
|
const startMs = Number(meta.startTime);
|
|
@@ -3240,13 +3386,13 @@ var KiroParser = class {
|
|
|
3240
3386
|
async parse() {
|
|
3241
3387
|
const base = getKiroBasePath();
|
|
3242
3388
|
if (!base) return { buckets: [], sessions: [] };
|
|
3243
|
-
const dbPath =
|
|
3244
|
-
const jsonlPath =
|
|
3389
|
+
const dbPath = join19(base, "dev_data", "devdata.sqlite");
|
|
3390
|
+
const jsonlPath = join19(base, "dev_data", "tokens_generated.jsonl");
|
|
3245
3391
|
let rows;
|
|
3246
3392
|
try {
|
|
3247
|
-
if (
|
|
3393
|
+
if (existsSync18(dbPath)) {
|
|
3248
3394
|
rows = readDb(dbPath);
|
|
3249
|
-
} else if (
|
|
3395
|
+
} else if (existsSync18(jsonlPath)) {
|
|
3250
3396
|
rows = readJsonl(jsonlPath);
|
|
3251
3397
|
} else {
|
|
3252
3398
|
return { buckets: [], sessions: [] };
|
|
@@ -3297,8 +3443,8 @@ registerParser(new KiroParser());
|
|
|
3297
3443
|
|
|
3298
3444
|
// src/parsers/roo-code.ts
|
|
3299
3445
|
import { readdirSync as readdirSync11, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
3300
|
-
import { homedir as
|
|
3301
|
-
import { basename as
|
|
3446
|
+
import { homedir as homedir19 } from "os";
|
|
3447
|
+
import { basename as basename8, join as join20 } from "path";
|
|
3302
3448
|
var EXTENSION_ID2 = "rooveterinaryinc.roo-cline";
|
|
3303
3449
|
var HOSTS2 = [
|
|
3304
3450
|
"Code",
|
|
@@ -3313,17 +3459,17 @@ function getHostRoots2() {
|
|
|
3313
3459
|
const out = [];
|
|
3314
3460
|
let roots;
|
|
3315
3461
|
if (process.platform === "darwin") {
|
|
3316
|
-
roots = [
|
|
3462
|
+
roots = [join20(homedir19(), "Library", "Application Support")];
|
|
3317
3463
|
} else if (process.platform === "win32") {
|
|
3318
3464
|
roots = [
|
|
3319
|
-
process.env.APPDATA?.trim() ||
|
|
3465
|
+
process.env.APPDATA?.trim() || join20(homedir19(), "AppData", "Roaming")
|
|
3320
3466
|
];
|
|
3321
3467
|
} else {
|
|
3322
|
-
roots = [process.env.XDG_CONFIG_HOME?.trim() ||
|
|
3468
|
+
roots = [process.env.XDG_CONFIG_HOME?.trim() || join20(homedir19(), ".config")];
|
|
3323
3469
|
}
|
|
3324
3470
|
for (const root of roots) {
|
|
3325
3471
|
for (const h of HOSTS2) {
|
|
3326
|
-
out.push(
|
|
3472
|
+
out.push(join20(root, h));
|
|
3327
3473
|
}
|
|
3328
3474
|
}
|
|
3329
3475
|
return out;
|
|
@@ -3331,7 +3477,7 @@ function getHostRoots2() {
|
|
|
3331
3477
|
function findExtensionDirs() {
|
|
3332
3478
|
const dirs = [];
|
|
3333
3479
|
for (const root of getHostRoots2()) {
|
|
3334
|
-
const ext =
|
|
3480
|
+
const ext = join20(root, "User", "globalStorage", EXTENSION_ID2);
|
|
3335
3481
|
try {
|
|
3336
3482
|
if (statSync3(ext).isDirectory()) dirs.push(ext);
|
|
3337
3483
|
} catch {
|
|
@@ -3349,13 +3495,13 @@ function readJsonSafe2(path) {
|
|
|
3349
3495
|
function projectFromPath2(absPath) {
|
|
3350
3496
|
if (!absPath || typeof absPath !== "string") return "unknown";
|
|
3351
3497
|
const trimmed = absPath.replace(/[\\/]+$/, "");
|
|
3352
|
-
const name =
|
|
3498
|
+
const name = basename8(trimmed);
|
|
3353
3499
|
return name || "unknown";
|
|
3354
3500
|
}
|
|
3355
3501
|
function readHistoryItems(extDir) {
|
|
3356
|
-
const tasksDir =
|
|
3502
|
+
const tasksDir = join20(extDir, "tasks");
|
|
3357
3503
|
const index = readJsonSafe2(
|
|
3358
|
-
|
|
3504
|
+
join20(tasksDir, "_index.json")
|
|
3359
3505
|
);
|
|
3360
3506
|
if (index?.entries && Array.isArray(index.entries)) return index.entries;
|
|
3361
3507
|
const items = [];
|
|
@@ -3369,7 +3515,7 @@ function readHistoryItems(extDir) {
|
|
|
3369
3515
|
if (!entry.isDirectory() || entry.name.startsWith("_") || entry.name.startsWith("."))
|
|
3370
3516
|
continue;
|
|
3371
3517
|
const item = readJsonSafe2(
|
|
3372
|
-
|
|
3518
|
+
join20(tasksDir, entry.name, "history_item.json")
|
|
3373
3519
|
);
|
|
3374
3520
|
if (item && typeof item === "object") items.push(item);
|
|
3375
3521
|
}
|
|
@@ -3396,7 +3542,7 @@ var RooCodeParser = class {
|
|
|
3396
3542
|
const project = projectFromPath2(item.workspace);
|
|
3397
3543
|
const fallbackModel = item.apiConfigName && String(item.apiConfigName).trim() || "roo-unknown";
|
|
3398
3544
|
const messages = readJsonSafe2(
|
|
3399
|
-
|
|
3545
|
+
join20(extDir, "tasks", taskId, "ui_messages.json")
|
|
3400
3546
|
);
|
|
3401
3547
|
if (!Array.isArray(messages)) continue;
|
|
3402
3548
|
for (const msg of messages) {
|
|
@@ -3460,11 +3606,11 @@ var RooCodeParser = class {
|
|
|
3460
3606
|
registerParser(new RooCodeParser());
|
|
3461
3607
|
|
|
3462
3608
|
// src/parsers/snow.ts
|
|
3463
|
-
import { existsSync as
|
|
3464
|
-
import { homedir as
|
|
3465
|
-
import { join as
|
|
3466
|
-
var DEFAULT_DATA_DIR6 =
|
|
3467
|
-
function
|
|
3609
|
+
import { existsSync as existsSync19 } from "fs";
|
|
3610
|
+
import { homedir as homedir20 } from "os";
|
|
3611
|
+
import { join as join21 } from "path";
|
|
3612
|
+
var DEFAULT_DATA_DIR6 = join21(homedir20(), ".snow", "usage");
|
|
3613
|
+
function toNonNegativeNumber2(value) {
|
|
3468
3614
|
const numberValue = Number(value);
|
|
3469
3615
|
return Number.isFinite(numberValue) && numberValue >= 0 ? numberValue : 0;
|
|
3470
3616
|
}
|
|
@@ -3487,10 +3633,10 @@ var SnowParser = class {
|
|
|
3487
3633
|
if (typeof record.timestamp !== "string") continue;
|
|
3488
3634
|
const timestamp = new Date(record.timestamp);
|
|
3489
3635
|
if (Number.isNaN(timestamp.getTime())) continue;
|
|
3490
|
-
const inputTokens =
|
|
3491
|
-
const outputTokens =
|
|
3492
|
-
const cachedTokens =
|
|
3493
|
-
const reasoningTokens =
|
|
3636
|
+
const inputTokens = toNonNegativeNumber2(record.inputTokens);
|
|
3637
|
+
const outputTokens = toNonNegativeNumber2(record.outputTokens);
|
|
3638
|
+
const cachedTokens = toNonNegativeNumber2(record.cacheReadInputTokens);
|
|
3639
|
+
const reasoningTokens = toNonNegativeNumber2(record.reasoningTokens);
|
|
3494
3640
|
if (inputTokens + outputTokens + cachedTokens + reasoningTokens === 0)
|
|
3495
3641
|
continue;
|
|
3496
3642
|
entries.push({
|
|
@@ -3510,26 +3656,26 @@ var SnowParser = class {
|
|
|
3510
3656
|
return { buckets: aggregateToBuckets(entries), sessions: [] };
|
|
3511
3657
|
}
|
|
3512
3658
|
isInstalled() {
|
|
3513
|
-
return
|
|
3659
|
+
return existsSync19(this.dataDir);
|
|
3514
3660
|
}
|
|
3515
3661
|
};
|
|
3516
3662
|
registerParser(new SnowParser());
|
|
3517
3663
|
|
|
3518
3664
|
// src/parsers/cursor.ts
|
|
3519
3665
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
3520
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
3521
|
-
import { homedir as
|
|
3522
|
-
import { dirname as dirname4, join as
|
|
3523
|
-
var
|
|
3524
|
-
var
|
|
3525
|
-
var STATE_DB_RELATIVE =
|
|
3666
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync20, mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
|
|
3667
|
+
import { homedir as homedir21, tmpdir as tmpdir2 } from "os";
|
|
3668
|
+
import { dirname as dirname4, join as join22, resolve as resolve2 } from "path";
|
|
3669
|
+
var TOOL_ID13 = "cursor";
|
|
3670
|
+
var TOOL_NAME13 = "Cursor";
|
|
3671
|
+
var STATE_DB_RELATIVE = join22("User", "globalStorage", "state.vscdb");
|
|
3526
3672
|
var ACCESS_TOKEN_KEY = "cursorAuth/accessToken";
|
|
3527
3673
|
var SESSION_COOKIE = "WorkosCursorSessionToken";
|
|
3528
3674
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
3529
3675
|
function getDefaultStateDbPath() {
|
|
3530
3676
|
if (process.platform === "darwin") {
|
|
3531
|
-
return
|
|
3532
|
-
|
|
3677
|
+
return join22(
|
|
3678
|
+
homedir21(),
|
|
3533
3679
|
"Library",
|
|
3534
3680
|
"Application Support",
|
|
3535
3681
|
"Cursor",
|
|
@@ -3537,25 +3683,25 @@ function getDefaultStateDbPath() {
|
|
|
3537
3683
|
);
|
|
3538
3684
|
}
|
|
3539
3685
|
if (process.platform === "win32") {
|
|
3540
|
-
const appData = process.env.APPDATA?.trim() ||
|
|
3541
|
-
return
|
|
3686
|
+
const appData = process.env.APPDATA?.trim() || join22(homedir21(), "AppData", "Roaming");
|
|
3687
|
+
return join22(appData, "Cursor", STATE_DB_RELATIVE);
|
|
3542
3688
|
}
|
|
3543
|
-
const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() ||
|
|
3544
|
-
return
|
|
3689
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim() || join22(homedir21(), ".config");
|
|
3690
|
+
return join22(xdgConfigHome, "Cursor", STATE_DB_RELATIVE);
|
|
3545
3691
|
}
|
|
3546
3692
|
function getCursorStateDbPath() {
|
|
3547
3693
|
const explicit = process.env.CURSOR_STATE_DB_PATH?.trim();
|
|
3548
3694
|
if (explicit) {
|
|
3549
3695
|
const resolved = resolve2(explicit);
|
|
3550
|
-
return
|
|
3696
|
+
return existsSync20(resolved) ? resolved : null;
|
|
3551
3697
|
}
|
|
3552
3698
|
const configDirs = process.env.CURSOR_CONFIG_DIR?.trim();
|
|
3553
3699
|
const candidates = configDirs ? configDirs.split(",").map((v) => v.trim()).filter(Boolean).map((v) => {
|
|
3554
3700
|
const r = resolve2(v);
|
|
3555
|
-
return r.endsWith(".vscdb") ? r :
|
|
3701
|
+
return r.endsWith(".vscdb") ? r : join22(r, STATE_DB_RELATIVE);
|
|
3556
3702
|
}) : [getDefaultStateDbPath()];
|
|
3557
3703
|
for (const c of candidates) {
|
|
3558
|
-
if (
|
|
3704
|
+
if (existsSync20(c)) return c;
|
|
3559
3705
|
}
|
|
3560
3706
|
return null;
|
|
3561
3707
|
}
|
|
@@ -3595,13 +3741,13 @@ function readAccessToken(dbPath) {
|
|
|
3595
3741
|
return queryAccessToken(dbPath);
|
|
3596
3742
|
} catch (err) {
|
|
3597
3743
|
if (!isLockError2(err)) throw err;
|
|
3598
|
-
const snapshotDir = mkdtempSync2(
|
|
3599
|
-
const queryPath =
|
|
3744
|
+
const snapshotDir = mkdtempSync2(join22(tmpdir2(), "tokenarena-cursor-"));
|
|
3745
|
+
const queryPath = join22(snapshotDir, "state.vscdb");
|
|
3600
3746
|
try {
|
|
3601
3747
|
copyFileSync2(dbPath, queryPath);
|
|
3602
3748
|
for (const suffix of ["-shm", "-wal"]) {
|
|
3603
3749
|
const companion = `${dbPath}${suffix}`;
|
|
3604
|
-
if (
|
|
3750
|
+
if (existsSync20(companion))
|
|
3605
3751
|
copyFileSync2(companion, `${queryPath}${suffix}`);
|
|
3606
3752
|
}
|
|
3607
3753
|
return queryAccessToken(queryPath);
|
|
@@ -3729,8 +3875,8 @@ function parseInt0(value) {
|
|
|
3729
3875
|
}
|
|
3730
3876
|
function createToolDefinition10(dbPath) {
|
|
3731
3877
|
return {
|
|
3732
|
-
id:
|
|
3733
|
-
name:
|
|
3878
|
+
id: TOOL_ID13,
|
|
3879
|
+
name: TOOL_NAME13,
|
|
3734
3880
|
dataDir: dirname4(dbPath)
|
|
3735
3881
|
};
|
|
3736
3882
|
}
|
|
@@ -3746,7 +3892,7 @@ var CursorParser = class {
|
|
|
3746
3892
|
this.tool = createToolDefinition10(this.dbPath);
|
|
3747
3893
|
}
|
|
3748
3894
|
async parse() {
|
|
3749
|
-
if (!this.dbPath || !
|
|
3895
|
+
if (!this.dbPath || !existsSync20(this.dbPath)) {
|
|
3750
3896
|
return { buckets: [], sessions: [] };
|
|
3751
3897
|
}
|
|
3752
3898
|
let token;
|
|
@@ -3793,7 +3939,7 @@ var CursorParser = class {
|
|
|
3793
3939
|
const output = outputIdx >= 0 ? parseInt0(row[outputIdx]) : 0;
|
|
3794
3940
|
if (inputCacheWrite + inputNoCache + cacheRead + output === 0) continue;
|
|
3795
3941
|
entries.push({
|
|
3796
|
-
source:
|
|
3942
|
+
source: TOOL_ID13,
|
|
3797
3943
|
model,
|
|
3798
3944
|
project: "unknown",
|
|
3799
3945
|
timestamp,
|
|
@@ -3809,19 +3955,19 @@ var CursorParser = class {
|
|
|
3809
3955
|
};
|
|
3810
3956
|
}
|
|
3811
3957
|
isInstalled() {
|
|
3812
|
-
return
|
|
3958
|
+
return existsSync20(this.dbPath);
|
|
3813
3959
|
}
|
|
3814
3960
|
};
|
|
3815
3961
|
registerParser(new CursorParser());
|
|
3816
3962
|
|
|
3817
3963
|
// src/parsers/zcode.ts
|
|
3818
3964
|
import { createHash as createHash2 } from "crypto";
|
|
3819
|
-
import { existsSync as
|
|
3820
|
-
import { homedir as
|
|
3821
|
-
import { dirname as dirname5, join as
|
|
3822
|
-
var
|
|
3823
|
-
var
|
|
3824
|
-
var DEFAULT_DB_PATH3 =
|
|
3965
|
+
import { existsSync as existsSync21 } from "fs";
|
|
3966
|
+
import { homedir as homedir22, hostname as hostname4 } from "os";
|
|
3967
|
+
import { dirname as dirname5, join as join23 } from "path";
|
|
3968
|
+
var TOOL_ID14 = "zcode";
|
|
3969
|
+
var TOOL_NAME14 = "ZCode";
|
|
3970
|
+
var DEFAULT_DB_PATH3 = join23(homedir22(), ".zcode", "cli", "db", "db.sqlite");
|
|
3825
3971
|
var MODEL_USAGE_QUERY = `SELECT
|
|
3826
3972
|
model_usage.session_id as sessionId,
|
|
3827
3973
|
session.directory as directory,
|
|
@@ -3856,8 +4002,8 @@ var TURN_USAGE_QUERY = `SELECT
|
|
|
3856
4002
|
WHERE duration_ms IS NOT NULL`;
|
|
3857
4003
|
function createToolDefinition11(dbPath) {
|
|
3858
4004
|
return {
|
|
3859
|
-
id:
|
|
3860
|
-
name:
|
|
4005
|
+
id: TOOL_ID14,
|
|
4006
|
+
name: TOOL_NAME14,
|
|
3861
4007
|
dataDir: dirname5(dbPath)
|
|
3862
4008
|
};
|
|
3863
4009
|
}
|
|
@@ -3905,7 +4051,7 @@ function getOrCreateDraft(drafts, sessionId, project) {
|
|
|
3905
4051
|
}
|
|
3906
4052
|
const next = {
|
|
3907
4053
|
sessionId,
|
|
3908
|
-
source:
|
|
4054
|
+
source: TOOL_ID14,
|
|
3909
4055
|
project,
|
|
3910
4056
|
firstMessageAt: null,
|
|
3911
4057
|
lastMessageAt: null,
|
|
@@ -4073,7 +4219,7 @@ var ZCodeParser = class {
|
|
|
4073
4219
|
this.tool = createToolDefinition11(this.dbPath);
|
|
4074
4220
|
}
|
|
4075
4221
|
async parse() {
|
|
4076
|
-
if (!
|
|
4222
|
+
if (!existsSync21(this.dbPath)) {
|
|
4077
4223
|
return { buckets: [], sessions: [] };
|
|
4078
4224
|
}
|
|
4079
4225
|
const usageRows = await this.queryRows(
|
|
@@ -4095,7 +4241,7 @@ var ZCodeParser = class {
|
|
|
4095
4241
|
}
|
|
4096
4242
|
entries.push({
|
|
4097
4243
|
sessionId: getString2(row.sessionId) ?? void 0,
|
|
4098
|
-
source:
|
|
4244
|
+
source: TOOL_ID14,
|
|
4099
4245
|
model: getString2(row.model) ?? "unknown",
|
|
4100
4246
|
project: getPathLeaf7(getString2(row.directory)),
|
|
4101
4247
|
timestamp,
|
|
@@ -4131,42 +4277,473 @@ var ZCodeParser = class {
|
|
|
4131
4277
|
};
|
|
4132
4278
|
}
|
|
4133
4279
|
isInstalled() {
|
|
4134
|
-
return
|
|
4280
|
+
return existsSync21(this.dbPath);
|
|
4135
4281
|
}
|
|
4136
4282
|
};
|
|
4137
4283
|
registerParser(new ZCodeParser());
|
|
4138
4284
|
|
|
4285
|
+
// src/parsers/qodercli.ts
|
|
4286
|
+
import { existsSync as existsSync22, readdirSync as readdirSync12 } from "fs";
|
|
4287
|
+
import { homedir as homedir23 } from "os";
|
|
4288
|
+
import { basename as basename9, join as join24 } from "path";
|
|
4289
|
+
var TOOL_ID15 = "qodercli";
|
|
4290
|
+
var TOOL_NAME15 = "Qoder CLI";
|
|
4291
|
+
var DEFAULT_PROJECTS_DIR = join24(homedir23(), ".qoder", "projects");
|
|
4292
|
+
var DEFAULT_LOGS_DIR = join24(homedir23(), ".qoder", "logs", "sessions");
|
|
4293
|
+
var DEFAULT_RUNS_DIR = join24(homedir23(), ".qoder", "logs", "runs");
|
|
4294
|
+
var CLI_ENTRYPOINT = "cli";
|
|
4295
|
+
var IDE_ENTRYPOINT = "acp";
|
|
4296
|
+
var CREDIT_MODEL_FALLBACK = "credits";
|
|
4297
|
+
function createToolDefinition12(projectsDir) {
|
|
4298
|
+
return {
|
|
4299
|
+
id: TOOL_ID15,
|
|
4300
|
+
name: TOOL_NAME15,
|
|
4301
|
+
dataDir: projectsDir
|
|
4302
|
+
};
|
|
4303
|
+
}
|
|
4304
|
+
function toSafeNumber12(value) {
|
|
4305
|
+
const numberValue = Number(value);
|
|
4306
|
+
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
4307
|
+
}
|
|
4308
|
+
function normalizeForPrefix5(value) {
|
|
4309
|
+
return value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
4310
|
+
}
|
|
4311
|
+
function extractQoderProject(filePath, projectsDir) {
|
|
4312
|
+
const normalizedFilePath = normalizeForPrefix5(filePath);
|
|
4313
|
+
const normalizedProjectsDir = normalizeForPrefix5(projectsDir);
|
|
4314
|
+
const prefix = `${normalizedProjectsDir}/`;
|
|
4315
|
+
if (!normalizedFilePath.startsWith(prefix)) return "unknown";
|
|
4316
|
+
const relative = normalizedFilePath.slice(prefix.length);
|
|
4317
|
+
const firstSeg = relative.split("/")[0];
|
|
4318
|
+
if (!firstSeg) return "unknown";
|
|
4319
|
+
const parts = firstSeg.split("-").filter(Boolean);
|
|
4320
|
+
return parts.length > 0 ? parts[parts.length - 1] ?? "unknown" : "unknown";
|
|
4321
|
+
}
|
|
4322
|
+
function classifyQoderEntrypoint(content) {
|
|
4323
|
+
let hasCli = false;
|
|
4324
|
+
let hasAcp = false;
|
|
4325
|
+
for (const line of content.split("\n")) {
|
|
4326
|
+
if (!line.trim()) continue;
|
|
4327
|
+
try {
|
|
4328
|
+
const obj = JSON.parse(line);
|
|
4329
|
+
if (obj.entrypoint === CLI_ENTRYPOINT) hasCli = true;
|
|
4330
|
+
else if (obj.entrypoint === IDE_ENTRYPOINT) hasAcp = true;
|
|
4331
|
+
} catch {
|
|
4332
|
+
}
|
|
4333
|
+
if (hasCli) return "cli";
|
|
4334
|
+
}
|
|
4335
|
+
if (hasAcp) return "acp";
|
|
4336
|
+
return "unknown";
|
|
4337
|
+
}
|
|
4338
|
+
function isQodercliBinaryPresent() {
|
|
4339
|
+
const home = homedir23();
|
|
4340
|
+
const candidates = [
|
|
4341
|
+
join24(home, ".local", "bin", "qodercli"),
|
|
4342
|
+
join24(home, ".qoder", "bin", "qodercli"),
|
|
4343
|
+
join24(home, ".qoder-cli")
|
|
4344
|
+
];
|
|
4345
|
+
return candidates.some((path) => existsSync22(path));
|
|
4346
|
+
}
|
|
4347
|
+
function projectFromEncodedSlug(slug) {
|
|
4348
|
+
const parts = slug.split("-").filter(Boolean);
|
|
4349
|
+
return parts.length > 0 ? parts[parts.length - 1] ?? "unknown" : "unknown";
|
|
4350
|
+
}
|
|
4351
|
+
function projectFromCwd(cwd) {
|
|
4352
|
+
if (!cwd) return "unknown";
|
|
4353
|
+
const leaf = basename9(cwd.replace(/[\\/]+$/, ""));
|
|
4354
|
+
return leaf || "unknown";
|
|
4355
|
+
}
|
|
4356
|
+
function totalCreditsUsed(quota) {
|
|
4357
|
+
return toSafeNumber12(quota.userQuota?.used) + toSafeNumber12(quota.orgResourcePackage?.used) + toSafeNumber12(quota.addOnQuota?.used);
|
|
4358
|
+
}
|
|
4359
|
+
function parseRunManifest(content) {
|
|
4360
|
+
if (!content) return null;
|
|
4361
|
+
try {
|
|
4362
|
+
return JSON.parse(content);
|
|
4363
|
+
} catch {
|
|
4364
|
+
return null;
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
function extractCreditSnapshotsFromLog(logContent, meta) {
|
|
4368
|
+
const snapshots = [];
|
|
4369
|
+
let sessionId = meta.defaultSessionId || meta.runId;
|
|
4370
|
+
let model = meta.defaultModel || CREDIT_MODEL_FALLBACK;
|
|
4371
|
+
for (const line of logContent.split("\n")) {
|
|
4372
|
+
if (!line.trim()) continue;
|
|
4373
|
+
if (line.includes("session.config.loaded")) {
|
|
4374
|
+
const sessionMatch = line.match(/session=([^\s\]]+)/);
|
|
4375
|
+
if (sessionMatch?.[1]) sessionId = sessionMatch[1];
|
|
4376
|
+
const modelMatch = line.match(/model="([^"]+)"/);
|
|
4377
|
+
if (modelMatch?.[1]) model = modelMatch[1];
|
|
4378
|
+
}
|
|
4379
|
+
if (!line.includes("quota/usage response:")) continue;
|
|
4380
|
+
const tsMatch = line.match(/^(\d{4}-\d{2}-\d{2}T[^\s]+)/);
|
|
4381
|
+
const jsonMatch = line.match(/response:\s+(\{.*\})\s*$/);
|
|
4382
|
+
if (!tsMatch?.[1] || !jsonMatch?.[1]) continue;
|
|
4383
|
+
let quota;
|
|
4384
|
+
try {
|
|
4385
|
+
quota = JSON.parse(jsonMatch[1]);
|
|
4386
|
+
} catch {
|
|
4387
|
+
continue;
|
|
4388
|
+
}
|
|
4389
|
+
const timestamp = new Date(tsMatch[1]);
|
|
4390
|
+
if (Number.isNaN(timestamp.getTime())) continue;
|
|
4391
|
+
snapshots.push({
|
|
4392
|
+
timestamp,
|
|
4393
|
+
// credits, not tokens
|
|
4394
|
+
totalUsed: totalCreditsUsed(quota),
|
|
4395
|
+
project: meta.project,
|
|
4396
|
+
sessionId,
|
|
4397
|
+
model,
|
|
4398
|
+
runId: meta.runId
|
|
4399
|
+
});
|
|
4400
|
+
}
|
|
4401
|
+
return snapshots;
|
|
4402
|
+
}
|
|
4403
|
+
function creditSnapshotsToEntries(snapshots) {
|
|
4404
|
+
if (snapshots.length === 0) return [];
|
|
4405
|
+
const sorted = [...snapshots].sort(
|
|
4406
|
+
(a, b) => a.timestamp.getTime() - b.timestamp.getTime()
|
|
4407
|
+
);
|
|
4408
|
+
const entries = [];
|
|
4409
|
+
let previousUsed = null;
|
|
4410
|
+
for (const snap of sorted) {
|
|
4411
|
+
if (previousUsed !== null) {
|
|
4412
|
+
const creditDelta = snap.totalUsed - previousUsed;
|
|
4413
|
+
if (creditDelta > 0) {
|
|
4414
|
+
entries.push({
|
|
4415
|
+
sessionId: snap.sessionId,
|
|
4416
|
+
source: TOOL_ID15,
|
|
4417
|
+
model: snap.model || CREDIT_MODEL_FALLBACK,
|
|
4418
|
+
project: snap.project,
|
|
4419
|
+
timestamp: snap.timestamp,
|
|
4420
|
+
// CREDIT counts (not tokens) — see file header.
|
|
4421
|
+
inputTokens: creditDelta,
|
|
4422
|
+
outputTokens: 0,
|
|
4423
|
+
reasoningTokens: 0,
|
|
4424
|
+
cachedTokens: 0
|
|
4425
|
+
});
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
previousUsed = snap.totalUsed;
|
|
4429
|
+
}
|
|
4430
|
+
return entries;
|
|
4431
|
+
}
|
|
4432
|
+
var QoderCliParser = class {
|
|
4433
|
+
constructor(projectsDir = DEFAULT_PROJECTS_DIR, logsDir = DEFAULT_LOGS_DIR, runsDir = DEFAULT_RUNS_DIR) {
|
|
4434
|
+
this.projectsDir = projectsDir;
|
|
4435
|
+
this.logsDir = logsDir;
|
|
4436
|
+
this.runsDir = runsDir;
|
|
4437
|
+
this.tool = createToolDefinition12(projectsDir);
|
|
4438
|
+
}
|
|
4439
|
+
projectsDir;
|
|
4440
|
+
logsDir;
|
|
4441
|
+
runsDir;
|
|
4442
|
+
tool;
|
|
4443
|
+
async parse() {
|
|
4444
|
+
const entries = [];
|
|
4445
|
+
const sessionEvents = [];
|
|
4446
|
+
this.parseProjectSessions(sessionEvents);
|
|
4447
|
+
entries.push(...this.parseCreditDeltas());
|
|
4448
|
+
return {
|
|
4449
|
+
buckets: aggregateToBuckets(entries),
|
|
4450
|
+
sessions: extractSessions(sessionEvents, entries)
|
|
4451
|
+
};
|
|
4452
|
+
}
|
|
4453
|
+
parseProjectSessions(sessionEvents) {
|
|
4454
|
+
if (!existsSync22(this.projectsDir)) return;
|
|
4455
|
+
for (const filePath of findJsonlFiles(this.projectsDir)) {
|
|
4456
|
+
if (basename9(filePath).startsWith("verified-")) continue;
|
|
4457
|
+
const content = readFileSafe(filePath);
|
|
4458
|
+
if (!content) continue;
|
|
4459
|
+
if (classifyQoderEntrypoint(content) !== CLI_ENTRYPOINT) continue;
|
|
4460
|
+
const project = extractQoderProject(filePath, this.projectsDir);
|
|
4461
|
+
const sessionId = extractSessionId(filePath);
|
|
4462
|
+
for (const line of content.split("\n")) {
|
|
4463
|
+
if (!line.trim()) continue;
|
|
4464
|
+
try {
|
|
4465
|
+
const obj = JSON.parse(line);
|
|
4466
|
+
if (obj.entrypoint === IDE_ENTRYPOINT) continue;
|
|
4467
|
+
if (obj.type !== "user" && obj.type !== "assistant") continue;
|
|
4468
|
+
const timestamp = obj.timestamp;
|
|
4469
|
+
if (timestamp == null) continue;
|
|
4470
|
+
const ts = new Date(
|
|
4471
|
+
typeof timestamp === "number" && timestamp < 1e12 ? timestamp * 1e3 : timestamp
|
|
4472
|
+
);
|
|
4473
|
+
if (Number.isNaN(ts.getTime())) continue;
|
|
4474
|
+
sessionEvents.push({
|
|
4475
|
+
sessionId,
|
|
4476
|
+
source: TOOL_ID15,
|
|
4477
|
+
project,
|
|
4478
|
+
timestamp: ts,
|
|
4479
|
+
role: obj.type === "user" ? "user" : "assistant"
|
|
4480
|
+
});
|
|
4481
|
+
} catch {
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
/**
|
|
4487
|
+
* Parse credit consumption from run logs.
|
|
4488
|
+
* There is no token data here — only quota/usage credit totals.
|
|
4489
|
+
*/
|
|
4490
|
+
parseCreditDeltas() {
|
|
4491
|
+
if (!existsSync22(this.runsDir)) return [];
|
|
4492
|
+
let runDirs;
|
|
4493
|
+
try {
|
|
4494
|
+
runDirs = readdirSync12(this.runsDir, { withFileTypes: true }).filter(
|
|
4495
|
+
(d) => d.isDirectory()
|
|
4496
|
+
);
|
|
4497
|
+
} catch {
|
|
4498
|
+
return [];
|
|
4499
|
+
}
|
|
4500
|
+
const allSnapshots = [];
|
|
4501
|
+
for (const dir of runDirs) {
|
|
4502
|
+
const runPath = join24(this.runsDir, dir.name);
|
|
4503
|
+
const logPath = join24(runPath, "qodercli.log");
|
|
4504
|
+
if (!existsSync22(logPath)) continue;
|
|
4505
|
+
const logContent = readFileSafe(logPath);
|
|
4506
|
+
if (!logContent?.includes("quota/usage response:")) {
|
|
4507
|
+
continue;
|
|
4508
|
+
}
|
|
4509
|
+
const manifest = parseRunManifest(
|
|
4510
|
+
readFileSafe(join24(runPath, "manifest.json"))
|
|
4511
|
+
);
|
|
4512
|
+
const project = manifest?.project_id ? projectFromEncodedSlug(manifest.project_id) : projectFromCwd(manifest?.cwd);
|
|
4513
|
+
const snapshots = extractCreditSnapshotsFromLog(logContent, {
|
|
4514
|
+
project,
|
|
4515
|
+
runId: manifest?.run_id || dir.name
|
|
4516
|
+
});
|
|
4517
|
+
allSnapshots.push(...snapshots);
|
|
4518
|
+
}
|
|
4519
|
+
return creditSnapshotsToEntries(allSnapshots);
|
|
4520
|
+
}
|
|
4521
|
+
isInstalled() {
|
|
4522
|
+
return isQodercliBinaryPresent() || existsSync22(this.runsDir) || existsSync22(this.logsDir) || existsSync22(this.projectsDir);
|
|
4523
|
+
}
|
|
4524
|
+
};
|
|
4525
|
+
registerParser(new QoderCliParser());
|
|
4526
|
+
|
|
4527
|
+
// src/parsers/grok-build.ts
|
|
4528
|
+
import { existsSync as existsSync23, readdirSync as readdirSync13 } from "fs";
|
|
4529
|
+
import { homedir as homedir24 } from "os";
|
|
4530
|
+
import { basename as basename10, join as join25 } from "path";
|
|
4531
|
+
var TOOL_ID16 = "grok-build";
|
|
4532
|
+
var TOOL_NAME16 = "Grok Build";
|
|
4533
|
+
var DEFAULT_DATA_DIR7 = join25(homedir24(), ".grok", "sessions");
|
|
4534
|
+
function createToolDefinition13(dataDir) {
|
|
4535
|
+
return {
|
|
4536
|
+
id: TOOL_ID16,
|
|
4537
|
+
name: TOOL_NAME16,
|
|
4538
|
+
dataDir
|
|
4539
|
+
};
|
|
4540
|
+
}
|
|
4541
|
+
function toSafeNumber13(value) {
|
|
4542
|
+
const numberValue = Number(value);
|
|
4543
|
+
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
4544
|
+
}
|
|
4545
|
+
function projectFromEncodedCwd(encoded) {
|
|
4546
|
+
try {
|
|
4547
|
+
const decoded = decodeURIComponent(encoded);
|
|
4548
|
+
const leaf = basename10(decoded.replace(/[\\/]+$/, ""));
|
|
4549
|
+
return leaf || "unknown";
|
|
4550
|
+
} catch {
|
|
4551
|
+
const leaf = basename10(encoded);
|
|
4552
|
+
return leaf || "unknown";
|
|
4553
|
+
}
|
|
4554
|
+
}
|
|
4555
|
+
function resolveTimestamp(obj) {
|
|
4556
|
+
const ms = obj._meta?.agentTimestampMs ?? obj.params?.update?._meta?.agentTimestampMs;
|
|
4557
|
+
if (typeof ms === "number" && Number.isFinite(ms)) {
|
|
4558
|
+
return new Date(ms);
|
|
4559
|
+
}
|
|
4560
|
+
const raw = obj.timestamp;
|
|
4561
|
+
if (raw == null) return null;
|
|
4562
|
+
if (typeof raw === "number") {
|
|
4563
|
+
return new Date(raw < 1e12 ? raw * 1e3 : raw);
|
|
4564
|
+
}
|
|
4565
|
+
const ts = new Date(raw);
|
|
4566
|
+
return Number.isNaN(ts.getTime()) ? null : ts;
|
|
4567
|
+
}
|
|
4568
|
+
function pushUsageEntries(entries, args) {
|
|
4569
|
+
const { sessionId, project, timestamp, usage, fallbackModel } = args;
|
|
4570
|
+
const modelUsage = usage.modelUsage;
|
|
4571
|
+
const models = modelUsage && Object.keys(modelUsage).length > 0 ? Object.entries(modelUsage) : [[fallbackModel, usage]];
|
|
4572
|
+
for (const [model, mu] of models) {
|
|
4573
|
+
const cached = toSafeNumber13(mu.cachedReadTokens);
|
|
4574
|
+
const reasoning = toSafeNumber13(mu.reasoningTokens);
|
|
4575
|
+
const rawInput = toSafeNumber13(mu.inputTokens);
|
|
4576
|
+
const rawOutput = toSafeNumber13(mu.outputTokens);
|
|
4577
|
+
const inputTokens = Math.max(0, rawInput - cached);
|
|
4578
|
+
const outputTokens = Math.max(0, rawOutput - reasoning);
|
|
4579
|
+
if (inputTokens === 0 && outputTokens === 0 && cached === 0 && reasoning === 0) {
|
|
4580
|
+
continue;
|
|
4581
|
+
}
|
|
4582
|
+
entries.push({
|
|
4583
|
+
sessionId,
|
|
4584
|
+
source: TOOL_ID16,
|
|
4585
|
+
model: model || fallbackModel || "unknown",
|
|
4586
|
+
project,
|
|
4587
|
+
timestamp,
|
|
4588
|
+
inputTokens,
|
|
4589
|
+
outputTokens,
|
|
4590
|
+
reasoningTokens: reasoning,
|
|
4591
|
+
cachedTokens: cached
|
|
4592
|
+
});
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
function findSessionDirs(dataDir) {
|
|
4596
|
+
const results = [];
|
|
4597
|
+
if (!existsSync23(dataDir)) return results;
|
|
4598
|
+
let projectDirs;
|
|
4599
|
+
try {
|
|
4600
|
+
projectDirs = readdirSync13(dataDir, { withFileTypes: true });
|
|
4601
|
+
} catch {
|
|
4602
|
+
return results;
|
|
4603
|
+
}
|
|
4604
|
+
for (const projectEntry of projectDirs) {
|
|
4605
|
+
if (!projectEntry.isDirectory()) continue;
|
|
4606
|
+
if (projectEntry.name.endsWith(".sqlite")) continue;
|
|
4607
|
+
const projectDir = join25(dataDir, projectEntry.name);
|
|
4608
|
+
const project = projectFromEncodedCwd(projectEntry.name);
|
|
4609
|
+
let sessionEntries;
|
|
4610
|
+
try {
|
|
4611
|
+
sessionEntries = readdirSync13(projectDir, { withFileTypes: true });
|
|
4612
|
+
} catch {
|
|
4613
|
+
continue;
|
|
4614
|
+
}
|
|
4615
|
+
for (const sessionEntry of sessionEntries) {
|
|
4616
|
+
if (!sessionEntry.isDirectory()) continue;
|
|
4617
|
+
const sessionDir = join25(projectDir, sessionEntry.name);
|
|
4618
|
+
if (!existsSync23(join25(sessionDir, "updates.jsonl"))) continue;
|
|
4619
|
+
results.push({
|
|
4620
|
+
sessionDir,
|
|
4621
|
+
project,
|
|
4622
|
+
sessionId: sessionEntry.name
|
|
4623
|
+
});
|
|
4624
|
+
}
|
|
4625
|
+
}
|
|
4626
|
+
return results;
|
|
4627
|
+
}
|
|
4628
|
+
function readFallbackModel(sessionDir) {
|
|
4629
|
+
const summaryPath = join25(sessionDir, "summary.json");
|
|
4630
|
+
const content = readFileSafe(summaryPath);
|
|
4631
|
+
if (!content) return "unknown";
|
|
4632
|
+
try {
|
|
4633
|
+
const summary = JSON.parse(content);
|
|
4634
|
+
return summary.current_model_id || "unknown";
|
|
4635
|
+
} catch {
|
|
4636
|
+
return "unknown";
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
var GrokBuildParser = class {
|
|
4640
|
+
constructor(dataDir = DEFAULT_DATA_DIR7) {
|
|
4641
|
+
this.dataDir = dataDir;
|
|
4642
|
+
this.tool = createToolDefinition13(dataDir);
|
|
4643
|
+
}
|
|
4644
|
+
dataDir;
|
|
4645
|
+
tool;
|
|
4646
|
+
async parse() {
|
|
4647
|
+
const entries = [];
|
|
4648
|
+
const sessionEvents = [];
|
|
4649
|
+
const sessions = findSessionDirs(this.dataDir);
|
|
4650
|
+
for (const { sessionDir, project, sessionId } of sessions) {
|
|
4651
|
+
const updatesPath = join25(sessionDir, "updates.jsonl");
|
|
4652
|
+
const content = readFileSafe(updatesPath);
|
|
4653
|
+
if (!content) continue;
|
|
4654
|
+
const fallbackModel = readFallbackModel(sessionDir);
|
|
4655
|
+
const seenUserPrompts = /* @__PURE__ */ new Set();
|
|
4656
|
+
const ANON_USER_OPEN = "__anon_user_open";
|
|
4657
|
+
for (const line of content.split("\n")) {
|
|
4658
|
+
if (!line.trim()) continue;
|
|
4659
|
+
let obj;
|
|
4660
|
+
try {
|
|
4661
|
+
obj = JSON.parse(line);
|
|
4662
|
+
} catch {
|
|
4663
|
+
continue;
|
|
4664
|
+
}
|
|
4665
|
+
const update = obj.params?.update;
|
|
4666
|
+
if (!update?.sessionUpdate) continue;
|
|
4667
|
+
const ts = resolveTimestamp(obj);
|
|
4668
|
+
if (!ts) continue;
|
|
4669
|
+
const sid = obj.params?.sessionId || sessionId;
|
|
4670
|
+
const updateType = update.sessionUpdate;
|
|
4671
|
+
const promptId = update.prompt_id || update._meta?.promptId || null;
|
|
4672
|
+
if (updateType === "user_message_chunk") {
|
|
4673
|
+
const key = promptId ?? ANON_USER_OPEN;
|
|
4674
|
+
if (seenUserPrompts.has(key)) continue;
|
|
4675
|
+
seenUserPrompts.add(key);
|
|
4676
|
+
sessionEvents.push({
|
|
4677
|
+
sessionId: sid,
|
|
4678
|
+
source: TOOL_ID16,
|
|
4679
|
+
project,
|
|
4680
|
+
timestamp: ts,
|
|
4681
|
+
role: "user"
|
|
4682
|
+
});
|
|
4683
|
+
continue;
|
|
4684
|
+
}
|
|
4685
|
+
if (updateType !== "turn_completed") continue;
|
|
4686
|
+
seenUserPrompts.delete(ANON_USER_OPEN);
|
|
4687
|
+
sessionEvents.push({
|
|
4688
|
+
sessionId: sid,
|
|
4689
|
+
source: TOOL_ID16,
|
|
4690
|
+
project,
|
|
4691
|
+
timestamp: ts,
|
|
4692
|
+
role: "assistant"
|
|
4693
|
+
});
|
|
4694
|
+
const usage = update.usage;
|
|
4695
|
+
if (!usage) continue;
|
|
4696
|
+
pushUsageEntries(entries, {
|
|
4697
|
+
sessionId: sid,
|
|
4698
|
+
project,
|
|
4699
|
+
timestamp: ts,
|
|
4700
|
+
usage,
|
|
4701
|
+
fallbackModel: update.model_id || fallbackModel
|
|
4702
|
+
});
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
return {
|
|
4706
|
+
buckets: aggregateToBuckets(entries),
|
|
4707
|
+
sessions: extractSessions(sessionEvents, entries)
|
|
4708
|
+
};
|
|
4709
|
+
}
|
|
4710
|
+
isInstalled() {
|
|
4711
|
+
return existsSync23(this.dataDir) || existsSync23(join25(homedir24(), ".grok")) || existsSync23(join25(homedir24(), ".local", "bin", "grok"));
|
|
4712
|
+
}
|
|
4713
|
+
};
|
|
4714
|
+
registerParser(new GrokBuildParser());
|
|
4715
|
+
|
|
4139
4716
|
// src/cli.ts
|
|
4140
4717
|
import { Command, Option } from "commander";
|
|
4141
4718
|
|
|
4142
4719
|
// src/infrastructure/config/manager.ts
|
|
4143
4720
|
import { randomUUID } from "crypto";
|
|
4144
4721
|
import {
|
|
4145
|
-
existsSync as
|
|
4722
|
+
existsSync as existsSync24,
|
|
4146
4723
|
mkdirSync,
|
|
4147
4724
|
readFileSync as readFileSync9,
|
|
4148
4725
|
unlinkSync,
|
|
4149
4726
|
writeFileSync
|
|
4150
4727
|
} from "fs";
|
|
4151
|
-
import { join as
|
|
4728
|
+
import { join as join27 } from "path";
|
|
4152
4729
|
|
|
4153
4730
|
// src/infrastructure/xdg.ts
|
|
4154
|
-
import { homedir as
|
|
4155
|
-
import { join as
|
|
4731
|
+
import { homedir as homedir25 } from "os";
|
|
4732
|
+
import { join as join26 } from "path";
|
|
4156
4733
|
function getConfigHome() {
|
|
4157
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
4734
|
+
return process.env.XDG_CONFIG_HOME || join26(homedir25(), ".config");
|
|
4158
4735
|
}
|
|
4159
4736
|
function getStateHome() {
|
|
4160
|
-
return process.env.XDG_STATE_HOME ||
|
|
4737
|
+
return process.env.XDG_STATE_HOME || join26(homedir25(), ".local", "state");
|
|
4161
4738
|
}
|
|
4162
4739
|
function getRuntimeDir() {
|
|
4163
4740
|
return process.env.XDG_RUNTIME_DIR || getStateHome();
|
|
4164
4741
|
}
|
|
4165
4742
|
|
|
4166
4743
|
// src/infrastructure/config/manager.ts
|
|
4167
|
-
var CONFIG_DIR =
|
|
4744
|
+
var CONFIG_DIR = join27(getConfigHome(), "tokenarena");
|
|
4168
4745
|
var isDev = process.env.TOKEN_ARENA_DEV === "1";
|
|
4169
|
-
var CONFIG_FILE =
|
|
4746
|
+
var CONFIG_FILE = join27(CONFIG_DIR, isDev ? "config.dev.json" : "config.json");
|
|
4170
4747
|
var DEFAULT_API_URL = "https://token.guji.uno";
|
|
4171
4748
|
var VALID_CONFIG_KEYS = [
|
|
4172
4749
|
"apiKey",
|
|
@@ -4182,7 +4759,7 @@ function getConfigDir() {
|
|
|
4182
4759
|
return CONFIG_DIR;
|
|
4183
4760
|
}
|
|
4184
4761
|
function loadConfig() {
|
|
4185
|
-
if (!
|
|
4762
|
+
if (!existsSync24(CONFIG_FILE)) return null;
|
|
4186
4763
|
try {
|
|
4187
4764
|
const raw = readFileSync9(CONFIG_FILE, "utf-8");
|
|
4188
4765
|
const config = JSON.parse(raw);
|
|
@@ -4200,7 +4777,7 @@ function saveConfig(config) {
|
|
|
4200
4777
|
`, "utf-8");
|
|
4201
4778
|
}
|
|
4202
4779
|
function deleteConfig() {
|
|
4203
|
-
if (
|
|
4780
|
+
if (existsSync24(CONFIG_FILE)) {
|
|
4204
4781
|
unlinkSync(CONFIG_FILE);
|
|
4205
4782
|
}
|
|
4206
4783
|
}
|
|
@@ -5062,7 +5639,7 @@ var ApiClient = class {
|
|
|
5062
5639
|
// src/infrastructure/runtime/lock.ts
|
|
5063
5640
|
import {
|
|
5064
5641
|
closeSync,
|
|
5065
|
-
existsSync as
|
|
5642
|
+
existsSync as existsSync25,
|
|
5066
5643
|
openSync,
|
|
5067
5644
|
readFileSync as readFileSync10,
|
|
5068
5645
|
rmSync as rmSync3,
|
|
@@ -5071,22 +5648,22 @@ import {
|
|
|
5071
5648
|
|
|
5072
5649
|
// src/infrastructure/runtime/paths.ts
|
|
5073
5650
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
5074
|
-
import { join as
|
|
5651
|
+
import { join as join28 } from "path";
|
|
5075
5652
|
var APP_NAME = "tokenarena";
|
|
5076
5653
|
function getRuntimeDirPath() {
|
|
5077
|
-
return
|
|
5654
|
+
return join28(getRuntimeDir(), APP_NAME);
|
|
5078
5655
|
}
|
|
5079
5656
|
function getStateDir() {
|
|
5080
|
-
return
|
|
5657
|
+
return join28(getStateHome(), APP_NAME);
|
|
5081
5658
|
}
|
|
5082
5659
|
function getSyncLockPath() {
|
|
5083
|
-
return
|
|
5660
|
+
return join28(getRuntimeDirPath(), "sync.lock");
|
|
5084
5661
|
}
|
|
5085
5662
|
function getSyncStatePath() {
|
|
5086
|
-
return
|
|
5663
|
+
return join28(getStateDir(), "status.json");
|
|
5087
5664
|
}
|
|
5088
5665
|
function getUploadManifestPath() {
|
|
5089
|
-
return
|
|
5666
|
+
return join28(getStateDir(), "upload-manifest.json");
|
|
5090
5667
|
}
|
|
5091
5668
|
function ensureAppDirs() {
|
|
5092
5669
|
mkdirSync2(getRuntimeDirPath(), { recursive: true });
|
|
@@ -5104,7 +5681,7 @@ function isProcessAlive(pid) {
|
|
|
5104
5681
|
}
|
|
5105
5682
|
}
|
|
5106
5683
|
function readLockMetadata(lockPath) {
|
|
5107
|
-
if (!
|
|
5684
|
+
if (!existsSync25(lockPath)) {
|
|
5108
5685
|
return null;
|
|
5109
5686
|
}
|
|
5110
5687
|
try {
|
|
@@ -5178,13 +5755,13 @@ function describeExistingSyncLock() {
|
|
|
5178
5755
|
}
|
|
5179
5756
|
|
|
5180
5757
|
// src/infrastructure/runtime/state.ts
|
|
5181
|
-
import { existsSync as
|
|
5758
|
+
import { existsSync as existsSync26, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
|
|
5182
5759
|
function getDefaultState() {
|
|
5183
5760
|
return { status: "idle" };
|
|
5184
5761
|
}
|
|
5185
5762
|
function loadSyncState() {
|
|
5186
5763
|
const path = getSyncStatePath();
|
|
5187
|
-
if (!
|
|
5764
|
+
if (!existsSync26(path)) {
|
|
5188
5765
|
return getDefaultState();
|
|
5189
5766
|
}
|
|
5190
5767
|
try {
|
|
@@ -5245,7 +5822,7 @@ function markSyncFailed(source, error, status) {
|
|
|
5245
5822
|
}
|
|
5246
5823
|
|
|
5247
5824
|
// src/infrastructure/runtime/upload-manifest.ts
|
|
5248
|
-
import { existsSync as
|
|
5825
|
+
import { existsSync as existsSync27, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
|
|
5249
5826
|
function isRecordOfStrings(value) {
|
|
5250
5827
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5251
5828
|
return false;
|
|
@@ -5261,7 +5838,7 @@ function isUploadManifest(value) {
|
|
|
5261
5838
|
}
|
|
5262
5839
|
function loadUploadManifest() {
|
|
5263
5840
|
const path = getUploadManifestPath();
|
|
5264
|
-
if (!
|
|
5841
|
+
if (!existsSync27(path)) {
|
|
5265
5842
|
return null;
|
|
5266
5843
|
}
|
|
5267
5844
|
try {
|
|
@@ -5801,18 +6378,18 @@ View your dashboard at: ${apiUrl}/usage`);
|
|
|
5801
6378
|
|
|
5802
6379
|
// src/commands/init.ts
|
|
5803
6380
|
import { execFileSync as execFileSync7, spawn } from "child_process";
|
|
5804
|
-
import { existsSync as
|
|
6381
|
+
import { existsSync as existsSync30 } from "fs";
|
|
5805
6382
|
import { appendFile, mkdir, readFile } from "fs/promises";
|
|
5806
|
-
import { homedir as
|
|
5807
|
-
import { dirname as dirname6, join as
|
|
6383
|
+
import { homedir as homedir28, platform as platform5 } from "os";
|
|
6384
|
+
import { dirname as dirname6, join as join29, posix as posix3, win32 } from "path";
|
|
5808
6385
|
|
|
5809
6386
|
// src/infrastructure/service/index.ts
|
|
5810
6387
|
import { platform as platform4 } from "os";
|
|
5811
6388
|
|
|
5812
6389
|
// src/infrastructure/service/linux-systemd.ts
|
|
5813
6390
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
5814
|
-
import { existsSync as
|
|
5815
|
-
import { homedir as
|
|
6391
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
6392
|
+
import { homedir as homedir26, platform as platform2 } from "os";
|
|
5816
6393
|
import { posix } from "path";
|
|
5817
6394
|
|
|
5818
6395
|
// src/utils/command.ts
|
|
@@ -5881,10 +6458,10 @@ function escapeXml(value) {
|
|
|
5881
6458
|
|
|
5882
6459
|
// src/infrastructure/service/linux-systemd.ts
|
|
5883
6460
|
var SYSTEMD_SERVICE_NAME = "tokenarena";
|
|
5884
|
-
function getLinuxSystemdServiceDir(homePath =
|
|
6461
|
+
function getLinuxSystemdServiceDir(homePath = homedir26()) {
|
|
5885
6462
|
return posix.join(homePath, ".config", "systemd", "user");
|
|
5886
6463
|
}
|
|
5887
|
-
function getLinuxSystemdServiceFile(homePath =
|
|
6464
|
+
function getLinuxSystemdServiceFile(homePath = homedir26()) {
|
|
5888
6465
|
return posix.join(
|
|
5889
6466
|
getLinuxSystemdServiceDir(homePath),
|
|
5890
6467
|
`${SYSTEMD_SERVICE_NAME}.service`
|
|
@@ -5941,7 +6518,7 @@ function ensureSystemdAvailable() {
|
|
|
5941
6518
|
}
|
|
5942
6519
|
function createLinuxSystemdServiceBackend() {
|
|
5943
6520
|
function isInstalled() {
|
|
5944
|
-
return
|
|
6521
|
+
return existsSync28(getLinuxSystemdServiceFile());
|
|
5945
6522
|
}
|
|
5946
6523
|
async function setup(skipPrompt = false) {
|
|
5947
6524
|
if (!ensureSystemdAvailable()) {
|
|
@@ -6066,7 +6643,7 @@ function createLinuxSystemdServiceBackend() {
|
|
|
6066
6643
|
}
|
|
6067
6644
|
async function uninstall(skipPrompt = false) {
|
|
6068
6645
|
const serviceFile = getLinuxSystemdServiceFile();
|
|
6069
|
-
if (!
|
|
6646
|
+
if (!existsSync28(serviceFile)) {
|
|
6070
6647
|
logger.info(formatBullet("\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002", "warning"));
|
|
6071
6648
|
return;
|
|
6072
6649
|
}
|
|
@@ -6127,17 +6704,17 @@ function createLinuxSystemdServiceBackend() {
|
|
|
6127
6704
|
|
|
6128
6705
|
// src/infrastructure/service/macos-launchd.ts
|
|
6129
6706
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
6130
|
-
import { existsSync as
|
|
6131
|
-
import { homedir as
|
|
6707
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync4, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
6708
|
+
import { homedir as homedir27, platform as platform3 } from "os";
|
|
6132
6709
|
import { posix as posix2 } from "path";
|
|
6133
6710
|
var MACOS_LAUNCHD_LABEL = "com.guji.tokenarena";
|
|
6134
6711
|
function getCurrentUid() {
|
|
6135
6712
|
return typeof process.getuid === "function" ? process.getuid() : null;
|
|
6136
6713
|
}
|
|
6137
|
-
function getMacosLaunchAgentDir(homePath =
|
|
6714
|
+
function getMacosLaunchAgentDir(homePath = homedir27()) {
|
|
6138
6715
|
return posix2.join(homePath, "Library", "LaunchAgents");
|
|
6139
6716
|
}
|
|
6140
|
-
function getMacosLaunchAgentFile(homePath =
|
|
6717
|
+
function getMacosLaunchAgentFile(homePath = homedir27()) {
|
|
6141
6718
|
return posix2.join(
|
|
6142
6719
|
getMacosLaunchAgentDir(homePath),
|
|
6143
6720
|
`${MACOS_LAUNCHD_LABEL}.plist`
|
|
@@ -6264,7 +6841,7 @@ function writeLaunchAgentPlist() {
|
|
|
6264
6841
|
label: MACOS_LAUNCHD_LABEL,
|
|
6265
6842
|
programArguments: [command.execPath, ...command.args],
|
|
6266
6843
|
environment: getManagedServiceEnvironment(),
|
|
6267
|
-
workingDirectory:
|
|
6844
|
+
workingDirectory: homedir27(),
|
|
6268
6845
|
standardOutPath: stdoutPath,
|
|
6269
6846
|
standardErrorPath: stderrPath
|
|
6270
6847
|
});
|
|
@@ -6289,7 +6866,7 @@ function bootstrapLaunchAgent() {
|
|
|
6289
6866
|
}
|
|
6290
6867
|
function createMacosLaunchdServiceBackend() {
|
|
6291
6868
|
function isInstalled() {
|
|
6292
|
-
return
|
|
6869
|
+
return existsSync29(getMacosLaunchAgentFile());
|
|
6293
6870
|
}
|
|
6294
6871
|
async function setup(skipPrompt = false) {
|
|
6295
6872
|
if (!ensureLaunchctlAvailable()) {
|
|
@@ -6430,7 +7007,7 @@ function createMacosLaunchdServiceBackend() {
|
|
|
6430
7007
|
}
|
|
6431
7008
|
async function uninstall(skipPrompt = false) {
|
|
6432
7009
|
const plistFile = getMacosLaunchAgentFile();
|
|
6433
|
-
if (!
|
|
7010
|
+
if (!existsSync29(plistFile)) {
|
|
6434
7011
|
logger.info(formatBullet("\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002", "warning"));
|
|
6435
7012
|
return;
|
|
6436
7013
|
}
|
|
@@ -6541,7 +7118,7 @@ function resolvePowerShellProfilePath() {
|
|
|
6541
7118
|
const systemRoot = process.env.SYSTEMROOT || "C:\\Windows";
|
|
6542
7119
|
const candidates = [
|
|
6543
7120
|
"pwsh.exe",
|
|
6544
|
-
|
|
7121
|
+
join29(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
6545
7122
|
];
|
|
6546
7123
|
for (const command of candidates) {
|
|
6547
7124
|
try {
|
|
@@ -6570,8 +7147,8 @@ function resolvePowerShellProfilePath() {
|
|
|
6570
7147
|
function resolveShellAliasSetup(options = {}) {
|
|
6571
7148
|
const currentPlatform = options.currentPlatform ?? platform5();
|
|
6572
7149
|
const env = options.env ?? process.env;
|
|
6573
|
-
const homeDir = options.homeDir ??
|
|
6574
|
-
const pathExists = options.exists ??
|
|
7150
|
+
const homeDir = options.homeDir ?? homedir28();
|
|
7151
|
+
const pathExists = options.exists ?? existsSync30;
|
|
6575
7152
|
const shellFromEnv = env.SHELL ? basenameLikeShell(env.SHELL).toLowerCase() : "";
|
|
6576
7153
|
const shellName = shellFromEnv || (currentPlatform === "win32" ? "powershell" : "");
|
|
6577
7154
|
const aliasName = "ta";
|
|
@@ -6768,7 +7345,7 @@ async function setupShellAlias() {
|
|
|
6768
7345
|
try {
|
|
6769
7346
|
await mkdir(dirname6(setup.configFile), { recursive: true });
|
|
6770
7347
|
let existingContent = "";
|
|
6771
|
-
if (
|
|
7348
|
+
if (existsSync30(setup.configFile)) {
|
|
6772
7349
|
existingContent = await readFile(setup.configFile, "utf-8");
|
|
6773
7350
|
}
|
|
6774
7351
|
const normalizedContent = existingContent.toLowerCase();
|
|
@@ -7027,7 +7604,7 @@ function buildLocalUsageDashboardData(input2) {
|
|
|
7027
7604
|
|
|
7028
7605
|
// src/infrastructure/runtime/cli-version.ts
|
|
7029
7606
|
import { readFileSync as readFileSync13 } from "fs";
|
|
7030
|
-
import { dirname as dirname7, join as
|
|
7607
|
+
import { dirname as dirname7, join as join30 } from "path";
|
|
7031
7608
|
import { fileURLToPath } from "url";
|
|
7032
7609
|
var FALLBACK_VERSION = "0.0.0";
|
|
7033
7610
|
var cachedVersion;
|
|
@@ -7035,7 +7612,7 @@ function getCliVersion(metaUrl = import.meta.url) {
|
|
|
7035
7612
|
if (cachedVersion) {
|
|
7036
7613
|
return cachedVersion;
|
|
7037
7614
|
}
|
|
7038
|
-
const packageJsonPath =
|
|
7615
|
+
const packageJsonPath = join30(
|
|
7039
7616
|
dirname7(fileURLToPath(metaUrl)),
|
|
7040
7617
|
"..",
|
|
7041
7618
|
"package.json"
|
|
@@ -7446,8 +8023,8 @@ async function runSyncCommand(opts = {}) {
|
|
|
7446
8023
|
}
|
|
7447
8024
|
|
|
7448
8025
|
// src/commands/uninstall.ts
|
|
7449
|
-
import { existsSync as
|
|
7450
|
-
import { homedir as
|
|
8026
|
+
import { existsSync as existsSync31, readFileSync as readFileSync14, rmSync as rmSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
8027
|
+
import { homedir as homedir29, platform as platform6 } from "os";
|
|
7451
8028
|
function removeShellAlias() {
|
|
7452
8029
|
const shell = process.env.SHELL;
|
|
7453
8030
|
if (!shell) return;
|
|
@@ -7456,22 +8033,22 @@ function removeShellAlias() {
|
|
|
7456
8033
|
let configFile;
|
|
7457
8034
|
switch (shellName) {
|
|
7458
8035
|
case "zsh":
|
|
7459
|
-
configFile = `${
|
|
8036
|
+
configFile = `${homedir29()}/.zshrc`;
|
|
7460
8037
|
break;
|
|
7461
8038
|
case "bash":
|
|
7462
|
-
if (platform6() === "darwin" &&
|
|
7463
|
-
configFile = `${
|
|
8039
|
+
if (platform6() === "darwin" && existsSync31(`${homedir29()}/.bash_profile`)) {
|
|
8040
|
+
configFile = `${homedir29()}/.bash_profile`;
|
|
7464
8041
|
} else {
|
|
7465
|
-
configFile = `${
|
|
8042
|
+
configFile = `${homedir29()}/.bashrc`;
|
|
7466
8043
|
}
|
|
7467
8044
|
break;
|
|
7468
8045
|
case "fish":
|
|
7469
|
-
configFile = `${
|
|
8046
|
+
configFile = `${homedir29()}/.config/fish/config.fish`;
|
|
7470
8047
|
break;
|
|
7471
8048
|
default:
|
|
7472
8049
|
return;
|
|
7473
8050
|
}
|
|
7474
|
-
if (!
|
|
8051
|
+
if (!existsSync31(configFile)) return;
|
|
7475
8052
|
try {
|
|
7476
8053
|
let content = readFileSync14(configFile, "utf-8");
|
|
7477
8054
|
const aliasPatterns = [
|
|
@@ -7510,7 +8087,7 @@ async function runUninstall() {
|
|
|
7510
8087
|
const runtimeDir = getRuntimeDirPath();
|
|
7511
8088
|
const serviceBackend = getServiceBackend();
|
|
7512
8089
|
const hasInstalledService = serviceBackend?.isInstalled() ?? false;
|
|
7513
|
-
const hasLocalArtifacts =
|
|
8090
|
+
const hasLocalArtifacts = existsSync31(configPath) || existsSync31(configDir) || existsSync31(stateDir) || existsSync31(runtimeDir) || hasInstalledService;
|
|
7514
8091
|
if (!hasLocalArtifacts) {
|
|
7515
8092
|
logger.info(formatHeader("\u5378\u8F7D TokenArena"));
|
|
7516
8093
|
logger.info(formatBullet("\u672A\u53D1\u73B0\u672C\u5730\u914D\u7F6E\uFF0C\u65E0\u9700\u5378\u8F7D\u3002"));
|
|
@@ -7554,22 +8131,22 @@ async function runUninstall() {
|
|
|
7554
8131
|
}
|
|
7555
8132
|
}
|
|
7556
8133
|
logger.info(formatSection("\u6267\u884C\u7ED3\u679C"));
|
|
7557
|
-
if (
|
|
8134
|
+
if (existsSync31(configPath)) {
|
|
7558
8135
|
deleteConfig();
|
|
7559
8136
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u6587\u4EF6\u3002", "success"));
|
|
7560
8137
|
}
|
|
7561
|
-
if (
|
|
8138
|
+
if (existsSync31(configDir)) {
|
|
7562
8139
|
try {
|
|
7563
8140
|
rmSync6(configDir, { recursive: false, force: true });
|
|
7564
8141
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u76EE\u5F55\u3002", "success"));
|
|
7565
8142
|
} catch {
|
|
7566
8143
|
}
|
|
7567
8144
|
}
|
|
7568
|
-
if (
|
|
8145
|
+
if (existsSync31(stateDir)) {
|
|
7569
8146
|
rmSync6(stateDir, { recursive: true, force: true });
|
|
7570
8147
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u72B6\u6001\u6570\u636E\u3002", "success"));
|
|
7571
8148
|
}
|
|
7572
|
-
if (
|
|
8149
|
+
if (existsSync31(runtimeDir)) {
|
|
7573
8150
|
rmSync6(runtimeDir, { recursive: true, force: true });
|
|
7574
8151
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u8FD0\u884C\u65F6\u6570\u636E\u3002", "success"));
|
|
7575
8152
|
}
|
|
@@ -7800,7 +8377,7 @@ function createCli() {
|
|
|
7800
8377
|
}
|
|
7801
8378
|
|
|
7802
8379
|
// src/infrastructure/runtime/main-module.ts
|
|
7803
|
-
import { existsSync as
|
|
8380
|
+
import { existsSync as existsSync32, realpathSync as realpathSync2 } from "fs";
|
|
7804
8381
|
import { resolve as resolve3 } from "path";
|
|
7805
8382
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7806
8383
|
function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
|
|
@@ -7811,7 +8388,7 @@ function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
|
|
|
7811
8388
|
try {
|
|
7812
8389
|
return realpathSync2(argvEntry) === realpathSync2(currentModulePath);
|
|
7813
8390
|
} catch {
|
|
7814
|
-
if (!
|
|
8391
|
+
if (!existsSync32(argvEntry)) {
|
|
7815
8392
|
return false;
|
|
7816
8393
|
}
|
|
7817
8394
|
return resolve3(argvEntry) === resolve3(currentModulePath);
|