@ipv9/tokentracker-cli 0.39.37 → 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.
- package/README.md +41 -9
- package/dashboard/dist/assets/{Card-DKmo-v8a.js → Card-BbRYRVXf.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-DYKHv0m3.js +60 -0
- package/dashboard/dist/assets/{FadeIn-Cf30rPTW.js → FadeIn-CjAacJ5t.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-D3CL8XP0.js → IpCheckPage-BGALK8Vy.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-BqST7DxD.js → LimitsPage-LkZGPYvg.js} +2 -2
- package/dashboard/dist/assets/{LocalOnlyNotice-CqHzPooT.js → LocalOnlyNotice-Dxo2vFMQ.js} +1 -1
- package/dashboard/dist/assets/PopoverPopup-DP9fwdtl.js +1 -0
- package/dashboard/dist/assets/Select-DPE53NmM.js +1 -0
- package/dashboard/dist/assets/SelectItemText-D69v77is.js +12 -0
- package/dashboard/dist/assets/SettingsPage-Dxzqpi02.js +1 -0
- package/dashboard/dist/assets/SkillsPage-Bo7e39AB.js +1 -0
- package/dashboard/dist/assets/WidgetsPage-HHcIr_Eq.js +1 -0
- package/dashboard/dist/assets/WrappedPage-C-_jLXXU.js +1 -0
- package/dashboard/dist/assets/{arrow-up-right-BJzUcPig.js → arrow-up-right-BJvJHUGj.js} +1 -1
- package/dashboard/dist/assets/{download-CsXweDLj.js → download-CnzY_EgN.js} +1 -1
- package/dashboard/dist/assets/format-1w-q5n2f.js +1 -0
- package/dashboard/dist/assets/main-1kxAVM3m.css +1 -0
- package/dashboard/dist/assets/main-3gBEI6Jl.js +694 -0
- package/dashboard/dist/assets/mock-data-CJOMGcL9.js +1 -0
- package/dashboard/dist/assets/use-limits-display-prefs-D1nT9-mr.js +1 -0
- package/dashboard/dist/assets/use-native-settings-Dh6NzqjY.js +1 -0
- package/dashboard/dist/assets/use-usage-limits-BXR6lzGf.js +1 -0
- package/dashboard/dist/assets/useCurrency-Hhs5jbWw.js +1 -0
- package/dashboard/dist/index.html +16 -28
- package/dashboard/dist/llms.txt +0 -2
- package/dashboard/dist/sitemap.xml +0 -12
- package/package.json +7 -4
- package/src/cli.js +4 -13
- package/src/commands/doctor.js +1 -3
- package/src/commands/init.js +63 -53
- package/src/commands/serve.js +2 -50
- package/src/commands/status.js +1 -55
- package/src/commands/sync.js +134 -227
- package/src/lib/{browser-auth.js → browser-open.js} +3 -149
- package/src/lib/claude-categorizer.js +204 -32
- package/src/lib/codex-context-breakdown.js +83 -7
- package/src/lib/codex-rollout-parser.js +52 -10
- package/src/lib/diagnostics.js +1 -49
- package/src/lib/doctor.js +12 -87
- package/src/lib/file-identity.js +69 -0
- package/src/lib/init-flow.js +6 -3
- package/src/lib/local-api.js +6 -364
- package/src/lib/pricing/curated-overrides.json +1 -1
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +392 -144
- package/src/lib/runtime-config.js +0 -32
- package/src/lib/sqlite-reader.js +83 -8
- package/dashboard/dist/assets/ActivityHeatmap-DPZ_Aj6E.js +0 -42
- package/dashboard/dist/assets/DashboardPage-C9Q5HCDh.js +0 -19
- package/dashboard/dist/assets/DevicePage-DhQFtROo.js +0 -1
- package/dashboard/dist/assets/DialogTitle-DduJCLiL.js +0 -1
- package/dashboard/dist/assets/InsforgeUserHeaderControls-CDqYVWBQ.js +0 -1
- package/dashboard/dist/assets/LandingPage-9345o0vr.js +0 -4356
- package/dashboard/dist/assets/LeaderboardAvatar-DNORVh3n.js +0 -1
- package/dashboard/dist/assets/LeaderboardPage-DBsdCCzY.js +0 -6
- package/dashboard/dist/assets/LeaderboardProfileModal-BuYdBVh_.js +0 -72
- package/dashboard/dist/assets/LeaderboardProfilePage-D4Fe1LOk.js +0 -1
- package/dashboard/dist/assets/LoginPage-BmcybmeK.js +0 -1
- package/dashboard/dist/assets/PopoverPopup-CDL7kqy5.js +0 -1
- package/dashboard/dist/assets/Select-BkzhG41t.js +0 -1
- package/dashboard/dist/assets/SelectItemText-BmRzs9ud.js +0 -1
- package/dashboard/dist/assets/SettingsPage-gXQl_o6s.js +0 -1
- package/dashboard/dist/assets/SkillsPage-BRXYEsKm.js +0 -1
- package/dashboard/dist/assets/WidgetsPage-CLHLz2UW.js +0 -1
- package/dashboard/dist/assets/WrappedPage-p4ZFwQjO.js +0 -1
- package/dashboard/dist/assets/index-BeoRn2gJ.js +0 -2
- package/dashboard/dist/assets/info-CuLr7ZIa.js +0 -1
- package/dashboard/dist/assets/main-CPGI-smk.js +0 -1004
- package/dashboard/dist/assets/main-DAcSUW2t.css +0 -1
- package/dashboard/dist/assets/use-limits-display-prefs-DOB09__q.js +0 -1
- package/dashboard/dist/assets/use-native-settings-JSylS2xS.js +0 -1
- package/dashboard/dist/assets/use-spring-qjUEvMQX.js +0 -1
- package/dashboard/dist/assets/use-usage-limits-B0bzPxNR.js +0 -1
- package/dashboard/dist/assets/useCurrency-BRorShq7.js +0 -1
- package/dashboard/dist/assets/useOpenInteractionType-DPP-6ZsL.js +0 -12
- package/dashboard/dist/share.html +0 -140
- package/src/commands/device-login.js +0 -161
- package/src/lib/upload-throttle.js +0 -148
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as A}from"./format-1w-q5n2f.js";function ht(){if(typeof Intl>"u"||!Intl.DateTimeFormat)return null;try{return Intl.DateTimeFormat().resolvedOptions().timeZone||null}catch{return null}}function kt(t=new Date){const e=t instanceof Date?t:new Date(t);if(!Number.isFinite(e.getTime()))return 0;const n=e.getTimezoneOffset();return Number.isFinite(n)?-n:0}function q(t){if(!Number.isFinite(t)||t===0)return"UTC";const e=t>=0?"+":"-",n=Math.abs(t),o=String(Math.floor(n/60)).padStart(2,"0"),a=String(n%60).padStart(2,"0");return`UTC${e}${o}:${a}`}function Dt({timeZone:t,offsetMinutes:e}={}){const n=q(e);return t&&t!=="UTC"?`${t} (${n})`:n}function bt({timeZone:t,offsetMinutes:e}={}){return Number.isFinite(e)?q(e):t||"UTC"}function wt({timeZone:t,offsetMinutes:e,date:n=new Date}={}){const o=n instanceof Date?n:new Date(n);if(!Number.isFinite(o.getTime()))return"";if(t&&typeof Intl<"u"&&Intl.DateTimeFormat)try{const s=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit"}).formatToParts(o).reduce((m,c)=>(c.type&&c.value&&(m[c.type]=c.value),m),{}),u=s.year,i=s.month,_=s.day;if(u&&i&&_)return`${u}-${i}-${_}`}catch{}if(typeof e=="number"&&Number.isFinite(e)){const a=new Date(o.getTime()+e*6e4);return G(a)}return Q(o)}function J({timeZone:t,offsetMinutes:e,date:n=new Date}={}){const o=n instanceof Date?n:new Date(n);if(!Number.isFinite(o.getTime()))return null;if(t&&typeof Intl<"u"&&Intl.DateTimeFormat)try{const s=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit"}).formatToParts(o).reduce((m,c)=>(c.type&&c.value&&(m[c.type]=c.value),m),{}),u=Number(s.year),i=Number(s.month),_=Number(s.day);if(Number.isFinite(u)&&Number.isFinite(i)&&Number.isFinite(_))return{year:u,month:i,day:_}}catch{}if(typeof e=="number"&&Number.isFinite(e)){const a=new Date(o.getTime()+e*6e4);return{year:a.getUTCFullYear(),month:a.getUTCMonth()+1,day:a.getUTCDate()}}return{year:o.getFullYear(),month:o.getMonth()+1,day:o.getDate()}}function yt({timeZone:t,offsetMinutes:e}={}){return t?`tz:${t}`:typeof e=="number"&&Number.isFinite(e)?`offset:${Math.trunc(e)}`:"utc"}function G(t){const e=t.getUTCFullYear(),n=String(t.getUTCMonth()+1).padStart(2,"0"),o=String(t.getUTCDate()).padStart(2,"0");return`${e}-${n}-${o}`}function Q(t){const e=t.getFullYear(),n=String(t.getMonth()+1).padStart(2,"0"),o=String(t.getDate()).padStart(2,"0");return`${e}-${n}-${o}`}function g(t){return new Date(Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate())).toISOString().slice(0,10)}function F(t){const e=t instanceof Date?t:new Date(t);if(!Number.isFinite(e.getTime()))return"";const n=e.getFullYear(),o=String(e.getMonth()+1).padStart(2,"0"),a=String(e.getDate()).padStart(2,"0");return`${n}-${o}-${a}`}function X(t){if(!t)return null;const e=String(t).trim(),n=e.split("-");if(n.length!==3)return null;const o=Number(n[0]),a=Number(n[1])-1,r=Number(n[2]);if(!Number.isFinite(o)||!Number.isFinite(a)||!Number.isFinite(r))return null;const s=new Date(Date.UTC(o,a,r));return Number.isFinite(s.getTime())&&g(s)===e?s:null}function Z(t){if(!t)return"";const e=t.year,n=String(t.month).padStart(2,"0"),o=String(t.day).padStart(2,"0");return!e||!n||!o?"":`${e}-${n}-${o}`}function tt(t,{timeZone:e,offsetMinutes:n,now:o}={}){const a=o instanceof Date&&Number.isFinite(o.getTime())?o:new Date,r=J({timeZone:e,offsetMinutes:n,date:a});if(!r){const i=F(new Date);return{from:i,to:i}}const s=Z(r),u=X(s);if(!u)return{from:s,to:s};if(t==="day")return{from:s,to:s};if(t==="24h"){const i=new Date(u);return i.setUTCDate(i.getUTCDate()-1),{from:g(i),to:s}}if(t==="week"){const i=new Date(u);return i.setUTCDate(i.getUTCDate()-6),{from:g(i),to:s}}if(t==="month"){const i=new Date(u);return i.setUTCDate(i.getUTCDate()-29),{from:g(i),to:s}}if(t==="total"){const i=new Date(Date.UTC(u.getUTCFullYear(),u.getUTCMonth()-23,1));return{from:g(i),to:s}}return tt("week")}function Y(t){if(typeof t!="string")return null;const e=/^(\d{4})-(\d{2})-(\d{2})$/.exec(t.trim());if(!e)return null;const n=Number(e[1]),o=Number(e[2])-1,a=Number(e[3]),r=new Date(Date.UTC(n,o,a));return Number.isFinite(r.getTime())&&g(r)===t.trim()?r:null}function v(t,e){return new Date(Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate()+e))}function et(t,e){const n=Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate())-Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate());return Math.floor(n/864e5)}function L(t,e){if(!Array.isArray(t)||t.length===0)return 0;const n=t.length,o=(n-1)*e,a=Math.floor(o),r=o-a,s=t[a]??t[n-1],u=t[Math.min(n-1,a+1)]??t[n-1];return Math.round(s+(u-s)*r)}function nt(t){return t<=0?0:t>=4?4:t}function z({weeks:t=52,now:e,weekStartsOn:n="sun"}={}){const o=e instanceof Date&&Number.isFinite(e.getTime())?e:new Date,a=F(o),r=Y(a)||new Date(Date.UTC(o.getFullYear(),o.getMonth(),o.getDate())),s=n==="mon"?1:0,u=r.getUTCDay(),i=v(r,-((u-s+7)%7)),_=v(i,-7*(Math.max(1,t)-1));return{from:g(_),to:a}}function ot({dailyRows:t,weeks:e=52,to:n,weekStartsOn:o="sun"}={}){const a=Y(n)||new Date(Date.UTC(new Date().getFullYear(),new Date().getMonth(),new Date().getDate())),{from:r}=z({weeks:e,now:a,weekStartsOn:o}),s=Y(r)||v(a,-(e*7-1)),u=(()=>{const h=(s.getUTCDay()-(o==="mon"?1:0)+7)%7;return v(s,-h)})(),i=new Map;for(const l of Array.isArray(t)?t:[]){const d=typeof l?.day=="string"?l.day:null;if(!d)continue;const h=A(l?.conversation_count)??0,y=A(l?.billable_total_tokens??l?.total_tokens)??0;i.set(d,{value:Math.max(0,h),tokens:Math.max(0,y),models:l?.models||null})}const _=et(u,a)+1,m=Math.ceil(_/7),c=[];for(let l=0;l<_;l++){const d=v(u,l),h=g(d),y=i.get(h),D=y?y.value:0;D>0&&c.push(D)}c.sort((l,d)=>l-d);const p=L(c,.5),C=L(c,.75),w=L(c,.9);function S(l){return!l||l<=0?0:l<=p?1:l<=C?2:l<=w?3:4}const f=[];for(let l=0;l<m;l++){const d=[];for(let h=0;h<7;h++){const y=l*7+h,D=v(u,y);if(D.getTime()>a.getTime()){d.push(null);continue}const T=g(D),b=i.get(T),M=b?b.value:0,N=b?b.tokens:0,x=b?b.models:null;d.push({day:T,value:M,total_tokens:N,level:nt(S(M)),models:x})}f.push(d)}const k=f.length>e?f.slice(f.length-e):f;return{from:r,to:g(a),weeks:k,thresholds:{t1:p,t2:C,t3:w}}}function at({dailyRows:t,to:e}={}){const n=Y(e)||new Date(Date.UTC(new Date().getFullYear(),new Date().getMonth(),new Date().getDate())),o=new Map;for(const r of Array.isArray(t)?t:[]){const s=typeof r?.day=="string"?r.day:null;if(!s)continue;const u=A(r?.conversation_count??r?.billable_total_tokens??r?.total_tokens)??0;o.set(s,Math.max(0,u))}let a=0;for(let r=0;r<370;r++){const s=g(v(n,-r));if((o.get(s)??0)>0){a+=1;continue}break}return a}const P={},H="tokentracker",st=["tokentracker/tokentracker","spacedriveapp/spacedrive","acme/alpha","acme/beta","neo/nebula","signal/flux","matrix/terminal","orbit/atlas","lumen/core","delta/horizon"];function rt(){if(typeof window<"u"){const t=new URLSearchParams(window.location.search),e=String(t.get("mock")||"").toLowerCase();if(e==="0"||e==="false"||e==="off"||e==="no")return!1;if(e==="1"||e==="true"||e==="on"||e==="yes")return!0}if(typeof import.meta<"u"&&P){const t="".toLowerCase();if(t==="1"||t==="true")return!0}return!1}function ut(){if(typeof import.meta<"u"&&P){const t="".trim();if(t)return t;const e="".trim();if(e)return e}if(typeof window<"u"){const t=new URLSearchParams(window.location.search),e=String(t.get("mock_now")||"").trim();if(e)return e;const n=String(t.get("mock_today")||"").trim();if(n)return n}return""}function it(t){if(!t)return null;const e=String(t).trim();if(!e)return null;if(/^\d{4}-\d{2}-\d{2}$/.test(e)){const[o,a,r]=e.split("-").map(Number);if(!Number.isFinite(o)||!Number.isFinite(a)||!Number.isFinite(r))return null;const s=new Date(o,a-1,r,12,0,0);return Number.isFinite(s.getTime())?s:null}const n=new Date(e);return Number.isFinite(n.getTime())?n:null}function Mt(){return rt()?it(ut()):null}function ct(){if(typeof import.meta<"u"&&P){const t="".trim();if(t)return t}if(typeof window<"u"){const t=new URLSearchParams(window.location.search),e=String(t.get("mock_seed")||"").trim();if(e)return e}return H}function lt(){if(typeof import.meta<"u"&&P){const t="".trim(),e=Number(t);if(Number.isFinite(e)&&e>0)return Math.floor(e)}if(typeof window<"u"){const t=new URLSearchParams(window.location.search),e=String(t.get("mock_missing")||"").trim(),n=Number(e);if(Number.isFinite(n)&&n>0)return Math.floor(n)}return 0}function I(t){return(t==null?ct():String(t)).trim()||H}function R(t){let e=2166136261;for(let n=0;n<t.length;n+=1)e^=t.charCodeAt(n),e=Math.imul(e,16777619);return e>>>0}function U(t){if(typeof t!="string")return null;const e=/^(\d{4})-(\d{2})-(\d{2})$/.exec(t.trim());if(!e)return null;const n=Number(e[1]),o=Number(e[2])-1,a=Number(e[3]),r=new Date(Date.UTC(n,o,a));return Number.isFinite(r.getTime())&&g(r)===t.trim()?r:null}function K(t,e){return new Date(Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate()+e))}function W(t,e){return new Date(Date.UTC(t.getUTCFullYear(),t.getUTCMonth()+e,1))}function _t(t){return`${t.getUTCFullYear()}-${String(t.getUTCMonth()+1).padStart(2,"0")}`}function $({from:t,to:e,seed:n}){const o=U(F(new Date))||new Date,a=U(t)||o,r=U(e)||a,s=[],u=I(n),i=Math.floor((Date.UTC(r.getUTCFullYear(),r.getUTCMonth(),r.getUTCDate())-Date.UTC(a.getUTCFullYear(),a.getUTCMonth(),a.getUTCDate()))/864e5)+1;for(let _=0;_<i;_+=1){const m=K(a,_),c=g(m),p=R(`${u}:${c}`),C=p%1e3/1e3,w=.6+.4*Math.sin(_/6*Math.PI*.5),S=m.getUTCDay()===0||m.getUTCDay()===6?.65:1,f=18e3+Math.round(12e3*C),k=Math.max(0,Math.round(f*w*S)),l=Math.round(k*.46),d=Math.round(k*.34),h=Math.round(k*.14),y=Math.max(0,k-l-d-h),D={};if(k>0){const T=["gpt-4o","claude-3.5-sonnet","gemini-1.5-pro","deepseek-coder"],b=1+p%3;let M=k;for(let N=0;N<b;N++){const x=T[(p+N)%T.length];if(N===b-1)D[x]=M;else{const j=Math.round(M*(.3+.4*((p+N*17)%10)/10));D[x]=j,M-=j}}}s.push({day:c,total_tokens:k,billable_total_tokens:k,input_tokens:l,output_tokens:d,cached_input_tokens:h,reasoning_output_tokens:y,conversation_count:1+p%5,models:D})}return s}function mt({day:t,seed:e}){const n=U(t)||U(F(new Date))||new Date,o=g(n),a=I(e),r=Array.from({length:48},(u,i)=>{const _=Math.floor(i/2),m=i%2===0?0:30,c=R(`${a}:${o}:${_}:${m}`),p=c%1e3/1e3,C=(_+m/60)/24,w=.4+.6*Math.sin(C*Math.PI*2),S=900+Math.round(700*p),f=Math.max(0,Math.round(S*w)),k=Math.round(f*.46),l=Math.round(f*.34),d=Math.round(f*.14),h=Math.max(0,f-k-l-d),y={};if(f>0){const D=["gpt-4o","claude-3.5-sonnet","gemini-1.5-pro","deepseek-coder"],T=1+c%2;let b=f;for(let M=0;M<T;M++){const N=D[(c+M)%D.length];if(M===T-1)y[N]=b;else{const x=Math.round(b*(.3+.4*((c+M*17)%10)/10));y[N]=x,b-=x}}}return{hour:`${o}T${String(_).padStart(2,"0")}:${String(m).padStart(2,"0")}:00`,total_tokens:f,billable_total_tokens:f,input_tokens:k,output_tokens:l,cached_input_tokens:d,reasoning_output_tokens:h,models:y}}),s=Math.max(0,Math.min(48,lt()));if(s>0){const u=Date.now(),i=r.map((c,p)=>{const C=Date.parse(c.hour);return Number.isFinite(C)&&C<=u?{index:p,ts:C}:null}).filter(Boolean),_=Math.max(0,i.length-s),m=i.slice(_);for(const c of m){const p=r[c.index];p&&(r[c.index]={...p,missing:!0})}}return r}function dt({months:t=24,to:e,seed:n}){const o=U(e)||U(F(new Date))||new Date,a=new Date(Date.UTC(o.getUTCFullYear(),o.getUTCMonth(),1)),r=I(n),s=[];for(let u=t-1;u>=0;u-=1){const i=W(a,-u),_=_t(i),m=R(`${r}:${_}`),c=m%1e3/1e3,p=.7+.3*Math.sin(s.length/6*Math.PI*.5),C=36e4+Math.round(2e5*c),w=Math.max(0,Math.round(C*p)),S=Math.round(w*.46),f=Math.round(w*.34),k=Math.round(w*.14),l=Math.max(0,w-S-f-k),d={};if(w>0){const h=["gpt-4o","claude-3.5-sonnet","gemini-1.5-pro","deepseek-coder"],y=1+m%3;let D=w;for(let T=0;T<y;T++){const b=h[(m+T)%h.length];if(T===y-1)d[b]=D;else{const M=Math.round(D*(.3+.4*((m+T*17)%10)/10));d[b]=M,D-=M}}}s.push({month:_,total_tokens:w,billable_total_tokens:w,input_tokens:S,output_tokens:f,cached_input_tokens:k,reasoning_output_tokens:l,models:d})}return s}function O(t){return t.reduce((e,n)=>(e.total_tokens+=Number(n.total_tokens||0),e.billable_total_tokens+=Number(n.billable_total_tokens||n.total_tokens||0),e.input_tokens+=Number(n.input_tokens||0),e.output_tokens+=Number(n.output_tokens||0),e.cached_input_tokens+=Number(n.cached_input_tokens||0),e.reasoning_output_tokens+=Number(n.reasoning_output_tokens||0),e.conversation_count+=Number(n.conversation_count||0),e),{total_tokens:0,billable_total_tokens:0,input_tokens:0,output_tokens:0,cached_input_tokens:0,reasoning_output_tokens:0,conversation_count:0})}function gt(t,e=1.75){const n=Number(t||0);return!Number.isFinite(n)||n<=0?"0.000000":(n*e/1e6).toFixed(6)}function E(t,e){const n=Number.isFinite(e)?e:0;return{total_tokens:Math.max(0,Math.round(t.total_tokens*n)),billable_total_tokens:Math.max(0,Math.round((t.billable_total_tokens??t.total_tokens)*n)),input_tokens:Math.max(0,Math.round(t.input_tokens*n)),output_tokens:Math.max(0,Math.round(t.output_tokens*n)),cached_input_tokens:Math.max(0,Math.round(t.cached_input_tokens*n)),reasoning_output_tokens:Math.max(0,Math.round(t.reasoning_output_tokens*n))}}function B(t){return{...t,total_cost_usd:gt(t.total_tokens)}}function Tt({from:t,to:e,seed:n}={}){const o=$({from:t,to:e,seed:n});return{from:t,to:e,data:o}}function Ut({day:t,seed:e}={}){const n=U(t)||new Date,o=g(n),a=mt({day:o,seed:e});return{day:o,data:a}}function Ct({months:t=24,to:e,seed:n}={}){const o=U(e)||U(F(new Date))||new Date,a=g(o),r=dt({months:t,to:a,seed:n}),s=W(new Date(Date.UTC(o.getUTCFullYear(),o.getUTCMonth(),1)),-(t-1));return{from:g(s),to:a,months:t,data:r}}function Nt({from:t,to:e,seed:n,rolling:o=!0}={}){const a=$({from:t,to:e,seed:n}),r=O(a),s=B(r),u=o?ft({to:e,seed:n}):null;return{from:t,to:e,days:a.length,totals:s,...u?{rolling:u}:{}}}function ft({to:t,seed:e}={}){const n=U(t)||U(F(new Date))||new Date,o=g(n),a=g(K(n,-6)),r=g(K(n,-29)),s=$({from:a,to:o,seed:e}),u=$({from:r,to:o,seed:e});return{last_7d:V({rows:s,from:a,to:o}),last_30d:V({rows:u,from:r,to:o})}}function V({rows:t,from:e,to:n}={}){const o=O(t||[]),a=(t||[]).filter(s=>Number(s.billable_total_tokens??s.total_tokens)>0).length,r=a>0?Math.floor(o.billable_total_tokens/a):0;return{from:e,to:n,totals:{billable_total_tokens:o.billable_total_tokens,conversation_count:o.conversation_count},active_days:a,avg_per_active_day:r}}function Ft({seed:t,limit:e=3}={}){const n=I(t),o=st.map((a,r)=>{const u=12e4+R(`${n}:${a}`)%9e5,i=r%4*4200,_=Math.max(0,u+i),m=Math.max(0,Math.round(_*.96));return{project_key:a,project_ref:`https://github.com/${a}`,total_tokens:String(_),billable_total_tokens:String(m)}}).sort((a,r)=>Number(r.billable_total_tokens)-Number(a.billable_total_tokens)).slice(0,Math.max(1,Math.min(10,Math.floor(Number(e)||3))));return{generated_at:new Date().toISOString(),entries:o}}function St({weeks:t=52,to:e,weekStartsOn:n="sun",seed:o}={}){const a=z({weeks:t,now:U(e)||U(F(new Date))||new Date,weekStartsOn:n}),r=$({from:a.from,to:a.to,seed:o});return{...ot({dailyRows:r,weeks:t,to:a.to,weekStartsOn:n}),week_starts_on:n,active_days:r.filter(u=>Number(u.billable_total_tokens??u.total_tokens)>0).length,streak_days:at({dailyRows:r,to:a.to})}}function xt({from:t,to:e,seed:n}={}){const o=$({from:t,to:e,seed:n}),a=O(o),s=[{source:"codex",weight:.7,models:[{model:"gpt-5.2-codex",model_id:"gpt-5.2-codex",weight:.2},{model:"unknown",model_id:"unknown",weight:.8}]},{source:"claude",weight:.2,models:[{model:"claude-3.5",model_id:"claude-3.5",weight:.3},{model:"unknown",model_id:"unknown",weight:.7}]},{source:"every-code",weight:.1,models:[{model:"unknown",model_id:"unknown",weight:1}]}].map(u=>{const i=E(a,u.weight),_=u.models.map(m=>{const c=E(i,m.weight);return{model:m.model,model_id:m.model_id||m.model,totals:B(c)}});return{source:u.source,totals:B(i),models:_}});return{from:t,to:e,days:o.length,sources:s,pricing:{model:"mock",pricing_mode:"add",source:"mock",effective_from:F(new Date),rates_per_million_usd:{input:"1.750000",cached_input:"0.175000",output:"14.000000",reasoning_output:"14.000000"}}}}function vt({from:t,to:e,source:n="claude"}={}){if(n==="codex")return{from:t,to:e,source:"codex",scope:"supported",totals:{input_tokens:142e4,cached_input_tokens:588e4,cache_creation_input_tokens:92e4,output_tokens:256e4,reasoning_output_tokens:61e4,total_tokens:1078e4},session_count:188,message_count:5436,tool_calls_breakdown:{categories:[{name:"Execution",calls:742,totals:{input_tokens:32e4,cached_input_tokens:104e4,cache_creation_input_tokens:11e4,output_tokens:46e4,reasoning_output_tokens:12e4,total_tokens:193e4},tools:[{name:"exec_command",calls:510,totals:{input_tokens:25e4,cached_input_tokens:82e4,cache_creation_input_tokens:8e4,output_tokens:37e4,reasoning_output_tokens:9e4,total_tokens:152e4}},{name:"write_stdin",calls:232,totals:{input_tokens:7e4,cached_input_tokens:22e4,cache_creation_input_tokens:3e4,output_tokens:9e4,reasoning_output_tokens:3e4,total_tokens:41e4}}]},{name:"Browser",calls:406,totals:{input_tokens:21e4,cached_input_tokens:88e4,cache_creation_input_tokens:9e4,output_tokens:42e4,reasoning_output_tokens:1e5,total_tokens:17e5},tools:[{name:"take_snapshot",calls:180,totals:{input_tokens:1e5,cached_input_tokens:4e5,cache_creation_input_tokens:4e4,output_tokens:18e4,reasoning_output_tokens:4e4,total_tokens:76e4}},{name:"click",calls:126,totals:{input_tokens:6e4,cached_input_tokens:25e4,cache_creation_input_tokens:3e4,output_tokens:12e4,reasoning_output_tokens:35e3,total_tokens:495e3}},{name:"evaluate_script",calls:100,totals:{input_tokens:5e4,cached_input_tokens:23e4,cache_creation_input_tokens:2e4,output_tokens:12e4,reasoning_output_tokens:25e3,total_tokens:445e3}}]}],tools_total:363e4,privacy:{includes_inputs:!1,note:"Aggregated tool names only; no tool arguments or outputs are included."}},exec_command_breakdown:{by_type:[{name:"test",calls:168,failures:14,duration_ms:482e3,max_duration_ms:18400,output_chars:45e4,output_lines:8600,totals:{input_tokens:9e4,cached_input_tokens:32e4,output_tokens:16e4,reasoning_output_tokens:42e3,total_tokens:612e3}},{name:"build",calls:116,failures:9,duration_ms:392e3,max_duration_ms:22100,output_chars:31e4,output_lines:5200,totals:{input_tokens:7e4,cached_input_tokens:24e4,output_tokens:13e4,reasoning_output_tokens:3e4,total_tokens:47e4}}],by_exit:[{name:"completed:0",calls:438,failures:0,duration_ms:104e4,max_duration_ms:22100,output_chars:83e4,output_lines:13100,totals:{input_tokens:22e4,cached_input_tokens:78e4,output_tokens:35e4,reasoning_output_tokens:82e3,total_tokens:1432e3}},{name:"completed:1",calls:72,failures:72,duration_ms:155e3,max_duration_ms:11800,output_chars:12e4,output_lines:2300,totals:{input_tokens:3e4,cached_input_tokens:11e4,output_tokens:55e3,reasoning_output_tokens:8e3,total_tokens:195e3}}]}};if(n!=="claude")return{from:t,to:e,source:n,scope:"unsupported",totals:{input_tokens:0,cached_input_tokens:0,cache_creation_input_tokens:0,output_tokens:0,reasoning_output_tokens:0,total_tokens:0},categories:["system_prefix","conversation_history","user_input","tool_calls","subagents","reasoning","assistant_response"].map(s=>({key:s,totals:{input_tokens:0,cached_input_tokens:0,cache_creation_input_tokens:0,output_tokens:0,reasoning_output_tokens:0,total_tokens:0},percent:0})),session_count:0,message_count:0};const o=[{key:"system_prefix",total:12896539},{key:"conversation_history",total:320207200},{key:"user_input",total:998025},{key:"tool_calls",total:4808739},{key:"subagents",total:1022828},{key:"reasoning",total:11073118},{key:"assistant_response",total:1289174}],a=o.reduce((s,u)=>s+u.total,0),r=o.map(({key:s,total:u})=>({key:s,totals:{input_tokens:s==="user_input"?u:0,cached_input_tokens:s==="conversation_history"?Math.round(u*.95):0,cache_creation_input_tokens:s==="system_prefix"?u:s==="conversation_history"?Math.round(u*.05):0,output_tokens:["tool_calls","subagents","reasoning","assistant_response"].includes(s)?u:0,reasoning_output_tokens:s==="reasoning"?u:0,total_tokens:u},percent:Number((u/a*100).toFixed(2))}));return{from:t,to:e,source:"claude",scope:"supported",totals:{input_tokens:998025,cached_input_tokens:Math.round(320207200*.95),cache_creation_input_tokens:12896539+Math.round(320207200*.05),output_tokens:18193859,reasoning_output_tokens:11073118,total_tokens:a},categories:r,session_count:312,message_count:12046}}export{yt as a,ot as b,at as c,wt as d,kt as e,g as f,z as g,ht as h,rt as i,Mt as j,tt as k,Dt as l,bt as m,Tt as n,Nt as o,xt as p,Ut as q,Ft as r,Ct as s,St as t,vt as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as o,$ as I,a0 as h,a1 as C,a2 as R}from"./main-3gBEI6Jl.js";const d=["claude","codex","cursor","gemini","kimi","zai","kiro","copilot","antigravity"],Y={claude:"Claude",codex:"Codex",cursor:"Cursor",gemini:"Gemini",kimi:"Kimi",zai:"Z.AI",kiro:"Kiro",copilot:"GitHub Copilot",antigravity:"Antigravity"},P={claude:"/brand-logos/claude-code.svg",codex:"/brand-logos/codex.svg",cursor:"/brand-logos/cursor.svg",gemini:"/brand-logos/gemini.svg",kimi:"/brand-logos/kimi.svg",zai:null,kiro:"/brand-logos/kiro.svg",copilot:"/brand-logos/copilot.svg",antigravity:"/brand-logos/antigravity.svg"},w="tt.limits.providerOrder",m="tt.limits.providerVisibility",S="tt.limits.displayMode",p="limitsDisplayMode",f=Object.freeze({USED:"used",REMAINING:"remaining"}),E=new Set(Object.values(f));function O(){if(typeof window>"u")return[...d];try{const n=window.localStorage.getItem(w);if(!n)return[...d];const a=JSON.parse(n);if(!Array.isArray(a))return[...d];const r=a.filter(c=>d.includes(c));for(const c of d)r.includes(c)||r.push(c);return r}catch{return[...d]}}function D(){const n=Object.fromEntries(d.map(a=>[a,!0]));if(typeof window>"u")return n;try{const a=window.localStorage.getItem(m);if(!a)return n;const r=JSON.parse(a);if(!r||typeof r!="object")return n;const c={...n};for(const u of d)typeof r[u]=="boolean"&&(c[u]=r[u]);return c}catch{return n}}function v(){if(typeof window>"u")return f.USED;try{const n=window.localStorage.getItem(S);return E.has(n)?n:f.USED}catch{return f.USED}}function T(){const[n,a]=o.useState(O),[r,c]=o.useState(D),[u,l]=o.useState(v),g=o.useCallback(t=>{E.has(t)&&(l(t),I()&&h(p,t))},[]);o.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(w,JSON.stringify(n))}catch{}},[n]),o.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(m,JSON.stringify(r))}catch{}},[r]),o.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(S,u)}catch{}},[u]),o.useEffect(()=>{if(!I())return;const t=C(e=>{const i=e?.[p];E.has(i)&&l(i)});return R(),t},[]),o.useEffect(()=>{if(typeof window>"u")return;const t=e=>{e.key===w&&a(O()),e.key===m&&c(D()),e.key===S&&l(v())};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)},[]);const k=o.useCallback(t=>{c(e=>({...e,[t]:!e[t]}))},[]),x=o.useCallback(t=>{a(e=>{const i=e.indexOf(t);if(i<=0)return e;const s=[...e];return[s[i-1],s[i]]=[s[i],s[i-1]],s})},[]),M=o.useCallback(t=>{a(e=>{const i=e.indexOf(t);if(i<0||i>=e.length-1)return e;const s=[...e];return[s[i],s[i+1]]=[s[i+1],s[i]],s})},[]),_=o.useCallback((t,e)=>{t!==e&&a(i=>{const s=i.indexOf(t),b=i.indexOf(e);if(s<0||b<0)return i;const y=[...i],[N]=y.splice(s,1);return y.splice(b,0,N),y})},[]),L=o.useCallback(()=>{a([...d]),c(Object.fromEntries(d.map(t=>[t,!0]))),g(f.USED)},[g]),A=o.useMemo(()=>n.filter(t=>r[t]!==!1),[n,r]);return{order:n,visibility:r,displayMode:u,setDisplayMode:g,visibleOrdered:A,toggle:k,moveUp:x,moveDown:M,moveToward:_,reset:L}}export{f as L,P as a,Y as b,T as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as a,x,r as n,b0 as g,b1 as m,a1 as b,a2 as u,a0 as f,a$ as h}from"./main-3gBEI6Jl.js";import{C as y}from"./Card-BbRYRVXf.js";function k({checked:s,onChange:t,disabled:e,ariaLabel:i}){return a.jsx("button",{type:"button",role:"switch","aria-checked":s,"aria-label":i,onClick:t,disabled:e,className:x("relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-oai-brand-500 disabled:opacity-50 disabled:cursor-not-allowed",s?"bg-oai-brand-500":"bg-oai-gray-300 dark:bg-oai-gray-700"),children:a.jsx("span",{className:x("inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform",s?"translate-x-[18px]":"translate-x-[3px]")})})}function p({label:s,hint:t,control:e}){return a.jsxs("div",{className:"flex items-center justify-between gap-4 py-3",children:[a.jsxs("div",{className:"min-w-0 flex-1",children:[a.jsx("div",{className:"text-sm text-oai-gray-900 dark:text-oai-gray-200",children:s}),t?a.jsx("div",{className:"mt-0.5 text-xs text-oai-gray-500 dark:text-oai-gray-400",children:t}):null]}),a.jsx("div",{className:"shrink-0",children:e})]})}function N({title:s,subtitle:t,action:e,children:i}){return a.jsxs(y,{children:[a.jsxs("div",{className:"mb-3 flex items-start justify-between gap-4",children:[a.jsxs("div",{className:"min-w-0 flex-1",children:[a.jsx("h2",{className:"text-sm font-medium text-oai-gray-500 dark:text-oai-gray-300 uppercase tracking-wide",children:s}),t?a.jsx("p",{className:"mt-1 truncate text-xs text-oai-gray-500 dark:text-oai-gray-400",children:t}):null]}),e?a.jsx("div",{className:"shrink-0",children:e}):null]}),a.jsx("div",{className:"-mb-3 divide-y divide-oai-gray-200/60 dark:divide-oai-gray-800/60",children:i})]})}function w({options:s,value:t,onChange:e}){return a.jsx("div",{className:"inline-flex items-center rounded-lg border border-oai-gray-200 bg-oai-gray-50 p-0.5 dark:border-oai-gray-800 dark:bg-oai-gray-900",children:s.map(({value:i,label:d,Icon:l})=>{const r=t===i;return a.jsxs("button",{type:"button",onClick:()=>e(i),"aria-pressed":r,className:x("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors",r?"bg-white text-oai-black shadow-sm dark:bg-oai-gray-800 dark:text-white":"text-oai-gray-500 hover:text-oai-black dark:text-oai-gray-400 dark:hover:text-white"),children:[l?a.jsx(l,{className:"h-3.5 w-3.5","aria-hidden":!0}):null,a.jsx("span",{children:d})]},i)})})}function S(){const[s,t]=n.useState(null),e=g()&&m();n.useEffect(()=>{if(!e)return;const r=b(o=>t(o));return u(),r},[e]);const i=n.useCallback((r,o)=>{e&&(t(c=>c&&{...c,[r]:o}),f(r,o))},[e]),d=n.useCallback(r=>{e&&h(r)},[e]),l=n.useCallback(()=>{e&&u()},[e]);return{available:e,settings:s,setSetting:i,runAction:d,refresh:l}}export{N as S,k as T,p as a,w as b,S as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{H as U,r as p,F as b}from"./main-3gBEI6Jl.js";import{i as y,n as M,o as H,p as L,q as j,r as z,s as B,t as _,u as C}from"./mock-data-CJOMGcL9.js";const f={usageSummary:"tokentracker-usage-summary",usageDaily:"tokentracker-usage-daily",usageHourly:"tokentracker-usage-hourly",usageMonthly:"tokentracker-usage-monthly",usageHeatmap:"tokentracker-usage-heatmap",usageModelBreakdown:"tokentracker-usage-model-breakdown",usageCategoryBreakdown:"tokentracker-usage-category-breakdown",projectUsageSummary:"tokentracker-project-usage-summary",userStatus:"tokentracker-user-status",localSync:"tokentracker-local-sync",usageLimits:"tokentracker-usage-limits"};async function m(t,e,a){const s=new URL(`/functions/${t}`,window.location.origin);if(e)for(const[c,i]of Object.entries(e))i!=null&&i!==""&&s.searchParams.set(c,String(i));const{accessToken:o,...r}=a||{},n=await fetch(s.toString(),{headers:{Accept:"application/json"},cache:"no-store",...r});if(!n.ok){const c=new Error(`Request failed with HTTP ${n.status}`);throw c.status=n.status,c}return n.json()}function d({timeZone:t,tzOffsetMinutes:e}={}){const a={},s=typeof t=="string"?t.trim():"";return s&&(a.tz=s),Number.isFinite(e)&&(a.tz_offset_minutes=String(Math.trunc(e))),a}function h({source:t,model:e}={}){const a={},s=typeof t=="string"?t.trim().toLowerCase():"";s&&(a.source=s);const o=typeof e=="string"?e.trim():"";return o&&(a.model=o),a}async function T({from:t,to:e,source:a,model:s,timeZone:o,tzOffsetMinutes:r,rolling:n=!1,accessToken:c}={}){if(y())return H({from:t,to:e,seed:c,rolling:n});const i=d({timeZone:o,tzOffsetMinutes:r}),l=h({source:a,model:s}),k=n?{rolling:"1"}:{};return m(f.usageSummary,{from:t,to:e,...l,...i,...k},{accessToken:c})}async function x({from:t,to:e,source:a,limit:s,timeZone:o,tzOffsetMinutes:r,accessToken:n}={}){if(y())return z({seed:n,limit:s});const c=d({timeZone:o,tzOffsetMinutes:r}),l={...h({source:a}),...c};return t&&(l.from=t),e&&(l.to=e),s!=null&&(l.limit=String(s)),m(f.projectUsageSummary,l)}async function A(t={}){if(y()){const e=new Date().toISOString();return{user_id:"local-user",created_at:e,pro:{active:!1,sources:[],expires_at:null,partial:!1,as_of:e},subscriptions:{partial:!1,as_of:e,items:[]}}}return m(f.userStatus)}async function $({signal:t}={}){const e=await U(),a=await fetch(`/functions/${f.localSync}`,{method:"POST",headers:{Accept:"application/json",...e},cache:"no-store",signal:t}),s=await a.json().catch(()=>({ok:!1,error:`Local sync request failed with HTTP ${a.status}`}));if(!a.ok||s?.ok===!1){const o=s?.error||s?.message||`Local sync request failed with HTTP ${a.status}`,r=new Error(o);throw r.status=a.status,r}return s}async function q({from:t,to:e,source:a,timeZone:s,tzOffsetMinutes:o,accessToken:r}={}){if(y())return L({from:t,to:e,seed:r});const n=d({timeZone:s,tzOffsetMinutes:o}),c=h({source:a});return m(f.usageModelBreakdown,{from:t,to:e,...c,...n},{accessToken:r})}async function R({from:t,to:e,source:a="claude",timeZone:s,tzOffsetMinutes:o}={}){if(y())return C({from:t,to:e,source:a});const r=d({timeZone:s,tzOffsetMinutes:o});return m(f.usageCategoryBreakdown,{from:t,to:e,source:a,...r})}async function F({from:t,to:e,source:a,model:s,timeZone:o,tzOffsetMinutes:r,accessToken:n}={}){if(y())return M({from:t,to:e,seed:n});const c=d({timeZone:o,tzOffsetMinutes:r}),i=h({source:a,model:s});return m(f.usageDaily,{from:t,to:e,...i,...c},{accessToken:n})}async function I({day:t,source:e,model:a,timeZone:s,tzOffsetMinutes:o,accessToken:r}={}){if(y())return j({day:t,seed:r});const n=d({timeZone:s,tzOffsetMinutes:o}),c=h({source:e,model:a}),i=t?{day:t,...c,...n}:{...c,...n};return m(f.usageHourly,i,{accessToken:r})}async function O({months:t,to:e,source:a,model:s,timeZone:o,tzOffsetMinutes:r,accessToken:n}={}){if(y())return B({months:t,to:e,seed:n});const c=d({timeZone:o,tzOffsetMinutes:r}),i=h({source:a,model:s});return m(f.usageMonthly,{...t?{months:String(t)}:{},...e?{to:e}:{},...i,...c},{accessToken:n})}async function P(t={}){const e=t?.refresh?{refresh:"1"}:void 0;return m(f.usageLimits,e)}async function v({weeks:t,to:e,weekStartsOn:a,source:s,model:o,timeZone:r,tzOffsetMinutes:n,accessToken:c}={}){if(y())return _({weeks:t,to:e,weekStartsOn:a,seed:c});const i=d({timeZone:r,tzOffsetMinutes:n}),l=h({source:s,model:o});return m(f.usageHeatmap,{weeks:String(t),to:e,week_starts_on:a,...l,...i},{accessToken:c})}function J(t){const e=!!t?.initialState,[a,s]=p.useState(()=>e?t?.initialState?.data??null:null),[o,r]=p.useState(()=>e?t?.initialState?.error??null:null),[n,c]=p.useState(!e),i=!!t?.initialRefresh,l=!!t?.publishToPreloadCache,k=p.useCallback((u,g)=>{!l||!u||typeof u!="object"||b(u,{source:g})},[l]),w=p.useCallback(async()=>{try{const u=await P({refresh:!0}),g=u&&typeof u=="object"?u:null;s(g),r(null),k(g,"manual-refresh")}catch(u){r(u?.message||String(u))}},[k]);return p.useEffect(()=>{if(e&&!i)return;let u=!1;return(async()=>{try{const g=await P(i?{refresh:!0}:{});if(u)return;const S=g&&typeof g=="object"?g:null;s(S),r(null),k(S,"page-load")}catch(g){if(u)return;r(g?.message||String(g))}finally{u||c(!1)}})(),()=>{u=!0}},[e,i,k]),{data:a,error:o,isLoading:n,refresh:w}}export{F as a,x as b,O as c,I as d,T as e,q as f,v as g,R as h,A as i,$ as t,J as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as e,r as t,aZ as c,a_ as r,C as a}from"./main-3gBEI6Jl.js";const o=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]],C=e("info",o),n=Object.freeze({currency:a,rate:1,symbol:"$",rates:{...r},rateSource:"default",rateFetchedAt:null,setCurrency:()=>{}});function y(){return t.useContext(c)??n}export{C as I,y as u};
|
|
@@ -3,19 +3,15 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>
|
|
7
|
-
<meta name="description" content="
|
|
8
|
-
<meta property="og:site_name" content="
|
|
9
|
-
<meta property="og:title" content="
|
|
10
|
-
<meta property="og:description" content="
|
|
11
|
-
<meta property="og:image" content="https://www.tokentracker.cc/dashboard-dark.png" />
|
|
6
|
+
<title>TokenTracker</title>
|
|
7
|
+
<meta name="description" content="See how many tokens your AI coding tools use — locally." />
|
|
8
|
+
<meta property="og:site_name" content="TokenTracker" />
|
|
9
|
+
<meta property="og:title" content="TokenTracker" />
|
|
10
|
+
<meta property="og:description" content="See how many tokens your AI coding tools use — locally." />
|
|
12
11
|
<meta property="og:type" content="website" />
|
|
13
|
-
<meta
|
|
14
|
-
<meta name="twitter:
|
|
15
|
-
<meta name="twitter:
|
|
16
|
-
<meta name="twitter:description" content="Automatically monitor token usage across Claude Code, Cursor, Codex, and more. Local-first, privacy-focused, and zero manual configuration." />
|
|
17
|
-
<meta name="twitter:image" content="https://www.tokentracker.cc/dashboard-dark.png" />
|
|
18
|
-
<link rel="canonical" href="https://www.tokentracker.cc/" />
|
|
12
|
+
<meta name="twitter:card" content="summary" />
|
|
13
|
+
<meta name="twitter:title" content="TokenTracker" />
|
|
14
|
+
<meta name="twitter:description" content="See how many tokens your AI coding tools use — locally." />
|
|
19
15
|
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
|
20
16
|
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
21
17
|
<link rel="icon" href="/favicon-32.png" sizes="32x32" type="image/png" />
|
|
@@ -146,12 +142,6 @@
|
|
|
146
142
|
"name": "Home",
|
|
147
143
|
"item": "https://www.tokentracker.cc/"
|
|
148
144
|
},
|
|
149
|
-
{
|
|
150
|
-
"@type": "ListItem",
|
|
151
|
-
"position": 2,
|
|
152
|
-
"name": "Leaderboard",
|
|
153
|
-
"item": "https://www.tokentracker.cc/leaderboard"
|
|
154
|
-
},
|
|
155
145
|
{
|
|
156
146
|
"@type": "ListItem",
|
|
157
147
|
"position": 3,
|
|
@@ -227,7 +217,7 @@
|
|
|
227
217
|
"name": "Does Token Tracker work offline?",
|
|
228
218
|
"acceptedAnswer": {
|
|
229
219
|
"@type": "Answer",
|
|
230
|
-
"text": "Yes. Token Tracker is local-
|
|
220
|
+
"text": "Yes. Token Tracker is local-only. All parsing, aggregation, and dashboard rendering happens on your machine, and nothing is uploaded anywhere."
|
|
231
221
|
}
|
|
232
222
|
}
|
|
233
223
|
]
|
|
@@ -235,8 +225,8 @@
|
|
|
235
225
|
]
|
|
236
226
|
}
|
|
237
227
|
</script>
|
|
238
|
-
<script type="module" crossorigin src="/assets/main-
|
|
239
|
-
<link rel="stylesheet" crossorigin href="/assets/main-
|
|
228
|
+
<script type="module" crossorigin src="/assets/main-3gBEI6Jl.js"></script>
|
|
229
|
+
<link rel="stylesheet" crossorigin href="/assets/main-1kxAVM3m.css">
|
|
240
230
|
</head>
|
|
241
231
|
<body>
|
|
242
232
|
<main class="aeo-seed-content" aria-label="Token Tracker AI-readable summary">
|
|
@@ -261,8 +251,8 @@
|
|
|
261
251
|
<h2>What you get after installing</h2>
|
|
262
252
|
<p>
|
|
263
253
|
Token Tracker runs entirely on your machine. After <code>npx tokentracker-cli</code>, a local
|
|
264
|
-
dashboard at <code>http://localhost:7680</code> exposes the following views —
|
|
265
|
-
|
|
254
|
+
dashboard at <code>http://localhost:7680</code> exposes the following views — your data stays on
|
|
255
|
+
your device. There is no upload path.
|
|
266
256
|
</p>
|
|
267
257
|
<ul>
|
|
268
258
|
<li><strong>Unified usage dashboard</strong> — input, output, cached, and cache-creation tokens across all 13 AI coding tools.</li>
|
|
@@ -273,7 +263,7 @@
|
|
|
273
263
|
<li><strong>Skills browser</strong> — discover and install agent skills from the open ecosystem.</li>
|
|
274
264
|
<li><strong>macOS menu bar app & desktop widget</strong> — at-a-glance usage without opening the dashboard.</li>
|
|
275
265
|
</ul>
|
|
276
|
-
<p><em>Privacy by design</em>: token counts only, never prompts or conversation content. Local-
|
|
266
|
+
<p><em>Privacy by design</em>: token counts only, never prompts or conversation content. Local-only — nothing is uploaded.</p>
|
|
277
267
|
|
|
278
268
|
<h2>Supported AI coding agent CLIs</h2>
|
|
279
269
|
<ul>
|
|
@@ -311,8 +301,7 @@
|
|
|
311
301
|
(<code>src/lib/rollout.js</code>) normalizes 9 distinct log formats into a unified schema: half-hour
|
|
312
302
|
UTC buckets keyed by <code>(source, model, hour_start)</code>. Aggregated buckets are written to
|
|
313
303
|
<code>queue.jsonl</code> and served from a local HTTP API on port 7680. The React dashboard reads
|
|
314
|
-
from those endpoints
|
|
315
|
-
leaderboard.
|
|
304
|
+
from those endpoints. Nothing is uploaded anywhere.
|
|
316
305
|
</p>
|
|
317
306
|
|
|
318
307
|
<h2>Frequently asked questions</h2>
|
|
@@ -332,12 +321,11 @@
|
|
|
332
321
|
<p>Input, output, cached, and cache-creation tokens per model, project, and time window. It also surfaces rate limits and subscription status for Claude Pro, ChatGPT plans, Cursor, Gemini, Kiro, and Antigravity.</p>
|
|
333
322
|
|
|
334
323
|
<h3>Does Token Tracker work offline?</h3>
|
|
335
|
-
<p>Yes. Token Tracker is local-
|
|
324
|
+
<p>Yes. Token Tracker is local-only. All parsing, aggregation, and dashboard rendering happen on your machine, and nothing is uploaded.</p>
|
|
336
325
|
|
|
337
326
|
<h2>Resources</h2>
|
|
338
327
|
<ul>
|
|
339
328
|
<li><a href="https://www.tokentracker.cc/">Homepage and install instructions</a></li>
|
|
340
|
-
<li><a href="https://www.tokentracker.cc/leaderboard">Public token usage leaderboard</a></li>
|
|
341
329
|
<li><a href="https://www.tokentracker.cc/ip-check">Claude IP region checker</a></li>
|
|
342
330
|
<li><a href="https://www.npmjs.com/package/tokentracker-cli">npm: tokentracker-cli</a></li>
|
|
343
331
|
<li><a href="https://github.com/mm7894215/TokenTracker">GitHub: mm7894215/TokenTracker</a></li>
|
package/dashboard/dist/llms.txt
CHANGED
|
@@ -9,7 +9,6 @@ Kiro, Hermes Agent, GitHub Copilot, Kimi Code, oh-my-pi (omp), and CodeBuddy.
|
|
|
9
9
|
|
|
10
10
|
## Priority URLs
|
|
11
11
|
- [Homepage](https://www.tokentracker.cc/)
|
|
12
|
-
- [Leaderboard](https://www.tokentracker.cc/leaderboard)
|
|
13
12
|
- [Claude IP check](https://www.tokentracker.cc/ip-check)
|
|
14
13
|
|
|
15
14
|
## Post-install (local) views
|
|
@@ -47,7 +46,6 @@ on the user's own machine — they are not public URLs:
|
|
|
47
46
|
- [feed.xml](https://www.tokentracker.cc/feed.xml)
|
|
48
47
|
- [robots.txt](https://www.tokentracker.cc/robots.txt)
|
|
49
48
|
- Data principle: token counts only, never prompts or conversation content.
|
|
50
|
-
- Local-first: all parsing, aggregation, and dashboard rendering happen on-device. Cloud sync is optional.
|
|
51
49
|
|
|
52
50
|
## Contact
|
|
53
51
|
- [GitHub issues](https://github.com/mm7894215/TokenTracker/issues)
|
|
@@ -6,22 +6,10 @@
|
|
|
6
6
|
<changefreq>weekly</changefreq>
|
|
7
7
|
<priority>1.0</priority>
|
|
8
8
|
</url>
|
|
9
|
-
<url>
|
|
10
|
-
<loc>https://www.tokentracker.cc/leaderboard</loc>
|
|
11
|
-
<lastmod>2026-05-07</lastmod>
|
|
12
|
-
<changefreq>daily</changefreq>
|
|
13
|
-
<priority>0.9</priority>
|
|
14
|
-
</url>
|
|
15
9
|
<url>
|
|
16
10
|
<loc>https://www.tokentracker.cc/ip-check</loc>
|
|
17
11
|
<lastmod>2026-05-07</lastmod>
|
|
18
12
|
<changefreq>monthly</changefreq>
|
|
19
13
|
<priority>0.5</priority>
|
|
20
14
|
</url>
|
|
21
|
-
<url>
|
|
22
|
-
<loc>https://www.tokentracker.cc/share</loc>
|
|
23
|
-
<lastmod>2026-05-07</lastmod>
|
|
24
|
-
<changefreq>weekly</changefreq>
|
|
25
|
-
<priority>0.4</priority>
|
|
26
|
-
</url>
|
|
27
15
|
</urlset>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ipv9/tokentracker-cli",
|
|
3
|
-
"version": "0.39.
|
|
3
|
+
"version": "0.39.39",
|
|
4
4
|
"description": "Local-first token and cost dashboard for 22 AI coding tools, including Claude Code, Codex, Cursor, Gemini, Kiro, OpenCode, OpenClaw, Copilot, Antigravity, Zed, and Goose.",
|
|
5
5
|
"main": "src/cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -23,13 +23,17 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
|
-
"ci:local": "npm run dashboard:build && npm test && npm run validate:copy && npm run validate:ui-hardcode && npm run validate:guardrails && node --test test/architecture-guardrails.test.js",
|
|
26
|
+
"ci:local": "npm run dashboard:build && npm --prefix dashboard run test && npm test && npm run validate:copy && npm run validate:ui-hardcode && npm run validate:guardrails && npm run docs:openwiki:check && node --test test/architecture-guardrails.test.js",
|
|
27
27
|
"copy:pull": "node scripts/copy-sync.cjs pull",
|
|
28
28
|
"copy:push": "node scripts/copy-sync.cjs push",
|
|
29
29
|
"dashboard:build": "npm --prefix dashboard run build",
|
|
30
30
|
"dashboard:dev": "npm --prefix dashboard run dev",
|
|
31
31
|
"dashboard:open": "bash scripts/open-dashboard.sh",
|
|
32
32
|
"dashboard:preview": "npm --prefix dashboard run preview",
|
|
33
|
+
"docs:openwiki:check": "node scripts/openwiki-check-facts.cjs",
|
|
34
|
+
"docs:openwiki:extract": "node scripts/openwiki-extract-facts.cjs",
|
|
35
|
+
"docs:openwiki:update": "bash scripts/docs-update.sh",
|
|
36
|
+
"docs:openwiki:verify": "bash scripts/openwiki-verify.sh",
|
|
33
37
|
"dev:shim": "node scripts/dev-bin-shim.cjs",
|
|
34
38
|
"audit:tokens": "node scripts/audit-token-correctness.cjs",
|
|
35
39
|
"graph:auto-index": "node scripts/graph/auto-index.cjs",
|
|
@@ -76,8 +80,7 @@
|
|
|
76
80
|
"zed",
|
|
77
81
|
"goose",
|
|
78
82
|
"local-first",
|
|
79
|
-
"rate-limits"
|
|
80
|
-
"leaderboard"
|
|
83
|
+
"rate-limits"
|
|
81
84
|
],
|
|
82
85
|
"license": "MIT",
|
|
83
86
|
"engines": {
|
package/src/cli.js
CHANGED
|
@@ -5,7 +5,6 @@ const { cmdDiagnostics } = require("./commands/diagnostics");
|
|
|
5
5
|
const { cmdDoctor } = require("./commands/doctor");
|
|
6
6
|
const { cmdUninstall } = require("./commands/uninstall");
|
|
7
7
|
const { cmdServe } = require("./commands/serve");
|
|
8
|
-
const { cmdDeviceLogin } = require("./commands/device-login");
|
|
9
8
|
const { cmdWrapped } = require("./commands/wrapped");
|
|
10
9
|
|
|
11
10
|
async function run(argv) {
|
|
@@ -44,9 +43,6 @@ async function run(argv) {
|
|
|
44
43
|
case "uninstall":
|
|
45
44
|
await cmdUninstall(rest);
|
|
46
45
|
return;
|
|
47
|
-
case "device-login":
|
|
48
|
-
await cmdDeviceLogin(rest);
|
|
49
|
-
return;
|
|
50
46
|
case "wrapped":
|
|
51
47
|
await cmdWrapped(rest);
|
|
52
48
|
return;
|
|
@@ -64,29 +60,24 @@ function printHelp() {
|
|
|
64
60
|
"Usage:",
|
|
65
61
|
" npx --yes @ipv9/tokentracker-cli Start local dashboard",
|
|
66
62
|
" npx --yes @ipv9/tokentracker-cli [--debug] serve [--port 7680] [--open] [--no-open] [--sync]",
|
|
67
|
-
" npx --yes @ipv9/tokentracker-cli [--debug] init [--yes] [--dry-run] [--no-open]
|
|
63
|
+
" npx --yes @ipv9/tokentracker-cli [--debug] init [--yes] [--dry-run] [--no-open]",
|
|
68
64
|
" npx --yes @ipv9/tokentracker-cli [--debug] sync [--auto] [--drain] [--from-openclaw]",
|
|
69
65
|
" npx --yes @ipv9/tokentracker-cli [--debug] status [--probe-keychain] [--probe-keychain-details]",
|
|
70
66
|
" npx --yes @ipv9/tokentracker-cli [--debug] diagnostics [--out diagnostics.json]",
|
|
71
|
-
" npx --yes @ipv9/tokentracker-cli [--debug] doctor [--json] [--out doctor.json]
|
|
67
|
+
" npx --yes @ipv9/tokentracker-cli [--debug] doctor [--json] [--out doctor.json]",
|
|
72
68
|
" npx --yes @ipv9/tokentracker-cli [--debug] uninstall [--purge]",
|
|
73
|
-
" npx --yes @ipv9/tokentracker-cli [--debug] device-login [--json] [--base-url <url>]",
|
|
74
69
|
" npx --yes @ipv9/tokentracker-cli [--debug] wrapped [--year 2026] [--json]",
|
|
75
70
|
"",
|
|
76
71
|
"Notes:",
|
|
77
|
-
" - init: consent first, local setup
|
|
72
|
+
" - init: consent first, then local setup. This build is local-only.",
|
|
78
73
|
" - --yes skips the consent menu (non-interactive safe).",
|
|
79
74
|
" - --dry-run previews changes without writing files.",
|
|
80
|
-
" - optional: --link-code <code> skips browser login when provided by Dashboard.",
|
|
81
75
|
" - Every Code notify installs when ~/.code/config.toml exists.",
|
|
82
76
|
" - OpenClaw hook auto-links when OpenClaw is installed (requires gateway restart).",
|
|
83
|
-
" - auto sync waits for a device token.",
|
|
84
|
-
" - optional: --dashboard-url for hosted landing.",
|
|
85
77
|
" - serve prints the local dashboard URL; pass --open to ask the OS to open a browser.",
|
|
86
|
-
" - sync parses ~/.codex/sessions/**/rollout-*.jsonl and ~/.code/sessions/**/rollout-*.jsonl
|
|
78
|
+
" - sync parses ~/.codex/sessions/**/rollout-*.jsonl and ~/.code/sessions/**/rollout-*.jsonl into the local queue. Nothing is uploaded.",
|
|
87
79
|
" - --from-openclaw marks sync runs triggered by OpenClaw hooks.",
|
|
88
80
|
" - --debug shows original backend errors.",
|
|
89
|
-
" - device-login pairs a headless CLI / SSH session with a browser sign-in (15-min code).",
|
|
90
81
|
"",
|
|
91
82
|
].join("\n"),
|
|
92
83
|
);
|
package/src/commands/doctor.js
CHANGED
|
@@ -17,7 +17,6 @@ async function cmdDoctor(argv = []) {
|
|
|
17
17
|
const config =
|
|
18
18
|
configStatus.status === "ok" && isPlainObject(configStatus.value) ? configStatus.value : {};
|
|
19
19
|
const runtime = resolveRuntimeConfig({
|
|
20
|
-
cli: { baseUrl: opts.baseUrl },
|
|
21
20
|
config,
|
|
22
21
|
env: process.env,
|
|
23
22
|
});
|
|
@@ -62,12 +61,11 @@ async function cmdDoctor(argv = []) {
|
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
function parseArgs(argv) {
|
|
65
|
-
const out = { json: false, out: null
|
|
64
|
+
const out = { json: false, out: null };
|
|
66
65
|
for (let i = 0; i < argv.length; i += 1) {
|
|
67
66
|
const arg = argv[i];
|
|
68
67
|
if (arg === "--json") out.json = true;
|
|
69
68
|
else if (arg === "--out") out.out = argv[++i] || null;
|
|
70
|
-
else if (arg === "--base-url") out.baseUrl = argv[++i] || null;
|
|
71
69
|
else throw new Error(`Unknown option: ${arg}`);
|
|
72
70
|
}
|
|
73
71
|
return out;
|
package/src/commands/init.js
CHANGED
|
@@ -57,7 +57,6 @@ const {
|
|
|
57
57
|
resolvePiAgentDir,
|
|
58
58
|
piAgentDirCollidesWithOmp,
|
|
59
59
|
} = require("../lib/rollout");
|
|
60
|
-
const { resolveRuntimeConfig, DEFAULT_BASE_URL } = require("../lib/runtime-config");
|
|
61
60
|
const {
|
|
62
61
|
BOLD,
|
|
63
62
|
DIM,
|
|
@@ -86,7 +85,6 @@ const ASCII_LOGO = [
|
|
|
86
85
|
].join("\n");
|
|
87
86
|
|
|
88
87
|
const DIVIDER = "----------------------------------------------";
|
|
89
|
-
const DEFAULT_DASHBOARD_URL = "https://www.tokentracker.cc";
|
|
90
88
|
|
|
91
89
|
// Single source of truth for the welcome screen's provider count + sample list.
|
|
92
90
|
// Keep in sync with the supported-tools table in CLAUDE.md.
|
|
@@ -120,11 +118,6 @@ async function cmdInit(argv) {
|
|
|
120
118
|
const linkCodeStatePath = path.join(trackerDir, "link_code_state.json");
|
|
121
119
|
|
|
122
120
|
const existingConfig = await readJson(configPath);
|
|
123
|
-
const runtime = resolveRuntimeConfig({
|
|
124
|
-
cli: { baseUrl: opts.baseUrl, dashboardUrl: opts.dashboardUrl },
|
|
125
|
-
config: existingConfig || {},
|
|
126
|
-
env: process.env,
|
|
127
|
-
});
|
|
128
121
|
const notifyPath = path.join(binDir, "notify.cjs");
|
|
129
122
|
const appDir = path.join(trackerDir, "app");
|
|
130
123
|
const trackerBinPath = path.join(appDir, "bin", "tracker.js");
|
|
@@ -156,7 +149,6 @@ async function cmdInit(argv) {
|
|
|
156
149
|
home,
|
|
157
150
|
trackerDir,
|
|
158
151
|
notifyPath,
|
|
159
|
-
runtime,
|
|
160
152
|
});
|
|
161
153
|
renderLocalReport({ summary: preview.summary, isDryRun: true });
|
|
162
154
|
renderAccountNotLinked({ context: "dry-run" });
|
|
@@ -178,7 +170,6 @@ async function cmdInit(argv) {
|
|
|
178
170
|
notifyPath,
|
|
179
171
|
appDir,
|
|
180
172
|
trackerBinPath,
|
|
181
|
-
runtime,
|
|
182
173
|
existingConfig,
|
|
183
174
|
});
|
|
184
175
|
} catch (err) {
|
|
@@ -280,20 +271,10 @@ function renderAccountNotLinked({ context } = {}) {
|
|
|
280
271
|
renderLocalSuccess();
|
|
281
272
|
}
|
|
282
273
|
|
|
283
|
-
function
|
|
284
|
-
if (deviceToken) return false;
|
|
285
|
-
if (opts.noAuth) return false;
|
|
286
|
-
if (opts.linkCode) return false;
|
|
287
|
-
if (opts.email || opts.password) return false;
|
|
288
|
-
return true;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
async function buildDryRunSummary({ opts, home, trackerDir, notifyPath, runtime }) {
|
|
292
|
-
const deviceToken = runtime?.deviceToken || null;
|
|
293
|
-
const pendingBrowserAuth = shouldUseBrowserAuth({ deviceToken, opts });
|
|
274
|
+
async function buildDryRunSummary({ opts, home, trackerDir, notifyPath }) {
|
|
294
275
|
const context = buildIntegrationTargets({ home, trackerDir, notifyPath });
|
|
295
276
|
const summary = await previewIntegrations({ context });
|
|
296
|
-
return { summary
|
|
277
|
+
return { summary };
|
|
297
278
|
}
|
|
298
279
|
|
|
299
280
|
async function runSetup({
|
|
@@ -307,15 +288,12 @@ async function runSetup({
|
|
|
307
288
|
notifyPath,
|
|
308
289
|
appDir,
|
|
309
290
|
trackerBinPath,
|
|
310
|
-
runtime,
|
|
311
291
|
existingConfig,
|
|
312
292
|
}) {
|
|
313
293
|
await ensureDir(trackerDir);
|
|
314
294
|
await ensureDir(binDir);
|
|
315
|
-
let deviceToken = runtime?.deviceToken || null;
|
|
316
295
|
let deviceId = existingConfig?.deviceId || null;
|
|
317
296
|
const installedAt = existingConfig?.installedAt || new Date().toISOString();
|
|
318
|
-
let pendingBrowserAuth = false;
|
|
319
297
|
|
|
320
298
|
await installLocalTrackerApp({ appDir });
|
|
321
299
|
|
|
@@ -323,13 +301,33 @@ async function runSetup({
|
|
|
323
301
|
existingConfig && typeof existingConfig === "object" && !Array.isArray(existingConfig)
|
|
324
302
|
? existingConfig
|
|
325
303
|
: {};
|
|
304
|
+
// Scrub cloud credentials and endpoints on upgrade. Spreading the previous
|
|
305
|
+
// config forward kept a live InsForge bearer token in config.json, and this
|
|
306
|
+
// branch also removed the `status` / `diagnostics` lines that used to reveal
|
|
307
|
+
// it — so the user is told "local-only, nothing is uploaded" while a valid
|
|
308
|
+
// credential sits on disk with nothing left to report or rotate it.
|
|
309
|
+
const {
|
|
310
|
+
deviceToken: _removedDeviceToken,
|
|
311
|
+
baseUrl: _removedBaseUrl,
|
|
312
|
+
dashboardUrl: _removedDashboardUrl,
|
|
313
|
+
...carriedConfig
|
|
314
|
+
} = existingPlainConfig;
|
|
326
315
|
const config = {
|
|
327
|
-
...
|
|
316
|
+
...carriedConfig,
|
|
328
317
|
installedAt,
|
|
329
|
-
baseUrl: opts.baseUrl || existingPlainConfig.baseUrl || DEFAULT_BASE_URL,
|
|
330
318
|
};
|
|
331
|
-
|
|
332
|
-
|
|
319
|
+
|
|
320
|
+
// Files written by the removed cloud paths. The only code that ever deleted
|
|
321
|
+
// relay-cookies.json was clearRelayCookies(), which went with the auth proxy,
|
|
322
|
+
// so an upgrading machine would otherwise keep a refresh token forever.
|
|
323
|
+
for (const stale of ["relay-cookies.json", "upload.throttle.json", "auto.retry.json"]) {
|
|
324
|
+
try {
|
|
325
|
+
await fs.unlink(path.join(trackerDir, stale));
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (error?.code !== "ENOENT") {
|
|
328
|
+
process.stderr.write(`[tokentracker] could not remove ${stale}: ${error.message}\n`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
333
331
|
}
|
|
334
332
|
|
|
335
333
|
await writeJson(configPath, config);
|
|
@@ -350,8 +348,6 @@ async function runSetup({
|
|
|
350
348
|
|
|
351
349
|
return {
|
|
352
350
|
summary,
|
|
353
|
-
pendingBrowserAuth,
|
|
354
|
-
deviceToken,
|
|
355
351
|
deviceId,
|
|
356
352
|
installedAt,
|
|
357
353
|
};
|
|
@@ -803,8 +799,6 @@ function arraysEqual(a, b) {
|
|
|
803
799
|
|
|
804
800
|
function parseArgs(argv) {
|
|
805
801
|
const out = {
|
|
806
|
-
baseUrl: null,
|
|
807
|
-
dashboardUrl: null,
|
|
808
802
|
email: null,
|
|
809
803
|
password: null,
|
|
810
804
|
deviceName: null,
|
|
@@ -817,13 +811,33 @@ function parseArgs(argv) {
|
|
|
817
811
|
|
|
818
812
|
for (let i = 0; i < argv.length; i++) {
|
|
819
813
|
const a = argv[i];
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
814
|
+
// Cloud sign-in flags (--email/--password/--device-name/--link-code/
|
|
815
|
+
// --no-auth) are gone: there is no account to sign into. Accept and
|
|
816
|
+
// ignore --no-auth so existing scripts and hooks do not start failing
|
|
817
|
+
// with "Unknown option"; the others were only ever used with it.
|
|
818
|
+
if (a === "--no-auth") {
|
|
819
|
+
// Accepted and ignored: it was the "skip sign-in" opt-out, and there is
|
|
820
|
+
// no sign-in left to skip. Silently tolerated so existing hooks and
|
|
821
|
+
// scripts do not start failing with "Unknown option".
|
|
822
|
+
out.noAuth = true;
|
|
823
|
+
} else if (a === "--email" || a === "--password" || a === "--device-name") {
|
|
824
|
+
i += 1;
|
|
825
|
+
} else if (
|
|
826
|
+
a.startsWith("--email=") ||
|
|
827
|
+
a.startsWith("--password=") ||
|
|
828
|
+
a.startsWith("--device-name=")
|
|
829
|
+
) {
|
|
830
|
+
// Swallow the `=` form too. Falling through raised
|
|
831
|
+
// `Unknown option: --password=hunter2`, and bin/tracker.js prints the
|
|
832
|
+
// stack — putting the secret on stderr and into any captured log.
|
|
833
|
+
} else if (a === "--link-code" || a.startsWith("--link-code=")) {
|
|
834
|
+
// Fail loudly. Unlike the others this was documented standalone, so a
|
|
835
|
+
// user pairing a device would otherwise see "Setup complete!" and
|
|
836
|
+
// believe the code was honored.
|
|
837
|
+
throw new Error(
|
|
838
|
+
"--link-code is no longer supported: TokenTracker is local-only and has no device pairing.",
|
|
839
|
+
);
|
|
840
|
+
}
|
|
827
841
|
else if (a === "--no-open") out.noOpen = true;
|
|
828
842
|
else if (a === "--yes") out.yes = true;
|
|
829
843
|
else if (a === "--dry-run") out.dryRun = true;
|
|
@@ -883,7 +897,6 @@ const codexOriginalPath = ${JSON.stringify(originalPath)};
|
|
|
883
897
|
const codeOriginalPath = ${JSON.stringify(path.join(trackerDir, "code_notify_original.json"))};
|
|
884
898
|
const trackerBinPath = ${JSON.stringify(trackerBinPath)};
|
|
885
899
|
const depsMarkerPath = path.join(trackerDir, 'app', 'bin', 'tracker.js');
|
|
886
|
-
const configPath = path.join(trackerDir, 'config.json');
|
|
887
900
|
const fallbackPkg = ${JSON.stringify(fallbackPkg)};
|
|
888
901
|
const selfPath = path.resolve(__filename);
|
|
889
902
|
const home = os.homedir();
|
|
@@ -919,20 +932,17 @@ if (debugEnabled) {
|
|
|
919
932
|
}
|
|
920
933
|
|
|
921
934
|
// Throttle spawn: at most once per 20 seconds.
|
|
935
|
+
// Parsing local logs and uploading to the cloud are two separate decisions.
|
|
936
|
+
// This hook makes only the first one. It runs whether or not a device token
|
|
937
|
+
// exists, because a local-only install still needs its queue refreshed when a
|
|
938
|
+
// session ends. Upload stays gated on a device token inside sync itself, so
|
|
939
|
+
// no credential here means local parse happens and nothing is transmitted.
|
|
922
940
|
try {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
if (cfg && typeof cfg.deviceToken === 'string') deviceToken = cfg.deviceToken;
|
|
929
|
-
} catch (_) {}
|
|
930
|
-
}
|
|
931
|
-
const canSync = Boolean(deviceToken && deviceToken.length > 0);
|
|
932
|
-
const now = Date.now();
|
|
933
|
-
let last = 0;
|
|
934
|
-
try { last = Number(fs.readFileSync(throttlePath, 'utf8')) || 0; } catch (_) {}
|
|
935
|
-
if (canSync && now - last > 20_000) {
|
|
941
|
+
const throttlePath = path.join(trackerDir, 'sync.throttle');
|
|
942
|
+
const now = Date.now();
|
|
943
|
+
let last = 0;
|
|
944
|
+
try { last = Number(fs.readFileSync(throttlePath, 'utf8')) || 0; } catch (_) {}
|
|
945
|
+
if (now - last > 20_000) {
|
|
936
946
|
try { fs.writeFileSync(throttlePath, String(now), 'utf8'); } catch (_) {}
|
|
937
947
|
const hasLocalRuntime = fs.existsSync(trackerBinPath);
|
|
938
948
|
const hasLocalDeps = fs.existsSync(depsMarkerPath);
|