@runfusion/fusion 0.26.0 → 0.27.1
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 +12847 -2514
- package/dist/client/assets/AgentDetailView-B7QRcHJH.css +1 -0
- package/dist/client/assets/AgentDetailView-shgiiUb4.js +18 -0
- package/dist/client/assets/{AgentsView-CV3vm7Qk.css → AgentsView-B3ADnF0D.css} +1 -1
- package/dist/client/assets/{AgentsView-D6Zi5zfP.js → AgentsView-CpwqOVDz.js} +12 -7
- package/dist/client/assets/ChatView-DyRBOIKL.js +1 -0
- package/dist/client/assets/{DevServerView--_WBvIDQ.js → DevServerView-Cdelj9-m.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-xedtR-Rd.js → DirectoryPicker-C0kmRv0u.js} +1 -1
- package/dist/client/assets/{DocumentsView-Bg2oaZks.js → DocumentsView-B94U9ijs.js} +1 -1
- package/dist/client/assets/{EvalsView-B3uOCXfr.js → EvalsView-O_4YWy--.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-Bx6yXVS5.js → ExperimentalAgentOnboardingModal-CkEiF85-.js} +1 -1
- package/dist/client/assets/InsightsView-D-Qe0tRr.js +11 -0
- package/dist/client/assets/{MemoryView-xcN_eouf.js → MemoryView-CoRUmRvb.js} +2 -2
- package/dist/client/assets/NodesView-DQzXjcLc.js +14 -0
- package/dist/client/assets/{PiExtensionsManager-Cc8aAZXg.js → PiExtensionsManager-Dn1LmFbq.js} +2 -2
- package/dist/client/assets/PluginManager-Y0fs-6No.js +1 -0
- package/dist/client/assets/{ResearchView-CERNf7sJ.js → ResearchView-CjOxKhdS.js} +1 -1
- package/dist/client/assets/{SettingsModal-B1r0yASu.js → SettingsModal-Bg1-3JO_.js} +1 -1
- package/dist/client/assets/{SettingsModal-Cis-4Lot.css → SettingsModal-Ci0_sqbU.css} +1 -1
- package/dist/client/assets/SettingsModal-DL7tjJQa.js +31 -0
- package/dist/client/assets/SettingsModal-DWKgRxBA.css +1 -0
- package/dist/client/assets/{SetupWizardModal-D1q548_L.js → SetupWizardModal-DuzYPbuJ.js} +1 -1
- package/dist/client/assets/{SkillsView-ClLM6u6p.js → SkillsView-BIFoVNUf.js} +1 -1
- package/dist/client/assets/{StashRecoveryView-ze0pEZ5U.js → StashRecoveryView-C52KsV7f.js} +1 -1
- package/dist/client/assets/{TodoView-CTmIfy2M.js → TodoView-sS_mT0Y7.js} +2 -2
- package/dist/client/assets/{dashboard-view-CyWN-d02.js → dashboard-view-BWGH_fAq.js} +1 -1
- package/dist/client/assets/dashboard-view-BoTzlP8b.css +1 -0
- package/dist/client/assets/dashboard-view-MB-86hAu.js +21 -0
- package/dist/client/assets/{folder-open-BZuKESeq.js → folder-open-B9cwJ-OX.js} +1 -1
- package/dist/client/assets/index-BOjPRqEk.js +692 -0
- package/dist/client/assets/index-BmSEq8Rb.css +1 -0
- package/dist/client/assets/{star-D75YKEq-.js → star-BDn04UYV.js} +1 -1
- package/dist/client/assets/{upload-BYYTgWFj.js → upload-zdPPycKQ.js} +1 -1
- package/dist/client/assets/{users-RS90Aii3.js → users-CPYZjK2g.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/droid-cli/package.json +1 -1
- package/dist/droid-cli/src/__tests__/index.test.ts +228 -0
- package/dist/extension.js +7433 -1920
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/pi-claude-cli/src/__tests__/provider.test.ts +36 -22
- package/dist/pi-claude-cli/src/provider.ts +7 -1
- package/dist/plugins/fusion-plugin-cli-printing-press/manifest.json +19 -1
- package/dist/plugins/fusion-plugin-cli-printing-press/package.json +20 -2
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/TestRunnerPanel.test.tsx +99 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/config-flow.test.ts +91 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/dashboard-view.test.tsx +40 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/dashboard-views.test.ts +46 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/draft-store.test.ts +50 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/fixtures/exec-mock.ts +80 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/fixtures/fixtures.test.ts +40 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/fixtures/registry.ts +82 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/generator.test.ts +54 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/manage-view.test.tsx +98 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/manifest.test.ts +21 -5
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/registration.test.ts +29 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/run-routes.test.ts +98 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/runner.test.ts +55 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/runtime-availability.test.ts +61 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/validation.test.ts +30 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/wizard-routes.test.ts +61 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/workflow-integration.test.ts +19 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/dashboard-view.css +43 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/dashboard-view.tsx +49 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/generation/generator.ts +95 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/generation/redact.ts +9 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/generation/runner.ts +79 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/generation/types.ts +31 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/index.ts +46 -2
- package/dist/plugins/fusion-plugin-cli-printing-press/src/manage/EditDraftModal.tsx +75 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/manage/useDrafts.ts +73 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/manage-view.css +79 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/manage-view.tsx +122 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/routes/wizard-routes.ts +272 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/run/TestRunnerPanel.css +70 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/run/TestRunnerPanel.tsx +98 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/run/useRunGeneratedCli.ts +37 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/runtime/__tests__/executor-runtime-env.test.ts +191 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/runtime/executor-runtime-env.ts +75 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/storage/draft-store.ts +85 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/store/__tests__/cli-press-store.test.ts +128 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/store/__tests__/credentials.test.ts +62 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/store/cli-press-store.ts +427 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/store/cli-press-types.ts +110 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/store/credentials.ts +95 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/wizard/steps.tsx +55 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/wizard/types.ts +33 -0
- package/dist/plugins/fusion-plugin-cli-printing-press/src/wizard/validation.ts +63 -0
- package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
- package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-reports/manifest.json +10 -0
- package/dist/plugins/fusion-plugin-reports/package.json +18 -2
- package/dist/plugins/fusion-plugin-reports/src/__tests__/approval.test.ts +164 -0
- package/dist/plugins/fusion-plugin-reports/src/__tests__/manifest.test.ts +14 -0
- package/dist/plugins/fusion-plugin-reports/src/__tests__/routes-approval.test.ts +109 -0
- package/dist/plugins/fusion-plugin-reports/src/__tests__/scaffold.test.ts +60 -0
- package/dist/plugins/fusion-plugin-reports/src/__tests__/share-blocks.test.ts +83 -0
- package/dist/plugins/fusion-plugin-reports/src/aggregation.ts +23 -0
- package/dist/plugins/fusion-plugin-reports/src/approval.ts +97 -0
- package/dist/plugins/fusion-plugin-reports/src/cadence.ts +23 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/ReportsView.css +82 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/ReportsView.tsx +24 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/__tests__/ReportComparisonDrawer.test.tsx +12 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/__tests__/ReportDetailPanel.test.tsx +12 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/__tests__/ReportFiltersBar.test.tsx +14 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/__tests__/ReportsView.test.tsx +27 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/__tests__/api.test.ts +19 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/__tests__/useReportSectionDiff.test.ts +11 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/__tests__/useReports.test.ts +13 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/api.ts +85 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ReportApprovalPanel.css +59 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ReportApprovalPanel.tsx +58 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ReportComparisonDrawer.tsx +21 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ReportDetailPanel.tsx +29 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ReportEmptyState.tsx +3 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ReportFiltersBar.tsx +19 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ReportListItem.tsx +8 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ShareBlocksPanel.css +29 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/ShareBlocksPanel.tsx +43 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/__tests__/ReportApprovalPanel.test.tsx +38 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/components/__tests__/ShareBlocksPanel.test.tsx +24 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/test-setup.ts +18 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/types.ts +22 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/useReportPreview.ts +44 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/useReportSectionDiff.ts +59 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/useReports.ts +71 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard/useViewportMode.ts +13 -0
- package/dist/plugins/fusion-plugin-reports/src/dashboard-view.tsx +6 -0
- package/dist/plugins/fusion-plugin-reports/src/index.ts +48 -2
- package/dist/plugins/fusion-plugin-reports/src/pipeline.ts +58 -0
- package/dist/plugins/fusion-plugin-reports/src/render/__tests__/escape.test.ts +20 -0
- package/dist/plugins/fusion-plugin-reports/src/render/__tests__/html-template.test.ts +110 -0
- package/dist/plugins/fusion-plugin-reports/src/render/__tests__/standalone-html.test.ts +66 -0
- package/dist/plugins/fusion-plugin-reports/src/render/escape.ts +12 -0
- package/dist/plugins/fusion-plugin-reports/src/render/html-styles.ts +40 -0
- package/dist/plugins/fusion-plugin-reports/src/render/html-template.ts +137 -0
- package/dist/plugins/fusion-plugin-reports/src/render/index.ts +4 -0
- package/dist/plugins/fusion-plugin-reports/src/render/standalone-html.ts +75 -0
- package/dist/plugins/fusion-plugin-reports/src/report-schema.ts +31 -0
- package/dist/plugins/fusion-plugin-reports/src/routes/__tests__/report-export-routes.test.ts +104 -0
- package/dist/plugins/fusion-plugin-reports/src/routes/report-approval-routes.ts +98 -0
- package/dist/plugins/fusion-plugin-reports/src/routes/report-export-routes.ts +77 -0
- package/dist/plugins/fusion-plugin-reports/src/routes/report-list-routes.ts +72 -0
- package/dist/plugins/fusion-plugin-reports/src/runs-store.ts +69 -0
- package/dist/plugins/fusion-plugin-reports/src/share-blocks.ts +82 -0
- package/dist/plugins/fusion-plugin-reports/src/store/report-store.ts +51 -2
- package/dist/plugins/fusion-plugin-reports/src/store/report-types.ts +6 -1
- package/dist/plugins/fusion-plugin-roadmap/bundled.js +1528 -29391
- package/dist/plugins/fusion-plugin-roadmap/manifest.json +1 -1
- package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
- package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
- package/package.json +1 -1
- package/skill/fusion/SKILL.md +1 -1
- package/skill/fusion/references/engine-tools.md +2 -2
- package/skill/fusion/references/extension-tools.md +4 -3
- package/skill/fusion/references/fusion-capabilities.md +1 -1
- package/skill/fusion/workflows/task-management.md +3 -1
- package/dist/client/assets/AgentDetailView-BwJaLqZh.css +0 -1
- package/dist/client/assets/AgentDetailView-Cv-vgOj3.js +0 -18
- package/dist/client/assets/ChatView-CAHjY9uO.js +0 -1
- package/dist/client/assets/InsightsView-Q1zvtF4F.js +0 -11
- package/dist/client/assets/NodesView-RxXg58_Q.js +0 -14
- package/dist/client/assets/PluginManager-BEkyBajl.js +0 -1
- package/dist/client/assets/SettingsModal-BLsac7CJ.js +0 -31
- package/dist/client/assets/SettingsModal-BNSrO1M9.css +0 -1
- package/dist/client/assets/dashboard-view-4xAN3yO5.js +0 -21
- package/dist/client/assets/dashboard-view-BkTMSZYn.css +0 -1
- package/dist/client/assets/index-Bdw6llW6.js +0 -692
- package/dist/client/assets/index-CZGlyJuS.css +0 -1
- package/dist/plugins/fusion-plugin-roadmap/bundled.css +0 -1093
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as s,a as As,j as t}from"./vendor-react-K0fH_qHe.js";import{i as ot,b1 as Bt,t as ts,b2 as Es,b3 as Wt,b4 as Ts,w as At,b5 as Fe,b6 as Ds,b7 as Ps,b8 as $s,b9 as Is,ba as Ls,bb as Fs,s as ss,bc as zs,bd as _s,be as Us,bf as Os,bg as Hs,bh as Bs,bi as Ws,k as ns,bj as Gs,p as Vs,bk as Ks,bl as qs,u as Js,bm as Ys,ab as as,ac as rs,bn as Xs,bo as Qs,S as Zs,W as Nt,P as nt,I as Ze,am as en,bp as Gt,bq as Vt,br as Kt,B as rt,a8 as tn,a9 as sn,a as nn,bs as an,bt as rn,aQ as on,bu as cn,bv as qt,bw as ln,h as dn,j as Jt,m as un}from"./index-Bdw6llW6.js";import"./vendor-xterm-DzcZoU0P.js";const jt="kb-chat-active-session";function Yt(n){const r=typeof n=="string"?n.trim():"",u=r.indexOf("/");return!r||u<=0||u>=r.length-1?{}:{modelProvider:r.slice(0,u),modelId:r.slice(u+1)}}function mn(n){const r=n?.toolCalls;if(!Array.isArray(r))return;const u=r.map(o=>{if(!o||typeof o!="object")return null;const c=o,v=typeof c.toolName=="string"?c.toolName:"";if(!v)return null;const D=c.args;return{toolName:v,...D&&typeof D=="object"?{args:D}:{},isError:!!c.isError,result:c.result,status:"completed"}}).filter(o=>o!==null);return u.length>0?u:void 0}function hn(n){const r=n?.fallback;if(!r||typeof r!="object")return;const u=r,o=typeof u.primaryModel=="string"?u.primaryModel:"",c=typeof u.fallbackModel=="string"?u.fallbackModel:"",v=u.triggerPoint;if(!(!o||!c||v!=="session-creation"&&v!=="prompt-time"))return{primaryModel:o,fallbackModel:c,triggerPoint:v}}function Mt(n){return{id:n.id,sessionId:n.sessionId,role:n.role,content:n.content,thinkingOutput:n.thinkingOutput,toolCalls:mn(n.metadata),fallbackInfo:hn(n.metadata),attachments:n.attachments,createdAt:n.createdAt}}function fn(n,r){const[u,o]=s.useState([]),[c,v]=s.useState(null),[D,P]=s.useState(!0),[$,w]=s.useState([]),[Y,b]=s.useState(!1),[F,M]=s.useState(!1),[te,N]=s.useState(""),[R,g]=s.useState(""),[y,A]=s.useState([]),[I,T]=s.useState(""),[ae,X]=s.useState(""),[z,p]=s.useState(!0),[m,d]=s.useState(new Map),i=s.useRef(null),h=s.useRef(!1),j=s.useRef(""),_=s.useRef(null),Ae=s.useRef(u),q=s.useRef(c),se=s.useRef(F);Ae.current=u,q.current=c,se.current=F,s.useEffect(()=>{j.current=I},[I]);const Ne=s.useRef(new Set),Q=s.useRef(0),fe=s.useRef(n);fe.current!==n&&(fe.current=n,Q.current++),s.useEffect(()=>{const f=Q.current;ot(void 0,n).then(x=>{if(Q.current!==f)return;const S=new Map;for(const E of x)S.set(E.id,E);d(S)}).catch(()=>{})},[n]);const je=s.useCallback(async()=>{P(!0);try{const x=[...(await Bt(n)).sessions].sort((S,E)=>new Date(E.updatedAt).getTime()-new Date(S.updatedAt).getTime());o(x)}catch{}finally{P(!1)}},[n]);s.useEffect(()=>{je()},[je]);const Ee=s.useRef(()=>{}),Z=s.useRef(!1);s.useEffect(()=>{Z.current=!1},[n]),s.useEffect(()=>{if(D||Z.current||q.current)return;const f=ts(jt,n);if(!f){Z.current=!0;return}const x=u.find(S=>S.id===f);if(x){Z.current=!0,Ee.current(f,x);return}Z.current=!0},[D,u,n]);const C=s.useCallback(async(f,x)=>{b(!0);try{const S=await Es(f,{limit:50,...x},n),E=S.messages.map(Mt);x?.offset&&x.offset>0?w(ee=>[...E,...ee]):w(E),p(S.messages.length>=50)}catch{}finally{b(!1)}},[n]),oe=s.useCallback(()=>{_.current?.(),_.current=null,j.current="",T(""),N(""),g(""),A([]),M(!1)},[]),ge=s.useCallback(f=>{if(i.current||!f)return!0;h.current=!1,M(!0);const{handlers:x}=Wt({sessionId:f,tempUserMessageId:"",setStreamingText:N,setStreamingThinking:g,setStreamingToolCalls:A,cancelStreamingFlushesRef:_,addToast:r,onFallbackSession:(E,ee)=>{const V=Yt(E.fallbackModel);o(B=>B.map(O=>O.id===ee?{...O,...V}:O)),v(B=>B&&B.id===ee?{...B,...V}:B)},onDone:()=>{N(""),g(""),A([]),M(!1),se.current=!1,i.current=null,C(f)},onError:E=>{N(""),g(""),A([]),M(!1),se.current=!1,i.current=null;const ee=typeof E=="string"&&E.trim()?E:"Failed to get response";r?.(ee,"error"),C(f)}}),S=Ts(f,x,n);return i.current=S,!0},[r,C,n]),pe=s.useCallback((f,x)=>{const S=q.current?.id??null;if(f&&S===f&&!x)return;i.current&&(i.current.close(),i.current=null);const E=x??u.find(ee=>ee.id===f);v(E||null),oe(),p(!0),f?C(f):w([]),E?.isGenerating&&(N(""),ge(E.id)),f?At(jt,f,n):Fe(jt,n)},[ge,u,C,n,oe]);Ee.current=pe;const Ve=s.useCallback(async f=>{const x=await Ds(f,n);i.current&&(i.current.close(),i.current=null);const S={id:x.session.id,title:x.session.title,agentId:x.session.agentId,status:x.session.status,modelProvider:x.session.modelProvider,modelId:x.session.modelId,createdAt:x.session.createdAt,updatedAt:x.session.updatedAt};return o(E=>E.some(ee=>ee.id===S.id)?E:[S,...E]),oe(),pe(S.id,S),w([]),S},[n,oe,pe]),it=s.useCallback(async f=>{await Ps(f,{status:"archived"},n),o(x=>x.filter(S=>S.id!==f)),c?.id===f&&(v(null),w([]))},[c,n]),Ke=s.useCallback(async f=>{c?.id===f&&i.current&&(i.current.close(),i.current=null),await $s(f,n),o(x=>x.filter(S=>S.id!==f)),c?.id===f&&(v(null),w([]))},[c,n]),be=s.useCallback(async()=>{!c||!z||await C(c.id,{offset:$.length})},[c,z,C,$.length]),ve=s.useCallback(()=>{c&&(h.current=!0,_.current?.(),_.current=null,i.current?.close(),i.current=null,Is(c.id,n).catch(()=>{}),M(!1),N(""),g(""),A([]))},[c,n]),_e=s.useCallback(()=>{j.current="",T("")},[]),xe=s.useRef(()=>{}),we=Ls(),ye=s.useCallback((f,x)=>{if(!c)return;if(se.current){j.current=f,T(f),r?.("Still waiting for previous response — message queued","warning");return}h.current=!1,i.current&&(i.current.close(),i.current=null);const S=`temp-${Date.now()}`,E={id:S,sessionId:c.id,role:"user",content:f,createdAt:new Date().toISOString()};w(V=>[...V,E]),N(""),g(""),A([]),M(!0);const{handlers:ee}=Wt({sessionId:c.id,tempUserMessageId:S,setStreamingText:N,setStreamingThinking:g,setStreamingToolCalls:A,cancelStreamingFlushesRef:_,addToast:r,onFallbackSession:(V,B)=>{const O=Yt(V.fallbackModel);o(re=>re.map(L=>L.id===B?{...L,...O}:L)),v(re=>re&&re.id===B?{...re,...O}:re)},onDone:({messageId:V,message:B,accumulated:O})=>{const re=B?Mt(B):{id:V||`msg-${Date.now()}`,sessionId:c.id,role:"assistant",content:O.text,thinkingOutput:O.thinking,toolCalls:O.toolCalls.length>0?O.toolCalls:void 0,fallbackInfo:O.fallbackInfo,createdAt:new Date().toISOString()};Ne.current.add(re.id),w(H=>[...H,re]),N(""),g(""),A([]),M(!1),se.current=!1,i.current=null,setTimeout(()=>{Ne.current.delete(re.id)},1e3),je();const L=j.current.trim();L&&(j.current="",T(""),xe.current(L))},onError:(V,B)=>{w(L=>L.filter(H=>H.id!==B)),N(""),g(""),A([]),M(!1),se.current=!1,i.current=null,console.error("[useChat] Stream error:",V);const O=typeof V=="string"&&V.trim()?V:"Failed to get response";if(typeof V=="string"&&zs(V)&&(we.isHiddenNow()||we.wasRecentlyHidden(5e3))?(console.info("[useChat] Suppressed tab-suspension stream error:",V),c?.id&&C(c.id)):r?.(O,"error"),!h.current){const L=j.current.trim();L&&(j.current="",T(""),xe.current(L))}}});i.current=Fs(c.id,f,ee,x,n)},[c,n,je,r,C,we]);xe.current=ye;const Se=ae?u.filter(f=>f.title?.toLowerCase().includes(ae.toLowerCase())||f.agentId.toLowerCase().includes(ae.toLowerCase())):u;return s.useEffect(()=>{if(!q.current?.isGenerating||(i.current||ge(q.current.id),!se.current||i.current||!q.current))return;const f=setInterval(async()=>{if(!se.current||i.current||!q.current){clearInterval(f);return}try{(await Bt(n)).sessions.find(E=>E.id===q.current?.id)?.isGenerating||(clearInterval(f),await C(q.current.id),N(""),g(""),A([]),M(!1))}catch{}},3e3);return()=>clearInterval(f)},[ge,C,n,c]),s.useEffect(()=>{const f=Q.current,x=n?`?projectId=${encodeURIComponent(n)}`:"",S=()=>Q.current!==f,E=L=>{if(S())return;const H=JSON.parse(L.data);o(W=>W.some(J=>J.id===H.id)?W:[H,...W])},ee=L=>{if(S())return;const H=JSON.parse(L.data);o(W=>[...W.map(ie=>ie.id===H.id?H:ie)]),q.current?.id===H.id&&(v(H),H.isGenerating&&!i.current&&(N(""),ge(H.id)))},V=L=>{if(S())return;const{id:H}=JSON.parse(L.data);o(W=>W.filter(J=>J.id!==H)),q.current?.id===H&&(v(null),w([]))},B=L=>{if(S())return;const H=JSON.parse(L.data),W=Mt(H);if(!Ne.current.has(W.id)){if(q.current?.id===W.sessionId&&se.current&&!i.current&&W.role==="assistant"){w(J=>J.some(ie=>ie.id===W.id)?J:[...J,W]),N(""),g(""),A([]),M(!1);return}q.current?.id===W.sessionId&&!se.current&&w(J=>{if(J.some(ie=>ie.id===W.id))return J;if(W.role==="user"){const ie=J.findIndex(de=>de.role==="user"&&de.id.startsWith("temp-")&&de.content.trim()===W.content.trim());if(ie>=0){const de=[...J];return de[ie]=W,de}}return[...J,W]})}},O=L=>{if(S())return;const{id:H}=JSON.parse(L.data);w(W=>W.filter(J=>J.id!==H))};return ss(`/api/events${x}`,{events:{"chat:session:created":E,"chat:session:updated":ee,"chat:session:deleted":V,"chat:message:added":B,"chat:message:deleted":O}})},[ge,n]),s.useEffect(()=>()=>{i.current&&(i.current.close(),i.current=null)},[]),{sessions:u,activeSession:c,sessionsLoading:D,messages:$,messagesLoading:Y,isStreaming:F,streamingText:te,streamingThinking:R,streamingToolCalls:y,pendingMessage:I,selectSession:pe,createSession:Ve,archiveSession:it,deleteSession:Ke,sendMessage:ye,stopStreaming:ve,clearPendingMessage:_e,loadMoreMessages:be,hasMoreMessages:z,searchQuery:ae,setSearchQuery:X,filteredSessions:Se,refreshSessions:je,agentsMap:m}}const ke="fusion:chat-active-room";function Et(n){return[...n].sort((r,u)=>new Date(u.updatedAt).getTime()-new Date(r.updatedAt).getTime())}function et(n,r){const u=n.findIndex(c=>c.id===r.id);if(u===-1)return Et([r,...n]);const o=[...n];return o[u]=r,Et(o)}function Ce(n){try{return JSON.parse(n.data)}catch{return null}}function gn(n,r){const[u,o]=s.useState([]),[c,v]=s.useState(!0),[D,P]=s.useState(null),[$,w]=s.useState(null),[Y,b]=s.useState([]),[F,M]=s.useState([]),[te,N]=s.useState(!1),R=s.useRef(u),g=s.useRef($),y=s.useRef(0),A=s.useRef(n);R.current=u,g.current=$,A.current!==n&&(A.current=n,y.current+=1);const I=s.useCallback(async(m,d=!0)=>{if(!m){b([]),M([]),N(!1);return}d&&M([]),N(!0);try{const[i,h]=await Promise.all([_s(m.id,n),Us(m.id,{limit:100},n)]);b(i.members),M(h.messages)}catch{b([]),M([])}finally{N(!1)}},[n]),T=s.useCallback(async()=>{v(!0);try{const m=await Os({},n),d=Et(m.rooms);o(d),P(null);const i=ts(ke,n);if(i){const h=d.find(j=>j.id===i)??null;h?(w(h),I(h,!0)):Fe(ke,n)}}catch(m){const d=m instanceof Error?m.message:"Failed to load chat rooms";P(d),r?.(d,"error")}finally{v(!1)}},[r,I,n]),ae=s.useCallback(m=>{if(!m){w(null),Fe(ke,n),I(null,!0);return}const d=R.current.find(i=>i.id===m)??null;w(d),d&&(At(ke,d.id,n),I(d,!0))},[I,n]),X=s.useCallback(async m=>{const i=(await Hs({name:m.name,memberAgentIds:m.memberAgentIds},n)).room;return o(h=>et(h,i)),w(i),At(ke,i.id,n),await I(i,!0),i},[I,n]),z=s.useCallback(async m=>{await Bs(m,n),o(d=>d.filter(i=>i.id!==m)),g.current?.id===m&&(w(null),b([]),M([]),Fe(ke,n))},[n]),p=s.useCallback(async(m,d)=>{const i=g.current?.id;if(!i)throw new Error("Select a room before sending a message");await Ws(i,{content:m,...d?.attachments?{attachments:d.attachments}:{}},n)},[n]);return s.useEffect(()=>{T()},[T]),s.useEffect(()=>{const m=y.current,d=n?`/api/events?projectId=${encodeURIComponent(n)}`:"/api/events";return ss(d,{onReconnect:()=>{T()},events:{"chat:room:created":i=>{if(y.current!==m)return;const h=Ce(i);h&&o(j=>et(j,h))},"chat:room:updated":i=>{if(y.current!==m)return;const h=Ce(i);h&&(o(j=>et(j,h)),g.current?.id===h.id&&w(h))},"chat:room:deleted":i=>{if(y.current!==m)return;const h=Ce(i);h?.id&&(o(j=>j.filter(_=>_.id!==h.id)),g.current?.id===h.id&&(w(null),b([]),M([]),Fe(ke,n)))},"chat:room:member:added":i=>{if(y.current!==m)return;const h=Ce(i);!h||g.current?.id!==h.roomId||b(j=>j.some(_=>_.agentId===h.agentId)?j:[...j,h])},"chat:room:member:removed":i=>{if(y.current!==m)return;const h=Ce(i);!h||g.current?.id!==h.roomId||b(j=>j.filter(_=>_.agentId!==h.agentId))},"chat:room:message:added":i=>{if(y.current!==m)return;const h=Ce(i);h&&(o(j=>{const _=j.find(Ae=>Ae.id===h.roomId);return _?et(j,{..._,updatedAt:h.createdAt}):j}),g.current?.id===h.roomId&&M(j=>j.some(_=>_.id===h.id)?j:[...j,h]))},"chat:room:message:updated":i=>{if(y.current!==m)return;const h=Ce(i);!h||g.current?.id!==h.roomId||M(j=>j.map(_=>_.id===h.id?h:_))},"chat:room:message:deleted":i=>{if(y.current!==m)return;const h=Ce(i);h?.id&&M(j=>j.filter(_=>_.id!==h.id))}}})},[n,T]),s.useEffect(()=>{$&&(u.some(m=>m.id===$.id)||(w(null),b([]),M([]),Fe(ke,n)))},[$,n,u]),{rooms:u,roomsLoading:c,roomsError:D,activeRoom:$,activeRoomMembers:Y,messages:F,messagesLoading:te,selectRoom:ae,createRoom:X,deleteRoom:z,sendRoomMessage:p,refreshRooms:T}}function pn(n,r=[]){const u=n.trim().replace(/^#/,"");if(!u)return{ok:!1,error:"Room name is required."};if(/[A-Z]/.test(u))return{ok:!1,error:"Use lowercase letters only."};const o=u.toLowerCase();return o.length>80?{ok:!1,error:"Room names can be at most 80 characters."}:/^[a-z0-9_-]+$/.test(o)?/^[-_]|[-_]$/.test(o)?{ok:!1,error:"Room names cannot start or end with a hyphen or underscore."}:r.some(c=>c.toLowerCase()===o)?{ok:!1,error:"A room with this name already exists."}:{ok:!0,name:o}:{ok:!1,error:"Use lowercase letters, numbers, hyphens, or underscores only."}}function bn({isOpen:n,onClose:r,onCreate:u,projectId:o,existingRoomNames:c=[]}){const[v,D]=s.useState(""),[P,$]=s.useState([]),[w,Y]=s.useState(""),[b,F]=s.useState([]),[M,te]=s.useState(!1),[N,R]=s.useState(null),[g,y]=s.useState(!1),A=s.useRef(null),I=s.useRef(null);s.useEffect(()=>{n&&(I.current=document.activeElement instanceof HTMLElement?document.activeElement:null,te(!0),R(null),ot(void 0,o).then(d=>$(d)).catch(()=>{$([]),R("Failed to load agents.")}).finally(()=>te(!1)))},[n,o]),s.useEffect(()=>{if(!n){D(""),Y(""),F([]),R(null),y(!1);return}const d=window.requestAnimationFrame(()=>A.current?.focus());return()=>window.cancelAnimationFrame(d)},[n]),s.useEffect(()=>{if(!n)return;const d=i=>{i.key==="Escape"&&r()};return document.addEventListener("keydown",d),()=>document.removeEventListener("keydown",d)},[n,r]),s.useEffect(()=>{n||I.current?.focus()},[n]);const T=s.useMemo(()=>pn(v,c),[v,c]),ae=s.useMemo(()=>{const d=w.trim().toLowerCase();return d?P.filter(i=>i.name.toLowerCase().includes(d)):P},[P,w]),X=s.useMemo(()=>P.filter(d=>b.includes(d.id)),[P,b]),z=T.ok&&b.length>0&&!g&&!M;if(!n)return null;const p=d=>{g||F(i=>i.includes(d)?i.filter(h=>h!==d):[...i,d])},m=async()=>{if(!T.ok){R(T.error);return}if(b.length===0){R("Select at least one member.");return}R(null),y(!0);try{await u({name:T.name,displayName:`#${T.name}`,memberAgentIds:b}),r()}catch(d){R(d instanceof Error?d.message:"Failed to create room.")}finally{y(!1)}};return As.createPortal(t.jsx("div",{className:"modal-overlay open",onClick:d=>d.target===d.currentTarget&&r(),children:t.jsxs("div",{className:"modal modal-lg create-room-modal",role:"dialog","aria-modal":"true","aria-label":"Create room",onClick:d=>d.stopPropagation(),children:[t.jsxs("div",{className:"modal-header",children:[t.jsx("h3",{children:"Create room"}),t.jsx("button",{type:"button",className:"modal-close","aria-label":"Close",onClick:r,children:"×"})]}),t.jsxs("div",{className:"form-group create-room-modal-name-group",children:[t.jsx("label",{htmlFor:"create-room-name",children:"Room name"}),t.jsxs("div",{className:"create-room-modal-name-field",children:[t.jsx("span",{"aria-hidden":"true",className:"create-room-modal-name-hash",children:"#"}),t.jsx("input",{ref:A,id:"create-room-name",className:"input",value:v,disabled:g,onChange:d=>{const i=d.target.value.replace(/^#/,"").replace(/\s+/g,"-").toLowerCase();D(i)}})]}),!T.ok&&t.jsx("div",{className:"form-error",children:T.error})]}),t.jsxs("div",{className:"form-group",children:[t.jsx("label",{htmlFor:"create-room-member-search",children:"Members"}),t.jsx("input",{id:"create-room-member-search",className:"input",placeholder:"Search agents",value:w,disabled:g,onChange:d=>Y(d.target.value)})]}),X.length>0&&t.jsx("div",{className:"create-room-modal-selected","data-testid":"create-room-selected-chips",children:X.map(d=>t.jsxs("button",{type:"button",className:"btn btn-sm create-room-modal-chip",onClick:()=>p(d.id),disabled:g,children:[d.name," ×"]},d.id))}),t.jsx("div",{className:"create-room-modal-member-list","data-testid":"create-room-member-list",children:M?t.jsx("div",{className:"create-room-modal-empty",children:"Loading agents..."}):ae.length===0?t.jsx("div",{className:"create-room-modal-empty",children:P.length===0?"No agents in this project yet.":"No agents match your search."}):ae.map(d=>{const i=b.includes(d.id);return t.jsxs("button",{type:"button",className:`create-room-modal-member-row${i?" create-room-modal-member-row--selected":""}`,onClick:()=>p(d.id),disabled:g,children:[t.jsx(ns,{agent:d,size:20}),t.jsx("span",{children:d.name}),t.jsx("span",{className:"create-room-modal-member-role",children:d.role})]},d.id)})}),N&&t.jsx("div",{className:"form-group",children:t.jsx("div",{className:"form-error",children:N})}),t.jsxs("div",{className:"modal-actions",children:[t.jsx("button",{type:"button",className:"btn",onClick:r,disabled:g,children:"Cancel"}),t.jsx("button",{type:"button",className:"btn btn-primary",onClick:()=>void m(),disabled:!z,children:g?"Creating...":"Create room"})]})]})}),document.body)}function os(n){const r=new Date(n),o=new Date().getTime()-r.getTime(),c=Math.floor(o/1e3),v=Math.floor(c/60),D=Math.floor(v/60),P=Math.floor(D/24);return c<60?"just now":v<60?`${v}m ago`:D<24?`${D}h ago`:P<7?`${P}d ago`:r.toLocaleDateString()}function Xt(n,r){if(!n||!r)return null;const u=r.toLowerCase();if(u.includes("claude")){let c=r.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(u.includes("gpt")||u.includes("openai")){const c=r.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(u.includes("gemini")){const c=r.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=r.replace(/-/g," ").replace(/^\w/,c=>c.toUpperCase()).replace(/\s+/g," ").trim();return o.length>30?o.slice(0,30)+"…":o}function at(n,r){return n.length<=r?n:`${n.slice(0,r)}…`}function vn(n){if(!n)return null;const r=Object.entries(n);return r.length===0?null:r.map(([u,o])=>{const c=typeof o=="string"?o:(()=>{try{return JSON.stringify(o)}catch{return String(o)}})();return`${u}=${at(c,50)}`}).join(", ")}function xn(n){if(n===void 0)return null;if(typeof n=="string")return at(n,200);try{return at(JSON.stringify(n),200)}catch{return at(String(n),200)}}function is(n){if(!n||n.length===0)return null;const r=(b,F)=>{const M=b.status==="running",te=b.status==="completed"&&b.isError,N=vn(b.args),R=xn(b.result),g=M?N:R?`result: ${R}`:N?`args: ${N}`:null,y=M?"running":te?"error":"completed";return t.jsxs("details",{className:`chat-tool-call${M?" chat-tool-call--running":""}${te?" 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",title:b.toolName,children:b.toolName}),g&&t.jsx("span",{className:"chat-tool-call-preview",title:g,children:g}),t.jsx("span",{className:"chat-tool-call-status-text",children:y})]}),t.jsxs("div",{className:"chat-tool-call-content",children:[N&&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:N})]}),R&&t.jsxs("div",{className:`chat-tool-call-row${te?" 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:R})]})]})]},`${b.toolName}-${F}`)},u="chat-tool-calls";if(n.length===1)return t.jsxs("div",{className:u,"data-testid":"chat-tool-calls",children:[t.jsxs("div",{className:"chat-tool-calls-header",children:[t.jsx(qt,{size:12,"aria-hidden":"true"}),t.jsx("span",{children:"Tool calls"})]}),r(n[0],0)]});const o=n.filter(b=>b.status==="running").length,c=n.filter(b=>b.status==="completed"&&b.isError).length,v=o>0,D=Array.from(new Set(n.map(b=>b.toolName))),P=D.slice(0,5),$=Math.max(0,D.length-P.length),w=$>0?`${P.join(", ")}, +${$} more`:P.join(", "),Y=v?`(${o} running)`:c>0?`(${c} ${c===1?"error":"errors"})`:null;return t.jsx("div",{className:u,"data-testid":"chat-tool-calls",children:t.jsxs("details",{className:"chat-tool-calls-group","data-testid":"chat-tool-calls-group",open:v,children:[t.jsxs("summary",{className:"chat-tool-calls-group-summary",children:[t.jsx(qt,{size:12,"aria-hidden":"true"}),t.jsxs("span",{className:"chat-tool-calls-count",children:[n.length," tool calls"]}),t.jsx("span",{className:"chat-tool-calls-names",title:w,children:w}),Y&&t.jsx("span",{className:"chat-tool-calls-group-status",children:Y})]}),n.map((b,F)=>r(b,F))]})})}const cs={pre:({children:n,...r})=>t.jsx("pre",{...r,className:"chat-markdown-pre",children:n}),table:({children:n,...r})=>t.jsx("table",{...r,className:"chat-markdown-table",children:n})},ze="__fn_agent__",wn=280,tt=180,st=500,Qt="fusion:chat-sidebar-width",Zt="fusion:chat-scope",yn=["image/png","image/jpeg","image/gif","image/webp","text/plain","application/json","text/yaml","text/markdown","text/csv","application/xml","text/x-log"];function es(n){const r=/(^|[\s])\/([^\s]*)$/.exec(n);if(!r)return null;const u=r[1]??"",o=r[2]??"",c=r.index+u.length;return{filter:o,start:c,end:n.length}}function Sn(n,r){const u=n.slice(0,r),o=/(^|[\s\n])@([\w-]*)$/.exec(u);if(!o)return null;const c=o[2]??"",v=u.length-c.length-1;return{filter:c,start:v,end:r}}function kn({projectId:n,onClose:r,onCreate:u}){const[o,c]=s.useState("agent"),[v,D]=s.useState([]),[P,$]=s.useState(!0),[w,Y]=s.useState(""),[b,F]=s.useState([]),[M,te]=s.useState(!0),[N,R]=s.useState(""),[g,y]=s.useState([]),[A,I]=s.useState([]);s.useEffect(()=>{let p=!1;return $(!0),ot(void 0,n).then(m=>{p||D(m)}).catch(()=>{p||D([])}).finally(()=>{p||$(!1)}),()=>{p=!0}},[n]),s.useEffect(()=>{te(!0),dn().then(p=>{F(p.models),y(p.favoriteProviders),I(p.favoriteModels)}).catch(()=>{F([]),y([]),I([])}).finally(()=>{te(!1)})},[]);const T=s.useCallback(async p=>{const m=g,i=m.includes(p)?m.filter(h=>h!==p):[p,...m];y(i);try{await Jt({favoriteProviders:i,favoriteModels:A})}catch{y(m)}},[g,A]),ae=s.useCallback(async p=>{const m=A,i=m.includes(p)?m.filter(h=>h!==p):[p,...m];I(i);try{await Jt({favoriteProviders:g,favoriteModels:i})}catch{I(m)}},[A,g]),X=p=>{if(p.preventDefault(),o==="agent"){if(!w)return;u({agentId:w});return}if(!N)return;const m=N.indexOf("/");if(m<=0)return;const d=N.slice(0,m),i=N.slice(m+1);u({agentId:ze,modelProvider:d,modelId:i})},z=o==="agent"?!w:!N;return t.jsx("div",{className:"chat-new-dialog-backdrop chat-view-dialog-backdrop",onClick:r,role:"dialog","aria-modal":"true",children:t.jsxs("div",{className:"chat-new-dialog chat-view-dialog",onClick:p=>p.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"),R("")},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"),Y("")},children:"Model"})]}),t.jsxs("form",{onSubmit:X,children:[o==="agent"&&t.jsxs("label",{className:"chat-new-dialog-model-label",children:["Agent",P?t.jsx("div",{className:"chat-new-dialog-loading",children:"Loading agents..."}):v.length===0?t.jsx("div",{className:"chat-new-dialog-empty",children:"No agents available"}):t.jsx("div",{className:"chat-new-dialog-agent-list",children:v.map(p=>t.jsxs("button",{type:"button",className:`chat-new-dialog-agent-item${w===p.id?" chat-new-dialog-agent-item--selected":""}`,onClick:()=>Y(p.id),"data-testid":`agent-option-${p.id}`,children:[t.jsx(rt,{size:16}),t.jsx("span",{className:"chat-new-dialog-agent-name",children:p.name}),t.jsx("span",{className:"chat-new-dialog-agent-role",children:p.role})]},p.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(un,{models:b,value:N,onChange:R,label:"Model",placeholder:"Select a model",favoriteProviders:g,onToggleFavorite:T,favoriteModels:A,onToggleModelFavorite:ae})}),t.jsxs("div",{className:"chat-new-dialog-actions",children:[t.jsx("button",{type:"button",className:"btn btn-sm",onClick:r,children:"Cancel"}),t.jsx("button",{type:"submit",className:"btn btn-sm btn-primary",disabled:z,children:"Create"})]})]})]})})}const Rt=s.memo(function({message:r,forcePlain:u,agentName:o,hideAssistantIdentity:c,showAssistantModelTag:v,activeModelTag:D,activeModelProvider:P,activeSessionId:$,mentionAgentsByName:w,roomContext:Y,copyAction:b}){const F=r.role==="assistant",M=s.useMemo(()=>{if(F)return null;const R=r.content,g=/@([\w-]+)/g,y=[];let A=0,I=g.exec(R);for(;I;){const[T,ae=""]=I,X=I.index;X>A&&y.push(R.slice(A,X));const z=ae.replace(/_/g," ").toLowerCase(),p=w.get(z);if(p){const m=!!(Y&&!Y.memberIds.has(p.id)),d=m?`Not a member of ${Y?.roomName}`:void 0;y.push(t.jsxs("span",{className:`chat-mention-chip${m?" chat-mention-chip--non-member":""}`,title:d,"aria-label":d,children:["@",p.name.replace(/\s+/g,"_")]},`${p.id}-${X}`))}else y.push(T);A=X+T.length,I=g.exec(R)}return A<R.length&&y.push(R.slice(A)),y.length===0?R:y},[F,r.content,w,Y]),te=s.useMemo(()=>{const R=r.attachments;if(!R||R.length===0||!$)return null;const g=`/api/chat/sessions/${encodeURIComponent($)}/attachments/`;return t.jsx("div",{className:"chat-message-attachments",children:R.map(y=>{const A=y.mimeType.startsWith("image/"),I=y.id||y.filename,T=`${g}${encodeURIComponent(y.filename)}`;return A?t.jsx("a",{className:"chat-message-attachment-link","data-testid":"chat-message-attachment",href:T,target:"_blank",rel:"noopener noreferrer",children:t.jsx("img",{className:"chat-message-attachment",src:T,alt:y.originalName})},I):t.jsxs("a",{className:"chat-message-attachment-file","data-testid":"chat-message-attachment",href:T,target:"_blank",rel:"noopener noreferrer",children:[t.jsx(cn,{size:14}),t.jsx("span",{children:y.originalName})]},I)})})},[r.attachments,$]),N=s.useMemo(()=>F?u?t.jsx("div",{className:"chat-message-content chat-message-content--plain",children:r.content}):t.jsx("div",{className:"chat-message-content chat-message-content--markdown",children:t.jsx(as,{remarkPlugins:[rs],components:cs,children:r.content})}):null,[F,u,r.content]);return t.jsxs("div",{className:`chat-message chat-message--${r.role}`,"data-testid":`chat-message-${r.id}`,children:[F&&!c&&t.jsxs("div",{className:"chat-message-avatar",children:[P?t.jsx(nt,{provider:P,size:"sm"}):t.jsx(rt,{size:14}),t.jsx("span",{children:o}),v&&D&&t.jsx("span",{className:"chat-model-tag",children:D})]}),F?N:t.jsx("div",{className:"chat-message-content",children:M}),b,is(r.toolCalls),r.thinkingOutput&&t.jsxs("details",{className:"chat-message-thinking",children:[t.jsx("summary",{children:"Thinking"}),t.jsx("pre",{className:"chat-message-thinking-content",children:r.thinkingOutput})]}),te,t.jsx("div",{className:"chat-message-time",children:os(r.createdAt)})]})});function Rn({projectId:n,addToast:r,experimentalFeatures:u}){const{activeSession:o,sessionsLoading:c,messages:v,messagesLoading:D,isStreaming:P,streamingText:$,streamingThinking:w,streamingToolCalls:Y,selectSession:b,createSession:F,archiveSession:M,deleteSession:te,sendMessage:N,stopStreaming:R,pendingMessage:g,clearPendingMessage:y,searchQuery:A,setSearchQuery:I,filteredSessions:T}=fn(n,r),[ae,X]=s.useState(!1),[z,p]=s.useState(""),[m,d]=s.useState(null),[i,h]=s.useState(null),[j,_]=s.useState(null),[Ae,q]=s.useState(!0),[se,Ne]=s.useState(wn),[Q,fe]=s.useState("direct"),[je,Ee]=s.useState(!1),Z=u?.chatRooms===!0,C=gn(n,r),[oe,ge]=s.useState(new Map),[pe,Ve]=s.useState([]),[it,Ke]=s.useState(!0),[be,ve]=s.useState(!1),[_e,xe]=s.useState(""),[we,ye]=s.useState(0),[Se,f]=s.useState(""),[x,S]=s.useState(!1),[E,ee]=s.useState(0),[V,B]=s.useState(-1),[O,re]=s.useState(!1),[L,H]=s.useState([]),[W,J]=s.useState(!1),[ie,de]=s.useState(!1),[Te,Tt]=s.useState({}),[,Ue]=s.useState(!1),[ls,ds]=s.useState({top:0,left:0}),U=Gs({projectId:n}),ct=s.useCallback(e=>{if(!e||!U.mentionActive)return;const a=e.getBoundingClientRect();ds({top:a.top-260,left:a.left+8})},[U.mentionActive]),Dt=s.useRef(null),lt=s.useRef(!1),dt=s.useRef(null),ue=s.useRef(null),De=s.useRef(null),ne=s.useRef(null),Pt=s.useRef(null),$t=s.useRef([]),Oe=s.useRef(0),He=s.useRef(new Map),K=Vs()==="mobile";s.useEffect(()=>{try{const e=localStorage.getItem(Qt);if(!e)return;const a=Number.parseInt(e,10);if(Number.isNaN(a))return;const l=Math.max(tt,Math.min(st,a));Ne(l)}catch{}},[]),s.useEffect(()=>{try{const e=localStorage.getItem(Zt);if(e==="direct"){fe("direct");return}e==="rooms"&&Z&&fe("rooms")}catch{}},[Z]),s.useEffect(()=>{if(!Z&&Q==="rooms"){fe("direct");return}try{localStorage.setItem(Zt,Q)}catch{}},[Z,Q]);const{keyboardOverlap:qe,viewportHeight:It,viewportOffsetTop:Lt,keyboardOpen:Be}=Ks({enabled:K&&!!o}),Ft=qe>0||Lt>0,us=Be&&Ft?{"--keyboard-overlap":`${qe}px`,"--vv-offset-top":`${Lt}px`,...It!==null?{"--vv-height":`${It}px`}:{}}:{},ce=s.useMemo(()=>{const e=_e.trim().toLowerCase();return(e?pe.filter(l=>l.name.toLowerCase().includes(e)):pe).slice(0,10)},[pe,_e]),Pe=s.useMemo(()=>Array.from(oe.values()),[oe]),me=s.useMemo(()=>!Z||Q!=="rooms"||!C.activeRoom?null:{roomId:C.activeRoom.id,roomName:C.activeRoom.name,memberIds:new Set(C.activeRoomMembers.map(e=>e.agentId))},[Z,Q,C.activeRoom,C.activeRoomMembers]),Me=s.useMemo(()=>{const e=Pe.filter(k=>qs(k.name,Se));if(!me)return e;const a=e.filter(k=>me.memberIds.has(k.id));if(Se.trim().length===0)return a;const l=e.filter(k=>!me.memberIds.has(k.id));return[...a,...l]},[Pe,Se,me]),ut=s.useMemo(()=>{const e=new Map;for(const a of Pe)e.set(a.name.toLowerCase(),a);return e},[Pe]);s.useEffect(()=>{ye(0)},[ce]),s.useEffect(()=>{ee(0)},[Se,x]),s.useEffect(()=>()=>{ue.current!==null&&window.clearTimeout(ue.current)},[]);const zt=s.useCallback(()=>{const e=De.current;if(!e)return;const l=e.scrollTop+e.clientHeight>=e.scrollHeight-50;de(!l),lt.current=!l},[]),Je=s.useCallback(e=>{if(!e.isConnected)return;let a=0,l=0,k=-1;const G=6,le=()=>{if(e.isConnected){if(e.scrollTop=e.scrollHeight,e.scrollHeight===k?l+=1:(l=0,k=e.scrollHeight),a+=1,a>=G||l>=2){de(!1),lt.current=!1;return}window.requestAnimationFrame(le)}};le()},[]),We=s.useCallback(()=>{const e=De.current;e&&Je(e)},[Je]);s.useLayoutEffect(()=>{const e=o?.id??null;if(!e){dt.current=null;return}const a={sessionId:e,loaded:!D,hasMessages:v.length>0},l=dt.current,k=l?.sessionId!==e,G=l?.sessionId===e&&!l.loaded&&a.loaded,le=l?.sessionId===e&&!l.hasMessages&&a.hasMessages;if(!(l===null||k||G||le))return;const he=De.current;he&&(Je(he),dt.current=a)},[o?.id,v.length,D,Je]),s.useEffect(()=>{lt.current||We()},[v,$,w,P,We]),s.useEffect(()=>{qe<=0||!De.current||We()},[qe,We]),Js(K&&Be),s.useEffect(()=>{const e=()=>d(null);if(m)return document.addEventListener("click",e),()=>document.removeEventListener("click",e)},[m]),s.useEffect(()=>{if(!K||!Be)return;const e=a=>{a.target?.closest(".chat-messages")||a.preventDefault()};return document.addEventListener("touchmove",e,{passive:!1}),()=>{document.removeEventListener("touchmove",e)}},[K,Be]),s.useEffect(()=>{if(!K||!o)return;const e=()=>{const a=ne.current;a&&document.activeElement===a&&(a.blur(),window.setTimeout(()=>{a.focus({preventScroll:!0})},0))};return document.addEventListener("visibilitychange",e),window.addEventListener("pageshow",e),()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pageshow",e)}},[K,o]),s.useEffect(()=>{let e=!1;const a=n;return ot(void 0,n).then(l=>{if(e||a!==n)return;const k=new Map;for(const G of l)k.set(G.id,G);ge(k)}).catch(()=>{}),()=>{e=!0}},[n]),s.useEffect(()=>{let e=!1;return Ke(!0),Ys(n).then(a=>{e||Ve(a)}).catch(()=>{e||Ve([])}).finally(()=>{e||Ke(!1)}),()=>{e=!0}},[n]),s.useEffect(()=>{$t.current=L},[L]),s.useEffect(()=>()=>{for(const e of $t.current)e.previewUrl&&URL.revokeObjectURL(e.previewUrl);for(const e of He.current.values())window.clearTimeout(e);He.current.clear()},[]);const Ye=s.useCallback(e=>{if(!e||e.length===0)return;const a=[];for(const l of Array.from(e)){if(!yn.includes(l.type))continue;const k=l.type.startsWith("image/");a.push({file:l,previewUrl:k?URL.createObjectURL(l):""})}a.length>0&&H(l=>[...l,...a])},[]),ms=s.useCallback(e=>{H(a=>{const l=a[e];return l?.previewUrl&&URL.revokeObjectURL(l.previewUrl),a.filter((k,G)=>G!==e)})},[]),hs=s.useCallback(e=>{const a=e.clipboardData?.files;if(!a||a.length===0)return;const l=Array.from(a).filter(k=>k.type.startsWith("image/"));l.length!==0&&Ye(l)},[Ye]),fs=s.useCallback(async e=>{try{await F(e),X(!1),K&&q(!1)}catch{r("Failed to create chat session","error")}},[F,r,K]),mt=s.useCallback(()=>{p(""),ve(!1),xe(""),S(!1),f(""),B(-1),H(e=>{for(const a of e)a.previewUrl&&URL.revokeObjectURL(a.previewUrl);return[]})},[]),ht=s.useCallback(()=>{const e=z.trim(),a=L.map(l=>l.file);if(!(!e&&a.length===0||!o)){if(e==="/clear"){mt(),R(),y(),F({agentId:o.agentId,modelProvider:o.modelProvider??void 0,modelId:o.modelId??void 0}).catch(()=>{r("Failed to clear conversation","error")});return}mt(),N(e,a)}},[z,L,o,mt,R,y,F,r,N]),ft=s.useCallback(async()=>{const e=z.trim();if(e){if(Z&&Q==="rooms"){if(!C.activeRoom)return;await C.sendRoomMessage(e),p("");return}ht()}},[z,Z,Q,C,ht]),gt=s.useCallback(e=>{p(a=>{const l=es(a);if(!l)return a;const k=`/skill:${e.name} `,G=a.slice(0,l.start)+k+a.slice(l.end);return window.requestAnimationFrame(()=>{ne.current&&(ne.current.style.height="auto",ne.current.style.height=`${Math.min(ne.current.scrollHeight,120)}px`,ne.current.focus())}),G}),ve(!1),xe(""),ye(0)},[]),Xe=s.useCallback(e=>{const a=ne.current;if(!a||V<0)return;const l=a.selectionStart??Oe.current,k=a.selectionEnd??l,G=Math.max(l,k),le=Math.min(V,G),he=`${`@${e.name.replace(/\s+/g,"_")}`} `,Ct=z.slice(0,le)+he+z.slice(G),Le=le+he.length;p(Ct),S(!1),f(""),ee(0),B(-1),window.requestAnimationFrame(()=>{ne.current&&(ne.current.style.height="auto",ne.current.style.height=`${Math.min(ne.current.scrollHeight,120)}px`,ne.current.focus(),ne.current.setSelectionRange(Le,Le))})},[V,z]),_t=s.useCallback(e=>{if(Oe.current=e.currentTarget.selectionStart??Oe.current,U.mentionActive&&U.files.length>0){if(U.handleKeyDown(e,z),e.key==="Enter"||e.key==="Tab"){const a=U.files[U.selectedIndex];if(a){const l=U.selectFile(a,z);p(l),U.dismissMention(),Ue(!1)}}return}if(x&&e.key==="ArrowDown"){e.preventDefault(),Me.length>0&&ee(a=>(a+1)%Me.length);return}if(x&&e.key==="ArrowUp"){e.preventDefault(),Me.length>0&&ee(a=>a===0?Me.length-1:a-1);return}if(x&&e.key==="Enter"){e.preventDefault();const a=Me[E]??Me[0];a&&Xe(a);return}if(x&&e.key==="Escape"){e.preventDefault(),S(!1),f(""),B(-1);return}if(be&&e.key==="ArrowDown"){e.preventDefault(),ce.length>0&&ye(a=>(a+1)%ce.length);return}if(be&&e.key==="ArrowUp"){e.preventDefault(),ce.length>0&&ye(a=>a===0?ce.length-1:a-1);return}if(be&&(e.key==="Enter"||e.key==="Tab")&&ce.length>0){e.preventDefault();const a=ce[we]??ce[0];a&>(a);return}if(be&&e.key==="Escape"){e.preventDefault(),ve(!1);return}e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),ft())},[x,Me,E,Xe,be,ce,we,gt,ft,U,z]),Qe=s.useCallback((e,a)=>{const l=Sn(e,a);if(l){S(!0),f(l.filter),B(l.start);return}S(!1),f(""),B(-1)},[]),Ut=s.useCallback(e=>{const a=e.target,l=a.value,k=a.selectionStart??l.length;Oe.current=k,p(l);const G=es(l);G?(ve(!0),xe(G.filter)):(ve(!1),xe("")),Qe(l,k),U.detectMention(l,k),Ue(U.mentionActive),U.mentionActive&&ct(a),a.style.height="auto",a.style.height=`${Math.min(a.scrollHeight,120)}px`},[Qe]),pt=s.useCallback(e=>{const a=e.currentTarget,l=a.selectionStart??a.value.length;Oe.current=l,Qe(a.value,l),U.detectMention(a.value,l),Ue(U.mentionActive),U.mentionActive&&ct(a)},[Qe,U,ct]),gs=s.useCallback(e=>{e.key!=="Escape"&&pt(e)},[pt]),ps=s.useCallback(()=>{ue.current!==null&&window.clearTimeout(ue.current),ue.current=window.setTimeout(()=>{ve(!1),S(!1),f(""),B(-1),Ue(!1),U.dismissMention(),ue.current=null},120)},[U]),bs=s.useCallback(()=>{ue.current!==null&&(window.clearTimeout(ue.current),ue.current=null),typeof window<"u"&&window.innerWidth<=768&&window.setTimeout(()=>{(window.scrollY!==0||window.scrollX!==0)&&window.scrollTo(0,0)},0)},[]),vs=s.useCallback(async e=>{d(null);try{await M(e),r("Conversation archived","success")}catch{r("Failed to archive conversation","error")}},[M,r]),xs=s.useCallback(async e=>{h(null),d(null);try{await te(e),r("Conversation deleted","success")}catch{r("Failed to delete conversation","error")}},[te,r]),Ge=s.useCallback(e=>{try{localStorage.setItem(Qt,String(e))}catch{}},[]),ws=s.useCallback(e=>{if(K)return;e.preventDefault(),e.stopPropagation();const a=e.currentTarget;typeof a.setPointerCapture=="function"&&a.setPointerCapture(e.pointerId);const l=e.clientX,k=se;let G=k;document.body.style.userSelect="none";const le=he=>{const Ct=he.clientX-l,Le=Math.max(tt,Math.min(st,k+Ct));G=Le,Ne(Le),Ge(Le)},Ie=he=>{typeof a.releasePointerCapture=="function"&&a.releasePointerCapture(he.pointerId),document.body.style.userSelect="",document.removeEventListener("pointermove",le),document.removeEventListener("pointerup",Ie),Ge(G)};document.addEventListener("pointermove",le),document.addEventListener("pointerup",Ie)},[K,Ge,se]),ys=s.useCallback(e=>{if(K||e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;e.preventDefault();const a=e.shiftKey?50:10,l=e.key==="ArrowLeft"?-a:a,k=Math.max(tt,Math.min(st,se+l));Ne(k),Ge(k)},[K,Ge,se]),Ss=s.useCallback(e=>{b(e),K&&q(!1)},[b,K]),ks=s.useCallback(()=>{b(""),q(!0)},[b]),Cs=()=>t.jsxs("div",{className:"chat-empty-state",children:[t.jsx(ln,{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(Ze,{size:16}),"New Chat"]})]}),Re=Xt(o?.modelProvider,o?.modelId),$e=o?.modelProvider??null,bt=!!(o||P||v.length>0),Ot=o?.agentId===ze?Re??"Fusion":o?.title||oe.get(o?.agentId??"")?.name||o?.agentId||"Chat",Ns=!!(Re&&Re!==Ot),vt=oe.get(o?.agentId??"")?.name||(o?.agentId===ze?Re??"Fusion":o?.agentId?.slice(0,30)??"Fusion"),xt=!1,wt=o?.agentId===ze,js=g.length>50?`${g.slice(0,50)}…`:g,Ms=s.useCallback(()=>{re(e=>!e)},[]),yt=s.useCallback((e,a)=>{const l=He.current.get(e);l&&window.clearTimeout(l),Tt(G=>({...G,[e]:a}));const k=window.setTimeout(()=>{Tt(G=>{const{[e]:le,...Ie}=G;return Ie}),He.current.delete(e)},2e3);He.current.set(e,k)},[]),Ht=s.useCallback(async(e,a)=>{try{if(!navigator.clipboard?.writeText)throw new Error("Clipboard API unavailable");await navigator.clipboard.writeText(a),yt(e,"success")}catch{yt(e,"error")}},[yt]),Rs=s.useCallback((e,a=!1)=>a?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(as,{remarkPlugins:[rs],components:cs,children:e})}),[]),St=o?.agentId===ze,kt=s.useCallback((e,a,l)=>t.jsx("button",{type:"button",className:`btn-icon chat-message-copy-action${Te[e]==="success"?" chat-message-copy-action--success":""}${Te[e]==="error"?" chat-message-copy-action--error":""}`,"data-testid":l??`chat-copy-response-${e}`,"aria-label":Te[e]==="success"?"Response copied":Te[e]==="error"?"Copy failed":"Copy response",onClick:()=>{Ht(e,a)},children:Te[e]==="success"?t.jsx(Xs,{size:14}):t.jsx(Qs,{size:14})}),[Te,Ht]);return t.jsxs("div",{className:"chat-view",children:[t.jsxs("div",{className:`chat-sidebar${Ae?"":" chat-sidebar--hidden"}`,style:K?void 0:{width:`${se}px`},children:[Z&&t.jsxs("div",{className:"chat-sidebar-scope-toggle",role:"tablist","data-testid":"chat-sidebar-scope-toggle",children:[t.jsx("button",{type:"button",role:"tab",className:`chat-sidebar-scope-btn${Q==="direct"?" chat-sidebar-scope-btn--active":""}`,"aria-selected":Q==="direct","data-testid":"chat-sidebar-scope-direct",onClick:()=>fe("direct"),children:"Direct"}),t.jsx("button",{type:"button",role:"tab",className:`chat-sidebar-scope-btn${Q==="rooms"?" chat-sidebar-scope-btn--active":""}`,"aria-selected":Q==="rooms","data-testid":"chat-sidebar-scope-rooms",onClick:()=>fe("rooms"),children:"Rooms"})]}),!Z||Q==="direct"?t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"chat-sidebar-search-container",children:t.jsxs("div",{className:"chat-sidebar-search-wrapper",children:[t.jsx(Zs,{size:14,className:"chat-sidebar-search-icon"}),t.jsx("input",{type:"text",className:"chat-sidebar-search",placeholder:"Search conversations...",value:A,onChange:e=>I(e.target.value),"data-testid":"chat-search-input"})]})}),t.jsx("div",{className:"chat-session-list chat-sidebar-list",children:c?t.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"Loading..."}):T.length===0?t.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"No conversations yet"}):T.map(e=>t.jsxs("div",{className:`chat-session-item${o?.id===e.id?" chat-session-item--active":""}`,onClick:()=>Ss(e.id),onContextMenu:a=>{a.preventDefault(),d({sessionId:e.id,x:a.clientX,y:a.clientY})},"data-testid":`chat-session-${e.id}`,children:[t.jsx("button",{className:"chat-session-delete-btn",onClick:a=>{a.stopPropagation(),h(e.id)},"data-testid":"chat-session-delete-btn","aria-label":"Delete conversation",children:t.jsx(Nt,{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.jsxs("span",{className:"chat-session-meta-model",children:[e.modelProvider&&t.jsx(nt,{provider:e.modelProvider,size:"sm"}),t.jsx("span",{children:oe.get(e.agentId)?.name||(e.agentId===ze?Xt(e.modelProvider,e.modelId)??"Fusion":e.agentId.slice(0,30))})]}),t.jsx("span",{children:e.updatedAt?os(e.updatedAt):""})]})]},e.id))})]}):t.jsxs("div",{className:"chat-sidebar-rooms","data-testid":"chat-sidebar-rooms",children:[t.jsx("div",{className:"chat-sidebar-rooms-header",children:t.jsxs("button",{type:"button",className:"btn btn-sm btn-primary","data-testid":"chat-create-room-btn",onClick:()=>Ee(!0),children:[t.jsx(Ze,{size:14}),"Create room"]})}),C.rooms.length===0?t.jsx("div",{className:"chat-sidebar-rooms-empty","data-testid":"chat-sidebar-rooms-empty",children:"No rooms yet."}):t.jsx("div",{className:"chat-session-list chat-sidebar-list",children:C.rooms.map(e=>{const a=C.activeRoom?.id===e.id,l=a?C.activeRoomMembers.length:"—";return t.jsxs("div",{role:"button",tabIndex:0,className:`chat-room-item${a?" chat-room-item--active":""}`,"data-testid":`chat-room-item-${e.slug}`,onClick:()=>{C.selectRoom(e.id),K&&q(!1)},onKeyDown:k=>{(k.key==="Enter"||k.key===" ")&&(k.preventDefault(),C.selectRoom(e.id),K&&q(!1))},children:[t.jsxs("span",{className:"chat-room-item-details",children:[t.jsxs("span",{className:"chat-room-item-name",children:["#",e.name]}),t.jsxs("span",{className:"chat-room-item-meta",children:[l," ",l===1?"member":"members"]})]}),t.jsx("button",{type:"button",className:"btn-icon chat-room-item-delete","data-testid":`chat-room-delete-${e.slug}`,"aria-label":`Delete room ${e.name}`,onClick:k=>{k.stopPropagation(),_(e.id)},children:t.jsx(Nt,{size:14})})]},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(Ze,{size:14}),"New Chat"]})})]}),!K&&Ae&&t.jsx("div",{className:"chat-sidebar-resize-handle",role:"separator","aria-orientation":"vertical","aria-valuemin":tt,"aria-valuemax":st,"aria-valuenow":se,"aria-label":"Resize chat sidebar",tabIndex:0,onPointerDown:ws,onKeyDown:ys}),m&&t.jsxs("div",{className:"chat-session-context-menu",style:{top:m.y,left:m.x},onClick:e=>e.stopPropagation(),children:[t.jsxs("button",{onClick:()=>vs(m.sessionId),"data-testid":"chat-context-archive",children:[t.jsx(en,{size:14}),"Archive"]}),t.jsxs("button",{onClick:()=>{d(null),h(m.sessionId)},"data-testid":"chat-context-delete",children:[t.jsx(Nt,{size:14}),"Delete"]})]}),i&&t.jsx("div",{className:"chat-new-dialog-backdrop chat-view-dialog-backdrop",onClick:()=>h(null),children:t.jsxs("div",{className:"chat-new-dialog chat-view-dialog",onClick:e=>e.stopPropagation(),children:[t.jsx("h3",{children:"Delete Conversation?"}),t.jsx("p",{className:"chat-view-delete-dialog-copy",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:()=>h(null),children:"Cancel"}),t.jsx("button",{className:"btn btn-sm btn-danger",onClick:()=>void xs(i),children:"Delete"})]})]})}),Z&&j&&t.jsx("div",{className:"chat-new-dialog-backdrop chat-view-dialog-backdrop",onClick:()=>_(null),children:t.jsxs("div",{className:"chat-new-dialog chat-view-dialog",onClick:e=>e.stopPropagation(),children:[t.jsx("h3",{children:"Delete Room?"}),t.jsx("p",{className:"chat-view-delete-dialog-copy",children:"This action cannot be undone. This room and all its messages will be permanently deleted."}),t.jsxs("div",{className:"chat-new-dialog-actions",children:[t.jsx("button",{className:"btn btn-sm",onClick:()=>_(null),children:"Cancel"}),t.jsx("button",{className:"btn btn-sm btn-danger",onClick:()=>{(async()=>{try{await C.deleteRoom(j),_(null)}catch{r("Failed to delete room","error")}})()},children:"Delete"})]})]})}),Z&&Q==="rooms"?t.jsxs("div",{className:"chat-thread",children:[C.activeRoom?t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"chat-room-thread-header",children:[K&&t.jsx("button",{className:"btn-icon",onClick:()=>{C.selectRoom(null),q(!0)},"data-testid":"chat-back-btn",children:t.jsx(Gt,{size:16})}),t.jsxs("div",{className:"chat-thread-header-title",children:["#",C.activeRoom.name]}),t.jsx("div",{className:"chat-room-thread-members",children:C.activeRoomMembers.map(e=>t.jsx(ns,{agent:oe.get(e.agentId)??{id:e.agentId,name:e.agentId.slice(0,30)}},e.agentId))})]}),t.jsxs("div",{className:"chat-messages",ref:De,onScroll:zt,children:[C.messagesLoading?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"Loading messages..."}):C.messages.length===0?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"No messages yet. Start the conversation!"}):C.messages.map(e=>{const a=e.senderAgentId?oe.get(e.senderAgentId)?.name??e.senderAgentId.slice(0,30):"You",l={id:e.id,sessionId:e.roomId,role:e.role,content:e.content,thinkingOutput:e.thinkingOutput??void 0,toolCalls:void 0,fallbackInfo:void 0,attachments:e.attachments,createdAt:e.createdAt};return t.jsx(Rt,{message:l,forcePlain:O,agentName:a,hideAssistantIdentity:!1,showAssistantModelTag:!1,activeModelTag:null,activeModelProvider:null,activeSessionId:C.activeRoom?.id??null,mentionAgentsByName:ut,roomContext:me},e.id)}),t.jsx("div",{ref:Dt})]})]}):t.jsx("div",{className:"chat-room-empty-pane","data-testid":"chat-rooms-empty-pane",children:"Select a room or create one"}),C.activeRoom&&t.jsx("div",{className:"chat-input-area",children:t.jsxs("div",{className:"chat-input-row",children:[t.jsxs("div",{className:"chat-input-wrapper",children:[t.jsx("textarea",{ref:ne,className:"chat-input-textarea",placeholder:"Type a message...",value:z,onChange:Ut,onKeyDown:_t,rows:1,"data-testid":"chat-input"}),t.jsx(Vt,{agents:Pe,filter:Se,highlightedIndex:E,visible:x,onSelect:Xe,position:"below",roomMemberIds:me?.memberIds,roomName:me?.roomName})]}),t.jsx("button",{type:"button",className:"chat-input-send",onClick:()=>{ft()},disabled:!z.trim(),"data-testid":"chat-send-btn",style:{touchAction:"manipulation"},children:t.jsx(Kt,{size:16})})]})})]}):t.jsxs("div",{className:`chat-thread${Be&&Ft?" chat-thread--keyboard-active":""}`,style:us,children:[(bt||!K)&&t.jsxs("div",{className:"chat-thread-header",children:[K&&bt&&t.jsx("button",{className:"btn-icon",onClick:ks,"data-testid":"chat-back-btn",children:t.jsx(Gt,{size:16})}),t.jsxs("div",{className:"chat-thread-header-identity","data-testid":"chat-thread-header-identity",children:[$e?t.jsx(nt,{provider:$e,size:"md"}):t.jsx(rt,{size:16}),t.jsx("span",{className:"chat-thread-header-title",children:Ot}),Ns&&t.jsx("span",{className:"chat-model-tag",children:Re})]}),bt&&t.jsx("button",{type:"button",className:`chat-thread-header-render-toggle${O?" chat-thread-header-render-toggle--plain":""}`,"data-testid":"chat-thread-render-toggle","aria-label":O?"Show all messages as rendered Markdown":"Show all messages as plain text",onClick:Ms,children:O?t.jsx(tn,{size:14}):t.jsx(sn,{size:14})}),!K&&t.jsxs("button",{className:"btn btn-sm btn-primary chat-thread-header-new-chat",onClick:()=>X(!0),"data-testid":"chat-thread-new-chat-btn",children:[t.jsx(Ze,{size:14}),"New Chat"]})]}),t.jsxs("div",{className:"chat-messages",ref:De,onScroll:zt,children:[P?t.jsxs(t.Fragment,{children:[v.map(e=>t.jsx(Rt,{message:e,forcePlain:O,agentName:vt,hideAssistantIdentity:wt,showAssistantModelTag:xt,activeModelTag:Re,activeModelProvider:$e,activeSessionId:o?.id??null,mentionAgentsByName:ut,roomContext:null,copyAction:St&&e.role==="assistant"?kt(e.id,e.content):void 0},e.id)),t.jsxs("div",{className:"chat-message chat-message--assistant chat-message--streaming",children:[!wt&&t.jsxs("div",{className:"chat-message-avatar",children:[$e?t.jsx(nt,{provider:$e,size:"sm"}):t.jsx(rt,{size:14}),t.jsx("span",{children:vt}),xt]}),$?Rs($,O):t.jsx("div",{className:"chat-message-content chat-message-content--waiting",children:w?"Thinking…":"Connecting…"}),St&&$&&kt("__streaming__",$,"chat-copy-response-streaming"),is(Y),w&&t.jsxs("details",{className:"chat-message-thinking",children:[t.jsx("summary",{children:"Thinking"}),t.jsx("pre",{className:"chat-message-thinking-content",children:w})]}),t.jsxs("div",{className:"chat-typing-indicator",children:[t.jsx("span",{}),t.jsx("span",{}),t.jsx("span",{})]})]})]}):D?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"Loading messages..."}):v.length===0&&!o?Cs():v.length===0&&o?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"No messages yet. Start the conversation!"}):t.jsx(t.Fragment,{children:v.map(e=>t.jsx(Rt,{message:e,forcePlain:O,agentName:vt,hideAssistantIdentity:wt,showAssistantModelTag:xt,activeModelTag:Re,activeModelProvider:$e,activeSessionId:o?.id??null,mentionAgentsByName:ut,roomContext:null,copyAction:St&&e.role==="assistant"?kt(e.id,e.content):void 0},e.id))}),t.jsx("div",{ref:Dt})]}),ie&&t.jsxs("button",{type:"button",className:"btn btn-sm chat-jump-to-latest","data-testid":"chat-jump-to-latest",onClick:We,children:[t.jsx(nn,{size:14}),"Latest"]}),o&&t.jsxs("div",{className:"chat-input-area",children:[t.jsx("input",{ref:Pt,type:"file",accept:"image/*,.txt,.json,.yaml,.yml,.log,.csv,.xml,.md",multiple:!0,style:{display:"none"},onChange:e=>{Ye(e.target.files),e.target.value=""}}),be&&t.jsx("div",{className:"chat-skill-menu","data-testid":"chat-skill-menu",role:"listbox","aria-label":"Skill suggestions",children:it?t.jsx("div",{className:"chat-skill-menu-empty",children:"Loading skills…"}):ce.length===0?t.jsx("div",{className:"chat-skill-menu-empty",children:_e?"No skills found":"No skills available"}):ce.map((e,a)=>t.jsxs("button",{type:"button",role:"option","aria-selected":a===we,className:`chat-skill-menu-item${a===we?" chat-skill-menu-item--highlighted":""}`,onMouseDown:l=>l.preventDefault(),onMouseEnter:()=>ye(a),onClick:()=>gt(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))}),L.length>0&&t.jsx("div",{className:"chat-attachment-previews","data-testid":"chat-attachment-previews",children:L.map((e,a)=>t.jsxs("div",{className:"chat-attachment-preview","data-testid":`chat-attachment-preview-${a}`,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:()=>ms(a),"data-testid":`chat-attachment-remove-${a}`,"aria-label":`Remove ${e.file.name}`,children:"×"})]},e.previewUrl||`${e.file.name}-${a}`))}),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:()=>Pt.current?.click(),children:t.jsx(an,{size:16})}),t.jsxs("div",{className:`chat-input-wrapper${W?" chat-input-wrapper--dragover":""}`,onDragOver:e=>{e.preventDefault(),J(!0)},onDragLeave:()=>J(!1),onDrop:e=>{e.preventDefault(),J(!1),Ye(e.dataTransfer.files)},children:[t.jsx("textarea",{ref:ne,className:"chat-input-textarea",placeholder:"Type a message...",value:z,onChange:Ut,onKeyDown:_t,onKeyUp:gs,onClick:pt,onBlur:ps,onFocus:bs,onPaste:hs,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(Vt,{agents:Pe,filter:Se,highlightedIndex:E,visible:x,onSelect:Xe,position:"below",roomMemberIds:me?.memberIds,roomName:me?.roomName}),t.jsx(rn,{visible:U.mentionActive&&!x,position:ls,files:U.files,selectedIndex:U.selectedIndex,onSelect:e=>{const a=U.selectFile(e,z);p(a),U.dismissMention(),Ue(!1),ne.current?.focus()},loading:U.loading}),g&&t.jsxs("div",{className:"chat-pending-message","data-testid":"chat-pending-indicator",children:[t.jsx("span",{children:`Queued: ${js}`}),t.jsx("button",{type:"button",className:"chat-pending-message-dismiss","aria-label":"Dismiss queued message","data-testid":"chat-pending-dismiss",onClick:y,children:"×"})]})]}),P?t.jsx("button",{className:"chat-input-stop",onClick:R,"aria-label":"Stop generation","data-testid":"chat-stop-btn",children:t.jsx(on,{size:14})}):t.jsx("button",{type:"button",className:"chat-input-send",onPointerDown:e=>{e.pointerType&&e.pointerType!=="mouse"&&e.preventDefault()},onMouseDown:e=>{e.preventDefault()},onClick:()=>{ht()},disabled:!z.trim()&&L.length===0,"data-testid":"chat-send-btn",style:{touchAction:"manipulation"},children:t.jsx(Kt,{size:16})})]})]})]}),Z&&t.jsx(bn,{isOpen:je,onClose:()=>Ee(!1),projectId:n,existingRoomNames:C.rooms.map(e=>e.name),onCreate:async e=>{await C.createRoom({name:e.name,memberAgentIds:e.memberAgentIds}),Ee(!1)}}),ae&&t.jsx(kn,{projectId:n,onClose:()=>X(!1),onCreate:fs})]})}export{Rn as ChatView};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import{r,j as e}from"./vendor-react-K0fH_qHe.js";import{c as xe,ae as Re,af as De,ag as Pe,ah as Le,ai as Ue,aj as he,ak as Ge,h as Te,j as de,al as w,X as ue,am as ie,R as j,an as _e,m as Oe,C as pe,ao as X,ap as ge,aq as qe,I as ye,ar as Be,as as be,at as He}from"./index-Bdw6llW6.js";import{U as me}from"./users-RS90Aii3.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 10h.01",key:"1nrarc"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M12 6h.01",key:"1vi96p"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M16 6h.01",key:"1x0f13"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M8 6h.01",key:"1dz90k"}],["path",{d:"M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3",key:"cabbwy"}],["rect",{x:"4",y:"2",width:"16",height:"20",rx:"2",key:"1uxh74"}]],Qe=xe("building",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 Ve=[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"m19 9-5 5-4-4-3 3",key:"2osh9i"}]],We=xe("chart-line",Ve),te=["architecture","quality","workflow","performance","reliability","security","ux","testability","documentation","dependency","features","competitive_analysis","research","trends","other"],ve={quality:"Quality",performance:"Performance",architecture:"Architecture",security:"Security",reliability:"Reliability",ux:"User Experience",testability:"Testability",documentation:"Documentation",dependency:"Dependencies",workflow:"Workflow",other:"Other",features:"Features",competitive_analysis:"Competitive Analysis",research:"Research",trends:"Trends"};function Xe(g){const[l,p]=r.useState([]),[S,$]=r.useState(()=>te.map(i=>({category:i,label:ve[i]??i,items:[],isLoading:!1,error:null}))),[L,C]=r.useState(!0),[U,v]=r.useState(null),[R,D]=r.useState(null),[G,P]=r.useState(!1),[T,N]=r.useState(null),[_,M]=r.useState(new Map),[J,F]=r.useState(new Map),[O,I]=r.useState(new Map),[q,A]=r.useState(new Map),[E,B]=r.useState(!1),x=r.useCallback(async()=>{C(!0),v(null);try{const i=await Re({status:void 0,limit:1e3},g);p(i.insights.filter(s=>s.status!=="dismissed"));const t=await De(g);t.runs.length>0&&D(t.runs[0])}catch(i){const t=i instanceof Error?i.message:"Failed to fetch insights";v(t)}finally{C(!1)}},[g]),d=r.useCallback(()=>{B(i=>!i)},[]),k=r.useCallback(async(i,t)=>{P(!0),N(null);try{const s=await Pe("manual",void 0,g,i,t);D(s),s.status==="completed"?await x():s.status==="failed"&&s.error&&N(s.error)}catch(s){const h=s instanceof Error?s.message:"Failed to generate insights";throw N(h),s}finally{P(!1)}},[g,x]),u=r.useCallback(async i=>{M(t=>{const s=new Map(t);return s.set(i,{running:!0,error:null}),s});try{await Le(i,g),p(t=>t.filter(s=>s.id!==i)),M(t=>{const s=new Map(t);return s.set(i,{running:!1,error:null}),s})}catch(t){const s=t instanceof Error?t.message:"Failed to dismiss insight";throw M(h=>{const m=new Map(h);return m.set(i,{running:!1,error:s}),m}),t}},[g]),H=r.useCallback(async i=>{F(t=>{const s=new Map(t);return s.set(i,{running:!0,error:null}),s});try{const t=await Ue(i,g);return await he(i,g),p(s=>s.map(h=>h.id===i?{...h,status:"archived",updatedAt:new Date().toISOString()}:h)),F(s=>{const h=new Map(s);return h.set(i,{running:!1,error:null}),h}),{title:t.suggestedTitle,description:t.suggestedDescription}}catch(t){const s=t instanceof Error?t.message:"Failed to create task";throw F(h=>{const m=new Map(h);return m.set(i,{running:!1,error:s}),m}),t}},[g]);r.useEffect(()=>{const i=new Map;for(const t of te)i.set(t,[]);for(const t of l){if(!E&&t.status==="archived")continue;const s=i.get(t.category)??[];i.set(t.category,[...s,t])}$(te.map(t=>({category:t,label:ve[t]??t,items:i.get(t)??[],isLoading:!1,error:null})))},[l,E]);const K=r.useCallback(async i=>{I(t=>{const s=new Map(t);return s.set(i,{running:!0,error:null}),s});try{await he(i,g),p(t=>t.map(s=>s.id===i?{...s,status:"archived",updatedAt:new Date().toISOString()}:s)),I(t=>{const s=new Map(t);return s.set(i,{running:!1,error:null}),s})}catch(t){const s=t instanceof Error?t.message:"Failed to archive insight";throw I(h=>{const m=new Map(h);return m.set(i,{running:!1,error:s}),m}),t}},[g]),f=r.useCallback(async i=>{A(t=>{const s=new Map(t);return s.set(i,{running:!0,error:null}),s});try{await Ge(i,g),p(t=>t.map(s=>s.id===i?{...s,status:"confirmed",updatedAt:new Date().toISOString()}:s)),A(t=>{const s=new Map(t);return s.set(i,{running:!1,error:null}),s})}catch(t){const s=t instanceof Error?t.message:"Failed to unarchive insight";throw A(h=>{const m=new Map(h);return m.set(i,{running:!1,error:s}),m}),t}},[g]),Y=r.useMemo(()=>S.reduce((i,t)=>i+t.items.length,0),[S]),Z=r.useMemo(()=>0,[]),ee=r.useMemo(()=>l.filter(i=>i.status==="archived").length,[l]);return r.useEffect(()=>{x()},[x]),{sections:S,loading:L,error:U,latestRun:R,isRunInFlight:G,runError:T,refresh:x,runInsights:k,dismiss:u,createTask:H,archive:K,unarchive:f,toggleShowArchived:d,dismissStates:_,createTaskStates:J,archiveStates:O,unarchiveStates:q,totalCount:Y,dismissedCount:Z,archivedCount:ee,showArchived:E}}const fe={architecture:Qe,quality:pe,workflow:be,performance:ge,reliability:j,security:X,ux:me,testability:ie,documentation:Be,dependency:ye,features:qe,competitive_analysis:me,research:We,trends:ge,other:w};function ss({projectId:g,addToast:l,onClose:p,onCreateTask:S,models:$}){const{sections:L,loading:C,error:U,latestRun:v,isRunInFlight:R,runError:D,refresh:G,runInsights:P,dismiss:T,createTask:N,archive:_=async()=>{},unarchive:M=async()=>{},toggleShowArchived:J=()=>{},dismissStates:F,createTaskStates:O,archiveStates:I=new Map,unarchiveStates:q=new Map,totalCount:A,archivedCount:E=0,showArchived:B=!1}=Xe(g),[x,d]=r.useState(null),[k,u]=r.useState("info"),[H,K]=r.useState(!1),[f,Y]=r.useState(()=>localStorage.getItem("fusion-insight-model")??""),[Z,ee]=r.useState([]),[i,t]=r.useState([]),[s,h]=r.useState([]),[m,we]=r.useState();r.useEffect(()=>{$||Te().then(n=>{ee(n.models),t(n.favoriteProviders),h(n.favoriteModels),we(n.resolvedPlanningProvider);const a=localStorage.getItem("fusion-insight-model");a&&(n.models.some(o=>`${o.provider}/${o.id}`===a)||(localStorage.removeItem("fusion-insight-model"),Y("")))}).catch(()=>{})},[$]);const je=$??Z,Se=r.useMemo(()=>i.length>0?i:m?[m]:[],[i,m]),ke=r.useCallback(async n=>{const c=i.includes(n)?i.filter(o=>o!==n):[n,...i];t(c);try{await de({favoriteProviders:c,favoriteModels:s})}catch{t(i)}},[i,s]),Ce=r.useCallback(async n=>{const c=s.includes(n)?s.filter(o=>o!==n):[n,...s];h(c);try{await de({favoriteProviders:i,favoriteModels:c})}catch{h(s)}},[s,i]),Ne=r.useCallback(n=>{Y(n),n?localStorage.setItem("fusion-insight-model",n):localStorage.removeItem("fusion-insight-model")},[]),y=r.useMemo(()=>L.filter(n=>n.items.length>0),[L]),[z,se]=r.useState(null);r.useEffect(()=>{if(y.length===0){z!==null&&se(null);return}z&&y.some(a=>a.category===z)||se(y[0].category)},[y,z]);const b=r.useMemo(()=>y.find(n=>n.category===z)??y[0],[y,z]);r.useEffect(()=>{if(x){const n=setTimeout(()=>d(null),5e3);return()=>clearTimeout(n)}},[x]);const ae=r.useCallback(async()=>{try{d("Generating insights..."),u("info");let n,a;if(f){const c=f.indexOf("/");if(c!==-1){const o=f.slice(0,c),Q=f.slice(c+1);o&&Q&&(n=o,a=Q)}}await P(n,a),d("Insight generation started"),u("success"),l("Insight generation started","success")}catch(n){const a=n instanceof Error?n.message:"Failed to start generation";d(a),u("error"),l(a,"error")}},[P,l,f]),Me=r.useCallback(async(n,a)=>{try{d(`Dismissing "${a}"...`),u("info"),await T(n),d(`Dismissed "${a}"`),u("success"),l(`Insight dismissed: ${a}`,"success")}catch(c){const o=c instanceof Error?c.message:"Failed to dismiss insight";d(o),u("error"),l(o,"error")}},[T,l]),Fe=r.useCallback(async(n,a)=>{try{d(`Archiving "${a}"...`),u("info"),await _(n),d(`Archived "${a}"`),u("success"),l(`Insight archived: ${a}`,"success")}catch(c){const o=c instanceof Error?c.message:"Failed to archive insight";d(o),u("error"),l(o,"error")}},[_,l]),Ie=r.useCallback(async(n,a)=>{try{d(`Unarchiving "${a}"...`),u("info"),await M(n),d(`Unarchived "${a}"`),u("success"),l(`Insight unarchived: ${a}`,"success")}catch(c){const o=c instanceof Error?c.message:"Failed to unarchive insight";d(o),u("error"),l(o,"error")}},[M,l]),Ae=r.useCallback(async(n,a)=>{try{if(d(`Creating task from "${a}"...`),u("info"),!S)throw new Error("Task creation is unavailable in this view");const c=await N(n);if(!c)throw new Error("Failed to prepare task payload from insight");await S({insightId:n,title:c.title,description:c.description}),d(`Task created from "${a}"`),u("success"),l(`Task created: ${c.title}`,"success")}catch(c){const o=c instanceof Error?c.message:"Failed to create task";d(o),u("error"),l(o,"error")}},[N,S,l]),Ee=n=>{const a=fe[n.category]??w,c=b?.category===n.category;return e.jsx("li",{children:e.jsxs("button",{type:"button",className:`insights-category-item${c?" insights-category-item--active":""}`,onClick:()=>se(n.category),"aria-current":c?"true":void 0,"data-testid":`insights-category-${n.category}`,children:[e.jsx(a,{size:16,className:"insights-category-icon"}),e.jsx("span",{className:"insights-category-label",children:n.label}),e.jsx("span",{className:"insights-category-count",children:n.items.length})]})},n.category)},ze=()=>{if(!b)return null;const n=fe[b.category]??w;return e.jsxs("section",{className:"insights-section","data-testid":`insights-section-${b.category}`,children:[e.jsx("div",{className:"insights-section-header",children:e.jsxs("div",{className:"insights-section-title",children:[e.jsx(n,{size:20,className:"insights-section-icon"}),e.jsx("h3",{children:b.label}),e.jsx("span",{className:"insights-section-count",children:b.items.length})]})}),e.jsx("div",{className:"insights-section-content",children:e.jsx("ul",{className:"insights-list",children:b.items.map(a=>{const c=F.get(a.id),o=O.get(a.id),Q=I.get(a.id),$e=q.get(a.id),ne=c?.running??!1,re=o?.running??!1,ce=Q?.running??!1,oe=$e?.running??!1,le=a.status==="archived",V=b.items.some(W=>F.get(W.id)?.running||O.get(W.id)?.running||I.get(W.id)?.running||q.get(W.id)?.running);return e.jsxs("li",{className:`insight-item${le?" insight-item--archived":""}`,"data-insight-id":a.id,children:[e.jsxs("div",{className:"insight-item-header",children:[e.jsx("h4",{className:"insight-item-title",children:a.title}),e.jsxs("div",{className:"insight-item-actions",children:[le?e.jsx("button",{className:"insight-item-action-btn",onClick:()=>void Ie(a.id,a.title),disabled:oe||V,title:"Unarchive this insight","aria-label":"Unarchive this insight","data-testid":`unarchive-${a.id}`,children:oe?e.jsx(j,{size:20,className:"spin"}):e.jsx(He,{size:20})}):e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"insight-item-action-btn",onClick:()=>void Ae(a.id,a.title),disabled:re||V,title:"Create task from this insight","aria-label":"Create task from this insight","data-testid":`create-task-${a.id}`,children:re?e.jsx(j,{size:20,className:"spin"}):e.jsx(ye,{size:20})}),e.jsx("button",{className:"insight-item-action-btn",onClick:()=>void Fe(a.id,a.title),disabled:ce||V,title:"Archive this insight","aria-label":"Archive this insight","data-testid":`archive-${a.id}`,children:ce?e.jsx(j,{size:20,className:"spin"}):e.jsx(ie,{size:20})})]}),e.jsx("button",{className:"insight-item-action-btn",onClick:()=>void Me(a.id,a.title),disabled:ne||V,title:"Dismiss this insight","aria-label":"Dismiss this insight","data-testid":`dismiss-${a.id}`,children:ne?e.jsx(j,{size:20,className:"spin"}):e.jsx(ue,{size:20})})]})]}),a.content&&e.jsx("p",{className:"insight-item-content",children:a.content}),e.jsxs("div",{className:"insight-item-meta",children:[e.jsx("span",{className:`insight-item-status insight-item-status--${a.status}`,children:a.status}),a.createdAt&&e.jsxs("span",{className:"insight-item-date",children:[e.jsx(be,{size:12}),new Date(a.createdAt).toLocaleDateString()]})]})]},a.id)})})})]})};return e.jsxs("div",{className:"insights-view","data-testid":"insights-view",children:[e.jsxs("div",{className:"insights-view-header",children:[e.jsxs("div",{className:"insights-view-title",children:[e.jsxs("h2",{children:[e.jsx(w,{size:20}),"Insights"]}),e.jsxs("span",{className:"insights-view-count",children:[A," total"]})]}),e.jsxs("div",{className:"insights-view-actions",children:[p&&e.jsx("button",{className:"btn btn-sm insights-view-close",onClick:p,"aria-label":"Close insights view",title:"Close",children:e.jsx(ue,{size:16})}),E>0&&e.jsxs("button",{className:"btn btn-sm insights-show-archived-toggle",onClick:J,"aria-label":B?"Hide archived insights":"Show archived insights","data-testid":"toggle-archived-insights",children:[e.jsx(ie,{size:14}),B?"Hide Archived":`Show Archived (${E})`]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void G(),disabled:C,"aria-label":"Refresh insights","data-testid":"refresh-insights",children:[e.jsx(j,{size:14,className:C?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-sm insights-model-toggle",onClick:()=>K(n=>!n),"aria-label":"Configure insight generation model","aria-expanded":H,"data-testid":"toggle-model-config",title:f?`Model: ${f}`:"Configure model",children:[e.jsx(_e,{size:14}),f&&e.jsx("span",{className:"insights-model-indicator"})]}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>void ae(),disabled:R,"aria-label":"Generate new insights","data-testid":"run-insights",children:R?e.jsxs(e.Fragment,{children:[e.jsx(j,{size:14,className:"spin"}),"Generating..."]}):e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14}),"Generate Insights"]})})]})]}),H&&e.jsxs("div",{className:"insights-model-config","data-testid":"model-config",children:[e.jsx("label",{htmlFor:"insight-model-select",className:"insights-model-label",children:"Model"}),e.jsx(Oe,{models:je,value:f,onChange:Ne,placeholder:"Use planning default",label:"Insight generation model",disabled:R,id:"insight-model-select",favoriteProviders:Se,favoriteModels:s,onToggleFavorite:ke,onToggleModelFavorite:Ce})]}),e.jsx("div",{className:"insights-status-region","aria-live":"polite","data-testid":"insights-status",children:x&&e.jsxs("div",{className:`insights-status-message insights-status-message--${k}`,role:k==="error"?"alert":void 0,children:[k==="success"&&e.jsx(pe,{size:16}),k==="error"&&e.jsx(X,{size:16}),k==="info"&&e.jsx(w,{size:16}),e.jsx("span",{children:x})]})}),D&&e.jsxs("div",{className:"insights-error-callout",role:"alert","data-testid":"run-error",children:[e.jsx(X,{size:16}),e.jsx("span",{children:D})]}),v&&e.jsx("div",{className:"insights-run-info","data-testid":"latest-run",children:e.jsxs("span",{className:"insights-run-status",children:["Latest run: ",v.status,v.status==="completed"&&e.jsxs(e.Fragment,{children:[" — ",v.insightsCreated," created, ",v.insightsUpdated," updated"]}),v.status==="failed"&&v.error&&e.jsxs(e.Fragment,{children:[" — ",v.error]})]})}),C?e.jsxs("div",{className:"insights-loading","data-testid":"insights-loading",children:[e.jsx(j,{size:24,className:"spin"}),e.jsx("p",{children:"Loading insights..."})]}):U?e.jsxs("div",{className:"insights-error","data-testid":"insights-error",children:[e.jsx(X,{size:24}),e.jsx("p",{children:U}),e.jsx("button",{className:"btn btn-sm",onClick:()=>void G(),children:"Retry"})]}):A===0?e.jsxs("div",{className:"insights-empty","data-testid":"insights-empty",children:[e.jsx(w,{size:48}),e.jsx("h3",{children:"No insights yet"}),e.jsx("p",{children:"Generate insights to get AI-powered recommendations for your project."}),e.jsxs("button",{className:"btn btn-primary",onClick:()=>void ae(),children:[e.jsx(w,{size:14}),"Generate First Insights"]})]}):e.jsxs("div",{className:"insights-body",children:[e.jsx("aside",{className:"insights-sidebar","aria-label":"Insight categories",children:e.jsx("ul",{className:"insights-category-list",children:y.map(Ee)})}),e.jsx("div",{className:"insights-detail",children:ze()})]})]})}export{ss as InsightsView};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{c as Ie,aI as ls,aJ as os,aK as cs,aL as is,aM as ve,aN as Ke,aO as ye,aP as Ve,A as Oe,an as ds,U as Fe,aQ as Ue,aR as us,W as _e,u as ms,R as Ne,a as we,I as he,aS as Be,aT as hs,aU as fs,aV as Le,X as me,a8 as gs,a9 as xs,aW as $e,F as ps,aX as De,aY as js,aZ as bs,a_ as vs,a$ as ys,b0 as _s,G as Ns}from"./index-Bdw6llW6.js";import{v as ks}from"./projectDetection-G3XuxD2X.js";import{U as Te}from"./upload-BYYTgWFj.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 Cs=[["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"}]],Ss=Ie("wifi-off",Cs);/**
|
|
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 ws=[["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"}]],Ms=Ie("wifi",ws);function pe(t){const{lastSyncAt:l,remoteReachable:a,diff:d}=t,m=d.global.length+d.project.length;return l===null?{syncState:"never-synced",lastSyncAt:l,diffCount:0}:a?m>0?{syncState:"diff",lastSyncAt:l,diffCount:m}:{syncState:"synced",lastSyncAt:l,diffCount:0}:{syncState:"error",lastSyncAt:l,diffCount:m}}function ke(t){if(t===null)return"Never synced";const l=new Date(t);if(Number.isNaN(l.getTime()))return"Never synced";const d=Date.now()-l.getTime(),m=Math.floor(d/1e3),f=Math.floor(m/60),o=Math.floor(f/60),p=Math.floor(o/24);return f<1?"Synced just now":f<60?`Synced ${f}m ago`:o<24?`Synced ${o}h ago`:`Synced ${p}d ago`}function Ps(t){switch(t){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 Es=3e4;function Rs(){const[t,l]=s.useState({}),[a,d]=s.useState(!1),[m,f]=s.useState({}),[o,p]=s.useState(null),c=s.useRef(new Set),b=s.useRef(!1),N=s.useRef(null),R=s.useRef(null),_=s.useCallback(async(x,g)=>{try{const C=await ls(x);l(G=>({...G,[x]:C})),p(null)}catch(C){console.error(`Failed to fetch sync status for node ${x}:`,C),p(C instanceof Error?C.message:"Failed to fetch sync status")}},[]),u=s.useCallback(async()=>{const x=Array.from(c.current);if(x.length===0)return;N.current&&N.current.abort(),N.current=new AbortController;const g=!b.current;g&&d(!0),p(null);try{const C=await Promise.allSettled(x.map(B=>_(B,g)));b.current=!0,C.filter(B=>B.status==="rejected").length>0&&p("Some sync status requests failed")}catch(C){if(C instanceof Error&&C.name==="AbortError")return;p(C instanceof Error?C.message:"Failed to fetch sync status"),b.current=!0}finally{d(!1)}},[_]),P=s.useCallback(()=>{R.current&&clearInterval(R.current),R.current=setInterval(()=>{u()},Es)},[u]),v=s.useCallback(()=>{R.current&&(clearInterval(R.current),R.current=null)},[]);s.useEffect(()=>(u(),P(),()=>{v(),N.current&&N.current.abort()}),[u,P,v]);const r=s.useCallback(x=>{c.current.has(x)||(c.current.add(x),_(x,!b.current))},[_]),j=s.useCallback(x=>{c.current.delete(x),l(g=>{const C={...g};return delete C[x],C}),c.current.size===0&&v()},[v]),S=s.useCallback(async x=>{f(g=>({...g,[x]:!0})),p(null);try{const g=await os(x);return _(x,!1),!g.success&&g.error&&p(g.error),g}catch(g){const C=g instanceof Error?g.message:"Push settings failed";throw p(C),g}finally{f(g=>{const C={...g};return delete C[x],C})}},[_]),k=s.useCallback(async x=>{f(g=>({...g,[x]:!0})),p(null);try{const g=await cs(x);return _(x,!1),!g.success&&g.error&&p(g.error),g}catch(g){const C=g instanceof Error?g.message:"Pull settings failed";throw p(C),g}finally{f(g=>{const C={...g};return delete C[x],C})}},[_]),D=s.useCallback(async x=>{f(g=>({...g,[x]:!0})),p(null);try{return await is(x)}catch(g){const C=g instanceof Error?g.message:"Auth sync failed";throw p(C),g}finally{f(g=>{const C={...g};return delete C[x],C})}},[]),K=s.useCallback(x=>t[x]?.authMatch,[t]),E=s.useCallback(x=>t[x]?.authDiff,[t]);return{syncStatusMap:t,loading:a,actionLoading:m,error:o,refresh:u,trackNode:r,untrackNode:j,pushSettings:S,pullSettings:k,syncAuth:D,getAuthSyncState:K,getAuthProviders:E}}const ue={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"},creating:{label:"Creating",color:"var(--color-warning)",className:"node-card__status--creating"},recreating:{label:"Recreating",color:"var(--color-warning)",className:"node-card__status--recreating"},deleting:{label:"Deleting",color:"var(--color-error)",className:"node-card__status--deleting"},running:{label:"Running",color:"var(--color-success)",className:"node-card__status--online"},stopped:{label:"Stopped",color:"var(--color-error)",className:"node-card__status--offline"},exited:{label:"Exited",color:"var(--color-error)",className:"node-card__status--offline"}},As={match:"var(--color-success)",differs:"var(--color-warning)","not-synced":"var(--text-muted)"};function Ls(t,l){if(t==="match")return"Auth credentials match";if(t==="not-synced")return"Auth not synced";if(l&&Object.keys(l).length>0){const a=Object.entries(l).filter(([,d])=>d==="differs").map(([d])=>d);if(a.length>0)return`Auth credentials differ: ${a.join(", ")}`}return"Auth credentials differ"}function $s(t,l=42){return t.length<=l?t:`${t.slice(0,l-3)}...`}function Ds(t,l){const a=t.node,d=l.node;if(a.id!==d.id||a.name!==d.name||a.type!==d.type||a.url!==d.url||a.status!==d.status||a.maxConcurrent!==d.maxConcurrent||a.updatedAt!==d.updatedAt||t.isLoading!==l.isLoading)return!1;const m=t.managedDockerNode,f=l.managedDockerNode;if(!!m!=!!f||m&&f&&(m.id!==f.id||m.status!==f.status||m.imageTag!==f.imageTag||m.updatedAt!==f.updatedAt))return!1;const o=t.syncStatus,p=l.syncStatus;if(!(!o&&!p)){if(!o||!p)return!1;if(o.syncState!==p.syncState||o.lastSyncAt!==p.lastSyncAt||o.diffCount!==p.diffCount)return!1}if(t.authSyncState!==l.authSyncState)return!1;const c=t.authSyncProviders,b=l.authSyncProviders;if(c!==b){if(!c||!b)return!1;{const _=Object.keys(c),u=Object.keys(b);if(_.length!==u.length||_.some(P=>c[P]!==b[P]))return!1}}const N=ve(t.projects,a),R=ve(l.projects,d);return N===R}function zs({node:t,projects:l,onHealthCheck:a,onEdit:d,onRemove:m,isLoading:f=!1,syncStatus:o,authSyncState:p,authSyncProviders:c,managedDockerNode:b}){const[N,R]=s.useState(!1),_=ue[t.status]??ue.offline,u=b?ue[b.status]??ue.error:null,P=b?.hostConfig.type==="remote"?`Remote: ${b.hostConfig.host??"unknown"}`:"Local Docker",v=s.useMemo(()=>ve(l,t),[l,t]),r=s.useCallback(()=>{d(t)},[d,t]),j=s.useCallback(K=>{K.stopPropagation(),a(t.id)},[a,t.id]),S=s.useCallback(K=>{K.stopPropagation(),d(t)},[d,t]),k=s.useCallback(K=>{if(K.stopPropagation(),!N){R(!0);return}m(t.id),R(!1)},[N,m,t.id]),D=s.useCallback(K=>{(K.key==="Enter"||K.key===" ")&&(K.preventDefault(),d(t))},[d,t]);return e.jsxs("article",{className:`node-card ${f?"node-card--loading":""}`,"data-node-id":t.id,role:"button",tabIndex:0,onClick:r,onKeyDown:D,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(Ke,{size:18})}),e.jsxs("div",{children:[e.jsx("h3",{className:"node-card__name",title:t.name,children:t.name}),e.jsxs("div",{className:"node-card__meta-row",children:[e.jsx("span",{className:"node-card__type-badge",children:t.type==="local"?"Local":"Remote"}),b&&e.jsxs("span",{className:"node-card__docker-badge",title:"Managed Docker node",children:[e.jsx(ye,{size:12,"aria-hidden":!0}),"Docker"]}),e.jsxs("span",{className:`node-card__status ${_.className}`,style:{color:_.color},"data-status":t.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:_.color},"aria-hidden":!0}),_.label]}),b&&u&&e.jsxs("span",{className:`node-card__status ${u.className}`,style:{color:u.color},"data-status":b.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:u.color},"aria-hidden":!0}),u.label]}),t.type==="remote"&&p&&e.jsx("span",{className:`node-card__auth-indicator node-card__auth-indicator--${p}`,title:Ls(p,c),"aria-label":`Auth sync: ${p==="match"?"credentials match":p==="differs"?"credentials differ":"not synced"}`,style:{color:As[p]},children:e.jsx(Ve,{size:14})})]})]})]})}),e.jsxs("div",{className:"node-card__body",children:[t.type==="remote"&&t.url&&e.jsx("div",{className:"node-card__url",title:t.url,children:$s(t.url)}),b&&e.jsxs("div",{className:"node-card__docker-meta",children:[e.jsxs("span",{title:`${b.imageName}:${b.imageTag}`,children:[b.imageName,":",b.imageTag]}),e.jsx("span",{title:P,children:P})]}),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:v})]}),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:t.maxConcurrent})]})]}),t.type==="remote"&&o&&e.jsxs("div",{className:"node-card__sync","data-sync-state":o.syncState,"data-testid":"node-card-sync",children:[e.jsx("span",{className:"node-card__sync-dot",style:{backgroundColor:Ps(o.syncState)},"aria-hidden":!0}),e.jsx("span",{className:"node-card__sync-time",children:ke(o.lastSyncAt)})]})]}),e.jsxs("footer",{className:"node-card__actions",children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:j,disabled:f,"aria-label":"Run node health check",title:"Health Check",children:[e.jsx(Oe,{size:14}),e.jsx("span",{children:"Health"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:S,disabled:f,"aria-label":"Edit node",title:"Edit",children:[e.jsx(ds,{size:14}),e.jsx("span",{children:"Edit"})]}),b&&e.jsxs(e.Fragment,{children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",disabled:!0,"aria-label":"Start node container",title:"Available after FN-3113",children:[e.jsx(Fe,{size:14}),e.jsx("span",{children:"Start"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",disabled:!0,"aria-label":"Stop node container",title:"Available after FN-3113",children:[e.jsx(Ue,{size:14}),e.jsx("span",{children:"Stop"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",disabled:!0,"aria-label":"Restart node container",title:"Available after FN-3113",children:[e.jsx(us,{size:14}),e.jsx("span",{children:"Restart"})]})]}),e.jsxs("button",{className:`btn btn-sm node-card__action node-card__action--remove ${N?"btn-danger is-armed":""}`,type:"button",onClick:k,disabled:f,"aria-label":N?"Confirm remove node":"Remove node",title:N?"Confirm remove":"Remove",children:[e.jsx(_e,{size:14}),e.jsx("span",{children:N?"Confirm":"Remove"})]})]})]})}const Is=s.memo(zs,Ds),ce={online:"var(--success, var(--color-success))",offline:"var(--text-dim)",connecting:"var(--triage)",error:"var(--color-error)"},re=28,ze=12,Ks=300,Vs=120;function Os({nodes:t,className:l}){const a=s.useMemo(()=>t.find(c=>c.type==="local")??t[0],[t]),d=s.useMemo(()=>t.filter(c=>c.type==="remote"),[t]),m=s.useMemo(()=>{const c=Ks,b=Math.max(0,d.length-4)*20;return c+b},[d.length]),f=m/2,o=m/2,p=s.useMemo(()=>{if(d.length===0)return[];const c=Math.min(Vs,m/2-re-10),b=2*Math.PI/d.length,N=-Math.PI/2;return d.map((R,_)=>{const u=N+_*b;return{node:R,x:f+c*Math.cos(u),y:o+c*Math.sin(u)}})},[d,m,f,o]);return t.length===0?e.jsx("div",{className:`mesh-topology mesh-topology--empty ${l??""}`,children:e.jsx("div",{className:"mesh-topology__empty-state",children:e.jsx("p",{children:"No nodes to display"})})}):e.jsxs("div",{className:`mesh-topology ${l??""}`,children:[e.jsxs("svg",{className:"mesh-topology__svg",viewBox:`0 0 ${m} ${m}`,preserveAspectRatio:"xMidYMid meet","aria-label":"Node mesh topology visualization",children:[p.map(c=>e.jsx("line",{className:"mesh-topology__link",x1:f,y1:o,x2:c.x,y2:c.y},`link-${c.node.id}`)),a&&e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${f}, ${o})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:re,fill:ce[a.status],"aria-label":`${a.name} (${a.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:re+ze,textAnchor:"middle",children:a.name.length>12?`${a.name.slice(0,10)}…`:a.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-re-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:a.type==="local"?"L":"R"})]})]}),p.map(c=>e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${c.x}, ${c.y})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:re,fill:ce[c.node.status],"aria-label":`${c.node.name} (${c.node.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:re+ze,textAnchor:"middle",children:c.node.name.length>12?`${c.node.name.slice(0,10)}…`:c.node.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-re-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:c.node.type==="local"?"L":"R"})]})]},c.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:ce.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:ce.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:ce.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:ce.error}}),e.jsx("span",{children:"Error"})]})]}),e.jsx("p",{className:"mesh-topology__notice",children:"Peer-to-peer discovery data unavailable."})]})}const Fs=s.memo(Os),Ce=1,Se=10;function Us(t){const l={projectMappings:{}};t.name.trim()||(l.name="Name is required"),t.type==="remote"&&!t.url?.trim()&&(l.url="URL is required for remote nodes"),(!Number.isFinite(t.maxConcurrent)||t.maxConcurrent<Ce||t.maxConcurrent>Se)&&(l.maxConcurrent=`Concurrency must be between ${Ce} and ${Se}`);for(const a of t.projectMappings){const d=ks(a.path);d.valid||(l.projectMappings[a.projectId]=d.error??"Path is invalid")}return l}function Bs({isOpen:t,onClose:l,onSubmit:a,onDiscoverRemoteProjects:d,addToast:m,projects:f}){ms(t);const[o,p]=s.useState(""),[c,b]=s.useState("local"),[N,R]=s.useState(""),[_,u]=s.useState(""),[P,v]=s.useState(2),[r,j]=s.useState("auto-generate"),[S,k]=s.useState({}),[D,K]=s.useState({projectMappings:{}}),[E,x]=s.useState(!1),[g,C]=s.useState("idle"),[G,B]=s.useState(null),[q,W]=s.useState([]),T=s.useCallback(()=>{p(""),b("local"),R(""),u(""),v(2),j("auto-generate"),k({}),K({projectMappings:{}}),x(!1),C("idle"),B(null),W([])},[]),Y=s.useCallback(()=>{E||(T(),l())},[E,l,T]);s.useEffect(()=>{if(!t){T();return}const y=$=>{$.key==="Escape"&&($.preventDefault(),Y())};return document.addEventListener("keydown",y),()=>{document.removeEventListener("keydown",y)}},[Y,t,T]);const O=s.useMemo(()=>({name:o.trim(),type:c,url:c==="remote"&&N.trim()||void 0,apiKey:c==="remote"&&r==="provide"&&_||void 0,maxConcurrent:P,apiKeyMode:r,projectMappings:Object.entries(S).map(([y,$])=>({projectId:y,path:$.trim()}))}),[_,r,P,o,S,c,N]),Q=s.useCallback(async()=>{if(E||g==="loading")return;const y=N.trim();if(!y){K($=>({...$,url:"URL is required for remote nodes"}));return}C("loading"),B(null);try{const $=await d({url:y,apiKey:r==="provide"&&_.trim().length>0?_:void 0});W($.projects),C("success"),k(z=>{if(Object.keys(z).length===0)return z;const F={...z};for(const ee of f){if(!(ee.id in F))continue;const M=$.projects.filter(A=>A.name===ee.name);M.length===1&&(F[ee.id]=M[0].path)}return F})}catch($){C("error"),W([]),B($ instanceof Error?$.message:"Failed to discover remote projects")}},[_,r,g,E,d,f,N]);s.useEffect(()=>{if(c!=="remote"){C("idle"),B(null),W([]);return}C("idle"),B(null),W([])},[_,r,c,N]);const H=s.useCallback(async()=>{if(E)return;const y=Us(O);if(K(y),!(y.name||y.url||y.maxConcurrent||Object.keys(y.projectMappings).length>0)){if(O.type==="remote"&&g!=="success"){B("Discover remote projects before adding this node.");return}x(!0);try{await a(O),m(`Node "${O.name}" registered`,"success"),Y()}catch($){const z=$ instanceof Error?$.message:"Failed to register node";m(z,"error")}finally{x(!1)}}},[m,Y,g,O,E,a]),se=y=>{k($=>{if(y.id in $){const{[y.id]:z,...F}=$;return F}if(c==="remote"&&g==="success"){const z=q.filter(F=>F.name===y.name);return z.length===1?{...$,[y.id]:z[0].path}:{...$,[y.id]:""}}return{...$,[y.id]:y.path}})},L=(y,$)=>{k(z=>({...z,[y]:$}))};return t?e.jsx("div",{className:"modal-overlay open",onClick:Y,children:e.jsxs("div",{className:"modal modal-md add-node-modal",onClick:y=>y.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:Y,disabled:E,"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:o,onChange:y=>p(y.target.value),placeholder:"Build Machine",disabled:E,"aria-invalid":!!D.name,autoFocus:!0}),D.name&&e.jsx("span",{className:"form-error add-node-modal__error",children:D.name})]}),e.jsxs("div",{className:"add-node-modal__type-toggle",children:[e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${c==="local"?"active":""}`,"data-type":"local",onClick:()=>b("local"),disabled:E,"aria-pressed":c==="local",children:"Local"}),e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${c==="remote"?"active":""}`,"data-type":"remote",onClick:()=>b("remote"),disabled:E,"aria-pressed":c==="remote",children:"Remote"})]}),c==="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:N,onChange:y=>R(y.target.value),placeholder:"https://node.example.com",disabled:E,"aria-invalid":!!D.url}),D.url&&e.jsx("span",{className:"form-error add-node-modal__error",children:D.url})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key Mode"}),e.jsxs("select",{className:"select",value:r,onChange:y=>j(y.target.value),disabled:E,children:[e.jsx("option",{value:"auto-generate",children:"Auto-generate"}),e.jsx("option",{value:"provide",children:"Provide key manually"})]})]}),r==="provide"&&e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:_,onChange:y=>u(y.target.value),placeholder:"Enter node API key",disabled:E})]}),e.jsxs("div",{className:"add-node-modal__discovery-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>void Q(),disabled:E||g==="loading",children:g==="loading"?"Discovering...":"Discover Remote Projects"}),g==="success"&&e.jsx("span",{className:"add-node-modal__discovery-state","data-state":"success",children:q.length>0?`Discovered ${q.length} remote project${q.length===1?"":"s"}.`:"No projects discovered on remote node."}),g==="error"&&G&&e.jsx("span",{className:"form-error add-node-modal__error",children:G}),g==="idle"&&e.jsx("span",{className:"add-node-modal__hint",children:"Discover remote projects before adding this node."})]}),g==="success"&&q.length>0&&e.jsx("div",{className:"add-node-modal__discovered-list","aria-label":"Discovered remote projects",children:q.map(y=>e.jsxs("div",{className:"card add-node-modal__discovered-card",children:[e.jsxs("div",{className:"add-node-modal__discovered-row",children:[e.jsx("strong",{children:y.name}),e.jsx("span",{className:"card-status-badge card-status-badge--in-review",children:y.status})]}),e.jsx("div",{className:"add-node-modal__hint",children:y.path})]},`${y.id}-${y.path}`))})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),e.jsx("input",{className:"input",type:"number",min:Ce,max:Se,value:P,onChange:y=>v(Number(y.target.value)),disabled:E,"aria-invalid":!!D.maxConcurrent}),e.jsx("span",{className:"add-node-modal__hint",children:"Max simultaneous task agents (1–10)"}),D.maxConcurrent&&e.jsx("span",{className:"form-error add-node-modal__error",children:D.maxConcurrent})]}),e.jsxs("section",{className:"add-node-modal__projects","aria-label":"Project path mappings",children:[e.jsx("h4",{className:"add-node-modal__projects-title",children:"Attach Existing Projects"}),e.jsx("p",{className:"add-node-modal__hint",children:"Select existing projects to run on this node and provide the node-specific absolute path for each one."}),f.length===0?e.jsx("p",{className:"add-node-modal__hint",children:"No projects are currently registered."}):e.jsx("div",{className:"add-node-modal__project-list",children:f.map(y=>{const $=y.id in S,z=D.projectMappings[y.id];return e.jsxs("div",{className:"card add-node-modal__project-card",children:[e.jsxs("label",{className:"checkbox-label add-node-modal__project-toggle",children:[e.jsx("input",{type:"checkbox",checked:$,onChange:()=>se(y),disabled:E}),e.jsx("span",{children:y.name})]}),$&&e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Path on this node"}),c==="remote"&&g==="success"&&e.jsx("span",{className:"add-node-modal__hint",children:(()=>{const F=q.filter(ee=>ee.name===y.name);return F.length===1?`Remote-authoritative path discovered: ${F[0].path}`:F.length>1?"Multiple remote projects matched this name. Enter the correct path manually.":"No exact remote name match. Enter this path manually."})()}),e.jsx("input",{className:"input",type:"text",value:S[y.id]??"",onChange:F=>L(y.id,F.target.value),disabled:E,placeholder:"/absolute/path/to/project","aria-invalid":!!z}),z&&e.jsx("span",{className:"form-error add-node-modal__error",children:z})]})]},y.id)})})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:Y,disabled:E,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm","data-testid":"add-node-submit",onClick:H,disabled:E,children:E?"Adding...":"Add Node"})]})]})}):null}function Ts(){const[t,l]=s.useState([]),[a,d]=s.useState(!1),[m,f]=s.useState(null),[o,p]=s.useState(!1),[c,b]=s.useState(null),[N,R]=s.useState(!1),_=s.useCallback(async()=>{d(!0),f(null);try{const v=await fetch("/api/docker/contexts");if(!v.ok)throw new Error(`Failed to load Docker contexts (${v.status})`);const r=await v.json();return l(r),r}catch(v){const r=v instanceof Error?v.message:String(v);throw f(r),v}finally{d(!1)}},[]),u=s.useCallback(async v=>{p(!0);try{const r=await fetch("/api/docker/test-connection",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({hostConfig:v})});if(!r.ok)throw new Error(`Failed to test Docker connection (${r.status})`);const j=await r.json();return b(j),j}finally{p(!1)}},[]),P=s.useCallback(async()=>{R(!0);try{const v=await fetch("/api/docker/local-available");if(!v.ok)throw new Error(`Failed to check local Docker availability (${v.status})`);return await v.json()}finally{R(!1)}},[]);return{contexts:t,isLoadingContexts:a,contextsError:m,loadContexts:_,isTestingConnection:o,lastTestResult:c,testConnection:u,isCheckingLocal:N,checkLocalDocker:P}}function Hs({value:t,onChange:l}){const[a,d]=s.useState(!!(t?.tlsCaPath||t?.tlsCertPath||t?.tlsKeyPath||t?.tlsVerify));s.useEffect(()=>{a||l({tlsVerify:void 0,tlsCaPath:void 0,tlsCertPath:void 0,tlsKeyPath:void 0})},[a,l]);const m=s.useMemo(()=>({tlsVerify:t?.tlsVerify??!0,tlsCaPath:t?.tlsCaPath??"",tlsCertPath:t?.tlsCertPath??"",tlsKeyPath:t?.tlsKeyPath??""}),[t]);return e.jsxs("div",{className:"docker-tls-config",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:a,onChange:f=>d(f.target.checked)}),"Use TLS"]}),a&&e.jsxs("div",{className:"docker-tls-config__fields",children:[e.jsxs("div",{className:"docker-tls-config__field",children:[e.jsx("label",{htmlFor:"docker-tls-ca-path",children:"CA Certificate Path"}),e.jsx("input",{id:"docker-tls-ca-path",className:"input",value:m.tlsCaPath,onChange:f=>l({...m,tlsCaPath:f.target.value}),placeholder:"/etc/docker/ca.pem"})]}),e.jsxs("div",{className:"docker-tls-config__field",children:[e.jsx("label",{htmlFor:"docker-tls-cert-path",children:"Client Certificate Path"}),e.jsx("input",{id:"docker-tls-cert-path",className:"input",value:m.tlsCertPath,onChange:f=>l({...m,tlsCertPath:f.target.value}),placeholder:"/etc/docker/cert.pem"})]}),e.jsxs("div",{className:"docker-tls-config__field",children:[e.jsx("label",{htmlFor:"docker-tls-key-path",children:"Client Key Path"}),e.jsx("input",{id:"docker-tls-key-path",className:"input",value:m.tlsKeyPath,onChange:f=>l({...m,tlsKeyPath:f.target.value}),placeholder:"/etc/docker/key.pem"})]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:m.tlsVerify,onChange:f=>l({...m,tlsVerify:f.target.checked})}),"Verify TLS Certificate"]})]})]})}function qs({value:t,onChange:l,onError:a}){const d=t?.context?"context":t?.host?"host":"local",[m,f]=s.useState(d),[o,p]=s.useState(t?.context??""),[c,b]=s.useState(t?.host??""),[N,R]=s.useState(null),{contexts:_,isLoadingContexts:u,contextsError:P,loadContexts:v,testConnection:r,isTestingConnection:j,lastTestResult:S,checkLocalDocker:k,isCheckingLocal:D}=Ts(),K=s.useMemo(()=>({tlsVerify:t?.tlsVerify,tlsCaPath:t?.tlsCaPath,tlsCertPath:t?.tlsCertPath,tlsKeyPath:t?.tlsKeyPath}),[t]);s.useEffect(()=>{if(m==="local"){l({});return}if(m==="context"){v().catch(x=>a?.(x instanceof Error?x.message:String(x))),l(o?{context:o}:{});return}l({host:c,...K})},[m]);const E=s.useCallback(x=>{m==="host"&&l({host:c,...x})},[c,m,l]);return e.jsxs("div",{className:"docker-target-selector",children:[e.jsxs("div",{className:"docker-target-selector__modes",role:"group","aria-label":"Docker target mode",children:[e.jsx("button",{type:"button",className:`btn btn-sm ${m==="local"?"docker-target-selector__mode-active":""}`,onClick:()=>{f("local"),k().then(x=>R(x.available?`Docker is available${x.version?` (${x.version})`:""}`:`Docker not found${x.error?`: ${x.error}`:""}`)).catch(x=>{const g=x instanceof Error?x.message:String(x);R(`Docker not found: ${g}`),a?.(g)})},children:"Local Docker"}),e.jsx("button",{type:"button",className:`btn btn-sm ${m==="context"?"docker-target-selector__mode-active":""}`,onClick:()=>f("context"),children:"Docker Context"}),e.jsx("button",{type:"button",className:`btn btn-sm ${m==="host"?"docker-target-selector__mode-active":""}`,onClick:()=>f("host"),children:"Remote Host"})]}),m==="local"&&N&&e.jsx("div",{className:"docker-target-selector__status",children:N}),m==="context"&&e.jsxs("div",{className:"docker-target-selector__panel",children:[e.jsxs("div",{className:"docker-target-selector__context-row",children:[e.jsxs("select",{className:"select",value:o,onChange:x=>{const g=x.target.value;p(g),l(g?{context:g}:{})},children:[e.jsx("option",{value:"",children:"Select context"}),_.map(x=>e.jsxs("option",{value:x.name,children:[x.name,x.isCurrentContext?" (current)":"",x.dockerHost?` — ${x.dockerHost}`:""]},x.name))]}),e.jsx("button",{type:"button",className:"btn btn-sm btn-icon",onClick:()=>void v(),disabled:u,"aria-label":"Refresh contexts",children:e.jsx(Ne,{size:14})})]}),P&&e.jsx("div",{className:"docker-target-selector__error",children:P})]}),m==="host"&&e.jsxs("div",{className:"docker-target-selector__panel",children:[e.jsxs("div",{className:"docker-target-selector__field",children:[e.jsx("label",{htmlFor:"docker-target-selector-host",children:"Docker Host"}),e.jsx("input",{id:"docker-target-selector-host",className:"input",placeholder:"tcp://host:2376",value:c,onChange:x=>{const g=x.target.value;b(g),l({host:g,...K})}})]}),e.jsx(Hs,{value:K,onChange:E})]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>void r(m==="local"?void 0:m==="context"?{context:o}:{host:c,...K}),disabled:j||D,children:j?"Testing...":"Test Connection"}),S&&e.jsx("div",{className:S.success?"docker-target-selector__success":"docker-target-selector__error",children:S.success?`Connected${S.dockerVersion?` (Docker ${S.dockerVersion})`:""}`:S.error??"Connection failed"})]})}const je="http://localhost:4040";function Ys({isOpen:t,onClose:l,onSubmit:a,addToast:d}){const[m,f]=s.useState(""),[o,p]=s.useState({}),[c,b]=s.useState(je),[N,R]=s.useState("auto"),[_,u]=s.useState(""),[P,v]=s.useState(!1),[r,j]=s.useState(!1),[S,k]=s.useState(!0),[D,K]=s.useState(4096),[E,x]=s.useState(2),[g,C]=s.useState(!1),[G,B]=s.useState("runfusion/fusion"),[q,W]=s.useState("latest"),[T,Y]=s.useState([]),[O,Q]=s.useState([]),[H,se]=s.useState({}),[L,y]=s.useState(!1),$=s.useCallback(()=>{f(""),p({}),b(je),R("auto"),u(""),v(!1),j(!1),k(!0),K(4096),x(2),C(!1),B("runfusion/fusion"),W("latest"),Y([]),Q([]),se({}),y(!1)},[]),z=s.useCallback(()=>{L||($(),l())},[l,$,L]);s.useEffect(()=>{if(!t){$();return}const i=U=>{U.key==="Escape"&&(U.preventDefault(),z())};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[z,t,$]);const F=s.useMemo(()=>({nodeId:null,name:m.trim(),imageName:G.trim()||"runfusion/fusion",imageTag:q.trim()||"latest",hostConfig:{context:o.context?.trim()||void 0,host:o.host?.trim()||void 0,tlsVerify:o.tlsVerify,tlsCaPath:o.tlsCaPath?.trim()||void 0,tlsCertPath:o.tlsCertPath?.trim()||void 0,tlsKeyPath:o.tlsKeyPath?.trim()||void 0},envVars:Object.fromEntries(T.map(i=>[i.key.trim(),i.value]).filter(([i])=>!!i)),volumeMounts:O.map(i=>({hostPath:i.hostPath.trim(),containerPath:i.containerPath.trim(),mode:i.mode})).filter(i=>i.hostPath&&i.containerPath),resourceSizing:{memoryMB:D,cpus:E},extraClis:[P?"claude-cli":null,r?"droid-cli":null].filter(Boolean),persistentStorage:S,reachableUrl:c.trim()||null,apiKey:N==="manual"&&_.trim()||null}),[_,N,E,o,T,G,q,P,r,D,O,m,S,c]),ee=s.useCallback(()=>{Y(i=>[...i,{key:"",value:""}])},[]),M=s.useCallback((i,U)=>{Y(X=>X.map((te,oe)=>oe===i?U:te))},[]),A=s.useCallback(i=>{Y(U=>U.filter((X,te)=>te!==i))},[]),J=s.useCallback(()=>{Q(i=>[...i,{hostPath:"",containerPath:"",mode:"rw"}])},[]),ae=s.useCallback((i,U)=>{Q(X=>X.map((te,oe)=>oe===i?U:te))},[]),le=s.useCallback(i=>{Q(U=>U.filter((X,te)=>te!==i))},[]),ie=s.useCallback(async()=>{if(L)return;const i={};if((!F.name||F.name.length>64)&&(i.name="Name is required and must be 64 characters or fewer"),F.reachableUrl||(i.reachableUrl="URL is required"),D<512&&(i.memoryMB="Memory must be at least 512 MB"),E<.5&&(i.cpus="CPUs must be at least 0.5"),se(i),!(Object.keys(i).length>0)){y(!0);try{await a(F),z()}catch{}finally{y(!1)}}},[z,E,F,D,a,L]);return t?e.jsx("div",{className:"modal-overlay open",onClick:z,children:e.jsxs("div",{className:"modal docker-onboarding",role:"dialog","aria-modal":"true","aria-label":"Docker node onboarding",onClick:i=>i.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Provision Docker Node"}),e.jsx("button",{className:"modal-close",onClick:z,disabled:L,"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:m,onChange:i=>f(i.target.value),disabled:L,placeholder:"my-docker-node",autoFocus:!0})]}),H.name&&e.jsx("div",{className:"form-error",children:H.name}),e.jsx(qs,{value:o,onChange:p}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Reachable URL"}),e.jsx("input",{className:"input",value:c,onChange:i=>b(i.target.value),disabled:L,placeholder:je})]}),H.reachableUrl&&e.jsx("div",{className:"form-error",children:H.reachableUrl}),e.jsxs("div",{className:"docker-onboarding__radio-group",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"radio",checked:N==="auto",onChange:()=>R("auto"),disabled:L}),"Auto-generate"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"radio",checked:N==="manual",onChange:()=>R("manual"),disabled:L}),"Provide manually"]})]}),N==="manual"&&e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:_,onChange:i=>u(i.target.value),disabled:L,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:P,onChange:i=>v(i.target.checked),disabled:L}),"Claude CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:r,onChange:i=>j(i.target.checked),disabled:L}),"Droid CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:S,onChange:i=>k(i.target.checked),disabled:L}),"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:D,onChange:i=>K(Number(i.target.value)),disabled:L})]}),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:E,onChange:i=>x(Number(i.target.value)),disabled:L})]})]}),H.memoryMB&&e.jsx("div",{className:"form-error",children:H.memoryMB}),H.cpus&&e.jsx("div",{className:"form-error",children:H.cpus})]}),e.jsxs("section",{className:"docker-onboarding__section",children:[e.jsxs("button",{type:"button",className:`docker-onboarding__advanced-toggle ${g?"is-expanded":""}`,onClick:()=>C(i=>!i),disabled:L,children:[e.jsx("span",{children:"Advanced"}),e.jsx(we,{})]}),e.jsx("div",{className:`docker-onboarding__advanced-content ${g?"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:G,onChange:i=>B(i.target.value),disabled:L,placeholder:"runfusion/fusion"})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Tag"}),e.jsx("input",{className:"input",value:q,onChange:i=>W(i.target.value),disabled:L,placeholder:"latest"})]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Environment Variables"}),T.map((i,U)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--env",children:[e.jsx("input",{className:"input",placeholder:"KEY",value:i.key,disabled:L,onChange:X=>M(U,{key:X.target.value,value:i.value})}),e.jsx("input",{className:"input",placeholder:"Value",value:i.value,disabled:L,onChange:X=>M(U,{key:i.key,value:X.target.value})}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":"Remove environment variable",onClick:()=>A(U),disabled:L,children:e.jsx(_e,{size:14})})]},`env-${U}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:ee,disabled:L,children:[e.jsx(he,{size:14}),"Add variable"]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Volume Mounts"}),O.map((i,U)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--mount",children:[e.jsx("input",{className:"input",placeholder:"Host path",value:i.hostPath,disabled:L,onChange:X=>ae(U,{hostPath:X.target.value,containerPath:i.containerPath,mode:i.mode})}),e.jsx("input",{className:"input",placeholder:"Container path",value:i.containerPath,disabled:L,onChange:X=>ae(U,{hostPath:i.hostPath,containerPath:X.target.value,mode:i.mode})}),e.jsxs("select",{className:"select",value:i.mode,disabled:L,onChange:X=>ae(U,{hostPath:i.hostPath,containerPath:i.containerPath,mode:X.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(U),disabled:L,children:e.jsx(_e,{size:14})})]},`mount-${U}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:J,disabled:L,children:[e.jsx(he,{size:14}),"Add mount"]})]})]})})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn",onClick:z,disabled:L,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",onClick:()=>void ie(),disabled:L,children:L?"Creating...":"Create Docker Node"})]})]})}):null}function Xs({nodeId:t,entries:l,loading:a=!1,singleNode:d=!1}){const[m,f]=s.useState(!1),[o,p]=s.useState("all"),[c,b]=s.useState("all"),N=s.useCallback(()=>{f(r=>!r)},[]),R=s.useMemo(()=>{const r=new Set;for(const j of l)r.add(j.nodeName);return Array.from(r).sort()},[l]),_=s.useMemo(()=>{let r=[...l];return o!=="all"&&(r=r.filter(j=>j.direction===o)),!d&&c!=="all"&&(r=r.filter(j=>j.nodeName===c)),r.sort((j,S)=>{const k=new Date(j.timestamp).getTime();return new Date(S.timestamp).getTime()-k}),r},[l,o,c,d]),u=s.useCallback(r=>new Date(r).toLocaleString(),[]),P=s.useCallback(r=>{switch(r){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""}},[]),v=s.useCallback(r=>{switch(r){case"success":return"Success";case"conflict":return"Conflict";case"error":return"Error";default:return r}},[]);return e.jsxs("div",{className:"settings-sync-log",children:[e.jsxs("button",{className:"settings-sync-log__header",type:"button",onClick:N,"aria-expanded":m,"data-testid":"settings-sync-log-header",children:[e.jsx(we,{size:16,className:`settings-sync-log__chevron ${m?"settings-sync-log__chevron--expanded":""}`}),e.jsxs("span",{children:[l.length," ",l.length===1?"entry":"entries"]})]}),m&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-sync-log__filters",children:[e.jsxs("label",{children:["Direction:",e.jsxs("select",{value:o,onChange:r=>p(r.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:c,onChange:r=>b(r.target.value),children:[e.jsx("option",{value:"all",children:"All Nodes"}),R.map(r=>e.jsx("option",{value:r,children:r},r))]})]})]}),a&&l.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"Loading..."}):_.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"No sync history available"}):e.jsx("div",{className:"settings-sync-log__list",children:_.map(r=>e.jsxs("div",{className:"settings-sync-log__entry",children:[e.jsx("span",{className:"settings-sync-log__entry-timestamp",children:u(r.timestamp)}),e.jsx("span",{className:"settings-sync-log__entry-direction",children:r.direction==="push"?e.jsx(Te,{size:14,"data-testid":"upload-icon"}):e.jsx(Be,{size:14,"data-testid":"download-icon"})}),e.jsx("span",{className:`settings-sync-log__entry-result ${P(r.result)}`,children:v(r.result)}),!d&&e.jsx("span",{className:"settings-sync-log__entry-node",children:r.nodeName}),r.details&&e.jsx("span",{className:"settings-sync-log__entry-details",title:r.details,children:r.details})]},r.id))})]})]})}function Js(t,l){const a=typeof t=="string"?t:JSON.stringify(t,null,2),d=typeof l=="string"?l:JSON.stringify(l,null,2);if(a===d)return a;const m=a.split(`
|
|
12
|
-
`),f=d.split(`
|
|
13
|
-
`),o=[],p=Math.max(m.length,f.length);for(let c=0;c<p;c++){const b=m[c],N=f[c];b!==void 0&&b!==N&&o.push(`- ${b}`),N!==void 0&&N!==b&&o.push(`+ ${N}`),b!==void 0&&b===N&&o.push(` ${b}`)}return o.join(`
|
|
14
|
-
`)}function Ws({isOpen:t,onClose:l,onResolve:a,conflicts:d,localNodeName:m,remoteNodeName:f,addToast:o}){const[p,c]=s.useState({}),[b,N]=s.useState(!1);s.useEffect(()=>{const r={};for(const j of d)p[j.key]||(r[j.key]={resolution:"local"});Object.keys(r).length>0&&c(j=>({...j,...r}))},[d,p]),s.useEffect(()=>{if(!t)return;const r=j=>{j.key==="Escape"&&(j.preventDefault(),l())};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[t,l]);const R=s.useCallback((r,j)=>{c(S=>{const k=S[r]??{};return j==="manual"?{...S,[r]:{resolution:"manual",manualValue:k.manualValue??JSON.stringify(d.find(D=>D.key===r)?.localValue??null,null,2)}}:{...S,[r]:{resolution:j}}})},[d]),_=s.useCallback((r,j)=>{c(S=>({...S,[r]:{...S[r],resolution:"manual",manualValue:j}}))},[]),u=s.useCallback(r=>{const j={};for(const S of d)j[S.key]={resolution:r};c(j)},[d]),P=s.useCallback(async()=>{N(!0);try{const r=d.map(j=>{const S=p[j.key]??{resolution:"local"};let k;switch(S.resolution){case"remote":k=j.remoteValue;break;case"manual":try{k=JSON.parse(S.manualValue??"null")}catch{k=S.manualValue??null}break;case"local":default:k=j.localValue;break}return{key:j.key,value:k}});await a(r),o("Settings conflicts resolved successfully","success"),l()}catch(r){const j=r instanceof Error?r.message:"Failed to resolve conflicts";o(j,"error")}finally{N(!1)}},[o,d,l,a,p]),v=s.useMemo(()=>{const r={};for(const j of d)r[j.key]=Js(j.localValue,j.remoteValue);return r},[d]);return!t||d.length===0?null:e.jsx("div",{className:"modal-overlay open",onClick:l,children:e.jsxs("div",{className:"modal modal-lg settings-sync-conflict-modal",onClick:r=>r.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:l,"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(r=>{const j=p[r.key]??{resolution:"local"},S=v[r.key];return e.jsxs("div",{className:"settings-sync-conflict-modal__conflict-item",children:[e.jsx("div",{className:"settings-sync-conflict-modal__key",children:r.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:m}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:S})})]}),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:S})})]})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__resolution",children:[e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${r.key}`,checked:j.resolution==="local",onChange:()=>R(r.key,"local")}),"Keep Local"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${r.key}`,checked:j.resolution==="remote",onChange:()=>R(r.key,"remote")}),"Keep Remote"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${r.key}`,checked:j.resolution==="manual",onChange:()=>R(r.key,"manual")}),"Merge Manually"]})]}),j.resolution==="manual"&&e.jsx("textarea",{className:"settings-sync-conflict-modal__manual-input",value:j.manualValue??"",onChange:k=>_(r.key,k.target.value),placeholder:"Enter JSON value..."})]},r.key)})}),e.jsxs("div",{className:"settings-sync-conflict-modal__bulk-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>u("local"),type:"button",children:"Resolve All: Keep Local"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>u("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:l,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:P,disabled:b,children:b?"Resolving...":"Confirm"})]})]})})}const He=/(KEY|TOKEN|SECRET|PASSWORD)/i;function be(t){if(!t)return"—";const l=new Date(t);return Number.isNaN(l.getTime())?"—":l.toLocaleString()}function Gs(t){if(!t)return"—";const l=new Date(t),a=Date.now();if(Number.isNaN(l.getTime())||l.getTime()>a)return"—";const d=Math.floor((a-l.getTime())/1e3);if(d<60)return`${d}s`;const m=Math.floor(d/60);if(m<60)return`${m}m`;const f=Math.floor(m/60);return f<24?`${f}h ${m%60}m`:`${Math.floor(f/24)}d ${f%24}h`}function Zs(t){switch(t){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 Qs(t){return t==="running"?"success":t==="creating"||t==="recreating"||t==="restarting"?"warning":"error"}function et(t){return t?`${t.charAt(0).toUpperCase()}${t.slice(1)}`:"Unknown"}function st(t){if(!t)return"—";try{const l=new URL(t);return l.port?l.port:l.protocol==="https:"?"443":l.protocol==="http:"?"80":"—"}catch{return"—"}}function tt(t,l){return He.test(t)?"••••••••":l}function at({isOpen:t,onClose:l,node:a,projects:d,onUpdate:m,onHealthCheck:f,addToast:o,syncStatus:p,onPushSettings:c,onPullSettings:b,onSyncAuth:N,syncHistory:R=[],onResolveConflicts:_,managedDockerNode:u,containerStatus:P,onFetchContainerStatus:v,onFetchLogs:r,onUpdateDockerConfig:j,onFetchDockerConfigDiff:S}){const k=s.useRef(!0),[D,K]=s.useState(!1),[E,x]=s.useState(""),[g,C]=s.useState(""),[G,B]=s.useState(""),[q,W]=s.useState(2),[T,Y]=s.useState(!1),[O,Q]=s.useState(!1),[H,se]=s.useState(!1),[L,y]=s.useState(!1),[$,z]=s.useState(null),[F,ee]=s.useState(!1),[M]=s.useState([]),[A,J]=s.useState(P),[ae,le]=s.useState(!1),[ie,i]=s.useState(!1),[U,X]=s.useState(""),[te,oe]=s.useState(!1),[fe,Me]=s.useState(!1),[h,V]=s.useState(a?.dockerConfig??null),[Pe,Ee]=s.useState({}),[de,Re]=s.useState(!1),[qe,Ae]=s.useState(!1);s.useEffect(()=>(k.current=!0,()=>{k.current=!1}),[]),s.useEffect(()=>{J(P)},[P]),s.useEffect(()=>{if(!a||!t){K(!1),i(!1),X("");return}x(a.name),C(a.url??""),B(a.apiKey??""),W(a.maxConcurrent),K(!1),V(a.dockerConfig??null),Me(!1),Ee({})},[t,a]),s.useEffect(()=>{if(!t)return;const n=w=>{w.key==="Escape"&&(w.preventDefault(),l())};return document.addEventListener("keydown",n),()=>document.removeEventListener("keydown",n)},[t,l]);const ge=s.useMemo(()=>a?hs(d,a):[],[a,d]),Ye=s.useMemo(()=>u?u.hostConfig.type==="remote"?u.hostConfig.host??"—":"Local Docker":"—",[u]),Xe=s.useMemo(()=>!u?.resourceSizing?.cpuLimit&&!u?.resourceSizing?.memoryLimit?"Default":`${u.resourceSizing?.cpuLimit??"Default CPU"} / ${u.resourceSizing?.memoryLimit??"Default memory"}`,[u]),Je=s.useCallback(async()=>{if(a)try{if(await f(a.id),!k.current)return;o(`Health check completed for ${a.name}`,"success")}catch(n){if(!k.current)return;const w=n instanceof Error?n.message:"Health check failed";o(w,"error")}},[o,a,f]),We=s.useCallback(async()=>{if(!(!a||!c)){z(null),Q(!0);try{if(await c(a.id),!k.current)return;o("Settings pushed successfully","success")}catch(n){if(!k.current)return;const w=n instanceof Error?n.message:"Push settings failed";z(w),o(w,"error")}finally{k.current&&Q(!1)}}},[o,a,c]),Ge=s.useCallback(async()=>{if(!(!a||!b)){z(null),se(!0);try{if(await b(a.id),!k.current)return;o("Settings pulled successfully","success")}catch(n){if(!k.current)return;const w=n instanceof Error?n.message:"Pull settings failed";z(w),o(w,"error")}finally{k.current&&se(!1)}}},[o,a,b]),Ze=s.useCallback(async()=>{if(!(!a||!N)){z(null),y(!0);try{if(await N(a.id),!k.current)return;o("Auth credentials synced successfully","success")}catch(n){if(!k.current)return;const w=n instanceof Error?n.message:"Auth sync failed";z(w),o(w,"error")}finally{k.current&&y(!1)}}},[o,a,N]),Qe=s.useCallback(()=>{z(null)},[]),es=s.useCallback(async()=>{if(!(!u||!v)){le(!0);try{const n=await v(u.id);if(!k.current)return;J(n)}catch(n){const w=n instanceof Error?n.message:"Failed to fetch container status";o(w,"error")}finally{k.current&&le(!1)}}},[o,u,v]),ss=s.useCallback(async()=>{if(!(!u||!r)){i(!0),oe(!0);try{const n=await r(u.id);if(!k.current)return;X(n)}catch(n){if(!k.current)return;X("");const w=n instanceof Error?n.message:"Failed to fetch container logs";o(w,"error")}finally{k.current&&oe(!1)}}},[o,u,r]),ts=s.useCallback(async()=>{if(!a||T)return;const n=E.trim();if(!n){o("Name is required","error");return}if(a.type==="remote"&&!g.trim()){o("URL is required for remote nodes","error");return}if(!Number.isFinite(q)||q<1){o("Concurrency must be at least 1","error");return}Y(!0);try{await m(a.id,{name:n,url:a.type==="remote"&&g.trim()||void 0,apiKey:a.type==="remote"&&G||void 0,maxConcurrent:q}),o(`Updated ${n}`,"success"),K(!1)}catch(w){const Z=w instanceof Error?w.message:"Failed to update node";o(Z,"error")}finally{Y(!1)}},[o,G,T,q,E,a,m,g]);s.useEffect(()=>{!a?.dockerConfig||!S||!t||S(a.id).then(n=>{k.current&&Ae(n.needsRecreate)}).catch(()=>{k.current&&Ae(!1)})},[t,a,S]);const as=s.useCallback(async()=>{if(!(!a||!h||!j||de)){Re(!0);try{const n=await j(a.id,{image:h.image,volumeMounts:h.volumeMounts,environment:h.environment,resources:h.resources,host:h.host,extraClis:h.extraClis,persistence:h.persistence,containerName:h.containerName});if(!k.current)return;V(n),o("Docker config saved","success")}catch(n){if(!k.current)return;const w=n instanceof Error?n.message:"Failed to save Docker config";o(w,"error")}finally{k.current&&Re(!1)}}},[o,h,de,a,j]),ns=s.useCallback(()=>{a&&(x(a.name),C(a.url??""),B(a.apiKey??""),W(a.maxConcurrent),K(!1))},[a]);if(!t||!a)return null;const ne=A?.status??u?.status,rs=Qs(ne);return e.jsxs("div",{className:"modal-overlay open",onClick:l,children:[e.jsxs("div",{className:"modal modal-lg node-detail-modal",onClick:n=>n.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":`Node details for ${a.name}`,children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Node Details"}),e.jsx("button",{className:"modal-close",onClick:l,"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"}),!D&&e.jsxs("button",{className:"btn btn-sm",onClick:()=>K(!0),children:[e.jsx(fs,{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"}),D?e.jsx("input",{className:"input",value:E,onChange:n=>x(n.target.value),disabled:T}):e.jsx("strong",{children:a.name})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Type"}),e.jsx("strong",{children:a.type==="local"?"Local":"Remote"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Status"}),e.jsx("strong",{children:a.status})]}),e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),D?e.jsx("input",{className:"input",type:"number",min:1,max:10,value:q,onChange:n=>W(Number(n.target.value)),disabled:T}):e.jsx("strong",{children:a.maxConcurrent})]}),a.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"}),D?e.jsx("input",{className:"input",value:g,onChange:n=>C(n.target.value),disabled:T}):e.jsx("strong",{children:a.url??"—"})]}),e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"API Key"}),D?e.jsx("input",{className:"input",type:"password",value:G,onChange:n=>B(n.target.value),placeholder:"Leave blank to keep unchanged",disabled:T}):e.jsx("strong",{children:a.apiKey?"••••••••":"Not configured"})]})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Created"}),e.jsx("strong",{children:be(a.createdAt)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Updated"}),e.jsx("strong",{children:be(a.updatedAt)})]})]}),D&&e.jsxs("div",{className:"node-detail-modal__edit-actions",children:[e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:ts,disabled:T,children:[e.jsx(Le,{size:14}),T?"Saving...":"Save"]}),e.jsxs("button",{className:"btn btn-sm",onClick:ns,disabled:T,children:[e.jsx(me,{size:14}),"Cancel"]})]})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsxs("h4",{children:[a.type==="local"?"Projects":"Assigned Projects"," (",ge.length,")"]}),ge.length===0?e.jsx("p",{className:"node-detail-modal__empty",children:a.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:ge.map(n=>e.jsxs("li",{className:"node-detail-modal__project-item",children:[e.jsx("span",{children:n.name}),e.jsx("code",{children:n.id})]},n.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:a.status})]}),e.jsxs("span",{children:["Last check: ",e.jsx("strong",{children:be(a.updatedAt)})]})]})]}),h&&e.jsxs("section",{className:"node-detail-modal__section node-detail-modal__docker-config",children:[e.jsxs("button",{className:"btn btn-sm node-detail-modal__docker-toggle",onClick:()=>Me(n=>!n),"aria-expanded":fe,children:[e.jsx(we,{size:14,className:fe?"node-detail-modal__docker-toggle-icon--expanded":""}),"Docker Configuration"]}),fe&&e.jsxs("div",{className:"node-detail-modal__docker-config-content",children:[e.jsx("div",{className:"node-detail-modal__grid",children:e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"Image"}),e.jsx("input",{className:"input",value:h.image,onChange:n=>V({...h,image:n.target.value})})]})}),e.jsxs("details",{children:[e.jsx("summary",{children:"Volume Mounts"}),e.jsxs("div",{className:"node-detail-modal__docker-list",children:[h.volumeMounts.map((n,w)=>e.jsxs("div",{className:"node-detail-modal__docker-row",children:[e.jsx("input",{className:"input",value:n.hostPath,placeholder:"Host path",onChange:Z=>{const I=[...h.volumeMounts];I[w]={...I[w],hostPath:Z.target.value},V({...h,volumeMounts:I})}}),e.jsx("input",{className:"input",value:n.containerPath,placeholder:"Container path",onChange:Z=>{const I=[...h.volumeMounts];I[w]={...I[w],containerPath:Z.target.value},V({...h,volumeMounts:I})}}),e.jsxs("select",{className:"input",value:n.mode??"rw",onChange:Z=>{const I=[...h.volumeMounts];I[w]={...I[w],mode:Z.target.value},V({...h,volumeMounts:I})},children:[e.jsx("option",{value:"rw",children:"rw"}),e.jsx("option",{value:"ro",children:"ro"})]}),e.jsxs("select",{className:"input",value:n.type??"volume",onChange:Z=>{const I=[...h.volumeMounts];I[w]={...I[w],type:Z.target.value},V({...h,volumeMounts:I})},children:[e.jsx("option",{value:"volume",children:"volume"}),e.jsx("option",{value:"bind",children:"bind"})]}),e.jsx("button",{className:"btn btn-sm",onClick:()=>V({...h,volumeMounts:h.volumeMounts.filter((Z,I)=>I!==w)}),children:"Remove"})]},`${n.hostPath}-${n.containerPath}-${w}`)),e.jsx("button",{className:"btn btn-sm",onClick:()=>V({...h,volumeMounts:[...h.volumeMounts,{hostPath:"",containerPath:"",mode:"rw",type:"volume"}]}),children:"Add Mount"})]})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Environment Variables"}),e.jsxs("div",{className:"node-detail-modal__docker-list",children:[Object.entries(h.environment).map(([n,w])=>{const Z=He.test(n)&&!Pe[n];return e.jsxs("div",{className:"node-detail-modal__docker-row",children:[e.jsx("input",{className:"input",value:n,onChange:I=>{const xe={...h.environment};delete xe[n],xe[I.target.value]=w,V({...h,environment:xe})}}),e.jsx("input",{className:"input",value:Z?"***":String(w),onChange:I=>V({...h,environment:{...h.environment,[n]:I.target.value}})}),e.jsx("button",{className:"btn btn-sm",onClick:()=>Ee(I=>({...I,[n]:!I[n]})),children:Pe[n]?e.jsx(gs,{size:14}):e.jsx(xs,{size:14})}),e.jsx("button",{className:"btn btn-sm",onClick:()=>{const I={...h.environment};delete I[n],V({...h,environment:I})},children:"Remove"})]},n)}),e.jsx("button",{className:"btn btn-sm",onClick:()=>{const n=`NEW_VAR_${Object.keys(h.environment).length+1}`;V({...h,environment:{...h.environment,[n]:""}})},children:"Add Variable"})]})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Resources"}),e.jsxs("div",{className:"node-detail-modal__docker-stack",children:[e.jsx("input",{className:"input",type:"number",placeholder:"Memory bytes (2 GB = 2147483648)",value:h.resources?.memoryBytes??"",onChange:n=>V({...h,resources:{...h.resources,memoryBytes:n.target.value?Number(n.target.value):void 0}})}),e.jsx("input",{className:"input",type:"number",placeholder:"CPU count",value:h.resources?.cpuCount??"",onChange:n=>V({...h,resources:{...h.resources,cpuCount:n.target.value?Number(n.target.value):void 0}})}),e.jsx("input",{className:"input",type:"number",placeholder:"PIDs limit",value:h.resources?.pidsLimit??"",onChange:n=>V({...h,resources:{...h.resources,pidsLimit:n.target.value?Number(n.target.value):void 0}})})]})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Host Config"}),e.jsxs("div",{className:"node-detail-modal__docker-stack",children:[e.jsx("input",{className:"input",placeholder:"Context name",value:h.host?.contextName??"",onChange:n=>V({...h,host:{...h.host,contextName:n.target.value}})}),e.jsx("input",{className:"input",placeholder:"Docker host URL",value:h.host?.dockerHost??"",onChange:n=>V({...h,host:{...h.host,dockerHost:n.target.value}})}),e.jsx("input",{className:"input",placeholder:"TLS CA cert path",value:h.host?.tlsCaCert??"",onChange:n=>V({...h,host:{...h.host,tlsCaCert:n.target.value}})}),e.jsx("input",{className:"input",placeholder:"TLS cert path",value:h.host?.tlsCert??"",onChange:n=>V({...h,host:{...h.host,tlsCert:n.target.value}})}),e.jsx("input",{className:"input",placeholder:"TLS key path",value:h.host?.tlsKey??"",onChange:n=>V({...h,host:{...h.host,tlsKey:n.target.value}})}),e.jsxs("label",{className:"node-detail-modal__checkbox",children:[e.jsx("input",{type:"checkbox",checked:h.host?.tlsVerify??!0,onChange:n=>V({...h,host:{...h.host,tlsVerify:n.target.checked}})}),"TLS verify"]})]})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Extra CLIs"}),e.jsxs("div",{className:"node-detail-modal__docker-list",children:[(h.extraClis??[]).map((n,w)=>e.jsxs("div",{className:"node-detail-modal__docker-row",children:[e.jsx("input",{className:"input",value:n,onChange:Z=>{const I=[...h.extraClis??[]];I[w]=Z.target.value,V({...h,extraClis:I})}}),e.jsx("button",{className:"btn btn-sm",onClick:()=>V({...h,extraClis:(h.extraClis??[]).filter((Z,I)=>I!==w)}),children:"Remove"})]},`${n}-${w}`)),e.jsx("button",{className:"btn btn-sm",onClick:()=>V({...h,extraClis:[...h.extraClis??[],""]}),children:"Add CLI"})]})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Persistence"}),e.jsxs("div",{className:"node-detail-modal__docker-stack",children:[e.jsx("input",{className:"input",placeholder:"Volume name",value:h.persistence?.volumeName??"",onChange:n=>V({...h,persistence:{...h.persistence,volumeName:n.target.value}})}),e.jsxs("label",{className:"node-detail-modal__checkbox",children:[e.jsx("input",{type:"checkbox",checked:h.persistence?.retainOnDelete??!1,onChange:n=>V({...h,persistence:{...h.persistence,retainOnDelete:n.target.checked}})}),"Retain on delete"]})]})]}),e.jsxs("div",{className:"node-detail-modal__docker-meta",children:[e.jsxs("span",{children:["Config v",h.configVersion," • Updated ",ke(h.lastUpdated??a.updatedAt)]}),qe&&e.jsx("span",{className:"node-detail-modal__docker-recreate",children:"Needs Recreate"})]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>void as(),disabled:de,children:[e.jsx(Le,{size:14}),de?"Saving...":"Save Docker Config"]})]})]}),u&&e.jsxs("section",{className:"node-detail-modal__section docker-management",children:[e.jsx("h4",{children:"Docker Management"}),e.jsxs("div",{className:"docker-management__status-card",children:[e.jsxs("div",{className:"docker-management__status-row",children:[e.jsx("span",{className:`docker-management__status-dot docker-management__status-dot--${rs}`,"aria-hidden":!0}),e.jsx("strong",{children:et(ne)}),(ne==="creating"||ne==="recreating"||ne==="restarting")&&e.jsx($e,{size:14,className:"spin","aria-hidden":!0})]}),e.jsxs("div",{className:"docker-management__status-meta",children:[ne==="running"&&e.jsxs("span",{children:["Uptime: ",Gs(A?.startedAt)]}),ne!=="running"&&A?.exitCode!==void 0&&e.jsxs("span",{children:["Exit code: ",A.exitCode]}),(A?.error||u.errorMessage)&&e.jsx("span",{children:A?.error??u.errorMessage})]}),e.jsx("button",{className:"btn btn-sm",onClick:()=>void es(),disabled:!v||ae,children:ae?"Refreshing...":"Refresh Status"})]}),e.jsxs("div",{className:"node-detail-modal__grid docker-management__info-grid",children:[e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Image"}),e.jsx("strong",{children:e.jsxs("code",{children:[u.imageName,":",u.imageTag]})})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Container ID"}),e.jsx("strong",{children:e.jsx("code",{children:u.containerId?u.containerId.slice(0,12):"—"})})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Host"}),e.jsx("strong",{children:Ye})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Persistent Storage"}),e.jsx("strong",{children:u.persistentStorage?"Yes":"No"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Port"}),e.jsx("strong",{children:st(u.reachableUrl)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Resource Sizing"}),e.jsx("strong",{children:Xe})]})]}),e.jsxs("div",{className:"docker-management__actions",children:[e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx(Fe,{size:14}),"Start"]}),e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx(Ue,{size:14}),"Stop"]}),e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx($e,{size:14}),"Restart"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void ss(),disabled:!r,children:[e.jsx(ps,{size:14}),"View Logs"]})]}),ie&&e.jsxs("div",{className:"docker-management__log-viewer",children:[e.jsxs("div",{className:"docker-management__log-viewer-header",children:[e.jsx("strong",{children:"Container Logs"}),e.jsx("button",{className:"btn-icon",onClick:()=>i(!1),"aria-label":"Close logs",children:e.jsx(me,{size:14})})]}),te?e.jsx("p",{children:"Fetching logs..."}):e.jsx("pre",{children:U.trim()||"No logs available"})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Environment Variables"}),e.jsx("dl",{className:"docker-management__env-list",children:Object.entries(u.envVars).map(([n,w])=>e.jsxs("div",{children:[e.jsx("dt",{children:n}),e.jsx("dd",{children:tt(n,w)})]},n))})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Volume Mounts"}),e.jsx("ul",{className:"docker-management__mounts-list",children:u.volumeMounts.map(n=>e.jsxs("li",{children:[e.jsxs("span",{children:[n.hostPath," → ",n.containerPath]}),n.readOnly&&e.jsx("span",{className:"node-card__type-badge",children:"Read-only"})]},`${n.hostPath}:${n.containerPath}`))})]})]}),a.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Settings Sync"}),p&&e.jsxs("div",{className:"node-detail-modal__sync-status",children:[e.jsx("span",{className:`node-detail-modal__sync-dot ${Zs(p.syncState)}`,"aria-hidden":!0}),e.jsxs("span",{children:["Last sync: ",e.jsx("strong",{children:p.lastSyncAt?ke(p.lastSyncAt):"Never synced"})]}),p.diffCount>0&&e.jsxs("span",{className:"node-detail-modal__sync-diff",children:["Differences: ",e.jsx("strong",{children:p.diffCount})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:We,disabled:O||!c,children:[e.jsx(Te,{size:14}),O?"Pushing...":"Push Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:Ge,disabled:H||!b,children:[e.jsx(Be,{size:14}),H?"Pulling...":"Pull Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:Ze,disabled:L||!N,children:[e.jsx(Ve,{size:14}),L?"Syncing...":"Sync Auth"]})]}),$&&e.jsxs("div",{className:"node-detail-modal__sync-error",children:[e.jsx("span",{children:$}),e.jsx("button",{className:"node-detail-modal__sync-error-dismiss",onClick:Qe,"aria-label":"Dismiss error",children:e.jsx(me,{size:14})})]})]}),a.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Sync History"}),e.jsx(Xs,{nodeId:a.id,entries:R,singleNode:!0})]})]}),e.jsxs("div",{className:"modal-actions node-detail-modal__actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:Je,children:[e.jsx(Oe,{size:14}),"Health Check"]}),e.jsx("button",{className:"btn btn-sm",onClick:l,children:"Close"})]})]}),a.type==="remote"&&e.jsx(Ws,{isOpen:F,onClose:()=>ee(!1),onResolve:_??(async()=>{}),conflicts:M,localNodeName:"Local",remoteNodeName:a.name,addToast:o})]})}const nt=15e3,rt=1e3;function lt(){const[t,l]=s.useState([]),[a,d]=s.useState(!0),[m,f]=s.useState(null),o=s.useRef(null),p=s.useRef(0),c=s.useCallback(async()=>{try{f(null);const _=await De();l(_)}catch(_){f(_ instanceof Error?_.message:"Failed to fetch managed Docker nodes")}},[]);s.useEffect(()=>{let _=!1;async function u(){d(!0);try{const v=await De();_||(l(v),f(null))}catch(v){_||f(v instanceof Error?v.message:"Failed to fetch managed Docker nodes")}finally{_||d(!1)}}u();const P=()=>{if(document.visibilityState!=="visible")return;const v=Date.now();v-p.current<rt||(p.current=v,c())};return document.addEventListener("visibilitychange",P),()=>{_=!0,document.removeEventListener("visibilitychange",P)}},[c]),s.useEffect(()=>{if(!a)return o.current=setInterval(()=>{c()},nt),()=>{o.current&&(clearInterval(o.current),o.current=null)}},[a,c]);const b=s.useCallback(async _=>js(_),[]),N=s.useCallback(async(_,u)=>(await bs(_,u)).logs,[]),R=s.useCallback(async _=>{const u=await vs(_),P={...u,nodeId:u.nodeId??void 0,containerId:u.containerId??void 0,status:u.status,hostConfig:{type:u.hostConfig.host||u.hostConfig.context?"remote":"local",host:u.hostConfig.host,context:u.hostConfig.context},reachableUrl:u.reachableUrl??void 0,volumeMounts:u.volumeMounts.map(v=>({hostPath:v.hostPath,containerPath:v.containerPath,readOnly:v.mode==="ro"?!0:void 0})),persistentStorage:u.persistentStorage,resourceSizing:{cpuLimit:u.resourceSizing.cpus!==void 0?String(u.resourceSizing.cpus):void 0,memoryLimit:u.resourceSizing.memoryMB!==void 0?`${u.resourceSizing.memoryMB}MB`:void 0},errorMessage:u.errorMessage??void 0};return l(v=>[...v,P]),P},[]);return{dockerNodes:t,loading:a,error:m,refresh:c,getContainerStatus:b,getLogs:N,create:R}}function mt({addToast:t,onClose:l}){const{nodes:a,loading:d,error:m,refresh:f,register:o,update:p,unregister:c,healthCheck:b,patchDockerConfig:N,fetchDockerDiff:R,discoverRemoteProjects:_}=ys(),{projects:u,refresh:P}=_s(),{syncStatusMap:v,pushSettings:r,pullSettings:j,syncAuth:S,trackNode:k,getAuthSyncState:D,getAuthProviders:K}=Rs(),{dockerNodes:E,loading:x,refresh:g,getContainerStatus:C,getLogs:G,create:B}=lt(),[q,W]=s.useState(!1),[T,Y]=s.useState(!1),[O,Q]=s.useState(null);s.useEffect(()=>{const M=a.filter(A=>A.type==="remote");for(const A of M)k(A.id)},[a,k]),s.useEffect(()=>{if(!O)return;const M=a.find(A=>A.id===O.id)??null;Q(M)},[a,O]);const H=s.useMemo(()=>{const M=a.length,A=a.filter(i=>i.status==="online").length,J=a.filter(i=>i.status==="offline"||i.status==="error").length,ae=a.filter(i=>i.type==="remote").length,le=a.filter(i=>i.type==="remote"&&v[i.id]&&pe(v[i.id]).syncState==="synced").length,ie=E.length;return{total:M,online:A,offline:J,remote:ae,synced:le,docker:ie}},[E.length,a,v]),se=s.useCallback(async M=>{await o(M),await P()},[P,o]),L=s.useCallback(async M=>{try{await B(M),t(`Docker node "${M.name}" created`,"success"),Y(!1)}catch(A){const J=A instanceof Error?A.message:"Failed to create Docker node";throw t(J,"error"),A}},[t,B]),y=s.useMemo(()=>{const M=new Map;for(const A of E)A.nodeId&&M.set(A.nodeId,A);return M},[E]),$=s.useCallback(async()=>{try{await Promise.all([f(),g()])}catch{t("Failed to refresh nodes","error")}},[t,f,g]),z=s.useCallback(async M=>{try{await b(M),t("Node health check complete","success")}catch(A){const J=A instanceof Error?A.message:"Health check failed";t(J,"error")}},[t,b]),F=s.useCallback(async M=>{try{await c(M),t("Node removed","success"),O?.id===M&&Q(null)}catch(A){const J=A instanceof Error?A.message:"Failed to remove node";t(J,"error")}},[t,O?.id,c]),ee=s.useCallback(async(M,A)=>{await p(M,A)},[p]);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(Ke,{size:20}),"Nodes"]}),e.jsxs("span",{className:"nodes-view-count",children:[a.length," registered"]})]}),e.jsxs("div",{className:"nodes-view-actions",children:[e.jsx("button",{className:"btn-icon nodes-view-close",onClick:l,"aria-label":"Close nodes view",children:e.jsx(me,{size:16})}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void $(),disabled:d||x,children:[e.jsx(Ne,{size:14,className:d?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>W(!0),children:[e.jsx(he,{size:14}),"Add Node"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>Y(!0),title:"Add a managed Docker node",children:[e.jsx(ye,{size:14}),"Add 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:H.total})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--online","data-testid":"nodes-stat-online",children:[e.jsxs("span",{children:[e.jsx(Ms,{size:14})," Online"]}),e.jsx("strong",{children:H.online})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--offline","data-testid":"nodes-stat-offline",children:[e.jsxs("span",{children:[e.jsx(Ss,{size:14})," Offline"]}),e.jsx("strong",{children:H.offline})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-remote",children:[e.jsxs("span",{children:[e.jsx(Ns,{size:14})," Remote"]}),e.jsx("strong",{children:H.remote})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--synced","data-testid":"nodes-stat-synced",children:[e.jsxs("span",{children:[e.jsx(Ne,{size:14})," Synced"]}),e.jsx("strong",{children:H.synced})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-docker",children:[e.jsxs("span",{children:[e.jsx(ye,{size:14})," Docker"]}),e.jsx("strong",{children:H.docker})]})]}),m&&e.jsx("div",{className:"nodes-view-error",children:m}),!d&&a.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:a})]}),d?e.jsx("div",{className:"nodes-view-grid",children:Array.from({length:4}).map((M,A)=>e.jsx("div",{className:"node-card node-card--loading","aria-hidden":!0},A))}):a.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:()=>W(!0),children:[e.jsx(he,{size:14}),"Add First Node"]})]}):e.jsx("div",{className:"nodes-view-grid",children:a.map(M=>{const A=M.type==="remote"&&v[M.id]?pe(v[M.id]):void 0;return e.jsx(Is,{node:M,projects:u,onHealthCheck:J=>{z(J)},onEdit:J=>Q(J),onRemove:J=>{F(J)},isLoading:d,syncStatus:A,authSyncState:M.type==="remote"?D(M.id):void 0,authSyncProviders:M.type==="remote"?K(M.id):void 0,managedDockerNode:y.get(M.id)},M.id)})}),e.jsx(Bs,{isOpen:q,onClose:()=>W(!1),onSubmit:se,onDiscoverRemoteProjects:_,addToast:t,projects:u}),e.jsx(Ys,{isOpen:T,onClose:()=>Y(!1),onSubmit:L,addToast:t}),e.jsx(at,{isOpen:O!==null,onClose:()=>Q(null),node:O,projects:u,onUpdate:ee,onHealthCheck:z,addToast:t,syncStatus:O?.type==="remote"&&O&&v[O.id]?pe(v[O.id]):void 0,onPushSettings:r,onPullSettings:j,onSyncAuth:S,managedDockerNode:O?y.get(O.id):void 0,onFetchContainerStatus:C,onFetchLogs:G,onUpdateDockerConfig:N,onFetchDockerConfigDiff:R})]})}export{mt as NodesView};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as g,j as e}from"./vendor-react-K0fH_qHe.js";import{v as fe,ef as ye,eg as Y,s as je,X as Z,ar as Ne,aP as Se,I as T,aW as ee,W as se,R as ve,eh as we,an as Ce,ei as Ie,ej as $e,cs as Pe,ek as Re,el as ke,em as Ee,en as Be,eo as te,cp as Ae,ep as Fe}from"./index-Bdw6llW6.js";import{D as Le}from"./DirectoryPicker-xedtR-Rd.js";import"./vendor-xterm-DzcZoU0P.js";import"./folder-open-BZuKESeq.js";const ie="fusion-plugin-agent-browser",ne={enabled:{type:"boolean",label:"Enable Agent Browser",group:"General"},installChannel:{type:"enum",label:"Install Channel",enumValues:["stable","beta","nightly"],defaultValue:"stable",group:"General"},commandTimeoutMs:{type:"number",label:"Command Timeout (ms)",defaultValue:12e4,group:"General"},headlessMode:{type:"boolean",label:"Headless Mode",defaultValue:!0,group:"Browser"},allowedDomains:{type:"array",label:"Allowed Domains",itemType:"string",group:"Browser"},promptExecutorSystem:{type:"string",label:"Executor System Prompt",multiline:!0,group:"Prompt Contributions"},promptExecutorTask:{type:"string",label:"Executor Task Prompt",multiline:!0,group:"Prompt Contributions"},promptTriage:{type:"string",label:"Triage Prompt",multiline:!0,group:"Prompt Contributions"},promptReviewer:{type:"string",label:"Reviewer Prompt",multiline:!0,group:"Prompt Contributions"},promptHeartbeat:{type:"string",label:"Heartbeat Prompt",multiline:!0,group:"Prompt Contributions"},skillExposure:{type:"enum",label:"Skill Exposure",enumValues:["none","selected","all"],defaultValue:"selected",group:"Skills"}},ae=[{id:"fusion-plugin-hermes-runtime",name:"Hermes Runtime",description:"Runtime provider for Hermes CLI-backed execution.",category:"runtime",path:"./plugins/fusion-plugin-hermes-runtime",experimental:!0},{id:"fusion-plugin-paperclip-runtime",name:"Paperclip Runtime",description:"Runtime provider for Paperclip agent connections.",category:"runtime",path:"./plugins/fusion-plugin-paperclip-runtime"},{id:"fusion-plugin-openclaw-runtime",name:"OpenClaw Runtime",description:"Runtime provider for OpenClaw execution.",category:"runtime",path:"./plugins/fusion-plugin-openclaw-runtime",experimental:!0},{id:"fusion-plugin-droid-runtime",name:"Droid Runtime",description:"Runtime provider for Droid CLI execution.",category:"runtime",path:"./plugins/fusion-plugin-droid-runtime",experimental:!0},{id:"fusion-plugin-dependency-graph",name:"Dependency Graph",description:"Dashboard plugin for task dependency graph visualization.",category:"integration",path:"./plugins/fusion-plugin-dependency-graph"},{id:"fusion-plugin-whatsapp-chat",name:"WhatsApp Chat",description:"Pairs to WhatsApp Web (multi-device) with QR or pairing code, then bridges direct chats to a Fusion agent.",category:"integration",path:"./plugins/fusion-plugin-whatsapp-chat"},{id:ie,name:"Agent Browser",description:"Built-in integration metadata. Package install support lands in FN-3101.",category:"integration",hasSetup:!0}],I={started:"var(--color-success)",loaded:"var(--color-warning)",error:"var(--color-error)",stopped:"var(--color-muted)",installed:"var(--color-info)"};function De(r){const o=r.settingsSchema,h=o&&Object.keys(o).length>0;return r.id!==ie?h?o:void 0:h?{...ne,...o}:ne}function Oe(r){const o=new Map,h=[];for(const[x,f]of Object.entries(r))if(f.group){const N=o.get(f.group)??[];N.push([x,f]),o.set(f.group,N)}else h.push([x,f]);return{grouped:o,ungrouped:h}}function Ve({addToast:r,projectId:o}){const[h,x]=g.useState([]),[f,N]=g.useState(!0),[le,$]=g.useState(!1),[w,P]=g.useState(""),[B,A]=g.useState(!1),[F,L]=g.useState(!1),[S,D]=g.useState(null),[l,R]=g.useState(null),[p,b]=g.useState({}),[re,O]=g.useState(!1),[z,U]=g.useState(null),[ce,k]=g.useState({}),[oe,G]=g.useState(null),[C,q]=g.useState(null),{confirm:ue}=fe(),m=g.useCallback(async()=>{try{N(!0);const s=await ye(o);x(s)}catch(s){r(`Failed to load plugins: ${s instanceof Error?s.message:String(s)}`,"error")}finally{N(!1)}},[o,r]);g.useEffect(()=>{m()},[m]),g.useEffect(()=>{const s=ae.filter(c=>c.hasSetup&&h.some(i=>i.id===c.id));if(s.length===0)return;let n=!1;return Promise.all(s.map(async c=>{try{const i=await Y(c.id,o);if(n)return;k(u=>({...u,[c.id]:i}))}catch{if(n)return;k(i=>({...i,[c.id]:{hasSetup:!0,setupCheckDeferred:!0,deferredReason:"plugin-not-started",pluginState:"installed"}}))}})),()=>{n=!0}},[h,o]);const de=g.useRef([]);de.current=h,g.useEffect(()=>{const s=o?`?projectId=${encodeURIComponent(o)}`:"",n=c=>{try{const i=JSON.parse(c.data);if(i.scope==="project"&&(i.projectId??o)!==o)return;switch(i.transition){case"installing":case"enabled":case"disabled":case"settings-updated":x(u=>{const a=u.findIndex(t=>t.id===i.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],enabled:i.enabled,state:i.state,settings:i.settings,error:i.error},t}else return m(),u});break;case"state-changed":x(u=>{const a=u.findIndex(t=>t.id===i.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],state:i.state,error:i.error},t}return u});break;case"uninstalled":x(u=>u.filter(a=>a.id!==i.pluginId));break;case"error":x(u=>{const a=u.findIndex(t=>t.id===i.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],state:i.state,error:i.error},t}return u});break}}catch{}};return je(`/api/events${s}`,{events:{"plugin:lifecycle":n},onReconnect:()=>{m()}})},[o,m]);const _=async()=>{if(!w.trim()){r("Please enter a plugin path","error");return}try{A(!0),await te({path:w,...F?{aiScanOnLoad:!0}:{}},o),r("Plugin installed globally","success"),$(!1),P(""),L(!1),await m()}catch(s){r(`Failed to install plugin: ${s instanceof Error?s.message:String(s)}`,"error")}finally{A(!1)}},pe=async s=>{if(!s.path){r(`${s.name} is built in and does not have an installable package yet`,"warning");return}try{U(s.id),await te({path:s.path},o),r(`${s.name} installed globally`,"success"),await m()}catch(n){r(`Failed to install ${s.name}: ${n instanceof Error?n.message:String(n)}`,"error")}finally{U(null)}},M=async s=>{try{q(s.id);const n=await Fe(s.id,o);if(!n.success){r(`Failed to install ${s.name} setup: ${n.error??"unknown error"}`,"error");return}r(`${s.name} setup installed`,"success"),G(s.id);const c=await Y(s.id,o);k(i=>({...i,[s.id]:c}))}catch(n){r(`Failed to install ${s.name} setup: ${n instanceof Error?n.message:String(n)}`,"error")}finally{q(null),G(null)}},V=async s=>{try{const n=await Ee(s.id,o);if(n.state==="error"){r(`Failed to enable ${s.name}: ${n.error??"Unknown error"}`,"error"),await m();return}r(`${s.name} enabled for this project`,"success"),await m()}catch(n){r(`Failed to enable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},W=async s=>{try{await ke(s.id,o),r(`${s.name} disabled for this project`,"success"),await m()}catch(n){r(`Failed to disable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},H=async s=>{try{D(s.id),await Re(s.id,o),r(`${s.name} reloaded`,"success"),await m()}catch(n){r(`Failed to reload plugin: ${n instanceof Error?n.message:String(n)}`,"error")}finally{D(null)}},J=async s=>{if(await ue({title:"Uninstall Plugin Globally",message:`Are you sure you want to uninstall "${s.name}" globally (all projects)?`,danger:!0}))try{await Be(s.id,o),r(`${s.name} uninstalled globally`,"success"),await m(),R(null)}catch(c){r(`Failed to uninstall plugin: ${c instanceof Error?c.message:String(c)}`,"error")}},ge=async(s,n)=>{try{await Ie(s.id,{aiScanOnLoad:n},o),r(`AI scan on load ${n?"enabled":"disabled"}`,"success"),await m()}catch(c){r(`Failed to update plugin: ${c instanceof Error?c.message:String(c)}`,"error")}},me=async s=>{try{await $e(s.id,o),r(`${s.name} rescanned`,"success"),await m()}catch(n){r(`Failed to rescan plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},E=async s=>{R(s);try{O(!0);const n=await Ae(s.id,o);b(n)}catch{b({})}finally{O(!1)}},he=async()=>{if(l)try{await Pe(l.id,p,o),r("Settings saved","success")}catch(s){r(`Failed to save settings: ${s instanceof Error?s.message:String(s)}`,"error")}};if(l)return e.jsxs("div",{className:"plugin-manager-detail","data-testid":"plugin-manager-detail",children:[e.jsxs("div",{className:"plugin-manager-detail-header",children:[e.jsx("button",{className:"btn-icon",onClick:()=>R(null),"aria-label":"Back to plugin list",children:e.jsx(Z,{size:16})}),e.jsxs("div",{className:"plugin-detail-title",children:[e.jsx("h4",{className:"plugin-detail-name",children:l.name}),e.jsx("span",{className:"plugin-state-badge",style:{color:I[l.state]||I.installed},children:l.state})]})]}),e.jsxs("div",{className:"plugin-detail-content",children:[e.jsxs("div",{className:"plugin-detail-card",children:[l.description&&e.jsx("p",{className:"plugin-description",children:l.description}),l.author&&e.jsxs("p",{className:"plugin-detail-meta-row",children:[e.jsx("span",{className:"text-muted",children:"Author:"}),l.author]}),l.homepage&&e.jsxs("p",{className:"plugin-detail-meta-row plugin-homepage",children:[e.jsx("span",{className:"text-muted",children:"Homepage:"}),e.jsxs("a",{href:l.homepage,target:"_blank",rel:"noopener noreferrer",children:[l.homepage,e.jsx(Ne,{size:12})]})]}),e.jsxs("p",{className:"plugin-detail-meta-row",children:[e.jsx("span",{className:"text-muted",children:"Version:"}),l.version]})]}),e.jsxs("div",{className:"plugin-detail-card",children:[e.jsx("h5",{className:"plugin-detail-section-heading",children:"Security Scan"}),e.jsxs("div",{className:"plugin-security-row",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:!!l.aiScanOnLoad,onChange:s=>void ge(l,s.target.checked)}),"Enable AI scan before load/reload"]}),e.jsxs("button",{className:"btn btn-secondary btn-sm",onClick:()=>void me(l),children:[e.jsx(Se,{size:14})," Rescan and Reload"]})]}),e.jsx("p",{className:"text-muted",children:"Turning this on only updates configuration. Use Rescan and Reload to run it now."}),l.lastSecurityScan?e.jsxs("div",{className:"plugin-security-results",children:[e.jsxs("div",{className:"plugin-security-header",children:[e.jsx("span",{className:`plugin-state-badge plugin-security-badge plugin-security-badge--${l.lastSecurityScan.verdict}`,children:l.lastSecurityScan.verdict}),e.jsx("span",{className:"text-muted",children:l.lastSecurityScan.scannedAt})]}),e.jsx("p",{className:"plugin-security-summary",children:l.lastSecurityScan.summary}),e.jsxs("details",{children:[e.jsxs("summary",{children:["Findings (",l.lastSecurityScan.findings.length,")"]}),e.jsx("ul",{className:"plugin-security-findings",children:l.lastSecurityScan.findings.map((s,n)=>e.jsxs("li",{children:[e.jsx("strong",{children:s.severity})," ",s.category," — ",s.file,": ",s.reason]},`${s.file}-${n}`))})]})]}):e.jsx("p",{className:"text-muted",children:"No security scan has been run yet."})]}),e.jsxs("div",{className:"plugin-detail-card",children:[e.jsx("h5",{className:"plugin-detail-section-heading",children:"Settings"}),re?e.jsx("p",{className:"text-muted",children:"Loading..."}):(()=>{const s=De(l);return s&&Object.keys(s).length>0?e.jsxs("div",{className:"plugin-settings-form",children:[(()=>{const{grouped:n,ungrouped:c}=Oe(s),i=[];c.length>0&&i.push({title:null,entries:c});for(const[u,a]of n.entries())i.push({title:u,entries:a});return i.map(u=>e.jsxs("div",{className:u.title?"plugin-settings-group":void 0,children:[u.title&&e.jsx("h6",{className:"plugin-settings-group-heading",children:u.title}),u.entries.map(([a,t])=>{const y=`setting-${a}-help`;return e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:`setting-${a}`,children:[t.label||a,t.required&&" *"]}),t.type==="string"&&!t.multiline&&e.jsx("input",{className:"input",type:"text",id:`setting-${a}`,value:p[a]??"",onChange:d=>b({...p,[a]:d.target.value}),placeholder:t.description,"aria-describedby":t.description&&!t.required?y:void 0}),t.type==="string"&&t.multiline&&e.jsx("textarea",{className:"input",id:`setting-${a}`,rows:4,value:p[a]??"",onChange:d=>b({...p,[a]:d.target.value}),placeholder:t.description,"aria-describedby":t.description&&!t.required?y:void 0}),t.type==="password"&&e.jsx("input",{className:"input",type:"password",id:`setting-${a}`,value:p[a]??"",onChange:d=>b({...p,[a]:d.target.value}),placeholder:t.description,"aria-describedby":t.description&&!t.required?y:void 0}),t.type==="number"&&e.jsx("input",{className:"input",type:"number",id:`setting-${a}`,value:p[a]??"",onChange:d=>b({...p,[a]:Number(d.target.value)}),"aria-describedby":t.description&&!t.required?y:void 0}),t.type==="boolean"&&e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:p[a]??!1,onChange:d=>b({...p,[a]:d.target.checked})}),t.description]}),t.type==="enum"&&e.jsxs("select",{className:"select",id:`setting-${a}`,value:p[a]??"",onChange:d=>b({...p,[a]:d.target.value}),"aria-describedby":t.description&&!t.required?y:void 0,children:[e.jsx("option",{value:"",children:"Select..."}),t.enumValues?.map(d=>e.jsx("option",{value:d,children:d},d))]}),t.type==="array"&&e.jsxs("div",{className:"plugin-settings-array",children:[p[a]?.map((d,j)=>e.jsxs("div",{className:"plugin-settings-array-item",children:[e.jsx("input",{className:"input",type:t.itemType==="number"?"number":"text",value:d??"",onChange:Q=>{const v=Q.target.value,X=[...p[a]||[]];X[j]=t.itemType==="number"?Number(v):v,b({...p,[a]:X})}}),e.jsx("button",{className:"btn-icon",onClick:()=>{const v=[...p[a]||[]];v.splice(j,1),b({...p,[a]:v})},"aria-label":"Remove item",children:e.jsx(Z,{size:14})})]},j)),e.jsxs("button",{className:"btn btn-secondary",onClick:()=>{const d=p[a]||[],j=t.itemType==="number"?0:"";b({...p,[a]:[...d,j]})},children:[e.jsx(T,{size:14})," Add Item"]})]}),t.description&&!t.required&&!t.multiline&&e.jsx("span",{id:y,className:"form-help",children:t.description})]},a)})]},u.title??"ungrouped"))})(),e.jsx("button",{className:"btn btn-primary",onClick:he,children:"Save Settings"})]}):e.jsx("p",{className:"text-muted",children:"No configurable settings."})})()]}),e.jsxs("div",{className:"plugin-detail-actions",children:[l.state==="started"&&e.jsxs("button",{className:"btn btn-secondary",onClick:()=>H(l),disabled:S===l.id,children:[e.jsx(ee,{size:14,className:S===l.id?"spin":""}),S===l.id?"Reloading...":"Reload"]}),l.enabled?e.jsx("button",{className:"btn btn-secondary",onClick:()=>W(l),children:"Disable in Project"}):e.jsx("button",{className:"btn btn-primary",onClick:()=>V(l),children:"Enable in Project"}),e.jsxs("button",{className:"btn btn-danger",onClick:()=>J(l),children:[e.jsx(se,{size:14})," Uninstall Globally"]})]})]})]});const be=new Map(h.map(s=>[s.id,s])),K=h,xe=()=>e.jsxs("section",{className:"plugin-builtins-section","aria-label":"Built-in Plugins",children:[e.jsxs("div",{className:"plugin-builtins-header",children:[e.jsx("h4",{className:"plugin-builtins-heading",children:"Built-in Plugins"}),e.jsx("p",{className:"plugin-builtins-description",children:"Built-in plugin catalog for runtimes and integrations."})]}),e.jsx("div",{className:"plugin-builtins-list","aria-label":"Built-in plugin recommendations",children:ae.map(s=>{const n=be.get(s.id),c=!!n,i=ce[s.id],u=!!(i&&"setupCheckDeferred"in i&&i.setupCheckDeferred),a=i&&"status"in i?i.status:void 0,t=c&&s.hasSetup&&i?.hasSetup&&!u&&n?.state==="started"&&(a==="not-installed"||a==="error"),y=c&&i?.hasSetup&&a==="installed",d=oe===s.id,j=!s.path;return e.jsxs("div",{className:"plugin-builtins-item",children:[e.jsxs("div",{className:"plugin-builtins-meta",children:[e.jsx("span",{className:"plugin-builtins-name",children:s.name}),s.experimental&&e.jsx("span",{className:"plugin-builtins-runtime-badge",children:"Experimental"}),e.jsx("span",{className:"plugin-builtins-runtime-badge",children:s.category}),e.jsx("span",{className:`plugin-builtins-status ${c?"plugin-builtins-status--installed":"plugin-builtins-status--available"}`,children:c?"Installed":j?"Built in":"Not installed"}),t&&e.jsx("span",{className:"plugin-builtins-setup-status plugin-builtins-setup-status--warning",children:"Setup required"}),y&&e.jsx("span",{className:"plugin-builtins-setup-status plugin-builtins-setup-status--ready",children:"Setup ready"}),d&&e.jsx("span",{className:"plugin-builtins-setup-status plugin-builtins-setup-status--pending",children:"Checking setup..."}),u&&e.jsx("span",{className:"plugin-builtins-setup-status plugin-builtins-setup-status--deferred",children:"Start plugin to check setup"}),e.jsx("span",{className:"plugin-builtins-description-text",children:s.description})]}),j?c&&t?e.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>void M(s),disabled:C===s.id||d,children:C===s.id?"Setting up...":"Install Setup"}):c&&n?e.jsx("button",{className:"btn btn-secondary btn-sm",onClick:()=>void E(n),children:"Manage"}):e.jsx("span",{className:"plugin-builtins-metadata-only",children:"Built-in metadata only"}):e.jsx("button",{className:`btn ${c&&!t?"btn-secondary":"btn-primary"} btn-sm`,onClick:()=>{if(!c){pe(s);return}if(t){M(s);return}n&&E(n)},disabled:z===s.id||C===s.id||d,children:c?t?C===s.id?"Setting up...":"Install Setup":"Manage":z===s.id?"Installing...":`Install ${s.name}`})]},s.id)})})]});return e.jsxs("div",{className:"plugin-manager","data-testid":"plugin-manager",children:[e.jsxs("div",{className:"plugin-manager-header",children:[e.jsx("span",{className:"plugin-manager-header-title",children:"Installed Plugins"}),e.jsxs("div",{className:"plugin-manager-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:m,title:"Refresh","aria-label":"Refresh plugin list",children:[e.jsx(ve,{size:14,className:f?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>$(!0),children:[e.jsx(T,{size:14})," Install"]})]})]}),le&&e.jsxs("div",{className:"plugin-install-form",children:[e.jsxs("p",{className:"plugin-install-hint",children:["Browse to a plugin package root (contains ",e.jsx("code",{children:"manifest.json"}),") or a built ",e.jsx("code",{children:"dist"})," directory."]}),e.jsx(Le,{value:w,onChange:P,placeholder:"Absolute path to plugin directory or dist folder",onInputKeyDown:s=>{s.key==="Enter"&&(s.preventDefault(),_())}}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:F,onChange:s=>L(s.target.checked)}),"Enable AI security scan on load"]}),e.jsxs("div",{className:"plugin-install-actions",children:[e.jsx("button",{className:"btn btn-primary",onClick:_,disabled:B||!w.trim(),children:B?"Installing...":"Install Plugin Globally"}),e.jsx("button",{className:"btn btn-secondary",onClick:()=>{$(!1),P("")},children:"Cancel"})]})]}),f?e.jsx("div",{className:"settings-empty-state",children:"Loading plugins..."}):e.jsxs(e.Fragment,{children:[K.length===0?e.jsxs("div",{className:"settings-empty-state",children:[e.jsx(we,{size:32,className:"text-muted"}),e.jsx("p",{children:"No plugins installed."}),e.jsx("p",{className:"text-muted",children:"Install a plugin to get started, or use the built-in catalog below."})]}):e.jsx("div",{className:"plugin-list",children:K.map(s=>e.jsxs("div",{className:"plugin-item",children:[e.jsxs("div",{className:"plugin-info",children:[e.jsx("span",{className:"plugin-name",children:s.name}),e.jsxs("span",{className:"plugin-version text-muted",children:["v",s.version]}),e.jsx("span",{className:"plugin-state-badge",style:{color:I[s.state]||I.installed},children:s.state})]}),e.jsxs("div",{className:"plugin-actions",children:[s.state==="started"&&e.jsx("button",{className:"btn-icon",onClick:()=>H(s),disabled:S===s.id,title:"Reload",children:e.jsx(ee,{size:14,className:S===s.id?"spin":""})}),e.jsxs("label",{className:"toggle-switch",children:[e.jsx("input",{type:"checkbox",checked:s.enabled,onChange:()=>s.enabled?W(s):V(s),"aria-label":`${s.enabled?"Disable":"Enable"} ${s.name}`}),e.jsx("span",{className:"toggle-slider"})]}),e.jsx("button",{className:"btn-icon",onClick:()=>E(s),title:"Settings",children:e.jsx(Ce,{size:14})}),e.jsx("button",{className:"btn-icon",onClick:()=>J(s),title:"Uninstall globally",children:e.jsx(se,{size:14})})]})]},s.id))}),xe()]})]})}export{ne as AGENT_BROWSER_SETTINGS_SCHEMA,ie as BUILTIN_AGENT_BROWSER_PLUGIN_ID,Ve as PluginManager,I as STATE_COLORS};
|