@yishiguji/tokenarena 0.16.2 → 0.16.4
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 +267 -119
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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();
|
|
@@ -628,13 +645,15 @@ function readRollout(path) {
|
|
|
628
645
|
let latestTimestampOrder = 0n;
|
|
629
646
|
let minLineTimestampOrder = null;
|
|
630
647
|
let line = 0;
|
|
631
|
-
let
|
|
648
|
+
let maxOrdinal = null;
|
|
632
649
|
for (const text of content.split("\n")) {
|
|
633
650
|
line++;
|
|
634
651
|
if (!text.trim()) continue;
|
|
635
|
-
lineCount++;
|
|
636
652
|
try {
|
|
637
653
|
const event = JSON.parse(text);
|
|
654
|
+
if (typeof event.ordinal === "number" && Number.isSafeInteger(event.ordinal) && event.ordinal >= 0 && (maxOrdinal === null || event.ordinal > maxOrdinal)) {
|
|
655
|
+
maxOrdinal = event.ordinal;
|
|
656
|
+
}
|
|
638
657
|
const timestamp = readTimestamp(event.timestamp);
|
|
639
658
|
const order = timestampOrder(event.timestamp, timestamp);
|
|
640
659
|
if (order !== null) {
|
|
@@ -685,7 +704,7 @@ function readRollout(path) {
|
|
|
685
704
|
forkedFrom && spawnedFrom && forkedFrom !== spawnedFrom
|
|
686
705
|
),
|
|
687
706
|
forkOrdinalExclusive: typeof meta?.forked_from_ordinal_exclusive === "number" && Number.isSafeInteger(meta.forked_from_ordinal_exclusive) && meta.forked_from_ordinal_exclusive > 0 ? meta.forked_from_ordinal_exclusive : null,
|
|
688
|
-
|
|
707
|
+
maxOrdinal,
|
|
689
708
|
rootTimestampOrder: timestampOrder(
|
|
690
709
|
rootMeta?.timestamp,
|
|
691
710
|
readTimestamp(rootMeta?.timestamp)
|
|
@@ -737,12 +756,16 @@ var CodexParser = class {
|
|
|
737
756
|
isInstalled() {
|
|
738
757
|
return this.dataDirs.some((directory) => existsSync4(directory));
|
|
739
758
|
}
|
|
759
|
+
/** The same list `parse()` reads, so the two can never drift apart. */
|
|
760
|
+
listSourceFiles() {
|
|
761
|
+
return [...new Set(this.dataDirs.flatMap(findJsonlFiles))].sort();
|
|
762
|
+
}
|
|
740
763
|
async parse() {
|
|
741
764
|
const entries = [];
|
|
742
765
|
const sessionEvents = [];
|
|
743
766
|
const threads = /* @__PURE__ */ new Map();
|
|
744
767
|
const threadIndex = /* @__PURE__ */ new Map();
|
|
745
|
-
const files =
|
|
768
|
+
const files = this.listSourceFiles();
|
|
746
769
|
for (const path of files) {
|
|
747
770
|
const file = readRollout(path);
|
|
748
771
|
if (!file) continue;
|
|
@@ -788,13 +811,11 @@ var CodexParser = class {
|
|
|
788
811
|
if (file.parentConflict || file.parentId) {
|
|
789
812
|
const parent = file.parentId ? threadIndex.get(file.parentId) : void 0;
|
|
790
813
|
const cutoff = file.rootTimestampOrder;
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
)
|
|
797
|
-
) : cutoff !== null && // 父最大时间戳落后不超过 1 秒,或父内容完全早于截止点
|
|
814
|
+
const parentMaxOrdinal = parent ? parent.files.reduce(
|
|
815
|
+
(max, rollout) => rollout.maxOrdinal !== null && (max === null || rollout.maxOrdinal > max) ? rollout.maxOrdinal : max,
|
|
816
|
+
null
|
|
817
|
+
) : null;
|
|
818
|
+
const coverageOk = parent ? file.forkOrdinalExclusive !== null && parentMaxOrdinal !== null ? parentMaxOrdinal >= file.forkOrdinalExclusive - 1 : cutoff !== null && // 父最大时间戳落后不超过 1 秒,或父内容完全早于截止点
|
|
798
819
|
// 且父最早行时间戳也早于截止点(父在截止前已停止写入)。
|
|
799
820
|
(parent.latestTimestampOrder >= cutoff - 1000000n || parent.minLineTimestampOrder !== null && parent.minLineTimestampOrder < cutoff) : false;
|
|
800
821
|
if (file.parentConflict || !parent || parent === thread || cutoff === null || !processThread(parent) || parent.invalidTokenTimestamp || !coverageOk) {
|
|
@@ -1261,7 +1282,15 @@ import { dirname, join as join6 } from "path";
|
|
|
1261
1282
|
import { execFileSync } from "child_process";
|
|
1262
1283
|
import { statSync } from "fs";
|
|
1263
1284
|
import { pathToFileURL } from "url";
|
|
1264
|
-
|
|
1285
|
+
var warningScope = Promise.resolve();
|
|
1286
|
+
async function withSuppressedSqliteWarning(fn) {
|
|
1287
|
+
const previousScope = warningScope;
|
|
1288
|
+
let releaseScope = () => {
|
|
1289
|
+
};
|
|
1290
|
+
warningScope = new Promise((resolve5) => {
|
|
1291
|
+
releaseScope = resolve5;
|
|
1292
|
+
});
|
|
1293
|
+
await previousScope;
|
|
1265
1294
|
const originalEmitWarning = process.emitWarning;
|
|
1266
1295
|
process.emitWarning = ((warning, ...args) => {
|
|
1267
1296
|
const warningName = typeof warning === "string" ? typeof args[0] === "string" ? args[0] : "" : warning.name;
|
|
@@ -1271,9 +1300,12 @@ function withSuppressedSqliteWarning(fn) {
|
|
|
1271
1300
|
}
|
|
1272
1301
|
originalEmitWarning.call(process, warning, ...args);
|
|
1273
1302
|
});
|
|
1274
|
-
|
|
1303
|
+
try {
|
|
1304
|
+
return await fn();
|
|
1305
|
+
} finally {
|
|
1275
1306
|
process.emitWarning = originalEmitWarning;
|
|
1276
|
-
|
|
1307
|
+
releaseScope();
|
|
1308
|
+
}
|
|
1277
1309
|
}
|
|
1278
1310
|
function warnWhenWalSkipped(dbPath) {
|
|
1279
1311
|
try {
|
|
@@ -2354,25 +2386,9 @@ function getOpenCodeDataDirs(env = process.env) {
|
|
|
2354
2386
|
].filter((value) => Boolean(value));
|
|
2355
2387
|
return Array.from(new Set(dirs));
|
|
2356
2388
|
}
|
|
2357
|
-
async function withSuppressedSqliteWarning2(fn) {
|
|
2358
|
-
const originalEmitWarning = process.emitWarning;
|
|
2359
|
-
process.emitWarning = ((warning, ...args) => {
|
|
2360
|
-
const warningName = typeof warning === "string" ? typeof args[0] === "string" ? args[0] : "" : warning.name;
|
|
2361
|
-
const warningMessage = typeof warning === "string" ? warning : warning.message;
|
|
2362
|
-
if (warningName === "ExperimentalWarning" && warningMessage.includes("SQLite")) {
|
|
2363
|
-
return;
|
|
2364
|
-
}
|
|
2365
|
-
originalEmitWarning.call(process, warning, ...args);
|
|
2366
|
-
});
|
|
2367
|
-
try {
|
|
2368
|
-
return await fn();
|
|
2369
|
-
} finally {
|
|
2370
|
-
process.emitWarning = originalEmitWarning;
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
2389
|
async function readSqliteRowsWithBuiltin2(dbPath, query) {
|
|
2374
2390
|
try {
|
|
2375
|
-
return await
|
|
2391
|
+
return await withSuppressedSqliteWarning(async () => {
|
|
2376
2392
|
const sqliteModuleId = "node:sqlite";
|
|
2377
2393
|
const sqlite = await import(sqliteModuleId);
|
|
2378
2394
|
const db = new sqlite.DatabaseSync(dbPath);
|
|
@@ -6661,7 +6677,7 @@ async function handleConfig(args) {
|
|
|
6661
6677
|
}
|
|
6662
6678
|
|
|
6663
6679
|
// src/services/sync-service.ts
|
|
6664
|
-
import { hostname as
|
|
6680
|
+
import { hostname as hostname7 } from "os";
|
|
6665
6681
|
|
|
6666
6682
|
// src/domain/project-identity.ts
|
|
6667
6683
|
import { createHmac } from "crypto";
|
|
@@ -7293,38 +7309,179 @@ function saveUploadManifest(manifest) {
|
|
|
7293
7309
|
);
|
|
7294
7310
|
}
|
|
7295
7311
|
|
|
7312
|
+
// src/services/parse-cache.ts
|
|
7313
|
+
import { createHash as createHash7 } from "crypto";
|
|
7314
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync14, statSync as statSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
7315
|
+
import { hostname as hostname6 } from "os";
|
|
7316
|
+
import { join as join35 } from "path";
|
|
7317
|
+
|
|
7318
|
+
// src/infrastructure/runtime/cli-version.ts
|
|
7319
|
+
import { dirname as dirname7, join as join34 } from "path";
|
|
7320
|
+
import { fileURLToPath } from "url";
|
|
7321
|
+
var FALLBACK_VERSION = "0.0.0";
|
|
7322
|
+
var versionCache = /* @__PURE__ */ new Map();
|
|
7323
|
+
function readPackageVersion(startDir) {
|
|
7324
|
+
let dir = startDir;
|
|
7325
|
+
while (true) {
|
|
7326
|
+
const contents = readFileSafe(join34(dir, "package.json"));
|
|
7327
|
+
if (contents !== null) {
|
|
7328
|
+
try {
|
|
7329
|
+
const { version } = JSON.parse(contents);
|
|
7330
|
+
return typeof version === "string" && version.length > 0 ? version : void 0;
|
|
7331
|
+
} catch {
|
|
7332
|
+
return void 0;
|
|
7333
|
+
}
|
|
7334
|
+
}
|
|
7335
|
+
const parent = dirname7(dir);
|
|
7336
|
+
if (parent === dir) {
|
|
7337
|
+
return void 0;
|
|
7338
|
+
}
|
|
7339
|
+
dir = parent;
|
|
7340
|
+
}
|
|
7341
|
+
}
|
|
7342
|
+
function getCliVersion(metaUrl = import.meta.url) {
|
|
7343
|
+
const startDir = dirname7(fileURLToPath(metaUrl));
|
|
7344
|
+
const cached = versionCache.get(startDir);
|
|
7345
|
+
if (cached !== void 0) {
|
|
7346
|
+
return cached;
|
|
7347
|
+
}
|
|
7348
|
+
const version = readPackageVersion(startDir) ?? FALLBACK_VERSION;
|
|
7349
|
+
versionCache.set(startDir, version);
|
|
7350
|
+
return version;
|
|
7351
|
+
}
|
|
7352
|
+
|
|
7353
|
+
// src/services/parse-cache.ts
|
|
7354
|
+
var CACHE_FORMAT_VERSION = 1;
|
|
7355
|
+
var SETTLE_MS = 5e3;
|
|
7356
|
+
function getParseCacheDir() {
|
|
7357
|
+
return join35(getStateDir(), "parse-cache");
|
|
7358
|
+
}
|
|
7359
|
+
function getParseCachePath(toolId) {
|
|
7360
|
+
return join35(getParseCacheDir(), `${toolId}.json`);
|
|
7361
|
+
}
|
|
7362
|
+
function computeScanFingerprint(files, now = Date.now()) {
|
|
7363
|
+
const hash = createHash7("sha256");
|
|
7364
|
+
hash.update(`v${CACHE_FORMAT_VERSION}\0`);
|
|
7365
|
+
hash.update(`${getCliVersion()}\0`);
|
|
7366
|
+
hash.update(`${hostname6()}\0`);
|
|
7367
|
+
for (const file of [...files].sort()) {
|
|
7368
|
+
let stats;
|
|
7369
|
+
try {
|
|
7370
|
+
stats = statSync6(file);
|
|
7371
|
+
} catch {
|
|
7372
|
+
return null;
|
|
7373
|
+
}
|
|
7374
|
+
if (now - stats.mtimeMs < SETTLE_MS) {
|
|
7375
|
+
return null;
|
|
7376
|
+
}
|
|
7377
|
+
hash.update(`${file}\0${stats.mtimeMs}\0${stats.size}\0`);
|
|
7378
|
+
}
|
|
7379
|
+
return hash.digest("hex");
|
|
7380
|
+
}
|
|
7381
|
+
function loadCachedParseResult(toolId, fingerprint2) {
|
|
7382
|
+
if (!fingerprint2) {
|
|
7383
|
+
return null;
|
|
7384
|
+
}
|
|
7385
|
+
try {
|
|
7386
|
+
const envelope = JSON.parse(
|
|
7387
|
+
readFileSync14(getParseCachePath(toolId), "utf-8")
|
|
7388
|
+
);
|
|
7389
|
+
if (envelope.formatVersion !== CACHE_FORMAT_VERSION || envelope.fingerprint !== fingerprint2 || !Array.isArray(envelope.result?.buckets) || !Array.isArray(envelope.result?.sessions)) {
|
|
7390
|
+
return null;
|
|
7391
|
+
}
|
|
7392
|
+
return {
|
|
7393
|
+
buckets: envelope.result.buckets,
|
|
7394
|
+
sessions: envelope.result.sessions
|
|
7395
|
+
};
|
|
7396
|
+
} catch {
|
|
7397
|
+
return null;
|
|
7398
|
+
}
|
|
7399
|
+
}
|
|
7400
|
+
function saveCachedParseResult(toolId, fingerprint2, result) {
|
|
7401
|
+
if (!fingerprint2 || result.incomplete) {
|
|
7402
|
+
return;
|
|
7403
|
+
}
|
|
7404
|
+
const envelope = {
|
|
7405
|
+
formatVersion: CACHE_FORMAT_VERSION,
|
|
7406
|
+
fingerprint: fingerprint2,
|
|
7407
|
+
result: { buckets: result.buckets, sessions: result.sessions }
|
|
7408
|
+
};
|
|
7409
|
+
try {
|
|
7410
|
+
mkdirSync3(getParseCacheDir(), { recursive: true });
|
|
7411
|
+
writeFileSync5(getParseCachePath(toolId), JSON.stringify(envelope), "utf-8");
|
|
7412
|
+
} catch {
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
|
|
7296
7416
|
// src/services/parser-service.ts
|
|
7417
|
+
var PARSER_CONCURRENCY = 8;
|
|
7418
|
+
async function parseWithCache(parser) {
|
|
7419
|
+
try {
|
|
7420
|
+
const files = parser.listSourceFiles?.();
|
|
7421
|
+
const fingerprint2 = files ? computeScanFingerprint(files) : null;
|
|
7422
|
+
const cached = loadCachedParseResult(parser.tool.id, fingerprint2);
|
|
7423
|
+
if (cached) {
|
|
7424
|
+
return { status: "ok", result: cached, cached: true };
|
|
7425
|
+
}
|
|
7426
|
+
const result = await parser.parse();
|
|
7427
|
+
saveCachedParseResult(parser.tool.id, fingerprint2, result);
|
|
7428
|
+
return { status: "ok", result, cached: false };
|
|
7429
|
+
} catch (err) {
|
|
7430
|
+
return {
|
|
7431
|
+
status: "failed",
|
|
7432
|
+
message: err instanceof Error ? err.message : String(err)
|
|
7433
|
+
};
|
|
7434
|
+
}
|
|
7435
|
+
}
|
|
7436
|
+
async function mapWithConcurrency(items, limit, run2) {
|
|
7437
|
+
const results = new Array(items.length);
|
|
7438
|
+
let cursor = 0;
|
|
7439
|
+
async function worker() {
|
|
7440
|
+
while (cursor < items.length) {
|
|
7441
|
+
const index = cursor++;
|
|
7442
|
+
results[index] = await run2(items[index]);
|
|
7443
|
+
}
|
|
7444
|
+
}
|
|
7445
|
+
await Promise.all(
|
|
7446
|
+
Array.from({ length: Math.min(limit, items.length) }, () => worker())
|
|
7447
|
+
);
|
|
7448
|
+
return results;
|
|
7449
|
+
}
|
|
7297
7450
|
async function runAllParsers() {
|
|
7298
7451
|
const allBuckets = [];
|
|
7299
7452
|
const allSessions = [];
|
|
7300
7453
|
const parserResults = [];
|
|
7301
7454
|
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) {
|
|
7455
|
+
const parsers2 = getAllParsers();
|
|
7456
|
+
const settled = await mapWithConcurrency(
|
|
7457
|
+
parsers2,
|
|
7458
|
+
PARSER_CONCURRENCY,
|
|
7459
|
+
parseWithCache
|
|
7460
|
+
);
|
|
7461
|
+
for (const [index, parser] of parsers2.entries()) {
|
|
7462
|
+
const outcome = settled[index];
|
|
7463
|
+
if (outcome.status === "failed") {
|
|
7464
|
+
failedSources.add(parser.tool.id);
|
|
7465
|
+
logger.warn(`${parser.tool.id} parser failed: ${outcome.message}`);
|
|
7466
|
+
continue;
|
|
7467
|
+
}
|
|
7468
|
+
const { buckets, sessions, incomplete } = outcome.result;
|
|
7469
|
+
if (incomplete) {
|
|
7324
7470
|
failedSources.add(parser.tool.id);
|
|
7325
7471
|
logger.warn(
|
|
7326
|
-
`${parser.tool.id} parser
|
|
7472
|
+
`${parser.tool.id} parser reported an incomplete scan; preserving its remote history.`
|
|
7327
7473
|
);
|
|
7474
|
+
continue;
|
|
7475
|
+
}
|
|
7476
|
+
if (buckets.length > 0) allBuckets.push(...buckets);
|
|
7477
|
+
if (sessions.length > 0) allSessions.push(...sessions);
|
|
7478
|
+
if (buckets.length > 0 || sessions.length > 0) {
|
|
7479
|
+
parserResults.push({
|
|
7480
|
+
source: parser.tool.id,
|
|
7481
|
+
buckets: buckets.length,
|
|
7482
|
+
sessions: sessions.length,
|
|
7483
|
+
...outcome.cached ? { cached: true } : {}
|
|
7484
|
+
});
|
|
7328
7485
|
}
|
|
7329
7486
|
}
|
|
7330
7487
|
return {
|
|
@@ -7399,17 +7556,31 @@ function persistUploadManifest(manifest, quiet) {
|
|
|
7399
7556
|
function toDeviceMetadata(config) {
|
|
7400
7557
|
return {
|
|
7401
7558
|
deviceId: getOrCreateDeviceId(config),
|
|
7402
|
-
hostname:
|
|
7559
|
+
hostname: hostname7().replace(/\.local$/, "")
|
|
7403
7560
|
};
|
|
7404
7561
|
}
|
|
7405
|
-
function
|
|
7562
|
+
function createProjectIdentityResolver(settings) {
|
|
7563
|
+
const identities = /* @__PURE__ */ new Map();
|
|
7564
|
+
return (project) => {
|
|
7565
|
+
const name = project || "unknown";
|
|
7566
|
+
let identity = identities.get(name);
|
|
7567
|
+
if (!identity) {
|
|
7568
|
+
identity = toProjectIdentity({
|
|
7569
|
+
project: name,
|
|
7570
|
+
mode: settings.projectMode,
|
|
7571
|
+
salt: settings.projectHashSalt
|
|
7572
|
+
});
|
|
7573
|
+
identities.set(name, identity);
|
|
7574
|
+
}
|
|
7575
|
+
return identity;
|
|
7576
|
+
};
|
|
7577
|
+
}
|
|
7578
|
+
function toUploadBuckets(buckets, settings, device, resolveProject = createProjectIdentityResolver(
|
|
7579
|
+
settings
|
|
7580
|
+
)) {
|
|
7406
7581
|
const aggregated = /* @__PURE__ */ new Map();
|
|
7407
7582
|
for (const bucket of buckets) {
|
|
7408
|
-
const project =
|
|
7409
|
-
project: bucket.project || "unknown",
|
|
7410
|
-
mode: settings.projectMode,
|
|
7411
|
-
salt: settings.projectHashSalt
|
|
7412
|
-
});
|
|
7583
|
+
const project = resolveProject(bucket.project);
|
|
7413
7584
|
const key = [
|
|
7414
7585
|
bucket.source,
|
|
7415
7586
|
bucket.model,
|
|
@@ -7445,13 +7616,11 @@ function toUploadBuckets(buckets, settings, device) {
|
|
|
7445
7616
|
}
|
|
7446
7617
|
return Array.from(aggregated.values());
|
|
7447
7618
|
}
|
|
7448
|
-
function toUploadSessions(sessions, settings, device
|
|
7619
|
+
function toUploadSessions(sessions, settings, device, resolveProject = createProjectIdentityResolver(
|
|
7620
|
+
settings
|
|
7621
|
+
)) {
|
|
7449
7622
|
return sessions.map((session) => {
|
|
7450
|
-
const project =
|
|
7451
|
-
project: session.project || "unknown",
|
|
7452
|
-
mode: settings.projectMode,
|
|
7453
|
-
salt: settings.projectHashSalt
|
|
7454
|
-
});
|
|
7623
|
+
const project = resolveProject(session.project);
|
|
7455
7624
|
return {
|
|
7456
7625
|
source: session.source,
|
|
7457
7626
|
projectKey: project.projectKey,
|
|
@@ -7598,7 +7767,8 @@ async function runSync(config, opts = {}) {
|
|
|
7598
7767
|
const parts = [];
|
|
7599
7768
|
if (p.buckets > 0) parts.push(`${p.buckets} buckets`);
|
|
7600
7769
|
if (p.sessions > 0) parts.push(`${p.sessions} sessions`);
|
|
7601
|
-
|
|
7770
|
+
const suffix = p.cached ? " (unchanged)" : "";
|
|
7771
|
+
logger.info(` ${p.source}: ${parts.join(", ")}${suffix}`);
|
|
7602
7772
|
}
|
|
7603
7773
|
}
|
|
7604
7774
|
const apiUrl = config.apiUrl || "https://token.guji.uno";
|
|
@@ -7629,8 +7799,19 @@ async function runSync(config, opts = {}) {
|
|
|
7629
7799
|
deviceId: device.deviceId,
|
|
7630
7800
|
settings
|
|
7631
7801
|
});
|
|
7632
|
-
const
|
|
7633
|
-
const
|
|
7802
|
+
const resolveProject = createProjectIdentityResolver(settings);
|
|
7803
|
+
const uploadBuckets = toUploadBuckets(
|
|
7804
|
+
allBuckets,
|
|
7805
|
+
settings,
|
|
7806
|
+
device,
|
|
7807
|
+
resolveProject
|
|
7808
|
+
);
|
|
7809
|
+
const uploadSessions = toUploadSessions(
|
|
7810
|
+
allSessions,
|
|
7811
|
+
settings,
|
|
7812
|
+
device,
|
|
7813
|
+
resolveProject
|
|
7814
|
+
);
|
|
7634
7815
|
const previousManifest = loadUploadManifest();
|
|
7635
7816
|
const uploadDiff = diffUploadManifest({
|
|
7636
7817
|
buckets: uploadBuckets,
|
|
@@ -7683,7 +7864,9 @@ async function runSync(config, opts = {}) {
|
|
|
7683
7864
|
skippedParts.length > 0 ? `No new or updated usage data to upload. Skipped ${skippedParts.join(" + ")}.` : "No new or updated usage data to upload."
|
|
7684
7865
|
);
|
|
7685
7866
|
}
|
|
7686
|
-
|
|
7867
|
+
if (uploadDiff.removedBuckets > 0 || uploadDiff.removedSessions > 0) {
|
|
7868
|
+
persistUploadManifest(uploadDiff.nextManifest, quiet);
|
|
7869
|
+
}
|
|
7687
7870
|
markSyncSucceeded(source, { buckets: 0, sessions: 0 });
|
|
7688
7871
|
return { buckets: 0, sessions: 0 };
|
|
7689
7872
|
}
|
|
@@ -7850,14 +8033,14 @@ import { execFileSync as execFileSync7, spawn } from "child_process";
|
|
|
7850
8033
|
import { existsSync as existsSync36 } from "fs";
|
|
7851
8034
|
import { appendFile, mkdir, readFile } from "fs/promises";
|
|
7852
8035
|
import { homedir as homedir33, platform as platform5 } from "os";
|
|
7853
|
-
import { dirname as
|
|
8036
|
+
import { dirname as dirname8, join as join36, posix as posix3, win32 } from "path";
|
|
7854
8037
|
|
|
7855
8038
|
// src/infrastructure/service/index.ts
|
|
7856
8039
|
import { platform as platform4 } from "os";
|
|
7857
8040
|
|
|
7858
8041
|
// src/infrastructure/service/linux-systemd.ts
|
|
7859
8042
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
7860
|
-
import { existsSync as existsSync34, mkdirSync as
|
|
8043
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync4, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
7861
8044
|
import { homedir as homedir31, platform as platform2 } from "os";
|
|
7862
8045
|
import { posix } from "path";
|
|
7863
8046
|
|
|
@@ -8019,8 +8202,8 @@ function createLinuxSystemdServiceBackend() {
|
|
|
8019
8202
|
execPath: command.execPath,
|
|
8020
8203
|
args: command.args
|
|
8021
8204
|
});
|
|
8022
|
-
|
|
8023
|
-
|
|
8205
|
+
mkdirSync4(serviceDir, { recursive: true });
|
|
8206
|
+
writeFileSync6(serviceFile, content, "utf-8");
|
|
8024
8207
|
execSystemctl(["daemon-reload"]);
|
|
8025
8208
|
execSystemctl(["enable", SYSTEMD_SERVICE_NAME]);
|
|
8026
8209
|
execSystemctl(["start", SYSTEMD_SERVICE_NAME]);
|
|
@@ -8179,7 +8362,7 @@ function createLinuxSystemdServiceBackend() {
|
|
|
8179
8362
|
|
|
8180
8363
|
// src/infrastructure/service/macos-launchd.ts
|
|
8181
8364
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
8182
|
-
import { existsSync as existsSync35, mkdirSync as
|
|
8365
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync5, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
8183
8366
|
import { homedir as homedir32, platform as platform3 } from "os";
|
|
8184
8367
|
import { posix as posix2 } from "path";
|
|
8185
8368
|
var MACOS_LAUNCHD_LABEL = "com.guji.tokenarena";
|
|
@@ -8321,8 +8504,8 @@ function writeLaunchAgentPlist() {
|
|
|
8321
8504
|
standardErrorPath: stderrPath
|
|
8322
8505
|
});
|
|
8323
8506
|
ensureAppDirs();
|
|
8324
|
-
|
|
8325
|
-
|
|
8507
|
+
mkdirSync5(getMacosLaunchAgentDir(), { recursive: true });
|
|
8508
|
+
writeFileSync7(plistFile, plist, "utf-8");
|
|
8326
8509
|
return plistFile;
|
|
8327
8510
|
}
|
|
8328
8511
|
function bootstrapLaunchAgent() {
|
|
@@ -8593,7 +8776,7 @@ function resolvePowerShellProfilePath() {
|
|
|
8593
8776
|
const systemRoot = process.env.SYSTEMROOT || "C:\\Windows";
|
|
8594
8777
|
const candidates = [
|
|
8595
8778
|
"pwsh.exe",
|
|
8596
|
-
|
|
8779
|
+
join36(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
8597
8780
|
];
|
|
8598
8781
|
for (const command of candidates) {
|
|
8599
8782
|
try {
|
|
@@ -8818,7 +9001,7 @@ async function setupShellAlias() {
|
|
|
8818
9001
|
return;
|
|
8819
9002
|
}
|
|
8820
9003
|
try {
|
|
8821
|
-
await mkdir(
|
|
9004
|
+
await mkdir(dirname8(setup.configFile), { recursive: true });
|
|
8822
9005
|
let existingContent = "";
|
|
8823
9006
|
if (existsSync36(setup.configFile)) {
|
|
8824
9007
|
existingContent = await readFile(setup.configFile, "utf-8");
|
|
@@ -9083,41 +9266,6 @@ function buildLocalUsageDashboardData(input2) {
|
|
|
9083
9266
|
};
|
|
9084
9267
|
}
|
|
9085
9268
|
|
|
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
9269
|
// src/infrastructure/ui/local-usage-dashboard.ts
|
|
9122
9270
|
var MAX_RANK_ROWS = 6;
|
|
9123
9271
|
var MAX_SESSION_ROWS = 6;
|
|
@@ -9516,7 +9664,7 @@ async function runSyncCommand(opts = {}) {
|
|
|
9516
9664
|
}
|
|
9517
9665
|
|
|
9518
9666
|
// src/commands/uninstall.ts
|
|
9519
|
-
import { existsSync as existsSync37, readFileSync as
|
|
9667
|
+
import { existsSync as existsSync37, readFileSync as readFileSync15, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
9520
9668
|
import { homedir as homedir34, platform as platform6 } from "os";
|
|
9521
9669
|
function removeShellAlias() {
|
|
9522
9670
|
const shell = process.env.SHELL;
|
|
@@ -9543,7 +9691,7 @@ function removeShellAlias() {
|
|
|
9543
9691
|
}
|
|
9544
9692
|
if (!existsSync37(configFile)) return;
|
|
9545
9693
|
try {
|
|
9546
|
-
let content =
|
|
9694
|
+
let content = readFileSync15(configFile, "utf-8");
|
|
9547
9695
|
const aliasPatterns = [
|
|
9548
9696
|
// zsh / bash format: alias ta="tokenarena"
|
|
9549
9697
|
new RegExp(
|
|
@@ -9565,7 +9713,7 @@ function removeShellAlias() {
|
|
|
9565
9713
|
content = next;
|
|
9566
9714
|
}
|
|
9567
9715
|
}
|
|
9568
|
-
|
|
9716
|
+
writeFileSync8(configFile, content, "utf-8");
|
|
9569
9717
|
logger.info(`Removed shell alias from ${configFile}`);
|
|
9570
9718
|
} catch (err) {
|
|
9571
9719
|
logger.warn(
|