tokentracker-cli 0.85.0 → 0.86.1
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/README.de.md +7 -4
- package/README.ja.md +7 -4
- package/README.ko.md +7 -4
- package/README.md +10 -7
- package/README.zh-CN.md +7 -4
- package/dashboard/dist/assets/{AchievementBadge-DEqbHlmn.js → AchievementBadge-BHWjTRZh.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-BOaEu1AQ.js → AchievementsPage-X6Z6fiAx.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-C370ngO3.js → AchievementsSection-DL2CccQ8.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-D7Wkef0K.js → BadgeDetailModal-DKn88JDX.js} +1 -1
- package/dashboard/dist/assets/{Card-mDEVjNdM.js → Card-B_gKsFZR.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-DdsX-z8n.js → ClawdAnimated-vEB5WCNu.js} +1 -1
- package/dashboard/dist/assets/{CommandPalette-DhxRIuHC.js → CommandPalette-BoxeCsUF.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-CG-9JPS6.js → CommunityStatsModal-BwELjQld.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-COhxErLm.js → ConfirmModal-j8yHWm2k.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-tX0DKgFE.js → DashboardPage-CkvAOuBF.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-BsSeHx84.js → DevicePage-k4Lr11LG.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-eyOW2cbx.js → DialogClose-C-ZhX9eY.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-BRiqm-uZ.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-H8sGiH7c.js → DialogTitle-XCGSHZDz.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-pq2ja50M.js → FadeIn-ljP_7vPC.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-DWgcpDHr.js → HeaderGithubStar-D4QupeSb.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-CcJ_VR65.js → HoverTooltip-Dkpz8RmH.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-CNUN346Q.js → IpCheckPage-WkZK9Tr3.js} +1 -1
- package/dashboard/dist/assets/LandingPage-Dp3m0uJg.js +2 -0
- package/dashboard/dist/assets/{LeaderboardAvatar-Ddai4I12.js → LeaderboardAvatar-DleP6bK7.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-Bajkxf63.js → LeaderboardPage-DTwMMaF2.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-BGYKDgIi.js → LeaderboardProfileModal-xdDlcRDd.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-Ck5vPaeN.js → LeaderboardProfilePage-Ckytgq9h.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-Bqobtsw2.js → LimitsPage-D_2cV3S4.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-e9KSE3wj.js → LocalOnlyNotice-DpCb8VIO.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-BhTSm2tb.js → LoginCard-BeAb35_3.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-CRwuThde.js → LoginModal-DNdAgKeE.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-j1i74lcc.js → LoginPage-nuWkBuqy.js} +1 -1
- package/dashboard/dist/assets/{PetPage-r62ViU1X.js → PetPage-CCLFROsF.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-DopNTyD4.js → PopoverPopup-BCaeRKf4.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-c1LkPhYM.js → ProviderIcon-C_Fpc2jL.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-DJdDNvtq.js → ResetPasswordPage-lLDxtpC9.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-DhWVOTPN.js → SegmentedControl-Bnfv5lDS.js} +1 -1
- package/dashboard/dist/assets/{Select-DeUmTmsJ.js → Select-CvY_Y0WS.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-pX0B5f7h.js → SelectItemText-DX4QYfBW.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-ejIPz6oF.js → ServiceStatusPage-DcUrtacl.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-WEbn90GW.js → SessionsPage-CJXyaHQA.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-B8t5gCeI.js → SettingsPage-BkgPxhGn.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-BWMlzeAp.js → SkillsPage-BGvK3HZ0.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-DIBRBvMj.js → TokenGalaxy-D9_H79bK.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-C6KxLvnI.js → ToolbarRootContext-BsM_3QBs.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-BaMNh67w.js → TrendMonitor-D2QSVlSi.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-DDsy4M3x.js → WidgetsPage-BpWOr7-c.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-CiNnUFRI.js → WrappedPage-DliB3OZk.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-CM-H8-LW.js → __vite-browser-external-CzDhMv0q.js} +15 -14
- package/dashboard/dist/assets/{agent-logos-BjVa6oe7.js → agent-logos-Q7rTqkGv.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-CCum1mqX.js → arrow-up-right-DwqQgMsR.js} +1 -1
- package/dashboard/dist/assets/{check-ySRQc1YP.js → check-Cypjnyke.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-5vFloHew.js → chevron-right-LZRe0crm.js} +1 -1
- package/dashboard/dist/assets/{copy-mhfKVMKo.js → copy-BUe15mXV.js} +1 -1
- package/dashboard/dist/assets/{download-GdrXglSx.js → download-BhjaQuUD.js} +1 -1
- package/dashboard/dist/assets/{external-link-KGFaKc8s.js → external-link-BHU7m_Df.js} +1 -1
- package/dashboard/dist/assets/{flame-BmNtNoS1.js → flame-BPQ7FpRu.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-CCpCNw3d.js → format-tokens-C0XEJ96L.js} +1 -1
- package/dashboard/dist/assets/{icons-XLKZavTf.js → icons-De5Qo1lp.js} +1 -1
- package/dashboard/dist/assets/{index-IKpmeZte.js → index-Cl8hqOBU.js} +1 -1
- package/dashboard/dist/assets/{index-_xU5U5Ct.js → index-UfiJKvuV.js} +1 -1
- package/dashboard/dist/assets/{index-CsywTeCQ.js → index-lmWJH5W9.js} +1 -1
- package/dashboard/dist/assets/{info-DUV5UpmT.js → info-CCPDu6hQ.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-DFkCZCZj.js → limits-providers-B2Qjydn9.js} +1 -1
- package/dashboard/dist/assets/{link-2-D7c64yLY.js → link-2-Dl1DAfTL.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-sMONRK2M.js → loader-circle-C-mC8s6j.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-CVWRgrk9.js → maximize-2-C9YpCcsr.js} +1 -1
- package/dashboard/dist/assets/{provider-display-DSKqVjgm.js → provider-display-DNXQkneb.js} +2 -2
- package/dashboard/dist/assets/{react-c1q4mGkS.js → react-LsYzFOQW.js} +1 -1
- package/dashboard/dist/assets/{search-CwD3s-_C.js → search-D5SGjOTl.js} +1 -1
- package/dashboard/dist/assets/{skills-api-BRXj8kjT.js → skills-api-CGRg1lZw.js} +1 -1
- package/dashboard/dist/assets/{store-lqTW2gfK.js → store-BMdm145i.js} +1 -1
- package/dashboard/dist/assets/{terminal-DU1_KbKo.js → terminal-HhtP7nqJ.js} +1 -1
- package/dashboard/dist/assets/{trash-2-B8Y5Xc-K.js → trash-2-CeEoITVO.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-DYwwimvp.js → use-community-stats-BTZHzzWd.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-Bst6ybK3.js → use-limits-display-prefs-DPNlMKcg.js} +1 -1
- package/dashboard/dist/assets/{use-native-settings-Cqle4lgw.js → use-native-settings-DFF0ouY5.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-Dtze0ahb.js → use-ordered-list-CCLtmxXg.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-DUtjZjIj.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-gwbDMHXa.js → use-session-efficiency-pref-CrvLKyhz.js} +1 -1
- package/dashboard/dist/assets/{use-transform-CU0yxXpX.js → use-transform-BnJ0PftW.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-5y1I1T5_.js → use-usage-limits-BY3ZXlDo.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-BfVNrywe.js → useCurrency-BiFDQKMu.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-CF1m7AMJ.js → useScrollLock-BXUoxe5p.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-DiRwVvRr.js → useTokenFormat-C6DBFS-R.js} +1 -1
- package/dashboard/dist/assets/{zap-BZtlWtuN.js → zap-9H5t1Kye.js} +1 -1
- package/dashboard/dist/index.html +12 -10
- package/dashboard/dist/ip-check.html +1 -1
- package/dashboard/dist/leaderboard.html +1 -1
- package/dashboard/dist/llms.txt +3 -2
- package/dashboard/dist/share.html +1 -1
- package/package.json +2 -2
- package/src/commands/init.js +1 -0
- package/src/commands/status.js +15 -0
- package/src/commands/sync.js +117 -10
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +471 -7
- package/src/lib/wsl-probe.js +36 -0
- package/dashboard/dist/assets/DialogDescription-BwtE4lKl.js +0 -1
- package/dashboard/dist/assets/LandingPage-yaoRGsNI.js +0 -2
- package/dashboard/dist/assets/use-reduced-motion-CbZDR54N.js +0 -1
package/src/commands/status.js
CHANGED
|
@@ -66,6 +66,7 @@ const {
|
|
|
66
66
|
resolveRoocodeTaskFiles,
|
|
67
67
|
resolveZedDbPath,
|
|
68
68
|
resolveQoderDbPaths,
|
|
69
|
+
resolveClaudeScienceDbPaths,
|
|
69
70
|
resolveAnythingllmDbPath,
|
|
70
71
|
resolveGooseDbPath,
|
|
71
72
|
listDroidSettingsFiles,
|
|
@@ -425,6 +426,14 @@ async function cmdStatus(argv = []) {
|
|
|
425
426
|
const qoderInstalled = qoderActive.length > 0;
|
|
426
427
|
const qoderDbPath = qoderActive.join(" | ");
|
|
427
428
|
|
|
429
|
+
// Claude Science — token usage lives on the `frames` table of operon-cli.db.
|
|
430
|
+
// Unlike the native/WSL pair other providers resolve to, this is an open-ended
|
|
431
|
+
// list: multi-org installs keep one DB per org (and on Windows they all sit
|
|
432
|
+
// inside WSL), so the resolver already returns only paths that exist.
|
|
433
|
+
const claudeScienceActive = resolveClaudeScienceDbPaths({ home, env: process.env });
|
|
434
|
+
const claudeScienceInstalled = claudeScienceActive.length > 0;
|
|
435
|
+
const claudeScienceDbPath = claudeScienceActive.join(" | ");
|
|
436
|
+
|
|
428
437
|
// OpenCode (JSON files + SQLite DB) — passive scan of storage/message/ and opencode.db.
|
|
429
438
|
const opencodeStorageNativeValue = process.env.OPENCODE_HOME || path.join(xdgDataHome, "opencode");
|
|
430
439
|
const wslOpencodeStorageDir = process.platform === "win32" && shouldProbeWsl(process.env)
|
|
@@ -786,6 +795,9 @@ async function cmdStatus(argv = []) {
|
|
|
786
795
|
qoder: qoderInstalled
|
|
787
796
|
? { installed: true, detail: qoderDbPath }
|
|
788
797
|
: { installed: false },
|
|
798
|
+
"claude-science": claudeScienceInstalled
|
|
799
|
+
? { installed: true, detail: claudeScienceDbPath }
|
|
800
|
+
: { installed: false },
|
|
789
801
|
kilocode: kilocodeInstalled
|
|
790
802
|
? { installed: true, files: kilocodeTaskFiles.length }
|
|
791
803
|
: { installed: false },
|
|
@@ -907,6 +919,9 @@ async function cmdStatus(argv = []) {
|
|
|
907
919
|
qoderInstalled
|
|
908
920
|
? `- Qoder: passive reader (${qoderDbPath})`
|
|
909
921
|
: null,
|
|
922
|
+
claudeScienceInstalled
|
|
923
|
+
? `- Claude Science: passive reader (${claudeScienceDbPath})`
|
|
924
|
+
: null,
|
|
910
925
|
opencodeInstalled
|
|
911
926
|
? `- OpenCode: passive reader (storage: ${opencodeStorageActive.join(" | ") || "not found"}, DB: ${opencodeDbActive.join(" | ") || "not found"})`
|
|
912
927
|
: null,
|
package/src/commands/sync.js
CHANGED
|
@@ -40,6 +40,12 @@ const {
|
|
|
40
40
|
parseOpencodeDbIncremental,
|
|
41
41
|
parseQoderDbIncremental,
|
|
42
42
|
parseOpenclawIncremental,
|
|
43
|
+
resolveOpenclawSessionFiles,
|
|
44
|
+
resolveOpenclawHome,
|
|
45
|
+
openclawCursorKey,
|
|
46
|
+
resolveClaudeScienceDbPaths,
|
|
47
|
+
readClaudeScienceFrames,
|
|
48
|
+
parseClaudeScienceIncremental,
|
|
43
49
|
parseCursorApiIncremental,
|
|
44
50
|
parseKiroIncremental,
|
|
45
51
|
parseHermesIncremental,
|
|
@@ -237,6 +243,7 @@ const AUTO_SYNC_SOURCES = new Set([
|
|
|
237
243
|
"antigravity",
|
|
238
244
|
"anythingllm",
|
|
239
245
|
"claude",
|
|
246
|
+
"claude-science",
|
|
240
247
|
"codebuddy",
|
|
241
248
|
"codex",
|
|
242
249
|
"copilot",
|
|
@@ -473,7 +480,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
473
480
|
// OpenClaw session plugin integration: lifecycle hooks request an
|
|
474
481
|
// OpenClaw-only auto sync so unrelated providers do not get walked.
|
|
475
482
|
const openclawSignal = opts.fromOpenclaw
|
|
476
|
-
? resolveOpenclawSignal({
|
|
483
|
+
? resolveOpenclawSignal({ env: process.env })
|
|
477
484
|
: null;
|
|
478
485
|
|
|
479
486
|
const autoSourceScope = resolveAutoSourceScope(opts);
|
|
@@ -668,9 +675,38 @@ async function cmdSync(argv, context = {}) {
|
|
|
668
675
|
codexCursorLoadRestarted = Boolean(loadResult?.restarted);
|
|
669
676
|
}
|
|
670
677
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
678
|
+
// Plugin-triggered sync points at one specific session file; a normal full
|
|
679
|
+
// sync also passively scans every on-disk OpenClaw transcript so usage is
|
|
680
|
+
// captured even when the session plugin never fires (issue #264). The scan
|
|
681
|
+
// is gated to full syncs so a scoped `--from-openclaw` hook still only
|
|
682
|
+
// touches its own file and the 5-minute background tick stays cheap. The
|
|
683
|
+
// event-identity dedup makes the plugin and passive paths idempotent, so
|
|
684
|
+
// overlap on the same file is safe.
|
|
685
|
+
//
|
|
686
|
+
// Keyed by openclawCursorKey, not the raw path: that is the same identity
|
|
687
|
+
// the parser assigns cursors by, so a plugin-supplied path and a scanned
|
|
688
|
+
// path that differ only in Windows casing collapse to one entry instead of
|
|
689
|
+
// being parsed twice.
|
|
690
|
+
const openclawSessionFiles = new Map();
|
|
691
|
+
if (openclawSignal?.sessionFile) {
|
|
692
|
+
openclawSessionFiles.set(openclawCursorKey(openclawSignal.sessionFile), {
|
|
693
|
+
path: openclawSignal.sessionFile,
|
|
694
|
+
source: "openclaw",
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
if (isFullSourceScan && sourceAllowed("openclaw")) {
|
|
698
|
+
try {
|
|
699
|
+
for (const f of await resolveOpenclawSessionFiles(process.env)) {
|
|
700
|
+
const key = openclawCursorKey(f);
|
|
701
|
+
if (!openclawSessionFiles.has(key)) {
|
|
702
|
+
openclawSessionFiles.set(key, { path: f, source: "openclaw" });
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
} catch (err) {
|
|
706
|
+
warnProviderParseFailure("OpenClaw", err, opts);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
const openclawFiles = Array.from(openclawSessionFiles.values());
|
|
674
710
|
|
|
675
711
|
if (progress?.enabled) {
|
|
676
712
|
progress.start(
|
|
@@ -740,7 +776,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
740
776
|
|
|
741
777
|
let openclawResult = { filesProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
742
778
|
if (sourceAllowed("openclaw") && openclawFiles.length > 0) {
|
|
743
|
-
//
|
|
779
|
+
// Parses plugin-triggered and/or passively discovered session files.
|
|
744
780
|
try {
|
|
745
781
|
openclawResult = await parseOpenclawIncremental({
|
|
746
782
|
sessionFiles: openclawFiles,
|
|
@@ -971,6 +1007,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
971
1007
|
dbResult = await parseOpencodeDbIncremental({
|
|
972
1008
|
...options,
|
|
973
1009
|
dbMessages,
|
|
1010
|
+
dbPath,
|
|
974
1011
|
});
|
|
975
1012
|
}
|
|
976
1013
|
}
|
|
@@ -1030,7 +1067,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
1030
1067
|
paths: qoderPaths,
|
|
1031
1068
|
parserFn: async ({ dbPath, ...rest }) => {
|
|
1032
1069
|
const dbMessages = await readQoderDbMessages(dbPath);
|
|
1033
|
-
const parsed = await parseQoderDbIncremental({ dbMessages, ...rest });
|
|
1070
|
+
const parsed = await parseQoderDbIncremental({ dbMessages, dbPath, ...rest });
|
|
1034
1071
|
return {
|
|
1035
1072
|
recordsProcessed: parsed.messagesProcessed || 0,
|
|
1036
1073
|
eventsAggregated: parsed.eventsAggregated || 0,
|
|
@@ -1055,13 +1092,52 @@ async function cmdSync(argv, context = {}) {
|
|
|
1055
1092
|
}
|
|
1056
1093
|
}
|
|
1057
1094
|
|
|
1095
|
+
// ── Claude Science (Anthropic's local research workbench, issue #246) ──
|
|
1096
|
+
// Per-frame token usage lives on the `frames` table of operon-cli.db.
|
|
1097
|
+
// Passive, incremental, subtract-on-change. There can be more than one DB:
|
|
1098
|
+
// multi-org installs keep one per org, and on Windows the app runs inside
|
|
1099
|
+
// WSL so the DB is on the distro home.
|
|
1100
|
+
let claudeScienceResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
1101
|
+
if (sourceAllowed("claude-science")) {
|
|
1102
|
+
// Resolution is inside the error isolation too: it touches the filesystem
|
|
1103
|
+
// and (on Windows) probes WSL, and a throw here would abort cmdSync before
|
|
1104
|
+
// any provider's buckets are written, not just this one's.
|
|
1105
|
+
let claudeScienceDbPaths = [];
|
|
1106
|
+
try {
|
|
1107
|
+
claudeScienceDbPaths = resolveClaudeScienceDbPaths({ home, env: process.env });
|
|
1108
|
+
} catch (err) {
|
|
1109
|
+
warnProviderParseFailure("Claude Science", err, opts);
|
|
1110
|
+
}
|
|
1111
|
+
if (claudeScienceDbPaths.length > 0 && progress?.enabled) {
|
|
1112
|
+
progress.start(`Parsing Claude Science ${renderBar(0)} | buckets 0`);
|
|
1113
|
+
}
|
|
1114
|
+
for (const claudeScienceDbPath of claudeScienceDbPaths) {
|
|
1115
|
+
try {
|
|
1116
|
+
const dbRows = await readClaudeScienceFrames(claudeScienceDbPath);
|
|
1117
|
+
const parsed = await parseClaudeScienceIncremental({
|
|
1118
|
+
dbRows,
|
|
1119
|
+
cursors,
|
|
1120
|
+
queuePath,
|
|
1121
|
+
onProgress: makeProviderProgress("Claude Science"),
|
|
1122
|
+
});
|
|
1123
|
+
claudeScienceResult = mergeParseResult(claudeScienceResult, {
|
|
1124
|
+
recordsProcessed: parsed.recordsProcessed || 0,
|
|
1125
|
+
eventsAggregated: parsed.eventsAggregated || 0,
|
|
1126
|
+
bucketsQueued: parsed.bucketsQueued || 0,
|
|
1127
|
+
});
|
|
1128
|
+
} catch (err) {
|
|
1129
|
+
warnProviderParseFailure("Claude Science", err, opts);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1058
1134
|
async function parseOpencodeDbForInstall({ dbPath, readFn, source, cursorKey, ...rest }) {
|
|
1059
1135
|
if (!dbPath || !fssync.existsSync(dbPath)) {
|
|
1060
1136
|
return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
1061
1137
|
}
|
|
1062
1138
|
const dbMessages = readFn(dbPath);
|
|
1063
1139
|
if (dbMessages.length === 0) return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
1064
|
-
const result = await parseOpencodeDbIncremental({ dbMessages, source, cursorKey, ...rest });
|
|
1140
|
+
const result = await parseOpencodeDbIncremental({ dbMessages, dbPath, source, cursorKey, ...rest });
|
|
1065
1141
|
return {
|
|
1066
1142
|
recordsProcessed: result.messagesProcessed || 0,
|
|
1067
1143
|
eventsAggregated: result.eventsAggregated || 0,
|
|
@@ -2215,6 +2291,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
2215
2291
|
antigravityResult.filesProcessed +
|
|
2216
2292
|
opencodeResult.filesProcessed +
|
|
2217
2293
|
qoderResult.recordsProcessed +
|
|
2294
|
+
claudeScienceResult.recordsProcessed +
|
|
2218
2295
|
cursorResult.recordsProcessed +
|
|
2219
2296
|
kiroResult.recordsProcessed +
|
|
2220
2297
|
kiroCliResult.recordsProcessed +
|
|
@@ -2245,6 +2322,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
2245
2322
|
antigravityResult.bucketsQueued +
|
|
2246
2323
|
opencodeResult.bucketsQueued +
|
|
2247
2324
|
qoderResult.bucketsQueued +
|
|
2325
|
+
claudeScienceResult.bucketsQueued +
|
|
2248
2326
|
cursorResult.bucketsQueued +
|
|
2249
2327
|
kiroResult.bucketsQueued +
|
|
2250
2328
|
kiroCliResult.bucketsQueued +
|
|
@@ -2586,15 +2664,18 @@ function normalizeString(value) {
|
|
|
2586
2664
|
return trimmed.length > 0 ? trimmed : null;
|
|
2587
2665
|
}
|
|
2588
2666
|
|
|
2589
|
-
function resolveOpenclawSignal({
|
|
2667
|
+
function resolveOpenclawSignal({ env } = {}) {
|
|
2590
2668
|
if (!env) return null;
|
|
2591
2669
|
|
|
2592
2670
|
const agentId = normalizeString(env.TOKENTRACKER_OPENCLAW_AGENT_ID);
|
|
2593
2671
|
const sessionId = normalizeString(env.TOKENTRACKER_OPENCLAW_PREV_SESSION_ID);
|
|
2594
2672
|
if (!agentId || !sessionId) return null;
|
|
2595
2673
|
|
|
2596
|
-
|
|
2597
|
-
|
|
2674
|
+
// Resolve the OpenClaw home identically to the passive scanner so the
|
|
2675
|
+
// plugin-triggered file and passively discovered files share one path
|
|
2676
|
+
// spelling — otherwise the same transcript could get two cursors and be
|
|
2677
|
+
// counted twice (issue #264 review).
|
|
2678
|
+
const openclawHome = resolveOpenclawHome(env);
|
|
2598
2679
|
const sessionFile = path.join(openclawHome, "agents", agentId, "sessions", `${sessionId}.jsonl`);
|
|
2599
2680
|
|
|
2600
2681
|
const prevTotals = {
|
|
@@ -2627,6 +2708,16 @@ async function applyOpenclawTotalsFallback({
|
|
|
2627
2708
|
return { filesProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
2628
2709
|
}
|
|
2629
2710
|
|
|
2711
|
+
// The passive/plugin transcript parse is authoritative: if this session's
|
|
2712
|
+
// transcript has ever yielded real per-event usage, synthesizing sessions.json
|
|
2713
|
+
// totals on top would count the same tokens twice (issue #264 review). Defer
|
|
2714
|
+
// to the real events and advance the fallback baseline so no stale delta lingers.
|
|
2715
|
+
const transcriptCursor =
|
|
2716
|
+
signal.sessionFile && cursors?.files
|
|
2717
|
+
? cursors.files[openclawCursorKey(signal.sessionFile)]
|
|
2718
|
+
: null;
|
|
2719
|
+
const transcriptHasRealUsage = Boolean(transcriptCursor?.hasRealUsage);
|
|
2720
|
+
|
|
2630
2721
|
const sessionKey = `${signal.agentId}:${signal.sessionId}`;
|
|
2631
2722
|
const statePath = path.join(trackerDir, "openclaw.fallback.state.json");
|
|
2632
2723
|
const fallbackFilePath = path.join(trackerDir, "openclaw.fallback.jsonl");
|
|
@@ -2635,6 +2726,22 @@ async function applyOpenclawTotalsFallback({
|
|
|
2635
2726
|
const prev =
|
|
2636
2727
|
sessions[sessionKey] && typeof sessions[sessionKey] === "object" ? sessions[sessionKey] : null;
|
|
2637
2728
|
|
|
2729
|
+
if (transcriptHasRealUsage) {
|
|
2730
|
+
sessions[sessionKey] = {
|
|
2731
|
+
totalTokens: normalizeNonNegativeInt(signal?.prevTotals?.totalTokens) || 0,
|
|
2732
|
+
inputTokens: normalizeNonNegativeInt(signal?.prevTotals?.inputTokens) || 0,
|
|
2733
|
+
outputTokens: normalizeNonNegativeInt(signal?.prevTotals?.outputTokens) || 0,
|
|
2734
|
+
model: normalizeString(signal?.prevTotals?.model) || "unknown",
|
|
2735
|
+
updatedAt: normalizeIsoOrEpoch(signal?.prevTotals?.updatedAt) || new Date().toISOString(),
|
|
2736
|
+
seenAt: new Date().toISOString(),
|
|
2737
|
+
coveredByEvents: true,
|
|
2738
|
+
};
|
|
2739
|
+
state.version = 1;
|
|
2740
|
+
state.sessions = sessions;
|
|
2741
|
+
await writeJson(statePath, state);
|
|
2742
|
+
return { filesProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2638
2745
|
const current = {
|
|
2639
2746
|
totalTokens: normalizeNonNegativeInt(signal?.prevTotals?.totalTokens) || 0,
|
|
2640
2747
|
inputTokens: normalizeNonNegativeInt(signal?.prevTotals?.inputTokens) || 0,
|