tokentracker-cli 0.88.1 → 0.88.2
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/dashboard/dist/assets/{AchievementBadge-Crrws1U1.js → AchievementBadge-BcCrg832.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-C65tiTnu.js → AchievementsPage-C95dF_C-.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-Gc28pe4U.js → AchievementsSection-B-VD8CfN.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-D_jEjBVd.js → BadgeDetailModal-CDTJ3tR6.js} +1 -1
- package/dashboard/dist/assets/{Card-DlZueiVg.js → Card-a0RpvhLn.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-DrwVfg1s.js → ClawdAnimated-CaLKUbmC.js} +1 -1
- package/dashboard/dist/assets/{CommandPalette-Dj753h1Y.js → CommandPalette-CQpkX7dK.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-PiK4kOib.js → CommunityStatsModal-Cj53g1ky.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-CJz-TMiD.js → ConfirmModal-FHZmD91i.js} +1 -1
- package/dashboard/dist/assets/{Controls-DZ0W7HPO.js → Controls-BSk2Eph4.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-DEDZy960.js → DashboardPage-Ci1jVw-F.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-BR60A3uN.js → DevicePage-BnCWVmOI.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-qcbYLZ_r.js → DialogClose-BUhPBSeF.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-Dp7bBdfJ.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-KMA1u6gh.js → DialogTitle-CbNKnmTY.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-BtTL9V_I.js → FadeIn-D87p8xfM.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-Ckp60oxi.js → HeaderGithubStar-kE4I1PyE.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-DaCmGdvh.js → HoverTooltip-miw72aLh.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-Bs2xgpWT.js → IpCheckPage-D-JoHTz-.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-Dj6382lF.js → LandingPage-Dx_MOVjJ.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-4LQRczW4.js → LeaderboardAvatar-arnp_cWI.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-BKTbW7CC.js → LeaderboardPage-zsoFUX5G.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-BP-I9FrE.js → LeaderboardProfileModal-CrmSTl9n.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-CWzqXfsO.js → LeaderboardProfilePage-BSE0fPco.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-DJL3rkrZ.js → LimitsPage-BrU9e8AV.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-CJ8aY8Yg.js → LocalOnlyNotice-BWDZKn00.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-RfbqlInv.js → LoginCard-DS8mxxs_.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-DEgSV0ho.js → LoginModal-DhINfVDV.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-biogQhPJ.js → LoginPage-BKmuhR74.js} +1 -1
- package/dashboard/dist/assets/{PetPage-bbmFMllf.js → PetPage-QQk_B1SJ.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-Bx_a2ATx.js → PopoverPopup-DS6ml7IE.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-ClMKnRNE.js → ProviderIcon-DkHp1Hrl.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-B0aAisWC.js → ResetPasswordPage-CvJiufPF.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-85G6K4nz.js → SegmentedControl-DbYmpdj3.js} +1 -1
- package/dashboard/dist/assets/{Select-D-PLRmNY.js → Select-DJcVfYm7.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-DOQMVovf.js → SelectItemText-DUQLkHGQ.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-C2fq26Du.js → ServiceStatusPage-DqPQUM1f.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-B-Gzrsxr.js → SessionsPage-CPOSombb.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-DzjURmD5.js → SettingsPage-nIfi1h7D.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-Bmu5fgPF.js → SkillsPage-BnngQwIu.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-DFVGDrXI.js → TokenGalaxy-CAVmlIYW.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-CgWa03di.js → ToolbarRootContext-CyG7xQo2.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-CbLhCRaf.js → TrendMonitor-DyuKVbzV.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-CClBDKNb.js → WidgetsPage-72n9-HCD.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-B1QPw5JI.js → WrappedPage-Dp1aUOyA.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-CV_fKq4F.js → __vite-browser-external-8kU62_i_.js} +2 -2
- package/dashboard/dist/assets/{agent-logos-D-hDhb_B.js → agent-logos-ChfjzWPV.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-DAr-mJ3B.js → arrow-up-right-CiTMPVa_.js} +1 -1
- package/dashboard/dist/assets/{check-DPefl5-t.js → check-OQW1qgf_.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-MlzWycxC.js → chevron-right-BitImfyV.js} +1 -1
- package/dashboard/dist/assets/{copy-B_53rp1c.js → copy-BM76c1Ob.js} +1 -1
- package/dashboard/dist/assets/{download-DnlmdACw.js → download-DaKmqoH2.js} +1 -1
- package/dashboard/dist/assets/{external-link-DytBHNpR.js → external-link-AL639M-l.js} +1 -1
- package/dashboard/dist/assets/{flame-CO4NpDfZ.js → flame-BeYD0c6y.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-CwDQe65M.js → format-tokens-DK1Fdxfq.js} +1 -1
- package/dashboard/dist/assets/{icons-DvviMgxO.js → icons-BtLj_BDi.js} +1 -1
- package/dashboard/dist/assets/{index-Dz9TFADl.js → index-BHBegQjp.js} +1 -1
- package/dashboard/dist/assets/{index-B0Lzl2gQ.js → index-BK2Bm5Vp.js} +1 -1
- package/dashboard/dist/assets/{index-hGGiJmvs.js → index-D4kdhgAz.js} +1 -1
- package/dashboard/dist/assets/{info-BY_SOAny.js → info-CIwDFvrE.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-Cpis_64d.js → limits-providers-BFkGzLM4.js} +1 -1
- package/dashboard/dist/assets/{link-2-DaIthsuC.js → link-2-xFS-GP5p.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-DXLU_CS0.js → loader-circle-83n_EWic.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-CnLZ2V-D.js → maximize-2-CevrJZKM.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-CtoD-5nh.js → modifiers.esm-a1oXNZlE.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-CwfUXtG9.js → monitor-smartphone-CSP2FeVP.js} +1 -1
- package/dashboard/dist/assets/{provider-display-C0gDapSI.js → provider-display-CamXa0pj.js} +1 -1
- package/dashboard/dist/assets/{react-BNEThWJE.js → react-DV1nb3lW.js} +1 -1
- package/dashboard/dist/assets/{search-GYLDIV-1.js → search-wj8Kxgr5.js} +1 -1
- package/dashboard/dist/assets/{skills-api-noC3sCP_.js → skills-api-BNpGEfgh.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-Bm4LZh1T.js → sortable.esm-Xh3nfzFR.js} +1 -1
- package/dashboard/dist/assets/{store-DWhiUbOS.js → store-lBXh9-l6.js} +1 -1
- package/dashboard/dist/assets/{terminal-BEQDw7-4.js → terminal-uNBlGBuA.js} +1 -1
- package/dashboard/dist/assets/{trash-2-Cm7eF7SC.js → trash-2-08YOSvJh.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-9a-td9J_.js → use-community-stats-CMyCuzcM.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-XY6qQJai.js → use-limits-display-prefs-BkqvWQ4X.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-BEaiYX4S.js → use-ordered-list-CJ9F2mdG.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-CD_DKLbl.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-oDZEyqyO.js → use-session-efficiency-pref-Hf4gvuAl.js} +1 -1
- package/dashboard/dist/assets/{use-transform-LKaVzl1V.js → use-transform-BBP_cds4.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-DY3e5o6f.js → use-usage-limits-DsLD0OEm.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-CSRY4U-t.js → useCurrency-CXngtOdH.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-CSZXl0Pl.js → useScrollLock-Q65zPe5d.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-f1kcdHaP.js → useTokenFormat-CE5zbI_h.js} +1 -1
- package/dashboard/dist/assets/{zap-BMZr9Qc1.js → zap-CHYAc2Be.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/ip-check.html +1 -1
- package/dashboard/dist/leaderboard.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +1 -1
- package/src/commands/sync.js +4 -2
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +136 -14
- package/src/lib/session-analytics.js +220 -145
- package/dashboard/dist/assets/DialogDescription-DMUlPgjH.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-C9_Q8rAl.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -1233,7 +1233,11 @@ async function parseOpencodeIncremental({
|
|
|
1233
1233
|
const size = Number.isFinite(st.size) ? st.size : 0;
|
|
1234
1234
|
const mtimeMs = Number.isFinite(st.mtimeMs) ? st.mtimeMs : 0;
|
|
1235
1235
|
const unchanged =
|
|
1236
|
-
prev &&
|
|
1236
|
+
prev &&
|
|
1237
|
+
prev.inode === inode &&
|
|
1238
|
+
prev.size === size &&
|
|
1239
|
+
prev.mtimeMs === mtimeMs &&
|
|
1240
|
+
prev.opencodeForkRepairVersion === 1;
|
|
1237
1241
|
if (unchanged) {
|
|
1238
1242
|
filesProcessed += 1;
|
|
1239
1243
|
if (cb) {
|
|
@@ -1287,6 +1291,7 @@ async function parseOpencodeIncremental({
|
|
|
1287
1291
|
mtimeMs,
|
|
1288
1292
|
lastTotals: result.lastTotals,
|
|
1289
1293
|
messageKey: result.messageKey || null,
|
|
1294
|
+
opencodeForkRepairVersion: 1,
|
|
1290
1295
|
updatedAt: new Date().toISOString(),
|
|
1291
1296
|
};
|
|
1292
1297
|
|
|
@@ -1300,6 +1305,7 @@ async function parseOpencodeIncremental({
|
|
|
1300
1305
|
messageKey: result.messageKey,
|
|
1301
1306
|
totals: result.lastTotals,
|
|
1302
1307
|
fingerprint: result.fingerprint || null,
|
|
1308
|
+
dedupedForkCopy: result.dedupedForkCopy === true,
|
|
1303
1309
|
});
|
|
1304
1310
|
}
|
|
1305
1311
|
|
|
@@ -2630,16 +2636,41 @@ async function parseOpencodeMessageFile({
|
|
|
2630
2636
|
// `Session.fork` re-materialises the parent's prefix under new message ids in
|
|
2631
2637
|
// a new session — count it once (issue #426, see deriveOpencodeMessageFingerprint).
|
|
2632
2638
|
const fingerprint = deriveOpencodeMessageFingerprint({ msg, totals: currentTotals, source });
|
|
2633
|
-
if (
|
|
2634
|
-
|
|
2639
|
+
if (isOpencodeForkCopy(fingerprintIndex, fingerprint, messageKey)) {
|
|
2640
|
+
if (lastTotals && prev?.dedupedForkCopy !== true) {
|
|
2641
|
+
repairCountedOpencodeForkCopy({
|
|
2642
|
+
msg,
|
|
2643
|
+
totals: lastTotals,
|
|
2644
|
+
source,
|
|
2645
|
+
hourlyState,
|
|
2646
|
+
touchedBuckets,
|
|
2647
|
+
projectState,
|
|
2648
|
+
projectTouchedBuckets,
|
|
2649
|
+
projectRef,
|
|
2650
|
+
projectKey,
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
return {
|
|
2654
|
+
messageKey,
|
|
2655
|
+
lastTotals: currentTotals,
|
|
2656
|
+
fingerprint,
|
|
2657
|
+
dedupedForkCopy: true,
|
|
2658
|
+
eventsAggregated: 0,
|
|
2659
|
+
shouldUpdate: prev?.dedupedForkCopy !== true || !lastTotals,
|
|
2660
|
+
};
|
|
2635
2661
|
}
|
|
2636
2662
|
|
|
2637
|
-
|
|
2663
|
+
// A formerly deduped copy can become a genuinely distinct in-place update.
|
|
2664
|
+
// Its prior totals were removed from the buckets, so re-add the full current
|
|
2665
|
+
// snapshot instead of only the delta from the suppressed value.
|
|
2666
|
+
const effectiveLastTotals = prev?.dedupedForkCopy === true ? null : lastTotals;
|
|
2667
|
+
const delta = diffGeminiTotals(currentTotals, effectiveLastTotals);
|
|
2638
2668
|
if (!delta || isAllZeroUsage(delta)) {
|
|
2639
2669
|
return {
|
|
2640
2670
|
messageKey,
|
|
2641
2671
|
lastTotals: currentTotals,
|
|
2642
2672
|
fingerprint,
|
|
2673
|
+
dedupedForkCopy: false,
|
|
2643
2674
|
eventsAggregated: 0,
|
|
2644
2675
|
shouldUpdate: true,
|
|
2645
2676
|
};
|
|
@@ -2686,6 +2717,7 @@ async function parseOpencodeMessageFile({
|
|
|
2686
2717
|
messageKey,
|
|
2687
2718
|
lastTotals: currentTotals,
|
|
2688
2719
|
fingerprint,
|
|
2720
|
+
dedupedForkCopy: false,
|
|
2689
2721
|
eventsAggregated: 1,
|
|
2690
2722
|
shouldUpdate: true,
|
|
2691
2723
|
};
|
|
@@ -3276,13 +3308,15 @@ function deriveOpencodeMessageFingerprint({ msg, totals, source }) {
|
|
|
3276
3308
|
return crypto.createHash("sha256").update(raw).digest("base64url").slice(0, 22);
|
|
3277
3309
|
}
|
|
3278
3310
|
|
|
3279
|
-
// `fingerprint -> messageKey` for
|
|
3280
|
-
//
|
|
3281
|
-
//
|
|
3311
|
+
// `fingerprint -> messageKey` for counted messages in this cursor namespace.
|
|
3312
|
+
// Rebuilt per parse run. Pre-#426 entries are fingerprinted as they are read;
|
|
3313
|
+
// the first claims ownership and later cross-session matches are retracted from
|
|
3314
|
+
// persisted buckets once. Tombstoned copies never claim ownership themselves.
|
|
3282
3315
|
function buildOpencodeFingerprintIndex(messageIndex) {
|
|
3283
3316
|
const byFingerprint = new Map();
|
|
3284
3317
|
if (!messageIndex || typeof messageIndex !== "object") return byFingerprint;
|
|
3285
3318
|
for (const [key, entry] of Object.entries(messageIndex)) {
|
|
3319
|
+
if (entry?.dedupedForkCopy === true) continue;
|
|
3286
3320
|
const fingerprint = entry && typeof entry.fingerprint === "string" ? entry.fingerprint : null;
|
|
3287
3321
|
if (fingerprint && !byFingerprint.has(fingerprint)) byFingerprint.set(fingerprint, key);
|
|
3288
3322
|
}
|
|
@@ -3314,13 +3348,25 @@ function isOpencodeForkCopy(fingerprintIndex, fingerprint, messageKey) {
|
|
|
3314
3348
|
// cursor untouched. A falsy `fingerprint` means "unknown" and preserves whatever
|
|
3315
3349
|
// the entry already carried; a new one releases the old claim so a stale
|
|
3316
3350
|
// mid-stream snapshot cannot shadow an unrelated message later.
|
|
3317
|
-
function recordOpencodeMessage({
|
|
3351
|
+
function recordOpencodeMessage({
|
|
3352
|
+
messageIndex,
|
|
3353
|
+
fingerprintIndex,
|
|
3354
|
+
messageKey,
|
|
3355
|
+
totals,
|
|
3356
|
+
fingerprint,
|
|
3357
|
+
dedupedForkCopy = false,
|
|
3358
|
+
}) {
|
|
3318
3359
|
if (!messageIndex || !messageKey) return;
|
|
3319
3360
|
const prev = messageIndex[messageKey];
|
|
3320
3361
|
const prevTotals = prev && typeof prev.lastTotals === "object" ? prev.lastTotals : null;
|
|
3321
3362
|
const prevFingerprint = prev && typeof prev.fingerprint === "string" ? prev.fingerprint : null;
|
|
3322
3363
|
const nextFingerprint = fingerprint || prevFingerprint;
|
|
3323
|
-
|
|
3364
|
+
const prevDeduped = prev?.dedupedForkCopy === true;
|
|
3365
|
+
if (
|
|
3366
|
+
sameGeminiTotals(totals, prevTotals) &&
|
|
3367
|
+
prevFingerprint === nextFingerprint &&
|
|
3368
|
+
prevDeduped === Boolean(dedupedForkCopy)
|
|
3369
|
+
) return;
|
|
3324
3370
|
|
|
3325
3371
|
if (fingerprintIndex && prevFingerprint && prevFingerprint !== nextFingerprint) {
|
|
3326
3372
|
if (fingerprintIndex.get(prevFingerprint) === messageKey) {
|
|
@@ -3329,12 +3375,52 @@ function recordOpencodeMessage({ messageIndex, fingerprintIndex, messageKey, tot
|
|
|
3329
3375
|
}
|
|
3330
3376
|
const entry = { lastTotals: totals, updatedAt: new Date().toISOString() };
|
|
3331
3377
|
if (nextFingerprint) entry.fingerprint = nextFingerprint;
|
|
3378
|
+
if (dedupedForkCopy) entry.dedupedForkCopy = true;
|
|
3332
3379
|
messageIndex[messageKey] = entry;
|
|
3333
|
-
if (
|
|
3380
|
+
if (
|
|
3381
|
+
fingerprintIndex &&
|
|
3382
|
+
nextFingerprint &&
|
|
3383
|
+
!dedupedForkCopy &&
|
|
3384
|
+
!fingerprintIndex.has(nextFingerprint)
|
|
3385
|
+
) {
|
|
3334
3386
|
fingerprintIndex.set(nextFingerprint, messageKey);
|
|
3335
3387
|
}
|
|
3336
3388
|
}
|
|
3337
3389
|
|
|
3390
|
+
function repairCountedOpencodeForkCopy({
|
|
3391
|
+
msg,
|
|
3392
|
+
totals,
|
|
3393
|
+
source,
|
|
3394
|
+
hourlyState,
|
|
3395
|
+
touchedBuckets,
|
|
3396
|
+
projectState,
|
|
3397
|
+
projectTouchedBuckets,
|
|
3398
|
+
projectRef,
|
|
3399
|
+
projectKey,
|
|
3400
|
+
}) {
|
|
3401
|
+
const timestampMs = coerceEpochMs(msg?.time?.completed) || coerceEpochMs(msg?.time?.created);
|
|
3402
|
+
if (!timestampMs) return false;
|
|
3403
|
+
const bucketStart = toUtcHalfHourStart(new Date(timestampMs).toISOString());
|
|
3404
|
+
if (!bucketStart) return false;
|
|
3405
|
+
const model = normalizeModelInput(msg?.modelID || msg?.model || msg?.modelId) || DEFAULT_MODEL;
|
|
3406
|
+
const counted = { ...totals, conversation_count: 1 };
|
|
3407
|
+
const bucket = getHourlyBucket(hourlyState, source, model, bucketStart);
|
|
3408
|
+
subtractTotals(bucket.totals, counted);
|
|
3409
|
+
touchedBuckets.add(bucketKey(source, model, bucketStart));
|
|
3410
|
+
if (projectKey && projectState && projectTouchedBuckets) {
|
|
3411
|
+
const projectBucket = getProjectBucket(
|
|
3412
|
+
projectState,
|
|
3413
|
+
projectKey,
|
|
3414
|
+
source,
|
|
3415
|
+
bucketStart,
|
|
3416
|
+
projectRef,
|
|
3417
|
+
);
|
|
3418
|
+
subtractTotals(projectBucket.totals, counted);
|
|
3419
|
+
projectTouchedBuckets.add(projectBucketKey(projectKey, source, bucketStart));
|
|
3420
|
+
}
|
|
3421
|
+
return true;
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3338
3424
|
function getHourlyBucket(state, source, model, hourStart) {
|
|
3339
3425
|
const buckets = state.buckets;
|
|
3340
3426
|
const normalizedSource = normalizeSourceInput(source) || DEFAULT_SOURCE;
|
|
@@ -4390,19 +4476,53 @@ async function parseOpencodeDbIncremental({
|
|
|
4390
4476
|
continue;
|
|
4391
4477
|
}
|
|
4392
4478
|
|
|
4393
|
-
// A fork copy of an already-counted turn contributes nothing
|
|
4394
|
-
//
|
|
4479
|
+
// A fork copy of an already-counted turn contributes nothing. Existing
|
|
4480
|
+
// pre-#426 cursor entries were already added to hourly/project buckets;
|
|
4481
|
+
// retract those once, then persist a tombstone so a later sync is a no-op.
|
|
4395
4482
|
const fingerprint = deriveOpencodeMessageFingerprint({
|
|
4396
4483
|
msg,
|
|
4397
4484
|
totals: currentTotals,
|
|
4398
4485
|
source: defaultSource,
|
|
4399
4486
|
});
|
|
4400
|
-
if (
|
|
4487
|
+
if (isOpencodeForkCopy(fingerprintIndex, fingerprint, messageKey)) {
|
|
4488
|
+
let projectContext = null;
|
|
4489
|
+
if (lastTotals && prev?.dedupedForkCopy !== true && projectEnabled) {
|
|
4490
|
+
projectContext = await resolveProjectContextForDb({
|
|
4491
|
+
msg,
|
|
4492
|
+
dbPath,
|
|
4493
|
+
projectMetaCache,
|
|
4494
|
+
publicRepoCache,
|
|
4495
|
+
publicRepoResolver,
|
|
4496
|
+
projectState,
|
|
4497
|
+
});
|
|
4498
|
+
}
|
|
4499
|
+
if (lastTotals && prev?.dedupedForkCopy !== true) {
|
|
4500
|
+
repairCountedOpencodeForkCopy({
|
|
4501
|
+
msg,
|
|
4502
|
+
totals: lastTotals,
|
|
4503
|
+
source: defaultSource,
|
|
4504
|
+
hourlyState,
|
|
4505
|
+
touchedBuckets,
|
|
4506
|
+
projectState,
|
|
4507
|
+
projectTouchedBuckets,
|
|
4508
|
+
projectRef: projectContext?.projectRef || null,
|
|
4509
|
+
projectKey: projectContext?.projectKey || null,
|
|
4510
|
+
});
|
|
4511
|
+
}
|
|
4512
|
+
recordOpencodeMessage({
|
|
4513
|
+
messageIndex,
|
|
4514
|
+
fingerprintIndex,
|
|
4515
|
+
messageKey,
|
|
4516
|
+
totals: currentTotals,
|
|
4517
|
+
fingerprint,
|
|
4518
|
+
dedupedForkCopy: true,
|
|
4519
|
+
});
|
|
4401
4520
|
messagesProcessed += 1;
|
|
4402
4521
|
continue;
|
|
4403
4522
|
}
|
|
4404
4523
|
|
|
4405
|
-
const
|
|
4524
|
+
const effectiveLastTotals = prev?.dedupedForkCopy === true ? null : lastTotals;
|
|
4525
|
+
const delta = diffGeminiTotals(currentTotals, effectiveLastTotals);
|
|
4406
4526
|
if (!delta || isAllZeroUsage(delta)) {
|
|
4407
4527
|
// Refresh the index even without a delta: normalization may have changed,
|
|
4408
4528
|
// and pre-#426 entries need their fingerprint backfilled so a fork taken
|
|
@@ -4413,6 +4533,7 @@ async function parseOpencodeDbIncremental({
|
|
|
4413
4533
|
messageKey,
|
|
4414
4534
|
totals: currentTotals,
|
|
4415
4535
|
fingerprint,
|
|
4536
|
+
dedupedForkCopy: false,
|
|
4416
4537
|
});
|
|
4417
4538
|
messagesProcessed += 1;
|
|
4418
4539
|
if (cb) {
|
|
@@ -4476,6 +4597,7 @@ async function parseOpencodeDbIncremental({
|
|
|
4476
4597
|
messageKey,
|
|
4477
4598
|
totals: currentTotals,
|
|
4478
4599
|
fingerprint,
|
|
4600
|
+
dedupedForkCopy: false,
|
|
4479
4601
|
});
|
|
4480
4602
|
messagesProcessed += 1;
|
|
4481
4603
|
eventsAggregated += 1;
|