tokentracker-cli 0.99.0 → 1.0.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 +6 -5
- package/README.ja.md +6 -5
- package/README.ko.md +6 -5
- package/README.md +7 -5
- package/README.zh-CN.md +6 -5
- package/dashboard/dist/assets/{AchievementBadge-kRsjlB3p.js → AchievementBadge-pib0F8p8.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-C3xybY0k.js → AchievementsPage-BMnub6CL.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-y5mok2w0.js → AchievementsSection-DG_-yxAt.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-IFLXYuKp.js → BadgeDetailModal-Sk2dHIkJ.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-D6x0PDt2.js → BotAnimated-VwwvOniA.js} +1 -1
- package/dashboard/dist/assets/{Card-CiKwEyVu.js → Card-COfjRX96.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-BQFcAIOy.js → ClawdAnimated-C3sF5c29.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-BvpX8PM_.js → CommandPalette-DvJFPsR2.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-D5rNlwfO.js → CommunityStatsModal-DfYHIeKr.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-CR0Evu8-.js → ConfirmModal-DtoHm0RD.js} +1 -1
- package/dashboard/dist/assets/{Controls-lyLUkbJW.js → Controls-DHHn10dy.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-X8CLr_au.js → DashboardPage-DJ_nDPjA.js} +1 -1
- package/dashboard/dist/assets/DevicePage-DlXWUpau.js +1 -0
- package/dashboard/dist/assets/{DialogClose-Bplj_718.js → DialogClose-BLegTe7F.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-Dl_wqXjc.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-Ckzf1tdi.js → DialogTitle-BZb-SEg0.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-C2Jqe95f.js → FadeIn-Dsk0V4DK.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-DgE7Cd5u.js → HeaderGithubStar-B20nLMWQ.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-CEmo0N-P.js → HoverTooltip-tGFmzZiJ.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-BwkpsLaF.js → IpCheckPage-BK7XI_aT.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-CA2klwbE.js → LandingPage-BYX6NXbl.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-B_PUenGZ.js → LeaderboardAvatar-CIDqKSNn.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-D6HGW3jX.js → LeaderboardPage-BxIpRUwn.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-Bfo1dSsS.js → LeaderboardProfileModal-DJlNN9YG.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-2OqwrqOs.js → LeaderboardProfilePage-D4HSgrjG.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-BHrkLXHZ.js → LimitsPage-BKTMBbKS.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-C45MmWYt.js → LocalOnlyNotice-DpZiPX4A.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-BikBibax.js → LoginCard-Cd03cg54.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-D0Aq85Zg.js → LoginModal-yPZi5JsE.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-B-kQaDQ_.js → LoginPage-BTL9oeVV.js} +1 -1
- package/dashboard/dist/assets/{PetPage-ZgPREiwD.js → PetPage-BWMSKd_3.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-eQgg3h1i.js → PopoverPopup-Dba9PYte.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-nDBPxn0N.js → ProviderIcon-DXI7Ztov.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-CjsOtiGr.js → ResetPasswordPage-wKDU07tl.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-6NcttkEH.js → SegmentedControl-DZh5rJHn.js} +1 -1
- package/dashboard/dist/assets/{Select-CzEhPICe.js → Select-CiJIsDf1.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-BwvzfXwj.js → SelectItemText-B8YkLJtE.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-C35wpxrT.js → ServiceStatusPage-CF_bMZMz.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-a30adkhf.js → SessionsPage-B0PnK1TY.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-C_7ZPBUF.js → SettingsPage-onYZIk-h.js} +2 -2
- package/dashboard/dist/assets/{SkillsPage-DsxkFnrV.js → SkillsPage-CSyoblke.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-D_bXRotA.js → TokenGalaxy-kK6wMGuy.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-CL7ma7ba.js → ToolbarRootContext-CnffyHPW.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-QZBF2IEY.js → TrendMonitor-CpxDm5q_.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-CWlxR0H-.js → WidgetsPage-vBedlR_d.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-D8XQ72nF.js → WrappedPage-D25YzXGY.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-CTGqjrCe.js → __vite-browser-external-OxXsgcds.js} +3 -3
- package/dashboard/dist/assets/{agent-logos-BscA25fS.js → agent-logos-frktji23.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-DTxCEGbR.js → arrow-up-right-BtBcf39e.js} +1 -1
- package/dashboard/dist/assets/{check-CCEoh2wj.js → check-PVwhLtMf.js} +1 -1
- package/dashboard/dist/assets/{composite-B2s880f5.js → composite-BxlyIOoF.js} +1 -1
- package/dashboard/dist/assets/{copy-CJVQglwG.js → copy-s5UqKoXC.js} +1 -1
- package/dashboard/dist/assets/{download-Cn-OpYm6.js → download-Ns8TNfey.js} +1 -1
- package/dashboard/dist/assets/{external-link-BnYlUn56.js → external-link-zpvfw1sA.js} +1 -1
- package/dashboard/dist/assets/{flame-D4yFLV1L.js → flame-DhPzeD5Z.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-CBUNbBvp.js → format-tokens-C4eAHkPw.js} +1 -1
- package/dashboard/dist/assets/{icons-CcgNgAvb.js → icons-CNeKwVFm.js} +1 -1
- package/dashboard/dist/assets/{index-CTjeDkbu.js → index-9qLVgAvh.js} +1 -1
- package/dashboard/dist/assets/{index-CkELwUyg.js → index-B5UHZH4-.js} +1 -1
- package/dashboard/dist/assets/{index-ZWeEKbo-.js → index-D8ciCYQM.js} +1 -1
- package/dashboard/dist/assets/{info-DoehRSQU.js → info-p2pKHzPt.js} +1 -1
- package/dashboard/dist/assets/{link-2-D8xSsPqy.js → link-2-BQhZyxUQ.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-DMu0-X5r.js → loader-circle-BnFE5J64.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-DLyYsZvE.js → maximize-2-Zt1L2xuV.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-Dm5Xy2jA.js → modifiers.esm-Sbhv1CrS.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-5uZGQNGJ.js → monitor-smartphone-Pmy9ktPf.js} +1 -1
- package/dashboard/dist/assets/{plus-8fnU0dkt.js → plus-FPP4P4tW.js} +1 -1
- package/dashboard/dist/assets/{provider-display-B3ed-pSc.js → provider-display-zpzUqFZ8.js} +2 -2
- package/dashboard/dist/assets/{react-Gft01KYk.js → react-C_5Bvle-.js} +1 -1
- package/dashboard/dist/assets/{search-jqzJg2kG.js → search-7f0zYUoC.js} +1 -1
- package/dashboard/dist/assets/{skills-api-Bwn_xcHV.js → skills-api-CdEcHyY0.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-CYjzLCp7.js → sortable.esm-DwOWVPK8.js} +1 -1
- package/dashboard/dist/assets/{store-CgJHe9jU.js → store-D3n2aJ7w.js} +1 -1
- package/dashboard/dist/assets/{terminal-CZ5j8yEQ.js → terminal-C6zDcArO.js} +1 -1
- package/dashboard/dist/assets/{trash-DtMLjI_S.js → trash-C_bcv-F0.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-Px3dHGlR.js → use-community-stats-fCkrn5Kd.js} +1 -1
- package/dashboard/dist/assets/{use-latest-request-guard-B7Vw4Wsd.js → use-latest-request-guard-DD2Nt1qS.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-DWWrcMPi.js → use-limits-display-prefs-a9HtQcOE.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-CevbB79U.js → use-ordered-list-B6-Nb6rL.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-DyXrwS-h.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-DoIaI0vm.js → use-session-efficiency-pref-gD9i2h4k.js} +1 -1
- package/dashboard/dist/assets/{use-transform-qRwUetOk.js → use-transform-DP6mCHUn.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-DlP7yg78.js → use-usage-limits-TdwK-gf2.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-DRUe8YoY.js → useCurrency-Bbxwhe-A.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-CmLbznUC.js → useTokenFormat-CzeTrne_.js} +1 -1
- package/dashboard/dist/assets/{zap-CS80c_uN.js → zap-CucEQWyU.js} +1 -1
- package/dashboard/dist/index.html +13 -11
- 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 +10 -0
- package/src/commands/status.js +16 -0
- package/src/commands/sync.js +43 -1
- package/src/lib/codex-rollout-parser.js +86 -8
- package/src/lib/codex-usage-record.js +195 -0
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +261 -11
- package/src/lib/skills-manager.js +2 -2
- package/dashboard/dist/assets/DevicePage-RCIANm45.js +0 -1
- package/dashboard/dist/assets/DialogDescription-C2EzE7DU.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-CCuEY-79.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -26,6 +26,20 @@ const {
|
|
|
26
26
|
readCodexServiceTier,
|
|
27
27
|
isPriorityServiceTier,
|
|
28
28
|
} = require("./codex-service-tier");
|
|
29
|
+
const {
|
|
30
|
+
awaitsCompactedLine,
|
|
31
|
+
createCompactionResponseIds,
|
|
32
|
+
createUsageRecordState,
|
|
33
|
+
extractTokenUsageRecord,
|
|
34
|
+
isCodexTurnEndEvent,
|
|
35
|
+
isRecordOnly,
|
|
36
|
+
noteLineAfterUsageRecord,
|
|
37
|
+
noteTokenCount,
|
|
38
|
+
noteTurnEnd,
|
|
39
|
+
noteUsageRecord,
|
|
40
|
+
snapshotUsageRecordState,
|
|
41
|
+
takeCompactionOnTokenCount,
|
|
42
|
+
} = require("./codex-usage-record");
|
|
29
43
|
const {
|
|
30
44
|
DEVIN_TABLE_PROBE_SQL,
|
|
31
45
|
devinUsageSql,
|
|
@@ -258,6 +272,10 @@ async function parseRolloutIncremental({
|
|
|
258
272
|
if (!cursors.files || typeof cursors.files !== "object") {
|
|
259
273
|
cursors.files = {};
|
|
260
274
|
}
|
|
275
|
+
// Counted Codex compaction calls by response_id (issue #652). Core cursor
|
|
276
|
+
// state, so a fork replay or a copied rollout under any path or day shard
|
|
277
|
+
// sees every compaction counted before.
|
|
278
|
+
const compactionResponseIds = createCompactionResponseIds(cursors);
|
|
261
279
|
|
|
262
280
|
// Persisted set of seen Codex event keys (sessionUUID:eventTimestamp). Mirrors
|
|
263
281
|
// the claudeHashes pattern: it makes an inode-changing re-scan idempotent so an
|
|
@@ -480,6 +498,12 @@ async function parseRolloutIncremental({
|
|
|
480
498
|
const modelAttributionState = sameInode && !truncated
|
|
481
499
|
? prev.modelAttributionState || null
|
|
482
500
|
: null;
|
|
501
|
+
// Only valid for the bytes before the resume offset; a rescan from 0
|
|
502
|
+
// rebuilds it. A cursor from before #652 with a lastTotal has seen a
|
|
503
|
+
// token_count already.
|
|
504
|
+
const usageRecordState = startOffset > 0
|
|
505
|
+
? prev?.codexUsageRecord || (prev?.lastTotal ? { sawTokenCount: true } : null)
|
|
506
|
+
: null;
|
|
483
507
|
|
|
484
508
|
const codexProjectFastPath =
|
|
485
509
|
projectEnabled && (fileSource === DEFAULT_SOURCE || fileSource === "acode");
|
|
@@ -575,6 +599,8 @@ async function parseRolloutIncremental({
|
|
|
575
599
|
lastModel,
|
|
576
600
|
lastServiceTier,
|
|
577
601
|
modelAttributionState,
|
|
602
|
+
usageRecordState,
|
|
603
|
+
compactionResponseIds,
|
|
578
604
|
hourlyState,
|
|
579
605
|
touchedBuckets,
|
|
580
606
|
source: fileSource,
|
|
@@ -601,6 +627,20 @@ async function parseRolloutIncremental({
|
|
|
601
627
|
modelAttributionState: result.modelAttributionState,
|
|
602
628
|
updatedAt: new Date().toISOString(),
|
|
603
629
|
};
|
|
630
|
+
const nextUsageRecordState = projectContextOnlyScan
|
|
631
|
+
? usageRecordState
|
|
632
|
+
: result.usageRecordState;
|
|
633
|
+
if (nextUsageRecordState) nextCursor.codexUsageRecord = nextUsageRecordState;
|
|
634
|
+
// Files whose usage only exists as token_usage_record rows are not
|
|
635
|
+
// counted (issue #652); keep them in core cursor state so sync and status
|
|
636
|
+
// can warn without loading per-file cursor shards.
|
|
637
|
+
if (fileSource === DEFAULT_SOURCE) {
|
|
638
|
+
if (isRecordOnly(nextUsageRecordState)) {
|
|
639
|
+
(cursors.codexUsageRecordOnlyFiles ||= {})[key] = true;
|
|
640
|
+
} else if (cursors.codexUsageRecordOnlyFiles?.[key]) {
|
|
641
|
+
delete cursors.codexUsageRecordOnlyFiles[key];
|
|
642
|
+
}
|
|
643
|
+
}
|
|
604
644
|
if (codexProjectFastPath) {
|
|
605
645
|
nextCursor.projectOffset = result.endOffset;
|
|
606
646
|
nextCursor.projectFileContext = buildProjectFileContext(
|
|
@@ -643,6 +683,12 @@ async function parseRolloutIncremental({
|
|
|
643
683
|
projectState.updatedAt = new Date().toISOString();
|
|
644
684
|
cursors.projectHourly = projectState;
|
|
645
685
|
}
|
|
686
|
+
compactionResponseIds.persist();
|
|
687
|
+
// A deleted rollout no longer needs a warning. The map is empty unless a
|
|
688
|
+
// record-only writer exists, so this is normally free.
|
|
689
|
+
for (const flaggedPath of Object.keys(cursors.codexUsageRecordOnlyFiles || {})) {
|
|
690
|
+
if (!fssync.existsSync(flaggedPath)) delete cursors.codexUsageRecordOnlyFiles[flaggedPath];
|
|
691
|
+
}
|
|
646
692
|
|
|
647
693
|
return { filesProcessed, eventsAggregated, bucketsQueued, projectBucketsQueued };
|
|
648
694
|
}
|
|
@@ -2071,6 +2117,8 @@ async function parseRolloutFile({
|
|
|
2071
2117
|
lastModel,
|
|
2072
2118
|
lastServiceTier,
|
|
2073
2119
|
modelAttributionState: previousModelAttributionState,
|
|
2120
|
+
usageRecordState: previousUsageRecordState = null,
|
|
2121
|
+
compactionResponseIds = null,
|
|
2074
2122
|
hourlyState,
|
|
2075
2123
|
touchedBuckets,
|
|
2076
2124
|
source,
|
|
@@ -2098,6 +2146,7 @@ async function parseRolloutFile({
|
|
|
2098
2146
|
lastModel,
|
|
2099
2147
|
lastServiceTier: typeof lastServiceTier === "string" ? lastServiceTier : null,
|
|
2100
2148
|
modelAttributionState: previousModelAttributionState,
|
|
2149
|
+
usageRecordState: previousUsageRecordState,
|
|
2101
2150
|
eventsAggregated: 0,
|
|
2102
2151
|
projectFileContexts,
|
|
2103
2152
|
};
|
|
@@ -2142,6 +2191,54 @@ async function parseRolloutFile({
|
|
|
2142
2191
|
let eventsAggregated = 0;
|
|
2143
2192
|
let scannedEndOffset = startOffset;
|
|
2144
2193
|
let committedEndOffset = startOffset;
|
|
2194
|
+
// Compaction records (issue #652, rules in codex-usage-record.js). Codex only.
|
|
2195
|
+
const usageRecordState = source === DEFAULT_SOURCE && compactionResponseIds
|
|
2196
|
+
? createUsageRecordState(previousUsageRecordState)
|
|
2197
|
+
: null;
|
|
2198
|
+
|
|
2199
|
+
// What a record adds if it turns out to be a compaction call: model, tier
|
|
2200
|
+
// and project are those in effect when the record was written. A record
|
|
2201
|
+
// without a response_id cannot be deduplicated and is never counted.
|
|
2202
|
+
function buildCompactionEvent(record) {
|
|
2203
|
+
if (!record.responseId) return null;
|
|
2204
|
+
const delta = normalizeUsage(record.usage);
|
|
2205
|
+
if (isAllZeroUsage(delta)) return null;
|
|
2206
|
+
delta.conversation_count = 1;
|
|
2207
|
+
const bucketStart = toUtcHalfHourStart(record.timestamp);
|
|
2208
|
+
if (!bucketStart) return null;
|
|
2209
|
+
return {
|
|
2210
|
+
responseId: record.responseId,
|
|
2211
|
+
bucketStart,
|
|
2212
|
+
model,
|
|
2213
|
+
serviceTier,
|
|
2214
|
+
projectKey: currentProjectKey,
|
|
2215
|
+
projectRef: currentProjectRef,
|
|
2216
|
+
delta,
|
|
2217
|
+
};
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
// Counted once per response_id across every rollout: a fork replays its
|
|
2221
|
+
// parent's records and a copied rollout repeats them, both with the same id.
|
|
2222
|
+
function addCompactionEvent(event) {
|
|
2223
|
+
if (compactionResponseIds.has(event.responseId)) return;
|
|
2224
|
+
compactionResponseIds.add(event.responseId);
|
|
2225
|
+
const bucket = getHourlyBucket(hourlyState, source, event.model, event.bucketStart);
|
|
2226
|
+
addTotals(bucket.totals, event.delta);
|
|
2227
|
+
if (isPriorityServiceTier(event.serviceTier)) addPriorityUsage(bucket.totals, event.delta);
|
|
2228
|
+
touchedBuckets.add(bucketKey(source, event.model, event.bucketStart));
|
|
2229
|
+
if (event.projectKey && projectState && projectTouchedBuckets) {
|
|
2230
|
+
const projectBucket = getProjectBucket(
|
|
2231
|
+
projectState,
|
|
2232
|
+
event.projectKey,
|
|
2233
|
+
source,
|
|
2234
|
+
event.bucketStart,
|
|
2235
|
+
event.projectRef,
|
|
2236
|
+
);
|
|
2237
|
+
addTotals(projectBucket.totals, event.delta);
|
|
2238
|
+
projectTouchedBuckets.add(projectBucketKey(event.projectKey, source, event.bucketStart));
|
|
2239
|
+
}
|
|
2240
|
+
eventsAggregated += 1;
|
|
2241
|
+
}
|
|
2145
2242
|
|
|
2146
2243
|
const invalidUtf8 = invalidRecordPolicy === "throw" ? "throw" : "record";
|
|
2147
2244
|
for await (const record of physicalJsonlRecords(stream, { invalidUtf8 })) {
|
|
@@ -2154,6 +2251,26 @@ async function parseRolloutFile({
|
|
|
2154
2251
|
|
|
2155
2252
|
const { line } = record;
|
|
2156
2253
|
if (!line) continue;
|
|
2254
|
+
// Only a `compacted` line directly after a record keeps it as a
|
|
2255
|
+
// compaction candidate. A line that is not complete yet decides nothing:
|
|
2256
|
+
// the read stops before it and the next sync sees it whole.
|
|
2257
|
+
if (awaitsCompactedLine(usageRecordState)) {
|
|
2258
|
+
let next;
|
|
2259
|
+
if (!record.terminated || line.includes('"compacted"')) {
|
|
2260
|
+
try {
|
|
2261
|
+
next = JSON.parse(line);
|
|
2262
|
+
} catch {
|
|
2263
|
+
next = undefined;
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
if (next !== undefined || record.terminated) {
|
|
2267
|
+
noteLineAfterUsageRecord(usageRecordState, next?.type === "compacted");
|
|
2268
|
+
}
|
|
2269
|
+
if (next?.type === "compacted") {
|
|
2270
|
+
committedEndOffset = scannedEndOffset;
|
|
2271
|
+
continue;
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2157
2274
|
const maybeTokenCount = line.includes('"token_count"');
|
|
2158
2275
|
const maybeModelReroute =
|
|
2159
2276
|
!maybeTokenCount &&
|
|
@@ -2168,7 +2285,19 @@ async function parseRolloutFile({
|
|
|
2168
2285
|
const maybeServiceTier =
|
|
2169
2286
|
!maybeTokenCount && !maybeModelReroute && !maybeTurnContext &&
|
|
2170
2287
|
line.includes(CODEX_SERVICE_TIER_MARKER);
|
|
2171
|
-
|
|
2288
|
+
const maybeUsageRecord =
|
|
2289
|
+
!maybeTokenCount &&
|
|
2290
|
+
Boolean(usageRecordState) &&
|
|
2291
|
+
(line.includes('"token_usage_record"') ||
|
|
2292
|
+
(usageRecordState.unmatchedRecord &&
|
|
2293
|
+
(line.includes('"task_complete"') || line.includes('"turn_aborted"'))));
|
|
2294
|
+
if (
|
|
2295
|
+
!maybeTokenCount &&
|
|
2296
|
+
!maybeTurnContext &&
|
|
2297
|
+
!maybeModelReroute &&
|
|
2298
|
+
!maybeServiceTier &&
|
|
2299
|
+
!maybeUsageRecord
|
|
2300
|
+
) {
|
|
2172
2301
|
if (invalidRecordPolicy === "throw" || !record.terminated) {
|
|
2173
2302
|
try {
|
|
2174
2303
|
JSON.parse(line);
|
|
@@ -2230,11 +2359,32 @@ async function parseRolloutFile({
|
|
|
2230
2359
|
continue;
|
|
2231
2360
|
}
|
|
2232
2361
|
|
|
2362
|
+
if (usageRecordState) {
|
|
2363
|
+
const usageRecord = extractTokenUsageRecord(obj);
|
|
2364
|
+
if (usageRecord) {
|
|
2365
|
+
noteUsageRecord(usageRecordState, buildCompactionEvent(usageRecord));
|
|
2366
|
+
continue;
|
|
2367
|
+
}
|
|
2368
|
+
if (isCodexTurnEndEvent(obj)) {
|
|
2369
|
+
noteTurnEnd(usageRecordState);
|
|
2370
|
+
continue;
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2233
2374
|
const token = extractTokenCount(obj);
|
|
2234
2375
|
if (!token) continue;
|
|
2235
2376
|
|
|
2236
2377
|
const info = token.info;
|
|
2237
2378
|
if (!info || typeof info !== "object") continue;
|
|
2379
|
+
if (usageRecordState) {
|
|
2380
|
+
noteTokenCount(usageRecordState);
|
|
2381
|
+
const compaction = takeCompactionOnTokenCount(
|
|
2382
|
+
usageRecordState,
|
|
2383
|
+
usageDeltaState.lastTotal,
|
|
2384
|
+
info.total_token_usage,
|
|
2385
|
+
);
|
|
2386
|
+
if (compaction) addCompactionEvent(compaction);
|
|
2387
|
+
}
|
|
2238
2388
|
|
|
2239
2389
|
const tokenTimestamp = typeof token.timestamp === "string" ? token.timestamp : null;
|
|
2240
2390
|
if (!tokenTimestamp) continue;
|
|
@@ -2352,6 +2502,9 @@ async function parseRolloutFile({
|
|
|
2352
2502
|
lastModel: model,
|
|
2353
2503
|
lastServiceTier: serviceTier,
|
|
2354
2504
|
modelAttributionState: snapshotCodexModelAttributionState(modelAttributionState),
|
|
2505
|
+
usageRecordState: usageRecordState
|
|
2506
|
+
? snapshotUsageRecordState(usageRecordState)
|
|
2507
|
+
: previousUsageRecordState,
|
|
2355
2508
|
eventsAggregated,
|
|
2356
2509
|
projectFileContexts,
|
|
2357
2510
|
};
|
|
@@ -3465,7 +3618,7 @@ function deriveOpencodeMessageFingerprint({ msg, totals, source }) {
|
|
|
3465
3618
|
totals.reasoning_output_tokens,
|
|
3466
3619
|
model,
|
|
3467
3620
|
provider,
|
|
3468
|
-
].join("
|
|
3621
|
+
].join("\u0000");
|
|
3469
3622
|
// Hashed rather than stored raw: the fingerprint is persisted per message in
|
|
3470
3623
|
// cursors.json, and heavy OpenCode users carry tens of thousands of entries.
|
|
3471
3624
|
return crypto.createHash("sha256").update(raw).digest("base64url").slice(0, 22);
|
|
@@ -15313,6 +15466,17 @@ function primeAgentSourceForProvider(provider) {
|
|
|
15313
15466
|
return slug ? `prime-agent-${slug}` : "prime-agent";
|
|
15314
15467
|
}
|
|
15315
15468
|
|
|
15469
|
+
// Maps one parsed JSONL line to { id, message, timestamp } or null. pi-family
|
|
15470
|
+
// files wrap each record as { type: "message", id, timestamp, message }.
|
|
15471
|
+
function readPiMessageEntry(entry) {
|
|
15472
|
+
if (!entry || entry.type !== "message") return null;
|
|
15473
|
+
return {
|
|
15474
|
+
id: typeof entry.id === "string" && entry.id ? entry.id : null,
|
|
15475
|
+
message: entry.message,
|
|
15476
|
+
timestamp: entry.timestamp,
|
|
15477
|
+
};
|
|
15478
|
+
}
|
|
15479
|
+
|
|
15316
15480
|
async function parsePiLikeIncremental({
|
|
15317
15481
|
sessionFiles,
|
|
15318
15482
|
cursors,
|
|
@@ -15326,6 +15490,7 @@ async function parsePiLikeIncremental({
|
|
|
15326
15490
|
resolveSessionFiles,
|
|
15327
15491
|
resolveDefaultModel,
|
|
15328
15492
|
sourceForProvider,
|
|
15493
|
+
readEntry = readPiMessageEntry,
|
|
15329
15494
|
} = {}) {
|
|
15330
15495
|
await ensureDir(path.dirname(queuePath));
|
|
15331
15496
|
const projectEnabled = typeof projectQueuePath === "string" && projectQueuePath.length > 0;
|
|
@@ -15427,15 +15592,16 @@ async function parsePiLikeIncremental({
|
|
|
15427
15592
|
let entry;
|
|
15428
15593
|
try { entry = JSON.parse(line); } catch { continue; }
|
|
15429
15594
|
|
|
15430
|
-
|
|
15595
|
+
const record = readEntry(entry);
|
|
15596
|
+
if (!record) continue;
|
|
15431
15597
|
|
|
15432
|
-
const msg =
|
|
15598
|
+
const msg = record.message;
|
|
15433
15599
|
if (!msg || msg.role !== "assistant") continue;
|
|
15434
15600
|
|
|
15435
15601
|
const usage = msg.usage;
|
|
15436
15602
|
if (!usage || typeof usage !== "object") continue;
|
|
15437
15603
|
|
|
15438
|
-
const entryId =
|
|
15604
|
+
const entryId = record.id;
|
|
15439
15605
|
if (!entryId) continue;
|
|
15440
15606
|
if (seenIds.has(entryId)) continue;
|
|
15441
15607
|
|
|
@@ -15461,8 +15627,8 @@ async function parsePiLikeIncremental({
|
|
|
15461
15627
|
let tsMs = null;
|
|
15462
15628
|
if (Number.isFinite(Number(msg.timestamp)) && Number(msg.timestamp) > 0) {
|
|
15463
15629
|
tsMs = Number(msg.timestamp);
|
|
15464
|
-
} else if (typeof
|
|
15465
|
-
const parsed = Date.parse(
|
|
15630
|
+
} else if (typeof record.timestamp === "string" && record.timestamp) {
|
|
15631
|
+
const parsed = Date.parse(record.timestamp);
|
|
15466
15632
|
if (Number.isFinite(parsed) && parsed > 0) tsMs = parsed;
|
|
15467
15633
|
}
|
|
15468
15634
|
if (tsMs == null) {
|
|
@@ -15573,11 +15739,12 @@ async function parsePiLikeIncremental({
|
|
|
15573
15739
|
if (!line || !line.trim()) continue;
|
|
15574
15740
|
let entry;
|
|
15575
15741
|
try { entry = JSON.parse(line); } catch { continue; }
|
|
15576
|
-
const
|
|
15742
|
+
const record = readEntry(entry);
|
|
15743
|
+
const msg = record ? record.message : null;
|
|
15577
15744
|
const usage = msg?.role === "assistant" ? msg.usage : null;
|
|
15578
15745
|
if (!usage || typeof usage !== "object") continue;
|
|
15579
15746
|
|
|
15580
|
-
const entryId =
|
|
15747
|
+
const entryId = record.id;
|
|
15581
15748
|
if (!entryId || projectSeenIds.has(entryId)) continue;
|
|
15582
15749
|
|
|
15583
15750
|
const input = toNonNegativeInt(usage.input);
|
|
@@ -15599,8 +15766,8 @@ async function parsePiLikeIncremental({
|
|
|
15599
15766
|
let tsMs = null;
|
|
15600
15767
|
if (Number.isFinite(Number(msg.timestamp)) && Number(msg.timestamp) > 0) {
|
|
15601
15768
|
tsMs = Number(msg.timestamp);
|
|
15602
|
-
} else if (typeof
|
|
15603
|
-
const parsed = Date.parse(
|
|
15769
|
+
} else if (typeof record.timestamp === "string" && record.timestamp) {
|
|
15770
|
+
const parsed = Date.parse(record.timestamp);
|
|
15604
15771
|
if (Number.isFinite(parsed) && parsed > 0) tsMs = parsed;
|
|
15605
15772
|
}
|
|
15606
15773
|
const bucketStart = tsMs == null
|
|
@@ -15700,6 +15867,85 @@ async function parsePrimeAgentIncremental(options = {}) {
|
|
|
15700
15867
|
});
|
|
15701
15868
|
}
|
|
15702
15869
|
|
|
15870
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
15871
|
+
// MiniMax Code (MiniMax's desktop coding agent) — passive JSONL reader
|
|
15872
|
+
// (~/.minimax/v2/sessions/YYYY/MM/DD/<HH-MM-SS-mmm>-session_<id>/messages.jsonl)
|
|
15873
|
+
//
|
|
15874
|
+
// Records carry pi-shaped usage (input excludes cacheRead) and a ms-epoch
|
|
15875
|
+
// message.timestamp, but have no type:"message" wrapper and dedupe on the
|
|
15876
|
+
// top-level message_id. MiniMax Code routes to many upstream models and records
|
|
15877
|
+
// the model per message. Its usage.cost block is always 0, so it is ignored in
|
|
15878
|
+
// favor of normal pricing. Migrated legacy sessions replay as model
|
|
15879
|
+
// "historical-transcript" with all-zero usage and are dropped by the engine's
|
|
15880
|
+
// zero-token guard. There is no cwd header, so no project attribution.
|
|
15881
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
15882
|
+
|
|
15883
|
+
const MINIMAX_CODE_SOURCE = "minimax-code";
|
|
15884
|
+
const MINIMAX_CODE_SESSION_FILE = "messages.jsonl";
|
|
15885
|
+
// sessions / YYYY / MM / DD / <session dir> / messages.jsonl
|
|
15886
|
+
const MINIMAX_CODE_MAX_SESSION_DEPTH = 5;
|
|
15887
|
+
|
|
15888
|
+
function resolveMinimaxCodeHome(env = process.env) {
|
|
15889
|
+
if (env.TOKENTRACKER_MINIMAX_HOME) return expandHomePath(env.TOKENTRACKER_MINIMAX_HOME, env);
|
|
15890
|
+
const home = env.HOME || require("node:os").homedir();
|
|
15891
|
+
if (process.platform === "win32") {
|
|
15892
|
+
return pickWin32ProviderPath({
|
|
15893
|
+
env,
|
|
15894
|
+
nativeValue: path.join(home, ".minimax"),
|
|
15895
|
+
wslProviderDir: ".minimax",
|
|
15896
|
+
});
|
|
15897
|
+
}
|
|
15898
|
+
return path.join(home, ".minimax");
|
|
15899
|
+
}
|
|
15900
|
+
|
|
15901
|
+
function resolveMinimaxCodeSessionsDir(env = process.env) {
|
|
15902
|
+
const minimaxHome = resolveMinimaxCodeHome(env);
|
|
15903
|
+
return minimaxHome ? path.join(minimaxHome, "v2", "sessions") : null;
|
|
15904
|
+
}
|
|
15905
|
+
|
|
15906
|
+
function resolveMinimaxCodeSessionFiles(env = process.env) {
|
|
15907
|
+
const sessionsDir = resolveMinimaxCodeSessionsDir(env);
|
|
15908
|
+
if (!sessionsDir) return [];
|
|
15909
|
+
const files = [];
|
|
15910
|
+
const walk = (dir, depth) => {
|
|
15911
|
+
let entries;
|
|
15912
|
+
try { entries = fssync.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
15913
|
+
for (const entry of entries) {
|
|
15914
|
+
const fullPath = path.join(dir, entry.name);
|
|
15915
|
+
if (entry.isDirectory()) {
|
|
15916
|
+
if (depth < MINIMAX_CODE_MAX_SESSION_DEPTH) walk(fullPath, depth + 1);
|
|
15917
|
+
} else if (entry.isFile() && entry.name === MINIMAX_CODE_SESSION_FILE && depth > 1) {
|
|
15918
|
+
files.push(fullPath);
|
|
15919
|
+
}
|
|
15920
|
+
}
|
|
15921
|
+
};
|
|
15922
|
+
walk(sessionsDir, 1);
|
|
15923
|
+
files.sort((a, b) => a.localeCompare(b));
|
|
15924
|
+
return files;
|
|
15925
|
+
}
|
|
15926
|
+
|
|
15927
|
+
function readMinimaxCodeEntry(entry) {
|
|
15928
|
+
if (!entry || typeof entry !== "object" || !entry.message) return null;
|
|
15929
|
+
return {
|
|
15930
|
+
id: typeof entry.message_id === "string" && entry.message_id ? entry.message_id : null,
|
|
15931
|
+
message: entry.message,
|
|
15932
|
+
timestamp: null,
|
|
15933
|
+
};
|
|
15934
|
+
}
|
|
15935
|
+
|
|
15936
|
+
async function parseMinimaxCodeIncremental(options = {}) {
|
|
15937
|
+
return parsePiLikeIncremental({
|
|
15938
|
+
...options,
|
|
15939
|
+
// Session files have no cwd header, so project attribution is unsupported.
|
|
15940
|
+
projectQueuePath: undefined,
|
|
15941
|
+
stateKey: "minimaxCode",
|
|
15942
|
+
resolveSessionFiles: resolveMinimaxCodeSessionFiles,
|
|
15943
|
+
resolveDefaultModel: () => `${MINIMAX_CODE_SOURCE}-unknown`,
|
|
15944
|
+
sourceForProvider: () => MINIMAX_CODE_SOURCE,
|
|
15945
|
+
readEntry: readMinimaxCodeEntry,
|
|
15946
|
+
});
|
|
15947
|
+
}
|
|
15948
|
+
|
|
15703
15949
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
15704
15950
|
// Craft Agents (lukilabs/craft-agents-oss) — passive JSONL reader
|
|
15705
15951
|
//
|
|
@@ -22935,6 +23181,10 @@ module.exports = {
|
|
|
22935
23181
|
resolvePrimeAgentSessionFiles,
|
|
22936
23182
|
resolvePrimeAgentDefaultModel,
|
|
22937
23183
|
parsePrimeAgentIncremental,
|
|
23184
|
+
resolveMinimaxCodeHome,
|
|
23185
|
+
resolveMinimaxCodeSessionsDir,
|
|
23186
|
+
resolveMinimaxCodeSessionFiles,
|
|
23187
|
+
parseMinimaxCodeIncremental,
|
|
22938
23188
|
resolveCraftConfigDir,
|
|
22939
23189
|
resolveCraftWorkspaceRoots,
|
|
22940
23190
|
resolveCraftSessionFiles,
|
|
@@ -490,13 +490,13 @@ function hashDirectory(dir) {
|
|
|
490
490
|
continue;
|
|
491
491
|
}
|
|
492
492
|
const execBit = process.platform === "win32" ? 0 : stat.mode & 0o111 ? 1 : 0;
|
|
493
|
-
hash.update(`${rel}
|
|
493
|
+
hash.update(`${rel}\u0000${execBit}\u0000`);
|
|
494
494
|
try {
|
|
495
495
|
hash.update(fs.readFileSync(abs));
|
|
496
496
|
} catch (_e) {
|
|
497
497
|
// unreadable file — fold its absence in deterministically
|
|
498
498
|
}
|
|
499
|
-
hash.update("
|
|
499
|
+
hash.update("\u0000");
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as b,r as l,j as r,c as e,i as v}from"./__vite-browser-external-CTGqjrCe.js";const x={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1,VITE_APP_VERSION:"0.99.0",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,v as a}from"./__vite-browser-external-CTGqjrCe.js";import{u as p}from"./DialogTitle-Ckzf1tdi.js";import{u as c}from"./composite-B2s880f5.js";const x=n.forwardRef(function(e,r){const{render:l,className:u,style:m,id:s,...t}=e,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-CTGqjrCe.js";import{h as r,i as t,p as s}from"./react-Gft01KYk.js";function i(){!r.current&&t();const[e]=o.useState(s.current);return e}export{i as u};
|