@tokz/cli 0.2.10 → 0.2.12
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/{Root-ZJO6F6LM.js → Root-FWMJ2TO2.js} +142 -53
- package/dist/cli.js +1 -1
- package/package.json +1 -1
|
@@ -206,6 +206,11 @@ async function loadProjects(home = homedir(), onProgress) {
|
|
|
206
206
|
|
|
207
207
|
// src/agents/usage.ts
|
|
208
208
|
import { readFile as readFile2 } from "fs/promises";
|
|
209
|
+
function recordDedupKey(r) {
|
|
210
|
+
const scope = r.id ?? r.ts;
|
|
211
|
+
if (!scope) return void 0;
|
|
212
|
+
return `${scope}|${r.model}|${r.input}|${r.output}|${r.cacheRead}|${r.cacheWrite}`;
|
|
213
|
+
}
|
|
209
214
|
async function readJson(file) {
|
|
210
215
|
try {
|
|
211
216
|
return JSON.parse(await readFile2(file, "utf8"));
|
|
@@ -230,10 +235,17 @@ async function readJsonl(file) {
|
|
|
230
235
|
}
|
|
231
236
|
return out;
|
|
232
237
|
}
|
|
233
|
-
function sessionFromRecords(file, cwd, records) {
|
|
238
|
+
function sessionFromRecords(file, cwd, records, seen) {
|
|
234
239
|
const stats = { file, cwd, usageByModel: {}, toolCalls: {}, toolCostUsd: {}, dailyUsage: {} };
|
|
235
240
|
for (const r of records) {
|
|
236
241
|
if (r.input + r.output + r.cacheRead + r.cacheWrite === 0) continue;
|
|
242
|
+
if (seen) {
|
|
243
|
+
const key = recordDedupKey(r);
|
|
244
|
+
if (key !== void 0) {
|
|
245
|
+
if (seen.has(key)) continue;
|
|
246
|
+
seen.add(key);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
237
249
|
if (r.ts) {
|
|
238
250
|
if (!stats.firstTs || r.ts < stats.firstTs) stats.firstTs = r.ts;
|
|
239
251
|
if (!stats.lastTs || r.ts > stats.lastTs) stats.lastTs = r.ts;
|
|
@@ -558,7 +570,7 @@ function isAssistant(msg) {
|
|
|
558
570
|
const role = str(msg, "variant") ?? str(msg, "role");
|
|
559
571
|
return role === "ai" || role === "agent" || role === "assistant";
|
|
560
572
|
}
|
|
561
|
-
async function parseFile(file) {
|
|
573
|
+
async function parseFile(file, seen) {
|
|
562
574
|
const arr = await readJson(file);
|
|
563
575
|
if (!Array.isArray(arr)) return sessionFromRecords(file, void 0, []);
|
|
564
576
|
let fileTs;
|
|
@@ -575,6 +587,7 @@ async function parseFile(file) {
|
|
|
575
587
|
records.push({
|
|
576
588
|
model: str(meta, "model") ?? "codebuff-unknown",
|
|
577
589
|
ts: str(msg, "timestamp") ?? fileTs,
|
|
590
|
+
id: str(msg, "id") ?? str(msg, "messageId") ?? str(msg, "message_id"),
|
|
578
591
|
input: pickNum(usage, ["inputTokens", "input_tokens"]),
|
|
579
592
|
output: pickNum(usage, ["outputTokens", "output_tokens"]),
|
|
580
593
|
cacheRead: pickNum(usage, ["cacheReadInputTokens", "cache_read_input_tokens", "cachedTokens"]),
|
|
@@ -591,10 +604,11 @@ async function loadCodebuffProjects(home, onProgress) {
|
|
|
591
604
|
);
|
|
592
605
|
}
|
|
593
606
|
const sessions = [];
|
|
607
|
+
const seen = /* @__PURE__ */ new Set();
|
|
594
608
|
let parsed = 0;
|
|
595
609
|
for (const f of files) {
|
|
596
610
|
onProgress?.({ parsed, total: files.length, currentProject: "Codebuff chats" });
|
|
597
|
-
sessions.push(await parseFile(f));
|
|
611
|
+
sessions.push(await parseFile(f, seen));
|
|
598
612
|
parsed += 1;
|
|
599
613
|
onProgress?.({ parsed, total: files.length, currentProject: "Codebuff chats" });
|
|
600
614
|
}
|
|
@@ -618,9 +632,7 @@ var codebuffAdapter = {
|
|
|
618
632
|
};
|
|
619
633
|
|
|
620
634
|
// src/agents/codex.ts
|
|
621
|
-
import {
|
|
622
|
-
import { access as access5 } from "fs/promises";
|
|
623
|
-
import { createInterface } from "readline";
|
|
635
|
+
import { access as access5, readFile as readFile4 } from "fs/promises";
|
|
624
636
|
import { homedir as homedir6 } from "os";
|
|
625
637
|
import { join as join6 } from "path";
|
|
626
638
|
import { glob as glob4 } from "tinyglobby";
|
|
@@ -642,7 +654,12 @@ var Line = z.object({
|
|
|
642
654
|
cwd: z.string().optional(),
|
|
643
655
|
model: z.string().optional(),
|
|
644
656
|
name: z.string().optional(),
|
|
645
|
-
info: z.object({
|
|
657
|
+
info: z.object({
|
|
658
|
+
total_token_usage: TokenTotals.optional(),
|
|
659
|
+
// Codex writes the per-turn amount here directly; prefer it over
|
|
660
|
+
// differencing cumulative totals.
|
|
661
|
+
last_token_usage: TokenTotals.optional()
|
|
662
|
+
}).nullish()
|
|
646
663
|
}).passthrough().optional()
|
|
647
664
|
});
|
|
648
665
|
function codexHome(home) {
|
|
@@ -650,13 +667,27 @@ function codexHome(home) {
|
|
|
650
667
|
return process.env.CODEX_HOME ?? join6(homedir6(), ".codex");
|
|
651
668
|
}
|
|
652
669
|
var DEFAULT_MODEL = "gpt-5";
|
|
653
|
-
|
|
670
|
+
function tsSecond(ts) {
|
|
671
|
+
return (ts ?? "").slice(0, 19);
|
|
672
|
+
}
|
|
673
|
+
function replayBurstSecond(content, lines) {
|
|
674
|
+
const head = content.slice(0, 16384);
|
|
675
|
+
if (!head.includes("thread_spawn") && !head.includes("forked_from_id")) return void 0;
|
|
676
|
+
let first;
|
|
677
|
+
for (const p of lines) {
|
|
678
|
+
const info = p.payload?.type === "token_count" ? p.payload.info : void 0;
|
|
679
|
+
if (!info?.last_token_usage && !info?.total_token_usage) continue;
|
|
680
|
+
const sec = tsSecond(p.timestamp);
|
|
681
|
+
if (first === void 0) first = sec;
|
|
682
|
+
else return first === sec ? first : void 0;
|
|
683
|
+
}
|
|
684
|
+
return void 0;
|
|
685
|
+
}
|
|
686
|
+
async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
654
687
|
const stats = { file, usageByModel: {}, toolCalls: {}, toolCostUsd: {}, dailyUsage: {} };
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
let turnTools = [];
|
|
659
|
-
for await (const raw of rl) {
|
|
688
|
+
const content = await readFile4(file, "utf8").catch(() => "");
|
|
689
|
+
const lines = [];
|
|
690
|
+
for (const raw of content.split("\n")) {
|
|
660
691
|
if (!raw.trim()) continue;
|
|
661
692
|
let obj;
|
|
662
693
|
try {
|
|
@@ -665,33 +696,79 @@ async function parseCodexRollout(file) {
|
|
|
665
696
|
continue;
|
|
666
697
|
}
|
|
667
698
|
const parsed = Line.safeParse(obj);
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
|
|
699
|
+
if (parsed.success) lines.push(parsed.data);
|
|
700
|
+
}
|
|
701
|
+
const burstSecond = replayBurstSecond(content, lines);
|
|
702
|
+
let skippingReplay = burstSecond !== void 0;
|
|
703
|
+
let model = DEFAULT_MODEL;
|
|
704
|
+
let prev = { input: 0, cached: 0, output: 0, total: 0 };
|
|
705
|
+
let turnTools = [];
|
|
706
|
+
for (const parsed of lines) {
|
|
707
|
+
const { timestamp, type, payload: payload2 } = parsed;
|
|
708
|
+
if (!stats.cwd) stats.cwd = payload2?.cwd ?? parsed.cwd;
|
|
671
709
|
if (payload2?.model) model = payload2.model;
|
|
672
710
|
if (timestamp) {
|
|
673
711
|
if (!stats.firstTs) stats.firstTs = timestamp;
|
|
674
712
|
stats.lastTs = timestamp;
|
|
675
713
|
}
|
|
676
|
-
const toolName = payload2?.type === "function_call" || payload2?.type === "custom_tool_call" ? payload2.name : payload2?.type === "local_shell_call" ? "shell" : type === "function_call" ? parsed.
|
|
714
|
+
const toolName = payload2?.type === "function_call" || payload2?.type === "custom_tool_call" ? payload2.name : payload2?.type === "local_shell_call" ? "shell" : type === "function_call" ? parsed.name : void 0;
|
|
677
715
|
if (toolName) {
|
|
678
716
|
stats.toolCalls[toolName] = (stats.toolCalls[toolName] ?? 0) + 1;
|
|
679
717
|
turnTools.push(toolName);
|
|
680
718
|
}
|
|
681
|
-
const
|
|
682
|
-
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
719
|
+
const info = payload2?.type === "token_count" ? payload2.info : void 0;
|
|
720
|
+
const last = info?.last_token_usage;
|
|
721
|
+
const totals = info?.total_token_usage;
|
|
722
|
+
if (!last && !totals) continue;
|
|
723
|
+
if (skippingReplay && tsSecond(timestamp) === burstSecond) {
|
|
724
|
+
if (totals) {
|
|
725
|
+
prev = {
|
|
726
|
+
input: totals.input_tokens,
|
|
727
|
+
cached: totals.cached_input_tokens,
|
|
728
|
+
output: totals.output_tokens,
|
|
729
|
+
total: totals.total_tokens
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
turnTools = [];
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
skippingReplay = false;
|
|
736
|
+
const idTotals = last ?? totals;
|
|
737
|
+
const dedupKey = `${timestamp ?? ""}|${model}|${idTotals.input_tokens}|${idTotals.cached_input_tokens}|${idTotals.output_tokens}|${idTotals.reasoning_output_tokens}|${idTotals.total_tokens}`;
|
|
738
|
+
let dInput;
|
|
739
|
+
let dCached;
|
|
740
|
+
let dOutput;
|
|
741
|
+
if (last) {
|
|
742
|
+
dInput = last.input_tokens;
|
|
743
|
+
dCached = last.cached_input_tokens;
|
|
744
|
+
dOutput = last.output_tokens;
|
|
745
|
+
if (totals) {
|
|
746
|
+
prev = {
|
|
747
|
+
input: totals.input_tokens,
|
|
748
|
+
cached: totals.cached_input_tokens,
|
|
749
|
+
output: totals.output_tokens,
|
|
750
|
+
total: totals.total_tokens
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
} else {
|
|
754
|
+
const cur = {
|
|
755
|
+
input: totals.input_tokens,
|
|
756
|
+
cached: totals.cached_input_tokens,
|
|
757
|
+
output: totals.output_tokens,
|
|
758
|
+
total: totals.total_tokens
|
|
759
|
+
};
|
|
760
|
+
if (cur.total < prev.total) prev = { input: 0, cached: 0, output: 0, total: 0 };
|
|
761
|
+
dInput = Math.max(0, cur.input - prev.input);
|
|
762
|
+
dCached = Math.max(0, cur.cached - prev.cached);
|
|
763
|
+
dOutput = Math.max(0, cur.output - prev.output);
|
|
764
|
+
prev = cur;
|
|
765
|
+
}
|
|
694
766
|
if (dInput + dOutput === 0) continue;
|
|
767
|
+
if (seen.has(dedupKey)) {
|
|
768
|
+
turnTools = [];
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
seen.add(dedupKey);
|
|
695
772
|
const delta = {
|
|
696
773
|
// Codex's input_tokens INCLUDES cached tokens; split them out.
|
|
697
774
|
inputTokens: Math.max(0, dInput - dCached),
|
|
@@ -730,10 +807,11 @@ async function loadCodexProjects(home, onProgress) {
|
|
|
730
807
|
}).catch(() => []);
|
|
731
808
|
if (files.length === 0) return [];
|
|
732
809
|
const sessions = [];
|
|
810
|
+
const seen = /* @__PURE__ */ new Set();
|
|
733
811
|
let parsed = 0;
|
|
734
812
|
for (const f of files) {
|
|
735
813
|
onProgress?.({ parsed, total: files.length, currentProject: "Codex sessions" });
|
|
736
|
-
sessions.push(await parseCodexRollout(f));
|
|
814
|
+
sessions.push(await parseCodexRollout(f, seen));
|
|
737
815
|
parsed += 1;
|
|
738
816
|
onProgress?.({ parsed, total: files.length, currentProject: "Codex sessions" });
|
|
739
817
|
}
|
|
@@ -791,9 +869,8 @@ function attrStr(attrs, keys) {
|
|
|
791
869
|
}
|
|
792
870
|
return void 0;
|
|
793
871
|
}
|
|
794
|
-
function parseOtelFile(records) {
|
|
872
|
+
function parseOtelFile(records, seen = /* @__PURE__ */ new Set()) {
|
|
795
873
|
const bySession = /* @__PURE__ */ new Map();
|
|
796
|
-
const seen = /* @__PURE__ */ new Set();
|
|
797
874
|
for (const rec of records) {
|
|
798
875
|
const attrs = rec.attributes;
|
|
799
876
|
if (!attrs || typeof attrs !== "object") continue;
|
|
@@ -824,10 +901,11 @@ function parseOtelFile(records) {
|
|
|
824
901
|
async function loadCopilotProjects(home, onProgress) {
|
|
825
902
|
const files = await glob5(["**/*.jsonl"], { cwd: copilotDir(home), absolute: true }).catch(() => []);
|
|
826
903
|
const bySession = /* @__PURE__ */ new Map();
|
|
904
|
+
const seen = /* @__PURE__ */ new Set();
|
|
827
905
|
let parsed = 0;
|
|
828
906
|
for (const f of files) {
|
|
829
907
|
onProgress?.({ parsed, total: files.length, currentProject: "Copilot otel" });
|
|
830
|
-
for (const [session, records] of parseOtelFile(await readJsonl(f))) {
|
|
908
|
+
for (const [session, records] of parseOtelFile(await readJsonl(f), seen)) {
|
|
831
909
|
const list = bySession.get(session) ?? [];
|
|
832
910
|
list.push(...records);
|
|
833
911
|
bySession.set(session, list);
|
|
@@ -928,13 +1006,14 @@ function recordFrom(node, model, ts) {
|
|
|
928
1006
|
return {
|
|
929
1007
|
model: str(node, "model") ?? model ?? "gemini-unknown",
|
|
930
1008
|
ts: str(node, "timestamp") ?? ts,
|
|
1009
|
+
id: str(node, "id") ?? str(node, "messageId") ?? str(node, "message_id") ?? str(node, "responseId"),
|
|
931
1010
|
input: pickNum(tokens, IN),
|
|
932
1011
|
output: pickNum(tokens, OUT) + reasoning,
|
|
933
1012
|
cacheRead: pickNum(tokens, ["cached", "cached_tokens"]),
|
|
934
1013
|
cacheWrite: 0
|
|
935
1014
|
};
|
|
936
1015
|
}
|
|
937
|
-
async function parseFile3(file) {
|
|
1016
|
+
async function parseFile3(file, seen) {
|
|
938
1017
|
const records = [];
|
|
939
1018
|
const push = (r) => r && records.push(r);
|
|
940
1019
|
if (file.endsWith(".jsonl")) {
|
|
@@ -946,17 +1025,18 @@ async function parseFile3(file) {
|
|
|
946
1025
|
if (Array.isArray(messages)) for (const m of messages) push(recordFrom(m, model, void 0));
|
|
947
1026
|
push(recordFrom(doc, model, void 0));
|
|
948
1027
|
}
|
|
949
|
-
return sessionFromRecords(file, void 0, records);
|
|
1028
|
+
return sessionFromRecords(file, void 0, records, seen);
|
|
950
1029
|
}
|
|
951
1030
|
async function loadGeminiProjects(home, onProgress) {
|
|
952
1031
|
const files = await glob7(["**/*.json", "**/*.jsonl"], { cwd: geminiRoot(home), absolute: true }).catch(
|
|
953
1032
|
() => []
|
|
954
1033
|
);
|
|
955
1034
|
const sessions = [];
|
|
1035
|
+
const seen = /* @__PURE__ */ new Set();
|
|
956
1036
|
let parsed = 0;
|
|
957
1037
|
for (const f of files) {
|
|
958
1038
|
onProgress?.({ parsed, total: files.length, currentProject: "Gemini logs" });
|
|
959
|
-
sessions.push(await parseFile3(f));
|
|
1039
|
+
sessions.push(await parseFile3(f, seen));
|
|
960
1040
|
parsed += 1;
|
|
961
1041
|
onProgress?.({ parsed, total: files.length, currentProject: "Gemini logs" });
|
|
962
1042
|
}
|
|
@@ -983,7 +1063,7 @@ import { homedir as homedir10 } from "os";
|
|
|
983
1063
|
import { join as join10 } from "path";
|
|
984
1064
|
|
|
985
1065
|
// src/sqlite.ts
|
|
986
|
-
import { readFile as
|
|
1066
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
987
1067
|
function u8(b, o) {
|
|
988
1068
|
return b[o];
|
|
989
1069
|
}
|
|
@@ -1123,7 +1203,7 @@ function columnNames(sql) {
|
|
|
1123
1203
|
async function readTable(file, table) {
|
|
1124
1204
|
let buf;
|
|
1125
1205
|
try {
|
|
1126
|
-
buf = await
|
|
1206
|
+
buf = await readFile5(file);
|
|
1127
1207
|
} catch {
|
|
1128
1208
|
return [];
|
|
1129
1209
|
}
|
|
@@ -1325,21 +1405,23 @@ function kimiRoots(home) {
|
|
|
1325
1405
|
const h = home ?? homedir13();
|
|
1326
1406
|
return KIMI_DIRS.map((d) => join13(h, d));
|
|
1327
1407
|
}
|
|
1328
|
-
async function parseFile4(file) {
|
|
1408
|
+
async function parseFile4(file, seen) {
|
|
1329
1409
|
const records = [];
|
|
1330
1410
|
for (const line of await readJsonl(file)) {
|
|
1331
1411
|
const usage = deepFind(line, USAGE_KEYS);
|
|
1332
1412
|
if (!usage) continue;
|
|
1413
|
+
const idHost = deepFind(line, ["messageId", "message_id", "id"]);
|
|
1333
1414
|
records.push({
|
|
1334
1415
|
model: str(line, "model") ?? "kimi-unknown",
|
|
1335
1416
|
ts: str(line, "timestamp"),
|
|
1417
|
+
id: idHost && (str(idHost, "messageId") ?? str(idHost, "message_id") ?? str(idHost, "id")),
|
|
1336
1418
|
input: pickNum(usage, ["inputOther", "input_other"]),
|
|
1337
1419
|
output: pickNum(usage, ["output"]),
|
|
1338
1420
|
cacheRead: pickNum(usage, ["inputCacheRead", "input_cache_read"]),
|
|
1339
1421
|
cacheWrite: pickNum(usage, ["inputCacheCreation", "input_cache_creation"])
|
|
1340
1422
|
});
|
|
1341
1423
|
}
|
|
1342
|
-
return sessionFromRecords(file, void 0, records);
|
|
1424
|
+
return sessionFromRecords(file, void 0, records, seen);
|
|
1343
1425
|
}
|
|
1344
1426
|
async function loadKimiProjects(home, onProgress) {
|
|
1345
1427
|
const files = [];
|
|
@@ -1349,10 +1431,11 @@ async function loadKimiProjects(home, onProgress) {
|
|
|
1349
1431
|
);
|
|
1350
1432
|
}
|
|
1351
1433
|
const sessions = [];
|
|
1434
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1352
1435
|
let parsed = 0;
|
|
1353
1436
|
for (const f of files) {
|
|
1354
1437
|
onProgress?.({ parsed, total: files.length, currentProject: "Kimi sessions" });
|
|
1355
|
-
sessions.push(await parseFile4(f));
|
|
1438
|
+
sessions.push(await parseFile4(f, seen));
|
|
1356
1439
|
parsed += 1;
|
|
1357
1440
|
onProgress?.({ parsed, total: files.length, currentProject: "Kimi sessions" });
|
|
1358
1441
|
}
|
|
@@ -1390,7 +1473,7 @@ function openclawRoots(home) {
|
|
|
1390
1473
|
function modelFrom(obj) {
|
|
1391
1474
|
return str(obj, "modelId") ?? str(obj, "model");
|
|
1392
1475
|
}
|
|
1393
|
-
async function parseFile5(file) {
|
|
1476
|
+
async function parseFile5(file, seen) {
|
|
1394
1477
|
const records = [];
|
|
1395
1478
|
let currentModel;
|
|
1396
1479
|
for (const line of await readJsonl(file)) {
|
|
@@ -1405,13 +1488,14 @@ async function parseFile5(file) {
|
|
|
1405
1488
|
records.push({
|
|
1406
1489
|
model,
|
|
1407
1490
|
ts: str(l.message, "timestamp") ?? str(l, "timestamp"),
|
|
1491
|
+
id: str(l.message, "id") ?? str(l, "id") ?? str(l.message, "messageId"),
|
|
1408
1492
|
input: pickNum(usage, ["input"]),
|
|
1409
1493
|
output: pickNum(usage, ["output"]),
|
|
1410
1494
|
cacheRead: pickNum(usage, ["cacheRead"]),
|
|
1411
1495
|
cacheWrite: pickNum(usage, ["cacheWrite"])
|
|
1412
1496
|
});
|
|
1413
1497
|
}
|
|
1414
|
-
return sessionFromRecords(file, void 0, records);
|
|
1498
|
+
return sessionFromRecords(file, void 0, records, seen);
|
|
1415
1499
|
}
|
|
1416
1500
|
async function loadOpenclawProjects(home, onProgress) {
|
|
1417
1501
|
const files = [];
|
|
@@ -1419,10 +1503,11 @@ async function loadOpenclawProjects(home, onProgress) {
|
|
|
1419
1503
|
files.push(...await glob9(["**/*.jsonl", "**/*.jsonl.*"], { cwd: root, absolute: true }).catch(() => []));
|
|
1420
1504
|
}
|
|
1421
1505
|
const sessions = [];
|
|
1506
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1422
1507
|
let parsed = 0;
|
|
1423
1508
|
for (const f of files) {
|
|
1424
1509
|
onProgress?.({ parsed, total: files.length, currentProject: "OpenClaw sessions" });
|
|
1425
|
-
sessions.push(await parseFile5(f));
|
|
1510
|
+
sessions.push(await parseFile5(f, seen));
|
|
1426
1511
|
parsed += 1;
|
|
1427
1512
|
onProgress?.({ parsed, total: files.length, currentProject: "OpenClaw sessions" });
|
|
1428
1513
|
}
|
|
@@ -1446,7 +1531,7 @@ var openclawAdapter = {
|
|
|
1446
1531
|
};
|
|
1447
1532
|
|
|
1448
1533
|
// src/agents/opencode.ts
|
|
1449
|
-
import { access as access14, readFile as
|
|
1534
|
+
import { access as access14, readFile as readFile6 } from "fs/promises";
|
|
1450
1535
|
import { homedir as homedir15 } from "os";
|
|
1451
1536
|
import { join as join15 } from "path";
|
|
1452
1537
|
import { glob as glob10 } from "tinyglobby";
|
|
@@ -1477,7 +1562,7 @@ function opencodeRoot(home) {
|
|
|
1477
1562
|
}
|
|
1478
1563
|
async function readJson2(file) {
|
|
1479
1564
|
try {
|
|
1480
|
-
return JSON.parse(await
|
|
1565
|
+
return JSON.parse(await readFile6(file, "utf8"));
|
|
1481
1566
|
} catch {
|
|
1482
1567
|
return void 0;
|
|
1483
1568
|
}
|
|
@@ -1566,7 +1651,7 @@ import { glob as glob11 } from "tinyglobby";
|
|
|
1566
1651
|
function piRoot(home) {
|
|
1567
1652
|
return process.env.PI_AGENT_DIR ?? join16(home ?? homedir16(), ".pi", "agent", "sessions");
|
|
1568
1653
|
}
|
|
1569
|
-
async function parseFile6(file) {
|
|
1654
|
+
async function parseFile6(file, seen) {
|
|
1570
1655
|
const records = [];
|
|
1571
1656
|
for (const line of await readJsonl(file)) {
|
|
1572
1657
|
const msg = line.message;
|
|
@@ -1575,21 +1660,23 @@ async function parseFile6(file) {
|
|
|
1575
1660
|
records.push({
|
|
1576
1661
|
model: str(msg, "model") ?? "pi-unknown",
|
|
1577
1662
|
ts: str(line, "timestamp"),
|
|
1663
|
+
id: str(msg, "id") ?? str(line, "id") ?? str(msg, "messageId"),
|
|
1578
1664
|
input: pickNum(usage, ["input"]),
|
|
1579
1665
|
output: pickNum(usage, ["output"]),
|
|
1580
1666
|
cacheRead: pickNum(usage, ["cacheRead"]),
|
|
1581
1667
|
cacheWrite: pickNum(usage, ["cacheWrite"])
|
|
1582
1668
|
});
|
|
1583
1669
|
}
|
|
1584
|
-
return sessionFromRecords(file, void 0, records);
|
|
1670
|
+
return sessionFromRecords(file, void 0, records, seen);
|
|
1585
1671
|
}
|
|
1586
1672
|
async function loadPiProjects(home, onProgress) {
|
|
1587
1673
|
const files = await glob11(["**/*.jsonl"], { cwd: piRoot(home), absolute: true }).catch(() => []);
|
|
1588
1674
|
const sessions = [];
|
|
1675
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1589
1676
|
let parsed = 0;
|
|
1590
1677
|
for (const f of files) {
|
|
1591
1678
|
onProgress?.({ parsed, total: files.length, currentProject: "pi sessions" });
|
|
1592
|
-
sessions.push(await parseFile6(f));
|
|
1679
|
+
sessions.push(await parseFile6(f, seen));
|
|
1593
1680
|
parsed += 1;
|
|
1594
1681
|
onProgress?.({ parsed, total: files.length, currentProject: "pi sessions" });
|
|
1595
1682
|
}
|
|
@@ -1618,7 +1705,7 @@ import { glob as glob12 } from "tinyglobby";
|
|
|
1618
1705
|
function qwenRoot(home) {
|
|
1619
1706
|
return process.env.QWEN_DATA_DIR ?? join17(home ?? homedir17(), ".qwen");
|
|
1620
1707
|
}
|
|
1621
|
-
async function parseFile7(file) {
|
|
1708
|
+
async function parseFile7(file, seen) {
|
|
1622
1709
|
const records = [];
|
|
1623
1710
|
for (const line of await readJsonl(file)) {
|
|
1624
1711
|
const meta = line.usageMetadata;
|
|
@@ -1629,23 +1716,25 @@ async function parseFile7(file) {
|
|
|
1629
1716
|
records.push({
|
|
1630
1717
|
model: str(line, "model") ?? "qwen-unknown",
|
|
1631
1718
|
ts: str(line, "timestamp"),
|
|
1719
|
+
id: str(line, "id") ?? str(line, "messageId") ?? str(line, "message_id"),
|
|
1632
1720
|
input: Math.max(0, prompt - cached),
|
|
1633
1721
|
output: pickNum(meta, ["candidatesTokenCount"]) + reasoning,
|
|
1634
1722
|
cacheRead: cached,
|
|
1635
1723
|
cacheWrite: 0
|
|
1636
1724
|
});
|
|
1637
1725
|
}
|
|
1638
|
-
return sessionFromRecords(file, void 0, records);
|
|
1726
|
+
return sessionFromRecords(file, void 0, records, seen);
|
|
1639
1727
|
}
|
|
1640
1728
|
async function loadQwenProjects(home, onProgress) {
|
|
1641
1729
|
const files = await glob12(["projects/**/*.jsonl"], { cwd: qwenRoot(home), absolute: true }).catch(
|
|
1642
1730
|
() => []
|
|
1643
1731
|
);
|
|
1644
1732
|
const sessions = [];
|
|
1733
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1645
1734
|
let parsed = 0;
|
|
1646
1735
|
for (const f of files) {
|
|
1647
1736
|
onProgress?.({ parsed, total: files.length, currentProject: "Qwen sessions" });
|
|
1648
|
-
sessions.push(await parseFile7(f));
|
|
1737
|
+
sessions.push(await parseFile7(f, seen));
|
|
1649
1738
|
parsed += 1;
|
|
1650
1739
|
onProgress?.({ parsed, total: files.length, currentProject: "Qwen sessions" });
|
|
1651
1740
|
}
|
package/dist/cli.js
CHANGED
|
@@ -276,7 +276,7 @@ program.action(async () => {
|
|
|
276
276
|
const [{ render }, React, { Root }, { Fullscreen }] = await Promise.all([
|
|
277
277
|
import("ink"),
|
|
278
278
|
import("react"),
|
|
279
|
-
import("./Root-
|
|
279
|
+
import("./Root-FWMJ2TO2.js"),
|
|
280
280
|
import("./Fullscreen-GK2ZYXHV.js")
|
|
281
281
|
]);
|
|
282
282
|
render(React.createElement(Fullscreen, null, React.createElement(Root)));
|