shine-code-submit 1.0.13 → 1.0.15

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/ui/.build/app.js CHANGED
@@ -73,4 +73,4 @@ Please report this to https://github.com/markedjs/marked.`,Y){let U="<p>An error
73
73
  `),U=String(G||"").split(`
74
74
  `),Z=X.length,A=U.length,z=Array.from({length:Z+1},()=>Array(A+1).fill(0));for(let M=Z-1;M>=0;M--)for(let q=A-1;q>=0;q--)z[M][q]=X[M]===U[q]?z[M+1][q+1]+1:Math.max(z[M+1][q],z[M][q+1]);let J=[],H=0,W=0;while(H<Z&&W<A)if(X[H]===U[W])J.push({op:"ctx",text:X[H]}),H++,W++;else if(z[H+1][W]>=z[H][W+1])J.push({op:"del",text:X[H]}),H++;else J.push({op:"add",text:U[W]}),W++;while(H<Z)J.push({op:"del",text:X[H]}),H++;while(W<A)J.push({op:"add",text:U[W]}),W++;return J}function iW(Y,G){let X=(U)=>{if(G&&typeof G==="object"){let Z=G[U];return Z!=null?String(Z):""}return""};switch(Y){case"Bash":return X("command");case"Read":case"Edit":case"Write":return X("file_path");case"Grep":case"Glob":return X("pattern");case"WebSearch":return X("query");case"WebFetch":return X("url");case"TaskCreate":return X("subject")||X("description");case"TaskUpdate":return"#"+X("taskId")+" → "+X("status");case"TaskGet":return"#"+X("taskId");case"TaskList":return"";case"Agent":return X("description");default:return FU(G).slice(0,80)}}var qQ={Bash:"▶",Read:"\uD83D\uDCC4",Edit:"✎",Write:"✎",Grep:"\uD83D\uDD0E",Glob:"\uD83D\uDDC2",WebSearch:"\uD83C\uDF10",WebFetch:"\uD83C\uDF10",TaskCreate:"\uD83D\uDCCC",TaskUpdate:"\uD83D\uDCCC",TaskGet:"\uD83D\uDCCC",TaskList:"\uD83D\uDCCC",Agent:"\uD83E\uDD16"};function pW(Y){return qQ[Y]??"\uD83D\uDEE0"}function rW(Y){let G=String(Y||"").split(`
75
75
  `),X=G.slice(0,50),U=X.map((Z)=>`<div class="diff-line ctx"><span class="diff-text">${RW(Z)}</span></div>`);if(G.length>X.length)U.push(`<div class="diff-folds">⋯ 共 ${G.length} 行,前 ${X.length} 行</div>`);return`<div class="diff-block">${U.join("")}</div>`}function oW({diffs:Y}){let G=[],X=[],U=0,Z=()=>{if(!X.length)return;if(X.length<=3)for(let A of X)G.push(B("div",{className:"diff-line ctx",children:B("span",{className:"diff-text",children:A.text})},U++));else{let A=X[0],z=X[X.length-1];G.push(B("div",{className:"diff-line ctx",children:B("span",{className:"diff-text",children:A.text})},U++)),G.push(O("div",{className:"diff-folds",children:["⋯ ",X.length-2," 行未改"]},U++)),G.push(B("div",{className:"diff-line ctx",children:B("span",{className:"diff-text",children:z.text})},U++))}X=[]};for(let A of Y){if(A.op==="ctx"){X.push(A);continue}if(Z(),A.op==="add")G.push(O("div",{className:"diff-line add",children:[B("span",{className:"diff-sign",children:"+"}),B("span",{className:"diff-text",children:A.text})]},U++));else G.push(O("div",{className:"diff-line del",children:[B("span",{className:"diff-sign",children:"-"}),B("span",{className:"diff-text",children:A.text})]},U++))}return Z(),B("div",{className:"diff-block",children:G})}function sW({t:Y}){let G=Y.name||"?",X=Y.input&&typeof Y.input==="object"?Y.input:{},U=(J)=>X[J]!=null?String(X[J]):"",Z=iW(G,X).slice(0,100),{body:A,stat:z}=f0(()=>{if(G==="Edit"){let J=lW(U("old_string"),U("new_string")),H=0,W=0;for(let M of J)if(M.op==="add")H++;else if(M.op==="del")W++;return{body:B(oW,{diffs:J}),stat:{add:H,del:W}}}if(G==="Write")return{body:B("div",{dangerouslySetInnerHTML:{__html:rW(U("content"))}}),stat:null};return{body:B("pre",{className:"card-output",children:FU(X)}),stat:null}},[G,X]);return O("details",{className:"tool-card",children:[O("summary",{className:"card-trigger",children:[B("span",{className:"card-chev",children:B(G0,{name:"chevron",size:12})}),B("span",{className:"tool-icon",children:pW(G)}),B("span",{className:"tool-title",children:G}),B("span",{className:"tool-sub",children:Z}),z&&O("span",{className:"tool-stat",children:[O("span",{className:"s-add",children:["+",z.add]})," ",O("span",{className:"s-del",children:["-",z.del]})]})]}),B("div",{className:"tool-content",children:A})]})}function aW({m:Y}){if(Y.role==="user")return B("div",{className:"msg-row user-row",children:B("div",{className:"bubble",children:Y.text})});if(Y.role==="tool")return B("div",{className:"msg-row",children:O("details",{className:`result-card${Y.isError?" is-error":""}`,children:[O("summary",{className:"card-trigger",children:[B("span",{className:"card-chev",children:B(G0,{name:"chevron",size:12})}),B("span",{className:"result-label",children:Y.toolName||"结果"})]}),B("pre",{className:"card-output",children:Y.text})]})});return O("div",{className:"msg-row assistant-row",children:[O("div",{className:"role-head",children:[B("span",{className:"role-mark",children:B(G0,{name:"diamond",size:10})}),B("span",{className:"role-name",children:"Claude"}),Y.usage&&B("span",{className:"role-tokens",title:d0(Y.usage),children:jG(Y.usage)}),Y.ts!=null&&B("span",{className:"role-ts",children:OW(Y.ts)})]}),Y.thinking&&O("details",{className:"think-card",children:[O("summary",{className:"card-trigger",children:[B("span",{className:"card-chev",children:B(G0,{name:"chevron",size:12})}),B("span",{className:"think-label",children:"Thinking"})]}),B("div",{className:"think-body",children:B(kz,{src:Y.thinking})})]}),Y.text&&B("div",{className:"assistant-text msg-text",children:B(kz,{src:Y.text})}),Y.tools.map((G,X)=>B(sW,{t:G},X))]})}function MQ(Y,G){if(!G)return!0;if((Y.text||"").toLowerCase().includes(G))return!0;if((Y.thinking||"").toLowerCase().includes(G))return!0;if((Y.toolName||"").toLowerCase().includes(G))return!0;return(Y.tools||[]).some((X)=>(X.name||"").toLowerCase().includes(G)||JSON.stringify(X.input).toLowerCase().includes(G))}function QQ(){return O(n,{children:[B("div",{className:"skeleton skel-bubble"}),B("div",{className:"skeleton skel-block"}),B("div",{className:"skeleton skel-bubble"}),B("div",{className:"skeleton skel-block",style:{width:"68%"}})]})}function nW({messages:Y,loading:G,error:X,search:U}){let Z=U.trim().toLowerCase(),A=f0(()=>Z?Y.filter((H)=>MQ(H,Z)):Y,[Y,Z]),z=f0(()=>DW(Y),[Y]),J;if(G&&Y.length===0)J=B(QQ,{});else if(X)J=O("div",{className:"empty-state",children:[B(G0,{name:"warning",size:28}),B("span",{className:"es-hint",children:"加载失败"}),B("span",{className:"es-sub",children:X})]});else if(!Y.length)J=O("div",{className:"empty-state",children:[B(G0,{name:"chat",size:30}),B("span",{className:"es-hint",children:"暂无对话"}),B("span",{className:"es-sub",children:"该会话无 transcript 或尚未产生对话"})]});else if(!A.length)J=O("div",{className:"empty-state",children:[B("span",{className:"es-hint",children:"无匹配消息"}),O("span",{className:"es-sub",children:["“",U,"” 未命中(0/",Y.length,")"]})]});else J=O(n,{children:[Z&&B("div",{className:"search-count",children:`${A.length}/${Y.length} 条匹配`}),A.map((H,W)=>B(aW,{m:H},W))]});return O("div",{id:"conversation",className:"conversation",children:[!G&&!X&&Y.length>0&&(z.input>0||z.output>0)&&O("div",{className:"conv-token-bar",title:d0(z),children:["本会话累计 ",B("b",{children:jG(z)}),O("span",{className:"conv-token-cache",children:[" ","· 缓存读 ",_0(z.cacheRead)," / 写 ",_0(z.cacheCreation)]})]}),J]})}function tW({sessionId:Y}){let{token:G,sessions:X}=t(),U=QY(G),[Z,A]=$(""),{messages:z,loading:J,error:H}=TW(U,Y,!0),W=X.find((q)=>q.sessionId===Y),M=W?.tokenTotal??null;return O("div",{className:"session-detail",children:[O("div",{className:"detail-head",children:[B("span",{className:"detail-sid",title:Y,children:Y.slice(0,8)}),W?.cwd&&B("span",{className:"detail-cwd",title:W.cwd,children:PG(W.cwd)}),M&&m0(M)>0&&B("span",{className:"detail-token",title:d0(M),children:VU(M)})]}),B("div",{className:"toolbar",children:B("input",{className:"search-input",type:"search",placeholder:"搜索对话…",value:Z,onChange:(q)=>A(q.target.value),autoComplete:"off"})}),B("div",{className:"detail-body",children:B(nW,{messages:z,loading:J,error:H,search:Z})})]})}X0();function eW(Y,G){let X=LY(null),U=Q7((Z)=>{Z.preventDefault();let A=X.current;if(!A)return;A.classList.add("dragging"),document.body.style.cursor=Y==="v"?"col-resize":"row-resize",document.body.style.userSelect="none";let{clientX:z,clientY:J}=Z,H=document.documentElement,W=Y==="v"?G??"--nav-w":"--footer-h",M=parseFloat(getComputedStyle(H).getPropertyValue(W))||200,q=parseFloat(getComputedStyle(H).getPropertyValue("--footer-h"))||170,Q=(V)=>{if(Y==="v")H.style.setProperty(W,Math.max(140,M+(V.clientX-z))+"px");else H.style.setProperty("--footer-h",Math.max(60,q-(V.clientY-J))+"px")},L=()=>{A.classList.remove("dragging"),document.body.style.cursor="",document.body.style.userSelect="",document.removeEventListener("mousemove",Q),document.removeEventListener("mouseup",L)};document.addEventListener("mousemove",Q),document.addEventListener("mouseup",L)},[Y,G]);return{ref:X,onMouseDown:U}}function CU({orient:Y,hidden:G,varName:X}){let{ref:U,onMouseDown:Z}=eW(Y,X),A=`splitter splitter-${Y}${G?" hidden":""}`;return B("div",{ref:U,className:A,"data-orient":Y,onMouseDown:Z,title:Y==="v"?"拖拽调整宽度":"拖拽调整高度"})}function Y4(){let{selectedSessionId:Y,setSelectedSessionId:G,sessions:X}=t();return B0(()=>{let U=X[0];if(!Y&&U)G(U.sessionId)},[Y,X,G]),O("div",{className:"sessions-with-tree",children:[B("aside",{className:"sessions-tree-panel panel",children:B(NW,{})}),B(CU,{orient:"v",varName:"--tree-w"}),B("div",{className:"sessions-main",children:Y?B(tW,{sessionId:Y}):O("div",{className:"empty-state",children:[B(G0,{name:"chat",size:30}),B("span",{className:"es-hint",children:"暂无会话"}),B("span",{className:"es-sub",children:"启动 Claude Code 后会出现"})]})})]})}X0();X0();function G4(Y,G,X){let[U,Z]=$([]),[A,z]=$(!1),[J,H]=$(null),W=LY(void 0);return B0(()=>{if(!X)return;if(W.current!==G)Z([]),W.current=G;let M=!0;return z(!0),H(null),(async()=>{try{let q=G?"?sessionId="+encodeURIComponent(G)+"&limit=200":"?limit=200",Q=await Y("/api/events"+q);if(M)Z(Q.events),H(null)}catch(q){if(M)H(q instanceof Error?q.message:String(q))}finally{if(M)z(!1)}})(),()=>{M=!1}},[Y,G,X]),{events:U,loading:A,error:J}}X0();function X4(Y,G,X){let[U,Z]=$([]),[A,z]=$(!1),J=LY("");return B0(()=>{if(!X)return;let H=Array.from(new Set(G.map((q)=>q.cwd).filter(Boolean))),W=H.join(`
76
- `);if(J.current===W)return;if(J.current=W,H.length===0){Z([]);return}let M=!0;return z(!0),(async()=>{try{let q=await Promise.all(H.map(async(L)=>{try{let V=await Y(`/api/commits?cwd=${encodeURIComponent(L)}&limit=200`);return{cwd:L,commits:V.commits??[]}}catch{return{cwd:L,commits:[]}}}));if(!M)return;let Q=q.flatMap((L)=>L.commits.map((V)=>({...V,cwd:L.cwd})));Q.sort((L,V)=>V.time-L.time),Z(Q)}finally{if(M)z(!1)}})(),()=>{M=!1}},[Y,G,X]),{commits:U,loading:A}}function xz(){let{token:Y,sessions:G,stats:X}=t(),U=QY(Y),{events:Z}=G4(U,null,!0),{commits:A}=X4(U,G,!0),[z,J]=$(null);B0(()=>{let M=!1;return U("/api/report?since=0").then((q)=>!M&&J(q)).catch(()=>{}),()=>{M=!0}},[U]);let H=z?.totals.tokens??null,W=f0(()=>{let M=Z.slice(0,20).map((Q)=>({ts:Q.timestamp,kind:"event",text:Q.type,cwd:Q.cwd})),q=A.slice(0,20).map((Q)=>({ts:Q.time,kind:"commit",text:Q.subject||"(无说明)",cwd:Q.cwd}));return[...M,...q].sort((Q,L)=>L.ts-Q.ts).slice(0,20)},[Z,A]);return O("div",{className:"overview-view",children:[O("div",{className:"kpi-grid",children:[O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"Token 总量"}),B("b",{className:"kpi-value",children:H?_0(m0(H)):"…"})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"Token 输出"}),B("b",{className:"kpi-value",children:H?_0(H.output):"…"})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"会话数"}),B("b",{className:"kpi-value",children:z?.totals.sessions??G.length})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"事件总数"}),B("b",{className:"kpi-value",children:X?.totalEvents??0})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"提交数"}),B("b",{className:"kpi-value",children:A.length})]})]}),O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"近期活动"})}),W.length===0?B("div",{className:"sum-empty",children:"暂无活动"}):B("ul",{className:"sum-list",children:W.map((M,q)=>O("li",{children:[B("span",{className:"sum-ts",children:SG(M.ts)}),B("span",{className:`tl-kind ${M.kind}`,children:M.kind==="event"?"事件":"提交"}),B("span",{className:"sum-cwd",title:M.cwd,children:PG(M.cwd)||"?"}),B("span",{className:"sum-subject",children:M.text})]},q))})]})]})}X0();var $U=20;function U4(){let{token:Y}=t(),G=QY(Y),[X,U]=$(null),[Z,A]=$(null),[z,J]=$(null),[H,W]=$(!1),[M,q]=$(null);B0(()=>{let L=!1;return A(null),G("/api/report?since=0").then((V)=>!L&&U(V)).catch((V)=>!L&&A(String(V))),()=>{L=!0}},[G]),B0(()=>{if(X&&!z&&X.projects[0])J(X.projects[0].cwd)},[X,z]);let Q=X?.projects.find((L)=>L.cwd===z)??null;return O("div",{className:"stats-view",children:[B("div",{className:"panel-header",style:{display:"flex",gap:"1.1rem",alignItems:"baseline",flexWrap:"wrap"},children:X?O(n,{children:[B("b",{children:"报表"}),O("span",{title:"软件版本",children:["v",X.version]}),O("span",{title:"git 用户",children:["\uD83D\uDC64 ",X.gitUser??"—"]}),O("span",{children:[X.totals.projects," 项目 · ",X.totals.sessions," 会话"]}),O("button",{type:"button",className:"tab",disabled:H,title:"手动上报报表到服务器(需先在「设置」配置上报地址)",style:{marginLeft:"auto"},onClick:async()=>{W(!0),q(null);try{let L=await fetch(`${location.origin}/api/report/upload`,{method:"POST",headers:{Authorization:`Bearer ${Y}`}}),V=await L.json().catch(()=>({}));if(L.ok&&V.status==="ok")q({ok:!0,text:"上报成功"});else if(L.ok&&V.status==="skipped")q({ok:!1,text:`已跳过:${V.reason??"无 git 身份"}`});else q({ok:!1,text:V.error??`HTTP ${L.status}`})}catch(L){q({ok:!1,text:L instanceof Error?L.message:String(L)})}finally{W(!1),setTimeout(()=>q(null),3000)}},children:["☁ ",H?"上报中…":"上报"]}),M&&B("span",{className:M.ok?"field-ok":"field-err",children:M.text})]}):B("span",{children:Z?`加载失败:${Z}`:"加载中…"})}),O("div",{className:"sessions-with-tree",children:[O("aside",{className:"sessions-tree-panel panel",children:[B("div",{className:"panel-header",children:O("h2",{children:["项目 · ",X?.projects.length??0]})}),!X||X.projects.length===0?O("div",{className:"empty-state",style:{padding:"2rem 1rem"},children:[B("span",{className:"es-hint",children:"暂无项目"}),B("span",{className:"es-sub",children:"启动 Claude Code 后会出现"})]}):B("ul",{className:"report-nav",children:X.projects.map((L)=>O("li",{className:L.cwd===z?"active":void 0,title:L.cwd,onClick:()=>J(L.cwd),style:{display:"flex",justifyContent:"space-between",alignItems:"baseline",gap:"0.5rem"},children:[B("span",{children:PG(L.cwd)||L.cwd}),B("span",{className:"nav-tokens",title:d0(L.totalTokens),children:_0(m0(L.totalTokens))})]},L.cwd))})]}),B(CU,{orient:"v",varName:"--tree-w"}),B("div",{className:"sessions-main",children:Q?B(_Q,{p:Q},Q.cwd):O("div",{className:"empty-state",children:[B(G0,{name:"log",size:30}),B("span",{className:"es-hint",children:"选左侧项目查看详情"})]})})]})]})}function _Q({p:Y}){let[G,X]=$(1),U=Y.sessions.filter((J)=>J.tokenTotal&&m0(J.tokenTotal)>0),Z=Math.max(1,Math.ceil(U.length/$U)),A=Math.min(G,Z),z=U.slice((A-1)*$U,A*$U);return O(n,{children:[O("div",{className:"report-title",children:[Y.gitRemote&&O("span",{className:"rt-sum",title:Y.gitRemote,style:{flex:"0 0 60ch",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:["\uD83D\uDD17 ",Y.gitRemote]}),B("span",{className:"rt-sum",title:d0(Y.totalTokens),style:{marginLeft:"auto",color:"#9dbefe"},children:VU(Y.totalTokens)}),O("span",{className:"rt-sum",title:`代码变更 +${Y.totalLines.added} -${Y.totalLines.deleted} M${Y.totalLines.modified}`,style:{color:"#9aa"},children:["+",Y.totalLines.added," -",Y.totalLines.deleted," M",Y.totalLines.modified]})]}),O("div",{style:{overflow:"auto",flex:"1 1 0",minHeight:0},children:[O("table",{className:"report-table",children:[B("thead",{children:O("tr",{children:[B("th",{className:"rt-idx",children:"#"}),B("th",{children:"Session"}),B("th",{children:"时间"}),B("th",{className:"rt-num",children:"输入 token"}),B("th",{className:"rt-num",children:"输出 token"}),B("th",{className:"rt-num",children:"总数"}),B("th",{className:"rt-num",children:"代码变更"})]})}),B("tbody",{children:z.map((J,H)=>O("tr",{children:[B("td",{className:"rt-idx",children:(A-1)*$U+H+1}),B("td",{className:"rt-sid",title:J.sessionId,children:J.sessionId.slice(0,8)}),B("td",{children:SG(J.lastActive)}),B("td",{className:"rt-num",children:_0(J.tokenTotal.input)}),B("td",{className:"rt-num",children:_0(J.tokenTotal.output)}),B("td",{className:"rt-num",children:_0(m0(J.tokenTotal))}),B("td",{className:"rt-num",title:J.linesTotal?`+${J.linesTotal.added} -${J.linesTotal.deleted} M${J.linesTotal.modified}`:"",children:J.linesTotal?`+${J.linesTotal.added} -${J.linesTotal.deleted} M${J.linesTotal.modified}`:"-"})]},J.sessionId))})]}),U.length===0&&B("div",{className:"sum-empty",children:"无有效会话(均已隐藏 0 token)"})]}),O("div",{className:"report-pager",children:[B("button",{type:"button",disabled:A<=1,onClick:()=>X(A-1),children:"‹ 上一页"}),O("span",{children:["第 ",A," / ",Z," 页"]}),B("button",{type:"button",disabled:A>=Z,onClick:()=>X(A+1),children:"下一页 ›"}),O("span",{style:{marginLeft:"auto"},children:["共 ",U.length," 个会话(已隐藏 0 token)"]})]})]})}X0();function Z4(){let{token:Y}=t(),G=QY(Y),X=location.origin,[U,Z]=$(""),[A,z]=$(""),[J,H]=$(!0),[W,M]=$(""),[q,Q]=$(""),[L,V]=$(null),[f,E]=$(!0),[w,_]=$(!1),[R,D]=$(null);B0(()=>{Promise.all([G("/api/settings"),fetch(X+"/api/health").then((N)=>N.json())]).then(([N,K])=>{Z(N.reportUrl??""),z(N.reportIntervalMin!=null?String(N.reportIntervalMin):""),H(N.autoUpdate!==!1),M(N.autoUpdateIntervalMin!=null?String(N.autoUpdateIntervalMin):""),V(N.latestVersion??null),Q(K.version??""),E(!1)}).catch(()=>{D({kind:"err",text:"读取设置失败"}),E(!1)})},[G,X]);let I=async()=>{_(!0),D(null);let N=parseInt(A,10),K=parseInt(W,10),b={reportUrl:U.trim()||null,reportIntervalMin:Number.isFinite(N)&&N>0?N:null,autoUpdate:J,autoUpdateIntervalMin:Number.isFinite(K)&&K>0?K:null};try{let S=await fetch(X+"/api/settings",{method:"PUT",headers:{Authorization:"Bearer "+Y,"content-type":"application/json"},body:JSON.stringify(b)});if(!S.ok)throw Error(String(S.status));let j=await S.json();Z(j.reportUrl??""),z(j.reportIntervalMin!=null?String(j.reportIntervalMin):""),H(j.autoUpdate!==!1),M(j.autoUpdateIntervalMin!=null?String(j.autoUpdateIntervalMin):""),D({kind:"ok",text:"已保存"}),setTimeout(()=>D(null),2000)}catch{D({kind:"err",text:"保存失败,请重试"})}finally{_(!1)}};return O("div",{className:"stats-view",children:[B("div",{className:"panel-header",children:B("h2",{children:"设置"})}),B("div",{className:"stats-body",children:f?B("div",{className:"sum-empty",children:"加载中…"}):O(n,{children:[O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"上报"})}),O("div",{className:"field-row",children:[B("label",{children:"上报地址"}),B("input",{className:"field-input",type:"url",placeholder:"https://your-server/api/report",value:U,onChange:(N)=>Z(N.target.value),spellCheck:!1})]}),O("div",{className:"field-row",children:[B("label",{children:"上报间隔"}),B("input",{className:"field-input",type:"number",min:1,placeholder:"0 = 不自动上报",value:A,onChange:(N)=>z(N.target.value),spellCheck:!1,style:{flex:"0 0 120px"}}),B("span",{className:"field-hint",style:{padding:0},children:"分钟(填了地址且间隔大于 0 才会自动上报)"})]}),B("div",{className:"field-hint",children:"daemon 每分钟检查一次:地址 + 间隔都配了,就把「报表」数据 POST 到该地址;留空 / 间隔 0 = 不上报。改完无需重启。"})]}),O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"自动更新"})}),O("div",{className:"field-row",children:[B("label",{children:"版本"}),O("span",{className:"field-hint",style:{padding:0},children:["当前 v",q||"?",L&&L!==q?`(npm 最新 v${L})`:"(已是最新)"]})]}),O("div",{className:"field-row",children:[B("label",{children:"自动更新"}),B("input",{type:"checkbox",checked:J,onChange:(N)=>H(N.target.checked)}),B("span",{className:"field-hint",style:{padding:0},children:"开启后 daemon 启动时 + 定时检测 npm 新版本,有新版自动后台升级"})]}),O("div",{className:"field-row",children:[B("label",{children:"检测间隔"}),B("input",{className:"field-input",type:"number",min:1,placeholder:"60",value:W,onChange:(N)=>M(N.target.value),style:{flex:"0 0 120px"}}),B("span",{className:"field-hint",style:{padding:0},children:"分钟(daemon 每分钟 tick,按此间隔节流)"})]}),O("div",{className:"field-row",children:[B("label",{})," ",B("button",{type:"button",className:"tab",onClick:I,disabled:w,title:"保存设置",children:w?"保存中…":"保存"}),R&&B("span",{className:R.kind==="ok"?"field-ok":"field-err",children:R.text})]}),O("div",{className:"field-hint",children:["升级后 daemon 自动重启到新版(版本感知);plugin 需重启 Claude Code 生效。也可命令行手动 ",B("code",{children:"shine-code-submit update"}),"。"]})]})]})})]})}function A4(){let{stats:Y}=t();if(!Y)return B("div",{className:"empty-state",children:B("span",{className:"es-hint",children:"连接中…"})});let G=Math.floor(Y.uptime/1000);return B("div",{className:"system-view",children:O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"Daemon"})}),O("div",{className:"sys-grid",children:[O("div",{className:"sys-row",children:[B("span",{children:"服务"}),B("b",{children:Y.service})]}),O("div",{className:"sys-row",children:[B("span",{children:"版本"}),O("b",{children:["v",Y.version]})]}),O("div",{className:"sys-row",children:[B("span",{children:"pid"}),B("b",{children:Y.pid})]}),O("div",{className:"sys-row",children:[B("span",{children:"uptime"}),O("b",{children:[G,"s"]})]}),O("div",{className:"sys-row",children:[B("span",{children:"事件总数"}),B("b",{children:Y.totalEvents})]}),O("div",{className:"sys-row",children:[B("span",{children:"事件速率"}),O("b",{children:[Y.eventsPerSec.toFixed(1)," evt/s"]})]}),O("div",{className:"sys-row",children:[B("span",{children:"spool 积压"}),B("b",{children:Y.spoolBacklog})]}),Y.lastError&&O("div",{className:"sys-row err",children:[B("span",{children:"最近错误"}),B("b",{children:Y.lastError.message})]})]})]})})}function LQ(){let{activeModule:Y}=t();switch(Y){case"overview":return B(xz,{});case"sessions":return B(Y4,{});case"report":return B(U4,{});case"settings":return B(Z4,{});case"system":return B(A4,{});default:return B(xz,{})}}function wQ(){let{navCollapsed:Y}=t();return O(n,{children:[B(KW,{}),O("div",{className:"body-middle",children:[B("aside",{id:"nav-panel",className:`panel${Y?" collapsed":""}`,children:B(fW,{})}),B("section",{id:"events-panel",className:"panel",children:B(LQ,{})})]})]})}function z4({token:Y}){return B(wW,{token:Y,children:B(wQ,{})})}var J4="shine_code_submit_token";function RQ(){let Y=new URLSearchParams(location.search).get("t");if(Y)return sessionStorage.setItem(J4,Y),history.replaceState(null,"",location.pathname),Y;return sessionStorage.getItem(J4)}var H4=RQ(),W4=document.getElementById("root");if(!H4)W4.innerHTML='<div style="padding:2rem;font-family:sans-serif;color:#ccc;background:#0f1115;min-height:100vh">'+"缺少 token。请通过 <code>shine-code-submit ui</code> 命令打开。</div>";else B4.createRoot(W4).render(B(jU,{children:B(z4,{token:H4})}));
76
+ `);if(J.current===W)return;if(J.current=W,H.length===0){Z([]);return}let M=!0;return z(!0),(async()=>{try{let q=await Promise.all(H.map(async(L)=>{try{let V=await Y(`/api/commits?cwd=${encodeURIComponent(L)}&limit=200`);return{cwd:L,commits:V.commits??[]}}catch{return{cwd:L,commits:[]}}}));if(!M)return;let Q=q.flatMap((L)=>L.commits.map((V)=>({...V,cwd:L.cwd})));Q.sort((L,V)=>V.time-L.time),Z(Q)}finally{if(M)z(!1)}})(),()=>{M=!1}},[Y,G,X]),{commits:U,loading:A}}function xz(){let{token:Y,sessions:G,stats:X}=t(),U=QY(Y),{events:Z}=G4(U,null,!0),{commits:A}=X4(U,G,!0),[z,J]=$(null);B0(()=>{let M=!1;return U("/api/report?since=0").then((q)=>!M&&J(q)).catch(()=>{}),()=>{M=!0}},[U]);let H=z?.totals.tokens??null,W=f0(()=>{let M=Z.slice(0,20).map((Q)=>({ts:Q.timestamp,kind:"event",text:Q.type,cwd:Q.cwd})),q=A.slice(0,20).map((Q)=>({ts:Q.time,kind:"commit",text:Q.subject||"(无说明)",cwd:Q.cwd}));return[...M,...q].sort((Q,L)=>L.ts-Q.ts).slice(0,20)},[Z,A]);return O("div",{className:"overview-view",children:[O("div",{className:"kpi-grid",children:[O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"Token 总量"}),B("b",{className:"kpi-value",children:H?_0(m0(H)):"…"})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"Token 输出"}),B("b",{className:"kpi-value",children:H?_0(H.output):"…"})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"会话数"}),B("b",{className:"kpi-value",children:z?.totals.sessions??G.length})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"事件总数"}),B("b",{className:"kpi-value",children:X?.totalEvents??0})]}),O("div",{className:"kpi-card",children:[B("span",{className:"kpi-label",children:"提交数"}),B("b",{className:"kpi-value",children:A.length})]})]}),O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"近期活动"})}),W.length===0?B("div",{className:"sum-empty",children:"暂无活动"}):B("ul",{className:"sum-list",children:W.map((M,q)=>O("li",{children:[B("span",{className:"sum-ts",children:SG(M.ts)}),B("span",{className:`tl-kind ${M.kind}`,children:M.kind==="event"?"事件":"提交"}),B("span",{className:"sum-cwd",title:M.cwd,children:PG(M.cwd)||"?"}),B("span",{className:"sum-subject",children:M.text})]},q))})]})]})}X0();var $U=20;function U4(){let{token:Y}=t(),G=QY(Y),[X,U]=$(null),[Z,A]=$(null),[z,J]=$(null),[H,W]=$(!1),[M,q]=$(null);B0(()=>{let L=!1;return A(null),G("/api/report?since=0").then((V)=>!L&&U(V)).catch((V)=>!L&&A(String(V))),()=>{L=!0}},[G]),B0(()=>{if(X&&!z&&X.projects[0])J(X.projects[0].cwd)},[X,z]);let Q=X?.projects.find((L)=>L.cwd===z)??null;return O("div",{className:"stats-view",children:[B("div",{className:"panel-header",style:{display:"flex",gap:"1.1rem",alignItems:"baseline",flexWrap:"wrap"},children:X?O(n,{children:[B("b",{children:"报表"}),O("span",{title:"软件版本",children:["v",X.version]}),O("span",{title:"git 用户",children:["\uD83D\uDC64 ",X.gitUser??"—"]}),O("span",{children:[X.totals.projects," 项目 · ",X.totals.sessions," 会话"]}),O("button",{type:"button",className:"tab",disabled:H,title:"手动上报报表到服务器(需先在「设置」配置上报地址)",style:{marginLeft:"auto"},onClick:async()=>{W(!0),q(null);try{let L=await fetch(`${location.origin}/api/report/upload`,{method:"POST",headers:{Authorization:`Bearer ${Y}`}}),V=await L.json().catch(()=>({}));if(L.ok&&V.status==="ok")q({ok:!0,text:"上报成功"});else if(L.ok&&V.status==="skipped")q({ok:!1,text:`已跳过:${V.reason??"无 git 身份"}`});else q({ok:!1,text:V.error??`HTTP ${L.status}`})}catch(L){q({ok:!1,text:L instanceof Error?L.message:String(L)})}finally{W(!1),setTimeout(()=>q(null),3000)}},children:["☁ ",H?"上报中…":"上报"]}),M&&B("span",{className:M.ok?"field-ok":"field-err",children:M.text})]}):B("span",{children:Z?`加载失败:${Z}`:"加载中…"})}),O("div",{className:"sessions-with-tree",children:[O("aside",{className:"sessions-tree-panel panel",children:[B("div",{className:"panel-header",children:O("h2",{children:["项目 · ",X?.projects.length??0]})}),!X||X.projects.length===0?O("div",{className:"empty-state",style:{padding:"2rem 1rem"},children:[B("span",{className:"es-hint",children:"暂无项目"}),B("span",{className:"es-sub",children:"启动 Claude Code 后会出现"})]}):B("ul",{className:"report-nav",children:X.projects.map((L)=>O("li",{className:L.cwd===z?"active":void 0,title:L.cwd,onClick:()=>J(L.cwd),style:{display:"flex",justifyContent:"space-between",alignItems:"baseline",gap:"0.5rem"},children:[B("span",{children:L.name||PG(L.cwd)||L.cwd}),B("span",{className:"nav-tokens",title:d0(L.totalTokens),children:_0(m0(L.totalTokens))})]},L.cwd))})]}),B(CU,{orient:"v",varName:"--tree-w"}),B("div",{className:"sessions-main",children:Q?B(_Q,{p:Q},Q.cwd):O("div",{className:"empty-state",children:[B(G0,{name:"log",size:30}),B("span",{className:"es-hint",children:"选左侧项目查看详情"})]})})]})]})}function _Q({p:Y}){let[G,X]=$(1),U=Y.sessions.filter((J)=>J.tokenTotal&&m0(J.tokenTotal)>0),Z=Math.max(1,Math.ceil(U.length/$U)),A=Math.min(G,Z),z=U.slice((A-1)*$U,A*$U);return O(n,{children:[O("div",{className:"report-title",children:[Y.gitRemote&&O("span",{className:"rt-sum",title:Y.gitRemote,style:{flex:"0 0 60ch",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:["\uD83D\uDD17 ",Y.gitRemote]}),B("span",{className:"rt-sum",title:d0(Y.totalTokens),style:{marginLeft:"auto",color:"#9dbefe"},children:VU(Y.totalTokens)}),O("span",{className:"rt-sum",title:`代码变更 +${Y.totalLines.added} -${Y.totalLines.deleted} M${Y.totalLines.modified}`,style:{color:"#9aa"},children:["+",Y.totalLines.added," -",Y.totalLines.deleted," M",Y.totalLines.modified]})]}),O("div",{style:{overflow:"auto",flex:"1 1 0",minHeight:0},children:[O("table",{className:"report-table",children:[B("thead",{children:O("tr",{children:[B("th",{className:"rt-idx",children:"#"}),B("th",{children:"Session"}),B("th",{children:"时间"}),B("th",{className:"rt-num",children:"输入 token"}),B("th",{className:"rt-num",children:"输出 token"}),B("th",{className:"rt-num",children:"总数"}),B("th",{className:"rt-num",children:"代码变更"})]})}),B("tbody",{children:z.map((J,H)=>O("tr",{children:[B("td",{className:"rt-idx",children:(A-1)*$U+H+1}),B("td",{className:"rt-sid",title:J.sessionId,children:J.sessionId.slice(0,8)}),B("td",{children:SG(J.lastActive)}),B("td",{className:"rt-num",children:_0(J.tokenTotal.input)}),B("td",{className:"rt-num",children:_0(J.tokenTotal.output)}),B("td",{className:"rt-num",children:_0(m0(J.tokenTotal))}),B("td",{className:"rt-num",title:J.linesTotal?`+${J.linesTotal.added} -${J.linesTotal.deleted} M${J.linesTotal.modified}`:"",children:J.linesTotal?`+${J.linesTotal.added} -${J.linesTotal.deleted} M${J.linesTotal.modified}`:"-"})]},J.sessionId))})]}),U.length===0&&B("div",{className:"sum-empty",children:"无有效会话(均已隐藏 0 token)"})]}),O("div",{className:"report-pager",children:[B("button",{type:"button",disabled:A<=1,onClick:()=>X(A-1),children:"‹ 上一页"}),O("span",{children:["第 ",A," / ",Z," 页"]}),B("button",{type:"button",disabled:A>=Z,onClick:()=>X(A+1),children:"下一页 ›"}),O("span",{style:{marginLeft:"auto"},children:["共 ",U.length," 个会话(已隐藏 0 token)"]})]})]})}X0();function Z4(){let{token:Y}=t(),G=QY(Y),X=location.origin,[U,Z]=$(""),[A,z]=$(""),[J,H]=$(!0),[W,M]=$(""),[q,Q]=$(""),[L,V]=$(null),[f,E]=$(!0),[w,_]=$(!1),[R,D]=$(null);B0(()=>{Promise.all([G("/api/settings"),fetch(X+"/api/health").then((N)=>N.json())]).then(([N,K])=>{Z(N.reportUrl??""),z(N.reportIntervalMin!=null?String(N.reportIntervalMin):""),H(N.autoUpdate!==!1),M(N.autoUpdateIntervalMin!=null?String(N.autoUpdateIntervalMin):""),V(N.latestVersion??null),Q(K.version??""),E(!1)}).catch(()=>{D({kind:"err",text:"读取设置失败"}),E(!1)})},[G,X]);let I=async()=>{_(!0),D(null);let N=parseInt(A,10),K=parseInt(W,10),b={reportUrl:U.trim()||null,reportIntervalMin:Number.isFinite(N)&&N>0?N:null,autoUpdate:J,autoUpdateIntervalMin:Number.isFinite(K)&&K>0?K:null};try{let S=await fetch(X+"/api/settings",{method:"PUT",headers:{Authorization:"Bearer "+Y,"content-type":"application/json"},body:JSON.stringify(b)});if(!S.ok)throw Error(String(S.status));let j=await S.json();Z(j.reportUrl??""),z(j.reportIntervalMin!=null?String(j.reportIntervalMin):""),H(j.autoUpdate!==!1),M(j.autoUpdateIntervalMin!=null?String(j.autoUpdateIntervalMin):""),D({kind:"ok",text:"已保存"}),setTimeout(()=>D(null),2000)}catch{D({kind:"err",text:"保存失败,请重试"})}finally{_(!1)}};return O("div",{className:"stats-view",children:[B("div",{className:"panel-header",children:B("h2",{children:"设置"})}),B("div",{className:"stats-body",children:f?B("div",{className:"sum-empty",children:"加载中…"}):O(n,{children:[O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"上报"})}),O("div",{className:"field-row",children:[B("label",{children:"上报地址"}),B("input",{className:"field-input",type:"url",placeholder:"https://your-server/api/report",value:U,onChange:(N)=>Z(N.target.value),spellCheck:!1})]}),O("div",{className:"field-row",children:[B("label",{children:"上报间隔"}),B("input",{className:"field-input",type:"number",min:1,placeholder:"0 = 不自动上报",value:A,onChange:(N)=>z(N.target.value),spellCheck:!1,style:{flex:"0 0 120px"}}),B("span",{className:"field-hint",style:{padding:0},children:"分钟(填了地址且间隔大于 0 才会自动上报)"})]}),B("div",{className:"field-hint",children:"daemon 每分钟检查一次:地址 + 间隔都配了,就把「报表」数据 POST 到该地址;留空 / 间隔 0 = 不上报。改完无需重启。"})]}),O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"自动更新"})}),O("div",{className:"field-row",children:[B("label",{children:"版本"}),O("span",{className:"field-hint",style:{padding:0},children:["当前 v",q||"?",L&&L!==q?`(npm 最新 v${L})`:"(已是最新)"]})]}),O("div",{className:"field-row",children:[B("label",{children:"自动更新"}),B("input",{type:"checkbox",checked:J,onChange:(N)=>H(N.target.checked)}),B("span",{className:"field-hint",style:{padding:0},children:"开启后 daemon 启动时 + 定时检测 npm 新版本,有新版自动后台升级"})]}),O("div",{className:"field-row",children:[B("label",{children:"检测间隔"}),B("input",{className:"field-input",type:"number",min:1,placeholder:"60",value:W,onChange:(N)=>M(N.target.value),style:{flex:"0 0 120px"}}),B("span",{className:"field-hint",style:{padding:0},children:"分钟(daemon 每分钟 tick,按此间隔节流)"})]}),O("div",{className:"field-row",children:[B("label",{})," ",B("button",{type:"button",className:"tab",onClick:I,disabled:w,title:"保存设置",children:w?"保存中…":"保存"}),R&&B("span",{className:R.kind==="ok"?"field-ok":"field-err",children:R.text})]}),O("div",{className:"field-hint",children:["升级后 daemon 自动重启到新版(版本感知);plugin 需重启 Claude Code 生效。也可命令行手动 ",B("code",{children:"shine-code-submit update"}),"。"]})]})]})})]})}function A4(){let{stats:Y}=t();if(!Y)return B("div",{className:"empty-state",children:B("span",{className:"es-hint",children:"连接中…"})});let G=Math.floor(Y.uptime/1000);return B("div",{className:"system-view",children:O("section",{className:"sum-section",children:[B("div",{className:"sum-head",children:B("h3",{children:"Daemon"})}),O("div",{className:"sys-grid",children:[O("div",{className:"sys-row",children:[B("span",{children:"服务"}),B("b",{children:Y.service})]}),O("div",{className:"sys-row",children:[B("span",{children:"版本"}),O("b",{children:["v",Y.version]})]}),O("div",{className:"sys-row",children:[B("span",{children:"pid"}),B("b",{children:Y.pid})]}),O("div",{className:"sys-row",children:[B("span",{children:"uptime"}),O("b",{children:[G,"s"]})]}),O("div",{className:"sys-row",children:[B("span",{children:"事件总数"}),B("b",{children:Y.totalEvents})]}),O("div",{className:"sys-row",children:[B("span",{children:"事件速率"}),O("b",{children:[Y.eventsPerSec.toFixed(1)," evt/s"]})]}),O("div",{className:"sys-row",children:[B("span",{children:"spool 积压"}),B("b",{children:Y.spoolBacklog})]}),Y.lastError&&O("div",{className:"sys-row err",children:[B("span",{children:"最近错误"}),B("b",{children:Y.lastError.message})]})]})]})})}function LQ(){let{activeModule:Y}=t();switch(Y){case"overview":return B(xz,{});case"sessions":return B(Y4,{});case"report":return B(U4,{});case"settings":return B(Z4,{});case"system":return B(A4,{});default:return B(xz,{})}}function wQ(){let{navCollapsed:Y}=t();return O(n,{children:[B(KW,{}),O("div",{className:"body-middle",children:[B("aside",{id:"nav-panel",className:`panel${Y?" collapsed":""}`,children:B(fW,{})}),B("section",{id:"events-panel",className:"panel",children:B(LQ,{})})]})]})}function z4({token:Y}){return B(wW,{token:Y,children:B(wQ,{})})}var J4="shine_code_submit_token";function RQ(){let Y=new URLSearchParams(location.search).get("t");if(Y)return sessionStorage.setItem(J4,Y),history.replaceState(null,"",location.pathname),Y;return sessionStorage.getItem(J4)}var H4=RQ(),W4=document.getElementById("root");if(!H4)W4.innerHTML='<div style="padding:2rem;font-family:sans-serif;color:#ccc;background:#0f1115;min-height:100vh">'+"缺少 token。请通过 <code>shine-code-submit ui</code> 命令打开。</div>";else B4.createRoot(W4).render(B(jU,{children:B(z4,{token:H4})}));
@@ -115,7 +115,7 @@ export function ReportModule() {
115
115
  onClick={() => setSelCwd(p.cwd)}
116
116
  style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: "0.5rem" }}
117
117
  >
118
- <span>{shortDir(p.cwd) || p.cwd}</span>
118
+ <span>{p.name || shortDir(p.cwd) || p.cwd}</span>
119
119
  <span className="nav-tokens" title={fmtUsageFull(p.totalTokens)}>
120
120
  {fmtTokens(rawTotal(p.totalTokens))}
121
121
  </span>