cicy-desktop 2.1.81 → 2.1.83
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 +6 -6
- package/scripts/sync-runtime-deps.cjs +8 -7
- package/src/backends/homepage-react/assets/{index-CSsNZgC5.js → index-xHkT3-tl.js} +1 -1
- package/src/backends/homepage-react/index.html +1 -1
- package/src/main.js +13 -0
- package/src/utils/desktop-snapshot.js +175 -0
- package/workers/render/src/App.jsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cicy-desktop",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.83",
|
|
4
4
|
"description": "CiCy - AI-powered operating system browser",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -133,11 +133,11 @@
|
|
|
133
133
|
},
|
|
134
134
|
"//optionalDependencies": "Runtime Bundle v1 (主人指令): platform binaries delivered by `npm i -g cicy-desktop` itself — npm installs only the current-platform subpackage (os/cpu pinned in each), so first start seeds the runtime store with ZERO network, ZERO npx. Windows packages are named *-windows-* (npm spam filter 403s new names containing win32). cicy-msys2 added once published.",
|
|
135
135
|
"optionalDependencies": {
|
|
136
|
-
"cicy-code-darwin-x64": "2.3.
|
|
137
|
-
"cicy-code-darwin-arm64": "2.3.
|
|
138
|
-
"cicy-code-linux-x64": "2.3.
|
|
139
|
-
"cicy-code-linux-arm64": "2.3.
|
|
140
|
-
"cicy-code-windows-x64": "2.3.
|
|
136
|
+
"cicy-code-darwin-x64": "2.3.2",
|
|
137
|
+
"cicy-code-darwin-arm64": "2.3.2",
|
|
138
|
+
"cicy-code-linux-x64": "2.3.2",
|
|
139
|
+
"cicy-code-linux-arm64": "2.3.2",
|
|
140
|
+
"cicy-code-windows-x64": "2.3.2",
|
|
141
141
|
"cicy-mihomo-darwin-x64": "1.10.4",
|
|
142
142
|
"cicy-mihomo-darwin-arm64": "1.10.4",
|
|
143
143
|
"cicy-mihomo-linux-x64": "1.10.4",
|
|
@@ -8,22 +8,23 @@
|
|
|
8
8
|
//
|
|
9
9
|
// Usage: node scripts/sync-runtime-deps.cjs (writes package.json in place)
|
|
10
10
|
|
|
11
|
-
const {
|
|
11
|
+
const { execSync } = require("child_process");
|
|
12
12
|
const fs = require("fs");
|
|
13
13
|
const path = require("path");
|
|
14
14
|
|
|
15
15
|
const REGISTRY = process.env.NPM_REGISTRY || "https://registry.npmjs.org";
|
|
16
|
-
// On Windows `npm` is `npm.cmd`; execFileSync (no shell) can't launch a bare
|
|
17
|
-
// "npm" there → every `npm view` throws ENOENT, gets swallowed by the catch,
|
|
18
|
-
// and the script aborts with "resolved nothing" (registry was fine all along).
|
|
19
|
-
// Resolve the real binary name per-platform.
|
|
20
|
-
const NPM = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
21
16
|
const PLATFORMS = ["darwin-x64", "darwin-arm64", "linux-x64", "linux-arm64", "windows-x64", "windows-arm64"];
|
|
22
17
|
const COMPONENTS = ["cicy-code", "cicy-mihomo"]; // NOT cicy-msys2 — win drops it
|
|
23
18
|
|
|
24
19
|
function latest(pkg) {
|
|
20
|
+
// Use execSync (runs through a shell) instead of execFileSync: on Windows npm
|
|
21
|
+
// is npm.cmd, and Node refuses to spawn .cmd/.bat without a shell (EINVAL) —
|
|
22
|
+
// execFileSync('npm'|'npm.cmd', …) therefore threw on every call and the whole
|
|
23
|
+
// script aborted with "resolved nothing" even though the registry was fine.
|
|
24
|
+
// cmd.exe (win) / sh (unix) resolve `npm` correctly. pkg/REGISTRY are trusted
|
|
25
|
+
// constants, so the interpolation is safe.
|
|
25
26
|
try {
|
|
26
|
-
return
|
|
27
|
+
return execSync(`npm view ${pkg} version --registry=${REGISTRY}`, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
|
|
27
28
|
} catch {
|
|
28
29
|
return null; // not published for this platform (e.g. cicy-code has no windows-arm64)
|
|
29
30
|
}
|
|
@@ -362,4 +362,4 @@ Error generating stack: `+a.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
|
-
`},Y=(o,U)=>{var E,m;try{const O=(m=(E=window.cicyI18n)==null?void 0:E.t)==null?void 0:m.call(E,o);return O&&O!==o?O:U}catch{return U}},Ka="cicy_token",oi="cicy_access_token",ri="cicy_user_id",mi="https://cicy-ai.com";async function hi(o){var U,E,m;try{(m=(E=(U=window.cicy)==null?void 0:U.shell)==null?void 0:E.openExternal)==null||m.call(E,`${mi}/dash${o}`)}catch{}}const Rs=new Set;let Yy=0,Ql=[];const Zn=new Map;function $d(){Rs.forEach(o=>o(Ql))}const je={show(o={}){const U=o.id||`t${++Yy}`,E=Ql.find(B=>B.id===U),m={id:U,status:"running",...E,...o};Ql=E?Ql.map(B=>B.id===U?m:B):[...Ql,m],$d();const O=Zn.get(U);return O&&(clearTimeout(O),Zn.delete(U)),o.ttl&&Zn.set(U,setTimeout(()=>je.dismiss(U),o.ttl)),U},dismiss(o){Ql=Ql.filter(E=>E.id!==o);const U=Zn.get(o);U&&(clearTimeout(U),Zn.delete(o)),$d()}};function Ly(){const[o,U]=N.useState(Ql);return N.useEffect(()=>(Rs.add(U),()=>{Rs.delete(U)}),[]),o.length?s.jsx("div",{className:"toast-host","data-id":"ToastHost",children:o.map(E=>s.jsxs("div",{className:"toast","data-id":`Toast-${E.id}`,"data-status":E.status||"running",children:[s.jsx("button",{type:"button",className:"toast__x","data-id":"Toast-dismiss",onClick:()=>je.dismiss(E.id),"aria-label":"dismiss",children:"×"}),s.jsxs("span",{className:"toast__msg",children:[E.message,Number.isFinite(E.progress)?` ${E.progress}%`:""]}),Number.isFinite(E.progress)&&s.jsx("span",{className:"toast__bar",children:s.jsx("span",{style:{width:`${Math.min(100,E.progress)}%`}})})]},E.id))}):null}const Hs=new Set;let Fd=0,oe=null;function di(){Hs.forEach(o=>o(oe))}function Id(){return new Date().toTimeString().slice(0,8)}const hl={open({teamId:o,fromVer:U,toVer:E,onRetry:m}={}){oe={teamId:o,fromVer:U||null,toVer:E||null,status:"running",phase:"download",logs:[],onRetry:m||null,lastAt:Date.now()},di()},push(o={}){if(!oe)return;const U={id:++Fd,t:Id(),phase:o.phase||oe.phase,status:o.status||"running",message:o.message||""};oe={...oe,phase:o.phase||oe.phase,toVer:o.toVer||oe.toVer,logs:[...oe.logs,U],lastAt:Date.now()},di()},finish({ok:o,message:U}={}){if(!oe)return;const E=o?"done":"error",m={id:++Fd,t:Id(),phase:"done",status:E,message:U||(o?"更新完成":"更新失败")};oe={...oe,status:E,phase:"done",logs:[...oe.logs,m],lastAt:Date.now()},di()},close(){oe=null,di()}},ws=[["download","下载"],["swap","切换"],["done","完成"]];function Gy(){var at;const[o,U]=N.useState(oe);N.useEffect(()=>(Hs.add(U),()=>{Hs.delete(U)}),[]);const E=N.useRef(null);N.useEffect(()=>{const z=E.current;z&&(z.scrollTop=z.scrollHeight)},[(at=o==null?void 0:o.logs)==null?void 0:at.length]);const[m,O]=N.useState(!1);if(N.useEffect(()=>{if(!o||o.status!=="running"){O(!1);return}const z=setInterval(()=>O(Date.now()-(o.lastAt||0)>25e3),3e3);return()=>clearInterval(z)},[o==null?void 0:o.lastAt,o==null?void 0:o.status]),!o)return null;const B=o.status==="running",P=ws.findIndex(([z])=>z===o.phase);return s.jsx("div",{className:"drawer-scrim","data-id":"UpdateDrawer-scrim",onClick:()=>{B||hl.close()},children:s.jsxs("div",{className:"drawer","data-id":"UpdateDrawer","data-status":o.status,onClick:z=>z.stopPropagation(),children:[s.jsxs("div",{className:"drawer__head",children:[s.jsxs("div",{className:"drawer__title",children:[s.jsx("span",{className:`drawer__spark drawer__spark--${o.status}`,children:B?s.jsx(yl,{}):o.status==="done"?"✓":"!"}),s.jsxs("div",{children:[s.jsx("div",{className:"drawer__h",children:"更新 cicy-code"}),s.jsxs("div",{className:"drawer__sub",children:[o.fromVer?`v${o.fromVer}`:"当前"," → ",o.toVer?`v${o.toVer}`:"最新版"]})]})]}),s.jsx("button",{type:"button",className:"drawer__x","data-id":"UpdateDrawer-close",disabled:B,title:B?"更新进行中":"关闭",onClick:()=>hl.close(),"aria-label":"close",children:"×"})]}),s.jsx("div",{className:"drawer__steps","data-id":"UpdateDrawer-steps",children:ws.map(([z,b],X)=>{const w=o.status==="done"||X<P,lt=X===P&&B,K=o.status==="error"&&X===P;return s.jsxs("div",{className:`drawer__step${lt?" is-active":""}${w?" is-done":""}${K?" is-error":""}`,children:[s.jsx("span",{className:"drawer__step-dot",children:w?"✓":K?"!":X+1}),s.jsx("span",{className:"drawer__step-label",children:b}),X<ws.length-1&&s.jsx("span",{className:"drawer__step-bar"})]},z)})}),s.jsx("div",{className:"drawer__log","data-id":"UpdateDrawer-log",ref:E,children:o.logs.length===0?s.jsx("div",{className:"drawer__log-empty",children:"准备中…"}):o.logs.map(z=>s.jsxs("div",{className:"drawer__line","data-status":z.status,children:[s.jsx("span",{className:"drawer__t",children:z.t}),s.jsx("span",{className:`drawer__badge drawer__badge--${z.phase}`,children:{download:"下载",swap:"切换",done:"完成"}[z.phase]||z.phase}),s.jsx("span",{className:"drawer__linemsg",children:z.message})]},z.id))}),m&&B&&s.jsx("div",{className:"drawer__hint","data-id":"UpdateDrawer-stuck",children:"正在等待新版本就绪,耗时比平常久。可以放到后台继续,完成或失败都会提示。"}),s.jsx("div",{className:"drawer__foot",children:B?s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"drawer__foot-status",children:"更新进行中…"}),s.jsx("button",{type:"button",className:"drawer__btn","data-id":"UpdateDrawer-background",onClick:()=>hl.close(),children:"在后台继续"})]}):o.status==="error"?s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"drawer__foot-status is-error",children:"更新失败"}),o.onRetry&&s.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-retry",onClick:()=>o.onRetry(),children:"重试"}),s.jsx("button",{type:"button",className:"drawer__btn","data-id":"UpdateDrawer-dismiss",onClick:()=>hl.close(),children:"关闭"})]}):s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"drawer__foot-status is-done",children:"已更新到最新"}),s.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-finish",onClick:()=>hl.close(),children:"完成"})]})})]})})}function Qy(){const[o,U]=N.useState(void 0);N.useEffect(()=>{var D,F;if(!((F=(D=window.cicy)==null?void 0:D.terms)!=null&&F.status)){U(!0);return}window.cicy.terms.status(cm).then(G=>U(!!(G!=null&&G.accepted))).catch(()=>U(!0))},[]),N.useEffect(()=>{var G,C,q,$;const D=document.documentElement;try{D.setAttribute("data-platform",((G=window.cicy)==null?void 0:G.platform)||"linux")}catch{}D.setAttribute("data-fullscreen","0");let F;try{F=($=(q=(C=window.cicy)==null?void 0:C.window)==null?void 0:q.onFullscreen)==null?void 0:$.call(q,et=>D.setAttribute("data-fullscreen",et?"1":"0"))}catch{}return()=>{try{F&&F()}catch{}}},[]);const[E,m]=N.useState(()=>Vn(Ka)),[O,B]=N.useState(()=>Vn(oi)),[P,at]=N.useState(()=>Vn(ri)),[z,b]=N.useState(()=>!Vn(Ka)),[X,w]=N.useState(!1),[lt,K]=N.useState(""),[Q,L]=N.useState(""),[k,ct]=N.useState(null),[st,it]=N.useState(null),[ht,Tt]=N.useState(!1),[W,j]=N.useState(""),bt=N.useRef(!1),[M,yt]=N.useState(null),[Qt,Xt]=N.useState(!1),[Zt,pe]=N.useState(!1),[Yt,S]=N.useState("all"),R=N.useCallback(async(D,F)=>{var C,q,$,et;if(!D)return;if(!((q=(C=window.cicy)==null?void 0:C.cloud)!=null&&q.fetch)){j("cloud fetch bridge missing");return}Tt(!0),j("");const G={Authorization:`Bearer ${D}`};try{const[Wt,Gt]=await Promise.all([window.cicy.cloud.fetch(`${mi}/api/user/self`,{headers:G}),window.cicy.cloud.fetch(`${mi}/api/teams`,{headers:G})]);if((Gt==null?void 0:Gt.status)===401){if(!bt.current&&((et=($=window.cicy)==null?void 0:$.auth)!=null&&et.loginStart)){bt.current=!0,j("会话已过期,正在重新登录…");try{await window.cicy.auth.loginStart()}catch{}}return}if(!(Gt!=null&&Gt.ok))throw new Error(`/api/teams ${(Gt==null?void 0:Gt.status)||"?"} ${(Gt==null?void 0:Gt.error)||""}`);const Oe=JSON.parse(Gt.body||"{}");if(it(Array.isArray(Oe==null?void 0:Oe.teams)?Oe.teams:[]),Wt!=null&&Wt.ok)try{const rt=JSON.parse(Wt.body||"{}");ct((rt==null?void 0:rt.success)===!1?null:(rt==null?void 0:rt.data)||null)}catch{ct(null)}else ct(null)}catch(Wt){j(Wt.message||String(Wt))}finally{Tt(!1)}},[]),tt=N.useRef("");N.useEffect(()=>{tt.current=E||O||""},[E,O]);const xt=N.useCallback(async()=>{var F,G;const D=tt.current;if(!(!D||!((G=(F=window.cicy)==null?void 0:F.cloud)!=null&&G.fetch)))try{const C=await window.cicy.cloud.fetch(`${mi}/api/teams`,{headers:{Authorization:`Bearer ${D}`}});if(C!=null&&C.ok){const q=JSON.parse(C.body||"{}");Array.isArray(q==null?void 0:q.teams)&&it(q.teams)}}catch{}},[]);N.useEffect(()=>{const D=E||O;D&&R(D,P)},[E,O,P,R]);const gt=N.useCallback(async()=>{var D,F;if((F=(D=window.cicy)==null?void 0:D.localTeams)!=null&&F.list){Xt(!0);try{const G=await window.cicy.localTeams.list({refresh:!0});yt(Array.isArray(G)?G:[])}catch{yt([])}finally{Xt(!1),pe(!0)}}},[]),r=N.useCallback(async(D,F)=>{var C,q;if(!((q=(C=window.cicy)==null?void 0:C.localTeams)!=null&&q.update))return{ok:!1,error:"no_bridge"};let G;try{G=await window.cicy.localTeams.update(D,{name:String(F||"").trim()||Y("localTeams.unnamed","未命名")})}catch($){G={ok:!1,error:($==null?void 0:$.message)||String($)}}return await gt(),G||{ok:!1,error:"no_result"}},[gt]);N.useEffect(()=>{let D,F=!1;const G=3e3,C=3e4,q=async()=>{var Wt,Gt,Oe;try{await((Oe=(Gt=(Wt=window.cicy)==null?void 0:Wt.localTeams)==null?void 0:Gt.syncCloud)==null?void 0:Oe.call(Gt))}catch{}await Promise.all([gt(),xt()])},$=()=>{if(F)return;const Wt=document.visibilityState==="visible";D=setTimeout(async()=>{document.visibilityState==="visible"?await q():await gt(),$()},Wt?G:C)};q(),$();const et=()=>{document.visibilityState==="visible"&&q()};return document.addEventListener("visibilitychange",et),window.addEventListener("focus",et),()=>{F=!0,clearTimeout(D),document.removeEventListener("visibilitychange",et),window.removeEventListener("focus",et)}},[gt,xt]),N.useEffect(()=>{var F,G;if(!((G=(F=window.cicy)==null?void 0:F.localTeams)!=null&&G.onWebviewRelay))return;const D=window.cicy.localTeams.onWebviewRelay(async({reqId:C,msg:q})=>{let $={ok:!1,error:"unknown relay type"};try{(q==null?void 0:q.type)==="localTeams:add"?$=await window.cicy.localTeams.add(q.spec||{}):(q==null?void 0:q.type)==="localTeams:remove"?$=await window.cicy.localTeams.remove(q.id):(q==null?void 0:q.type)==="localTeams:update"?$=await window.cicy.localTeams.update(q.id,q.patch||{}):(q==null?void 0:q.type)==="localTeams:upgrade"?$=await window.cicy.localTeams.upgrade(q.id):(q==null?void 0:q.type)==="localTeams:list"&&($={ok:!0,teams:await window.cicy.localTeams.list({refresh:!0})}),gt()}catch(et){$={ok:!1,error:(et==null?void 0:et.message)||String(et)}}try{window.cicy.localTeams.replyWebviewRelay(C,$)}catch{}});return()=>{try{D==null||D()}catch{}}},[gt]);const x=N.useCallback(async D=>{var F,G;if((G=(F=window.cicy)==null?void 0:F.localTeams)!=null&&G.open)try{await window.cicy.localTeams.open(D)}catch{}},[]);N.useEffect(()=>{var F,G;if(Vn(Ka)){b(!1);return}if(!((G=(F=window.cicy)==null?void 0:F.auth)!=null&&G.getSaved)){b(!1);return}let D=!1;return(async()=>{try{const C=await window.cicy.auth.getSaved();if(D)return;if(C!=null&&C.token){try{localStorage.setItem(Ka,C.token)}catch{}if(m(C.token),C.accessToken){try{localStorage.setItem(oi,C.accessToken)}catch{}B(C.accessToken)}if(C.userId){try{localStorage.setItem(ri,String(C.userId))}catch{}at(String(C.userId))}}}catch{}finally{D||b(!1)}})(),()=>{D=!0}},[]),N.useEffect(()=>{var D,F;if((F=(D=window.cicy)==null?void 0:D.auth)!=null&&F.onComplete)return window.cicy.auth.onComplete(G=>{if(w(!1),G!=null&&G.error){K(lm(G.error));return}if(G!=null&&G.token){bt.current=!1,j("");try{localStorage.setItem(Ka,G.token)}catch{}if(m(G.token),G.accessToken){try{localStorage.setItem(oi,G.accessToken)}catch{}B(G.accessToken)}if(G.userId){try{localStorage.setItem(ri,String(G.userId))}catch{}at(String(G.userId))}K(""),L(G.reused?"已恢复你之前的登录":"登录成功"),setTimeout(()=>L(""),3e3)}})},[]);async function H(){var F,G;if(!((G=(F=window.cicy)==null?void 0:F.auth)!=null&&G.loginStart)){K("auth bridge missing");return}K(""),w(!0);const D=await window.cicy.auth.loginStart();D!=null&&D.ok||(w(!1),K(lm((D==null?void 0:D.error)||"login start failed")))}function Z(){var D,F,G;try{localStorage.removeItem(Ka),localStorage.removeItem(oi),localStorage.removeItem(ri)}catch{}try{(G=(F=(D=window.cicy)==null?void 0:D.auth)==null?void 0:F.logout)==null||G.call(F)}catch{}m(null),B(null),at(null),ct(null),it(null),K(""),j("")}if(o===void 0)return s.jsxs("div",{className:"shell","data-id":"TermsCheckingSplash",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"card",children:[s.jsx(Us,{}),s.jsx("div",{className:"spinner-row",children:s.jsx(yl,{})})]})]});if(!o)return s.jsx(Ky,{onAgree:()=>U(!0)});if(!E&&z)return s.jsxs("div",{className:"shell","data-id":"AuthRestoringSplash",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"card",children:[s.jsx(Us,{}),s.jsxs("div",{className:"spinner-row",children:[s.jsx(yl,{}),s.jsx("span",{children:"正在恢复登录…"})]})]})]});if(!E)return s.jsxs("div",{className:"shell",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"card",children:[s.jsx(Us,{}),!X&&s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"tagline",children:"登录以同步你的团队、配置与 AI 助手"}),s.jsxs("button",{className:"btn-primary",onClick:H,children:[s.jsx("span",{children:"使用浏览器登录"}),s.jsx(Ys,{})]}),s.jsx("p",{className:"hint",children:"点击后会自动打开浏览器"})]}),X&&s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"tagline",children:"已在浏览器打开登录页,等待你完成…"}),s.jsxs("div",{className:"spinner-row",children:[s.jsx(yl,{}),s.jsx("span",{children:"等待回调"})]}),s.jsx("button",{className:"btn-ghost",onClick:()=>{var D,F,G;(G=(F=(D=window.cicy)==null?void 0:D.auth)==null?void 0:F.loginCancel)==null||G.call(F),w(!1)},children:"取消"})]}),lt&&s.jsx("div",{className:"error",children:lt})]})]});const nt=(M||[]).filter(D=>Bs(D.base_url)),ft=(M||[]).filter(D=>!Bs(D.base_url)),At=nt.length,Ht=ft.length,Nt=(st||[]).filter(D=>!D.is_local&&D.kind!=="local"),Ne=Nt.length,Ze=Yt==="all"||Yt==="local",gl=Yt==="all"||Yt==="custom",Xl=Yt==="all"||Yt==="cloud";return s.jsxs("div",{className:"shell shell--app",children:[s.jsx("div",{className:"glow glow--app","aria-hidden":!0}),s.jsxs("div",{className:"shell__left",children:[s.jsx(Vy,{me:k,welcome:Q,onLogout:Z,mitmTeam:nt.length>0?nt[0]:null}),s.jsxs("main",{className:"main",children:[s.jsxs("div",{className:"app__tabsrow",children:[s.jsx("div",{className:"app__tabs",children:[{k:"all",label:"全部",n:At+Ht+Ne},{k:"local",label:"本地",n:At},{k:"cloud",label:"私有云",n:Ne},{k:"custom",label:"自定义",n:Ht}].map(({k:D,label:F,n:G})=>s.jsxs("button",{type:"button",className:`app__tab ${Yt===D?"is-active":""}`,onClick:()=>S(D),children:[F,s.jsx("span",{className:"app__tab-count",children:G})]},D))}),s.jsxs("button",{type:"button","data-id":"AddTeamButton",className:"app__add-team",title:Y("teams.addHint","在云端新建私有云团队"),onClick:()=>hi("?tab=private"),children:["+ ",Y("teams.add","新加团队")]})]}),W&&s.jsxs("div",{className:"error",style:{marginBottom:12},children:["云端: ",W,s.jsx("button",{className:"btn-ghost",style:{marginLeft:8},onClick:()=>R(E||O,P),children:"重试"})]}),s.jsxs("div",{className:"app__grid",children:[Ze&&nt.map(D=>s.jsx(Pd,{team:D,onOpen:()=>x(D.id),onRename:r,onRefresh:gt},"local:"+D.id)),Ze&&nt.length===0&&s.jsxs("div",{"data-id":"LocalTeamPlaceholder",className:"bcard bcard--local",children:[s.jsx("div",{className:"bcard__accent"}),s.jsx("div",{className:"bcard__top",children:s.jsxs("div",{className:"bcard__pill",children:[s.jsx("span",{className:"bcard__dot","data-tone":"warn"}),s.jsx(fm,{})]})}),s.jsxs("div",{className:"bcard__body",children:[s.jsx("h3",{className:"bcard__name",children:"本地团队"}),s.jsx("div",{className:"bcard__host",children:"http://127.0.0.1:8008"}),s.jsx("div",{className:"bcard__meta"})]}),s.jsxs("button",{type:"button",className:"bcard__cta",disabled:!0,children:[s.jsx(yl,{}),s.jsx("span",{children:Zt?"正在启动,就绪后自动加入…":"检测中…"})]})]}),gl&&ft.map(D=>s.jsx(Pd,{team:D,onOpen:()=>x(D.id),onRename:r,onRefresh:gt},"custom:"+D.id)),Xl&&Nt.map(D=>s.jsx(Jy,{team:D,onOpen:()=>{var G,C,q;const F=D.kind==="private"?D.host_url:D.workspace_url||D.workspace_direct_url;F&&((q=(C=(G=window.cicy)==null?void 0:G.tabs)==null?void 0:C.open)==null||q.call(C,F,D.name||D.title||""))}},"cloud:"+D.id)),Ze&&s.jsxs("button",{type:"button",className:"add-card",onClick:()=>{alert("装本地 cicy-code(npx cicy-code / docker run)后会自动出现,或在云端创建团队。")},children:[s.jsx("span",{className:"add-card__plus",children:"+"}),s.jsx("span",{className:"add-card__label",children:"新建本地团队"})]})]}),!ht&&!W&&st&&st.length===0&&!(M!=null&&M.length)&&s.jsx("div",{className:"empty",style:{marginTop:14},children:"还没有团队 — 安装本地 cicy-code 起一个本地 team,或在云端创建。"})]})]}),s.jsx(Ly,{}),s.jsx(Gy,{})]})}function Xy({onClose:o}){const[U,E]=N.useState(null),[m,O]=N.useState(""),[B,P]=N.useState(!1),[at,z]=N.useState(""),b=typeof window<"u"&&window.cicy&&window.cicy.trustedOrigins||null,X=N.useCallback(async()=>{try{E(b&&await b.list()||[])}catch{E([])}},[b]);N.useEffect(()=>{X()},[X]);const w=async()=>{const Q=m.trim();if(!(!Q||B||!b)){P(!0),z("");try{const L=await b.add(Q);L&&L.ok===!1?z(L.error||Y("trustedSites.addFailed","添加失败")):(O(""),E(L&&L.origins||await b.list()))}catch(L){z(String(L&&L.message||L))}finally{P(!1)}}},lt=async Q=>{if(!(B||!b)){P(!0),z("");try{const L=await b.remove(Q);L&&L.ok===!1?z(L.error||Y("trustedSites.removeFailed","删除失败")):E(L&&L.origins||await b.list())}catch(L){z(String(L&&L.message||L))}finally{P(!1)}}},K={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:Q=>({flex:1,fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",fontSize:13,color:Q?"#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 Kn.createPortal(s.jsx("div",{style:K.overlay,onClick:o,"data-id":"TrustedSitesModal",children:s.jsxs("div",{style:K.card,onClick:Q=>Q.stopPropagation(),children:[s.jsxs("div",{style:K.head,children:[s.jsx("h2",{style:K.title,children:Y("trustedSites.title","受信任站点")}),s.jsx("button",{type:"button",style:K.x,onClick:o,"aria-label":"close",children:"✕"})]}),s.jsx("div",{style:K.warn,children:Y("trustedSites.warn","⚠ 列表中的站点可以在你的电脑上执行命令(exec)。只添加你完全信任的地址。")}),s.jsxs("div",{style:K.addRow,children:[s.jsx("input",{"data-id":"trusted-sites-input",style:K.input,value:m,onChange:Q=>O(Q.target.value),onKeyDown:Q=>{Q.key==="Enter"&&w()},placeholder:Y("trustedSites.placeholder","添加站点,如 app.cicy-ai.com 或 my-cloud.example.org")}),s.jsx("button",{type:"button","data-id":"trusted-sites-add",style:{...K.addBtn,opacity:B||!m.trim()?.5:1},onClick:w,disabled:B||!m.trim(),children:Y("trustedSites.add","添加")})]}),at&&s.jsx("div",{style:K.err,children:at}),s.jsx("div",{style:K.listWrap,children:U===null?s.jsx("div",{style:K.muted,children:Y("trustedSites.loading","加载中…")}):U.length===0?s.jsx("div",{style:K.muted,children:Y("trustedSites.empty","暂无")}):U.map(Q=>s.jsxs("div",{style:K.row,"data-id":"trusted-sites-row",children:[s.jsx("span",{style:K.host(Q.builtin),children:Q.host}),Q.builtin?s.jsx("span",{style:K.tag,children:Y("trustedSites.builtin","系统")}):s.jsx("button",{type:"button",style:K.rm,onClick:()=>lt(Q.host),disabled:B,children:Y("trustedSites.remove","删除")})]},Q.host))})]})}),document.body)}function Zy({onClose:o}){const[U,E]=N.useState(null),[m,O]=N.useState(""),[B,P]=N.useState(""),[at,z]=N.useState(!1),b=typeof window<"u"&&window.cicy&&window.cicy.rpcAudit||null,X=N.useCallback(async()=>{z(!0),O("");try{const M=b&&await b.tail(400);!M||M.ok===!1?(O(M&&M.error||Y("audit.loadFailed","读取失败")),E([])):(E(M.entries||[]),P(M.path||""))}catch(M){O(String(M&&M.message||M)),E([])}finally{z(!1)}},[b]);N.useEffect(()=>{X()},[X]);const[w,lt]=N.useState("all"),[K,Q]=N.useState(""),L=M=>{try{return new Date(M).toLocaleString()}catch{return M||""}},k=M=>{if(M.kind==="auth"){const yt=/deny/.test(M.decision||"");return{text:M.decision||"auth",color:yt?"#fca5a5":"#86efac",bg:yt?"rgba(239,68,68,.14)":"rgba(34,197,94,.14)"}}if(M.kind==="rpc"){const yt=M.ok!==!1&&!M.error;return{text:yt?"ok":"err",color:yt?"#86efac":"#fca5a5",bg:yt?"rgba(34,197,94,.14)":"rgba(239,68,68,.14)"}}return{text:M.kind||"log",color:"#a1a1aa",bg:"rgba(255,255,255,.06)"}},ct=M=>M.kind==="auth"?`${M.gate||""}${M.decision?" · "+M.decision:""}`:M.kind==="rpc"?`${M.tool||""}${M.dangerous?" ⚠":""}`:M.kind||"",st=M=>M.error||M.args||(M.kind==="rpc"?M.channel:"")||"",it=U||[],ht=K.trim().toLowerCase(),Tt=it.filter(M=>w!=="all"&&M.kind!==w?!1:ht?[M.origin,M.host,M.tool,M.gate,M.decision,M.channel,M.args,M.error,M.kind].filter(Boolean).join(" ").toLowerCase().includes(ht):!0),W="186px 104px minmax(160px,1.1fr) minmax(150px,1.1fr) minmax(220px,1.8fr)",j={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:M=>({background:M?"rgba(255,255,255,.14)":"transparent",border:"1px solid rgba(255,255,255,.12)",borderRadius:999,padding:"6px 16px",color:M?"#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:W,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:W,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:M=>({justifySelf:"start",fontSize:11.5,color:M.color,background:M.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}},bt=M=>s.jsx("div",{children:M});return Kn.createPortal(s.jsx("div",{style:j.overlay,onClick:o,"data-id":"AuditLogModal",children:s.jsxs("div",{style:j.card,onClick:M=>M.stopPropagation(),children:[s.jsxs("div",{style:j.head,children:[s.jsxs("div",{style:j.titleWrap,children:[s.jsx("h2",{style:j.title,children:Y("audit.title","审计日志")}),B&&s.jsx("p",{style:j.subtitle,children:B})]}),s.jsxs("span",{style:j.count,children:[Y("audit.count","共")," ",Tt.length,w!=="all"||ht?` / ${it.length}`:""]}),s.jsx("button",{type:"button","data-id":"audit-refresh",style:{...j.refresh,opacity:at?.5:1},onClick:X,disabled:at,children:Y("audit.refresh","刷新")}),s.jsx("button",{type:"button",style:j.x,onClick:o,"aria-label":"close",children:"✕"})]}),s.jsxs("div",{style:j.toolbar,children:[s.jsxs("div",{style:j.chips,children:[s.jsx("button",{type:"button",style:j.chip(w==="all"),onClick:()=>lt("all"),children:Y("audit.all","全部")}),s.jsx("button",{type:"button",style:j.chip(w==="rpc"),onClick:()=>lt("rpc"),children:Y("audit.rpc","RPC 调用")}),s.jsx("button",{type:"button",style:j.chip(w==="auth"),onClick:()=>lt("auth"),children:Y("audit.auth","授权决定")})]}),s.jsx("input",{"data-id":"audit-search",style:j.search,value:K,onChange:M=>Q(M.target.value),placeholder:Y("audit.search","搜索来源 / 工具 / 命令…")})]}),m&&s.jsx("div",{style:j.err,children:m}),s.jsxs("div",{style:j.tableWrap,children:[s.jsxs("div",{style:j.theadRow,children:[bt(Y("audit.colTime","时间")),bt(Y("audit.colType","类型")),bt(Y("audit.colSource","来源")),bt(Y("audit.colOp","操作")),bt(Y("audit.colDetail","详情"))]}),U===null?s.jsx("div",{style:j.muted,children:Y("audit.loading","加载中…")}):Tt.length===0?s.jsx("div",{style:j.muted,children:it.length===0?Y("audit.empty","暂无审计记录"):Y("audit.noMatch","无匹配记录")}):Tt.map((M,yt)=>{const Qt=k(M);return s.jsxs("div",{style:j.row,"data-id":"audit-row",children:[s.jsx("span",{style:j.time,children:L(M.ts)}),s.jsx("span",{style:j.badge(Qt),children:Qt.text}),s.jsx("span",{style:j.cell,children:M.origin||M.host||"—"}),s.jsx("span",{style:j.cell,children:ct(M)||"—"}),s.jsx("span",{style:j.detail,children:st(M)||"—"})]},yt)})]})]})}),document.body)}function Vy({me:o,welcome:U,onLogout:E,mitmTeam:m}){const O=(o==null?void 0:o.display_name)||(o==null?void 0:o.username)||"…",B=O.slice(0,1).toUpperCase(),[P,at]=N.useState(!1),[z,b]=N.useState(!1),[X,w]=N.useState(!1),lt=N.useRef(null);N.useEffect(()=>{if(!P)return;const Q=L=>{lt.current&&!lt.current.contains(L.target)&&at(!1)};return document.addEventListener("mousedown",Q),()=>document.removeEventListener("mousedown",Q)},[P]);const K=Q=>{hi(Q),at(!1)};return s.jsxs("header",{className:"topbar",children:[s.jsxs("div",{className:"brand-mini",children:[s.jsx("div",{className:"brand-mark sm",children:s.jsx(sm,{})}),s.jsx("span",{className:"brand-name",children:"CiCy Desktop"})]}),s.jsxs("div",{className:"user-chip","data-id":"UserChip",ref:lt,children:[U&&s.jsx("span",{className:"welcome",children:U}),s.jsxs("button",{type:"button","data-id":"UserChip-trigger",className:`user-chip__trigger${P?" is-open":""}`,onClick:()=>at(Q=>!Q),children:[s.jsx("div",{className:"avatar",children:B}),s.jsx("span",{className:"user-name",children:O}),s.jsx("span",{className:"user-chip__caret","aria-hidden":!0,children:"▾"})]}),P&&s.jsxs("div",{className:"user-chip__menu","data-id":"UserChip-menu",role:"menu",children:[s.jsx("button",{type:"button","data-id":"UserChip-wallet",className:"user-chip__menu-item",onClick:()=>K("?view=wallet"),children:"我的钱包"}),s.jsx("button",{type:"button","data-id":"UserChip-billing",className:"user-chip__menu-item",onClick:()=>K("?view=usage"),children:"我的账单"}),s.jsx("button",{type:"button","data-id":"UserChip-trusted-sites",className:"user-chip__menu-item",onClick:()=>{at(!1),b(!0)},children:Y("trustedSites.menu","受信任站点")}),s.jsx("button",{type:"button","data-id":"UserChip-audit-log",className:"user-chip__menu-item",onClick:()=>{at(!1),w(!0)},children:Y("audit.menu","审计日志")}),m&&s.jsx("div",{className:"user-chip__menu-mitm","data-id":"UserChip-mitm",onClick:Q=>Q.stopPropagation(),children:s.jsx(ky,{team:m,variant:"menu"})}),s.jsx("div",{className:"user-chip__menu-sep","aria-hidden":!0}),s.jsx("button",{type:"button","data-id":"UserChip-logout",className:"user-chip__menu-item is-danger",onClick:()=>{at(!1),E()},children:"退出"})]})]}),z&&s.jsx(Xy,{onClose:()=>b(!1)}),X&&s.jsx(Zy,{onClose:()=>w(!1)})]})}function Ky({onAgree:o}){var Q;const[U,E]=N.useState(!1),[m,O]=N.useState(!1),[B,P]=N.useState(!1),at=(((Q=window.cicyI18n)==null?void 0:Q.locale)||"en").startsWith("zh")?"zh-CN":"en",z=(L,k)=>Y(`firstRunTerms.${L}`,k),b=[1,2,3,4,5,6].map(L=>z(`summary${L}`,"")),X=L=>{const k=L.currentTarget;k.scrollHeight-k.scrollTop-k.clientHeight<24&&E(!0)},w=N.useRef(null);N.useEffect(()=>{const L=w.current;L&&L.scrollHeight<=L.clientHeight+24&&E(!0)},[m]);const lt=async()=>{var L,k,ct;if(!(B||!U)){P(!0);try{await((ct=(k=(L=window.cicy)==null?void 0:L.terms)==null?void 0:k.agree)==null?void 0:ct.call(k,cm)),o==null||o()}catch{o==null||o()}}},K=()=>{var L,k,ct;try{(ct=(k=(L=window.cicy)==null?void 0:L.terms)==null?void 0:k.decline)==null||ct.call(k)}catch{}};return s.jsxs("div",{className:"shell terms-gate","data-id":"FirstRunTermsGate",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"terms-gate__panel",children:[s.jsx("h1",{className:"terms-gate__title","data-id":"FirstRunTermsGate-title",children:z("title","用户协议与授权说明")}),s.jsx("p",{className:"terms-gate__subtitle",children:z("subtitle","使用 CiCy Desktop 前,请阅读并同意以下条款")}),s.jsxs("div",{className:"terms-gate__body",ref:w,onScroll:X,"data-id":"FirstRunTermsGate-body",children:[s.jsx("h2",{className:"terms-gate__h2",children:z("summaryTitle","一眼看懂")}),s.jsx("ol",{className:"terms-gate__summary",children:b.filter(Boolean).map((L,k)=>s.jsx("li",{children:L},k))}),m?s.jsx("pre",{className:"terms-gate__fulltext","data-id":"FirstRunTermsGate-fulltext",children:Wd[at]||Wd.en}):s.jsx("button",{className:"terms-gate__viewfull","data-id":"FirstRunTermsGate-viewfull",onClick:()=>O(!0),children:z("viewFull","查看完整条款")})]}),!U&&s.jsx("div",{className:"terms-gate__scrollhint","data-id":"FirstRunTermsGate-scrollhint",children:z("scrollHint","请阅读至底部以继续")}),s.jsxs("div",{className:"terms-gate__actions",children:[s.jsx("button",{"data-id":"FirstRunTermsGate-decline",className:"terms-gate__btn terms-gate__btn--ghost",onClick:K,children:z("decline","不同意并退出")}),s.jsx("button",{"data-id":"FirstRunTermsGate-agree",className:"terms-gate__btn",disabled:!U||B,title:U?"":z("mustAgree","未同意则无法使用本软件。"),onClick:lt,children:z("agree","同意并继续")})]})]})]})}function ky({team:o,variant:U}){const[E,m]=N.useState(void 0),[O,B]=N.useState(""),[P,at]=N.useState(""),z=((o==null?void 0:o.base_url)||"").replace(/\/$/,""),b=(o==null?void 0:o.api_token)||"",X=N.useCallback(async(ct,st={})=>{var Tt,W;if(!((W=(Tt=window.cicy)==null?void 0:Tt.cloud)!=null&&W.fetch))throw new Error("bridge missing");const it=await window.cicy.cloud.fetch(`${z}${ct}`,{...st,headers:{Authorization:`Bearer ${b}`,"Content-Type":"application/json",...st.headers||{}}});let ht=null;try{ht=JSON.parse(it.body)}catch{}return{ok:it.ok,status:it.status,json:ht}},[z,b]),w=N.useCallback(async()=>{try{const ct=await X("/api/mitm/ca-status");m(ct.ok&&ct.json?ct.json:null)}catch{m(null)}},[X]);if(N.useEffect(()=>{z&&b&&w()},[z,b,w]),E===void 0||!E||!E.generated)return null;const lt=async()=>{var ct,st,it,ht,Tt,W,j,bt,M;if(!O){B("enable"),at("");try{const yt=await X("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!0})}),Qt=`${((ct=yt.json)==null?void 0:ct.error)||""} ${((st=yt.json)==null?void 0:st.detail)||""}`,Xt=((it=yt.json)==null?void 0:it.error)==="need_elevation"||!yt.ok&&yt.status===403||/need_elevation|add-trusted-cert|write permission|SecCertificate|not permitted|requires admin|administrator/i.test(Qt);if(yt.ok&&((ht=yt.json)!=null&&ht.ok)&&((Tt=yt.json)!=null&&Tt.trusted))await w();else if(Xt){const Zt=await((bt=(j=(W=window.cicy)==null?void 0:W.mitm)==null?void 0:j.caExec)==null?void 0:bt.call(j,"install"));Zt!=null&&Zt.ok?await w():at(/cancel/i.test((Zt==null?void 0:Zt.stderr)||"")?Y("mitmConsent.errorAdminDenied","未获得管理员授权,已取消。"):(Zt==null?void 0:Zt.stderr)||Y("mitmConsent.errorTitle","提权失败,请从管理员控制台运行"))}else at(((M=yt.json)==null?void 0:M.error)||`失败 (HTTP ${yt.status})`)}catch(yt){at(String((yt==null?void 0:yt.message)||yt))}finally{B("")}}},K=async()=>{var ct,st,it,ht,Tt;if(!O){B("disable"),at("");try{const W=await X("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!1})});if(W.ok&&((ct=W.json)!=null&&ct.ok))await w();else{const j=await((ht=(it=(st=window.cicy)==null?void 0:st.mitm)==null?void 0:it.caExec)==null?void 0:ht.call(it,"uninstall"));j!=null&&j.ok?await w():at((j==null?void 0:j.stderr)||((Tt=W.json)==null?void 0:Tt.error)||"撤销失败")}}catch(W){at(String((W==null?void 0:W.message)||W))}finally{B("")}}},Q=E.consent&&E.trusted,L=E.consent&&!E.trusted,k=(ct,st)=>Y(`mitmConsent.${ct}`,st);if(U==="menu"){const ct=st=>{var it;(it=st==null?void 0:st.stopPropagation)==null||it.call(st),!O&&(Q?window.confirm(k("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&K():lt())};return s.jsxs("div",{className:"user-chip__mitm","data-id":"MitmConsentCard",children:[s.jsxs("div",{className:"user-chip__menu-item user-chip__mitm-row",title:k("scopeNote","仅解密 AI 厂商域名,数据留本地,随时可关闭。"),children:[s.jsx("span",{className:"user-chip__mitm-label",children:k("rowLabel","HTTPS 审计")}),s.jsx("button",{type:"button",role:"switch","aria-checked":Q?"true":"false","data-id":"MitmConsentCard-toggle",className:`mini-switch${Q?" is-on":""}${O?" is-busy":""}`,disabled:!!O,onClick:ct,children:s.jsx("span",{className:"mini-switch__knob"})})]}),L&&!O&&s.jsx("div",{className:"user-chip__mitm-note","data-id":"MitmConsentCard-note",children:k("partialNote","已同意但未安装,点开关重试")}),P&&s.jsx("div",{className:"user-chip__mitm-err","data-id":"MitmConsentCard-error",children:P})]})}return Q||O==="disable"?Kn.createPortal(s.jsxs("div",{"data-id":"MitmConsentCard",className:"mitm-pill",title:k("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具生效;随时可关闭。"),children:[s.jsx("span",{className:"mitm-pill__dot","data-busy":O?"1":"0"}),s.jsx("span",{className:"mitm-pill__text","data-id":"MitmConsentCard-title",children:O==="disable"?k("processingRevoke","正在关闭…"):k("statePillOn","HTTPS 审计已开启")}),!O&&s.jsx("button",{type:"button","data-id":"MitmConsentCard-revoke",className:"mitm-pill__off",onClick:()=>{window.confirm(k("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&K()},children:k("turnOff","关闭")})]}),document.body):s.jsxs("div",{"data-id":"MitmConsentCard",className:`mitm-card${Q?" mitm-card--on":""}`,children:[s.jsxs("div",{className:"mitm-card__head",children:[s.jsx("span",{className:"mitm-card__dot","data-state":Q?"on":L?"warn":"off"}),s.jsx("span",{className:"mitm-card__title","data-id":"MitmConsentCard-title",children:O?k("stateProcessingTitle","处理中…"):Q?k("stateGrantedTitle","已启用"):`${k("cardTitle","HTTPS 流量本地审计")}${L?" — "+k("retry","重试"):""}`})]}),s.jsxs("p",{className:"mitm-card__desc","data-id":"MitmConsentCard-desc",children:[Q?k("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具(claude / codex 等)生效;随时可关闭。"):k("body","启用后,CiCy 启动的 AI 工具(claude / codex 等)访问 AI 厂商(Claude / OpenAI / DeepSeek / Gemini)的 HTTPS 流量将被本地审计解密,数据留本地,随时可关闭。"),!Q&&s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsx("span",{className:"mitm-card__note",children:k("adminNote","通过环境变量对 CiCy 启动的 AI 工具生效,不修改系统、无需管理员授权。")}),s.jsx("br",{}),s.jsx("span",{className:"mitm-card__sub",children:k("scopeNote","仅解密上述 AI 厂商域名,其余一切流量不被解密、不被读取。")})]})]}),P&&s.jsxs("div",{className:"mitm-card__error","data-id":"MitmConsentCard-error",children:[k("errorTitle","操作失败"),": ",P]}),s.jsx("div",{className:"mitm-card__actions",children:Q?s.jsx("button",{"data-id":"MitmConsentCard-revoke",className:"mitm-card__btn mitm-card__btn--ghost",disabled:!!O,onClick:()=>{window.confirm(k("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&K()},children:O==="disable"?k("processingRevoke","正在关闭…"):k("revoke","撤销")}):s.jsx("button",{"data-id":"MitmConsentCard-enable",className:"mitm-card__btn",disabled:!!O,onClick:lt,children:O==="enable"?k("processingEnable","正在启用…"):L?k("retry","重试"):k("enable","同意并启用")})})]})}function Pd({team:o,onOpen:U,onRename:E,onRefresh:m}){var Xl,D,F,G;const B=(em[o.status]||em.error).tone,[P,at]=N.useState(!1),[z,b]=N.useState(o.name||""),[X,w]=N.useState(null),[lt,K]=N.useState(""),Q=X??o.name;N.useEffect(()=>{X!=null&&o.name===X&&w(null)},[o.name,X]);const L=C=>{var q;(q=C==null?void 0:C.stopPropagation)==null||q.call(C),b(Q||""),at(!0)},k=async()=>{at(!1);const C=String(z||"").trim();if(!E||!C||C===Q)return;w(C),K("saving");let q;try{q=await E(o.id,C)}catch($){q={ok:!1,error:$==null?void 0:$.message}}w(null),q&&q.ok?(K("saved"),setTimeout(()=>K($=>$==="saved"?"":$),1500)):(K(""),je.show({message:Y("localTeams.renameFailed","改名没保存,已恢复"),status:"error",ttl:4e3}))},st=!!((D=(Xl=window.cicy)==null?void 0:Xl.sidecar)!=null&&D.restart)&&Bs(o.base_url),it=o.status==="running",[ht,Tt]=N.useState(""),[W,j]=N.useState(!1),[bt,M]=N.useState({running:void 0,latest:null,installed:null}),yt=bt.latest,Qt=bt.running,[Xt,Zt]=N.useState(!1),pe=N.useRef(null),Yt=N.useRef(null),S=N.useRef(null),[R,tt]=N.useState({top:0,left:0}),xt=184,gt=()=>{if(!W&&Yt.current){const C=Yt.current.getBoundingClientRect(),q=Math.max(8,Math.min(C.right-xt,window.innerWidth-xt-8));tt({top:Math.round(C.bottom+4),left:Math.round(q)})}j(C=>!C)},r=N.useCallback(async(C=!1)=>{var q,$;if(!(!st||!(($=(q=window.cicy)==null?void 0:q.sidecar)!=null&&$.versions))){C&&Zt(!0);try{const et=await window.cicy.sidecar.versions();M({running:(et==null?void 0:et.running)??null,latest:(et==null?void 0:et.latest)??null,installed:(et==null?void 0:et.installed)??null}),C&&(et!=null&&et.running&&(et!=null&&et.latest)&&tm(et.latest,et.running)>0?je.show({message:`${Y("sidecar.found","发现新版本")} v${et.latest}`,status:"done",ttl:2500}):et!=null&&et.running?je.show({message:`${Y("sidecar.upToDate","已是最新")} v${et.running}`,status:"done",ttl:2500}):je.show({message:Y("sidecar.notRunning","cicy-code 未运行"),status:"error",ttl:4e3}))}catch{C&&je.show({message:Y("sidecar.checkFailed","检查更新失败"),status:"error",ttl:5e3})}finally{C&&Zt(!1)}}},[st]);N.useEffect(()=>{r(!1)},[r]),N.useEffect(()=>{it&&r(!1)},[it,r]);const x=!!(st&&yt&&Qt&&tm(yt,Qt)>0),H=!st&&!!((G=(F=window.cicy)==null?void 0:F.localTeams)!=null&&G.remove),Z=st||H,[nt,ft]=N.useState(!1);N.useEffect(()=>{if(!W)return;const C=q=>{var $,et;($=Yt.current)!=null&&$.contains(q.target)||(et=S.current)!=null&&et.contains(q.target)||j(!1)};return document.addEventListener("mousedown",C),()=>document.removeEventListener("mousedown",C)},[W]),N.useEffect(()=>{W||ft(!1)},[W]);const At=async()=>{var C,q,$;if(!nt){ft(!0);return}if(j(!1),ft(!1),!ht){Tt("remove");try{await(($=(q=(C=window.cicy)==null?void 0:C.localTeams)==null?void 0:q.remove)==null?void 0:$.call(q,o.id))}catch{}Tt(""),m==null||m()}},Ht=`sidecar-op:${o.id}`,Nt=async(C,q,$)=>{var Gt,Oe;if(j(!1),ht)return;Tt(C);const et=C==="update";let Wt=null;et?(hl.open({teamId:o.id,fromVer:Qt,toVer:yt,onRetry:()=>Nt("update",q,$)}),(Oe=(Gt=window.cicy)==null?void 0:Gt.sidecar)!=null&&Oe.onOpProgress&&(Wt=window.cicy.sidecar.onOpProgress(rt=>{(rt==null?void 0:rt.op)==="update"&&hl.push(rt)}))):je.show({id:Ht,message:Ne[C]||`${C}…`,status:"running",progress:void 0});try{const rt=await q(),Ve=!!(rt!=null&&rt.ok),ka=rt!=null&&rt.warning?`${$}(${rt.warning})`:$,Ja=Y("sidecar.failed","操作失败")+(rt!=null&&rt.error?`: ${rt.error}`:"");et?hl.finish({ok:Ve,message:Ve?ka:Ja}):je.show({id:Ht,message:Ve?ka:Ja,progress:void 0,status:Ve?"done":"error",ttl:Ve?4e3:8e3})}catch(rt){const Ve=Y("sidecar.failed","操作失败")+`: ${(rt==null?void 0:rt.message)||rt}`;et?hl.finish({ok:!1,message:Ve}):je.show({id:Ht,message:Ve,progress:void 0,status:"error",ttl:8e3})}finally{try{Wt&&Wt()}catch{}Tt(""),m==null||m(),(C==="update"||C==="restart"||C==="start")&&r(!1)}},Ne={start:"启动中…",restart:"重启中…",update:"更新中…",stop:"停止中…"},Ze=async()=>{var C,q;if(!ht){if(!it&&st&&((q=(C=window.cicy)==null?void 0:C.sidecar)!=null&&q.start)){Tt("start"),je.show({id:Ht,message:Ne.start,status:"running",progress:void 0});const $=await window.cicy.sidecar.start().catch(et=>({ok:!1,error:(et==null?void 0:et.message)||String(et)}));if(Tt(""),m==null||m(),!($!=null&&$.ok)||$!=null&&$.warning){je.show({id:Ht,message:Y("sidecar.startFailed","启动失败")+($!=null&&$.error?`: ${$.error}`:$!=null&&$.warning?`: ${$.warning}`:""),status:"error",ttl:8e3});return}je.dismiss(Ht)}U()}},gl=it?Y("localTeams.open","打开"):st?Y("localTeams.startOpen","启动并打开"):Y("localTeams.open","打开");return s.jsxs("div",{"data-id":"LocalTeamCard",className:`bcard ${st?"bcard--local":"bcard--custom"}${B==="ok"?" bcard--online":""}`,children:[s.jsx("div",{className:"bcard__accent"}),s.jsxs("div",{className:"bcard__top",children:[s.jsxs("div",{className:"bcard__pill",children:[s.jsx("span",{className:"bcard__dot","data-tone":B}),s.jsx(fm,{})]}),Z&&s.jsxs("div",{className:"bcard__menuwrap",ref:pe,onClick:C=>C.stopPropagation(),children:[s.jsx("button",{type:"button",ref:Yt,"data-id":"LocalTeamCard-menu-btn",className:`bcard__kebab${x?" has-dot":""}`,title:st?Y("localTeams.manage","管理本地 cicy-code"):Y("localTeams.more","更多"),disabled:!!ht,onClick:gt,children:ht?s.jsx(yl,{}):s.jsx(om,{})}),W&&Kn.createPortal(s.jsxs("div",{className:"bcard__menu bcard__menu--portal","data-id":"LocalTeamCard-menu",role:"menu",ref:S,style:{position:"fixed",top:R.top,left:R.left,width:xt},onClick:C=>C.stopPropagation(),children:[x&&s.jsxs("button",{type:"button","data-id":"LocalTeamCard-update",className:"bcard__menu-item is-accent",onClick:()=>Nt("update",()=>window.cicy.sidecar.update(),Y("sidecar.updated","已更新到最新")),children:[Y("sidecar.updateTo","更新到")," v",yt]}),st&&it&&s.jsxs(s.Fragment,{children:[s.jsx("button",{type:"button","data-id":"LocalTeamCard-reload",className:"bcard__menu-item",onClick:()=>Nt("reload",async()=>{const C=await window.cicy.localTeams.reload(o.id);return!(C!=null&&C.ok)&&(C==null?void 0:C.error)==="no_open_window"?window.cicy.localTeams.open(o.id):C},Y("localTeams.reloaded","已刷新窗口")),children:Y("localTeams.reloadWindow","刷新窗口")}),s.jsx("button",{type:"button","data-id":"LocalTeamCard-restart",className:"bcard__menu-item",onClick:()=>Nt("restart",()=>window.cicy.sidecar.restart(),Y("sidecar.restarted","已重启")),children:Y("sidecar.restart","重启")}),s.jsx("button",{type:"button","data-id":"LocalTeamCard-stop",className:"bcard__menu-item is-danger",onClick:()=>Nt("stop",()=>window.cicy.sidecar.stop(),Y("sidecar.stoppedDone","已停止")),children:Y("sidecar.stop","停止")})]}),st&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-check-update",className:"bcard__menu-item",disabled:Xt,onClick:C=>{C.stopPropagation(),r(!0)},children:Xt?Y("sidecar.checking2","检查中…"):Y("sidecar.checkUpdate","检查更新")}),o.cloud_team_id&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-billing",className:"bcard__menu-item",onClick:C=>{C.stopPropagation(),j(!1),hi(`?team=${encodeURIComponent(o.cloud_team_id)}`)},children:Y("localTeams.billing","账单")}),H&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-remove",className:"bcard__menu-item is-danger",onClick:At,children:nt?Y("localTeams.removeConfirm","确认删除?"):Y("localTeams.remove","删除")})]}),document.body)]})]}),s.jsxs("div",{className:"bcard__body",children:[P?s.jsx("input",{"data-id":"LocalTeamCard-rename-input",autoFocus:!0,value:z,onChange:C=>b(C.target.value),onFocus:C=>C.target.select(),onBlur:k,onClick:C=>C.stopPropagation(),onKeyDown:C=>{C.key==="Enter"?k():C.key==="Escape"&&at(!1)},style:{width:"100%",font:"inherit",fontWeight:600,padding:"2px 6px",border:"1px solid #3b82f6",borderRadius:6,background:"#0d1117",color:"#e6edf3",boxSizing:"border-box"}}):s.jsxs("h3",{className:"bcard__name",title:Y("localTeams.renameHint","点名字或 ✎ 改名"),style:{display:"flex",alignItems:"center",gap:6},onDoubleClick:L,children:[s.jsx("span",{"data-id":"LocalTeamCard-name-text",onClick:L,style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",cursor:"text"},children:Q}),lt==="saving"&&s.jsx("span",{"data-id":"LocalTeamCard-save-state",title:Y("localTeams.saving","保存中…"),style:{flex:"none",display:"inline-flex"},children:s.jsx(yl,{})}),lt==="saved"&&s.jsx("span",{"data-id":"LocalTeamCard-save-state",title:Y("localTeams.saved","已保存"),style:{flex:"none",color:"#3fb950",fontSize:13,lineHeight:1},children:"✓"}),!lt&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-rename-btn",title:Y("localTeams.rename","重命名"),onClick:L,style:{flex:"none",cursor:"pointer",border:"none",background:"transparent",color:"#8b949e",fontSize:13,padding:0,lineHeight:1},children:"✎"})]}),s.jsx("div",{className:"bcard__host",children:o.base_url||"—"}),s.jsx("div",{className:"bcard__meta",children:(Qt||o.version)&&s.jsxs("span",{className:"bcard__ver","data-id":"LocalTeamCard-version",children:["v",Qt||o.version]})})]}),s.jsxs("button",{type:"button",className:"bcard__cta","data-id":"LocalTeamCard-open",disabled:!!ht||!o.base_url,onClick:Ze,children:[ht&&ht!=="stop"?s.jsx(yl,{}):s.jsx(Ys,{}),s.jsx("span",{children:ht&&Ne[ht]||gl})]})]})}function Bs(o){try{const U=new URL(o);return(U.hostname==="127.0.0.1"||U.hostname==="localhost"||U.hostname==="::1")&&(U.port==="8008"||U.port==="")}catch{return!1}}function tm(o,U){const E=String(o).split("."),m=String(U).split(".");for(let O=0;O<Math.max(E.length,m.length);O++){const B=(parseInt(E[O],10)||0)-(parseInt(m[O],10)||0);if(B)return B>0?1:-1}return 0}const em={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 Jy({team:o,onOpen:U}){const E=o.kind==="private",m=o.status==="active",O=o.name||o.title||"—",B=o.host_url||"",P=o.teamId||o.id,at=E?"私有云":o.team_kind==="personal"?"个人":"共享",z=E?B:o.workspace_url||o.workspace_direct_url,b=!!z,[X,w]=N.useState(!1),[lt,K]=N.useState(!1),[Q,L]=N.useState({top:0,left:0}),k=N.useRef(null),ct=N.useRef(null),st=N.useRef(null),it=184,ht=()=>{if(!X&&ct.current){const W=ct.current.getBoundingClientRect(),j=Math.max(8,Math.min(W.right-it,window.innerWidth-it-8));L({top:Math.round(W.bottom+4),left:Math.round(j)})}w(W=>!W)};N.useEffect(()=>{if(!X)return;const W=j=>{var bt,M;(bt=ct.current)!=null&&bt.contains(j.target)||(M=st.current)!=null&&M.contains(j.target)||w(!1)};return document.addEventListener("mousedown",W),()=>document.removeEventListener("mousedown",W)},[X]);const Tt=async()=>{var W,j,bt;if(!(!b||lt)){K(!0),w(!1);try{await((bt=(j=(W=window.cicy)==null?void 0:W.tabs)==null?void 0:j.reload)==null?void 0:bt.call(j,z,O))}catch{}finally{K(!1)}}};return s.jsxs("div",{"data-id":"TeamCard",className:`bcard bcard--cloud${m?" bcard--online":""}`,children:[s.jsx("div",{className:"bcard__accent"}),s.jsxs("div",{className:"bcard__top",children:[s.jsxs("div",{className:"bcard__pill",children:[s.jsx("span",{className:"bcard__dot","data-tone":m?"ok":"off"}),s.jsx(Wy,{})]}),s.jsxs("div",{className:"bcard__top-right",children:[o.is_trial&&s.jsx("span",{className:"bcard__badge",children:"trial"}),P!=null&&s.jsx("button",{type:"button","data-id":"TeamCard-billing",className:"bcard__billing-btn",title:Y("localTeams.billing","账单"),onClick:W=>{W.stopPropagation(),hi(`?team=${encodeURIComponent(P)}`)},children:Y("localTeams.billing","账单")}),b&&s.jsxs("div",{className:"bcard__menuwrap",ref:k,onClick:W=>W.stopPropagation(),children:[s.jsx("button",{type:"button",ref:ct,"data-id":"TeamCard-menu-btn",className:"bcard__kebab",title:Y("localTeams.more","更多"),disabled:lt,onClick:ht,children:lt?s.jsx(yl,{}):s.jsx(om,{})}),X&&Kn.createPortal(s.jsx("div",{className:"bcard__menu bcard__menu--portal","data-id":"TeamCard-menu",role:"menu",ref:st,style:{position:"fixed",top:Q.top,left:Q.left,width:it},onClick:W=>W.stopPropagation(),children:s.jsx("button",{type:"button","data-id":"TeamCard-reload",className:"bcard__menu-item",onClick:Tt,children:Y("localTeams.reloadWindow","刷新窗口")})}),document.body)]})]})]}),s.jsxs("div",{className:"bcard__body",children:[s.jsx("h3",{className:"bcard__name",title:O,children:O}),s.jsx("div",{className:"bcard__host",title:E&&B||"",children:E?B||Y("teamCard.noHost","未填访问地址"):o.runtime_region||o.region||"—"}),s.jsxs("div",{className:"bcard__meta",children:[s.jsx("span",{className:"bcard__chip",children:at}),!E&&o.membership_status&&o.membership_status!=="active"&&s.jsx("span",{className:"bcard__chip",children:o.membership_status})]})]}),s.jsxs("button",{type:"button",className:"bcard__cta",onClick:U,disabled:!b,children:[s.jsx(Ys,{}),s.jsx("span",{children:b?Y("localTeams.open","打开"):E?Y("teamCard.noHost","未填访问地址"):Y("teamCard.noUrl","无 URL")})]})]})}function Us(){return s.jsxs("div",{className:"brand",children:[s.jsx("div",{className:"brand-mark",children:s.jsx(sm,{})}),s.jsxs("div",{className:"brand-text",children:[s.jsx("div",{className:"brand-name",children:"CiCy Desktop"}),s.jsx("div",{className:"brand-sub",children:"团队 AI 协作工作台"})]})]})}function sm(){return s.jsx("svg",{width:"22",height:"22",viewBox:"0 0 96 96",fill:"none",children:s.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 Ys(){return s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("line",{x1:"5",y1:"12",x2:"19",y2:"12"}),s.jsx("polyline",{points:"12 5 19 12 12 19"})]})}function yl(){return s.jsx("svg",{className:"spin",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.4",strokeLinecap:"round",children:s.jsx("path",{d:"M21 12a9 9 0 1 1-6.2-8.55"})})}function fm(){return s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"4",width:"18",height:"12",rx:"2"}),s.jsx("line",{x1:"2",y1:"20",x2:"22",y2:"20"})]})}function om(){return s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:[s.jsx("circle",{cx:"12",cy:"5",r:"1.7"}),s.jsx("circle",{cx:"12",cy:"12",r:"1.7"}),s.jsx("circle",{cx:"12",cy:"19",r:"1.7"})]})}function Wy(){return s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("circle",{cx:"12",cy:"12",r:"10"}),s.jsx("line",{x1:"2",y1:"12",x2:"22",y2:"12"}),s.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 Vn(o){try{return localStorage.getItem(o)||null}catch{return null}}function lm(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 am;const $y=((am=window.cicy)==null?void 0:am.platform)||(()=>{const o=navigator.userAgent||"";return/Mac/i.test(o)?"darwin":/Windows/i.test(o)?"win32":"linux"})();document.documentElement.dataset.platform=$y;document.documentElement.dataset.fullscreen="0";var nm,um;(um=(nm=window.cicy)==null?void 0:nm.window)!=null&&um.onFullscreen&&window.cicy.window.onFullscreen(o=>{document.documentElement.dataset.fullscreen=o?"1":"0"});qy.createRoot(document.getElementById("root")).render(s.jsx(Qy,{}));
|
|
365
|
+
`},Y=(o,U)=>{var E,m;try{const O=(m=(E=window.cicyI18n)==null?void 0:E.t)==null?void 0:m.call(E,o);return O&&O!==o?O:U}catch{return U}},Ka="cicy_token",oi="cicy_access_token",ri="cicy_user_id",mi="https://cicy-ai.com";async function hi(o){var U,E,m;try{(m=(E=(U=window.cicy)==null?void 0:U.shell)==null?void 0:E.openExternal)==null||m.call(E,`${mi}/dash${o}`)}catch{}}const Rs=new Set;let Yy=0,Ql=[];const Zn=new Map;function $d(){Rs.forEach(o=>o(Ql))}const je={show(o={}){const U=o.id||`t${++Yy}`,E=Ql.find(B=>B.id===U),m={id:U,status:"running",...E,...o};Ql=E?Ql.map(B=>B.id===U?m:B):[...Ql,m],$d();const O=Zn.get(U);return O&&(clearTimeout(O),Zn.delete(U)),o.ttl&&Zn.set(U,setTimeout(()=>je.dismiss(U),o.ttl)),U},dismiss(o){Ql=Ql.filter(E=>E.id!==o);const U=Zn.get(o);U&&(clearTimeout(U),Zn.delete(o)),$d()}};function Ly(){const[o,U]=N.useState(Ql);return N.useEffect(()=>(Rs.add(U),()=>{Rs.delete(U)}),[]),o.length?s.jsx("div",{className:"toast-host","data-id":"ToastHost",children:o.map(E=>s.jsxs("div",{className:"toast","data-id":`Toast-${E.id}`,"data-status":E.status||"running",children:[s.jsx("button",{type:"button",className:"toast__x","data-id":"Toast-dismiss",onClick:()=>je.dismiss(E.id),"aria-label":"dismiss",children:"×"}),s.jsxs("span",{className:"toast__msg",children:[E.message,Number.isFinite(E.progress)?` ${E.progress}%`:""]}),Number.isFinite(E.progress)&&s.jsx("span",{className:"toast__bar",children:s.jsx("span",{style:{width:`${Math.min(100,E.progress)}%`}})})]},E.id))}):null}const Hs=new Set;let Fd=0,oe=null;function di(){Hs.forEach(o=>o(oe))}function Id(){return new Date().toTimeString().slice(0,8)}const hl={open({teamId:o,fromVer:U,toVer:E,onRetry:m}={}){oe={teamId:o,fromVer:U||null,toVer:E||null,status:"running",phase:"download",logs:[],onRetry:m||null,lastAt:Date.now()},di()},push(o={}){if(!oe)return;const U={id:++Fd,t:Id(),phase:o.phase||oe.phase,status:o.status||"running",message:o.message||""};oe={...oe,phase:o.phase||oe.phase,toVer:o.toVer||oe.toVer,logs:[...oe.logs,U],lastAt:Date.now()},di()},finish({ok:o,message:U}={}){if(!oe)return;const E=o?"done":"error",m={id:++Fd,t:Id(),phase:"done",status:E,message:U||(o?"更新完成":"更新失败")};oe={...oe,status:E,phase:"done",logs:[...oe.logs,m],lastAt:Date.now()},di()},close(){oe=null,di()}},ws=[["download","下载"],["swap","切换"],["done","完成"]];function Gy(){var at;const[o,U]=N.useState(oe);N.useEffect(()=>(Hs.add(U),()=>{Hs.delete(U)}),[]);const E=N.useRef(null);N.useEffect(()=>{const z=E.current;z&&(z.scrollTop=z.scrollHeight)},[(at=o==null?void 0:o.logs)==null?void 0:at.length]);const[m,O]=N.useState(!1);if(N.useEffect(()=>{if(!o||o.status!=="running"){O(!1);return}const z=setInterval(()=>O(Date.now()-(o.lastAt||0)>25e3),3e3);return()=>clearInterval(z)},[o==null?void 0:o.lastAt,o==null?void 0:o.status]),!o)return null;const B=o.status==="running",P=ws.findIndex(([z])=>z===o.phase);return s.jsx("div",{className:"drawer-scrim","data-id":"UpdateDrawer-scrim",onClick:()=>{B||hl.close()},children:s.jsxs("div",{className:"drawer","data-id":"UpdateDrawer","data-status":o.status,onClick:z=>z.stopPropagation(),children:[s.jsxs("div",{className:"drawer__head",children:[s.jsxs("div",{className:"drawer__title",children:[s.jsx("span",{className:`drawer__spark drawer__spark--${o.status}`,children:B?s.jsx(yl,{}):o.status==="done"?"✓":"!"}),s.jsxs("div",{children:[s.jsx("div",{className:"drawer__h",children:"更新 cicy-code"}),s.jsxs("div",{className:"drawer__sub",children:[o.fromVer?`v${o.fromVer}`:"当前"," → ",o.toVer?`v${o.toVer}`:"最新版"]})]})]}),s.jsx("button",{type:"button",className:"drawer__x","data-id":"UpdateDrawer-close",disabled:B,title:B?"更新进行中":"关闭",onClick:()=>hl.close(),"aria-label":"close",children:"×"})]}),s.jsx("div",{className:"drawer__steps","data-id":"UpdateDrawer-steps",children:ws.map(([z,b],X)=>{const w=o.status==="done"||X<P,lt=X===P&&B,K=o.status==="error"&&X===P;return s.jsxs("div",{className:`drawer__step${lt?" is-active":""}${w?" is-done":""}${K?" is-error":""}`,children:[s.jsx("span",{className:"drawer__step-dot",children:w?"✓":K?"!":X+1}),s.jsx("span",{className:"drawer__step-label",children:b}),X<ws.length-1&&s.jsx("span",{className:"drawer__step-bar"})]},z)})}),s.jsx("div",{className:"drawer__log","data-id":"UpdateDrawer-log",ref:E,children:o.logs.length===0?s.jsx("div",{className:"drawer__log-empty",children:"准备中…"}):o.logs.map(z=>s.jsxs("div",{className:"drawer__line","data-status":z.status,children:[s.jsx("span",{className:"drawer__t",children:z.t}),s.jsx("span",{className:`drawer__badge drawer__badge--${z.phase}`,children:{download:"下载",swap:"切换",done:"完成"}[z.phase]||z.phase}),s.jsx("span",{className:"drawer__linemsg",children:z.message})]},z.id))}),m&&B&&s.jsx("div",{className:"drawer__hint","data-id":"UpdateDrawer-stuck",children:"正在等待新版本就绪,耗时比平常久。可以放到后台继续,完成或失败都会提示。"}),s.jsx("div",{className:"drawer__foot",children:B?s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"drawer__foot-status",children:"更新进行中…"}),s.jsx("button",{type:"button",className:"drawer__btn","data-id":"UpdateDrawer-background",onClick:()=>hl.close(),children:"在后台继续"})]}):o.status==="error"?s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"drawer__foot-status is-error",children:"更新失败"}),o.onRetry&&s.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-retry",onClick:()=>o.onRetry(),children:"重试"}),s.jsx("button",{type:"button",className:"drawer__btn","data-id":"UpdateDrawer-dismiss",onClick:()=>hl.close(),children:"关闭"})]}):s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"drawer__foot-status is-done",children:"已更新到最新"}),s.jsx("button",{type:"button",className:"drawer__btn is-accent","data-id":"UpdateDrawer-finish",onClick:()=>hl.close(),children:"完成"})]})})]})})}function Qy(){const[o,U]=N.useState(void 0);N.useEffect(()=>{var D,F;if(!((F=(D=window.cicy)==null?void 0:D.terms)!=null&&F.status)){U(!0);return}window.cicy.terms.status(cm).then(G=>U(!!(G!=null&&G.accepted))).catch(()=>U(!0))},[]),N.useEffect(()=>{var G,C,q,$;const D=document.documentElement;try{D.setAttribute("data-platform",((G=window.cicy)==null?void 0:G.platform)||"linux")}catch{}D.setAttribute("data-fullscreen","0");let F;try{F=($=(q=(C=window.cicy)==null?void 0:C.window)==null?void 0:q.onFullscreen)==null?void 0:$.call(q,et=>D.setAttribute("data-fullscreen",et?"1":"0"))}catch{}return()=>{try{F&&F()}catch{}}},[]);const[E,m]=N.useState(()=>Vn(Ka)),[O,B]=N.useState(()=>Vn(oi)),[P,at]=N.useState(()=>Vn(ri)),[z,b]=N.useState(()=>!Vn(Ka)),[X,w]=N.useState(!1),[lt,K]=N.useState(""),[Q,L]=N.useState(""),[k,ct]=N.useState(null),[st,it]=N.useState(null),[ht,Tt]=N.useState(!1),[W,j]=N.useState(""),bt=N.useRef(!1),[M,yt]=N.useState(null),[Qt,Xt]=N.useState(!1),[Zt,pe]=N.useState(!1),[Yt,S]=N.useState("all"),R=N.useCallback(async(D,F)=>{var C,q,$,et;if(!D)return;if(!((q=(C=window.cicy)==null?void 0:C.cloud)!=null&&q.fetch)){j("cloud fetch bridge missing");return}Tt(!0),j("");const G={Authorization:`Bearer ${D}`};try{const[Wt,Gt]=await Promise.all([window.cicy.cloud.fetch(`${mi}/api/user/self`,{headers:G}),window.cicy.cloud.fetch(`${mi}/api/teams`,{headers:G})]);if((Gt==null?void 0:Gt.status)===401){if(!bt.current&&((et=($=window.cicy)==null?void 0:$.auth)!=null&&et.loginStart)){bt.current=!0,j("会话已过期,正在重新登录…");try{await window.cicy.auth.loginStart()}catch{}}return}if(!(Gt!=null&&Gt.ok))throw new Error(`/api/teams ${(Gt==null?void 0:Gt.status)||"?"} ${(Gt==null?void 0:Gt.error)||""}`);const Oe=JSON.parse(Gt.body||"{}");if(it(Array.isArray(Oe==null?void 0:Oe.teams)?Oe.teams:[]),Wt!=null&&Wt.ok)try{const rt=JSON.parse(Wt.body||"{}");ct((rt==null?void 0:rt.success)===!1?null:(rt==null?void 0:rt.data)||null)}catch{ct(null)}else ct(null)}catch(Wt){j(Wt.message||String(Wt))}finally{Tt(!1)}},[]),tt=N.useRef("");N.useEffect(()=>{tt.current=E||O||""},[E,O]);const xt=N.useCallback(async()=>{var F,G;const D=tt.current;if(!(!D||!((G=(F=window.cicy)==null?void 0:F.cloud)!=null&&G.fetch)))try{const C=await window.cicy.cloud.fetch(`${mi}/api/teams`,{headers:{Authorization:`Bearer ${D}`}});if(C!=null&&C.ok){const q=JSON.parse(C.body||"{}");Array.isArray(q==null?void 0:q.teams)&&it(q.teams)}}catch{}},[]);N.useEffect(()=>{const D=E||O;D&&R(D,P)},[E,O,P,R]);const gt=N.useCallback(async()=>{var D,F;if((F=(D=window.cicy)==null?void 0:D.localTeams)!=null&&F.list){Xt(!0);try{const G=await window.cicy.localTeams.list({refresh:!0});yt(Array.isArray(G)?G:[])}catch{yt([])}finally{Xt(!1),pe(!0)}}},[]),r=N.useCallback(async(D,F)=>{var C,q;if(!((q=(C=window.cicy)==null?void 0:C.localTeams)!=null&&q.update))return{ok:!1,error:"no_bridge"};let G;try{G=await window.cicy.localTeams.update(D,{name:String(F||"").trim()||Y("localTeams.unnamed","未命名")})}catch($){G={ok:!1,error:($==null?void 0:$.message)||String($)}}return await gt(),G||{ok:!1,error:"no_result"}},[gt]);N.useEffect(()=>{let D,F=!1;const G=3e3,C=3e4,q=async()=>{var Wt,Gt,Oe;try{await((Oe=(Gt=(Wt=window.cicy)==null?void 0:Wt.localTeams)==null?void 0:Gt.syncCloud)==null?void 0:Oe.call(Gt))}catch{}await Promise.all([gt(),xt()])},$=()=>{if(F)return;const Wt=document.visibilityState==="visible";D=setTimeout(async()=>{document.visibilityState==="visible"?await q():await gt(),$()},Wt?G:C)};q(),$();const et=()=>{document.visibilityState==="visible"&&q()};return document.addEventListener("visibilitychange",et),window.addEventListener("focus",et),()=>{F=!0,clearTimeout(D),document.removeEventListener("visibilitychange",et),window.removeEventListener("focus",et)}},[gt,xt]),N.useEffect(()=>{var F,G;if(!((G=(F=window.cicy)==null?void 0:F.localTeams)!=null&&G.onWebviewRelay))return;const D=window.cicy.localTeams.onWebviewRelay(async({reqId:C,msg:q})=>{let $={ok:!1,error:"unknown relay type"};try{(q==null?void 0:q.type)==="localTeams:add"?$=await window.cicy.localTeams.add(q.spec||{}):(q==null?void 0:q.type)==="localTeams:remove"?$=await window.cicy.localTeams.remove(q.id):(q==null?void 0:q.type)==="localTeams:update"?$=await window.cicy.localTeams.update(q.id,q.patch||{}):(q==null?void 0:q.type)==="localTeams:upgrade"?$=await window.cicy.localTeams.upgrade(q.id):(q==null?void 0:q.type)==="localTeams:list"&&($={ok:!0,teams:await window.cicy.localTeams.list({refresh:!0})}),gt()}catch(et){$={ok:!1,error:(et==null?void 0:et.message)||String(et)}}try{window.cicy.localTeams.replyWebviewRelay(C,$)}catch{}});return()=>{try{D==null||D()}catch{}}},[gt]);const x=N.useCallback(async D=>{var F,G;if((G=(F=window.cicy)==null?void 0:F.localTeams)!=null&&G.open)try{await window.cicy.localTeams.open(D)}catch{}},[]);N.useEffect(()=>{var F,G;if(Vn(Ka)){b(!1);return}if(!((G=(F=window.cicy)==null?void 0:F.auth)!=null&&G.getSaved)){b(!1);return}let D=!1;return(async()=>{try{const C=await window.cicy.auth.getSaved();if(D)return;if(C!=null&&C.token){try{localStorage.setItem(Ka,C.token)}catch{}if(m(C.token),C.accessToken){try{localStorage.setItem(oi,C.accessToken)}catch{}B(C.accessToken)}if(C.userId){try{localStorage.setItem(ri,String(C.userId))}catch{}at(String(C.userId))}}}catch{}finally{D||b(!1)}})(),()=>{D=!0}},[]),N.useEffect(()=>{var D,F;if((F=(D=window.cicy)==null?void 0:D.auth)!=null&&F.onComplete)return window.cicy.auth.onComplete(G=>{if(w(!1),G!=null&&G.error){K(lm(G.error));return}if(G!=null&&G.token){bt.current=!1,j("");try{localStorage.setItem(Ka,G.token)}catch{}if(m(G.token),G.accessToken){try{localStorage.setItem(oi,G.accessToken)}catch{}B(G.accessToken)}if(G.userId){try{localStorage.setItem(ri,String(G.userId))}catch{}at(String(G.userId))}K(""),L(G.reused?"已恢复你之前的登录":"登录成功"),setTimeout(()=>L(""),3e3)}})},[]);async function H(){var F,G;if(!((G=(F=window.cicy)==null?void 0:F.auth)!=null&&G.loginStart)){K("auth bridge missing");return}K(""),w(!0);const D=await window.cicy.auth.loginStart();D!=null&&D.ok||(w(!1),K(lm((D==null?void 0:D.error)||"login start failed")))}function Z(){var D,F,G;try{localStorage.removeItem(Ka),localStorage.removeItem(oi),localStorage.removeItem(ri)}catch{}try{(G=(F=(D=window.cicy)==null?void 0:D.auth)==null?void 0:F.logout)==null||G.call(F)}catch{}m(null),B(null),at(null),ct(null),it(null),K(""),j("")}if(o===void 0)return s.jsxs("div",{className:"shell","data-id":"TermsCheckingSplash",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"card",children:[s.jsx(Us,{}),s.jsx("div",{className:"spinner-row",children:s.jsx(yl,{})})]})]});if(!o)return s.jsx(Ky,{onAgree:()=>U(!0)});if(!E&&z)return s.jsxs("div",{className:"shell","data-id":"AuthRestoringSplash",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"card",children:[s.jsx(Us,{}),s.jsxs("div",{className:"spinner-row",children:[s.jsx(yl,{}),s.jsx("span",{children:"正在恢复登录…"})]})]})]});if(!E)return s.jsxs("div",{className:"shell",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"card",children:[s.jsx(Us,{}),!X&&s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"tagline",children:"登录以同步你的团队、配置与 AI 助手"}),s.jsxs("button",{className:"btn-primary",onClick:H,children:[s.jsx("span",{children:"使用浏览器登录"}),s.jsx(Ys,{})]}),s.jsx("p",{className:"hint",children:"点击后会自动打开浏览器"})]}),X&&s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"tagline",children:"已在浏览器打开登录页,等待你完成…"}),s.jsxs("div",{className:"spinner-row",children:[s.jsx(yl,{}),s.jsx("span",{children:"等待回调"})]}),s.jsx("button",{className:"btn-ghost",onClick:()=>{var D,F,G;(G=(F=(D=window.cicy)==null?void 0:D.auth)==null?void 0:F.loginCancel)==null||G.call(F),w(!1)},children:"取消"})]}),lt&&s.jsx("div",{className:"error",children:lt})]})]});const nt=(M||[]).filter(D=>Bs(D.base_url)),ft=(M||[]).filter(D=>!Bs(D.base_url)),At=nt.length,Ht=ft.length,Nt=(st||[]).filter(D=>!D.is_local&&D.kind!=="local"),Ne=Nt.length,Ze=Yt==="all"||Yt==="local",gl=Yt==="all"||Yt==="custom",Xl=Yt==="all"||Yt==="cloud";return s.jsxs("div",{className:"shell shell--app",children:[s.jsx("div",{className:"glow glow--app","aria-hidden":!0}),s.jsxs("div",{className:"shell__left",children:[s.jsx(Vy,{me:k,welcome:Q,onLogout:Z,mitmTeam:nt.length>0?nt[0]:null}),s.jsxs("main",{className:"main",children:[s.jsxs("div",{className:"app__tabsrow",children:[s.jsx("div",{className:"app__tabs",children:[{k:"all",label:"全部",n:At+Ht+Ne},{k:"local",label:"本地",n:At},{k:"cloud",label:"私有云",n:Ne},{k:"custom",label:"自定义",n:Ht}].map(({k:D,label:F,n:G})=>s.jsxs("button",{type:"button",className:`app__tab ${Yt===D?"is-active":""}`,onClick:()=>S(D),children:[F,s.jsx("span",{className:"app__tab-count",children:G})]},D))}),s.jsxs("button",{type:"button","data-id":"AddTeamButton",className:"app__add-team",title:Y("teams.addHint","在云端新建私有云团队"),onClick:()=>hi("?tab=private"),children:["+ ",Y("teams.add","新加团队")]})]}),W&&s.jsxs("div",{className:"error",style:{marginBottom:12},children:["云端: ",W,s.jsx("button",{className:"btn-ghost",style:{marginLeft:8},onClick:()=>R(E||O,P),children:"重试"})]}),s.jsxs("div",{className:"app__grid",children:[Ze&&nt.map(D=>s.jsx(Pd,{team:D,onOpen:()=>x(D.id),onRename:r,onRefresh:gt},"local:"+D.id)),Ze&&nt.length===0&&s.jsxs("div",{"data-id":"LocalTeamPlaceholder",className:"bcard bcard--local",children:[s.jsx("div",{className:"bcard__accent"}),s.jsx("div",{className:"bcard__top",children:s.jsxs("div",{className:"bcard__pill",children:[s.jsx("span",{className:"bcard__dot","data-tone":"warn"}),s.jsx(fm,{})]})}),s.jsxs("div",{className:"bcard__body",children:[s.jsx("h3",{className:"bcard__name",children:"本地团队"}),s.jsx("div",{className:"bcard__host",children:"http://127.0.0.1:8008"}),s.jsx("div",{className:"bcard__meta"})]}),s.jsxs("button",{type:"button",className:"bcard__cta",disabled:!0,children:[s.jsx(yl,{}),s.jsx("span",{children:Zt?"正在启动,就绪后自动加入…":"检测中…"})]})]}),gl&&ft.map(D=>s.jsx(Pd,{team:D,onOpen:()=>x(D.id),onRename:r,onRefresh:gt},"custom:"+D.id)),Xl&&Nt.map(D=>s.jsx(Jy,{team:D,onOpen:()=>{var G,C,q;const F=D.kind==="private"?D.host_url:D.workspace_url||D.workspace_direct_url;F&&((q=(C=(G=window.cicy)==null?void 0:G.tabs)==null?void 0:C.open)==null||q.call(C,F,D.name||D.title||""))}},"cloud:"+D.id)),Ze&&s.jsxs("button",{type:"button",className:"add-card",onClick:()=>{alert("装本地 cicy-code(npx cicy-code / docker run)后会自动出现,或在云端创建团队。")},children:[s.jsx("span",{className:"add-card__plus",children:"+"}),s.jsx("span",{className:"add-card__label",children:"新建本地团队"})]})]}),!ht&&!W&&st&&st.length===0&&!(M!=null&&M.length)&&s.jsx("div",{className:"empty",style:{marginTop:14},children:"还没有团队 — 安装本地 cicy-code 起一个本地 team,或在云端创建。"})]})]}),s.jsx(Ly,{}),s.jsx(Gy,{})]})}function Xy({onClose:o}){const[U,E]=N.useState(null),[m,O]=N.useState(""),[B,P]=N.useState(!1),[at,z]=N.useState(""),b=typeof window<"u"&&window.cicy&&window.cicy.trustedOrigins||null,X=N.useCallback(async()=>{try{E(b&&await b.list()||[])}catch{E([])}},[b]);N.useEffect(()=>{X()},[X]);const w=async()=>{const Q=m.trim();if(!(!Q||B||!b)){P(!0),z("");try{const L=await b.add(Q);L&&L.ok===!1?z(L.error||Y("trustedSites.addFailed","添加失败")):(O(""),E(L&&L.origins||await b.list()))}catch(L){z(String(L&&L.message||L))}finally{P(!1)}}},lt=async Q=>{if(!(B||!b)){P(!0),z("");try{const L=await b.remove(Q);L&&L.ok===!1?z(L.error||Y("trustedSites.removeFailed","删除失败")):E(L&&L.origins||await b.list())}catch(L){z(String(L&&L.message||L))}finally{P(!1)}}},K={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:Q=>({flex:1,fontFamily:"ui-monospace,SFMono-Regular,Menlo,monospace",fontSize:13,color:Q?"#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 Kn.createPortal(s.jsx("div",{style:K.overlay,onClick:o,"data-id":"TrustedSitesModal",children:s.jsxs("div",{style:K.card,onClick:Q=>Q.stopPropagation(),children:[s.jsxs("div",{style:K.head,children:[s.jsx("h2",{style:K.title,children:Y("trustedSites.title","受信任站点")}),s.jsx("button",{type:"button",style:K.x,onClick:o,"aria-label":"close",children:"✕"})]}),s.jsx("div",{style:K.warn,children:Y("trustedSites.warn","⚠ 列表中的站点可以在你的电脑上执行命令(exec)。只添加你完全信任的地址。")}),s.jsxs("div",{style:K.addRow,children:[s.jsx("input",{"data-id":"trusted-sites-input",style:K.input,value:m,onChange:Q=>O(Q.target.value),onKeyDown:Q=>{Q.key==="Enter"&&w()},placeholder:Y("trustedSites.placeholder","添加站点,如 app.cicy-ai.com 或 my-cloud.example.org")}),s.jsx("button",{type:"button","data-id":"trusted-sites-add",style:{...K.addBtn,opacity:B||!m.trim()?.5:1},onClick:w,disabled:B||!m.trim(),children:Y("trustedSites.add","添加")})]}),at&&s.jsx("div",{style:K.err,children:at}),s.jsx("div",{style:K.listWrap,children:U===null?s.jsx("div",{style:K.muted,children:Y("trustedSites.loading","加载中…")}):U.length===0?s.jsx("div",{style:K.muted,children:Y("trustedSites.empty","暂无")}):U.map(Q=>s.jsxs("div",{style:K.row,"data-id":"trusted-sites-row",children:[s.jsx("span",{style:K.host(Q.builtin),children:Q.host}),Q.builtin?s.jsx("span",{style:K.tag,children:Y("trustedSites.builtin","系统")}):s.jsx("button",{type:"button",style:K.rm,onClick:()=>lt(Q.host),disabled:B,children:Y("trustedSites.remove","删除")})]},Q.host))})]})}),document.body)}function Zy({onClose:o}){const[U,E]=N.useState(null),[m,O]=N.useState(""),[B,P]=N.useState(""),[at,z]=N.useState(!1),b=typeof window<"u"&&window.cicy&&window.cicy.rpcAudit||null,X=N.useCallback(async()=>{z(!0),O("");try{const M=b&&await b.tail(400);!M||M.ok===!1?(O(M&&M.error||Y("audit.loadFailed","读取失败")),E([])):(E(M.entries||[]),P(M.path||""))}catch(M){O(String(M&&M.message||M)),E([])}finally{z(!1)}},[b]);N.useEffect(()=>{X()},[X]);const[w,lt]=N.useState("all"),[K,Q]=N.useState(""),L=M=>{try{return new Date(M).toLocaleString()}catch{return M||""}},k=M=>{if(M.kind==="auth"){const yt=/deny/.test(M.decision||"");return{text:M.decision||"auth",color:yt?"#fca5a5":"#86efac",bg:yt?"rgba(239,68,68,.14)":"rgba(34,197,94,.14)"}}if(M.kind==="rpc"){const yt=M.ok!==!1&&!M.error;return{text:yt?"ok":"err",color:yt?"#86efac":"#fca5a5",bg:yt?"rgba(34,197,94,.14)":"rgba(239,68,68,.14)"}}return{text:M.kind||"log",color:"#a1a1aa",bg:"rgba(255,255,255,.06)"}},ct=M=>M.kind==="auth"?`${M.gate||""}${M.decision?" · "+M.decision:""}`:M.kind==="rpc"?`${M.tool||""}${M.dangerous?" ⚠":""}`:M.kind||"",st=M=>M.error||M.args||(M.kind==="rpc"?M.channel:"")||"",it=U||[],ht=K.trim().toLowerCase(),Tt=it.filter(M=>w!=="all"&&M.kind!==w?!1:ht?[M.origin,M.host,M.tool,M.gate,M.decision,M.channel,M.args,M.error,M.kind].filter(Boolean).join(" ").toLowerCase().includes(ht):!0),W="186px 104px minmax(160px,1.1fr) minmax(150px,1.1fr) minmax(220px,1.8fr)",j={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:M=>({background:M?"rgba(255,255,255,.14)":"transparent",border:"1px solid rgba(255,255,255,.12)",borderRadius:999,padding:"6px 16px",color:M?"#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:W,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:W,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:M=>({justifySelf:"start",fontSize:11.5,color:M.color,background:M.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}},bt=M=>s.jsx("div",{children:M});return Kn.createPortal(s.jsx("div",{style:j.overlay,onClick:o,"data-id":"AuditLogModal",children:s.jsxs("div",{style:j.card,onClick:M=>M.stopPropagation(),children:[s.jsxs("div",{style:j.head,children:[s.jsxs("div",{style:j.titleWrap,children:[s.jsx("h2",{style:j.title,children:Y("audit.title","审计日志")}),B&&s.jsx("p",{style:j.subtitle,children:B})]}),s.jsxs("span",{style:j.count,children:[Y("audit.count","共")," ",Tt.length,w!=="all"||ht?` / ${it.length}`:""]}),s.jsx("button",{type:"button","data-id":"audit-refresh",style:{...j.refresh,opacity:at?.5:1},onClick:X,disabled:at,children:Y("audit.refresh","刷新")}),s.jsx("button",{type:"button",style:j.x,onClick:o,"aria-label":"close",children:"✕"})]}),s.jsxs("div",{style:j.toolbar,children:[s.jsxs("div",{style:j.chips,children:[s.jsx("button",{type:"button",style:j.chip(w==="all"),onClick:()=>lt("all"),children:Y("audit.all","全部")}),s.jsx("button",{type:"button",style:j.chip(w==="rpc"),onClick:()=>lt("rpc"),children:Y("audit.rpc","RPC 调用")}),s.jsx("button",{type:"button",style:j.chip(w==="auth"),onClick:()=>lt("auth"),children:Y("audit.auth","授权决定")})]}),s.jsx("input",{"data-id":"audit-search",style:j.search,value:K,onChange:M=>Q(M.target.value),placeholder:Y("audit.search","搜索来源 / 工具 / 命令…")})]}),m&&s.jsx("div",{style:j.err,children:m}),s.jsxs("div",{style:j.tableWrap,children:[s.jsxs("div",{style:j.theadRow,children:[bt(Y("audit.colTime","时间")),bt(Y("audit.colType","类型")),bt(Y("audit.colSource","来源")),bt(Y("audit.colOp","操作")),bt(Y("audit.colDetail","详情"))]}),U===null?s.jsx("div",{style:j.muted,children:Y("audit.loading","加载中…")}):Tt.length===0?s.jsx("div",{style:j.muted,children:it.length===0?Y("audit.empty","暂无审计记录"):Y("audit.noMatch","无匹配记录")}):Tt.map((M,yt)=>{const Qt=k(M);return s.jsxs("div",{style:j.row,"data-id":"audit-row",children:[s.jsx("span",{style:j.time,children:L(M.ts)}),s.jsx("span",{style:j.badge(Qt),children:Qt.text}),s.jsx("span",{style:j.cell,children:M.origin||M.host||"—"}),s.jsx("span",{style:j.cell,children:ct(M)||"—"}),s.jsx("span",{style:j.detail,children:st(M)||"—"})]},yt)})]})]})}),document.body)}function Vy({me:o,welcome:U,onLogout:E,mitmTeam:m}){const O=(o==null?void 0:o.display_name)||(o==null?void 0:o.username)||"…",B=O.slice(0,1).toUpperCase(),[P,at]=N.useState(!1),[z,b]=N.useState(!1),[X,w]=N.useState(!1),lt=N.useRef(null);N.useEffect(()=>{if(!P)return;const Q=L=>{lt.current&&!lt.current.contains(L.target)&&at(!1)};return document.addEventListener("mousedown",Q),()=>document.removeEventListener("mousedown",Q)},[P]);const K=Q=>{hi(Q),at(!1)};return s.jsxs("header",{className:"topbar",children:[s.jsxs("div",{className:"brand-mini",children:[s.jsx("div",{className:"brand-mark sm",children:s.jsx(sm,{})}),s.jsx("span",{className:"brand-name",children:"CiCy Desktop"})]}),s.jsxs("div",{className:"user-chip","data-id":"UserChip",ref:lt,children:[U&&s.jsx("span",{className:"welcome",children:U}),s.jsxs("button",{type:"button","data-id":"UserChip-trigger",className:`user-chip__trigger${P?" is-open":""}`,onClick:()=>at(Q=>!Q),children:[s.jsx("div",{className:"avatar",children:B}),s.jsx("span",{className:"user-name",children:O}),s.jsx("span",{className:"user-chip__caret","aria-hidden":!0,children:"▾"})]}),P&&s.jsxs("div",{className:"user-chip__menu","data-id":"UserChip-menu",role:"menu",children:[s.jsx("button",{type:"button","data-id":"UserChip-wallet",className:"user-chip__menu-item",onClick:()=>K("?view=wallet"),children:"我的钱包"}),s.jsx("button",{type:"button","data-id":"UserChip-billing",className:"user-chip__menu-item",onClick:()=>K("?view=usage"),children:"我的账单"}),s.jsx("button",{type:"button","data-id":"UserChip-trusted-sites",className:"user-chip__menu-item",onClick:()=>{at(!1),b(!0)},children:Y("trustedSites.menu","受信任站点")}),s.jsx("button",{type:"button","data-id":"UserChip-audit-log",className:"user-chip__menu-item",onClick:()=>{at(!1),w(!0)},children:Y("audit.menu","审计日志")}),m&&s.jsx("div",{className:"user-chip__menu-mitm","data-id":"UserChip-mitm",onClick:Q=>Q.stopPropagation(),children:s.jsx(ky,{team:m,variant:"menu"})}),s.jsx("div",{className:"user-chip__menu-sep","aria-hidden":!0}),s.jsx("button",{type:"button","data-id":"UserChip-logout",className:"user-chip__menu-item is-danger",onClick:()=>{at(!1),E()},children:"退出"})]})]}),z&&s.jsx(Xy,{onClose:()=>b(!1)}),X&&s.jsx(Zy,{onClose:()=>w(!1)})]})}function Ky({onAgree:o}){var Q;const[U,E]=N.useState(!1),[m,O]=N.useState(!1),[B,P]=N.useState(!1),at=(((Q=window.cicyI18n)==null?void 0:Q.locale)||"en").startsWith("zh")?"zh-CN":"en",z=(L,k)=>Y(`firstRunTerms.${L}`,k),b=[1,2,3,4,5,6].map(L=>z(`summary${L}`,"")),X=L=>{const k=L.currentTarget;k.scrollHeight-k.scrollTop-k.clientHeight<24&&E(!0)},w=N.useRef(null);N.useEffect(()=>{const L=w.current;L&&L.scrollHeight<=L.clientHeight+24&&E(!0)},[m]);const lt=async()=>{var L,k,ct;if(!(B||!U)){P(!0);try{await((ct=(k=(L=window.cicy)==null?void 0:L.terms)==null?void 0:k.agree)==null?void 0:ct.call(k,cm)),o==null||o()}catch{o==null||o()}}},K=()=>{var L,k,ct;try{(ct=(k=(L=window.cicy)==null?void 0:L.terms)==null?void 0:k.decline)==null||ct.call(k)}catch{}};return s.jsxs("div",{className:"shell terms-gate","data-id":"FirstRunTermsGate",children:[s.jsx("div",{className:"glow","aria-hidden":!0}),s.jsxs("div",{className:"terms-gate__panel",children:[s.jsx("h1",{className:"terms-gate__title","data-id":"FirstRunTermsGate-title",children:z("title","用户协议与授权说明")}),s.jsx("p",{className:"terms-gate__subtitle",children:z("subtitle","使用 CiCy Desktop 前,请阅读并同意以下条款")}),s.jsxs("div",{className:"terms-gate__body",ref:w,onScroll:X,"data-id":"FirstRunTermsGate-body",children:[s.jsx("h2",{className:"terms-gate__h2",children:z("summaryTitle","一眼看懂")}),s.jsx("ol",{className:"terms-gate__summary",children:b.filter(Boolean).map((L,k)=>s.jsx("li",{children:L},k))}),m?s.jsx("pre",{className:"terms-gate__fulltext","data-id":"FirstRunTermsGate-fulltext",children:Wd[at]||Wd.en}):s.jsx("button",{className:"terms-gate__viewfull","data-id":"FirstRunTermsGate-viewfull",onClick:()=>O(!0),children:z("viewFull","查看完整条款")})]}),!U&&s.jsx("div",{className:"terms-gate__scrollhint","data-id":"FirstRunTermsGate-scrollhint",children:z("scrollHint","请阅读至底部以继续")}),s.jsxs("div",{className:"terms-gate__actions",children:[s.jsx("button",{"data-id":"FirstRunTermsGate-decline",className:"terms-gate__btn terms-gate__btn--ghost",onClick:K,children:z("decline","不同意并退出")}),s.jsx("button",{"data-id":"FirstRunTermsGate-agree",className:"terms-gate__btn",disabled:!U||B,title:U?"":z("mustAgree","未同意则无法使用本软件。"),onClick:lt,children:z("agree","同意并继续")})]})]})]})}function ky({team:o,variant:U}){const[E,m]=N.useState(void 0),[O,B]=N.useState(""),[P,at]=N.useState(""),z=((o==null?void 0:o.base_url)||"").replace(/\/$/,""),b=(o==null?void 0:o.api_token)||"",X=N.useCallback(async(ct,st={})=>{var Tt,W;if(!((W=(Tt=window.cicy)==null?void 0:Tt.cloud)!=null&&W.fetch))throw new Error("bridge missing");const it=await window.cicy.cloud.fetch(`${z}${ct}`,{...st,headers:{Authorization:`Bearer ${b}`,"Content-Type":"application/json",...st.headers||{}}});let ht=null;try{ht=JSON.parse(it.body)}catch{}return{ok:it.ok,status:it.status,json:ht}},[z,b]),w=N.useCallback(async()=>{try{const ct=await X("/api/mitm/ca-status");m(ct.ok&&ct.json?ct.json:null)}catch{m(null)}},[X]);if(N.useEffect(()=>{z&&b&&w()},[z,b,w]),E===void 0||!E||!E.generated)return null;const lt=async()=>{var ct,st,it,ht,Tt,W,j,bt,M;if(!O){B("enable"),at("");try{const yt=await X("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!0})}),Qt=`${((ct=yt.json)==null?void 0:ct.error)||""} ${((st=yt.json)==null?void 0:st.detail)||""}`,Xt=((it=yt.json)==null?void 0:it.error)==="need_elevation"||!yt.ok&&yt.status===403||/need_elevation|add-trusted-cert|write permission|SecCertificate|not permitted|requires admin|administrator/i.test(Qt);if(yt.ok&&((ht=yt.json)!=null&&ht.ok)&&((Tt=yt.json)!=null&&Tt.trusted))await w();else if(Xt){const Zt=await((bt=(j=(W=window.cicy)==null?void 0:W.mitm)==null?void 0:j.caExec)==null?void 0:bt.call(j,"install"));Zt!=null&&Zt.ok?await w():at(/cancel/i.test((Zt==null?void 0:Zt.stderr)||"")?Y("mitmConsent.errorAdminDenied","未获得管理员授权,已取消。"):(Zt==null?void 0:Zt.stderr)||Y("mitmConsent.errorTitle","提权失败,请从管理员控制台运行"))}else at(((M=yt.json)==null?void 0:M.error)||`失败 (HTTP ${yt.status})`)}catch(yt){at(String((yt==null?void 0:yt.message)||yt))}finally{B("")}}},K=async()=>{var ct,st,it,ht,Tt;if(!O){B("disable"),at("");try{const W=await X("/api/mitm/consent",{method:"POST",body:JSON.stringify({enable:!1})});if(W.ok&&((ct=W.json)!=null&&ct.ok))await w();else{const j=await((ht=(it=(st=window.cicy)==null?void 0:st.mitm)==null?void 0:it.caExec)==null?void 0:ht.call(it,"uninstall"));j!=null&&j.ok?await w():at((j==null?void 0:j.stderr)||((Tt=W.json)==null?void 0:Tt.error)||"撤销失败")}}catch(W){at(String((W==null?void 0:W.message)||W))}finally{B("")}}},Q=E.consent&&E.trusted,L=E.consent&&!E.trusted,k=(ct,st)=>Y(`mitmConsent.${ct}`,st);if(U==="menu"){const ct=st=>{var it;(it=st==null?void 0:st.stopPropagation)==null||it.call(st),!O&&(Q?window.confirm(k("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&K():lt())};return s.jsxs("div",{className:"user-chip__mitm","data-id":"MitmConsentCard",children:[s.jsxs("div",{className:"user-chip__menu-item user-chip__mitm-row",title:k("scopeNote","仅解密 AI 厂商域名,数据留本地,随时可关闭。"),children:[s.jsx("span",{className:"user-chip__mitm-label",children:k("rowLabel","HTTPS 审计")}),s.jsx("button",{type:"button",role:"switch","aria-checked":Q?"true":"false","data-id":"MitmConsentCard-toggle",className:`mini-switch${Q?" is-on":""}${O?" is-busy":""}`,disabled:!!O,onClick:ct,children:s.jsx("span",{className:"mini-switch__knob"})})]}),L&&!O&&s.jsx("div",{className:"user-chip__mitm-note","data-id":"MitmConsentCard-note",children:k("partialNote","已同意但未安装,点开关重试")}),P&&s.jsx("div",{className:"user-chip__mitm-err","data-id":"MitmConsentCard-error",children:P})]})}return Q||O==="disable"?Kn.createPortal(s.jsxs("div",{"data-id":"MitmConsentCard",className:"mitm-pill",title:k("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具生效;随时可关闭。"),children:[s.jsx("span",{className:"mitm-pill__dot","data-busy":O?"1":"0"}),s.jsx("span",{className:"mitm-pill__text","data-id":"MitmConsentCard-title",children:O==="disable"?k("processingRevoke","正在关闭…"):k("statePillOn","HTTPS 审计已开启")}),!O&&s.jsx("button",{type:"button","data-id":"MitmConsentCard-revoke",className:"mitm-pill__off",onClick:()=>{window.confirm(k("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&K()},children:k("turnOff","关闭")})]}),document.body):s.jsxs("div",{"data-id":"MitmConsentCard",className:`mitm-card${Q?" mitm-card--on":""}`,children:[s.jsxs("div",{className:"mitm-card__head",children:[s.jsx("span",{className:"mitm-card__dot","data-state":Q?"on":L?"warn":"off"}),s.jsx("span",{className:"mitm-card__title","data-id":"MitmConsentCard-title",children:O?k("stateProcessingTitle","处理中…"):Q?k("stateGrantedTitle","已启用"):`${k("cardTitle","HTTPS 流量本地审计")}${L?" — "+k("retry","重试"):""}`})]}),s.jsxs("p",{className:"mitm-card__desc","data-id":"MitmConsentCard-desc",children:[Q?k("grantedDesc","HTTPS 审计已开启,仅对 CiCy 启动的 AI 工具(claude / codex 等)生效;随时可关闭。"):k("body","启用后,CiCy 启动的 AI 工具(claude / codex 等)访问 AI 厂商(Claude / OpenAI / DeepSeek / Gemini)的 HTTPS 流量将被本地审计解密,数据留本地,随时可关闭。"),!Q&&s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsx("span",{className:"mitm-card__note",children:k("adminNote","通过环境变量对 CiCy 启动的 AI 工具生效,不修改系统、无需管理员授权。")}),s.jsx("br",{}),s.jsx("span",{className:"mitm-card__sub",children:k("scopeNote","仅解密上述 AI 厂商域名,其余一切流量不被解密、不被读取。")})]})]}),P&&s.jsxs("div",{className:"mitm-card__error","data-id":"MitmConsentCard-error",children:[k("errorTitle","操作失败"),": ",P]}),s.jsx("div",{className:"mitm-card__actions",children:Q?s.jsx("button",{"data-id":"MitmConsentCard-revoke",className:"mitm-card__btn mitm-card__btn--ghost",disabled:!!O,onClick:()=>{window.confirm(k("revokeConfirm","撤销后将停止解密审计并清除同意标记。确定?"))&&K()},children:O==="disable"?k("processingRevoke","正在关闭…"):k("revoke","撤销")}):s.jsx("button",{"data-id":"MitmConsentCard-enable",className:"mitm-card__btn",disabled:!!O,onClick:lt,children:O==="enable"?k("processingEnable","正在启用…"):L?k("retry","重试"):k("enable","同意并启用")})})]})}function Pd({team:o,onOpen:U,onRename:E,onRefresh:m}){var Xl,D,F,G;const B=(em[o.status]||em.error).tone,[P,at]=N.useState(!1),[z,b]=N.useState(o.name||""),[X,w]=N.useState(null),[lt,K]=N.useState(""),Q=X??o.name;N.useEffect(()=>{X!=null&&o.name===X&&w(null)},[o.name,X]);const L=C=>{var q;(q=C==null?void 0:C.stopPropagation)==null||q.call(C),b(Q||""),at(!0)},k=async()=>{at(!1);const C=String(z||"").trim();if(!E||!C||C===Q)return;w(C),K("saving");let q;try{q=await E(o.id,C)}catch($){q={ok:!1,error:$==null?void 0:$.message}}w(null),q&&q.ok?(K("saved"),setTimeout(()=>K($=>$==="saved"?"":$),1500)):(K(""),je.show({message:Y("localTeams.renameFailed","改名没保存,已恢复"),status:"error",ttl:4e3}))},st=!!((D=(Xl=window.cicy)==null?void 0:Xl.sidecar)!=null&&D.restart)&&Bs(o.base_url),it=o.status==="running",[ht,Tt]=N.useState(""),[W,j]=N.useState(!1),[bt,M]=N.useState({running:void 0,latest:null,installed:null}),yt=bt.latest,Qt=bt.running,[Xt,Zt]=N.useState(!1),pe=N.useRef(null),Yt=N.useRef(null),S=N.useRef(null),[R,tt]=N.useState({top:0,left:0}),xt=184,gt=()=>{if(!W&&Yt.current){const C=Yt.current.getBoundingClientRect(),q=Math.max(8,Math.min(C.right-xt,window.innerWidth-xt-8));tt({top:Math.round(C.bottom+4),left:Math.round(q)})}j(C=>!C)},r=N.useCallback(async(C=!1)=>{var q,$;if(!(!st||!(($=(q=window.cicy)==null?void 0:q.sidecar)!=null&&$.versions))){C&&Zt(!0);try{const et=await window.cicy.sidecar.versions();M({running:(et==null?void 0:et.running)??null,latest:(et==null?void 0:et.latest)??null,installed:(et==null?void 0:et.installed)??null}),C&&(et!=null&&et.running&&(et!=null&&et.latest)&&tm(et.latest,et.running)>0?je.show({message:`${Y("sidecar.found","发现新版本")} v${et.latest}`,status:"done",ttl:2500}):et!=null&&et.running?je.show({message:`${Y("sidecar.upToDate","已是最新")} v${et.running}`,status:"done",ttl:2500}):je.show({message:Y("sidecar.notRunning","cicy-code 未运行"),status:"error",ttl:4e3}))}catch{C&&je.show({message:Y("sidecar.checkFailed","检查更新失败"),status:"error",ttl:5e3})}finally{C&&Zt(!1)}}},[st]);N.useEffect(()=>{r(!1)},[r]),N.useEffect(()=>{it&&r(!1)},[it,r]);const x=!!(st&&yt&&Qt&&tm(yt,Qt)>0),H=!st&&!!((G=(F=window.cicy)==null?void 0:F.localTeams)!=null&&G.remove),Z=st||H,[nt,ft]=N.useState(!1);N.useEffect(()=>{if(!W)return;const C=q=>{var $,et;($=Yt.current)!=null&&$.contains(q.target)||(et=S.current)!=null&&et.contains(q.target)||j(!1)};return document.addEventListener("mousedown",C),()=>document.removeEventListener("mousedown",C)},[W]),N.useEffect(()=>{W||ft(!1)},[W]);const At=async()=>{var C,q,$;if(!nt){ft(!0);return}if(j(!1),ft(!1),!ht){Tt("remove");try{await(($=(q=(C=window.cicy)==null?void 0:C.localTeams)==null?void 0:q.remove)==null?void 0:$.call(q,o.id))}catch{}Tt(""),m==null||m()}},Ht=`sidecar-op:${o.id}`,Nt=async(C,q,$)=>{var Gt,Oe;if(j(!1),ht)return;Tt(C);const et=C==="update";let Wt=null;et?(hl.open({teamId:o.id,fromVer:Qt,toVer:yt,onRetry:()=>Nt("update",q,$)}),(Oe=(Gt=window.cicy)==null?void 0:Gt.sidecar)!=null&&Oe.onOpProgress&&(Wt=window.cicy.sidecar.onOpProgress(rt=>{(rt==null?void 0:rt.op)==="update"&&hl.push(rt)}))):je.show({id:Ht,message:Ne[C]||`${C}…`,status:"running",progress:void 0});try{const rt=await q(),Ve=!!(rt!=null&&rt.ok),ka=rt!=null&&rt.warning?`${$}(${rt.warning})`:$,Ja=Y("sidecar.failed","操作失败")+(rt!=null&&rt.error?`: ${rt.error}`:"");et?hl.finish({ok:Ve,message:Ve?ka:Ja}):je.show({id:Ht,message:Ve?ka:Ja,progress:void 0,status:Ve?"done":"error",ttl:Ve?4e3:8e3})}catch(rt){const Ve=Y("sidecar.failed","操作失败")+`: ${(rt==null?void 0:rt.message)||rt}`;et?hl.finish({ok:!1,message:Ve}):je.show({id:Ht,message:Ve,progress:void 0,status:"error",ttl:8e3})}finally{try{Wt&&Wt()}catch{}Tt(""),m==null||m(),(C==="update"||C==="restart"||C==="start")&&r(!1)}},Ne={start:"启动中…",restart:"重启中…",update:"更新中…",stop:"停止中…"},Ze=async()=>{var C,q;if(!ht){if(!it&&st&&((q=(C=window.cicy)==null?void 0:C.sidecar)!=null&&q.start)){Tt("start"),je.show({id:Ht,message:Ne.start,status:"running",progress:void 0});const $=await window.cicy.sidecar.start().catch(et=>({ok:!1,error:(et==null?void 0:et.message)||String(et)}));if(Tt(""),m==null||m(),!($!=null&&$.ok)||$!=null&&$.warning){je.show({id:Ht,message:Y("sidecar.startFailed","启动失败")+($!=null&&$.error?`: ${$.error}`:$!=null&&$.warning?`: ${$.warning}`:""),status:"error",ttl:8e3});return}je.dismiss(Ht)}U()}},gl=it?Y("localTeams.open","打开"):st?Y("localTeams.startOpen","启动并打开"):Y("localTeams.open","打开");return s.jsxs("div",{"data-id":"LocalTeamCard",className:`bcard ${st?"bcard--local":"bcard--custom"}${B==="ok"?" bcard--online":""}`,children:[s.jsx("div",{className:"bcard__accent"}),s.jsxs("div",{className:"bcard__top",children:[s.jsxs("div",{className:"bcard__pill",children:[s.jsx("span",{className:"bcard__dot","data-tone":B}),s.jsx(fm,{})]}),Z&&s.jsxs("div",{className:"bcard__menuwrap",ref:pe,onClick:C=>C.stopPropagation(),children:[s.jsx("button",{type:"button",ref:Yt,"data-id":"LocalTeamCard-menu-btn",className:`bcard__kebab${x?" has-dot":""}`,title:st?Y("localTeams.manage","管理本地 cicy-code"):Y("localTeams.more","更多"),disabled:!!ht,onClick:gt,children:ht?s.jsx(yl,{}):s.jsx(om,{})}),W&&Kn.createPortal(s.jsxs("div",{className:"bcard__menu bcard__menu--portal","data-id":"LocalTeamCard-menu",role:"menu",ref:S,style:{position:"fixed",top:R.top,left:R.left,width:xt},onClick:C=>C.stopPropagation(),children:[x&&s.jsxs("button",{type:"button","data-id":"LocalTeamCard-update",className:"bcard__menu-item is-accent",onClick:()=>Nt("update",()=>window.cicy.sidecar.update(),Y("sidecar.updated","已更新到最新")),children:[Y("sidecar.updateTo","更新到")," v",yt]}),st&&it&&s.jsxs(s.Fragment,{children:[s.jsx("button",{type:"button","data-id":"LocalTeamCard-reload",className:"bcard__menu-item",onClick:()=>Nt("reload",async()=>{const C=await window.cicy.localTeams.reload(o.id);return!(C!=null&&C.ok)&&(C==null?void 0:C.error)==="no_open_window"?window.cicy.localTeams.open(o.id):C},Y("localTeams.reloaded","已刷新窗口")),children:Y("localTeams.reloadWindow","刷新窗口")}),s.jsx("button",{type:"button","data-id":"LocalTeamCard-restart",className:"bcard__menu-item",onClick:()=>Nt("restart",()=>window.cicy.sidecar.restart(),Y("sidecar.restarted","已重启")),children:Y("sidecar.restart","重启")}),s.jsx("button",{type:"button","data-id":"LocalTeamCard-stop",className:"bcard__menu-item is-danger",onClick:()=>Nt("stop",()=>window.cicy.sidecar.stop(),Y("sidecar.stoppedDone","已停止")),children:Y("sidecar.stop","停止")})]}),st&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-check-update",className:"bcard__menu-item",disabled:Xt,onClick:C=>{C.stopPropagation(),r(!0)},children:Xt?Y("sidecar.checking2","检查中…"):Y("sidecar.checkUpdate","检查更新")}),o.cloud_team_id&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-billing",className:"bcard__menu-item",onClick:C=>{C.stopPropagation(),j(!1),hi(`?team=${encodeURIComponent(o.cloud_team_id)}`)},children:Y("localTeams.billing","账单")}),H&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-remove",className:"bcard__menu-item is-danger",onClick:At,children:nt?Y("localTeams.removeConfirm","确认删除?"):Y("localTeams.remove","删除")})]}),document.body)]})]}),s.jsxs("div",{className:"bcard__body",children:[P?s.jsx("input",{"data-id":"LocalTeamCard-rename-input",autoFocus:!0,value:z,onChange:C=>b(C.target.value),onFocus:C=>C.target.select(),onBlur:k,onClick:C=>C.stopPropagation(),onKeyDown:C=>{C.nativeEvent.isComposing||C.keyCode===229||(C.key==="Enter"?k():C.key==="Escape"&&at(!1))},style:{width:"100%",font:"inherit",fontWeight:600,padding:"2px 6px",border:"1px solid #3b82f6",borderRadius:6,background:"#0d1117",color:"#e6edf3",boxSizing:"border-box"}}):s.jsxs("h3",{className:"bcard__name",title:Y("localTeams.renameHint","点名字或 ✎ 改名"),style:{display:"flex",alignItems:"center",gap:6},onDoubleClick:L,children:[s.jsx("span",{"data-id":"LocalTeamCard-name-text",onClick:L,style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",cursor:"text"},children:Q}),lt==="saving"&&s.jsx("span",{"data-id":"LocalTeamCard-save-state",title:Y("localTeams.saving","保存中…"),style:{flex:"none",display:"inline-flex"},children:s.jsx(yl,{})}),lt==="saved"&&s.jsx("span",{"data-id":"LocalTeamCard-save-state",title:Y("localTeams.saved","已保存"),style:{flex:"none",color:"#3fb950",fontSize:13,lineHeight:1},children:"✓"}),!lt&&s.jsx("button",{type:"button","data-id":"LocalTeamCard-rename-btn",title:Y("localTeams.rename","重命名"),onClick:L,style:{flex:"none",cursor:"pointer",border:"none",background:"transparent",color:"#8b949e",fontSize:13,padding:0,lineHeight:1},children:"✎"})]}),s.jsx("div",{className:"bcard__host",children:o.base_url||"—"}),s.jsx("div",{className:"bcard__meta",children:(Qt||o.version)&&s.jsxs("span",{className:"bcard__ver","data-id":"LocalTeamCard-version",children:["v",Qt||o.version]})})]}),s.jsxs("button",{type:"button",className:"bcard__cta","data-id":"LocalTeamCard-open",disabled:!!ht||!o.base_url,onClick:Ze,children:[ht&&ht!=="stop"?s.jsx(yl,{}):s.jsx(Ys,{}),s.jsx("span",{children:ht&&Ne[ht]||gl})]})]})}function Bs(o){try{const U=new URL(o);return(U.hostname==="127.0.0.1"||U.hostname==="localhost"||U.hostname==="::1")&&(U.port==="8008"||U.port==="")}catch{return!1}}function tm(o,U){const E=String(o).split("."),m=String(U).split(".");for(let O=0;O<Math.max(E.length,m.length);O++){const B=(parseInt(E[O],10)||0)-(parseInt(m[O],10)||0);if(B)return B>0?1:-1}return 0}const em={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 Jy({team:o,onOpen:U}){const E=o.kind==="private",m=o.status==="active",O=o.name||o.title||"—",B=o.host_url||"",P=o.teamId||o.id,at=E?"私有云":o.team_kind==="personal"?"个人":"共享",z=E?B:o.workspace_url||o.workspace_direct_url,b=!!z,[X,w]=N.useState(!1),[lt,K]=N.useState(!1),[Q,L]=N.useState({top:0,left:0}),k=N.useRef(null),ct=N.useRef(null),st=N.useRef(null),it=184,ht=()=>{if(!X&&ct.current){const W=ct.current.getBoundingClientRect(),j=Math.max(8,Math.min(W.right-it,window.innerWidth-it-8));L({top:Math.round(W.bottom+4),left:Math.round(j)})}w(W=>!W)};N.useEffect(()=>{if(!X)return;const W=j=>{var bt,M;(bt=ct.current)!=null&&bt.contains(j.target)||(M=st.current)!=null&&M.contains(j.target)||w(!1)};return document.addEventListener("mousedown",W),()=>document.removeEventListener("mousedown",W)},[X]);const Tt=async()=>{var W,j,bt;if(!(!b||lt)){K(!0),w(!1);try{await((bt=(j=(W=window.cicy)==null?void 0:W.tabs)==null?void 0:j.reload)==null?void 0:bt.call(j,z,O))}catch{}finally{K(!1)}}};return s.jsxs("div",{"data-id":"TeamCard",className:`bcard bcard--cloud${m?" bcard--online":""}`,children:[s.jsx("div",{className:"bcard__accent"}),s.jsxs("div",{className:"bcard__top",children:[s.jsxs("div",{className:"bcard__pill",children:[s.jsx("span",{className:"bcard__dot","data-tone":m?"ok":"off"}),s.jsx(Wy,{})]}),s.jsxs("div",{className:"bcard__top-right",children:[o.is_trial&&s.jsx("span",{className:"bcard__badge",children:"trial"}),P!=null&&s.jsx("button",{type:"button","data-id":"TeamCard-billing",className:"bcard__billing-btn",title:Y("localTeams.billing","账单"),onClick:W=>{W.stopPropagation(),hi(`?team=${encodeURIComponent(P)}`)},children:Y("localTeams.billing","账单")}),b&&s.jsxs("div",{className:"bcard__menuwrap",ref:k,onClick:W=>W.stopPropagation(),children:[s.jsx("button",{type:"button",ref:ct,"data-id":"TeamCard-menu-btn",className:"bcard__kebab",title:Y("localTeams.more","更多"),disabled:lt,onClick:ht,children:lt?s.jsx(yl,{}):s.jsx(om,{})}),X&&Kn.createPortal(s.jsx("div",{className:"bcard__menu bcard__menu--portal","data-id":"TeamCard-menu",role:"menu",ref:st,style:{position:"fixed",top:Q.top,left:Q.left,width:it},onClick:W=>W.stopPropagation(),children:s.jsx("button",{type:"button","data-id":"TeamCard-reload",className:"bcard__menu-item",onClick:Tt,children:Y("localTeams.reloadWindow","刷新窗口")})}),document.body)]})]})]}),s.jsxs("div",{className:"bcard__body",children:[s.jsx("h3",{className:"bcard__name",title:O,children:O}),s.jsx("div",{className:"bcard__host",title:E&&B||"",children:E?B||Y("teamCard.noHost","未填访问地址"):o.runtime_region||o.region||"—"}),s.jsxs("div",{className:"bcard__meta",children:[s.jsx("span",{className:"bcard__chip",children:at}),!E&&o.membership_status&&o.membership_status!=="active"&&s.jsx("span",{className:"bcard__chip",children:o.membership_status})]})]}),s.jsxs("button",{type:"button",className:"bcard__cta",onClick:U,disabled:!b,children:[s.jsx(Ys,{}),s.jsx("span",{children:b?Y("localTeams.open","打开"):E?Y("teamCard.noHost","未填访问地址"):Y("teamCard.noUrl","无 URL")})]})]})}function Us(){return s.jsxs("div",{className:"brand",children:[s.jsx("div",{className:"brand-mark",children:s.jsx(sm,{})}),s.jsxs("div",{className:"brand-text",children:[s.jsx("div",{className:"brand-name",children:"CiCy Desktop"}),s.jsx("div",{className:"brand-sub",children:"团队 AI 协作工作台"})]})]})}function sm(){return s.jsx("svg",{width:"22",height:"22",viewBox:"0 0 96 96",fill:"none",children:s.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 Ys(){return s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("line",{x1:"5",y1:"12",x2:"19",y2:"12"}),s.jsx("polyline",{points:"12 5 19 12 12 19"})]})}function yl(){return s.jsx("svg",{className:"spin",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.4",strokeLinecap:"round",children:s.jsx("path",{d:"M21 12a9 9 0 1 1-6.2-8.55"})})}function fm(){return s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"4",width:"18",height:"12",rx:"2"}),s.jsx("line",{x1:"2",y1:"20",x2:"22",y2:"20"})]})}function om(){return s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:[s.jsx("circle",{cx:"12",cy:"5",r:"1.7"}),s.jsx("circle",{cx:"12",cy:"12",r:"1.7"}),s.jsx("circle",{cx:"12",cy:"19",r:"1.7"})]})}function Wy(){return s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("circle",{cx:"12",cy:"12",r:"10"}),s.jsx("line",{x1:"2",y1:"12",x2:"22",y2:"12"}),s.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 Vn(o){try{return localStorage.getItem(o)||null}catch{return null}}function lm(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 am;const $y=((am=window.cicy)==null?void 0:am.platform)||(()=>{const o=navigator.userAgent||"";return/Mac/i.test(o)?"darwin":/Windows/i.test(o)?"win32":"linux"})();document.documentElement.dataset.platform=$y;document.documentElement.dataset.fullscreen="0";var nm,um;(um=(nm=window.cicy)==null?void 0:nm.window)!=null&&um.onFullscreen&&window.cicy.window.onFullscreen(o=>{document.documentElement.dataset.fullscreen=o?"1":"0"});qy.createRoot(document.getElementById("root")).render(s.jsx(Qy,{}));
|
|
@@ -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-xHkT3-tl.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="./assets/index-CKpaMBKz.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
package/src/main.js
CHANGED
|
@@ -1048,6 +1048,19 @@ electronApp.whenReady().then(async () => {
|
|
|
1048
1048
|
} catch (e) { log.warn(`[thumbs] start failed: ${e.message}`); }
|
|
1049
1049
|
}
|
|
1050
1050
|
|
|
1051
|
+
// Periodic WHOLE-desktop snapshot → ~/cicy-files/desktop-snapshot/desktop.b64
|
|
1052
|
+
// (≤600px wide JPEG). WINDOWS ONLY: the cloud (cicy-code) live-captures mac/
|
|
1053
|
+
// linux via the OS grabber, but on Windows live PowerShell capture fails under
|
|
1054
|
+
// 360/AppLocker/RDP, so there it reads this file instead. The capture runs in a
|
|
1055
|
+
// --disable-gpu child electron (GDI path, works over RDP; main app GPU intact).
|
|
1056
|
+
if (process.platform === "win32" && !global.__cicyDesktopSnapStarted) {
|
|
1057
|
+
global.__cicyDesktopSnapStarted = true;
|
|
1058
|
+
try {
|
|
1059
|
+
const info = require("./utils/desktop-snapshot").startDesktopSnapshots();
|
|
1060
|
+
log.info(`[desktop-snap] desktop snapshots → ${info.dir} (every ${info.intervalMs}ms, maxW ${info.maxWidth})`);
|
|
1061
|
+
} catch (e) { log.warn(`[desktop-snap] start failed: ${e.message}`); }
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1051
1064
|
// Local-team discovery — reads ~/cicy-ai/global.json's cicyDesktopNodes
|
|
1052
1065
|
// and probes each via /api/health. Pure local, never talks to the cloud
|
|
1053
1066
|
// and never runs docker shells.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// desktop-snapshot.js
|
|
2
|
+
// Periodically captures the WHOLE desktop (not a window) to disk so the cloud
|
|
3
|
+
// (cicy-code) can fetch a recent screen preview by just reading a file — no live
|
|
4
|
+
// per-request capture. Fixes Windows, where the old on-demand path (server →
|
|
5
|
+
// exec_shell → PowerShell CopyFromScreen) returns empty under AppLocker / a
|
|
6
|
+
// display-less RDP session.
|
|
7
|
+
//
|
|
8
|
+
// Output (<dir> = ~/cicy-files/desktop-snapshot, override CICY_DESKTOP_SNAP_DIR):
|
|
9
|
+
// <dir>/desktop.jpg the image (≤600px wide JPEG)
|
|
10
|
+
// <dir>/desktop.b64 its base64 text ← the cloud reads THIS (cat / type)
|
|
11
|
+
//
|
|
12
|
+
// Capture per platform (all from inside the user's session):
|
|
13
|
+
// darwin → `screencapture -x -t jpg` (in-process)
|
|
14
|
+
// linux → scrot / ImageMagick import (in-process)
|
|
15
|
+
// win32 → Electron desktopCapturer, but run in a SEPARATE `--disable-gpu`
|
|
16
|
+
// child electron: an RDP session has no DXGI desktop-duplication, so
|
|
17
|
+
// the in-process (GPU) capturer fails ("Duplication failed"); the GDI
|
|
18
|
+
// path needs --disable-gpu. We isolate that to a child daemon so the
|
|
19
|
+
// MAIN app keeps hardware acceleration. (主人令: 不禁用主 app 的 GPU。)
|
|
20
|
+
|
|
21
|
+
const fs = require("fs");
|
|
22
|
+
const path = require("path");
|
|
23
|
+
const os = require("os");
|
|
24
|
+
const { execFileSync, spawn } = require("child_process");
|
|
25
|
+
const electron = require("electron");
|
|
26
|
+
|
|
27
|
+
const MAX_W = 600; // 主人令: 压到 600 以下宽度
|
|
28
|
+
const QUALITY = 60;
|
|
29
|
+
const DEFAULT_INTERVAL_MS = 8000;
|
|
30
|
+
|
|
31
|
+
function snapDir() {
|
|
32
|
+
const fromEnv = (process.env.CICY_DESKTOP_SNAP_DIR || "").trim();
|
|
33
|
+
return fromEnv || path.join(os.homedir(), "cicy-files", "desktop-snapshot");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function intervalMs(opt) {
|
|
37
|
+
const fromEnv = parseInt(process.env.CICY_DESKTOP_SNAP_INTERVAL_MS || "", 10);
|
|
38
|
+
return (opt && opt.intervalMs) || (fromEnv > 0 ? fromEnv : DEFAULT_INTERVAL_MS);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Grab the primary screen as a NativeImage. win32 uses desktopCapturer (only
|
|
42
|
+
// valid when GPU is off → run from the --disable-gpu daemon); mac/linux shell out.
|
|
43
|
+
async function grabScreenImage() {
|
|
44
|
+
const { desktopCapturer, screen, nativeImage } = electron;
|
|
45
|
+
if (process.platform === "win32") {
|
|
46
|
+
const d = screen.getPrimaryDisplay();
|
|
47
|
+
const sf = d.scaleFactor || 1;
|
|
48
|
+
const w = Math.max(1, Math.round(d.size.width * sf));
|
|
49
|
+
const h = Math.max(1, Math.round(d.size.height * sf));
|
|
50
|
+
const sources = await desktopCapturer.getSources({
|
|
51
|
+
types: ["screen"],
|
|
52
|
+
thumbnailSize: { width: w, height: h },
|
|
53
|
+
});
|
|
54
|
+
if (!sources.length) throw new Error("no screen source");
|
|
55
|
+
let img = sources[0].thumbnail;
|
|
56
|
+
for (const s of sources) { if (!s.thumbnail.isEmpty()) { img = s.thumbnail; break; } }
|
|
57
|
+
if (img.isEmpty()) throw new Error("empty screen capture (no display?)");
|
|
58
|
+
return img;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const tmp = path.join(os.tmpdir(), `cicy_desktop_snap_${process.pid}.jpg`);
|
|
62
|
+
try { fs.unlinkSync(tmp); } catch (_) {}
|
|
63
|
+
if (process.platform === "darwin") {
|
|
64
|
+
execFileSync("/usr/sbin/screencapture", ["-x", "-t", "jpg", tmp], { stdio: "ignore" });
|
|
65
|
+
} else {
|
|
66
|
+
const env = { ...process.env, DISPLAY: process.env.DISPLAY || ":0" };
|
|
67
|
+
try { execFileSync("scrot", ["-o", tmp], { stdio: "ignore", env }); }
|
|
68
|
+
catch (_) { execFileSync("import", ["-window", "root", tmp], { stdio: "ignore", env }); }
|
|
69
|
+
}
|
|
70
|
+
const buf = fs.readFileSync(tmp);
|
|
71
|
+
try { fs.unlinkSync(tmp); } catch (_) {}
|
|
72
|
+
const img = electron.nativeImage.createFromBuffer(buf);
|
|
73
|
+
if (img.isEmpty()) throw new Error("empty native capture");
|
|
74
|
+
return img;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function captureOnce() {
|
|
78
|
+
const dir = snapDir();
|
|
79
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
80
|
+
let img = await grabScreenImage();
|
|
81
|
+
if (img.getSize().width > MAX_W) {
|
|
82
|
+
img = img.resize({ width: MAX_W, quality: "good" }); // width-only → keeps aspect
|
|
83
|
+
}
|
|
84
|
+
const jpeg = img.toJPEG(QUALITY);
|
|
85
|
+
if (!jpeg || jpeg.length < 256) throw new Error("encoded jpeg too small");
|
|
86
|
+
fs.writeFileSync(path.join(dir, "desktop.jpg"), jpeg);
|
|
87
|
+
const b64Path = path.join(dir, "desktop.b64");
|
|
88
|
+
const tmpB64 = b64Path + ".tmp";
|
|
89
|
+
fs.writeFileSync(tmpB64, jpeg.toString("base64"));
|
|
90
|
+
fs.renameSync(tmpB64, b64Path); // atomic swap so readers never see a partial file
|
|
91
|
+
const o = img.getSize();
|
|
92
|
+
return { dir, w: o.width, h: o.height, bytes: jpeg.length };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── parent (started from main.js) ─────────────────────────────────────────────
|
|
96
|
+
let child = null;
|
|
97
|
+
let timer = null;
|
|
98
|
+
let kickTimer = null;
|
|
99
|
+
let running = false;
|
|
100
|
+
|
|
101
|
+
async function tick() {
|
|
102
|
+
if (running) return;
|
|
103
|
+
running = true;
|
|
104
|
+
try { await captureOnce(); } catch (_) { /* keep last good file */ }
|
|
105
|
+
finally { running = false; }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function startDesktopSnapshots(options = {}) {
|
|
109
|
+
const ms = intervalMs(options);
|
|
110
|
+
stopDesktopSnapshots();
|
|
111
|
+
|
|
112
|
+
if (process.platform === "win32") {
|
|
113
|
+
// Spawn ONE persistent --disable-gpu child electron that runs this file as a
|
|
114
|
+
// capture daemon (GDI path, works over RDP). Main app's GPU is untouched.
|
|
115
|
+
const dir = snapDir();
|
|
116
|
+
try { fs.mkdirSync(dir, { recursive: true }); } catch (_) {}
|
|
117
|
+
let stdio = "ignore";
|
|
118
|
+
let logFd = null;
|
|
119
|
+
try { logFd = fs.openSync(path.join(dir, "daemon.log"), "a"); stdio = ["ignore", logFd, logFd]; } catch (_) {}
|
|
120
|
+
child = spawn(process.execPath, ["--disable-gpu", "--disable-logging", __filename], {
|
|
121
|
+
env: { ...process.env, CICY_SNAP_DAEMON: "1", CICY_DESKTOP_SNAP_INTERVAL_MS: String(ms) },
|
|
122
|
+
stdio,
|
|
123
|
+
windowsHide: true,
|
|
124
|
+
});
|
|
125
|
+
child.on("exit", () => { child = null; });
|
|
126
|
+
return { dir, intervalMs: ms, maxWidth: MAX_W, mode: "win-daemon", execPath: process.execPath };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// mac / linux: in-process native capture loop (no GPU concern).
|
|
130
|
+
const kick = () => { tick().catch(() => {}); };
|
|
131
|
+
timer = setInterval(kick, ms);
|
|
132
|
+
if (timer.unref) timer.unref();
|
|
133
|
+
kickTimer = setTimeout(kick, 2500);
|
|
134
|
+
if (kickTimer.unref) kickTimer.unref();
|
|
135
|
+
return { dir: snapDir(), intervalMs: ms, maxWidth: MAX_W, mode: "inproc" };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function stopDesktopSnapshots() {
|
|
139
|
+
if (timer) { clearInterval(timer); timer = null; }
|
|
140
|
+
if (kickTimer) { clearTimeout(kickTimer); kickTimer = null; }
|
|
141
|
+
if (child) { try { child.kill(); } catch (_) {} child = null; }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── daemon mode ───────────────────────────────────────────────────────────────
|
|
145
|
+
// Entered when this file is the entry of `electron --disable-gpu
|
|
146
|
+
// desktop-snapshot.js` (Windows capture child). Detected purely via the env flag
|
|
147
|
+
// the parent sets — NOT require.main, which is `undefined` in Electron's main
|
|
148
|
+
// process. The main worker requires this module WITHOUT that env, so it's skipped
|
|
149
|
+
// there.
|
|
150
|
+
if (process.env.CICY_SNAP_DAEMON === "1") {
|
|
151
|
+
const { app } = electron;
|
|
152
|
+
try { app.disableHardwareAcceleration(); } catch (_) {}
|
|
153
|
+
let firstOk = true;
|
|
154
|
+
let lastErr = "";
|
|
155
|
+
const once = async () => {
|
|
156
|
+
try {
|
|
157
|
+
const r = await captureOnce();
|
|
158
|
+
if (firstOk) { firstOk = false; console.error("[snap-daemon] capturing → " + JSON.stringify(r)); }
|
|
159
|
+
} catch (e) {
|
|
160
|
+
const msg = (e && e.message) || String(e);
|
|
161
|
+
if (msg !== lastErr) { lastErr = msg; console.error("[snap-daemon] ERR " + msg); } // dedupe spam
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
console.error("[snap-daemon] booting, dir=" + snapDir());
|
|
165
|
+
app.whenReady().then(() => {
|
|
166
|
+
once();
|
|
167
|
+
const t = setInterval(once, intervalMs());
|
|
168
|
+
if (t.unref) t.unref();
|
|
169
|
+
});
|
|
170
|
+
// No window is ever created; the interval keeps the process alive. Quit if the
|
|
171
|
+
// GPU/renderer dies so we don't linger as a zombie.
|
|
172
|
+
app.on("render-process-gone", () => app.quit());
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
module.exports = { startDesktopSnapshots, stopDesktopSnapshots, snapDir, captureOnce };
|
|
@@ -1729,7 +1729,7 @@ function LocalTeamCard({ team, onOpen, onRename, onRefresh }) {
|
|
|
1729
1729
|
onFocus={(e) => e.target.select()}
|
|
1730
1730
|
onBlur={commit}
|
|
1731
1731
|
onClick={(e) => e.stopPropagation()}
|
|
1732
|
-
onKeyDown={(e) => { if (e.key === "Enter") commit(); else if (e.key === "Escape") setEditing(false); }}
|
|
1732
|
+
onKeyDown={(e) => { if (e.nativeEvent.isComposing || e.keyCode === 229) return; if (e.key === "Enter") commit(); else if (e.key === "Escape") setEditing(false); }}
|
|
1733
1733
|
style={{ width: "100%", font: "inherit", fontWeight: 600, padding: "2px 6px", border: "1px solid #3b82f6", borderRadius: 6, background: "#0d1117", color: "#e6edf3", boxSizing: "border-box" }}
|
|
1734
1734
|
/>
|
|
1735
1735
|
) : (
|