@yishiguji/tokenarena 0.16.2 → 0.16.3
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 +202 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -367,8 +367,25 @@ function selectSnapshot(current, candidate) {
|
|
|
367
367
|
}
|
|
368
368
|
};
|
|
369
369
|
}
|
|
370
|
+
function getScanDirectories() {
|
|
371
|
+
const directories = [];
|
|
372
|
+
for (const root of getClaudeRoots()) {
|
|
373
|
+
directories.push(join2(root, "projects"));
|
|
374
|
+
}
|
|
375
|
+
for (const root of getClaudeRoots()) {
|
|
376
|
+
for (const directory of ["transcripts", "sessions"]) {
|
|
377
|
+
directories.push(join2(root, directory));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return directories;
|
|
381
|
+
}
|
|
370
382
|
var ClaudeCodeParser = class {
|
|
371
383
|
tool = TOOL;
|
|
384
|
+
listSourceFiles() {
|
|
385
|
+
return getScanDirectories().flatMap(
|
|
386
|
+
(directory) => findJsonlFiles(directory)
|
|
387
|
+
);
|
|
388
|
+
}
|
|
372
389
|
async parse() {
|
|
373
390
|
const snapshots = /* @__PURE__ */ new Map();
|
|
374
391
|
const sessionEvents = /* @__PURE__ */ new Map();
|
|
@@ -737,12 +754,16 @@ var CodexParser = class {
|
|
|
737
754
|
isInstalled() {
|
|
738
755
|
return this.dataDirs.some((directory) => existsSync4(directory));
|
|
739
756
|
}
|
|
757
|
+
/** The same list `parse()` reads, so the two can never drift apart. */
|
|
758
|
+
listSourceFiles() {
|
|
759
|
+
return [...new Set(this.dataDirs.flatMap(findJsonlFiles))].sort();
|
|
760
|
+
}
|
|
740
761
|
async parse() {
|
|
741
762
|
const entries = [];
|
|
742
763
|
const sessionEvents = [];
|
|
743
764
|
const threads = /* @__PURE__ */ new Map();
|
|
744
765
|
const threadIndex = /* @__PURE__ */ new Map();
|
|
745
|
-
const files =
|
|
766
|
+
const files = this.listSourceFiles();
|
|
746
767
|
for (const path of files) {
|
|
747
768
|
const file = readRollout(path);
|
|
748
769
|
if (!file) continue;
|
|
@@ -6661,7 +6682,7 @@ async function handleConfig(args) {
|
|
|
6661
6682
|
}
|
|
6662
6683
|
|
|
6663
6684
|
// src/services/sync-service.ts
|
|
6664
|
-
import { hostname as
|
|
6685
|
+
import { hostname as hostname7 } from "os";
|
|
6665
6686
|
|
|
6666
6687
|
// src/domain/project-identity.ts
|
|
6667
6688
|
import { createHmac } from "crypto";
|
|
@@ -7293,38 +7314,179 @@ function saveUploadManifest(manifest) {
|
|
|
7293
7314
|
);
|
|
7294
7315
|
}
|
|
7295
7316
|
|
|
7317
|
+
// src/services/parse-cache.ts
|
|
7318
|
+
import { createHash as createHash7 } from "crypto";
|
|
7319
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync14, statSync as statSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
7320
|
+
import { hostname as hostname6 } from "os";
|
|
7321
|
+
import { join as join35 } from "path";
|
|
7322
|
+
|
|
7323
|
+
// src/infrastructure/runtime/cli-version.ts
|
|
7324
|
+
import { dirname as dirname7, join as join34 } from "path";
|
|
7325
|
+
import { fileURLToPath } from "url";
|
|
7326
|
+
var FALLBACK_VERSION = "0.0.0";
|
|
7327
|
+
var versionCache = /* @__PURE__ */ new Map();
|
|
7328
|
+
function readPackageVersion(startDir) {
|
|
7329
|
+
let dir = startDir;
|
|
7330
|
+
while (true) {
|
|
7331
|
+
const contents = readFileSafe(join34(dir, "package.json"));
|
|
7332
|
+
if (contents !== null) {
|
|
7333
|
+
try {
|
|
7334
|
+
const { version } = JSON.parse(contents);
|
|
7335
|
+
return typeof version === "string" && version.length > 0 ? version : void 0;
|
|
7336
|
+
} catch {
|
|
7337
|
+
return void 0;
|
|
7338
|
+
}
|
|
7339
|
+
}
|
|
7340
|
+
const parent = dirname7(dir);
|
|
7341
|
+
if (parent === dir) {
|
|
7342
|
+
return void 0;
|
|
7343
|
+
}
|
|
7344
|
+
dir = parent;
|
|
7345
|
+
}
|
|
7346
|
+
}
|
|
7347
|
+
function getCliVersion(metaUrl = import.meta.url) {
|
|
7348
|
+
const startDir = dirname7(fileURLToPath(metaUrl));
|
|
7349
|
+
const cached = versionCache.get(startDir);
|
|
7350
|
+
if (cached !== void 0) {
|
|
7351
|
+
return cached;
|
|
7352
|
+
}
|
|
7353
|
+
const version = readPackageVersion(startDir) ?? FALLBACK_VERSION;
|
|
7354
|
+
versionCache.set(startDir, version);
|
|
7355
|
+
return version;
|
|
7356
|
+
}
|
|
7357
|
+
|
|
7358
|
+
// src/services/parse-cache.ts
|
|
7359
|
+
var CACHE_FORMAT_VERSION = 1;
|
|
7360
|
+
var SETTLE_MS = 5e3;
|
|
7361
|
+
function getParseCacheDir() {
|
|
7362
|
+
return join35(getStateDir(), "parse-cache");
|
|
7363
|
+
}
|
|
7364
|
+
function getParseCachePath(toolId) {
|
|
7365
|
+
return join35(getParseCacheDir(), `${toolId}.json`);
|
|
7366
|
+
}
|
|
7367
|
+
function computeScanFingerprint(files, now = Date.now()) {
|
|
7368
|
+
const hash = createHash7("sha256");
|
|
7369
|
+
hash.update(`v${CACHE_FORMAT_VERSION}\0`);
|
|
7370
|
+
hash.update(`${getCliVersion()}\0`);
|
|
7371
|
+
hash.update(`${hostname6()}\0`);
|
|
7372
|
+
for (const file of [...files].sort()) {
|
|
7373
|
+
let stats;
|
|
7374
|
+
try {
|
|
7375
|
+
stats = statSync6(file);
|
|
7376
|
+
} catch {
|
|
7377
|
+
return null;
|
|
7378
|
+
}
|
|
7379
|
+
if (now - stats.mtimeMs < SETTLE_MS) {
|
|
7380
|
+
return null;
|
|
7381
|
+
}
|
|
7382
|
+
hash.update(`${file}\0${stats.mtimeMs}\0${stats.size}\0`);
|
|
7383
|
+
}
|
|
7384
|
+
return hash.digest("hex");
|
|
7385
|
+
}
|
|
7386
|
+
function loadCachedParseResult(toolId, fingerprint2) {
|
|
7387
|
+
if (!fingerprint2) {
|
|
7388
|
+
return null;
|
|
7389
|
+
}
|
|
7390
|
+
try {
|
|
7391
|
+
const envelope = JSON.parse(
|
|
7392
|
+
readFileSync14(getParseCachePath(toolId), "utf-8")
|
|
7393
|
+
);
|
|
7394
|
+
if (envelope.formatVersion !== CACHE_FORMAT_VERSION || envelope.fingerprint !== fingerprint2 || !Array.isArray(envelope.result?.buckets) || !Array.isArray(envelope.result?.sessions)) {
|
|
7395
|
+
return null;
|
|
7396
|
+
}
|
|
7397
|
+
return {
|
|
7398
|
+
buckets: envelope.result.buckets,
|
|
7399
|
+
sessions: envelope.result.sessions
|
|
7400
|
+
};
|
|
7401
|
+
} catch {
|
|
7402
|
+
return null;
|
|
7403
|
+
}
|
|
7404
|
+
}
|
|
7405
|
+
function saveCachedParseResult(toolId, fingerprint2, result) {
|
|
7406
|
+
if (!fingerprint2 || result.incomplete) {
|
|
7407
|
+
return;
|
|
7408
|
+
}
|
|
7409
|
+
const envelope = {
|
|
7410
|
+
formatVersion: CACHE_FORMAT_VERSION,
|
|
7411
|
+
fingerprint: fingerprint2,
|
|
7412
|
+
result: { buckets: result.buckets, sessions: result.sessions }
|
|
7413
|
+
};
|
|
7414
|
+
try {
|
|
7415
|
+
mkdirSync3(getParseCacheDir(), { recursive: true });
|
|
7416
|
+
writeFileSync5(getParseCachePath(toolId), JSON.stringify(envelope), "utf-8");
|
|
7417
|
+
} catch {
|
|
7418
|
+
}
|
|
7419
|
+
}
|
|
7420
|
+
|
|
7296
7421
|
// src/services/parser-service.ts
|
|
7422
|
+
var PARSER_CONCURRENCY = 8;
|
|
7423
|
+
async function parseWithCache(parser) {
|
|
7424
|
+
const files = parser.listSourceFiles?.();
|
|
7425
|
+
const fingerprint2 = files ? computeScanFingerprint(files) : null;
|
|
7426
|
+
const cached = loadCachedParseResult(parser.tool.id, fingerprint2);
|
|
7427
|
+
if (cached) {
|
|
7428
|
+
return { status: "ok", result: cached, cached: true };
|
|
7429
|
+
}
|
|
7430
|
+
try {
|
|
7431
|
+
const result = await parser.parse();
|
|
7432
|
+
saveCachedParseResult(parser.tool.id, fingerprint2, result);
|
|
7433
|
+
return { status: "ok", result, cached: false };
|
|
7434
|
+
} catch (err) {
|
|
7435
|
+
return {
|
|
7436
|
+
status: "failed",
|
|
7437
|
+
message: err instanceof Error ? err.message : String(err)
|
|
7438
|
+
};
|
|
7439
|
+
}
|
|
7440
|
+
}
|
|
7441
|
+
async function mapWithConcurrency(items, limit, run2) {
|
|
7442
|
+
const results = new Array(items.length);
|
|
7443
|
+
let cursor = 0;
|
|
7444
|
+
async function worker() {
|
|
7445
|
+
while (cursor < items.length) {
|
|
7446
|
+
const index = cursor++;
|
|
7447
|
+
results[index] = await run2(items[index]);
|
|
7448
|
+
}
|
|
7449
|
+
}
|
|
7450
|
+
await Promise.all(
|
|
7451
|
+
Array.from({ length: Math.min(limit, items.length) }, () => worker())
|
|
7452
|
+
);
|
|
7453
|
+
return results;
|
|
7454
|
+
}
|
|
7297
7455
|
async function runAllParsers() {
|
|
7298
7456
|
const allBuckets = [];
|
|
7299
7457
|
const allSessions = [];
|
|
7300
7458
|
const parserResults = [];
|
|
7301
7459
|
const failedSources = /* @__PURE__ */ new Set();
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
parserResults.push({
|
|
7318
|
-
source: parser.tool.id,
|
|
7319
|
-
buckets: buckets.length,
|
|
7320
|
-
sessions: sessions.length
|
|
7321
|
-
});
|
|
7322
|
-
}
|
|
7323
|
-
} catch (err) {
|
|
7460
|
+
const parsers2 = getAllParsers();
|
|
7461
|
+
const settled = await mapWithConcurrency(
|
|
7462
|
+
parsers2,
|
|
7463
|
+
PARSER_CONCURRENCY,
|
|
7464
|
+
parseWithCache
|
|
7465
|
+
);
|
|
7466
|
+
for (const [index, parser] of parsers2.entries()) {
|
|
7467
|
+
const outcome = settled[index];
|
|
7468
|
+
if (outcome.status === "failed") {
|
|
7469
|
+
failedSources.add(parser.tool.id);
|
|
7470
|
+
logger.warn(`${parser.tool.id} parser failed: ${outcome.message}`);
|
|
7471
|
+
continue;
|
|
7472
|
+
}
|
|
7473
|
+
const { buckets, sessions, incomplete } = outcome.result;
|
|
7474
|
+
if (incomplete) {
|
|
7324
7475
|
failedSources.add(parser.tool.id);
|
|
7325
7476
|
logger.warn(
|
|
7326
|
-
`${parser.tool.id} parser
|
|
7477
|
+
`${parser.tool.id} parser reported an incomplete scan; preserving its remote history.`
|
|
7327
7478
|
);
|
|
7479
|
+
continue;
|
|
7480
|
+
}
|
|
7481
|
+
if (buckets.length > 0) allBuckets.push(...buckets);
|
|
7482
|
+
if (sessions.length > 0) allSessions.push(...sessions);
|
|
7483
|
+
if (buckets.length > 0 || sessions.length > 0) {
|
|
7484
|
+
parserResults.push({
|
|
7485
|
+
source: parser.tool.id,
|
|
7486
|
+
buckets: buckets.length,
|
|
7487
|
+
sessions: sessions.length,
|
|
7488
|
+
...outcome.cached ? { cached: true } : {}
|
|
7489
|
+
});
|
|
7328
7490
|
}
|
|
7329
7491
|
}
|
|
7330
7492
|
return {
|
|
@@ -7399,7 +7561,7 @@ function persistUploadManifest(manifest, quiet) {
|
|
|
7399
7561
|
function toDeviceMetadata(config) {
|
|
7400
7562
|
return {
|
|
7401
7563
|
deviceId: getOrCreateDeviceId(config),
|
|
7402
|
-
hostname:
|
|
7564
|
+
hostname: hostname7().replace(/\.local$/, "")
|
|
7403
7565
|
};
|
|
7404
7566
|
}
|
|
7405
7567
|
function toUploadBuckets(buckets, settings, device) {
|
|
@@ -7598,7 +7760,8 @@ async function runSync(config, opts = {}) {
|
|
|
7598
7760
|
const parts = [];
|
|
7599
7761
|
if (p.buckets > 0) parts.push(`${p.buckets} buckets`);
|
|
7600
7762
|
if (p.sessions > 0) parts.push(`${p.sessions} sessions`);
|
|
7601
|
-
|
|
7763
|
+
const suffix = p.cached ? " (unchanged)" : "";
|
|
7764
|
+
logger.info(` ${p.source}: ${parts.join(", ")}${suffix}`);
|
|
7602
7765
|
}
|
|
7603
7766
|
}
|
|
7604
7767
|
const apiUrl = config.apiUrl || "https://token.guji.uno";
|
|
@@ -7850,14 +8013,14 @@ import { execFileSync as execFileSync7, spawn } from "child_process";
|
|
|
7850
8013
|
import { existsSync as existsSync36 } from "fs";
|
|
7851
8014
|
import { appendFile, mkdir, readFile } from "fs/promises";
|
|
7852
8015
|
import { homedir as homedir33, platform as platform5 } from "os";
|
|
7853
|
-
import { dirname as
|
|
8016
|
+
import { dirname as dirname8, join as join36, posix as posix3, win32 } from "path";
|
|
7854
8017
|
|
|
7855
8018
|
// src/infrastructure/service/index.ts
|
|
7856
8019
|
import { platform as platform4 } from "os";
|
|
7857
8020
|
|
|
7858
8021
|
// src/infrastructure/service/linux-systemd.ts
|
|
7859
8022
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
7860
|
-
import { existsSync as existsSync34, mkdirSync as
|
|
8023
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync4, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
7861
8024
|
import { homedir as homedir31, platform as platform2 } from "os";
|
|
7862
8025
|
import { posix } from "path";
|
|
7863
8026
|
|
|
@@ -8019,8 +8182,8 @@ function createLinuxSystemdServiceBackend() {
|
|
|
8019
8182
|
execPath: command.execPath,
|
|
8020
8183
|
args: command.args
|
|
8021
8184
|
});
|
|
8022
|
-
|
|
8023
|
-
|
|
8185
|
+
mkdirSync4(serviceDir, { recursive: true });
|
|
8186
|
+
writeFileSync6(serviceFile, content, "utf-8");
|
|
8024
8187
|
execSystemctl(["daemon-reload"]);
|
|
8025
8188
|
execSystemctl(["enable", SYSTEMD_SERVICE_NAME]);
|
|
8026
8189
|
execSystemctl(["start", SYSTEMD_SERVICE_NAME]);
|
|
@@ -8179,7 +8342,7 @@ function createLinuxSystemdServiceBackend() {
|
|
|
8179
8342
|
|
|
8180
8343
|
// src/infrastructure/service/macos-launchd.ts
|
|
8181
8344
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
8182
|
-
import { existsSync as existsSync35, mkdirSync as
|
|
8345
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync5, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
8183
8346
|
import { homedir as homedir32, platform as platform3 } from "os";
|
|
8184
8347
|
import { posix as posix2 } from "path";
|
|
8185
8348
|
var MACOS_LAUNCHD_LABEL = "com.guji.tokenarena";
|
|
@@ -8321,8 +8484,8 @@ function writeLaunchAgentPlist() {
|
|
|
8321
8484
|
standardErrorPath: stderrPath
|
|
8322
8485
|
});
|
|
8323
8486
|
ensureAppDirs();
|
|
8324
|
-
|
|
8325
|
-
|
|
8487
|
+
mkdirSync5(getMacosLaunchAgentDir(), { recursive: true });
|
|
8488
|
+
writeFileSync7(plistFile, plist, "utf-8");
|
|
8326
8489
|
return plistFile;
|
|
8327
8490
|
}
|
|
8328
8491
|
function bootstrapLaunchAgent() {
|
|
@@ -8593,7 +8756,7 @@ function resolvePowerShellProfilePath() {
|
|
|
8593
8756
|
const systemRoot = process.env.SYSTEMROOT || "C:\\Windows";
|
|
8594
8757
|
const candidates = [
|
|
8595
8758
|
"pwsh.exe",
|
|
8596
|
-
|
|
8759
|
+
join36(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
8597
8760
|
];
|
|
8598
8761
|
for (const command of candidates) {
|
|
8599
8762
|
try {
|
|
@@ -8818,7 +8981,7 @@ async function setupShellAlias() {
|
|
|
8818
8981
|
return;
|
|
8819
8982
|
}
|
|
8820
8983
|
try {
|
|
8821
|
-
await mkdir(
|
|
8984
|
+
await mkdir(dirname8(setup.configFile), { recursive: true });
|
|
8822
8985
|
let existingContent = "";
|
|
8823
8986
|
if (existsSync36(setup.configFile)) {
|
|
8824
8987
|
existingContent = await readFile(setup.configFile, "utf-8");
|
|
@@ -9083,41 +9246,6 @@ function buildLocalUsageDashboardData(input2) {
|
|
|
9083
9246
|
};
|
|
9084
9247
|
}
|
|
9085
9248
|
|
|
9086
|
-
// src/infrastructure/runtime/cli-version.ts
|
|
9087
|
-
import { dirname as dirname8, join as join35 } from "path";
|
|
9088
|
-
import { fileURLToPath } from "url";
|
|
9089
|
-
var FALLBACK_VERSION = "0.0.0";
|
|
9090
|
-
var versionCache = /* @__PURE__ */ new Map();
|
|
9091
|
-
function readPackageVersion(startDir) {
|
|
9092
|
-
let dir = startDir;
|
|
9093
|
-
while (true) {
|
|
9094
|
-
const contents = readFileSafe(join35(dir, "package.json"));
|
|
9095
|
-
if (contents !== null) {
|
|
9096
|
-
try {
|
|
9097
|
-
const { version } = JSON.parse(contents);
|
|
9098
|
-
return typeof version === "string" && version.length > 0 ? version : void 0;
|
|
9099
|
-
} catch {
|
|
9100
|
-
return void 0;
|
|
9101
|
-
}
|
|
9102
|
-
}
|
|
9103
|
-
const parent = dirname8(dir);
|
|
9104
|
-
if (parent === dir) {
|
|
9105
|
-
return void 0;
|
|
9106
|
-
}
|
|
9107
|
-
dir = parent;
|
|
9108
|
-
}
|
|
9109
|
-
}
|
|
9110
|
-
function getCliVersion(metaUrl = import.meta.url) {
|
|
9111
|
-
const startDir = dirname8(fileURLToPath(metaUrl));
|
|
9112
|
-
const cached = versionCache.get(startDir);
|
|
9113
|
-
if (cached !== void 0) {
|
|
9114
|
-
return cached;
|
|
9115
|
-
}
|
|
9116
|
-
const version = readPackageVersion(startDir) ?? FALLBACK_VERSION;
|
|
9117
|
-
versionCache.set(startDir, version);
|
|
9118
|
-
return version;
|
|
9119
|
-
}
|
|
9120
|
-
|
|
9121
9249
|
// src/infrastructure/ui/local-usage-dashboard.ts
|
|
9122
9250
|
var MAX_RANK_ROWS = 6;
|
|
9123
9251
|
var MAX_SESSION_ROWS = 6;
|
|
@@ -9516,7 +9644,7 @@ async function runSyncCommand(opts = {}) {
|
|
|
9516
9644
|
}
|
|
9517
9645
|
|
|
9518
9646
|
// src/commands/uninstall.ts
|
|
9519
|
-
import { existsSync as existsSync37, readFileSync as
|
|
9647
|
+
import { existsSync as existsSync37, readFileSync as readFileSync15, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
9520
9648
|
import { homedir as homedir34, platform as platform6 } from "os";
|
|
9521
9649
|
function removeShellAlias() {
|
|
9522
9650
|
const shell = process.env.SHELL;
|
|
@@ -9543,7 +9671,7 @@ function removeShellAlias() {
|
|
|
9543
9671
|
}
|
|
9544
9672
|
if (!existsSync37(configFile)) return;
|
|
9545
9673
|
try {
|
|
9546
|
-
let content =
|
|
9674
|
+
let content = readFileSync15(configFile, "utf-8");
|
|
9547
9675
|
const aliasPatterns = [
|
|
9548
9676
|
// zsh / bash format: alias ta="tokenarena"
|
|
9549
9677
|
new RegExp(
|
|
@@ -9565,7 +9693,7 @@ function removeShellAlias() {
|
|
|
9565
9693
|
content = next;
|
|
9566
9694
|
}
|
|
9567
9695
|
}
|
|
9568
|
-
|
|
9696
|
+
writeFileSync8(configFile, content, "utf-8");
|
|
9569
9697
|
logger.info(`Removed shell alias from ${configFile}`);
|
|
9570
9698
|
} catch (err) {
|
|
9571
9699
|
logger.warn(
|