@juejin-opensource/jusage 0.1.3 → 0.1.6-beta.0

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.
@@ -0,0 +1,16 @@
1
+ import{c as F,r as u,j as e,M as R,B as S,A as ne,C as ce,Q as de,a as ue,b as me,e as _e,f as X,g as P,h as L,i as fe,T as A,P as B,k as C,u as Y,l as he,m as pe,D as G,n as xe,S as we,d as be,o as ge}from"./index-DpG68XJd.js";import{C as U,T,a as ke,S as M,i as ve}from"./env-Bahc-RuR.js";import{S as b,a as v,L as Z,b as y}from"./index-C28OANM4.js";import{L as ye,G as W}from"./downloads-DRt36RTZ.js";/**
2
+ * @license lucide-react v1.24.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const je=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8",key:"1h4pet"}],["path",{d:"M12 18V6",key:"zqpxq5"}]],Ne=F("circle-dollar-sign",je);/**
7
+ * @license lucide-react v1.24.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const Se=[["path",{d:"M13.744 17.736a6 6 0 1 1-7.48-7.48",key:"bq4yh3"}],["path",{d:"M15 6h1v4",key:"11y1tn"}],["path",{d:"m6.134 14.768.866-.5 2 3.464",key:"17snzx"}],["circle",{cx:"16",cy:"8",r:"6",key:"14bfc9"}]],Le=F("coins",Se);/**
12
+ * @license lucide-react v1.24.0 - ISC
13
+ *
14
+ * This source code is licensed under the ISC license.
15
+ * See the LICENSE file in the root directory of this source tree.
16
+ */const Ce=[["circle",{cx:"18",cy:"5",r:"3",key:"gq8acd"}],["circle",{cx:"6",cy:"12",r:"3",key:"w7nqdw"}],["circle",{cx:"18",cy:"19",r:"3",key:"1xt0gg"}],["line",{x1:"8.59",x2:"15.42",y1:"13.51",y2:"17.49",key:"47mynk"}],["line",{x1:"15.41",x2:"8.59",y1:"6.51",y2:"10.49",key:"1n3mei"}]],Ie=F("share-2",Ce);function Re(t,a=""){const s=new Set,o=[];for(const r of t)a&&r.tool!==a||!r.model||s.has(r.model)||(s.add(r.model),o.push(r));return o}function ee(t){return t==null||!Number.isFinite(t)||t<1?"—":t>99?"> 99":String(Math.floor(t))}const Ae="https://juejin.cn/aiusage/rank",te=5;function Te({board:t,loading:a,metric:s,modelLabel:o,onOpenChange:r,open:i,profiles:l,toolLabel:h}){const p=(t==null?void 0:t.currentUser)??null,m=u.useRef(null),[c,d]=u.useState(null),[n,x]=u.useState(null);u.useEffect(()=>{i&&(d(null),x(null))},[i]);const f=w=>c===w?w==="download"?"生成中…":"复制中…":(n==null?void 0:n.action)===w?n.state==="success"?w==="download"?"已下载":"已复制":w==="download"?"下载失败":"复制失败":w==="download"?"下载到本地":"复制分享图",g=(w,I)=>{d(null),x({action:w,state:I})},j=()=>m.current?fe(m.current):Promise.reject(new Error("分享海报尚未准备完成")),_=async()=>{if(!(c||a)){d("download"),x(null);try{me(await j()),g("download","success")}catch(w){console.error("[rank-share] download failed",w),g("download","error")}}},O=async()=>{if(!(c||a)){d("copy"),x(null);try{await _e(j()),g("copy","success")}catch(w){console.error("[rank-share] clipboard write failed",w),g("copy","error")}}};return e.jsx(R,{children:e.jsx(R.Backdrop,{isOpen:i,onOpenChange:r,variant:"blur",children:e.jsx(R.Container,{className:"px-3 py-8 sm:px-4",scroll:"inside",size:"sm",children:e.jsx(R.Dialog,{"aria-label":"分享排行榜",className:"!w-full !max-w-[420px] !overflow-visible !border-0 !bg-transparent !p-0 !shadow-none",children:e.jsxs(R.Body,{className:"space-y-3 p-0",children:[e.jsxs("section",{"aria-label":`${s==="tokens"?"Token":"消费"} 排行榜分享预览`,className:"relative isolate overflow-hidden rounded-[22px] border border-white/85 bg-[#edf7ff] px-4 pb-4 pt-5 text-[#18283a] shadow-[0_18px_36px_rgb(56_121_188_/0.18)] dark:border-white/10 dark:bg-[#0d1b2d] dark:text-[#eaf4ff] dark:shadow-[0_18px_36px_rgb(0_0_0_/0.38)] sm:px-5 sm:pb-5 sm:pt-6",ref:m,children:[e.jsx(De,{}),e.jsxs("div",{className:"relative z-10",children:[e.jsxs("header",{className:"flex items-start justify-between gap-3",children:[e.jsxs("h2",{className:"inline-flex whitespace-nowrap pt-0.5 text-[28px] font-black italic leading-none tracking-[-0.055em] text-[#14243a] dark:text-[#f1f8ff] sm:text-[32px]",children:[e.jsx("span",{children:"Token"}),e.jsx("span",{className:"ml-2",children:"排行榜"})]}),e.jsx("div",{"aria-label":"排行榜指标",className:"-mr-1.5 -mt-1 shrink-0",children:e.jsx(Pe,{children:s==="tokens"?"按 Token":"按消费"})})]}),e.jsxs("section",{className:"mt-5","aria-label":"排行榜",children:[e.jsxs("div",{className:"flex flex-wrap gap-1.5 text-[10px] font-medium text-[#5c7d9c] dark:text-[#a8c1da]",children:[e.jsx("span",{className:"max-w-32 truncate rounded-full border border-white/80 bg-white/[0.5] px-2 py-1 shadow-[inset_0_1px_0_rgb(255_255_255_/0.9)] backdrop-blur-sm dark:border-white/10 dark:bg-white/[0.08] dark:shadow-none",children:h}),e.jsx("span",{className:"max-w-44 truncate rounded-full border border-white/80 bg-white/[0.5] px-2 py-1 shadow-[inset_0_1px_0_rgb(255_255_255_/0.9)] backdrop-blur-sm dark:border-white/10 dark:bg-white/[0.08] dark:shadow-none",children:o})]}),a?e.jsx(Ue,{}):e.jsx(Me,{currentUser:p,profiles:l,rows:(t==null?void 0:t.rows)??[]})]}),e.jsx(Ee,{})]})]}),e.jsxs("div",{className:"flex items-center justify-center gap-2 pb-1",children:[e.jsxs(S,{isDisabled:a||c==="copy",isPending:c==="download",onPress:()=>void _(),size:"sm",children:[e.jsx(ne,{className:"size-3.5"}),f("download")]}),e.jsxs(S,{isDisabled:a||c==="download",isPending:c==="copy",onPress:()=>void O(),size:"sm",variant:"tertiary",children:[e.jsx(ce,{className:"size-3.5"}),f("copy")]}),e.jsx(S,{size:"sm",slot:"close",variant:"tertiary",children:"关闭"})]})]})})})})})}function Me({currentUser:t,profiles:a,rows:s}){const o=s.slice(0,te),r=t?o.some(i=>q(i,t)):!1;return e.jsxs("div",{className:"mt-5","aria-label":"排行榜列表",children:[o.length>0?e.jsx("ol",{className:"space-y-1.5",children:o.map(i=>e.jsx(K,{isCurrentUser:!!(t&&q(i,t)),profiles:a,row:i},`${i.userHash}-${i.rank}`))}):e.jsx("p",{className:"mt-3 px-2 text-[11px] text-[#7892ac] dark:text-[#9bb7d2]",children:"暂无排行榜数据"}),t&&!r?e.jsxs(e.Fragment,{children:[o.length>0&&e.jsx("div",{"aria-hidden":!0,className:"py-2 text-center text-sm font-black tracking-[0.3em] text-[#7892ac] dark:text-[#9bb7d2]",children:"· · ·"}),e.jsx("ol",{className:"my-1.5 py-1.5",children:e.jsx(K,{isCurrentUser:!0,profiles:a,row:t})})]}):null,!t&&e.jsxs("div",{className:"mt-4 flex items-center justify-between rounded-xl border border-dashed border-[#b9d8ff] bg-white/[0.32] px-3 py-2.5 text-[11px] dark:border-white/15 dark:bg-white/[0.05]",children:[e.jsx("span",{className:"font-semibold text-[#5c7d9c] dark:text-[#a8c1da]",children:"我的排名"}),e.jsx("span",{className:"font-bold text-[#334e69] dark:text-[#f1f8ff]",children:"99+名"})]})]})}function K({isCurrentUser:t,profiles:a,row:s}){const o=Fe(s,a),r=X(s.totalTokens??s.tokens),i=P(s.costUsd),l=ee(s.rank);return e.jsxs("li",{className:t?"relative mx-5 my-4 origin-center scale-110 py-1.5":"relative","data-current-user":t?"true":void 0,children:[t&&e.jsxs("p",{className:"mb-3 text-[10px] font-semibold tracking-[0.04em] text-[#1e80ff] dark:text-[#79b7ff]",children:["@",o.displayName," · 排名"]}),e.jsxs("div",{className:`grid grid-cols-[2.5rem_minmax(0,1fr)_auto] items-center gap-1 rounded-xl px-2 py-2.5 ${t?"border border-[#8ec0ff]/80 bg-[#dcedff]/90 shadow-[0_8px_18px_rgb(30_128_255_/0.16),inset_0_1px_0_rgb(255_255_255_/0.9)] dark:border-[#4b91d1] dark:bg-[#173b5f]/90 dark:shadow-[0_8px_18px_rgb(0_0_0_/0.25)]":"border border-white/55 bg-white/[0.38] shadow-[inset_0_1px_0_rgb(255_255_255_/0.72)] dark:border-white/[0.07] dark:bg-white/[0.045] dark:shadow-none"}`,children:[e.jsx("span",{className:`text-center text-[17px] font-black leading-none tabular-nums ${t?"text-[#1e80ff] dark:text-[#79b7ff]":ze(s.rank)}`,children:l==="—"?"未上榜":`#${l}`}),e.jsxs("div",{className:"flex min-w-0 items-center gap-2",children:[e.jsxs(L,{className:"size-7 shrink-0 border border-white/80 shadow-sm dark:border-white/15",size:"sm",children:[o.avatarUrl?e.jsx(L.Image,{alt:"",loading:"eager",src:o.avatarUrl}):null,e.jsx(L.Fallback,{color:"accent",delayMs:0,children:o.displayName.slice(0,1).toUpperCase()||"J"})]}),e.jsx("span",{className:"min-w-0 truncate text-[12px] font-semibold text-[#294560] dark:text-[#dceeff]",children:o.displayName})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-3 text-right text-[10px] font-bold tabular-nums",children:[e.jsxs("span",{className:"inline-flex w-auto shrink-0 items-center gap-1 whitespace-nowrap rounded-full border border-[#b9d8ff]/85 bg-[#e4f1ff]/80 px-2 py-1 text-[#1e80ff] shadow-[inset_0_1px_0_rgb(255_255_255_/0.82)] dark:border-[#356796] dark:bg-[#193755]/80 dark:text-[#79b7ff] dark:shadow-none",title:`Token:${r}`,children:[e.jsx(Le,{"aria-hidden":!0,className:"size-3 shrink-0"}),e.jsx("span",{children:r})]}),e.jsxs("span",{className:"inline-flex w-auto shrink-0 items-center gap-1 whitespace-nowrap rounded-full border border-[#a8d9ba]/85 bg-[#e6f8ec]/80 px-2 py-1 text-[#22a05a] shadow-[inset_0_1px_0_rgb(255_255_255_/0.82)] dark:border-[#377b55] dark:bg-[#153d29]/80 dark:text-[#63d98a] dark:shadow-none",title:`消费:${i}`,children:[e.jsx(Ne,{"aria-hidden":!0,className:"size-3 shrink-0"}),e.jsx("span",{children:i})]})]})]})]})}function q(t,a){return t.userHash===a.userHash||!!t.uid&&t.uid===a.uid||t.isCurrentUser&&a.isCurrentUser}function ze(t){return t===1?"text-[#f26b42] dark:text-[#ff9b74]":t===2?"text-[#e39a3a] dark:text-[#ffc36b]":t===3?"text-[#8f79d8] dark:text-[#b9a7ff]":"text-[#5c7d9c] dark:text-[#a8c1da]"}function Ue(){return e.jsxs("div",{className:"mt-5","aria-label":"排行榜加载中",children:[e.jsx("div",{className:"space-y-1.5",children:Array.from({length:te},(t,a)=>e.jsxs("div",{className:"grid grid-cols-[2.5rem_minmax(0,1fr)_auto] items-center gap-1 rounded-xl border border-white/55 bg-white/[0.38] px-2 py-2.5 dark:border-white/[0.07] dark:bg-white/[0.045]",children:[e.jsx(b,{className:"mx-auto h-5 w-7 rounded"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{className:"size-7 rounded-full"}),e.jsx(b,{className:"h-3 w-24 rounded"})]}),e.jsxs("div",{className:"ml-auto flex items-center gap-3",children:[e.jsx(b,{className:"h-6 w-16 rounded-full"}),e.jsx(b,{className:"h-6 w-14 rounded-full"})]})]},a))}),e.jsxs("div",{className:"my-4 py-1.5",children:[e.jsx(b,{className:"mb-1.5 ml-3 h-3 w-24 rounded"}),e.jsx(b,{className:"h-11 w-full rounded-xl"})]})]})}function Ee(){return e.jsxs("footer",{className:"mt-8 flex items-center justify-between gap-3 rounded-2xl border border-white/75 bg-white/[0.52] px-3 py-2.5 shadow-[inset_0_1px_0_rgb(255_255_255_/0.9)] backdrop-blur-sm dark:border-white/10 dark:bg-white/[0.06] dark:shadow-none",children:[e.jsxs("div",{className:"min-w-0 pl-1",children:[e.jsx("p",{className:"text-[13px] font-semibold text-[#385775] dark:text-[#d6e8fa]",children:"扫码查看排行榜"}),e.jsx("p",{className:"mt-1 truncate text-[11px] text-[#7892ac] dark:text-[#9bb7d2]",children:"Juejin Usage · Token 排行榜"})]}),e.jsx(de,{bgColor:"#ffffff",className:"size-[58px] shrink-0 rounded-lg bg-white p-1 shadow-sm",fgColor:"#14243a",imageSettings:{excavate:!0,height:12,src:ue,width:12},level:"H",marginSize:1,size:58,title:"扫码查看 Juejin Usage 排行榜",value:Ae})]})}function Pe({children:t}){return e.jsx(U,{className:"h-6 min-h-6 border border-[#b9d8ff] bg-[#e4f1ff]/90 px-2.5 text-[#1e80ff] shadow-[inset_0_1px_0_rgb(255_255_255_/0.9),0_2px_8px_rgb(56_121_188_/0.08)] backdrop-blur-md dark:border-[#356796] dark:bg-[#193755]/90 dark:text-[#79b7ff] dark:shadow-none",size:"sm",variant:"secondary",children:e.jsx(U.Label,{className:"text-[10px] font-semibold leading-none",children:t})})}function De(){return e.jsxs("div",{"aria-hidden":!0,className:"pointer-events-none absolute inset-0 overflow-hidden",children:[e.jsx("div",{className:"absolute -right-16 -top-20 size-72 rounded-full bg-[#cfe8ff]/75 blur-3xl dark:bg-[#1e80ff]/20"}),e.jsx("div",{className:"absolute right-12 top-5 size-24 rounded-full bg-white/70 blur-2xl dark:bg-[#4b9cff]/15"}),e.jsx("div",{className:"absolute -left-12 bottom-24 size-40 rounded-full bg-[#dbeeff]/80 blur-3xl dark:bg-[#347ff0]/15"}),e.jsx("span",{className:"absolute right-9 top-12 size-2.5 rounded-full bg-[#7eb6ff]/75"}),e.jsx("span",{className:"absolute right-28 top-20 size-1.5 rounded-full bg-[#5aa2ff]/60"}),e.jsx("span",{className:"absolute right-5 top-40 size-2 rounded-full border-2 border-[#8ec0ff]/80"}),e.jsxs("svg",{className:"absolute -right-1 top-9 h-32 w-24 rotate-[16deg] opacity-60 dark:opacity-15",fill:"none",viewBox:"0 0 112 148",children:[e.jsx("rect",{fill:"#f5f9ff",height:"132",rx:"14",stroke:"#c5dcff",strokeWidth:"2",width:"96",x:"8",y:"8"}),e.jsx("path",{d:"M28 40H84M28 56H72M28 72H78M28 88H64",stroke:"#c5dcff",strokeLinecap:"round",strokeWidth:"6"})]}),e.jsxs("svg",{className:"absolute right-6 top-20 h-36 w-28 rotate-[7deg] opacity-70 drop-shadow-[0_10px_18px_rgb(30_128_255_/0.12)] dark:opacity-25",fill:"none",viewBox:"0 0 128 168",children:[e.jsx("rect",{fill:"#eef6ff",height:"148",rx:"16",stroke:"#7eb6ff",strokeWidth:"2.5",width:"108",x:"10",y:"10"}),e.jsx("path",{d:"M34 46H94M34 66H82M34 86H88M34 106H70",stroke:"#8ec0ff",strokeLinecap:"round",strokeWidth:"7"})]}),e.jsxs("svg",{className:"absolute -bottom-4 -right-2 size-20 rotate-[14deg] opacity-65 dark:opacity-25",fill:"none",viewBox:"0 0 64 64",children:[e.jsx("path",{d:"M20 14h24v12c0 8-5.5 14-12 14s-12-6-12-14V14z",fill:"#e8f3ff",stroke:"#7eb6ff",strokeLinejoin:"round",strokeWidth:"2"}),e.jsx("path",{d:"M20 18H14c0 8 4 12 8 13M44 18h6c0 8-4 12-8 13",stroke:"#5aa2ff",strokeLinecap:"round",strokeWidth:"2"}),e.jsx("path",{d:"M28 40v6h8v-6M24 50h16",stroke:"#8ec0ff",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"2.5"}),e.jsx("circle",{cx:"32",cy:"24",fill:"#1e80ff",r:"3"})]})]})}function Fe(t,a){const s=t,o=s.uid??t.userHash,r=a[o];return{avatarUrl:(r==null?void 0:r.avatarUrl)??s.avatarUrl??null,displayName:(r==null?void 0:r.userName)??t.displayName}}const J=[{id:"today",label:"今天"},{id:"week",label:"本周"},{id:"month",label:"本月"},{id:"all",label:"全部"}],ae="!h-8 !min-h-8",se="w-50 !max-h-64 overflow-hidden rounded-xl bg-surface shadow-md",re="!max-h-64 overflow-y-auto!";function Oe(){const t=window.open(W,"_blank");if(t){t.opener=null;return}window.location.assign(W)}function He({loading:t,metric:a,model:s,modelOptions:o,onModelChange:r,onToolChange:i,profiles:l,board:h,tool:p,tools:m,value:c,onChange:d}){var j;const[n,x]=u.useState(!1),f=((j=m.find(_=>_.key===p))==null?void 0:j.displayName)??"全部工具",g=s||"全部模型";return e.jsxs("div",{"aria-label":"排行榜筛选",className:"mb-4 flex w-full min-w-0 items-center gap-1.5 sm:gap-2",children:[e.jsx("div",{className:"shrink-0 sm:hidden",children:e.jsx(Q,{ariaLabel:"时间范围",options:J.map(_=>({id:_.id,label:_.label})),placeholder:"时间范围",value:c,onChange:_=>d(_),allowEmpty:!1})}),e.jsx(A,{className:"hidden w-fit shrink-0 text-center sm:block",selectedKey:c,onSelectionChange:_=>d(String(_)),children:e.jsx(A.ListContainer,{children:e.jsx(A.List,{"aria-label":"时间范围",className:"w-fit *:h-6 *:w-fit *:px-3 *:text-sm *:font-normal *:data-[selected=true]:text-accent-foreground",children:J.map(_=>e.jsxs(A.Tab,{id:_.id,children:[e.jsx("span",{className:"text-xs font-normal",children:_.label}),e.jsx(A.Indicator,{className:"bg-accent"})]},_.id))})})}),e.jsx(Ve,{tools:m,value:p,onChange:i}),e.jsx(Q,{ariaLabel:"模型筛选",options:[...new Set(o.map(_=>_.model))].map(_=>({id:_,label:_})),placeholder:"全部模型",value:s,onChange:r}),e.jsxs("div",{className:"ml-auto flex shrink-0 items-center gap-1",children:[e.jsxs(T,{closeDelay:80,delay:100,children:[e.jsx(S,{"aria-label":"GitHub 仓库",className:"size-8 min-h-8 min-w-8 shrink-0 p-0",isIconOnly:!0,onPress:Oe,size:"sm",variant:"tertiary",children:e.jsx(ye,{className:"size-4"})}),e.jsx(T.Content,{placement:"bottom",children:e.jsx("p",{children:"GitHub 仓库"})})]}),e.jsxs(T,{closeDelay:80,delay:100,children:[e.jsx(S,{"aria-label":"分享排行榜",className:"size-8 min-h-8 min-w-8 shrink-0 p-0",isIconOnly:!0,onPress:()=>x(!0),size:"sm",variant:"tertiary",children:e.jsx(Ie,{className:"size-4"})}),e.jsx(T.Content,{placement:"bottom",children:e.jsx("p",{children:"分享"})})]}),e.jsx(ke,{})]}),e.jsx(Te,{board:h,loading:t,metric:a,modelLabel:g,onOpenChange:x,open:n,profiles:l,toolLabel:f})]})}function Ve({onChange:t,tools:a,value:s}){const o=a.find(r=>r.key===s);return e.jsxs(v,{"aria-label":"工具筛选",className:"min-w-0 max-w-[7.5rem] shrink text-xs sm:max-w-52 sm:shrink-0",variant:"secondary",value:s||"all",onChange:r=>t(r==="all"||r==null?"":String(r)),children:[e.jsx(Z,{className:"sr-only",children:"工具筛选"}),e.jsxs(v.Trigger,{className:`${ae} !w-fit max-w-[7.5rem] items-center leading-none ps-2.5 pe-7 !text-xs font-normal sm:max-w-52 sm:ps-3 sm:pe-8`,children:[e.jsx(v.Value,{className:"min-w-0 max-w-20 !text-xs sm:max-w-40",children:()=>o?e.jsxs("span",{className:"flex min-w-0 items-center gap-1.5",children:[e.jsx(B,{provider:o.key,size:14}),e.jsx("span",{className:"truncate",children:o.displayName})]}):"全部工具"}),e.jsx(v.Indicator,{className:"size-3.5 text-muted"})]}),e.jsx(v.Popover,{className:se,placement:"bottom start",children:e.jsxs(y,{"aria-label":"工具筛选",className:re,children:[e.jsxs(y.Item,{id:"all",textValue:"全部工具",children:["全部工具",e.jsx(y.ItemIndicator,{})]}),a.map(r=>e.jsxs(y.Item,{className:"gap-2! rounded-lg px-1.5 py-1 text-xs",id:r.key,textValue:r.displayName,children:[e.jsx("span",{className:"flex size-5 shrink-0 items-center justify-center",children:e.jsx(B,{provider:r.key,size:14})}),e.jsx("span",{className:"min-w-0 flex-1 truncate",children:r.displayName}),e.jsx(y.ItemIndicator,{})]},r.key))]})})]})}function Q({allowEmpty:t=!0,ariaLabel:a,onChange:s,options:o,placeholder:r,value:i}){return e.jsxs(v,{"aria-label":a,className:"min-w-0 max-w-[7.5rem] shrink text-xs sm:max-w-52 sm:shrink-0",variant:"secondary",value:t?i||"all":i,onChange:l=>{if(t){s(l==="all"||l==null?"":String(l));return}l!=null&&s(String(l))},children:[e.jsx(Z,{className:"sr-only",children:a}),e.jsxs(v.Trigger,{className:`${ae} !w-fit max-w-[7.5rem] items-center leading-none ps-2.5 pe-7 !text-xs font-normal sm:max-w-52 sm:ps-3 sm:pe-8`,children:[e.jsx(v.Value,{className:"min-w-0 max-w-20 !text-xs sm:max-w-40"}),e.jsx(v.Indicator,{className:"size-3.5 text-muted"})]}),e.jsx(v.Popover,{className:se,placement:"bottom start",children:e.jsxs(y,{"aria-label":a,className:re,children:[t?e.jsxs(y.Item,{id:"all",textValue:r,children:[r,e.jsx(y.ItemIndicator,{})]}):null,o.map(l=>e.jsxs(y.Item,{id:l.id,textValue:l.label,children:[l.label,e.jsx(y.ItemIndicator,{})]},l.id))]})})]})}const $e="inline-flex h-8 max-w-full items-center rounded-full border border-white/70 bg-white/55 p-0.5 shadow-[0_1px_2px_rgb(15_60_120_/0.06)] backdrop-blur-md dark:border-white/10 dark:bg-white/[0.08] dark:shadow-none";function Be({cost:t,hideFromLeaderboard:a=!1,loading:s,metric:o,onMetricChange:r,tokens:i}){var h,p;const l=[{id:"tokens",label:"按 Token",rank:(h=i==null?void 0:i.currentUser)==null?void 0:h.rank},{id:"cost",label:"按消费",rank:(p=t==null?void 0:t.currentUser)==null?void 0:p.rank}];return e.jsx("div",{"aria-label":"排行指标",className:$e,role:"tablist",children:l.map(({id:m,label:c,rank:d})=>{const n=o===m,x=a||s?null:Ge(d);return e.jsxs("button",{"aria-label":x?`${c} ${x}`:c,"aria-selected":n,className:C("inline-flex h-full items-center gap-1 rounded-full px-2 text-xs font-medium transition-colors sm:px-2.5",n?"bg-white text-[#1e80ff] shadow-xs dark:bg-white/15 dark:text-[#4b9cff]":"text-muted hover:text-foreground dark:text-foreground/55 dark:hover:text-foreground/85"),onClick:()=>r(m),role:"tab",type:"button",children:[e.jsx("span",{children:c}),a?null:s?e.jsx(b,{"aria-label":`${c}排名加载中`,className:"h-3 w-6 rounded-sm"}):x?e.jsx("span",{className:"tabular-nums opacity-80",children:x}):null]},m)})})}function Ge(t){const a=ee(t);return a==="—"?null:`#${a}`}function We({aside:t,children:a}){const s=Math.max(0,a.length-2),o=a.slice(0,s),r=a.slice(s,s+1),i=a.slice(s+1);return e.jsxs("span",{className:"inline-flex flex-wrap items-center gap-2.5 sm:gap-3",children:[e.jsxs("span",{className:"relative inline-flex items-baseline leading-none",children:[o,e.jsxs("span",{className:"relative inline-block",children:[r,e.jsx("svg",{"aria-hidden":!0,className:"pointer-events-none absolute left-1/2 top-[calc(100%-1px)] h-2.5 w-7 -translate-x-1/2 text-[#1e80ff] sm:h-3 sm:w-9 dark:text-[#4b9cff]",fill:"none",viewBox:"0 0 36 12",children:e.jsx("path",{d:"M2 7.5C8 3.5 13 2.5 18 5C23 7.5 28 8.5 34 4.5",stroke:"currentColor",strokeLinecap:"round",strokeWidth:"2.8"})})]}),i]}),t]})}const D="overflow-hidden rounded-2xl border border-white/60 bg-white/90 shadow-[0_8px_30px_rgb(15_60_120_/0.06)] dark:border-white/8 dark:bg-surface dark:shadow-[0_8px_30px_rgb(0_0_0_/0.35)]",Ke="240px 0px";function qe({global:t,hideFromLeaderboard:a=!1,hideToggleDisabled:s=!1,loading:o,metric:r,onHideFromLeaderboardChange:i,onMetricChange:l,profiles:h,refreshing:p=!1,showHideToggle:m=!1}){const c=(t==null?void 0:t[r])??null;return e.jsxs("section",{"aria-labelledby":"rank-users-title",className:"space-y-3 sm:space-y-4",children:[e.jsxs("div",{className:"flex w-full min-w-0 flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-3",children:[e.jsx("h2",{className:"text-2xl font-bold tracking-tight sm:text-3xl",id:"rank-users-title",children:e.jsx(We,{children:"用户排行榜"})}),e.jsx(Be,{cost:(t==null?void 0:t.cost)??null,hideFromLeaderboard:a,loading:o,metric:r,onMetricChange:l,tokens:(t==null?void 0:t.tokens)??null})]}),m?e.jsx(M,{className:"shrink-0 self-start sm:self-center",isDisabled:s,isSelected:a,size:"sm",onChange:d=>i==null?void 0:i(d),children:e.jsxs(M.Content,{className:"gap-1.5 text-xs font-normal text-muted",children:[e.jsx(M.Control,{children:e.jsx(M.Thumb,{})}),"隐藏自己"]})}):null]}),o&&c==null?e.jsx(Ze,{}):e.jsx("div",{className:C("transition-opacity duration-150",p&&"pointer-events-none opacity-60"),children:e.jsx(Je,{board:c,profiles:h})})]})}function Je({board:t,profiles:a}){const s=(t==null?void 0:t.rows)??[];return s.length===0?e.jsxs("div",{className:C(D,"flex min-h-56 flex-col items-center justify-center gap-2 text-center"),children:[e.jsx("p",{className:"text-sm",children:"当前范围暂无用户排行数据"}),e.jsx("p",{className:"text-xs text-muted",children:"产生用量后再回来看看"})]}):e.jsxs("div",{className:C(D,"min-w-0"),children:[e.jsxs("div",{"aria-hidden":!0,className:"flex items-center gap-2 px-4 py-2.5 text-[11px] text-muted sm:gap-5 sm:px-6 sm:py-3 sm:text-xs",children:[e.jsx("span",{className:"w-6 shrink-0 sm:w-8"}),e.jsx("span",{className:"min-w-0 flex-1",children:"用户"}),e.jsxs("div",{className:"flex shrink-0 items-center gap-2 sm:gap-8",children:[e.jsx("span",{className:"w-[3.25rem] text-right sm:w-24",children:"总 Token"}),e.jsx("span",{className:"w-[3.25rem] text-right sm:w-20",children:"总费用"})]})]}),e.jsx("ol",{className:"min-w-0",children:s.map(o=>{const r=o,i=r.uid??o.userHash,l=a[i],h=(l==null?void 0:l.userName)??o.displayName,p=(l==null?void 0:l.avatarUrl)??r.avatarUrl,m=(l==null?void 0:l.profileUrl)??`https://juejin.cn/user/${encodeURIComponent(i)}`,c=r.totalTokens??o.tokens;return e.jsx("li",{className:"min-w-0 [content-visibility:auto] [contain-intrinsic-size:auto_56px] transition-colors hover:bg-black/[0.02] dark:hover:bg-white/[0.04]",children:e.jsxs("div",{className:"flex min-w-0 items-center gap-2 px-4 py-3 sm:gap-5 sm:px-6 sm:py-4",children:[e.jsx(Xe,{rank:o.rank}),e.jsxs("div",{className:"flex min-w-0 flex-1 items-center gap-2 sm:gap-2.5",children:[e.jsx(Qe,{fallback:h.slice(0,1),src:p}),e.jsx("a",{className:"min-w-0 truncate text-sm font-semibold text-foreground underline-offset-2 hover:underline sm:text-[15px]",href:m,rel:"noreferrer",target:"_blank",title:h,children:h}),o.isCurrentUser&&e.jsx(U,{className:"shrink-0",color:"success",size:"sm",variant:"soft",children:e.jsx(U.Label,{children:"我"})})]}),e.jsx(Ye,{costUsd:o.costUsd,tokens:c})]})},o.userHash)})})]})}function Qe({fallback:t,src:a}){const s=u.useRef(null),[o,r]=u.useState(!a);return u.useEffect(()=>{if(!a){r(!0);return}const i=s.current;if(!i)return;if(typeof IntersectionObserver>"u"){r(!0);return}const l=new IntersectionObserver(h=>{h.some(p=>p.isIntersecting)&&(r(!0),l.disconnect())},{rootMargin:Ke,threshold:.01});return l.observe(i),()=>l.disconnect()},[a]),e.jsx("span",{className:"inline-flex shrink-0",ref:s,children:e.jsxs(L,{className:"size-7 sm:size-8",size:"sm",children:[o&&a?e.jsx(L.Image,{alt:"",decoding:"async",loading:"lazy",src:a}):null,e.jsx(L.Fallback,{children:t})]})})}function Xe({rank:t}){return e.jsx("span",{"aria-label":`第 ${t} 名`,className:C("w-6 shrink-0 text-center text-xl font-bold tabular-nums leading-none sm:w-8 sm:text-2xl",t===1&&"text-[#F53F3F] dark:text-[#ff6b6b]",t===2&&"text-[#F77234] dark:text-[#ff9a5c]",t===3&&"text-[#FF7D00] dark:text-[#ffb020]",t>3&&"text-foreground/55 dark:text-foreground/45"),children:t})}function Ye({costUsd:t,tokens:a}){return e.jsxs("div",{className:"flex shrink-0 items-center gap-2 sm:gap-8",children:[e.jsx("span",{className:"w-[3.25rem] truncate text-right text-xs font-medium tabular-nums text-foreground sm:w-24 sm:text-sm",title:`${a.toLocaleString("zh-CN")} Token`,children:X(a)}),e.jsx("span",{className:"w-[3.25rem] truncate text-right text-xs font-medium tabular-nums text-foreground sm:w-20 sm:text-sm",title:P(t),children:P(t)})]})}function Ze(){return e.jsxs("div",{"aria-label":"用户排行榜加载中",className:C(D,"min-w-0"),children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-2.5 sm:gap-5 sm:px-6 sm:py-3",children:[e.jsx("span",{className:"w-6 shrink-0 sm:w-8"}),e.jsx(b,{className:"h-3 w-8 rounded-md"}),e.jsxs("div",{className:"ml-auto flex shrink-0 items-center gap-2 sm:gap-8",children:[e.jsx(b,{className:"h-3 w-12 rounded-md sm:w-16"}),e.jsx(b,{className:"h-3 w-12 rounded-md sm:w-14"})]})]}),Array.from({length:7},(t,a)=>e.jsxs("div",{className:"flex items-center gap-2 px-4 py-3 sm:gap-5 sm:px-6 sm:py-4",children:[e.jsx(b,{className:"h-6 w-6 shrink-0 rounded-md sm:h-7 sm:w-8"}),e.jsxs("div",{className:"flex min-w-0 flex-1 items-center gap-2 sm:gap-2.5",children:[e.jsx(b,{className:"size-7 shrink-0 rounded-full sm:size-8"}),e.jsx(b,{className:"h-4 w-24 max-w-full rounded-md sm:w-36"})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-2 sm:gap-8",children:[e.jsx(b,{className:"h-3.5 w-12 rounded-md sm:h-4 sm:w-20"}),e.jsx(b,{className:"h-3.5 w-12 rounded-md sm:h-4 sm:w-16"})]})]},a))]})}const et=JSON.parse('[{"content":{"content_id":"7668309258707386378","item_type":2,"format":"","author_id":"1468603264447661","title":"我的AI工作流整理【个人向】","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640642101116936","7337236878996799522"]},"content_counter":{"view":1255,"like":20,"collect":20,"hot_rank":801,"comment_count":8,"interact_count":28},"author":{"user_id":"1468603264447661","name":"昭阳","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/be57be505955ef23e4ad41465db23038~300x300.image","is_followed":false},"author_counter":{"level":3,"power":502,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668540866239529010","item_type":2,"format":"","author_id":"3271760779459694","title":"DeepSeek V4-Flash 更新:代码与 Agent 能力全面增强","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093","6809640408797167623","7467857238493757466"]},"content_counter":{"view":1060,"like":10,"collect":1,"hot_rank":558,"comment_count":0,"interact_count":10},"author":{"user_id":"3271760779459694","name":"勇宝趣学前端","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/5a2596246a214e4bff4a4ceff6213c54~300x300.image","is_followed":false},"author_counter":{"level":4,"power":3937,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7667863898348126271","item_type":2,"format":"","author_id":"817692379985752","title":"KotlinLLM 开源 ,一个可以在运行时自己生成永久 Kotlin 代码的 Agent 库","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809635626879549454","tag_ids":["6809640407484334093","6809640400832167949","6809640642101116936"]},"content_counter":{"view":936,"like":13,"collect":9,"hot_rank":549,"comment_count":2,"interact_count":15},"author":{"user_id":"817692379985752","name":"恋猫de小郭","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/f4117a39915ab646a21a190e1fc5795d~300x300.image","is_followed":false},"author_counter":{"level":8,"power":162020,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668191994554073142","item_type":2,"format":"","author_id":"817692379985752","title":"Flutter Starling : 用 Swift和 Flutter 写了一个 Linux 桌面系统,震惊我一整年","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809635626879549454","tag_ids":["6809640407484334093","6809641090145058824","6809640400832167949"]},"content_counter":{"view":789,"like":16,"collect":8,"hot_rank":522,"comment_count":3,"interact_count":19},"author":{"user_id":"817692379985752","name":"恋猫de小郭","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/f4117a39915ab646a21a190e1fc5795d~300x300.image","is_followed":false},"author_counter":{"level":8,"power":162020,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668634785267695625","item_type":2,"format":"","author_id":"2101921964109880","title":"DeepSeek-V4-Flash 正式版来了!这次提升有点夸张。","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640408797167623","6809640482725953550","6809640642101116936"]},"content_counter":{"view":795,"like":10,"collect":3,"hot_rank":441,"comment_count":0,"interact_count":10},"author":{"user_id":"2101921964109880","name":"cxuanAI","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/5920859b1d1dd54b8e09b7a55c956f0b~300x300.image","is_followed":false},"author_counter":{"level":6,"power":66857,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668305038255521838","item_type":2,"format":"","author_id":"465848661970824","title":"Spring之父再次出山,开发了新的AI框架!","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640408797167623"]},"content_counter":{"view":725,"like":8,"collect":16,"hot_rank":387,"comment_count":0,"interact_count":8},"author":{"user_id":"465848661970824","name":"苏三说技术","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/dc678f02170ae25eb82989d0f7715e1f~300x300.image","is_followed":false},"author_counter":{"level":7,"power":77230,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7667895598095826970","item_type":2,"format":"","author_id":"1046390797768519","title":"别再只用 Loading、Success、Error 表示所有页面状态了","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809635626879549454","tag_ids":["6809640615584727053","6809640400832167949"]},"content_counter":{"view":574,"like":5,"collect":13,"hot_rank":315,"comment_count":2,"interact_count":7},"author":{"user_id":"1046390797768519","name":"RockByte","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/dc915432f9ea15229a7cbaeb90b832a9~300x300.image","is_followed":false},"author_counter":{"level":5,"power":11195,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668535450420019236","item_type":2,"format":"","author_id":"1239904848718135","title":"我用AI写了半年代码——回头看,这5个能力正在退化","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093","7467857238494019610","6809640398105870343"]},"content_counter":{"view":497,"like":4,"collect":3,"hot_rank":279,"comment_count":3,"interact_count":7},"author":{"user_id":"1239904848718135","name":"kyriewen","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/dc010ce441d17f8236be40eb2d03ef25~300x300.image","is_followed":false},"author_counter":{"level":5,"power":8065,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668341210563870720","item_type":2,"format":"","author_id":"3109843365802925","title":"公司取消前端岗后,做了 10 年 Java 的我,第一次认真拥抱 AI","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637771511070734","tag_ids":["6809640408797167623","6809640407484334093","6809641073527226376"]},"content_counter":{"view":572,"like":1,"collect":3,"hot_rank":270,"comment_count":1,"interact_count":2},"author":{"user_id":"3109843365802925","name":"天天摸鱼的java工程师","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/154899ea78d48ae7f7b6f942da934035~300x300.image","is_followed":false},"author_counter":{"level":5,"power":20605,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668490153107783732","item_type":2,"format":"","author_id":"1747564987417529","title":"DeepSeek-V4-Flash 接入 Codex(Windows 版)","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637776263217160","tag_ids":["6809640419505209358"]},"content_counter":{"view":516,"like":0,"collect":1,"hot_rank":234,"comment_count":1,"interact_count":1},"author":{"user_id":"1747564987417529","name":"iMountTai","avatar":"https://p6-passport.byteacctimg.com/img/mosaic-legacy/3793/3131589739~300x300.image","is_followed":false},"author_counter":{"level":1,"power":36,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668608790367682595","item_type":2,"format":"","author_id":"3280598428302727","title":"DeepSeek V4-Flash 正式版深度解读:一行 changelog 里的暗涌与野心","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640642101116936","7257794499869573175"]},"content_counter":{"view":422,"like":4,"collect":1,"hot_rank":216,"comment_count":0,"interact_count":4},"author":{"user_id":"3280598428302727","name":"土豆1250","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/d885d8cedee72a3f762988d43f4e6cf9~300x300.image","is_followed":false},"author_counter":{"level":4,"power":3230,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7667863898349289535","item_type":2,"format":"","author_id":"131597124767479","title":"用户埋点怎么设计","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637776263217160","tag_ids":["6809640408797167623"]},"content_counter":{"view":340,"like":6,"collect":8,"hot_rank":207,"comment_count":0,"interact_count":6},"author":{"user_id":"131597124767479","name":"Harries","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/a4c138f466be404ddcc48d60e50672d7~300x300.image","is_followed":false},"author_counter":{"level":6,"power":33562,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668204673984675850","item_type":2,"format":"","author_id":"3193422001474199","title":"从零开发一个 Coding Agent(四):使用状态机校验大模型事件流","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093","6809640408797167623","6809640642101116936"]},"content_counter":{"view":398,"like":3,"collect":6,"hot_rank":198,"comment_count":0,"interact_count":3},"author":{"user_id":"3193422001474199","name":"东方小月","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/2361b8d5a0de5981a126064173e399d6~300x300.image","is_followed":false},"author_counter":{"level":5,"power":23223,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668532403132301362","item_type":2,"format":"","author_id":"1081575170131006","title":"全栈工程师必会技术栈:从入门到架构的完整成长地图 🗺️","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093","6809640408797167623","6809640458684203021"]},"content_counter":{"view":296,"like":5,"collect":10,"hot_rank":189,"comment_count":2,"interact_count":7},"author":{"user_id":"1081575170131006","name":"前端小小栈","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/d214cb622791e83300abdd4c3260ec4b~300x300.image","is_followed":false},"author_counter":{"level":5,"power":5595,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668589503620546611","item_type":2,"format":"","author_id":"1239904846873326","title":"bm2,MoonBit实现的pm2替代品","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637772874219534","tag_ids":["6809640407484334093","6809640408797167623","6809640482725953550"]},"content_counter":{"view":212,"like":4,"collect":4,"hot_rank":162,"comment_count":4,"interact_count":8},"author":{"user_id":"1239904846873326","name":"前端之虎陈随易","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/1e53615038b0e9a227c4627ee0bb0a65~300x300.image","is_followed":false},"author_counter":{"level":5,"power":22346,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668274158058504201","item_type":2,"format":"","author_id":"4001878056904584","title":"Spring Boot 集成 OnlyOffice,5 分钟搞定 Word/Excel 在线编辑","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640408797167623","6809640445233070094","6809640482725953550"]},"content_counter":{"view":288,"like":3,"collect":11,"hot_rank":153,"comment_count":0,"interact_count":3},"author":{"user_id":"4001878056904584","name":"SimonKing","avatar":"https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/mirror-assets/16cadd4c73660bef648~tplv-t2oaga2asx-image.image","is_followed":false},"author_counter":{"level":5,"power":12998,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7669024144831168518","item_type":2,"format":"","author_id":"4441682708283191","title":"DeepSeek-V4-Flash 正式版上线了,但这 3 个坑我帮你提前踩了","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637776263217160","tag_ids":["6809640407484334093","6809640408797167623","6809640398105870343"]},"content_counter":{"view":298,"like":2,"collect":1,"hot_rank":144,"comment_count":0,"interact_count":2},"author":{"user_id":"4441682708283191","name":"万少","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/3559b8826a8e632112e62195b3a1c745~300x300.image","is_followed":false},"author_counter":{"level":5,"power":12410,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668933720747638834","item_type":2,"format":"","author_id":"1204720476890477","title":"架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640407484334093","7467857238493757466","7197380506562871333"]},"content_counter":{"view":283,"like":2,"collect":1,"hot_rank":135,"comment_count":0,"interact_count":2},"author":{"user_id":"1204720476890477","name":"小帅不太帅","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/939ad8ae4c08781557a64b2b48b77a7d~300x300.image","is_followed":false},"author_counter":{"level":5,"power":6158,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7667907789688274953","item_type":2,"format":"","author_id":"1662117311414462","title":"JS 代码技巧 vol.10 — 20 个 V8 引擎原理,解释\\"为什么这样写快\\"","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093","6809640398105870343","6809640404791590919"]},"content_counter":{"view":204,"like":3,"collect":4,"hot_rank":117,"comment_count":0,"interact_count":3},"author":{"user_id":"1662117311414462","name":"不简说","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/079dd96c51924889586213e3d88d5890~300x300.image","is_followed":false},"author_counter":{"level":4,"power":2596,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7667748470229860378","item_type":2,"format":"","author_id":"3271760779459694","title":"《道德经》第 9 章:别把系统和自己都推到过载","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637772874219534","tag_ids":["6809640407484334093","6809640408797167623","6809640482725953550"]},"content_counter":{"view":123,"like":5,"collect":2,"hot_rank":108,"comment_count":1,"interact_count":6},"author":{"user_id":"3271760779459694","name":"勇宝趣学前端","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/5a2596246a214e4bff4a4ceff6213c54~300x300.image","is_followed":false},"author_counter":{"level":4,"power":3937,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668524314757349385","item_type":2,"format":"","author_id":"4371313964097565","title":"Agentic AI 工程实战","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640642101116936"]},"content_counter":{"view":151,"like":4,"collect":3,"hot_rank":99,"comment_count":0,"interact_count":4},"author":{"user_id":"4371313964097565","name":"Shockang","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/4665bb630e37a2f96abecb263cd5f753~300x300.image","is_followed":false},"author_counter":{"level":4,"power":2368,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668309258707320842","item_type":2,"format":"","author_id":"1380642337863272","title":"SDKMAN vs jEnv vs JetTUI,JDK 版本管理到底选哪个","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637771511070734","tag_ids":["6809640408797167623"]},"content_counter":{"view":74,"like":2,"collect":1,"hot_rank":99,"comment_count":6,"interact_count":8},"author":{"user_id":"1380642337863272","name":"极客悟道","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/4a2d5c0741c2ab9451777574d769dab2~300x300.image","is_followed":false},"author_counter":{"level":3,"power":474,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668880520002240566","item_type":2,"format":"","author_id":"149189314230039","title":"GPT-5.6 Luna 降价 80%:Agent 真正该重算的是单次成功成本","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640642101116936","7257794499869573175","7197380216015028281"]},"content_counter":{"view":142,"like":4,"collect":1,"hot_rank":99,"comment_count":0,"interact_count":4},"author":{"user_id":"149189314230039","name":"武子康","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/2176f1cd005191db850b0d9d8967a45b~300x300.image","is_followed":false},"author_counter":{"level":5,"power":10970,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668906037449834502","item_type":2,"format":"","author_id":"1239904846873326","title":"MoonBit抓包模块pcap,查看电脑的每一次联网通信","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637772874219534","tag_ids":["6809640407484334093","6809640408797167623","6809640482725953550"]},"content_counter":{"view":106,"like":3,"collect":4,"hot_rank":90,"comment_count":2,"interact_count":5},"author":{"user_id":"1239904846873326","name":"前端之虎陈随易","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/1e53615038b0e9a227c4627ee0bb0a65~300x300.image","is_followed":false},"author_counter":{"level":5,"power":22346,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668613701019467782","item_type":2,"format":"","author_id":"1239904848718135","title":"面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093","6809640398105870343","6809640404791590919"]},"content_counter":{"view":164,"like":2,"collect":2,"hot_rank":90,"comment_count":0,"interact_count":2},"author":{"user_id":"1239904848718135","name":"kyriewen","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/dc010ce441d17f8236be40eb2d03ef25~300x300.image","is_followed":false},"author_counter":{"level":5,"power":8065,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668508411719090230","item_type":2,"format":"","author_id":"1694775710064217","title":"iOS 客户端视角扫盲:WKWebView 里 window、messageHandlers 与 Native 回调到底怎么工作?","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809635626661445640","tag_ids":["6809640398105870343"]},"content_counter":{"view":111,"like":5,"collect":9,"hot_rank":90,"comment_count":0,"interact_count":5},"author":{"user_id":"1694775710064217","name":"大龄秃头程序员","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/b57565666e223f09fdfeb2c5102c6e4a~300x300.image","is_followed":false},"author_counter":{"level":3,"power":525,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668247452035579939","item_type":2,"format":"","author_id":"1151943919285431","title":"面试官突然问:“数仓哪一层最适合做RAG?”他一下被问住了…","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640404791590919"]},"content_counter":{"view":179,"like":2,"collect":4,"hot_rank":90,"comment_count":0,"interact_count":2},"author":{"user_id":"1151943919285431","name":"神奇小汤圆","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/7faa641980319649e45a847fcd54c46e~300x300.image","is_followed":false},"author_counter":{"level":5,"power":11601,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668613701018583046","item_type":2,"format":"","author_id":"220360279590862","title":"AI时代,程序员该往哪走?","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640407484334093","6809640408797167623"]},"content_counter":{"view":128,"like":2,"collect":2,"hot_rank":81,"comment_count":1,"interact_count":3},"author":{"user_id":"220360279590862","name":"程序员_小雨","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/254baefb585a9a27d77df8976366f55e~300x300.image","is_followed":false},"author_counter":{"level":4,"power":3173,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668341210564214784","item_type":2,"format":"","author_id":"3148645291002232","title":"从火焰图到代码:如何揪出“用久必卡”的前端性能瓶颈","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093"]},"content_counter":{"view":189,"like":0,"collect":5,"hot_rank":81,"comment_count":0,"interact_count":0},"author":{"user_id":"3148645291002232","name":"IT橘子皮","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/e1dcb4a9ffbfc57847420b18b52b1296~300x300.image","is_followed":false},"author_counter":{"level":5,"power":10129,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668198031946809380","item_type":2,"format":"","author_id":"858052674727959","title":"15|(前端转全栈)从一个副标题字段看懂后端完整交付链路","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640407484334093","6809640408797167623","6809640404791590919"]},"content_counter":{"view":109,"like":3,"collect":4,"hot_rank":81,"comment_count":1,"interact_count":4},"author":{"user_id":"858052674727959","name":"swipe","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/ba6476a882ad6e83b4332cd6b7d48c6e~300x300.image","is_followed":false},"author_counter":{"level":4,"power":4558,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668494151793803305","item_type":2,"format":"","author_id":"2770425030646920","title":"深入理解 Flutter 架构:从 Widget 到 GPU 像素的全链路解析","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809635626879549454","tag_ids":["6809641090145058824","6809641091428515853","6809640404791590919"]},"content_counter":{"view":104,"like":3,"collect":1,"hot_rank":81,"comment_count":1,"interact_count":4},"author":{"user_id":"2770425030646920","name":"GitLqr","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/ccc4bb40b0cda1df6b2b885e69c63cc4~300x300.image","is_followed":false},"author_counter":{"level":5,"power":20432,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7669321508946919451","item_type":2,"format":"","author_id":"1574156382242637","title":"给 AI Agent 加上语音交互:ASR + 流式 TTS 实战","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640642101116936","6809640407484334093","6809640408797167623"]},"content_counter":{"view":58,"like":6,"collect":3,"hot_rank":72,"comment_count":0,"interact_count":6},"author":{"user_id":"1574156382242637","name":"云浪","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/f56a64387805ddf3200e9d065da433b9~300x300.image","is_followed":false},"author_counter":{"level":4,"power":4022,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668632356999462946","item_type":2,"format":"","author_id":"3350967174045047","title":"从 mldong 到 jeeflow:一个工作流引擎的独立进化","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640408797167623"]},"content_counter":{"view":108,"like":2,"collect":3,"hot_rank":72,"comment_count":1,"interact_count":3},"author":{"user_id":"3350967174045047","name":"mldong","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/cd319eca3d1c3138ae5798e314786040~300x300.image","is_followed":false},"author_counter":{"level":5,"power":9064,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668247452035350563","item_type":2,"format":"","author_id":"3386151544043960","title":"腾讯 Mars XLog 日志框架的编译和修改","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809635626879549454","tag_ids":["6809640400832167949"]},"content_counter":{"view":119,"like":3,"collect":4,"hot_rank":72,"comment_count":0,"interact_count":3},"author":{"user_id":"3386151544043960","name":"李斯维","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/e202048c011082de7974c4447a899765~300x300.image","is_followed":false},"author_counter":{"level":3,"power":1636,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668718271143952435","item_type":2,"format":"","author_id":"976022055165608","title":"DeepSeek V4-Flash 正式版发布:Agent 基准、价格与 Codex 接入保姆级教程","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["7467857238494019610","7467857238493757466","7516396389476401162"]},"content_counter":{"view":152,"like":0,"collect":1,"hot_rank":63,"comment_count":0,"interact_count":0},"author":{"user_id":"976022055165608","name":"极客密码","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/31dc63f4c1be7194a4e3ba134d121210~300x300.image","is_followed":false},"author_counter":{"level":5,"power":5744,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668598831861661722","item_type":2,"format":"","author_id":"2832784963939438","title":"2840亿参数只卖白菜价:DeepSeek V4 Flash 正式版上线,Agent 能力暴涨6倍","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640499062767624","6809640642101116936"]},"content_counter":{"view":130,"like":1,"collect":1,"hot_rank":63,"comment_count":0,"interact_count":1},"author":{"user_id":"2832784963939438","name":"怕浪猫","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/0e141e0ee39472b8dbddd3a4d8983a38~300x300.image","is_followed":false},"author_counter":{"level":5,"power":5955,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668331078025773071","item_type":2,"format":"","author_id":"199452905712459","title":"教你用最简单的数学自底向上地高效学习SQL注入","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640408797167623"]},"content_counter":{"view":104,"like":2,"collect":0,"hot_rank":63,"comment_count":0,"interact_count":2},"author":{"user_id":"199452905712459","name":"大侠在此在在此","avatar":"https://p26-passport.byteacctimg.com/img/mosaic-legacy/3793/3131589739~300x300.image","is_followed":false},"author_counter":{"level":1,"power":26,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668316523342987270","item_type":2,"format":"","author_id":"1020824523126637","title":"从原始采样到可缩放心电图:用 h5ECG 绘制自己的 ECG","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093"]},"content_counter":{"view":65,"like":0,"collect":2,"hot_rank":63,"comment_count":4,"interact_count":4},"author":{"user_id":"1020824523126637","name":"洪贺","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/76096d8d5fc4b8f99a2428512573b74c~300x300.image","is_followed":false},"author_counter":{"level":1,"power":28,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668206734344667174","item_type":2,"format":"","author_id":"392940069589529","title":"React 状态提升:一个 ColorPicker,彻底搞懂状态该放哪里","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640357354012685","6809640543006490638","6809640406058270733"]},"content_counter":{"view":70,"like":4,"collect":0,"hot_rank":63,"comment_count":0,"interact_count":4},"author":{"user_id":"392940069589529","name":"烬羽","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/17a70c62f5d39e21845ced34dd665b0a~300x300.image","is_followed":false},"author_counter":{"level":4,"power":1840,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668202727697317922","item_type":2,"format":"","author_id":"3667626523633389","title":"tailwind 速记","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093"]},"content_counter":{"view":95,"like":3,"collect":7,"hot_rank":63,"comment_count":0,"interact_count":3},"author":{"user_id":"3667626523633389","name":"时光不负努力","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/0a77281dbfaaeb49a2feb08a5d5db15f~300x300.image","is_followed":false},"author_counter":{"level":3,"power":1066,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7669268061262397503","item_type":2,"format":"","author_id":"2172290706715565","title":"栗子前端技术周刊第 140 期 - pnpm、Node 新 API 文档网站、Oxlint...","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093","6809640398105870343","6809640361531539470"]},"content_counter":{"view":90,"like":3,"collect":1,"hot_rank":63,"comment_count":0,"interact_count":3},"author":{"user_id":"2172290706715565","name":"晓得迷路了","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/2245abbd9a1b2147a918ec036c2149e1~300x300.image","is_followed":false},"author_counter":{"level":5,"power":26100,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7669068704309329960","item_type":2,"format":"","author_id":"3192637495714686","title":"网页端OCR, 加载6mb大小模型, 又快又准, 百度这次真香","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640408797167623","6809640407484334093"]},"content_counter":{"view":77,"like":3,"collect":4,"hot_rank":54,"comment_count":0,"interact_count":3},"author":{"user_id":"3192637495714686","name":"半刻纬度","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/07e4b5b998a373958f919e974f769f01~300x300.image","is_followed":false},"author_counter":{"level":5,"power":24376,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7669036838767034387","item_type":2,"format":"","author_id":"1611207712190058","title":"Android:Hilt框架入门 · 在ViewUI和ComposeUI下的应用","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809635626879549454","tag_ids":["6809640400832167949","6809641107346063368"]},"content_counter":{"view":70,"like":3,"collect":0,"hot_rank":54,"comment_count":0,"interact_count":3},"author":{"user_id":"1611207712190058","name":"Lesile","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/c861ba9bf058d6b23878f43ea1708508~300x300.image","is_followed":false},"author_counter":{"level":2,"power":150,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668692837795725347","item_type":2,"format":"","author_id":"3806962499980916","title":" 08|韧性:一套接口接三家 API —— LLMProvider","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["7467857238494019610"]},"content_counter":{"view":71,"like":3,"collect":2,"hot_rank":54,"comment_count":0,"interact_count":3},"author":{"user_id":"3806962499980916","name":"浪遏","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/5c1619281bed61a788ee074772296e90~300x300.image","is_followed":false},"author_counter":{"level":5,"power":6111,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668602914118041610","item_type":2,"format":"","author_id":"2463384809252397","title":"Go语言第四章(类型转换)","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640408797167623","6809640364677267469"]},"content_counter":{"view":66,"like":3,"collect":2,"hot_rank":54,"comment_count":0,"interact_count":3},"author":{"user_id":"2463384809252397","name":"小满zs","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/f406e4f16ef06556e95d7fe50241a5e8~300x300.image","is_followed":false},"author_counter":{"level":6,"power":31270,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668564914921881636","item_type":2,"format":"","author_id":"245921884145240","title":"VS Code 内置浏览器打开网页","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640407484334093"]},"content_counter":{"view":85,"like":1,"collect":1,"hot_rank":54,"comment_count":1,"interact_count":2},"author":{"user_id":"245921884145240","name":"笨笨狗吞噬者","avatar":"https://p3-passport.byteacctimg.com/img/user-avatar/24ee78f33f9379577dc9dffa1b6669a8~300x300.image","is_followed":false},"author_counter":{"level":4,"power":4767,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668547554775695400","item_type":2,"format":"","author_id":"3669540352043419","title":"React 组件重新渲染时,到底重新执行了什么","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637767543259144","tag_ids":["6809640357354012685","6809640407484334093","6809640404791590919"]},"content_counter":{"view":88,"like":2,"collect":3,"hot_rank":54,"comment_count":1,"interact_count":3},"author":{"user_id":"3669540352043419","name":"Revolution61","avatar":"https://p26-passport.byteacctimg.com/img/user-avatar/abdd9a332b03603e265e249e7f415bf9~300x300.image","is_followed":false},"author_counter":{"level":3,"power":654,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668247452035874851","item_type":2,"format":"","author_id":"3737995265453661","title":"改了20字描述,MCP工具调用准确率飙到85%","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["7467857241178259507","7467857238494019610","7516396389476401162"]},"content_counter":{"view":89,"like":1,"collect":0,"hot_rank":54,"comment_count":1,"interact_count":2},"author":{"user_id":"3737995265453661","name":"码哥字节","avatar":"https://p6-passport.byteacctimg.com/img/user-avatar/8be362627ed4532e3af99463b755598f~300x300.image","is_followed":false},"author_counter":{"level":5,"power":9471,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7667750500684152867","item_type":2,"format":"","author_id":"3956505282886506","title":"BCrypt 还是 Argon2?Spring Security 密码加密方案深度解析与实战对比","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637769959178254","tag_ids":["6809640445233070094","6809640703325372423"]},"content_counter":{"view":89,"like":2,"collect":2,"hot_rank":54,"comment_count":0,"interact_count":2},"author":{"user_id":"3956505282886506","name":"都叫我大帅哥","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/4330d38b5347bc9896ed88eaf9592a9a~300x300.image","is_followed":false},"author_counter":{"level":5,"power":7163,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}},{"content":{"content_id":"7668977124872732722","item_type":2,"format":"","author_id":"3456520291098686","title":"AI编程出海第二步:验证关键词能否做站","brief":"","status":2,"ctime":0,"mtime":0,"category_id":"6809637773935378440","tag_ids":["6809640408797167623","6809640407484334093","6809640642101116936"]},"content_counter":{"view":62,"like":2,"collect":2,"hot_rank":45,"comment_count":0,"interact_count":2},"author":{"user_id":"3456520291098686","name":"卷福同学","avatar":"https://p9-passport.byteacctimg.com/img/user-avatar/ea20d1a80e4b73968e0be6c4027915d8~300x300.image","is_followed":false},"author_counter":{"level":5,"power":6374,"follower":0,"followee":0,"publish":0,"view":0,"like":0,"hot_rank":0},"user_interact":{"is_user_like":false,"is_user_collect":false,"is_follow":false}}]'),tt=50,z=(()=>{const t=new Map;for(const a of et){const s=a.author;!(s!=null&&s.user_id)||t.has(s.user_id)||t.set(s.user_id,{userId:s.user_id,name:s.name,avatar:s.avatar})}return Array.from(t.values())})();Array.from({length:tt},(t,a)=>{const s=z.length>0?z[a%z.length]:void 0,o=a===0,r=o?"c0dec001":(Math.imul(73244475,a+17)>>>0).toString(16).padStart(8,"0"),i=s?a<z.length?s.userId:`${s.userId}-${a}`:r;return{displayName:(s==null?void 0:s.name)??`用户 ${r}`,userHash:r,uid:i,avatarUrl:s==null?void 0:s.avatar,tokens:o?15e9:Math.max(12e7,95e8-a*175e6+a*7%5*45e6),costUsd:o?14e3:Math.max(80,Number((8200-a*145+a*11%7*38).toFixed(2))),isCurrentUser:o}});const at=1e4;function st(t,a){return`${t}|${a.tool??""}|${a.model??""}`}function rt(t,a={}){const s=ve(),o=pe(),{authStatus:r}=Y(),[i,l]=u.useState(0),h=u.useRef(null),[p,m]=u.useState({data:null,loading:!0,refreshing:!1,error:null}),c=u.useCallback(()=>{l(d=>d+1)},[]);return u.useEffect(()=>{let d=!1;const n=st(t,a);return m(f=>f.data==null?{...f,loading:!0,refreshing:!1,error:null}:h.current!=null&&h.current!==n?{...f,loading:!1,refreshing:!0,error:null}:f),he(t,void 0,a).then(f=>{d||(h.current=n,m({data:f,loading:!1,refreshing:!1,error:null}))}).catch(f=>{d||m(g=>({data:g.data,loading:!1,refreshing:!1,error:f instanceof Error?f.message:"排行榜加载失败"}))}),()=>{d=!0}},[t,i,s,o,r,a.model,a.tool]),u.useEffect(()=>{let d=0,n=performance.now();const x=g=>{g-n>=at&&(n=g,c()),d=requestAnimationFrame(x)};d=requestAnimationFrame(x);const f=()=>{n=performance.now(),c()};return window.addEventListener("focus",f),()=>{cancelAnimationFrame(d),window.removeEventListener("focus",f)}},[c]),{...p,reload:c}}function ot(){const[t,a]=u.useState("week"),[s,o]=u.useState(""),[r,i]=u.useState(""),[l,h]=u.useState("tokens"),[p,m]=u.useState(!1),[c,d]=u.useState(!1),{data:n,error:x,loading:f,refreshing:g,reload:j}=rt(t,{tool:s||void 0,model:r||void 0}),_=f||g,{authStatus:O,userId:w,userName:I,avatarLarge:H}=Y(),V=!0;u.useEffect(()=>{const k=()=>{j()};return window.addEventListener(G,k),()=>window.removeEventListener(G,k)},[j]),u.useEffect(()=>{let k=!1;return xe().then(E=>{k||m(E.hideFromLeaderboard)}).catch(()=>{k||m(!1)}),()=>{k=!0}},[V]);const oe=!f&&!x&&n!=null&&n.global.cost.currentUser==null&&n.global.tokens.currentUser==null,N=n==null?void 0:n.filterOptions,ie=u.useMemo(()=>Re((N==null?void 0:N.models)??[],s),[N==null?void 0:N.models,s]),$=u.useMemo(()=>{const k={...(n==null?void 0:n.profiles)??{}};return w&&I&&(k[w]={uid:w,userName:I,avatarUrl:H,profileUrl:`https://juejin.cn/user/${encodeURIComponent(w)}`}),k},[n==null?void 0:n.profiles,w,I,H]),le=k=>{const E=p;m(k),d(!0),ge(k).then(()=>{j()}).catch(()=>{m(E)}).finally(()=>{d(!1)})};return e.jsxs("div",{"aria-busy":_,className:"relative flex w-full min-w-0 flex-col",children:[e.jsx(He,{board:(n==null?void 0:n.global[l])??null,loading:_,metric:l,model:r,modelOptions:ie,onChange:a,onModelChange:i,onToolChange:k=>{o(k),i("")},profiles:$,tool:s,tools:(N==null?void 0:N.tools)??[],value:t}),e.jsxs("div",{className:"space-y-6",children:[oe&&e.jsxs("div",{className:"flex max-w-2xl flex-col gap-3 sm:flex-row sm:items-center",children:[e.jsx("div",{className:"min-w-0 flex-1",children:e.jsx(we,{description:"无法标注你的排名。请前往设置绑定鉴权 Token,或登录后再查看个人名次。",title:"鉴权无效或未登录",tone:"warn"})}),e.jsx(S,{className:"shrink-0 self-start sm:self-center",onPress:()=>{be()},variant:"secondary",children:"去设置"})]}),e.jsx(qe,{global:(n==null?void 0:n.global)??null,hideFromLeaderboard:p,hideToggleDisabled:c,loading:f,metric:l,onHideFromLeaderboardChange:le,onMetricChange:h,profiles:$,refreshing:g,showHideToggle:V})]})]})}const dt=ot;export{dt as component};
@@ -1 +1 @@
1
- import{r as t,d as n}from"./index-DUrAxTsQ.js";function e(){return t.useEffect(()=>{n()},[]),null}const s=e;export{s as component};
1
+ import{r as t,d as n}from"./index-DpG68XJd.js";function e(){return t.useEffect(()=>{n()},[]),null}const s=e;export{s as component};
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>AI Usage Dashboard</title>
7
- <script type="module" crossorigin src="/assets/index-DUrAxTsQ.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-8rr_cXkj.css">
7
+ <script type="module" crossorigin src="/assets/index-DpG68XJd.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-I_ub2jqy.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { dirname, join } from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
- import { appendJsonLog, BucketStore, createAggregateCache, createApplyAfterSync, createHttpServer, createLocalApiApp, createPollBackoff, DEFAULT_PORT, getHookStatus, getRunningOwner, listenServer, loadConfig, POLL_INTERVAL_MS, pollIntervalLabel, releaseRuntimeOwner, resolveLocalCollectSince, runtimeKindLabel, saveConfig, setupClaudeHook, setupCodexHook, syncAll, collectWrittenBuckets, syncLogPath, touchStatsSince, watchRuntimeSignals, watchSyncSignals, writeSyncDone, maybeUploadAfterSync, uploadToServer, kickBackfillDrain, stopBackfillDrain, drainBackfillUntilIdle, resolvePricingRefreshConfig, startPricingRefresh, } from '@juejin-opensource/jusage-core';
3
+ import { appendJsonLog, BucketStore, createAggregateCache, createApplyAfterSync, createHttpServer, createLocalApiApp, createPollBackoff, DEFAULT_PORT, getHookStatus, getRunningOwner, listenServer, loadConfig, POLL_INTERVAL_MS, pollIntervalLabel, releaseRuntimeOwner, resolveLocalCollectSince, runtimeKindLabel, saveConfig, setupClaudeHook, setupCodexHook, syncAll, collectWrittenBuckets, syncLogPath, touchStatsSince, watchRuntimeSignals, watchSyncSignals, writeSyncDone, maybeUploadAfterSync, uploadToServer, kickBackfillDrain, stopBackfillDrain, drainBackfillUntilIdle, resolvePricingRefreshConfig, DEFAULT_PRICING_FIRST_FETCH_TIMEOUT_MS, startPricingRefresh, } from '@juejin-opensource/jusage-core';
4
4
  import { writePid } from './daemon.js';
5
5
  import { cmdServiceStart, cmdServiceStatus, cmdServiceStop } from './service.js';
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -14,7 +14,7 @@ let runtimeDataDir = null;
14
14
  /** True only when this process wrote `tud.pid` as sync/upload owner. */
15
15
  let ownedPid = false;
16
16
  let runtimeRole = 'owner';
17
- function startPricingOverlayRefresh(config) {
17
+ async function startPricingOverlayRefresh(dir, config) {
18
18
  pricingRefreshStop?.();
19
19
  pricingRefreshStop = null;
20
20
  const { url, ttlMs } = resolvePricingRefreshConfig({
@@ -23,14 +23,28 @@ function startPricingOverlayRefresh(config) {
23
23
  });
24
24
  if (!url)
25
25
  return;
26
- pricingRefreshStop = startPricingRefresh({
26
+ const handle = startPricingRefresh({
27
27
  url,
28
28
  ttlMs,
29
+ dataDir: dir,
30
+ firstFetchTimeoutMs: DEFAULT_PRICING_FIRST_FETCH_TIMEOUT_MS,
31
+ onUpdate: () => {
32
+ const current = runtime;
33
+ if (!current)
34
+ return;
35
+ void current.aggregateCache
36
+ .rebuildFromRows(current.bucketStore.getRows())
37
+ .catch((err) => {
38
+ console.warn('定价覆盖层刷新后重建缓存失败:', err instanceof Error ? err.message : err);
39
+ });
40
+ },
29
41
  onError: (err) => {
30
42
  console.warn('定价表远程刷新失败(继续用内置/上次覆盖):', err instanceof Error ? err.message : err);
31
43
  },
32
44
  });
45
+ pricingRefreshStop = handle;
33
46
  console.log(`定价覆盖层: ${url}(TTL ${ttlMs}ms)`);
47
+ await handle.ready;
34
48
  }
35
49
  function resolveDashboardDir() {
36
50
  return join(__dirname, 'dashboard');
@@ -100,7 +114,7 @@ Commands:
100
114
  status 查看 CLI / 面板当前启动状态
101
115
  sync 手动同步本地用量数据
102
116
  upload 上报数据到云端
103
- service <action> 后台服务与开机自启(macOS / Windows)
117
+ service <action> 后台服务与开机自启(macOS / Windows / Linux
104
118
  action: start | stop | status
105
119
  help 显示帮助
106
120
 
@@ -195,7 +209,7 @@ async function cmdStart(port, daysAgo) {
195
209
  }
196
210
  }
197
211
  const { config: refreshed } = await loadConfig(dir);
198
- startPricingOverlayRefresh(refreshed);
212
+ await startPricingOverlayRefresh(dir, refreshed);
199
213
  const bucketStore = new BucketStore();
200
214
  await bucketStore.reload(dir, resolveLocalCollectSince(refreshed));
201
215
  const aggregateCache = await createAggregateCache(dir, bucketStore.getRows());
@@ -0,0 +1,8 @@
1
+ export declare const LINUX_UNIT_NAME = "jusage";
2
+ export declare function linuxUnitPath(): string;
3
+ /** Quote a systemd unit value; `%` is a specifier and must be doubled. */
4
+ export declare function systemdQuote(value: string): string;
5
+ export declare function buildLinuxUnit(nodePath: string, args: readonly string[], home: string, logPath: string): string;
6
+ export declare function isLinuxAutostartRegistered(): Promise<boolean>;
7
+ export declare function registerLinuxAutostart(cliBinPath: string, dataDir: string): Promise<void>;
8
+ export declare function unregisterLinuxAutostart(): Promise<void>;
@@ -0,0 +1,125 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ import { mkdir, unlink, writeFile } from 'node:fs/promises';
5
+ import { spawnSync } from 'node:child_process';
6
+ import { daemonLogPath, ensureDaemonLogDir, resolveServiceCommand } from './daemon.js';
7
+ export const LINUX_UNIT_NAME = 'jusage';
8
+ const SYSTEMD_HINT = '可用 jusage start 前台运行。若在 WSL,请在 /etc/wsl.conf 启用 [boot] systemd=true 后执行 wsl --shutdown 再打开。';
9
+ function systemdConfigHome() {
10
+ const xdg = process.env.XDG_CONFIG_HOME?.trim();
11
+ return xdg || join(homedir(), '.config');
12
+ }
13
+ export function linuxUnitPath() {
14
+ return join(systemdConfigHome(), 'systemd', 'user', `${LINUX_UNIT_NAME}.service`);
15
+ }
16
+ function defaultPath(nodePath, home) {
17
+ const parts = [
18
+ dirname(nodePath),
19
+ '/usr/local/bin',
20
+ join(home, '.local', 'bin'),
21
+ '/usr/bin',
22
+ '/bin',
23
+ '/usr/sbin',
24
+ '/sbin',
25
+ ];
26
+ return [...new Set(parts)].join(':');
27
+ }
28
+ /** Quote a systemd unit value; `%` is a specifier and must be doubled. */
29
+ export function systemdQuote(value) {
30
+ const escapedPct = value.replace(/%/g, '%%');
31
+ if (/^[A-Za-z0-9_./:@+=,-]+$/.test(value))
32
+ return escapedPct;
33
+ return `"${escapedPct.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
34
+ }
35
+ function envLine(key, value) {
36
+ const assignment = `${key}=${value.replace(/%/g, '%%')}`;
37
+ if (/^[A-Za-z0-9_]+=[A-Za-z0-9_./:@+=,-]+$/.test(`${key}=${value}`)) {
38
+ return `Environment=${key}=${value}`;
39
+ }
40
+ return `Environment="${assignment.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
41
+ }
42
+ export function buildLinuxUnit(nodePath, args, home, logPath) {
43
+ const execStart = [nodePath, ...args].map(systemdQuote).join(' ');
44
+ const quotedHome = systemdQuote(home);
45
+ const output = `append:${systemdQuote(logPath)}`;
46
+ return `[Unit]
47
+ Description=Juejin Usage CLI
48
+ After=default.target
49
+
50
+ [Service]
51
+ Type=simple
52
+ ExecStart=${execStart}
53
+ WorkingDirectory=${quotedHome}
54
+ Restart=always
55
+ RestartSec=3
56
+ ${envLine('HOME', home)}
57
+ ${envLine('LANG', 'en_US.UTF-8')}
58
+ ${envLine('LC_ALL', 'en_US.UTF-8')}
59
+ ${envLine('PATH', defaultPath(nodePath, home))}
60
+ StandardOutput=${output}
61
+ StandardError=${output}
62
+
63
+ [Install]
64
+ WantedBy=default.target
65
+ `;
66
+ }
67
+ function isCommandMissing(err) {
68
+ return (typeof err === 'object' &&
69
+ err !== null &&
70
+ 'code' in err &&
71
+ err.code === 'ENOENT');
72
+ }
73
+ function runSystemctl(args) {
74
+ const result = spawnSync('systemctl', ['--user', ...args], {
75
+ encoding: 'utf8',
76
+ timeout: 8_000,
77
+ });
78
+ const missing = isCommandMissing(result.error);
79
+ const stderr = `${result.stderr ?? ''}${result.stdout ?? ''}`.trim();
80
+ return { ok: result.status === 0 && !missing, stderr, missing };
81
+ }
82
+ function assertSystemdUser() {
83
+ const probe = runSystemctl(['show-environment']);
84
+ if (probe.missing) {
85
+ throw new Error(`jusage service 在 Linux 上需要 systemd 用户服务,未找到 systemctl。${SYSTEMD_HINT}`);
86
+ }
87
+ if (!probe.ok) {
88
+ throw new Error(`jusage service 在 Linux 上需要可用的 systemd 用户实例(systemctl --user)。${probe.stderr ? ` ${probe.stderr}` : ''} ${SYSTEMD_HINT}`);
89
+ }
90
+ }
91
+ export async function isLinuxAutostartRegistered() {
92
+ return existsSync(linuxUnitPath());
93
+ }
94
+ export async function registerLinuxAutostart(cliBinPath, dataDir) {
95
+ assertSystemdUser();
96
+ await ensureDaemonLogDir(dataDir);
97
+ // Stop the previous unit before rewrite so Restart=always does not fight us.
98
+ await unregisterLinuxAutostart();
99
+ const unitPath = linuxUnitPath();
100
+ await mkdir(dirname(unitPath), { recursive: true });
101
+ const { nodePath, args } = resolveServiceCommand(cliBinPath);
102
+ await writeFile(unitPath, buildLinuxUnit(nodePath, args, homedir(), daemonLogPath(dataDir)), 'utf8');
103
+ const reloaded = runSystemctl(['daemon-reload']);
104
+ if (!reloaded.ok) {
105
+ throw new Error(`注册 Linux 自启失败(daemon-reload): ${reloaded.stderr || 'systemctl 返回非零'}`);
106
+ }
107
+ const enabled = runSystemctl(['enable', '--now', `${LINUX_UNIT_NAME}.service`]);
108
+ if (!enabled.ok) {
109
+ throw new Error(`注册 Linux 自启失败: ${enabled.stderr || 'systemctl enable --now 返回非零'}`);
110
+ }
111
+ }
112
+ export async function unregisterLinuxAutostart() {
113
+ runSystemctl(['disable', '--now', `${LINUX_UNIT_NAME}.service`]);
114
+ runSystemctl(['stop', `${LINUX_UNIT_NAME}.service`]);
115
+ const unitPath = linuxUnitPath();
116
+ if (existsSync(unitPath)) {
117
+ try {
118
+ await unlink(unitPath);
119
+ }
120
+ catch {
121
+ // ignore
122
+ }
123
+ }
124
+ runSystemctl(['daemon-reload']);
125
+ }
package/dist/service.js CHANGED
@@ -1,19 +1,22 @@
1
1
  import { platform } from 'node:os';
2
2
  import { DEFAULT_DATA_DIR, DEFAULT_PORT, getRunningOwner, loadConfig, runtimeKindLabel, touchStatsSince, } from '@juejin-opensource/jusage-core';
3
3
  import { clearPid, daemonLogPath, readDaemonLogTail, stopPid, waitForServiceReady, } from './daemon.js';
4
+ import { isLinuxAutostartRegistered, registerLinuxAutostart, unregisterLinuxAutostart, } from './service-linux.js';
4
5
  import { isMacosAutostartRegistered, registerMacosAutostart, unregisterMacosAutostart, } from './service-macos.js';
5
6
  import { isWindowsAutostartRegistered, registerWindowsAutostart, unregisterWindowsAutostart, } from './service-windows.js';
6
7
  function assertSupportedPlatform() {
7
8
  const p = platform();
8
- if (p === 'darwin' || p === 'win32')
9
+ if (p === 'darwin' || p === 'win32' || p === 'linux')
9
10
  return p;
10
- throw new Error(`jusage service 仅支持 macOS 与 Windows(当前: ${p})`);
11
+ throw new Error(`jusage service 仅支持 macOS、WindowsLinux(当前: ${p})`);
11
12
  }
12
13
  async function isAutostartRegistered() {
13
14
  const p = assertSupportedPlatform();
14
15
  if (p === 'darwin')
15
16
  return isMacosAutostartRegistered();
16
- return isWindowsAutostartRegistered();
17
+ if (p === 'win32')
18
+ return isWindowsAutostartRegistered();
19
+ return isLinuxAutostartRegistered();
17
20
  }
18
21
  async function registerAutostart(cliBinPath, dataDir) {
19
22
  const p = assertSupportedPlatform();
@@ -21,7 +24,11 @@ async function registerAutostart(cliBinPath, dataDir) {
21
24
  await registerMacosAutostart(cliBinPath, dataDir);
22
25
  return;
23
26
  }
24
- await registerWindowsAutostart(cliBinPath, dataDir);
27
+ if (p === 'win32') {
28
+ await registerWindowsAutostart(cliBinPath, dataDir);
29
+ return;
30
+ }
31
+ await registerLinuxAutostart(cliBinPath, dataDir);
25
32
  }
26
33
  async function unregisterAutostart() {
27
34
  const p = assertSupportedPlatform();
@@ -29,7 +36,11 @@ async function unregisterAutostart() {
29
36
  await unregisterMacosAutostart();
30
37
  return;
31
38
  }
32
- await unregisterWindowsAutostart();
39
+ if (p === 'win32') {
40
+ await unregisterWindowsAutostart();
41
+ return;
42
+ }
43
+ await unregisterLinuxAutostart();
33
44
  }
34
45
  export async function cmdServiceStart(cliBinPath, daysAgo) {
35
46
  assertSupportedPlatform();
package/package.json CHANGED
@@ -1,14 +1,18 @@
1
1
  {
2
2
  "name": "@juejin-opensource/jusage",
3
- "version": "0.1.3",
4
- "description": "本地优先的 AI Agent Token 用量看板 CLI(采集 + 本地面板 + 可选云端上报)",
3
+ "version": "0.1.6-beta.0",
4
+ "description": "Juejin AI Usage 统计 CLI:Token 用量明细追踪,本地记录、云端同步,内置用量看板。",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/juejin-cn/ai-usage.git",
9
+ "url": "git+https://github.com/juejin-cn/juejin-usage.git",
10
10
  "directory": "packages/cli"
11
11
  },
12
+ "bugs": {
13
+ "url": "https://github.com/juejin-cn/juejin-usage/issues"
14
+ },
15
+ "homepage": "https://github.com/juejin-cn/juejin-usage#readme",
12
16
  "keywords": [
13
17
  "ai",
14
18
  "token",
@@ -29,23 +33,24 @@
29
33
  "publishConfig": {
30
34
  "access": "public"
31
35
  },
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.json && node ./scripts/copy-dashboard.mjs",
38
+ "start": "node ./bin/jusage.js start",
39
+ "sync": "node ./bin/jusage.js sync",
40
+ "status": "node ./bin/jusage.js status",
41
+ "upload": "node ./bin/jusage.js upload",
42
+ "service": "node ./bin/jusage.js service",
43
+ "test": "tsc -p tsconfig.json && node --test \"test/**/*.test.js\""
44
+ },
32
45
  "dependencies": {
33
- "@juejin-opensource/jusage-core": "0.1.3"
46
+ "@juejin-opensource/jusage-core": "0.1.5"
34
47
  },
35
48
  "devDependencies": {
49
+ "@juejin-opensource/jusage-dashboard": "workspace:*",
36
50
  "@types/node": "^22.13.10",
37
- "typescript": "^5.8.2",
38
- "@juejin-opensource/jusage-dashboard": "0.1.3"
51
+ "typescript": "^5.8.2"
39
52
  },
40
53
  "engines": {
41
54
  "node": ">=20"
42
- },
43
- "scripts": {
44
- "build": "tsc -p tsconfig.json && node ./scripts/copy-dashboard.mjs",
45
- "start": "node ./bin/jusage.js start",
46
- "sync": "node ./bin/jusage.js sync",
47
- "status": "node ./bin/jusage.js status",
48
- "upload": "node ./bin/jusage.js upload",
49
- "service": "node ./bin/jusage.js service"
50
55
  }
51
- }
56
+ }