@runfusion/fusion 0.14.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +4151 -2184
- package/dist/client/assets/AgentDetailView-BoEpPOjM.css +1 -0
- package/dist/client/assets/AgentDetailView-KQz9dg0n.js +18 -0
- package/dist/client/assets/AgentsView-8Xo-c04o.js +517 -0
- package/dist/client/assets/ChatView-CjgOh8x7.js +1 -0
- package/dist/client/assets/DevServerView-BOPrzi-j.js +1 -0
- package/dist/client/assets/{DirectoryPicker-BkAIXNrP.js → DirectoryPicker-CFj7FOgn.js} +1 -1
- package/dist/client/assets/DocumentsView-CcJNmH06.js +1 -0
- package/dist/client/assets/{InsightsView-Dz9Ivclw.js → InsightsView-B0DKRIYV.js} +1 -1
- package/dist/client/assets/MemoryView-DDbr1DaJ.js +2 -0
- package/dist/client/assets/NodesView-BprfihLf.css +1 -0
- package/dist/client/assets/NodesView-BqtHfXsl.js +14 -0
- package/dist/client/assets/{PiExtensionsManager-C_U2g7y3.js → PiExtensionsManager-QgzWFBAT.js} +3 -3
- package/dist/client/assets/{PluginManager-pIDsTk5v.js → PluginManager-KHiz9oLY.js} +1 -1
- package/dist/client/assets/ResearchView-CVxPC1vz.css +1 -0
- package/dist/client/assets/ResearchView-s3SrjNBm.js +1 -0
- package/dist/client/assets/RoadmapsView-BlbAZTdi.js +6 -0
- package/dist/client/assets/RoadmapsView-DdGlfuu-.css +1 -0
- package/dist/client/assets/SettingsModal-D0QA2W5K.css +1 -0
- package/dist/client/assets/{SettingsModal-BiZVi3cI.js → SettingsModal-D5EUFR2z.js} +1 -1
- package/dist/client/assets/SettingsModal-c9MG4sxl.js +31 -0
- package/dist/client/assets/{SetupWizardModal-BcIGBBpA.js → SetupWizardModal-tTXAm1Wb.js} +1 -1
- package/dist/client/assets/SkillsView-CS4ONN3D.js +1 -0
- package/dist/client/assets/{folder-open-CgjcFqww.js → folder-open-DObdkm5J.js} +1 -1
- package/dist/client/assets/index-BRaIPmpp.js +682 -0
- package/dist/client/assets/index-DeED_ky2.css +1 -0
- package/dist/client/assets/{star-4nUh67-U.js → star-BkGA2L-k.js} +1 -1
- package/dist/client/assets/{upload-CEt5-Bnq.js → upload-B0NF4J5P.js} +1 -1
- package/dist/client/assets/{users-4I0JDmgO.js → users-DgomiHTd.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +4248 -3235
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/plugins/fusion-plugin-dependency-graph/manifest.json +16 -0
- package/dist/plugins/fusion-plugin-dependency-graph/package.json +32 -0
- package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.css +101 -0
- package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.tsx +320 -0
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/storage.test.ts +31 -0
- package/dist/plugins/fusion-plugin-dependency-graph/src/index.ts +25 -0
- package/dist/plugins/fusion-plugin-dependency-graph/src/storage.ts +23 -0
- package/package.json +8 -4
- package/skill/fusion/references/engine-tools.md +2 -2
- package/dist/client/assets/AgentDetailView-B5tq9ius.css +0 -1
- package/dist/client/assets/AgentDetailView-BBCnqhqI.js +0 -18
- package/dist/client/assets/AgentsView-BY-Yq-Te.js +0 -522
- package/dist/client/assets/ChatView-DkoJNxFW.js +0 -1
- package/dist/client/assets/DevServerView-qvs6pp6c.js +0 -1
- package/dist/client/assets/DocumentsView-BcaUGgaL.js +0 -1
- package/dist/client/assets/MemoryView-BsweARBT.js +0 -2
- package/dist/client/assets/NodesView-DCoS6iYh.css +0 -1
- package/dist/client/assets/NodesView-bAU-v4bJ.js +0 -14
- package/dist/client/assets/ResearchView-BzRdUzNq.css +0 -1
- package/dist/client/assets/ResearchView-D4Eib_uR.js +0 -1
- package/dist/client/assets/RoadmapsView-BOYnyMCh.css +0 -1
- package/dist/client/assets/RoadmapsView-BaGwsUGS.js +0 -6
- package/dist/client/assets/SettingsModal-CRyg643t.js +0 -31
- package/dist/client/assets/SettingsModal-DcGFm6NR.css +0 -1
- package/dist/client/assets/SkillMultiselect-DDHJnrkn.css +0 -1
- package/dist/client/assets/SkillMultiselect-DPARHJeQ.js +0 -1
- package/dist/client/assets/SkillsView-Da_d_HPu.js +0 -1
- package/dist/client/assets/TodoView-5rAeqYtV.js +0 -6
- package/dist/client/assets/TodoView-SeO9o7km.css +0 -1
- package/dist/client/assets/index-D1gTSlYB.css +0 -1
- package/dist/client/assets/index-DoQ5ALYY.js +0 -662
- package/dist/client/assets/list-checks-C9YWtF7h.js +0 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as s,j as t}from"./vendor-react-K0fH_qHe.js";import{e as et,aS as Ht,v as Bt,aT as qt,x as Vt,aU as Gt,aV as Kt,aW as Xt,aX as Jt,aY as Yt,aZ as Qt,s as Zt,a_ as es,q as ts,a$ as ss,b0 as ns,ac as pt,ad as xt,S as as,W as lt,J as ot,aq as is,_ as rs,B as We,a9 as vt,aa as wt,b1 as ls,b2 as os,b3 as cs,aJ as ds,b4 as us,b5 as hs,b6 as ct,b7 as ms,d as fs,u as dt,i as gs}from"./index-BRaIPmpp.js";import"./vendor-xterm-DzcZoU0P.js";const Ze="kb-chat-active-session";function ps(a){const i=a?.toolCalls;if(!Array.isArray(i))return;const l=i.map(o=>{if(!o||typeof o!="object")return null;const c=o,N=typeof c.toolName=="string"?c.toolName:"";if(!N)return null;const b=c.args;return{toolName:N,...b&&typeof b=="object"?{args:b}:{},isError:!!c.isError,result:c.result,status:"completed"}}).filter(o=>o!==null);return l.length>0?l:void 0}function ut(a){return{id:a.id,sessionId:a.sessionId,role:a.role,content:a.content,thinkingOutput:a.thinkingOutput,toolCalls:ps(a.metadata),attachments:a.attachments,createdAt:a.createdAt}}function xs(a){const[i,l]=s.useState([]),[o,c]=s.useState(null),[N,b]=s.useState(!0),[D,S]=s.useState([]),[E,U]=s.useState(!1),[g,I]=s.useState(!1),[M,T]=s.useState(""),[f,v]=s.useState(""),[j,y]=s.useState([]),[G,P]=s.useState(""),[se,X]=s.useState(""),[_,J]=s.useState(!0),[h,C]=s.useState(new Map),w=s.useRef(null),L=s.useRef(!1),W=s.useRef(""),le=s.useRef(null),de=s.useRef(i),ue=s.useRef(o),he=s.useRef(g);de.current=i,ue.current=o,he.current=g,s.useEffect(()=>{W.current=G},[G]);const Ne=s.useRef(new Set),oe=s.useRef(0),je=s.useRef(a);je.current!==a&&(je.current=a,oe.current++),s.useEffect(()=>{const d=oe.current;et(void 0,a).then(p=>{if(oe.current!==d)return;const m=new Map;for(const k of p)m.set(k.id,k);C(m)}).catch(()=>{})},[a]);const ge=s.useCallback(async()=>{b(!0);try{const p=[...(await Ht(a)).sessions].sort((m,k)=>new Date(k.updatedAt).getTime()-new Date(m.updatedAt).getTime());l(p)}catch{}finally{b(!1)}},[a]);s.useEffect(()=>{ge()},[ge]);const Ce=s.useRef(()=>{});s.useEffect(()=>{if(N)return;const d=Bt(Ze,a);d&&i.find(m=>m.id===d)&&Ce.current(d)},[N,i,a]);const Y=s.useCallback(async(d,p)=>{U(!0);try{const m=await qt(d,{limit:50,...p},a),k=m.messages.map(ut);p?.offset&&p.offset>0?S(Z=>[...k,...Z]):S(k),J(m.messages.length>=50)}catch{}finally{U(!1)}},[a]),Q=s.useCallback(()=>{le.current?.(),le.current=null,W.current="",P(""),T(""),v(""),y([]),I(!1)},[]),me=s.useCallback((d,p)=>{w.current&&(w.current.close(),w.current=null);const m=p??i.find(k=>k.id===d);c(m||null),Q(),J(!0),d?Y(d):S([]),d?Vt(Ze,d,a):Gt(Ze,a)},[i,Y,a,Q]);Ce.current=me;const ve=s.useCallback(async d=>{const p=await Kt(d,a);w.current&&(w.current.close(),w.current=null);const m={id:p.session.id,title:p.session.title,agentId:p.session.agentId,status:p.session.status,modelProvider:p.session.modelProvider,modelId:p.session.modelId,createdAt:p.session.createdAt,updatedAt:p.session.updatedAt};return l(k=>k.some(Z=>Z.id===m.id)?k:[m,...k]),Q(),me(m.id,m),S([]),m},[a,Q,me]),we=s.useCallback(async d=>{await Xt(d,{status:"archived"},a),l(p=>p.filter(m=>m.id!==d)),o?.id===d&&(c(null),S([]))},[o,a]),pe=s.useCallback(async d=>{o?.id===d&&w.current&&(w.current.close(),w.current=null),await Jt(d,a),l(p=>p.filter(m=>m.id!==d)),o?.id===d&&(c(null),S([]))},[o,a]),Se=s.useCallback(async()=>{!o||!_||await Y(o.id,{offset:D.length})},[o,_,Y,D.length]),fe=s.useCallback(()=>{o&&(L.current=!0,le.current?.(),le.current=null,w.current?.close(),w.current=null,Yt(o.id,a).catch(()=>{}),I(!1),T(""),v(""),y([]))},[o,a]),ne=s.useCallback(()=>{W.current="",P("")},[]),ae=s.useCallback((d,p)=>{if(!o)return;if(g){W.current=d,P(d);return}L.current=!1,w.current&&(w.current.close(),w.current=null);const m=`temp-${Date.now()}`,k={id:m,sessionId:o.id,role:"user",content:d,createdAt:new Date().toISOString()};S(x=>[...x,k]),T(""),v(""),y([]),I(!0);let Z="",K="",H=[],ie=null,ee=null;const O=()=>{ie=null,T(Z)},F=()=>{ee=null,v(K)},R=()=>{ie!==null&&(cancelAnimationFrame(ie),ie=null),ee!==null&&(cancelAnimationFrame(ee),ee=null)};le.current=R;const u={onThinking:x=>{K+=x,ee===null&&(ee=requestAnimationFrame(F))},onText:x=>{Z+=x,ie===null&&(ie=requestAnimationFrame(O))},onToolStart:x=>{H=[...H,{toolName:x.toolName,args:x.args,isError:!1,status:"running"}],y(H)},onToolEnd:x=>{const z=[...H];for(let $=z.length-1;$>=0;$--){const ce=z[$];if(ce?.toolName===x.toolName&&ce.status==="running"){z[$]={...ce,status:"completed",isError:x.isError,result:x.result},H=z,y(z);return}}H=[...z,{toolName:x.toolName,isError:x.isError,result:x.result,status:"completed"}],y(H)},onDone:x=>{R();const z={id:x.messageId||`msg-${Date.now()}`,sessionId:o.id,role:"assistant",content:Z,thinkingOutput:K,toolCalls:H.length>0?H:void 0,createdAt:new Date().toISOString()};Ne.current.add(z.id),S(ce=>[...ce,z]),T(""),v(""),y([]),I(!1),w.current=null,setTimeout(()=>{Ne.current.delete(z.id)},1e3),ge();const $=W.current.trim();$&&(W.current="",P(""),ae($))},onError:x=>{if(R(),S(z=>z.filter($=>$.id!==m)),T(""),v(""),y([]),I(!1),w.current=null,console.error("[useChat] Stream error:",x),!L.current){const z=W.current.trim();z&&(W.current="",P(""),ae(z))}}};w.current=Qt(o.id,d,u,p,a)},[o,g,a,ge]),Me=se?i.filter(d=>d.title?.toLowerCase().includes(se.toLowerCase())||d.agentId.toLowerCase().includes(se.toLowerCase())):i;return s.useEffect(()=>{const d=oe.current,p=a?`?projectId=${encodeURIComponent(a)}`:"",m=()=>oe.current!==d,k=O=>{if(m())return;const F=JSON.parse(O.data);l(R=>R.some(u=>u.id===F.id)?R:[F,...R])},Z=O=>{if(m())return;const F=JSON.parse(O.data);l(R=>[...R.map(x=>x.id===F.id?F:x)]),ue.current?.id===F.id&&c(F)},K=O=>{if(m())return;const{id:F}=JSON.parse(O.data);l(R=>R.filter(u=>u.id!==F)),ue.current?.id===F&&(c(null),S([]))},H=O=>{if(m())return;const F=JSON.parse(O.data),R=ut(F);Ne.current.has(R.id)||ue.current?.id===R.sessionId&&!he.current&&S(u=>u.some(x=>x.id===R.id)?u:[...u,R])},ie=O=>{if(m())return;const{id:F}=JSON.parse(O.data);S(R=>R.filter(u=>u.id!==F))};return Zt(`/api/events${p}`,{events:{"chat:session:created":k,"chat:session:updated":Z,"chat:session:deleted":K,"chat:message:added":H,"chat:message:deleted":ie}})},[a]),s.useEffect(()=>()=>{w.current&&(w.current.close(),w.current=null)},[]),{sessions:i,activeSession:o,sessionsLoading:N,messages:D,messagesLoading:E,isStreaming:g,streamingText:M,streamingThinking:f,streamingToolCalls:j,pendingMessage:G,selectSession:me,createSession:ve,archiveSession:we,deleteSession:pe,sendMessage:ae,stopStreaming:fe,clearPendingMessage:ne,loadMoreMessages:Se,hasMoreMessages:_,searchQuery:se,setSearchQuery:X,filteredSessions:Me,refreshSessions:ge,agentsMap:h}}function St(a){const i=new Date(a),o=new Date().getTime()-i.getTime(),c=Math.floor(o/1e3),N=Math.floor(c/60),b=Math.floor(N/60),D=Math.floor(b/24);return c<60?"just now":N<60?`${N}m ago`:b<24?`${b}h ago`:D<7?`${D}d ago`:i.toLocaleDateString()}function ht(a,i){if(!a||!i)return null;const l=i.toLowerCase();if(l.includes("claude")){let c=i.replace(/^claude[- ]/i,"Claude ").replace(/sonnet[- ](\d+)[- ](\d+)/i,"Sonnet $1.$2").replace(/sonnet[- ](\d+)/i,"Sonnet $1").replace(/haiku[- ](\d+)/i,"Haiku $1").replace(/opus[- ](\d+)/i,"Opus $1").replace(/sonnet/i,"Sonnet").replace(/haiku/i,"Haiku").replace(/opus/i,"Opus").replace(/-/g," ").trim();return c=c.replace(/\s+/g," "),c.length>30?c.slice(0,30)+"…":c}if(l.includes("gpt")||l.includes("openai")){const c=i.replace(/^gpt-4-turbo$/i,"GPT-4 Turbo").replace(/^gpt-4o-mini$/i,"GPT-4o Mini").replace(/^gpt-4o$/i,"GPT-4o").replace(/^gpt-4$/i,"GPT-4").replace(/^gpt-o1-preview$/i,"GPT-o1 Preview").replace(/^gpt-o1-mini$/i,"GPT-o1 Mini").replace(/^gpt-o1$/i,"GPT-o1").replace(/^gpt/i,"GPT").trim();return c.length>30?c.slice(0,30)+"…":c}if(l.includes("gemini")){const c=i.replace(/^gemini[- ]/i,"Gemini ").replace(/pro[- ](\d+)[- ](\d+)/i,"Pro $1.$2").replace(/pro[- ](\d+)/i,"Pro $1").replace(/-/g," ").replace(/\s+/g," ").trim();return c.length>30?c.slice(0,30)+"…":c}const o=i.replace(/-/g," ").replace(/^\w/,c=>c.toUpperCase()).replace(/\s+/g," ").trim();return o.length>30?o.slice(0,30)+"…":o}function ze(a,i){return a.length<=i?a:`${a.slice(0,i)}…`}function vs(a){if(!a)return null;const i=Object.entries(a);return i.length===0?null:i.map(([l,o])=>{const c=typeof o=="string"?o:(()=>{try{return JSON.stringify(o)}catch{return String(o)}})();return`${l}=${ze(c,50)}`}).join(", ")}function ws(a){if(a===void 0)return null;if(typeof a=="string")return ze(a,200);try{return ze(JSON.stringify(a),200)}catch{return ze(String(a),200)}}function bt(a){if(!a||a.length===0)return null;const i=(g,I)=>{const M=g.status==="running",T=g.status==="completed"&&g.isError,f=vs(g.args),v=ws(g.result),j=M?f:v?`result: ${v}`:f?`args: ${f}`:null,y=M?"running":T?"error":"completed";return t.jsxs("details",{className:`chat-tool-call${M?" chat-tool-call--running":""}${T?" chat-tool-call--error":""}`,open:M,children:[t.jsxs("summary",{children:[t.jsx("span",{className:"chat-tool-call-status-dot","aria-hidden":"true"}),t.jsx("span",{className:"chat-tool-call-name",children:g.toolName}),j&&t.jsx("span",{className:"chat-tool-call-preview",title:j,children:j}),t.jsx("span",{className:"chat-tool-call-status-text",children:y})]}),t.jsxs("div",{className:"chat-tool-call-content",children:[f&&t.jsxs("div",{className:"chat-tool-call-row",children:[t.jsx("span",{className:"chat-tool-call-label",children:"args"}),t.jsx("span",{className:"chat-tool-call-value",children:f})]}),v&&t.jsxs("div",{className:`chat-tool-call-row${T?" chat-tool-call-row--error":""}`,children:[t.jsx("span",{className:"chat-tool-call-label",children:"result"}),t.jsx("span",{className:"chat-tool-call-value",children:v})]})]})]},`${g.toolName}-${I}`)},l="chat-tool-calls";if(a.length===1)return t.jsxs("div",{className:l,"data-testid":"chat-tool-calls",children:[t.jsxs("div",{className:"chat-tool-calls-header",children:[t.jsx(ct,{size:12,"aria-hidden":"true"}),t.jsx("span",{children:"Tool calls"})]}),i(a[0],0)]});const o=a.filter(g=>g.status==="running").length,c=a.filter(g=>g.status==="completed"&&g.isError).length,N=o>0,b=Array.from(new Set(a.map(g=>g.toolName))),D=b.slice(0,5),S=Math.max(0,b.length-D.length),E=S>0?`${D.join(", ")}, +${S} more`:D.join(", "),U=N?`(${o} running)`:c>0?`(${c} ${c===1?"error":"errors"})`:null;return t.jsx("div",{className:l,"data-testid":"chat-tool-calls",children:t.jsxs("details",{className:"chat-tool-calls-group","data-testid":"chat-tool-calls-group",open:N,children:[t.jsxs("summary",{className:"chat-tool-calls-group-summary",children:[t.jsx(ct,{size:12,"aria-hidden":"true"}),t.jsxs("span",{children:[a.length," tool calls"]}),t.jsx("span",{className:"chat-tool-calls-names",title:E,children:E}),U&&t.jsx("span",{className:"chat-tool-calls-group-status",children:U})]}),a.map((g,I)=>i(g,I))]})})}const yt={pre:({children:a,...i})=>t.jsx("pre",{...i,className:"chat-markdown-pre",children:a}),table:({children:a,...i})=>t.jsx("table",{...i,className:"chat-markdown-table",children:a})},Ue="__fn_agent__",Ss=280,Le=180,Oe=500,mt="fusion:chat-sidebar-width",bs=["image/png","image/jpeg","image/gif","image/webp","text/plain","application/json","text/yaml","text/markdown","text/csv","application/xml","text/x-log"];function ft(a){const i=/(^|[\s])\/([^\s]*)$/.exec(a);if(!i)return null;const l=i[1]??"",o=i[2]??"",c=i.index+l.length;return{filter:o,start:c,end:a.length}}function ys(a,i){const l=a.slice(0,i),o=/(^|[\s\n])@([\w-]*)$/.exec(l);if(!o)return null;const c=o[2]??"",N=l.length-c.length-1;return{filter:c,start:N,end:i}}function ks({projectId:a,onClose:i,onCreate:l}){const[o,c]=s.useState("agent"),[N,b]=s.useState([]),[D,S]=s.useState(!0),[E,U]=s.useState(""),[g,I]=s.useState([]),[M,T]=s.useState(!0),[f,v]=s.useState(""),[j,y]=s.useState([]),[G,P]=s.useState([]);s.useEffect(()=>{let h=!1;return S(!0),et(void 0,a).then(C=>{h||b(C)}).catch(()=>{h||b([])}).finally(()=>{h||S(!1)}),()=>{h=!0}},[a]),s.useEffect(()=>{T(!0),fs().then(h=>{I(h.models),y(h.favoriteProviders),P(h.favoriteModels)}).catch(()=>{I([]),y([]),P([])}).finally(()=>{T(!1)})},[]);const se=s.useCallback(async h=>{const C=j,L=C.includes(h)?C.filter(W=>W!==h):[h,...C];y(L);try{await dt({favoriteProviders:L,favoriteModels:G})}catch{y(C)}},[j,G]),X=s.useCallback(async h=>{const C=G,L=C.includes(h)?C.filter(W=>W!==h):[h,...C];P(L);try{await dt({favoriteProviders:j,favoriteModels:L})}catch{P(C)}},[G,j]),_=h=>{if(h.preventDefault(),o==="agent"){if(!E)return;l({agentId:E});return}if(!f)return;const C=f.indexOf("/");if(C<=0)return;const w=f.slice(0,C),L=f.slice(C+1);l({agentId:Ue,modelProvider:w,modelId:L})},J=o==="agent"?!E:!f;return t.jsx("div",{className:"chat-new-dialog-backdrop",onClick:i,role:"dialog","aria-modal":"true",children:t.jsxs("div",{className:"chat-new-dialog",onClick:h=>h.stopPropagation(),children:[t.jsx("h3",{children:"New Chat"}),t.jsxs("div",{className:"chat-new-dialog-mode-toggle","data-testid":"chat-new-dialog-mode-toggle",children:[t.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${o==="agent"?" chat-new-dialog-mode-btn--active":""}`,"data-testid":"chat-new-dialog-mode-agent",onClick:()=>{c("agent"),v("")},children:"Agent"}),t.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${o==="model"?" chat-new-dialog-mode-btn--active":""}`,"data-testid":"chat-new-dialog-mode-model",onClick:()=>{c("model"),U("")},children:"Model"})]}),t.jsxs("form",{onSubmit:_,children:[o==="agent"&&t.jsxs("label",{className:"chat-new-dialog-model-label",children:["Agent",D?t.jsx("div",{className:"chat-new-dialog-loading",children:"Loading agents..."}):N.length===0?t.jsx("div",{className:"chat-new-dialog-empty",children:"No agents available"}):t.jsx("div",{className:"chat-new-dialog-agent-list",children:N.map(h=>t.jsxs("button",{type:"button",className:`chat-new-dialog-agent-item${E===h.id?" chat-new-dialog-agent-item--selected":""}`,onClick:()=>U(h.id),"data-testid":`agent-option-${h.id}`,children:[t.jsx(We,{size:16}),t.jsx("span",{className:"chat-new-dialog-agent-name",children:h.name}),t.jsx("span",{className:"chat-new-dialog-agent-role",children:h.role})]},h.id))})]}),o==="model"&&t.jsx("div",{className:"chat-new-dialog-model-dropdown","data-testid":"chat-new-dialog-model-section",children:M?t.jsx("div",{className:"chat-new-dialog-loading",children:"Loading models..."}):t.jsx(gs,{models:g,value:f,onChange:v,label:"Model",placeholder:"Select a model",favoriteProviders:j,onToggleFavorite:se,favoriteModels:G,onToggleModelFavorite:X})}),t.jsxs("div",{className:"chat-new-dialog-actions",children:[t.jsx("button",{type:"button",className:"btn btn-sm",onClick:i,children:"Cancel"}),t.jsx("button",{type:"submit",className:"btn btn-sm btn-primary",disabled:J,children:"Create"})]})]})]})})}const gt=s.memo(function({message:i,forcePlain:l,agentName:o,showAssistantModelTag:c,activeModelTag:N,activeSessionId:b,mentionAgentsByName:D,onToggleRender:S}){const E=i.role==="assistant",U=s.useMemo(()=>{if(E)return null;const M=i.content,T=/@([\w-]+)/g,f=[];let v=0,j=T.exec(M);for(;j;){const[y,G=""]=j,P=j.index;P>v&&f.push(M.slice(v,P));const se=G.replace(/_/g," ").toLowerCase(),X=D.get(se);X?f.push(t.jsxs("span",{className:"chat-mention-chip",children:["@",X.name.replace(/\s+/g,"_")]},`${X.id}-${P}`)):f.push(y),v=P+y.length,j=T.exec(M)}return v<M.length&&f.push(M.slice(v)),f.length===0?M:f},[E,i.content,D]),g=s.useMemo(()=>{const M=i.attachments;if(!M||M.length===0||!b)return null;const T=`/api/chat/sessions/${encodeURIComponent(b)}/attachments/`;return t.jsx("div",{className:"chat-message-attachments",children:M.map(f=>{const v=f.mimeType.startsWith("image/"),j=f.id||f.filename,y=`${T}${encodeURIComponent(f.filename)}`;return v?t.jsx("a",{className:"chat-message-attachment-link","data-testid":"chat-message-attachment",href:y,target:"_blank",rel:"noopener noreferrer",children:t.jsx("img",{className:"chat-message-attachment",src:y,alt:f.originalName})},j):t.jsxs("a",{className:"chat-message-attachment-file","data-testid":"chat-message-attachment",href:y,target:"_blank",rel:"noopener noreferrer",children:[t.jsx(hs,{size:14}),t.jsx("span",{children:f.originalName})]},j)})})},[i.attachments,b]),I=s.useMemo(()=>E?l?t.jsx("div",{className:"chat-message-content chat-message-content--plain",children:i.content}):t.jsx("div",{className:"chat-message-content chat-message-content--markdown",children:t.jsx(pt,{remarkPlugins:[xt],components:yt,children:i.content})}):null,[E,l,i.content]);return t.jsxs("div",{className:`chat-message chat-message--${i.role}`,"data-testid":`chat-message-${i.id}`,children:[E&&t.jsxs("div",{className:"chat-message-avatar",children:[t.jsx(We,{size:14}),t.jsx("span",{children:o}),c&&N&&t.jsx("span",{className:"chat-model-tag",children:N}),t.jsx("button",{type:"button",className:`chat-message-render-toggle${l?" chat-message-render-toggle--plain":""}`,"data-testid":"chat-message-render-toggle","aria-label":l?"Show rendered markdown":"Show plain text",onClick:()=>S(i.id),children:l?t.jsx(vt,{size:14}):t.jsx(wt,{size:14})})]}),E?I:t.jsx("div",{className:"chat-message-content",children:U}),bt(i.toolCalls),i.thinkingOutput&&t.jsxs("details",{className:"chat-message-thinking",children:[t.jsx("summary",{children:"Thinking"}),t.jsx("pre",{className:"chat-message-thinking-content",children:i.thinkingOutput})]}),g,t.jsx("div",{className:"chat-message-time",children:St(i.createdAt)})]})});function Ts({projectId:a,addToast:i}){const{activeSession:l,sessionsLoading:o,messages:c,messagesLoading:N,isStreaming:b,streamingText:D,streamingThinking:S,streamingToolCalls:E,selectSession:U,createSession:g,archiveSession:I,deleteSession:M,sendMessage:T,stopStreaming:f,pendingMessage:v,clearPendingMessage:j,searchQuery:y,setSearchQuery:G,filteredSessions:P}=xs(a),[se,X]=s.useState(!1),[_,J]=s.useState(""),[h,C]=s.useState(null),[w,L]=s.useState(null),[W,le]=s.useState(!0),[de,ue]=s.useState(Ss),[he,Ne]=s.useState(new Map),[oe,je]=s.useState([]),[ge,Ce]=s.useState(!0),[Y,Q]=s.useState(!1),[me,ve]=s.useState(""),[we,pe]=s.useState(0),[Se,fe]=s.useState(""),[ne,ae]=s.useState(!1),[Me,d]=s.useState(0),[p,m]=s.useState(-1),[k,Z]=s.useState(()=>new Set),[K,H]=s.useState([]),[ie,ee]=s.useState(!1),[,O]=s.useState(!1),[F,R]=s.useState({top:0,left:0}),u=es({projectId:a}),x=s.useCallback(e=>{if(!e||!u.mentionActive)return;const n=e.getBoundingClientRect();R({top:n.top-260,left:n.left+8})},[u.mentionActive]),z=s.useRef(null),$=s.useRef(null),ce=s.useRef(null),B=s.useRef(null),$e=s.useRef(!1),Ee=s.useRef(!1),tt=s.useRef(null),st=s.useRef([]),Te=s.useRef(0),q=ts()==="mobile";s.useEffect(()=>{try{const e=localStorage.getItem(mt);if(!e)return;const n=Number.parseInt(e,10);if(Number.isNaN(n))return;const r=Math.max(Le,Math.min(Oe,n));ue(r)}catch{}},[]);const{keyboardOverlap:He,viewportHeight:nt,viewportOffsetTop:kt,keyboardOpen:Be}=ss({enabled:q&&!!l}),Nt=Be?{"--keyboard-overlap":`${He}px`,"--vv-offset-top":`${kt}px`,...nt!==null?{"--vv-height":`${nt}px`}:{}}:{},te=s.useMemo(()=>{const e=me.trim().toLowerCase();return(e?oe.filter(r=>r.name.toLowerCase().includes(e)):oe).slice(0,10)},[oe,me]),be=s.useMemo(()=>Array.from(he.values()),[he]),xe=s.useMemo(()=>{const e=Se.trim().toLowerCase();return e?be.filter(n=>n.name.toLowerCase().includes(e)):be},[be,Se]),at=s.useMemo(()=>{const e=new Map;for(const n of be)e.set(n.name.toLowerCase(),n);return e},[be]);s.useEffect(()=>{pe(0)},[te]),s.useEffect(()=>{d(0)},[Se,ne]),s.useEffect(()=>()=>{$.current!==null&&window.clearTimeout($.current)},[]),s.useEffect(()=>{const e=ce.current;e&&(e.scrollTop=e.scrollHeight)},[c,D,S,b]),s.useEffect(()=>{if(He<=0)return;const e=ce.current;e&&(e.scrollTop=e.scrollHeight)},[He]),s.useEffect(()=>{if(!q||!Be)return;const e=document.documentElement,n=document.body,r={htmlOverflow:e.style.overflow,bodyOverflow:n.style.overflow};return e.style.overflow="hidden",n.style.overflow="hidden",()=>{e.style.overflow=r.htmlOverflow,n.style.overflow=r.bodyOverflow}},[q,Be]),s.useEffect(()=>{const e=()=>C(null);if(h)return document.addEventListener("click",e),()=>document.removeEventListener("click",e)},[h]),s.useEffect(()=>{let e=!1;const n=a;return et(void 0,a).then(r=>{if(e||n!==a)return;const A=new Map;for(const V of r)A.set(V.id,V);Ne(A)}).catch(()=>{}),()=>{e=!0}},[a]),s.useEffect(()=>{let e=!1;return Ce(!0),ns(a).then(n=>{e||je(n)}).catch(()=>{e||je([])}).finally(()=>{e||Ce(!1)}),()=>{e=!0}},[a]),s.useEffect(()=>{st.current=K},[K]),s.useEffect(()=>()=>{for(const e of st.current)e.previewUrl&&URL.revokeObjectURL(e.previewUrl)},[]);const Pe=s.useCallback(e=>{if(!e||e.length===0)return;const n=[];for(const r of Array.from(e)){if(!bs.includes(r.type))continue;const A=r.type.startsWith("image/");n.push({file:r,previewUrl:A?URL.createObjectURL(r):""})}n.length>0&&H(r=>[...r,...n])},[]),jt=s.useCallback(e=>{H(n=>{const r=n[e];return r?.previewUrl&&URL.revokeObjectURL(r.previewUrl),n.filter((A,V)=>V!==e)})},[]),Ct=s.useCallback(e=>{const n=e.clipboardData?.files;if(!n||n.length===0)return;const r=Array.from(n).filter(A=>A.type.startsWith("image/"));r.length!==0&&Pe(r)},[Pe]),Mt=s.useCallback(async e=>{try{await g(e),X(!1),q&&le(!1)}catch{i("Failed to create chat session","error")}},[g,i,q]),qe=s.useCallback(()=>{J(""),Q(!1),ve(""),ae(!1),fe(""),m(-1),H(e=>{for(const n of e)n.previewUrl&&URL.revokeObjectURL(n.previewUrl);return[]})},[]),Ae=s.useCallback(()=>{const e=_.trim(),n=K.map(r=>r.file);if(!(!e&&n.length===0||!l)){if(e==="/clear"){qe(),f(),j(),g({agentId:l.agentId,modelProvider:l.modelProvider??void 0,modelId:l.modelId??void 0}).catch(()=>{i("Failed to clear conversation","error")});return}qe(),T(e,n)}},[_,K,l,qe,f,j,g,i,T]),Fe=s.useCallback(()=>{if(typeof window>"u"||window.innerWidth>768)return;const e=B.current;if(!e||e.disabled)return;const n=window.scrollX,r=window.scrollY;e.focus({preventScroll:!0}),window.requestAnimationFrame(()=>{(window.scrollX!==n||window.scrollY!==r)&&window.scrollTo(n,r)})},[]),it=s.useCallback(()=>{typeof window>"u"||window.innerWidth>768||($e.current=!0)},[]),Ve=s.useCallback(e=>{J(n=>{const r=ft(n);if(!r)return n;const A=`/skill:${e.name} `,V=n.slice(0,r.start)+A+n.slice(r.end);return window.requestAnimationFrame(()=>{B.current&&(B.current.style.height="auto",B.current.style.height=`${Math.min(B.current.scrollHeight,120)}px`,B.current.focus())}),V}),Q(!1),ve(""),pe(0)},[]),Ge=s.useCallback(e=>{const n=B.current;if(!n||p<0)return;const r=n.selectionStart??Te.current,A=n.selectionEnd??r,V=Math.max(r,A),De=Math.min(p,V),ye=`${`@${e.name.replace(/\s+/g,"_")}`} `,Qe=_.slice(0,De)+ye+_.slice(V),ke=De+ye.length;J(Qe),ae(!1),fe(""),d(0),m(-1),window.requestAnimationFrame(()=>{B.current&&(B.current.style.height="auto",B.current.style.height=`${Math.min(B.current.scrollHeight,120)}px`,B.current.focus(),B.current.setSelectionRange(ke,ke))})},[p,_]),Tt=s.useCallback(e=>{if(Te.current=e.currentTarget.selectionStart??Te.current,u.mentionActive&&u.files.length>0){if(u.handleKeyDown(e,_),e.key==="Enter"||e.key==="Tab"){const n=u.files[u.selectedIndex];if(n){const r=u.selectFile(n,_);J(r),u.dismissMention(),O(!1)}}return}if(ne&&e.key==="ArrowDown"){e.preventDefault(),xe.length>0&&d(n=>(n+1)%xe.length);return}if(ne&&e.key==="ArrowUp"){e.preventDefault(),xe.length>0&&d(n=>n===0?xe.length-1:n-1);return}if(ne&&e.key==="Enter"){e.preventDefault();const n=xe[Me]??xe[0];n&&Ge(n);return}if(ne&&e.key==="Escape"){e.preventDefault(),ae(!1),fe(""),m(-1);return}if(Y&&e.key==="ArrowDown"){e.preventDefault(),te.length>0&&pe(n=>(n+1)%te.length);return}if(Y&&e.key==="ArrowUp"){e.preventDefault(),te.length>0&&pe(n=>n===0?te.length-1:n-1);return}if(Y&&(e.key==="Enter"||e.key==="Tab")&&te.length>0){e.preventDefault();const n=te[we]??te[0];n&&Ve(n);return}if(Y&&e.key==="Escape"){e.preventDefault(),Q(!1);return}e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Ae())},[ne,xe,Me,Ge,Y,te,we,Ve,Ae,u,_]),Ie=s.useCallback((e,n)=>{const r=ys(e,n);if(r){ae(!0),fe(r.filter),m(r.start);return}ae(!1),fe(""),m(-1)},[]),At=s.useCallback(e=>{const n=e.target,r=n.value,A=n.selectionStart??r.length;Te.current=A,J(r);const V=ft(r);V?(Q(!0),ve(V.filter)):(Q(!1),ve("")),Ie(r,A),u.detectMention(r,A),O(u.mentionActive),u.mentionActive&&x(n),n.style.height="auto",n.style.height=`${Math.min(n.scrollHeight,120)}px`},[Ie]),Ke=s.useCallback(e=>{const n=e.currentTarget,r=n.selectionStart??n.value.length;Te.current=r,Ie(n.value,r),u.detectMention(n.value,r),O(u.mentionActive),u.mentionActive&&x(n)},[Ie,u,x]),Rt=s.useCallback(e=>{e.key!=="Escape"&&Ke(e)},[Ke]),Dt=s.useCallback(()=>{if($e.current){window.requestAnimationFrame(()=>{Fe()});return}$.current!==null&&window.clearTimeout($.current),$.current=window.setTimeout(()=>{Q(!1),ae(!1),fe(""),m(-1),O(!1),u.dismissMention(),$.current=null},120)},[u,Fe]),$t=s.useCallback(()=>{$.current!==null&&(window.clearTimeout($.current),$.current=null)},[]),Et=s.useCallback(async e=>{C(null);try{await I(e),i("Conversation archived","success")}catch{i("Failed to archive conversation","error")}},[I,i]),Pt=s.useCallback(async e=>{L(null),C(null);try{await M(e),i("Conversation deleted","success")}catch{i("Failed to delete conversation","error")}},[M,i]),Re=s.useCallback(e=>{try{localStorage.setItem(mt,String(e))}catch{}},[]),Ft=s.useCallback(e=>{if(q)return;e.preventDefault(),e.stopPropagation();const n=e.currentTarget;typeof n.setPointerCapture=="function"&&n.setPointerCapture(e.pointerId);const r=e.clientX,A=de;let V=A;document.body.style.userSelect="none";const De=ye=>{const Qe=ye.clientX-r,ke=Math.max(Le,Math.min(Oe,A+Qe));V=ke,ue(ke),Re(ke)},Ye=ye=>{typeof n.releasePointerCapture=="function"&&n.releasePointerCapture(ye.pointerId),document.body.style.userSelect="",document.removeEventListener("pointermove",De),document.removeEventListener("pointerup",Ye),Re(V)};document.addEventListener("pointermove",De),document.addEventListener("pointerup",Ye)},[q,Re,de]),It=s.useCallback(e=>{if(q||e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;e.preventDefault();const n=e.shiftKey?50:10,r=e.key==="ArrowLeft"?-n:n,A=Math.max(Le,Math.min(Oe,de+r));ue(A),Re(A)},[q,Re,de]),_t=s.useCallback(e=>{U(e),q&&le(!1)},[U,q]),Lt=s.useCallback(()=>{U(""),le(!0)},[U]),Ot=()=>t.jsxs("div",{className:"chat-empty-state",children:[t.jsx(ms,{size:48,strokeWidth:1.5}),t.jsx("h2",{children:"Start a new conversation"}),t.jsxs("button",{className:"btn btn-primary",onClick:()=>X(!0),children:[t.jsx(ot,{size:16}),"New Chat"]})]}),re=ht(l?.modelProvider,l?.modelId),rt=l?.agentId===Ue?re??"Fusion":l?.title||he.get(l?.agentId??"")?.name||l?.agentId||"Chat",zt=!!(re&&re!==rt),_e=he.get(l?.agentId??"")?.name||(l?.agentId===Ue?re??"Fusion":l?.agentId?.slice(0,30)??"Fusion"),Xe=!!(re&&re!==_e),Ut=v.length>50?`${v.slice(0,50)}…`:v,Je=s.useCallback(e=>{Z(n=>{const r=new Set(n);return r.has(e)?r.delete(e):r.add(e),r})},[]),Wt=s.useCallback((e,n=!1)=>n?t.jsx("div",{className:"chat-message-content chat-message-content--plain",children:e}):t.jsx("div",{className:"chat-message-content chat-message-content--markdown",children:t.jsx(pt,{remarkPlugins:[xt],components:yt,children:e})}),[]);return t.jsxs("div",{className:"chat-view",children:[t.jsxs("div",{className:`chat-sidebar${W?"":" chat-sidebar--hidden"}`,style:q?void 0:{width:`${de}px`},children:[t.jsx("div",{className:"chat-sidebar-search",children:t.jsxs("div",{className:"chat-sidebar-search-wrapper",children:[t.jsx(as,{size:14,className:"chat-sidebar-search-icon"}),t.jsx("input",{type:"text",className:"chat-sidebar-search",placeholder:"Search conversations...",value:y,onChange:e=>G(e.target.value),"data-testid":"chat-search-input"})]})}),t.jsx("div",{className:"chat-session-list chat-sidebar-list",children:o?t.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"Loading..."}):P.length===0?t.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"No conversations yet"}):P.map(e=>t.jsxs("div",{className:`chat-session-item${l?.id===e.id?" chat-session-item--active":""}`,onClick:()=>_t(e.id),onContextMenu:n=>{n.preventDefault(),C({sessionId:e.id,x:n.clientX,y:n.clientY})},"data-testid":`chat-session-${e.id}`,children:[t.jsx("button",{className:"chat-session-delete-btn",onClick:n=>{n.stopPropagation(),L(e.id)},"data-testid":"chat-session-delete-btn","aria-label":"Delete conversation",children:t.jsx(lt,{size:14})}),t.jsx("div",{className:"chat-session-title",children:e.title||"Untitled"}),t.jsx("div",{className:"chat-session-preview",children:e.lastMessagePreview||"No messages"}),t.jsxs("div",{className:"chat-session-meta",children:[t.jsx("span",{children:he.get(e.agentId)?.name||(e.agentId===Ue?ht(e.modelProvider,e.modelId)??"Fusion":e.agentId.slice(0,30))}),t.jsx("span",{children:e.updatedAt?St(e.updatedAt):""})]})]},e.id))}),t.jsx("div",{className:"chat-sidebar-footer",children:t.jsxs("button",{className:"btn btn-sm btn-primary chat-sidebar-footer-btn",onClick:()=>X(!0),"data-testid":"chat-new-btn",children:[t.jsx(ot,{size:14}),"New Chat"]})})]}),!q&&W&&t.jsx("div",{className:"chat-sidebar-resize-handle",role:"separator","aria-orientation":"vertical","aria-valuemin":Le,"aria-valuemax":Oe,"aria-valuenow":de,"aria-label":"Resize chat sidebar",tabIndex:0,onPointerDown:Ft,onKeyDown:It}),h&&t.jsxs("div",{className:"chat-session-context-menu",style:{top:h.y,left:h.x},onClick:e=>e.stopPropagation(),children:[t.jsxs("button",{onClick:()=>Et(h.sessionId),"data-testid":"chat-context-archive",children:[t.jsx(is,{size:14}),"Archive"]}),t.jsxs("button",{onClick:()=>{C(null),L(h.sessionId)},"data-testid":"chat-context-delete",children:[t.jsx(lt,{size:14}),"Delete"]})]}),w&&t.jsx("div",{className:"chat-new-dialog-backdrop",onClick:()=>L(null),children:t.jsxs("div",{className:"chat-new-dialog",onClick:e=>e.stopPropagation(),children:[t.jsx("h3",{children:"Delete Conversation?"}),t.jsx("p",{style:{fontSize:"14px",color:"var(--text-secondary)",marginBottom:"16px"},children:"This action cannot be undone. All messages in this conversation will be permanently deleted."}),t.jsxs("div",{className:"chat-new-dialog-actions",children:[t.jsx("button",{className:"btn btn-sm",onClick:()=>L(null),children:"Cancel"}),t.jsx("button",{className:"btn btn-sm btn-danger",onClick:()=>void Pt(w),children:"Delete"})]})]})}),t.jsxs("div",{className:"chat-thread",style:Nt,children:[(l||!q)&&t.jsxs("div",{className:"chat-thread-header",children:[q&&l&&t.jsx("button",{className:"btn-icon",onClick:Lt,"data-testid":"chat-back-btn",children:t.jsx(rs,{size:16})}),t.jsx(We,{size:16}),t.jsx("span",{className:"chat-thread-header-title",children:rt}),zt&&t.jsx("span",{className:"chat-model-tag",children:re})]}),t.jsxs("div",{className:"chat-messages",ref:ce,children:[b?t.jsxs(t.Fragment,{children:[c.map(e=>t.jsx(gt,{message:e,forcePlain:k.has(e.id),agentName:_e,showAssistantModelTag:Xe,activeModelTag:re,activeSessionId:l?.id??null,mentionAgentsByName:at,onToggleRender:Je},e.id)),t.jsxs("div",{className:"chat-message chat-message--assistant chat-message--streaming",children:[t.jsxs("div",{className:"chat-message-avatar",children:[t.jsx(We,{size:14}),t.jsx("span",{children:_e}),Xe&&t.jsx("span",{className:"chat-model-tag",children:re}),t.jsx("button",{type:"button",className:`chat-message-render-toggle${k.has("__streaming__")?" chat-message-render-toggle--plain":""}`,"data-testid":"chat-message-render-toggle","aria-label":k.has("__streaming__")?"Show rendered markdown":"Show plain text",onClick:()=>Je("__streaming__"),children:k.has("__streaming__")?t.jsx(vt,{size:14}):t.jsx(wt,{size:14})})]}),D?Wt(D,k.has("__streaming__")):t.jsx("div",{className:"chat-message-content chat-message-content--waiting",children:S?"Thinking…":"Connecting…"}),bt(E),S&&t.jsxs("details",{className:"chat-message-thinking",children:[t.jsx("summary",{children:"Thinking"}),t.jsx("pre",{className:"chat-message-thinking-content",children:S})]}),t.jsxs("div",{className:"chat-typing-indicator",children:[t.jsx("span",{}),t.jsx("span",{}),t.jsx("span",{})]})]})]}):N?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"Loading messages..."}):c.length===0&&!l?Ot():c.length===0&&l?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"No messages yet. Start the conversation!"}):t.jsx(t.Fragment,{children:c.map(e=>t.jsx(gt,{message:e,forcePlain:k.has(e.id),agentName:_e,showAssistantModelTag:Xe,activeModelTag:re,activeSessionId:l?.id??null,mentionAgentsByName:at,onToggleRender:Je},e.id))}),t.jsx("div",{ref:z})]}),l&&t.jsxs("div",{className:"chat-input-area",children:[t.jsx("input",{ref:tt,type:"file",accept:"image/*,.txt,.json,.yaml,.yml,.log,.csv,.xml,.md",multiple:!0,style:{display:"none"},onChange:e=>{Pe(e.target.files),e.target.value=""}}),Y&&t.jsx("div",{className:"chat-skill-menu","data-testid":"chat-skill-menu",role:"listbox","aria-label":"Skill suggestions",children:ge?t.jsx("div",{className:"chat-skill-menu-empty",children:"Loading skills…"}):te.length===0?t.jsx("div",{className:"chat-skill-menu-empty",children:me?"No skills found":"No skills available"}):te.map((e,n)=>t.jsxs("button",{type:"button",role:"option","aria-selected":n===we,className:`chat-skill-menu-item${n===we?" chat-skill-menu-item--highlighted":""}`,onMouseDown:r=>r.preventDefault(),onMouseEnter:()=>pe(n),onClick:()=>Ve(e),children:[t.jsx("span",{className:"chat-skill-menu-item-name",children:e.name}),t.jsx("span",{className:"chat-skill-menu-item-description",title:e.relativePath,children:e.relativePath})]},e.id))}),K.length>0&&t.jsx("div",{className:"chat-attachment-previews","data-testid":"chat-attachment-previews",children:K.map((e,n)=>t.jsxs("div",{className:"chat-attachment-preview","data-testid":`chat-attachment-preview-${n}`,children:[e.previewUrl?t.jsx("img",{src:e.previewUrl,alt:e.file.name}):t.jsx("span",{className:"chat-attachment-preview-name",children:e.file.name}),t.jsx("button",{type:"button",className:"chat-attachment-remove",onClick:()=>jt(n),"data-testid":`chat-attachment-remove-${n}`,"aria-label":`Remove ${e.file.name}`,children:"×"})]},e.previewUrl||`${e.file.name}-${n}`))}),t.jsxs("div",{className:"chat-input-row",children:[t.jsx("button",{type:"button",className:"btn-icon chat-attach-btn","data-testid":"chat-attach-btn","aria-label":"Attach files",onClick:()=>tt.current?.click(),children:t.jsx(ls,{size:16})}),t.jsxs("div",{className:`chat-input-wrapper${ie?" chat-input-wrapper--dragover":""}`,onDragOver:e=>{e.preventDefault(),ee(!0)},onDragLeave:()=>ee(!1),onDrop:e=>{e.preventDefault(),ee(!1),Pe(e.dataTransfer.files)},children:[t.jsx("textarea",{ref:B,className:"chat-input-textarea",placeholder:"Type a message...",value:_,onChange:At,onKeyDown:Tt,onKeyUp:Rt,onClick:Ke,onBlur:Dt,onFocus:$t,onPaste:Ct,onTouchStart:e=>{typeof window>"u"||window.innerWidth>768||document.activeElement!==e.currentTarget&&(e.preventDefault(),e.currentTarget.focus({preventScroll:!0}))},rows:1,"data-testid":"chat-input"}),t.jsx(os,{agents:be,filter:Se,highlightedIndex:Me,visible:ne,onSelect:Ge,position:"below"}),t.jsx(cs,{visible:u.mentionActive&&!ne,position:F,files:u.files,selectedIndex:u.selectedIndex,onSelect:e=>{const n=u.selectFile(e,_);J(n),u.dismissMention(),O(!1),B.current?.focus()},loading:u.loading}),v&&t.jsxs("div",{className:"chat-pending-message","data-testid":"chat-pending-indicator",children:[t.jsx("span",{children:`Queued: ${Ut}`}),t.jsx("button",{type:"button",className:"chat-pending-message-dismiss","aria-label":"Dismiss queued message","data-testid":"chat-pending-dismiss",onClick:j,children:"×"})]})]}),b?t.jsx("button",{className:"chat-input-stop",onClick:f,"aria-label":"Stop generation","data-testid":"chat-stop-btn",children:t.jsx(ds,{size:14})}):t.jsx("button",{type:"button",className:"chat-input-send",onPointerDown:e=>{typeof window>"u"||window.innerWidth>768||(e.preventDefault(),e.pointerType&&e.pointerType!=="mouse"&&(Ee.current=!0,it(),Fe(),Ae(),window.setTimeout(()=>{$e.current=!1},1500)))},onTouchStart:e=>{typeof window>"u"||window.innerWidth>768||(e.preventDefault(),Ee.current=!0,it(),Fe(),Ae(),window.setTimeout(()=>{$e.current=!1},1500))},onMouseDown:e=>{typeof window>"u"||window.innerWidth>768||e.preventDefault()},onClick:()=>{if(Ee.current){Ee.current=!1;return}Ae()},disabled:!_.trim()&&K.length===0,"data-testid":"chat-send-btn",children:t.jsx(us,{size:16})})]})]})]}),se&&t.jsx(ks,{projectId:a,onClose:()=>X(!1),onCreate:Mt})]})}export{Ts as ChatView};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r,j as t}from"./vendor-react-K0fH_qHe.js";import{bK as De,bL as de,bM as Ze,bN as ue,s as Ue,bO as ge,bP as we,bQ as xe,bR as ye,bS as et,bT as ae,bU as tt,bV as rt,bW as st,bX as nt,bY as at,bZ as ie,L as ee,S as it,b_ as lt,b$ as ct,ae as ot,c0 as Me,T as Ae,c1 as dt,U as ut,aJ as vt,aK as mt,aa as ft,ap as pt,R as ht}from"./index-BRaIPmpp.js";import"./vendor-xterm-DzcZoU0P.js";const ve=500,bt=3e3;function B(e){return e instanceof Error?e.message:String(e)}function Pe(e){return e.length<=ve?e:e.slice(-ve)}function le(e,i){return Pe([...e,i])}function G(e){try{return JSON.parse(e)}catch{return null}}function Q(e){const i=e.text??"";return e.stream==="stderr"?`[stderr] ${i}`:i}function gt(e){return e?.previewUrl??null}async function Se(e){return tt(e)}async function Ne(e,i){return rt(e,i)}async function wt(e){return st(e)}async function xt(e){return nt(e)}async function je(e){return at(e)}function V(e){try{return e()}catch{return null}}function ce(){return typeof V(()=>de)=="function"&&typeof V(()=>De)=="function"}function X(e){return{config:{id:e.id??"default",name:e.name??"Dev Server",command:e.command??"",cwd:e.cwd??"."},status:e.status,runtime:e.pid?{pid:e.pid,startedAt:e.startedAt??new Date().toISOString(),exitCode:e.exitCode??void 0,previewUrl:e.previewUrl}:void 0,previewUrl:e.previewUrl??e.detectedUrl??e.manualUrl??void 0,logHistory:(e.logs??[]).map(i=>({timestamp:new Date().toISOString(),stream:i.startsWith("[stderr]")?"stderr":"stdout",text:i.replace(/^\[stderr\]\s*/,"")}))}}function yt(e){const[i,o]=r.useState(null),[b,y]=r.useState([]),[w,f]=r.useState([]),[k,U]=r.useState([]),[C,P]=r.useState(!0),[S,u]=r.useState(null),n=r.useRef(0),[d,M]=r.useState(null),R=r.useCallback(a=>{if(o(a),a?.logHistory){const s=a.logHistory.slice(-ve).map(Q);f(s)}},[]),A=r.useCallback(async()=>{const a=n.current;try{if(ce())if(d){const s=await De(d,e);if(n.current!==a)return;R(s)}else{const s=await de(e);if(n.current!==a)return;y(s),s.length>0&&(M(s[0].config.id),R(s[0]))}else{const s=await Se(e);if(n.current!==a)return;const c=X(s);y([c]),R(c)}u(null)}catch(s){if(n.current!==a)return;u(B(s))}},[R,e,d]);r.useEffect(()=>{n.current+=1;const a=n.current;o(null),y([]),f([]),U([]),P(!0),u(null),M(null),(async()=>{try{const[c,l]=await Promise.allSettled([ce()?de(e):Se(e).then(N=>[X(N)]),typeof V(()=>ae)=="function"?ae(e):je(e).then(N=>N.map(g=>({name:g.name,command:g.command,cwd:g.cwd,scriptName:g.scriptName,packagePath:g.packagePath})))]);if(n.current!==a)return;let v=null;if(c.status==="fulfilled"){const N=c.value;if(y(N),N.length>0){const g=N[0];ce()&&M(g.config.id),R(g)}}else v=B(c.reason);l.status==="fulfilled"&&U(l.value),v&&u(v)}catch(c){if(n.current!==a)return;u(B(c))}finally{n.current===a&&P(!1)}})()},[R,e]),r.useEffect(()=>{const a=d?Ze(d,e):typeof V(()=>ue)=="function"?ue(e):null;if(!a)return;const s=n.current,c=Ue(a,{events:{history:l=>{if(n.current!==s)return;const v=G(l.data);if(v?.lines){const N=v.lines.map(Q);f(Pe(N))}},log:l=>{if(n.current!==s)return;const v=G(l.data);if(v){const N=typeof v.line=="string"?v.line:Q(v);f(g=>le(g,N))}},"dev-server:log":l=>{if(n.current!==s)return;const v=G(l.data);if(v){const N=typeof v.line=="string"?v.line:Q(v);f(g=>le(g,N))}},"dev-server:output":l=>{if(n.current!==s)return;const v=G(l.data);v?.line&&f(N=>le(N,v.line))},status:l=>{if(n.current!==s)return;const v=G(l.data),N=v?.status;N&&o(g=>g&&{...g,status:N,runtime:v.pid?{...g.runtime??{startedAt:new Date().toISOString()},pid:v.pid}:g.runtime})},"dev-server:status":l=>{if(n.current!==s)return;const v=G(l.data);if(v?.status){const N=X(v);o(N),y([N])}},stopped:()=>{n.current},failed:()=>{n.current}},onReconnect:()=>{n.current===s&&A()},onError:()=>{n.current===s&&u(l=>l??"Lost log stream connection.")}});return()=>{c()}},[e,A,d]),r.useEffect(()=>{if(i?.status!=="running"&&i?.status!=="starting")return;const a=setInterval(()=>{A()},bt);return()=>{clearInterval(a)}},[A,i?.status]);const _=r.useCallback(async(a,s)=>{n.current+=1;const c=n.current;try{let l;if(d&&typeof V(()=>ge)=="function")l=await ge(d,e);else{const v=await Ne({command:a,cwd:s},e);l=X(v)}if(n.current!==c)return;o(l),u(null)}catch(l){if(n.current!==c)return;throw u(B(l)),l}},[e,d]),D=r.useCallback(async()=>{n.current+=1;const a=n.current;try{let s;if(d&&typeof V(()=>we)=="function")s=await we(d,e);else{const c=await wt(e);s=X(c)}if(n.current!==a)return;o(s),u(null)}catch(s){if(n.current!==a)return;throw u(B(s)),s}},[e,d]),j=r.useCallback(async()=>{n.current+=1;const a=n.current;try{let s;if(d&&typeof V(()=>xe)=="function")s=await xe(d,e);else{const c=await xt(e);s=X(c)}if(n.current!==a)return;o(s),u(null)}catch(s){if(n.current!==a)return;throw u(B(s)),s}},[e,d]),T=r.useCallback(async a=>{n.current+=1;const s=n.current;try{let c;if(d&&typeof V(()=>ye)=="function")c=await ye(d,a,e);else{const l=await et({url:a},e);c={url:l.manualUrl??l.previewUrl??l.detectedUrl??null,source:l.manualUrl?"manual":"auto"}}if(n.current!==s)return;o(l=>l?{...l,previewUrl:c.url??void 0}:null),u(null)}catch(c){if(n.current!==s)return;throw u(B(c)),c}},[e,d]),h=r.useCallback(async()=>{n.current+=1;const a=n.current;try{let s;try{s=await ae(e)}catch{s=(await je(e)).map(l=>({name:l.name,command:l.command,cwd:l.cwd,scriptName:l.scriptName,packagePath:l.packagePath}))}if(n.current!==a)return;U(s),u(null)}catch(s){if(n.current!==a)return;throw u(B(s)),s}},[e]),p=r.useCallback(async(a,s)=>{if(typeof a!="string"&&!d)try{const v=a,N=await Ne({command:v.command,cwd:v.cwd,scriptName:v.scriptName,packagePath:v.packagePath??v.cwd},e),g=X(N);o(g),y([g]),u(null);return}catch(v){throw u(B(v)),v}const c=typeof a=="string"?a:a.command,l=typeof a=="string"?s:a.cwd;await _(c,l)},[e,_,d]),E=r.useCallback(async()=>{await D()},[D]),L=r.useCallback(async()=>{await j()},[j]),z=r.useCallback(async a=>{await T(a)},[T]),F=r.useCallback(async()=>{await h()},[h]),O=r.useCallback(async()=>{await A()},[A]),H=gt(i),x=i?{...i,pid:i.runtime?.pid}:null;return{session:i,sessions:b,logs:w,detectedCommands:k,previewUrl:H,isLoading:C,error:S,startServer:_,stopServer:D,restartServer:j,setPreviewUrl:T,detectCommands:h,refresh:A,candidates:k,serverState:x,loading:C,start:p,stop:E,restart:L,setManualUrl:z,detect:F,refreshStatus:O}}const ke=500,Ce=100;function Te(e){return e.length>ke?e.slice(-ke):e}function ze(e){return e==="stderr"?"stderr":"stdout"}function Y(e){try{return JSON.parse(e.data)}catch{return null}}function Z(e,i){return{id:typeof e.id=="number"&&Number.isFinite(e.id)?e.id:i,text:typeof e.text=="string"?e.text:"",stream:ze(e.stream),timestamp:typeof e.timestamp=="string"?e.timestamp:""}}function St(e,i){return{id:i,text:e,stream:"stdout",timestamp:""}}function oe(e,i){if(i.length===0)return e;const o=[...e],b=new Set(e.map(y=>y.id));for(const y of i)b.has(y.id)||(b.add(y.id),o.push(y));return o.sort((y,w)=>y.id-w.id),Te(o)}function Nt(e,i){const[o,b]=r.useState([]),[y,w]=r.useState(!1),[f,k]=r.useState(!1),[U,C]=r.useState(!1),[P,S]=r.useState(null),u=r.useRef(null),n=r.useRef(!1),d=r.useRef(0),M=r.useRef(0),R=r.useRef(e),A=r.useRef(i),_=r.useRef(0),D=r.useRef(1);(R.current!==e||A.current!==i)&&(R.current=e,A.current=i,d.current++,n.current=!0,_.current=0,D.current=1,b([]),w(!1),k(!1),C(!1),S(null),u.current&&(u.current(),u.current=null)),r.useEffect(()=>{if(!i){u.current&&(u.current(),u.current=null);return}const E=d.current,L=++M.current;n.current=!1,w(!0);const z=(x,a)=>{const s=Te(x);b(s),S(a),C(a!==null?a>s.length:!1);const c=s.length>0?s[s.length-1].id:0;_.current=c,D.current=c+1},F=x=>{if(n.current||d.current!==E||!x||typeof x!="object")return;const a=x.lines;if(!Array.isArray(a))return;if(a.length>0&&typeof a[0]=="string"){const c=a.filter(l=>typeof l=="string").map((l,v)=>St(l,v+1));z(c,c.length);return}const s=a.filter(c=>!!c&&typeof c=="object").map((c,l)=>Z(c,l+1));z(s,s.length)},O=x=>{if(n.current||d.current!==E)return;const a=typeof x.text=="string"?x.text:typeof x.line=="string"?x.line:null;if(!a)return;const s=D.current,c=typeof x.id=="number"&&Number.isFinite(x.id)?x.id:s,l={id:c,text:a,stream:ze(x.stream),timestamp:typeof x.timestamp=="string"?x.timestamp:""};_.current=Math.max(_.current,c),D.current=Math.max(D.current,c+1),b(v=>oe(v,[l])),S(v=>v===null?v:Math.max(v+1,l.id))};async function H(){try{const a=await ie({maxLines:Ce},e);if(n.current||d.current!==E||M.current!==L)return;const s=a.lines.map((c,l)=>Z(c,l+1));z(s,a.totalLines)}catch{if(n.current||d.current!==E||M.current!==L)return;z([],null)}finally{!n.current&&d.current===E&&M.current===L&&w(!1)}const x=ue(e);u.current=Ue(x,{events:{"dev-server:log":a=>{const s=Y(a);s&&O(s)},log:a=>{const s=Y(a);s&&O(s)},history:a=>{const s=Y(a);F(s)},"dev-server:history":a=>{const s=Y(a);F(s)}},onReconnect:()=>{n.current||d.current!==E||ie({lastEventId:_.current,maxLines:50},e).then(a=>{if(n.current||d.current!==E)return;const s=a.lines.map((c,l)=>Z(c,D.current+l));if(s.length>0){const c=s[s.length-1].id;_.current=Math.max(_.current,c),D.current=Math.max(D.current,c+1)}b(c=>oe(c,s)),S(a.totalLines)}).catch(()=>{})}})}return H(),()=>{n.current=!0,u.current&&(u.current(),u.current=null)}},[i,e]);const T=r.useCallback(async()=>{if(!i||f)return;const E=d.current,L=o.length;k(!0);try{const z=await ie({maxLines:Ce,offset:L},e);if(n.current||d.current!==E)return;const F=z.lines.map((O,H)=>Z(O,H+1));b(O=>oe(F,O)),C(z.totalLines>L+F.length),S(z.totalLines)}catch{}finally{k(!1)}},[i,o.length,f,e]),h=r.useCallback(()=>{b([])},[]),p=u.current!==null&&!y&&!n.current;return{entries:o,loading:y,loadingMore:f,hasMore:U,total:P,loadMore:T,clear:h,logs:o,isStreaming:p,clearLogs:h}}const jt="This preview appears to block iframe embedding. Open it in a new tab instead.",kt="The preview URL could not be loaded. Verify the server is running and the URL is correct.",Ct="Preview is taking longer than expected and may block iframe embedding.";function Et(e){return e==="blocked"?jt:e==="error"?kt:null}function Lt(e,i={}){const{loadTimeoutMs:o=1e4,detectionMethod:b=null}=i,y=r.useRef(null),w=r.useRef(null),[f,k]=r.useState("unknown"),[U,C]=r.useState(null),[P]=r.useState(b),S=r.useCallback(()=>{w.current!==null&&(window.clearTimeout(w.current),w.current=null)},[]),u=r.useCallback(j=>{k(j),C(Et(j))},[]),n=r.useCallback(()=>{k("blocked"),C(Ct)},[]);r.useEffect(()=>{if(S(),!e){k("unknown"),C(null);return}k("unknown"),C(null);let j=!1;return queueMicrotask(()=>{j||(k("loading"),C(null))}),()=>{j=!0,S()}},[S,e]),r.useEffect(()=>{if(f!=="loading"){S();return}const j=setTimeout(()=>{w.current=null,n()},o);return w.current=j,()=>{clearTimeout(j),w.current===j&&(w.current=null)}},[S,f,o,n]);const d=r.useCallback(()=>{const j=y.current;if(!j){u("embedded");return}try{if(j.contentWindow?.location?.href==="about:blank"&&j.src!=="about:blank"){u("blocked");return}}catch{}u("embedded")},[u]),M=r.useCallback(()=>{u("error")},[u]);r.useEffect(()=>{if(S(),!e){k("unknown"),C(null);return}k("unknown"),C(null)},[S]);const R=r.useCallback(()=>{S(),k("unknown"),C(null)},[S]),A=R,_=r.useMemo(()=>f==="embedded",[f]),D=r.useMemo(()=>f==="blocked"||f==="error",[f]);return{embedStatus:f,isEmbedded:_,isBlocked:D,blockReason:U,detectionMethod:P,iframeRef:y,resetEmbedStatus:R,setEmbedStatus:u,retry:A,embedContext:U,handleIframeLoad:d,handleIframeError:M}}const Rt=/\x1b\[[0-9;]*m/g;function me(e){return e.replace(Rt,"")}function _t(e){if(!e)return"";const i=new Date(e);return Number.isNaN(i.getTime())?"":i.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}function Dt(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Ut(e){if(e.stream==="stderr")return"error";const i=me(e.text).toLowerCase();return/\b(warn|warning)\b/.test(i)?"warn":/\b(error|fatal)\b/.test(i)?"error":"info"}function Mt(e,i){if(!i)return e;const o=new RegExp(`(${Dt(i)})`,"ig"),b=e.split(o),y=i.toLowerCase();return t.jsx(t.Fragment,{children:b.map((w,f)=>w.toLowerCase()===y?t.jsx("mark",{children:w},`${w}-${f}`):t.jsx("span",{children:w},`${w}-${f}`))})}function At({entries:e,loading:i,loadingMore:o,hasMore:b,total:y,onLoadMore:w,isRunning:f}){const k=r.useRef(null),U=r.useRef(e.length),C=r.useRef(f),[P,S]=r.useState(!1),[u,n]=r.useState(!1),[d,M]=r.useState(""),[R,A]=r.useState("all"),_=r.useMemo(()=>R==="all"?e:e.filter(p=>Ut(p)===R),[e,R]),D=r.useMemo(()=>{const p=d.trim().toLowerCase();return p?_.filter(E=>me(E.text).toLowerCase().includes(p)):_},[_,d]),j=D.length,T=r.useCallback(()=>{const p=k.current;p&&(p.scrollTop=p.scrollHeight,n(!1))},[]);r.useEffect(()=>{const p=C.current,E=U.current,L=e.length>E;f&&(!p||!u&&L)&&T(),C.current=f,U.current=e.length},[e.length,f,u,T]);const h=r.useCallback(()=>{const p=k.current;if(!p)return;const L=p.scrollTop+p.clientHeight>=p.scrollHeight-50;n(!L)},[]);return r.useEffect(()=>{i||e.length===0||!u&&f&&T()},[e,f,u,i,T]),i&&e.length===0?t.jsx("section",{className:"devserver-log-viewer","data-testid":"devserver-log-viewer",children:t.jsxs("div",{className:"devserver-log-viewer__loading","data-testid":"devserver-log-loading",children:[t.jsx(ee,{size:16,className:"devserver-log-viewer__spinner"}),t.jsx("span",{children:"Loading logs…"})]})}):t.jsxs("section",{className:`devserver-log-viewer${P?" devserver-log-viewer--fullscreen":""}`,"data-testid":"devserver-log-viewer",children:[t.jsxs("header",{className:"devserver-log-viewer__toolbar",children:[t.jsxs("div",{className:"devserver-log-viewer__toolbar-meta",children:[t.jsx("span",{className:"devserver-log-viewer__title",children:"Logs"}),t.jsxs("span",{className:"devserver-log-viewer__count","data-testid":"devserver-log-count",children:[y!==null?`${e.length}/${y}`:`${e.length}`," lines"]})]}),t.jsxs("div",{className:"devserver-log-viewer__toolbar-actions",children:[t.jsxs("label",{className:"devserver-log-viewer__severity",htmlFor:"devserver-log-severity-filter",children:[t.jsx("span",{className:"visually-hidden",children:"Filter logs by severity"}),t.jsxs("select",{id:"devserver-log-severity-filter",className:"select devserver-log-viewer__severity-select",value:R,onChange:p=>A(p.target.value),"data-testid":"devserver-log-severity-filter","aria-label":"Filter logs by severity",children:[t.jsx("option",{value:"all",children:"All severities"}),t.jsx("option",{value:"info",children:"Info"}),t.jsx("option",{value:"warn",children:"Warn"}),t.jsx("option",{value:"error",children:"Error"})]})]}),t.jsxs("label",{className:"devserver-log-viewer__search",htmlFor:"devserver-log-search",children:[t.jsx("span",{className:"visually-hidden",children:"Search logs"}),t.jsx(it,{size:14}),t.jsx("input",{id:"devserver-log-search",className:"input devserver-log-viewer__search-input",type:"text",value:d,onChange:p=>M(p.target.value),placeholder:"Search logs","data-testid":"devserver-log-search-input","aria-label":"Search logs"})]}),d.trim().length>0&&t.jsxs("span",{className:"devserver-log-viewer__matches","data-testid":"devserver-log-match-count",children:[j," match",j===1?"":"es"]}),t.jsx("button",{type:"button",className:"btn btn-sm btn-icon",onClick:()=>S(p=>!p),"data-testid":"devserver-log-fullscreen-toggle","aria-label":P?"Exit fullscreen logs":"Enter fullscreen logs",children:P?t.jsx(lt,{size:14}):t.jsx(ct,{size:14})})]})]}),t.jsxs("div",{className:"devserver-log-viewer__body",children:[b&&t.jsx("div",{className:"devserver-log-viewer__load-more","data-testid":"devserver-log-load-more",children:t.jsx("button",{type:"button",className:"btn btn-sm touch-target",onClick:w,disabled:o,"data-testid":"devserver-log-load-more-button",children:o?t.jsxs(t.Fragment,{children:[t.jsx(ee,{size:14,className:"devserver-log-viewer__spinner"}),"Loading older logs…"]}):"Load older logs"})}),t.jsxs("div",{ref:k,className:"devserver-log-viewer__content",onScroll:h,"data-testid":"devserver-log-content",children:[!i&&D.length===0&&t.jsx("p",{className:"devserver-log-viewer__empty","data-testid":"devserver-log-empty",children:e.length===0?"No logs yet. Start the dev server to see output.":_.length===0?"No log lines match the selected severity.":"No log lines match your search."}),D.map(p=>{const E=me(p.text),L=_t(p.timestamp);return t.jsxs("div",{className:"devserver-log-line",children:[L&&t.jsx("span",{className:"devserver-log-timestamp","data-testid":"devserver-log-timestamp",children:L}),p.stream==="stderr"&&t.jsx("span",{className:"devserver-log-stream-badge","data-testid":"devserver-log-stderr-badge",children:"ERR"}),t.jsx("span",{className:"devserver-log-text",children:Mt(E,d.trim())})]},p.id)})]}),u&&f&&t.jsxs("button",{type:"button",className:"btn btn-sm devserver-log-viewer__new-logs-button",onClick:T,"data-testid":"devserver-log-jump-button",children:[t.jsx(ot,{size:14}),"New logs"]})]})]})}const Pt="devserver-preview-iframe";function Tt({url:e,embedStatus:i,onEmbedStatusChange:o,iframeRef:b,blockReason:y,onRetry:w,className:f=Pt,embedContext:k}){const U=y??k??null,[C,P]=r.useState(0);r.useEffect(()=>{!e||i!=="unknown"||(P(d=>d+1),o("loading"))},[i,o,e]);const S=r.useCallback(()=>{const d=b.current;if(!d){o("embedded");return}try{if(d.contentWindow?.location?.href==="about:blank"&&d.src!=="about:blank"){o("blocked");return}}catch{}o("embedded")},[b,o]),u=r.useCallback(d=>{d.stopPropagation(),o("error")},[o]),n=r.useCallback(()=>{e&&window.open(e,"_blank","noopener,noreferrer")},[e]);return e?t.jsxs("div",{className:"devserver-preview-iframe-shell",children:[t.jsx("iframe",{src:e,ref:b,sandbox:"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox",className:f,title:"Dev server preview",onLoad:S,onError:u,onErrorCapture:u,"data-testid":"devserver-preview-iframe"},`${e}-${C}`),i==="loading"&&t.jsxs("div",{className:"devserver-preview-overlay","data-testid":"devserver-preview-loading",children:[t.jsx(ee,{size:16,className:"dev-server-spin"}),t.jsx("span",{children:"Loading preview..."})]}),i==="blocked"&&t.jsxs("div",{className:"devserver-preview-blocked-panel",role:"alert","data-testid":"devserver-preview-blocked-panel",children:[t.jsx(Me,{className:"devserver-preview-blocked-icon","aria-hidden":"true"}),t.jsxs("div",{children:[t.jsx("p",{className:"devserver-preview-blocked-title",children:"Preview cannot be embedded"}),U&&t.jsx("p",{className:"devserver-preview-blocked-context",children:U})]}),t.jsx("p",{className:"devserver-preview-blocked-description",children:"You can view the preview in a separate browser tab."}),t.jsxs("div",{className:"devserver-preview-blocked-actions",children:[t.jsx("button",{type:"button",className:"btn btn-primary",onClick:n,children:"Open in new tab"}),w&&t.jsx("button",{type:"button",className:"btn btn-sm",onClick:w,children:"Retry"})]})]}),i==="error"&&t.jsxs("div",{className:"devserver-preview-error-panel",role:"alert","data-testid":"devserver-preview-error-panel",children:[t.jsx(Ae,{className:"devserver-preview-blocked-icon","aria-hidden":"true"}),t.jsxs("div",{children:[t.jsx("p",{className:"devserver-preview-blocked-title",children:"Unable to load preview"}),U&&t.jsx("p",{className:"devserver-preview-blocked-context",children:U})]}),t.jsx("p",{className:"devserver-preview-blocked-description",children:"You can view the preview in a separate browser tab."}),t.jsxs("div",{className:"devserver-preview-blocked-actions",children:[t.jsx("button",{type:"button",className:"btn btn-primary",onClick:n,children:"Open in new tab"}),w&&t.jsx("button",{type:"button",className:"btn btn-sm",onClick:w,children:"Retry"})]})]})]}):null}const Ee={stopped:{className:"dev-server-status-badge--stopped",label:"Stopped"},starting:{className:"dev-server-status-badge--starting",label:"Starting..."},running:{className:"dev-server-status-badge--running",label:"Running"},stopping:{className:"dev-server-status-badge--starting",label:"Stopping..."},failed:{className:"dev-server-status-badge--failed",label:"Failed"}};function Le(e){return e instanceof Error?e.message:String(e)}function $e(e){return e==="."?"root":e}function Re(e){return e?e==="root"?".":e:null}function _e(e,i,o){return!i||e.scriptName!==i?!1:o?$e(e.cwd)===o:!0}function zt(e){return e.cwd==="."?"root":e.cwd}function $t(e){return e.length<=60?e:`${e.slice(0,60)}…`}function Ht({addToast:e,projectId:i}){const{session:o,detectedCommands:b,previewUrl:y,isLoading:w,error:f,startServer:k,stopServer:U,restartServer:C,setPreviewUrl:P,detectCommands:S,refresh:u}=yt(i),n=o?.status??"stopped",d=n==="running"||n==="starting",M=Ee[n]??Ee.stopped,{entries:R,loading:A,loadingMore:_,hasMore:D,total:j,loadMore:T}=Nt(i,!!i),h=y,p=o?.config?.cwd??null,[E,L]=r.useState(!0),[z,F]=r.useState(""),[O,H]=r.useState(""),[x,a]=r.useState(null),[s,c]=r.useState(null),[l,v]=r.useState("embedded"),N=l==="embedded"?h:null,{embedStatus:g,setEmbedStatus:Fe,resetEmbedStatus:I,iframeRef:q,isEmbedded:Oe,isBlocked:te,blockReason:re,retry:fe}=Lt(N),[pe,W]=r.useState(!1),he=r.useRef(g);r.useEffect(()=>{const m=he.current!==g;te&&m&&W(!0),g==="embedded"&&W(!1),he.current=g},[g,te]),r.useEffect(()=>{W(!1)},[h]);const J=r.useMemo(()=>{if(!x)return null;const m=Re(p);return b.find($=>!($.scriptName!==x||m&&$.cwd!==m||o?.config?.command&&$.command!==o.config.command))??b.find($=>_e($,x,p))??null},[b,o?.config?.command,x,p]);r.useEffect(()=>{typeof S=="function"&&S().catch(m=>{e(Le(m),"error")})},[e,S]),r.useEffect(()=>{if(x){L(!1);return}L(!0)},[x]),r.useEffect(()=>{if(o?.status==="running"||o?.status==="starting"){o.config?.command?.trim().length>0&&F(o.config.command);return}if(J){F(J.command);return}b.length>0&&F(m=>m.trim().length>0?m:b[0]?.command??"")},[b,J,o?.config?.command,o?.status]),r.useEffect(()=>{H(h??"")},[h]);const se=r.useCallback(()=>{h&&window.open(h,"_blank","noopener,noreferrer")},[h]),be=r.useCallback(()=>{W(!1),fe()},[fe]),Be=r.useCallback(()=>{try{const m=q.current;if(m?.contentWindow){m.contentWindow.location.reload(),W(!1),I();return}}catch{}if(!(!h||!q.current))try{const m=new URL(h);m.searchParams.set("_t",Date.now().toString()),q.current.src=m.toString(),W(!1),I()}catch{q.current.src=h,W(!1),I()}},[h,q,I]),K=r.useCallback(async(m,$,ne)=>{c(m);try{await $(),e(ne,"success")}catch(Ye){e(Le(Ye),"error")}finally{c(null)}},[e]),He=r.useCallback(m=>{a(m.scriptName),L(!1),F(m.command),e(`Selected ${m.scriptName} script.`,"success")},[e]),Ve=r.useCallback(()=>{a(null),L(!0),e("Cleared selected dev server script.","success")},[e]),We=()=>{const m=z.trim();if(m.length===0){e("Enter a command before starting the dev server.","warning");return}const $=Re(p)??".",ne=J?.cwd??$;K("start",()=>k(m,ne),"Dev server started.")},Xe=()=>{K("stop",U,"Dev server stopped.")},qe=()=>{K("restart",C,"Dev server restarted.")},Ge=()=>{const m=O.trim(),$=m.length>0?m:null;K("preview",()=>P($),$?"Preview URL updated.":"Preview URL override cleared.")},Ie=r.useCallback(()=>{f&&u()},[f,u]),Je=n==="starting"||n==="running"||s!==null,Ke=n==="stopped"||s!==null,Qe=n==="stopped"||n==="starting"||s!==null;return t.jsxs("div",{className:"dev-server-view","data-testid":"dev-server-view",children:[t.jsxs("section",{className:"dev-server-header","aria-label":"Dev server controls header",children:[t.jsxs("div",{className:"dev-server-header-title",children:[t.jsx(dt,{size:16}),t.jsx("h2",{children:"Dev Server"}),t.jsx("span",{className:`dev-server-status-badge ${M.className}`,"data-testid":"dev-server-status-badge",children:M.label})]}),t.jsxs("div",{className:"dev-server-header-actions",children:[t.jsxs("button",{type:"button",className:"btn btn-primary btn-sm",onClick:We,disabled:Je,"data-testid":"dev-server-start-button",children:[t.jsx(ut,{size:14}),t.jsx("span",{children:s==="start"?"Starting...":"Start"})]}),t.jsxs("button",{type:"button",className:"btn btn-danger btn-sm",onClick:Xe,disabled:Ke,"data-testid":"dev-server-stop-button",children:[t.jsx(vt,{size:14}),t.jsx("span",{children:s==="stop"?"Stopping...":"Stop"})]}),t.jsxs("button",{type:"button",className:"btn btn-sm",onClick:qe,disabled:Qe,"data-testid":"dev-server-restart-button",children:[t.jsx(mt,{size:14}),t.jsx("span",{children:s==="restart"?"Restarting...":"Restart"})]})]})]}),t.jsxs("section",{className:"dev-server-panel dev-server-config","aria-label":"Dev server configuration",children:[t.jsxs("div",{className:"dev-server-section-header",children:[t.jsx("h3",{children:"Configuration"}),w&&t.jsx("span",{className:"dev-server-muted",children:"Loading..."})]}),w&&!o&&b.length===0&&t.jsxs("div",{className:"dev-server-loading-state","data-testid":"dev-server-loading-state",children:[t.jsx(ee,{size:16,className:"dev-server-spin"}),t.jsx("span",{children:"Loading dev server configuration..."})]}),f&&t.jsxs("div",{className:"dev-server-error-box",role:"alert","data-testid":"dev-server-error-box",children:[t.jsx("p",{children:f}),t.jsx("button",{type:"button",className:"btn btn-sm",onClick:Ie,children:"Retry"})]}),t.jsxs("div",{className:"dev-server-section",children:[t.jsx("h3",{children:"Script Selection"}),x&&t.jsxs("div",{className:"dev-server-selected","data-testid":"dev-server-selected-summary",children:[t.jsx("span",{className:"dev-server-candidate-name",children:x}),t.jsx("span",{className:"dev-server-candidate-source",children:p??"root"}),t.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>L(!0),"data-testid":"dev-server-change-selection",children:"Change"}),t.jsx("button",{type:"button",className:"btn btn-danger btn-sm",onClick:Ve,"data-testid":"dev-server-clear-selection",children:"Clear"})]}),E&&b.length===0&&t.jsxs("p",{className:"dev-server-empty-state","data-testid":"dev-server-empty-candidates",children:["No dev server scripts detected. Check that your project has a ",t.jsx("code",{children:"package.json"})," with a ",t.jsx("code",{children:"dev"}),", ",t.jsx("code",{children:"start"}),", or similar script."]}),E&&b.length>0&&t.jsx("div",{className:"dev-server-candidates","data-testid":"dev-server-candidates",children:b.map(m=>{const $=_e(m,x,p);return t.jsxs("button",{type:"button",className:`dev-server-candidate ${$?"dev-server-candidate--selected":""}`,onClick:()=>He(m),"data-testid":`dev-server-candidate-${m.scriptName}-${$e(m.cwd)}`,children:[t.jsx("span",{className:"dev-server-candidate-name",children:m.scriptName}),t.jsx("span",{className:"dev-server-candidate-command",children:$t(m.command)}),t.jsx("span",{className:"dev-server-candidate-source",children:zt(m)})]},`${m.cwd}::${m.scriptName}::${m.command}`)})})]}),t.jsxs("div",{className:"dev-server-field-group",children:[t.jsx("label",{htmlFor:"dev-server-command",className:"dev-server-label",children:"Command"}),t.jsx("input",{id:"dev-server-command",className:"input",value:z,onChange:m=>F(m.target.value),placeholder:"pnpm dev","data-testid":"dev-server-command-input",readOnly:n==="running"||n==="starting"})]}),(n==="running"||n==="starting")&&o&&t.jsxs("div",{className:"dev-server-current-command","data-testid":"dev-server-current-command",children:[t.jsx("span",{className:"dev-server-label",children:"Running command"}),t.jsx("code",{children:o.config?.command??z})]}),t.jsxs("div",{className:"dev-server-preview-override",children:[t.jsx("label",{htmlFor:"dev-server-preview-input",className:"dev-server-label",children:"Preview URL Override"}),t.jsx("input",{id:"dev-server-preview-input",className:"input",type:"url",value:O,onChange:m=>H(m.target.value),placeholder:"http://localhost:3000","data-testid":"dev-server-preview-input"}),t.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:Ge,disabled:s==="preview","data-testid":"dev-server-set-preview",children:"Save"})]}),h&&t.jsxs("p",{className:"dev-server-preview-hint",children:["Auto-detected: ",h]})]}),t.jsx("div",{className:"dev-server-content",children:t.jsxs("section",{className:"dev-server-panel dev-server-logs-panel","data-testid":"dev-server-logs-panel","aria-label":"Dev server logs",children:[t.jsxs("div",{className:"dev-server-section-header",children:[t.jsx("h3",{children:"Logs"}),t.jsxs("span",{className:"dev-server-muted",children:[j??R.length," lines"]})]}),t.jsx("div",{className:"dev-server-logs-viewer","data-testid":"dev-server-log-viewer",children:t.jsx(At,{entries:R,loading:A,loadingMore:_,hasMore:D,total:j,onLoadMore:T,isRunning:d})})]})}),t.jsxs("section",{className:"dev-server-panel devserver-preview-panel","data-testid":"devserver-preview-panel","aria-label":"Dev server preview",children:[t.jsxs("div",{className:"devserver-preview-header",children:[t.jsxs("div",{className:"devserver-preview-title",children:[t.jsx(ft,{size:14}),t.jsx("span",{children:"Preview"})]}),t.jsxs("span",{className:"devserver-preview-url-badge devserver-preview-url-badge--auto",title:h??"No preview URL","data-testid":"devserver-preview-url-badge",children:["Auto",h?` · ${h}`:" · Not available"]}),t.jsxs("div",{className:"devserver-preview-actions",children:[t.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>v(m=>m==="embedded"?"external":"embedded"),"data-testid":"devserver-preview-mode-toggle",children:l==="embedded"?"External only":"Embedded"}),t.jsx("button",{type:"button",className:"btn btn-sm btn-icon",title:"Open in new tab",onClick:se,disabled:!h,"data-testid":"devserver-preview-open-tab",children:t.jsx(pt,{})}),t.jsx("button",{type:"button",className:"btn btn-sm btn-icon",title:"Refresh preview",onClick:Be,disabled:!h,"data-testid":"devserver-preview-refresh",children:t.jsx(ht,{})})]})]}),t.jsxs("div",{className:"devserver-preview-container","data-embed-status":g,"data-embedded":Oe?"true":"false",children:[!h&&!d&&t.jsx("p",{className:"devserver-preview-empty",children:"Start a dev server to see a live preview here."}),!h&&d&&t.jsx("p",{className:"devserver-preview-empty",children:"No preview URL detected. Start the dev server or set a manual URL to preview your app."}),h&&l==="external"&&t.jsxs("div",{className:"devserver-preview-external-only","data-testid":"devserver-preview-external-only",children:[t.jsx("p",{children:"Embedded preview is disabled. Open your app in a separate browser tab."}),t.jsx("button",{type:"button",className:"btn btn-primary btn-sm touch-target",onClick:se,"data-testid":"devserver-preview-external-open-tab",children:"Open in new tab"})]}),h&&l==="embedded"&&pe&&te&&t.jsxs("div",{className:g==="error"?"devserver-preview-error-panel":"devserver-preview-blocked-panel","data-testid":"devserver-preview-fallback",role:"alert",children:[g==="error"?t.jsx(Ae,{className:"devserver-preview-blocked-icon","aria-hidden":"true"}):t.jsx(Me,{className:"devserver-preview-blocked-icon","aria-hidden":"true"}),t.jsxs("div",{children:[t.jsx("p",{className:"devserver-preview-blocked-title",children:g==="error"?"Preview failed":"Preview blocked"}),re&&t.jsx("p",{className:"devserver-preview-blocked-context",children:re})]}),t.jsx("p",{className:"devserver-preview-blocked-description",children:"Open the preview in a new tab, or retry embedded mode after checking your server settings."}),t.jsxs("div",{className:"devserver-preview-blocked-actions",children:[t.jsx("button",{type:"button",className:"btn btn-primary",onClick:se,"data-testid":"devserver-preview-fallback-open-tab",children:"Open preview in new tab"}),t.jsx("button",{type:"button",className:"btn btn-sm",onClick:be,"data-testid":"devserver-preview-fallback-retry",children:"Retry embedded preview"})]})]}),h&&l==="embedded"&&!pe&&t.jsx(Tt,{url:h,embedStatus:g,onEmbedStatusChange:Fe,iframeRef:q,blockReason:re,onRetry:be})]})]})]})}export{Ht as DevServerView};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as i,j as r}from"./vendor-react-K0fH_qHe.js";import{
|
|
1
|
+
import{r as i,j as r}from"./vendor-react-K0fH_qHe.js";import{dU as N,dV as g,cV as b,O as m,af as P,a9 as H,aa as C,L as O,am as v}from"./index-BRaIPmpp.js";import{F as z}from"./folder-open-DObdkm5J.js";function D({value:o,onChange:d,placeholder:y,onInputKeyDown:x,nodeId:l,localNodeId:h}){const[e,n]=i.useState({isOpen:!1,loading:!1,error:null,currentPath:"",parentPath:null,entries:[],showHidden:!1}),a=i.useCallback(async(s,c=!1)=>{n(t=>({...t,loading:!0,error:null}));try{const t=await N(s,c,l,h);n(u=>({...u,loading:!1,currentPath:t.currentPath,parentPath:t.parentPath,entries:t.entries}))}catch(t){n(u=>({...u,loading:!1,error:t instanceof Error?t.message:"Failed to browse directory"}))}},[l,h]),j=i.useCallback(()=>{n(s=>s.isOpen?{...s,isOpen:!1}:{...s,isOpen:!0})},[]);i.useEffect(()=>{e.isOpen&&!e.loading&&e.entries.length===0&&!e.error&&a(o||void 0,e.showHidden)},[e.isOpen,e.loading,e.entries.length,e.error,o,e.showHidden,a,l,h]);const p=i.useCallback(s=>{a(s,e.showHidden)},[a,e.showHidden]),k=i.useCallback(()=>{d(e.currentPath),n(s=>({...s,isOpen:!1}))},[e.currentPath,d]),w=i.useCallback(()=>{n(s=>{const c=!s.showHidden;return{...s,showHidden:c}})},[]);i.useEffect(()=>{e.isOpen&&e.currentPath&&a(e.currentPath,e.showHidden)},[e.showHidden]);const f=e.currentPath?g(e.currentPath):[];return r.jsxs("div",{className:"directory-picker",children:[r.jsxs("div",{className:"directory-picker-input-row",children:[r.jsx("input",{type:"text",className:"input directory-picker-input",value:o,onChange:s=>d(s.target.value),onKeyDown:x,placeholder:y||"/path/to/your/project"}),r.jsxs("button",{type:"button",className:"btn btn-secondary btn-sm directory-picker-browse-btn",onClick:j,"aria-label":e.isOpen?"Close directory browser":"Browse directories",children:[e.isOpen?r.jsx(z,{size:16}):r.jsx(b,{size:16}),r.jsx("span",{children:"Browse"})]})]}),e.isOpen&&r.jsxs("div",{className:"directory-picker-browser",role:"tree","aria-label":"Directory browser",children:[r.jsx("div",{className:"directory-picker-breadcrumbs",children:f.map((s,c)=>r.jsxs("span",{className:"directory-picker-breadcrumb-item",children:[c>0&&r.jsx(m,{size:12,className:"directory-picker-breadcrumb-sep"}),r.jsx("button",{type:"button",className:"directory-picker-breadcrumb",onClick:()=>p(s.path),title:s.path,children:s.label})]},s.path))}),r.jsxs("div",{className:"directory-picker-toolbar",children:[e.parentPath&&r.jsxs("button",{type:"button",className:"btn btn-sm btn-secondary directory-picker-up-btn",onClick:()=>p(e.parentPath),"aria-label":"Go to parent directory",title:"Parent directory",children:[r.jsx(P,{size:14}),r.jsx("span",{children:"Up"})]}),r.jsxs("button",{type:"button",className:"btn btn-sm btn-secondary directory-picker-hidden-toggle",onClick:w,"aria-label":e.showHidden?"Hide hidden directories":"Show hidden directories",title:e.showHidden?"Hide hidden":"Show hidden",children:[e.showHidden?r.jsx(H,{size:14}):r.jsx(C,{size:14}),r.jsx("span",{children:e.showHidden?"Hide hidden":"Show hidden"})]})]}),e.loading?r.jsxs("div",{className:"directory-picker-loading",children:[r.jsx(O,{size:20,className:"animate-spin"}),r.jsx("span",{children:"Loading…"})]}):e.error?r.jsxs("div",{className:"directory-picker-error",children:[r.jsx(v,{size:16}),r.jsx("span",{children:e.error})]}):r.jsx("div",{className:"directory-picker-entries",children:e.entries.length===0?r.jsx("div",{className:"directory-picker-empty",children:"No subdirectories"}):e.entries.map(s=>r.jsxs("button",{type:"button",className:"directory-picker-entry",onClick:()=>p(s.path),role:"treeitem",title:s.path,children:[r.jsx(b,{size:16,className:"directory-picker-entry-icon"}),r.jsx("span",{className:"directory-picker-entry-name",children:s.name}),s.hasChildren&&r.jsx(m,{size:14,className:"directory-picker-entry-arrow"})]},s.path))}),r.jsxs("div",{className:"directory-picker-actions",children:[r.jsx("span",{className:"directory-picker-selected-path",title:e.currentPath,children:e.currentPath}),r.jsx("button",{type:"button",className:"btn btn-primary directory-picker-select-btn",onClick:k,children:"Select"})]})]})]})}export{D};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{a6 as oe,a7 as K,f as le,a8 as ie,F as z,a9 as de,aa as ue,S as me,X as he,R as pe,ab as fe,ac as W,ad as V,ae as X,O as je,af as xe}from"./index-BRaIPmpp.js";import"./vendor-xterm-DzcZoU0P.js";function we(n){const{projectId:c,searchQuery:u,includeProjectFiles:a=!0}=n??{},[x,l]=s.useState([]),[h,i]=s.useState([]),[o,p]=s.useState(!0),[k,b]=s.useState(null),f=s.useRef(null),g=s.useRef(!1),m=s.useRef(null),j=s.useCallback(async()=>{f.current&&f.current.abort();const C=new AbortController;f.current=C;const E=!g.current;E&&p(!0),b(null);const L=oe(u?{q:u}:void 0,c),y=a?K(c):Promise.resolve({files:[]}),[v,F]=await Promise.allSettled([L,y]);if(C.signal.aborted)return;let R=null;if(v.status==="fulfilled"?(l(v.value),g.current=!0):R=v.reason instanceof Error?v.reason.message:String(v.reason),F.status==="fulfilled"){const M=F.value.files,P=u?.trim().toLowerCase(),T=P?M.filter(N=>N.name.toLowerCase().includes(P)||N.path.toLowerCase().includes(P)):M;i(T)}b(R),E&&p(!1)},[a,c,u]);return s.useEffect(()=>(m.current&&clearTimeout(m.current),m.current=setTimeout(()=>{j()},300),()=>{m.current&&clearTimeout(m.current)}),[j]),s.useEffect(()=>(j(),()=>{f.current&&f.current.abort()}),[]),{documents:x,projectFiles:h,loading:o,error:k,refresh:j}}function ke(n,c){const[u,a]=s.useState([]),[x,l]=s.useState(!0),[h,i]=s.useState(null),o=s.useRef(null),p=s.useRef(!1),k=c?.showHidden??!1,b=s.useCallback(async f=>{o.current&&o.current.abort();const g=new AbortController;o.current=g;const m=!p.current;m&&l(!0),i(null);try{const j=await K(n,{showHidden:f?.showHidden??k});if(g.signal.aborted)return;a(j.files),p.current=!0}catch(j){if(g.signal.aborted)return;i(j instanceof Error?j.message:String(j))}finally{!g.signal.aborted&&m&&l(!1)}},[n,k]);return s.useEffect(()=>(p.current=!1,b({showHidden:k}),()=>{o.current&&o.current.abort()}),[b,k]),{files:u,loading:x,error:h,refresh:b}}const be=768;function _(n){return n?new Date(n).toLocaleString():""}function ge(n){return n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(n>=10*1024?0:1)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}function ve(n,c=200){return n.length<=c?n:`${n.substring(0,c)}…`}function Ne({document:n,renderMarkdown:c,onToggleMarkdown:u}){const[a,x]=s.useState(!1),l=ve(n.content),h=n.content.length>200;return e.jsxs("div",{className:"document-card",children:[e.jsxs("div",{className:"document-card-header",children:[e.jsxs("div",{className:"document-card-key",children:[e.jsx(z,{size:14}),e.jsx("span",{className:"document-card-key-text",children:n.key}),e.jsxs("span",{className:"document-card-revision-badge",children:["v",n.revision]})]}),e.jsx("div",{className:"document-card-actions",children:e.jsx("button",{className:"btn btn-sm document-card-expand-btn",onClick:()=>x(i=>!i),title:a?"Collapse":"Expand","aria-label":a?"Collapse content":"Expand content",children:a?e.jsx(xe,{size:14}):e.jsx(X,{size:14})})})]}),e.jsxs("div",{className:"document-card-meta",children:[e.jsx("span",{className:"document-card-author",children:n.author}),e.jsx("span",{className:"document-card-separator",children:"·"}),e.jsx("span",{className:"document-card-date",children:_(n.updatedAt)})]}),e.jsxs("div",{className:`document-card-content${a?" document-card-content--expanded":""}`,children:[a?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"document-card-content-header",children:e.jsx("button",{className:"btn btn-sm document-mode-toggle",onClick:u,"aria-label":c?"Switch to plain text":"Switch to markdown","aria-pressed":c,title:c?"Switch to plain text":"Switch to markdown",children:c?"Markdown":"Plain"})}),c?e.jsx("div",{className:"document-card-content-markdown",children:e.jsx("div",{className:"markdown-body",children:e.jsx(W,{remarkPlugins:[V],children:n.content})})}):e.jsx("pre",{className:"document-card-content-text",children:n.content})]}):e.jsx("p",{className:"document-card-preview",children:l}),h&&!a&&e.jsx("p",{className:"document-card-preview-truncated",children:"…"})]})]})}function Se({taskId:n,taskTitle:c,documents:u,onOpenTask:a,renderMarkdownStates:x,onToggleMarkdown:l}){const[h,i]=s.useState(!1);return e.jsxs("div",{className:"documents-group",children:[e.jsxs("div",{className:"documents-group-header",children:[e.jsxs("button",{className:"documents-group-toggle-btn",onClick:()=>i(o=>!o),"aria-expanded":h,"aria-label":`${h?"Collapse":"Expand"} documents for task ${n}`,children:[e.jsx("span",{className:"documents-group-toggle","aria-hidden":"true",children:h?e.jsx(X,{size:16}):e.jsx(je,{size:16})}),e.jsx("span",{className:"documents-group-task-id",children:n}),e.jsx("span",{className:"documents-group-task-title",children:c||"Untitled"})]}),e.jsxs("span",{className:"documents-group-count",children:[u.length," doc",u.length!==1?"s":""]}),e.jsx("button",{className:"documents-group-task-link",onClick:()=>a(n),"aria-label":`Open task ${n}: ${c||"Untitled"}`,children:"Open task"})]}),h&&e.jsx("div",{className:"documents-group-content",children:u.map(o=>e.jsx(Ne,{document:o,renderMarkdown:x.get(o.id)??!1,onToggleMarkdown:()=>l(o.id)},o.id))})]})}function ye({projectId:n,addToast:c,onOpenDetail:u}){const[a,x]=s.useState("project"),[l,h]=s.useState(""),[i,o]=s.useState(null),[p,k]=s.useState(!1),[b,f]=s.useState(null),[g,m]=s.useState(!1),[j,C]=s.useState(null),[E,L]=s.useState(!1),y=s.useRef(0),v=s.useRef(!1),[F,R]=s.useState(!1),[M,P]=s.useState(new Map),T=a==="tasks"?l.trim():"",{documents:N,loading:D,error:J,refresh:B}=we({projectId:n,searchQuery:T||void 0,includeProjectFiles:!1}),{files:S,loading:$,error:Y,refresh:O}=ke(n,{showHidden:p});s.useEffect(()=>{const t=()=>{L(window.innerWidth<=be)};return t(),window.addEventListener("resize",t),()=>{window.removeEventListener("resize",t)}},[]),s.useEffect(()=>{v.current=!1,x("project"),o(null),k(!1),f(null),C(null),m(!1),R(!1),P(new Map)},[n]),s.useEffect(()=>{v.current||D||$||(S.length>0?x("project"):N.length>0&&x("tasks"),v.current=!0)},[N.length,D,S.length,$]);const H=s.useMemo(()=>{const t=new Map;for(const r of N){const d=t.get(r.taskId)||[];t.set(r.taskId,[...d,r])}return Array.from(t.entries()).map(([r,d])=>{const w=[...d].sort((re,ce)=>ce.updatedAt.localeCompare(re.updatedAt));return{taskId:r,taskTitle:w[0]?.taskTitle,documents:w,latestUpdated:w[0]?.updatedAt??""}}).sort((r,d)=>d.latestUpdated.localeCompare(r.latestUpdated))},[N]),A=s.useMemo(()=>{const t=l.trim().toLowerCase();return t?S.filter(r=>{const d=r.path.toLowerCase(),w=r.name.toLowerCase();return d.includes(t)||w.includes(t)}):S},[S,l]);s.useEffect(()=>{if(!i)return;S.some(r=>r.path===i.path)||(o(null),f(null),C(null),m(!1))},[S,i]);const Z=s.useCallback(t=>{h(t.target.value)},[]),I=s.useCallback(()=>{h("")},[]),Q=s.useCallback(t=>{x(t)},[]),ee=s.useCallback(async t=>{try{const r=await le(t,n);u(r)}catch{c(`Failed to open task ${t}`,"error")}},[n,u,c]),se=s.useCallback(async t=>{o(t),m(!0),C(null),f(null);const r=y.current+1;y.current=r;try{const d=await ie("project",t.path,n);if(y.current!==r)return;f(d.content)}catch(d){if(y.current!==r)return;const w=d instanceof Error?d.message:`Failed to open ${t.path}`;C(w),c(w,"error")}finally{y.current===r&&m(!1)}},[n,c]),te=s.useCallback(()=>{o(null),f(null),C(null),m(!1)},[]),ne=s.useCallback(t=>{P(r=>{const d=new Map(r),w=d.get(t)??!1;return d.set(t,!w),d})},[]),U=a==="project"?Y:J,ae=s.useCallback(async()=>{if(a==="project"){await O();return}await B()},[a,O,B]),q=a==="project"?A.length:N.length,G=a==="project"?"Search project markdown files…":"Search task documents…";return e.jsxs("div",{className:"documents-view",children:[e.jsxs("div",{className:"documents-view-header",children:[e.jsxs("div",{className:"documents-view-title-row",children:[e.jsxs("h2",{className:"documents-view-title",children:[e.jsx(z,{size:20}),"Documents"]}),e.jsxs("span",{className:"documents-view-count",children:[q," result",q!==1?"s":""]})]}),e.jsxs("div",{className:"documents-controls-row",children:[e.jsxs("div",{className:"documents-tab-bar",role:"tablist","aria-label":"Documents sections",children:[e.jsxs("button",{className:`btn documents-tab${a==="project"?" active":""}`,role:"tab","aria-selected":a==="project","aria-label":"Show project markdown files",onClick:()=>Q("project"),children:["Project Files",e.jsx("span",{className:"documents-tab-count",children:S.length})]}),e.jsxs("button",{className:`btn documents-tab${a==="tasks"?" active":""}`,role:"tab","aria-selected":a==="tasks","aria-label":"Show task documents",onClick:()=>Q("tasks"),children:["Task Documents",e.jsx("span",{className:"documents-tab-count",children:H.length})]})]}),a==="project"&&e.jsxs("button",{className:"btn btn-sm documents-hidden-toggle",onClick:()=>k(t=>!t),"aria-pressed":p,"aria-label":p?"Hide hidden project files":"Show hidden project files",title:p?"Hide hidden files":"Show hidden files",children:[p?e.jsx(de,{size:14}):e.jsx(ue,{size:14}),p?"Hide Hidden":"Show Hidden"]}),e.jsxs("div",{className:"documents-search",children:[e.jsx(me,{size:16,className:"documents-search-icon"}),e.jsx("input",{type:"text",className:"documents-search-input",placeholder:G,value:l,onChange:Z,"aria-label":G}),l&&e.jsx("button",{className:"documents-search-clear",onClick:I,"aria-label":"Clear search",children:e.jsx(he,{size:16})})]})]})]}),e.jsx("div",{className:"documents-view-content",children:U?e.jsxs("div",{className:"documents-view-error",children:[e.jsxs("p",{children:["Failed to load ",a==="project"?"project files":"task documents",": ",U]}),e.jsxs("button",{className:"btn btn-primary",onClick:()=>void ae(),"aria-label":"Retry loading documents",children:[e.jsx(pe,{size:16}),"Retry"]})]}):a==="project"?$&&S.length===0?e.jsx("div",{className:"documents-view-loading",children:e.jsx("p",{children:"Loading project markdown files…"})}):A.length===0?e.jsx("div",{className:"documents-view-empty",children:l.trim()?e.jsxs("p",{children:['No project markdown files match "',l.trim(),'".']}):e.jsxs(e.Fragment,{children:[e.jsx(z,{size:48,className:"documents-view-empty-icon"}),e.jsx("p",{children:"No Markdown files found in this project."})]})}):e.jsxs("div",{className:`documents-project-layout${E?" documents-project-layout--mobile":""}`,children:[(!E||!i)&&e.jsx("aside",{className:"documents-view-sidebar","aria-label":"Project markdown files",children:e.jsx("ul",{className:"markdown-file-list",children:A.map(t=>{const r=i?.path===t.path;return e.jsx("li",{className:"markdown-file-list-item",children:e.jsxs("button",{className:`markdown-file-item${r?" markdown-file-item--selected":""}`,onClick:()=>void se(t),"aria-label":`Open ${t.path}`,"aria-current":r?"true":void 0,children:[e.jsx("span",{className:"markdown-file-item-name",children:t.name}),e.jsx("span",{className:"markdown-file-item-path",children:t.path}),e.jsxs("span",{className:"markdown-file-item-meta",children:[ge(t.size)," · ",_(t.mtime)]})]})},t.path)})})}),(!E||i)&&e.jsxs("section",{className:"documents-view-main","aria-label":"Project file content preview",children:[E&&i&&e.jsxs("button",{className:"btn btn-sm documents-mobile-back",onClick:te,"aria-label":"Back to project files list",children:[e.jsx(fe,{size:14}),"Back to files"]}),i?e.jsxs("div",{className:"documents-content-viewer",children:[e.jsxs("div",{className:"documents-content-header",children:[e.jsx("p",{className:"documents-file-path-header",children:i.path}),e.jsx("button",{className:"btn btn-sm document-mode-toggle",onClick:()=>R(t=>!t),"aria-label":F?"Switch to plain text":"Switch to markdown","aria-pressed":F,title:F?"Switch to plain text":"Switch to markdown",children:F?"Markdown":"Plain"})]}),g?e.jsx("p",{className:"documents-content-state",children:"Loading file content…"}):j?e.jsx("p",{className:"documents-content-state documents-content-state--error",children:j}):F?e.jsx("div",{className:"documents-content-markdown",children:e.jsx("div",{className:"markdown-body",children:e.jsx(W,{remarkPlugins:[V],children:b??""})})}):e.jsx("pre",{className:"document-card-content-text documents-content-viewer-text",children:b??""})]}):e.jsx("div",{className:"documents-view-empty",children:e.jsx("p",{children:"Select a Markdown file to view its content."})})]})]}):D&&N.length===0?e.jsx("div",{className:"documents-view-loading",children:e.jsx("p",{children:"Loading task documents…"})}):H.length===0?e.jsx("div",{className:"documents-view-empty",children:l.trim()?e.jsxs("p",{children:['No task documents match "',l.trim(),'".']}):e.jsxs(e.Fragment,{children:[e.jsx(z,{size:48,className:"documents-view-empty-icon"}),e.jsx("p",{children:"No task documents yet."}),e.jsx("p",{className:"documents-view-empty-hint",children:"Documents are created in task detail tabs."})]})}):e.jsx("div",{className:"documents-task-list-wrap",children:e.jsx("div",{className:"documents-view-list",children:H.map(({taskId:t,taskTitle:r,documents:d})=>e.jsx(Se,{taskId:t,taskTitle:r,documents:d,onOpenTask:ee,renderMarkdownStates:M,onToggleMarkdown:ne},t))})})})]})}export{ye as DocumentsView};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as a,j as s}from"./vendor-react-K0fH_qHe.js";import{c as J,
|
|
1
|
+
import{r as a,j as s}from"./vendor-react-K0fH_qHe.js";import{c as J,ag as Z,ah as ss,ai as es,aj as ts,ak as is,al as f,X as q,R as w,C as Q,am as L,an as B,ao as as,J as V,ap as ns,aq as rs,ar as W}from"./index-BRaIPmpp.js";import{U as P}from"./users-DgomiHTd.js";import"./vendor-xterm-DzcZoU0P.js";/**
|
|
2
2
|
* @license lucide-react v1.7.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{u as Le}from"./SettingsModal-D5EUFR2z.js";import{bv as Ee,bw as ke,bx as Ie,z as Re,by as qe,bz as _e,bA as Pe,bB as Me,bC as we,bD as We,bE as Oe,bF as Te,bG as Ae,bH as $e,y as Ue,bI as He,L as w,bJ as Fe}from"./index-BRaIPmpp.js";import"./vendor-xterm-DzcZoU0P.js";const O=".fusion/memory/MEMORY.md",Qe=5e4,Ye="0 3 * * *",Be="0 4 * * *";function he(i){return{memoryEnabled:i.memoryEnabled!==!1,memoryAutoSummarizeEnabled:i.memoryAutoSummarizeEnabled??!1,memoryAutoSummarizeThresholdChars:i.memoryAutoSummarizeThresholdChars??Qe,memoryAutoSummarizeSchedule:i.memoryAutoSummarizeSchedule??Ye,memoryDreamsEnabled:i.memoryDreamsEnabled??!1,memoryDreamsSchedule:i.memoryDreamsSchedule??Be}}function De(i,t){return i.some(m=>m.path===t)?t:i.find(m=>m.path===O)?.path??i[0]?.path??O}function Ge(i={}){const{projectId:t}=i,[m,u]=a.useState(""),[C,A]=a.useState(!0),[E,k]=a.useState(!1),[b,x]=a.useState(!1),[r,p]=a.useState(null),[T,K]=a.useState(!0),[X,L]=a.useState(!1),[S,P]=a.useState(()=>he({})),[F,ee]=a.useState(!0),[ue,$]=a.useState(!1),[o,v]=a.useState([]),[se,I]=a.useState(!0),[c,M]=a.useState(O),[W,y]=a.useState(""),[d,te]=a.useState(!1),[U,f]=a.useState(!1),[ae,H]=a.useState(!1),[ne,Q]=a.useState(!1),[Y,re]=a.useState(!1),[D,z]=a.useState(null),[ye,R]=a.useState(!0),[ge,B]=a.useState(!1),[ie,G]=a.useState(!1),[le,V]=a.useState(null),{status:me,loading:Z,refresh:j}=Le({projectId:t}),be=a.useCallback(n=>{y(n),f(!0)},[]),N=a.useCallback(async n=>{te(!0);try{const{content:l}=await Ee(n,t);M(n),y(l),f(!1)}finally{te(!1)}},[t]),q=a.useCallback(async()=>{I(!0);try{const{files:n}=await ke(t);if(v(n),n.length===0){M(O),y(""),f(!1);return}const l=De(n,c);l!==c&&await N(l)}finally{I(!1)}},[t,c,N]);a.useEffect(()=>{let n=!1;async function l(){try{const s=await $e(t);n||(u(s.content),A(!1))}catch{n||(u(""),A(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await we(t);n||(p(s.content),L(s.exists),K(!1))}catch{n||(p(null),L(!1),K(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){ee(!0);try{const s=await Ue(t);n||P(he(s))}catch{n||P(he({}))}finally{n||ee(!1)}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){I(!0);try{const{files:s}=await ke(t);if(n)return;if(v(s),s.length===0){M(O),y(""),f(!1);return}const h=De(s,c),{content:g}=await Ee(h,t);if(n)return;M(h),y(g),f(!1)}catch{n||(v([]),M(O),y(""),f(!1))}finally{n||I(!1)}}return l(),()=>{n=!0}},[t,c]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Me(t);n||(z(s),R(!1))}catch{n||(z(null),R(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await He(t);n||V(s)}catch{n||V(null)}}return l(),()=>{n=!0}},[t]);const ce=a.useCallback(n=>{u(n),k(!0)},[]),oe=a.useCallback(async()=>{if(E){x(!0);try{await Ie(m,t),k(!1)}finally{x(!1)}}},[m,E,t]),xe=a.useCallback(async n=>{$(!0);try{const l=await Re(n,t);P(he(l))}finally{$(!1)}},[t]),pe=a.useCallback(async n=>{await N(n)},[N]),fe=a.useCallback(async()=>{if(U){H(!0);try{await qe(c,W,t),f(!1),await q()}finally{H(!1)}}},[W,U,c,t,q]),je=a.useCallback(async()=>{G(!0);try{const n=await _e(t);return await j(),n}finally{G(!1)}},[t,j]),Se=a.useCallback(async n=>Pe(n,t),[t]),J=a.useCallback(async()=>{try{const n=await Me(t);z(n)}catch{z(null)}},[t]),_=a.useCallback(async()=>{try{const n=await we(t);p(n.content),L(n.exists)}catch{p(null),L(!1)}},[t]),de=a.useCallback(async n=>{await We(n,t),await _()},[t,_]),ve=a.useCallback(async()=>{Q(!0);try{const n=await Oe(t);return await Promise.all([_(),J()]),{success:n.success,summary:n.summary}}finally{Q(!1)}},[t,_,J]),Ne=a.useCallback(async()=>{re(!0);try{return await Te(t)}finally{re(!1)}},[t]),Ce=a.useCallback(async n=>{B(!0);try{const l=n?await Ae(n,t):await Ae(t);if(n){const s=l.path??n;M(s),y(l.content),f(!1),await q();return}u(l.content),k(!0)}finally{B(!1)}},[t,q]);return{workingMemory:m,workingMemoryLoading:C,workingMemoryDirty:E,setWorkingMemory:ce,saveWorkingMemory:oe,savingWorkingMemory:b,insightsContent:r,insightsLoading:T,insightsExists:X,refreshInsights:_,saveInsights:de,memorySettings:S,settingsLoading:F,savingMemorySettings:ue,saveMemorySettings:xe,memoryFiles:o,memoryFilesLoading:se,selectedFilePath:c,selectedFileContent:W,selectedFileLoading:d,selectedFileDirty:U,setSelectedFileContent:be,selectFile:pe,saveSelectedFile:fe,savingSelectedFile:ae,reloadMemoryFiles:q,backendStatus:me,backendLoading:Z,extractInsights:ve,extracting:ne,triggerDreamNow:Ne,dreamRunning:Y,auditReport:D,auditLoading:ye,refreshAudit:J,compactMemory:Ce,compacting:ge,installQmdAction:je,installingQmd:ie,testRetrieval:Se,stats:le}}const Ve={Patterns:"pattern",Principles:"principle",Conventions:"convention",Pitfalls:"pitfall",Context:"context"},Ze={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"},Je={"long-term":"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",daily:"Raw daily observations, open loops, and running context for dream processing.",dreams:"Synthesized patterns and open loops promoted from daily memory."},Ke=72;function Xe(i,t){if(i.length<=t)return i;const m=Math.max(1,t-1),u=Math.ceil(m/2),C=Math.floor(m/2);return`${i.slice(0,u)}…${i.slice(i.length-C)}`}function es(i){const t=`${i.label} — ${i.path}`;return Xe(t,Ke)}function ss(i){if(!i)return[];const t=[],m=i.split(/(?=^## )/m);for(const u of m){const C=u.trim();if(!C)continue;const A=C.match(/^##\s+(.+?)(\n|$)/);if(A){const E=A[1].trim(),k=Ve[E]??E.toLowerCase(),b=C.slice(A[0].length).trim(),x=b.split(`
|
|
2
|
+
`).map(r=>r.replace(/^-\s+/,"").trim()).filter(r=>r.length>0&&(r.startsWith("- ")||r.startsWith("* ")));(x.length>0||b.length>0)&&t.push({name:E,key:k,items:x.length>0?x:b.length>0?[b]:[],expanded:!0})}}return t}function ts(i){if(!i)return null;const t=i.match(/##\s+Last\s+Updated:\s*(\d{4}-\d{2}-\d{2})/i);return t?t[1]:null}function as(i){return i.reduce((t,m)=>t+m.items.length,0)}function ns(i){switch(i){case"file":return"File (.fusion/memory/)";case"readonly":return"Read-Only";case"qmd":return"QMD (Quantized Memory Distillation)";default:return i}}function rs(i){switch(i){case"healthy":return"Healthy";case"warning":return"Warning";case"issues":return"Issues Found"}}function os({projectId:i,addToast:t}){const[m,u]=a.useState("working"),[C,A]=a.useState(new Set),[E,k]=a.useState(!1),[b,x]=a.useState(null),[r,p]=a.useState({memoryEnabled:!0,memoryAutoSummarizeEnabled:!1,memoryAutoSummarizeThresholdChars:5e4,memoryAutoSummarizeSchedule:"0 3 * * *",memoryDreamsEnabled:!1,memoryDreamsSchedule:"0 4 * * *"}),[T,K]=a.useState(""),[X,L]=a.useState(!1),[S,P]=a.useState(null),{insightsContent:F,insightsLoading:ee,insightsExists:ue,saveInsights:$,memorySettings:o,settingsLoading:v,saveMemorySettings:se,savingMemorySettings:I,backendStatus:c,backendLoading:M,extractInsights:W,extracting:y,auditReport:d,auditLoading:te,refreshAudit:U,compactMemory:f,compacting:ae,installQmdAction:H,installingQmd:ne,testRetrieval:Q,memoryFiles:Y,memoryFilesLoading:re,selectedFilePath:D,selectedFileContent:z,selectedFileLoading:ye,selectedFileDirty:R,setSelectedFileContent:ge,selectFile:B,saveSelectedFile:ie,savingSelectedFile:G,reloadMemoryFiles:le,triggerDreamNow:V,dreamRunning:me}=Ge({projectId:i});a.useEffect(()=>{p(o)},[o]);const Z=a.useMemo(()=>r.memoryEnabled!==o.memoryEnabled||r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled||r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars||r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule||r.memoryDreamsEnabled!==o.memoryDreamsEnabled||r.memoryDreamsSchedule!==o.memoryDreamsSchedule,[r,o]),j=a.useMemo(()=>Y.find(s=>s.path===D),[Y,D]),be=j?Je[j.layer]:"Edits the selected memory file.",N=a.useMemo(()=>ss(F),[F]),q=a.useMemo(()=>as(N),[N]),ce=a.useMemo(()=>ts(F),[F]),oe=a.useCallback(s=>{A(h=>{const g=new Set(h);return g.has(s)?g.delete(s):g.add(s),g})},[]),xe=a.useCallback(async s=>{try{await B(s)}catch{t("Failed to load memory file","error")}},[B,t]),pe=a.useCallback(async()=>{try{await ie(),t("Memory saved","success")}catch{t("Failed to save memory","error")}},[ie,t]),fe=a.useCallback(async()=>{if(!Z)return;const s={};r.memoryEnabled!==o.memoryEnabled&&(s.memoryEnabled=r.memoryEnabled),r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled&&(s.memoryAutoSummarizeEnabled=r.memoryAutoSummarizeEnabled),r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars&&(s.memoryAutoSummarizeThresholdChars=r.memoryAutoSummarizeThresholdChars),r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule&&(s.memoryAutoSummarizeSchedule=r.memoryAutoSummarizeSchedule),r.memoryDreamsEnabled!==o.memoryDreamsEnabled&&(s.memoryDreamsEnabled=r.memoryDreamsEnabled),r.memoryDreamsSchedule!==o.memoryDreamsSchedule&&(s.memoryDreamsSchedule=r.memoryDreamsSchedule);try{await se(s),t("Memory settings saved","success")}catch{t("Failed to save memory settings","error")}},[Z,r,o,se,t]),je=a.useCallback(async()=>{try{const s=await H();t(s.qmdAvailable?"qmd installed successfully":"qmd install finished, but qmd is still unavailable",s.qmdAvailable?"success":"info")}catch{t("Failed to install qmd","error")}},[H,t]),Se=a.useCallback(async()=>{L(!0),P(null);try{const s=await Q(T);P(s),t(s.qmdAvailable?"Memory retrieval test complete":"qmd is not installed; local fallback was used",s.qmdAvailable?"success":"info")}catch{t("Failed to test memory retrieval","error")}finally{L(!1)}},[T,Q,t]),J=a.useCallback(async()=>{try{await V(),t("Dream processing completed","success"),await le()}catch(s){t(s instanceof Error?s.message:"Failed to run dream processing","error")}},[V,le,t]),_=a.useCallback(async()=>{try{await f(D),t("Memory file compacted","success")}catch{t("Failed to compact memory","error")}},[f,D,t]),de=a.useCallback(async()=>{try{const s=await W();t(s.summary,"success")}catch(s){t(s instanceof Error?s.message:"Failed to extract insights","error")}},[W,t]),ve=a.useCallback(async()=>{if(b!==null)try{await $(b),k(!1),x(null),t("Insights saved","success")}catch{t("Failed to save insights","error")}},[b,$,t]),Ne=a.useCallback(()=>{x(F??""),k(!0)},[F]),Ce=a.useCallback(()=>{k(!1),x(null)},[]),n=!M&&c!==null,l=c?.capabilities?.writable??!1;return e.jsxs("div",{className:"memory-view",children:[e.jsx("div",{className:"memory-view-header",children:e.jsxs("div",{children:[e.jsx("h2",{children:"Memory"}),e.jsx("p",{className:"memory-view-description",children:"Working memory, long-term insights, and engine status"})]})}),e.jsxs("div",{className:"memory-view-tabs",role:"tablist",children:[e.jsx("button",{type:"button",role:"tab","aria-selected":m==="working",className:`memory-view-tab${m==="working"?" memory-view-tab--active":""}`,onClick:()=>u("working"),"data-testid":"memory-tab-working",children:"Working Memory"}),e.jsx("button",{type:"button",role:"tab","aria-selected":m==="insights",className:`memory-view-tab${m==="insights"?" memory-view-tab--active":""}`,onClick:()=>u("insights"),"data-testid":"memory-tab-insights",children:"Insights"}),e.jsx("button",{type:"button",role:"tab","aria-selected":m==="engines",className:`memory-view-tab${m==="engines"?" memory-view-tab--active":""}`,onClick:()=>u("engines"),"data-testid":"memory-tab-engines",children:"Engines"})]}),e.jsxs("div",{className:"memory-view-content",children:[m==="working"&&e.jsxs("div",{className:"memory-working-tab",children:[n&&!l&&e.jsx("div",{className:"memory-readonly-banner",children:"This memory backend is read-only. Changes cannot be saved."}),re||ye?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading memory file…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-editor-section",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryViewFilePath",children:"Memory File"}),e.jsx("select",{id:"memoryViewFilePath",className:"select",value:D,onChange:s=>{xe(s.target.value)},disabled:R,children:Y.map(s=>e.jsx("option",{value:s.path,title:`${s.label} — ${s.path}`,children:es(s)},s.path))}),e.jsx("small",{children:R?"Save or discard the current edits before switching files.":"Choose any project memory file to view or edit."})]}),j&&e.jsxs("div",{className:"memory-file-summary",children:[e.jsx("span",{children:Ze[j.layer]}),e.jsx("strong",{children:j.path}),e.jsxs("small",{children:[j.size.toLocaleString()," bytes · updated ",new Date(j.updatedAt).toLocaleString()]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:j?.label||"Memory Editor"}),e.jsx("small",{children:be}),e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:z,onChange:ge,readOnly:!l,filePath:D})})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsxs("span",{className:"memory-char-count",children:[z.length," characters"]}),e.jsx("div",{className:"memory-flex-spacer"}),l&&z.length>0&&e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:_,disabled:ae||R,children:ae?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Compacting…"]}):"Compact Selected File"}),R&&l&&e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:pe,disabled:G,children:G?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save"})]}),e.jsxs("div",{className:"memory-config-section",children:[e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryDreamsEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryDreamsEnabled",type:"checkbox",checked:r.memoryDreamsEnabled,onChange:s=>{p(h=>({...h,memoryDreamsEnabled:s.target.checked}))},disabled:!r.memoryEnabled||v}),"Process dreams from daily memory"]}),e.jsx("small",{children:"Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md."})]}),r.memoryEnabled&&r.memoryDreamsEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryDreamsSchedule",children:"Dream Schedule"}),e.jsx("input",{id:"memoryDreamsSchedule",type:"text",className:"input",value:r.memoryDreamsSchedule,onChange:s=>{p(h=>({...h,memoryDreamsSchedule:s.target.value}))},placeholder:"0 4 * * *",disabled:v}),e.jsx("small",{children:"Cron expression for dream processing."})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:J,disabled:me||!r.memoryDreamsEnabled,children:me?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Dreaming…"]}):"Dream Now"}),e.jsx("small",{children:"Manually trigger dream processing now."})]})]})]}),e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryAutoSummarizeEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryAutoSummarizeEnabled",type:"checkbox",checked:r.memoryAutoSummarizeEnabled,onChange:s=>{p(h=>({...h,memoryAutoSummarizeEnabled:s.target.checked}))},disabled:!r.memoryEnabled||v}),"Auto-Summarize Memory"]}),e.jsx("small",{children:"Automatically compact memory when it exceeds the threshold on a schedule"})]}),r.memoryEnabled&&r.memoryAutoSummarizeEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeThresholdChars",children:"Compaction Threshold (chars)"}),e.jsx("input",{id:"memoryAutoSummarizeThresholdChars",type:"number",className:"input",value:r.memoryAutoSummarizeThresholdChars,onChange:s=>{p(h=>({...h,memoryAutoSummarizeThresholdChars:parseInt(s.target.value,10)||5e4}))},min:1e3,disabled:v}),e.jsx("small",{children:"Memory will be compacted when it exceeds this character count"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeSchedule",children:"Schedule (cron)"}),e.jsx("input",{id:"memoryAutoSummarizeSchedule",type:"text",className:"input",value:r.memoryAutoSummarizeSchedule,onChange:s=>{p(h=>({...h,memoryAutoSummarizeSchedule:s.target.value}))},placeholder:"0 3 * * *",disabled:v}),e.jsx("small",{children:"Cron expression for auto-summarize schedule (default: daily at 3 AM)"})]})]})]}),!r.memoryEnabled&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:"Memory is currently disabled. Enable memory tools in Settings to edit these automations."}),Z&&e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:fe,disabled:I||v,children:I?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save Settings"})})]})]})]}),m==="insights"&&e.jsx("div",{className:"memory-insights-tab",children:ee?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading insights…"})]}):E?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:b??"",onChange:x,readOnly:!1,filePath:".fusion/memory/INSIGHTS.md"})}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ce,children:"Cancel"}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:ve,children:"Save Insights"})]})]}):!ue||N.length===0?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx("p",{children:"No insights extracted yet."}),e.jsx("p",{children:'Insights are automatically extracted from working memory. Click "Extract Now" to trigger extraction manually.'}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm memory-empty-extract-button",onClick:de,disabled:y,children:y?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-stats-row",children:[e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:q}),e.jsx("div",{className:"memory-stat-label",children:"Total Insights"})]}),e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:N.length}),e.jsx("div",{className:"memory-stat-label",children:"Categories"})]}),ce&&e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value memory-stat-value--updated",children:ce}),e.jsx("div",{className:"memory-stat-label",children:"Last Updated"})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:de,disabled:y,children:y?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ne,children:"Edit Raw"})]}),e.jsx("div",{className:"memory-categories-list",children:N.map(s=>{const h=!C.has(s.key);return e.jsxs("div",{className:"memory-category-section",children:[e.jsxs("div",{className:"memory-category-header",onClick:()=>oe(s.key),role:"button",tabIndex:0,onKeyDown:g=>{(g.key==="Enter"||g.key===" ")&&(g.preventDefault(),oe(s.key))},children:[e.jsx("h4",{children:s.name}),e.jsx("span",{className:"memory-category-count",children:s.items.length})]}),h&&e.jsx("div",{className:"memory-category-items",children:s.items.map((g,ze)=>e.jsx("div",{className:"memory-insight-item",children:g.replace(/^-\s+/,"").replace(/^\*\s+/,"")},ze))})]},s.key)})})]})}),m==="engines"&&e.jsx("div",{className:"memory-engines-tab",children:M||te?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading engine status…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-engine-card memory-qmd-card",children:[e.jsx("h3",{children:"QMD Integration"}),c?.qmdAvailable===!0?e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge memory-health-badge--healthy",children:"Installed"}),e.jsx("span",{className:"memory-char-count",children:"qmd is available on PATH."})]}):c?.qmdAvailable===!1?e.jsxs("div",{className:"settings-empty-state memory-status-message",children:[e.jsxs("span",{children:["qmd is not installed. Search will use local files. Install indexed retrieval: ",e.jsx("code",{children:c.qmdInstallCommand||"bun install -g @tobilu/qmd"})]}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:je,disabled:ne,children:ne?"Installing…":"Install qmd"})]}):e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge",children:"Checking"}),e.jsx("span",{className:"memory-char-count",children:"Checking qmd availability…"})]}),e.jsxs("div",{className:"memory-capability-row",children:[c?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),c?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),c?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),c?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),e.jsxs("div",{className:"memory-engine-card memory-retrieval-card",children:[e.jsx("h3",{children:"Test Memory Search"}),e.jsxs("div",{className:"memory-retrieval-input-row",children:[e.jsx("input",{type:"text",className:"input",value:T,onChange:s=>K(s.target.value),placeholder:"Search memory with qmd"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Se,disabled:X,children:X?"Testing…":"Test Retrieval"})]}),e.jsx("small",{className:"settings-muted",children:"Runs the same qmd-backed memory_search path agents use."}),S&&e.jsxs("div",{className:"memory-test-result",children:[e.jsxs("strong",{children:[S.results.length," result",S.results.length===1?"":"s"," ",'for "',S.query,'"']}),e.jsxs("small",{children:["qmd ",S.qmdAvailable?"available":"missing"," · ",S.usedFallback?"local fallback used":"qmd path used"]}),S.results.length>0?e.jsx("ul",{children:S.results.map((s,h)=>e.jsxs("li",{children:[e.jsxs("span",{children:[s.path,":",s.lineStart]}),e.jsx("p",{children:s.snippet})]},`${s.path}-${s.lineStart}-${h}`))}):e.jsx("small",{children:"No matching memory found."})]})]}),e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Current Backend"}),e.jsx("div",{className:"memory-engine-status",children:e.jsx("span",{className:"memory-emphasis-text",children:ns(c?.currentBackend??"unknown")})}),e.jsxs("div",{className:"memory-capability-row",children:[c?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),c?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),c?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),c?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),d&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsxs("div",{className:"memory-health-header",children:[e.jsx("h3",{children:"Health Status"}),e.jsx("span",{className:`memory-health-badge memory-health-badge--${d.health}`,children:rs(d.health)})]}),e.jsxs("div",{className:"memory-health-grid",children:[e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Working Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.workingMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.workingMemory.sectionCount," sections"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Insights Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.insightsMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.insightsMemory.insightCount," insights"]})]})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Last Extraction"}),e.jsx("div",{className:"memory-emphasis-text",children:d.extraction.success?e.jsx("span",{className:"memory-status-text memory-status-text--success",children:"Success"}):e.jsx("span",{className:"memory-status-text memory-status-text--error",children:"Failed"})}),e.jsx("div",{className:"memory-health-detail",children:d.extraction.summary||`${d.extraction.insightCount} insights extracted`})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Pruning"}),e.jsx("div",{className:"memory-emphasis-text",children:d.pruning.applied?e.jsx("span",{className:"memory-status-text memory-status-text--warning",children:"Applied"}):e.jsx("span",{className:"memory-status-text memory-status-text--muted",children:"Not needed"})}),d.pruning.applied&&e.jsx("div",{className:"memory-health-detail",children:d.pruning.reason})]})]}),d&&d.checks.length>0&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Audit Checks"}),e.jsx("div",{children:d.checks.map(s=>e.jsxs("div",{className:"memory-audit-check",children:[e.jsx("span",{className:s.passed?"memory-audit-check-passed":"memory-audit-check-failed",children:s.passed?"✓":"✗"}),e.jsxs("div",{className:"memory-audit-check-content",children:[e.jsx("div",{className:"memory-emphasis-text",children:s.name}),e.jsx("div",{className:"memory-health-detail",children:s.details})]})]},s.id))})]}),e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:()=>U(),children:"Run Audit"})}),e.jsxs("div",{className:"memory-settings-note",children:[e.jsx("span",{children:"Note: Change backend type in"}),e.jsx("button",{type:"button",className:"memory-settings-note-button",onClick:()=>{t("Open Settings → Memory to change backend type","info")},children:"Settings → Memory"})]})]})})]})]})}export{os as MemoryView};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.nodes-management-overlay{display:flex;flex-direction:column;gap:var(--space-md);height:100%;overflow-y:auto;-webkit-overflow-scrolling:touch}.nodes-management-overlay__header{display:flex;justify-content:flex-end}.nodes-view{display:flex;flex-direction:column;gap:var(--space-md);padding:var(--space-sm) var(--space-md) var(--space-xl)}.nodes-view-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--space-sm)}.nodes-view-title{display:flex;align-items:center;gap:var(--space-sm)}.nodes-view-title h2{margin:0;display:flex;align-items:center;gap:var(--space-sm)}.nodes-view-count{color:var(--text-muted);font-size:calc(var(--space-md) + var(--space-xs) / 4)}.nodes-view-actions{display:flex;gap:var(--space-sm)}.nodes-view-close{margin-left:auto}.nodes-view-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(calc(var(--space-xl) * 5.833),1fr));gap:var(--space-sm)}.nodes-view-stat{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:var(--space-sm) var(--space-md);display:flex;align-items:center;justify-content:space-between;gap:var(--space-sm)}.nodes-view-stat span{display:inline-flex;align-items:center;gap:var(--space-sm);color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs))}.nodes-view-stat strong{font-size:calc(var(--space-lg) + var(--space-xs) / 2)}.nodes-view-stat--online strong{color:var(--color-success)}.nodes-view-stat--offline strong{color:var(--color-error)}.nodes-view-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(calc(var(--space-lg) * 20),1fr));gap:var(--space-md)}.nodes-view-empty{padding:var(--space-xl);border:1px dashed var(--border);border-radius:var(--radius);text-align:center;color:var(--text-muted);display:flex;flex-direction:column;align-items:center;gap:var(--space-md)}.nodes-view-error{color:var(--color-error);font-size:calc(var(--space-md) + var(--space-xs) / 4)}.node-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:var(--space-md);display:flex;flex-direction:column;gap:var(--space-md);cursor:pointer;transition:border-color var(--transition-fast),transform var(--transition-fast)}.node-card:hover{border-color:var(--accent);transform:translateY(calc(var(--space-xs) * -.25))}.node-card:focus-visible{outline:none;border-color:var(--todo);box-shadow:var(--focus-ring-strong)}.node-card--loading{min-height:calc(var(--space-xl) * 9.167);opacity:.55;pointer-events:none}.node-card__header{display:flex;align-items:center;justify-content:space-between}.node-card__title-wrap{display:flex;align-items:center;gap:var(--space-sm)}.node-card__icon{width:calc(var(--space-lg) * 2.125);height:calc(var(--space-lg) * 2.125);border-radius:var(--radius-sm);display:inline-flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--accent) 12%,transparent);color:var(--accent)}.node-card__name{margin:0;font-size:calc(var(--space-md) + var(--space-xs));line-height:1.25}.node-card__meta-row{margin-top:var(--space-xs);display:flex;align-items:center;gap:var(--space-xs)}.node-card__type-badge{border:1px solid var(--border);border-radius:var(--radius-pill);padding:var(--space-xs) var(--space-sm);font-size:calc(var(--space-sm) + var(--space-xs) * .75);color:var(--text-muted)}.node-card__status{display:inline-flex;align-items:center;gap:var(--space-xs);font-size:calc(var(--space-sm) + var(--space-xs) * .75);font-weight:600}.node-card__status-indicator{width:var(--space-sm);height:var(--space-sm);border-radius:50%}.node-card__status--online .node-card__status-indicator{background:var(--color-success)}.node-card__status--offline .node-card__status-indicator,.node-card__status--error .node-card__status-indicator{background:var(--color-error)}.node-card__status--connecting .node-card__status-indicator{background:var(--color-warning)}.node-card__auth-indicator{display:inline-flex;align-items:center;margin-left:var(--space-xs);vertical-align:middle}.node-card__url{font-family:var(--font-mono);font-size:calc(var(--space-sm) + var(--space-xs));color:var(--text-muted);word-break:break-all}.node-card__metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-sm)}.node-card__metric{display:flex;flex-direction:column;gap:var(--space-xs)}.node-card__metric-label{color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs) * .75);text-transform:uppercase;letter-spacing:.03em}.node-card__metric-value{font-size:calc(var(--space-md) + var(--space-xs));font-weight:600}.node-card__sync{display:flex;align-items:center;gap:var(--space-xs);margin-top:var(--space-sm);font-size:calc(var(--space-sm) + var(--space-xs));color:var(--text-muted)}.node-card__sync-dot{width:var(--space-sm);height:var(--space-sm);border-radius:50%;flex-shrink:0}.node-card__sync-time{color:var(--text-muted)}.nodes-view-stat--synced strong{color:var(--color-success)}.node-card__actions{display:flex;gap:var(--space-xs);flex-wrap:wrap}.node-card__action{display:inline-flex;align-items:center;gap:var(--space-xs)}.node-card__action--remove{margin-left:auto}.node-card__action--remove:not(.btn-danger){color:var(--color-error);border-color:color-mix(in srgb,var(--color-error) 45%,var(--border))}.node-card__action--remove.is-armed{background:color-mix(in srgb,var(--color-error) 14%,transparent)}.mesh-topology{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-md);min-height:calc(var(--space-2xl) * 6.25);padding:var(--space-md);background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md)}.mesh-topology__svg{width:100%;max-width:calc(var(--space-2xl) * 12.5);height:auto;aspect-ratio:1}.mesh-topology__node{transition:filter var(--transition-fast)}.mesh-topology__node:hover{filter:brightness(1.1)}.mesh-topology__node-circle{stroke:var(--border);stroke-width:calc(var(--space-xs) / 2);transition:fill var(--transition-fast)}.mesh-topology__node-label{font-size:calc(var(--space-sm) + var(--space-xs) * .75);fill:var(--text);font-weight:500}.mesh-topology__node-type-badge{fill:color-mix(in srgb,var(--surface) 75%,var(--bg));stroke:var(--border);stroke-width:calc(var(--space-xs) / 4)}.mesh-topology__node-type-text{font-size:calc(var(--space-sm) + var(--space-xs) / 2);font-weight:700;fill:var(--text-muted);text-transform:uppercase;letter-spacing:.03em}.mesh-topology__link{stroke:var(--border);stroke-width:calc((var(--space-xs) * 3) / 8);stroke-dasharray:var(--space-xs),var(--space-xs);opacity:.6}.mesh-topology__legend{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-md);font-size:calc(var(--space-sm) + var(--space-xs));color:var(--text-muted)}.mesh-topology__legend-item{display:flex;align-items:center;gap:var(--space-sm)}.mesh-topology__notice{margin:var(--space-md) 0 0;text-align:center;color:var(--text-dim);font-size:calc(var(--space-sm) + var(--space-xs))}.mesh-topology__legend-dot{width:calc(var(--space-sm) + var(--space-xs) / 2);height:calc(var(--space-sm) + var(--space-xs) / 2);border-radius:50%;border:1px solid var(--border)}.mesh-topology--empty{justify-content:center}.mesh-topology__empty-state{text-align:center;color:var(--text-muted);font-size:calc(var(--space-md) + var(--space-xs) / 2)}.connect-node-modal{width:min(calc(var(--space-lg) * 30),calc(100vw - (var(--space-lg) * 2)))}.connect-node-form{display:flex;flex-direction:column;gap:var(--space-md)}.connect-node-form .form-group{padding:0;margin-top:0}.connect-node-form .form-group:last-of-type{margin-bottom:0}.connect-node-field{display:flex;flex-direction:column;gap:var(--space-xs)}.connect-node-field__input{width:100%}.connect-node-field__input[aria-invalid=true]{border-color:var(--color-error);background:color-mix(in srgb,var(--color-error) 5%,var(--surface))}.connect-node-field__input[aria-invalid=true]:focus-visible{border-color:var(--color-error);box-shadow:var(--glow-danger)}.connect-node-url-preview{display:flex;align-items:center;gap:var(--space-sm);padding:var(--space-sm) var(--space-md);background:color-mix(in srgb,var(--surface) 50%,var(--bg));border-radius:var(--radius-sm);border-left:var(--space-xs) solid var(--accent);font-size:calc(var(--space-sm) + var(--space-xs))}.connect-node-url-preview-label{color:var(--text-muted)}.connect-node-url-preview code{font-family:var(--font-mono);color:var(--text);font-size:calc(var(--space-sm) + var(--space-xs))}.connect-node-actions{display:flex;justify-content:flex-end;gap:var(--space-sm);padding:var(--modal-padding);border-top:1px solid var(--border)}.nodes-view-topology{margin-bottom:var(--space-md)}.nodes-view-section-title{font-size:calc(var(--space-md) + var(--space-xs) * .5);font-weight:600;color:var(--text);margin:0 0 var(--space-sm)}.nodes-view .node-status-indicator{display:inline-flex;align-items:center;gap:var(--space-xs);font-size:calc(var(--space-sm) + var(--space-xs) * .625)}.nodes-view .node-status-indicator__label,.nodes-view .node-status-indicator--local{color:var(--text-muted)}.nodes-view .node-status-indicator--remote{color:var(--text)}.nodes-view .node-status-indicator__dot{width:var(--space-sm);height:var(--space-sm);border-radius:50%;position:relative;display:inline-block}.nodes-view .node-status-indicator__dot--online{background:var(--color-success);box-shadow:var(--glow-success)}.nodes-view .node-status-indicator__dot--offline,.nodes-view .node-status-indicator__dot--error{background:var(--color-error)}.nodes-view .node-status-indicator__dot--connecting{background:var(--color-warning);animation:pulse-warning 1.5s ease-in-out infinite}.nodes-view .node-status-indicator__spinner{position:absolute;inset:0;border:calc(var(--space-xs) / 2) solid transparent;border-top-color:currentColor;border-radius:50%;animation:spin 1s linear infinite}.nodes-view .node-status-indicator__name{font-weight:500}.nodes-view .node-status-indicator__details{font-size:calc(var(--space-sm) + var(--space-xs));color:var(--text-muted)}@keyframes pulse-warning{0%,to{opacity:1;box-shadow:var(--glow-warning)}50%{opacity:.6;box-shadow:var(--glow-warning)}}@media(max-width:768px){.nodes-view{padding-inline:var(--space-sm)}.nodes-view-grid,.node-card__metrics{grid-template-columns:1fr}.connect-node-modal{width:calc(100vw - (var(--space-md) * 2))}.connect-node-field__input{min-height:calc(var(--space-2xl) + var(--space-md))}.nodes-view-header{padding:var(--space-sm) var(--space-md);flex-wrap:wrap;gap:var(--space-sm)}.nodes-view-title h2{font-size:calc(var(--space-md) + var(--space-xs))}.nodes-view-title h2 svg{flex-shrink:0}.nodes-view-count{font-size:calc(var(--space-sm) + var(--space-xs))}.nodes-view-actions{flex-wrap:wrap;gap:var(--space-sm);width:100%;justify-content:flex-end}.nodes-view-close{min-height:calc(var(--space-xl) + var(--space-md));min-width:calc(var(--space-xl) + var(--space-md))}.nodes-view-actions .btn{min-height:calc(var(--space-xl) + var(--space-md))}.nodes-view-stats{grid-template-columns:repeat(2,1fr);gap:var(--space-sm)}.nodes-view-stat{padding:var(--space-xs) var(--space-sm)}.nodes-view-stat span{font-size:calc(var(--space-sm) + var(--space-xs) * .75)}.nodes-view-stat strong{font-size:calc(var(--space-md) + var(--space-xs) / 2)}.nodes-view-empty{padding:var(--space-xl) var(--space-md);text-align:center}.nodes-view-error{padding:var(--space-md);margin:var(--space-md) 0}.nodes-view-topology{padding:var(--space-sm) 0}.nodes-view-section-title{font-size:calc(var(--space-md) + var(--space-xs) / 4)}}.add-node-modal{width:min(calc(var(--space-lg) * 32.5),calc(100vw - (var(--space-lg) * 2)))}.add-node-modal__body{display:flex;flex-direction:column;gap:var(--space-md)}.add-node-modal__row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-sm)}.add-node-modal__fieldset{border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--space-sm);display:flex;flex-direction:column;gap:var(--space-sm)}.add-node-modal__fieldset legend{color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs) * .625);padding:0 var(--space-xs)}.add-node-modal__storage-toggle{border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--space-sm)}.add-node-modal__advanced-btn{align-self:flex-start}.add-node-modal__advanced{border:1px dashed var(--border);border-radius:var(--radius-sm);padding:var(--space-sm);display:flex;flex-direction:column;gap:var(--space-sm)}.add-node-modal__textarea{min-height:calc(var(--space-2xl) * 2.25);resize:vertical;font-family:var(--font-mono)}.add-node-modal__description{font-size:calc(var(--space-sm) + var(--space-xs) * .625);color:var(--text-muted);margin-bottom:var(--space-sm);padding:0}.add-node-modal__field{display:flex;flex-direction:column;gap:var(--space-xs)}.add-node-modal__field>span{font-size:calc(var(--space-sm) + var(--space-xs) * .625);font-weight:600;color:var(--text-muted)}.add-node-modal__field .input{width:100%;padding:var(--space-sm) var(--space-md);font-size:calc(var(--space-md) + var(--space-xs) * .5)}.add-node-modal__field .input:focus-visible{border-color:var(--accent);box-shadow:var(--focus-ring-strong)}.add-node-modal__field .input[aria-invalid=true]{border-color:var(--color-error);background:color-mix(in srgb,var(--color-error) 5%,var(--surface))}.add-node-modal__field .input[aria-invalid=true]:focus{box-shadow:var(--glow-danger)}.add-node-modal__hint{font-size:calc(var(--space-sm) + var(--space-xs) * .375);color:var(--text-dim);margin-top:calc(var(--space-xs) / 2)}.add-node-modal__error{margin-top:calc(var(--space-xs) / 2)}.add-node-modal__type-toggle{display:flex;gap:0;border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden;background:var(--surface)}.add-node-modal__type-btn{flex:1;padding:calc(var(--space-sm) + var(--space-xs) / 2) var(--space-lg);border:none;background:transparent;color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs) * .625);font-weight:500;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.add-node-modal__type-btn:hover:not(:disabled){background:color-mix(in srgb,var(--bg) 50%,var(--surface))}.add-node-modal__type-btn:focus-visible{outline:none;box-shadow:var(--focus-ring-strong);z-index:1}.add-node-modal__type-btn.active{background:var(--accent);color:var(--bg)}.add-node-modal__type-btn:disabled{opacity:.6;cursor:not-allowed}.add-node-modal__remote-fields{display:grid;gap:var(--space-sm)}@media(max-width:768px){.add-node-modal{width:calc(100vw - (var(--space-md) * 2))}.add-node-modal__type-toggle{width:100%}.add-node-modal__type-btn{flex:1;padding:var(--space-md) var(--space-lg)}.add-node-modal__field input{min-height:calc(var(--space-2xl) + var(--space-md));font-size:calc(var(--space-md) + var(--space-xs) * .5)}.add-node-modal__row{grid-template-columns:1fr}}.docker-onboarding{width:min(calc(var(--space-2xl) * 22.5),calc(100vw - (var(--space-lg) * 2)))}.docker-onboarding__body{display:flex;flex-direction:column;gap:var(--space-md)}.docker-onboarding__section{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-md);display:flex;flex-direction:column;gap:var(--space-sm)}.docker-onboarding__section-title{margin:0;display:flex;align-items:center;gap:var(--space-sm);font-size:calc(var(--space-md) + var(--space-xs) / 2)}.docker-onboarding__field{display:flex;flex-direction:column;gap:var(--space-xs)}.docker-onboarding__inline-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-sm)}.docker-onboarding__radio-group{display:flex;align-items:center;gap:var(--space-md);flex-wrap:wrap}.docker-onboarding__type-toggle{display:flex;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden}.docker-onboarding__type-btn{flex:1;border:none;background:var(--surface);color:var(--text);padding:var(--space-sm) var(--space-md);cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.docker-onboarding__type-btn+.docker-onboarding__type-btn{border-left:1px solid var(--border)}.docker-onboarding__type-btn.is-active{background:var(--todo);color:var(--bg)}.docker-onboarding__type-btn:focus-visible{outline:none;box-shadow:var(--focus-ring-strong);position:relative;z-index:1}.docker-onboarding__checkbox-group{display:flex;flex-direction:column;gap:var(--space-xs)}.docker-onboarding__kv-list{display:flex;flex-direction:column;gap:var(--space-sm)}.docker-onboarding__kv-list h5{margin:0;font-size:calc(var(--space-sm) + var(--space-xs))}.docker-onboarding__kv-row{display:grid;gap:var(--space-sm);align-items:center}.docker-onboarding__kv-row--env{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto}.docker-onboarding__kv-row--mount{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto auto}.docker-onboarding__kv-add{align-self:flex-start}.docker-onboarding__advanced-toggle{border:none;background:none;color:var(--text);padding:var(--space-xs);margin:calc(var(--space-xs) * -1);border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:space-between;width:100%;cursor:pointer;font-size:calc(var(--space-md) + var(--space-xs) / 2);font-weight:600}.docker-onboarding__advanced-toggle:focus-visible{outline:none;box-shadow:var(--focus-ring-strong)}.docker-onboarding__advanced-toggle svg{transition:transform var(--transition-fast)}.docker-onboarding__advanced-toggle.is-expanded svg{transform:rotate(180deg)}.docker-onboarding__advanced-content{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--transition-fast)}.docker-onboarding__advanced-content>div{overflow:hidden;display:flex;flex-direction:column;gap:var(--space-sm)}.docker-onboarding__advanced-content.is-expanded{grid-template-rows:1fr}.docker-onboarding__tls-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-sm)}.docker-onboarding__tls-fields .docker-onboarding__field:first-child{grid-column:1 / -1}@media(max-width:768px){.docker-onboarding{width:calc(100vw - (var(--space-md) * 2))}.docker-onboarding__inline-fields,.docker-onboarding__tls-fields,.docker-onboarding__kv-row{grid-template-columns:1fr}.docker-onboarding .input,.docker-onboarding .select,.docker-onboarding .btn{min-height:calc(var(--space-2xl) + var(--space-md))}.docker-onboarding__advanced-content{transition:none}}.settings-sync-log{display:flex;flex-direction:column;gap:var(--space-sm)}.settings-sync-log__header{display:flex;align-items:center;gap:var(--space-xs);cursor:pointer;padding:var(--space-xs) 0;border-radius:var(--radius-sm);border:none;background:transparent;color:var(--text);font:inherit;text-align:left;transition:background-color var(--transition-fast)}.settings-sync-log__header:hover{background:var(--surface-hover)}.settings-sync-log__header:focus-visible{outline:none;box-shadow:var(--focus-ring-strong);background:var(--surface-hover)}.settings-sync-log__chevron{transform:rotate(0);transition:transform var(--transition-fast)}.settings-sync-log__chevron--expanded{transform:rotate(180deg)}.settings-sync-log__filters{display:flex;gap:var(--space-sm);align-items:center;flex-wrap:wrap}.settings-sync-log__filters label{display:flex;align-items:center;gap:var(--space-xs);font-size:12px;color:var(--text-muted)}.settings-sync-log__filters select{font-size:12px;padding:4px 8px;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text)}.settings-sync-log__filters select:focus{outline:none;border-color:var(--todo);box-shadow:var(--focus-ring)}.settings-sync-log__list{display:flex;flex-direction:column}.settings-sync-log__entry{display:flex;align-items:center;gap:var(--space-sm);padding:var(--space-xs) 0;border-bottom:1px solid var(--border)}.settings-sync-log__entry:last-child{border-bottom:none}.settings-sync-log__entry-timestamp{font-size:12px;color:var(--text-muted);min-width:140px}.settings-sync-log__entry-direction{display:flex;align-items:center;color:var(--text-muted)}.settings-sync-log__entry-result{display:inline-flex;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:500}.settings-sync-log__badge--success{background:color-mix(in srgb,var(--color-success, #2da44e) 14%,transparent);color:var(--color-success, #2da44e)}.settings-sync-log__badge--conflict{background:color-mix(in srgb,#d29922 14%,transparent);color:#d29922}.settings-sync-log__badge--error{background:color-mix(in srgb,var(--color-error, #cf222e) 14%,transparent);color:var(--color-error, #cf222e)}.settings-sync-log__entry-node{font-weight:500;font-size:12px}.settings-sync-log__entry-details{font-size:12px;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.settings-sync-log__empty{text-align:center;color:var(--text-muted);padding:var(--space-md);font-size:13px}.node-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:color-mix(in srgb,var(--accent) 14%,transparent);border:1px solid color-mix(in srgb,var(--accent) 36%,transparent);color:var(--text-muted);font-size:11px;width:fit-content;margin-top:4px}@media(max-width:768px){.settings-sync-conflict-modal__diff-panel{grid-template-columns:1fr}}.settings-sync-conflict-modal{max-width:860px;width:min(860px,calc(100vw - 32px))}.settings-sync-conflict-modal__conflict-list{display:flex;flex-direction:column;gap:var(--space-md);max-height:min(50vh,400px);overflow-y:auto}.settings-sync-conflict-modal__conflict-item{border:1px solid var(--border);border-radius:var(--radius);padding:var(--space-md)}.settings-sync-conflict-modal__key{font-weight:600;font-family:monospace;margin-bottom:var(--space-sm)}.settings-sync-conflict-modal__diff-panel{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-sm);margin-bottom:var(--space-sm)}.settings-sync-conflict-modal__diff-side{border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden}.settings-sync-conflict-modal__diff-label{font-size:calc(var(--space-sm) + var(--space-xs) * .75);color:var(--text-muted);padding:4px 8px;border-bottom:1px solid var(--border);background:var(--surface)}.settings-sync-conflict-modal__diff-content{padding:var(--space-xs) var(--space-sm);white-space:pre;font-family:monospace;font-size:12px;line-height:1.5;overflow-x:auto}.settings-sync-conflict-modal__resolution{display:flex;gap:var(--space-md);align-items:center}.settings-sync-conflict-modal__resolution label{display:flex;align-items:center;gap:var(--space-xs);cursor:pointer}.settings-sync-conflict-modal__resolution input[type=radio]{cursor:pointer}.settings-sync-conflict-modal__manual-input{width:100%;font-family:monospace;font-size:12px;min-height:80px;margin-top:var(--space-xs);padding:var(--space-sm);background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);resize:vertical}.settings-sync-conflict-modal__manual-input:focus{outline:none;border-color:var(--todo);box-shadow:var(--focus-ring)}.settings-sync-conflict-modal__bulk-actions{display:flex;gap:var(--space-xs);padding-top:var(--space-sm);border-top:1px solid var(--border)}.settings-sync-conflict-modal__footer{display:flex;justify-content:flex-end;gap:var(--space-xs)}.node-detail-modal{max-width:calc(var(--space-lg) * 53.75);width:min(calc(var(--space-lg) * 53.75),calc(100vw - (var(--space-lg) * 2)))}.node-detail-modal__body{display:flex;flex-direction:column;gap:var(--space-md);max-height:min(72vh,calc(var(--space-lg) * 42.5));overflow-y:auto}.node-detail-modal__section{border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-md)}.node-detail-modal__section h4{margin:0 0 var(--space-sm) 0}.node-detail-modal__section-header{display:flex;justify-content:space-between;align-items:center;gap:var(--space-sm);margin-bottom:var(--space-sm)}.node-detail-modal__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-sm)}.node-detail-modal__field{display:flex;flex-direction:column;gap:var(--space-xs)}.node-detail-modal__field--full{grid-column:span 2}.node-detail-modal__field span{color:var(--text-muted);font-size:calc(var(--space-sm) + var(--space-xs))}.node-detail-modal__edit-actions{margin-top:var(--space-sm);display:flex;gap:var(--space-xs)}.node-detail-modal__project-list{margin:0;padding-left:var(--space-lg);display:flex;flex-direction:column;gap:var(--space-sm)}.node-detail-modal__project-item{display:flex;justify-content:space-between;align-items:center;gap:var(--space-sm)}.node-detail-modal__project-item code{color:var(--text-muted)}.node-detail-modal__empty{margin:0;color:var(--text-muted)}.node-detail-modal__health-row{display:flex;flex-wrap:wrap;gap:var(--space-md)}.node-detail-modal__actions{justify-content:space-between}.node-detail-modal__docker-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-sm);margin-top:var(--space-sm)}.node-detail-modal__textarea{min-height:calc(var(--space-2xl) * 2.25);resize:vertical;font-family:var(--font-mono)}.node-detail-modal__sync-status{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-sm);margin-bottom:var(--space-sm)}.node-detail-modal__sync-dot{width:calc(var(--space-sm) + var(--space-xs) / 2);height:calc(var(--space-sm) + var(--space-xs) / 2);border-radius:50%;flex-shrink:0}.node-detail-modal__sync-dot--synced{background:var(--color-success)}.node-detail-modal__sync-dot--diff,.node-detail-modal__sync-dot--pending{background:var(--color-warning)}.node-detail-modal__sync-dot--error{background:var(--color-error)}.node-detail-modal__sync-dot--never{background:var(--text-muted)}.node-detail-modal__sync-diff{color:var(--color-warning);font-size:calc(var(--space-sm) + var(--space-xs))}.node-detail-modal__sync-actions{display:flex;flex-wrap:wrap;gap:var(--space-sm);margin-top:var(--space-sm)}.node-detail-modal__sync-error{display:flex;align-items:center;justify-content:space-between;gap:var(--space-sm);margin-top:var(--space-sm);padding:var(--space-sm);background:color-mix(in srgb,var(--color-error) 10%,transparent);border:1px solid color-mix(in srgb,var(--color-error) 30%,transparent);border-radius:var(--radius-sm);color:var(--color-error);font-size:calc(var(--space-sm) + var(--space-xs))}.node-detail-modal__sync-error-dismiss{background:transparent;border:none;color:var(--color-error);cursor:pointer;padding:calc(var(--space-xs) / 2);display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm)}.node-detail-modal__sync-error-dismiss:hover{background:color-mix(in srgb,var(--color-error) 20%,transparent)}.node-detail-modal__sync-error-dismiss:focus-visible{outline:none;box-shadow:var(--focus-ring-strong);background:color-mix(in srgb,var(--color-error) 20%,transparent)}@media(max-width:768px){.node-detail-modal__grid,.node-detail-modal__docker-grid{grid-template-columns:1fr}.node-detail-modal__field--full{grid-column:span 1}}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{c as ke,aC as ze,aD as Ie,aE as Ke,aF as Oe,aG as Ce,aH as Se,A as we,aI as Ue,U as Fe,aJ as Ve,aK as Be,W as xe,ae as Me,J as re,aL as Pe,aM as He,aN as qe,X as pe,aO as Ne,aP as Je,aQ as Xe,aR as Ge,R as ve,G as We}from"./index-BRaIPmpp.js";import{U as Ee}from"./upload-B0NF4J5P.js";import"./vendor-xterm-DzcZoU0P.js";/**
|
|
2
|
+
* @license lucide-react v1.7.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/const Ye=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}],["path",{d:"M5 12.859a10 10 0 0 1 5.17-2.69",key:"1dl1wf"}],["path",{d:"M19 12.859a10 10 0 0 0-2.007-1.523",key:"4k23kn"}],["path",{d:"M2 8.82a15 15 0 0 1 4.177-2.643",key:"1grhjp"}],["path",{d:"M22 8.82a15 15 0 0 0-11.288-3.764",key:"z3jwby"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],Te=ke("wifi-off",Ye);/**
|
|
7
|
+
* @license lucide-react v1.7.0 - ISC
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the ISC license.
|
|
10
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/const Qe=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],Ze=ke("wifi",Qe);function he(a){const{lastSyncAt:o,remoteReachable:t,diff:d}=a,p=d.global.length+d.project.length;return o===null?{syncState:"never-synced",lastSyncAt:o,diffCount:0}:t?p>0?{syncState:"diff",lastSyncAt:o,diffCount:p}:{syncState:"synced",lastSyncAt:o,diffCount:0}:{syncState:"error",lastSyncAt:o,diffCount:p}}function Ae(a){if(a===null)return"Never synced";const o=new Date(a);if(Number.isNaN(o.getTime()))return"Never synced";const d=Date.now()-o.getTime(),p=Math.floor(d/1e3),f=Math.floor(p/60),l=Math.floor(f/60),u=Math.floor(l/24);return f<1?"Synced just now":f<60?`Synced ${f}m ago`:l<24?`Synced ${l}h ago`:`Synced ${u}d ago`}function es(a){switch(a){case"synced":return"var(--color-success)";case"pending":return"var(--color-warning)";case"diff":return"var(--color-warning)";case"error":return"var(--color-error)";case"never-synced":return"var(--text-muted)"}}const ss=3e4;function as(){const[a,o]=s.useState({}),[t,d]=s.useState(!1),[p,f]=s.useState({}),[l,u]=s.useState(null),i=s.useRef(new Set),g=s.useRef(!1),x=s.useRef(null),_=s.useRef(null),C=s.useCallback(async(y,c)=>{try{const b=await ze(y);o(I=>({...I,[y]:b})),u(null)}catch(b){console.error(`Failed to fetch sync status for node ${y}:`,b),u(b instanceof Error?b.message:"Failed to fetch sync status")}},[]),k=s.useCallback(async()=>{const y=Array.from(i.current);if(y.length===0)return;x.current&&x.current.abort(),x.current=new AbortController;const c=!g.current;c&&d(!0),u(null);try{const b=await Promise.allSettled(y.map(O=>C(O,c)));g.current=!0,b.filter(O=>O.status==="rejected").length>0&&u("Some sync status requests failed")}catch(b){if(b instanceof Error&&b.name==="AbortError")return;u(b instanceof Error?b.message:"Failed to fetch sync status"),g.current=!0}finally{d(!1)}},[C]),M=s.useCallback(()=>{_.current&&clearInterval(_.current),_.current=setInterval(()=>{k()},ss)},[k]),w=s.useCallback(()=>{_.current&&(clearInterval(_.current),_.current=null)},[]);s.useEffect(()=>(k(),M(),()=>{w(),x.current&&x.current.abort()}),[k,M,w]);const n=s.useCallback(y=>{i.current.has(y)||(i.current.add(y),C(y,!g.current))},[C]),m=s.useCallback(y=>{i.current.delete(y),o(c=>{const b={...c};return delete b[y],b}),i.current.size===0&&w()},[w]),h=s.useCallback(async y=>{f(c=>({...c,[y]:!0})),u(null);try{const c=await Ie(y);return C(y,!1),!c.success&&c.error&&u(c.error),c}catch(c){const b=c instanceof Error?c.message:"Push settings failed";throw u(b),c}finally{f(c=>{const b={...c};return delete b[y],b})}},[C]),P=s.useCallback(async y=>{f(c=>({...c,[y]:!0})),u(null);try{const c=await Ke(y);return C(y,!1),!c.success&&c.error&&u(c.error),c}catch(c){const b=c instanceof Error?c.message:"Pull settings failed";throw u(b),c}finally{f(c=>{const b={...c};return delete b[y],b})}},[C]),E=s.useCallback(async y=>{f(c=>({...c,[y]:!0})),u(null);try{return await Oe(y)}catch(c){const b=c instanceof Error?c.message:"Auth sync failed";throw u(b),c}finally{f(c=>{const b={...c};return delete b[y],b})}},[]),R=s.useCallback(y=>a[y]?.authMatch,[a]),D=s.useCallback(y=>a[y]?.authDiff,[a]);return{syncStatusMap:a,loading:t,actionLoading:p,error:l,refresh:k,trackNode:n,untrackNode:m,pushSettings:h,pullSettings:P,syncAuth:E,getAuthSyncState:R,getAuthProviders:D}}function ts(a,o){return o.type==="remote"?a.nodeId===o.id:a.nodeId===o.id||a.nodeId===void 0||a.nodeId===null}function Re(a,o){return a.filter(t=>ts(t,o))}function be(a,o){return Re(a,o).length}const ns={online:{label:"Online",color:"var(--color-success)",className:"node-card__status--online"},offline:{label:"Offline",color:"var(--color-error)",className:"node-card__status--offline"},connecting:{label:"Connecting",color:"var(--color-warning)",className:"node-card__status--connecting"},error:{label:"Error",color:"var(--color-error)",className:"node-card__status--error"}},ls={match:"var(--color-success)",differs:"var(--color-warning)","not-synced":"var(--text-muted)"};function rs(a,o){if(a==="match")return"Auth credentials match";if(a==="not-synced")return"Auth not synced";if(o&&Object.keys(o).length>0){const t=Object.entries(o).filter(([,d])=>d==="differs").map(([d])=>d);if(t.length>0)return`Auth credentials differ: ${t.join(", ")}`}return"Auth credentials differ"}function os(a,o=42){return a.length<=o?a:`${a.slice(0,o-3)}...`}function cs(a,o){const t=a.node,d=o.node;if(t.id!==d.id||t.name!==d.name||t.type!==d.type||t.url!==d.url||t.status!==d.status||t.maxConcurrent!==d.maxConcurrent||t.updatedAt!==d.updatedAt||a.isLoading!==o.isLoading)return!1;const p=a.syncStatus,f=o.syncStatus;if(!(!p&&!f)){if(!p||!f)return!1;if(p.syncState!==f.syncState||p.lastSyncAt!==f.lastSyncAt||p.diffCount!==f.diffCount)return!1}if(a.authSyncState!==o.authSyncState)return!1;const l=a.authSyncProviders,u=o.authSyncProviders;if(l!==u){if(!l||!u)return!1;{const x=Object.keys(l),_=Object.keys(u);if(x.length!==_.length||x.some(C=>l[C]!==u[C]))return!1}}const i=be(a.projects,t),g=be(o.projects,d);return i===g}function is({node:a,projects:o,onHealthCheck:t,onEdit:d,onRemove:p,isLoading:f=!1,syncStatus:l,authSyncState:u,authSyncProviders:i}){const[g,x]=s.useState(!1),_=ns[a.status],C=s.useMemo(()=>be(o,a),[o,a]),k=s.useCallback(()=>{d(a)},[d,a]),M=s.useCallback(h=>{h.stopPropagation(),t(a.id)},[t,a.id]),w=s.useCallback(h=>{h.stopPropagation(),d(a)},[d,a]),n=s.useCallback(h=>{if(h.stopPropagation(),!g){x(!0);return}p(a.id),x(!1)},[g,p,a.id]),m=s.useCallback(h=>{(h.key==="Enter"||h.key===" ")&&(h.preventDefault(),d(a))},[d,a]);return e.jsxs("article",{className:`node-card ${f?"node-card--loading":""}`,"data-node-id":a.id,role:"button",tabIndex:0,onClick:k,onKeyDown:m,children:[e.jsx("header",{className:"node-card__header",children:e.jsxs("div",{className:"node-card__title-wrap",children:[e.jsx("div",{className:"node-card__icon",children:e.jsx(Ce,{size:18})}),e.jsxs("div",{children:[e.jsx("h3",{className:"node-card__name",title:a.name,children:a.name}),e.jsxs("div",{className:"node-card__meta-row",children:[e.jsx("span",{className:"node-card__type-badge",children:a.type==="local"?"Local":"Remote"}),e.jsxs("span",{className:`node-card__status ${_.className}`,style:{color:_.color},"data-status":a.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:_.color},"aria-hidden":!0}),_.label]}),a.type==="remote"&&u&&e.jsx("span",{className:`node-card__auth-indicator node-card__auth-indicator--${u}`,title:rs(u,i),"aria-label":`Auth sync: ${u==="match"?"credentials match":u==="differs"?"credentials differ":"not synced"}`,style:{color:ls[u]},children:e.jsx(Se,{size:14})})]})]})]})}),e.jsxs("div",{className:"node-card__body",children:[a.type==="remote"&&a.url&&e.jsx("div",{className:"node-card__url",title:a.url,children:os(a.url)}),e.jsxs("div",{className:"node-card__metrics",children:[e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Projects"}),e.jsx("span",{className:"node-card__metric-value",children:C})]}),e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Concurrency"}),e.jsx("span",{className:"node-card__metric-value",children:a.maxConcurrent})]})]}),a.type==="remote"&&l&&e.jsxs("div",{className:"node-card__sync","data-sync-state":l.syncState,"data-testid":"node-card-sync",children:[e.jsx("span",{className:"node-card__sync-dot",style:{backgroundColor:es(l.syncState)},"aria-hidden":!0}),e.jsx("span",{className:"node-card__sync-time",children:Ae(l.lastSyncAt)})]})]}),e.jsxs("footer",{className:"node-card__actions",children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:M,disabled:f,"aria-label":"Run node health check",title:"Health Check",children:[e.jsx(we,{size:14}),e.jsx("span",{children:"Health"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:w,disabled:f,"aria-label":"Edit node",title:"Edit",children:[e.jsx(Ue,{size:14}),e.jsx("span",{children:"Edit"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:w,disabled:f,"aria-label":"Start node container",title:"Start Container",children:[e.jsx(Fe,{size:14}),e.jsx("span",{children:"Start"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:w,disabled:f,"aria-label":"Stop node container",title:"Stop Container",children:[e.jsx(Ve,{size:14}),e.jsx("span",{children:"Stop"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:w,disabled:f,"aria-label":"Restart node container",title:"Restart Container",children:[e.jsx(Be,{size:14}),e.jsx("span",{children:"Restart"})]}),e.jsxs("button",{className:`btn btn-sm node-card__action node-card__action--remove ${g?"btn-danger is-armed":""}`,type:"button",onClick:n,disabled:f,"aria-label":g?"Confirm remove node":"Remove node",title:g?"Confirm remove":"Remove",children:[e.jsx(xe,{size:14}),e.jsx("span",{children:g?"Confirm":"Remove"})]})]})]})}const ds=s.memo(is,cs),se={online:"var(--success, var(--color-success))",offline:"var(--text-dim)",connecting:"var(--triage)",error:"var(--color-error)"},Q=28,_e=12,us=300,ms=120;function hs({nodes:a,className:o}){const t=s.useMemo(()=>a.find(i=>i.type==="local")??a[0],[a]),d=s.useMemo(()=>a.filter(i=>i.type==="remote"),[a]),p=s.useMemo(()=>{const i=us,g=Math.max(0,d.length-4)*20;return i+g},[d.length]),f=p/2,l=p/2,u=s.useMemo(()=>{if(d.length===0)return[];const i=Math.min(ms,p/2-Q-10),g=2*Math.PI/d.length,x=-Math.PI/2;return d.map((_,C)=>{const k=x+C*g;return{node:_,x:f+i*Math.cos(k),y:l+i*Math.sin(k)}})},[d,p,f,l]);return a.length===0?e.jsx("div",{className:`mesh-topology mesh-topology--empty ${o??""}`,children:e.jsx("div",{className:"mesh-topology__empty-state",children:e.jsx("p",{children:"No nodes to display"})})}):e.jsxs("div",{className:`mesh-topology ${o??""}`,children:[e.jsxs("svg",{className:"mesh-topology__svg",viewBox:`0 0 ${p} ${p}`,preserveAspectRatio:"xMidYMid meet","aria-label":"Node mesh topology visualization",children:[u.map(i=>e.jsx("line",{className:"mesh-topology__link",x1:f,y1:l,x2:i.x,y2:i.y},`link-${i.node.id}`)),t&&e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${f}, ${l})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:Q,fill:se[t.status],"aria-label":`${t.name} (${t.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:Q+_e,textAnchor:"middle",children:t.name.length>12?`${t.name.slice(0,10)}…`:t.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-Q-10})`,children:[e.jsx("circle",{className:"mesh-topology__node-type-badge",r:"8"}),e.jsx("text",{className:"mesh-topology__node-type-text",textAnchor:"middle",dominantBaseline:"middle",children:t.type==="local"?"L":"R"})]})]}),u.map(i=>e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${i.x}, ${i.y})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:Q,fill:se[i.node.status],"aria-label":`${i.node.name} (${i.node.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:Q+_e,textAnchor:"middle",children:i.node.name.length>12?`${i.node.name.slice(0,10)}…`:i.node.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-Q-10})`,children:[e.jsx("circle",{className:"mesh-topology__node-type-badge",r:"8"}),e.jsx("text",{className:"mesh-topology__node-type-text",textAnchor:"middle",dominantBaseline:"middle",children:i.node.type==="local"?"L":"R"})]})]},i.node.id))]}),e.jsxs("div",{className:"mesh-topology__legend",children:[e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.online}}),e.jsx("span",{children:"Online"})]}),e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.offline}}),e.jsx("span",{children:"Offline"})]}),e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.connecting}}),e.jsx("span",{children:"Connecting"})]}),e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.error}}),e.jsx("span",{children:"Error"})]})]}),e.jsx("p",{className:"mesh-topology__notice",children:"Peer-to-peer discovery data unavailable."})]})}const fs=s.memo(hs),ye=1,je=10;function gs(a){const o={};return a.name.trim()||(o.name="Name is required"),a.type==="remote"&&!a.url?.trim()&&(o.url="URL is required for remote nodes"),(!Number.isFinite(a.maxConcurrent)||a.maxConcurrent<ye||a.maxConcurrent>je)&&(o.maxConcurrent=`Concurrency must be between ${ye} and ${je}`),o}function xs({isOpen:a,onClose:o,onSubmit:t,addToast:d}){const[p,f]=s.useState(""),[l,u]=s.useState("local"),[i,g]=s.useState(""),[x,_]=s.useState(""),[C,k]=s.useState(2),[M,w]=s.useState("auto-generate"),[n,m]=s.useState({}),[h,P]=s.useState(!1),E=s.useCallback(()=>{f(""),u("local"),g(""),_(""),k(2),w("auto-generate"),m({}),P(!1)},[]),R=s.useCallback(()=>{h||(E(),o())},[h,o,E]);s.useEffect(()=>{if(!a){E();return}const c=b=>{b.key==="Escape"&&(b.preventDefault(),R())};return document.addEventListener("keydown",c),()=>{document.removeEventListener("keydown",c)}},[R,a,E]);const D=s.useMemo(()=>({name:p.trim(),type:l,url:l==="remote"&&i.trim()||void 0,apiKey:l==="remote"&&M==="provide"&&x||void 0,maxConcurrent:C,apiKeyMode:M}),[x,M,C,p,l,i]),y=s.useCallback(async()=>{if(h)return;const c=gs(D);if(m(c),!(Object.keys(c).length>0)){P(!0);try{await t(D),d(`Node "${D.name}" registered`,"success"),R()}catch(b){const I=b instanceof Error?b.message:"Failed to register node";d(I,"error")}finally{P(!1)}}},[d,R,D,h,t]);return a?e.jsx("div",{className:"modal-overlay open",onClick:R,children:e.jsxs("div",{className:"modal modal-md add-node-modal",onClick:c=>c.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":"Add Node",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Add Node"}),e.jsx("button",{className:"modal-close",onClick:R,disabled:h,"aria-label":"Close add node modal",children:"×"})]}),e.jsxs("div",{className:"modal-body add-node-modal__body",children:[e.jsx("p",{className:"add-node-modal__description",children:"Register an existing Fusion node by providing its connection details and concurrency settings."}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Name"}),e.jsx("input",{className:"input",type:"text",value:p,onChange:c=>f(c.target.value),placeholder:"Build Machine",disabled:h,"aria-invalid":!!n.name,autoFocus:!0}),n.name&&e.jsx("span",{className:"form-error add-node-modal__error",children:n.name})]}),e.jsxs("div",{className:"add-node-modal__type-toggle",children:[e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${l==="local"?"active":""}`,"data-type":"local",onClick:()=>u("local"),disabled:h,"aria-pressed":l==="local",children:"Local"}),e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${l==="remote"?"active":""}`,"data-type":"remote",onClick:()=>u("remote"),disabled:h,"aria-pressed":l==="remote",children:"Remote"})]}),l==="remote"&&e.jsxs("div",{className:"add-node-modal__remote-fields","data-testid":"remote-fields-container","data-visible":!0,children:[e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Reachable URL / Hostname"}),e.jsx("input",{className:"input",type:"text",value:i,onChange:c=>g(c.target.value),placeholder:"https://node.example.com",disabled:h,"aria-invalid":!!n.url}),n.url&&e.jsx("span",{className:"form-error add-node-modal__error",children:n.url})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key Mode"}),e.jsxs("select",{className:"select",value:M,onChange:c=>w(c.target.value),disabled:h,children:[e.jsx("option",{value:"auto-generate",children:"Auto-generate"}),e.jsx("option",{value:"provide",children:"Provide key manually"})]})]}),M==="provide"&&e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:x,onChange:c=>_(c.target.value),placeholder:"Enter node API key",disabled:h})]})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),e.jsx("input",{className:"input",type:"number",min:ye,max:je,value:C,onChange:c=>k(Number(c.target.value)),disabled:h,"aria-invalid":!!n.maxConcurrent}),e.jsx("span",{className:"add-node-modal__hint",children:"Max simultaneous task agents (1–10)"}),n.maxConcurrent&&e.jsx("span",{className:"form-error add-node-modal__error",children:n.maxConcurrent})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:R,disabled:h,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm","data-testid":"add-node-submit",onClick:y,disabled:h,children:h?"Adding...":"Add Node"})]})]})}):null}const fe="http://localhost:4040";function ps({isOpen:a,onClose:o,onSubmit:t,addToast:d}){const[p,f]=s.useState(""),[l,u]=s.useState("local"),[i,g]=s.useState(fe),[x,_]=s.useState("auto"),[C,k]=s.useState(""),[M,w]=s.useState(!1),[n,m]=s.useState(!1),[h,P]=s.useState(!0),[E,R]=s.useState(4096),[D,y]=s.useState(2),[c,b]=s.useState(!1),[I,O]=s.useState("runfusion/fusion"),[q,X]=s.useState("latest"),[U,G]=s.useState(""),[B,v]=s.useState(""),[S,z]=s.useState(!0),[W,Z]=s.useState(""),[L,oe]=s.useState(""),[ae,ce]=s.useState(""),[te,J]=s.useState([]),[ne,ee]=s.useState([]),[F,ie]=s.useState({}),[N,le]=s.useState(!1),V=s.useCallback(()=>{f(""),u("local"),g(fe),_("auto"),k(""),w(!1),m(!1),P(!0),R(4096),y(2),b(!1),O("runfusion/fusion"),X("latest"),G(""),v(""),z(!0),Z(""),oe(""),ce(""),J([]),ee([]),ie({}),le(!1)},[]),H=s.useCallback(()=>{N||(V(),o())},[o,V,N]);s.useEffect(()=>{if(!a){V();return}const r=A=>{A.key==="Escape"&&(A.preventDefault(),H())};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[H,a,V]);const Y=s.useMemo(()=>({nodeId:null,name:p.trim(),imageName:I.trim()||"runfusion/fusion",imageTag:q.trim()||"latest",hostConfig:{context:U.trim()||void 0,host:l==="remote"&&B.trim()||void 0,tlsVerify:l==="remote"?S:void 0,tlsCaPath:l==="remote"&&W.trim()||void 0,tlsCertPath:l==="remote"&&L.trim()||void 0,tlsKeyPath:l==="remote"&&ae.trim()||void 0},envVars:Object.fromEntries(te.map(r=>[r.key.trim(),r.value]).filter(([r])=>!!r)),volumeMounts:ne.map(r=>({hostPath:r.hostPath.trim(),containerPath:r.containerPath.trim(),mode:r.mode})).filter(r=>r.hostPath&&r.containerPath),resourceSizing:{memoryMB:E,cpus:D},extraClis:[M?"claude-cli":null,n?"droid-cli":null].filter(Boolean),persistentStorage:h,reachableUrl:i.trim()||null,apiKey:x==="manual"&&C.trim()||null}),[C,x,D,U,B,te,I,q,M,n,l,E,ne,p,h,i,W,L,ae,S]),j=s.useCallback(()=>{J(r=>[...r,{key:"",value:""}])},[]),$=s.useCallback((r,A)=>{J(K=>K.map((T,me)=>me===r?A:T))},[]),de=s.useCallback(r=>{J(A=>A.filter((K,T)=>T!==r))},[]),De=s.useCallback(()=>{ee(r=>[...r,{hostPath:"",containerPath:"",mode:"rw"}])},[]),ue=s.useCallback((r,A)=>{ee(K=>K.map((T,me)=>me===r?A:T))},[]),Le=s.useCallback(r=>{ee(A=>A.filter((K,T)=>T!==r))},[]),$e=s.useCallback(async()=>{if(N)return;const r={};if((!Y.name||Y.name.length>64)&&(r.name="Name is required and must be 64 characters or fewer"),l==="remote"&&!Y.reachableUrl&&(r.reachableUrl="URL is required for remote Docker"),E<512&&(r.memoryMB="Memory must be at least 512 MB"),D<.5&&(r.cpus="CPUs must be at least 0.5"),ie(r),!(Object.keys(r).length>0)){le(!0);try{await t(Y),H()}catch{}finally{le(!1)}}},[H,D,Y,l,E,t,N]);return a?e.jsx("div",{className:"modal-overlay open",onClick:H,children:e.jsxs("div",{className:"modal docker-onboarding",role:"dialog","aria-modal":"true","aria-label":"Docker node onboarding",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Provision Docker Node"}),e.jsx("button",{className:"modal-close",onClick:H,disabled:N,"aria-label":"Close onboarding modal",children:"×"})]}),e.jsxs("div",{className:"modal-body docker-onboarding__body",children:[e.jsxs("section",{className:"docker-onboarding__section",children:[e.jsx("h4",{className:"docker-onboarding__section-title",children:"Required Settings"}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Node Name"}),e.jsx("input",{className:"input",value:p,onChange:r=>f(r.target.value),disabled:N,placeholder:"my-docker-node",autoFocus:!0})]}),F.name&&e.jsx("div",{className:"form-error",children:F.name}),e.jsxs("div",{className:"docker-onboarding__type-toggle",role:"tablist","aria-label":"Target location",children:[e.jsx("button",{type:"button",className:`docker-onboarding__type-btn ${l==="local"?"is-active":""}`,onClick:()=>u("local"),disabled:N,"aria-pressed":l==="local",children:"Local Docker"}),e.jsx("button",{type:"button",className:`docker-onboarding__type-btn ${l==="remote"?"is-active":""}`,onClick:()=>u("remote"),disabled:N,"aria-pressed":l==="remote",children:"Remote Docker"})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Reachable URL"}),e.jsx("input",{className:"input",value:i,onChange:r=>g(r.target.value),disabled:N,placeholder:l==="local"?fe:"http://192.168.1.50:4040"})]}),F.reachableUrl&&e.jsx("div",{className:"form-error",children:F.reachableUrl}),l==="remote"&&e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Docker Host"}),e.jsx("input",{className:"input",value:B,onChange:r=>v(r.target.value),disabled:N,placeholder:"tcp://host:2376"})]}),e.jsxs("div",{className:"docker-onboarding__radio-group",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"radio",checked:x==="auto",onChange:()=>_("auto"),disabled:N}),"Auto-generate"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"radio",checked:x==="manual",onChange:()=>_("manual"),disabled:N}),"Provide manually"]})]}),x==="manual"&&e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:C,onChange:r=>k(r.target.value),disabled:N,placeholder:"Enter API key"})]}),e.jsxs("div",{className:"docker-onboarding__checkbox-group",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:M,onChange:r=>w(r.target.checked),disabled:N}),"Claude CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:n,onChange:r=>m(r.target.checked),disabled:N}),"Droid CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:h,onChange:r=>P(r.target.checked),disabled:N}),"Keep data across container recreations"]})]}),e.jsxs("div",{className:"docker-onboarding__inline-fields",children:[e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Memory (MB)"}),e.jsx("input",{className:"input",type:"number",min:512,value:E,onChange:r=>R(Number(r.target.value)),disabled:N})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"CPUs"}),e.jsx("input",{className:"input",type:"number",min:.5,step:.5,value:D,onChange:r=>y(Number(r.target.value)),disabled:N})]})]}),F.memoryMB&&e.jsx("div",{className:"form-error",children:F.memoryMB}),F.cpus&&e.jsx("div",{className:"form-error",children:F.cpus})]}),e.jsxs("section",{className:"docker-onboarding__section",children:[e.jsxs("button",{type:"button",className:`docker-onboarding__advanced-toggle ${c?"is-expanded":""}`,onClick:()=>b(r=>!r),disabled:N,children:[e.jsx("span",{children:"Advanced"}),e.jsx(Me,{})]}),e.jsx("div",{className:`docker-onboarding__advanced-content ${c?"is-expanded":""}`,children:e.jsxs("div",{children:[e.jsxs("div",{className:"docker-onboarding__inline-fields",children:[e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Image"}),e.jsx("input",{className:"input",value:I,onChange:r=>O(r.target.value),disabled:N,placeholder:"runfusion/fusion"})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Tag"}),e.jsx("input",{className:"input",value:q,onChange:r=>X(r.target.value),disabled:N,placeholder:"latest"})]})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Docker Context"}),e.jsx("input",{className:"input",value:U,onChange:r=>G(r.target.value),disabled:N,placeholder:"default"})]}),l==="local"&&e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Docker Host"}),e.jsx("input",{className:"input",value:B,onChange:r=>v(r.target.value),disabled:N||!!U.trim(),placeholder:"tcp://host:2376"})]}),l==="remote"&&e.jsxs("div",{className:"docker-onboarding__tls-fields",children:[e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"CA Cert Path"}),e.jsx("input",{className:"input",value:W,onChange:r=>Z(r.target.value),disabled:N,placeholder:"/etc/docker/ca.pem"})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Client Cert Path"}),e.jsx("input",{className:"input",value:L,onChange:r=>oe(r.target.value),disabled:N,placeholder:"/etc/docker/cert.pem"})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Client Key Path"}),e.jsx("input",{className:"input",value:ae,onChange:r=>ce(r.target.value),disabled:N,placeholder:"/etc/docker/key.pem"})]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:S,onChange:r=>z(r.target.checked),disabled:N}),"TLS verify"]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Environment Variables"}),te.map((r,A)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--env",children:[e.jsx("input",{className:"input",placeholder:"KEY",value:r.key,disabled:N,onChange:K=>$(A,{key:K.target.value,value:r.value})}),e.jsx("input",{className:"input",placeholder:"Value",value:r.value,disabled:N,onChange:K=>$(A,{key:r.key,value:K.target.value})}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":"Remove environment variable",onClick:()=>de(A),disabled:N,children:e.jsx(xe,{size:14})})]},`env-${A}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:j,disabled:N,children:[e.jsx(re,{size:14}),"Add variable"]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Volume Mounts"}),ne.map((r,A)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--mount",children:[e.jsx("input",{className:"input",placeholder:"Host path",value:r.hostPath,disabled:N,onChange:K=>ue(A,{hostPath:K.target.value,containerPath:r.containerPath,mode:r.mode})}),e.jsx("input",{className:"input",placeholder:"Container path",value:r.containerPath,disabled:N,onChange:K=>ue(A,{hostPath:r.hostPath,containerPath:K.target.value,mode:r.mode})}),e.jsxs("select",{className:"select",value:r.mode,disabled:N,onChange:K=>ue(A,{hostPath:r.hostPath,containerPath:r.containerPath,mode:K.target.value==="ro"?"ro":"rw"}),children:[e.jsx("option",{value:"rw",children:"rw"}),e.jsx("option",{value:"ro",children:"ro"})]}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":"Remove volume mount",onClick:()=>Le(A),disabled:N,children:e.jsx(xe,{size:14})})]},`mount-${A}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:De,disabled:N,children:[e.jsx(re,{size:14}),"Add mount"]})]})]})})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn",onClick:H,disabled:N,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",onClick:()=>void $e(),disabled:N,children:N?"Creating...":"Create Docker Node"})]})]})}):null}function bs({nodeId:a,entries:o,loading:t=!1,singleNode:d=!1}){const[p,f]=s.useState(!1),[l,u]=s.useState("all"),[i,g]=s.useState("all"),x=s.useCallback(()=>{f(n=>!n)},[]),_=s.useMemo(()=>{const n=new Set;for(const m of o)n.add(m.nodeName);return Array.from(n).sort()},[o]),C=s.useMemo(()=>{let n=[...o];return l!=="all"&&(n=n.filter(m=>m.direction===l)),!d&&i!=="all"&&(n=n.filter(m=>m.nodeName===i)),n.sort((m,h)=>{const P=new Date(m.timestamp).getTime();return new Date(h.timestamp).getTime()-P}),n},[o,l,i,d]),k=s.useCallback(n=>new Date(n).toLocaleString(),[]),M=s.useCallback(n=>{switch(n){case"success":return"settings-sync-log__badge--success";case"conflict":return"settings-sync-log__badge--conflict";case"error":return"settings-sync-log__badge--error";default:return""}},[]),w=s.useCallback(n=>{switch(n){case"success":return"Success";case"conflict":return"Conflict";case"error":return"Error";default:return n}},[]);return e.jsxs("div",{className:"settings-sync-log",children:[e.jsxs("button",{className:"settings-sync-log__header",type:"button",onClick:x,"aria-expanded":p,"data-testid":"settings-sync-log-header",children:[e.jsx(Me,{size:16,className:`settings-sync-log__chevron ${p?"settings-sync-log__chevron--expanded":""}`}),e.jsxs("span",{children:[o.length," ",o.length===1?"entry":"entries"]})]}),p&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-sync-log__filters",children:[e.jsxs("label",{children:["Direction:",e.jsxs("select",{value:l,onChange:n=>u(n.target.value),children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"push",children:"Push"}),e.jsx("option",{value:"pull",children:"Pull"})]})]}),!d&&e.jsxs("label",{children:["Node:",e.jsxs("select",{value:i,onChange:n=>g(n.target.value),children:[e.jsx("option",{value:"all",children:"All Nodes"}),_.map(n=>e.jsx("option",{value:n,children:n},n))]})]})]}),t&&o.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"Loading..."}):C.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"No sync history available"}):e.jsx("div",{className:"settings-sync-log__list",children:C.map(n=>e.jsxs("div",{className:"settings-sync-log__entry",children:[e.jsx("span",{className:"settings-sync-log__entry-timestamp",children:k(n.timestamp)}),e.jsx("span",{className:"settings-sync-log__entry-direction",children:n.direction==="push"?e.jsx(Ee,{size:14,"data-testid":"upload-icon"}):e.jsx(Pe,{size:14,"data-testid":"download-icon"})}),e.jsx("span",{className:`settings-sync-log__entry-result ${M(n.result)}`,children:w(n.result)}),!d&&e.jsx("span",{className:"settings-sync-log__entry-node",children:n.nodeName}),n.details&&e.jsx("span",{className:"settings-sync-log__entry-details",title:n.details,children:n.details})]},n.id))})]})]})}function ys(a,o){const t=typeof a=="string"?a:JSON.stringify(a,null,2),d=typeof o=="string"?o:JSON.stringify(o,null,2);if(t===d)return t;const p=t.split(`
|
|
12
|
+
`),f=d.split(`
|
|
13
|
+
`),l=[],u=Math.max(p.length,f.length);for(let i=0;i<u;i++){const g=p[i],x=f[i];g!==void 0&&g!==x&&l.push(`- ${g}`),x!==void 0&&x!==g&&l.push(`+ ${x}`),g!==void 0&&g===x&&l.push(` ${g}`)}return l.join(`
|
|
14
|
+
`)}function js({isOpen:a,onClose:o,onResolve:t,conflicts:d,localNodeName:p,remoteNodeName:f,addToast:l}){const[u,i]=s.useState({}),[g,x]=s.useState(!1);s.useEffect(()=>{const n={};for(const m of d)u[m.key]||(n[m.key]={resolution:"local"});Object.keys(n).length>0&&i(m=>({...m,...n}))},[d,u]),s.useEffect(()=>{if(!a)return;const n=m=>{m.key==="Escape"&&(m.preventDefault(),o())};return document.addEventListener("keydown",n),()=>document.removeEventListener("keydown",n)},[a,o]);const _=s.useCallback((n,m)=>{i(h=>{const P=h[n]??{};return m==="manual"?{...h,[n]:{resolution:"manual",manualValue:P.manualValue??JSON.stringify(d.find(E=>E.key===n)?.localValue??null,null,2)}}:{...h,[n]:{resolution:m}}})},[d]),C=s.useCallback((n,m)=>{i(h=>({...h,[n]:{...h[n],resolution:"manual",manualValue:m}}))},[]),k=s.useCallback(n=>{const m={};for(const h of d)m[h.key]={resolution:n};i(m)},[d]),M=s.useCallback(async()=>{x(!0);try{const n=d.map(m=>{const h=u[m.key]??{resolution:"local"};let P;switch(h.resolution){case"remote":P=m.remoteValue;break;case"manual":try{P=JSON.parse(h.manualValue??"null")}catch{P=h.manualValue??null}break;case"local":default:P=m.localValue;break}return{key:m.key,value:P}});await t(n),l("Settings conflicts resolved successfully","success"),o()}catch(n){const m=n instanceof Error?n.message:"Failed to resolve conflicts";l(m,"error")}finally{x(!1)}},[l,d,o,t,u]),w=s.useMemo(()=>{const n={};for(const m of d)n[m.key]=ys(m.localValue,m.remoteValue);return n},[d]);return!a||d.length===0?null:e.jsx("div",{className:"modal-overlay open",onClick:o,children:e.jsxs("div",{className:"modal modal-lg settings-sync-conflict-modal",onClick:n=>n.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":"Resolve Settings Conflicts",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Resolve Settings Conflicts"}),e.jsx("button",{className:"modal-close",onClick:o,"aria-label":"Close conflict modal",children:"×"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsx("div",{className:"settings-sync-conflict-modal__conflict-list",children:d.map(n=>{const m=u[n.key]??{resolution:"local"},h=w[n.key];return e.jsxs("div",{className:"settings-sync-conflict-modal__conflict-item",children:[e.jsx("div",{className:"settings-sync-conflict-modal__key",children:n.key}),e.jsxs("div",{className:"settings-sync-conflict-modal__diff-panel",children:[e.jsxs("div",{className:"settings-sync-conflict-modal__diff-side",children:[e.jsx("div",{className:"settings-sync-conflict-modal__diff-label",children:p}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:h})})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__diff-side",children:[e.jsx("div",{className:"settings-sync-conflict-modal__diff-label",children:f}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:h})})]})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__resolution",children:[e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${n.key}`,checked:m.resolution==="local",onChange:()=>_(n.key,"local")}),"Keep Local"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${n.key}`,checked:m.resolution==="remote",onChange:()=>_(n.key,"remote")}),"Keep Remote"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${n.key}`,checked:m.resolution==="manual",onChange:()=>_(n.key,"manual")}),"Merge Manually"]})]}),m.resolution==="manual"&&e.jsx("textarea",{className:"settings-sync-conflict-modal__manual-input",value:m.manualValue??"",onChange:P=>C(n.key,P.target.value),placeholder:"Enter JSON value..."})]},n.key)})}),e.jsxs("div",{className:"settings-sync-conflict-modal__bulk-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>k("local"),type:"button",children:"Resolve All: Keep Local"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>k("remote"),type:"button",children:"Resolve All: Keep Remote"})]})]}),e.jsxs("div",{className:"modal-actions settings-sync-conflict-modal__footer",children:[e.jsx("button",{className:"btn btn-sm",onClick:o,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:M,disabled:g,children:g?"Resolving...":"Confirm"})]})]})})}function ge(a){if(!a)return"—";const o=new Date(a);return Number.isNaN(o.getTime())?"—":o.toLocaleString()}function Ns(a){switch(a){case"synced":return"node-detail-modal__sync-dot--synced";case"diff":return"node-detail-modal__sync-dot--diff";case"error":return"node-detail-modal__sync-dot--error";case"pending":return"node-detail-modal__sync-dot--pending";case"never-synced":default:return"node-detail-modal__sync-dot--never"}}function vs({isOpen:a,onClose:o,node:t,projects:d,onUpdate:p,onHealthCheck:f,addToast:l,syncStatus:u,onPushSettings:i,onPullSettings:g,onSyncAuth:x,syncHistory:_=[],onResolveConflicts:C}){const k=s.useRef(!0),[M,w]=s.useState(!1),[n,m]=s.useState(""),[h,P]=s.useState(""),[E,R]=s.useState(""),[D,y]=s.useState(2),[c,b]=s.useState(!1),[I,O]=s.useState(!1),[q,X]=s.useState(!1),[U,G]=s.useState(!1),[B,v]=s.useState(null),[S,z]=s.useState(!1),[W]=s.useState([]),[Z,L]=s.useState("running"),[oe,ae]=s.useState("FUSION_LOG_LEVEL=info"),[ce,te]=s.useState("/srv/fusion:/data:rw");s.useEffect(()=>(k.current=!0,()=>{k.current=!1}),[]),s.useEffect(()=>{if(!t||!a){w(!1);return}m(t.name),P(t.url??""),R(t.apiKey??""),y(t.maxConcurrent),w(!1)},[a,t]),s.useEffect(()=>{if(!a)return;const j=$=>{$.key==="Escape"&&($.preventDefault(),o())};return document.addEventListener("keydown",j),()=>document.removeEventListener("keydown",j)},[a,o]);const J=s.useMemo(()=>t?Re(d,t):[],[t,d]),ne=s.useMemo(()=>t?.capabilities?.includes("docker-managed")??!1,[t]),ee=s.useCallback(async()=>{if(t)try{if(await f(t.id),!k.current)return;l(`Health check completed for ${t.name}`,"success")}catch(j){if(!k.current)return;const $=j instanceof Error?j.message:"Health check failed";l($,"error")}},[l,t,f]),F=s.useCallback(async()=>{if(!(!t||!i)){v(null),O(!0);try{if(await i(t.id),!k.current)return;l("Settings pushed successfully","success")}catch(j){if(!k.current)return;const $=j instanceof Error?j.message:"Push settings failed";v($),l($,"error")}finally{k.current&&O(!1)}}},[l,t,i]),ie=s.useCallback(async()=>{if(!(!t||!g)){v(null),X(!0);try{if(await g(t.id),!k.current)return;l("Settings pulled successfully","success")}catch(j){if(!k.current)return;const $=j instanceof Error?j.message:"Pull settings failed";v($),l($,"error")}finally{k.current&&X(!1)}}},[l,t,g]),N=s.useCallback(async()=>{if(!(!t||!x)){v(null),G(!0);try{if(await x(t.id),!k.current)return;l("Auth credentials synced successfully","success")}catch(j){if(!k.current)return;const $=j instanceof Error?j.message:"Auth sync failed";v($),l($,"error")}finally{k.current&&G(!1)}}},[l,t,x]),le=s.useCallback(()=>{v(null)},[]),V=s.useCallback(j=>{j==="start"&&L("running"),j==="stop"&&L("stopped"),j==="restart"&&L("running"),j==="recreate"&&L("recreating"),j==="upgrade"&&L("recreating"),l(`Docker action queued: ${j}`,"success")},[l]),H=s.useCallback(async()=>{if(!t||c)return;const j=n.trim();if(!j){l("Name is required","error");return}if(t.type==="remote"&&!h.trim()){l("URL is required for remote nodes","error");return}if(!Number.isFinite(D)||D<1){l("Concurrency must be at least 1","error");return}b(!0);try{await p(t.id,{name:j,url:t.type==="remote"&&h.trim()||void 0,apiKey:t.type==="remote"&&E||void 0,maxConcurrent:D}),l(`Updated ${j}`,"success"),w(!1)}catch($){const de=$ instanceof Error?$.message:"Failed to update node";l(de,"error")}finally{b(!1)}},[l,E,c,D,n,t,p,h]),Y=s.useCallback(()=>{t&&(m(t.name),P(t.url??""),R(t.apiKey??""),y(t.maxConcurrent),w(!1))},[t]);return!a||!t?null:e.jsxs("div",{className:"modal-overlay open",onClick:o,children:[e.jsxs("div",{className:"modal modal-lg node-detail-modal",onClick:j=>j.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":`Node details for ${t.name}`,children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Node Details"}),e.jsx("button",{className:"modal-close",onClick:o,"aria-label":"Close node detail modal",children:"×"})]}),e.jsxs("div",{className:"modal-body node-detail-modal__body",children:[e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsxs("div",{className:"node-detail-modal__section-header",children:[e.jsx("h4",{children:"Overview"}),!M&&e.jsxs("button",{className:"btn btn-sm",onClick:()=>w(!0),children:[e.jsx(He,{size:14}),"Edit"]})]}),e.jsxs("div",{className:"node-detail-modal__grid",children:[e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Name"}),M?e.jsx("input",{className:"input",value:n,onChange:j=>m(j.target.value),disabled:c}):e.jsx("strong",{children:t.name})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Type"}),e.jsx("strong",{children:t.type==="local"?"Local":"Remote"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Status"}),e.jsx("strong",{children:t.status})]}),e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),M?e.jsx("input",{className:"input",type:"number",min:1,max:10,value:D,onChange:j=>y(Number(j.target.value)),disabled:c}):e.jsx("strong",{children:t.maxConcurrent})]}),t.type==="remote"&&e.jsxs(e.Fragment,{children:[e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"URL"}),M?e.jsx("input",{className:"input",value:h,onChange:j=>P(j.target.value),disabled:c}):e.jsx("strong",{children:t.url??"—"})]}),e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"API Key"}),M?e.jsx("input",{className:"input",type:"password",value:E,onChange:j=>R(j.target.value),placeholder:"Leave blank to keep unchanged",disabled:c}):e.jsx("strong",{children:t.apiKey?"••••••••":"Not configured"})]})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Created"}),e.jsx("strong",{children:ge(t.createdAt)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Updated"}),e.jsx("strong",{children:ge(t.updatedAt)})]})]}),M&&e.jsxs("div",{className:"node-detail-modal__edit-actions",children:[e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:H,disabled:c,children:[e.jsx(qe,{size:14}),c?"Saving...":"Save"]}),e.jsxs("button",{className:"btn btn-sm",onClick:Y,disabled:c,children:[e.jsx(pe,{size:14}),"Cancel"]})]})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsxs("h4",{children:[t.type==="local"?"Projects":"Assigned Projects"," (",J.length,")"]}),J.length===0?e.jsx("p",{className:"node-detail-modal__empty",children:t.type==="local"?"No projects are running on this node.":"No projects are assigned to this node."}):e.jsx("ul",{className:"node-detail-modal__project-list",children:J.map(j=>e.jsxs("li",{className:"node-detail-modal__project-item",children:[e.jsx("span",{children:j.name}),e.jsx("code",{children:j.id})]},j.id))})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Health"}),e.jsxs("div",{className:"node-detail-modal__health-row",children:[e.jsxs("span",{children:["Status: ",e.jsx("strong",{children:t.status})]}),e.jsxs("span",{children:["Last check: ",e.jsx("strong",{children:ge(t.updatedAt)})]})]})]}),ne&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Docker Management"}),e.jsxs("div",{className:"node-detail-modal__health-row",children:[e.jsxs("span",{children:["Container: ",e.jsx("strong",{children:Z})]}),e.jsxs("span",{children:["Image: ",e.jsx("strong",{children:"runfusion/fusion:latest"})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>V("start"),children:"Start"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>V("stop"),children:"Stop"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>V("restart"),children:"Restart"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>V("recreate"),children:"Recreate"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>V("upgrade"),children:"Upgrade Image"})]}),e.jsxs("div",{className:"node-detail-modal__docker-grid",children:[e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Environment Variables"}),e.jsx("textarea",{className:"input node-detail-modal__textarea",value:oe,onChange:j=>ae(j.target.value)})]}),e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Volume Mounts"}),e.jsx("textarea",{className:"input node-detail-modal__textarea",value:ce,onChange:j=>te(j.target.value)})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>l("Container logs opened","success"),children:"View Logs"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>l("Config changes saved","success"),children:"Save Config"}),e.jsx("button",{className:"btn btn-danger btn-sm",onClick:()=>l("Delete flow opened (retain/remove volumes)","warning"),children:"Delete Node…"})]})]}),t.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Settings Sync"}),u&&e.jsxs("div",{className:"node-detail-modal__sync-status",children:[e.jsx("span",{className:`node-detail-modal__sync-dot ${Ns(u.syncState)}`,"aria-hidden":!0}),e.jsxs("span",{children:["Last sync:"," ",e.jsx("strong",{children:u.lastSyncAt?Ae(u.lastSyncAt):"Never synced"})]}),u.diffCount>0&&e.jsxs("span",{className:"node-detail-modal__sync-diff",children:["Differences: ",e.jsx("strong",{children:u.diffCount})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:F,disabled:I||!i,children:[e.jsx(Ee,{size:14}),I?"Pushing...":"Push Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:ie,disabled:q||!g,children:[e.jsx(Pe,{size:14}),q?"Pulling...":"Pull Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:N,disabled:U||!x,children:[e.jsx(Se,{size:14}),U?"Syncing...":"Sync Auth"]})]}),B&&e.jsxs("div",{className:"node-detail-modal__sync-error",children:[e.jsx("span",{children:B}),e.jsx("button",{className:"node-detail-modal__sync-error-dismiss",onClick:le,"aria-label":"Dismiss error",children:e.jsx(pe,{size:14})})]})]}),t.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Sync History"}),e.jsx(bs,{nodeId:t.id,entries:_,singleNode:!0})]})]}),e.jsxs("div",{className:"modal-actions node-detail-modal__actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:ee,children:[e.jsx(we,{size:14}),"Health Check"]}),e.jsx("button",{className:"btn btn-sm",onClick:o,children:"Close"})]})]}),t.type==="remote"&&e.jsx(js,{isOpen:S,onClose:()=>z(!1),onResolve:C??(async()=>{}),conflicts:W,localNodeName:"Local",remoteNodeName:t.name,addToast:l})]})}function _s(){const[a,o]=s.useState([]),[t,d]=s.useState(!0),[p,f]=s.useState(null),l=s.useCallback(async()=>{try{f(null);const i=await Ne();o(i)}catch(i){f(i instanceof Error?i.message:"Failed to fetch managed Docker nodes")}},[]);s.useEffect(()=>{let i=!1;async function g(){d(!0);try{const x=await Ne();i||(o(x),f(null))}catch(x){i||f(x instanceof Error?x.message:"Failed to fetch managed Docker nodes")}finally{i||d(!1)}}return g(),()=>{i=!0}},[]);const u=s.useCallback(async i=>{const g=await Je(i);return o(x=>[...x,g]),g},[]);return{dockerNodes:a,loading:t,error:p,refresh:l,create:u}}function Ms({addToast:a,onClose:o}){const{nodes:t,loading:d,error:p,refresh:f,register:l,update:u,unregister:i,healthCheck:g}=Xe(),{projects:x}=Ge(),{syncStatusMap:_,pushSettings:C,pullSettings:k,syncAuth:M,trackNode:w,getAuthSyncState:n,getAuthProviders:m}=as(),{dockerNodes:h,create:P}=_s(),[E,R]=s.useState(!1),[D,y]=s.useState(!1),[c,b]=s.useState(null);s.useEffect(()=>{const v=t.filter(S=>S.type==="remote");for(const S of v)w(S.id)},[t,w]),s.useEffect(()=>{if(!c)return;const v=t.find(S=>S.id===c.id)??null;b(v)},[t,c]);const I=s.useMemo(()=>{const v=t.length,S=t.filter(L=>L.status==="online").length,z=t.filter(L=>L.status==="offline"||L.status==="error").length,W=t.filter(L=>L.type==="remote").length,Z=t.filter(L=>L.type==="remote"&&_[L.id]&&he(_[L.id]).syncState==="synced").length;return{total:v,online:S,offline:z,remote:W,synced:Z}},[t,_]),O=s.useCallback(async v=>{await l(v)},[l]),q=s.useCallback(async v=>{try{await P(v),a(`Docker node "${v.name}" created`,"success"),y(!1)}catch(S){const z=S instanceof Error?S.message:"Failed to create Docker node";throw a(z,"error"),S}},[a,P]),X=s.useCallback(async()=>{try{await f()}catch{a("Failed to refresh nodes","error")}},[a,f]),U=s.useCallback(async v=>{try{await g(v),a("Node health check complete","success")}catch(S){const z=S instanceof Error?S.message:"Health check failed";a(z,"error")}},[a,g]),G=s.useCallback(async v=>{try{await i(v),a("Node removed","success"),c?.id===v&&b(null)}catch(S){const z=S instanceof Error?S.message:"Failed to remove node";a(z,"error")}},[a,c?.id,i]),B=s.useCallback(async(v,S)=>{await u(v,S)},[u]);return e.jsxs("div",{className:"nodes-view","data-testid":"nodes-view",children:[e.jsxs("div",{className:"nodes-view-header",children:[e.jsxs("div",{className:"nodes-view-title",children:[e.jsxs("h2",{children:[e.jsx(Ce,{size:20}),"Nodes"]}),e.jsxs("span",{className:"nodes-view-count",children:[t.length," registered"]})]}),e.jsxs("div",{className:"nodes-view-actions",children:[e.jsx("button",{className:"btn-icon nodes-view-close",onClick:o,"aria-label":"Close nodes view",children:e.jsx(pe,{size:16})}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void X(),disabled:d,children:[e.jsx(ve,{size:14,className:d?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>R(!0),children:[e.jsx(re,{size:14}),"Add Node"]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>y(!0),children:[e.jsx(re,{size:14}),"Provision Docker Node"]})]})]}),e.jsxs("div",{className:"nodes-view-stats",children:[e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-total",children:[e.jsx("span",{children:"Total"}),e.jsx("strong",{children:I.total})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--online","data-testid":"nodes-stat-online",children:[e.jsxs("span",{children:[e.jsx(Ze,{size:14})," Online"]}),e.jsx("strong",{children:I.online})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--offline","data-testid":"nodes-stat-offline",children:[e.jsxs("span",{children:[e.jsx(Te,{size:14})," Offline"]}),e.jsx("strong",{children:I.offline})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-remote",children:[e.jsxs("span",{children:[e.jsx(We,{size:14})," Remote"]}),e.jsx("strong",{children:I.remote})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--synced","data-testid":"nodes-stat-synced",children:[e.jsxs("span",{children:[e.jsx(ve,{size:14})," Synced"]}),e.jsx("strong",{children:I.synced})]})]}),p&&e.jsx("div",{className:"nodes-view-error",children:p}),e.jsxs("section",{className:"nodes-view-topology","aria-label":"Docker Nodes Summary",children:[e.jsx("h3",{className:"nodes-view-section-title",children:"Docker Nodes"}),e.jsxs("div",{className:"nodes-view-stat",children:[e.jsx("span",{children:"Managed Docker Nodes"}),e.jsx("strong",{children:h.length}),e.jsx("button",{className:"btn btn-sm",onClick:()=>y(!0),children:"Provision"})]})]}),!d&&t.length>0&&e.jsxs("section",{className:"nodes-view-topology","aria-label":"Mesh Topology",children:[e.jsx("h3",{className:"nodes-view-section-title",children:"Mesh Topology"}),e.jsx(fs,{nodes:t})]}),d?e.jsx("div",{className:"nodes-view-grid",children:Array.from({length:4}).map((v,S)=>e.jsx("div",{className:"node-card node-card--loading","aria-hidden":!0},S))}):t.length===0?e.jsxs("div",{className:"nodes-view-empty",children:[e.jsx("p",{children:"No nodes are registered yet."}),e.jsxs("button",{className:"btn btn-primary",onClick:()=>R(!0),children:[e.jsx(re,{size:14}),"Add First Node"]})]}):e.jsx("div",{className:"nodes-view-grid",children:t.map(v=>{const S=v.type==="remote"&&_[v.id]?he(_[v.id]):void 0;return e.jsx(ds,{node:v,projects:x,onHealthCheck:z=>{U(z)},onEdit:z=>b(z),onRemove:z=>{G(z)},isLoading:d,syncStatus:S,authSyncState:v.type==="remote"?n(v.id):void 0,authSyncProviders:v.type==="remote"?m(v.id):void 0},v.id)})}),e.jsx(xs,{isOpen:E,onClose:()=>R(!1),onSubmit:O,addToast:a}),e.jsx(ps,{isOpen:D,onClose:()=>y(!1),onSubmit:q,addToast:a}),e.jsx(vs,{isOpen:c!==null,onClose:()=>b(null),node:c,projects:x,onUpdate:B,onHealthCheck:U,addToast:a,syncStatus:c?.type==="remote"&&c&&_[c.id]?he(_[c.id]):void 0,onPushSettings:C,onPullSettings:k,onSyncAuth:M})]})}export{Ms as NodesView};
|