agentix-cli 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +12 -6
  2. package/dist/{agent-LRSSVFDR.js → agent-BCDPSPKU.js} +2 -2
  3. package/dist/{board-dashboard-DAPHL6W2.js → board-dashboard-LA7WW56M.js} +1227 -67
  4. package/dist/board-dashboard-LA7WW56M.js.map +1 -0
  5. package/dist/chunk-5F3J55LG.js +2 -0
  6. package/dist/chunk-5F3J55LG.js.map +1 -0
  7. package/dist/chunk-64P4QHSZ.js +2 -0
  8. package/dist/chunk-64P4QHSZ.js.map +1 -0
  9. package/dist/chunk-7FJQGD6U.js +6 -0
  10. package/dist/chunk-7FJQGD6U.js.map +1 -0
  11. package/dist/chunk-ABDP7TDL.js +71 -0
  12. package/dist/chunk-ABDP7TDL.js.map +1 -0
  13. package/dist/chunk-BFZUG66X.js +45 -0
  14. package/dist/chunk-BFZUG66X.js.map +1 -0
  15. package/dist/{chunk-RGUYBH77.js → chunk-FLOGK2U7.js} +2 -2
  16. package/dist/{chunk-AU37OREL.js → chunk-HVC6FJNP.js} +2 -2
  17. package/dist/chunk-K7BE4E35.js +138 -0
  18. package/dist/chunk-K7BE4E35.js.map +1 -0
  19. package/dist/{chunk-3XULOWYB.js → chunk-KXJSLLSQ.js} +2 -2
  20. package/dist/chunk-LEIYC3BF.js +104 -0
  21. package/dist/chunk-LEIYC3BF.js.map +1 -0
  22. package/dist/chunk-WZEYII2S.js +6 -0
  23. package/dist/chunk-WZEYII2S.js.map +1 -0
  24. package/dist/{chunk-HLRVDCNH.js → chunk-YI2T5QYB.js} +2 -2
  25. package/dist/cli.js +208 -190
  26. package/dist/cli.js.map +1 -1
  27. package/dist/{config-DCJYECL4.js → config-LN6JEHMF.js} +2 -2
  28. package/dist/config-mutator-24TH7PHM.js +2 -0
  29. package/dist/index.d.ts +854 -12
  30. package/dist/index.js +47 -44
  31. package/dist/index.js.map +1 -1
  32. package/dist/query-PKGYE5HR.js +2 -0
  33. package/dist/registry-ASC2QS5K.js +2 -0
  34. package/dist/scheduler-A3TQOCKT.js +2 -0
  35. package/dist/scheduler-A3TQOCKT.js.map +1 -0
  36. package/dist/types-OIFU3KSQ.js +2 -0
  37. package/dist/types-OIFU3KSQ.js.map +1 -0
  38. package/dist/wiki-UDPYFJBL.js +2 -0
  39. package/dist/wiki-UDPYFJBL.js.map +1 -0
  40. package/package.json +2 -2
  41. package/dist/board-dashboard-DAPHL6W2.js.map +0 -1
  42. package/dist/chunk-B4Q4X7D5.js +0 -6
  43. package/dist/chunk-B4Q4X7D5.js.map +0 -1
  44. package/dist/chunk-IEVEMKAI.js +0 -168
  45. package/dist/chunk-IEVEMKAI.js.map +0 -1
  46. package/dist/chunk-WVNSWBCU.js +0 -138
  47. package/dist/chunk-WVNSWBCU.js.map +0 -1
  48. package/dist/config-mutator-6EJHSP3Y.js +0 -2
  49. package/dist/registry-5ND7GLFJ.js +0 -2
  50. package/dist/scheduler-FCXOXCN5.js +0 -2
  51. /package/dist/{agent-LRSSVFDR.js.map → agent-BCDPSPKU.js.map} +0 -0
  52. /package/dist/{chunk-RGUYBH77.js.map → chunk-FLOGK2U7.js.map} +0 -0
  53. /package/dist/{chunk-AU37OREL.js.map → chunk-HVC6FJNP.js.map} +0 -0
  54. /package/dist/{chunk-3XULOWYB.js.map → chunk-KXJSLLSQ.js.map} +0 -0
  55. /package/dist/{chunk-HLRVDCNH.js.map → chunk-YI2T5QYB.js.map} +0 -0
  56. /package/dist/{config-DCJYECL4.js.map → config-LN6JEHMF.js.map} +0 -0
  57. /package/dist/{config-mutator-6EJHSP3Y.js.map → config-mutator-24TH7PHM.js.map} +0 -0
  58. /package/dist/{registry-5ND7GLFJ.js.map → query-PKGYE5HR.js.map} +0 -0
  59. /package/dist/{scheduler-FCXOXCN5.js.map → registry-ASC2QS5K.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import{a as x,b as re,c as ie,d as se,e as T,f as B,g as le}from"./chunk-3XULOWYB.js";import{a as oe}from"./chunk-6U2XOQHU.js";import{a as te,b as ae,c as Re,f as U,h as He,i as ne}from"./chunk-B4Q4X7D5.js";import{a as ee,d as Oe}from"./chunk-FIOB3MEX.js";Re();import{createServer as _t}from"http";import{appendFileSync as Mt,existsSync as $t,mkdirSync as It}from"fs";import{resolve as Ie}from"path";var ce='/*! Sortable 1.15.2 - MIT | git://github.com/SortableJS/Sortable.git */\n!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function e(e,t){var n,o=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),o.push.apply(o,n)),o}function I(o){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?e(Object(i),!0).forEach(function(t){var e,n;e=o,t=i[n=t],n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t}):Object.getOwnPropertyDescriptors?Object.defineProperties(o,Object.getOwnPropertyDescriptors(i)):e(Object(i)).forEach(function(t){Object.defineProperty(o,t,Object.getOwnPropertyDescriptor(i,t))})}return o}function o(t){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function a(){return(a=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n,o=arguments[e];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(t[n]=o[n])}return t}).apply(this,arguments)}function i(t,e){if(null==t)return{};var n,o=function(t,e){if(null==t)return{};for(var n,o={},i=Object.keys(t),r=0;r<i.length;r++)n=i[r],0<=e.indexOf(n)||(o[n]=t[n]);return o}(t,e);if(Object.getOwnPropertySymbols)for(var i=Object.getOwnPropertySymbols(t),r=0;r<i.length;r++)n=i[r],0<=e.indexOf(n)||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n]);return o}function r(t){return function(t){if(Array.isArray(t))return l(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return l(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Map"===(n="Object"===n&&t.constructor?t.constructor.name:n)||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?l(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var y=t(/(?:Trident.*rv[ :]?11\\.|msie|iemobile|Windows Phone)/i),w=t(/Edge/i),s=t(/firefox/i),u=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),n=t(/iP(ad|od|hone)/i),c=t(/chrome/i)&&t(/android/i),d={capture:!1,passive:!1};function h(t,e,n){t.addEventListener(e,n,!y&&d)}function f(t,e,n){t.removeEventListener(e,n,!y&&d)}function p(t,e){if(e&&(">"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&p(t,e)||o&&t===n)return t}while(t!==n&&(t=(i=t).host&&i!==document&&i.host.nodeType?i.host:i.parentNode))}var i;return null}var g,m=/\\s+/g;function k(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(m," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(m," ")))}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function v(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function b(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i<r;i++)n(o[i],i);return o}return[]}function O(){var t=document.scrollingElement;return t||document.documentElement}function X(t,e,n,o,i){if(t.getBoundingClientRect||t===window){var r,a,l,s,c,u,d=t!==window&&t.parentNode&&t!==O()?(a=(r=t.getBoundingClientRect()).top,l=r.left,s=r.bottom,c=r.right,u=r.height,r.width):(l=a=0,s=window.innerHeight,c=window.innerWidth,u=window.innerHeight,window.innerWidth);if((e||n)&&t!==window&&(i=i||t.parentNode,!y))do{if(i&&i.getBoundingClientRect&&("none"!==R(i,"transform")||n&&"static"!==R(i,"position"))){var h=i.getBoundingClientRect();a-=h.top+parseInt(R(i,"border-top-width")),l-=h.left+parseInt(R(i,"border-left-width")),s=a+r.height,c=l+r.width;break}}while(i=i.parentNode);return o&&t!==window&&(o=(e=v(i||t))&&e.a,t=e&&e.d,e&&(s=(a/=t)+(u/=t),c=(l/=o)+(d/=o))),{top:a,left:l,bottom:s,right:c,width:d,height:u}}}function Y(t,e,n){for(var o=M(t,!0),i=X(t)[e];o;){var r=X(o)[n];if(!("top"===n||"left"===n?r<=i:i<=r))return o;if(o===O())break;o=M(o,!1)}return!1}function B(t,e,n,o){for(var i=0,r=0,a=t.children;r<a.length;){if("none"!==a[r].style.display&&a[r]!==Ft.ghost&&(o||a[r]!==Ft.dragged)&&P(a[r],n.draggable,t,!1)){if(i===e)return a[r];i++}r++}return null}function F(t,e){for(var n=t.lastElementChild;n&&(n===Ft.ghost||"none"===R(n,"display")||e&&!p(n,e));)n=n.previousElementSibling;return n||null}function j(t,e){var n=0;if(!t||!t.parentNode)return-1;for(;t=t.previousElementSibling;)"TEMPLATE"===t.nodeName.toUpperCase()||t===Ft.clone||e&&!p(t,e)||n++;return n}function E(t){var e=0,n=0,o=O();if(t)do{var i=v(t),r=i.a,i=i.d}while(e+=t.scrollLeft*r,n+=t.scrollTop*i,t!==o&&(t=t.parentNode));return[e,n]}function M(t,e){if(!t||!t.getBoundingClientRect)return O();var n=t,o=!1;do{if(n.clientWidth<n.scrollWidth||n.clientHeight<n.scrollHeight){var i=R(n);if(n.clientWidth<n.scrollWidth&&("auto"==i.overflowX||"scroll"==i.overflowX)||n.clientHeight<n.scrollHeight&&("auto"==i.overflowY||"scroll"==i.overflowY)){if(!n.getBoundingClientRect||n===document.body)return O();if(o||e)return n;o=!0}}}while(n=n.parentNode);return O()}function D(t,e){return Math.round(t.top)===Math.round(e.top)&&Math.round(t.left)===Math.round(e.left)&&Math.round(t.height)===Math.round(e.height)&&Math.round(t.width)===Math.round(e.width)}function S(e,n){return function(){var t;g||(1===(t=arguments).length?e.call(this,t[0]):e.apply(this,t),g=setTimeout(function(){g=void 0},n))}}function H(t,e,n){t.scrollLeft+=e,t.scrollTop+=n}function _(t){var e=window.Polymer,n=window.jQuery||window.Zepto;return e&&e.dom?e.dom(t).cloneNode(!0):n?n(t).clone(!0)[0]:t.cloneNode(!0)}function C(t,e){R(t,"position","absolute"),R(t,"top",e.top),R(t,"left",e.left),R(t,"width",e.width),R(t,"height",e.height)}function T(t){R(t,"position",""),R(t,"top",""),R(t,"left",""),R(t,"width",""),R(t,"height","")}function L(n,o,i){var r={};return Array.from(n.children).forEach(function(t){var e;P(t,o.draggable,n,!1)&&!t.animated&&t!==i&&(e=X(t),r.left=Math.min(null!==(t=r.left)&&void 0!==t?t:1/0,e.left),r.top=Math.min(null!==(t=r.top)&&void 0!==t?t:1/0,e.top),r.right=Math.max(null!==(t=r.right)&&void 0!==t?t:-1/0,e.right),r.bottom=Math.max(null!==(t=r.bottom)&&void 0!==t?t:-1/0,e.bottom))}),r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}var K="Sortable"+(new Date).getTime();function x(){var e,o=[];return{captureAnimationState:function(){o=[],this.options.animation&&[].slice.call(this.el.children).forEach(function(t){var e,n;"none"!==R(t,"display")&&t!==Ft.ghost&&(o.push({target:t,rect:X(t)}),e=I({},o[o.length-1].rect),!t.thisAnimationDuration||(n=v(t,!0))&&(e.top-=n.f,e.left-=n.e),t.fromRect=e)})},addAnimationState:function(t){o.push(t)},removeAnimationState:function(t){o.splice(function(t,e){for(var n in t)if(t.hasOwnProperty(n))for(var o in e)if(e.hasOwnProperty(o)&&e[o]===t[n][o])return Number(n);return-1}(o,{target:t}),1)},animateAll:function(t){var c=this;if(!this.options.animation)return clearTimeout(e),void("function"==typeof t&&t());var u=!1,d=0;o.forEach(function(t){var e=0,n=t.target,o=n.fromRect,i=X(n),r=n.prevFromRect,a=n.prevToRect,l=t.rect,s=v(n,!0);s&&(i.top-=s.f,i.left-=s.e),n.toRect=i,n.thisAnimationDuration&&D(r,i)&&!D(o,i)&&(l.top-i.top)/(l.left-i.left)==(o.top-i.top)/(o.left-i.left)&&(t=l,s=r,r=a,a=c.options,e=Math.sqrt(Math.pow(s.top-t.top,2)+Math.pow(s.left-t.left,2))/Math.sqrt(Math.pow(s.top-r.top,2)+Math.pow(s.left-r.left,2))*a.animation),D(i,o)||(n.prevFromRect=o,n.prevToRect=i,e=e||c.options.animation,c.animate(n,l,i,e)),e&&(u=!0,d=Math.max(d,e),clearTimeout(n.animationResetTimer),n.animationResetTimer=setTimeout(function(){n.animationTime=0,n.prevFromRect=null,n.fromRect=null,n.prevToRect=null,n.thisAnimationDuration=null},e),n.thisAnimationDuration=e)}),clearTimeout(e),u?e=setTimeout(function(){"function"==typeof t&&t()},d):"function"==typeof t&&t(),o=[]},animate:function(t,e,n,o){var i,r;o&&(R(t,"transition",""),R(t,"transform",""),i=(r=v(this.el))&&r.a,r=r&&r.d,i=(e.left-n.left)/(i||1),r=(e.top-n.top)/(r||1),t.animatingX=!!i,t.animatingY=!!r,R(t,"transform","translate3d("+i+"px,"+r+"px,0)"),this.forRepaintDummy=t.offsetWidth,R(t,"transition","transform "+o+"ms"+(this.options.easing?" "+this.options.easing:"")),R(t,"transform","translate3d(0,0,0)"),"number"==typeof t.animated&&clearTimeout(t.animated),t.animated=setTimeout(function(){R(t,"transition",""),R(t,"transform",""),t.animated=!1,t.animatingX=!1,t.animatingY=!1},o))}}}var A=[],N={initializeByDefault:!0},W={mount:function(e){for(var t in N)!N.hasOwnProperty(t)||t in e||(e[t]=N[t]);A.forEach(function(t){if(t.pluginName===e.pluginName)throw"Sortable: Cannot mount plugin ".concat(e.pluginName," more than once")}),A.push(e)},pluginEvent:function(e,n,o){var t=this;this.eventCanceled=!1,o.cancel=function(){t.eventCanceled=!0};var i=e+"Global";A.forEach(function(t){n[t.pluginName]&&(n[t.pluginName][i]&&n[t.pluginName][i](I({sortable:n},o)),n.options[t.pluginName]&&n[t.pluginName][e]&&n[t.pluginName][e](I({sortable:n},o)))})},initializePlugins:function(n,o,i,t){for(var e in A.forEach(function(t){var e=t.pluginName;(n.options[e]||t.initializeByDefault)&&((t=new t(n,o,n.options)).sortable=n,t.options=n.options,n[e]=t,a(i,t.defaults))}),n.options){var r;n.options.hasOwnProperty(e)&&(void 0!==(r=this.modifyOption(n,e,n.options[e]))&&(n.options[e]=r))}},getEventProperties:function(e,n){var o={};return A.forEach(function(t){"function"==typeof t.eventProperties&&a(o,t.eventProperties.call(n[t.pluginName],e))}),o},modifyOption:function(e,n,o){var i;return A.forEach(function(t){e[t.pluginName]&&t.optionListeners&&"function"==typeof t.optionListeners[n]&&(i=t.optionListeners[n].call(e[t.pluginName],o))}),i}};function z(t){var e=t.sortable,n=t.rootEl,o=t.name,i=t.targetEl,r=t.cloneEl,a=t.toEl,l=t.fromEl,s=t.oldIndex,c=t.newIndex,u=t.oldDraggableIndex,d=t.newDraggableIndex,h=t.originalEvent,f=t.putSortable,p=t.extraEventProperties;if(e=e||n&&n[K]){var g,m=e.options,t="on"+o.charAt(0).toUpperCase()+o.substr(1);!window.CustomEvent||y||w?(g=document.createEvent("Event")).initEvent(o,!0,!0):g=new CustomEvent(o,{bubbles:!0,cancelable:!0}),g.to=a||n,g.from=l||n,g.item=i||n,g.clone=r,g.oldIndex=s,g.newIndex=c,g.oldDraggableIndex=u,g.newDraggableIndex=d,g.originalEvent=h,g.pullMode=f?f.lastPutMode:void 0;var v,b=I(I({},p),W.getEventProperties(o,e));for(v in b)g[v]=b[v];n&&n.dispatchEvent(g),m[t]&&m[t].call(e,g)}}function G(t,e){var n=(o=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{}).evt,o=i(o,U);W.pluginEvent.bind(Ft)(t,e,I({dragEl:V,parentEl:Z,ghostEl:$,rootEl:Q,nextEl:J,lastDownEl:tt,cloneEl:et,cloneHidden:nt,dragStarted:gt,putSortable:st,activeSortable:Ft.active,originalEvent:n,oldIndex:ot,oldDraggableIndex:rt,newIndex:it,newDraggableIndex:at,hideGhostForTarget:Rt,unhideGhostForTarget:Xt,cloneNowHidden:function(){nt=!0},cloneNowShown:function(){nt=!1},dispatchSortableEvent:function(t){q({sortable:e,name:t,originalEvent:n})}},o))}var U=["evt"];function q(t){z(I({putSortable:st,cloneEl:et,targetEl:V,rootEl:Q,oldIndex:ot,oldDraggableIndex:rt,newIndex:it,newDraggableIndex:at},t))}var V,Z,$,Q,J,tt,et,nt,ot,it,rt,at,lt,st,ct,ut,dt,ht,ft,pt,gt,mt,vt,bt,yt,wt=!1,Et=!1,Dt=[],St=!1,_t=!1,Ct=[],Tt=!1,xt=[],Ot="undefined"!=typeof document,Mt=n,At=w||y?"cssFloat":"float",Nt=Ot&&!c&&!n&&"draggable"in document.createElement("div"),It=function(){if(Ot){if(y)return!1;var t=document.createElement("x");return t.style.cssText="pointer-events:auto","auto"===t.style.pointerEvents}}(),Pt=function(t,e){var n=R(t),o=parseInt(n.width)-parseInt(n.paddingLeft)-parseInt(n.paddingRight)-parseInt(n.borderLeftWidth)-parseInt(n.borderRightWidth),i=B(t,0,e),r=B(t,1,e),a=i&&R(i),l=r&&R(r),s=a&&parseInt(a.marginLeft)+parseInt(a.marginRight)+X(i).width,t=l&&parseInt(l.marginLeft)+parseInt(l.marginRight)+X(r).width;if("flex"===n.display)return"column"===n.flexDirection||"column-reverse"===n.flexDirection?"vertical":"horizontal";if("grid"===n.display)return n.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(i&&a.float&&"none"!==a.float){e="left"===a.float?"left":"right";return!r||"both"!==l.clear&&l.clear!==e?"horizontal":"vertical"}return i&&("block"===a.display||"flex"===a.display||"table"===a.display||"grid"===a.display||o<=s&&"none"===n[At]||r&&"none"===n[At]&&o<s+t)?"vertical":"horizontal"},kt=function(t){function l(r,a){return function(t,e,n,o){var i=t.options.group.name&&e.options.group.name&&t.options.group.name===e.options.group.name;if(null==r&&(a||i))return!0;if(null==r||!1===r)return!1;if(a&&"clone"===r)return r;if("function"==typeof r)return l(r(t,e,n,o),a)(t,e,n,o);e=(a?t:e).options.group.name;return!0===r||"string"==typeof r&&r===e||r.join&&-1<r.indexOf(e)}}var e={},n=t.group;n&&"object"==o(n)||(n={name:n}),e.name=n.name,e.checkPull=l(n.pull,!0),e.checkPut=l(n.put),e.revertClone=n.revertClone,t.group=e},Rt=function(){!It&&$&&R($,"display","none")},Xt=function(){!It&&$&&R($,"display","")};Ot&&!c&&document.addEventListener("click",function(t){if(Et)return t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),Et=!1},!0);function Yt(t){if(V){t=t.touches?t.touches[0]:t;var e=(i=t.clientX,r=t.clientY,Dt.some(function(t){var e=t[K].options.emptyInsertThreshold;if(e&&!F(t)){var n=X(t),o=i>=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[K]._onDragOver(o)}}var i,r,a}function Bt(t){V&&V.parentNode[K]._isOutsideThisEl(t.target)}function Ft(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[K]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Pt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Ft.supportPointer&&"PointerEvent"in window&&!u,emptyInsertThreshold:5};for(n in W.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in kt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&Nt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?h(t,"pointerdown",this._onTapStart):(h(t,"mousedown",this._onTapStart),h(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(h(t,"dragover",this),h(t,"dragenter",this)),Dt.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,x())}function jt(t,e,n,o,i,r,a,l){var s,c,u=t[K],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function Ht(t){t.draggable=!1}function Lt(){Tt=!1}function Kt(t){return setTimeout(t,0)}function Wt(t){return clearTimeout(t)}Ft.prototype={constructor:Ft,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(mt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,V):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){xt.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&xt.push(o)}}(o),!V&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||tt===l)){if(ot=j(l),rt=j(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return q({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),G("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return q({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),G("filter",n,{evt:e}),!0}))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!V&&n.parentNode===r&&(o=X(n),Q=r,Z=(V=n).parentNode,J=V.nextSibling,tt=n,lt=a.group,ct={target:Ft.dragged=V,clientX:(e||t).clientX,clientY:(e||t).clientY},ft=ct.clientX-o.left,pt=ct.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,V.style["will-change"]="all",o=function(){G("delayEnded",i,{evt:t}),Ft.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(V.draggable=!0),i._triggerDragStart(t,e),q({sortable:i,name:"choose",originalEvent:t}),k(V,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){b(V,t.trim(),Ht)}),h(l,"dragover",Yt),h(l,"mousemove",Yt),h(l,"touchmove",Yt),h(l,"mouseup",i._onDrop),h(l,"touchend",i._onDrop),h(l,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,V.draggable=!0),G("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():Ft.eventCanceled?this._onDrop():(h(l,"mouseup",i._disableDelayedDrag),h(l,"touchend",i._disableDelayedDrag),h(l,"touchcancel",i._disableDelayedDrag),h(l,"mousemove",i._delayedDragTouchMoveHandler),h(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&h(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){V&&Ht(V),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._disableDelayedDrag),f(t,"touchend",this._disableDelayedDrag),f(t,"touchcancel",this._disableDelayedDrag),f(t,"mousemove",this._delayedDragTouchMoveHandler),f(t,"touchmove",this._delayedDragTouchMoveHandler),f(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?h(document,"pointermove",this._onTouchMove):h(document,e?"touchmove":"mousemove",this._onTouchMove):(h(V,"dragend",this),h(Q,"dragstart",this._onDragStart));try{document.selection?Kt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;wt=!1,Q&&V?(G("dragStarted",this,{evt:e}),this.nativeDraggable&&h(document,"dragover",Bt),n=this.options,t||k(V,n.dragClass,!1),k(V,n.ghostClass,!0),Ft.active=this,t&&this._appendGhost(),q({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(ut){this._lastX=ut.clientX,this._lastY=ut.clientY,Rt();for(var t=document.elementFromPoint(ut.clientX,ut.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(ut.clientX,ut.clientY))!==e;)e=t;if(V.parentNode[K]._isOutsideThisEl(t),e)do{if(e[K])if(e[K]._onDragOver({clientX:ut.clientX,clientY:ut.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=(t=e).parentNode);Xt()}},_onTouchMove:function(t){if(ct){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=$&&v($,!0),a=$&&r&&r.a,l=$&&r&&r.d,e=Mt&&yt&&E(yt),a=(i.clientX-ct.clientX+o.x)/(a||1)+(e?e[0]-Ct[0]:0)/(a||1),l=(i.clientY-ct.clientY+o.y)/(l||1)+(e?e[1]-Ct[1]:0)/(l||1);if(!Ft.active&&!wt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))<n)return;this._onDragStart(t,!0)}$&&(r?(r.e+=a-(dt||0),r.f+=l-(ht||0)):r={a:1,b:0,c:0,d:1,e:a,f:l},r="matrix(".concat(r.a,",").concat(r.b,",").concat(r.c,",").concat(r.d,",").concat(r.e,",").concat(r.f,")"),R($,"webkitTransform",r),R($,"mozTransform",r),R($,"msTransform",r),R($,"transform",r),dt=a,ht=l,ut=i),t.cancelable&&t.preventDefault()}},_appendGhost:function(){if(!$){var t=this.options.fallbackOnBody?document.body:Q,e=X(V,!0,Mt,!0,t),n=this.options;if(Mt){for(yt=t;"static"===R(yt,"position")&&"none"===R(yt,"transform")&&yt!==document;)yt=yt.parentNode;yt!==document.body&&yt!==document.documentElement?(yt===document&&(yt=O()),e.top+=yt.scrollTop,e.left+=yt.scrollLeft):yt=O(),Ct=E(yt)}k($=V.cloneNode(!0),n.ghostClass,!1),k($,n.fallbackClass,!0),k($,n.dragClass,!0),R($,"transition",""),R($,"transform",""),R($,"box-sizing","border-box"),R($,"margin",0),R($,"top",e.top),R($,"left",e.left),R($,"width",e.width),R($,"height",e.height),R($,"opacity","0.8"),R($,"position",Mt?"absolute":"fixed"),R($,"zIndex","100000"),R($,"pointerEvents","none"),Ft.ghost=$,t.appendChild($),R($,"transform-origin",ft/parseInt($.style.width)*100+"% "+pt/parseInt($.style.height)*100+"%")}},_onDragStart:function(t,e){var n=this,o=t.dataTransfer,i=n.options;G("dragStart",this,{evt:t}),Ft.eventCanceled?this._onDrop():(G("setupClone",this),Ft.eventCanceled||((et=_(V)).removeAttribute("id"),et.draggable=!1,et.style["will-change"]="",this._hideClone(),k(et,this.options.chosenClass,!1),Ft.clone=et),n.cloneId=Kt(function(){G("clone",n),Ft.eventCanceled||(n.options.removeCloneOnHide||Q.insertBefore(et,V),n._hideClone(),q({sortable:n,name:"clone"}))}),e||k(V,i.dragClass,!0),e?(Et=!0,n._loopId=setInterval(n._emulateDragOver,50)):(f(document,"mouseup",n._onDrop),f(document,"touchend",n._onDrop),f(document,"touchcancel",n._onDrop),o&&(o.effectAllowed="move",i.setData&&i.setData.call(n,o,V)),h(document,"drop",n),R(V,"transform","translateZ(0)")),wt=!0,n._dragStartId=Kt(n._dragStarted.bind(n,e,t)),h(document,"selectstart",n),gt=!0,u&&R(document.body,"user-select","none"))},_onDragOver:function(n){var o,i,r,t,e,a=this.el,l=n.target,s=this.options,c=s.group,u=Ft.active,d=lt===c,h=s.sort,f=st||u,p=this,g=!1;if(!Tt){if(void 0!==n.preventDefault&&n.cancelable&&n.preventDefault(),l=P(l,s.draggable,a,!0),O("dragOver"),Ft.eventCanceled)return g;if(V.contains(n.target)||l.animated&&l.animatingX&&l.animatingY||p._ignoreWhileAnimating===l)return A(!1);if(Et=!1,u&&!s.disabled&&(d?h||(i=Z!==Q):st===this||(this.lastPutMode=lt.checkPull(this,u,V,n))&&c.checkPut(this,u,V,n))){if(r="vertical"===this._getDirection(n,l),o=X(V),O("dragOverValid"),Ft.eventCanceled)return g;if(i)return Z=Q,M(),this._hideClone(),O("revert"),Ft.eventCanceled||(J?Q.insertBefore(V,J):Q.appendChild(V)),A(!0);var m=F(a,s.draggable);if(m&&(S=n,c=r,x=X(F((D=this).el,D.options.draggable)),D=L(D.el,D.options,$),!(c?S.clientX>D.right+10||S.clientY>x.bottom&&S.clientX>x.left:S.clientY>D.bottom+10||S.clientX>x.right&&S.clientY>x.top)||m.animated)){if(m&&(t=n,e=r,C=X(B((_=this).el,0,_.options,!0)),_=L(_.el,_.options,$),e?t.clientX<_.left-10||t.clientY<C.top&&t.clientX<C.right:t.clientY<_.top-10||t.clientY<C.bottom&&t.clientX<C.left)){var v=B(a,0,s,!0);if(v===V)return A(!1);if(E=X(l=v),!1!==jt(Q,a,V,o,l,E,n,!1))return M(),a.insertBefore(V,v),Z=a,N(),A(!0)}else if(l.parentNode===a){var b,y,w,E=X(l),D=V.parentNode!==a,S=(S=V.animated&&V.toRect||o,x=l.animated&&l.toRect||E,_=(e=r)?S.left:S.top,t=e?S.right:S.bottom,C=e?S.width:S.height,v=e?x.left:x.top,S=e?x.right:x.bottom,x=e?x.width:x.height,!(_===v||t===S||_+C/2===v+x/2)),_=r?"top":"left",C=Y(l,"top","top")||Y(V,"top","top"),v=C?C.scrollTop:void 0;if(mt!==l&&(y=E[_],St=!1,_t=!S&&s.invertSwap||D),0!==(b=function(t,e,n,o,i,r,a,l){var s=o?t.clientY:t.clientX,c=o?n.height:n.width,t=o?n.top:n.left,o=o?n.bottom:n.right,n=!1;if(!a)if(l&&bt<c*i){if(St=!St&&(1===vt?t+c*r/2<s:s<o-c*r/2)?!0:St)n=!0;else if(1===vt?s<t+bt:o-bt<s)return-vt}else if(t+c*(1-i)/2<s&&s<o-c*(1-i)/2)return function(t){return j(V)<j(t)?1:-1}(e);if((n=n||a)&&(s<t+c*r/2||o-c*r/2<s))return t+c/2<s?1:-1;return 0}(n,l,E,r,S?1:s.swapThreshold,null==s.invertedSwapThreshold?s.swapThreshold:s.invertedSwapThreshold,_t,mt===l)))for(var T=j(V);(w=Z.children[T-=b])&&("none"===R(w,"display")||w===$););if(0===b||w===l)return A(!1);vt=b;var x=(mt=l).nextElementSibling,D=!1,S=jt(Q,a,V,o,l,E,n,D=1===b);if(!1!==S)return 1!==S&&-1!==S||(D=1===S),Tt=!0,setTimeout(Lt,30),M(),D&&!x?a.appendChild(V):l.parentNode.insertBefore(V,D?x:l),C&&H(C,0,v-C.scrollTop),Z=V.parentNode,void 0===y||_t||(bt=Math.abs(y-X(l)[_])),N(),A(!0)}}else{if(m===V)return A(!1);if((l=m&&a===n.target?m:l)&&(E=X(l)),!1!==jt(Q,a,V,o,l,E,n,!!l))return M(),m&&m.nextSibling?a.insertBefore(V,m.nextSibling):a.appendChild(V),Z=a,N(),A(!0)}if(a.contains(V))return A(!1)}return!1}function O(t,e){G(t,p,I({evt:n,isOwner:d,axis:r?"vertical":"horizontal",revert:i,dragRect:o,targetRect:E,canSort:h,fromSortable:f,target:l,completed:A,onMove:function(t,e){return jt(Q,a,V,o,t,X(t),n,e)},changed:N},e))}function M(){O("dragOverAnimationCapture"),p.captureAnimationState(),p!==f&&f.captureAnimationState()}function A(t){return O("dragOverCompleted",{insertion:t}),t&&(d?u._hideClone():u._showClone(p),p!==f&&(k(V,(st||u).options.ghostClass,!1),k(V,s.ghostClass,!0)),st!==p&&p!==Ft.active?st=p:p===Ft.active&&st&&(st=null),f===p&&(p._ignoreWhileAnimating=l),p.animateAll(function(){O("dragOverAnimationComplete"),p._ignoreWhileAnimating=null}),p!==f&&(f.animateAll(),f._ignoreWhileAnimating=null)),(l===V&&!V.animated||l===a&&!l.animated)&&(mt=null),s.dragoverBubble||n.rootEl||l===document||(V.parentNode[K]._isOutsideThisEl(n.target),t||Yt(n)),!s.dragoverBubble&&n.stopPropagation&&n.stopPropagation(),g=!0}function N(){it=j(V),at=j(V,s.draggable),q({sortable:p,name:"change",toEl:a,newIndex:it,newDraggableIndex:at,originalEvent:n})}},_ignoreWhileAnimating:null,_offMoveEvents:function(){f(document,"mousemove",this._onTouchMove),f(document,"touchmove",this._onTouchMove),f(document,"pointermove",this._onTouchMove),f(document,"dragover",Yt),f(document,"mousemove",Yt),f(document,"touchmove",Yt)},_offUpEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._onDrop),f(t,"touchend",this._onDrop),f(t,"pointerup",this._onDrop),f(t,"touchcancel",this._onDrop),f(document,"selectstart",this)},_onDrop:function(t){var e=this.el,n=this.options;it=j(V),at=j(V,n.draggable),G("drop",this,{evt:t}),Z=V&&V.parentNode,it=j(V),at=j(V,n.draggable),Ft.eventCanceled||(St=_t=wt=!1,clearInterval(this._loopId),clearTimeout(this._dragStartTimer),Wt(this.cloneId),Wt(this._dragStartId),this.nativeDraggable&&(f(document,"drop",this),f(e,"dragstart",this._onDragStart)),this._offMoveEvents(),this._offUpEvents(),u&&R(document.body,"user-select",""),R(V,"transform",""),t&&(gt&&(t.cancelable&&t.preventDefault(),n.dropBubble||t.stopPropagation()),$&&$.parentNode&&$.parentNode.removeChild($),(Q===Z||st&&"clone"!==st.lastPutMode)&&et&&et.parentNode&&et.parentNode.removeChild(et),V&&(this.nativeDraggable&&f(V,"dragend",this),Ht(V),V.style["will-change"]="",gt&&!wt&&k(V,(st||this).options.ghostClass,!1),k(V,this.options.chosenClass,!1),q({sortable:this,name:"unchoose",toEl:Z,newIndex:null,newDraggableIndex:null,originalEvent:t}),Q!==Z?(0<=it&&(q({rootEl:Z,name:"add",toEl:Z,fromEl:Q,originalEvent:t}),q({sortable:this,name:"remove",toEl:Z,originalEvent:t}),q({rootEl:Z,name:"sort",toEl:Z,fromEl:Q,originalEvent:t}),q({sortable:this,name:"sort",toEl:Z,originalEvent:t})),st&&st.save()):it!==ot&&0<=it&&(q({sortable:this,name:"update",toEl:Z,originalEvent:t}),q({sortable:this,name:"sort",toEl:Z,originalEvent:t})),Ft.active&&(null!=it&&-1!==it||(it=ot,at=rt),q({sortable:this,name:"end",toEl:Z,originalEvent:t}),this.save())))),this._nulling()},_nulling:function(){G("nulling",this),Q=V=Z=$=J=et=tt=nt=ct=ut=gt=it=at=ot=rt=mt=vt=st=lt=Ft.dragged=Ft.ghost=Ft.clone=Ft.active=null,xt.forEach(function(t){t.checked=!0}),xt.length=dt=ht=0},handleEvent:function(t){switch(t.type){case"drop":case"dragend":this._onDrop(t);break;case"dragenter":case"dragover":V&&(this._onDragOver(t),function(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move");t.cancelable&&t.preventDefault()}(t));break;case"selectstart":t.preventDefault()}},toArray:function(){for(var t,e=[],n=this.el.children,o=0,i=n.length,r=this.options;o<i;o++)P(t=n[o],r.draggable,this.el,!1)&&e.push(t.getAttribute(r.dataIdAttr)||function(t){var e=t.tagName+t.className+t.src+t.href+t.textContent,n=e.length,o=0;for(;n--;)o+=e.charCodeAt(n);return o.toString(36)}(t));return e},sort:function(t,e){var n={},o=this.el;this.toArray().forEach(function(t,e){e=o.children[e];P(e,this.options.draggable,o,!1)&&(n[t]=e)},this),e&&this.captureAnimationState(),t.forEach(function(t){n[t]&&(o.removeChild(n[t]),o.appendChild(n[t]))}),e&&this.animateAll()},save:function(){var t=this.options.store;t&&t.set&&t.set(this)},closest:function(t,e){return P(t,e||this.options.draggable,this.el,!1)},option:function(t,e){var n=this.options;if(void 0===e)return n[t];var o=W.modifyOption(this,t,e);n[t]=void 0!==o?o:e,"group"===t&&kt(n)},destroy:function(){G("destroy",this);var t=this.el;t[K]=null,f(t,"mousedown",this._onTapStart),f(t,"touchstart",this._onTapStart),f(t,"pointerdown",this._onTapStart),this.nativeDraggable&&(f(t,"dragover",this),f(t,"dragenter",this)),Array.prototype.forEach.call(t.querySelectorAll("[draggable]"),function(t){t.removeAttribute("draggable")}),this._onDrop(),this._disableDelayedDragEvents(),Dt.splice(Dt.indexOf(this.el),1),this.el=t=null},_hideClone:function(){nt||(G("hideClone",this),Ft.eventCanceled||(R(et,"display","none"),this.options.removeCloneOnHide&&et.parentNode&&et.parentNode.removeChild(et),nt=!0))},_showClone:function(t){"clone"===t.lastPutMode?nt&&(G("showClone",this),Ft.eventCanceled||(V.parentNode!=Q||this.options.group.revertClone?J?Q.insertBefore(et,J):Q.appendChild(et):Q.insertBefore(et,V),this.options.group.revertClone&&this.animate(V,et),R(et,"display",""),nt=!1)):this._hideClone()}},Ot&&h(document,"touchmove",function(t){(Ft.active||wt)&&t.cancelable&&t.preventDefault()}),Ft.utils={on:h,off:f,css:R,find:b,is:function(t,e){return!!P(t,e,t,!1)},extend:function(t,e){if(t&&e)for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t},throttle:S,closest:P,toggleClass:k,clone:_,index:j,nextTick:Kt,cancelNextTick:Wt,detectDirection:Pt,getChild:B},Ft.get=function(t){return t[K]},Ft.mount=function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];(e=e[0].constructor===Array?e[0]:e).forEach(function(t){if(!t.prototype||!t.prototype.constructor)throw"Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(t));t.utils&&(Ft.utils=I(I({},Ft.utils),t.utils)),W.mount(t)})},Ft.create=function(t,e){return new Ft(t,e)};var zt,Gt,Ut,qt,Vt,Zt,$t=[],Qt=!(Ft.version="1.15.2");function Jt(){$t.forEach(function(t){clearInterval(t.pid)}),$t=[]}function te(){clearInterval(Zt)}var ee,ne=S(function(n,t,e,o){if(t.scroll){var i,r=(n.touches?n.touches[0]:n).clientX,a=(n.touches?n.touches[0]:n).clientY,l=t.scrollSensitivity,s=t.scrollSpeed,c=O(),u=!1;Gt!==e&&(Gt=e,Jt(),zt=t.scroll,i=t.scrollFn,!0===zt&&(zt=M(e,!0)));var d=0,h=zt;do{var f=h,p=X(f),g=p.top,m=p.bottom,v=p.left,b=p.right,y=p.width,w=p.height,E=void 0,D=void 0,S=f.scrollWidth,_=f.scrollHeight,C=R(f),T=f.scrollLeft,p=f.scrollTop,D=f===c?(E=y<S&&("auto"===C.overflowX||"scroll"===C.overflowX||"visible"===C.overflowX),w<_&&("auto"===C.overflowY||"scroll"===C.overflowY||"visible"===C.overflowY)):(E=y<S&&("auto"===C.overflowX||"scroll"===C.overflowX),w<_&&("auto"===C.overflowY||"scroll"===C.overflowY)),T=E&&(Math.abs(b-r)<=l&&T+y<S)-(Math.abs(v-r)<=l&&!!T),p=D&&(Math.abs(m-a)<=l&&p+w<_)-(Math.abs(g-a)<=l&&!!p);if(!$t[d])for(var x=0;x<=d;x++)$t[x]||($t[x]={});$t[d].vx==T&&$t[d].vy==p&&$t[d].el===f||($t[d].el=f,$t[d].vx=T,$t[d].vy=p,clearInterval($t[d].pid),0==T&&0==p||(u=!0,$t[d].pid=setInterval(function(){o&&0===this.layer&&Ft.active._onTouchMove(Vt);var t=$t[this.layer].vy?$t[this.layer].vy*s:0,e=$t[this.layer].vx?$t[this.layer].vx*s:0;"function"==typeof i&&"continue"!==i.call(Ft.dragged.parentNode[K],e,t,n,Vt,$t[this.layer].el)||H($t[this.layer].el,e,t)}.bind({layer:d}),24))),d++}while(t.bubbleScroll&&h!==c&&(h=M(h,!1)));Qt=u}},30),c=function(t){var e=t.originalEvent,n=t.putSortable,o=t.dragEl,i=t.activeSortable,r=t.dispatchSortableEvent,a=t.hideGhostForTarget,t=t.unhideGhostForTarget;e&&(i=n||i,a(),e=e.changedTouches&&e.changedTouches.length?e.changedTouches[0]:e,e=document.elementFromPoint(e.clientX,e.clientY),t(),i&&!i.el.contains(e)&&(r("spill"),this.onSpill({dragEl:o,putSortable:n})))};function oe(){}function ie(){}oe.prototype={startIndex:null,dragStart:function(t){t=t.oldDraggableIndex;this.startIndex=t},onSpill:function(t){var e=t.dragEl,n=t.putSortable;this.sortable.captureAnimationState(),n&&n.captureAnimationState();t=B(this.sortable.el,this.startIndex,this.options);t?this.sortable.el.insertBefore(e,t):this.sortable.el.appendChild(e),this.sortable.animateAll(),n&&n.animateAll()},drop:c},a(oe,{pluginName:"revertOnSpill"}),ie.prototype={onSpill:function(t){var e=t.dragEl,t=t.putSortable||this.sortable;t.captureAnimationState(),e.parentNode&&e.parentNode.removeChild(e),t.animateAll()},drop:c},a(ie,{pluginName:"removeOnSpill"});var re,ae,le,se,ce,ue=[],de=[],he=!1,fe=!1,pe=!1;function ge(n,o){de.forEach(function(t,e){e=o.children[t.sortableIndex+(n?Number(e):0)];e?o.insertBefore(t,e):o.appendChild(t)})}function me(){ue.forEach(function(t){t!==le&&t.parentNode&&t.parentNode.removeChild(t)})}return Ft.mount(new function(){function t(){for(var t in this.defaults={scroll:!0,forceAutoScrollFallback:!1,scrollSensitivity:30,scrollSpeed:10,bubbleScroll:!0},this)"_"===t.charAt(0)&&"function"==typeof this[t]&&(this[t]=this[t].bind(this))}return t.prototype={dragStarted:function(t){t=t.originalEvent;this.sortable.nativeDraggable?h(document,"dragover",this._handleAutoScroll):this.options.supportPointer?h(document,"pointermove",this._handleFallbackAutoScroll):t.touches?h(document,"touchmove",this._handleFallbackAutoScroll):h(document,"mousemove",this._handleFallbackAutoScroll)},dragOverCompleted:function(t){t=t.originalEvent;this.options.dragOverBubble||t.rootEl||this._handleAutoScroll(t)},drop:function(){this.sortable.nativeDraggable?f(document,"dragover",this._handleAutoScroll):(f(document,"pointermove",this._handleFallbackAutoScroll),f(document,"touchmove",this._handleFallbackAutoScroll),f(document,"mousemove",this._handleFallbackAutoScroll)),te(),Jt(),clearTimeout(g),g=void 0},nulling:function(){Vt=Gt=zt=Qt=Zt=Ut=qt=null,$t.length=0},_handleFallbackAutoScroll:function(t){this._handleAutoScroll(t,!0)},_handleAutoScroll:function(e,n){var o,i=this,r=(e.touches?e.touches[0]:e).clientX,a=(e.touches?e.touches[0]:e).clientY,t=document.elementFromPoint(r,a);Vt=e,n||this.options.forceAutoScrollFallback||w||y||u?(ne(e,this.options,t,n),o=M(t,!0),!Qt||Zt&&r===Ut&&a===qt||(Zt&&te(),Zt=setInterval(function(){var t=M(document.elementFromPoint(r,a),!0);t!==o&&(o=t,Jt()),ne(e,i.options,t,n)},10),Ut=r,qt=a)):this.options.bubbleScroll&&M(t,!0)!==O()?ne(e,this.options,M(t,!1),!1):Jt()}},a(t,{pluginName:"scroll",initializeByDefault:!0})}),Ft.mount(ie,oe),Ft.mount(new function(){function t(){this.defaults={swapClass:"sortable-swap-highlight"}}return t.prototype={dragStart:function(t){t=t.dragEl;ee=t},dragOverValid:function(t){var e=t.completed,n=t.target,o=t.onMove,i=t.activeSortable,r=t.changed,a=t.cancel;i.options.swap&&(t=this.sortable.el,i=this.options,n&&n!==t&&(t=ee,ee=!1!==o(n)?(k(n,i.swapClass,!0),n):null,t&&t!==ee&&k(t,i.swapClass,!1)),r(),e(!0),a())},drop:function(t){var e,n,o=t.activeSortable,i=t.putSortable,r=t.dragEl,a=i||this.sortable,l=this.options;ee&&k(ee,l.swapClass,!1),ee&&(l.swap||i&&i.options.swap)&&r!==ee&&(a.captureAnimationState(),a!==o&&o.captureAnimationState(),n=ee,t=(e=r).parentNode,l=n.parentNode,t&&l&&!t.isEqualNode(n)&&!l.isEqualNode(e)&&(i=j(e),r=j(n),t.isEqualNode(l)&&i<r&&r++,t.insertBefore(n,t.children[i]),l.insertBefore(e,l.children[r])),a.animateAll(),a!==o&&o.animateAll())},nulling:function(){ee=null}},a(t,{pluginName:"swap",eventProperties:function(){return{swapItem:ee}}})}),Ft.mount(new function(){function t(o){for(var t in this)"_"===t.charAt(0)&&"function"==typeof this[t]&&(this[t]=this[t].bind(this));o.options.avoidImplicitDeselect||(o.options.supportPointer?h(document,"pointerup",this._deselectMultiDrag):(h(document,"mouseup",this._deselectMultiDrag),h(document,"touchend",this._deselectMultiDrag))),h(document,"keydown",this._checkKeyDown),h(document,"keyup",this._checkKeyUp),this.defaults={selectedClass:"sortable-selected",multiDragKey:null,avoidImplicitDeselect:!1,setData:function(t,e){var n="";ue.length&&ae===o?ue.forEach(function(t,e){n+=(e?", ":"")+t.textContent}):n=e.textContent,t.setData("Text",n)}}}return t.prototype={multiDragKeyDown:!1,isMultiDrag:!1,delayStartGlobal:function(t){t=t.dragEl;le=t},delayEnded:function(){this.isMultiDrag=~ue.indexOf(le)},setupClone:function(t){var e=t.sortable,t=t.cancel;if(this.isMultiDrag){for(var n=0;n<ue.length;n++)de.push(_(ue[n])),de[n].sortableIndex=ue[n].sortableIndex,de[n].draggable=!1,de[n].style["will-change"]="",k(de[n],this.options.selectedClass,!1),ue[n]===le&&k(de[n],this.options.chosenClass,!1);e._hideClone(),t()}},clone:function(t){var e=t.sortable,n=t.rootEl,o=t.dispatchSortableEvent,t=t.cancel;this.isMultiDrag&&(this.options.removeCloneOnHide||ue.length&&ae===e&&(ge(!0,n),o("clone"),t()))},showClone:function(t){var e=t.cloneNowShown,n=t.rootEl,t=t.cancel;this.isMultiDrag&&(ge(!1,n),de.forEach(function(t){R(t,"display","")}),e(),ce=!1,t())},hideClone:function(t){var e=this,n=(t.sortable,t.cloneNowHidden),t=t.cancel;this.isMultiDrag&&(de.forEach(function(t){R(t,"display","none"),e.options.removeCloneOnHide&&t.parentNode&&t.parentNode.removeChild(t)}),n(),ce=!0,t())},dragStartGlobal:function(t){t.sortable;!this.isMultiDrag&&ae&&ae.multiDrag._deselectMultiDrag(),ue.forEach(function(t){t.sortableIndex=j(t)}),ue=ue.sort(function(t,e){return t.sortableIndex-e.sortableIndex}),pe=!0},dragStarted:function(t){var e,n=this,t=t.sortable;this.isMultiDrag&&(this.options.sort&&(t.captureAnimationState(),this.options.animation&&(ue.forEach(function(t){t!==le&&R(t,"position","absolute")}),e=X(le,!1,!0,!0),ue.forEach(function(t){t!==le&&C(t,e)}),he=fe=!0)),t.animateAll(function(){he=fe=!1,n.options.animation&&ue.forEach(function(t){T(t)}),n.options.sort&&me()}))},dragOver:function(t){var e=t.target,n=t.completed,t=t.cancel;fe&&~ue.indexOf(e)&&(n(!1),t())},revert:function(t){var n,o,e=t.fromSortable,i=t.rootEl,r=t.sortable,a=t.dragRect;1<ue.length&&(ue.forEach(function(t){r.addAnimationState({target:t,rect:fe?X(t):a}),T(t),t.fromRect=a,e.removeAnimationState(t)}),fe=!1,n=!this.options.removeCloneOnHide,o=i,ue.forEach(function(t,e){e=o.children[t.sortableIndex+(n?Number(e):0)];e?o.insertBefore(t,e):o.appendChild(t)}))},dragOverCompleted:function(t){var e,n=t.sortable,o=t.isOwner,i=t.insertion,r=t.activeSortable,a=t.parentEl,l=t.putSortable,t=this.options;i&&(o&&r._hideClone(),he=!1,t.animation&&1<ue.length&&(fe||!o&&!r.options.sort&&!l)&&(e=X(le,!1,!0,!0),ue.forEach(function(t){t!==le&&(C(t,e),a.appendChild(t))}),fe=!0),o||(fe||me(),1<ue.length?(o=ce,r._showClone(n),r.options.animation&&!ce&&o&&de.forEach(function(t){r.addAnimationState({target:t,rect:se}),t.fromRect=se,t.thisAnimationDuration=null})):r._showClone(n)))},dragOverAnimationCapture:function(t){var e=t.dragRect,n=t.isOwner,t=t.activeSortable;ue.forEach(function(t){t.thisAnimationDuration=null}),t.options.animation&&!n&&t.multiDrag.isMultiDrag&&(se=a({},e),e=v(le,!0),se.top-=e.f,se.left-=e.e)},dragOverAnimationComplete:function(){fe&&(fe=!1,me())},drop:function(t){var e=t.originalEvent,n=t.rootEl,o=t.parentEl,i=t.sortable,r=t.dispatchSortableEvent,a=t.oldIndex,l=t.putSortable,s=l||this.sortable;if(e){var c,u,d,h=this.options,f=o.children;if(!pe)if(h.multiDragKey&&!this.multiDragKeyDown&&this._deselectMultiDrag(),k(le,h.selectedClass,!~ue.indexOf(le)),~ue.indexOf(le))ue.splice(ue.indexOf(le),1),re=null,z({sortable:i,rootEl:n,name:"deselect",targetEl:le,originalEvent:e});else{if(ue.push(le),z({sortable:i,rootEl:n,name:"select",targetEl:le,originalEvent:e}),e.shiftKey&&re&&i.el.contains(re)){var p=j(re),t=j(le);if(~p&&~t&&p!==t)for(var g,m=p<t?(g=p,t):(g=t,p+1);g<m;g++)~ue.indexOf(f[g])||(k(f[g],h.selectedClass,!0),ue.push(f[g]),z({sortable:i,rootEl:n,name:"select",targetEl:f[g],originalEvent:e}))}else re=le;ae=s}pe&&this.isMultiDrag&&(fe=!1,(o[K].options.sort||o!==n)&&1<ue.length&&(c=X(le),u=j(le,":not(."+this.options.selectedClass+")"),!he&&h.animation&&(le.thisAnimationDuration=null),s.captureAnimationState(),he||(h.animation&&(le.fromRect=c,ue.forEach(function(t){var e;t.thisAnimationDuration=null,t!==le&&(e=fe?X(t):c,t.fromRect=e,s.addAnimationState({target:t,rect:e}))})),me(),ue.forEach(function(t){f[u]?o.insertBefore(t,f[u]):o.appendChild(t),u++}),a===j(le)&&(d=!1,ue.forEach(function(t){t.sortableIndex!==j(t)&&(d=!0)}),d&&(r("update"),r("sort")))),ue.forEach(function(t){T(t)}),s.animateAll()),ae=s),(n===o||l&&"clone"!==l.lastPutMode)&&de.forEach(function(t){t.parentNode&&t.parentNode.removeChild(t)})}},nullingGlobal:function(){this.isMultiDrag=pe=!1,de.length=0},destroyGlobal:function(){this._deselectMultiDrag(),f(document,"pointerup",this._deselectMultiDrag),f(document,"mouseup",this._deselectMultiDrag),f(document,"touchend",this._deselectMultiDrag),f(document,"keydown",this._checkKeyDown),f(document,"keyup",this._checkKeyUp)},_deselectMultiDrag:function(t){if(!(void 0!==pe&&pe||ae!==this.sortable||t&&P(t.target,this.options.draggable,this.sortable.el,!1)||t&&0!==t.button))for(;ue.length;){var e=ue[0];k(e,this.options.selectedClass,!1),ue.shift(),z({sortable:this.sortable,rootEl:this.sortable.el,name:"deselect",targetEl:e,originalEvent:t})}},_checkKeyDown:function(t){t.key===this.options.multiDragKey&&(this.multiDragKeyDown=!0)},_checkKeyUp:function(t){t.key===this.options.multiDragKey&&(this.multiDragKeyDown=!1)}},a(t,{pluginName:"multiDrag",utils:{select:function(t){var e=t.parentNode[K];e&&e.options.multiDrag&&!~ue.indexOf(t)&&(ae&&ae!==e&&(ae.multiDrag._deselectMultiDrag(),ae=e),k(t,e.options.selectedClass,!0),ue.push(t))},deselect:function(t){var e=t.parentNode[K],n=ue.indexOf(t);e&&e.options.multiDrag&&~n&&(k(t,e.options.selectedClass,!1),ue.splice(n,1))}},eventProperties:function(){var n=this,o=[],i=[];return ue.forEach(function(t){var e;o.push({multiDragElement:t,index:t.sortableIndex}),e=fe&&t!==le?-1:fe?j(t,":not(."+n.options.selectedClass+")"):j(t),i.push({multiDragElement:t,index:e})}),{items:r(ue),clones:[].concat(de),oldIndicies:o,newIndicies:i}},optionListeners:{multiDragKey:function(t){return"ctrl"===(t=t.toLowerCase())?t="Control":1<t.length&&(t=t.charAt(0).toUpperCase()+t.substr(1)),t}}})}),Ft});';var E={brand:"AgentX",subtitle:"Team AI ops",nodes:"machines",agentsCount:"agents",activeNow:"handling now",errorsCount:"failed",stats:{active:"Handling",total:"Today",errors:"Failed"},idle:"idle",runningNoPreview:"working \xB7 preparing reply",recentActivities:"Recent activities \u2192",noAgentsOnNode:"No agents set up on this machine.",unreachable:"This machine is unreachable.",neverRan:"not used yet",tierLabels:{"claude-code":"Claude Code",sdk:"SDK",orchestrator:"Orchestrator"},taskModalTitle:"Task activity",taskModalConnecting:"connecting\u2026",taskModalLive:"live",taskModalFinished:"finished",taskModalArchived:"archived",taskModalLoadFailed:"couldn't load",taskModalFinalResponse:"Final reply",historyPanelTitle:"Recent activities",historyEmpty:"No activity yet.",historyLoading:"loading\u2026"};var de=[{term:"Agent",definition:'An AI worker with its own role, instructions, and channels it responds on. Think of each agent as a job title \u2014 "support", "devops", "sales".'},{term:"Trigger word",alias:"mention",definition:"A word that activates an agent. When the trigger appears in a message (e.g. @support), AgentX routes the message to that agent."},{term:"Channel",definition:"Where messages come from \u2014 Telegram, WhatsApp, Discord, GitLab comments, a scheduled cron, or an HTTP webhook."},{term:"AI engine",alias:"tier",definition:"Which backend answers: Claude Code (reasoning + tools + files), an SDK provider (OpenAI, Anthropic API, Ollama), or an Orchestrator that coordinates sub-agents."},{term:"Agent folder",alias:"workspace",definition:"The directory on disk where the agent lives. It holds the agent's personality (CLAUDE.md), its knowledge (wiki), and the tools it can use."},{term:"Team network",alias:"mesh",definition:'When you run AgentX on more than one machine, the machines find each other and share work. Each machine is a "node"; together they are your team network.'},{term:"Status check-in",alias:"heartbeat",definition:"A lightweight ping between machines so each one knows the others are alive and responsive."},{term:"Board",definition:"A Kanban view of tasks (issues, tickets) pulled from GitLab. Drag cards between columns to move work forward \u2014 the labels update upstream automatically."},{term:"Task",definition:"A single conversation or job an agent handles, from trigger message to final reply. Every task is logged and replayable."},{term:"Schedule",alias:"cron",definition:'A recurring job \u2014 e.g. "every Monday at 9am" \u2014 that nudges an agent without a human trigger.'},{term:"Status label",alias:"scopedLabel",definition:"A GitLab label that moves an issue between Kanban columns (e.g. Status::Doing). Labels are mutually exclusive by prefix."}];import{existsSync as K,readFileSync as je,writeFileSync as Se,rmSync as sa}from"fs";import{resolve as N}from"path";ne();import{existsSync as A,readFileSync as me,writeFileSync as he,mkdirSync as q,readdirSync as pe,rmSync as Be,statSync as C}from"fs";import{resolve as ue,relative as Ne,dirname as ge,join as P,extname as fe,basename as ze}from"path";var _=200*1024,be=new Set([".md",".markdown",".txt"]),Ue=new Set(["CLAUDE.md","SOUL.md","IDENTITY.md","PERSONA.md","AGENT.md","BOOTSTRAP.md"]);function O(t,e){if(!t)throw new Error("Agent workspace is not configured.");let a=ue(t);if(A(a)||q(a,{recursive:!0}),!e||e.startsWith("/")||e.match(/^[a-zA-Z]:/))throw new Error(`Path must be relative to the workspace: ${e}`);let n=ue(a,e);if(Ne(a,n).startsWith(".."))throw new Error(`Path escapes the workspace: ${e}`);return n}function ve(t){let e=fe(t).toLowerCase();if(!be.has(e))throw new Error(`Only text files (.md, .markdown, .txt) can be edited from the admin panel (got ${e}).`)}function F(t,e){let a=t.split(/\r?\n/).find(n=>n.trim().startsWith("#"));return a&&a.replace(/^#+\s*/,"").trim().slice(0,120)||e}function xe(t){let e=O(t,"."),a=[],n=new Set,o=[];try{o=pe(e)}catch{}for(let l of Ue){let c=P(e,l);if(A(c)&&C(c).isFile()){let d=C(c).size,g=d>0&&d<_?j(c):"";a.push({path:l,title:F(g,l),size:d,exists:!0}),n.add(l)}else a.push({path:l,title:l,size:0,exists:!1}),n.add(l)}for(let l of o){if(n.has(l))continue;let c=P(e,l);try{let d=C(c);if(!d.isFile()||!be.has(fe(l).toLowerCase()))continue;let g=d.size>0&&d.size<_?j(c):"";a.push({path:l,title:F(g,l),size:d.size,exists:!0})}catch{}}let r=[],s=P(e,".claude","skills");if(A(s))try{for(let l of pe(s)){let c=P(s,l),d;try{d=C(c)}catch{continue}if(!d.isDirectory())continue;let g=P(c,"SKILL.md");if(!A(g))continue;let u=C(g),i=u.size<_?j(g):"";r.push({slug:l,title:F(i,l),size:u.size,path:`.claude/skills/${l}/SKILL.md`})}}catch{}return r.sort((l,c)=>l.slug.localeCompare(c.slug)),{identity:a,skills:r,workspace:e}}function j(t){try{return me(t,"utf-8")}catch{return""}}function ye(t,e){let a=O(t,e);if(ve(a),!A(a))return{path:e,content:""};if(C(a).size>_)throw new Error(`File is too large to edit in the admin panel (> ${_/1024} KB).`);return{path:e,content:me(a,"utf-8")}}function ke(t,e,a){let n=O(t,e);ve(n);let o=Buffer.from(a,"utf-8");if(o.length>_)throw new Error(`File too large (${o.length} > ${_} bytes).`);return q(ge(n),{recursive:!0}),he(n,o),{path:e,bytes:o.length}}function we(t,e,a={}){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Skill slug must be lowercase (letters, digits, -, _) and start with a letter or digit.");let n=`.claude/skills/${e}/SKILL.md`,o=O(t,n);if(A(o))throw new Error(`Skill "${e}" already exists.`);q(ge(o),{recursive:!0});let r=a.content?.trim()?a.content:Fe(e,a.title);return he(o,r),{slug:e,path:n}}function Ee(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let a=O(t,`.claude/skills/${e}`);if(!A(a))throw new Error(`Skill "${e}" not found.`);if(!C(a).isDirectory())throw new Error(`Skill path is not a directory: ${e}`);return Be(a,{recursive:!0,force:!0}),{slug:e}}function Fe(t,e){return`# ${e?.trim()||t}
1
+ import{a as x,b as Ae,c as Ce,d as $e,e as O,f as W,g as Me}from"./chunk-KXJSLLSQ.js";import{a as Te}from"./chunk-6U2XOQHU.js";import{a as we}from"./chunk-5F3J55LG.js";import{b as ke}from"./chunk-WZEYII2S.js";import{a as Ee,b as Se,c as st,f as A,h as lt,i as G}from"./chunk-7FJQGD6U.js";import{a as ye,d as it}from"./chunk-FIOB3MEX.js";st();import{createServer as La}from"http";import{appendFileSync as Da,existsSync as Pa,mkdirSync as Oa}from"fs";import{resolve as at}from"path";var _e='/*! Sortable 1.15.2 - MIT | git://github.com/SortableJS/Sortable.git */\n!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function e(e,t){var n,o=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),o.push.apply(o,n)),o}function I(o){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?e(Object(i),!0).forEach(function(t){var e,n;e=o,t=i[n=t],n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t}):Object.getOwnPropertyDescriptors?Object.defineProperties(o,Object.getOwnPropertyDescriptors(i)):e(Object(i)).forEach(function(t){Object.defineProperty(o,t,Object.getOwnPropertyDescriptor(i,t))})}return o}function o(t){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function a(){return(a=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n,o=arguments[e];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(t[n]=o[n])}return t}).apply(this,arguments)}function i(t,e){if(null==t)return{};var n,o=function(t,e){if(null==t)return{};for(var n,o={},i=Object.keys(t),r=0;r<i.length;r++)n=i[r],0<=e.indexOf(n)||(o[n]=t[n]);return o}(t,e);if(Object.getOwnPropertySymbols)for(var i=Object.getOwnPropertySymbols(t),r=0;r<i.length;r++)n=i[r],0<=e.indexOf(n)||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n]);return o}function r(t){return function(t){if(Array.isArray(t))return l(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return l(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Map"===(n="Object"===n&&t.constructor?t.constructor.name:n)||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?l(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var y=t(/(?:Trident.*rv[ :]?11\\.|msie|iemobile|Windows Phone)/i),w=t(/Edge/i),s=t(/firefox/i),u=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),n=t(/iP(ad|od|hone)/i),c=t(/chrome/i)&&t(/android/i),d={capture:!1,passive:!1};function h(t,e,n){t.addEventListener(e,n,!y&&d)}function f(t,e,n){t.removeEventListener(e,n,!y&&d)}function p(t,e){if(e&&(">"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&p(t,e)||o&&t===n)return t}while(t!==n&&(t=(i=t).host&&i!==document&&i.host.nodeType?i.host:i.parentNode))}var i;return null}var g,m=/\\s+/g;function k(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(m," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(m," ")))}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function v(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function b(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i<r;i++)n(o[i],i);return o}return[]}function O(){var t=document.scrollingElement;return t||document.documentElement}function X(t,e,n,o,i){if(t.getBoundingClientRect||t===window){var r,a,l,s,c,u,d=t!==window&&t.parentNode&&t!==O()?(a=(r=t.getBoundingClientRect()).top,l=r.left,s=r.bottom,c=r.right,u=r.height,r.width):(l=a=0,s=window.innerHeight,c=window.innerWidth,u=window.innerHeight,window.innerWidth);if((e||n)&&t!==window&&(i=i||t.parentNode,!y))do{if(i&&i.getBoundingClientRect&&("none"!==R(i,"transform")||n&&"static"!==R(i,"position"))){var h=i.getBoundingClientRect();a-=h.top+parseInt(R(i,"border-top-width")),l-=h.left+parseInt(R(i,"border-left-width")),s=a+r.height,c=l+r.width;break}}while(i=i.parentNode);return o&&t!==window&&(o=(e=v(i||t))&&e.a,t=e&&e.d,e&&(s=(a/=t)+(u/=t),c=(l/=o)+(d/=o))),{top:a,left:l,bottom:s,right:c,width:d,height:u}}}function Y(t,e,n){for(var o=M(t,!0),i=X(t)[e];o;){var r=X(o)[n];if(!("top"===n||"left"===n?r<=i:i<=r))return o;if(o===O())break;o=M(o,!1)}return!1}function B(t,e,n,o){for(var i=0,r=0,a=t.children;r<a.length;){if("none"!==a[r].style.display&&a[r]!==Ft.ghost&&(o||a[r]!==Ft.dragged)&&P(a[r],n.draggable,t,!1)){if(i===e)return a[r];i++}r++}return null}function F(t,e){for(var n=t.lastElementChild;n&&(n===Ft.ghost||"none"===R(n,"display")||e&&!p(n,e));)n=n.previousElementSibling;return n||null}function j(t,e){var n=0;if(!t||!t.parentNode)return-1;for(;t=t.previousElementSibling;)"TEMPLATE"===t.nodeName.toUpperCase()||t===Ft.clone||e&&!p(t,e)||n++;return n}function E(t){var e=0,n=0,o=O();if(t)do{var i=v(t),r=i.a,i=i.d}while(e+=t.scrollLeft*r,n+=t.scrollTop*i,t!==o&&(t=t.parentNode));return[e,n]}function M(t,e){if(!t||!t.getBoundingClientRect)return O();var n=t,o=!1;do{if(n.clientWidth<n.scrollWidth||n.clientHeight<n.scrollHeight){var i=R(n);if(n.clientWidth<n.scrollWidth&&("auto"==i.overflowX||"scroll"==i.overflowX)||n.clientHeight<n.scrollHeight&&("auto"==i.overflowY||"scroll"==i.overflowY)){if(!n.getBoundingClientRect||n===document.body)return O();if(o||e)return n;o=!0}}}while(n=n.parentNode);return O()}function D(t,e){return Math.round(t.top)===Math.round(e.top)&&Math.round(t.left)===Math.round(e.left)&&Math.round(t.height)===Math.round(e.height)&&Math.round(t.width)===Math.round(e.width)}function S(e,n){return function(){var t;g||(1===(t=arguments).length?e.call(this,t[0]):e.apply(this,t),g=setTimeout(function(){g=void 0},n))}}function H(t,e,n){t.scrollLeft+=e,t.scrollTop+=n}function _(t){var e=window.Polymer,n=window.jQuery||window.Zepto;return e&&e.dom?e.dom(t).cloneNode(!0):n?n(t).clone(!0)[0]:t.cloneNode(!0)}function C(t,e){R(t,"position","absolute"),R(t,"top",e.top),R(t,"left",e.left),R(t,"width",e.width),R(t,"height",e.height)}function T(t){R(t,"position",""),R(t,"top",""),R(t,"left",""),R(t,"width",""),R(t,"height","")}function L(n,o,i){var r={};return Array.from(n.children).forEach(function(t){var e;P(t,o.draggable,n,!1)&&!t.animated&&t!==i&&(e=X(t),r.left=Math.min(null!==(t=r.left)&&void 0!==t?t:1/0,e.left),r.top=Math.min(null!==(t=r.top)&&void 0!==t?t:1/0,e.top),r.right=Math.max(null!==(t=r.right)&&void 0!==t?t:-1/0,e.right),r.bottom=Math.max(null!==(t=r.bottom)&&void 0!==t?t:-1/0,e.bottom))}),r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}var K="Sortable"+(new Date).getTime();function x(){var e,o=[];return{captureAnimationState:function(){o=[],this.options.animation&&[].slice.call(this.el.children).forEach(function(t){var e,n;"none"!==R(t,"display")&&t!==Ft.ghost&&(o.push({target:t,rect:X(t)}),e=I({},o[o.length-1].rect),!t.thisAnimationDuration||(n=v(t,!0))&&(e.top-=n.f,e.left-=n.e),t.fromRect=e)})},addAnimationState:function(t){o.push(t)},removeAnimationState:function(t){o.splice(function(t,e){for(var n in t)if(t.hasOwnProperty(n))for(var o in e)if(e.hasOwnProperty(o)&&e[o]===t[n][o])return Number(n);return-1}(o,{target:t}),1)},animateAll:function(t){var c=this;if(!this.options.animation)return clearTimeout(e),void("function"==typeof t&&t());var u=!1,d=0;o.forEach(function(t){var e=0,n=t.target,o=n.fromRect,i=X(n),r=n.prevFromRect,a=n.prevToRect,l=t.rect,s=v(n,!0);s&&(i.top-=s.f,i.left-=s.e),n.toRect=i,n.thisAnimationDuration&&D(r,i)&&!D(o,i)&&(l.top-i.top)/(l.left-i.left)==(o.top-i.top)/(o.left-i.left)&&(t=l,s=r,r=a,a=c.options,e=Math.sqrt(Math.pow(s.top-t.top,2)+Math.pow(s.left-t.left,2))/Math.sqrt(Math.pow(s.top-r.top,2)+Math.pow(s.left-r.left,2))*a.animation),D(i,o)||(n.prevFromRect=o,n.prevToRect=i,e=e||c.options.animation,c.animate(n,l,i,e)),e&&(u=!0,d=Math.max(d,e),clearTimeout(n.animationResetTimer),n.animationResetTimer=setTimeout(function(){n.animationTime=0,n.prevFromRect=null,n.fromRect=null,n.prevToRect=null,n.thisAnimationDuration=null},e),n.thisAnimationDuration=e)}),clearTimeout(e),u?e=setTimeout(function(){"function"==typeof t&&t()},d):"function"==typeof t&&t(),o=[]},animate:function(t,e,n,o){var i,r;o&&(R(t,"transition",""),R(t,"transform",""),i=(r=v(this.el))&&r.a,r=r&&r.d,i=(e.left-n.left)/(i||1),r=(e.top-n.top)/(r||1),t.animatingX=!!i,t.animatingY=!!r,R(t,"transform","translate3d("+i+"px,"+r+"px,0)"),this.forRepaintDummy=t.offsetWidth,R(t,"transition","transform "+o+"ms"+(this.options.easing?" "+this.options.easing:"")),R(t,"transform","translate3d(0,0,0)"),"number"==typeof t.animated&&clearTimeout(t.animated),t.animated=setTimeout(function(){R(t,"transition",""),R(t,"transform",""),t.animated=!1,t.animatingX=!1,t.animatingY=!1},o))}}}var A=[],N={initializeByDefault:!0},W={mount:function(e){for(var t in N)!N.hasOwnProperty(t)||t in e||(e[t]=N[t]);A.forEach(function(t){if(t.pluginName===e.pluginName)throw"Sortable: Cannot mount plugin ".concat(e.pluginName," more than once")}),A.push(e)},pluginEvent:function(e,n,o){var t=this;this.eventCanceled=!1,o.cancel=function(){t.eventCanceled=!0};var i=e+"Global";A.forEach(function(t){n[t.pluginName]&&(n[t.pluginName][i]&&n[t.pluginName][i](I({sortable:n},o)),n.options[t.pluginName]&&n[t.pluginName][e]&&n[t.pluginName][e](I({sortable:n},o)))})},initializePlugins:function(n,o,i,t){for(var e in A.forEach(function(t){var e=t.pluginName;(n.options[e]||t.initializeByDefault)&&((t=new t(n,o,n.options)).sortable=n,t.options=n.options,n[e]=t,a(i,t.defaults))}),n.options){var r;n.options.hasOwnProperty(e)&&(void 0!==(r=this.modifyOption(n,e,n.options[e]))&&(n.options[e]=r))}},getEventProperties:function(e,n){var o={};return A.forEach(function(t){"function"==typeof t.eventProperties&&a(o,t.eventProperties.call(n[t.pluginName],e))}),o},modifyOption:function(e,n,o){var i;return A.forEach(function(t){e[t.pluginName]&&t.optionListeners&&"function"==typeof t.optionListeners[n]&&(i=t.optionListeners[n].call(e[t.pluginName],o))}),i}};function z(t){var e=t.sortable,n=t.rootEl,o=t.name,i=t.targetEl,r=t.cloneEl,a=t.toEl,l=t.fromEl,s=t.oldIndex,c=t.newIndex,u=t.oldDraggableIndex,d=t.newDraggableIndex,h=t.originalEvent,f=t.putSortable,p=t.extraEventProperties;if(e=e||n&&n[K]){var g,m=e.options,t="on"+o.charAt(0).toUpperCase()+o.substr(1);!window.CustomEvent||y||w?(g=document.createEvent("Event")).initEvent(o,!0,!0):g=new CustomEvent(o,{bubbles:!0,cancelable:!0}),g.to=a||n,g.from=l||n,g.item=i||n,g.clone=r,g.oldIndex=s,g.newIndex=c,g.oldDraggableIndex=u,g.newDraggableIndex=d,g.originalEvent=h,g.pullMode=f?f.lastPutMode:void 0;var v,b=I(I({},p),W.getEventProperties(o,e));for(v in b)g[v]=b[v];n&&n.dispatchEvent(g),m[t]&&m[t].call(e,g)}}function G(t,e){var n=(o=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{}).evt,o=i(o,U);W.pluginEvent.bind(Ft)(t,e,I({dragEl:V,parentEl:Z,ghostEl:$,rootEl:Q,nextEl:J,lastDownEl:tt,cloneEl:et,cloneHidden:nt,dragStarted:gt,putSortable:st,activeSortable:Ft.active,originalEvent:n,oldIndex:ot,oldDraggableIndex:rt,newIndex:it,newDraggableIndex:at,hideGhostForTarget:Rt,unhideGhostForTarget:Xt,cloneNowHidden:function(){nt=!0},cloneNowShown:function(){nt=!1},dispatchSortableEvent:function(t){q({sortable:e,name:t,originalEvent:n})}},o))}var U=["evt"];function q(t){z(I({putSortable:st,cloneEl:et,targetEl:V,rootEl:Q,oldIndex:ot,oldDraggableIndex:rt,newIndex:it,newDraggableIndex:at},t))}var V,Z,$,Q,J,tt,et,nt,ot,it,rt,at,lt,st,ct,ut,dt,ht,ft,pt,gt,mt,vt,bt,yt,wt=!1,Et=!1,Dt=[],St=!1,_t=!1,Ct=[],Tt=!1,xt=[],Ot="undefined"!=typeof document,Mt=n,At=w||y?"cssFloat":"float",Nt=Ot&&!c&&!n&&"draggable"in document.createElement("div"),It=function(){if(Ot){if(y)return!1;var t=document.createElement("x");return t.style.cssText="pointer-events:auto","auto"===t.style.pointerEvents}}(),Pt=function(t,e){var n=R(t),o=parseInt(n.width)-parseInt(n.paddingLeft)-parseInt(n.paddingRight)-parseInt(n.borderLeftWidth)-parseInt(n.borderRightWidth),i=B(t,0,e),r=B(t,1,e),a=i&&R(i),l=r&&R(r),s=a&&parseInt(a.marginLeft)+parseInt(a.marginRight)+X(i).width,t=l&&parseInt(l.marginLeft)+parseInt(l.marginRight)+X(r).width;if("flex"===n.display)return"column"===n.flexDirection||"column-reverse"===n.flexDirection?"vertical":"horizontal";if("grid"===n.display)return n.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(i&&a.float&&"none"!==a.float){e="left"===a.float?"left":"right";return!r||"both"!==l.clear&&l.clear!==e?"horizontal":"vertical"}return i&&("block"===a.display||"flex"===a.display||"table"===a.display||"grid"===a.display||o<=s&&"none"===n[At]||r&&"none"===n[At]&&o<s+t)?"vertical":"horizontal"},kt=function(t){function l(r,a){return function(t,e,n,o){var i=t.options.group.name&&e.options.group.name&&t.options.group.name===e.options.group.name;if(null==r&&(a||i))return!0;if(null==r||!1===r)return!1;if(a&&"clone"===r)return r;if("function"==typeof r)return l(r(t,e,n,o),a)(t,e,n,o);e=(a?t:e).options.group.name;return!0===r||"string"==typeof r&&r===e||r.join&&-1<r.indexOf(e)}}var e={},n=t.group;n&&"object"==o(n)||(n={name:n}),e.name=n.name,e.checkPull=l(n.pull,!0),e.checkPut=l(n.put),e.revertClone=n.revertClone,t.group=e},Rt=function(){!It&&$&&R($,"display","none")},Xt=function(){!It&&$&&R($,"display","")};Ot&&!c&&document.addEventListener("click",function(t){if(Et)return t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),Et=!1},!0);function Yt(t){if(V){t=t.touches?t.touches[0]:t;var e=(i=t.clientX,r=t.clientY,Dt.some(function(t){var e=t[K].options.emptyInsertThreshold;if(e&&!F(t)){var n=X(t),o=i>=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[K]._onDragOver(o)}}var i,r,a}function Bt(t){V&&V.parentNode[K]._isOutsideThisEl(t.target)}function Ft(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[K]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Pt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Ft.supportPointer&&"PointerEvent"in window&&!u,emptyInsertThreshold:5};for(n in W.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in kt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&Nt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?h(t,"pointerdown",this._onTapStart):(h(t,"mousedown",this._onTapStart),h(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(h(t,"dragover",this),h(t,"dragenter",this)),Dt.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,x())}function jt(t,e,n,o,i,r,a,l){var s,c,u=t[K],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function Ht(t){t.draggable=!1}function Lt(){Tt=!1}function Kt(t){return setTimeout(t,0)}function Wt(t){return clearTimeout(t)}Ft.prototype={constructor:Ft,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(mt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,V):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){xt.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&xt.push(o)}}(o),!V&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||tt===l)){if(ot=j(l),rt=j(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return q({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),G("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return q({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),G("filter",n,{evt:e}),!0}))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!V&&n.parentNode===r&&(o=X(n),Q=r,Z=(V=n).parentNode,J=V.nextSibling,tt=n,lt=a.group,ct={target:Ft.dragged=V,clientX:(e||t).clientX,clientY:(e||t).clientY},ft=ct.clientX-o.left,pt=ct.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,V.style["will-change"]="all",o=function(){G("delayEnded",i,{evt:t}),Ft.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(V.draggable=!0),i._triggerDragStart(t,e),q({sortable:i,name:"choose",originalEvent:t}),k(V,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){b(V,t.trim(),Ht)}),h(l,"dragover",Yt),h(l,"mousemove",Yt),h(l,"touchmove",Yt),h(l,"mouseup",i._onDrop),h(l,"touchend",i._onDrop),h(l,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,V.draggable=!0),G("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():Ft.eventCanceled?this._onDrop():(h(l,"mouseup",i._disableDelayedDrag),h(l,"touchend",i._disableDelayedDrag),h(l,"touchcancel",i._disableDelayedDrag),h(l,"mousemove",i._delayedDragTouchMoveHandler),h(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&h(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){V&&Ht(V),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._disableDelayedDrag),f(t,"touchend",this._disableDelayedDrag),f(t,"touchcancel",this._disableDelayedDrag),f(t,"mousemove",this._delayedDragTouchMoveHandler),f(t,"touchmove",this._delayedDragTouchMoveHandler),f(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?h(document,"pointermove",this._onTouchMove):h(document,e?"touchmove":"mousemove",this._onTouchMove):(h(V,"dragend",this),h(Q,"dragstart",this._onDragStart));try{document.selection?Kt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;wt=!1,Q&&V?(G("dragStarted",this,{evt:e}),this.nativeDraggable&&h(document,"dragover",Bt),n=this.options,t||k(V,n.dragClass,!1),k(V,n.ghostClass,!0),Ft.active=this,t&&this._appendGhost(),q({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(ut){this._lastX=ut.clientX,this._lastY=ut.clientY,Rt();for(var t=document.elementFromPoint(ut.clientX,ut.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(ut.clientX,ut.clientY))!==e;)e=t;if(V.parentNode[K]._isOutsideThisEl(t),e)do{if(e[K])if(e[K]._onDragOver({clientX:ut.clientX,clientY:ut.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=(t=e).parentNode);Xt()}},_onTouchMove:function(t){if(ct){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=$&&v($,!0),a=$&&r&&r.a,l=$&&r&&r.d,e=Mt&&yt&&E(yt),a=(i.clientX-ct.clientX+o.x)/(a||1)+(e?e[0]-Ct[0]:0)/(a||1),l=(i.clientY-ct.clientY+o.y)/(l||1)+(e?e[1]-Ct[1]:0)/(l||1);if(!Ft.active&&!wt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))<n)return;this._onDragStart(t,!0)}$&&(r?(r.e+=a-(dt||0),r.f+=l-(ht||0)):r={a:1,b:0,c:0,d:1,e:a,f:l},r="matrix(".concat(r.a,",").concat(r.b,",").concat(r.c,",").concat(r.d,",").concat(r.e,",").concat(r.f,")"),R($,"webkitTransform",r),R($,"mozTransform",r),R($,"msTransform",r),R($,"transform",r),dt=a,ht=l,ut=i),t.cancelable&&t.preventDefault()}},_appendGhost:function(){if(!$){var t=this.options.fallbackOnBody?document.body:Q,e=X(V,!0,Mt,!0,t),n=this.options;if(Mt){for(yt=t;"static"===R(yt,"position")&&"none"===R(yt,"transform")&&yt!==document;)yt=yt.parentNode;yt!==document.body&&yt!==document.documentElement?(yt===document&&(yt=O()),e.top+=yt.scrollTop,e.left+=yt.scrollLeft):yt=O(),Ct=E(yt)}k($=V.cloneNode(!0),n.ghostClass,!1),k($,n.fallbackClass,!0),k($,n.dragClass,!0),R($,"transition",""),R($,"transform",""),R($,"box-sizing","border-box"),R($,"margin",0),R($,"top",e.top),R($,"left",e.left),R($,"width",e.width),R($,"height",e.height),R($,"opacity","0.8"),R($,"position",Mt?"absolute":"fixed"),R($,"zIndex","100000"),R($,"pointerEvents","none"),Ft.ghost=$,t.appendChild($),R($,"transform-origin",ft/parseInt($.style.width)*100+"% "+pt/parseInt($.style.height)*100+"%")}},_onDragStart:function(t,e){var n=this,o=t.dataTransfer,i=n.options;G("dragStart",this,{evt:t}),Ft.eventCanceled?this._onDrop():(G("setupClone",this),Ft.eventCanceled||((et=_(V)).removeAttribute("id"),et.draggable=!1,et.style["will-change"]="",this._hideClone(),k(et,this.options.chosenClass,!1),Ft.clone=et),n.cloneId=Kt(function(){G("clone",n),Ft.eventCanceled||(n.options.removeCloneOnHide||Q.insertBefore(et,V),n._hideClone(),q({sortable:n,name:"clone"}))}),e||k(V,i.dragClass,!0),e?(Et=!0,n._loopId=setInterval(n._emulateDragOver,50)):(f(document,"mouseup",n._onDrop),f(document,"touchend",n._onDrop),f(document,"touchcancel",n._onDrop),o&&(o.effectAllowed="move",i.setData&&i.setData.call(n,o,V)),h(document,"drop",n),R(V,"transform","translateZ(0)")),wt=!0,n._dragStartId=Kt(n._dragStarted.bind(n,e,t)),h(document,"selectstart",n),gt=!0,u&&R(document.body,"user-select","none"))},_onDragOver:function(n){var o,i,r,t,e,a=this.el,l=n.target,s=this.options,c=s.group,u=Ft.active,d=lt===c,h=s.sort,f=st||u,p=this,g=!1;if(!Tt){if(void 0!==n.preventDefault&&n.cancelable&&n.preventDefault(),l=P(l,s.draggable,a,!0),O("dragOver"),Ft.eventCanceled)return g;if(V.contains(n.target)||l.animated&&l.animatingX&&l.animatingY||p._ignoreWhileAnimating===l)return A(!1);if(Et=!1,u&&!s.disabled&&(d?h||(i=Z!==Q):st===this||(this.lastPutMode=lt.checkPull(this,u,V,n))&&c.checkPut(this,u,V,n))){if(r="vertical"===this._getDirection(n,l),o=X(V),O("dragOverValid"),Ft.eventCanceled)return g;if(i)return Z=Q,M(),this._hideClone(),O("revert"),Ft.eventCanceled||(J?Q.insertBefore(V,J):Q.appendChild(V)),A(!0);var m=F(a,s.draggable);if(m&&(S=n,c=r,x=X(F((D=this).el,D.options.draggable)),D=L(D.el,D.options,$),!(c?S.clientX>D.right+10||S.clientY>x.bottom&&S.clientX>x.left:S.clientY>D.bottom+10||S.clientX>x.right&&S.clientY>x.top)||m.animated)){if(m&&(t=n,e=r,C=X(B((_=this).el,0,_.options,!0)),_=L(_.el,_.options,$),e?t.clientX<_.left-10||t.clientY<C.top&&t.clientX<C.right:t.clientY<_.top-10||t.clientY<C.bottom&&t.clientX<C.left)){var v=B(a,0,s,!0);if(v===V)return A(!1);if(E=X(l=v),!1!==jt(Q,a,V,o,l,E,n,!1))return M(),a.insertBefore(V,v),Z=a,N(),A(!0)}else if(l.parentNode===a){var b,y,w,E=X(l),D=V.parentNode!==a,S=(S=V.animated&&V.toRect||o,x=l.animated&&l.toRect||E,_=(e=r)?S.left:S.top,t=e?S.right:S.bottom,C=e?S.width:S.height,v=e?x.left:x.top,S=e?x.right:x.bottom,x=e?x.width:x.height,!(_===v||t===S||_+C/2===v+x/2)),_=r?"top":"left",C=Y(l,"top","top")||Y(V,"top","top"),v=C?C.scrollTop:void 0;if(mt!==l&&(y=E[_],St=!1,_t=!S&&s.invertSwap||D),0!==(b=function(t,e,n,o,i,r,a,l){var s=o?t.clientY:t.clientX,c=o?n.height:n.width,t=o?n.top:n.left,o=o?n.bottom:n.right,n=!1;if(!a)if(l&&bt<c*i){if(St=!St&&(1===vt?t+c*r/2<s:s<o-c*r/2)?!0:St)n=!0;else if(1===vt?s<t+bt:o-bt<s)return-vt}else if(t+c*(1-i)/2<s&&s<o-c*(1-i)/2)return function(t){return j(V)<j(t)?1:-1}(e);if((n=n||a)&&(s<t+c*r/2||o-c*r/2<s))return t+c/2<s?1:-1;return 0}(n,l,E,r,S?1:s.swapThreshold,null==s.invertedSwapThreshold?s.swapThreshold:s.invertedSwapThreshold,_t,mt===l)))for(var T=j(V);(w=Z.children[T-=b])&&("none"===R(w,"display")||w===$););if(0===b||w===l)return A(!1);vt=b;var x=(mt=l).nextElementSibling,D=!1,S=jt(Q,a,V,o,l,E,n,D=1===b);if(!1!==S)return 1!==S&&-1!==S||(D=1===S),Tt=!0,setTimeout(Lt,30),M(),D&&!x?a.appendChild(V):l.parentNode.insertBefore(V,D?x:l),C&&H(C,0,v-C.scrollTop),Z=V.parentNode,void 0===y||_t||(bt=Math.abs(y-X(l)[_])),N(),A(!0)}}else{if(m===V)return A(!1);if((l=m&&a===n.target?m:l)&&(E=X(l)),!1!==jt(Q,a,V,o,l,E,n,!!l))return M(),m&&m.nextSibling?a.insertBefore(V,m.nextSibling):a.appendChild(V),Z=a,N(),A(!0)}if(a.contains(V))return A(!1)}return!1}function O(t,e){G(t,p,I({evt:n,isOwner:d,axis:r?"vertical":"horizontal",revert:i,dragRect:o,targetRect:E,canSort:h,fromSortable:f,target:l,completed:A,onMove:function(t,e){return jt(Q,a,V,o,t,X(t),n,e)},changed:N},e))}function M(){O("dragOverAnimationCapture"),p.captureAnimationState(),p!==f&&f.captureAnimationState()}function A(t){return O("dragOverCompleted",{insertion:t}),t&&(d?u._hideClone():u._showClone(p),p!==f&&(k(V,(st||u).options.ghostClass,!1),k(V,s.ghostClass,!0)),st!==p&&p!==Ft.active?st=p:p===Ft.active&&st&&(st=null),f===p&&(p._ignoreWhileAnimating=l),p.animateAll(function(){O("dragOverAnimationComplete"),p._ignoreWhileAnimating=null}),p!==f&&(f.animateAll(),f._ignoreWhileAnimating=null)),(l===V&&!V.animated||l===a&&!l.animated)&&(mt=null),s.dragoverBubble||n.rootEl||l===document||(V.parentNode[K]._isOutsideThisEl(n.target),t||Yt(n)),!s.dragoverBubble&&n.stopPropagation&&n.stopPropagation(),g=!0}function N(){it=j(V),at=j(V,s.draggable),q({sortable:p,name:"change",toEl:a,newIndex:it,newDraggableIndex:at,originalEvent:n})}},_ignoreWhileAnimating:null,_offMoveEvents:function(){f(document,"mousemove",this._onTouchMove),f(document,"touchmove",this._onTouchMove),f(document,"pointermove",this._onTouchMove),f(document,"dragover",Yt),f(document,"mousemove",Yt),f(document,"touchmove",Yt)},_offUpEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._onDrop),f(t,"touchend",this._onDrop),f(t,"pointerup",this._onDrop),f(t,"touchcancel",this._onDrop),f(document,"selectstart",this)},_onDrop:function(t){var e=this.el,n=this.options;it=j(V),at=j(V,n.draggable),G("drop",this,{evt:t}),Z=V&&V.parentNode,it=j(V),at=j(V,n.draggable),Ft.eventCanceled||(St=_t=wt=!1,clearInterval(this._loopId),clearTimeout(this._dragStartTimer),Wt(this.cloneId),Wt(this._dragStartId),this.nativeDraggable&&(f(document,"drop",this),f(e,"dragstart",this._onDragStart)),this._offMoveEvents(),this._offUpEvents(),u&&R(document.body,"user-select",""),R(V,"transform",""),t&&(gt&&(t.cancelable&&t.preventDefault(),n.dropBubble||t.stopPropagation()),$&&$.parentNode&&$.parentNode.removeChild($),(Q===Z||st&&"clone"!==st.lastPutMode)&&et&&et.parentNode&&et.parentNode.removeChild(et),V&&(this.nativeDraggable&&f(V,"dragend",this),Ht(V),V.style["will-change"]="",gt&&!wt&&k(V,(st||this).options.ghostClass,!1),k(V,this.options.chosenClass,!1),q({sortable:this,name:"unchoose",toEl:Z,newIndex:null,newDraggableIndex:null,originalEvent:t}),Q!==Z?(0<=it&&(q({rootEl:Z,name:"add",toEl:Z,fromEl:Q,originalEvent:t}),q({sortable:this,name:"remove",toEl:Z,originalEvent:t}),q({rootEl:Z,name:"sort",toEl:Z,fromEl:Q,originalEvent:t}),q({sortable:this,name:"sort",toEl:Z,originalEvent:t})),st&&st.save()):it!==ot&&0<=it&&(q({sortable:this,name:"update",toEl:Z,originalEvent:t}),q({sortable:this,name:"sort",toEl:Z,originalEvent:t})),Ft.active&&(null!=it&&-1!==it||(it=ot,at=rt),q({sortable:this,name:"end",toEl:Z,originalEvent:t}),this.save())))),this._nulling()},_nulling:function(){G("nulling",this),Q=V=Z=$=J=et=tt=nt=ct=ut=gt=it=at=ot=rt=mt=vt=st=lt=Ft.dragged=Ft.ghost=Ft.clone=Ft.active=null,xt.forEach(function(t){t.checked=!0}),xt.length=dt=ht=0},handleEvent:function(t){switch(t.type){case"drop":case"dragend":this._onDrop(t);break;case"dragenter":case"dragover":V&&(this._onDragOver(t),function(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move");t.cancelable&&t.preventDefault()}(t));break;case"selectstart":t.preventDefault()}},toArray:function(){for(var t,e=[],n=this.el.children,o=0,i=n.length,r=this.options;o<i;o++)P(t=n[o],r.draggable,this.el,!1)&&e.push(t.getAttribute(r.dataIdAttr)||function(t){var e=t.tagName+t.className+t.src+t.href+t.textContent,n=e.length,o=0;for(;n--;)o+=e.charCodeAt(n);return o.toString(36)}(t));return e},sort:function(t,e){var n={},o=this.el;this.toArray().forEach(function(t,e){e=o.children[e];P(e,this.options.draggable,o,!1)&&(n[t]=e)},this),e&&this.captureAnimationState(),t.forEach(function(t){n[t]&&(o.removeChild(n[t]),o.appendChild(n[t]))}),e&&this.animateAll()},save:function(){var t=this.options.store;t&&t.set&&t.set(this)},closest:function(t,e){return P(t,e||this.options.draggable,this.el,!1)},option:function(t,e){var n=this.options;if(void 0===e)return n[t];var o=W.modifyOption(this,t,e);n[t]=void 0!==o?o:e,"group"===t&&kt(n)},destroy:function(){G("destroy",this);var t=this.el;t[K]=null,f(t,"mousedown",this._onTapStart),f(t,"touchstart",this._onTapStart),f(t,"pointerdown",this._onTapStart),this.nativeDraggable&&(f(t,"dragover",this),f(t,"dragenter",this)),Array.prototype.forEach.call(t.querySelectorAll("[draggable]"),function(t){t.removeAttribute("draggable")}),this._onDrop(),this._disableDelayedDragEvents(),Dt.splice(Dt.indexOf(this.el),1),this.el=t=null},_hideClone:function(){nt||(G("hideClone",this),Ft.eventCanceled||(R(et,"display","none"),this.options.removeCloneOnHide&&et.parentNode&&et.parentNode.removeChild(et),nt=!0))},_showClone:function(t){"clone"===t.lastPutMode?nt&&(G("showClone",this),Ft.eventCanceled||(V.parentNode!=Q||this.options.group.revertClone?J?Q.insertBefore(et,J):Q.appendChild(et):Q.insertBefore(et,V),this.options.group.revertClone&&this.animate(V,et),R(et,"display",""),nt=!1)):this._hideClone()}},Ot&&h(document,"touchmove",function(t){(Ft.active||wt)&&t.cancelable&&t.preventDefault()}),Ft.utils={on:h,off:f,css:R,find:b,is:function(t,e){return!!P(t,e,t,!1)},extend:function(t,e){if(t&&e)for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t},throttle:S,closest:P,toggleClass:k,clone:_,index:j,nextTick:Kt,cancelNextTick:Wt,detectDirection:Pt,getChild:B},Ft.get=function(t){return t[K]},Ft.mount=function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];(e=e[0].constructor===Array?e[0]:e).forEach(function(t){if(!t.prototype||!t.prototype.constructor)throw"Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(t));t.utils&&(Ft.utils=I(I({},Ft.utils),t.utils)),W.mount(t)})},Ft.create=function(t,e){return new Ft(t,e)};var zt,Gt,Ut,qt,Vt,Zt,$t=[],Qt=!(Ft.version="1.15.2");function Jt(){$t.forEach(function(t){clearInterval(t.pid)}),$t=[]}function te(){clearInterval(Zt)}var ee,ne=S(function(n,t,e,o){if(t.scroll){var i,r=(n.touches?n.touches[0]:n).clientX,a=(n.touches?n.touches[0]:n).clientY,l=t.scrollSensitivity,s=t.scrollSpeed,c=O(),u=!1;Gt!==e&&(Gt=e,Jt(),zt=t.scroll,i=t.scrollFn,!0===zt&&(zt=M(e,!0)));var d=0,h=zt;do{var f=h,p=X(f),g=p.top,m=p.bottom,v=p.left,b=p.right,y=p.width,w=p.height,E=void 0,D=void 0,S=f.scrollWidth,_=f.scrollHeight,C=R(f),T=f.scrollLeft,p=f.scrollTop,D=f===c?(E=y<S&&("auto"===C.overflowX||"scroll"===C.overflowX||"visible"===C.overflowX),w<_&&("auto"===C.overflowY||"scroll"===C.overflowY||"visible"===C.overflowY)):(E=y<S&&("auto"===C.overflowX||"scroll"===C.overflowX),w<_&&("auto"===C.overflowY||"scroll"===C.overflowY)),T=E&&(Math.abs(b-r)<=l&&T+y<S)-(Math.abs(v-r)<=l&&!!T),p=D&&(Math.abs(m-a)<=l&&p+w<_)-(Math.abs(g-a)<=l&&!!p);if(!$t[d])for(var x=0;x<=d;x++)$t[x]||($t[x]={});$t[d].vx==T&&$t[d].vy==p&&$t[d].el===f||($t[d].el=f,$t[d].vx=T,$t[d].vy=p,clearInterval($t[d].pid),0==T&&0==p||(u=!0,$t[d].pid=setInterval(function(){o&&0===this.layer&&Ft.active._onTouchMove(Vt);var t=$t[this.layer].vy?$t[this.layer].vy*s:0,e=$t[this.layer].vx?$t[this.layer].vx*s:0;"function"==typeof i&&"continue"!==i.call(Ft.dragged.parentNode[K],e,t,n,Vt,$t[this.layer].el)||H($t[this.layer].el,e,t)}.bind({layer:d}),24))),d++}while(t.bubbleScroll&&h!==c&&(h=M(h,!1)));Qt=u}},30),c=function(t){var e=t.originalEvent,n=t.putSortable,o=t.dragEl,i=t.activeSortable,r=t.dispatchSortableEvent,a=t.hideGhostForTarget,t=t.unhideGhostForTarget;e&&(i=n||i,a(),e=e.changedTouches&&e.changedTouches.length?e.changedTouches[0]:e,e=document.elementFromPoint(e.clientX,e.clientY),t(),i&&!i.el.contains(e)&&(r("spill"),this.onSpill({dragEl:o,putSortable:n})))};function oe(){}function ie(){}oe.prototype={startIndex:null,dragStart:function(t){t=t.oldDraggableIndex;this.startIndex=t},onSpill:function(t){var e=t.dragEl,n=t.putSortable;this.sortable.captureAnimationState(),n&&n.captureAnimationState();t=B(this.sortable.el,this.startIndex,this.options);t?this.sortable.el.insertBefore(e,t):this.sortable.el.appendChild(e),this.sortable.animateAll(),n&&n.animateAll()},drop:c},a(oe,{pluginName:"revertOnSpill"}),ie.prototype={onSpill:function(t){var e=t.dragEl,t=t.putSortable||this.sortable;t.captureAnimationState(),e.parentNode&&e.parentNode.removeChild(e),t.animateAll()},drop:c},a(ie,{pluginName:"removeOnSpill"});var re,ae,le,se,ce,ue=[],de=[],he=!1,fe=!1,pe=!1;function ge(n,o){de.forEach(function(t,e){e=o.children[t.sortableIndex+(n?Number(e):0)];e?o.insertBefore(t,e):o.appendChild(t)})}function me(){ue.forEach(function(t){t!==le&&t.parentNode&&t.parentNode.removeChild(t)})}return Ft.mount(new function(){function t(){for(var t in this.defaults={scroll:!0,forceAutoScrollFallback:!1,scrollSensitivity:30,scrollSpeed:10,bubbleScroll:!0},this)"_"===t.charAt(0)&&"function"==typeof this[t]&&(this[t]=this[t].bind(this))}return t.prototype={dragStarted:function(t){t=t.originalEvent;this.sortable.nativeDraggable?h(document,"dragover",this._handleAutoScroll):this.options.supportPointer?h(document,"pointermove",this._handleFallbackAutoScroll):t.touches?h(document,"touchmove",this._handleFallbackAutoScroll):h(document,"mousemove",this._handleFallbackAutoScroll)},dragOverCompleted:function(t){t=t.originalEvent;this.options.dragOverBubble||t.rootEl||this._handleAutoScroll(t)},drop:function(){this.sortable.nativeDraggable?f(document,"dragover",this._handleAutoScroll):(f(document,"pointermove",this._handleFallbackAutoScroll),f(document,"touchmove",this._handleFallbackAutoScroll),f(document,"mousemove",this._handleFallbackAutoScroll)),te(),Jt(),clearTimeout(g),g=void 0},nulling:function(){Vt=Gt=zt=Qt=Zt=Ut=qt=null,$t.length=0},_handleFallbackAutoScroll:function(t){this._handleAutoScroll(t,!0)},_handleAutoScroll:function(e,n){var o,i=this,r=(e.touches?e.touches[0]:e).clientX,a=(e.touches?e.touches[0]:e).clientY,t=document.elementFromPoint(r,a);Vt=e,n||this.options.forceAutoScrollFallback||w||y||u?(ne(e,this.options,t,n),o=M(t,!0),!Qt||Zt&&r===Ut&&a===qt||(Zt&&te(),Zt=setInterval(function(){var t=M(document.elementFromPoint(r,a),!0);t!==o&&(o=t,Jt()),ne(e,i.options,t,n)},10),Ut=r,qt=a)):this.options.bubbleScroll&&M(t,!0)!==O()?ne(e,this.options,M(t,!1),!1):Jt()}},a(t,{pluginName:"scroll",initializeByDefault:!0})}),Ft.mount(ie,oe),Ft.mount(new function(){function t(){this.defaults={swapClass:"sortable-swap-highlight"}}return t.prototype={dragStart:function(t){t=t.dragEl;ee=t},dragOverValid:function(t){var e=t.completed,n=t.target,o=t.onMove,i=t.activeSortable,r=t.changed,a=t.cancel;i.options.swap&&(t=this.sortable.el,i=this.options,n&&n!==t&&(t=ee,ee=!1!==o(n)?(k(n,i.swapClass,!0),n):null,t&&t!==ee&&k(t,i.swapClass,!1)),r(),e(!0),a())},drop:function(t){var e,n,o=t.activeSortable,i=t.putSortable,r=t.dragEl,a=i||this.sortable,l=this.options;ee&&k(ee,l.swapClass,!1),ee&&(l.swap||i&&i.options.swap)&&r!==ee&&(a.captureAnimationState(),a!==o&&o.captureAnimationState(),n=ee,t=(e=r).parentNode,l=n.parentNode,t&&l&&!t.isEqualNode(n)&&!l.isEqualNode(e)&&(i=j(e),r=j(n),t.isEqualNode(l)&&i<r&&r++,t.insertBefore(n,t.children[i]),l.insertBefore(e,l.children[r])),a.animateAll(),a!==o&&o.animateAll())},nulling:function(){ee=null}},a(t,{pluginName:"swap",eventProperties:function(){return{swapItem:ee}}})}),Ft.mount(new function(){function t(o){for(var t in this)"_"===t.charAt(0)&&"function"==typeof this[t]&&(this[t]=this[t].bind(this));o.options.avoidImplicitDeselect||(o.options.supportPointer?h(document,"pointerup",this._deselectMultiDrag):(h(document,"mouseup",this._deselectMultiDrag),h(document,"touchend",this._deselectMultiDrag))),h(document,"keydown",this._checkKeyDown),h(document,"keyup",this._checkKeyUp),this.defaults={selectedClass:"sortable-selected",multiDragKey:null,avoidImplicitDeselect:!1,setData:function(t,e){var n="";ue.length&&ae===o?ue.forEach(function(t,e){n+=(e?", ":"")+t.textContent}):n=e.textContent,t.setData("Text",n)}}}return t.prototype={multiDragKeyDown:!1,isMultiDrag:!1,delayStartGlobal:function(t){t=t.dragEl;le=t},delayEnded:function(){this.isMultiDrag=~ue.indexOf(le)},setupClone:function(t){var e=t.sortable,t=t.cancel;if(this.isMultiDrag){for(var n=0;n<ue.length;n++)de.push(_(ue[n])),de[n].sortableIndex=ue[n].sortableIndex,de[n].draggable=!1,de[n].style["will-change"]="",k(de[n],this.options.selectedClass,!1),ue[n]===le&&k(de[n],this.options.chosenClass,!1);e._hideClone(),t()}},clone:function(t){var e=t.sortable,n=t.rootEl,o=t.dispatchSortableEvent,t=t.cancel;this.isMultiDrag&&(this.options.removeCloneOnHide||ue.length&&ae===e&&(ge(!0,n),o("clone"),t()))},showClone:function(t){var e=t.cloneNowShown,n=t.rootEl,t=t.cancel;this.isMultiDrag&&(ge(!1,n),de.forEach(function(t){R(t,"display","")}),e(),ce=!1,t())},hideClone:function(t){var e=this,n=(t.sortable,t.cloneNowHidden),t=t.cancel;this.isMultiDrag&&(de.forEach(function(t){R(t,"display","none"),e.options.removeCloneOnHide&&t.parentNode&&t.parentNode.removeChild(t)}),n(),ce=!0,t())},dragStartGlobal:function(t){t.sortable;!this.isMultiDrag&&ae&&ae.multiDrag._deselectMultiDrag(),ue.forEach(function(t){t.sortableIndex=j(t)}),ue=ue.sort(function(t,e){return t.sortableIndex-e.sortableIndex}),pe=!0},dragStarted:function(t){var e,n=this,t=t.sortable;this.isMultiDrag&&(this.options.sort&&(t.captureAnimationState(),this.options.animation&&(ue.forEach(function(t){t!==le&&R(t,"position","absolute")}),e=X(le,!1,!0,!0),ue.forEach(function(t){t!==le&&C(t,e)}),he=fe=!0)),t.animateAll(function(){he=fe=!1,n.options.animation&&ue.forEach(function(t){T(t)}),n.options.sort&&me()}))},dragOver:function(t){var e=t.target,n=t.completed,t=t.cancel;fe&&~ue.indexOf(e)&&(n(!1),t())},revert:function(t){var n,o,e=t.fromSortable,i=t.rootEl,r=t.sortable,a=t.dragRect;1<ue.length&&(ue.forEach(function(t){r.addAnimationState({target:t,rect:fe?X(t):a}),T(t),t.fromRect=a,e.removeAnimationState(t)}),fe=!1,n=!this.options.removeCloneOnHide,o=i,ue.forEach(function(t,e){e=o.children[t.sortableIndex+(n?Number(e):0)];e?o.insertBefore(t,e):o.appendChild(t)}))},dragOverCompleted:function(t){var e,n=t.sortable,o=t.isOwner,i=t.insertion,r=t.activeSortable,a=t.parentEl,l=t.putSortable,t=this.options;i&&(o&&r._hideClone(),he=!1,t.animation&&1<ue.length&&(fe||!o&&!r.options.sort&&!l)&&(e=X(le,!1,!0,!0),ue.forEach(function(t){t!==le&&(C(t,e),a.appendChild(t))}),fe=!0),o||(fe||me(),1<ue.length?(o=ce,r._showClone(n),r.options.animation&&!ce&&o&&de.forEach(function(t){r.addAnimationState({target:t,rect:se}),t.fromRect=se,t.thisAnimationDuration=null})):r._showClone(n)))},dragOverAnimationCapture:function(t){var e=t.dragRect,n=t.isOwner,t=t.activeSortable;ue.forEach(function(t){t.thisAnimationDuration=null}),t.options.animation&&!n&&t.multiDrag.isMultiDrag&&(se=a({},e),e=v(le,!0),se.top-=e.f,se.left-=e.e)},dragOverAnimationComplete:function(){fe&&(fe=!1,me())},drop:function(t){var e=t.originalEvent,n=t.rootEl,o=t.parentEl,i=t.sortable,r=t.dispatchSortableEvent,a=t.oldIndex,l=t.putSortable,s=l||this.sortable;if(e){var c,u,d,h=this.options,f=o.children;if(!pe)if(h.multiDragKey&&!this.multiDragKeyDown&&this._deselectMultiDrag(),k(le,h.selectedClass,!~ue.indexOf(le)),~ue.indexOf(le))ue.splice(ue.indexOf(le),1),re=null,z({sortable:i,rootEl:n,name:"deselect",targetEl:le,originalEvent:e});else{if(ue.push(le),z({sortable:i,rootEl:n,name:"select",targetEl:le,originalEvent:e}),e.shiftKey&&re&&i.el.contains(re)){var p=j(re),t=j(le);if(~p&&~t&&p!==t)for(var g,m=p<t?(g=p,t):(g=t,p+1);g<m;g++)~ue.indexOf(f[g])||(k(f[g],h.selectedClass,!0),ue.push(f[g]),z({sortable:i,rootEl:n,name:"select",targetEl:f[g],originalEvent:e}))}else re=le;ae=s}pe&&this.isMultiDrag&&(fe=!1,(o[K].options.sort||o!==n)&&1<ue.length&&(c=X(le),u=j(le,":not(."+this.options.selectedClass+")"),!he&&h.animation&&(le.thisAnimationDuration=null),s.captureAnimationState(),he||(h.animation&&(le.fromRect=c,ue.forEach(function(t){var e;t.thisAnimationDuration=null,t!==le&&(e=fe?X(t):c,t.fromRect=e,s.addAnimationState({target:t,rect:e}))})),me(),ue.forEach(function(t){f[u]?o.insertBefore(t,f[u]):o.appendChild(t),u++}),a===j(le)&&(d=!1,ue.forEach(function(t){t.sortableIndex!==j(t)&&(d=!0)}),d&&(r("update"),r("sort")))),ue.forEach(function(t){T(t)}),s.animateAll()),ae=s),(n===o||l&&"clone"!==l.lastPutMode)&&de.forEach(function(t){t.parentNode&&t.parentNode.removeChild(t)})}},nullingGlobal:function(){this.isMultiDrag=pe=!1,de.length=0},destroyGlobal:function(){this._deselectMultiDrag(),f(document,"pointerup",this._deselectMultiDrag),f(document,"mouseup",this._deselectMultiDrag),f(document,"touchend",this._deselectMultiDrag),f(document,"keydown",this._checkKeyDown),f(document,"keyup",this._checkKeyUp)},_deselectMultiDrag:function(t){if(!(void 0!==pe&&pe||ae!==this.sortable||t&&P(t.target,this.options.draggable,this.sortable.el,!1)||t&&0!==t.button))for(;ue.length;){var e=ue[0];k(e,this.options.selectedClass,!1),ue.shift(),z({sortable:this.sortable,rootEl:this.sortable.el,name:"deselect",targetEl:e,originalEvent:t})}},_checkKeyDown:function(t){t.key===this.options.multiDragKey&&(this.multiDragKeyDown=!0)},_checkKeyUp:function(t){t.key===this.options.multiDragKey&&(this.multiDragKeyDown=!1)}},a(t,{pluginName:"multiDrag",utils:{select:function(t){var e=t.parentNode[K];e&&e.options.multiDrag&&!~ue.indexOf(t)&&(ae&&ae!==e&&(ae.multiDrag._deselectMultiDrag(),ae=e),k(t,e.options.selectedClass,!0),ue.push(t))},deselect:function(t){var e=t.parentNode[K],n=ue.indexOf(t);e&&e.options.multiDrag&&~n&&(k(t,e.options.selectedClass,!1),ue.splice(n,1))}},eventProperties:function(){var n=this,o=[],i=[];return ue.forEach(function(t){var e;o.push({multiDragElement:t,index:t.sortableIndex}),e=fe&&t!==le?-1:fe?j(t,":not(."+n.options.selectedClass+")"):j(t),i.push({multiDragElement:t,index:e})}),{items:r(ue),clones:[].concat(de),oldIndicies:o,newIndicies:i}},optionListeners:{multiDragKey:function(t){return"ctrl"===(t=t.toLowerCase())?t="Control":1<t.length&&(t=t.charAt(0).toUpperCase()+t.substr(1)),t}}})}),Ft});';var L={brand:"AgentX",subtitle:"Team AI ops",nodes:"machines",agentsCount:"agents",activeNow:"handling now",errorsCount:"failed",stats:{active:"Handling",total:"Today",errors:"Failed"},idle:"idle",runningNoPreview:"working \xB7 preparing reply",recentActivities:"Recent activities \u2192",noAgentsOnNode:"No agents set up on this machine.",unreachable:"This machine is unreachable.",neverRan:"not used yet",tierLabels:{"claude-code":"Claude Code",sdk:"SDK",orchestrator:"Orchestrator"},taskModalTitle:"Task activity",taskModalConnecting:"connecting\u2026",taskModalLive:"live",taskModalFinished:"finished",taskModalArchived:"archived",taskModalLoadFailed:"couldn't load",taskModalFinalResponse:"Final reply",historyPanelTitle:"Recent activities",historyEmpty:"No activity yet.",historyLoading:"loading\u2026"};var Ie=[{term:"Agent",definition:'An AI worker with its own role, instructions, and channels it responds on. Think of each agent as a job title \u2014 "support", "devops", "sales".'},{term:"Trigger word",alias:"mention",definition:"A word that activates an agent. When the trigger appears in a message (e.g. @support), AgentX routes the message to that agent."},{term:"Channel",definition:"Where messages come from \u2014 Telegram, WhatsApp, Discord, GitLab comments, a scheduled cron, or an HTTP webhook."},{term:"AI engine",alias:"tier",definition:"Which backend answers: Claude Code (reasoning + tools + files), an SDK provider (OpenAI, Anthropic API, Ollama), or an Orchestrator that coordinates sub-agents."},{term:"Agent folder",alias:"workspace",definition:"The directory on disk where the agent lives. It holds the agent's personality (CLAUDE.md), its knowledge (wiki), and the tools it can use."},{term:"Team network",alias:"mesh",definition:'When you run AgentX on more than one machine, the machines find each other and share work. Each machine is a "node"; together they are your team network.'},{term:"Status check-in",alias:"heartbeat",definition:"A lightweight ping between machines so each one knows the others are alive and responsive."},{term:"Board",definition:"A Kanban view of tasks (issues, tickets) pulled from GitLab. Drag cards between columns to move work forward \u2014 the labels update upstream automatically."},{term:"Task",definition:"A single conversation or job an agent handles, from trigger message to final reply. Every task is logged and replayable."},{term:"Schedule",alias:"cron",definition:'A recurring job \u2014 e.g. "every Monday at 9am" \u2014 that nudges an agent without a human trigger.'},{term:"Status label",alias:"scopedLabel",definition:"A GitLab label that moves an issue between Kanban columns (e.g. Status::Doing). Labels are mutually exclusive by prefix."}];import{existsSync as de,readFileSync as ht,writeFileSync as Ne,rmSync as un}from"fs";import{resolve as Z}from"path";G();import{existsSync as S,readFileSync as oe,writeFileSync as re,mkdirSync as K,readdirSync as ne,rmSync as ct,statSync as C}from"fs";import{resolve as Le,relative as dt,dirname as ie,join as R,extname as U,basename as se}from"path";var E=200*1024,De=new Set([".md",".markdown",".txt"]),B=new Set([".md",".markdown",".txt",".json",".jsonc",".yaml",".yml",".toml",".sh",".bash",".zsh",".py",".js",".mjs",".ts",".tsx",".jsx",".css",".html",".lock",".cfg",".ini",".env",".gitignore"]),pt=6,ut=new Set(["CLAUDE.md","SOUL.md","IDENTITY.md","PERSONA.md","AGENT.md","BOOTSTRAP.md"]);function D(t,e){if(!t)throw new Error("Agent workspace is not configured.");let a=Le(t);if(S(a)||K(a,{recursive:!0}),!e||e.startsWith("/")||e.match(/^[a-zA-Z]:/))throw new Error(`Path must be relative to the workspace: ${e}`);let n=Le(a,e);if(dt(a,n).startsWith(".."))throw new Error(`Path escapes the workspace: ${e}`);return n}function Pe(t){let e=U(t).toLowerCase();if(!De.has(e))throw new Error(`Only text files (.md, .markdown, .txt) can be edited from the admin panel (got ${e}).`)}function te(t,e){let a=t.split(/\r?\n/).find(n=>n.trim().startsWith("#"));return a&&a.replace(/^#+\s*/,"").trim().slice(0,120)||e}function z(t){let e=D(t,"."),a=[],n=new Set,o=[];try{o=ne(e)}catch{}for(let s of ut){let l=R(e,s);if(S(l)&&C(l).isFile()){let c=C(l).size,m=c>0&&c<E?ae(l):"";a.push({path:s,title:te(m,s),size:c,exists:!0}),n.add(s)}else a.push({path:s,title:s,size:0,exists:!1}),n.add(s)}for(let s of o){if(n.has(s))continue;let l=R(e,s);try{let c=C(l);if(!c.isFile()||!De.has(U(s).toLowerCase()))continue;let m=c.size>0&&c.size<E?ae(l):"";a.push({path:s,title:te(m,s),size:c.size,exists:!0})}catch{}}let r=[],i=R(e,".claude","skills");if(S(i))try{for(let s of ne(i)){let l=R(i,s),c;try{c=C(l)}catch{continue}if(!c.isDirectory())continue;let m=R(l,"SKILL.md");if(!S(m))continue;let u=C(m),f=u.size<E?ae(m):"";r.push({slug:s,title:te(f,s),size:u.size,path:`.claude/skills/${s}/SKILL.md`})}}catch{}return r.sort((s,l)=>s.slug.localeCompare(l.slug)),{identity:a,skills:r,workspace:e}}function ae(t){try{return oe(t,"utf-8")}catch{return""}}function X(t,e){let a=D(t,e);if(Pe(a),!S(a))return{path:e,content:""};if(C(a).size>E)throw new Error(`File is too large to edit in the admin panel (> ${E/1024} KB).`);return{path:e,content:oe(a,"utf-8")}}function V(t,e,a){let n=D(t,e);Pe(n);let o=Buffer.from(a,"utf-8");if(o.length>E)throw new Error(`File too large (${o.length} > ${E} bytes).`);return K(ie(n),{recursive:!0}),re(n,o),{path:e,bytes:o.length}}function J(t,e,a={}){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Skill slug must be lowercase (letters, digits, -, _) and start with a letter or digit.");let n=`.claude/skills/${e}/SKILL.md`,o=D(t,n);if(S(o))throw new Error(`Skill "${e}" already exists.`);K(ie(o),{recursive:!0});let r=a.content?.trim()?a.content:mt(e,a.title);return re(o,r),{slug:e,path:n}}function Y(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let a=D(t,`.claude/skills/${e}`);if(!S(a))throw new Error(`Skill "${e}" not found.`);if(!C(a).isDirectory())throw new Error(`Skill path is not a directory: ${e}`);return ct(a,{recursive:!0,force:!0}),{slug:e}}function Oe(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let a=D(t,`.claude/skills/${e}`);if(!S(a))throw new Error(`Skill "${e}" not found.`);let n=[];return o(a,"",0,n),n.sort((r,i)=>r.kind!==i.kind?r.kind==="dir"?-1:1:r.path.localeCompare(i.path)),n;function o(r,i,s,l){if(s>pt)return;let c=[];try{c=ne(r)}catch{return}for(let m of c){if(m==="node_modules"||m===".git")continue;let u=R(r,m),f=i?`${i}/${m}`:m,d;try{d=C(u)}catch{continue}if(d.isDirectory())l.push({path:`${f}/`,kind:"dir",size:0,editable:!1}),o(u,f,s+1,l);else if(d.isFile()){let p=U(m).toLowerCase(),v=B.has(p)||B.has(m.toLowerCase());l.push({path:f,kind:"file",size:d.size,editable:v&&d.size<E})}}}}function He(t,e,a){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);if(!a||a.includes(".."))throw new Error(`Invalid file path: ${a}`);let n=D(t,`.claude/skills/${e}/${a}`);if(!S(n)||!C(n).isFile())throw new Error(`File not found: ${a}`);let o=U(n).toLowerCase(),r=se(n).toLowerCase();if(!B.has(o)&&!B.has(r))throw new Error(`File type not editable: ${a}`);if(C(n).size>E)throw new Error(`File too large to edit (> ${E/1024} KB): ${a}`);return{path:a,content:oe(n,"utf-8")}}function Re(t,e,a,n){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);if(!a||a.includes(".."))throw new Error(`Invalid file path: ${a}`);let o=D(t,`.claude/skills/${e}/${a}`),r=U(o).toLowerCase(),i=se(o).toLowerCase();if(!B.has(r)&&!B.has(i))throw new Error(`File type not editable: ${a}`);let s=Buffer.from(n,"utf-8");if(s.length>E)throw new Error(`File too large (${s.length} > ${E} bytes).`);return K(ie(o),{recursive:!0}),re(o,s),{path:a,bytes:s.length}}function Q(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let a=D(t,`.claude/skills/${e}`);if(!S(a))throw new Error(`Skill "${e}" not found.`);let n=o=>S(R(a,o));return n("pnpm-lock.yaml")?{manager:"pnpm",file:"pnpm-lock.yaml",command:"pnpm install"}:n("yarn.lock")?{manager:"yarn",file:"yarn.lock",command:"yarn install"}:n("package.json")?{manager:"npm",file:"package.json",command:"npm install"}:n("requirements.txt")?{manager:"pip",file:"requirements.txt",command:"pip install -r requirements.txt"}:n("Gemfile")?{manager:"bundle",file:"Gemfile",command:"bundle install"}:{manager:null,file:null,command:null}}function mt(t,e){return`# ${e?.trim()||t}
2
2
 
3
3
  Describe what this skill does and when the agent should use it. Keep it under ~5 lines \u2014 the agent reads this to decide whether to invoke the skill.
4
4
 
@@ -11,12 +11,12 @@ Document the arguments, commands, or files the skill expects. Example:
11
11
 
12
12
  \`\`\`bash
13
13
  # Example invocation
14
- claude-code ${ze(t)} --arg value
14
+ claude-code ${se(t)} --arg value
15
15
  \`\`\`
16
16
  `}var $=`<link rel="preconnect" href="https://fonts.googleapis.com">
17
17
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
18
18
  <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
19
- <script>(function(){try{var t=localStorage.getItem('ax-theme')||'dark';document.documentElement.setAttribute('data-theme',t)}catch(e){}})();</script>`,I=`
19
+ <script>(function(){try{var t=localStorage.getItem('ax-theme')||'dark';document.documentElement.setAttribute('data-theme',t)}catch(e){}})();</script>`,M=`
20
20
  .ax-topbar{display:flex;align-items:center;justify-content:space-between;
21
21
  padding:8px 18px;border-bottom:1px solid var(--ax-border);
22
22
  background:var(--ax-bg-elev);position:sticky;top:0;z-index:20;gap:10px;flex-wrap:nowrap}
@@ -80,7 +80,7 @@ claude-code ${ze(t)} --arg value
80
80
  background:var(--ax-bg-elev);border-bottom:1px solid var(--ax-border);
81
81
  flex-wrap:wrap}
82
82
  .ax-subheader > * {flex-shrink:0}
83
- .ax-subheader .spacer{flex:1}`,L=`<script>
83
+ .ax-subheader .spacer{flex:1}`,_=`<script>
84
84
  (function(){
85
85
  function wireTheme(){
86
86
  var sw = document.querySelectorAll('[data-theme-opt]');
@@ -150,23 +150,23 @@ claude-code ${ze(t)} --arg value
150
150
  document.addEventListener('DOMContentLoaded', wire);
151
151
  } else { wire(); }
152
152
  })();
153
- </script>`;function D(t){let e=t.peers&&t.peers.length>0?t.peers:[{id:"local",name:"this daemon",dashboardUrl:"",primary:!0}],a=t.currentPeerId||e.find(c=>c.primary)?.id||e[0].id,n=e.find(c=>c.id===a)||e[0],o=e.map(c=>{let d=c.id===a,g=c.primary?' <span style="color:var(--ax-muted);font-size:10px">\xB7 primary</span>':"",u=!!c.tokenScope&&!c.primary,i=u?"#":c.dashboardUrl?`${c.dashboardUrl.replace(/\/+$/,"")}/admin`:"#",p=u?` data-peer-id="${M(c.id)}" data-peer-action="proxy"`:c.primary?' data-peer-id="primary" data-peer-action="proxy"':"",h=u?'<div class="url" style="color:var(--ax-accent)">manage from this dashboard \u2713</div>':c.tokenScope?`<div class="url">${M(c.tokenScope)}</div>`:c.dashboardUrl?'<div class="url" style="color:var(--ax-muted)">(open peer dashboard \u2197)</div>':"";return`<a href="${M(i)}" class="${d?"is-current":""}"${p}>
154
- <div class="row"><span class="dot"></span><span>${M(c.name)}${g}</span></div>
155
- ${c.dashboardUrl?`<div class="url">${M(c.dashboardUrl)}</div>`:""}
156
- ${h}
153
+ </script>`;function I(t){let e=t.peers&&t.peers.length>0?t.peers:[{id:"local",name:"this daemon",dashboardUrl:"",primary:!0}],a=t.currentPeerId||e.find(l=>l.primary)?.id||e[0].id,n=e.find(l=>l.id===a)||e[0],o=e.map(l=>{let c=l.id===a,m=l.primary?' <span style="color:var(--ax-muted);font-size:10px">\xB7 primary</span>':"",u=!!l.tokenScope&&!l.primary,f=u?"#":l.dashboardUrl?`${l.dashboardUrl.replace(/\/+$/,"")}/admin`:"#",d=u?` data-peer-id="${N(l.id)}" data-peer-action="proxy"`:l.primary?' data-peer-id="primary" data-peer-action="proxy"':"",p=u?'<div class="url" style="color:var(--ax-accent)">manage from this dashboard \u2713</div>':l.tokenScope?`<div class="url">${N(l.tokenScope)}</div>`:l.dashboardUrl?'<div class="url" style="color:var(--ax-muted)">(open peer dashboard \u2197)</div>':"";return`<a href="${N(f)}" class="${c?"is-current":""}"${d}>
154
+ <div class="row"><span class="dot"></span><span>${N(l.name)}${m}</span></div>
155
+ ${l.dashboardUrl?`<div class="url">${N(l.dashboardUrl)}</div>`:""}
156
+ ${p}
157
157
  </a>`}).join(""),r=`<div class="ax-mesh-sel" aria-haspopup="menu">
158
158
  <span class="lbl">managing</span>
159
- <span class="name">${M(n.name)}</span>
159
+ <span class="name">${N(n.name)}</span>
160
160
  <span class="chev">\u25BE</span>
161
161
  <div class="ax-mesh-menu" role="menu">${o}</div>
162
- </div>`,s=[{id:"live",label:"Live",href:"/live"},{id:"boards",label:"Boards",href:"/"},{id:"admin",label:"Settings",href:"/admin"},{id:"glossary",label:"Glossary",href:"/glossary"}].map(c=>{let d=c.id===t.activeTab?"ax-topbar__tab is-active":"ax-topbar__tab";return`<a href="${c.href}" class="${d}">${c.label}</a>`}).join("");return`<header class="ax-topbar">
162
+ </div>`,i=[{id:"live",label:"Live",href:"/live"},{id:"boards",label:"Boards",href:"/"},{id:"admin",label:"Settings",href:"/admin"},{id:"glossary",label:"Glossary",href:"/glossary"}].map(l=>{let c=l.id===t.activeTab?"ax-topbar__tab is-active":"ax-topbar__tab";return`<a href="${l.href}" class="${c}">${l.label}</a>`}).join("");return`<header class="ax-topbar">
163
163
  <div class="ax-topbar__left">
164
164
  <div class="ax-brand">
165
165
  <span class="ax-brand__mark">AX</span>
166
166
  <span class="ax-brand__name">AgentX</span>
167
- <span class="ax-brand__subtitle">${M(t.subtitle)}</span>
167
+ <span class="ax-brand__subtitle">${N(t.subtitle)}</span>
168
168
  </div>
169
- <nav class="ax-topbar__tabs">${s}</nav>
169
+ <nav class="ax-topbar__tabs">${i}</nav>
170
170
  </div>
171
171
  <div class="ax-topbar__right">
172
172
  ${t.rightExtras||""}
@@ -177,11 +177,11 @@ claude-code ${ze(t)} --arg value
177
177
  <button data-theme-opt="crt">CRT</button>
178
178
  </div>
179
179
  </div>
180
- </header>${t.subheader?`<div class="ax-subheader">${t.subheader}</div>`:""}`}function M(t){return String(t||"").replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function Te(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(At(a,n))}async function Ce(t,e){let a=X();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function Ae(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await nt(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await qe(t),o={"GET /api/admin/state":()=>We(),"POST /api/admin/agents":()=>Je(n),"PATCH /api/admin/agents":()=>Qe(n),"DELETE /api/admin/agents":()=>Ze(n),"POST /api/admin/agents/access":()=>Ge(n),"POST /api/admin/channels/telegram":()=>et(n),"DELETE /api/admin/channels/telegram":()=>wt(n),"POST /api/admin/channels/telegram/toggle":()=>Et(n),"POST /api/admin/crons":()=>St(n),"DELETE /api/admin/crons":()=>Tt(n),"POST /api/admin/config/raw":()=>Ct(n),"GET /api/admin/tokens":()=>Ke(),"POST /api/admin/tokens":()=>Xe(n),"DELETE /api/admin/tokens":()=>Ve(n),"POST /api/admin/agents/test":()=>Ye(n),"PATCH /api/admin/channels/telegram":()=>tt(n),"POST /api/admin/channels/slack":()=>gt(n),"POST /api/admin/channels/slack/toggle":()=>ft(n),"POST /api/admin/channels/discord":()=>bt(n),"POST /api/admin/channels/discord/toggle":()=>vt(n),"POST /api/admin/channels/gitlab":()=>xt(n),"POST /api/admin/channels/gitlab/toggle":()=>yt(n),"GET /api/admin/channels/whatsapp/state":()=>at("/whatsapp/state"),"POST /api/admin/crons/preview":()=>kt(n),"POST /api/admin/webhooks":()=>ct(n),"PATCH /api/admin/webhooks":()=>dt(n),"DELETE /api/admin/webhooks":()=>ht(n),"POST /api/admin/mesh/peers":()=>pt(n),"DELETE /api/admin/mesh/peers":()=>ut(n),"POST /api/admin/mesh/toggle":()=>mt(n),"GET /api/admin/files":()=>ot(t),"GET /api/admin/files/read":()=>rt(t),"PUT /api/admin/files":()=>it(n),"POST /api/admin/files/skill":()=>st(n),"DELETE /api/admin/files/skill":()=>lt(n)},r=`${t.method} ${a}`,s=o[r];if(!s){W(e,404,{error:`unknown admin endpoint: ${r}`});return}let l=await s();W(e,200,l)}catch(n){W(e,400,{error:n.message||"admin op failed"})}}function W(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function qe(t){return new Promise((e,a)=>{let n="";t.on("data",o=>{n+=o}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(o){a(o)}}),t.on("error",a)})}function X(){let t=N(process.cwd(),"agentx.json");return K(t)?JSON.parse(je(t,"utf-8")):null}function We(){let t=X();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([i,p])=>({id:i,name:p.name,tier:p.tier,model:p.model,mentions:p.mentions||[],workspace:p.workspace,access:p.access||"private",systemPrompt:p.systemPrompt||"",maxConcurrent:p.maxConcurrent??1,maxExecutionMinutes:p.maxExecutionMinutes??20,permissionMode:p.permissionMode||"default"})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([i,p])=>({id:i,botUsername:p.botUsername||"",agentBinding:p.agentBinding||"",botTokenRef:p.botToken||""}))},o={enabled:!!t.channels?.slack?.enabled,botTokenRef:t.channels?.slack?.botToken||"",appTokenRef:t.channels?.slack?.appToken||"",agentBinding:t.channels?.slack?.agentBinding||""},r={enabled:!!t.channels?.discord?.enabled,tokenRef:t.channels?.discord?.token||"",agentBinding:t.channels?.discord?.agentBinding||""},s={enabled:!!t.channels?.gitlab?.enabled,host:t.channels?.gitlab?.host||"",webhookPort:t.channels?.gitlab?.webhookPort||18810,tokenRef:t.channels?.gitlab?.token||"",routeCount:Array.isArray(t.channels?.gitlab?.routes)?t.channels.gitlab.routes.length:0,agentMappingCount:Array.isArray(t.channels?.gitlab?.agentMappings)?t.channels.gitlab.agentMappings.length:0},l={enabled:!!t.channels?.whatsapp?.enabled,sessionDir:t.channels?.whatsapp?.sessionDir||".agentx/whatsapp-sessions",routeCount:Array.isArray(t.channels?.whatsapp?.routes)?t.channels.whatsapp.routes.length:0},c=Object.entries(t.crons||{}).map(([i,p])=>({id:i,schedule:p.schedule,agent:p.agent,prompt:(p.prompt||"").slice(0,200),enabled:p.enabled!==!1})),d=Array.isArray(t.webhooks)?t.webhooks.map(i=>({id:i.id,source:i.source,agentId:i.agentId,secretEnv:i.secretEnv||"",description:i.description||"",enabled:i.enabled!==!1})):[],g={enabled:!!t.mesh?.enabled,discovery:t.mesh?.discovery||"static",peers:(t.mesh?.peers||[]).map(i=>({url:i.url,name:i.name,hasToken:!!i.token}))},u=t.dashboard?.daemonUrl||"http://localhost:18800";return{exists:!0,agents:e,telegram:n,slack:o,discord:r,gitlab:s,whatsapp:l,crons:c,webhooks:d,mesh:g,daemonUrl:u,nodeName:t.node?.name}}function Ge(t){let e=String(t?.id||"").trim(),a=t?.access==="public"?"public":"private";if(!e)throw new Error("Agent id is required.");let{summary:n}=x(o=>{if(!o.agents?.[e])throw new Error(`Agent "${e}" not found.`);return o.agents[e].access=a,`agent "${e}" is now ${a}`});return{summary:n}}function Ke(){return new T().list().map(t=>({id:t.id,name:t.name,prefix:t.prefix,scopes:t.scopes,createdAt:t.createdAt,expiresAt:t.expiresAt,revokedAt:t.revokedAt,lastUsedAt:t.lastUsedAt}))}function Xe(t){let e=String(t?.name||"").trim(),a=Array.isArray(t?.scopes)?t.scopes.map(String):[],n=t?.expiresInDays?Number(t.expiresInDays):void 0,{token:o,record:r}=new T().create({name:e,scopes:a,expiresInDays:n});return{summary:`created token "${e}"`,token:o,record:r}}function Ve(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Token id is required.");let a=new T().revoke(e);if(!a)throw new Error(`Token "${e}" not found.`);return{summary:`revoked token ${e} (${a.name})`}}async function Ye(t){let e=String(t?.agent||t?.id||"").trim(),a=String(t?.message||"").trim(),n=String(t?.chatId||"").trim()||`admin-${Date.now()}`;if(!e)throw new Error("Agent id is required.");if(!a)throw new Error("Message is required.");let o="http://127.0.0.1:18800",r;try{let g=U();o=g.dashboard.daemonUrl.replace(/\/+$/,"")||o,r=g.dashboard.token}catch{}let s={"Content-Type":"application/json"};r&&(s.Authorization=`Bearer ${r}`);let l=await fetch(`${o}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"test-drive",sender:"admin",chatId:n}})}),c=await l.text(),d;try{d=JSON.parse(c)}catch{d={content:c}}if(!l.ok)throw new Error(d?.error||`daemon HTTP ${l.status}`);return{chatId:n,response:d}}function Je(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=t?.tier==="sdk"?"sdk":"claude-code",o=$e(t?.triggerWords),r=t?.model?String(t.model).trim():void 0,s=t?.personality?String(t.personality).trim():void 0;if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Agent id must be lowercase (letters, digits, -, _).");if(!a)throw new Error("Agent name is required.");if(o.length===0)throw new Error("At least one trigger word is required.");let l=N(process.cwd(),"agents",e),{summary:c}=x(g=>{if(g.agents=g.agents||{},g.agents[e])throw new Error(`Agent "${e}" already exists.`);let u={name:a,workspace:l,tier:n,mentions:o,maxConcurrent:2,permissionMode:"default"};return r&&(u.model=r),s&&(u.systemPrompt=s.slice(0,400)),g.agents[e]=u,`added agent "${e}"`}),d=N(l,"CLAUDE.md");if(!K(d))try{ee("fs").mkdirSync(l,{recursive:!0}),Se(d,`# ${a}
180
+ </header>${t.subheader?`<div class="ax-subheader">${t.subheader}</div>`:""}`}function N(t){return String(t||"").replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function Be(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Qt(a,n))}async function ze(t,e){let a=pe();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function je(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await $t(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await gt(t),o={"GET /api/admin/state":()=>ft(),"POST /api/admin/agents":()=>wt(n),"PATCH /api/admin/agents":()=>Et(n),"DELETE /api/admin/agents":()=>St(n),"POST /api/admin/agents/access":()=>vt(n),"POST /api/admin/channels/telegram":()=>Tt(n),"DELETE /api/admin/channels/telegram":()=>Kt(n),"POST /api/admin/channels/telegram/toggle":()=>Xt(n),"POST /api/admin/crons":()=>Vt(n),"DELETE /api/admin/crons":()=>Jt(n),"POST /api/admin/config/raw":()=>Yt(n),"GET /api/admin/tokens":()=>bt(),"POST /api/admin/tokens":()=>xt(n),"DELETE /api/admin/tokens":()=>yt(n),"POST /api/admin/agents/test":()=>kt(n),"PATCH /api/admin/channels/telegram":()=>At(n),"POST /api/admin/channels/slack":()=>zt(n),"POST /api/admin/channels/slack/toggle":()=>jt(n),"POST /api/admin/channels/discord":()=>Ut(n),"POST /api/admin/channels/discord/toggle":()=>Ft(n),"POST /api/admin/channels/gitlab":()=>qt(n),"POST /api/admin/channels/gitlab/toggle":()=>Gt(n),"GET /api/admin/channels/whatsapp/state":()=>Ct("/whatsapp/state"),"POST /api/admin/crons/preview":()=>Wt(n),"POST /api/admin/webhooks":()=>Pt(n),"PATCH /api/admin/webhooks":()=>Ot(n),"DELETE /api/admin/webhooks":()=>Bt(n),"POST /api/admin/mesh/peers":()=>Ht(n),"DELETE /api/admin/mesh/peers":()=>Rt(n),"POST /api/admin/mesh/toggle":()=>Nt(n),"GET /api/admin/files":()=>Mt(t),"GET /api/admin/files/read":()=>_t(t),"PUT /api/admin/files":()=>It(n),"POST /api/admin/files/skill":()=>Lt(n),"DELETE /api/admin/files/skill":()=>Dt(n)},r=`${t.method} ${a}`,i=o[r];if(!i){le(e,404,{error:`unknown admin endpoint: ${r}`});return}let s=await i();le(e,200,s)}catch(n){le(e,400,{error:n.message||"admin op failed"})}}function le(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function gt(t){return new Promise((e,a)=>{let n="";t.on("data",o=>{n+=o}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(o){a(o)}}),t.on("error",a)})}function pe(){let t=Z(process.cwd(),"agentx.json");return de(t)?JSON.parse(ht(t,"utf-8")):null}function ft(){let t=pe();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([f,d])=>({id:f,name:d.name,tier:d.tier,model:d.model,mentions:d.mentions||[],workspace:d.workspace,access:d.access||"private",systemPrompt:d.systemPrompt||"",maxConcurrent:d.maxConcurrent??1,maxExecutionMinutes:d.maxExecutionMinutes??20,permissionMode:d.permissionMode||"default"})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([f,d])=>({id:f,botUsername:d.botUsername||"",agentBinding:d.agentBinding||"",botTokenRef:d.botToken||""}))},o={enabled:!!t.channels?.slack?.enabled,botTokenRef:t.channels?.slack?.botToken||"",appTokenRef:t.channels?.slack?.appToken||"",agentBinding:t.channels?.slack?.agentBinding||""},r={enabled:!!t.channels?.discord?.enabled,tokenRef:t.channels?.discord?.token||"",agentBinding:t.channels?.discord?.agentBinding||""},i={enabled:!!t.channels?.gitlab?.enabled,host:t.channels?.gitlab?.host||"",webhookPort:t.channels?.gitlab?.webhookPort||18810,tokenRef:t.channels?.gitlab?.token||"",routeCount:Array.isArray(t.channels?.gitlab?.routes)?t.channels.gitlab.routes.length:0,agentMappingCount:Array.isArray(t.channels?.gitlab?.agentMappings)?t.channels.gitlab.agentMappings.length:0},s={enabled:!!t.channels?.whatsapp?.enabled,sessionDir:t.channels?.whatsapp?.sessionDir||".agentx/whatsapp-sessions",routeCount:Array.isArray(t.channels?.whatsapp?.routes)?t.channels.whatsapp.routes.length:0},l=Object.entries(t.crons||{}).map(([f,d])=>({id:f,schedule:d.schedule,agent:d.agent,prompt:(d.prompt||"").slice(0,200),enabled:d.enabled!==!1})),c=Array.isArray(t.webhooks)?t.webhooks.map(f=>({id:f.id,source:f.source,agentId:f.agentId,secretEnv:f.secretEnv||"",description:f.description||"",enabled:f.enabled!==!1})):[],m={enabled:!!t.mesh?.enabled,discovery:t.mesh?.discovery||"static",peers:(t.mesh?.peers||[]).map(f=>({url:f.url,name:f.name,hasToken:!!f.token}))},u=t.dashboard?.daemonUrl||"http://localhost:18800";return{exists:!0,agents:e,telegram:n,slack:o,discord:r,gitlab:i,whatsapp:s,crons:l,webhooks:c,mesh:m,daemonUrl:u,nodeName:t.node?.name}}function vt(t){let e=String(t?.id||"").trim(),a=t?.access==="public"?"public":"private";if(!e)throw new Error("Agent id is required.");let{summary:n}=x(o=>{if(!o.agents?.[e])throw new Error(`Agent "${e}" not found.`);return o.agents[e].access=a,`agent "${e}" is now ${a}`});return{summary:n}}function bt(){return new O().list().map(t=>({id:t.id,name:t.name,prefix:t.prefix,scopes:t.scopes,createdAt:t.createdAt,expiresAt:t.expiresAt,revokedAt:t.revokedAt,lastUsedAt:t.lastUsedAt}))}function xt(t){let e=String(t?.name||"").trim(),a=Array.isArray(t?.scopes)?t.scopes.map(String):[],n=t?.expiresInDays?Number(t.expiresInDays):void 0,{token:o,record:r}=new O().create({name:e,scopes:a,expiresInDays:n});return{summary:`created token "${e}"`,token:o,record:r}}function yt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Token id is required.");let a=new O().revoke(e);if(!a)throw new Error(`Token "${e}" not found.`);return{summary:`revoked token ${e} (${a.name})`}}async function kt(t){let e=String(t?.agent||t?.id||"").trim(),a=String(t?.message||"").trim(),n=String(t?.chatId||"").trim()||`admin-${Date.now()}`;if(!e)throw new Error("Agent id is required.");if(!a)throw new Error("Message is required.");let o="http://127.0.0.1:18800",r;try{let m=A();o=m.dashboard.daemonUrl.replace(/\/+$/,"")||o,r=m.dashboard.token}catch{}let i={"Content-Type":"application/json"};r&&(i.Authorization=`Bearer ${r}`);let s=await fetch(`${o}/task`,{method:"POST",headers:i,body:JSON.stringify({agent:e,message:a,context:{channel:"test-drive",sender:"admin",chatId:n}})}),l=await s.text(),c;try{c=JSON.parse(l)}catch{c={content:l}}if(!s.ok)throw new Error(c?.error||`daemon HTTP ${s.status}`);return{chatId:n,response:c}}function wt(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=t?.tier==="sdk"?"sdk":"claude-code",o=qe(t?.triggerWords),r=t?.model?String(t.model).trim():void 0,i=t?.personality?String(t.personality).trim():void 0;if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Agent id must be lowercase (letters, digits, -, _).");if(!a)throw new Error("Agent name is required.");if(o.length===0)throw new Error("At least one trigger word is required.");let s=Z(process.cwd(),"agents",e),{summary:l}=x(m=>{if(m.agents=m.agents||{},m.agents[e])throw new Error(`Agent "${e}" already exists.`);let u={name:a,workspace:s,tier:n,mentions:o,maxConcurrent:2,permissionMode:"default"};return r&&(u.model=r),i&&(u.systemPrompt=i.slice(0,400)),m.agents[e]=u,`added agent "${e}"`}),c=Z(s,"CLAUDE.md");if(!de(c))try{ye("fs").mkdirSync(s,{recursive:!0}),Ne(c,`# ${a}
181
181
 
182
- ${s||"You are "+a+"."}
183
- `)}catch{}return{summary:c}}function Qe(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let a=t?.patch||{},{summary:n}=x(o=>{if(!o.agents?.[e])throw new Error(`Agent "${e}" not found.`);let r=o.agents[e];return typeof a.name=="string"&&a.name.trim()&&(r.name=a.name.trim()),typeof a.model=="string"&&(r.model=a.model.trim()||void 0),typeof a.tier=="string"&&["claude-code","sdk","orchestrator"].includes(a.tier)&&(r.tier=a.tier),typeof a.systemPrompt=="string"&&(r.systemPrompt=a.systemPrompt.trim()||void 0),Array.isArray(a.mentions)?r.mentions=a.mentions.map(s=>String(s).trim()).filter(Boolean):typeof a.triggerWords=="string"&&(r.mentions=$e(a.triggerWords)),typeof a.maxConcurrent=="number"&&a.maxConcurrent>=1&&(r.maxConcurrent=a.maxConcurrent),typeof a.maxExecutionMinutes=="number"&&a.maxExecutionMinutes>=1&&a.maxExecutionMinutes<=240&&(r.maxExecutionMinutes=a.maxExecutionMinutes),typeof a.permissionMode=="string"&&(r.permissionMode=a.permissionMode),(a.access==="public"||a.access==="private")&&(r.access=a.access),`updated agent "${e}"`});return{summary:n}}function Ze(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let{summary:a}=x(n=>{if(!n.agents||!n.agents[e])throw new Error(`Agent "${e}" not found.`);if(delete n.agents[e],n.channels?.telegram?.accounts)for(let o of Object.keys(n.channels.telegram.accounts))n.channels.telegram.accounts[o]?.agentBinding===e&&(n.channels.telegram.accounts[o].agentBinding="");return`removed agent "${e}"`});return{summary:a}}function et(t){let e=String(t?.id||"").trim(),a=String(t?.agentBinding||"").trim(),n=String(t?.botUsername||"").trim(),o=String(t?.botTokenEnv||"").trim();if(!e)throw new Error("Account id is required.");if(!a)throw new Error("Choose an agent to bind this account to.");if(!o)throw new Error("Bot token env-var name is required (e.g. TG_SUPPORT_BOT_TOKEN).");let{summary:r}=x(s=>{if(s.channels=s.channels||{},s.channels.telegram=s.channels.telegram||{enabled:!0,accounts:{},policy:{dm:"pair",group:"mention-required"}},s.channels.telegram.enabled=!0,s.channels.telegram.accounts=s.channels.telegram.accounts||{},s.channels.telegram.accounts[e])throw new Error(`Telegram account "${e}" already exists.`);if(!s.agents?.[a])throw new Error(`Unknown agent "${a}".`);return s.channels.telegram.accounts[e]={botToken:"${"+o+"}",botUsername:n,agentBinding:a},`added telegram account "${e}"`});return{summary:r,hint:`Add ${o}=<bot-token> to your .env file.`}}function tt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let a=t?.patch||{},{summary:n}=x(o=>{let r=o.channels?.telegram?.accounts?.[e];if(!r)throw new Error(`Account "${e}" not found.`);if(typeof a.agentBinding=="string"&&a.agentBinding.trim()){if(!o.agents?.[a.agentBinding])throw new Error(`Unknown agent "${a.agentBinding}".`);r.agentBinding=a.agentBinding.trim()}return typeof a.botUsername=="string"&&(r.botUsername=a.botUsername.trim()),typeof a.botTokenEnv=="string"&&a.botTokenEnv.trim()&&(r.botToken="${"+a.botTokenEnv.trim()+"}"),`updated telegram account "${e}"`});return{summary:n}}async function at(t){let{url:e,headers:a}=_e(),n=await fetch(e+t,{headers:a}),o=await n.text();if(!n.ok)throw new Error(`daemon ${n.status}: ${o.slice(0,200)}`);try{return JSON.parse(o)}catch{return{raw:o}}}async function nt(t,e){try{let{url:a,headers:n}=_e(),o=await fetch(a+e,{headers:n}),r=await o.text();t.writeHead(o.status,{"Content-Type":o.headers.get("content-type")||"image/svg+xml","Cache-Control":"no-store"}),t.end(r)}catch(a){t.writeHead(502,{"Content-Type":"text/plain; charset=utf-8"}),t.end("daemon unreachable: "+(a?.message||"unknown"))}}function _e(){let t="http://127.0.0.1:18800",e={};try{let a=U();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function R(t){let a=X()?.agents?.[t];if(!a)throw new Error(`Unknown agent "${t}".`);if(!a.workspace)throw new Error(`Agent "${t}" has no workspace configured.`);return a.workspace}function G(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function ot(t){let e=G(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=xe(R(e));return{agentId:e,...a}}function rt(t){let e=G(t,"agent").trim(),a=G(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return ye(R(e),a)}function it(t){let e=String(t?.agent||"").trim(),a=String(t?.path||"").trim(),n=typeof t?.content=="string"?t.content:"";if(!e||!a)throw new Error("agent and path are required.");let o=ke(R(e),a,n);return{summary:`saved ${a} (${o.bytes} bytes)`,...o}}function st(t){let e=String(t?.agent||"").trim(),a=String(t?.slug||"").trim(),n=t?.title?String(t.title):void 0,o=t?.content?String(t.content):void 0;if(!e)throw new Error("agent is required.");let r=we(R(e),a,{title:n,content:o});return{summary:`added skill "${a}"`,...r}}function lt(t){let e=String(t?.agent||"").trim(),a=String(t?.slug||"").trim();if(!e||!a)throw new Error("agent and slug are required.");let n=Ee(R(e),a);return{summary:`removed skill "${a}"`,...n}}var Me=["gitlab","github","sentry","stripe","discord","slack","custom"];function ct(t){let e=String(t?.id||"").trim(),a=String(t?.source||"").trim(),n=String(t?.agentId||"").trim(),o=String(t?.secretEnv||"").trim(),r=String(t?.description||"").trim();if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Webhook id must be lowercase (letters, digits, -, _).");if(!Me.includes(a))throw new Error(`Unknown source: ${a}`);if(!n)throw new Error("Pick an agent to bind the webhook to.");let{summary:s}=x(l=>{if(!l.agents?.[n])throw new Error(`Unknown agent "${n}".`);if(l.webhooks=Array.isArray(l.webhooks)?l.webhooks:[],l.webhooks.find(d=>d.id===e))throw new Error(`Webhook "${e}" already exists.`);let c={id:e,source:a,agentId:n,enabled:!0};return o&&(c.secretEnv=o),r&&(c.description=r),l.webhooks.push(c),`added webhook "${e}" (${a} \u2192 ${n})`});return{summary:s}}function dt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let a=t?.patch||{},{summary:n}=x(o=>{let r=(o.webhooks||[]).find(s=>s.id===e);if(!r)throw new Error(`Webhook "${e}" not found.`);if(typeof a.source=="string"&&Me.includes(a.source)&&(r.source=a.source),typeof a.agentId=="string"&&a.agentId.trim()){if(!o.agents?.[a.agentId])throw new Error(`Unknown agent "${a.agentId}".`);r.agentId=a.agentId.trim()}return typeof a.secretEnv=="string"&&(r.secretEnv=a.secretEnv.trim()||void 0),typeof a.description=="string"&&(r.description=a.description.trim()||void 0),typeof a.enabled=="boolean"&&(r.enabled=a.enabled),`updated webhook "${e}"`});return{summary:n}}function pt(t){let e=String(t?.url||"").trim().replace(/\/+$/,""),a=String(t?.name||"").trim(),n=String(t?.token||"").trim()||void 0;if(!e||!/^https?:\/\//.test(e))throw new Error("Peer URL must start with http:// or https://");if(!a)throw new Error("Peer name is required.");let{summary:o}=x(r=>{if(r.mesh=r.mesh||{enabled:!0,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},r.mesh.enabled=!0,r.mesh.peers=Array.isArray(r.mesh.peers)?r.mesh.peers:[],r.mesh.peers.find(l=>l.url===e))throw new Error(`Peer at ${e} already registered.`);let s={url:e,name:a};return n&&(s.token=n),r.mesh.peers.push(s),`added mesh peer "${a}"`});return{summary:o}}function ut(t){let e=String(t?.url||"").trim().replace(/\/+$/,"");if(!e)throw new Error("Peer URL is required.");let{summary:a}=x(n=>{let o=(n.mesh?.peers||[]).length;if(n.mesh=n.mesh||{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},n.mesh.peers=(n.mesh.peers||[]).filter(r=>r.url.replace(/\/+$/,"")!==e),n.mesh.peers.length===o)throw new Error(`Peer at ${e} not found.`);return`removed mesh peer ${e}`});return{summary:a}}function mt(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.mesh=n.mesh||{enabled:e,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},n.mesh.enabled=e,`mesh ${e?"enabled":"disabled"}`));return{summary:a}}function ht(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let{summary:a}=x(n=>{let o=(n.webhooks||[]).length;if(n.webhooks=(n.webhooks||[]).filter(r=>r.id!==e),n.webhooks.length===o)throw new Error(`Webhook "${e}" not found.`);return`removed webhook "${e}"`});return{summary:a}}function gt(t){let e=String(t?.botTokenEnv||"").trim(),a=String(t?.appTokenEnv||"").trim(),n=String(t?.agentBinding||"").trim();if(!e)throw new Error("Bot token env-var name is required (e.g. SLACK_BOT_TOKEN).");if(!a)throw new Error("App-level token env-var name is required (e.g. SLACK_APP_TOKEN).");let{summary:o}=x(r=>{if(r.channels=r.channels||{},r.channels.slack=r.channels.slack||{enabled:!1},r.channels.slack.enabled=!0,r.channels.slack.botToken="${"+e+"}",r.channels.slack.appToken="${"+a+"}",n){if(!r.agents?.[n])throw new Error(`Unknown agent "${n}".`);r.channels.slack.agentBinding=n}return"configured slack connector"});return{summary:o,hint:`Add ${e}=xoxb-\u2026 and ${a}=xapp-\u2026 to your .env.`}}function ft(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.slack=n.channels.slack||{enabled:!1},n.channels.slack.enabled=e,`slack ${e?"enabled":"disabled"}`));return{summary:a}}function bt(t){let e=String(t?.tokenEnv||"").trim(),a=String(t?.agentBinding||"").trim();if(!e)throw new Error("Bot token env-var name is required (e.g. DISCORD_BOT_TOKEN).");let{summary:n}=x(o=>{if(o.channels=o.channels||{},o.channels.discord=o.channels.discord||{enabled:!1},o.channels.discord.enabled=!0,o.channels.discord.token="${"+e+"}",a){if(!o.agents?.[a])throw new Error(`Unknown agent "${a}".`);o.channels.discord.agentBinding=a}return"configured discord connector"});return{summary:n,hint:`Add ${e}=<bot-token> to your .env.`}}function vt(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.discord=n.channels.discord||{enabled:!1},n.channels.discord.enabled=e,`discord ${e?"enabled":"disabled"}`));return{summary:a}}function xt(t){let e=String(t?.host||"").trim().replace(/\/+$/,""),a=String(t?.tokenEnv||"").trim(),n=parseInt(String(t?.webhookPort||"18810"),10);if(!e||!/^https?:\/\//.test(e))throw new Error("Host must start with http:// or https://");if(!a)throw new Error("Admin token env-var name is required (e.g. GITLAB_TOKEN).");if(!Number.isFinite(n)||n<1||n>65535)throw new Error("Webhook port must be between 1 and 65535.");let{summary:o}=x(r=>(r.channels=r.channels||{},r.channels.gitlab=r.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},r.channels.gitlab.enabled=!0,r.channels.gitlab.host=e,r.channels.gitlab.token="${"+a+"}",r.channels.gitlab.webhookPort=n,"configured gitlab connector"));return{summary:o,hint:`Add ${a}=<personal-access-token> to your .env. Per-project routes + per-agent tokens stay in the Advanced JSON editor.`}}function yt(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.gitlab=n.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},n.channels.gitlab.enabled=e,`gitlab ${e?"enabled":"disabled"}`));return{summary:a}}async function kt(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-FCXOXCN5.js"),n;try{n=(await import("cronstrue")).default.toString(e,{use24HourTimeFormat:!1})}catch(l){throw new Error(`Invalid cron: ${l.message||"unknown"}`)}let o=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC",r=[],s=new Date;try{for(let l=0;l<3;l++)s=a(e,s,o),r.push(s.toISOString())}catch(l){throw new Error(`Cron preview failed: ${l.message}`)}return{human:n,next:r,timezone:o}}function wt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let{summary:a}=x(n=>{if(!n.channels?.telegram?.accounts?.[e])throw new Error(`Account "${e}" not found.`);return delete n.channels.telegram.accounts[e],`removed telegram account "${e}"`});return{summary:a}}function Et(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.telegram=n.channels.telegram||{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},n.channels.telegram.enabled=e,`telegram ${e?"enabled":"disabled"}`));return{summary:a}}function St(t){let e=String(t?.id||"").trim(),a=String(t?.schedule||"").trim(),n=String(t?.agent||"").trim(),o=String(t?.prompt||"").trim();if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Cron id must be lowercase (letters, digits, -, _).");if(!a)throw new Error("Cron expression is required (e.g. '0 9 * * 1' for Mondays at 9am).");if(!n)throw new Error("Pick an agent to run this schedule.");if(!o)throw new Error("A prompt is required (what should the agent do?).");let{summary:r}=x(s=>{if(s.crons=s.crons||{},s.crons[e])throw new Error(`Cron "${e}" already exists.`);if(!s.agents?.[n])throw new Error(`Unknown agent "${n}".`);return s.crons[e]={schedule:a,agent:n,prompt:o,enabled:!0},`added cron "${e}"`});return{summary:r}}function Tt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Cron id is required.");let{summary:a}=x(n=>{if(!n.crons?.[e])throw new Error(`Cron "${e}" not found.`);return delete n.crons[e],`removed cron "${e}"`});return{summary:a}}function Ct(t){let e=String(t?.raw||"");if(!e.trim())throw new Error("Config body is empty.");let a;try{a=JSON.parse(e)}catch(r){throw new Error(`Invalid JSON: ${r.message}`)}let n=N(process.cwd(),"agentx.json"),o=`${n}.bak.${Date.now()}`;if(K(n))try{ee("fs").copyFileSync(n,o)}catch{}Se(n,JSON.stringify(a,null,2)+`
184
- `,"utf-8");try{let{loadDaemonConfig:r}=(ne(),Oe(He)),l=r().dashboard.daemonUrl?.replace(/\/+$/,"")||"http://127.0.0.1:18800";fetch(`${l}/reload`,{method:"POST"}).catch(()=>null)}catch{}return{summary:"agentx.json replaced",backupPath:o}}function $e(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}function At(t,e){let a=D({activeTab:"admin",subtitle:"Settings",peers:t}),n=e?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(e)};</script>`:"";return`<!DOCTYPE html>
182
+ ${i||"You are "+a+"."}
183
+ `)}catch{}return{summary:l}}function Et(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let a=t?.patch||{},{summary:n}=x(o=>{if(!o.agents?.[e])throw new Error(`Agent "${e}" not found.`);let r=o.agents[e];return typeof a.name=="string"&&a.name.trim()&&(r.name=a.name.trim()),typeof a.model=="string"&&(r.model=a.model.trim()||void 0),typeof a.tier=="string"&&["claude-code","sdk","orchestrator"].includes(a.tier)&&(r.tier=a.tier),typeof a.systemPrompt=="string"&&(r.systemPrompt=a.systemPrompt.trim()||void 0),Array.isArray(a.mentions)?r.mentions=a.mentions.map(i=>String(i).trim()).filter(Boolean):typeof a.triggerWords=="string"&&(r.mentions=qe(a.triggerWords)),typeof a.maxConcurrent=="number"&&a.maxConcurrent>=1&&(r.maxConcurrent=a.maxConcurrent),typeof a.maxExecutionMinutes=="number"&&a.maxExecutionMinutes>=1&&a.maxExecutionMinutes<=240&&(r.maxExecutionMinutes=a.maxExecutionMinutes),typeof a.permissionMode=="string"&&(r.permissionMode=a.permissionMode),(a.access==="public"||a.access==="private")&&(r.access=a.access),`updated agent "${e}"`});return{summary:n}}function St(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let{summary:a}=x(n=>{if(!n.agents||!n.agents[e])throw new Error(`Agent "${e}" not found.`);if(delete n.agents[e],n.channels?.telegram?.accounts)for(let o of Object.keys(n.channels.telegram.accounts))n.channels.telegram.accounts[o]?.agentBinding===e&&(n.channels.telegram.accounts[o].agentBinding="");return`removed agent "${e}"`});return{summary:a}}function Tt(t){let e=String(t?.id||"").trim(),a=String(t?.agentBinding||"").trim(),n=String(t?.botUsername||"").trim(),o=String(t?.botTokenEnv||"").trim();if(!e)throw new Error("Account id is required.");if(!a)throw new Error("Choose an agent to bind this account to.");if(!o)throw new Error("Bot token env-var name is required (e.g. TG_SUPPORT_BOT_TOKEN).");let{summary:r}=x(i=>{if(i.channels=i.channels||{},i.channels.telegram=i.channels.telegram||{enabled:!0,accounts:{},policy:{dm:"pair",group:"mention-required"}},i.channels.telegram.enabled=!0,i.channels.telegram.accounts=i.channels.telegram.accounts||{},i.channels.telegram.accounts[e])throw new Error(`Telegram account "${e}" already exists.`);if(!i.agents?.[a])throw new Error(`Unknown agent "${a}".`);return i.channels.telegram.accounts[e]={botToken:"${"+o+"}",botUsername:n,agentBinding:a},`added telegram account "${e}"`});return{summary:r,hint:`Add ${o}=<bot-token> to your .env file.`}}function At(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let a=t?.patch||{},{summary:n}=x(o=>{let r=o.channels?.telegram?.accounts?.[e];if(!r)throw new Error(`Account "${e}" not found.`);if(typeof a.agentBinding=="string"&&a.agentBinding.trim()){if(!o.agents?.[a.agentBinding])throw new Error(`Unknown agent "${a.agentBinding}".`);r.agentBinding=a.agentBinding.trim()}return typeof a.botUsername=="string"&&(r.botUsername=a.botUsername.trim()),typeof a.botTokenEnv=="string"&&a.botTokenEnv.trim()&&(r.botToken="${"+a.botTokenEnv.trim()+"}"),`updated telegram account "${e}"`});return{summary:n}}async function Ct(t){let{url:e,headers:a}=Ue(),n=await fetch(e+t,{headers:a}),o=await n.text();if(!n.ok)throw new Error(`daemon ${n.status}: ${o.slice(0,200)}`);try{return JSON.parse(o)}catch{return{raw:o}}}async function $t(t,e){try{let{url:a,headers:n}=Ue(),o=await fetch(a+e,{headers:n}),r=await o.text();t.writeHead(o.status,{"Content-Type":o.headers.get("content-type")||"image/svg+xml","Cache-Control":"no-store"}),t.end(r)}catch(a){t.writeHead(502,{"Content-Type":"text/plain; charset=utf-8"}),t.end("daemon unreachable: "+(a?.message||"unknown"))}}function Ue(){let t="http://127.0.0.1:18800",e={};try{let a=A();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function F(t){let a=pe()?.agents?.[t];if(!a)throw new Error(`Unknown agent "${t}".`);if(!a.workspace)throw new Error(`Agent "${t}" has no workspace configured.`);return a.workspace}function ce(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function Mt(t){let e=ce(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=z(F(e));return{agentId:e,...a}}function _t(t){let e=ce(t,"agent").trim(),a=ce(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return X(F(e),a)}function It(t){let e=String(t?.agent||"").trim(),a=String(t?.path||"").trim(),n=typeof t?.content=="string"?t.content:"";if(!e||!a)throw new Error("agent and path are required.");let o=V(F(e),a,n);return{summary:`saved ${a} (${o.bytes} bytes)`,...o}}function Lt(t){let e=String(t?.agent||"").trim(),a=String(t?.slug||"").trim(),n=t?.title?String(t.title):void 0,o=t?.content?String(t.content):void 0;if(!e)throw new Error("agent is required.");let r=J(F(e),a,{title:n,content:o});return{summary:`added skill "${a}"`,...r}}function Dt(t){let e=String(t?.agent||"").trim(),a=String(t?.slug||"").trim();if(!e||!a)throw new Error("agent and slug are required.");let n=Y(F(e),a);return{summary:`removed skill "${a}"`,...n}}var Fe=["gitlab","github","sentry","stripe","discord","slack","custom"];function Pt(t){let e=String(t?.id||"").trim(),a=String(t?.source||"").trim(),n=String(t?.agentId||"").trim(),o=String(t?.secretEnv||"").trim(),r=String(t?.description||"").trim();if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Webhook id must be lowercase (letters, digits, -, _).");if(!Fe.includes(a))throw new Error(`Unknown source: ${a}`);if(!n)throw new Error("Pick an agent to bind the webhook to.");let{summary:i}=x(s=>{if(!s.agents?.[n])throw new Error(`Unknown agent "${n}".`);if(s.webhooks=Array.isArray(s.webhooks)?s.webhooks:[],s.webhooks.find(c=>c.id===e))throw new Error(`Webhook "${e}" already exists.`);let l={id:e,source:a,agentId:n,enabled:!0};return o&&(l.secretEnv=o),r&&(l.description=r),s.webhooks.push(l),`added webhook "${e}" (${a} \u2192 ${n})`});return{summary:i}}function Ot(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let a=t?.patch||{},{summary:n}=x(o=>{let r=(o.webhooks||[]).find(i=>i.id===e);if(!r)throw new Error(`Webhook "${e}" not found.`);if(typeof a.source=="string"&&Fe.includes(a.source)&&(r.source=a.source),typeof a.agentId=="string"&&a.agentId.trim()){if(!o.agents?.[a.agentId])throw new Error(`Unknown agent "${a.agentId}".`);r.agentId=a.agentId.trim()}return typeof a.secretEnv=="string"&&(r.secretEnv=a.secretEnv.trim()||void 0),typeof a.description=="string"&&(r.description=a.description.trim()||void 0),typeof a.enabled=="boolean"&&(r.enabled=a.enabled),`updated webhook "${e}"`});return{summary:n}}function Ht(t){let e=String(t?.url||"").trim().replace(/\/+$/,""),a=String(t?.name||"").trim(),n=String(t?.token||"").trim()||void 0;if(!e||!/^https?:\/\//.test(e))throw new Error("Peer URL must start with http:// or https://");if(!a)throw new Error("Peer name is required.");let{summary:o}=x(r=>{if(r.mesh=r.mesh||{enabled:!0,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},r.mesh.enabled=!0,r.mesh.peers=Array.isArray(r.mesh.peers)?r.mesh.peers:[],r.mesh.peers.find(s=>s.url===e))throw new Error(`Peer at ${e} already registered.`);let i={url:e,name:a};return n&&(i.token=n),r.mesh.peers.push(i),`added mesh peer "${a}"`});return{summary:o}}function Rt(t){let e=String(t?.url||"").trim().replace(/\/+$/,"");if(!e)throw new Error("Peer URL is required.");let{summary:a}=x(n=>{let o=(n.mesh?.peers||[]).length;if(n.mesh=n.mesh||{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},n.mesh.peers=(n.mesh.peers||[]).filter(r=>r.url.replace(/\/+$/,"")!==e),n.mesh.peers.length===o)throw new Error(`Peer at ${e} not found.`);return`removed mesh peer ${e}`});return{summary:a}}function Nt(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.mesh=n.mesh||{enabled:e,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},n.mesh.enabled=e,`mesh ${e?"enabled":"disabled"}`));return{summary:a}}function Bt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let{summary:a}=x(n=>{let o=(n.webhooks||[]).length;if(n.webhooks=(n.webhooks||[]).filter(r=>r.id!==e),n.webhooks.length===o)throw new Error(`Webhook "${e}" not found.`);return`removed webhook "${e}"`});return{summary:a}}function zt(t){let e=String(t?.botTokenEnv||"").trim(),a=String(t?.appTokenEnv||"").trim(),n=String(t?.agentBinding||"").trim();if(!e)throw new Error("Bot token env-var name is required (e.g. SLACK_BOT_TOKEN).");if(!a)throw new Error("App-level token env-var name is required (e.g. SLACK_APP_TOKEN).");let{summary:o}=x(r=>{if(r.channels=r.channels||{},r.channels.slack=r.channels.slack||{enabled:!1},r.channels.slack.enabled=!0,r.channels.slack.botToken="${"+e+"}",r.channels.slack.appToken="${"+a+"}",n){if(!r.agents?.[n])throw new Error(`Unknown agent "${n}".`);r.channels.slack.agentBinding=n}return"configured slack connector"});return{summary:o,hint:`Add ${e}=xoxb-\u2026 and ${a}=xapp-\u2026 to your .env.`}}function jt(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.slack=n.channels.slack||{enabled:!1},n.channels.slack.enabled=e,`slack ${e?"enabled":"disabled"}`));return{summary:a}}function Ut(t){let e=String(t?.tokenEnv||"").trim(),a=String(t?.agentBinding||"").trim();if(!e)throw new Error("Bot token env-var name is required (e.g. DISCORD_BOT_TOKEN).");let{summary:n}=x(o=>{if(o.channels=o.channels||{},o.channels.discord=o.channels.discord||{enabled:!1},o.channels.discord.enabled=!0,o.channels.discord.token="${"+e+"}",a){if(!o.agents?.[a])throw new Error(`Unknown agent "${a}".`);o.channels.discord.agentBinding=a}return"configured discord connector"});return{summary:n,hint:`Add ${e}=<bot-token> to your .env.`}}function Ft(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.discord=n.channels.discord||{enabled:!1},n.channels.discord.enabled=e,`discord ${e?"enabled":"disabled"}`));return{summary:a}}function qt(t){let e=String(t?.host||"").trim().replace(/\/+$/,""),a=String(t?.tokenEnv||"").trim(),n=parseInt(String(t?.webhookPort||"18810"),10);if(!e||!/^https?:\/\//.test(e))throw new Error("Host must start with http:// or https://");if(!a)throw new Error("Admin token env-var name is required (e.g. GITLAB_TOKEN).");if(!Number.isFinite(n)||n<1||n>65535)throw new Error("Webhook port must be between 1 and 65535.");let{summary:o}=x(r=>(r.channels=r.channels||{},r.channels.gitlab=r.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},r.channels.gitlab.enabled=!0,r.channels.gitlab.host=e,r.channels.gitlab.token="${"+a+"}",r.channels.gitlab.webhookPort=n,"configured gitlab connector"));return{summary:o,hint:`Add ${a}=<personal-access-token> to your .env. Per-project routes + per-agent tokens stay in the Advanced JSON editor.`}}function Gt(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.gitlab=n.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},n.channels.gitlab.enabled=e,`gitlab ${e?"enabled":"disabled"}`));return{summary:a}}async function Wt(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-A3TQOCKT.js"),n;try{n=(await import("cronstrue")).default.toString(e,{use24HourTimeFormat:!1})}catch(s){throw new Error(`Invalid cron: ${s.message||"unknown"}`)}let o=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC",r=[],i=new Date;try{for(let s=0;s<3;s++)i=a(e,i,o),r.push(i.toISOString())}catch(s){throw new Error(`Cron preview failed: ${s.message}`)}return{human:n,next:r,timezone:o}}function Kt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let{summary:a}=x(n=>{if(!n.channels?.telegram?.accounts?.[e])throw new Error(`Account "${e}" not found.`);return delete n.channels.telegram.accounts[e],`removed telegram account "${e}"`});return{summary:a}}function Xt(t){let e=!!t?.enabled,{summary:a}=x(n=>(n.channels=n.channels||{},n.channels.telegram=n.channels.telegram||{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},n.channels.telegram.enabled=e,`telegram ${e?"enabled":"disabled"}`));return{summary:a}}function Vt(t){let e=String(t?.id||"").trim(),a=String(t?.schedule||"").trim(),n=String(t?.agent||"").trim(),o=String(t?.prompt||"").trim();if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Cron id must be lowercase (letters, digits, -, _).");if(!a)throw new Error("Cron expression is required (e.g. '0 9 * * 1' for Mondays at 9am).");if(!n)throw new Error("Pick an agent to run this schedule.");if(!o)throw new Error("A prompt is required (what should the agent do?).");let{summary:r}=x(i=>{if(i.crons=i.crons||{},i.crons[e])throw new Error(`Cron "${e}" already exists.`);if(!i.agents?.[n])throw new Error(`Unknown agent "${n}".`);return i.crons[e]={schedule:a,agent:n,prompt:o,enabled:!0},`added cron "${e}"`});return{summary:r}}function Jt(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Cron id is required.");let{summary:a}=x(n=>{if(!n.crons?.[e])throw new Error(`Cron "${e}" not found.`);return delete n.crons[e],`removed cron "${e}"`});return{summary:a}}function Yt(t){let e=String(t?.raw||"");if(!e.trim())throw new Error("Config body is empty.");let a;try{a=JSON.parse(e)}catch(r){throw new Error(`Invalid JSON: ${r.message}`)}let n=Z(process.cwd(),"agentx.json"),o=`${n}.bak.${Date.now()}`;if(de(n))try{ye("fs").copyFileSync(n,o)}catch{}Ne(n,JSON.stringify(a,null,2)+`
184
+ `,"utf-8");try{let{loadDaemonConfig:r}=(G(),it(lt)),s=r().dashboard.daemonUrl?.replace(/\/+$/,"")||"http://127.0.0.1:18800";fetch(`${s}/reload`,{method:"POST"}).catch(()=>null)}catch{}return{summary:"agentx.json replaced",backupPath:o}}function qe(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}function Qt(t,e){let a=I({activeTab:"admin",subtitle:"Settings",peers:t}),n=e?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(e)};</script>`:"";return`<!DOCTYPE html>
185
185
  <html lang="en" data-theme="dark">
186
186
  <head>
187
187
  <meta charset="utf-8">
@@ -215,7 +215,7 @@ ${$}
215
215
  --ax-surface-2:#0b2922;--ax-border:#164a30;--ax-border-2:#1f6a44;
216
216
  --ax-text:#b7ffcc;--ax-text-2:#83e3a8;--ax-muted:#4f9a73;--ax-accent:#6dff9e;
217
217
  --ax-font:"IBM Plex Mono",ui-monospace,monospace}
218
- ${I}
218
+ ${M}
219
219
  *{box-sizing:border-box}
220
220
  html,body{margin:0;min-height:100vh;background:var(--ax-bg);color:var(--ax-text);
221
221
  font-family:var(--ax-font);font-size:13px;line-height:1.5;
@@ -911,6 +911,7 @@ function renderAgents() {
911
911
  '</div>' +
912
912
  '<button class="primary" data-test="' + escapeHtml(a.id) + '" data-name="' + escapeHtml(a.name) + '" style="margin-right:6px;padding:6px 12px;font-size:12px">Test drive</button>' +
913
913
  '<button class="ghost" data-edit="' + escapeHtml(a.id) + '" style="margin-right:6px">Edit</button>' +
914
+ '<a class="btn ghost" href="/admin/agents/' + encodeURIComponent(a.id) + '" style="margin-right:6px;display:inline-block;text-decoration:none">Manage</a>' +
914
915
  '<button class="ghost" data-files="' + escapeHtml(a.id) + '" data-name="' + escapeHtml(a.name) + '" style="margin-right:6px">Files</button>' +
915
916
  '<button class="ghost" data-toggle="' + escapeHtml(a.id) + '" data-access="' + escapeHtml(a.access) + '" style="margin-right:6px">' + (a.access === 'public' ? 'Make private' : 'Make public') + '</button>' +
916
917
  '<button class="danger" data-id="' + escapeHtml(a.id) + '">Delete</button>';
@@ -1956,17 +1957,1118 @@ for (const btn of document.querySelectorAll('nav.tabs button')) {
1956
1957
 
1957
1958
  refresh();
1958
1959
  </script>
1959
- ${L}
1960
+ ${_}
1960
1961
  </body>
1961
- </html>`}function Ca(t){let e=t.dashboard,a=t.boards,n=e.port,o=e.bind,r=e.token,s=new Map;for(let c of a)try{s.set(c.id,Ot(c,t))}catch(d){console.error(` Board "${c.id}" failed to initialize: ${d.message}`)}_t(async(c,d)=>{try{await Lt(c,d,{boards:a,sources:s,token:r,config:t})}catch(g){m(d,500,{error:g.message||"internal error"})}}).listen(n,o,()=>{let c=o==="0.0.0.0"?"localhost":o;a.length===0?(console.log(`
1962
- Live dashboard: http://${c}:${n}
1962
+ </html>`}G();import{resolve as Zt}from"path";function We(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ca(a,n))}async function Ke(t,e,a){try{let n=t.method==="GET"?void 0:await la(t),o=ea(),r={"GET /api/admin/graph/state":()=>ta(o),"POST /api/admin/graph/classifications/approve":()=>aa(o,n),"POST /api/admin/graph/classifications/reject":()=>na(o,n),"POST /api/admin/graph/nodes":()=>oa(o,n),"PATCH /api/admin/graph/nodes":()=>ra(o,n),"DELETE /api/admin/graph/nodes":()=>ia(o,n),"PUT /api/admin/graph/schema":()=>sa(o,n)},i=`${t.method} ${a}`,s=r[i];if(!s){ue(e,404,{error:`unknown graph endpoint: ${i}`});return}let l=await s();ue(e,200,l)}catch(n){ue(e,400,{error:n?.message||"graph op failed"})}}function ea(){let t=A(),e=Zt(process.cwd(),t.graph.baseDir);return new ke({baseDir:e})}function ta(t){let e=A(),a=t.loadSchema(),n=t.loadNodes().nodes,o=t.readRecentClassifications(100),r=t.loadIndex().entries,i=new Map;for(let l of o)i.has(l.msgHash)||i.set(l.msgHash,l);let s=[];for(let l of i.values())l.status==="pending"&&!r[l.msgHash]&&s.push(l);return{enabled:e.graph.enabled,schema:a,nodes:n,pending:s,recent:o.slice(0,25),counts:{nodes:n.length,pending:s.length,fingerprints:Object.keys(r).length}}}function aa(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=Xe(t,a);return Array.isArray(e?.path)&&e.path.length>0&&(n.path=e.path.map(o=>String(o))),e?.proposedAxes&&typeof e.proposedAxes=="object"&&(n.proposedAxes=me(e.proposedAxes)),t.approveClassification(n),{summary:`Approved ${n.msgHash}`}}function na(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=Xe(t,a);return t.rejectClassification(n),{summary:`Rejected ${n.msgHash}`}}function Xe(t,e){let n=t.readRecentClassifications(500).find(o=>o.msgHash===e);if(!n)throw new Error(`No classification found for ${e}`);return n}function oa(t,e){let a=Ge(String(e?.id||"")),n=String(e?.level||"").trim(),o=e?.parentId?Ge(String(e.parentId)):null,r=me({[a]:e?.axes||{}})[a]||{};if(!a)throw new Error("id is required");if(!n)throw new Error("level is required");let i={id:a,level:n,parentId:o,axes:r,createdAt:new Date().toISOString(),createdBy:"admin-ui"};return t.addNode(i),{node:i}}function ra(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");let n=me({[a]:e?.axes||{}})[a]||{};return{node:t.updateNodeAxes(a,n)}}function ia(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");return t.deleteNode(a),{summary:`Deleted ${a}`}}function sa(t,e){if(!e?.schema||typeof e.schema!="object")throw new Error("schema object is required");return t.saveSchema(e.schema),{summary:"Schema saved"}}function me(t){let e={};for(let[a,n]of Object.entries(t||{})){if(!n||typeof n!="object")continue;let o={};for(let[r,i]of Object.entries(n))typeof i=="string"&&(o[r]=i);e[a]=o}return e}function Ge(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")}function ue(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function la(t){return new Promise((e,a)=>{let n="";t.on("data",o=>{n+=o}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(o){a(o)}}),t.on("error",a)})}function ca(t,e){let a=I({activeTab:"graph",subtitle:"Intent Graph",peers:t}),n=e?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(e)};</script>`:"";return`<!doctype html>
1963
+ <html lang="en" data-theme="dark">
1964
+ <head>
1965
+ <meta charset="utf-8">
1966
+ <title>AgentX \xB7 Intent Graph</title>
1967
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1968
+ ${$}
1969
+ <style>
1970
+ :root{
1971
+ --ax-bg:#0a0b0f; --ax-bg-elev:#101218; --ax-surface:#151823;
1972
+ --ax-text:#e5e7eb; --ax-text-2:#b1b4c0; --ax-muted:#7a7d8a;
1973
+ --ax-border:#1d212d; --ax-border-2:#262a38; --ax-accent:#7aa2f7;
1974
+ --ax-green:#4ade80; --ax-red:#f87171; --ax-yellow:#fbbf24;
1975
+ --ax-mono:'IBM Plex Mono',ui-monospace,monospace;
1976
+ }
1977
+ :root[data-theme="light"]{
1978
+ --ax-bg:#f8fafc;--ax-bg-elev:#ffffff;--ax-surface:#ffffff;
1979
+ --ax-text:#111827;--ax-text-2:#374151;--ax-muted:#6b7280;
1980
+ --ax-border:#e5e7eb;--ax-border-2:#d1d5db;--ax-accent:#2563eb;
1981
+ }
1982
+ *{box-sizing:border-box}
1983
+ body{margin:0;background:var(--ax-bg);color:var(--ax-text);
1984
+ font-family:'IBM Plex Sans',system-ui,-apple-system,sans-serif;font-size:13px;line-height:1.5}
1985
+ ${M}
1986
+ main{max-width:1200px;margin:0 auto;padding:24px 20px 60px}
1987
+ h2{margin:0 0 12px;font-size:16px;font-weight:600;letter-spacing:-0.01em}
1988
+ .grid{display:grid;gap:20px;grid-template-columns:1fr}
1989
+ @media (min-width:920px){.grid-2{grid-template-columns:3fr 2fr}}
1990
+ .card{background:var(--ax-bg-elev);border:1px solid var(--ax-border);
1991
+ border-radius:8px;padding:16px}
1992
+ .card h2{margin-top:0}
1993
+ .muted{color:var(--ax-muted);font-size:12px}
1994
+ .mono{font-family:var(--ax-mono)}
1995
+ .chip{display:inline-block;padding:1px 8px;border-radius:3px;
1996
+ font-size:11px;background:var(--ax-surface);color:var(--ax-text-2);
1997
+ border:1px solid var(--ax-border);margin-right:4px}
1998
+ .chip.pending{background:rgba(251,191,36,0.15);color:var(--ax-yellow);border-color:transparent}
1999
+ .chip.approved{background:rgba(74,222,128,0.15);color:var(--ax-green);border-color:transparent}
2000
+ .chip.rejected{background:rgba(248,113,113,0.15);color:var(--ax-red);border-color:transparent}
2001
+ button,.btn{font:inherit;font-size:12px;padding:6px 12px;border-radius:4px;
2002
+ border:1px solid var(--ax-border-2);background:var(--ax-surface);
2003
+ color:var(--ax-text);cursor:pointer}
2004
+ button:hover{border-color:var(--ax-accent);color:var(--ax-accent)}
2005
+ button.primary{background:var(--ax-accent);color:#0a0b0f;border-color:var(--ax-accent);font-weight:600}
2006
+ button.primary:hover{filter:brightness(1.08);color:#0a0b0f}
2007
+ button.danger{color:var(--ax-red);border-color:var(--ax-red)}
2008
+ button.danger:hover{background:var(--ax-red);color:#fff}
2009
+ input,textarea,select{font:inherit;font-size:12px;padding:6px 10px;
2010
+ background:var(--ax-surface);color:var(--ax-text);
2011
+ border:1px solid var(--ax-border);border-radius:4px;width:100%;
2012
+ font-family:var(--ax-mono)}
2013
+ textarea{min-height:220px;white-space:pre;line-height:1.45}
2014
+ .row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
2015
+ .row > *{flex:0 0 auto}
2016
+ .row > input,.row > select{flex:1 1 160px;min-width:0}
2017
+ .pending-item{border-bottom:1px solid var(--ax-border);padding:12px 0}
2018
+ .pending-item:last-child{border-bottom:none}
2019
+ .pending-preview{color:var(--ax-text-2);font-size:12px;margin:6px 0 8px;
2020
+ padding:8px 10px;background:var(--ax-surface);border-radius:4px;
2021
+ border-left:2px solid var(--ax-accent);white-space:pre-wrap}
2022
+ .path-crumbs{font-family:var(--ax-mono);font-size:12px;color:var(--ax-accent);
2023
+ margin:4px 0}
2024
+ .level-group{margin-bottom:16px}
2025
+ .level-group h3{font-size:12px;margin:0 0 6px;font-weight:600;
2026
+ text-transform:uppercase;letter-spacing:0.06em;color:var(--ax-muted)}
2027
+ .node-row{display:flex;align-items:center;gap:10px;padding:6px 0;
2028
+ border-bottom:1px dotted var(--ax-border)}
2029
+ .node-row:last-child{border:none}
2030
+ .node-id{font-family:var(--ax-mono);font-weight:600;min-width:180px}
2031
+ .axes{display:flex;gap:6px;flex-wrap:wrap;flex:1}
2032
+ .axis{font-size:11px;color:var(--ax-text-2)}
2033
+ .axis b{color:var(--ax-text);font-weight:500}
2034
+ .empty{color:var(--ax-muted);font-style:italic;padding:16px;text-align:center}
2035
+ .banner{padding:10px 14px;border-radius:6px;margin-bottom:16px;font-size:12px}
2036
+ .banner.warn{background:rgba(251,191,36,0.08);color:var(--ax-yellow);
2037
+ border:1px solid rgba(251,191,36,0.3)}
2038
+ .msg{font-size:11px;padding:6px 10px;border-radius:4px;margin-top:8px;display:none}
2039
+ .msg.ok{background:rgba(74,222,128,0.1);color:var(--ax-green);display:block}
2040
+ .msg.err{background:rgba(248,113,113,0.1);color:var(--ax-red);display:block}
2041
+ .counts{display:flex;gap:16px;margin-bottom:16px;flex-wrap:wrap}
2042
+ .count{background:var(--ax-bg-elev);border:1px solid var(--ax-border);
2043
+ border-radius:6px;padding:10px 14px;min-width:110px}
2044
+ .count .n{font-size:20px;font-weight:600;line-height:1}
2045
+ .count .l{font-size:11px;color:var(--ax-muted);margin-top:4px}
2046
+ details{background:var(--ax-surface);border:1px solid var(--ax-border);
2047
+ border-radius:4px;padding:8px 12px;margin-top:8px}
2048
+ details summary{cursor:pointer;font-size:11px;color:var(--ax-muted);
2049
+ user-select:none}
2050
+ details[open] summary{margin-bottom:8px}
2051
+ </style>
2052
+ </head>
2053
+ <body>
2054
+ ${a}
2055
+ <main>
2056
+ <div id="msg" class="msg"></div>
2057
+
2058
+ <div id="disabled-banner" class="banner warn" style="display:none">
2059
+ <b>Graph is disabled.</b> Set <code class="mono">graph.enabled: true</code>
2060
+ in <code class="mono">agentx.json</code> to start classifying traffic.
2061
+ The admin UI works either way \u2014 nothing classifies until the daemon reloads with graph enabled.
2062
+ </div>
2063
+
2064
+ <div class="counts">
2065
+ <div class="count"><div class="n" id="c-nodes">\u2014</div><div class="l">Nodes</div></div>
2066
+ <div class="count"><div class="n" id="c-pending">\u2014</div><div class="l">Pending</div></div>
2067
+ <div class="count"><div class="n" id="c-fp">\u2014</div><div class="l">Cached fingerprints</div></div>
2068
+ </div>
2069
+
2070
+ <div class="grid grid-2">
2071
+ <section class="card">
2072
+ <h2>Pending approval</h2>
2073
+ <p class="muted">The LLM proposed a path for these messages. Approve to add the fingerprint to the snap-to-path cache so similar messages don't hit the LLM again.</p>
2074
+ <div id="pending-list"></div>
2075
+ </section>
2076
+
2077
+ <section class="card">
2078
+ <h2>Taxonomy</h2>
2079
+ <p class="muted">Current nodes, grouped by level. Edit axes inline; add nodes with the form below.</p>
2080
+ <div id="tree"></div>
2081
+
2082
+ <details>
2083
+ <summary>Add node</summary>
2084
+ <div class="row" style="margin-top:10px">
2085
+ <select id="n-level"></select>
2086
+ <input id="n-id" placeholder="node id (e.g. noqta-devops)" />
2087
+ <select id="n-parent"><option value="">\u2014 no parent \u2014</option></select>
2088
+ </div>
2089
+ <div class="row" style="margin-top:6px">
2090
+ <input id="n-axes" placeholder='axes JSON, e.g. {"name":"DevOps","orgKind":"team"}' />
2091
+ <button class="primary" id="btn-add-node">Add</button>
2092
+ </div>
2093
+ </details>
2094
+ </section>
2095
+ </div>
2096
+
2097
+ <section class="card" style="margin-top:20px">
2098
+ <h2>Schema (advanced)</h2>
2099
+ <p class="muted">Levels and their required axes. Edit carefully \u2014 changing enum values or removing axes can orphan existing nodes.</p>
2100
+ <textarea id="schema-editor" spellcheck="false"></textarea>
2101
+ <div class="row" style="margin-top:10px;justify-content:flex-end">
2102
+ <button id="btn-reload-schema">Reload</button>
2103
+ <button class="primary" id="btn-save-schema">Save schema</button>
2104
+ </div>
2105
+ </section>
2106
+
2107
+ <section class="card" style="margin-top:20px">
2108
+ <h2>Recent classifications</h2>
2109
+ <p class="muted">Last 25 log rows, newest first \u2014 approved / pending / rejected.</p>
2110
+ <div id="recent"></div>
2111
+ </section>
2112
+ </main>
2113
+
2114
+ <script>
2115
+ const $ = (id) => document.getElementById(id);
2116
+ const state = { schema: null, nodes: [], pending: [], recent: [] };
2117
+
2118
+ function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));}
2119
+
2120
+ async function req(method, path, body) {
2121
+ const headers = { 'Content-Type': 'application/json' };
2122
+ if (window.AX_LOCAL_TOKEN) headers['Authorization'] = 'Bearer ' + window.AX_LOCAL_TOKEN;
2123
+ const r = await fetch(path, {
2124
+ method,
2125
+ headers,
2126
+ body: body ? JSON.stringify(body) : undefined,
2127
+ });
2128
+ const data = await r.json().catch(() => ({}));
2129
+ if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));
2130
+ return data;
2131
+ }
2132
+
2133
+ function showMsg(kind, text) {
2134
+ const m = $('msg');
2135
+ m.className = 'msg ' + kind;
2136
+ m.textContent = text;
2137
+ setTimeout(() => { m.className = 'msg'; }, 4000);
2138
+ }
2139
+
2140
+ function pathLabel(path) {
2141
+ return path.map(id => {
2142
+ const n = state.nodes.find(x => x.id === id);
2143
+ return n ? (n.axes?.name || n.axes?.what || id) : id;
2144
+ }).join(' \u203A ');
2145
+ }
2146
+
2147
+ function renderCounts(counts, enabled) {
2148
+ $('c-nodes').textContent = counts.nodes;
2149
+ $('c-pending').textContent = counts.pending;
2150
+ $('c-fp').textContent = counts.fingerprints;
2151
+ $('disabled-banner').style.display = enabled ? 'none' : 'block';
2152
+ }
2153
+
2154
+ function renderTree() {
2155
+ const host = $('tree');
2156
+ if (!state.schema || state.nodes.length === 0) {
2157
+ host.innerHTML = '<div class="empty">No nodes yet. The classifier populates these as new intents arrive.</div>';
2158
+ return;
2159
+ }
2160
+ let html = '';
2161
+ for (const level of state.schema.levels) {
2162
+ const nodes = state.nodes.filter(n => n.level === level.id);
2163
+ html += '<div class="level-group"><h3>' + esc(level.id) + '</h3>';
2164
+ if (!nodes.length) {
2165
+ html += '<div class="muted" style="padding-left:4px">\u2014</div>';
2166
+ } else {
2167
+ for (const n of nodes) {
2168
+ const axes = Object.entries(n.axes || {}).map(([k, v]) =>
2169
+ '<span class="axis"><b>' + esc(k) + ':</b> ' + esc(v) + '</span>'
2170
+ ).join(' ');
2171
+ html += '<div class="node-row">'
2172
+ + '<span class="node-id">' + esc(n.id) + '</span>'
2173
+ + '<div class="axes">' + axes + '</div>'
2174
+ + '<button data-edit="' + esc(n.id) + '">Edit</button>'
2175
+ + '<button class="danger" data-del="' + esc(n.id) + '">Delete</button>'
2176
+ + '</div>';
2177
+ }
2178
+ }
2179
+ html += '</div>';
2180
+ }
2181
+ host.innerHTML = html;
2182
+ host.querySelectorAll('[data-edit]').forEach(b =>
2183
+ b.addEventListener('click', () => editNode(b.getAttribute('data-edit')))
2184
+ );
2185
+ host.querySelectorAll('[data-del]').forEach(b =>
2186
+ b.addEventListener('click', () => deleteNode(b.getAttribute('data-del')))
2187
+ );
2188
+ }
2189
+
2190
+ function renderPending() {
2191
+ const host = $('pending-list');
2192
+ if (!state.pending.length) {
2193
+ host.innerHTML = '<div class="empty">Nothing pending. New traffic will appear here when the classifier proposes a novel path.</div>';
2194
+ return;
2195
+ }
2196
+ host.innerHTML = state.pending.map(c => {
2197
+ const conf = c.confidence != null ? ' \xB7 confidence ' + (c.confidence * 100).toFixed(0) + '%' : '';
2198
+ const preview = c.preview || '(no preview)';
2199
+ const path = pathLabel(c.path);
2200
+ return '<div class="pending-item" data-hash="' + esc(c.msgHash) + '">'
2201
+ + '<div class="muted" style="font-size:11px">' + esc(c.channel || '?') + ' \xB7 ' + esc(c.sender || '?') + conf + ' \xB7 ' + esc(c.ts) + '</div>'
2202
+ + '<div class="path-crumbs">' + esc(path) + '</div>'
2203
+ + '<div class="pending-preview">' + esc(preview) + '</div>'
2204
+ + '<div class="row">'
2205
+ + '<button class="primary" data-approve="' + esc(c.msgHash) + '">Approve</button>'
2206
+ + '<button class="danger" data-reject="' + esc(c.msgHash) + '">Reject</button>'
2207
+ + '</div>'
2208
+ + '</div>';
2209
+ }).join('');
2210
+ host.querySelectorAll('[data-approve]').forEach(b =>
2211
+ b.addEventListener('click', () => approve(b.getAttribute('data-approve')))
2212
+ );
2213
+ host.querySelectorAll('[data-reject]').forEach(b =>
2214
+ b.addEventListener('click', () => reject(b.getAttribute('data-reject')))
2215
+ );
2216
+ }
2217
+
2218
+ function renderRecent() {
2219
+ const host = $('recent');
2220
+ if (!state.recent.length) {
2221
+ host.innerHTML = '<div class="empty">No classifications yet.</div>';
2222
+ return;
2223
+ }
2224
+ host.innerHTML = state.recent.map(c =>
2225
+ '<div class="node-row">'
2226
+ + '<span class="chip ' + esc(c.status) + '">' + esc(c.status) + '</span>'
2227
+ + '<span class="mono muted" style="font-size:11px">' + esc(c.ts) + '</span>'
2228
+ + '<span style="flex:1">' + esc(pathLabel(c.path)) + '</span>'
2229
+ + '<span class="muted" style="font-size:11px">' + esc(c.source) + '</span>'
2230
+ + '</div>'
2231
+ ).join('');
2232
+ }
2233
+
2234
+ function renderSchemaEditor() {
2235
+ $('schema-editor').value = JSON.stringify(state.schema, null, 2);
2236
+ const levelSel = $('n-level');
2237
+ levelSel.innerHTML = state.schema.levels.map(l =>
2238
+ '<option value="' + esc(l.id) + '">' + esc(l.id) + '</option>'
2239
+ ).join('');
2240
+ const parentSel = $('n-parent');
2241
+ parentSel.innerHTML = '<option value="">\u2014 no parent \u2014</option>' +
2242
+ state.nodes.map(n => '<option value="' + esc(n.id) + '">'
2243
+ + esc(n.id) + ' (' + esc(n.level) + ')</option>').join('');
2244
+ }
2245
+
2246
+ async function refresh() {
2247
+ try {
2248
+ const r = await req('GET', '/api/admin/graph/state');
2249
+ state.schema = r.schema;
2250
+ state.nodes = r.nodes;
2251
+ state.pending = r.pending;
2252
+ state.recent = r.recent;
2253
+ renderCounts(r.counts, r.enabled);
2254
+ renderTree();
2255
+ renderPending();
2256
+ renderRecent();
2257
+ renderSchemaEditor();
2258
+ } catch (e) { showMsg('err', e.message); }
2259
+ }
2260
+
2261
+ async function approve(msgHash) {
2262
+ try {
2263
+ await req('POST', '/api/admin/graph/classifications/approve', { msgHash });
2264
+ showMsg('ok', 'Approved.');
2265
+ refresh();
2266
+ } catch (e) { showMsg('err', e.message); }
2267
+ }
2268
+
2269
+ async function reject(msgHash) {
2270
+ if (!confirm('Reject this classification? It will not be committed and no fingerprint is cached.')) return;
2271
+ try {
2272
+ await req('POST', '/api/admin/graph/classifications/reject', { msgHash });
2273
+ showMsg('ok', 'Rejected.');
2274
+ refresh();
2275
+ } catch (e) { showMsg('err', e.message); }
2276
+ }
2277
+
2278
+ async function editNode(id) {
2279
+ const n = state.nodes.find(x => x.id === id);
2280
+ if (!n) return;
2281
+ const current = JSON.stringify(n.axes || {}, null, 2);
2282
+ const next = prompt('Edit axes for "' + id + '" (JSON):', current);
2283
+ if (next == null) return;
2284
+ let axes;
2285
+ try { axes = JSON.parse(next); } catch { showMsg('err', 'Invalid JSON'); return; }
2286
+ try {
2287
+ await req('PATCH', '/api/admin/graph/nodes', { id, axes });
2288
+ showMsg('ok', 'Node updated.');
2289
+ refresh();
2290
+ } catch (e) { showMsg('err', e.message); }
2291
+ }
2292
+
2293
+ async function deleteNode(id) {
2294
+ if (!confirm('Delete node "' + id + '"? Fails if it has children or references.')) return;
2295
+ try {
2296
+ await req('DELETE', '/api/admin/graph/nodes', { id });
2297
+ showMsg('ok', 'Deleted.');
2298
+ refresh();
2299
+ } catch (e) { showMsg('err', e.message); }
2300
+ }
2301
+
2302
+ $('btn-add-node').addEventListener('click', async () => {
2303
+ const level = $('n-level').value;
2304
+ const id = $('n-id').value.trim();
2305
+ const parentId = $('n-parent').value || null;
2306
+ let axes = {};
2307
+ const raw = $('n-axes').value.trim();
2308
+ if (raw) {
2309
+ try { axes = JSON.parse(raw); }
2310
+ catch { showMsg('err', 'Axes JSON invalid.'); return; }
2311
+ }
2312
+ try {
2313
+ await req('POST', '/api/admin/graph/nodes', { id, level, parentId, axes });
2314
+ $('n-id').value = ''; $('n-axes').value = '';
2315
+ showMsg('ok', 'Node added.');
2316
+ refresh();
2317
+ } catch (e) { showMsg('err', e.message); }
2318
+ });
2319
+
2320
+ $('btn-save-schema').addEventListener('click', async () => {
2321
+ let schema;
2322
+ try { schema = JSON.parse($('schema-editor').value); }
2323
+ catch { showMsg('err', 'Schema JSON invalid.'); return; }
2324
+ try {
2325
+ await req('PUT', '/api/admin/graph/schema', { schema });
2326
+ showMsg('ok', 'Schema saved.');
2327
+ refresh();
2328
+ } catch (e) { showMsg('err', e.message); }
2329
+ });
2330
+
2331
+ $('btn-reload-schema').addEventListener('click', refresh);
2332
+
2333
+ refresh();
2334
+ </script>
2335
+ ${n}
2336
+ ${_}
2337
+ </body>
2338
+ </html>`}import{existsSync as da,readFileSync as pa}from"fs";import{resolve as Ve}from"path";G();function Je(t,e,a,n=[],o){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ia(a,n,o))}async function Ye(t,e,a){try{let n=t.method==="GET"?void 0:await _a(t),o=new URL(t.url||"/","http://localhost"),r=Object.fromEntries(o.searchParams),i=a.match(/^\/api\/admin\/agent\/([a-z0-9][a-z0-9_-]*)(?:\/(.+))?$/);if(!i){ee(e,404,{error:`unknown agent endpoint: ${a}`});return}let s=i[1],l=i[2]||"",c=`${t.method} ${l}`,u={"GET ":()=>Ze(s),"PATCH ":()=>ua(s,n),"GET identity":()=>ma(s),"GET identity/file":()=>ha(s,String(r.path||"")),"PUT identity/file":()=>ga(s,n),"GET skills":()=>fa(s),"POST skills":()=>va(s,n),"DELETE skills":()=>ba(s,n),"GET skills/tree":()=>xa(s,String(r.slug||"")),"GET skills/file":()=>ya(s,String(r.slug||""),String(r.path||"")),"PUT skills/file":()=>ka(s,n),"GET skills/deps":()=>wa(s,String(r.slug||"")),"POST skills/install":()=>Ea(s,n,t),"POST skills/deps":()=>Sa(s,n,t),"GET channels":()=>Ta(s),"GET activity":()=>Aa(s,t),"GET handovers":()=>Ca(s),"POST handovers":()=>$a(s,n),"DELETE handovers":()=>Ma(n)}[c];if(!u){ee(e,404,{error:`unknown agent sub-endpoint: ${c}`});return}let f=await u();ee(e,200,f)}catch(n){ee(e,400,{error:n?.message||"agent op failed"})}}function Qe(){let t=Ve(process.cwd(),"agentx.json");return da(t)?JSON.parse(pa(t,"utf-8")):null}function w(t){let e=Qe();if(!e)throw new Error("agentx.json not found");let a=e.agents?.[t];if(!a)throw new Error(`Agent "${t}" not found`);return{def:a,cfg:e}}function Ze(t){let{def:e,cfg:a}=w(t),n=e.workspace?z(e.workspace):null;return{id:t,name:e.name||t,tier:e.tier,model:e.model,workspace:e.workspace,systemPrompt:e.systemPrompt||"",mentions:e.mentions||[],access:e.access||"private",maxConcurrent:e.maxConcurrent??1,maxExecutionMinutes:e.maxExecutionMinutes??20,permissionMode:e.permissionMode||"default",overview:n,defaultWorker:a.node?.defaultAgent,draftAgent:a.dashboard?.draftAgent}}function ua(t,e){let a={};for(let o of["name","tier","model","systemPrompt","mentions","access","maxConcurrent","maxExecutionMinutes","permissionMode"])e?.[o]!==void 0&&(a[o]=e[o]);let{summary:n}=x(o=>{if(!o.agents?.[t])throw new Error(`Agent "${t}" not found`);return o.agents[t]={...o.agents[t],...a},`agent "${t}" updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:Ze(t)}}function ma(t){let{def:e}=w(t);return z(e.workspace)}function ha(t,e){if(!e)throw new Error("path query param required");let{def:a}=w(t);return X(a.workspace,e)}function ga(t,e){let a=String(e?.path||"");if(!a)throw new Error("path required");let{def:n}=w(t);return V(n.workspace,a,String(e?.content??""))}function fa(t){let{def:e}=w(t),a=z(e.workspace);return{skills:a.skills,workspace:a.workspace}}function va(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=w(t);return J(n.workspace,a,{title:e?.title,content:e?.content})}function ba(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=w(t);return Y(n.workspace,a)}function xa(t,e){if(!e)throw new Error("slug query param required");let{def:a}=w(t),n=Oe(a.workspace,e),o=Q(a.workspace,e);return{slug:e,tree:n,deps:o}}function ya(t,e,a){if(!e||!a)throw new Error("slug and path query params required");let{def:n}=w(t);return He(n.workspace,e,a)}function ka(t,e){let a=String(e?.slug||""),n=String(e?.path||"");if(!a||!n)throw new Error("slug and path required");let{def:o}=w(t);return Re(o.workspace,a,n,String(e?.content??""))}function wa(t,e){if(!e)throw new Error("slug query param required");let{def:a}=w(t);return Q(a.workspace,e)}async function Ea(t,e,a){let n=String(e?.package||"").trim();if(!n||!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)?$/.test(n))throw new Error("package must be in 'owner/repo' or 'owner/repo/skill' form");let o=et(e?.worker),{def:r}=w(t),i=[`Install the skills.sh package "${n}" into agent "${t}".`,`Workspace: ${r.workspace}`,`Run: cd ${r.workspace} && npx -y skills add ${n}`,`If that fails, fall back to: agentx skill install ${n}`,`Skills should land under ${r.workspace}/.claude/skills/. Report what was installed and any errors.`].join(`
2339
+ `);return tt(a,o,i,`install-${n}:${Date.now()}`)}async function Sa(t,e,a){let n=String(e?.slug||"").trim();if(!n)throw new Error("slug required");let o=et(e?.worker),{def:r}=w(t),i=Q(r.workspace,n);if(!i.manager)throw new Error(`No dependency manifest detected in .claude/skills/${n}. Expected one of: package.json, requirements.txt, Gemfile.`);let s=Ve(r.workspace,".claude","skills",n),l=[`Install dependencies for skill "${n}" in agent "${t}".`,`cd to: ${s}`,`Detected manifest: ${i.file}`,`Run: ${i.command}`,"Stream the install output. On success, summarise the packages installed.","On failure, report the exit code and the last 20 lines of output."].join(`
2340
+ `);return tt(a,o,l,`deps-${t}-${n}:${Date.now()}`)}function et(t){if(t&&typeof t=="string")return t;let e=A();return e.dashboard?.draftAgent||e.node?.defaultAgent||Object.keys(e.agents).find(a=>a.includes("devops"))||Object.keys(e.agents)[0]}async function tt(t,e,a,n){let o=A(),r=(o.dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),i={"Content-Type":"application/json"},s=t.headers.authorization;s?i.Authorization=String(s):o.dashboard.token&&(i.Authorization=`Bearer ${o.dashboard.token}`);let l=await fetch(`${r}/task`,{method:"POST",headers:i,body:JSON.stringify({agent:e,message:a,context:{channel:"admin",sender:"admin-ui",chatId:n}})}),c=await l.text(),m;try{m=JSON.parse(c)}catch{m={content:c}}if(!l.ok)throw new Error(m?.error||`daemon /task HTTP ${l.status}`);return{worker:e,taskId:m?.taskId,content:m?.content,duration:m?.duration,error:m?.error}}function Ta(t){let e=Qe(),a=[],n=e?.channels?.telegram?.accounts||{};for(let[r,i]of Object.entries(n))i?.agentBinding===t&&a.push({channel:"telegram",account:r,detail:i?.botUsername||r});e?.channels?.slack?.agentBinding===t&&a.push({channel:"slack",detail:"bound"}),e?.channels?.discord?.agentBinding===t&&a.push({channel:"discord",detail:"bound"});let o=e?.channels?.gitlab?.agentMappings||[];for(let r of o)r?.agentId===t&&a.push({channel:"gitlab",detail:(r?.gitlabUsernames||[]).join(", ")||"mapped"});return{bindings:a}}async function Aa(t,e){try{let n=(A().dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),o=await fetch(`${n}/agents`);if(!o.ok)throw new Error(`daemon HTTP ${o.status}`);let i=(await o.json()).find(s=>s.id===t);return{activeTasks:i?.activeTasks??0,totalTasks:i?.totalTasks??0,errors:i?.errors??0,lastActive:i?.lastActive??null,runningTasks:i?.runningTasks??[],lastSummary:i?.lastSummary??null}}catch(a){return{error:a?.message,activeTasks:0,totalTasks:0,errors:0,runningTasks:[]}}}function ge(){return new we}function Ca(t){let e=ge(),{incoming:a,outgoing:n}=e.listByAgent(t);return{incoming:a,outgoing:n}}function $a(t,e){let a=String(e?.channel||"").trim(),n=String(e?.chatId||"").trim(),o=String(e?.toAgent||"").trim();if(!a||!n||!o)throw new Error("channel, chatId, toAgent required");let r=String(e?.fromAgent||t||"").trim()||t,i=e?.accountId?String(e.accountId):void 0,s=e?.summary?String(e.summary):void 0,l=e?.expiresAt?String(e.expiresAt):void 0,c=ge().set({channel:a,chatId:n,accountId:i,fromAgent:r,toAgent:o,summary:s,expiresAt:l,createdBy:"admin-ui"});return{summary:`Handed off ${a}:${n} from ${r} to ${o}`,record:c}}function Ma(t){let e=String(t?.channel||"").trim(),a=String(t?.chatId||"").trim();if(!e||!a)throw new Error("channel and chatId required");let n=t?.accountId?String(t.accountId):void 0;return{summary:ge().remove(e,a,n)?"Released":"No active handover for that chat"}}function ee(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function _a(t){return new Promise((e,a)=>{let n="";t.on("data",o=>{n+=o}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(o){a(o)}}),t.on("error",a)})}function Ia(t,e,a){let n=I({activeTab:"admin",subtitle:`Agent \xB7 ${t}`,peers:e}),o=a?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(a)};</script>`:"";return`<!doctype html>
2341
+ <html lang="en" data-theme="dark">
2342
+ <head>
2343
+ <meta charset="utf-8">
2344
+ <title>AgentX \xB7 ${he(t)}</title>
2345
+ <meta name="viewport" content="width=device-width, initial-scale=1">
2346
+ ${$}
2347
+ <link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css">
2348
+ <style>
2349
+ :root{
2350
+ --ax-bg:#0a0b0f; --ax-bg-elev:#101218; --ax-surface:#151823;
2351
+ --ax-text:#e5e7eb; --ax-text-2:#b1b4c0; --ax-muted:#7a7d8a;
2352
+ --ax-border:#1d212d; --ax-border-2:#262a38; --ax-accent:#7aa2f7;
2353
+ --ax-green:#4ade80; --ax-red:#f87171; --ax-yellow:#fbbf24;
2354
+ --ax-mono:'IBM Plex Mono',ui-monospace,monospace;
2355
+ }
2356
+ :root[data-theme="light"]{
2357
+ --ax-bg:#f8fafc;--ax-bg-elev:#ffffff;--ax-surface:#ffffff;
2358
+ --ax-text:#111827;--ax-text-2:#374151;--ax-muted:#6b7280;
2359
+ --ax-border:#e5e7eb;--ax-border-2:#d1d5db;--ax-accent:#2563eb;
2360
+ }
2361
+ *{box-sizing:border-box}
2362
+ body{margin:0;background:var(--ax-bg);color:var(--ax-text);
2363
+ font-family:'IBM Plex Sans',system-ui,-apple-system,sans-serif;font-size:13px;line-height:1.5}
2364
+ ${M}
2365
+ main{max-width:1280px;margin:0 auto;padding:18px 20px 60px}
2366
+ .msg{font-size:12px;padding:8px 12px;border-radius:4px;margin-bottom:12px;display:none}
2367
+ .msg.ok{background:rgba(74,222,128,0.12);color:var(--ax-green);display:block}
2368
+ .msg.err{background:rgba(248,113,113,0.12);color:var(--ax-red);display:block}
2369
+ .back-link{display:inline-flex;align-items:center;gap:6px;color:var(--ax-muted);
2370
+ text-decoration:none;font-size:12px;margin-bottom:12px}
2371
+ .back-link:hover{color:var(--ax-accent)}
2372
+ .card{background:var(--ax-bg-elev);border:1px solid var(--ax-border);
2373
+ border-radius:8px;padding:18px;margin-bottom:16px}
2374
+ .header-card{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}
2375
+ .header-card h1{margin:0 0 6px;font-size:20px;font-weight:600;letter-spacing:-0.02em}
2376
+ .header-card .sub{color:var(--ax-muted);font-size:12px;font-family:var(--ax-mono)}
2377
+ .chips{display:flex;gap:6px;margin-top:8px;flex-wrap:wrap}
2378
+ .chip{padding:2px 10px;border-radius:3px;font-size:11px;background:var(--ax-surface);
2379
+ color:var(--ax-text-2);border:1px solid var(--ax-border);font-family:var(--ax-mono)}
2380
+ .chip.accent{background:rgba(122,162,247,0.12);color:var(--ax-accent);border-color:transparent}
2381
+ nav.tabs{display:flex;gap:2px;margin-bottom:16px;border-bottom:1px solid var(--ax-border);
2382
+ padding:0 4px}
2383
+ nav.tabs button{background:transparent;border:none;color:var(--ax-muted);padding:10px 14px;
2384
+ font:inherit;font-size:12px;cursor:pointer;border-bottom:2px solid transparent;
2385
+ letter-spacing:-0.005em;white-space:nowrap}
2386
+ nav.tabs button:hover{color:var(--ax-text)}
2387
+ nav.tabs button.active{color:var(--ax-text);border-bottom-color:var(--ax-accent)}
2388
+ section.tab{display:none}
2389
+ section.tab.active{display:block}
2390
+ button,.btn{font:inherit;font-size:12px;padding:7px 14px;border-radius:4px;
2391
+ border:1px solid var(--ax-border-2);background:var(--ax-surface);
2392
+ color:var(--ax-text);cursor:pointer}
2393
+ button:hover{border-color:var(--ax-accent);color:var(--ax-accent)}
2394
+ button.primary{background:var(--ax-accent);color:#0a0b0f;border-color:var(--ax-accent);font-weight:600}
2395
+ button.primary:hover{filter:brightness(1.08);color:#0a0b0f}
2396
+ button.danger{color:var(--ax-red);border-color:var(--ax-red)}
2397
+ button.danger:hover{background:var(--ax-red);color:#fff}
2398
+ button[disabled]{opacity:0.5;cursor:not-allowed}
2399
+ input,select,textarea{font:inherit;font-size:12px;padding:7px 10px;
2400
+ background:var(--ax-surface);color:var(--ax-text);
2401
+ border:1px solid var(--ax-border);border-radius:4px;width:100%;
2402
+ font-family:var(--ax-mono)}
2403
+ label{display:block;font-size:11px;color:var(--ax-muted);margin-bottom:4px;
2404
+ text-transform:uppercase;letter-spacing:0.05em;font-weight:600}
2405
+ .field{margin-bottom:12px}
2406
+ .row{display:flex;gap:12px;flex-wrap:wrap}
2407
+ .row > .field{flex:1 1 200px;min-width:0}
2408
+ .empty{color:var(--ax-muted);font-style:italic;padding:14px;text-align:center}
2409
+ .kv{display:flex;gap:8px;font-size:12px;color:var(--ax-text-2);margin:4px 0}
2410
+ .kv b{color:var(--ax-text);font-weight:500;min-width:80px}
2411
+ /* Skills browser */
2412
+ .skills-grid{display:grid;gap:14px;grid-template-columns:260px 260px 1fr;min-height:520px}
2413
+ @media(max-width:1000px){.skills-grid{grid-template-columns:1fr}}
2414
+ .skill-pane{background:var(--ax-surface);border:1px solid var(--ax-border);
2415
+ border-radius:6px;padding:10px;overflow:auto;max-height:620px}
2416
+ .skill-pane h3{font-size:11px;margin:0 0 10px;text-transform:uppercase;
2417
+ letter-spacing:0.06em;color:var(--ax-muted)}
2418
+ .skill-row{padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;
2419
+ justify-content:space-between;align-items:center;font-size:12px;gap:6px}
2420
+ .skill-row:hover{background:var(--ax-bg-elev)}
2421
+ .skill-row.active{background:rgba(122,162,247,0.14);color:var(--ax-accent)}
2422
+ .skill-row .slug{font-family:var(--ax-mono);color:var(--ax-muted);font-size:11px}
2423
+ .tree-entry{display:flex;justify-content:space-between;padding:4px 6px;border-radius:3px;
2424
+ cursor:pointer;font-family:var(--ax-mono);font-size:11px;color:var(--ax-text-2)}
2425
+ .tree-entry:hover{background:var(--ax-bg-elev);color:var(--ax-text)}
2426
+ .tree-entry.active{background:rgba(122,162,247,0.14);color:var(--ax-accent)}
2427
+ .tree-entry.dir{color:var(--ax-muted);font-weight:500}
2428
+ .tree-entry.readonly{opacity:0.55;cursor:default}
2429
+ .editor-wrap{display:flex;flex-direction:column;gap:8px}
2430
+ .editor-wrap .toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
2431
+ .editor-wrap .path{font-family:var(--ax-mono);font-size:11px;color:var(--ax-muted);flex:1}
2432
+ /* EasyMDE theme tweaks for dark mode */
2433
+ .EasyMDEContainer .editor-toolbar{border-color:var(--ax-border);background:var(--ax-surface)}
2434
+ .EasyMDEContainer .editor-toolbar button{color:var(--ax-text-2)}
2435
+ .EasyMDEContainer .editor-toolbar button:hover,
2436
+ .EasyMDEContainer .editor-toolbar button.active{background:var(--ax-bg-elev);color:var(--ax-accent)}
2437
+ .EasyMDEContainer .CodeMirror{border-color:var(--ax-border);background:var(--ax-bg);
2438
+ color:var(--ax-text)}
2439
+ .EasyMDEContainer .CodeMirror-cursor{border-left-color:var(--ax-accent)}
2440
+ .EasyMDEContainer .editor-statusbar{color:var(--ax-muted)}
2441
+ .plain-editor{width:100%;min-height:420px;font-family:var(--ax-mono);font-size:12px;
2442
+ line-height:1.5;resize:vertical}
2443
+ /* Confirm modal */
2444
+ .modal{position:fixed;inset:0;background:rgba(0,0,0,0.55);display:flex;
2445
+ align-items:center;justify-content:center;z-index:100}
2446
+ .modal[aria-hidden="true"]{display:none}
2447
+ .modal-card{background:var(--ax-bg-elev);border:1px solid var(--ax-border);
2448
+ border-radius:8px;padding:20px;max-width:560px;width:94vw}
2449
+ .modal-card h3{margin:0 0 10px;font-size:15px}
2450
+ .modal-card .detail{color:var(--ax-muted);font-size:12px;margin-bottom:14px;
2451
+ font-family:var(--ax-mono);background:var(--ax-surface);padding:10px;
2452
+ border-radius:4px;white-space:pre-wrap;word-break:break-word}
2453
+ .modal-card .row{justify-content:flex-end}
2454
+ .task-output{font-family:var(--ax-mono);font-size:11px;background:var(--ax-bg);
2455
+ border:1px solid var(--ax-border);border-radius:4px;padding:10px;
2456
+ max-height:300px;overflow:auto;white-space:pre-wrap;display:none;margin-top:10px}
2457
+ </style>
2458
+ </head>
2459
+ <body>
2460
+ ${n}
2461
+ <main>
2462
+ <a class="back-link" href="/admin">\u2190 Back to Settings</a>
2463
+ <div id="msg" class="msg"></div>
2464
+
2465
+ <div class="card header-card">
2466
+ <div style="flex:1">
2467
+ <h1 id="a-name">${he(t)}</h1>
2468
+ <div class="sub" id="a-id">${he(t)}</div>
2469
+ <div class="chips" id="a-chips"></div>
2470
+ </div>
2471
+ <div style="display:flex;gap:8px">
2472
+ <button id="btn-test-drive">Test drive</button>
2473
+ <button id="btn-save-meta" class="primary">Save</button>
2474
+ </div>
2475
+ </div>
2476
+
2477
+ <nav class="tabs">
2478
+ <button data-tab="overview" class="active">Overview</button>
2479
+ <button data-tab="identity">Identity</button>
2480
+ <button data-tab="skills">Skills</button>
2481
+ <button data-tab="channels">Channels</button>
2482
+ <button data-tab="handovers">Handovers</button>
2483
+ <button data-tab="activity">Activity</button>
2484
+ </nav>
2485
+
2486
+ <!-- Overview -->
2487
+ <section class="tab active" id="tab-overview">
2488
+ <div class="card">
2489
+ <label>System prompt</label>
2490
+ <textarea id="sp-editor" placeholder="# Who the agent is, what it does, how it communicates"></textarea>
2491
+ </div>
2492
+ <div class="card">
2493
+ <div class="row">
2494
+ <div class="field"><label>Name</label><input id="f-name" /></div>
2495
+ <div class="field"><label>Tier</label>
2496
+ <select id="f-tier">
2497
+ <option value="claude-code">claude-code</option>
2498
+ <option value="sdk">sdk</option>
2499
+ <option value="orchestrator">orchestrator</option>
2500
+ </select>
2501
+ </div>
2502
+ <div class="field"><label>Model</label><input id="f-model" /></div>
2503
+ </div>
2504
+ <div class="row">
2505
+ <div class="field"><label>Access</label>
2506
+ <select id="f-access">
2507
+ <option value="private">private</option>
2508
+ <option value="public">public</option>
2509
+ </select>
2510
+ </div>
2511
+ <div class="field"><label>Max concurrent</label><input id="f-maxc" type="number" min="1" /></div>
2512
+ <div class="field"><label>Max execution (min)</label><input id="f-maxt" type="number" min="1" /></div>
2513
+ <div class="field"><label>Permission mode</label>
2514
+ <select id="f-pmode">
2515
+ <option value="default">default</option>
2516
+ <option value="acceptEdits">acceptEdits</option>
2517
+ <option value="plan">plan</option>
2518
+ <option value="bypassPermissions">bypassPermissions</option>
2519
+ </select>
2520
+ </div>
2521
+ </div>
2522
+ <div class="field">
2523
+ <label>Mentions (comma-separated)</label>
2524
+ <input id="f-mentions" placeholder="@noqta_foo_bot, foo" />
2525
+ </div>
2526
+ </div>
2527
+ </section>
2528
+
2529
+ <!-- Identity -->
2530
+ <section class="tab" id="tab-identity">
2531
+ <div class="card">
2532
+ <div class="editor-wrap">
2533
+ <div class="toolbar">
2534
+ <label style="margin:0">File</label>
2535
+ <select id="id-select" style="width:260px"></select>
2536
+ <span class="path" id="id-path"></span>
2537
+ <button id="btn-save-id" class="primary">Save file</button>
2538
+ </div>
2539
+ <textarea id="id-editor"></textarea>
2540
+ </div>
2541
+ </div>
2542
+ </section>
2543
+
2544
+ <!-- Skills -->
2545
+ <section class="tab" id="tab-skills">
2546
+ <div class="card">
2547
+ <div class="row" style="align-items:center">
2548
+ <div style="flex:1"></div>
2549
+ <input id="pkg-input" placeholder="owner/repo (or owner/repo/skill)" style="flex:0 0 320px" />
2550
+ <button id="btn-install-pkg">Install package\u2026</button>
2551
+ <button id="btn-new-skill">+ New skill</button>
2552
+ </div>
2553
+ <div class="task-output" id="dispatch-output"></div>
2554
+ </div>
2555
+ <div class="skills-grid">
2556
+ <div class="skill-pane">
2557
+ <h3>Skills</h3>
2558
+ <div id="skills-list"></div>
2559
+ </div>
2560
+ <div class="skill-pane">
2561
+ <h3>Tree <span style="float:right"><button id="btn-install-deps" style="font-size:10px;padding:3px 8px" disabled>Install deps\u2026</button> <button id="btn-delete-skill" class="danger" style="font-size:10px;padding:3px 8px" disabled>Delete</button></span></h3>
2562
+ <div id="skill-tree"></div>
2563
+ </div>
2564
+ <div class="skill-pane" style="padding:14px">
2565
+ <div class="editor-wrap" id="sk-editor-wrap" style="display:none">
2566
+ <div class="toolbar">
2567
+ <span class="path" id="sk-path">\u2014</span>
2568
+ <button id="btn-save-sk" class="primary">Save file</button>
2569
+ </div>
2570
+ <textarea id="sk-editor"></textarea>
2571
+ </div>
2572
+ <div class="empty" id="sk-editor-empty">Select a file in the tree to edit.</div>
2573
+ </div>
2574
+ </div>
2575
+ </section>
2576
+
2577
+ <!-- Channels -->
2578
+ <section class="tab" id="tab-channels">
2579
+ <div class="card"><div id="channels-list" class="empty">loading\u2026</div></div>
2580
+ </section>
2581
+
2582
+ <!-- Handovers -->
2583
+ <section class="tab" id="tab-handovers">
2584
+ <div class="card">
2585
+ <h2 style="margin:0 0 4px;font-size:14px">Hand this agent's chat to someone else</h2>
2586
+ <p class="muted" style="margin:0 0 12px">Routes every subsequent message from (channel, chatId) to the target agent. A one-shot briefing is injected into the target agent's first context.</p>
2587
+ <div class="row">
2588
+ <div class="field" style="flex:0 0 140px"><label>Channel</label>
2589
+ <select id="ho-channel"><option value="telegram">telegram</option><option value="whatsapp">whatsapp</option></select>
2590
+ </div>
2591
+ <div class="field" style="flex:1 1 180px"><label>Chat id</label>
2592
+ <input id="ho-chatid" placeholder="1816212449 or +21612345678" />
2593
+ </div>
2594
+ <div class="field" style="flex:0 0 140px"><label>Account (optional)</label>
2595
+ <input id="ho-account" placeholder="default" />
2596
+ </div>
2597
+ <div class="field" style="flex:1 1 180px"><label>Transfer to</label>
2598
+ <select id="ho-target"></select>
2599
+ </div>
2600
+ </div>
2601
+ <div class="field">
2602
+ <label>Briefing summary (one-shot note for the receiving agent)</label>
2603
+ <textarea id="ho-summary" style="min-height:90px" placeholder="Customer is asking about enterprise pricing. They've already seen the standard tier..."></textarea>
2604
+ </div>
2605
+ <div class="row" style="align-items:flex-end">
2606
+ <div class="field" style="flex:0 0 200px"><label>Expires (optional ISO)</label>
2607
+ <input id="ho-expires" placeholder="2026-04-20T00:00:00Z" />
2608
+ </div>
2609
+ <button id="btn-handover" class="primary">Hand off</button>
2610
+ </div>
2611
+ </div>
2612
+
2613
+ <div class="card">
2614
+ <h2 style="margin:0 0 8px;font-size:14px">Incoming \u2014 chats routed TO this agent</h2>
2615
+ <div id="ho-incoming" class="empty">loading\u2026</div>
2616
+ </div>
2617
+
2618
+ <div class="card">
2619
+ <h2 style="margin:0 0 8px;font-size:14px">Outgoing \u2014 chats routed AWAY from this agent</h2>
2620
+ <div id="ho-outgoing" class="empty">loading\u2026</div>
2621
+ </div>
2622
+ </section>
2623
+
2624
+ <!-- Activity -->
2625
+ <section class="tab" id="tab-activity">
2626
+ <div class="card"><div id="activity" class="empty">loading\u2026</div></div>
2627
+ </section>
2628
+ </main>
2629
+
2630
+ <!-- Confirm modal -->
2631
+ <div class="modal" id="confirm-modal" aria-hidden="true">
2632
+ <div class="modal-card">
2633
+ <h3 id="confirm-title">Confirm</h3>
2634
+ <div class="detail" id="confirm-detail"></div>
2635
+ <div class="row">
2636
+ <button id="confirm-cancel">Cancel</button>
2637
+ <button id="confirm-ok" class="primary">Run</button>
2638
+ </div>
2639
+ </div>
2640
+ </div>
2641
+
2642
+ <script src="https://unpkg.com/easymde/dist/easymde.min.js"></script>
2643
+ <script>
2644
+ const AGENT_ID = ${JSON.stringify(t)};
2645
+ const $ = (id) => document.getElementById(id);
2646
+ const state = { agent: null, activeSkill: null, activeSkillFile: null, identityPath: null };
2647
+
2648
+ function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));}
2649
+
2650
+ async function req(method, path, body) {
2651
+ const headers = { 'Content-Type': 'application/json' };
2652
+ if (window.AX_LOCAL_TOKEN) headers['Authorization'] = 'Bearer ' + window.AX_LOCAL_TOKEN;
2653
+ const r = await fetch(path, { method, headers, body: body ? JSON.stringify(body) : undefined });
2654
+ const data = await r.json().catch(() => ({}));
2655
+ if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));
2656
+ return data;
2657
+ }
2658
+
2659
+ function showMsg(kind, text){ const m = $('msg'); m.className='msg '+kind; m.textContent=text; setTimeout(()=>{m.className='msg';}, 4000); }
2660
+
2661
+ // --- confirm modal ---
2662
+ function confirmAction(title, detail, onConfirm){
2663
+ $('confirm-title').textContent = title;
2664
+ $('confirm-detail').textContent = detail;
2665
+ const modal = $('confirm-modal');
2666
+ modal.setAttribute('aria-hidden', 'false');
2667
+ const cleanup = () => {
2668
+ modal.setAttribute('aria-hidden', 'true');
2669
+ $('confirm-ok').onclick = null;
2670
+ $('confirm-cancel').onclick = null;
2671
+ };
2672
+ $('confirm-ok').onclick = () => { cleanup(); onConfirm(); };
2673
+ $('confirm-cancel').onclick = cleanup;
2674
+ }
2675
+
2676
+ // --- Tabs ---
2677
+ for (const btn of document.querySelectorAll('nav.tabs button')) {
2678
+ btn.addEventListener('click', () => {
2679
+ document.querySelectorAll('nav.tabs button').forEach(b=>b.classList.remove('active'));
2680
+ document.querySelectorAll('section.tab').forEach(s=>s.classList.remove('active'));
2681
+ btn.classList.add('active');
2682
+ $('tab-' + btn.dataset.tab).classList.add('active');
2683
+ if (btn.dataset.tab === 'skills' && !state.agent?.skillsLoaded) loadSkills();
2684
+ if (btn.dataset.tab === 'identity' && !state.agent?.identityLoaded) loadIdentity();
2685
+ if (btn.dataset.tab === 'channels') loadChannels();
2686
+ if (btn.dataset.tab === 'handovers') loadHandovers();
2687
+ if (btn.dataset.tab === 'activity') loadActivity();
2688
+ });
2689
+ }
2690
+
2691
+ // --- EasyMDE instances ---
2692
+ let spMde, idMde, skMde;
2693
+ function makeMde(el){
2694
+ return new EasyMDE({
2695
+ element: el, spellChecker: false, status: ['lines','words'],
2696
+ autoDownloadFontAwesome: true, autofocus: false,
2697
+ toolbar: ['bold','italic','heading','|','quote','code','unordered-list','ordered-list','|','link','image','table','|','preview','side-by-side','fullscreen','|','guide'],
2698
+ });
2699
+ }
2700
+
2701
+ // --- Overview ---
2702
+ async function loadAgent(){
2703
+ try {
2704
+ const a = await req('GET', '/api/admin/agent/' + AGENT_ID);
2705
+ state.agent = a;
2706
+ $('a-name').textContent = a.name || AGENT_ID;
2707
+ $('a-id').textContent = AGENT_ID + ' \xB7 ' + (a.workspace || '\u2014');
2708
+ const chips = [
2709
+ a.tier && '<span class="chip accent">'+esc(a.tier)+'</span>',
2710
+ a.model && '<span class="chip">'+esc(a.model)+'</span>',
2711
+ a.access && '<span class="chip">'+esc(a.access)+'</span>',
2712
+ ...(a.mentions || []).map(m => '<span class="chip">'+esc(m)+'</span>'),
2713
+ ].filter(Boolean).join('');
2714
+ $('a-chips').innerHTML = chips;
2715
+ $('f-name').value = a.name || '';
2716
+ $('f-tier').value = a.tier || 'claude-code';
2717
+ $('f-model').value = a.model || '';
2718
+ $('f-access').value = a.access || 'private';
2719
+ $('f-maxc').value = a.maxConcurrent ?? 1;
2720
+ $('f-maxt').value = a.maxExecutionMinutes ?? 20;
2721
+ $('f-pmode').value = a.permissionMode || 'default';
2722
+ $('f-mentions').value = (a.mentions || []).join(', ');
2723
+ if (!spMde) spMde = makeMde($('sp-editor'));
2724
+ spMde.value(a.systemPrompt || '');
2725
+ } catch (e) { showMsg('err', e.message); }
2726
+ }
2727
+
2728
+ $('btn-save-meta').addEventListener('click', async () => {
2729
+ const body = {
2730
+ name: $('f-name').value.trim(),
2731
+ tier: $('f-tier').value,
2732
+ model: $('f-model').value.trim(),
2733
+ access: $('f-access').value,
2734
+ maxConcurrent: Number($('f-maxc').value) || 1,
2735
+ maxExecutionMinutes: Number($('f-maxt').value) || 20,
2736
+ permissionMode: $('f-pmode').value,
2737
+ mentions: $('f-mentions').value.split(',').map(s=>s.trim()).filter(Boolean),
2738
+ systemPrompt: spMde ? spMde.value() : '',
2739
+ };
2740
+ try {
2741
+ await req('PATCH', '/api/admin/agent/' + AGENT_ID, body);
2742
+ showMsg('ok', 'Saved. Restart the daemon for tier/model changes to take effect.');
2743
+ } catch (e) { showMsg('err', e.message); }
2744
+ });
2745
+
2746
+ // --- Identity ---
2747
+ async function loadIdentity(){
2748
+ try {
2749
+ const r = await req('GET', '/api/admin/agent/' + AGENT_ID + '/identity');
2750
+ const sel = $('id-select');
2751
+ sel.innerHTML = r.identity.map(f =>
2752
+ '<option value="'+esc(f.path)+'" '+(f.exists?'':'data-new="1"')+'>'+esc(f.title)+(f.exists?'':' (new)')+'</option>'
2753
+ ).join('');
2754
+ sel.onchange = loadIdentityFile;
2755
+ if (!idMde) idMde = makeMde($('id-editor'));
2756
+ if (r.identity.length) {
2757
+ sel.value = r.identity[0].path;
2758
+ await loadIdentityFile();
2759
+ }
2760
+ state.agent.identityLoaded = true;
2761
+ } catch (e) { showMsg('err', e.message); }
2762
+ }
2763
+
2764
+ async function loadIdentityFile(){
2765
+ const p = $('id-select').value;
2766
+ $('id-path').textContent = p;
2767
+ state.identityPath = p;
2768
+ try {
2769
+ const f = await req('GET', '/api/admin/agent/' + AGENT_ID + '/identity/file?path=' + encodeURIComponent(p));
2770
+ idMde.value(f.content || '');
2771
+ } catch (e) { showMsg('err', e.message); idMde.value(''); }
2772
+ }
2773
+
2774
+ $('btn-save-id').addEventListener('click', async () => {
2775
+ if (!state.identityPath) return;
2776
+ try {
2777
+ await req('PUT', '/api/admin/agent/' + AGENT_ID + '/identity/file', {
2778
+ path: state.identityPath, content: idMde.value(),
2779
+ });
2780
+ showMsg('ok', 'Saved ' + state.identityPath);
2781
+ } catch (e) { showMsg('err', e.message); }
2782
+ });
2783
+
2784
+ // --- Skills ---
2785
+ async function loadSkills(){
2786
+ try {
2787
+ const r = await req('GET', '/api/admin/agent/' + AGENT_ID + '/skills');
2788
+ const list = $('skills-list');
2789
+ if (!r.skills.length) {
2790
+ list.innerHTML = '<div class="empty">No skills. Install a package or create one below.</div>';
2791
+ } else {
2792
+ list.innerHTML = r.skills.map(s =>
2793
+ '<div class="skill-row" data-slug="'+esc(s.slug)+'">'
2794
+ + '<span>'+esc(s.title)+'<br><span class="slug">'+esc(s.slug)+'</span></span>'
2795
+ + '</div>'
2796
+ ).join('');
2797
+ list.querySelectorAll('[data-slug]').forEach(r=>r.addEventListener('click', ()=>selectSkill(r.dataset.slug)));
2798
+ }
2799
+ state.agent.skillsLoaded = true;
2800
+ } catch (e) { showMsg('err', e.message); }
2801
+ }
2802
+
2803
+ async function selectSkill(slug){
2804
+ state.activeSkill = slug;
2805
+ state.activeSkillFile = null;
2806
+ document.querySelectorAll('#skills-list [data-slug]').forEach(r=>{
2807
+ r.classList.toggle('active', r.dataset.slug === slug);
2808
+ });
2809
+ $('btn-delete-skill').disabled = false;
2810
+ $('btn-install-deps').disabled = true;
2811
+ $('sk-editor-wrap').style.display = 'none';
2812
+ $('sk-editor-empty').style.display = 'block';
2813
+ try {
2814
+ const r = await req('GET', '/api/admin/agent/' + AGENT_ID + '/skills/tree?slug=' + encodeURIComponent(slug));
2815
+ $('btn-install-deps').disabled = !r.deps?.manager;
2816
+ $('btn-install-deps').title = r.deps?.command || 'No package manifest detected';
2817
+ const host = $('skill-tree');
2818
+ host.innerHTML = r.tree.map(e => {
2819
+ const depth = (e.path.match(/\\//g) || []).length;
2820
+ const pad = 'padding-left:' + (depth * 10) + 'px';
2821
+ const icon = e.kind === 'dir' ? '\u25B8' : '\xB7';
2822
+ const cls = 'tree-entry ' + e.kind + (e.editable ? '' : ' readonly');
2823
+ return '<div class="'+cls+'" style="'+pad+'" data-path="'+esc(e.path)+'" data-editable="'+(e.editable?'1':'0')+'">'
2824
+ + '<span>'+icon+' '+esc(e.path.split('/').filter(Boolean).pop() || e.path)+'</span>'
2825
+ + '<span style="color:var(--ax-muted);font-size:10px">'+(e.kind==='file'?formatBytes(e.size):'')+'</span>'
2826
+ + '</div>';
2827
+ }).join('');
2828
+ host.querySelectorAll('[data-path]').forEach(r=>r.addEventListener('click', ()=>{
2829
+ if (r.dataset.editable === '1') openSkillFile(r.dataset.path);
2830
+ }));
2831
+ // Auto-open SKILL.md
2832
+ const skillMd = r.tree.find(e => e.path === 'SKILL.md' && e.editable);
2833
+ if (skillMd) openSkillFile('SKILL.md');
2834
+ } catch (e) { showMsg('err', e.message); }
2835
+ }
2836
+
2837
+ function formatBytes(n){ if (!n) return ''; if (n < 1024) return n+'b'; if (n<1048576) return (n/1024).toFixed(1)+'k'; return (n/1048576).toFixed(1)+'M'; }
2838
+
2839
+ async function openSkillFile(path){
2840
+ state.activeSkillFile = path;
2841
+ $('sk-path').textContent = state.activeSkill + '/' + path;
2842
+ $('sk-editor-empty').style.display = 'none';
2843
+ $('sk-editor-wrap').style.display = 'flex';
2844
+ document.querySelectorAll('#skill-tree [data-path]').forEach(r=>r.classList.toggle('active', r.dataset.path === path));
2845
+ try {
2846
+ const f = await req('GET', '/api/admin/agent/' + AGENT_ID + '/skills/file?slug=' + encodeURIComponent(state.activeSkill) + '&path=' + encodeURIComponent(path));
2847
+ // Use EasyMDE for .md, plain textarea for everything else
2848
+ const isMd = path.toLowerCase().endsWith('.md') || path.toLowerCase().endsWith('.markdown');
2849
+ $('sk-editor').classList.toggle('plain-editor', !isMd);
2850
+ if (skMde) { skMde.toTextArea(); skMde = null; }
2851
+ if (isMd) {
2852
+ skMde = makeMde($('sk-editor'));
2853
+ skMde.value(f.content || '');
2854
+ } else {
2855
+ $('sk-editor').value = f.content || '';
2856
+ }
2857
+ } catch (e) { showMsg('err', e.message); }
2858
+ }
2859
+
2860
+ $('btn-save-sk').addEventListener('click', async () => {
2861
+ if (!state.activeSkill || !state.activeSkillFile) return;
2862
+ const content = skMde ? skMde.value() : $('sk-editor').value;
2863
+ try {
2864
+ await req('PUT', '/api/admin/agent/' + AGENT_ID + '/skills/file', {
2865
+ slug: state.activeSkill, path: state.activeSkillFile, content,
2866
+ });
2867
+ showMsg('ok', 'Saved ' + state.activeSkill + '/' + state.activeSkillFile);
2868
+ } catch (e) { showMsg('err', e.message); }
2869
+ });
2870
+
2871
+ $('btn-new-skill').addEventListener('click', async () => {
2872
+ const slug = prompt('New skill slug (lowercase, letters/digits/-/_):');
2873
+ if (!slug) return;
2874
+ try {
2875
+ await req('POST', '/api/admin/agent/' + AGENT_ID + '/skills', { slug });
2876
+ showMsg('ok', 'Skill created: ' + slug);
2877
+ await loadSkills();
2878
+ selectSkill(slug);
2879
+ } catch (e) { showMsg('err', e.message); }
2880
+ });
2881
+
2882
+ $('btn-delete-skill').addEventListener('click', () => {
2883
+ if (!state.activeSkill) return;
2884
+ const slug = state.activeSkill;
2885
+ confirmAction(
2886
+ 'Delete skill "' + slug + '"?',
2887
+ 'This removes .claude/skills/' + slug + ' and all files inside it. This cannot be undone.',
2888
+ async () => {
2889
+ try {
2890
+ await req('DELETE', '/api/admin/agent/' + AGENT_ID + '/skills', { slug });
2891
+ state.activeSkill = null;
2892
+ state.activeSkillFile = null;
2893
+ $('skill-tree').innerHTML = '';
2894
+ $('sk-editor-wrap').style.display = 'none';
2895
+ $('sk-editor-empty').style.display = 'block';
2896
+ $('btn-delete-skill').disabled = true;
2897
+ $('btn-install-deps').disabled = true;
2898
+ showMsg('ok', 'Deleted ' + slug);
2899
+ loadSkills();
2900
+ } catch (e) { showMsg('err', e.message); }
2901
+ }
2902
+ );
2903
+ });
2904
+
2905
+ $('btn-install-pkg').addEventListener('click', () => {
2906
+ const pkg = $('pkg-input').value.trim();
2907
+ if (!pkg) { showMsg('err', 'Enter a package like "owner/repo".'); return; }
2908
+ const worker = state.agent?.draftAgent || state.agent?.defaultWorker || 'devops-agent';
2909
+ confirmAction(
2910
+ 'Install skills.sh package?',
2911
+ 'Package: ' + pkg + '\\n\\nWorker agent: ' + worker + '\\n\\nThe worker will run: npx skills add ' + pkg + '\\n\\nInside: ' + (state.agent?.workspace || '(agent workspace)') + '\\n\\nOutput will appear below.',
2912
+ async () => {
2913
+ $('dispatch-output').style.display = 'block';
2914
+ $('dispatch-output').textContent = 'Dispatching to ' + worker + '\u2026';
2915
+ try {
2916
+ const r = await req('POST', '/api/admin/agent/' + AGENT_ID + '/skills/install', { package: pkg });
2917
+ $('dispatch-output').textContent = (r.content || '(no output)') + '\\n\\n-- done --';
2918
+ loadSkills();
2919
+ } catch (e) { $('dispatch-output').textContent = 'Error: ' + e.message; }
2920
+ }
2921
+ );
2922
+ });
2923
+
2924
+ $('btn-install-deps').addEventListener('click', async () => {
2925
+ if (!state.activeSkill) return;
2926
+ const slug = state.activeSkill;
2927
+ try {
2928
+ const hint = await req('GET', '/api/admin/agent/' + AGENT_ID + '/skills/deps?slug=' + encodeURIComponent(slug));
2929
+ if (!hint.manager) { showMsg('err', 'No package manifest in skill dir.'); return; }
2930
+ const worker = state.agent?.draftAgent || state.agent?.defaultWorker || 'devops-agent';
2931
+ confirmAction(
2932
+ 'Install dependencies?',
2933
+ 'Skill: ' + slug + '\\nManifest: ' + hint.file + '\\nCommand: ' + hint.command + '\\n\\nWorker agent: ' + worker + '\\n\\nRunning install scripts executes third-party code. Confirm only if you trust this skill\\'s source.',
2934
+ async () => {
2935
+ $('dispatch-output').style.display = 'block';
2936
+ $('dispatch-output').textContent = 'Dispatching to ' + worker + '\u2026';
2937
+ try {
2938
+ const r = await req('POST', '/api/admin/agent/' + AGENT_ID + '/skills/deps', { slug });
2939
+ $('dispatch-output').textContent = (r.content || '(no output)') + '\\n\\n-- done --';
2940
+ } catch (e) { $('dispatch-output').textContent = 'Error: ' + e.message; }
2941
+ }
2942
+ );
2943
+ } catch (e) { showMsg('err', e.message); }
2944
+ });
2945
+
2946
+ // --- Channels + Activity ---
2947
+ async function loadChannels(){
2948
+ try {
2949
+ const r = await req('GET', '/api/admin/agent/' + AGENT_ID + '/channels');
2950
+ const host = $('channels-list');
2951
+ if (!r.bindings.length) { host.innerHTML = '<div class="empty">No channel bindings.</div>'; return; }
2952
+ host.classList.remove('empty');
2953
+ host.innerHTML = r.bindings.map(b =>
2954
+ '<div class="kv"><b>'+esc(b.channel)+'</b>'
2955
+ + (b.account ? ' \xB7 <span class="chip">'+esc(b.account)+'</span>' : '')
2956
+ + ' \xB7 ' + esc(b.detail) + '</div>'
2957
+ ).join('');
2958
+ } catch (e) { showMsg('err', e.message); }
2959
+ }
2960
+
2961
+ async function loadHandovers(){
2962
+ try {
2963
+ // Populate the "Transfer to" dropdown with every local agent except self.
2964
+ const targets = $('ho-target');
2965
+ if (!targets.options.length) {
2966
+ const raw = await fetch('/api/admin/state', { headers: window.AX_LOCAL_TOKEN ? { Authorization: 'Bearer ' + window.AX_LOCAL_TOKEN } : {} });
2967
+ const st = await raw.json();
2968
+ targets.innerHTML = (st.agents || [])
2969
+ .filter(a => a.id !== AGENT_ID)
2970
+ .map(a => '<option value="'+esc(a.id)+'">'+esc(a.name || a.id)+' ('+esc(a.id)+')</option>')
2971
+ .join('');
2972
+ }
2973
+ const r = await req('GET', '/api/admin/agent/' + AGENT_ID + '/handovers');
2974
+ renderHandoverList($('ho-incoming'), r.incoming, 'incoming');
2975
+ renderHandoverList($('ho-outgoing'), r.outgoing, 'outgoing');
2976
+ } catch (e) { showMsg('err', e.message); }
2977
+ }
2978
+
2979
+ function renderHandoverList(host, list, direction){
2980
+ if (!list.length) {
2981
+ host.classList.add('empty');
2982
+ host.innerHTML = direction === 'incoming'
2983
+ ? 'No chats are currently routed to this agent.'
2984
+ : 'No chats are currently routed away from this agent.';
2985
+ return;
2986
+ }
2987
+ host.classList.remove('empty');
2988
+ host.innerHTML = list.map(o => {
2989
+ const who = direction === 'incoming' ? ('from ' + esc(o.fromAgent)) : ('to ' + esc(o.toAgent));
2990
+ const expires = o.expiresAt ? ' \xB7 expires ' + esc(o.expiresAt) : '';
2991
+ const consumed = o.summaryConsumedAt ? ' \xB7 briefing delivered' : (o.summary ? ' \xB7 briefing pending' : '');
2992
+ return '<div class="node-row">'
2993
+ + '<span class="chip">'+esc(o.channel)+'</span>'
2994
+ + '<span class="mono">'+esc(o.chatId)+(o.accountId ? ':'+esc(o.accountId) : '')+'</span>'
2995
+ + '<span class="muted" style="flex:1">'+who+' \xB7 since '+esc(o.createdAt)+expires+consumed+'</span>'
2996
+ + '<button class="danger" data-release="'+esc(o.channel)+'::'+esc(o.chatId)+'::'+esc(o.accountId || '')+'">Release</button>'
2997
+ + '</div>';
2998
+ }).join('');
2999
+ host.querySelectorAll('[data-release]').forEach(btn => btn.addEventListener('click', () => {
3000
+ const [ch, cid, acct] = btn.dataset.release.split('::');
3001
+ releaseHandover(ch, cid, acct || undefined);
3002
+ }));
3003
+ }
3004
+
3005
+ async function releaseHandover(channel, chatId, accountId){
3006
+ if (!confirm('Release the handover for ' + channel + ':' + chatId + '? Routing will revert to the config default on the next message.')) return;
3007
+ try {
3008
+ await req('DELETE', '/api/admin/agent/' + AGENT_ID + '/handovers', { channel, chatId, accountId });
3009
+ showMsg('ok', 'Handover released.');
3010
+ loadHandovers();
3011
+ } catch (e) { showMsg('err', e.message); }
3012
+ }
3013
+
3014
+ $('btn-handover').addEventListener('click', () => {
3015
+ const channel = $('ho-channel').value;
3016
+ const chatId = $('ho-chatid').value.trim();
3017
+ const accountId = $('ho-account').value.trim() || undefined;
3018
+ const toAgent = $('ho-target').value;
3019
+ const summary = $('ho-summary').value.trim() || undefined;
3020
+ const expiresAt = $('ho-expires').value.trim() || undefined;
3021
+ if (!chatId || !toAgent) { showMsg('err', 'chat id and target agent are required'); return; }
3022
+ confirmAction(
3023
+ 'Hand off this chat?',
3024
+ channel + ':' + chatId + (accountId ? ':'+accountId : '') + '\\n\\n'
3025
+ + 'From: ' + AGENT_ID + '\\nTo: ' + toAgent + '\\n\\n'
3026
+ + 'Every next message from this chat will be routed to ' + toAgent + ' until you release the handover. '
3027
+ + (summary ? 'The target agent will see your briefing note on its first reply.' : 'No briefing note set \u2014 the target agent will not know why.'),
3028
+ async () => {
3029
+ try {
3030
+ await req('POST', '/api/admin/agent/' + AGENT_ID + '/handovers',
3031
+ { channel, chatId, accountId, toAgent, summary, expiresAt });
3032
+ $('ho-summary').value = '';
3033
+ showMsg('ok', 'Handed off.');
3034
+ loadHandovers();
3035
+ } catch (e) { showMsg('err', e.message); }
3036
+ }
3037
+ );
3038
+ });
3039
+
3040
+ async function loadActivity(){
3041
+ try {
3042
+ const r = await req('GET', '/api/admin/agent/' + AGENT_ID + '/activity');
3043
+ const host = $('activity');
3044
+ host.classList.remove('empty');
3045
+ host.innerHTML =
3046
+ '<div class="kv"><b>Active</b>' + (r.activeTasks ?? 0) + '</div>' +
3047
+ '<div class="kv"><b>Total</b>' + (r.totalTasks ?? 0) + '</div>' +
3048
+ '<div class="kv"><b>Errors</b>' + (r.errors ?? 0) + '</div>' +
3049
+ '<div class="kv"><b>Last active</b>' + (r.lastActive || '\u2014') + '</div>' +
3050
+ (r.lastSummary ? '<div class="kv"><b>Last task</b><span>'+esc((r.lastSummary.text || '').slice(0, 240))+'</span></div>' : '');
3051
+ } catch (e) { showMsg('err', e.message); }
3052
+ }
3053
+
3054
+ $('btn-test-drive').addEventListener('click', () => {
3055
+ window.location.href = '/admin#agent=' + encodeURIComponent(AGENT_ID);
3056
+ });
3057
+
3058
+ loadAgent();
3059
+ </script>
3060
+ ${o}
3061
+ ${_}
3062
+ </body>
3063
+ </html>`}function he(t){return String(t||"").replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function Wn(t){let e=t.dashboard,a=t.boards,n=e.port,o=e.bind,r=e.token,i=new Map;for(let l of a)try{i.set(l.id,Ba(l,t))}catch(c){console.error(` Board "${l.id}" failed to initialize: ${c.message}`)}La(async(l,c)=>{try{await Ha(l,c,{boards:a,sources:i,token:r,config:t})}catch(m){h(c,500,{error:m.message||"internal error"})}}).listen(n,o,()=>{let l=o==="0.0.0.0"?"localhost":o;a.length===0?(console.log(`
3064
+ Live dashboard: http://${l}:${n}
1963
3065
  `),console.log(" (no boards configured \u2014 '/' serves the live view; add a board with 'agentx board add')")):(console.log(`
1964
- Kanban dashboard: http://${c}:${n}
1965
- `),console.log(` Boards: ${a.map(d=>d.id).join(", ")}`)),o==="127.0.0.1"&&!r?console.log(" (bound to localhost; no auth token \u2014 safe default)"):o!=="127.0.0.1"&&!r&&console.log(" \u26A0 bound to a non-loopback address without a token \u2014 writes are UNAUTHENTICATED")})}async function Lt(t,e,a){let n=new URL(t.url||"/","http://localhost"),o=n.pathname,r=(t.method||"GET").toUpperCase();if(e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, PATCH, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization, X-Requested-With"),r==="OPTIONS"){e.writeHead(204),e.end();return}if(r==="GET"&&o==="/"){let i=re();if(!i.configExists||i.agentCount===0){e.writeHead(302,{Location:"/setup"}),e.end();return}let p=a.boards.length===0?Le(a.config):Gt(a.config);e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(p);return}if(r==="GET"&&o==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Le(a.config));return}if(r==="GET"&&o==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Vt(a.config));return}if(r==="GET"&&o==="/setup"){ie(t,e);return}if(r==="POST"&&o==="/api/setup"){await se(t,e);return}if(r==="GET"&&o==="/admin"){Te(t,e,z(a.config),a.token);return}if(o.startsWith("/api/admin/")){let i=String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(i&&i!=="primary"){let p=Xt(i,a.config);if(!p){m(e,404,{error:`unknown peer: ${i}`});return}await Kt(t,e,p,o+(n.search||""));return}if(a.token){let p=t.headers.authorization||"",h=p.startsWith("Bearer ")?p.slice(7):"";if(h!==a.token){let v=new T,y=h?v.verify(h):null;if(!y||!B(y,"dashboard:write")){m(e,401,{error:"unauthorized"});return}}}}if(r==="GET"&&o==="/api/admin/config"){await Ce(t,e);return}if(o.startsWith("/api/admin/")){await Ae(t,e,o);return}if(r==="GET"&&o==="/sortable.min.js"){e.writeHead(200,{"Content-Type":"application/javascript; charset=utf-8","Cache-Control":"public, max-age=86400"}),e.end(ce);return}if(r==="GET"&&o==="/api/live"){try{let i=await De(a.config);m(e,200,i)}catch(i){m(e,502,{error:i.message})}return}if(r==="GET"&&o==="/api/live/stream"){Bt(t,e,a.config);return}if(r==="GET"&&o==="/api/task/stream"){let i=new URL(t.url||"/","http://localhost"),p=i.searchParams.get("node"),h=i.searchParams.get("agent"),v=i.searchParams.get("task");if(!p||!h||!v){m(e,400,{error:"node, agent, task query params required"});return}await Nt(t,e,a,p,h,v);return}if(r==="GET"&&o==="/api/task/history"){let i=new URL(t.url||"/","http://localhost"),p=i.searchParams.get("node"),h=i.searchParams.get("agent"),v=i.searchParams.get("task"),y=i.searchParams.get("limit")||"50";if(!p||!h){m(e,400,{error:"node and agent query params required"});return}await Ft(e,a,p,h,v,y);return}if(r==="GET"&&o==="/api/agents"){try{let i={};a.config.dashboard.token&&(i.Authorization=`Bearer ${a.config.dashboard.token}`);let p=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:i});if(!p.ok)throw new Error(`HTTP ${p.status}`);let h=await p.json();m(e,200,h)}catch(i){m(e,502,{error:i.message||"agents fetch failed"})}return}if(r==="POST"&&o==="/api/draft"){let i=await H(t);try{let p=await qt(a.config,i);m(e,200,p)}catch(p){m(e,502,{error:p.message||"draft failed"})}return}let s=o.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(s&&r==="POST"){let i=s[1];if(!zt(t,e,[`agent:${i}`]))return;await Ut(t,e,a.config,i);return}if(o.startsWith("/api/")&&a.token){let i=t.headers.authorization||"",p=i.startsWith("Bearer ")?i.slice(7):"";if(p!==a.token){let h=new T,v=p?h.verify(p):null;if(!v||!B(v,"dashboard:write")){m(e,401,{error:"unauthorized"});return}}}if((r==="POST"||r==="PATCH"||r==="DELETE")&&o.startsWith("/api/")&&t.headers["x-requested-with"]!=="agentx-board"){m(e,400,{error:"missing X-Requested-With: agentx-board"});return}if(r==="GET"&&o==="/api/boards"){m(e,200,a.boards.map(i=>({id:i.id,name:i.name,source:i.source,primaryToolLabel:i.primaryToolLabel,labels:i.labels,columns:i.columns,timeRangeDays:i.timeRangeDays})));return}let c=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/members$/);if(c&&r==="GET"){let i=a.sources.get(c[1]);if(!i){m(e,404,{error:"unknown board"});return}try{let p=typeof i.listMembers=="function"?await i.listMembers():[];m(e,200,p)}catch(p){m(e,502,{error:p.message})}return}let d=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(d&&r==="GET"){let i=a.sources.get(d[1]);if(!i){m(e,404,{error:"unknown board"});return}try{let p=typeof i.listMilestones=="function"?await i.listMilestones():[];m(e,200,p)}catch(p){m(e,502,{error:p.message})}return}let g=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),u=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(g&&r==="PATCH"){let[,i,p]=g,h=decodeURIComponent(p),v=a.boards.find(w=>w.id===i);if(!v){m(e,404,{error:`unknown board: ${i}`});return}let y=a.sources.get(i);if(!y){m(e,503,{error:`board "${i}" source unavailable`});return}let b=await H(t),f=v.columns.find(w=>w.id===b.to),k=v.columns.find(w=>w.id===b.from);if(!f){m(e,400,{error:`unknown 'to' column: ${b.to}`});return}try{await Pt(y,h,k,f),V({actor:Y(t),action:"move",boardId:i,itemId:h,payload:{from:b.from,to:b.to}}),m(e,200,{ok:!0})}catch(w){m(e,502,{error:w.message||"transition failed"})}return}if(u){let[,i,p]=u,h=p?decodeURIComponent(p):void 0,v=a.boards.find(b=>b.id===i);if(!v){m(e,404,{error:`unknown board: ${i}`});return}let y=a.sources.get(i);if(!y){m(e,503,{error:`board "${i}" source unavailable`});return}if(r==="GET"&&!h){let{columns:b,totals:f}=await Dt(v,y,n.searchParams);m(e,200,{columns:b,totals:f});return}if(r==="GET"&&h){try{let b=typeof y.getItem=="function"?await y.getItem(h):null;if(!b){m(e,404,{error:"not found"});return}m(e,200,b)}catch(b){m(e,502,{error:b.message})}return}if(r==="PATCH"&&h){let b=await H(t);try{let f=typeof y.updateItem=="function"?await y.updateItem(h,b):null;if(!f){m(e,501,{error:"update unsupported"});return}V({actor:Y(t),action:"update",boardId:i,itemId:h,payload:b}),m(e,200,f)}catch(f){m(e,502,{error:f.message})}return}if(r==="POST"&&!h){let b=await H(t);if(!b.title){m(e,400,{error:"title required"});return}if(!y.capabilities.create||!y.create){m(e,400,{error:`source ${y.type} does not support create`});return}try{let f=await y.create({title:b.title,description:b.description,labels:b.labels,assigneeUsernames:b.assigneeUsernames,milestoneTitle:b.milestoneTitle,projectHint:b.projectHint});V({actor:Y(t),action:"create",boardId:i,itemId:f.id,payload:{title:b.title}}),m(e,201,f)}catch(f){m(e,502,{error:f.message})}return}}m(e,404,{error:"not found",path:o})}async function Dt(t,e,a){if(!e.capabilities.listAll||!e.listAll){let f={};for(let k of t.columns)f[k.id]=[];return{columns:f,totals:Object.fromEntries(t.columns.map(k=>[k.id,0]))}}let n=[];t.primaryToolLabel&&n.push(t.primaryToolLabel);let o=a.get("label")||void 0;o&&n.push(o);let r=a.get("q")||void 0,s=a.get("milestone")||void 0,l=a.get("assignee")||void 0,c=parseInt(a.get("days")||String(t.timeRangeDays),10),d=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),g=t.columns.some(f=>f.kind!=="closed"),u=t.columns.some(f=>f.kind==="closed"),i=g?await e.listAll({sinceDays:c,labels:n.length?n:void 0,search:r,milestone:s,state:"opened"}):[],p=u?await e.listAll({sinceDays:d,labels:n.length?n:void 0,search:r,milestone:s,state:"closed"}):[],h={};for(let f of t.columns)h[f.id]=[];let v=t.columns.find(f=>f.kind==="closed");for(let f of p)v&&h[v.id].push({...f,stage:v.id});let y=t.columns.filter(f=>f.kind!=="closed");for(let f of i){let k=te(f,y);if(!k)continue;let w=h[k];w&&w.push({...f,stage:k})}if(l)for(let f of Object.keys(h))h[f]=h[f].filter(k=>k.assignee===l);for(let f of Object.keys(h))h[f].sort((k,w)=>{let Z=(k.priority??99)-(w.priority??99);return Z!==0?Z:(w.updatedAt||"").localeCompare(k.updatedAt||"")});let b=Object.fromEntries(Object.entries(h).map(([f,k])=>[f,k.length]));return{columns:h,totals:b}}async function Pt(t,e,a,n){let o=ae(a,n),r=t;o.closeIssue&&typeof r.setState=="function"?await r.setState(e,"close"):o.reopen&&typeof r.setState=="function"&&await r.setState(e,"reopen"),(o.addLabels?.length||o.removeLabels?.length)&&typeof r.transitionMany=="function"?await r.transitionMany(e,o.addLabels||[],o.removeLabels||[]):o.addLabels?.length&&t.transition&&await t.transition(e,o.addLabels[0],o.removeLabels?.[0])}function Ot(t,e){if(t.source.type==="gitlab"){let a=e.channels.gitlab;if(!a?.token)throw new Error("channels.gitlab.token is required for gitlab boards");let n={};for(let o of a.agentMappings)o.gitlabUsernames.length&&(n[o.agentId]=o.gitlabUsernames);return new oe(a.host,a.token,t.source.projects,n,(...o)=>console.log("[board]",...o))}throw new Error(`unsupported board source: ${t.source.type}`)}function V(t){try{let e=Ie(process.cwd(),".agentx");$t(e)||It(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
1966
- `;Mt(Ie(e,"board-audit.jsonl"),a)}catch{}}function Y(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}async function Rt(t,e,a){let n={};e&&(n.Authorization=`Bearer ${e}`);let o={id:t,name:t,url:t,reachable:!1,agents:[]};try{let[r,s,l]=await Promise.all([fetch(t+"/health",{headers:n,signal:a}).catch(()=>null),fetch(t+"/agents",{headers:n,signal:a}).catch(()=>null),fetch(t+"/mesh",{headers:n,signal:a}).catch(()=>null)]);if(!s||!s.ok)return o.error=s?`HTTP ${s.status}`:"unreachable",o;let c=await s.json();if(o.agents=c.map(d=>({id:d.id,name:d.name,tier:d.tier,model:d.model,active:d.active||0,total:d.total||0,errors:d.errors||0,lastActive:d.lastActive,lastSummary:d.lastSummary,hourlyTasks:Array.isArray(d.hourlyTasks)?d.hourlyTasks:void 0,runningTasks:Array.isArray(d.runningTasks)?d.runningTasks:[]})),r&&r.ok){let d=await r.json();o.uptimeSec=d.uptime,o.name=d.node?.name||d.node?.id||t,o.id=d.node?.id||t,d.usage&&(o.usage=d.usage)}o.reachable=!0,o._peers=Array.isArray(l&&await Ht(l))?o._peers:void 0}catch(r){o.error=r.message||String(r)}return o}var J=new WeakMap;async function Ht(t){if(J.has(t))return J.get(t);try{let e=t.ok?await t.json():null;return J.set(t,e),e}catch{return null}}async function Q(t,e,a){try{let n={};e&&(n.Authorization=`Bearer ${e}`);let o=await fetch(t+"/mesh",{headers:n,signal:a});return o.ok?(await o.json()).filter(s=>s&&s.peerUrl).map(s=>({url:String(s.peerUrl).replace(/\/+$/,""),name:s.peer||s.peerUrl})):[]}catch{return[]}}async function De(t){let e=t.dashboard,a=e.daemonUrl.replace(/\/+$/,""),n=e.token,o=new Map;o.set(a,{name:"primary",url:a,token:n});for(let l of e.daemons){let c=l.url.replace(/\/+$/,"");o.has(c)||o.set(c,{name:l.name,url:c,token:l.token})}let r=new AbortController,s=setTimeout(()=>r.abort(),3e3);try{let l=await Q(a,n,r.signal);for(let d of l)o.has(d.url)||o.set(d.url,d);let c=await Promise.all([...o.values()].map(d=>Rt(d.url,d.token,r.signal)));return{ts:new Date().toISOString(),nodes:c}}finally{clearTimeout(s)}}function Bt(t,e,a){e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"});let n=!1,o=(l,c)=>{n||e.write(`event: ${l}
1967
- data: ${JSON.stringify(c)}
3066
+ Kanban dashboard: http://${l}:${n}
3067
+ `),console.log(` Boards: ${a.map(c=>c.id).join(", ")}`)),o==="127.0.0.1"&&!r?console.log(" (bound to localhost; no auth token \u2014 safe default)"):o!=="127.0.0.1"&&!r&&console.log(" \u26A0 bound to a non-loopback address without a token \u2014 writes are UNAUTHENTICATED")})}async function Ha(t,e,a){let n=new URL(t.url||"/","http://localhost"),o=n.pathname,r=(t.method||"GET").toUpperCase();if(e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, PATCH, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization, X-Requested-With"),r==="OPTIONS"){e.writeHead(204),e.end();return}if(r==="GET"&&o==="/"){let d=Ae();if(!d.configExists||d.agentCount===0){e.writeHead(302,{Location:"/setup"}),e.end();return}let p=a.boards.length===0?nt(a.config):Ja(a.config);e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(p);return}if(r==="GET"&&o==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(nt(a.config));return}if(r==="GET"&&o==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Za(a.config));return}if(r==="GET"&&o==="/setup"){Ce(t,e);return}if(r==="POST"&&o==="/api/setup"){await $e(t,e);return}if(r==="GET"&&o==="/admin"){Be(t,e,j(a.config),a.token);return}if(r==="GET"&&o==="/admin/graph"){We(t,e,j(a.config),a.token);return}let i=r==="GET"&&o.match(/^\/admin\/agents\/([a-z0-9][a-z0-9_-]*)$/);if(i){Je(t,e,i[1],j(a.config),a.token);return}if(o.startsWith("/api/admin/")){let d=String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(d&&d!=="primary"){let p=Qa(d,a.config);if(!p){h(e,404,{error:`unknown peer: ${d}`});return}await Ya(t,e,p,o+(n.search||""));return}if(a.token){let p=t.headers.authorization||"",v=p.startsWith("Bearer ")?p.slice(7):"";if(v!==a.token){let k=new O,y=v?k.verify(v):null;if(!y||!W(y,"dashboard:write")){h(e,401,{error:"unauthorized"});return}}}}if(r==="GET"&&o==="/api/admin/config"){await ze(t,e);return}if(o.startsWith("/api/admin/graph/")){await Ke(t,e,o);return}if(o.startsWith("/api/admin/agent/")){await Ye(t,e,o);return}if(o.startsWith("/api/admin/")){await je(t,e,o);return}if(r==="GET"&&o==="/sortable.min.js"){e.writeHead(200,{"Content-Type":"application/javascript; charset=utf-8","Cache-Control":"public, max-age=86400"}),e.end(_e);return}if(r==="GET"&&o==="/api/live"){try{let d=await ot(a.config);h(e,200,d)}catch(d){h(e,502,{error:d.message})}return}if(r==="GET"&&o==="/api/live/stream"){Ua(t,e,a.config);return}if(r==="GET"&&o==="/api/task/stream"){let d=new URL(t.url||"/","http://localhost"),p=d.searchParams.get("node"),v=d.searchParams.get("agent"),k=d.searchParams.get("task");if(!p||!v||!k){h(e,400,{error:"node, agent, task query params required"});return}await Fa(t,e,a,p,v,k);return}if(r==="GET"&&o==="/api/task/history"){let d=new URL(t.url||"/","http://localhost"),p=d.searchParams.get("node"),v=d.searchParams.get("agent"),k=d.searchParams.get("task"),y=d.searchParams.get("limit")||"50";if(!p||!v){h(e,400,{error:"node and agent query params required"});return}await Wa(e,a,p,v,k,y);return}if(r==="GET"&&o==="/api/agents"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let p=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:d});if(!p.ok)throw new Error(`HTTP ${p.status}`);let v=await p.json();h(e,200,v)}catch(d){h(e,502,{error:d.message||"agents fetch failed"})}return}if(r==="POST"&&o==="/api/draft"){let d=await q(t);try{let p=await Xa(a.config,d);h(e,200,p)}catch(p){h(e,502,{error:p.message||"draft failed"})}return}let s=o.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(s&&r==="POST"){let d=s[1];if(!qa(t,e,[`agent:${d}`]))return;await Ga(t,e,a.config,d);return}if(o.startsWith("/api/")&&a.token){let d=t.headers.authorization||"",p=d.startsWith("Bearer ")?d.slice(7):"";if(p!==a.token){let v=new O,k=p?v.verify(p):null;if(!k||!W(k,"dashboard:write")){h(e,401,{error:"unauthorized"});return}}}if((r==="POST"||r==="PATCH"||r==="DELETE")&&o.startsWith("/api/")&&t.headers["x-requested-with"]!=="agentx-board"){h(e,400,{error:"missing X-Requested-With: agentx-board"});return}if(r==="GET"&&o==="/api/boards"){h(e,200,a.boards.map(d=>({id:d.id,name:d.name,source:d.source,primaryToolLabel:d.primaryToolLabel,labels:d.labels,columns:d.columns,timeRangeDays:d.timeRangeDays})));return}let c=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/members$/);if(c&&r==="GET"){let d=a.sources.get(c[1]);if(!d){h(e,404,{error:"unknown board"});return}try{let p=typeof d.listMembers=="function"?await d.listMembers():[];h(e,200,p)}catch(p){h(e,502,{error:p.message})}return}let m=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(m&&r==="GET"){let d=a.sources.get(m[1]);if(!d){h(e,404,{error:"unknown board"});return}try{let p=typeof d.listMilestones=="function"?await d.listMilestones():[];h(e,200,p)}catch(p){h(e,502,{error:p.message})}return}let u=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),f=o.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(u&&r==="PATCH"){let[,d,p]=u,v=decodeURIComponent(p),k=a.boards.find(T=>T.id===d);if(!k){h(e,404,{error:`unknown board: ${d}`});return}let y=a.sources.get(d);if(!y){h(e,503,{error:`board "${d}" source unavailable`});return}let g=await q(t),b=k.columns.find(T=>T.id===g.to),H=k.columns.find(T=>T.id===g.from);if(!b){h(e,400,{error:`unknown 'to' column: ${g.to}`});return}try{await Na(y,v,H,b),fe({actor:ve(t),action:"move",boardId:d,itemId:v,payload:{from:g.from,to:g.to}}),h(e,200,{ok:!0})}catch(T){h(e,502,{error:T.message||"transition failed"})}return}if(f){let[,d,p]=f,v=p?decodeURIComponent(p):void 0,k=a.boards.find(g=>g.id===d);if(!k){h(e,404,{error:`unknown board: ${d}`});return}let y=a.sources.get(d);if(!y){h(e,503,{error:`board "${d}" source unavailable`});return}if(r==="GET"&&!v){let{columns:g,totals:b}=await Ra(k,y,n.searchParams);h(e,200,{columns:g,totals:b});return}if(r==="GET"&&v){try{let g=typeof y.getItem=="function"?await y.getItem(v):null;if(!g){h(e,404,{error:"not found"});return}h(e,200,g)}catch(g){h(e,502,{error:g.message})}return}if(r==="PATCH"&&v){let g=await q(t);try{let b=typeof y.updateItem=="function"?await y.updateItem(v,g):null;if(!b){h(e,501,{error:"update unsupported"});return}fe({actor:ve(t),action:"update",boardId:d,itemId:v,payload:g}),h(e,200,b)}catch(b){h(e,502,{error:b.message})}return}if(r==="POST"&&!v){let g=await q(t);if(!g.title){h(e,400,{error:"title required"});return}if(!y.capabilities.create||!y.create){h(e,400,{error:`source ${y.type} does not support create`});return}try{let b=await y.create({title:g.title,description:g.description,labels:g.labels,assigneeUsernames:g.assigneeUsernames,milestoneTitle:g.milestoneTitle,projectHint:g.projectHint});fe({actor:ve(t),action:"create",boardId:d,itemId:b.id,payload:{title:g.title}}),h(e,201,b)}catch(b){h(e,502,{error:b.message})}return}}h(e,404,{error:"not found",path:o})}async function Ra(t,e,a){if(!e.capabilities.listAll||!e.listAll){let g={};for(let b of t.columns)g[b.id]=[];return{columns:g,totals:Object.fromEntries(t.columns.map(b=>[b.id,0]))}}let n=[];t.primaryToolLabel&&n.push(t.primaryToolLabel);let o=a.get("label")||void 0;o&&n.push(o);let r=a.get("q")||void 0,i=a.get("milestone")||void 0,s=a.get("assignee")||void 0,l=parseInt(a.get("days")||String(t.timeRangeDays),10),c=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),m=t.columns.some(g=>g.kind!=="closed"),u=t.columns.some(g=>g.kind==="closed"),f=m?await e.listAll({sinceDays:l,labels:n.length?n:void 0,search:r,milestone:i,state:"opened"}):[],d=u?await e.listAll({sinceDays:c,labels:n.length?n:void 0,search:r,milestone:i,state:"closed"}):[],p={};for(let g of t.columns)p[g.id]=[];let v=t.columns.find(g=>g.kind==="closed");for(let g of d)v&&p[v.id].push({...g,stage:v.id});let k=t.columns.filter(g=>g.kind!=="closed");for(let g of f){let b=Ee(g,k);if(!b)continue;let H=p[b];H&&H.push({...g,stage:b})}if(s)for(let g of Object.keys(p))p[g]=p[g].filter(b=>b.assignee===s);for(let g of Object.keys(p))p[g].sort((b,H)=>{let T=(b.priority??99)-(H.priority??99);return T!==0?T:(H.updatedAt||"").localeCompare(b.updatedAt||"")});let y=Object.fromEntries(Object.entries(p).map(([g,b])=>[g,b.length]));return{columns:p,totals:y}}async function Na(t,e,a,n){let o=Se(a,n),r=t;o.closeIssue&&typeof r.setState=="function"?await r.setState(e,"close"):o.reopen&&typeof r.setState=="function"&&await r.setState(e,"reopen"),(o.addLabels?.length||o.removeLabels?.length)&&typeof r.transitionMany=="function"?await r.transitionMany(e,o.addLabels||[],o.removeLabels||[]):o.addLabels?.length&&t.transition&&await t.transition(e,o.addLabels[0],o.removeLabels?.[0])}function Ba(t,e){if(t.source.type==="gitlab"){let a=e.channels.gitlab;if(!a?.token)throw new Error("channels.gitlab.token is required for gitlab boards");let n={};for(let o of a.agentMappings)o.gitlabUsernames.length&&(n[o.agentId]=o.gitlabUsernames);return new Te(a.host,a.token,t.source.projects,n,(...o)=>console.log("[board]",...o))}throw new Error(`unsupported board source: ${t.source.type}`)}function fe(t){try{let e=at(process.cwd(),".agentx");Pa(e)||Oa(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
3068
+ `;Da(at(e,"board-audit.jsonl"),a)}catch{}}function ve(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}async function za(t,e,a){let n={};e&&(n.Authorization=`Bearer ${e}`);let o={id:t,name:t,url:t,reachable:!1,agents:[]};try{let[r,i,s]=await Promise.all([fetch(t+"/health",{headers:n,signal:a}).catch(()=>null),fetch(t+"/agents",{headers:n,signal:a}).catch(()=>null),fetch(t+"/mesh",{headers:n,signal:a}).catch(()=>null)]);if(!i||!i.ok)return o.error=i?`HTTP ${i.status}`:"unreachable",o;let l=await i.json();if(o.agents=l.map(c=>({id:c.id,name:c.name,tier:c.tier,model:c.model,active:c.active||0,total:c.total||0,errors:c.errors||0,lastActive:c.lastActive,lastSummary:c.lastSummary,hourlyTasks:Array.isArray(c.hourlyTasks)?c.hourlyTasks:void 0,runningTasks:Array.isArray(c.runningTasks)?c.runningTasks:[]})),r&&r.ok){let c=await r.json();o.uptimeSec=c.uptime,o.name=c.node?.name||c.node?.id||t,o.id=c.node?.id||t,c.usage&&(o.usage=c.usage)}o.reachable=!0,o._peers=Array.isArray(s&&await ja(s))?o._peers:void 0}catch(r){o.error=r.message||String(r)}return o}var be=new WeakMap;async function ja(t){if(be.has(t))return be.get(t);try{let e=t.ok?await t.json():null;return be.set(t,e),e}catch{return null}}async function xe(t,e,a){try{let n={};e&&(n.Authorization=`Bearer ${e}`);let o=await fetch(t+"/mesh",{headers:n,signal:a});return o.ok?(await o.json()).filter(i=>i&&i.peerUrl).map(i=>({url:String(i.peerUrl).replace(/\/+$/,""),name:i.peer||i.peerUrl})):[]}catch{return[]}}async function ot(t){let e=t.dashboard,a=e.daemonUrl.replace(/\/+$/,""),n=e.token,o=new Map;o.set(a,{name:"primary",url:a,token:n});for(let s of e.daemons){let l=s.url.replace(/\/+$/,"");o.has(l)||o.set(l,{name:s.name,url:l,token:s.token})}let r=new AbortController,i=setTimeout(()=>r.abort(),3e3);try{let s=await xe(a,n,r.signal);for(let c of s)o.has(c.url)||o.set(c.url,c);let l=await Promise.all([...o.values()].map(c=>za(c.url,c.token,r.signal)));return{ts:new Date().toISOString(),nodes:l}}finally{clearTimeout(i)}}function Ua(t,e,a){e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"});let n=!1,o=(s,l)=>{n||e.write(`event: ${s}
3069
+ data: ${JSON.stringify(l)}
1968
3070
 
1969
- `)},r=async()=>{try{let l=await De(a);o("snapshot",l)}catch(l){o("error",{message:l.message})}};r();let s=setInterval(r,2e3);t.on("close",()=>{n=!0,clearInterval(s),e.end()})}async function Nt(t,e,a,n,o,r){let s=n.replace(/\/+$/,""),l=new Set;l.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let h of a.config.dashboard.daemons)l.add(h.url.replace(/\/+$/,""));try{let h=await Q(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let v of h)l.add(v.url.replace(/\/+$/,""))}catch{}if(!l.has(s)){m(e,403,{error:"node not in dashboard allowlist",target:s});return}let c=s===a.config.dashboard.daemonUrl.replace(/\/+$/,"")?a.config.dashboard.token:a.config.dashboard.daemons.find(h=>h.url.replace(/\/+$/,"")===s)?.token,d={Accept:"text/event-stream"};c&&(d.Authorization=`Bearer ${c}`);let g=new AbortController,u;try{u=await fetch(`${s}/agents/${encodeURIComponent(o)}/tasks/${encodeURIComponent(r)}/stream`,{headers:d,signal:g.signal})}catch(h){m(e,502,{error:h.message||"upstream connect failed"});return}if(!u.ok||!u.body){m(e,u.status||502,{error:`upstream HTTP ${u.status}`});return}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*","X-Accel-Buffering":"no"});let i=u.body.getReader();(async()=>{try{for(;;){let{value:h,done:v}=await i.read();if(v)break;h&&e.write(h)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{g.abort();try{e.end()}catch{}})}function zt(t,e,a){let n=le(t);if(!n)return m(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let o=new T().verify(n);if(!o)return m(e,401,{error:"invalid or revoked token"}),null;for(let r of a)if(!B(o,r))return m(e,403,{error:`token missing scope: ${r}`,scopes:o.scopes}),null;return o}async function Ut(t,e,a,n){let o=a.agents?.[n];if(!o){m(e,404,{error:"unknown agent"});return}if(o.access!=="public"){m(e,403,{error:"agent is private",hint:`set agents.${n}.access = "public" to expose it`});return}let r;try{r=await H(t)}catch{m(e,400,{error:"invalid JSON body"});return}let s=r?.message;if(!s||typeof s!="string"){m(e,400,{error:"required: { message: string, context?: {...} }"});return}let l=a.dashboard.daemonUrl.replace(/\/+$/,""),c={"Content-Type":"application/json"};a.dashboard.token&&(c.Authorization=`Bearer ${a.dashboard.token}`);try{let d=await fetch(`${l}/task`,{method:"POST",headers:c,body:JSON.stringify({agent:n,message:s,context:{channel:"public-api",sender:r.context?.sender||"api",...r.context||{}}})}),g=await d.text();e.writeHead(d.status,{"Content-Type":d.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),e.end(g)}catch(d){m(e,502,{error:d.message||"upstream call failed"})}}async function Ft(t,e,a,n,o,r){let s=a.replace(/\/+$/,""),l=new Set;l.add(e.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let u of e.config.dashboard.daemons)l.add(u.url.replace(/\/+$/,""));try{let u=await Q(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let i of u)l.add(i.url.replace(/\/+$/,""))}catch{}if(!l.has(s)){m(t,403,{error:"node not in dashboard allowlist",target:s});return}let c=s===e.config.dashboard.daemonUrl.replace(/\/+$/,"")?e.config.dashboard.token:e.config.dashboard.daemons.find(u=>u.url.replace(/\/+$/,"")===s)?.token,d={Accept:"application/json"};c&&(d.Authorization=`Bearer ${c}`);let g=o?`/agents/${encodeURIComponent(n)}/tasks/${encodeURIComponent(o)}`:`/agents/${encodeURIComponent(n)}/tasks?limit=${encodeURIComponent(r)}`;try{let u=await fetch(`${s}${g}`,{headers:d}),i=await u.text();t.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),t.end(i)}catch(u){m(t,502,{error:u.message||"upstream fetch failed"})}}var jt=`
3071
+ `)},r=async()=>{try{let s=await ot(a);o("snapshot",s)}catch(s){o("error",{message:s.message})}};r();let i=setInterval(r,2e3);t.on("close",()=>{n=!0,clearInterval(i),e.end()})}async function Fa(t,e,a,n,o,r){let i=n.replace(/\/+$/,""),s=new Set;s.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let p of a.config.dashboard.daemons)s.add(p.url.replace(/\/+$/,""));try{let p=await xe(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let v of p)s.add(v.url.replace(/\/+$/,""))}catch{}if(!s.has(i)){h(e,403,{error:"node not in dashboard allowlist",target:i});return}let l=i===a.config.dashboard.daemonUrl.replace(/\/+$/,"")?a.config.dashboard.token:a.config.dashboard.daemons.find(p=>p.url.replace(/\/+$/,"")===i)?.token,c={Accept:"text/event-stream"};l&&(c.Authorization=`Bearer ${l}`);let m=new AbortController,u;try{u=await fetch(`${i}/agents/${encodeURIComponent(o)}/tasks/${encodeURIComponent(r)}/stream`,{headers:c,signal:m.signal})}catch(p){h(e,502,{error:p.message||"upstream connect failed"});return}if(!u.ok||!u.body){h(e,u.status||502,{error:`upstream HTTP ${u.status}`});return}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*","X-Accel-Buffering":"no"});let f=u.body.getReader();(async()=>{try{for(;;){let{value:p,done:v}=await f.read();if(v)break;p&&e.write(p)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{m.abort();try{e.end()}catch{}})}function qa(t,e,a){let n=Me(t);if(!n)return h(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let o=new O().verify(n);if(!o)return h(e,401,{error:"invalid or revoked token"}),null;for(let r of a)if(!W(o,r))return h(e,403,{error:`token missing scope: ${r}`,scopes:o.scopes}),null;return o}async function Ga(t,e,a,n){let o=a.agents?.[n];if(!o){h(e,404,{error:"unknown agent"});return}if(o.access!=="public"){h(e,403,{error:"agent is private",hint:`set agents.${n}.access = "public" to expose it`});return}let r;try{r=await q(t)}catch{h(e,400,{error:"invalid JSON body"});return}let i=r?.message;if(!i||typeof i!="string"){h(e,400,{error:"required: { message: string, context?: {...} }"});return}let s=a.dashboard.daemonUrl.replace(/\/+$/,""),l={"Content-Type":"application/json"};a.dashboard.token&&(l.Authorization=`Bearer ${a.dashboard.token}`);try{let c=await fetch(`${s}/task`,{method:"POST",headers:l,body:JSON.stringify({agent:n,message:i,context:{channel:"public-api",sender:r.context?.sender||"api",...r.context||{}}})}),m=await c.text();e.writeHead(c.status,{"Content-Type":c.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),e.end(m)}catch(c){h(e,502,{error:c.message||"upstream call failed"})}}async function Wa(t,e,a,n,o,r){let i=a.replace(/\/+$/,""),s=new Set;s.add(e.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let u of e.config.dashboard.daemons)s.add(u.url.replace(/\/+$/,""));try{let u=await xe(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let f of u)s.add(f.url.replace(/\/+$/,""))}catch{}if(!s.has(i)){h(t,403,{error:"node not in dashboard allowlist",target:i});return}let l=i===e.config.dashboard.daemonUrl.replace(/\/+$/,"")?e.config.dashboard.token:e.config.dashboard.daemons.find(u=>u.url.replace(/\/+$/,"")===i)?.token,c={Accept:"application/json"};l&&(c.Authorization=`Bearer ${l}`);let m=o?`/agents/${encodeURIComponent(n)}/tasks/${encodeURIComponent(o)}`:`/agents/${encodeURIComponent(n)}/tasks?limit=${encodeURIComponent(r)}`;try{let u=await fetch(`${i}${m}`,{headers:c}),f=await u.text();t.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),t.end(f)}catch(u){h(t,502,{error:u.message||"upstream fetch failed"})}}var Ka=`
1970
3072
  You are helping draft a new GitLab issue. Follow these conventions strictly.
1971
3073
 
1972
3074
  Title pattern:
@@ -1998,10 +3100,10 @@ Return ONLY a single JSON object on one line \u2014 no prose, no code fences, no
1998
3100
  Shape:
1999
3101
  { "title": string, "description": string, "labels": string[], "assigneeUsername": string | null, "kind": string }
2000
3102
  If you don't have enough information to pick a label confidently, omit it rather than guessing.
2001
- `;async function qt(t,e){let a=(e?.rough||"").toString().trim();if(!a)throw new Error("rough description required");let n=e?.agent||t.dashboard.draftAgent;if(!n)throw new Error("no draft agent configured (set dashboard.draftAgent or pass agent in body)");let o=e?.context||{},r=["Rough description from the user:",'"""',a,'"""',"",`Board: ${o.boardName||"(unspecified)"}`,o.primaryLabel?`Primary board label (include in labels): ${o.primaryLabel}`:"",o.columnLabel?`Target column label (include in labels): ${o.columnLabel}`:"",o.project?`GitLab project: ${o.project}`:"",o.knownLabels?.length?`Known labels in this project (prefer picking from these when they fit):
3103
+ `;async function Xa(t,e){let a=(e?.rough||"").toString().trim();if(!a)throw new Error("rough description required");let n=e?.agent||t.dashboard.draftAgent;if(!n)throw new Error("no draft agent configured (set dashboard.draftAgent or pass agent in body)");let o=e?.context||{},r=["Rough description from the user:",'"""',a,'"""',"",`Board: ${o.boardName||"(unspecified)"}`,o.primaryLabel?`Primary board label (include in labels): ${o.primaryLabel}`:"",o.columnLabel?`Target column label (include in labels): ${o.columnLabel}`:"",o.project?`GitLab project: ${o.project}`:"",o.knownLabels?.length?`Known labels in this project (prefer picking from these when they fit):
2002
3104
  - ${o.knownLabels.slice(0,60).join(`
2003
3105
  - `)}`:"",o.members?.length?`Possible assignees (GitLab usernames): ${o.members.slice(0,20).join(", ")}`:"","","Produce the JSON draft now."].filter(Boolean).join(`
2004
- `),s=t.dashboard.daemonUrl.replace(/\/+$/,"")+"/task",l={"Content-Type":"application/json"};t.dashboard.token&&(l.Authorization=`Bearer ${t.dashboard.token}`);let c=await fetch(s,{method:"POST",headers:l,body:JSON.stringify({agent:n,message:r,context:{channel:"a2a",sender:"board-dashboard",systemPrompt:jt}})});if(!c.ok)throw new Error(`daemon /task HTTP ${c.status}: ${await c.text().catch(()=>"")}`);let d=await c.json();if(d.error)throw new Error(String(d.error));let g=(d.content||"").toString(),u=Wt(g);if(!u||typeof u.title!="string")throw new Error("agent did not return a valid JSON draft. Raw: "+g.slice(0,400));let i=Array.isArray(u.labels)?u.labels.filter(p=>typeof p=="string"):[];return o.primaryLabel&&!i.includes(o.primaryLabel)&&i.unshift(o.primaryLabel),o.columnLabel&&!i.includes(o.columnLabel)&&i.unshift(o.columnLabel),{title:u.title.trim(),description:(u.description||"").toString(),labels:i,assigneeUsername:typeof u.assigneeUsername=="string"?u.assigneeUsername:void 0,kind:typeof u.kind=="string"?u.kind:void 0,raw:g}}function Wt(t){if(!t)return null;try{return JSON.parse(t)}catch{}let e=t.match(/```(?:json)?\s*([\s\S]*?)```/);if(e)try{return JSON.parse(e[1])}catch{}let a=t.indexOf("{");if(a===-1)return null;let n=0;for(let o=a;o<t.length;o++){let r=t[o];if(r==="{")n++;else if(r==="}"&&(n--,n===0))try{return JSON.parse(t.slice(a,o+1))}catch{return null}}return null}function m(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function H(t){return new Promise((e,a)=>{let n=[];t.on("data",o=>n.push(o)),t.on("end",()=>{try{let o=Buffer.concat(n).toString("utf-8");e(o?JSON.parse(o):{})}catch(o){a(o)}}),t.on("error",a)})}function Gt(t){let n=D({activeTab:"boards",subtitle:"Boards",subheader:`
3106
+ `),i=t.dashboard.daemonUrl.replace(/\/+$/,"")+"/task",s={"Content-Type":"application/json"};t.dashboard.token&&(s.Authorization=`Bearer ${t.dashboard.token}`);let l=await fetch(i,{method:"POST",headers:s,body:JSON.stringify({agent:n,message:r,context:{channel:"a2a",sender:"board-dashboard",systemPrompt:Ka}})});if(!l.ok)throw new Error(`daemon /task HTTP ${l.status}: ${await l.text().catch(()=>"")}`);let c=await l.json();if(c.error)throw new Error(String(c.error));let m=(c.content||"").toString(),u=Va(m);if(!u||typeof u.title!="string")throw new Error("agent did not return a valid JSON draft. Raw: "+m.slice(0,400));let f=Array.isArray(u.labels)?u.labels.filter(d=>typeof d=="string"):[];return o.primaryLabel&&!f.includes(o.primaryLabel)&&f.unshift(o.primaryLabel),o.columnLabel&&!f.includes(o.columnLabel)&&f.unshift(o.columnLabel),{title:u.title.trim(),description:(u.description||"").toString(),labels:f,assigneeUsername:typeof u.assigneeUsername=="string"?u.assigneeUsername:void 0,kind:typeof u.kind=="string"?u.kind:void 0,raw:m}}function Va(t){if(!t)return null;try{return JSON.parse(t)}catch{}let e=t.match(/```(?:json)?\s*([\s\S]*?)```/);if(e)try{return JSON.parse(e[1])}catch{}let a=t.indexOf("{");if(a===-1)return null;let n=0;for(let o=a;o<t.length;o++){let r=t[o];if(r==="{")n++;else if(r==="}"&&(n--,n===0))try{return JSON.parse(t.slice(a,o+1))}catch{return null}}return null}function h(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function q(t){return new Promise((e,a)=>{let n=[];t.on("data",o=>n.push(o)),t.on("end",()=>{try{let o=Buffer.concat(n).toString("utf-8");e(o?JSON.parse(o):{})}catch(o){a(o)}}),t.on("error",a)})}function Ja(t){let n=I({activeTab:"boards",subtitle:"Boards",subheader:`
2005
3107
  <select id="boardPicker" title="Switch board"></select>
2006
3108
  <div class="search">
2007
3109
  <span class="icon">\u2315</span>
@@ -2013,15 +3115,15 @@ If you don't have enough information to pick a label confidently, omit it rather
2013
3115
  <div class="spacer"></div>
2014
3116
  <button id="activityBtn" title="Agent activity (a)">\u25C9 Activity</button>
2015
3117
  <button id="newIssueBtn" title="New issue">+ New</button>
2016
- <button id="refreshBtn" title="Refresh (r)">\u21BB</button>`,rightExtras:'<div id="conn" class="conn ok" title="ready">\u25CF</div>',peers:z(t)});return`<!DOCTYPE html>
3118
+ <button id="refreshBtn" title="Refresh (r)">\u21BB</button>`,rightExtras:'<div id="conn" class="conn ok" title="ready">\u25CF</div>',peers:j(t)});return`<!DOCTYPE html>
2017
3119
  <html lang="en" data-theme="dark">
2018
3120
  <head>
2019
3121
  <meta charset="utf-8">
2020
3122
  <meta name="viewport" content="width=device-width, initial-scale=1">
2021
3123
  <title>AgentX \xB7 Boards</title>
2022
3124
  ${$}
2023
- <style>${Qt}
2024
- ${I}</style>
3125
+ <style>${an}
3126
+ ${M}</style>
2025
3127
  </head>
2026
3128
  <body>
2027
3129
  ${n}
@@ -2115,20 +3217,20 @@ ${n}
2115
3217
  </div>
2116
3218
  </div>
2117
3219
  <script src="/sortable.min.js"></script>
2118
- <script>${Zt}</script>
2119
- ${L}
3220
+ <script>${nn}</script>
3221
+ ${_}
2120
3222
  </body>
2121
- </html>`}function Le(t){let e=`<script>window.UI_LABELS = ${JSON.stringify(E)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
3223
+ </html>`}function nt(t){let e=`<script>window.UI_LABELS = ${JSON.stringify(L)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
2122
3224
  <span id="conn-dot" class="ax-dot ax-dot--ok ax-dot--pulse" title="connected"></span>
2123
- <span id="conn-label">live</span>`,n=D({activeTab:"live",subtitle:E.subtitle,rightExtras:a,peers:z(t)});return`<!DOCTYPE html>
3225
+ <span id="conn-label">live</span>`,n=I({activeTab:"live",subtitle:L.subtitle,rightExtras:a,peers:j(t)});return`<!DOCTYPE html>
2124
3226
  <html lang="en" data-theme="dark" data-density="normal">
2125
3227
  <head>
2126
3228
  <meta charset="utf-8">
2127
3229
  <meta name="viewport" content="width=device-width, initial-scale=1">
2128
- <title>${S(E.brand)} \xB7 ${S(E.subtitle)}</title>
3230
+ <title>${P(L.brand)} \xB7 ${P(L.subtitle)}</title>
2129
3231
  ${$}
2130
- <style>${I}
2131
- ${Yt}</style>
3232
+ <style>${M}
3233
+ ${en}</style>
2132
3234
  </head>
2133
3235
  <body>
2134
3236
  <div class="ax-app">
@@ -2138,7 +3240,7 @@ ${Yt}</style>
2138
3240
  </div>
2139
3241
  <aside id="history-panel" class="history-panel hidden" aria-hidden="true">
2140
3242
  <header>
2141
- <h2 id="history-panel-title">${S(E.historyPanelTitle)}</h2>
3243
+ <h2 id="history-panel-title">${P(L.historyPanelTitle)}</h2>
2142
3244
  <span class="history-panel-source" id="history-panel-source"></span>
2143
3245
  <button class="history-panel-close" id="history-panel-close" aria-label="Close">\xD7</button>
2144
3246
  </header>
@@ -2149,23 +3251,23 @@ ${Yt}</style>
2149
3251
  <div class="task-modal-card" role="dialog" aria-modal="true">
2150
3252
  <header>
2151
3253
  <span class="task-modal-channel" id="task-modal-channel"></span>
2152
- <h2 id="task-modal-title">${S(E.taskModalTitle)}</h2>
2153
- <span class="task-modal-status" id="task-modal-status">${S(E.taskModalConnecting)}</span>
3254
+ <h2 id="task-modal-title">${P(L.taskModalTitle)}</h2>
3255
+ <span class="task-modal-status" id="task-modal-status">${P(L.taskModalConnecting)}</span>
2154
3256
  <button class="task-modal-close" id="task-modal-close" aria-label="Close">\xD7</button>
2155
3257
  </header>
2156
3258
  <div id="task-modal-output" class="task-modal-output"></div>
2157
3259
  </div>
2158
3260
  </div>
2159
3261
  ${e}
2160
- ${L}
2161
- <script>${Jt}</script>
3262
+ ${_}
3263
+ <script>${tn}</script>
2162
3264
  </body>
2163
- </html>`}function S(t){return String(t).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function Pe(t){return t.dashboardUrl?t.dashboardUrl.replace(/\/+$/,""):t.url.replace(/\/+$/,"").replace(/:(?:1[89][89]00|18810)$/,":4202")}function z(t,e){let a=e||t,n={id:"primary",name:a.node?.name||"this daemon",dashboardUrl:"",primary:!0},o=(a.dashboard?.daemons||[]).map(r=>({id:r.url.replace(/\/+$/,""),name:r.name,dashboardUrl:Pe(r),tokenScope:r.dashboardToken||r.token?"proxy-ready":void 0}));return[n,...o]}async function Kt(t,e,a,n){let o=a.url+n,r=(t.method||"GET").toUpperCase(),l=r!=="GET"&&r!=="HEAD"?await new Promise((u,i)=>{let p=[];t.on("data",h=>p.push(h)),t.on("end",()=>u(Buffer.concat(p))),t.on("error",i)}):void 0,c={},d=t.headers["content-type"];d&&(c["Content-Type"]=Array.isArray(d)?d[0]:d);let g=t.headers["x-requested-with"];g&&(c["X-Requested-With"]=Array.isArray(g)?g[0]:g),a.token&&(c.Authorization=`Bearer ${a.token}`),c["X-Agentx-Peer"]="primary";try{let u=await fetch(o,{method:r,headers:c,body:l&&l.length>0?l:void 0}),i=Buffer.from(await u.arrayBuffer());e.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json","Cache-Control":"no-store","Access-Control-Allow-Origin":"*"}),e.end(i)}catch(u){m(e,502,{error:`proxy to peer failed: ${u?.message||u}`,target:o})}}function Xt(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(o=>o.url.replace(/\/+$/,"")===a);return n?{url:Pe(n),token:n.dashboardToken||n.token}:null}function Vt(t){let e=de.map(n=>{let o=n.alias?`<span class="alias" title="Schema key">${S(n.alias)}</span>`:"";return`<article class="term"><h3>${S(n.term)}${o}</h3><p>${S(n.definition)}</p></article>`}).join(""),a=D({activeTab:"glossary",subtitle:"Glossary",peers:z(t)});return`<!DOCTYPE html>
3265
+ </html>`}function P(t){return String(t).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function rt(t){return t.dashboardUrl?t.dashboardUrl.replace(/\/+$/,""):t.url.replace(/\/+$/,"").replace(/:(?:1[89][89]00|18810)$/,":4202")}function j(t,e){let a=e||t,n={id:"primary",name:a.node?.name||"this daemon",dashboardUrl:"",primary:!0},o=(a.dashboard?.daemons||[]).map(r=>({id:r.url.replace(/\/+$/,""),name:r.name,dashboardUrl:rt(r),tokenScope:r.dashboardToken||r.token?"proxy-ready":void 0}));return[n,...o]}async function Ya(t,e,a,n){let o=a.url+n,r=(t.method||"GET").toUpperCase(),s=r!=="GET"&&r!=="HEAD"?await new Promise((u,f)=>{let d=[];t.on("data",p=>d.push(p)),t.on("end",()=>u(Buffer.concat(d))),t.on("error",f)}):void 0,l={},c=t.headers["content-type"];c&&(l["Content-Type"]=Array.isArray(c)?c[0]:c);let m=t.headers["x-requested-with"];m&&(l["X-Requested-With"]=Array.isArray(m)?m[0]:m),a.token&&(l.Authorization=`Bearer ${a.token}`),l["X-Agentx-Peer"]="primary";try{let u=await fetch(o,{method:r,headers:l,body:s&&s.length>0?s:void 0}),f=Buffer.from(await u.arrayBuffer());e.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json","Cache-Control":"no-store","Access-Control-Allow-Origin":"*"}),e.end(f)}catch(u){h(e,502,{error:`proxy to peer failed: ${u?.message||u}`,target:o})}}function Qa(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(o=>o.url.replace(/\/+$/,"")===a);return n?{url:rt(n),token:n.dashboardToken||n.token}:null}function Za(t){let e=Ie.map(n=>{let o=n.alias?`<span class="alias" title="Schema key">${P(n.alias)}</span>`:"";return`<article class="term"><h3>${P(n.term)}${o}</h3><p>${P(n.definition)}</p></article>`}).join(""),a=I({activeTab:"glossary",subtitle:"Glossary",peers:j(t)});return`<!DOCTYPE html>
2164
3266
  <html lang="en" data-theme="dark">
2165
3267
  <head>
2166
3268
  <meta charset="utf-8">
2167
3269
  <meta name="viewport" content="width=device-width, initial-scale=1">
2168
- <title>${S(E.brand)} \xB7 Glossary</title>
3270
+ <title>${P(L.brand)} \xB7 Glossary</title>
2169
3271
  ${$}
2170
3272
  <style>
2171
3273
  :root{
@@ -2187,7 +3289,7 @@ ${$}
2187
3289
  --ax-border:#164a30;--ax-border-2:#1f6a44;--ax-text:#b7ffcc;
2188
3290
  --ax-text-2:#83e3a8;--ax-muted:#4f9a73;--ax-accent:#6dff9e;
2189
3291
  --ax-font:"IBM Plex Mono",ui-monospace,monospace}
2190
- ${I}
3292
+ ${M}
2191
3293
  *{box-sizing:border-box}
2192
3294
  html,body{margin:0;min-height:100vh;background:var(--ax-bg);color:var(--ax-text);
2193
3295
  font-family:var(--ax-font);font-size:14px;line-height:1.55;
@@ -2214,9 +3316,9 @@ ${a}
2214
3316
  <p class="lead">What the terms on the dashboard mean. Schema keys (shown in the pill on the right of each term) are what you'd write in <code>agentx.json</code> \u2014 the dashboard just relabels them for readability.</p>
2215
3317
  ${e}
2216
3318
  </main>
2217
- ${L}
3319
+ ${_}
2218
3320
  </body>
2219
- </html>`}var Yt=`
3321
+ </html>`}var en=`
2220
3322
  /* --- Design tokens (ported from /Users/macbookpro/Downloads/agentx-redesign) --- */
2221
3323
  :root {
2222
3324
  --ax-bg: oklch(0.16 0.010 265);
@@ -2337,6 +3439,16 @@ pre, code, .ax-mono { font-family: var(--ax-mono); font-variant-numeric: tabular
2337
3439
  text-transform: uppercase; font-size: 10px; }
2338
3440
  .ax-badge--accent { color: var(--ax-accent);
2339
3441
  border-color: color-mix(in oklch, var(--ax-accent) 50%, transparent); }
3442
+ /* --live modifier: tinted-fill + bold so the "live" pill stands out in
3443
+ * the card header while keeping the original pulsing accent dot visible
3444
+ * (a solid-accent background would swallow the pulse animation). */
3445
+ .ax-badge--live {
3446
+ color: var(--ax-accent);
3447
+ background: color-mix(in oklch, var(--ax-accent) 14%, transparent);
3448
+ border-color: color-mix(in oklch, var(--ax-accent) 60%, transparent);
3449
+ font-weight: 600;
3450
+ letter-spacing: 0.06em;
3451
+ }
2340
3452
  .ax-badge--warn { color: var(--ax-warn);
2341
3453
  border-color: color-mix(in oklch, var(--ax-warn) 50%, transparent); }
2342
3454
  .ax-badge--ghost { color: var(--ax-muted); border-color: var(--ax-border); background: var(--ax-surface-2); }
@@ -2385,9 +3497,32 @@ pre, code, .ax-mono { font-family: var(--ax-mono); font-variant-numeric: tabular
2385
3497
  /* --- Agent cards --- */
2386
3498
  .ax-card { background: var(--ax-surface); border: 1px solid var(--ax-border);
2387
3499
  border-radius: var(--ax-radius); padding: var(--ax-pad); }
2388
- .ax-agent { display: flex; flex-direction: column; gap: 10px; }
2389
- .ax-agent.is-handling { border-color: color-mix(in oklch, var(--ax-accent) 35%, var(--ax-border)); }
2390
- .ax-agent.is-errored { border-color: color-mix(in oklch, var(--ax-err) 35%, var(--ax-border)); }
3500
+ .ax-agent { display: flex; flex-direction: column; gap: 10px;
3501
+ transition: border-color 200ms ease, box-shadow 200ms ease, background 200ms ease; }
3502
+ .ax-agent.is-handling {
3503
+ border-color: color-mix(in oklch, var(--ax-accent) 75%, var(--ax-border));
3504
+ background:
3505
+ linear-gradient(180deg,
3506
+ color-mix(in oklch, var(--ax-accent) 6%, var(--ax-surface)) 0%,
3507
+ var(--ax-surface) 38%);
3508
+ animation: ax-agent-breathe 2.2s ease-in-out infinite;
3509
+ }
3510
+ .ax-agent.is-errored {
3511
+ border-color: color-mix(in oklch, var(--ax-err) 55%, var(--ax-border));
3512
+ box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--ax-err) 25%, transparent);
3513
+ }
3514
+ @keyframes ax-agent-breathe {
3515
+ 0%, 100% {
3516
+ box-shadow:
3517
+ 0 0 0 1px color-mix(in oklch, var(--ax-accent) 45%, transparent),
3518
+ 0 0 20px -6px color-mix(in oklch, var(--ax-accent) 30%, transparent);
3519
+ }
3520
+ 50% {
3521
+ box-shadow:
3522
+ 0 0 0 1px color-mix(in oklch, var(--ax-accent) 70%, transparent),
3523
+ 0 0 32px -2px color-mix(in oklch, var(--ax-accent) 55%, transparent);
3524
+ }
3525
+ }
2391
3526
  .ax-agent__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2392
3527
  .ax-agent__id { display: flex; align-items: baseline; gap: 8px; min-width: 0; flex: 1; }
2393
3528
  .ax-mention { color: var(--ax-accent); font-size: 15px; font-weight: 500;
@@ -2525,7 +3660,7 @@ pre, code, .ax-mono { font-family: var(--ax-mono); font-variant-numeric: tabular
2525
3660
  border-top-color: var(--ax-accent); border-radius: 50%;
2526
3661
  animation: ax-spin 800ms linear infinite; display: inline-block; }
2527
3662
  @keyframes ax-spin { to { transform: rotate(360deg); } }
2528
- `,Jt=`
3663
+ `,tn=`
2529
3664
  'use strict';
2530
3665
 
2531
3666
  const ui = { nodes: new Map(), summary: { nodes: 0, agents: 0, busy: 0, errors: 0 } };
@@ -2664,7 +3799,12 @@ function renderNode(node) {
2664
3799
  function renderAgent(a, node) {
2665
3800
  const card = document.createElement('div');
2666
3801
  const busy = (a.runningTasks && a.runningTasks.length > 0) || (a.active || 0) > 0;
2667
- const errored = (a.errors || 0) > 0;
3802
+ // Error border reflects the MOST RECENT task's status, not the cumulative
3803
+ // error count. A red border drops the moment a new task succeeds \u2014 it should
3804
+ // not persist forever because of a failure an hour ago. The cumulative
3805
+ // a.errors count stays visible in the "failed" ministat below as an
3806
+ // informational value.
3807
+ const errored = a.lastSummary && a.lastSummary.ok === false;
2668
3808
  card.className = 'ax-card ax-agent' + (busy ? ' is-handling' : '') + (errored ? ' is-errored' : '');
2669
3809
  const nodeUrl = (node && node.url) || '';
2670
3810
  const L = window.UI_LABELS || {};
@@ -2677,7 +3817,7 @@ function renderAgent(a, node) {
2677
3817
  const dataAttrs = t.id
2678
3818
  ? ' data-task-id="' + escapeHtml(t.id) + '" data-agent-id="' + escapeHtml(a.id) + '" data-node-url="' + escapeHtml(nodeUrl) + '" data-channel="' + escapeHtml(t.channel || '') + '" data-agent-name="' + escapeHtml(a.name || a.id) + '"'
2679
3819
  : '';
2680
- return '<button class="ax-agent__task"' + dataAttrs + ' title="' + escapeHtml(t.messagePreview || '') + '">' +
3820
+ return '<button class="ax-agent__task"' + dataAttrs + ' data-started-at="' + escapeHtml(t.startedAt || '') + '" title="' + escapeHtml(t.messagePreview || '') + '">' +
2681
3821
  '<div class="ax-agent__task-head">' +
2682
3822
  '<span class="ax-dot ax-dot--live ax-dot--pulse"></span>' +
2683
3823
  '<span>running \xB7 ' + escapeHtml(t.channel || '') + '</span>' +
@@ -2723,6 +3863,7 @@ function renderAgent(a, node) {
2723
3863
  '</div>';
2724
3864
 
2725
3865
  const lastActiveText = a.lastActive ? 'last active ' + fmtAgo(a.lastActive) : (L.neverRan || 'not used yet');
3866
+ const lastActiveAttr = a.lastActive ? ' data-last-active="' + escapeHtml(a.lastActive) + '"' : '';
2726
3867
  const recentLink = nodeUrl
2727
3868
  ? '<button class="ax-linkbtn" data-agent-id="' + escapeHtml(a.id) + '" data-agent-name="' + escapeHtml(a.name || a.id) + '" data-node-url="' + escapeHtml(nodeUrl) + '" data-recent="1">history \u2192</button>'
2728
3869
  : '';
@@ -2730,7 +3871,7 @@ function renderAgent(a, node) {
2730
3871
  // Head: mention (trigger) + human name + tier badge + live/idle badge
2731
3872
  const mention = (a.mentions && a.mentions.length) ? '@' + a.mentions[0].replace(/^@/, '') : '@' + a.id;
2732
3873
  const liveBadge = busy
2733
- ? '<span class="ax-badge ax-badge--mono ax-badge--accent"><span class="ax-dot ax-dot--live ax-dot--pulse"></span> live</span>'
3874
+ ? '<span class="ax-badge ax-badge--mono ax-badge--live"><span class="ax-dot ax-dot--live ax-dot--pulse"></span> live</span>'
2734
3875
  : (errored ? '<span class="ax-badge ax-badge--mono ax-badge--warn">errored</span>' : '<span class="ax-badge ax-badge--mono ax-badge--ghost">idle</span>');
2735
3876
  const tierBadge = tierDisplay ? '<span class="ax-badge ax-badge--mono ax-badge--ghost" title="AI engine">' + escapeHtml(tierDisplay) + '</span>' : '';
2736
3877
 
@@ -2747,7 +3888,7 @@ function renderAgent(a, node) {
2747
3888
  sparkBlock +
2748
3889
  runningBlock +
2749
3890
  summaryBlock +
2750
- '<div class="ax-agent__foot"><span>' + escapeHtml(lastActiveText) + '</span>' + recentLink + '</div>';
3891
+ '<div class="ax-agent__foot"' + lastActiveAttr + '><span class="last-active">' + escapeHtml(lastActiveText) + '</span>' + recentLink + '</div>';
2751
3892
  return card;
2752
3893
  }
2753
3894
 
@@ -2789,29 +3930,48 @@ function fmtAgo(iso) {
2789
3930
  }
2790
3931
 
2791
3932
  function connect() {
3933
+ // #conn exists on the Kanban page; the Live page only has #conn-dot/#conn-label
3934
+ // in the topbar. Guard it or the snapshot handler throws before render runs,
3935
+ // which silently freezes the live grid between page reloads.
2792
3936
  const conn = document.getElementById('conn');
2793
3937
  let es;
2794
3938
  const open = () => {
2795
3939
  try { es = new EventSource('/api/live/stream'); } catch (e) { setTimeout(open, 2000); return; }
2796
3940
  es.addEventListener('snapshot', (ev) => {
2797
- conn.className = 'conn ok'; conn.title = 'connected';
2798
- try { render(JSON.parse(ev.data)); } catch {}
3941
+ if (conn) { conn.className = 'conn ok'; conn.title = 'connected'; }
3942
+ try { render(JSON.parse(ev.data)); } catch (e) { console.error('live render failed', e); }
2799
3943
  });
2800
3944
  es.addEventListener('error', () => {
2801
- conn.className = 'conn err'; conn.title = 'reconnecting\u2026';
3945
+ if (conn) { conn.className = 'conn err'; conn.title = 'reconnecting\u2026'; }
2802
3946
  es.close(); setTimeout(open, 2000);
2803
3947
  });
2804
3948
  };
2805
3949
  open();
2806
3950
  }
2807
3951
 
2808
- // Re-render every second to tick elapsed counters even when no new snapshot arrives.
3952
+ // Tick elapsed / last-active counters every second from DOM data attributes,
3953
+ // so they advance smoothly between 2s server snapshots instead of jumping.
2809
3954
  let lastSnap = null;
2810
3955
  fetch('/api/live').then(r => r.json()).then(s => { lastSnap = s; render(s); }).catch(() => {});
2811
- setInterval(() => { if (lastSnap) {
2812
- // Patch elapsed times without a fresh snapshot
2813
- document.querySelectorAll('.agent .task .elapsed').forEach((el) => { /* placeholder: server snapshot advances on stream */ });
2814
- } }, 1000);
3956
+ setInterval(() => {
3957
+ const now = Date.now();
3958
+ // Running-task elapsed counters.
3959
+ document.querySelectorAll('.ax-agent__task[data-started-at]').forEach((btn) => {
3960
+ const startedAt = btn.getAttribute('data-started-at');
3961
+ if (!startedAt) return;
3962
+ const t = new Date(startedAt).getTime();
3963
+ if (!t) return;
3964
+ const el = btn.querySelector('.elapsed');
3965
+ if (el) el.textContent = fmtElapsed(now - t);
3966
+ });
3967
+ // Idle-card "last active" text \u2014 smooths from "5s ago" to "6s ago".
3968
+ document.querySelectorAll('.ax-agent__foot[data-last-active]').forEach((foot) => {
3969
+ const iso = foot.getAttribute('data-last-active');
3970
+ if (!iso) return;
3971
+ const el = foot.querySelector('.last-active');
3972
+ if (el) el.textContent = 'last active ' + fmtAgo(iso);
3973
+ });
3974
+ }, 1000);
2815
3975
  connect();
2816
3976
 
2817
3977
  // --- Task output modal ---
@@ -3149,7 +4309,7 @@ document.getElementById('grid').addEventListener('click', (e) => {
3149
4309
  });
3150
4310
  }
3151
4311
  });
3152
- `,Qt=`
4312
+ `,an=`
3153
4313
  /* --- Design tokens (ops-daemon, matches /live and /admin) --- */
3154
4314
  :root {
3155
4315
  --ax-bg: oklch(0.16 0.010 265); --ax-bg-elev: oklch(0.19 0.012 265);
@@ -3445,7 +4605,7 @@ header a.link:hover { color: var(--accent); border-color: var(--accent); }
3445
4605
  .draft-box .draft-row .hint { color: var(--muted); font-size: 12px; flex: 1; }
3446
4606
  .draft-box .draft-row .hint.err { color: var(--red); }
3447
4607
  .draft-box .draft-row .hint.ok { color: var(--green); }
3448
- `,Zt=`
4608
+ `,nn=`
3449
4609
  'use strict';
3450
4610
  const state = {
3451
4611
  boards: [], current: null, items: {},
@@ -4504,5 +5664,5 @@ function appendEvents(events) {
4504
5664
  }
4505
5665
 
4506
5666
  loadBoards().catch(e => toast('Init failed: ' + e.message));
4507
- `;export{Ca as startBoardDashboard};
4508
- //# sourceMappingURL=board-dashboard-DAPHL6W2.js.map
5667
+ `;export{Wn as startBoardDashboard};
5668
+ //# sourceMappingURL=board-dashboard-LA7WW56M.js.map