tokentracker-cli 0.94.1 → 0.95.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 +9 -7
- package/README.ja.md +8 -6
- package/README.ko.md +8 -6
- package/README.md +23 -10
- package/README.zh-CN.md +8 -6
- package/dashboard/dist/assets/{AchievementBadge-DnmgEa4q.js → AchievementBadge-Cyju9OnL.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-B7YTbAuK.js → AchievementsPage-Bh2dQR-I.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-CwgT5sqH.js → AchievementsSection-DSFAM0Zp.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-Dets6jzW.js → BadgeDetailModal-CgVF0VI0.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-5KwUvC9F.js → BotAnimated-DI-rTxI9.js} +1 -1
- package/dashboard/dist/assets/{Card-jf9w-4-N.js → Card-DAlV-PSI.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-CGxDVQ0c.js → ClawdAnimated-oOYKgcpq.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-B1bUUf32.js → CommandPalette-bYE5uD63.js} +1 -1
- package/dashboard/dist/assets/CommunityStatsModal-DCx0sQjk.js +1 -0
- package/dashboard/dist/assets/{ConfirmModal-BR-aIRH9.js → ConfirmModal-DrYf9m15.js} +1 -1
- package/dashboard/dist/assets/{Controls-CbHsJAqV.js → Controls-DAift9Z4.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-CLswnOil.js +1 -0
- package/dashboard/dist/assets/{DevicePage-DDlicLLn.js → DevicePage-uWLgMC4Z.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-B89uLXqp.js → DialogClose-NitVrdVC.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-CQuJCP4L.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-jOyycYKF.js → DialogTitle-CA_ZstJL.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-BEND42ze.js → FadeIn-CIkYDamA.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-Dacl1WGS.js → HeaderGithubStar-CYTJNLpL.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-B2Mh2LTi.js → HoverTooltip-jh3sI8NC.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-CPEuRhiU.js → IpCheckPage-Brpe-N7B.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-BYWNR_dx.js → LandingPage-D4PjaNcN.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-B9_5LDVj.js → LeaderboardAvatar-D9dc6frq.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-_Hl1NaIa.js → LeaderboardPage-CEuqopiC.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-Cydp7CyA.js → LeaderboardProfileModal-TeYdXeIA.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-Dz0ecujs.js → LeaderboardProfilePage-DmtuwJkL.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-CmdT2qOZ.js → LimitsPage-BJW3teYA.js} +2 -2
- package/dashboard/dist/assets/{LocalOnlyNotice-DhuPGUkw.js → LocalOnlyNotice-V8_KFKOD.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-DQtHaX_5.js → LoginCard-ud0lCY_u.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-DvpPRnYV.js → LoginModal-Bnemx4UD.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-DOjfmdwb.js → LoginPage-v89BHssa.js} +1 -1
- package/dashboard/dist/assets/{PetPage-Dd6U9fh2.js → PetPage-Bg9kEi7o.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-B1V01u10.js → PopoverPopup-CCHVwh0w.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-BLRe55c7.js → ProviderIcon-BecpRylD.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-BJ95vy1S.js → ResetPasswordPage-CsUtFeUr.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-DacS_m9M.js → SegmentedControl-3rBqbzW_.js} +1 -1
- package/dashboard/dist/assets/{Select-bQDO5BEA.js → Select-DZ2ll7Qv.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-CUGrs9CY.js → SelectItemText-Dr1W47W6.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-CsERvmVC.js → ServiceStatusPage-Cc1LXdAh.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-0VvqEfPx.js → SessionsPage-ytOFN1h9.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-9EHh2HfD.js → SettingsPage-2wYQ2ly6.js} +2 -2
- package/dashboard/dist/assets/SkillsPage-BEDAwBTN.js +1 -0
- package/dashboard/dist/assets/{TokenGalaxy-DSKTHQSs.js → TokenGalaxy-DxG0dBeG.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-DP4mQLbq.js → ToolbarRootContext-DG1pr5UP.js} +1 -1
- package/dashboard/dist/assets/TrendMonitor-CeuEQ0XC.js +19 -0
- package/dashboard/dist/assets/{WidgetsPage-Cr6Wg9QX.js → WidgetsPage-ALDlZ5aR.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-DqQvRcnA.js → WrappedPage-BF59ouR-.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-BHz2N7Ih.css → __vite-browser-external-CCMdjCX2.css} +1 -1
- package/dashboard/dist/assets/__vite-browser-external-DXtgoDkV.js +45 -0
- package/dashboard/dist/assets/{agent-logos-BjIh_mqf.js → agent-logos-D6Ya1qw1.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-BIhbN0NO.js → arrow-up-right-DUR69elJ.js} +1 -1
- package/dashboard/dist/assets/{check-U-wNzPvd.js → check-9_1xp5h5.js} +1 -1
- package/dashboard/dist/assets/{composite-BR91CxNl.js → composite-CEzovOpb.js} +1 -1
- package/dashboard/dist/assets/{copy-Bw3hXBCu.js → copy-DEoLQqJE.js} +1 -1
- package/dashboard/dist/assets/{download-WOqcQzvK.js → download-BNjfcJ1g.js} +1 -1
- package/dashboard/dist/assets/{external-link-BZtf6WfS.js → external-link-fV_WJ5f_.js} +1 -1
- package/dashboard/dist/assets/{flame-B5kp2VI9.js → flame-DqpuFJ14.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-BOCnuMuJ.js → format-tokens-CatddjmK.js} +1 -1
- package/dashboard/dist/assets/{icons-CA3FiIa_.js → icons-CBT1KI7V.js} +1 -1
- package/dashboard/dist/assets/{index-DjWC63Bs.js → index-BK3SzL7v.js} +1 -1
- package/dashboard/dist/assets/{index-DQaanK52.js → index-_2LEUZTl.js} +1 -1
- package/dashboard/dist/assets/{index-mEG0HZ-a.js → index-tK7s2SeO.js} +1 -1
- package/dashboard/dist/assets/{info-Djer9i3-.js → info-DBotcfT9.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-F-RnNFAb.js → limits-providers-CjMU709b.js} +1 -1
- package/dashboard/dist/assets/{link-2-DV4ocD0l.js → link-2-Wc54x2fh.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-DJK72c-o.js → loader-circle-nRhGIddE.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-BwBA_lMm.js → maximize-2-Dw3_GuKW.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-B3sl4qyZ.js → modifiers.esm-rTZ5BUxp.js} +1 -1
- package/dashboard/dist/assets/module-xpSFyNBK.js +3 -0
- package/dashboard/dist/assets/{monitor-smartphone-BUTpM4ng.js → monitor-smartphone-CNVAqV_N.js} +1 -1
- package/dashboard/dist/assets/{plus-BA9RP5L6.js → plus-B5oPOXhp.js} +1 -1
- package/dashboard/dist/assets/{provider-display-DqsJzGSr.js → provider-display-DhAUWfC6.js} +2 -2
- package/dashboard/dist/assets/{react-BYw5AVSz.js → react-BKACWrsB.js} +1 -1
- package/dashboard/dist/assets/{search-BzcnFWVD.js → search-DgddmV09.js} +1 -1
- package/dashboard/dist/assets/{skills-api-vAME1P7G.js → skills-api-BT1uiqeq.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-BpEiRqqI.js → sortable.esm-UCoNfZ6z.js} +1 -1
- package/dashboard/dist/assets/{store-GeT5fhRX.js → store-ZswY8Voz.js} +1 -1
- package/dashboard/dist/assets/{terminal-CZCMYQ8K.js → terminal-BtQyotJS.js} +1 -1
- package/dashboard/dist/assets/{trash-2-DzlWEwKO.js → trash-2-Dc_NLbWs.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-DOvJfj-i.js → use-community-stats-yOKag_ou.js} +1 -1
- package/dashboard/dist/assets/use-latest-request-guard-BEiszvlI.js +1 -0
- package/dashboard/dist/assets/{use-limits-display-prefs-BmLs4HyN.js → use-limits-display-prefs-C-l_Mxvy.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-BgozDSSV.js → use-ordered-list-CKjRaO6K.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-BlOkflqU.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-HP1ckVkS.js → use-session-efficiency-pref-DPI_--W2.js} +1 -1
- package/dashboard/dist/assets/{use-transform-B4VSogOx.js → use-transform-BQUem5OA.js} +1 -1
- package/dashboard/dist/assets/use-usage-limits-lvkMBnNR.js +1 -0
- package/dashboard/dist/assets/{useCurrency-CSuzCBAL.js → useCurrency-C5xhS1QV.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-ClnL9OFe.js → useTokenFormat-FBMikfEq.js} +1 -1
- package/dashboard/dist/assets/{zap-C_T9CCiS.js → zap-BsCNYelz.js} +1 -1
- package/dashboard/dist/brand-logos/lmstudio.svg +12 -0
- package/dashboard/dist/brand-logos/unsloth.svg +1 -0
- package/dashboard/dist/index.html +16 -12
- package/dashboard/dist/ip-check.html +2 -2
- package/dashboard/dist/leaderboard.html +2 -2
- package/dashboard/dist/llms.txt +4 -2
- package/dashboard/dist/share.html +2 -2
- package/package.json +2 -2
- package/src/commands/device-login.js +5 -10
- package/src/commands/init.js +28 -1
- package/src/commands/serve.js +6 -0
- package/src/commands/status.js +75 -8
- package/src/commands/sync.js +189 -18
- package/src/lib/cloud-account.js +102 -29
- package/src/lib/fs.js +30 -0
- package/src/lib/local-api.js +99 -13
- package/src/lib/pricing/index.js +5 -0
- package/src/lib/pricing/matcher.js +15 -0
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +1418 -28
- package/src/lib/usage-limits.js +507 -55
- package/src/lib/zcode-limits.js +65 -8
- package/dashboard/dist/assets/CommunityStatsModal-DRDpZycV.js +0 -1
- package/dashboard/dist/assets/DashboardPage-B5XMQoxy.js +0 -1
- package/dashboard/dist/assets/DialogDescription-DiVbwvTR.js +0 -1
- package/dashboard/dist/assets/SkillsPage-B1AcLX41.js +0 -1
- package/dashboard/dist/assets/TrendMonitor-rabtcE5w.js +0 -19
- package/dashboard/dist/assets/__vite-browser-external-C8KwSyTz.js +0 -45
- package/dashboard/dist/assets/chevron-right-Du-QVNj4.js +0 -1
- package/dashboard/dist/assets/module-D2D5r9gC.js +0 -3
- package/dashboard/dist/assets/use-reduced-motion-Bc3RFJdg.js +0 -1
- package/dashboard/dist/assets/use-usage-limits-DNNhD2H6.js +0 -1
package/src/commands/status.js
CHANGED
|
@@ -69,8 +69,14 @@ const {
|
|
|
69
69
|
resolveKilocodeTaskFiles,
|
|
70
70
|
resolveRoocodeTaskFiles,
|
|
71
71
|
resolveZedDbPath,
|
|
72
|
+
resolveLmstudioHome,
|
|
73
|
+
resolveLmstudioLogFiles,
|
|
74
|
+
resolveUnslothDbPath,
|
|
72
75
|
resolveQoderDbPaths,
|
|
73
76
|
resolveQoderCnDbPaths,
|
|
77
|
+
resolveQoderProjectsDir,
|
|
78
|
+
resolveQoderCnProjectsDir,
|
|
79
|
+
listQoderNewSessionFiles,
|
|
74
80
|
resolveClaudeScienceDbPaths,
|
|
75
81
|
resolveAnythingllmDbPath,
|
|
76
82
|
resolveGooseDbPath,
|
|
@@ -127,6 +133,13 @@ function formatResolvedPaths(paths, filename) {
|
|
|
127
133
|
return active;
|
|
128
134
|
}
|
|
129
135
|
|
|
136
|
+
// Combine a legacy DB path with its new-JSONL projects-dir path for the
|
|
137
|
+
// machine-readable summary. Either side may be "" (absent); both absent
|
|
138
|
+
// yields "" so callers can fall back to "not found".
|
|
139
|
+
function summarizeQoderDetail(dbPath, newPath) {
|
|
140
|
+
return [dbPath, newPath].filter(Boolean).join(" + ") || "";
|
|
141
|
+
}
|
|
142
|
+
|
|
130
143
|
// The Trae SOLO entitlement snapshot is read directly from the Trae Local
|
|
131
144
|
// State storage.json via the shared parser (readTraeEntitlementFromStorage).
|
|
132
145
|
// The queue.jsonl contract is token-count-only (CLAUDE.md privacy rule), so
|
|
@@ -488,15 +501,28 @@ async function cmdStatus(argv = []) {
|
|
|
488
501
|
const zcodeInstalled = zcodeActive.length > 0;
|
|
489
502
|
const zcodeDbPath = zcodeActive.join(" | ");
|
|
490
503
|
|
|
491
|
-
// Qoder Desktop 1.18+ — token usage lives in SharedClientCache/local.db
|
|
504
|
+
// Qoder Desktop 1.18+ — token usage lives in SharedClientCache/local.db (legacy)
|
|
505
|
+
// and since 2026-08 (app 0.1.2+) also in ~/.qoder/projects JSONL (credit-based).
|
|
492
506
|
const qoderPaths = resolveQoderDbPaths({
|
|
493
507
|
home,
|
|
494
508
|
env: process.env,
|
|
495
509
|
platform: process.platform,
|
|
496
510
|
});
|
|
497
511
|
const qoderActive = formatResolvedPaths(qoderPaths);
|
|
498
|
-
|
|
512
|
+
// New JSONL location (com.qoder.app.stable + ~/.qoder/projects)
|
|
513
|
+
const qoderProjectsDirResolved = resolveQoderProjectsDir({ home, env: process.env });
|
|
514
|
+
let qoderNewFiles = [];
|
|
515
|
+
try {
|
|
516
|
+
qoderNewFiles = await listQoderNewSessionFiles(qoderProjectsDirResolved);
|
|
517
|
+
} catch (_e) {
|
|
518
|
+
qoderNewFiles = [];
|
|
519
|
+
}
|
|
520
|
+
const qoderNewInstalled = qoderNewFiles.length > 0;
|
|
521
|
+
const qoderInstalled = qoderActive.length > 0 || qoderNewInstalled;
|
|
499
522
|
const qoderDbPath = qoderActive.join(" | ");
|
|
523
|
+
const qoderNewPath = qoderNewFiles.length > 0
|
|
524
|
+
? `${qoderProjectsDirResolved} (${qoderNewFiles.length} sessions)`
|
|
525
|
+
: "";
|
|
500
526
|
|
|
501
527
|
// Qoder CN (国内版) — same schema, separate Application Support/QoderCN dir.
|
|
502
528
|
const qoderCnPaths = resolveQoderCnDbPaths({
|
|
@@ -505,8 +531,28 @@ async function cmdStatus(argv = []) {
|
|
|
505
531
|
platform: process.platform,
|
|
506
532
|
});
|
|
507
533
|
const qoderCnActive = formatResolvedPaths(qoderCnPaths);
|
|
508
|
-
|
|
534
|
+
// CN new-JSONL mirrors sync.js: CN and international currently share
|
|
535
|
+
// ~/.qoder/projects, and sync only parses the CN dir when it diverges from
|
|
536
|
+
// the international one (same files must not count under two sources). Only
|
|
537
|
+
// report CN JSONL when the dirs diverge.
|
|
538
|
+
const qoderCnProjectsDirResolved = resolveQoderCnProjectsDir({ home, env: process.env });
|
|
539
|
+
const qoderCnSharesIntlDir = path.normalize(qoderCnProjectsDirResolved) === path.normalize(qoderProjectsDirResolved)
|
|
540
|
+
|| (process.platform === "win32"
|
|
541
|
+
&& path.normalize(qoderCnProjectsDirResolved).toLowerCase() === path.normalize(qoderProjectsDirResolved).toLowerCase());
|
|
542
|
+
let qoderCnNewFiles = [];
|
|
543
|
+
if (!qoderCnSharesIntlDir) {
|
|
544
|
+
try {
|
|
545
|
+
qoderCnNewFiles = await listQoderNewSessionFiles(qoderCnProjectsDirResolved);
|
|
546
|
+
} catch (_e) {
|
|
547
|
+
qoderCnNewFiles = [];
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
const qoderCnNewInstalled = qoderCnNewFiles.length > 0;
|
|
551
|
+
const qoderCnInstalled = qoderCnActive.length > 0 || qoderCnNewInstalled;
|
|
509
552
|
const qoderCnDbPath = qoderCnActive.join(" | ");
|
|
553
|
+
const qoderCnNewPath = qoderCnNewFiles.length > 0
|
|
554
|
+
? `${qoderCnProjectsDirResolved} (${qoderCnNewFiles.length} sessions)`
|
|
555
|
+
: "";
|
|
510
556
|
|
|
511
557
|
// Claude Science — token usage lives on the `frames` table of operon-cli.db.
|
|
512
558
|
// Unlike the native/WSL pair other providers resolve to, this is an open-ended
|
|
@@ -637,6 +683,11 @@ async function cmdStatus(argv = []) {
|
|
|
637
683
|
const dshSessionsDir = dshHomes.map((homeDir) => path.join(homeDir, "sessions")).join(", ");
|
|
638
684
|
const dshSessionFiles = await resolveDshSessionFiles(process.env);
|
|
639
685
|
const dshInstalled = dshSessionFiles.length > 0;
|
|
686
|
+
const lmstudioHome = resolveLmstudioHome(process.env);
|
|
687
|
+
const lmstudioLogFiles = await resolveLmstudioLogFiles(process.env);
|
|
688
|
+
const lmstudioInstalled = lmstudioLogFiles.length > 0;
|
|
689
|
+
const unslothDbPath = resolveUnslothDbPath(process.env);
|
|
690
|
+
const unslothInstalled = Boolean(unslothDbPath && fssync.existsSync(unslothDbPath));
|
|
640
691
|
|
|
641
692
|
// Trae SOLO (ByteDance AI IDE) — passive entitlement snapshot reader.
|
|
642
693
|
const traeStoragePath = resolveTraeStoragePath(process.env);
|
|
@@ -937,10 +988,10 @@ async function cmdStatus(argv = []) {
|
|
|
937
988
|
? { installed: true, detail: zcodeDbPath }
|
|
938
989
|
: { installed: false },
|
|
939
990
|
qoder: qoderInstalled
|
|
940
|
-
? { installed: true, detail: qoderDbPath }
|
|
991
|
+
? { installed: true, detail: summarizeQoderDetail(qoderDbPath, qoderNewPath) }
|
|
941
992
|
: { installed: false },
|
|
942
993
|
"qoder-cn": qoderCnInstalled
|
|
943
|
-
? { installed: true, detail: qoderCnDbPath }
|
|
994
|
+
? { installed: true, detail: summarizeQoderDetail(qoderCnDbPath, qoderCnNewPath) }
|
|
944
995
|
: { installed: false },
|
|
945
996
|
"claude-science": claudeScienceInstalled
|
|
946
997
|
? { installed: true, detail: claudeScienceDbPath }
|
|
@@ -961,6 +1012,16 @@ async function cmdStatus(argv = []) {
|
|
|
961
1012
|
dsh: dshInstalled
|
|
962
1013
|
? { installed: true, files: dshSessionFiles.length, detail: dshSessionsDir }
|
|
963
1014
|
: { installed: false },
|
|
1015
|
+
lmstudio: lmstudioInstalled
|
|
1016
|
+
? {
|
|
1017
|
+
installed: true,
|
|
1018
|
+
files: lmstudioLogFiles.length,
|
|
1019
|
+
detail: path.join(lmstudioHome, "server-logs"),
|
|
1020
|
+
}
|
|
1021
|
+
: { installed: false },
|
|
1022
|
+
unsloth: unslothInstalled
|
|
1023
|
+
? { installed: true, detail: unslothDbPath }
|
|
1024
|
+
: { installed: false },
|
|
964
1025
|
trae: traeInstalled
|
|
965
1026
|
? {
|
|
966
1027
|
installed: true,
|
|
@@ -1089,10 +1150,10 @@ async function cmdStatus(argv = []) {
|
|
|
1089
1150
|
? `- ZCode: passive reader (${zcodeDbPath})`
|
|
1090
1151
|
: null,
|
|
1091
1152
|
qoderInstalled
|
|
1092
|
-
? `- Qoder: passive reader (${qoderDbPath})`
|
|
1153
|
+
? `- Qoder: passive reader (${[qoderDbPath, qoderNewPath].filter(Boolean).join(" + ") || "not found"}${qoderNewInstalled && qoderActive.length > 0 ? " [legacy DB + new JSONL (both tracked)]" : ""}${qoderNewInstalled && qoderActive.length === 0 ? " [new JSONL only]" : ""})`
|
|
1093
1154
|
: null,
|
|
1094
1155
|
qoderCnInstalled
|
|
1095
|
-
? `- Qoder CN: passive reader (${qoderCnDbPath})`
|
|
1156
|
+
? `- Qoder CN: passive reader (${summarizeQoderDetail(qoderCnDbPath, qoderCnNewPath) || "not found"}${qoderCnNewInstalled && qoderCnActive.length > 0 ? " [legacy DB + new JSONL (both tracked)]" : ""}${qoderCnNewInstalled && qoderCnActive.length === 0 ? " [new JSONL only]" : ""})`
|
|
1096
1157
|
: null,
|
|
1097
1158
|
claudeScienceInstalled
|
|
1098
1159
|
? `- Claude Science: passive reader (${claudeScienceDbPath})`
|
|
@@ -1137,6 +1198,12 @@ async function cmdStatus(argv = []) {
|
|
|
1137
1198
|
dshInstalled
|
|
1138
1199
|
? `- DeepSeek Harness: passive reader (${dshSessionFiles.length} session${dshSessionFiles.length !== 1 ? "s" : ""} in ${dshSessionsDir})`
|
|
1139
1200
|
: null,
|
|
1201
|
+
lmstudioInstalled
|
|
1202
|
+
? `- LM Studio: passive reader (${lmstudioLogFiles.length} log${lmstudioLogFiles.length !== 1 ? "s" : ""} in ${path.join(lmstudioHome, "server-logs")})`
|
|
1203
|
+
: null,
|
|
1204
|
+
unslothInstalled
|
|
1205
|
+
? `- Unsloth Studio: passive reader (${unslothDbPath})`
|
|
1206
|
+
: null,
|
|
1140
1207
|
traeInstalled
|
|
1141
1208
|
// Deliberately NOT "passive reader": every other line with that wording
|
|
1142
1209
|
// means tokens are being counted. Trae encrypts its session transcripts
|
|
@@ -1438,4 +1505,4 @@ function parseEpochMsToIso(v) {
|
|
|
1438
1505
|
return d.toISOString();
|
|
1439
1506
|
}
|
|
1440
1507
|
|
|
1441
|
-
module.exports = { cmdStatus };
|
|
1508
|
+
module.exports = { cmdStatus, summarizeQoderDetail };
|
package/src/commands/sync.js
CHANGED
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
chmod600IfPossible,
|
|
16
16
|
openLock,
|
|
17
17
|
inspectLock,
|
|
18
|
+
updateJsonLocked,
|
|
18
19
|
} = require("../lib/fs");
|
|
19
20
|
const { physicalJsonlRecords } = require("../lib/jsonl-lines");
|
|
20
21
|
const {
|
|
@@ -33,6 +34,10 @@ const {
|
|
|
33
34
|
resolveQoderDbPaths,
|
|
34
35
|
resolveQoderCnDbPaths,
|
|
35
36
|
readQoderDbMessages,
|
|
37
|
+
resolveQoderProjectsDir,
|
|
38
|
+
resolveQoderCnProjectsDir,
|
|
39
|
+
listQoderNewSessionFiles,
|
|
40
|
+
parseQoderNewIncremental,
|
|
36
41
|
resolveKiroDbPath,
|
|
37
42
|
resolveKiroJsonlPath,
|
|
38
43
|
resolveKiroBasePath,
|
|
@@ -104,6 +109,10 @@ const {
|
|
|
104
109
|
parseRoocodeIncremental,
|
|
105
110
|
resolveZedDbPath,
|
|
106
111
|
parseZedIncremental,
|
|
112
|
+
resolveLmstudioLogFiles,
|
|
113
|
+
parseLmstudioIncremental,
|
|
114
|
+
resolveUnslothDbPath,
|
|
115
|
+
parseUnslothIncremental,
|
|
107
116
|
resolveAnythingllmDbPath,
|
|
108
117
|
parseAnythingllmIncremental,
|
|
109
118
|
resolveGooseDbPath,
|
|
@@ -260,6 +269,7 @@ const CODEX_COLD_SCAN_AUDIT_MAX_SYNCS = 288;
|
|
|
260
269
|
const MIMO_PROVIDER_REPAIR_KEY = "mimoClaudeMislabelRepair_2026_06";
|
|
261
270
|
const DSH_LEGACY_SOURCE_MIGRATION_KEY = "deepseekHarnessSourceMigration_2026_08";
|
|
262
271
|
const ZCODE_NATIVE_USAGE_REPAIR_KEY = "zcodeNativeUsageRepair_2026_08";
|
|
272
|
+
const ZCODE_INCLUSIVE_TOKEN_REPAIR_KEY = "zcodeInclusiveTokenRepair_2026_09";
|
|
263
273
|
const AUTO_SYNC_SOURCE_ALIASES = new Map([
|
|
264
274
|
["code", "every-code"],
|
|
265
275
|
["deepseek", "dsh"],
|
|
@@ -291,6 +301,7 @@ const AUTO_SYNC_SOURCES = new Set([
|
|
|
291
301
|
"kiro",
|
|
292
302
|
"kimi",
|
|
293
303
|
"kimi-code",
|
|
304
|
+
"lmstudio",
|
|
294
305
|
"mimo",
|
|
295
306
|
"omp",
|
|
296
307
|
"opencode",
|
|
@@ -301,6 +312,7 @@ const AUTO_SYNC_SOURCES = new Set([
|
|
|
301
312
|
"reasonix",
|
|
302
313
|
"roocode",
|
|
303
314
|
"trae-cn",
|
|
315
|
+
"unsloth",
|
|
304
316
|
"workbuddy",
|
|
305
317
|
"zcode",
|
|
306
318
|
"zed",
|
|
@@ -561,6 +573,8 @@ async function cmdSync(argv, context = {}) {
|
|
|
561
573
|
legacyBaseUrlMigration = {
|
|
562
574
|
previousDeviceToken,
|
|
563
575
|
replacementDeviceToken,
|
|
576
|
+
hadPersistedAnonKey: Object.prototype.hasOwnProperty.call(config, "anonKey"),
|
|
577
|
+
persistedAnonKey: config.anonKey,
|
|
564
578
|
};
|
|
565
579
|
}
|
|
566
580
|
const codexCursorRoots = [process.env.CODEX_HOME || path.join(home, ".codex")];
|
|
@@ -1259,6 +1273,39 @@ async function cmdSync(argv, context = {}) {
|
|
|
1259
1273
|
}
|
|
1260
1274
|
}
|
|
1261
1275
|
|
|
1276
|
+
// Qoder new (JSONL) — com.qoder.app.stable / ~/.qoder/projects (2026-08+)
|
|
1277
|
+
// The new Electron app no longer writes SharedClientCache/local.db; all
|
|
1278
|
+
// recent sessions live in ~/.qoder/projects as flat JSONL with credit-based
|
|
1279
|
+
// usage. Parse them into the same "qoder" source so history is continuous.
|
|
1280
|
+
// The legacy DB block above remains as a fallback for pre-migration rows.
|
|
1281
|
+
if (sourceAllowed("qoder")) {
|
|
1282
|
+
try {
|
|
1283
|
+
const projectsDir = resolveQoderProjectsDir({ home, env: process.env });
|
|
1284
|
+
const sessionFiles = await listQoderNewSessionFiles(projectsDir);
|
|
1285
|
+
if (sessionFiles.length > 0) {
|
|
1286
|
+
if (progress?.enabled) {
|
|
1287
|
+
progress.start(`Parsing Qoder (new) ${renderBar(0)} | buckets 0`);
|
|
1288
|
+
}
|
|
1289
|
+
const parsed = await parseQoderNewIncremental({
|
|
1290
|
+
sessionFiles,
|
|
1291
|
+
cursors,
|
|
1292
|
+
queuePath,
|
|
1293
|
+
projectQueuePath,
|
|
1294
|
+
onProgress: makeProviderProgress("Qoder (new)"),
|
|
1295
|
+
sourceKey: "qoder",
|
|
1296
|
+
cursorKey: "qoderNew",
|
|
1297
|
+
});
|
|
1298
|
+
qoderResult = {
|
|
1299
|
+
recordsProcessed: qoderResult.recordsProcessed + (parsed.messagesProcessed || 0),
|
|
1300
|
+
eventsAggregated: qoderResult.eventsAggregated + (parsed.eventsAggregated || 0),
|
|
1301
|
+
bucketsQueued: qoderResult.bucketsQueued + (parsed.bucketsQueued || 0),
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
} catch (err) {
|
|
1305
|
+
warnProviderParseFailure("Qoder (new)", err, opts);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1262
1309
|
// ── Qoder CN (国内版) — same SharedClientCache/local.db schema, separate
|
|
1263
1310
|
// Application Support/QoderCN data directory. Tracked as its own source
|
|
1264
1311
|
// with its own cursor namespace: the two DBs each number rowids from 1, so
|
|
@@ -1310,6 +1357,44 @@ async function cmdSync(argv, context = {}) {
|
|
|
1310
1357
|
}
|
|
1311
1358
|
}
|
|
1312
1359
|
|
|
1360
|
+
// Qoder CN new (JSONL) — currently shares ~/.qoder/projects with international;
|
|
1361
|
+
// keep distinct parsing only when CN projects dir diverges (future CN split)
|
|
1362
|
+
// to avoid double-counting the same JSONL under two sources.
|
|
1363
|
+
if (sourceAllowed("qoder-cn")) {
|
|
1364
|
+
try {
|
|
1365
|
+
const cnProjectsDir = resolveQoderCnProjectsDir({ home, env: process.env });
|
|
1366
|
+
const intlProjectsDir = resolveQoderProjectsDir({ home, env: process.env });
|
|
1367
|
+
const projectsDirKey = (p) => {
|
|
1368
|
+
const normalized = path.normalize(p);
|
|
1369
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
1370
|
+
};
|
|
1371
|
+
if (projectsDirKey(cnProjectsDir) !== projectsDirKey(intlProjectsDir)) {
|
|
1372
|
+
const sessionFiles = await listQoderNewSessionFiles(cnProjectsDir);
|
|
1373
|
+
if (sessionFiles.length > 0) {
|
|
1374
|
+
if (progress?.enabled) {
|
|
1375
|
+
progress.start(`Parsing Qoder CN (new) ${renderBar(0)} | buckets 0`);
|
|
1376
|
+
}
|
|
1377
|
+
const parsed = await parseQoderNewIncremental({
|
|
1378
|
+
sessionFiles,
|
|
1379
|
+
cursors,
|
|
1380
|
+
queuePath,
|
|
1381
|
+
projectQueuePath,
|
|
1382
|
+
onProgress: makeProviderProgress("Qoder CN (new)"),
|
|
1383
|
+
sourceKey: "qoder-cn",
|
|
1384
|
+
cursorKey: "qoderCnNew",
|
|
1385
|
+
});
|
|
1386
|
+
qoderCnResult = {
|
|
1387
|
+
recordsProcessed: qoderCnResult.recordsProcessed + (parsed.messagesProcessed || 0),
|
|
1388
|
+
eventsAggregated: qoderCnResult.eventsAggregated + (parsed.eventsAggregated || 0),
|
|
1389
|
+
bucketsQueued: qoderCnResult.bucketsQueued + (parsed.bucketsQueued || 0),
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
} catch (err) {
|
|
1394
|
+
warnProviderParseFailure("Qoder CN (new)", err, opts);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1313
1398
|
// ── Claude Science (Anthropic's local research workbench, issue #246) ──
|
|
1314
1399
|
// Per-frame token usage lives on the `frames` table of operon-cli.db.
|
|
1315
1400
|
// Passive, incremental, subtract-on-change. There can be more than one DB:
|
|
@@ -1432,6 +1517,13 @@ async function cmdSync(argv, context = {}) {
|
|
|
1432
1517
|
projectQueueStatePath,
|
|
1433
1518
|
});
|
|
1434
1519
|
}
|
|
1520
|
+
await repairZcodeInclusiveTokenMigration({
|
|
1521
|
+
cursors,
|
|
1522
|
+
queuePath,
|
|
1523
|
+
queueStatePath,
|
|
1524
|
+
projectQueuePath,
|
|
1525
|
+
projectQueueStatePath,
|
|
1526
|
+
});
|
|
1435
1527
|
zcodeResult = await multiInstallParse({
|
|
1436
1528
|
paths: zcodePaths, parserFn: parseOpencodeDbForInstall, providerName: "zcode",
|
|
1437
1529
|
cursors, getParams: (p) => ({ dbPath: p, readFn: readZcodeDbMessages, source: "zcode", cursorKey: "zcode" }),
|
|
@@ -1477,6 +1569,47 @@ async function cmdSync(argv, context = {}) {
|
|
|
1477
1569
|
}
|
|
1478
1570
|
}
|
|
1479
1571
|
|
|
1572
|
+
// ── LM Studio and Unsloth Studio — passive inference usage ──
|
|
1573
|
+
let lmstudioResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
1574
|
+
if (sourceAllowed("lmstudio")) {
|
|
1575
|
+
const lmstudioLogFiles = await resolveLmstudioLogFiles(process.env);
|
|
1576
|
+
if (lmstudioLogFiles.length > 0) {
|
|
1577
|
+
if (progress?.enabled) {
|
|
1578
|
+
progress.start(
|
|
1579
|
+
`Parsing LM Studio ${renderBar(0)} 0/${formatNumber(lmstudioLogFiles.length)} logs | buckets 0`,
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1582
|
+
try {
|
|
1583
|
+
lmstudioResult = await parseLmstudioIncremental({
|
|
1584
|
+
logFiles: lmstudioLogFiles,
|
|
1585
|
+
cursors,
|
|
1586
|
+
queuePath,
|
|
1587
|
+
onProgress: makeProviderProgress("LM Studio"),
|
|
1588
|
+
});
|
|
1589
|
+
} catch (err) {
|
|
1590
|
+
warnProviderParseFailure("LM Studio", err, opts);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
let unslothResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
1596
|
+
if (sourceAllowed("unsloth")) {
|
|
1597
|
+
const unslothDbPath = resolveUnslothDbPath(process.env);
|
|
1598
|
+
if (unslothDbPath && fssync.existsSync(unslothDbPath)) {
|
|
1599
|
+
if (progress?.enabled) progress.start(`Parsing Unsloth ${renderBar(0)} | buckets 0`);
|
|
1600
|
+
try {
|
|
1601
|
+
unslothResult = await parseUnslothIncremental({
|
|
1602
|
+
dbPath: unslothDbPath,
|
|
1603
|
+
cursors,
|
|
1604
|
+
queuePath,
|
|
1605
|
+
onProgress: makeProviderProgress("Unsloth"),
|
|
1606
|
+
});
|
|
1607
|
+
} catch (err) {
|
|
1608
|
+
warnProviderParseFailure("Unsloth", err, opts);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1480
1613
|
// ── AnythingLLM Desktop (workspace_chats.response.metrics) ──
|
|
1481
1614
|
let anythingllmResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
1482
1615
|
if (sourceAllowed("anythingllm")) {
|
|
@@ -2747,6 +2880,8 @@ async function cmdSync(argv, context = {}) {
|
|
|
2747
2880
|
reasonixResult.recordsProcessed +
|
|
2748
2881
|
grokResult.recordsProcessed +
|
|
2749
2882
|
copilotResult.recordsProcessed +
|
|
2883
|
+
lmstudioResult.recordsProcessed +
|
|
2884
|
+
unslothResult.recordsProcessed +
|
|
2750
2885
|
anythingllmResult.recordsProcessed +
|
|
2751
2886
|
kiloResult.recordsProcessed +
|
|
2752
2887
|
mimoResult.recordsProcessed +
|
|
@@ -2783,6 +2918,8 @@ async function cmdSync(argv, context = {}) {
|
|
|
2783
2918
|
reasonixResult.bucketsQueued +
|
|
2784
2919
|
grokResult.bucketsQueued +
|
|
2785
2920
|
copilotResult.bucketsQueued +
|
|
2921
|
+
lmstudioResult.bucketsQueued +
|
|
2922
|
+
unslothResult.bucketsQueued +
|
|
2786
2923
|
anythingllmResult.bucketsQueued +
|
|
2787
2924
|
kiloResult.bucketsQueued +
|
|
2788
2925
|
mimoResult.bucketsQueued +
|
|
@@ -2835,6 +2972,9 @@ async function cmdSync(argv, context = {}) {
|
|
|
2835
2972
|
progress?.stop();
|
|
2836
2973
|
|
|
2837
2974
|
const runtimeConfig = config ? { ...config } : {};
|
|
2975
|
+
if (legacyBaseUrlMigration) {
|
|
2976
|
+
delete runtimeConfig.anonKey;
|
|
2977
|
+
}
|
|
2838
2978
|
if (legacyBaseUrlMigration?.replacementDeviceToken) {
|
|
2839
2979
|
runtimeConfig.deviceToken = legacyBaseUrlMigration.replacementDeviceToken;
|
|
2840
2980
|
}
|
|
@@ -2888,6 +3028,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
2888
3028
|
const drainWithToken = (deviceToken) =>
|
|
2889
3029
|
drainQueueToCloud({
|
|
2890
3030
|
baseUrl: runtime.baseUrl,
|
|
3031
|
+
anonKey: runtime.anonKey,
|
|
2891
3032
|
deviceToken,
|
|
2892
3033
|
queuePath,
|
|
2893
3034
|
queueStatePath,
|
|
@@ -2917,15 +3058,25 @@ async function cmdSync(argv, context = {}) {
|
|
|
2917
3058
|
if (legacyBaseUrlMigration && uploadResult.batches > 0) {
|
|
2918
3059
|
// device-login does not share the sync lock and may have written a
|
|
2919
3060
|
// fresh current-backend config while the scan/upload was running.
|
|
2920
|
-
// Re-read before committing
|
|
2921
|
-
//
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
3061
|
+
// Re-read before committing and only remove the anonymous key this
|
|
3062
|
+
// migration observed. A concurrent login may replace the backend URL
|
|
3063
|
+
// while preserving the old key, or another writer may replace the key
|
|
3064
|
+
// while the legacy URL is still present.
|
|
3065
|
+
await updateJsonLocked(configPath, async (latestConfig) => {
|
|
3066
|
+
const hasLegacyBaseUrl = isLegacyInsforgeBaseUrl(latestConfig.baseUrl);
|
|
3067
|
+
const hasUnchangedLegacyAnonKey =
|
|
3068
|
+
legacyBaseUrlMigration.hadPersistedAnonKey &&
|
|
3069
|
+
latestConfig.anonKey === legacyBaseUrlMigration.persistedAnonKey;
|
|
3070
|
+
if (!hasLegacyBaseUrl && !hasUnchangedLegacyAnonKey) return null;
|
|
3071
|
+
if (hasLegacyBaseUrl) {
|
|
3072
|
+
latestConfig.deviceToken = successfulDeviceToken;
|
|
3073
|
+
delete latestConfig.baseUrl;
|
|
3074
|
+
}
|
|
3075
|
+
if (hasUnchangedLegacyAnonKey) {
|
|
3076
|
+
delete latestConfig.anonKey;
|
|
3077
|
+
}
|
|
3078
|
+
return latestConfig;
|
|
3079
|
+
});
|
|
2929
3080
|
}
|
|
2930
3081
|
// Record success so the exponential backoff step resets — otherwise
|
|
2931
3082
|
// a single past failure keeps us pessimistically throttled forever.
|
|
@@ -3138,6 +3289,7 @@ module.exports = {
|
|
|
3138
3289
|
repairDroidDuplicateSessionInflation,
|
|
3139
3290
|
repairMimoClaudeMislabel,
|
|
3140
3291
|
repairZcodeNativeUsageMigration,
|
|
3292
|
+
repairZcodeInclusiveTokenMigration,
|
|
3141
3293
|
reincludeClaudeMemObserverFiles,
|
|
3142
3294
|
repairGrokQueueFromSessionSnapshots,
|
|
3143
3295
|
applyCloudConversationsBackfill,
|
|
@@ -3613,7 +3765,7 @@ const AUTO_RETRY_MAX_DELAY_MS = 2 * 60 * 60 * 1000;
|
|
|
3613
3765
|
const INGEST_SLUG = "tokentracker-ingest";
|
|
3614
3766
|
const MAX_INGEST_BUCKETS = 500;
|
|
3615
3767
|
|
|
3616
|
-
async function drainQueueToCloud({ baseUrl, deviceToken, queuePath, queueStatePath, maxBatches = 5, batchSize = 200 }) {
|
|
3768
|
+
async function drainQueueToCloud({ baseUrl, anonKey, deviceToken, queuePath, queueStatePath, maxBatches = 5, batchSize = 200 }) {
|
|
3617
3769
|
const state = (await readJson(queueStatePath)) || { offset: 0 };
|
|
3618
3770
|
let offset = Number(state.offset || 0);
|
|
3619
3771
|
let inserted = 0;
|
|
@@ -3632,7 +3784,6 @@ async function drainQueueToCloud({ baseUrl, deviceToken, queuePath, queueStatePa
|
|
|
3632
3784
|
if (result.buckets.length === 0 && result.sessionStates.length === 0) break;
|
|
3633
3785
|
|
|
3634
3786
|
const root = baseUrl.replace(/\/$/, "");
|
|
3635
|
-
const anonKey = process.env.TOKENTRACKER_INSFORGE_ANON_KEY || "";
|
|
3636
3787
|
const headers = {
|
|
3637
3788
|
"Content-Type": "application/json",
|
|
3638
3789
|
Accept: "application/json",
|
|
@@ -4116,7 +4267,7 @@ async function repairMimoClaudeMislabel({
|
|
|
4116
4267
|
return true;
|
|
4117
4268
|
}
|
|
4118
4269
|
|
|
4119
|
-
async function
|
|
4270
|
+
async function resetUploadOffsetForZcodeRepair(queueStatePath, note) {
|
|
4120
4271
|
if (typeof queueStatePath !== "string" || !queueStatePath) return false;
|
|
4121
4272
|
let state = {};
|
|
4122
4273
|
try {
|
|
@@ -4126,7 +4277,7 @@ async function resetUploadOffsetForZcodeNativeRepair(queueStatePath) {
|
|
|
4126
4277
|
}
|
|
4127
4278
|
state.offset = 0;
|
|
4128
4279
|
state.updatedAt = new Date().toISOString();
|
|
4129
|
-
state.note =
|
|
4280
|
+
state.note = note;
|
|
4130
4281
|
await ensureDir(path.dirname(queueStatePath));
|
|
4131
4282
|
await fs.writeFile(queueStatePath, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
4132
4283
|
return true;
|
|
@@ -4188,7 +4339,9 @@ async function dropZcodeQueueRows(filePath, { retainRetractions = false } = {})
|
|
|
4188
4339
|
return { removed, retractions: retractions.size };
|
|
4189
4340
|
}
|
|
4190
4341
|
|
|
4191
|
-
async function
|
|
4342
|
+
async function repairZcodeUsageMigration({
|
|
4343
|
+
migrationKey,
|
|
4344
|
+
queueStateNote,
|
|
4192
4345
|
cursors,
|
|
4193
4346
|
queuePath,
|
|
4194
4347
|
queueStatePath,
|
|
@@ -4197,7 +4350,7 @@ async function repairZcodeNativeUsageMigration({
|
|
|
4197
4350
|
} = {}) {
|
|
4198
4351
|
if (!cursors || typeof cursors !== "object") return false;
|
|
4199
4352
|
const migrations = (cursors.migrations ||= {});
|
|
4200
|
-
if (migrations[
|
|
4353
|
+
if (migrations[migrationKey]) return false;
|
|
4201
4354
|
|
|
4202
4355
|
const mainRepair = await dropZcodeQueueRows(queuePath, { retainRetractions: true });
|
|
4203
4356
|
const projectRepair = projectQueuePath
|
|
@@ -4225,11 +4378,13 @@ async function repairZcodeNativeUsageMigration({
|
|
|
4225
4378
|
}
|
|
4226
4379
|
delete cursors.zcode;
|
|
4227
4380
|
|
|
4228
|
-
if (mainRepair.removed > 0)
|
|
4381
|
+
if (mainRepair.removed > 0) {
|
|
4382
|
+
await resetUploadOffsetForZcodeRepair(queueStatePath, queueStateNote);
|
|
4383
|
+
}
|
|
4229
4384
|
if (projectRepair.removed > 0) {
|
|
4230
|
-
await
|
|
4385
|
+
await resetUploadOffsetForZcodeRepair(projectQueueStatePath, queueStateNote);
|
|
4231
4386
|
}
|
|
4232
|
-
migrations[
|
|
4387
|
+
migrations[migrationKey] = {
|
|
4233
4388
|
appliedAt: new Date().toISOString(),
|
|
4234
4389
|
removedMain: mainRepair.removed,
|
|
4235
4390
|
removedProject: projectRepair.removed,
|
|
@@ -4238,6 +4393,22 @@ async function repairZcodeNativeUsageMigration({
|
|
|
4238
4393
|
return true;
|
|
4239
4394
|
}
|
|
4240
4395
|
|
|
4396
|
+
async function repairZcodeNativeUsageMigration(options = {}) {
|
|
4397
|
+
return repairZcodeUsageMigration({
|
|
4398
|
+
...options,
|
|
4399
|
+
migrationKey: ZCODE_NATIVE_USAGE_REPAIR_KEY,
|
|
4400
|
+
queueStateNote: "reset_after_zcode_native_usage_repair_2026_08",
|
|
4401
|
+
});
|
|
4402
|
+
}
|
|
4403
|
+
|
|
4404
|
+
async function repairZcodeInclusiveTokenMigration(options = {}) {
|
|
4405
|
+
return repairZcodeUsageMigration({
|
|
4406
|
+
...options,
|
|
4407
|
+
migrationKey: ZCODE_INCLUSIVE_TOKEN_REPAIR_KEY,
|
|
4408
|
+
queueStateNote: "reset_after_zcode_inclusive_token_repair_2026_09",
|
|
4409
|
+
});
|
|
4410
|
+
}
|
|
4411
|
+
|
|
4241
4412
|
async function repairGrokQueueFromSessionSnapshots({ cursors, queuePath, queueStatePath } = {}) {
|
|
4242
4413
|
if (!cursors || typeof cursors !== "object") return false;
|
|
4243
4414
|
const grokState = (cursors.grok ||= {});
|