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 +1 -1
- package/src/backends/homepage-react/assets/{index-C-W_SxZ_.js → index-DKTmSMvA.js} +1 -1
- package/src/backends/homepage-react/index.html +1 -1
- package/src/backends/sidecar-ipc.js +28 -49
- package/src/i18n/locales/en.json +3 -3
- package/src/i18n/locales/fr.json +3 -3
- package/src/i18n/locales/ja.json +3 -3
- package/src/i18n/locales/zh-CN.json +3 -3
- package/src/sidecar/docker.js +1 -0
- package/src/sidecar/wsl-docker.js +227 -0
- package/workers/render/src/App.jsx +1 -1
package/package.json
CHANGED
|
@@ -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&>.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&>&&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&>.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&>&&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-
|
|
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
|
|
110
|
-
//
|
|
111
|
-
//
|
|
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
|
|
118
|
-
|
|
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
|
|
127
|
-
//
|
|
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,
|
|
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
|
|
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
|
|
145
|
-
//
|
|
146
|
-
//
|
|
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
|
+
// image → start :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
|
|
153
|
-
|
|
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 →
|
|
158
|
+
// ⋯ menu → 重启 the :8009 container, wait for health.
|
|
165
159
|
ipcMain.handle("docker:app-restart", async () => {
|
|
166
|
-
try {
|
|
167
|
-
|
|
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` (
|
|
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
|
|
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
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
});
|
package/src/i18n/locales/en.json
CHANGED
|
@@ -124,11 +124,11 @@
|
|
|
124
124
|
},
|
|
125
125
|
"docker": {
|
|
126
126
|
"title": "Docker cicy-code",
|
|
127
|
-
"install": "
|
|
127
|
+
"install": "Install",
|
|
128
128
|
"start": "Start",
|
|
129
129
|
"running": "Running · :8009",
|
|
130
130
|
"notRunning": "Stopped · click Start",
|
|
131
|
-
"notInstalled": "
|
|
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
|
+
}
|
package/src/i18n/locales/fr.json
CHANGED
|
@@ -123,11 +123,11 @@
|
|
|
123
123
|
},
|
|
124
124
|
"docker": {
|
|
125
125
|
"title": "Docker cicy-code",
|
|
126
|
-
"install": "
|
|
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": "
|
|
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
|
+
}
|
package/src/i18n/locales/ja.json
CHANGED
|
@@ -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": "
|
|
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": "
|
|
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
|
+
}
|
package/src/sidecar/docker.js
CHANGED
|
@@ -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", "
|
|
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) {
|