tokentracker-cli 0.87.9 → 0.87.10
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-D3_hERkQ.js → AchievementBadge-BG9bVXuQ.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-DZGjT92g.js → AchievementsPage-DwYIajgz.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-CEzq3U3A.js → AchievementsSection-BPuhWCWC.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-D3_B8E--.js → BadgeDetailModal-BU81AHIH.js} +1 -1
- package/dashboard/dist/assets/{Card-CMXM3-lp.js → Card-CxiGV6bE.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-lQxUKRzw.js → ClawdAnimated-NHcv2_KK.js} +1 -1
- package/dashboard/dist/assets/{CommandPalette-BCGdAeFB.js → CommandPalette-BKmTa5b8.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-BwE5h2y5.js → CommunityStatsModal-nhHtSw7U.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-8uhS2ccj.js → ConfirmModal-DCicMVqg.js} +1 -1
- package/dashboard/dist/assets/{Controls-CBEQTl2X.js → Controls-CtjjJ8gt.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-UE_3tGVy.js → DashboardPage-BL-NfLIM.js} +1 -1
- package/dashboard/dist/assets/DevicePage-DuIiuci7.js +1 -0
- package/dashboard/dist/assets/{DialogClose-L_t-nrYm.js → DialogClose-8GK6rJCf.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-C9StmaUp.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-Bsft4VvL.js → DialogTitle-EBphaJIt.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-BNDdLqTu.js → FadeIn-B8099njp.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-CvNaKDbl.js → HeaderGithubStar-Cyxc4vKa.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-D5j5IpNx.js → HoverTooltip-BcXNDc20.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-Csf8gMJW.js → IpCheckPage-Bn5aOiJK.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-BVSSwM0D.js → LandingPage-BMbP2M_2.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-DXxSHqmP.js → LeaderboardAvatar-sRNGsVJE.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-DXj21BBR.js → LeaderboardPage-DUv9hCNQ.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-DbEzZGg4.js → LeaderboardProfileModal-D66DzEVL.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-DoIm3jB_.js → LeaderboardProfilePage-CWzNEHjJ.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-D_tpQrUM.js → LimitsPage-B7dTsxXt.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-DBi5iuPr.js → LocalOnlyNotice-BCR-4Ipk.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-qDIJgUX1.js → LoginCard-Dt7v1Pgi.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-D4b5p4u1.js → LoginModal-BaKS0AvW.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-CsSgItFA.js → LoginPage-J7ir_N3K.js} +1 -1
- package/dashboard/dist/assets/{PetPage-B-wElg5q.js → PetPage-uAxjE9Vs.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-9C_VarUQ.js → PopoverPopup-WRGNwhEe.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-CciEdEeR.js → ProviderIcon-BTZXNlML.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-lsI8qlzE.js → ResetPasswordPage-B_TvqHvF.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-BGonMV45.js → SegmentedControl-C1NPnzuC.js} +1 -1
- package/dashboard/dist/assets/{Select-DhRrGrDT.js → Select-DetlANRp.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-ClMYgZsa.js → SelectItemText-CdhCuD7u.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-DuzttgL7.js → ServiceStatusPage-yMTV03js.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-gZbxx0f_.js → SessionsPage-rJw-lY6d.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-NhxTrVNW.js → SettingsPage-BHIGCXa8.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-BeXojJqQ.js → SkillsPage-BZTTHrKR.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-DM49zKzo.js → TokenGalaxy-D2tFBs42.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-BfvoVNMW.js → ToolbarRootContext-CD4Dh9IV.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-Bu-dXcrV.js → TrendMonitor-mL7Z3Pu9.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-D2Wo7seE.js → WidgetsPage-Dech66hD.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-BXAwic4D.js → WrappedPage-CYaLijy2.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-BDEQk--l.js → __vite-browser-external-CcMKDoRA.js} +2 -2
- package/dashboard/dist/assets/{agent-logos-DMEEHjG7.js → agent-logos-BzFhwsm5.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-gNviKtY8.js → arrow-up-right-TrcWBi5O.js} +1 -1
- package/dashboard/dist/assets/{check-Cvg5pmYP.js → check-CKWLtHpO.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-DxdaNTo8.js → chevron-right-BjL_B3tf.js} +1 -1
- package/dashboard/dist/assets/{copy-BNIJL7bf.js → copy-B5XqmEDV.js} +1 -1
- package/dashboard/dist/assets/{download-C9McJlPa.js → download-BtVO_3_3.js} +1 -1
- package/dashboard/dist/assets/{external-link-C_IU6zDK.js → external-link-CTpQdeXU.js} +1 -1
- package/dashboard/dist/assets/{flame-CII7X8Je.js → flame-CMixyq1C.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-DuQbGpPt.js → format-tokens-DOgiRUv2.js} +1 -1
- package/dashboard/dist/assets/{icons-B1YTqnxG.js → icons-DNpysD5S.js} +1 -1
- package/dashboard/dist/assets/{index-BRMxraNK.js → index-B7Zuq72U.js} +1 -1
- package/dashboard/dist/assets/{index-QtcYir6O.js → index-Dadn8f0V.js} +1 -1
- package/dashboard/dist/assets/{index-Dc9xsIu2.js → index-k5haeuyB.js} +1 -1
- package/dashboard/dist/assets/{info-CIgVqJoj.js → info-CodBJXwL.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-B31NsGar.js → limits-providers-DiSK8fij.js} +1 -1
- package/dashboard/dist/assets/{link-2-DTPXzHuB.js → link-2-BE84-D1K.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-CgQSyCz8.js → loader-circle-62hGDJej.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-BL5J4aHZ.js → maximize-2-Dn0j7N4g.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-s_rzcEf2.js → modifiers.esm-D48EfMXn.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-C9ei_xde.js → monitor-smartphone-B4O-1qqp.js} +1 -1
- package/dashboard/dist/assets/{provider-display-ZgvoJi05.js → provider-display-BBlUUXou.js} +1 -1
- package/dashboard/dist/assets/{react-DhfPVGOm.js → react-B7hdp-KU.js} +1 -1
- package/dashboard/dist/assets/{search-Ba_MWO7q.js → search-DYcfh3D9.js} +1 -1
- package/dashboard/dist/assets/{skills-api-BkmJmyg1.js → skills-api-BL0Jj4TS.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-Bmd5t12E.js → sortable.esm-UJyxEfLh.js} +1 -1
- package/dashboard/dist/assets/{store-BxRQs9yc.js → store-koEJUHLx.js} +1 -1
- package/dashboard/dist/assets/{terminal-BzUwAs4g.js → terminal-CA8uz-Rp.js} +1 -1
- package/dashboard/dist/assets/{trash-2-CCprY7cu.js → trash-2-Cwdcw5RS.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-TCdPJ_ir.js → use-community-stats-BIBrzbia.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-CNF9luO6.js → use-limits-display-prefs-BCdQk1ck.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-BlTuSYJy.js → use-ordered-list-Bf9Ozum9.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-DGTFk58t.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-iHS0O_Fo.js → use-session-efficiency-pref-C83fbwfz.js} +1 -1
- package/dashboard/dist/assets/{use-transform-CcVfL3mi.js → use-transform-DnR7Iz0p.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-Xdy-Y_1Z.js → use-usage-limits-D_MtlDKv.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-IXccXbmx.js → useCurrency-DVO1i6vp.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-BEVewfZm.js → useScrollLock-CW2lrPuY.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-Cihv3Ghl.js → useTokenFormat-BFhS3XRy.js} +1 -1
- package/dashboard/dist/assets/{zap-zG2Fbb5_.js → zap-DCY5z8oI.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 +186 -1
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +232 -44
- package/dashboard/dist/assets/DevicePage-B06ybHJI.js +0 -1
- package/dashboard/dist/assets/DialogDescription-B7FFtR7A.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-CfiR91Eg.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -7842,9 +7842,8 @@ function resolveCodebuddyDefaultModel(env = process.env) {
|
|
|
7842
7842
|
|
|
7843
7843
|
// Modern CodeBuddy writes token usage into providerData.rawUsage on JSONL
|
|
7844
7844
|
// records. Older IDE installs may have no usable JSONL usage and rely on the
|
|
7845
|
-
// extension log fallback below. Keep the sniff bounded: it is used
|
|
7846
|
-
//
|
|
7847
|
-
// the same round trips.
|
|
7845
|
+
// extension log fallback below. Keep the sniff bounded: it is used by the
|
|
7846
|
+
// guarded historical migration to decide whether a JSONL rebuild is safe.
|
|
7848
7847
|
function codebuddyJsonlHasUsage(filePath) {
|
|
7849
7848
|
let fd;
|
|
7850
7849
|
try {
|
|
@@ -7875,6 +7874,60 @@ function codebuddyJsonlHasUsage(filePath) {
|
|
|
7875
7874
|
return false;
|
|
7876
7875
|
}
|
|
7877
7876
|
|
|
7877
|
+
// Legacy IDE extension logs and modern JSONL records do not share an id. Keep
|
|
7878
|
+
// a bounded, source-neutral fingerprint ledger so a log line can be matched to
|
|
7879
|
+
// the JSONL round-trip it mirrors without collapsing legitimate same-second
|
|
7880
|
+
// requests. The ledger is persisted in the CodeBuddy cursor because the two
|
|
7881
|
+
// sources can arrive on different syncs.
|
|
7882
|
+
function codebuddyUsageFingerprint({ model, timestampMs, inputTokens, cacheRead, cacheCreation, outputTokens, reasoningTokens }) {
|
|
7883
|
+
if (!Number.isFinite(Number(timestampMs)) || Number(timestampMs) <= 0) return null;
|
|
7884
|
+
const second = Math.floor(Number(timestampMs) / 1000);
|
|
7885
|
+
return [
|
|
7886
|
+
second,
|
|
7887
|
+
normalizeModelInput(model) || "unknown",
|
|
7888
|
+
toNonNegativeInt(inputTokens),
|
|
7889
|
+
toNonNegativeInt(cacheRead),
|
|
7890
|
+
toNonNegativeInt(cacheCreation),
|
|
7891
|
+
toNonNegativeInt(outputTokens),
|
|
7892
|
+
toNonNegativeInt(reasoningTokens),
|
|
7893
|
+
].join(":");
|
|
7894
|
+
}
|
|
7895
|
+
|
|
7896
|
+
function restoreCodebuddyUsageFingerprints(raw) {
|
|
7897
|
+
const state = new Map();
|
|
7898
|
+
if (!raw || typeof raw !== "object") return state;
|
|
7899
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
7900
|
+
const jsonl = toNonNegativeInt(value?.jsonl);
|
|
7901
|
+
const log = toNonNegativeInt(value?.log);
|
|
7902
|
+
if (jsonl > 0 || log > 0) state.set(key, { jsonl, log });
|
|
7903
|
+
}
|
|
7904
|
+
return state;
|
|
7905
|
+
}
|
|
7906
|
+
|
|
7907
|
+
function addCodebuddyJsonlFingerprint(state, fingerprint) {
|
|
7908
|
+
if (!fingerprint) return false;
|
|
7909
|
+
const current = state.get(fingerprint) || { jsonl: 0, log: 0 };
|
|
7910
|
+
const mirrored = current.log > current.jsonl;
|
|
7911
|
+
current.jsonl += 1;
|
|
7912
|
+
state.set(fingerprint, current);
|
|
7913
|
+
return mirrored;
|
|
7914
|
+
}
|
|
7915
|
+
|
|
7916
|
+
function consumeCodebuddyLogFingerprint(state, fingerprint) {
|
|
7917
|
+
if (!fingerprint) return false;
|
|
7918
|
+
const current = state.get(fingerprint) || { jsonl: 0, log: 0 };
|
|
7919
|
+
const mirrored = current.jsonl > current.log;
|
|
7920
|
+
current.log += 1;
|
|
7921
|
+
state.set(fingerprint, current);
|
|
7922
|
+
return mirrored;
|
|
7923
|
+
}
|
|
7924
|
+
|
|
7925
|
+
function capCodebuddyUsageFingerprints(state, maxEntries = 10_000) {
|
|
7926
|
+
const entries = Array.from(state.entries());
|
|
7927
|
+
if (entries.length <= maxEntries) return Object.fromEntries(entries);
|
|
7928
|
+
return Object.fromEntries(entries.slice(entries.length - maxEntries));
|
|
7929
|
+
}
|
|
7930
|
+
|
|
7878
7931
|
function resolveCodebuddyProjectFiles(env = process.env) {
|
|
7879
7932
|
const codebuddyHome = resolveCodebuddyHome(env);
|
|
7880
7933
|
const jsonlFiles = [];
|
|
@@ -7965,9 +8018,12 @@ function resolveCodebuddyProjectFiles(env = process.env) {
|
|
|
7965
8018
|
}
|
|
7966
8019
|
|
|
7967
8020
|
const fallbackMode = String(env.TOKENTRACKER_CODEBUDDY_LOG_FALLBACK || "").trim();
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
8021
|
+
// Auto mode keeps both sources available. The parser performs bounded,
|
|
8022
|
+
// count-aware cross-source fingerprint matching, so mixed histories retain
|
|
8023
|
+
// legacy-only log sessions while mirrored rounds are counted once. Env=0 is
|
|
8024
|
+
// still a supported escape hatch for users who want to suppress extension
|
|
8025
|
+
// logs entirely; env=1 remains an explicit force-on value.
|
|
8026
|
+
const includeLogs = fallbackMode !== "0";
|
|
7971
8027
|
const files = [...jsonlFiles, ...(includeLogs ? logFiles : [])];
|
|
7972
8028
|
files.sort((a, b) => a.localeCompare(b));
|
|
7973
8029
|
return files;
|
|
@@ -8030,10 +8086,21 @@ async function parseCodebuddyIncremental({
|
|
|
8030
8086
|
codebuddyState.logModelsByAgent && typeof codebuddyState.logModelsByAgent === "object"
|
|
8031
8087
|
? { ...codebuddyState.logModelsByAgent }
|
|
8032
8088
|
: {};
|
|
8089
|
+
const usageFingerprints = restoreCodebuddyUsageFingerprints(codebuddyState.usageFingerprints);
|
|
8033
8090
|
|
|
8034
|
-
const
|
|
8091
|
+
const discoveredFiles = Array.isArray(projectFiles)
|
|
8035
8092
|
? projectFiles
|
|
8036
8093
|
: resolveCodebuddyProjectFiles(env || process.env);
|
|
8094
|
+
// JSONL must be parsed before extension logs so the fingerprint ledger can
|
|
8095
|
+
// match mirrored rounds in the same sync. Keep the legacy bare-string API
|
|
8096
|
+
// accepted for callers and tests.
|
|
8097
|
+
const files = [...discoveredFiles].sort((a, b) => {
|
|
8098
|
+
const aPath = typeof a === "string" ? a : a?.path || "";
|
|
8099
|
+
const bPath = typeof b === "string" ? b : b?.path || "";
|
|
8100
|
+
const aLog = aPath.endsWith(".log") ? 1 : 0;
|
|
8101
|
+
const bLog = bPath.endsWith(".log") ? 1 : 0;
|
|
8102
|
+
return aLog - bLog || aPath.localeCompare(bPath);
|
|
8103
|
+
});
|
|
8037
8104
|
const fallbackModel = defaultModel || resolveCodebuddyDefaultModel(env || process.env);
|
|
8038
8105
|
|
|
8039
8106
|
if (files.length === 0) {
|
|
@@ -8041,6 +8108,7 @@ async function parseCodebuddyIncremental({
|
|
|
8041
8108
|
...codebuddyState,
|
|
8042
8109
|
seenIds: Array.from(seenIds),
|
|
8043
8110
|
fileOffsets,
|
|
8111
|
+
usageFingerprints: capCodebuddyUsageFingerprints(usageFingerprints),
|
|
8044
8112
|
updatedAt: new Date().toISOString(),
|
|
8045
8113
|
};
|
|
8046
8114
|
return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
@@ -8192,6 +8260,20 @@ async function parseCodebuddyIncremental({
|
|
|
8192
8260
|
fallbackModel;
|
|
8193
8261
|
const model = normalizeModelInput(rawModel);
|
|
8194
8262
|
|
|
8263
|
+
const fingerprint = codebuddyUsageFingerprint({
|
|
8264
|
+
model,
|
|
8265
|
+
timestampMs: tsMs,
|
|
8266
|
+
inputTokens,
|
|
8267
|
+
cacheRead,
|
|
8268
|
+
cacheCreation,
|
|
8269
|
+
outputTokens: completionTokens,
|
|
8270
|
+
reasoningTokens,
|
|
8271
|
+
});
|
|
8272
|
+
if (consumeCodebuddyLogFingerprint(usageFingerprints, fingerprint)) {
|
|
8273
|
+
seenIds.add(messageId);
|
|
8274
|
+
continue;
|
|
8275
|
+
}
|
|
8276
|
+
|
|
8195
8277
|
const delta = {
|
|
8196
8278
|
input_tokens: inputTokens,
|
|
8197
8279
|
cached_input_tokens: cacheRead,
|
|
@@ -8318,6 +8400,20 @@ async function parseCodebuddyIncremental({
|
|
|
8318
8400
|
normalizeModelInput(entry.model) ||
|
|
8319
8401
|
fallbackModel;
|
|
8320
8402
|
|
|
8403
|
+
const fingerprint = codebuddyUsageFingerprint({
|
|
8404
|
+
model,
|
|
8405
|
+
timestampMs: tsMs,
|
|
8406
|
+
inputTokens,
|
|
8407
|
+
cacheRead,
|
|
8408
|
+
cacheCreation,
|
|
8409
|
+
outputTokens: completionTokens,
|
|
8410
|
+
reasoningTokens,
|
|
8411
|
+
});
|
|
8412
|
+
if (addCodebuddyJsonlFingerprint(usageFingerprints, fingerprint)) {
|
|
8413
|
+
seenIds.add(messageId);
|
|
8414
|
+
continue;
|
|
8415
|
+
}
|
|
8416
|
+
|
|
8321
8417
|
const delta = {
|
|
8322
8418
|
input_tokens: inputTokens,
|
|
8323
8419
|
cached_input_tokens: cacheRead,
|
|
@@ -8333,6 +8429,13 @@ async function parseCodebuddyIncremental({
|
|
|
8333
8429
|
addTotals(bucket.totals, delta);
|
|
8334
8430
|
touchedBuckets.add(bucketKey("codebuddy", model, bucketStart));
|
|
8335
8431
|
seenIds.add(messageId);
|
|
8432
|
+
// Preserve the pre-fingerprint cursor key as well. Older releases
|
|
8433
|
+
// keyed JSONL rows by entry.id; retaining it prevents the first
|
|
8434
|
+
// post-upgrade sync from replaying an already-counted row when
|
|
8435
|
+
// providerData.messageId is now preferred.
|
|
8436
|
+
if (typeof entry.id === "string" && entry.id && entry.id !== messageId) {
|
|
8437
|
+
seenIds.add(entry.id);
|
|
8438
|
+
}
|
|
8336
8439
|
eventsAggregated++;
|
|
8337
8440
|
|
|
8338
8441
|
if (cb) {
|
|
@@ -8380,6 +8483,7 @@ async function parseCodebuddyIncremental({
|
|
|
8380
8483
|
seenIds: cappedSeen,
|
|
8381
8484
|
fileOffsets,
|
|
8382
8485
|
logModelsByAgent: cappedLogModelsByAgent,
|
|
8486
|
+
usageFingerprints: capCodebuddyUsageFingerprints(usageFingerprints),
|
|
8383
8487
|
updatedAt,
|
|
8384
8488
|
};
|
|
8385
8489
|
|
|
@@ -8433,9 +8537,11 @@ async function parseCodebuddyIncremental({
|
|
|
8433
8537
|
//
|
|
8434
8538
|
// 4. Completed ~/.workbuddy/traces/**/trace_*.json summaries expose aggregate
|
|
8435
8539
|
// modelInfo input/output/cache totals. They are a fallback only when the
|
|
8436
|
-
// session has no detailed JSONL usage
|
|
8437
|
-
//
|
|
8438
|
-
//
|
|
8540
|
+
// session has no detailed JSONL usage. The current SQLite session_usage
|
|
8541
|
+
// table exposes bounded context-window state (`used`/`size`) plus credits,
|
|
8542
|
+
// not billable token columns, so SQLite-only rows are ignored rather than
|
|
8543
|
+
// mislabelled as input usage. A future schema with explicit token columns
|
|
8544
|
+
// is accepted by workbuddySqliteUsageSnapshot.
|
|
8439
8545
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
8440
8546
|
|
|
8441
8547
|
function resolveWorkbuddyHome(env = process.env) {
|
|
@@ -8534,6 +8640,49 @@ function resolveWorkbuddyProjectFiles(env = process.env) {
|
|
|
8534
8640
|
return files;
|
|
8535
8641
|
}
|
|
8536
8642
|
|
|
8643
|
+
// WorkBuddy's current session_usage table stores context-window state in
|
|
8644
|
+
// `used`/`size` and model credit dollars in `credit_json`; neither is a token
|
|
8645
|
+
// accounting breakdown. Only consume a SQLite row when a future schema (or a
|
|
8646
|
+
// newer installation) exposes explicit cumulative token columns. This keeps
|
|
8647
|
+
// the fallback forward-compatible without treating a context snapshot as
|
|
8648
|
+
// billable usage.
|
|
8649
|
+
function workbuddySqliteUsageSnapshot(row) {
|
|
8650
|
+
if (!row || typeof row !== "object") return null;
|
|
8651
|
+
const hasAny = (keys) => keys.some((key) => Object.prototype.hasOwnProperty.call(row, key));
|
|
8652
|
+
const inputKeys = ["input_tokens", "inputTokens", "prompt_tokens", "promptTokens"];
|
|
8653
|
+
const cacheReadKeys = [
|
|
8654
|
+
"cached_input_tokens",
|
|
8655
|
+
"cachedInputTokens",
|
|
8656
|
+
"cache_read_input_tokens",
|
|
8657
|
+
"cacheReadInputTokens",
|
|
8658
|
+
"cache_read_tokens",
|
|
8659
|
+
"cacheReadTokens",
|
|
8660
|
+
];
|
|
8661
|
+
const cacheCreationKeys = [
|
|
8662
|
+
"cache_creation_input_tokens",
|
|
8663
|
+
"cacheCreationInputTokens",
|
|
8664
|
+
"prompt_cache_write_tokens",
|
|
8665
|
+
"promptCacheWriteTokens",
|
|
8666
|
+
];
|
|
8667
|
+
const outputKeys = ["output_tokens", "outputTokens", "completion_tokens", "completionTokens"];
|
|
8668
|
+
const reasoningKeys = [
|
|
8669
|
+
"reasoning_output_tokens",
|
|
8670
|
+
"reasoningOutputTokens",
|
|
8671
|
+
"reasoning_tokens",
|
|
8672
|
+
"reasoningTokens",
|
|
8673
|
+
];
|
|
8674
|
+
if (!hasAny([...inputKeys, ...cacheReadKeys, ...cacheCreationKeys, ...outputKeys, ...reasoningKeys])) {
|
|
8675
|
+
return null;
|
|
8676
|
+
}
|
|
8677
|
+
return {
|
|
8678
|
+
input: firstPresentNonNegativeInt(inputKeys.map((key) => row[key])),
|
|
8679
|
+
cacheRead: firstPresentNonNegativeInt(cacheReadKeys.map((key) => row[key])),
|
|
8680
|
+
cacheCreation: firstPresentNonNegativeInt(cacheCreationKeys.map((key) => row[key])),
|
|
8681
|
+
output: firstPresentNonNegativeInt(outputKeys.map((key) => row[key])),
|
|
8682
|
+
reasoning: firstPresentNonNegativeInt(reasoningKeys.map((key) => row[key])),
|
|
8683
|
+
};
|
|
8684
|
+
}
|
|
8685
|
+
|
|
8537
8686
|
async function parseWorkbuddyIncremental({
|
|
8538
8687
|
projectFiles,
|
|
8539
8688
|
cursors,
|
|
@@ -8641,26 +8790,28 @@ async function parseWorkbuddyIncremental({
|
|
|
8641
8790
|
typeof entry.sessionId === "string" && entry.sessionId
|
|
8642
8791
|
? entry.sessionId
|
|
8643
8792
|
: path.basename(filePath, ".jsonl");
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
tracedSessionIds.has(sessionId)
|
|
8647
|
-
) {
|
|
8793
|
+
const sqliteSession = sqliteSessions[sessionId];
|
|
8794
|
+
if (sqliteSession?.detailed || tracedSessionIds.has(sessionId)) {
|
|
8648
8795
|
continue;
|
|
8649
8796
|
}
|
|
8650
8797
|
const tsMs =
|
|
8651
8798
|
Number.isFinite(Number(entry.timestamp)) && Number(entry.timestamp) > 0
|
|
8652
8799
|
? Number(entry.timestamp)
|
|
8653
8800
|
: null;
|
|
8654
|
-
// One usage record per LLM round-trip;
|
|
8655
|
-
//
|
|
8801
|
+
// One usage record per LLM round-trip; providerData.messageId is the
|
|
8802
|
+
// response-level id shared by function_call/message records and must win
|
|
8803
|
+
// over the per-record append id. Fall back to entry.uuid/id only when the
|
|
8804
|
+
// response-level id is absent.
|
|
8656
8805
|
const messageId =
|
|
8657
|
-
typeof
|
|
8658
|
-
? entry.id
|
|
8659
|
-
: typeof provider.messageId === "string" && provider.messageId
|
|
8806
|
+
typeof provider?.messageId === "string" && provider.messageId
|
|
8660
8807
|
? provider.messageId
|
|
8661
|
-
:
|
|
8662
|
-
?
|
|
8663
|
-
:
|
|
8808
|
+
: typeof entry.uuid === "string" && entry.uuid
|
|
8809
|
+
? entry.uuid
|
|
8810
|
+
: typeof entry.id === "string" && entry.id
|
|
8811
|
+
? entry.id
|
|
8812
|
+
: tsMs != null
|
|
8813
|
+
? `${sessionId}:${tsMs}`
|
|
8814
|
+
: null;
|
|
8664
8815
|
if (!messageId) continue;
|
|
8665
8816
|
if (seenIds.has(messageId)) continue;
|
|
8666
8817
|
|
|
@@ -8732,6 +8883,11 @@ async function parseWorkbuddyIncremental({
|
|
|
8732
8883
|
addTotals(bucket.totals, delta);
|
|
8733
8884
|
touchedBuckets.add(bucketKey("workbuddy", model, bucketStart));
|
|
8734
8885
|
seenIds.add(messageId);
|
|
8886
|
+
// Keep legacy entry-id keys alongside the response id so upgrading a
|
|
8887
|
+
// cursor cannot replay a row that an older build already counted.
|
|
8888
|
+
if (typeof entry.id === "string" && entry.id && entry.id !== messageId) {
|
|
8889
|
+
seenIds.add(entry.id);
|
|
8890
|
+
}
|
|
8735
8891
|
detailedSessions[sessionId] = true;
|
|
8736
8892
|
detailedSessionsWithUsage.add(sessionId);
|
|
8737
8893
|
eventsAggregated++;
|
|
@@ -8852,11 +9008,9 @@ async function parseWorkbuddyIncremental({
|
|
|
8852
9008
|
if (dbExists) {
|
|
8853
9009
|
const query = `
|
|
8854
9010
|
SELECT
|
|
8855
|
-
su
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
s.model,
|
|
8859
|
-
s.cwd
|
|
9011
|
+
su.*,
|
|
9012
|
+
s.model AS session_model,
|
|
9013
|
+
s.cwd AS session_cwd
|
|
8860
9014
|
FROM session_usage su
|
|
8861
9015
|
LEFT JOIN sessions s ON s.id = su.session_id
|
|
8862
9016
|
WHERE su.used IS NOT NULL
|
|
@@ -8887,33 +9041,68 @@ async function parseWorkbuddyIncremental({
|
|
|
8887
9041
|
tracedSessionIds.has(sessionId)
|
|
8888
9042
|
) continue;
|
|
8889
9043
|
|
|
8890
|
-
const usedNow = toNonNegativeInt(row.used);
|
|
8891
9044
|
const updatedAtRaw = toNonNegativeInt(row.updated_at);
|
|
8892
|
-
const rawModel = typeof row.
|
|
9045
|
+
const rawModel = typeof row.session_model === "string"
|
|
9046
|
+
? row.session_model.trim()
|
|
9047
|
+
: typeof row.model === "string" ? row.model.trim() : "";
|
|
8893
9048
|
|
|
8894
|
-
if (
|
|
9049
|
+
if (updatedAtRaw <= 0) continue;
|
|
9050
|
+
|
|
9051
|
+
const snapshot = workbuddySqliteUsageSnapshot(row);
|
|
9052
|
+
const usedNow = toNonNegativeInt(row.used);
|
|
9053
|
+
const prev = sqliteSessions[sessionId] || {};
|
|
8895
9054
|
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
9055
|
+
// Current WorkBuddy releases expose only context state (`used` versus
|
|
9056
|
+
// `size`) here. Do not turn that bounded snapshot into a fake usage
|
|
9057
|
+
// delta; detailed JSONL/trace sources remain the authoritative path.
|
|
9058
|
+
if (!snapshot) {
|
|
9059
|
+
sqliteSessions[sessionId] = {
|
|
9060
|
+
...prev,
|
|
9061
|
+
used: usedNow,
|
|
9062
|
+
updatedAt: updatedAtRaw,
|
|
9063
|
+
model: rawModel || prev.model || fallbackModel,
|
|
9064
|
+
detailed: false,
|
|
9065
|
+
};
|
|
9066
|
+
continue;
|
|
9067
|
+
}
|
|
9068
|
+
|
|
9069
|
+
const previousTokens = prev.tokens && typeof prev.tokens === "object"
|
|
9070
|
+
? prev.tokens
|
|
9071
|
+
: { input: 0, cacheRead: 0, cacheCreation: 0, output: 0, reasoning: 0 };
|
|
9072
|
+
const isReset = ["input", "cacheRead", "cacheCreation", "output", "reasoning"]
|
|
9073
|
+
.some((key) => snapshot[key] < toNonNegativeInt(previousTokens[key]));
|
|
9074
|
+
const deltaTokens = {
|
|
9075
|
+
input: isReset ? snapshot.input : Math.max(0, snapshot.input - toNonNegativeInt(previousTokens.input)),
|
|
9076
|
+
cacheRead: isReset ? snapshot.cacheRead : Math.max(0, snapshot.cacheRead - toNonNegativeInt(previousTokens.cacheRead)),
|
|
9077
|
+
cacheCreation: isReset ? snapshot.cacheCreation : Math.max(0, snapshot.cacheCreation - toNonNegativeInt(previousTokens.cacheCreation)),
|
|
9078
|
+
output: isReset ? snapshot.output : Math.max(0, snapshot.output - toNonNegativeInt(previousTokens.output)),
|
|
9079
|
+
reasoning: isReset ? snapshot.reasoning : Math.max(0, snapshot.reasoning - toNonNegativeInt(previousTokens.reasoning)),
|
|
9080
|
+
};
|
|
9081
|
+
if (
|
|
9082
|
+
deltaTokens.input === 0 &&
|
|
9083
|
+
deltaTokens.cacheRead === 0 &&
|
|
9084
|
+
deltaTokens.cacheCreation === 0 &&
|
|
9085
|
+
deltaTokens.output === 0 &&
|
|
9086
|
+
deltaTokens.reasoning === 0
|
|
9087
|
+
) {
|
|
8901
9088
|
sqliteSessions[sessionId] = {
|
|
8902
9089
|
...prev,
|
|
8903
9090
|
used: usedNow,
|
|
8904
9091
|
updatedAt: updatedAtRaw,
|
|
8905
9092
|
model: rawModel || prev.model || fallbackModel,
|
|
9093
|
+
tokens: snapshot,
|
|
9094
|
+
detailed: true,
|
|
8906
9095
|
};
|
|
8907
9096
|
continue;
|
|
8908
9097
|
}
|
|
8909
9098
|
|
|
8910
9099
|
recordsProcessed++;
|
|
8911
9100
|
|
|
8912
|
-
const inputTokens =
|
|
8913
|
-
const completionTokens =
|
|
8914
|
-
const cacheRead =
|
|
8915
|
-
const cacheCreation =
|
|
8916
|
-
const reasoningTokens =
|
|
9101
|
+
const inputTokens = deltaTokens.input;
|
|
9102
|
+
const completionTokens = deltaTokens.output;
|
|
9103
|
+
const cacheRead = deltaTokens.cacheRead;
|
|
9104
|
+
const cacheCreation = deltaTokens.cacheCreation;
|
|
9105
|
+
const reasoningTokens = deltaTokens.reasoning;
|
|
8917
9106
|
|
|
8918
9107
|
const tsMs = updatedAtRaw > 10000000000 ? updatedAtRaw : updatedAtRaw * 1000;
|
|
8919
9108
|
const tsIso = new Date(tsMs).toISOString();
|
|
@@ -8922,9 +9111,6 @@ async function parseWorkbuddyIncremental({
|
|
|
8922
9111
|
|
|
8923
9112
|
const model = normalizeModelInput(rawModel) || fallbackModel;
|
|
8924
9113
|
|
|
8925
|
-
// session_usage only exposes a cumulative `used` value. It has no
|
|
8926
|
-
// output/cache/reasoning columns, so SQLite-only history can safely
|
|
8927
|
-
// contribute input/total but must not invent a token split.
|
|
8928
9114
|
const delta = {
|
|
8929
9115
|
input_tokens: inputTokens,
|
|
8930
9116
|
cached_input_tokens: cacheRead,
|
|
@@ -8932,7 +9118,7 @@ async function parseWorkbuddyIncremental({
|
|
|
8932
9118
|
output_tokens: completionTokens,
|
|
8933
9119
|
reasoning_output_tokens: reasoningTokens,
|
|
8934
9120
|
total_tokens: inputTokens + completionTokens + cacheRead + cacheCreation + reasoningTokens,
|
|
8935
|
-
conversation_count:
|
|
9121
|
+
conversation_count: Object.keys(previousTokens).every((key) => toNonNegativeInt(previousTokens[key]) === 0) || isReset ? 1 : 0,
|
|
8936
9122
|
};
|
|
8937
9123
|
|
|
8938
9124
|
const bucket = getHourlyBucket(hourlyState, "workbuddy", model, bucketStart);
|
|
@@ -8942,6 +9128,8 @@ async function parseWorkbuddyIncremental({
|
|
|
8942
9128
|
used: usedNow,
|
|
8943
9129
|
updatedAt: updatedAtRaw,
|
|
8944
9130
|
model,
|
|
9131
|
+
tokens: snapshot,
|
|
9132
|
+
detailed: true,
|
|
8945
9133
|
};
|
|
8946
9134
|
eventsAggregated++;
|
|
8947
9135
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as b,r as l,j as r,c as e,i as v}from"./__vite-browser-external-BDEQk--l.js";const x={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1,VITE_APP_VERSION:"0.87.9",VITE_INSFORGE_ANON_KEY:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3OC0xMjM0LTU2NzgtOTBhYi1jZGVmMTIzNDU2NzgiLCJlbWFpbCI6ImFub25AaW5zZm9yZ2UuY29tIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODExNDU5NDd9.T0auta_IrVIh0uXW1bob5QSnzvsnJmN28r5XkSGEuQY",VITE_INSFORGE_BASE_URL:"https://srctyff5.us-east.insforge.app"};function f(){return v(),`${(x&&"https://srctyff5.us-east.insforge.app"||"https://srctyff5.us-east.insforge.app").replace(/\/$/,"")}/functions/tokentracker-device-flow-grant`}function p(s){return(s||"").toUpperCase().replace(/\s+/g,"").replace(/[^A-Z0-9-]/g,"")}function h(){const s=b(),[m,g]=l.useState(""),[i,a]=l.useState({kind:"idle",message:""});l.useEffect(()=>{try{const d=new URLSearchParams(window.location.search).get("user_code");d&&g(p(d))}catch{}},[]);async function u(c){if(c?.preventDefault?.(),!s?.signedIn){a({kind:"error",message:e("device.approval.error.sign_in")});return}const d=p(m);if(!/^[A-HJKMNP-Z2-9]{4}-[A-HJKMNP-Z2-9]{4}$/.test(d)){a({kind:"error",message:e("device.approval.error.invalid_code")});return}a({kind:"working",message:e("device.approval.action.approving")});try{const n=await s.getAccessToken?.();if(!n){a({kind:"error",message:e("device.approval.error.no_token")});return}const o=await fetch(f(),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({user_code:d})}),t=await o.json().catch(()=>({}));o.ok?a({kind:"success",message:t.status==="already_approved"?t.client_info?e("device.approval.success.already_client",{client:t.client_info}):e("device.approval.success.already"):t.client_info?e("device.approval.success.approved_client",{client:t.client_info}):e("device.approval.success.approved")}):o.status===404?a({kind:"error",message:e("device.approval.error.not_found")}):o.status===410?a({kind:"error",message:e("device.approval.error.expired")}):o.status===401?a({kind:"error",message:e("device.approval.error.session_expired")}):a({kind:"error",message:t?.error?e("device.approval.error.server_detail",{message:t.error}):e("device.approval.error.server",{status:o.status})})}catch(n){a({kind:"error",message:e("device.approval.error.network",{message:n?.message||n})})}}return r.jsx("div",{className:"min-h-screen flex items-center justify-center bg-white dark:bg-oai-gray-950 px-6 py-12",children:r.jsxs("div",{className:"w-full max-w-md rounded-xl border border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-900 p-8",children:[r.jsx("h1",{className:"text-2xl font-semibold text-oai-gray-900 dark:text-white mb-2",children:e("device.approval.title")}),r.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400 mb-6",children:e("device.approval.description")}),s?.signedIn?null:r.jsx("div",{className:"rounded-md border border-amber-200 bg-amber-50 dark:bg-amber-900/20 dark:border-amber-800 p-4 mb-4",children:r.jsx("p",{className:"text-sm text-amber-700 dark:text-amber-300",children:e("device.approval.sign_in_banner")})}),r.jsxs("form",{onSubmit:u,className:"space-y-4",children:[r.jsxs("label",{className:"block",children:[r.jsx("span",{className:"block text-xs font-medium uppercase tracking-wide text-oai-gray-500 dark:text-oai-gray-400 mb-1",children:e("device.approval.code_label")}),r.jsx("input",{type:"text",value:m,onChange:c=>g(p(c.target.value)),placeholder:"XXXX-XXXX",spellCheck:!1,autoCapitalize:"characters",maxLength:9,className:"w-full font-mono text-xl tracking-widest text-center rounded-md border border-oai-gray-300 dark:border-oai-gray-700 bg-white dark:bg-oai-gray-900 text-oai-gray-900 dark:text-white px-4 py-3 focus:outline-none focus:ring-inset focus:ring-2 focus:ring-emerald-600"})]}),r.jsx("button",{type:"submit",disabled:i.kind==="working"||!s?.signedIn,className:"w-full rounded-md bg-emerald-600 hover:bg-emerald-500 disabled:bg-oai-gray-300 disabled:cursor-not-allowed text-white font-medium py-3 transition-colors",children:i.kind==="working"?e("device.approval.action.approving"):e("device.approval.action.approve")})]}),i.kind==="success"&&r.jsx("div",{className:"mt-4 rounded-md border border-emerald-200 bg-emerald-50 dark:bg-emerald-900/20 dark:border-emerald-800 p-4",children:r.jsx("p",{className:"text-sm text-emerald-700 dark:text-emerald-300",children:i.message})}),i.kind==="error"&&r.jsx("div",{className:"mt-4 rounded-md border border-red-200 bg-red-50 dark:bg-red-900/20 dark:border-red-800 p-4",children:r.jsx("p",{className:"text-sm text-red-700 dark:text-red-300",children:i.message})})]})})}export{h as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as n,z as a}from"./__vite-browser-external-BDEQk--l.js";import{u as p}from"./DialogTitle-Bsft4VvL.js";import{u as c}from"./useScrollLock-BEVewfZm.js";const x=n.forwardRef(function(e,r){const{render:l,className:u,style:m,id:s,...t}=e,{store:i}=p(),o=c(s);return i.useSyncedValueWithCleanup("descriptionElementId",o),a("p",e,{ref:r,props:[{id:o},t]})});export{x as D};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as o}from"./__vite-browser-external-BDEQk--l.js";import{h as r,i as t,p as s}from"./react-DhfPVGOm.js";function i(){!r.current&&t();const[e]=o.useState(s.current);return e}export{i as u};
|