@swarmroom/server 0.2.0 → 0.3.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 (39) hide show
  1. package/LICENSE +21 -0
  2. package/dist/app.js +2 -0
  3. package/dist/index.js +2 -0
  4. package/dist/public/assets/_agentId-Det2HUaT.js +36 -0
  5. package/dist/public/assets/{activity-B3TqhZ-f.js → activity-C5c3pd0l.js} +1 -1
  6. package/dist/public/assets/{arrow-left-u9wxRsmJ.js → arrow-left-Bho8c3gL.js} +1 -1
  7. package/dist/public/assets/avatar-D6PiXqfu.js +1 -0
  8. package/dist/public/assets/{card-B896vjxa.js → card-BWnhVACg.js} +1 -1
  9. package/dist/public/assets/{chevron-down-CwGQLAwz.js → chevron-down-io8WQqgh.js} +1 -1
  10. package/dist/public/assets/{error-boundary-GFV_5F1L.js → error-boundary-ONLtI3m8.js} +1 -1
  11. package/dist/public/assets/{external-link-skx4o5wJ.js → external-link-D6ZNJ2De.js} +1 -1
  12. package/dist/public/assets/{index-CZLH7_Xl.js → index-B3vl6HkB.js} +1 -1
  13. package/dist/public/assets/{index-D0-THR73.js → index-CRKuXBmU.js} +1 -1
  14. package/dist/public/assets/index-Coo_PliT.js +213 -0
  15. package/dist/public/assets/{index-MKgtdaN5.js → index-CrAz8zKh.js} +1 -1
  16. package/dist/public/assets/{index-Drki27xM.js → index-DSLPkkn7.js} +1 -1
  17. package/dist/public/assets/{index-DC3HeWGk.js → index-DTF52X7L.js} +1 -1
  18. package/dist/public/assets/{index-D8d9U5S5.js → index-DrvfFRRH.js} +1 -1
  19. package/dist/public/assets/{input-BROwVVEx.js → input-CpGy8OTc.js} +1 -1
  20. package/dist/public/assets/{loader-circle-atY3HcdA.js → loader-circle-BBfeX6jI.js} +1 -1
  21. package/dist/public/assets/{plus-Bq20n-_S.js → plus-c5hdQFYj.js} +1 -1
  22. package/dist/public/assets/{radio-D8C4proJ.js → radio-zlZI1pp6.js} +1 -1
  23. package/dist/public/assets/scroll-area-BD_ZWvua.js +1 -0
  24. package/dist/public/assets/{send-Dl7T7Bm1.js → send-D7L2DhCM.js} +1 -1
  25. package/dist/public/assets/{useMutation-BhJRnGsH.js → useMutation-C7s7l6mS.js} +1 -1
  26. package/dist/public/assets/{user-minus-SI0czWZH.js → user-minus-B2DcEtYp.js} +1 -1
  27. package/dist/public/assets/{utils-AH9TuImk.js → utils-Dt8_kYy9.js} +1 -1
  28. package/dist/public/assets/{wifi-BMnLTkMX.js → wifi-CkkG3jQZ.js} +1 -1
  29. package/dist/public/index.html +1 -1
  30. package/dist/routes/skills.d.ts +3 -0
  31. package/dist/routes/skills.js +19 -0
  32. package/dist/services/mdns-browser.js +110 -33
  33. package/dist/services/skill-service.d.ts +4 -0
  34. package/dist/services/skill-service.js +81 -0
  35. package/package.json +25 -14
  36. package/dist/public/assets/_agentId-B5f3yJc6.js +0 -36
  37. package/dist/public/assets/avatar-B_Cqbi60.js +0 -1
  38. package/dist/public/assets/index-DqvmWes8.js +0 -213
  39. package/dist/public/assets/scroll-area-C4F6zoWB.js +0 -1
@@ -1,4 +1,4 @@
1
- import{c as ne,j as e,U as Y,n as $,r as h,D as L,d as O,e as k,f as E,g as Q,o as K,b as x,t as v,A as b,u as M,S as re,p as ie,m as W}from"./index-DqvmWes8.js";import{B as I,S as D,E as le}from"./error-boundary-GFV_5F1L.js";import{C as X,a as Z}from"./card-B896vjxa.js";import{A as oe,a as _,b as U,c as ce}from"./avatar-B_Cqbi60.js";import{g as R,a as B,s as T,T as de}from"./utils-AH9TuImk.js";import{u as w}from"./useMutation-BhJRnGsH.js";import{I as S}from"./input-BROwVVEx.js";import{L as P}from"./loader-circle-atY3HcdA.js";import{S as ee}from"./scroll-area-C4F6zoWB.js";import{P as G}from"./plus-Bq20n-_S.js";import{P as me,U as ue}from"./user-minus-SI0czWZH.js";/**
1
+ import{c as ne,j as e,U as Y,n as $,r as h,D as L,d as O,e as k,f as E,g as Q,o as K,b as x,t as v,A as b,u as M,S as re,p as ie,m as W}from"./index-Coo_PliT.js";import{B as I,S as D,E as le}from"./error-boundary-ONLtI3m8.js";import{C as X,a as Z}from"./card-BWnhVACg.js";import{A as oe,a as _,b as U,c as ce}from"./avatar-D6PiXqfu.js";import{g as R,a as B,s as T,T as de}from"./utils-Dt8_kYy9.js";import{u as w}from"./useMutation-C7s7l6mS.js";import{I as S}from"./input-CpGy8OTc.js";import{L as P}from"./loader-circle-BBfeX6jI.js";import{S as ee}from"./scroll-area-BD_ZWvua.js";import{P as G}from"./plus-c5hdQFYj.js";import{P as me,U as ue}from"./user-minus-B2DcEtYp.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as m,u as k,j as e,b as x,U as A,A as b,t as c,r as C,C as z,q as E,s as S,v as M,w as U,p as y}from"./index-DqvmWes8.js";import{C as u,b as h,c as f,d as g,a as p}from"./card-B896vjxa.js";import{R as H,S as j,B as v,E as T}from"./error-boundary-GFV_5F1L.js";import{A as L}from"./activity-B3TqhZ-f.js";import{W as q,G as F,C as I,a as $,F as B}from"./wifi-BMnLTkMX.js";import{R as O}from"./radio-D8C4proJ.js";import{E as P}from"./external-link-skx4o5wJ.js";/**
1
+ import{c as m,u as k,j as e,b as x,U as A,A as b,t as c,r as C,C as z,q as E,s as S,v as M,w as U,p as y}from"./index-Coo_PliT.js";import{C as u,b as h,c as f,d as g,a as p}from"./card-BWnhVACg.js";import{R as H,S as j,B as v,E as T}from"./error-boundary-ONLtI3m8.js";import{A as L}from"./activity-C5c3pd0l.js";import{W as q,G as F,C as I,a as $,F as B}from"./wifi-CkkG3jQZ.js";import{R as O}from"./radio-zlZI1pp6.js";import{E as P}from"./external-link-D6ZNJ2De.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as R,u as C,j as e,U as B,A as y,n as k,r as p,t as j,D as S,d as P,e as F,f as E,g as A,S as G,b as h,p as _,o as D,m as O,F as J}from"./index-DqvmWes8.js";import{B as Q,S as b,E as W}from"./error-boundary-GFV_5F1L.js";import{C as H,a as V}from"./card-B896vjxa.js";import{A as X,a as q,b as $,c as Y}from"./avatar-B_Cqbi60.js";import{t as M,g as T,a as I,s as w,T as Z}from"./utils-AH9TuImk.js";import{E as U}from"./external-link-skx4o5wJ.js";import{u as v}from"./useMutation-BhJRnGsH.js";import{I as N}from"./input-BROwVVEx.js";import{S as ee}from"./scroll-area-C4F6zoWB.js";import{A as se}from"./arrow-left-u9wxRsmJ.js";import{P as te,U as re}from"./user-minus-SI0czWZH.js";import{P as L}from"./plus-Bq20n-_S.js";/**
1
+ import{c as R,u as C,j as e,U as B,A as y,n as k,r as p,t as j,D as S,d as P,e as F,f as E,g as A,S as G,b as h,p as _,o as D,m as O,F as J}from"./index-Coo_PliT.js";import{B as Q,S as b,E as W}from"./error-boundary-ONLtI3m8.js";import{C as H,a as V}from"./card-BWnhVACg.js";import{A as X,a as q,b as $,c as Y}from"./avatar-D6PiXqfu.js";import{t as M,g as T,a as I,s as w,T as Z}from"./utils-Dt8_kYy9.js";import{E as U}from"./external-link-D6ZNJ2De.js";import{u as v}from"./useMutation-C7s7l6mS.js";import{I as N}from"./input-CpGy8OTc.js";import{S as ee}from"./scroll-area-BD_ZWvua.js";import{A as se}from"./arrow-left-Bho8c3gL.js";import{P as te,U as re}from"./user-minus-B2DcEtYp.js";import{P as L}from"./plus-c5hdQFYj.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as D,j as e,S as ne,V as E,W as $,b as f,X as F,Y as q,Z as H,_,$ as O,x as T,r as m,a0 as re,M as ie,D as ce,d as de,e as oe,f as xe,g as me,o as he,L as Y,n as ue,u as K,t as Q,A as B,m as P,B as ge}from"./index-DqvmWes8.js";import{u as je}from"./useMutation-BhJRnGsH.js";import{B as S,S as C,E as fe}from"./error-boundary-GFV_5F1L.js";import{I as pe}from"./input-BROwVVEx.js";import{a as Z,b as X}from"./avatar-B_Cqbi60.js";import{T as be,s as R,g as J,a as ee,t as ye,f as se}from"./utils-AH9TuImk.js";import{C as Ne,a as ve}from"./card-B896vjxa.js";/**
1
+ import{c as D,j as e,S as ne,V as E,W as $,b as f,X as F,Y as q,Z as H,_,$ as O,x as T,r as m,a0 as re,M as ie,D as ce,d as de,e as oe,f as xe,g as me,o as he,L as Y,n as ue,u as K,t as Q,A as B,m as P,B as ge}from"./index-Coo_PliT.js";import{u as je}from"./useMutation-C7s7l6mS.js";import{B as S,S as C,E as fe}from"./error-boundary-ONLtI3m8.js";import{I as pe}from"./input-CpGy8OTc.js";import{a as Z,b as X}from"./avatar-D6PiXqfu.js";import{T as be,s as R,g as J,a as ee,t as ye,f as se}from"./utils-Dt8_kYy9.js";import{C as Ne,a as ve}from"./card-BWnhVACg.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{j as t,x as n}from"./index-DqvmWes8.js";function a({className:e,type:i,...r}){return t.jsx("input",{type:i,"data-slot":"input",className:n("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm","focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]","aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",e),...r})}export{a as I};
1
+ import{j as t,x as n}from"./index-Coo_PliT.js";function a({className:e,type:i,...r}){return t.jsx("input",{type:i,"data-slot":"input",className:n("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm","focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]","aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",e),...r})}export{a as I};
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DqvmWes8.js";/**
1
+ import{c as e}from"./index-Coo_PliT.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DqvmWes8.js";/**
1
+ import{c as e}from"./index-Coo_PliT.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DqvmWes8.js";/**
1
+ import{c}from"./index-Coo_PliT.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -0,0 +1 @@
1
+ import{r as s,I as T,J as se,j as f,P as L,K as O,N as ce,O as C,Q as P,R as ae,x as F}from"./index-Coo_PliT.js";function ie(e,[o,r]){return Math.min(r,Math.max(o,e))}function de(e,o){return s.useReducer((r,l)=>o[r][l]??r,e)}var U="ScrollArea",[$]=ce(U),[ue,p]=$(U),q=s.forwardRef((e,o)=>{const{__scopeScrollArea:r,type:l="hover",dir:t,scrollHideDelay:n=600,...c}=e,[a,i]=s.useState(null),[h,d]=s.useState(null),[b,u]=s.useState(null),[S,m]=s.useState(null),[A,X]=s.useState(null),[x,_]=s.useState(0),[Y,D]=s.useState(0),[j,y]=s.useState(!1),[N,W]=s.useState(!1),v=T(o,R=>i(R)),w=se(t);return f.jsx(ue,{scope:r,type:l,dir:w,scrollHideDelay:n,scrollArea:a,viewport:h,onViewportChange:d,content:b,onContentChange:u,scrollbarX:S,onScrollbarXChange:m,scrollbarXEnabled:j,onScrollbarXEnabledChange:y,scrollbarY:A,onScrollbarYChange:X,scrollbarYEnabled:N,onScrollbarYEnabledChange:W,onCornerWidthChange:_,onCornerHeightChange:D,children:f.jsx(L.div,{dir:w,...c,ref:v,style:{position:"relative","--radix-scroll-area-corner-width":x+"px","--radix-scroll-area-corner-height":Y+"px",...e.style}})})});q.displayName=U;var J="ScrollAreaViewport",K=s.forwardRef((e,o)=>{const{__scopeScrollArea:r,children:l,nonce:t,...n}=e,c=p(J,r),a=s.useRef(null),i=T(o,a,c.onViewportChange);return f.jsxs(f.Fragment,{children:[f.jsx("style",{dangerouslySetInnerHTML:{__html:"[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}"},nonce:t}),f.jsx(L.div,{"data-radix-scroll-area-viewport":"",...n,ref:i,style:{overflowX:c.scrollbarXEnabled?"scroll":"hidden",overflowY:c.scrollbarYEnabled?"scroll":"hidden",...e.style},children:f.jsx("div",{ref:c.onContentChange,style:{minWidth:"100%",display:"table"},children:l})})]})});K.displayName=J;var g="ScrollAreaScrollbar",Q=s.forwardRef((e,o)=>{const{forceMount:r,...l}=e,t=p(g,e.__scopeScrollArea),{onScrollbarXEnabledChange:n,onScrollbarYEnabledChange:c}=t,a=e.orientation==="horizontal";return s.useEffect(()=>(a?n(!0):c(!0),()=>{a?n(!1):c(!1)}),[a,n,c]),t.type==="hover"?f.jsx(he,{...l,ref:o,forceMount:r}):t.type==="scroll"?f.jsx(fe,{...l,ref:o,forceMount:r}):t.type==="auto"?f.jsx(G,{...l,ref:o,forceMount:r}):t.type==="always"?f.jsx(V,{...l,ref:o}):null});Q.displayName=g;var he=s.forwardRef((e,o)=>{const{forceMount:r,...l}=e,t=p(g,e.__scopeScrollArea),[n,c]=s.useState(!1);return s.useEffect(()=>{const a=t.scrollArea;let i=0;if(a){const h=()=>{window.clearTimeout(i),c(!0)},d=()=>{i=window.setTimeout(()=>c(!1),t.scrollHideDelay)};return a.addEventListener("pointerenter",h),a.addEventListener("pointerleave",d),()=>{window.clearTimeout(i),a.removeEventListener("pointerenter",h),a.removeEventListener("pointerleave",d)}}},[t.scrollArea,t.scrollHideDelay]),f.jsx(O,{present:r||n,children:f.jsx(G,{"data-state":n?"visible":"hidden",...l,ref:o})})}),fe=s.forwardRef((e,o)=>{const{forceMount:r,...l}=e,t=p(g,e.__scopeScrollArea),n=e.orientation==="horizontal",c=M(()=>i("SCROLL_END"),100),[a,i]=de("hidden",{hidden:{SCROLL:"scrolling"},scrolling:{SCROLL_END:"idle",POINTER_ENTER:"interacting"},interacting:{SCROLL:"interacting",POINTER_LEAVE:"idle"},idle:{HIDE:"hidden",SCROLL:"scrolling",POINTER_ENTER:"interacting"}});return s.useEffect(()=>{if(a==="idle"){const h=window.setTimeout(()=>i("HIDE"),t.scrollHideDelay);return()=>window.clearTimeout(h)}},[a,t.scrollHideDelay,i]),s.useEffect(()=>{const h=t.viewport,d=n?"scrollLeft":"scrollTop";if(h){let b=h[d];const u=()=>{const S=h[d];b!==S&&(i("SCROLL"),c()),b=S};return h.addEventListener("scroll",u),()=>h.removeEventListener("scroll",u)}},[t.viewport,n,i,c]),f.jsx(O,{present:r||a!=="hidden",children:f.jsx(V,{"data-state":a==="hidden"?"hidden":"visible",...l,ref:o,onPointerEnter:C(e.onPointerEnter,()=>i("POINTER_ENTER")),onPointerLeave:C(e.onPointerLeave,()=>i("POINTER_LEAVE"))})})}),G=s.forwardRef((e,o)=>{const r=p(g,e.__scopeScrollArea),{forceMount:l,...t}=e,[n,c]=s.useState(!1),a=e.orientation==="horizontal",i=M(()=>{if(r.viewport){const h=r.viewport.offsetWidth<r.viewport.scrollWidth,d=r.viewport.offsetHeight<r.viewport.scrollHeight;c(a?h:d)}},10);return E(r.viewport,i),E(r.content,i),f.jsx(O,{present:l||n,children:f.jsx(V,{"data-state":n?"visible":"hidden",...t,ref:o})})}),V=s.forwardRef((e,o)=>{const{orientation:r="vertical",...l}=e,t=p(g,e.__scopeScrollArea),n=s.useRef(null),c=s.useRef(0),[a,i]=s.useState({content:0,viewport:0,scrollbar:{size:0,paddingStart:0,paddingEnd:0}}),h=te(a.viewport,a.content),d={...l,sizes:a,onSizesChange:i,hasThumb:h>0&&h<1,onThumbChange:u=>n.current=u,onThumbPointerUp:()=>c.current=0,onThumbPointerDown:u=>c.current=u};function b(u,S){return we(u,c.current,a,S)}return r==="horizontal"?f.jsx(be,{...d,ref:o,onThumbPositionChange:()=>{if(t.viewport&&n.current){const u=t.viewport.scrollLeft,S=k(u,a,t.dir);n.current.style.transform=`translate3d(${S}px, 0, 0)`}},onWheelScroll:u=>{t.viewport&&(t.viewport.scrollLeft=u)},onDragScroll:u=>{t.viewport&&(t.viewport.scrollLeft=b(u,t.dir))}}):r==="vertical"?f.jsx(Se,{...d,ref:o,onThumbPositionChange:()=>{if(t.viewport&&n.current){const u=t.viewport.scrollTop,S=k(u,a);n.current.style.transform=`translate3d(0, ${S}px, 0)`}},onWheelScroll:u=>{t.viewport&&(t.viewport.scrollTop=u)},onDragScroll:u=>{t.viewport&&(t.viewport.scrollTop=b(u))}}):null}),be=s.forwardRef((e,o)=>{const{sizes:r,onSizesChange:l,...t}=e,n=p(g,e.__scopeScrollArea),[c,a]=s.useState(),i=s.useRef(null),h=T(o,i,n.onScrollbarXChange);return s.useEffect(()=>{i.current&&a(getComputedStyle(i.current))},[i]),f.jsx(ee,{"data-orientation":"horizontal",...t,ref:h,sizes:r,style:{bottom:0,left:n.dir==="rtl"?"var(--radix-scroll-area-corner-width)":0,right:n.dir==="ltr"?"var(--radix-scroll-area-corner-width)":0,"--radix-scroll-area-thumb-width":I(r)+"px",...e.style},onThumbPointerDown:d=>e.onThumbPointerDown(d.x),onDragScroll:d=>e.onDragScroll(d.x),onWheelScroll:(d,b)=>{if(n.viewport){const u=n.viewport.scrollLeft+d.deltaX;e.onWheelScroll(u),le(u,b)&&d.preventDefault()}},onResize:()=>{i.current&&n.viewport&&c&&l({content:n.viewport.scrollWidth,viewport:n.viewport.offsetWidth,scrollbar:{size:i.current.clientWidth,paddingStart:z(c.paddingLeft),paddingEnd:z(c.paddingRight)}})}})}),Se=s.forwardRef((e,o)=>{const{sizes:r,onSizesChange:l,...t}=e,n=p(g,e.__scopeScrollArea),[c,a]=s.useState(),i=s.useRef(null),h=T(o,i,n.onScrollbarYChange);return s.useEffect(()=>{i.current&&a(getComputedStyle(i.current))},[i]),f.jsx(ee,{"data-orientation":"vertical",...t,ref:h,sizes:r,style:{top:0,right:n.dir==="ltr"?0:void 0,left:n.dir==="rtl"?0:void 0,bottom:"var(--radix-scroll-area-corner-height)","--radix-scroll-area-thumb-height":I(r)+"px",...e.style},onThumbPointerDown:d=>e.onThumbPointerDown(d.y),onDragScroll:d=>e.onDragScroll(d.y),onWheelScroll:(d,b)=>{if(n.viewport){const u=n.viewport.scrollTop+d.deltaY;e.onWheelScroll(u),le(u,b)&&d.preventDefault()}},onResize:()=>{i.current&&n.viewport&&c&&l({content:n.viewport.scrollHeight,viewport:n.viewport.offsetHeight,scrollbar:{size:i.current.clientHeight,paddingStart:z(c.paddingTop),paddingEnd:z(c.paddingBottom)}})}})}),[ve,Z]=$(g),ee=s.forwardRef((e,o)=>{const{__scopeScrollArea:r,sizes:l,hasThumb:t,onThumbChange:n,onThumbPointerUp:c,onThumbPointerDown:a,onThumbPositionChange:i,onDragScroll:h,onWheelScroll:d,onResize:b,...u}=e,S=p(g,r),[m,A]=s.useState(null),X=T(o,v=>A(v)),x=s.useRef(null),_=s.useRef(""),Y=S.viewport,D=l.content-l.viewport,j=P(d),y=P(i),N=M(b,10);function W(v){if(x.current){const w=v.clientX-x.current.left,R=v.clientY-x.current.top;h({x:w,y:R})}}return s.useEffect(()=>{const v=w=>{const R=w.target;(m==null?void 0:m.contains(R))&&j(w,D)};return document.addEventListener("wheel",v,{passive:!1}),()=>document.removeEventListener("wheel",v,{passive:!1})},[Y,m,D,j]),s.useEffect(y,[l,y]),E(m,N),E(S.content,N),f.jsx(ve,{scope:r,scrollbar:m,hasThumb:t,onThumbChange:P(n),onThumbPointerUp:P(c),onThumbPositionChange:y,onThumbPointerDown:P(a),children:f.jsx(L.div,{...u,ref:X,style:{position:"absolute",...u.style},onPointerDown:C(e.onPointerDown,v=>{v.button===0&&(v.target.setPointerCapture(v.pointerId),x.current=m.getBoundingClientRect(),_.current=document.body.style.webkitUserSelect,document.body.style.webkitUserSelect="none",S.viewport&&(S.viewport.style.scrollBehavior="auto"),W(v))}),onPointerMove:C(e.onPointerMove,W),onPointerUp:C(e.onPointerUp,v=>{const w=v.target;w.hasPointerCapture(v.pointerId)&&w.releasePointerCapture(v.pointerId),document.body.style.webkitUserSelect=_.current,S.viewport&&(S.viewport.style.scrollBehavior=""),x.current=null})})})}),H="ScrollAreaThumb",re=s.forwardRef((e,o)=>{const{forceMount:r,...l}=e,t=Z(H,e.__scopeScrollArea);return f.jsx(O,{present:r||t.hasThumb,children:f.jsx(me,{ref:o,...l})})}),me=s.forwardRef((e,o)=>{const{__scopeScrollArea:r,style:l,...t}=e,n=p(H,r),c=Z(H,r),{onThumbPositionChange:a}=c,i=T(o,b=>c.onThumbChange(b)),h=s.useRef(void 0),d=M(()=>{h.current&&(h.current(),h.current=void 0)},100);return s.useEffect(()=>{const b=n.viewport;if(b){const u=()=>{if(d(),!h.current){const S=ge(b,a);h.current=S,a()}};return a(),b.addEventListener("scroll",u),()=>b.removeEventListener("scroll",u)}},[n.viewport,d,a]),f.jsx(L.div,{"data-state":c.hasThumb?"visible":"hidden",...t,ref:i,style:{width:"var(--radix-scroll-area-thumb-width)",height:"var(--radix-scroll-area-thumb-height)",...l},onPointerDownCapture:C(e.onPointerDownCapture,b=>{const S=b.target.getBoundingClientRect(),m=b.clientX-S.left,A=b.clientY-S.top;c.onThumbPointerDown({x:m,y:A})}),onPointerUp:C(e.onPointerUp,c.onThumbPointerUp)})});re.displayName=H;var B="ScrollAreaCorner",oe=s.forwardRef((e,o)=>{const r=p(B,e.__scopeScrollArea),l=!!(r.scrollbarX&&r.scrollbarY);return r.type!=="scroll"&&l?f.jsx(pe,{...e,ref:o}):null});oe.displayName=B;var pe=s.forwardRef((e,o)=>{const{__scopeScrollArea:r,...l}=e,t=p(B,r),[n,c]=s.useState(0),[a,i]=s.useState(0),h=!!(n&&a);return E(t.scrollbarX,()=>{var b;const d=((b=t.scrollbarX)==null?void 0:b.offsetHeight)||0;t.onCornerHeightChange(d),i(d)}),E(t.scrollbarY,()=>{var b;const d=((b=t.scrollbarY)==null?void 0:b.offsetWidth)||0;t.onCornerWidthChange(d),c(d)}),h?f.jsx(L.div,{...l,ref:o,style:{width:n,height:a,position:"absolute",right:t.dir==="ltr"?0:void 0,left:t.dir==="rtl"?0:void 0,bottom:0,...e.style}}):null});function z(e){return e?parseInt(e,10):0}function te(e,o){const r=e/o;return isNaN(r)?0:r}function I(e){const o=te(e.viewport,e.content),r=e.scrollbar.paddingStart+e.scrollbar.paddingEnd,l=(e.scrollbar.size-r)*o;return Math.max(l,18)}function we(e,o,r,l="ltr"){const t=I(r),n=t/2,c=o||n,a=t-c,i=r.scrollbar.paddingStart+c,h=r.scrollbar.size-r.scrollbar.paddingEnd-a,d=r.content-r.viewport,b=l==="ltr"?[0,d]:[d*-1,0];return ne([i,h],b)(e)}function k(e,o,r="ltr"){const l=I(o),t=o.scrollbar.paddingStart+o.scrollbar.paddingEnd,n=o.scrollbar.size-t,c=o.content-o.viewport,a=n-l,i=r==="ltr"?[0,c]:[c*-1,0],h=ie(e,i);return ne([0,c],[0,a])(h)}function ne(e,o){return r=>{if(e[0]===e[1]||o[0]===o[1])return o[0];const l=(o[1]-o[0])/(e[1]-e[0]);return o[0]+l*(r-e[0])}}function le(e,o){return e>0&&e<o}var ge=(e,o=()=>{})=>{let r={left:e.scrollLeft,top:e.scrollTop},l=0;return(function t(){const n={left:e.scrollLeft,top:e.scrollTop},c=r.left!==n.left,a=r.top!==n.top;(c||a)&&o(),r=n,l=window.requestAnimationFrame(t)})(),()=>window.cancelAnimationFrame(l)};function M(e,o){const r=P(e),l=s.useRef(0);return s.useEffect(()=>()=>window.clearTimeout(l.current),[]),s.useCallback(()=>{window.clearTimeout(l.current),l.current=window.setTimeout(r,o)},[r,o])}function E(e,o){const r=P(o);ae(()=>{let l=0;if(e){const t=new ResizeObserver(()=>{cancelAnimationFrame(l),l=window.requestAnimationFrame(r)});return t.observe(e),()=>{window.cancelAnimationFrame(l),t.unobserve(e)}}},[e,r])}var xe=q,Pe=K,Ce=oe;function Ae({className:e,children:o,...r}){return f.jsxs(xe,{"data-slot":"scroll-area",className:F("relative",e),...r,children:[f.jsx(Pe,{"data-slot":"scroll-area-viewport",className:"focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",children:o}),f.jsx(Re,{}),f.jsx(Ce,{})]})}function Re({className:e,orientation:o="vertical",...r}){return f.jsx(Q,{"data-slot":"scroll-area-scrollbar",orientation:o,className:F("flex touch-none p-px transition-colors select-none",o==="vertical"&&"h-full w-2.5 border-l border-l-transparent",o==="horizontal"&&"h-2.5 flex-col border-t border-t-transparent",e),...r,children:f.jsx(re,{"data-slot":"scroll-area-thumb",className:"bg-border relative flex-1 rounded-full"})})}export{Ae as S};
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DqvmWes8.js";/**
1
+ import{c as e}from"./index-Coo_PliT.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- var R=i=>{throw TypeError(i)};var E=(i,t,s)=>t.has(i)||R("Cannot "+s);var e=(i,t,s)=>(E(i,t,"read from private field"),s?s.call(i):t.get(i)),m=(i,t,s)=>t.has(i)?R("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(i):t.set(i,s),p=(i,t,s,r)=>(E(i,t,"write to private field"),r?r.call(i,s):t.set(i,s),s),y=(i,t,s)=>(E(i,t,"access private method"),s);import{aa as U,ab as k,ac as j,ad as q,ae as P,n as L,r as v,af as A,ag as D}from"./index-DqvmWes8.js";var a,c,o,h,n,C,S,w,I=(w=class extends U{constructor(t,s){super();m(this,n);m(this,a);m(this,c);m(this,o);m(this,h);p(this,a,t),this.setOptions(s),this.bindMethods(),y(this,n,C).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(t){var r;const s=this.options;this.options=e(this,a).defaultMutationOptions(t),k(this.options,s)||e(this,a).getMutationCache().notify({type:"observerOptionsUpdated",mutation:e(this,o),observer:this}),s!=null&&s.mutationKey&&this.options.mutationKey&&j(s.mutationKey)!==j(this.options.mutationKey)?this.reset():((r=e(this,o))==null?void 0:r.state.status)==="pending"&&e(this,o).setOptions(this.options)}onUnsubscribe(){var t;this.hasListeners()||(t=e(this,o))==null||t.removeObserver(this)}onMutationUpdate(t){y(this,n,C).call(this),y(this,n,S).call(this,t)}getCurrentResult(){return e(this,c)}reset(){var t;(t=e(this,o))==null||t.removeObserver(this),p(this,o,void 0),y(this,n,C).call(this),y(this,n,S).call(this)}mutate(t,s){var r;return p(this,h,s),(r=e(this,o))==null||r.removeObserver(this),p(this,o,e(this,a).getMutationCache().build(e(this,a),this.options)),e(this,o).addObserver(this),e(this,o).execute(t)}},a=new WeakMap,c=new WeakMap,o=new WeakMap,h=new WeakMap,n=new WeakSet,C=function(){var s;const t=((s=e(this,o))==null?void 0:s.state)??q();p(this,c,{...t,isPending:t.status==="pending",isSuccess:t.status==="success",isError:t.status==="error",isIdle:t.status==="idle",mutate:this.mutate,reset:this.reset})},S=function(t){P.batch(()=>{var s,r,u,f,d,O,x,K;if(e(this,h)&&this.hasListeners()){const b=e(this,c).variables,g=e(this,c).context,M={client:e(this,a),meta:this.options.meta,mutationKey:this.options.mutationKey};if((t==null?void 0:t.type)==="success"){try{(r=(s=e(this,h)).onSuccess)==null||r.call(s,t.data,b,g,M)}catch(l){Promise.reject(l)}try{(f=(u=e(this,h)).onSettled)==null||f.call(u,t.data,null,b,g,M)}catch(l){Promise.reject(l)}}else if((t==null?void 0:t.type)==="error"){try{(O=(d=e(this,h)).onError)==null||O.call(d,t.error,b,g,M)}catch(l){Promise.reject(l)}try{(K=(x=e(this,h)).onSettled)==null||K.call(x,void 0,t.error,b,g,M)}catch(l){Promise.reject(l)}}}this.listeners.forEach(b=>{b(e(this,c))})})},w);function z(i,t){const s=L(),[r]=v.useState(()=>new I(s,i));v.useEffect(()=>{r.setOptions(i)},[r,i]);const u=v.useSyncExternalStore(v.useCallback(d=>r.subscribe(P.batchCalls(d)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),f=v.useCallback((d,O)=>{r.mutate(d,O).catch(A)},[r]);if(u.error&&D(r.options.throwOnError,[u.error]))throw u.error;return{...u,mutate:f,mutateAsync:u.mutate}}export{z as u};
1
+ var R=i=>{throw TypeError(i)};var E=(i,t,s)=>t.has(i)||R("Cannot "+s);var e=(i,t,s)=>(E(i,t,"read from private field"),s?s.call(i):t.get(i)),m=(i,t,s)=>t.has(i)?R("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(i):t.set(i,s),p=(i,t,s,r)=>(E(i,t,"write to private field"),r?r.call(i,s):t.set(i,s),s),y=(i,t,s)=>(E(i,t,"access private method"),s);import{aa as U,ab as k,ac as j,ad as q,ae as P,n as L,r as v,af as A,ag as D}from"./index-Coo_PliT.js";var a,c,o,h,n,C,S,w,I=(w=class extends U{constructor(t,s){super();m(this,n);m(this,a);m(this,c);m(this,o);m(this,h);p(this,a,t),this.setOptions(s),this.bindMethods(),y(this,n,C).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(t){var r;const s=this.options;this.options=e(this,a).defaultMutationOptions(t),k(this.options,s)||e(this,a).getMutationCache().notify({type:"observerOptionsUpdated",mutation:e(this,o),observer:this}),s!=null&&s.mutationKey&&this.options.mutationKey&&j(s.mutationKey)!==j(this.options.mutationKey)?this.reset():((r=e(this,o))==null?void 0:r.state.status)==="pending"&&e(this,o).setOptions(this.options)}onUnsubscribe(){var t;this.hasListeners()||(t=e(this,o))==null||t.removeObserver(this)}onMutationUpdate(t){y(this,n,C).call(this),y(this,n,S).call(this,t)}getCurrentResult(){return e(this,c)}reset(){var t;(t=e(this,o))==null||t.removeObserver(this),p(this,o,void 0),y(this,n,C).call(this),y(this,n,S).call(this)}mutate(t,s){var r;return p(this,h,s),(r=e(this,o))==null||r.removeObserver(this),p(this,o,e(this,a).getMutationCache().build(e(this,a),this.options)),e(this,o).addObserver(this),e(this,o).execute(t)}},a=new WeakMap,c=new WeakMap,o=new WeakMap,h=new WeakMap,n=new WeakSet,C=function(){var s;const t=((s=e(this,o))==null?void 0:s.state)??q();p(this,c,{...t,isPending:t.status==="pending",isSuccess:t.status==="success",isError:t.status==="error",isIdle:t.status==="idle",mutate:this.mutate,reset:this.reset})},S=function(t){P.batch(()=>{var s,r,u,f,d,O,x,K;if(e(this,h)&&this.hasListeners()){const b=e(this,c).variables,g=e(this,c).context,M={client:e(this,a),meta:this.options.meta,mutationKey:this.options.mutationKey};if((t==null?void 0:t.type)==="success"){try{(r=(s=e(this,h)).onSuccess)==null||r.call(s,t.data,b,g,M)}catch(l){Promise.reject(l)}try{(f=(u=e(this,h)).onSettled)==null||f.call(u,t.data,null,b,g,M)}catch(l){Promise.reject(l)}}else if((t==null?void 0:t.type)==="error"){try{(O=(d=e(this,h)).onError)==null||O.call(d,t.error,b,g,M)}catch(l){Promise.reject(l)}try{(K=(x=e(this,h)).onSettled)==null||K.call(x,void 0,t.error,b,g,M)}catch(l){Promise.reject(l)}}}this.listeners.forEach(b=>{b(e(this,c))})})},w);function z(i,t){const s=L(),[r]=v.useState(()=>new I(s,i));v.useEffect(()=>{r.setOptions(i)},[r,i]);const u=v.useSyncExternalStore(v.useCallback(d=>r.subscribe(P.batchCalls(d)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),f=v.useCallback((d,O)=>{r.mutate(d,O).catch(A)},[r]);if(u.error&&D(r.options.throwOnError,[u.error]))throw u.error;return{...u,mutate:f,mutateAsync:u.mutate}}export{z as u};
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DqvmWes8.js";/**
1
+ import{c as e}from"./index-Coo_PliT.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as f}from"./index-DqvmWes8.js";/**
1
+ import{c as f}from"./index-Coo_PliT.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as a}from"./index-DqvmWes8.js";/**
1
+ import{c as a}from"./index-Coo_PliT.js";/**
2
2
  * @license lucide-react v0.400.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>SwarmRoom</title>
8
- <script type="module" crossorigin src="/assets/index-DqvmWes8.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-Coo_PliT.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-DcbqFmA_.css">
10
10
  </head>
11
11
  <body>
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const skillsRoute: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export { skillsRoute };
@@ -0,0 +1,19 @@
1
+ import { Hono } from 'hono';
2
+ import { HTTPException } from 'hono/http-exception';
3
+ import { listSkills, getSkill } from '../services/skill-service.js';
4
+ const skillsRoute = new Hono();
5
+ skillsRoute.get('/', (c) => {
6
+ const skills = listSkills();
7
+ return c.json({ success: true, data: skills });
8
+ });
9
+ skillsRoute.get('/:name', (c) => {
10
+ const name = c.req.param('name');
11
+ const skill = getSkill(name);
12
+ if (!skill) {
13
+ throw new HTTPException(404, {
14
+ message: `Skill "${name}" not found`,
15
+ });
16
+ }
17
+ return c.json({ success: true, data: skill });
18
+ });
19
+ export { skillsRoute };
@@ -1,53 +1,130 @@
1
- import { createSocket } from 'dgram';
2
- import { MDNS_SERVICE_TYPE } from '@swarmroom/shared';
3
- const MDNS_ADDRESS = '224.0.0.251';
4
- const MDNS_PORT = 5353;
5
- let socket = null;
1
+ import mdns from 'multicast-dns';
2
+ import { MDNS_SERVICE_TYPE, DEFAULT_PORT } from '@swarmroom/shared';
3
+ const SERVICE_NAME = `${MDNS_SERVICE_TYPE}.local`;
4
+ const QUERY_INTERVAL_MS = 30_000;
5
+ let browser = null;
6
+ let queryTimer = null;
6
7
  let running = false;
8
+ let lastDiscoveredUrl = null;
9
+ function normalizeName(name) {
10
+ return name.endsWith('.') ? name.slice(0, -1) : name;
11
+ }
12
+ function isServiceRecordName(name) {
13
+ return normalizeName(name).endsWith(SERVICE_NAME);
14
+ }
15
+ function parseTxtEntries(data) {
16
+ const entries = Array.isArray(data) ? data : [data];
17
+ return entries
18
+ .map((entry) => (Buffer.isBuffer(entry) ? entry.toString('utf8') : String(entry)))
19
+ .map((entry) => entry.trim())
20
+ .filter((entry) => entry.length > 0);
21
+ }
22
+ function findTxtUrl(records) {
23
+ for (const record of records) {
24
+ if (record.type !== 'TXT' || !isServiceRecordName(record.name))
25
+ continue;
26
+ const entries = parseTxtEntries(record.data);
27
+ for (const entry of entries) {
28
+ const separatorIndex = entry.indexOf('=');
29
+ if (separatorIndex === -1)
30
+ continue;
31
+ const key = entry.slice(0, separatorIndex).trim();
32
+ const value = entry.slice(separatorIndex + 1).trim();
33
+ if (key === 'url' && value) {
34
+ return value;
35
+ }
36
+ }
37
+ }
38
+ return null;
39
+ }
40
+ function findSrvRecord(records) {
41
+ for (const record of records) {
42
+ if (record.type === 'SRV' && isServiceRecordName(record.name)) {
43
+ return record;
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ function resolveTargetIp(target, records) {
49
+ const normalizedTarget = normalizeName(target);
50
+ let fallbackIpv6 = null;
51
+ for (const record of records) {
52
+ if (record.type !== 'A' && record.type !== 'AAAA')
53
+ continue;
54
+ if (normalizeName(record.name) !== normalizedTarget)
55
+ continue;
56
+ if (record.type === 'A' && typeof record.data === 'string') {
57
+ return record.data;
58
+ }
59
+ if (record.type === 'AAAA' && typeof record.data === 'string') {
60
+ fallbackIpv6 = record.data;
61
+ }
62
+ }
63
+ return fallbackIpv6;
64
+ }
65
+ function extractHubUrl(records) {
66
+ const txtUrl = findTxtUrl(records);
67
+ if (txtUrl)
68
+ return txtUrl;
69
+ const srvRecord = findSrvRecord(records);
70
+ if (!srvRecord)
71
+ return null;
72
+ const srvData = srvRecord.data;
73
+ const targetIp = resolveTargetIp(srvData.target, records);
74
+ if (!targetIp)
75
+ return null;
76
+ const port = srvData.port ?? DEFAULT_PORT;
77
+ return `http://${targetIp}:${port}`;
78
+ }
79
+ function sendQuery() {
80
+ if (!browser)
81
+ return;
82
+ browser.query({ questions: [{ name: SERVICE_NAME, type: 'PTR' }] });
83
+ }
7
84
  export function startBrowsing() {
8
85
  if (process.env.SWARMROOM_DISABLE_MDNS === 'true') {
9
86
  return;
10
87
  }
88
+ if (running)
89
+ return;
11
90
  try {
12
- socket = createSocket({ type: 'udp4', reuseAddr: true });
13
- socket.on('message', (msg) => {
14
- const content = msg.toString('utf8');
15
- if (content.includes(MDNS_SERVICE_TYPE.replace(/^_/, '').replace(/\._tcp$/, ''))) {
16
- console.log(`[mdns-browser] Detected ${MDNS_SERVICE_TYPE} service activity on the network`);
17
- }
91
+ browser = mdns();
92
+ running = true;
93
+ console.log(`[mdns-browser] Browsing for ${MDNS_SERVICE_TYPE} services on the network`);
94
+ browser.on('response', (response) => {
95
+ const records = [...(response.answers ?? []), ...(response.additionals ?? [])];
96
+ const url = extractHubUrl(records);
97
+ if (!url)
98
+ return;
99
+ if (url === lastDiscoveredUrl)
100
+ return;
101
+ lastDiscoveredUrl = url;
102
+ console.log(`[mdns-browser] Discovered SwarmRoom hub at ${url}`);
18
103
  });
19
- socket.on('error', (err) => {
20
- console.warn('[mdns-browser] Socket error:', err.message);
21
- stopBrowsing();
22
- });
23
- socket.bind(MDNS_PORT, () => {
24
- try {
25
- socket?.addMembership(MDNS_ADDRESS);
26
- running = true;
27
- console.log(`[mdns-browser] Browsing for ${MDNS_SERVICE_TYPE} services on the network`);
28
- }
29
- catch (error) {
30
- console.warn('[mdns-browser] Failed to join multicast group:', error);
31
- stopBrowsing();
32
- }
104
+ browser.on('error', (error) => {
105
+ console.warn('[mdns-browser] mDNS error:', error.message);
33
106
  });
107
+ sendQuery();
108
+ queryTimer = setInterval(sendQuery, QUERY_INTERVAL_MS);
34
109
  }
35
110
  catch (error) {
36
111
  console.warn('[mdns-browser] Failed to start browsing — continuing without mDNS browsing:', error);
37
- socket = null;
112
+ stopBrowsing();
38
113
  }
39
114
  }
40
115
  export function stopBrowsing() {
41
- if (socket) {
42
- try {
43
- socket.close();
44
- }
45
- catch {
46
- }
47
- socket = null;
116
+ if (queryTimer) {
117
+ clearInterval(queryTimer);
118
+ queryTimer = null;
119
+ }
120
+ if (browser) {
121
+ browser.removeAllListeners();
122
+ browser.destroy();
123
+ browser = null;
48
124
  }
49
125
  if (running) {
50
126
  running = false;
127
+ lastDiscoveredUrl = null;
51
128
  console.log('[mdns-browser] Stopped browsing');
52
129
  }
53
130
  }
@@ -0,0 +1,4 @@
1
+ import type { SkillInfo, SkillSummary } from '@swarmroom/shared';
2
+ export declare function scanSkills(dirs?: string[]): void;
3
+ export declare function listSkills(): SkillSummary[];
4
+ export declare function getSkill(name: string): SkillInfo | null;
@@ -0,0 +1,81 @@
1
+ import { readFileSync, readdirSync, existsSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ const skills = new Map();
5
+ function parseFrontmatter(content) {
6
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
7
+ if (!match)
8
+ return { frontmatter: {}, body: content };
9
+ const frontmatter = {};
10
+ for (const line of match[1].split('\n')) {
11
+ const [key, ...rest] = line.split(':');
12
+ if (key && rest.length) {
13
+ frontmatter[key.trim()] = rest.join(':').trim().replace(/^["']|["']$/g, '');
14
+ }
15
+ }
16
+ return { frontmatter, body: match[2].trim() };
17
+ }
18
+ function scanDirectory(dir) {
19
+ if (!existsSync(dir))
20
+ return;
21
+ try {
22
+ const entries = readdirSync(dir, { withFileTypes: true });
23
+ for (const entry of entries) {
24
+ if (entry.isDirectory()) {
25
+ const skillPath = join(dir, entry.name, 'SKILL.md');
26
+ if (existsSync(skillPath)) {
27
+ try {
28
+ const content = readFileSync(skillPath, 'utf-8');
29
+ const { frontmatter, body } = parseFrontmatter(content);
30
+ const name = frontmatter.name || entry.name;
31
+ const description = frontmatter.description || '';
32
+ const metadata = {};
33
+ for (const [key, value] of Object.entries(frontmatter)) {
34
+ if (key !== 'name' && key !== 'description') {
35
+ metadata[key] = value;
36
+ }
37
+ }
38
+ skills.set(name, {
39
+ name,
40
+ description,
41
+ location: skillPath,
42
+ content: body,
43
+ metadata,
44
+ });
45
+ }
46
+ catch (error) {
47
+ console.warn(`Failed to load skill from ${skillPath}:`, error);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ catch (error) {
54
+ console.warn(`Failed to scan directory ${dir}:`, error);
55
+ }
56
+ }
57
+ export function scanSkills(dirs) {
58
+ const defaultDirs = [
59
+ resolve(homedir(), '.swarmroom', 'skills'),
60
+ resolve(homedir(), '.opencode', 'skills'),
61
+ resolve(homedir(), '.claude', 'skills'),
62
+ resolve(process.cwd(), '.swarmroom', 'skills'),
63
+ ];
64
+ const scanDirs = dirs || defaultDirs;
65
+ skills.clear();
66
+ for (const dir of scanDirs) {
67
+ scanDirectory(dir);
68
+ }
69
+ console.log(`Loaded ${skills.size} skill(s) from ${scanDirs.length} directories`);
70
+ }
71
+ export function listSkills() {
72
+ return Array.from(skills.values()).map(skill => ({
73
+ name: skill.name,
74
+ description: skill.description,
75
+ location: skill.location,
76
+ metadata: skill.metadata,
77
+ }));
78
+ }
79
+ export function getSkill(name) {
80
+ return skills.get(name) || null;
81
+ }
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@swarmroom/server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "SwarmRoom hub server - HTTP, WebSocket, MCP, and mDNS services",
6
- "keywords": ["swarmroom", "server", "hub", "mcp", "websocket"],
6
+ "keywords": [
7
+ "swarmroom",
8
+ "server",
9
+ "hub",
10
+ "mcp",
11
+ "websocket"
12
+ ],
7
13
  "license": "MIT",
8
14
  "publishConfig": {
9
15
  "access": "public"
@@ -19,30 +25,35 @@
19
25
  ".": "./dist/index.js",
20
26
  "./dist/*": "./dist/*"
21
27
  },
22
- "files": ["dist", "README.md", "LICENSE"],
23
- "scripts": {
24
- "build": "tsc",
25
- "postbuild": "node -e \"const fs=require('fs'),p=require('path'),s=p.join(__dirname,'../web/dist'),d=p.join(__dirname,'dist/public');fs.existsSync(s)?(fs.cpSync(s,d,{recursive:true}),console.log('Web dashboard bundled')):console.log('Web dist not found, skipping')\"",
26
- "dev": "tsx watch src/index.ts",
27
- "start": "node dist/index.js",
28
- "test": "vitest run",
29
- "prepublishOnly": "npm run build"
30
- },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "LICENSE"
32
+ ],
31
33
  "dependencies": {
32
34
  "@homebridge/ciao": "^1.3.5",
33
35
  "@hono/node-server": "^1.19.9",
34
36
  "@hono/node-ws": "^1.3.0",
35
37
  "@modelcontextprotocol/sdk": "^1.26.0",
36
- "@swarmroom/shared": "^0.2.0",
37
38
  "better-sqlite3": "^12.6.2",
38
39
  "drizzle-orm": "^0.45.1",
39
40
  "hono": "^4.11.9",
41
+ "multicast-dns": "^7.2.5",
40
42
  "tsx": "^4.21.0",
41
- "zod": "^4.3.6"
43
+ "zod": "^4.3.6",
44
+ "@swarmroom/shared": "0.3.0"
42
45
  },
43
46
  "devDependencies": {
44
47
  "@types/better-sqlite3": "^7.6.13",
48
+ "@types/multicast-dns": "^7.2.4",
45
49
  "drizzle-kit": "^0.31.9",
46
50
  "vitest": "^4.0.18"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc",
54
+ "postbuild": "node -e \"const fs=require('fs'),p=require('path'),s=p.join(__dirname,'../web/dist'),d=p.join(__dirname,'dist/public');fs.existsSync(s)?(fs.cpSync(s,d,{recursive:true}),console.log('Web dashboard bundled')):console.log('Web dist not found, skipping')\"",
55
+ "dev": "tsx watch src/index.ts",
56
+ "start": "node dist/index.js",
57
+ "test": "vitest run"
47
58
  }
48
- }
59
+ }
@@ -1,36 +0,0 @@
1
- import{c as N,r as p,j as e,I as fe,K as ge,a2 as je,a3 as ve,a4 as Ne,a5 as ye,O as P,P as be,a6 as Y,N as we,x as F,a7 as Ce,a0 as ee,b as h,M as se,p as z,L as ke,D as q,d as D,e as M,f as I,g as _,o as O,u as T,A as g,n as S,t as f,U,a8 as ae,B as Te,a9 as Ae}from"./index-DqvmWes8.js";import{u as A}from"./useMutation-BhJRnGsH.js";import{B as v,S as c,E as ze}from"./error-boundary-GFV_5F1L.js";import{g as Fe,a as Se,s as J,T as Ee,t as $e,f as te}from"./utils-AH9TuImk.js";import{E as Pe}from"./external-link-skx4o5wJ.js";import{C as Le,W as Re,F as W,G as qe,a as De}from"./wifi-BMnLTkMX.js";import{A as Me}from"./arrow-left-u9wxRsmJ.js";import{C as b,b as w,c as C,a as k}from"./card-B896vjxa.js";import{C as Ie}from"./chevron-down-CwGQLAwz.js";import{P as re}from"./plus-Bq20n-_S.js";import{L as ne}from"./loader-circle-atY3HcdA.js";/**
2
- * @license lucide-react v0.400.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 _e=N("ArrowDownLeft",[["path",{d:"M17 7 7 17",key:"15tmo1"}],["path",{d:"M17 17H7V7",key:"1org7z"}]]);/**
7
- * @license lucide-react v0.400.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 Oe=N("ArrowUpRight",[["path",{d:"M7 7h10v10",key:"1tivn9"}],["path",{d:"M7 17 17 7",key:"1vkiza"}]]);/**
12
- * @license lucide-react v0.400.0 - ISC
13
- *
14
- * This source code is licensed under the ISC license.
15
- * See the LICENSE file in the root directory of this source tree.
16
- */const Ke=N("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);/**
17
- * @license lucide-react v0.400.0 - ISC
18
- *
19
- * This source code is licensed under the ISC license.
20
- * See the LICENSE file in the root directory of this source tree.
21
- */const X=N("FolderOpen",[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]]);/**
22
- * @license lucide-react v0.400.0 - ISC
23
- *
24
- * This source code is licensed under the ISC license.
25
- * See the LICENSE file in the root directory of this source tree.
26
- */const Qe=N("Sparkles",[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M22 5h-4",key:"1gvqau"}],["path",{d:"M4 17v2",key:"vumght"}],["path",{d:"M5 18H3",key:"zchphs"}]]);/**
27
- * @license lucide-react v0.400.0 - ISC
28
- *
29
- * This source code is licensed under the ISC license.
30
- * See the LICENSE file in the root directory of this source tree.
31
- */const He=N("Tag",[["path",{d:"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z",key:"vktsd0"}],["circle",{cx:"7.5",cy:"7.5",r:".5",fill:"currentColor",key:"kqv944"}]]);/**
32
- * @license lucide-react v0.400.0 - ISC
33
- *
34
- * This source code is licensed under the ISC license.
35
- * See the LICENSE file in the root directory of this source tree.
36
- */const Ve=N("Zap",[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]]);var Be=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","select","span","svg","ul"],E=Be.reduce((s,r)=>{const l=fe(`Primitive.${r}`),n=p.forwardRef((a,o)=>{const{asChild:i,...d}=a,x=i?l:r;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),e.jsx(x,{...d,ref:o})});return n.displayName=`Primitive.${r}`,{...s,[r]:n}},{}),$="Tabs",[Ge]=we($,[Y]),ie=Y(),[Ue,K]=Ge($),oe=p.forwardRef((s,r)=>{const{__scopeTabs:l,value:n,onValueChange:a,defaultValue:o,orientation:i="horizontal",dir:d,activationMode:x="automatic",...t}=s,m=ge(d),[u,j]=je({prop:n,onChange:a,defaultProp:o??"",caller:$});return e.jsx(Ue,{scope:l,baseId:ve(),value:u,onValueChange:j,orientation:i,dir:m,activationMode:x,children:e.jsx(E.div,{dir:m,"data-orientation":i,...t,ref:r})})});oe.displayName=$;var le="TabsList",de=p.forwardRef((s,r)=>{const{__scopeTabs:l,loop:n=!0,...a}=s,o=K(le,l),i=ie(l);return e.jsx(Ne,{asChild:!0,...i,orientation:o.orientation,dir:o.dir,loop:n,children:e.jsx(E.div,{role:"tablist","aria-orientation":o.orientation,...a,ref:r})})});de.displayName=le;var ce="TabsTrigger",me=p.forwardRef((s,r)=>{const{__scopeTabs:l,value:n,disabled:a=!1,...o}=s,i=K(ce,l),d=ie(l),x=pe(i.baseId,n),t=he(i.baseId,n),m=n===i.value;return e.jsx(ye,{asChild:!0,...d,focusable:!a,active:m,children:e.jsx(E.button,{type:"button",role:"tab","aria-selected":m,"aria-controls":t,"data-state":m?"active":"inactive","data-disabled":a?"":void 0,disabled:a,id:x,...o,ref:r,onMouseDown:P(s.onMouseDown,u=>{!a&&u.button===0&&u.ctrlKey===!1?i.onValueChange(n):u.preventDefault()}),onKeyDown:P(s.onKeyDown,u=>{[" ","Enter"].includes(u.key)&&i.onValueChange(n)}),onFocus:P(s.onFocus,()=>{const u=i.activationMode!=="manual";!m&&!a&&u&&i.onValueChange(n)})})})});me.displayName=ce;var xe="TabsContent",ue=p.forwardRef((s,r)=>{const{__scopeTabs:l,value:n,forceMount:a,children:o,...i}=s,d=K(xe,l),x=pe(d.baseId,n),t=he(d.baseId,n),m=n===d.value,u=p.useRef(m);return p.useEffect(()=>{const j=requestAnimationFrame(()=>u.current=!1);return()=>cancelAnimationFrame(j)},[]),e.jsx(be,{present:a||m,children:({present:j})=>e.jsx(E.div,{"data-state":m?"active":"inactive","data-orientation":d.orientation,role:"tabpanel","aria-labelledby":x,hidden:!j,id:t,tabIndex:0,...i,ref:r,style:{...s.style,animationDuration:u.current?"0s":void 0},children:j&&o})})});ue.displayName=xe;function pe(s,r){return`${s}-trigger-${r}`}function he(s,r){return`${s}-content-${r}`}var Je=oe,We=de,Xe=me,Ze=ue;function Ye({className:s,orientation:r="horizontal",...l}){return e.jsx(Je,{"data-slot":"tabs","data-orientation":r,orientation:r,className:F("group/tabs flex gap-2 data-[orientation=horizontal]:flex-col",s),...l})}const es=Ce("rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",{variants:{variant:{default:"bg-muted",line:"gap-1 bg-transparent"}},defaultVariants:{variant:"default"}});function ss({className:s,variant:r="default",...l}){return e.jsx(We,{"data-slot":"tabs-list","data-variant":r,className:F(es({variant:r}),s),...l})}function L({className:s,...r}){return e.jsx(Xe,{"data-slot":"tabs-trigger",className:F("focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4","group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent","data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground","after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",s),...r})}function R({className:s,...r}){return e.jsx(Ze,{"data-slot":"tabs-content",className:F("flex-1 outline-none",s),...r})}function as({agent:s,onDelete:r,isDeleting:l}){var t,m,u,j,Q,H,V,B,G;const[n,a]=p.useState(!1),o=ee(),i=Fe(s.displayName),d=Se(s.displayName),x=J[s.status]??J.offline;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"relative overflow-hidden rounded-xl border border-border/60 bg-card",children:[e.jsx("div",{className:"h-24 w-full",style:{background:`linear-gradient(135deg, ${d}44 0%, ${d}18 40%, transparent 70%)`}}),e.jsxs("div",{className:"relative px-6 pb-6",children:[e.jsxs("div",{className:"-mt-10 flex items-end gap-5",children:[e.jsx("div",{className:"flex size-20 shrink-0 items-center justify-center rounded-2xl text-2xl font-bold text-white shadow-lg ring-4 ring-card",style:{backgroundColor:d},children:i}),e.jsxs("div",{className:"flex min-w-0 flex-1 flex-wrap items-start justify-between gap-4 pt-1",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("h1",{className:"truncate text-xl font-bold tracking-tight text-foreground",children:s.displayName}),e.jsxs(v,{variant:x.variant,className:"gap-1.5 text-xs",children:[e.jsx("span",{className:`inline-block size-1.5 rounded-full ${x.dot} ${s.status==="online"?"animate-pulse":""}`}),x.label]})]}),e.jsx("p",{className:"mt-0.5 truncate font-mono text-sm text-muted-foreground",children:s.name})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(h,{size:"sm",onClick:()=>o({to:"/messages",search:{to:s.id}}),children:[e.jsx(se,{className:"size-4"}),"Send Message"]}),e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>a(!0),children:[e.jsx(Ee,{className:"size-4"}),"Remove"]})]})]})]}),e.jsxs("div",{className:"mt-5 flex flex-wrap items-center gap-x-5 gap-y-2 text-sm text-muted-foreground",children:[s.url&&e.jsxs("a",{href:s.url,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 transition-colors hover:text-foreground",children:[e.jsx(Pe,{className:"size-3.5"}),$e(s.url,40)]}),((t=s.agentCard)==null?void 0:t.version)&&e.jsxs(e.Fragment,{children:[e.jsx(z,{orientation:"vertical",className:"!h-4"}),e.jsxs("span",{className:"font-mono text-xs",children:["v",s.agentCard.version]})]}),s.lastHeartbeat&&e.jsxs(e.Fragment,{children:[e.jsx(z,{orientation:"vertical",className:"!h-4"}),e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(Le,{className:"size-3.5"}),te(s.lastHeartbeat)]})]}),s.status==="online"&&e.jsxs(e.Fragment,{children:[e.jsx(z,{orientation:"vertical",className:"!h-4"}),e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-emerald-600 dark:text-emerald-400",children:[e.jsx(Re,{className:"size-3.5"}),"Connected"]})]})]}),((((u=(m=s.agentCard)==null?void 0:m.teams)==null?void 0:u.length)??0)>0||(((Q=(j=s.agentCard)==null?void 0:j.projectGroups)==null?void 0:Q.length)??0)>0)&&e.jsxs("div",{className:"mt-4 flex flex-wrap items-center gap-2",children:[(V=(H=s.agentCard)==null?void 0:H.teams)==null?void 0:V.map(y=>e.jsx(v,{variant:"secondary",className:"text-xs",children:y},y)),(G=(B=s.agentCard)==null?void 0:B.projectGroups)==null?void 0:G.map(y=>e.jsx(v,{variant:"outline",className:"text-xs",children:y},y))]})]}),e.jsxs(ke,{to:"/agents",className:"absolute top-4 left-4 inline-flex items-center gap-1.5 rounded-lg bg-card/80 px-2.5 py-1.5 text-xs font-medium text-muted-foreground backdrop-blur-sm transition-colors hover:text-foreground",children:[e.jsx(Me,{className:"size-3.5"}),"Agents"]})]}),e.jsx(q,{open:n,onOpenChange:a,children:e.jsxs(D,{children:[e.jsxs(M,{children:[e.jsx(I,{children:"Remove agent"}),e.jsxs(_,{children:["This will set"," ",e.jsx("span",{className:"font-medium text-foreground",children:s.displayName})," ","to offline. The agent can re-register at any time."]})]}),e.jsxs(O,{children:[e.jsx(h,{variant:"outline",onClick:()=>a(!1),disabled:l,children:"Cancel"}),e.jsx(h,{variant:"destructive",disabled:l,onClick:()=>{r(),a(!1)},children:l?"Removing…":"Remove Agent"})]})]})})]})}function ts({agentId:s}){const[r,l]=p.useState(!1),n=T({queryKey:["agent-card",s],queryFn:async()=>{const o=await fetch(`${g}/agents/${s}/card`);if(!o.ok)throw new Error("Failed to fetch agent card");return(await o.json()).data},staleTime:3e4,retry:1});if(n.isLoading)return e.jsx(rs,{});if(n.isError||!n.data)return e.jsxs("div",{className:"flex flex-col items-center justify-center rounded-xl border border-dashed border-border/60 py-16",children:[e.jsx(W,{className:"size-10 text-muted-foreground/40"}),e.jsx("p",{className:"mt-3 text-sm text-muted-foreground",children:"No Agent Card available"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground/60",children:"This agent hasn't published an A2A Agent Card yet."})]});const a=n.data;return e.jsxs("div",{className:"grid gap-5 lg:grid-cols-2",children:[e.jsxs(b,{className:"gap-0 py-0",children:[e.jsx(w,{className:"border-b px-5 py-4",children:e.jsxs(C,{className:"flex items-center gap-2 text-sm",children:[e.jsx(Qe,{className:"size-4 text-amber-500"}),"Description"]})}),e.jsxs(k,{className:"px-5 py-4",children:[e.jsx("p",{className:"text-sm leading-relaxed text-muted-foreground",children:a.description||"No description provided."}),e.jsxs("div",{className:"mt-4 flex flex-wrap items-center gap-3 text-xs text-muted-foreground",children:[a.version&&e.jsxs("span",{className:"inline-flex items-center gap-1.5 rounded-md bg-muted px-2 py-1 font-mono",children:["v",a.version]}),a.url&&e.jsxs("a",{href:a.url,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 rounded-md bg-muted px-2 py-1 transition-colors hover:text-foreground",children:[e.jsx(qe,{className:"size-3"}),a.url]})]})]})]}),e.jsxs(b,{className:"gap-0 py-0",children:[e.jsx(w,{className:"border-b px-5 py-4",children:e.jsxs(C,{className:"flex items-center gap-2 text-sm",children:[e.jsx(Ve,{className:"size-4 text-blue-500"}),"Skills",a.skills.length>0&&e.jsx(v,{variant:"secondary",className:"ml-auto text-[10px]",children:a.skills.length})]})}),e.jsx(k,{className:"px-5 py-4",children:a.skills.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No skills declared."}):e.jsx("div",{className:"space-y-3",children:a.skills.map(o=>e.jsxs("div",{className:"group",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(De,{className:"size-3.5 shrink-0 text-muted-foreground"}),e.jsx("span",{className:"text-sm font-medium",children:o.name})]}),e.jsx("p",{className:"ml-5.5 mt-0.5 text-xs leading-relaxed text-muted-foreground",children:o.description}),o.tags.length>0&&e.jsx("div",{className:"ml-5.5 mt-1.5 flex flex-wrap gap-1",children:o.tags.map(i=>e.jsxs(v,{variant:"outline",className:"text-[10px] font-normal",children:[e.jsx(He,{className:"mr-0.5 size-2.5"}),i]},i))})]},o.id))})})]}),e.jsxs(b,{className:"gap-0 py-0 lg:col-span-2",children:[e.jsx(w,{className:"px-5 py-4",children:e.jsxs("button",{type:"button",onClick:()=>l(o=>!o),className:"flex w-full items-center gap-2 text-left",children:[e.jsxs(C,{className:"flex items-center gap-2 text-sm",children:[e.jsx(W,{className:"size-4 text-muted-foreground"}),"Raw Agent Card"]}),r?e.jsx(Ie,{className:"ml-auto size-4 text-muted-foreground"}):e.jsx(Ke,{className:"ml-auto size-4 text-muted-foreground"})]})}),r&&e.jsxs(e.Fragment,{children:[e.jsx(z,{}),e.jsx(k,{className:"px-5 py-4",children:e.jsx("pre",{className:"max-h-96 overflow-auto rounded-lg bg-muted/60 p-4 font-mono text-xs leading-relaxed text-foreground/80",children:JSON.stringify(a,null,2)})})]})]})]})}function rs(){return e.jsxs("div",{className:"grid gap-5 lg:grid-cols-2",children:[e.jsx(c,{className:"h-48 rounded-xl"}),e.jsx(c,{className:"h-48 rounded-xl"}),e.jsx(c,{className:"h-20 rounded-xl lg:col-span-2"})]})}const Z={notification:{label:"Notification",variant:"secondary"},query:{label:"Query",variant:"default"},response:{label:"Response",variant:"outline"},broadcast:{label:"Broadcast",variant:"secondary"}};function ns({agentId:s}){const r=T({queryKey:["agent-messages",s],queryFn:async()=>{const n=await fetch(`${g}/messages?agentId=${s}&limit=20`);if(!n.ok)throw new Error("Failed to fetch messages");return(await n.json()).data},staleTime:3e4,refetchInterval:15e3,retry:1});if(r.isLoading)return e.jsx(is,{});const l=r.data??[];return l.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center rounded-xl border border-dashed border-border/60 py-16",children:[e.jsx(se,{className:"size-10 text-muted-foreground/40"}),e.jsx("p",{className:"mt-3 text-sm text-muted-foreground",children:"No activity yet"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground/60",children:"Messages sent to or from this agent will appear here."})]}):e.jsx("div",{className:"space-y-1",children:l.map(n=>{const a=n.from===s,o=Z[n.type]??Z.notification;return e.jsxs("div",{className:"group flex items-start gap-3 rounded-lg px-3 py-3 transition-colors hover:bg-muted/40",children:[e.jsx("div",{className:"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted",children:a?e.jsx(Oe,{className:"size-4 text-blue-500"}):e.jsx(_e,{className:"size-4 text-emerald-500"})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{className:"text-xs font-medium text-muted-foreground",children:[a?"Sent to":"Received from"," ",e.jsx("span",{className:"font-semibold text-foreground",children:a?n.to:n.from})]}),e.jsx(v,{variant:o.variant,className:"text-[9px] leading-tight",children:o.label}),e.jsx("span",{className:"ml-auto text-[10px] text-muted-foreground/60",children:te(n.createdAt)})]}),e.jsx("p",{className:"mt-1 line-clamp-2 text-sm text-foreground/80",children:n.content})]})]},n.id)})})}function is(){return e.jsx("div",{className:"space-y-2",children:Array.from({length:5}).map((s,r)=>e.jsxs("div",{className:"flex items-start gap-3 px-3 py-3",children:[e.jsx(c,{className:"size-8 rounded-lg"}),e.jsxs("div",{className:"flex-1 space-y-2",children:[e.jsx(c,{className:"h-3 w-48"}),e.jsx(c,{className:"h-4 w-full"})]})]},r))})}function os({agent:s}){S();const r=T({queryKey:["teams"],queryFn:async()=>{const t=await fetch(`${g}/teams`);if(!t.ok)throw new Error("Failed to fetch teams");return(await t.json()).data},staleTime:6e4,retry:1}),l=T({queryKey:["projects"],queryFn:async()=>{const t=await fetch(`${g}/projects`);if(!t.ok)throw new Error("Failed to fetch projects");return(await t.json()).data},staleTime:6e4,retry:1}),n=r.data??[],a=l.data??[],o=n.filter(t=>t.agentIds.includes(s.id)),i=a.filter(t=>t.agentIds.includes(s.id)),d=n.filter(t=>!t.agentIds.includes(s.id)),x=a.filter(t=>!t.agentIds.includes(s.id));return e.jsxs("div",{className:"grid gap-5 lg:grid-cols-2",children:[e.jsx(ls,{agent:s,agentTeams:o,availableTeams:d,isLoading:r.isLoading}),e.jsx(ds,{agent:s,agentProjects:i,availableProjects:x,isLoading:l.isLoading})]})}function ls({agent:s,agentTeams:r,availableTeams:l,isLoading:n}){const a=S(),[o,i]=p.useState(!1),d=A({mutationFn:async t=>{if(!(await fetch(`${g}/teams/${t}/agents`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agentId:s.id})})).ok)throw new Error("Failed to add agent to team")},onSuccess:()=>{a.invalidateQueries({queryKey:["teams"]}),a.invalidateQueries({queryKey:["agents"]}),f.success("Added to team"),i(!1)},onError:()=>f.error("Failed to add to team")}),x=A({mutationFn:async t=>{if(!(await fetch(`${g}/teams/${t}/agents/${s.id}`,{method:"DELETE"})).ok)throw new Error("Failed to remove agent from team")},onSuccess:()=>{a.invalidateQueries({queryKey:["teams"]}),a.invalidateQueries({queryKey:["agents"]}),f.success("Removed from team")},onError:()=>f.error("Failed to remove from team")});return e.jsxs(e.Fragment,{children:[e.jsxs(b,{className:"gap-0 py-0",children:[e.jsx(w,{className:"border-b px-5 py-4",children:e.jsxs(C,{className:"flex items-center gap-2 text-sm",children:[e.jsx(U,{className:"size-4 text-violet-500"}),"Teams",e.jsx(v,{variant:"secondary",className:"ml-auto text-[10px]",children:r.length})]})}),e.jsxs(k,{className:"px-5 py-4",children:[n?e.jsxs("div",{className:"space-y-2",children:[e.jsx(c,{className:"h-8 w-full"}),e.jsx(c,{className:"h-8 w-2/3"})]}):r.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Not assigned to any teams."}):e.jsx("div",{className:"space-y-2",children:r.map(t=>e.jsxs("div",{className:"flex items-center justify-between rounded-lg bg-muted/40 px-3 py-2",children:[e.jsx("span",{className:"text-sm font-medium",children:t.name}),e.jsx(h,{variant:"ghost",size:"icon-xs",onClick:()=>x.mutate(t.id),disabled:x.isPending,children:e.jsx(ae,{className:"size-3.5"})})]},t.id))}),e.jsxs(h,{variant:"outline",size:"sm",className:"mt-4 w-full",onClick:()=>i(!0),disabled:l.length===0,children:[e.jsx(re,{className:"size-4"}),"Add to Team"]})]})]}),e.jsx(q,{open:o,onOpenChange:i,children:e.jsxs(D,{children:[e.jsxs(M,{children:[e.jsx(I,{children:"Add to team"}),e.jsxs(_,{children:["Select a team to add"," ",e.jsx("span",{className:"font-medium text-foreground",children:s.displayName})," ","to."]})]}),e.jsx("div",{className:"max-h-64 space-y-1 overflow-y-auto",children:l.map(t=>e.jsxs("button",{type:"button",onClick:()=>d.mutate(t.id),disabled:d.isPending,className:"flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left transition-colors hover:bg-muted",children:[e.jsx(U,{className:"size-4 shrink-0 text-muted-foreground"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("p",{className:"text-sm font-medium",children:t.name}),t.description&&e.jsx("p",{className:"truncate text-xs text-muted-foreground",children:t.description})]}),d.isPending&&e.jsx(ne,{className:"size-4 animate-spin text-muted-foreground"})]},t.id))}),e.jsx(O,{children:e.jsx(h,{variant:"outline",onClick:()=>i(!1),children:"Cancel"})})]})})]})}function ds({agent:s,agentProjects:r,availableProjects:l,isLoading:n}){const a=S(),[o,i]=p.useState(!1),d=A({mutationFn:async t=>{if(!(await fetch(`${g}/projects/${t}/agents`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agentId:s.id})})).ok)throw new Error("Failed to add agent to project")},onSuccess:()=>{a.invalidateQueries({queryKey:["projects"]}),a.invalidateQueries({queryKey:["agents"]}),f.success("Added to project"),i(!1)},onError:()=>f.error("Failed to add to project")}),x=A({mutationFn:async t=>{if(!(await fetch(`${g}/projects/${t}/agents/${s.id}`,{method:"DELETE"})).ok)throw new Error("Failed to remove agent from project")},onSuccess:()=>{a.invalidateQueries({queryKey:["projects"]}),a.invalidateQueries({queryKey:["agents"]}),f.success("Removed from project")},onError:()=>f.error("Failed to remove from project")});return e.jsxs(e.Fragment,{children:[e.jsxs(b,{className:"gap-0 py-0",children:[e.jsx(w,{className:"border-b px-5 py-4",children:e.jsxs(C,{className:"flex items-center gap-2 text-sm",children:[e.jsx(X,{className:"size-4 text-teal-500"}),"Projects",e.jsx(v,{variant:"secondary",className:"ml-auto text-[10px]",children:r.length})]})}),e.jsxs(k,{className:"px-5 py-4",children:[n?e.jsxs("div",{className:"space-y-2",children:[e.jsx(c,{className:"h-8 w-full"}),e.jsx(c,{className:"h-8 w-2/3"})]}):r.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Not assigned to any projects."}):e.jsx("div",{className:"space-y-2",children:r.map(t=>e.jsxs("div",{className:"flex items-center justify-between rounded-lg bg-muted/40 px-3 py-2",children:[e.jsx("span",{className:"text-sm font-medium",children:t.name}),e.jsx(h,{variant:"ghost",size:"icon-xs",onClick:()=>x.mutate(t.id),disabled:x.isPending,children:e.jsx(ae,{className:"size-3.5"})})]},t.id))}),e.jsxs(h,{variant:"outline",size:"sm",className:"mt-4 w-full",onClick:()=>i(!0),disabled:l.length===0,children:[e.jsx(re,{className:"size-4"}),"Add to Project"]})]})]}),e.jsx(q,{open:o,onOpenChange:i,children:e.jsxs(D,{children:[e.jsxs(M,{children:[e.jsx(I,{children:"Add to project"}),e.jsxs(_,{children:["Select a project to add"," ",e.jsx("span",{className:"font-medium text-foreground",children:s.displayName})," ","to."]})]}),e.jsx("div",{className:"max-h-64 space-y-1 overflow-y-auto",children:l.map(t=>e.jsxs("button",{type:"button",onClick:()=>d.mutate(t.id),disabled:d.isPending,className:"flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left transition-colors hover:bg-muted",children:[e.jsx(X,{className:"size-4 shrink-0 text-muted-foreground"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("p",{className:"text-sm font-medium",children:t.name}),t.description&&e.jsx("p",{className:"truncate text-xs text-muted-foreground",children:t.description})]}),d.isPending&&e.jsx(ne,{className:"size-4 animate-spin text-muted-foreground"})]},t.id))}),e.jsx(O,{children:e.jsx(h,{variant:"outline",onClick:()=>i(!1),children:"Cancel"})})]})})]})}function cs({agentId:s}){const r=S(),l=ee(),n=T({queryKey:["agent",s],queryFn:async()=>{const i=await fetch(`${g}/agents/${s}`);if(!i.ok)throw new Error("Failed to fetch agent");return(await i.json()).data},staleTime:3e4,refetchInterval:1e4,retry:1}),a=A({mutationFn:async()=>{if(!(await fetch(`${g}/agents/${s}`,{method:"DELETE"})).ok)throw new Error("Failed to remove agent")},onSuccess:()=>{r.invalidateQueries({queryKey:["agents"]}),f.success("Agent removed"),l({to:"/agents"})},onError:()=>{f.error("Failed to remove agent")}});if(n.isLoading)return e.jsx(ms,{});if(n.isError||!n.data)return e.jsxs("div",{className:"flex flex-1 flex-col items-center justify-center gap-4 p-4 sm:p-8",children:[e.jsx("div",{className:"flex size-16 items-center justify-center rounded-2xl bg-muted",children:e.jsx(Te,{className:"size-8 text-muted-foreground"})}),e.jsxs("div",{className:"text-center",children:[e.jsx("h2",{className:"text-lg font-semibold",children:"Agent not found"}),e.jsx("p",{className:"mt-1 text-sm text-muted-foreground",children:"This agent may have been removed or the ID is invalid."})]})]});const o=n.data;return e.jsxs("div",{className:"flex flex-col gap-6 p-4 sm:p-6",children:[e.jsx(as,{agent:o,onDelete:()=>a.mutate(),isDeleting:a.isPending}),e.jsxs(Ye,{defaultValue:"overview",children:[e.jsxs(ss,{variant:"line",children:[e.jsx(L,{value:"overview",children:"Agent Card"}),e.jsx(L,{value:"activity",children:"Activity"}),e.jsx(L,{value:"management",children:"Management"})]}),e.jsx(R,{value:"overview",className:"mt-4",children:e.jsx(ts,{agentId:s})}),e.jsx(R,{value:"activity",className:"mt-4",children:e.jsx(ns,{agentId:s})}),e.jsx(R,{value:"management",className:"mt-4",children:e.jsx(os,{agent:o})})]})]})}function ms(){return e.jsxs("div",{className:"flex flex-col gap-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"overflow-hidden rounded-xl border border-border/60",children:[e.jsx(c,{className:"h-24 w-full rounded-none"}),e.jsxs("div",{className:"px-6 pb-6",children:[e.jsxs("div",{className:"-mt-10 flex items-end gap-5",children:[e.jsx(c,{className:"size-20 rounded-2xl"}),e.jsxs("div",{className:"flex-1 space-y-2 pt-1",children:[e.jsx(c,{className:"h-6 w-48"}),e.jsx(c,{className:"h-4 w-32"})]})]}),e.jsxs("div",{className:"mt-5 flex gap-4",children:[e.jsx(c,{className:"h-4 w-40"}),e.jsx(c,{className:"h-4 w-20"}),e.jsx(c,{className:"h-4 w-24"})]})]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(c,{className:"h-9 w-24"}),e.jsx(c,{className:"h-9 w-24"}),e.jsx(c,{className:"h-9 w-28"})]}),e.jsxs("div",{className:"grid gap-5 lg:grid-cols-2",children:[e.jsx(c,{className:"h-48 rounded-xl"}),e.jsx(c,{className:"h-48 rounded-xl"})]})]})}function ws(){const{agentId:s}=Ae.useParams();return e.jsx(ze,{featureName:"Agent Detail",children:e.jsx(cs,{agentId:s})})}export{ws as component};
@@ -1 +0,0 @@
1
- import{r as u,j as d,I as w,a1 as E,N,Q as j,R as f,x as v}from"./index-DqvmWes8.js";var y=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","select","span","svg","ul"],g=y.reduce((t,a)=>{const s=w(`Primitive.${a}`),r=u.forwardRef((n,e)=>{const{asChild:l,...o}=n,i=l?s:a;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),d.jsx(i,{...o,ref:e})});return r.displayName=`Primitive.${a}`,{...t,[a]:r}},{}),C=E();function R(){return C.useSyncExternalStore(k,()=>!0,()=>!1)}function k(){return()=>{}}var m="Avatar",[I]=N(m),[_,A]=I(m),S=u.forwardRef((t,a)=>{const{__scopeAvatar:s,...r}=t,[n,e]=u.useState("idle");return d.jsx(_,{scope:s,imageLoadingStatus:n,onImageLoadingStatusChange:e,children:d.jsx(g.span,{...r,ref:a})})});S.displayName=m;var h="AvatarImage",P=u.forwardRef((t,a)=>{const{__scopeAvatar:s,src:r,onLoadingStatusChange:n=()=>{},...e}=t,l=A(h,s),o=F(r,e),i=j(c=>{n(c),l.onImageLoadingStatusChange(c)});return f(()=>{o!=="idle"&&i(o)},[o,i]),o==="loaded"?d.jsx(g.img,{...e,ref:a,src:r}):null});P.displayName=h;var L="AvatarFallback",z=u.forwardRef((t,a)=>{const{__scopeAvatar:s,delayMs:r,...n}=t,e=A(L,s),[l,o]=u.useState(r===void 0);return u.useEffect(()=>{if(r!==void 0){const i=window.setTimeout(()=>o(!0),r);return()=>window.clearTimeout(i)}},[r]),l&&e.imageLoadingStatus!=="loaded"?d.jsx(g.span,{...n,ref:a}):null});z.displayName=L;function x(t,a){return t?a?(t.src!==a&&(t.src=a),t.complete&&t.naturalWidth>0?"loaded":"loading"):"error":"idle"}function F(t,{referrerPolicy:a,crossOrigin:s}){const r=R(),n=u.useRef(null),e=r?(n.current||(n.current=new window.Image),n.current):null,[l,o]=u.useState(()=>x(e,t));return f(()=>{o(x(e,t))},[e,t]),f(()=>{const i=b=>()=>{o(b)};if(!e)return;const c=i("loaded"),p=i("error");return e.addEventListener("load",c),e.addEventListener("error",p),a&&(e.referrerPolicy=a),typeof s=="string"&&(e.crossOrigin=s),()=>{e.removeEventListener("load",c),e.removeEventListener("error",p)}},[e,s,a]),l}var M=S,$=z;function T({className:t,size:a="default",...s}){return d.jsx(M,{"data-slot":"avatar","data-size":a,className:v("group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",t),...s})}function H({className:t,...a}){return d.jsx($,{"data-slot":"avatar-fallback",className:v("bg-muted text-muted-foreground flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs",t),...a})}function q({className:t,...a}){return d.jsx("div",{"data-slot":"avatar-group",className:v("*:data-[slot=avatar]:ring-background group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2",t),...a})}function B({className:t,...a}){return d.jsx("div",{"data-slot":"avatar-group-count",className:v("bg-muted text-muted-foreground ring-background relative flex size-8 shrink-0 items-center justify-center rounded-full text-sm ring-2 group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",t),...a})}export{q as A,T as a,H as b,B as c};