@runfusion/fusion 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +23464 -10700
- package/dist/client/.vite/manifest.json +61 -61
- package/dist/client/assets/{AgentDetailView-CnFf_eBZ.js → AgentDetailView-BACu9GYE.js} +3 -3
- package/dist/client/assets/{AgentPermissionPolicyEditor-Cmkt9Z01.js → AgentPermissionPolicyEditor-tNNlcCDk.js} +2 -2
- package/dist/client/assets/AgentsView-CPpHwjn3.js +29 -0
- package/dist/client/assets/ChatView-CCAUA7HB.js +6 -0
- package/dist/client/assets/DevServerView-BlxSS8Uu.js +1 -0
- package/dist/client/assets/{DirectoryPicker-DctpCNrd.js → DirectoryPicker-ioTzF36r.js} +1 -1
- package/dist/client/assets/{DocumentsView-DORp5JjC.js → DocumentsView-CsDb8dPw.js} +1 -1
- package/dist/client/assets/{EvalsView-CYVJ1pbc.js → EvalsView-I0GhxVhm.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-BULVNAiq.js → ExperimentalAgentOnboardingModal-Cr6g_jok.js} +2 -2
- package/dist/client/assets/{GoalsView-bmpZKOI_.js → GoalsView-DXJxe6D4.js} +1 -1
- package/dist/client/assets/{InsightsView-mmtem0RU.js → InsightsView-BaIhzpvX.js} +1 -1
- package/dist/client/assets/{MemoryView-HVpO1fCH.js → MemoryView-DlmcI0ca.js} +2 -2
- package/dist/client/assets/NodesView-vc4T0uCy.js +14 -0
- package/dist/client/assets/{PiExtensionsManager-Cyfas2VT.js → PiExtensionsManager-C0ljxGbt.js} +2 -2
- package/dist/client/assets/{PluginManager-C7QDE3Lk.js → PluginManager-D27abRF-.js} +1 -1
- package/dist/client/assets/ResearchView-BSpDz8YN.js +1 -0
- package/dist/client/assets/SecretsView-BmCemEu8.js +1 -0
- package/dist/client/assets/{SecretsView-BFhVwJu6.css → SecretsView-D5bHZ-wM.css} +1 -1
- package/dist/client/assets/SettingsModal-0gevFhXV.css +1 -0
- package/dist/client/assets/{SettingsModal-YCJM5is3.js → SettingsModal-DvmwpEUE.js} +1 -1
- package/dist/client/assets/SettingsModal-m3KMs_uS.js +31 -0
- package/dist/client/assets/{SetupWizardModal-BT-mj3VD.js → SetupWizardModal-CDfZpkB7.js} +1 -1
- package/dist/client/assets/{SkillsView-Db7dYpqd.js → SkillsView-BCpa_vud.js} +1 -1
- package/dist/client/assets/{StashRecoveryView-CSYYcWux.js → StashRecoveryView-BYLja93K.js} +1 -1
- package/dist/client/assets/{TodoView-zqCqfy26.js → TodoView-lbnG-8cZ.js} +2 -2
- package/dist/client/assets/{dashboard-view-PpcsMDvN.js → dashboard-view-CY6MGQbI.js} +1 -1
- package/dist/client/assets/{folder-open-mxsFQlAX.js → folder-open-CZghG0dv.js} +1 -1
- package/dist/client/assets/index-lDPXOH7J.css +1 -0
- package/dist/client/assets/index-tJzhtiGM.js +742 -0
- package/dist/client/assets/{upload-j7JjaJzG.js → upload-L7aDk8Xn.js} +1 -1
- package/dist/client/assets/{users-DZ_0WcB6.js → users-DoWKt94F.js} +1 -1
- package/dist/client/index.html +102 -3
- package/dist/client/version.json +1 -1
- package/dist/droid-cli/package.json +1 -1
- package/dist/extension.js +18491 -6644
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
- 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/package.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/references/extension-tools.md +2 -1
- package/skill/fusion/references/fusion-capabilities.md +1 -1
- package/dist/client/assets/AgentsView-LkVv9hph.js +0 -34
- package/dist/client/assets/ChatView-DYjECCRG.js +0 -1
- package/dist/client/assets/DevServerView-D7legPr1.js +0 -1
- package/dist/client/assets/NodesView-CM0eoCP8.js +0 -14
- package/dist/client/assets/ResearchView-Bn2WxwnQ.js +0 -1
- package/dist/client/assets/SecretsView-DgrrgzFc.js +0 -1
- package/dist/client/assets/SettingsModal-BCZrCLl3.js +0 -31
- package/dist/client/assets/SettingsModal-BZBV2kLr.css +0 -1
- package/dist/client/assets/index-Ba-F8c1g.js +0 -732
- package/dist/client/assets/index-D4HhaIOp.css +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{c as Ve,aR as os,aS as cs,aT as is,aU as ds,aV as De,aF as he,aW as ye,aX as Fe,aY as _e,aZ as Oe,A as Ke,aw as us,Q as Ue,a_ as Te,a$ as ms,_ as Ne,u as hs,R as ke,a as Me,J as fe,b0 as Be,b1 as fs,b2 as gs,b3 as ps,b4 as $e,X as me,ae as xs,af as js,b5 as Ie,F as bs,b6 as ze,b7 as vs,b8 as ys,b9 as _s,ba as Ns,bb as ks,G as Cs}from"./index-tJzhtiGM.js";import{v as Ss}from"./projectDetection-G3XuxD2X.js";import{U as He}from"./upload-L7aDk8Xn.js";import"./vendor-xterm-DzcZoU0P.js";import"./vendor-codemirror-jBKmHyH0.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 ws=[["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"}]],Ms=Ve("wifi-off",ws);/**
|
|
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 Ps=[["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"}]],Es=Ve("wifi",Ps);function je(t){const{lastSyncAt:l,remoteReachable:a,diff:d}=t,u=d.global.length+d.project.length;return l===null?{syncState:"never-synced",lastSyncAt:l,diffCount:0}:a?u>0?{syncState:"diff",lastSyncAt:l,diffCount:u}:{syncState:"synced",lastSyncAt:l,diffCount:0}:{syncState:"error",lastSyncAt:l,diffCount:u}}function Ce(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(),u=Math.floor(d/1e3),m=Math.floor(u/60),o=Math.floor(m/60),j=Math.floor(o/24);return m<1?"Synced just now":m<60?`Synced ${m}m ago`:o<24?`Synced ${o}h ago`:`Synced ${j}d ago`}function Rs(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 As=3e4;function Ls(){const[t,l]=s.useState({}),[a,d]=s.useState(!1),[u,m]=s.useState({}),[o,j]=s.useState(null),g=s.useRef(new Set),c=s.useRef(!1),N=s.useRef(null),w=s.useRef(null),b=s.useCallback(async(x,p)=>{try{const S=await os(x);l(Z=>({...Z,[x]:S})),j(null)}catch(S){console.error(`Failed to fetch sync status for node ${x}:`,S),j(S instanceof Error?S.message:"Failed to fetch sync status")}},[]),i=s.useCallback(async()=>{const x=Array.from(g.current);if(x.length===0)return;N.current&&N.current.abort(),N.current=new AbortController;const p=!c.current;p&&d(!0),j(null);try{const S=await Promise.allSettled(x.map(H=>b(H,p)));c.current=!0,S.filter(H=>H.status==="rejected").length>0&&j("Some sync status requests failed")}catch(S){if(S instanceof Error&&S.name==="AbortError")return;j(S instanceof Error?S.message:"Failed to fetch sync status"),c.current=!0}finally{d(!1)}},[b]),M=s.useCallback(()=>{w.current&&clearInterval(w.current),w.current=setInterval(()=>{i()},As)},[i]),_=s.useCallback(()=>{w.current&&(clearInterval(w.current),w.current=null)},[]);s.useEffect(()=>(i(),M(),()=>{_(),N.current&&N.current.abort()}),[i,M,_]);const n=s.useCallback(x=>{g.current.has(x)||(g.current.add(x),b(x,!c.current))},[b]),v=s.useCallback(x=>{g.current.delete(x),l(p=>{const S={...p};return delete S[x],S}),g.current.size===0&&_()},[_]),C=s.useCallback(async x=>{m(p=>({...p,[x]:!0})),j(null);try{const p=await cs(x);return b(x,!1),!p.success&&p.error&&j(p.error),p}catch(p){const S=p instanceof Error?p.message:"Push settings failed";throw j(S),p}finally{m(p=>{const S={...p};return delete S[x],S})}},[b]),k=s.useCallback(async x=>{m(p=>({...p,[x]:!0})),j(null);try{const p=await is(x);return b(x,!1),!p.success&&p.error&&j(p.error),p}catch(p){const S=p instanceof Error?p.message:"Pull settings failed";throw j(S),p}finally{m(p=>{const S={...p};return delete S[x],S})}},[b]),D=s.useCallback(async x=>{m(p=>({...p,[x]:!0})),j(null);try{return await ds(x)}catch(p){const S=p instanceof Error?p.message:"Auth sync failed";throw j(S),p}finally{m(p=>{const S={...p};return delete S[x],S})}},[]),V=s.useCallback(x=>t[x]?.authMatch,[t]),A=s.useCallback(x=>t[x]?.authDiff,[t]);return{syncStatusMap:t,loading:a,actionLoading:u,error:o,refresh:i,trackNode:n,untrackNode:v,pushSettings:C,pullSettings:k,syncAuth:D,getAuthSyncState:V,getAuthProviders:A}}const Ds=1e4,$s=1e3;function Is(){const[t,l]=s.useState([]),[a,d]=s.useState(!0),[u,m]=s.useState(null),o=s.useRef(null),j=s.useRef(0),g=s.useCallback(async()=>{try{m(null);const c=await De();l(c.nodes)}catch(c){m(c instanceof Error?c.message:"Failed to fetch mesh state")}},[]);return s.useEffect(()=>{let c=!1;async function N(){d(!0);try{const b=await De();c||(l(b.nodes),m(null))}catch(b){c||m(b instanceof Error?b.message:"Failed to fetch mesh state")}finally{c||d(!1)}}N();const w=()=>{if(document.visibilityState!=="visible")return;const b=Date.now(),i=b-j.current;if(i<$s){he({view:"useMeshState",trigger:"visibility",projectId:void 0,replayAttempted:!1,reason:"debounce-skipped",detail:{timeSinceLastRefreshMs:i}});return}j.current=b,he({view:"useMeshState",trigger:"visibility",projectId:void 0,replayAttempted:!1,reason:"debounced-refresh"}),g()};return document.addEventListener("visibilitychange",w),()=>{c=!0,document.removeEventListener("visibilitychange",w)}},[g]),s.useEffect(()=>{if(!a)return o.current=setInterval(()=>{g()},Ds),()=>{o.current&&(clearInterval(o.current),o.current=null)}},[a,g]),{meshState:t,loading:a,error:u,refresh:g}}const de={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"}},zs={match:"var(--color-success)",differs:"var(--color-warning)","not-synced":"var(--text-muted)"};function Vs(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 Fs(t,l=42){return t.length<=l?t:`${t.slice(0,l-3)}...`}function Os(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 u=t.managedDockerNode,m=l.managedDockerNode;if(!!u!=!!m||u&&m&&(u.id!==m.id||u.status!==m.status||u.imageTag!==m.imageTag||u.updatedAt!==m.updatedAt))return!1;const o=t.syncStatus,j=l.syncStatus;if(!(!o&&!j)){if(!o||!j)return!1;if(o.syncState!==j.syncState||o.lastSyncAt!==j.lastSyncAt||o.diffCount!==j.diffCount)return!1}if(t.authSyncState!==l.authSyncState)return!1;const g=t.authSyncProviders,c=l.authSyncProviders;if(g!==c){if(!g||!c)return!1;{const b=Object.keys(g),i=Object.keys(c);if(b.length!==i.length||b.some(M=>g[M]!==c[M]))return!1}}const N=ye(t.projects,a),w=ye(l.projects,d);return N===w}function Ks({node:t,projects:l,onHealthCheck:a,onEdit:d,onRemove:u,isLoading:m=!1,syncStatus:o,authSyncState:j,authSyncProviders:g,managedDockerNode:c}){const[N,w]=s.useState(!1),b=de[t.status]??de.offline,i=c?de[c.status]??de.error:null,M=c?.hostConfig.type==="remote"?`Remote: ${c.hostConfig.host??"unknown"}`:"Local Docker",_=s.useMemo(()=>ye(l,t),[l,t]),n=s.useCallback(()=>{d(t)},[d,t]),v=s.useCallback(V=>{V.stopPropagation(),a(t.id)},[a,t.id]),C=s.useCallback(V=>{V.stopPropagation(),d(t)},[d,t]),k=s.useCallback(V=>{if(V.stopPropagation(),!N){w(!0);return}u(t.id),w(!1)},[N,u,t.id]),D=s.useCallback(V=>{(V.key==="Enter"||V.key===" ")&&(V.preventDefault(),d(t))},[d,t]);return e.jsxs("article",{className:`node-card ${m?"node-card--loading":""}`,"data-node-id":t.id,role:"button",tabIndex:0,onClick:n,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(Fe,{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"}),c&&e.jsxs("span",{className:"node-card__docker-badge",title:"Managed Docker node",children:[e.jsx(_e,{size:12,"aria-hidden":!0}),"Docker"]}),e.jsxs("span",{className:`node-card__status ${b.className}`,style:{color:b.color},"data-status":t.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:b.color},"aria-hidden":!0}),b.label]}),c&&i&&e.jsxs("span",{className:`node-card__status ${i.className}`,style:{color:i.color},"data-status":c.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:i.color},"aria-hidden":!0}),i.label]}),t.type==="remote"&&j&&e.jsx("span",{className:`node-card__auth-indicator node-card__auth-indicator--${j}`,title:Vs(j,g),"aria-label":`Auth sync: ${j==="match"?"credentials match":j==="differs"?"credentials differ":"not synced"}`,style:{color:zs[j]},children:e.jsx(Oe,{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:Fs(t.url)}),c&&e.jsxs("div",{className:"node-card__docker-meta",children:[e.jsxs("span",{title:`${c.imageName}:${c.imageTag}`,children:[c.imageName,":",c.imageTag]}),e.jsx("span",{title:M,children:M})]}),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:_})]}),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:Rs(o.syncState)},"aria-hidden":!0}),e.jsx("span",{className:"node-card__sync-time",children:Ce(o.lastSyncAt)})]})]}),e.jsxs("footer",{className:"node-card__actions",children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:v,disabled:m,"aria-label":"Run node health check",title:"Health Check",children:[e.jsx(Ke,{size:14}),e.jsx("span",{children:"Health"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:C,disabled:m,"aria-label":"Edit node",title:"Edit",children:[e.jsx(us,{size:14}),e.jsx("span",{children:"Edit"})]}),c&&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(Ue,{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(Te,{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(ms,{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:m,"aria-label":N?"Confirm remove node":"Remove node",title:N?"Confirm remove":"Remove",children:[e.jsx(Ne,{size:14}),e.jsx("span",{children:N?"Confirm":"Remove"})]})]})]})}const Us=s.memo(Ks,Os),ce={online:"var(--success, var(--color-success))",offline:"var(--text-dim)",connecting:"var(--color-warning)",error:"var(--color-error)"},ue=28,Ts=12,Bs=300,Hs=120;function qs({nodes:t,className:l}){const a=s.useMemo(()=>t.find(c=>c.nodeType==="local")??t[0],[t]),d=s.useMemo(()=>t.filter(c=>c.nodeId!==a?.nodeId),[t,a?.nodeId]),u=s.useMemo(()=>Bs+Math.max(0,d.length-4)*20,[d.length]),m=u/2,o=u/2,j=s.useMemo(()=>{const c=new Map;if(a&&c.set(a.nodeId,{x:m,y:o,node:a}),d.length>0){const N=Math.min(Hs,u/2-ue-10),w=2*Math.PI/d.length,b=-Math.PI/2;d.forEach((i,M)=>{const _=b+M*w;c.set(i.nodeId,{node:i,x:m+N*Math.cos(_),y:o+N*Math.sin(_)})})}return c},[m,o,a,d,u]),g=s.useMemo(()=>{const c=new Set,N=[];for(const w of t){const b=j.get(w.nodeId);if(b)for(const i of w.knownPeers){const M=j.get(i.peerNodeId);if(!M)continue;const _=[w.nodeId,i.peerNodeId].sort().join("::");c.has(_)||(c.add(_),N.push({key:_,from:b,to:M}))}}return N},[j,t]);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 ${u} ${u}`,preserveAspectRatio:"xMidYMid meet","aria-label":"Node mesh topology visualization",children:[g.map(c=>e.jsx("line",{className:"mesh-topology__link mesh-topology__peer-line",x1:c.from.x,y1:c.from.y,x2:c.to.x,y2:c.to.y},c.key)),Array.from(j.values()).map(({node:c,x:N,y:w})=>e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${N}, ${w})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:ue,fill:ce[c.status],"aria-label":`${c.nodeName} (${c.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:ue+Ts,textAnchor:"middle",children:c.nodeName.length>12?`${c.nodeName.slice(0,10)}…`:c.nodeName}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-ue-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.nodeType==="local"?"L":"R"})]})]},c.nodeId))]}),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"})]})]}),g.length===0&&e.jsx("p",{className:"mesh-topology__notice",children:"Peer-to-peer discovery data unavailable."})]})}const Ys=s.memo(qs),Se=1,we=10;function Xs(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<Se||t.maxConcurrent>we)&&(l.maxConcurrent=`Concurrency must be between ${Se} and ${we}`);for(const a of t.projectMappings){const d=Ss(a.path);d.valid||(l.projectMappings[a.projectId]=d.error??"Path is invalid")}return l}function Js({isOpen:t,onClose:l,onSubmit:a,onDiscoverRemoteProjects:d,addToast:u,projects:m}){hs(t);const[o,j]=s.useState(""),[g,c]=s.useState("local"),[N,w]=s.useState(""),[b,i]=s.useState(""),[M,_]=s.useState(2),[n,v]=s.useState("auto-generate"),[C,k]=s.useState({}),[D,V]=s.useState({projectMappings:{}}),[A,x]=s.useState(!1),[p,S]=s.useState("idle"),[Z,H]=s.useState(null),[Y,ee]=s.useState([]),U=s.useCallback(()=>{j(""),c("local"),w(""),i(""),_(2),v("auto-generate"),k({}),V({projectMappings:{}}),x(!1),S("idle"),H(null),ee([])},[]),X=s.useCallback(()=>{A||(U(),l())},[A,l,U]);s.useEffect(()=>{if(!t){U();return}const y=L=>{L.key==="Escape"&&(L.preventDefault(),X())};return document.addEventListener("keydown",y),()=>{document.removeEventListener("keydown",y)}},[X,t,U]);const G=s.useMemo(()=>({name:o.trim(),type:g,url:g==="remote"&&N.trim()||void 0,apiKey:g==="remote"&&n==="provide"&&b||void 0,maxConcurrent:M,apiKeyMode:n,projectMappings:Object.entries(C).map(([y,L])=>({projectId:y,path:L.trim()}))}),[b,n,M,o,C,g,N]),te=s.useCallback(async()=>{if(A||p==="loading")return;const y=N.trim();if(!y){V(L=>({...L,url:"URL is required for remote nodes"}));return}S("loading"),H(null);try{const L=await d({url:y,apiKey:n==="provide"&&b.trim().length>0?b:void 0});ee(L.projects),S("success"),k($=>{if(Object.keys($).length===0)return $;const K={...$};for(const ae of m){if(!(ae.id in K))continue;const ne=L.projects.filter(se=>se.name===ae.name);ne.length===1&&(K[ae.id]=ne[0].path)}return K})}catch(L){S("error"),ee([]),H(L instanceof Error?L.message:"Failed to discover remote projects")}},[b,n,p,A,d,m,N]);s.useEffect(()=>{if(g!=="remote"){S("idle"),H(null),ee([]);return}S("idle"),H(null),ee([])},[b,n,g,N]);const J=s.useCallback(async()=>{if(A)return;const y=Xs(G);if(V(y),!(y.name||y.url||y.maxConcurrent||Object.keys(y.projectMappings).length>0)){if(G.type==="remote"&&p!=="success"){H("Discover remote projects before adding this node.");return}x(!0);try{await a(G),u(`Node "${G.name}" registered`,"success"),X()}catch(L){const $=L instanceof Error?L.message:"Failed to register node";u($,"error")}finally{x(!1)}}},[u,X,p,G,A,a]),T=y=>{k(L=>{if(y.id in L){const{[y.id]:$,...K}=L;return K}if(g==="remote"&&p==="success"){const $=Y.filter(K=>K.name===y.name);return $.length===1?{...L,[y.id]:$[0].path}:{...L,[y.id]:""}}return{...L,[y.id]:y.path}})},E=(y,L)=>{k($=>({...$,[y]:L}))};return t?e.jsx("div",{className:"modal-overlay open",onClick:X,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:X,disabled:A,"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=>j(y.target.value),placeholder:"Build Machine",disabled:A,"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 ${g==="local"?"active":""}`,"data-type":"local",onClick:()=>c("local"),disabled:A,"aria-pressed":g==="local",children:"Local"}),e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${g==="remote"?"active":""}`,"data-type":"remote",onClick:()=>c("remote"),disabled:A,"aria-pressed":g==="remote",children:"Remote"})]}),g==="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=>w(y.target.value),placeholder:"https://node.example.com",disabled:A,"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:n,onChange:y=>v(y.target.value),disabled:A,children:[e.jsx("option",{value:"auto-generate",children:"Auto-generate"}),e.jsx("option",{value:"provide",children:"Provide key manually"})]})]}),n==="provide"&&e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:b,onChange:y=>i(y.target.value),placeholder:"Enter node API key",disabled:A})]}),e.jsxs("div",{className:"add-node-modal__discovery-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>void te(),disabled:A||p==="loading",children:p==="loading"?"Discovering...":"Discover Remote Projects"}),p==="success"&&e.jsx("span",{className:"add-node-modal__discovery-state","data-state":"success",children:Y.length>0?`Discovered ${Y.length} remote project${Y.length===1?"":"s"}.`:"No projects discovered on remote node."}),p==="error"&&Z&&e.jsx("span",{className:"form-error add-node-modal__error",children:Z}),p==="idle"&&e.jsx("span",{className:"add-node-modal__hint",children:"Discover remote projects before adding this node."})]}),p==="success"&&Y.length>0&&e.jsx("div",{className:"add-node-modal__discovered-list","aria-label":"Discovered remote projects",children:Y.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:Se,max:we,value:M,onChange:y=>_(Number(y.target.value)),disabled:A,"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."}),m.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:m.map(y=>{const L=y.id in C,$=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:L,onChange:()=>T(y),disabled:A}),e.jsx("span",{children:y.name})]}),L&&e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Path on this node"}),g==="remote"&&p==="success"&&e.jsx("span",{className:"add-node-modal__hint",children:(()=>{const K=Y.filter(ae=>ae.name===y.name);return K.length===1?`Remote-authoritative path discovered: ${K[0].path}`:K.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:C[y.id]??"",onChange:K=>E(y.id,K.target.value),disabled:A,placeholder:"/absolute/path/to/project","aria-invalid":!!$}),$&&e.jsx("span",{className:"form-error add-node-modal__error",children:$})]})]},y.id)})})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:X,disabled:A,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm","data-testid":"add-node-submit",onClick:J,disabled:A,children:A?"Adding...":"Add Node"})]})]})}):null}function Ws(){const[t,l]=s.useState([]),[a,d]=s.useState(!1),[u,m]=s.useState(null),[o,j]=s.useState(!1),[g,c]=s.useState(null),[N,w]=s.useState(!1),b=s.useCallback(async()=>{d(!0),m(null);try{const _=await fetch("/api/docker/contexts");if(!_.ok)throw new Error(`Failed to load Docker contexts (${_.status})`);const n=await _.json();return l(n),n}catch(_){const n=_ instanceof Error?_.message:String(_);throw m(n),_}finally{d(!1)}},[]),i=s.useCallback(async _=>{j(!0);try{const n=await fetch("/api/docker/test-connection",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({hostConfig:_})});if(!n.ok)throw new Error(`Failed to test Docker connection (${n.status})`);const v=await n.json();return c(v),v}finally{j(!1)}},[]),M=s.useCallback(async()=>{w(!0);try{const _=await fetch("/api/docker/local-available");if(!_.ok)throw new Error(`Failed to check local Docker availability (${_.status})`);return await _.json()}finally{w(!1)}},[]);return{contexts:t,isLoadingContexts:a,contextsError:u,loadContexts:b,isTestingConnection:o,lastTestResult:g,testConnection:i,isCheckingLocal:N,checkLocalDocker:M}}function Gs({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 u=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:m=>d(m.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:u.tlsCaPath,onChange:m=>l({...u,tlsCaPath:m.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:u.tlsCertPath,onChange:m=>l({...u,tlsCertPath:m.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:u.tlsKeyPath,onChange:m=>l({...u,tlsKeyPath:m.target.value}),placeholder:"/etc/docker/key.pem"})]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:u.tlsVerify,onChange:m=>l({...u,tlsVerify:m.target.checked})}),"Verify TLS Certificate"]})]})]})}function Zs({value:t,onChange:l,onError:a}){const d=t?.context?"context":t?.host?"host":"local",[u,m]=s.useState(d),[o,j]=s.useState(t?.context??""),[g,c]=s.useState(t?.host??""),[N,w]=s.useState(null),{contexts:b,isLoadingContexts:i,contextsError:M,loadContexts:_,testConnection:n,isTestingConnection:v,lastTestResult:C,checkLocalDocker:k,isCheckingLocal:D}=Ws(),V=s.useMemo(()=>({tlsVerify:t?.tlsVerify,tlsCaPath:t?.tlsCaPath,tlsCertPath:t?.tlsCertPath,tlsKeyPath:t?.tlsKeyPath}),[t]);s.useEffect(()=>{if(u==="local"){l({});return}if(u==="context"){_().catch(x=>a?.(x instanceof Error?x.message:String(x))),l(o?{context:o}:{});return}l({host:g,...V})},[u]);const A=s.useCallback(x=>{u==="host"&&l({host:g,...x})},[g,u,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 ${u==="local"?"docker-target-selector__mode-active":""}`,onClick:()=>{m("local"),k().then(x=>w(x.available?`Docker is available${x.version?` (${x.version})`:""}`:`Docker not found${x.error?`: ${x.error}`:""}`)).catch(x=>{const p=x instanceof Error?x.message:String(x);w(`Docker not found: ${p}`),a?.(p)})},children:"Local Docker"}),e.jsx("button",{type:"button",className:`btn btn-sm ${u==="context"?"docker-target-selector__mode-active":""}`,onClick:()=>m("context"),children:"Docker Context"}),e.jsx("button",{type:"button",className:`btn btn-sm ${u==="host"?"docker-target-selector__mode-active":""}`,onClick:()=>m("host"),children:"Remote Host"})]}),u==="local"&&N&&e.jsx("div",{className:"docker-target-selector__status",children:N}),u==="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 p=x.target.value;j(p),l(p?{context:p}:{})},children:[e.jsx("option",{value:"",children:"Select context"}),b.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 _(),disabled:i,"aria-label":"Refresh contexts",children:e.jsx(ke,{size:14})})]}),M&&e.jsx("div",{className:"docker-target-selector__error",children:M})]}),u==="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:g,onChange:x=>{const p=x.target.value;c(p),l({host:p,...V})}})]}),e.jsx(Gs,{value:V,onChange:A})]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>void n(u==="local"?void 0:u==="context"?{context:o}:{host:g,...V}),disabled:v||D,children:v?"Testing...":"Test Connection"}),C&&e.jsx("div",{className:C.success?"docker-target-selector__success":"docker-target-selector__error",children:C.success?`Connected${C.dockerVersion?` (Docker ${C.dockerVersion})`:""}`:C.error??"Connection failed"})]})}const be="http://localhost:4040";function Qs({isOpen:t,onClose:l,onSubmit:a,addToast:d}){const[u,m]=s.useState(""),[o,j]=s.useState({}),[g,c]=s.useState(be),[N,w]=s.useState("auto"),[b,i]=s.useState(""),[M,_]=s.useState(!1),[n,v]=s.useState(!1),[C,k]=s.useState(!0),[D,V]=s.useState(4096),[A,x]=s.useState(2),[p,S]=s.useState(!1),[Z,H]=s.useState("runfusion/fusion"),[Y,ee]=s.useState("latest"),[U,X]=s.useState([]),[G,te]=s.useState([]),[J,T]=s.useState({}),[E,y]=s.useState(!1),L=s.useCallback(()=>{m(""),j({}),c(be),w("auto"),i(""),_(!1),v(!1),k(!0),V(4096),x(2),S(!1),H("runfusion/fusion"),ee("latest"),X([]),te([]),T({}),y(!1)},[]),$=s.useCallback(()=>{E||(L(),l())},[l,L,E]);s.useEffect(()=>{if(!t){L();return}const h=O=>{O.key==="Escape"&&(O.preventDefault(),$())};return document.addEventListener("keydown",h),()=>document.removeEventListener("keydown",h)},[$,t,L]);const K=s.useMemo(()=>({nodeId:null,name:u.trim(),imageName:Z.trim()||"runfusion/fusion",imageTag:Y.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(U.map(h=>[h.key.trim(),h.value]).filter(([h])=>!!h)),volumeMounts:G.map(h=>({hostPath:h.hostPath.trim(),containerPath:h.containerPath.trim(),mode:h.mode})).filter(h=>h.hostPath&&h.containerPath),resourceSizing:{memoryMB:D,cpus:A},extraClis:[M?"claude-cli":null,n?"droid-cli":null].filter(Boolean),persistentStorage:C,reachableUrl:g.trim()||null,apiKey:N==="manual"&&b.trim()||null}),[b,N,A,o,U,Z,Y,M,n,D,G,u,C,g]),ae=s.useCallback(()=>{X(h=>[...h,{key:"",value:""}])},[]),ne=s.useCallback((h,O)=>{X(B=>B.map((q,oe)=>oe===h?O:q))},[]),se=s.useCallback(h=>{X(O=>O.filter((B,q)=>q!==h))},[]),le=s.useCallback(()=>{te(h=>[...h,{hostPath:"",containerPath:"",mode:"rw"}])},[]),R=s.useCallback((h,O)=>{te(B=>B.map((q,oe)=>oe===h?O:q))},[]),I=s.useCallback(h=>{te(O=>O.filter((B,q)=>q!==h))},[]),W=s.useCallback(async()=>{if(E)return;const h={};if((!K.name||K.name.length>64)&&(h.name="Name is required and must be 64 characters or fewer"),K.reachableUrl||(h.reachableUrl="URL is required"),D<512&&(h.memoryMB="Memory must be at least 512 MB"),A<.5&&(h.cpus="CPUs must be at least 0.5"),T(h),!(Object.keys(h).length>0)){y(!0);try{await a(K),$()}catch{}finally{y(!1)}}},[$,A,K,D,a,E]);return t?e.jsx("div",{className:"modal-overlay open",onClick:$,children:e.jsxs("div",{className:"modal docker-onboarding",role:"dialog","aria-modal":"true","aria-label":"Docker node onboarding",onClick:h=>h.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Provision Docker Node"}),e.jsx("button",{className:"modal-close",onClick:$,disabled:E,"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:u,onChange:h=>m(h.target.value),disabled:E,placeholder:"my-docker-node",autoFocus:!0})]}),J.name&&e.jsx("div",{className:"form-error",children:J.name}),e.jsx(Zs,{value:o,onChange:j}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Reachable URL"}),e.jsx("input",{className:"input",value:g,onChange:h=>c(h.target.value),disabled:E,placeholder:be})]}),J.reachableUrl&&e.jsx("div",{className:"form-error",children:J.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:()=>w("auto"),disabled:E}),"Auto-generate"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"radio",checked:N==="manual",onChange:()=>w("manual"),disabled:E}),"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:b,onChange:h=>i(h.target.value),disabled:E,placeholder:"Enter API key"})]}),e.jsxs("div",{className:"docker-onboarding__checkbox-group",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:M,onChange:h=>_(h.target.checked),disabled:E}),"Claude CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:n,onChange:h=>v(h.target.checked),disabled:E}),"Droid CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:C,onChange:h=>k(h.target.checked),disabled:E}),"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:h=>V(Number(h.target.value)),disabled:E})]}),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:A,onChange:h=>x(Number(h.target.value)),disabled:E})]})]}),J.memoryMB&&e.jsx("div",{className:"form-error",children:J.memoryMB}),J.cpus&&e.jsx("div",{className:"form-error",children:J.cpus})]}),e.jsxs("section",{className:"docker-onboarding__section",children:[e.jsxs("button",{type:"button",className:`docker-onboarding__advanced-toggle ${p?"is-expanded":""}`,onClick:()=>S(h=>!h),disabled:E,children:[e.jsx("span",{children:"Advanced"}),e.jsx(Me,{})]}),e.jsx("div",{className:`docker-onboarding__advanced-content ${p?"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:Z,onChange:h=>H(h.target.value),disabled:E,placeholder:"runfusion/fusion"})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Tag"}),e.jsx("input",{className:"input",value:Y,onChange:h=>ee(h.target.value),disabled:E,placeholder:"latest"})]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Environment Variables"}),U.map((h,O)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--env",children:[e.jsx("input",{className:"input",placeholder:"KEY",value:h.key,disabled:E,onChange:B=>ne(O,{key:B.target.value,value:h.value})}),e.jsx("input",{className:"input",placeholder:"Value",value:h.value,disabled:E,onChange:B=>ne(O,{key:h.key,value:B.target.value})}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":"Remove environment variable",onClick:()=>se(O),disabled:E,children:e.jsx(Ne,{size:14})})]},`env-${O}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:ae,disabled:E,children:[e.jsx(fe,{size:14}),"Add variable"]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Volume Mounts"}),G.map((h,O)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--mount",children:[e.jsx("input",{className:"input",placeholder:"Host path",value:h.hostPath,disabled:E,onChange:B=>R(O,{hostPath:B.target.value,containerPath:h.containerPath,mode:h.mode})}),e.jsx("input",{className:"input",placeholder:"Container path",value:h.containerPath,disabled:E,onChange:B=>R(O,{hostPath:h.hostPath,containerPath:B.target.value,mode:h.mode})}),e.jsxs("select",{className:"select",value:h.mode,disabled:E,onChange:B=>R(O,{hostPath:h.hostPath,containerPath:h.containerPath,mode:B.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:()=>I(O),disabled:E,children:e.jsx(Ne,{size:14})})]},`mount-${O}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:le,disabled:E,children:[e.jsx(fe,{size:14}),"Add mount"]})]})]})})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn",onClick:$,disabled:E,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",onClick:()=>void W(),disabled:E,children:E?"Creating...":"Create Docker Node"})]})]})}):null}function et({nodeId:t,entries:l,loading:a=!1,singleNode:d=!1}){const[u,m]=s.useState(!1),[o,j]=s.useState("all"),[g,c]=s.useState("all"),N=s.useCallback(()=>{m(n=>!n)},[]),w=s.useMemo(()=>{const n=new Set;for(const v of l)n.add(v.nodeName);return Array.from(n).sort()},[l]),b=s.useMemo(()=>{let n=[...l];return o!=="all"&&(n=n.filter(v=>v.direction===o)),!d&&g!=="all"&&(n=n.filter(v=>v.nodeName===g)),n.sort((v,C)=>{const k=new Date(v.timestamp).getTime();return new Date(C.timestamp).getTime()-k}),n},[l,o,g,d]),i=s.useCallback(n=>new Date(n).toLocaleString(),[]),M=s.useCallback(n=>{switch(n){case"success":return"settings-sync-log__badge--success";case"conflict":return"settings-sync-log__badge--conflict";case"error":return"settings-sync-log__badge--error";default:return""}},[]),_=s.useCallback(n=>{switch(n){case"success":return"Success";case"conflict":return"Conflict";case"error":return"Error";default:return n}},[]);return e.jsxs("div",{className:"settings-sync-log",children:[e.jsxs("button",{className:"settings-sync-log__header",type:"button",onClick:N,"aria-expanded":u,"data-testid":"settings-sync-log-header",children:[e.jsx(Me,{size:16,className:`settings-sync-log__chevron ${u?"settings-sync-log__chevron--expanded":""}`}),e.jsxs("span",{children:[l.length," ",l.length===1?"entry":"entries"]})]}),u&&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:n=>j(n.target.value),children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"push",children:"Push"}),e.jsx("option",{value:"pull",children:"Pull"})]})]}),!d&&e.jsxs("label",{children:["Node:",e.jsxs("select",{value:g,onChange:n=>c(n.target.value),children:[e.jsx("option",{value:"all",children:"All Nodes"}),w.map(n=>e.jsx("option",{value:n,children:n},n))]})]})]}),a&&l.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"Loading..."}):b.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"No sync history available"}):e.jsx("div",{className:"settings-sync-log__list",children:b.map(n=>e.jsxs("div",{className:"settings-sync-log__entry",children:[e.jsx("span",{className:"settings-sync-log__entry-timestamp",children:i(n.timestamp)}),e.jsx("span",{className:"settings-sync-log__entry-direction",children:n.direction==="push"?e.jsx(He,{size:14,"data-testid":"upload-icon"}):e.jsx(Be,{size:14,"data-testid":"download-icon"})}),e.jsx("span",{className:`settings-sync-log__entry-result ${M(n.result)}`,children:_(n.result)}),!d&&e.jsx("span",{className:"settings-sync-log__entry-node",children:n.nodeName}),n.details&&e.jsx("span",{className:"settings-sync-log__entry-details",title:n.details,children:fs(n.details??"")})]},n.id))})]})]})}function st(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 u=a.split(`
|
|
12
|
+
`),m=d.split(`
|
|
13
|
+
`),o=[],j=Math.max(u.length,m.length);for(let g=0;g<j;g++){const c=u[g],N=m[g];c!==void 0&&c!==N&&o.push(`- ${c}`),N!==void 0&&N!==c&&o.push(`+ ${N}`),c!==void 0&&c===N&&o.push(` ${c}`)}return o.join(`
|
|
14
|
+
`)}function tt({isOpen:t,onClose:l,onResolve:a,conflicts:d,localNodeName:u,remoteNodeName:m,addToast:o}){const[j,g]=s.useState({}),[c,N]=s.useState(!1);s.useEffect(()=>{const n={};for(const v of d)j[v.key]||(n[v.key]={resolution:"local"});Object.keys(n).length>0&&g(v=>({...v,...n}))},[d,j]),s.useEffect(()=>{if(!t)return;const n=v=>{v.key==="Escape"&&(v.preventDefault(),l())};return document.addEventListener("keydown",n),()=>document.removeEventListener("keydown",n)},[t,l]);const w=s.useCallback((n,v)=>{g(C=>{const k=C[n]??{};return v==="manual"?{...C,[n]:{resolution:"manual",manualValue:k.manualValue??JSON.stringify(d.find(D=>D.key===n)?.localValue??null,null,2)}}:{...C,[n]:{resolution:v}}})},[d]),b=s.useCallback((n,v)=>{g(C=>({...C,[n]:{...C[n],resolution:"manual",manualValue:v}}))},[]),i=s.useCallback(n=>{const v={};for(const C of d)v[C.key]={resolution:n};g(v)},[d]),M=s.useCallback(async()=>{N(!0);try{const n=d.map(v=>{const C=j[v.key]??{resolution:"local"};let k;switch(C.resolution){case"remote":k=v.remoteValue;break;case"manual":try{k=JSON.parse(C.manualValue??"null")}catch{k=C.manualValue??null}break;case"local":default:k=v.localValue;break}return{key:v.key,value:k}});await a(n),o("Settings conflicts resolved successfully","success"),l()}catch(n){const v=n instanceof Error?n.message:"Failed to resolve conflicts";o(v,"error")}finally{N(!1)}},[o,d,l,a,j]),_=s.useMemo(()=>{const n={};for(const v of d)n[v.key]=st(v.localValue,v.remoteValue);return n},[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:n=>n.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":"Resolve Settings Conflicts",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Resolve Settings Conflicts"}),e.jsx("button",{className:"modal-close",onClick: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(n=>{const v=j[n.key]??{resolution:"local"},C=_[n.key];return e.jsxs("div",{className:"settings-sync-conflict-modal__conflict-item",children:[e.jsx("div",{className:"settings-sync-conflict-modal__key",children:n.key}),e.jsxs("div",{className:"settings-sync-conflict-modal__diff-panel",children:[e.jsxs("div",{className:"settings-sync-conflict-modal__diff-side",children:[e.jsx("div",{className:"settings-sync-conflict-modal__diff-label",children:u}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:C})})]}),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:C})})]})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__resolution",children:[e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${n.key}`,checked:v.resolution==="local",onChange:()=>w(n.key,"local")}),"Keep Local"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${n.key}`,checked:v.resolution==="remote",onChange:()=>w(n.key,"remote")}),"Keep Remote"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${n.key}`,checked:v.resolution==="manual",onChange:()=>w(n.key,"manual")}),"Merge Manually"]})]}),v.resolution==="manual"&&e.jsx("textarea",{className:"settings-sync-conflict-modal__manual-input",value:v.manualValue??"",onChange:k=>b(n.key,k.target.value),placeholder:"Enter JSON value..."})]},n.key)})}),e.jsxs("div",{className:"settings-sync-conflict-modal__bulk-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>i("local"),type:"button",children:"Resolve All: Keep Local"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>i("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:M,disabled:c,children:c?"Resolving...":"Confirm"})]})]})})}const qe=/(KEY|TOKEN|SECRET|PASSWORD)/i;function ve(t){if(!t)return"—";const l=new Date(t);return Number.isNaN(l.getTime())?"—":l.toLocaleString()}function at(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 u=Math.floor(d/60);if(u<60)return`${u}m`;const m=Math.floor(u/60);return m<24?`${m}h ${u%60}m`:`${Math.floor(m/24)}d ${m%24}h`}function nt(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 rt(t){return t==="running"?"success":t==="creating"||t==="recreating"||t==="restarting"?"warning":"error"}function lt(t){return t?`${t.charAt(0).toUpperCase()}${t.slice(1)}`:"Unknown"}function ot(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 ct(t,l){return qe.test(t)?"••••••••":l}function it({isOpen:t,onClose:l,node:a,projects:d,onUpdate:u,onHealthCheck:m,addToast:o,syncStatus:j,onPushSettings:g,onPullSettings:c,onSyncAuth:N,syncHistory:w=[],onResolveConflicts:b,managedDockerNode:i,containerStatus:M,onFetchContainerStatus:_,onFetchLogs:n,onUpdateDockerConfig:v,onFetchDockerConfigDiff:C}){const k=s.useRef(!0),[D,V]=s.useState(!1),[A,x]=s.useState(""),[p,S]=s.useState(""),[Z,H]=s.useState(""),[Y,ee]=s.useState(2),[U,X]=s.useState(!1),[G,te]=s.useState(!1),[J,T]=s.useState(!1),[E,y]=s.useState(!1),[L,$]=s.useState(null),[K,ae]=s.useState(!1),[ne]=s.useState([]),[se,le]=s.useState(M),[R,I]=s.useState(!1),[W,h]=s.useState(!1),[O,B]=s.useState(""),[q,oe]=s.useState(!1),[ge,Pe]=s.useState(!1),[f,F]=s.useState(a?.dockerConfig??null),[Ee,Re]=s.useState({}),[ie,Ae]=s.useState(!1),[Ye,Le]=s.useState(!1);s.useEffect(()=>(k.current=!0,()=>{k.current=!1}),[]),s.useEffect(()=>{le(M)},[M]),s.useEffect(()=>{if(!a||!t){V(!1),h(!1),B("");return}x(a.name),S(a.url??""),H(a.apiKey??""),ee(a.maxConcurrent),V(!1),F(a.dockerConfig??null),Pe(!1),Re({})},[t,a]),s.useEffect(()=>{if(!t)return;const r=P=>{P.key==="Escape"&&(P.preventDefault(),l())};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[t,l]);const pe=s.useMemo(()=>a?gs(d,a):[],[a,d]),Xe=s.useMemo(()=>i?i.hostConfig.type==="remote"?i.hostConfig.host??"—":"Local Docker":"—",[i]),Je=s.useMemo(()=>!i?.resourceSizing?.cpuLimit&&!i?.resourceSizing?.memoryLimit?"Default":`${i.resourceSizing?.cpuLimit??"Default CPU"} / ${i.resourceSizing?.memoryLimit??"Default memory"}`,[i]),We=s.useCallback(async()=>{if(a)try{if(await m(a.id),!k.current)return;o(`Health check completed for ${a.name}`,"success")}catch(r){if(!k.current)return;const P=r instanceof Error?r.message:"Health check failed";o(P,"error")}},[o,a,m]),Ge=s.useCallback(async()=>{if(!(!a||!g)){$(null),te(!0);try{if(await g(a.id),!k.current)return;o("Settings pushed successfully","success")}catch(r){if(!k.current)return;const P=r instanceof Error?r.message:"Push settings failed";$(P),o(P,"error")}finally{k.current&&te(!1)}}},[o,a,g]),Ze=s.useCallback(async()=>{if(!(!a||!c)){$(null),T(!0);try{if(await c(a.id),!k.current)return;o("Settings pulled successfully","success")}catch(r){if(!k.current)return;const P=r instanceof Error?r.message:"Pull settings failed";$(P),o(P,"error")}finally{k.current&&T(!1)}}},[o,a,c]),Qe=s.useCallback(async()=>{if(!(!a||!N)){$(null),y(!0);try{if(await N(a.id),!k.current)return;o("Auth credentials synced successfully","success")}catch(r){if(!k.current)return;const P=r instanceof Error?r.message:"Auth sync failed";$(P),o(P,"error")}finally{k.current&&y(!1)}}},[o,a,N]),es=s.useCallback(()=>{$(null)},[]),ss=s.useCallback(async()=>{if(!(!i||!_)){I(!0);try{const r=await _(i.id);if(!k.current)return;le(r)}catch(r){const P=r instanceof Error?r.message:"Failed to fetch container status";o(P,"error")}finally{k.current&&I(!1)}}},[o,i,_]),ts=s.useCallback(async()=>{if(!(!i||!n)){h(!0),oe(!0);try{const r=await n(i.id);if(!k.current)return;B(r)}catch(r){if(!k.current)return;B("");const P=r instanceof Error?r.message:"Failed to fetch container logs";o(P,"error")}finally{k.current&&oe(!1)}}},[o,i,n]),as=s.useCallback(async()=>{if(!a||U)return;const r=A.trim();if(!r){o("Name is required","error");return}if(a.type==="remote"&&!p.trim()){o("URL is required for remote nodes","error");return}if(!Number.isFinite(Y)||Y<1){o("Concurrency must be at least 1","error");return}X(!0);try{await u(a.id,{name:r,url:a.type==="remote"&&p.trim()||void 0,apiKey:a.type==="remote"&&Z||void 0,maxConcurrent:Y}),o(`Updated ${r}`,"success"),V(!1)}catch(P){const Q=P instanceof Error?P.message:"Failed to update node";o(Q,"error")}finally{X(!1)}},[o,Z,U,Y,A,a,u,p]);s.useEffect(()=>{!a?.dockerConfig||!C||!t||C(a.id).then(r=>{k.current&&Le(r.needsRecreate)}).catch(()=>{k.current&&Le(!1)})},[t,a,C]);const ns=s.useCallback(async()=>{if(!(!a||!f||!v||ie)){Ae(!0);try{const r=await v(a.id,{image:f.image,volumeMounts:f.volumeMounts,environment:f.environment,resources:f.resources,host:f.host,extraClis:f.extraClis,persistence:f.persistence,containerName:f.containerName});if(!k.current)return;F(r),o("Docker config saved","success")}catch(r){if(!k.current)return;const P=r instanceof Error?r.message:"Failed to save Docker config";o(P,"error")}finally{k.current&&Ae(!1)}}},[o,f,ie,a,v]),rs=s.useCallback(()=>{a&&(x(a.name),S(a.url??""),H(a.apiKey??""),ee(a.maxConcurrent),V(!1))},[a]);if(!t||!a)return null;const re=se?.status??i?.status,ls=rt(re);return e.jsxs("div",{className:"modal-overlay open",onClick:l,children:[e.jsxs("div",{className:"modal modal-lg node-detail-modal",onClick:r=>r.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:()=>V(!0),children:[e.jsx(ps,{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:A,onChange:r=>x(r.target.value),disabled:U}):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:Y,onChange:r=>ee(Number(r.target.value)),disabled:U}):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:p,onChange:r=>S(r.target.value),disabled:U}):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:Z,onChange:r=>H(r.target.value),placeholder:"Leave blank to keep unchanged",disabled:U}):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:ve(a.createdAt)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Updated"}),e.jsx("strong",{children:ve(a.updatedAt)})]})]}),D&&e.jsxs("div",{className:"node-detail-modal__edit-actions",children:[e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:as,disabled:U,children:[e.jsx($e,{size:14}),U?"Saving...":"Save"]}),e.jsxs("button",{className:"btn btn-sm",onClick:rs,disabled:U,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"," (",pe.length,")"]}),pe.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:pe.map(r=>e.jsxs("li",{className:"node-detail-modal__project-item",children:[e.jsx("span",{children:r.name}),e.jsx("code",{children:r.id})]},r.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:ve(a.updatedAt)})]})]})]}),f&&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:()=>Pe(r=>!r),"aria-expanded":ge,children:[e.jsx(Me,{size:14,className:ge?"node-detail-modal__docker-toggle-icon--expanded":""}),"Docker Configuration"]}),ge&&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:f.image,onChange:r=>F({...f,image:r.target.value})})]})}),e.jsxs("details",{children:[e.jsx("summary",{children:"Volume Mounts"}),e.jsxs("div",{className:"node-detail-modal__docker-list",children:[f.volumeMounts.map((r,P)=>e.jsxs("div",{className:"node-detail-modal__docker-row",children:[e.jsx("input",{className:"input",value:r.hostPath,placeholder:"Host path",onChange:Q=>{const z=[...f.volumeMounts];z[P]={...z[P],hostPath:Q.target.value},F({...f,volumeMounts:z})}}),e.jsx("input",{className:"input",value:r.containerPath,placeholder:"Container path",onChange:Q=>{const z=[...f.volumeMounts];z[P]={...z[P],containerPath:Q.target.value},F({...f,volumeMounts:z})}}),e.jsxs("select",{className:"input",value:r.mode??"rw",onChange:Q=>{const z=[...f.volumeMounts];z[P]={...z[P],mode:Q.target.value},F({...f,volumeMounts:z})},children:[e.jsx("option",{value:"rw",children:"rw"}),e.jsx("option",{value:"ro",children:"ro"})]}),e.jsxs("select",{className:"input",value:r.type??"volume",onChange:Q=>{const z=[...f.volumeMounts];z[P]={...z[P],type:Q.target.value},F({...f,volumeMounts:z})},children:[e.jsx("option",{value:"volume",children:"volume"}),e.jsx("option",{value:"bind",children:"bind"})]}),e.jsx("button",{className:"btn btn-sm",onClick:()=>F({...f,volumeMounts:f.volumeMounts.filter((Q,z)=>z!==P)}),children:"Remove"})]},`${r.hostPath}-${r.containerPath}-${P}`)),e.jsx("button",{className:"btn btn-sm",onClick:()=>F({...f,volumeMounts:[...f.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(f.environment).map(([r,P])=>{const Q=qe.test(r)&&!Ee[r];return e.jsxs("div",{className:"node-detail-modal__docker-row",children:[e.jsx("input",{className:"input",value:r,onChange:z=>{const xe={...f.environment};delete xe[r],xe[z.target.value]=P,F({...f,environment:xe})}}),e.jsx("input",{className:"input",value:Q?"***":String(P),onChange:z=>F({...f,environment:{...f.environment,[r]:z.target.value}})}),e.jsx("button",{className:"btn btn-sm",onClick:()=>Re(z=>({...z,[r]:!z[r]})),children:Ee[r]?e.jsx(xs,{size:14}):e.jsx(js,{size:14})}),e.jsx("button",{className:"btn btn-sm",onClick:()=>{const z={...f.environment};delete z[r],F({...f,environment:z})},children:"Remove"})]},r)}),e.jsx("button",{className:"btn btn-sm",onClick:()=>{const r=`NEW_VAR_${Object.keys(f.environment).length+1}`;F({...f,environment:{...f.environment,[r]:""}})},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:f.resources?.memoryBytes??"",onChange:r=>F({...f,resources:{...f.resources,memoryBytes:r.target.value?Number(r.target.value):void 0}})}),e.jsx("input",{className:"input",type:"number",placeholder:"CPU count",value:f.resources?.cpuCount??"",onChange:r=>F({...f,resources:{...f.resources,cpuCount:r.target.value?Number(r.target.value):void 0}})}),e.jsx("input",{className:"input",type:"number",placeholder:"PIDs limit",value:f.resources?.pidsLimit??"",onChange:r=>F({...f,resources:{...f.resources,pidsLimit:r.target.value?Number(r.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:f.host?.contextName??"",onChange:r=>F({...f,host:{...f.host,contextName:r.target.value}})}),e.jsx("input",{className:"input",placeholder:"Docker host URL",value:f.host?.dockerHost??"",onChange:r=>F({...f,host:{...f.host,dockerHost:r.target.value}})}),e.jsx("input",{className:"input",placeholder:"TLS CA cert path",value:f.host?.tlsCaCert??"",onChange:r=>F({...f,host:{...f.host,tlsCaCert:r.target.value}})}),e.jsx("input",{className:"input",placeholder:"TLS cert path",value:f.host?.tlsCert??"",onChange:r=>F({...f,host:{...f.host,tlsCert:r.target.value}})}),e.jsx("input",{className:"input",placeholder:"TLS key path",value:f.host?.tlsKey??"",onChange:r=>F({...f,host:{...f.host,tlsKey:r.target.value}})}),e.jsxs("label",{className:"node-detail-modal__checkbox",children:[e.jsx("input",{type:"checkbox",checked:f.host?.tlsVerify??!0,onChange:r=>F({...f,host:{...f.host,tlsVerify:r.target.checked}})}),"TLS verify"]})]})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Extra CLIs"}),e.jsxs("div",{className:"node-detail-modal__docker-list",children:[(f.extraClis??[]).map((r,P)=>e.jsxs("div",{className:"node-detail-modal__docker-row",children:[e.jsx("input",{className:"input",value:r,onChange:Q=>{const z=[...f.extraClis??[]];z[P]=Q.target.value,F({...f,extraClis:z})}}),e.jsx("button",{className:"btn btn-sm",onClick:()=>F({...f,extraClis:(f.extraClis??[]).filter((Q,z)=>z!==P)}),children:"Remove"})]},`${r}-${P}`)),e.jsx("button",{className:"btn btn-sm",onClick:()=>F({...f,extraClis:[...f.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:f.persistence?.volumeName??"",onChange:r=>F({...f,persistence:{...f.persistence,volumeName:r.target.value}})}),e.jsxs("label",{className:"node-detail-modal__checkbox",children:[e.jsx("input",{type:"checkbox",checked:f.persistence?.retainOnDelete??!1,onChange:r=>F({...f,persistence:{...f.persistence,retainOnDelete:r.target.checked}})}),"Retain on delete"]})]})]}),e.jsxs("div",{className:"node-detail-modal__docker-meta",children:[e.jsxs("span",{children:["Config v",f.configVersion," • Updated ",Ce(f.lastUpdated??a.updatedAt)]}),Ye&&e.jsx("span",{className:"node-detail-modal__docker-recreate",children:"Needs Recreate"})]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>void ns(),disabled:ie,children:[e.jsx($e,{size:14}),ie?"Saving...":"Save Docker Config"]})]})]}),i&&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--${ls}`,"aria-hidden":!0}),e.jsx("strong",{children:lt(re)}),(re==="creating"||re==="recreating"||re==="restarting")&&e.jsx(Ie,{size:14,className:"spin","aria-hidden":!0})]}),e.jsxs("div",{className:"docker-management__status-meta",children:[re==="running"&&e.jsxs("span",{children:["Uptime: ",at(se?.startedAt)]}),re!=="running"&&se?.exitCode!==void 0&&e.jsxs("span",{children:["Exit code: ",se.exitCode]}),(se?.error||i.errorMessage)&&e.jsx("span",{children:se?.error??i.errorMessage})]}),e.jsx("button",{className:"btn btn-sm",onClick:()=>void ss(),disabled:!_||R,children:R?"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:[i.imageName,":",i.imageTag]})})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Container ID"}),e.jsx("strong",{children:e.jsx("code",{children:i.containerId?i.containerId.slice(0,12):"—"})})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Host"}),e.jsx("strong",{children:Xe})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Persistent Storage"}),e.jsx("strong",{children:i.persistentStorage?"Yes":"No"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Port"}),e.jsx("strong",{children:ot(i.reachableUrl)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Resource Sizing"}),e.jsx("strong",{children:Je})]})]}),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(Ue,{size:14}),"Start"]}),e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx(Te,{size:14}),"Stop"]}),e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx(Ie,{size:14}),"Restart"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void ts(),disabled:!n,children:[e.jsx(bs,{size:14}),"View Logs"]})]}),W&&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:()=>h(!1),"aria-label":"Close logs",children:e.jsx(me,{size:14})})]}),q?e.jsx("p",{children:"Fetching logs..."}):e.jsx("pre",{children:O.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(i.envVars).map(([r,P])=>e.jsxs("div",{children:[e.jsx("dt",{children:r}),e.jsx("dd",{children:ct(r,P)})]},r))})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Volume Mounts"}),e.jsx("ul",{className:"docker-management__mounts-list",children:i.volumeMounts.map(r=>e.jsxs("li",{children:[e.jsxs("span",{children:[r.hostPath," → ",r.containerPath]}),r.readOnly&&e.jsx("span",{className:"node-card__type-badge",children:"Read-only"})]},`${r.hostPath}:${r.containerPath}`))})]})]}),a.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Settings Sync"}),j&&e.jsxs("div",{className:"node-detail-modal__sync-status",children:[e.jsx("span",{className:`node-detail-modal__sync-dot ${nt(j.syncState)}`,"aria-hidden":!0}),e.jsxs("span",{children:["Last sync: ",e.jsx("strong",{children:j.lastSyncAt?Ce(j.lastSyncAt):"Never synced"})]}),j.diffCount>0&&e.jsxs("span",{className:"node-detail-modal__sync-diff",children:["Differences: ",e.jsx("strong",{children:j.diffCount})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:Ge,disabled:G||!g,children:[e.jsx(He,{size:14}),G?"Pushing...":"Push Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:Ze,disabled:J||!c,children:[e.jsx(Be,{size:14}),J?"Pulling...":"Pull Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:Qe,disabled:E||!N,children:[e.jsx(Oe,{size:14}),E?"Syncing...":"Sync Auth"]})]}),L&&e.jsxs("div",{className:"node-detail-modal__sync-error",children:[e.jsx("span",{children:L}),e.jsx("button",{className:"node-detail-modal__sync-error-dismiss",onClick:es,"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(et,{nodeId:a.id,entries:w,singleNode:!0})]})]}),e.jsxs("div",{className:"modal-actions node-detail-modal__actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:We,children:[e.jsx(Ke,{size:14}),"Health Check"]}),e.jsx("button",{className:"btn btn-sm",onClick:l,children:"Close"})]})]}),a.type==="remote"&&e.jsx(tt,{isOpen:K,onClose:()=>ae(!1),onResolve:b??(async()=>{}),conflicts:ne,localNodeName:"Local",remoteNodeName:a.name,addToast:o})]})}const dt=15e3,ut=1e3;function mt(){const[t,l]=s.useState([]),[a,d]=s.useState(!0),[u,m]=s.useState(null),o=s.useRef(null),j=s.useRef(0),g=s.useCallback(async()=>{try{m(null);const b=await ze();l(b)}catch(b){m(b instanceof Error?b.message:"Failed to fetch managed Docker nodes")}},[]);s.useEffect(()=>{let b=!1;async function i(){d(!0);try{const _=await ze();b||(l(_),m(null))}catch(_){b||m(_ instanceof Error?_.message:"Failed to fetch managed Docker nodes")}finally{b||d(!1)}}i();const M=()=>{if(document.visibilityState!=="visible")return;const _=Date.now(),n=_-j.current;if(n<ut){he({view:"useManagedDockerNodes",trigger:"visibility",projectId:void 0,replayAttempted:!1,reason:"debounce-skipped",detail:{timeSinceLastRefreshMs:n}});return}j.current=_,he({view:"useManagedDockerNodes",trigger:"visibility",projectId:void 0,replayAttempted:!1,reason:"debounced-refresh"}),g()};return document.addEventListener("visibilitychange",M),()=>{b=!0,document.removeEventListener("visibilitychange",M)}},[g]),s.useEffect(()=>{if(!a)return o.current=setInterval(()=>{g()},dt),()=>{o.current&&(clearInterval(o.current),o.current=null)}},[a,g]);const c=s.useCallback(async b=>vs(b),[]),N=s.useCallback(async(b,i)=>(await ys(b,i)).logs,[]),w=s.useCallback(async b=>{const i=await _s(b),M={...i,nodeId:i.nodeId??void 0,containerId:i.containerId??void 0,status:i.status,hostConfig:{type:i.hostConfig.host||i.hostConfig.context?"remote":"local",host:i.hostConfig.host,context:i.hostConfig.context},reachableUrl:i.reachableUrl??void 0,volumeMounts:i.volumeMounts.map(_=>({hostPath:_.hostPath,containerPath:_.containerPath,readOnly:_.mode==="ro"?!0:void 0})),persistentStorage:i.persistentStorage,resourceSizing:{cpuLimit:i.resourceSizing.cpus!==void 0?String(i.resourceSizing.cpus):void 0,memoryLimit:i.resourceSizing.memoryMB!==void 0?`${i.resourceSizing.memoryMB}MB`:void 0},errorMessage:i.errorMessage??void 0};return l(_=>[..._,M]),M},[]);return{dockerNodes:t,loading:a,error:u,refresh:g,getContainerStatus:c,getLogs:N,create:w}}function bt({addToast:t,onClose:l}){const{nodes:a,loading:d,error:u,refresh:m,register:o,update:j,unregister:g,healthCheck:c,patchDockerConfig:N,fetchDockerDiff:w,discoverRemoteProjects:b}=Ns(),{projects:i,refresh:M}=ks(),{meshState:_,loading:n,error:v}=Is(),{syncStatusMap:C,pushSettings:k,pullSettings:D,syncAuth:V,trackNode:A,getAuthSyncState:x,getAuthProviders:p}=Ls(),{dockerNodes:S,loading:Z,refresh:H,getContainerStatus:Y,getLogs:ee,create:U}=mt(),[X,G]=s.useState(!1),[te,J]=s.useState(!1),[T,E]=s.useState(null);s.useEffect(()=>{const R=a.filter(I=>I.type==="remote");for(const I of R)A(I.id)},[a,A]),s.useEffect(()=>{if(!T)return;const R=a.find(I=>I.id===T.id)??null;E(R)},[a,T]);const y=s.useMemo(()=>{const R=a.length,I=a.filter(q=>q.status==="online").length,W=a.filter(q=>q.status==="offline"||q.status==="error").length,h=a.filter(q=>q.type==="remote").length,O=a.filter(q=>q.type==="remote"&&C[q.id]&&je(C[q.id]).syncState==="synced").length,B=S.length;return{total:R,online:I,offline:W,remote:h,synced:O,docker:B}},[S.length,a,C]),L=s.useCallback(async R=>{await o(R),await M()},[M,o]),$=s.useCallback(async R=>{try{await U(R),t(`Docker node "${R.name}" created`,"success"),J(!1)}catch(I){const W=I instanceof Error?I.message:"Failed to create Docker node";throw t(W,"error"),I}},[t,U]),K=s.useMemo(()=>{const R=new Map;for(const I of S)I.nodeId&&R.set(I.nodeId,I);return R},[S]),ae=s.useCallback(async()=>{try{await Promise.all([m(),H()])}catch{t("Failed to refresh nodes","error")}},[t,m,H]),ne=s.useCallback(async R=>{try{await c(R),t("Node health check complete","success")}catch(I){const W=I instanceof Error?I.message:"Health check failed";t(W,"error")}},[t,c]),se=s.useCallback(async R=>{try{await g(R),t("Node removed","success"),T?.id===R&&E(null)}catch(I){const W=I instanceof Error?I.message:"Failed to remove node";t(W,"error")}},[t,T?.id,g]),le=s.useCallback(async(R,I)=>{await j(R,I)},[j]);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(Fe,{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 ae(),disabled:d||Z,children:[e.jsx(ke,{size:14,className:d?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>G(!0),children:[e.jsx(fe,{size:14}),"Add Node"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>J(!0),title:"Add a managed Docker node",children:[e.jsx(_e,{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:y.total})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--online","data-testid":"nodes-stat-online",children:[e.jsxs("span",{children:[e.jsx(Es,{size:14})," Online"]}),e.jsx("strong",{children:y.online})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--offline","data-testid":"nodes-stat-offline",children:[e.jsxs("span",{children:[e.jsx(Ms,{size:14})," Offline"]}),e.jsx("strong",{children:y.offline})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-remote",children:[e.jsxs("span",{children:[e.jsx(Cs,{size:14})," Remote"]}),e.jsx("strong",{children:y.remote})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--synced","data-testid":"nodes-stat-synced",children:[e.jsxs("span",{children:[e.jsx(ke,{size:14})," Synced"]}),e.jsx("strong",{children:y.synced})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-docker",children:[e.jsxs("span",{children:[e.jsx(_e,{size:14})," Docker"]}),e.jsx("strong",{children:y.docker})]})]}),(u||v)&&e.jsx("div",{className:"nodes-view-error",children:u??v}),!n&&_.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(Ys,{nodes:_})]}),d?e.jsx("div",{className:"nodes-view-grid",children:Array.from({length:4}).map((R,I)=>e.jsx("div",{className:"node-card node-card--loading","aria-hidden":!0},I))}):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:()=>G(!0),children:[e.jsx(fe,{size:14}),"Add First Node"]})]}):e.jsx("div",{className:"nodes-view-grid",children:a.map(R=>{const I=R.type==="remote"&&C[R.id]?je(C[R.id]):void 0;return e.jsx(Us,{node:R,projects:i,onHealthCheck:W=>{ne(W)},onEdit:W=>E(W),onRemove:W=>{se(W)},isLoading:d,syncStatus:I,authSyncState:R.type==="remote"?x(R.id):void 0,authSyncProviders:R.type==="remote"?p(R.id):void 0,managedDockerNode:K.get(R.id)},R.id)})}),e.jsx(Js,{isOpen:X,onClose:()=>G(!1),onSubmit:L,onDiscoverRemoteProjects:b,addToast:t,projects:i}),e.jsx(Qs,{isOpen:te,onClose:()=>J(!1),onSubmit:$,addToast:t}),e.jsx(it,{isOpen:T!==null,onClose:()=>E(null),node:T,projects:i,onUpdate:le,onHealthCheck:ne,addToast:t,syncStatus:T?.type==="remote"&&T&&C[T.id]?je(C[T.id]):void 0,onPushSettings:k,onPullSettings:D,onSyncAuth:V,managedDockerNode:T?K.get(T.id):void 0,onFetchContainerStatus:Y,onFetchLogs:ee,onUpdateDockerConfig:N,onFetchDockerConfigDiff:w})]})}export{bt as NodesView};
|
package/dist/client/assets/{PiExtensionsManager-Cyfas2VT.js → PiExtensionsManager-C0ljxGbt.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{r as l,j as e}from"./vendor-react-K0fH_qHe.js";import{c as
|
|
1
|
+
import{r as l,j as e}from"./vendor-react-K0fH_qHe.js";import{c as Y,eX as Z,eY as H,eZ as Q,R as $,eM as y,J as V,a as T,b as ee,_ as se,e_ as L,cT as D,F as _,e$ as ae,f0 as te,f1 as M,X as ie}from"./index-tJzhtiGM.js";import"./vendor-xterm-DzcZoU0P.js";import"./vendor-codemirror-jBKmHyH0.js";/**
|
|
2
2
|
* @license lucide-react v1.7.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/const ne=[["path",{d:"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",key:"e79jfc"}],["circle",{cx:"13.5",cy:"6.5",r:".5",fill:"currentColor",key:"1okk4w"}],["circle",{cx:"17.5",cy:"10.5",r:".5",fill:"currentColor",key:"f64h9f"}],["circle",{cx:"6.5",cy:"12.5",r:".5",fill:"currentColor",key:"qy21gx"}],["circle",{cx:"8.5",cy:"7.5",r:".5",fill:"currentColor",key:"fotxhn"}]],A=
|
|
6
|
+
*/const ne=[["path",{d:"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",key:"e79jfc"}],["circle",{cx:"13.5",cy:"6.5",r:".5",fill:"currentColor",key:"1okk4w"}],["circle",{cx:"17.5",cy:"10.5",r:".5",fill:"currentColor",key:"f64h9f"}],["circle",{cx:"6.5",cy:"12.5",r:".5",fill:"currentColor",key:"qy21gx"}],["circle",{cx:"8.5",cy:"7.5",r:".5",fill:"currentColor",key:"fotxhn"}]],A=Y("palette",ne);function le(t){return t.replace(/-/g,"-")}function ce(t){return{"fusion-global":"Fusion Global","pi-global":"Pi Global","fusion-project":"Fusion Project","pi-project":"Pi Project",package:"Package"}[t]??t}function re(t){return t.startsWith("npm:")?"npm":t.startsWith("git:")?"git":"local"}function oe(t){return t.replace(/^(npm:|git:)/,"")}function he({addToast:t,projectId:x}){const[c,G]=l.useState(null),[f,P]=l.useState(!0),[N,S]=l.useState(!1),[E,w]=l.useState(!1),[h,F]=l.useState(""),[I,O]=l.useState(new Set),[p,W]=l.useState([]),[b,C]=l.useState(!0),[X,R]=l.useState(!1),r=l.useCallback(async()=>{try{P(!0);const s=await Z();G(s)}catch(s){t(`Failed to load Pi settings: ${s instanceof Error?s.message:String(s)}`,"error")}finally{P(!1)}},[t]),m=l.useCallback(async()=>{try{C(!0);const s=await H(x);W(s.extensions)}catch(s){t(`Failed to load extensions: ${s instanceof Error?s.message:String(s)}`,"error")}finally{C(!1)}},[t,x]),q=l.useCallback(async s=>{try{R(!0);const i=s.enabled?[...p.filter(a=>a.enabled&&a.id!==s.id).map(a=>a.id),s.id]:p.filter(a=>a.enabled&&a.id!==s.id).map(a=>a.id);await Q(i,x),await m(),t(s.enabled?"Extension disabled":"Extension enabled","success")}catch(i){t(`Failed to update extension: ${i instanceof Error?i.message:String(i)}`,"error")}finally{R(!1)}},[p,x,m,t]);l.useEffect(()=>{r()},[r]),l.useEffect(()=>{m()},[m]);const B=s=>{O(i=>{const a=new Set(i);return a.has(s)?a.delete(s):a.add(s),a})},z=async()=>{if(!h.trim()){t("Please enter a package source","error");return}try{S(!0),await ae(h.trim()),t("Package installed successfully","success"),F(""),await r()}catch(s){t(`Failed to install package: ${s instanceof Error?s.message:String(s)}`,"error")}finally{S(!1)}},J=async()=>{try{w(!0),await te(x),await Promise.all([r(),m()]),t("Fusion skill reinstalled successfully","success")}catch(s){t(`Failed to reinstall Fusion skill: ${s instanceof Error?s.message:String(s)}`,"error")}finally{w(!1)}},K=async s=>{if(!c)return;const i=c.packages.filter(a=>(typeof a=="string"?a:a.source)!==s);try{await M({packages:i}),t("Package removed","success"),await r()}catch(a){t(`Failed to remove package: ${a instanceof Error?a.message:String(a)}`,"error")}},U=async(s,i)=>{if(!c)return;const a=c[s].filter(n=>n!==i);try{await M({[s]:a}),t(`${s.slice(0,-1)} removed`,"success"),await r()}catch(n){t(`Failed to update settings: ${n instanceof Error?n.message:String(n)}`,"error")}},u=(s,i,a)=>!c||c[a].length===0?null:e.jsxs("div",{className:"pi-ext-section",children:[e.jsxs("div",{className:"pi-ext-section-header",children:[e.jsx(i,{size:14}),e.jsx("span",{children:s}),e.jsx("span",{className:"pi-ext-count",children:c[a].length})]}),e.jsx("div",{className:"pi-ext-resource-list",children:c[a].map((n,g)=>e.jsxs("span",{className:"pi-ext-resource-tag",children:[e.jsx("span",{className:"pi-ext-resource-path",children:n}),e.jsx("button",{className:"btn-icon touch-target pi-ext-resource-remove",onClick:()=>U(a,n),title:`Remove ${n}`,"aria-label":`Remove ${n}`,children:e.jsx(ie,{})})]},g))})]});return e.jsxs("div",{className:"pi-ext-manager",children:[e.jsxs("div",{className:"pi-ext-manager-header",children:[e.jsx("h4",{className:"pi-ext-manager-title",children:"Pi Extensions"}),e.jsx("div",{className:"pi-ext-manager-actions",children:e.jsx("button",{className:"btn-icon",onClick:r,title:"Refresh",disabled:f,children:e.jsx($,{size:16,className:f?"spin":""})})})]}),f?e.jsx("div",{className:"loading-state",children:"Loading Pi settings…"}):c?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"pi-ext-add-form",children:[e.jsxs("div",{className:"pi-ext-add-form-row",children:[e.jsx("input",{type:"text",className:"input",placeholder:"npm:pi-extension-name or git:https://github.com/...",value:h,onChange:s=>F(s.target.value),onKeyDown:s=>{s.key==="Enter"&&(s.preventDefault(),z())},disabled:N}),e.jsxs("button",{className:"btn btn-primary",onClick:z,disabled:N||!h.trim(),children:[e.jsx(V,{size:14}),N?"Installing…":"Add"]})]}),e.jsx("div",{className:"pi-ext-add-form-row",children:e.jsx("button",{className:"btn",onClick:J,disabled:E,children:E?"Reinstalling Fusion…":"Reinstall Fusion skill"})})]}),c.packages.length>0?e.jsx("div",{className:"pi-ext-package-list",children:c.packages.map((s,i)=>{const a=typeof s=="string"?s:s.source,n=re(a),g=oe(a),j=typeof s=="object"&&s!==null,v=j&&(s.extensions?.length??0)>0||(s.skills?.length??0)>0||(s.prompts?.length??0)>0||(s.themes?.length??0)>0,k=I.has(i);return e.jsxs("div",{className:"pi-ext-package-card",children:[e.jsxs("div",{className:"pi-ext-package-header",children:[j&&v?e.jsx("button",{className:"pi-ext-expand-btn",onClick:()=>B(i),"aria-expanded":k,children:k?e.jsx(T,{size:14}):e.jsx(ee,{size:14})}):e.jsx("span",{className:"pi-ext-expand-placeholder"}),e.jsx("span",{className:`pi-ext-source-badge pi-ext-source-badge--${n}`,children:n}),e.jsx("span",{className:"pi-ext-package-source",children:g}),e.jsxs("div",{className:"pi-ext-package-actions",children:[j&&v&&e.jsxs("span",{className:"pi-ext-filter-hint",children:[s.extensions?.length??0," ext,"," ",s.skills?.length??0," skill,"," ",s.prompts?.length??0," prompt,"," ",s.themes?.length??0," theme"]}),e.jsx("button",{className:"btn-icon touch-target pi-ext-remove-btn",onClick:()=>K(a),title:"Remove package","aria-label":`Remove package ${g}`,children:e.jsx(se,{size:14})})]})]}),j&&v&&k&&e.jsxs("div",{className:"pi-ext-filter-list",children:[s.extensions?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(L,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Extensions:"}),s.extensions.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null,s.skills?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(D,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Skills:"}),s.skills.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null,s.prompts?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(_,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Prompts:"}),s.prompts.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null,s.themes?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(A,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Themes:"}),s.themes.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null]})]},i)})}):e.jsxs("div",{className:"empty-state",children:[e.jsx(y,{size:32,className:"text-muted"}),e.jsx("p",{children:"No packages configured."}),e.jsx("p",{className:"text-muted",children:"Add a package source above to get started."})]}),e.jsxs("div",{className:"pi-ext-top-level",children:[u("Extensions",L,"extensions"),u("Skills",D,"skills"),u("Prompts",_,"prompts"),u("Themes",A,"themes")]})]}):e.jsxs("div",{className:"empty-state",children:[e.jsx(y,{size:32,className:"text-muted"}),e.jsx("p",{children:"Failed to load Pi settings."})]}),e.jsxs("div",{className:"pi-ext-discovered-section",children:[e.jsxs("div",{className:"pi-ext-discovered-header",children:[e.jsx("h4",{children:"Discovered Extensions"}),e.jsx("button",{className:"btn-icon",onClick:m,disabled:b,title:"Refresh extensions",children:e.jsx($,{className:b?"spin":""})})]}),e.jsx("p",{className:"pi-ext-description",children:"Installed extensions resolved from packages and configured paths."}),b?e.jsx("div",{className:"loading-state",children:"Loading extensions…"}):p.length===0?e.jsxs("div",{className:"empty-state",children:[e.jsx(y,{size:32,className:"text-muted"}),e.jsx("p",{children:"No extensions discovered."})]}):e.jsx("div",{className:"pi-ext-list",children:p.map(s=>e.jsxs("div",{className:"pi-ext-item",children:[e.jsxs("div",{className:"pi-ext-item-content",children:[e.jsxs("div",{className:"pi-ext-info",children:[e.jsx("span",{className:"pi-ext-name",children:s.name}),e.jsx("span",{className:`pi-ext-source-badge pi-ext-source-badge--${le(s.source)}`,children:ce(s.source)})]}),e.jsx("span",{className:"pi-ext-path",children:s.path})]}),e.jsx("div",{className:"pi-ext-actions",children:e.jsxs("label",{className:"toggle-switch",children:[e.jsx("input",{type:"checkbox",checked:s.enabled,onChange:()=>void q(s),disabled:X,"aria-label":`Toggle ${s.name}`}),e.jsx("span",{className:"toggle-slider"})]})})]},s.id))})]})]})}export{he as PiExtensionsManager};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as g,j as e}from"./vendor-react-K0fH_qHe.js";import{v as ye,eA as je,eB as Y,s as Ne,X as Z,az as Se,aX as ve,J as T,b3 as ee,Y as se,R as we,eC as Ce,av as Ie,eD as $e,eE as Pe,cC as Re,eF as Ee,eG as ke,eH as Be,eI as Ae,eJ as te,cz as Le,eK as Fe}from"./index-Ba-F8c1g.js";import{D as De}from"./DirectoryPicker-DctpCNrd.js";import"./vendor-xterm-DzcZoU0P.js";import"./vendor-codemirror-jBKmHyH0.js";import"./folder-open-mxsFQlAX.js";const le="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-reports",name:"Reports",description:"View report history, compare runs side-by-side, and export standalone HTML summaries.",category:"integration",path:"./plugins/fusion-plugin-reports"},{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:"fusion-plugin-cli-printing-press",name:"CLI Printing Press",description:"Guided wizard for drafting external service CLI definitions.",category:"integration",path:"./plugins/fusion-plugin-cli-printing-press"},{id:le,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 ze(i){const c=i.settingsSchema,h=c&&Object.keys(c).length>0;return i.id!==le?h?c:void 0:h?{...ne,...c}:ne}function Oe(i){const c=new Map,h=[];for(const[x,f]of Object.entries(i))if(f.group){const N=c.get(f.group)??[];N.push([x,f]),c.set(f.group,N)}else h.push([x,f]);return{grouped:c,ungrouped:h}}function ie(i,c="plugin-error-text"){return i.state!=="error"||!i.error?null:e.jsx("p",{className:c,title:i.error,children:i.error})}function We({addToast:i,projectId:c}){const[h,x]=g.useState([]),[f,N]=g.useState(!0),[re,$]=g.useState(!1),[w,P]=g.useState(""),[B,A]=g.useState(!1),[L,F]=g.useState(!1),[S,D]=g.useState(null),[r,R]=g.useState(null),[p,b]=g.useState({}),[ce,z]=g.useState(!1),[O,G]=g.useState(null),[oe,E]=g.useState({}),[ue,U]=g.useState(null),[C,q]=g.useState(null),{confirm:de}=ye(),m=g.useCallback(async()=>{try{N(!0);const s=await je(c);x(s)}catch(s){i(`Failed to load plugins: ${s instanceof Error?s.message:String(s)}`,"error")}finally{N(!1)}},[c,i]);g.useEffect(()=>{m()},[m]),g.useEffect(()=>{const s=ae.filter(o=>o.hasSetup&&h.some(l=>l.id===o.id));if(s.length===0)return;let n=!1;return Promise.all(s.map(async o=>{try{const l=await Y(o.id,c);if(n)return;E(u=>({...u,[o.id]:l}))}catch{if(n)return;E(l=>({...l,[o.id]:{hasSetup:!0,setupCheckDeferred:!0,deferredReason:"plugin-not-started",pluginState:"installed"}}))}})),()=>{n=!0}},[h,c]);const pe=g.useRef([]);pe.current=h,g.useEffect(()=>{const s=c?`?projectId=${encodeURIComponent(c)}`:"",n=o=>{try{const l=JSON.parse(o.data);if(l.scope==="project"&&(l.projectId??c)!==c)return;switch(l.transition){case"installing":case"enabled":case"disabled":case"settings-updated":x(u=>{const a=u.findIndex(t=>t.id===l.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],enabled:l.enabled,state:l.state,settings:l.settings,error:l.error},t}else return m(),u});break;case"state-changed":x(u=>{const a=u.findIndex(t=>t.id===l.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],state:l.state,error:l.error},t}return u});break;case"uninstalled":x(u=>u.filter(a=>a.id!==l.pluginId));break;case"error":x(u=>{const a=u.findIndex(t=>t.id===l.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],state:l.state,error:l.error},t}return u});break}}catch{}};return Ne(`/api/events${s}`,{events:{"plugin:lifecycle":n},onReconnect:()=>{m()}})},[c,m]);const M=async()=>{if(!w.trim()){i("Please enter a plugin path","error");return}try{A(!0),await te({path:w,...L?{aiScanOnLoad:!0}:{}},c),i("Plugin installed globally","success"),$(!1),P(""),F(!1),await m()}catch(s){i(`Failed to install plugin: ${s instanceof Error?s.message:String(s)}`,"error")}finally{A(!1)}},ge=async s=>{if(!s.path){i(`${s.name} is built in and does not have an installable package yet`,"warning");return}try{G(s.id),await te({path:s.path},c),i(`${s.name} installed globally`,"success"),await m()}catch(n){i(`Failed to install ${s.name}: ${n instanceof Error?n.message:String(n)}`,"error")}finally{G(null)}},V=async s=>{try{q(s.id);const n=await Fe(s.id,c);if(!n.success){i(`Failed to install ${s.name} setup: ${n.error??"unknown error"}`,"error");return}i(`${s.name} setup installed`,"success"),U(s.id);const o=await Y(s.id,c);E(l=>({...l,[s.id]:o}))}catch(n){i(`Failed to install ${s.name} setup: ${n instanceof Error?n.message:String(n)}`,"error")}finally{q(null),U(null)}},_=async s=>{try{const n=await Be(s.id,c);if(n.state==="error"){i(`Failed to enable ${s.name}: ${n.error??"Unknown error"}`,"error"),await m();return}i(`${s.name} enabled for this project`,"success"),await m()}catch(n){i(`Failed to enable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},H=async s=>{try{await ke(s.id,c),i(`${s.name} disabled for this project`,"success"),await m()}catch(n){i(`Failed to disable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},W=async s=>{try{D(s.id),await Ee(s.id,c),i(`${s.name} reloaded`,"success"),await m()}catch(n){i(`Failed to reload plugin: ${n instanceof Error?n.message:String(n)}`,"error")}finally{D(null)}},J=async s=>{if(await de({title:"Uninstall Plugin Globally",message:`Are you sure you want to uninstall "${s.name}" globally (all projects)?`,danger:!0}))try{await Ae(s.id,c),i(`${s.name} uninstalled globally`,"success"),await m(),R(null)}catch(o){i(`Failed to uninstall plugin: ${o instanceof Error?o.message:String(o)}`,"error")}},me=async(s,n)=>{try{await $e(s.id,{aiScanOnLoad:n},c),i(`AI scan on load ${n?"enabled":"disabled"}`,"success"),await m()}catch(o){i(`Failed to update plugin: ${o instanceof Error?o.message:String(o)}`,"error")}},he=async s=>{try{await Pe(s.id,c),i(`${s.name} rescanned`,"success"),await m()}catch(n){i(`Failed to rescan plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},k=async s=>{R(s);try{z(!0);const n=await Le(s.id,c);b(n)}catch{b({})}finally{z(!1)}},be=async()=>{if(r)try{await Re(r.id,p,c),i("Settings saved","success")}catch(s){i(`Failed to save settings: ${s instanceof Error?s.message:String(s)}`,"error")}};if(r)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.jsxs("div",{className:"plugin-detail-title-copy",children:[e.jsx("h4",{className:"plugin-detail-name",children:r.name}),ie(r,"plugin-error-text plugin-error-text--detail")]}),e.jsx("span",{className:"plugin-state-badge",style:{color:I[r.state]||I.installed},children:r.state})]})]}),e.jsxs("div",{className:"plugin-detail-content",children:[e.jsxs("div",{className:"plugin-detail-card",children:[r.description&&e.jsx("p",{className:"plugin-description",children:r.description}),r.author&&e.jsxs("p",{className:"plugin-detail-meta-row",children:[e.jsx("span",{className:"text-muted",children:"Author:"}),r.author]}),r.homepage&&e.jsxs("p",{className:"plugin-detail-meta-row plugin-homepage",children:[e.jsx("span",{className:"text-muted",children:"Homepage:"}),e.jsxs("a",{href:r.homepage,target:"_blank",rel:"noopener noreferrer",children:[r.homepage,e.jsx(Se,{size:12})]})]}),e.jsxs("p",{className:"plugin-detail-meta-row",children:[e.jsx("span",{className:"text-muted",children:"Version:"}),r.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:!!r.aiScanOnLoad,onChange:s=>void me(r,s.target.checked)}),"Enable AI scan before load/reload"]}),e.jsxs("button",{className:"btn btn-secondary btn-sm",onClick:()=>void he(r),children:[e.jsx(ve,{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."}),r.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--${r.lastSecurityScan.verdict}`,children:r.lastSecurityScan.verdict}),e.jsx("span",{className:"text-muted",children:r.lastSecurityScan.scannedAt})]}),e.jsx("p",{className:"plugin-security-summary",children:r.lastSecurityScan.summary}),e.jsxs("details",{children:[e.jsxs("summary",{children:["Findings (",r.lastSecurityScan.findings.length,")"]}),e.jsx("ul",{className:"plugin-security-findings",children:r.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"}),ce?e.jsx("p",{className:"text-muted",children:"Loading..."}):(()=>{const s=ze(r);return s&&Object.keys(s).length>0?e.jsxs("div",{className:"plugin-settings-form",children:[(()=>{const{grouped:n,ungrouped:o}=Oe(s),l=[];o.length>0&&l.push({title:null,entries:o});for(const[u,a]of n.entries())l.push({title:u,entries:a});return l.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:X=>{const v=X.target.value,Q=[...p[a]||[]];Q[j]=t.itemType==="number"?Number(v):v,b({...p,[a]:Q})}}),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:be,children:"Save Settings"})]}):e.jsx("p",{className:"text-muted",children:"No configurable settings."})})()]}),e.jsxs("div",{className:"plugin-detail-actions",children:[r.state==="started"&&e.jsxs("button",{className:"btn btn-secondary",onClick:()=>W(r),disabled:S===r.id,children:[e.jsx(ee,{size:14,className:S===r.id?"spin":""}),S===r.id?"Reloading...":"Reload"]}),r.enabled?e.jsx("button",{className:"btn btn-secondary",onClick:()=>H(r),children:"Disable in Project"}):e.jsx("button",{className:"btn btn-primary",onClick:()=>_(r),children:"Enable in Project"}),e.jsxs("button",{className:"btn btn-danger",onClick:()=>J(r),children:[e.jsx(se,{size:14})," Uninstall Globally"]})]})]})]});const xe=new Map(h.map(s=>[s.id,s])),K=h,fe=()=>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=xe.get(s.id),o=!!n,l=oe[s.id],u=!!(l&&"setupCheckDeferred"in l&&l.setupCheckDeferred),a=l&&"status"in l?l.status:void 0,t=o&&s.hasSetup&&l?.hasSetup&&!u&&n?.state==="started"&&(a==="not-installed"||a==="error"),y=o&&l?.hasSetup&&a==="installed",d=ue===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 ${o?"plugin-builtins-status--installed":"plugin-builtins-status--available"}`,children:o?"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?o&&t?e.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>void V(s),disabled:C===s.id||d,children:C===s.id?"Setting up...":"Install Setup"}):o&&n?e.jsx("button",{className:"btn btn-secondary btn-sm",onClick:()=>void k(n),children:"Manage"}):e.jsx("span",{className:"plugin-builtins-metadata-only",children:"Built-in metadata only"}):e.jsx("button",{className:`btn ${o&&!t?"btn-secondary":"btn-primary"} btn-sm`,onClick:()=>{if(!o){ge(s);return}if(t){V(s);return}n&&k(n)},disabled:O===s.id||C===s.id||d,children:o?t?C===s.id?"Setting up...":"Install Setup":"Manage":O===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(we,{size:14,className:f?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>$(!0),children:[e.jsx(T,{size:14})," Install"]})]})]}),re&&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(De,{value:w,onChange:P,placeholder:"Absolute path to plugin directory or dist folder",onInputKeyDown:s=>{s.key==="Enter"&&(s.preventDefault(),M())}}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:L,onChange:s=>F(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:M,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(Ce,{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.jsx("div",{className:"plugin-info",children:e.jsxs("div",{className:"plugin-copy",children:[e.jsxs("div",{className:"plugin-copy-header",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})]}),ie(s)]})}),e.jsxs("div",{className:"plugin-actions",children:[s.state==="started"&&e.jsx("button",{className:"btn-icon",onClick:()=>W(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?H(s):_(s),"aria-label":`${s.enabled?"Disable":"Enable"} ${s.name}`}),e.jsx("span",{className:"toggle-slider"})]}),e.jsx("button",{className:"btn-icon",onClick:()=>k(s),title:"Settings",children:e.jsx(Ie,{size:14})}),e.jsx("button",{className:"btn-icon",onClick:()=>J(s),title:"Uninstall globally",children:e.jsx(se,{size:14})})]})]},s.id))}),fe()]})]})}export{ne as AGENT_BROWSER_SETTINGS_SCHEMA,le as BUILTIN_AGENT_BROWSER_PLUGIN_ID,We as PluginManager,I as STATE_COLORS};
|
|
1
|
+
import{r as g,j as e}from"./vendor-react-K0fH_qHe.js";import{v as ye,eK as je,eL as Z,s as Ne,X as Y,aA as Se,aZ as ve,J as T,b5 as ee,_ as se,R as we,eM as Ce,aw as Ie,eN as Pe,eO as $e,cJ as Re,eP as Ee,eQ as ke,eR as Be,eS as Le,eT as te,cG as Ae,eU as Fe}from"./index-tJzhtiGM.js";import{D as De}from"./DirectoryPicker-ioTzF36r.js";import"./vendor-xterm-DzcZoU0P.js";import"./vendor-codemirror-jBKmHyH0.js";import"./folder-open-CZghG0dv.js";const le="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-reports",name:"Reports",description:"View report history, compare runs side-by-side, and export standalone HTML summaries.",category:"integration",path:"./plugins/fusion-plugin-reports"},{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:"fusion-plugin-cli-printing-press",name:"CLI Printing Press",description:"Guided wizard for drafting external service CLI definitions.",category:"integration",path:"./plugins/fusion-plugin-cli-printing-press"},{id:le,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 Oe(i){const c=i.settingsSchema,h=c&&Object.keys(c).length>0;return i.id!==le?h?c:void 0:h?{...ne,...c}:ne}function ze(i){const c=new Map,h=[];for(const[x,f]of Object.entries(i))if(f.group){const N=c.get(f.group)??[];N.push([x,f]),c.set(f.group,N)}else h.push([x,f]);return{grouped:c,ungrouped:h}}function ie(i,c="plugin-error-text"){return i.state!=="error"||!i.error?null:e.jsx("p",{className:c,title:i.error,children:i.error})}function We({addToast:i,projectId:c}){const[h,x]=g.useState([]),[f,N]=g.useState(!0),[re,P]=g.useState(!1),[w,$]=g.useState(""),[B,L]=g.useState(!1),[A,F]=g.useState(!1),[S,D]=g.useState(null),[r,R]=g.useState(null),[p,b]=g.useState({}),[ce,O]=g.useState(!1),[z,G]=g.useState(null),[oe,E]=g.useState({}),[ue,U]=g.useState(null),[C,M]=g.useState(null),{confirm:de}=ye(),m=g.useCallback(async()=>{try{N(!0);const s=await je(c);x(s)}catch(s){i(`Failed to load plugins: ${s instanceof Error?s.message:String(s)}`,"error")}finally{N(!1)}},[c,i]);g.useEffect(()=>{m()},[m]),g.useEffect(()=>{const s=ae.filter(o=>o.hasSetup&&h.some(l=>l.id===o.id));if(s.length===0)return;let n=!1;return Promise.all(s.map(async o=>{try{const l=await Z(o.id,c);if(n)return;E(u=>({...u,[o.id]:l}))}catch{if(n)return;E(l=>({...l,[o.id]:{hasSetup:!0,setupCheckDeferred:!0,deferredReason:"plugin-not-started",pluginState:"installed"}}))}})),()=>{n=!0}},[h,c]);const pe=g.useRef([]);pe.current=h,g.useEffect(()=>{const s=c?`?projectId=${encodeURIComponent(c)}`:"",n=o=>{try{const l=JSON.parse(o.data);if(l.scope==="project"&&(l.projectId??c)!==c)return;switch(l.transition){case"installing":case"enabled":case"disabled":case"settings-updated":x(u=>{const a=u.findIndex(t=>t.id===l.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],enabled:l.enabled,state:l.state,settings:l.settings,error:l.error},t}else return m(),u});break;case"state-changed":x(u=>{const a=u.findIndex(t=>t.id===l.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],state:l.state,error:l.error},t}return u});break;case"uninstalled":x(u=>u.filter(a=>a.id!==l.pluginId));break;case"error":x(u=>{const a=u.findIndex(t=>t.id===l.pluginId);if(a>=0){const t=[...u];return t[a]={...t[a],state:l.state,error:l.error},t}return u});break}}catch{}};return Ne(`/api/events${s}`,{events:{"plugin:lifecycle":n},onReconnect:()=>{m()}})},[c,m]);const _=async()=>{if(!w.trim()){i("Please enter a plugin path","error");return}try{L(!0),await te({path:w,...A?{aiScanOnLoad:!0}:{}},c),i("Plugin installed globally","success"),P(!1),$(""),F(!1),await m()}catch(s){i(`Failed to install plugin: ${s instanceof Error?s.message:String(s)}`,"error")}finally{L(!1)}},ge=async s=>{if(!s.path){i(`${s.name} is built in and does not have an installable package yet`,"warning");return}try{G(s.id),await te({path:s.path},c),i(`${s.name} installed globally`,"success"),await m()}catch(n){i(`Failed to install ${s.name}: ${n instanceof Error?n.message:String(n)}`,"error")}finally{G(null)}},q=async s=>{try{M(s.id);const n=await Fe(s.id,c);if(!n.success){i(`Failed to install ${s.name} setup: ${n.error??"unknown error"}`,"error");return}i(`${s.name} setup installed`,"success"),U(s.id);const o=await Z(s.id,c);E(l=>({...l,[s.id]:o}))}catch(n){i(`Failed to install ${s.name} setup: ${n instanceof Error?n.message:String(n)}`,"error")}finally{M(null),U(null)}},V=async s=>{try{const n=await Be(s.id,c);if(n.state==="error"){i(`Failed to enable ${s.name}: ${n.error??"Unknown error"}`,"error"),await m();return}i(`${s.name} enabled for this project`,"success"),await m()}catch(n){i(`Failed to enable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},H=async s=>{try{await ke(s.id,c),i(`${s.name} disabled for this project`,"success"),await m()}catch(n){i(`Failed to disable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},W=async s=>{try{D(s.id),await Ee(s.id,c),i(`${s.name} reloaded`,"success"),await m()}catch(n){i(`Failed to reload plugin: ${n instanceof Error?n.message:String(n)}`,"error")}finally{D(null)}},J=async s=>{if(await de({title:"Uninstall Plugin Globally",message:`Are you sure you want to uninstall "${s.name}" globally (all projects)?`,danger:!0}))try{await Le(s.id,c),i(`${s.name} uninstalled globally`,"success"),await m(),R(null)}catch(o){i(`Failed to uninstall plugin: ${o instanceof Error?o.message:String(o)}`,"error")}},me=async(s,n)=>{try{await Pe(s.id,{aiScanOnLoad:n},c),i(`AI scan on load ${n?"enabled":"disabled"}`,"success"),await m()}catch(o){i(`Failed to update plugin: ${o instanceof Error?o.message:String(o)}`,"error")}},he=async s=>{try{await $e(s.id,c),i(`${s.name} rescanned`,"success"),await m()}catch(n){i(`Failed to rescan plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},k=async s=>{R(s);try{O(!0);const n=await Ae(s.id,c);b(n)}catch{b({})}finally{O(!1)}},be=async()=>{if(r)try{await Re(r.id,p,c),i("Settings saved","success")}catch(s){i(`Failed to save settings: ${s instanceof Error?s.message:String(s)}`,"error")}};if(r)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(Y,{size:16})}),e.jsxs("div",{className:"plugin-detail-title",children:[e.jsxs("div",{className:"plugin-detail-title-copy",children:[e.jsx("h4",{className:"plugin-detail-name",children:r.name}),ie(r,"plugin-error-text plugin-error-text--detail")]}),e.jsx("span",{className:"plugin-state-badge",style:{color:I[r.state]||I.installed},children:r.state})]})]}),e.jsxs("div",{className:"plugin-detail-content",children:[e.jsxs("div",{className:"plugin-detail-card",children:[r.description&&e.jsx("p",{className:"plugin-description",children:r.description}),r.author&&e.jsxs("p",{className:"plugin-detail-meta-row",children:[e.jsx("span",{className:"text-muted",children:"Author:"}),r.author]}),r.homepage&&e.jsxs("p",{className:"plugin-detail-meta-row plugin-homepage",children:[e.jsx("span",{className:"text-muted",children:"Homepage:"}),e.jsxs("a",{href:r.homepage,target:"_blank",rel:"noopener noreferrer",children:[r.homepage,e.jsx(Se,{size:12})]})]}),e.jsxs("p",{className:"plugin-detail-meta-row",children:[e.jsx("span",{className:"text-muted",children:"Version:"}),r.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:!!r.aiScanOnLoad,onChange:s=>void me(r,s.target.checked)}),"Enable AI scan before load/reload"]}),e.jsxs("button",{className:"btn btn-secondary btn-sm",onClick:()=>void he(r),children:[e.jsx(ve,{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."}),r.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--${r.lastSecurityScan.verdict}`,children:r.lastSecurityScan.verdict}),e.jsx("span",{className:"text-muted",children:r.lastSecurityScan.scannedAt})]}),e.jsx("p",{className:"plugin-security-summary",children:r.lastSecurityScan.summary}),e.jsxs("details",{children:[e.jsxs("summary",{children:["Findings (",r.lastSecurityScan.findings.length,")"]}),e.jsx("ul",{className:"plugin-security-findings",children:r.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"}),ce?e.jsx("p",{className:"text-muted",children:"Loading..."}):(()=>{const s=Oe(r);return s&&Object.keys(s).length>0?e.jsxs("div",{className:"plugin-settings-form",children:[(()=>{const{grouped:n,ungrouped:o}=ze(s),l=[];o.length>0&&l.push({title:null,entries:o});for(const[u,a]of n.entries())l.push({title:u,entries:a});return l.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(Y,{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:be,children:"Save Settings"})]}):e.jsx("p",{className:"text-muted",children:"No configurable settings."})})()]}),e.jsxs("div",{className:"plugin-detail-actions",children:[r.state==="started"&&e.jsxs("button",{className:"btn btn-secondary",onClick:()=>W(r),disabled:S===r.id,children:[e.jsx(ee,{size:14,className:S===r.id?"spin":""}),S===r.id?"Reloading...":"Reload"]}),r.enabled?e.jsx("button",{className:"btn btn-secondary",onClick:()=>H(r),children:"Disable in Project"}):e.jsx("button",{className:"btn btn-primary",onClick:()=>V(r),children:"Enable in Project"}),e.jsxs("button",{className:"btn btn-danger",onClick:()=>J(r),children:[e.jsx(se,{size:14})," Uninstall Globally"]})]})]})]});const xe=new Map(h.map(s=>[s.id,s])),K=h,fe=()=>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=xe.get(s.id),o=!!n,l=oe[s.id],u=!!(l&&"setupCheckDeferred"in l&&l.setupCheckDeferred),a=l&&"status"in l?l.status:void 0,t=o&&s.hasSetup&&l?.hasSetup&&!u&&n?.state==="started"&&(a==="not-installed"||a==="error"),y=o&&l?.hasSetup&&a==="installed",d=ue===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 ${o?"plugin-builtins-status--installed":"plugin-builtins-status--available"}`,children:o?"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?o&&t?e.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>void q(s),disabled:C===s.id||d,children:C===s.id?"Setting up...":"Install Setup"}):o&&n?e.jsx("button",{className:"btn btn-secondary btn-sm",onClick:()=>void k(n),children:"Manage"}):e.jsx("span",{className:"plugin-builtins-metadata-only",children:"Built-in metadata only"}):e.jsx("button",{className:`btn ${o&&!t?"btn-secondary":"btn-primary"} btn-sm`,onClick:()=>{if(!o){ge(s);return}if(t){q(s);return}n&&k(n)},disabled:z===s.id||C===s.id||d,children:o?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(we,{size:14,className:f?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>P(!0),children:[e.jsx(T,{size:14})," Install"]})]})]}),re&&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(De,{value:w,onChange:$,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:A,onChange:s=>F(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:()=>{P(!1),$("")},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(Ce,{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.jsx("div",{className:"plugin-info",children:e.jsxs("div",{className:"plugin-copy",children:[e.jsxs("div",{className:"plugin-copy-header",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})]}),ie(s)]})}),e.jsxs("div",{className:"plugin-actions",children:[s.state==="started"&&e.jsx("button",{className:"btn-icon",onClick:()=>W(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?H(s):V(s),"aria-label":`${s.enabled?"Disable":"Enable"} ${s.name}`}),e.jsx("span",{className:"toggle-slider"})]}),e.jsx("button",{className:"btn-icon",onClick:()=>k(s),title:"Settings",children:e.jsx(Ie,{size:14})}),e.jsx("button",{className:"btn-icon",onClick:()=>J(s),title:"Uninstall globally",children:e.jsx(se,{size:14})})]})]},s.id))}),fe()]})]})}export{ne as AGENT_BROWSER_SETTINGS_SCHEMA,le as BUILTIN_AGENT_BROWSER_PLUGIN_ID,We as PluginManager,I as STATE_COLORS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as n,j as e}from"./vendor-react-K0fH_qHe.js";import{a7 as z,a8 as le,a9 as oe,ak as de,aD as be,ac as te,aE as fe,s as ve,aF as W,aG as xe,aH as pe,aI as ye,aJ as ge,aK as Re,aL as _e,ao as je,u as Se,aM as we,x as Ne,aN as Ee,L as ke,S as Ce}from"./index-tJzhtiGM.js";import"./vendor-xterm-DzcZoU0P.js";import"./vendor-codemirror-jBKmHyH0.js";const Ae="builtin",Q={pageFetch:!0,github:!1,localDocs:!0,llmSynthesis:!0};function ae(r){const t=r?.researchGlobalDefaults,i=r?.researchSettings;return{enabled:i?.enabled??r?.researchEnabled??r?.researchGlobalEnabled??!0,searchProvider:i?.searchProvider??t?.searchProvider??r?.researchGlobalWebSearchProvider??Ae,synthesisProvider:i?.synthesisProvider??t?.synthesisProvider,synthesisModelId:i?.synthesisModelId??t?.synthesisModelId,enabledSources:{webSearch:!0,pageFetch:i?.enabledSources?.pageFetch??t?.enabledSources?.pageFetch??Q.pageFetch,github:i?.enabledSources?.github??t?.enabledSources?.github??Q.github,localDocs:i?.enabledSources?.localDocs??t?.enabledSources?.localDocs??Q.localDocs,llmSynthesis:i?.enabledSources?.llmSynthesis??t?.enabledSources?.llmSynthesis??Q.llmSynthesis},limits:{maxConcurrentRuns:i?.limits?.maxConcurrentRuns??r?.researchMaxConcurrentRuns??r?.researchGlobalMaxConcurrentRuns??3,maxSourcesPerRun:i?.limits?.maxSourcesPerRun??t?.maxSourcesPerRun??r?.researchMaxSourcesPerRun??r?.researchGlobalMaxSourcesPerRun??20,maxDurationMs:i?.limits?.maxDurationMs??r?.researchDefaultTimeout??r?.researchGlobalDefaultTimeout??3e5,requestTimeoutMs:i?.limits?.requestTimeoutMs??r?.researchGlobalFetchTimeoutMs??3e4},defaultExportFormat:t?.defaultExportFormat??"markdown"}}const Pe=300,Te=4e3,Ie=["queued","running","cancelling","retry_waiting"];function re(r,t){if(r instanceof je){const i=r;return{message:r.message,status:r.status,code:i.researchCode??"INTERNAL_ERROR",setupHint:i.setupHint,retryable:i.retryable}}return r instanceof Error?{message:r.message,code:"INTERNAL_ERROR"}:{message:t,code:"INTERNAL_ERROR"}}function Le(r){if(!r)return{cancelable:!1,retryable:!1,isTransitioning:!1,blockingReason:"No run selected"};const t=Ie.includes(r.status),i=r.status==="queued"||r.status==="running",f=r.lifecycle?.retryable,y=r.status==="failed"||r.status==="timed_out",a=!!(y&&f);let _;return!i&&t?_="Run is already transitioning":!i&&r.status==="completed"?_="Completed runs cannot be cancelled":!i&&r.status==="cancelled"?_="Run is already cancelled":!i&&r.status==="retry_exhausted"?_="Retry attempts exhausted":!i&&r.status==="failed"?_="Failed runs cannot be cancelled":!i&&r.status==="timed_out"&&(_="Timed out runs cannot be cancelled"),!a&&y&&f===!1&&(_=r.lifecycle?.errorCode==="RETRY_EXHAUSTED"?"Retry attempts exhausted":"Run is not retryable"),{cancelable:i,retryable:a,isTransitioning:t,blockingReason:_}}function Me(r){const t=r?.projectId,i=t??"",f=`${oe.RESEARCH_RUNS_PREFIX}${i}`,y=`${oe.RESEARCH_SELECTED_ID_PREFIX}${i}`,a=z(f,{maxAgeMs:le}),_=z(y,{maxAgeMs:de}),N=n.useRef(Array.isArray(a)&&a.length>0),[j,A]=n.useState(()=>Array.isArray(a)?a:[]),[x,T]=n.useState(_??null),[F,w]=n.useState(null),[D,I]=n.useState({available:!0}),[q,L]=n.useState(!(Array.isArray(a)&&a.length>0)),[H,M]=n.useState(null),[P,R]=n.useState(null),[g,E]=n.useState(""),o=n.useRef(0),v=n.useRef(0),$=n.useRef(t);n.useEffect(()=>{$.current!==t&&($.current=t,v.current++);const c=z(f,{maxAgeMs:le}),l=z(y,{maxAgeMs:de}),h=Array.isArray(c)&&c.length>0;A(Array.isArray(c)?c:[]),T(l??null),w(null),L(!h),N.current=h},[t,f,y]);const k=n.useCallback(async(c=g)=>{const l=++o.current,h=t;N.current||L(!0),M(null),R(null);try{const m=await be({q:c||void 0,limit:100},h);if(l!==o.current||h!==t)return;A(m.runs),te(f,m.runs,{maxBytes:5e5}),N.current=!0,I(m.availability),x&&!m.runs.some(p=>p.id===x)&&(T(null),te(y,null,{maxBytes:5e5}),w(null))}catch(m){if(l!==o.current||h!==t)return;const p=re(m,"Failed to load research runs");M(p.message),R(p)}finally{l===o.current&&L(!1)}},[t,f,g,y,x]),O=n.useCallback(async c=>{const l=await fe(c,t);return w(l.run),I(l.availability),l.run},[t]);n.useEffect(()=>{N.current||L(!0);const c=window.setTimeout(()=>{k(g)},Pe);return()=>window.clearTimeout(c)},[k,g]),n.useEffect(()=>{if(!x){w(null);return}O(x)},[O,x]),n.useEffect(()=>{const c=v.current,l=()=>v.current!==c,h=t?`?projectId=${encodeURIComponent(t)}`:"";let m=!0;const p=()=>{!m||l()||(k(),x&&O(x))},S=`/api/events${h}`,U=ve(S,{events:{"research:run:created":p,"research:run:updated":p,"research:run:completed":p,"research:run:failed":p,"research:run:cancelled":p},onReconnect:()=>{W({view:"useResearch",trigger:"sse-reconnect",projectId:t,replayAttempted:!1,sseChannel:S}),p()}});W({view:"useResearch",trigger:"sse-open",projectId:t,replayAttempted:!1,sseChannel:S});const G=window.setInterval(p,Te);return()=>{m=!1,U(),window.clearInterval(G)}},[t,k,x,O]);const B=n.useCallback(c=>{T(c),te(y,c,{maxBytes:5e5})},[y]);return{runs:j,selectedRun:F,selectedRunId:x,setSelectedRunId:B,availability:D,loading:q,error:H,searchQuery:g,setSearchQuery:E,refresh:k,createRun:c=>_e(c,t),cancelRun:async c=>{try{R(null);const l=await Re(c,t);return x===c&&w(l.run),await k(),l}catch(l){const h=re(l,"Failed to cancel run");throw R(h),h}},retryRun:async c=>{try{R(null);const l=await ge(c,t);return x===c&&w(l.run),await k(),l}catch(l){const h=re(l,"Failed to retry run");throw R(h),h}},exportRun:(c,l)=>ye(c,l,t),createTaskFromRun:(c,l,h,m,p,S)=>pe(c,{title:l,findingId:h,description:m,priority:p,attachExport:S},t),attachRunToTask:(c,l,h,m)=>xe(c,{taskId:l,findingId:h,attachExport:m},t),uiError:P,runActionState:Le(F),statusCounts:j.reduce((c,l)=>(c[l.status]+=1,c),{queued:0,running:0,cancelling:0,retry_waiting:0,completed:0,failed:0,cancelled:0,timed_out:0,retry_exhausted:0})}}function Fe({open:r,mode:t,run:i,finding:f,projectId:y,onClose:a,onConfirm:_}){Se(r);const[N,j]=n.useState(!1),[A,x]=n.useState(""),[T,F]=n.useState(""),[w,D]=n.useState("normal"),[I,q]=n.useState(""),[L,H]=n.useState([]),[M,P]=n.useState(!1),[R,g]=n.useState(!1),E=n.useMemo(()=>{const o=(f.content??"").split(/(?<=[.!?])\s+/)[0]??"";return`${f.heading||"Research finding"} — ${o}`.trim()},[f.content,f.heading]);return n.useEffect(()=>{r&&(j(!1),x(`Research: ${f.heading||i.title}`),F(E),D("normal"),q(""),t==="enrich"&&(P(!0),we(50,0,y).then(o=>H(o.filter(v=>v.column!=="archived"))).finally(()=>P(!1))))},[r,t,y,f.heading,E,i.title]),r?e.jsx("div",{className:"modal-overlay open",role:"presentation",onClick:a,children:e.jsxs("div",{className:"modal modal-lg research-task-action-modal",role:"dialog","aria-modal":"true",onClick:o=>o.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:t==="create"?"Create task from finding":"Enrich existing task"}),e.jsx("button",{className:"modal-close",type:"button","aria-label":"Close",onClick:a,children:"×"})]}),e.jsxs("div",{className:"research-task-action-modal__body",children:[e.jsxs("div",{className:"card research-task-action-modal__preview",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Run:"})," ",i.id]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Finding:"})," ",f.id,f.heading?` — ${f.heading}`:""]}),e.jsx("p",{children:E||"No preview available."})]}),t==="create"?e.jsxs(e.Fragment,{children:[e.jsxs("label",{className:"research-task-action-modal__field",children:["Title",e.jsx("input",{className:"input",value:A,onChange:o=>x(o.target.value)})]}),e.jsxs("label",{className:"research-task-action-modal__field",children:["Description",e.jsx("textarea",{className:"input research-task-action-modal__textarea",value:T,onChange:o=>F(o.target.value)})]}),e.jsxs("label",{className:"research-task-action-modal__field",children:["Priority",e.jsxs("select",{className:"select",value:w,onChange:o=>D(o.target.value),children:[e.jsx("option",{value:"low",children:"Low"}),e.jsx("option",{value:"normal",children:"Normal"}),e.jsx("option",{value:"high",children:"High"}),e.jsx("option",{value:"urgent",children:"Urgent"})]})]})]}):e.jsxs("label",{className:"research-task-action-modal__field",children:["Target task",e.jsx("input",{className:"input",list:"research-task-action-task-list",value:I,placeholder:M?"Loading tasks…":"Enter task ID",onChange:o=>q(o.target.value)}),e.jsx("datalist",{id:"research-task-action-task-list",children:L.map(o=>e.jsx("option",{value:o.id,children:o.title},o.id))})]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:N,onChange:o=>j(o.target.checked)}),e.jsx("span",{children:"Attach markdown export artifact"})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn",type:"button",onClick:a,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",type:"button",disabled:R||t==="enrich"&&!I,onClick:()=>{g(!0),_({taskId:t==="enrich"?I:void 0,title:t==="create"?A.trim():void 0,description:t==="create"?T.trim():void 0,priority:t==="create"?w:void 0,attachExport:N}).finally(()=>g(!1))},children:t==="create"?"Create Task":"Enrich Task"})]})]})}):null}const De=["web-search","page-fetch","github","local-docs","llm-synthesis"],qe={"web-search":"webSearch","page-fetch":"pageFetch",github:"github","local-docs":"localDocs","llm-synthesis":"llmSynthesis"},Oe={"web-search":"Web Search","page-fetch":"Page Fetch",github:"GitHub","local-docs":"Local Docs","llm-synthesis":"LLM Synthesis"};let ne=!1;function Be({projectId:r,addToast:t,onOpenSettings:i,readinessVersion:f=0}){n.useEffect(()=>(W({view:"ResearchView",trigger:ne?"route-active":"remount",projectId:r,replayAttempted:!1}),ne=!1,()=>{ne=!0,W({view:"ResearchView",trigger:"route-inactive",projectId:r,replayAttempted:!1})}),[r]);const{runs:y,selectedRun:a,selectedRunId:_,setSelectedRunId:N,availability:j,loading:A,error:x,searchQuery:T,setSearchQuery:F,createRun:w,cancelRun:D,retryRun:I,exportRun:q,createTaskFromRun:L,attachRunToTask:H,statusCounts:M,refresh:P,uiError:R,runActionState:g}=Me({projectId:r}),[E,o]=n.useState(""),[v,$]=n.useState(()=>ae(void 0)),[k,O]=n.useState([]),[B,c]=n.useState(!1),[l,h]=n.useState([]),[m,p]=n.useState(null),[S,U]=n.useState(null),G=j.supportedProviders??De,X=v.searchProvider,Y=s=>s==="web-search"?!0:v.enabledSources[qe[s]];n.useEffect(()=>{const s=G.filter(d=>Y(d));h(d=>{const b=d.filter(u=>s.includes(u));return b.length>0?b:s})},[v.enabledSources,G]),n.useEffect(()=>{let s=!1;return Promise.all([Ne(r),Ee().catch(()=>({providers:[]}))]).then(([d,b])=>{s||($(ae(d)),O(b.providers.filter(u=>u.type==="api_key").map(u=>({id:u.id,authenticated:u.authenticated}))))}).catch(()=>{s||$(ae(void 0))}),()=>{s=!0}},[r,f]);const ue=n.useMemo(()=>a?a.status:"No run selected",[a]),he=n.useMemo(()=>a?a.status==="queued"||a.status==="retry_waiting"?"status-dot status-dot--pending":a.status==="running"?"status-dot status-dot--connecting":a.status==="completed"?"status-dot status-dot--online":a.status==="failed"||a.status==="cancelled"?"status-dot status-dot--error":"status-dot":"status-dot",[a]),J=j.supportedExportFormats??["markdown","json","html"],Z=n.useMemo(()=>new Map(k.map(s=>[s.id,s.authenticated])),[k]),ee=n.useMemo(()=>{const s=new Set;return v.enabledSources.webSearch&&X&&s.add(X),v.enabledSources.llmSynthesis&&v.synthesisProvider&&s.add(v.synthesisProvider),[...s].filter(d=>Z.has(d))},[v.enabledSources.llmSynthesis,v.enabledSources.webSearch,v.synthesisProvider,X,Z]).find(s=>Z.get(s)!==!0),V=n.useMemo(()=>j.available?v.enabled?ee?{reason:`Missing API key for ${ee}.`,details:"Add provider credentials in Authentication settings.",settingsSection:"authentication"}:null:{reason:"Research is disabled for this project.",details:"Enable project research settings to create runs.",settingsSection:"research-project"}:{reason:j.reason??"Research is unavailable for this project.",details:j.setupInstructions,settingsSection:"research-project"},[j.available,j.reason,j.setupInstructions,v.enabled,ee]),K=async(s,d,b)=>{p(s);try{await d(),t?.(b,"success"),await P()}catch(u){t?.(u instanceof Error?u.message:"Action failed","error")}finally{p(null)}},se=async s=>{if(a){p(`export-${s}`);try{const d=await q(a.id,s),b=new Blob([d.content],{type:"text/plain;charset=utf-8"}),u=URL.createObjectURL(b),C=document.createElement("a");C.href=u,C.download=d.filename,document.body.appendChild(C),C.click(),C.remove(),URL.revokeObjectURL(u),t?.(`Exported ${d.filename}`,"success")}catch(d){t?.(d instanceof Error?d.message:"Export failed","error")}finally{p(null)}}},me=async()=>{if(E.trim()){c(!0);try{const s=l.filter(b=>Y(b));if(s.length===0){c(!1),t?.("No enabled research sources are available for this project.","error");return}const d=await w({query:E.trim(),providers:s});N(d.run.id),o(""),t?.("Research run created","success"),await P()}catch(s){t?.(s instanceof Error?s.message:"Failed to create run","error")}finally{c(!1)}}};return e.jsxs("section",{className:"research-view","aria-label":"Research view",children:[e.jsxs("header",{className:"research-view__header",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"research-view__title",children:"Research"}),e.jsx("p",{className:"research-view__subtitle",children:"Cited search and synthesis runs: gather sources, fetch content, and synthesize findings."})]}),e.jsx("div",{className:"research-view__header-actions",children:e.jsx("button",{className:"btn",type:"button",onClick:()=>void P(),children:"Refresh"})})]}),V?e.jsxs("div",{className:"research-view__state research-view__state--error card","data-testid":"research-state-unavailable",children:[e.jsx("p",{children:V.reason}),V.details&&e.jsx("p",{children:V.details}),e.jsxs("p",{children:["Current defaults: provider ",v.searchProvider??"(not set)",", max sources ",v.limits.maxSourcesPerRun]}),e.jsxs("div",{className:"research-view__actions",children:[e.jsx("button",{className:"btn",type:"button",onClick:()=>void P(),children:"Refresh"}),e.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>i?.(V.settingsSection),children:"Open Settings"})]})]}):e.jsx(e.Fragment,{children:e.jsxs("div",{className:"research-view__layout",children:[e.jsx("aside",{className:"research-view__sidebar card",children:e.jsxs("div",{className:"research-view__sidebar-content",children:[e.jsxs("div",{className:"research-view__form",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"research-query",children:"Query"}),e.jsx("textarea",{id:"research-query",className:"input research-view__textarea",value:E,onChange:s=>o(s.target.value)})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Providers"}),e.jsx("div",{className:"research-view__providers",children:G.map(s=>{const d=Y(s),b=s==="web-search";return e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:b||l.includes(s),disabled:b||!d,onChange:()=>{b||!d||h(u=>u.includes(s)?u.filter(C=>C!==s):[...u,s])}}),e.jsxs("span",{children:[Oe[s]??s,b?e.jsx("span",{className:"research-view__provider-lock",children:"Always on"}):null]})]},s)})})]}),e.jsxs("button",{className:"btn btn-primary",type:"button",disabled:!E.trim()||B,onClick:()=>void me(),children:[B?e.jsx(ke,{className:"animate-spin",size:14}):null,"Create Run"]})]}),e.jsxs("div",{className:"research-view__history-header form-group",children:[e.jsx("label",{htmlFor:"research-run-search",children:"Search"}),e.jsxs("div",{className:"research-view__history-search-row",children:[e.jsx(Ce,{size:14}),e.jsx("input",{id:"research-run-search",className:"input",placeholder:"Search runs",value:T,onChange:s=>F(s.target.value)})]})]}),e.jsx("div",{className:"research-view__history","data-testid":"research-state-running",children:y.map(s=>e.jsxs("button",{type:"button",className:`research-view__history-item card${_===s.id?" research-view__history-item--active":""}`,onClick:()=>N(s.id),children:[e.jsx("span",{className:"card-id",children:s.id}),e.jsx("span",{children:s.title})]},s.id))})]})}),e.jsxs("div",{className:"research-view__reader card",children:[A&&e.jsx("p",{"data-testid":"research-state-loading",children:"Loading research runs…"}),!A&&x&&e.jsx("p",{"data-testid":"research-state-error",children:x}),!A&&!x&&y.length===0&&e.jsx("p",{"data-testid":"research-state-empty",children:"No research runs yet"}),e.jsxs("div",{className:"research-view__reader-content",children:[a&&e.jsxs("div",{className:"research-view__run-detail",children:[e.jsxs("div",{className:"research-view__status-row",children:[e.jsx("span",{className:he}),e.jsx("strong",{children:ue})]}),e.jsx("h3",{className:"research-view__run-title",children:a.title}),e.jsx("p",{className:"research-view__run-query",children:a.query}),e.jsx("p",{className:"research-view__run-summary","data-testid":"research-state-results",children:a.results?.summary??"No summary yet."}),e.jsxs("div",{className:"research-view__actions",children:[e.jsx("button",{className:"btn",type:"button",title:g.cancelable?void 0:g.blockingReason,disabled:m==="cancel"||m==="retry"||!g.cancelable,onClick:()=>void K("cancel",()=>D(a.id),"Run cancelled"),children:"Cancel"}),e.jsx("button",{className:"btn",type:"button",title:g.retryable?void 0:g.blockingReason,disabled:m==="cancel"||m==="retry"||!g.retryable,onClick:()=>void K("retry",()=>I(a.id),"Run retried"),children:"Retry"}),J.includes("markdown")&&e.jsx("button",{className:"btn",type:"button",disabled:m==="export-markdown",onClick:()=>void se("markdown"),children:"Export MD"}),J.includes("json")&&e.jsx("button",{className:"btn",type:"button",disabled:m==="export-json",onClick:()=>void se("json"),children:"Export JSON"}),J.includes("html")&&e.jsx("button",{className:"btn",type:"button",disabled:m==="export-html",onClick:()=>void se("html"),children:"Export HTML"})]}),a.error&&e.jsx("p",{className:"research-view__error",children:a.error}),R&&e.jsxs("div",{className:"form-error",role:"alert",children:[e.jsx("p",{children:R.message}),R.setupHint&&e.jsx("p",{children:R.setupHint}),R.code==="MISSING_CREDENTIALS"&&e.jsx("button",{className:"btn btn-sm",type:"button",onClick:()=>i?.("authentication"),children:"Open Authentication Settings"}),R.code==="FEATURE_DISABLED"&&e.jsx("button",{className:"btn btn-sm",type:"button",onClick:()=>i?.("research-project"),children:"Open Research Settings"})]}),g.blockingReason&&e.jsx("p",{className:"research-view__run-query",children:g.blockingReason}),Array.isArray(a.results?.findings)&&a.results.findings.length>0&&e.jsx("div",{className:"research-view__findings",children:a.results.findings.map((s,d)=>{const u=s.id?.trim()||`finding-${d+1}`;return e.jsxs("article",{className:"research-view__finding card",children:[e.jsx("h4",{children:s.heading}),e.jsx("p",{children:s.content}),e.jsxs("div",{className:"research-view__actions research-view__finding-actions",children:[e.jsx("button",{className:"btn btn-primary btn-sm",type:"button",onClick:()=>U({mode:"create",findingId:u}),children:"Create Task"}),e.jsx("button",{className:"btn btn-sm",type:"button",onClick:()=>U({mode:"enrich",findingId:u}),children:"Enrich Task"})]})]},u)})}),Array.isArray(a.results?.citations)&&a.results.citations.length>0&&e.jsx("ul",{className:"research-view__citations",children:a.results.citations.map(s=>e.jsx("li",{children:e.jsx("a",{href:s,target:"_blank",rel:"noreferrer",children:s})},s))}),a.events.length>0&&e.jsxs("details",{children:[e.jsx("summary",{children:"Run history"}),e.jsx("ul",{className:"research-view__events",children:a.events.map(s=>e.jsx("li",{children:s.message},s.id))})]})]}),!a&&y.length>0&&e.jsx("p",{children:"Select a run to view details."}),e.jsxs("div",{className:"research-view__stats",children:[e.jsxs("div",{className:"research-view__stat-card",children:[e.jsx("div",{className:"research-view__stat-label",children:"Running"}),e.jsx("div",{className:"research-view__stat-value",children:M.running})]}),e.jsxs("div",{className:"research-view__stat-card",children:[e.jsx("div",{className:"research-view__stat-label",children:"Completed"}),e.jsx("div",{className:"research-view__stat-value",children:M.completed})]}),e.jsxs("div",{className:"research-view__stat-card",children:[e.jsx("div",{className:"research-view__stat-label",children:"Failed"}),e.jsx("div",{className:"research-view__stat-value",children:M.failed})]})]})]})]})]})}),a&&S&&(()=>{const s=a.results?.findings?.findIndex((b,u)=>(b.id?.trim()||`finding-${u+1}`)===S.findingId)??-1,d=s>=0?a.results.findings[s]:null;return d?e.jsx(Fe,{open:!0,mode:S.mode,run:a,finding:{id:S.findingId,heading:d.heading,content:d.content},projectId:r,onClose:()=>U(null),onConfirm:async({taskId:b,title:u,description:C,priority:ce,attachExport:ie})=>{S.mode==="create"?await K("create-task",()=>L(a.id,u,S.findingId,C,ce,ie),"Task created from research"):b&&await K("attach-task",()=>H(a.id,b,S.findingId,ie),"Task enriched from research"),U(null)}}):null})()]})}export{Be as ResearchView};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as l,j as e}from"./vendor-react-K0fH_qHe.js";import{R as L,J as oe,ae as J,af as q,bB as ie,bC as de,b3 as pe,_ as ue}from"./index-tJzhtiGM.js";import"./vendor-xterm-DzcZoU0P.js";import"./vendor-codemirror-jBKmHyH0.js";const he="__sync_passphrase__",k={key:"",value:"",description:"",scope:"project",accessPolicy:"prompt",envExportable:!1,envExportKey:""},c={className:"secrets-action-icon","aria-hidden":!0,style:{width:"1em",height:"1em"}},me={...c,className:"secrets-action-icon spin"},be=({addToast:o})=>{const[P,Y]=l.useState([]),[R,K]=l.useState(!0),[M,T]=l.useState(null),[_,y]=l.useState(null),[i,A]=l.useState(null),[G,h]=l.useState(!1),[U,b]=l.useState(null),[n,t]=l.useState(k),[N,f]=l.useState(!1),[$,g]=l.useState({}),[z,O]=l.useState(null),[d,Q]=l.useState(!1),[W,D]=l.useState(!1),[v,V]=l.useState(""),[S,F]=l.useState(""),[X,I]=l.useState(!1),C=l.useRef(new Map),E=l.useRef(new Map),r=l.useCallback(async(s,a)=>{const p=await fetch(s,{...a,headers:{"Content-Type":"application/json",...a?.headers??{}}});if(!p.ok){const u=await p.json().catch(()=>({error:"Request failed"}));throw new Error(String(u?.error??"Request failed"))}if(p.status!==204)return p.json()},[]),m=l.useCallback(async()=>{K(!0),T(null);try{const s=await r("/api/secrets");Y(s.secrets)}catch(s){T(s instanceof Error?s.message:String(s))}finally{K(!1)}},[r]),j=l.useCallback(async()=>{try{const s=await r("/api/secrets/sync-passphrase");Q(!!s.configured)}catch(s){o?.(`Failed to load sync passphrase status: ${s instanceof Error?s.message:String(s)}`,"error")}},[o,r]);l.useEffect(()=>(m(),j(),()=>{C.current.forEach(s=>clearTimeout(s)),E.current.forEach(s=>clearTimeout(s))}),[m,j]);const w=()=>{D(!1),V(""),F("")},Z=async s=>{await r("/api/secrets/sync-passphrase",{method:"PUT",body:JSON.stringify({passphrase:s})})},ee=async()=>{I(!0);try{await Z(v),o?.(d?"Sync passphrase rotated":"Sync passphrase set","success"),w(),await j()}catch(s){o?.(`Failed to save sync passphrase: ${s instanceof Error?s.message:String(s)}`,"error")}finally{I(!1)}},se=async()=>{if(window.confirm("Clear the cross-node sync passphrase? Existing sync pairs will stop working until you set a new passphrase."))try{await r("/api/secrets/sync-passphrase",{method:"DELETE"}),o?.("Sync passphrase cleared","success"),await j()}catch(a){o?.(`Failed to clear sync passphrase: ${a instanceof Error?a.message:String(a)}`,"error")}},ae=()=>{A(null),t(k),h(!0),f(!1),y(null)},ne=s=>{A(s),t({key:s.key,value:"",description:s.description??"",scope:s.scope,accessPolicy:s.accessPolicy,envExportable:s.envExportable,envExportKey:s.envExportKey??""}),h(!0),f(!1),y(null)},le=async()=>{y(null);try{if(i){const s={key:n.key,description:n.description||null,accessPolicy:n.accessPolicy,envExportable:n.envExportable,envExportKey:n.envExportable&&n.envExportKey||null};n.value&&(s.value=n.value),await r(`/api/secrets/${i.scope}/${i.id}`,{method:"PATCH",body:JSON.stringify(s)})}else await r("/api/secrets",{method:"POST",body:JSON.stringify({scope:n.scope,key:n.key,value:n.value,description:n.description||null,accessPolicy:n.accessPolicy,envExportable:n.envExportable,envExportKey:n.envExportable&&n.envExportKey||null})});h(!1),t(k),await m()}catch(s){y(s instanceof Error?s.message:String(s))}},te=async s=>{const a=await r(`/api/secrets/${s.scope}/${s.id}/reveal`,{method:"POST"});g(x=>({...x,[s.id]:a.value})),o?.("Revealed","success");const p=setTimeout(()=>{g(x=>({...x,[s.id]:null}))},3e4),u=C.current.get(s.id);u&&clearTimeout(u),C.current.set(s.id,p)},ce=async s=>{const a=$[s.id];if(!a)return;await navigator.clipboard.writeText(a),O(s.id),o?.("Copied","success");const p=setTimeout(()=>{O(null),g(x=>({...x,[s.id]:null}))},1500),u=E.current.get(s.id);u&&clearTimeout(u),E.current.set(s.id,p)},re=async s=>{await r(`/api/secrets/${s.scope}/${s.id}`,{method:"DELETE"}),b(null),await m()},B=l.useMemo(()=>[...P].filter(s=>!(s.scope==="global"&&s.key===he)).sort((s,a)=>s.key.localeCompare(a.key)),[P]),H=v.length>0&&v===S;return e.jsxs("section",{className:"secrets-view",children:[e.jsxs("div",{className:"secrets-header",children:[e.jsx("h2",{children:"Secrets"}),e.jsxs("div",{className:"secrets-header-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:()=>void m(),children:[e.jsx(L,{...c})," Refresh"]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:ae,children:[e.jsx(oe,{...c})," Add Secret"]})]})]}),e.jsxs("article",{className:"card secrets-sync-card",children:[e.jsxs("div",{className:"secrets-sync-header",children:[e.jsxs("div",{children:[e.jsx("h3",{children:"Cross-Node Sync Passphrase"}),e.jsxs("p",{className:"secrets-sync-status",children:[e.jsx("span",{className:`status-dot ${d?"status-dot--online":"status-dot--pending"}`,"aria-hidden":"true"})," ",d?"Configured":"Not configured"]})]}),e.jsxs("div",{className:"secrets-sync-actions",children:[e.jsx("button",{className:"btn",onClick:()=>D(!0),children:d?"Rotate":"Set passphrase"}),d?e.jsx("button",{className:"btn btn-danger",onClick:()=>void se(),children:"Clear"}):null]})]}),e.jsx("p",{className:"secrets-sync-copy",children:"Shared passphrase used to wrap cross-node secret bundles. Both nodes in a sync pair must share the same value. Stored locally only; never transmitted."})]}),M?e.jsx("div",{className:"form-error",children:M}):null,R?e.jsxs("div",{className:"secrets-loading",children:[e.jsx(L,{...me})," Loading…"]}):null,!R&&B.length===0?e.jsx("div",{className:"secrets-empty",children:"No secrets found."}):null,e.jsx("div",{className:"secrets-list",children:B.map(s=>{const a=$[s.id];return e.jsxs("article",{className:"card secrets-row",children:[e.jsxs("div",{className:"secrets-row-main",children:[e.jsx("div",{className:"secrets-row-key",children:s.key}),e.jsxs("div",{className:"secrets-row-meta",children:[e.jsx("span",{className:"secrets-chip",children:s.scope}),e.jsx("span",{className:"secrets-chip",children:s.accessPolicy}),s.envExportable?e.jsx("span",{className:"secrets-chip",children:"env_exportable"}):null]}),a?e.jsx("pre",{className:"secrets-revealed",children:a}):null]}),e.jsxs("div",{className:"secrets-row-side",children:[e.jsx("span",{className:"secrets-row-read",children:s.lastReadAt?new Date(s.lastReadAt).toLocaleString():"Never read"}),e.jsxs("div",{className:"secrets-row-actions",children:[e.jsx("button",{type:"button",className:"btn btn-icon secrets-visibility-toggle",onClick:()=>void te(s),"aria-label":a?"Hide":"Reveal",children:a?e.jsx(J,{...c}):e.jsx(q,{...c})}),e.jsx("button",{className:"btn btn-icon",onClick:()=>void ce(s),"aria-label":"Copy",disabled:!a,children:z===s.id?e.jsx(ie,{...c}):e.jsx(de,{...c})}),e.jsx("button",{className:"btn btn-icon",onClick:()=>ne(s),"aria-label":"Edit",children:e.jsx(pe,{...c})}),e.jsx("button",{className:"btn btn-icon btn-danger",onClick:()=>b(s.id),"aria-label":"Delete",children:e.jsx(ue,{...c})})]}),U===s.id?e.jsxs("div",{className:"secrets-confirm",children:[e.jsx("button",{className:"btn btn-sm btn-danger",onClick:()=>void re(s),children:"Confirm"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>b(null),children:"Cancel"})]}):null]})]},s.id)})}),W?e.jsx("div",{className:"modal-overlay open",role:"presentation",children:e.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-label":d?"Rotate sync passphrase":"Set sync passphrase",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:d?"Rotate sync passphrase":"Set sync passphrase"}),e.jsx("button",{className:"modal-close",onClick:w,"aria-label":"Close",children:"×"})]}),e.jsxs("div",{className:"secrets-modal-body",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Passphrase"}),e.jsx("input",{"aria-label":"Passphrase",className:"input",type:"password",autoComplete:"new-password",value:v,onChange:s=>V(s.target.value)})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Confirm passphrase"}),e.jsx("input",{"aria-label":"Confirm passphrase",className:"input",type:"password",autoComplete:"new-password",value:S,onChange:s=>F(s.target.value)})]}),!H&&S.length>0?e.jsx("div",{className:"form-error",children:"Passphrases must match."}):null]}),e.jsx("div",{className:"modal-actions",children:e.jsxs("div",{className:"modal-actions-right",children:[e.jsx("button",{className:"btn",onClick:w,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",onClick:()=>void ee(),disabled:!H||X,children:d?"Rotate":"Set passphrase"})]})})]})}):null,G?e.jsx("div",{className:"modal-overlay open",role:"presentation",children:e.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-label":i?"Edit secret":"Add secret",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:i?"Edit secret":"Add secret"}),e.jsx("button",{className:"modal-close",onClick:()=>h(!1),"aria-label":"Close",children:"×"})]}),e.jsxs("div",{className:"secrets-modal-body",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Key"}),e.jsx("input",{className:"input",value:n.key,onChange:s=>t(a=>({...a,key:s.target.value}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Value"}),e.jsxs("div",{className:"secrets-value-row",children:[e.jsx("input",{className:"input",type:N?"text":"password",autoComplete:"off",spellCheck:!1,value:n.value,onChange:s=>t(a=>({...a,value:s.target.value}))}),e.jsx("button",{type:"button",className:"btn btn-icon secrets-visibility-toggle",onClick:()=>f(s=>!s),"aria-label":N?"Hide value":"Show value",children:N?e.jsx(J,{...c}):e.jsx(q,{...c})})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Description"}),e.jsx("textarea",{className:"input",value:n.description,onChange:s=>t(a=>({...a,description:s.target.value}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Scope"}),e.jsxs("div",{className:"secrets-radio-row",children:[e.jsxs("label",{children:[e.jsx("input",{type:"radio",checked:n.scope==="project",onChange:()=>t(s=>({...s,scope:"project"})),disabled:!!i})," Project"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",checked:n.scope==="global",onChange:()=>t(s=>({...s,scope:"global"})),disabled:!!i})," Global"]})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Access policy"}),e.jsxs("select",{className:"select",value:n.accessPolicy,onChange:s=>t(a=>({...a,accessPolicy:s.target.value})),children:[e.jsx("option",{value:"auto",children:"auto"}),e.jsx("option",{value:"prompt",children:"prompt"}),e.jsx("option",{value:"deny",children:"deny"})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:n.envExportable,onChange:s=>t(a=>({...a,envExportable:s.target.checked}))})," Export to env"]})}),n.envExportable?e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Env key"}),e.jsx("input",{className:"input",value:n.envExportKey,onChange:s=>t(a=>({...a,envExportKey:s.target.value}))})]}):null,_?e.jsx("div",{className:"form-error",children:_}):null]}),e.jsx("div",{className:"modal-actions",children:e.jsxs("div",{className:"modal-actions-right",children:[e.jsx("button",{className:"btn",onClick:()=>h(!1),children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",onClick:()=>void le(),children:i?"Save":"Create"})]})})]})}):null]})};export{be as SecretsView};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.secrets-view{display:flex;flex-direction:column;gap:var(--space-lg);padding-block:var(--space-md);padding-inline:var(--space-xl)}.secrets-header{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md)}.secrets-header h2{margin:0}.secrets-header-actions{display:flex;gap:var(--space-sm)}.secrets-loading,.secrets-empty{color:var(--text-muted);display:flex;align-items:center;gap:var(--space-sm);padding-block:var(--space-sm)}.secrets-sync-card{display:flex;flex-direction:column;gap:var(--space-md)}.secrets-sync-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:var(--space-md)}.secrets-sync-status{display:inline-flex;align-items:center;gap:var(--space-xs);margin:0;color:var(--text-muted)}.secrets-sync-copy{margin:0;max-width:60ch;color:var(--text-muted);line-height:1.5}.secrets-sync-actions{display:flex;gap:var(--space-sm)}.secrets-list{display:flex;flex-direction:column;gap:var(--space-md)}.secrets-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--space-md);align-items:start}.secrets-row-main{display:flex;flex-direction:column;gap:var(--space-sm)}.secrets-row-key{font-family:var(--font-mono);font-size:1em;overflow-wrap:anywhere}.secrets-row-meta{display:flex;flex-wrap:wrap;gap:var(--space-sm);row-gap:var(--space-xs)}.secrets-chip{border:var(--btn-border-width) solid var(--border);border-radius:var(--radius-pill);padding:var(--space-xs) var(--space-sm);color:var(--text-muted)}.secrets-revealed{margin:0;max-width:100%;overflow-x:auto;white-space:pre-wrap;word-break:break-all;font-family:var(--font-mono);border:var(--btn-border-width) solid var(--border);border-radius:var(--radius-sm);padding:var(--space-sm);background:var(--surface)}.secrets-row-side{display:flex;flex-direction:column;gap:var(--space-sm);align-items:flex-end}.secrets-row-read{color:var(--text-muted);font-size:.95em;font-weight:400}.secrets-row-actions,.secrets-confirm,.secrets-value-row,.secrets-radio-row{display:flex;gap:var(--space-sm);align-items:center}.secrets-radio-row{flex-wrap:wrap;row-gap:var(--space-xs)}.secrets-modal-body{display:flex;flex-direction:column;gap:var(--space-md);padding:0 var(--space-xl) var(--space-lg)}.secrets-modal-body .form-group{margin:0;padding:0}.secrets-value-row .input{flex:1}@media(max-width:768px){.secrets-view{padding-inline:var(--space-md);padding-bottom:calc(var(--space-md) + var(--mobile-nav-height) + env(safe-area-inset-bottom,0px) + var(--standalone-bottom-gap, 0px))}.secrets-header,.secrets-row,.secrets-sync-header{grid-template-columns:minmax(0,1fr);display:flex;flex-direction:column;align-items:stretch;gap:var(--space-sm)}.secrets-sync-header{flex-wrap:wrap}.secrets-sync-copy{max-width:none}.secrets-sync-actions{flex-direction:column}.secrets-row-key{font-size:.95em}.secrets-row-side{width:100%;align-items:flex-start;gap:var(--space-sm)}}
|
|
1
|
+
.secrets-view{display:flex;flex-direction:column;gap:var(--space-lg);padding-block:var(--space-md);padding-inline:var(--space-xl)}.secrets-header{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md)}.secrets-header h2{margin:0}.secrets-header-actions{display:flex;gap:var(--space-sm)}.secrets-loading,.secrets-empty{color:var(--text-muted);display:flex;align-items:center;gap:var(--space-sm);padding-block:var(--space-sm)}.secrets-sync-card{display:flex;flex-direction:column;gap:var(--space-md)}.secrets-sync-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:var(--space-md)}.secrets-sync-status{display:inline-flex;align-items:center;gap:var(--space-xs);margin:0;color:var(--text-muted)}.secrets-sync-copy{margin:0;max-width:60ch;color:var(--text-muted);line-height:1.5}.secrets-sync-actions{display:flex;gap:var(--space-sm)}.secrets-list{display:flex;flex-direction:column;gap:var(--space-md)}.secrets-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--space-md);align-items:start}.secrets-row-main{display:flex;flex-direction:column;gap:var(--space-sm)}.secrets-row-key{font-family:var(--font-mono);font-size:1em;overflow-wrap:anywhere}.secrets-row-meta{display:flex;flex-wrap:wrap;gap:var(--space-sm);row-gap:var(--space-xs)}.secrets-chip{border:var(--btn-border-width) solid var(--border);border-radius:var(--radius-pill);padding:var(--space-xs) var(--space-sm);color:var(--text-muted)}.secrets-revealed{margin:0;max-width:100%;overflow-x:auto;white-space:pre-wrap;word-break:break-all;font-family:var(--font-mono);border:var(--btn-border-width) solid var(--border);border-radius:var(--radius-sm);padding:var(--space-sm);background:var(--surface)}.secrets-row-side{display:flex;flex-direction:column;gap:var(--space-sm);align-items:flex-end}.secrets-row-read{color:var(--text-muted);font-size:.95em;font-weight:400}.secrets-row-actions,.secrets-confirm,.secrets-value-row,.secrets-radio-row{display:flex;gap:var(--space-sm);align-items:center}.secrets-radio-row{flex-wrap:wrap;row-gap:var(--space-xs)}.secrets-modal-body{display:flex;flex-direction:column;gap:var(--space-md);padding:0 var(--space-xl) var(--space-lg)}.secrets-modal-body .form-group{margin:0;padding:0}.secrets-value-row .input{flex:1}.secrets-action-icon{width:1em;height:1em;min-width:1em;min-height:1em;flex-shrink:0;display:block;stroke:currentColor;font-size:var(--icon-size-sm)}.secrets-header-actions .btn,.secrets-row-actions .btn,.secrets-value-row .btn-icon{color:var(--text)}.secrets-header-actions .btn-primary,.secrets-row-actions .btn-danger{color:var(--cta-text)}.secrets-row-actions .btn:disabled{color:var(--text-muted)}@media(max-width:768px){.secrets-view{padding-inline:var(--space-md);padding-bottom:calc(var(--space-md) + var(--mobile-nav-height) + env(safe-area-inset-bottom,0px) + var(--standalone-bottom-gap, 0px))}.secrets-header,.secrets-row,.secrets-sync-header{grid-template-columns:minmax(0,1fr);display:flex;flex-direction:column;align-items:stretch;gap:var(--space-sm)}.secrets-sync-header{flex-wrap:wrap}.secrets-sync-copy{max-width:none}.secrets-sync-actions{flex-direction:column}.secrets-row-key{font-size:.95em}.secrets-row-side{width:100%;align-items:flex-start;gap:var(--space-sm)}}
|