@fudrouter/fsrouter 0.6.73 → 0.6.75

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.
Files changed (52) hide show
  1. package/dist/lib/headroom/detect.js +97 -7
  2. package/dist/lib/headroom/process.js +136 -4
  3. package/dist/routes/headroom/extras/route.js +58 -0
  4. package/dist/routes/headroom/restart/route.js +33 -0
  5. package/package.json +1 -1
  6. package/public/assets/EndpointPageClient.BnlQVTIB.js +6 -0
  7. package/public/assets/{Loading.Bj-WGl4k.js → Loading.C1il44u0.js} +1 -1
  8. package/public/assets/{NoAuthProxyCard.qAv57b-0.js → NoAuthProxyCard.WHGGEUIp.js} +1 -1
  9. package/public/assets/index.COMgQZYj.css +1 -0
  10. package/public/assets/index.D4FwOBBU.js +89 -0
  11. package/public/assets/{page.Qkkv8roc.js → page.0Rt4rWPG.js} +1 -1
  12. package/public/assets/{page.Dx_GRRdT.js → page.1numFcXc.js} +1 -1
  13. package/public/assets/{page.vla5Mzki.js → page.1w9bTOPd.js} +1 -1
  14. package/public/assets/{page.CzlQTyAL.js → page.3ARdH6tE.js} +1 -1
  15. package/public/assets/{page.sOFOrxqq.js → page.A4gD6oiw.js} +1 -1
  16. package/public/assets/{page.D5gj98Oe.js → page.AhxgKhsm.js} +1 -1
  17. package/public/assets/{page.DUI8kqOY.js → page.B1og8_GD.js} +1 -1
  18. package/public/assets/{page.CssmrzTT.js → page.B5nk3H0f.js} +1 -1
  19. package/public/assets/{page.DX4Nno6M.js → page.BGDrqCcI.js} +1 -1
  20. package/public/assets/{page.DzZLqI5Q.js → page.BJIIZWfZ.js} +1 -1
  21. package/public/assets/{page.BdmJ3yY3.js → page.BdB6udZG.js} +1 -1
  22. package/public/assets/{page.Ir7KvKcF.js → page.BfGkHTDS.js} +1 -1
  23. package/public/assets/{page.CPZav1_c.js → page.Bfr4417O.js} +1 -1
  24. package/public/assets/{page.ChX1NqmC.js → page.BpcyRUKz.js} +1 -1
  25. package/public/assets/{page.O2ddJYoT.js → page.BvcbHe5b.js} +1 -1
  26. package/public/assets/{page.C72FTTJr.js → page.C6WsIDgW.js} +1 -1
  27. package/public/assets/{page.Dh5f0XJC.js → page.CCEJ5tPH.js} +1 -1
  28. package/public/assets/{page.DxMDTbSx.js → page.CMUifPIU.js} +1 -1
  29. package/public/assets/{page.1qjqvrwX.js → page.CR7Yees9.js} +1 -1
  30. package/public/assets/{page.CsxWmPoI.js → page.CXCEdPh6.js} +1 -1
  31. package/public/assets/{page.DPyOkPVo.js → page.CsroRewc.js} +1 -1
  32. package/public/assets/{page.CQlVGoXg.js → page.CtLa-V_T.js} +1 -1
  33. package/public/assets/{page.BnmTC5jG.js → page.DINPUA6N.js} +1 -1
  34. package/public/assets/page.DSEK9UW0.js +1 -0
  35. package/public/assets/{page.i4KDuWcM.js → page.DSTzvOQ8.js} +1 -1
  36. package/public/assets/{page.CSs3-gdt.js → page.DT7cpJ8d.js} +1 -1
  37. package/public/assets/{page.DVIHRbxB.js → page.DT_RnrSs.js} +1 -1
  38. package/public/assets/{page.Cj5h09Zo.js → page.DU7jwIPk.js} +1 -1
  39. package/public/assets/{page.DBhu4Arl.js → page.DcmbyZGV.js} +1 -1
  40. package/public/assets/{page.CbkENBd5.js → page.DjguJpCk.js} +1 -1
  41. package/public/assets/{page.CnTop8Zt.js → page.Dr6yAoTO.js} +1 -1
  42. package/public/assets/{page.CXd_R9yU.js → page.FR_Izkgi.js} +1 -1
  43. package/public/assets/{page.BSLJ4tx5.js → page.GhgvWftU.js} +1 -1
  44. package/public/assets/{page.BbO1pspY.js → page.UoGOSKkx.js} +1 -1
  45. package/public/assets/page.cAR8tR7Z.js +1 -0
  46. package/public/assets/{page.DibhF7f-.js → page.feKgaG20.js} +1 -1
  47. package/public/assets/{page.D1oKew1j.js → page.t4nKFefI.js} +1 -1
  48. package/public/index.html +2 -2
  49. package/public/assets/EndpointPageClient.LyNNvZ4z.js +0 -6
  50. package/public/assets/index.BuPfZebu.css +0 -1
  51. package/public/assets/index.CShjRV_B.js +0 -89
  52. package/public/assets/page.DD_czjjP.js +0 -1
@@ -1 +1 @@
1
- import{j as e}from"./index.CShjRV_B.js";import{b as n}from"./router.Cjj1--8t.js";import"./zustand.akaTi5uX.js";function j(){const[o,p]=n.useState("tts"),[x,h]=n.useState(""),[t,s]=n.useState(null),[i,r]=n.useState(!1),u=async()=>{r(!0);try{const a=await fetch("/api/audio/speech",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:x,model:"tts-1",voice:"alloy"})});if(a.ok){const c=await a.blob();s({audio:URL.createObjectURL(c)})}else s({error:await a.text()})}catch(a){s({error:a.message})}r(!1)},m=async a=>{const c=a.target.files[0];if(!c)return;r(!0);const l=new FormData;l.append("file",c),l.append("model","whisper-1");try{const d=await fetch("/api/audio/transcriptions",{method:"POST",body:l});s(await d.json())}catch(d){s({error:d.message})}r(!1)};return e.jsxs("div",{className:"space-y-6 p-6",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Audio"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:()=>p("tts"),className:`px-4 py-2 rounded-lg ${o==="tts"?"bg-primary text-white":"bg-black/5"}`,children:"Text to Speech"}),e.jsx("button",{onClick:()=>p("stt"),className:`px-4 py-2 rounded-lg ${o==="stt"?"bg-primary text-white":"bg-black/5"}`,children:"Speech to Text"})]}),o==="tts"&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("textarea",{className:"w-full p-3 rounded-lg border h-40",placeholder:"Enter text to convert to speech...",value:x,onChange:a=>h(a.target.value)}),e.jsx("button",{onClick:u,disabled:i,className:"px-4 py-2 bg-primary text-white rounded-lg",children:i?"Generating...":"Generate Speech"}),(t==null?void 0:t.audio)&&e.jsx("audio",{controls:!0,src:t.audio,className:"w-full"})]}),o==="stt"&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("input",{type:"file",accept:"audio/*",onChange:m,className:"block"}),i&&e.jsx("p",{children:"Transcribing..."})]}),(t==null?void 0:t.error)&&e.jsx("p",{className:"text-red-500",children:t.error}),(t==null?void 0:t.text)&&e.jsx("pre",{className:"p-4 bg-black/5 rounded-lg text-sm",children:t.text})]})}export{j as default};
1
+ import{j as e}from"./index.D4FwOBBU.js";import{b as n}from"./router.Cjj1--8t.js";import"./zustand.akaTi5uX.js";function j(){const[o,p]=n.useState("tts"),[x,h]=n.useState(""),[t,s]=n.useState(null),[i,r]=n.useState(!1),u=async()=>{r(!0);try{const a=await fetch("/api/audio/speech",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:x,model:"tts-1",voice:"alloy"})});if(a.ok){const c=await a.blob();s({audio:URL.createObjectURL(c)})}else s({error:await a.text()})}catch(a){s({error:a.message})}r(!1)},m=async a=>{const c=a.target.files[0];if(!c)return;r(!0);const l=new FormData;l.append("file",c),l.append("model","whisper-1");try{const d=await fetch("/api/audio/transcriptions",{method:"POST",body:l});s(await d.json())}catch(d){s({error:d.message})}r(!1)};return e.jsxs("div",{className:"space-y-6 p-6",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Audio"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:()=>p("tts"),className:`px-4 py-2 rounded-lg ${o==="tts"?"bg-primary text-white":"bg-black/5"}`,children:"Text to Speech"}),e.jsx("button",{onClick:()=>p("stt"),className:`px-4 py-2 rounded-lg ${o==="stt"?"bg-primary text-white":"bg-black/5"}`,children:"Speech to Text"})]}),o==="tts"&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("textarea",{className:"w-full p-3 rounded-lg border h-40",placeholder:"Enter text to convert to speech...",value:x,onChange:a=>h(a.target.value)}),e.jsx("button",{onClick:u,disabled:i,className:"px-4 py-2 bg-primary text-white rounded-lg",children:i?"Generating...":"Generate Speech"}),(t==null?void 0:t.audio)&&e.jsx("audio",{controls:!0,src:t.audio,className:"w-full"})]}),o==="stt"&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("input",{type:"file",accept:"audio/*",onChange:m,className:"block"}),i&&e.jsx("p",{children:"Transcribing..."})]}),(t==null?void 0:t.error)&&e.jsx("p",{className:"text-red-500",children:t.error}),(t==null?void 0:t.text)&&e.jsx("pre",{className:"p-4 bg-black/5 rounded-lg text-sm",children:t.text})]})}export{j as default};
@@ -1,2 +1,2 @@
1
1
  const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index.1VBQU7rF.js","assets/router.Cjj1--8t.js"])))=>i.map(i=>d[i]);
2
- import{u as z,j as t,B as c,_ as F}from"./index.CShjRV_B.js";import{b as x}from"./router.Cjj1--8t.js";import{C as $}from"./NoAuthProxyCard.qAv57b-0.js";import"./zustand.akaTi5uX.js";const B=x.lazy(()=>F(()=>import("./index.1VBQU7rF.js"),__vite__mapDeps([0,1]))),v=[{id:1,label:"Client Request",file:"1_req_client.json",lang:"json",desc:"Raw request from client"},{id:2,label:"Source Body",file:"2_req_source.json",lang:"json",desc:"After initial conversion"},{id:3,label:"OpenAI Intermediate",file:"3_req_openai.json",lang:"json",desc:"source → openai"},{id:4,label:"Target Request",file:"4_req_target.json",lang:"json",desc:"openai → target + URL + headers"},{id:5,label:"Provider Response",file:"5_res_provider.txt",lang:"text",desc:"Raw SSE from provider"},{id:6,label:"OpenAI Response",file:"6_res_openai.txt",lang:"text",desc:"target → openai (response)"},{id:7,label:"Client Response",file:"7_res_client.txt",lang:"text",desc:"Final response to client"}],I={minimap:{enabled:!1},fontSize:12,lineNumbers:"on",scrollBeyondLastLine:!1,wordWrap:"on",automaticLayout:!0};function W(){const[i,h]=x.useState({}),[g,u]=x.useState({1:!0}),[p,S]=x.useState({}),[o,w]=x.useState(null),l=(e,s)=>S(a=>({...a,[e]:s})),d=(e,s)=>h(a=>({...a,[e]:s})),O=e=>u(s=>({...s,[e]:!s[e]})),j=e=>u(s=>{const a={};return v.forEach(n=>{a[n.id]=!1}),a[e]=!0,a}),_=async e=>{const s=v.find(a=>a.id===e);l(`load-${e}`,!0);try{const n=await(await fetch(`/api/translator/load?file=${s.file}`)).json();n.success?(d(e,n.content),e===1&&await N(n.content)):alert(n.error||"File not found")}catch(a){alert(a.message)}l(`load-${e}`,!1)},N=async e=>{try{const s=typeof e=="string"?JSON.parse(e):e,n=await(await fetch("/api/translator/translate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({step:1,body:s})})).json();n.success&&w(n.result)}catch{}},f=(e,s)=>fetch("/api/translator/save",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({file:e,content:s})}).catch(()=>{}),T=async()=>{l("toOpenAI",!0);try{const e=i[1],s=JSON.parse(e);f("1_req_client.json",e),f("2_req_source.json",JSON.stringify({timestamp:new Date().toISOString(),headers:{},body:s.body||s},null,2));const n=await(await fetch("/api/translator/translate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({step:2,body:s})})).json();if(!n.success){alert(n.error);return}const r=JSON.stringify(n.result.body,null,2);d(3,r),j(3)}catch(e){alert(e.message)}l("toOpenAI",!1)},C=async()=>{l("toTarget",!0);try{const e=i[3],s=JSON.parse(e);f("3_req_openai.json",e);const n=await(await fetch("/api/translator/translate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({step:3,body:{...s,provider:o==null?void 0:o.provider,model:o==null?void 0:o.model}})})).json();if(!n.success){alert(n.error);return}const r={...n.result,provider:o==null?void 0:o.provider,model:o==null?void 0:o.model};d(4,JSON.stringify(r,null,2)),j(4)}catch(e){alert(e.message)}l("toTarget",!1)},J=async()=>{l("send",!0);try{const e=i[4],s=JSON.parse(e);f("4_req_target.json",e);const a=s.provider||(o==null?void 0:o.provider),n=s.model||(o==null?void 0:o.model);if(!a||!n){alert("Missing provider or model. Please run step 1 first to detect them.");return}const r=await fetch("/api/translator/send",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:a,model:n,body:s.body||s})});if(!r.ok){const b=await r.json().catch(()=>({error:r.statusText}));alert(b.error||"Send failed");return}const E=r.body.getReader(),A=new TextDecoder;let y="";for(;;){const{done:b,value:L}=await E.read();if(b)break;y+=A.decode(L,{stream:!0})}d(5,y),j(5),await fetch("/api/translator/save",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({file:"5_res_provider.txt",content:y})})}catch(e){alert(e.message)}finally{l("send",!1)}},{copy:P}=z(),R=async e=>{i[e]&&P(i[e],`translator-step-${e}`)},k=e=>{try{const s=JSON.parse(i[e]);d(e,JSON.stringify(s,null,2))}catch{}},q=e=>e===1?t.jsx(c,{size:"sm",icon:"arrow_forward",loading:p.toOpenAI,onClick:T,children:"→ OpenAI"}):e===3?t.jsx(c,{size:"sm",icon:"arrow_forward",loading:p.toTarget,onClick:C,children:"→ Target"}):e===4?t.jsx(c,{size:"sm",icon:"send",loading:p.send,onClick:J,children:"Send"}):null;return t.jsxs("div",{className:"p-8 space-y-3",children:[t.jsxs("div",{className:"flex items-center justify-between mb-2",children:[t.jsxs("div",{children:[t.jsx("h1",{className:"text-2xl font-bold text-text-main",children:"Translator Debug"}),t.jsx("p",{className:"text-sm text-text-muted mt-1",children:"Replay request flow — matches log files"})]}),o&&t.jsxs("div",{className:"flex items-center gap-2 flex-wrap justify-end",children:[t.jsx(m,{label:"src",value:o.sourceFormat,color:"blue"}),t.jsx("span",{className:"material-symbols-outlined text-text-muted text-[14px]",children:"arrow_forward"}),t.jsx(m,{label:"dst",value:o.targetFormat,color:"orange"}),t.jsx(m,{label:"provider",value:o.provider,color:"green"}),t.jsx(m,{label:"model",value:o.model,color:"purple"})]})]}),v.map(e=>{const s=q(e.id),a=!!g[e.id],n=i[e.id]||"";return t.jsx($,{children:t.jsxs("div",{className:"p-4 space-y-3",children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsxs("button",{onClick:()=>O(e.id),className:"flex items-center gap-2 flex-1 text-left group",children:[t.jsx("span",{className:"material-symbols-outlined text-[20px] text-text-muted group-hover:text-primary transition-colors",children:a?"expand_more":"chevron_right"}),t.jsx("span",{className:"text-xs font-mono text-text-muted/60 w-4",children:e.id}),t.jsx("h3",{className:"text-sm font-semibold text-text-main",children:e.label}),t.jsx("span",{className:"text-xs text-text-muted/60 font-mono",children:e.file}),n&&t.jsxs("span",{className:"text-xs text-green-500",children:["(",n.length," chars)"]})]}),!a&&t.jsxs("div",{className:"flex gap-1 shrink-0",children:[t.jsx(c,{size:"sm",variant:"ghost",icon:"folder_open",loading:p[`load-${e.id}`],onClick:()=>_(e.id)}),s]})]}),a&&t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"border border-border rounded-lg overflow-hidden",children:t.jsx(B,{height:"400px",defaultLanguage:e.lang==="text"?"plaintext":"json",value:n,onChange:r=>{d(e.id,r||""),e.id===1&&N(r||"")},theme:"vs-dark",options:I})}),t.jsxs("div",{className:"flex gap-2 flex-wrap",children:[t.jsx(c,{size:"sm",variant:"outline",icon:"folder_open",loading:p[`load-${e.id}`],onClick:()=>_(e.id),children:"Load"}),t.jsx(c,{size:"sm",variant:"outline",icon:"data_object",onClick:()=>k(e.id),children:"Format"}),t.jsx(c,{size:"sm",variant:"outline",icon:"content_copy",onClick:()=>R(e.id),children:"Copy"}),s]})]})]})},e.id)})]})}function m({label:i,value:h,color:g}){const u={blue:"bg-blue-500/10 text-blue-500",orange:"bg-orange-500/10 text-orange-500",green:"bg-green-500/10 text-green-500",purple:"bg-purple-500/10 text-purple-500"};return t.jsxs("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-mono ${u[g]}`,children:[t.jsxs("span",{className:"text-text-muted/70 font-sans text-[10px]",children:[i,":"]}),h]})}export{W as default};
2
+ import{u as z,j as t,B as c,_ as F}from"./index.D4FwOBBU.js";import{b as x}from"./router.Cjj1--8t.js";import{C as $}from"./NoAuthProxyCard.WHGGEUIp.js";import"./zustand.akaTi5uX.js";const B=x.lazy(()=>F(()=>import("./index.1VBQU7rF.js"),__vite__mapDeps([0,1]))),v=[{id:1,label:"Client Request",file:"1_req_client.json",lang:"json",desc:"Raw request from client"},{id:2,label:"Source Body",file:"2_req_source.json",lang:"json",desc:"After initial conversion"},{id:3,label:"OpenAI Intermediate",file:"3_req_openai.json",lang:"json",desc:"source → openai"},{id:4,label:"Target Request",file:"4_req_target.json",lang:"json",desc:"openai → target + URL + headers"},{id:5,label:"Provider Response",file:"5_res_provider.txt",lang:"text",desc:"Raw SSE from provider"},{id:6,label:"OpenAI Response",file:"6_res_openai.txt",lang:"text",desc:"target → openai (response)"},{id:7,label:"Client Response",file:"7_res_client.txt",lang:"text",desc:"Final response to client"}],I={minimap:{enabled:!1},fontSize:12,lineNumbers:"on",scrollBeyondLastLine:!1,wordWrap:"on",automaticLayout:!0};function W(){const[i,h]=x.useState({}),[g,u]=x.useState({1:!0}),[p,S]=x.useState({}),[o,w]=x.useState(null),l=(e,s)=>S(a=>({...a,[e]:s})),d=(e,s)=>h(a=>({...a,[e]:s})),O=e=>u(s=>({...s,[e]:!s[e]})),j=e=>u(s=>{const a={};return v.forEach(n=>{a[n.id]=!1}),a[e]=!0,a}),_=async e=>{const s=v.find(a=>a.id===e);l(`load-${e}`,!0);try{const n=await(await fetch(`/api/translator/load?file=${s.file}`)).json();n.success?(d(e,n.content),e===1&&await N(n.content)):alert(n.error||"File not found")}catch(a){alert(a.message)}l(`load-${e}`,!1)},N=async e=>{try{const s=typeof e=="string"?JSON.parse(e):e,n=await(await fetch("/api/translator/translate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({step:1,body:s})})).json();n.success&&w(n.result)}catch{}},f=(e,s)=>fetch("/api/translator/save",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({file:e,content:s})}).catch(()=>{}),T=async()=>{l("toOpenAI",!0);try{const e=i[1],s=JSON.parse(e);f("1_req_client.json",e),f("2_req_source.json",JSON.stringify({timestamp:new Date().toISOString(),headers:{},body:s.body||s},null,2));const n=await(await fetch("/api/translator/translate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({step:2,body:s})})).json();if(!n.success){alert(n.error);return}const r=JSON.stringify(n.result.body,null,2);d(3,r),j(3)}catch(e){alert(e.message)}l("toOpenAI",!1)},C=async()=>{l("toTarget",!0);try{const e=i[3],s=JSON.parse(e);f("3_req_openai.json",e);const n=await(await fetch("/api/translator/translate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({step:3,body:{...s,provider:o==null?void 0:o.provider,model:o==null?void 0:o.model}})})).json();if(!n.success){alert(n.error);return}const r={...n.result,provider:o==null?void 0:o.provider,model:o==null?void 0:o.model};d(4,JSON.stringify(r,null,2)),j(4)}catch(e){alert(e.message)}l("toTarget",!1)},J=async()=>{l("send",!0);try{const e=i[4],s=JSON.parse(e);f("4_req_target.json",e);const a=s.provider||(o==null?void 0:o.provider),n=s.model||(o==null?void 0:o.model);if(!a||!n){alert("Missing provider or model. Please run step 1 first to detect them.");return}const r=await fetch("/api/translator/send",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:a,model:n,body:s.body||s})});if(!r.ok){const b=await r.json().catch(()=>({error:r.statusText}));alert(b.error||"Send failed");return}const E=r.body.getReader(),A=new TextDecoder;let y="";for(;;){const{done:b,value:L}=await E.read();if(b)break;y+=A.decode(L,{stream:!0})}d(5,y),j(5),await fetch("/api/translator/save",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({file:"5_res_provider.txt",content:y})})}catch(e){alert(e.message)}finally{l("send",!1)}},{copy:P}=z(),R=async e=>{i[e]&&P(i[e],`translator-step-${e}`)},k=e=>{try{const s=JSON.parse(i[e]);d(e,JSON.stringify(s,null,2))}catch{}},q=e=>e===1?t.jsx(c,{size:"sm",icon:"arrow_forward",loading:p.toOpenAI,onClick:T,children:"→ OpenAI"}):e===3?t.jsx(c,{size:"sm",icon:"arrow_forward",loading:p.toTarget,onClick:C,children:"→ Target"}):e===4?t.jsx(c,{size:"sm",icon:"send",loading:p.send,onClick:J,children:"Send"}):null;return t.jsxs("div",{className:"p-8 space-y-3",children:[t.jsxs("div",{className:"flex items-center justify-between mb-2",children:[t.jsxs("div",{children:[t.jsx("h1",{className:"text-2xl font-bold text-text-main",children:"Translator Debug"}),t.jsx("p",{className:"text-sm text-text-muted mt-1",children:"Replay request flow — matches log files"})]}),o&&t.jsxs("div",{className:"flex items-center gap-2 flex-wrap justify-end",children:[t.jsx(m,{label:"src",value:o.sourceFormat,color:"blue"}),t.jsx("span",{className:"material-symbols-outlined text-text-muted text-[14px]",children:"arrow_forward"}),t.jsx(m,{label:"dst",value:o.targetFormat,color:"orange"}),t.jsx(m,{label:"provider",value:o.provider,color:"green"}),t.jsx(m,{label:"model",value:o.model,color:"purple"})]})]}),v.map(e=>{const s=q(e.id),a=!!g[e.id],n=i[e.id]||"";return t.jsx($,{children:t.jsxs("div",{className:"p-4 space-y-3",children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsxs("button",{onClick:()=>O(e.id),className:"flex items-center gap-2 flex-1 text-left group",children:[t.jsx("span",{className:"material-symbols-outlined text-[20px] text-text-muted group-hover:text-primary transition-colors",children:a?"expand_more":"chevron_right"}),t.jsx("span",{className:"text-xs font-mono text-text-muted/60 w-4",children:e.id}),t.jsx("h3",{className:"text-sm font-semibold text-text-main",children:e.label}),t.jsx("span",{className:"text-xs text-text-muted/60 font-mono",children:e.file}),n&&t.jsxs("span",{className:"text-xs text-green-500",children:["(",n.length," chars)"]})]}),!a&&t.jsxs("div",{className:"flex gap-1 shrink-0",children:[t.jsx(c,{size:"sm",variant:"ghost",icon:"folder_open",loading:p[`load-${e.id}`],onClick:()=>_(e.id)}),s]})]}),a&&t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"border border-border rounded-lg overflow-hidden",children:t.jsx(B,{height:"400px",defaultLanguage:e.lang==="text"?"plaintext":"json",value:n,onChange:r=>{d(e.id,r||""),e.id===1&&N(r||"")},theme:"vs-dark",options:I})}),t.jsxs("div",{className:"flex gap-2 flex-wrap",children:[t.jsx(c,{size:"sm",variant:"outline",icon:"folder_open",loading:p[`load-${e.id}`],onClick:()=>_(e.id),children:"Load"}),t.jsx(c,{size:"sm",variant:"outline",icon:"data_object",onClick:()=>k(e.id),children:"Format"}),t.jsx(c,{size:"sm",variant:"outline",icon:"content_copy",onClick:()=>R(e.id),children:"Copy"}),s]})]})]})},e.id)})]})}function m({label:i,value:h,color:g}){const u={blue:"bg-blue-500/10 text-blue-500",orange:"bg-orange-500/10 text-orange-500",green:"bg-green-500/10 text-green-500",purple:"bg-purple-500/10 text-purple-500"};return t.jsxs("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-mono ${u[g]}`,children:[t.jsxs("span",{className:"text-text-muted/70 font-sans text-[10px]",children:[i,":"]}),h]})}export{W as default};
@@ -1 +1 @@
1
- import{j as e,L as Qe,D as Xe,E as ye,G as je,H as Ze,n as he,B as v,I as ge,C as es}from"./index.CShjRV_B.js";import{b as o,c as ss,d as ts}from"./router.Cjj1--8t.js";import{C as T,T as C,I as m}from"./NoAuthProxyCard.qAv57b-0.js";import"./zustand.akaTi5uX.js";function as(){if(typeof document>"u")return"en";const g=document.cookie.split(";").find(S=>S.trim().startsWith(`${ye}=`)),k=g?decodeURIComponent(g.split("=")[1]):"en";return je(k)}const oe=g=>({en:{name:"English",flag:"🇺🇸"},vi:{name:"Tiếng Việt",flag:"🇻🇳"},"zh-CN":{name:"简体中文",flag:"🇨🇳"},"zh-TW":{name:"繁體中文",flag:"🇹🇼"},ja:{name:"日本語",flag:"🇯🇵"},"pt-BR":{name:"Português (Brasil)",flag:"🇧🇷"},"pt-PT":{name:"Português (Portugal)",flag:"🇵🇹"},ko:{name:"한국어",flag:"🇰🇷"},es:{name:"Español",flag:"🇪🇸"},de:{name:"Deutsch",flag:"🇩🇪"},fr:{name:"Français",flag:"🇫🇷"},he:{name:"עברית",flag:"🇮🇱"},ar:{name:"العربية",flag:"🇸🇦"},ru:{name:"Русский",flag:"🇷🇺"},pl:{name:"Polski",flag:"🇵🇱"},cs:{name:"Čeština",flag:"🇨🇿"},nl:{name:"Nederlands",flag:"🇳🇱"},tr:{name:"Türkçe",flag:"🇹🇷"},uk:{name:"Українська",flag:"🇺🇦"},tl:{name:"Tagalog",flag:"🇵🇭"},id:{name:"Indonesia",flag:"🇮🇩"},th:{name:"ไทย",flag:"🇹🇭"},hi:{name:"हिन्दी",flag:"🇮🇳"},bn:{name:"বাংলা",flag:"🇧🇩"},ur:{name:"اردو",flag:"🇵🇰"},ro:{name:"Română",flag:"🇷🇴"},sv:{name:"Svenska",flag:"🇸🇪"},it:{name:"Italiano",flag:"🇮🇹"},el:{name:"Ελληνικά",flag:"🇬🇷"},hu:{name:"Magyar",flag:"🇭🇺"},fi:{name:"Suomi",flag:"🇫🇮"},da:{name:"Dansk",flag:"🇩🇰"},no:{name:"Norsk",flag:"🇳🇴"}})[g]||{name:g,flag:"🌐"};function os({className:g="",isOpen:k,onClose:S,hideTrigger:re=!1}){const[P,U]=o.useState("en"),[R,H]=o.useState(!1),[E,V]=o.useState(!1),F=o.useRef(null),r=typeof k=="boolean",x=r?k:E,i=c=>{r?!c&&S&&S(P):V(c)};o.useEffect(()=>{U(as())},[]),o.useEffect(()=>{function c(N){F.current&&!F.current.contains(N.target)&&i(!1)}if(x)return document.addEventListener("mousedown",c),()=>document.removeEventListener("mousedown",c)},[x]);const B=async c=>{if(!(c===P||R)){H(!0),i(!1);try{await fetch("/api/locale",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({locale:c})}),await Xe(),U(c)}catch(N){console.error("Failed to set locale:",N)}finally{H(!1)}}};return e.jsxs("div",{className:g,children:[!re&&e.jsxs("button",{onClick:()=>i(!x),disabled:R,className:"flex items-center gap-2 px-3 py-2 rounded-lg text-text-muted hover:text-text-main hover:bg-surface/60 transition-colors",title:"Language","data-i18n-skip":"true",children:[e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"language"}),e.jsx("span",{className:"text-sm font-medium",children:oe(P).name}),e.jsx("span",{className:"text-lg",children:oe(P).flag})]}),x&&ss.createPortal(e.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center p-4","data-i18n-skip":"true",children:[e.jsx("div",{className:"absolute inset-0 bg-black/30 backdrop-blur-sm",onClick:()=>i(!1)}),e.jsxs("div",{ref:F,className:"relative w-full bg-surface border border-black/10 dark:border-white/10 rounded-xl shadow-2xl animate-in fade-in zoom-in-95 duration-200 max-w-2xl flex flex-col max-h-[80vh]",children:[e.jsxs("div",{className:"flex items-center justify-between p-3 border-b border-black/5 dark:border-white/5",children:[e.jsx("h2",{className:"text-lg font-semibold text-text-main",children:"Select Language"}),e.jsx("button",{onClick:()=>i(!1),className:"p-1.5 rounded-lg text-text-muted hover:bg-black/5 dark:hover:bg-white/5 transition-colors","aria-label":"Close",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"close"})})]}),e.jsx("div",{className:"p-6 overflow-y-auto flex-1",children:e.jsx("div",{className:"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-2",children:Qe.map(c=>{const N=P===c,O=oe(c);return e.jsxs("button",{onClick:()=>B(c),disabled:R,className:`flex flex-col items-center justify-start gap-1 px-2 py-3 rounded-lg text-xs font-medium transition-colors w-full ${N?"bg-primary/15 text-primary ring-2 ring-primary":"text-text-main hover:bg-black/5 dark:hover:bg-white/5"} ${R?"opacity-70 cursor-wait":""}`,title:O.name,children:[e.jsx("span",{className:"text-2xl",children:O.flag}),e.jsx("span",{className:"text-center leading-tight line-clamp-2 h-8 flex items-center",children:O.name}),N&&e.jsx("span",{className:"material-symbols-outlined text-sm",children:"check"})]},c)})})})]})]}),document.body)]})}function rs(){if(typeof document>"u")return"en";const g=document.cookie.split(";").find(S=>S.trim().startsWith(`${ye}=`)),k=g?decodeURIComponent(g.split("=")[1]):"en";return je(k)}function ds(){const g=ts(),{theme:k,setTheme:S}=Ze(),[re,P]=o.useState("en"),[U,R]=o.useState(!1),[H,E]=o.useState(!1),[V,F]=o.useState(!1),[r,x]=o.useState({fallbackStrategy:"fill-first"}),[i,B]=o.useState(!0),[c,N]=o.useState({current:"",new:"",confirm:""}),[O,M]=o.useState({type:"",message:""}),[we,ie]=o.useState(!1),[le,W]=o.useState(!1),[Y,D]=o.useState({type:"",message:""}),[p,Q]=o.useState({authMode:"password",oidcIssuerUrl:"",oidcClientId:"",oidcScopes:"openid profile email",oidcLoginLabel:"Sign in with OIDC"}),[X,Z]=o.useState(""),[ee,A]=o.useState({type:"",message:""}),[L,ne]=o.useState(!1),[ve,ce]=o.useState(!1),[se,I]=o.useState({type:"",message:""}),[Ne,_e]=o.useState("/api/auth/oidc/callback"),[de,me]=o.useState(!1),K=o.useRef(null),[J,z]=o.useState({outboundProxyEnabled:!1,outboundProxyUrl:"",outboundNoProxy:""}),[te,y]=o.useState({type:"",message:""}),[$,G]=o.useState(!1),[ke,xe]=o.useState(!1),[l,j]=o.useState({codebuddy_auto_fsrouter:!1,codebuddy_leave_canva_team:!1,codebuddy_browser_headless:!0,codebuddy_proxy_enabled:!1,codebuddy_proxy_server:"",codebuddy_proxy_username:"",codebuddy_proxy_password:"",fsmail_base_url:"",fsmail_api_key:"",fsmail_default_domain:"",fsmail_webhook_secret:""}),[ae,f]=o.useState({type:"",message:""}),[w,ue]=o.useState(!1),[Ce,pe]=o.useState(!1),[Se,be]=o.useState(!1),[fe,Pe]=o.useState(!1);o.useEffect(()=>{P(rs())},[U]),o.useEffect(()=>{fetch("/api/settings").then(s=>s.json()).then(s=>{x(s),Q({authMode:(s==null?void 0:s.authMode)||"password",oidcIssuerUrl:(s==null?void 0:s.oidcIssuerUrl)||"",oidcClientId:(s==null?void 0:s.oidcClientId)||"",oidcScopes:(s==null?void 0:s.oidcScopes)||"openid profile email",oidcLoginLabel:(s==null?void 0:s.oidcLoginLabel)||"Sign in with OIDC"}),Z(""),((s==null?void 0:s.authMode)==="oidc"||(s==null?void 0:s.authMode)==="both")&&me(!0),z({outboundProxyEnabled:(s==null?void 0:s.outboundProxyEnabled)===!0,outboundProxyUrl:(s==null?void 0:s.outboundProxyUrl)||"",outboundNoProxy:(s==null?void 0:s.outboundNoProxy)||""}),j({codebuddy_auto_fsrouter:(s==null?void 0:s.codebuddy_auto_fsrouter)==="1",codebuddy_leave_canva_team:(s==null?void 0:s.codebuddy_leave_canva_team)==="1",codebuddy_browser_headless:(s==null?void 0:s.codebuddy_browser_headless)!=="0",codebuddy_proxy_enabled:(s==null?void 0:s.codebuddy_proxy_enabled)==="1",codebuddy_proxy_server:(s==null?void 0:s.codebuddy_proxy_server)||"",codebuddy_proxy_username:(s==null?void 0:s.codebuddy_proxy_username)||"",codebuddy_proxy_password:(s==null?void 0:s.codebuddy_proxy_password)||"",fsmail_base_url:(s==null?void 0:s.fsmail_base_url)||"",fsmail_api_key:(s==null?void 0:s.fsmail_api_key)||"",fsmail_default_domain:(s==null?void 0:s.fsmail_default_domain)||"",fsmail_webhook_secret:(s==null?void 0:s.fsmail_webhook_secret)||""}),B(!1)}).catch(s=>{console.error("Failed to fetch settings:",s),B(!1)})},[]),o.useEffect(()=>{typeof window<"u"&&_e(`${window.location.origin}/api/auth/oidc/callback`)},[]);const Oe=async s=>{ue(!0),f({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({codebuddy_auto_fsrouter:l.codebuddy_auto_fsrouter?"1":"0",codebuddy_leave_canva_team:l.codebuddy_leave_canva_team?"1":"0",codebuddy_browser_headless:l.codebuddy_browser_headless?"1":"0",codebuddy_proxy_enabled:l.codebuddy_proxy_enabled?"1":"0",codebuddy_proxy_server:l.codebuddy_proxy_server,codebuddy_proxy_username:l.codebuddy_proxy_username,codebuddy_proxy_password:l.codebuddy_proxy_password,fsmail_base_url:l.fsmail_base_url,fsmail_api_key:l.fsmail_api_key,fsmail_default_domain:l.fsmail_default_domain,fsmail_webhook_secret:l.fsmail_webhook_secret})}),a=await t.json();t.ok?(x(n=>({...n,...a})),f({type:"success",message:"Automation settings saved successfully."})):f({type:"error",message:a.error||"Failed to update automation settings"})}catch{f({type:"error",message:"An error occurred"})}finally{ue(!1)}},Le=async()=>{pe(!0),f({type:"",message:""});try{const s=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({fsmail_base_url:l.fsmail_base_url,fsmail_api_key:l.fsmail_api_key,fsmail_default_domain:l.fsmail_default_domain,fsmail_webhook_secret:l.fsmail_webhook_secret})});if(!s.ok){const n=await s.json().catch(()=>({}));f({type:"error",message:n.error||"Failed to save settings before testing connection"});return}const t=await fetch("/api/automation/fsmail",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"test-connection"})}),a=await t.json().catch(()=>({}));t.ok?f({type:"success",message:"FSMail Connection Successful!"}):f({type:"error",message:a.error||"FSMail Connection Failed."})}catch(s){f({type:"error",message:s.message||"An error occurred"})}finally{pe(!1)}},Ie=async()=>{var s;be(!0),f({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({fsmail_base_url:l.fsmail_base_url,fsmail_api_key:l.fsmail_api_key,fsmail_default_domain:l.fsmail_default_domain,fsmail_webhook_secret:l.fsmail_webhook_secret})});if(!t.ok){const b=await t.json().catch(()=>({}));f({type:"error",message:b.error||"Failed to save settings before registering webhook"});return}const a=await fetch("/api/automation/fsmail",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"webhook-register"})}),n=await a.json().catch(()=>({}));a.ok?(f({type:"success",message:"FSMail Webhook Registered Successfully!"}),(s=n.webhook)!=null&&s.secret&&j(b=>({...b,fsmail_webhook_secret:n.webhook.secret}))):f({type:"error",message:n.error||"FSMail Webhook Registration Failed."})}catch(t){f({type:"error",message:t.message||"An error occurred"})}finally{be(!1)}},Te=async s=>{if(s.preventDefault(),r.outboundProxyEnabled===!0){G(!0),y({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({outboundProxyUrl:J.outboundProxyUrl,outboundNoProxy:J.outboundNoProxy})}),a=await t.json();t.ok?(x(n=>({...n,...a})),y({type:"success",message:"Proxy settings applied"})):y({type:"error",message:a.error||"Failed to update proxy settings"})}catch{y({type:"error",message:"An error occurred"})}finally{G(!1)}}},Re=async()=>{if(r.outboundProxyEnabled!==!0)return;const s=(J.outboundProxyUrl||"").trim();if(!s){y({type:"error",message:"Please enter a Proxy URL to test"});return}xe(!0),y({type:"",message:""});try{const t=await fetch("/api/settings/proxy-test",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({proxyUrl:s})}),a=await t.json();t.ok&&(a!=null&&a.ok)?y({type:"success",message:`Proxy test OK (${a.status}) in ${a.elapsedMs}ms`}):y({type:"error",message:(a==null?void 0:a.error)||"Proxy test failed"})}catch{y({type:"error",message:"An error occurred"})}finally{xe(!1)}},Fe=async s=>{G(!0),y({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({outboundProxyEnabled:s})}),a=await t.json();t.ok?(x(n=>({...n,...a})),z(n=>({...n,outboundProxyEnabled:(a==null?void 0:a.outboundProxyEnabled)===!0})),y({type:"success",message:s?"Proxy enabled":"Proxy disabled"})):y({type:"error",message:a.error||"Failed to update proxy settings"})}catch{y({type:"error",message:"An error occurred"})}finally{G(!1)}},De=async s=>{if(s.preventDefault(),c.new!==c.confirm){M({type:"error",message:"Passwords do not match"});return}ie(!0),M({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({currentPassword:c.current,newPassword:c.new})}),a=await t.json();t.ok?(M({type:"success",message:"Password updated successfully"}),N({current:"",new:"",confirm:""})):M({type:"error",message:a.error||"Failed to update password"})}catch{M({type:"error",message:"An error occurred"})}finally{ie(!1)}},Ae=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({fallbackStrategy:s})})).ok&&x(a=>({...a,fallbackStrategy:s}))}catch(t){console.error("Failed to update settings:",t)}},Ue=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({comboStrategy:s})})).ok&&x(a=>({...a,comboStrategy:s}))}catch(t){console.error("Failed to update combo strategy:",t)}},Ee=async s=>{const t=parseInt(s);if(!(isNaN(t)||t<1))try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({stickyRoundRobinLimit:t})})).ok&&x(n=>({...n,stickyRoundRobinLimit:t}))}catch(a){console.error("Failed to update sticky limit:",a)}},Me=async s=>{const t=parseInt(s);if(!(isNaN(t)||t<1))try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({comboStickyRoundRobinLimit:t})})).ok&&x(n=>({...n,comboStickyRoundRobinLimit:t}))}catch(a){console.error("Failed to update combo sticky limit:",a)}},Je=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({requireLogin:s})})).ok&&x(a=>({...a,requireLogin:s}))}catch(t){console.error("Failed to update require login:",t)}},q=(s,t)=>{Q(a=>({...a,[s]:t}))},$e=async(s=p.authMode||"password")=>{const t=p.oidcIssuerUrl.trim(),a=p.oidcClientId.trim(),n=p.oidcScopes.trim(),b=p.oidcLoginLabel.trim(),u=X.trim();if(s!=="password"&&(!t||!a||!u)&&!r.oidcConfigured){A({type:"error",message:"Issuer URL, client ID, and client secret are required to enable OIDC."});return}ne(!0),A({type:"",message:""}),I({type:"",message:""});try{const _={authMode:s,oidcIssuerUrl:t,oidcClientId:a,oidcScopes:n||"openid profile email",oidcLoginLabel:b||"Sign in with OIDC"};u&&(_.oidcClientSecret=u);const h=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(_)}),d=await h.json();h.ok?(x(Ye=>({...Ye,...d})),Q({authMode:(d==null?void 0:d.authMode)||s,oidcIssuerUrl:(d==null?void 0:d.oidcIssuerUrl)||t,oidcClientId:(d==null?void 0:d.oidcClientId)||a,oidcScopes:(d==null?void 0:d.oidcScopes)||n||"openid profile email",oidcLoginLabel:(d==null?void 0:d.oidcLoginLabel)||b||"Sign in with OIDC"}),Z(""),A({type:"success",message:s==="oidc"?"OIDC login enabled":s==="both"?"Password and OIDC login enabled":"OIDC settings saved"})):A({type:"error",message:d.error||"Failed to save OIDC settings"})}catch{A({type:"error",message:"An error occurred"})}finally{ne(!1)}},qe=async()=>{const s=p.oidcIssuerUrl.trim(),t=p.oidcClientId.trim(),a=p.oidcScopes.trim(),n=X.trim();if(!s||!t){I({type:"error",message:"Issuer URL and client ID are required to test the connection."});return}ce(!0),A({type:"",message:""}),I({type:"",message:""});try{const b=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({authMode:p.authMode||r.authMode||"password",oidcIssuerUrl:s,oidcClientId:t,oidcScopes:a||"openid profile email",oidcLoginLabel:p.oidcLoginLabel.trim()||"Sign in with OIDC",...n?{oidcClientSecret:n}:{}})}),u=await b.json().catch(()=>({}));if(!b.ok){I({type:"error",message:u.error||"Failed to save OIDC settings before testing"});return}const _=await fetch("/api/auth/oidc/test",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({issuerUrl:u.oidcIssuerUrl||s,clientId:u.oidcClientId||t,scopes:u.oidcScopes||a||"openid profile email"})}),h=await _.json().catch(()=>({}));if(_.ok&&(h!=null&&h.ok)){const d=h.clientSecretTested?h.clientSecretValid===!0?`Connection OK. Discovery loaded from ${h.issuerUrl}. Client secret validated too.`:`Connection OK. Discovery loaded from ${h.issuerUrl}. Client secret was not checked.`:`Connection OK. Discovery loaded from ${h.issuerUrl}.`;I({type:"success",message:d})}else I({type:"error",message:h.error||"OIDC connection test failed"})}catch{I({type:"error",message:"An error occurred"})}finally{ce(!1)}},He=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({enableObservability:s})})).ok&&x(a=>({...a,enableObservability:s}))}catch(t){console.error("Failed to update enableObservability:",t)}},Be=async()=>{try{const s=await fetch("/api/settings");if(!s.ok)return;const t=await s.json();x(t)}catch(s){console.error("Failed to reload settings:",s)}},We=async()=>{W(!0),D({type:"",message:""});try{const s=await fetch("/api/settings/database");if(!s.ok){const h=await s.json().catch(()=>({}));throw new Error(h.error||"Failed to export database")}const t=await s.json(),a=JSON.stringify(t,null,2),n=new Blob([a],{type:"application/json"}),b=URL.createObjectURL(n),u=document.createElement("a"),_=new Date().toISOString().replace(/[.:]/g,"-");u.href=b,u.download=`fsrouter-backup-${_}.json`,document.body.appendChild(u),u.click(),document.body.removeChild(u),URL.revokeObjectURL(b),D({type:"success",message:"Database backup downloaded"})}catch(s){D({type:"error",message:s.message||"Failed to export database"})}finally{W(!1)}},Ke=async s=>{var a;const t=(a=s.target.files)==null?void 0:a[0];if(t){W(!0),D({type:"",message:""});try{const n=await t.text(),b=JSON.parse(n),u=await fetch("/api/settings/database",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(b)}),_=await u.json().catch(()=>({}));if(!u.ok)throw new Error(_.error||"Failed to import database");await Be(),D({type:"success",message:"Database imported successfully"})}catch(n){D({type:"error",message:n.message||"Invalid backup file"})}finally{K.current&&(K.current.value=""),W(!1)}}},ze=r.enableObservability===!0,Ge=async()=>{F(!0);try{await fetch("/api/version/shutdown",{method:"POST"})}catch{}F(!1),E(!1)},Ve=async()=>{try{(await fetch("/api/auth/logout",{method:"POST"})).ok&&(localStorage.removeItem("9r_authed"),g("/login"),g(0))}catch(s){console.error("Failed to logout:",s)}};return e.jsxs("div",{className:"max-w-2xl mx-auto px-4 sm:px-0",children:[e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsxs(T,{children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-4",children:[e.jsxs("div",{className:"flex items-center gap-3 sm:gap-4",children:[e.jsx("div",{className:"size-10 sm:size-12 rounded-lg bg-green-500/10 text-green-500 flex items-center justify-center shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-xl sm:text-2xl",children:"computer"})}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg sm:text-xl font-semibold",children:"Local Mode"}),e.jsx("p",{className:"text-sm text-text-muted",children:"Running on your machine"})]})]}),e.jsx("div",{className:"inline-flex p-1 rounded-lg bg-black/5 dark:bg-white/5 w-full sm:w-auto",children:["light","dark","system"].map(s=>e.jsxs("button",{type:"button",onClick:()=>S(s),className:he("flex items-center justify-center gap-1 sm:gap-1.5 px-2 sm:px-3 py-1.5 rounded-md font-medium transition-all flex-1 sm:flex-initial",k===s?"bg-white dark:bg-white/10 text-text-main shadow-sm":"text-text-muted hover:text-text-main"),children:[e.jsx("span",{className:"material-symbols-outlined text-[18px]",children:s==="light"?"light_mode":s==="dark"?"dark_mode":"contrast"}),e.jsx("span",{className:"capitalize text-xs sm:text-sm",children:s})]},s))})]}),e.jsxs("div",{className:"flex flex-col gap-3 pt-4 border-t border-border",children:[e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between p-3 rounded-lg bg-bg border border-border gap-2",children:e.jsxs("div",{children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Database Location"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted font-mono break-all",children:"~/.fsrouter/db/data.sqlite"})]})}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsx(v,{variant:"secondary",icon:"download",onClick:We,loading:le,className:"w-full sm:w-auto",children:"Download Backup"}),e.jsx(v,{variant:"outline",icon:"upload",onClick:()=>{var s;return(s=K.current)==null?void 0:s.click()},disabled:le,className:"w-full sm:w-auto",children:"Import Backup"}),e.jsx("input",{ref:K,type:"file",accept:"application/json,.json",className:"hidden",onChange:Ke})]}),Y.message&&e.jsx("p",{className:`text-sm ${Y.type==="error"?"text-red-500":"text-green-600 dark:text-green-400"}`,children:Y.message})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-primary/10 text-primary shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"shield"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Security"})]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Require login"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"When ON, dashboard requires password. When OFF, access without login."})]}),e.jsx(C,{checked:r.requireLogin===!0,onChange:()=>Je(!r.requireLogin),disabled:i})]}),r.requireLogin===!0&&e.jsxs("form",{onSubmit:De,className:"flex flex-col gap-4 pt-4 border-t border-border/50",children:[r.hasPassword&&e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"text-xs sm:text-sm font-medium",children:"Current Password"}),e.jsx(m,{type:"password",placeholder:"Enter current password",value:c.current,onChange:s=>N({...c,current:s.target.value}),required:!0})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"text-xs sm:text-sm font-medium",children:"New Password"}),e.jsx(m,{type:"password",placeholder:"Enter new password",value:c.new,onChange:s=>N({...c,new:s.target.value}),required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"text-xs sm:text-sm font-medium",children:"Confirm New Password"}),e.jsx(m,{type:"password",placeholder:"Confirm new password",value:c.confirm,onChange:s=>N({...c,confirm:s.target.value}),required:!0})]})]}),O.message&&e.jsx("p",{className:`text-xs sm:text-sm ${O.type==="error"?"text-red-500":"text-green-500"}`,children:O.message}),e.jsx("div",{className:"pt-2",children:e.jsx(v,{type:"submit",variant:"primary",loading:we,className:"w-full sm:w-auto",children:r.hasPassword?"Update Password":"Set Password"})})]})]})]}),e.jsxs(T,{children:[e.jsxs("button",{type:"button",onClick:()=>me(s=>!s),className:"w-full flex items-center gap-3 text-left",children:[e.jsx("div",{className:"p-2 rounded-lg bg-indigo-500/10 text-indigo-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"lock_open"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"OIDC Dashboard Login"}),e.jsx("p",{className:"text-xs text-text-muted",children:r.authMode==="oidc"?"OIDC active":r.authMode==="both"?"Password + OIDC active":"Optional SSO via Authentik/Keycloak/Google"})]}),e.jsx("span",{className:"material-symbols-outlined text-text-muted shrink-0",children:de?"expand_less":"expand_more"})]}),de&&e.jsxs("div",{className:"flex flex-col gap-4 mt-4",children:[e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Use Authentik or any OIDC provider to sign in to the dashboard. You can enable password-only, OIDC-only, or both for the dashboard; model API access still uses API keys."}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Auth Mode"}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-2",children:[{value:"password",title:"Password only",desc:"Keep the legacy password login."},{value:"oidc",title:"OIDC only",desc:"Require OIDC for dashboard access."},{value:"both",title:"Both",desc:"Allow either password or OIDC."}].map(s=>{const t=p.authMode===s.value;return e.jsxs("button",{type:"button",onClick:()=>q("authMode",s.value),className:he("text-left rounded-lg border p-3 transition-colors",t?"border-primary bg-primary/5":"border-border bg-bg hover:bg-black/5 dark:hover:bg-white/5"),disabled:i||L,children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:s.title}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted mt-1",children:s.desc})]},s.value)})})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Issuer URL"}),e.jsx(m,{placeholder:"https://auth.example.com/application/o/fsrouter/",value:p.oidcIssuerUrl,onChange:s=>q("oidcIssuerUrl",s.target.value),disabled:i||L})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Client ID"}),e.jsx(m,{placeholder:"fsrouter-dashboard",value:p.oidcClientId,onChange:s=>q("oidcClientId",s.target.value),disabled:i||L})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Client Secret"}),e.jsx(m,{type:"password",placeholder:"Leave blank to keep existing secret",value:X,onChange:s=>Z(s.target.value),disabled:i||L}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"This value is write-only after saving."})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Scopes"}),e.jsx(m,{placeholder:"openid profile email",value:p.oidcScopes,onChange:s=>q("oidcScopes",s.target.value),disabled:i||L})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Login Button Label"}),e.jsx(m,{placeholder:"Sign in with OIDC",value:p.oidcLoginLabel,onChange:s=>q("oidcLoginLabel",s.target.value),disabled:i||L})]})]}),e.jsxs("div",{className:"rounded-lg border border-border bg-bg p-3 text-xs sm:text-sm text-text-muted",children:[e.jsx("p",{className:"font-medium text-text-main mb-1",children:"Redirect URI"}),e.jsx("code",{className:"block break-all font-mono",children:Ne})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-2 border-t border-border/50",children:[e.jsx(v,{type:"button",variant:"primary",loading:L,onClick:()=>$e(),className:"w-full sm:w-auto",children:"Save auth mode"}),e.jsx(v,{type:"button",variant:"outline",loading:ve,onClick:qe,className:"w-full sm:w-auto",children:"Test connection"})]}),se.message&&e.jsx("p",{className:`text-xs sm:text-sm ${se.type==="error"?"text-red-500":"text-green-500"}`,children:se.message}),ee.message&&e.jsx("p",{className:`text-xs sm:text-sm ${ee.type==="error"?"text-red-500":"text-green-500"}`,children:ee.message}),r.authMode==="oidc"&&e.jsx("p",{className:"text-xs sm:text-sm text-amber-600 dark:text-amber-400",children:"OIDC login is currently active. Password login is disabled until you switch back."}),r.authMode==="both"&&e.jsx("p",{className:"text-xs sm:text-sm text-amber-600 dark:text-amber-400",children:"Password and OIDC login are both active."})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-blue-500/10 text-blue-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"route"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Routing Strategy"})]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Round Robin"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Cycle through accounts to distribute load"})]}),e.jsx(C,{checked:r.fallbackStrategy==="round-robin",onChange:()=>Ae(r.fallbackStrategy==="round-robin"?"fill-first":"round-robin"),disabled:i})]}),r.fallbackStrategy==="round-robin"&&e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Sticky Limit"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Calls per account before switching"})]}),e.jsx(m,{type:"number",min:"1",max:"10",value:r.stickyRoundRobinLimit||3,onChange:s=>Ee(s.target.value),disabled:i,className:"w-16 sm:w-20 text-center shrink-0"})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-4 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Combo Round Robin"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Cycle through providers in combos instead of always starting with first"})]}),e.jsx(C,{checked:r.comboStrategy==="round-robin",onChange:()=>Ue(r.comboStrategy==="round-robin"?"fallback":"round-robin"),disabled:i})]}),r.comboStrategy==="round-robin"&&e.jsxs("div",{className:"flex items-center justify-between pt-2 border-t border-border/50",children:[e.jsxs("div",{children:[e.jsx("p",{className:"font-medium",children:"Combo Sticky Limit"}),e.jsx("p",{className:"text-sm text-text-muted",children:"Calls per combo model before switching"})]}),e.jsx(m,{type:"number",min:"1",max:"100",value:r.comboStickyRoundRobinLimit||1,onChange:s=>Me(s.target.value),disabled:i,className:"w-20 text-center"})]}),e.jsxs("p",{className:"text-xs text-text-muted italic pt-2 border-t border-border/50",children:[r.fallbackStrategy==="round-robin"?`Currently distributing requests across all available accounts with ${r.stickyRoundRobinLimit||3} calls per account.`:"Currently using accounts in priority order (Fill First).",r.comboStrategy==="round-robin"?` Combos rotate after ${r.comboStickyRoundRobinLimit||1} call${(r.comboStickyRoundRobinLimit||1)===1?"":"s"} per model.`:" Combos always start with their first model."]})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-purple-500/10 text-purple-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"wifi"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Network"})]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Outbound Proxy"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Enable proxy for OAuth + provider outbound requests."})]}),e.jsx(C,{checked:r.outboundProxyEnabled===!0,onChange:()=>Fe(r.outboundProxyEnabled!==!0),disabled:i||$})]}),r.outboundProxyEnabled===!0&&e.jsxs("form",{onSubmit:Te,className:"flex flex-col gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Proxy URL"}),e.jsx(m,{placeholder:"http://127.0.0.1:7897",value:J.outboundProxyUrl,onChange:s=>z(t=>({...t,outboundProxyUrl:s.target.value})),disabled:i||$}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Leave empty to inherit existing env proxy (if any)."})]}),e.jsxs("div",{className:"flex flex-col gap-2 pt-2 border-t border-border/50",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"No Proxy"}),e.jsx(m,{placeholder:"localhost,127.0.0.1",value:J.outboundNoProxy,onChange:s=>z(t=>({...t,outboundNoProxy:s.target.value})),disabled:i||$}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Comma-separated hostnames/domains to bypass the proxy."})]}),e.jsxs("div",{className:"pt-2 border-t border-border/50 flex flex-col sm:flex-row items-stretch sm:items-center gap-2",children:[e.jsx(v,{type:"button",variant:"secondary",loading:ke,disabled:i||$,onClick:Re,className:"w-full sm:w-auto",children:"Test proxy URL"}),e.jsx(v,{type:"submit",variant:"primary",loading:$,className:"w-full sm:w-auto",children:"Apply"})]})]}),te.message&&e.jsx("p",{className:`text-xs sm:text-sm ${te.type==="error"?"text-red-500":"text-green-500"} pt-2 border-t border-border/50`,children:te.message})]})]}),e.jsxs(T,{children:[e.jsxs("button",{type:"button",onClick:()=>Pe(s=>!s),className:"w-full flex items-center gap-3 text-left focus:outline-none",children:[e.jsx("div",{className:"p-2 rounded-lg bg-emerald-500/10 text-emerald-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"smart_toy"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Automation Settings"}),e.jsx("p",{className:"text-xs text-text-muted",children:"Manage CodeBuddy browser signup & FSMail temporary email configurations."})]}),e.jsx("span",{className:"material-symbols-outlined text-text-muted shrink-0",children:fe?"expand_less":"expand_more"})]}),fe&&e.jsxs("div",{className:"flex flex-col gap-4 mt-4",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("h4",{className:"font-semibold text-sm text-text-main flex items-center gap-1.5 border-b border-border/55 pb-1",children:[e.jsx("span",{className:"material-symbols-outlined text-[16px]",children:"smart_toy"}),"CodeBuddy API Gen Settings"]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Headless Browser"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Run the automated signup browser in headless mode (no visual window)."})]}),e.jsx(C,{checked:l.codebuddy_browser_headless,onChange:s=>j(t=>({...t,codebuddy_browser_headless:s})),disabled:i||w})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Auto Inject to fsrouter"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Automatically add newly generated CodeBuddy API keys to fsrouter connections."})]}),e.jsx(C,{checked:l.codebuddy_auto_fsrouter,onChange:s=>j(t=>({...t,codebuddy_auto_fsrouter:s})),disabled:i||w})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Leave Canva Team after Leonardo Registration"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Automatically leave the Canva team after completing Leonardo registration to free up team invite slots."})]}),e.jsx(C,{checked:l.codebuddy_leave_canva_team,onChange:s=>j(t=>({...t,codebuddy_leave_canva_team:s})),disabled:i||w})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Use Outbound Proxy"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Route the automation browser traffic through a proxy server."})]}),e.jsx(C,{checked:l.codebuddy_proxy_enabled,onChange:s=>j(t=>({...t,codebuddy_proxy_enabled:s})),disabled:i||w})]}),l.codebuddy_proxy_enabled&&e.jsxs("div",{className:"flex flex-col gap-3 pl-4 border-l-2 border-primary/20 pt-2",children:[e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-xs font-medium text-text-main",children:"Proxy Server"}),e.jsx(m,{placeholder:"host:port (e.g. 127.0.0.1:8080)",value:l.codebuddy_proxy_server,onChange:s=>j(t=>({...t,codebuddy_proxy_server:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-xs font-medium text-text-main",children:"Proxy Username (Optional)"}),e.jsx(m,{placeholder:"username",value:l.codebuddy_proxy_username,onChange:s=>j(t=>({...t,codebuddy_proxy_username:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-xs font-medium text-text-main",children:"Proxy Password (Optional)"}),e.jsx(m,{type:"password",placeholder:"password",value:l.codebuddy_proxy_password,onChange:s=>j(t=>({...t,codebuddy_proxy_password:s.target.value})),disabled:i||w})]})]})]})]}),e.jsxs("div",{className:"space-y-4 pt-4 border-t border-border/55",children:[e.jsxs("h4",{className:"font-semibold text-sm text-text-main flex items-center gap-1.5 border-b border-border/55 pb-1",children:[e.jsx("span",{className:"material-symbols-outlined text-[16px]",children:"mail"}),"FSMail Temp Mail Settings"]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Base URL"}),e.jsx(m,{placeholder:"https://fsmail.example.com",value:l.fsmail_base_url,onChange:s=>j(t=>({...t,fsmail_base_url:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"API Key"}),e.jsx(m,{type:"password",placeholder:"FSMail API Key",value:l.fsmail_api_key,onChange:s=>j(t=>({...t,fsmail_api_key:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Default Domain"}),e.jsx(m,{placeholder:"example.com",value:l.fsmail_default_domain,onChange:s=>j(t=>({...t,fsmail_default_domain:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Webhook Secret"}),e.jsx(m,{type:"password",placeholder:"Leave empty to auto-generate",value:l.fsmail_webhook_secret,onChange:s=>j(t=>({...t,fsmail_webhook_secret:s.target.value})),disabled:i||w})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-4 border-t border-border/50",children:[e.jsx(v,{type:"button",variant:"primary",loading:w,onClick:()=>Oe(),className:"w-full sm:w-auto",children:"Save Settings"}),e.jsx(v,{type:"button",variant:"secondary",loading:Ce,onClick:Le,className:"w-full sm:w-auto",children:"Test FSMail Connection"}),e.jsx(v,{type:"button",variant:"outline",loading:Se,onClick:Ie,className:"w-full sm:w-auto",children:"Register Webhook"})]}),ae.message&&e.jsx("p",{className:`text-xs sm:text-sm ${ae.type==="error"?"text-red-500":"text-green-500"} pt-2 border-t border-border/50`,children:ae.message})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-orange-500/10 text-orange-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"monitoring"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Observability"})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Enable Observability"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Record request details for inspection in the logs view"})]}),e.jsx(C,{checked:ze,onChange:He,disabled:i})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsx(v,{variant:"outline",fullWidth:!0,icon:"power_settings_new",onClick:()=>E(!0),className:"text-red-500 border-red-200 hover:bg-red-50 hover:border-red-300",children:"Shutdown"}),e.jsx(v,{variant:"outline",fullWidth:!0,icon:"logout",onClick:Ve,children:"Logout"})]}),e.jsxs("div",{className:"text-center text-xs sm:text-sm text-text-muted py-4",children:[e.jsxs("p",{children:[ge.name," v",ge.version]}),e.jsx("p",{className:"mt-1",children:"Local Mode - All data stored on your machine"})]})]}),e.jsx(os,{hideTrigger:!0,isOpen:U,onClose:s=>{R(!1),P(s)}}),e.jsx(es,{isOpen:H,onClose:()=>E(!1),onConfirm:Ge,title:"Close Proxy",message:"Are you sure you want to close the proxy server?",confirmText:"Close",cancelText:"Cancel",variant:"danger",loading:V})]})}export{ds as default};
1
+ import{j as e,L as Qe,D as Xe,E as ye,G as je,H as Ze,n as he,B as v,I as ge,C as es}from"./index.D4FwOBBU.js";import{b as o,c as ss,d as ts}from"./router.Cjj1--8t.js";import{C as T,T as C,I as m}from"./NoAuthProxyCard.WHGGEUIp.js";import"./zustand.akaTi5uX.js";function as(){if(typeof document>"u")return"en";const g=document.cookie.split(";").find(S=>S.trim().startsWith(`${ye}=`)),k=g?decodeURIComponent(g.split("=")[1]):"en";return je(k)}const oe=g=>({en:{name:"English",flag:"🇺🇸"},vi:{name:"Tiếng Việt",flag:"🇻🇳"},"zh-CN":{name:"简体中文",flag:"🇨🇳"},"zh-TW":{name:"繁體中文",flag:"🇹🇼"},ja:{name:"日本語",flag:"🇯🇵"},"pt-BR":{name:"Português (Brasil)",flag:"🇧🇷"},"pt-PT":{name:"Português (Portugal)",flag:"🇵🇹"},ko:{name:"한국어",flag:"🇰🇷"},es:{name:"Español",flag:"🇪🇸"},de:{name:"Deutsch",flag:"🇩🇪"},fr:{name:"Français",flag:"🇫🇷"},he:{name:"עברית",flag:"🇮🇱"},ar:{name:"العربية",flag:"🇸🇦"},ru:{name:"Русский",flag:"🇷🇺"},pl:{name:"Polski",flag:"🇵🇱"},cs:{name:"Čeština",flag:"🇨🇿"},nl:{name:"Nederlands",flag:"🇳🇱"},tr:{name:"Türkçe",flag:"🇹🇷"},uk:{name:"Українська",flag:"🇺🇦"},tl:{name:"Tagalog",flag:"🇵🇭"},id:{name:"Indonesia",flag:"🇮🇩"},th:{name:"ไทย",flag:"🇹🇭"},hi:{name:"हिन्दी",flag:"🇮🇳"},bn:{name:"বাংলা",flag:"🇧🇩"},ur:{name:"اردو",flag:"🇵🇰"},ro:{name:"Română",flag:"🇷🇴"},sv:{name:"Svenska",flag:"🇸🇪"},it:{name:"Italiano",flag:"🇮🇹"},el:{name:"Ελληνικά",flag:"🇬🇷"},hu:{name:"Magyar",flag:"🇭🇺"},fi:{name:"Suomi",flag:"🇫🇮"},da:{name:"Dansk",flag:"🇩🇰"},no:{name:"Norsk",flag:"🇳🇴"}})[g]||{name:g,flag:"🌐"};function os({className:g="",isOpen:k,onClose:S,hideTrigger:re=!1}){const[P,U]=o.useState("en"),[R,H]=o.useState(!1),[E,V]=o.useState(!1),F=o.useRef(null),r=typeof k=="boolean",x=r?k:E,i=c=>{r?!c&&S&&S(P):V(c)};o.useEffect(()=>{U(as())},[]),o.useEffect(()=>{function c(N){F.current&&!F.current.contains(N.target)&&i(!1)}if(x)return document.addEventListener("mousedown",c),()=>document.removeEventListener("mousedown",c)},[x]);const B=async c=>{if(!(c===P||R)){H(!0),i(!1);try{await fetch("/api/locale",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({locale:c})}),await Xe(),U(c)}catch(N){console.error("Failed to set locale:",N)}finally{H(!1)}}};return e.jsxs("div",{className:g,children:[!re&&e.jsxs("button",{onClick:()=>i(!x),disabled:R,className:"flex items-center gap-2 px-3 py-2 rounded-lg text-text-muted hover:text-text-main hover:bg-surface/60 transition-colors",title:"Language","data-i18n-skip":"true",children:[e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"language"}),e.jsx("span",{className:"text-sm font-medium",children:oe(P).name}),e.jsx("span",{className:"text-lg",children:oe(P).flag})]}),x&&ss.createPortal(e.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center p-4","data-i18n-skip":"true",children:[e.jsx("div",{className:"absolute inset-0 bg-black/30 backdrop-blur-sm",onClick:()=>i(!1)}),e.jsxs("div",{ref:F,className:"relative w-full bg-surface border border-black/10 dark:border-white/10 rounded-xl shadow-2xl animate-in fade-in zoom-in-95 duration-200 max-w-2xl flex flex-col max-h-[80vh]",children:[e.jsxs("div",{className:"flex items-center justify-between p-3 border-b border-black/5 dark:border-white/5",children:[e.jsx("h2",{className:"text-lg font-semibold text-text-main",children:"Select Language"}),e.jsx("button",{onClick:()=>i(!1),className:"p-1.5 rounded-lg text-text-muted hover:bg-black/5 dark:hover:bg-white/5 transition-colors","aria-label":"Close",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"close"})})]}),e.jsx("div",{className:"p-6 overflow-y-auto flex-1",children:e.jsx("div",{className:"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-2",children:Qe.map(c=>{const N=P===c,O=oe(c);return e.jsxs("button",{onClick:()=>B(c),disabled:R,className:`flex flex-col items-center justify-start gap-1 px-2 py-3 rounded-lg text-xs font-medium transition-colors w-full ${N?"bg-primary/15 text-primary ring-2 ring-primary":"text-text-main hover:bg-black/5 dark:hover:bg-white/5"} ${R?"opacity-70 cursor-wait":""}`,title:O.name,children:[e.jsx("span",{className:"text-2xl",children:O.flag}),e.jsx("span",{className:"text-center leading-tight line-clamp-2 h-8 flex items-center",children:O.name}),N&&e.jsx("span",{className:"material-symbols-outlined text-sm",children:"check"})]},c)})})})]})]}),document.body)]})}function rs(){if(typeof document>"u")return"en";const g=document.cookie.split(";").find(S=>S.trim().startsWith(`${ye}=`)),k=g?decodeURIComponent(g.split("=")[1]):"en";return je(k)}function ds(){const g=ts(),{theme:k,setTheme:S}=Ze(),[re,P]=o.useState("en"),[U,R]=o.useState(!1),[H,E]=o.useState(!1),[V,F]=o.useState(!1),[r,x]=o.useState({fallbackStrategy:"fill-first"}),[i,B]=o.useState(!0),[c,N]=o.useState({current:"",new:"",confirm:""}),[O,M]=o.useState({type:"",message:""}),[we,ie]=o.useState(!1),[le,W]=o.useState(!1),[Y,D]=o.useState({type:"",message:""}),[p,Q]=o.useState({authMode:"password",oidcIssuerUrl:"",oidcClientId:"",oidcScopes:"openid profile email",oidcLoginLabel:"Sign in with OIDC"}),[X,Z]=o.useState(""),[ee,A]=o.useState({type:"",message:""}),[L,ne]=o.useState(!1),[ve,ce]=o.useState(!1),[se,I]=o.useState({type:"",message:""}),[Ne,_e]=o.useState("/api/auth/oidc/callback"),[de,me]=o.useState(!1),K=o.useRef(null),[J,z]=o.useState({outboundProxyEnabled:!1,outboundProxyUrl:"",outboundNoProxy:""}),[te,y]=o.useState({type:"",message:""}),[$,G]=o.useState(!1),[ke,xe]=o.useState(!1),[l,j]=o.useState({codebuddy_auto_fsrouter:!1,codebuddy_leave_canva_team:!1,codebuddy_browser_headless:!0,codebuddy_proxy_enabled:!1,codebuddy_proxy_server:"",codebuddy_proxy_username:"",codebuddy_proxy_password:"",fsmail_base_url:"",fsmail_api_key:"",fsmail_default_domain:"",fsmail_webhook_secret:""}),[ae,f]=o.useState({type:"",message:""}),[w,ue]=o.useState(!1),[Ce,pe]=o.useState(!1),[Se,be]=o.useState(!1),[fe,Pe]=o.useState(!1);o.useEffect(()=>{P(rs())},[U]),o.useEffect(()=>{fetch("/api/settings").then(s=>s.json()).then(s=>{x(s),Q({authMode:(s==null?void 0:s.authMode)||"password",oidcIssuerUrl:(s==null?void 0:s.oidcIssuerUrl)||"",oidcClientId:(s==null?void 0:s.oidcClientId)||"",oidcScopes:(s==null?void 0:s.oidcScopes)||"openid profile email",oidcLoginLabel:(s==null?void 0:s.oidcLoginLabel)||"Sign in with OIDC"}),Z(""),((s==null?void 0:s.authMode)==="oidc"||(s==null?void 0:s.authMode)==="both")&&me(!0),z({outboundProxyEnabled:(s==null?void 0:s.outboundProxyEnabled)===!0,outboundProxyUrl:(s==null?void 0:s.outboundProxyUrl)||"",outboundNoProxy:(s==null?void 0:s.outboundNoProxy)||""}),j({codebuddy_auto_fsrouter:(s==null?void 0:s.codebuddy_auto_fsrouter)==="1",codebuddy_leave_canva_team:(s==null?void 0:s.codebuddy_leave_canva_team)==="1",codebuddy_browser_headless:(s==null?void 0:s.codebuddy_browser_headless)!=="0",codebuddy_proxy_enabled:(s==null?void 0:s.codebuddy_proxy_enabled)==="1",codebuddy_proxy_server:(s==null?void 0:s.codebuddy_proxy_server)||"",codebuddy_proxy_username:(s==null?void 0:s.codebuddy_proxy_username)||"",codebuddy_proxy_password:(s==null?void 0:s.codebuddy_proxy_password)||"",fsmail_base_url:(s==null?void 0:s.fsmail_base_url)||"",fsmail_api_key:(s==null?void 0:s.fsmail_api_key)||"",fsmail_default_domain:(s==null?void 0:s.fsmail_default_domain)||"",fsmail_webhook_secret:(s==null?void 0:s.fsmail_webhook_secret)||""}),B(!1)}).catch(s=>{console.error("Failed to fetch settings:",s),B(!1)})},[]),o.useEffect(()=>{typeof window<"u"&&_e(`${window.location.origin}/api/auth/oidc/callback`)},[]);const Oe=async s=>{ue(!0),f({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({codebuddy_auto_fsrouter:l.codebuddy_auto_fsrouter?"1":"0",codebuddy_leave_canva_team:l.codebuddy_leave_canva_team?"1":"0",codebuddy_browser_headless:l.codebuddy_browser_headless?"1":"0",codebuddy_proxy_enabled:l.codebuddy_proxy_enabled?"1":"0",codebuddy_proxy_server:l.codebuddy_proxy_server,codebuddy_proxy_username:l.codebuddy_proxy_username,codebuddy_proxy_password:l.codebuddy_proxy_password,fsmail_base_url:l.fsmail_base_url,fsmail_api_key:l.fsmail_api_key,fsmail_default_domain:l.fsmail_default_domain,fsmail_webhook_secret:l.fsmail_webhook_secret})}),a=await t.json();t.ok?(x(n=>({...n,...a})),f({type:"success",message:"Automation settings saved successfully."})):f({type:"error",message:a.error||"Failed to update automation settings"})}catch{f({type:"error",message:"An error occurred"})}finally{ue(!1)}},Le=async()=>{pe(!0),f({type:"",message:""});try{const s=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({fsmail_base_url:l.fsmail_base_url,fsmail_api_key:l.fsmail_api_key,fsmail_default_domain:l.fsmail_default_domain,fsmail_webhook_secret:l.fsmail_webhook_secret})});if(!s.ok){const n=await s.json().catch(()=>({}));f({type:"error",message:n.error||"Failed to save settings before testing connection"});return}const t=await fetch("/api/automation/fsmail",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"test-connection"})}),a=await t.json().catch(()=>({}));t.ok?f({type:"success",message:"FSMail Connection Successful!"}):f({type:"error",message:a.error||"FSMail Connection Failed."})}catch(s){f({type:"error",message:s.message||"An error occurred"})}finally{pe(!1)}},Ie=async()=>{var s;be(!0),f({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({fsmail_base_url:l.fsmail_base_url,fsmail_api_key:l.fsmail_api_key,fsmail_default_domain:l.fsmail_default_domain,fsmail_webhook_secret:l.fsmail_webhook_secret})});if(!t.ok){const b=await t.json().catch(()=>({}));f({type:"error",message:b.error||"Failed to save settings before registering webhook"});return}const a=await fetch("/api/automation/fsmail",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"webhook-register"})}),n=await a.json().catch(()=>({}));a.ok?(f({type:"success",message:"FSMail Webhook Registered Successfully!"}),(s=n.webhook)!=null&&s.secret&&j(b=>({...b,fsmail_webhook_secret:n.webhook.secret}))):f({type:"error",message:n.error||"FSMail Webhook Registration Failed."})}catch(t){f({type:"error",message:t.message||"An error occurred"})}finally{be(!1)}},Te=async s=>{if(s.preventDefault(),r.outboundProxyEnabled===!0){G(!0),y({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({outboundProxyUrl:J.outboundProxyUrl,outboundNoProxy:J.outboundNoProxy})}),a=await t.json();t.ok?(x(n=>({...n,...a})),y({type:"success",message:"Proxy settings applied"})):y({type:"error",message:a.error||"Failed to update proxy settings"})}catch{y({type:"error",message:"An error occurred"})}finally{G(!1)}}},Re=async()=>{if(r.outboundProxyEnabled!==!0)return;const s=(J.outboundProxyUrl||"").trim();if(!s){y({type:"error",message:"Please enter a Proxy URL to test"});return}xe(!0),y({type:"",message:""});try{const t=await fetch("/api/settings/proxy-test",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({proxyUrl:s})}),a=await t.json();t.ok&&(a!=null&&a.ok)?y({type:"success",message:`Proxy test OK (${a.status}) in ${a.elapsedMs}ms`}):y({type:"error",message:(a==null?void 0:a.error)||"Proxy test failed"})}catch{y({type:"error",message:"An error occurred"})}finally{xe(!1)}},Fe=async s=>{G(!0),y({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({outboundProxyEnabled:s})}),a=await t.json();t.ok?(x(n=>({...n,...a})),z(n=>({...n,outboundProxyEnabled:(a==null?void 0:a.outboundProxyEnabled)===!0})),y({type:"success",message:s?"Proxy enabled":"Proxy disabled"})):y({type:"error",message:a.error||"Failed to update proxy settings"})}catch{y({type:"error",message:"An error occurred"})}finally{G(!1)}},De=async s=>{if(s.preventDefault(),c.new!==c.confirm){M({type:"error",message:"Passwords do not match"});return}ie(!0),M({type:"",message:""});try{const t=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({currentPassword:c.current,newPassword:c.new})}),a=await t.json();t.ok?(M({type:"success",message:"Password updated successfully"}),N({current:"",new:"",confirm:""})):M({type:"error",message:a.error||"Failed to update password"})}catch{M({type:"error",message:"An error occurred"})}finally{ie(!1)}},Ae=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({fallbackStrategy:s})})).ok&&x(a=>({...a,fallbackStrategy:s}))}catch(t){console.error("Failed to update settings:",t)}},Ue=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({comboStrategy:s})})).ok&&x(a=>({...a,comboStrategy:s}))}catch(t){console.error("Failed to update combo strategy:",t)}},Ee=async s=>{const t=parseInt(s);if(!(isNaN(t)||t<1))try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({stickyRoundRobinLimit:t})})).ok&&x(n=>({...n,stickyRoundRobinLimit:t}))}catch(a){console.error("Failed to update sticky limit:",a)}},Me=async s=>{const t=parseInt(s);if(!(isNaN(t)||t<1))try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({comboStickyRoundRobinLimit:t})})).ok&&x(n=>({...n,comboStickyRoundRobinLimit:t}))}catch(a){console.error("Failed to update combo sticky limit:",a)}},Je=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({requireLogin:s})})).ok&&x(a=>({...a,requireLogin:s}))}catch(t){console.error("Failed to update require login:",t)}},q=(s,t)=>{Q(a=>({...a,[s]:t}))},$e=async(s=p.authMode||"password")=>{const t=p.oidcIssuerUrl.trim(),a=p.oidcClientId.trim(),n=p.oidcScopes.trim(),b=p.oidcLoginLabel.trim(),u=X.trim();if(s!=="password"&&(!t||!a||!u)&&!r.oidcConfigured){A({type:"error",message:"Issuer URL, client ID, and client secret are required to enable OIDC."});return}ne(!0),A({type:"",message:""}),I({type:"",message:""});try{const _={authMode:s,oidcIssuerUrl:t,oidcClientId:a,oidcScopes:n||"openid profile email",oidcLoginLabel:b||"Sign in with OIDC"};u&&(_.oidcClientSecret=u);const h=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(_)}),d=await h.json();h.ok?(x(Ye=>({...Ye,...d})),Q({authMode:(d==null?void 0:d.authMode)||s,oidcIssuerUrl:(d==null?void 0:d.oidcIssuerUrl)||t,oidcClientId:(d==null?void 0:d.oidcClientId)||a,oidcScopes:(d==null?void 0:d.oidcScopes)||n||"openid profile email",oidcLoginLabel:(d==null?void 0:d.oidcLoginLabel)||b||"Sign in with OIDC"}),Z(""),A({type:"success",message:s==="oidc"?"OIDC login enabled":s==="both"?"Password and OIDC login enabled":"OIDC settings saved"})):A({type:"error",message:d.error||"Failed to save OIDC settings"})}catch{A({type:"error",message:"An error occurred"})}finally{ne(!1)}},qe=async()=>{const s=p.oidcIssuerUrl.trim(),t=p.oidcClientId.trim(),a=p.oidcScopes.trim(),n=X.trim();if(!s||!t){I({type:"error",message:"Issuer URL and client ID are required to test the connection."});return}ce(!0),A({type:"",message:""}),I({type:"",message:""});try{const b=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({authMode:p.authMode||r.authMode||"password",oidcIssuerUrl:s,oidcClientId:t,oidcScopes:a||"openid profile email",oidcLoginLabel:p.oidcLoginLabel.trim()||"Sign in with OIDC",...n?{oidcClientSecret:n}:{}})}),u=await b.json().catch(()=>({}));if(!b.ok){I({type:"error",message:u.error||"Failed to save OIDC settings before testing"});return}const _=await fetch("/api/auth/oidc/test",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({issuerUrl:u.oidcIssuerUrl||s,clientId:u.oidcClientId||t,scopes:u.oidcScopes||a||"openid profile email"})}),h=await _.json().catch(()=>({}));if(_.ok&&(h!=null&&h.ok)){const d=h.clientSecretTested?h.clientSecretValid===!0?`Connection OK. Discovery loaded from ${h.issuerUrl}. Client secret validated too.`:`Connection OK. Discovery loaded from ${h.issuerUrl}. Client secret was not checked.`:`Connection OK. Discovery loaded from ${h.issuerUrl}.`;I({type:"success",message:d})}else I({type:"error",message:h.error||"OIDC connection test failed"})}catch{I({type:"error",message:"An error occurred"})}finally{ce(!1)}},He=async s=>{try{(await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({enableObservability:s})})).ok&&x(a=>({...a,enableObservability:s}))}catch(t){console.error("Failed to update enableObservability:",t)}},Be=async()=>{try{const s=await fetch("/api/settings");if(!s.ok)return;const t=await s.json();x(t)}catch(s){console.error("Failed to reload settings:",s)}},We=async()=>{W(!0),D({type:"",message:""});try{const s=await fetch("/api/settings/database");if(!s.ok){const h=await s.json().catch(()=>({}));throw new Error(h.error||"Failed to export database")}const t=await s.json(),a=JSON.stringify(t,null,2),n=new Blob([a],{type:"application/json"}),b=URL.createObjectURL(n),u=document.createElement("a"),_=new Date().toISOString().replace(/[.:]/g,"-");u.href=b,u.download=`fsrouter-backup-${_}.json`,document.body.appendChild(u),u.click(),document.body.removeChild(u),URL.revokeObjectURL(b),D({type:"success",message:"Database backup downloaded"})}catch(s){D({type:"error",message:s.message||"Failed to export database"})}finally{W(!1)}},Ke=async s=>{var a;const t=(a=s.target.files)==null?void 0:a[0];if(t){W(!0),D({type:"",message:""});try{const n=await t.text(),b=JSON.parse(n),u=await fetch("/api/settings/database",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(b)}),_=await u.json().catch(()=>({}));if(!u.ok)throw new Error(_.error||"Failed to import database");await Be(),D({type:"success",message:"Database imported successfully"})}catch(n){D({type:"error",message:n.message||"Invalid backup file"})}finally{K.current&&(K.current.value=""),W(!1)}}},ze=r.enableObservability===!0,Ge=async()=>{F(!0);try{await fetch("/api/version/shutdown",{method:"POST"})}catch{}F(!1),E(!1)},Ve=async()=>{try{(await fetch("/api/auth/logout",{method:"POST"})).ok&&(localStorage.removeItem("9r_authed"),g("/login"),g(0))}catch(s){console.error("Failed to logout:",s)}};return e.jsxs("div",{className:"max-w-2xl mx-auto px-4 sm:px-0",children:[e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsxs(T,{children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-4",children:[e.jsxs("div",{className:"flex items-center gap-3 sm:gap-4",children:[e.jsx("div",{className:"size-10 sm:size-12 rounded-lg bg-green-500/10 text-green-500 flex items-center justify-center shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-xl sm:text-2xl",children:"computer"})}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg sm:text-xl font-semibold",children:"Local Mode"}),e.jsx("p",{className:"text-sm text-text-muted",children:"Running on your machine"})]})]}),e.jsx("div",{className:"inline-flex p-1 rounded-lg bg-black/5 dark:bg-white/5 w-full sm:w-auto",children:["light","dark","system"].map(s=>e.jsxs("button",{type:"button",onClick:()=>S(s),className:he("flex items-center justify-center gap-1 sm:gap-1.5 px-2 sm:px-3 py-1.5 rounded-md font-medium transition-all flex-1 sm:flex-initial",k===s?"bg-white dark:bg-white/10 text-text-main shadow-sm":"text-text-muted hover:text-text-main"),children:[e.jsx("span",{className:"material-symbols-outlined text-[18px]",children:s==="light"?"light_mode":s==="dark"?"dark_mode":"contrast"}),e.jsx("span",{className:"capitalize text-xs sm:text-sm",children:s})]},s))})]}),e.jsxs("div",{className:"flex flex-col gap-3 pt-4 border-t border-border",children:[e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between p-3 rounded-lg bg-bg border border-border gap-2",children:e.jsxs("div",{children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Database Location"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted font-mono break-all",children:"~/.fsrouter/db/data.sqlite"})]})}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsx(v,{variant:"secondary",icon:"download",onClick:We,loading:le,className:"w-full sm:w-auto",children:"Download Backup"}),e.jsx(v,{variant:"outline",icon:"upload",onClick:()=>{var s;return(s=K.current)==null?void 0:s.click()},disabled:le,className:"w-full sm:w-auto",children:"Import Backup"}),e.jsx("input",{ref:K,type:"file",accept:"application/json,.json",className:"hidden",onChange:Ke})]}),Y.message&&e.jsx("p",{className:`text-sm ${Y.type==="error"?"text-red-500":"text-green-600 dark:text-green-400"}`,children:Y.message})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-primary/10 text-primary shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"shield"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Security"})]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Require login"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"When ON, dashboard requires password. When OFF, access without login."})]}),e.jsx(C,{checked:r.requireLogin===!0,onChange:()=>Je(!r.requireLogin),disabled:i})]}),r.requireLogin===!0&&e.jsxs("form",{onSubmit:De,className:"flex flex-col gap-4 pt-4 border-t border-border/50",children:[r.hasPassword&&e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"text-xs sm:text-sm font-medium",children:"Current Password"}),e.jsx(m,{type:"password",placeholder:"Enter current password",value:c.current,onChange:s=>N({...c,current:s.target.value}),required:!0})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"text-xs sm:text-sm font-medium",children:"New Password"}),e.jsx(m,{type:"password",placeholder:"Enter new password",value:c.new,onChange:s=>N({...c,new:s.target.value}),required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"text-xs sm:text-sm font-medium",children:"Confirm New Password"}),e.jsx(m,{type:"password",placeholder:"Confirm new password",value:c.confirm,onChange:s=>N({...c,confirm:s.target.value}),required:!0})]})]}),O.message&&e.jsx("p",{className:`text-xs sm:text-sm ${O.type==="error"?"text-red-500":"text-green-500"}`,children:O.message}),e.jsx("div",{className:"pt-2",children:e.jsx(v,{type:"submit",variant:"primary",loading:we,className:"w-full sm:w-auto",children:r.hasPassword?"Update Password":"Set Password"})})]})]})]}),e.jsxs(T,{children:[e.jsxs("button",{type:"button",onClick:()=>me(s=>!s),className:"w-full flex items-center gap-3 text-left",children:[e.jsx("div",{className:"p-2 rounded-lg bg-indigo-500/10 text-indigo-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"lock_open"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"OIDC Dashboard Login"}),e.jsx("p",{className:"text-xs text-text-muted",children:r.authMode==="oidc"?"OIDC active":r.authMode==="both"?"Password + OIDC active":"Optional SSO via Authentik/Keycloak/Google"})]}),e.jsx("span",{className:"material-symbols-outlined text-text-muted shrink-0",children:de?"expand_less":"expand_more"})]}),de&&e.jsxs("div",{className:"flex flex-col gap-4 mt-4",children:[e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Use Authentik or any OIDC provider to sign in to the dashboard. You can enable password-only, OIDC-only, or both for the dashboard; model API access still uses API keys."}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Auth Mode"}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-2",children:[{value:"password",title:"Password only",desc:"Keep the legacy password login."},{value:"oidc",title:"OIDC only",desc:"Require OIDC for dashboard access."},{value:"both",title:"Both",desc:"Allow either password or OIDC."}].map(s=>{const t=p.authMode===s.value;return e.jsxs("button",{type:"button",onClick:()=>q("authMode",s.value),className:he("text-left rounded-lg border p-3 transition-colors",t?"border-primary bg-primary/5":"border-border bg-bg hover:bg-black/5 dark:hover:bg-white/5"),disabled:i||L,children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:s.title}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted mt-1",children:s.desc})]},s.value)})})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Issuer URL"}),e.jsx(m,{placeholder:"https://auth.example.com/application/o/fsrouter/",value:p.oidcIssuerUrl,onChange:s=>q("oidcIssuerUrl",s.target.value),disabled:i||L})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Client ID"}),e.jsx(m,{placeholder:"fsrouter-dashboard",value:p.oidcClientId,onChange:s=>q("oidcClientId",s.target.value),disabled:i||L})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Client Secret"}),e.jsx(m,{type:"password",placeholder:"Leave blank to keep existing secret",value:X,onChange:s=>Z(s.target.value),disabled:i||L}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"This value is write-only after saving."})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Scopes"}),e.jsx(m,{placeholder:"openid profile email",value:p.oidcScopes,onChange:s=>q("oidcScopes",s.target.value),disabled:i||L})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Login Button Label"}),e.jsx(m,{placeholder:"Sign in with OIDC",value:p.oidcLoginLabel,onChange:s=>q("oidcLoginLabel",s.target.value),disabled:i||L})]})]}),e.jsxs("div",{className:"rounded-lg border border-border bg-bg p-3 text-xs sm:text-sm text-text-muted",children:[e.jsx("p",{className:"font-medium text-text-main mb-1",children:"Redirect URI"}),e.jsx("code",{className:"block break-all font-mono",children:Ne})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-2 border-t border-border/50",children:[e.jsx(v,{type:"button",variant:"primary",loading:L,onClick:()=>$e(),className:"w-full sm:w-auto",children:"Save auth mode"}),e.jsx(v,{type:"button",variant:"outline",loading:ve,onClick:qe,className:"w-full sm:w-auto",children:"Test connection"})]}),se.message&&e.jsx("p",{className:`text-xs sm:text-sm ${se.type==="error"?"text-red-500":"text-green-500"}`,children:se.message}),ee.message&&e.jsx("p",{className:`text-xs sm:text-sm ${ee.type==="error"?"text-red-500":"text-green-500"}`,children:ee.message}),r.authMode==="oidc"&&e.jsx("p",{className:"text-xs sm:text-sm text-amber-600 dark:text-amber-400",children:"OIDC login is currently active. Password login is disabled until you switch back."}),r.authMode==="both"&&e.jsx("p",{className:"text-xs sm:text-sm text-amber-600 dark:text-amber-400",children:"Password and OIDC login are both active."})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-blue-500/10 text-blue-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"route"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Routing Strategy"})]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Round Robin"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Cycle through accounts to distribute load"})]}),e.jsx(C,{checked:r.fallbackStrategy==="round-robin",onChange:()=>Ae(r.fallbackStrategy==="round-robin"?"fill-first":"round-robin"),disabled:i})]}),r.fallbackStrategy==="round-robin"&&e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Sticky Limit"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Calls per account before switching"})]}),e.jsx(m,{type:"number",min:"1",max:"10",value:r.stickyRoundRobinLimit||3,onChange:s=>Ee(s.target.value),disabled:i,className:"w-16 sm:w-20 text-center shrink-0"})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-4 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Combo Round Robin"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Cycle through providers in combos instead of always starting with first"})]}),e.jsx(C,{checked:r.comboStrategy==="round-robin",onChange:()=>Ue(r.comboStrategy==="round-robin"?"fallback":"round-robin"),disabled:i})]}),r.comboStrategy==="round-robin"&&e.jsxs("div",{className:"flex items-center justify-between pt-2 border-t border-border/50",children:[e.jsxs("div",{children:[e.jsx("p",{className:"font-medium",children:"Combo Sticky Limit"}),e.jsx("p",{className:"text-sm text-text-muted",children:"Calls per combo model before switching"})]}),e.jsx(m,{type:"number",min:"1",max:"100",value:r.comboStickyRoundRobinLimit||1,onChange:s=>Me(s.target.value),disabled:i,className:"w-20 text-center"})]}),e.jsxs("p",{className:"text-xs text-text-muted italic pt-2 border-t border-border/50",children:[r.fallbackStrategy==="round-robin"?`Currently distributing requests across all available accounts with ${r.stickyRoundRobinLimit||3} calls per account.`:"Currently using accounts in priority order (Fill First).",r.comboStrategy==="round-robin"?` Combos rotate after ${r.comboStickyRoundRobinLimit||1} call${(r.comboStickyRoundRobinLimit||1)===1?"":"s"} per model.`:" Combos always start with their first model."]})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-purple-500/10 text-purple-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"wifi"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Network"})]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Outbound Proxy"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Enable proxy for OAuth + provider outbound requests."})]}),e.jsx(C,{checked:r.outboundProxyEnabled===!0,onChange:()=>Fe(r.outboundProxyEnabled!==!0),disabled:i||$})]}),r.outboundProxyEnabled===!0&&e.jsxs("form",{onSubmit:Te,className:"flex flex-col gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Proxy URL"}),e.jsx(m,{placeholder:"http://127.0.0.1:7897",value:J.outboundProxyUrl,onChange:s=>z(t=>({...t,outboundProxyUrl:s.target.value})),disabled:i||$}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Leave empty to inherit existing env proxy (if any)."})]}),e.jsxs("div",{className:"flex flex-col gap-2 pt-2 border-t border-border/50",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"No Proxy"}),e.jsx(m,{placeholder:"localhost,127.0.0.1",value:J.outboundNoProxy,onChange:s=>z(t=>({...t,outboundNoProxy:s.target.value})),disabled:i||$}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Comma-separated hostnames/domains to bypass the proxy."})]}),e.jsxs("div",{className:"pt-2 border-t border-border/50 flex flex-col sm:flex-row items-stretch sm:items-center gap-2",children:[e.jsx(v,{type:"button",variant:"secondary",loading:ke,disabled:i||$,onClick:Re,className:"w-full sm:w-auto",children:"Test proxy URL"}),e.jsx(v,{type:"submit",variant:"primary",loading:$,className:"w-full sm:w-auto",children:"Apply"})]})]}),te.message&&e.jsx("p",{className:`text-xs sm:text-sm ${te.type==="error"?"text-red-500":"text-green-500"} pt-2 border-t border-border/50`,children:te.message})]})]}),e.jsxs(T,{children:[e.jsxs("button",{type:"button",onClick:()=>Pe(s=>!s),className:"w-full flex items-center gap-3 text-left focus:outline-none",children:[e.jsx("div",{className:"p-2 rounded-lg bg-emerald-500/10 text-emerald-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"smart_toy"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Automation Settings"}),e.jsx("p",{className:"text-xs text-text-muted",children:"Manage CodeBuddy browser signup & FSMail temporary email configurations."})]}),e.jsx("span",{className:"material-symbols-outlined text-text-muted shrink-0",children:fe?"expand_less":"expand_more"})]}),fe&&e.jsxs("div",{className:"flex flex-col gap-4 mt-4",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("h4",{className:"font-semibold text-sm text-text-main flex items-center gap-1.5 border-b border-border/55 pb-1",children:[e.jsx("span",{className:"material-symbols-outlined text-[16px]",children:"smart_toy"}),"CodeBuddy API Gen Settings"]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Headless Browser"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Run the automated signup browser in headless mode (no visual window)."})]}),e.jsx(C,{checked:l.codebuddy_browser_headless,onChange:s=>j(t=>({...t,codebuddy_browser_headless:s})),disabled:i||w})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Auto Inject to fsrouter"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Automatically add newly generated CodeBuddy API keys to fsrouter connections."})]}),e.jsx(C,{checked:l.codebuddy_auto_fsrouter,onChange:s=>j(t=>({...t,codebuddy_auto_fsrouter:s})),disabled:i||w})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Leave Canva Team after Leonardo Registration"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Automatically leave the Canva team after completing Leonardo registration to free up team invite slots."})]}),e.jsx(C,{checked:l.codebuddy_leave_canva_team,onChange:s=>j(t=>({...t,codebuddy_leave_canva_team:s})),disabled:i||w})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Use Outbound Proxy"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Route the automation browser traffic through a proxy server."})]}),e.jsx(C,{checked:l.codebuddy_proxy_enabled,onChange:s=>j(t=>({...t,codebuddy_proxy_enabled:s})),disabled:i||w})]}),l.codebuddy_proxy_enabled&&e.jsxs("div",{className:"flex flex-col gap-3 pl-4 border-l-2 border-primary/20 pt-2",children:[e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-xs font-medium text-text-main",children:"Proxy Server"}),e.jsx(m,{placeholder:"host:port (e.g. 127.0.0.1:8080)",value:l.codebuddy_proxy_server,onChange:s=>j(t=>({...t,codebuddy_proxy_server:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-xs font-medium text-text-main",children:"Proxy Username (Optional)"}),e.jsx(m,{placeholder:"username",value:l.codebuddy_proxy_username,onChange:s=>j(t=>({...t,codebuddy_proxy_username:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-xs font-medium text-text-main",children:"Proxy Password (Optional)"}),e.jsx(m,{type:"password",placeholder:"password",value:l.codebuddy_proxy_password,onChange:s=>j(t=>({...t,codebuddy_proxy_password:s.target.value})),disabled:i||w})]})]})]})]}),e.jsxs("div",{className:"space-y-4 pt-4 border-t border-border/55",children:[e.jsxs("h4",{className:"font-semibold text-sm text-text-main flex items-center gap-1.5 border-b border-border/55 pb-1",children:[e.jsx("span",{className:"material-symbols-outlined text-[16px]",children:"mail"}),"FSMail Temp Mail Settings"]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Base URL"}),e.jsx(m,{placeholder:"https://fsmail.example.com",value:l.fsmail_base_url,onChange:s=>j(t=>({...t,fsmail_base_url:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"API Key"}),e.jsx(m,{type:"password",placeholder:"FSMail API Key",value:l.fsmail_api_key,onChange:s=>j(t=>({...t,fsmail_api_key:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Default Domain"}),e.jsx(m,{placeholder:"example.com",value:l.fsmail_default_domain,onChange:s=>j(t=>({...t,fsmail_default_domain:s.target.value})),disabled:i||w})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("label",{className:"font-medium text-sm sm:text-base",children:"Webhook Secret"}),e.jsx(m,{type:"password",placeholder:"Leave empty to auto-generate",value:l.fsmail_webhook_secret,onChange:s=>j(t=>({...t,fsmail_webhook_secret:s.target.value})),disabled:i||w})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-4 border-t border-border/50",children:[e.jsx(v,{type:"button",variant:"primary",loading:w,onClick:()=>Oe(),className:"w-full sm:w-auto",children:"Save Settings"}),e.jsx(v,{type:"button",variant:"secondary",loading:Ce,onClick:Le,className:"w-full sm:w-auto",children:"Test FSMail Connection"}),e.jsx(v,{type:"button",variant:"outline",loading:Se,onClick:Ie,className:"w-full sm:w-auto",children:"Register Webhook"})]}),ae.message&&e.jsx("p",{className:`text-xs sm:text-sm ${ae.type==="error"?"text-red-500":"text-green-500"} pt-2 border-t border-border/50`,children:ae.message})]})]}),e.jsxs(T,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-orange-500/10 text-orange-500 shrink-0",children:e.jsx("span",{className:"material-symbols-outlined text-[20px]",children:"monitoring"})}),e.jsx("h3",{className:"text-base sm:text-lg font-semibold",children:"Observability"})]}),e.jsxs("div",{className:"flex items-start sm:items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-sm sm:text-base",children:"Enable Observability"}),e.jsx("p",{className:"text-xs sm:text-sm text-text-muted",children:"Record request details for inspection in the logs view"})]}),e.jsx(C,{checked:ze,onChange:He,disabled:i})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsx(v,{variant:"outline",fullWidth:!0,icon:"power_settings_new",onClick:()=>E(!0),className:"text-red-500 border-red-200 hover:bg-red-50 hover:border-red-300",children:"Shutdown"}),e.jsx(v,{variant:"outline",fullWidth:!0,icon:"logout",onClick:Ve,children:"Logout"})]}),e.jsxs("div",{className:"text-center text-xs sm:text-sm text-text-muted py-4",children:[e.jsxs("p",{children:[ge.name," v",ge.version]}),e.jsx("p",{className:"mt-1",children:"Local Mode - All data stored on your machine"})]})]}),e.jsx(os,{hideTrigger:!0,isOpen:U,onClose:s=>{R(!1),P(s)}}),e.jsx(es,{isOpen:H,onClose:()=>E(!1),onConfirm:Ge,title:"Close Proxy",message:"Are you sure you want to close the proxy server?",confirmText:"Close",cancelText:"Cancel",variant:"danger",loading:V})]})}export{ds as default};
@@ -1,4 +1,4 @@
1
- import{u as ze,j as e,M as Ue,B as q,w as De,x as Be,y as ke,z as He,h as We}from"./index.CShjRV_B.js";import{b as t,L as Te,h as Je,N as qe}from"./router.Cjj1--8t.js";import{C as Le}from"./cliTools.CsdwAybi.js";import{g as Pe}from"./machine.CagOtseJ.js";import{I as Ge,M as fe,C as ge}from"./NoAuthProxyCard.qAv57b-0.js";import{C as Ve}from"./Loading.Bj-WGl4k.js";import"./zustand.akaTi5uX.js";function ye({isOpen:d,onClose:r,title:L="Manual Configuration",configs:Y=[]}){const{copy:g}=ze(),[l,A]=t.useState(null),O=(E,_)=>{g(E,`manualconfig-${_}`),A(_),setTimeout(()=>A(null),2e3)};return e.jsx(Ue,{isOpen:d,onClose:r,title:L,size:"xl",children:e.jsx("div",{className:"flex flex-col gap-4",children:Y.map((E,_)=>e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm font-medium text-text-main",children:E.filename}),e.jsxs(q,{variant:"ghost",size:"sm",onClick:()=>O(E.content,_),children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:l===_?"check":"content_copy"}),l===_?"Copied!":"Copy"]})]}),e.jsx("pre",{className:"px-3 py-2 bg-black/5 dark:bg-white/5 rounded font-mono text-xs overflow-x-auto whitespace-pre-wrap break-all max-h-60 overflow-y-auto border border-border",children:E.content})]},_))})})}const Ye=/^[a-zA-Z0-9_.\-]+$/;function Xe({index:d,model:r,isFirst:L,isLast:Y,onEdit:g,onMoveUp:l,onMoveDown:A,onRemove:O}){const[E,_]=t.useState(!1),[B,U]=t.useState(r),o=()=>{const i=B.trim();i&&i!==r?g(i):U(r),_(!1)},s=i=>{i.key==="Enter"&&o(),i.key==="Escape"&&(U(r),_(!1))};return e.jsxs("div",{className:"group flex min-w-0 items-center gap-1.5 rounded-md bg-black/[0.02] px-2 py-1 transition-colors hover:bg-black/[0.04] dark:bg-white/[0.02] dark:hover:bg-white/[0.04]",children:[e.jsx("span",{className:"text-[10px] font-medium text-text-muted w-3 text-center shrink-0",children:d+1}),E?e.jsx("input",{autoFocus:!0,value:B,onChange:i=>U(i.target.value),onBlur:o,onKeyDown:s,className:"min-w-0 flex-1 rounded border border-primary/40 bg-white px-1.5 py-0.5 font-mono text-xs text-text-main outline-none dark:bg-black/20"}):e.jsx("div",{className:"min-w-0 flex-1 cursor-text truncate rounded px-1.5 py-0.5 font-mono text-xs text-text-main hover:bg-black/5 dark:hover:bg-white/5",onClick:()=>_(!0),title:"Click to edit",children:r}),e.jsxs("div",{className:"flex shrink-0 items-center gap-0.5",children:[e.jsx("button",{onClick:l,disabled:L,className:`p-0.5 rounded ${L?"text-text-muted/20 cursor-not-allowed":"text-text-muted hover:text-primary hover:bg-black/5 dark:hover:bg-white/5"}`,title:"Move up",children:e.jsx("span",{className:"material-symbols-outlined text-[12px]",children:"arrow_upward"})}),e.jsx("button",{onClick:A,disabled:Y,className:`p-0.5 rounded ${Y?"text-text-muted/20 cursor-not-allowed":"text-text-muted hover:text-primary hover:bg-black/5 dark:hover:bg-white/5"}`,title:"Move down",children:e.jsx("span",{className:"material-symbols-outlined text-[12px]",children:"arrow_downward"})})]}),e.jsx("button",{onClick:O,className:"p-0.5 hover:bg-red-500/10 rounded text-text-muted hover:text-red-500 transition-all",title:"Remove",children:e.jsx("span",{className:"material-symbols-outlined text-[12px]",children:"close"})})]})}function Qe({isOpen:d,combo:r,onClose:L,onSave:Y,activeProviders:g,kindFilter:l=null,forcePrefix:A="",title:O}){const E=r!=null&&r.name?A&&r.name.startsWith(A)?r.name.slice(A.length):r.name:"",[_,B]=t.useState(E),[U,o]=t.useState((r==null?void 0:r.models)||[]),[s,i]=t.useState(!1),[M,Q]=t.useState(!1),[P,K]=t.useState(""),[ee,W]=t.useState({});t.useEffect(()=>{d&&fetch("/api/models/alias").then(m=>m.ok?m.json():null).then(m=>m&&W(m.aliases||{})).catch(()=>{})},[d]);const b=m=>{if(!m.trim())return K("Name is required"),!1;const h=A+m;return Ye.test(h)?(K(""),!0):(K("Only letters, numbers, -, _ and . allowed"),!1)},y=m=>{let h=m.target.value;A&&h.startsWith(A)&&(h=h.slice(A.length)),B(h),h?b(h):K("")},w=m=>{U.includes(m.value)||o([...U,m.value])},x=m=>{o(U.filter(h=>h!==m.value))},C=m=>o(U.filter((h,v)=>v!==m)),j=m=>{if(m===0)return;const h=[...U];[h[m-1],h[m]]=[h[m],h[m-1]],o(h)},T=m=>{if(m===U.length-1)return;const h=[...U];[h[m],h[m+1]]=[h[m+1],h[m]],o(h)},p=async()=>{b(_)&&(Q(!0),await Y({name:A+_.trim(),models:U}),Q(!1))},a=!!r;return e.jsxs(e.Fragment,{children:[e.jsx(Ue,{isOpen:d,onClose:L,title:O||(a?"Edit Combo":"Create Combo"),children:e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{children:[A?e.jsxs(e.Fragment,{children:[e.jsx("label",{className:"text-sm font-medium mb-1 block",children:"Combo Name"}),e.jsxs("div",{className:"flex items-stretch",children:[e.jsx("span",{className:"inline-flex items-center px-2 rounded-l border border-r-0 border-black/10 dark:border-white/10 bg-black/[0.04] dark:bg-white/[0.04] text-text-muted font-mono text-sm",children:A}),e.jsx("input",{value:_,onChange:y,placeholder:"my-combo",className:"flex-1 min-w-0 rounded-r border border-black/10 dark:border-white/10 bg-white dark:bg-black/20 px-2 py-1.5 font-mono text-sm outline-none focus:border-primary"})]}),P&&e.jsx("p",{className:"text-[11px] text-red-500 mt-0.5",children:P})]}):e.jsx(Ge,{label:"Combo Name",value:_,onChange:y,placeholder:"my-combo",error:P}),e.jsxs("p",{className:"text-[10px] text-text-muted mt-0.5",children:[A?`Auto-prefixed with "${A}". `:"","Only letters, numbers, -, _ and . allowed"]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium mb-1.5 block",children:"Models"}),U.length===0?e.jsxs("div",{className:"text-center py-4 border border-dashed border-black/10 dark:border-white/10 rounded-lg bg-black/[0.01] dark:bg-white/[0.01]",children:[e.jsx("span",{className:"material-symbols-outlined text-text-muted text-xl mb-1",children:"layers"}),e.jsx("p",{className:"text-xs text-text-muted",children:"No models added yet"})]}):e.jsx("div",{className:"flex max-h-[55vh] min-w-0 flex-col gap-1 overflow-y-auto sm:max-h-[350px]",children:U.map((m,h)=>e.jsx(Xe,{index:h,model:m,isFirst:h===0,isLast:h===U.length-1,onEdit:v=>{const I=[...U];I[h]=v,o(I)},onMoveUp:()=>j(h),onMoveDown:()=>T(h),onRemove:()=>C(h)},h))}),e.jsxs("button",{onClick:()=>i(!0),className:"w-full mt-2 py-2 border border-dashed border-black/10 dark:border-white/10 rounded-lg text-xs text-primary font-medium hover:text-primary hover:border-primary/50 transition-colors flex items-center justify-center gap-1",children:[e.jsx("span",{className:"material-symbols-outlined text-[16px]",children:"add"}),"Add Model"]})]}),e.jsxs("div",{className:"flex flex-col gap-2 pt-1 sm:flex-row",children:[e.jsx(q,{onClick:L,variant:"ghost",fullWidth:!0,size:"sm",children:"Cancel"}),e.jsx(q,{onClick:p,fullWidth:!0,size:"sm",disabled:!_.trim()||!!P||M,children:M?"Saving...":a?"Save":"Create"})]})]})}),e.jsx(fe,{isOpen:s,onClose:()=>i(!1),onSelect:w,onDeselect:x,activeProviders:g,modelAliases:ee,title:"Add Model to Combo",kindFilter:l,addedModelValues:U,closeOnSelect:!1})]})}const Ze="/api/cli-tools/cowork-mcp-registry",Ke="/api/cli-tools/cowork-mcp-tools";function et({isOpen:d,onClose:r,onAdd:L,addedNames:Y=[]}){const[g,l]=t.useState([]),[A,O]=t.useState(!1),[E,_]=t.useState(""),[B,U]=t.useState("all"),[o,s]=t.useState(null),[i,M]=t.useState(null),[Q,P]=t.useState({}),[K,ee]=t.useState({}),[W,b]=t.useState({});t.useEffect(()=>{d&&(g.length>0||(O(!0),fetch(Ze).then(a=>a.json()).then(a=>{a.error?s(a.error):l(a.servers||[])}).catch(a=>s(a.message)).finally(()=>O(!1))))},[d]);const y=t.useMemo(()=>new Set(Y),[Y]),w=t.useMemo(()=>{const a=E.trim().toLowerCase();return g.filter(m=>B==="authless"&&m.oauth||B==="oauth"&&!m.oauth?!1:a?(m.title||"").toLowerCase().includes(a)||(m.description||"").toLowerCase().includes(a)||(m.name||"").toLowerCase().includes(a):!0)},[g,E,B]),x=async a=>{if(!Q[a.url]){ee(m=>({...m,[a.url]:!0}));try{const h=await(await fetch(Ke,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:a.url})})).json(),v=h.tools||[],I=Array.isArray(a.toolNames)?a.toolNames:[],G=v.length>0?v.map(V=>V.name):I;P(V=>({...V,[a.url]:{tools:v,requiresAuth:!!h.requiresAuth,error:h.error}})),b(V=>({...V,[a.url]:Object.fromEntries(G.map(ae=>[ae,!0]))}))}catch(m){P(h=>({...h,[a.url]:{tools:[],error:m.message}}))}finally{ee(m=>({...m,[a.url]:!1}))}}},C=a=>{if(i===a.url){M(null);return}M(a.url),x(a)},j=(a,m)=>{b(h=>{var v;return{...h,[a]:{...h[a],[m]:!((v=h[a])!=null&&v[m])}}})},T=(a,m)=>{const h=W[a]||{};b(v=>({...v,[a]:Object.fromEntries(Object.keys(h).map(I=>[I,m]))}))},p=a=>{const m=W[a.url]||{},h=Object.keys(m).filter(v=>m[v]);L==null||L({name:a.slug||a.name,title:a.title,description:a.description,url:a.url,transport:a.transport,oauth:a.oauth,toolNames:h}),M(null)};return e.jsx(Ue,{isOpen:d,onClose:r,title:"Browse MCP Marketplace",size:"lg",children:e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",value:E,onChange:a=>_(a.target.value),placeholder:"Search by name or description...",className:"flex-1 px-2 py-1.5 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50"}),e.jsxs("select",{value:B,onChange:a=>U(a.target.value),className:"px-2 py-1.5 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50",children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"authless",children:"Authless"}),e.jsx("option",{value:"oauth",children:"OAuth"})]})]}),o&&e.jsx("div",{className:"px-2 py-1.5 rounded text-xs bg-red-500/10 text-red-600",children:o}),A&&e.jsxs("div",{className:"flex items-center gap-2 text-text-muted text-xs py-4 justify-center",children:[e.jsx("span",{className:"material-symbols-outlined animate-spin text-[18px]",children:"progress_activity"}),e.jsx("span",{children:"Loading registry..."})]}),!A&&e.jsxs("div",{className:"flex flex-col gap-1 max-h-[60vh] overflow-y-auto",children:[w.length===0&&e.jsx("div",{className:"text-center text-xs text-text-muted py-6",children:"No servers match filter"}),w.map(a=>{const m=y.has(a.slug||a.name),h=i===a.url,v=Q[a.url],I=K[a.url],G=W[a.url]||{},V=Object.keys(G),ae=Object.values(G).filter(Boolean).length;return e.jsxs("div",{className:"rounded border border-transparent hover:border-border",children:[e.jsxs("div",{className:"flex items-start gap-2 px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5",children:[a.iconUrl?e.jsx("img",{src:a.iconUrl,alt:"",className:"size-7 rounded shrink-0 object-contain",onError:F=>{F.target.style.display="none"}}):e.jsx("div",{className:"size-7 rounded bg-surface shrink-0"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-1.5 flex-wrap",children:[e.jsx("span",{className:"font-medium text-xs",children:a.title}),a.oauth?e.jsx("span",{className:"px-1 py-0.5 text-[9px] rounded bg-amber-500/10 text-amber-600",children:"OAuth"}):e.jsx("span",{className:"px-1 py-0.5 text-[9px] rounded bg-green-500/10 text-green-600",children:"Authless"}),a.toolCount>0&&e.jsxs("span",{className:"text-[10px] text-text-muted",children:[a.toolCount," tools"]})]}),a.description&&e.jsx("p",{className:"text-[10px] text-text-muted line-clamp-2 mt-0.5",children:a.description})]}),e.jsx("button",{onClick:()=>m?null:C(a),disabled:m,className:`shrink-0 px-2 py-1 rounded text-[10px] font-medium transition-colors ${m?"bg-green-500/10 text-green-600 cursor-default":h?"bg-surface border border-border text-text-muted hover:bg-black/5":"bg-primary/10 border border-primary/40 text-primary hover:bg-primary/20"}`,children:m?"Added":h?"Cancel":"+ Add"})]}),h&&e.jsxs("div",{className:"px-3 py-2 bg-surface/40 border-t border-border flex flex-col gap-2",children:[I&&e.jsxs("div",{className:"flex items-center gap-2 text-text-muted text-[10px] py-1",children:[e.jsx("span",{className:"material-symbols-outlined animate-spin text-[14px]",children:"progress_activity"}),e.jsx("span",{children:"Probing server for tools..."})]}),!I&&(v==null?void 0:v.requiresAuth)&&e.jsx("p",{className:"text-[10px] text-amber-600 bg-amber-500/10 px-2 py-1 rounded",children:"🔐 OAuth required. Add now and authenticate after Apply; tool list will be discovered after first connect."}),!I&&(v==null?void 0:v.error)&&!(v!=null&&v.requiresAuth)&&e.jsxs("p",{className:"text-[10px] text-red-600 bg-red-500/10 px-2 py-1 rounded",children:["Probe failed: ",v.error]}),!I&&V.length===0&&!(v!=null&&v.requiresAuth)&&!(v!=null&&v.error)&&e.jsx("p",{className:"text-[10px] text-text-muted",children:"No tools advertised by server."}),!I&&V.length>0&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-[10px] text-text-muted",children:[ae,"/",V.length," tools enabled"]}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx("button",{onClick:()=>T(a.url,!0),className:"text-[10px] text-primary hover:underline",children:"All"}),e.jsx("span",{className:"text-[10px] text-text-muted",children:"·"}),e.jsx("button",{onClick:()=>T(a.url,!1),className:"text-[10px] text-primary hover:underline",children:"None"})]})]}),e.jsx("div",{className:"grid grid-cols-2 gap-1 max-h-40 overflow-y-auto",children:V.map(F=>e.jsxs("label",{className:"flex items-center gap-1.5 text-[10px] cursor-pointer hover:bg-black/5 dark:hover:bg-white/5 px-1 rounded",children:[e.jsx("input",{type:"checkbox",checked:!!G[F],onChange:()=>j(a.url,F),className:"size-3"}),e.jsx("span",{className:"truncate",children:F})]},F))})]}),e.jsx("button",{onClick:()=>p(a),className:"self-end px-2 py-1 rounded text-[10px] font-medium bg-primary text-white hover:bg-primary/90",children:"✓ Confirm Add"})]})]},a.url)})]}),e.jsxs("div",{className:"text-[10px] text-text-muted text-right",children:[w.length," of ",g.length," servers"]})]})})}const Fe="fsrouter.cliToolEndpointPresets",ve="__custom__",Re="__save__",tt=d=>{const r=(d||"").replace(/\/+$/,"");return r?/\/v1$/.test(r)?r:`${r}/v1`:""},st=()=>{if(typeof window>"u")return[];try{const d=JSON.parse(window.localStorage.getItem(Fe)||"[]");return Array.isArray(d)?d.filter(r=>(r==null?void 0:r.name)&&(r==null?void 0:r.baseUrl)):[]}catch{return[]}},Ie=d=>{typeof window>"u"||window.localStorage.setItem(Fe,JSON.stringify(d))},lt=({requiresExternalUrl:d,tunnelEnabled:r,tunnelPublicUrl:L,tailscaleEnabled:Y,tailscaleUrl:g,cloudEnabled:l,cloudUrl:A,savedPresets:O,withV1:E})=>{const _=[],B=U=>E?tt(U):(U||"").replace(/\/+$/,"");if(!d){const U=B(`http://127.0.0.1:${De()}`);_.push({value:"local",label:U,url:U})}if(r&&L){const U=B(L);_.push({value:"tunnel",label:U,url:U})}if(Y&&g){const U=B(g);_.push({value:"tailscale",label:U,url:U})}if(l&&A){const U=B(A);_.push({value:"cloud",label:U,url:U})}return O.forEach(U=>{_.push({value:`saved:${U.name}`,label:U.baseUrl,url:U.baseUrl,saved:!0})}),_.push({value:ve,label:"Custom URL...",url:""}),_};function je({value:d,onChange:r,requiresExternalUrl:L=!1,tunnelEnabled:Y=!1,tunnelPublicUrl:g="",tailscaleEnabled:l=!1,tailscaleUrl:A="",cloudEnabled:O=!1,cloudUrl:E="",withV1:_=!0}){const[B,U]=t.useState([]),[o,s]=t.useState(""),[i,M]=t.useState(""),Q=t.useRef(!1);t.useEffect(()=>{U(st())},[]);const P=t.useMemo(()=>lt({requiresExternalUrl:L,tunnelEnabled:Y,tunnelPublicUrl:g,tailscaleEnabled:l,tailscaleUrl:A,cloudEnabled:O,cloudUrl:E,savedPresets:B,withV1:_}),[L,Y,g,l,A,O,E,B,_]);t.useEffect(()=>{if(Q.current||P.length===0)return;Q.current=!0;const x=P.find(C=>C.value!==ve);x?(s(x.value),r(x.url)):s(ve)},[P,r]);const K=x=>{const C=x.target.value;if(C===Re){const T=(d||"").trim();if(!T)return;let p=T;try{p=new URL(T).host}catch{}const a=window.prompt("Save endpoint as:",p);if(!(a!=null&&a.trim()))return;const m=[...B.filter(h=>h.name!==a.trim()),{name:a.trim(),baseUrl:T}].sort((h,v)=>h.name.localeCompare(v.name));U(m),Ie(m);return}if(s(C),C===ve){M(""),r("");return}const j=P.find(T=>T.value===C);j&&r(j.url)},ee=x=>{const C=x.target.value;M(C),r(C)},W=()=>{if(!o.startsWith("saved:"))return;const x=o.slice(6),C=B.filter(j=>j.name!==x);U(C),Ie(C),s(ve),M(""),r("")},b=o.startsWith("saved:"),y=o===ve,w=y&&(i||"").trim().length>0;return e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:o,onChange:K,className:"flex-1 min-w-0 px-2 py-2 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5",children:[P.map(x=>e.jsx("option",{value:x.value,children:x.label},x.value)),w&&e.jsx("option",{value:Re,children:"+ Save current as..."})]}),b&&e.jsx("button",{type:"button",onClick:W,className:"p-1 text-text-muted hover:text-red-500 rounded transition-colors shrink-0",title:"Delete saved endpoint",children:e.jsx("span",{className:"material-symbols-outlined text-[14px]",children:"delete"})})]}),y&&e.jsx("input",{type:"text",value:i,onChange:ee,placeholder:_?"https://example.com/v1":"https://example.com",className:"w-full min-w-0 px-2 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5"})]})}const we="__custom__";function be({value:d,onChange:r,apiKeys:L=[],cloudEnabled:Y=!1,className:g=""}){const l=!L.some(s=>s.key===d)&&d!=="",[A,O]=t.useState(()=>d?L.some(s=>s.key===d)?d:we:L.length>0?L[0].key:we),[E,_]=t.useState(l?d:""),B=s=>{const i=s.target.value;O(i),i===we?(_(""),r("")):r(i)},U=s=>{const i=s.target.value;_(i),r(i)};return L.length===0&&A!==we&&A!==we?e.jsx("span",{className:`min-w-0 rounded bg-surface/40 px-2 py-2 text-xs text-text-muted sm:py-1.5 ${g}`,children:Y?"No API keys - Create one in Keys page":"sk_fsrouter (default)"}):e.jsxs("div",{className:`flex flex-col gap-1.5 ${g}`,children:[e.jsxs("select",{value:A,onChange:B,className:"w-full min-w-0 px-2 py-2 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5",children:[L.map(s=>e.jsx("option",{value:s.key,children:s.key},s.id)),e.jsx("option",{value:we,children:"Custom..."})]}),A===we&&e.jsx("input",{type:"text",value:E,onChange:U,placeholder:"sk-...",className:"w-full min-w-0 px-2 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5"})]})}const Se=d=>(d||"").replace(/\/+$/,"");function Ne(d,r={}){if(!d)return!1;const L=Se(d),{tunnelPublicUrl:Y,tailscaleUrl:g,cloudUrl:l}=r;return!!(/localhost|127\.0\.0\.1|0\.0\.0\.0/.test(L)||Y&&L.startsWith(Se(Y))||g&&L.startsWith(Se(g))||l&&L.startsWith(Se(l)))}var rt={};const at=rt.NEXT_PUBLIC_CLOUD_URL;function nt({tool:d,isExpanded:r,onToggle:L,activeProviders:Y,modelMappings:g,onModelMappingChange:l,baseUrl:A,hasActiveProviders:O,apiKeys:E,cloudEnabled:_,initialStatus:B,tunnelEnabled:U,tunnelPublicUrl:o,tailscaleEnabled:s,tailscaleUrl:i}){var pe,R;const[M,Q]=t.useState(B||null),[P,K]=t.useState(!1),[ee,W]=t.useState(!1),[b,y]=t.useState(!1),[w,x]=t.useState(null),[C,j]=t.useState(!1),[T,p]=t.useState(!1),[a,m]=t.useState(null),[h,v]=t.useState(""),[I,G]=t.useState({}),[V,ae]=t.useState(!1),[F,oe]=t.useState(""),[ie,te]=t.useState(!1),se=t.useRef(!1),ne=(()=>{var z,le;if(!(M!=null&&M.installed))return null;const n=(le=(z=M.settings)==null?void 0:z.env)==null?void 0:le.ANTHROPIC_BASE_URL;return n?Ne(n,{tunnelPublicUrl:o,tailscaleUrl:i,cloudUrl:_?at:null})?"configured":"other":"not_configured"})();t.useEffect(()=>{(E==null?void 0:E.length)>0&&!h&&v(E[0].key)},[E,h]),t.useEffect(()=>{B&&Q(B)},[B]),t.useEffect(()=>{r&&!M&&(f(),H()),r&&H()},[r]),t.useEffect(()=>{fetch("/api/settings").then(n=>n.json()).then(n=>{te(!!n.ccFilterNaming)}).catch(()=>{})},[]);const ue=async n=>{const z=n.target.checked;te(z),await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({ccFilterNaming:z})}).catch(()=>{})},H=async()=>{try{const n=await fetch("/api/models/alias"),z=await n.json();n.ok&&G(z.aliases||{})}catch(n){console.log("Error fetching model aliases:",n)}};t.useEffect(()=>{var n;if(M!=null&&M.installed&&!se.current){se.current=!0;const z=((n=M.settings)==null?void 0:n.env)||{};d.defaultModels.forEach(k=>{if(k.envKey){const J=z[k.envKey]||k.defaultValue||"";J&&l(k.alias,J)}});const le=z.ANTHROPIC_AUTH_TOKEN;le&&(E!=null&&E.some(k=>k.key===le))&&v(le)}},[M,E,d.defaultModels,l]);const f=async()=>{K(!0);try{const z=await(await fetch("/api/cli-tools/claude-settings")).json();Q(z)}catch(n){Q({installed:!1,error:n.message})}finally{K(!1)}},$=()=>{const n=F||A;return n.endsWith("/v1")?n:`${n}/v1`},X=()=>{const n=F||A;return n.endsWith("/v1")?n:`${n}/v1`},u=async()=>{W(!0),x(null);try{const n={ANTHROPIC_BASE_URL:$()},z=(h==null?void 0:h.trim())||((E==null?void 0:E.length)>0?E[0].key:null)||(_?null:"sk_fsrouter");z&&(n.ANTHROPIC_AUTH_TOKEN=z),d.defaultModels.forEach(J=>{const de=g[J.alias];de&&J.envKey&&(n[J.envKey]=de)});const le=await fetch("/api/cli-tools/claude-settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({env:n})}),k=await le.json();le.ok?(x({type:"success",text:"Settings applied successfully!"}),Q(J=>({...J,hasBackup:!0,settings:{...J==null?void 0:J.settings,env:n}}))):x({type:"error",text:k.error||"Failed to apply settings"})}catch(n){x({type:"error",text:n.message})}finally{W(!1)}},N=async()=>{y(!0),x(null);try{const n=await fetch("/api/cli-tools/claude-settings",{method:"DELETE"}),z=await n.json();n.ok?(x({type:"success",text:"Settings reset successfully!"}),d.defaultModels.forEach(le=>l(le.alias,le.defaultValue||"")),v("")):x({type:"error",text:z.error||"Failed to reset settings"})}catch(n){x({type:"error",text:n.message})}finally{y(!1)}},S=n=>{m(n),p(!0)},ce=n=>{a&&l(a,n.value)},xe=()=>{const n=h&&h.trim()?h:_?"<API_KEY_FROM_DASHBOARD>":"sk_fsrouter",z={ANTHROPIC_BASE_URL:$(),ANTHROPIC_AUTH_TOKEN:n};return d.defaultModels.forEach(le=>{const k=g[le.alias];k&&le.envKey&&(z[le.envKey]=k)}),[{filename:"~/.claude/settings.json",content:JSON.stringify({hasCompletedOnboarding:!0,env:z},null,2)}]};return e.jsxs(ge,{padding:"xs",className:"overflow-hidden",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 hover:cursor-pointer sm:items-center",onClick:L,children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[e.jsx("div",{className:"size-8 flex items-center justify-center shrink-0",children:e.jsx("img",{src:"/providers/claude.png",alt:d.name,width:32,height:32,className:"size-8 object-contain rounded-lg",sizes:"32px",onError:n=>{n.target.style.display="none"}})}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2",children:[e.jsx("h3",{className:"font-medium text-sm",children:d.name}),ne==="configured"&&e.jsx("span",{className:"px-1.5 py-0.5 text-[10px] font-medium bg-green-500/10 text-green-600 dark:text-green-400 rounded-full",children:"Connected"}),ne==="not_configured"&&e.jsx("span",{className:"px-1.5 py-0.5 text-[10px] font-medium bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 rounded-full",children:"Not configured"}),ne==="other"&&e.jsx("span",{className:"px-1.5 py-0.5 text-[10px] font-medium bg-blue-500/10 text-blue-600 dark:text-blue-400 rounded-full",children:"Other"})]}),e.jsx("p",{className:"text-xs text-text-muted truncate",children:d.description})]})]}),e.jsx("span",{className:`material-symbols-outlined text-text-muted text-[20px] transition-transform ${r?"rotate-180":""}`,children:"expand_more"})]}),r&&e.jsxs("div",{className:"mt-4 pt-4 border-t border-border flex flex-col gap-4",children:[P&&e.jsxs("div",{className:"flex items-center gap-2 text-text-muted",children:[e.jsx("span",{className:"material-symbols-outlined animate-spin",children:"progress_activity"}),e.jsx("span",{children:"Checking Claude CLI..."})]}),!P&&M&&!M.installed&&e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-3 p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("span",{className:"material-symbols-outlined text-yellow-500",children:"warning"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("p",{className:"font-medium text-yellow-600 dark:text-yellow-400",children:"Claude CLI not detected locally"}),e.jsx("p",{className:"text-sm text-text-muted",children:"Manual configuration is still available if fsrouter is deployed on a remote server."})]})]}),e.jsxs("div",{className:"flex items-center gap-2 pl-9",children:[e.jsxs(q,{variant:"secondary",size:"sm",onClick:()=>ae(!0),className:"!bg-yellow-500/20 !border-yellow-500/40 !text-yellow-700 dark:!text-yellow-300 hover:!bg-yellow-500/30",children:[e.jsx("span",{className:"material-symbols-outlined text-[18px] mr-1",children:"content_copy"}),"Manual Config"]}),e.jsxs(q,{variant:"outline",size:"sm",onClick:()=>j(!C),children:[e.jsx("span",{className:"material-symbols-outlined text-[18px] mr-1",children:C?"expand_less":"help"}),C?"Hide":"How to Install"]})]})]}),C&&e.jsxs("div",{className:"p-4 bg-surface border border-border rounded-lg",children:[e.jsx("h4",{className:"font-medium mb-3",children:"Installation Guide"}),e.jsxs("div",{className:"space-y-3 text-sm",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-text-muted mb-1",children:"macOS / Linux / Windows:"}),e.jsx("code",{className:"block px-3 py-2 bg-black/5 dark:bg-white/5 rounded font-mono text-xs",children:"npm install -g @anthropic-ai/claude-code"})]}),e.jsxs("p",{className:"text-text-muted",children:["After installation, run ",e.jsx("code",{className:"px-1 bg-black/5 dark:bg-white/5 rounded",children:"claude"})," to verify."]})]})]})]}),!P&&(M==null?void 0:M.installed)&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"Select Endpoint"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsx(je,{value:F||X(),onChange:oe,requiresExternalUrl:d.requiresExternalUrl,tunnelEnabled:U,tunnelPublicUrl:o,tailscaleEnabled:s,tailscaleUrl:i})]}),((R=(pe=M==null?void 0:M.settings)==null?void 0:pe.env)==null?void 0:R.ANTHROPIC_BASE_URL)&&e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"Current"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsx("span",{className:"min-w-0 truncate rounded bg-surface/40 px-2 py-2 text-xs text-text-muted sm:py-1.5",children:M.settings.env.ANTHROPIC_BASE_URL})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"API Key"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsx(be,{value:h,onChange:v,apiKeys:E,cloudEnabled:_})]}),d.defaultModels.map(n=>e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:n.name}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsxs("div",{className:"relative w-full min-w-0",children:[e.jsx("input",{type:"text",value:g[n.alias]||"",onChange:z=>l(n.alias,z.target.value),placeholder:"provider/model-id",className:"w-full min-w-0 pl-2 pr-7 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5"}),g[n.alias]&&e.jsx("button",{onClick:()=>l(n.alias,""),className:"absolute right-1 top-1/2 -translate-y-1/2 p-0.5 text-text-muted hover:text-red-500 rounded transition-colors",title:"Clear",children:e.jsx("span",{className:"material-symbols-outlined text-[14px]",children:"close"})})]}),e.jsx("button",{onClick:()=>S(n.alias),disabled:!O,className:`w-full sm:w-auto rounded border px-2 py-2 text-xs transition-colors sm:py-1.5 whitespace-nowrap sm:shrink-0 ${O?"bg-surface border-border text-text-main hover:border-primary cursor-pointer":"opacity-50 cursor-not-allowed border-border"}`,children:"Select Model"})]},n.alias)),e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"Filter naming"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsxs("label",{className:"flex items-center gap-1.5 cursor-pointer select-none",children:[e.jsx("input",{type:"checkbox",checked:ie,onChange:ue,className:"w-3.5 h-3.5 accent-primary cursor-pointer"}),e.jsx("span",{className:"text-xs text-text-muted",children:"Filter naming requests"})]}),e.jsx(Be,{text:"Intercepts Claude Code's topic-naming requests and returns a fake response locally, saving API tokens.",children:e.jsx("span",{className:"material-symbols-outlined text-text-muted text-[14px] cursor-help",children:"info"})})]})]}),w&&e.jsxs("div",{className:`flex items-center gap-2 px-2 py-1.5 rounded text-xs ${w.type==="success"?"bg-green-500/10 text-green-600":"bg-red-500/10 text-red-600"}`,children:[e.jsx("span",{className:"material-symbols-outlined text-[14px]",children:w.type==="success"?"check_circle":"error"}),e.jsx("span",{children:w.text})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-2 sm:flex sm:items-center",children:[e.jsxs(q,{variant:"primary",size:"sm",onClick:u,disabled:!O,loading:ee,children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:"save"}),"Apply"]}),e.jsxs(q,{variant:"outline",size:"sm",onClick:N,disabled:!(M!=null&&M.hasFSRouter),loading:b,children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:"restore"}),"Reset"]}),e.jsxs(q,{variant:"ghost",size:"sm",onClick:()=>ae(!0),children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:"content_copy"}),"Manual Config"]})]})]})]}),e.jsx(fe,{isOpen:T,onClose:()=>p(!1),onSelect:ce,selectedModel:a?g[a]:null,activeProviders:Y,modelAliases:I,title:`Select model for ${a}`}),e.jsx(ye,{isOpen:V,onClose:()=>ae(!1),title:"Claude CLI - Manual Configuration",configs:xe()})]})}function ot({tool:d,isExpanded:r,onToggle:L,baseUrl:Y,apiKeys:g,activeProviders:l,cloudEnabled:A,initialStatus:O,tunnelEnabled:E,tunnelPublicUrl:_,tailscaleEnabled:B,tailscaleUrl:U}){const[o,s]=t.useState(O||null),[i,M]=t.useState(!1),[Q,P]=t.useState(!1),[K,ee]=t.useState(!1),[W,b]=t.useState(null),[y,w]=t.useState(!1),[x,C]=t.useState(""),[j,T]=t.useState(""),[p,a]=t.useState(""),[m,h]=t.useState(!1),[v,I]=t.useState(!1),[G,V]=t.useState({}),[ae,F]=t.useState(!1),[oe,ie]=t.useState("");t.useEffect(()=>{(g==null?void 0:g.length)>0&&!x&&C(g[0].key)},[g,x]),t.useEffect(()=>{O&&s(O)},[O]),t.useEffect(()=>{r&&!o&&(H(),te()),r&&te()},[r]);const te=async()=>{try{const N=await fetch("/api/models/alias"),S=await N.json();N.ok&&V(S.aliases||{})}catch(N){console.log("Error fetching model aliases:",N)}};t.useEffect(()=>{if(o!=null&&o.config){const N=o.config.match(/^model\s*=\s*"([^"]+)"/m);N&&T(N[1]);const S=o.config.match(/\[agents\.subagent\]\s*\n\s*model\s*=\s*"([^"]+)"/m);S&&a(S[1])}},[o]);const Z=(()=>{if(!(o!=null&&o.installed))return null;if(!o.config)return"not_configured";const N=o.config.match(/base_url\s*=\s*"([^"]+)"/),S=N?N[1]:"";return Ne(S,{tunnelPublicUrl:_,tailscaleUrl:U})?"configured":"other"})(),ne=()=>{const N=oe||`${Y}/v1`;return N.endsWith("/v1")?N:`${N}/v1`},ue=()=>oe||`${Y}/v1`,H=async()=>{M(!0);try{const S=await(await fetch("/api/cli-tools/codex-settings")).json();s(S)}catch(N){s({installed:!1,error:N.message})}finally{M(!1)}},f=async()=>{P(!0),b(null);try{const N=x&&x.trim()||A?x:"sk_fsrouter",S=await fetch("/api/cli-tools/codex-settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({baseUrl:ne(),apiKey:N,model:j,subagentModel:p||j})}),ce=await S.json();S.ok?(b({type:"success",text:"Settings applied successfully!"}),H()):b({type:"error",text:ce.error||"Failed to apply settings"})}catch(N){b({type:"error",text:N.message})}finally{P(!1)}},$=async()=>{ee(!0),b(null);try{const N=await fetch("/api/cli-tools/codex-settings",{method:"DELETE"}),S=await N.json();N.ok?(b({type:"success",text:"Settings reset successfully!"}),T(""),a(""),H()):b({type:"error",text:S.error||"Failed to reset settings"})}catch(N){b({type:"error",text:N.message})}finally{ee(!1)}},X=N=>{T(N.value),p||a(N.value),h(!1)},u=()=>{const N=x&&x.trim()?x:A?"<API_KEY_FROM_DASHBOARD>":"sk_fsrouter",S=p||j,ce=`# FSRouter Configuration for Codex CLI
1
+ import{u as ze,j as e,M as Ue,B as q,w as De,x as Be,y as ke,z as He,h as We}from"./index.D4FwOBBU.js";import{b as t,L as Te,h as Je,N as qe}from"./router.Cjj1--8t.js";import{C as Le}from"./cliTools.CsdwAybi.js";import{g as Pe}from"./machine.CagOtseJ.js";import{I as Ge,M as fe,C as ge}from"./NoAuthProxyCard.WHGGEUIp.js";import{C as Ve}from"./Loading.C1il44u0.js";import"./zustand.akaTi5uX.js";function ye({isOpen:d,onClose:r,title:L="Manual Configuration",configs:Y=[]}){const{copy:g}=ze(),[l,A]=t.useState(null),O=(E,_)=>{g(E,`manualconfig-${_}`),A(_),setTimeout(()=>A(null),2e3)};return e.jsx(Ue,{isOpen:d,onClose:r,title:L,size:"xl",children:e.jsx("div",{className:"flex flex-col gap-4",children:Y.map((E,_)=>e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm font-medium text-text-main",children:E.filename}),e.jsxs(q,{variant:"ghost",size:"sm",onClick:()=>O(E.content,_),children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:l===_?"check":"content_copy"}),l===_?"Copied!":"Copy"]})]}),e.jsx("pre",{className:"px-3 py-2 bg-black/5 dark:bg-white/5 rounded font-mono text-xs overflow-x-auto whitespace-pre-wrap break-all max-h-60 overflow-y-auto border border-border",children:E.content})]},_))})})}const Ye=/^[a-zA-Z0-9_.\-]+$/;function Xe({index:d,model:r,isFirst:L,isLast:Y,onEdit:g,onMoveUp:l,onMoveDown:A,onRemove:O}){const[E,_]=t.useState(!1),[B,U]=t.useState(r),o=()=>{const i=B.trim();i&&i!==r?g(i):U(r),_(!1)},s=i=>{i.key==="Enter"&&o(),i.key==="Escape"&&(U(r),_(!1))};return e.jsxs("div",{className:"group flex min-w-0 items-center gap-1.5 rounded-md bg-black/[0.02] px-2 py-1 transition-colors hover:bg-black/[0.04] dark:bg-white/[0.02] dark:hover:bg-white/[0.04]",children:[e.jsx("span",{className:"text-[10px] font-medium text-text-muted w-3 text-center shrink-0",children:d+1}),E?e.jsx("input",{autoFocus:!0,value:B,onChange:i=>U(i.target.value),onBlur:o,onKeyDown:s,className:"min-w-0 flex-1 rounded border border-primary/40 bg-white px-1.5 py-0.5 font-mono text-xs text-text-main outline-none dark:bg-black/20"}):e.jsx("div",{className:"min-w-0 flex-1 cursor-text truncate rounded px-1.5 py-0.5 font-mono text-xs text-text-main hover:bg-black/5 dark:hover:bg-white/5",onClick:()=>_(!0),title:"Click to edit",children:r}),e.jsxs("div",{className:"flex shrink-0 items-center gap-0.5",children:[e.jsx("button",{onClick:l,disabled:L,className:`p-0.5 rounded ${L?"text-text-muted/20 cursor-not-allowed":"text-text-muted hover:text-primary hover:bg-black/5 dark:hover:bg-white/5"}`,title:"Move up",children:e.jsx("span",{className:"material-symbols-outlined text-[12px]",children:"arrow_upward"})}),e.jsx("button",{onClick:A,disabled:Y,className:`p-0.5 rounded ${Y?"text-text-muted/20 cursor-not-allowed":"text-text-muted hover:text-primary hover:bg-black/5 dark:hover:bg-white/5"}`,title:"Move down",children:e.jsx("span",{className:"material-symbols-outlined text-[12px]",children:"arrow_downward"})})]}),e.jsx("button",{onClick:O,className:"p-0.5 hover:bg-red-500/10 rounded text-text-muted hover:text-red-500 transition-all",title:"Remove",children:e.jsx("span",{className:"material-symbols-outlined text-[12px]",children:"close"})})]})}function Qe({isOpen:d,combo:r,onClose:L,onSave:Y,activeProviders:g,kindFilter:l=null,forcePrefix:A="",title:O}){const E=r!=null&&r.name?A&&r.name.startsWith(A)?r.name.slice(A.length):r.name:"",[_,B]=t.useState(E),[U,o]=t.useState((r==null?void 0:r.models)||[]),[s,i]=t.useState(!1),[M,Q]=t.useState(!1),[P,K]=t.useState(""),[ee,W]=t.useState({});t.useEffect(()=>{d&&fetch("/api/models/alias").then(m=>m.ok?m.json():null).then(m=>m&&W(m.aliases||{})).catch(()=>{})},[d]);const b=m=>{if(!m.trim())return K("Name is required"),!1;const h=A+m;return Ye.test(h)?(K(""),!0):(K("Only letters, numbers, -, _ and . allowed"),!1)},y=m=>{let h=m.target.value;A&&h.startsWith(A)&&(h=h.slice(A.length)),B(h),h?b(h):K("")},w=m=>{U.includes(m.value)||o([...U,m.value])},x=m=>{o(U.filter(h=>h!==m.value))},C=m=>o(U.filter((h,v)=>v!==m)),j=m=>{if(m===0)return;const h=[...U];[h[m-1],h[m]]=[h[m],h[m-1]],o(h)},T=m=>{if(m===U.length-1)return;const h=[...U];[h[m],h[m+1]]=[h[m+1],h[m]],o(h)},p=async()=>{b(_)&&(Q(!0),await Y({name:A+_.trim(),models:U}),Q(!1))},a=!!r;return e.jsxs(e.Fragment,{children:[e.jsx(Ue,{isOpen:d,onClose:L,title:O||(a?"Edit Combo":"Create Combo"),children:e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{children:[A?e.jsxs(e.Fragment,{children:[e.jsx("label",{className:"text-sm font-medium mb-1 block",children:"Combo Name"}),e.jsxs("div",{className:"flex items-stretch",children:[e.jsx("span",{className:"inline-flex items-center px-2 rounded-l border border-r-0 border-black/10 dark:border-white/10 bg-black/[0.04] dark:bg-white/[0.04] text-text-muted font-mono text-sm",children:A}),e.jsx("input",{value:_,onChange:y,placeholder:"my-combo",className:"flex-1 min-w-0 rounded-r border border-black/10 dark:border-white/10 bg-white dark:bg-black/20 px-2 py-1.5 font-mono text-sm outline-none focus:border-primary"})]}),P&&e.jsx("p",{className:"text-[11px] text-red-500 mt-0.5",children:P})]}):e.jsx(Ge,{label:"Combo Name",value:_,onChange:y,placeholder:"my-combo",error:P}),e.jsxs("p",{className:"text-[10px] text-text-muted mt-0.5",children:[A?`Auto-prefixed with "${A}". `:"","Only letters, numbers, -, _ and . allowed"]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium mb-1.5 block",children:"Models"}),U.length===0?e.jsxs("div",{className:"text-center py-4 border border-dashed border-black/10 dark:border-white/10 rounded-lg bg-black/[0.01] dark:bg-white/[0.01]",children:[e.jsx("span",{className:"material-symbols-outlined text-text-muted text-xl mb-1",children:"layers"}),e.jsx("p",{className:"text-xs text-text-muted",children:"No models added yet"})]}):e.jsx("div",{className:"flex max-h-[55vh] min-w-0 flex-col gap-1 overflow-y-auto sm:max-h-[350px]",children:U.map((m,h)=>e.jsx(Xe,{index:h,model:m,isFirst:h===0,isLast:h===U.length-1,onEdit:v=>{const I=[...U];I[h]=v,o(I)},onMoveUp:()=>j(h),onMoveDown:()=>T(h),onRemove:()=>C(h)},h))}),e.jsxs("button",{onClick:()=>i(!0),className:"w-full mt-2 py-2 border border-dashed border-black/10 dark:border-white/10 rounded-lg text-xs text-primary font-medium hover:text-primary hover:border-primary/50 transition-colors flex items-center justify-center gap-1",children:[e.jsx("span",{className:"material-symbols-outlined text-[16px]",children:"add"}),"Add Model"]})]}),e.jsxs("div",{className:"flex flex-col gap-2 pt-1 sm:flex-row",children:[e.jsx(q,{onClick:L,variant:"ghost",fullWidth:!0,size:"sm",children:"Cancel"}),e.jsx(q,{onClick:p,fullWidth:!0,size:"sm",disabled:!_.trim()||!!P||M,children:M?"Saving...":a?"Save":"Create"})]})]})}),e.jsx(fe,{isOpen:s,onClose:()=>i(!1),onSelect:w,onDeselect:x,activeProviders:g,modelAliases:ee,title:"Add Model to Combo",kindFilter:l,addedModelValues:U,closeOnSelect:!1})]})}const Ze="/api/cli-tools/cowork-mcp-registry",Ke="/api/cli-tools/cowork-mcp-tools";function et({isOpen:d,onClose:r,onAdd:L,addedNames:Y=[]}){const[g,l]=t.useState([]),[A,O]=t.useState(!1),[E,_]=t.useState(""),[B,U]=t.useState("all"),[o,s]=t.useState(null),[i,M]=t.useState(null),[Q,P]=t.useState({}),[K,ee]=t.useState({}),[W,b]=t.useState({});t.useEffect(()=>{d&&(g.length>0||(O(!0),fetch(Ze).then(a=>a.json()).then(a=>{a.error?s(a.error):l(a.servers||[])}).catch(a=>s(a.message)).finally(()=>O(!1))))},[d]);const y=t.useMemo(()=>new Set(Y),[Y]),w=t.useMemo(()=>{const a=E.trim().toLowerCase();return g.filter(m=>B==="authless"&&m.oauth||B==="oauth"&&!m.oauth?!1:a?(m.title||"").toLowerCase().includes(a)||(m.description||"").toLowerCase().includes(a)||(m.name||"").toLowerCase().includes(a):!0)},[g,E,B]),x=async a=>{if(!Q[a.url]){ee(m=>({...m,[a.url]:!0}));try{const h=await(await fetch(Ke,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:a.url})})).json(),v=h.tools||[],I=Array.isArray(a.toolNames)?a.toolNames:[],G=v.length>0?v.map(V=>V.name):I;P(V=>({...V,[a.url]:{tools:v,requiresAuth:!!h.requiresAuth,error:h.error}})),b(V=>({...V,[a.url]:Object.fromEntries(G.map(ae=>[ae,!0]))}))}catch(m){P(h=>({...h,[a.url]:{tools:[],error:m.message}}))}finally{ee(m=>({...m,[a.url]:!1}))}}},C=a=>{if(i===a.url){M(null);return}M(a.url),x(a)},j=(a,m)=>{b(h=>{var v;return{...h,[a]:{...h[a],[m]:!((v=h[a])!=null&&v[m])}}})},T=(a,m)=>{const h=W[a]||{};b(v=>({...v,[a]:Object.fromEntries(Object.keys(h).map(I=>[I,m]))}))},p=a=>{const m=W[a.url]||{},h=Object.keys(m).filter(v=>m[v]);L==null||L({name:a.slug||a.name,title:a.title,description:a.description,url:a.url,transport:a.transport,oauth:a.oauth,toolNames:h}),M(null)};return e.jsx(Ue,{isOpen:d,onClose:r,title:"Browse MCP Marketplace",size:"lg",children:e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",value:E,onChange:a=>_(a.target.value),placeholder:"Search by name or description...",className:"flex-1 px-2 py-1.5 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50"}),e.jsxs("select",{value:B,onChange:a=>U(a.target.value),className:"px-2 py-1.5 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50",children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"authless",children:"Authless"}),e.jsx("option",{value:"oauth",children:"OAuth"})]})]}),o&&e.jsx("div",{className:"px-2 py-1.5 rounded text-xs bg-red-500/10 text-red-600",children:o}),A&&e.jsxs("div",{className:"flex items-center gap-2 text-text-muted text-xs py-4 justify-center",children:[e.jsx("span",{className:"material-symbols-outlined animate-spin text-[18px]",children:"progress_activity"}),e.jsx("span",{children:"Loading registry..."})]}),!A&&e.jsxs("div",{className:"flex flex-col gap-1 max-h-[60vh] overflow-y-auto",children:[w.length===0&&e.jsx("div",{className:"text-center text-xs text-text-muted py-6",children:"No servers match filter"}),w.map(a=>{const m=y.has(a.slug||a.name),h=i===a.url,v=Q[a.url],I=K[a.url],G=W[a.url]||{},V=Object.keys(G),ae=Object.values(G).filter(Boolean).length;return e.jsxs("div",{className:"rounded border border-transparent hover:border-border",children:[e.jsxs("div",{className:"flex items-start gap-2 px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5",children:[a.iconUrl?e.jsx("img",{src:a.iconUrl,alt:"",className:"size-7 rounded shrink-0 object-contain",onError:F=>{F.target.style.display="none"}}):e.jsx("div",{className:"size-7 rounded bg-surface shrink-0"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-1.5 flex-wrap",children:[e.jsx("span",{className:"font-medium text-xs",children:a.title}),a.oauth?e.jsx("span",{className:"px-1 py-0.5 text-[9px] rounded bg-amber-500/10 text-amber-600",children:"OAuth"}):e.jsx("span",{className:"px-1 py-0.5 text-[9px] rounded bg-green-500/10 text-green-600",children:"Authless"}),a.toolCount>0&&e.jsxs("span",{className:"text-[10px] text-text-muted",children:[a.toolCount," tools"]})]}),a.description&&e.jsx("p",{className:"text-[10px] text-text-muted line-clamp-2 mt-0.5",children:a.description})]}),e.jsx("button",{onClick:()=>m?null:C(a),disabled:m,className:`shrink-0 px-2 py-1 rounded text-[10px] font-medium transition-colors ${m?"bg-green-500/10 text-green-600 cursor-default":h?"bg-surface border border-border text-text-muted hover:bg-black/5":"bg-primary/10 border border-primary/40 text-primary hover:bg-primary/20"}`,children:m?"Added":h?"Cancel":"+ Add"})]}),h&&e.jsxs("div",{className:"px-3 py-2 bg-surface/40 border-t border-border flex flex-col gap-2",children:[I&&e.jsxs("div",{className:"flex items-center gap-2 text-text-muted text-[10px] py-1",children:[e.jsx("span",{className:"material-symbols-outlined animate-spin text-[14px]",children:"progress_activity"}),e.jsx("span",{children:"Probing server for tools..."})]}),!I&&(v==null?void 0:v.requiresAuth)&&e.jsx("p",{className:"text-[10px] text-amber-600 bg-amber-500/10 px-2 py-1 rounded",children:"🔐 OAuth required. Add now and authenticate after Apply; tool list will be discovered after first connect."}),!I&&(v==null?void 0:v.error)&&!(v!=null&&v.requiresAuth)&&e.jsxs("p",{className:"text-[10px] text-red-600 bg-red-500/10 px-2 py-1 rounded",children:["Probe failed: ",v.error]}),!I&&V.length===0&&!(v!=null&&v.requiresAuth)&&!(v!=null&&v.error)&&e.jsx("p",{className:"text-[10px] text-text-muted",children:"No tools advertised by server."}),!I&&V.length>0&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-[10px] text-text-muted",children:[ae,"/",V.length," tools enabled"]}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx("button",{onClick:()=>T(a.url,!0),className:"text-[10px] text-primary hover:underline",children:"All"}),e.jsx("span",{className:"text-[10px] text-text-muted",children:"·"}),e.jsx("button",{onClick:()=>T(a.url,!1),className:"text-[10px] text-primary hover:underline",children:"None"})]})]}),e.jsx("div",{className:"grid grid-cols-2 gap-1 max-h-40 overflow-y-auto",children:V.map(F=>e.jsxs("label",{className:"flex items-center gap-1.5 text-[10px] cursor-pointer hover:bg-black/5 dark:hover:bg-white/5 px-1 rounded",children:[e.jsx("input",{type:"checkbox",checked:!!G[F],onChange:()=>j(a.url,F),className:"size-3"}),e.jsx("span",{className:"truncate",children:F})]},F))})]}),e.jsx("button",{onClick:()=>p(a),className:"self-end px-2 py-1 rounded text-[10px] font-medium bg-primary text-white hover:bg-primary/90",children:"✓ Confirm Add"})]})]},a.url)})]}),e.jsxs("div",{className:"text-[10px] text-text-muted text-right",children:[w.length," of ",g.length," servers"]})]})})}const Fe="fsrouter.cliToolEndpointPresets",ve="__custom__",Re="__save__",tt=d=>{const r=(d||"").replace(/\/+$/,"");return r?/\/v1$/.test(r)?r:`${r}/v1`:""},st=()=>{if(typeof window>"u")return[];try{const d=JSON.parse(window.localStorage.getItem(Fe)||"[]");return Array.isArray(d)?d.filter(r=>(r==null?void 0:r.name)&&(r==null?void 0:r.baseUrl)):[]}catch{return[]}},Ie=d=>{typeof window>"u"||window.localStorage.setItem(Fe,JSON.stringify(d))},lt=({requiresExternalUrl:d,tunnelEnabled:r,tunnelPublicUrl:L,tailscaleEnabled:Y,tailscaleUrl:g,cloudEnabled:l,cloudUrl:A,savedPresets:O,withV1:E})=>{const _=[],B=U=>E?tt(U):(U||"").replace(/\/+$/,"");if(!d){const U=B(`http://127.0.0.1:${De()}`);_.push({value:"local",label:U,url:U})}if(r&&L){const U=B(L);_.push({value:"tunnel",label:U,url:U})}if(Y&&g){const U=B(g);_.push({value:"tailscale",label:U,url:U})}if(l&&A){const U=B(A);_.push({value:"cloud",label:U,url:U})}return O.forEach(U=>{_.push({value:`saved:${U.name}`,label:U.baseUrl,url:U.baseUrl,saved:!0})}),_.push({value:ve,label:"Custom URL...",url:""}),_};function je({value:d,onChange:r,requiresExternalUrl:L=!1,tunnelEnabled:Y=!1,tunnelPublicUrl:g="",tailscaleEnabled:l=!1,tailscaleUrl:A="",cloudEnabled:O=!1,cloudUrl:E="",withV1:_=!0}){const[B,U]=t.useState([]),[o,s]=t.useState(""),[i,M]=t.useState(""),Q=t.useRef(!1);t.useEffect(()=>{U(st())},[]);const P=t.useMemo(()=>lt({requiresExternalUrl:L,tunnelEnabled:Y,tunnelPublicUrl:g,tailscaleEnabled:l,tailscaleUrl:A,cloudEnabled:O,cloudUrl:E,savedPresets:B,withV1:_}),[L,Y,g,l,A,O,E,B,_]);t.useEffect(()=>{if(Q.current||P.length===0)return;Q.current=!0;const x=P.find(C=>C.value!==ve);x?(s(x.value),r(x.url)):s(ve)},[P,r]);const K=x=>{const C=x.target.value;if(C===Re){const T=(d||"").trim();if(!T)return;let p=T;try{p=new URL(T).host}catch{}const a=window.prompt("Save endpoint as:",p);if(!(a!=null&&a.trim()))return;const m=[...B.filter(h=>h.name!==a.trim()),{name:a.trim(),baseUrl:T}].sort((h,v)=>h.name.localeCompare(v.name));U(m),Ie(m);return}if(s(C),C===ve){M(""),r("");return}const j=P.find(T=>T.value===C);j&&r(j.url)},ee=x=>{const C=x.target.value;M(C),r(C)},W=()=>{if(!o.startsWith("saved:"))return;const x=o.slice(6),C=B.filter(j=>j.name!==x);U(C),Ie(C),s(ve),M(""),r("")},b=o.startsWith("saved:"),y=o===ve,w=y&&(i||"").trim().length>0;return e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:o,onChange:K,className:"flex-1 min-w-0 px-2 py-2 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5",children:[P.map(x=>e.jsx("option",{value:x.value,children:x.label},x.value)),w&&e.jsx("option",{value:Re,children:"+ Save current as..."})]}),b&&e.jsx("button",{type:"button",onClick:W,className:"p-1 text-text-muted hover:text-red-500 rounded transition-colors shrink-0",title:"Delete saved endpoint",children:e.jsx("span",{className:"material-symbols-outlined text-[14px]",children:"delete"})})]}),y&&e.jsx("input",{type:"text",value:i,onChange:ee,placeholder:_?"https://example.com/v1":"https://example.com",className:"w-full min-w-0 px-2 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5"})]})}const we="__custom__";function be({value:d,onChange:r,apiKeys:L=[],cloudEnabled:Y=!1,className:g=""}){const l=!L.some(s=>s.key===d)&&d!=="",[A,O]=t.useState(()=>d?L.some(s=>s.key===d)?d:we:L.length>0?L[0].key:we),[E,_]=t.useState(l?d:""),B=s=>{const i=s.target.value;O(i),i===we?(_(""),r("")):r(i)},U=s=>{const i=s.target.value;_(i),r(i)};return L.length===0&&A!==we&&A!==we?e.jsx("span",{className:`min-w-0 rounded bg-surface/40 px-2 py-2 text-xs text-text-muted sm:py-1.5 ${g}`,children:Y?"No API keys - Create one in Keys page":"sk_fsrouter (default)"}):e.jsxs("div",{className:`flex flex-col gap-1.5 ${g}`,children:[e.jsxs("select",{value:A,onChange:B,className:"w-full min-w-0 px-2 py-2 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5",children:[L.map(s=>e.jsx("option",{value:s.key,children:s.key},s.id)),e.jsx("option",{value:we,children:"Custom..."})]}),A===we&&e.jsx("input",{type:"text",value:E,onChange:U,placeholder:"sk-...",className:"w-full min-w-0 px-2 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5"})]})}const Se=d=>(d||"").replace(/\/+$/,"");function Ne(d,r={}){if(!d)return!1;const L=Se(d),{tunnelPublicUrl:Y,tailscaleUrl:g,cloudUrl:l}=r;return!!(/localhost|127\.0\.0\.1|0\.0\.0\.0/.test(L)||Y&&L.startsWith(Se(Y))||g&&L.startsWith(Se(g))||l&&L.startsWith(Se(l)))}var rt={};const at=rt.NEXT_PUBLIC_CLOUD_URL;function nt({tool:d,isExpanded:r,onToggle:L,activeProviders:Y,modelMappings:g,onModelMappingChange:l,baseUrl:A,hasActiveProviders:O,apiKeys:E,cloudEnabled:_,initialStatus:B,tunnelEnabled:U,tunnelPublicUrl:o,tailscaleEnabled:s,tailscaleUrl:i}){var pe,R;const[M,Q]=t.useState(B||null),[P,K]=t.useState(!1),[ee,W]=t.useState(!1),[b,y]=t.useState(!1),[w,x]=t.useState(null),[C,j]=t.useState(!1),[T,p]=t.useState(!1),[a,m]=t.useState(null),[h,v]=t.useState(""),[I,G]=t.useState({}),[V,ae]=t.useState(!1),[F,oe]=t.useState(""),[ie,te]=t.useState(!1),se=t.useRef(!1),ne=(()=>{var z,le;if(!(M!=null&&M.installed))return null;const n=(le=(z=M.settings)==null?void 0:z.env)==null?void 0:le.ANTHROPIC_BASE_URL;return n?Ne(n,{tunnelPublicUrl:o,tailscaleUrl:i,cloudUrl:_?at:null})?"configured":"other":"not_configured"})();t.useEffect(()=>{(E==null?void 0:E.length)>0&&!h&&v(E[0].key)},[E,h]),t.useEffect(()=>{B&&Q(B)},[B]),t.useEffect(()=>{r&&!M&&(f(),H()),r&&H()},[r]),t.useEffect(()=>{fetch("/api/settings").then(n=>n.json()).then(n=>{te(!!n.ccFilterNaming)}).catch(()=>{})},[]);const ue=async n=>{const z=n.target.checked;te(z),await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({ccFilterNaming:z})}).catch(()=>{})},H=async()=>{try{const n=await fetch("/api/models/alias"),z=await n.json();n.ok&&G(z.aliases||{})}catch(n){console.log("Error fetching model aliases:",n)}};t.useEffect(()=>{var n;if(M!=null&&M.installed&&!se.current){se.current=!0;const z=((n=M.settings)==null?void 0:n.env)||{};d.defaultModels.forEach(k=>{if(k.envKey){const J=z[k.envKey]||k.defaultValue||"";J&&l(k.alias,J)}});const le=z.ANTHROPIC_AUTH_TOKEN;le&&(E!=null&&E.some(k=>k.key===le))&&v(le)}},[M,E,d.defaultModels,l]);const f=async()=>{K(!0);try{const z=await(await fetch("/api/cli-tools/claude-settings")).json();Q(z)}catch(n){Q({installed:!1,error:n.message})}finally{K(!1)}},$=()=>{const n=F||A;return n.endsWith("/v1")?n:`${n}/v1`},X=()=>{const n=F||A;return n.endsWith("/v1")?n:`${n}/v1`},u=async()=>{W(!0),x(null);try{const n={ANTHROPIC_BASE_URL:$()},z=(h==null?void 0:h.trim())||((E==null?void 0:E.length)>0?E[0].key:null)||(_?null:"sk_fsrouter");z&&(n.ANTHROPIC_AUTH_TOKEN=z),d.defaultModels.forEach(J=>{const de=g[J.alias];de&&J.envKey&&(n[J.envKey]=de)});const le=await fetch("/api/cli-tools/claude-settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({env:n})}),k=await le.json();le.ok?(x({type:"success",text:"Settings applied successfully!"}),Q(J=>({...J,hasBackup:!0,settings:{...J==null?void 0:J.settings,env:n}}))):x({type:"error",text:k.error||"Failed to apply settings"})}catch(n){x({type:"error",text:n.message})}finally{W(!1)}},N=async()=>{y(!0),x(null);try{const n=await fetch("/api/cli-tools/claude-settings",{method:"DELETE"}),z=await n.json();n.ok?(x({type:"success",text:"Settings reset successfully!"}),d.defaultModels.forEach(le=>l(le.alias,le.defaultValue||"")),v("")):x({type:"error",text:z.error||"Failed to reset settings"})}catch(n){x({type:"error",text:n.message})}finally{y(!1)}},S=n=>{m(n),p(!0)},ce=n=>{a&&l(a,n.value)},xe=()=>{const n=h&&h.trim()?h:_?"<API_KEY_FROM_DASHBOARD>":"sk_fsrouter",z={ANTHROPIC_BASE_URL:$(),ANTHROPIC_AUTH_TOKEN:n};return d.defaultModels.forEach(le=>{const k=g[le.alias];k&&le.envKey&&(z[le.envKey]=k)}),[{filename:"~/.claude/settings.json",content:JSON.stringify({hasCompletedOnboarding:!0,env:z},null,2)}]};return e.jsxs(ge,{padding:"xs",className:"overflow-hidden",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 hover:cursor-pointer sm:items-center",onClick:L,children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[e.jsx("div",{className:"size-8 flex items-center justify-center shrink-0",children:e.jsx("img",{src:"/providers/claude.png",alt:d.name,width:32,height:32,className:"size-8 object-contain rounded-lg",sizes:"32px",onError:n=>{n.target.style.display="none"}})}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2",children:[e.jsx("h3",{className:"font-medium text-sm",children:d.name}),ne==="configured"&&e.jsx("span",{className:"px-1.5 py-0.5 text-[10px] font-medium bg-green-500/10 text-green-600 dark:text-green-400 rounded-full",children:"Connected"}),ne==="not_configured"&&e.jsx("span",{className:"px-1.5 py-0.5 text-[10px] font-medium bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 rounded-full",children:"Not configured"}),ne==="other"&&e.jsx("span",{className:"px-1.5 py-0.5 text-[10px] font-medium bg-blue-500/10 text-blue-600 dark:text-blue-400 rounded-full",children:"Other"})]}),e.jsx("p",{className:"text-xs text-text-muted truncate",children:d.description})]})]}),e.jsx("span",{className:`material-symbols-outlined text-text-muted text-[20px] transition-transform ${r?"rotate-180":""}`,children:"expand_more"})]}),r&&e.jsxs("div",{className:"mt-4 pt-4 border-t border-border flex flex-col gap-4",children:[P&&e.jsxs("div",{className:"flex items-center gap-2 text-text-muted",children:[e.jsx("span",{className:"material-symbols-outlined animate-spin",children:"progress_activity"}),e.jsx("span",{children:"Checking Claude CLI..."})]}),!P&&M&&!M.installed&&e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-3 p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("span",{className:"material-symbols-outlined text-yellow-500",children:"warning"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("p",{className:"font-medium text-yellow-600 dark:text-yellow-400",children:"Claude CLI not detected locally"}),e.jsx("p",{className:"text-sm text-text-muted",children:"Manual configuration is still available if fsrouter is deployed on a remote server."})]})]}),e.jsxs("div",{className:"flex items-center gap-2 pl-9",children:[e.jsxs(q,{variant:"secondary",size:"sm",onClick:()=>ae(!0),className:"!bg-yellow-500/20 !border-yellow-500/40 !text-yellow-700 dark:!text-yellow-300 hover:!bg-yellow-500/30",children:[e.jsx("span",{className:"material-symbols-outlined text-[18px] mr-1",children:"content_copy"}),"Manual Config"]}),e.jsxs(q,{variant:"outline",size:"sm",onClick:()=>j(!C),children:[e.jsx("span",{className:"material-symbols-outlined text-[18px] mr-1",children:C?"expand_less":"help"}),C?"Hide":"How to Install"]})]})]}),C&&e.jsxs("div",{className:"p-4 bg-surface border border-border rounded-lg",children:[e.jsx("h4",{className:"font-medium mb-3",children:"Installation Guide"}),e.jsxs("div",{className:"space-y-3 text-sm",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-text-muted mb-1",children:"macOS / Linux / Windows:"}),e.jsx("code",{className:"block px-3 py-2 bg-black/5 dark:bg-white/5 rounded font-mono text-xs",children:"npm install -g @anthropic-ai/claude-code"})]}),e.jsxs("p",{className:"text-text-muted",children:["After installation, run ",e.jsx("code",{className:"px-1 bg-black/5 dark:bg-white/5 rounded",children:"claude"})," to verify."]})]})]})]}),!P&&(M==null?void 0:M.installed)&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"Select Endpoint"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsx(je,{value:F||X(),onChange:oe,requiresExternalUrl:d.requiresExternalUrl,tunnelEnabled:U,tunnelPublicUrl:o,tailscaleEnabled:s,tailscaleUrl:i})]}),((R=(pe=M==null?void 0:M.settings)==null?void 0:pe.env)==null?void 0:R.ANTHROPIC_BASE_URL)&&e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"Current"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsx("span",{className:"min-w-0 truncate rounded bg-surface/40 px-2 py-2 text-xs text-text-muted sm:py-1.5",children:M.settings.env.ANTHROPIC_BASE_URL})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"API Key"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsx(be,{value:h,onChange:v,apiKeys:E,cloudEnabled:_})]}),d.defaultModels.map(n=>e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:n.name}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsxs("div",{className:"relative w-full min-w-0",children:[e.jsx("input",{type:"text",value:g[n.alias]||"",onChange:z=>l(n.alias,z.target.value),placeholder:"provider/model-id",className:"w-full min-w-0 pl-2 pr-7 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5"}),g[n.alias]&&e.jsx("button",{onClick:()=>l(n.alias,""),className:"absolute right-1 top-1/2 -translate-y-1/2 p-0.5 text-text-muted hover:text-red-500 rounded transition-colors",title:"Clear",children:e.jsx("span",{className:"material-symbols-outlined text-[14px]",children:"close"})})]}),e.jsx("button",{onClick:()=>S(n.alias),disabled:!O,className:`w-full sm:w-auto rounded border px-2 py-2 text-xs transition-colors sm:py-1.5 whitespace-nowrap sm:shrink-0 ${O?"bg-surface border-border text-text-main hover:border-primary cursor-pointer":"opacity-50 cursor-not-allowed border-border"}`,children:"Select Model"})]},n.alias)),e.jsxs("div",{className:"grid grid-cols-1 gap-1.5 sm:grid-cols-[8rem_auto_1fr_auto] sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs font-semibold text-text-main sm:text-right sm:text-sm",children:"Filter naming"}),e.jsx("span",{className:"material-symbols-outlined hidden text-text-muted text-[14px] sm:inline",children:"arrow_forward"}),e.jsxs("label",{className:"flex items-center gap-1.5 cursor-pointer select-none",children:[e.jsx("input",{type:"checkbox",checked:ie,onChange:ue,className:"w-3.5 h-3.5 accent-primary cursor-pointer"}),e.jsx("span",{className:"text-xs text-text-muted",children:"Filter naming requests"})]}),e.jsx(Be,{text:"Intercepts Claude Code's topic-naming requests and returns a fake response locally, saving API tokens.",children:e.jsx("span",{className:"material-symbols-outlined text-text-muted text-[14px] cursor-help",children:"info"})})]})]}),w&&e.jsxs("div",{className:`flex items-center gap-2 px-2 py-1.5 rounded text-xs ${w.type==="success"?"bg-green-500/10 text-green-600":"bg-red-500/10 text-red-600"}`,children:[e.jsx("span",{className:"material-symbols-outlined text-[14px]",children:w.type==="success"?"check_circle":"error"}),e.jsx("span",{children:w.text})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-2 sm:flex sm:items-center",children:[e.jsxs(q,{variant:"primary",size:"sm",onClick:u,disabled:!O,loading:ee,children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:"save"}),"Apply"]}),e.jsxs(q,{variant:"outline",size:"sm",onClick:N,disabled:!(M!=null&&M.hasFSRouter),loading:b,children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:"restore"}),"Reset"]}),e.jsxs(q,{variant:"ghost",size:"sm",onClick:()=>ae(!0),children:[e.jsx("span",{className:"material-symbols-outlined text-[14px] mr-1",children:"content_copy"}),"Manual Config"]})]})]})]}),e.jsx(fe,{isOpen:T,onClose:()=>p(!1),onSelect:ce,selectedModel:a?g[a]:null,activeProviders:Y,modelAliases:I,title:`Select model for ${a}`}),e.jsx(ye,{isOpen:V,onClose:()=>ae(!1),title:"Claude CLI - Manual Configuration",configs:xe()})]})}function ot({tool:d,isExpanded:r,onToggle:L,baseUrl:Y,apiKeys:g,activeProviders:l,cloudEnabled:A,initialStatus:O,tunnelEnabled:E,tunnelPublicUrl:_,tailscaleEnabled:B,tailscaleUrl:U}){const[o,s]=t.useState(O||null),[i,M]=t.useState(!1),[Q,P]=t.useState(!1),[K,ee]=t.useState(!1),[W,b]=t.useState(null),[y,w]=t.useState(!1),[x,C]=t.useState(""),[j,T]=t.useState(""),[p,a]=t.useState(""),[m,h]=t.useState(!1),[v,I]=t.useState(!1),[G,V]=t.useState({}),[ae,F]=t.useState(!1),[oe,ie]=t.useState("");t.useEffect(()=>{(g==null?void 0:g.length)>0&&!x&&C(g[0].key)},[g,x]),t.useEffect(()=>{O&&s(O)},[O]),t.useEffect(()=>{r&&!o&&(H(),te()),r&&te()},[r]);const te=async()=>{try{const N=await fetch("/api/models/alias"),S=await N.json();N.ok&&V(S.aliases||{})}catch(N){console.log("Error fetching model aliases:",N)}};t.useEffect(()=>{if(o!=null&&o.config){const N=o.config.match(/^model\s*=\s*"([^"]+)"/m);N&&T(N[1]);const S=o.config.match(/\[agents\.subagent\]\s*\n\s*model\s*=\s*"([^"]+)"/m);S&&a(S[1])}},[o]);const Z=(()=>{if(!(o!=null&&o.installed))return null;if(!o.config)return"not_configured";const N=o.config.match(/base_url\s*=\s*"([^"]+)"/),S=N?N[1]:"";return Ne(S,{tunnelPublicUrl:_,tailscaleUrl:U})?"configured":"other"})(),ne=()=>{const N=oe||`${Y}/v1`;return N.endsWith("/v1")?N:`${N}/v1`},ue=()=>oe||`${Y}/v1`,H=async()=>{M(!0);try{const S=await(await fetch("/api/cli-tools/codex-settings")).json();s(S)}catch(N){s({installed:!1,error:N.message})}finally{M(!1)}},f=async()=>{P(!0),b(null);try{const N=x&&x.trim()||A?x:"sk_fsrouter",S=await fetch("/api/cli-tools/codex-settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({baseUrl:ne(),apiKey:N,model:j,subagentModel:p||j})}),ce=await S.json();S.ok?(b({type:"success",text:"Settings applied successfully!"}),H()):b({type:"error",text:ce.error||"Failed to apply settings"})}catch(N){b({type:"error",text:N.message})}finally{P(!1)}},$=async()=>{ee(!0),b(null);try{const N=await fetch("/api/cli-tools/codex-settings",{method:"DELETE"}),S=await N.json();N.ok?(b({type:"success",text:"Settings reset successfully!"}),T(""),a(""),H()):b({type:"error",text:S.error||"Failed to reset settings"})}catch(N){b({type:"error",text:N.message})}finally{ee(!1)}},X=N=>{T(N.value),p||a(N.value),h(!1)},u=()=>{const N=x&&x.trim()?x:A?"<API_KEY_FROM_DASHBOARD>":"sk_fsrouter",S=p||j,ce=`# FSRouter Configuration for Codex CLI
2
2
  model = "${j}"
3
3
  model_provider = "fsrouter"
4
4