@yishiguji/tokenarena 0.8.7 → 0.9.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 +446 -234
- 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,7 +4277,7 @@ 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());
|
|
@@ -4142,31 +4288,31 @@ import { Command, Option } from "commander";
|
|
|
4142
4288
|
// src/infrastructure/config/manager.ts
|
|
4143
4289
|
import { randomUUID } from "crypto";
|
|
4144
4290
|
import {
|
|
4145
|
-
existsSync as
|
|
4291
|
+
existsSync as existsSync22,
|
|
4146
4292
|
mkdirSync,
|
|
4147
4293
|
readFileSync as readFileSync9,
|
|
4148
4294
|
unlinkSync,
|
|
4149
4295
|
writeFileSync
|
|
4150
4296
|
} from "fs";
|
|
4151
|
-
import { join as
|
|
4297
|
+
import { join as join25 } from "path";
|
|
4152
4298
|
|
|
4153
4299
|
// src/infrastructure/xdg.ts
|
|
4154
|
-
import { homedir as
|
|
4155
|
-
import { join as
|
|
4300
|
+
import { homedir as homedir23 } from "os";
|
|
4301
|
+
import { join as join24 } from "path";
|
|
4156
4302
|
function getConfigHome() {
|
|
4157
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
4303
|
+
return process.env.XDG_CONFIG_HOME || join24(homedir23(), ".config");
|
|
4158
4304
|
}
|
|
4159
4305
|
function getStateHome() {
|
|
4160
|
-
return process.env.XDG_STATE_HOME ||
|
|
4306
|
+
return process.env.XDG_STATE_HOME || join24(homedir23(), ".local", "state");
|
|
4161
4307
|
}
|
|
4162
4308
|
function getRuntimeDir() {
|
|
4163
4309
|
return process.env.XDG_RUNTIME_DIR || getStateHome();
|
|
4164
4310
|
}
|
|
4165
4311
|
|
|
4166
4312
|
// src/infrastructure/config/manager.ts
|
|
4167
|
-
var CONFIG_DIR =
|
|
4313
|
+
var CONFIG_DIR = join25(getConfigHome(), "tokenarena");
|
|
4168
4314
|
var isDev = process.env.TOKEN_ARENA_DEV === "1";
|
|
4169
|
-
var CONFIG_FILE =
|
|
4315
|
+
var CONFIG_FILE = join25(CONFIG_DIR, isDev ? "config.dev.json" : "config.json");
|
|
4170
4316
|
var DEFAULT_API_URL = "https://token.guji.uno";
|
|
4171
4317
|
var VALID_CONFIG_KEYS = [
|
|
4172
4318
|
"apiKey",
|
|
@@ -4182,7 +4328,7 @@ function getConfigDir() {
|
|
|
4182
4328
|
return CONFIG_DIR;
|
|
4183
4329
|
}
|
|
4184
4330
|
function loadConfig() {
|
|
4185
|
-
if (!
|
|
4331
|
+
if (!existsSync22(CONFIG_FILE)) return null;
|
|
4186
4332
|
try {
|
|
4187
4333
|
const raw = readFileSync9(CONFIG_FILE, "utf-8");
|
|
4188
4334
|
const config = JSON.parse(raw);
|
|
@@ -4200,7 +4346,7 @@ function saveConfig(config) {
|
|
|
4200
4346
|
`, "utf-8");
|
|
4201
4347
|
}
|
|
4202
4348
|
function deleteConfig() {
|
|
4203
|
-
if (
|
|
4349
|
+
if (existsSync22(CONFIG_FILE)) {
|
|
4204
4350
|
unlinkSync(CONFIG_FILE);
|
|
4205
4351
|
}
|
|
4206
4352
|
}
|
|
@@ -4836,14 +4982,19 @@ import { URL as URL2 } from "url";
|
|
|
4836
4982
|
var MAX_RETRIES = 3;
|
|
4837
4983
|
var INITIAL_DELAY = 1e3;
|
|
4838
4984
|
var TIMEOUT_MS = 6e4;
|
|
4839
|
-
function
|
|
4840
|
-
|
|
4985
|
+
function buildIngestPayload(device, buckets, sessions, options) {
|
|
4986
|
+
return {
|
|
4841
4987
|
schemaVersion: 2,
|
|
4842
4988
|
device,
|
|
4843
4989
|
buckets,
|
|
4844
|
-
sessions: sessions ?? []
|
|
4990
|
+
sessions: sessions ?? [],
|
|
4991
|
+
...options?.syncAchievements === void 0 ? {} : { syncAchievements: options.syncAchievements }
|
|
4845
4992
|
};
|
|
4846
|
-
|
|
4993
|
+
}
|
|
4994
|
+
function getIngestPayloadSize(device, buckets, sessions, options) {
|
|
4995
|
+
return Buffer.byteLength(
|
|
4996
|
+
JSON.stringify(buildIngestPayload(device, buckets, sessions, options))
|
|
4997
|
+
);
|
|
4847
4998
|
}
|
|
4848
4999
|
var ApiClient = class {
|
|
4849
5000
|
constructor(apiUrl, apiKey) {
|
|
@@ -4855,11 +5006,17 @@ var ApiClient = class {
|
|
|
4855
5006
|
/**
|
|
4856
5007
|
* Ingest buckets and sessions to server
|
|
4857
5008
|
*/
|
|
4858
|
-
async ingest(device, buckets, sessions, onProgress) {
|
|
5009
|
+
async ingest(device, buckets, sessions, onProgress, options) {
|
|
4859
5010
|
let lastError;
|
|
4860
5011
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
4861
5012
|
try {
|
|
4862
|
-
return await this.sendIngest(
|
|
5013
|
+
return await this.sendIngest(
|
|
5014
|
+
device,
|
|
5015
|
+
buckets,
|
|
5016
|
+
sessions,
|
|
5017
|
+
onProgress,
|
|
5018
|
+
options
|
|
5019
|
+
);
|
|
4863
5020
|
} catch (err) {
|
|
4864
5021
|
lastError = err;
|
|
4865
5022
|
const httpErr = err;
|
|
@@ -4874,16 +5031,11 @@ var ApiClient = class {
|
|
|
4874
5031
|
}
|
|
4875
5032
|
throw lastError;
|
|
4876
5033
|
}
|
|
4877
|
-
sendIngest(device, buckets, sessions, onProgress) {
|
|
5034
|
+
sendIngest(device, buckets, sessions, onProgress, options) {
|
|
4878
5035
|
return new Promise((resolve4, reject) => {
|
|
4879
5036
|
const url = new URL2("/api/usage/ingest", this.apiUrl);
|
|
4880
5037
|
const body = Buffer.from(
|
|
4881
|
-
JSON.stringify(
|
|
4882
|
-
schemaVersion: 2,
|
|
4883
|
-
device,
|
|
4884
|
-
buckets,
|
|
4885
|
-
sessions: sessions ?? []
|
|
4886
|
-
})
|
|
5038
|
+
JSON.stringify(buildIngestPayload(device, buckets, sessions, options))
|
|
4887
5039
|
);
|
|
4888
5040
|
const totalBytes = body.length;
|
|
4889
5041
|
const mod = url.protocol === "https:" ? https : http;
|
|
@@ -5056,7 +5208,7 @@ var ApiClient = class {
|
|
|
5056
5208
|
// src/infrastructure/runtime/lock.ts
|
|
5057
5209
|
import {
|
|
5058
5210
|
closeSync,
|
|
5059
|
-
existsSync as
|
|
5211
|
+
existsSync as existsSync23,
|
|
5060
5212
|
openSync,
|
|
5061
5213
|
readFileSync as readFileSync10,
|
|
5062
5214
|
rmSync as rmSync3,
|
|
@@ -5065,22 +5217,22 @@ import {
|
|
|
5065
5217
|
|
|
5066
5218
|
// src/infrastructure/runtime/paths.ts
|
|
5067
5219
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
5068
|
-
import { join as
|
|
5220
|
+
import { join as join26 } from "path";
|
|
5069
5221
|
var APP_NAME = "tokenarena";
|
|
5070
5222
|
function getRuntimeDirPath() {
|
|
5071
|
-
return
|
|
5223
|
+
return join26(getRuntimeDir(), APP_NAME);
|
|
5072
5224
|
}
|
|
5073
5225
|
function getStateDir() {
|
|
5074
|
-
return
|
|
5226
|
+
return join26(getStateHome(), APP_NAME);
|
|
5075
5227
|
}
|
|
5076
5228
|
function getSyncLockPath() {
|
|
5077
|
-
return
|
|
5229
|
+
return join26(getRuntimeDirPath(), "sync.lock");
|
|
5078
5230
|
}
|
|
5079
5231
|
function getSyncStatePath() {
|
|
5080
|
-
return
|
|
5232
|
+
return join26(getStateDir(), "status.json");
|
|
5081
5233
|
}
|
|
5082
5234
|
function getUploadManifestPath() {
|
|
5083
|
-
return
|
|
5235
|
+
return join26(getStateDir(), "upload-manifest.json");
|
|
5084
5236
|
}
|
|
5085
5237
|
function ensureAppDirs() {
|
|
5086
5238
|
mkdirSync2(getRuntimeDirPath(), { recursive: true });
|
|
@@ -5098,7 +5250,7 @@ function isProcessAlive(pid) {
|
|
|
5098
5250
|
}
|
|
5099
5251
|
}
|
|
5100
5252
|
function readLockMetadata(lockPath) {
|
|
5101
|
-
if (!
|
|
5253
|
+
if (!existsSync23(lockPath)) {
|
|
5102
5254
|
return null;
|
|
5103
5255
|
}
|
|
5104
5256
|
try {
|
|
@@ -5172,13 +5324,13 @@ function describeExistingSyncLock() {
|
|
|
5172
5324
|
}
|
|
5173
5325
|
|
|
5174
5326
|
// src/infrastructure/runtime/state.ts
|
|
5175
|
-
import { existsSync as
|
|
5327
|
+
import { existsSync as existsSync24, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
|
|
5176
5328
|
function getDefaultState() {
|
|
5177
5329
|
return { status: "idle" };
|
|
5178
5330
|
}
|
|
5179
5331
|
function loadSyncState() {
|
|
5180
5332
|
const path = getSyncStatePath();
|
|
5181
|
-
if (!
|
|
5333
|
+
if (!existsSync24(path)) {
|
|
5182
5334
|
return getDefaultState();
|
|
5183
5335
|
}
|
|
5184
5336
|
try {
|
|
@@ -5239,7 +5391,7 @@ function markSyncFailed(source, error, status) {
|
|
|
5239
5391
|
}
|
|
5240
5392
|
|
|
5241
5393
|
// src/infrastructure/runtime/upload-manifest.ts
|
|
5242
|
-
import { existsSync as
|
|
5394
|
+
import { existsSync as existsSync25, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
|
|
5243
5395
|
function isRecordOfStrings(value) {
|
|
5244
5396
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5245
5397
|
return false;
|
|
@@ -5255,7 +5407,7 @@ function isUploadManifest(value) {
|
|
|
5255
5407
|
}
|
|
5256
5408
|
function loadUploadManifest() {
|
|
5257
5409
|
const path = getUploadManifestPath();
|
|
5258
|
-
if (!
|
|
5410
|
+
if (!existsSync25(path)) {
|
|
5259
5411
|
return null;
|
|
5260
5412
|
}
|
|
5261
5413
|
try {
|
|
@@ -5316,6 +5468,7 @@ function getDetectedTools() {
|
|
|
5316
5468
|
// src/services/sync-service.ts
|
|
5317
5469
|
var BATCH_SIZE = 100;
|
|
5318
5470
|
var SESSION_BATCH_SIZE = 500;
|
|
5471
|
+
var MAX_INGEST_PAYLOAD_BYTES = 8 * 1024 * 1024;
|
|
5319
5472
|
var PROGRESS_BAR_WIDTH = 28;
|
|
5320
5473
|
function formatBytes(bytes) {
|
|
5321
5474
|
if (bytes < 1024) return `${bytes}B`;
|
|
@@ -5327,6 +5480,9 @@ function renderProgressBar(progress) {
|
|
|
5327
5480
|
const filled = Math.round(safeProgress * PROGRESS_BAR_WIDTH);
|
|
5328
5481
|
return `${"\u2588".repeat(filled)}${"\u2591".repeat(PROGRESS_BAR_WIDTH - filled)}`;
|
|
5329
5482
|
}
|
|
5483
|
+
function shouldSyncAchievementsForBatch(batchIndex, totalBatches) {
|
|
5484
|
+
return batchIndex === totalBatches - 1;
|
|
5485
|
+
}
|
|
5330
5486
|
function writeUploadProgress(sent, total, batchNum, totalBatches) {
|
|
5331
5487
|
const pct = total > 0 ? Math.round(sent / total * 100) : 100;
|
|
5332
5488
|
const progressBar = renderProgressBar(total > 0 ? sent / total : 1);
|
|
@@ -5456,6 +5612,64 @@ var SyncFailure = class extends Error {
|
|
|
5456
5612
|
kind;
|
|
5457
5613
|
causeError;
|
|
5458
5614
|
};
|
|
5615
|
+
function splitOversizedUploadBatch(device, buckets, sessions) {
|
|
5616
|
+
const payloadSize = getIngestPayloadSize(device, buckets, sessions, {
|
|
5617
|
+
syncAchievements: true
|
|
5618
|
+
});
|
|
5619
|
+
if (payloadSize <= MAX_INGEST_PAYLOAD_BYTES) {
|
|
5620
|
+
return [{ buckets, sessions }];
|
|
5621
|
+
}
|
|
5622
|
+
if (buckets.length + sessions.length <= 1) {
|
|
5623
|
+
throw new SyncFailure(
|
|
5624
|
+
`A single usage record exceeds the ${formatBytes(MAX_INGEST_PAYLOAD_BYTES)} ingest payload limit. Reduce the record size before syncing.`,
|
|
5625
|
+
"error"
|
|
5626
|
+
);
|
|
5627
|
+
}
|
|
5628
|
+
if (sessions.length > 1 && sessions.length >= buckets.length) {
|
|
5629
|
+
const midpoint = Math.ceil(sessions.length / 2);
|
|
5630
|
+
return [
|
|
5631
|
+
...splitOversizedUploadBatch(
|
|
5632
|
+
device,
|
|
5633
|
+
buckets,
|
|
5634
|
+
sessions.slice(0, midpoint)
|
|
5635
|
+
),
|
|
5636
|
+
...splitOversizedUploadBatch(device, [], sessions.slice(midpoint))
|
|
5637
|
+
];
|
|
5638
|
+
}
|
|
5639
|
+
if (buckets.length > 1) {
|
|
5640
|
+
const midpoint = Math.ceil(buckets.length / 2);
|
|
5641
|
+
return [
|
|
5642
|
+
...splitOversizedUploadBatch(
|
|
5643
|
+
device,
|
|
5644
|
+
buckets.slice(0, midpoint),
|
|
5645
|
+
sessions
|
|
5646
|
+
),
|
|
5647
|
+
...splitOversizedUploadBatch(device, buckets.slice(midpoint), [])
|
|
5648
|
+
];
|
|
5649
|
+
}
|
|
5650
|
+
return [
|
|
5651
|
+
...splitOversizedUploadBatch(device, buckets, []),
|
|
5652
|
+
...splitOversizedUploadBatch(device, [], sessions)
|
|
5653
|
+
];
|
|
5654
|
+
}
|
|
5655
|
+
function buildUploadBatches(device, buckets, sessions) {
|
|
5656
|
+
const batches = [];
|
|
5657
|
+
let bucketOffset = 0;
|
|
5658
|
+
let sessionOffset = 0;
|
|
5659
|
+
while (bucketOffset < buckets.length || sessionOffset < sessions.length) {
|
|
5660
|
+
const batchBuckets = buckets.slice(bucketOffset, bucketOffset + BATCH_SIZE);
|
|
5661
|
+
const batchSessions = sessions.slice(
|
|
5662
|
+
sessionOffset,
|
|
5663
|
+
sessionOffset + SESSION_BATCH_SIZE
|
|
5664
|
+
);
|
|
5665
|
+
batches.push(
|
|
5666
|
+
...splitOversizedUploadBatch(device, batchBuckets, batchSessions)
|
|
5667
|
+
);
|
|
5668
|
+
bucketOffset += batchBuckets.length;
|
|
5669
|
+
sessionOffset += batchSessions.length;
|
|
5670
|
+
}
|
|
5671
|
+
return batches;
|
|
5672
|
+
}
|
|
5459
5673
|
async function runSync(config, opts = {}) {
|
|
5460
5674
|
const { quiet = false, source = "manual", throws = false } = opts;
|
|
5461
5675
|
const lock = tryAcquireSyncLock(source);
|
|
@@ -5596,24 +5810,19 @@ async function runSync(config, opts = {}) {
|
|
|
5596
5810
|
markSyncSucceeded(source, { buckets: 0, sessions: 0 });
|
|
5597
5811
|
return { buckets: 0, sessions: 0 };
|
|
5598
5812
|
}
|
|
5599
|
-
const
|
|
5600
|
-
|
|
5601
|
-
|
|
5813
|
+
const uploadBatches = buildUploadBatches(
|
|
5814
|
+
device,
|
|
5815
|
+
changedBuckets,
|
|
5816
|
+
changedSessions
|
|
5602
5817
|
);
|
|
5603
|
-
const totalBatches =
|
|
5604
|
-
const batchPayloadSizes =
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
batchIdx * BATCH_SIZE,
|
|
5610
|
-
(batchIdx + 1) * BATCH_SIZE
|
|
5611
|
-
),
|
|
5612
|
-
changedSessions.slice(
|
|
5613
|
-
batchIdx * SESSION_BATCH_SIZE,
|
|
5614
|
-
(batchIdx + 1) * SESSION_BATCH_SIZE
|
|
5818
|
+
const totalBatches = uploadBatches.length;
|
|
5819
|
+
const batchPayloadSizes = uploadBatches.map(
|
|
5820
|
+
(batch, batchIdx) => getIngestPayloadSize(device, batch.buckets, batch.sessions, {
|
|
5821
|
+
syncAchievements: shouldSyncAchievementsForBatch(
|
|
5822
|
+
batchIdx,
|
|
5823
|
+
totalBatches
|
|
5615
5824
|
)
|
|
5616
|
-
)
|
|
5825
|
+
})
|
|
5617
5826
|
);
|
|
5618
5827
|
const totalPayloadBytes = batchPayloadSizes.reduce(
|
|
5619
5828
|
(sum, size) => sum + size,
|
|
@@ -5640,14 +5849,11 @@ async function runSync(config, opts = {}) {
|
|
|
5640
5849
|
);
|
|
5641
5850
|
}
|
|
5642
5851
|
for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {
|
|
5643
|
-
const
|
|
5644
|
-
|
|
5645
|
-
(
|
|
5646
|
-
|
|
5647
|
-
const batchSessions =
|
|
5648
|
-
batchIdx * SESSION_BATCH_SIZE,
|
|
5649
|
-
(batchIdx + 1) * SESSION_BATCH_SIZE
|
|
5650
|
-
);
|
|
5852
|
+
const uploadBatch = uploadBatches[batchIdx];
|
|
5853
|
+
if (!uploadBatch) {
|
|
5854
|
+
throw new SyncFailure("Upload batch planning failed.", "error");
|
|
5855
|
+
}
|
|
5856
|
+
const { buckets: batch, sessions: batchSessions } = uploadBatch;
|
|
5651
5857
|
const batchNum = batchIdx + 1;
|
|
5652
5858
|
const result = await apiClient.ingest(
|
|
5653
5859
|
device,
|
|
@@ -5660,6 +5866,12 @@ async function runSync(config, opts = {}) {
|
|
|
5660
5866
|
batchNum,
|
|
5661
5867
|
totalBatches
|
|
5662
5868
|
);
|
|
5869
|
+
},
|
|
5870
|
+
{
|
|
5871
|
+
syncAchievements: shouldSyncAchievementsForBatch(
|
|
5872
|
+
batchIdx,
|
|
5873
|
+
totalBatches
|
|
5874
|
+
)
|
|
5663
5875
|
}
|
|
5664
5876
|
);
|
|
5665
5877
|
totalIngested += result.ingested ?? batch.length;
|
|
@@ -5735,18 +5947,18 @@ View your dashboard at: ${apiUrl}/usage`);
|
|
|
5735
5947
|
|
|
5736
5948
|
// src/commands/init.ts
|
|
5737
5949
|
import { execFileSync as execFileSync7, spawn } from "child_process";
|
|
5738
|
-
import { existsSync as
|
|
5950
|
+
import { existsSync as existsSync28 } from "fs";
|
|
5739
5951
|
import { appendFile, mkdir, readFile } from "fs/promises";
|
|
5740
|
-
import { homedir as
|
|
5741
|
-
import { dirname as dirname6, join as
|
|
5952
|
+
import { homedir as homedir26, platform as platform5 } from "os";
|
|
5953
|
+
import { dirname as dirname6, join as join27, posix as posix3, win32 } from "path";
|
|
5742
5954
|
|
|
5743
5955
|
// src/infrastructure/service/index.ts
|
|
5744
5956
|
import { platform as platform4 } from "os";
|
|
5745
5957
|
|
|
5746
5958
|
// src/infrastructure/service/linux-systemd.ts
|
|
5747
5959
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
5748
|
-
import { existsSync as
|
|
5749
|
-
import { homedir as
|
|
5960
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
5961
|
+
import { homedir as homedir24, platform as platform2 } from "os";
|
|
5750
5962
|
import { posix } from "path";
|
|
5751
5963
|
|
|
5752
5964
|
// src/utils/command.ts
|
|
@@ -5815,10 +6027,10 @@ function escapeXml(value) {
|
|
|
5815
6027
|
|
|
5816
6028
|
// src/infrastructure/service/linux-systemd.ts
|
|
5817
6029
|
var SYSTEMD_SERVICE_NAME = "tokenarena";
|
|
5818
|
-
function getLinuxSystemdServiceDir(homePath =
|
|
6030
|
+
function getLinuxSystemdServiceDir(homePath = homedir24()) {
|
|
5819
6031
|
return posix.join(homePath, ".config", "systemd", "user");
|
|
5820
6032
|
}
|
|
5821
|
-
function getLinuxSystemdServiceFile(homePath =
|
|
6033
|
+
function getLinuxSystemdServiceFile(homePath = homedir24()) {
|
|
5822
6034
|
return posix.join(
|
|
5823
6035
|
getLinuxSystemdServiceDir(homePath),
|
|
5824
6036
|
`${SYSTEMD_SERVICE_NAME}.service`
|
|
@@ -5875,7 +6087,7 @@ function ensureSystemdAvailable() {
|
|
|
5875
6087
|
}
|
|
5876
6088
|
function createLinuxSystemdServiceBackend() {
|
|
5877
6089
|
function isInstalled() {
|
|
5878
|
-
return
|
|
6090
|
+
return existsSync26(getLinuxSystemdServiceFile());
|
|
5879
6091
|
}
|
|
5880
6092
|
async function setup(skipPrompt = false) {
|
|
5881
6093
|
if (!ensureSystemdAvailable()) {
|
|
@@ -6000,7 +6212,7 @@ function createLinuxSystemdServiceBackend() {
|
|
|
6000
6212
|
}
|
|
6001
6213
|
async function uninstall(skipPrompt = false) {
|
|
6002
6214
|
const serviceFile = getLinuxSystemdServiceFile();
|
|
6003
|
-
if (!
|
|
6215
|
+
if (!existsSync26(serviceFile)) {
|
|
6004
6216
|
logger.info(formatBullet("\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002", "warning"));
|
|
6005
6217
|
return;
|
|
6006
6218
|
}
|
|
@@ -6061,17 +6273,17 @@ function createLinuxSystemdServiceBackend() {
|
|
|
6061
6273
|
|
|
6062
6274
|
// src/infrastructure/service/macos-launchd.ts
|
|
6063
6275
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
6064
|
-
import { existsSync as
|
|
6065
|
-
import { homedir as
|
|
6276
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync4, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
6277
|
+
import { homedir as homedir25, platform as platform3 } from "os";
|
|
6066
6278
|
import { posix as posix2 } from "path";
|
|
6067
6279
|
var MACOS_LAUNCHD_LABEL = "com.guji.tokenarena";
|
|
6068
6280
|
function getCurrentUid() {
|
|
6069
6281
|
return typeof process.getuid === "function" ? process.getuid() : null;
|
|
6070
6282
|
}
|
|
6071
|
-
function getMacosLaunchAgentDir(homePath =
|
|
6283
|
+
function getMacosLaunchAgentDir(homePath = homedir25()) {
|
|
6072
6284
|
return posix2.join(homePath, "Library", "LaunchAgents");
|
|
6073
6285
|
}
|
|
6074
|
-
function getMacosLaunchAgentFile(homePath =
|
|
6286
|
+
function getMacosLaunchAgentFile(homePath = homedir25()) {
|
|
6075
6287
|
return posix2.join(
|
|
6076
6288
|
getMacosLaunchAgentDir(homePath),
|
|
6077
6289
|
`${MACOS_LAUNCHD_LABEL}.plist`
|
|
@@ -6198,7 +6410,7 @@ function writeLaunchAgentPlist() {
|
|
|
6198
6410
|
label: MACOS_LAUNCHD_LABEL,
|
|
6199
6411
|
programArguments: [command.execPath, ...command.args],
|
|
6200
6412
|
environment: getManagedServiceEnvironment(),
|
|
6201
|
-
workingDirectory:
|
|
6413
|
+
workingDirectory: homedir25(),
|
|
6202
6414
|
standardOutPath: stdoutPath,
|
|
6203
6415
|
standardErrorPath: stderrPath
|
|
6204
6416
|
});
|
|
@@ -6223,7 +6435,7 @@ function bootstrapLaunchAgent() {
|
|
|
6223
6435
|
}
|
|
6224
6436
|
function createMacosLaunchdServiceBackend() {
|
|
6225
6437
|
function isInstalled() {
|
|
6226
|
-
return
|
|
6438
|
+
return existsSync27(getMacosLaunchAgentFile());
|
|
6227
6439
|
}
|
|
6228
6440
|
async function setup(skipPrompt = false) {
|
|
6229
6441
|
if (!ensureLaunchctlAvailable()) {
|
|
@@ -6364,7 +6576,7 @@ function createMacosLaunchdServiceBackend() {
|
|
|
6364
6576
|
}
|
|
6365
6577
|
async function uninstall(skipPrompt = false) {
|
|
6366
6578
|
const plistFile = getMacosLaunchAgentFile();
|
|
6367
|
-
if (!
|
|
6579
|
+
if (!existsSync27(plistFile)) {
|
|
6368
6580
|
logger.info(formatBullet("\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002", "warning"));
|
|
6369
6581
|
return;
|
|
6370
6582
|
}
|
|
@@ -6475,7 +6687,7 @@ function resolvePowerShellProfilePath() {
|
|
|
6475
6687
|
const systemRoot = process.env.SYSTEMROOT || "C:\\Windows";
|
|
6476
6688
|
const candidates = [
|
|
6477
6689
|
"pwsh.exe",
|
|
6478
|
-
|
|
6690
|
+
join27(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
6479
6691
|
];
|
|
6480
6692
|
for (const command of candidates) {
|
|
6481
6693
|
try {
|
|
@@ -6504,8 +6716,8 @@ function resolvePowerShellProfilePath() {
|
|
|
6504
6716
|
function resolveShellAliasSetup(options = {}) {
|
|
6505
6717
|
const currentPlatform = options.currentPlatform ?? platform5();
|
|
6506
6718
|
const env = options.env ?? process.env;
|
|
6507
|
-
const homeDir = options.homeDir ??
|
|
6508
|
-
const pathExists = options.exists ??
|
|
6719
|
+
const homeDir = options.homeDir ?? homedir26();
|
|
6720
|
+
const pathExists = options.exists ?? existsSync28;
|
|
6509
6721
|
const shellFromEnv = env.SHELL ? basenameLikeShell(env.SHELL).toLowerCase() : "";
|
|
6510
6722
|
const shellName = shellFromEnv || (currentPlatform === "win32" ? "powershell" : "");
|
|
6511
6723
|
const aliasName = "ta";
|
|
@@ -6702,7 +6914,7 @@ async function setupShellAlias() {
|
|
|
6702
6914
|
try {
|
|
6703
6915
|
await mkdir(dirname6(setup.configFile), { recursive: true });
|
|
6704
6916
|
let existingContent = "";
|
|
6705
|
-
if (
|
|
6917
|
+
if (existsSync28(setup.configFile)) {
|
|
6706
6918
|
existingContent = await readFile(setup.configFile, "utf-8");
|
|
6707
6919
|
}
|
|
6708
6920
|
const normalizedContent = existingContent.toLowerCase();
|
|
@@ -6961,7 +7173,7 @@ function buildLocalUsageDashboardData(input2) {
|
|
|
6961
7173
|
|
|
6962
7174
|
// src/infrastructure/runtime/cli-version.ts
|
|
6963
7175
|
import { readFileSync as readFileSync13 } from "fs";
|
|
6964
|
-
import { dirname as dirname7, join as
|
|
7176
|
+
import { dirname as dirname7, join as join28 } from "path";
|
|
6965
7177
|
import { fileURLToPath } from "url";
|
|
6966
7178
|
var FALLBACK_VERSION = "0.0.0";
|
|
6967
7179
|
var cachedVersion;
|
|
@@ -6969,7 +7181,7 @@ function getCliVersion(metaUrl = import.meta.url) {
|
|
|
6969
7181
|
if (cachedVersion) {
|
|
6970
7182
|
return cachedVersion;
|
|
6971
7183
|
}
|
|
6972
|
-
const packageJsonPath =
|
|
7184
|
+
const packageJsonPath = join28(
|
|
6973
7185
|
dirname7(fileURLToPath(metaUrl)),
|
|
6974
7186
|
"..",
|
|
6975
7187
|
"package.json"
|
|
@@ -7380,8 +7592,8 @@ async function runSyncCommand(opts = {}) {
|
|
|
7380
7592
|
}
|
|
7381
7593
|
|
|
7382
7594
|
// src/commands/uninstall.ts
|
|
7383
|
-
import { existsSync as
|
|
7384
|
-
import { homedir as
|
|
7595
|
+
import { existsSync as existsSync29, readFileSync as readFileSync14, rmSync as rmSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
7596
|
+
import { homedir as homedir27, platform as platform6 } from "os";
|
|
7385
7597
|
function removeShellAlias() {
|
|
7386
7598
|
const shell = process.env.SHELL;
|
|
7387
7599
|
if (!shell) return;
|
|
@@ -7390,22 +7602,22 @@ function removeShellAlias() {
|
|
|
7390
7602
|
let configFile;
|
|
7391
7603
|
switch (shellName) {
|
|
7392
7604
|
case "zsh":
|
|
7393
|
-
configFile = `${
|
|
7605
|
+
configFile = `${homedir27()}/.zshrc`;
|
|
7394
7606
|
break;
|
|
7395
7607
|
case "bash":
|
|
7396
|
-
if (platform6() === "darwin" &&
|
|
7397
|
-
configFile = `${
|
|
7608
|
+
if (platform6() === "darwin" && existsSync29(`${homedir27()}/.bash_profile`)) {
|
|
7609
|
+
configFile = `${homedir27()}/.bash_profile`;
|
|
7398
7610
|
} else {
|
|
7399
|
-
configFile = `${
|
|
7611
|
+
configFile = `${homedir27()}/.bashrc`;
|
|
7400
7612
|
}
|
|
7401
7613
|
break;
|
|
7402
7614
|
case "fish":
|
|
7403
|
-
configFile = `${
|
|
7615
|
+
configFile = `${homedir27()}/.config/fish/config.fish`;
|
|
7404
7616
|
break;
|
|
7405
7617
|
default:
|
|
7406
7618
|
return;
|
|
7407
7619
|
}
|
|
7408
|
-
if (!
|
|
7620
|
+
if (!existsSync29(configFile)) return;
|
|
7409
7621
|
try {
|
|
7410
7622
|
let content = readFileSync14(configFile, "utf-8");
|
|
7411
7623
|
const aliasPatterns = [
|
|
@@ -7444,7 +7656,7 @@ async function runUninstall() {
|
|
|
7444
7656
|
const runtimeDir = getRuntimeDirPath();
|
|
7445
7657
|
const serviceBackend = getServiceBackend();
|
|
7446
7658
|
const hasInstalledService = serviceBackend?.isInstalled() ?? false;
|
|
7447
|
-
const hasLocalArtifacts =
|
|
7659
|
+
const hasLocalArtifacts = existsSync29(configPath) || existsSync29(configDir) || existsSync29(stateDir) || existsSync29(runtimeDir) || hasInstalledService;
|
|
7448
7660
|
if (!hasLocalArtifacts) {
|
|
7449
7661
|
logger.info(formatHeader("\u5378\u8F7D TokenArena"));
|
|
7450
7662
|
logger.info(formatBullet("\u672A\u53D1\u73B0\u672C\u5730\u914D\u7F6E\uFF0C\u65E0\u9700\u5378\u8F7D\u3002"));
|
|
@@ -7488,22 +7700,22 @@ async function runUninstall() {
|
|
|
7488
7700
|
}
|
|
7489
7701
|
}
|
|
7490
7702
|
logger.info(formatSection("\u6267\u884C\u7ED3\u679C"));
|
|
7491
|
-
if (
|
|
7703
|
+
if (existsSync29(configPath)) {
|
|
7492
7704
|
deleteConfig();
|
|
7493
7705
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u6587\u4EF6\u3002", "success"));
|
|
7494
7706
|
}
|
|
7495
|
-
if (
|
|
7707
|
+
if (existsSync29(configDir)) {
|
|
7496
7708
|
try {
|
|
7497
7709
|
rmSync6(configDir, { recursive: false, force: true });
|
|
7498
7710
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u914D\u7F6E\u76EE\u5F55\u3002", "success"));
|
|
7499
7711
|
} catch {
|
|
7500
7712
|
}
|
|
7501
7713
|
}
|
|
7502
|
-
if (
|
|
7714
|
+
if (existsSync29(stateDir)) {
|
|
7503
7715
|
rmSync6(stateDir, { recursive: true, force: true });
|
|
7504
7716
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u72B6\u6001\u6570\u636E\u3002", "success"));
|
|
7505
7717
|
}
|
|
7506
|
-
if (
|
|
7718
|
+
if (existsSync29(runtimeDir)) {
|
|
7507
7719
|
rmSync6(runtimeDir, { recursive: true, force: true });
|
|
7508
7720
|
logger.info(formatBullet("\u5DF2\u5220\u9664\u8FD0\u884C\u65F6\u6570\u636E\u3002", "success"));
|
|
7509
7721
|
}
|
|
@@ -7734,7 +7946,7 @@ function createCli() {
|
|
|
7734
7946
|
}
|
|
7735
7947
|
|
|
7736
7948
|
// src/infrastructure/runtime/main-module.ts
|
|
7737
|
-
import { existsSync as
|
|
7949
|
+
import { existsSync as existsSync30, realpathSync as realpathSync2 } from "fs";
|
|
7738
7950
|
import { resolve as resolve3 } from "path";
|
|
7739
7951
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7740
7952
|
function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
|
|
@@ -7745,7 +7957,7 @@ function isMainModule(argvEntry = process.argv[1], metaUrl = import.meta.url) {
|
|
|
7745
7957
|
try {
|
|
7746
7958
|
return realpathSync2(argvEntry) === realpathSync2(currentModulePath);
|
|
7747
7959
|
} catch {
|
|
7748
|
-
if (!
|
|
7960
|
+
if (!existsSync30(argvEntry)) {
|
|
7749
7961
|
return false;
|
|
7750
7962
|
}
|
|
7751
7963
|
return resolve3(argvEntry) === resolve3(currentModulePath);
|