@runfusion/fusion 0.12.0 → 0.14.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.
Files changed (74) hide show
  1. package/README.md +13 -0
  2. package/dist/bin.js +1707 -610
  3. package/dist/client/assets/AgentDetailView-CBFUveyO.js +18 -0
  4. package/dist/client/assets/AgentsView-DPezXQ-U.js +522 -0
  5. package/dist/client/assets/{AgentsView-Bkk-uBij.css → AgentsView-V5GhlBYu.css} +1 -1
  6. package/dist/client/assets/ChatView-5N4-EuhD.js +1 -0
  7. package/dist/client/assets/{DevServerView-DQrVLbK5.js → DevServerView-Daft4YFc.js} +1 -1
  8. package/dist/client/assets/{DirectoryPicker-DVmy6sLM.js → DirectoryPicker-rew1y6qO.js} +1 -1
  9. package/dist/client/assets/{DocumentsView-DHEv-Q2a.js → DocumentsView-i72qJzwd.js} +1 -1
  10. package/dist/client/assets/{InsightsView-ByyY7GX7.js → InsightsView-BL5eZJ0a.js} +3 -3
  11. package/dist/client/assets/{MemoryView-Udiu0u8R.js → MemoryView-pl8Cdg_p.js} +2 -2
  12. package/dist/client/assets/{NodesView-CupS-GGc.js → NodesView-D6eJ15zc.js} +4 -4
  13. package/dist/client/assets/PiExtensionsManager-ExInwXWP.js +11 -0
  14. package/dist/client/assets/PluginManager-CYhtxHun.js +1 -0
  15. package/dist/client/assets/{ResearchView-BG9Feaeb.js → ResearchView-B_QPUEjB.js} +1 -1
  16. package/dist/client/assets/{RoadmapsView-BTJtmBnF.js → RoadmapsView-DBNLaEsK.js} +2 -2
  17. package/dist/client/assets/SettingsModal-1ET586M3.js +31 -0
  18. package/dist/client/assets/{SettingsModal-eNCZiHa6.js → SettingsModal-CL_gWmOj.js} +1 -1
  19. package/dist/client/assets/SettingsModal-D_AFkDJa.css +1 -0
  20. package/dist/client/assets/{SetupWizardModal-yf79TN1L.js → SetupWizardModal-CLkY9HFL.js} +1 -1
  21. package/dist/client/assets/{SkillMultiselect-DOj5vX4U.js → SkillMultiselect-B0qi32SQ.js} +1 -1
  22. package/dist/client/assets/{SkillsView-CgnCnikX.js → SkillsView-umVjRq6o.js} +1 -1
  23. package/dist/client/assets/TodoView-CFifSvrD.js +6 -0
  24. package/dist/client/assets/TodoView-SeO9o7km.css +1 -0
  25. package/dist/client/assets/{folder-open-D11gjHGK.js → folder-open-nYPrL1W3.js} +1 -1
  26. package/dist/client/assets/index-Bc8nfKeH.js +661 -0
  27. package/dist/client/assets/index-C1prPuSl.css +1 -0
  28. package/dist/client/assets/{list-checks-CBzPc3GA.js → list-checks-sK8xJeH_.js} +1 -1
  29. package/dist/client/assets/{star-BWcRk8nt.js → star-BRtXbYkB.js} +1 -1
  30. package/dist/client/assets/{upload-91TM4ljC.js → upload-BP60eBwN.js} +1 -1
  31. package/dist/client/assets/{users-BAsI___L.js → users-qSGAX2Pf.js} +1 -1
  32. package/dist/client/index.html +2 -2
  33. package/dist/client/sw.js +6 -0
  34. package/dist/client/version.json +1 -1
  35. package/dist/droid-cli/index.ts +127 -0
  36. package/dist/droid-cli/package.json +37 -0
  37. package/dist/droid-cli/src/__tests__/control-handler.test.ts +164 -0
  38. package/dist/droid-cli/src/__tests__/event-bridge.test.ts +1318 -0
  39. package/dist/droid-cli/src/__tests__/mcp-config.test.ts +310 -0
  40. package/dist/droid-cli/src/__tests__/process-manager.test.ts +818 -0
  41. package/dist/droid-cli/src/__tests__/prompt-builder.test.ts +1206 -0
  42. package/dist/droid-cli/src/__tests__/provider.test.ts +1894 -0
  43. package/dist/droid-cli/src/__tests__/setup-test-isolation.test.ts +32 -0
  44. package/dist/droid-cli/src/__tests__/setup-test-isolation.ts +14 -0
  45. package/dist/droid-cli/src/__tests__/stream-parser.test.ts +188 -0
  46. package/dist/droid-cli/src/__tests__/thinking-config.test.ts +141 -0
  47. package/dist/droid-cli/src/__tests__/tool-mapping.test.ts +253 -0
  48. package/dist/droid-cli/src/control-handler.ts +82 -0
  49. package/dist/droid-cli/src/event-bridge.ts +397 -0
  50. package/dist/droid-cli/src/mcp-config.ts +144 -0
  51. package/dist/droid-cli/src/mcp-schema-server.cjs +49 -0
  52. package/dist/droid-cli/src/process-manager.ts +358 -0
  53. package/dist/droid-cli/src/prompt-builder.ts +629 -0
  54. package/dist/droid-cli/src/provider.ts +447 -0
  55. package/dist/droid-cli/src/stream-parser.ts +37 -0
  56. package/dist/droid-cli/src/thinking-config.ts +83 -0
  57. package/dist/droid-cli/src/tool-mapping.ts +147 -0
  58. package/dist/droid-cli/src/types.ts +87 -0
  59. package/dist/extension.js +542 -141
  60. package/dist/pi-claude-cli/package.json +1 -1
  61. package/dist/pi-claude-cli/src/__tests__/prompt-builder.test.ts +36 -0
  62. package/dist/pi-claude-cli/src/prompt-builder.ts +19 -28
  63. package/package.json +2 -1
  64. package/dist/client/assets/AgentDetailView-B20ApPe1.js +0 -18
  65. package/dist/client/assets/AgentsView-ChN1tgQ0.js +0 -522
  66. package/dist/client/assets/ChatView-oPMFwmoc.js +0 -1
  67. package/dist/client/assets/PiExtensionsManager-DXs2xI8K.js +0 -11
  68. package/dist/client/assets/PluginManager-BCpiZf4_.js +0 -1
  69. package/dist/client/assets/SettingsModal-9HS8MnmW.css +0 -1
  70. package/dist/client/assets/SettingsModal-DZ_LaEhd.js +0 -31
  71. package/dist/client/assets/TodoView-67BMyICY.js +0 -6
  72. package/dist/client/assets/TodoView-C1g65hJo.css +0 -1
  73. package/dist/client/assets/index-BLn1R7Ob.css +0 -1
  74. package/dist/client/assets/index-CLAHcGnI.js +0 -656
@@ -1,11 +1,11 @@
1
- import{r as a,j as s}from"./vendor-react-K0fH_qHe.js";import{c as Q,ag as Z,ah as ss,ai as es,aj as ts,ak as is,al as f,X as q,R as w,C as V,am as L,an as B,ao as as,M as W,ap as ns,aq as rs,ar as X}from"./index-CLAHcGnI.js";import{U as P}from"./users-BAsI___L.js";import"./vendor-xterm-DzcZoU0P.js";/**
1
+ import{r as a,j as s}from"./vendor-react-K0fH_qHe.js";import{c as J,ae as Z,af as ss,ag as es,ah as ts,ai as is,aj as f,X as q,R as w,C as Q,ak as L,al as B,am as as,J as V,an as ns,ao as rs,ap as W}from"./index-Bc8nfKeH.js";import{U as P}from"./users-qSGAX2Pf.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
5
5
  * See the LICENSE file in the root directory of this source tree.
6
- */const cs=[["path",{d:"M12 10h.01",key:"1nrarc"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M12 6h.01",key:"1vi96p"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M16 6h.01",key:"1x0f13"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M8 6h.01",key:"1dz90k"}],["path",{d:"M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3",key:"cabbwy"}],["rect",{x:"4",y:"2",width:"16",height:"20",rx:"2",key:"1uxh74"}]],ls=Q("building",cs);/**
6
+ */const cs=[["path",{d:"M12 10h.01",key:"1nrarc"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M12 6h.01",key:"1vi96p"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M16 6h.01",key:"1x0f13"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M8 6h.01",key:"1dz90k"}],["path",{d:"M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3",key:"cabbwy"}],["rect",{x:"4",y:"2",width:"16",height:"20",rx:"2",key:"1uxh74"}]],ls=J("building",cs);/**
7
7
  * @license lucide-react v1.7.0 - ISC
8
8
  *
9
9
  * This source code is licensed under the ISC license.
10
10
  * See the LICENSE file in the root directory of this source tree.
11
- */const os=[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"m19 9-5 5-4-4-3 3",key:"2osh9i"}]],hs=Q("chart-line",os),T=["architecture","quality","workflow","performance","reliability","security","ux","testability","documentation","dependency","features","competitive_analysis","research","trends","other"],Y={quality:"Quality",performance:"Performance",architecture:"Architecture",security:"Security",reliability:"Reliability",ux:"User Experience",testability:"Testability",documentation:"Documentation",dependency:"Dependencies",workflow:"Workflow",other:"Other",features:"Features",competitive_analysis:"Competitive Analysis",research:"Research",trends:"Trends"};function ds(d){const[o,C]=a.useState(()=>T.map(t=>({category:t,label:Y[t]??t,items:[],isLoading:!1,error:null}))),[S,M]=a.useState(!0),[I,E]=a.useState(null),[g,z]=a.useState(null),[F,R]=a.useState(!1),[A,k]=a.useState(null),[D,N]=a.useState(new Map),[$,v]=a.useState(new Map),x=a.useCallback(async()=>{M(!0),E(null);try{const t=await Z({status:void 0,limit:1e3},d),e=new Map;for(const c of T)e.set(c,[]);for(const c of t.insights)if(c.status!=="dismissed"){const y=e.get(c.category)??[];e.set(c.category,[...y,c])}C(T.map(c=>({category:c,label:Y[c]??c,items:e.get(c)??[],isLoading:!1,error:null})));const n=await ss(d);n.runs.length>0&&z(n.runs[0])}catch(t){const e=t instanceof Error?t.message:"Failed to fetch insights";E(e)}finally{M(!1)}},[d]),h=a.useCallback(async()=>{R(!0),k(null);try{const t=await es("manual",void 0,d);z(t),t.status==="completed"?await x():t.status==="failed"&&t.error&&k(t.error)}catch(t){const e=t instanceof Error?t.message:"Failed to generate insights";throw k(e),t}finally{R(!1)}},[d,x]),j=a.useCallback(async t=>{N(e=>{const n=new Map(e);return n.set(t,{running:!0,error:null}),n});try{await ts(t,d),C(e=>e.map(n=>({...n,items:n.items.filter(c=>c.id!==t)}))),N(e=>{const n=new Map(e);return n.set(t,{running:!1,error:null}),n})}catch(e){const n=e instanceof Error?e.message:"Failed to dismiss insight";throw N(c=>{const y=new Map(c);return y.set(t,{running:!1,error:n}),y}),e}},[d]),u=a.useCallback(async t=>{v(e=>{const n=new Map(e);return n.set(t,{running:!0,error:null}),n});try{const e=await is(t,d);return v(n=>{const c=new Map(n);return c.set(t,{running:!1,error:null}),c}),{title:e.suggestedTitle,description:e.suggestedDescription}}catch(e){const n=e instanceof Error?e.message:"Failed to create task";throw v(c=>{const y=new Map(c);return y.set(t,{running:!1,error:n}),y}),e}},[d]),m=a.useMemo(()=>o.reduce((t,e)=>t+e.items.length,0),[o]),p=a.useMemo(()=>0,[o]);return a.useMemo(()=>{x()},[]),{sections:o,loading:S,error:I,latestRun:g,isRunInFlight:F,runError:A,refresh:x,runInsights:h,dismiss:j,createTask:u,dismissStates:D,createTaskStates:$,totalCount:m,dismissedCount:p}}const H={architecture:ls,quality:V,workflow:X,performance:B,reliability:w,security:L,ux:P,testability:rs,documentation:ns,dependency:W,features:as,competitive_analysis:P,research:hs,trends:B,other:f};function ys({projectId:d,addToast:o,onClose:C,onCreateTask:S}){const{sections:M,loading:I,error:E,latestRun:g,isRunInFlight:z,runError:F,refresh:R,runInsights:A,dismiss:k,createTask:D,dismissStates:N,createTaskStates:$,totalCount:v}=ds(d),[x,h]=a.useState(null),[j,u]=a.useState("info"),m=a.useMemo(()=>M.filter(r=>r.items.length>0),[M]),[p,t]=a.useState(null);a.useEffect(()=>{if(m.length===0){p!==null&&t(null);return}p&&m.some(i=>i.category===p)||t(m[0].category)},[m,p]);const e=a.useMemo(()=>m.find(r=>r.category===p)??m[0],[m,p]);a.useEffect(()=>{if(x){const r=setTimeout(()=>h(null),5e3);return()=>clearTimeout(r)}},[x]);const n=a.useCallback(async()=>{try{h("Generating insights..."),u("info"),await A(),h("Insight generation started"),u("success"),o("Insight generation started","success")}catch(r){const i=r instanceof Error?r.message:"Failed to start generation";h(i),u("error"),o(i,"error")}},[A,o]),c=a.useCallback(async(r,i)=>{try{h(`Dismissing "${i}"...`),u("info"),await k(r),h(`Dismissed "${i}"`),u("success"),o(`Insight dismissed: ${i}`,"success")}catch(l){const b=l instanceof Error?l.message:"Failed to dismiss insight";h(b),u("error"),o(b,"error")}},[k,o]),y=a.useCallback(async(r,i)=>{try{h(`Creating task from "${i}"...`),u("info");const l=await D(r);l&&S&&S(l.title,l.description),h(`Task created from "${i}"`),u("success"),o(`Task created: ${l?.title??i}`,"success")}catch(l){const b=l instanceof Error?l.message:"Failed to create task";h(b),u("error"),o(b,"error")}},[D,S,o]),J=r=>{const i=H[r.category]??f,l=e?.category===r.category;return s.jsx("li",{children:s.jsxs("button",{type:"button",className:`insights-category-item${l?" insights-category-item--active":""}`,onClick:()=>t(r.category),"aria-current":l?"true":void 0,"data-testid":`insights-category-${r.category}`,children:[s.jsx(i,{size:16,className:"insights-category-icon"}),s.jsx("span",{className:"insights-category-label",children:r.label}),s.jsx("span",{className:"insights-category-count",children:r.items.length})]})},r.category)},K=()=>{if(!e)return null;const r=H[e.category]??f;return s.jsxs("section",{className:"insights-section","data-testid":`insights-section-${e.category}`,children:[s.jsx("div",{className:"insights-section-header",children:s.jsxs("div",{className:"insights-section-title",children:[s.jsx(r,{size:20,className:"insights-section-icon"}),s.jsx("h3",{children:e.label}),s.jsx("span",{className:"insights-section-count",children:e.items.length})]})}),s.jsx("div",{className:"insights-section-content",children:s.jsx("ul",{className:"insights-list",children:e.items.map(i=>{const l=N.get(i.id),b=$.get(i.id),G=l?.running??!1,_=b?.running??!1,O=e.items.some(U=>N.get(U.id)?.running||$.get(U.id)?.running);return s.jsxs("li",{className:"insight-item","data-insight-id":i.id,children:[s.jsxs("div",{className:"insight-item-header",children:[s.jsx("h4",{className:"insight-item-title",children:i.title}),s.jsxs("div",{className:"insight-item-actions",children:[s.jsx("button",{className:"insight-item-action-btn",onClick:()=>void y(i.id,i.title),disabled:_||O,title:"Create task from this insight","aria-label":"Create task from this insight","data-testid":`create-task-${i.id}`,children:_?s.jsx(w,{size:20,className:"spin"}):s.jsx(W,{size:20})}),s.jsx("button",{className:"insight-item-action-btn",onClick:()=>void c(i.id,i.title),disabled:G||O,title:"Dismiss this insight","aria-label":"Dismiss this insight","data-testid":`dismiss-${i.id}`,children:G?s.jsx(w,{size:20,className:"spin"}):s.jsx(q,{size:20})})]})]}),i.content&&s.jsx("p",{className:"insight-item-content",children:i.content}),s.jsxs("div",{className:"insight-item-meta",children:[s.jsx("span",{className:`insight-item-status insight-item-status--${i.status}`,children:i.status}),i.createdAt&&s.jsxs("span",{className:"insight-item-date",children:[s.jsx(X,{size:12}),new Date(i.createdAt).toLocaleDateString()]})]})]},i.id)})})})]})};return s.jsxs("div",{className:"insights-view","data-testid":"insights-view",children:[s.jsxs("div",{className:"insights-view-header",children:[s.jsxs("div",{className:"insights-view-title",children:[s.jsxs("h2",{children:[s.jsx(f,{size:20}),"Insights"]}),s.jsxs("span",{className:"insights-view-count",children:[v," total"]})]}),s.jsxs("div",{className:"insights-view-actions",children:[C&&s.jsx("button",{className:"btn btn-sm insights-view-close",onClick:C,"aria-label":"Close insights view",title:"Close",children:s.jsx(q,{size:16})}),s.jsxs("button",{className:"btn btn-sm",onClick:()=>void R(),disabled:I,"aria-label":"Refresh insights","data-testid":"refresh-insights",children:[s.jsx(w,{size:14,className:I?"spin":""}),"Refresh"]}),s.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>void n(),disabled:z,"aria-label":"Generate new insights","data-testid":"run-insights",children:z?s.jsxs(s.Fragment,{children:[s.jsx(w,{size:14,className:"spin"}),"Generating..."]}):s.jsxs(s.Fragment,{children:[s.jsx(f,{size:14}),"Generate Insights"]})})]})]}),s.jsx("div",{className:"insights-status-region","aria-live":"polite","data-testid":"insights-status",children:x&&s.jsxs("div",{className:`insights-status-message insights-status-message--${j}`,role:j==="error"?"alert":void 0,children:[j==="success"&&s.jsx(V,{size:16}),j==="error"&&s.jsx(L,{size:16}),j==="info"&&s.jsx(f,{size:16}),s.jsx("span",{children:x})]})}),F&&s.jsxs("div",{className:"insights-error-callout",role:"alert","data-testid":"run-error",children:[s.jsx(L,{size:16}),s.jsx("span",{children:F})]}),g&&s.jsx("div",{className:"insights-run-info","data-testid":"latest-run",children:s.jsxs("span",{className:"insights-run-status",children:["Latest run: ",g.status,g.status==="completed"&&s.jsxs(s.Fragment,{children:[" — ",g.insightsCreated," created, ",g.insightsUpdated," updated"]}),g.status==="failed"&&g.error&&s.jsxs(s.Fragment,{children:[" — ",g.error]})]})}),I?s.jsxs("div",{className:"insights-loading","data-testid":"insights-loading",children:[s.jsx(w,{size:24,className:"spin"}),s.jsx("p",{children:"Loading insights..."})]}):E?s.jsxs("div",{className:"insights-error","data-testid":"insights-error",children:[s.jsx(L,{size:24}),s.jsx("p",{children:E}),s.jsx("button",{className:"btn btn-sm",onClick:()=>void R(),children:"Retry"})]}):v===0?s.jsxs("div",{className:"insights-empty","data-testid":"insights-empty",children:[s.jsx(f,{size:48}),s.jsx("h3",{children:"No insights yet"}),s.jsx("p",{children:"Generate insights to get AI-powered recommendations for your project."}),s.jsxs("button",{className:"btn btn-primary",onClick:()=>void n(),children:[s.jsx(f,{size:14}),"Generate First Insights"]})]}):s.jsxs("div",{className:"insights-body",children:[s.jsx("aside",{className:"insights-sidebar","aria-label":"Insight categories",children:s.jsx("ul",{className:"insights-category-list",children:m.map(J)})}),s.jsx("div",{className:"insights-detail",children:K()})]})]})}export{ys as InsightsView};
11
+ */const os=[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"m19 9-5 5-4-4-3 3",key:"2osh9i"}]],hs=J("chart-line",os),T=["architecture","quality","workflow","performance","reliability","security","ux","testability","documentation","dependency","features","competitive_analysis","research","trends","other"],Y={quality:"Quality",performance:"Performance",architecture:"Architecture",security:"Security",reliability:"Reliability",ux:"User Experience",testability:"Testability",documentation:"Documentation",dependency:"Dependencies",workflow:"Workflow",other:"Other",features:"Features",competitive_analysis:"Competitive Analysis",research:"Research",trends:"Trends"};function ds(d){const[o,C]=a.useState(()=>T.map(t=>({category:t,label:Y[t]??t,items:[],isLoading:!1,error:null}))),[S,M]=a.useState(!0),[I,E]=a.useState(null),[g,z]=a.useState(null),[F,R]=a.useState(!1),[A,k]=a.useState(null),[D,N]=a.useState(new Map),[$,v]=a.useState(new Map),x=a.useCallback(async()=>{M(!0),E(null);try{const t=await Z({status:void 0,limit:1e3},d),e=new Map;for(const c of T)e.set(c,[]);for(const c of t.insights)if(c.status!=="dismissed"){const y=e.get(c.category)??[];e.set(c.category,[...y,c])}C(T.map(c=>({category:c,label:Y[c]??c,items:e.get(c)??[],isLoading:!1,error:null})));const n=await ss(d);n.runs.length>0&&z(n.runs[0])}catch(t){const e=t instanceof Error?t.message:"Failed to fetch insights";E(e)}finally{M(!1)}},[d]),h=a.useCallback(async()=>{R(!0),k(null);try{const t=await es("manual",void 0,d);z(t),t.status==="completed"?await x():t.status==="failed"&&t.error&&k(t.error)}catch(t){const e=t instanceof Error?t.message:"Failed to generate insights";throw k(e),t}finally{R(!1)}},[d,x]),j=a.useCallback(async t=>{N(e=>{const n=new Map(e);return n.set(t,{running:!0,error:null}),n});try{await ts(t,d),C(e=>e.map(n=>({...n,items:n.items.filter(c=>c.id!==t)}))),N(e=>{const n=new Map(e);return n.set(t,{running:!1,error:null}),n})}catch(e){const n=e instanceof Error?e.message:"Failed to dismiss insight";throw N(c=>{const y=new Map(c);return y.set(t,{running:!1,error:n}),y}),e}},[d]),u=a.useCallback(async t=>{v(e=>{const n=new Map(e);return n.set(t,{running:!0,error:null}),n});try{const e=await is(t,d);return v(n=>{const c=new Map(n);return c.set(t,{running:!1,error:null}),c}),{title:e.suggestedTitle,description:e.suggestedDescription}}catch(e){const n=e instanceof Error?e.message:"Failed to create task";throw v(c=>{const y=new Map(c);return y.set(t,{running:!1,error:n}),y}),e}},[d]),m=a.useMemo(()=>o.reduce((t,e)=>t+e.items.length,0),[o]),p=a.useMemo(()=>0,[o]);return a.useMemo(()=>{x()},[]),{sections:o,loading:S,error:I,latestRun:g,isRunInFlight:F,runError:A,refresh:x,runInsights:h,dismiss:j,createTask:u,dismissStates:D,createTaskStates:$,totalCount:m,dismissedCount:p}}const H={architecture:ls,quality:Q,workflow:W,performance:B,reliability:w,security:L,ux:P,testability:rs,documentation:ns,dependency:V,features:as,competitive_analysis:P,research:hs,trends:B,other:f};function ys({projectId:d,addToast:o,onClose:C,onCreateTask:S}){const{sections:M,loading:I,error:E,latestRun:g,isRunInFlight:z,runError:F,refresh:R,runInsights:A,dismiss:k,createTask:D,dismissStates:N,createTaskStates:$,totalCount:v}=ds(d),[x,h]=a.useState(null),[j,u]=a.useState("info"),m=a.useMemo(()=>M.filter(r=>r.items.length>0),[M]),[p,t]=a.useState(null);a.useEffect(()=>{if(m.length===0){p!==null&&t(null);return}p&&m.some(i=>i.category===p)||t(m[0].category)},[m,p]);const e=a.useMemo(()=>m.find(r=>r.category===p)??m[0],[m,p]);a.useEffect(()=>{if(x){const r=setTimeout(()=>h(null),5e3);return()=>clearTimeout(r)}},[x]);const n=a.useCallback(async()=>{try{h("Generating insights..."),u("info"),await A(),h("Insight generation started"),u("success"),o("Insight generation started","success")}catch(r){const i=r instanceof Error?r.message:"Failed to start generation";h(i),u("error"),o(i,"error")}},[A,o]),c=a.useCallback(async(r,i)=>{try{h(`Dismissing "${i}"...`),u("info"),await k(r),h(`Dismissed "${i}"`),u("success"),o(`Insight dismissed: ${i}`,"success")}catch(l){const b=l instanceof Error?l.message:"Failed to dismiss insight";h(b),u("error"),o(b,"error")}},[k,o]),y=a.useCallback(async(r,i)=>{try{h(`Creating task from "${i}"...`),u("info");const l=await D(r);l&&S&&S(l.title,l.description),h(`Task created from "${i}"`),u("success"),o(`Task created: ${l?.title??i}`,"success")}catch(l){const b=l instanceof Error?l.message:"Failed to create task";h(b),u("error"),o(b,"error")}},[D,S,o]),X=r=>{const i=H[r.category]??f,l=e?.category===r.category;return s.jsx("li",{children:s.jsxs("button",{type:"button",className:`insights-category-item${l?" insights-category-item--active":""}`,onClick:()=>t(r.category),"aria-current":l?"true":void 0,"data-testid":`insights-category-${r.category}`,children:[s.jsx(i,{size:16,className:"insights-category-icon"}),s.jsx("span",{className:"insights-category-label",children:r.label}),s.jsx("span",{className:"insights-category-count",children:r.items.length})]})},r.category)},K=()=>{if(!e)return null;const r=H[e.category]??f;return s.jsxs("section",{className:"insights-section","data-testid":`insights-section-${e.category}`,children:[s.jsx("div",{className:"insights-section-header",children:s.jsxs("div",{className:"insights-section-title",children:[s.jsx(r,{size:20,className:"insights-section-icon"}),s.jsx("h3",{children:e.label}),s.jsx("span",{className:"insights-section-count",children:e.items.length})]})}),s.jsx("div",{className:"insights-section-content",children:s.jsx("ul",{className:"insights-list",children:e.items.map(i=>{const l=N.get(i.id),b=$.get(i.id),G=l?.running??!1,_=b?.running??!1,O=e.items.some(U=>N.get(U.id)?.running||$.get(U.id)?.running);return s.jsxs("li",{className:"insight-item","data-insight-id":i.id,children:[s.jsxs("div",{className:"insight-item-header",children:[s.jsx("h4",{className:"insight-item-title",children:i.title}),s.jsxs("div",{className:"insight-item-actions",children:[s.jsx("button",{className:"insight-item-action-btn",onClick:()=>void y(i.id,i.title),disabled:_||O,title:"Create task from this insight","aria-label":"Create task from this insight","data-testid":`create-task-${i.id}`,children:_?s.jsx(w,{size:20,className:"spin"}):s.jsx(V,{size:20})}),s.jsx("button",{className:"insight-item-action-btn",onClick:()=>void c(i.id,i.title),disabled:G||O,title:"Dismiss this insight","aria-label":"Dismiss this insight","data-testid":`dismiss-${i.id}`,children:G?s.jsx(w,{size:20,className:"spin"}):s.jsx(q,{size:20})})]})]}),i.content&&s.jsx("p",{className:"insight-item-content",children:i.content}),s.jsxs("div",{className:"insight-item-meta",children:[s.jsx("span",{className:`insight-item-status insight-item-status--${i.status}`,children:i.status}),i.createdAt&&s.jsxs("span",{className:"insight-item-date",children:[s.jsx(W,{size:12}),new Date(i.createdAt).toLocaleDateString()]})]})]},i.id)})})})]})};return s.jsxs("div",{className:"insights-view","data-testid":"insights-view",children:[s.jsxs("div",{className:"insights-view-header",children:[s.jsxs("div",{className:"insights-view-title",children:[s.jsxs("h2",{children:[s.jsx(f,{size:20}),"Insights"]}),s.jsxs("span",{className:"insights-view-count",children:[v," total"]})]}),s.jsxs("div",{className:"insights-view-actions",children:[C&&s.jsx("button",{className:"btn btn-sm insights-view-close",onClick:C,"aria-label":"Close insights view",title:"Close",children:s.jsx(q,{size:16})}),s.jsxs("button",{className:"btn btn-sm",onClick:()=>void R(),disabled:I,"aria-label":"Refresh insights","data-testid":"refresh-insights",children:[s.jsx(w,{size:14,className:I?"spin":""}),"Refresh"]}),s.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>void n(),disabled:z,"aria-label":"Generate new insights","data-testid":"run-insights",children:z?s.jsxs(s.Fragment,{children:[s.jsx(w,{size:14,className:"spin"}),"Generating..."]}):s.jsxs(s.Fragment,{children:[s.jsx(f,{size:14}),"Generate Insights"]})})]})]}),s.jsx("div",{className:"insights-status-region","aria-live":"polite","data-testid":"insights-status",children:x&&s.jsxs("div",{className:`insights-status-message insights-status-message--${j}`,role:j==="error"?"alert":void 0,children:[j==="success"&&s.jsx(Q,{size:16}),j==="error"&&s.jsx(L,{size:16}),j==="info"&&s.jsx(f,{size:16}),s.jsx("span",{children:x})]})}),F&&s.jsxs("div",{className:"insights-error-callout",role:"alert","data-testid":"run-error",children:[s.jsx(L,{size:16}),s.jsx("span",{children:F})]}),g&&s.jsx("div",{className:"insights-run-info","data-testid":"latest-run",children:s.jsxs("span",{className:"insights-run-status",children:["Latest run: ",g.status,g.status==="completed"&&s.jsxs(s.Fragment,{children:[" — ",g.insightsCreated," created, ",g.insightsUpdated," updated"]}),g.status==="failed"&&g.error&&s.jsxs(s.Fragment,{children:[" — ",g.error]})]})}),I?s.jsxs("div",{className:"insights-loading","data-testid":"insights-loading",children:[s.jsx(w,{size:24,className:"spin"}),s.jsx("p",{children:"Loading insights..."})]}):E?s.jsxs("div",{className:"insights-error","data-testid":"insights-error",children:[s.jsx(L,{size:24}),s.jsx("p",{children:E}),s.jsx("button",{className:"btn btn-sm",onClick:()=>void R(),children:"Retry"})]}):v===0?s.jsxs("div",{className:"insights-empty","data-testid":"insights-empty",children:[s.jsx(f,{size:48}),s.jsx("h3",{children:"No insights yet"}),s.jsx("p",{children:"Generate insights to get AI-powered recommendations for your project."}),s.jsxs("button",{className:"btn btn-primary",onClick:()=>void n(),children:[s.jsx(f,{size:14}),"Generate First Insights"]})]}):s.jsxs("div",{className:"insights-body",children:[s.jsx("aside",{className:"insights-sidebar","aria-label":"Insight categories",children:s.jsx("ul",{className:"insights-category-list",children:m.map(X)})}),s.jsx("div",{className:"insights-detail",children:K()})]})]})}export{ys as InsightsView};
@@ -1,2 +1,2 @@
1
- import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{u as Ie}from"./SettingsModal-eNCZiHa6.js";import{bt as Ee,bu as ke,bv as Le,D as Re,bw as qe,bx as Pe,by as We,bz as we,bA as Me,bB as Te,bC as _e,bD as Oe,bE as Ae,bF as Ue,z as He,bG as Qe,L as w,bH as Fe}from"./index-CLAHcGnI.js";import"./vendor-xterm-DzcZoU0P.js";const _=".fusion/memory/MEMORY.md",$e=5e4,Ye="0 3 * * *",Be="0 4 * * *";function he(i){return{memoryEnabled:i.memoryEnabled!==!1,memoryAutoSummarizeEnabled:i.memoryAutoSummarizeEnabled??!1,memoryAutoSummarizeThresholdChars:i.memoryAutoSummarizeThresholdChars??$e,memoryAutoSummarizeSchedule:i.memoryAutoSummarizeSchedule??Ye,memoryDreamsEnabled:i.memoryDreamsEnabled??!1,memoryDreamsSchedule:i.memoryDreamsSchedule??Be}}function De(i,t){return i.some(c=>c.path===t)?t:i.find(c=>c.path===_)?.path??i[0]?.path??_}function Ge(i={}){const{projectId:t}=i,[c,j]=a.useState(""),[z,M]=a.useState(!0),[C,E]=a.useState(!1),[g,b]=a.useState(!1),[r,x]=a.useState(null),[O,J]=a.useState(!0),[X,I]=a.useState(!1),[v,W]=a.useState(()=>he({})),[A,ee]=a.useState(!0),[ue,U]=a.useState(!1),[o,S]=a.useState([]),[se,L]=a.useState(!0),[m,k]=a.useState(_),[T,u]=a.useState(""),[d,te]=a.useState(!1),[H,p]=a.useState(!1),[ae,Q]=a.useState(!1),[ne,$]=a.useState(!1),[Y,re]=a.useState(!1),[F,D]=a.useState(null),[ye,R]=a.useState(!0),[ge,B]=a.useState(!1),[ie,G]=a.useState(!1),[le,V]=a.useState(null),{status:me,loading:Z,refresh:f}=Ie({projectId:t}),be=a.useCallback(n=>{u(n),p(!0)},[]),N=a.useCallback(async n=>{te(!0);try{const{content:l}=await Ee(n,t);k(n),u(l),p(!1)}finally{te(!1)}},[t]),q=a.useCallback(async()=>{L(!0);try{const{files:n}=await ke(t);if(S(n),n.length===0){k(_),u(""),p(!1);return}const l=De(n,m);l!==m&&await N(l)}finally{L(!1)}},[t,m,N]);a.useEffect(()=>{let n=!1;async function l(){try{const s=await Ue(t);n||(j(s.content),M(!1))}catch{n||(j(""),M(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Me(t);n||(x(s.content),I(s.exists),J(!1))}catch{n||(x(null),I(!1),J(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){ee(!0);try{const s=await He(t);n||W(he(s))}catch{n||W(he({}))}finally{n||ee(!1)}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){L(!0);try{const{files:s}=await ke(t);if(n)return;if(S(s),s.length===0){k(_),u(""),p(!1);return}const h=De(s,m),{content:y}=await Ee(h,t);if(n)return;k(h),u(y),p(!1)}catch{n||(S([]),k(_),u(""),p(!1))}finally{n||L(!1)}}return l(),()=>{n=!0}},[t,m]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await we(t);n||(D(s),R(!1))}catch{n||(D(null),R(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Qe(t);n||V(s)}catch{n||V(null)}}return l(),()=>{n=!0}},[t]);const ce=a.useCallback(n=>{j(n),E(!0)},[]),oe=a.useCallback(async()=>{if(C){b(!0);try{await Le(c,t),E(!1)}finally{b(!1)}}},[c,C,t]),xe=a.useCallback(async n=>{U(!0);try{const l=await Re(n,t);W(he(l))}finally{U(!1)}},[t]),pe=a.useCallback(async n=>{await N(n)},[N]),fe=a.useCallback(async()=>{if(H){Q(!0);try{await qe(m,T,t),p(!1),await q()}finally{Q(!1)}}},[T,H,m,t,q]),je=a.useCallback(async()=>{G(!0);try{const n=await Pe(t);return await f(),n}finally{G(!1)}},[t,f]),ve=a.useCallback(async n=>We(n,t),[t]),K=a.useCallback(async()=>{try{const n=await we(t);D(n)}catch{D(null)}},[t]),P=a.useCallback(async()=>{try{const n=await Me(t);x(n.content),I(n.exists)}catch{x(null),I(!1)}},[t]),de=a.useCallback(async n=>{await Te(n,t),await P()},[t,P]),Se=a.useCallback(async()=>{$(!0);try{const n=await _e(t);return await Promise.all([P(),K()]),{success:n.success,summary:n.summary}}finally{$(!1)}},[t,P,K]),Ne=a.useCallback(async()=>{re(!0);try{return await Oe(t)}finally{re(!1)}},[t]),Ce=a.useCallback(async n=>{B(!0);try{const l=n?await Ae(n,t):await Ae(t);if(n){const s=l.path??n;k(s),u(l.content),p(!1),await q();return}j(l.content),E(!0)}finally{B(!1)}},[t,q]);return{workingMemory:c,workingMemoryLoading:z,workingMemoryDirty:C,setWorkingMemory:ce,saveWorkingMemory:oe,savingWorkingMemory:g,insightsContent:r,insightsLoading:O,insightsExists:X,refreshInsights:P,saveInsights:de,memorySettings:v,settingsLoading:A,savingMemorySettings:ue,saveMemorySettings:xe,memoryFiles:o,memoryFilesLoading:se,selectedFilePath:m,selectedFileContent:T,selectedFileLoading:d,selectedFileDirty:H,setSelectedFileContent:be,selectFile:pe,saveSelectedFile:fe,savingSelectedFile:ae,reloadMemoryFiles:q,backendStatus:me,backendLoading:Z,extractInsights:Se,extracting:ne,triggerDreamNow:Ne,dreamRunning:Y,auditReport:F,auditLoading:ye,refreshAudit:K,compactMemory:Ce,compacting:ge,installQmdAction:je,installingQmd:ie,testRetrieval:ve,stats:le}}const Ve={Patterns:"pattern",Principles:"principle",Conventions:"convention",Pitfalls:"pitfall",Context:"context"},Ze={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"},Ke={"long-term":"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",daily:"Raw daily observations, open loops, and running context for dream processing.",dreams:"Synthesized patterns and open loops promoted from daily memory."};function Je(i){if(!i)return[];const t=[],c=i.split(/(?=^## )/m);for(const j of c){const z=j.trim();if(!z)continue;const M=z.match(/^##\s+(.+?)(\n|$)/);if(M){const C=M[1].trim(),E=Ve[C]??C.toLowerCase(),g=z.slice(M[0].length).trim(),b=g.split(`
2
- `).map(r=>r.replace(/^-\s+/,"").trim()).filter(r=>r.length>0&&(r.startsWith("- ")||r.startsWith("* ")));(b.length>0||g.length>0)&&t.push({name:C,key:E,items:b.length>0?b:g.length>0?[g]:[],expanded:!0})}}return t}function Xe(i){if(!i)return null;const t=i.match(/##\s+Last\s+Updated:\s*(\d{4}-\d{2}-\d{2})/i);return t?t[1]:null}function es(i){return i.reduce((t,c)=>t+c.items.length,0)}function ss(i){switch(i){case"file":return"File (.fusion/memory/)";case"readonly":return"Read-Only";case"qmd":return"QMD (Quantized Memory Distillation)";default:return i}}function ts(i){switch(i){case"healthy":return"Healthy";case"warning":return"Warning";case"issues":return"Issues Found"}}function ls({projectId:i,addToast:t}){const[c,j]=a.useState("working"),[z,M]=a.useState(new Set),[C,E]=a.useState(!1),[g,b]=a.useState(null),[r,x]=a.useState({memoryEnabled:!0,memoryAutoSummarizeEnabled:!1,memoryAutoSummarizeThresholdChars:5e4,memoryAutoSummarizeSchedule:"0 3 * * *",memoryDreamsEnabled:!1,memoryDreamsSchedule:"0 4 * * *"}),[O,J]=a.useState(""),[X,I]=a.useState(!1),[v,W]=a.useState(null),{insightsContent:A,insightsLoading:ee,insightsExists:ue,saveInsights:U,memorySettings:o,settingsLoading:S,saveMemorySettings:se,savingMemorySettings:L,backendStatus:m,backendLoading:k,extractInsights:T,extracting:u,auditReport:d,auditLoading:te,refreshAudit:H,compactMemory:p,compacting:ae,installQmdAction:Q,installingQmd:ne,testRetrieval:$,memoryFiles:Y,memoryFilesLoading:re,selectedFilePath:F,selectedFileContent:D,selectedFileLoading:ye,selectedFileDirty:R,setSelectedFileContent:ge,selectFile:B,saveSelectedFile:ie,savingSelectedFile:G,reloadMemoryFiles:le,triggerDreamNow:V,dreamRunning:me}=Ge({projectId:i});a.useEffect(()=>{x(o)},[o]);const Z=a.useMemo(()=>r.memoryEnabled!==o.memoryEnabled||r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled||r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars||r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule||r.memoryDreamsEnabled!==o.memoryDreamsEnabled||r.memoryDreamsSchedule!==o.memoryDreamsSchedule,[r,o]),f=a.useMemo(()=>Y.find(s=>s.path===F),[Y,F]),be=f?Ke[f.layer]:"Edits the selected memory file.",N=a.useMemo(()=>Je(A),[A]),q=a.useMemo(()=>es(N),[N]),ce=a.useMemo(()=>Xe(A),[A]),oe=a.useCallback(s=>{M(h=>{const y=new Set(h);return y.has(s)?y.delete(s):y.add(s),y})},[]),xe=a.useCallback(async s=>{try{await B(s)}catch{t("Failed to load memory file","error")}},[B,t]),pe=a.useCallback(async()=>{try{await ie(),t("Memory saved","success")}catch{t("Failed to save memory","error")}},[ie,t]),fe=a.useCallback(async()=>{if(!Z)return;const s={};r.memoryEnabled!==o.memoryEnabled&&(s.memoryEnabled=r.memoryEnabled),r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled&&(s.memoryAutoSummarizeEnabled=r.memoryAutoSummarizeEnabled),r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars&&(s.memoryAutoSummarizeThresholdChars=r.memoryAutoSummarizeThresholdChars),r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule&&(s.memoryAutoSummarizeSchedule=r.memoryAutoSummarizeSchedule),r.memoryDreamsEnabled!==o.memoryDreamsEnabled&&(s.memoryDreamsEnabled=r.memoryDreamsEnabled),r.memoryDreamsSchedule!==o.memoryDreamsSchedule&&(s.memoryDreamsSchedule=r.memoryDreamsSchedule);try{await se(s),t("Memory settings saved","success")}catch{t("Failed to save memory settings","error")}},[Z,r,o,se,t]),je=a.useCallback(async()=>{try{const s=await Q();t(s.qmdAvailable?"qmd installed successfully":"qmd install finished, but qmd is still unavailable",s.qmdAvailable?"success":"info")}catch{t("Failed to install qmd","error")}},[Q,t]),ve=a.useCallback(async()=>{I(!0),W(null);try{const s=await $(O);W(s),t(s.qmdAvailable?"Memory retrieval test complete":"qmd is not installed; local fallback was used",s.qmdAvailable?"success":"info")}catch{t("Failed to test memory retrieval","error")}finally{I(!1)}},[O,$,t]),K=a.useCallback(async()=>{try{await V(),t("Dream processing completed","success"),await le()}catch(s){t(s instanceof Error?s.message:"Failed to run dream processing","error")}},[V,le,t]),P=a.useCallback(async()=>{try{await p(F),t("Memory file compacted","success")}catch{t("Failed to compact memory","error")}},[p,F,t]),de=a.useCallback(async()=>{try{const s=await T();t(s.summary,"success")}catch(s){t(s instanceof Error?s.message:"Failed to extract insights","error")}},[T,t]),Se=a.useCallback(async()=>{if(g!==null)try{await U(g),E(!1),b(null),t("Insights saved","success")}catch{t("Failed to save insights","error")}},[g,U,t]),Ne=a.useCallback(()=>{b(A??""),E(!0)},[A]),Ce=a.useCallback(()=>{E(!1),b(null)},[]),n=!k&&m!==null,l=m?.capabilities?.writable??!1;return e.jsxs("div",{className:"memory-view",children:[e.jsx("div",{className:"memory-view-header",children:e.jsxs("div",{children:[e.jsx("h2",{children:"Memory"}),e.jsx("p",{className:"memory-view-description",children:"Working memory, long-term insights, and engine status"})]})}),e.jsxs("div",{className:"memory-view-tabs",role:"tablist",children:[e.jsx("button",{type:"button",role:"tab","aria-selected":c==="working",className:`memory-view-tab${c==="working"?" memory-view-tab--active":""}`,onClick:()=>j("working"),"data-testid":"memory-tab-working",children:"Working Memory"}),e.jsx("button",{type:"button",role:"tab","aria-selected":c==="insights",className:`memory-view-tab${c==="insights"?" memory-view-tab--active":""}`,onClick:()=>j("insights"),"data-testid":"memory-tab-insights",children:"Insights"}),e.jsx("button",{type:"button",role:"tab","aria-selected":c==="engines",className:`memory-view-tab${c==="engines"?" memory-view-tab--active":""}`,onClick:()=>j("engines"),"data-testid":"memory-tab-engines",children:"Engines"})]}),e.jsxs("div",{className:"memory-view-content",children:[c==="working"&&e.jsxs("div",{className:"memory-working-tab",children:[n&&!l&&e.jsx("div",{className:"memory-readonly-banner",children:"This memory backend is read-only. Changes cannot be saved."}),re||ye?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading memory file…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-editor-section",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryViewFilePath",children:"Memory File"}),e.jsx("select",{id:"memoryViewFilePath",className:"select",value:F,onChange:s=>{xe(s.target.value)},disabled:R,children:Y.map(s=>e.jsxs("option",{value:s.path,children:[s.label," - ",s.path]},s.path))}),e.jsx("small",{children:R?"Save or discard the current edits before switching files.":"Choose any project memory file to view or edit."})]}),f&&e.jsxs("div",{className:"memory-file-summary",children:[e.jsx("span",{children:Ze[f.layer]}),e.jsx("strong",{children:f.path}),e.jsxs("small",{children:[f.size.toLocaleString()," bytes · updated ",new Date(f.updatedAt).toLocaleString()]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:f?.label||"Memory Editor"}),e.jsx("small",{children:be}),e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:D,onChange:ge,readOnly:!l,filePath:F})})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsxs("span",{className:"memory-char-count",children:[D.length," characters"]}),e.jsx("div",{className:"memory-flex-spacer"}),l&&D.length>0&&e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:P,disabled:ae||R,children:ae?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Compacting…"]}):"Compact Selected File"}),R&&l&&e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:pe,disabled:G,children:G?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save"})]}),e.jsxs("div",{className:"memory-config-section",children:[e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryDreamsEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryDreamsEnabled",type:"checkbox",checked:r.memoryDreamsEnabled,onChange:s=>{x(h=>({...h,memoryDreamsEnabled:s.target.checked}))},disabled:!r.memoryEnabled||S}),"Process dreams from daily memory"]}),e.jsx("small",{children:"Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md."})]}),r.memoryEnabled&&r.memoryDreamsEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryDreamsSchedule",children:"Dream Schedule"}),e.jsx("input",{id:"memoryDreamsSchedule",type:"text",className:"input",value:r.memoryDreamsSchedule,onChange:s=>{x(h=>({...h,memoryDreamsSchedule:s.target.value}))},placeholder:"0 4 * * *",disabled:S}),e.jsx("small",{children:"Cron expression for dream processing."})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:K,disabled:me||!r.memoryDreamsEnabled,children:me?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Dreaming…"]}):"Dream Now"}),e.jsx("small",{children:"Manually trigger dream processing now."})]})]})]}),e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryAutoSummarizeEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryAutoSummarizeEnabled",type:"checkbox",checked:r.memoryAutoSummarizeEnabled,onChange:s=>{x(h=>({...h,memoryAutoSummarizeEnabled:s.target.checked}))},disabled:!r.memoryEnabled||S}),"Auto-Summarize Memory"]}),e.jsx("small",{children:"Automatically compact memory when it exceeds the threshold on a schedule"})]}),r.memoryEnabled&&r.memoryAutoSummarizeEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeThresholdChars",children:"Compaction Threshold (chars)"}),e.jsx("input",{id:"memoryAutoSummarizeThresholdChars",type:"number",className:"input",value:r.memoryAutoSummarizeThresholdChars,onChange:s=>{x(h=>({...h,memoryAutoSummarizeThresholdChars:parseInt(s.target.value,10)||5e4}))},min:1e3,disabled:S}),e.jsx("small",{children:"Memory will be compacted when it exceeds this character count"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeSchedule",children:"Schedule (cron)"}),e.jsx("input",{id:"memoryAutoSummarizeSchedule",type:"text",className:"input",value:r.memoryAutoSummarizeSchedule,onChange:s=>{x(h=>({...h,memoryAutoSummarizeSchedule:s.target.value}))},placeholder:"0 3 * * *",disabled:S}),e.jsx("small",{children:"Cron expression for auto-summarize schedule (default: daily at 3 AM)"})]})]})]}),!r.memoryEnabled&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:"Memory is currently disabled. Enable memory tools in Settings to edit these automations."}),Z&&e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:fe,disabled:L||S,children:L?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save Settings"})})]})]})]}),c==="insights"&&e.jsx("div",{className:"memory-insights-tab",children:ee?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading insights…"})]}):C?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:g??"",onChange:b,readOnly:!1,filePath:".fusion/memory/INSIGHTS.md"})}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ce,children:"Cancel"}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:Se,children:"Save Insights"})]})]}):!ue||N.length===0?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx("p",{children:"No insights extracted yet."}),e.jsx("p",{children:'Insights are automatically extracted from working memory. Click "Extract Now" to trigger extraction manually.'}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm memory-empty-extract-button",onClick:de,disabled:u,children:u?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-stats-row",children:[e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:q}),e.jsx("div",{className:"memory-stat-label",children:"Total Insights"})]}),e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:N.length}),e.jsx("div",{className:"memory-stat-label",children:"Categories"})]}),ce&&e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value memory-stat-value--updated",children:ce}),e.jsx("div",{className:"memory-stat-label",children:"Last Updated"})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:de,disabled:u,children:u?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ne,children:"Edit Raw"})]}),e.jsx("div",{className:"memory-categories-list",children:N.map(s=>{const h=!z.has(s.key);return e.jsxs("div",{className:"memory-category-section",children:[e.jsxs("div",{className:"memory-category-header",onClick:()=>oe(s.key),role:"button",tabIndex:0,onKeyDown:y=>{(y.key==="Enter"||y.key===" ")&&(y.preventDefault(),oe(s.key))},children:[e.jsx("h4",{children:s.name}),e.jsx("span",{className:"memory-category-count",children:s.items.length})]}),h&&e.jsx("div",{className:"memory-category-items",children:s.items.map((y,ze)=>e.jsx("div",{className:"memory-insight-item",children:y.replace(/^-\s+/,"").replace(/^\*\s+/,"")},ze))})]},s.key)})})]})}),c==="engines"&&e.jsx("div",{className:"memory-engines-tab",children:k||te?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading engine status…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-engine-card memory-qmd-card",children:[e.jsx("h3",{children:"QMD Integration"}),m?.qmdAvailable===!0?e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge memory-health-badge--healthy",children:"Installed"}),e.jsx("span",{className:"memory-char-count",children:"qmd is available on PATH."})]}):m?.qmdAvailable===!1?e.jsxs("div",{className:"settings-empty-state memory-status-message",children:[e.jsxs("span",{children:["qmd is not installed. Search will use local files. Install indexed retrieval: ",e.jsx("code",{children:m.qmdInstallCommand||"bun install -g @tobilu/qmd"})]}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:je,disabled:ne,children:ne?"Installing…":"Install qmd"})]}):e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge",children:"Checking"}),e.jsx("span",{className:"memory-char-count",children:"Checking qmd availability…"})]}),e.jsxs("div",{className:"memory-capability-row",children:[m?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),m?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),m?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),m?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),e.jsxs("div",{className:"memory-engine-card memory-retrieval-card",children:[e.jsx("h3",{children:"Test Memory Search"}),e.jsxs("div",{className:"memory-retrieval-input-row",children:[e.jsx("input",{type:"text",className:"input",value:O,onChange:s=>J(s.target.value),placeholder:"Search memory with qmd"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:ve,disabled:X,children:X?"Testing…":"Test Retrieval"})]}),e.jsx("small",{className:"settings-muted",children:"Runs the same qmd-backed memory_search path agents use."}),v&&e.jsxs("div",{className:"memory-test-result",children:[e.jsxs("strong",{children:[v.results.length," result",v.results.length===1?"":"s"," ",'for "',v.query,'"']}),e.jsxs("small",{children:["qmd ",v.qmdAvailable?"available":"missing"," · ",v.usedFallback?"local fallback used":"qmd path used"]}),v.results.length>0?e.jsx("ul",{children:v.results.map((s,h)=>e.jsxs("li",{children:[e.jsxs("span",{children:[s.path,":",s.lineStart]}),e.jsx("p",{children:s.snippet})]},`${s.path}-${s.lineStart}-${h}`))}):e.jsx("small",{children:"No matching memory found."})]})]}),e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Current Backend"}),e.jsx("div",{className:"memory-engine-status",children:e.jsx("span",{className:"memory-emphasis-text",children:ss(m?.currentBackend??"unknown")})}),e.jsxs("div",{className:"memory-capability-row",children:[m?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),m?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),m?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),m?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),d&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsxs("div",{className:"memory-health-header",children:[e.jsx("h3",{children:"Health Status"}),e.jsx("span",{className:`memory-health-badge memory-health-badge--${d.health}`,children:ts(d.health)})]}),e.jsxs("div",{className:"memory-health-grid",children:[e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Working Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.workingMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.workingMemory.sectionCount," sections"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Insights Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.insightsMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.insightsMemory.insightCount," insights"]})]})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Last Extraction"}),e.jsx("div",{className:"memory-emphasis-text",children:d.extraction.success?e.jsx("span",{className:"memory-status-text memory-status-text--success",children:"Success"}):e.jsx("span",{className:"memory-status-text memory-status-text--error",children:"Failed"})}),e.jsx("div",{className:"memory-health-detail",children:d.extraction.summary||`${d.extraction.insightCount} insights extracted`})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Pruning"}),e.jsx("div",{className:"memory-emphasis-text",children:d.pruning.applied?e.jsx("span",{className:"memory-status-text memory-status-text--warning",children:"Applied"}):e.jsx("span",{className:"memory-status-text memory-status-text--muted",children:"Not needed"})}),d.pruning.applied&&e.jsx("div",{className:"memory-health-detail",children:d.pruning.reason})]})]}),d&&d.checks.length>0&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Audit Checks"}),e.jsx("div",{children:d.checks.map(s=>e.jsxs("div",{className:"memory-audit-check",children:[e.jsx("span",{className:s.passed?"memory-audit-check-passed":"memory-audit-check-failed",children:s.passed?"✓":"✗"}),e.jsxs("div",{className:"memory-audit-check-content",children:[e.jsx("div",{className:"memory-emphasis-text",children:s.name}),e.jsx("div",{className:"memory-health-detail",children:s.details})]})]},s.id))})]}),e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:()=>H(),children:"Run Audit"})}),e.jsxs("div",{className:"memory-settings-note",children:[e.jsx("span",{children:"Note: Change backend type in"}),e.jsx("button",{type:"button",className:"memory-settings-note-button",onClick:()=>{t("Open Settings → Memory to change backend type","info")},children:"Settings → Memory"})]})]})})]})]})}export{ls as MemoryView};
1
+ import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{u as Ie}from"./SettingsModal-CL_gWmOj.js";import{br as Ee,bs as ke,bt as Le,y as Re,bu as qe,bv as Pe,bw as We,bx as we,by as Me,bz as Te,bA as _e,bB as Oe,bC as Ae,bD as Ue,x as Qe,bE as He,L as w,bF as Fe}from"./index-Bc8nfKeH.js";import"./vendor-xterm-DzcZoU0P.js";const _=".fusion/memory/MEMORY.md",$e=5e4,Ye="0 3 * * *",Be="0 4 * * *";function he(i){return{memoryEnabled:i.memoryEnabled!==!1,memoryAutoSummarizeEnabled:i.memoryAutoSummarizeEnabled??!1,memoryAutoSummarizeThresholdChars:i.memoryAutoSummarizeThresholdChars??$e,memoryAutoSummarizeSchedule:i.memoryAutoSummarizeSchedule??Ye,memoryDreamsEnabled:i.memoryDreamsEnabled??!1,memoryDreamsSchedule:i.memoryDreamsSchedule??Be}}function De(i,t){return i.some(c=>c.path===t)?t:i.find(c=>c.path===_)?.path??i[0]?.path??_}function Ge(i={}){const{projectId:t}=i,[c,j]=a.useState(""),[z,M]=a.useState(!0),[C,E]=a.useState(!1),[g,b]=a.useState(!1),[r,x]=a.useState(null),[O,J]=a.useState(!0),[X,I]=a.useState(!1),[v,W]=a.useState(()=>he({})),[A,ee]=a.useState(!0),[ue,U]=a.useState(!1),[o,S]=a.useState([]),[se,L]=a.useState(!0),[m,k]=a.useState(_),[T,u]=a.useState(""),[d,te]=a.useState(!1),[Q,p]=a.useState(!1),[ae,H]=a.useState(!1),[ne,$]=a.useState(!1),[Y,re]=a.useState(!1),[F,D]=a.useState(null),[ye,R]=a.useState(!0),[ge,B]=a.useState(!1),[ie,G]=a.useState(!1),[le,V]=a.useState(null),{status:me,loading:Z,refresh:f}=Ie({projectId:t}),be=a.useCallback(n=>{u(n),p(!0)},[]),N=a.useCallback(async n=>{te(!0);try{const{content:l}=await Ee(n,t);k(n),u(l),p(!1)}finally{te(!1)}},[t]),q=a.useCallback(async()=>{L(!0);try{const{files:n}=await ke(t);if(S(n),n.length===0){k(_),u(""),p(!1);return}const l=De(n,m);l!==m&&await N(l)}finally{L(!1)}},[t,m,N]);a.useEffect(()=>{let n=!1;async function l(){try{const s=await Ue(t);n||(j(s.content),M(!1))}catch{n||(j(""),M(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Me(t);n||(x(s.content),I(s.exists),J(!1))}catch{n||(x(null),I(!1),J(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){ee(!0);try{const s=await Qe(t);n||W(he(s))}catch{n||W(he({}))}finally{n||ee(!1)}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){L(!0);try{const{files:s}=await ke(t);if(n)return;if(S(s),s.length===0){k(_),u(""),p(!1);return}const h=De(s,m),{content:y}=await Ee(h,t);if(n)return;k(h),u(y),p(!1)}catch{n||(S([]),k(_),u(""),p(!1))}finally{n||L(!1)}}return l(),()=>{n=!0}},[t,m]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await we(t);n||(D(s),R(!1))}catch{n||(D(null),R(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await He(t);n||V(s)}catch{n||V(null)}}return l(),()=>{n=!0}},[t]);const ce=a.useCallback(n=>{j(n),E(!0)},[]),oe=a.useCallback(async()=>{if(C){b(!0);try{await Le(c,t),E(!1)}finally{b(!1)}}},[c,C,t]),xe=a.useCallback(async n=>{U(!0);try{const l=await Re(n,t);W(he(l))}finally{U(!1)}},[t]),pe=a.useCallback(async n=>{await N(n)},[N]),fe=a.useCallback(async()=>{if(Q){H(!0);try{await qe(m,T,t),p(!1),await q()}finally{H(!1)}}},[T,Q,m,t,q]),je=a.useCallback(async()=>{G(!0);try{const n=await Pe(t);return await f(),n}finally{G(!1)}},[t,f]),ve=a.useCallback(async n=>We(n,t),[t]),K=a.useCallback(async()=>{try{const n=await we(t);D(n)}catch{D(null)}},[t]),P=a.useCallback(async()=>{try{const n=await Me(t);x(n.content),I(n.exists)}catch{x(null),I(!1)}},[t]),de=a.useCallback(async n=>{await Te(n,t),await P()},[t,P]),Se=a.useCallback(async()=>{$(!0);try{const n=await _e(t);return await Promise.all([P(),K()]),{success:n.success,summary:n.summary}}finally{$(!1)}},[t,P,K]),Ne=a.useCallback(async()=>{re(!0);try{return await Oe(t)}finally{re(!1)}},[t]),Ce=a.useCallback(async n=>{B(!0);try{const l=n?await Ae(n,t):await Ae(t);if(n){const s=l.path??n;k(s),u(l.content),p(!1),await q();return}j(l.content),E(!0)}finally{B(!1)}},[t,q]);return{workingMemory:c,workingMemoryLoading:z,workingMemoryDirty:C,setWorkingMemory:ce,saveWorkingMemory:oe,savingWorkingMemory:g,insightsContent:r,insightsLoading:O,insightsExists:X,refreshInsights:P,saveInsights:de,memorySettings:v,settingsLoading:A,savingMemorySettings:ue,saveMemorySettings:xe,memoryFiles:o,memoryFilesLoading:se,selectedFilePath:m,selectedFileContent:T,selectedFileLoading:d,selectedFileDirty:Q,setSelectedFileContent:be,selectFile:pe,saveSelectedFile:fe,savingSelectedFile:ae,reloadMemoryFiles:q,backendStatus:me,backendLoading:Z,extractInsights:Se,extracting:ne,triggerDreamNow:Ne,dreamRunning:Y,auditReport:F,auditLoading:ye,refreshAudit:K,compactMemory:Ce,compacting:ge,installQmdAction:je,installingQmd:ie,testRetrieval:ve,stats:le}}const Ve={Patterns:"pattern",Principles:"principle",Conventions:"convention",Pitfalls:"pitfall",Context:"context"},Ze={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"},Ke={"long-term":"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",daily:"Raw daily observations, open loops, and running context for dream processing.",dreams:"Synthesized patterns and open loops promoted from daily memory."};function Je(i){if(!i)return[];const t=[],c=i.split(/(?=^## )/m);for(const j of c){const z=j.trim();if(!z)continue;const M=z.match(/^##\s+(.+?)(\n|$)/);if(M){const C=M[1].trim(),E=Ve[C]??C.toLowerCase(),g=z.slice(M[0].length).trim(),b=g.split(`
2
+ `).map(r=>r.replace(/^-\s+/,"").trim()).filter(r=>r.length>0&&(r.startsWith("- ")||r.startsWith("* ")));(b.length>0||g.length>0)&&t.push({name:C,key:E,items:b.length>0?b:g.length>0?[g]:[],expanded:!0})}}return t}function Xe(i){if(!i)return null;const t=i.match(/##\s+Last\s+Updated:\s*(\d{4}-\d{2}-\d{2})/i);return t?t[1]:null}function es(i){return i.reduce((t,c)=>t+c.items.length,0)}function ss(i){switch(i){case"file":return"File (.fusion/memory/)";case"readonly":return"Read-Only";case"qmd":return"QMD (Quantized Memory Distillation)";default:return i}}function ts(i){switch(i){case"healthy":return"Healthy";case"warning":return"Warning";case"issues":return"Issues Found"}}function ls({projectId:i,addToast:t}){const[c,j]=a.useState("working"),[z,M]=a.useState(new Set),[C,E]=a.useState(!1),[g,b]=a.useState(null),[r,x]=a.useState({memoryEnabled:!0,memoryAutoSummarizeEnabled:!1,memoryAutoSummarizeThresholdChars:5e4,memoryAutoSummarizeSchedule:"0 3 * * *",memoryDreamsEnabled:!1,memoryDreamsSchedule:"0 4 * * *"}),[O,J]=a.useState(""),[X,I]=a.useState(!1),[v,W]=a.useState(null),{insightsContent:A,insightsLoading:ee,insightsExists:ue,saveInsights:U,memorySettings:o,settingsLoading:S,saveMemorySettings:se,savingMemorySettings:L,backendStatus:m,backendLoading:k,extractInsights:T,extracting:u,auditReport:d,auditLoading:te,refreshAudit:Q,compactMemory:p,compacting:ae,installQmdAction:H,installingQmd:ne,testRetrieval:$,memoryFiles:Y,memoryFilesLoading:re,selectedFilePath:F,selectedFileContent:D,selectedFileLoading:ye,selectedFileDirty:R,setSelectedFileContent:ge,selectFile:B,saveSelectedFile:ie,savingSelectedFile:G,reloadMemoryFiles:le,triggerDreamNow:V,dreamRunning:me}=Ge({projectId:i});a.useEffect(()=>{x(o)},[o]);const Z=a.useMemo(()=>r.memoryEnabled!==o.memoryEnabled||r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled||r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars||r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule||r.memoryDreamsEnabled!==o.memoryDreamsEnabled||r.memoryDreamsSchedule!==o.memoryDreamsSchedule,[r,o]),f=a.useMemo(()=>Y.find(s=>s.path===F),[Y,F]),be=f?Ke[f.layer]:"Edits the selected memory file.",N=a.useMemo(()=>Je(A),[A]),q=a.useMemo(()=>es(N),[N]),ce=a.useMemo(()=>Xe(A),[A]),oe=a.useCallback(s=>{M(h=>{const y=new Set(h);return y.has(s)?y.delete(s):y.add(s),y})},[]),xe=a.useCallback(async s=>{try{await B(s)}catch{t("Failed to load memory file","error")}},[B,t]),pe=a.useCallback(async()=>{try{await ie(),t("Memory saved","success")}catch{t("Failed to save memory","error")}},[ie,t]),fe=a.useCallback(async()=>{if(!Z)return;const s={};r.memoryEnabled!==o.memoryEnabled&&(s.memoryEnabled=r.memoryEnabled),r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled&&(s.memoryAutoSummarizeEnabled=r.memoryAutoSummarizeEnabled),r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars&&(s.memoryAutoSummarizeThresholdChars=r.memoryAutoSummarizeThresholdChars),r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule&&(s.memoryAutoSummarizeSchedule=r.memoryAutoSummarizeSchedule),r.memoryDreamsEnabled!==o.memoryDreamsEnabled&&(s.memoryDreamsEnabled=r.memoryDreamsEnabled),r.memoryDreamsSchedule!==o.memoryDreamsSchedule&&(s.memoryDreamsSchedule=r.memoryDreamsSchedule);try{await se(s),t("Memory settings saved","success")}catch{t("Failed to save memory settings","error")}},[Z,r,o,se,t]),je=a.useCallback(async()=>{try{const s=await H();t(s.qmdAvailable?"qmd installed successfully":"qmd install finished, but qmd is still unavailable",s.qmdAvailable?"success":"info")}catch{t("Failed to install qmd","error")}},[H,t]),ve=a.useCallback(async()=>{I(!0),W(null);try{const s=await $(O);W(s),t(s.qmdAvailable?"Memory retrieval test complete":"qmd is not installed; local fallback was used",s.qmdAvailable?"success":"info")}catch{t("Failed to test memory retrieval","error")}finally{I(!1)}},[O,$,t]),K=a.useCallback(async()=>{try{await V(),t("Dream processing completed","success"),await le()}catch(s){t(s instanceof Error?s.message:"Failed to run dream processing","error")}},[V,le,t]),P=a.useCallback(async()=>{try{await p(F),t("Memory file compacted","success")}catch{t("Failed to compact memory","error")}},[p,F,t]),de=a.useCallback(async()=>{try{const s=await T();t(s.summary,"success")}catch(s){t(s instanceof Error?s.message:"Failed to extract insights","error")}},[T,t]),Se=a.useCallback(async()=>{if(g!==null)try{await U(g),E(!1),b(null),t("Insights saved","success")}catch{t("Failed to save insights","error")}},[g,U,t]),Ne=a.useCallback(()=>{b(A??""),E(!0)},[A]),Ce=a.useCallback(()=>{E(!1),b(null)},[]),n=!k&&m!==null,l=m?.capabilities?.writable??!1;return e.jsxs("div",{className:"memory-view",children:[e.jsx("div",{className:"memory-view-header",children:e.jsxs("div",{children:[e.jsx("h2",{children:"Memory"}),e.jsx("p",{className:"memory-view-description",children:"Working memory, long-term insights, and engine status"})]})}),e.jsxs("div",{className:"memory-view-tabs",role:"tablist",children:[e.jsx("button",{type:"button",role:"tab","aria-selected":c==="working",className:`memory-view-tab${c==="working"?" memory-view-tab--active":""}`,onClick:()=>j("working"),"data-testid":"memory-tab-working",children:"Working Memory"}),e.jsx("button",{type:"button",role:"tab","aria-selected":c==="insights",className:`memory-view-tab${c==="insights"?" memory-view-tab--active":""}`,onClick:()=>j("insights"),"data-testid":"memory-tab-insights",children:"Insights"}),e.jsx("button",{type:"button",role:"tab","aria-selected":c==="engines",className:`memory-view-tab${c==="engines"?" memory-view-tab--active":""}`,onClick:()=>j("engines"),"data-testid":"memory-tab-engines",children:"Engines"})]}),e.jsxs("div",{className:"memory-view-content",children:[c==="working"&&e.jsxs("div",{className:"memory-working-tab",children:[n&&!l&&e.jsx("div",{className:"memory-readonly-banner",children:"This memory backend is read-only. Changes cannot be saved."}),re||ye?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading memory file…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-editor-section",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryViewFilePath",children:"Memory File"}),e.jsx("select",{id:"memoryViewFilePath",className:"select",value:F,onChange:s=>{xe(s.target.value)},disabled:R,children:Y.map(s=>e.jsxs("option",{value:s.path,children:[s.label," - ",s.path]},s.path))}),e.jsx("small",{children:R?"Save or discard the current edits before switching files.":"Choose any project memory file to view or edit."})]}),f&&e.jsxs("div",{className:"memory-file-summary",children:[e.jsx("span",{children:Ze[f.layer]}),e.jsx("strong",{children:f.path}),e.jsxs("small",{children:[f.size.toLocaleString()," bytes · updated ",new Date(f.updatedAt).toLocaleString()]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:f?.label||"Memory Editor"}),e.jsx("small",{children:be}),e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:D,onChange:ge,readOnly:!l,filePath:F})})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsxs("span",{className:"memory-char-count",children:[D.length," characters"]}),e.jsx("div",{className:"memory-flex-spacer"}),l&&D.length>0&&e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:P,disabled:ae||R,children:ae?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Compacting…"]}):"Compact Selected File"}),R&&l&&e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:pe,disabled:G,children:G?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save"})]}),e.jsxs("div",{className:"memory-config-section",children:[e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryDreamsEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryDreamsEnabled",type:"checkbox",checked:r.memoryDreamsEnabled,onChange:s=>{x(h=>({...h,memoryDreamsEnabled:s.target.checked}))},disabled:!r.memoryEnabled||S}),"Process dreams from daily memory"]}),e.jsx("small",{children:"Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md."})]}),r.memoryEnabled&&r.memoryDreamsEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryDreamsSchedule",children:"Dream Schedule"}),e.jsx("input",{id:"memoryDreamsSchedule",type:"text",className:"input",value:r.memoryDreamsSchedule,onChange:s=>{x(h=>({...h,memoryDreamsSchedule:s.target.value}))},placeholder:"0 4 * * *",disabled:S}),e.jsx("small",{children:"Cron expression for dream processing."})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:K,disabled:me||!r.memoryDreamsEnabled,children:me?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Dreaming…"]}):"Dream Now"}),e.jsx("small",{children:"Manually trigger dream processing now."})]})]})]}),e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryAutoSummarizeEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryAutoSummarizeEnabled",type:"checkbox",checked:r.memoryAutoSummarizeEnabled,onChange:s=>{x(h=>({...h,memoryAutoSummarizeEnabled:s.target.checked}))},disabled:!r.memoryEnabled||S}),"Auto-Summarize Memory"]}),e.jsx("small",{children:"Automatically compact memory when it exceeds the threshold on a schedule"})]}),r.memoryEnabled&&r.memoryAutoSummarizeEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeThresholdChars",children:"Compaction Threshold (chars)"}),e.jsx("input",{id:"memoryAutoSummarizeThresholdChars",type:"number",className:"input",value:r.memoryAutoSummarizeThresholdChars,onChange:s=>{x(h=>({...h,memoryAutoSummarizeThresholdChars:parseInt(s.target.value,10)||5e4}))},min:1e3,disabled:S}),e.jsx("small",{children:"Memory will be compacted when it exceeds this character count"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeSchedule",children:"Schedule (cron)"}),e.jsx("input",{id:"memoryAutoSummarizeSchedule",type:"text",className:"input",value:r.memoryAutoSummarizeSchedule,onChange:s=>{x(h=>({...h,memoryAutoSummarizeSchedule:s.target.value}))},placeholder:"0 3 * * *",disabled:S}),e.jsx("small",{children:"Cron expression for auto-summarize schedule (default: daily at 3 AM)"})]})]})]}),!r.memoryEnabled&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:"Memory is currently disabled. Enable memory tools in Settings to edit these automations."}),Z&&e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:fe,disabled:L||S,children:L?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save Settings"})})]})]})]}),c==="insights"&&e.jsx("div",{className:"memory-insights-tab",children:ee?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading insights…"})]}):C?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:g??"",onChange:b,readOnly:!1,filePath:".fusion/memory/INSIGHTS.md"})}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ce,children:"Cancel"}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:Se,children:"Save Insights"})]})]}):!ue||N.length===0?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx("p",{children:"No insights extracted yet."}),e.jsx("p",{children:'Insights are automatically extracted from working memory. Click "Extract Now" to trigger extraction manually.'}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm memory-empty-extract-button",onClick:de,disabled:u,children:u?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-stats-row",children:[e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:q}),e.jsx("div",{className:"memory-stat-label",children:"Total Insights"})]}),e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:N.length}),e.jsx("div",{className:"memory-stat-label",children:"Categories"})]}),ce&&e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value memory-stat-value--updated",children:ce}),e.jsx("div",{className:"memory-stat-label",children:"Last Updated"})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:de,disabled:u,children:u?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ne,children:"Edit Raw"})]}),e.jsx("div",{className:"memory-categories-list",children:N.map(s=>{const h=!z.has(s.key);return e.jsxs("div",{className:"memory-category-section",children:[e.jsxs("div",{className:"memory-category-header",onClick:()=>oe(s.key),role:"button",tabIndex:0,onKeyDown:y=>{(y.key==="Enter"||y.key===" ")&&(y.preventDefault(),oe(s.key))},children:[e.jsx("h4",{children:s.name}),e.jsx("span",{className:"memory-category-count",children:s.items.length})]}),h&&e.jsx("div",{className:"memory-category-items",children:s.items.map((y,ze)=>e.jsx("div",{className:"memory-insight-item",children:y.replace(/^-\s+/,"").replace(/^\*\s+/,"")},ze))})]},s.key)})})]})}),c==="engines"&&e.jsx("div",{className:"memory-engines-tab",children:k||te?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading engine status…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-engine-card memory-qmd-card",children:[e.jsx("h3",{children:"QMD Integration"}),m?.qmdAvailable===!0?e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge memory-health-badge--healthy",children:"Installed"}),e.jsx("span",{className:"memory-char-count",children:"qmd is available on PATH."})]}):m?.qmdAvailable===!1?e.jsxs("div",{className:"settings-empty-state memory-status-message",children:[e.jsxs("span",{children:["qmd is not installed. Search will use local files. Install indexed retrieval: ",e.jsx("code",{children:m.qmdInstallCommand||"bun install -g @tobilu/qmd"})]}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:je,disabled:ne,children:ne?"Installing…":"Install qmd"})]}):e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge",children:"Checking"}),e.jsx("span",{className:"memory-char-count",children:"Checking qmd availability…"})]}),e.jsxs("div",{className:"memory-capability-row",children:[m?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),m?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),m?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),m?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),e.jsxs("div",{className:"memory-engine-card memory-retrieval-card",children:[e.jsx("h3",{children:"Test Memory Search"}),e.jsxs("div",{className:"memory-retrieval-input-row",children:[e.jsx("input",{type:"text",className:"input",value:O,onChange:s=>J(s.target.value),placeholder:"Search memory with qmd"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:ve,disabled:X,children:X?"Testing…":"Test Retrieval"})]}),e.jsx("small",{className:"settings-muted",children:"Runs the same qmd-backed memory_search path agents use."}),v&&e.jsxs("div",{className:"memory-test-result",children:[e.jsxs("strong",{children:[v.results.length," result",v.results.length===1?"":"s"," ",'for "',v.query,'"']}),e.jsxs("small",{children:["qmd ",v.qmdAvailable?"available":"missing"," · ",v.usedFallback?"local fallback used":"qmd path used"]}),v.results.length>0?e.jsx("ul",{children:v.results.map((s,h)=>e.jsxs("li",{children:[e.jsxs("span",{children:[s.path,":",s.lineStart]}),e.jsx("p",{children:s.snippet})]},`${s.path}-${s.lineStart}-${h}`))}):e.jsx("small",{children:"No matching memory found."})]})]}),e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Current Backend"}),e.jsx("div",{className:"memory-engine-status",children:e.jsx("span",{className:"memory-emphasis-text",children:ss(m?.currentBackend??"unknown")})}),e.jsxs("div",{className:"memory-capability-row",children:[m?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),m?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),m?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),m?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),d&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsxs("div",{className:"memory-health-header",children:[e.jsx("h3",{children:"Health Status"}),e.jsx("span",{className:`memory-health-badge memory-health-badge--${d.health}`,children:ts(d.health)})]}),e.jsxs("div",{className:"memory-health-grid",children:[e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Working Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.workingMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.workingMemory.sectionCount," sections"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Insights Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.insightsMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.insightsMemory.insightCount," insights"]})]})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Last Extraction"}),e.jsx("div",{className:"memory-emphasis-text",children:d.extraction.success?e.jsx("span",{className:"memory-status-text memory-status-text--success",children:"Success"}):e.jsx("span",{className:"memory-status-text memory-status-text--error",children:"Failed"})}),e.jsx("div",{className:"memory-health-detail",children:d.extraction.summary||`${d.extraction.insightCount} insights extracted`})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Pruning"}),e.jsx("div",{className:"memory-emphasis-text",children:d.pruning.applied?e.jsx("span",{className:"memory-status-text memory-status-text--warning",children:"Applied"}):e.jsx("span",{className:"memory-status-text memory-status-text--muted",children:"Not needed"})}),d.pruning.applied&&e.jsx("div",{className:"memory-health-detail",children:d.pruning.reason})]})]}),d&&d.checks.length>0&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Audit Checks"}),e.jsx("div",{children:d.checks.map(s=>e.jsxs("div",{className:"memory-audit-check",children:[e.jsx("span",{className:s.passed?"memory-audit-check-passed":"memory-audit-check-failed",children:s.passed?"✓":"✗"}),e.jsxs("div",{className:"memory-audit-check-content",children:[e.jsx("div",{className:"memory-emphasis-text",children:s.name}),e.jsx("div",{className:"memory-health-detail",children:s.details})]})]},s.id))})]}),e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:()=>Q(),children:"Run Audit"})}),e.jsxs("div",{className:"memory-settings-note",children:[e.jsx("span",{children:"Note: Change backend type in"}),e.jsx("button",{type:"button",className:"memory-settings-note-button",onClick:()=>{t("Open Settings → Memory to change backend type","info")},children:"Settings → Memory"})]})]})})]})]})}export{ls as MemoryView};
@@ -1,14 +1,14 @@
1
- import{r as n,j as e}from"./vendor-react-K0fH_qHe.js";import{c as W,aB as xe,aC as ge,aD as pe,aE as je,aF as Z,aG as Q,A as T,aH as _e,Y as Ne,_ as be,aI as ee,aJ as ve,aK as Ce,X as V,aL as ke,aM as Se,R as J,M as G,G as we}from"./index-CLAHcGnI.js";import{U as se}from"./upload-91TM4ljC.js";import"./vendor-xterm-DzcZoU0P.js";/**
1
+ import{r as n,j as e}from"./vendor-react-K0fH_qHe.js";import{c as Y,az as xe,aA as ge,aB as pe,aC as je,aD as Z,aE as Q,A as T,aF as _e,V as Ne,W as be,aG as ee,aH as ve,aI as Ce,X as B,aJ as ke,aK as Se,R as X,J as G,G as we}from"./index-Bc8nfKeH.js";import{U as se}from"./upload-BP60eBwN.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
5
5
  * See the LICENSE file in the root directory of this source tree.
6
- */const Me=[["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"}]],Ae=W("wifi-off",Me);/**
6
+ */const Ae=[["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"}]],Me=Y("wifi-off",Ae);/**
7
7
  * @license lucide-react v1.7.0 - ISC
8
8
  *
9
9
  * This source code is licensed under the ISC license.
10
10
  * See the LICENSE file in the root directory of this source tree.
11
- */const Ee=[["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"}]],Re=W("wifi",Ee);function U(t){const{lastSyncAt:l,remoteReachable:s,diff:r}=t,f=r.global.length+r.project.length;return l===null?{syncState:"never-synced",lastSyncAt:l,diffCount:0}:s?f>0?{syncState:"diff",lastSyncAt:l,diffCount:f}:{syncState:"synced",lastSyncAt:l,diffCount:0}:{syncState:"error",lastSyncAt:l,diffCount:f}}function te(t){if(t===null)return"Never synced";const l=new Date(t);if(Number.isNaN(l.getTime()))return"Never synced";const r=Date.now()-l.getTime(),f=Math.floor(r/1e3),m=Math.floor(f/60),c=Math.floor(m/60),u=Math.floor(c/24);return m<1?"Synced just now":m<60?`Synced ${m}m ago`:c<24?`Synced ${c}h ago`:`Synced ${u}d ago`}function ae(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 Pe=3e4;function $e(){const[t,l]=n.useState({}),[s,r]=n.useState(!1),[f,m]=n.useState({}),[c,u]=n.useState(null),o=n.useRef(new Set),y=n.useRef(!1),g=n.useRef(null),j=n.useRef(null),C=n.useCallback(async(h,d)=>{try{const p=await xe(h);l(z=>({...z,[h]:p})),u(null)}catch(p){console.error(`Failed to fetch sync status for node ${h}:`,p),u(p instanceof Error?p.message:"Failed to fetch sync status")}},[]),_=n.useCallback(async()=>{const h=Array.from(o.current);if(h.length===0)return;g.current&&g.current.abort(),g.current=new AbortController;const d=!y.current;d&&r(!0),u(null);try{const p=await Promise.allSettled(h.map(L=>C(L,d)));y.current=!0,p.filter(L=>L.status==="rejected").length>0&&u("Some sync status requests failed")}catch(p){if(p instanceof Error&&p.name==="AbortError")return;u(p instanceof Error?p.message:"Failed to fetch sync status"),y.current=!0}finally{r(!1)}},[C]),S=n.useCallback(()=>{j.current&&clearInterval(j.current),j.current=setInterval(()=>{_()},Pe)},[_]),M=n.useCallback(()=>{j.current&&(clearInterval(j.current),j.current=null)},[]);n.useEffect(()=>(_(),S(),()=>{M(),g.current&&g.current.abort()}),[_,S,M]);const a=n.useCallback(h=>{o.current.has(h)||(o.current.add(h),C(h,!y.current))},[C]),i=n.useCallback(h=>{o.current.delete(h),l(d=>{const p={...d};return delete p[h],p}),o.current.size===0&&M()},[M]),x=n.useCallback(async h=>{m(d=>({...d,[h]:!0})),u(null);try{const d=await ge(h);return C(h,!1),!d.success&&d.error&&u(d.error),d}catch(d){const p=d instanceof Error?d.message:"Push settings failed";throw u(p),d}finally{m(d=>{const p={...d};return delete p[h],p})}},[C]),b=n.useCallback(async h=>{m(d=>({...d,[h]:!0})),u(null);try{const d=await pe(h);return C(h,!1),!d.success&&d.error&&u(d.error),d}catch(d){const p=d instanceof Error?d.message:"Pull settings failed";throw u(p),d}finally{m(d=>{const p={...d};return delete p[h],p})}},[C]),w=n.useCallback(async h=>{m(d=>({...d,[h]:!0})),u(null);try{return await je(h)}catch(d){const p=d instanceof Error?d.message:"Auth sync failed";throw u(p),d}finally{m(d=>{const p={...d};return delete p[h],p})}},[]),$=n.useCallback(h=>t[h]?.authMatch,[t]),v=n.useCallback(h=>t[h]?.authDiff,[t]);return{syncStatusMap:t,loading:s,actionLoading:f,error:c,refresh:_,trackNode:a,untrackNode:i,pushSettings:x,pullSettings:b,syncAuth:w,getAuthSyncState:$,getAuthProviders:v}}function Le(t,l){return l.type==="remote"?t.nodeId===l.id:t.nodeId===l.id||t.nodeId===void 0||t.nodeId===null}function ne(t,l){return t.filter(s=>Le(s,l))}function H(t,l){return ne(t,l).length}const ze={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"}},De={match:"var(--color-success)",differs:"var(--color-warning)","not-synced":"var(--text-muted)"};function Oe(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 s=Object.entries(l).filter(([,r])=>r==="differs").map(([r])=>r);if(s.length>0)return`Auth credentials differ: ${s.join(", ")}`}return"Auth credentials differ"}function Fe(t,l=42){return t.length<=l?t:`${t.slice(0,l-3)}...`}function Ie(t,l){const s=t.node,r=l.node;if(s.id!==r.id||s.name!==r.name||s.type!==r.type||s.url!==r.url||s.status!==r.status||s.maxConcurrent!==r.maxConcurrent||s.updatedAt!==r.updatedAt||t.isLoading!==l.isLoading)return!1;const f=t.syncStatus,m=l.syncStatus;if(!(!f&&!m)){if(!f||!m)return!1;if(f.syncState!==m.syncState||f.lastSyncAt!==m.lastSyncAt||f.diffCount!==m.diffCount)return!1}if(t.authSyncState!==l.authSyncState)return!1;const c=t.authSyncProviders,u=l.authSyncProviders;if(c!==u){if(!c||!u)return!1;{const g=Object.keys(c),j=Object.keys(u);if(g.length!==j.length||g.some(C=>c[C]!==u[C]))return!1}}const o=H(t.projects,s),y=H(l.projects,r);return o===y}function Ke({node:t,projects:l,onHealthCheck:s,onEdit:r,onRemove:f,isLoading:m=!1,syncStatus:c,authSyncState:u,authSyncProviders:o}){const[y,g]=n.useState(!1),j=ze[t.status],C=n.useMemo(()=>H(l,t),[l,t]),_=n.useCallback(()=>{r(t)},[r,t]),S=n.useCallback(x=>{x.stopPropagation(),s(t.id)},[s,t.id]),M=n.useCallback(x=>{x.stopPropagation(),r(t)},[r,t]),a=n.useCallback(x=>{if(x.stopPropagation(),!y){g(!0);return}f(t.id),g(!1)},[y,f,t.id]),i=n.useCallback(x=>{(x.key==="Enter"||x.key===" ")&&(x.preventDefault(),r(t))},[r,t]);return e.jsxs("article",{className:`node-card ${m?"node-card--loading":""}`,"data-node-id":t.id,role:"button",tabIndex:0,onClick:_,onKeyDown:i,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(Z,{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"}),e.jsxs("span",{className:`node-card__status ${j.className}`,style:{color:j.color},"data-status":t.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:j.color},"aria-hidden":!0}),j.label]}),t.type==="remote"&&u&&e.jsx("span",{className:`node-card__auth-indicator node-card__auth-indicator--${u}`,title:Oe(u,o),"aria-label":`Auth sync: ${u==="match"?"credentials match":u==="differs"?"credentials differ":"not synced"}`,style:{color:De[u]},children:e.jsx(Q,{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:Fe(t.url)}),e.jsxs("div",{className:"node-card__metrics",children:[e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Projects"}),e.jsx("span",{className:"node-card__metric-value",children:C})]}),e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Concurrency"}),e.jsx("span",{className:"node-card__metric-value",children:t.maxConcurrent})]})]}),t.type==="remote"&&c&&e.jsxs("div",{className:"node-card__sync","data-sync-state":c.syncState,"data-testid":"node-card-sync",children:[e.jsx("span",{className:"node-card__sync-dot",style:{backgroundColor:ae(c.syncState)},"aria-hidden":!0}),e.jsx("span",{className:"node-card__sync-time",children:te(c.lastSyncAt)})]})]}),e.jsxs("footer",{className:"node-card__actions",children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:S,disabled:m,"aria-label":"Run node health check",title:"Health Check",children:[e.jsx(T,{size:14}),e.jsx("span",{children:"Health"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:M,disabled:m,"aria-label":"Edit node",title:"Edit",children:[e.jsx(_e,{size:14}),e.jsx("span",{children:"Edit"})]}),e.jsxs("button",{className:`btn btn-sm node-card__action node-card__action--remove ${y?"btn-danger is-armed":""}`,type:"button",onClick:a,disabled:m,"aria-label":y?"Confirm remove node":"Remove node",title:y?"Confirm remove":"Remove",children:[e.jsx(Ne,{size:14}),e.jsx("span",{children:y?"Confirm":"Remove"})]})]})]})}const Ue=n.memo(Ke,Ie),O={online:"var(--success, var(--color-success))",offline:"var(--text-dim)",connecting:"var(--triage)",error:"var(--color-error)"},D=28,Y=12,Be=300,Ve=120;function He({nodes:t,className:l}){const s=n.useMemo(()=>t.find(o=>o.type==="local")??t[0],[t]),r=n.useMemo(()=>t.filter(o=>o.type==="remote"),[t]),f=n.useMemo(()=>{const o=Be,y=Math.max(0,r.length-4)*20;return o+y},[r.length]),m=f/2,c=f/2,u=n.useMemo(()=>{if(r.length===0)return[];const o=Math.min(Ve,f/2-D-10),y=2*Math.PI/r.length,g=-Math.PI/2;return r.map((j,C)=>{const _=g+C*y;return{node:j,x:m+o*Math.cos(_),y:c+o*Math.sin(_)}})},[r,f,m,c]);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 ${f} ${f}`,preserveAspectRatio:"xMidYMid meet","aria-label":"Node mesh topology visualization",children:[u.map(o=>e.jsx("line",{className:"mesh-topology__link",x1:m,y1:c,x2:o.x,y2:o.y},`link-${o.node.id}`)),s&&e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${m}, ${c})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:D,fill:O[s.status],"aria-label":`${s.name} (${s.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:D+Y,textAnchor:"middle",children:s.name.length>12?`${s.name.slice(0,10)}…`:s.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-D-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:s.type==="local"?"L":"R"})]})]}),u.map(o=>e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${o.x}, ${o.y})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:D,fill:O[o.node.status],"aria-label":`${o.node.name} (${o.node.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:D+Y,textAnchor:"middle",children:o.node.name.length>12?`${o.node.name.slice(0,10)}…`:o.node.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-D-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:o.node.type==="local"?"L":"R"})]})]},o.node.id))]}),e.jsxs("div",{className:"mesh-topology__legend",children:[e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:O.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:O.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:O.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:O.error}}),e.jsx("span",{children:"Error"})]})]}),e.jsx("p",{className:"mesh-topology__notice",children:"Peer-to-peer discovery data unavailable."})]})}const qe=n.memo(He),q=1,X=10;function Xe(t){const l={};return 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<q||t.maxConcurrent>X)&&(l.maxConcurrent=`Concurrency must be between ${q} and ${X}`),l}function Je({isOpen:t,onClose:l,onSubmit:s,addToast:r}){const[f,m]=n.useState(""),[c,u]=n.useState("local"),[o,y]=n.useState(""),[g,j]=n.useState(""),[C,_]=n.useState(2),[S,M]=n.useState({}),[a,i]=n.useState(!1),x=n.useCallback(()=>{m(""),u("local"),y(""),j(""),_(2),M({}),i(!1)},[]),b=n.useCallback(()=>{a||(x(),l())},[a,l,x]);n.useEffect(()=>{if(!t){x();return}const v=h=>{h.key==="Escape"&&(h.preventDefault(),b())};return document.addEventListener("keydown",v),()=>{document.removeEventListener("keydown",v)}},[b,t,x]);const w=n.useMemo(()=>({name:f.trim(),type:c,url:c==="remote"&&o.trim()||void 0,apiKey:c==="remote"&&g||void 0,maxConcurrent:C}),[g,C,f,c,o]),$=n.useCallback(async()=>{if(a)return;const v=Xe(w);if(M(v),!(Object.keys(v).length>0)){i(!0);try{await s(w),r(`Node "${w.name}" registered`,"success"),b()}catch(h){const d=h instanceof Error?h.message:"Failed to register node";r(d,"error")}finally{i(!1)}}},[r,b,w,a,s]);return t?e.jsx("div",{className:"modal-overlay open",onClick:b,children:e.jsxs("div",{className:"modal modal-md add-node-modal",onClick:v=>v.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:b,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 a node to distribute task execution across machines."}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Name"}),e.jsx("input",{className:"input",type:"text",value:f,onChange:v=>m(v.target.value),placeholder:"Build Machine",disabled:a,"aria-invalid":!!S.name,autoFocus:!0}),S.name&&e.jsx("span",{className:"form-error add-node-modal__error",children:S.name})]}),e.jsxs("div",{className:"add-node-modal__type-toggle",children:[e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${c==="local"?"active":""}`,"data-type":"local",onClick:()=>u("local"),disabled:a,"aria-pressed":c==="local",children:"Local"}),e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${c==="remote"?"active":""}`,"data-type":"remote",onClick:()=>u("remote"),disabled:a,"aria-pressed":c==="remote",children:"Remote"})]}),e.jsxs("div",{className:"add-node-modal__remote-fields","data-testid":"remote-fields-container","data-visible":c==="remote",children:[e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"URL"}),e.jsx("input",{className:"input",type:"text",value:o,onChange:v=>y(v.target.value),placeholder:"https://node.example.com",disabled:a,"aria-invalid":!!S.url}),S.url&&e.jsx("span",{className:"form-error add-node-modal__error",children:S.url})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:g,onChange:v=>j(v.target.value),placeholder:"Optional",disabled:a})]})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),e.jsx("input",{className:"input",type:"number",min:q,max:X,value:C,onChange:v=>_(Number(v.target.value)),disabled:a,"aria-invalid":!!S.maxConcurrent}),e.jsx("span",{className:"add-node-modal__hint",children:"Max simultaneous task agents (1–10)"}),S.maxConcurrent&&e.jsx("span",{className:"form-error add-node-modal__error",children:S.maxConcurrent})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:b,disabled:a,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm","data-testid":"add-node-submit",onClick:$,disabled:a,children:a?"Adding...":"Add Node"})]})]})}):null}function Ge({nodeId:t,entries:l,loading:s=!1,singleNode:r=!1}){const[f,m]=n.useState(!1),[c,u]=n.useState("all"),[o,y]=n.useState("all"),g=n.useCallback(()=>{m(a=>!a)},[]),j=n.useMemo(()=>{const a=new Set;for(const i of l)a.add(i.nodeName);return Array.from(a).sort()},[l]),C=n.useMemo(()=>{let a=[...l];return c!=="all"&&(a=a.filter(i=>i.direction===c)),!r&&o!=="all"&&(a=a.filter(i=>i.nodeName===o)),a.sort((i,x)=>{const b=new Date(i.timestamp).getTime();return new Date(x.timestamp).getTime()-b}),a},[l,c,o,r]),_=n.useCallback(a=>new Date(a).toLocaleString(),[]),S=n.useCallback(a=>{switch(a){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""}},[]),M=n.useCallback(a=>{switch(a){case"success":return"Success";case"conflict":return"Conflict";case"error":return"Error";default:return a}},[]);return e.jsxs("div",{className:"settings-sync-log",children:[e.jsxs("button",{className:"settings-sync-log__header",type:"button",onClick:g,"aria-expanded":f,"data-testid":"settings-sync-log-header",children:[e.jsx(be,{size:16,className:`settings-sync-log__chevron ${f?"settings-sync-log__chevron--expanded":""}`}),e.jsxs("span",{children:[l.length," ",l.length===1?"entry":"entries"]})]}),f&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-sync-log__filters",children:[e.jsxs("label",{children:["Direction:",e.jsxs("select",{value:c,onChange:a=>u(a.target.value),children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"push",children:"Push"}),e.jsx("option",{value:"pull",children:"Pull"})]})]}),!r&&e.jsxs("label",{children:["Node:",e.jsxs("select",{value:o,onChange:a=>y(a.target.value),children:[e.jsx("option",{value:"all",children:"All Nodes"}),j.map(a=>e.jsx("option",{value:a,children:a},a))]})]})]}),s&&l.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"Loading..."}):C.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"No sync history available"}):e.jsx("div",{className:"settings-sync-log__list",children:C.map(a=>e.jsxs("div",{className:"settings-sync-log__entry",children:[e.jsx("span",{className:"settings-sync-log__entry-timestamp",children:_(a.timestamp)}),e.jsx("span",{className:"settings-sync-log__entry-direction",children:a.direction==="push"?e.jsx(se,{size:14,"data-testid":"upload-icon"}):e.jsx(ee,{size:14,"data-testid":"download-icon"})}),e.jsx("span",{className:`settings-sync-log__entry-result ${S(a.result)}`,children:M(a.result)}),!r&&e.jsx("span",{className:"settings-sync-log__entry-node",children:a.nodeName}),a.details&&e.jsx("span",{className:"settings-sync-log__entry-details",title:a.details,children:a.details})]},a.id))})]})]})}function Ye(t,l){const s=typeof t=="string"?t:JSON.stringify(t,null,2),r=typeof l=="string"?l:JSON.stringify(l,null,2);if(s===r)return s;const f=s.split(`
11
+ */const Ee=[["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"}]],Re=Y("wifi",Ee);function U(t){const{lastSyncAt:l,remoteReachable:s,diff:r}=t,f=r.global.length+r.project.length;return l===null?{syncState:"never-synced",lastSyncAt:l,diffCount:0}:s?f>0?{syncState:"diff",lastSyncAt:l,diffCount:f}:{syncState:"synced",lastSyncAt:l,diffCount:0}:{syncState:"error",lastSyncAt:l,diffCount:f}}function te(t){if(t===null)return"Never synced";const l=new Date(t);if(Number.isNaN(l.getTime()))return"Never synced";const r=Date.now()-l.getTime(),f=Math.floor(r/1e3),m=Math.floor(f/60),c=Math.floor(m/60),u=Math.floor(c/24);return m<1?"Synced just now":m<60?`Synced ${m}m ago`:c<24?`Synced ${c}h ago`:`Synced ${u}d ago`}function ae(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 Pe=3e4;function $e(){const[t,l]=n.useState({}),[s,r]=n.useState(!1),[f,m]=n.useState({}),[c,u]=n.useState(null),o=n.useRef(new Set),y=n.useRef(!1),g=n.useRef(null),j=n.useRef(null),C=n.useCallback(async(h,d)=>{try{const p=await xe(h);l(z=>({...z,[h]:p})),u(null)}catch(p){console.error(`Failed to fetch sync status for node ${h}:`,p),u(p instanceof Error?p.message:"Failed to fetch sync status")}},[]),_=n.useCallback(async()=>{const h=Array.from(o.current);if(h.length===0)return;g.current&&g.current.abort(),g.current=new AbortController;const d=!y.current;d&&r(!0),u(null);try{const p=await Promise.allSettled(h.map(L=>C(L,d)));y.current=!0,p.filter(L=>L.status==="rejected").length>0&&u("Some sync status requests failed")}catch(p){if(p instanceof Error&&p.name==="AbortError")return;u(p instanceof Error?p.message:"Failed to fetch sync status"),y.current=!0}finally{r(!1)}},[C]),S=n.useCallback(()=>{j.current&&clearInterval(j.current),j.current=setInterval(()=>{_()},Pe)},[_]),A=n.useCallback(()=>{j.current&&(clearInterval(j.current),j.current=null)},[]);n.useEffect(()=>(_(),S(),()=>{A(),g.current&&g.current.abort()}),[_,S,A]);const a=n.useCallback(h=>{o.current.has(h)||(o.current.add(h),C(h,!y.current))},[C]),i=n.useCallback(h=>{o.current.delete(h),l(d=>{const p={...d};return delete p[h],p}),o.current.size===0&&A()},[A]),x=n.useCallback(async h=>{m(d=>({...d,[h]:!0})),u(null);try{const d=await ge(h);return C(h,!1),!d.success&&d.error&&u(d.error),d}catch(d){const p=d instanceof Error?d.message:"Push settings failed";throw u(p),d}finally{m(d=>{const p={...d};return delete p[h],p})}},[C]),b=n.useCallback(async h=>{m(d=>({...d,[h]:!0})),u(null);try{const d=await pe(h);return C(h,!1),!d.success&&d.error&&u(d.error),d}catch(d){const p=d instanceof Error?d.message:"Pull settings failed";throw u(p),d}finally{m(d=>{const p={...d};return delete p[h],p})}},[C]),w=n.useCallback(async h=>{m(d=>({...d,[h]:!0})),u(null);try{return await je(h)}catch(d){const p=d instanceof Error?d.message:"Auth sync failed";throw u(p),d}finally{m(d=>{const p={...d};return delete p[h],p})}},[]),$=n.useCallback(h=>t[h]?.authMatch,[t]),v=n.useCallback(h=>t[h]?.authDiff,[t]);return{syncStatusMap:t,loading:s,actionLoading:f,error:c,refresh:_,trackNode:a,untrackNode:i,pushSettings:x,pullSettings:b,syncAuth:w,getAuthSyncState:$,getAuthProviders:v}}function Le(t,l){return l.type==="remote"?t.nodeId===l.id:t.nodeId===l.id||t.nodeId===void 0||t.nodeId===null}function ne(t,l){return t.filter(s=>Le(s,l))}function H(t,l){return ne(t,l).length}const ze={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"}},De={match:"var(--color-success)",differs:"var(--color-warning)","not-synced":"var(--text-muted)"};function Oe(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 s=Object.entries(l).filter(([,r])=>r==="differs").map(([r])=>r);if(s.length>0)return`Auth credentials differ: ${s.join(", ")}`}return"Auth credentials differ"}function Fe(t,l=42){return t.length<=l?t:`${t.slice(0,l-3)}...`}function Ie(t,l){const s=t.node,r=l.node;if(s.id!==r.id||s.name!==r.name||s.type!==r.type||s.url!==r.url||s.status!==r.status||s.maxConcurrent!==r.maxConcurrent||s.updatedAt!==r.updatedAt||t.isLoading!==l.isLoading)return!1;const f=t.syncStatus,m=l.syncStatus;if(!(!f&&!m)){if(!f||!m)return!1;if(f.syncState!==m.syncState||f.lastSyncAt!==m.lastSyncAt||f.diffCount!==m.diffCount)return!1}if(t.authSyncState!==l.authSyncState)return!1;const c=t.authSyncProviders,u=l.authSyncProviders;if(c!==u){if(!c||!u)return!1;{const g=Object.keys(c),j=Object.keys(u);if(g.length!==j.length||g.some(C=>c[C]!==u[C]))return!1}}const o=H(t.projects,s),y=H(l.projects,r);return o===y}function Ke({node:t,projects:l,onHealthCheck:s,onEdit:r,onRemove:f,isLoading:m=!1,syncStatus:c,authSyncState:u,authSyncProviders:o}){const[y,g]=n.useState(!1),j=ze[t.status],C=n.useMemo(()=>H(l,t),[l,t]),_=n.useCallback(()=>{r(t)},[r,t]),S=n.useCallback(x=>{x.stopPropagation(),s(t.id)},[s,t.id]),A=n.useCallback(x=>{x.stopPropagation(),r(t)},[r,t]),a=n.useCallback(x=>{if(x.stopPropagation(),!y){g(!0);return}f(t.id),g(!1)},[y,f,t.id]),i=n.useCallback(x=>{(x.key==="Enter"||x.key===" ")&&(x.preventDefault(),r(t))},[r,t]);return e.jsxs("article",{className:`node-card ${m?"node-card--loading":""}`,"data-node-id":t.id,role:"button",tabIndex:0,onClick:_,onKeyDown:i,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(Z,{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"}),e.jsxs("span",{className:`node-card__status ${j.className}`,style:{color:j.color},"data-status":t.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:j.color},"aria-hidden":!0}),j.label]}),t.type==="remote"&&u&&e.jsx("span",{className:`node-card__auth-indicator node-card__auth-indicator--${u}`,title:Oe(u,o),"aria-label":`Auth sync: ${u==="match"?"credentials match":u==="differs"?"credentials differ":"not synced"}`,style:{color:De[u]},children:e.jsx(Q,{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:Fe(t.url)}),e.jsxs("div",{className:"node-card__metrics",children:[e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Projects"}),e.jsx("span",{className:"node-card__metric-value",children:C})]}),e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Concurrency"}),e.jsx("span",{className:"node-card__metric-value",children:t.maxConcurrent})]})]}),t.type==="remote"&&c&&e.jsxs("div",{className:"node-card__sync","data-sync-state":c.syncState,"data-testid":"node-card-sync",children:[e.jsx("span",{className:"node-card__sync-dot",style:{backgroundColor:ae(c.syncState)},"aria-hidden":!0}),e.jsx("span",{className:"node-card__sync-time",children:te(c.lastSyncAt)})]})]}),e.jsxs("footer",{className:"node-card__actions",children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:S,disabled:m,"aria-label":"Run node health check",title:"Health Check",children:[e.jsx(T,{size:14}),e.jsx("span",{children:"Health"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:A,disabled:m,"aria-label":"Edit node",title:"Edit",children:[e.jsx(_e,{size:14}),e.jsx("span",{children:"Edit"})]}),e.jsxs("button",{className:`btn btn-sm node-card__action node-card__action--remove ${y?"btn-danger is-armed":""}`,type:"button",onClick:a,disabled:m,"aria-label":y?"Confirm remove node":"Remove node",title:y?"Confirm remove":"Remove",children:[e.jsx(Ne,{size:14}),e.jsx("span",{children:y?"Confirm":"Remove"})]})]})]})}const Ue=n.memo(Ke,Ie),O={online:"var(--success, var(--color-success))",offline:"var(--text-dim)",connecting:"var(--triage)",error:"var(--color-error)"},D=28,W=12,Ve=300,Be=120;function He({nodes:t,className:l}){const s=n.useMemo(()=>t.find(o=>o.type==="local")??t[0],[t]),r=n.useMemo(()=>t.filter(o=>o.type==="remote"),[t]),f=n.useMemo(()=>{const o=Ve,y=Math.max(0,r.length-4)*20;return o+y},[r.length]),m=f/2,c=f/2,u=n.useMemo(()=>{if(r.length===0)return[];const o=Math.min(Be,f/2-D-10),y=2*Math.PI/r.length,g=-Math.PI/2;return r.map((j,C)=>{const _=g+C*y;return{node:j,x:m+o*Math.cos(_),y:c+o*Math.sin(_)}})},[r,f,m,c]);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 ${f} ${f}`,preserveAspectRatio:"xMidYMid meet","aria-label":"Node mesh topology visualization",children:[u.map(o=>e.jsx("line",{className:"mesh-topology__link",x1:m,y1:c,x2:o.x,y2:o.y},`link-${o.node.id}`)),s&&e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${m}, ${c})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:D,fill:O[s.status],"aria-label":`${s.name} (${s.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:D+W,textAnchor:"middle",children:s.name.length>12?`${s.name.slice(0,10)}…`:s.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-D-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:s.type==="local"?"L":"R"})]})]}),u.map(o=>e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${o.x}, ${o.y})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:D,fill:O[o.node.status],"aria-label":`${o.node.name} (${o.node.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:D+W,textAnchor:"middle",children:o.node.name.length>12?`${o.node.name.slice(0,10)}…`:o.node.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-D-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:o.node.type==="local"?"L":"R"})]})]},o.node.id))]}),e.jsxs("div",{className:"mesh-topology__legend",children:[e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:O.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:O.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:O.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:O.error}}),e.jsx("span",{children:"Error"})]})]}),e.jsx("p",{className:"mesh-topology__notice",children:"Peer-to-peer discovery data unavailable."})]})}const qe=n.memo(He),q=1,J=10;function Je(t){const l={};return 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<q||t.maxConcurrent>J)&&(l.maxConcurrent=`Concurrency must be between ${q} and ${J}`),l}function Xe({isOpen:t,onClose:l,onSubmit:s,addToast:r}){const[f,m]=n.useState(""),[c,u]=n.useState("local"),[o,y]=n.useState(""),[g,j]=n.useState(""),[C,_]=n.useState(2),[S,A]=n.useState({}),[a,i]=n.useState(!1),x=n.useCallback(()=>{m(""),u("local"),y(""),j(""),_(2),A({}),i(!1)},[]),b=n.useCallback(()=>{a||(x(),l())},[a,l,x]);n.useEffect(()=>{if(!t){x();return}const v=h=>{h.key==="Escape"&&(h.preventDefault(),b())};return document.addEventListener("keydown",v),()=>{document.removeEventListener("keydown",v)}},[b,t,x]);const w=n.useMemo(()=>({name:f.trim(),type:c,url:c==="remote"&&o.trim()||void 0,apiKey:c==="remote"&&g||void 0,maxConcurrent:C}),[g,C,f,c,o]),$=n.useCallback(async()=>{if(a)return;const v=Je(w);if(A(v),!(Object.keys(v).length>0)){i(!0);try{await s(w),r(`Node "${w.name}" registered`,"success"),b()}catch(h){const d=h instanceof Error?h.message:"Failed to register node";r(d,"error")}finally{i(!1)}}},[r,b,w,a,s]);return t?e.jsx("div",{className:"modal-overlay open",onClick:b,children:e.jsxs("div",{className:"modal modal-md add-node-modal",onClick:v=>v.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:b,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 a node to distribute task execution across machines."}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Name"}),e.jsx("input",{className:"input",type:"text",value:f,onChange:v=>m(v.target.value),placeholder:"Build Machine",disabled:a,"aria-invalid":!!S.name,autoFocus:!0}),S.name&&e.jsx("span",{className:"form-error add-node-modal__error",children:S.name})]}),e.jsxs("div",{className:"add-node-modal__type-toggle",children:[e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${c==="local"?"active":""}`,"data-type":"local",onClick:()=>u("local"),disabled:a,"aria-pressed":c==="local",children:"Local"}),e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${c==="remote"?"active":""}`,"data-type":"remote",onClick:()=>u("remote"),disabled:a,"aria-pressed":c==="remote",children:"Remote"})]}),e.jsxs("div",{className:"add-node-modal__remote-fields","data-testid":"remote-fields-container","data-visible":c==="remote",children:[e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"URL"}),e.jsx("input",{className:"input",type:"text",value:o,onChange:v=>y(v.target.value),placeholder:"https://node.example.com",disabled:a,"aria-invalid":!!S.url}),S.url&&e.jsx("span",{className:"form-error add-node-modal__error",children:S.url})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:g,onChange:v=>j(v.target.value),placeholder:"Optional",disabled:a})]})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),e.jsx("input",{className:"input",type:"number",min:q,max:J,value:C,onChange:v=>_(Number(v.target.value)),disabled:a,"aria-invalid":!!S.maxConcurrent}),e.jsx("span",{className:"add-node-modal__hint",children:"Max simultaneous task agents (1–10)"}),S.maxConcurrent&&e.jsx("span",{className:"form-error add-node-modal__error",children:S.maxConcurrent})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:b,disabled:a,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm","data-testid":"add-node-submit",onClick:$,disabled:a,children:a?"Adding...":"Add Node"})]})]})}):null}function Ge({nodeId:t,entries:l,loading:s=!1,singleNode:r=!1}){const[f,m]=n.useState(!1),[c,u]=n.useState("all"),[o,y]=n.useState("all"),g=n.useCallback(()=>{m(a=>!a)},[]),j=n.useMemo(()=>{const a=new Set;for(const i of l)a.add(i.nodeName);return Array.from(a).sort()},[l]),C=n.useMemo(()=>{let a=[...l];return c!=="all"&&(a=a.filter(i=>i.direction===c)),!r&&o!=="all"&&(a=a.filter(i=>i.nodeName===o)),a.sort((i,x)=>{const b=new Date(i.timestamp).getTime();return new Date(x.timestamp).getTime()-b}),a},[l,c,o,r]),_=n.useCallback(a=>new Date(a).toLocaleString(),[]),S=n.useCallback(a=>{switch(a){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""}},[]),A=n.useCallback(a=>{switch(a){case"success":return"Success";case"conflict":return"Conflict";case"error":return"Error";default:return a}},[]);return e.jsxs("div",{className:"settings-sync-log",children:[e.jsxs("button",{className:"settings-sync-log__header",type:"button",onClick:g,"aria-expanded":f,"data-testid":"settings-sync-log-header",children:[e.jsx(be,{size:16,className:`settings-sync-log__chevron ${f?"settings-sync-log__chevron--expanded":""}`}),e.jsxs("span",{children:[l.length," ",l.length===1?"entry":"entries"]})]}),f&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-sync-log__filters",children:[e.jsxs("label",{children:["Direction:",e.jsxs("select",{value:c,onChange:a=>u(a.target.value),children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"push",children:"Push"}),e.jsx("option",{value:"pull",children:"Pull"})]})]}),!r&&e.jsxs("label",{children:["Node:",e.jsxs("select",{value:o,onChange:a=>y(a.target.value),children:[e.jsx("option",{value:"all",children:"All Nodes"}),j.map(a=>e.jsx("option",{value:a,children:a},a))]})]})]}),s&&l.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"Loading..."}):C.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"No sync history available"}):e.jsx("div",{className:"settings-sync-log__list",children:C.map(a=>e.jsxs("div",{className:"settings-sync-log__entry",children:[e.jsx("span",{className:"settings-sync-log__entry-timestamp",children:_(a.timestamp)}),e.jsx("span",{className:"settings-sync-log__entry-direction",children:a.direction==="push"?e.jsx(se,{size:14,"data-testid":"upload-icon"}):e.jsx(ee,{size:14,"data-testid":"download-icon"})}),e.jsx("span",{className:`settings-sync-log__entry-result ${S(a.result)}`,children:A(a.result)}),!r&&e.jsx("span",{className:"settings-sync-log__entry-node",children:a.nodeName}),a.details&&e.jsx("span",{className:"settings-sync-log__entry-details",title:a.details,children:a.details})]},a.id))})]})]})}function We(t,l){const s=typeof t=="string"?t:JSON.stringify(t,null,2),r=typeof l=="string"?l:JSON.stringify(l,null,2);if(s===r)return s;const f=s.split(`
12
12
  `),m=r.split(`
13
13
  `),c=[],u=Math.max(f.length,m.length);for(let o=0;o<u;o++){const y=f[o],g=m[o];y!==void 0&&y!==g&&c.push(`- ${y}`),g!==void 0&&g!==y&&c.push(`+ ${g}`),y!==void 0&&y===g&&c.push(` ${y}`)}return c.join(`
14
- `)}function We({isOpen:t,onClose:l,onResolve:s,conflicts:r,localNodeName:f,remoteNodeName:m,addToast:c}){const[u,o]=n.useState({}),[y,g]=n.useState(!1);n.useEffect(()=>{const a={};for(const i of r)u[i.key]||(a[i.key]={resolution:"local"});Object.keys(a).length>0&&o(i=>({...i,...a}))},[r,u]),n.useEffect(()=>{if(!t)return;const a=i=>{i.key==="Escape"&&(i.preventDefault(),l())};return document.addEventListener("keydown",a),()=>document.removeEventListener("keydown",a)},[t,l]);const j=n.useCallback((a,i)=>{o(x=>{const b=x[a]??{};return i==="manual"?{...x,[a]:{resolution:"manual",manualValue:b.manualValue??JSON.stringify(r.find(w=>w.key===a)?.localValue??null,null,2)}}:{...x,[a]:{resolution:i}}})},[r]),C=n.useCallback((a,i)=>{o(x=>({...x,[a]:{...x[a],resolution:"manual",manualValue:i}}))},[]),_=n.useCallback(a=>{const i={};for(const x of r)i[x.key]={resolution:a};o(i)},[r]),S=n.useCallback(async()=>{g(!0);try{const a=r.map(i=>{const x=u[i.key]??{resolution:"local"};let b;switch(x.resolution){case"remote":b=i.remoteValue;break;case"manual":try{b=JSON.parse(x.manualValue??"null")}catch{b=x.manualValue??null}break;case"local":default:b=i.localValue;break}return{key:i.key,value:b}});await s(a),c("Settings conflicts resolved successfully","success"),l()}catch(a){const i=a instanceof Error?a.message:"Failed to resolve conflicts";c(i,"error")}finally{g(!1)}},[c,r,l,s,u]),M=n.useMemo(()=>{const a={};for(const i of r)a[i.key]=Ye(i.localValue,i.remoteValue);return a},[r]);return!t||r.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:a=>a.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:r.map(a=>{const i=u[a.key]??{resolution:"local"},x=M[a.key];return e.jsxs("div",{className:"settings-sync-conflict-modal__conflict-item",children:[e.jsx("div",{className:"settings-sync-conflict-modal__key",children:a.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:f}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:x})})]}),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:x})})]})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__resolution",children:[e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${a.key}`,checked:i.resolution==="local",onChange:()=>j(a.key,"local")}),"Keep Local"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${a.key}`,checked:i.resolution==="remote",onChange:()=>j(a.key,"remote")}),"Keep Remote"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${a.key}`,checked:i.resolution==="manual",onChange:()=>j(a.key,"manual")}),"Merge Manually"]})]}),i.resolution==="manual"&&e.jsx("textarea",{className:"settings-sync-conflict-modal__manual-input",value:i.manualValue??"",onChange:b=>C(a.key,b.target.value),placeholder:"Enter JSON value..."})]},a.key)})}),e.jsxs("div",{className:"settings-sync-conflict-modal__bulk-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>_("local"),type:"button",children:"Resolve All: Keep Local"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>_("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:S,disabled:y,children:y?"Resolving...":"Confirm"})]})]})})}function B(t){if(!t)return"—";const l=new Date(t);return Number.isNaN(l.getTime())?"—":l.toLocaleString()}function Ze({isOpen:t,onClose:l,node:s,projects:r,onUpdate:f,onHealthCheck:m,addToast:c,syncStatus:u,onPushSettings:o,onPullSettings:y,onSyncAuth:g,syncHistory:j=[],onResolveConflicts:C}){const _=n.useRef(!0),[S,M]=n.useState(!1),[a,i]=n.useState(""),[x,b]=n.useState(""),[w,$]=n.useState(""),[v,h]=n.useState(2),[d,p]=n.useState(!1),[z,L]=n.useState(!1),[k,A]=n.useState(!1),[P,F]=n.useState(!1),[I,E]=n.useState(null),[le,re]=n.useState(!1),[ce]=n.useState([]);n.useEffect(()=>(_.current=!0,()=>{_.current=!1}),[]),n.useEffect(()=>{if(!s||!t){M(!1);return}i(s.name),b(s.url??""),$(s.apiKey??""),h(s.maxConcurrent),M(!1)},[t,s]),n.useEffect(()=>{if(!t)return;const N=R=>{R.key==="Escape"&&(R.preventDefault(),l())};return document.addEventListener("keydown",N),()=>document.removeEventListener("keydown",N)},[t,l]);const K=n.useMemo(()=>s?ne(r,s):[],[s,r]),oe=n.useCallback(async()=>{if(s)try{if(await m(s.id),!_.current)return;c(`Health check completed for ${s.name}`,"success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Health check failed";c(R,"error")}},[c,s,m]),ie=n.useCallback(async()=>{if(!(!s||!o)){E(null),L(!0);try{if(await o(s.id),!_.current)return;c("Settings pushed successfully","success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Push settings failed";E(R),c(R,"error")}finally{_.current&&L(!1)}}},[c,s,o]),de=n.useCallback(async()=>{if(!(!s||!y)){E(null),A(!0);try{if(await y(s.id),!_.current)return;c("Settings pulled successfully","success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Pull settings failed";E(R),c(R,"error")}finally{_.current&&A(!1)}}},[c,s,y]),ue=n.useCallback(async()=>{if(!(!s||!g)){E(null),F(!0);try{if(await g(s.id),!_.current)return;c("Auth credentials synced successfully","success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Auth sync failed";E(R),c(R,"error")}finally{_.current&&F(!1)}}},[c,s,g]),me=n.useCallback(()=>{E(null)},[]),he=n.useCallback(async()=>{if(!s||d)return;const N=a.trim();if(!N){c("Name is required","error");return}if(s.type==="remote"&&!x.trim()){c("URL is required for remote nodes","error");return}if(!Number.isFinite(v)||v<1){c("Concurrency must be at least 1","error");return}p(!0);try{await f(s.id,{name:N,url:s.type==="remote"&&x.trim()||void 0,apiKey:s.type==="remote"&&w||void 0,maxConcurrent:v}),c(`Updated ${N}`,"success"),M(!1)}catch(R){const ye=R instanceof Error?R.message:"Failed to update node";c(ye,"error")}finally{p(!1)}},[c,w,d,v,a,s,f,x]),fe=n.useCallback(()=>{s&&(i(s.name),b(s.url??""),$(s.apiKey??""),h(s.maxConcurrent),M(!1))},[s]);return!t||!s?null:e.jsxs("div",{className:"modal-overlay open",onClick:l,children:[e.jsxs("div",{className:"modal modal-lg node-detail-modal",onClick:N=>N.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":`Node details for ${s.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"}),!S&&e.jsxs("button",{className:"btn btn-sm",onClick:()=>M(!0),children:[e.jsx(ve,{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"}),S?e.jsx("input",{className:"input",value:a,onChange:N=>i(N.target.value),disabled:d}):e.jsx("strong",{children:s.name})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Type"}),e.jsx("strong",{children:s.type==="local"?"Local":"Remote"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Status"}),e.jsx("strong",{children:s.status})]}),e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),S?e.jsx("input",{className:"input",type:"number",min:1,max:10,value:v,onChange:N=>h(Number(N.target.value)),disabled:d}):e.jsx("strong",{children:s.maxConcurrent})]}),s.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"}),S?e.jsx("input",{className:"input",value:x,onChange:N=>b(N.target.value),disabled:d}):e.jsx("strong",{children:s.url??"—"})]}),e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"API Key"}),S?e.jsx("input",{className:"input",type:"password",value:w,onChange:N=>$(N.target.value),placeholder:"Leave blank to keep unchanged",disabled:d}):e.jsx("strong",{children:s.apiKey?"••••••••":"Not configured"})]})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Created"}),e.jsx("strong",{children:B(s.createdAt)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Updated"}),e.jsx("strong",{children:B(s.updatedAt)})]})]}),S&&e.jsxs("div",{className:"node-detail-modal__edit-actions",children:[e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:he,disabled:d,children:[e.jsx(Ce,{size:14}),d?"Saving...":"Save"]}),e.jsxs("button",{className:"btn btn-sm",onClick:fe,disabled:d,children:[e.jsx(V,{size:14}),"Cancel"]})]})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsxs("h4",{children:[s.type==="local"?"Projects":"Assigned Projects"," (",K.length,")"]}),K.length===0?e.jsx("p",{className:"node-detail-modal__empty",children:s.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:K.map(N=>e.jsxs("li",{className:"node-detail-modal__project-item",children:[e.jsx("span",{children:N.name}),e.jsx("code",{children:N.id})]},N.id))})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Health"}),e.jsxs("div",{className:"node-detail-modal__health-row",children:[e.jsxs("span",{children:["Status: ",e.jsx("strong",{children:s.status})]}),e.jsxs("span",{children:["Last check: ",e.jsx("strong",{children:B(s.updatedAt)})]})]})]}),s.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Settings Sync"}),u&&e.jsxs("div",{className:"node-detail-modal__sync-status",children:[e.jsx("span",{className:"node-detail-modal__sync-dot",style:{backgroundColor:ae(u.syncState)},"aria-hidden":!0}),e.jsxs("span",{children:["Last sync:"," ",e.jsx("strong",{children:u.lastSyncAt?te(u.lastSyncAt):"Never synced"})]}),u.diffCount>0&&e.jsxs("span",{className:"node-detail-modal__sync-diff",children:["Differences: ",e.jsx("strong",{children:u.diffCount})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:ie,disabled:z||!o,children:[e.jsx(se,{size:14}),z?"Pushing...":"Push Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:de,disabled:k||!y,children:[e.jsx(ee,{size:14}),k?"Pulling...":"Pull Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:ue,disabled:P||!g,children:[e.jsx(Q,{size:14}),P?"Syncing...":"Sync Auth"]})]}),I&&e.jsxs("div",{className:"node-detail-modal__sync-error",children:[e.jsx("span",{children:I}),e.jsx("button",{className:"node-detail-modal__sync-error-dismiss",onClick:me,"aria-label":"Dismiss error",children:e.jsx(V,{size:14})})]})]}),s.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Sync History"}),e.jsx(Ge,{nodeId:s.id,entries:j,singleNode:!0})]})]}),e.jsxs("div",{className:"modal-actions node-detail-modal__actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:oe,children:[e.jsx(T,{size:14}),"Health Check"]}),e.jsx("button",{className:"btn btn-sm",onClick:l,children:"Close"})]})]}),s.type==="remote"&&e.jsx(We,{isOpen:le,onClose:()=>re(!1),onResolve:C??(async()=>{}),conflicts:ce,localNodeName:"Local",remoteNodeName:s.name,addToast:c})]})}function ts({addToast:t,onClose:l}){const{nodes:s,loading:r,error:f,refresh:m,register:c,update:u,unregister:o,healthCheck:y}=ke(),{projects:g}=Se(),{syncStatusMap:j,pushSettings:C,pullSettings:_,syncAuth:S,trackNode:M,getAuthSyncState:a,getAuthProviders:i}=$e(),[x,b]=n.useState(!1),[w,$]=n.useState(null);n.useEffect(()=>{const k=s.filter(A=>A.type==="remote");for(const A of k)M(A.id)},[s,M]),n.useEffect(()=>{if(!w)return;const k=s.find(A=>A.id===w.id)??null;$(k)},[s,w]);const v=n.useMemo(()=>{const k=s.length,A=s.filter(E=>E.status==="online").length,P=s.filter(E=>E.status==="offline"||E.status==="error").length,F=s.filter(E=>E.type==="remote").length,I=s.filter(E=>E.type==="remote"&&j[E.id]&&U(j[E.id]).syncState==="synced").length;return{total:k,online:A,offline:P,remote:F,synced:I}},[s,j]),h=n.useCallback(async k=>{await c(k)},[c]),d=n.useCallback(async()=>{try{await m()}catch{t("Failed to refresh nodes","error")}},[t,m]),p=n.useCallback(async k=>{try{await y(k),t("Node health check complete","success")}catch(A){const P=A instanceof Error?A.message:"Health check failed";t(P,"error")}},[t,y]),z=n.useCallback(async k=>{try{await o(k),t("Node removed","success"),w?.id===k&&$(null)}catch(A){const P=A instanceof Error?A.message:"Failed to remove node";t(P,"error")}},[t,w?.id,o]),L=n.useCallback(async(k,A)=>{await u(k,A)},[u]);return e.jsxs("div",{className:"nodes-view","data-testid":"nodes-view",children:[e.jsxs("div",{className:"nodes-view-header",children:[e.jsxs("div",{className:"nodes-view-title",children:[e.jsxs("h2",{children:[e.jsx(Z,{size:20}),"Nodes"]}),e.jsxs("span",{className:"nodes-view-count",children:[s.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(V,{size:16})}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void d(),disabled:r,children:[e.jsx(J,{size:14,className:r?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>b(!0),children:[e.jsx(G,{size:14}),"Add 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:v.total})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--online","data-testid":"nodes-stat-online",children:[e.jsxs("span",{children:[e.jsx(Re,{size:14})," Online"]}),e.jsx("strong",{children:v.online})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--offline","data-testid":"nodes-stat-offline",children:[e.jsxs("span",{children:[e.jsx(Ae,{size:14})," Offline"]}),e.jsx("strong",{children:v.offline})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-remote",children:[e.jsxs("span",{children:[e.jsx(we,{size:14})," Remote"]}),e.jsx("strong",{children:v.remote})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--synced","data-testid":"nodes-stat-synced",children:[e.jsxs("span",{children:[e.jsx(J,{size:14})," Synced"]}),e.jsx("strong",{children:v.synced})]})]}),f&&e.jsx("div",{className:"nodes-view-error",children:f}),!r&&s.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(qe,{nodes:s})]}),r?e.jsx("div",{className:"nodes-view-grid",children:Array.from({length:4}).map((k,A)=>e.jsx("div",{className:"node-card node-card--loading","aria-hidden":!0},A))}):s.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:()=>b(!0),children:[e.jsx(G,{size:14}),"Add First Node"]})]}):e.jsx("div",{className:"nodes-view-grid",children:s.map(k=>{const A=k.type==="remote"&&j[k.id]?U(j[k.id]):void 0;return e.jsx(Ue,{node:k,projects:g,onHealthCheck:P=>{p(P)},onEdit:P=>$(P),onRemove:P=>{z(P)},isLoading:r,syncStatus:A,authSyncState:k.type==="remote"?a(k.id):void 0,authSyncProviders:k.type==="remote"?i(k.id):void 0},k.id)})}),e.jsx(Je,{isOpen:x,onClose:()=>b(!1),onSubmit:h,addToast:t}),e.jsx(Ze,{isOpen:w!==null,onClose:()=>$(null),node:w,projects:g,onUpdate:L,onHealthCheck:p,addToast:t,syncStatus:w?.type==="remote"&&w&&j[w.id]?U(j[w.id]):void 0,onPushSettings:C,onPullSettings:_,onSyncAuth:S})]})}export{ts as NodesView};
14
+ `)}function Ye({isOpen:t,onClose:l,onResolve:s,conflicts:r,localNodeName:f,remoteNodeName:m,addToast:c}){const[u,o]=n.useState({}),[y,g]=n.useState(!1);n.useEffect(()=>{const a={};for(const i of r)u[i.key]||(a[i.key]={resolution:"local"});Object.keys(a).length>0&&o(i=>({...i,...a}))},[r,u]),n.useEffect(()=>{if(!t)return;const a=i=>{i.key==="Escape"&&(i.preventDefault(),l())};return document.addEventListener("keydown",a),()=>document.removeEventListener("keydown",a)},[t,l]);const j=n.useCallback((a,i)=>{o(x=>{const b=x[a]??{};return i==="manual"?{...x,[a]:{resolution:"manual",manualValue:b.manualValue??JSON.stringify(r.find(w=>w.key===a)?.localValue??null,null,2)}}:{...x,[a]:{resolution:i}}})},[r]),C=n.useCallback((a,i)=>{o(x=>({...x,[a]:{...x[a],resolution:"manual",manualValue:i}}))},[]),_=n.useCallback(a=>{const i={};for(const x of r)i[x.key]={resolution:a};o(i)},[r]),S=n.useCallback(async()=>{g(!0);try{const a=r.map(i=>{const x=u[i.key]??{resolution:"local"};let b;switch(x.resolution){case"remote":b=i.remoteValue;break;case"manual":try{b=JSON.parse(x.manualValue??"null")}catch{b=x.manualValue??null}break;case"local":default:b=i.localValue;break}return{key:i.key,value:b}});await s(a),c("Settings conflicts resolved successfully","success"),l()}catch(a){const i=a instanceof Error?a.message:"Failed to resolve conflicts";c(i,"error")}finally{g(!1)}},[c,r,l,s,u]),A=n.useMemo(()=>{const a={};for(const i of r)a[i.key]=We(i.localValue,i.remoteValue);return a},[r]);return!t||r.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:a=>a.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:r.map(a=>{const i=u[a.key]??{resolution:"local"},x=A[a.key];return e.jsxs("div",{className:"settings-sync-conflict-modal__conflict-item",children:[e.jsx("div",{className:"settings-sync-conflict-modal__key",children:a.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:f}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:x})})]}),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:x})})]})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__resolution",children:[e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${a.key}`,checked:i.resolution==="local",onChange:()=>j(a.key,"local")}),"Keep Local"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${a.key}`,checked:i.resolution==="remote",onChange:()=>j(a.key,"remote")}),"Keep Remote"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${a.key}`,checked:i.resolution==="manual",onChange:()=>j(a.key,"manual")}),"Merge Manually"]})]}),i.resolution==="manual"&&e.jsx("textarea",{className:"settings-sync-conflict-modal__manual-input",value:i.manualValue??"",onChange:b=>C(a.key,b.target.value),placeholder:"Enter JSON value..."})]},a.key)})}),e.jsxs("div",{className:"settings-sync-conflict-modal__bulk-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>_("local"),type:"button",children:"Resolve All: Keep Local"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>_("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:S,disabled:y,children:y?"Resolving...":"Confirm"})]})]})})}function V(t){if(!t)return"—";const l=new Date(t);return Number.isNaN(l.getTime())?"—":l.toLocaleString()}function Ze({isOpen:t,onClose:l,node:s,projects:r,onUpdate:f,onHealthCheck:m,addToast:c,syncStatus:u,onPushSettings:o,onPullSettings:y,onSyncAuth:g,syncHistory:j=[],onResolveConflicts:C}){const _=n.useRef(!0),[S,A]=n.useState(!1),[a,i]=n.useState(""),[x,b]=n.useState(""),[w,$]=n.useState(""),[v,h]=n.useState(2),[d,p]=n.useState(!1),[z,L]=n.useState(!1),[k,M]=n.useState(!1),[P,F]=n.useState(!1),[I,E]=n.useState(null),[le,re]=n.useState(!1),[ce]=n.useState([]);n.useEffect(()=>(_.current=!0,()=>{_.current=!1}),[]),n.useEffect(()=>{if(!s||!t){A(!1);return}i(s.name),b(s.url??""),$(s.apiKey??""),h(s.maxConcurrent),A(!1)},[t,s]),n.useEffect(()=>{if(!t)return;const N=R=>{R.key==="Escape"&&(R.preventDefault(),l())};return document.addEventListener("keydown",N),()=>document.removeEventListener("keydown",N)},[t,l]);const K=n.useMemo(()=>s?ne(r,s):[],[s,r]),oe=n.useCallback(async()=>{if(s)try{if(await m(s.id),!_.current)return;c(`Health check completed for ${s.name}`,"success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Health check failed";c(R,"error")}},[c,s,m]),ie=n.useCallback(async()=>{if(!(!s||!o)){E(null),L(!0);try{if(await o(s.id),!_.current)return;c("Settings pushed successfully","success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Push settings failed";E(R),c(R,"error")}finally{_.current&&L(!1)}}},[c,s,o]),de=n.useCallback(async()=>{if(!(!s||!y)){E(null),M(!0);try{if(await y(s.id),!_.current)return;c("Settings pulled successfully","success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Pull settings failed";E(R),c(R,"error")}finally{_.current&&M(!1)}}},[c,s,y]),ue=n.useCallback(async()=>{if(!(!s||!g)){E(null),F(!0);try{if(await g(s.id),!_.current)return;c("Auth credentials synced successfully","success")}catch(N){if(!_.current)return;const R=N instanceof Error?N.message:"Auth sync failed";E(R),c(R,"error")}finally{_.current&&F(!1)}}},[c,s,g]),me=n.useCallback(()=>{E(null)},[]),he=n.useCallback(async()=>{if(!s||d)return;const N=a.trim();if(!N){c("Name is required","error");return}if(s.type==="remote"&&!x.trim()){c("URL is required for remote nodes","error");return}if(!Number.isFinite(v)||v<1){c("Concurrency must be at least 1","error");return}p(!0);try{await f(s.id,{name:N,url:s.type==="remote"&&x.trim()||void 0,apiKey:s.type==="remote"&&w||void 0,maxConcurrent:v}),c(`Updated ${N}`,"success"),A(!1)}catch(R){const ye=R instanceof Error?R.message:"Failed to update node";c(ye,"error")}finally{p(!1)}},[c,w,d,v,a,s,f,x]),fe=n.useCallback(()=>{s&&(i(s.name),b(s.url??""),$(s.apiKey??""),h(s.maxConcurrent),A(!1))},[s]);return!t||!s?null:e.jsxs("div",{className:"modal-overlay open",onClick:l,children:[e.jsxs("div",{className:"modal modal-lg node-detail-modal",onClick:N=>N.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":`Node details for ${s.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"}),!S&&e.jsxs("button",{className:"btn btn-sm",onClick:()=>A(!0),children:[e.jsx(ve,{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"}),S?e.jsx("input",{className:"input",value:a,onChange:N=>i(N.target.value),disabled:d}):e.jsx("strong",{children:s.name})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Type"}),e.jsx("strong",{children:s.type==="local"?"Local":"Remote"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Status"}),e.jsx("strong",{children:s.status})]}),e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),S?e.jsx("input",{className:"input",type:"number",min:1,max:10,value:v,onChange:N=>h(Number(N.target.value)),disabled:d}):e.jsx("strong",{children:s.maxConcurrent})]}),s.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"}),S?e.jsx("input",{className:"input",value:x,onChange:N=>b(N.target.value),disabled:d}):e.jsx("strong",{children:s.url??"—"})]}),e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"API Key"}),S?e.jsx("input",{className:"input",type:"password",value:w,onChange:N=>$(N.target.value),placeholder:"Leave blank to keep unchanged",disabled:d}):e.jsx("strong",{children:s.apiKey?"••••••••":"Not configured"})]})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Created"}),e.jsx("strong",{children:V(s.createdAt)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Updated"}),e.jsx("strong",{children:V(s.updatedAt)})]})]}),S&&e.jsxs("div",{className:"node-detail-modal__edit-actions",children:[e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:he,disabled:d,children:[e.jsx(Ce,{size:14}),d?"Saving...":"Save"]}),e.jsxs("button",{className:"btn btn-sm",onClick:fe,disabled:d,children:[e.jsx(B,{size:14}),"Cancel"]})]})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsxs("h4",{children:[s.type==="local"?"Projects":"Assigned Projects"," (",K.length,")"]}),K.length===0?e.jsx("p",{className:"node-detail-modal__empty",children:s.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:K.map(N=>e.jsxs("li",{className:"node-detail-modal__project-item",children:[e.jsx("span",{children:N.name}),e.jsx("code",{children:N.id})]},N.id))})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Health"}),e.jsxs("div",{className:"node-detail-modal__health-row",children:[e.jsxs("span",{children:["Status: ",e.jsx("strong",{children:s.status})]}),e.jsxs("span",{children:["Last check: ",e.jsx("strong",{children:V(s.updatedAt)})]})]})]}),s.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Settings Sync"}),u&&e.jsxs("div",{className:"node-detail-modal__sync-status",children:[e.jsx("span",{className:"node-detail-modal__sync-dot",style:{backgroundColor:ae(u.syncState)},"aria-hidden":!0}),e.jsxs("span",{children:["Last sync:"," ",e.jsx("strong",{children:u.lastSyncAt?te(u.lastSyncAt):"Never synced"})]}),u.diffCount>0&&e.jsxs("span",{className:"node-detail-modal__sync-diff",children:["Differences: ",e.jsx("strong",{children:u.diffCount})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:ie,disabled:z||!o,children:[e.jsx(se,{size:14}),z?"Pushing...":"Push Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:de,disabled:k||!y,children:[e.jsx(ee,{size:14}),k?"Pulling...":"Pull Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:ue,disabled:P||!g,children:[e.jsx(Q,{size:14}),P?"Syncing...":"Sync Auth"]})]}),I&&e.jsxs("div",{className:"node-detail-modal__sync-error",children:[e.jsx("span",{children:I}),e.jsx("button",{className:"node-detail-modal__sync-error-dismiss",onClick:me,"aria-label":"Dismiss error",children:e.jsx(B,{size:14})})]})]}),s.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Sync History"}),e.jsx(Ge,{nodeId:s.id,entries:j,singleNode:!0})]})]}),e.jsxs("div",{className:"modal-actions node-detail-modal__actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:oe,children:[e.jsx(T,{size:14}),"Health Check"]}),e.jsx("button",{className:"btn btn-sm",onClick:l,children:"Close"})]})]}),s.type==="remote"&&e.jsx(Ye,{isOpen:le,onClose:()=>re(!1),onResolve:C??(async()=>{}),conflicts:ce,localNodeName:"Local",remoteNodeName:s.name,addToast:c})]})}function ts({addToast:t,onClose:l}){const{nodes:s,loading:r,error:f,refresh:m,register:c,update:u,unregister:o,healthCheck:y}=ke(),{projects:g}=Se(),{syncStatusMap:j,pushSettings:C,pullSettings:_,syncAuth:S,trackNode:A,getAuthSyncState:a,getAuthProviders:i}=$e(),[x,b]=n.useState(!1),[w,$]=n.useState(null);n.useEffect(()=>{const k=s.filter(M=>M.type==="remote");for(const M of k)A(M.id)},[s,A]),n.useEffect(()=>{if(!w)return;const k=s.find(M=>M.id===w.id)??null;$(k)},[s,w]);const v=n.useMemo(()=>{const k=s.length,M=s.filter(E=>E.status==="online").length,P=s.filter(E=>E.status==="offline"||E.status==="error").length,F=s.filter(E=>E.type==="remote").length,I=s.filter(E=>E.type==="remote"&&j[E.id]&&U(j[E.id]).syncState==="synced").length;return{total:k,online:M,offline:P,remote:F,synced:I}},[s,j]),h=n.useCallback(async k=>{await c(k)},[c]),d=n.useCallback(async()=>{try{await m()}catch{t("Failed to refresh nodes","error")}},[t,m]),p=n.useCallback(async k=>{try{await y(k),t("Node health check complete","success")}catch(M){const P=M instanceof Error?M.message:"Health check failed";t(P,"error")}},[t,y]),z=n.useCallback(async k=>{try{await o(k),t("Node removed","success"),w?.id===k&&$(null)}catch(M){const P=M instanceof Error?M.message:"Failed to remove node";t(P,"error")}},[t,w?.id,o]),L=n.useCallback(async(k,M)=>{await u(k,M)},[u]);return e.jsxs("div",{className:"nodes-view","data-testid":"nodes-view",children:[e.jsxs("div",{className:"nodes-view-header",children:[e.jsxs("div",{className:"nodes-view-title",children:[e.jsxs("h2",{children:[e.jsx(Z,{size:20}),"Nodes"]}),e.jsxs("span",{className:"nodes-view-count",children:[s.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(B,{size:16})}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void d(),disabled:r,children:[e.jsx(X,{size:14,className:r?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>b(!0),children:[e.jsx(G,{size:14}),"Add 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:v.total})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--online","data-testid":"nodes-stat-online",children:[e.jsxs("span",{children:[e.jsx(Re,{size:14})," Online"]}),e.jsx("strong",{children:v.online})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--offline","data-testid":"nodes-stat-offline",children:[e.jsxs("span",{children:[e.jsx(Me,{size:14})," Offline"]}),e.jsx("strong",{children:v.offline})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-remote",children:[e.jsxs("span",{children:[e.jsx(we,{size:14})," Remote"]}),e.jsx("strong",{children:v.remote})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--synced","data-testid":"nodes-stat-synced",children:[e.jsxs("span",{children:[e.jsx(X,{size:14})," Synced"]}),e.jsx("strong",{children:v.synced})]})]}),f&&e.jsx("div",{className:"nodes-view-error",children:f}),!r&&s.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(qe,{nodes:s})]}),r?e.jsx("div",{className:"nodes-view-grid",children:Array.from({length:4}).map((k,M)=>e.jsx("div",{className:"node-card node-card--loading","aria-hidden":!0},M))}):s.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:()=>b(!0),children:[e.jsx(G,{size:14}),"Add First Node"]})]}):e.jsx("div",{className:"nodes-view-grid",children:s.map(k=>{const M=k.type==="remote"&&j[k.id]?U(j[k.id]):void 0;return e.jsx(Ue,{node:k,projects:g,onHealthCheck:P=>{p(P)},onEdit:P=>$(P),onRemove:P=>{z(P)},isLoading:r,syncStatus:M,authSyncState:k.type==="remote"?a(k.id):void 0,authSyncProviders:k.type==="remote"?i(k.id):void 0},k.id)})}),e.jsx(Xe,{isOpen:x,onClose:()=>b(!1),onSubmit:h,addToast:t}),e.jsx(Ze,{isOpen:w!==null,onClose:()=>$(null),node:w,projects:g,onUpdate:L,onHealthCheck:p,addToast:t,syncStatus:w?.type==="remote"&&w&&j[w.id]?U(j[w.id]):void 0,onPushSettings:C,onPullSettings:_,onSyncAuth:S})]})}export{ts as NodesView};
@@ -0,0 +1,11 @@
1
+ import{r as l,j as e}from"./vendor-react-K0fH_qHe.js";import{c as A,dZ as Z,d_ as H,d$ as Q,R as $,dR as y,J as Y,W as T,N as ee,V as se,cr as L,F as _,e0 as ae,e1 as te,e2 as D,X as ie}from"./index-Bc8nfKeH.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
+ * @license lucide-react v1.7.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const 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"}]],M=A("palette",ne);/**
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 le=[["path",{d:"M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z",key:"w46dr5"}]],W=A("puzzle",le);function ce(t){return t.replace(/-/g,"-")}function re(t){return{"fusion-global":"Fusion Global","pi-global":"Pi Global","fusion-project":"Fusion Project","pi-project":"Pi Project",package:"Package"}[t]??t}function oe(t){return t.startsWith("npm:")?"npm":t.startsWith("git:")?"git":"local"}function de(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,q]=l.useState([]),[b,C]=l.useState(!0),[B,z]=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);q(s.extensions)}catch(s){t(`Failed to load extensions: ${s instanceof Error?s.message:String(s)}`,"error")}finally{C(!1)}},[t,x]),J=l.useCallback(async s=>{try{z(!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{z(!1)}},[p,x,m,t]);l.useEffect(()=>{r()},[r]),l.useEffect(()=>{m()},[m]);const K=s=>{O(i=>{const a=new Set(i);return a.has(s)?a.delete(s):a.add(s),a})},R=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)}},U=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)}},V=async s=>{if(!c)return;const i=c.packages.filter(a=>(typeof a=="string"?a:a.source)!==s);try{await D({packages:i}),t("Package removed","success"),await r()}catch(a){t(`Failed to remove package: ${a instanceof Error?a.message:String(a)}`,"error")}},X=async(s,i)=>{if(!c)return;const a=c[s].filter(n=>n!==i);try{await D({[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:()=>X(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(),R())},disabled:N}),e.jsxs("button",{className:"btn btn-primary",onClick:R,disabled:N||!h.trim(),children:[e.jsx(Y,{size:14}),N?"Installing…":"Add"]})]}),e.jsx("div",{className:"pi-ext-add-form-row",children:e.jsx("button",{className:"btn",onClick:U,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=oe(a),g=de(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:()=>K(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:()=>V(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(W,{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(L,{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(M,{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",W,"extensions"),u("Skills",L,"skills"),u("Prompts",_,"prompts"),u("Themes",M,"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--${ce(s.source)}`,children:re(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 J(s),disabled:B,"aria-label":`Toggle ${s.name}`}),e.jsx("span",{className:"toggle-slider"})]})})]},s.id))})]})]})}export{he as PiExtensionsManager};
@@ -0,0 +1 @@
1
+ import{r as u,j as s}from"./vendor-react-K0fH_qHe.js";import{w as ee,dP as se,s as ne,X as k,an as te,J as O,dQ as A,V,R as ie,dR as ae,aF as le,ch as re,dS as ce,dT as de,dU as ue,dV as oe,dW as _,ce as ge}from"./index-Bc8nfKeH.js";import{D as me}from"./DirectoryPicker-rew1y6qO.js";import"./vendor-xterm-DzcZoU0P.js";import"./folder-open-nYPrL1W3.js";const H=[{id:"fusion-plugin-hermes-runtime",name:"Hermes Runtime",path:"./plugins/fusion-plugin-hermes-runtime",experimental:!0},{id:"fusion-plugin-paperclip-runtime",name:"Paperclip Runtime",path:"./plugins/fusion-plugin-paperclip-runtime"},{id:"fusion-plugin-openclaw-runtime",name:"OpenClaw Runtime",path:"./plugins/fusion-plugin-openclaw-runtime",experimental:!0}],j={started:"var(--color-success)",loaded:"var(--color-warning)",error:"var(--color-error)",stopped:"var(--color-muted)",installed:"var(--color-info)"};function fe({addToast:l,projectId:c}){const[N,x]=u.useState([]),[S,w]=u.useState(!0),[J,f]=u.useState(!1),[b,v]=u.useState(""),[C,P]=u.useState(!1),[h,I]=u.useState(null),[i,y]=u.useState(null),[a,p]=u.useState({}),[M,R]=u.useState(!1),[$,E]=u.useState(null),{confirm:G}=ee(),o=u.useCallback(async()=>{try{w(!0);const e=await se(c);x(e)}catch(e){l(`Failed to load plugins: ${e instanceof Error?e.message:String(e)}`,"error")}finally{w(!1)}},[c,l]);u.useEffect(()=>{o()},[o]);const K=u.useRef([]);K.current=N,u.useEffect(()=>{const e=c?`?projectId=${encodeURIComponent(c)}`:"",n=g=>{try{const t=JSON.parse(g.data);if(c&&t.projectId&&t.projectId!==c)return;switch(t.transition){case"installing":case"enabled":case"disabled":case"settings-updated":x(d=>{const m=d.findIndex(r=>r.id===t.pluginId);if(m>=0){const r=[...d];return r[m]={...r[m],enabled:t.enabled,state:t.state,settings:t.settings,error:t.error},r}else return o(),d});break;case"uninstalled":x(d=>d.filter(m=>m.id!==t.pluginId));break;case"error":x(d=>{const m=d.findIndex(r=>r.id===t.pluginId);if(m>=0){const r=[...d];return r[m]={...r[m],state:t.state,error:t.error},r}return d});break}}catch{}};return ne(`/api/events${e}`,{events:{"plugin:lifecycle":n},onReconnect:()=>{o()}})},[c,o]);const z=async()=>{if(!b.trim()){l("Please enter a plugin path","error");return}try{P(!0),await _({path:b},c),l("Plugin installed successfully","success"),f(!1),v(""),await o()}catch(e){l(`Failed to install plugin: ${e instanceof Error?e.message:String(e)}`,"error")}finally{P(!1)}},Q=async e=>{try{E(e.id),await _({path:e.path},c),l(`${e.name} installed successfully`,"success"),await o()}catch(n){l(`Failed to install ${e.name}: ${n instanceof Error?n.message:String(n)}`,"error")}finally{E(null)}},F=async e=>{try{await ue(e.id,c),l(`${e.name} enabled`,"success"),await o()}catch(n){l(`Failed to enable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},U=async e=>{try{await de(e.id,c),l(`${e.name} disabled`,"success"),await o()}catch(n){l(`Failed to disable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},B=async e=>{try{I(e.id),await ce(e.id,c),l(`${e.name} reloaded`,"success"),await o()}catch(n){l(`Failed to reload plugin: ${n instanceof Error?n.message:String(n)}`,"error")}finally{I(null)}},L=async e=>{if(await G({title:"Uninstall Plugin",message:`Are you sure you want to uninstall "${e.name}"?`,danger:!0}))try{await oe(e.id,c),l(`${e.name} uninstalled`,"success"),await o(),y(null)}catch(g){l(`Failed to uninstall plugin: ${g instanceof Error?g.message:String(g)}`,"error")}},W=async e=>{y(e);try{R(!0);const n=await ge(e.id,c);p(n)}catch{p({})}finally{R(!1)}},X=async()=>{if(i)try{await re(i.id,a,c),l("Settings saved","success")}catch(e){l(`Failed to save settings: ${e instanceof Error?e.message:String(e)}`,"error")}};if(i)return s.jsxs("div",{className:"plugin-manager-detail","data-testid":"plugin-manager-detail",children:[s.jsxs("div",{className:"plugin-manager-detail-header",children:[s.jsx("button",{className:"btn-icon",onClick:()=>y(null),"aria-label":"Back to plugin list",children:s.jsx(k,{size:16})}),s.jsxs("div",{className:"plugin-detail-title",children:[s.jsx("h4",{className:"plugin-detail-name",children:i.name}),s.jsx("span",{className:"plugin-state-badge",style:{color:j[i.state]||j.installed},children:i.state})]})]}),s.jsxs("div",{className:"plugin-detail-content",children:[s.jsxs("div",{className:"plugin-detail-card",children:[i.description&&s.jsx("p",{className:"plugin-description",children:i.description}),i.author&&s.jsxs("p",{className:"plugin-detail-meta-row",children:[s.jsx("span",{className:"text-muted",children:"Author:"}),i.author]}),i.homepage&&s.jsxs("p",{className:"plugin-detail-meta-row plugin-homepage",children:[s.jsx("span",{className:"text-muted",children:"Homepage:"}),s.jsxs("a",{href:i.homepage,target:"_blank",rel:"noopener noreferrer",children:[i.homepage,s.jsx(te,{size:12})]})]}),s.jsxs("p",{className:"plugin-detail-meta-row",children:[s.jsx("span",{className:"text-muted",children:"Version:"}),i.version]})]}),s.jsxs("div",{className:"plugin-detail-card",children:[s.jsx("h5",{className:"plugin-detail-section-heading",children:"Settings"}),M?s.jsx("p",{className:"text-muted",children:"Loading..."}):i.settingsSchema&&Object.keys(i.settingsSchema).length>0?s.jsxs("div",{className:"plugin-settings-form",children:[Object.entries(i.settingsSchema).map(([e,n])=>{const g=`setting-${e}-help`;return s.jsxs("div",{className:"form-group",children:[s.jsxs("label",{htmlFor:`setting-${e}`,children:[n.label||e,n.required&&" *"]}),n.type==="string"&&!n.multiline&&s.jsx("input",{type:"text",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:n.description,"aria-describedby":n.description&&!n.required?g:void 0}),n.type==="string"&&n.multiline&&s.jsx("textarea",{id:`setting-${e}`,rows:4,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:n.description,"aria-describedby":n.description&&!n.required?g:void 0}),n.type==="password"&&s.jsx("input",{type:"password",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:n.description,"aria-describedby":n.description&&!n.required?g:void 0}),n.type==="number"&&s.jsx("input",{type:"number",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:Number(t.target.value)}),"aria-describedby":n.description&&!n.required?g:void 0}),n.type==="boolean"&&s.jsxs("label",{className:"checkbox-label",children:[s.jsx("input",{type:"checkbox",checked:a[e]??!1,onChange:t=>p({...a,[e]:t.target.checked})}),n.description]}),n.type==="enum"&&s.jsxs("select",{id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),"aria-describedby":n.description&&!n.required?g:void 0,children:[s.jsx("option",{value:"",children:"Select..."}),n.enumValues?.map(t=>s.jsx("option",{value:t,children:t},t))]}),n.type==="array"&&s.jsxs("div",{className:"plugin-settings-array",children:[a[e]?.map((t,d)=>s.jsxs("div",{className:"plugin-settings-array-item",children:[s.jsx("input",{type:n.itemType==="number"?"number":"text",value:t??"",onChange:m=>{const r=m.target.value,D=[...a[e]||[]];D[d]=n.itemType==="number"?Number(r):r,p({...a,[e]:D})}}),s.jsx("button",{className:"btn-icon",onClick:()=>{const r=[...a[e]||[]];r.splice(d,1),p({...a,[e]:r})},"aria-label":"Remove item",children:s.jsx(k,{size:14})})]},d)),s.jsxs("button",{className:"btn btn-secondary",onClick:()=>{const t=a[e]||[],d=n.itemType==="number"?0:"";p({...a,[e]:[...t,d]})},children:[s.jsx(O,{size:14})," Add Item"]})]}),n.description&&!n.required&&!n.multiline&&s.jsx("span",{id:g,className:"form-help",children:n.description})]},e)}),s.jsx("button",{className:"btn btn-primary",onClick:X,children:"Save Settings"})]}):s.jsx("p",{className:"text-muted",children:"No configurable settings."})]}),s.jsxs("div",{className:"plugin-detail-actions",children:[i.state==="started"&&s.jsxs("button",{className:"btn btn-secondary",onClick:()=>B(i),disabled:h===i.id,children:[s.jsx(A,{size:14,className:h===i.id?"spin":""}),h===i.id?"Reloading...":"Reload"]}),i.enabled?s.jsx("button",{className:"btn btn-secondary",onClick:()=>U(i),children:"Disable"}):s.jsx("button",{className:"btn btn-primary",onClick:()=>F(i),children:"Enable"}),s.jsxs("button",{className:"btn btn-danger",onClick:()=>L(i),children:[s.jsx(V,{size:14})," Uninstall"]})]})]})]});const Y=new Set(N.map(e=>e.id)),Z=new Set(H.map(e=>e.id)),q=N.filter(e=>!Z.has(e.id)),T=()=>s.jsxs("section",{className:"plugin-bundled-runtime-section","aria-label":"Bundled Runtime Plugins",children:[s.jsxs("div",{className:"plugin-bundled-runtime-header",children:[s.jsx("h4",{className:"plugin-bundled-runtime-heading",children:"Bundled Runtime Plugins"}),s.jsx("p",{className:"plugin-bundled-runtime-description",children:"Install Fusion's bundled runtimes directly from this screen."})]}),s.jsx("div",{className:"plugin-bundled-runtime-list","aria-label":"Bundled runtime plugin recommendations",children:H.map(e=>{const n=Y.has(e.id);return s.jsxs("div",{className:"plugin-bundled-runtime-item",children:[s.jsxs("div",{className:"plugin-bundled-runtime-meta",children:[s.jsx("span",{className:"plugin-bundled-runtime-name",children:e.name}),e.experimental&&s.jsx("span",{className:"plugin-bundled-runtime-badge",children:"Experimental"}),s.jsx("span",{className:`plugin-bundled-runtime-status ${n?"plugin-bundled-runtime-status--installed":"plugin-bundled-runtime-status--available"}`,children:n?"Installed":"Not installed"})]}),s.jsx("button",{className:`btn ${n?"btn-secondary":"btn-primary"} btn-sm`,onClick:()=>Q(e),disabled:n||$===e.id,children:n?"Installed":$===e.id?"Installing...":`Install ${e.name}`})]},e.id)})})]});return s.jsxs("div",{className:"plugin-manager","data-testid":"plugin-manager",children:[s.jsxs("div",{className:"plugin-manager-header",children:[s.jsx("span",{className:"plugin-manager-header-title",children:"Installed Plugins"}),s.jsxs("div",{className:"plugin-manager-actions",children:[s.jsxs("button",{className:"btn btn-sm btn-ghost",onClick:o,title:"Refresh","aria-label":"Refresh plugin list",children:[s.jsx(ie,{size:14,className:S?"spin":""}),"Refresh"]}),s.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>f(!0),children:[s.jsx(O,{size:14})," Install"]})]})]}),J&&s.jsxs("div",{className:"plugin-install-form",children:[s.jsxs("p",{className:"plugin-install-hint",children:["Browse to a plugin package root (contains ",s.jsx("code",{children:"manifest.json"}),") or a built ",s.jsx("code",{children:"dist"})," directory."]}),s.jsx(me,{value:b,onChange:v,placeholder:"Absolute path to plugin directory or dist folder",onInputKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),z())}}),s.jsxs("div",{className:"plugin-install-actions",children:[s.jsx("button",{className:"btn btn-primary",onClick:z,disabled:C||!b.trim(),children:C?"Installing...":"Install Plugin"}),s.jsx("button",{className:"btn btn-secondary",onClick:()=>{f(!1),v("")},children:"Cancel"})]})]}),S?s.jsx("div",{className:"settings-empty-state",children:"Loading plugins..."}):s.jsxs(s.Fragment,{children:[q.length===0?s.jsxs("div",{className:"settings-empty-state",children:[s.jsx(ae,{size:32,className:"text-muted"}),s.jsx("p",{children:"No plugins installed."}),s.jsx("p",{className:"text-muted",children:"Install a plugin to get started, or use a bundled runtime below."})]}):s.jsx("div",{className:"plugin-list",children:q.map(e=>s.jsxs("div",{className:"plugin-item",children:[s.jsxs("div",{className:"plugin-info",children:[s.jsx("span",{className:"plugin-name",children:e.name}),s.jsxs("span",{className:"plugin-version text-muted",children:["v",e.version]}),s.jsx("span",{className:"plugin-state-badge",style:{color:j[e.state]||j.installed},children:e.state})]}),s.jsxs("div",{className:"plugin-actions",children:[e.state==="started"&&s.jsx("button",{className:"btn-icon",onClick:()=>B(e),disabled:h===e.id,title:"Reload",children:s.jsx(A,{size:14,className:h===e.id?"spin":""})}),s.jsxs("label",{className:"toggle-switch",children:[s.jsx("input",{type:"checkbox",checked:e.enabled,onChange:()=>e.enabled?U(e):F(e)}),s.jsx("span",{className:"toggle-slider"})]}),s.jsx("button",{className:"btn-icon",onClick:()=>W(e),title:"Settings",children:s.jsx(le,{size:14})}),s.jsx("button",{className:"btn-icon",onClick:()=>L(e),title:"Uninstall",children:s.jsx(V,{size:14})})]})]},e.id))}),T()]})]})}export{fe as PluginManager,j as STATE_COLORS};