cicy-desktop 2.1.106 → 2.1.107

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cicy-desktop",
3
- "version": "2.1.106",
3
+ "version": "2.1.107",
4
4
  "description": "CiCy - AI-powered operating system browser",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -362,4 +362,4 @@ Error generating stack: `+l.message+`
362
362
  > - Backend gating: Section 4 corresponds to the \`~/cicy-ai/mitm/ca-trust-consent\` flag + \`exec cicy-code mitm install-ca/uninstall-ca\`.
363
363
  > - Container/headless deployment: if using the \`CICY_CA_TRUST_CONSENT=1\` escape hatch, "setting this environment variable means the deployer has, on behalf of its environment, given the notice and consent under Section 4.4"; responsibility rests with the deployer and this must be documented.
364
364
  > - Production: zh + en (EU) bilingual; wording of Sections 3C/6/8 may be adjusted per jurisdiction; high-risk authorizations should retain a user-revocable audit log as evidence of consent.
365
- `},w=(o,A)=>{var T,r;try{const D=(r=(T=window.cicyI18n)==null?void 0:T.t)==null?void 0:r.call(T,o);return D&&D!==o?D:A}catch{return A}},Wl="cicy_token",gu="cicy_access_token",vu="cicy_user_id",pu="https://cicy-ai.com";async function Su(o){var A,T,r;try{(r=(T=(A=window.cicy)==null?void 0:A.shell)==null?void 0:T.openExternal)==null||r.call(T,`${pu}/dash${o}`)}catch{}}const Qs=new Set;let Jy=0,Va=[];const Fn=new Map;function nm(){Qs.forEach(o=>o(Va))}const de={show(o={}){const A=o.id||`t${++Jy}`,T=Va.find(q=>q.id===A),r={id:A,status:"running",...T,...o};Va=T?Va.map(q=>q.id===A?r:q):[...Va,r],nm();const D=Fn.get(A);return D&&(clearTimeout(D),Fn.delete(A)),o.ttl&&Fn.set(A,setTimeout(()=>de.dismiss(A),o.ttl)),A},dismiss(o){Va=Va.filter(T=>T.id!==o);const A=Fn.get(o);A&&(clearTimeout(A),Fn.delete(o)),nm()}};function $y(){const[o,A]=N.useState(Va);return N.useEffect(()=>(Qs.add(A),()=>{Qs.delete(A)}),[]),o.length?c.jsx("div",{className:"toast-host","data-id":"ToastHost",children:o.map(T=>c.jsxs("div",{className:"toast","data-id":`Toast-${T.id}`,"data-status":T.status||"running",children:[c.jsx("button",{type:"button",className:"toast__x","data-id":"Toast-dismiss",onClick:()=>de.dismiss(T.id),"aria-label":"dismiss",children:"×"}),c.jsxs("span",{className:"toast__msg",children:[T.message,Number.isFinite(T.progress)?` ${T.progress}%`:""]}),Number.isFinite(T.progress)&&c.jsx("span",{className:"toast__bar",children:c.jsx("span",{style:{width:`${Math.min(100,T.progress)}%`}})})]},T.id))}):null}const Xs=new Set;let im=0,Wt=null;function Fl(){Xs.forEach(o=>o(Wt))}function bu(){return new Date().toTimeString().slice(0,8)}const ea={open({teamId:o,fromVer:A,toVer:T,onRetry:r}={}){Wt={teamId:o,fromVer:A||null,toVer:T||null,status:"running",phase:"download",logs:[],onRetry:r||null,lastAt:Date.now()},Fl()},push(o={}){if(!Wt)return;const A={id:++im,t:bu(),phase:o.phase||Wt.phase,status:o.status||"running",message:o.message||""};Wt={...Wt,phase:o.phase||Wt.phase,toVer:o.toVer||Wt.toVer,logs:[...Wt.logs,A],lastAt:Date.now()},Fl()},minimize(){Wt&&(Wt={...Wt,minimized:!0},Fl())},restore(){Wt&&(Wt={...Wt,minimized:!1},Fl())},finish({ok:o,message:A}={}){if(!Wt)return;const T=o?"done":"error",r={id:++im,t:bu(),phase:"done",status:T,message:A||(o?"更新完成":"更新失败")};Wt={...Wt,status:T,phase:"done",minimized:!1,logs:[...Wt.logs,r],lastAt:Date.now()},Fl()},close(){Wt=null,Fl()}},Ys=[["download","下载"],["swap","切换"],["done","完成"]];function Wy(){var R;const[o,A]=N.useState(Wt);N.useEffect(()=>(Xs.add(A),()=>{Xs.delete(A)}),[]);const T=N.useRef(null);N.useEffect(()=>{const C=T.current;C&&(C.scrollTop=C.scrollHeight)},[(R=o==null?void 0:o.logs)==null?void 0:R.length]);const[r,D]=N.useState(!1);if(N.useEffect(()=>{if(!o||o.status!=="running"){D(!1);return}const C=setInterval(()=>D(Date.now()-(o.lastAt||0)>25e3),3e3);return()=>clearInterval(C)},[o==null?void 0:o.lastAt,o==null?void 0:o.status]),!o)return null;const q=o.status==="running",V=Ys.findIndex(([C])=>C===o.phase);return o.minimized?c.jsxs("button",{type:"button",className:`drawer-min drawer-min--${o.status}`,"data-id":"UpdateDrawer-restore",onClick:()=>ea.restore(),children:[c.jsx("span",{className:"drawer-min__spark",children:q?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("span",{className:"drawer-min__label",children:["更新 cicy-code",o.toVer?` · v${o.toVer}`:""]})]}):c.jsx("div",{className:"drawer-scrim","data-id":"UpdateDrawer-scrim",onClick:()=>q?ea.minimize():ea.close(),children:c.jsxs("div",{className:"drawer","data-id":"UpdateDrawer","data-status":o.status,onClick:C=>C.stopPropagation(),children:[c.jsxs("div",{className:"drawer__head",children:[c.jsxs("div",{className:"drawer__title",children:[c.jsx("span",{className:`drawer__spark drawer__spark--${o.status}`,children:q?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("div",{children:[c.jsx("div",{className:"drawer__h",children:"更新 cicy-code"}),c.jsxs("div",{className:"drawer__sub",children:[o.fromVer?`v${o.fromVer}`:"当前"," → ",o.toVer?`v${o.toVer}`:"最新版"]})]})]}),c.jsx("div",{className:"drawer__headbtns",children:c.jsx("button",{type:"button",className:"drawer__x","data-id":"UpdateDrawer-min",title:"最小化",onClick:()=>ea.minimize(),"aria-label":"minimize",children:"‒"})})]}),c.jsx("div",{className:"drawer__steps","data-id":"UpdateDrawer-steps",children:Ys.map(([C,g],Y)=>{const H=o.status==="done"||Y<V,lt=Y===V&&q,J=o.status==="error"&&Y===V;return c.jsxs("div",{className:`drawer__step${lt?" is-active":""}${H?" is-done":""}${J?" is-error":""}`,children:[c.jsx("span",{className:"drawer__step-dot",children:H?"✓":J?"!":Y+1}),c.jsx("span",{className:"drawer__step-label",children:g}),Y<Ys.length-1&&c.jsx("span",{className:"drawer__step-bar"})]},C)})}),c.jsx("div",{className:"drawer__log","data-id":"UpdateDrawer-log",ref:T,children:o.logs.length===0?c.jsx("div",{className:"drawer__log-empty",children:"准备中…"}):o.logs.map(C=>c.jsxs("div",{className:"drawer__line","data-status":C.status,children:[c.jsx("span",{className:"drawer__t",children:C.t}),c.jsx("span",{className:`drawer__badge drawer__badge--${C.phase}`,children:{download:"下载",swap:"切换",done:"完成"}[C.phase]||C.phase}),c.jsx("span",{className:"drawer__linemsg",children:C.message})]},C.id))}),r&&q&&c.jsx("div",{className:"drawer__hint","data-id":"UpdateDrawer-stuck",children:"正在等待新版本就绪,耗时比平常久。可以放到后台继续,完成或失败都会提示。"}),c.jsx("div",{className:"drawer__foot",children:q?c.jsx(c.Fragment,{children:c.jsx("span",{className:"drawer__foot-status",children:"更新进行中…"})}):o.status==="error"?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-error",children:"更新失败"}),o.onRetry&&c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-retry",onClick:()=>o.onRetry(),children:"重试"}),c.jsx("button",{type:"button",className:"drawer__btn","data-id":"UpdateDrawer-dismiss",onClick:()=>ea.close(),children:"关闭"})]}):c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-done",children:"已更新到最新"}),c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-finish",onClick:()=>ea.close(),children:"完成"})]})})]})})}function Fy(){const[o,A]=N.useState(void 0);N.useEffect(()=>{var B,at;if(!((at=(B=window.cicy)==null?void 0:B.terms)!=null&&at.status)){A(!0);return}window.cicy.terms.status(vm).then(x=>A(!!(x!=null&&x.accepted))).catch(()=>A(!0))},[]),N.useEffect(()=>{var x,K,L,et;const B=document.documentElement;try{B.setAttribute("data-platform",((x=window.cicy)==null?void 0:x.platform)||"linux")}catch{}B.setAttribute("data-fullscreen","0");let at;try{at=(et=(L=(K=window.cicy)==null?void 0:K.window)==null?void 0:L.onFullscreen)==null?void 0:et.call(L,Zt=>B.setAttribute("data-fullscreen",Zt?"1":"0"))}catch{}return()=>{try{at&&at()}catch{}}},[]);const[T,r]=N.useState(()=>In(Wl)),[D,q]=N.useState(()=>In(gu)),[V,R]=N.useState(()=>In(vu)),[C,g]=N.useState(()=>!In(Wl)),[Y,H]=N.useState(!1),[lt,J]=N.useState(""),[I,W]=N.useState(""),[it,Z]=N.useState(null),[k,P]=N.useState(null),[dt,ot]=N.useState(!1),[X,M]=N.useState(""),pt=N.useRef(!1),[U,gt]=N.useState(null),[qt,Lt]=N.useState(!1),[Yt,me]=N.useState(!1),[ut,S]=N.useState("all"),O=N.useCallback(async(B,at)=>{var K,L,et,Zt;if(!B)return;if(!((L=(K=window.cicy)==null?void 0:K.cloud)!=null&&L.fetch)){M("cloud fetch bridge missing");return}ot(!0),M("");const x={Authorization:`Bearer ${B}`};try{const[ue,Xt]=await Promise.all([window.cicy.cloud.fetch(`${pu}/api/user/self`,{headers:x}),window.cicy.cloud.fetch(`${pu}/api/teams`,{headers:x})]);if((Xt==null?void 0:Xt.status)===401){if(!pt.current&&((Zt=(et=window.cicy)==null?void 0:et.auth)!=null&&Zt.loginStart)){pt.current=!0,M("会话已过期,正在重新登录…");try{await window.cicy.auth.loginStart()}catch{}}return}if(!(Xt!=null&&Xt.ok))throw new Error(`/api/teams ${(Xt==null?void 0:Xt.status)||"?"} ${(Xt==null?void 0:Xt.error)||""}`);const kt=JSON.parse(Xt.body||"{}");if(P(Array.isArray(kt==null?void 0:kt.teams)?kt.teams:[]),ue!=null&&ue.ok)try{const Ae=JSON.parse(ue.body||"{}");Z((Ae==null?void 0:Ae.success)===!1?null:(Ae==null?void 0:Ae.data)||null)}catch{Z(null)}else Z(null)}catch(ue){M(ue.message||String(ue))}finally{ot(!1)}},[]),Q=N.useRef("");N.useEffect(()=>{Q.current=T||D||""},[T,D]);const mt=N.useCallback(async()=>{var at,x;const B=Q.current;if(!(!B||!((x=(at=window.cicy)==null?void 0:at.cloud)!=null&&x.fetch)))try{const K=await window.cicy.cloud.fetch(`${pu}/api/teams`,{headers:{Authorization:`Bearer ${B}`}});if(K!=null&&K.ok){const L=JSON.parse(K.body||"{}");Array.isArray(L==null?void 0:L.teams)&&P(L.teams)}}catch{}},[]);N.useEffect(()=>{const B=T||D;B&&O(B,V)},[T,D,V,O]);const st=N.useCallback(async()=>{var B,at;if((at=(B=window.cicy)==null?void 0:B.localTeams)!=null&&at.list){Lt(!0);try{const x=await window.cicy.localTeams.list({refresh:!0});gt(Array.isArray(x)?x:[])}catch{gt([])}finally{Lt(!1),me(!0)}}},[]),d=N.useCallback(async(B,at)=>{var K,L;if(!((L=(K=window.cicy)==null?void 0:K.localTeams)!=null&&L.update))return{ok:!1,error:"no_bridge"};let x;try{x=await window.cicy.localTeams.update(B,{name:String(at||"").trim()||w("localTeams.unnamed","未命名")})}catch(et){x={ok:!1,error:(et==null?void 0:et.message)||String(et)}}return await st(),x||{ok:!1,error:"no_result"}},[st]);N.useEffect(()=>{let B,at=!1;const x=3e3,K=3e4,L=async()=>{var ue,Xt,kt;try{await((kt=(Xt=(ue=window.cicy)==null?void 0:ue.localTeams)==null?void 0:Xt.syncCloud)==null?void 0:kt.call(Xt))}catch{}await Promise.all([st(),mt()])},et=()=>{if(at)return;const ue=document.visibilityState==="visible";B=setTimeout(async()=>{document.visibilityState==="visible"?await L():await st(),et()},ue?x:K)};L(),et();const Zt=()=>{document.visibilityState==="visible"&&L()};return document.addEventListener("visibilitychange",Zt),window.addEventListener("focus",Zt),()=>{at=!0,clearTimeout(B),document.removeEventListener("visibilitychange",Zt),window.removeEventListener("focus",Zt)}},[st,mt]),N.useEffect(()=>{var at,x;if(!((x=(at=window.cicy)==null?void 0:at.localTeams)!=null&&x.onWebviewRelay))return;const B=window.cicy.localTeams.onWebviewRelay(async({reqId:K,msg:L})=>{let et={ok:!1,error:"unknown relay type"};try{(L==null?void 0:L.type)==="localTeams:add"?et=await window.cicy.localTeams.add(L.spec||{}):(L==null?void 0:L.type)==="localTeams:remove"?et=await window.cicy.localTeams.remove(L.id):(L==null?void 0:L.type)==="localTeams:update"?et=await window.cicy.localTeams.update(L.id,L.patch||{}):(L==null?void 0:L.type)==="localTeams:upgrade"?et=await window.cicy.localTeams.upgrade(L.id):(L==null?void 0:L.type)==="localTeams:list"&&(et={ok:!0,teams:await window.cicy.localTeams.list({refresh:!0})}),st()}catch(Zt){et={ok:!1,error:(Zt==null?void 0:Zt.message)||String(Zt)}}try{window.cicy.localTeams.replyWebviewRelay(K,et)}catch{}});return()=>{try{B==null||B()}catch{}}},[st]);const y=N.useCallback(async B=>{var at,x;if((x=(at=window.cicy)==null?void 0:at.localTeams)!=null&&x.open)try{await window.cicy.localTeams.open(B)}catch{}},[]);N.useEffect(()=>{var at,x;if(In(Wl)){g(!1);return}if(!((x=(at=window.cicy)==null?void 0:at.auth)!=null&&x.getSaved)){g(!1);return}let B=!1;return(async()=>{try{const K=await window.cicy.auth.getSaved();if(B)return;if(K!=null&&K.token){try{localStorage.setItem(Wl,K.token)}catch{}if(r(K.token),K.accessToken){try{localStorage.setItem(gu,K.accessToken)}catch{}q(K.accessToken)}if(K.userId){try{localStorage.setItem(vu,String(K.userId))}catch{}R(String(K.userId))}}}catch{}finally{B||g(!1)}})(),()=>{B=!0}},[]),N.useEffect(()=>{var B,at;if((at=(B=window.cicy)==null?void 0:B.auth)!=null&&at.onComplete)return window.cicy.auth.onComplete(x=>{if(H(!1),x!=null&&x.error){J(dm(x.error));return}if(x!=null&&x.token){pt.current=!1,M("");try{localStorage.setItem(Wl,x.token)}catch{}if(r(x.token),x.accessToken){try{localStorage.setItem(gu,x.accessToken)}catch{}q(x.accessToken)}if(x.userId){try{localStorage.setItem(vu,String(x.userId))}catch{}R(String(x.userId))}J(""),W(x.reused?"已恢复你之前的登录":"登录成功"),setTimeout(()=>W(""),3e3)}})},[]);async function G(){var at,x;if(!((x=(at=window.cicy)==null?void 0:at.auth)!=null&&x.loginStart)){J("auth bridge missing");return}J(""),H(!0);const B=await window.cicy.auth.loginStart();B!=null&&B.ok||(H(!1),J(dm((B==null?void 0:B.error)||"login start failed")))}function $(){var B,at,x;try{localStorage.removeItem(Wl),localStorage.removeItem(gu),localStorage.removeItem(vu)}catch{}try{(x=(at=(B=window.cicy)==null?void 0:B.auth)==null?void 0:at.logout)==null||x.call(at)}catch{}r(null),q(null),R(null),Z(null),P(null),J(""),M("")}if(o===void 0)return c.jsxs("div",{className:"shell","data-id":"TermsCheckingSplash",children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"card",children:[c.jsx(Gs,{}),c.jsx("div",{className:"spinner-row",children:c.jsx(ge,{})})]})]});if(!o)return c.jsx(pm,{onAgree:()=>A(!0)});if(!T&&C)return c.jsxs("div",{className:"shell","data-id":"AuthRestoringSplash",children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"card",children:[c.jsx(Gs,{}),c.jsxs("div",{className:"spinner-row",children:[c.jsx(ge,{}),c.jsx("span",{children:"正在恢复登录…"})]})]})]});if(!T)return c.jsxs("div",{className:"shell",children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"card",children:[c.jsx(Gs,{}),!Y&&c.jsxs(c.Fragment,{children:[c.jsx("p",{className:"tagline",children:"登录以同步你的团队、配置与 AI 助手"}),c.jsxs("button",{className:"btn-primary",onClick:G,children:[c.jsx("span",{children:"使用浏览器登录"}),c.jsx(_u,{})]}),c.jsx("p",{className:"hint",children:"点击后会自动打开浏览器"})]}),Y&&c.jsxs(c.Fragment,{children:[c.jsx("p",{className:"tagline",children:"已在浏览器打开登录页,等待你完成…"}),c.jsxs("div",{className:"spinner-row",children:[c.jsx(ge,{}),c.jsx("span",{children:"等待回调"})]}),c.jsx("button",{className:"btn-ghost",onClick:()=>{var B,at,x;(x=(at=(B=window.cicy)==null?void 0:B.auth)==null?void 0:at.loginCancel)==null||x.call(at),H(!1)},children:"取消"})]}),lt&&c.jsx("div",{className:"error",children:lt})]})]});const ft=(U||[]).find(B=>om(B.base_url))||null,rt=(U||[]).filter(B=>Vs(B.base_url)),Tt=(U||[]).filter(B=>!Vs(B.base_url)&&!om(B.base_url)),Rt=rt.length,Et=Tt.length,Re=(k||[]).filter(B=>!B.is_local&&B.kind!=="local"),aa=Re.length,We=ut==="all"||ut==="local",Ka=ut==="all"||ut==="custom",He=ut==="all"||ut==="cloud";return c.jsxs("div",{className:"shell shell--app",children:[c.jsx("div",{className:"glow glow--app","aria-hidden":!0}),c.jsxs("div",{className:"shell__left",children:[c.jsx(t0,{me:it,welcome:I,onLogout:$,mitmTeam:rt.length>0?rt[0]:null}),c.jsxs("main",{className:"main",children:[c.jsxs("div",{className:"app__tabsrow",children:[c.jsx("div",{className:"app__tabs",children:[{k:"all",label:"全部",n:Rt+Et+aa},{k:"local",label:"本地",n:Rt},{k:"cloud",label:"私有云",n:aa},{k:"custom",label:"自定义",n:Et}].map(({k:B,label:at,n:x})=>c.jsxs("button",{type:"button",className:`app__tab ${ut===B?"is-active":""}`,onClick:()=>S(B),children:[at,c.jsx("span",{className:"app__tab-count",children:x})]},B))}),c.jsxs("button",{type:"button","data-id":"AddTeamButton",className:"app__add-team",title:w("teams.addHint","在云端新建私有云团队"),onClick:()=>Su("?tab=private"),children:["+ ",w("teams.add","新加团队")]})]}),X&&c.jsxs("div",{className:"error",style:{marginBottom:12},children:["云端: ",X,c.jsx("button",{className:"btn-ghost",style:{marginLeft:8},onClick:()=>O(T||D,V),children:"重试"})]}),c.jsxs("div",{className:"app__grid",children:[We&&rt.map(B=>c.jsx(sm,{team:B,onOpen:()=>y(B.id),onRename:d,onRefresh:st},"local:"+B.id)),We&&rt.length===0&&c.jsxs("div",{"data-id":"LocalTeamPlaceholder",className:"bcard bcard--local",children:[c.jsx("div",{className:"bcard__accent"}),c.jsx("div",{className:"bcard__top",children:c.jsxs("div",{className:"bcard__pill",children:[c.jsx("span",{className:"bcard__dot","data-tone":"warn"}),c.jsx(Sm,{})]})}),c.jsxs("div",{className:"bcard__body",children:[c.jsx("h3",{className:"bcard__name",children:"本地团队"}),c.jsx("div",{className:"bcard__host",children:"http://127.0.0.1:8008"}),c.jsx("div",{className:"bcard__meta"})]}),c.jsxs("button",{type:"button",className:"bcard__cta",disabled:!0,children:[c.jsx(ge,{}),c.jsx("span",{children:Yt?"正在启动,就绪后自动加入…":"检测中…"})]})]}),We&&c.jsx(u0,{dockerTeam:ft,onOpen:B=>{var at,x,K;B?y(B):(K=(x=(at=window.cicy)==null?void 0:at.tabs)==null?void 0:x.open)==null||K.call(x,"http://127.0.0.1:8009","Docker cicy-code")},onRefresh:st}),Ka&&Tt.map(B=>c.jsx(sm,{team:B,onOpen:()=>y(B.id),onRename:d,onRefresh:st},"custom:"+B.id)),He&&Re.map(B=>c.jsx(c0,{team:B,onOpen:()=>{var x,K,L;const at=B.kind==="private"?B.host_url:B.workspace_url||B.workspace_direct_url;at&&((L=(K=(x=window.cicy)==null?void 0:x.tabs)==null?void 0:K.open)==null||L.call(K,at,B.name||B.title||""))}},"cloud:"+B.id))]}),!dt&&!X&&k&&k.length===0&&!(U!=null&&U.length)&&c.jsx("div",{className:"empty",style:{marginTop:14},children:"还没有团队 — 安装本地 cicy-code 起一个本地 team,或在云端创建。"})]})]}),c.jsx($y,{}),c.jsx(Wy,{}),c.jsx(i0,{})]})}function Iy({onClose:o}){const[A,T]=N.useState(null),[r,D]=N.useState(""),[q,V]=N.useState(!1),[R,C]=N.useState(""),g=typeof window<"u"&&window.cicy&&window.cicy.trustedOrigins||null,Y=N.useCallback(async()=>{try{T(g&&await g.list()||[])}catch{T([])}},[g]);N.useEffect(()=>{Y()},[Y]);const H=async()=>{const I=r.trim();if(!(!I||q||!g)){V(!0),C("");try{const W=await g.add(I);W&&W.ok===!1?C(W.error||w("trustedSites.addFailed","添加失败")):(D(""),T(W&&W.origins||await g.list()))}catch(W){C(String(W&&W.message||W))}finally{V(!1)}}},lt=async I=>{if(!(q||!g)){V(!0),C("");try{const W=await g.remove(I);W&&W.ok===!1?C(W.error||w("trustedSites.removeFailed","删除失败")):T(W&&W.origins||await g.list())}catch(W){C(String(W&&W.message||W))}finally{V(!1)}}},J={overlay:{position:"fixed",inset:0,zIndex:2e3,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,.62)",backdropFilter:"blur(3px)"},card:{width:560,maxWidth:"94vw",maxHeight:"82vh",display:"flex",flexDirection:"column",background:"#101012",border:"1px solid rgba(255,255,255,.09)",borderRadius:16,boxShadow:"0 24px 64px rgba(0,0,0,.55)",overflow:"hidden",color:"#e4e4e7"},head:{display:"flex",alignItems:"center",gap:8,padding:"14px 16px",borderBottom:"1px solid rgba(255,255,255,.06)"},title:{margin:0,fontSize:15,fontWeight:600,flex:1},x:{background:"transparent",border:"none",color:"#a1a1aa",fontSize:16,cursor:"pointer",lineHeight:1,padding:4},warn:{margin:"14px 16px 0",padding:"10px 12px",fontSize:12.5,lineHeight:1.55,color:"#fca5a5",background:"rgba(239,68,68,.08)",border:"1px solid rgba(239,68,68,.25)",borderRadius:10},addRow:{display:"flex",gap:8,padding:"12px 16px 4px"},input:{flex:1,minWidth:0,background:"#161618",border:"1px solid rgba(255,255,255,.1)",borderRadius:9,padding:"9px 11px",color:"#e4e4e7",fontSize:13,outline:"none"},addBtn:{background:"rgba(255,255,255,.1)",border:"none",borderRadius:9,padding:"0 16px",color:"#fff",fontSize:13,fontWeight:500,cursor:"pointer"},err:{margin:"6px 16px 0",fontSize:12,color:"#fca5a5"},listWrap:{margin:"10px 16px 16px",border:"1px solid rgba(255,255,255,.07)",borderRadius:10,overflow:"auto",flex:1,minHeight:80},row:{display:"flex",alignItems:"center",gap:10,padding:"9px 12px",borderTop:"1px solid rgba(255,255,255,.05)"},host:I=>({flex:1,fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",fontSize:13,color:I?"#71717a":"#e4e4e7",wordBreak:"break-all"}),tag:{fontSize:11,color:"#71717a",background:"rgba(255,255,255,.05)",borderRadius:6,padding:"2px 7px"},rm:{background:"transparent",border:"none",color:"#a1a1aa",fontSize:12,cursor:"pointer",padding:"3px 6px",borderRadius:6},muted:{padding:"16px",textAlign:"center",color:"#71717a",fontSize:12.5}};return Pl.createPortal(c.jsx("div",{style:J.overlay,onClick:o,"data-id":"TrustedSitesModal",children:c.jsxs("div",{style:J.card,onClick:I=>I.stopPropagation(),children:[c.jsxs("div",{style:J.head,children:[c.jsx("h2",{style:J.title,children:w("trustedSites.title","受信任站点")}),c.jsx("button",{type:"button",style:J.x,onClick:o,"aria-label":"close",children:"✕"})]}),c.jsx("div",{style:J.warn,children:w("trustedSites.warn","⚠ 列表中的站点可以在你的电脑上执行命令(exec)。只添加你完全信任的地址。")}),c.jsxs("div",{style:J.addRow,children:[c.jsx("input",{"data-id":"trusted-sites-input",style:J.input,value:r,onChange:I=>D(I.target.value),onKeyDown:I=>{I.key==="Enter"&&H()},placeholder:w("trustedSites.placeholder","添加站点,如 app.cicy-ai.com 或 my-cloud.example.org")}),c.jsx("button",{type:"button","data-id":"trusted-sites-add",style:{...J.addBtn,opacity:q||!r.trim()?.5:1},onClick:H,disabled:q||!r.trim(),children:w("trustedSites.add","添加")})]}),R&&c.jsx("div",{style:J.err,children:R}),c.jsx("div",{style:J.listWrap,children:A===null?c.jsx("div",{style:J.muted,children:w("trustedSites.loading","加载中…")}):A.length===0?c.jsx("div",{style:J.muted,children:w("trustedSites.empty","暂无")}):A.map(I=>c.jsxs("div",{style:J.row,"data-id":"trusted-sites-row",children:[c.jsx("span",{style:J.host(I.builtin),children:I.host}),I.builtin?c.jsx("span",{style:J.tag,children:w("trustedSites.builtin","系统")}):c.jsx("button",{type:"button",style:J.rm,onClick:()=>lt(I.host),disabled:q,children:w("trustedSites.remove","删除")})]},I.host))})]})}),document.body)}function Py({onClose:o}){const[A,T]=N.useState(null),[r,D]=N.useState(""),[q,V]=N.useState(""),[R,C]=N.useState(!1),g=typeof window<"u"&&window.cicy&&window.cicy.rpcAudit||null,Y=N.useCallback(async()=>{C(!0),D("");try{const U=g&&await g.tail(400);!U||U.ok===!1?(D(U&&U.error||w("audit.loadFailed","读取失败")),T([])):(T(U.entries||[]),V(U.path||""))}catch(U){D(String(U&&U.message||U)),T([])}finally{C(!1)}},[g]);N.useEffect(()=>{Y()},[Y]);const[H,lt]=N.useState("all"),[J,I]=N.useState(""),W=U=>{try{return new Date(U).toLocaleString()}catch{return U||""}},it=U=>{if(U.kind==="auth"){const gt=/deny/.test(U.decision||"");return{text:U.decision||"auth",color:gt?"#fca5a5":"#86efac",bg:gt?"rgba(239,68,68,.14)":"rgba(34,197,94,.14)"}}if(U.kind==="rpc"){const gt=U.ok!==!1&&!U.error;return{text:gt?"ok":"err",color:gt?"#86efac":"#fca5a5",bg:gt?"rgba(34,197,94,.14)":"rgba(239,68,68,.14)"}}return{text:U.kind||"log",color:"#a1a1aa",bg:"rgba(255,255,255,.06)"}},Z=U=>U.kind==="auth"?`${U.gate||""}${U.decision?" · "+U.decision:""}`:U.kind==="rpc"?`${U.tool||""}${U.dangerous?" ⚠":""}`:U.kind||"",k=U=>U.error||U.args||(U.kind==="rpc"?U.channel:"")||"",P=A||[],dt=J.trim().toLowerCase(),ot=P.filter(U=>H!=="all"&&U.kind!==H?!1:dt?[U.origin,U.host,U.tool,U.gate,U.decision,U.channel,U.args,U.error,U.kind].filter(Boolean).join(" ").toLowerCase().includes(dt):!0),X="186px 104px minmax(160px,1.1fr) minmax(150px,1.1fr) minmax(220px,1.8fr)",M={overlay:{position:"fixed",inset:0,zIndex:2e3,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,.66)",backdropFilter:"blur(4px)"},card:{width:"96vw",height:"92vh",maxWidth:1480,display:"flex",flexDirection:"column",background:"#0d0d0f",border:"1px solid rgba(255,255,255,.09)",borderRadius:18,boxShadow:"0 32px 80px rgba(0,0,0,.6)",overflow:"hidden",color:"#e4e4e7"},head:{display:"flex",alignItems:"center",gap:14,padding:"20px 24px",borderBottom:"1px solid rgba(255,255,255,.07)"},titleWrap:{flex:1,minWidth:0},title:{margin:0,fontSize:21,fontWeight:650,letterSpacing:.2},subtitle:{margin:"3px 0 0",fontSize:12.5,color:"#71717a",fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",wordBreak:"break-all"},count:{fontSize:12.5,color:"#a1a1aa",whiteSpace:"nowrap"},refresh:{background:"rgba(255,255,255,.1)",border:"none",borderRadius:9,padding:"9px 16px",color:"#fff",fontSize:13,fontWeight:500,cursor:"pointer"},x:{background:"transparent",border:"none",color:"#a1a1aa",fontSize:20,cursor:"pointer",lineHeight:1,padding:6},toolbar:{display:"flex",alignItems:"center",gap:10,padding:"14px 24px",borderBottom:"1px solid rgba(255,255,255,.05)"},chips:{display:"flex",gap:6},chip:U=>({background:U?"rgba(255,255,255,.14)":"transparent",border:"1px solid rgba(255,255,255,.12)",borderRadius:999,padding:"6px 16px",color:U?"#fff":"#a1a1aa",fontSize:13,cursor:"pointer"}),search:{flex:1,minWidth:0,background:"#161618",border:"1px solid rgba(255,255,255,.1)",borderRadius:10,padding:"10px 14px",color:"#e4e4e7",fontSize:13.5,outline:"none"},err:{margin:"10px 24px 0",fontSize:12.5,color:"#fca5a5"},tableWrap:{flex:1,overflow:"auto",margin:"0"},theadRow:{position:"sticky",top:0,zIndex:1,display:"grid",gridTemplateColumns:X,gap:16,padding:"12px 24px",background:"#141417",borderBottom:"1px solid rgba(255,255,255,.08)",fontSize:11.5,letterSpacing:.6,textTransform:"uppercase",color:"#71717a",fontWeight:600},row:{display:"grid",gridTemplateColumns:X,gap:16,padding:"13px 24px",borderBottom:"1px solid rgba(255,255,255,.045)",alignItems:"center"},time:{fontSize:12.5,color:"#a1a1aa",fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",whiteSpace:"nowrap"},badge:U=>({justifySelf:"start",fontSize:11.5,color:U.color,background:U.bg,borderRadius:7,padding:"3px 10px",whiteSpace:"nowrap",fontWeight:500}),cell:{fontSize:13,color:"#d4d4d8",fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",wordBreak:"break-all"},detail:{fontSize:12.5,color:"#8b8b93",wordBreak:"break-all"},muted:{padding:"60px 24px",textAlign:"center",color:"#71717a",fontSize:14}},pt=U=>c.jsx("div",{children:U});return Pl.createPortal(c.jsx("div",{style:M.overlay,onClick:o,"data-id":"AuditLogModal",children:c.jsxs("div",{style:M.card,onClick:U=>U.stopPropagation(),children:[c.jsxs("div",{style:M.head,children:[c.jsxs("div",{style:M.titleWrap,children:[c.jsx("h2",{style:M.title,children:w("audit.title","审计日志")}),q&&c.jsx("p",{style:M.subtitle,children:q})]}),c.jsxs("span",{style:M.count,children:[w("audit.count","共")," ",ot.length,H!=="all"||dt?` / ${P.length}`:""]}),c.jsx("button",{type:"button","data-id":"audit-refresh",style:{...M.refresh,opacity:R?.5:1},onClick:Y,disabled:R,children:w("audit.refresh","刷新")}),c.jsx("button",{type:"button",style:M.x,onClick:o,"aria-label":"close",children:"✕"})]}),c.jsxs("div",{style:M.toolbar,children:[c.jsxs("div",{style:M.chips,children:[c.jsx("button",{type:"button",style:M.chip(H==="all"),onClick:()=>lt("all"),children:w("audit.all","全部")}),c.jsx("button",{type:"button",style:M.chip(H==="rpc"),onClick:()=>lt("rpc"),children:w("audit.rpc","RPC 调用")}),c.jsx("button",{type:"button",style:M.chip(H==="auth"),onClick:()=>lt("auth"),children:w("audit.auth","授权决定")})]}),c.jsx("input",{"data-id":"audit-search",style:M.search,value:J,onChange:U=>I(U.target.value),placeholder:w("audit.search","搜索来源 / 工具 / 命令…")})]}),r&&c.jsx("div",{style:M.err,children:r}),c.jsxs("div",{style:M.tableWrap,children:[c.jsxs("div",{style:M.theadRow,children:[pt(w("audit.colTime","时间")),pt(w("audit.colType","类型")),pt(w("audit.colSource","来源")),pt(w("audit.colOp","操作")),pt(w("audit.colDetail","详情"))]}),A===null?c.jsx("div",{style:M.muted,children:w("audit.loading","加载中…")}):ot.length===0?c.jsx("div",{style:M.muted,children:P.length===0?w("audit.empty","暂无审计记录"):w("audit.noMatch","无匹配记录")}):ot.map((U,gt)=>{const qt=it(U);return c.jsxs("div",{style:M.row,"data-id":"audit-row",children:[c.jsx("span",{style:M.time,children:W(U.ts)}),c.jsx("span",{style:M.badge(qt),children:qt.text}),c.jsx("span",{style:M.cell,children:U.origin||U.host||"—"}),c.jsx("span",{style:M.cell,children:Z(U)||"—"}),c.jsx("span",{style:M.detail,children:k(U)||"—"})]},gt)})]})]})}),document.body)}function t0({me:o,welcome:A,onLogout:T,mitmTeam:r}){const D=(o==null?void 0:o.display_name)||(o==null?void 0:o.username)||"…",q=D.slice(0,1).toUpperCase(),[V,R]=N.useState(!1),[C,g]=N.useState(!1),[Y,H]=N.useState(!1),[lt,J]=N.useState(!1),[I,W]=N.useState(""),it=N.useRef(null);N.useEffect(()=>{var P,dt,ot;let k=!0;return(ot=(dt=(P=window.cicy)==null?void 0:P.app)==null?void 0:dt.getVersion)==null||ot.call(dt).then(X=>{k&&W(typeof X=="string"?X:String((X==null?void 0:X.desktop)||""))}).catch(()=>{}),()=>{k=!1}},[]),N.useEffect(()=>{if(!V)return;const k=P=>{it.current&&!it.current.contains(P.target)&&R(!1)};return document.addEventListener("mousedown",k),()=>document.removeEventListener("mousedown",k)},[V]);const Z=k=>{Su(k),R(!1)};return c.jsxs("header",{className:"topbar",children:[c.jsxs("div",{className:"brand-mini",children:[c.jsx("div",{className:"brand-mark sm",children:c.jsx(bm,{})}),c.jsx("span",{className:"brand-name",children:"CiCy Desktop"})]}),c.jsxs("div",{className:"user-chip","data-id":"UserChip",ref:it,children:[A&&c.jsx("span",{className:"welcome",children:A}),c.jsxs("button",{type:"button","data-id":"UserChip-trigger",className:`user-chip__trigger${V?" is-open":""}`,onClick:()=>R(k=>!k),children:[c.jsx("div",{className:"avatar",children:q}),c.jsx("span",{className:"user-name",children:D}),c.jsx("span",{className:"user-chip__caret","aria-hidden":!0,children:"▾"})]}),V&&c.jsxs("div",{className:"user-chip__menu","data-id":"UserChip-menu",role:"menu",children:[c.jsx("button",{type:"button","data-id":"UserChip-wallet",className:"user-chip__menu-item",onClick:()=>Z("?view=wallet"),children:"我的钱包"}),c.jsx("button",{type:"button","data-id":"UserChip-billing",className:"user-chip__menu-item",onClick:()=>Z("?view=usage"),children:"我的账单"}),c.jsx("button",{type:"button","data-id":"UserChip-trusted-sites",className:"user-chip__menu-item",onClick:()=>{R(!1),g(!0)},children:w("trustedSites.menu","受信任站点")}),c.jsx("button",{type:"button","data-id":"UserChip-audit-log",className:"user-chip__menu-item",onClick:()=>{R(!1),H(!0)},children:w("audit.menu","审计日志")}),c.jsx("button",{type:"button","data-id":"UserChip-terms",className:"user-chip__menu-item",onClick:()=>{R(!1),J(!0)},children:w("firstRunTerms.menu","用户协议")}),r&&c.jsx("div",{className:"user-chip__menu-mitm","data-id":"UserChip-mitm",onClick:k=>k.stopPropagation(),children:c.jsx(e0,{team:r,variant:"menu"})}),c.jsx("div",{className:"user-chip__menu-sep","aria-hidden":!0}),c.jsx("button",{type:"button","data-id":"UserChip-logout",className:"user-chip__menu-item is-danger",onClick:()=>{R(!1),T()},children:"退出"}),c.jsxs("div",{className:"user-chip__menu-version","data-id":"UserChip-version",children:["CiCy Desktop ",I?`v${I}`:"…"]})]})]}),C&&c.jsx(Iy,{onClose:()=>g(!1)}),Y&&c.jsx(Py,{onClose:()=>H(!1)}),lt&&c.jsx(pm,{onClose:()=>J(!1)})]})}function pm({onAgree:o,onClose:A}){var it;const[T,r]=N.useState(!1),[D,q]=N.useState(!1),[V,R]=N.useState(!1),C=(((it=window.cicyI18n)==null?void 0:it.locale)||"en").startsWith("zh")?"zh-CN":"en",g=(Z,k)=>w(`firstRunTerms.${Z}`,k),Y=!!A,H=[1,2,3,4,5,6].map(Z=>g(`summary${Z}`,"")),lt=Z=>{const k=Z.currentTarget;k.scrollHeight-k.scrollTop-k.clientHeight<24&&r(!0)},J=N.useRef(null);N.useEffect(()=>{const Z=J.current;Z&&Z.scrollHeight<=Z.clientHeight+24&&r(!0)},[D]);const I=async()=>{var Z,k,P;if(!(V||!T)){R(!0);try{await((P=(k=(Z=window.cicy)==null?void 0:Z.terms)==null?void 0:k.agree)==null?void 0:P.call(k,vm)),o==null||o()}catch{o==null||o()}}},W=()=>{var Z,k,P;try{(P=(k=(Z=window.cicy)==null?void 0:Z.terms)==null?void 0:k.decline)==null||P.call(k)}catch{}};return c.jsxs("div",{className:Y?"terms-gate terms-gate--review":"shell terms-gate","data-id":"FirstRunTermsGate",style:Y?{position:"fixed",inset:0,zIndex:1e3,background:"rgba(8,9,14,.72)",backdropFilter:"blur(4px)"}:void 0,onClick:Y?Z=>{Z.target===Z.currentTarget&&A()}:void 0,children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"terms-gate__panel",children:[c.jsx("h1",{className:"terms-gate__title","data-id":"FirstRunTermsGate-title",children:g("title","用户协议与授权说明")}),c.jsx("p",{className:"terms-gate__subtitle",children:g("subtitle","使用 CiCy Desktop 前,请阅读并同意以下条款")}),c.jsxs("div",{className:"terms-gate__body",ref:J,onScroll:lt,"data-id":"FirstRunTermsGate-body",children:[c.jsx("h2",{className:"terms-gate__h2",children:g("summaryTitle","一眼看懂")}),c.jsx("ol",{className:"terms-gate__summary",children:H.filter(Boolean).map((Z,k)=>c.jsx("li",{children:Z},k))}),D?c.jsx("pre",{className:"terms-gate__fulltext","data-id":"FirstRunTermsGate-fulltext",children:lm[C]||lm.en}):c.jsx("button",{className:"terms-gate__viewfull","data-id":"FirstRunTermsGate-viewfull",onClick:()=>q(!0),children:g("viewFull","查看完整条款")})]}),Y?c.jsx("div",{className:"terms-gate__actions",children:c.jsx("button",{"data-id":"FirstRunTermsGate-close",className:"terms-gate__btn",onClick:A,children:g("close","关闭")})}):c.jsxs(c.Fragment,{children:[!T&&c.jsx("div",{className:"terms-gate__scrollhint","data-id":"FirstRunTermsGate-scrollhint",children:g("scrollHint","请阅读至底部以继续")}),c.jsxs("div",{className:"terms-gate__actions",children:[c.jsx("button",{"data-id":"FirstRunTermsGate-decline",className:"terms-gate__btn terms-gate__btn--ghost",onClick:W,children:g("decline","不同意并退出")}),c.jsx("button",{"data-id":"FirstRunTermsGate-agree",className:"terms-gate__btn",disabled:!T||V,title:T?"":g("mustAgree","未同意则无法使用本软件。"),onClick:I,children:g("agree","同意并继续")})]})]})]})]})}function e0({team:o,variant:A}){const[T,r]=N.useState(void 0),[D,q]=N.useState(""),[V,R]=N.useState(""),C=((o==null?void 0:o.base_url)||"").replace(/\/$/,""),g=(o==null?void 0:o.api_token)||"",Y=N.useCallback(async(Z,k={})=>{var ot,X;if(!((X=(ot=window.cicy)==null?void 0:ot.cloud)!=null&&X.fetch))throw new Error("bridge missing");const P=await window.cicy.cloud.fetch(`${C}${Z}`,{...k,headers:{Authorization:`Bearer ${g}`,"Content-Type":"application/json",...k.headers||{}}});let dt=null;try{dt=JSON.parse(P.body)}catch{}return{ok:P.ok,status:P.status,json:dt}},[C,g]),H=N.useCallback(async()=>{try{const Z=await Y("/api/mitm/ca-status");r(Z.ok&&Z.json?Z.json:null)}catch{r(null)}},[Y]);if(N.useEffect(()=>{C&&g&&H()},[C,g,H]),T===void 0||!T||!T.generated)return null;const lt=async()=>{var Z,k,P,dt,ot,X,M,pt,U;if(!D){q("enable"),R("");try{const gt=await Y("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!0})}),qt=`${((Z=gt.json)==null?void 0:Z.error)||""} ${((k=gt.json)==null?void 0:k.detail)||""}`,Lt=((P=gt.json)==null?void 0:P.error)==="need_elevation"||!gt.ok&&gt.status===403||/need_elevation|add-trusted-cert|write permission|SecCertificate|not permitted|requires admin|administrator/i.test(qt);if(gt.ok&&((dt=gt.json)!=null&&dt.ok)&&((ot=gt.json)!=null&&ot.trusted))await H();else if(Lt){const Yt=await((pt=(M=(X=window.cicy)==null?void 0:X.mitm)==null?void 0:M.caExec)==null?void 0:pt.call(M,"install"));Yt!=null&&Yt.ok?await H():R(/cancel/i.test((Yt==null?void 0:Yt.stderr)||"")?w("mitmConsent.errorAdminDenied","未获得管理员授权,已取消。"):(Yt==null?void 0:Yt.stderr)||w("mitmConsent.errorTitle","提权失败,请从管理员控制台运行"))}else R(((U=gt.json)==null?void 0:U.error)||`失败 (HTTP ${gt.status})`)}catch(gt){R(String((gt==null?void 0:gt.message)||gt))}finally{q("")}}},J=async()=>{var Z,k,P,dt,ot;if(!D){q("disable"),R("");try{const X=await Y("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!1})});if(X.ok&&((Z=X.json)!=null&&Z.ok))await H();else{const M=await((dt=(P=(k=window.cicy)==null?void 0:k.mitm)==null?void 0:P.caExec)==null?void 0:dt.call(P,"uninstall"));M!=null&&M.ok?await H():R((M==null?void 0:M.stderr)||((ot=X.json)==null?void 0:ot.error)||"撤销失败")}}catch(X){R(String((X==null?void 0:X.message)||X))}finally{q("")}}},I=T.consent&&T.trusted,W=T.consent&&!T.trusted,it=(Z,k)=>w(`mitmConsent.${Z}`,k);if(A==="menu"){const Z=k=>{var P;(P=k==null?void 0:k.stopPropagation)==null||P.call(k),!D&&(I?window.confirm(it("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&J():lt())};return c.jsxs("div",{className:"user-chip__mitm","data-id":"MitmConsentCard",children:[c.jsxs("div",{className:"user-chip__menu-item user-chip__mitm-row",title:it("scopeNote","仅解密 AI 厂商域名,数据留本地,随时可关闭。"),children:[c.jsx("span",{className:"user-chip__mitm-label",children:it("rowLabel","HTTPS 审计")}),c.jsx("button",{type:"button",role:"switch","aria-checked":I?"true":"false","data-id":"MitmConsentCard-toggle",className:`mini-switch${I?" is-on":""}${D?" is-busy":""}`,disabled:!!D,onClick:Z,children:c.jsx("span",{className:"mini-switch__knob"})})]}),W&&!D&&c.jsx("div",{className:"user-chip__mitm-note","data-id":"MitmConsentCard-note",children:it("partialNote","已同意但未安装,点开关重试")}),V&&c.jsx("div",{className:"user-chip__mitm-err","data-id":"MitmConsentCard-error",children:V})]})}return I||D==="disable"?Pl.createPortal(c.jsxs("div",{"data-id":"MitmConsentCard",className:"mitm-pill",title:it("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具生效;随时可关闭。"),children:[c.jsx("span",{className:"mitm-pill__dot","data-busy":D?"1":"0"}),c.jsx("span",{className:"mitm-pill__text","data-id":"MitmConsentCard-title",children:D==="disable"?it("processingRevoke","正在关闭…"):it("statePillOn","HTTPS 审计已开启")}),!D&&c.jsx("button",{type:"button","data-id":"MitmConsentCard-revoke",className:"mitm-pill__off",onClick:()=>{window.confirm(it("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&J()},children:it("turnOff","关闭")})]}),document.body):c.jsxs("div",{"data-id":"MitmConsentCard",className:`mitm-card${I?" mitm-card--on":""}`,children:[c.jsxs("div",{className:"mitm-card__head",children:[c.jsx("span",{className:"mitm-card__dot","data-state":I?"on":W?"warn":"off"}),c.jsx("span",{className:"mitm-card__title","data-id":"MitmConsentCard-title",children:D?it("stateProcessingTitle","处理中…"):I?it("stateGrantedTitle","已启用"):`${it("cardTitle","HTTPS 流量本地审计")}${W?" — "+it("retry","重试"):""}`})]}),c.jsxs("p",{className:"mitm-card__desc","data-id":"MitmConsentCard-desc",children:[I?it("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具(claude / codex 等)生效;随时可关闭。"):it("body","启用后,CiCy 启动的 AI 工具(claude / codex 等)访问 AI 厂商(Claude / OpenAI / DeepSeek / Gemini)的 HTTPS 流量将被本地审计解密,数据留本地,随时可关闭。"),!I&&c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsx("span",{className:"mitm-card__note",children:it("adminNote","通过环境变量对 CiCy 启动的 AI 工具生效,不修改系统、无需管理员授权。")}),c.jsx("br",{}),c.jsx("span",{className:"mitm-card__sub",children:it("scopeNote","仅解密上述 AI 厂商域名,其余一切流量不被解密、不被读取。")})]})]}),V&&c.jsxs("div",{className:"mitm-card__error","data-id":"MitmConsentCard-error",children:[it("errorTitle","操作失败"),": ",V]}),c.jsx("div",{className:"mitm-card__actions",children:I?c.jsx("button",{"data-id":"MitmConsentCard-revoke",className:"mitm-card__btn mitm-card__btn--ghost",disabled:!!D,onClick:()=>{window.confirm(it("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&J()},children:D==="disable"?it("processingRevoke","正在关闭…"):it("revoke","撤销")}):c.jsx("button",{"data-id":"MitmConsentCard-enable",className:"mitm-card__btn",disabled:!!D,onClick:lt,children:D==="enable"?it("processingEnable","正在启用…"):W?it("retry","重试"):it("enable","同意并启用")})})]})}const Zs=new Set;let um=0,Ft=null;function Il(){Zs.forEach(o=>o(Ft))}const ie={open({onRetry:o}={}){Ft={status:"running",phase:"install-docker",logs:[],bars:{},minimized:!1,onRetry:o||null,lastAt:Date.now()},Il()},minimize(){Ft&&(Ft={...Ft,minimized:!0},Il())},restore(){Ft&&(Ft={...Ft,minimized:!1},Il())},push(o={}){var V;if(!Ft)return;const A=o.phase==="health"?"container":o.phase||Ft.phase,T={...Ft,phase:A,lastAt:Date.now()},r=Number.isFinite(o.progress),D=A==="install-docker"||A==="image";if(D&&(r||o.dest||o.url)){const R=((V=Ft.bars)==null?void 0:V[A])||{},C=r?o.progress:o.status==="skip"||o.status==="done"?100:R.progress;T.bars={...Ft.bars,[A]:{progress:C,received:o.received??R.received,total:o.total??R.total,url:o.url||R.url,dest:o.dest||R.dest}}}if(!(o.status==="running"&&r&&D)){const R={id:++um,t:bu(),phase:A,status:o.status||"running",message:o.message||""};T.logs=[...Ft.logs,R]}Ft=T,Il()},finish({ok:o,message:A,status:T}={}){if(!Ft)return;const r=T||(o?"done":"error"),D={id:++um,t:bu(),phase:"done",status:r,message:A||(o?"完成":"失败")};Ft={...Ft,status:r,phase:"done",minimized:!1,logs:[...Ft.logs,D],lastAt:Date.now()},Il()},close(){Ft=null,Il()}},ks=[["install-docker","装 Docker"],["image","加载镜像"],["container","启动容器"],["done","完成"]],a0={"install-docker":"Docker",image:"镜像",container:"容器",health:"容器",done:"完成"},l0={"install-docker":"Docker Desktop",image:"基础镜像"};function cm(o){return Number.isFinite(o)?o<1024?o+" B":o<1048576?(o/1024).toFixed(0)+" KB":o<1073741824?(o/1048576).toFixed(1)+" MB":(o/1073741824).toFixed(2)+" GB":"?"}function n0({phaseKey:o,bar:A}){const T=Number.isFinite(A==null?void 0:A.progress)?Math.max(0,Math.min(100,A.progress)):0,r=T>=100;return c.jsxs("div",{className:"dlbar","data-id":`DockerDrawer-dlbar-${o}`,children:[c.jsxs("div",{className:"dlbar__head",children:[c.jsx("span",{className:"dlbar__name",children:l0[o]||o}),c.jsxs("span",{className:"dlbar__pct",children:[T,"%",A!=null&&A.total?` · ${cm(A.received)} / ${cm(A.total)}`:""]})]}),c.jsx("div",{className:"dlbar__track",children:c.jsx("div",{className:`dlbar__fill${r?" is-done":""}`,style:{width:`${T}%`}})}),(A==null?void 0:A.url)&&c.jsxs("div",{className:"dlbar__url",title:A.url,children:[c.jsx("span",{className:"dlbar__urlk",children:"源"})," ",A.url]}),(A==null?void 0:A.dest)&&c.jsxs("div",{className:"dlbar__url",title:A.dest,children:[c.jsx("span",{className:"dlbar__urlk",children:"存"})," ",A.dest]})]})}function i0(){var V;const[o,A]=N.useState(Ft);N.useEffect(()=>(Zs.add(A),()=>{Zs.delete(A)}),[]);const T=N.useRef(null);if(N.useEffect(()=>{const R=T.current;R&&(R.scrollTop=R.scrollHeight)},[(V=o==null?void 0:o.logs)==null?void 0:V.length]),!o)return null;const r=o.status==="running",D=ks.findIndex(([R])=>R===o.phase),q=["install-docker","image"].filter(R=>{var C;return(C=o.bars)==null?void 0:C[R]});if(o.minimized){const R=q.map(g=>{var Y;return(Y=o.bars[g])==null?void 0:Y.progress}).filter(Number.isFinite),C=R.length?Math.round(R.reduce((g,Y)=>g+Y,0)/R.length):null;return c.jsxs("button",{type:"button",className:`drawer-min drawer-min--${o.status}`,"data-id":"DockerDrawer-restore",onClick:()=>ie.restore(),children:[c.jsx("span",{className:"drawer-min__spark",children:r?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("span",{className:"drawer-min__label",children:[w("docker.setupTitle","安装 Docker cicy-code"),C!=null?` · ${C}%`:""]})]})}return c.jsx("div",{className:"drawer-scrim","data-id":"DockerDrawer-scrim",onClick:()=>r?ie.minimize():ie.close(),children:c.jsxs("div",{className:"drawer","data-id":"DockerDrawer","data-status":o.status,onClick:R=>R.stopPropagation(),children:[c.jsxs("div",{className:"drawer__head",children:[c.jsxs("div",{className:"drawer__title",children:[c.jsx("span",{className:`drawer__spark drawer__spark--${o.status}`,children:r?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("div",{children:[c.jsx("div",{className:"drawer__h",children:w("docker.setupTitle","安装 Docker cicy-code")}),c.jsx("div",{className:"drawer__sub",children:"127.0.0.1:8009"})]})]}),c.jsx("div",{className:"drawer__headbtns",children:c.jsx("button",{type:"button",className:"drawer__x","data-id":"DockerDrawer-min",title:w("common.minimize","最小化"),onClick:()=>ie.minimize(),"aria-label":"minimize",children:"‒"})})]}),c.jsx("div",{className:"drawer__steps","data-id":"DockerDrawer-steps",children:ks.map(([R,C],g)=>{const Y=o.status==="done"||D>=0&&g<D,H=g===D&&r,lt=o.status==="error"&&g===D;return c.jsxs("div",{className:`drawer__step${H?" is-active":""}${Y?" is-done":""}${lt?" is-error":""}`,children:[c.jsx("span",{className:"drawer__step-dot",children:Y?"✓":lt?"!":g+1}),c.jsx("span",{className:"drawer__step-label",children:C}),g<ks.length-1&&c.jsx("span",{className:"drawer__step-bar"})]},R)})}),q.length>0&&c.jsx("div",{className:"drawer__dlbars","data-id":"DockerDrawer-dlbars",children:q.map(R=>c.jsx(n0,{phaseKey:R,bar:o.bars[R]},R))}),r&&o.logs.length>0&&c.jsxs("div",{className:"drawer__now","data-id":"DockerDrawer-now",children:[c.jsx(ge,{}),c.jsx("span",{children:o.logs[o.logs.length-1].message})]}),c.jsx("div",{className:"drawer__log drawer__log--scroll","data-id":"DockerDrawer-log",ref:T,children:o.logs.length===0?c.jsx("div",{className:"drawer__log-empty",children:w("docker.preparing","准备中…")}):o.logs.map(R=>c.jsxs("div",{className:"drawer__line","data-status":R.status,children:[c.jsx("span",{className:"drawer__t",children:R.t}),c.jsx("span",{className:`drawer__badge drawer__badge--${R.phase}`,children:a0[R.phase]||R.phase}),c.jsx("span",{className:"drawer__linemsg",children:R.message})]},R.id))}),c.jsx("div",{className:"drawer__foot",children:r?c.jsx(c.Fragment,{children:c.jsx("span",{className:"drawer__foot-status",children:w("docker.installing2","安装进行中…")})}):o.status==="reboot"?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-reboot",children:w("docker.rebootShort","需重启 Windows")}),o.onRetry&&c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"DockerDrawer-retry",onClick:()=>o.onRetry(),children:w("common.retry","重试")}),c.jsx("button",{type:"button",className:"drawer__btn","data-id":"DockerDrawer-dismiss",onClick:()=>ie.close(),children:w("common.close","关闭")})]}):o.status==="error"?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-error",children:w("docker.failed","安装失败")}),o.onRetry&&c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"DockerDrawer-retry",onClick:()=>o.onRetry(),children:w("common.retry","重试")}),c.jsx("button",{type:"button",className:"drawer__btn","data-id":"DockerDrawer-dismiss",onClick:()=>ie.close(),children:w("common.close","关闭")})]}):c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-done",children:w("docker.ready","已就绪")}),c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"DockerDrawer-finish",onClick:()=>ie.close(),children:w("common.done","完成")})]})})]})})}function u0({dockerTeam:o,onOpen:A,onRefresh:T}){var me;const[r,D]=N.useState(null),[q,V]=N.useState(""),[R,C]=N.useState(!1),[g,Y]=N.useState({top:0,left:0}),H=N.useRef(null),lt=N.useRef(null),J=184,I="#2496ed",W=N.useCallback(async()=>{var ut,S,O;try{D(await((O=(S=(ut=window.cicy)==null?void 0:ut.docker)==null?void 0:S.appStatus)==null?void 0:O.call(S)))}catch(Q){console.warn("[DockerCard]",Q)}},[]);N.useEffect(()=>{W();const ut=setInterval(()=>{q||W()},12e3);return()=>clearInterval(ut)},[W,q]),N.useEffect(()=>{if(!R)return;const ut=O=>{var Q,mt;(Q=H.current)!=null&&Q.contains(O.target)||(mt=lt.current)!=null&&mt.contains(O.target)||C(!1)},S=O=>{O.key==="Escape"&&C(!1)};return document.addEventListener("mousedown",ut),document.addEventListener("keydown",S),()=>{document.removeEventListener("mousedown",ut),document.removeEventListener("keydown",S)}},[R]);const it=()=>{if(!R&&H.current){const ut=H.current.getBoundingClientRect(),S=Math.max(8,Math.min(ut.right-J,window.innerWidth-J-8));Y({top:Math.round(ut.bottom+4),left:Math.round(S)})}C(ut=>!ut)},Z=N.useCallback(async()=>{var S,O,Q,mt,st,d;V("bootstrap"),ie.open({onRetry:Z});const ut=(Q=(O=(S=window.cicy)==null?void 0:S.docker)==null?void 0:O.onAppProgress)==null?void 0:Q.call(O,y=>ie.push(y));try{const y=await((d=(st=(mt=window.cicy)==null?void 0:mt.docker)==null?void 0:st.appBootstrap)==null?void 0:d.call(st));(y==null?void 0:y.reason)==="installer_launched"?ie.finish({status:"reboot",message:w("docker.installerLaunched","已打开 Docker 安装程序——请完成安装(会装 WSL2、可能需重启),装好后点「重试」")}):(y==null?void 0:y.reason)==="wsl_reboot_required"?ie.finish({status:"reboot",message:w("docker.rebootNeeded","WSL2 已安装,请【重启 Windows】后回来点「重试」继续")}):ie.finish({ok:!!(y!=null&&y.ok),message:y!=null&&y.ok?w("docker.ready","Docker cicy-code 已就绪"):(y==null?void 0:y.error)||w("docker.failed","安装失败")}),y!=null&&y.ok&&(T==null||T())}catch(y){ie.finish({ok:!1,message:y.message})}finally{try{ut&&ut()}catch{}V(""),W()}},[W,T]),k=N.useCallback(async()=>{var S,O,Q,mt,st,d;C(!1),V("upgrade"),ie.open({onRetry:k});const ut=(Q=(O=(S=window.cicy)==null?void 0:S.docker)==null?void 0:O.onAppProgress)==null?void 0:Q.call(O,y=>ie.push(y));try{const y=await((d=(st=(mt=window.cicy)==null?void 0:mt.docker)==null?void 0:st.appUpgrade)==null?void 0:d.call(st));(y==null?void 0:y.reason)==="wsl_reboot_required"?ie.finish({status:"reboot",message:w("docker.rebootNeeded","WSL2 已安装,请【重启 Windows】后回来点「重试」继续")}):ie.finish({ok:!!(y!=null&&y.ok),message:y!=null&&y.ok?w("docker.upgraded","已升级到最新"):(y==null?void 0:y.error)||w("docker.upgradeFailed","升级失败")}),y!=null&&y.ok&&(T==null||T())}catch(y){ie.finish({ok:!1,message:y.message})}finally{try{ut&&ut()}catch{}V(""),W()}},[W,T]),P=N.useCallback(async(ut,S,O)=>{C(!1),V(ut),de.show({id:"docker-op",message:w(`docker.${ut}ing`,ut==="restart"?"重启中…":"停止中…"),status:"running"});try{const Q=await S();Q!=null&&Q.ok?de.show({id:"docker-op",message:O,status:"done",ttl:2500}):de.show({id:"docker-op",message:(Q==null?void 0:Q.error)||w("docker.opFailed","操作失败"),status:"error",ttl:6e3})}catch(Q){de.show({id:"docker-op",message:Q.message,status:"error",ttl:6e3})}finally{V(""),W()}},[W]);if((((me=window.cicy)==null?void 0:me.platform)||(r==null?void 0:r.platform))!=="win32")return null;const ot=!!(r!=null&&r.running)||(o==null?void 0:o.status)==="running",X=!!(r!=null&&r.dockerRunning),M=!!(r!=null&&r.installed),pt=ot?"ok":X||M?"warn":"off",U=!!q,gt=ot?w("docker.running","运行中 · :8009"):X?w("docker.notRunning","未启动 · 点「启动」"):M?w("docker.engineDown","Docker 未运行 · 点启动"):w("docker.notInstalled","Docker Desktop 未安装"),qt=U?w("docker.working","处理中…"):ot?w("localTeams.open","打开"):X?w("docker.start","启动"):M?w("docker.startDocker","启动 Docker"):w("docker.install","下载安装"),Lt=()=>{if(!U){if(ot){A==null||A(o==null?void 0:o.id);return}Z()}},Yt=ot;return c.jsxs("div",{"data-id":"DockerCard",className:`bcard bcard--docker${ot?" bcard--online":""}`,children:[c.jsx("div",{className:"bcard__accent",style:{background:I}}),c.jsxs("div",{className:"bcard__top",children:[c.jsxs("div",{className:"bcard__pill",style:{color:I},children:[c.jsx("span",{className:"bcard__dot","data-tone":pt}),c.jsx("svg",{style:{width:18,height:18},viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:c.jsx("path",{d:"M21.81 10.25c-.06-.05-.67-.51-1.95-.51-.34 0-.68.03-1.01.09-.25-1.69-1.64-2.51-1.7-2.55l-.34-.2-.22.32a4.5 4.5 0 0 0-.59 1.4c-.23.94-.09 1.83.39 2.59-.58.32-1.51.4-1.7.41H2.62a.61.61 0 0 0-.61.61 9.32 9.32 0 0 0 .57 3.35 4.9 4.9 0 0 0 1.95 2.53c.92.52 2.42.82 4.12.82.77 0 1.54-.07 2.3-.21a9.6 9.6 0 0 0 3-1.09 8.3 8.3 0 0 0 2.05-1.68c.98-1.11 1.56-2.35 1.99-3.45h.17c1.36 0 2.2-.55 2.66-1l.13-.16zM4.7 11.33h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H4.7a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.46 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H7.16a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.5 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H9.66a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.47 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16h-1.78a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16M7.16 9.06h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16H7.16a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.5 0h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16H9.66a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.47 0h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16h-1.78a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16"})})]}),Yt&&c.jsxs("div",{className:"bcard__menuwrap",onClick:ut=>ut.stopPropagation(),children:[c.jsx("button",{type:"button",ref:H,"data-id":"DockerCard-menu-btn",className:"bcard__kebab",title:w("docker.manage","管理 Docker cicy-code"),disabled:U,onClick:it,children:U?c.jsx(ge,{}):c.jsx(Js,{})}),R&&Pl.createPortal(c.jsxs("div",{className:"bcard__menu bcard__menu--portal","data-id":"DockerCard-menu",role:"menu",ref:lt,style:{position:"fixed",top:g.top,left:g.left,width:J},onClick:ut=>ut.stopPropagation(),children:[ot&&c.jsx("button",{type:"button","data-id":"DockerCard-restart",className:"bcard__menu-item",onClick:()=>P("restart",()=>window.cicy.docker.appRestart(),w("docker.restarted","已重启")),children:w("docker.restart","重启")}),c.jsx("button",{type:"button","data-id":"DockerCard-upgrade",className:"bcard__menu-item is-accent",onClick:k,children:w("docker.upgrade","升级(拉取最新镜像)")}),ot&&c.jsx("button",{type:"button","data-id":"DockerCard-stop",className:"bcard__menu-item is-danger",onClick:()=>P("stop",()=>window.cicy.docker.appStop(),w("docker.stopped","已停止")),children:w("docker.stop","停止")})]}),document.body)]})]}),c.jsxs("div",{className:"bcard__body",children:[c.jsx("h3",{className:"bcard__name",children:w("docker.title","Docker cicy-code")}),c.jsx("div",{className:"bcard__host",children:"http://127.0.0.1:8009"}),c.jsx("div",{className:"bcard__meta",style:{fontSize:12,color:"#8b949e"},children:gt})]}),c.jsxs("button",{type:"button",className:"bcard__cta","data-id":"DockerCard-cta",disabled:U,onClick:Lt,style:ot?void 0:{background:I,color:"white"},children:[U?c.jsx(ge,{}):c.jsx(_u,{}),c.jsx("span",{children:qt})]})]})}function sm({team:o,onOpen:A,onRename:T,onRefresh:r}){var Ka,He,B,at;const q=(rm[o.status]||rm.error).tone,[V,R]=N.useState(!1),[C,g]=N.useState(o.name||""),[Y,H]=N.useState(null),[lt,J]=N.useState(""),I=Y??o.name;N.useEffect(()=>{Y!=null&&o.name===Y&&H(null)},[o.name,Y]);const W=x=>{var K;(K=x==null?void 0:x.stopPropagation)==null||K.call(x),g(I||""),R(!0)},it=async()=>{R(!1);const x=String(C||"").trim();if(!T||!x||x===I)return;H(x),J("saving");let K;try{K=await T(o.id,x)}catch(L){K={ok:!1,error:L==null?void 0:L.message}}H(null),K&&K.ok?(J("saved"),setTimeout(()=>J(L=>L==="saved"?"":L),1500)):(J(""),de.show({message:w("localTeams.renameFailed","改名没保存,已恢复"),status:"error",ttl:4e3}))},k=!!((He=(Ka=window.cicy)==null?void 0:Ka.sidecar)!=null&&He.restart)&&Vs(o.base_url),P=o.status==="running",[dt,ot]=N.useState(""),[X,M]=N.useState(!1),[pt,U]=N.useState({running:void 0,latest:null,installed:null}),gt=pt.latest,qt=pt.running,[Lt,Yt]=N.useState(!1),me=N.useRef(null),ut=N.useRef(null),S=N.useRef(null),[O,Q]=N.useState({top:0,left:0}),mt=184,st=()=>{if(!X&&ut.current){const x=ut.current.getBoundingClientRect(),K=Math.max(8,Math.min(x.right-mt,window.innerWidth-mt-8));Q({top:Math.round(x.bottom+4),left:Math.round(K)})}M(x=>!x)},d=N.useCallback(async(x=!1)=>{var K,L;if(!(!k||!((L=(K=window.cicy)==null?void 0:K.sidecar)!=null&&L.versions))){x&&Yt(!0);try{const et=await window.cicy.sidecar.versions();U({running:(et==null?void 0:et.running)??null,latest:(et==null?void 0:et.latest)??null,installed:(et==null?void 0:et.installed)??null}),x&&(et!=null&&et.running&&(et!=null&&et.latest)&&fm(et.latest,et.running)>0?de.show({message:`${w("sidecar.found","发现新版本")} v${et.latest}`,status:"done",ttl:2500}):et!=null&&et.running?de.show({message:`${w("sidecar.upToDate","已是最新")} v${et.running}`,status:"done",ttl:2500}):de.show({message:w("sidecar.notRunning","cicy-code 未运行"),status:"error",ttl:4e3}))}catch{x&&de.show({message:w("sidecar.checkFailed","检查更新失败"),status:"error",ttl:5e3})}finally{x&&Yt(!1)}}},[k]);N.useEffect(()=>{d(!1)},[d]),N.useEffect(()=>{P&&d(!1)},[P,d]);const y=!!(k&&gt&&qt&&fm(gt,qt)>0),G=!k&&!!((at=(B=window.cicy)==null?void 0:B.localTeams)!=null&&at.remove),$=k||G,[ft,rt]=N.useState(!1);N.useEffect(()=>{if(!X)return;const x=K=>{var L,et;(L=ut.current)!=null&&L.contains(K.target)||(et=S.current)!=null&&et.contains(K.target)||M(!1)};return document.addEventListener("mousedown",x),()=>document.removeEventListener("mousedown",x)},[X]),N.useEffect(()=>{X||rt(!1)},[X]);const Tt=async()=>{var x,K,L;if(!ft){rt(!0);return}if(M(!1),rt(!1),!dt){ot("remove");try{await((L=(K=(x=window.cicy)==null?void 0:x.localTeams)==null?void 0:K.remove)==null?void 0:L.call(K,o.id))}catch{}ot(""),r==null||r()}},Rt=`sidecar-op:${o.id}`,Et=async(x,K,L)=>{var ue,Xt,kt,Ae,tn;if(M(!1),dt)return;ot(x);const et=x==="update";let Zt=null;et?(ea.open({teamId:o.id,fromVer:qt,toVer:gt,onRetry:()=>Et("update",K,L)}),(Xt=(ue=window.cicy)==null?void 0:ue.sidecar)!=null&&Xt.onOpProgress&&(Zt=window.cicy.sidecar.onOpProgress(Gt=>{(Gt==null?void 0:Gt.op)==="update"&&ea.push(Gt)}))):de.show({id:Rt,message:Re[x]||`${x}…`,status:"running",progress:void 0});try{const Gt=await K(),ve=!!(Gt!=null&&Gt.ok),Pn=Gt!=null&&Gt.warning?`${L}(${Gt.warning})`:L,en=w("sidecar.failed","操作失败")+(Gt!=null&&Gt.error?`: ${Gt.error}`:"");if(et){if(ea.finish({ok:ve,message:ve?Pn:en}),ve)try{await((tn=(Ae=(kt=window.cicy)==null?void 0:kt.localTeams)==null?void 0:Ae.reload)==null?void 0:tn.call(Ae,o.id,{ignoreCache:!0}))}catch{}}else de.show({id:Rt,message:ve?Pn:en,progress:void 0,status:ve?"done":"error",ttl:ve?4e3:8e3})}catch(Gt){const ve=w("sidecar.failed","操作失败")+`: ${(Gt==null?void 0:Gt.message)||Gt}`;et?ea.finish({ok:!1,message:ve}):de.show({id:Rt,message:ve,progress:void 0,status:"error",ttl:8e3})}finally{try{Zt&&Zt()}catch{}ot(""),r==null||r(),(x==="update"||x==="restart"||x==="start")&&d(!1)}},Re={start:"启动中…",restart:"重启中…",update:"更新中…",stop:"停止中…"},aa=async()=>{var x,K;if(!dt){if(!P&&k&&((K=(x=window.cicy)==null?void 0:x.sidecar)!=null&&K.start)){ot("start"),de.show({id:Rt,message:Re.start,status:"running",progress:void 0});const L=await window.cicy.sidecar.start().catch(et=>({ok:!1,error:(et==null?void 0:et.message)||String(et)}));if(ot(""),r==null||r(),!(L!=null&&L.ok)||L!=null&&L.warning){de.show({id:Rt,message:w("sidecar.startFailed","启动失败")+(L!=null&&L.error?`: ${L.error}`:L!=null&&L.warning?`: ${L.warning}`:""),status:"error",ttl:8e3});return}de.dismiss(Rt)}A()}},We=P?w("localTeams.open","打开"):k?w("localTeams.startOpen","启动并打开"):w("localTeams.open","打开");return c.jsxs("div",{"data-id":"LocalTeamCard",className:`bcard ${k?"bcard--local":"bcard--custom"}${q==="ok"?" bcard--online":""}`,children:[c.jsx("div",{className:"bcard__accent"}),c.jsxs("div",{className:"bcard__top",children:[c.jsxs("div",{className:"bcard__pill",children:[c.jsx("span",{className:"bcard__dot","data-tone":q}),c.jsx(Sm,{})]}),$&&c.jsxs("div",{className:"bcard__menuwrap",ref:me,onClick:x=>x.stopPropagation(),children:[c.jsx("button",{type:"button",ref:ut,"data-id":"LocalTeamCard-menu-btn",className:`bcard__kebab${y?" has-dot":""}`,title:k?w("localTeams.manage","管理本地 cicy-code"):w("localTeams.more","更多"),disabled:!!dt,onClick:st,children:dt?c.jsx(ge,{}):c.jsx(Js,{})}),X&&Pl.createPortal(c.jsxs("div",{className:"bcard__menu bcard__menu--portal","data-id":"LocalTeamCard-menu",role:"menu",ref:S,style:{position:"fixed",top:O.top,left:O.left,width:mt},onClick:x=>x.stopPropagation(),children:[k&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-check-update",className:"bcard__menu-item",disabled:Lt,onClick:x=>{x.stopPropagation(),d(!0)},children:Lt?w("sidecar.checking2","检查中…"):w("sidecar.checkUpdate","检查更新")}),y&&c.jsxs("button",{type:"button","data-id":"LocalTeamCard-update",className:"bcard__menu-item is-accent",onClick:()=>Et("update",()=>window.cicy.sidecar.update(),w("sidecar.updated","已更新到最新")),children:[w("sidecar.updateTo","更新到")," v",gt]}),k&&P&&c.jsxs(c.Fragment,{children:[c.jsx("button",{type:"button","data-id":"LocalTeamCard-reload",className:"bcard__menu-item",onClick:()=>Et("reload",async()=>{const x=await window.cicy.localTeams.reload(o.id);return!(x!=null&&x.ok)&&(x==null?void 0:x.error)==="no_open_window"?{ok:!1,error:w("localTeams.windowNotOpen","窗口未打开,请先点「打开」")}:x},w("localTeams.reloaded","已刷新窗口")),children:w("localTeams.reloadWindow","刷新窗口")}),c.jsx("button",{type:"button","data-id":"LocalTeamCard-restart",className:"bcard__menu-item",onClick:()=>Et("restart",()=>window.cicy.sidecar.restart(),w("sidecar.restarted","已重启")),children:w("sidecar.restart","重启")}),c.jsx("button",{type:"button","data-id":"LocalTeamCard-stop",className:"bcard__menu-item is-danger",onClick:()=>Et("stop",()=>window.cicy.sidecar.stop(),w("sidecar.stoppedDone","已停止")),children:w("sidecar.stop","停止")})]}),o.cloud_team_id&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-billing",className:"bcard__menu-item",onClick:x=>{x.stopPropagation(),M(!1),Su(`?team=${encodeURIComponent(o.cloud_team_id)}`)},children:w("localTeams.billing","账单")}),G&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-remove",className:"bcard__menu-item is-danger",onClick:Tt,children:ft?w("localTeams.removeConfirm","确认删除?"):w("localTeams.remove","删除")})]}),document.body)]})]}),c.jsxs("div",{className:"bcard__body",children:[V?c.jsx("input",{"data-id":"LocalTeamCard-rename-input",autoFocus:!0,value:C,onChange:x=>g(x.target.value),onFocus:x=>x.target.select(),onBlur:it,onClick:x=>x.stopPropagation(),onKeyDown:x=>{x.nativeEvent.isComposing||x.keyCode===229||(x.key==="Enter"?it():x.key==="Escape"&&R(!1))},style:{width:"100%",font:"inherit",fontWeight:600,padding:"2px 6px",border:"1px solid #3b82f6",borderRadius:6,background:"#0d1117",color:"#e6edf3",boxSizing:"border-box"}}):c.jsxs("h3",{className:"bcard__name",title:w("localTeams.renameHint","点名字或 ✎ 改名"),style:{display:"flex",alignItems:"center",gap:6},onDoubleClick:W,children:[c.jsx("span",{"data-id":"LocalTeamCard-name-text",onClick:W,style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",cursor:"text"},children:I}),lt==="saving"&&c.jsx("span",{"data-id":"LocalTeamCard-save-state",title:w("localTeams.saving","保存中…"),style:{flex:"none",display:"inline-flex"},children:c.jsx(ge,{})}),lt==="saved"&&c.jsx("span",{"data-id":"LocalTeamCard-save-state",title:w("localTeams.saved","已保存"),style:{flex:"none",color:"#3fb950",fontSize:13,lineHeight:1},children:"✓"}),!lt&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-rename-btn",title:w("localTeams.rename","重命名"),onClick:W,style:{flex:"none",cursor:"pointer",border:"none",background:"transparent",color:"#8b949e",fontSize:13,padding:0,lineHeight:1},children:"✎"})]}),c.jsx("div",{className:"bcard__host",children:o.base_url||"—"}),c.jsx("div",{className:"bcard__meta",children:(qt||o.version)&&c.jsxs("span",{className:"bcard__ver","data-id":"LocalTeamCard-version",children:["v",qt||o.version]})})]}),c.jsxs("button",{type:"button",className:"bcard__cta","data-id":"LocalTeamCard-open",disabled:!!dt||!o.base_url,onClick:aa,children:[dt&&dt!=="stop"?c.jsx(ge,{}):c.jsx(_u,{}),c.jsx("span",{children:dt&&Re[dt]||We})]})]})}function Vs(o){try{const A=new URL(o);return(A.hostname==="127.0.0.1"||A.hostname==="localhost"||A.hostname==="::1")&&(A.port==="8008"||A.port==="")}catch{return!1}}function om(o){try{const A=new URL(o);return(A.hostname==="127.0.0.1"||A.hostname==="localhost"||A.hostname==="::1")&&A.port==="8009"}catch{return!1}}function fm(o,A){const T=String(o).split("."),r=String(A).split(".");for(let D=0;D<Math.max(T.length,r.length);D++){const q=(parseInt(T[D],10)||0)-(parseInt(r[D],10)||0);if(q)return q>0?1:-1}return 0}const rm={running:{tone:"ok",label:"running",cta:"打开"},stopped:{tone:"off",label:"stopped",cta:"未运行"},auth_error:{tone:"warn",label:"auth error",cta:"Token 失效"},misconfigured:{tone:"err",label:"bad config",cta:"URL 错误"},error:{tone:"err",label:"error",cta:"异常"}};function c0({team:o,onOpen:A}){const T=o.kind==="private",r=o.status==="active",D=o.name||o.title||"—",q=o.host_url||"",V=o.teamId||o.id,R=T?"私有云":o.team_kind==="personal"?"个人":"共享",C=T?q:o.workspace_url||o.workspace_direct_url,g=!!C,[Y,H]=N.useState(!1),[lt,J]=N.useState(!1),[I,W]=N.useState({top:0,left:0}),it=N.useRef(null),Z=N.useRef(null),k=N.useRef(null),P=184,dt=()=>{if(!Y&&Z.current){const X=Z.current.getBoundingClientRect(),M=Math.max(8,Math.min(X.right-P,window.innerWidth-P-8));W({top:Math.round(X.bottom+4),left:Math.round(M)})}H(X=>!X)};N.useEffect(()=>{if(!Y)return;const X=M=>{var pt,U;(pt=Z.current)!=null&&pt.contains(M.target)||(U=k.current)!=null&&U.contains(M.target)||H(!1)};return document.addEventListener("mousedown",X),()=>document.removeEventListener("mousedown",X)},[Y]);const ot=async()=>{var X,M,pt;if(!(!g||lt)){J(!0),H(!1);try{await((pt=(M=(X=window.cicy)==null?void 0:X.tabs)==null?void 0:M.reload)==null?void 0:pt.call(M,C,D))}catch{}finally{J(!1)}}};return c.jsxs("div",{"data-id":"TeamCard",className:`bcard bcard--cloud${r?" bcard--online":""}`,children:[c.jsx("div",{className:"bcard__accent"}),c.jsxs("div",{className:"bcard__top",children:[c.jsxs("div",{className:"bcard__pill",children:[c.jsx("span",{className:"bcard__dot","data-tone":r?"ok":"off"}),c.jsx(s0,{})]}),c.jsxs("div",{className:"bcard__top-right",children:[o.is_trial&&c.jsx("span",{className:"bcard__badge",children:"trial"}),V!=null&&c.jsx("button",{type:"button","data-id":"TeamCard-billing",className:"bcard__billing-btn",title:w("localTeams.billing","账单"),onClick:X=>{X.stopPropagation(),Su(`?team=${encodeURIComponent(V)}`)},children:w("localTeams.billing","账单")}),g&&c.jsxs("div",{className:"bcard__menuwrap",ref:it,onClick:X=>X.stopPropagation(),children:[c.jsx("button",{type:"button",ref:Z,"data-id":"TeamCard-menu-btn",className:"bcard__kebab",title:w("localTeams.more","更多"),disabled:lt,onClick:dt,children:lt?c.jsx(ge,{}):c.jsx(Js,{})}),Y&&Pl.createPortal(c.jsx("div",{className:"bcard__menu bcard__menu--portal","data-id":"TeamCard-menu",role:"menu",ref:k,style:{position:"fixed",top:I.top,left:I.left,width:P},onClick:X=>X.stopPropagation(),children:c.jsx("button",{type:"button","data-id":"TeamCard-reload",className:"bcard__menu-item",onClick:ot,children:w("localTeams.reloadWindow","刷新窗口")})}),document.body)]})]})]}),c.jsxs("div",{className:"bcard__body",children:[c.jsx("h3",{className:"bcard__name",title:D,children:D}),c.jsx("div",{className:"bcard__host",title:T&&q||"",children:T?q||w("teamCard.noHost","未填访问地址"):o.runtime_region||o.region||"—"}),c.jsxs("div",{className:"bcard__meta",children:[c.jsx("span",{className:"bcard__chip",children:R}),!T&&o.membership_status&&o.membership_status!=="active"&&c.jsx("span",{className:"bcard__chip",children:o.membership_status})]})]}),c.jsxs("button",{type:"button",className:"bcard__cta",onClick:A,disabled:!g,children:[c.jsx(_u,{}),c.jsx("span",{children:g?w("localTeams.open","打开"):T?w("teamCard.noHost","未填访问地址"):w("teamCard.noUrl","无 URL")})]})]})}function Gs(){return c.jsxs("div",{className:"brand",children:[c.jsx("div",{className:"brand-mark",children:c.jsx(bm,{})}),c.jsxs("div",{className:"brand-text",children:[c.jsx("div",{className:"brand-name",children:"CiCy Desktop"}),c.jsx("div",{className:"brand-sub",children:"团队 AI 协作工作台"})]})]})}function bm(){return c.jsx("svg",{width:"22",height:"22",viewBox:"0 0 96 96",fill:"none",children:c.jsx("path",{d:"M48 11L39.5 33.3L16 29.5L31 48L16 66.5L39.5 62.7L48 85L56.5 62.7L80 66.5L65 48L80 29.5L56.5 33.3Z",fill:"white",stroke:"white",strokeWidth:"8",strokeLinejoin:"round",strokeLinecap:"round"})})}function _u(){return c.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round",children:[c.jsx("line",{x1:"5",y1:"12",x2:"19",y2:"12"}),c.jsx("polyline",{points:"12 5 19 12 12 19"})]})}function ge(){return c.jsx("svg",{className:"spin",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.4",strokeLinecap:"round",children:c.jsx("path",{d:"M21 12a9 9 0 1 1-6.2-8.55"})})}function Sm(){return c.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[c.jsx("rect",{x:"3",y:"4",width:"18",height:"12",rx:"2"}),c.jsx("line",{x1:"2",y1:"20",x2:"22",y2:"20"})]})}function Js(){return c.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:[c.jsx("circle",{cx:"12",cy:"5",r:"1.7"}),c.jsx("circle",{cx:"12",cy:"12",r:"1.7"}),c.jsx("circle",{cx:"12",cy:"19",r:"1.7"})]})}function s0(){return c.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[c.jsx("circle",{cx:"12",cy:"12",r:"10"}),c.jsx("line",{x1:"2",y1:"12",x2:"22",y2:"12"}),c.jsx("path",{d:"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"})]})}function In(o){try{return localStorage.getItem(o)||null}catch{return null}}function dm(o){return o?/timeout/i.test(o)?"登录超时,请重新点击 Login。":/state/i.test(o)?"校验失败,请重新登录。":/no token/i.test(o)?"登录未完成,请重试。":/bridge missing/i.test(o)?"无法连接到登录服务(preload 未就绪)。":o:""}var mm;const o0=((mm=window.cicy)==null?void 0:mm.platform)||(()=>{const o=navigator.userAgent||"";return/Mac/i.test(o)?"darwin":/Windows/i.test(o)?"win32":"linux"})();document.documentElement.dataset.platform=o0;document.documentElement.dataset.fullscreen="0";var hm,ym;(ym=(hm=window.cicy)==null?void 0:hm.window)!=null&&ym.onFullscreen&&window.cicy.window.onFullscreen(o=>{document.documentElement.dataset.fullscreen=o?"1":"0"});Ky.createRoot(document.getElementById("root")).render(c.jsx(Fy,{}));
365
+ `},w=(o,A)=>{var T,r;try{const D=(r=(T=window.cicyI18n)==null?void 0:T.t)==null?void 0:r.call(T,o);return D&&D!==o?D:A}catch{return A}},Wl="cicy_token",gu="cicy_access_token",vu="cicy_user_id",pu="https://cicy-ai.com";async function Su(o){var A,T,r;try{(r=(T=(A=window.cicy)==null?void 0:A.shell)==null?void 0:T.openExternal)==null||r.call(T,`${pu}/dash${o}`)}catch{}}const Qs=new Set;let Jy=0,Va=[];const Fn=new Map;function nm(){Qs.forEach(o=>o(Va))}const de={show(o={}){const A=o.id||`t${++Jy}`,T=Va.find(q=>q.id===A),r={id:A,status:"running",...T,...o};Va=T?Va.map(q=>q.id===A?r:q):[...Va,r],nm();const D=Fn.get(A);return D&&(clearTimeout(D),Fn.delete(A)),o.ttl&&Fn.set(A,setTimeout(()=>de.dismiss(A),o.ttl)),A},dismiss(o){Va=Va.filter(T=>T.id!==o);const A=Fn.get(o);A&&(clearTimeout(A),Fn.delete(o)),nm()}};function $y(){const[o,A]=N.useState(Va);return N.useEffect(()=>(Qs.add(A),()=>{Qs.delete(A)}),[]),o.length?c.jsx("div",{className:"toast-host","data-id":"ToastHost",children:o.map(T=>c.jsxs("div",{className:"toast","data-id":`Toast-${T.id}`,"data-status":T.status||"running",children:[c.jsx("button",{type:"button",className:"toast__x","data-id":"Toast-dismiss",onClick:()=>de.dismiss(T.id),"aria-label":"dismiss",children:"×"}),c.jsxs("span",{className:"toast__msg",children:[T.message,Number.isFinite(T.progress)?` ${T.progress}%`:""]}),Number.isFinite(T.progress)&&c.jsx("span",{className:"toast__bar",children:c.jsx("span",{style:{width:`${Math.min(100,T.progress)}%`}})})]},T.id))}):null}const Xs=new Set;let im=0,Wt=null;function Fl(){Xs.forEach(o=>o(Wt))}function bu(){return new Date().toTimeString().slice(0,8)}const ea={open({teamId:o,fromVer:A,toVer:T,onRetry:r}={}){Wt={teamId:o,fromVer:A||null,toVer:T||null,status:"running",phase:"download",logs:[],onRetry:r||null,lastAt:Date.now()},Fl()},push(o={}){if(!Wt)return;const A={id:++im,t:bu(),phase:o.phase||Wt.phase,status:o.status||"running",message:o.message||""};Wt={...Wt,phase:o.phase||Wt.phase,toVer:o.toVer||Wt.toVer,logs:[...Wt.logs,A],lastAt:Date.now()},Fl()},minimize(){Wt&&(Wt={...Wt,minimized:!0},Fl())},restore(){Wt&&(Wt={...Wt,minimized:!1},Fl())},finish({ok:o,message:A}={}){if(!Wt)return;const T=o?"done":"error",r={id:++im,t:bu(),phase:"done",status:T,message:A||(o?"更新完成":"更新失败")};Wt={...Wt,status:T,phase:"done",minimized:!1,logs:[...Wt.logs,r],lastAt:Date.now()},Fl()},close(){Wt=null,Fl()}},Ys=[["download","下载"],["swap","切换"],["done","完成"]];function Wy(){var R;const[o,A]=N.useState(Wt);N.useEffect(()=>(Xs.add(A),()=>{Xs.delete(A)}),[]);const T=N.useRef(null);N.useEffect(()=>{const C=T.current;C&&(C.scrollTop=C.scrollHeight)},[(R=o==null?void 0:o.logs)==null?void 0:R.length]);const[r,D]=N.useState(!1);if(N.useEffect(()=>{if(!o||o.status!=="running"){D(!1);return}const C=setInterval(()=>D(Date.now()-(o.lastAt||0)>25e3),3e3);return()=>clearInterval(C)},[o==null?void 0:o.lastAt,o==null?void 0:o.status]),!o)return null;const q=o.status==="running",V=Ys.findIndex(([C])=>C===o.phase);return o.minimized?c.jsxs("button",{type:"button",className:`drawer-min drawer-min--${o.status}`,"data-id":"UpdateDrawer-restore",onClick:()=>ea.restore(),children:[c.jsx("span",{className:"drawer-min__spark",children:q?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("span",{className:"drawer-min__label",children:["更新 cicy-code",o.toVer?` · v${o.toVer}`:""]})]}):c.jsx("div",{className:"drawer-scrim","data-id":"UpdateDrawer-scrim",onClick:()=>q?ea.minimize():ea.close(),children:c.jsxs("div",{className:"drawer","data-id":"UpdateDrawer","data-status":o.status,onClick:C=>C.stopPropagation(),children:[c.jsxs("div",{className:"drawer__head",children:[c.jsxs("div",{className:"drawer__title",children:[c.jsx("span",{className:`drawer__spark drawer__spark--${o.status}`,children:q?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("div",{children:[c.jsx("div",{className:"drawer__h",children:"更新 cicy-code"}),c.jsxs("div",{className:"drawer__sub",children:[o.fromVer?`v${o.fromVer}`:"当前"," → ",o.toVer?`v${o.toVer}`:"最新版"]})]})]}),c.jsx("div",{className:"drawer__headbtns",children:c.jsx("button",{type:"button",className:"drawer__x","data-id":"UpdateDrawer-min",title:"最小化",onClick:()=>ea.minimize(),"aria-label":"minimize",children:"‒"})})]}),c.jsx("div",{className:"drawer__steps","data-id":"UpdateDrawer-steps",children:Ys.map(([C,g],Y)=>{const H=o.status==="done"||Y<V,lt=Y===V&&q,J=o.status==="error"&&Y===V;return c.jsxs("div",{className:`drawer__step${lt?" is-active":""}${H?" is-done":""}${J?" is-error":""}`,children:[c.jsx("span",{className:"drawer__step-dot",children:H?"✓":J?"!":Y+1}),c.jsx("span",{className:"drawer__step-label",children:g}),Y<Ys.length-1&&c.jsx("span",{className:"drawer__step-bar"})]},C)})}),c.jsx("div",{className:"drawer__log","data-id":"UpdateDrawer-log",ref:T,children:o.logs.length===0?c.jsx("div",{className:"drawer__log-empty",children:"准备中…"}):o.logs.map(C=>c.jsxs("div",{className:"drawer__line","data-status":C.status,children:[c.jsx("span",{className:"drawer__t",children:C.t}),c.jsx("span",{className:`drawer__badge drawer__badge--${C.phase}`,children:{download:"下载",swap:"切换",done:"完成"}[C.phase]||C.phase}),c.jsx("span",{className:"drawer__linemsg",children:C.message})]},C.id))}),r&&q&&c.jsx("div",{className:"drawer__hint","data-id":"UpdateDrawer-stuck",children:"正在等待新版本就绪,耗时比平常久。可以放到后台继续,完成或失败都会提示。"}),c.jsx("div",{className:"drawer__foot",children:q?c.jsx(c.Fragment,{children:c.jsx("span",{className:"drawer__foot-status",children:"更新进行中…"})}):o.status==="error"?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-error",children:"更新失败"}),o.onRetry&&c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-retry",onClick:()=>o.onRetry(),children:"重试"}),c.jsx("button",{type:"button",className:"drawer__btn","data-id":"UpdateDrawer-dismiss",onClick:()=>ea.close(),children:"关闭"})]}):c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-done",children:"已更新到最新"}),c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-finish",onClick:()=>ea.close(),children:"完成"})]})})]})})}function Fy(){const[o,A]=N.useState(void 0);N.useEffect(()=>{var B,at;if(!((at=(B=window.cicy)==null?void 0:B.terms)!=null&&at.status)){A(!0);return}window.cicy.terms.status(vm).then(x=>A(!!(x!=null&&x.accepted))).catch(()=>A(!0))},[]),N.useEffect(()=>{var x,K,L,et;const B=document.documentElement;try{B.setAttribute("data-platform",((x=window.cicy)==null?void 0:x.platform)||"linux")}catch{}B.setAttribute("data-fullscreen","0");let at;try{at=(et=(L=(K=window.cicy)==null?void 0:K.window)==null?void 0:L.onFullscreen)==null?void 0:et.call(L,Zt=>B.setAttribute("data-fullscreen",Zt?"1":"0"))}catch{}return()=>{try{at&&at()}catch{}}},[]);const[T,r]=N.useState(()=>In(Wl)),[D,q]=N.useState(()=>In(gu)),[V,R]=N.useState(()=>In(vu)),[C,g]=N.useState(()=>!In(Wl)),[Y,H]=N.useState(!1),[lt,J]=N.useState(""),[I,W]=N.useState(""),[it,Z]=N.useState(null),[k,P]=N.useState(null),[dt,ot]=N.useState(!1),[X,M]=N.useState(""),pt=N.useRef(!1),[U,gt]=N.useState(null),[qt,Lt]=N.useState(!1),[Yt,me]=N.useState(!1),[ut,S]=N.useState("all"),O=N.useCallback(async(B,at)=>{var K,L,et,Zt;if(!B)return;if(!((L=(K=window.cicy)==null?void 0:K.cloud)!=null&&L.fetch)){M("cloud fetch bridge missing");return}ot(!0),M("");const x={Authorization:`Bearer ${B}`};try{const[ue,Xt]=await Promise.all([window.cicy.cloud.fetch(`${pu}/api/user/self`,{headers:x}),window.cicy.cloud.fetch(`${pu}/api/teams`,{headers:x})]);if((Xt==null?void 0:Xt.status)===401){if(!pt.current&&((Zt=(et=window.cicy)==null?void 0:et.auth)!=null&&Zt.loginStart)){pt.current=!0,M("会话已过期,正在重新登录…");try{await window.cicy.auth.loginStart()}catch{}}return}if(!(Xt!=null&&Xt.ok))throw new Error(`/api/teams ${(Xt==null?void 0:Xt.status)||"?"} ${(Xt==null?void 0:Xt.error)||""}`);const kt=JSON.parse(Xt.body||"{}");if(P(Array.isArray(kt==null?void 0:kt.teams)?kt.teams:[]),ue!=null&&ue.ok)try{const Ae=JSON.parse(ue.body||"{}");Z((Ae==null?void 0:Ae.success)===!1?null:(Ae==null?void 0:Ae.data)||null)}catch{Z(null)}else Z(null)}catch(ue){M(ue.message||String(ue))}finally{ot(!1)}},[]),Q=N.useRef("");N.useEffect(()=>{Q.current=T||D||""},[T,D]);const mt=N.useCallback(async()=>{var at,x;const B=Q.current;if(!(!B||!((x=(at=window.cicy)==null?void 0:at.cloud)!=null&&x.fetch)))try{const K=await window.cicy.cloud.fetch(`${pu}/api/teams`,{headers:{Authorization:`Bearer ${B}`}});if(K!=null&&K.ok){const L=JSON.parse(K.body||"{}");Array.isArray(L==null?void 0:L.teams)&&P(L.teams)}}catch{}},[]);N.useEffect(()=>{const B=T||D;B&&O(B,V)},[T,D,V,O]);const st=N.useCallback(async()=>{var B,at;if((at=(B=window.cicy)==null?void 0:B.localTeams)!=null&&at.list){Lt(!0);try{const x=await window.cicy.localTeams.list({refresh:!0});gt(Array.isArray(x)?x:[])}catch{gt([])}finally{Lt(!1),me(!0)}}},[]),d=N.useCallback(async(B,at)=>{var K,L;if(!((L=(K=window.cicy)==null?void 0:K.localTeams)!=null&&L.update))return{ok:!1,error:"no_bridge"};let x;try{x=await window.cicy.localTeams.update(B,{name:String(at||"").trim()||w("localTeams.unnamed","未命名")})}catch(et){x={ok:!1,error:(et==null?void 0:et.message)||String(et)}}return await st(),x||{ok:!1,error:"no_result"}},[st]);N.useEffect(()=>{let B,at=!1;const x=3e3,K=3e4,L=async()=>{var ue,Xt,kt;try{await((kt=(Xt=(ue=window.cicy)==null?void 0:ue.localTeams)==null?void 0:Xt.syncCloud)==null?void 0:kt.call(Xt))}catch{}await Promise.all([st(),mt()])},et=()=>{if(at)return;const ue=document.visibilityState==="visible";B=setTimeout(async()=>{document.visibilityState==="visible"?await L():await st(),et()},ue?x:K)};L(),et();const Zt=()=>{document.visibilityState==="visible"&&L()};return document.addEventListener("visibilitychange",Zt),window.addEventListener("focus",Zt),()=>{at=!0,clearTimeout(B),document.removeEventListener("visibilitychange",Zt),window.removeEventListener("focus",Zt)}},[st,mt]),N.useEffect(()=>{var at,x;if(!((x=(at=window.cicy)==null?void 0:at.localTeams)!=null&&x.onWebviewRelay))return;const B=window.cicy.localTeams.onWebviewRelay(async({reqId:K,msg:L})=>{let et={ok:!1,error:"unknown relay type"};try{(L==null?void 0:L.type)==="localTeams:add"?et=await window.cicy.localTeams.add(L.spec||{}):(L==null?void 0:L.type)==="localTeams:remove"?et=await window.cicy.localTeams.remove(L.id):(L==null?void 0:L.type)==="localTeams:update"?et=await window.cicy.localTeams.update(L.id,L.patch||{}):(L==null?void 0:L.type)==="localTeams:upgrade"?et=await window.cicy.localTeams.upgrade(L.id):(L==null?void 0:L.type)==="localTeams:list"&&(et={ok:!0,teams:await window.cicy.localTeams.list({refresh:!0})}),st()}catch(Zt){et={ok:!1,error:(Zt==null?void 0:Zt.message)||String(Zt)}}try{window.cicy.localTeams.replyWebviewRelay(K,et)}catch{}});return()=>{try{B==null||B()}catch{}}},[st]);const y=N.useCallback(async B=>{var at,x;if((x=(at=window.cicy)==null?void 0:at.localTeams)!=null&&x.open)try{await window.cicy.localTeams.open(B)}catch{}},[]);N.useEffect(()=>{var at,x;if(In(Wl)){g(!1);return}if(!((x=(at=window.cicy)==null?void 0:at.auth)!=null&&x.getSaved)){g(!1);return}let B=!1;return(async()=>{try{const K=await window.cicy.auth.getSaved();if(B)return;if(K!=null&&K.token){try{localStorage.setItem(Wl,K.token)}catch{}if(r(K.token),K.accessToken){try{localStorage.setItem(gu,K.accessToken)}catch{}q(K.accessToken)}if(K.userId){try{localStorage.setItem(vu,String(K.userId))}catch{}R(String(K.userId))}}}catch{}finally{B||g(!1)}})(),()=>{B=!0}},[]),N.useEffect(()=>{var B,at;if((at=(B=window.cicy)==null?void 0:B.auth)!=null&&at.onComplete)return window.cicy.auth.onComplete(x=>{if(H(!1),x!=null&&x.error){J(dm(x.error));return}if(x!=null&&x.token){pt.current=!1,M("");try{localStorage.setItem(Wl,x.token)}catch{}if(r(x.token),x.accessToken){try{localStorage.setItem(gu,x.accessToken)}catch{}q(x.accessToken)}if(x.userId){try{localStorage.setItem(vu,String(x.userId))}catch{}R(String(x.userId))}J(""),W(x.reused?"已恢复你之前的登录":"登录成功"),setTimeout(()=>W(""),3e3)}})},[]);async function G(){var at,x;if(!((x=(at=window.cicy)==null?void 0:at.auth)!=null&&x.loginStart)){J("auth bridge missing");return}J(""),H(!0);const B=await window.cicy.auth.loginStart();B!=null&&B.ok||(H(!1),J(dm((B==null?void 0:B.error)||"login start failed")))}function $(){var B,at,x;try{localStorage.removeItem(Wl),localStorage.removeItem(gu),localStorage.removeItem(vu)}catch{}try{(x=(at=(B=window.cicy)==null?void 0:B.auth)==null?void 0:at.logout)==null||x.call(at)}catch{}r(null),q(null),R(null),Z(null),P(null),J(""),M("")}if(o===void 0)return c.jsxs("div",{className:"shell","data-id":"TermsCheckingSplash",children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"card",children:[c.jsx(Gs,{}),c.jsx("div",{className:"spinner-row",children:c.jsx(ge,{})})]})]});if(!o)return c.jsx(pm,{onAgree:()=>A(!0)});if(!T&&C)return c.jsxs("div",{className:"shell","data-id":"AuthRestoringSplash",children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"card",children:[c.jsx(Gs,{}),c.jsxs("div",{className:"spinner-row",children:[c.jsx(ge,{}),c.jsx("span",{children:"正在恢复登录…"})]})]})]});if(!T)return c.jsxs("div",{className:"shell",children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"card",children:[c.jsx(Gs,{}),!Y&&c.jsxs(c.Fragment,{children:[c.jsx("p",{className:"tagline",children:"登录以同步你的团队、配置与 AI 助手"}),c.jsxs("button",{className:"btn-primary",onClick:G,children:[c.jsx("span",{children:"使用浏览器登录"}),c.jsx(_u,{})]}),c.jsx("p",{className:"hint",children:"点击后会自动打开浏览器"})]}),Y&&c.jsxs(c.Fragment,{children:[c.jsx("p",{className:"tagline",children:"已在浏览器打开登录页,等待你完成…"}),c.jsxs("div",{className:"spinner-row",children:[c.jsx(ge,{}),c.jsx("span",{children:"等待回调"})]}),c.jsx("button",{className:"btn-ghost",onClick:()=>{var B,at,x;(x=(at=(B=window.cicy)==null?void 0:B.auth)==null?void 0:at.loginCancel)==null||x.call(at),H(!1)},children:"取消"})]}),lt&&c.jsx("div",{className:"error",children:lt})]})]});const ft=(U||[]).find(B=>om(B.base_url))||null,rt=(U||[]).filter(B=>Vs(B.base_url)),Tt=(U||[]).filter(B=>!Vs(B.base_url)&&!om(B.base_url)),Rt=rt.length,Et=Tt.length,Re=(k||[]).filter(B=>!B.is_local&&B.kind!=="local"),aa=Re.length,We=ut==="all"||ut==="local",Ka=ut==="all"||ut==="custom",He=ut==="all"||ut==="cloud";return c.jsxs("div",{className:"shell shell--app",children:[c.jsx("div",{className:"glow glow--app","aria-hidden":!0}),c.jsxs("div",{className:"shell__left",children:[c.jsx(t0,{me:it,welcome:I,onLogout:$,mitmTeam:rt.length>0?rt[0]:null}),c.jsxs("main",{className:"main",children:[c.jsxs("div",{className:"app__tabsrow",children:[c.jsx("div",{className:"app__tabs",children:[{k:"all",label:"全部",n:Rt+Et+aa},{k:"local",label:"本地",n:Rt},{k:"cloud",label:"私有云",n:aa},{k:"custom",label:"自定义",n:Et}].map(({k:B,label:at,n:x})=>c.jsxs("button",{type:"button",className:`app__tab ${ut===B?"is-active":""}`,onClick:()=>S(B),children:[at,c.jsx("span",{className:"app__tab-count",children:x})]},B))}),c.jsxs("button",{type:"button","data-id":"AddTeamButton",className:"app__add-team",title:w("teams.addHint","在云端新建私有云团队"),onClick:()=>Su("?tab=private"),children:["+ ",w("teams.add","新加团队")]})]}),X&&c.jsxs("div",{className:"error",style:{marginBottom:12},children:["云端: ",X,c.jsx("button",{className:"btn-ghost",style:{marginLeft:8},onClick:()=>O(T||D,V),children:"重试"})]}),c.jsxs("div",{className:"app__grid",children:[We&&rt.map(B=>c.jsx(sm,{team:B,onOpen:()=>y(B.id),onRename:d,onRefresh:st},"local:"+B.id)),We&&rt.length===0&&c.jsxs("div",{"data-id":"LocalTeamPlaceholder",className:"bcard bcard--local",children:[c.jsx("div",{className:"bcard__accent"}),c.jsx("div",{className:"bcard__top",children:c.jsxs("div",{className:"bcard__pill",children:[c.jsx("span",{className:"bcard__dot","data-tone":"warn"}),c.jsx(Sm,{})]})}),c.jsxs("div",{className:"bcard__body",children:[c.jsx("h3",{className:"bcard__name",children:"本地团队"}),c.jsx("div",{className:"bcard__host",children:"http://127.0.0.1:8008"}),c.jsx("div",{className:"bcard__meta"})]}),c.jsxs("button",{type:"button",className:"bcard__cta",disabled:!0,children:[c.jsx(ge,{}),c.jsx("span",{children:Yt?"正在启动,就绪后自动加入…":"检测中…"})]})]}),We&&c.jsx(u0,{dockerTeam:ft,onOpen:B=>{var at,x,K;B?y(B):(K=(x=(at=window.cicy)==null?void 0:at.tabs)==null?void 0:x.open)==null||K.call(x,"http://127.0.0.1:8009","Docker cicy-code")},onRefresh:st}),Ka&&Tt.map(B=>c.jsx(sm,{team:B,onOpen:()=>y(B.id),onRename:d,onRefresh:st},"custom:"+B.id)),He&&Re.map(B=>c.jsx(c0,{team:B,onOpen:()=>{var x,K,L;const at=B.kind==="private"?B.host_url:B.workspace_url||B.workspace_direct_url;at&&((L=(K=(x=window.cicy)==null?void 0:x.tabs)==null?void 0:K.open)==null||L.call(K,at,B.name||B.title||""))}},"cloud:"+B.id))]}),!dt&&!X&&k&&k.length===0&&!(U!=null&&U.length)&&c.jsx("div",{className:"empty",style:{marginTop:14},children:"还没有团队 — 安装本地 cicy-code 起一个本地 team,或在云端创建。"})]})]}),c.jsx($y,{}),c.jsx(Wy,{}),c.jsx(i0,{})]})}function Iy({onClose:o}){const[A,T]=N.useState(null),[r,D]=N.useState(""),[q,V]=N.useState(!1),[R,C]=N.useState(""),g=typeof window<"u"&&window.cicy&&window.cicy.trustedOrigins||null,Y=N.useCallback(async()=>{try{T(g&&await g.list()||[])}catch{T([])}},[g]);N.useEffect(()=>{Y()},[Y]);const H=async()=>{const I=r.trim();if(!(!I||q||!g)){V(!0),C("");try{const W=await g.add(I);W&&W.ok===!1?C(W.error||w("trustedSites.addFailed","添加失败")):(D(""),T(W&&W.origins||await g.list()))}catch(W){C(String(W&&W.message||W))}finally{V(!1)}}},lt=async I=>{if(!(q||!g)){V(!0),C("");try{const W=await g.remove(I);W&&W.ok===!1?C(W.error||w("trustedSites.removeFailed","删除失败")):T(W&&W.origins||await g.list())}catch(W){C(String(W&&W.message||W))}finally{V(!1)}}},J={overlay:{position:"fixed",inset:0,zIndex:2e3,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,.62)",backdropFilter:"blur(3px)"},card:{width:560,maxWidth:"94vw",maxHeight:"82vh",display:"flex",flexDirection:"column",background:"#101012",border:"1px solid rgba(255,255,255,.09)",borderRadius:16,boxShadow:"0 24px 64px rgba(0,0,0,.55)",overflow:"hidden",color:"#e4e4e7"},head:{display:"flex",alignItems:"center",gap:8,padding:"14px 16px",borderBottom:"1px solid rgba(255,255,255,.06)"},title:{margin:0,fontSize:15,fontWeight:600,flex:1},x:{background:"transparent",border:"none",color:"#a1a1aa",fontSize:16,cursor:"pointer",lineHeight:1,padding:4},warn:{margin:"14px 16px 0",padding:"10px 12px",fontSize:12.5,lineHeight:1.55,color:"#fca5a5",background:"rgba(239,68,68,.08)",border:"1px solid rgba(239,68,68,.25)",borderRadius:10},addRow:{display:"flex",gap:8,padding:"12px 16px 4px"},input:{flex:1,minWidth:0,background:"#161618",border:"1px solid rgba(255,255,255,.1)",borderRadius:9,padding:"9px 11px",color:"#e4e4e7",fontSize:13,outline:"none"},addBtn:{background:"rgba(255,255,255,.1)",border:"none",borderRadius:9,padding:"0 16px",color:"#fff",fontSize:13,fontWeight:500,cursor:"pointer"},err:{margin:"6px 16px 0",fontSize:12,color:"#fca5a5"},listWrap:{margin:"10px 16px 16px",border:"1px solid rgba(255,255,255,.07)",borderRadius:10,overflow:"auto",flex:1,minHeight:80},row:{display:"flex",alignItems:"center",gap:10,padding:"9px 12px",borderTop:"1px solid rgba(255,255,255,.05)"},host:I=>({flex:1,fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",fontSize:13,color:I?"#71717a":"#e4e4e7",wordBreak:"break-all"}),tag:{fontSize:11,color:"#71717a",background:"rgba(255,255,255,.05)",borderRadius:6,padding:"2px 7px"},rm:{background:"transparent",border:"none",color:"#a1a1aa",fontSize:12,cursor:"pointer",padding:"3px 6px",borderRadius:6},muted:{padding:"16px",textAlign:"center",color:"#71717a",fontSize:12.5}};return Pl.createPortal(c.jsx("div",{style:J.overlay,onClick:o,"data-id":"TrustedSitesModal",children:c.jsxs("div",{style:J.card,onClick:I=>I.stopPropagation(),children:[c.jsxs("div",{style:J.head,children:[c.jsx("h2",{style:J.title,children:w("trustedSites.title","受信任站点")}),c.jsx("button",{type:"button",style:J.x,onClick:o,"aria-label":"close",children:"✕"})]}),c.jsx("div",{style:J.warn,children:w("trustedSites.warn","⚠ 列表中的站点可以在你的电脑上执行命令(exec)。只添加你完全信任的地址。")}),c.jsxs("div",{style:J.addRow,children:[c.jsx("input",{"data-id":"trusted-sites-input",style:J.input,value:r,onChange:I=>D(I.target.value),onKeyDown:I=>{I.key==="Enter"&&H()},placeholder:w("trustedSites.placeholder","添加站点,如 app.cicy-ai.com 或 my-cloud.example.org")}),c.jsx("button",{type:"button","data-id":"trusted-sites-add",style:{...J.addBtn,opacity:q||!r.trim()?.5:1},onClick:H,disabled:q||!r.trim(),children:w("trustedSites.add","添加")})]}),R&&c.jsx("div",{style:J.err,children:R}),c.jsx("div",{style:J.listWrap,children:A===null?c.jsx("div",{style:J.muted,children:w("trustedSites.loading","加载中…")}):A.length===0?c.jsx("div",{style:J.muted,children:w("trustedSites.empty","暂无")}):A.map(I=>c.jsxs("div",{style:J.row,"data-id":"trusted-sites-row",children:[c.jsx("span",{style:J.host(I.builtin),children:I.host}),I.builtin?c.jsx("span",{style:J.tag,children:w("trustedSites.builtin","系统")}):c.jsx("button",{type:"button",style:J.rm,onClick:()=>lt(I.host),disabled:q,children:w("trustedSites.remove","删除")})]},I.host))})]})}),document.body)}function Py({onClose:o}){const[A,T]=N.useState(null),[r,D]=N.useState(""),[q,V]=N.useState(""),[R,C]=N.useState(!1),g=typeof window<"u"&&window.cicy&&window.cicy.rpcAudit||null,Y=N.useCallback(async()=>{C(!0),D("");try{const U=g&&await g.tail(400);!U||U.ok===!1?(D(U&&U.error||w("audit.loadFailed","读取失败")),T([])):(T(U.entries||[]),V(U.path||""))}catch(U){D(String(U&&U.message||U)),T([])}finally{C(!1)}},[g]);N.useEffect(()=>{Y()},[Y]);const[H,lt]=N.useState("all"),[J,I]=N.useState(""),W=U=>{try{return new Date(U).toLocaleString()}catch{return U||""}},it=U=>{if(U.kind==="auth"){const gt=/deny/.test(U.decision||"");return{text:U.decision||"auth",color:gt?"#fca5a5":"#86efac",bg:gt?"rgba(239,68,68,.14)":"rgba(34,197,94,.14)"}}if(U.kind==="rpc"){const gt=U.ok!==!1&&!U.error;return{text:gt?"ok":"err",color:gt?"#86efac":"#fca5a5",bg:gt?"rgba(34,197,94,.14)":"rgba(239,68,68,.14)"}}return{text:U.kind||"log",color:"#a1a1aa",bg:"rgba(255,255,255,.06)"}},Z=U=>U.kind==="auth"?`${U.gate||""}${U.decision?" · "+U.decision:""}`:U.kind==="rpc"?`${U.tool||""}${U.dangerous?" ⚠":""}`:U.kind||"",k=U=>U.error||U.args||(U.kind==="rpc"?U.channel:"")||"",P=A||[],dt=J.trim().toLowerCase(),ot=P.filter(U=>H!=="all"&&U.kind!==H?!1:dt?[U.origin,U.host,U.tool,U.gate,U.decision,U.channel,U.args,U.error,U.kind].filter(Boolean).join(" ").toLowerCase().includes(dt):!0),X="186px 104px minmax(160px,1.1fr) minmax(150px,1.1fr) minmax(220px,1.8fr)",M={overlay:{position:"fixed",inset:0,zIndex:2e3,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,.66)",backdropFilter:"blur(4px)"},card:{width:"96vw",height:"92vh",maxWidth:1480,display:"flex",flexDirection:"column",background:"#0d0d0f",border:"1px solid rgba(255,255,255,.09)",borderRadius:18,boxShadow:"0 32px 80px rgba(0,0,0,.6)",overflow:"hidden",color:"#e4e4e7"},head:{display:"flex",alignItems:"center",gap:14,padding:"20px 24px",borderBottom:"1px solid rgba(255,255,255,.07)"},titleWrap:{flex:1,minWidth:0},title:{margin:0,fontSize:21,fontWeight:650,letterSpacing:.2},subtitle:{margin:"3px 0 0",fontSize:12.5,color:"#71717a",fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",wordBreak:"break-all"},count:{fontSize:12.5,color:"#a1a1aa",whiteSpace:"nowrap"},refresh:{background:"rgba(255,255,255,.1)",border:"none",borderRadius:9,padding:"9px 16px",color:"#fff",fontSize:13,fontWeight:500,cursor:"pointer"},x:{background:"transparent",border:"none",color:"#a1a1aa",fontSize:20,cursor:"pointer",lineHeight:1,padding:6},toolbar:{display:"flex",alignItems:"center",gap:10,padding:"14px 24px",borderBottom:"1px solid rgba(255,255,255,.05)"},chips:{display:"flex",gap:6},chip:U=>({background:U?"rgba(255,255,255,.14)":"transparent",border:"1px solid rgba(255,255,255,.12)",borderRadius:999,padding:"6px 16px",color:U?"#fff":"#a1a1aa",fontSize:13,cursor:"pointer"}),search:{flex:1,minWidth:0,background:"#161618",border:"1px solid rgba(255,255,255,.1)",borderRadius:10,padding:"10px 14px",color:"#e4e4e7",fontSize:13.5,outline:"none"},err:{margin:"10px 24px 0",fontSize:12.5,color:"#fca5a5"},tableWrap:{flex:1,overflow:"auto",margin:"0"},theadRow:{position:"sticky",top:0,zIndex:1,display:"grid",gridTemplateColumns:X,gap:16,padding:"12px 24px",background:"#141417",borderBottom:"1px solid rgba(255,255,255,.08)",fontSize:11.5,letterSpacing:.6,textTransform:"uppercase",color:"#71717a",fontWeight:600},row:{display:"grid",gridTemplateColumns:X,gap:16,padding:"13px 24px",borderBottom:"1px solid rgba(255,255,255,.045)",alignItems:"center"},time:{fontSize:12.5,color:"#a1a1aa",fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",whiteSpace:"nowrap"},badge:U=>({justifySelf:"start",fontSize:11.5,color:U.color,background:U.bg,borderRadius:7,padding:"3px 10px",whiteSpace:"nowrap",fontWeight:500}),cell:{fontSize:13,color:"#d4d4d8",fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",wordBreak:"break-all"},detail:{fontSize:12.5,color:"#8b8b93",wordBreak:"break-all"},muted:{padding:"60px 24px",textAlign:"center",color:"#71717a",fontSize:14}},pt=U=>c.jsx("div",{children:U});return Pl.createPortal(c.jsx("div",{style:M.overlay,onClick:o,"data-id":"AuditLogModal",children:c.jsxs("div",{style:M.card,onClick:U=>U.stopPropagation(),children:[c.jsxs("div",{style:M.head,children:[c.jsxs("div",{style:M.titleWrap,children:[c.jsx("h2",{style:M.title,children:w("audit.title","审计日志")}),q&&c.jsx("p",{style:M.subtitle,children:q})]}),c.jsxs("span",{style:M.count,children:[w("audit.count","共")," ",ot.length,H!=="all"||dt?` / ${P.length}`:""]}),c.jsx("button",{type:"button","data-id":"audit-refresh",style:{...M.refresh,opacity:R?.5:1},onClick:Y,disabled:R,children:w("audit.refresh","刷新")}),c.jsx("button",{type:"button",style:M.x,onClick:o,"aria-label":"close",children:"✕"})]}),c.jsxs("div",{style:M.toolbar,children:[c.jsxs("div",{style:M.chips,children:[c.jsx("button",{type:"button",style:M.chip(H==="all"),onClick:()=>lt("all"),children:w("audit.all","全部")}),c.jsx("button",{type:"button",style:M.chip(H==="rpc"),onClick:()=>lt("rpc"),children:w("audit.rpc","RPC 调用")}),c.jsx("button",{type:"button",style:M.chip(H==="auth"),onClick:()=>lt("auth"),children:w("audit.auth","授权决定")})]}),c.jsx("input",{"data-id":"audit-search",style:M.search,value:J,onChange:U=>I(U.target.value),placeholder:w("audit.search","搜索来源 / 工具 / 命令…")})]}),r&&c.jsx("div",{style:M.err,children:r}),c.jsxs("div",{style:M.tableWrap,children:[c.jsxs("div",{style:M.theadRow,children:[pt(w("audit.colTime","时间")),pt(w("audit.colType","类型")),pt(w("audit.colSource","来源")),pt(w("audit.colOp","操作")),pt(w("audit.colDetail","详情"))]}),A===null?c.jsx("div",{style:M.muted,children:w("audit.loading","加载中…")}):ot.length===0?c.jsx("div",{style:M.muted,children:P.length===0?w("audit.empty","暂无审计记录"):w("audit.noMatch","无匹配记录")}):ot.map((U,gt)=>{const qt=it(U);return c.jsxs("div",{style:M.row,"data-id":"audit-row",children:[c.jsx("span",{style:M.time,children:W(U.ts)}),c.jsx("span",{style:M.badge(qt),children:qt.text}),c.jsx("span",{style:M.cell,children:U.origin||U.host||"—"}),c.jsx("span",{style:M.cell,children:Z(U)||"—"}),c.jsx("span",{style:M.detail,children:k(U)||"—"})]},gt)})]})]})}),document.body)}function t0({me:o,welcome:A,onLogout:T,mitmTeam:r}){const D=(o==null?void 0:o.display_name)||(o==null?void 0:o.username)||"…",q=D.slice(0,1).toUpperCase(),[V,R]=N.useState(!1),[C,g]=N.useState(!1),[Y,H]=N.useState(!1),[lt,J]=N.useState(!1),[I,W]=N.useState(""),it=N.useRef(null);N.useEffect(()=>{var P,dt,ot;let k=!0;return(ot=(dt=(P=window.cicy)==null?void 0:P.app)==null?void 0:dt.getVersion)==null||ot.call(dt).then(X=>{k&&W(typeof X=="string"?X:String((X==null?void 0:X.desktop)||""))}).catch(()=>{}),()=>{k=!1}},[]),N.useEffect(()=>{if(!V)return;const k=P=>{it.current&&!it.current.contains(P.target)&&R(!1)};return document.addEventListener("mousedown",k),()=>document.removeEventListener("mousedown",k)},[V]);const Z=k=>{Su(k),R(!1)};return c.jsxs("header",{className:"topbar",children:[c.jsxs("div",{className:"brand-mini",children:[c.jsx("div",{className:"brand-mark sm",children:c.jsx(bm,{})}),c.jsx("span",{className:"brand-name",children:"CiCy Desktop"})]}),c.jsxs("div",{className:"user-chip","data-id":"UserChip",ref:it,children:[A&&c.jsx("span",{className:"welcome",children:A}),c.jsxs("button",{type:"button","data-id":"UserChip-trigger",className:`user-chip__trigger${V?" is-open":""}`,onClick:()=>R(k=>!k),children:[c.jsx("div",{className:"avatar",children:q}),c.jsx("span",{className:"user-name",children:D}),c.jsx("span",{className:"user-chip__caret","aria-hidden":!0,children:"▾"})]}),V&&c.jsxs("div",{className:"user-chip__menu","data-id":"UserChip-menu",role:"menu",children:[c.jsx("button",{type:"button","data-id":"UserChip-wallet",className:"user-chip__menu-item",onClick:()=>Z("?view=wallet"),children:"我的钱包"}),c.jsx("button",{type:"button","data-id":"UserChip-billing",className:"user-chip__menu-item",onClick:()=>Z("?view=usage"),children:"我的账单"}),c.jsx("button",{type:"button","data-id":"UserChip-trusted-sites",className:"user-chip__menu-item",onClick:()=>{R(!1),g(!0)},children:w("trustedSites.menu","受信任站点")}),c.jsx("button",{type:"button","data-id":"UserChip-audit-log",className:"user-chip__menu-item",onClick:()=>{R(!1),H(!0)},children:w("audit.menu","审计日志")}),c.jsx("button",{type:"button","data-id":"UserChip-terms",className:"user-chip__menu-item",onClick:()=>{R(!1),J(!0)},children:w("firstRunTerms.menu","用户协议")}),r&&c.jsx("div",{className:"user-chip__menu-mitm","data-id":"UserChip-mitm",onClick:k=>k.stopPropagation(),children:c.jsx(e0,{team:r,variant:"menu"})}),c.jsx("div",{className:"user-chip__menu-sep","aria-hidden":!0}),c.jsx("button",{type:"button","data-id":"UserChip-logout",className:"user-chip__menu-item is-danger",onClick:()=>{R(!1),T()},children:"退出"}),c.jsxs("div",{className:"user-chip__menu-version","data-id":"UserChip-version",children:["CiCy Desktop ",I?`v${I}`:"…"]})]})]}),C&&c.jsx(Iy,{onClose:()=>g(!1)}),Y&&c.jsx(Py,{onClose:()=>H(!1)}),lt&&c.jsx(pm,{onClose:()=>J(!1)})]})}function pm({onAgree:o,onClose:A}){var it;const[T,r]=N.useState(!1),[D,q]=N.useState(!1),[V,R]=N.useState(!1),C=(((it=window.cicyI18n)==null?void 0:it.locale)||"en").startsWith("zh")?"zh-CN":"en",g=(Z,k)=>w(`firstRunTerms.${Z}`,k),Y=!!A,H=[1,2,3,4,5,6].map(Z=>g(`summary${Z}`,"")),lt=Z=>{const k=Z.currentTarget;k.scrollHeight-k.scrollTop-k.clientHeight<24&&r(!0)},J=N.useRef(null);N.useEffect(()=>{const Z=J.current;Z&&Z.scrollHeight<=Z.clientHeight+24&&r(!0)},[D]);const I=async()=>{var Z,k,P;if(!(V||!T)){R(!0);try{await((P=(k=(Z=window.cicy)==null?void 0:Z.terms)==null?void 0:k.agree)==null?void 0:P.call(k,vm)),o==null||o()}catch{o==null||o()}}},W=()=>{var Z,k,P;try{(P=(k=(Z=window.cicy)==null?void 0:Z.terms)==null?void 0:k.decline)==null||P.call(k)}catch{}};return c.jsxs("div",{className:Y?"terms-gate terms-gate--review":"shell terms-gate","data-id":"FirstRunTermsGate",style:Y?{position:"fixed",inset:0,zIndex:1e3,background:"rgba(8,9,14,.72)",backdropFilter:"blur(4px)"}:void 0,onClick:Y?Z=>{Z.target===Z.currentTarget&&A()}:void 0,children:[c.jsx("div",{className:"glow","aria-hidden":!0}),c.jsxs("div",{className:"terms-gate__panel",children:[c.jsx("h1",{className:"terms-gate__title","data-id":"FirstRunTermsGate-title",children:g("title","用户协议与授权说明")}),c.jsx("p",{className:"terms-gate__subtitle",children:g("subtitle","使用 CiCy Desktop 前,请阅读并同意以下条款")}),c.jsxs("div",{className:"terms-gate__body",ref:J,onScroll:lt,"data-id":"FirstRunTermsGate-body",children:[c.jsx("h2",{className:"terms-gate__h2",children:g("summaryTitle","一眼看懂")}),c.jsx("ol",{className:"terms-gate__summary",children:H.filter(Boolean).map((Z,k)=>c.jsx("li",{children:Z},k))}),D?c.jsx("pre",{className:"terms-gate__fulltext","data-id":"FirstRunTermsGate-fulltext",children:lm[C]||lm.en}):c.jsx("button",{className:"terms-gate__viewfull","data-id":"FirstRunTermsGate-viewfull",onClick:()=>q(!0),children:g("viewFull","查看完整条款")})]}),Y?c.jsx("div",{className:"terms-gate__actions",children:c.jsx("button",{"data-id":"FirstRunTermsGate-close",className:"terms-gate__btn",onClick:A,children:g("close","关闭")})}):c.jsxs(c.Fragment,{children:[!T&&c.jsx("div",{className:"terms-gate__scrollhint","data-id":"FirstRunTermsGate-scrollhint",children:g("scrollHint","请阅读至底部以继续")}),c.jsxs("div",{className:"terms-gate__actions",children:[c.jsx("button",{"data-id":"FirstRunTermsGate-decline",className:"terms-gate__btn terms-gate__btn--ghost",onClick:W,children:g("decline","不同意并退出")}),c.jsx("button",{"data-id":"FirstRunTermsGate-agree",className:"terms-gate__btn",disabled:!T||V,title:T?"":g("mustAgree","未同意则无法使用本软件。"),onClick:I,children:g("agree","同意并继续")})]})]})]})]})}function e0({team:o,variant:A}){const[T,r]=N.useState(void 0),[D,q]=N.useState(""),[V,R]=N.useState(""),C=((o==null?void 0:o.base_url)||"").replace(/\/$/,""),g=(o==null?void 0:o.api_token)||"",Y=N.useCallback(async(Z,k={})=>{var ot,X;if(!((X=(ot=window.cicy)==null?void 0:ot.cloud)!=null&&X.fetch))throw new Error("bridge missing");const P=await window.cicy.cloud.fetch(`${C}${Z}`,{...k,headers:{Authorization:`Bearer ${g}`,"Content-Type":"application/json",...k.headers||{}}});let dt=null;try{dt=JSON.parse(P.body)}catch{}return{ok:P.ok,status:P.status,json:dt}},[C,g]),H=N.useCallback(async()=>{try{const Z=await Y("/api/mitm/ca-status");r(Z.ok&&Z.json?Z.json:null)}catch{r(null)}},[Y]);if(N.useEffect(()=>{C&&g&&H()},[C,g,H]),T===void 0||!T||!T.generated)return null;const lt=async()=>{var Z,k,P,dt,ot,X,M,pt,U;if(!D){q("enable"),R("");try{const gt=await Y("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!0})}),qt=`${((Z=gt.json)==null?void 0:Z.error)||""} ${((k=gt.json)==null?void 0:k.detail)||""}`,Lt=((P=gt.json)==null?void 0:P.error)==="need_elevation"||!gt.ok&&gt.status===403||/need_elevation|add-trusted-cert|write permission|SecCertificate|not permitted|requires admin|administrator/i.test(qt);if(gt.ok&&((dt=gt.json)!=null&&dt.ok)&&((ot=gt.json)!=null&&ot.trusted))await H();else if(Lt){const Yt=await((pt=(M=(X=window.cicy)==null?void 0:X.mitm)==null?void 0:M.caExec)==null?void 0:pt.call(M,"install"));Yt!=null&&Yt.ok?await H():R(/cancel/i.test((Yt==null?void 0:Yt.stderr)||"")?w("mitmConsent.errorAdminDenied","未获得管理员授权,已取消。"):(Yt==null?void 0:Yt.stderr)||w("mitmConsent.errorTitle","提权失败,请从管理员控制台运行"))}else R(((U=gt.json)==null?void 0:U.error)||`失败 (HTTP ${gt.status})`)}catch(gt){R(String((gt==null?void 0:gt.message)||gt))}finally{q("")}}},J=async()=>{var Z,k,P,dt,ot;if(!D){q("disable"),R("");try{const X=await Y("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!1})});if(X.ok&&((Z=X.json)!=null&&Z.ok))await H();else{const M=await((dt=(P=(k=window.cicy)==null?void 0:k.mitm)==null?void 0:P.caExec)==null?void 0:dt.call(P,"uninstall"));M!=null&&M.ok?await H():R((M==null?void 0:M.stderr)||((ot=X.json)==null?void 0:ot.error)||"撤销失败")}}catch(X){R(String((X==null?void 0:X.message)||X))}finally{q("")}}},I=T.consent&&T.trusted,W=T.consent&&!T.trusted,it=(Z,k)=>w(`mitmConsent.${Z}`,k);if(A==="menu"){const Z=k=>{var P;(P=k==null?void 0:k.stopPropagation)==null||P.call(k),!D&&(I?window.confirm(it("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&J():lt())};return c.jsxs("div",{className:"user-chip__mitm","data-id":"MitmConsentCard",children:[c.jsxs("div",{className:"user-chip__menu-item user-chip__mitm-row",title:it("scopeNote","仅解密 AI 厂商域名,数据留本地,随时可关闭。"),children:[c.jsx("span",{className:"user-chip__mitm-label",children:it("rowLabel","HTTPS 审计")}),c.jsx("button",{type:"button",role:"switch","aria-checked":I?"true":"false","data-id":"MitmConsentCard-toggle",className:`mini-switch${I?" is-on":""}${D?" is-busy":""}`,disabled:!!D,onClick:Z,children:c.jsx("span",{className:"mini-switch__knob"})})]}),W&&!D&&c.jsx("div",{className:"user-chip__mitm-note","data-id":"MitmConsentCard-note",children:it("partialNote","已同意但未安装,点开关重试")}),V&&c.jsx("div",{className:"user-chip__mitm-err","data-id":"MitmConsentCard-error",children:V})]})}return I||D==="disable"?Pl.createPortal(c.jsxs("div",{"data-id":"MitmConsentCard",className:"mitm-pill",title:it("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具生效;随时可关闭。"),children:[c.jsx("span",{className:"mitm-pill__dot","data-busy":D?"1":"0"}),c.jsx("span",{className:"mitm-pill__text","data-id":"MitmConsentCard-title",children:D==="disable"?it("processingRevoke","正在关闭…"):it("statePillOn","HTTPS 审计已开启")}),!D&&c.jsx("button",{type:"button","data-id":"MitmConsentCard-revoke",className:"mitm-pill__off",onClick:()=>{window.confirm(it("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&J()},children:it("turnOff","关闭")})]}),document.body):c.jsxs("div",{"data-id":"MitmConsentCard",className:`mitm-card${I?" mitm-card--on":""}`,children:[c.jsxs("div",{className:"mitm-card__head",children:[c.jsx("span",{className:"mitm-card__dot","data-state":I?"on":W?"warn":"off"}),c.jsx("span",{className:"mitm-card__title","data-id":"MitmConsentCard-title",children:D?it("stateProcessingTitle","处理中…"):I?it("stateGrantedTitle","已启用"):`${it("cardTitle","HTTPS 流量本地审计")}${W?" — "+it("retry","重试"):""}`})]}),c.jsxs("p",{className:"mitm-card__desc","data-id":"MitmConsentCard-desc",children:[I?it("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具(claude / codex 等)生效;随时可关闭。"):it("body","启用后,CiCy 启动的 AI 工具(claude / codex 等)访问 AI 厂商(Claude / OpenAI / DeepSeek / Gemini)的 HTTPS 流量将被本地审计解密,数据留本地,随时可关闭。"),!I&&c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsx("span",{className:"mitm-card__note",children:it("adminNote","通过环境变量对 CiCy 启动的 AI 工具生效,不修改系统、无需管理员授权。")}),c.jsx("br",{}),c.jsx("span",{className:"mitm-card__sub",children:it("scopeNote","仅解密上述 AI 厂商域名,其余一切流量不被解密、不被读取。")})]})]}),V&&c.jsxs("div",{className:"mitm-card__error","data-id":"MitmConsentCard-error",children:[it("errorTitle","操作失败"),": ",V]}),c.jsx("div",{className:"mitm-card__actions",children:I?c.jsx("button",{"data-id":"MitmConsentCard-revoke",className:"mitm-card__btn mitm-card__btn--ghost",disabled:!!D,onClick:()=>{window.confirm(it("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&J()},children:D==="disable"?it("processingRevoke","正在关闭…"):it("revoke","撤销")}):c.jsx("button",{"data-id":"MitmConsentCard-enable",className:"mitm-card__btn",disabled:!!D,onClick:lt,children:D==="enable"?it("processingEnable","正在启用…"):W?it("retry","重试"):it("enable","同意并启用")})})]})}const Zs=new Set;let um=0,Ft=null;function Il(){Zs.forEach(o=>o(Ft))}const ie={open({onRetry:o}={}){Ft={status:"running",phase:"install-docker",logs:[],bars:{},minimized:!1,onRetry:o||null,lastAt:Date.now()},Il()},minimize(){Ft&&(Ft={...Ft,minimized:!0},Il())},restore(){Ft&&(Ft={...Ft,minimized:!1},Il())},push(o={}){var V;if(!Ft)return;const A=o.phase==="health"?"container":o.phase||Ft.phase,T={...Ft,phase:A,lastAt:Date.now()},r=Number.isFinite(o.progress),D=A==="install-docker"||A==="image";if(D&&(r||o.dest||o.url)){const R=((V=Ft.bars)==null?void 0:V[A])||{},C=r?o.progress:o.status==="skip"||o.status==="done"?100:R.progress;T.bars={...Ft.bars,[A]:{progress:C,received:o.received??R.received,total:o.total??R.total,url:o.url||R.url,dest:o.dest||R.dest}}}if(!(o.status==="running"&&r&&D)){const R={id:++um,t:bu(),phase:A,status:o.status||"running",message:o.message||""};T.logs=[...Ft.logs,R]}Ft=T,Il()},finish({ok:o,message:A,status:T}={}){if(!Ft)return;const r=T||(o?"done":"error"),D={id:++um,t:bu(),phase:"done",status:r,message:A||(o?"完成":"失败")};Ft={...Ft,status:r,phase:"done",minimized:!1,logs:[...Ft.logs,D],lastAt:Date.now()},Il()},close(){Ft=null,Il()}},ks=[["install-docker","准备环境"],["image","加载镜像"],["container","启动容器"],["done","完成"]],a0={"install-docker":"Docker",image:"镜像",container:"容器",health:"容器",done:"完成"},l0={"install-docker":"Docker Desktop",image:"基础镜像"};function cm(o){return Number.isFinite(o)?o<1024?o+" B":o<1048576?(o/1024).toFixed(0)+" KB":o<1073741824?(o/1048576).toFixed(1)+" MB":(o/1073741824).toFixed(2)+" GB":"?"}function n0({phaseKey:o,bar:A}){const T=Number.isFinite(A==null?void 0:A.progress)?Math.max(0,Math.min(100,A.progress)):0,r=T>=100;return c.jsxs("div",{className:"dlbar","data-id":`DockerDrawer-dlbar-${o}`,children:[c.jsxs("div",{className:"dlbar__head",children:[c.jsx("span",{className:"dlbar__name",children:l0[o]||o}),c.jsxs("span",{className:"dlbar__pct",children:[T,"%",A!=null&&A.total?` · ${cm(A.received)} / ${cm(A.total)}`:""]})]}),c.jsx("div",{className:"dlbar__track",children:c.jsx("div",{className:`dlbar__fill${r?" is-done":""}`,style:{width:`${T}%`}})}),(A==null?void 0:A.url)&&c.jsxs("div",{className:"dlbar__url",title:A.url,children:[c.jsx("span",{className:"dlbar__urlk",children:"源"})," ",A.url]}),(A==null?void 0:A.dest)&&c.jsxs("div",{className:"dlbar__url",title:A.dest,children:[c.jsx("span",{className:"dlbar__urlk",children:"存"})," ",A.dest]})]})}function i0(){var V;const[o,A]=N.useState(Ft);N.useEffect(()=>(Zs.add(A),()=>{Zs.delete(A)}),[]);const T=N.useRef(null);if(N.useEffect(()=>{const R=T.current;R&&(R.scrollTop=R.scrollHeight)},[(V=o==null?void 0:o.logs)==null?void 0:V.length]),!o)return null;const r=o.status==="running",D=ks.findIndex(([R])=>R===o.phase),q=["install-docker","image"].filter(R=>{var C;return(C=o.bars)==null?void 0:C[R]});if(o.minimized){const R=q.map(g=>{var Y;return(Y=o.bars[g])==null?void 0:Y.progress}).filter(Number.isFinite),C=R.length?Math.round(R.reduce((g,Y)=>g+Y,0)/R.length):null;return c.jsxs("button",{type:"button",className:`drawer-min drawer-min--${o.status}`,"data-id":"DockerDrawer-restore",onClick:()=>ie.restore(),children:[c.jsx("span",{className:"drawer-min__spark",children:r?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("span",{className:"drawer-min__label",children:[w("docker.setupTitle","安装 Docker cicy-code"),C!=null?` · ${C}%`:""]})]})}return c.jsx("div",{className:"drawer-scrim","data-id":"DockerDrawer-scrim",onClick:()=>r?ie.minimize():ie.close(),children:c.jsxs("div",{className:"drawer","data-id":"DockerDrawer","data-status":o.status,onClick:R=>R.stopPropagation(),children:[c.jsxs("div",{className:"drawer__head",children:[c.jsxs("div",{className:"drawer__title",children:[c.jsx("span",{className:`drawer__spark drawer__spark--${o.status}`,children:r?c.jsx(ge,{}):o.status==="done"?"✓":o.status==="reboot"?"⟳":"!"}),c.jsxs("div",{children:[c.jsx("div",{className:"drawer__h",children:w("docker.setupTitle","安装 Docker cicy-code")}),c.jsx("div",{className:"drawer__sub",children:"127.0.0.1:8009"})]})]}),c.jsx("div",{className:"drawer__headbtns",children:c.jsx("button",{type:"button",className:"drawer__x","data-id":"DockerDrawer-min",title:w("common.minimize","最小化"),onClick:()=>ie.minimize(),"aria-label":"minimize",children:"‒"})})]}),c.jsx("div",{className:"drawer__steps","data-id":"DockerDrawer-steps",children:ks.map(([R,C],g)=>{const Y=o.status==="done"||D>=0&&g<D,H=g===D&&r,lt=o.status==="error"&&g===D;return c.jsxs("div",{className:`drawer__step${H?" is-active":""}${Y?" is-done":""}${lt?" is-error":""}`,children:[c.jsx("span",{className:"drawer__step-dot",children:Y?"✓":lt?"!":g+1}),c.jsx("span",{className:"drawer__step-label",children:C}),g<ks.length-1&&c.jsx("span",{className:"drawer__step-bar"})]},R)})}),q.length>0&&c.jsx("div",{className:"drawer__dlbars","data-id":"DockerDrawer-dlbars",children:q.map(R=>c.jsx(n0,{phaseKey:R,bar:o.bars[R]},R))}),r&&o.logs.length>0&&c.jsxs("div",{className:"drawer__now","data-id":"DockerDrawer-now",children:[c.jsx(ge,{}),c.jsx("span",{children:o.logs[o.logs.length-1].message})]}),c.jsx("div",{className:"drawer__log drawer__log--scroll","data-id":"DockerDrawer-log",ref:T,children:o.logs.length===0?c.jsx("div",{className:"drawer__log-empty",children:w("docker.preparing","准备中…")}):o.logs.map(R=>c.jsxs("div",{className:"drawer__line","data-status":R.status,children:[c.jsx("span",{className:"drawer__t",children:R.t}),c.jsx("span",{className:`drawer__badge drawer__badge--${R.phase}`,children:a0[R.phase]||R.phase}),c.jsx("span",{className:"drawer__linemsg",children:R.message})]},R.id))}),c.jsx("div",{className:"drawer__foot",children:r?c.jsx(c.Fragment,{children:c.jsx("span",{className:"drawer__foot-status",children:w("docker.installing2","安装进行中…")})}):o.status==="reboot"?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-reboot",children:w("docker.rebootShort","需重启 Windows")}),o.onRetry&&c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"DockerDrawer-retry",onClick:()=>o.onRetry(),children:w("common.retry","重试")}),c.jsx("button",{type:"button",className:"drawer__btn","data-id":"DockerDrawer-dismiss",onClick:()=>ie.close(),children:w("common.close","关闭")})]}):o.status==="error"?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-error",children:w("docker.failed","安装失败")}),o.onRetry&&c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"DockerDrawer-retry",onClick:()=>o.onRetry(),children:w("common.retry","重试")}),c.jsx("button",{type:"button",className:"drawer__btn","data-id":"DockerDrawer-dismiss",onClick:()=>ie.close(),children:w("common.close","关闭")})]}):c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"drawer__foot-status is-done",children:w("docker.ready","已就绪")}),c.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"DockerDrawer-finish",onClick:()=>ie.close(),children:w("common.done","完成")})]})})]})})}function u0({dockerTeam:o,onOpen:A,onRefresh:T}){var me;const[r,D]=N.useState(null),[q,V]=N.useState(""),[R,C]=N.useState(!1),[g,Y]=N.useState({top:0,left:0}),H=N.useRef(null),lt=N.useRef(null),J=184,I="#2496ed",W=N.useCallback(async()=>{var ut,S,O;try{D(await((O=(S=(ut=window.cicy)==null?void 0:ut.docker)==null?void 0:S.appStatus)==null?void 0:O.call(S)))}catch(Q){console.warn("[DockerCard]",Q)}},[]);N.useEffect(()=>{W();const ut=setInterval(()=>{q||W()},12e3);return()=>clearInterval(ut)},[W,q]),N.useEffect(()=>{if(!R)return;const ut=O=>{var Q,mt;(Q=H.current)!=null&&Q.contains(O.target)||(mt=lt.current)!=null&&mt.contains(O.target)||C(!1)},S=O=>{O.key==="Escape"&&C(!1)};return document.addEventListener("mousedown",ut),document.addEventListener("keydown",S),()=>{document.removeEventListener("mousedown",ut),document.removeEventListener("keydown",S)}},[R]);const it=()=>{if(!R&&H.current){const ut=H.current.getBoundingClientRect(),S=Math.max(8,Math.min(ut.right-J,window.innerWidth-J-8));Y({top:Math.round(ut.bottom+4),left:Math.round(S)})}C(ut=>!ut)},Z=N.useCallback(async()=>{var S,O,Q,mt,st,d;V("bootstrap"),ie.open({onRetry:Z});const ut=(Q=(O=(S=window.cicy)==null?void 0:S.docker)==null?void 0:O.onAppProgress)==null?void 0:Q.call(O,y=>ie.push(y));try{const y=await((d=(st=(mt=window.cicy)==null?void 0:mt.docker)==null?void 0:st.appBootstrap)==null?void 0:d.call(st));(y==null?void 0:y.reason)==="installer_launched"?ie.finish({status:"reboot",message:w("docker.installerLaunched","已打开 Docker 安装程序——请完成安装(会装 WSL2、可能需重启),装好后点「重试」")}):(y==null?void 0:y.reason)==="wsl_reboot_required"?ie.finish({status:"reboot",message:w("docker.rebootNeeded","WSL2 已安装,请【重启 Windows】后回来点「重试」继续")}):ie.finish({ok:!!(y!=null&&y.ok),message:y!=null&&y.ok?w("docker.ready","Docker cicy-code 已就绪"):(y==null?void 0:y.error)||w("docker.failed","安装失败")}),y!=null&&y.ok&&(T==null||T())}catch(y){ie.finish({ok:!1,message:y.message})}finally{try{ut&&ut()}catch{}V(""),W()}},[W,T]),k=N.useCallback(async()=>{var S,O,Q,mt,st,d;C(!1),V("upgrade"),ie.open({onRetry:k});const ut=(Q=(O=(S=window.cicy)==null?void 0:S.docker)==null?void 0:O.onAppProgress)==null?void 0:Q.call(O,y=>ie.push(y));try{const y=await((d=(st=(mt=window.cicy)==null?void 0:mt.docker)==null?void 0:st.appUpgrade)==null?void 0:d.call(st));(y==null?void 0:y.reason)==="wsl_reboot_required"?ie.finish({status:"reboot",message:w("docker.rebootNeeded","WSL2 已安装,请【重启 Windows】后回来点「重试」继续")}):ie.finish({ok:!!(y!=null&&y.ok),message:y!=null&&y.ok?w("docker.upgraded","已升级到最新"):(y==null?void 0:y.error)||w("docker.upgradeFailed","升级失败")}),y!=null&&y.ok&&(T==null||T())}catch(y){ie.finish({ok:!1,message:y.message})}finally{try{ut&&ut()}catch{}V(""),W()}},[W,T]),P=N.useCallback(async(ut,S,O)=>{C(!1),V(ut),de.show({id:"docker-op",message:w(`docker.${ut}ing`,ut==="restart"?"重启中…":"停止中…"),status:"running"});try{const Q=await S();Q!=null&&Q.ok?de.show({id:"docker-op",message:O,status:"done",ttl:2500}):de.show({id:"docker-op",message:(Q==null?void 0:Q.error)||w("docker.opFailed","操作失败"),status:"error",ttl:6e3})}catch(Q){de.show({id:"docker-op",message:Q.message,status:"error",ttl:6e3})}finally{V(""),W()}},[W]);if((((me=window.cicy)==null?void 0:me.platform)||(r==null?void 0:r.platform))!=="win32")return null;const ot=!!(r!=null&&r.running)||(o==null?void 0:o.status)==="running",X=!!(r!=null&&r.dockerRunning),M=!!(r!=null&&r.installed),pt=ot?"ok":X||M?"warn":"off",U=!!q,gt=ot?w("docker.running","运行中 · :8009"):X?w("docker.notRunning","未启动 · 点「启动」"):M?w("docker.engineDown","Docker 未运行 · 点启动"):w("docker.notInstalled","Docker Desktop 未安装"),qt=U?w("docker.working","处理中…"):ot?w("localTeams.open","打开"):X?w("docker.start","启动"):M?w("docker.startDocker","启动 Docker"):w("docker.install","下载安装"),Lt=()=>{if(!U){if(ot){A==null||A(o==null?void 0:o.id);return}Z()}},Yt=ot;return c.jsxs("div",{"data-id":"DockerCard",className:`bcard bcard--docker${ot?" bcard--online":""}`,children:[c.jsx("div",{className:"bcard__accent",style:{background:I}}),c.jsxs("div",{className:"bcard__top",children:[c.jsxs("div",{className:"bcard__pill",style:{color:I},children:[c.jsx("span",{className:"bcard__dot","data-tone":pt}),c.jsx("svg",{style:{width:18,height:18},viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:c.jsx("path",{d:"M21.81 10.25c-.06-.05-.67-.51-1.95-.51-.34 0-.68.03-1.01.09-.25-1.69-1.64-2.51-1.7-2.55l-.34-.2-.22.32a4.5 4.5 0 0 0-.59 1.4c-.23.94-.09 1.83.39 2.59-.58.32-1.51.4-1.7.41H2.62a.61.61 0 0 0-.61.61 9.32 9.32 0 0 0 .57 3.35 4.9 4.9 0 0 0 1.95 2.53c.92.52 2.42.82 4.12.82.77 0 1.54-.07 2.3-.21a9.6 9.6 0 0 0 3-1.09 8.3 8.3 0 0 0 2.05-1.68c.98-1.11 1.56-2.35 1.99-3.45h.17c1.36 0 2.2-.55 2.66-1l.13-.16zM4.7 11.33h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H4.7a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.46 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H7.16a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.5 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H9.66a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.47 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16h-1.78a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16M7.16 9.06h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16H7.16a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.5 0h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16H9.66a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.47 0h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16h-1.78a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16"})})]}),Yt&&c.jsxs("div",{className:"bcard__menuwrap",onClick:ut=>ut.stopPropagation(),children:[c.jsx("button",{type:"button",ref:H,"data-id":"DockerCard-menu-btn",className:"bcard__kebab",title:w("docker.manage","管理 Docker cicy-code"),disabled:U,onClick:it,children:U?c.jsx(ge,{}):c.jsx(Js,{})}),R&&Pl.createPortal(c.jsxs("div",{className:"bcard__menu bcard__menu--portal","data-id":"DockerCard-menu",role:"menu",ref:lt,style:{position:"fixed",top:g.top,left:g.left,width:J},onClick:ut=>ut.stopPropagation(),children:[ot&&c.jsx("button",{type:"button","data-id":"DockerCard-restart",className:"bcard__menu-item",onClick:()=>P("restart",()=>window.cicy.docker.appRestart(),w("docker.restarted","已重启")),children:w("docker.restart","重启")}),c.jsx("button",{type:"button","data-id":"DockerCard-upgrade",className:"bcard__menu-item is-accent",onClick:k,children:w("docker.upgrade","升级(拉取最新镜像)")}),ot&&c.jsx("button",{type:"button","data-id":"DockerCard-stop",className:"bcard__menu-item is-danger",onClick:()=>P("stop",()=>window.cicy.docker.appStop(),w("docker.stopped","已停止")),children:w("docker.stop","停止")})]}),document.body)]})]}),c.jsxs("div",{className:"bcard__body",children:[c.jsx("h3",{className:"bcard__name",children:w("docker.title","Docker cicy-code")}),c.jsx("div",{className:"bcard__host",children:"http://127.0.0.1:8009"}),c.jsx("div",{className:"bcard__meta",style:{fontSize:12,color:"#8b949e"},children:gt})]}),c.jsxs("button",{type:"button",className:"bcard__cta","data-id":"DockerCard-cta",disabled:U,onClick:Lt,style:ot?void 0:{background:I,color:"white"},children:[U?c.jsx(ge,{}):c.jsx(_u,{}),c.jsx("span",{children:qt})]})]})}function sm({team:o,onOpen:A,onRename:T,onRefresh:r}){var Ka,He,B,at;const q=(rm[o.status]||rm.error).tone,[V,R]=N.useState(!1),[C,g]=N.useState(o.name||""),[Y,H]=N.useState(null),[lt,J]=N.useState(""),I=Y??o.name;N.useEffect(()=>{Y!=null&&o.name===Y&&H(null)},[o.name,Y]);const W=x=>{var K;(K=x==null?void 0:x.stopPropagation)==null||K.call(x),g(I||""),R(!0)},it=async()=>{R(!1);const x=String(C||"").trim();if(!T||!x||x===I)return;H(x),J("saving");let K;try{K=await T(o.id,x)}catch(L){K={ok:!1,error:L==null?void 0:L.message}}H(null),K&&K.ok?(J("saved"),setTimeout(()=>J(L=>L==="saved"?"":L),1500)):(J(""),de.show({message:w("localTeams.renameFailed","改名没保存,已恢复"),status:"error",ttl:4e3}))},k=!!((He=(Ka=window.cicy)==null?void 0:Ka.sidecar)!=null&&He.restart)&&Vs(o.base_url),P=o.status==="running",[dt,ot]=N.useState(""),[X,M]=N.useState(!1),[pt,U]=N.useState({running:void 0,latest:null,installed:null}),gt=pt.latest,qt=pt.running,[Lt,Yt]=N.useState(!1),me=N.useRef(null),ut=N.useRef(null),S=N.useRef(null),[O,Q]=N.useState({top:0,left:0}),mt=184,st=()=>{if(!X&&ut.current){const x=ut.current.getBoundingClientRect(),K=Math.max(8,Math.min(x.right-mt,window.innerWidth-mt-8));Q({top:Math.round(x.bottom+4),left:Math.round(K)})}M(x=>!x)},d=N.useCallback(async(x=!1)=>{var K,L;if(!(!k||!((L=(K=window.cicy)==null?void 0:K.sidecar)!=null&&L.versions))){x&&Yt(!0);try{const et=await window.cicy.sidecar.versions();U({running:(et==null?void 0:et.running)??null,latest:(et==null?void 0:et.latest)??null,installed:(et==null?void 0:et.installed)??null}),x&&(et!=null&&et.running&&(et!=null&&et.latest)&&fm(et.latest,et.running)>0?de.show({message:`${w("sidecar.found","发现新版本")} v${et.latest}`,status:"done",ttl:2500}):et!=null&&et.running?de.show({message:`${w("sidecar.upToDate","已是最新")} v${et.running}`,status:"done",ttl:2500}):de.show({message:w("sidecar.notRunning","cicy-code 未运行"),status:"error",ttl:4e3}))}catch{x&&de.show({message:w("sidecar.checkFailed","检查更新失败"),status:"error",ttl:5e3})}finally{x&&Yt(!1)}}},[k]);N.useEffect(()=>{d(!1)},[d]),N.useEffect(()=>{P&&d(!1)},[P,d]);const y=!!(k&&gt&&qt&&fm(gt,qt)>0),G=!k&&!!((at=(B=window.cicy)==null?void 0:B.localTeams)!=null&&at.remove),$=k||G,[ft,rt]=N.useState(!1);N.useEffect(()=>{if(!X)return;const x=K=>{var L,et;(L=ut.current)!=null&&L.contains(K.target)||(et=S.current)!=null&&et.contains(K.target)||M(!1)};return document.addEventListener("mousedown",x),()=>document.removeEventListener("mousedown",x)},[X]),N.useEffect(()=>{X||rt(!1)},[X]);const Tt=async()=>{var x,K,L;if(!ft){rt(!0);return}if(M(!1),rt(!1),!dt){ot("remove");try{await((L=(K=(x=window.cicy)==null?void 0:x.localTeams)==null?void 0:K.remove)==null?void 0:L.call(K,o.id))}catch{}ot(""),r==null||r()}},Rt=`sidecar-op:${o.id}`,Et=async(x,K,L)=>{var ue,Xt,kt,Ae,tn;if(M(!1),dt)return;ot(x);const et=x==="update";let Zt=null;et?(ea.open({teamId:o.id,fromVer:qt,toVer:gt,onRetry:()=>Et("update",K,L)}),(Xt=(ue=window.cicy)==null?void 0:ue.sidecar)!=null&&Xt.onOpProgress&&(Zt=window.cicy.sidecar.onOpProgress(Gt=>{(Gt==null?void 0:Gt.op)==="update"&&ea.push(Gt)}))):de.show({id:Rt,message:Re[x]||`${x}…`,status:"running",progress:void 0});try{const Gt=await K(),ve=!!(Gt!=null&&Gt.ok),Pn=Gt!=null&&Gt.warning?`${L}(${Gt.warning})`:L,en=w("sidecar.failed","操作失败")+(Gt!=null&&Gt.error?`: ${Gt.error}`:"");if(et){if(ea.finish({ok:ve,message:ve?Pn:en}),ve)try{await((tn=(Ae=(kt=window.cicy)==null?void 0:kt.localTeams)==null?void 0:Ae.reload)==null?void 0:tn.call(Ae,o.id,{ignoreCache:!0}))}catch{}}else de.show({id:Rt,message:ve?Pn:en,progress:void 0,status:ve?"done":"error",ttl:ve?4e3:8e3})}catch(Gt){const ve=w("sidecar.failed","操作失败")+`: ${(Gt==null?void 0:Gt.message)||Gt}`;et?ea.finish({ok:!1,message:ve}):de.show({id:Rt,message:ve,progress:void 0,status:"error",ttl:8e3})}finally{try{Zt&&Zt()}catch{}ot(""),r==null||r(),(x==="update"||x==="restart"||x==="start")&&d(!1)}},Re={start:"启动中…",restart:"重启中…",update:"更新中…",stop:"停止中…"},aa=async()=>{var x,K;if(!dt){if(!P&&k&&((K=(x=window.cicy)==null?void 0:x.sidecar)!=null&&K.start)){ot("start"),de.show({id:Rt,message:Re.start,status:"running",progress:void 0});const L=await window.cicy.sidecar.start().catch(et=>({ok:!1,error:(et==null?void 0:et.message)||String(et)}));if(ot(""),r==null||r(),!(L!=null&&L.ok)||L!=null&&L.warning){de.show({id:Rt,message:w("sidecar.startFailed","启动失败")+(L!=null&&L.error?`: ${L.error}`:L!=null&&L.warning?`: ${L.warning}`:""),status:"error",ttl:8e3});return}de.dismiss(Rt)}A()}},We=P?w("localTeams.open","打开"):k?w("localTeams.startOpen","启动并打开"):w("localTeams.open","打开");return c.jsxs("div",{"data-id":"LocalTeamCard",className:`bcard ${k?"bcard--local":"bcard--custom"}${q==="ok"?" bcard--online":""}`,children:[c.jsx("div",{className:"bcard__accent"}),c.jsxs("div",{className:"bcard__top",children:[c.jsxs("div",{className:"bcard__pill",children:[c.jsx("span",{className:"bcard__dot","data-tone":q}),c.jsx(Sm,{})]}),$&&c.jsxs("div",{className:"bcard__menuwrap",ref:me,onClick:x=>x.stopPropagation(),children:[c.jsx("button",{type:"button",ref:ut,"data-id":"LocalTeamCard-menu-btn",className:`bcard__kebab${y?" has-dot":""}`,title:k?w("localTeams.manage","管理本地 cicy-code"):w("localTeams.more","更多"),disabled:!!dt,onClick:st,children:dt?c.jsx(ge,{}):c.jsx(Js,{})}),X&&Pl.createPortal(c.jsxs("div",{className:"bcard__menu bcard__menu--portal","data-id":"LocalTeamCard-menu",role:"menu",ref:S,style:{position:"fixed",top:O.top,left:O.left,width:mt},onClick:x=>x.stopPropagation(),children:[k&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-check-update",className:"bcard__menu-item",disabled:Lt,onClick:x=>{x.stopPropagation(),d(!0)},children:Lt?w("sidecar.checking2","检查中…"):w("sidecar.checkUpdate","检查更新")}),y&&c.jsxs("button",{type:"button","data-id":"LocalTeamCard-update",className:"bcard__menu-item is-accent",onClick:()=>Et("update",()=>window.cicy.sidecar.update(),w("sidecar.updated","已更新到最新")),children:[w("sidecar.updateTo","更新到")," v",gt]}),k&&P&&c.jsxs(c.Fragment,{children:[c.jsx("button",{type:"button","data-id":"LocalTeamCard-reload",className:"bcard__menu-item",onClick:()=>Et("reload",async()=>{const x=await window.cicy.localTeams.reload(o.id);return!(x!=null&&x.ok)&&(x==null?void 0:x.error)==="no_open_window"?{ok:!1,error:w("localTeams.windowNotOpen","窗口未打开,请先点「打开」")}:x},w("localTeams.reloaded","已刷新窗口")),children:w("localTeams.reloadWindow","刷新窗口")}),c.jsx("button",{type:"button","data-id":"LocalTeamCard-restart",className:"bcard__menu-item",onClick:()=>Et("restart",()=>window.cicy.sidecar.restart(),w("sidecar.restarted","已重启")),children:w("sidecar.restart","重启")}),c.jsx("button",{type:"button","data-id":"LocalTeamCard-stop",className:"bcard__menu-item is-danger",onClick:()=>Et("stop",()=>window.cicy.sidecar.stop(),w("sidecar.stoppedDone","已停止")),children:w("sidecar.stop","停止")})]}),o.cloud_team_id&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-billing",className:"bcard__menu-item",onClick:x=>{x.stopPropagation(),M(!1),Su(`?team=${encodeURIComponent(o.cloud_team_id)}`)},children:w("localTeams.billing","账单")}),G&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-remove",className:"bcard__menu-item is-danger",onClick:Tt,children:ft?w("localTeams.removeConfirm","确认删除?"):w("localTeams.remove","删除")})]}),document.body)]})]}),c.jsxs("div",{className:"bcard__body",children:[V?c.jsx("input",{"data-id":"LocalTeamCard-rename-input",autoFocus:!0,value:C,onChange:x=>g(x.target.value),onFocus:x=>x.target.select(),onBlur:it,onClick:x=>x.stopPropagation(),onKeyDown:x=>{x.nativeEvent.isComposing||x.keyCode===229||(x.key==="Enter"?it():x.key==="Escape"&&R(!1))},style:{width:"100%",font:"inherit",fontWeight:600,padding:"2px 6px",border:"1px solid #3b82f6",borderRadius:6,background:"#0d1117",color:"#e6edf3",boxSizing:"border-box"}}):c.jsxs("h3",{className:"bcard__name",title:w("localTeams.renameHint","点名字或 ✎ 改名"),style:{display:"flex",alignItems:"center",gap:6},onDoubleClick:W,children:[c.jsx("span",{"data-id":"LocalTeamCard-name-text",onClick:W,style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",cursor:"text"},children:I}),lt==="saving"&&c.jsx("span",{"data-id":"LocalTeamCard-save-state",title:w("localTeams.saving","保存中…"),style:{flex:"none",display:"inline-flex"},children:c.jsx(ge,{})}),lt==="saved"&&c.jsx("span",{"data-id":"LocalTeamCard-save-state",title:w("localTeams.saved","已保存"),style:{flex:"none",color:"#3fb950",fontSize:13,lineHeight:1},children:"✓"}),!lt&&c.jsx("button",{type:"button","data-id":"LocalTeamCard-rename-btn",title:w("localTeams.rename","重命名"),onClick:W,style:{flex:"none",cursor:"pointer",border:"none",background:"transparent",color:"#8b949e",fontSize:13,padding:0,lineHeight:1},children:"✎"})]}),c.jsx("div",{className:"bcard__host",children:o.base_url||"—"}),c.jsx("div",{className:"bcard__meta",children:(qt||o.version)&&c.jsxs("span",{className:"bcard__ver","data-id":"LocalTeamCard-version",children:["v",qt||o.version]})})]}),c.jsxs("button",{type:"button",className:"bcard__cta","data-id":"LocalTeamCard-open",disabled:!!dt||!o.base_url,onClick:aa,children:[dt&&dt!=="stop"?c.jsx(ge,{}):c.jsx(_u,{}),c.jsx("span",{children:dt&&Re[dt]||We})]})]})}function Vs(o){try{const A=new URL(o);return(A.hostname==="127.0.0.1"||A.hostname==="localhost"||A.hostname==="::1")&&(A.port==="8008"||A.port==="")}catch{return!1}}function om(o){try{const A=new URL(o);return(A.hostname==="127.0.0.1"||A.hostname==="localhost"||A.hostname==="::1")&&A.port==="8009"}catch{return!1}}function fm(o,A){const T=String(o).split("."),r=String(A).split(".");for(let D=0;D<Math.max(T.length,r.length);D++){const q=(parseInt(T[D],10)||0)-(parseInt(r[D],10)||0);if(q)return q>0?1:-1}return 0}const rm={running:{tone:"ok",label:"running",cta:"打开"},stopped:{tone:"off",label:"stopped",cta:"未运行"},auth_error:{tone:"warn",label:"auth error",cta:"Token 失效"},misconfigured:{tone:"err",label:"bad config",cta:"URL 错误"},error:{tone:"err",label:"error",cta:"异常"}};function c0({team:o,onOpen:A}){const T=o.kind==="private",r=o.status==="active",D=o.name||o.title||"—",q=o.host_url||"",V=o.teamId||o.id,R=T?"私有云":o.team_kind==="personal"?"个人":"共享",C=T?q:o.workspace_url||o.workspace_direct_url,g=!!C,[Y,H]=N.useState(!1),[lt,J]=N.useState(!1),[I,W]=N.useState({top:0,left:0}),it=N.useRef(null),Z=N.useRef(null),k=N.useRef(null),P=184,dt=()=>{if(!Y&&Z.current){const X=Z.current.getBoundingClientRect(),M=Math.max(8,Math.min(X.right-P,window.innerWidth-P-8));W({top:Math.round(X.bottom+4),left:Math.round(M)})}H(X=>!X)};N.useEffect(()=>{if(!Y)return;const X=M=>{var pt,U;(pt=Z.current)!=null&&pt.contains(M.target)||(U=k.current)!=null&&U.contains(M.target)||H(!1)};return document.addEventListener("mousedown",X),()=>document.removeEventListener("mousedown",X)},[Y]);const ot=async()=>{var X,M,pt;if(!(!g||lt)){J(!0),H(!1);try{await((pt=(M=(X=window.cicy)==null?void 0:X.tabs)==null?void 0:M.reload)==null?void 0:pt.call(M,C,D))}catch{}finally{J(!1)}}};return c.jsxs("div",{"data-id":"TeamCard",className:`bcard bcard--cloud${r?" bcard--online":""}`,children:[c.jsx("div",{className:"bcard__accent"}),c.jsxs("div",{className:"bcard__top",children:[c.jsxs("div",{className:"bcard__pill",children:[c.jsx("span",{className:"bcard__dot","data-tone":r?"ok":"off"}),c.jsx(s0,{})]}),c.jsxs("div",{className:"bcard__top-right",children:[o.is_trial&&c.jsx("span",{className:"bcard__badge",children:"trial"}),V!=null&&c.jsx("button",{type:"button","data-id":"TeamCard-billing",className:"bcard__billing-btn",title:w("localTeams.billing","账单"),onClick:X=>{X.stopPropagation(),Su(`?team=${encodeURIComponent(V)}`)},children:w("localTeams.billing","账单")}),g&&c.jsxs("div",{className:"bcard__menuwrap",ref:it,onClick:X=>X.stopPropagation(),children:[c.jsx("button",{type:"button",ref:Z,"data-id":"TeamCard-menu-btn",className:"bcard__kebab",title:w("localTeams.more","更多"),disabled:lt,onClick:dt,children:lt?c.jsx(ge,{}):c.jsx(Js,{})}),Y&&Pl.createPortal(c.jsx("div",{className:"bcard__menu bcard__menu--portal","data-id":"TeamCard-menu",role:"menu",ref:k,style:{position:"fixed",top:I.top,left:I.left,width:P},onClick:X=>X.stopPropagation(),children:c.jsx("button",{type:"button","data-id":"TeamCard-reload",className:"bcard__menu-item",onClick:ot,children:w("localTeams.reloadWindow","刷新窗口")})}),document.body)]})]})]}),c.jsxs("div",{className:"bcard__body",children:[c.jsx("h3",{className:"bcard__name",title:D,children:D}),c.jsx("div",{className:"bcard__host",title:T&&q||"",children:T?q||w("teamCard.noHost","未填访问地址"):o.runtime_region||o.region||"—"}),c.jsxs("div",{className:"bcard__meta",children:[c.jsx("span",{className:"bcard__chip",children:R}),!T&&o.membership_status&&o.membership_status!=="active"&&c.jsx("span",{className:"bcard__chip",children:o.membership_status})]})]}),c.jsxs("button",{type:"button",className:"bcard__cta",onClick:A,disabled:!g,children:[c.jsx(_u,{}),c.jsx("span",{children:g?w("localTeams.open","打开"):T?w("teamCard.noHost","未填访问地址"):w("teamCard.noUrl","无 URL")})]})]})}function Gs(){return c.jsxs("div",{className:"brand",children:[c.jsx("div",{className:"brand-mark",children:c.jsx(bm,{})}),c.jsxs("div",{className:"brand-text",children:[c.jsx("div",{className:"brand-name",children:"CiCy Desktop"}),c.jsx("div",{className:"brand-sub",children:"团队 AI 协作工作台"})]})]})}function bm(){return c.jsx("svg",{width:"22",height:"22",viewBox:"0 0 96 96",fill:"none",children:c.jsx("path",{d:"M48 11L39.5 33.3L16 29.5L31 48L16 66.5L39.5 62.7L48 85L56.5 62.7L80 66.5L65 48L80 29.5L56.5 33.3Z",fill:"white",stroke:"white",strokeWidth:"8",strokeLinejoin:"round",strokeLinecap:"round"})})}function _u(){return c.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round",children:[c.jsx("line",{x1:"5",y1:"12",x2:"19",y2:"12"}),c.jsx("polyline",{points:"12 5 19 12 12 19"})]})}function ge(){return c.jsx("svg",{className:"spin",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.4",strokeLinecap:"round",children:c.jsx("path",{d:"M21 12a9 9 0 1 1-6.2-8.55"})})}function Sm(){return c.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[c.jsx("rect",{x:"3",y:"4",width:"18",height:"12",rx:"2"}),c.jsx("line",{x1:"2",y1:"20",x2:"22",y2:"20"})]})}function Js(){return c.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:[c.jsx("circle",{cx:"12",cy:"5",r:"1.7"}),c.jsx("circle",{cx:"12",cy:"12",r:"1.7"}),c.jsx("circle",{cx:"12",cy:"19",r:"1.7"})]})}function s0(){return c.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[c.jsx("circle",{cx:"12",cy:"12",r:"10"}),c.jsx("line",{x1:"2",y1:"12",x2:"22",y2:"12"}),c.jsx("path",{d:"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"})]})}function In(o){try{return localStorage.getItem(o)||null}catch{return null}}function dm(o){return o?/timeout/i.test(o)?"登录超时,请重新点击 Login。":/state/i.test(o)?"校验失败,请重新登录。":/no token/i.test(o)?"登录未完成,请重试。":/bridge missing/i.test(o)?"无法连接到登录服务(preload 未就绪)。":o:""}var mm;const o0=((mm=window.cicy)==null?void 0:mm.platform)||(()=>{const o=navigator.userAgent||"";return/Mac/i.test(o)?"darwin":/Windows/i.test(o)?"win32":"linux"})();document.documentElement.dataset.platform=o0;document.documentElement.dataset.fullscreen="0";var hm,ym;(ym=(hm=window.cicy)==null?void 0:hm.window)!=null&&ym.onFullscreen&&window.cicy.window.onFullscreen(o=>{document.documentElement.dataset.fullscreen=o?"1":"0"});Ky.createRoot(document.getElementById("root")).render(c.jsx(Fy,{}));
@@ -6,7 +6,7 @@
6
6
  <link rel="icon" type="image/svg+xml" href="./favicon.svg" />
7
7
  <link rel="icon" type="image/png" sizes="256x256" href="./favicon-256.png" />
8
8
  <title>CiCy Desktop</title>
9
- <script type="module" crossorigin src="./assets/index-C-W_SxZ_.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-DKTmSMvA.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-BcVFakIC.css">
11
11
  </head>
12
12
  <body>
@@ -18,6 +18,7 @@ const os = require("os");
18
18
  const path = require("path");
19
19
  const sidecar = require("../sidecar/cicy-code");
20
20
  const docker = require("../sidecar/docker");
21
+ const wslDocker = require("../sidecar/wsl-docker"); // Docker-版 via WSL2+Ubuntu (方案 A)
21
22
 
22
23
  const PORT = Number(process.env.CICY_CODE_PORT || 8008);
23
24
 
@@ -106,52 +107,45 @@ function register({ sidecarLogPath } = {}) {
106
107
  }
107
108
  });
108
109
 
109
- // ---- Docker-版 cicy-code on :8009 (homepage "Docker cicy-code" card) ----
110
- // Distinct states so the card shows the RIGHT button (主人: 状态要分清楚):
111
- // installed Docker Desktop is on disk
112
- // dockerRunning — the Docker daemon/engine is up
113
- // running — the :8009 cicy-code container is healthy
114
- // `installed` kept (= dockerRunning) for back-compat with older renderers.
110
+ // ---- Docker-版 cicy-code on :8009 WSL2 + Ubuntu + Docker Engine (方案 A) ----
111
+ // Card states (主人: 状态分清楚): running(:8009 healthy)→打开 / dockerRunning
112
+ // (engine up)→启动 / installed(Ubuntu present)→启动 Docker / else→下载安装.
115
113
  ipcMain.handle("docker:app-status", async () => {
116
114
  try {
117
- const dockerRunning = await docker.dockerOk();
118
- const installed = !!docker.dockerDesktopExe();
119
- const running = dockerRunning ? await docker.probeHealth(APP_PORT) : false;
120
- return { installed, dockerRunning, running, port: APP_PORT, platform: process.platform };
115
+ const s = await wslDocker.status(APP_PORT); // { wsl, distro, engineUp, running }
116
+ return { installed: !!s.distro, dockerRunning: !!s.engineUp, running: !!s.running, port: APP_PORT, platform: process.platform };
121
117
  } catch (e) {
122
118
  return { installed: false, dockerRunning: false, running: false, port: APP_PORT, platform: process.platform, error: e.message };
123
119
  }
124
120
  });
125
121
 
126
- // Common run options for the :8009 instance: its own container/volume, the
127
- // whole-home mount, and the LLM gateway env keyed by the 8008 team's token.
122
+ // Common run options for the :8009 instance: its own container/volume + the
123
+ // LLM gateway env keyed by the 8008 team's token. (WSL: whole-home mount via
124
+ // -v <volume>:/home/cicy inside wsl-docker.)
128
125
  const appOpts = () => {
129
126
  const token = readLocalApiToken();
130
127
  const env = { CICY_AI_GATEWAY_LLM_ENDPOINT: GATEWAY_ENDPOINT };
131
128
  if (token) env.CICY_AI_GATEWAY_LLM_API_KEY = token;
132
- return { port: APP_PORT, container: APP_CONTAINER, volume: APP_VOLUME, mountTarget: APP_MOUNT, env };
129
+ return { port: APP_PORT, container: APP_CONTAINER, volume: APP_VOLUME, env };
133
130
  };
134
131
  // Register the running :8009 instance as a (custom) team so the card's "打开"
135
132
  // reuses the token-injected open/reload flow. addTeam dedups by host:port.
136
133
  const registerAppTeam = async () => {
137
134
  try {
138
135
  const lt = require("./local-teams");
139
- const tok = await docker.readContainerToken(APP_PORT);
136
+ const tok = await wslDocker.readContainerToken(APP_PORT);
140
137
  await lt.addTeam({ base_url: `http://127.0.0.1:${APP_PORT}`, name: "Docker cicy-code", ...(tok ? { api_token: tok } : {}) });
141
138
  } catch { /* best-effort — the container itself is up */ }
142
139
  };
143
140
 
144
- // One-click bootstrap of the Docker-版 instance: install Docker Desktop if
145
- // missing (installer Desktop) WHILE downloading the R2 image (→ ~/Downloads)
146
- // in parallel, import it, start the :8009 container, wait for health. Streams
147
- // phase/progress on 'docker:app-progress' so the card's modal mirrors the
148
- // cicy-code 升级 modal. Idempotent + resumable → the modal's 重试 just re-runs.
141
+ // One-click bootstrap (方案 A): ensure WSL2 Ubuntu → Docker Engine → load
142
+ // imagestart :8009 container health. Streams phase/progress on
143
+ // 'docker:app-progress'. Idempotent + resumable the modal's 重试 just re-runs.
149
144
  ipcMain.handle("docker:app-bootstrap", async (e) => {
150
145
  if (process.platform !== "win32") return { ok: false, error: "Docker cicy-code is Windows-only" };
151
146
  try {
152
- const installDest = path.join(docker.downloadsDir(), "Docker Desktop Installer.exe");
153
- const result = await docker.bootstrap({
154
- ...appOpts(), installDest,
147
+ const result = await wslDocker.bootstrap({
148
+ ...appOpts(),
155
149
  onProgress: (ev) => { try { e.sender.send("docker:app-progress", ev); } catch {} },
156
150
  });
157
151
  if (result && result.ok) await registerAppTeam();
@@ -161,44 +155,29 @@ function register({ sidecarLogPath } = {}) {
161
155
  }
162
156
  });
163
157
 
164
- // ⋯ menu → 重启: `docker restart` the :8009 container, wait for health.
158
+ // ⋯ menu → 重启 the :8009 container, wait for health.
165
159
  ipcMain.handle("docker:app-restart", async () => {
166
- try {
167
- await docker.restart({ container: APP_CONTAINER });
168
- const ok = await docker.waitUntil(() => docker.probeHealth(APP_PORT), { totalMs: 60000, everyMs: 2000 });
169
- return { ok };
170
- } catch (e) { return { ok: false, error: e.message }; }
160
+ try { const ok = await wslDocker.restart({ container: APP_CONTAINER, port: APP_PORT }); return { ok: !!ok }; }
161
+ catch (e) { return { ok: false, error: e.message }; }
171
162
  });
172
163
 
173
- // ⋯ menu → 停止: graceful `docker stop` (keeps the container; data persists in
174
- // the named volume). The card's 启动 path re-creates/starts it.
164
+ // ⋯ menu → 停止: graceful `docker stop` (data persists in the named volume).
175
165
  ipcMain.handle("docker:app-stop", async () => {
176
- try { await docker.stopContainer({ container: APP_CONTAINER }); return { ok: true }; }
166
+ try { await wslDocker.stop({ container: APP_CONTAINER }); return { ok: true }; }
177
167
  catch (e) { return { ok: false, error: e.message }; }
178
168
  });
179
169
 
180
- // ⋯ menu → 升级: re-pull the latest R2 image (→ ~/Downloads, resume/skip + bad-
181
- // partial delete), import it, re-create the :8009 container on the new image.
182
- // Streams on 'docker:app-progress' so the same modal shows the upgrade.
170
+ // ⋯ menu → 升级: re-pull the latest R2 image, re-create the :8009 container.
183
171
  ipcMain.handle("docker:app-upgrade", async (e) => {
184
172
  if (process.platform !== "win32") return { ok: false, error: "Docker cicy-code is Windows-only" };
185
- const emit = (ev) => { try { e.sender.send("docker:app-progress", ev); } catch {} };
186
173
  try {
187
- if (!(await docker.dockerOk())) { emit({ phase: "done", status: "error", message: "Docker 未运行" }); return { ok: false, error: "docker_not_running" }; }
188
- const tmp = await docker.downloadImageTarball({ emit });
189
- await docker.loadImageFromTarball(tmp, { emit });
190
- emit({ phase: "image", status: "done", message: "镜像已更新" });
191
- emit({ phase: "container", status: "running", message: "用新镜像重建容器…" });
192
- await docker.stop({ container: APP_CONTAINER });
193
- const child = await docker.start(appOpts());
194
- if (!child) { emit({ phase: "done", status: "error", message: "容器启动失败" }); return { ok: false, error: "container_start_failed" }; }
195
- emit({ phase: "health", status: "running", message: "等待就绪…" });
196
- const ok = await docker.waitUntil(() => docker.probeHealth(APP_PORT), { totalMs: 120000, everyMs: 3000 });
197
- emit({ phase: "done", status: ok ? "done" : "error", message: ok ? "升级完成 🎉" : "启动了但 :8009 还没响应" });
198
- if (ok) await registerAppTeam();
199
- return { ok };
174
+ const result = await wslDocker.upgrade({
175
+ ...appOpts(),
176
+ onProgress: (ev) => { try { e.sender.send("docker:app-progress", ev); } catch {} },
177
+ });
178
+ if (result && result.ok) await registerAppTeam();
179
+ return result;
200
180
  } catch (err) {
201
- emit({ phase: "done", status: "error", message: `升级失败:${err.message}` });
202
181
  return { ok: false, error: err.message };
203
182
  }
204
183
  });
@@ -124,11 +124,11 @@
124
124
  },
125
125
  "docker": {
126
126
  "title": "Docker cicy-code",
127
- "install": "Download & Install",
127
+ "install": "Install",
128
128
  "start": "Start",
129
129
  "running": "Running · :8009",
130
130
  "notRunning": "Stopped · click Start",
131
- "notInstalled": "Docker Desktop not installed",
131
+ "notInstalled": "Not installed · click Install",
132
132
  "working": "Working…",
133
133
  "ready": "Docker cicy-code is ready",
134
134
  "failed": "Install failed",
@@ -160,4 +160,4 @@
160
160
  "done": "Done",
161
161
  "minimize": "Minimize"
162
162
  }
163
- }
163
+ }
@@ -123,11 +123,11 @@
123
123
  },
124
124
  "docker": {
125
125
  "title": "Docker cicy-code",
126
- "install": "Télécharger et installer",
126
+ "install": "Installer",
127
127
  "start": "Démarrer",
128
128
  "running": "En cours · :8009",
129
129
  "notRunning": "Arrêté · cliquez sur Démarrer",
130
- "notInstalled": "Docker Desktop non installé",
130
+ "notInstalled": "Non installé · cliquez pour installer",
131
131
  "working": "En cours…",
132
132
  "ready": "Docker cicy-code est prêt",
133
133
  "failed": "Échec de l'installation",
@@ -159,4 +159,4 @@
159
159
  "done": "Terminé",
160
160
  "minimize": "Réduire"
161
161
  }
162
- }
162
+ }
@@ -123,11 +123,11 @@
123
123
  },
124
124
  "docker": {
125
125
  "title": "Docker cicy-code",
126
- "install": "ダウンロードしてインストール",
126
+ "install": "インストール",
127
127
  "start": "起動",
128
128
  "running": "実行中 · :8009",
129
129
  "notRunning": "停止中 · 「起動」をクリック",
130
- "notInstalled": "Docker Desktop 未インストール",
130
+ "notInstalled": "未インストール · クリックでインストール",
131
131
  "working": "処理中…",
132
132
  "ready": "Docker cicy-code の準備完了",
133
133
  "failed": "インストール失敗",
@@ -159,4 +159,4 @@
159
159
  "done": "完了",
160
160
  "minimize": "最小化"
161
161
  }
162
- }
162
+ }
@@ -124,11 +124,11 @@
124
124
  },
125
125
  "docker": {
126
126
  "title": "Docker cicy-code",
127
- "install": "下载安装",
127
+ "install": "一键安装",
128
128
  "start": "启动",
129
129
  "running": "运行中 · :8009",
130
130
  "notRunning": "未启动 · 点「启动」",
131
- "notInstalled": "Docker Desktop 未安装",
131
+ "notInstalled": "未安装 · 点安装",
132
132
  "working": "处理中…",
133
133
  "ready": "Docker cicy-code 已就绪",
134
134
  "failed": "安装失败",
@@ -160,4 +160,4 @@
160
160
  "done": "完成",
161
161
  "minimize": "最小化"
162
162
  }
163
- }
163
+ }
@@ -612,6 +612,7 @@ module.exports = {
612
612
  start, stop, stopContainer, restart, checkStatus, loadImage, loadImageFromTarball,
613
613
  downloadImageTarball, imagePresent, dockerOk, installDocker,
614
614
  bootstrap, probeHealth, readContainerToken, dockerDesktopExe, desktopDir, downloadsDir, imageTarballPath,
615
+ launchElevated, wslMissing, ensureWsl,
615
616
  // platform-agnostic download/retry primitives, reused by native.js
616
617
  ensureDownloaded, withRetry, waitUntil, run,
617
618
  };
@@ -0,0 +1,227 @@
1
+ // Docker-版 cicy-code via WSL2 + Ubuntu + Docker Engine (主人选定方案 A).
2
+ //
3
+ // Instead of the heavy/fragile Docker Desktop GUI install, we run Docker Engine
4
+ // (Apache-2.0, no licensing) INSIDE a WSL2 Ubuntu distro and drive it with
5
+ // deterministic Linux commands — no UAC click-through, no whale-icon wait, no
6
+ // leftover-staging / PATH issues. WSL2 forwards localhost, so a container
7
+ // published on :8009 in Ubuntu is reachable at 127.0.0.1:8009 on Windows.
8
+ //
9
+ // Flow: ensure WSL2 → ensure Ubuntu distro → apt install docker.io → start
10
+ // dockerd → docker load (image tarball from ~/Downloads via /mnt/c) → docker run
11
+ // → health-probe :8009 from Windows. Every step checks-then-acts and is
12
+ // idempotent, so 重试 resumes.
13
+
14
+ const { execFile, execFileSync } = require("child_process");
15
+ const path = require("path");
16
+ const docker = require("./docker"); // shared: downloads, waitUntil, probeHealth, launchElevated, ensureWsl…
17
+
18
+ const DISTRO = process.env.CICY_WSL_DISTRO || "Ubuntu";
19
+ const IMAGE = process.env.CICY_DOCKER_IMAGE || "cicybot/cicy-code:latest";
20
+
21
+ // Run a bash command as root inside the distro. execFile (no host shell) → the
22
+ // command string is passed verbatim to `bash -lc`, so only bash-level quoting
23
+ // matters inside `cmd`.
24
+ function wslRun(cmd, { timeout = 60000, distro = DISTRO } = {}) {
25
+ return new Promise((resolve, reject) => {
26
+ execFile("wsl", ["-d", distro, "-u", "root", "--", "bash", "-lc", cmd],
27
+ { timeout, windowsHide: true, maxBuffer: 1 << 26 },
28
+ (err, stdout, stderr) => {
29
+ if (err) { err.stdout = String(stdout || ""); err.stderr = String(stderr || ""); return reject(err); }
30
+ resolve({ stdout: String(stdout), stderr: String(stderr) });
31
+ });
32
+ });
33
+ }
34
+
35
+ // Is `DISTRO` registered? `wsl -l -q` lists installed distros (UTF-16LE).
36
+ function distroInstalled(distro = DISTRO) {
37
+ if (process.platform !== "win32") return false;
38
+ try {
39
+ const out = execFileSync("wsl", ["-l", "-q"], { timeout: 8000, windowsHide: true, encoding: "utf16le" });
40
+ return String(out).split(/\r?\n/).map((s) => s.replace(/\0/g, "").trim()).filter(Boolean)
41
+ .some((d) => d.toLowerCase() === distro.toLowerCase());
42
+ } catch { return false; }
43
+ }
44
+
45
+ // Install the Ubuntu distro WITHOUT launching its interactive first-run setup
46
+ // (--no-launch). We always run commands as root afterwards, so no user account
47
+ // is needed. Elevated via the scheduled-task path (reliable on these machines).
48
+ async function installDistro({ emit } = {}) {
49
+ emit && emit({ phase: "install-docker", status: "running", message: `安装 ${DISTRO} 子系统(首次下载较大,请耐心等待)…` });
50
+ // Try non-elevated first (adding a distro to an existing WSL is per-user);
51
+ // fall back to elevated if it errors.
52
+ try {
53
+ await new Promise((resolve, reject) => {
54
+ execFile("wsl", ["--install", "-d", DISTRO, "--no-launch"], { timeout: 600000, windowsHide: true }, (err) => err ? reject(err) : resolve());
55
+ });
56
+ } catch {
57
+ await docker.launchElevated("wsl", ["--install", "-d", DISTRO, "--no-launch"], { emit });
58
+ }
59
+ }
60
+
61
+ // docker CLI present inside the distro?
62
+ async function dockerInstalled() {
63
+ try { await wslRun("command -v docker >/dev/null 2>&1", { timeout: 8000 }); return true; }
64
+ catch { return false; }
65
+ }
66
+
67
+ // Install Docker Engine (docker.io) inside the distro.
68
+ async function installDockerEngine({ emit } = {}) {
69
+ emit && emit({ phase: "install-docker", status: "running", message: "在 Ubuntu 里安装 Docker(apt,几分钟)…" });
70
+ await wslRun("apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y docker.io", { timeout: 900000 });
71
+ }
72
+
73
+ // dockerd reachable inside the distro?
74
+ async function dockerEngineUp() {
75
+ try { await wslRun("docker version --format '{{.Server.Version}}'", { timeout: 8000 }); return true; }
76
+ catch { return false; }
77
+ }
78
+
79
+ // Start the Docker daemon (SysV service; docker.io ships an init script).
80
+ async function startEngine() {
81
+ // `service docker start` works without systemd; the `|| dockerd &` keeps it
82
+ // up on distros where the service script is absent.
83
+ try { await wslRun("service docker start 2>/dev/null || (nohup dockerd >/var/log/cicy-dockerd.log 2>&1 &)", { timeout: 30000 }); } catch {}
84
+ }
85
+
86
+ // The cicy-code base image present inside the distro's Docker?
87
+ async function imagePresent() {
88
+ try { await wslRun(`docker image inspect ${IMAGE} >/dev/null 2>&1`, { timeout: 10000 }); return true; }
89
+ catch { return false; }
90
+ }
91
+
92
+ // Convert a Windows path (C:\Users\..\x) to its WSL /mnt/c/Users/../x form.
93
+ function toWslPath(winPath) {
94
+ return String(winPath).replace(/^([A-Za-z]):[\\/]/, (_m, d) => `/mnt/${d.toLowerCase()}/`).replace(/\\/g, "/");
95
+ }
96
+
97
+ // docker load the (Windows-side) tarball into the distro's Docker + retag.
98
+ async function loadImage(winTarballPath, { emit } = {}) {
99
+ emit && emit({ phase: "image", status: "loading", message: "正在导入镜像到 Docker(较大,约 1-3 分钟,请稍候)…" });
100
+ const p = toWslPath(winTarballPath);
101
+ const { stdout } = await wslRun(`docker load -i "${p}"`, { timeout: 600000 });
102
+ const m = String(stdout).match(/Loaded image:\s*(\S+)/i);
103
+ if (m && m[1] !== IMAGE) { try { await wslRun(`docker tag ${m[1]} ${IMAGE}`, { timeout: 15000 }); } catch {} }
104
+ }
105
+
106
+ // HTTP /health probe on 127.0.0.1:port from Windows — WSL2 forwards localhost,
107
+ // so a container published on :port is reachable here. Reuse docker.js's probe.
108
+ const probeHealth = docker.probeHealth;
109
+
110
+ // Start (or adopt) the container on :port inside the distro.
111
+ async function runContainer({ port = 8009, container = "cicy-code-docker", volume = "cicy-team", env = {} } = {}) {
112
+ if (await probeHealth(port)) return { adopted: true };
113
+ // Replace any stale same-named container.
114
+ try { await wslRun(`docker rm -f ${container}`, { timeout: 20000 }); } catch {}
115
+ const envArgs = Object.entries(env || {})
116
+ .filter(([, v]) => v != null && v !== "")
117
+ .map(([k, v]) => `-e ${k}='${String(v).replace(/'/g, "'\\''")}'`)
118
+ .join(" ");
119
+ const cmd = `docker run -d --name ${container} --restart unless-stopped -p ${port}:8008 -v ${volume}:/home/cicy ${envArgs} ${IMAGE}`;
120
+ await wslRun(cmd, { timeout: 60000 });
121
+ return { started: true };
122
+ }
123
+
124
+ // Read the container's own api_token (its volume-persisted global.json) for the
125
+ // team registration — the host token is a different credential.
126
+ async function readContainerToken(port = 8009) {
127
+ try {
128
+ const { stdout } = await wslRun(`docker ps --filter "publish=${port}" --format '{{.Names}}'`, { timeout: 10000 });
129
+ const name = stdout.trim().split("\n")[0];
130
+ if (!name) return "";
131
+ const r = await wslRun(`docker exec ${name} cat /home/cicy/cicy-ai/global.json`, { timeout: 10000 });
132
+ return JSON.parse(r.stdout).api_token || "";
133
+ } catch { return ""; }
134
+ }
135
+
136
+ // Composite status for the card.
137
+ async function status(port = 8009) {
138
+ const wsl = !docker.wslMissing();
139
+ const distro = wsl && distroInstalled();
140
+ const engineUp = distro && (await dockerEngineUp());
141
+ const running = engineUp && (await probeHealth(port));
142
+ return { wsl, distro, engineUp, running };
143
+ }
144
+
145
+ // Full bootstrap. Honest progress + honest terminal (ok only when :port healthy).
146
+ async function bootstrap({ onProgress, port = 8009, container = "cicy-code-docker", volume = "cicy-team", env = {} } = {}) {
147
+ const emit = (ev) => { try { onProgress && onProgress(ev); } catch {} };
148
+
149
+ // 1) WSL2 platform
150
+ if (docker.wslMissing()) {
151
+ const w = await docker.ensureWsl({ emit });
152
+ if (w.needsReboot) { emit({ phase: "done", status: "reboot", message: "WSL2 正在安装——请【重启 Windows】后回来点「重试」继续。" }); return { ok: false, reason: "wsl_reboot_required" }; }
153
+ }
154
+
155
+ // 2) Ubuntu distro
156
+ if (!distroInstalled()) {
157
+ try { await installDistro({ emit }); } catch (e) { emit({ phase: "done", status: "error", message: `Ubuntu 安装失败:${e.message}(点重试)` }); return { ok: false, reason: "distro_install_failed" }; }
158
+ const ok = await docker.waitUntil(() => distroInstalled(), { totalMs: 600000, everyMs: 5000 });
159
+ if (!ok) { emit({ phase: "done", status: "error", message: "Ubuntu 还没装好——稍等或点「重试」" }); return { ok: false, reason: "distro_not_ready" }; }
160
+ }
161
+
162
+ // 3) Docker Engine inside Ubuntu
163
+ if (!(await dockerInstalled())) {
164
+ try { await installDockerEngine({ emit }); } catch (e) { emit({ phase: "done", status: "error", message: `Docker 安装失败:${e.message}(点重试)` }); return { ok: false, reason: "docker_install_failed" }; }
165
+ }
166
+
167
+ // 4) dockerd up
168
+ if (!(await dockerEngineUp())) {
169
+ emit({ phase: "install-docker", status: "running", message: "启动 Docker 引擎…" });
170
+ await startEngine();
171
+ const up = await docker.waitUntil(dockerEngineUp, { totalMs: 60000, everyMs: 3000 });
172
+ if (!up) { emit({ phase: "done", status: "error", message: "Docker 引擎没起来——点「重试」" }); return { ok: false, reason: "dockerd_not_up" }; }
173
+ }
174
+ emit({ phase: "install-docker", status: "done", message: "Docker 环境就绪" });
175
+
176
+ // 5) Base image
177
+ if (!(await imagePresent())) {
178
+ let tarball;
179
+ try { tarball = await docker.downloadImageTarball({ emit }); }
180
+ catch (e) { emit({ phase: "done", status: "error", message: `镜像下载失败:${e.message}(点重试续传)` }); return { ok: false, reason: "image_download_failed" }; }
181
+ try { await loadImage(tarball, { emit }); emit({ phase: "image", status: "done", message: "镜像就绪" }); }
182
+ catch (e) { emit({ phase: "done", status: "error", message: `镜像导入失败:${e.message}(点重试)` }); return { ok: false, reason: "image_load_failed" }; }
183
+ } else {
184
+ emit({ phase: "image", status: "skip", message: "镜像已就绪,跳过" });
185
+ }
186
+
187
+ // 6) Container
188
+ if (!(await probeHealth(port))) {
189
+ emit({ phase: "container", status: "running", message: "启动 cicy-code 容器…" });
190
+ try { await runContainer({ port, container, volume, env }); }
191
+ catch (e) { emit({ phase: "done", status: "error", message: `容器启动失败:${e.message}(点重试)` }); return { ok: false, reason: "container_start_failed" }; }
192
+ }
193
+
194
+ // 7) Health — the ONLY path to ok:true.
195
+ emit({ phase: "health", status: "running", message: "等待 cicy-code 就绪…" });
196
+ const healthy = await docker.waitUntil(() => probeHealth(port), { totalMs: 120000, everyMs: 3000 });
197
+ emit({ phase: "done", status: healthy ? "done" : "error", message: healthy ? "Docker cicy-code 已就绪 🎉" : `容器起来了但 :${port} 还没响应——稍等或点「重试」` });
198
+ return { ok: healthy, container };
199
+ }
200
+
201
+ // Lifecycle (card ⋯ menu).
202
+ async function restart({ container = "cicy-code-docker", port = 8009 } = {}) {
203
+ await startEngine();
204
+ await wslRun(`docker restart ${container}`, { timeout: 60000 });
205
+ return await docker.waitUntil(() => probeHealth(port), { totalMs: 60000, everyMs: 2000 });
206
+ }
207
+ async function stop({ container = "cicy-code-docker" } = {}) {
208
+ try { await wslRun(`docker stop ${container}`, { timeout: 30000 }); } catch {}
209
+ }
210
+ async function upgrade({ onProgress, port = 8009, container = "cicy-code-docker", volume = "cicy-team", env = {} } = {}) {
211
+ const emit = (ev) => { try { onProgress && onProgress(ev); } catch {} };
212
+ if (!(await dockerEngineUp())) { await startEngine(); if (!(await dockerEngineUp())) { emit({ phase: "done", status: "error", message: "Docker 引擎未运行" }); return { ok: false, reason: "dockerd_not_up" }; } }
213
+ let tarball;
214
+ try { tarball = await docker.downloadImageTarball({ emit }); await loadImage(tarball, { emit }); emit({ phase: "image", status: "done", message: "镜像已更新" }); }
215
+ catch (e) { emit({ phase: "done", status: "error", message: `升级失败:${e.message}` }); return { ok: false, reason: "image_failed" }; }
216
+ emit({ phase: "container", status: "running", message: "用新镜像重建容器…" });
217
+ try { await stop({ container }); await runContainer({ port, container, volume, env }); }
218
+ catch (e) { emit({ phase: "done", status: "error", message: `容器启动失败:${e.message}` }); return { ok: false, reason: "container_start_failed" }; }
219
+ const healthy = await docker.waitUntil(() => probeHealth(port), { totalMs: 120000, everyMs: 3000 });
220
+ emit({ phase: "done", status: healthy ? "done" : "error", message: healthy ? "升级完成 🎉" : `启动了但 :${port} 还没响应` });
221
+ return { ok: healthy };
222
+ }
223
+
224
+ module.exports = {
225
+ bootstrap, status, restart, stop, upgrade, runContainer, readContainerToken,
226
+ distroInstalled, dockerInstalled, dockerEngineUp, imagePresent, probeHealth, wslRun,
227
+ };
@@ -1500,7 +1500,7 @@ const dockerDrawer = {
1500
1500
  },
1501
1501
  close() { dockerDrawerState = null; emitDockerDrawer(); },
1502
1502
  };
1503
- const DOCKER_PHASES = [["install-docker", "装 Docker"], ["image", "加载镜像"], ["container", "启动容器"], ["done", "完成"]];
1503
+ const DOCKER_PHASES = [["install-docker", "准备环境"], ["image", "加载镜像"], ["container", "启动容器"], ["done", "完成"]];
1504
1504
  const DOCKER_BADGE = { "install-docker": "Docker", image: "镜像", container: "容器", health: "容器", done: "完成" };
1505
1505
  const DOCKER_DL_LABEL = { "install-docker": "Docker Desktop", image: "基础镜像" };
1506
1506
  function fmtBytes(n) {