@ipv9/tokentracker-cli 0.39.38 → 0.39.39

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.
Files changed (79) hide show
  1. package/README.md +41 -9
  2. package/dashboard/dist/assets/{Card-DD4s0V6T.js → Card-BbRYRVXf.js} +1 -1
  3. package/dashboard/dist/assets/DashboardPage-DYKHv0m3.js +60 -0
  4. package/dashboard/dist/assets/{FadeIn-CUSBK0jm.js → FadeIn-CjAacJ5t.js} +1 -1
  5. package/dashboard/dist/assets/{IpCheckPage-PHF4lPax.js → IpCheckPage-BGALK8Vy.js} +1 -1
  6. package/dashboard/dist/assets/{LimitsPage-dS9C9Vdt.js → LimitsPage-LkZGPYvg.js} +2 -2
  7. package/dashboard/dist/assets/{LocalOnlyNotice-DCmtS_j5.js → LocalOnlyNotice-Dxo2vFMQ.js} +1 -1
  8. package/dashboard/dist/assets/PopoverPopup-DP9fwdtl.js +1 -0
  9. package/dashboard/dist/assets/Select-DPE53NmM.js +1 -0
  10. package/dashboard/dist/assets/SelectItemText-D69v77is.js +12 -0
  11. package/dashboard/dist/assets/SettingsPage-Dxzqpi02.js +1 -0
  12. package/dashboard/dist/assets/SkillsPage-Bo7e39AB.js +1 -0
  13. package/dashboard/dist/assets/WidgetsPage-HHcIr_Eq.js +1 -0
  14. package/dashboard/dist/assets/WrappedPage-C-_jLXXU.js +1 -0
  15. package/dashboard/dist/assets/{arrow-up-right-CjaBQnwI.js → arrow-up-right-BJvJHUGj.js} +1 -1
  16. package/dashboard/dist/assets/{download-DLBqkSwp.js → download-CnzY_EgN.js} +1 -1
  17. package/dashboard/dist/assets/format-1w-q5n2f.js +1 -0
  18. package/dashboard/dist/assets/main-1kxAVM3m.css +1 -0
  19. package/dashboard/dist/assets/main-3gBEI6Jl.js +694 -0
  20. package/dashboard/dist/assets/mock-data-CJOMGcL9.js +1 -0
  21. package/dashboard/dist/assets/use-limits-display-prefs-D1nT9-mr.js +1 -0
  22. package/dashboard/dist/assets/use-native-settings-Dh6NzqjY.js +1 -0
  23. package/dashboard/dist/assets/use-usage-limits-BXR6lzGf.js +1 -0
  24. package/dashboard/dist/assets/useCurrency-Hhs5jbWw.js +1 -0
  25. package/dashboard/dist/index.html +15 -27
  26. package/dashboard/dist/llms.txt +0 -2
  27. package/dashboard/dist/sitemap.xml +0 -12
  28. package/package.json +7 -4
  29. package/src/cli.js +4 -13
  30. package/src/commands/doctor.js +1 -3
  31. package/src/commands/init.js +63 -53
  32. package/src/commands/serve.js +2 -50
  33. package/src/commands/status.js +1 -55
  34. package/src/commands/sync.js +134 -227
  35. package/src/lib/{browser-auth.js → browser-open.js} +3 -149
  36. package/src/lib/claude-categorizer.js +204 -32
  37. package/src/lib/codex-context-breakdown.js +83 -7
  38. package/src/lib/codex-rollout-parser.js +52 -10
  39. package/src/lib/diagnostics.js +1 -49
  40. package/src/lib/doctor.js +12 -87
  41. package/src/lib/file-identity.js +69 -0
  42. package/src/lib/init-flow.js +6 -3
  43. package/src/lib/local-api.js +6 -364
  44. package/src/lib/pricing/curated-overrides.json +1 -1
  45. package/src/lib/pricing/seed-snapshot.json +1 -1
  46. package/src/lib/rollout.js +392 -144
  47. package/src/lib/runtime-config.js +0 -32
  48. package/src/lib/sqlite-reader.js +83 -8
  49. package/dashboard/dist/assets/ActivityHeatmap-BrehqUIb.js +0 -42
  50. package/dashboard/dist/assets/DashboardPage-CyUShBRJ.js +0 -19
  51. package/dashboard/dist/assets/DevicePage-BA74Su1l.js +0 -1
  52. package/dashboard/dist/assets/DialogTitle-DoKsz5wi.js +0 -1
  53. package/dashboard/dist/assets/InsforgeUserHeaderControls-Bk_U2dHr.js +0 -1
  54. package/dashboard/dist/assets/LandingPage-Bbeu84Iu.js +0 -4356
  55. package/dashboard/dist/assets/LeaderboardAvatar-ByqeB6bM.js +0 -1
  56. package/dashboard/dist/assets/LeaderboardPage-BeWXF00S.js +0 -6
  57. package/dashboard/dist/assets/LeaderboardProfileModal-C4yvbZd_.js +0 -72
  58. package/dashboard/dist/assets/LeaderboardProfilePage-D3cbSh5o.js +0 -1
  59. package/dashboard/dist/assets/LoginPage-Ch3UQoWj.js +0 -1
  60. package/dashboard/dist/assets/PopoverPopup-DjG0gjlA.js +0 -1
  61. package/dashboard/dist/assets/Select-HzIjWJpE.js +0 -1
  62. package/dashboard/dist/assets/SelectItemText-f0tCwtvZ.js +0 -1
  63. package/dashboard/dist/assets/SettingsPage-DJOZAlZy.js +0 -1
  64. package/dashboard/dist/assets/SkillsPage-BQcyJIdx.js +0 -1
  65. package/dashboard/dist/assets/WidgetsPage-B_vxuV09.js +0 -1
  66. package/dashboard/dist/assets/WrappedPage-CZN9Y3Vz.js +0 -1
  67. package/dashboard/dist/assets/index-BeoRn2gJ.js +0 -2
  68. package/dashboard/dist/assets/info-BAIxlHIB.js +0 -1
  69. package/dashboard/dist/assets/main-DAcSUW2t.css +0 -1
  70. package/dashboard/dist/assets/main-pi07CfeC.js +0 -1004
  71. package/dashboard/dist/assets/use-limits-display-prefs-CMfASZsh.js +0 -1
  72. package/dashboard/dist/assets/use-native-settings-CfPik-Ao.js +0 -1
  73. package/dashboard/dist/assets/use-spring-wsmJQRqb.js +0 -1
  74. package/dashboard/dist/assets/use-usage-limits-Bt0Dp6kx.js +0 -1
  75. package/dashboard/dist/assets/useCurrency-CsaAMc3j.js +0 -1
  76. package/dashboard/dist/assets/useOpenInteractionType-CPzi5Z8M.js +0 -12
  77. package/dashboard/dist/share.html +0 -140
  78. package/src/commands/device-login.js +0 -161
  79. package/src/lib/upload-throttle.js +0 -148
@@ -3,7 +3,6 @@ const os = require("node:os");
3
3
  const path = require("node:path");
4
4
  const { spawn } = require("node:child_process");
5
5
  const crypto = require("node:crypto");
6
- const { DEFAULT_BASE_URL, resolveRuntimeConfig } = require("./runtime-config");
7
6
  const {
8
7
  filterRowsByUsageScope,
9
8
  getSourceScope,
@@ -445,35 +444,7 @@ function trimOutput(value, max = 4000) {
445
444
  return t.length <= max ? t : t.slice(t.length - max);
446
445
  }
447
446
 
448
- function normalizeRemoteHttpBaseUrl(value) {
449
- if (typeof value !== "string") return null;
450
- const trimmed = value.trim();
451
- if (!trimmed) return null;
452
- try {
453
- const url = new URL(trimmed);
454
- if (url.protocol !== "http:" && url.protocol !== "https:") return null;
455
- url.username = "";
456
- url.password = "";
457
- url.hash = "";
458
- return url.toString().replace(/\/$/, "");
459
- } catch (_e) {
460
- return null;
461
- }
462
- }
463
447
 
464
- function resolveAllowedInsforgeBaseUrl(value) {
465
- const requested = normalizeRemoteHttpBaseUrl(value);
466
- if (!requested) return null;
467
-
468
- const runtime = resolveRuntimeConfig();
469
- const allowed = new Set(
470
- [runtime.baseUrl, DEFAULT_BASE_URL]
471
- .map((entry) => normalizeRemoteHttpBaseUrl(entry))
472
- .filter(Boolean),
473
- );
474
-
475
- return allowed.has(requested) ? requested : null;
476
- }
477
448
 
478
449
  function parseCookieHeader(value) {
479
450
  const out = new Map();
@@ -709,45 +680,6 @@ const HOP_BY_HOP_HEADERS = new Set([
709
680
  "trailers",
710
681
  ]);
711
682
 
712
- // Strip forbidden + hop-by-hop headers when forwarding an inbound request to
713
- // fetch(). Honours the Connection header's named-headers list (RFC 7230 §6.1)
714
- // so values like `Connection: keep-alive, x-custom` also drop x-custom.
715
- function buildProxyHeaders(headers) {
716
- const entries =
717
- headers && typeof headers.entries === "function"
718
- ? Array.from(headers.entries())
719
- : Object.entries(headers || {});
720
-
721
- const connectionNamed = new Set();
722
- const normalized = [];
723
- for (const [rawKey, rawValue] of entries) {
724
- if (rawValue == null) continue;
725
- const key = String(rawKey).toLowerCase();
726
- normalized.push([key, rawValue]);
727
- if (key === "connection") {
728
- const values = Array.isArray(rawValue) ? rawValue : [rawValue];
729
- for (const v of values) {
730
- String(v)
731
- .split(",")
732
- .map((part) => part.trim().toLowerCase())
733
- .filter(Boolean)
734
- .forEach((part) => connectionNamed.add(part));
735
- }
736
- }
737
- }
738
-
739
- const out = {};
740
- for (const [key, rawValue] of normalized) {
741
- if (HOP_BY_HOP_HEADERS.has(key) || connectionNamed.has(key)) continue;
742
- if (Array.isArray(rawValue)) {
743
- const joined = rawValue.filter((e) => e != null).map(String).join(", ");
744
- if (joined) out[key] = joined;
745
- continue;
746
- }
747
- out[key] = String(rawValue);
748
- }
749
- return out;
750
- }
751
683
 
752
684
  // ---------------------------------------------------------------------------
753
685
  // Main handler factory
@@ -756,169 +688,7 @@ function buildProxyHeaders(headers) {
756
688
  function createLocalApiHandler({ queuePath }) {
757
689
  const qp = queuePath || resolveQueuePath();
758
690
 
759
- // Server-side cookie relay: captures auth cookies from InsForge cloud responses
760
- // so that both browser and WKWebView share the same login session via the proxy.
761
- // Persisted to disk so cookies survive server restarts.
762
- const csrfRelayCookieName = "insforge_csrf_token";
763
- let relayCookies = new Map();
764
691
  const localAuthToken = crypto.randomBytes(24).toString("hex");
765
- const trackerDataDir = path.join(os.homedir(), ".tokentracker", "tracker");
766
- const cookiePath = path.join(trackerDataDir, "relay-cookies.json");
767
-
768
- // Load persisted cookies on startup
769
- try {
770
- if (!fs.existsSync(trackerDataDir)) fs.mkdirSync(trackerDataDir, { recursive: true });
771
- if (fs.existsSync(cookiePath)) {
772
- const content = fs.readFileSync(cookiePath, "utf8");
773
- const saved = JSON.parse(content);
774
- if (saved && typeof saved === "object") {
775
- let count = 0;
776
- for (const [k, v] of Object.entries(saved)) {
777
- relayCookies.set(k, v);
778
- count++;
779
- }
780
- if (count > 0) console.log(`[LocalAPI] Loaded ${count} relay cookies from ${cookiePath}`);
781
- }
782
- }
783
- } catch (e) {
784
- console.error("[LocalAPI] Failed to load relay cookies:", e.message);
785
- }
786
-
787
- function persistRelayCookies() {
788
- try {
789
- // Sticky semantics: never replace an existing on-disk session with an empty cookie map.
790
- if (relayCookies.size === 0) return;
791
-
792
- const json = JSON.stringify(Object.fromEntries(relayCookies));
793
- fs.writeFileSync(cookiePath, json, { encoding: "utf8", mode: 0o600 });
794
- } catch (e) {
795
- console.error("[LocalAPI] Failed to persist relay cookies:", e.message);
796
- }
797
- }
798
-
799
- function clearRelayCookies(reason) {
800
- if (relayCookies.size === 0) return;
801
- relayCookies.clear();
802
- try {
803
- if (fs.existsSync(cookiePath)) fs.unlinkSync(cookiePath);
804
- } catch (e) {
805
- console.error("[LocalAPI] Failed to clear relay cookies:", e.message);
806
- return;
807
- }
808
- if (reason) console.warn(`[LocalAPI] Cleared relay cookies: ${reason}`);
809
- }
810
-
811
- function captureSetCookies(headerValue) {
812
- if (!headerValue) return;
813
- const parts = headerValue.split(/,(?=\s*\w+=)/);
814
- let changed = false;
815
- for (const raw of parts) {
816
- const eqIdx = raw.indexOf("=");
817
- if (eqIdx < 1) continue;
818
- const name = raw.substring(0, eqIdx).trim();
819
- if (!name) continue;
820
-
821
- // Basic sticky logic: if it's a deletion cookie (Max-Age=0 or past date),
822
- // we only remove it if we have it.
823
- const lower = raw.toLowerCase();
824
- const isDeletion = lower.includes("max-age=0") || lower.includes("expires=thu, 01 jan 1970");
825
-
826
- if (isDeletion) {
827
- if (relayCookies.has(name)) {
828
- relayCookies.delete(name);
829
- changed = true;
830
- console.log(`[LocalAPI] Cookie deleted: ${name}`);
831
- }
832
- } else {
833
- const oldVal = relayCookies.get(name);
834
- if (oldVal !== raw.trim()) {
835
- relayCookies.set(name, raw.trim());
836
- changed = true;
837
- console.log(`[LocalAPI] Cookie captured: ${name}`);
838
- }
839
- }
840
- }
841
- if (changed) persistRelayCookies();
842
- }
843
-
844
- function getRelayCookieValue(name, { decode = false } = {}) {
845
- const raw = relayCookies.get(name);
846
- if (!raw || typeof raw !== "string") return "";
847
- const pair = raw.split(";")[0] || "";
848
- const eqIdx = pair.indexOf("=");
849
- if (eqIdx < 1) return "";
850
- const value = pair.substring(eqIdx + 1).trim();
851
- if (!decode) return value;
852
- try {
853
- return decodeURIComponent(value);
854
- } catch {
855
- return value;
856
- }
857
- }
858
-
859
- function captureAuthTokensFromBody(bodyBuffer, contentType) {
860
- if (!bodyBuffer || !String(contentType || "").toLowerCase().includes("application/json")) return;
861
- let parsed = null;
862
- try {
863
- parsed = JSON.parse(bodyBuffer.toString("utf8"));
864
- } catch {
865
- return;
866
- }
867
- let changed = false;
868
- const token = typeof parsed?.csrfToken === "string" ? parsed.csrfToken.trim() : "";
869
- if (token) {
870
- const cookie = `${csrfRelayCookieName}=${encodeURIComponent(token)}; Path=/; SameSite=Lax`;
871
- if (relayCookies.get(csrfRelayCookieName) !== cookie) {
872
- relayCookies.set(csrfRelayCookieName, cookie);
873
- changed = true;
874
- }
875
- }
876
- const refreshToken = typeof parsed?.refreshToken === "string" ? parsed.refreshToken.trim() : "";
877
- if (refreshToken) {
878
- const cookie = `insforge_refresh_token=${encodeURIComponent(refreshToken)}; Path=/; HttpOnly; SameSite=Lax`;
879
- if (relayCookies.get("insforge_refresh_token") !== cookie) {
880
- relayCookies.set("insforge_refresh_token", cookie);
881
- changed = true;
882
- }
883
- }
884
- if (changed) persistRelayCookies();
885
- }
886
-
887
- function normalizeCookieHeader(value) {
888
- if (Array.isArray(value)) return value.filter(Boolean).join("; ");
889
- return typeof value === "string" ? value : "";
890
- }
891
-
892
- function buildRelayCookieHeader(clientCookieHeader, { relayPrecedenceNames = [] } = {}) {
893
- const normalizedClientCookieHeader = normalizeCookieHeader(clientCookieHeader);
894
- if (relayCookies.size === 0) return normalizedClientCookieHeader;
895
- const relayPrecedence = new Set(relayPrecedenceNames);
896
- const clientPairs = new Map();
897
- if (normalizedClientCookieHeader) {
898
- for (const part of normalizedClientCookieHeader.split(";")) {
899
- const eqIdx = part.indexOf("=");
900
- if (eqIdx < 1) continue;
901
- const n = part.substring(0, eqIdx).trim();
902
- if (n) clientPairs.set(n, part.trim());
903
- }
904
- }
905
- // Merge relay cookies. Normal requests keep client precedence; refresh
906
- // recovery can opt relay cookies into precedence over stale WebView cookies.
907
- for (const [name, raw] of relayCookies) {
908
- if (clientPairs.has(name) && !relayPrecedence.has(name)) continue;
909
- const scIdx = raw.indexOf(";");
910
- const pair = scIdx > 0 ? raw.substring(0, scIdx).trim() : raw;
911
- clientPairs.set(name, pair);
912
- }
913
- return [...clientPairs.values()].join("; ");
914
- }
915
-
916
- // Ephemeral auth bridge: WebView sets a "native" flag before opening system browser
917
- // for OAuth. The callback page (in browser) checks this flag to decide whether to
918
- // relay the code back to the app or handle it as a normal web flow.
919
- let _nativeAuthPending = false;
920
- let _nativeAuthExpiry = 0;
921
-
922
692
  function isAuthorizedLocalMutation(req) {
923
693
  const headerToken = req?.headers?.["x-tokentracker-local-auth"];
924
694
  const cookieToken = parseCookieHeader(req?.headers?.cookie).get("tokentracker_local_auth");
@@ -945,124 +715,6 @@ function createLocalApiHandler({ queuePath }) {
945
715
  return true;
946
716
  }
947
717
 
948
- // --- Auth bridge: native OAuth flag (WebView ↔ system browser) ---
949
- if (p === "/api/auth-bridge/verifier") {
950
- const method = String(req.method || "GET").toUpperCase();
951
- if (method === "PUT" || method === "POST") {
952
- if (!isAuthorizedLocalMutation(req)) {
953
- json(res, { error: "Unauthorized" }, 401);
954
- return true;
955
- }
956
- const body = await readJsonBody(req);
957
- _nativeAuthPending = Boolean(body?.native);
958
- _nativeAuthExpiry = Date.now() + 5 * 60 * 1000; // 5 min TTL
959
- json(res, { ok: true });
960
- return true;
961
- }
962
- if (method === "GET") {
963
- const isNative = _nativeAuthPending && Date.now() < _nativeAuthExpiry;
964
- _nativeAuthPending = false; // one-time read
965
- _nativeAuthExpiry = 0;
966
- json(res, { native: isNative });
967
- return true;
968
- }
969
- json(res, { error: "Method Not Allowed" }, 405);
970
- return true;
971
- }
972
-
973
- // --- auth proxy: forward /api/auth/* to InsForge cloud ---
974
- if (p.startsWith("/api/auth/")) {
975
- const runtime = resolveRuntimeConfig();
976
- const insforgeBase = runtime.baseUrl || DEFAULT_BASE_URL;
977
- try {
978
- const targetUrl = `${insforgeBase.replace(/\/$/, "")}${p}${url.search || ""}`;
979
- const proxyHeaders = buildProxyHeaders(req.headers);
980
- const hasClientCookie = normalizeCookieHeader(proxyHeaders["cookie"]).trim().length > 0;
981
- const hasCsrfHeader = typeof proxyHeaders["x-csrf-token"] === "string" && proxyHeaders["x-csrf-token"].trim().length > 0;
982
- const relayCsrfToken = getRelayCookieValue(csrfRelayCookieName);
983
- if (p === "/api/auth/refresh" && relayCsrfToken) {
984
- proxyHeaders["x-csrf-token"] = relayCsrfToken;
985
- }
986
- const hasEffectiveCsrfHeader =
987
- hasCsrfHeader ||
988
- (typeof proxyHeaders["x-csrf-token"] === "string" && proxyHeaders["x-csrf-token"].trim().length > 0);
989
- let shouldInjectRelayCookies =
990
- p !== "/api/auth/refresh" || hasClientCookie || hasEffectiveCsrfHeader;
991
- const relayRefreshToken = getRelayCookieValue("insforge_refresh_token", { decode: true });
992
- const shouldUseRelayRefreshFallback =
993
- p === "/api/auth/refresh" && !hasClientCookie && !hasEffectiveCsrfHeader && relayRefreshToken;
994
- if (shouldUseRelayRefreshFallback) {
995
- shouldInjectRelayCookies = false;
996
- }
997
-
998
- // Inject relay cookies so WebView benefits from browser's login session.
999
- // Refresh requests need either a browser cookie or an explicit CSRF token;
1000
- // otherwise replaying a stale persisted refresh cookie just manufactures
1001
- // Invalid CSRF errors on startup.
1002
- const originalCookieHeader = normalizeCookieHeader(proxyHeaders["cookie"]);
1003
- const mergedCookie = shouldInjectRelayCookies
1004
- ? buildRelayCookieHeader(originalCookieHeader, {
1005
- relayPrecedenceNames: p === "/api/auth/refresh"
1006
- ? [csrfRelayCookieName, "insforge_refresh_token"]
1007
- : [],
1008
- })
1009
- : originalCookieHeader;
1010
- const injectedRelayCookies =
1011
- shouldInjectRelayCookies && relayCookies.size > 0 && mergedCookie !== originalCookieHeader;
1012
- if (mergedCookie) proxyHeaders["cookie"] = mergedCookie;
1013
-
1014
- const bodyChunks = [];
1015
- for await (const chunk of req) bodyChunks.push(chunk);
1016
- let proxyBody = bodyChunks.length > 0 ? Buffer.concat(bodyChunks) : undefined;
1017
- let effectiveTargetUrl = targetUrl;
1018
- if (shouldUseRelayRefreshFallback) {
1019
- effectiveTargetUrl = `${insforgeBase.replace(/\/$/, "")}/api/auth/refresh?client_type=mobile`;
1020
- proxyHeaders["content-type"] = "application/json";
1021
- delete proxyHeaders["content-length"];
1022
- proxyBody = Buffer.from(JSON.stringify({ refresh_token: relayRefreshToken }), "utf8");
1023
- }
1024
- const proxyRes = await fetch(effectiveTargetUrl, {
1025
- method: req.method || "GET",
1026
- headers: proxyHeaders,
1027
- body: proxyBody,
1028
- credentials: "include",
1029
- redirect: "manual",
1030
- });
1031
- const responseHeaders = [...proxyRes.headers.entries()]
1032
- .filter(([k]) => !["transfer-encoding", "connection"].includes(k.toLowerCase()))
1033
- .map(([k, v]) => {
1034
- if (k.toLowerCase() === "set-cookie") {
1035
- const rewritten = v.replace(/;\s*[Dd]omain=[^;]*/g, "; Domain=localhost");
1036
- captureSetCookies(rewritten);
1037
- return [k, rewritten];
1038
- }
1039
- return [k, v];
1040
- });
1041
- res.writeHead(proxyRes.status, Object.fromEntries(responseHeaders));
1042
- const resBody = Buffer.from(await proxyRes.arrayBuffer());
1043
- if (proxyRes.status >= 200 && proxyRes.status < 300) {
1044
- if (p === "/api/auth/logout") {
1045
- clearRelayCookies("sign out");
1046
- } else {
1047
- captureAuthTokensFromBody(resBody, proxyRes.headers.get("content-type"));
1048
- }
1049
- }
1050
- if (
1051
- p === "/api/auth/refresh"
1052
- && proxyRes.status === 403
1053
- && injectedRelayCookies
1054
- && !hasClientCookie
1055
- && /invalid csrf token/i.test(resBody.toString("utf8"))
1056
- ) {
1057
- clearRelayCookies("stale refresh cookie without local CSRF context");
1058
- }
1059
- res.end(resBody);
1060
- } catch (e) {
1061
- json(res, { error: `Auth proxy error: ${e?.message || e}` }, 502);
1062
- }
1063
- return true;
1064
- }
1065
-
1066
718
  // --- ip-check proxy: reverse-proxy ip.net.coffee (issue #81) ---
1067
719
  // Lock-down: GET/HEAD only, restricted path prefixes, do not forward
1068
720
  // browser credentials or fingerprintable headers. Without these limits
@@ -1101,7 +753,7 @@ function createLocalApiHandler({ queuePath }) {
1101
753
  accept: req.headers["accept"] || "*/*",
1102
754
  "accept-language": req.headers["accept-language"] || "en",
1103
755
  "accept-encoding": req.headers["accept-encoding"] || "gzip",
1104
- "user-agent": "TokenTracker/IPCheck (https://www.tokentracker.cc)",
756
+ "user-agent": "TokenTracker/IPCheck",
1105
757
  referer: `${IP_CHECK_TARGET}${targetPath}`,
1106
758
  };
1107
759
 
@@ -1207,7 +859,7 @@ function createLocalApiHandler({ queuePath }) {
1207
859
  headers: {
1208
860
  accept: req.headers["accept"] || "image/*",
1209
861
  "accept-language": req.headers["accept-language"] || "en",
1210
- "user-agent": "TokenTracker/AvatarProxy (https://www.tokentracker.cc)",
862
+ "user-agent": "TokenTracker/AvatarProxy",
1211
863
  },
1212
864
  });
1213
865
  if (!upstream.ok) {
@@ -1257,19 +909,10 @@ function createLocalApiHandler({ queuePath }) {
1257
909
  } catch {
1258
910
  body = {};
1259
911
  }
1260
- const extraEnv = {};
1261
- if (typeof body.deviceToken === "string" && body.deviceToken.trim()) {
1262
- extraEnv.TOKENTRACKER_DEVICE_TOKEN = body.deviceToken.trim();
1263
- }
1264
- if (body.insforgeBaseUrl != null) {
1265
- const allowedBaseUrl = resolveAllowedInsforgeBaseUrl(body.insforgeBaseUrl);
1266
- if (!allowedBaseUrl) {
1267
- json(res, { ok: false, error: "Unsupported insforgeBaseUrl override" }, 400);
1268
- return true;
1269
- }
1270
- extraEnv.TOKENTRACKER_INSFORGE_BASE_URL = allowedBaseUrl;
1271
- }
1272
- const result = await runSyncCommand(extraEnv);
912
+ // Local-only: the sync command takes no cloud credentials or endpoint
913
+ // overrides any more, so the request body carries nothing to forward.
914
+ void body;
915
+ const result = await runSyncCommand({});
1273
916
  try {
1274
917
  const { resetUsageLimitsCache } = require("./usage-limits");
1275
918
  resetUsageLimitsCache();
@@ -1876,7 +1519,6 @@ function createLocalApiHandler({ queuePath }) {
1876
1519
 
1877
1520
  module.exports = {
1878
1521
  createLocalApiHandler,
1879
- resolveAllowedInsforgeBaseUrl,
1880
1522
  resolveQueuePath,
1881
1523
  // Exported for cross-consumer tests (pricing + native contract lock).
1882
1524
  MODEL_PRICING,
@@ -3,7 +3,7 @@
3
3
  "note": "Curated price overrides. Always wins over LiteLLM. Two reasons to live here: (1) self-defined alias names that LiteLLM will never carry (kiro-*, hy3-*, composer-*, kimi-for-coding, free-tier OpenRouter routes); (2) prices we want to pin even if LiteLLM has the model (e.g. cache_write fields LiteLLM often omits). Units: USD per million tokens. Edit this file to override pricing without redeploying.",
4
4
  "units": "usd_per_million_tokens",
5
5
  "deepseek_v4_pro_discount_expiry": "2026-05-31T15:59:00Z — DeepSeek v4-pro is currently at a 75% promotional discount. After expiry the prices revert to 4x: input $1.74/M, output $3.48/M, cache_read $0.0145/M, cache_write $1.74/M. Update this file before the cutover.",
6
- "sonnet5_intro_price_expiry": "2026-08-31 — Sonnet 5 intro price 2/10 reverts to 3/15 sticker. The src pricing path auto-tracks LiteLLM (no edit needed), but the 5 dashboard/edge-patches MODEL_PRICING tables hardcode 2/10 and must be reverted to 3/15 manually + re-vendor the seed. See issue #16."
6
+ "sonnet5_intro_price_expiry": "2026-08-31 — Sonnet 5 intro price 2/10 reverts to 3/15 sticker. The src pricing path auto-tracks LiteLLM (no edit needed); re-vendor the seed after the cutover. See issue #16."
7
7
  },
8
8
  "exact": {
9
9
  "claude-fable-5": { "input": 10, "output": 50, "cache_read": 1, "cache_write": 12.5, "note": "Pinned from Anthropic public pricing until bundled LiteLLM seed carries Fable 5." },