tokentracker-cli 1.5.0 → 1.5.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.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dashboard/dist/.well-known/submitby-ai/6e2fa70e-9eb2-4c97-a9a9-fed567a3d4a9.txt +1 -0
- package/dashboard/dist/assets/AchievementBadge-mB7HZSGE.js +1 -0
- package/dashboard/dist/assets/{AchievementsPage-9_MxdI7O.js → AchievementsPage-DLzeq_eo.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-CKDQGcJh.js → AchievementsSection-DrXQyDns.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-DdrXPVRL.js → BadgeDetailModal-WrgKRybi.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-DsJDdDid.js → BotAnimated-DFRaixVK.js} +1 -1
- package/dashboard/dist/assets/{Card-Bz-sWY1C.js → Card-bFq2tlO8.js} +1 -1
- package/dashboard/dist/assets/{CloudCheckoutPage-DRjZcE0W.js → CloudCheckoutPage-gwhGxavy.js} +1 -1
- package/dashboard/dist/assets/{CloudPage-BNDyyX9r.js → CloudPage-BD4iBYeZ.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-LbE6Icc0.js → CommandPalette-C_KlPl0U.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-DuEcAOB9.js → CommunityStatsModal-Cl1Bgv8M.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-B5V7ONKv.js → ConfirmModal-NWoYevYC.js} +1 -1
- package/dashboard/dist/assets/{Controls-ZfN0QwwD.js → Controls-D2-D2cfA.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-DqZPFmlv.js → DashboardPage-vITMnPXx.js} +1 -1
- package/dashboard/dist/assets/{DateRangePopover-CbkBeaEI.js → DateRangePopover-8EMVXuH6.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-DrHjmpPH.js → DevicePage-DbP8d6bM.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-DHaAwV1u.js → DialogClose-CEstgLa1.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-0wcygxtH.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-CBhd4oLc.js → DialogTitle-DP5TLLbz.js} +1 -1
- package/dashboard/dist/assets/{ElectricLogo-CSWd3b2H.js → ElectricLogo-Uvi3yMum.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-D5p6nDla.js → FadeIn-Dpzihg6f.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-BKVSzY27.js → HeaderGithubStar-DllqemKr.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-CvkAyCDm.js → HoverTooltip-Dc-TAH6l.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-BEMJGKtl.js → IpCheckPage-jd1D5ZKX.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-iRp33enQ.js → LandingPage-CB1ZVw-a.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardPage-DVMPrN4z.js → LeaderboardPage-Bt2cRRmE.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProBadge-DwnaJoje.js → LeaderboardProBadge-BVlyVOFf.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardProfileModal-DnzVweLM.js → LeaderboardProfileModal-CwQFRJg_.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-BHNuPuW7.js → LeaderboardProfilePage-CeqcTbUG.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-9LitacBf.js → LimitsPage-Bp4ZORmR.js} +6 -6
- package/dashboard/dist/assets/{LocalOnlyNotice-DStlbPET.js → LocalOnlyNotice-B2_HoCVD.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-I47ukXU5.js → LoginCard-nw9JOc2d.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-C4iotNjY.js → LoginModal-BHNLTK1D.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-46QSEnG0.js → LoginPage-LI2GZKhM.js} +1 -1
- package/dashboard/dist/assets/{PetPage-SvgDUR8o.js → PetPage-CK6sPeI0.js} +2 -2
- package/dashboard/dist/assets/{PopoverPopup-k2ejLK1I.js → PopoverPopup-BsXchEVa.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-Bx1XKzin.js → ProviderIcon-vgCEy0dh.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-CcKIDknp.js → ResetPasswordPage-B4CPj2vX.js} +1 -1
- package/dashboard/dist/assets/{Select-D0hLQyU8.js → Select-BkAy6P2r.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-DJGBJhDK.js → SelectItemText-C0RNqDrD.js} +1 -1
- package/dashboard/dist/assets/{SelfHostPage-CeIFGRep.js → SelfHostPage-B-_w-Z-a.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-DMtw0YDh.js → ServiceStatusPage-5YevsGGD.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-D6h5vSZn.js → SessionsPage-CmWXBqD2.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-BZgpB5SB.js → SettingsPage-CA70zP-t.js} +3 -3
- package/dashboard/dist/assets/{SkillsPage-CtFuZ1ob.js → SkillsPage-CNamhfzU.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-DC-no047.js → TokenGalaxy-CXrVBSk6.js} +1 -1
- package/dashboard/dist/assets/{TooltipPopup-ZM0Ie2_C.js → TooltipPopup-CR4MqElX.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-fpLaqJ-o.js → TrendMonitor-DQfcrEve.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-DIoHY6ZJ.js → WidgetsPage-BBXxtZbP.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-D1-7o8Z1.js → WrappedPage-C8i2KlMF.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-DZF5L1pt.js → __vite-browser-external-BEEzY7mq.js} +2 -2
- package/dashboard/dist/assets/{agent-logos-YBC1iAbE.js → agent-logos-CxQb8vir.js} +1 -1
- package/dashboard/dist/assets/{arrow-left-BIe3z7iW.js → arrow-left-D6zkcLVt.js} +1 -1
- package/dashboard/dist/assets/{arrow-right-CJmRcvYZ.js → arrow-right-BGb-XVn_.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-IgkBHoCl.js → arrow-up-right-XTStagDJ.js} +1 -1
- package/dashboard/dist/assets/{calendar-days-DTuIv3ts.js → calendar-days-Cz3NGZiS.js} +1 -1
- package/dashboard/dist/assets/{check-DrXhhj46.js → check-1z_vmHPD.js} +1 -1
- package/dashboard/dist/assets/{chevron-down-DHaFKHMK.js → chevron-down-CkSBY3bE.js} +1 -1
- package/dashboard/dist/assets/{cloud-checkout-BffVMyzI.js → cloud-checkout-pD5C4r_S.js} +1 -1
- package/dashboard/dist/assets/{composite-M_CP_KSx.js → composite-BtDzx3a2.js} +1 -1
- package/dashboard/dist/assets/{copy-D5xoS-Q8.js → copy-Ctv_wxuD.js} +1 -1
- package/dashboard/dist/assets/{download-CqomMv4-.js → download-DKbKMGSR.js} +1 -1
- package/dashboard/dist/assets/{external-link--q3pCw6b.js → external-link-g9cU017t.js} +1 -1
- package/dashboard/dist/assets/{flame-CUGlDV__.js → flame-DZq3kXUt.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-BZ6TX9Km.js → format-tokens-CXQfx0PC.js} +1 -1
- package/dashboard/dist/assets/{gift-BBgOeC20.js → gift-CKlKjGP6.js} +1 -1
- package/dashboard/dist/assets/{icons-BELeB4ms.js → icons-xPGMnBjl.js} +1 -1
- package/dashboard/dist/assets/{index-CsdgnKGf.js → index-BwOjMtB2.js} +1 -1
- package/dashboard/dist/assets/{index-CoRqgJ71.js → index-CDBOKcDh.js} +1 -1
- package/dashboard/dist/assets/{index-DkBvk4Qg.js → index-Dl0oFLNr.js} +33 -33
- package/dashboard/dist/assets/{index-B1B6oAbl.js → index-fVbP5wOv.js} +1 -1
- package/dashboard/dist/assets/{info-BG1vQZ1r.js → info-D9xNIuGh.js} +1 -1
- package/dashboard/dist/assets/{link-2-oi5TrXqi.js → link-2-Bk5wYt2n.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-BQQ_Xbby.js → loader-circle-CcN3pHWb.js} +1 -1
- package/dashboard/dist/assets/{local-usage-transfer-Dwz-clJ-.js → local-usage-transfer-CYcy1ici.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-C7a817l7.js → modifiers.esm-DbpEzkJe.js} +1 -1
- package/dashboard/dist/assets/module-ZyVsxBG_.js +3 -0
- package/dashboard/dist/assets/{monitor-smartphone-Bnbo7uRg.js → monitor-smartphone-WkWv1qIS.js} +1 -1
- package/dashboard/dist/assets/{play-C_xI_JM_.js → play-2yZGWMes.js} +1 -1
- package/dashboard/dist/assets/{plus-xF6PK5As.js → plus-mOF8tG1F.js} +1 -1
- package/dashboard/dist/assets/{provider-display-DxquW3js.js → provider-display-7gaOvgMp.js} +1 -1
- package/dashboard/dist/assets/{react-CGK0_x3G.js → react-CdPiPDhk.js} +1 -1
- package/dashboard/dist/assets/{safePolygon-CCoDMR4f.js → safePolygon-C7FJLAlh.js} +1 -1
- package/dashboard/dist/assets/{search-EZAGpmfJ.js → search-C63nCrjo.js} +1 -1
- package/dashboard/dist/assets/{server-2qbrx2G0.js → server-BaG1rnuv.js} +1 -1
- package/dashboard/dist/assets/{shield-check-D8kUejpE.js → shield-check-D_4-Cm6L.js} +1 -1
- package/dashboard/dist/assets/{skills-api-DYPf1Vxh.js → skills-api-DfbzwpDv.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-D9gC08dQ.js → sortable.esm-D-v8FRX5.js} +1 -1
- package/dashboard/dist/assets/{store-BWUCbK6Y.js → store-Dv_FYrXK.js} +1 -1
- package/dashboard/dist/assets/{terminal-B16b7r6H.js → terminal-FQi6MaYt.js} +1 -1
- package/dashboard/dist/assets/{trash-BIEoE13C.js → trash-TbK96dEz.js} +1 -1
- package/dashboard/dist/assets/use-community-stats-DGoWVZuk.js +1 -0
- package/dashboard/dist/assets/{use-latest-request-guard-CYKu-VOB.js → use-latest-request-guard-Dg6uSaYt.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-CEAjVxFr.js → use-limits-display-prefs-Djbdp7fi.js} +1 -1
- package/dashboard/dist/assets/{use-native-settings-vTg4j5Ln.js → use-native-settings-DIk0AF3b.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-CtXedlqH.js → use-ordered-list-CUqV3Zgl.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-DMCok-vZ.js +1 -0
- package/dashboard/dist/assets/{use-transform-CdeW5xhz.js → use-transform-D_-w22c8.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-DmDa5Py8.js → use-usage-limits-h7aGsIQr.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-bqycM681.js → useCurrency-B_AuLCsL.js} +1 -1
- package/dashboard/dist/assets/{usePositioner-DEXS10fY.js → usePositioner-DfxvIif8.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-YF6hY8_m.js → useTokenFormat-bbO13V4s.js} +1 -1
- package/dashboard/dist/assets/{zap-Dg-ij-lq.js → zap-k07-EXTK.js} +1 -1
- package/dashboard/dist/index.html +20 -1
- package/dashboard/dist/indexnow-key.txt +1 -0
- package/dashboard/dist/ip-check.html +1 -1
- package/dashboard/dist/leaderboard.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/dashboard/dist/tt6a1c9e2f4b8d.txt +1 -0
- package/package.json +3 -3
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/qoder-limits.js +178 -38
- package/dashboard/dist/assets/AchievementBadge-Dn39pyx9.js +0 -1
- package/dashboard/dist/assets/DialogDescription-CEY6jbs9.js +0 -1
- package/dashboard/dist/assets/module-C2SOSUuR.js +0 -3
- package/dashboard/dist/assets/use-community-stats-DWS7YKbM.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-DVLsAhSA.js +0 -1
package/src/lib/qoder-limits.js
CHANGED
|
@@ -40,6 +40,14 @@ const QODER_ACTIVITY_CACHE_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
|
40
40
|
const QODER_LIMITS_CACHE_FILE = "qoder-usage-limits-cache.json";
|
|
41
41
|
const QODER_LIMITS_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
42
42
|
const QODER_LIMITS_CACHE_UNKNOWN_RESET_TTL_MS = 12 * 60 * 60 * 1000;
|
|
43
|
+
// Qoder Desktop 0.4+ writes its account usage summary to main.log, which can
|
|
44
|
+
// accumulate a whole session before the quota is read. Scan a bounded window
|
|
45
|
+
// backwards instead of assuming the summary is near EOF.
|
|
46
|
+
const QODER_LOG_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
47
|
+
const QODER_LOG_SCAN_MAX_BYTES = 8 * 1024 * 1024;
|
|
48
|
+
const QODER_LOG_SCAN_CHUNK_BYTES = 512 * 1024;
|
|
49
|
+
const QODER_LOG_SCAN_OVERLAP_BYTES = 64 * 1024;
|
|
50
|
+
const QODER_LOG_MAX_FILES = 8;
|
|
43
51
|
const QODER_SERVER_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
44
52
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA8iMH5c02LilrsERw9t6Pv5Nc
|
|
45
53
|
4k6Pz1EaDicBMpdpxKduSZu5OANqUq8er4GM95omAGIOPOh+Nx0spthYA2BqGz+l
|
|
@@ -575,7 +583,38 @@ async function fetchQoderUsage(cookieHeader, site, fetchImpl) {
|
|
|
575
583
|
return normalizeQoderUsageResponse(await response.json());
|
|
576
584
|
}
|
|
577
585
|
|
|
578
|
-
function
|
|
586
|
+
function qoderLogRoots({
|
|
587
|
+
home = os.homedir(),
|
|
588
|
+
platform = process.platform,
|
|
589
|
+
env = process.env,
|
|
590
|
+
appDir = "Qoder",
|
|
591
|
+
envPrefix = "QODER",
|
|
592
|
+
} = {}) {
|
|
593
|
+
const explicitLogRoot = env[`${envPrefix}_LOG_ROOT`];
|
|
594
|
+
if (typeof explicitLogRoot === "string" && explicitLogRoot.trim()) {
|
|
595
|
+
return [path.resolve(explicitLogRoot.trim())];
|
|
596
|
+
}
|
|
597
|
+
const configuredHome = env[`${envPrefix}_HOME`];
|
|
598
|
+
if (typeof configuredHome === "string" && configuredHome.trim()) {
|
|
599
|
+
return [path.join(path.resolve(configuredHome.trim()), "logs")];
|
|
600
|
+
}
|
|
601
|
+
const base = platform === "darwin"
|
|
602
|
+
? path.join(home, "Library", "Application Support")
|
|
603
|
+
: platform === "win32"
|
|
604
|
+
? (env.APPDATA || path.join(home, "AppData", "Roaming"))
|
|
605
|
+
: path.join(home, ".config");
|
|
606
|
+
// Qoder Desktop 0.4.x moved its Electron profile from Qoder[CN]/ to the
|
|
607
|
+
// bundle id directory and writes the account usage summary to main.log.
|
|
608
|
+
const bundleId = appDir === "QoderCN" || envPrefix === "QODER_CN"
|
|
609
|
+
? "com.qodercn.app.stable"
|
|
610
|
+
: "com.qoder.app.stable";
|
|
611
|
+
return [
|
|
612
|
+
path.join(base, appDir, "logs"),
|
|
613
|
+
path.join(base, bundleId, "logs"),
|
|
614
|
+
];
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function listRecentQoderLogs(logRoot, maxFiles = QODER_LOG_MAX_FILES) {
|
|
579
618
|
if (!fs.existsSync(logRoot)) return [];
|
|
580
619
|
const files = [];
|
|
581
620
|
const stack = [{ dir: logRoot, depth: 0 }];
|
|
@@ -591,19 +630,106 @@ function listRecentQoderRendererLogs(logRoot, maxFiles = 12) {
|
|
|
591
630
|
const full = path.join(current.dir, entry.name);
|
|
592
631
|
if (entry.isDirectory() && current.depth < 4) {
|
|
593
632
|
stack.push({ dir: full, depth: current.depth + 1 });
|
|
594
|
-
} else if (entry.isFile() && entry.name === "renderer.log") {
|
|
633
|
+
} else if (entry.isFile() && (entry.name === "main.log" || entry.name === "renderer.log")) {
|
|
595
634
|
let mtimeMs = 0;
|
|
635
|
+
let size = 0;
|
|
596
636
|
try {
|
|
597
|
-
|
|
637
|
+
const stat = fs.statSync(full);
|
|
638
|
+
mtimeMs = stat.mtimeMs;
|
|
639
|
+
size = stat.size;
|
|
598
640
|
} catch (_error) {}
|
|
599
|
-
files.push({ full, mtimeMs });
|
|
641
|
+
files.push({ full, mtimeMs, size });
|
|
600
642
|
}
|
|
601
643
|
}
|
|
602
644
|
}
|
|
603
645
|
return files
|
|
604
646
|
.sort((a, b) => b.mtimeMs - a.mtimeMs)
|
|
605
|
-
.slice(0, maxFiles)
|
|
606
|
-
|
|
647
|
+
.slice(0, maxFiles);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// Returns a parse hit, or null after a completed scan with no hit; undefined
|
|
651
|
+
// means the scan itself failed (open/read) so callers must not treat it as
|
|
652
|
+
// "no summary".
|
|
653
|
+
function scanQoderLogFromEnd(logPath, parse, {
|
|
654
|
+
maxBytes = QODER_LOG_SCAN_MAX_BYTES,
|
|
655
|
+
chunkBytes = QODER_LOG_SCAN_CHUNK_BYTES,
|
|
656
|
+
overlapBytes = QODER_LOG_SCAN_OVERLAP_BYTES,
|
|
657
|
+
} = {}) {
|
|
658
|
+
let fd;
|
|
659
|
+
try {
|
|
660
|
+
fd = fs.openSync(logPath, "r");
|
|
661
|
+
} catch (_error) {
|
|
662
|
+
return undefined;
|
|
663
|
+
}
|
|
664
|
+
try {
|
|
665
|
+
const size = fs.fstatSync(fd).size;
|
|
666
|
+
const floor = Math.max(0, size - maxBytes);
|
|
667
|
+
let end = size;
|
|
668
|
+
let carry = "";
|
|
669
|
+
while (end > floor) {
|
|
670
|
+
const start = Math.max(floor, end - chunkBytes);
|
|
671
|
+
const length = end - start;
|
|
672
|
+
const buffer = Buffer.alloc(length);
|
|
673
|
+
const read = fs.readSync(fd, buffer, 0, length, start);
|
|
674
|
+
const text = buffer.subarray(0, read).toString("utf8") + carry;
|
|
675
|
+
const parsed = parse(text);
|
|
676
|
+
if (parsed) return parsed;
|
|
677
|
+
// Keep this chunk's head so a line split across the boundary parses
|
|
678
|
+
// when the previous chunk is prepended.
|
|
679
|
+
carry = text.slice(0, overlapBytes);
|
|
680
|
+
end = start;
|
|
681
|
+
}
|
|
682
|
+
} catch (_error) {
|
|
683
|
+
return undefined;
|
|
684
|
+
} finally {
|
|
685
|
+
fs.closeSync(fd);
|
|
686
|
+
}
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function parseQoderAccountUsageLog(text, { fallbackObservedAtMs = null } = {}) {
|
|
691
|
+
if (typeof text !== "string" || !text.includes('"qoderUsage"')) return null;
|
|
692
|
+
const lines = text.split(/\r?\n/);
|
|
693
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
694
|
+
const line = lines[index];
|
|
695
|
+
if (!line.includes('"qoderUsage"')) continue;
|
|
696
|
+
const jsonStart = line.indexOf('{"') >= 0 ? line.indexOf('{"') : line.indexOf("{");
|
|
697
|
+
if (jsonStart < 0) continue;
|
|
698
|
+
let payload;
|
|
699
|
+
try {
|
|
700
|
+
payload = JSON.parse(line.slice(jsonStart));
|
|
701
|
+
} catch (_error) {
|
|
702
|
+
try {
|
|
703
|
+
payload = JSON.parse(line.slice(jsonStart, line.lastIndexOf("}") + 1));
|
|
704
|
+
} catch (_error2) {
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
const usage = payload?.qoderUsage;
|
|
709
|
+
if (!usage || typeof usage !== "object") continue;
|
|
710
|
+
let limits;
|
|
711
|
+
try {
|
|
712
|
+
limits = normalizeQoderRpcUsage({
|
|
713
|
+
userType: usage.userType,
|
|
714
|
+
expiresAt: usage.expiresAt,
|
|
715
|
+
isQuotaExceeded: usage.isQuotaExceeded,
|
|
716
|
+
totalUsagePercentage: usage.totalUsagePercentage,
|
|
717
|
+
userQuota: usage.userQuota,
|
|
718
|
+
addOnQuota: usage.addOnQuota,
|
|
719
|
+
});
|
|
720
|
+
} catch (_error) {
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
if (!limits) continue;
|
|
724
|
+
limits.source = "local-log";
|
|
725
|
+
const timestampMatch = /^\[([^\]]+)\]/.exec(line);
|
|
726
|
+
const lineObservedAtMs = timestampMatch ? Date.parse(timestampMatch[1]) : NaN;
|
|
727
|
+
return {
|
|
728
|
+
limits,
|
|
729
|
+
observedAtMs: Number.isFinite(lineObservedAtMs) ? lineObservedAtMs : fallbackObservedAtMs,
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
return null;
|
|
607
733
|
}
|
|
608
734
|
|
|
609
735
|
function parseQoderQuotaLog(text) {
|
|
@@ -640,44 +766,57 @@ function parseQoderQuotaLog(text) {
|
|
|
640
766
|
};
|
|
641
767
|
}
|
|
642
768
|
|
|
769
|
+
// Maps a log path to its "size:mtimeMs" signature from the last completed
|
|
770
|
+
// scan that found no usable summary (failed I/O is never recorded). Qoder
|
|
771
|
+
// only appends to these logs, so an unchanged signature cannot have gained
|
|
772
|
+
// one; pruning to the current candidate set keeps the map bounded.
|
|
773
|
+
const qoderNoSummaryScans = new Map();
|
|
774
|
+
|
|
643
775
|
function readQoderLocalQuota({
|
|
644
776
|
home = os.homedir(),
|
|
645
777
|
platform = process.platform,
|
|
646
778
|
env = process.env,
|
|
647
779
|
appDir = "Qoder",
|
|
648
780
|
envPrefix = "QODER",
|
|
781
|
+
nowMs = Date.now(),
|
|
782
|
+
maxAgeMs = QODER_LOG_MAX_AGE_MS,
|
|
649
783
|
} = {}) {
|
|
650
|
-
const
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
const stat = fs.fstatSync(fd);
|
|
672
|
-
const length = Math.min(stat.size, 512 * 1024);
|
|
673
|
-
const buffer = Buffer.alloc(length);
|
|
674
|
-
fs.readSync(fd, buffer, 0, length, Math.max(0, stat.size - length));
|
|
675
|
-
const parsed = parseQoderQuotaLog(buffer.toString("utf8"));
|
|
676
|
-
if (parsed) return parsed;
|
|
677
|
-
} finally {
|
|
678
|
-
fs.closeSync(fd);
|
|
784
|
+
const candidates = [];
|
|
785
|
+
for (const logRoot of qoderLogRoots({ home, platform, env, appDir, envPrefix })) {
|
|
786
|
+
for (const entry of listRecentQoderLogs(logRoot)) {
|
|
787
|
+
if (nowMs - entry.mtimeMs > maxAgeMs) continue;
|
|
788
|
+
candidates.push(entry);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
candidates.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
792
|
+
const scanned = candidates.slice(0, QODER_LOG_MAX_FILES);
|
|
793
|
+
const seenPaths = new Set();
|
|
794
|
+
for (const { full, mtimeMs, size } of scanned) {
|
|
795
|
+
seenPaths.add(full);
|
|
796
|
+
const signature = `${size}:${mtimeMs}`;
|
|
797
|
+
if (qoderNoSummaryScans.get(full) === signature) continue;
|
|
798
|
+
// A stale modern summary must not end the scan: fall through so a legacy
|
|
799
|
+
// match in the same chunk — or deeper — can still be used; only a fresh
|
|
800
|
+
// modern result returns early.
|
|
801
|
+
const parsed = scanQoderLogFromEnd(full, (text) => {
|
|
802
|
+
const accountUsage = parseQoderAccountUsageLog(text, { fallbackObservedAtMs: mtimeMs });
|
|
803
|
+
if (accountUsage && nowMs - (accountUsage.observedAtMs ?? mtimeMs) <= maxAgeMs) {
|
|
804
|
+
return accountUsage;
|
|
679
805
|
}
|
|
680
|
-
|
|
806
|
+
const legacy = parseQoderQuotaLog(text);
|
|
807
|
+
return legacy ? { limits: legacy, observedAtMs: mtimeMs } : null;
|
|
808
|
+
});
|
|
809
|
+
if (parsed === undefined) continue; // Scan failed (I/O); retry on the next call.
|
|
810
|
+
if (!parsed) {
|
|
811
|
+
qoderNoSummaryScans.set(full, signature);
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
const observedAtMs = parsed.observedAtMs ?? mtimeMs;
|
|
815
|
+
if (nowMs - observedAtMs > maxAgeMs) continue;
|
|
816
|
+
return parsed.limits;
|
|
817
|
+
}
|
|
818
|
+
for (const cachedPath of qoderNoSummaryScans.keys()) {
|
|
819
|
+
if (!seenPaths.has(cachedPath)) qoderNoSummaryScans.delete(cachedPath);
|
|
681
820
|
}
|
|
682
821
|
return null;
|
|
683
822
|
}
|
|
@@ -793,7 +932,7 @@ async function fetchQoderLimits({
|
|
|
793
932
|
// Preserve that status as metadata, but match Qoder's Credits UI by
|
|
794
933
|
// rendering an empty 0/0 bucket as 0%, not a full red 100% bar.
|
|
795
934
|
const local = result.primary_window?.limit_credits === 0
|
|
796
|
-
? readQoderLocalQuota({ home, platform, env, appDir, envPrefix })
|
|
935
|
+
? readQoderLocalQuota({ home, platform, env, appDir, envPrefix, nowMs })
|
|
797
936
|
: null;
|
|
798
937
|
if (local) {
|
|
799
938
|
result.quota_exceeded = local.quota_exceeded === true;
|
|
@@ -817,7 +956,7 @@ async function fetchQoderLimits({
|
|
|
817
956
|
}
|
|
818
957
|
}
|
|
819
958
|
|
|
820
|
-
const local = readQoderLocalQuota({ home, platform, env, appDir, envPrefix });
|
|
959
|
+
const local = readQoderLocalQuota({ home, platform, env, appDir, envPrefix, nowMs });
|
|
821
960
|
if (local) {
|
|
822
961
|
if (activityWindow) {
|
|
823
962
|
local.secondary_window = activityWindow;
|
|
@@ -874,6 +1013,7 @@ module.exports = {
|
|
|
874
1013
|
readQoderLimitsCache,
|
|
875
1014
|
writeQoderLimitsCache,
|
|
876
1015
|
parseQoderQuotaLog,
|
|
1016
|
+
parseQoderAccountUsageLog,
|
|
877
1017
|
readQoderLocalQuota,
|
|
878
1018
|
fetchQoderLimits,
|
|
879
1019
|
fetchQoderCnLimits,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o,V as H,j as r}from"./__vite-browser-external-DZF5L1pt.js";import{Z as R}from"./zap-Dg-ij-lq.js";import{F}from"./flame-CUGlDV__.js";import{C as I}from"./calendar-days-DTuIv3ts.js";import{S as G}from"./shield-check-D8kUejpE.js";const u={name:"blocks",size:24,node:[["path",{d:"M10 22V7a1 1 0 0 0-1-1H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-5a1 1 0 0 0-1-1H2",key:"1ah6g2"}],["rect",{x:"14",y:"2",width:"8",height:"8",rx:"1",key:"88lufb"}]]};u.node;const N=o(u);const k={name:"brain",size:24,node:[["path",{d:"M12 18V5",key:"adv99a"}],["path",{d:"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4",key:"1e3is1"}],["path",{d:"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5",key:"1gqd8o"}],["path",{d:"M17.997 5.125a4 4 0 0 1 2.526 5.77",key:"iwvgf7"}],["path",{d:"M18 18a4 4 0 0 0 2-7.464",key:"efp6ie"}],["path",{d:"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517",key:"1gq6am"}],["path",{d:"M6 18a4 4 0 0 1-2-7.464",key:"k1g0md"}],["path",{d:"M6.003 5.125a4 4 0 0 0-2.526 5.77",key:"q97ue3"}]]};k.node;const S=o(k);const v={name:"crown",size:24,node:[["path",{d:"M11.562 3.266a.5.5 0 0 1 .876 0L15.39 8.87a1 1 0 0 0 1.516.294L21.183 5.5a.5.5 0 0 1 .798.519l-2.834 10.246a1 1 0 0 1-.956.734H5.81a1 1 0 0 1-.957-.734L2.02 6.02a.5.5 0 0 1 .798-.519l4.276 3.664a1 1 0 0 0 1.516-.294z",key:"1vdc57"}],["path",{d:"M5 21h14",key:"11awu3"}]]};v.node;const V=o(v);const b={name:"feather",size:24,node:[["path",{d:"M14.086 18.412A2 2 0 0112.67 19H5v-7.672a2 2 0 01.586-1.414L11.75 3.75a6 6 0 118.49 8.49z",key:"1nq9jb"}],["path",{d:"M16 8 2 22",key:"vp34q"}],["path",{d:"M17.488 15H9",key:"16yirz"}]]};b.node;const Z=o(b);const M={name:"folder-git-2",size:24,node:[["path",{d:"M18 19a5 5 0 0 1-5-5v8",key:"sz5oeg"}],["path",{d:"M9 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v5",key:"1w6njk"}],["circle",{cx:"13",cy:"12",r:"2",key:"1j92g6"}],["circle",{cx:"20",cy:"19",r:"2",key:"1obnsp"}]]};M.node;const O=o(M);const _={name:"footprints",size:24,node:[["path",{d:"M4 16v-2.38C4 11.5 2.97 10.5 3 8c.03-2.72 1.49-6 4.5-6C9.37 2 10 3.8 10 5.5c0 3.11-2 5.66-2 8.68V16a2 2 0 1 1-4 0Z",key:"1dudjm"}],["path",{d:"M20 20v-2.38c0-2.12 1.03-3.12 1-5.62-.03-2.72-1.49-6-4.5-6C14.63 6 14 7.8 14 9.5c0 3.11 2 5.66 2 8.68V20a2 2 0 1 0 4 0Z",key:"l2t8xc"}],["path",{d:"M16 17h4",key:"1dejxt"}],["path",{d:"M4 13h4",key:"1bwh8b"}]]};_.node;const P=o(_);const x={name:"heart",size:24,node:[["path",{d:"M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5",key:"mvr1a0"}]]};x.node;const X=o(x);const w={name:"medal",size:24,node:[["path",{d:"M7.21 15 2.66 7.14a2 2 0 0 1 .13-2.2L4.4 2.8A2 2 0 0 1 6 2h12a2 2 0 0 1 1.6.8l1.6 2.14a2 2 0 0 1 .14 2.2L16.79 15",key:"143lza"}],["path",{d:"M11 12 5.12 2.2",key:"qhuxz6"}],["path",{d:"m13 12 5.88-9.8",key:"hbye0f"}],["path",{d:"M8 7h8",key:"i86dvs"}],["circle",{cx:"12",cy:"17",r:"5",key:"qbz8iq"}],["path",{d:"M12 18v-2h-.5",key:"fawc4q"}]]};w.node;const K=o(w);const z={name:"moon-star",size:24,node:[["path",{d:"M18 5h4",key:"1lhgn2"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",key:"kfwtm"}]]};z.node;const U=o(z);const A={name:"rocket",size:24,node:[["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}],["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09",key:"u4xsad"}],["path",{d:"M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z",key:"676m9"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05",key:"92ym6u"}]]};A.node;const W=o(A);const D={name:"trending-up",size:24,node:[["path",{d:"M16 7h6v6",key:"box55l"}],["path",{d:"m22 7-8.5 8.5-5-5L2 17",key:"1t1m79"}]]};D.node;const Y=o(D),$=[{id:"token_titan",scope:"cloud",icon:V,format:"tokens",art:"/achievements/token-titan.png"},{id:"big_day",scope:"cloud",icon:R,format:"tokens",art:"/achievements/big-day.png"},{id:"wordsmith",scope:"cloud",icon:Z,format:"tokens",art:"/achievements/wordsmith.png"},{id:"marathoner",scope:"cloud",icon:P,format:"days",art:"/achievements/marathoner.png"},{id:"streak",scope:"cloud",icon:F,format:"days",art:"/achievements/streak.png"},{id:"weekend_warrior",scope:"cloud",icon:I,format:"days",art:"/achievements/weekend-warrior.png"},{id:"momentum",scope:"cloud",icon:Y,format:"multiplier",art:"/achievements/momentum.png"},{id:"polyglot",scope:"cloud",icon:S,format:"count",art:"/achievements/polyglot.png"},{id:"trendsetter",scope:"cloud",icon:W,format:"count",art:"/achievements/trendsetter.png"},{id:"multitool",scope:"cloud",icon:N,format:"count",art:"/achievements/multitool.png"},{id:"podium",scope:"cloud",icon:K,format:"rank",art:"/achievements/podium.png"},{id:"veteran",scope:"cloud",icon:G,format:"days",art:"/achievements/veteran.png"},{id:"project_hopper",scope:"local",icon:O,format:"count",art:"/achievements/project-hopper.png"},{id:"project_devotion",scope:"local",icon:X,format:"tokens",art:"/achievements/project-devotion.png"},{id:"night_owl",scope:"local",icon:U,format:"count",art:"/achievements/night-owl.png"}],j=new Map($.map(e=>[e.id,e])),m=new Map($.map((e,a)=>[e.id,a]));function de(e,a){return`achievements.badge.${e}.${a}`}function J(e){return[...e||[]].sort((a,t)=>{const c=(t?.tier||0)-(a?.tier||0);return c!==0?c:(m.get(a?.id)??99)-(m.get(t?.id)??99)})}function re(e){const a=(e||[]).filter(t=>t&&(t.tier||0)>=1&&j.has(t.id));return a.length===0?null:J(a)[0]}const E={1:"bronze",2:"silver",3:"gold",4:"diamond"},ie=["bronze","silver","gold","diamond"],Q={bronze:{rim:["#a06a44","#5c3a22"],face:["#d29a6c","#96602f"],glyph:"#3f2817",ring:"#e8c3a0",sheen:"rgba(255, 236, 220, 0.45)",label:"#a06a44"},silver:{rim:["#aab3bb","#67707b"],face:["#dde2e7","#9ba5ae"],glyph:"#39424b",ring:"#f2f5f7",sheen:"rgba(255, 255, 255, 0.55)",label:"#8b959f"},gold:{rim:["#c9971c","#8a6508"],face:["#f2ca52","#cf9c26"],glyph:"#5c430e",ring:"#ffe9a8",sheen:"rgba(255, 248, 214, 0.55)",label:"#b8860b"},diamond:{rim:["#62b1e0","#7c6fd9"],face:["#c8ecf6","#84b4ea"],glyph:"#27496d",ring:"#eafcff",sheen:"rgba(255, 255, 255, 0.65)",label:"#5a9bd8"}},g={rim:["#a8ada9","#7c817d"],face:["#cdd2ce","#a3a8a4"],glyph:"#6a706c",ring:"#dde1de",sheen:"rgba(255, 255, 255, 0.25)",label:"#8b908c"};function ee(e,a=!1){return a||!e||e<1?g:Q[E[Math.min(e,4)]]||g}function se(e){return E[e]||null}const f={xs:18,sm:24,md:44,xl:88,lg:108},y={xs:.75,sm:1,md:1.5,xl:2,lg:2};function le({badgeId:e,tier:a=0,size:t="md",locked:c=!1,label:i,className:L=""}){const s=j.get(e),p=c||!a||a<1,n=ee(a,p),d=t==="fill",l=d?"100%":f[t]||f.md,T=d?4:y[t]||y.md,[C,q]=H.useState(!1),h=s?.icon||null,B=!!s?.art&&!C;return r.jsx("span",{role:i?"img":void 0,"aria-label":i||void 0,"aria-hidden":i?void 0:!0,className:`inline-flex shrink-0 rounded-full ${L}`,style:{width:l,height:l,padding:T,background:`linear-gradient(135deg, ${n.rim[0]} 0%, ${n.ring} 42%, ${n.rim[1]} 100%)`,boxShadow:d||t==="md"||t==="xl"||t==="lg"?"0 0 0 1px rgba(10, 15, 12, 0.06), 0 1px 2px rgba(10, 15, 12, 0.08)":void 0},children:B?r.jsx("img",{src:s.art,alt:"",draggable:!1,loading:"lazy",onError:()=>q(!0),className:"h-full w-full rounded-full object-cover",style:p?{filter:"grayscale(1)",opacity:.55}:void 0}):r.jsx("span",{className:"flex h-full w-full items-center justify-center rounded-full",style:{background:`linear-gradient(145deg, ${n.face[0]}, ${n.face[1]})`},children:h?r.jsx(h,{size:d?64:Math.round(l*.5),color:n.glyph,strokeWidth:2}):null})})}export{le as A,$ as B,X as H,Y as T,Q as a,de as b,j as c,ie as d,re as h,ee as p,J as s,se as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as n,J as a}from"./__vite-browser-external-DZF5L1pt.js";import{u as p}from"./DialogTitle-CBhd4oLc.js";import{u as c}from"./composite-M_CP_KSx.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};
|