agentix-cli 0.112.0 → 0.114.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 (134) hide show
  1. package/apps/mac-helper/Resources/AppIcon.png +0 -0
  2. package/apps/mac-voice/Resources/AppIcon.png +0 -0
  3. package/apps/mac-voice/Resources/Info.plist +1 -0
  4. package/apps/mac-voice/build.sh +10 -0
  5. package/dist/{App-4AX6LR6Q.js → App-Q4UAYL2V.js} +2 -2
  6. package/dist/{ChatApp-HAIPYO4I.js → ChatApp-6KGP57OP.js} +2 -2
  7. package/dist/agent-5F4EKGQN.js +2 -0
  8. package/dist/{board-dashboard-RNWZ3H2T.js → board-dashboard-GGW5ZZLT.js} +841 -329
  9. package/dist/board-dashboard-GGW5ZZLT.js.map +1 -0
  10. package/dist/{chunk-5MUJZODV.js → chunk-2PJKGZWP.js} +32 -32
  11. package/dist/chunk-2PJKGZWP.js.map +1 -0
  12. package/dist/{chunk-NHAVY7VU.js → chunk-4COYYJJY.js} +2 -2
  13. package/dist/{chunk-QAIYUMHW.js → chunk-4VDA4UM7.js} +2 -2
  14. package/dist/{chunk-K4TN34OM.js → chunk-6WNQY6K2.js} +2 -2
  15. package/dist/{chunk-HIVQHFPT.js → chunk-A35RTVMM.js} +2 -2
  16. package/dist/{chunk-DG5I6PPM.js → chunk-BGG3ZSMW.js} +4 -2
  17. package/dist/chunk-BGG3ZSMW.js.map +1 -0
  18. package/dist/{chunk-2JEJIVOZ.js → chunk-C4S5XQKD.js} +2 -2
  19. package/dist/{chunk-ZVUVFMYN.js → chunk-CYKPDILL.js} +2 -2
  20. package/dist/{chunk-JRMYIPIL.js → chunk-FDCTFT2Q.js} +2 -2
  21. package/dist/{chunk-2S5T3VT5.js → chunk-HG6QA6EU.js} +2 -2
  22. package/dist/{chunk-HNRQQEDE.js → chunk-HPY54DU6.js} +2 -2
  23. package/dist/{chunk-EUCLJ2VL.js → chunk-ILGLEA3I.js} +5 -5
  24. package/dist/{chunk-EUCLJ2VL.js.map → chunk-ILGLEA3I.js.map} +1 -1
  25. package/dist/{chunk-ETV2UH66.js → chunk-J3GXZQXY.js} +2 -2
  26. package/dist/{chunk-Q6ILGUDE.js → chunk-LP227A6L.js} +2 -2
  27. package/dist/{chunk-WN5MCIVA.js → chunk-O2RVUM2B.js} +2 -2
  28. package/dist/{chunk-SFAZ6IH2.js → chunk-QQIWLN3H.js} +160 -160
  29. package/dist/chunk-QQIWLN3H.js.map +1 -0
  30. package/dist/{chunk-N7HKIMMR.js → chunk-SCJ5ZXEN.js} +2 -2
  31. package/dist/{chunk-C245D4BZ.js → chunk-UG2OF2EI.js} +2 -2
  32. package/dist/{chunk-7MTHXIT5.js → chunk-VGI4EZTP.js} +2 -2
  33. package/dist/{chunk-R4KGAIBF.js → chunk-VQM77L54.js} +2 -2
  34. package/dist/{chunk-6DGPWKRK.js → chunk-VTWSW4KB.js} +2 -2
  35. package/dist/{chunk-RXAR3JIV.js → chunk-XTO4GRGN.js} +8 -8
  36. package/dist/{chunk-MOO6DKMZ.js → chunk-XX7NXI3Y.js} +2 -2
  37. package/dist/{chunk-34KJ4Q4E.js → chunk-Y5HBYSJW.js} +12 -12
  38. package/dist/chunk-Y5HBYSJW.js.map +1 -0
  39. package/dist/{chunk-23A5K5UW.js → chunk-Y5MFVVTM.js} +2 -2
  40. package/dist/{chunk-XEJ4E5HH.js → chunk-YLKCFW2R.js} +2 -2
  41. package/dist/{chunk-ANV4T62P.js → chunk-YU5NDKPA.js} +6 -6
  42. package/dist/cli.js +1 -1
  43. package/dist/{client-MYU23KWY.js → client-QTXWO46T.js} +2 -2
  44. package/dist/{compaction-MECSN36J.js → compaction-FS6XNRLM.js} +3 -3
  45. package/dist/config-4XGZYYQP.js +2 -0
  46. package/dist/config-mutator-QLSA6JOY.js +2 -0
  47. package/dist/{context-planner-JU7CNXCB.js → context-planner-BKHPKDX5.js} +2 -2
  48. package/dist/{doctor-AUF5HJPW.js → doctor-DO262COW.js} +2 -2
  49. package/dist/heal-U67X6NIN.js +2 -0
  50. package/dist/index.d.ts +184 -0
  51. package/dist/index.js +1 -1
  52. package/dist/memory-extract-ATD6YLRK.js +2 -0
  53. package/dist/processes-5MP32QZT.js +2 -0
  54. package/dist/{program-7ZNCVU5A.js → program-IEMICVO3.js} +14 -14
  55. package/dist/{promote-FP4LHKWZ.js → promote-S7SKOKX2.js} +2 -2
  56. package/dist/{providers-ES5KVLI4.js → providers-55NC2SFN.js} +2 -2
  57. package/dist/{query-IJWC42YJ.js → query-GOBQ3GL5.js} +2 -2
  58. package/dist/{registry-US7IWI5G.js → registry-HUJEORRW.js} +2 -2
  59. package/dist/{request-planner-SDUMKFFP.js → request-planner-RYWFGBGK.js} +2 -2
  60. package/dist/{review-candidates-QOKFHMPL.js → review-candidates-TXX532LY.js} +2 -2
  61. package/dist/{routing-XZBHJ63Q.js → routing-IT4YS6X3.js} +2 -2
  62. package/dist/schedule-tool-FJKH2ERY.js +2 -0
  63. package/dist/scheduler-ALPDUE4H.js +2 -0
  64. package/dist/{seat-OU3VAP5Y.js → seat-LK45MTVI.js} +2 -2
  65. package/dist/{select-S6E3HJPE.js → select-4LAHUZ74.js} +2 -2
  66. package/dist/{set-enabled-GY7O7IRS.js → set-enabled-F2K56HQZ.js} +2 -2
  67. package/dist/{tool-RGYNLN6I.js → tool-J4VHHZWN.js} +2 -2
  68. package/dist/{tool-RT5REMY7.js → tool-W3ODKQM2.js} +2 -2
  69. package/dist/wiki-FZHSX4K3.js +2 -0
  70. package/package.json +1 -1
  71. package/dist/agent-Q7MDX45J.js +0 -2
  72. package/dist/board-dashboard-RNWZ3H2T.js.map +0 -1
  73. package/dist/chunk-34KJ4Q4E.js.map +0 -1
  74. package/dist/chunk-5MUJZODV.js.map +0 -1
  75. package/dist/chunk-DG5I6PPM.js.map +0 -1
  76. package/dist/chunk-SFAZ6IH2.js.map +0 -1
  77. package/dist/config-45OK6PHO.js +0 -2
  78. package/dist/config-mutator-4SUOOBNK.js +0 -2
  79. package/dist/heal-CMQL5SG4.js +0 -2
  80. package/dist/memory-extract-YCNCARZ2.js +0 -2
  81. package/dist/processes-W5VHBP7T.js +0 -2
  82. package/dist/schedule-tool-XQYEDYXX.js +0 -2
  83. package/dist/scheduler-VDIZDO6Y.js +0 -2
  84. package/dist/wiki-3UTXUIN6.js +0 -2
  85. /package/dist/{App-4AX6LR6Q.js.map → App-Q4UAYL2V.js.map} +0 -0
  86. /package/dist/{ChatApp-HAIPYO4I.js.map → ChatApp-6KGP57OP.js.map} +0 -0
  87. /package/dist/{agent-Q7MDX45J.js.map → agent-5F4EKGQN.js.map} +0 -0
  88. /package/dist/{chunk-NHAVY7VU.js.map → chunk-4COYYJJY.js.map} +0 -0
  89. /package/dist/{chunk-QAIYUMHW.js.map → chunk-4VDA4UM7.js.map} +0 -0
  90. /package/dist/{chunk-K4TN34OM.js.map → chunk-6WNQY6K2.js.map} +0 -0
  91. /package/dist/{chunk-HIVQHFPT.js.map → chunk-A35RTVMM.js.map} +0 -0
  92. /package/dist/{chunk-2JEJIVOZ.js.map → chunk-C4S5XQKD.js.map} +0 -0
  93. /package/dist/{chunk-ZVUVFMYN.js.map → chunk-CYKPDILL.js.map} +0 -0
  94. /package/dist/{chunk-JRMYIPIL.js.map → chunk-FDCTFT2Q.js.map} +0 -0
  95. /package/dist/{chunk-2S5T3VT5.js.map → chunk-HG6QA6EU.js.map} +0 -0
  96. /package/dist/{chunk-HNRQQEDE.js.map → chunk-HPY54DU6.js.map} +0 -0
  97. /package/dist/{chunk-ETV2UH66.js.map → chunk-J3GXZQXY.js.map} +0 -0
  98. /package/dist/{chunk-Q6ILGUDE.js.map → chunk-LP227A6L.js.map} +0 -0
  99. /package/dist/{chunk-WN5MCIVA.js.map → chunk-O2RVUM2B.js.map} +0 -0
  100. /package/dist/{chunk-N7HKIMMR.js.map → chunk-SCJ5ZXEN.js.map} +0 -0
  101. /package/dist/{chunk-C245D4BZ.js.map → chunk-UG2OF2EI.js.map} +0 -0
  102. /package/dist/{chunk-7MTHXIT5.js.map → chunk-VGI4EZTP.js.map} +0 -0
  103. /package/dist/{chunk-R4KGAIBF.js.map → chunk-VQM77L54.js.map} +0 -0
  104. /package/dist/{chunk-6DGPWKRK.js.map → chunk-VTWSW4KB.js.map} +0 -0
  105. /package/dist/{chunk-RXAR3JIV.js.map → chunk-XTO4GRGN.js.map} +0 -0
  106. /package/dist/{chunk-MOO6DKMZ.js.map → chunk-XX7NXI3Y.js.map} +0 -0
  107. /package/dist/{chunk-23A5K5UW.js.map → chunk-Y5MFVVTM.js.map} +0 -0
  108. /package/dist/{chunk-XEJ4E5HH.js.map → chunk-YLKCFW2R.js.map} +0 -0
  109. /package/dist/{chunk-ANV4T62P.js.map → chunk-YU5NDKPA.js.map} +0 -0
  110. /package/dist/{client-MYU23KWY.js.map → client-QTXWO46T.js.map} +0 -0
  111. /package/dist/{compaction-MECSN36J.js.map → compaction-FS6XNRLM.js.map} +0 -0
  112. /package/dist/{config-45OK6PHO.js.map → config-4XGZYYQP.js.map} +0 -0
  113. /package/dist/{config-mutator-4SUOOBNK.js.map → config-mutator-QLSA6JOY.js.map} +0 -0
  114. /package/dist/{context-planner-JU7CNXCB.js.map → context-planner-BKHPKDX5.js.map} +0 -0
  115. /package/dist/{doctor-AUF5HJPW.js.map → doctor-DO262COW.js.map} +0 -0
  116. /package/dist/{heal-CMQL5SG4.js.map → heal-U67X6NIN.js.map} +0 -0
  117. /package/dist/{memory-extract-YCNCARZ2.js.map → memory-extract-ATD6YLRK.js.map} +0 -0
  118. /package/dist/{processes-W5VHBP7T.js.map → processes-5MP32QZT.js.map} +0 -0
  119. /package/dist/{program-7ZNCVU5A.js.map → program-IEMICVO3.js.map} +0 -0
  120. /package/dist/{promote-FP4LHKWZ.js.map → promote-S7SKOKX2.js.map} +0 -0
  121. /package/dist/{providers-ES5KVLI4.js.map → providers-55NC2SFN.js.map} +0 -0
  122. /package/dist/{query-IJWC42YJ.js.map → query-GOBQ3GL5.js.map} +0 -0
  123. /package/dist/{registry-US7IWI5G.js.map → registry-HUJEORRW.js.map} +0 -0
  124. /package/dist/{request-planner-SDUMKFFP.js.map → request-planner-RYWFGBGK.js.map} +0 -0
  125. /package/dist/{review-candidates-QOKFHMPL.js.map → review-candidates-TXX532LY.js.map} +0 -0
  126. /package/dist/{routing-XZBHJ63Q.js.map → routing-IT4YS6X3.js.map} +0 -0
  127. /package/dist/{schedule-tool-XQYEDYXX.js.map → schedule-tool-FJKH2ERY.js.map} +0 -0
  128. /package/dist/{scheduler-VDIZDO6Y.js.map → scheduler-ALPDUE4H.js.map} +0 -0
  129. /package/dist/{seat-OU3VAP5Y.js.map → seat-LK45MTVI.js.map} +0 -0
  130. /package/dist/{select-S6E3HJPE.js.map → select-4LAHUZ74.js.map} +0 -0
  131. /package/dist/{set-enabled-GY7O7IRS.js.map → set-enabled-F2K56HQZ.js.map} +0 -0
  132. /package/dist/{tool-RGYNLN6I.js.map → tool-J4VHHZWN.js.map} +0 -0
  133. /package/dist/{tool-RT5REMY7.js.map → tool-W3ODKQM2.js.map} +0 -0
  134. /package/dist/{wiki-3UTXUIN6.js.map → wiki-FZHSX4K3.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import{A as Dr,B as Hr,C as Br,a as A,b as _r,c as Sr,d as Er,e as Tr,f as Se,g as Ar,h as Cr,i as Rt,k as Ir,q as Mr,r as Lr,s as Rr,t as $r,u as Pr,y as jr,z as Or}from"./chunk-HNRQQEDE.js";import{a as Nr}from"./chunk-4FU4BFCH.js";import{a as kr}from"./chunk-QAIYUMHW.js";import{a as He,b as B,c as M,h as be,i as Mt,j as re,k as K,l as Lt,m as br,n as yr,o as wr}from"./chunk-N7HKIMMR.js";import{a as vr}from"./chunk-2NYP4OQU.js";import{a as ce,b as xr}from"./chunk-JWDJMFU6.js";import{A as kt,Aa as lr,B as Kn,Ba as cr,C as _t,D as St,E as Jn,F as Yn,I as Qn,J as Zn,Ja as dr,K as er,La as Ne,Qa as pr,R as U,S as tr,Sa as De,T as ar,Ta as Et,Ua as Tt,Va as At,Wa as Ct,Xa as ur,Ya as mr,Za as fr,_a as It,a as Hn,ab as hr,c as gt,d as ha,db as gr,e as Bn,i as xt,l as Je,n as zn,w as bt,x as Xn,xa as sr,y as yt,z as wt,za as ir}from"./chunk-K4TN34OM.js";import{g as Nn,h as Dn}from"./chunk-6DGPWKRK.js";import{p as qn,t as Fn}from"./chunk-S2GAEH2F.js";import"./chunk-GTJIKXDB.js";import{a as Vn,b as N,c as nr,d as rr,h as or}from"./chunk-DG5I6PPM.js";import"./chunk-NHAVY7VU.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as F,c as _e,d as Un,e as ga}from"./chunk-ACFQBLPX.js";import{g as vt}from"./chunk-LQE73AZR.js";import{b as Wn,c as Gn}from"./chunk-2D3RYIDU.js";import"./chunk-JIT5GPTX.js";import{a as Mn,f as Ln,g as ma,h as fa,l as Rn,m as $n,n as Pn,u as mt,v as ft,w as ht,x as le,y as On}from"./chunk-ETV2UH66.js";import"./chunk-GLQLCBJS.js";import"./chunk-6W74CHNW.js";import"./chunk-SHEUCITK.js";import"./chunk-Y4CYQV7G.js";import"./chunk-XEJ4E5HH.js";import"./chunk-GV7S5BAX.js";import"./chunk-SZDACK6O.js";import"./chunk-AFRHKA7B.js";import"./chunk-7MTHXIT5.js";import{a as jn}from"./chunk-ZVUVFMYN.js";import"./chunk-R4KGAIBF.js";import"./chunk-MOO6DKMZ.js";import"./chunk-KA2UIZXG.js";import"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-GSX4NK2N.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import{g as In}from"./chunk-EUCLJ2VL.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import"./chunk-HIVQHFPT.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import{A as rc,J as En,M as oc,O as pt,P as Tn,R as An,T as Cn,X as ua,a as vn,b as bn,c as tc,ia as X,la as ut,u as lt,v as ac,w as da,x as pa}from"./chunk-34KJ4Q4E.js";import{d as _n,e as nc,f as dt,n as Sn}from"./chunk-UIBUZ2N3.js";import{a as yn,b as ct,c as ca,d as wn,h as kn}from"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";function xa(t,e,a=Date.now()){let n=Math.max(0,a-(t.updatedAt||a)),r=t.clientId?e[t.clientId]:void 0;if(!r)return{score:n/864e5,ageMs:n,rising:!1,overdue:!1};let o=n/(r*6e4);return{score:1e3+o,ageMs:n,rising:!0,overdue:o>=1}}function zr(t,e,a=Date.now()){return t.map((n,r)=>({i:r,s:xa(n,e,a).score})).sort((n,r)=>r.s-n.s||n.i-r.i).map(n=>n.i)}var oe={refresh:'<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>',clock:'<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',alert:'<path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/><path d="M12 9v4"/><path d="M12 17h.01"/>',gavel:'<path d="M12 3 6 9"/><path d="m9 6 6 6"/><path d="M15 9 9 15"/><path d="m12 12 6 6"/><path d="M4 21h10"/>',loop:'<path d="M17 2l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 22l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/>',broom:'<path d="M3 21h18"/><path d="M12 3v9"/><path d="m7 12 5-3 5 3-1.5 6h-7Z"/>',server:'<rect x="2" y="3" width="20" height="7" rx="2"/><rect x="2" y="14" width="20" height="7" rx="2"/><path d="M6 6.5h.01"/><path d="M6 17.5h.01"/>',inbox:'<path d="M21 12h-6l-2 3h-2l-2-3H3"/><path d="M5 5h14l2 7v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Z"/>',cross:'<circle cx="12" cy="12" r="9"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/>',file:'<path d="M14 2H7a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7Z"/><path d="M14 2v5h5"/>',search:'<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>',chev:'<path d="m6 9 6 6 6-6"/>',chevr:'<path d="m9 6 6 6-6 6"/>',ext:'<path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>',pulse:'<path d="M3 12h4l3-8 4 16 3-8h4"/>',plug:'<path d="M9 2v6"/><path d="M15 2v6"/><path d="M6 8h12v3a6 6 0 0 1-12 0Z"/><path d="M12 17v5"/>',check:'<path d="M20 6 9 17l-5-5"/>',route:'<circle cx="6" cy="19" r="3"/><circle cx="18" cy="5" r="3"/><path d="M9 19h6a4 4 0 0 0 0-8H9a4 4 0 0 1 0-8h6"/>',branch:'<circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="8" r="3"/><path d="M18 11v1a3 3 0 0 1-3 3H9"/><path d="M6 9v6"/>',send:'<path d="M22 2 11 13"/><path d="M22 2l-7 20-4-9-9-4Z"/>',msg:'<path d="M21 11.5a8.4 8.4 0 0 1-12.9 7.5L3 21l2-5.1A8.4 8.4 0 1 1 21 11.5Z"/>',code:'<path d="m9 18-6-6 6-6"/><path d="m15 6 6 6-6 6"/>',hash:'<path d="M4 9h16"/><path d="M4 15h16"/><path d="M10 3 8 21"/><path d="M16 3l-2 18"/>',x:'<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',trace:'<path d="M4 4v16h16"/><path d="m7 15 4-4 3 3 5-6"/>'},Ee=(t,e=14)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+e+'" height="'+e+'" aria-hidden="true">'+t+"</svg>",$t=(t,e,a,n="")=>'<div class="ax-sec-label"><h3>'+Ee(t,13)+e+(a?'<span class="ax-sec-label__n" id="'+a+'"></span>':"")+"</h3>"+n+"</div>";function qr(t={}){return M({title:"AgentX \xB7 Monitor",activeTab:"monitor",subtitle:"Monitor",peers:t.peers,body:`<div class="bf">
1
+ import{A as Jr,B as Vr,C as Yr,a as C,b as $r,c as jr,d as Or,e as Nr,f as Ie,g as Dr,h as Hr,i as jt,k as Br,q as zr,r as qr,s as Fr,t as Ur,u as Wr,y as Gr,z as Xr}from"./chunk-HPY54DU6.js";import{a as Kr}from"./chunk-4FU4BFCH.js";import{a as Pr}from"./chunk-4VDA4UM7.js";import{a as Fe,b as q,c as I,h as ue,i as Pt,j as se,k as K,l as $t,m as Mr,n as Lr,o as Rr}from"./chunk-SCJ5ZXEN.js";import{a as Ir}from"./chunk-2NYP4OQU.js";import{a as pe,b as Cr}from"./chunk-JWDJMFU6.js";import{A as Tt,Aa as vr,B as or,Ba as yr,C as ze,D as At,E as sr,F as lr,I as cr,J as dr,Ja as wr,K as pr,La as Ce,Qa as kr,R as W,S as ur,Sa as qe,T as mr,Ta as Ct,Ua as It,Va as Mt,Wa as Lt,Xa as _r,Ya as Sr,Za as Er,_a as Rt,a as Vn,ab as Tr,c as yt,d as ya,db as Ar,e as Yn,i as wt,l as et,n as Qn,w as _t,x as rr,xa as xr,y as St,z as Et,za as br}from"./chunk-6WNQY6K2.js";import{g as Kn,h as Jn}from"./chunk-VTWSW4KB.js";import{p as Zn,t as er}from"./chunk-S2GAEH2F.js";import"./chunk-GTJIKXDB.js";import{a as ir,b as H,c as fr,d as hr,h as gr}from"./chunk-BGG3ZSMW.js";import"./chunk-4COYYJJY.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as G,c as Ae,d as tr,e as wa}from"./chunk-ACFQBLPX.js";import{g as kt}from"./chunk-LQE73AZR.js";import{b as ar,c as nr}from"./chunk-2D3RYIDU.js";import"./chunk-JIT5GPTX.js";import{a as zn,f as qn,g as ba,h as va,l as Fn,m as Un,n as Wn,u as xt,v as bt,w as vt,x as de,y as Xn}from"./chunk-J3GXZQXY.js";import"./chunk-GLQLCBJS.js";import"./chunk-6W74CHNW.js";import"./chunk-SHEUCITK.js";import"./chunk-Y4CYQV7G.js";import"./chunk-YLKCFW2R.js";import"./chunk-GV7S5BAX.js";import"./chunk-SZDACK6O.js";import"./chunk-AFRHKA7B.js";import"./chunk-VGI4EZTP.js";import{a as Gn}from"./chunk-CYKPDILL.js";import"./chunk-VQM77L54.js";import"./chunk-XX7NXI3Y.js";import"./chunk-KA2UIZXG.js";import"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-GSX4NK2N.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import{g as Bn}from"./chunk-ILGLEA3I.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import"./chunk-A35RTVMM.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import{A as Gc,H as jn,K as ga,N as On,P as ht,Q as Nn,S as Dn,U as Hn,Y as xa,a as Cn,b as In,c as Fc,ja as X,ma as gt,u as ut,v as Uc,w as fa,x as ha}from"./chunk-Y5HBYSJW.js";import{d as Pn,e as Wc,f as ft,n as $n}from"./chunk-UIBUZ2N3.js";import{a as Mn,b as mt,c as ma,d as Ln,h as Rn}from"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";function ka(t,e,a=Date.now()){let n=Math.max(0,a-(t.updatedAt||a)),r=t.clientId?e[t.clientId]:void 0;if(!r)return{score:n/864e5,ageMs:n,rising:!1,overdue:!1};let o=n/(r*6e4);return{score:1e3+o,ageMs:n,rising:!0,overdue:o>=1}}function Qr(t,e,a=Date.now()){return t.map((n,r)=>({i:r,s:ka(n,e,a).score})).sort((n,r)=>r.s-n.s||n.i-r.i).map(n=>n.i)}var ie={refresh:'<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>',clock:'<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',alert:'<path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/><path d="M12 9v4"/><path d="M12 17h.01"/>',gavel:'<path d="M12 3 6 9"/><path d="m9 6 6 6"/><path d="M15 9 9 15"/><path d="m12 12 6 6"/><path d="M4 21h10"/>',loop:'<path d="M17 2l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 22l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/>',broom:'<path d="M3 21h18"/><path d="M12 3v9"/><path d="m7 12 5-3 5 3-1.5 6h-7Z"/>',server:'<rect x="2" y="3" width="20" height="7" rx="2"/><rect x="2" y="14" width="20" height="7" rx="2"/><path d="M6 6.5h.01"/><path d="M6 17.5h.01"/>',inbox:'<path d="M21 12h-6l-2 3h-2l-2-3H3"/><path d="M5 5h14l2 7v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Z"/>',cross:'<circle cx="12" cy="12" r="9"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/>',file:'<path d="M14 2H7a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7Z"/><path d="M14 2v5h5"/>',search:'<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>',chev:'<path d="m6 9 6 6 6-6"/>',chevr:'<path d="m9 6 6 6-6 6"/>',ext:'<path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>',pulse:'<path d="M3 12h4l3-8 4 16 3-8h4"/>',plug:'<path d="M9 2v6"/><path d="M15 2v6"/><path d="M6 8h12v3a6 6 0 0 1-12 0Z"/><path d="M12 17v5"/>',check:'<path d="M20 6 9 17l-5-5"/>',route:'<circle cx="6" cy="19" r="3"/><circle cx="18" cy="5" r="3"/><path d="M9 19h6a4 4 0 0 0 0-8H9a4 4 0 0 1 0-8h6"/>',branch:'<circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="8" r="3"/><path d="M18 11v1a3 3 0 0 1-3 3H9"/><path d="M6 9v6"/>',send:'<path d="M22 2 11 13"/><path d="M22 2l-7 20-4-9-9-4Z"/>',msg:'<path d="M21 11.5a8.4 8.4 0 0 1-12.9 7.5L3 21l2-5.1A8.4 8.4 0 1 1 21 11.5Z"/>',code:'<path d="m9 18-6-6 6-6"/><path d="m15 6 6 6-6 6"/>',hash:'<path d="M4 9h16"/><path d="M4 15h16"/><path d="M10 3 8 21"/><path d="M16 3l-2 18"/>',x:'<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',trace:'<path d="M4 4v16h16"/><path d="m7 15 4-4 3 3 5-6"/>'},Me=(t,e=14)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+e+'" height="'+e+'" aria-hidden="true">'+t+"</svg>",Ot=(t,e,a,n="")=>'<div class="ax-sec-label"><h3>'+Me(t,13)+e+(a?'<span class="ax-sec-label__n" id="'+a+'"></span>':"")+"</h3>"+n+"</div>";function Zr(t={}){return I({title:"AgentX \xB7 Monitor",activeTab:"monitor",subtitle:"Monitor",peers:t.peers,body:`<div class="bf">
2
2
 
3
3
  <div class="bf-head">
4
4
  <div>
@@ -7,8 +7,8 @@ import{A as Dr,B as Hr,C as Br,a as A,b as _r,c as Sr,d as Er,e as Tr,f as Se,g
7
7
  </div>
8
8
  <div class="bf-sync">
9
9
  <span class="bf-sync__t" id="synced">Gathering&hellip;</span>
10
- <a class="ax-btn ax-btn--sm" href="/activity" title="What ran, and when">${Ee(oe.pulse,13)} Activity</a>
11
- <button class="ax-btn" id="refresh" title="Refresh now">${Ee(oe.refresh)} Refresh</button>
10
+ <a class="ax-btn ax-btn--sm" href="/activity" title="What ran, and when">${Me(ie.pulse,13)} Activity</a>
11
+ <button class="ax-btn" id="refresh" title="Refresh now">${Me(ie.refresh)} Refresh</button>
12
12
  </div>
13
13
  </div>
14
14
 
@@ -21,24 +21,24 @@ import{A as Dr,B as Hr,C as Br,a as A,b as _r,c as Sr,d as Er,e as Tr,f as Se,g
21
21
 
22
22
  <div class="bf-grid">
23
23
  <section class="bf-col">
24
- ${$t(oe.alert,"Only you","you-count",'<span class="bf-why">needs your authority, your relationship, or something the system cannot know</span><button class="ax-btn ax-btn--sm" id="clear-actions" title="Mark every open action done on every node">Clear all</button>')}
24
+ ${Ot(ie.alert,"Only you","you-count",'<span class="bf-why">needs your authority, your relationship, or something the system cannot know</span><button class="ax-btn ax-btn--sm" id="clear-actions" title="Mark every open action done on every node">Clear all</button>')}
25
25
  <div id="you" class="bf-col"></div>
26
26
 
27
- ${$t(oe.plug,"Agents can handle","agents-count",'<span class="bf-why">no human needed &mdash; not yet automatic</span>')}
27
+ ${Ot(ie.plug,"Agents can handle","agents-count",'<span class="bf-why">no human needed &mdash; not yet automatic</span>')}
28
28
  <div id="agents" class="bf-col"></div>
29
29
  <button class="ax-btn ax-btn--sm" id="more-actions" hidden></button>
30
30
 
31
31
  <div id="handled"></div>
32
32
  </section>
33
33
  <aside class="bf-col">
34
- ${$t(oe.pulse,"In motion","run-count")}
34
+ ${Ot(ie.pulse,"In motion","run-count")}
35
35
  <div id="running" class="bf-col"></div>
36
36
  </aside>
37
37
  </div>
38
38
 
39
- ${$t(oe.file,"Session briefings","brief-count")}
39
+ ${Ot(ie.file,"Session briefings","brief-count")}
40
40
  <div class="bf-toolbar">
41
- <div class="bf-search">${Ee(oe.search)}
41
+ <div class="bf-search">${Me(ie.search)}
42
42
  <input id="search" type="search" placeholder="Search sessions&hellip;" aria-label="Search sessions">
43
43
  </div>
44
44
  <div class="bf-filters" id="filters" role="group" aria-label="Filter briefings"></div>
@@ -46,15 +46,15 @@ ${$t(oe.file,"Session briefings","brief-count")}
46
46
  <div id="reviews" class="bf-col"></div>
47
47
 
48
48
  <section class="ax-panel bf-connect">
49
- <div class="bf-connect__head">${Ee(oe.plug,17)}<h2>Connect a CLI session</h2>
49
+ <div class="bf-connect__head">${Me(ie.plug,17)}<h2>Connect a CLI session</h2>
50
50
  <span class="bf-connect__note">Daemon-owned processes only</span></div>
51
51
  <div class="bf-discover">
52
52
  <div class="ax-field"><label for="node">Node</label><select id="node"></select></div>
53
- <button class="ax-btn" id="discover">${Ee(oe.search)} Discover CLIs</button>
53
+ <button class="ax-btn" id="discover">${Me(ie.search)} Discover CLIs</button>
54
54
  </div>
55
55
  <div class="bf-cli" id="discovered"></div>
56
56
  <details class="bf-manual">
57
- <summary>${Ee(oe.chev,12)} Register manually</summary>
57
+ <summary>${Me(ie.chev,12)} Register manually</summary>
58
58
  <div class="bf-forms">
59
59
  <form id="register" class="bf-form">
60
60
  <div class="ax-sec-label"><h3>Register a session</h3></div>
@@ -85,7 +85,7 @@ ${$t(oe.file,"Session briefings","brief-count")}
85
85
  </div>
86
86
  </details>
87
87
  </section>
88
- </div>`,css:sc,scripts:`<script>${B({decayOf:xa,rankByDecay:zr})}const ICON = ${JSON.stringify(oe)};${ic}</script>`})}var sc=`
88
+ </div>`,css:Xc,scripts:`<script>${q({decayOf:ka,rankByDecay:Qr})}const ICON = ${JSON.stringify(ie)};${Kc}</script>`})}var Xc=`
89
89
  .bf{max-width:1240px;margin:0 auto;padding:22px 24px 48px}
90
90
  .bf-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
91
91
  .bf :focus-visible{outline:2px solid var(--ax-accent);outline-offset:2px;border-radius:4px}
@@ -361,7 +361,7 @@ button.bf-tag.is-on{background:color-mix(in oklch,var(--ax-accent) 14%,transpare
361
361
  .bf{padding:16px 14px 36px}
362
362
  .bf-head{flex-direction:column;gap:14px;align-items:stretch}
363
363
  .bf-sync{justify-content:space-between}
364
- }`,ic=String.raw`
364
+ }`,Kc=String.raw`
365
365
  (function(){
366
366
  const $=id=>document.getElementById(id), esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
367
367
  const ic=(n,s)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+(s||14)+'" height="'+(s||14)+'" aria-hidden="true">'+ICON[n]+'</svg>';
@@ -776,22 +776,22 @@ if(document.querySelector('form :focus'))return;
776
776
  if(document.querySelector('.bf-trace[open]'))return; // don't yank an open trace
777
777
  refresh();
778
778
  },15000);
779
- })();`;function va(t,e=20*6e4,a=6){let n=[...t].sort((l,c)=>l.startedAt-c.startedAt);if(!n.length)return{bands:[],gaps:[]};let r=[];for(let l of n){let c=l.startedAt+Math.max(l.durationMs||0,0),p=r[r.length-1];p&&l.startedAt-p.to<=e?(p.to=Math.max(p.to,c),p.runs++):r.push({from:l.startedAt,to:c,runs:1})}for(;r.length>a;){let l=0,c=1/0;for(let p=1;p<r.length;p++){let u=r[p].from-r[p-1].to;u<c&&(c=u,l=p)}r[l-1].to=r[l].to,r[l-1].runs+=r[l].runs,r.splice(l,1)}let o=r.reduce((l,c)=>l+c.runs,0)||1,s=r.map(l=>({from:l.from,to:Math.max(l.to,l.from+1),weight:l.runs/o,runs:l.runs})),i=r.slice(1).map((l,c)=>l.from-r[c].to);return{bands:s,gaps:i}}function ba(t){let e=[];for(let a of t.sort((n,r)=>n.startedAt-r.startedAt)){let n=a.startedAt+Math.max(a.durationMs||0,0),r=e.findIndex(o=>o<=a.startedAt);r===-1?(r=e.length,e.push(n)):e[r]=n,a.track=r}return Math.max(e.length,1)}function Fr(t,e=[],a){let{bands:n,gaps:r}=va(t,a);if(!n.length)return{bands:[],gaps:[],lanes:[],from:0,to:0};let o=new Map;for(let l of e){let c=o.get(l.runId);c?c.push(l):o.set(l.runId,[l])}let s=new Map;for(let l of t){let c=n.findIndex(v=>l.startedAt>=v.from&&l.startedAt<=v.to);if(c===-1)continue;let p=n[c],u=p.to-p.from||1,m=(l.startedAt-p.from)/u*100,h=Math.min(Math.max((l.durationMs||0)/u*100,1.2),100-m),_=s.get(l.laneKey)??{key:l.laneKey,label:l.laneLabel,sub:l.laneSub,tracks:1,runs:[]};_.runs.push({...l,band:c,track:0,left:m,width:h,marks:o.get(l.id)??[]}),s.set(l.laneKey,_)}let i=[...s.values()];for(let l of i)l.tracks=Math.max(...n.map((c,p)=>ba(l.runs.filter(u=>u.band===p))),1);return i.sort((l,c)=>c.runs.length-l.runs.length||l.label.localeCompare(c.label)),{bands:n,gaps:r,lanes:i,from:n[0].from,to:n[n.length-1].to}}import{createHash as lc}from"crypto";import{readFileSync as cc,statSync as dc}from"fs";import{resolve as pc,dirname as uc}from"path";import{fileURLToPath as mc}from"url";var Ur=new Map;function Pt(t){let e=Ur.get(t);if(e)return e;let a=`/assets/${t}`;try{let n=uc(mc(import.meta.url)),r=pc(n,"web",t),o=dc(r),s=o.size<8e6?lc("sha1").update(cc(r)).digest("hex").slice(0,10):`${o.size}-${Math.floor(o.mtimeMs)}`;a=`/assets/${t}?v=${s}`}catch{}return Ur.set(t,a),a}var se={refresh:'<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>',bot:'<rect x="4" y="8" width="16" height="12" rx="2"/><path d="M12 8V5M9 14h.01M15 14h.01"/>',user:'<circle cx="12" cy="8" r="3.5"/><path d="M5 21a7 7 0 0 1 14 0"/>',folder:'<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',map:'<path d="M9 4 3 6v14l6-2 6 2 6-2V4l-6 2-6-2z"/><path d="M9 4v14M15 6v14"/>',timeline:'<path d="M3 6h10M7 12h14M3 18h8"/>',mesh:'<circle cx="5" cy="19" r="2.5"/><circle cx="19" cy="19" r="2.5"/><circle cx="12" cy="5" r="2.5"/><path d="M7 17.5l4-10M17 17.5l-4-10"/>',route:'<circle cx="6" cy="6" r="3"/><circle cx="18" cy="18" r="3"/><path d="M9 6h6a3 3 0 0 1 0 6H9a3 3 0 0 0 0 6h6"/>',clock:'<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',x:'<path d="M18 6L6 18M6 6l12 12"/>',alert:'<path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/>'},jt=(t,e=14)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+e+'" height="'+e+'" aria-hidden="true">'+t+"</svg>",fc=[["agent","Agent",se.bot],["client","Client",se.user],["project","Project",se.folder],["channel","Channel",se.route],["person","Person",se.user],["node","Node",se.mesh]],Wr={timeline:"Every run on the mesh, from task traces. The axis breaks over silence &mdash; quiet stretches are labelled, not drawn.",map:"The fleet as a transit map: projects are lines, agents are stations, work in flight is a train. Live."};function Gr(t={}){let e=t.view==="map"?"map":"timeline",a=e==="map";return M({title:"AgentX \xB7 Activity",activeTab:"activity",subtitle:"Activity",peers:t.peers,body:`<div class="ac">
779
+ })();`;function _a(t,e=20*6e4,a=6){let n=[...t].sort((l,c)=>l.startedAt-c.startedAt);if(!n.length)return{bands:[],gaps:[]};let r=[];for(let l of n){let c=l.startedAt+Math.max(l.durationMs||0,0),d=r[r.length-1];d&&l.startedAt-d.to<=e?(d.to=Math.max(d.to,c),d.runs++):r.push({from:l.startedAt,to:c,runs:1})}for(;r.length>a;){let l=0,c=1/0;for(let d=1;d<r.length;d++){let p=r[d].from-r[d-1].to;p<c&&(c=p,l=d)}r[l-1].to=r[l].to,r[l-1].runs+=r[l].runs,r.splice(l,1)}let o=r.reduce((l,c)=>l+c.runs,0)||1,s=r.map(l=>({from:l.from,to:Math.max(l.to,l.from+1),weight:l.runs/o,runs:l.runs})),i=r.slice(1).map((l,c)=>l.from-r[c].to);return{bands:s,gaps:i}}function Sa(t){let e=[];for(let a of t.sort((n,r)=>n.startedAt-r.startedAt)){let n=a.startedAt+Math.max(a.durationMs||0,0),r=e.findIndex(o=>o<=a.startedAt);r===-1?(r=e.length,e.push(n)):e[r]=n,a.track=r}return Math.max(e.length,1)}function eo(t,e=[],a){let{bands:n,gaps:r}=_a(t,a);if(!n.length)return{bands:[],gaps:[],lanes:[],from:0,to:0};let o=new Map;for(let l of e){let c=o.get(l.runId);c?c.push(l):o.set(l.runId,[l])}let s=new Map;for(let l of t){let c=n.findIndex(b=>l.startedAt>=b.from&&l.startedAt<=b.to);if(c===-1)continue;let d=n[c],p=d.to-d.from||1,m=(l.startedAt-d.from)/p*100,f=Math.min(Math.max((l.durationMs||0)/p*100,1.2),100-m),S=s.get(l.laneKey)??{key:l.laneKey,label:l.laneLabel,sub:l.laneSub,tracks:1,runs:[]};S.runs.push({...l,band:c,track:0,left:m,width:f,marks:o.get(l.id)??[]}),s.set(l.laneKey,S)}let i=[...s.values()];for(let l of i)l.tracks=Math.max(...n.map((c,d)=>Sa(l.runs.filter(p=>p.band===d))),1);return i.sort((l,c)=>c.runs.length-l.runs.length||l.label.localeCompare(c.label)),{bands:n,gaps:r,lanes:i,from:n[0].from,to:n[n.length-1].to}}import{createHash as Jc}from"crypto";import{readFileSync as Vc,statSync as Yc}from"fs";import{resolve as Qc,dirname as Zc}from"path";import{fileURLToPath as ed}from"url";var to=new Map;function Nt(t){let e=to.get(t);if(e)return e;let a=`/assets/${t}`;try{let n=Zc(ed(import.meta.url)),r=Qc(n,"web",t),o=Yc(r),s=o.size<8e6?Jc("sha1").update(Vc(r)).digest("hex").slice(0,10):`${o.size}-${Math.floor(o.mtimeMs)}`;a=`/assets/${t}?v=${s}`}catch{}return to.set(t,a),a}var le={refresh:'<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>',bot:'<rect x="4" y="8" width="16" height="12" rx="2"/><path d="M12 8V5M9 14h.01M15 14h.01"/>',user:'<circle cx="12" cy="8" r="3.5"/><path d="M5 21a7 7 0 0 1 14 0"/>',folder:'<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',map:'<path d="M9 4 3 6v14l6-2 6 2 6-2V4l-6 2-6-2z"/><path d="M9 4v14M15 6v14"/>',timeline:'<path d="M3 6h10M7 12h14M3 18h8"/>',mesh:'<circle cx="5" cy="19" r="2.5"/><circle cx="19" cy="19" r="2.5"/><circle cx="12" cy="5" r="2.5"/><path d="M7 17.5l4-10M17 17.5l-4-10"/>',route:'<circle cx="6" cy="6" r="3"/><circle cx="18" cy="18" r="3"/><path d="M9 6h6a3 3 0 0 1 0 6H9a3 3 0 0 0 0 6h6"/>',clock:'<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',x:'<path d="M18 6L6 18M6 6l12 12"/>',alert:'<path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/>'},Dt=(t,e=14)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+e+'" height="'+e+'" aria-hidden="true">'+t+"</svg>",td=[["agent","Agent",le.bot],["client","Client",le.user],["project","Project",le.folder],["channel","Channel",le.route],["person","Person",le.user],["node","Node",le.mesh]],ao={timeline:"Every run on the mesh, from task traces. The axis breaks over silence &mdash; quiet stretches are labelled, not drawn.",map:"The fleet as a transit map: projects are lines, agents are stations, work in flight is a train. Live."};function no(t={}){let e=t.view==="map"?"map":"timeline",a=e==="map";return I({title:"AgentX \xB7 Activity",activeTab:"activity",subtitle:"Activity",peers:t.peers,body:`<div class="ac">
780
780
 
781
781
  <div class="ac-head">
782
782
  <div>
783
783
  <div class="ac-kicker">Operations</div>
784
784
  <h1>What ran, where, and what it decided</h1>
785
- <p class="ac-sub" id="sub">${Wr[e]}</p>
785
+ <p class="ac-sub" id="sub">${ao[e]}</p>
786
786
  </div>
787
787
  <div class="ac-tools">
788
788
  <div class="ac-seg" id="view" role="radiogroup" aria-label="View">
789
- ${[["timeline","Timeline",se.timeline],["map","Map",se.map]].map(([n,r,o])=>`<button type="button" role="radio" data-value="${n}" aria-checked="${n===e}"${n===e?' class="is-on"':""}>${jt(o,13)}${r}</button>`).join("")}
789
+ ${[["timeline","Timeline",le.timeline],["map","Map",le.map]].map(([n,r,o])=>`<button type="button" role="radio" data-value="${n}" aria-checked="${n===e}"${n===e?' class="is-on"':""}>${Dt(o,13)}${r}</button>`).join("")}
790
790
  </div>
791
791
  <div class="ac-seg" id="hours" role="radiogroup" aria-label="Window">
792
792
  ${[["6","6h"],["24","24h"],["72","3d"],["168","7d"]].map(([n,r],o)=>`<button type="button" role="radio" data-value="${n}" aria-checked="${o===1}"${o===1?' class="is-on"':""}>${r}</button>`).join("")}
793
793
  </div>
794
- <button class="ax-btn ax-btn--sm" id="refresh"${a?" hidden":""}>${jt(se.refresh,13)} Refresh</button>
794
+ <button class="ax-btn ax-btn--sm" id="refresh"${a?" hidden":""}>${Dt(le.refresh,13)} Refresh</button>
795
795
  </div>
796
796
  </div>
797
797
 
@@ -799,14 +799,14 @@ refresh();
799
799
  <div class="ac-bar">
800
800
  <span class="ac-lbl">Lanes by</span>
801
801
  <div class="ac-seg" id="persp" role="radiogroup" aria-label="Perspective">
802
- ${fc.map(([n,r,o],s)=>`<button type="button" role="radio" data-value="${n}" aria-checked="${s===0}"${s===0?' class="is-on"':""}>${jt(o,13)}${r}</button>`).join("")}
802
+ ${td.map(([n,r,o],s)=>`<button type="button" role="radio" data-value="${n}" aria-checked="${s===0}"${s===0?' class="is-on"':""}>${Dt(o,13)}${r}</button>`).join("")}
803
803
  </div>
804
804
  <div class="ac-key">
805
805
  <span class="ac-k"><i class="ac-d ac-d--decision"></i>decision</span>
806
806
  <span class="ac-k"><i class="ac-d ac-d--warning"></i>warning</span>
807
807
  <span class="ac-k"><i class="ac-d ac-d--recommendation"></i>friction</span>
808
808
  <span class="ac-k"><i class="ac-d ac-d--later"></i>do later</span>
809
- <span class="ac-k">${jt(se.x,11)}canceled</span>
809
+ <span class="ac-k">${Dt(le.x,11)}canceled</span>
810
810
  </div>
811
811
  </div>
812
812
 
@@ -816,10 +816,10 @@ refresh();
816
816
  </div>
817
817
 
818
818
  <div id="view-map" class="ac-map"${a?"":" hidden"}>
819
- <div id="ax-fleet-root" data-hours="24" data-src="${Pt("activity-graph.global.js")}"></div>
819
+ <div id="ax-fleet-root" data-hours="24" data-src="${Nt("activity-graph.global.js")}"></div>
820
820
  </div>
821
821
 
822
- </div>`,css:hc,scripts:`<script>${B({computeBands:va,packTracks:ba,buildTimeline:Fr})}const ICON = ${JSON.stringify(se)};const SUB = ${JSON.stringify(Wr)};${gc}</script>`})}var hc=`
822
+ </div>`,css:ad,scripts:`<script>${q({computeBands:_a,packTracks:Sa,buildTimeline:eo})}const ICON = ${JSON.stringify(le)};const SUB = ${JSON.stringify(ao)};${nd}</script>`})}var ad=`
823
823
  .ac{max-width:1440px;margin:0 auto;padding:22px 24px 48px}
824
824
  .ac :focus-visible{outline:2px solid var(--ax-accent);outline-offset:2px;border-radius:4px}
825
825
  .ac-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:14px}
@@ -905,7 +905,7 @@ refresh();
905
905
  @media (max-width:640px){.ac{padding:16px 16px 32px}.ac-head{flex-direction:column;gap:10px}
906
906
  .ac-tools{flex-wrap:wrap;padding-top:0}.ac-map{height:calc(100vh - 250px);margin:0 -16px;
907
907
  border-left:none;border-right:none;border-radius:0}}
908
- `,gc=String.raw`
908
+ `,nd=String.raw`
909
909
  const $=id=>document.getElementById(id);
910
910
  const esc=s=>String(s==null?'':s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
911
911
  const ic=(n,s)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+(s||14)+'" height="'+(s||14)+'" aria-hidden="true">'+ICON[n]+'</svg>';
@@ -1024,7 +1024,7 @@ history.replaceState(null,'',u);
1024
1024
  if(v==='map')ensureMap();else if(!loaded){loaded=true;load();}}
1025
1025
  $('view').addEventListener('click',e=>{const b=e.target.closest('button[data-value]');if(!b||b.dataset.value===view)return;show(b.dataset.value);});
1026
1026
  show(view);
1027
- `;function Xr(t={}){let e='<div id="wfe-root" style="height:100%"></div>';return M({title:"AgentX \xB7 Workflow editor",activeTab:"workflows",subtitle:"Workflow editor",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:xc,scripts:`<script src="${Pt("workflow-editor.global.js")}" defer></script>`,noMain:!0})}var xc=`
1027
+ `;function ro(t={}){let e='<div id="wfe-root" style="height:100%"></div>';return I({title:"AgentX \xB7 Workflow editor",activeTab:"workflows",subtitle:"Workflow editor",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:rd,scripts:`<script src="${Nt("workflow-editor.global.js")}" defer></script>`,noMain:!0})}var rd=`
1028
1028
  /* Preload the fonts the redesign's CSS references. Placed in the shell so
1029
1029
  * they start fetching while the React bundle is still parsing. */
1030
1030
  @import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Instrument+Serif&display=swap");
@@ -1045,11 +1045,11 @@ body { margin: 0; overflow: hidden; }
1045
1045
  font: 13px/1 -apple-system, BlinkMacSystemFont, sans-serif;
1046
1046
  text-align: center;
1047
1047
  }
1048
- `;import{createServer as lf}from"http";import{appendFileSync as cf,existsSync as Wl,mkdirSync as df}from"fs";import{readFile as pf}from"fs/promises";import{fileURLToPath as uf}from"url";import{dirname as mf,resolve as ot}from"path";oc();function Be(t,e){if(!t)return"absent";let a=Un(t),n=e.list().find(r=>r.hash===a);return n&&(n.revokedAt||n.expiresAt&&Date.parse(n.expiresAt)<Date.now())?"revoked":"invalid"}var Te=class{constructor(e=r=>console.log(r),a=Date.now,n=6e4){this.log=e;this.now=a;this.everyMs=n}last=new Map;record(e,a){let n=Object.entries(a).map(([i,l])=>`${i}=${l}`).join(" "),r=`${e} ${a.cookie??""} ${a.bearer??""}`,o=this.now(),s=this.last.get(r);s!==void 0&&o-s<this.everyMs||(this.last.size>500&&this.prune(o),this.last.set(r,o),this.log(`[app] unauthenticated ${e} ${n}`))}prune(e){for(let[a,n]of this.last)e-n>=this.everyMs&&this.last.delete(a);this.last.size>500&&this.last.clear()}};function Ot(t,e,a){let n={cookie:e};return a&&(n.bearer=a),n.mode=Kr(t.headers["sec-fetch-mode"]),n.site=Kr(t.headers["sec-fetch-site"]),n}function Kr(t){let e=Array.isArray(t)?t[0]:t;return e&&/^[a-z-]{1,20}$/.test(e)?e:"-"}import{deflateSync as vc}from"zlib";var bc=[41,121,255],yc=[255,255,255],Jr=new Map;function ze(t){let e=Jr.get(t);return e||(e=kc(t,wc(t)),Jr.set(t,e)),e}function wc(t){let e=1+t*3,a=Buffer.alloc(e*t),n=t/2,r=t*.22;for(let o=0;o<t;o++)for(let s=0;s<t;s++){let i=s+.5-n,l=o+.5-n,c=i*i+l*l<=r*r?yc:bc;a.set(c,o*e+1+s*3)}return a}function kc(t,e){let a=Buffer.alloc(13);return a.writeUInt32BE(t,0),a.writeUInt32BE(t,4),a[8]=8,a[9]=2,Buffer.concat([Buffer.from([137,80,78,71,13,10,26,10]),ya("IHDR",a),ya("IDAT",vc(e)),ya("IEND",Buffer.alloc(0))])}function ya(t,e){let a=Buffer.alloc(4);a.writeUInt32BE(e.length);let n=Buffer.concat([Buffer.from(t,"ascii"),e]),r=Buffer.alloc(4);return r.writeUInt32BE(Sc(n)),Buffer.concat([a,n,r])}var _c=Array.from({length:256},(t,e)=>{let a=e;for(let n=0;n<8;n++)a=a&1?3988292384^a>>>1:a>>>1;return a>>>0});function Sc(t){let e=4294967295;for(let a of t)e=_c[(e^a)&255]^e>>>8;return(e^4294967295)>>>0}ut();rc();var Nt=7,Ec=["waiting_owner","needs_attention"],Tc={gitlab:"GitLab",github:"GitHub",telegram:"Telegram",whatsapp:"WhatsApp",slack:"Slack",discord:"Discord",voice:"Voice",app:"Phone app",dashboard:"Dashboard",webrtc:"Call"};function qe(t,e){let a=t.toLowerCase().split("@")[0],n=Tc[a]??t,r=/^(.+):(issue|merge_request|pull):(\d+)$/.exec(e);if(r){let o=r[2]==="issue"?"issue":r[2]==="pull"?"pull request":"merge request";return`${n} ${o} #${r[3]} in ${r[1]}`}return n}function Vr(t,e,a){let n=t.toLowerCase().split("@")[0],r=/^(.+):(issue|merge_request|pull):(\d+)$/.exec(e);if(!r)return null;let[,o,s,i]=r;return n==="gitlab"?`${(a.gitlab||"https://gitlab.com").replace(/\/+$/,"")}/${o}/-/${s==="issue"?"issues":"merge_requests"}/${i}`:n==="github"?`${(a.github||"https://github.com").replace(/\/+$/,"")}/${o}/${s==="issue"?"issues":"pull"}/${i}`:null}function Yr(t,e,a={}){let n=a.now??Date.now(),s=(t.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'requests'").get()?t.prepare("PRAGMA table_info(requests)").all():[]).some(v=>v.name==="person"),i=v=>({id:v.id,state:v.state,agentId:v.agent_id,text:v.text,channel:v.channel,chatId:v.chat_id,createdAt:v.created_at,updatedAt:v.updated_at,closedAt:v.closed_at??null,question:v.question??null,attentionReason:v.attention_reason??null,evidence:v.evidence??null,where:{label:qe(v.channel,v.chat_id),url:a.linkFor?.(v.channel,v.chat_id)??null}}),l=s?t.prepare(`SELECT * FROM requests WHERE person = ? AND state IN (${da.map(()=>"?").join(",")}) ORDER BY created_at, rowid`).all(e,...da).map(i):[],c=s?t.prepare(`SELECT * FROM requests WHERE person = ? AND state IN (${pa.map(()=>"?").join(",")}) AND COALESCE(closed_at, updated_at) >= ?
1049
- ORDER BY COALESCE(closed_at, updated_at) DESC LIMIT 50`).all(e,...pa,n-Nt*864e5).map(i):[],p=[];try{p=Rt(t,e,50).filter(v=>v.startedAt>=n-Nt*864e5)}catch{}let u=new Map;if(s&&p.length){let v=t.prepare(`SELECT l.ref, r.id, r.state, r.evidence FROM request_links l JOIN requests r ON r.id = l.request_id
1050
- WHERE l.kind = 'run' AND r.person = ? AND l.ref IN (${p.map(()=>"?").join(",")})`).all(e,...p.map(S=>S.taskId));for(let S of v)u.set(S.ref,{id:S.id,state:S.state,evidence:S.evidence??null})}let m=p.map(v=>({...v,where:v.channel?{label:qe(v.channel,v.chatId??""),url:a.linkFor?.(v.channel,v.chatId??"")??null}:null,request:u.get(v.taskId)??null})),h=new Set(m.map(v=>v.request?.id).filter(Boolean)),_=[...l.filter(v=>!Ec.includes(v.state)),...c].filter(v=>!h.has(v.id));return{open:l,recent:c,runs:m,other:_}}ua();nc();var Qr={waiting:0,yours:0,ahead:null};function Zr(t,e,a={}){let n=_n(t),r=new Map,o=[],s=new Map;for(let i of n){let l=`${i.agentId}\0${i.channel}\0${i.chatId}`,c=s.get(l)??0;s.set(l,c+1);let p=r.get(i.agentId)??{waiting:0,yours:0,ahead:null};p.waiting++,i.person===e&&(p.yours++,p.ahead===null&&(p.ahead=c),o.push({agentId:i.agentId,channel:i.channel,chatId:i.chatId,queuedAt:i.queuedAt,messagePreview:i.messagePreview,where:{label:qe(i.channel,i.chatId),url:a.linkFor?.(i.channel,i.chatId)??null},ahead:c})),r.set(i.agentId,p)}return{byAgent:r,mine:o}}var Ac=4e3;function eo(t,e,a){return e.agents?.length?[...e.agents]:t.prepare(`SELECT agent_id, MAX(started_at) AS last FROM task_traces
1048
+ `;import{createServer as mh}from"http";import{appendFileSync as fh,existsSync as $c,mkdirSync as hh}from"fs";import{readFile as gh}from"fs/promises";import{fileURLToPath as xh}from"url";import{dirname as bh,resolve as ct}from"path";On();function Ue(t,e){if(!t)return"absent";let a=tr(t),n=e.list().find(r=>r.hash===a);return n&&(n.revokedAt||n.expiresAt&&Date.parse(n.expiresAt)<Date.now())?"revoked":"invalid"}var Le=class{constructor(e=r=>console.log(r),a=Date.now,n=6e4){this.log=e;this.now=a;this.everyMs=n}last=new Map;record(e,a){let n=Object.entries(a).map(([i,l])=>`${i}=${l}`).join(" "),r=`${e} ${a.cookie??""} ${a.bearer??""}`,o=this.now(),s=this.last.get(r);s!==void 0&&o-s<this.everyMs||(this.last.size>500&&this.prune(o),this.last.set(r,o),this.log(`[app] unauthenticated ${e} ${n}`))}prune(e){for(let[a,n]of this.last)e-n>=this.everyMs&&this.last.delete(a);this.last.size>500&&this.last.clear()}};function Ht(t,e,a){let n={cookie:e};return a&&(n.bearer=a),n.mode=oo(t.headers["sec-fetch-mode"]),n.site=oo(t.headers["sec-fetch-site"]),n}function oo(t){let e=Array.isArray(t)?t[0]:t;return e&&/^[a-z-]{1,20}$/.test(e)?e:"-"}import{deflateSync as id}from"zlib";var od=[[[441,393],[600,393],[614,396],[625,401],[634,410],[1028,940],[846,940],[833,937],[823,931],[818,925],[440,414],[435,406],[436,398]],[[893,393],[1079,393],[861,653],[771,535]],[[413,439],[510,574],[282,874],[100,874]],[[451,709],[610,709],[615,712],[698,824],[599,939],[447,719],[446,713]]],ke={x:100,y:393,width:979,height:547},Ea="#1a1a18",Ta="#ffffff",so=Math.hypot(ke.width,ke.height)/2/ke.width,Bt={full:.74,safe:.37/so,android:.29/so,mac:.6};function Aa(t,e){let a=t*e/ke.width,n=t/2-(ke.x+ke.width/2)*a,r=t/2-(ke.y+ke.height/2)*a;return od.map(o=>o.map(([s,i])=>[s*a+n,i*a+r]))}function sd(t,e){let a=n=>String(Math.round(n*100)/100);return Aa(t,e).map(n=>"M"+n.map(([r,o])=>`${a(r)},${a(o)}`).join("L")+"Z").join("")}function io(t=64,e=Bt.full){return`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${t} ${t}"><rect width="${t}" height="${t}" rx="${t*.18}" fill="${Ta}"/><path fill="${Ea}" d="${sd(t,e)}"/></svg>`}var ld=go(Ea),lo=go(Ta),co=new Map;function We(t){let e=co.get(t);return e||(e=ho({size:t,width:Bt.safe,background:"square"}),co.set(t,e)),e}var cd=io();function fo(t){return t==="/favicon.svg"?{type:"image/svg+xml",body:cd}:t==="/favicon.ico"?{type:"image/png",body:uo(32)}:t==="/apple-touch-icon.png"?{type:"image/png",body:uo(180)}:null}var po=new Map;function uo(t){let e=po.get(t);return e||(e=ho({size:t,width:Bt.full,background:"square"}),po.set(t,e)),e}function ho(t){let{size:e}=t,a=t.background==="mac"?mo(e,[dd(e)]):null,n=mo(e,Aa(e,t.width)),r=1+e*4,o=Buffer.alloc(r*e);for(let s=0;s<e;s++)for(let i=0;i<e;i++){let l=s*e+i,c=n[l],d=s*r+1+i*4;for(let p=0;p<3;p++)o[d+p]=Math.round(lo[p]+(ld[p]-lo[p])*c);o[d+3]=Math.round(255*(a?a[l]:1))}return pd(e,o)}function dd(t){let e=t/1024,a=100*e,n=924*e,r=185*e,o=[],s=[[n-r,a+r,-90],[n-r,n-r,0],[a+r,n-r,90],[a+r,a+r,180]];for(let[i,l,c]of s)for(let d=0;d<=12;d++){let p=(c+90*d/12)*Math.PI/180;o.push([i+r*Math.cos(p),l+r*Math.sin(p)])}return o}var Ca=8;function mo(t,e){let a=new Float32Array(t*t),n=[];for(let o of e)for(let s=0;s<o.length;s++){let[i,l]=o[s],[c,d]=o[(s+1)%o.length];l!==d&&n.push([i,l,c,d])}let r=[];for(let o=0;o<t;o++)for(let s=0;s<Ca;s++){let i=o+(s+.5)/Ca;r.length=0;for(let[l,c,d,p]of n)(i>=c&&i<p||i>=p&&i<c)&&r.push(l+(i-c)*(d-l)/(p-c));r.sort((l,c)=>l-c);for(let l=0;l+1<r.length;l+=2){let c=Math.max(0,r[l]),d=Math.min(t,r[l+1]);for(let p=Math.floor(c);p<d;p++){let m=Math.min(p+1,d)-Math.max(p,c);m>0&&(a[o*t+p]+=m/Ca)}}}for(let o=0;o<a.length;o++)a[o]>1&&(a[o]=1);return a}function go(t){let e=parseInt(t.slice(1),16);return[e>>16&255,e>>8&255,e&255]}function pd(t,e){let a=Buffer.alloc(13);return a.writeUInt32BE(t,0),a.writeUInt32BE(t,4),a[8]=8,a[9]=6,Buffer.concat([Buffer.from([137,80,78,71,13,10,26,10]),Ia("IHDR",a),Ia("IDAT",id(e)),Ia("IEND",Buffer.alloc(0))])}function Ia(t,e){let a=Buffer.alloc(4);a.writeUInt32BE(e.length);let n=Buffer.concat([Buffer.from(t,"ascii"),e]),r=Buffer.alloc(4);return r.writeUInt32BE(md(n)),Buffer.concat([a,n,r])}var ud=Array.from({length:256},(t,e)=>{let a=e;for(let n=0;n<8;n++)a=a&1?3988292384^a>>>1:a>>>1;return a>>>0});function md(t){let e=4294967295;for(let a of t)e=ud[(e^a)&255]^e>>>8;return(e^4294967295)>>>0}gt();Gc();var zt=7,fd=["waiting_owner","needs_attention"],hd={gitlab:"GitLab",github:"GitHub",telegram:"Telegram",whatsapp:"WhatsApp",slack:"Slack",discord:"Discord",voice:"Voice",app:"Phone app",dashboard:"Dashboard",webrtc:"Call"};function Ge(t,e){let a=t.toLowerCase().split("@")[0],n=hd[a]??t,r=/^(.+):(issue|merge_request|pull):(\d+)$/.exec(e);if(r){let o=r[2]==="issue"?"issue":r[2]==="pull"?"pull request":"merge request";return`${n} ${o} #${r[3]} in ${r[1]}`}return n}function xo(t,e,a){let n=t.toLowerCase().split("@")[0],r=/^(.+):(issue|merge_request|pull):(\d+)$/.exec(e);if(!r)return null;let[,o,s,i]=r;return n==="gitlab"?`${(a.gitlab||"https://gitlab.com").replace(/\/+$/,"")}/${o}/-/${s==="issue"?"issues":"merge_requests"}/${i}`:n==="github"?`${(a.github||"https://github.com").replace(/\/+$/,"")}/${o}/${s==="issue"?"issues":"pull"}/${i}`:null}function bo(t,e,a={}){let n=a.now??Date.now(),s=(t.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'requests'").get()?t.prepare("PRAGMA table_info(requests)").all():[]).some(b=>b.name==="person"),i=b=>({id:b.id,state:b.state,agentId:b.agent_id,text:b.text,channel:b.channel,chatId:b.chat_id,createdAt:b.created_at,updatedAt:b.updated_at,closedAt:b.closed_at??null,question:b.question??null,attentionReason:b.attention_reason??null,evidence:b.evidence??null,where:{label:Ge(b.channel,b.chat_id),url:a.linkFor?.(b.channel,b.chat_id)??null}}),l=s?t.prepare(`SELECT * FROM requests WHERE person = ? AND state IN (${fa.map(()=>"?").join(",")}) ORDER BY created_at, rowid`).all(e,...fa).map(i):[],c=s?t.prepare(`SELECT * FROM requests WHERE person = ? AND state IN (${ha.map(()=>"?").join(",")}) AND COALESCE(closed_at, updated_at) >= ?
1049
+ ORDER BY COALESCE(closed_at, updated_at) DESC LIMIT 50`).all(e,...ha,n-zt*864e5).map(i):[],d=[];try{d=jt(t,e,50).filter(b=>b.startedAt>=n-zt*864e5)}catch{}let p=new Map;if(s&&d.length){let b=t.prepare(`SELECT l.ref, r.id, r.state, r.evidence FROM request_links l JOIN requests r ON r.id = l.request_id
1050
+ WHERE l.kind = 'run' AND r.person = ? AND l.ref IN (${d.map(()=>"?").join(",")})`).all(e,...d.map(E=>E.taskId));for(let E of b)p.set(E.ref,{id:E.id,state:E.state,evidence:E.evidence??null})}let m=d.map(b=>({...b,where:b.channel?{label:Ge(b.channel,b.chatId??""),url:a.linkFor?.(b.channel,b.chatId??"")??null}:null,request:p.get(b.taskId)??null})),f=new Set(m.map(b=>b.request?.id).filter(Boolean)),S=[...l.filter(b=>!fd.includes(b.state)),...c].filter(b=>!f.has(b.id));return{open:l,recent:c,runs:m,other:S}}xa();Wc();var vo={waiting:0,yours:0,ahead:null};function yo(t,e,a={}){let n=Pn(t),r=new Map,o=[],s=new Map;for(let i of n){let l=`${i.agentId}\0${i.channel}\0${i.chatId}`,c=s.get(l)??0;s.set(l,c+1);let d=r.get(i.agentId)??{waiting:0,yours:0,ahead:null};d.waiting++,i.person===e&&(d.yours++,d.ahead===null&&(d.ahead=c),o.push({agentId:i.agentId,channel:i.channel,chatId:i.chatId,queuedAt:i.queuedAt,messagePreview:i.messagePreview,where:{label:Ge(i.channel,i.chatId),url:a.linkFor?.(i.channel,i.chatId)??null},ahead:c})),r.set(i.agentId,d)}return{byAgent:r,mine:o}}var gd=4e3;function wo(t,e,a){return e.agents?.length?[...e.agents]:t.prepare(`SELECT agent_id, MAX(started_at) AS last FROM task_traces
1051
1051
  WHERE person = ? AND started_at >= ? AND (channel IS NULL OR channel != 'a2a')
1052
- GROUP BY agent_id ORDER BY last DESC LIMIT 12`).all(e.id,a-Nt*864e5).map(r=>r.agent_id)}function to(t,e,a,n){let r=new Set(n.people.filter(l=>l.role==="owner").map(l=>l.id));r.add(pt);let o=l=>l===e?"you":l&&r.has(l)?"owner":"other",s=t.prepare("SELECT * FROM task_traces WHERE agent_id = ? AND status = 'in-flight' ORDER BY started_at DESC, rowid DESC LIMIT 1"),i=t.prepare("SELECT * FROM task_traces WHERE agent_id = ? AND status != 'in-flight' ORDER BY started_at DESC, rowid DESC LIMIT 1");return a.map(l=>{let c=n.queue?.get(l)??Qr,p=s.get(l),u=p??i.get(l);if(!u)return{agentId:l,state:"free",by:null,at:null,text:null,fullText:null,where:null,queue:c};let m=o(u.person??null),h=u.status==="error"||u.status==="timeout",_=p?"working":h&&m==="you"?"blocked":"free",v=m==="you"&&u.channel!=="a2a",S=v&&u.channel;return{agentId:l,state:_,by:m,at:p?u.started_at:u.finished_at??u.started_at,text:p||v?u.message_preview??null:null,fullText:v&&p&&String(u.original_message??u.message_preview??"").slice(0,Ac)||null,where:S?{label:qe(u.channel,u.chat_id??""),url:n.linkFor?.(u.channel,u.chat_id??"")??null}:null,queue:c}})}function ao(t){return t>=200&&t<300?"retry":t===401?"lock":"keep"}function no(t,e){return!t||e-t>=3e4||t>e}function Dt(t,e){let a="23456789ABCDEFGHJKMNPQRSTUVWXYZ",n=String(t||"").toUpperCase(),r=Math.max(0,Math.min(Number(e)||0,n.length)),o="",s=0;for(let l=0;l<n.length&&o.length<8;l++)a.indexOf(n.charAt(l))<0||(o+=n.charAt(l),l<r&&s++);let i=o.length>4?o.slice(0,4)+"-"+o.slice(4):o;return{value:i,caret:Math.min(s>4?s+1:s,i.length)}}function ro(t){let e=String(t||"").trim(),a=/^https?:[/][/][^/#?]+[/]app[/]pair[/]?#(.*)$/i.exec(e);if(a){let r=a[1].split("&");for(let o=0;o<r.length;o++){if(r[o].indexOf("token=")!==0)continue;let s="";try{s=decodeURIComponent(r[o].slice(6))}catch{return{kind:"none"}}return/^agx_live_[0-9a-f]{64}$/.test(s)?{kind:"token",token:s}:{kind:"none"}}return{kind:"none"}}let n=e.toUpperCase();return/^[A-Z0-9]{4}-?[A-Z0-9]{4}$/.test(n)?{kind:"code",code:n.slice(0,4)+"-"+n.slice(-4)}:{kind:"none"}}function Ht(t,e,a,n){return t?e?{text:"Can't reach the server. "+(n?"Showing what was last loaded. ":"")+"Trying again every "+a+" seconds.",retry:!0}:{text:"Offline. Showing what was last loaded; live state needs a connection.",retry:!1}:null}function Bt(t){return String(t??"").replace(/```[\w-]*|`/g,"").replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^[ \t]*(?:#{1,6}|>+|[-*+]|\d+[.)])[ \t]+(?:\[[ xX]\][ \t]+)?/gm,"").replace(/\*\*|~~/g,"").replace(/(^|[\s(])\*(\S(?:[^*\n]*\S)?)\*(?=[\s).,;:!?]|$)/gm,"$1$2").replace(/\s+/g," ").trim()}function oo(t){let e=t.by==="you"?"you":t.by==="owner"?"the owner":t.by?"someone else":null;if(t.state==="working"){let a=t.queue||{waiting:0,yours:0,ahead:null},n=a.ahead||0,r;return a.yours>0?r=(a.yours===1?"Your message is in line":a.yours+" messages of yours are in line")+(n===0?a.yours===1?": it runs when this ends.":": the first runs when this ends.":", "+n+(n===1?" message":" messages")+" ahead of "+(a.yours===1?"it.":"the first.")):a.waiting>0?r=a.waiting+(a.waiting===1?" message waits":" messages wait")+" in line. A new one from you waits behind "+(a.waiting===1?"it.":"them."):r=t.by==="you"?"Busy. A new message waits in line until this ends.":"A message you send now waits in line until this ends.",t.by==="you"?{label:"Working",tone:"work",what:t.text,by:e,hint:r}:{label:"Working",tone:"work",what:t.text||"Busy with someone else's task",by:e,hint:r}}return t.state==="blocked"?{label:"Blocked",tone:"stuck",what:t.text?"Stopped on: "+t.text:null,by:e,hint:"It stopped before finishing. It needs a person."}:{label:"Free",tone:"free",what:t.by==="you"&&t.text?"Finished: "+t.text:null,by:t.by==="you"?e:null,hint:"Free. Ready for your next message."}}function so(t){let e=t.request?t.request.state:"";return e==="waiting_owner"?{label:"Waiting on the owner",tone:"wait"}:e==="waiting_other"?{label:"Waiting on another agent",tone:"wait"}:e==="needs_attention"?{label:"Stuck",tone:"stuck"}:t.status==="queued"?{label:"In line",tone:"wait"}:t.status==="in-flight"?{label:"Running",tone:"work"}:t.status==="ok"?{label:"Finished",tone:"done"}:t.status==="error"||t.status==="timeout"?{label:"Stopped",tone:"stuck"}:t.status==="canceled"||t.status==="cancelled"?{label:"Stopped",tone:"off"}:{label:String(t.status||"").replace(/[_-]/g," "),tone:"off"}}function io(t){return t==="in_progress"?{label:"In progress",tone:"work"}:t==="waiting_owner"?{label:"Waiting on the owner",tone:"wait"}:t==="waiting_other"?{label:"Waiting on another agent",tone:"wait"}:t==="needs_attention"?{label:"Stuck",tone:"stuck"}:t==="done"?{label:"Finished",tone:"done"}:t==="declined"?{label:"Declined",tone:"off"}:t==="dropped"?{label:"Dropped",tone:"off"}:{label:String(t||"").replace(/_/g," "),tone:"off"}}function lo(t,e){if(!t.length&&!e)return"Nothing sent yet.";let a=t.slice(0,4).map(function(n){return n.state==="working"?n.agentId+(n.by==="you"?" is working on your task.":" is busy with someone else's task."):n.state==="blocked"?n.agentId+" stopped on your task.":n.agentId+" is free."});return t.length>4&&a.push(t.length-4+" more below."),a.join(" ")||"Nothing running now."}function co(t,e){if(!t)return[];let a={};return t.forEach(function(n){a[n.agentId]=n.state}),e.filter(function(n){return n.state==="free"&&a[n.agentId]==="working"}).map(function(n){return n.agentId})}var po=`
1052
+ GROUP BY agent_id ORDER BY last DESC LIMIT 12`).all(e.id,a-zt*864e5).map(r=>r.agent_id)}function ko(t,e,a,n){let r=new Set(n.people.filter(l=>l.role==="owner").map(l=>l.id));r.add(ht);let o=l=>l===e?"you":l&&r.has(l)?"owner":"other",s=t.prepare("SELECT * FROM task_traces WHERE agent_id = ? AND status = 'in-flight' ORDER BY started_at DESC, rowid DESC LIMIT 1"),i=t.prepare("SELECT * FROM task_traces WHERE agent_id = ? AND status != 'in-flight' ORDER BY started_at DESC, rowid DESC LIMIT 1");return a.map(l=>{let c=n.queue?.get(l)??vo,d=s.get(l),p=d??i.get(l);if(!p)return{agentId:l,state:"free",by:null,at:null,text:null,fullText:null,where:null,queue:c};let m=o(p.person??null),f=p.status==="error"||p.status==="timeout",S=d?"working":f&&m==="you"?"blocked":"free",b=m==="you"&&p.channel!=="a2a",E=b&&p.channel;return{agentId:l,state:S,by:m,at:d?p.started_at:p.finished_at??p.started_at,text:d||b?p.message_preview??null:null,fullText:b&&d&&String(p.original_message??p.message_preview??"").slice(0,gd)||null,where:E?{label:Ge(p.channel,p.chat_id??""),url:n.linkFor?.(p.channel,p.chat_id??"")??null}:null,queue:c}})}function _o(t){return t>=200&&t<300?"retry":t===401?"lock":"keep"}function So(t,e){return!t||e-t>=3e4||t>e}function qt(t,e){let a="23456789ABCDEFGHJKMNPQRSTUVWXYZ",n=String(t||"").toUpperCase(),r=Math.max(0,Math.min(Number(e)||0,n.length)),o="",s=0;for(let l=0;l<n.length&&o.length<8;l++)a.indexOf(n.charAt(l))<0||(o+=n.charAt(l),l<r&&s++);let i=o.length>4?o.slice(0,4)+"-"+o.slice(4):o;return{value:i,caret:Math.min(s>4?s+1:s,i.length)}}function Eo(t){let e=String(t||"").trim(),a=/^https?:[/][/][^/#?]+[/]app[/]pair[/]?#(.*)$/i.exec(e);if(a){let r=a[1].split("&");for(let o=0;o<r.length;o++){if(r[o].indexOf("token=")!==0)continue;let s="";try{s=decodeURIComponent(r[o].slice(6))}catch{return{kind:"none"}}return/^agx_live_[0-9a-f]{64}$/.test(s)?{kind:"token",token:s}:{kind:"none"}}return{kind:"none"}}let n=e.toUpperCase();return/^[A-Z0-9]{4}-?[A-Z0-9]{4}$/.test(n)?{kind:"code",code:n.slice(0,4)+"-"+n.slice(-4)}:{kind:"none"}}function Ft(t,e,a,n){return t?e?{text:"Can't reach the server. "+(n?"Showing what was last loaded. ":"")+"Trying again every "+a+" seconds.",retry:!0}:{text:"Offline. Showing what was last loaded; live state needs a connection.",retry:!1}:null}function Ut(t){return String(t??"").replace(/```[\w-]*|`/g,"").replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^[ \t]*(?:#{1,6}|>+|[-*+]|\d+[.)])[ \t]+(?:\[[ xX]\][ \t]+)?/gm,"").replace(/\*\*|~~/g,"").replace(/(^|[\s(])\*(\S(?:[^*\n]*\S)?)\*(?=[\s).,;:!?]|$)/gm,"$1$2").replace(/\s+/g," ").trim()}function To(t){let e=t.by==="you"?"you":t.by==="owner"?"the owner":t.by?"someone else":null;if(t.state==="working"){let a=t.queue||{waiting:0,yours:0,ahead:null},n=a.ahead||0,r;return a.yours>0?r=(a.yours===1?"Your message is in line":a.yours+" messages of yours are in line")+(n===0?a.yours===1?": it runs when this ends.":": the first runs when this ends.":", "+n+(n===1?" message":" messages")+" ahead of "+(a.yours===1?"it.":"the first.")):a.waiting>0?r=a.waiting+(a.waiting===1?" message waits":" messages wait")+" in line. A new one from you waits behind "+(a.waiting===1?"it.":"them."):r=t.by==="you"?"Busy. A new message waits in line until this ends.":"A message you send now waits in line until this ends.",t.by==="you"?{label:"Working",tone:"work",what:t.text,by:e,hint:r}:{label:"Working",tone:"work",what:t.text||"Busy with someone else's task",by:e,hint:r}}return t.state==="blocked"?{label:"Blocked",tone:"stuck",what:t.text?"Stopped on: "+t.text:null,by:e,hint:"It stopped before finishing. It needs a person."}:{label:"Free",tone:"free",what:t.by==="you"&&t.text?"Finished: "+t.text:null,by:t.by==="you"?e:null,hint:"Free. Ready for your next message."}}function Ao(t){let e=t.request?t.request.state:"";return e==="waiting_owner"?{label:"Waiting on the owner",tone:"wait"}:e==="waiting_other"?{label:"Waiting on another agent",tone:"wait"}:e==="needs_attention"?{label:"Stuck",tone:"stuck"}:t.status==="queued"?{label:"In line",tone:"wait"}:t.status==="in-flight"?{label:"Running",tone:"work"}:t.status==="ok"?{label:"Finished",tone:"done"}:t.status==="error"||t.status==="timeout"?{label:"Stopped",tone:"stuck"}:t.status==="canceled"||t.status==="cancelled"?{label:"Stopped",tone:"off"}:{label:String(t.status||"").replace(/[_-]/g," "),tone:"off"}}function Co(t){return t==="in_progress"?{label:"In progress",tone:"work"}:t==="waiting_owner"?{label:"Waiting on the owner",tone:"wait"}:t==="waiting_other"?{label:"Waiting on another agent",tone:"wait"}:t==="needs_attention"?{label:"Stuck",tone:"stuck"}:t==="done"?{label:"Finished",tone:"done"}:t==="declined"?{label:"Declined",tone:"off"}:t==="dropped"?{label:"Dropped",tone:"off"}:{label:String(t||"").replace(/_/g," "),tone:"off"}}function Io(t,e){if(!t.length&&!e)return"Nothing sent yet.";let a=t.slice(0,4).map(function(n){return n.state==="working"?n.agentId+(n.by==="you"?" is working on your task.":" is busy with someone else's task."):n.state==="blocked"?n.agentId+" stopped on your task.":n.agentId+" is free."});return t.length>4&&a.push(t.length-4+" more below."),a.join(" ")||"Nothing running now."}function Mo(t,e){if(!t)return[];let a={};return t.forEach(function(n){a[n.agentId]=n.state}),e.filter(function(n){return n.state==="free"&&a[n.agentId]==="working"}).map(function(n){return n.agentId})}var Lo=`
1053
1053
  (function () {
1054
1054
  var POLL_S = 30, RETRY_S = 20, GIVE_UP_MS = 15000;
1055
1055
  var who = document.getElementById('who');
@@ -1235,7 +1235,7 @@ body { margin: 0; overflow: hidden; }
1235
1235
  showConn();
1236
1236
  load();
1237
1237
  })();
1238
- `;var zt=`
1238
+ `;var Wt=`
1239
1239
  :root { --link: var(--ax-blue-d); --ring: var(--ax-blue); --tick: var(--ax-green-d); }
1240
1240
  [data-theme="dark"] { --link: var(--ax-blue); --tick: var(--ax-green); }
1241
1241
  * { box-sizing: border-box; }
@@ -1263,7 +1263,7 @@ code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surf
1263
1263
  .card h2 { font-size: 24px; font-weight: 700; line-height: 1.2; margin-bottom: 8px; }
1264
1264
  .card p { color: var(--ax-text-2); }
1265
1265
  .help { margin-top: 20px; font-size: 14px; color: var(--ax-text-2); }
1266
- `,qt=`
1266
+ `,Gt=`
1267
1267
  .icon-btn { min-width: 44px; min-height: 44px; font-size: 20px; line-height: 1; border: var(--ax-border-w) solid var(--ax-border-2); border-radius: var(--ax-radius-pill); background: var(--ax-surface); color: var(--ax-text); cursor: pointer; }
1268
1268
  .strip, .install { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; padding: 10px 20px; font-size: 14px; background: var(--ax-amber-t); color: var(--ax-amber-ink); border-bottom: var(--ax-border-w) solid var(--ax-amber-e); }
1269
1269
  .strip[hidden], .install[hidden] { display: none; }
@@ -1338,7 +1338,7 @@ code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surf
1338
1338
  .blank { padding: 28px 24px; border: var(--ax-border-w) dashed var(--ax-border-2); border-radius: var(--ax-radius-lg); }
1339
1339
  .blank p + p { margin-top: 8px; color: var(--ax-text-2); }
1340
1340
  .foot { margin-top: 28px; font-size: 14px; color: var(--ax-text-2); }
1341
- `,uo=`
1341
+ `,Ro=`
1342
1342
  .pair-form { display: grid; gap: 8px; margin-top: 20px; }
1343
1343
  .pair-form label { font-weight: 600; margin-top: 8px; }
1344
1344
  .pair-form input { width: 100%; min-height: 52px; padding: 10px 14px; font: inherit; font-size: 17px; color: var(--ax-text); background: var(--ax-surface); border: var(--ax-border-w) solid var(--ax-text-2); border-radius: var(--ax-radius-sm); }
@@ -1350,11 +1350,11 @@ code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surf
1350
1350
  .card .pair-msg.bad { color: var(--ax-red-ink); }
1351
1351
  [data-theme="dark"] .card .pair-msg.bad { color: var(--ax-red); }
1352
1352
  .card .pair-offline { padding: 8px 12px; border-radius: var(--ax-radius-sm); font-size: 14px; background: var(--ax-amber-t); color: var(--ax-amber-ink); border: 1px solid var(--ax-amber-e); }
1353
- `,mo=`
1353
+ `,Po=`
1354
1354
  .pulse { display: inline-block; width: 12px; height: 12px; margin-right: 10px; border-radius: 50%; border: 3px solid var(--ax-amber-ink); box-sizing: border-box; animation: breathe 2.4s ease-in-out infinite; }
1355
1355
  @keyframes breathe { 50% { opacity: 0.35; } }
1356
1356
  @media (prefers-reduced-motion: reduce) { .pulse { animation: none; } }
1357
- `;var Cc="<script>(function(){var t;try{t=localStorage.getItem('ax-theme')}catch(e){}if(t!=='light'&&t!=='dark'){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)})()</script>";function wa(t,e={}){return`<meta charset="utf-8">
1357
+ `;var xd="<script>(function(){var t;try{t=localStorage.getItem('ax-theme')}catch(e){}if(t!=='light'&&t!=='dark'){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)})()</script>";function Ma(t,e={}){return`<meta charset="utf-8">
1358
1358
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
1359
1359
  <meta name="theme-color" content="#2979FF">
1360
1360
  <meta name="referrer" content="no-referrer">
@@ -1364,8 +1364,8 @@ code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surf
1364
1364
  <link rel="icon" type="image/png" href="/member/icon-192.png">
1365
1365
  <link rel="apple-touch-icon" href="/member/icon-192.png">
1366
1366
  <title>${t}</title>
1367
- ${Cc}
1368
- <style>${He}${zt}</style>`}function fo(){return JSON.stringify({id:"/member",name:"My work \xB7 AgentX",short_name:"My work",description:"What you asked the agents for, and where it stands.",start_url:"/member",scope:"/member",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/member/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var ho=`
1367
+ ${xd}
1368
+ <style>${Fe}${Wt}</style>`}function $o(){return JSON.stringify({id:"/member",name:"My work \xB7 AgentX",short_name:"My work",description:"What you asked the agents for, and where it stands.",start_url:"/member",scope:"/member",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/member/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var jo=`
1369
1369
  var CACHE = 'agentx-member-v1';
1370
1370
  var STATIC = ['/member/manifest.webmanifest', '/member/icon-192.png', '/member/icon-512.png'];
1371
1371
  self.addEventListener('install', function (e) {
@@ -1395,14 +1395,14 @@ self.addEventListener('fetch', function (e) {
1395
1395
  e.respondWith(caches.match(url.pathname).then(function (hit) { return hit || fetch(req); }));
1396
1396
  }
1397
1397
  });
1398
- `;function ka(t,e="",a="My work"){return`<header class="bar">
1398
+ `;function La(t,e="",a="My work"){return`<header class="bar">
1399
1399
  <img class="mark" src="/member/icon-192.png" alt="" width="36" height="36">
1400
1400
  <div class="grow"><h1>${a}</h1><p id="who" class="who">${t}</p></div>${e}
1401
- </header>`}var _a=wa,Sa=ka;function go(t){return`<ol class="steps" aria-label="Steps">${["Type the code","The owner says yes","Your work opens"].map((a,n)=>n<t?`<li class="done"><span class="sr">Done: </span>${a}</li>`:n===t?`<li class="now" aria-current="step">${a}</li>`:`<li>${a}</li>`).join("")}</ol>`}function xo(){return`<!doctype html>
1401
+ </header>`}var Ra=Ma,Pa=La;function Oo(t){return`<ol class="steps" aria-label="Steps">${["Type the code","The owner says yes","Your work opens"].map((a,n)=>n<t?`<li class="done"><span class="sr">Done: </span>${a}</li>`:n===t?`<li class="now" aria-current="step">${a}</li>`:`<li>${a}</li>`).join("")}</ol>`}function No(){return`<!doctype html>
1402
1402
  <html lang="en">
1403
- <head>${_a("My work \xB7 AgentX")}<style>${qt}</style></head>
1403
+ <head>${Ra("My work \xB7 AgentX")}<style>${Gt}</style></head>
1404
1404
  <body>
1405
- ${Sa("Connecting\u2026",`
1405
+ ${Pa("Connecting\u2026",`
1406
1406
  <button type="button" id="theme" class="icon-btn" aria-label="Switch theme">\u25D0</button>`)}
1407
1407
  <p id="offline" class="strip" role="status" hidden><span id="offline-text"></span><button type="button" id="retry" hidden>Try now</button></p>
1408
1408
  <p id="install" class="install" hidden>To keep this window on your desktop: in Edge or Chrome open the browser menu, then <b>Apps</b>, then <b>Install this site as an app</b>.</p>
@@ -1413,15 +1413,15 @@ ${Sa("Connecting\u2026",`
1413
1413
  <section aria-labelledby="h-sent"><h2 id="h-sent">What you sent <span class="n">(last 7 days)</span></h2><ul id="sent" class="rows"></ul></section>
1414
1414
  <p id="updated" class="foot"></p>
1415
1415
  </main>
1416
- <script>${B({workState:Ic,ageText:Ea,connectionNote:Ht,plainPreview:Bt,agentLine:oo,sentState:so,requestState:io,summaryLine:lo,freedAgents:co})}${po}</script>
1416
+ <script>${q({workState:bd,ageText:$a,connectionNote:Ft,plainPreview:Ut,agentLine:To,sentState:Ao,requestState:Co,summaryLine:Io,freedAgents:Mo})}${Lo}</script>
1417
1417
  </body>
1418
- </html>`}function vo(){return`<!doctype html>
1418
+ </html>`}function Do(){return`<!doctype html>
1419
1419
  <html lang="en">
1420
- <head>${_a("Pair this machine \xB7 AgentX")}<style>${uo}</style></head>
1420
+ <head>${Ra("Pair this machine \xB7 AgentX")}<style>${Ro}</style></head>
1421
1421
  <body>
1422
- ${Sa("This machine is not paired yet")}
1422
+ ${Pa("This machine is not paired yet")}
1423
1423
  <main class="narrow">
1424
- ${go(0)}
1424
+ ${Oo(0)}
1425
1425
  <div class="card">
1426
1426
  <h2>Pair this machine</h2>
1427
1427
  <p>The owner sent you a pairing code. Type it with a name for this machine. The owner then approves the machine, and your work page opens.</p>
@@ -1438,24 +1438,24 @@ ${Sa("This machine is not paired yet")}
1438
1438
  <p class="help">No code? Ask the person who invited you for one. A code works once, for 10 minutes.</p>
1439
1439
  </div>
1440
1440
  </main>
1441
- <script>${B({formatPairInput:Dt})}${Mc}</script>
1441
+ <script>${q({formatPairInput:qt})}${vd}</script>
1442
1442
  </body>
1443
- </html>`}function bo(){return`<!doctype html>
1443
+ </html>`}function Ho(){return`<!doctype html>
1444
1444
  <html lang="en">
1445
- <head>${_a("Waiting for the owner \xB7 AgentX")}<style>${mo}</style></head>
1445
+ <head>${Ra("Waiting for the owner \xB7 AgentX")}<style>${Po}</style></head>
1446
1446
  <body>
1447
- ${Sa("This machine is paired")}
1447
+ ${Pa("This machine is paired")}
1448
1448
  <main class="narrow">
1449
- ${go(1)}
1449
+ ${Oo(1)}
1450
1450
  <div class="card">
1451
1451
  <h2><span class="pulse" aria-hidden="true"></span>Waiting for the owner</h2>
1452
1452
  <p id="msg" role="status">This machine is paired. The owner has to approve it once; this page opens your work by itself when they do.</p>
1453
1453
  <p class="help">If they say no, this page asks for a new code.</p>
1454
1454
  </div>
1455
1455
  </main>
1456
- <script>${Lc}</script>
1456
+ <script>${yd}</script>
1457
1457
  </body>
1458
- </html>`}function Ic(t){let e=String(t||"");return e==="in_progress"?{label:"In progress",tone:"ok"}:e==="waiting_owner"?{label:"Waiting on the owner",tone:"warn"}:e==="waiting_other"?{label:"Waiting on another agent",tone:"warn"}:e==="needs_attention"?{label:"Stuck: needs attention",tone:"bad"}:e==="done"?{label:"Done",tone:"ok"}:e==="declined"?{label:"Declined",tone:"bad"}:e==="dropped"?{label:"Dropped",tone:"muted"}:{label:e.replace(/_/g," "),tone:"muted"}}function Ea(t,e){let a=Math.max(0,Number(e)-Number(t)),n=Math.floor(a/6e4);if(n<1)return"just now";if(n<60)return n+" min";let r=Math.floor(n/60);return r<24?r+" h "+n%60+" min":Math.floor(r/24)+" d "+r%24+" h"}var Mc=`
1458
+ </html>`}function bd(t){let e=String(t||"");return e==="in_progress"?{label:"In progress",tone:"ok"}:e==="waiting_owner"?{label:"Waiting on the owner",tone:"warn"}:e==="waiting_other"?{label:"Waiting on another agent",tone:"warn"}:e==="needs_attention"?{label:"Stuck: needs attention",tone:"bad"}:e==="done"?{label:"Done",tone:"ok"}:e==="declined"?{label:"Declined",tone:"bad"}:e==="dropped"?{label:"Dropped",tone:"muted"}:{label:e.replace(/_/g," "),tone:"muted"}}function $a(t,e){let a=Math.max(0,Number(e)-Number(t)),n=Math.floor(a/6e4);if(n<1)return"just now";if(n<60)return n+" min";let r=Math.floor(n/60);return r<24?r+" h "+n%60+" min":Math.floor(r/24)+" d "+r%24+" h"}var vd=`
1459
1459
  (function () {
1460
1460
  var form = document.getElementById('pair-form');
1461
1461
  var machine = document.getElementById('machine');
@@ -1499,7 +1499,7 @@ ${Sa("This machine is paired")}
1499
1499
  }).catch(function () { busy = false; btn.disabled = false; say('No connection. Check the private network and try again.', true); });
1500
1500
  });
1501
1501
  })();
1502
- `,Lc=`
1502
+ `,yd=`
1503
1503
  (function () {
1504
1504
  var msg = document.getElementById('msg');
1505
1505
  function check() {
@@ -1510,16 +1510,16 @@ ${Sa("This machine is paired")}
1510
1510
  }
1511
1511
  setInterval(check, 5000);
1512
1512
  })();
1513
- `;function yo(t){let e=t.request?t.request.state:"";return e==="waiting_owner"||e==="waiting_other"?{label:"Waiting on us",tone:"wait"}:e==="needs_attention"?{label:"Needs a look from us",tone:"stuck"}:t.status==="in-flight"?{label:"Being worked on",tone:"work"}:t.status==="ok"?{label:"Finished",tone:"done"}:t.status==="error"||t.status==="timeout"?{label:"Stopped, we will look at it",tone:"stuck"}:t.status==="canceled"||t.status==="cancelled"?{label:"Stopped",tone:"off"}:{label:String(t.status||"").replace(/[_-]/g," "),tone:"off"}}function wo(t){return t==="in_progress"?{label:"Being worked on",tone:"work"}:t==="waiting_owner"||t==="waiting_other"?{label:"Waiting on us",tone:"wait"}:t==="needs_attention"?{label:"Needs a look from us",tone:"stuck"}:t==="done"?{label:"Finished",tone:"done"}:t==="declined"?{label:"Not taken on",tone:"off"}:t==="dropped"?{label:"Set aside",tone:"off"}:{label:String(t||"").replace(/_/g," "),tone:"off"}}function ko(t){if(!t.length)return"Nothing asked for yet.";let e=0,a=0,n=0,r=0;for(let s=0;s<t.length;s++)t[s]==="work"?e++:t[s]==="wait"?a++:t[s]==="stuck"?n++:t[s]==="done"&&r++;let o=[];return e&&o.push(e===1?"1 request is being worked on for you.":e+" requests are being worked on for you."),a&&o.push(a===1?"1 is waiting on us.":a+" are waiting on us."),n&&o.push(n===1?"1 needs a look from us.":n+" need a look from us."),o.length?o.join(" "):r?"Nothing in progress right now. "+(r===1?"1 request finished":r+" requests finished")+" this week.":"Nothing in progress right now."}var Ta="/member/client.webmanifest",Ve="Your project";function _o(){return JSON.stringify({id:"/member?client",name:`${Ve} \xB7 AgentX`,short_name:Ve,description:"What you asked for, and where it stands.",start_url:"/member",scope:"/member",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/member/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var Rc=`
1513
+ `;function Bo(t){let e=t.request?t.request.state:"";return e==="waiting_owner"||e==="waiting_other"?{label:"Waiting on us",tone:"wait"}:e==="needs_attention"?{label:"Needs a look from us",tone:"stuck"}:t.status==="in-flight"?{label:"Being worked on",tone:"work"}:t.status==="ok"?{label:"Finished",tone:"done"}:t.status==="error"||t.status==="timeout"?{label:"Stopped, we will look at it",tone:"stuck"}:t.status==="canceled"||t.status==="cancelled"?{label:"Stopped",tone:"off"}:{label:String(t.status||"").replace(/[_-]/g," "),tone:"off"}}function zo(t){return t==="in_progress"?{label:"Being worked on",tone:"work"}:t==="waiting_owner"||t==="waiting_other"?{label:"Waiting on us",tone:"wait"}:t==="needs_attention"?{label:"Needs a look from us",tone:"stuck"}:t==="done"?{label:"Finished",tone:"done"}:t==="declined"?{label:"Not taken on",tone:"off"}:t==="dropped"?{label:"Set aside",tone:"off"}:{label:String(t||"").replace(/_/g," "),tone:"off"}}function qo(t){if(!t.length)return"Nothing asked for yet.";let e=0,a=0,n=0,r=0;for(let s=0;s<t.length;s++)t[s]==="work"?e++:t[s]==="wait"?a++:t[s]==="stuck"?n++:t[s]==="done"&&r++;let o=[];return e&&o.push(e===1?"1 request is being worked on for you.":e+" requests are being worked on for you."),a&&o.push(a===1?"1 is waiting on us.":a+" are waiting on us."),n&&o.push(n===1?"1 needs a look from us.":n+" need a look from us."),o.length?o.join(" "):r?"Nothing in progress right now. "+(r===1?"1 request finished":r+" requests finished")+" this week.":"Nothing in progress right now."}var ja="/member/client.webmanifest",tt="Your project";function Fo(){return JSON.stringify({id:"/member?client",name:`${tt} \xB7 AgentX`,short_name:tt,description:"What you asked for, and where it stands.",start_url:"/member",scope:"/member",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/member/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/member/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var wd=`
1514
1514
  .about { margin-top: 32px; padding: 16px 20px; border: var(--ax-border-w) solid var(--ax-border); border-radius: var(--ax-radius-lg); background: var(--ax-surface); font-size: 15px; color: var(--ax-text-2); }
1515
1515
  .wrap .about h2 { margin: 0 0 6px; }
1516
1516
  .about p + p { margin-top: 6px; }
1517
- `;function So(){return`<!doctype html>
1517
+ `;function Uo(){return`<!doctype html>
1518
1518
  <html lang="en">
1519
- <head>${wa(`${Ve} \xB7 AgentX`,{manifest:Ta,appTitle:Ve})}<style>${He}${zt}${qt}${Rc}</style></head>
1519
+ <head>${Ma(`${tt} \xB7 AgentX`,{manifest:ja,appTitle:tt})}<style>${Fe}${Wt}${Gt}${wd}</style></head>
1520
1520
  <body>
1521
- ${ka("Connecting\u2026",`
1522
- <button type="button" id="theme" class="icon-btn" aria-label="Switch theme">\u25D0</button>`,Ve)}
1521
+ ${La("Connecting\u2026",`
1522
+ <button type="button" id="theme" class="icon-btn" aria-label="Switch theme">\u25D0</button>`,tt)}
1523
1523
  <p id="offline" class="strip" role="status" hidden><span id="offline-text"></span><button type="button" id="retry" hidden>Try now</button></p>
1524
1524
  <p id="install" class="install" hidden>To keep this window on your desktop: in Edge or Chrome open the browser menu, then <b>Apps</b>, then <b>Install this site as an app</b>.</p>
1525
1525
  <main class="wrap">
@@ -1531,9 +1531,9 @@ ${ka("Connecting\u2026",`
1531
1531
  </section>
1532
1532
  <p id="updated" class="foot"></p>
1533
1533
  </main>
1534
- <script>${B({ageText:Ea,connectionNote:Ht,plainPreview:Bt,clientSentState:yo,clientRequestState:wo,clientSummary:ko})}${$c}</script>
1534
+ <script>${q({ageText:$a,connectionNote:Ft,plainPreview:Ut,clientSentState:Bo,clientRequestState:zo,clientSummary:qo})}${kd}</script>
1535
1535
  </body>
1536
- </html>`}var $c=`
1536
+ </html>`}var kd=`
1537
1537
  (function () {
1538
1538
  var POLL_S = 30, RETRY_S = 20, GIVE_UP_MS = 15000;
1539
1539
  var who = document.getElementById('who');
@@ -1640,10 +1640,10 @@ ${ka("Connecting\u2026",`
1640
1640
  showConn();
1641
1641
  load();
1642
1642
  })();
1643
- `;var Ft="agentx_member",Pc=90*86400,jc=new St,Co=t=>t.replace(/^\[app\]/,"[member]"),Oc=new Te(t=>console.log(Co(t))),Eo=new WeakMap;function Nc(t){if(t.rejectLog)return t.rejectLog;if(!t.log)return Oc;let e=Eo.get(t.log);return e||Eo.set(t.log,e=new Te(a=>t.log(Co(a)))),e}var To=null;function Ye(t,e=X){try{return To=e().people}catch{return To??t}}async function Io(t,e,a,n,r){if(a!=="/member"&&!a.startsWith("/member/")&&!a.startsWith("/api/member/"))return!1;let o=r.tokens??new F(r.root),s=r.members??new mt(r.root),i={tokens:o,members:s,people:r.people,root:r.root,codes:r.pairCodes??new vt(r.root),limiter:r.pairLimiter??jc,minMs:r.pairMinMs,log:r.log,now:r.now};if(n==="GET"){if(a==="/member/manifest.webmanifest")return ue(e,200,"application/manifest+json",fo());if(a===Ta)return ue(e,200,"application/manifest+json",_o());if(a==="/member/sw.js")return e.setHeader("Service-Worker-Allowed","/member"),ue(e,200,"text/javascript; charset=utf-8",ho);if(a==="/member/icon-192.png")return ue(e,200,"image/png",ze(192),"public, max-age=86400");if(a==="/member/icon-512.png")return ue(e,200,"image/png",ze(512),"public, max-age=86400")}if(n==="POST"&&a==="/api/member/pair-code"){let u=await Lr(t,i);return u.status===200&&e.setHeader("Set-Cookie",Ao(u.token)),u.status===429&&e.setHeader("Retry-After",String(u.retryAfter)),ye(e,u.status,u.body)}let l=$r(Hc(t),i,Mr(t));if(!l.ok){if(l.status===401){let u=Aa(t);return Nc(r).record(a.slice(0,120),Ot(t,Be(Ca(t,Ft),o),u?Be(u,o):null)),a==="/member"?ue(e,401,"text/html; charset=utf-8",vo()):ye(e,401,{error:l.error,hint:"ask the owner to run: agentx people invite <you>"})}return a==="/member"?ue(e,202,"text/html; charset=utf-8",bo()):ye(e,403,{error:l.error,waiting:!0})}let c=r.people().find(u=>u.id===l.personId),p=c?.role==="client";if(n==="GET"&&a==="/member"){let u=Ca(t,Ft);return u&&!Aa(t)&&e.setHeader("Set-Cookie",Ao(u)),ue(e,200,"text/html; charset=utf-8",p?So():xo())}if(n==="GET"&&a==="/api/member/me")return ye(e,200,{person:l.personId,name:c?.name??l.personId,role:c?.role??"member",device:l.device.name,since:l.device.approvedAt??l.device.createdAt,node:r.nodeName??null});if(n==="GET"&&a==="/api/member/work"){let u=r.db?.()??null;if(!u)return ye(e,503,{error:"the work list needs the database"});let m=(r.now??Date.now)(),h=Yr(u,l.personId,{now:m,linkFor:r.linkFor}),_=(g,d)=>{let f=d instanceof Error?d.message:String(d);/no such table/i.test(f)||r.log?.(`[member] ${g} failed: ${f}`)},v={byAgent:new Map,mine:[]};try{v=Zr(u,l.personId,{linkFor:r.linkFor})}catch(g){_("the line",g)}let S=[];if(p)return ye(e,200,{...Dc(h),agents:S});try{let g=eo(u,c??{id:l.personId},m);S=to(u,l.personId,g,{people:r.people(),linkFor:r.linkFor,queue:v.byAgent})}catch(g){_("agent cards",g)}return ye(e,200,{...h,agents:S,queued:v.mine})}return ye(e,404,{error:"not found"})}function Dc(t){let e=a=>a.map(({agentId:n,...r})=>r);return{...t,open:e(t.open),recent:e(t.recent),runs:e(t.runs),other:e(t.other)}}function Ao(t){return`${Ft}=${t}; Path=/; Max-Age=${Pc}; HttpOnly; Secure; SameSite=Lax`}function Hc(t){return Aa(t)??Ca(t,Ft)}function Aa(t){let e=t.headers.authorization||"";return e.toLowerCase().startsWith("bearer ")&&e.slice(7).trim()||null}function Ca(t,e){for(let a of(t.headers.cookie||"").split(";")){let n=a.indexOf("=");if(n>0&&a.slice(0,n).trim()===e)return a.slice(n+1).trim()||null}return null}function ue(t,e,a,n,r="no-store"){return t.writeHead(e,{"Content-Type":a,"Cache-Control":r}),t.end(n),!0}function ye(t,e,a){return ue(t,e,"application/json",JSON.stringify(a))}tc();var Mo='/*! 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});';import{existsSync as Wt,readFileSync as Do,writeFileSync as Ho,rmSync as ug,mkdirSync as Wc,copyFileSync as Gc,readdirSync as Xc}from"fs";import{resolve as Fe}from"path";ac();function Ro(t){let e=lt.safeParse(t?.whatsappTriage??{}),a=e.success?e.data:lt.parse({});return{enabled:a.enabled,secretEnv:a.secretEnv,secretSet:!!process.env[a.secretEnv],batchSeconds:a.batchSeconds,allowAutoAck:a.allowAutoAck,rules:a.rules,...e.success?{}:{error:e.error.issues[0]?.message??"invalid whatsappTriage section"}}}function Ut(t){return A(e=>{let a=e.whatsappTriage&&typeof e.whatsappTriage=="object"?e.whatsappTriage:{};a.rules=Array.isArray(a.rules)?a.rules:[];let n=t(a,e),r=lt.safeParse(a);if(!r.success){let o=r.error.issues[0];throw new Error(`${o?.path.join(".")||"whatsappTriage"}: ${o?.message??"invalid"}`)}return e.whatsappTriage=a,n})}var Lo=t=>(Array.isArray(t)?t:String(t??"").split(/[,\n]/)).map(e=>String(e).trim()).filter(Boolean);function $o(t){return Ut(e=>(typeof t?.enabled=="boolean"&&(e.enabled=t.enabled),typeof t?.allowAutoAck=="boolean"&&(e.allowAutoAck=t.allowAutoAck),t?.batchSeconds!==void 0&&(e.batchSeconds=Number(t.batchSeconds)),`WhatsApp triage ${e.enabled?"on":"off"}`))}function Po(t){let e=String(t?.id??"").trim(),a=String(t?.agent??"").trim();return Ut((n,r)=>{if(!r.agents?.[a])throw new Error(`Unknown agent "${a}".`);if(n.rules.some(i=>i.id===e))throw new Error(`Watch rule "${e}" already exists.`);let o={id:e,agent:a,chats:Lo(t?.chats),senders:Lo(t?.senders)},s=String(t?.prompt??"").trim();return s&&(o.prompt=s),t?.quietStart&&t?.quietEnd&&(o.quietHours={start:String(t.quietStart),end:String(t.quietEnd)}),t?.autoAck===!0&&(o.autoAck=!0),n.rules.push(o),`added watch rule "${e}" \u2192 ${a}`})}function jo(t){let e=String(t?.id??"");return Ut(a=>{let n=a.rules.find(r=>r.id===e);if(!n)throw new Error(`Watch rule "${e}" not found.`);return typeof t?.patch?.enabled=="boolean"&&(n.enabled=t.patch.enabled),typeof t?.patch?.autoAck=="boolean"&&(n.autoAck=t.patch.autoAck),`updated watch rule "${e}"`})}function Oo(t){let e=String(t?.id??"");return Ut(a=>{if(!a.rules.some(n=>n.id===e))throw new Error(`Watch rule "${e}" not found.`);return a.rules=a.rules.filter(n=>n.id!==e),`removed watch rule "${e}"`})}ut();var de={agents:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4M8 16h.01M16 16h.01"/></svg>',channels:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>',schedules:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>',webhooks:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M10 12a3 3 0 1 0 3-3m-8 11a3 3 0 1 0 2.6-1.5L10 12m7 3a3 3 0 1 0-2-5.5"/></svg>',mesh:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="6" cy="18" r="2"/><circle cx="18" cy="18" r="2"/><circle cx="12" cy="12" r="2"/><path d="M7.4 7.4l3.2 3.2M13.4 13.4l3.2 3.2M16.6 7.4l-3.2 3.2M10.6 13.4l-3.2 3.2"/></svg>',tokens:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-8 8a4 4 0 1 1-6 6m6-6l5-5 3 3-5 5m-3-3l3 3"/></svg>',advanced:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 4h8l4 4v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M9 13l2 2 4-4"/></svg>',actions:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>'};function No(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=be({kicker:"Settings",title:"Your team's control room",lead:`Manage the agents, the places they answer from, and who's allowed to reach them. Everything here writes to <span class="mono muted">agentx.json</span> on your machine \u2014 nothing leaves.`})+Mt([{kind:"off",num:"\u2014",label:"Agents online"},{kind:"off",num:"\u2014",label:"Channels connected"},{kind:"off",num:"0",label:"Needs attention"},{kind:"off",num:"\u2014",label:"Active tokens"}]).replace('<div class="ax-health-strip">','<div class="ax-health-strip" id="ax-health">')+'<div class="ax-wit" id="ax-voice-missing" style="display:none"><span class="ax-wit__icon">!</span><div></div></div>';return M({title:"AgentX \xB7 Settings",activeTab:"admin",subtitle:"Settings",peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a+zc()+br,css:Fc,scripts:`${e}<script>${yr}
1644
- ${wr}
1645
- ${Bc}
1646
- ${Uc}</script>`})}var Bc=`
1643
+ `;var Xt="agentx_member",_d=90*86400,Sd=new At,Ko=t=>t.replace(/^\[app\]/,"[member]"),Ed=new Le(t=>console.log(Ko(t))),Wo=new WeakMap;function Td(t){if(t.rejectLog)return t.rejectLog;if(!t.log)return Ed;let e=Wo.get(t.log);return e||Wo.set(t.log,e=new Le(a=>t.log(Ko(a)))),e}var Go=null;function at(t,e=X){try{return Go=e().people}catch{return Go??t}}async function Jo(t,e,a,n,r){if(a!=="/member"&&!a.startsWith("/member/")&&!a.startsWith("/api/member/"))return!1;let o=r.tokens??new G(r.root),s=r.members??new xt(r.root),i={tokens:o,members:s,people:r.people,root:r.root,codes:r.pairCodes??new kt(r.root),limiter:r.pairLimiter??Sd,minMs:r.pairMinMs,log:r.log,now:r.now};if(n==="GET"){if(a==="/member/manifest.webmanifest")return ge(e,200,"application/manifest+json",$o());if(a===ja)return ge(e,200,"application/manifest+json",Fo());if(a==="/member/sw.js")return e.setHeader("Service-Worker-Allowed","/member"),ge(e,200,"text/javascript; charset=utf-8",jo);if(a==="/member/icon-192.png")return ge(e,200,"image/png",We(192),"public, max-age=86400");if(a==="/member/icon-512.png")return ge(e,200,"image/png",We(512),"public, max-age=86400")}if(n==="POST"&&a==="/api/member/pair-code"){let p=await qr(t,i);return p.status===200&&e.setHeader("Set-Cookie",Xo(p.token)),p.status===429&&e.setHeader("Retry-After",String(p.retryAfter)),_e(e,p.status,p.body)}let l=Ur(Cd(t),i,zr(t));if(!l.ok){if(l.status===401){let p=Oa(t);return Td(r).record(a.slice(0,120),Ht(t,Ue(Na(t,Xt),o),p?Ue(p,o):null)),a==="/member"?ge(e,401,"text/html; charset=utf-8",Do()):_e(e,401,{error:l.error,hint:"ask the owner to run: agentx people invite <you>"})}return a==="/member"?ge(e,202,"text/html; charset=utf-8",Ho()):_e(e,403,{error:l.error,waiting:!0})}let c=r.people().find(p=>p.id===l.personId),d=c?.role==="client";if(n==="GET"&&a==="/member"){let p=Na(t,Xt);return p&&!Oa(t)&&e.setHeader("Set-Cookie",Xo(p)),ge(e,200,"text/html; charset=utf-8",d?Uo():No())}if(n==="GET"&&a==="/api/member/me")return _e(e,200,{person:l.personId,name:c?.name??l.personId,role:c?.role??"member",device:l.device.name,since:l.device.approvedAt??l.device.createdAt,node:r.nodeName??null});if(n==="GET"&&a==="/api/member/work"){let p=r.db?.()??null;if(!p)return _e(e,503,{error:"the work list needs the database"});let m=(r.now??Date.now)(),f=bo(p,l.personId,{now:m,linkFor:r.linkFor}),S=(g,x)=>{let u=x instanceof Error?x.message:String(x);/no such table/i.test(u)||r.log?.(`[member] ${g} failed: ${u}`)},b={byAgent:new Map,mine:[]};try{b=yo(p,l.personId,{linkFor:r.linkFor})}catch(g){S("the line",g)}let E=[];if(d)return _e(e,200,{...Ad(f),agents:E});try{let g=wo(p,c??{id:l.personId},m);E=ko(p,l.personId,g,{people:r.people(),linkFor:r.linkFor,queue:b.byAgent})}catch(g){S("agent cards",g)}return _e(e,200,{...f,agents:E,queued:b.mine})}return _e(e,404,{error:"not found"})}function Ad(t){let e=a=>a.map(({agentId:n,...r})=>r);return{...t,open:e(t.open),recent:e(t.recent),runs:e(t.runs),other:e(t.other)}}function Xo(t){return`${Xt}=${t}; Path=/; Max-Age=${_d}; HttpOnly; Secure; SameSite=Lax`}function Cd(t){return Oa(t)??Na(t,Xt)}function Oa(t){let e=t.headers.authorization||"";return e.toLowerCase().startsWith("bearer ")&&e.slice(7).trim()||null}function Na(t,e){for(let a of(t.headers.cookie||"").split(";")){let n=a.indexOf("=");if(n>0&&a.slice(0,n).trim()===e)return a.slice(n+1).trim()||null}return null}function ge(t,e,a,n,r="no-store"){return t.writeHead(e,{"Content-Type":a,"Cache-Control":r}),t.end(n),!0}function _e(t,e,a){return ge(t,e,"application/json",JSON.stringify(a))}Fc();var Vo='/*! 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});';import{existsSync as Jt,readFileSync as rs,writeFileSync as os,rmSync as vx,mkdirSync as $d,copyFileSync as jd,readdirSync as Od}from"fs";import{resolve as Xe}from"path";Uc();function Qo(t){let e=ut.safeParse(t?.whatsappTriage??{}),a=e.success?e.data:ut.parse({});return{enabled:a.enabled,secretEnv:a.secretEnv,secretSet:!!process.env[a.secretEnv],batchSeconds:a.batchSeconds,allowAutoAck:a.allowAutoAck,rules:a.rules,...e.success?{}:{error:e.error.issues[0]?.message??"invalid whatsappTriage section"}}}function Kt(t){return C(e=>{let a=e.whatsappTriage&&typeof e.whatsappTriage=="object"?e.whatsappTriage:{};a.rules=Array.isArray(a.rules)?a.rules:[];let n=t(a,e),r=ut.safeParse(a);if(!r.success){let o=r.error.issues[0];throw new Error(`${o?.path.join(".")||"whatsappTriage"}: ${o?.message??"invalid"}`)}return e.whatsappTriage=a,n})}var Yo=t=>(Array.isArray(t)?t:String(t??"").split(/[,\n]/)).map(e=>String(e).trim()).filter(Boolean);function Zo(t){return Kt(e=>(typeof t?.enabled=="boolean"&&(e.enabled=t.enabled),typeof t?.allowAutoAck=="boolean"&&(e.allowAutoAck=t.allowAutoAck),t?.batchSeconds!==void 0&&(e.batchSeconds=Number(t.batchSeconds)),`WhatsApp triage ${e.enabled?"on":"off"}`))}function es(t){let e=String(t?.id??"").trim(),a=String(t?.agent??"").trim();return Kt((n,r)=>{if(!r.agents?.[a])throw new Error(`Unknown agent "${a}".`);if(n.rules.some(i=>i.id===e))throw new Error(`Watch rule "${e}" already exists.`);let o={id:e,agent:a,chats:Yo(t?.chats),senders:Yo(t?.senders)},s=String(t?.prompt??"").trim();return s&&(o.prompt=s),t?.quietStart&&t?.quietEnd&&(o.quietHours={start:String(t.quietStart),end:String(t.quietEnd)}),t?.autoAck===!0&&(o.autoAck=!0),n.rules.push(o),`added watch rule "${e}" \u2192 ${a}`})}function ts(t){let e=String(t?.id??"");return Kt(a=>{let n=a.rules.find(r=>r.id===e);if(!n)throw new Error(`Watch rule "${e}" not found.`);return typeof t?.patch?.enabled=="boolean"&&(n.enabled=t.patch.enabled),typeof t?.patch?.autoAck=="boolean"&&(n.autoAck=t.patch.autoAck),`updated watch rule "${e}"`})}function as(t){let e=String(t?.id??"");return Kt(a=>{if(!a.rules.some(n=>n.id===e))throw new Error(`Watch rule "${e}" not found.`);return a.rules=a.rules.filter(n=>n.id!==e),`removed watch rule "${e}"`})}gt();var me={agents:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4M8 16h.01M16 16h.01"/></svg>',channels:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>',schedules:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>',webhooks:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M10 12a3 3 0 1 0 3-3m-8 11a3 3 0 1 0 2.6-1.5L10 12m7 3a3 3 0 1 0-2-5.5"/></svg>',mesh:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="6" cy="18" r="2"/><circle cx="18" cy="18" r="2"/><circle cx="12" cy="12" r="2"/><path d="M7.4 7.4l3.2 3.2M13.4 13.4l3.2 3.2M16.6 7.4l-3.2 3.2M10.6 13.4l-3.2 3.2"/></svg>',tokens:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-8 8a4 4 0 1 1-6 6m6-6l5-5 3 3-5 5m-3-3l3 3"/></svg>',advanced:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 4h8l4 4v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M9 13l2 2 4-4"/></svg>',actions:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>'};function ns(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=ue({kicker:"Settings",title:"Your team's control room",lead:`Manage the agents, the places they answer from, and who's allowed to reach them. Everything here writes to <span class="mono muted">agentx.json</span> on your machine \u2014 nothing leaves.`})+Pt([{kind:"off",num:"\u2014",label:"Agents online"},{kind:"off",num:"\u2014",label:"Channels connected"},{kind:"off",num:"0",label:"Needs attention"},{kind:"off",num:"\u2014",label:"Active tokens"}]).replace('<div class="ax-health-strip">','<div class="ax-health-strip" id="ax-health">')+'<div class="ax-wit" id="ax-voice-missing" style="display:none"><span class="ax-wit__icon">!</span><div></div></div>';return I({title:"AgentX \xB7 Settings",activeTab:"admin",subtitle:"Settings",peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a+Md()+Mr,css:Rd,scripts:`${e}<script>${Lr}
1644
+ ${Rr}
1645
+ ${Id}
1646
+ ${Pd}</script>`})}var Id=`
1647
1647
  (function(){
1648
1648
  function fmt(n) { return n == null ? '\u2014' : String(n); }
1649
1649
  async function voiceMissing() {
@@ -1737,8 +1737,8 @@ ${Uc}</script>`})}var Bc=`
1737
1737
  refresh();
1738
1738
  // Refresh again after the main admin script has had a chance to mutate config.
1739
1739
  document.addEventListener('ax-config-saved', refresh);
1740
- })();`;function zc(){let t=rr().business?`<button data-tab="business">Business</button>
1741
- `:"";return qc.replace("__BUSINESS_TABS__",t)}var qc=`
1740
+ })();`;function Md(){let t=hr().business?`<button data-tab="business">Business</button>
1741
+ `:"";return Ld.replace("__BUSINESS_TABS__",t)}var Ld=`
1742
1742
  <div id="peer-banner" class="peer-banner">
1743
1743
  <span class="label">Managing</span>
1744
1744
  <span class="name" id="peer-banner-name">\u2014</span>
@@ -1881,8 +1881,8 @@ ${Uc}</script>`})}var Bc=`
1881
1881
  <div id="global-msg" class="msg"></div>
1882
1882
 
1883
1883
  <section id="tab-agents" class="tab active">
1884
- ${K({icon:de.agents,title:"Your agents",lead:"Each agent is a role with its own trigger words and workspace. Delete removes the config only \u2014 the folder on disk stays."})}
1885
- ${re({persistKey:"agents",bodyHtml:`<b>What's an agent, exactly?</b> Think of it as a specialised teammate. A sales agent handles pricing questions, a support agent answers tickets, a reports agent sends a weekly summary. You decide what they do and what to say to wake them up (their "trigger words", like <code>@support</code>).`})}
1884
+ ${K({icon:me.agents,title:"Your agents",lead:"Each agent is a role with its own trigger words and workspace. Delete removes the config only \u2014 the folder on disk stays."})}
1885
+ ${se({persistKey:"agents",bodyHtml:`<b>What's an agent, exactly?</b> Think of it as a specialised teammate. A sales agent handles pricing questions, a support agent answers tickets, a reports agent sends a weekly summary. You decide what they do and what to say to wake them up (their "trigger words", like <code>@support</code>).`})}
1886
1886
  <div id="agent-list" class="ax-stack"></div>
1887
1887
  <div class="add-form">
1888
1888
  <h3>Add a new agent</h3>
@@ -1904,8 +1904,8 @@ ${Uc}</script>`})}var Bc=`
1904
1904
  </section>
1905
1905
 
1906
1906
  <section id="tab-channels" class="tab">
1907
- ${K({icon:de.channels,title:"Where your agents show up",lead:"Connect a chat app, and your agents can answer from there. Set up once \u2014 they'll keep working in the background."})}
1908
- ${re({persistKey:"channels",bodyHtml:"<b>How does this work?</b> Connect Telegram with a bot token or pair WhatsApp with a QR code. For webhook sources (GitHub, GitLab), use the URL shown in setup. Slack and Discord adapters are not supported in this build."})}
1907
+ ${K({icon:me.channels,title:"Where your agents show up",lead:"Connect a chat app, and your agents can answer from there. Set up once \u2014 they'll keep working in the background."})}
1908
+ ${se({persistKey:"channels",bodyHtml:"<b>How does this work?</b> Connect Telegram with a bot token or pair WhatsApp with a QR code. For webhook sources (GitHub, GitLab), use the URL shown in setup. Slack and Discord adapters are not supported in this build."})}
1909
1909
 
1910
1910
  <details class="add-form" style="margin-top:14px;margin-bottom:18px" id="notif-section">
1911
1911
  <summary class="primary">\u2699 Notifications routing</summary>
@@ -1990,10 +1990,10 @@ ${Uc}</script>`})}var Bc=`
1990
1990
  </div>
1991
1991
  </details>
1992
1992
 
1993
- <div id="ch-chatapps-label">${Lt({label:"Chat apps"})}</div>
1993
+ <div id="ch-chatapps-label">${$t({label:"Chat apps"})}</div>
1994
1994
  <div class="ax-connectors" id="ch-chatapps"></div>
1995
1995
 
1996
- <div id="ch-devtools-label">${Lt({label:"Developer tools",rightHtml:'<span class="ax-pill">Send events from GitHub, GitLab, Sentry, etc.</span>'})}</div>
1996
+ <div id="ch-devtools-label">${$t({label:"Developer tools",rightHtml:'<span class="ax-pill">Send events from GitHub, GitLab, Sentry, etc.</span>'})}</div>
1997
1997
  <div class="ax-connectors" id="ch-devtools"></div>
1998
1998
 
1999
1999
  <!-- Active-channel configuration panes. One shows at a time; clicking
@@ -2011,8 +2011,8 @@ ${Uc}</script>`})}var Bc=`
2011
2011
  </section>
2012
2012
 
2013
2013
  <section id="tab-crons" class="tab">
2014
- ${K({icon:de.schedules,title:"Schedules",lead:"Make an agent do something on a timer \u2014 no one has to ask. Daily summaries, weekly reports, hourly health checks."})}
2015
- ${re({persistKey:"crons",bodyHtml:"<b>What's a good schedule?</b> Anything recurring. A <i>Reports agent</i> sending Monday-morning numbers, a <i>Health agent</i> pinging you at 3am if a server's down, a <i>Standup agent</i> reminding the team. Pick a time below."})}
2014
+ ${K({icon:me.schedules,title:"Schedules",lead:"Make an agent do something on a timer \u2014 no one has to ask. Daily summaries, weekly reports, hourly health checks."})}
2015
+ ${se({persistKey:"crons",bodyHtml:"<b>What's a good schedule?</b> Anything recurring. A <i>Reports agent</i> sending Monday-morning numbers, a <i>Health agent</i> pinging you at 3am if a server's down, a <i>Standup agent</i> reminding the team. Pick a time below."})}
2016
2016
  <div id="cron-list" class="ax-stack" style="margin-bottom:22px"></div>
2017
2017
 
2018
2018
  <div class="ax-builder">
@@ -2109,8 +2109,8 @@ ${Uc}</script>`})}var Bc=`
2109
2109
  </section>
2110
2110
 
2111
2111
  <section id="tab-webhooks" class="tab">
2112
- ${K({icon:de.webhooks,title:"Webhooks",lead:"A URL you give to another service. When something happens there \u2014 a PR is merged, an error fires \u2014 they POST to that URL, and we forward it to your agent as a readable message."})}
2113
- ${re({persistKey:"webhooks",bodyHtml:`<b>Not sure you need this?</b> If a service you use has a "webhooks" setting (GitHub, Stripe, Sentry, Typeform\u2026), you probably do. It's how those services tell AgentX when something's worth looking at.`})}
2112
+ ${K({icon:me.webhooks,title:"Webhooks",lead:"A URL you give to another service. When something happens there \u2014 a PR is merged, an error fires \u2014 they POST to that URL, and we forward it to your agent as a readable message."})}
2113
+ ${se({persistKey:"webhooks",bodyHtml:`<b>Not sure you need this?</b> If a service you use has a "webhooks" setting (GitHub, Stripe, Sentry, Typeform\u2026), you probably do. It's how those services tell AgentX when something's worth looking at.`})}
2114
2114
  <div id="webhook-list" class="ax-stack"></div>
2115
2115
  <div class="add-form">
2116
2116
  <h3>Add a webhook</h3>
@@ -2151,10 +2151,10 @@ ${Uc}</script>`})}var Bc=`
2151
2151
  </section>
2152
2152
 
2153
2153
  <section id="tab-mesh" class="tab">
2154
- ${K({icon:de.mesh,title:"Mesh",lead:"Link this AgentX to other machines so they share work. Good for teams running AgentX on multiple laptops or a mix of laptop + server."})}
2154
+ ${K({icon:me.mesh,title:"Mesh",lead:"Link this AgentX to other machines so they share work. Good for teams running AgentX on multiple laptops or a mix of laptop + server."})}
2155
2155
  <div id="mesh-hero" class="ax-mesh-hero"></div>
2156
- ${re({persistKey:"mesh",bodyHtml:"<b>Do I need mesh?</b> Only if you're running AgentX in more than one place. Solo users on one laptop can skip this entirely."})}
2157
- ${Lt({label:"Connected peers"})}
2156
+ ${se({persistKey:"mesh",bodyHtml:"<b>Do I need mesh?</b> Only if you're running AgentX in more than one place. Solo users on one laptop can skip this entirely."})}
2157
+ ${$t({label:"Connected peers"})}
2158
2158
  <div id="mesh-peers" class="ax-stack"></div>
2159
2159
  <div class="add-form">
2160
2160
  <h3>Add a peer</h3>
@@ -2181,8 +2181,8 @@ ${Uc}</script>`})}var Bc=`
2181
2181
  </section>
2182
2182
 
2183
2183
  <section id="tab-business" class="tab">
2184
- ${K({icon:de.tokens,title:"Business layer",lead:"Org chart, projects, and contact map \u2014 the data that drives PM gating and activity-graph attribution. Same as agentx business in the terminal."})}
2185
- ${re({persistKey:"business",bodyHtml:'<b>Three concepts.</b> The <b>org chart</b> is who reports to whom (<code>reportsTo</code>). <b>Projects</b> map an id to a PM and client (drives the PM gate and lets the activity graph attribute work to the right client). The <b>contact map</b> tells the activity graph which client a Telegram/WhatsApp chat belongs to \u2014 without it, free-text channels fall into the catch-all "internal" bucket. Editing here writes to <code>agentx.json</code>; restart the daemon (or POST /reload) for the change to take effect.'})}
2184
+ ${K({icon:me.tokens,title:"Business layer",lead:"Org chart, projects, and contact map \u2014 the data that drives PM gating and activity-graph attribution. Same as agentx business in the terminal."})}
2185
+ ${se({persistKey:"business",bodyHtml:'<b>Three concepts.</b> The <b>org chart</b> is who reports to whom (<code>reportsTo</code>). <b>Projects</b> map an id to a PM and client (drives the PM gate and lets the activity graph attribute work to the right client). The <b>contact map</b> tells the activity graph which client a Telegram/WhatsApp chat belongs to \u2014 without it, free-text channels fall into the catch-all "internal" bucket. Editing here writes to <code>agentx.json</code>; restart the daemon (or POST /reload) for the change to take effect.'})}
2186
2186
 
2187
2187
  <div class="ax-stack" style="margin-top:14px">
2188
2188
  <h3 style="margin:0 0 6px;font-size:13px">Org chart</h3>
@@ -2269,8 +2269,8 @@ ${Uc}</script>`})}var Bc=`
2269
2269
  </section>
2270
2270
 
2271
2271
  <section id="tab-boards-cfg" class="tab">
2272
- ${K({icon:de.tokens,title:"Kanban boards",lead:"Configure the boards rendered on the home page. Same as agentx board add, edit, remove and column in the terminal. Source is GitLab today; backlog/wiki sources land when the schema unlocks them."})}
2273
- ${re({persistKey:"boards-cfg",bodyHtml:'<b>Two layers.</b> A board points to one or more GitLab projects (<code>source.projects</code>) and optionally filters by a primary tool label. Inside each board, <b>columns</b> map drag-drop actions to scoped-labels (e.g. dropping a card on "Doing" adds <code>Status::Doing</code>). The default flow is Open \u2192 To Do \u2192 Doing \u2192 On Hold \u2192 Review \u2192 Closed; override per-board with the column controls below.'})}
2272
+ ${K({icon:me.tokens,title:"Kanban boards",lead:"Configure the boards rendered on the home page. Same as agentx board add, edit, remove and column in the terminal. Source is GitLab today; backlog/wiki sources land when the schema unlocks them."})}
2273
+ ${se({persistKey:"boards-cfg",bodyHtml:'<b>Two layers.</b> A board points to one or more GitLab projects (<code>source.projects</code>) and optionally filters by a primary tool label. Inside each board, <b>columns</b> map drag-drop actions to scoped-labels (e.g. dropping a card on "Doing" adds <code>Status::Doing</code>). The default flow is Open \u2192 To Do \u2192 Doing \u2192 On Hold \u2192 Review \u2192 Closed; override per-board with the column controls below.'})}
2274
2274
 
2275
2275
  <div class="ax-stack" style="margin-top:14px">
2276
2276
  <h3 style="margin:0 0 6px;font-size:13px">Boards</h3>
@@ -2294,8 +2294,8 @@ ${Uc}</script>`})}var Bc=`
2294
2294
  </section>
2295
2295
 
2296
2296
  <section id="tab-actions" class="tab">
2297
- ${K({icon:de.actions,title:"Action registry",lead:"Reusable shell commands and HTTP calls. Workflows invoke them by id; the dashboard runs them on demand for smoke-tests. Same as agentx actions in the terminal."})}
2298
- ${re({persistKey:"actions",bodyHtml:"<b>Two flavors.</b> <code>shell</code> runs a templated command on the daemon host (cwd + extra env vars supported). <code>http</code> calls a URL with templated method/headers/body. Inputs are typed (string / number / boolean) and fill <code>{{name}}</code> markers; <code>$VAR</code> resolves against the daemon's process env. Output capped at 32KB."})}
2297
+ ${K({icon:me.actions,title:"Action registry",lead:"Reusable shell commands and HTTP calls. Workflows invoke them by id; the dashboard runs them on demand for smoke-tests. Same as agentx actions in the terminal."})}
2298
+ ${se({persistKey:"actions",bodyHtml:"<b>Two flavors.</b> <code>shell</code> runs a templated command on the daemon host (cwd + extra env vars supported). <code>http</code> calls a URL with templated method/headers/body. Inputs are typed (string / number / boolean) and fill <code>{{name}}</code> markers; <code>$VAR</code> resolves against the daemon's process env. Output capped at 32KB."})}
2299
2299
 
2300
2300
  <div class="ax-stack" style="margin-top:14px">
2301
2301
  <h3 style="margin:0 0 6px;font-size:13px">Registered actions</h3>
@@ -2350,8 +2350,8 @@ ${Uc}</script>`})}var Bc=`
2350
2350
  </section>
2351
2351
 
2352
2352
  <section id="tab-tokens" class="tab">
2353
- ${K({icon:de.tokens,title:"Access tokens",lead:"Passwords, but for software. Anything that wants to talk to AgentX from outside (a Slack bridge, another AgentX machine, a script) uses one."})}
2354
- ${re({persistKey:"tokens",bodyHtml:"<b>Tokens get scopes.</b> A scope is what the token is allowed to do. Give the narrowest one that works \u2014 a Slack bridge only needs to send messages, it doesn't need to edit settings. You can't recover a token after you close this page, so copy it immediately."})}
2353
+ ${K({icon:me.tokens,title:"Access tokens",lead:"Passwords, but for software. Anything that wants to talk to AgentX from outside (a Slack bridge, another AgentX machine, a script) uses one."})}
2354
+ ${se({persistKey:"tokens",bodyHtml:"<b>Tokens get scopes.</b> A scope is what the token is allowed to do. Give the narrowest one that works \u2014 a Slack bridge only needs to send messages, it doesn't need to edit settings. You can't recover a token after you close this page, so copy it immediately."})}
2355
2355
  <div id="token-list" class="ax-stack"></div>
2356
2356
  <div class="add-form">
2357
2357
  <h3>Mint a new token</h3>
@@ -2370,8 +2370,8 @@ ${Uc}</script>`})}var Bc=`
2370
2370
  </section>
2371
2371
 
2372
2372
  <section id="tab-advanced" class="tab">
2373
- ${K({icon:de.advanced,title:"Raw configuration",lead:"Everything on the other tabs writes to this file. Edit here for bulk changes, diffs, or fields we haven't put in the UI yet. Saving creates a timestamped backup."})}
2374
- ${re({persistKey:"advanced",bodyHtml:`<b>Safe to look, careful editing.</b> We've pretty-printed and annotated each section so you can read it. Click any <span class="mono" style="color:var(--ax-muted)">\u25B8</span> to fold. Switch to <b>Edit</b> to change values \u2014 invalid JSON is refused before saving.`})}
2373
+ ${K({icon:me.advanced,title:"Raw configuration",lead:"Everything on the other tabs writes to this file. Edit here for bulk changes, diffs, or fields we haven't put in the UI yet. Saving creates a timestamped backup."})}
2374
+ ${se({persistKey:"advanced",bodyHtml:`<b>Safe to look, careful editing.</b> We've pretty-printed and annotated each section so you can read it. Click any <span class="mono" style="color:var(--ax-muted)">\u25B8</span> to fold. Switch to <b>Edit</b> to change values \u2014 invalid JSON is refused before saving.`})}
2375
2375
 
2376
2376
  <div class="ax-jv-toolbar">
2377
2377
  <input class="ax-jv-search" id="jv-search" placeholder="Search keys & values\u2026" />
@@ -2397,7 +2397,7 @@ ${Uc}</script>`})}var Bc=`
2397
2397
  <div class="hint-block">Every setting is documented in the <code>docs/reference/config.md</code> reference. Invalid JSON is refused; schema-level errors only surface after the daemon tries to use the new config.</div>
2398
2398
  </section>
2399
2399
  </main>
2400
- `,Fc=`
2400
+ `,Rd=`
2401
2401
 
2402
2402
  /* --- Inner tabs (Agents / Channels / Schedules / \u2026) --- */
2403
2403
  nav.tabs{display:flex;gap:4px;padding:14px 24px 0;background:var(--ax-bg-elev);
@@ -2605,7 +2605,7 @@ textarea.raw{min-height:480px;font-family:var(--ax-mono);font-size:12px;line-hei
2605
2605
  .peer-banner button{background:transparent;border:1px solid currentColor;color:var(--ax-accent);
2606
2606
  padding:4px 10px;border-radius:4px;font:inherit;font-size:11px;cursor:pointer}
2607
2607
  .peer-banner button:hover{background:color-mix(in oklch,var(--ax-accent) 12%,transparent)}
2608
- `,Uc=`
2608
+ `,Pd=`
2609
2609
  const $ = (id) => document.getElementById(id);
2610
2610
  let state = null;
2611
2611
 
@@ -5489,11 +5489,11 @@ for (const btn of document.querySelectorAll('nav.tabs button')) {
5489
5489
  })();
5490
5490
 
5491
5491
  refresh();
5492
- `;function Bo(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(No({peers:a,localToken:n}))}async function zo(t,e){let a=La();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function qo(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await id(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await Kc(t),r={"GET /api/admin/state":()=>Vc(),"POST /api/admin/agents":()=>ad(n),"PATCH /api/admin/agents":()=>nd(n),"DELETE /api/admin/agents":()=>rd(n),"POST /api/admin/agents/access":()=>Yc(n),"POST /api/admin/channels/telegram":()=>od(n),"DELETE /api/admin/channels/telegram":()=>Id(n),"POST /api/admin/channels/telegram/toggle":()=>Md(n),"POST /api/admin/crons":()=>Ld(n),"DELETE /api/admin/crons":()=>Rd(n),"POST /api/admin/config/raw":()=>$d(n),"GET /api/admin/tokens":()=>Qc(),"POST /api/admin/tokens":()=>Zc(n),"DELETE /api/admin/tokens":()=>ed(n),"POST /api/admin/agents/test":()=>td(n),"POST /api/admin/agents/integrations":()=>md(n),"DELETE /api/admin/agents/integrations":()=>fd(n),"PATCH /api/admin/agents/integrations":()=>hd(n),"PATCH /api/admin/channels/telegram":()=>sd(n),"POST /api/admin/channels/slack":()=>kd(n),"POST /api/admin/channels/slack/toggle":()=>_d(n),"POST /api/admin/channels/discord":()=>Sd(n),"POST /api/admin/channels/discord/toggle":()=>Ed(n),"POST /api/admin/channels/gitlab":()=>Td(n),"POST /api/admin/channels/gitlab/toggle":()=>Ad(n),"POST /api/admin/channels/request-status":()=>Or(n),"GET /api/admin/channels/whatsapp/state":()=>Qe("/whatsapp/state"),"GET /api/admin/channels/webrtc/history":()=>Qe("/webrtc/history"),"POST /api/admin/actions":()=>Gd(n),"DELETE /api/admin/actions":()=>Xd(n),"POST /api/admin/actions/run":()=>Kd(n),"GET /api/admin/channels/whatsapp/chats":()=>Qe("/whatsapp/chats"),"GET /api/admin/channels/whatsapp/contacts":()=>Qe("/whatsapp/contacts"),"POST /api/admin/channels/whatsapp/ingest":()=>me("/whatsapp/ingest",n),"POST /api/admin/crons/preview":()=>Cd(n),"POST /api/admin/webhooks":()=>gd(n),"PATCH /api/admin/webhooks":()=>xd(n),"DELETE /api/admin/webhooks":()=>wd(n),"POST /api/admin/whatsapp-triage":()=>$o(n),"POST /api/admin/whatsapp-triage/rules":()=>Po(n),"PATCH /api/admin/whatsapp-triage/rules":()=>jo(n),"DELETE /api/admin/whatsapp-triage/rules":()=>Oo(n),"POST /api/admin/mesh/peers":()=>vd(n),"DELETE /api/admin/mesh/peers":()=>bd(n),"POST /api/admin/mesh/toggle":()=>yd(n),"GET /api/admin/files":()=>ld(t),"GET /api/admin/files/read":()=>cd(t),"PUT /api/admin/files":()=>dd(n),"POST /api/admin/files/skill":()=>pd(n),"DELETE /api/admin/files/skill":()=>ud(n),"POST /api/admin/business/orgchart":()=>Pd(n),"DELETE /api/admin/business/orgchart":()=>jd(n),"POST /api/admin/business/project":()=>Od(n),"DELETE /api/admin/business/project":()=>Hd(n),"POST /api/admin/business/client":()=>Nd(n),"DELETE /api/admin/business/client":()=>Dd(n),"POST /api/admin/business/contact":()=>Bd(n),"DELETE /api/admin/business/contact":()=>zd(n),"POST /api/admin/boards":()=>qd(n),"DELETE /api/admin/boards":()=>Fd(n),"POST /api/admin/boards/columns":()=>Ud(n),"DELETE /api/admin/boards/columns":()=>Wd(n),"POST /api/admin/notifications":()=>Vd(n),"POST /api/admin/screen":()=>Yd(n),"POST /api/admin/webhooks/triggers":()=>Qd(n),"POST /api/admin/mesh/health":()=>Jd(n),"GET /api/admin/projects":()=>Qe("/api/admin/projects"),"POST /api/admin/projects/workflows/link":()=>me("/api/admin/projects/workflows/link",n),"POST /api/admin/projects/workflows/unlink":()=>me("/api/admin/projects/workflows/unlink",n),"POST /api/admin/projects/header":()=>me("/api/admin/projects/header",n),"POST /api/admin/projects/clauses":()=>me("/api/admin/projects/clauses",n),"POST /api/admin/projects/contacts/link":()=>me("/api/admin/projects/contacts/link",n),"POST /api/admin/projects/contacts/unlink":()=>me("/api/admin/projects/contacts/unlink",n),"POST /api/admin/projects/create":()=>me("/api/admin/projects/create",n),"POST /api/admin/projects/delete":()=>me("/api/admin/projects/delete",n)},o=`${t.method} ${a}`,s=r[o];if(!s){Ia(e,404,{error:`unknown admin endpoint: ${o}`});return}let i=await s();Ia(e,200,i)}catch(n){Ia(e,400,{error:n.message||"admin op failed"})}}function Ia(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Kc(t){return new Promise((e,a)=>{let n="";t.on("data",r=>{n+=r}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(r){a(r)}}),t.on("error",a)})}function Jc(t){let e=Fe(process.cwd(),t);if(!Wt(e))return[];let a=[];for(let n of Xc(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".json")))try{a.push(JSON.parse(Do(Fe(e,n.name),"utf-8")))}catch{}return a}function La(){let t=Fe(process.cwd(),"agentx.json");return Wt(t)?JSON.parse(Do(t,"utf-8")):null}function Vc(){let t=La();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([d,f])=>({id:d,name:f.name,tier:f.tier,model:f.model,mentions:f.mentions||[],workspace:f.workspace,access:f.access||"private",systemPrompt:f.systemPrompt||"",maxConcurrent:f.maxConcurrent??1,maxExecutionMinutes:f.maxExecutionMinutes??20,permissionMode:f.permissionMode||"default",integrations:(Array.isArray(f.integrations)?f.integrations:[]).map(x=>{let b=x.credentials||{},k={};for(let[T,w]of Object.entries(b))typeof w=="string"&&/^[A-Z][A-Z0-9_]*$/.test(w)?k[T]=process.env[w]?"set":"unset":typeof w=="string"&&(k[T]="literal");return{kind:x.kind,label:x.label,enabled:x.enabled!==!1,credentials:b,credStatus:k,metadata:x.metadata||{}}})})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([d,f])=>({id:d,botUsername:f.botUsername||"",agentBinding:f.agentBinding||"",botTokenRef:f.token||""}))},r={enabled:!!t.channels?.slack?.enabled,botTokenRef:t.channels?.slack?.botToken||"",appTokenRef:t.channels?.slack?.appToken||"",agentBinding:t.channels?.slack?.agentBinding||""},o={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},i={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(([d,f])=>({id:d,schedule:f.schedule,agent:f.agent,prompt:(f.prompt||"").slice(0,200),enabled:f.enabled!==!1})),c=Array.isArray(t.webhooks)?t.webhooks.map(d=>({id:d.id,source:d.source,agentId:d.agentId,secretEnv:d.secretEnv||"",description:d.description||"",enabled:d.enabled!==!1,triggers:d.triggers&&typeof d.triggers=="object"?d.triggers:{},defaultWorkflow:d.defaultWorkflow||""})):[],p={enabled:!!t.mesh?.enabled,discovery:t.mesh?.discovery||"static",peers:(t.mesh?.peers||[]).map(d=>({url:d.url,name:d.name,hasToken:!!d.token})),healthCheck:{interval:t.mesh?.healthCheck?.interval??60,timeout:t.mesh?.healthCheck?.timeout??10}},u=t.dashboard?.daemonUrl||"http://localhost:18800",m=t.business||{},h={enabled:!!m.enabled,timezone:m.timezone||"UTC",orgChart:m.orgChart||{},projects:Array.isArray(m.projects)?m.projects:[],contactMap:Array.isArray(m.contactMap)?m.contactMap:[],clients:m.clients&&typeof m.clients=="object"?m.clients:{}},_=t.notifications||{},v={longTaskThreshold:_.longTaskThreshold??30,destination:_.destination||null,on:{taskComplete:_.on?.taskComplete!==!1,taskError:_.on?.taskError!==!1,taskQueued:!!_.on?.taskQueued},local:qn(_.local),ntfy:Dr(t.channels?.ntfy)},S=[];try{S=Jc(".agentx/actions").filter(f=>f&&typeof f=="object"&&f.id).map(f=>({id:f.id,title:f.title,kind:f.kind,description:f.description||"",inputs:Array.isArray(f.inputs)?f.inputs:[],timeoutMs:f.timeoutMs??3e4,command:f.kind==="shell"?f.command:void 0,url:f.kind==="http"?f.url:void 0,method:f.kind==="http"?f.method:void 0})).sort((f,x)=>f.id.localeCompare(x.id))}catch{}let g=(Array.isArray(t.boards)?t.boards:[]).map(d=>({id:d.id,name:d.name,source:d.source||{type:"gitlab",projects:[]},primaryToolLabel:d.primaryToolLabel||"",timeRangeDays:d.timeRangeDays??30,closedWindowDays:d.closedWindowDays??30,columns:Array.isArray(d.columns)?d.columns:[]}));return{exists:!0,agents:e,telegram:n,slack:r,discord:o,gitlab:s,whatsapp:i,requestStatus:jr(t),whatsappTriage:Ro(t),crons:l,webhooks:c,mesh:p,daemonUrl:u,nodeName:t.node?.name,business:h,boards:g,notifications:v,screen:hr(t.screen),actions:S}}function Yc(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}=A(r=>{if(!r.agents?.[e])throw new Error(`Agent "${e}" not found.`);return r.agents[e].access=a,`agent "${e}" is now ${a}`});return{summary:n}}function Qc(){return new F().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 Zc(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:r,record:o}=new F().create({name:e,scopes:a,expiresInDays:n});return{summary:`created token "${e}"`,token:r,record:o}}function ed(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Token id is required.");let a=new F().revoke(e);if(!a)throw new Error(`Token "${e}" not found.`);return{summary:`revoked token ${e} (${a.name})`}}async function td(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 r="http://127.0.0.1:18800",o;try{let p=X();r=p.dashboard.daemonUrl.replace(/\/+$/,"")||r,o=p.dashboard.token}catch{}let s={"Content-Type":"application/json"};o&&(s.Authorization=`Bearer ${o}`);let i=await fetch(`${r}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"test-drive",sender:"admin",chatId:n}})}),l=await i.text(),c;try{c=JSON.parse(l)}catch{c={content:l}}if(!i.ok)throw new Error(c?.error||`daemon HTTP ${i.status}`);return{chatId:n,response:c}}function ad(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=["claude-code","codex-cli","opencode","sdk","orchestrator"].includes(t?.tier)?t.tier:"claude-code",r=Uo(t?.triggerWords),o=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(r.length===0)throw new Error("At least one trigger word is required.");let i=Fe(process.cwd(),"agents",e),{summary:l}=A(p=>{if(p.agents=p.agents||{},p.agents[e])throw new Error(`Agent "${e}" already exists.`);let u={name:a,workspace:i,tier:n,mentions:r,maxConcurrent:2,permissionMode:"default"};return o&&(u.model=o),s&&(u.systemPrompt=s.slice(0,400)),p.agents[e]=u,`added agent "${e}"`}),c=Fe(i,"CLAUDE.md");if(!Wt(c))try{Wc(i,{recursive:!0}),Ho(c,`# ${a}
5492
+ `;function ss(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ns({peers:a,localToken:n}))}async function is(t,e){let a=Ba();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function ls(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await Vd(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await Nd(t),r={"GET /api/admin/state":()=>Hd(),"POST /api/admin/agents":()=>Wd(n),"PATCH /api/admin/agents":()=>Gd(n),"DELETE /api/admin/agents":()=>Xd(n),"POST /api/admin/agents/access":()=>Bd(n),"POST /api/admin/channels/telegram":()=>Kd(n),"DELETE /api/admin/channels/telegram":()=>bp(n),"POST /api/admin/channels/telegram/toggle":()=>vp(n),"POST /api/admin/crons":()=>yp(n),"DELETE /api/admin/crons":()=>wp(n),"POST /api/admin/config/raw":()=>kp(n),"GET /api/admin/tokens":()=>zd(),"POST /api/admin/tokens":()=>qd(n),"DELETE /api/admin/tokens":()=>Fd(n),"POST /api/admin/agents/test":()=>Ud(n),"POST /api/admin/agents/integrations":()=>ap(n),"DELETE /api/admin/agents/integrations":()=>np(n),"PATCH /api/admin/agents/integrations":()=>rp(n),"PATCH /api/admin/channels/telegram":()=>Jd(n),"POST /api/admin/channels/slack":()=>pp(n),"POST /api/admin/channels/slack/toggle":()=>up(n),"POST /api/admin/channels/discord":()=>mp(n),"POST /api/admin/channels/discord/toggle":()=>fp(n),"POST /api/admin/channels/gitlab":()=>hp(n),"POST /api/admin/channels/gitlab/toggle":()=>gp(n),"POST /api/admin/channels/request-status":()=>Xr(n),"GET /api/admin/channels/whatsapp/state":()=>nt("/whatsapp/state"),"GET /api/admin/channels/webrtc/history":()=>nt("/webrtc/history"),"POST /api/admin/actions":()=>jp(n),"DELETE /api/admin/actions":()=>Op(n),"POST /api/admin/actions/run":()=>Np(n),"GET /api/admin/channels/whatsapp/chats":()=>nt("/whatsapp/chats"),"GET /api/admin/channels/whatsapp/contacts":()=>nt("/whatsapp/contacts"),"POST /api/admin/channels/whatsapp/ingest":()=>xe("/whatsapp/ingest",n),"POST /api/admin/crons/preview":()=>xp(n),"POST /api/admin/webhooks":()=>op(n),"PATCH /api/admin/webhooks":()=>sp(n),"DELETE /api/admin/webhooks":()=>dp(n),"POST /api/admin/whatsapp-triage":()=>Zo(n),"POST /api/admin/whatsapp-triage/rules":()=>es(n),"PATCH /api/admin/whatsapp-triage/rules":()=>ts(n),"DELETE /api/admin/whatsapp-triage/rules":()=>as(n),"POST /api/admin/mesh/peers":()=>ip(n),"DELETE /api/admin/mesh/peers":()=>lp(n),"POST /api/admin/mesh/toggle":()=>cp(n),"GET /api/admin/files":()=>Yd(t),"GET /api/admin/files/read":()=>Qd(t),"PUT /api/admin/files":()=>Zd(n),"POST /api/admin/files/skill":()=>ep(n),"DELETE /api/admin/files/skill":()=>tp(n),"POST /api/admin/business/orgchart":()=>_p(n),"DELETE /api/admin/business/orgchart":()=>Sp(n),"POST /api/admin/business/project":()=>Ep(n),"DELETE /api/admin/business/project":()=>Cp(n),"POST /api/admin/business/client":()=>Tp(n),"DELETE /api/admin/business/client":()=>Ap(n),"POST /api/admin/business/contact":()=>Ip(n),"DELETE /api/admin/business/contact":()=>Mp(n),"POST /api/admin/boards":()=>Lp(n),"DELETE /api/admin/boards":()=>Rp(n),"POST /api/admin/boards/columns":()=>Pp(n),"DELETE /api/admin/boards/columns":()=>$p(n),"POST /api/admin/notifications":()=>Hp(n),"POST /api/admin/screen":()=>Bp(n),"POST /api/admin/webhooks/triggers":()=>zp(n),"POST /api/admin/mesh/health":()=>Dp(n),"GET /api/admin/projects":()=>nt("/api/admin/projects"),"POST /api/admin/projects/workflows/link":()=>xe("/api/admin/projects/workflows/link",n),"POST /api/admin/projects/workflows/unlink":()=>xe("/api/admin/projects/workflows/unlink",n),"POST /api/admin/projects/header":()=>xe("/api/admin/projects/header",n),"POST /api/admin/projects/clauses":()=>xe("/api/admin/projects/clauses",n),"POST /api/admin/projects/contacts/link":()=>xe("/api/admin/projects/contacts/link",n),"POST /api/admin/projects/contacts/unlink":()=>xe("/api/admin/projects/contacts/unlink",n),"POST /api/admin/projects/create":()=>xe("/api/admin/projects/create",n),"POST /api/admin/projects/delete":()=>xe("/api/admin/projects/delete",n)},o=`${t.method} ${a}`,s=r[o];if(!s){Da(e,404,{error:`unknown admin endpoint: ${o}`});return}let i=await s();Da(e,200,i)}catch(n){Da(e,400,{error:n.message||"admin op failed"})}}function Da(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Nd(t){return new Promise((e,a)=>{let n="";t.on("data",r=>{n+=r}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(r){a(r)}}),t.on("error",a)})}function Dd(t){let e=Xe(process.cwd(),t);if(!Jt(e))return[];let a=[];for(let n of Od(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".json")))try{a.push(JSON.parse(rs(Xe(e,n.name),"utf-8")))}catch{}return a}function Ba(){let t=Xe(process.cwd(),"agentx.json");return Jt(t)?JSON.parse(rs(t,"utf-8")):null}function Hd(){let t=Ba();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([x,u])=>({id:x,name:u.name,tier:u.tier,model:u.model,mentions:u.mentions||[],workspace:u.workspace,access:u.access||"private",systemPrompt:u.systemPrompt||"",maxConcurrent:u.maxConcurrent??1,maxExecutionMinutes:u.maxExecutionMinutes??20,permissionMode:u.permissionMode||"default",integrations:(Array.isArray(u.integrations)?u.integrations:[]).map(h=>{let w=h.credentials||{},y={};for(let[T,v]of Object.entries(w))typeof v=="string"&&/^[A-Z][A-Z0-9_]*$/.test(v)?y[T]=process.env[v]?"set":"unset":typeof v=="string"&&(y[T]="literal");return{kind:h.kind,label:h.label,enabled:h.enabled!==!1,credentials:w,credStatus:y,metadata:h.metadata||{}}})})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([x,u])=>({id:x,botUsername:u.botUsername||"",agentBinding:u.agentBinding||"",botTokenRef:u.token||""}))},r={enabled:!!t.channels?.slack?.enabled,botTokenRef:t.channels?.slack?.botToken||"",appTokenRef:t.channels?.slack?.appToken||"",agentBinding:t.channels?.slack?.agentBinding||""},o={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},i={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(([x,u])=>({id:x,schedule:u.schedule,agent:u.agent,prompt:(u.prompt||"").slice(0,200),enabled:u.enabled!==!1})),c=Array.isArray(t.webhooks)?t.webhooks.map(x=>({id:x.id,source:x.source,agentId:x.agentId,secretEnv:x.secretEnv||"",description:x.description||"",enabled:x.enabled!==!1,triggers:x.triggers&&typeof x.triggers=="object"?x.triggers:{},defaultWorkflow:x.defaultWorkflow||""})):[],d={enabled:!!t.mesh?.enabled,discovery:t.mesh?.discovery||"static",peers:(t.mesh?.peers||[]).map(x=>({url:x.url,name:x.name,hasToken:!!x.token})),healthCheck:{interval:t.mesh?.healthCheck?.interval??60,timeout:t.mesh?.healthCheck?.timeout??10}},p=t.dashboard?.daemonUrl||"http://localhost:18800",m=t.business||{},f={enabled:!!m.enabled,timezone:m.timezone||"UTC",orgChart:m.orgChart||{},projects:Array.isArray(m.projects)?m.projects:[],contactMap:Array.isArray(m.contactMap)?m.contactMap:[],clients:m.clients&&typeof m.clients=="object"?m.clients:{}},S=t.notifications||{},b={longTaskThreshold:S.longTaskThreshold??30,destination:S.destination||null,on:{taskComplete:S.on?.taskComplete!==!1,taskError:S.on?.taskError!==!1,taskQueued:!!S.on?.taskQueued},local:Zn(S.local),ntfy:Jr(t.channels?.ntfy)},E=[];try{E=Dd(".agentx/actions").filter(u=>u&&typeof u=="object"&&u.id).map(u=>({id:u.id,title:u.title,kind:u.kind,description:u.description||"",inputs:Array.isArray(u.inputs)?u.inputs:[],timeoutMs:u.timeoutMs??3e4,command:u.kind==="shell"?u.command:void 0,url:u.kind==="http"?u.url:void 0,method:u.kind==="http"?u.method:void 0})).sort((u,h)=>u.id.localeCompare(h.id))}catch{}let g=(Array.isArray(t.boards)?t.boards:[]).map(x=>({id:x.id,name:x.name,source:x.source||{type:"gitlab",projects:[]},primaryToolLabel:x.primaryToolLabel||"",timeRangeDays:x.timeRangeDays??30,closedWindowDays:x.closedWindowDays??30,columns:Array.isArray(x.columns)?x.columns:[]}));return{exists:!0,agents:e,telegram:n,slack:r,discord:o,gitlab:s,whatsapp:i,requestStatus:Gr(t),whatsappTriage:Qo(t),crons:l,webhooks:c,mesh:d,daemonUrl:p,nodeName:t.node?.name,business:f,boards:g,notifications:b,screen:Tr(t.screen),actions:E}}function Bd(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}=C(r=>{if(!r.agents?.[e])throw new Error(`Agent "${e}" not found.`);return r.agents[e].access=a,`agent "${e}" is now ${a}`});return{summary:n}}function zd(){return new G().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 qd(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:r,record:o}=new G().create({name:e,scopes:a,expiresInDays:n});return{summary:`created token "${e}"`,token:r,record:o}}function Fd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Token id is required.");let a=new G().revoke(e);if(!a)throw new Error(`Token "${e}" not found.`);return{summary:`revoked token ${e} (${a.name})`}}async function Ud(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 r="http://127.0.0.1:18800",o;try{let d=X();r=d.dashboard.daemonUrl.replace(/\/+$/,"")||r,o=d.dashboard.token}catch{}let s={"Content-Type":"application/json"};o&&(s.Authorization=`Bearer ${o}`);let i=await fetch(`${r}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"test-drive",sender:"admin",chatId:n}})}),l=await i.text(),c;try{c=JSON.parse(l)}catch{c={content:l}}if(!i.ok)throw new Error(c?.error||`daemon HTTP ${i.status}`);return{chatId:n,response:c}}function Wd(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=["claude-code","codex-cli","opencode","sdk","orchestrator"].includes(t?.tier)?t.tier:"claude-code",r=ds(t?.triggerWords),o=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(r.length===0)throw new Error("At least one trigger word is required.");let i=Xe(process.cwd(),"agents",e),{summary:l}=C(d=>{if(d.agents=d.agents||{},d.agents[e])throw new Error(`Agent "${e}" already exists.`);let p={name:a,workspace:i,tier:n,mentions:r,maxConcurrent:2,permissionMode:"default"};return o&&(p.model=o),s&&(p.systemPrompt=s.slice(0,400)),d.agents[e]=p,`added agent "${e}"`}),c=Xe(i,"CLAUDE.md");if(!Jt(c))try{$d(i,{recursive:!0}),os(c,`# ${a}
5493
5493
 
5494
5494
  ${s||"You are "+a+"."}
5495
- `)}catch{}return{summary:l}}function nd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let a=t?.patch||{},{summary:n}=A(r=>{if(!r.agents?.[e])throw new Error(`Agent "${e}" not found.`);let o=r.agents[e];return typeof a.name=="string"&&a.name.trim()&&(o.name=a.name.trim()),typeof a.model=="string"&&(o.model=a.model.trim()||void 0),typeof a.tier=="string"&&["claude-code","codex-cli","opencode","sdk","orchestrator"].includes(a.tier)&&(o.tier=a.tier),typeof a.systemPrompt=="string"&&(o.systemPrompt=a.systemPrompt.trim()||void 0),Array.isArray(a.mentions)?o.mentions=a.mentions.map(s=>String(s).trim()).filter(Boolean):typeof a.triggerWords=="string"&&(o.mentions=Uo(a.triggerWords)),typeof a.maxConcurrent=="number"&&a.maxConcurrent>=1&&(o.maxConcurrent=a.maxConcurrent),typeof a.maxExecutionMinutes=="number"&&a.maxExecutionMinutes>=1&&a.maxExecutionMinutes<=240&&(o.maxExecutionMinutes=a.maxExecutionMinutes),typeof a.permissionMode=="string"&&(o.permissionMode=a.permissionMode),(a.access==="public"||a.access==="private")&&(o.access=a.access),`updated agent "${e}"`});return{summary:n}}function rd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let{summary:a}=A(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 r of Object.keys(n.channels.telegram.accounts))n.channels.telegram.accounts[r]?.agentBinding===e&&(n.channels.telegram.accounts[r].agentBinding="");return`removed agent "${e}"`});return{summary:a}}function od(t){let e=String(t?.id||"").trim(),a=String(t?.agentBinding||"").trim(),n=String(t?.botUsername||"").trim(),r=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(!r)throw new Error("Bot token env-var name is required (e.g. TG_SUPPORT_BOT_TOKEN).");let{summary:o}=A(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]={token:"${"+r+"}",agentBinding:a},`added telegram account "${e}"`});return{summary:o,hint:`Add ${r}=<bot-token> to your .env file.`}}function sd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let a=t?.patch||{},{summary:n}=A(r=>{let o=r.channels?.telegram?.accounts?.[e];if(!o)throw new Error(`Account "${e}" not found.`);if(typeof a.agentBinding=="string"&&a.agentBinding.trim()){if(!r.agents?.[a.agentBinding])throw new Error(`Unknown agent "${a.agentBinding}".`);o.agentBinding=a.agentBinding.trim()}return typeof a.botUsername=="string"&&(o.botUsername=a.botUsername.trim()),typeof a.botTokenEnv=="string"&&a.botTokenEnv.trim()&&(o.token="${"+a.botTokenEnv.trim()+"}"),`updated telegram account "${e}"`});return{summary:n}}async function Qe(t){let{url:e,headers:a}=Ra(),n=await fetch(e+t,{headers:a}),r=await n.text();if(!n.ok)throw new Error(`daemon ${n.status}: ${r.slice(0,200)}`);try{return JSON.parse(r)}catch{return{raw:r}}}async function me(t,e){let{url:a,headers:n}=Ra(),r=await fetch(a+t,{method:"POST",headers:{...n,"Content-Type":"application/json"},body:JSON.stringify(e||{})}),o=await r.text();if(!r.ok)throw new Error(`daemon ${r.status}: ${o.slice(0,200)}`);try{return JSON.parse(o)}catch{return{raw:o}}}async function id(t,e){try{let{url:a,headers:n}=Ra(),r=await fetch(a+e,{headers:n}),o=await r.text();t.writeHead(r.status,{"Content-Type":r.headers.get("content-type")||"image/svg+xml","Cache-Control":"no-store"}),t.end(o)}catch(a){t.writeHead(502,{"Content-Type":"text/plain; charset=utf-8"}),t.end("daemon unreachable: "+(a?.message||"unknown"))}}function Ra(){let t="http://127.0.0.1:18800",e={};try{let a=X();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function Ze(t){let a=La()?.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 Ma(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function ld(t){let e=Ma(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=De(Ze(e));return{agentId:e,...a}}function cd(t){let e=Ma(t,"agent").trim(),a=Ma(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return Et(Ze(e),a)}function dd(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 r=Tt(Ze(e),a,n);return{summary:`saved ${a} (${r.bytes} bytes)`,...r}}function pd(t){let e=String(t?.agent||"").trim(),a=String(t?.slug||"").trim(),n=t?.title?String(t.title):void 0,r=t?.content?String(t.content):void 0;if(!e)throw new Error("agent is required.");let o=At(Ze(e),a,{title:n,content:r});return{summary:`added skill "${a}"`,...o}}function ud(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=Ct(Ze(e),a);return{summary:`removed skill "${a}"`,...n}}function md(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a)throw new Error("kind is required");if(!n)throw new Error("label is required");let r={},o=t?.credentials||{};for(let l of["tokenEnv","privateAppTokenEnv","apiKeyEnv","refreshTokenEnv","clientIdEnv","clientSecretEnv"]){let c=o[l];if(typeof c=="string"&&c.trim()){if(!/^[A-Z][A-Z0-9_]*$/.test(c.trim()))throw new Error(`${l} must be uppercase identifier (got "${c}")`);r[l]=c.trim()}}if(o.auth==="keyring"&&(r.auth="keyring"),typeof o.sessionDir=="string"&&o.sessionDir.trim()&&(r.sessionDir=o.sessionDir.trim()),Object.keys(r).length===0)throw new Error("at least one credential field required");let s={};for(let[l,c]of Object.entries(t?.metadata||{}))(typeof c=="string"||typeof c=="number"||typeof c=="boolean")&&(s[l]=c);let{summary:i}=A(l=>{if(!l.agents?.[e])throw new Error(`Unknown agent "${e}"`);if(l.agents[e].integrations=Array.isArray(l.agents[e].integrations)?l.agents[e].integrations:[],l.agents[e].integrations.find(c=>c.kind===a&&c.label===n))throw new Error(`integration (${a}, ${n}) already exists on ${e}`);return l.agents[e].integrations.push({kind:a,label:n,credentials:r,metadata:s,enabled:!0}),`added ${a} integration "${n}" to ${e}`});return{summary:i}}function fd(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let{summary:r}=A(o=>{let s=o.agents?.[e];if(!s)throw new Error(`Unknown agent "${e}"`);let i=s.integrations||[],l=i.findIndex(c=>c.kind===a&&c.label===n);if(l===-1)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return i.splice(l,1),`removed ${a} integration "${n}" from ${e}`});return{summary:r}}function hd(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let r=t?.patch||{},{summary:o}=A(s=>{let i=s.agents?.[e];if(!i)throw new Error(`Unknown agent "${e}"`);let c=(i.integrations||[]).find(p=>p.kind===a&&p.label===n);if(!c)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return typeof r.enabled=="boolean"&&(c.enabled=r.enabled),r.metadata&&typeof r.metadata=="object"&&(c.metadata={...c.metadata||{},...r.metadata}),`updated integration (${a}, ${n}) on ${e}`});return{summary:o}}var Fo=["gitlab","github","sentry","stripe","vercel","odoo","hubspot","discord","slack","custom"];function gd(t){let e=String(t?.id||"").trim(),a=String(t?.source||"").trim(),n=String(t?.agentId||"").trim(),r=String(t?.secretEnv||"").trim(),o=String(t?.description||"").trim(),s=String(t?.node||"").trim();if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Webhook id must be lowercase (letters, digits, -, _).");if(!Fo.includes(a))throw new Error(`Unknown source: ${a}`);if(!n)throw new Error("Pick an agent to bind the webhook to.");let{summary:i}=A(l=>{if(s){if(!(l.mesh?.peers||[]).find(u=>u.name===s))throw new Error(`Mesh peer "${s}" not found in mesh.peers. Add the peer first or remove the node field.`)}else if(!l.agents?.[n])throw new Error(`Unknown agent "${n}". Add it locally, or set --node <peer> to forward to a mesh peer.`);if(l.webhooks=Array.isArray(l.webhooks)?l.webhooks:[],l.webhooks.find(p=>p.id===e))throw new Error(`Webhook "${e}" already exists.`);let c={id:e,source:a,agentId:n,enabled:!0};return r&&(c.secretEnv=r),o&&(c.description=o),s&&(c.node=s),l.webhooks.push(c),`added webhook "${e}" (${a} \u2192 ${n}${s?` @ ${s}`:""})`});return{summary:i}}function xd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let a=t?.patch||{},{summary:n}=A(r=>{let o=(r.webhooks||[]).find(s=>s.id===e);if(!o)throw new Error(`Webhook "${e}" not found.`);if(typeof a.source=="string"&&Fo.includes(a.source)&&(o.source=a.source),typeof a.agentId=="string"&&a.agentId.trim()){if(!r.agents?.[a.agentId])throw new Error(`Unknown agent "${a.agentId}".`);o.agentId=a.agentId.trim()}return typeof a.secretEnv=="string"&&(o.secretEnv=a.secretEnv.trim()||void 0),typeof a.description=="string"&&(o.description=a.description.trim()||void 0),typeof a.enabled=="boolean"&&(o.enabled=a.enabled),`updated webhook "${e}"`});return{summary:n}}function vd(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:r}=A(o=>{if(o.mesh=o.mesh||{enabled:!0,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},o.mesh.enabled=!0,o.mesh.peers=Array.isArray(o.mesh.peers)?o.mesh.peers:[],o.mesh.peers.find(i=>i.url===e))throw new Error(`Peer at ${e} already registered.`);let s={url:e,name:a};return n&&(s.token=n),o.mesh.peers.push(s),`added mesh peer "${a}"`});return{summary:r}}function bd(t){let e=String(t?.url||"").trim().replace(/\/+$/,"");if(!e)throw new Error("Peer URL is required.");let{summary:a}=A(n=>{let r=(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(o=>o.url.replace(/\/+$/,"")!==e),n.mesh.peers.length===r)throw new Error(`Peer at ${e} not found.`);return`removed mesh peer ${e}`});return{summary:a}}function yd(t){let e=!!t?.enabled,{summary:a}=A(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 wd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let{summary:a}=A(n=>{let r=(n.webhooks||[]).length;if(n.webhooks=(n.webhooks||[]).filter(o=>o.id!==e),n.webhooks.length===r)throw new Error(`Webhook "${e}" not found.`);return`removed webhook "${e}"`});return{summary:a}}function kd(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:r}=A(o=>{if(o.channels=o.channels||{},o.channels.slack=o.channels.slack||{enabled:!1},o.channels.slack.enabled=!0,o.channels.slack.botToken="${"+e+"}",o.channels.slack.appToken="${"+a+"}",n){if(!o.agents?.[n])throw new Error(`Unknown agent "${n}".`);o.channels.slack.agentBinding=n}return"configured slack connector"});return{summary:r,hint:`Add ${e}=xoxb-\u2026 and ${a}=xapp-\u2026 to your .env.`}}function _d(t){let e=!!t?.enabled,{summary:a}=A(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 Sd(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}=A(r=>{if(r.channels=r.channels||{},r.channels.discord=r.channels.discord||{enabled:!1},r.channels.discord.enabled=!0,r.channels.discord.token="${"+e+"}",a){if(!r.agents?.[a])throw new Error(`Unknown agent "${a}".`);r.channels.discord.agentBinding=a}return"configured discord connector"});return{summary:n,hint:`Add ${e}=<bot-token> to your .env.`}}function Ed(t){let e=!!t?.enabled,{summary:a}=A(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 Td(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:r}=A(o=>(o.channels=o.channels||{},o.channels.gitlab=o.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},o.channels.gitlab.enabled=!0,o.channels.gitlab.host=e,o.channels.gitlab.token="${"+a+"}",o.channels.gitlab.webhookPort=n,"configured gitlab connector"));return{summary:r,hint:`Add ${a}=<personal-access-token> to your .env. Per-project routes + per-agent tokens stay in the Advanced JSON editor.`}}function Ad(t){let e=!!t?.enabled,{summary:a}=A(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 Cd(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-VDIZDO6Y.js"),n;try{n=(await import("cronstrue")).default.toString(e,{use24HourTimeFormat:!1})}catch(i){throw new Error(`Invalid cron: ${i.message||"unknown"}`)}let r=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC",o=[],s=new Date;try{for(let i=0;i<3;i++)s=a(e,s,r),o.push(s.toISOString())}catch(i){throw new Error(`Cron preview failed: ${i.message}`)}return{human:n,next:o,timezone:r}}function Id(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let{summary:a}=A(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 Md(t){let e=!!t?.enabled,{summary:a}=A(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 Ld(t){let e=String(t?.id||"").trim(),a=String(t?.schedule||"").trim(),n=String(t?.agent||"").trim(),r=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(!r)throw new Error("A prompt is required (what should the agent do?).");let{summary:o}=A(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:r,enabled:!0},`added cron "${e}"`});return{summary:o}}function Rd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Cron id is required.");let{summary:a}=A(n=>{if(!n.crons?.[e])throw new Error(`Cron "${e}" not found.`);return delete n.crons[e],`removed cron "${e}"`});return{summary:a}}function $d(t){let e=String(t?.raw||"");if(!e.trim())throw new Error("Config body is empty.");let a;try{a=JSON.parse(e)}catch(o){throw new Error(`Invalid JSON: ${o.message}`)}let n=Fe(process.cwd(),"agentx.json"),r=`${n}.bak.${Date.now()}`;if(Wt(n))try{Gc(n,r)}catch{}Ho(n,JSON.stringify(a,null,2)+`
5496
- `,"utf-8");try{let s=X().dashboard.daemonUrl?.replace(/\/+$/,"")||"http://127.0.0.1:18800";fetch(`${s}/reload`,{method:"POST"}).catch(()=>null)}catch{}return{summary:"agentx.json replaced",backupPath:r}}function Uo(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}async function Pd(t){let e=String(t?.agentId||"").trim(),a=String(t?.role||"").trim();if(!e)throw new Error("agentId required");if(!a)throw new Error("role required");let n=Array.isArray(t?.days)&&t.days.length>0?t.days:["mon","tue","wed","thu","fri"],r=String(t?.start||"09:00"),o=String(t?.end||"17:00"),s=t?.reportsTo?String(t.reportsTo).trim():"",i=typeof t?.utilizationTarget=="number"?t.utilizationTarget:.8,{summary:l}=A(c=>(c.business=c.business||{},c.business.orgChart=c.business.orgChart||{},c.business.orgChart[e]={role:a,...s?{reportsTo:s}:{},schedule:{days:n,start:r,end:o},utilizationTarget:i},`orgChart "${e}" upserted`));return{summary:l}}async function jd(t){let e=String(t?.agentId||"").trim();if(!e)throw new Error("agentId required");let{summary:a}=A(n=>{if(!n.business?.orgChart||!(e in n.business.orgChart))throw new Error(`no orgChart entry for "${e}"`);return delete n.business.orgChart[e],`orgChart "${e}" removed`});return{summary:a}}async function Od(t){let e=String(t?.id||"").trim();if(!e)throw new Error("project id required");let a=t?.pm?String(t.pm).trim():"",n=t?.client?String(t.client).trim():"",{summary:r}=A(o=>{o.business=o.business||{},o.business.projects=o.business.projects||[];let s=o.business.projects.findIndex(l=>l.id===e),i={id:e,...a?{pm:a}:{},...n?{client:n}:{}};return s>=0?o.business.projects[s]={...o.business.projects[s],...i}:o.business.projects.push(i),s>=0?`project "${e}" updated`:`project "${e}" added`});return{summary:r}}async function Nd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let a=String(t?.kind||"").trim();if(a&&!["client","internal","own"].includes(a))throw new Error("kind must be client, internal or own");let n=String(t?.respondWithin||"").trim();if(n&&!/^\d+\s*[mhd]$/.test(n))throw new Error('respondWithin must look like "4h", "90m" or "2d"');let r=Array.isArray(t?.standing)?t.standing.map(s=>String(s).trim()).filter(Boolean):String(t?.standing||"").split(",").map(s=>s.trim()).filter(Boolean),{summary:o}=A(s=>{s.business=s.business||{},s.business.clients=s.business.clients||{};let i=!!s.business.clients[e];return s.business.clients[e]={...s.business.clients[e]||{},...t?.name?{name:String(t.name).trim()}:{},...a?{kind:a}:{},...n?{respondWithin:n}:{},standing:r},i?`client "${e}" updated`:`client "${e}" configured`});return{summary:o}}async function Dd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let{summary:a}=A(n=>{if(!n.business?.clients?.[e])throw new Error(`no client override "${e}"`);return delete n.business.clients[e],`client "${e}" reset to defaults`});return{summary:a}}async function Hd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("project id required");let{summary:a}=A(n=>{let r=n.business?.projects||[],o=r.length;if(n.business.projects=r.filter(s=>s.id!==e),n.business.projects.length===o)throw new Error(`no project "${e}"`);return`project "${e}" removed`});return{summary:a}}async function Bd(t){let e=String(t?.client||"").trim();if(!e)throw new Error("client required");if(!t?.chatId&&!t?.username&&!t?.senderId)throw new Error("one of chatId / username / senderId required");let{summary:a}=A(n=>{n.business=n.business||{},n.business.contactMap=n.business.contactMap||[];let r={client:e};t?.channel&&(r.channel=String(t.channel)),t?.chatId&&(r.chatId=String(t.chatId)),t?.username&&(r.username=String(t.username)),t?.senderId&&(r.senderId=String(t.senderId)),t?.project&&(r.project=String(t.project)),t?.displayName&&(r.displayName=String(t.displayName)),n.business.contactMap.push(r);let o=r.chatId||r.username||r.senderId;return`contact ${r.channel?r.channel+"/":""}${o} \u2192 ${e} added`});return{summary:a}}async function zd(t){let a=["channel","chatId","username","senderId"].filter(r=>t?.[r]);if(a.length===0)throw new Error("at least one filter (channel/chatId/username/senderId) required");let{summary:n}=A(r=>{let o=r.business?.contactMap||[],s=o.length;if(r.business.contactMap=o.filter(i=>{for(let l of a)if(i[l]!==t[l])return!0;return!1}),r.business.contactMap.length===s)throw new Error("no matching contact entry");return`${s-r.business.contactMap.length} contact entry/entries removed`});return{summary:n}}async function qd(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=String(t?.projects||"").split(/[,\n]/).map(l=>l.trim()).filter(Boolean);if(!e)throw new Error("id required");if(!a)throw new Error("name required");if(n.length===0)throw new Error("at least one project path required");let r=t?.primaryToolLabel?String(t.primaryToolLabel).trim():"",o=Number.isFinite(Number(t?.timeRangeDays))?Number(t.timeRangeDays):30,s=Number.isFinite(Number(t?.closedWindowDays))?Number(t.closedWindowDays):30,{summary:i}=A(l=>{l.boards=Array.isArray(l.boards)?l.boards:[];let c=l.boards.findIndex(u=>u.id===e),p={id:e,name:a,source:{type:"gitlab",projects:n},timeRangeDays:o,closedWindowDays:s};if(r&&(p.primaryToolLabel=r),c>=0){let u=l.boards[c];return l.boards[c]={...u,...p,columns:u.columns,labels:u.labels},`board "${e}" updated`}return l.boards.push(p),`board "${e}" added`});return{summary:i}}async function Fd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("id required");let{summary:a}=A(n=>{let r=Array.isArray(n.boards)?n.boards:[],o=r.length;if(n.boards=r.filter(s=>s.id!==e),n.boards.length===o)throw new Error(`board "${e}" not found`);return`board "${e}" removed`});return{summary:a}}async function Ud(t){let e=String(t?.boardId||"").trim(),a=String(t?.columnId||"").trim().toLowerCase().replace(/[^a-z0-9_-]/g,"-"),n=String(t?.title||"").trim(),r=String(t?.kind||"scoped-label");if(!e)throw new Error("boardId required");if(!a)throw new Error("columnId required");if(!n)throw new Error("title required");if(!["open-backlog","scoped-label","closed","label"].includes(r))throw new Error("kind must be open-backlog | scoped-label | closed | label");let{summary:o}=A(s=>{let l=(Array.isArray(s.boards)?s.boards:[]).find(u=>u.id===e);if(!l)throw new Error(`board "${e}" not found`);l.columns=Array.isArray(l.columns)?l.columns:[];let c={id:a,title:n,kind:r,scopedPrefix:t?.scopedPrefix||"Status"};if(r==="scoped-label"){if(!t?.scopedLabel)throw new Error("scopedLabel required for kind=scoped-label");c.scopedLabel=String(t.scopedLabel)}if(r==="label"){if(!t?.mapsToLabel)throw new Error("mapsToLabel required for kind=label");c.mapsToLabel=String(t.mapsToLabel)}t?.accent&&(c.accent=String(t.accent));let p=l.columns.findIndex(u=>u.id===a);return p>=0?(l.columns[p]={...l.columns[p],...c},`column "${a}" updated`):(l.columns.push(c),`column "${a}" added to board "${e}"`)});return{summary:o}}async function Wd(t){let e=String(t?.boardId||"").trim(),a=String(t?.columnId||"").trim();if(!e||!a)throw new Error("boardId and columnId required");let{summary:n}=A(r=>{let s=(Array.isArray(r.boards)?r.boards:[]).find(l=>l.id===e);if(!s)throw new Error(`board "${e}" not found`);let i=(s.columns||[]).length;if(s.columns=(s.columns||[]).filter(l=>l.id!==a),s.columns.length===i)throw new Error(`column "${a}" not found`);return`column "${a}" removed from board "${e}"`});return{summary:n}}async function Gd(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{actionSchema:a}=await import("./types-DO3KLIBS.js");if(!t||typeof t!="object")throw new Error("body required");let n=a.safeParse(t);if(!n.success){let o=n.error.issues[0];throw new Error(`${o.path.join(".")||"<root>"}: ${o.message}`)}let r=new e().save(n.data);return{summary:`action "${r.id}" saved (${r.kind})`,action:r}}async function Xd(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),a=String(t?.id||"").trim();if(!a)throw new Error("id required");if(!new e().delete(a))throw new Error(`action "${a}" not found`);return{summary:`action "${a}" removed`}}async function Kd(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{runAction:a}=await import("./runner-56G3N7M4.js"),n=String(t?.id||"").trim();if(!n)throw new Error("id required");let r=new e().get(n);if(!r)throw new Error(`action "${n}" not found`);let o=t?.inputs&&typeof t.inputs=="object"?t.inputs:{},s=await a(r,o);return{summary:`action "${n}" ${s.ok?"ok":"failed"} (${s.durationMs}ms)`,result:s}}async function Jd(t){let e=t?.interval!==void 0?Number(t.interval):void 0,a=t?.timeout!==void 0?Number(t.timeout):void 0;if(e!==void 0&&(!Number.isFinite(e)||e<5||e>3600))throw new Error("interval must be 5..3600 seconds");if(a!==void 0&&(!Number.isFinite(a)||a<1||a>60))throw new Error("timeout must be 1..60 seconds");if(e===void 0&&a===void 0)throw new Error("nothing to update");let{summary:n}=A(r=>(r.mesh=r.mesh||{},r.mesh.healthCheck=r.mesh.healthCheck||{},e!==void 0&&(r.mesh.healthCheck.interval=e),a!==void 0&&(r.mesh.healthCheck.timeout=a),`mesh.healthCheck updated (interval=${r.mesh.healthCheck.interval}s, timeout=${r.mesh.healthCheck.timeout}s)`));return{summary:n}}async function Vd(t){let{summary:e}=A(a=>{a.notifications=a.notifications||{};let n=[];if(t&&typeof t=="object"){if("destination"in t)if(!t.destination)delete a.notifications.destination,n.push("destination cleared");else if(t.destination.channel&&t.destination.chatId)a.notifications.destination={channel:String(t.destination.channel),chatId:String(t.destination.chatId),...t.destination.accountId?{accountId:String(t.destination.accountId)}:{}},n.push(`destination=${t.destination.channel}:${t.destination.chatId}`);else throw new Error("destination requires channel + chatId");if("on"in t&&t.on&&typeof t.on=="object"){a.notifications.on=a.notifications.on||{};for(let r of["taskComplete","taskError","taskQueued"])r in t.on&&(a.notifications.on[r]=!!t.on[r]);n.push("on="+JSON.stringify(a.notifications.on))}if("longTaskThreshold"in t){let r=Number(t.longTaskThreshold);if(!Number.isFinite(r)||r<0)throw new Error("longTaskThreshold must be a non-negative number");a.notifications.longTaskThreshold=r,n.push(`threshold=${r}s`)}"local"in t&&t.local&&typeof t.local=="object"&&(a.notifications.local=Fn(a.notifications.local,t.local),n.push("local="+JSON.stringify(a.notifications.local))),"ntfy"in t&&t.ntfy&&typeof t.ntfy=="object"&&(a.channels=a.channels||{},a.channels.ntfy=Hr(a.channels.ntfy,t.ntfy),n.push(`ntfy ${a.channels.ntfy.enabled?"on":"off"} (restart the daemon to apply)`))}if(n.length===0)throw new Error("nothing to update");return`notifications updated (${n.join(", ")})`});return{summary:e}}async function Yd(t){if(!t||typeof t!="object")throw new Error("nothing to update");let{summary:e}=A(a=>(a.screen=gr(a.screen,t),`screen updated (buffer ${a.screen.buffer?.enabled?"on":"off"})`));return{summary:e}}async function Qd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("webhook id required");let{summary:a}=A(n=>{let o=(Array.isArray(n.webhooks)?n.webhooks:[]).find(s=>s.id===e);if(!o)throw new Error(`webhook "${e}" not found`);if("triggers"in t){if(t.triggers===null||typeof t.triggers=="object"&&Object.keys(t.triggers).length===0)delete o.triggers;else if(typeof t.triggers=="object"){let s={};for(let[i,l]of Object.entries(t.triggers))typeof l=="string"&&l.trim()&&(s[String(i)]=l.trim());Object.keys(s).length===0?delete o.triggers:o.triggers=s}}return"defaultWorkflow"in t&&(t.defaultWorkflow?o.defaultWorkflow=String(t.defaultWorkflow).trim():delete o.defaultWorkflow),`webhook "${e}" triggers/defaultWorkflow updated`});return{summary:a}}ut();import{resolve as tp}from"path";function Wo(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div id="msg" class="msg"></div>
5495
+ `)}catch{}return{summary:l}}function Gd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let a=t?.patch||{},{summary:n}=C(r=>{if(!r.agents?.[e])throw new Error(`Agent "${e}" not found.`);let o=r.agents[e];return typeof a.name=="string"&&a.name.trim()&&(o.name=a.name.trim()),typeof a.model=="string"&&(o.model=a.model.trim()||void 0),typeof a.tier=="string"&&["claude-code","codex-cli","opencode","sdk","orchestrator"].includes(a.tier)&&(o.tier=a.tier),typeof a.systemPrompt=="string"&&(o.systemPrompt=a.systemPrompt.trim()||void 0),Array.isArray(a.mentions)?o.mentions=a.mentions.map(s=>String(s).trim()).filter(Boolean):typeof a.triggerWords=="string"&&(o.mentions=ds(a.triggerWords)),typeof a.maxConcurrent=="number"&&a.maxConcurrent>=1&&(o.maxConcurrent=a.maxConcurrent),typeof a.maxExecutionMinutes=="number"&&a.maxExecutionMinutes>=1&&a.maxExecutionMinutes<=240&&(o.maxExecutionMinutes=a.maxExecutionMinutes),typeof a.permissionMode=="string"&&(o.permissionMode=a.permissionMode),(a.access==="public"||a.access==="private")&&(o.access=a.access),`updated agent "${e}"`});return{summary:n}}function Xd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let{summary:a}=C(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 r of Object.keys(n.channels.telegram.accounts))n.channels.telegram.accounts[r]?.agentBinding===e&&(n.channels.telegram.accounts[r].agentBinding="");return`removed agent "${e}"`});return{summary:a}}function Kd(t){let e=String(t?.id||"").trim(),a=String(t?.agentBinding||"").trim(),n=String(t?.botUsername||"").trim(),r=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(!r)throw new Error("Bot token env-var name is required (e.g. TG_SUPPORT_BOT_TOKEN).");let{summary:o}=C(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]={token:"${"+r+"}",agentBinding:a},`added telegram account "${e}"`});return{summary:o,hint:`Add ${r}=<bot-token> to your .env file.`}}function Jd(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let a=t?.patch||{},{summary:n}=C(r=>{let o=r.channels?.telegram?.accounts?.[e];if(!o)throw new Error(`Account "${e}" not found.`);if(typeof a.agentBinding=="string"&&a.agentBinding.trim()){if(!r.agents?.[a.agentBinding])throw new Error(`Unknown agent "${a.agentBinding}".`);o.agentBinding=a.agentBinding.trim()}return typeof a.botUsername=="string"&&(o.botUsername=a.botUsername.trim()),typeof a.botTokenEnv=="string"&&a.botTokenEnv.trim()&&(o.token="${"+a.botTokenEnv.trim()+"}"),`updated telegram account "${e}"`});return{summary:n}}async function nt(t){let{url:e,headers:a}=za(),n=await fetch(e+t,{headers:a}),r=await n.text();if(!n.ok)throw new Error(`daemon ${n.status}: ${r.slice(0,200)}`);try{return JSON.parse(r)}catch{return{raw:r}}}async function xe(t,e){let{url:a,headers:n}=za(),r=await fetch(a+t,{method:"POST",headers:{...n,"Content-Type":"application/json"},body:JSON.stringify(e||{})}),o=await r.text();if(!r.ok)throw new Error(`daemon ${r.status}: ${o.slice(0,200)}`);try{return JSON.parse(o)}catch{return{raw:o}}}async function Vd(t,e){try{let{url:a,headers:n}=za(),r=await fetch(a+e,{headers:n}),o=await r.text();t.writeHead(r.status,{"Content-Type":r.headers.get("content-type")||"image/svg+xml","Cache-Control":"no-store"}),t.end(o)}catch(a){t.writeHead(502,{"Content-Type":"text/plain; charset=utf-8"}),t.end("daemon unreachable: "+(a?.message||"unknown"))}}function za(){let t="http://127.0.0.1:18800",e={};try{let a=X();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function rt(t){let a=Ba()?.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 Ha(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function Yd(t){let e=Ha(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=qe(rt(e));return{agentId:e,...a}}function Qd(t){let e=Ha(t,"agent").trim(),a=Ha(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return Ct(rt(e),a)}function Zd(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 r=It(rt(e),a,n);return{summary:`saved ${a} (${r.bytes} bytes)`,...r}}function ep(t){let e=String(t?.agent||"").trim(),a=String(t?.slug||"").trim(),n=t?.title?String(t.title):void 0,r=t?.content?String(t.content):void 0;if(!e)throw new Error("agent is required.");let o=Mt(rt(e),a,{title:n,content:r});return{summary:`added skill "${a}"`,...o}}function tp(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=Lt(rt(e),a);return{summary:`removed skill "${a}"`,...n}}function ap(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a)throw new Error("kind is required");if(!n)throw new Error("label is required");let r={},o=t?.credentials||{};for(let l of["tokenEnv","privateAppTokenEnv","apiKeyEnv","refreshTokenEnv","clientIdEnv","clientSecretEnv"]){let c=o[l];if(typeof c=="string"&&c.trim()){if(!/^[A-Z][A-Z0-9_]*$/.test(c.trim()))throw new Error(`${l} must be uppercase identifier (got "${c}")`);r[l]=c.trim()}}if(o.auth==="keyring"&&(r.auth="keyring"),typeof o.sessionDir=="string"&&o.sessionDir.trim()&&(r.sessionDir=o.sessionDir.trim()),Object.keys(r).length===0)throw new Error("at least one credential field required");let s={};for(let[l,c]of Object.entries(t?.metadata||{}))(typeof c=="string"||typeof c=="number"||typeof c=="boolean")&&(s[l]=c);let{summary:i}=C(l=>{if(!l.agents?.[e])throw new Error(`Unknown agent "${e}"`);if(l.agents[e].integrations=Array.isArray(l.agents[e].integrations)?l.agents[e].integrations:[],l.agents[e].integrations.find(c=>c.kind===a&&c.label===n))throw new Error(`integration (${a}, ${n}) already exists on ${e}`);return l.agents[e].integrations.push({kind:a,label:n,credentials:r,metadata:s,enabled:!0}),`added ${a} integration "${n}" to ${e}`});return{summary:i}}function np(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let{summary:r}=C(o=>{let s=o.agents?.[e];if(!s)throw new Error(`Unknown agent "${e}"`);let i=s.integrations||[],l=i.findIndex(c=>c.kind===a&&c.label===n);if(l===-1)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return i.splice(l,1),`removed ${a} integration "${n}" from ${e}`});return{summary:r}}function rp(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let r=t?.patch||{},{summary:o}=C(s=>{let i=s.agents?.[e];if(!i)throw new Error(`Unknown agent "${e}"`);let c=(i.integrations||[]).find(d=>d.kind===a&&d.label===n);if(!c)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return typeof r.enabled=="boolean"&&(c.enabled=r.enabled),r.metadata&&typeof r.metadata=="object"&&(c.metadata={...c.metadata||{},...r.metadata}),`updated integration (${a}, ${n}) on ${e}`});return{summary:o}}var cs=["gitlab","github","sentry","stripe","vercel","odoo","hubspot","discord","slack","custom"];function op(t){let e=String(t?.id||"").trim(),a=String(t?.source||"").trim(),n=String(t?.agentId||"").trim(),r=String(t?.secretEnv||"").trim(),o=String(t?.description||"").trim(),s=String(t?.node||"").trim();if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Webhook id must be lowercase (letters, digits, -, _).");if(!cs.includes(a))throw new Error(`Unknown source: ${a}`);if(!n)throw new Error("Pick an agent to bind the webhook to.");let{summary:i}=C(l=>{if(s){if(!(l.mesh?.peers||[]).find(p=>p.name===s))throw new Error(`Mesh peer "${s}" not found in mesh.peers. Add the peer first or remove the node field.`)}else if(!l.agents?.[n])throw new Error(`Unknown agent "${n}". Add it locally, or set --node <peer> to forward to a mesh peer.`);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 r&&(c.secretEnv=r),o&&(c.description=o),s&&(c.node=s),l.webhooks.push(c),`added webhook "${e}" (${a} \u2192 ${n}${s?` @ ${s}`:""})`});return{summary:i}}function sp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let a=t?.patch||{},{summary:n}=C(r=>{let o=(r.webhooks||[]).find(s=>s.id===e);if(!o)throw new Error(`Webhook "${e}" not found.`);if(typeof a.source=="string"&&cs.includes(a.source)&&(o.source=a.source),typeof a.agentId=="string"&&a.agentId.trim()){if(!r.agents?.[a.agentId])throw new Error(`Unknown agent "${a.agentId}".`);o.agentId=a.agentId.trim()}return typeof a.secretEnv=="string"&&(o.secretEnv=a.secretEnv.trim()||void 0),typeof a.description=="string"&&(o.description=a.description.trim()||void 0),typeof a.enabled=="boolean"&&(o.enabled=a.enabled),`updated webhook "${e}"`});return{summary:n}}function ip(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:r}=C(o=>{if(o.mesh=o.mesh||{enabled:!0,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},o.mesh.enabled=!0,o.mesh.peers=Array.isArray(o.mesh.peers)?o.mesh.peers:[],o.mesh.peers.find(i=>i.url===e))throw new Error(`Peer at ${e} already registered.`);let s={url:e,name:a};return n&&(s.token=n),o.mesh.peers.push(s),`added mesh peer "${a}"`});return{summary:r}}function lp(t){let e=String(t?.url||"").trim().replace(/\/+$/,"");if(!e)throw new Error("Peer URL is required.");let{summary:a}=C(n=>{let r=(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(o=>o.url.replace(/\/+$/,"")!==e),n.mesh.peers.length===r)throw new Error(`Peer at ${e} not found.`);return`removed mesh peer ${e}`});return{summary:a}}function cp(t){let e=!!t?.enabled,{summary:a}=C(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 dp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let{summary:a}=C(n=>{let r=(n.webhooks||[]).length;if(n.webhooks=(n.webhooks||[]).filter(o=>o.id!==e),n.webhooks.length===r)throw new Error(`Webhook "${e}" not found.`);return`removed webhook "${e}"`});return{summary:a}}function pp(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:r}=C(o=>{if(o.channels=o.channels||{},o.channels.slack=o.channels.slack||{enabled:!1},o.channels.slack.enabled=!0,o.channels.slack.botToken="${"+e+"}",o.channels.slack.appToken="${"+a+"}",n){if(!o.agents?.[n])throw new Error(`Unknown agent "${n}".`);o.channels.slack.agentBinding=n}return"configured slack connector"});return{summary:r,hint:`Add ${e}=xoxb-\u2026 and ${a}=xapp-\u2026 to your .env.`}}function up(t){let e=!!t?.enabled,{summary:a}=C(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 mp(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}=C(r=>{if(r.channels=r.channels||{},r.channels.discord=r.channels.discord||{enabled:!1},r.channels.discord.enabled=!0,r.channels.discord.token="${"+e+"}",a){if(!r.agents?.[a])throw new Error(`Unknown agent "${a}".`);r.channels.discord.agentBinding=a}return"configured discord connector"});return{summary:n,hint:`Add ${e}=<bot-token> to your .env.`}}function fp(t){let e=!!t?.enabled,{summary:a}=C(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 hp(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:r}=C(o=>(o.channels=o.channels||{},o.channels.gitlab=o.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},o.channels.gitlab.enabled=!0,o.channels.gitlab.host=e,o.channels.gitlab.token="${"+a+"}",o.channels.gitlab.webhookPort=n,"configured gitlab connector"));return{summary:r,hint:`Add ${a}=<personal-access-token> to your .env. Per-project routes + per-agent tokens stay in the Advanced JSON editor.`}}function gp(t){let e=!!t?.enabled,{summary:a}=C(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 xp(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-ALPDUE4H.js"),n;try{n=(await import("cronstrue")).default.toString(e,{use24HourTimeFormat:!1})}catch(i){throw new Error(`Invalid cron: ${i.message||"unknown"}`)}let r=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC",o=[],s=new Date;try{for(let i=0;i<3;i++)s=a(e,s,r),o.push(s.toISOString())}catch(i){throw new Error(`Cron preview failed: ${i.message}`)}return{human:n,next:o,timezone:r}}function bp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let{summary:a}=C(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 vp(t){let e=!!t?.enabled,{summary:a}=C(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 yp(t){let e=String(t?.id||"").trim(),a=String(t?.schedule||"").trim(),n=String(t?.agent||"").trim(),r=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(!r)throw new Error("A prompt is required (what should the agent do?).");let{summary:o}=C(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:r,enabled:!0},`added cron "${e}"`});return{summary:o}}function wp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Cron id is required.");let{summary:a}=C(n=>{if(!n.crons?.[e])throw new Error(`Cron "${e}" not found.`);return delete n.crons[e],`removed cron "${e}"`});return{summary:a}}function kp(t){let e=String(t?.raw||"");if(!e.trim())throw new Error("Config body is empty.");let a;try{a=JSON.parse(e)}catch(o){throw new Error(`Invalid JSON: ${o.message}`)}let n=Xe(process.cwd(),"agentx.json"),r=`${n}.bak.${Date.now()}`;if(Jt(n))try{jd(n,r)}catch{}os(n,JSON.stringify(a,null,2)+`
5496
+ `,"utf-8");try{let s=X().dashboard.daemonUrl?.replace(/\/+$/,"")||"http://127.0.0.1:18800";fetch(`${s}/reload`,{method:"POST"}).catch(()=>null)}catch{}return{summary:"agentx.json replaced",backupPath:r}}function ds(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}async function _p(t){let e=String(t?.agentId||"").trim(),a=String(t?.role||"").trim();if(!e)throw new Error("agentId required");if(!a)throw new Error("role required");let n=Array.isArray(t?.days)&&t.days.length>0?t.days:["mon","tue","wed","thu","fri"],r=String(t?.start||"09:00"),o=String(t?.end||"17:00"),s=t?.reportsTo?String(t.reportsTo).trim():"",i=typeof t?.utilizationTarget=="number"?t.utilizationTarget:.8,{summary:l}=C(c=>(c.business=c.business||{},c.business.orgChart=c.business.orgChart||{},c.business.orgChart[e]={role:a,...s?{reportsTo:s}:{},schedule:{days:n,start:r,end:o},utilizationTarget:i},`orgChart "${e}" upserted`));return{summary:l}}async function Sp(t){let e=String(t?.agentId||"").trim();if(!e)throw new Error("agentId required");let{summary:a}=C(n=>{if(!n.business?.orgChart||!(e in n.business.orgChart))throw new Error(`no orgChart entry for "${e}"`);return delete n.business.orgChart[e],`orgChart "${e}" removed`});return{summary:a}}async function Ep(t){let e=String(t?.id||"").trim();if(!e)throw new Error("project id required");let a=t?.pm?String(t.pm).trim():"",n=t?.client?String(t.client).trim():"",{summary:r}=C(o=>{o.business=o.business||{},o.business.projects=o.business.projects||[];let s=o.business.projects.findIndex(l=>l.id===e),i={id:e,...a?{pm:a}:{},...n?{client:n}:{}};return s>=0?o.business.projects[s]={...o.business.projects[s],...i}:o.business.projects.push(i),s>=0?`project "${e}" updated`:`project "${e}" added`});return{summary:r}}async function Tp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let a=String(t?.kind||"").trim();if(a&&!["client","internal","own"].includes(a))throw new Error("kind must be client, internal or own");let n=String(t?.respondWithin||"").trim();if(n&&!/^\d+\s*[mhd]$/.test(n))throw new Error('respondWithin must look like "4h", "90m" or "2d"');let r=Array.isArray(t?.standing)?t.standing.map(s=>String(s).trim()).filter(Boolean):String(t?.standing||"").split(",").map(s=>s.trim()).filter(Boolean),{summary:o}=C(s=>{s.business=s.business||{},s.business.clients=s.business.clients||{};let i=!!s.business.clients[e];return s.business.clients[e]={...s.business.clients[e]||{},...t?.name?{name:String(t.name).trim()}:{},...a?{kind:a}:{},...n?{respondWithin:n}:{},standing:r},i?`client "${e}" updated`:`client "${e}" configured`});return{summary:o}}async function Ap(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let{summary:a}=C(n=>{if(!n.business?.clients?.[e])throw new Error(`no client override "${e}"`);return delete n.business.clients[e],`client "${e}" reset to defaults`});return{summary:a}}async function Cp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("project id required");let{summary:a}=C(n=>{let r=n.business?.projects||[],o=r.length;if(n.business.projects=r.filter(s=>s.id!==e),n.business.projects.length===o)throw new Error(`no project "${e}"`);return`project "${e}" removed`});return{summary:a}}async function Ip(t){let e=String(t?.client||"").trim();if(!e)throw new Error("client required");if(!t?.chatId&&!t?.username&&!t?.senderId)throw new Error("one of chatId / username / senderId required");let{summary:a}=C(n=>{n.business=n.business||{},n.business.contactMap=n.business.contactMap||[];let r={client:e};t?.channel&&(r.channel=String(t.channel)),t?.chatId&&(r.chatId=String(t.chatId)),t?.username&&(r.username=String(t.username)),t?.senderId&&(r.senderId=String(t.senderId)),t?.project&&(r.project=String(t.project)),t?.displayName&&(r.displayName=String(t.displayName)),n.business.contactMap.push(r);let o=r.chatId||r.username||r.senderId;return`contact ${r.channel?r.channel+"/":""}${o} \u2192 ${e} added`});return{summary:a}}async function Mp(t){let a=["channel","chatId","username","senderId"].filter(r=>t?.[r]);if(a.length===0)throw new Error("at least one filter (channel/chatId/username/senderId) required");let{summary:n}=C(r=>{let o=r.business?.contactMap||[],s=o.length;if(r.business.contactMap=o.filter(i=>{for(let l of a)if(i[l]!==t[l])return!0;return!1}),r.business.contactMap.length===s)throw new Error("no matching contact entry");return`${s-r.business.contactMap.length} contact entry/entries removed`});return{summary:n}}async function Lp(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=String(t?.projects||"").split(/[,\n]/).map(l=>l.trim()).filter(Boolean);if(!e)throw new Error("id required");if(!a)throw new Error("name required");if(n.length===0)throw new Error("at least one project path required");let r=t?.primaryToolLabel?String(t.primaryToolLabel).trim():"",o=Number.isFinite(Number(t?.timeRangeDays))?Number(t.timeRangeDays):30,s=Number.isFinite(Number(t?.closedWindowDays))?Number(t.closedWindowDays):30,{summary:i}=C(l=>{l.boards=Array.isArray(l.boards)?l.boards:[];let c=l.boards.findIndex(p=>p.id===e),d={id:e,name:a,source:{type:"gitlab",projects:n},timeRangeDays:o,closedWindowDays:s};if(r&&(d.primaryToolLabel=r),c>=0){let p=l.boards[c];return l.boards[c]={...p,...d,columns:p.columns,labels:p.labels},`board "${e}" updated`}return l.boards.push(d),`board "${e}" added`});return{summary:i}}async function Rp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("id required");let{summary:a}=C(n=>{let r=Array.isArray(n.boards)?n.boards:[],o=r.length;if(n.boards=r.filter(s=>s.id!==e),n.boards.length===o)throw new Error(`board "${e}" not found`);return`board "${e}" removed`});return{summary:a}}async function Pp(t){let e=String(t?.boardId||"").trim(),a=String(t?.columnId||"").trim().toLowerCase().replace(/[^a-z0-9_-]/g,"-"),n=String(t?.title||"").trim(),r=String(t?.kind||"scoped-label");if(!e)throw new Error("boardId required");if(!a)throw new Error("columnId required");if(!n)throw new Error("title required");if(!["open-backlog","scoped-label","closed","label"].includes(r))throw new Error("kind must be open-backlog | scoped-label | closed | label");let{summary:o}=C(s=>{let l=(Array.isArray(s.boards)?s.boards:[]).find(p=>p.id===e);if(!l)throw new Error(`board "${e}" not found`);l.columns=Array.isArray(l.columns)?l.columns:[];let c={id:a,title:n,kind:r,scopedPrefix:t?.scopedPrefix||"Status"};if(r==="scoped-label"){if(!t?.scopedLabel)throw new Error("scopedLabel required for kind=scoped-label");c.scopedLabel=String(t.scopedLabel)}if(r==="label"){if(!t?.mapsToLabel)throw new Error("mapsToLabel required for kind=label");c.mapsToLabel=String(t.mapsToLabel)}t?.accent&&(c.accent=String(t.accent));let d=l.columns.findIndex(p=>p.id===a);return d>=0?(l.columns[d]={...l.columns[d],...c},`column "${a}" updated`):(l.columns.push(c),`column "${a}" added to board "${e}"`)});return{summary:o}}async function $p(t){let e=String(t?.boardId||"").trim(),a=String(t?.columnId||"").trim();if(!e||!a)throw new Error("boardId and columnId required");let{summary:n}=C(r=>{let s=(Array.isArray(r.boards)?r.boards:[]).find(l=>l.id===e);if(!s)throw new Error(`board "${e}" not found`);let i=(s.columns||[]).length;if(s.columns=(s.columns||[]).filter(l=>l.id!==a),s.columns.length===i)throw new Error(`column "${a}" not found`);return`column "${a}" removed from board "${e}"`});return{summary:n}}async function jp(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{actionSchema:a}=await import("./types-DO3KLIBS.js");if(!t||typeof t!="object")throw new Error("body required");let n=a.safeParse(t);if(!n.success){let o=n.error.issues[0];throw new Error(`${o.path.join(".")||"<root>"}: ${o.message}`)}let r=new e().save(n.data);return{summary:`action "${r.id}" saved (${r.kind})`,action:r}}async function Op(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),a=String(t?.id||"").trim();if(!a)throw new Error("id required");if(!new e().delete(a))throw new Error(`action "${a}" not found`);return{summary:`action "${a}" removed`}}async function Np(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{runAction:a}=await import("./runner-56G3N7M4.js"),n=String(t?.id||"").trim();if(!n)throw new Error("id required");let r=new e().get(n);if(!r)throw new Error(`action "${n}" not found`);let o=t?.inputs&&typeof t.inputs=="object"?t.inputs:{},s=await a(r,o);return{summary:`action "${n}" ${s.ok?"ok":"failed"} (${s.durationMs}ms)`,result:s}}async function Dp(t){let e=t?.interval!==void 0?Number(t.interval):void 0,a=t?.timeout!==void 0?Number(t.timeout):void 0;if(e!==void 0&&(!Number.isFinite(e)||e<5||e>3600))throw new Error("interval must be 5..3600 seconds");if(a!==void 0&&(!Number.isFinite(a)||a<1||a>60))throw new Error("timeout must be 1..60 seconds");if(e===void 0&&a===void 0)throw new Error("nothing to update");let{summary:n}=C(r=>(r.mesh=r.mesh||{},r.mesh.healthCheck=r.mesh.healthCheck||{},e!==void 0&&(r.mesh.healthCheck.interval=e),a!==void 0&&(r.mesh.healthCheck.timeout=a),`mesh.healthCheck updated (interval=${r.mesh.healthCheck.interval}s, timeout=${r.mesh.healthCheck.timeout}s)`));return{summary:n}}async function Hp(t){let{summary:e}=C(a=>{a.notifications=a.notifications||{};let n=[];if(t&&typeof t=="object"){if("destination"in t)if(!t.destination)delete a.notifications.destination,n.push("destination cleared");else if(t.destination.channel&&t.destination.chatId)a.notifications.destination={channel:String(t.destination.channel),chatId:String(t.destination.chatId),...t.destination.accountId?{accountId:String(t.destination.accountId)}:{}},n.push(`destination=${t.destination.channel}:${t.destination.chatId}`);else throw new Error("destination requires channel + chatId");if("on"in t&&t.on&&typeof t.on=="object"){a.notifications.on=a.notifications.on||{};for(let r of["taskComplete","taskError","taskQueued"])r in t.on&&(a.notifications.on[r]=!!t.on[r]);n.push("on="+JSON.stringify(a.notifications.on))}if("longTaskThreshold"in t){let r=Number(t.longTaskThreshold);if(!Number.isFinite(r)||r<0)throw new Error("longTaskThreshold must be a non-negative number");a.notifications.longTaskThreshold=r,n.push(`threshold=${r}s`)}"local"in t&&t.local&&typeof t.local=="object"&&(a.notifications.local=er(a.notifications.local,t.local),n.push("local="+JSON.stringify(a.notifications.local))),"ntfy"in t&&t.ntfy&&typeof t.ntfy=="object"&&(a.channels=a.channels||{},a.channels.ntfy=Vr(a.channels.ntfy,t.ntfy),n.push(`ntfy ${a.channels.ntfy.enabled?"on":"off"} (restart the daemon to apply)`))}if(n.length===0)throw new Error("nothing to update");return`notifications updated (${n.join(", ")})`});return{summary:e}}async function Bp(t){if(!t||typeof t!="object")throw new Error("nothing to update");let{summary:e}=C(a=>(a.screen=Ar(a.screen,t),`screen updated (buffer ${a.screen.buffer?.enabled?"on":"off"})`));return{summary:e}}async function zp(t){let e=String(t?.id||"").trim();if(!e)throw new Error("webhook id required");let{summary:a}=C(n=>{let o=(Array.isArray(n.webhooks)?n.webhooks:[]).find(s=>s.id===e);if(!o)throw new Error(`webhook "${e}" not found`);if("triggers"in t){if(t.triggers===null||typeof t.triggers=="object"&&Object.keys(t.triggers).length===0)delete o.triggers;else if(typeof t.triggers=="object"){let s={};for(let[i,l]of Object.entries(t.triggers))typeof l=="string"&&l.trim()&&(s[String(i)]=l.trim());Object.keys(s).length===0?delete o.triggers:o.triggers=s}}return"defaultWorkflow"in t&&(t.defaultWorkflow?o.defaultWorkflow=String(t.defaultWorkflow).trim():delete o.defaultWorkflow),`webhook "${e}" triggers/defaultWorkflow updated`});return{summary:a}}gt();import{resolve as Up}from"path";function ps(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div id="msg" class="msg"></div>
5497
5497
 
5498
5498
  <div id="disabled-banner" class="banner warn" style="display:none">
5499
5499
  <b>Graph is disabled.</b> Set <code class="mono">graph.enabled: true</code>
@@ -5548,7 +5548,7 @@ ${s||"You are "+a+"."}
5548
5548
  <h2>Recent classifications</h2>
5549
5549
  <p class="muted">Last 25 log rows, newest first \u2014 approved / pending / rejected.</p>
5550
5550
  <div id="recent"></div>
5551
- </section>`;return M({title:"AgentX \xB7 Intent Graph",activeTab:"graph",subtitle:"Intent Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Zd,scripts:`${e}<script>${ep}</script>`})}var Zd=`
5551
+ </section>`;return I({title:"AgentX \xB7 Intent Graph",activeTab:"graph",subtitle:"Intent Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:qp,scripts:`${e}<script>${Fp}</script>`})}var qp=`
5552
5552
  main { max-width: 1200px; margin: 0 auto; padding: 24px 20px 60px; }
5553
5553
  h2 { margin: 0 0 12px; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
5554
5554
  .grid { display: grid; gap: 20px; grid-template-columns: 1fr; }
@@ -5652,7 +5652,7 @@ details {
5652
5652
  border-radius: 4px; padding: 8px 12px; margin-top: 8px;
5653
5653
  }
5654
5654
  details summary { cursor: pointer; font-size: 11px; color: var(--ax-muted); user-select: none; }
5655
- details[open] summary { margin-bottom: 8px; }`,ep=`
5655
+ details[open] summary { margin-bottom: 8px; }`,Fp=`
5656
5656
  const $ = (id) => document.getElementById(id);
5657
5657
  const state = { schema: null, nodes: [], pending: [], recent: [] };
5658
5658
 
@@ -5872,7 +5872,7 @@ $('btn-save-schema').addEventListener('click', async () => {
5872
5872
  $('btn-reload-schema').addEventListener('click', refresh);
5873
5873
 
5874
5874
  refresh();
5875
- `;function Xo(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Wo({peers:a,localToken:n}))}async function Ko(t,e,a){try{let n=t.method==="GET"?void 0:await dp(t),r=ap(),o={"GET /api/admin/graph/state":()=>np(r),"POST /api/admin/graph/classifications/approve":()=>rp(r,n),"POST /api/admin/graph/classifications/reject":()=>op(r,n),"POST /api/admin/graph/nodes":()=>sp(r,n),"PATCH /api/admin/graph/nodes":()=>ip(r,n),"DELETE /api/admin/graph/nodes":()=>lp(r,n),"PUT /api/admin/graph/schema":()=>cp(r,n)},s=`${t.method} ${a}`,i=o[s];if(!i){$a(e,404,{error:`unknown graph endpoint: ${s}`});return}let l=await i();$a(e,200,l)}catch(n){$a(e,400,{error:n?.message||"graph op failed"})}}function ap(){let t=X(),e=tp(process.cwd(),t.graph.baseDir);return new In({baseDir:e})}function np(t){let e=X(),a=t.loadSchema(),n=t.loadNodes().nodes,r=t.readRecentClassifications(100),o=t.loadIndex().entries,s=new Map;for(let l of r)s.has(l.msgHash)||s.set(l.msgHash,l);let i=[];for(let l of s.values())l.status==="pending"&&!o[l.msgHash]&&i.push(l);return{enabled:e.graph.enabled,schema:a,nodes:n,pending:i,recent:r.slice(0,25),counts:{nodes:n.length,pending:i.length,fingerprints:Object.keys(o).length}}}function rp(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=Jo(t,a);return Array.isArray(e?.path)&&e.path.length>0&&(n.path=e.path.map(r=>String(r))),e?.proposedAxes&&typeof e.proposedAxes=="object"&&(n.proposedAxes=Pa(e.proposedAxes)),t.approveClassification(n),{summary:`Approved ${n.msgHash}`}}function op(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=Jo(t,a);return t.rejectClassification(n),{summary:`Rejected ${n.msgHash}`}}function Jo(t,e){let n=t.readRecentClassifications(500).find(r=>r.msgHash===e);if(!n)throw new Error(`No classification found for ${e}`);return n}function sp(t,e){let a=Go(String(e?.id||"")),n=String(e?.level||"").trim(),r=e?.parentId?Go(String(e.parentId)):null,o=Pa({[a]:e?.axes||{}})[a]||{};if(!a)throw new Error("id is required");if(!n)throw new Error("level is required");let s={id:a,level:n,parentId:r,axes:o,createdAt:new Date().toISOString(),createdBy:"admin-ui"};return t.addNode(s),{node:s}}function ip(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");let n=Pa({[a]:e?.axes||{}})[a]||{};return{node:t.updateNodeAxes(a,n)}}function lp(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");return t.deleteNode(a),{summary:`Deleted ${a}`}}function cp(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 Pa(t){let e={};for(let[a,n]of Object.entries(t||{})){if(!n||typeof n!="object")continue;let r={};for(let[o,s]of Object.entries(n))typeof s=="string"&&(r[o]=s);e[a]=r}return e}function Go(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")}function $a(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function dp(t){return new Promise((e,a)=>{let n="";t.on("data",r=>{n+=r}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(r){a(r)}}),t.on("error",a)})}var Vo=`
5875
+ `;function ms(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ps({peers:a,localToken:n}))}async function fs(t,e,a){try{let n=t.method==="GET"?void 0:await Zp(t),r=Wp(),o={"GET /api/admin/graph/state":()=>Gp(r),"POST /api/admin/graph/classifications/approve":()=>Xp(r,n),"POST /api/admin/graph/classifications/reject":()=>Kp(r,n),"POST /api/admin/graph/nodes":()=>Jp(r,n),"PATCH /api/admin/graph/nodes":()=>Vp(r,n),"DELETE /api/admin/graph/nodes":()=>Yp(r,n),"PUT /api/admin/graph/schema":()=>Qp(r,n)},s=`${t.method} ${a}`,i=o[s];if(!i){qa(e,404,{error:`unknown graph endpoint: ${s}`});return}let l=await i();qa(e,200,l)}catch(n){qa(e,400,{error:n?.message||"graph op failed"})}}function Wp(){let t=X(),e=Up(process.cwd(),t.graph.baseDir);return new Bn({baseDir:e})}function Gp(t){let e=X(),a=t.loadSchema(),n=t.loadNodes().nodes,r=t.readRecentClassifications(100),o=t.loadIndex().entries,s=new Map;for(let l of r)s.has(l.msgHash)||s.set(l.msgHash,l);let i=[];for(let l of s.values())l.status==="pending"&&!o[l.msgHash]&&i.push(l);return{enabled:e.graph.enabled,schema:a,nodes:n,pending:i,recent:r.slice(0,25),counts:{nodes:n.length,pending:i.length,fingerprints:Object.keys(o).length}}}function Xp(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=hs(t,a);return Array.isArray(e?.path)&&e.path.length>0&&(n.path=e.path.map(r=>String(r))),e?.proposedAxes&&typeof e.proposedAxes=="object"&&(n.proposedAxes=Fa(e.proposedAxes)),t.approveClassification(n),{summary:`Approved ${n.msgHash}`}}function Kp(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=hs(t,a);return t.rejectClassification(n),{summary:`Rejected ${n.msgHash}`}}function hs(t,e){let n=t.readRecentClassifications(500).find(r=>r.msgHash===e);if(!n)throw new Error(`No classification found for ${e}`);return n}function Jp(t,e){let a=us(String(e?.id||"")),n=String(e?.level||"").trim(),r=e?.parentId?us(String(e.parentId)):null,o=Fa({[a]:e?.axes||{}})[a]||{};if(!a)throw new Error("id is required");if(!n)throw new Error("level is required");let s={id:a,level:n,parentId:r,axes:o,createdAt:new Date().toISOString(),createdBy:"admin-ui"};return t.addNode(s),{node:s}}function Vp(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");let n=Fa({[a]:e?.axes||{}})[a]||{};return{node:t.updateNodeAxes(a,n)}}function Yp(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");return t.deleteNode(a),{summary:`Deleted ${a}`}}function Qp(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 Fa(t){let e={};for(let[a,n]of Object.entries(t||{})){if(!n||typeof n!="object")continue;let r={};for(let[o,s]of Object.entries(n))typeof s=="string"&&(r[o]=s);e[a]=r}return e}function us(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")}function qa(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Zp(t){return new Promise((e,a)=>{let n="";t.on("data",r=>{n+=r}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(r){a(r)}}),t.on("error",a)})}var gs=`
5876
5876
  <section class="apv__req" id="req-section" aria-labelledby="req-h">
5877
5877
  <h2 id="req-h">Open requests <span id="req-n"></span></h2>
5878
5878
  <p class="apv__lead">What you asked agents for that is not finished, oldest first. Reply, hand it to an agent, close it as done, or drop it. Nothing leaves this list by getting old.</p>
@@ -5889,7 +5889,7 @@ refresh();
5889
5889
  <div><button type="submit" class="ax-btn ax-btn--primary">Save settings</button></div>
5890
5890
  </form>
5891
5891
  </details>
5892
- </section>`,Yo=`
5892
+ </section>`,xs=`
5893
5893
  .apv__req { margin-top: 32px; border-top: 1px solid var(--ax-border); padding-top: 16px; }
5894
5894
  .apv__req h2 { margin: 0 0 4px; font-size: 17px; font-weight: 600; }
5895
5895
  .apv__req h2 span { color: var(--ax-muted); font-family: var(--ax-mono); font-size: 12px; font-weight: 400; }
@@ -5911,7 +5911,7 @@ refresh();
5911
5911
  .apv__req select { min-height: 40px; max-width: 100%; }
5912
5912
  .apv__mic.is-on { border-color: var(--ax-err); color: var(--ax-err); }
5913
5913
  .apv__acts + .apv__acts { margin-top: 8px; }
5914
- `,Qo=`
5914
+ `,bs=`
5915
5915
  (function(){
5916
5916
  var STATE = { in_progress: 'In progress', waiting_owner: 'Waiting on you', waiting_other: 'Waiting on another agent', needs_attention: 'Needs attention' };
5917
5917
  function $(id){ return document.getElementById(id); }
@@ -6053,7 +6053,7 @@ function busy(){
6053
6053
  }
6054
6054
  setInterval(function(){ if (document.visibilityState === 'visible' && !busy()) load(); }, 60000);
6055
6055
  })();
6056
- `;function Zo(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div class="apv">
6056
+ `;function vs(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div class="apv">
6057
6057
  <header class="apv__head">
6058
6058
  <div>
6059
6059
  <h1>Approvals</h1>
@@ -6075,7 +6075,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !busy()) l
6075
6075
  <ol id="apv-list" class="apv__list" aria-label="Waiting for you"></ol>
6076
6076
  <p id="apv-snoozed" class="apv__foot"></p>
6077
6077
 
6078
- ${Vo}
6078
+ ${gs}
6079
6079
 
6080
6080
  <details class="apv__settings" id="apv-settings">
6081
6081
  <summary>Settings: expiry, later, daily digest</summary>
@@ -6090,7 +6090,7 @@ ${Vo}
6090
6090
  <div><button type="submit" class="ax-btn ax-btn--primary">Save settings</button></div>
6091
6091
  </form>
6092
6092
  </details>
6093
- </div>`;return M({title:"AgentX \xB7 Approvals",activeTab:"approvals",subtitle:"Approvals",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:pp+Yo,scripts:`${e}<script>${up}</script><script>${Qo}</script>`})}var pp=`
6093
+ </div>`;return I({title:"AgentX \xB7 Approvals",activeTab:"approvals",subtitle:"Approvals",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:eu+xs,scripts:`${e}<script>${tu}</script><script>${bs}</script>`})}var eu=`
6094
6094
  .apv { max-width: 860px; margin: 0 auto; padding: 20px 16px 64px; color: var(--ax-text); }
6095
6095
  .apv__head { display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; align-items: flex-end; margin-bottom: 14px; }
6096
6096
  .apv__head h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
@@ -6139,7 +6139,7 @@ ${Vo}
6139
6139
  @media (max-width: 560px) {
6140
6140
  .apv__acts .ax-btn { flex: 1 1 0; }
6141
6141
  }
6142
- `,up=`
6142
+ `,tu=`
6143
6143
  (function(){
6144
6144
  var state = { items: [], snoozed: 0, kind: '', showAll: false, popup: false };
6145
6145
  var LABEL = { card: 'Card', schedule: 'Schedule', memory: 'Memory fact', wiki: 'Wiki lesson', whatsapp: 'WhatsApp reply', request: 'Request' };
@@ -6307,7 +6307,7 @@ $('apv-form').addEventListener('submit', async function(ev){
6307
6307
  load();
6308
6308
  setInterval(function(){ if (document.visibilityState === 'visible' && !document.querySelector('.apv__item:focus-within')) load(); }, 60000);
6309
6309
  })();
6310
- `;import{existsSync as mp,readFileSync as fp}from"fs";var Ae="/api/admin/approvals/requests";function es(t){let e=jn(t);if(!mp(e))return[];try{let a=JSON.parse(fp(e,"utf-8"))?.agents??{};return Object.entries(a).map(([n,r])=>({id:n,name:typeof r?.name=="string"&&r.name?r.name:n}))}catch{return[]}}var ts=t=>typeof t=="string"?t.split(",").map(e=>e.trim()).filter(Boolean):void 0;async function as(t,e,a,n){try{return await hp(t,e,a,n)}catch(r){return{status:400,body:{error:String(r?.message??r).slice(0,300)}}}}async function hp(t,e,a,n){if(t==="GET"&&e===Ae){let o=yt(n);return{status:200,body:{items:o?o.listOpen().map(s=>Yn(s,o)):[],agents:es(n.configPath),settings:bt(n.configPath)}}}let r=e===`${Ae}/reply`?"reply":e===`${Ae}/handoff`?"handoff":null;if(t==="POST"&&r){let o=typeof a.id=="string"?a.id:"",s=r==="reply"?a.text:a.note,i=typeof s=="string"?s.trim():"";if(!o||r==="reply"&&!i)return{status:400,body:{error:r==="reply"?"send { id, text }":"send { id, agentId, note? }"}};let l=yt(n),c=l?.get(o);if(!l||!c||c.state==="candidate")return{status:404,body:{error:`no request "${o}"`}};let p=r==="reply"?c.agentId:typeof a.agentId=="string"?a.agentId:"",u=es(n.configPath).find(h=>h.id===p);if(r==="handoff"&&!u)return{status:400,body:{error:`"${p}" is not an agent on this node`}};if(!bt(n.configPath).enabled)return{status:409,body:{error:"Requests are off, so nothing would tell the agent. Turn them on in the settings below."}};if(!l.handOff(o,p,i,n.now??Date.now()))return{status:409,body:{error:`${o} is already closed`}};let m=u?.name??p;return{status:200,body:{ok:!0,message:r==="reply"?`Reply sent: ${m} will go on with ${o}`:`${m} has ${o} now and will be told within a minute`}}}if(t==="POST"&&e===`${Ae}/close`){let o=typeof a.id=="string"?a.id:"",s=a.action;if(!o||s!=="done"&&s!=="drop")return{status:400,body:{error:"send { id, action: done | drop }"}};let i=yt(n),l=i?.get(o);if(!i||!l||l.state==="candidate")return{status:404,body:{error:`no request "${o}"`}};let c=s==="done"?typeof a.evidence=="string"&&a.evidence.trim()?a.evidence:"closed by the owner (dashboard)":typeof a.reason=="string"&&a.reason.trim()?a.reason:"dropped by the owner (dashboard)";return i.close(o,s==="done"?"done":"dropped",c,n.now??Date.now())?{status:200,body:{ok:!0,message:s==="done"?`${o} closed as done`:`${o} dropped`}}:{status:409,body:{error:`${o} is already closed`}}}if(t==="POST"&&e===`${Ae}/settings`){let o={},s=l=>{let c=a[l];if(c!==void 0){if(typeof c!="number"||!(c>0))throw new Error(`${l} must be a positive number`);return c}};typeof a.enabled=="boolean"&&(o.enabled=a.enabled),o.from=ts(a.from),o.channels=ts(a.channels),o.staleAfterHours=s("staleAfterHours"),o.retentionDays=s("retentionDays");let i=await Xn(o,{configPath:n.configPath,reload:n.reload});return i.success?{status:200,body:{ok:!0,settings:bt(n.configPath)}}:{status:400,body:{error:i.error}}}return{status:404,body:{error:"Not found"}}}var gp=["yes","no","later"];function te(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function Gt(t,e=64*1024){let a=0,n=[];for await(let s of t){if(a+=s.length,a>e)throw new Error("body too large");n.push(s)}let r=Buffer.concat(n).toString("utf-8");if(!r.trim())return{};let o=JSON.parse(r);if(!o||typeof o!="object"||Array.isArray(o))throw new Error("expected a JSON object");return o}function ns(t,e,a){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(Zo({peers:e,localToken:a}))}async function rs(t,e,a,n,r={}){if(!a.startsWith("/api/admin/approvals"))return!1;let o=(t.method||"GET").toUpperCase(),s=r.ctx??{root:process.cwd(),configPath:r.configPath,reload:r.reload};if(o!=="GET"&&t.headers["x-requested-with"]!=="agentx-board")return te(e,400,{error:"missing X-Requested-With: agentx-board"}),!0;try{if(a.startsWith(Ae)){let i=await as(o,a,o==="POST"?await Gt(t):{},s);return te(e,i.status,i.body),!0}if(o==="GET"&&a==="/api/admin/approvals"){let i=wt(s,{includeSnoozed:n.searchParams.get("all")==="1"});return te(e,200,{...i,settings:Se(s.configPath)}),!0}if(o==="POST"&&a==="/api/admin/approvals/decide"){let i=await Gt(t),l=typeof i.key=="string"?i.key:"",c=i.action;if(!l||!gp.includes(c))return te(e,400,{error:"send { key, action: yes | no | later }"}),!0;let p=Se(s.configPath),u=await kt(s,l,c,{note:typeof i.note=="string"?i.note:void 0,force:i.force===!0,laterHours:p.laterHours,by:"operator (dashboard)"});return u.ok?(te(e,200,{ok:!0,message:u.message}),!0):(te(e,409,{error:u.error}),!0)}if(o==="POST"&&a==="/api/admin/approvals/popup"){let i=await Gt(t),l=Qn(s,typeof i.key=="string"?i.key:"",!!Se(s.configPath).popup?.enabled);return l.ok?(te(e,200,{ok:!0,message:l.message}),!0):(te(e,409,{error:l.error}),!0)}if(o==="POST"&&a==="/api/admin/approvals/settings"){let i=await Gt(t),l={},c=u=>{let m=i[u];if(m!==void 0){if(typeof m!="number"||!(m>0))throw new Error(`${u} must be a positive number`);return m}};if(l.defaultExpiryDays=c("defaultExpiryDays"),l.maxExpiryDays=c("maxExpiryDays"),l.laterHours=c("laterHours"),typeof i.notifyAgent=="boolean"&&(l.notifyAgent=i.notifyAgent),typeof i.digestEnabled=="boolean"&&(l.digestEnabled=i.digestEnabled),typeof i.digestTime=="string"&&(l.digestTime=i.digestTime),typeof i.destination=="string"){let u=i.destination.trim();if(!u)l.destination=null;else{let m=Ar(u);if(!m)throw new Error("digest destination takes channel:chat id, for example telegram:123456");l.destination=m}}let p=await Cr(l,{configPath:s.configPath,reload:s.reload});return p.success?(te(e,200,{ok:!0,settings:Se(s.configPath)}),!0):(te(e,400,{error:p.error}),!0)}}catch(i){return te(e,400,{error:String(i?.message??i).slice(0,300)}),!0}return te(e,404,{error:"Not found"}),!0}ua();function os(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=be({kicker:"Operations",title:"People",lead:"Everyone who talks to your agents: you, your teammates, your clients and guests. Open a person to see the machines they paired and what they asked for."})+`
6310
+ `;import{existsSync as au,readFileSync as nu}from"fs";var Re="/api/admin/approvals/requests";function ys(t){let e=Gn(t);if(!au(e))return[];try{let a=JSON.parse(nu(e,"utf-8"))?.agents??{};return Object.entries(a).map(([n,r])=>({id:n,name:typeof r?.name=="string"&&r.name?r.name:n}))}catch{return[]}}var ws=t=>typeof t=="string"?t.split(",").map(e=>e.trim()).filter(Boolean):void 0;async function ks(t,e,a,n){try{return await ru(t,e,a,n)}catch(r){return{status:400,body:{error:String(r?.message??r).slice(0,300)}}}}async function ru(t,e,a,n){if(t==="GET"&&e===Re){let o=St(n);return{status:200,body:{items:o?o.listOpen().map(s=>lr(s,o)):[],agents:ys(n.configPath),settings:_t(n.configPath)}}}let r=e===`${Re}/reply`?"reply":e===`${Re}/handoff`?"handoff":null;if(t==="POST"&&r){let o=typeof a.id=="string"?a.id:"",s=r==="reply"?a.text:a.note,i=typeof s=="string"?s.trim():"";if(!o||r==="reply"&&!i)return{status:400,body:{error:r==="reply"?"send { id, text }":"send { id, agentId, note? }"}};let l=St(n),c=l?.get(o);if(!l||!c||c.state==="candidate")return{status:404,body:{error:`no request "${o}"`}};let d=r==="reply"?c.agentId:typeof a.agentId=="string"?a.agentId:"",p=ys(n.configPath).find(f=>f.id===d);if(r==="handoff"&&!p)return{status:400,body:{error:`"${d}" is not an agent on this node`}};if(!_t(n.configPath).enabled)return{status:409,body:{error:"Requests are off, so nothing would tell the agent. Turn them on in the settings below."}};if(!l.handOff(o,d,i,n.now??Date.now()))return{status:409,body:{error:`${o} is already closed`}};let m=p?.name??d;return{status:200,body:{ok:!0,message:r==="reply"?`Reply sent: ${m} will go on with ${o}`:`${m} has ${o} now and will be told within a minute`}}}if(t==="POST"&&e===`${Re}/close`){let o=typeof a.id=="string"?a.id:"",s=a.action;if(!o||s!=="done"&&s!=="drop")return{status:400,body:{error:"send { id, action: done | drop }"}};let i=St(n),l=i?.get(o);if(!i||!l||l.state==="candidate")return{status:404,body:{error:`no request "${o}"`}};let c=s==="done"?typeof a.evidence=="string"&&a.evidence.trim()?a.evidence:"closed by the owner (dashboard)":typeof a.reason=="string"&&a.reason.trim()?a.reason:"dropped by the owner (dashboard)";return i.close(o,s==="done"?"done":"dropped",c,n.now??Date.now())?{status:200,body:{ok:!0,message:s==="done"?`${o} closed as done`:`${o} dropped`}}:{status:409,body:{error:`${o} is already closed`}}}if(t==="POST"&&e===`${Re}/settings`){let o={},s=l=>{let c=a[l];if(c!==void 0){if(typeof c!="number"||!(c>0))throw new Error(`${l} must be a positive number`);return c}};typeof a.enabled=="boolean"&&(o.enabled=a.enabled),o.from=ws(a.from),o.channels=ws(a.channels),o.staleAfterHours=s("staleAfterHours"),o.retentionDays=s("retentionDays");let i=await rr(o,{configPath:n.configPath,reload:n.reload});return i.success?{status:200,body:{ok:!0,settings:_t(n.configPath)}}:{status:400,body:{error:i.error}}}return{status:404,body:{error:"Not found"}}}var ou=["yes","no","later"];function ae(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function Vt(t,e=64*1024){let a=0,n=[];for await(let s of t){if(a+=s.length,a>e)throw new Error("body too large");n.push(s)}let r=Buffer.concat(n).toString("utf-8");if(!r.trim())return{};let o=JSON.parse(r);if(!o||typeof o!="object"||Array.isArray(o))throw new Error("expected a JSON object");return o}function _s(t,e,a){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(vs({peers:e,localToken:a}))}async function Ss(t,e,a,n,r={}){if(!a.startsWith("/api/admin/approvals"))return!1;let o=(t.method||"GET").toUpperCase(),s=r.ctx??{root:process.cwd(),configPath:r.configPath,reload:r.reload};if(o!=="GET"&&t.headers["x-requested-with"]!=="agentx-board")return ae(e,400,{error:"missing X-Requested-With: agentx-board"}),!0;try{if(a.startsWith(Re)){let i=await ks(o,a,o==="POST"?await Vt(t):{},s);return ae(e,i.status,i.body),!0}if(o==="GET"&&a==="/api/admin/approvals"){let i=Et(s,{includeSnoozed:n.searchParams.get("all")==="1"});return ae(e,200,{...i,settings:Ie(s.configPath)}),!0}if(o==="POST"&&a==="/api/admin/approvals/decide"){let i=await Vt(t),l=typeof i.key=="string"?i.key:"",c=i.action;if(!l||!ou.includes(c))return ae(e,400,{error:"send { key, action: yes | no | later }"}),!0;let d=Ie(s.configPath),p=await Tt(s,l,c,{note:typeof i.note=="string"?i.note:void 0,force:i.force===!0,laterHours:d.laterHours,by:"operator (dashboard)"});return p.ok?(ae(e,200,{ok:!0,message:p.message}),!0):(ae(e,409,{error:p.error}),!0)}if(o==="POST"&&a==="/api/admin/approvals/popup"){let i=await Vt(t),l=cr(s,typeof i.key=="string"?i.key:"",!!Ie(s.configPath).popup?.enabled);return l.ok?(ae(e,200,{ok:!0,message:l.message}),!0):(ae(e,409,{error:l.error}),!0)}if(o==="POST"&&a==="/api/admin/approvals/settings"){let i=await Vt(t),l={},c=p=>{let m=i[p];if(m!==void 0){if(typeof m!="number"||!(m>0))throw new Error(`${p} must be a positive number`);return m}};if(l.defaultExpiryDays=c("defaultExpiryDays"),l.maxExpiryDays=c("maxExpiryDays"),l.laterHours=c("laterHours"),typeof i.notifyAgent=="boolean"&&(l.notifyAgent=i.notifyAgent),typeof i.digestEnabled=="boolean"&&(l.digestEnabled=i.digestEnabled),typeof i.digestTime=="string"&&(l.digestTime=i.digestTime),typeof i.destination=="string"){let p=i.destination.trim();if(!p)l.destination=null;else{let m=Dr(p);if(!m)throw new Error("digest destination takes channel:chat id, for example telegram:123456");l.destination=m}}let d=await Hr(l,{configPath:s.configPath,reload:s.reload});return d.success?(ae(e,200,{ok:!0,settings:Ie(s.configPath)}),!0):(ae(e,400,{error:d.error}),!0)}}catch(i){return ae(e,400,{error:String(i?.message??i).slice(0,300)}),!0}return ae(e,404,{error:"Not found"}),!0}xa();function Es(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=ue({kicker:"Operations",title:"People",lead:"Everyone who talks to your agents: you, your teammates, your clients and guests. Open a person to see the machines they paired and what they asked for."})+`
6311
6311
  <div class="pp">
6312
6312
  <div id="pp-msg" class="pp-msg" role="status" aria-live="polite"></div>
6313
6313
  <section id="pp-none" class="pp-none" hidden aria-labelledby="pp-none-title">
@@ -6320,7 +6320,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6320
6320
  </ol>
6321
6321
  </section>
6322
6322
  <ol id="pp-list" class="pp-list" aria-label="People"><li class="pp-empty">Loading\u2026</li></ol>
6323
- </div>`;return M({title:"AgentX \xB7 People",activeTab:"people",subtitle:"People",peers:t.peers,body:a,css:xp,scripts:`${e}<script>${vp}</script>`})}var xp=`
6323
+ </div>`;return I({title:"AgentX \xB7 People",activeTab:"people",subtitle:"People",peers:t.peers,body:a,css:su,scripts:`${e}<script>${iu}</script>`})}var su=`
6324
6324
  .pp { max-width: 1040px; margin: 0 auto; padding: 0 24px 64px; }
6325
6325
  .pp-msg { min-height: 1.4em; margin: 4px 0 8px; font-size: var(--ax-fs-sm); }
6326
6326
  .pp-msg.is-bad { color: var(--ax-red-ink); }
@@ -6361,7 +6361,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6361
6361
  .pp-text { overflow-wrap: anywhere; }
6362
6362
  .pp-meta { margin-top: 2px; display: flex; flex-wrap: wrap; gap: 2px 12px; font-size: var(--ax-fs-xs); color: var(--ax-text-2); }
6363
6363
  @media (prefers-reduced-motion: reduce) { .pp-caret { transition: none; } }
6364
- `,vp=`
6364
+ `,iu=`
6365
6365
  (function () {
6366
6366
  var list = document.getElementById('pp-list');
6367
6367
  var msg = document.getElementById('pp-msg');
@@ -6499,7 +6499,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6499
6499
  load();
6500
6500
  setInterval(load, 30000);
6501
6501
  })();
6502
- `;var ja="/api/admin/people";function bp(t,e){let a=Rr(t,e);return a?{...e,answer:a}:e}function yp(t){return t.state!=="pending"||!t.answer?t.state:t.answer==="yes"?"active":"removed"}function fe(t,e,a){t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a))}function wp(t,e){let a=(o,s)=>e.filter(i=>i.personId===o&&yp(i)===s).length,n=o=>({id:o.id,name:o.name,role:o.role,identities:o.identities,agents:o.agents??[],machines:{active:a(o.id,"active"),pending:a(o.id,"pending")}}),r=t.map(n);return t.some(o=>o.role==="owner")||r.unshift({...n({id:pt,name:"Owner of this machine",role:"owner",identities:[]}),builtIn:!0}),r}var kp=(t,e)=>e.createdAt.localeCompare(t.createdAt);async function ss(t,e,a,n){if(a!=="/people"&&a!==ja&&!a.startsWith(`${ja}/`))return!1;let r=(t.method||"GET").toUpperCase();if(a==="/people")return r!=="GET"?(fe(e,405,{error:"GET only"}),!0):(e.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end(os({peers:n.peers,localToken:n.localToken})),!0);if(r!=="GET"&&t.headers["x-requested-with"]!=="agentx-board")return fe(e,400,{error:"missing X-Requested-With: agentx-board"}),!0;let o=c=>n.members.devices(c).map(p=>bp(n.root,p)),s=()=>wp(n.people(),o());if(r==="GET"&&a===ja){let c=s();return fe(e,200,{people:c,paired:c.reduce((p,u)=>p+u.machines.active+u.machines.pending,0)}),!0}let i=a.match(/^\/api\/admin\/people\/([a-z0-9][a-z0-9_-]{0,39})$/);if(r==="GET"&&i){let c=s().find(h=>h.id===i[1]);if(!c)return fe(e,404,{error:`no person "${i[1]}"`}),!0;let p=n.db(),u=[],m=[];try{p&&(u=Ir(p,c.id))}catch{}try{p&&(m=Rt(p,c.id,20))}catch{}return fe(e,200,{person:c,devices:o(c.id).sort(kp),requests:u,runs:m,database:!!p}),!0}let l=a.match(/^\/api\/admin\/people\/([a-z0-9][a-z0-9_-]{0,39})\/devices\/([A-Za-z0-9_-]{1,80})\/end$/);if(r==="POST"&&l){let[,c,p]=l,u=n.members.byToken(p);if(!u||u.personId!==c)return fe(e,404,{error:"no such machine for this person"}),!0;if(u.state==="removed")return fe(e,409,{error:"this machine's access has already ended"}),!0;let m=Pr({tokens:n.tokens??new F,members:n.members,now:n.now},p,"removed by the owner (dashboard)");return fe(e,200,{ok:!0,device:m}),!0}return fe(e,404,{error:"not found"}),!0}import{resolve as Ap}from"path";import{existsSync as Cp}from"fs";import Ip from"better-sqlite3";var is=new WeakSet;function _p(t,e,a={}){if(is.has(t))return;is.add(t);let n=a.thresholdMs??200,r=a.now??(()=>performance.now()),o=t.prepare.bind(t);t.prepare=s=>{let i=o(s);for(let l of["all","get","run"]){let c=i[l].bind(i);i[l]=(...p)=>{let u=r();try{return c(...p)}finally{let m=r()-u;m>=n&&e({sql:s,ms:m})}}}return i}}function Sp(t,e=160){let a=t.replace(/\s+/g," ").trim();return a.length>e?`${a.slice(0,e-1)}\u2026`:a}function we(t,e){_p(t,({sql:a,ms:n})=>console.error(`[${e}] slow query, ${Math.round(n)} ms: ${Sp(a)}`))}function ls(t={}){let e=`<div class="ax-obs">
6502
+ `;var Ua="/api/admin/people";function lu(t,e){let a=Fr(t,e);return a?{...e,answer:a}:e}function cu(t){return t.state!=="pending"||!t.answer?t.state:t.answer==="yes"?"active":"removed"}function be(t,e,a){t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a))}function du(t,e){let a=(o,s)=>e.filter(i=>i.personId===o&&cu(i)===s).length,n=o=>({id:o.id,name:o.name,role:o.role,identities:o.identities,agents:o.agents??[],machines:{active:a(o.id,"active"),pending:a(o.id,"pending")}}),r=t.map(n);return t.some(o=>o.role==="owner")||r.unshift({...n({id:ht,name:"Owner of this machine",role:"owner",identities:[]}),builtIn:!0}),r}var pu=(t,e)=>e.createdAt.localeCompare(t.createdAt);async function Ts(t,e,a,n){if(a!=="/people"&&a!==Ua&&!a.startsWith(`${Ua}/`))return!1;let r=(t.method||"GET").toUpperCase();if(a==="/people")return r!=="GET"?(be(e,405,{error:"GET only"}),!0):(e.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end(Es({peers:n.peers,localToken:n.localToken})),!0);if(r!=="GET"&&t.headers["x-requested-with"]!=="agentx-board")return be(e,400,{error:"missing X-Requested-With: agentx-board"}),!0;let o=c=>n.members.devices(c).map(d=>lu(n.root,d)),s=()=>du(n.people(),o());if(r==="GET"&&a===Ua){let c=s();return be(e,200,{people:c,paired:c.reduce((d,p)=>d+p.machines.active+p.machines.pending,0)}),!0}let i=a.match(/^\/api\/admin\/people\/([a-z0-9][a-z0-9_-]{0,39})$/);if(r==="GET"&&i){let c=s().find(f=>f.id===i[1]);if(!c)return be(e,404,{error:`no person "${i[1]}"`}),!0;let d=n.db(),p=[],m=[];try{d&&(p=Br(d,c.id))}catch{}try{d&&(m=jt(d,c.id,20))}catch{}return be(e,200,{person:c,devices:o(c.id).sort(pu),requests:p,runs:m,database:!!d}),!0}let l=a.match(/^\/api\/admin\/people\/([a-z0-9][a-z0-9_-]{0,39})\/devices\/([A-Za-z0-9_-]{1,80})\/end$/);if(r==="POST"&&l){let[,c,d]=l,p=n.members.byToken(d);if(!p||p.personId!==c)return be(e,404,{error:"no such machine for this person"}),!0;if(p.state==="removed")return be(e,409,{error:"this machine's access has already ended"}),!0;let m=Wr({tokens:n.tokens??new G,members:n.members,now:n.now},d,"removed by the owner (dashboard)");return be(e,200,{ok:!0,device:m}),!0}return be(e,404,{error:"not found"}),!0}import{resolve as gu}from"path";import{existsSync as xu}from"fs";import bu from"better-sqlite3";var As=new WeakSet;function uu(t,e,a={}){if(As.has(t))return;As.add(t);let n=a.thresholdMs??200,r=a.now??(()=>performance.now()),o=t.prepare.bind(t);t.prepare=s=>{let i=o(s);for(let l of["all","get","run"]){let c=i[l].bind(i);i[l]=(...d)=>{let p=r();try{return c(...d)}finally{let m=r()-p;m>=n&&e({sql:s,ms:m})}}}return i}}function mu(t,e=160){let a=t.replace(/\s+/g," ").trim();return a.length>e?`${a.slice(0,e-1)}\u2026`:a}function Se(t,e){uu(t,({sql:a,ms:n})=>console.error(`[${e}] slow query, ${Math.round(n)} ms: ${mu(a)}`))}function Cs(t={}){let e=`<div class="ax-obs">
6503
6503
  <header class="ax-obs__head">
6504
6504
  <h1>Health</h1>
6505
6505
  <p class="ax-obs__sub">Platform-health view: what each agent ran, what failed, and how the router decided. <span class="ax-obs__sub-link">Spend lives on the <a href="/admin/cost">Cost</a> page.</span></p>
@@ -6621,7 +6621,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6621
6621
  </div>
6622
6622
  <div id="obs-doctor-body" class="ax-obs__doctor-body"></div>
6623
6623
  </section>
6624
- </div>`;return M({title:"AgentX \xB7 Health",activeTab:"health",subtitle:"Health",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Ep,scripts:`<script>${Tp}</script>`})}var Ep=`
6624
+ </div>`;return I({title:"AgentX \xB7 Health",activeTab:"health",subtitle:"Health",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:fu,scripts:`<script>${hu}</script>`})}var fu=`
6625
6625
  .ax-obs { padding: 16px 24px; }
6626
6626
  .ax-obs__head { margin-bottom: 16px; }
6627
6627
  .ax-obs__head h1 { margin: 0 0 4px; font-size: 18px; }
@@ -6738,7 +6738,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6738
6738
  .ax-obs__doctor-title { font-size: 12px; font-weight: 500; }
6739
6739
  .ax-obs__doctor-detail { font-size: 11px; color: var(--ax-muted); margin-top: 2px; font-family: 'IBM Plex Mono', monospace; word-break: break-word; }
6740
6740
  .ax-obs__doctor-fix { font-size: 11px; color: var(--ax-accent, #3a7bd5); margin-top: 2px; }
6741
- `,Tp=`
6741
+ `,hu=`
6742
6742
  (function(){
6743
6743
  var panes = document.querySelectorAll('.ax-obs__pane');
6744
6744
  var tabs = document.querySelectorAll('.ax-obs__tab');
@@ -7122,23 +7122,23 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7122
7122
 
7123
7123
  load(current);
7124
7124
  })();
7125
- `;var ps={opus:{input:15,output:75,cacheRead:1.5,cacheCreate:18.75},sonnet:{input:3,output:15,cacheRead:.3,cacheCreate:3.75},haiku:{input:.25,output:1.25,cacheRead:.025,cacheCreate:.3125},external:{input:0,output:0,cacheRead:0,cacheCreate:0}};function us(t){let e=(t||"").toLowerCase();return e.includes("opus")?"opus":e.includes("haiku")?"haiku":e.includes("sonnet")||e.includes("claude")?"sonnet":"external"}function Oa(t){let e=ps[us(t.model)],a=t.input_tokens/1e6*e.input+t.output_tokens/1e6*e.output+t.cache_read_tokens/1e6*e.cacheRead+t.cache_create_tokens/1e6*e.cacheCreate,n=(t.tier2_input_tokens??0)/1e6*e.input*.5+(t.tier2_output_tokens??0)/1e6*e.output*.5+(t.tier2_cache_read_tokens??0)/1e6*e.cacheRead*.5+(t.tier2_cache_create_tokens??0)/1e6*e.cacheCreate*.5;return a+n}function Mp(){let t=Ap(process.cwd(),".agentx/db.sqlite");if(!Cp(t))return null;try{let e=new Ip(t,{readonly:!0,fileMustExist:!0});return we(e,"health"),{db:e,close:()=>e.close()}}catch{return null}}function ms(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ls({peers:a}))}function Lp(t){let e=new URL(t.url||"/","http://_"),a=parseInt(e.searchParams.get("limit")||"50",10),n=Number.isFinite(a)?Math.max(1,Math.min(500,a)):50,r=e.searchParams.get("agent")||void 0;return{limit:n,agent:r&&r.length>0?r:void 0}}function he(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function fs(t,e,a){if(!a.startsWith("/api/admin/observability/"))return!1;let n=a.replace(/^\/api\/admin\/observability\//,"").split("?")[0],r=Mp();if(!r)return he(e,503,{error:"operational SQLite not available",rows:[]}),!0;try{let{limit:o,agent:s}=Lp(t);if(n==="routing"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
7125
+ `;var Ls={opus:{input:15,output:75,cacheRead:1.5,cacheCreate:18.75},sonnet:{input:3,output:15,cacheRead:.3,cacheCreate:3.75},haiku:{input:.25,output:1.25,cacheRead:.025,cacheCreate:.3125},external:{input:0,output:0,cacheRead:0,cacheCreate:0}};function Rs(t){let e=(t||"").toLowerCase();return e.includes("opus")?"opus":e.includes("haiku")?"haiku":e.includes("sonnet")||e.includes("claude")?"sonnet":"external"}function Wa(t){let e=Ls[Rs(t.model)],a=t.input_tokens/1e6*e.input+t.output_tokens/1e6*e.output+t.cache_read_tokens/1e6*e.cacheRead+t.cache_create_tokens/1e6*e.cacheCreate,n=(t.tier2_input_tokens??0)/1e6*e.input*.5+(t.tier2_output_tokens??0)/1e6*e.output*.5+(t.tier2_cache_read_tokens??0)/1e6*e.cacheRead*.5+(t.tier2_cache_create_tokens??0)/1e6*e.cacheCreate*.5;return a+n}function vu(){let t=gu(process.cwd(),".agentx/db.sqlite");if(!xu(t))return null;try{let e=new bu(t,{readonly:!0,fileMustExist:!0});return Se(e,"health"),{db:e,close:()=>e.close()}}catch{return null}}function Ps(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Cs({peers:a}))}function yu(t){let e=new URL(t.url||"/","http://_"),a=parseInt(e.searchParams.get("limit")||"50",10),n=Number.isFinite(a)?Math.max(1,Math.min(500,a)):50,r=e.searchParams.get("agent")||void 0;return{limit:n,agent:r&&r.length>0?r:void 0}}function ve(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function $s(t,e,a){if(!a.startsWith("/api/admin/observability/"))return!1;let n=a.replace(/^\/api\/admin\/observability\//,"").split("?")[0],r=vu();if(!r)return ve(e,503,{error:"operational SQLite not available",rows:[]}),!0;try{let{limit:o,agent:s}=yu(t);if(n==="routing"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
7126
7126
  SELECT at, channel, chat_id, account_id, kind, deciding_stage, agent_id, reason
7127
7127
  FROM route_traces
7128
7128
  ${i.length?"WHERE "+i.join(" AND "):""}
7129
7129
  ORDER BY at DESC LIMIT @limit
7130
- `,p=r.db.prepare(c).all(l);return he(e,200,{rows:p}),!0}if(n==="rotations"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
7130
+ `,d=r.db.prepare(c).all(l);return ve(e,200,{rows:d}),!0}if(n==="rotations"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
7131
7131
  SELECT rotated_at, agent_id, channel, reason, last_turn_input_tokens
7132
7132
  FROM rotations
7133
7133
  ${i.length?"WHERE "+i.join(" AND "):""}
7134
7134
  ORDER BY rotated_at DESC LIMIT @limit
7135
- `,p=r.db.prepare(c).all(l);return he(e,200,{rows:p}),!0}if(n==="errors"){let i=["status = 'error'"],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
7135
+ `,d=r.db.prepare(c).all(l);return ve(e,200,{rows:d}),!0}if(n==="errors"){let i=["status = 'error'"],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
7136
7136
  SELECT started_at, agent_id, channel, message_preview, error
7137
7137
  FROM task_history
7138
7138
  WHERE ${i.join(" AND ")}
7139
7139
  ORDER BY started_at DESC LIMIT @limit
7140
- `,u=r.db.prepare(c).all(l).map(m=>({...m,plain:hs(m.error)}));return he(e,200,{rows:u}),!0}if(n==="summary"||n==="overview")return he(e,200,Rp(r.db)),!0;if(n==="activity")return he(e,200,$p(r.db,{agent:s})),!0;if(n==="cost"){let i=new URL(t.url||"/","http://_"),l=cs(i.searchParams.get("range"));return he(e,200,ds(r.db,l)),!0}if(n==="cost.csv"){let i=new URL(t.url||"/","http://_"),l=cs(i.searchParams.get("range")),c=ds(r.db,l),p=Pp(c.days);return e.writeHead(200,{"Content-Type":"text/csv; charset=utf-8","Content-Disposition":`attachment; filename="agentx-cost-${l||"all"}d-${Date.now()}.csv"`}),e.end(p),!0}return he(e,404,{error:"unknown observability slice",rows:[]}),!0}catch(o){return he(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function hs(t){let e=String(t||"");return e?/timed out|SIGTERM|exit 143|maxExecutionMinutes/i.test(e)?"Agent ran past its time limit":/ECONNREFUSED|fetch failed|getaddrinfo|ENOTFOUND/i.test(e)?"Couldn't reach a service over the network":/401|403|Unauthorized|Forbidden|invalid token|missing scope/i.test(e)?"Authentication or permission denied":/rate limit|429|too many requests/i.test(e)?"Hit a rate limit (too many calls)":/quota|insufficient_quota/i.test(e)?"Provider account out of quota or credits":/tier-?2|tier two|200K|200,000/i.test(e)?"Hit Anthropic tier-2 billing threshold":/JSON|parse|unexpected token/i.test(e)?"Got a response in the wrong shape":/permission denied|EACCES|EPERM/i.test(e)?"File permission denied":/ENOENT|no such file/i.test(e)?"Expected file is missing":/abort|cancel/i.test(e)?"Task was cancelled before it finished":e.split(`
7141
- `)[0].slice(0,80)+(e.length>80?"\u2026":""):"unknown failure"}function Rp(t){let e=new Date,a=new Date(e.getFullYear(),e.getMonth(),e.getDate()).toISOString(),n=new Date(e.getTime()-864e5),r=new Date(n.getFullYear(),n.getMonth(),n.getDate()).toISOString(),o=new Date(e.getTime()-864e5).toISOString(),s=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ?").get(a).n,i=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ? AND started_at < ?").get(r,a).n,l=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE status='error' AND started_at >= ?").get(a).n,c=t.prepare("SELECT AVG(duration_ms) AS d FROM task_history WHERE status='ok' AND started_at >= ?").get(a).d??0,p=t.prepare("SELECT duration_ms FROM task_history WHERE status='ok' AND started_at >= ? AND duration_ms IS NOT NULL ORDER BY duration_ms ASC").all(a),u=w=>p.length?p[Math.min(p.length-1,Math.floor(p.length*w))].duration_ms:0,m=u(.5),h=u(.95),v=t.prepare("SELECT * FROM usage_daily WHERE day = date('now')").all().reduce((w,I)=>w+Oa(I),0),S=t.prepare("SELECT * FROM usage_daily WHERE day = date('now', '-1 day')").all().reduce((w,I)=>w+Oa(I),0),g=t.prepare(`
7140
+ `,p=r.db.prepare(c).all(l).map(m=>({...m,plain:js(m.error)}));return ve(e,200,{rows:p}),!0}if(n==="summary"||n==="overview")return ve(e,200,wu(r.db)),!0;if(n==="activity")return ve(e,200,ku(r.db,{agent:s})),!0;if(n==="cost"){let i=new URL(t.url||"/","http://_"),l=Is(i.searchParams.get("range"));return ve(e,200,Ms(r.db,l)),!0}if(n==="cost.csv"){let i=new URL(t.url||"/","http://_"),l=Is(i.searchParams.get("range")),c=Ms(r.db,l),d=_u(c.days);return e.writeHead(200,{"Content-Type":"text/csv; charset=utf-8","Content-Disposition":`attachment; filename="agentx-cost-${l||"all"}d-${Date.now()}.csv"`}),e.end(d),!0}return ve(e,404,{error:"unknown observability slice",rows:[]}),!0}catch(o){return ve(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function js(t){let e=String(t||"");return e?/timed out|SIGTERM|exit 143|maxExecutionMinutes/i.test(e)?"Agent ran past its time limit":/ECONNREFUSED|fetch failed|getaddrinfo|ENOTFOUND/i.test(e)?"Couldn't reach a service over the network":/401|403|Unauthorized|Forbidden|invalid token|missing scope/i.test(e)?"Authentication or permission denied":/rate limit|429|too many requests/i.test(e)?"Hit a rate limit (too many calls)":/quota|insufficient_quota/i.test(e)?"Provider account out of quota or credits":/tier-?2|tier two|200K|200,000/i.test(e)?"Hit Anthropic tier-2 billing threshold":/JSON|parse|unexpected token/i.test(e)?"Got a response in the wrong shape":/permission denied|EACCES|EPERM/i.test(e)?"File permission denied":/ENOENT|no such file/i.test(e)?"Expected file is missing":/abort|cancel/i.test(e)?"Task was cancelled before it finished":e.split(`
7141
+ `)[0].slice(0,80)+(e.length>80?"\u2026":""):"unknown failure"}function wu(t){let e=new Date,a=new Date(e.getFullYear(),e.getMonth(),e.getDate()).toISOString(),n=new Date(e.getTime()-864e5),r=new Date(n.getFullYear(),n.getMonth(),n.getDate()).toISOString(),o=new Date(e.getTime()-864e5).toISOString(),s=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ?").get(a).n,i=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ? AND started_at < ?").get(r,a).n,l=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE status='error' AND started_at >= ?").get(a).n,c=t.prepare("SELECT AVG(duration_ms) AS d FROM task_history WHERE status='ok' AND started_at >= ?").get(a).d??0,d=t.prepare("SELECT duration_ms FROM task_history WHERE status='ok' AND started_at >= ? AND duration_ms IS NOT NULL ORDER BY duration_ms ASC").all(a),p=v=>d.length?d[Math.min(d.length-1,Math.floor(d.length*v))].duration_ms:0,m=p(.5),f=p(.95),b=t.prepare("SELECT * FROM usage_daily WHERE day = date('now')").all().reduce((v,A)=>v+Wa(A),0),E=t.prepare("SELECT * FROM usage_daily WHERE day = date('now', '-1 day')").all().reduce((v,A)=>v+Wa(A),0),g=t.prepare(`
7142
7142
  SELECT agent_id,
7143
7143
  COUNT(*) AS tasks,
7144
7144
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors,
@@ -7148,7 +7148,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7148
7148
  WHERE started_at >= ?
7149
7149
  GROUP BY agent_id
7150
7150
  ORDER BY tasks DESC LIMIT 10
7151
- `).all(a),d=t.prepare(`
7151
+ `).all(a),x=t.prepare(`
7152
7152
  SELECT COALESCE(channel, 'unknown') AS channel,
7153
7153
  COUNT(*) AS tasks,
7154
7154
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -7156,12 +7156,12 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7156
7156
  WHERE started_at >= ?
7157
7157
  GROUP BY channel
7158
7158
  ORDER BY tasks DESC
7159
- `).all(a),f=t.prepare("SELECT DISTINCT agent_id FROM usage_daily WHERE day >= date('now', '-7 day')").all().map(w=>w.agent_id),x=new Set(t.prepare("SELECT DISTINCT agent_id FROM task_history WHERE started_at >= ?").all(o).map(w=>w.agent_id)),b=f.filter(w=>!x.has(w)),T=t.prepare(`
7159
+ `).all(a),u=t.prepare("SELECT DISTINCT agent_id FROM usage_daily WHERE day >= date('now', '-7 day')").all().map(v=>v.agent_id),h=new Set(t.prepare("SELECT DISTINCT agent_id FROM task_history WHERE started_at >= ?").all(o).map(v=>v.agent_id)),w=u.filter(v=>!h.has(v)),T=t.prepare(`
7160
7160
  SELECT started_at, agent_id, channel, message_preview, error
7161
7161
  FROM task_history
7162
7162
  WHERE status='error' AND started_at >= ?
7163
7163
  ORDER BY started_at DESC LIMIT 5
7164
- `).all(o).map(w=>({...w,plain:hs(w.error)}));return{kpis:{tasksToday:s,tasksDelta:s-i,errorsToday:l,errorRate:s>0?l/s:0,avgDurationMs:Math.round(c),p50DurationMs:m,p95DurationMs:h,spendToday:v,spendDelta:v-S,idleAgentCount:b.length},perAgent:g,perChannel:d,idleAgents:b,recentErrors:T}}function $p(t,e){let a=new Date(Date.now()-864e5).toISOString(),n=new Date(Date.now()-7*864e5).toISOString(),r=e.agent?"AND agent_id = @agent":"",o=e.agent?{agent:e.agent}:{},s=t.prepare(`
7164
+ `).all(o).map(v=>({...v,plain:js(v.error)}));return{kpis:{tasksToday:s,tasksDelta:s-i,errorsToday:l,errorRate:s>0?l/s:0,avgDurationMs:Math.round(c),p50DurationMs:m,p95DurationMs:f,spendToday:b,spendDelta:b-E,idleAgentCount:w.length},perAgent:g,perChannel:x,idleAgents:w,recentErrors:T}}function ku(t,e){let a=new Date(Date.now()-864e5).toISOString(),n=new Date(Date.now()-7*864e5).toISOString(),r=e.agent?"AND agent_id = @agent":"",o=e.agent?{agent:e.agent}:{},s=t.prepare(`
7165
7165
  SELECT strftime('%Y-%m-%dT%H:00', started_at) AS hour,
7166
7166
  COUNT(*) AS tasks,
7167
7167
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -7188,7 +7188,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7188
7188
  WHERE started_at >= @since
7189
7189
  GROUP BY agent_id
7190
7190
  ORDER BY tasks_24h DESC, tasks_7d DESC
7191
- `).all({since:n,last24:a});return{hourly:s,daily:i,perAgent:l}}function cs(t){if(!t)return 30;if(t==="all"||t==="0")return 0;let e=parseInt(t,10);return!Number.isFinite(e)||e<=0?30:Math.min(e,365)}function ds(t,e){let a=e>0?`WHERE day >= date('now', '-${e} day')`:"",n=t.prepare(`
7191
+ `).all({since:n,last24:a});return{hourly:s,daily:i,perAgent:l}}function Is(t){if(!t)return 30;if(t==="all"||t==="0")return 0;let e=parseInt(t,10);return!Number.isFinite(e)||e<=0?30:Math.min(e,365)}function Ms(t,e){let a=e>0?`WHERE day >= date('now', '-${e} day')`:"",n=t.prepare(`
7192
7192
  SELECT day, agent_id, model,
7193
7193
  input_tokens, output_tokens, cache_read_tokens, cache_create_tokens,
7194
7194
  tier2_input_tokens, tier2_output_tokens, tier2_cache_read_tokens, tier2_cache_create_tokens,
@@ -7196,37 +7196,37 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7196
7196
  FROM usage_daily
7197
7197
  ${a}
7198
7198
  ORDER BY day
7199
- `).all(),r=new Date().toISOString().slice(0,10),o=new Date(Date.now()-864e5).toISOString().slice(0,10),s=new Date(Date.now()-7*864e5).toISOString().slice(0,10),i=new Date(Date.now()-14*864e5).toISOString().slice(0,10),l=0,c=0,p=0,u=0,m=0,h=0,_=0,v=0,S=0,g={},d={};for(let E of n){let $=Oa(E),L=us(E.model),j=ps[L],W=(E.tier2_input_tokens||0)/1e6*j.input*.5+(E.tier2_output_tokens||0)/1e6*j.output*.5+(E.tier2_cache_read_tokens||0)/1e6*j.cacheRead*.5+(E.tier2_cache_create_tokens||0)/1e6*j.cacheCreate*.5,q=(E.input_tokens||0)+(E.tier2_input_tokens||0),G=(E.output_tokens||0)+(E.tier2_output_tokens||0),ie=(E.cache_read_tokens||0)+(E.tier2_cache_read_tokens||0),Oe=(E.cache_create_tokens||0)+(E.tier2_cache_create_tokens||0);u+=$,E.day>=s&&(p+=$,_+=E.tasks||0),E.day>=i&&E.day<s&&(S+=$,v+=E.tasks||0),E.day===r&&(l+=$),E.day===o&&(c+=$),E.day===r&&(m+=W),E.day>=s&&(h+=W);let Z=g[E.day]||(g[E.day]={date:E.day,tasks:0,input:0,output:0,cacheRead:0,cacheCreate:0,cost:0,tier2:0,agents:{}});Z.tasks+=E.tasks||0,Z.input+=q,Z.output+=G,Z.cacheRead+=ie,Z.cacheCreate+=Oe,Z.cost+=$,Z.tier2+=W;let z=Z.agents[E.agent_id]||(Z.agents[E.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:E.model});z.tasks+=E.tasks||0,z.cost+=$,z.tier2+=W,z.input+=q,z.output+=G,z.cacheRead+=ie,z.cacheCreate+=Oe,E.model&&(z.model=E.model);let O=d[E.agent_id]||(d[E.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:E.model});O.tasks+=E.tasks||0,O.cost+=$,O.tier2+=W,O.input+=q,O.output+=G,O.cacheRead+=ie,O.cacheCreate+=Oe,E.model&&(O.model=E.model)}let f=Object.values(g).sort((E,$)=>E.date<$.date?-1:1),x=0,b=0,k=0,T=0,w=0,I=0;for(let E of f)x+=E.tasks,b+=E.input,k+=E.output,T+=E.cacheRead,w+=E.cacheCreate,I+=E.cost;let C=Object.entries(d).map(([E,$])=>({agent_id:E,...$,tokens:$.input+$.output+$.cacheRead+$.cacheCreate})).sort((E,$)=>$.cost-E.cost);return{range:e,generatedAt:new Date().toISOString(),kpis:{spendToday:l,spendYesterday:c,spend7d:p,spend30d:u,tier2Today:m,tier2_7d:h,tier2PctToday:l>0?m/l:0,spendRange:I,avgDailyRange:f.length?I/f.length:0,tasksRange:x,tokensRange:b+k+T+w,cacheHitRange:T+b>0?T/(T+b):0,costPerTaskRange:x>0?I/x:0,spendDeltaWoW:S>0?(p-S)/S:0,tasksDeltaWoW:v>0?(_-v)/v:0},days:f,perAgent:C}}function Pp(t){let e="date,tasks,input,output,cache_read,cache_create,cost_usd,top_agent",a=t.map(n=>{let r=Object.entries(n.agents).sort(([,o],[,s])=>s.cost-o.cost)[0];return[n.date,n.tasks,n.input,n.output,n.cacheRead,n.cacheCreate,n.cost.toFixed(6),r?r[0]:""].join(",")});return e+`
7199
+ `).all(),r=new Date().toISOString().slice(0,10),o=new Date(Date.now()-864e5).toISOString().slice(0,10),s=new Date(Date.now()-7*864e5).toISOString().slice(0,10),i=new Date(Date.now()-14*864e5).toISOString().slice(0,10),l=0,c=0,d=0,p=0,m=0,f=0,S=0,b=0,E=0,g={},x={};for(let _ of n){let L=Wa(_),j=Rs(_.model),$=Ls[j],O=(_.tier2_input_tokens||0)/1e6*$.input*.5+(_.tier2_output_tokens||0)/1e6*$.output*.5+(_.tier2_cache_read_tokens||0)/1e6*$.cacheRead*.5+(_.tier2_cache_create_tokens||0)/1e6*$.cacheCreate*.5,U=(_.input_tokens||0)+(_.tier2_input_tokens||0),ce=(_.output_tokens||0)+(_.tier2_output_tokens||0),Z=(_.cache_read_tokens||0)+(_.tier2_cache_read_tokens||0),oe=(_.cache_create_tokens||0)+(_.tier2_cache_create_tokens||0);p+=L,_.day>=s&&(d+=L,S+=_.tasks||0),_.day>=i&&_.day<s&&(E+=L,b+=_.tasks||0),_.day===r&&(l+=L),_.day===o&&(c+=L),_.day===r&&(m+=O),_.day>=s&&(f+=O);let ee=g[_.day]||(g[_.day]={date:_.day,tasks:0,input:0,output:0,cacheRead:0,cacheCreate:0,cost:0,tier2:0,agents:{}});ee.tasks+=_.tasks||0,ee.input+=U,ee.output+=ce,ee.cacheRead+=Z,ee.cacheCreate+=oe,ee.cost+=L,ee.tier2+=O;let F=ee.agents[_.agent_id]||(ee.agents[_.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:_.model});F.tasks+=_.tasks||0,F.cost+=L,F.tier2+=O,F.input+=U,F.output+=ce,F.cacheRead+=Z,F.cacheCreate+=oe,_.model&&(F.model=_.model);let N=x[_.agent_id]||(x[_.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:_.model});N.tasks+=_.tasks||0,N.cost+=L,N.tier2+=O,N.input+=U,N.output+=ce,N.cacheRead+=Z,N.cacheCreate+=oe,_.model&&(N.model=_.model)}let u=Object.values(g).sort((_,L)=>_.date<L.date?-1:1),h=0,w=0,y=0,T=0,v=0,A=0;for(let _ of u)h+=_.tasks,w+=_.input,y+=_.output,T+=_.cacheRead,v+=_.cacheCreate,A+=_.cost;let R=Object.entries(x).map(([_,L])=>({agent_id:_,...L,tokens:L.input+L.output+L.cacheRead+L.cacheCreate})).sort((_,L)=>L.cost-_.cost);return{range:e,generatedAt:new Date().toISOString(),kpis:{spendToday:l,spendYesterday:c,spend7d:d,spend30d:p,tier2Today:m,tier2_7d:f,tier2PctToday:l>0?m/l:0,spendRange:A,avgDailyRange:u.length?A/u.length:0,tasksRange:h,tokensRange:w+y+T+v,cacheHitRange:T+w>0?T/(T+w):0,costPerTaskRange:h>0?A/h:0,spendDeltaWoW:E>0?(d-E)/E:0,tasksDeltaWoW:b>0?(S-b)/b:0},days:u,perAgent:R}}function _u(t){let e="date,tasks,input,output,cache_read,cache_create,cost_usd,top_agent",a=t.map(n=>{let r=Object.entries(n.agents).sort(([,o],[,s])=>s.cost-o.cost)[0];return[n.date,n.tasks,n.input,n.output,n.cacheRead,n.cacheCreate,n.cost.toFixed(6),r?r[0]:""].join(",")});return e+`
7200
7200
  `+a.join(`
7201
7201
  `)+`
7202
- `}import{resolve as jp}from"path";import{existsSync as Op}from"fs";import Np from"better-sqlite3";function Dp(){let t=jp(process.cwd(),".agentx/intent/ledger.sqlite");if(!Op(t))return null;try{let e=new Np(t,{readonly:!0,fileMustExist:!0});return we(e,"ledger-panel"),{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-gs>6e4&&(gs=a,console.error(`[ledger-panel] openReadOnly failed: ${e?.message??e}`)),null}}var gs=0;function Ce(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Hp(t){if(!t)return;let e=String(t).trim().match(/^(\d+)\s*(s|m|h|d|w)?$/i);if(!e)return;let a=parseInt(e[1],10),n=(e[2]||"h").toLowerCase(),r=n==="s"?1e3:n==="m"?6e4:n==="h"?36e5:n==="d"?864e5:n==="w"?7*864e5:0;return Date.now()-a*r}async function xs(t,e,a){if(!a.startsWith("/api/admin/ledger/"))return!1;let n=a.replace(/^\/api\/admin\/ledger\//,"").split("?")[0],r=Dp();if(!r)return Ce(e,503,{error:"intent ledger not available",rows:[]}),!0;try{let o=new URL(t.url||"/","http://_"),s=Hp(o.searchParams.get("since")),i=o.searchParams.get("source")||"",l=o.searchParams.get("project")||"",c=parseInt(o.searchParams.get("limit")||"50",10),p=Number.isFinite(c)?Math.max(1,Math.min(500,c)):50;if(n==="stats"){let u=s!==void 0?"WHERE ts >= @since":"",m=s!==void 0?"WHERE decided_at >= @since":"",h=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_events ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),_=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_decisions ${m}`).get({since:s}).n,v=r.db.prepare(`SELECT outcome, COUNT(*) AS n FROM intent_decisions ${m} GROUP BY outcome ORDER BY n DESC`).all({since:s}),S=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_divergences ${u}`).get({since:s}).n,g=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_divergences ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),d=r.db.prepare(`
7202
+ `}import{resolve as Su}from"path";import{existsSync as Eu}from"fs";import Tu from"better-sqlite3";function Au(){let t=Su(process.cwd(),".agentx/intent/ledger.sqlite");if(!Eu(t))return null;try{let e=new Tu(t,{readonly:!0,fileMustExist:!0});return Se(e,"ledger-panel"),{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-Os>6e4&&(Os=a,console.error(`[ledger-panel] openReadOnly failed: ${e?.message??e}`)),null}}var Os=0;function Pe(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Cu(t){if(!t)return;let e=String(t).trim().match(/^(\d+)\s*(s|m|h|d|w)?$/i);if(!e)return;let a=parseInt(e[1],10),n=(e[2]||"h").toLowerCase(),r=n==="s"?1e3:n==="m"?6e4:n==="h"?36e5:n==="d"?864e5:n==="w"?7*864e5:0;return Date.now()-a*r}async function Ns(t,e,a){if(!a.startsWith("/api/admin/ledger/"))return!1;let n=a.replace(/^\/api\/admin\/ledger\//,"").split("?")[0],r=Au();if(!r)return Pe(e,503,{error:"intent ledger not available",rows:[]}),!0;try{let o=new URL(t.url||"/","http://_"),s=Cu(o.searchParams.get("since")),i=o.searchParams.get("source")||"",l=o.searchParams.get("project")||"",c=parseInt(o.searchParams.get("limit")||"50",10),d=Number.isFinite(c)?Math.max(1,Math.min(500,c)):50;if(n==="stats"){let p=s!==void 0?"WHERE ts >= @since":"",m=s!==void 0?"WHERE decided_at >= @since":"",f=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_events ${p} GROUP BY source ORDER BY n DESC`).all({since:s}),S=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_decisions ${m}`).get({since:s}).n,b=r.db.prepare(`SELECT outcome, COUNT(*) AS n FROM intent_decisions ${m} GROUP BY outcome ORDER BY n DESC`).all({since:s}),E=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_divergences ${p}`).get({since:s}).n,g=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_divergences ${p} GROUP BY source ORDER BY n DESC`).all({since:s}),x=r.db.prepare(`
7203
7203
  SELECT COUNT(*) AS n FROM intent_decisions d
7204
7204
  LEFT JOIN intent_resolutions r
7205
7205
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
7206
7206
  WHERE d.outcome = 'dispatched' AND r.decision_event_id IS NULL
7207
- `).get().n;return Ce(e,200,{since:s??null,eventsBySource:h,totalDecisions:_,decisionsByOutcome:v,totalDivergences:S,divergencesBySource:g,inFlight:d}),!0}if(n==="events"){let u=[],m={limit:p};s!==void 0&&(u.push("ts >= @since"),m.since=s),i&&(u.push("source = @source"),m.source=i),l&&(u.push("project = @project"),m.project=l);let h=`
7207
+ `).get().n;return Pe(e,200,{since:s??null,eventsBySource:f,totalDecisions:S,decisionsByOutcome:b,totalDivergences:E,divergencesBySource:g,inFlight:x}),!0}if(n==="events"){let p=[],m={limit:d};s!==void 0&&(p.push("ts >= @since"),m.since=s),i&&(p.push("source = @source"),m.source=i),l&&(p.push("project = @project"),m.project=l);let f=`
7208
7208
  SELECT id, ts, source, source_event_id, project, subject, intent
7209
7209
  FROM intent_events
7210
- ${u.length?"WHERE "+u.join(" AND "):""}
7210
+ ${p.length?"WHERE "+p.join(" AND "):""}
7211
7211
  ORDER BY ts DESC LIMIT @limit
7212
- `;return Ce(e,200,{rows:r.db.prepare(h).all(m)}),!0}if(n==="divergences"){let u=[],m={limit:p};s!==void 0&&(u.push("ts >= @since"),m.since=s),i&&(u.push("source = @source"),m.source=i);let h=`
7212
+ `;return Pe(e,200,{rows:r.db.prepare(f).all(m)}),!0}if(n==="divergences"){let p=[],m={limit:d};s!==void 0&&(p.push("ts >= @since"),m.since=s),i&&(p.push("source = @source"),m.source=i);let f=`
7213
7213
  SELECT ts, source, decided_by,
7214
7214
  legacy_agent_id, legacy_outcome, legacy_reason,
7215
7215
  ledger_agent_id, ledger_outcome, ledger_reason,
7216
7216
  event_id
7217
7217
  FROM intent_divergences
7218
- ${u.length?"WHERE "+u.join(" AND "):""}
7218
+ ${p.length?"WHERE "+p.join(" AND "):""}
7219
7219
  ORDER BY ts DESC LIMIT @limit
7220
- `;return Ce(e,200,{rows:r.db.prepare(h).all(m)}),!0}if(n==="active"){let u=["d.outcome = 'dispatched'","r.decision_event_id IS NULL"],m={limit:p};i&&(u.push("e.source = @source"),m.source=i);let h=`
7220
+ `;return Pe(e,200,{rows:r.db.prepare(f).all(m)}),!0}if(n==="active"){let p=["d.outcome = 'dispatched'","r.decision_event_id IS NULL"],m={limit:d};i&&(p.push("e.source = @source"),m.source=i);let f=`
7221
7221
  SELECT e.id AS event_id, e.ts, e.source, e.project, e.subject, e.intent,
7222
7222
  d.decided_by, d.decided_at, d.agent_id, d.reason
7223
7223
  FROM intent_decisions d
7224
7224
  JOIN intent_events e ON e.id = d.event_id
7225
7225
  LEFT JOIN intent_resolutions r
7226
7226
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
7227
- WHERE ${u.join(" AND ")}
7227
+ WHERE ${p.join(" AND ")}
7228
7228
  ORDER BY d.decided_at DESC LIMIT @limit
7229
- `;return Ce(e,200,{rows:r.db.prepare(h).all(m)}),!0}return Ce(e,404,{error:"unknown ledger slice",rows:[]}),!0}catch(o){return Ce(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function vs(t={}){return M({title:"AgentX \xB7 Ledger",activeTab:"graph",subtitle:"Ledger",body:`<div class="ax-led">
7229
+ `;return Pe(e,200,{rows:r.db.prepare(f).all(m)}),!0}return Pe(e,404,{error:"unknown ledger slice",rows:[]}),!0}catch(o){return Pe(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function Ds(t={}){return I({title:"AgentX \xB7 Ledger",activeTab:"graph",subtitle:"Ledger",body:`<div class="ax-led">
7230
7230
  <header class="ax-led__head">
7231
7231
  <h1>Intent ledger</h1>
7232
7232
  <p class="ax-led__sub">Read-only view over <code>.agentx/intent/ledger.sqlite</code> \u2014 same source as <code>agentx ledger</code>. Replay and lineage live in the CLI for now.</p>
@@ -7431,7 +7431,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7431
7431
  }
7432
7432
  load();
7433
7433
  })();
7434
- </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function bs(t={}){return M({title:"AgentX \xB7 Cost",activeTab:"cost",subtitle:"Cost",body:`<div class="ax-cost">
7434
+ </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function Hs(t={}){return I({title:"AgentX \xB7 Cost",activeTab:"cost",subtitle:"Cost",body:`<div class="ax-cost">
7435
7435
  <header class="ax-cost__head">
7436
7436
  <div>
7437
7437
  <h1>Cost</h1>
@@ -8004,7 +8004,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
8004
8004
  load();
8005
8005
  setInterval(load, 30000);
8006
8006
  })();
8007
- </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function ys(t={}){let e=`<div class="ax-pj__root">
8007
+ </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function Bs(t={}){let e=`<div class="ax-pj__root">
8008
8008
  <aside class="ax-pj__list">
8009
8009
  <header>
8010
8010
  <h2>Projects</h2>
@@ -8031,7 +8031,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
8031
8031
  </header>
8032
8032
  <div id="pj-detail-body" class="ax-pj__detail-body"></div>
8033
8033
  </section>
8034
- </div>`;return M({title:"AgentX \xB7 Projects",activeTab:"projects",subtitle:"Projects",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Bp,scripts:`<script>${zp}</script>`})}var Bp=`
8034
+ </div>`;return I({title:"AgentX \xB7 Projects",activeTab:"projects",subtitle:"Projects",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Iu,scripts:`<script>${Mu}</script>`})}var Iu=`
8035
8035
  .ax-pj__root {
8036
8036
  display: grid;
8037
8037
  grid-template-columns: 360px 1fr;
@@ -8218,7 +8218,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
8218
8218
  }
8219
8219
  .ax-pj__warn { color: var(--ax-warn, #facc15); border-top: 1px solid var(--ax-border); }
8220
8220
  .ax-pj__hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); margin-top: 4px; }
8221
- `,zp=`
8221
+ `,Mu=`
8222
8222
  (function(){
8223
8223
  const $ = (sel) => document.querySelector(sel);
8224
8224
  const esc = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({"&":"&amp;","<":"&lt;",">":"&gt;","\\"":"&quot;"}[c]));
@@ -8868,31 +8868,31 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
8868
8868
  load();
8869
8869
  });
8870
8870
  })();
8871
- `;import{resolve as za,join as nu}from"path";import{existsSync as qa,readdirSync as ru,readFileSync as ou}from"fs";import su from"better-sqlite3";var ks=String.raw`[\w.-]+(?:/[\w.-]+)+`,qp=new RegExp(`^(?:chat:)?(${ks}):(?:issue|issues|merge_request|mr|pull|pr)s?:\\d+`),Fp=new RegExp(`^\\[(?:GitLab|GitHub) (${ks}) `);function ws(t){if(!t)return null;let e=t.match(qp);return e?e[1]:null}function Na(t){if(!t)return null;let e=t.trimStart().match(Fp);return e?e[1]:null}function Xt(t,e,a){let n=t&&typeof t=="object"?t.context:null;return n&&typeof n.project=="string"&&n.project.trim()?n.project.trim():ws(typeof n?.chatId=="string"?n.chatId:null)??ws(e)??Na(a)}function Up(t){let[e,...a]=t.split("/");return!a.length||e==="unmapped"||a[0].startsWith("_")?null:t}function Kt(t,e){return`${t}${e.kind==="mr"?"!":"#"}${e.n}`}var Wp=/\b(issue|merge_request|pull|MR|Issue)s?[:\s]+[#!]?(\d+)/,Gp=/^\[(?:GitLab|GitHub) \S+ (issue|merge_request|pull|MR|Issue)s? [#!]?(\d+)/i,Xp=t=>/^issue/i.test(t)?"issue":"mr";function Kp(t){let e=t.subject.match(Wp)??t.inputPreview.trimStart().match(Gp);return e?{kind:Xp(e[1]),n:Number(e[2])}:null}function Jp(t,e=8){let a=[],n=new Set;for(let r of t.matchAll(/(?:^|[\s(,])!(\d{1,6})\b/g)){let o=Number(r[1]);if(!n.has(o)&&(n.add(o),a.push({kind:"mr",n:o}),a.length>=e))break}return a}function _s(t){if(!Up(t.projectId))return[];let e=Kp(t);return e?[e]:Jp(t.inputPreview)}var Vp=6e4,Yp=5*6e4,Qp=40,Ss=6,Es=new Map;function Ts(t){let e=new Map,a=[...t].sort((n,r)=>r.startedAt-n.startedAt);for(let n of a){let r=n.channelId==="github"||/\bpull:\d+/.test(n.subject);for(let o of _s(n)){let s=Kt(n.projectId,o);if(e.has(s)||e.set(s,{project:n.projectId,ref:o,github:r}),e.size>=Qp)return[...e.values()]}}return[...e.values()]}async function As(t,e,a=fetch,n=Date.now()){let r={},o=[];for(let s of t){let i=Kt(s.project,s.ref),l=Es.get(i);l&&n-l.at<(s.github?Yp:Vp)?l.item&&(r[i]=l.item):o.push(s)}for(let s=0;s<o.length;s+=Ss)await Promise.all(o.slice(s,s+Ss).map(async i=>{let l=Kt(i.project,i.ref),c=null;try{c=i.github?await eu(i,e,a):await Zp(i,e,a)}catch{}Es.set(l,{at:n,item:c}),c&&(r[l]=c)}));return r}async function Cs(t,e,a){let n=new AbortController,r=setTimeout(()=>n.abort(),5e3);try{let o=await a(t,{headers:e,signal:n.signal});return o.ok?await o.json():null}finally{clearTimeout(r)}}async function Zp(t,e,a){let n=e.gitlab;if(!n?.host||!n.token)return null;let r=`${n.host.replace(/\/+$/,"")}/api/v4/projects/${encodeURIComponent(t.project)}`,o=t.ref.kind==="mr"?`merge_requests/${t.ref.n}`:`issues/${t.ref.n}`,s=await Cs(`${r}/${o}`,{"PRIVATE-TOKEN":n.token},a);if(!s)return null;let i=s.head_pipeline??s.pipeline;return{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(s.title??""),state:String(s.state??"opened"),draft:!!(s.draft??s.work_in_progress),url:String(s.web_url??""),pipeline:i&&typeof i.status=="string"?{status:i.status,url:String(i.web_url??"")}:null,mergedAt:s.merged_at?Date.parse(s.merged_at):null}}async function eu(t,e,a){let n=t.ref.kind==="mr"?`pulls/${t.ref.n}`:`issues/${t.ref.n}`,r={Accept:"application/vnd.github+json","User-Agent":"agentx-dashboard"};e.githubToken&&(r.Authorization=`Bearer ${e.githubToken}`);let o=await Cs(`https://api.github.com/repos/${t.project}/${n}`,r,a);return o?{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(o.title??""),state:o.merged_at?"merged":o.state==="open"?"opened":String(o.state??"opened"),draft:!!o.draft,url:String(o.html_url??""),pipeline:null,mergedAt:o.merged_at?Date.parse(o.merged_at):null}:null}kn();var Da=(t,e)=>typeof t=="string"&&t.trim()?t.trim().slice(0,e):void 0;function Is(t){let e=t&&typeof t=="object"?t.context:void 0;if(!e||typeof e!="object")return{};let a={},n=ct(e);n&&(a.root={kind:n.kind,channel:n.channel},n.sender&&(a.root.sender=n.sender),n.agentId&&(a.root.agentId=n.agentId));let r=e.delegation;if(r&&typeof r=="object"){let o=r,s=Da(o.from,80);if(s){a.callback={from:s,status:Da(o.status,20)??"done"};let i=Da(o.peer,80);i&&(a.callback.peer=i)}}return a}kn();ua();var Ms={kind:"agentx",id:"agentx",name:"AgentX"},Ha={kind:"person",id:"unknown",name:"Unknown"},tu=new Set(["cron","workflow","a2a","mcp","mesh","events","reminder","heartbeat","system","internal","business"]),Ls=t=>typeof t=="string"&&/\[bot\]$|^(project|group)_\d+_bot/i.test(t),Ie=t=>typeof t=="string"&&t?t:typeof t=="number"?String(t):void 0;function au(t,e,a){let n=t==="workflow"?a?.event?.payload:a,r=n?.issueEvent||n?.webhookEvent,o=n?.sender??r?.sender??n?.message?.from??n?.user??r?.user,s=Ie(o?.id)??(e==="whatsapp"?Ie(n?.from):void 0),i=Ie(o?.username)??Ie(o?.login);return s||i?{id:s,username:i,name:Ie(o?.name)}:null}function Rs(t){let e=s=>({kind:"person",id:`person:${s}`,name:Tn(t.people,s)}),a=(s,i)=>i||tu.has(s)?Ms:{kind:"external",id:`ext:${s}`,name:t.channelLabel(s)},n=t.raw&&typeof t.raw=="object"?t.raw:{};if(t.source==="mesh"){let s=n.context&&typeof n.context=="object"?n.context:void 0,i=Ie(n.person)??Cn(t.people,s)?.id;if(i)return e(i);let l=ct(s),c=l?.channel??t.channel;if(wn(s)==="human")return Ls(s?.senderUsername)?a(c,!1):Ha;let p=!!Ie(n.senderAgentId)||ca(l?l.sender:s?.sender);return c==="desktop"&&!p?Ha:a(c,p)}let r=au(t.source,t.channel,n);if(!r)return a(t.channel,!1);let o=An(t.people,t.channel,r);return o?e(o.id):ca(r.name)?Ms:yn.has(t.channel)&&!Ls(r.username)?Ha:a(t.channel,!1)}function Fa(){let t=za(process.cwd(),".agentx/intent/ledger.sqlite");if(!qa(t))return null;try{let e=new su(t,{readonly:!0,fileMustExist:!0});return we(e,"activity-graph"),{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-$s>6e4&&($s=a,console.error(`[activity-graph] openLedger failed: ${e?.message??e}`)),null}}var $s=0;function ge(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}var Me={gitlab:{label:"GitLab",color:"#fc6d26"},github:{label:"GitHub",color:"#6e7681"},telegram:{label:"Telegram",color:"#0088cc"},whatsapp:{label:"WhatsApp",color:"#25d366"},slack:{label:"Slack",color:"#4a154b"},discord:{label:"Discord",color:"#5865f2"},mesh:{label:"Mesh (a2a)",color:"#bf8700"},a2a:{label:"Agent \u2192 Agent",color:"#bf8700"},cron:{label:"Cron",color:"#6b7280"},workflow:{label:"Workflow",color:"#9333ea"},api:{label:"Web API",color:"#3a7bd5"},mcp:{label:"Agent tools (MCP)",color:"#bf8700"},voice:{label:"Voice",color:"#e5534b"},desktop:{label:"Desktop assistant",color:"#8957e5"},app:{label:"Phone app",color:"#0f9d8a"},opencode:{label:"OpenCode",color:"#57606a"}};function iu(t,e,a){if(t==="mesh"){let n=a?.context?.channel;if(typeof n=="string"&&n in Me)return n;if(e.startsWith("mesh.")){let r=e.slice(5);if(r==="a2a")return"a2a";if(r in Me)return r}return"mesh"}if(t==="workflow"){let n=a?.event?.payload,r=typeof n?.channel=="string"?n.channel:"";if(r&&r in Me)return r;let o=n?.issueEvent||n?.webhookEvent;if(o){if(o.user?.username||o.project?.path_with_namespace)return"gitlab";if(o.sender?.login)return"github"}if(e.startsWith("workflow.")){let s=e.slice(9).split("-")[0];if(s in Me)return s}return"workflow"}return t}function Os(t){let e={globex:"#e07a3a",initech:"#3a7bd5",acme:"#10b981",umbrella:"#bc8cff","umbrella-lab":"#bc8cff",hexastack:"#06b6d4",demosite:"#ec775c",internal:"#6b7280",unmapped:"#d29922"};if(e[t])return e[t];let a=["#e07a3a","#3a7bd5","#10b981","#bc8cff","#ec775c","#bf8700","#5865f2","#cf222e"],n=0;for(let r=0;r<t.length;r++)n=n*31+t.charCodeAt(r)|0;return a[Math.abs(n)%a.length]}function lu(t,e){if(!t)return!1;let a=e?.agents?.[t];return a&&typeof a.system=="boolean"?a.system:!!(t==="graph-agent"||t==="intent-classifier"||/-classifier$/.test(t))}function Ns(t,e,a){return Bn(t,{chatId:String(e?.chatId??e?.message?.chat?.id??""),username:String(e?.sender?.username??e?.message?.from?.username??""),senderId:String(e?.sender?.id??e?.message?.from?.id??"")},a)}function cu(t,e,a){if(!a||typeof a!="object")return null;if(t==="mesh"){if(typeof a.senderAgentId=="string"&&a.senderAgentId.trim()){let r=a.senderAgentId.trim();return{id:r,name:r,avatar:J(r),kind:"a2a"}}let n=a.context&&typeof a.context=="object"?a.context:null;if(n){let r=typeof n.senderUsername=="string"?n.senderUsername:null,o=typeof n.sender=="string"?n.sender:null,s=typeof n.senderId=="string"?n.senderId:null;if(o&&o.startsWith("agent:")){let l=o.slice(6);if(l&&!Ba(l))return{id:l,name:l,avatar:J(l),kind:"a2a"}}let i=o||r||s;if(i&&!Ba(r||o||"")){let l=r||o||s;return{id:l,name:o||r||l,avatar:J(i),kind:pu(e,n)}}}return e==="mesh.task"||e==="mesh.a2a"?{id:"__a2a",name:"Internal (A2A)",avatar:"\u21BB",kind:"a2a"}:null}if(t==="cron"){let n=typeof a.jobId=="string"?a.jobId:null;if(n)return{id:`cron:${n}`,name:`Cron: ${n}`,avatar:"\u23F1",kind:"cron"}}if(t==="workflow"){let n=a.event?.payload;if(n&&typeof n=="object"){if(n.sender&&typeof n.sender=="object"){let s=n.sender,i=typeof s.username=="string"?s.username:null,l=typeof s.name=="string"?s.name:null,c=i||(s.id!=null?String(s.id):null)||l;if(c&&!Ba(i||l||"")){let p=typeof n.channel=="string"?n.channel:"",u=Ps(p);return{id:c,name:l||i||c,avatar:J(l||i||c),kind:u}}}let o=n.issueEvent||n.webhookEvent;if(o&&typeof o=="object"){let s=o.user;if(s&&typeof s=="object"&&(s.username||s.name)){let l=s.username||s.name,c=s.name||s.username;return{id:l,name:c,avatar:J(c),kind:"gitlab"}}let i=o.sender;if(i?.login)return{id:i.login,name:i.login,avatar:J(i.login),kind:"github"}}}let r=typeof a.workflowId=="string"&&a.workflowId||typeof a.runId=="string"&&a.runId||typeof a.workflow=="string"&&a.workflow||typeof a.event?.id=="string"&&a.event.id.split(":")[0];if(r)return{id:`workflow:${r}`,name:`Workflow: ${r}`,avatar:"\u25B6",kind:"workflow"}}if(a.sender&&typeof a.sender=="object"){let n=a.sender,r=typeof n.username=="string"?n.username:null,o=typeof n.name=="string"?n.name:null,s=r||(n.id!=null?String(n.id):null)||o;if(s){let i=o||r||s;return{id:s,name:i,avatar:J(i),kind:Ps(t)}}}if(t==="gitlab"){let n=a.user||a.payload?.user;if(n&&typeof n=="object"&&(n.username||n.name)){let r=n.username||n.name,o=n.name||n.username;return{id:r,name:o,avatar:J(o),kind:"gitlab"}}}if(t==="github"){let n=a.sender||a.payload?.sender;if(n?.login)return{id:n.login,name:n.login,avatar:J(n.login),kind:"github"}}if(t==="telegram"){let n=a.message?.from||a.from;if(n?.username){let r=n.first_name||n.username;return{id:n.username,name:r,avatar:J(r),kind:"telegram"}}if(n?.id)return{id:String(n.id),name:n.first_name||`tg:${n.id}`,avatar:J(n.first_name||`tg${n.id}`),kind:"telegram"}}if(t==="whatsapp"){let n=a.from||a.payload?.from;if(n){let r=String(n),o=r.replace(/@.*$/,"");return{id:r,name:o,avatar:J(o),kind:"whatsapp"}}}return null}var du={github:"github",gitlab:"gitlab",a2a:"a2a",voice:"voice",desktop:"desktop",app:"app"};function pu(t,e){let a=du[t.startsWith("mesh.")?t.slice(5):""]??"mesh";return a!=="a2a"&&e.via==="voice"?"voice":a}function Ps(t){return t==="telegram"||t==="whatsapp"||t==="slack"||t==="discord"?t:"system"}function Ba(t){if(!t)return!1;let e=t.toLowerCase();return e==="graph-classifier"||e==="graph-agent"||e.startsWith("system:")||e.startsWith("internal:")||e.endsWith("-system")}function J(t){let e=String(t||"?").trim().split(/\s+/).filter(Boolean);return e.length>=2?(e[0][0]+e[1][0]).toUpperCase():String(t||"?").slice(0,2).toUpperCase()}function Ds(t,e){if(!e||typeof e!="object")return"";let a=[];if(typeof e.text=="string"&&a.push(e.text),e.message?.text&&a.push(e.message.text),e.message?.caption&&a.push(e.message.caption),e.object_attributes?.note&&a.push(e.object_attributes.note),e.object_attributes?.title){let n=e.object_attributes.title,r=e.object_attributes.description;a.push(r?`${n}
8871
+ `;import{resolve as Va,join as Gu}from"path";import{existsSync as Ya,readdirSync as Xu,readFileSync as Ku}from"fs";import Ju from"better-sqlite3";var qs=String.raw`[\w.-]+(?:/[\w.-]+)+`,Lu=new RegExp(`^(?:chat:)?(${qs}):(?:issue|issues|merge_request|mr|pull|pr)s?:\\d+`),Ru=new RegExp(`^\\[(?:GitLab|GitHub) (${qs}) `);function zs(t){if(!t)return null;let e=t.match(Lu);return e?e[1]:null}function Ga(t){if(!t)return null;let e=t.trimStart().match(Ru);return e?e[1]:null}function Yt(t,e,a){let n=t&&typeof t=="object"?t.context:null;return n&&typeof n.project=="string"&&n.project.trim()?n.project.trim():zs(typeof n?.chatId=="string"?n.chatId:null)??zs(e)??Ga(a)}function Pu(t){let[e,...a]=t.split("/");return!a.length||e==="unmapped"||a[0].startsWith("_")?null:t}function Qt(t,e){return`${t}${e.kind==="mr"?"!":"#"}${e.n}`}var $u=/\b(issue|merge_request|pull|MR|Issue)s?[:\s]+[#!]?(\d+)/,ju=/^\[(?:GitLab|GitHub) \S+ (issue|merge_request|pull|MR|Issue)s? [#!]?(\d+)/i,Ou=t=>/^issue/i.test(t)?"issue":"mr";function Nu(t){let e=t.subject.match($u)??t.inputPreview.trimStart().match(ju);return e?{kind:Ou(e[1]),n:Number(e[2])}:null}function Du(t,e=8){let a=[],n=new Set;for(let r of t.matchAll(/(?:^|[\s(,])!(\d{1,6})\b/g)){let o=Number(r[1]);if(!n.has(o)&&(n.add(o),a.push({kind:"mr",n:o}),a.length>=e))break}return a}function Fs(t){if(!Pu(t.projectId))return[];let e=Nu(t);return e?[e]:Du(t.inputPreview)}var Hu=6e4,Bu=5*6e4,zu=40,Us=6,Ws=new Map;function Gs(t){let e=new Map,a=[...t].sort((n,r)=>r.startedAt-n.startedAt);for(let n of a){let r=n.channelId==="github"||/\bpull:\d+/.test(n.subject);for(let o of Fs(n)){let s=Qt(n.projectId,o);if(e.has(s)||e.set(s,{project:n.projectId,ref:o,github:r}),e.size>=zu)return[...e.values()]}}return[...e.values()]}async function Xs(t,e,a=fetch,n=Date.now()){let r={},o=[];for(let s of t){let i=Qt(s.project,s.ref),l=Ws.get(i);l&&n-l.at<(s.github?Bu:Hu)?l.item&&(r[i]=l.item):o.push(s)}for(let s=0;s<o.length;s+=Us)await Promise.all(o.slice(s,s+Us).map(async i=>{let l=Qt(i.project,i.ref),c=null;try{c=i.github?await Fu(i,e,a):await qu(i,e,a)}catch{}Ws.set(l,{at:n,item:c}),c&&(r[l]=c)}));return r}async function Ks(t,e,a){let n=new AbortController,r=setTimeout(()=>n.abort(),5e3);try{let o=await a(t,{headers:e,signal:n.signal});return o.ok?await o.json():null}finally{clearTimeout(r)}}async function qu(t,e,a){let n=e.gitlab;if(!n?.host||!n.token)return null;let r=`${n.host.replace(/\/+$/,"")}/api/v4/projects/${encodeURIComponent(t.project)}`,o=t.ref.kind==="mr"?`merge_requests/${t.ref.n}`:`issues/${t.ref.n}`,s=await Ks(`${r}/${o}`,{"PRIVATE-TOKEN":n.token},a);if(!s)return null;let i=s.head_pipeline??s.pipeline;return{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(s.title??""),state:String(s.state??"opened"),draft:!!(s.draft??s.work_in_progress),url:String(s.web_url??""),pipeline:i&&typeof i.status=="string"?{status:i.status,url:String(i.web_url??"")}:null,mergedAt:s.merged_at?Date.parse(s.merged_at):null}}async function Fu(t,e,a){let n=t.ref.kind==="mr"?`pulls/${t.ref.n}`:`issues/${t.ref.n}`,r={Accept:"application/vnd.github+json","User-Agent":"agentx-dashboard"};e.githubToken&&(r.Authorization=`Bearer ${e.githubToken}`);let o=await Ks(`https://api.github.com/repos/${t.project}/${n}`,r,a);return o?{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(o.title??""),state:o.merged_at?"merged":o.state==="open"?"opened":String(o.state??"opened"),draft:!!o.draft,url:String(o.html_url??""),pipeline:null,mergedAt:o.merged_at?Date.parse(o.merged_at):null}:null}Rn();var Xa=(t,e)=>typeof t=="string"&&t.trim()?t.trim().slice(0,e):void 0;function Js(t){let e=t&&typeof t=="object"?t.context:void 0;if(!e||typeof e!="object")return{};let a={},n=mt(e);n&&(a.root={kind:n.kind,channel:n.channel},n.sender&&(a.root.sender=n.sender),n.agentId&&(a.root.agentId=n.agentId));let r=e.delegation;if(r&&typeof r=="object"){let o=r,s=Xa(o.from,80);if(s){a.callback={from:s,status:Xa(o.status,20)??"done"};let i=Xa(o.peer,80);i&&(a.callback.peer=i)}}return a}Rn();xa();var Vs={kind:"agentx",id:"agentx",name:"AgentX"},Ka={kind:"person",id:"unknown",name:"Unknown"},Uu=new Set(["cron","workflow","a2a","mcp","mesh","events","reminder","heartbeat","system","internal","business"]),Ys=t=>typeof t=="string"&&/\[bot\]$|^(project|group)_\d+_bot/i.test(t),$e=t=>typeof t=="string"&&t?t:typeof t=="number"?String(t):void 0;function Wu(t,e,a){let n=t==="workflow"?a?.event?.payload:a,r=n?.issueEvent||n?.webhookEvent,o=n?.sender??r?.sender??n?.message?.from??n?.user??r?.user,s=$e(o?.id)??(e==="whatsapp"?$e(n?.from):void 0),i=$e(o?.username)??$e(o?.login);return s||i?{id:s,username:i,name:$e(o?.name)}:null}function Qs(t){let e=s=>({kind:"person",id:`person:${s}`,name:Nn(t.people,s)}),a=(s,i)=>i||Uu.has(s)?Vs:{kind:"external",id:`ext:${s}`,name:t.channelLabel(s)},n=t.raw&&typeof t.raw=="object"?t.raw:{};if(t.source==="mesh"){let s=n.context&&typeof n.context=="object"?n.context:void 0,i=$e(n.person)??Hn(t.people,s)?.id;if(i)return e(i);let l=mt(s),c=l?.channel??t.channel;if(Ln(s)==="human")return Ys(s?.senderUsername)?a(c,!1):Ka;let d=!!$e(n.senderAgentId)||ma(l?l.sender:s?.sender);return c==="desktop"&&!d?Ka:a(c,d)}let r=Wu(t.source,t.channel,n);if(!r)return a(t.channel,!1);let o=Dn(t.people,t.channel,r);return o?e(o.id):ma(r.name)?Vs:Mn.has(t.channel)&&!Ys(r.username)?Ka:a(t.channel,!1)}function Qa(){let t=Va(process.cwd(),".agentx/intent/ledger.sqlite");if(!Ya(t))return null;try{let e=new Ju(t,{readonly:!0,fileMustExist:!0});return Se(e,"activity-graph"),{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-Zs>6e4&&(Zs=a,console.error(`[activity-graph] openLedger failed: ${e?.message??e}`)),null}}var Zs=0;function ye(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}var je={gitlab:{label:"GitLab",color:"#fc6d26"},github:{label:"GitHub",color:"#6e7681"},telegram:{label:"Telegram",color:"#0088cc"},whatsapp:{label:"WhatsApp",color:"#25d366"},slack:{label:"Slack",color:"#4a154b"},discord:{label:"Discord",color:"#5865f2"},mesh:{label:"Mesh (a2a)",color:"#bf8700"},a2a:{label:"Agent \u2192 Agent",color:"#bf8700"},cron:{label:"Cron",color:"#6b7280"},workflow:{label:"Workflow",color:"#9333ea"},api:{label:"Web API",color:"#3a7bd5"},mcp:{label:"Agent tools (MCP)",color:"#bf8700"},voice:{label:"Voice",color:"#e5534b"},desktop:{label:"Desktop assistant",color:"#8957e5"},app:{label:"Phone app",color:"#0f9d8a"},opencode:{label:"OpenCode",color:"#57606a"}};function Vu(t,e,a){if(t==="mesh"){let n=a?.context?.channel;if(typeof n=="string"&&n in je)return n;if(e.startsWith("mesh.")){let r=e.slice(5);if(r==="a2a")return"a2a";if(r in je)return r}return"mesh"}if(t==="workflow"){let n=a?.event?.payload,r=typeof n?.channel=="string"?n.channel:"";if(r&&r in je)return r;let o=n?.issueEvent||n?.webhookEvent;if(o){if(o.user?.username||o.project?.path_with_namespace)return"gitlab";if(o.sender?.login)return"github"}if(e.startsWith("workflow.")){let s=e.slice(9).split("-")[0];if(s in je)return s}return"workflow"}return t}function ai(t){let e={globex:"#e07a3a",initech:"#3a7bd5",acme:"#10b981",umbrella:"#bc8cff","umbrella-lab":"#bc8cff",hexastack:"#06b6d4",demosite:"#ec775c",internal:"#6b7280",unmapped:"#d29922"};if(e[t])return e[t];let a=["#e07a3a","#3a7bd5","#10b981","#bc8cff","#ec775c","#bf8700","#5865f2","#cf222e"],n=0;for(let r=0;r<t.length;r++)n=n*31+t.charCodeAt(r)|0;return a[Math.abs(n)%a.length]}function Yu(t,e){if(!t)return!1;let a=e?.agents?.[t];return a&&typeof a.system=="boolean"?a.system:!!(t==="graph-agent"||t==="intent-classifier"||/-classifier$/.test(t))}function ni(t,e,a){return Yn(t,{chatId:String(e?.chatId??e?.message?.chat?.id??""),username:String(e?.sender?.username??e?.message?.from?.username??""),senderId:String(e?.sender?.id??e?.message?.from?.id??"")},a)}function Qu(t,e,a){if(!a||typeof a!="object")return null;if(t==="mesh"){if(typeof a.senderAgentId=="string"&&a.senderAgentId.trim()){let r=a.senderAgentId.trim();return{id:r,name:r,avatar:J(r),kind:"a2a"}}let n=a.context&&typeof a.context=="object"?a.context:null;if(n){let r=typeof n.senderUsername=="string"?n.senderUsername:null,o=typeof n.sender=="string"?n.sender:null,s=typeof n.senderId=="string"?n.senderId:null;if(o&&o.startsWith("agent:")){let l=o.slice(6);if(l&&!Ja(l))return{id:l,name:l,avatar:J(l),kind:"a2a"}}let i=o||r||s;if(i&&!Ja(r||o||"")){let l=r||o||s;return{id:l,name:o||r||l,avatar:J(i),kind:em(e,n)}}}return e==="mesh.task"||e==="mesh.a2a"?{id:"__a2a",name:"Internal (A2A)",avatar:"\u21BB",kind:"a2a"}:null}if(t==="cron"){let n=typeof a.jobId=="string"?a.jobId:null;if(n)return{id:`cron:${n}`,name:`Cron: ${n}`,avatar:"\u23F1",kind:"cron"}}if(t==="workflow"){let n=a.event?.payload;if(n&&typeof n=="object"){if(n.sender&&typeof n.sender=="object"){let s=n.sender,i=typeof s.username=="string"?s.username:null,l=typeof s.name=="string"?s.name:null,c=i||(s.id!=null?String(s.id):null)||l;if(c&&!Ja(i||l||"")){let d=typeof n.channel=="string"?n.channel:"",p=ei(d);return{id:c,name:l||i||c,avatar:J(l||i||c),kind:p}}}let o=n.issueEvent||n.webhookEvent;if(o&&typeof o=="object"){let s=o.user;if(s&&typeof s=="object"&&(s.username||s.name)){let l=s.username||s.name,c=s.name||s.username;return{id:l,name:c,avatar:J(c),kind:"gitlab"}}let i=o.sender;if(i?.login)return{id:i.login,name:i.login,avatar:J(i.login),kind:"github"}}}let r=typeof a.workflowId=="string"&&a.workflowId||typeof a.runId=="string"&&a.runId||typeof a.workflow=="string"&&a.workflow||typeof a.event?.id=="string"&&a.event.id.split(":")[0];if(r)return{id:`workflow:${r}`,name:`Workflow: ${r}`,avatar:"\u25B6",kind:"workflow"}}if(a.sender&&typeof a.sender=="object"){let n=a.sender,r=typeof n.username=="string"?n.username:null,o=typeof n.name=="string"?n.name:null,s=r||(n.id!=null?String(n.id):null)||o;if(s){let i=o||r||s;return{id:s,name:i,avatar:J(i),kind:ei(t)}}}if(t==="gitlab"){let n=a.user||a.payload?.user;if(n&&typeof n=="object"&&(n.username||n.name)){let r=n.username||n.name,o=n.name||n.username;return{id:r,name:o,avatar:J(o),kind:"gitlab"}}}if(t==="github"){let n=a.sender||a.payload?.sender;if(n?.login)return{id:n.login,name:n.login,avatar:J(n.login),kind:"github"}}if(t==="telegram"){let n=a.message?.from||a.from;if(n?.username){let r=n.first_name||n.username;return{id:n.username,name:r,avatar:J(r),kind:"telegram"}}if(n?.id)return{id:String(n.id),name:n.first_name||`tg:${n.id}`,avatar:J(n.first_name||`tg${n.id}`),kind:"telegram"}}if(t==="whatsapp"){let n=a.from||a.payload?.from;if(n){let r=String(n),o=r.replace(/@.*$/,"");return{id:r,name:o,avatar:J(o),kind:"whatsapp"}}}return null}var Zu={github:"github",gitlab:"gitlab",a2a:"a2a",voice:"voice",desktop:"desktop",app:"app"};function em(t,e){let a=Zu[t.startsWith("mesh.")?t.slice(5):""]??"mesh";return a!=="a2a"&&e.via==="voice"?"voice":a}function ei(t){return t==="telegram"||t==="whatsapp"||t==="slack"||t==="discord"?t:"system"}function Ja(t){if(!t)return!1;let e=t.toLowerCase();return e==="graph-classifier"||e==="graph-agent"||e.startsWith("system:")||e.startsWith("internal:")||e.endsWith("-system")}function J(t){let e=String(t||"?").trim().split(/\s+/).filter(Boolean);return e.length>=2?(e[0][0]+e[1][0]).toUpperCase():String(t||"?").slice(0,2).toUpperCase()}function ri(t,e){if(!e||typeof e!="object")return"";let a=[];if(typeof e.text=="string"&&a.push(e.text),e.message?.text&&a.push(e.message.text),e.message?.caption&&a.push(e.message.caption),e.object_attributes?.note&&a.push(e.object_attributes.note),e.object_attributes?.title){let n=e.object_attributes.title,r=e.object_attributes.description;a.push(r?`${n}
8872
8872
  ${r}`:n)}e.comment?.body&&a.push(e.comment.body),e.issue?.title&&a.push(e.issue.title+(e.issue.body?`
8873
- ${e.issue.body}`:"")),e.pull_request?.title&&a.push(e.pull_request.title),typeof e.message=="string"&&a.push(e.message),typeof e.prompt=="string"&&a.push(e.prompt),typeof e.input=="string"&&a.push(e.input),e.payload&&typeof e.payload.text=="string"&&a.push(e.payload.text),e.payload&&typeof e.payload.message=="string"&&a.push(e.payload.message);for(let n of a)if(typeof n=="string"&&n.trim().length>0){let r=n.trim();return r.length>220?r.slice(0,217)+"\u2026":r}return""}function uu(t){if(!t)return"(no subject)";let e;return(e=t.match(/^merge_request:(\d+)(?::note:(\d+))?/))?e[2]?`MR #${e[1]} \xB7 note ${e[2]}`:`MR #${e[1]}`:(e=t.match(/^issue:(\d+)(?::note:(\d+))?/))?e[2]?`Issue #${e[1]} \xB7 note ${e[2]}`:`Issue #${e[1]}`:(e=t.match(/^chat:(.+?):(.+)$/))?`${e[1]} \xB7 ${e[2].slice(0,40)}`:(e=t.match(/^mesh:agent:(.+)$/))?`\u2192 ${e[1]}`:(e=t.match(/^workflow:([^:]+):(.+)$/))?`${e[1]} \xB7 ${e[2].slice(0,30)}`:t.length>60?t.slice(0,57)+"\u2026":t}function Hs(t,e,a){let n=Date.now(),r=n-a*3600*1e3,o=t.prepare(`
8873
+ ${e.issue.body}`:"")),e.pull_request?.title&&a.push(e.pull_request.title),typeof e.message=="string"&&a.push(e.message),typeof e.prompt=="string"&&a.push(e.prompt),typeof e.input=="string"&&a.push(e.input),e.payload&&typeof e.payload.text=="string"&&a.push(e.payload.text),e.payload&&typeof e.payload.message=="string"&&a.push(e.payload.message);for(let n of a)if(typeof n=="string"&&n.trim().length>0){let r=n.trim();return r.length>220?r.slice(0,217)+"\u2026":r}return""}function tm(t){if(!t)return"(no subject)";let e;return(e=t.match(/^merge_request:(\d+)(?::note:(\d+))?/))?e[2]?`MR #${e[1]} \xB7 note ${e[2]}`:`MR #${e[1]}`:(e=t.match(/^issue:(\d+)(?::note:(\d+))?/))?e[2]?`Issue #${e[1]} \xB7 note ${e[2]}`:`Issue #${e[1]}`:(e=t.match(/^chat:(.+?):(.+)$/))?`${e[1]} \xB7 ${e[2].slice(0,40)}`:(e=t.match(/^mesh:agent:(.+)$/))?`\u2192 ${e[1]}`:(e=t.match(/^workflow:([^:]+):(.+)$/))?`${e[1]} \xB7 ${e[2].slice(0,30)}`:t.length>60?t.slice(0,57)+"\u2026":t}function oi(t,e,a){let n=Date.now(),r=n-a*3600*1e3,o=t.prepare(`
8874
8874
  SELECT id, ts, source, project, subject, intent, raw_json
8875
8875
  FROM intent_events WHERE ts >= ? ORDER BY ts ASC
8876
- `).all(r),s=new Map,i=new Map;if(o.length>0){let w=o.map(L=>L.id),I=w.map((L,j)=>`@id${j}`).join(","),C=Object.fromEntries(w.map((L,j)=>[`id${j}`,L])),E=t.prepare(`
8876
+ `).all(r),s=new Map,i=new Map;if(o.length>0){let v=o.map(j=>j.id),A=v.map((j,$)=>`@id${$}`).join(","),R=Object.fromEntries(v.map((j,$)=>[`id${$}`,j])),_=t.prepare(`
8877
8877
  SELECT event_id, decided_at, decided_by, agent_id, outcome, reason
8878
- FROM intent_decisions WHERE event_id IN (${I}) ORDER BY decided_at ASC
8879
- `).all(C);for(let L of E)s.has(L.event_id)||s.set(L.event_id,[]),s.get(L.event_id).push(L);let $=t.prepare(`
8878
+ FROM intent_decisions WHERE event_id IN (${A}) ORDER BY decided_at ASC
8879
+ `).all(R);for(let j of _)s.has(j.event_id)||s.set(j.event_id,[]),s.get(j.event_id).push(j);let L=t.prepare(`
8880
8880
  SELECT decision_event_id, decision_decided_by, resolved_at, status, duration_ms, result_summary
8881
- FROM intent_resolutions WHERE decision_event_id IN (${I})
8882
- `).all(C);for(let L of $)i.set(`${L.decision_event_id}|${L.decision_decided_by}`,L)}let l=new Map,c=new Map,p=new Map,u=new Map,m=[],h=e?.business?.projects??[],_=e?.business?.contactMap??[],v=ha(e?.business??{}),S=e?.people??[];for(let w of o){let I=null;try{I=JSON.parse(w.raw_json)}catch{}let C=Ns(w.source,I,_),E=Ds(w.source,I),$=Is(I),L=w.project??Xt(I,w.subject,E),j=null,W=null;C?(j=C.client,W=C.project||`${C.client}/_chat`):L&&(j=gt(L,h),W=L);let q=iu(w.source,w.intent||"",I),G=Me[q]||{label:q,color:"#6b7280"};p.has(q)||p.set(q,{id:q,label:G.label,color:G.color});let ie=Rs({source:w.source,channel:q,raw:I,people:S,channelLabel:O=>Me[O]?.label??O}),Oe="__system",Z,z=cu(w.source,w.intent||"",I);if(z){Oe=z.id,Z=z.kind;let O=C?.displayName||z.name;(!u.has(z.id)||C?.displayName)&&u.set(z.id,{id:z.id,name:O,avatar:J(O),kind:z.kind})}else u.has("__system")||u.set("__system",{id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});for(let O of s.get(w.id)??[]){if(O.outcome!=="dispatched"||!O.agent_id)continue;let Ql=`${w.id}|${O.decided_by}`,it=i.get(Ql),gn=O.decided_at,xn=it?.resolved_at??null,ia=xn===null,Zl=it?.duration_ms??(ia?n-gn:0),ec=ia?"active":it?.status==="error"||it?.status==="fail"?"error":"completed",ee,Ke;if(j)ee=j,Ke=W;else{let la=v.get(O.agent_id);la?(ee=la,Ke=`${la}/_${w.source}`):(ee="unmapped",Ke=`unmapped/_${w.source}`)}l.has(ee)||l.set(ee,{id:ee,name:ee,color:Os(ee),projects:[]}),c.has(ee)||c.set(ee,new Set),c.get(ee).add(Ke),m.push({id:`${w.id}|${O.decided_by}`,agentId:O.agent_id,clientId:ee,projectId:Ke,channelId:q,initiatorId:Oe,initiatorKind:Z,subject:uu(w.subject),intent:w.intent||"",startedAt:gn,resolvedAt:xn,duration:Zl,active:ia,outcome:ec,tokens:0,inputPreview:E,system:lu(O.agent_id,e),...$,starter:ie})}}let g=[...l.values()].map(w=>({...w,projects:[...c.get(w.id)||[]].sort()})).sort((w,I)=>w.id.localeCompare(I.id)),d=[],f=new Set;if(e){let w=e.business??{},I=C=>{let E=w.orgChart?.[C]?.role,$=E?w.roles?.[E]?.title:void 0;return typeof $=="string"&&$.trim()?$.trim():void 0};for(let[C,E]of Object.entries(e.agents||{})){let $={id:C,name:E.name||C,tier:E.tier==="claude-code"?"lead":"worker",model:E.model||"",role:E.systemPrompt?E.systemPrompt.split(/[.\n]/)[0].slice(0,60):E.tier||"",title:I(C)};d.push($),f.add(C)}}for(let w of m)f.has(w.agentId)||(d.push({id:w.agentId,name:w.agentId,tier:"worker",model:"",role:""}),f.add(w.agentId));d.sort((w,I)=>w.id.localeCompare(I.id));let x=[],b=new Set;for(let[w,I]of Object.entries(Me))x.push({id:w,label:I.label,color:I.color}),b.add(w);for(let w of p.values())b.has(w.id)||x.push(w);let k=[...u.values()];k.find(w=>w.id==="__system")||k.push({id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});let T=e?.channels?.gitlab?.host;return{now:n,windowH:a,clients:g,agents:d,channels:x,initiators:k,dispatches:m,forges:{gitlab:typeof T=="string"?T:void 0,github:"https://github.com"}}}function Ua(t){let e=Fa();if(!e)return null;try{return Hs(e.db,zs(),t)}finally{e.close()}}function Bs(t){let e=new Map,a=new Map,n=new Map,r=new Map,o=[],s=0,i=0,l={};for(let{nodeId:c,snap:p}of t){l.gitlab??=p.forges?.gitlab,l.github??=p.forges?.github,p.now>s&&(s=p.now),p.windowH>i&&(i=p.windowH);for(let u of p.clients){let m=e.get(u.id);if(!m)e.set(u.id,{...u,projects:[...u.projects]});else{let h=Array.from(new Set([...m.projects,...u.projects])).sort();e.set(u.id,{...m,projects:h})}}for(let u of p.agents)a.has(u.id)||a.set(u.id,u);for(let u of p.channels)n.has(u.id)||n.set(u.id,u);for(let u of p.initiators)r.has(u.id)||r.set(u.id,u);for(let u of p.dispatches){let m=mu(u);if(m.clientId!==u.clientId&&!e.has(m.clientId)&&e.set(m.clientId,{id:m.clientId,name:m.clientId,color:Os(m.clientId),projects:[]}),m.projectId!==u.projectId){let h=e.get(m.clientId);h.projects.includes(m.projectId)||e.set(m.clientId,{...h,projects:[...h.projects,m.projectId].sort()})}o.push({...m,nodeId:c,id:`${c}::${m.id}`})}}return{now:s||Date.now(),windowH:i||6,localNodeId:t[0]?.nodeId,forges:l,clients:[...e.values()].sort((c,p)=>c.id.localeCompare(p.id)),agents:[...a.values()].sort((c,p)=>c.id.localeCompare(p.id)),channels:[...n.values()],initiators:[...r.values()],dispatches:o.sort((c,p)=>p.startedAt-c.startedAt)}}function mu(t){if(t.clientId!=="unmapped")return t;let e=Na(t.inputPreview);if(!e)return t;let a=xe?.business?.projects??[];return{...t,projectId:e,clientId:gt(e,a)}}async function Jt(t){let e=xe?.channels?.gitlab,a=await As(Ts(t.dispatches),{gitlab:e?.host&&e?.token?{host:e.host,token:e.token}:void 0,githubToken:process.env.GITHUB_TOKEN||void 0});return{...t,forge:a}}var xe=null;function zs(){return xe&&{...xe,people:Ye(xe.people)}}function qs(t){xe=t}async function Fs(t,e,a){if(a!=="/api/admin/activity-graph"&&!a.startsWith("/api/admin/activity-graph?"))return!1;let n=Fa();if(!n)return ge(e,503,{error:"intent ledger not available",clients:[],agents:[],channels:[],initiators:[],dispatches:[]}),!0;try{let r=new URL(t.url||"/","http://_"),o=Us(parseInt(r.searchParams.get("hours")||"6",10));ge(e,200,await Jt(Hs(n.db,zs(),o)))}catch(r){ge(e,500,{error:r?.message??String(r)})}finally{n.close()}return!0}var fu=5e3;async function Wa(t,e,a,n=Ua){if(a!=="/api/admin/activity-graph/stream"&&!a.startsWith("/api/admin/activity-graph/stream?"))return!1;e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`: connected
8881
+ FROM intent_resolutions WHERE decision_event_id IN (${A})
8882
+ `).all(R);for(let j of L)i.set(`${j.decision_event_id}|${j.decision_decided_by}`,j)}let l=new Map,c=new Map,d=new Map,p=new Map,m=[],f=e?.business?.projects??[],S=e?.business?.contactMap??[],b=ya(e?.business??{}),E=e?.people??[];for(let v of o){let A=null;try{A=JSON.parse(v.raw_json)}catch{}let R=ni(v.source,A,S),_=ri(v.source,A),L=Js(A),j=v.project??Yt(A,v.subject,_),$=null,O=null;R?($=R.client,O=R.project||`${R.client}/_chat`):j&&($=yt(j,f),O=j);let U=Vu(v.source,v.intent||"",A),ce=je[U]||{label:U,color:"#6b7280"};d.has(U)||d.set(U,{id:U,label:ce.label,color:ce.color});let Z=Qs({source:v.source,channel:U,raw:A,people:E,channelLabel:N=>je[N]?.label??N}),oe="__system",ee,F=Qu(v.source,v.intent||"",A);if(F){oe=F.id,ee=F.kind;let N=R?.displayName||F.name;(!p.has(F.id)||R?.displayName)&&p.set(F.id,{id:F.id,name:N,avatar:J(N),kind:F.kind})}else p.has("__system")||p.set("__system",{id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});for(let N of s.get(v.id)??[]){if(N.outcome!=="dispatched"||!N.agent_id)continue;let Bc=`${v.id}|${N.decided_by}`,pt=i.get(Bc),Tn=N.decided_at,An=pt?.resolved_at??null,pa=An===null,zc=pt?.duration_ms??(pa?n-Tn:0),qc=pa?"active":pt?.status==="error"||pt?.status==="fail"?"error":"completed",te,Ze;if($)te=$,Ze=O;else{let ua=b.get(N.agent_id);ua?(te=ua,Ze=`${ua}/_${v.source}`):(te="unmapped",Ze=`unmapped/_${v.source}`)}l.has(te)||l.set(te,{id:te,name:te,color:ai(te),projects:[]}),c.has(te)||c.set(te,new Set),c.get(te).add(Ze),m.push({id:`${v.id}|${N.decided_by}`,agentId:N.agent_id,clientId:te,projectId:Ze,channelId:U,initiatorId:oe,initiatorKind:ee,subject:tm(v.subject),intent:v.intent||"",startedAt:Tn,resolvedAt:An,duration:zc,active:pa,outcome:qc,tokens:0,inputPreview:_,system:Yu(N.agent_id,e),...L,starter:Z})}}let g=[...l.values()].map(v=>({...v,projects:[...c.get(v.id)||[]].sort()})).sort((v,A)=>v.id.localeCompare(A.id)),x=[],u=new Set;if(e){let v=e.business??{},A=R=>{let _=v.orgChart?.[R]?.role,L=_?v.roles?.[_]?.title:void 0;return typeof L=="string"&&L.trim()?L.trim():void 0};for(let[R,_]of Object.entries(e.agents||{})){let L={id:R,name:_.name||R,tier:_.tier==="claude-code"?"lead":"worker",model:_.model||"",role:_.systemPrompt?_.systemPrompt.split(/[.\n]/)[0].slice(0,60):_.tier||"",title:A(R)};x.push(L),u.add(R)}}for(let v of m)u.has(v.agentId)||(x.push({id:v.agentId,name:v.agentId,tier:"worker",model:"",role:""}),u.add(v.agentId));x.sort((v,A)=>v.id.localeCompare(A.id));let h=[],w=new Set;for(let[v,A]of Object.entries(je))h.push({id:v,label:A.label,color:A.color}),w.add(v);for(let v of d.values())w.has(v.id)||h.push(v);let y=[...p.values()];y.find(v=>v.id==="__system")||y.push({id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});let T=e?.channels?.gitlab?.host;return{now:n,windowH:a,clients:g,agents:x,channels:h,initiators:y,dispatches:m,forges:{gitlab:typeof T=="string"?T:void 0,github:"https://github.com"}}}function Za(t){let e=Qa();if(!e)return null;try{return oi(e.db,ii(),t)}finally{e.close()}}function si(t){let e=new Map,a=new Map,n=new Map,r=new Map,o=[],s=0,i=0,l={};for(let{nodeId:c,snap:d}of t){l.gitlab??=d.forges?.gitlab,l.github??=d.forges?.github,d.now>s&&(s=d.now),d.windowH>i&&(i=d.windowH);for(let p of d.clients){let m=e.get(p.id);if(!m)e.set(p.id,{...p,projects:[...p.projects]});else{let f=Array.from(new Set([...m.projects,...p.projects])).sort();e.set(p.id,{...m,projects:f})}}for(let p of d.agents)a.has(p.id)||a.set(p.id,p);for(let p of d.channels)n.has(p.id)||n.set(p.id,p);for(let p of d.initiators)r.has(p.id)||r.set(p.id,p);for(let p of d.dispatches){let m=am(p);if(m.clientId!==p.clientId&&!e.has(m.clientId)&&e.set(m.clientId,{id:m.clientId,name:m.clientId,color:ai(m.clientId),projects:[]}),m.projectId!==p.projectId){let f=e.get(m.clientId);f.projects.includes(m.projectId)||e.set(m.clientId,{...f,projects:[...f.projects,m.projectId].sort()})}o.push({...m,nodeId:c,id:`${c}::${m.id}`})}}return{now:s||Date.now(),windowH:i||6,localNodeId:t[0]?.nodeId,forges:l,clients:[...e.values()].sort((c,d)=>c.id.localeCompare(d.id)),agents:[...a.values()].sort((c,d)=>c.id.localeCompare(d.id)),channels:[...n.values()],initiators:[...r.values()],dispatches:o.sort((c,d)=>d.startedAt-c.startedAt)}}function am(t){if(t.clientId!=="unmapped")return t;let e=Ga(t.inputPreview);if(!e)return t;let a=we?.business?.projects??[];return{...t,projectId:e,clientId:yt(e,a)}}async function Zt(t){let e=we?.channels?.gitlab,a=await Xs(Gs(t.dispatches),{gitlab:e?.host&&e?.token?{host:e.host,token:e.token}:void 0,githubToken:process.env.GITHUB_TOKEN||void 0});return{...t,forge:a}}var we=null;function ii(){return we&&{...we,people:at(we.people)}}function li(t){we=t}async function ci(t,e,a){if(a!=="/api/admin/activity-graph"&&!a.startsWith("/api/admin/activity-graph?"))return!1;let n=Qa();if(!n)return ye(e,503,{error:"intent ledger not available",clients:[],agents:[],channels:[],initiators:[],dispatches:[]}),!0;try{let r=new URL(t.url||"/","http://_"),o=di(parseInt(r.searchParams.get("hours")||"6",10));ye(e,200,await Zt(oi(n.db,ii(),o)))}catch(r){ye(e,500,{error:r?.message??String(r)})}finally{n.close()}return!0}var nm=5e3;async function en(t,e,a,n=Za){if(a!=="/api/admin/activity-graph/stream"&&!a.startsWith("/api/admin/activity-graph/stream?"))return!1;e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`: connected
8883
8883
 
8884
- `);let r=new URL(t.url||"/","http://_"),o=Us(parseInt(r.searchParams.get("hours")||"6",10)),s=!1,i=()=>{s=!0};t.on("close",i),t.on("error",i),e.on("close",i),e.on("error",i);let l=setInterval(()=>{if(!s)try{e.write(`: hb
8884
+ `);let r=new URL(t.url||"/","http://_"),o=di(parseInt(r.searchParams.get("hours")||"6",10)),s=!1,i=()=>{s=!0};t.on("close",i),t.on("error",i),e.on("close",i),e.on("error",i);let l=setInterval(()=>{if(!s)try{e.write(`: hb
8885
8885
 
8886
- `)}catch{i()}},25e3);try{for(;!s;){try{let p=await n(o),u=p&&await Jt(p);if(s)break;u?(e.write(`event: snapshot
8887
- `),e.write(`data: ${JSON.stringify(u)}
8886
+ `)}catch{i()}},25e3);try{for(;!s;){try{let d=await n(o),p=d&&await Zt(d);if(s)break;p?(e.write(`event: snapshot
8887
+ `),e.write(`data: ${JSON.stringify(p)}
8888
8888
 
8889
8889
  `)):e.write(`event: error
8890
8890
  data: ${JSON.stringify({error:"ledger not available"})}
8891
8891
 
8892
- `)}catch(p){e.write(`event: error
8893
- data: ${JSON.stringify({error:p?.message??String(p)})}
8892
+ `)}catch(d){e.write(`event: error
8893
+ data: ${JSON.stringify({error:d?.message??String(d)})}
8894
8894
 
8895
- `)}let c=Date.now();for(;!s&&Date.now()-c<fu;)await new Promise(p=>setTimeout(p,200))}}finally{clearInterval(l);try{e.end()}catch{}}return!0}function Us(t){return!Number.isFinite(t)||t<1?6:Math.min(720,Math.max(1,t))}function hu(t,e,a=5e3){let n=new Date(e).toISOString().slice(0,10),r=za(process.cwd(),".agentx/task-history",t,n);if(!qa(r)){let o=new Date(e-864e5).toISOString().slice(0,10),s=za(process.cwd(),".agentx/task-history",t,o);return qa(s)?js(s,e,a):null}return js(r,e,a)}function js(t,e,a){let n=null,r=1/0;for(let o of ru(t)){if(!o.endsWith(".json"))continue;let s;try{s=JSON.parse(ou(nu(t,o),"utf-8"))}catch{continue}let i=s.startedAt,l;if(typeof i=="number")l=i;else if(typeof i=="string"){let p=Date.parse(i);if(!Number.isFinite(p))continue;l=p}else continue;let c=Math.abs(l-e);c<r&&c<=a&&(n=s,r=c)}return n}async function Ws(t,e,a){let n=a.match(/^\/api\/admin\/activity-graph\/dispatch\/([^/?]+)(?:\?.*)?$/);if(!n)return!1;let r=decodeURIComponent(n[1]),o=r.indexOf("|");if(o<0)return ge(e,400,{error:"invalid dispatch id"}),!0;let s=r.slice(0,o),i=r.slice(o+1),l=Fa();if(!l)return ge(e,503,{error:"ledger not available"}),!0;try{let c=l.db.prepare("SELECT id, ts, source, project, subject, intent, raw_json FROM intent_events WHERE id = ?").get(s);if(!c)return ge(e,404,{error:"event not found"}),!0;let p=l.db.prepare("SELECT decided_at, decided_by, agent_id, outcome, reason FROM intent_decisions WHERE event_id = ? AND decided_by = ?").get(s,i);if(!p)return ge(e,404,{error:"decision not found"}),!0;let u=l.db.prepare("SELECT resolved_at, status, duration_ms, result_summary FROM intent_resolutions WHERE decision_event_id = ? AND decision_decided_by = ?").get(s,i),m=null;try{m=JSON.parse(c.raw_json)}catch{}let h=Ds(c.source,m),_=m&&typeof m=="object"&&(m.text||m.message?.text||m.message?.caption||m.object_attributes?.note||m.object_attributes?.description||m.comment?.body||m.issue?.body||(typeof m.message=="string"?m.message:null)||(typeof m.prompt=="string"?m.prompt:null)||null)||h,v=null,S=null;if(p.agent_id){let k=hu(p.agent_id,p.decided_at);if(k){typeof k.responseText=="string"&&(v=k.responseText);let T=k.transcript;Array.isArray(T)&&(S=T.length)}}let g=xe?.business?.projects??[],d=xe?.business?.contactMap??[],f=ha(xe?.business??{}),x={client:"unmapped",project:`unmapped/_${c.source}`,via:"fallback"},b=Ns(c.source,m,d);if(b)x={client:b.client,project:b.project||`${b.client}/_chat`,via:`contactMap (channel=${b.channel??"*"}${b.username?` username=${b.username}`:""}${b.chatId?` chatId=${b.chatId}`:""})`};else if(c.project||Xt(m,c.subject,h)){let k=c.project||Xt(m,c.subject,h);x={client:gt(k,g),project:k,via:c.project?`project namespace prefix (${k})`:`forge path in chat id / message (${k})`}}else if(p.agent_id){let k=f.get(p.agent_id);k&&(x={client:k,project:`${k}/_${c.source}`,via:`orgChart fallback (agent ${p.agent_id} reports up to a PM whose project belongs to ${k})`})}ge(e,200,{id:r,eventId:s,source:c.source,subject:c.subject,intent:c.intent,project:c.project,decidedBy:p.decided_by,agentId:p.agent_id,outcome:p.outcome,reason:p.reason,startedAt:p.decided_at,resolvedAt:u?.resolved_at??null,durationMs:u?.duration_ms??null,input:_,response:v,transcriptLen:S,resolutionStatus:u?.status??null,resultSummary:u?.result_summary??null,attribution:x})}catch(c){ge(e,500,{error:c?.message??String(c)})}finally{l.close()}return!0}import{existsSync as bu,readFileSync as yu}from"fs";import{resolve as Xs}from"path";ut();function Gs(t){let e=t.agentId,a=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",n=`<script>window.AGENT_ID = ${JSON.stringify(e)};</script>`,r=gu.replace(/__AGENT_ID__/g,N(e));return M({title:`AgentX \xB7 ${N(e)}`,activeTab:"admin",subtitle:`Agent \xB7 ${N(e)}`,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:r,css:xu,headExtras:'<link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css">',scripts:`${n}${a}<script src="https://unpkg.com/easymde/dist/easymde.min.js"></script><script>${vu}</script>`})}var gu=`
8895
+ `)}let c=Date.now();for(;!s&&Date.now()-c<nm;)await new Promise(d=>setTimeout(d,200))}}finally{clearInterval(l);try{e.end()}catch{}}return!0}function di(t){return!Number.isFinite(t)||t<1?6:Math.min(720,Math.max(1,t))}function rm(t,e,a=5e3){let n=new Date(e).toISOString().slice(0,10),r=Va(process.cwd(),".agentx/task-history",t,n);if(!Ya(r)){let o=new Date(e-864e5).toISOString().slice(0,10),s=Va(process.cwd(),".agentx/task-history",t,o);return Ya(s)?ti(s,e,a):null}return ti(r,e,a)}function ti(t,e,a){let n=null,r=1/0;for(let o of Xu(t)){if(!o.endsWith(".json"))continue;let s;try{s=JSON.parse(Ku(Gu(t,o),"utf-8"))}catch{continue}let i=s.startedAt,l;if(typeof i=="number")l=i;else if(typeof i=="string"){let d=Date.parse(i);if(!Number.isFinite(d))continue;l=d}else continue;let c=Math.abs(l-e);c<r&&c<=a&&(n=s,r=c)}return n}async function pi(t,e,a){let n=a.match(/^\/api\/admin\/activity-graph\/dispatch\/([^/?]+)(?:\?.*)?$/);if(!n)return!1;let r=decodeURIComponent(n[1]),o=r.indexOf("|");if(o<0)return ye(e,400,{error:"invalid dispatch id"}),!0;let s=r.slice(0,o),i=r.slice(o+1),l=Qa();if(!l)return ye(e,503,{error:"ledger not available"}),!0;try{let c=l.db.prepare("SELECT id, ts, source, project, subject, intent, raw_json FROM intent_events WHERE id = ?").get(s);if(!c)return ye(e,404,{error:"event not found"}),!0;let d=l.db.prepare("SELECT decided_at, decided_by, agent_id, outcome, reason FROM intent_decisions WHERE event_id = ? AND decided_by = ?").get(s,i);if(!d)return ye(e,404,{error:"decision not found"}),!0;let p=l.db.prepare("SELECT resolved_at, status, duration_ms, result_summary FROM intent_resolutions WHERE decision_event_id = ? AND decision_decided_by = ?").get(s,i),m=null;try{m=JSON.parse(c.raw_json)}catch{}let f=ri(c.source,m),S=m&&typeof m=="object"&&(m.text||m.message?.text||m.message?.caption||m.object_attributes?.note||m.object_attributes?.description||m.comment?.body||m.issue?.body||(typeof m.message=="string"?m.message:null)||(typeof m.prompt=="string"?m.prompt:null)||null)||f,b=null,E=null;if(d.agent_id){let y=rm(d.agent_id,d.decided_at);if(y){typeof y.responseText=="string"&&(b=y.responseText);let T=y.transcript;Array.isArray(T)&&(E=T.length)}}let g=we?.business?.projects??[],x=we?.business?.contactMap??[],u=ya(we?.business??{}),h={client:"unmapped",project:`unmapped/_${c.source}`,via:"fallback"},w=ni(c.source,m,x);if(w)h={client:w.client,project:w.project||`${w.client}/_chat`,via:`contactMap (channel=${w.channel??"*"}${w.username?` username=${w.username}`:""}${w.chatId?` chatId=${w.chatId}`:""})`};else if(c.project||Yt(m,c.subject,f)){let y=c.project||Yt(m,c.subject,f);h={client:yt(y,g),project:y,via:c.project?`project namespace prefix (${y})`:`forge path in chat id / message (${y})`}}else if(d.agent_id){let y=u.get(d.agent_id);y&&(h={client:y,project:`${y}/_${c.source}`,via:`orgChart fallback (agent ${d.agent_id} reports up to a PM whose project belongs to ${y})`})}ye(e,200,{id:r,eventId:s,source:c.source,subject:c.subject,intent:c.intent,project:c.project,decidedBy:d.decided_by,agentId:d.agent_id,outcome:d.outcome,reason:d.reason,startedAt:d.decided_at,resolvedAt:p?.resolved_at??null,durationMs:p?.duration_ms??null,input:S,response:b,transcriptLen:E,resolutionStatus:p?.status??null,resultSummary:p?.result_summary??null,attribution:h})}catch(c){ye(e,500,{error:c?.message??String(c)})}finally{l.close()}return!0}import{existsSync as lm,readFileSync as cm}from"fs";import{resolve as mi}from"path";gt();function ui(t){let e=t.agentId,a=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",n=`<script>window.AGENT_ID = ${JSON.stringify(e)};</script>`,r=om.replace(/__AGENT_ID__/g,H(e));return I({title:`AgentX \xB7 ${H(e)}`,activeTab:"admin",subtitle:`Agent \xB7 ${H(e)}`,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:r,css:sm,headExtras:'<link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css">',scripts:`${n}${a}<script src="https://unpkg.com/easymde/dist/easymde.min.js"></script><script>${im}</script>`})}var om=`
8896
8896
  <!-- Breadcrumb -->
8897
8897
  <div class="ax-crumb">
8898
8898
  <a href="/admin">Settings</a>
@@ -9481,7 +9481,7 @@ data: ${JSON.stringify({error:p?.message??String(p)})}
9481
9481
  </div>
9482
9482
  </div>
9483
9483
  </div>
9484
- `,xu=`
9484
+ `,sm=`
9485
9485
  /* Agent-specific layout + legacy styles for bits the migration left in
9486
9486
  * place (EasyMDE theming, skills tree, plain-editor). Shared chrome + tab
9487
9487
  * primitives live in components.css.ts. */
@@ -9600,7 +9600,7 @@ textarea.inp.mono { font-family: var(--ax-mono); }
9600
9600
 
9601
9601
  /* Agent-specific button variant used in rail context (no ax-btn wrapper) */
9602
9602
  .ax-btn.lg { padding: 9px 16px; font-size: 13px; }
9603
- `,vu=`
9603
+ `,im=`
9604
9604
  const $ = (id) => document.getElementById(id);
9605
9605
  const state = { agent: null, activeSkill: null, activeSkillFile: null, identityPath: null };
9606
9606
 
@@ -10456,15 +10456,15 @@ document.addEventListener('keydown', (e) => {
10456
10456
  /* ===== Boot ===== */
10457
10457
  initOptsToggles();
10458
10458
  loadAgent();
10459
- `;function Ks(t,e,a,n=[],r){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Gs({agentId:a,peers:n,localToken:r}))}async function Js(t,e,a){try{let n=t.method==="GET"?void 0:await qu(t),r=new URL(t.url||"/","http://localhost"),o=Object.fromEntries(r.searchParams),s=a.match(/^\/api\/admin\/agent\/([a-z0-9][a-z0-9_-]*)(?:\/(.+))?$/);if(!s){Vt(e,404,{error:`unknown agent endpoint: ${a}`});return}let i=s[1],l=s[2]||"",c=`${t.method} ${l}`,u={"GET ":()=>et(i),"PATCH ":()=>wu(i,n),"PATCH capability":()=>Su(i,n),"POST mcp":()=>ku(i,n),"DELETE mcp":()=>_u(i,n),"GET identity":()=>Eu(i),"GET identity/file":()=>Tu(i,String(o.path||"")),"PUT identity/file":()=>Au(i,n),"GET skills":()=>Cu(i),"POST skills":()=>Iu(i,n),"DELETE skills":()=>Mu(i,n),"GET skills/tree":()=>Lu(i,String(o.slug||"")),"GET skills/file":()=>Ru(i,String(o.slug||""),String(o.path||"")),"PUT skills/file":()=>$u(i,n),"GET skills/deps":()=>Pu(i,String(o.slug||"")),"POST skills/install":()=>ju(i,n,t),"POST skills/deps":()=>Ou(i,n,t),"GET channels":()=>Nu(i),"GET activity":()=>Du(i,t),"GET handovers":()=>Hu(i),"POST handovers":()=>Bu(i,n),"DELETE handovers":()=>zu(n)}[c];if(!u){Vt(e,404,{error:`unknown agent sub-endpoint: ${c}`});return}let m=await u();Vt(e,200,m)}catch(n){Vt(e,400,{error:n?.message||"agent op failed"})}}function Vs(){let t=Xs(process.cwd(),"agentx.json");return bu(t)?JSON.parse(yu(t,"utf-8")):null}function V(t){let e=Vs();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 et(t){let{def:e,cfg:a}=V(t),n=e.workspace?De(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",intents:Array.isArray(e.intents)?e.intents:[],maxDelegationDepth:e.maxDelegationDepth??5,contextReferences:!!e.contextReferences,contextStrategy:e.contextStrategy||"",mcp:e.mcp&&typeof e.mcp=="object"?e.mcp:{},overview:n,defaultWorker:a.node?.defaultAgent,draftAgent:a.dashboard?.draftAgent}}function wu(t,e){let a={};for(let r of["name","tier","model","systemPrompt","mentions","access","maxConcurrent","maxExecutionMinutes","permissionMode"])e?.[r]!==void 0&&(a[r]=e[r]);let{summary:n}=A(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);return r.agents[t]={...r.agents[t],...a},`agent "${t}" updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:et(t)}}function ku(t,e){let a=String(e?.name||"").trim(),n=String(e?.command||"").trim();if(!a)throw new Error("name required");if(!/^[a-zA-Z0-9_-]+$/.test(a))throw new Error("name must be identifier-safe (alnum, _, -)");if(!n)throw new Error("command required");let r=Array.isArray(e?.args)?e.args.map(i=>String(i)):[],o;if(e?.env&&typeof e.env=="object"){o={};for(let[i,l]of Object.entries(e.env))typeof l=="string"&&(o[i]=l);Object.keys(o).length===0&&(o=void 0)}let{summary:s}=A(i=>{if(!i.agents?.[t])throw new Error(`Agent "${t}" not found`);return i.agents[t].mcp=i.agents[t].mcp||{},i.agents[t].mcp[a]={command:n,args:r,...o?{env:o}:{}},`agent "${t}" mcp.${a} upserted`});return{summary:s,agent:et(t)}}function _u(t,e){let a=String(e?.name||"").trim();if(!a)throw new Error("name required");let{summary:n}=A(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);if(!r.agents[t].mcp||!(a in r.agents[t].mcp))throw new Error(`no mcp.${a} on "${t}"`);return delete r.agents[t].mcp[a],Object.keys(r.agents[t].mcp).length===0&&delete r.agents[t].mcp,`agent "${t}" mcp.${a} removed`});return{summary:n,agent:et(t)}}function Su(t,e){let a={};if(Array.isArray(e?.intents)&&(a.intents=e.intents.map(r=>String(r)).filter(Boolean)),e?.maxDelegationDepth!==void 0){let r=Number(e.maxDelegationDepth);if(!Number.isFinite(r)||r<0||r>50)throw new Error("maxDelegationDepth must be 0..50");a.maxDelegationDepth=r}if(e?.contextReferences!==void 0&&(a.contextReferences=!!e.contextReferences),e?.contextStrategy!==void 0){if(e.contextStrategy&&!["layered","planner"].includes(e.contextStrategy))throw new Error("contextStrategy must be layered|planner|empty");e.contextStrategy?a.contextStrategy=e.contextStrategy:a.contextStrategy=void 0}if(e?.maxExecutionMinutes!==void 0){let r=Number(e.maxExecutionMinutes);if(!Number.isFinite(r)||r<1||r>240)throw new Error("maxExecutionMinutes must be 1..240");a.maxExecutionMinutes=r}if(Object.keys(a).length===0)throw new Error("nothing to update");let{summary:n}=A(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);let o={...r.agents[t]};for(let[s,i]of Object.entries(a))i===void 0?delete o[s]:o[s]=i;return r.agents[t]=o,`agent "${t}" capability updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:et(t)}}function Eu(t){let{def:e}=V(t);return De(e.workspace)}function Tu(t,e){if(!e)throw new Error("path query param required");let{def:a}=V(t);return Et(a.workspace,e)}function Au(t,e){let a=String(e?.path||"");if(!a)throw new Error("path required");let{def:n}=V(t);return Tt(n.workspace,a,String(e?.content??""))}function Cu(t){let{def:e}=V(t),a=De(e.workspace);return{skills:a.skills,workspace:a.workspace}}function Iu(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=V(t);return At(n.workspace,a,{title:e?.title,content:e?.content})}function Mu(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=V(t);return Ct(n.workspace,a)}function Lu(t,e){if(!e)throw new Error("slug query param required");let{def:a}=V(t),n=ur(a.workspace,e),r=It(a.workspace,e);return{slug:e,tree:n,deps:r}}function Ru(t,e,a){if(!e||!a)throw new Error("slug and path query params required");let{def:n}=V(t);return mr(n.workspace,e,a)}function $u(t,e){let a=String(e?.slug||""),n=String(e?.path||"");if(!a||!n)throw new Error("slug and path required");let{def:r}=V(t);return fr(r.workspace,a,n,String(e?.content??""))}function Pu(t,e){if(!e)throw new Error("slug query param required");let{def:a}=V(t);return It(a.workspace,e)}async function ju(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 r=Ys(e?.worker),{def:o}=V(t),s=[`Install the skills.sh package "${n}" into agent "${t}".`,`Workspace: ${o.workspace}`,`Run: cd ${o.workspace} && npx -y skills add ${n}`,`If that fails, fall back to: agentx skill install ${n}`,`Skills should land under ${o.workspace}/.claude/skills/. Report what was installed and any errors.`].join(`
10460
- `);return Qs(a,r,s,`install-${n}:${Date.now()}`)}async function Ou(t,e,a){let n=String(e?.slug||"").trim();if(!n)throw new Error("slug required");let r=Ys(e?.worker),{def:o}=V(t),s=It(o.workspace,n);if(!s.manager)throw new Error(`No dependency manifest detected in .claude/skills/${n}. Expected one of: package.json, requirements.txt, Gemfile.`);let i=Xs(o.workspace,".claude","skills",n),l=[`Install dependencies for skill "${n}" in agent "${t}".`,`cd to: ${i}`,`Detected manifest: ${s.file}`,`Run: ${s.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(`
10461
- `);return Qs(a,r,l,`deps-${t}-${n}:${Date.now()}`)}function Ys(t){if(t&&typeof t=="string")return t;let e=X();return e.dashboard?.draftAgent||e.node?.defaultAgent||Object.keys(e.agents).find(a=>a.includes("devops"))||Object.keys(e.agents)[0]}async function Qs(t,e,a,n){let r=X(),o=(r.dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),s={"Content-Type":"application/json"},i=t.headers.authorization;i?s.Authorization=String(i):r.dashboard.token&&(s.Authorization=`Bearer ${r.dashboard.token}`);let l=await fetch(`${o}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"admin",sender:"admin-ui",chatId:n}})}),c=await l.text(),p;try{p=JSON.parse(c)}catch{p={content:c}}if(!l.ok)throw new Error(p?.error||`daemon /task HTTP ${l.status}`);return{worker:e,taskId:p?.taskId,content:p?.content,duration:p?.duration,error:p?.error}}function Nu(t){let e=Vs(),a=[],n=e?.channels?.telegram?.accounts||{};for(let[o,s]of Object.entries(n))s?.agentBinding===t&&a.push({channel:"telegram",account:o,detail:s?.botUsername||o});e?.channels?.slack?.agentBinding===t&&a.push({channel:"slack",detail:"bound"}),e?.channels?.discord?.agentBinding===t&&a.push({channel:"discord",detail:"bound"});let r=e?.channels?.gitlab?.agentMappings||[];for(let o of r)o?.agentId===t&&a.push({channel:"gitlab",detail:(o?.gitlabUsernames||[]).join(", ")||"mapped"});return{bindings:a}}async function Du(t,e){try{let n=(X().dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),r=await fetch(`${n}/agents`);if(!r.ok)throw new Error(`daemon HTTP ${r.status}`);let s=(await r.json()).find(i=>i.id===t);return{activeTasks:s?.activeTasks??0,totalTasks:s?.totalTasks??0,errors:s?.errors??0,lastActive:s?.lastActive??null,runningTasks:s?.runningTasks??[],lastSummary:s?.lastSummary??null}}catch(a){return{error:a?.message,activeTasks:0,totalTasks:0,errors:0,runningTasks:[]}}}function Ga(){return new Mn}function Hu(t){let e=Ga(),{incoming:a,outgoing:n}=e.listByAgent(t);return{incoming:a,outgoing:n}}function Bu(t,e){let a=String(e?.channel||"").trim(),n=String(e?.chatId||"").trim(),r=String(e?.toAgent||"").trim();if(!a||!n||!r)throw new Error("channel, chatId, toAgent required");let o=String(e?.fromAgent||t||"").trim()||t,s=e?.accountId?String(e.accountId):void 0,i=e?.summary?String(e.summary):void 0,l=e?.expiresAt?String(e.expiresAt):void 0,c=Ga().set({channel:a,chatId:n,accountId:s,fromAgent:o,toAgent:r,summary:i,expiresAt:l,createdBy:"admin-ui"});return{summary:`Handed off ${a}:${n} from ${o} to ${r}`,record:c}}function zu(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:Ga().remove(e,a,n)?"Released":"No active handover for that chat"}}function Vt(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function qu(t){return new Promise((e,a)=>{let n="";t.on("data",r=>{n+=r}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(r){a(r)}}),t.on("error",a)})}var Le={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","codex-cli":"Codex CLI",opencode:"OpenCode",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 Zs=[{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, Codex CLI, Anthropic Agent SDK, or AgentX's provider-agnostic orchestrator."},{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."}];function Xa(t={}){let e=`<script>window.UI_LABELS = ${JSON.stringify(Le)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
10459
+ `;function fi(t,e,a,n=[],r){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ui({agentId:a,peers:n,localToken:r}))}async function hi(t,e,a){try{let n=t.method==="GET"?void 0:await Lm(t),r=new URL(t.url||"/","http://localhost"),o=Object.fromEntries(r.searchParams),s=a.match(/^\/api\/admin\/agent\/([a-z0-9][a-z0-9_-]*)(?:\/(.+))?$/);if(!s){ea(e,404,{error:`unknown agent endpoint: ${a}`});return}let i=s[1],l=s[2]||"",c=`${t.method} ${l}`,p={"GET ":()=>ot(i),"PATCH ":()=>dm(i,n),"PATCH capability":()=>mm(i,n),"POST mcp":()=>pm(i,n),"DELETE mcp":()=>um(i,n),"GET identity":()=>fm(i),"GET identity/file":()=>hm(i,String(o.path||"")),"PUT identity/file":()=>gm(i,n),"GET skills":()=>xm(i),"POST skills":()=>bm(i,n),"DELETE skills":()=>vm(i,n),"GET skills/tree":()=>ym(i,String(o.slug||"")),"GET skills/file":()=>wm(i,String(o.slug||""),String(o.path||"")),"PUT skills/file":()=>km(i,n),"GET skills/deps":()=>_m(i,String(o.slug||"")),"POST skills/install":()=>Sm(i,n,t),"POST skills/deps":()=>Em(i,n,t),"GET channels":()=>Tm(i),"GET activity":()=>Am(i,t),"GET handovers":()=>Cm(i),"POST handovers":()=>Im(i,n),"DELETE handovers":()=>Mm(n)}[c];if(!p){ea(e,404,{error:`unknown agent sub-endpoint: ${c}`});return}let m=await p();ea(e,200,m)}catch(n){ea(e,400,{error:n?.message||"agent op failed"})}}function gi(){let t=mi(process.cwd(),"agentx.json");return lm(t)?JSON.parse(cm(t,"utf-8")):null}function V(t){let e=gi();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 ot(t){let{def:e,cfg:a}=V(t),n=e.workspace?qe(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",intents:Array.isArray(e.intents)?e.intents:[],maxDelegationDepth:e.maxDelegationDepth??5,contextReferences:!!e.contextReferences,contextStrategy:e.contextStrategy||"",mcp:e.mcp&&typeof e.mcp=="object"?e.mcp:{},overview:n,defaultWorker:a.node?.defaultAgent,draftAgent:a.dashboard?.draftAgent}}function dm(t,e){let a={};for(let r of["name","tier","model","systemPrompt","mentions","access","maxConcurrent","maxExecutionMinutes","permissionMode"])e?.[r]!==void 0&&(a[r]=e[r]);let{summary:n}=C(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);return r.agents[t]={...r.agents[t],...a},`agent "${t}" updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:ot(t)}}function pm(t,e){let a=String(e?.name||"").trim(),n=String(e?.command||"").trim();if(!a)throw new Error("name required");if(!/^[a-zA-Z0-9_-]+$/.test(a))throw new Error("name must be identifier-safe (alnum, _, -)");if(!n)throw new Error("command required");let r=Array.isArray(e?.args)?e.args.map(i=>String(i)):[],o;if(e?.env&&typeof e.env=="object"){o={};for(let[i,l]of Object.entries(e.env))typeof l=="string"&&(o[i]=l);Object.keys(o).length===0&&(o=void 0)}let{summary:s}=C(i=>{if(!i.agents?.[t])throw new Error(`Agent "${t}" not found`);return i.agents[t].mcp=i.agents[t].mcp||{},i.agents[t].mcp[a]={command:n,args:r,...o?{env:o}:{}},`agent "${t}" mcp.${a} upserted`});return{summary:s,agent:ot(t)}}function um(t,e){let a=String(e?.name||"").trim();if(!a)throw new Error("name required");let{summary:n}=C(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);if(!r.agents[t].mcp||!(a in r.agents[t].mcp))throw new Error(`no mcp.${a} on "${t}"`);return delete r.agents[t].mcp[a],Object.keys(r.agents[t].mcp).length===0&&delete r.agents[t].mcp,`agent "${t}" mcp.${a} removed`});return{summary:n,agent:ot(t)}}function mm(t,e){let a={};if(Array.isArray(e?.intents)&&(a.intents=e.intents.map(r=>String(r)).filter(Boolean)),e?.maxDelegationDepth!==void 0){let r=Number(e.maxDelegationDepth);if(!Number.isFinite(r)||r<0||r>50)throw new Error("maxDelegationDepth must be 0..50");a.maxDelegationDepth=r}if(e?.contextReferences!==void 0&&(a.contextReferences=!!e.contextReferences),e?.contextStrategy!==void 0){if(e.contextStrategy&&!["layered","planner"].includes(e.contextStrategy))throw new Error("contextStrategy must be layered|planner|empty");e.contextStrategy?a.contextStrategy=e.contextStrategy:a.contextStrategy=void 0}if(e?.maxExecutionMinutes!==void 0){let r=Number(e.maxExecutionMinutes);if(!Number.isFinite(r)||r<1||r>240)throw new Error("maxExecutionMinutes must be 1..240");a.maxExecutionMinutes=r}if(Object.keys(a).length===0)throw new Error("nothing to update");let{summary:n}=C(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);let o={...r.agents[t]};for(let[s,i]of Object.entries(a))i===void 0?delete o[s]:o[s]=i;return r.agents[t]=o,`agent "${t}" capability updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:ot(t)}}function fm(t){let{def:e}=V(t);return qe(e.workspace)}function hm(t,e){if(!e)throw new Error("path query param required");let{def:a}=V(t);return Ct(a.workspace,e)}function gm(t,e){let a=String(e?.path||"");if(!a)throw new Error("path required");let{def:n}=V(t);return It(n.workspace,a,String(e?.content??""))}function xm(t){let{def:e}=V(t),a=qe(e.workspace);return{skills:a.skills,workspace:a.workspace}}function bm(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=V(t);return Mt(n.workspace,a,{title:e?.title,content:e?.content})}function vm(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=V(t);return Lt(n.workspace,a)}function ym(t,e){if(!e)throw new Error("slug query param required");let{def:a}=V(t),n=_r(a.workspace,e),r=Rt(a.workspace,e);return{slug:e,tree:n,deps:r}}function wm(t,e,a){if(!e||!a)throw new Error("slug and path query params required");let{def:n}=V(t);return Sr(n.workspace,e,a)}function km(t,e){let a=String(e?.slug||""),n=String(e?.path||"");if(!a||!n)throw new Error("slug and path required");let{def:r}=V(t);return Er(r.workspace,a,n,String(e?.content??""))}function _m(t,e){if(!e)throw new Error("slug query param required");let{def:a}=V(t);return Rt(a.workspace,e)}async function Sm(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 r=xi(e?.worker),{def:o}=V(t),s=[`Install the skills.sh package "${n}" into agent "${t}".`,`Workspace: ${o.workspace}`,`Run: cd ${o.workspace} && npx -y skills add ${n}`,`If that fails, fall back to: agentx skill install ${n}`,`Skills should land under ${o.workspace}/.claude/skills/. Report what was installed and any errors.`].join(`
10460
+ `);return bi(a,r,s,`install-${n}:${Date.now()}`)}async function Em(t,e,a){let n=String(e?.slug||"").trim();if(!n)throw new Error("slug required");let r=xi(e?.worker),{def:o}=V(t),s=Rt(o.workspace,n);if(!s.manager)throw new Error(`No dependency manifest detected in .claude/skills/${n}. Expected one of: package.json, requirements.txt, Gemfile.`);let i=mi(o.workspace,".claude","skills",n),l=[`Install dependencies for skill "${n}" in agent "${t}".`,`cd to: ${i}`,`Detected manifest: ${s.file}`,`Run: ${s.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(`
10461
+ `);return bi(a,r,l,`deps-${t}-${n}:${Date.now()}`)}function xi(t){if(t&&typeof t=="string")return t;let e=X();return e.dashboard?.draftAgent||e.node?.defaultAgent||Object.keys(e.agents).find(a=>a.includes("devops"))||Object.keys(e.agents)[0]}async function bi(t,e,a,n){let r=X(),o=(r.dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),s={"Content-Type":"application/json"},i=t.headers.authorization;i?s.Authorization=String(i):r.dashboard.token&&(s.Authorization=`Bearer ${r.dashboard.token}`);let l=await fetch(`${o}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"admin",sender:"admin-ui",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 /task HTTP ${l.status}`);return{worker:e,taskId:d?.taskId,content:d?.content,duration:d?.duration,error:d?.error}}function Tm(t){let e=gi(),a=[],n=e?.channels?.telegram?.accounts||{};for(let[o,s]of Object.entries(n))s?.agentBinding===t&&a.push({channel:"telegram",account:o,detail:s?.botUsername||o});e?.channels?.slack?.agentBinding===t&&a.push({channel:"slack",detail:"bound"}),e?.channels?.discord?.agentBinding===t&&a.push({channel:"discord",detail:"bound"});let r=e?.channels?.gitlab?.agentMappings||[];for(let o of r)o?.agentId===t&&a.push({channel:"gitlab",detail:(o?.gitlabUsernames||[]).join(", ")||"mapped"});return{bindings:a}}async function Am(t,e){try{let n=(X().dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),r=await fetch(`${n}/agents`);if(!r.ok)throw new Error(`daemon HTTP ${r.status}`);let s=(await r.json()).find(i=>i.id===t);return{activeTasks:s?.activeTasks??0,totalTasks:s?.totalTasks??0,errors:s?.errors??0,lastActive:s?.lastActive??null,runningTasks:s?.runningTasks??[],lastSummary:s?.lastSummary??null}}catch(a){return{error:a?.message,activeTasks:0,totalTasks:0,errors:0,runningTasks:[]}}}function tn(){return new zn}function Cm(t){let e=tn(),{incoming:a,outgoing:n}=e.listByAgent(t);return{incoming:a,outgoing:n}}function Im(t,e){let a=String(e?.channel||"").trim(),n=String(e?.chatId||"").trim(),r=String(e?.toAgent||"").trim();if(!a||!n||!r)throw new Error("channel, chatId, toAgent required");let o=String(e?.fromAgent||t||"").trim()||t,s=e?.accountId?String(e.accountId):void 0,i=e?.summary?String(e.summary):void 0,l=e?.expiresAt?String(e.expiresAt):void 0,c=tn().set({channel:a,chatId:n,accountId:s,fromAgent:o,toAgent:r,summary:i,expiresAt:l,createdBy:"admin-ui"});return{summary:`Handed off ${a}:${n} from ${o} to ${r}`,record:c}}function Mm(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:tn().remove(e,a,n)?"Released":"No active handover for that chat"}}function ea(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Lm(t){return new Promise((e,a)=>{let n="";t.on("data",r=>{n+=r}),t.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(r){a(r)}}),t.on("error",a)})}var Oe={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","codex-cli":"Codex CLI",opencode:"OpenCode",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 vi=[{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, Codex CLI, Anthropic Agent SDK, or AgentX's provider-agnostic orchestrator."},{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."}];function an(t={}){let e=`<script>window.UI_LABELS = ${JSON.stringify(Oe)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
10462
10462
  <span id="conn-dot" class="ax-dot ax-dot--ok ax-dot--pulse" title="connected"></span>
10463
10463
  <span id="conn-label">live</span>`,n=`<div class="ax-app-live">
10464
10464
  <section id="statstrip" class="ax-statstrip"></section>
10465
10465
  <main id="grid" class="ax-live__body"></main>
10466
10466
  </div>
10467
- `;return M({title:`${Le.brand} \xB7 ${Le.subtitle}`,activeTab:"live",subtitle:Le.subtitle,peers:t.peers,currentPeerId:t.currentPeerId,customHeader:void 0,noMain:!0,body:n,css:Fu,scripts:e+`<script>${Uu}</script>`,headExtras:`<script>
10467
+ `;return I({title:`${Oe.brand} \xB7 ${Oe.subtitle}`,activeTab:"live",subtitle:Oe.subtitle,peers:t.peers,currentPeerId:t.currentPeerId,customHeader:void 0,noMain:!0,body:n,css:Rm,scripts:e+`<script>${Pm}</script>`,headExtras:`<script>
10468
10468
  // rightExtras for the topbar are injected at runtime \u2014 they reference
10469
10469
  // IDs (#ts, #conn-dot) that the script below addresses directly.
10470
10470
  document.addEventListener('DOMContentLoaded', () => {
@@ -10475,7 +10475,7 @@ loadAgent();
10475
10475
  extras.innerHTML = ${JSON.stringify(a)};
10476
10476
  right.insertBefore(extras, right.firstChild);
10477
10477
  });
10478
- </script>`})}var Fu=`
10478
+ </script>`})}var Rm=`
10479
10479
  /* --- Page frame --- */
10480
10480
  .ax-app-live { min-height: 100vh; display: flex; flex-direction: column; }
10481
10481
 
@@ -10682,7 +10682,7 @@ loadAgent();
10682
10682
  border-top-color: var(--ax-accent); border-radius: 50%;
10683
10683
  animation: ax-spin 800ms linear infinite; display: inline-block;
10684
10684
  }
10685
- @keyframes ax-spin { to { transform: rotate(360deg); } }`,Uu=`
10685
+ @keyframes ax-spin { to { transform: rotate(360deg); } }`,Pm=`
10686
10686
  'use strict';
10687
10687
 
10688
10688
  const ui = { nodes: new Map(), summary: { nodes: 0, agents: 0, busy: 0, errors: 0 } };
@@ -11253,7 +11253,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
11253
11253
  });
11254
11254
  }
11255
11255
 
11256
- `;var ei=`
11256
+ `;var yi=`
11257
11257
  .mx-content{max-width:1180px;margin:0 auto;padding:0 24px 56px}
11258
11258
  .mx-updated{margin:0;color:var(--ax-muted);font-size:11px;font-family:var(--ax-mono)}
11259
11259
  .mx-section{margin-bottom:28px}.mx-section .ax-section-head{margin-bottom:14px}
@@ -11427,7 +11427,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
11427
11427
  .mx-summary{max-width:56vw}
11428
11428
  }
11429
11429
  @media(prefers-reduced-motion:reduce){.mx-drawer{transition:none}}
11430
- `;var ti=`<script>
11430
+ `;var wi=`<script>
11431
11431
  window.MX=(function(){
11432
11432
  var ENT={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'};
11433
11433
  function esc(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return ENT[c]})}
@@ -11536,7 +11536,7 @@ window.MX=(function(){
11536
11536
  verdict:verdict,verdictChip:verdictChip,mark:mark,causeLabel:causeLabel,
11537
11537
  setHealth:setHealth,get:get};
11538
11538
  })();
11539
- </script>`;var ai=`<script>
11539
+ </script>`;var ki=`<script>
11540
11540
  window.MXD=(function(){
11541
11541
  function el(id){return document.getElementById(id)}
11542
11542
  function tz(){return -new Date().getTimezoneOffset()}
@@ -11750,7 +11750,7 @@ window.MXD=(function(){
11750
11750
 
11751
11751
  return {openDay:openDay,openJob:openJob,openConversation:openConversation};
11752
11752
  })();
11753
- </script>`;var ni=`<script>
11753
+ </script>`;var _i=`<script>
11754
11754
  (function(){
11755
11755
  var LANES=[
11756
11756
  {id:'cron',name:'Scheduled',hint:'cron jobs'},
@@ -12066,7 +12066,7 @@ window.MXD=(function(){
12066
12066
  window.addEventListener('scroll',hideTip,{passive:true});
12067
12067
  load();
12068
12068
  })();
12069
- </script>`;var ri=`<script>
12069
+ </script>`;var Si=`<script>
12070
12070
  (function(){
12071
12071
  var showAll=document.getElementById('mx-show-all'),expanded=false;
12072
12072
  var esc=MX.esc;
@@ -12244,7 +12244,7 @@ window.MXD=(function(){
12244
12244
  }
12245
12245
  load();setInterval(load,5000);
12246
12246
  })();
12247
- </script>`;var oi=`
12247
+ </script>`;var Ei=`
12248
12248
  .mx-rt-bar{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:12px}
12249
12249
  .mx-rt-wrap{border:var(--ax-border-w) solid var(--ax-border);border-radius:var(--ax-radius-lg);background:var(--ax-surface);overflow-x:auto}
12250
12250
  .mx-rt-wrap > .mx-empty{border:0}
@@ -12285,7 +12285,7 @@ window.MXD=(function(){
12285
12285
  .mx-rt-msg td{display:block}.mx-rt-msg td::before{content:none}
12286
12286
  .mx-rt-name{max-width:100%}
12287
12287
  }
12288
- `,si=`<script>
12288
+ `,Ti=`<script>
12289
12289
  (function(){
12290
12290
  var root=document.getElementById('mx-routines');
12291
12291
  var bar=document.getElementById('mx-rt-filter');
@@ -12412,7 +12412,7 @@ window.MXD=(function(){
12412
12412
  syncBar();
12413
12413
  document.addEventListener('mx:snapshot',function(e){render(e.detail||{})});
12414
12414
  })();
12415
- </script>`;var ii=[{id:"all",label:"All"},{id:"peers",label:"Other machines"},{id:"announce",label:"Announcements"},{id:"problems",label:"Problems"}],li=`<script>
12415
+ </script>`;var Ai=[{id:"all",label:"All"},{id:"peers",label:"Other machines"},{id:"announce",label:"Announcements"},{id:"problems",label:"Problems"}],Ci=`<script>
12416
12416
  (function(){
12417
12417
  var root=document.getElementById('mx-feed');
12418
12418
  if(!root)return;
@@ -12487,17 +12487,17 @@ window.MXD=(function(){
12487
12487
  }
12488
12488
  load();setInterval(load,5000);
12489
12489
  })();
12490
- </script>`;var ae={activity:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h3l2-6 4 12 2-6h5"/></svg>',breakage:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v6l-3 3 3 3v6"/><path d="M5 5l14 14"/></svg>',effort:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20V4M4 20h16"/><circle cx="9" cy="15" r="2"/><circle cx="15" cy="8" r="2"/></svg>',lifetime:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h18"/><path d="M7 8v8M13 8v8M19 8v8"/></svg>',cuts:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><path d="M8 8l12 10M8 16L20 6"/></svg>',schedules:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>',routines:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h11M4 12h7M4 17h9"/><path d="M17 5l3 3-3 3M16 14l4 4M20 14l-4 4"/></svg>',nodes:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M8 6h8M7 8l4 8M17 8l-4 8"/></svg>',feed:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1.5"/></svg>',agents:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4M8 16h.01M16 16h.01"/></svg>'};function ne(t,e,a,n,r=""){return K({icon:t,title:e,lead:a,actionHtml:r}).replace("<h2>",`<h2 id="${n}">`)}var Wu=[{id:"all",label:"All"},{id:"attention",label:"Flagged"},{id:"schedule",label:"Schedules"},{id:"event",label:"Events"}],Gu=[{id:"activity",label:"Activity"},{id:"lifetime",label:"Lifetime"},{id:"ops",label:"Operations"}],Xu=[{days:0,label:"Today"},{days:7,label:"7d"},{days:30,label:"30d"},{days:90,label:"90d"}];function ci(t){let e=be({kicker:"Operations",title:"Mesh operations",lead:"What the fleet actually did, how long it lived, and which of it was worth running."})+Mt([{kind:"off",num:"-",label:"Nodes online"},{kind:"off",num:"-",label:"Tasks running"},{kind:"off",num:"-",label:"Failed today"},{kind:"off",num:"-",label:"Jobs needing review"}]).replace('<div class="ax-health-strip">','<div class="ax-health-strip" id="mx-health">'),a=`<div class="mx-toolbar">
12490
+ </script>`;var ne={activity:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h3l2-6 4 12 2-6h5"/></svg>',breakage:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v6l-3 3 3 3v6"/><path d="M5 5l14 14"/></svg>',effort:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20V4M4 20h16"/><circle cx="9" cy="15" r="2"/><circle cx="15" cy="8" r="2"/></svg>',lifetime:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h18"/><path d="M7 8v8M13 8v8M19 8v8"/></svg>',cuts:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><path d="M8 8l12 10M8 16L20 6"/></svg>',schedules:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>',routines:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h11M4 12h7M4 17h9"/><path d="M17 5l3 3-3 3M16 14l4 4M20 14l-4 4"/></svg>',nodes:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M8 6h8M7 8l4 8M17 8l-4 8"/></svg>',feed:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1.5"/></svg>',agents:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4M8 16h.01M16 16h.01"/></svg>'};function re(t,e,a,n,r=""){return K({icon:t,title:e,lead:a,actionHtml:r}).replace("<h2>",`<h2 id="${n}">`)}var $m=[{id:"all",label:"All"},{id:"attention",label:"Flagged"},{id:"schedule",label:"Schedules"},{id:"event",label:"Events"}],jm=[{id:"activity",label:"Activity"},{id:"lifetime",label:"Lifetime"},{id:"ops",label:"Operations"}],Om=[{days:0,label:"Today"},{days:7,label:"7d"},{days:30,label:"30d"},{days:90,label:"90d"}];function Ii(t){let e=ue({kicker:"Operations",title:"Mesh operations",lead:"What the fleet actually did, how long it lived, and which of it was worth running."})+Pt([{kind:"off",num:"-",label:"Nodes online"},{kind:"off",num:"-",label:"Tasks running"},{kind:"off",num:"-",label:"Failed today"},{kind:"off",num:"-",label:"Jobs needing review"}]).replace('<div class="ax-health-strip">','<div class="ax-health-strip" id="mx-health">'),a=`<div class="mx-toolbar">
12491
12491
  <div class="mx-tabs" role="tablist" aria-label="Mesh views">
12492
- ${Gu.map((i,l)=>`<button class="mx-tab" type="button" role="tab" id="mx-tab-${i.id}" aria-controls="mx-view-${i.id}" aria-selected="${l===0}" data-view="${i.id}">${i.label}</button>`).join("")}
12492
+ ${jm.map((i,l)=>`<button class="mx-tab" type="button" role="tab" id="mx-tab-${i.id}" aria-controls="mx-view-${i.id}" aria-selected="${l===0}" data-view="${i.id}">${i.label}</button>`).join("")}
12493
12493
  </div>
12494
12494
  <div class="mx-range" id="mx-range" role="group" aria-label="History window">
12495
- ${Xu.map(i=>`<button type="button" data-days="${i.days}" aria-pressed="${i.days===30}">${i.label}</button>`).join("")}
12495
+ ${Om.map(i=>`<button type="button" data-days="${i.days}" aria-pressed="${i.days===30}">${i.label}</button>`).join("")}
12496
12496
  </div>
12497
12497
  </div>
12498
12498
  <p id="mx-analytics-updated" class="mx-updated" aria-live="polite">Reading node histories...</p>`,n=`<div class="mx-view" id="mx-view-activity" role="tabpanel" aria-labelledby="mx-tab-activity">
12499
12499
  <section class="mx-section" aria-labelledby="mx-lanes-title">
12500
- ${ne(ae.activity,"What ran","One lane per origin. Each lane is scaled to its own peak so a quiet channel stays readable next to a busy one. Select a column for the day behind it.","mx-lanes-title")}
12500
+ ${re(ne.activity,"What ran","One lane per origin. Each lane is scaled to its own peak so a quiet channel stays readable next to a busy one. Select a column for the day behind it.","mx-lanes-title")}
12501
12501
  <div id="mx-lanes"><div class="mx-empty">Loading activity...</div></div>
12502
12502
  <div class="mx-axis" id="mx-axis"></div>
12503
12503
  <p class="mx-note">Coloured bars are runs that finished; the red cap on a column is the failures inside that day. Select any column for what ran that day, down to a single conversation.</p>
@@ -12505,32 +12505,32 @@ window.MXD=(function(){
12505
12505
 
12506
12506
  <div class="mx-two">
12507
12507
  <section class="mx-section" aria-labelledby="mx-origins-title">
12508
- ${ne(ae.breakage,"Where it breaks","Attempts per origin, with the failed share marked on the same bar.","mx-origins-title")}
12508
+ ${re(ne.breakage,"Where it breaks","Attempts per origin, with the failed share marked on the same bar.","mx-origins-title")}
12509
12509
  <div class="mx-bars" id="mx-origins"><div class="mx-empty">Loading...</div></div>
12510
12510
  </section>
12511
12511
  <section class="mx-section" aria-labelledby="mx-causes-title">
12512
- ${ne(ae.breakage,"Why it fails","Failures grouped by cause class, matched from the recorded error text.","mx-causes-title")}
12512
+ ${re(ne.breakage,"Why it fails","Failures grouped by cause class, matched from the recorded error text.","mx-causes-title")}
12513
12513
  <div class="mx-bars" id="mx-causes"><div class="mx-empty">Loading...</div></div>
12514
12514
  <p class="mx-note" id="mx-cause-note"></p>
12515
12515
  </section>
12516
12516
  </div>
12517
12517
 
12518
12518
  <section class="mx-section" aria-labelledby="mx-scatter-title">
12519
- ${ne(ae.effort,"Effort against output","Every recurring job, plotted as runtime spent against tokens produced on its successful runs. Both axes are logarithmic.","mx-scatter-title")}
12519
+ ${re(ne.effort,"Effort against output","Every recurring job, plotted as runtime spent against tokens produced on its successful runs. Both axes are logarithmic.","mx-scatter-title")}
12520
12520
  <div class="mx-scatter" id="mx-scatter"><div class="mx-empty">Loading jobs...</div></div>
12521
12521
  <div class="mx-legend" id="mx-scatter-legend"></div>
12522
12522
  <p class="mx-note">Bubble size is the number of runs. Anything not healthy is labelled on the chart; select it for the attempt history behind the verdict.</p>
12523
12523
  </section>
12524
12524
  </div>`,r=`<div class="mx-view" id="mx-view-lifetime" role="tabpanel" aria-labelledby="mx-tab-lifetime" hidden>
12525
12525
  <section class="mx-section" aria-labelledby="mx-threads-title">
12526
- ${ne(ae.lifetime,"Thread lifetimes","A thread is one agent talking on one channel in one conversation. The bar is its real first-to-last span; each tick is a session cut. Select one for its turns, tokens and time.","mx-threads-title")}
12526
+ ${re(ne.lifetime,"Thread lifetimes","A thread is one agent talking on one channel in one conversation. The bar is its real first-to-last span; each tick is a session cut. Select one for its turns, tokens and time.","mx-threads-title")}
12527
12527
  <div class="mx-chips" id="mx-thread-chips"></div>
12528
12528
  <div id="mx-threads"><div class="mx-empty">Loading threads...</div></div>
12529
12529
  <p class="mx-note">Select a thread to walk its runs, then a run to see which tools it touched. Grey ticks are stale cuts, amber ticks are context-full cuts.</p>
12530
12530
  </section>
12531
12531
 
12532
12532
  <section class="mx-section" aria-labelledby="mx-rot-title">
12533
- ${ne(ae.cuts,"Session cuts","Why threads lost their session, across the fleet.","mx-rot-title")}
12533
+ ${re(ne.cuts,"Session cuts","Why threads lost their session, across the fleet.","mx-rot-title")}
12534
12534
  <div class="mx-bars" id="mx-rotations"><div class="mx-empty">Loading...</div></div>
12535
12535
  <p class="mx-note" id="mx-rot-note"></p>
12536
12536
  </section>
@@ -12538,39 +12538,39 @@ window.MXD=(function(){
12538
12538
  <p id="mx-updated" class="mx-updated" aria-live="polite">Connecting to the fleet...</p>
12539
12539
 
12540
12540
  <section class="mx-section" aria-labelledby="mx-auto-title">
12541
- ${ne(ae.schedules,"Today's automations","Persisted attempts are authoritative. Select a schedule to inspect its latest result and runtime.","mx-auto-title",'<div class="mx-section-actions"><span class="ax-tab-count" id="mx-run-count">0 schedules</span><button class="ax-btn ax-btn--ghost mx-show-all" id="mx-show-all" type="button" hidden>Show all</button></div>')}
12541
+ ${re(ne.schedules,"Today's automations","Persisted attempts are authoritative. Select a schedule to inspect its latest result and runtime.","mx-auto-title",'<div class="mx-section-actions"><span class="ax-tab-count" id="mx-run-count">0 schedules</span><button class="ax-btn ax-btn--ghost mx-show-all" id="mx-show-all" type="button" hidden>Show all</button></div>')}
12542
12542
  <div class="ax-stack" id="mx-runs"><div class="mx-empty">Loading schedules...</div></div>
12543
12543
  </section>
12544
12544
 
12545
12545
  <section class="mx-section" aria-labelledby="mx-routines-title">
12546
- ${ne(ae.routines,"Routines","Everything that runs on its own: schedules and cron- or event-triggered workflows, per node. Flags mark routines that keep failing, went quiet, never ran, or sat disabled.","mx-routines-title",'<span class="ax-tab-count" id="mx-rt-count">0 routines</span>')}
12546
+ ${re(ne.routines,"Routines","Everything that runs on its own: schedules and cron- or event-triggered workflows, per node. Flags mark routines that keep failing, went quiet, never ran, or sat disabled.","mx-routines-title",'<span class="ax-tab-count" id="mx-rt-count">0 routines</span>')}
12547
12547
  <div class="mx-rt-bar" id="mx-rt-filter" role="group" aria-label="Filter routines">
12548
- ${Wu.map(i=>`<button class="mx-chip" type="button" data-rt-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
12548
+ ${$m.map(i=>`<button class="mx-chip" type="button" data-rt-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
12549
12549
  </div>
12550
12550
  <div class="mx-rt-wrap" id="mx-routines"><div class="mx-empty">Loading routines...</div></div>
12551
12551
  </section>
12552
12552
 
12553
12553
  <section class="mx-section" aria-labelledby="mx-feed-title">
12554
- ${ne(ae.feed,"Mesh feed","The newest events from this machine and every machine it follows. Unreachable machines and announcements show here too. Select an event for its details.","mx-feed-title",'<div class="mx-section-actions"><span class="ax-tab-count" id="mx-feed-count">0 events</span><button class="ax-btn ax-btn--ghost" id="mx-feed-more" type="button" hidden>Show all</button></div>')}
12554
+ ${re(ne.feed,"Mesh feed","The newest events from this machine and every machine it follows. Unreachable machines and announcements show here too. Select an event for its details.","mx-feed-title",'<div class="mx-section-actions"><span class="ax-tab-count" id="mx-feed-count">0 events</span><button class="ax-btn ax-btn--ghost" id="mx-feed-more" type="button" hidden>Show all</button></div>')}
12555
12555
  <div class="mx-rt-bar" role="group" aria-label="Filter the mesh feed">
12556
- ${ii.map(i=>`<button class="mx-chip" type="button" data-feed-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
12556
+ ${Ai.map(i=>`<button class="mx-chip" type="button" data-feed-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
12557
12557
  </div>
12558
12558
  <div class="ax-stack" id="mx-feed" aria-live="polite"><div class="mx-empty">Loading the mesh feed...</div></div>
12559
12559
  </section>
12560
12560
 
12561
12561
  <div class="mx-columns">
12562
12562
  <section class="mx-section" aria-labelledby="mx-active-title">
12563
- ${ne(ae.activity,"Activity provenance","Who initiated current work and where it is running.","mx-active-title",'<span class="ax-tab-count" id="mx-active-count">0 active</span>')}
12563
+ ${re(ne.activity,"Activity provenance","Who initiated current work and where it is running.","mx-active-title",'<span class="ax-tab-count" id="mx-active-count">0 active</span>')}
12564
12564
  <div class="ax-stack" id="mx-active"><div class="mx-empty">No activity loaded.</div></div>
12565
12565
  </section>
12566
12566
  <section class="mx-section" aria-labelledby="mx-nodes-title">
12567
- ${ne(ae.nodes,"Nodes","Reachability and capacity across the fleet.","mx-nodes-title",'<span class="ax-tab-count" id="mx-node-count">0 nodes</span>')}
12567
+ ${re(ne.nodes,"Nodes","Reachability and capacity across the fleet.","mx-nodes-title",'<span class="ax-tab-count" id="mx-node-count">0 nodes</span>')}
12568
12568
  <div class="ax-stack" id="mx-nodes"><div class="mx-empty">No nodes loaded.</div></div>
12569
12569
  </section>
12570
12570
  </div>
12571
12571
 
12572
12572
  <section class="mx-section" aria-labelledby="mx-agents-title">
12573
- ${ne(ae.agents,"Agents and skills","Runtime, model, installed skills, and task totals by node.","mx-agents-title",'<span class="ax-tab-count" id="mx-agent-count">0 agents</span>')}
12573
+ ${re(ne.agents,"Agents and skills","Runtime, model, installed skills, and task totals by node.","mx-agents-title",'<span class="ax-tab-count" id="mx-agent-count">0 agents</span>')}
12574
12574
  <div class="mx-agent-grid" id="mx-agents"><div class="mx-empty">No agents loaded.</div></div>
12575
12575
  </section>
12576
12576
  </div>`,s=`${e}<main class="mx-content">
@@ -12586,7 +12586,7 @@ window.MXD=(function(){
12586
12586
  <button class="ax-btn ax-btn--ghost" id="mx-close" type="button" aria-label="Close details">Close</button>
12587
12587
  </header>
12588
12588
  <div class="mx-drawer__body" id="mx-drawer-body"></div>
12589
- </aside>`;return M({title:"AgentX \xB7 Mesh Operations",activeTab:"mesh",subtitle:"Operations",peers:t.peers,noMain:!0,body:s,css:ei+oi,scripts:ti+Ku+ai+ni+si+ri+li})}var Ku=`<script>
12589
+ </aside>`;return I({title:"AgentX \xB7 Mesh Operations",activeTab:"mesh",subtitle:"Operations",peers:t.peers,noMain:!0,body:s,css:yi+Ei,scripts:wi+Nm+ki+_i+Ti+Si+Ci})}var Nm=`<script>
12590
12590
  (function(){
12591
12591
  var tabs=Array.prototype.slice.call(document.querySelectorAll('.mx-tab'));
12592
12592
  var range=document.getElementById('mx-range');
@@ -12614,10 +12614,10 @@ window.MXD=(function(){
12614
12614
  var saved=null;try{saved=localStorage.getItem('mx-view')}catch(e){}
12615
12615
  select(tabs.some(function(t){return t.dataset.view===saved})?saved:'activity');
12616
12616
  })();
12617
- </script>`;function di(t){let e=be({kicker:"Operations",title:"Guest meshes",lead:"Other organisations let into part of this mesh. Each grant names one agent of yours, what it may touch for them, how much freedom it has and until when. Nothing is shared until you open it."})+`
12617
+ </script>`;function Mi(t){let e=ue({kicker:"Operations",title:"Guest meshes",lead:"Other organisations let into part of this mesh. Each grant names one agent of yours, what it may touch for them, how much freedom it has and until when. Nothing is shared until you open it."})+`
12618
12618
  <div id="gm-msg" class="gm-msg" role="status" aria-live="polite"></div>
12619
12619
  <ol id="gm-list" class="gm-list" aria-label="Grants"><li class="gm-empty">Loading\u2026</li></ol>
12620
- <p class="gm-note">Open a grant from a terminal: <code>agentx mesh guests invite --name "\u2026" --guest "\u2026" --agent &lt;id&gt;</code>. The guest joins with the code; its join arrives as a card in Approvals.</p>`;return M({title:"AgentX \xB7 Guest meshes",activeTab:"mesh",subtitle:"Guest meshes",peers:t.peers,body:e,css:Ju,scripts:`<script>${Vu}</script>`})}var Ju=`
12620
+ <p class="gm-note">Open a grant from a terminal: <code>agentx mesh guests invite --name "\u2026" --guest "\u2026" --agent &lt;id&gt;</code>. The guest joins with the code; its join arrives as a card in Approvals.</p>`;return I({title:"AgentX \xB7 Guest meshes",activeTab:"mesh",subtitle:"Guest meshes",peers:t.peers,body:e,css:Dm,scripts:`<script>${Hm}</script>`})}var Dm=`
12621
12621
  .gm-list { list-style: none; margin: 16px 0; padding: 0; display: grid; gap: 12px; }
12622
12622
  .gm-empty { color: var(--ax-text-2); }
12623
12623
  .gm-item { padding: 14px 16px; border: var(--ax-border-w) solid var(--ax-border); border-radius: var(--ax-radius); background: var(--ax-surface); }
@@ -12635,7 +12635,7 @@ window.MXD=(function(){
12635
12635
  .gm-msg { min-height: 1.4em; margin: 8px 0 0; }
12636
12636
  .gm-msg.is-bad { color: var(--ax-red-ink); }
12637
12637
  .gm-note { color: var(--ax-text-2); font-size: var(--ax-fs-sm); }
12638
- `,Vu=`
12638
+ `,Hm=`
12639
12639
  (function () {
12640
12640
  var list = document.getElementById('gm-list');
12641
12641
  var msg = document.getElementById('gm-msg');
@@ -12682,7 +12682,7 @@ window.MXD=(function(){
12682
12682
  load();
12683
12683
  setInterval(load, 30000);
12684
12684
  })();
12685
- `;async function pi(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?days=${e.days}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/mesh"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return Yu(s,e.days)}function Yu(t,e){let a={runs:0,errors:0,hours:0,agents:0,threads:0},n=new Map,r=new Map,o=new Map,s=new Map,i=[],l=[],c=0,p=0,u=0,m=0,h=0,_=0;for(let{node:S,data:g}of t)if(g){a.runs+=g.totals.runs,a.errors+=g.totals.errors,a.hours+=g.totals.hours,a.agents+=g.totals.agents,a.threads+=g.totals.threads;for(let d of g.days){let f=n.get(d.day)||{day:d.day,cron:[0,0],workflow:[0,0],direct:[0,0]};for(let x of["cron","workflow","direct"])f[x][0]+=d[x]?.[0]||0,f[x][1]+=d[x]?.[1]||0;n.set(d.day,f)}for(let d of g.origins){let f=r.get(d.channel)||{channel:d.channel,runs:0,errors:0,hours:0};f.runs+=d.runs,f.errors+=d.errors,f.hours+=d.hours,r.set(d.channel,f)}for(let d of g.causes){let f=o.get(d.cause)||{cause:d.cause,count:0,agents:[],example:""};f.count+=d.count;for(let x of d.agents)f.agents.includes(x)||f.agents.push(x);f.example||(f.example=d.example),o.set(d.cause,f)}for(let d of g.rotations.byReason)s.set(d.reason,(s.get(d.reason)||0)+d.count);c+=g.rotations.total,p+=g.rotations.tokenSum||0,u+=g.rotations.tokenSamples||0,m=Math.max(m,g.rotations.maxTokens),h+=g.retention.traces,_+=g.retention.tracesWithSteps;for(let d of g.jobs)i.push({...d,node:S.name,nodeUrl:S.url});for(let d of g.threads)l.push({...d,node:S.name,nodeUrl:S.url})}let v=t.filter(S=>S.data).map(S=>S.data.since).filter(S=>Number.isFinite(S));return{generatedAt:Date.now(),windowDays:e,since:v.length?Math.min(...v):Date.now()-e*864e5,nodes:t.map(S=>({name:S.node.name,url:S.node.url,ok:!!S.data,error:S.error,runs:S.data?.totals.runs||0})),totals:{...a,hours:Math.round(a.hours*100)/100},days:[...n.values()].sort((S,g)=>S.day.localeCompare(g.day)),origins:[...r.values()].map(S=>({...S,hours:Math.round(S.hours*100)/100})).sort((S,g)=>g.runs-S.runs),causes:[...o.values()].sort((S,g)=>g.count-S.count),jobs:i.sort((S,g)=>g.hours-S.hours),threads:l.sort((S,g)=>g.lastAt-g.firstAt-(S.lastAt-S.firstAt)||g.runs-S.runs),rotations:{total:c,byReason:[...s.entries()].map(([S,g])=>({reason:S,count:g})).sort((S,g)=>g.count-S.count),tokenSum:p,tokenSamples:u,maxTokens:m},retention:{traces:h,tracesWithSteps:_}}}async function ui(t,e,a,n){let r=a.replace(/\/+$/,""),o=e.find(i=>i.url.replace(/\/+$/,"")===r);if(!o){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"node not in dashboard allowlist",target:r}));return}let s={Accept:"application/json"};o.token&&(s.Authorization=`Bearer ${o.token}`);try{let i=await fetch(r+n,{headers:s}),l=await i.text();t.writeHead(i.status,{"Content-Type":"application/json; charset=utf-8"}),t.end(l)}catch(i){t.writeHead(502,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:i?.message||"upstream fetch failed"}))}}async function mi(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?day=${encodeURIComponent(e.day)}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/day"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return Qu(s,e.day)}function Qu(t,e){let a={runs:0,errors:0,ms:0,inputTokens:0,outputTokens:0},n=new Map,r=new Map,o=[];for(let{node:s,data:i}of t)if(i){a.runs+=i.totals.runs,a.errors+=i.totals.errors,a.ms+=i.totals.ms,a.inputTokens+=i.totals.inputTokens,a.outputTokens+=i.totals.outputTokens;for(let l of i.origins){let c=n.get(l.channel)||{channel:l.channel,runs:0,errors:0,ms:0};c.runs+=l.runs,c.errors+=l.errors,c.ms+=l.ms,n.set(l.channel,c)}for(let l of i.causes)r.set(l.cause,(r.get(l.cause)||0)+l.count);for(let l of i.conversations)o.push({...l,node:s.name,nodeUrl:s.url})}return{day:e,nodes:t.map(s=>({name:s.node.name,url:s.node.url,ok:!!s.data,error:s.error,runs:s.data?.totals.runs||0})),totals:a,origins:[...n.values()].sort((s,i)=>i.runs-s.runs),causes:[...r.entries()].map(([s,i])=>({cause:s,count:i})).sort((s,i)=>i.count-s.count),conversations:o.sort((s,i)=>i.ms-s.ms||i.turns-s.turns)}}function fi(t={}){let e=`
12685
+ `;async function Li(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?days=${e.days}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/mesh"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return Bm(s,e.days)}function Bm(t,e){let a={runs:0,errors:0,hours:0,agents:0,threads:0},n=new Map,r=new Map,o=new Map,s=new Map,i=[],l=[],c=0,d=0,p=0,m=0,f=0,S=0;for(let{node:E,data:g}of t)if(g){a.runs+=g.totals.runs,a.errors+=g.totals.errors,a.hours+=g.totals.hours,a.agents+=g.totals.agents,a.threads+=g.totals.threads;for(let x of g.days){let u=n.get(x.day)||{day:x.day,cron:[0,0],workflow:[0,0],direct:[0,0]};for(let h of["cron","workflow","direct"])u[h][0]+=x[h]?.[0]||0,u[h][1]+=x[h]?.[1]||0;n.set(x.day,u)}for(let x of g.origins){let u=r.get(x.channel)||{channel:x.channel,runs:0,errors:0,hours:0};u.runs+=x.runs,u.errors+=x.errors,u.hours+=x.hours,r.set(x.channel,u)}for(let x of g.causes){let u=o.get(x.cause)||{cause:x.cause,count:0,agents:[],example:""};u.count+=x.count;for(let h of x.agents)u.agents.includes(h)||u.agents.push(h);u.example||(u.example=x.example),o.set(x.cause,u)}for(let x of g.rotations.byReason)s.set(x.reason,(s.get(x.reason)||0)+x.count);c+=g.rotations.total,d+=g.rotations.tokenSum||0,p+=g.rotations.tokenSamples||0,m=Math.max(m,g.rotations.maxTokens),f+=g.retention.traces,S+=g.retention.tracesWithSteps;for(let x of g.jobs)i.push({...x,node:E.name,nodeUrl:E.url});for(let x of g.threads)l.push({...x,node:E.name,nodeUrl:E.url})}let b=t.filter(E=>E.data).map(E=>E.data.since).filter(E=>Number.isFinite(E));return{generatedAt:Date.now(),windowDays:e,since:b.length?Math.min(...b):Date.now()-e*864e5,nodes:t.map(E=>({name:E.node.name,url:E.node.url,ok:!!E.data,error:E.error,runs:E.data?.totals.runs||0})),totals:{...a,hours:Math.round(a.hours*100)/100},days:[...n.values()].sort((E,g)=>E.day.localeCompare(g.day)),origins:[...r.values()].map(E=>({...E,hours:Math.round(E.hours*100)/100})).sort((E,g)=>g.runs-E.runs),causes:[...o.values()].sort((E,g)=>g.count-E.count),jobs:i.sort((E,g)=>g.hours-E.hours),threads:l.sort((E,g)=>g.lastAt-g.firstAt-(E.lastAt-E.firstAt)||g.runs-E.runs),rotations:{total:c,byReason:[...s.entries()].map(([E,g])=>({reason:E,count:g})).sort((E,g)=>g.count-E.count),tokenSum:d,tokenSamples:p,maxTokens:m},retention:{traces:f,tracesWithSteps:S}}}async function Ri(t,e,a,n){let r=a.replace(/\/+$/,""),o=e.find(i=>i.url.replace(/\/+$/,"")===r);if(!o){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"node not in dashboard allowlist",target:r}));return}let s={Accept:"application/json"};o.token&&(s.Authorization=`Bearer ${o.token}`);try{let i=await fetch(r+n,{headers:s}),l=await i.text();t.writeHead(i.status,{"Content-Type":"application/json; charset=utf-8"}),t.end(l)}catch(i){t.writeHead(502,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:i?.message||"upstream fetch failed"}))}}async function Pi(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?day=${encodeURIComponent(e.day)}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/day"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return zm(s,e.day)}function zm(t,e){let a={runs:0,errors:0,ms:0,inputTokens:0,outputTokens:0},n=new Map,r=new Map,o=[];for(let{node:s,data:i}of t)if(i){a.runs+=i.totals.runs,a.errors+=i.totals.errors,a.ms+=i.totals.ms,a.inputTokens+=i.totals.inputTokens,a.outputTokens+=i.totals.outputTokens;for(let l of i.origins){let c=n.get(l.channel)||{channel:l.channel,runs:0,errors:0,ms:0};c.runs+=l.runs,c.errors+=l.errors,c.ms+=l.ms,n.set(l.channel,c)}for(let l of i.causes)r.set(l.cause,(r.get(l.cause)||0)+l.count);for(let l of i.conversations)o.push({...l,node:s.name,nodeUrl:s.url})}return{day:e,nodes:t.map(s=>({name:s.node.name,url:s.node.url,ok:!!s.data,error:s.error,runs:s.data?.totals.runs||0})),totals:a,origins:[...n.values()].sort((s,i)=>i.runs-s.runs),causes:[...r.entries()].map(([s,i])=>({cause:s,count:i})).sort((s,i)=>i.count-s.count),conversations:o.sort((s,i)=>i.ms-s.ms||i.turns-s.turns)}}function $i(t={}){let e=`
12686
12686
  <select id="boardPicker" title="Switch board"></select>
12687
12687
  <div class="search">
12688
12688
  <span class="icon">\u2315</span>
@@ -12783,7 +12783,7 @@ window.MXD=(function(){
12783
12783
  </footer>
12784
12784
  </div>
12785
12785
  </div>
12786
- <script src="/sortable.min.js"></script>`;return M({title:"AgentX \xB7 Boards",activeTab:"boards",subtitle:"Boards",subheader:e,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a,css:Zu,scripts:`<script>${em}</script>`,headExtras:`<script>
12786
+ <script src="/sortable.min.js"></script>`;return I({title:"AgentX \xB7 Boards",activeTab:"boards",subtitle:"Boards",subheader:e,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a,css:qm,scripts:`<script>${Fm}</script>`,headExtras:`<script>
12787
12787
  // The boards page has its own connection dot + wants body height:100%
12788
12788
  // for the full-viewport kanban layout. Inject the dot into the topbar
12789
12789
  // and override body height at runtime so the shared shell doesn't
@@ -12799,7 +12799,7 @@ window.MXD=(function(){
12799
12799
  right.insertBefore(dot, right.firstChild);
12800
12800
  }
12801
12801
  });
12802
- </script>`})}var Zu=`
12802
+ </script>`})}var qm=`
12803
12803
  /* Kanban subheader \u2014 replaces the legacy toolbar that used to live in <header>. */
12804
12804
  .ax-subheader select, .ax-subheader input, .ax-subheader button {
12805
12805
  background: var(--col); color: var(--text); border: 1px solid var(--border);
@@ -13052,7 +13052,7 @@ header a.link:hover { color: var(--accent); border-color: var(--accent); }
13052
13052
  .draft-box .draft-row .hint { color: var(--muted); font-size: 12px; flex: 1; }
13053
13053
  .draft-box .draft-row .hint.err { color: var(--red); }
13054
13054
  .draft-box .draft-row .hint.ok { color: var(--green); }
13055
- `,em=`
13055
+ `,Fm=`
13056
13056
  'use strict';
13057
13057
  const state = {
13058
13058
  boards: [], current: null, items: {},
@@ -14105,9 +14105,9 @@ function appendEvents(events) {
14105
14105
  }
14106
14106
 
14107
14107
  loadBoards().catch(e => toast('Init failed: ' + e.message));
14108
- `;function hi(t={}){let a=`<h1>Plain-English glossary</h1>
14108
+ `;function ji(t={}){let a=`<h1>Plain-English glossary</h1>
14109
14109
  <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>
14110
- ${Zs.map(n=>{let r=n.alias?`<span class="alias" title="Schema key">${N(n.alias)}</span>`:"";return`<article class="term"><h3>${N(n.term)}${r}</h3><p>${N(n.definition)}</p></article>`}).join("")}`;return M({title:`${Le.brand} \xB7 Glossary`,activeTab:"glossary",subtitle:"Glossary",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:tm})}var tm=`
14110
+ ${vi.map(n=>{let r=n.alias?`<span class="alias" title="Schema key">${H(n.alias)}</span>`:"";return`<article class="term"><h3>${H(n.term)}${r}</h3><p>${H(n.definition)}</p></article>`}).join("")}`;return I({title:`${Oe.brand} \xB7 Glossary`,activeTab:"glossary",subtitle:"Glossary",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Um})}var Um=`
14111
14111
  main { max-width: 760px; margin: 0 auto; padding: 32px 24px 80px; }
14112
14112
  h1 { font-size: 22px; margin: 0 0 6px; font-weight: 600; letter-spacing: -0.01em; }
14113
14113
  .lead {
@@ -14137,7 +14137,7 @@ article.term .alias {
14137
14137
  }
14138
14138
  article.term p {
14139
14139
  margin: 0; color: var(--ax-text-2); font-size: 13px; line-height: 1.6;
14140
- }`;function gi(t={}){let e=`<div class="ax-wf__root">
14140
+ }`;function Oi(t={}){let e=`<div class="ax-wf__root">
14141
14141
  <aside class="ax-wf__list">
14142
14142
  <header>
14143
14143
  <h2>Workflows</h2>
@@ -14214,7 +14214,7 @@ article.term p {
14214
14214
  </aside>
14215
14215
  </div>
14216
14216
 
14217
- <div id="wf-toast" class="ax-wf__toast" hidden></div>`;return M({title:"AgentX \xB7 Workflows",activeTab:"workflows",subtitle:"Workflows",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:am,scripts:`<script>${B({workflowHealth:Hn})}${nm}</script>`})}var am=`
14217
+ <div id="wf-toast" class="ax-wf__toast" hidden></div>`;return I({title:"AgentX \xB7 Workflows",activeTab:"workflows",subtitle:"Workflows",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Wm,scripts:`<script>${q({workflowHealth:Vn})}${Gm}</script>`})}var Wm=`
14218
14218
  .ax-wf__root {
14219
14219
  display: grid;
14220
14220
  grid-template-columns: 340px 1fr;
@@ -14598,7 +14598,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14598
14598
  font-size: 12px; z-index: 50;
14599
14599
  }
14600
14600
  .hint { color: var(--ax-muted); font-size: 11px; }
14601
- `,nm=`
14601
+ `,Gm=`
14602
14602
  (() => {
14603
14603
  const $ = (sel) => document.querySelector(sel)
14604
14604
  const $$ = (sel) => Array.from(document.querySelectorAll(sel))
@@ -15387,7 +15387,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15387
15387
  setInterval(refresh, 15000)
15388
15388
  })
15389
15389
  })();
15390
- `;function xi(t={}){let e=`<div class="ax-proc__root">
15390
+ `;function Ni(t={}){let e=`<div class="ax-proc__root">
15391
15391
  <header class="ax-proc__header">
15392
15392
  <h1>Procedures</h1>
15393
15393
  <p class="hint">Reusable building blocks workflows compose. See <a href="/admin/wiki/architecture/three-tier" target="_blank">three-tier model</a> for how this fits with System and Processes.</p>
@@ -15431,7 +15431,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15431
15431
  <p class="hint">AgentX is layered: <strong>System</strong> (agents, channels, mesh) \u2192 <strong>Processes</strong> (workflows that turn intent into work) \u2192 <strong>Procedures</strong> (this page: reusable steps a process composes). Higher tiers depend on lower; never the reverse.</p>
15432
15432
  <p class="hint">Adding a new procedure is a code change (a new <code>action.builtin</code> module under <code>src/actions/builtin/</code> or a new template YAML in <code>src/workflows/templates/</code>) \u2014 not a UI flow. This page is the read-only catalog.</p>
15433
15433
  </section>
15434
- </div>`;return M({title:"AgentX \xB7 Procedures",activeTab:"procedures",subtitle:"Procedures",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:rm,scripts:`<script>${om}</script>`})}var rm=`
15434
+ </div>`;return I({title:"AgentX \xB7 Procedures",activeTab:"procedures",subtitle:"Procedures",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Xm,scripts:`<script>${Km}</script>`})}var Xm=`
15435
15435
  .ax-proc__root { padding: 18px 24px 40px; max-width: 1100px; margin: 0 auto; color: var(--ax-text); }
15436
15436
  .ax-proc__header h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
15437
15437
  .ax-proc__header .hint { color: var(--ax-muted); font-size: 12px; margin: 0 0 18px; }
@@ -15457,7 +15457,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15457
15457
  .ax-proc__req { display: inline-block; padding: 1px 6px; font-size: 10px; font-family: var(--ax-mono); border: 1px solid color-mix(in oklch, var(--ax-warn, #f59e0b) 40%, var(--ax-border)); border-radius: 3px; color: var(--ax-warn, #f59e0b); }
15458
15458
  .ax-proc__link { color: var(--ax-accent, #6366f1); text-decoration: none; font-size: 11px; }
15459
15459
  .ax-proc__link:hover { text-decoration: underline; }
15460
- `,om=`
15460
+ `,Km=`
15461
15461
  (function(){
15462
15462
  function $(sel){ return document.querySelector(sel) }
15463
15463
  function esc(s){ return String(s||"").replace(/[&<>"']/g, function(c){ return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c] }) }
@@ -15557,24 +15557,24 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15557
15557
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bootAll)
15558
15558
  else bootAll()
15559
15559
  })();
15560
- `;function vi(t){let e=t.agentName||t.agentId,a=`<div class="ax-task-page"
15561
- data-task-id="${N(t.taskId)}"
15562
- data-agent-id="${N(t.agentId)}"
15563
- data-node-url="${N(t.nodeUrl)}"
15560
+ `;function Di(t){let e=t.agentName||t.agentId,a=`<div class="ax-task-page"
15561
+ data-task-id="${H(t.taskId)}"
15562
+ data-agent-id="${H(t.agentId)}"
15563
+ data-node-url="${H(t.nodeUrl)}"
15564
15564
  data-archived="${t.archived?"1":""}"
15565
- data-ask="${N(t.ask||"")}"
15566
- data-ask-at="${N(t.askAt||"")}">
15565
+ data-ask="${H(t.ask||"")}"
15566
+ data-ask-at="${H(t.askAt||"")}">
15567
15567
 
15568
15568
  <header class="ax-task-page__head">
15569
15569
  <nav class="ax-crumbs" aria-label="Breadcrumb">
15570
15570
  <a href="/live">Live</a>
15571
15571
  <span class="ax-crumbs__sep">/</span>
15572
- <a href="/agents/${N(t.agentId)}/history?node=${encodeURIComponent(t.nodeUrl)}&name=${encodeURIComponent(e)}"><span class="ax-mention">@${N(t.agentId)}</span></a>
15572
+ <a href="/agents/${H(t.agentId)}/history?node=${encodeURIComponent(t.nodeUrl)}&name=${encodeURIComponent(e)}"><span class="ax-mention">@${H(t.agentId)}</span></a>
15573
15573
  <span class="ax-crumbs__sep">/</span>
15574
15574
  <span class="ax-crumbs__here">Task</span>
15575
15575
  </nav>
15576
15576
  <div class="ax-task-page__meta">
15577
- ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${N(t.channel)}</span>`:""}
15577
+ ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${H(t.channel)}</span>`:""}
15578
15578
  <span class="ax-badge ax-badge--mono" id="task-status">connecting\u2026</span>
15579
15579
  <span class="ax-mono ax-muted" id="task-elapsed"></span>
15580
15580
  </div>
@@ -15600,7 +15600,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15600
15600
  <button type="button" id="task-send" class="ax-btn ax-btn--primary">send \u2192</button>
15601
15601
  </div>
15602
15602
  </footer>
15603
- </div>`;return M({title:`AgentX \xB7 ${e}`,activeTab:"live",subtitle:"Task",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:sm,scripts:`<script>${im}</script>`})}var sm=`
15603
+ </div>`;return I({title:`AgentX \xB7 ${e}`,activeTab:"live",subtitle:"Task",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Jm,scripts:`<script>${Vm}</script>`})}var Jm=`
15604
15604
  /* The shell gives <main> no padding, so page content butted straight against
15605
15605
  the sticky topbar. Breathe. */
15606
15606
  .ax-task-page {
@@ -15742,7 +15742,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15742
15742
  line-height: 1.55; text-wrap: pretty; white-space: pre-wrap; word-break: break-word;
15743
15743
  }
15744
15744
 
15745
- `,im=`
15745
+ `,Vm=`
15746
15746
  (function () {
15747
15747
  var root = document.querySelector('.ax-task-page');
15748
15748
  if (!root) return;
@@ -16127,15 +16127,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
16127
16127
  });
16128
16128
 
16129
16129
  })();
16130
- `;function bi(t){let e=t.agentName||t.agentId,a=`<div class="ax-history"
16131
- data-agent-id="${N(t.agentId)}"
16132
- data-agent-name="${N(e)}"
16133
- data-node-url="${N(t.nodeUrl)}">
16130
+ `;function Hi(t){let e=t.agentName||t.agentId,a=`<div class="ax-history"
16131
+ data-agent-id="${H(t.agentId)}"
16132
+ data-agent-name="${H(e)}"
16133
+ data-node-url="${H(t.nodeUrl)}">
16134
16134
  <header class="ax-history__head">
16135
16135
  <nav class="ax-crumbs" aria-label="Breadcrumb">
16136
16136
  <a href="/live">Live</a>
16137
16137
  <span class="ax-crumbs__sep">/</span>
16138
- <span class="ax-mention">@${N(t.agentId)}</span>
16138
+ <span class="ax-mention">@${H(t.agentId)}</span>
16139
16139
  <span class="ax-crumbs__sep">/</span>
16140
16140
  <span class="ax-crumbs__here">History</span>
16141
16141
  </nav>
@@ -16156,7 +16156,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
16156
16156
  <div class="ax-history__list" id="hist-list">
16157
16157
  <div class="ax-history__empty">loading\u2026</div>
16158
16158
  </div>
16159
- </div>`;return M({title:`AgentX \xB7 ${e} history`,activeTab:"live",subtitle:"History",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:lm,scripts:`<script>${cm}</script>`})}var lm=`
16159
+ </div>`;return I({title:`AgentX \xB7 ${e} history`,activeTab:"live",subtitle:"History",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Ym,scripts:`<script>${Qm}</script>`})}var Ym=`
16160
16160
  /* <main> carries no padding in the shell \u2014 without this the breadcrumb sits
16161
16161
  flush against the sticky topbar. */
16162
16162
  .ax-history {
@@ -16208,7 +16208,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
16208
16208
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
16209
16209
  }
16210
16210
  .ax-history__foot { margin-top: 6px; font-size: var(--ax-fs-xs); color: var(--ax-muted); font-family: var(--ax-mono); }
16211
- `,cm=`
16211
+ `,Qm=`
16212
16212
  (function () {
16213
16213
  var root = document.querySelector('.ax-history');
16214
16214
  if (!root) return;
@@ -16308,26 +16308,31 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
16308
16308
  listEl.innerHTML = '<div class="ax-history__empty" style="color:var(--ax-err)">' + esc(e.message) + '</div>';
16309
16309
  });
16310
16310
  })();
16311
- `;function wi(t,e,a){let n=t.url||"";if(!n.startsWith("/api/workflows"))return!1;let r=t.method||"GET";if(n==="/api/workflows"){if(r==="GET")return a.requireScope(t,e,["dashboard:read"])?R(e,200,{workflows:a.store.list()}):!0;if(r==="POST"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let s=new URL(n,"http://_").searchParams,i=s.get("convertFromYaml")==="true"||s.get("convertFromYaml")==="1";return Ue(t,e,l=>yi(e,a,l,{mode:"create",convertFromYaml:i}))}}if(n.startsWith("/api/workflows/runs"))return r==="GET"&&!a.requireScope(t,e,["dashboard:read"])?!0:pm(t,e,a,n);if(n.startsWith("/api/workflows/signal/")){if(r!=="POST")return R(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;if(!a.dispatcher)return R(e,501,{error:"dispatcher not enabled"});let s=decodeURIComponent(n.replace(/^\/api\/workflows\/signal\//,"").split("?")[0]);return s?Ue(t,e,i=>{let l=i,c=a.dispatcher.emitSignal({name:s,scope:l?.scope,workflowId:l?.workflowId,payload:l?.payload});return R(e,200,{ok:!0,emission:c})}):R(e,400,{error:"signal name required"})}let o=n.match(/^\/api\/workflows\/([^\/?]+)(\/layout|\/validate)?(\?.*)?$/);if(o){let s=decodeURIComponent(o[1]),i=o[2];if(i==="/layout"){if(r==="GET")return a.requireScope(t,e,["dashboard:read"])?R(e,200,{layout:a.layouts.get(s)}):!0;if(r==="PUT")return a.requireScope(t,e,["dashboard:write"])?Ue(t,e,l=>{try{let c=a.layouts.save(s,l);return R(e,200,{layout:c})}catch(c){return R(e,400,{error:"invalid layout",message:c.message})}}):!0}if(i==="/validate"&&r==="POST")return a.requireScope(t,e,["dashboard:read"])?Ue(t,e,l=>{let c=ma.safeParse(l);if(!c.success)return R(e,200,{ok:!1,issues:c.error.issues.map(u=>({path:u.path.join("."),message:u.message}))});let p=fa(c.data).map(u=>({path:"",message:u}));return R(e,200,{ok:p.length===0,issues:p,workflow:c.data})}):!0;if(!i){if(r==="GET"){if(!a.requireScope(t,e,["dashboard:read"]))return!0;let l=a.store.get(s);return l?R(e,200,{workflow:l}):R(e,404,{error:"workflow not found"})}if(r==="PUT"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=new URL(n,"http://_").searchParams,c=l.get("convertFromYaml")==="true"||l.get("convertFromYaml")==="1";return Ue(t,e,p=>yi(e,a,p,{mode:"update",id:s,convertFromYaml:c}))}if(r==="DELETE"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=a.store.delete(s);return a.layouts.delete(s),R(e,l?200:404,l?{ok:!0}:{error:"workflow not found"})}}}return R(e,404,{error:"unknown workflows endpoint",path:n})}var dm=["mesh"];function yi(t,e,a,n){let r=ma.safeParse(a);if(!r.success)return R(t,400,{error:"invalid workflow",issues:r.error.issues.map(l=>({path:l.path.join("."),message:l.message}))});let o=r.data,s=fa(o);if(s.length>0)return R(t,400,{error:"lint errors",issues:s.map(l=>({path:"",message:l}))});if(n.mode==="update"&&o.id!==n.id)return R(t,400,{error:"workflow id does not match path"});if(n.mode==="create"&&e.store.get(o.id))return R(t,409,{error:`workflow "${o.id}" already exists`});if(n.mode==="update"&&a&&typeof a=="object"){let l=a,c=e.store.get(n.id);if(c)for(let p of dm)!(p in l)&&p in c&&(o[p]=c[p])}let i;try{i=e.store.save(o,{convertFromYaml:n.convertFromYaml})}catch(l){let c=l?.message||String(l),p=l?.yamlPath,u=!!p||/yaml round-trip failed/.test(c);return R(t,u?409:500,{error:u?"couldn't preserve comments while saving back to the YAML file. Re-submit with ?convertFromYaml=true to convert this workflow to JSON (comments will be lost).":c,kind:u?"yaml-authored":"save-failed",...p?{path:p}:{}})}return e.layouts.sync(i.id,i.nodes.map(l=>l.id)),R(t,200,{workflow:i})}function pm(t,e,a,n){let r=new URL(n,"http://_").searchParams,o=n.replace(/^\/api\/workflows\/runs/,"");if(o===""||o.startsWith("?")){let l=Math.max(1,Math.min(500,Number(r.get("limit")||50))),c=r.get("workflowId")||void 0,p=r.get("summary")==="1"||r.get("summary")==="true",u=a.runs.list({workflowId:c,limit:l});if(!p)return R(e,200,{runs:u});let m=u.map(h=>({id:h.id,workflowId:h.workflowId,workflowVersion:h.workflowVersion,homeNode:h.homeNode,status:h.status,pending:h.pending,entityRef:h.entityRef,history:(h.history||[]).slice(-5),parentRunId:h.parentRunId,parentNodeId:h.parentNodeId,rootRunId:h.rootRunId,depth:h.depth,createdAt:h.createdAt,updatedAt:h.updatedAt}));return R(e,200,{runs:m})}let s=o.match(/^\/([^\/?]+)\/status$/);if(s){if((t.method||"GET").toUpperCase()!=="POST")return R(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=decodeURIComponent(s[1]);return Ue(t,e,c=>{let p=c?.status;return p!=="paused"&&p!=="running"&&p!=="canceled"?R(e,400,{error:"status must be paused|running|canceled"}):a.runs.setStatus(l,p)?R(e,200,{ok:!0,runId:l,status:p}):R(e,404,{error:"run not found"})})}let i=o.match(/^\/([^\/?]+)(\/stream)?$/);if(i){let l=decodeURIComponent(i[1]);if(i[2])return um(t,e,a,l);let c=a.runs.get(l);return c?R(e,200,{run:c}):R(e,404,{error:"run not found"})}return R(e,404,{error:"unknown runs endpoint"})}function um(t,e,a,n){let r=a.runs.get(n);if(!r)return R(e,404,{error:"run not found"}),!0;e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`data: ${JSON.stringify(r)}
16311
+ `;function zi(t,e,a){let n=t.url||"";if(!n.startsWith("/api/workflows"))return!1;let r=t.method||"GET";if(n==="/api/workflows"){if(r==="GET")return a.requireScope(t,e,["dashboard:read"])?P(e,200,{workflows:a.store.list()}):!0;if(r==="POST"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let s=new URL(n,"http://_").searchParams,i=s.get("convertFromYaml")==="true"||s.get("convertFromYaml")==="1";return Ke(t,e,l=>Bi(e,a,l,{mode:"create",convertFromYaml:i}))}}if(n.startsWith("/api/workflows/runs"))return r==="GET"&&!a.requireScope(t,e,["dashboard:read"])?!0:ef(t,e,a,n);if(n.startsWith("/api/workflows/signal/")){if(r!=="POST")return P(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;if(!a.dispatcher)return P(e,501,{error:"dispatcher not enabled"});let s=decodeURIComponent(n.replace(/^\/api\/workflows\/signal\//,"").split("?")[0]);return s?Ke(t,e,i=>{let l=i,c=a.dispatcher.emitSignal({name:s,scope:l?.scope,workflowId:l?.workflowId,payload:l?.payload});return P(e,200,{ok:!0,emission:c})}):P(e,400,{error:"signal name required"})}let o=n.match(/^\/api\/workflows\/([^\/?]+)(\/layout|\/validate)?(\?.*)?$/);if(o){let s=decodeURIComponent(o[1]),i=o[2];if(i==="/layout"){if(r==="GET")return a.requireScope(t,e,["dashboard:read"])?P(e,200,{layout:a.layouts.get(s)}):!0;if(r==="PUT")return a.requireScope(t,e,["dashboard:write"])?Ke(t,e,l=>{try{let c=a.layouts.save(s,l);return P(e,200,{layout:c})}catch(c){return P(e,400,{error:"invalid layout",message:c.message})}}):!0}if(i==="/validate"&&r==="POST")return a.requireScope(t,e,["dashboard:read"])?Ke(t,e,l=>{let c=ba.safeParse(l);if(!c.success)return P(e,200,{ok:!1,issues:c.error.issues.map(p=>({path:p.path.join("."),message:p.message}))});let d=va(c.data).map(p=>({path:"",message:p}));return P(e,200,{ok:d.length===0,issues:d,workflow:c.data})}):!0;if(!i){if(r==="GET"){if(!a.requireScope(t,e,["dashboard:read"]))return!0;let l=a.store.get(s);return l?P(e,200,{workflow:l}):P(e,404,{error:"workflow not found"})}if(r==="PUT"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=new URL(n,"http://_").searchParams,c=l.get("convertFromYaml")==="true"||l.get("convertFromYaml")==="1";return Ke(t,e,d=>Bi(e,a,d,{mode:"update",id:s,convertFromYaml:c}))}if(r==="DELETE"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=a.store.delete(s);return a.layouts.delete(s),P(e,l?200:404,l?{ok:!0}:{error:"workflow not found"})}}}return P(e,404,{error:"unknown workflows endpoint",path:n})}var Zm=["mesh"];function Bi(t,e,a,n){let r=ba.safeParse(a);if(!r.success)return P(t,400,{error:"invalid workflow",issues:r.error.issues.map(l=>({path:l.path.join("."),message:l.message}))});let o=r.data,s=va(o);if(s.length>0)return P(t,400,{error:"lint errors",issues:s.map(l=>({path:"",message:l}))});if(n.mode==="update"&&o.id!==n.id)return P(t,400,{error:"workflow id does not match path"});if(n.mode==="create"&&e.store.get(o.id))return P(t,409,{error:`workflow "${o.id}" already exists`});if(n.mode==="update"&&a&&typeof a=="object"){let l=a,c=e.store.get(n.id);if(c)for(let d of Zm)!(d in l)&&d in c&&(o[d]=c[d])}let i;try{i=e.store.save(o,{convertFromYaml:n.convertFromYaml})}catch(l){let c=l?.message||String(l),d=l?.yamlPath,p=!!d||/yaml round-trip failed/.test(c);return P(t,p?409:500,{error:p?"couldn't preserve comments while saving back to the YAML file. Re-submit with ?convertFromYaml=true to convert this workflow to JSON (comments will be lost).":c,kind:p?"yaml-authored":"save-failed",...d?{path:d}:{}})}return e.layouts.sync(i.id,i.nodes.map(l=>l.id)),P(t,200,{workflow:i})}function ef(t,e,a,n){let r=new URL(n,"http://_").searchParams,o=n.replace(/^\/api\/workflows\/runs/,"");if(o===""||o.startsWith("?")){let l=Math.max(1,Math.min(500,Number(r.get("limit")||50))),c=r.get("workflowId")||void 0,d=r.get("summary")==="1"||r.get("summary")==="true",p=a.runs.list({workflowId:c,limit:l});if(!d)return P(e,200,{runs:p});let m=p.map(f=>({id:f.id,workflowId:f.workflowId,workflowVersion:f.workflowVersion,homeNode:f.homeNode,status:f.status,pending:f.pending,entityRef:f.entityRef,history:(f.history||[]).slice(-5),parentRunId:f.parentRunId,parentNodeId:f.parentNodeId,rootRunId:f.rootRunId,depth:f.depth,createdAt:f.createdAt,updatedAt:f.updatedAt}));return P(e,200,{runs:m})}let s=o.match(/^\/([^\/?]+)\/status$/);if(s){if((t.method||"GET").toUpperCase()!=="POST")return P(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=decodeURIComponent(s[1]);return Ke(t,e,c=>{let d=c?.status;return d!=="paused"&&d!=="running"&&d!=="canceled"?P(e,400,{error:"status must be paused|running|canceled"}):a.runs.setStatus(l,d)?P(e,200,{ok:!0,runId:l,status:d}):P(e,404,{error:"run not found"})})}let i=o.match(/^\/([^\/?]+)(\/stream)?$/);if(i){let l=decodeURIComponent(i[1]);if(i[2])return tf(t,e,a,l);let c=a.runs.get(l);return c?P(e,200,{run:c}):P(e,404,{error:"run not found"})}return P(e,404,{error:"unknown runs endpoint"})}function tf(t,e,a,n){let r=a.runs.get(n);if(!r)return P(e,404,{error:"run not found"}),!0;e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`data: ${JSON.stringify(r)}
16312
16312
 
16313
- `);let o=!1,s=()=>{o=!0,l?.(),clearInterval(p);try{e.end()}catch{}};t.on("close",s);let i=u=>{if(!o)try{e.write(`data: ${JSON.stringify(u)}
16313
+ `);let o=!1,s=()=>{o=!0,l?.(),clearInterval(d);try{e.end()}catch{}};t.on("close",s);let i=p=>{if(!o)try{e.write(`data: ${JSON.stringify(p)}
16314
16314
 
16315
- `)}catch{s()}},l=a.runEvents?.subscribe(n,i),c=r.updatedAt,p=setInterval(()=>{if(o)return;let u=a.runs.get(n);u&&u.updatedAt!==c&&(c=u.updatedAt,i(u))},2e3);return!0}function Ue(t,e,a){let n="";return t.setEncoding("utf8"),t.on("data",r=>{n+=r}),t.on("end",()=>{let r;try{r=n?JSON.parse(n):{}}catch(s){R(e,400,{error:"invalid JSON body",message:s.message});return}let o;try{o=a(r)}catch(s){try{R(e,500,{error:"handler threw (sync)",message:s?.message??String(s)})}catch{}return}Promise.resolve(o).catch(s=>{try{R(e,500,{error:"handler threw",message:s?.message??String(s)})}catch{}})}),t.on("error",r=>R(e,400,{error:"body read failed",message:r.message})),!0}function R(t,e,a){return t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a)),!0}import{readFileSync as Wm}from"fs";import{createRequire as Gm}from"module";var mm=2048,ki=/^[A-Za-z0-9_-]{8,256}$/;async function _i(t,e,a,n,r,o){if(a!=="/api/app/push"&&!a.startsWith("/api/app/push/")&&a!=="/api/app/alerts")return!1;let s=o.store(),i=s?o.publicKey():null,l=s?i?void 0:"This computer has no push keys yet. On it, run: agentx app push-keys":o.reason??"Notifications are not set up on this computer.";if(n==="GET"&&a==="/api/app/push")return Y(e,200,{available:!l,reason:l??null,publicKey:i,subscriptions:s&&i?s.list(r.id).filter(h=>h.publicKey===i).length:0,...s?s.prefs.all(r.id):fm()});if(n==="GET"&&a==="/api/app/alerts")return Y(e,200,{items:s?s.recent(o.keepRecent,r.id):[]});if(n!=="POST"||a!=="/api/app/push/subscribe"&&a!=="/api/app/push/unsubscribe"&&a!=="/api/app/push/prefs")return Y(e,404,{error:"not found"});if(!s||l)return Y(e,503,{error:l});let c;try{c=await _t(t)}catch(h){return Y(e,400,{error:h.message})}if(a==="/api/app/push/prefs"){let h=Object.keys(ce).filter(g=>c[ce[g].field]!==void 0),_=h.map(g=>ce[g].field).join(", "),v=Object.values(ce).map(g=>g.field).join(" or ");if(h.length===0)return Y(e,400,{error:`send ${v}, true or false`});if(h.some(g=>typeof c[ce[g].field]!="boolean"))return Y(e,400,{error:`${_} must be true or false`});let S={};for(let g of h)s.prefs.set(r.id,g,c[ce[g].field]),S[ce[g].field]=c[ce[g].field];return Y(e,200,{ok:!0,...S})}let p=hm(c.endpoint,o.allowedHosts);if(!p){let h="";try{h=new URL(String(c.endpoint)).hostname}catch{}return Y(e,400,{error:`not a known push service${h?`: ${h}`:""} (see channels.push.allowedHosts)`})}if(a==="/api/app/push/unsubscribe")return Y(e,200,{ok:!0,removed:s.unsubscribe(p,r.id)});let u=c.keys?.p256dh,m=c.keys?.auth;return typeof u!="string"||!ki.test(u)||typeof m!="string"||!ki.test(m)?Y(e,400,{error:"keys.p256dh and keys.auth are required"}):c.publicKey!==void 0&&c.publicKey!==i?Y(e,409,{error:"this computer's push keys changed; turn notifications on again"}):(s.subscribe({endpoint:p,p256dh:u,auth:m,deviceId:r.id,deviceName:r.name,publicKey:i}),Y(e,200,{ok:!0}))}function fm(){let t={};for(let e of Object.values(ce))t[e.field]=e.default;return t}function hm(t,e){if(typeof t!="string"||t.length>mm)return null;try{let a=new URL(t);if(a.protocol!=="https:"||a.port||a.username||a.password)return null;let n=a.hostname.toLowerCase();return e.some(o=>{let s=o.toLowerCase().replace(/^\.+|\.+$/g,"");return!!s&&(n===s||n.endsWith("."+s))})?t:null}catch{return null}}function Y(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}Sn();var Ei=50,gm=280;async function Ti(t,e,a,n,r,o){if(a!=="/api/app/announcements")return!1;if(n==="GET"){let s=o.prefs(),i=[],l=null;try{i=xm(await o.recent(Ei))}catch(c){l=String(c?.message||"unreachable").slice(0,200)}return Si(e,200,{items:i,error:l,notify:s?s.on(r.id,"announce"):!1,notifyAvailable:!!s})}return Si(e,404,{error:"not found"})}function Ai(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=process.env.MESH_TOKEN||U(t.dashboard,e),n=t.channels.push;return{async recent(r){let o=await fetch(`${e}/events/recent?kind=announce&limit=${r}`,{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(5e3)});if(!o.ok)throw new Error(`the daemon answered ${o.status}`);return(await o.json()).events??[]},prefs:()=>{if(!n.enabled||n.relayTo)return null;let r=dt();return r?new xr(r):null}}}function xm(t){let e=[];for(let a of Array.isArray(t)?t:[]){let n=a;!n||n.kind!=="announce"||typeof n.id!="string"||typeof n.at!="string"||e.push({id:n.id.slice(0,64),text:Ka(typeof n.summary=="string"?n.summary:"",gm),by:typeof n.agentId=="string"?Ka(n.agentId,100):null,node:Ka(typeof n.node=="string"?n.node:"",100),at:n.at.slice(0,40)})}return e.sort((a,n)=>(Date.parse(n.at)||0)-(Date.parse(a.at)||0)),e.slice(0,Ei)}function Ka(t,e){let a=[...t];return a.length>e?a.slice(0,e-1).join("")+"\u2026":t}function Si(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var vm="operator",bm=50,Ci=4,Ii=500;function ym(t){let e={channel:"app",chatId:t.chatId,sender:vm,...t.spoken?{via:"voice"}:{}};return t.node==="local"?{path:"/task",body:{agent:t.agent,message:t.message,stream:!0,context:e}}:{path:"/mesh/task",body:{peer:t.node,agent:t.agent,message:t.message,stream:!0,context:e}}}async function Mi(t,e,a,n){let{path:r,body:o}=ym(e),s="",i=!1,l=[],c=new Map,p=(u,m,h)=>{let _=u!=="done",v=i?{text:ht(m,_),artifacts:[]}:ft(m,le.perMessage,_),{cleanText:S,ui:g}=u==="done"?xt(v.text):{cleanText:v.text,ui:void 0},d=i?void 0:Ja(g);return{status:u,text:S,tools:l,files:v.artifacts,...d?{ui:d}:{},...h?{error:h}:{}}};try{let u=await fetch(t.url.replace(/\/+$/,"")+r,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream",...t.token?{Authorization:`Bearer ${t.token}`}:{},...t.operatorKey?{"X-AgentX-Operator":t.operatorKey}:{}},body:JSON.stringify(o),signal:a});if(!u.ok||!u.body){let m=await u.json().then(h=>h?.error).catch(()=>"");return p("error",s,m||`AgentX answered HTTP ${u.status}.`)}for await(let m of km(u.body)){n(m.event,m.data);let h=m.data??{};if(m.event==="start")i=h.rich===!1;else if(m.event==="text"&&typeof h.text=="string")s+=h.text;else if(m.event==="tool"&&h.status==="start"&&l.length<bm){let _={name:String(h.name||"tool").slice(0,80),...h.arg?{arg:String(h.arg).slice(0,80)}:{}};l.push(_),h.id&&c.set(String(h.id),_)}else if(m.event==="tool"&&h.status==="result"&&h.error===!0&&c.has(String(h.id)))c.get(String(h.id)).error=!0;else{if(m.event==="done")return p("done",typeof h.content=="string"&&h.content?h.content:s);if(m.event==="error")return p("error",s,wm(h.error))}}return a.aborted?p("stopped",s):p("error",s,"The connection to the agent closed before it answered.")}catch(u){return a.aborted?p("stopped",s):p("error",s,`Could not reach AgentX: ${u?.message||u}`)}}function wm(t){let e=String(t||"The agent could not answer.");return Ln(e)?"The agent is busy with other work. Send the message again when it is free.":e.slice(0,500)}function Ja(t){if(!t)return;let e=s=>/^https?:\/\//i.test(s)&&s.length<=2048,a={},n=(t.buttons??[]).filter(s=>e(s.url)).slice(0,8).map(s=>({label:s.label.slice(0,80),url:s.url}));n.length&&(a.buttons=n),t.poll&&(a.poll={question:t.poll.question.slice(0,300),options:t.poll.options.slice(0,10).map(s=>s.slice(0,100)),multiple:t.poll.multiple===!0}),t.media&&e(t.media.url)&&(a.media={type:t.media.type,url:t.media.url,...t.media.caption?{caption:t.media.caption.slice(0,300)}:{}});let r=(t.quickReplies??[]).slice(0,Ci).map(s=>s.slice(0,Ii));r.length&&(a.quickReplies=r);let o=(t.replies??[]).slice(0,Ci).map(s=>({label:s.label.slice(0,80),reply:s.reply.slice(0,Ii)}));return o.length&&(a.replies=o),Object.keys(a).length?a:void 0}async function*km(t){let e=t.getReader(),a=new TextDecoder,n="";try{for(;;){let{done:r,value:o}=await e.read();if(r)break;n+=a.decode(o,{stream:!0}).replace(/\r\n/g,`
16315
+ `)}catch{s()}},l=a.runEvents?.subscribe(n,i),c=r.updatedAt,d=setInterval(()=>{if(o)return;let p=a.runs.get(n);p&&p.updatedAt!==c&&(c=p.updatedAt,i(p))},2e3);return!0}function Ke(t,e,a){let n="";return t.setEncoding("utf8"),t.on("data",r=>{n+=r}),t.on("end",()=>{let r;try{r=n?JSON.parse(n):{}}catch(s){P(e,400,{error:"invalid JSON body",message:s.message});return}let o;try{o=a(r)}catch(s){try{P(e,500,{error:"handler threw (sync)",message:s?.message??String(s)})}catch{}return}Promise.resolve(o).catch(s=>{try{P(e,500,{error:"handler threw",message:s?.message??String(s)})}catch{}})}),t.on("error",r=>P(e,400,{error:"body read failed",message:r.message})),!0}function P(t,e,a){return t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a)),!0}import{readFileSync as Jf}from"fs";import{createRequire as Vf}from"module";var af=2048,qi=/^[A-Za-z0-9_-]{8,256}$/;async function Fi(t,e,a,n,r,o){if(a!=="/api/app/push"&&!a.startsWith("/api/app/push/")&&a!=="/api/app/alerts")return!1;let s=o.store(),i=s?o.publicKey():null,l=s?i?void 0:"This computer has no push keys yet. On it, run: agentx app push-keys":o.reason??"Notifications are not set up on this computer.";if(n==="GET"&&a==="/api/app/push")return Y(e,200,{available:!l,reason:l??null,publicKey:i,subscriptions:s&&i?s.list(r.id).filter(f=>f.publicKey===i).length:0,...s?s.prefs.all(r.id):nf()});if(n==="GET"&&a==="/api/app/alerts")return Y(e,200,{items:s?s.recent(o.keepRecent,r.id):[]});if(n!=="POST"||a!=="/api/app/push/subscribe"&&a!=="/api/app/push/unsubscribe"&&a!=="/api/app/push/prefs")return Y(e,404,{error:"not found"});if(!s||l)return Y(e,503,{error:l});let c;try{c=await ze(t)}catch(f){return Y(e,400,{error:f.message})}if(a==="/api/app/push/prefs"){let f=Object.keys(pe).filter(g=>c[pe[g].field]!==void 0),S=f.map(g=>pe[g].field).join(", "),b=Object.values(pe).map(g=>g.field).join(" or ");if(f.length===0)return Y(e,400,{error:`send ${b}, true or false`});if(f.some(g=>typeof c[pe[g].field]!="boolean"))return Y(e,400,{error:`${S} must be true or false`});let E={};for(let g of f)s.prefs.set(r.id,g,c[pe[g].field]),E[pe[g].field]=c[pe[g].field];return Y(e,200,{ok:!0,...E})}let d=rf(c.endpoint,o.allowedHosts);if(!d){let f="";try{f=new URL(String(c.endpoint)).hostname}catch{}return Y(e,400,{error:`not a known push service${f?`: ${f}`:""} (see channels.push.allowedHosts)`})}if(a==="/api/app/push/unsubscribe")return Y(e,200,{ok:!0,removed:s.unsubscribe(d,r.id)});let p=c.keys?.p256dh,m=c.keys?.auth;return typeof p!="string"||!qi.test(p)||typeof m!="string"||!qi.test(m)?Y(e,400,{error:"keys.p256dh and keys.auth are required"}):c.publicKey!==void 0&&c.publicKey!==i?Y(e,409,{error:"this computer's push keys changed; turn notifications on again"}):(s.subscribe({endpoint:d,p256dh:p,auth:m,deviceId:r.id,deviceName:r.name,publicKey:i}),Y(e,200,{ok:!0}))}function nf(){let t={};for(let e of Object.values(pe))t[e.field]=e.default;return t}function rf(t,e){if(typeof t!="string"||t.length>af)return null;try{let a=new URL(t);if(a.protocol!=="https:"||a.port||a.username||a.password)return null;let n=a.hostname.toLowerCase();return e.some(o=>{let s=o.toLowerCase().replace(/^\.+|\.+$/g,"");return!!s&&(n===s||n.endsWith("."+s))})?t:null}catch{return null}}function Y(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}$n();var Wi=50,of=280;async function Gi(t,e,a,n,r,o){if(a!=="/api/app/announcements")return!1;if(n==="GET"){let s=o.prefs(),i=[],l=null;try{i=sf(await o.recent(Wi))}catch(c){l=String(c?.message||"unreachable").slice(0,200)}return Ui(e,200,{items:i,error:l,notify:s?s.on(r.id,"announce"):!1,notifyAvailable:!!s})}return Ui(e,404,{error:"not found"})}function Xi(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=process.env.MESH_TOKEN||W(t.dashboard,e),n=t.channels.push;return{async recent(r){let o=await fetch(`${e}/events/recent?kind=announce&limit=${r}`,{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(5e3)});if(!o.ok)throw new Error(`the daemon answered ${o.status}`);return(await o.json()).events??[]},prefs:()=>{if(!n.enabled||n.relayTo)return null;let r=ft();return r?new Cr(r):null}}}function sf(t){let e=[];for(let a of Array.isArray(t)?t:[]){let n=a;!n||n.kind!=="announce"||typeof n.id!="string"||typeof n.at!="string"||e.push({id:n.id.slice(0,64),text:nn(typeof n.summary=="string"?n.summary:"",of),by:typeof n.agentId=="string"?nn(n.agentId,100):null,node:nn(typeof n.node=="string"?n.node:"",100),at:n.at.slice(0,40)})}return e.sort((a,n)=>(Date.parse(n.at)||0)-(Date.parse(a.at)||0)),e.slice(0,Wi)}function nn(t,e){let a=[...t];return a.length>e?a.slice(0,e-1).join("")+"\u2026":t}function Ui(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var lf="operator",cf=50,Ki=4,Ji=500;function df(t){let e={channel:"app",chatId:t.chatId,sender:lf,...t.spoken?{via:"voice"}:{}};return t.node==="local"?{path:"/task",body:{agent:t.agent,message:t.message,stream:!0,context:e}}:{path:"/mesh/task",body:{peer:t.node,agent:t.agent,message:t.message,stream:!0,context:e}}}async function Vi(t,e,a,n){let{path:r,body:o}=df(e),s="",i=!1,l=[],c=new Map,d=(p,m,f)=>{let S=p!=="done",b=i?{text:vt(m,S),artifacts:[]}:bt(m,de.perMessage,S),{cleanText:E,ui:g}=p==="done"?wt(b.text):{cleanText:b.text,ui:void 0},x=i?void 0:rn(g);return{status:p,text:E,tools:l,files:b.artifacts,...x?{ui:x}:{},...f?{error:f}:{}}};try{let p=await fetch(t.url.replace(/\/+$/,"")+r,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream",...t.token?{Authorization:`Bearer ${t.token}`}:{},...t.operatorKey?{"X-AgentX-Operator":t.operatorKey}:{}},body:JSON.stringify(o),signal:a});if(!p.ok||!p.body){let m=await p.json().then(f=>f?.error).catch(()=>"");return d("error",s,m||`AgentX answered HTTP ${p.status}.`)}for await(let m of uf(p.body)){n(m.event,m.data);let f=m.data??{};if(m.event==="start")i=f.rich===!1;else if(m.event==="text"&&typeof f.text=="string")s+=f.text;else if(m.event==="tool"&&f.status==="start"&&l.length<cf){let S={name:String(f.name||"tool").slice(0,80),...f.arg?{arg:String(f.arg).slice(0,80)}:{}};l.push(S),f.id&&c.set(String(f.id),S)}else if(m.event==="tool"&&f.status==="result"&&f.error===!0&&c.has(String(f.id)))c.get(String(f.id)).error=!0;else{if(m.event==="done")return d("done",typeof f.content=="string"&&f.content?f.content:s);if(m.event==="error")return d("error",s,pf(f.error))}}return a.aborted?d("stopped",s):d("error",s,"The connection to the agent closed before it answered.")}catch(p){return a.aborted?d("stopped",s):d("error",s,`Could not reach AgentX: ${p?.message||p}`)}}function pf(t){let e=String(t||"The agent could not answer.");return qn(e)?"The agent is busy with other work. Send the message again when it is free.":e.slice(0,500)}function rn(t){if(!t)return;let e=s=>/^https?:\/\//i.test(s)&&s.length<=2048,a={},n=(t.buttons??[]).filter(s=>e(s.url)).slice(0,8).map(s=>({label:s.label.slice(0,80),url:s.url}));n.length&&(a.buttons=n),t.poll&&(a.poll={question:t.poll.question.slice(0,300),options:t.poll.options.slice(0,10).map(s=>s.slice(0,100)),multiple:t.poll.multiple===!0}),t.media&&e(t.media.url)&&(a.media={type:t.media.type,url:t.media.url,...t.media.caption?{caption:t.media.caption.slice(0,300)}:{}});let r=(t.quickReplies??[]).slice(0,Ki).map(s=>s.slice(0,Ji));r.length&&(a.quickReplies=r);let o=(t.replies??[]).slice(0,Ki).map(s=>({label:s.label.slice(0,80),reply:s.reply.slice(0,Ji)}));return o.length&&(a.replies=o),Object.keys(a).length?a:void 0}async function*uf(t){let e=t.getReader(),a=new TextDecoder,n="";try{for(;;){let{done:r,value:o}=await e.read();if(r)break;n+=a.decode(o,{stream:!0}).replace(/\r\n/g,`
16316
16316
  `);let s;for(;(s=n.indexOf(`
16317
16317
 
16318
- `))!==-1;){let i=n.slice(0,s);n=n.slice(s+2);let l="message",c=[];for(let p of i.split(`
16319
- `))p.startsWith("event:")?l=p.slice(6).trim():p.startsWith("data:")&&c.push(p.slice(5).replace(/^ /,""));if(c.length)try{yield{event:l,data:JSON.parse(c.join(`
16320
- `))}}catch{}}}}finally{e.releaseLock()}}var Yt=class{constructor(e){this.orphanLimitMs=e}ac=new AbortController;text="";tools=[];plain=!1;orphaned=!1;startedAt=Date.now();listeners=new Map;orphanTimer=null;done=!1;broadcast(e,a){e==="start"&&(this.plain=a?.rich===!1),e==="text"&&typeof a?.text=="string"&&(this.text+=a.text),e==="tool"&&a?.status==="start"&&this.tools.length<50&&this.tools.push({name:String(a.name||"tool"),...a.arg?{arg:String(a.arg)}:{}});for(let n of this.listeners.keys())n(e,a)}watched(){return this.listeners.size>0}attach(e){let a=()=>!e.writableEnded&&!e.destroyed,n=(o,s)=>{a()&&e.write(`event: ${o}
16318
+ `))!==-1;){let i=n.slice(0,s);n=n.slice(s+2);let l="message",c=[];for(let d of i.split(`
16319
+ `))d.startsWith("event:")?l=d.slice(6).trim():d.startsWith("data:")&&c.push(d.slice(5).replace(/^ /,""));if(c.length)try{yield{event:l,data:JSON.parse(c.join(`
16320
+ `))}}catch{}}}}finally{e.releaseLock()}}var ta=class{constructor(e){this.orphanLimitMs=e}ac=new AbortController;text="";tools=[];plain=!1;orphaned=!1;startedAt=Date.now();listeners=new Map;orphanTimer=null;done=!1;broadcast(e,a){e==="start"&&(this.plain=a?.rich===!1),e==="text"&&typeof a?.text=="string"&&(this.text+=a.text),e==="tool"&&a?.status==="start"&&this.tools.length<50&&this.tools.push({name:String(a.name||"tool"),...a.arg?{arg:String(a.arg)}:{}});for(let n of this.listeners.keys())n(e,a)}watched(){return this.listeners.size>0}attach(e){let a=()=>!e.writableEnded&&!e.destroyed,n=(o,s)=>{a()&&e.write(`event: ${o}
16321
16321
  data: ${JSON.stringify(s)}
16322
16322
 
16323
16323
  `)},r=setInterval(()=>{a()&&e.write(`: ping
16324
16324
 
16325
- `)},15e3);r.unref?.(),this.listeners.set(n,e),this.orphanTimer&&(clearTimeout(this.orphanTimer),this.orphanTimer=null),e.on("close",()=>{clearInterval(r),this.listeners.delete(n),!this.done&&!this.listeners.size&&!this.ac.signal.aborted&&!this.orphanTimer&&(this.orphanTimer=setTimeout(()=>{this.orphaned=!0,this.ac.abort()},this.orphanLimitMs),this.orphanTimer.unref?.())})}finish(){this.done=!0,this.orphanTimer&&clearTimeout(this.orphanTimer);for(let e of this.listeners.values())e.writableEnded||e.end();this.listeners.clear()}};function Ri(t,e,a,n=12){let r=[],o=new Set,s=e.filter(i=>i.deviceId===t).sort((i,l)=>i.startedAt-l.startedAt);for(let i of s){if(r.length>=n)break;o.add(i.id);let l=_m(i.text);r.push({id:i.id,title:i.title,agent:i.agent,agentName:i.agentName||i.agent,...i.color?{color:i.color}:{},state:l?"answering":"thinking",preview:l||i.title.slice(0,120),updatedAt:i.startedAt})}for(let i of a){if(r.length>=n)break;o.has(i.id)||(o.add(i.id),r.push({id:i.id,title:i.title,agent:i.agent,agentName:i.agentName||i.agent,...i.color?{color:i.color}:{},state:"done",status:i.status,preview:Va(i.answer)||(i.status==="done"?"Answered.":i.status==="stopped"?"Stopped.":"The agent could not answer."),updatedAt:i.at}))}return r}function Va(t,e=120){for(let a of t.split(`
16326
- `)){let n=$i(a);if(n)return Ya(n,e)}return""}function _m(t,e=120){let a=t.split(`
16327
- `).map($i).filter(Boolean);return a.length?Ya(a[a.length-1],e):""}function $i(t){return t.replace(/^\s*(?:[#>]+|[-*+]\s|\d+\.\s)\s*/,"").replace(/[*_`]+/g,"").replace(/\s+/g," ").trim()}function Ya(t,e){let a=[...t];return a.length>e?a.slice(0,e-1).join("")+"\u2026":t}var Qt=class{constructor(e=15e3){this.windowMs=e}seen=new Map;poll(e,a=Date.now()){this.seen.set(e,a)}away(e){this.seen.delete(e)}open(e,a=Date.now()){let n=this.seen.get(e);return n!==void 0&&a-n<=this.windowMs}};function Zt(t){return t.enabled&&!t.attached&&!t.appOpen&&t.status!=="stopped"}var Li=140;function ea(t,e,a,n,r){let o=a==="error"?`Could not answer: ${Va(r||"",Li-18)||"something went wrong."}`:Va(n,Li)||"Answered.";return{deviceId:t,title:Ya(e.agentName||e.agent,80),body:o,url:`/app#chat=${e.id}`}}var ji=8e3,Em=/^[A-Za-z0-9_.:-]{1,64}$/,Re=new Map,Qa=new Map,tn=new Qt;function Oi(){return tn}async function Ni(t,e,a,n,r,o){if(a!=="/api/app/agents"&&a!=="/api/app/chat"&&a!=="/api/app/chat/stop"&&a!=="/api/app/chat/attach"&&a!=="/api/app/chat/active"&&a!=="/api/app/chat/away"&&a!=="/api/app/conversations"&&!a.startsWith("/api/app/conversations/"))return!1;let s=o.presence??tn;if(n==="GET"&&a==="/api/app/agents")return H(e,200,{nodes:await Di(o)});let i=o.store();if(!i)return H(e,503,{error:"The database on this computer is unavailable, so chats can't be saved."});if(n==="GET"&&a==="/api/app/chat/active")return s.poll(r.id),H(e,200,{conversations:Ri(r.id,Cm(),i.unread(r.id,12))});if(n==="POST"&&a==="/api/app/chat/away")return s.away(r.id),H(e,200,{ok:!0});if(n==="GET"&&a==="/api/app/conversations")return H(e,200,{conversations:i.list(r.id)});let l=n==="GET"?/^\/api\/app\/conversations\/([^/]+)$/.exec(a):null;if(l){let p=i.get(r.id,decodeURIComponent(l[1]));if(!p)return H(e,404,{error:"no such conversation"});new URL(t.url||a,"http://x").searchParams.get("peek")!=="1"&&i.markRead(r.id,p.id);let u=Re.get(p.id);return H(e,200,{...p,running:!!u,...u?{partial:{text:u.text,tools:u.tools,...u.plain?{plain:!0}:{}}}:{}})}if(n==="GET"&&a==="/api/app/chat/attach"){let p=i.get(r.id,new URL(t.url||a,"http://x").searchParams.get("conversationId")||""),u=p&&Re.get(p.id);if(!p||!u)return H(e,404,{error:"nothing is running in this conversation"});i.markRead(r.id,p.id),Hi(e);let{id:m,title:h,node:_,nodeName:v,agent:S,agentName:g}=p;return e.write(Za("conversation",{id:m,title:h,node:_,nodeName:v,agent:S,agentName:g})),e.write(Za("resume",{text:u.text,tools:u.tools,...u.plain?{plain:!0}:{}})),u.attach(e),!0}if(n!=="POST"||a!=="/api/app/chat"&&a!=="/api/app/chat/stop")return H(e,404,{error:"not found"});let c;try{c=await _t(t,64*1024)}catch(p){return H(e,400,{error:p.message})}if(a==="/api/app/chat/stop"){let p=i.get(r.id,String(c.conversationId??""));if(!p)return H(e,404,{error:"no such conversation"});let u=Re.get(p.id);return u?(u.ac.abort(),en(p,o,r.name),H(e,200,{stopped:!0})):await en(p,o,r.name)?H(e,200,{stopped:!0}):H(e,404,{error:"nothing is running in this conversation"})}return await Am(e,c,r,i,o),!0}function Tm(t,e,a){let n=We(e.url),r=new Set,o=[];for(let s of t){let i=We(s.url),l=a.find(u=>We(u.peerUrl)===i);l&&r.add(l.peer);let c=i===n,p=s.agents.length?s.agents:l?.skills??[];o.push({target:c?"local":l?l.peer:null,name:s.reachable?s.name:(c?e.name:l?.peer)||s.name,online:c?s.reachable:l?l.healthy:!1,agents:p.map(u=>{let m=Array.isArray(u.runningTasks)?u.runningTasks.length:0;return{id:u.id,name:u.name||u.id,busy:m>0||(u.active??0)>0,running:m,...u.color?{color:u.color}:{}}})})}for(let s of a)r.has(s.peer)||o.push({target:s.peer,name:s.peer,online:s.healthy,agents:(s.skills??[]).map(i=>({id:i.id,name:i.name||i.id,busy:!1,running:0}))});return o}async function Di(t){let[e,a]=await Promise.all([t.snapshot().catch(()=>({nodes:[]})),t.meshPeers().catch(()=>[])]);return Tm(e.nodes,t.daemon,a)}async function Am(t,e,a,n,r){let o=typeof e.message=="string"?e.message.trim():"";if(!o||o.length>ji){H(t,400,{error:`message must be 1\u2013${ji} characters`});return}let s;if(e.conversationId!=null){if(s=n.get(a.id,String(e.conversationId)),!s){H(t,404,{error:"no such conversation"});return}}else{let _=typeof e.node=="string"?e.node:"",v=typeof e.agent=="string"?e.agent:"";if(!Em.test(v)){H(t,400,{error:"pick an agent"});return}let S=(await Di(r)).find(d=>d.target===_);if(!S){H(t,400,{error:`unknown node "${_}"`});return}if(!S.online){H(t,409,{error:`${S.name} is offline`});return}let g=S.agents.find(d=>d.id===v);if(!g){H(t,400,{error:`no agent "${v}" on ${S.name}`});return}s=n.create(a.id,{node:_,nodeName:S.name,agent:v,agentName:g.name,...g.color?{color:g.color}:{}},o)}if(Re.has(s.id)){H(t,409,{error:"The agent is still answering in this conversation."});return}let i=new Yt(r.orphanLimitMs??18e5);Re.set(s.id,i);let{id:l,title:c,node:p,nodeName:u,agent:m,agentName:h}=s;Qa.set(l,{id:l,deviceId:a.id,title:c,agent:m,...h?{agentName:h}:{},...s.color?{color:s.color}:{}}),n.append(a.id,s.id,{role:"user",content:o,at:Date.now()}),Hi(t),t.write(Za("conversation",{id:l,title:c,node:p,nodeName:u,agent:m,agentName:h})),i.attach(t);try{let _=e.spoken===!0,v=await Mi(r.daemon,{node:p,agent:m,message:o,chatId:`app:${l}`,spoken:_},i.ac.signal,(f,x)=>i.broadcast(f,x));i.orphaned&&(v.error=`Stopped: the phone was away for more than ${Math.round((r.orphanLimitMs??18e5)/6e4)} minutes.`,en(s,r,a.name));let S=n.appendWithFiles(a.id,l,{role:"assistant",content:v.text,status:v.status,at:Date.now(),...v.error?{error:v.error}:{},...v.ui?{ui:v.ui}:{},...v.tools.length?{tools:v.tools}:{}},v.files)??[];i.broadcast("final",{status:v.status,content:v.text,...v.error?{error:v.error}:{},...v.ui?{ui:v.ui}:{},...S.length?{files:S}:{}});let g=i.watched();g&&n.markRead(a.id,l);let d={status:v.status,attached:g,appOpen:(r.presence??tn).open(a.id),enabled:!!r.finishAlerts?.(a.id)};r.notifyFinish&&Zt(d)&&r.notifyFinish(ea(a.id,s,v.status,v.text,v.error)).catch(()=>{})}finally{Re.delete(l),Qa.delete(l),i.finish()}}function Cm(){let t=[];for(let[e,a]of Qa){let n=Re.get(e);n&&t.push({...a,text:n.text,startedAt:n.startedAt})}return t}function Hi(t){t.writeHead(200,{"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-store","X-Accel-Buffering":"no"})}function Za(t,e){return`event: ${t}
16325
+ `)},15e3);r.unref?.(),this.listeners.set(n,e),this.orphanTimer&&(clearTimeout(this.orphanTimer),this.orphanTimer=null),e.on("close",()=>{clearInterval(r),this.listeners.delete(n),!this.done&&!this.listeners.size&&!this.ac.signal.aborted&&!this.orphanTimer&&(this.orphanTimer=setTimeout(()=>{this.orphaned=!0,this.ac.abort()},this.orphanLimitMs),this.orphanTimer.unref?.())})}finish(){this.done=!0,this.orphanTimer&&clearTimeout(this.orphanTimer);for(let e of this.listeners.values())e.writableEnded||e.end();this.listeners.clear()}};function Qi(t,e,a,n=12){let r=[],o=new Set,s=e.filter(i=>i.deviceId===t).sort((i,l)=>i.startedAt-l.startedAt);for(let i of s){if(r.length>=n)break;o.add(i.id);let l=mf(i.text);r.push({id:i.id,title:i.title,agent:i.agent,agentName:i.agentName||i.agent,...i.color?{color:i.color}:{},state:l?"answering":"thinking",preview:l||i.title.slice(0,120),updatedAt:i.startedAt})}for(let i of a){if(r.length>=n)break;o.has(i.id)||(o.add(i.id),r.push({id:i.id,title:i.title,agent:i.agent,agentName:i.agentName||i.agent,...i.color?{color:i.color}:{},state:"done",status:i.status,preview:on(i.answer)||(i.status==="done"?"Answered.":i.status==="stopped"?"Stopped.":"The agent could not answer."),updatedAt:i.at}))}return r}function on(t,e=120){for(let a of t.split(`
16326
+ `)){let n=Zi(a);if(n)return sn(n,e)}return""}function mf(t,e=120){let a=t.split(`
16327
+ `).map(Zi).filter(Boolean);return a.length?sn(a[a.length-1],e):""}function Zi(t){return t.replace(/^\s*(?:[#>]+|[-*+]\s|\d+\.\s)\s*/,"").replace(/[*_`]+/g,"").replace(/\s+/g," ").trim()}function sn(t,e){let a=[...t];return a.length>e?a.slice(0,e-1).join("")+"\u2026":t}var aa=class{constructor(e=15e3){this.windowMs=e}seen=new Map;poll(e,a=Date.now()){this.seen.set(e,a)}away(e){this.seen.delete(e)}open(e,a=Date.now()){let n=this.seen.get(e);return n!==void 0&&a-n<=this.windowMs}};function na(t){return t.enabled&&!t.attached&&!t.appOpen&&t.status!=="stopped"}var Yi=140;function ra(t,e,a,n,r){let o=a==="error"?`Could not answer: ${on(r||"",Yi-18)||"something went wrong."}`:on(n,Yi)||"Answered.";return{deviceId:t,title:sn(e.agentName||e.agent,80),body:o,url:`/app#chat=${e.id}`}}var tl=8e3,hf=/^[A-Za-z0-9_.:-]{1,64}$/,Ne=new Map,ln=new Map,pn=new aa;function al(){return pn}async function nl(t,e,a,n,r,o){if(a!=="/api/app/agents"&&a!=="/api/app/chat"&&a!=="/api/app/chat/stop"&&a!=="/api/app/chat/attach"&&a!=="/api/app/chat/active"&&a!=="/api/app/chat/away"&&a!=="/api/app/conversations"&&!a.startsWith("/api/app/conversations/"))return!1;let s=o.presence??pn;if(n==="GET"&&a==="/api/app/agents")return B(e,200,{nodes:await rl(o)});let i=o.store();if(!i)return B(e,503,{error:"The database on this computer is unavailable, so chats can't be saved."});if(n==="GET"&&a==="/api/app/chat/active")return s.poll(r.id),B(e,200,{conversations:Qi(r.id,bf(),i.unread(r.id,12))});if(n==="POST"&&a==="/api/app/chat/away")return s.away(r.id),B(e,200,{ok:!0});if(n==="GET"&&a==="/api/app/conversations")return B(e,200,{conversations:i.list(r.id)});let l=n==="GET"?/^\/api\/app\/conversations\/([^/]+)$/.exec(a):null;if(l){let d=i.get(r.id,decodeURIComponent(l[1]));if(!d)return B(e,404,{error:"no such conversation"});new URL(t.url||a,"http://x").searchParams.get("peek")!=="1"&&i.markRead(r.id,d.id);let p=Ne.get(d.id);return B(e,200,{...d,running:!!p,...p?{partial:{text:p.text,tools:p.tools,...p.plain?{plain:!0}:{}}}:{}})}if(n==="GET"&&a==="/api/app/chat/attach"){let d=i.get(r.id,new URL(t.url||a,"http://x").searchParams.get("conversationId")||""),p=d&&Ne.get(d.id);if(!d||!p)return B(e,404,{error:"nothing is running in this conversation"});i.markRead(r.id,d.id),ol(e);let{id:m,title:f,node:S,nodeName:b,agent:E,agentName:g}=d;return e.write(cn("conversation",{id:m,title:f,node:S,nodeName:b,agent:E,agentName:g})),e.write(cn("resume",{text:p.text,tools:p.tools,...p.plain?{plain:!0}:{}})),p.attach(e),!0}if(n!=="POST"||a!=="/api/app/chat"&&a!=="/api/app/chat/stop")return B(e,404,{error:"not found"});let c;try{c=await ze(t,64*1024)}catch(d){return B(e,400,{error:d.message})}if(a==="/api/app/chat/stop"){let d=i.get(r.id,String(c.conversationId??""));if(!d)return B(e,404,{error:"no such conversation"});let p=Ne.get(d.id);return p?(p.ac.abort(),dn(d,o,r.name),B(e,200,{stopped:!0})):await dn(d,o,r.name)?B(e,200,{stopped:!0}):B(e,404,{error:"nothing is running in this conversation"})}return await xf(e,c,r,i,o),!0}function gf(t,e,a){let n=Je(e.url),r=new Set,o=[];for(let s of t){let i=Je(s.url),l=a.find(p=>Je(p.peerUrl)===i);l&&r.add(l.peer);let c=i===n,d=s.agents.length?s.agents:l?.skills??[];o.push({target:c?"local":l?l.peer:null,name:s.reachable?s.name:(c?e.name:l?.peer)||s.name,online:c?s.reachable:l?l.healthy:!1,agents:d.map(p=>{let m=Array.isArray(p.runningTasks)?p.runningTasks.length:0;return{id:p.id,name:p.name||p.id,busy:m>0||(p.active??0)>0,running:m,...p.color?{color:p.color}:{}}})})}for(let s of a)r.has(s.peer)||o.push({target:s.peer,name:s.peer,online:s.healthy,agents:(s.skills??[]).map(i=>({id:i.id,name:i.name||i.id,busy:!1,running:0}))});return o}async function rl(t){let[e,a]=await Promise.all([t.snapshot().catch(()=>({nodes:[]})),t.meshPeers().catch(()=>[])]);return gf(e.nodes,t.daemon,a)}async function xf(t,e,a,n,r){let o=typeof e.message=="string"?e.message.trim():"";if(!o||o.length>tl){B(t,400,{error:`message must be 1\u2013${tl} characters`});return}let s;if(e.conversationId!=null){if(s=n.get(a.id,String(e.conversationId)),!s){B(t,404,{error:"no such conversation"});return}}else{let S=typeof e.node=="string"?e.node:"",b=typeof e.agent=="string"?e.agent:"";if(!hf.test(b)){B(t,400,{error:"pick an agent"});return}let E=(await rl(r)).find(x=>x.target===S);if(!E){B(t,400,{error:`unknown node "${S}"`});return}if(!E.online){B(t,409,{error:`${E.name} is offline`});return}let g=E.agents.find(x=>x.id===b);if(!g){B(t,400,{error:`no agent "${b}" on ${E.name}`});return}s=n.create(a.id,{node:S,nodeName:E.name,agent:b,agentName:g.name,...g.color?{color:g.color}:{}},o)}if(Ne.has(s.id)){B(t,409,{error:"The agent is still answering in this conversation."});return}let i=new ta(r.orphanLimitMs??18e5);Ne.set(s.id,i);let{id:l,title:c,node:d,nodeName:p,agent:m,agentName:f}=s;ln.set(l,{id:l,deviceId:a.id,title:c,agent:m,...f?{agentName:f}:{},...s.color?{color:s.color}:{}}),n.append(a.id,s.id,{role:"user",content:o,at:Date.now()}),ol(t),t.write(cn("conversation",{id:l,title:c,node:d,nodeName:p,agent:m,agentName:f})),i.attach(t);try{let S=e.spoken===!0,b=await Vi(r.daemon,{node:d,agent:m,message:o,chatId:`app:${l}`,spoken:S},i.ac.signal,(u,h)=>i.broadcast(u,h));i.orphaned&&(b.error=`Stopped: the phone was away for more than ${Math.round((r.orphanLimitMs??18e5)/6e4)} minutes.`,dn(s,r,a.name));let E=n.appendWithFiles(a.id,l,{role:"assistant",content:b.text,status:b.status,at:Date.now(),...b.error?{error:b.error}:{},...b.ui?{ui:b.ui}:{},...b.tools.length?{tools:b.tools}:{}},b.files)??[];i.broadcast("final",{status:b.status,content:b.text,...b.error?{error:b.error}:{},...b.ui?{ui:b.ui}:{},...E.length?{files:E}:{}});let g=i.watched();g&&n.markRead(a.id,l);let x={status:b.status,attached:g,appOpen:(r.presence??pn).open(a.id),enabled:!!r.finishAlerts?.(a.id)};r.notifyFinish&&na(x)&&r.notifyFinish(ra(a.id,s,b.status,b.text,b.error)).catch(()=>{})}finally{Ne.delete(l),ln.delete(l),i.finish()}}function bf(){let t=[];for(let[e,a]of ln){let n=Ne.get(e);n&&t.push({...a,text:n.text,startedAt:n.startedAt})}return t}function ol(t){t.writeHead(200,{"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-store","X-Accel-Buffering":"no"})}function cn(t,e){return`event: ${t}
16328
16328
  data: ${JSON.stringify(e)}
16329
16329
 
16330
- `}async function en(t,e,a){try{let n=We(e.daemon.url);if(t.node!=="local"){let l=(await e.meshPeers()).find(c=>c.peer===t.node);if(!l)return 0;n=We(l.peerUrl)}let s=(await e.snapshot()).nodes.find(l=>We(l.url)===n)?.agents.find(l=>l.id===t.agent)?.runningTasks?.filter(l=>l.chatId===`app:${t.id}`)??[],i=0;for(let l of s)(await e.nodePost(n,`/api/tasks/${encodeURIComponent(l.id)}/cancel`,{reason:`cancelled by operator (phone: ${a})`})).status<300&&i++;return i}catch{return 0}}function We(t){return t.replace(/\/+$/,"")}function H(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}import{Readable as Im}from"stream";var Mm=/^\/api\/app\/files\/([^/]+)$/,Lm=15e3;async function zi(t,e,a,n,r,o){let s=Mm.exec(a);if(!s)return!1;if(n!=="GET"&&n!=="HEAD")return $e(e,405,{error:"GET only"});let i=o.store();if(!i)return $e(e,503,{error:"The database on this computer is unavailable."});let l="";try{l=decodeURIComponent(s[1])}catch{}let c=i.getFile(r.id,l);if(!c)return $e(e,404,{error:"no such file"});let p=await Rm(c.node,o);if(!p)return $e(e,502,{error:`${c.node} is not linked to this computer's mesh any more.`});let u=new AbortController;e.on("close",()=>u.abort());let m=setTimeout(()=>u.abort(),Lm),h;try{let d=new URLSearchParams({agent:c.agent,file:c.path});h=await fetch(`${p.url}${Zn}?${d}`,{method:n,headers:{...p.token?{Authorization:`Bearer ${p.token}`}:{},...typeof t.headers.range=="string"?{Range:t.headers.range}:{}},signal:u.signal})}catch{return $e(e,502,{error:"The computer that made this file did not answer."})}finally{clearTimeout(m)}if(h.status!==200&&h.status!==206){let d=await h.json().then(x=>x?.error).catch(()=>""),f=[403,404,413,415,416].includes(h.status)?h.status:502;return $e(e,f,{error:d||`The computer that made this file answered HTTP ${h.status}.`})}let _=Number(h.headers.get("content-length")||0);if(_>le.bytes)return u.abort(),$e(e,413,{error:"the file is too large"});let v=h.headers.get("content-range");if(e.writeHead(h.status,{...er(c.mime,c.name,c.kind),...h.headers.get("content-length")?{"Content-Length":String(_)}:{},...h.status===206&&v?{"Content-Range":v}:{}}),n==="HEAD"||!h.body)return e.end(),!0;let S=0,g=Im.fromWeb(h.body);return g.on("data",d=>{S+=d.length,S>le.bytes&&(g.destroy(),e.destroy())}),g.on("error",()=>e.destroy()),g.pipe(e),!0}async function Rm(t,e){if(t==="local")return{url:Bi(e.daemon.url),token:e.daemon.token};let a=(await e.meshPeers().catch(()=>[])).find(r=>r.peer===t);if(!a)return null;let n=Bi(a.peerUrl);return{url:n,token:e.tokenFor?.(n)}}function Bi(t){return t.replace(/\/+$/,"")}function $e(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store","X-Content-Type-Options":"nosniff"}),t.end(JSON.stringify(a)),!0}var Fi=8e3;async function Ui(t,e,a,n,r,o){if(a!=="/api/app/voice/transcribe"&&a!=="/api/app/voice/speak")return!1;if(n!=="POST")return Q(e,405,{error:"POST"});if(a==="/api/app/voice/transcribe"){let h=String(t.headers["content-type"]||"");if(!cr(h))return Q(e,415,{error:"Send the recording as audio (webm, mp4, ogg, mp3 or wav)."});let _=lr(t.headers["x-audio-duration-ms"]);if(_)return t.resume(),Q(e,_.status,{error:_.error});let v=await Ne(t,ir.bytes);if(!v)return Q(e,413,{error:dr()});if(!v.length)return Q(e,400,{error:"The recording is empty."});let S={"Content-Type":h,"X-Audio-Duration-Ms":String(t.headers["x-audio-duration-ms"]).trim()};return qi(e,o.daemon,"/voice/transcribe",v,S,18e4)}let s,i=await Ne(t,64*1024);if(!i)return Q(e,413,{error:"request too large"});try{s=JSON.parse(i.toString("utf8")||"{}")}catch{return Q(e,400,{error:"expected JSON"})}let l=o.store();if(!l)return Q(e,503,{error:"The database on this computer is unavailable."});let c=l.get(r.id,String(s?.conversationId??""));if(!c)return Q(e,404,{error:"no such conversation"});let p=typeof s?.text=="string"?s.text.slice(0,Fi):"";if(!p.trim())return Q(e,400,{error:"text is required"});if(!Pm(c.messages,p))return Q(e,404,{error:"no such answer in this conversation"});let u=s?.announce===!0?`${c.agentName||c.agent}: ${p}`:p,m={agent:c.agent,text:u,...c.node!=="local"?{peer:c.node}:{}};return qi(e,o.daemon,"/voice/speak",Buffer.from(JSON.stringify(m)),{"Content-Type":"application/json"},9e4)}async function qi(t,e,a,n,r,o){try{let s=await fetch(e.url.replace(/\/+$/,"")+a,{method:"POST",headers:{...r,...e.token?{Authorization:`Bearer ${e.token}`}:{}},body:new Uint8Array(n),signal:AbortSignal.timeout(o)}),i=s.headers.get("content-type")||"",l=Buffer.from(await s.arrayBuffer());return s.ok&&i.startsWith("audio/")?(t.writeHead(200,{"Content-Type":i,"Content-Length":l.length,"Cache-Control":"no-store"}),t.end(l),!0):s.status===404&&Array.isArray($m(l)?.endpoints)?Q(t,503,{error:"AgentX on this computer is too old for voice. Update it."}):(t.writeHead(s.status,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(i.includes("json")?l:JSON.stringify({error:`AgentX answered HTTP ${s.status}.`})),!0)}catch(s){return Q(t,502,{error:s?.name==="TimeoutError"?"AgentX took too long to answer.":"Could not reach AgentX on this computer."})}}function Q(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}function $m(t){try{return JSON.parse(t.toString("utf8"))}catch{return null}}function Pm(t,e){return t.some(a=>a.role==="assistant"&&(a.content===e||e.length===Fi&&a.content.startsWith(e)))}var jm=new Set(["ring","offer","answer","ice","hangup"]),ta=/^[A-Za-z0-9_-]{4,64}$/,Om=128*1024;async function Wi(t,e,a,n,r){if(!a.startsWith("/api/app/camera/"))return!1;let o=r.daemon.url.replace(/\/+$/,""),s=r.daemon.token?{Authorization:`Bearer ${r.daemon.token}`}:{};if(a==="/api/app/camera/config"){if(n!=="GET")return P(e,405,{error:"GET"});try{let l=await fetch(`${o}/webrtc/config`,{headers:s,signal:AbortSignal.timeout(1e4)});if(l.status===404)return P(e,503,{error:"Calls are off on this computer. Set channels.webrtc.enabled to true in agentx.json."});if(!l.ok)return P(e,502,{error:`AgentX answered HTTP ${l.status}.`});let c=await l.json(),p=Je(r.nodeName),u=(Array.isArray(c.peers)?c.peers:[]).filter(h=>Je(String(h?.name??""))!==p),m=(Array.isArray(c.agents)?c.agents:[]).filter(h=>h&&typeof h.id=="string").map(h=>({id:h.id,name:typeof h.name=="string"&&h.name?h.name:h.id}));return P(e,200,{node:r.nodeName,iceServers:c.iceServers??[],peers:u,agents:m,camera:c.camera??null})}catch{return P(e,502,{error:"Could not reach AgentX on this computer."})}}if(a==="/api/app/camera/signal"){if(n!=="POST")return P(e,405,{error:"POST"});let l=await Ne(t,Om);if(!l)return P(e,413,{error:"signal too large"});let c;try{c=JSON.parse(l.toString("utf8")||"{}")}catch{return P(e,400,{error:"expected JSON"})}let p=Nm(c,r.nodeName);if(typeof p=="string")return P(e,400,{error:p});let u=Gi(p.to);if(u&&p.kind==="ring"){let m=await tt(o,s,"POST","/webrtc/camera/watch",{callId:p.callId,agentId:u});return P(e,m.status,m.status<300?{ok:!0,watch:m.body.watch}:{error:m.body.error})}try{let m=await fetch(`${o}/webrtc/signal/out`,{method:"POST",headers:{"Content-Type":"application/json",...s},body:JSON.stringify(p),signal:AbortSignal.timeout(15e3)}),h=await m.json().catch(()=>({}));return P(e,m.ok?200:502,m.ok?{ok:!0}:{error:h?.error||`AgentX answered HTTP ${m.status}.`})}catch{return P(e,502,{error:"Could not reach AgentX on this computer."})}}if(a==="/api/app/camera/events"){if(n!=="GET")return P(e,405,{error:"GET"});let l=new URL(t.url||"/","http://x").searchParams.get("callId")||"";return ta.test(l)?Dm(t,e,`${o}/webrtc/events?callId=${encodeURIComponent(l)}&as=${encodeURIComponent(r.nodeName)}`,s):P(e,400,{error:"callId is required"})}if(a==="/api/app/camera/look"){if(n!=="POST")return P(e,405,{error:"POST"});let l=await Ne(t,4096);if(!l)return P(e,413,{error:"note too long"});let c;try{c=JSON.parse(l.toString("utf8")||"{}")}catch{return P(e,400,{error:"expected JSON"})}let p=String(c?.callId??"");if(!ta.test(p))return P(e,400,{error:"callId is required"});let u=typeof c?.note=="string"?c.note:"",m=await tt(o,s,"POST",`/webrtc/camera/watch/${encodeURIComponent(p)}/look`,{note:u},18e4);return P(e,m.status,m.status<300?{reply:m.body.reply,frame:m.body.frame}:{error:m.body.error})}if(a==="/api/app/camera/asks"){if(n!=="GET")return P(e,405,{error:"GET"});let l=await tt(o,s,"GET","/calls/asking");if(l.status>=300)return P(e,l.status,{error:l.body.error});let c=(Array.isArray(l.body.calls)?l.body.calls:[]).map(p=>({id:p.id,agentId:p.agentId,reason:p.reason,createdAt:p.createdAt}));return P(e,200,{asks:c,ringSeconds:l.body.ringSeconds??null})}let i=/^\/api\/app\/camera\/asks\/([A-Za-z0-9_-]{4,64})\/(answer|decline)$/.exec(a);if(i){if(n!=="POST")return P(e,405,{error:"POST"});let l=await tt(o,s,"POST",`/calls/${i[1]}/${i[2]}`,{});return P(e,l.status,l.status<300?{call:l.body.call}:{error:l.body.error})}if(a==="/api/app/camera/watch"){if(n!=="GET")return P(e,405,{error:"GET"});let l=new URL(t.url||"/","http://x").searchParams.get("callId")||"";if(!ta.test(l))return P(e,400,{error:"callId is required"});let c=await tt(o,s,"GET",`/webrtc/camera/watch/${encodeURIComponent(l)}`);return P(e,c.status,c.status<300?{watch:c.body.watch}:{error:c.body.error})}return P(e,404,{error:"not found"})}function Gi(t){let e=/^bot:([A-Za-z0-9_.-]{1,80})$/.exec(t);return e?e[1]:null}async function tt(t,e,a,n,r,o=15e3){try{let s=await fetch(`${t}${n}`,{method:a,headers:{"Content-Type":"application/json",...e},body:r===void 0?void 0:JSON.stringify(r),signal:AbortSignal.timeout(o)}),i=await s.json().catch(()=>({}));return s.status===404&&typeof i?.error=="string"&&/channels\.webrtc\.enabled/.test(i.error)?{status:503,body:i}:{status:s.ok?s.status:s.status>=500?502:s.status,body:s.ok?i:{error:i?.error||`AgentX answered HTTP ${s.status}.`}}}catch{return{status:502,body:{error:"Could not reach AgentX on this computer."}}}}function Nm(t,e){let a=String(t?.kind??"");if(!jm.has(a))return"kind must be ring, offer, answer, ice or hangup";let n=String(t?.callId??"");if(!ta.test(n))return"callId must be 4 to 64 letters, digits, - or _";let r=typeof t?.to=="string"?t.to.trim():"";if(!r||r.length>100)return"to must name a machine or an agent";if(r.startsWith("bot:")&&!Gi(r))return"to must be bot:<agent id> for an agent";if(Je(r)===Je(e))return"pick another machine; this phone signals from this one";let o={kind:a,callId:n,from:e,to:r};if(a==="offer"||a==="answer"){if(typeof t.sdp!="string"||!t.sdp)return"sdp is required";o.sdp=t.sdp}if(a==="ice"){let s=t.candidate;if(!s||typeof s.candidate!="string")return"candidate is required";o.candidate={candidate:s.candidate,sdpMid:typeof s.sdpMid=="string"?s.sdpMid:null,sdpMLineIndex:typeof s.sdpMLineIndex=="number"?s.sdpMLineIndex:null,usernameFragment:typeof s.usernameFragment=="string"?s.usernameFragment:null}}return a==="ring"&&(o.reason="camera"),o}async function Dm(t,e,a,n){let r=new AbortController;t.on("close",()=>r.abort());let o;try{o=await fetch(a,{headers:{Accept:"text/event-stream",...n},signal:r.signal})}catch{return P(e,502,{error:"Could not reach AgentX on this computer."})}if(!o.ok||!o.body)return o.status===404?P(e,503,{error:"Calls are off on this computer."}):P(e,502,{error:`AgentX answered HTTP ${o.status}.`});e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-store","X-Accel-Buffering":"no"});let s=o.body.getReader();try{for(;;){let{done:i,value:l}=await s.read();if(i)break;e.write(l)}}catch{}finally{r.abort(),e.end()}return!0}function P(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var Xi=`
16330
+ `}async function dn(t,e,a){try{let n=Je(e.daemon.url);if(t.node!=="local"){let l=(await e.meshPeers()).find(c=>c.peer===t.node);if(!l)return 0;n=Je(l.peerUrl)}let s=(await e.snapshot()).nodes.find(l=>Je(l.url)===n)?.agents.find(l=>l.id===t.agent)?.runningTasks?.filter(l=>l.chatId===`app:${t.id}`)??[],i=0;for(let l of s)(await e.nodePost(n,`/api/tasks/${encodeURIComponent(l.id)}/cancel`,{reason:`cancelled by operator (phone: ${a})`})).status<300&&i++;return i}catch{return 0}}function Je(t){return t.replace(/\/+$/,"")}function B(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}import{Readable as vf}from"stream";var yf=/^\/api\/app\/files\/([^/]+)$/,wf=15e3;async function il(t,e,a,n,r,o){let s=yf.exec(a);if(!s)return!1;if(n!=="GET"&&n!=="HEAD")return De(e,405,{error:"GET only"});let i=o.store();if(!i)return De(e,503,{error:"The database on this computer is unavailable."});let l="";try{l=decodeURIComponent(s[1])}catch{}let c=i.getFile(r.id,l);if(!c)return De(e,404,{error:"no such file"});let d=await kf(c.node,o);if(!d)return De(e,502,{error:`${c.node} is not linked to this computer's mesh any more.`});let p=new AbortController;e.on("close",()=>p.abort());let m=setTimeout(()=>p.abort(),wf),f;try{let x=new URLSearchParams({agent:c.agent,file:c.path});f=await fetch(`${d.url}${dr}?${x}`,{method:n,headers:{...d.token?{Authorization:`Bearer ${d.token}`}:{},...typeof t.headers.range=="string"?{Range:t.headers.range}:{}},signal:p.signal})}catch{return De(e,502,{error:"The computer that made this file did not answer."})}finally{clearTimeout(m)}if(f.status!==200&&f.status!==206){let x=await f.json().then(h=>h?.error).catch(()=>""),u=[403,404,413,415,416].includes(f.status)?f.status:502;return De(e,u,{error:x||`The computer that made this file answered HTTP ${f.status}.`})}let S=Number(f.headers.get("content-length")||0);if(S>de.bytes)return p.abort(),De(e,413,{error:"the file is too large"});let b=f.headers.get("content-range");if(e.writeHead(f.status,{...pr(c.mime,c.name,c.kind),...f.headers.get("content-length")?{"Content-Length":String(S)}:{},...f.status===206&&b?{"Content-Range":b}:{}}),n==="HEAD"||!f.body)return e.end(),!0;let E=0,g=vf.fromWeb(f.body);return g.on("data",x=>{E+=x.length,E>de.bytes&&(g.destroy(),e.destroy())}),g.on("error",()=>e.destroy()),g.pipe(e),!0}async function kf(t,e){if(t==="local")return{url:sl(e.daemon.url),token:e.daemon.token};let a=(await e.meshPeers().catch(()=>[])).find(r=>r.peer===t);if(!a)return null;let n=sl(a.peerUrl);return{url:n,token:e.tokenFor?.(n)}}function sl(t){return t.replace(/\/+$/,"")}function De(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store","X-Content-Type-Options":"nosniff"}),t.end(JSON.stringify(a)),!0}var cl=8e3;async function dl(t,e,a,n,r,o){if(a!=="/api/app/voice/transcribe"&&a!=="/api/app/voice/speak")return!1;if(n!=="POST")return Q(e,405,{error:"POST"});if(a==="/api/app/voice/transcribe"){let f=String(t.headers["content-type"]||"");if(!yr(f))return Q(e,415,{error:"Send the recording as audio (webm, mp4, ogg, mp3 or wav)."});let S=vr(t.headers["x-audio-duration-ms"]);if(S)return t.resume(),Q(e,S.status,{error:S.error});let b=await Ce(t,br.bytes);if(!b)return Q(e,413,{error:wr()});if(!b.length)return Q(e,400,{error:"The recording is empty."});let E={"Content-Type":f,"X-Audio-Duration-Ms":String(t.headers["x-audio-duration-ms"]).trim()};return ll(e,o.daemon,"/voice/transcribe",b,E,18e4)}let s,i=await Ce(t,64*1024);if(!i)return Q(e,413,{error:"request too large"});try{s=JSON.parse(i.toString("utf8")||"{}")}catch{return Q(e,400,{error:"expected JSON"})}let l=o.store();if(!l)return Q(e,503,{error:"The database on this computer is unavailable."});let c=l.get(r.id,String(s?.conversationId??""));if(!c)return Q(e,404,{error:"no such conversation"});let d=typeof s?.text=="string"?s.text.slice(0,cl):"";if(!d.trim())return Q(e,400,{error:"text is required"});if(!Sf(c.messages,d))return Q(e,404,{error:"no such answer in this conversation"});let p=s?.announce===!0?`${c.agentName||c.agent}: ${d}`:d,m={agent:c.agent,text:p,...c.node!=="local"?{peer:c.node}:{}};return ll(e,o.daemon,"/voice/speak",Buffer.from(JSON.stringify(m)),{"Content-Type":"application/json"},9e4)}async function ll(t,e,a,n,r,o){try{let s=await fetch(e.url.replace(/\/+$/,"")+a,{method:"POST",headers:{...r,...e.token?{Authorization:`Bearer ${e.token}`}:{}},body:new Uint8Array(n),signal:AbortSignal.timeout(o)}),i=s.headers.get("content-type")||"",l=Buffer.from(await s.arrayBuffer());return s.ok&&i.startsWith("audio/")?(t.writeHead(200,{"Content-Type":i,"Content-Length":l.length,"Cache-Control":"no-store"}),t.end(l),!0):s.status===404&&Array.isArray(_f(l)?.endpoints)?Q(t,503,{error:"AgentX on this computer is too old for voice. Update it."}):(t.writeHead(s.status,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(i.includes("json")?l:JSON.stringify({error:`AgentX answered HTTP ${s.status}.`})),!0)}catch(s){return Q(t,502,{error:s?.name==="TimeoutError"?"AgentX took too long to answer.":"Could not reach AgentX on this computer."})}}function Q(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}function _f(t){try{return JSON.parse(t.toString("utf8"))}catch{return null}}function Sf(t,e){return t.some(a=>a.role==="assistant"&&(a.content===e||e.length===cl&&a.content.startsWith(e)))}var Ef=new Set(["ring","offer","answer","ice","hangup"]),Ve=/^[A-Za-z0-9_-]{4,64}$/,Tf=128*1024;async function ul(t,e,a,n,r){if(!a.startsWith("/api/app/camera/"))return!1;let o=r.daemon.url.replace(/\/+$/,""),s=r.daemon.token?{Authorization:`Bearer ${r.daemon.token}`}:{};if(a==="/api/app/camera/config"){if(n!=="GET")return M(e,405,{error:"GET"});try{let l=await fetch(`${o}/webrtc/config`,{headers:s,signal:AbortSignal.timeout(1e4)});if(l.status===404)return M(e,503,{error:"Calls are off on this computer. Set channels.webrtc.enabled to true in agentx.json."});if(!l.ok)return M(e,502,{error:`AgentX answered HTTP ${l.status}.`});let c=await l.json(),d=et(r.nodeName),p=(Array.isArray(c.peers)?c.peers:[]).filter(f=>et(String(f?.name??""))!==d),m=(Array.isArray(c.agents)?c.agents:[]).filter(f=>f&&typeof f.id=="string").map(f=>({id:f.id,name:typeof f.name=="string"&&f.name?f.name:f.id}));return M(e,200,{node:r.nodeName,iceServers:c.iceServers??[],peers:p,agents:m,camera:c.camera??null})}catch{return M(e,502,{error:"Could not reach AgentX on this computer."})}}if(a==="/api/app/camera/signal"){if(n!=="POST")return M(e,405,{error:"POST"});let l=await Ce(t,Tf);if(!l)return M(e,413,{error:"signal too large"});let c;try{c=JSON.parse(l.toString("utf8")||"{}")}catch{return M(e,400,{error:"expected JSON"})}let d=Cf(c,r.nodeName);if(typeof d=="string")return M(e,400,{error:d});let p=ml(d.to);if(p&&d.kind==="ring"){let m=await He(o,s,"POST","/webrtc/camera/watch",{callId:d.callId,agentId:p});return M(e,m.status,m.status<300?{ok:!0,watch:m.body.watch}:{error:m.body.error})}try{let m=await fetch(`${o}/webrtc/signal/out`,{method:"POST",headers:{"Content-Type":"application/json",...s},body:JSON.stringify(d),signal:AbortSignal.timeout(15e3)}),f=await m.json().catch(()=>({}));return M(e,m.ok?200:502,m.ok?{ok:!0}:{error:f?.error||`AgentX answered HTTP ${m.status}.`})}catch{return M(e,502,{error:"Could not reach AgentX on this computer."})}}if(a==="/api/app/camera/events"){if(n!=="GET")return M(e,405,{error:"GET"});let l=new URL(t.url||"/","http://x").searchParams.get("callId")||"";return Ve.test(l)?If(t,e,`${o}/webrtc/events?callId=${encodeURIComponent(l)}&as=${encodeURIComponent(r.nodeName)}`,s):M(e,400,{error:"callId is required"})}if(a==="/api/app/camera/look"){if(n!=="POST")return M(e,405,{error:"POST"});let l=await Ce(t,4096);if(!l)return M(e,413,{error:"note too long"});let c;try{c=JSON.parse(l.toString("utf8")||"{}")}catch{return M(e,400,{error:"expected JSON"})}let d=String(c?.callId??"");if(!Ve.test(d))return M(e,400,{error:"callId is required"});let p=typeof c?.note=="string"?c.note:"",m=await He(o,s,"POST",`/webrtc/camera/watch/${encodeURIComponent(d)}/look`,{note:p},18e4);return M(e,m.status,m.status<300?{reply:m.body.reply,frame:m.body.frame}:{error:m.body.error})}if(a==="/api/app/camera/stream"){if(n!=="POST")return M(e,405,{error:"POST"});let l=await pl(t,4096);if(!l)return M(e,400,{error:"expected JSON"});let c=String(l.callId??"");if(!Ve.test(c))return M(e,400,{error:"callId is required"});let d=Number(l.seconds??0);if(!Number.isFinite(d)||d<0)return M(e,400,{error:"seconds must be 0 or more"});let p=typeof l.note=="string"?l.note:"",m=await He(o,s,"POST",`/webrtc/camera/watch/${encodeURIComponent(c)}/stream`,{seconds:d,note:p});return M(e,m.status,m.status<300?{watch:m.body.watch}:{error:m.body.error})}if(a==="/api/app/camera/speak"){if(n!=="POST")return M(e,405,{error:"POST"});let l=await pl(t,4096);if(!l)return M(e,400,{error:"expected JSON"});let c=String(l.callId??"");if(!Ve.test(c))return M(e,400,{error:"callId is required"});let d=await He(o,s,"GET",`/webrtc/camera/watch/${encodeURIComponent(c)}`);if(d.status>=300)return M(e,d.status,{error:d.body.error});let p=(Array.isArray(d.body.watch?.replies)?d.body.watch.replies:[]).find(m=>m&&m.at===l.at);return!p||typeof p.text!="string"?M(e,404,{error:"no such answer on this share"}):Af(e,o,s,{agent:String(d.body.watch.agentId??""),text:p.text})}if(a==="/api/app/camera/asks"){if(n!=="GET")return M(e,405,{error:"GET"});let l=await He(o,s,"GET","/calls/asking");if(l.status>=300)return M(e,l.status,{error:l.body.error});let c=(Array.isArray(l.body.calls)?l.body.calls:[]).map(d=>({id:d.id,agentId:d.agentId,reason:d.reason,createdAt:d.createdAt}));return M(e,200,{asks:c,ringSeconds:l.body.ringSeconds??null})}let i=/^\/api\/app\/camera\/asks\/([A-Za-z0-9_-]{4,64})\/(answer|decline)$/.exec(a);if(i){if(n!=="POST")return M(e,405,{error:"POST"});let l=await He(o,s,"POST",`/calls/${i[1]}/${i[2]}`,{});return M(e,l.status,l.status<300?{call:l.body.call}:{error:l.body.error})}if(a==="/api/app/camera/watch"){if(n!=="GET")return M(e,405,{error:"GET"});let l=new URL(t.url||"/","http://x").searchParams.get("callId")||"";if(!Ve.test(l))return M(e,400,{error:"callId is required"});let c=await He(o,s,"GET",`/webrtc/camera/watch/${encodeURIComponent(l)}`);return M(e,c.status,c.status<300?{watch:c.body.watch}:{error:c.body.error})}return M(e,404,{error:"not found"})}function ml(t){let e=/^bot:([A-Za-z0-9_.-]{1,80})$/.exec(t);return e?e[1]:null}async function He(t,e,a,n,r,o=15e3){try{let s=await fetch(`${t}${n}`,{method:a,headers:{"Content-Type":"application/json",...e},body:r===void 0?void 0:JSON.stringify(r),signal:AbortSignal.timeout(o)}),i=await s.json().catch(()=>({}));return s.status===404&&typeof i?.error=="string"&&/channels\.webrtc\.enabled/.test(i.error)?{status:503,body:i}:{status:s.ok?s.status:s.status>=500?502:s.status,body:s.ok?i:{error:i?.error||`AgentX answered HTTP ${s.status}.`}}}catch{return{status:502,body:{error:"Could not reach AgentX on this computer."}}}}async function pl(t,e){let a=await Ce(t,e);if(!a)return null;try{let n=JSON.parse(a.toString("utf8")||"{}");return n&&typeof n=="object"&&!Array.isArray(n)?n:null}catch{return null}}async function Af(t,e,a,n){try{let r=await fetch(`${e}/voice/speak`,{method:"POST",headers:{"Content-Type":"application/json",...a},body:JSON.stringify(n),signal:AbortSignal.timeout(9e4)}),o=r.headers.get("content-type")||"";if(r.ok&&o.startsWith("audio/")){let i=Buffer.from(await r.arrayBuffer());return t.writeHead(200,{"Content-Type":o,"Content-Length":String(i.length),"Cache-Control":"no-store"}),t.end(i),!0}let s=await r.json().catch(()=>({}));return r.ok||typeof s?.text=="string"?M(t,200,{text:typeof s?.text=="string"?s.text:n.text}):M(t,200,{text:n.text,error:s?.error||`AgentX answered HTTP ${r.status}.`})}catch{return M(t,200,{text:n.text,error:"Could not reach AgentX on this computer."})}}function Cf(t,e){let a=String(t?.kind??"");if(!Ef.has(a))return"kind must be ring, offer, answer, ice or hangup";let n=String(t?.callId??"");if(!Ve.test(n))return"callId must be 4 to 64 letters, digits, - or _";let r=typeof t?.to=="string"?t.to.trim():"";if(!r||r.length>100)return"to must name a machine or an agent";if(r.startsWith("bot:")&&!ml(r))return"to must be bot:<agent id> for an agent";if(et(r)===et(e))return"pick another machine; this phone signals from this one";let o={kind:a,callId:n,from:e,to:r};if(a==="offer"||a==="answer"){if(typeof t.sdp!="string"||!t.sdp)return"sdp is required";o.sdp=t.sdp}if(a==="ice"){let s=t.candidate;if(!s||typeof s.candidate!="string")return"candidate is required";o.candidate={candidate:s.candidate,sdpMid:typeof s.sdpMid=="string"?s.sdpMid:null,sdpMLineIndex:typeof s.sdpMLineIndex=="number"?s.sdpMLineIndex:null,usernameFragment:typeof s.usernameFragment=="string"?s.usernameFragment:null}}return a==="ring"&&(o.reason="camera"),o}async function If(t,e,a,n){let r=new AbortController;t.on("close",()=>r.abort());let o;try{o=await fetch(a,{headers:{Accept:"text/event-stream",...n},signal:r.signal})}catch{return M(e,502,{error:"Could not reach AgentX on this computer."})}if(!o.ok||!o.body)return o.status===404?M(e,503,{error:"Calls are off on this computer."}):M(e,502,{error:`AgentX answered HTTP ${o.status}.`});e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-store","X-Accel-Buffering":"no"});let s=o.body.getReader();try{for(;;){let{done:i,value:l}=await s.read();if(i)break;e.write(l)}}catch{}finally{r.abort(),e.end()}return!0}function M(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}import{mkdirSync as Mf,readFileSync as Lf,renameSync as Rf,writeFileSync as Pf}from"fs";import{dirname as $f,isAbsolute as jf,resolve as Of}from"path";import{randomBytes as Nf}from"crypto";var fl=60,hl=500,Df=200,bl=/^[a-z]{2,5}_[a-z0-9]{6,32}$/,Hf=/^[A-Za-z0-9_-]{8,64}$/,Bf=/^[A-Za-z0-9._-]{1,64}$/;function vl(t,e){return jf(e)?e:Of(t,e)}function gl(t){return`${t}_${Nf(6).toString("hex")}`}function xl(){return{places:[],rules:[],seen:[]}}function yl(t,e){let a=typeof t.name=="string"?t.name.trim():"";if(!a)return{ok:!1,error:"Give the place a name."};if([...a].length>fl)return{ok:!1,error:`Keep the name under ${fl} characters.`};let n=Number(t.lat),r=Number(t.lng);if(t.lat===void 0||t.lat===""||!Number.isFinite(n)||n<-90||n>90)return{ok:!1,error:"Latitude must be a number from -90 to 90."};if(t.lng===void 0||t.lng===""||!Number.isFinite(r)||r<-180||r>180)return{ok:!1,error:"Longitude must be a number from -180 to 180."};let o=t.radius===void 0||t.radius===""?e.defaultRadiusMeters:Math.round(Number(t.radius));if(!Number.isFinite(o)||o<e.minRadiusMeters||o>e.maxRadiusMeters)return{ok:!1,error:`The radius must be from ${e.minRadiusMeters} to ${e.maxRadiusMeters} metres.`};let s=i=>Math.round(i*1e6)/1e6;return{ok:!0,value:{name:a,lat:s(n),lng:s(r),radius:o}}}function wl(t,e){let a=typeof t.placeId=="string"?t.placeId:"";if(!bl.test(a))return{ok:!1,error:"Pick a place."};let n=t.on===void 0?"enter":t.on;if(n!=="enter"&&n!=="exit")return{ok:!1,error:"on must be enter or exit."};let r=typeof t.text=="string"?t.text.trim():"";if(!r)return{ok:!1,error:"Write what to remind you of."};if([...r].length>hl)return{ok:!1,error:`Keep it under ${hl} characters.`};let o=typeof t.agent=="string"?t.agent.trim():"";return o&&(!Bf.test(o)||!e(o))?{ok:!1,error:`There is no agent called ${o.slice(0,64)} on this computer.`}:t.repeat!==void 0&&typeof t.repeat!="boolean"?{ok:!1,error:"repeat must be true or false."}:{ok:!0,value:{placeId:a,on:n,text:r,...o?{agent:o}:{},repeat:t.repeat===!0}}}function kl(t){let e=typeof t.id=="string"?t.id:"";if(!Hf.test(e))return{ok:!1,error:"id must be 8 to 64 letters, digits, - or _"};let a=typeof t.place=="string"?t.place:"";if(!bl.test(a))return{ok:!1,error:"place must be a place id"};let n=t.transition;if(n!=="enter"&&n!=="exit")return{ok:!1,error:"transition must be enter or exit"};let r=typeof t.time=="number"?t.time:typeof t.time=="string"?Date.parse(t.time):NaN;return Number.isFinite(r)?{ok:!0,value:{id:e,place:a,transition:n,time:r}}:{ok:!1,error:"time must be a timestamp"}}var oa=class{constructor(e,a=Date.now){this.path=e;this.now=a}read(){try{let e=JSON.parse(Lf(this.path,"utf-8"));return!e||typeof e!="object"?xl():{places:Array.isArray(e.places)?e.places:[],rules:Array.isArray(e.rules)?e.rules:[],seen:Array.isArray(e.seen)?e.seen.filter(a=>typeof a=="string"):[]}}catch{return xl()}}write(e){Mf($f(this.path),{recursive:!0});let a=`${this.path}.${process.pid}.tmp`;Pf(a,JSON.stringify(e,null,2)+`
16331
+ `,{mode:384}),Rf(a,this.path)}addPlace(e,a){let n=this.read();if(n.places.length>=a.maxPlaces)return{ok:!1,error:`You already have ${a.maxPlaces} places, the most allowed (app.places.maxPlaces). Remove one first.`};if(n.places.some(o=>o.name.toLowerCase()===e.name.toLowerCase()))return{ok:!1,error:`You already have a place called ${e.name}.`};let r={id:gl("pl"),...e,createdAt:new Date(this.now()).toISOString()};return n.places.push(r),this.write(n),{ok:!0,place:r}}removePlace(e){let a=this.read(),n=a.places.length;return a.places=a.places.filter(r=>r.id!==e),a.places.length===n?!1:(a.rules=a.rules.filter(r=>r.placeId!==e),this.write(a),!0)}addRule(e,a){let n=this.read();if(!n.places.some(o=>o.id===e.placeId))return{ok:!1,error:"That place doesn't exist any more."};if(n.rules.filter(o=>o.placeId===e.placeId).length>=a.maxRulesPerPlace)return{ok:!1,error:`That place already has ${a.maxRulesPerPlace} reminders, the most allowed (app.places.maxRulesPerPlace).`};let r={id:gl("pr"),...e,enabled:!0,createdAt:new Date(this.now()).toISOString()};return n.rules.push(r),this.write(n),{ok:!0,rule:r}}setRuleEnabled(e,a){let n=this.read(),r=n.rules.find(o=>o.id===e);return r?(r.enabled=a,this.write(n),r):null}removeRule(e){let a=this.read(),n=a.rules.length;return a.rules=a.rules.filter(r=>r.id!==e),a.rules.length===n?!1:(this.write(a),!0)}accept(e,a){let n=this.read();if(n.seen.includes(e.id))return{status:"duplicate"};n.seen=[...n.seen,e.id].slice(-Df);let r=this.now(),o=n.places.find(i=>i.id===e.place),s;if(!o)s={status:"unknown-place"};else if(e.time<r-a.maxEventAgeMinutes*6e4)s={status:"too-old"};else{let i=a.cooldownMinutes*6e4,l=n.rules.filter(c=>c.placeId===o.id&&c.on===e.transition&&c.enabled&&!(c.lastFiredAt&&Date.parse(c.lastFiredAt)>r-i));for(let c of l)c.lastFiredAt=new Date(r).toISOString(),c.repeat||(c.enabled=!1);s=l.length?{status:"fired",place:o,rules:l.map(c=>({...c}))}:{status:"no-rules"}}return this.write(n),s}};On();function zf(t,e){return e==="enter"?`Arrived at ${t.name}`:`Left ${t.name}`}function qf(t,e,a){let n=new Date(a).toISOString().slice(0,16).replace("T"," ")+" UTC";return[`[Place reminder \xB7 ${e.on==="enter"?"the owner arrived at":"the owner left"} ${t.name} \xB7 ${n}]`,e.text,"","Your answer is sent to the owner's phone as a notification. Keep it short."].join(`
16332
+ `)}async function _l(t,e,a,n,r){await Promise.all(a.map(async o=>{let s=zf(e,o.on),i=o.text;if(o.agent)try{i=(await r.task(o.agent,qf(e,o,n),o.id)).trim()||`${o.agent} had nothing to add.`}catch(l){i=`${o.text}
16333
+
16334
+ (${o.agent} couldn't run this: ${String(l?.message||l).slice(0,160)})`}try{await r.push(t,s,i),r.log(`[places] ${o.id} on ${e.id}: pushed to ${t}`)}catch(l){r.log(`[places] ${o.id} on ${e.id}: push failed: ${String(l?.message||l).slice(0,200)}`)}}))}function Sl(t,e=console.error){let a=t.url.replace(/\/+$/,""),n={"Content-Type":"application/json",...t.token?{Authorization:`Bearer ${t.token}`}:{}};return{async push(r,o,s){let i=await fetch(a+"/channel/send",{method:"POST",headers:n,body:JSON.stringify({channel:"push",chatId:r,text:`${o}
16335
+ ${s}`,buttons:[{label:"Open",url:"/app#alerts"}]}),signal:AbortSignal.timeout(15e3)});if(!i.ok)throw new Error(`HTTP ${i.status} ${(await i.text().catch(()=>"")).slice(0,160)}`)},async task(r,o,s){let i=await fetch(a+"/task",{method:"POST",headers:{...n,...t.operatorKey?{[jn]:t.operatorKey}:{}},body:JSON.stringify({agent:r,message:o,context:{channel:"app",chatId:`place:${s}`,sender:"places"}}),signal:AbortSignal.timeout(6e5)}),l=await i.json().catch(()=>({}));if(!i.ok||l.error)throw new Error(String(l.error||`HTTP ${i.status}`));return String(l.content??"")},log:e}}async function El(t,e,a,n,r,o){return a!=="/api/app/places"&&!a.startsWith("/api/app/places/")?!1:Al(t,e,a.slice(15),n,o,r)}async function Tl(t,e,a,n,r){return a!=="/api/places"&&!a.startsWith("/api/places/")?!1:Al(t,e,a.slice(11),n,r,null)}async function Al(t,e,a,n,r,o){if(n==="GET"&&a===""){let i=r.enabled?r.store.read():{places:[],rules:[]};return z(e,200,{enabled:r.enabled,reason:r.enabled?null:"Place reminders are off on this computer (app.places.enabled).",pushAvailable:!!r.fire,pushReason:r.fire?null:r.pushReason??null,limits:{defaultRadiusMeters:r.limits.defaultRadiusMeters,minRadiusMeters:r.limits.minRadiusMeters,maxRadiusMeters:r.limits.maxRadiusMeters,maxPlaces:r.limits.maxPlaces},syncMinutes:r.syncMinutes,android:{packageName:r.androidPackage},places:i.places,rules:i.rules,agents:r.agents()})}if(n!=="POST")return z(e,404,{error:"not found"});if(!r.enabled)return z(e,403,{error:"Place reminders are off on this computer (app.places.enabled)."});let s;try{s=await ze(t,4096)}catch(i){return z(e,400,{error:i.message})}if(a==="/event"){if(!o)return z(e,404,{error:"not found"});let i=kl(s);if(!i.ok)return z(e,400,{error:i.error});let l=r.store.accept(i.value,r.limits);return r.log(`[places] ${o.id} ${i.value.transition} ${i.value.place}: ${l.status}${l.status==="fired"?` (${l.rules.length})`:""}`),l.status==="fired"&&(r.fire?_l(o.id,l.place,l.rules,i.value.time,r.fire).catch(c=>r.log(`[places] delivery failed: ${c?.message||c}`)):r.log(`[places] ${l.rules.length} reminder(s) not sent: ${r.pushReason??"this computer doesn't send pushes"}`)),z(e,202,{ok:!0,status:l.status,fired:l.status==="fired"?l.rules.length:0})}if(a==="/add"){let i=yl(s,r.limits);if(!i.ok)return z(e,400,{error:i.error});let l=r.store.addPlace(i.value,r.limits);return l.ok?z(e,200,{ok:!0,place:l.place}):z(e,409,{error:l.error})}if(a==="/remove"){let i=typeof s.id=="string"?s.id:"";return r.store.removePlace(i)?z(e,200,{ok:!0}):z(e,404,{error:"No such place."})}if(a==="/rules/add"){let i=new Set(r.agents()),l=wl(s,d=>i.has(d));if(!l.ok)return z(e,400,{error:l.error});let c=r.store.addRule(l.value,r.limits);return c.ok?z(e,200,{ok:!0,rule:c.rule}):z(e,409,{error:c.error})}if(a==="/rules/enable"){if(typeof s.enabled!="boolean")return z(e,400,{error:"enabled must be true or false"});let i=r.store.setRuleEnabled(typeof s.id=="string"?s.id:"",s.enabled);return i?z(e,200,{ok:!0,rule:i}):z(e,404,{error:"No such reminder."})}if(a==="/rules/remove"){let i=typeof s.id=="string"?s.id:"";return r.store.removeRule(i)?z(e,200,{ok:!0}):z(e,404,{error:"No such reminder."})}return z(e,404,{error:"not found"})}function Cl(t,e,a,n){let r=t.app.places;return{enabled:r.enabled,limits:r,syncMinutes:r.syncMinutes,store:new oa(vl(e,r.file)),agents:()=>Object.keys(t.agents||{}).sort(),fire:a,pushReason:n,androidPackage:t.app.android.packageName,log:o=>console.error(o)}}function Il(t){let e=t.app.android;return e.certFingerprints.length?[{relation:["delegate_permission/common.handle_all_urls"],target:{namespace:"android_app",package_name:e.packageName,sha256_cert_fingerprints:e.certFingerprints.map(a=>a.toUpperCase())}}]:null}function z(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var Ml=`
16331
16336
  :root {
16332
16337
  --ax-bg: #fff; --ax-surface: #fff; --ax-surface-2: #f4f5f7; --ax-surface-3: #f6f7f9;
16333
16338
  --ax-text: #0b0d10; --ax-text-2: #5a616c; --ax-border: #e5e7eb;
@@ -16341,7 +16346,7 @@ data: ${JSON.stringify(e)}
16341
16346
  --ax-accent: #6aa0ff; --ax-accent-2: #6aa0ff; --ax-accent-t: #1c2b47;
16342
16347
  --phone-bubble: #1d2f52; --phone-green: #3dbe74;
16343
16348
  }
16344
- `,Ki=`
16349
+ `,Ll=`
16345
16350
  [hidden] { display: none !important; }
16346
16351
  main > .sw-peek[hidden] { display: block !important; }
16347
16352
  main > #panel-chat.sw-peek[hidden] { display: flex !important; }
@@ -16447,7 +16452,7 @@ main > #panel-chat.sw-peek { height: 100%; padding-top: 8px; }
16447
16452
  @media (max-width: 360px) { #cam-btn span { display: none; } .bar { padding-left: 12px; } .bar-btns { gap: 4px; } .vx-row { gap: 24px; } }
16448
16453
  @media (max-height: 540px) { .vx { gap: 4px; padding-top: 4px; } .cx-top { padding-bottom: 4px; } }
16449
16454
  @media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; transition: none !important; animation: none !important; } }
16450
- `;var Ji=`
16455
+ `;var Rl=`
16451
16456
  window.AXSheet = function (sheet, onClose) {
16452
16457
  var handle = document.createElement('button');
16453
16458
  handle.type = 'button'; handle.className = 'sheet-handle';
@@ -16476,7 +16481,7 @@ window.AXSheet = function (sheet, onClose) {
16476
16481
  handle.addEventListener('pointercancel', reset);
16477
16482
  sheet.addEventListener('close', function () { reset(); if (onClose) onClose(); });
16478
16483
  };
16479
- `;var Vi=`
16484
+ `;var Pl=`
16480
16485
  (function () {
16481
16486
  var fleetPanel = document.getElementById('panel-fleet');
16482
16487
  var activityPanel = document.getElementById('panel-activity');
@@ -16725,7 +16730,7 @@ window.AXSheet = function (sheet, onClose) {
16725
16730
  setInterval(refresh, 15000);
16726
16731
  refresh();
16727
16732
  })();
16728
- `;var Yi=`
16733
+ `;var $l=`
16729
16734
  .fx-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
16730
16735
  .fx-head h2 { margin: 4px 0 0; }
16731
16736
  .fx-sub { font-size: 15px; margin: 18px 0 8px; color: var(--ax-text-2); }
@@ -16782,7 +16787,7 @@ details[open] > summary::before { transform: rotate(90deg); }
16782
16787
  }
16783
16788
  .fx-error:empty { display: none; }
16784
16789
  .fx-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
16785
- `;var Qi=`
16790
+ `;var jl=`
16786
16791
  (function () {
16787
16792
  var panel = document.getElementById('panel-alerts');
16788
16793
  if (!panel) return;
@@ -16993,7 +16998,173 @@ details[open] > summary::before { transform: rotate(90deg); }
16993
16998
  refresh();
16994
16999
  loadRecent();
16995
17000
  })();
16996
- `;var Zi=`
17001
+ `;var Ol=`
17002
+ (function () {
17003
+ var panel = document.getElementById('panel-alerts');
17004
+ if (!panel) return;
17005
+ var card = document.createElement('div');
17006
+ card.className = 'fx-card pl-card';
17007
+ card.id = 'pl-card';
17008
+ card.innerHTML = '<div class="fx-row"><h3>Places</h3><span id="pl-pill" class="fx-pill"></span></div>' +
17009
+ '<p id="pl-text" class="fx-muted">Checking\u2026</p>' +
17010
+ '<p id="pl-shell" class="fx-muted" hidden></p>' +
17011
+ '<ul id="pl-list" class="fx-list pl-list"></ul>' +
17012
+ '<details id="pl-add-wrap" class="pl-add" hidden><summary class="fx-btn">Add a place</summary>' +
17013
+ '<form id="pl-add" autocomplete="off">' +
17014
+ '<label><span>Name</span><input name="name" required maxlength="60" placeholder="School"></label>' +
17015
+ '<button type="button" id="pl-here" class="fx-btn">Use where I am now</button>' +
17016
+ '<label><span>Latitude, longitude</span><input name="coords" required inputmode="decimal" placeholder="48.8584, 2.2945"></label>' +
17017
+ '<label><span>Radius in metres</span><input name="radius" type="number" inputmode="numeric" step="10"></label>' +
17018
+ '<div class="fx-actions"><button type="submit" class="fx-btn fx-primary">Save place</button></div>' +
17019
+ '</form></details>' +
17020
+ '<p id="pl-error" class="fx-error fx-bad" role="alert"></p>';
17021
+ var head = document.getElementById('al-recent-head');
17022
+ panel.insertBefore(card, head || null);
17023
+
17024
+ var pill = document.getElementById('pl-pill');
17025
+ var text = document.getElementById('pl-text');
17026
+ var shellNote = document.getElementById('pl-shell');
17027
+ var list = document.getElementById('pl-list');
17028
+ var addWrap = document.getElementById('pl-add-wrap');
17029
+ var form = document.getElementById('pl-add');
17030
+ var err = document.getElementById('pl-error');
17031
+ var state = null;
17032
+ function field(f, n) { return f.elements.namedItem(n); }
17033
+
17034
+ var inShell = false;
17035
+ try {
17036
+ if (/^android-app:/.test(document.referrer)) localStorage.setItem('ax-shell', 'android');
17037
+ inShell = localStorage.getItem('ax-shell') === 'android';
17038
+ } catch (e) { inShell = /^android-app:/.test(document.referrer); }
17039
+
17040
+ function esc(s) {
17041
+ return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
17042
+ return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
17043
+ });
17044
+ }
17045
+ function api(method, path, body) {
17046
+ return fetch(path, {
17047
+ method: method, credentials: 'same-origin',
17048
+ headers: body ? { 'Content-Type': 'application/json' } : {},
17049
+ body: body ? JSON.stringify(body) : undefined,
17050
+ }).then(function (r) {
17051
+ return r.json().catch(function () { return {}; }).then(function (b) {
17052
+ if (!r.ok) throw new Error(b.error || ('HTTP ' + r.status));
17053
+ return b;
17054
+ });
17055
+ });
17056
+ }
17057
+ function ruleRow(r) {
17058
+ var what = (r.on === 'exit' ? 'Leave: ' : 'Arrive: ') + r.text;
17059
+ var how = (r.agent ? 'asks ' + r.agent : 'reminder') + (r.repeat ? ', every time' : ', once') + (r.enabled ? '' : (r.repeat ? ', paused' : ', done'));
17060
+ return '<li class="pl-rule' + (r.enabled ? '' : ' is-off') + '"><span>' + esc(what) + ' <small class="fx-muted">' + esc(how) + '</small></span>' +
17061
+ '<button type="button" class="fx-btn" data-act="rule-remove" data-id="' + esc(r.id) + '" aria-label="Remove reminder ' + esc(r.text) + '">Remove</button></li>';
17062
+ }
17063
+ function placeRow(p) {
17064
+ var rules = (state.rules || []).filter(function (r) { return r.placeId === p.id; });
17065
+ var agents = (state.agents || []).map(function (a) { return '<option value="' + esc(a) + '">Ask ' + esc(a) + '</option>'; }).join('');
17066
+ return '<li class="pl-place"><div class="fx-row"><strong>' + esc(p.name) + '</strong><span class="fx-muted">' + esc(p.radius) + ' m</span></div>' +
17067
+ (rules.length ? '<ul class="pl-rules">' + rules.map(ruleRow).join('') + '</ul>' : '<p class="fx-muted">No reminders yet.</p>') +
17068
+ '<details class="pl-more"><summary>Add a reminder or remove</summary>' +
17069
+ '<form class="pl-rule-form" data-place="' + esc(p.id) + '">' +
17070
+ '<label><span>When</span><select name="on"><option value="enter">When I arrive</option><option value="exit">When I leave</option></select></label>' +
17071
+ '<label><span>Remind me to</span><input name="text" required maxlength="500" placeholder="Pick up the parcel"></label>' +
17072
+ '<label><span>Who</span><select name="agent"><option value="">Just remind me</option>' + agents + '</select></label>' +
17073
+ '<label class="pl-check"><input type="checkbox" name="repeat"> Every time, not just once</label>' +
17074
+ '<div class="fx-actions"><button type="button" class="fx-btn fx-danger-o" data-act="remove" data-id="' + esc(p.id) + '" data-name="' + esc(p.name) + '">Remove place</button>' +
17075
+ '<button type="submit" class="fx-btn fx-primary">Add reminder</button></div>' +
17076
+ '</form></details></li>';
17077
+ }
17078
+ function paint() {
17079
+ if (!state.enabled) {
17080
+ pill.textContent = 'Off'; pill.className = 'fx-pill fx-off';
17081
+ text.textContent = state.reason; list.innerHTML = ''; addWrap.hidden = true; shellNote.hidden = true;
17082
+ return;
17083
+ }
17084
+ var n = state.places.length;
17085
+ pill.textContent = n + (n === 1 ? ' place' : ' places');
17086
+ pill.className = 'fx-pill ' + (n ? 'fx-on' : 'fx-warn');
17087
+ text.textContent = state.pushAvailable
17088
+ ? 'Get a reminder when you arrive at or leave a place. Your phone tells this computer only which place, never where you are.'
17089
+ : 'Places are saved, but reminders are not sent: ' + (state.pushReason || 'notifications are off.');
17090
+ shellNote.hidden = false;
17091
+ shellNote.innerHTML = inShell
17092
+ ? 'This phone watches these places in the background. <a href="intent://places#Intent;scheme=agentx;package=' + esc(state.android.packageName) + ';end">Location settings</a>'
17093
+ : 'Reminders fire only on an Android phone with the AgentX Android app. See Place reminders in the AgentX docs.';
17094
+ var radius = field(form, 'radius');
17095
+ radius.placeholder = String(state.limits.defaultRadiusMeters);
17096
+ radius.min = String(state.limits.minRadiusMeters);
17097
+ radius.max = String(state.limits.maxRadiusMeters);
17098
+ addWrap.hidden = n >= state.limits.maxPlaces;
17099
+ list.innerHTML = n ? state.places.map(placeRow).join('') : '<li class="fx-muted">No places yet.</li>';
17100
+ }
17101
+ function load() {
17102
+ return api('GET', '/api/app/places').then(function (s) { state = s; paint(); })
17103
+ .catch(function (e) { pill.textContent = ''; text.textContent = 'Could not load places: ' + e.message; });
17104
+ }
17105
+
17106
+ document.getElementById('pl-here').addEventListener('click', function () {
17107
+ err.textContent = '';
17108
+ if (!navigator.geolocation) { err.textContent = 'This browser can\u2019t read the location. Type the coordinates instead.'; return; }
17109
+ var b = this; b.disabled = true; b.textContent = 'Finding you\u2026';
17110
+ navigator.geolocation.getCurrentPosition(function (pos) {
17111
+ field(form, 'coords').value = pos.coords.latitude.toFixed(6) + ', ' + pos.coords.longitude.toFixed(6);
17112
+ b.disabled = false; b.textContent = 'Use where I am now';
17113
+ }, function (e) {
17114
+ err.textContent = e.code === 1 ? 'Location is blocked for this app. Allow it in the phone\u2019s settings, or type the coordinates.' : 'Could not find where you are. Try again outdoors, or type the coordinates.';
17115
+ b.disabled = false; b.textContent = 'Use where I am now';
17116
+ }, { enableHighAccuracy: true, timeout: 20000, maximumAge: 0 });
17117
+ });
17118
+ form.addEventListener('submit', function (ev) {
17119
+ ev.preventDefault();
17120
+ err.textContent = '';
17121
+ var parts = field(form, 'coords').value.split(',');
17122
+ if (parts.length !== 2) { err.textContent = 'Type the coordinates as latitude, longitude.'; return; }
17123
+ api('POST', '/api/app/places/add', { name: field(form, 'name').value, lat: parts[0].trim(), lng: parts[1].trim(), radius: field(form, 'radius').value })
17124
+ .then(function () { form.reset(); addWrap.open = false; return load(); })
17125
+ .catch(function (e) { err.textContent = e.message; });
17126
+ });
17127
+ list.addEventListener('submit', function (ev) {
17128
+ var f = ev.target.closest('form[data-place]');
17129
+ if (!f) return;
17130
+ ev.preventDefault();
17131
+ err.textContent = '';
17132
+ api('POST', '/api/app/places/rules/add', { placeId: f.getAttribute('data-place'), on: field(f, 'on').value, text: field(f, 'text').value, agent: field(f, 'agent').value, repeat: field(f, 'repeat').checked })
17133
+ .then(load).catch(function (e) { err.textContent = e.message; });
17134
+ });
17135
+ list.addEventListener('click', function (ev) {
17136
+ var b = ev.target.closest('button[data-act]');
17137
+ if (!b) return;
17138
+ var act = b.getAttribute('data-act');
17139
+ if (act === 'remove' && !confirm('Remove ' + b.getAttribute('data-name') + ' and its reminders?')) return;
17140
+ b.disabled = true;
17141
+ err.textContent = '';
17142
+ api('POST', act === 'remove' ? '/api/app/places/remove' : '/api/app/places/rules/remove', { id: b.getAttribute('data-id') })
17143
+ .then(load).catch(function (e) { err.textContent = e.message; b.disabled = false; });
17144
+ });
17145
+ document.addEventListener('visibilitychange', function () { if (!document.hidden && state) load(); });
17146
+ load();
17147
+ })();
17148
+ `,Nl=`
17149
+ .pl-card { margin-top: 12px; }
17150
+ .pl-list { margin-top: 8px; }
17151
+ .pl-rules { list-style: none; margin: 6px 0 0; padding: 0; }
17152
+ .pl-rules .pl-rule { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 0; border: 0; }
17153
+ .pl-rule.is-off { opacity: .7; }
17154
+ .pl-more summary, .pl-add summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; }
17155
+ .pl-more summary { color: var(--ax-accent); font-size: var(--ax-fs-sm); }
17156
+ .pl-add summary { list-style: none; display: inline-flex; margin-top: 10px; }
17157
+ .pl-add summary::-webkit-details-marker { display: none; }
17158
+ .pl-card form { display: grid; gap: 10px; margin-top: 10px; }
17159
+ .pl-card label span { display: block; font-weight: 600; margin-bottom: 4px; font-size: var(--ax-fs-sm); }
17160
+ .pl-card input:not([type=checkbox]), .pl-card select {
17161
+ width: 100%; box-sizing: border-box; min-height: 44px; padding: 8px 10px; font: inherit;
17162
+ border: var(--ax-border-w) solid var(--ax-border); border-radius: var(--ax-radius-sm); background: var(--ax-surface-2); color: var(--ax-text);
17163
+ }
17164
+ .pl-check { display: flex; align-items: center; gap: 8px; font-size: var(--ax-fs-sm); }
17165
+ .pl-check input { width: 20px; height: 20px; }
17166
+ #pl-here { justify-self: start; }
17167
+ `;var Dl=`
16997
17168
  (function () {
16998
17169
  var panel = document.getElementById('panel-alerts');
16999
17170
  if (!panel) return;
@@ -17106,7 +17277,7 @@ details[open] > summary::before { transform: rotate(90deg); }
17106
17277
  }
17107
17278
  load();
17108
17279
  })();
17109
- `;var el=`
17280
+ `;var Hl=`
17110
17281
  (function () {
17111
17282
  var panel = document.getElementById('panel-chat');
17112
17283
  var V = window.AXChatView;
@@ -17389,7 +17560,7 @@ details[open] > summary::before { transform: rotate(90deg); }
17389
17560
  var last = recall('ax-chat-conv');
17390
17561
  if (!fromHash() && last) openConversation(last);
17391
17562
  })();
17392
- `;var tl=`
17563
+ `;var Bl=`
17393
17564
  window.AXChatView = (function () {
17394
17565
  var NL = String.fromCharCode(10), TAB = String.fromCharCode(9), FENCE = String.fromCharCode(96, 96, 96);
17395
17566
  // Cut a half-written agentx:ui block from a streaming reply so its raw
@@ -17670,7 +17841,7 @@ window.AXChatView = (function () {
17670
17841
  openViewer: openViewer, closeViewer: closeViewer, readStream: readStream,
17671
17842
  cachePut: cachePut, cacheGet: cacheGet, cacheAll: cacheAll, cacheDrop: cacheDrop };
17672
17843
  })();
17673
- `;var al=`
17844
+ `;var zl=`
17674
17845
  window.AXChatSheets = function (o) {
17675
17846
  var V = o.V, picker = o.picker, hist = o.hist;
17676
17847
  function loadPicker() {
@@ -17716,7 +17887,7 @@ window.AXChatSheets = function (o) {
17716
17887
  });
17717
17888
  return { loadPicker: loadPicker, loadHistory: loadHistory };
17718
17889
  };
17719
- `;var nl=`
17890
+ `;var ql=`
17720
17891
  window.AXChatLog = function (o) {
17721
17892
  var V = o.V, log = o.log, empty = o.empty, NOTES = o.notes;
17722
17893
  function scrollDown() { var m = log; if (m) m.scrollTop = m.scrollHeight; }
@@ -17779,7 +17950,7 @@ window.AXChatLog = function (o) {
17779
17950
  return { scrollDown: scrollDown, clear: clear, userMsg: userMsg, queuedMsg: queuedMsg, agentMsg: agentMsg, setBody: setBody,
17780
17951
  setNote: setNote, renderUi: renderUi, renderFiles: renderFiles, renderConversation: renderConversation, flash: flash };
17781
17952
  };
17782
- `;var rl=`
17953
+ `;var Fl=`
17783
17954
  (function () {
17784
17955
  var panel = document.getElementById('panel-chat'), C = window.AXChat, V = window.AXChatView, O = window.AXOrb;
17785
17956
  var top = panel && panel.querySelector('.cx-top');
@@ -17929,7 +18100,7 @@ window.AXChatLog = function (o) {
17929
18100
  window.AXStrip = { poll: poll, update: update, banner: banner };
17930
18101
  poll();
17931
18102
  })();
17932
- `;var ol=`
18103
+ `;var Ul=`
17933
18104
  .cs { margin: 0 -2px; }
17934
18105
  .cs[hidden] { display: none; }
17935
18106
  .cs-list {
@@ -17985,7 +18156,7 @@ window.AXChatLog = function (o) {
17985
18156
  @media (prefers-reduced-motion: reduce) {
17986
18157
  .cs-thinking .cs-dot, .cs-answering .cs-dot, .cs-banner { animation: none; }
17987
18158
  }
17988
- `;function sl(t,e,a=5){if(t.some(o=>o.key===e.key))return{queue:t.slice(),dropped:[]};let n=t.concat([e]),r=Math.max(0,n.length-Math.max(1,a));return{queue:n.slice(r),dropped:n.slice(0,r)}}function il(t,e){return e||!t.length?{item:null,queue:t.slice()}:{item:t[0],queue:t.slice(1)}}var ll=`
18159
+ `;function Wl(t,e,a=5){if(t.some(o=>o.key===e.key))return{queue:t.slice(),dropped:[]};let n=t.concat([e]),r=Math.max(0,n.length-Math.max(1,a));return{queue:n.slice(r),dropped:n.slice(0,r)}}function Gl(t,e){return e||!t.length?{item:null,queue:t.slice()}:{item:t[0],queue:t.slice(1)}}var Xl=`
17989
18160
  body { height: 100dvh; }
17990
18161
  main { min-height: 0; }
17991
18162
  #panel-chat:not([hidden]) { display: flex; flex-direction: column; min-height: 100%; }
@@ -18095,7 +18266,7 @@ main { min-height: 0; }
18095
18266
  background: color-mix(in oklch, var(--ax-accent) 15%, var(--ax-surface)); color: var(--ax-accent);
18096
18267
  }
18097
18268
  .cx-composer .fx-btn { border-radius: var(--ax-radius); }
18098
- `;var cl=`
18269
+ `;var Kl=`
18099
18270
  window.AXOrb = (function () {
18100
18271
  // Same list, order and hash as presenceLook (src/voice/presence.ts) and
18101
18272
  // OrbMath.colorHex, for an agent whose colour did not come with it.
@@ -18212,7 +18383,7 @@ window.AXOrb = (function () {
18212
18383
  }
18213
18384
  return { create: create, colorFor: colorFor, levelFromRms: levelFromRms, speakingEnvelope: speakingEnvelope };
18214
18385
  })();
18215
- `;var dl=`
18386
+ `;var Jl=`
18216
18387
  window.AXVoiceIO = (function () {
18217
18388
  var TYPES = ['audio/webm;codecs=opus', 'audio/mp4', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/aac'];
18218
18389
  var ac = null, playing = null;
@@ -18330,7 +18501,7 @@ window.AXVoiceIO = (function () {
18330
18501
 
18331
18502
  return { canRecord: canRecord, mimeType: mimeType, unlock: unlock, record: record, playAudio: playAudio, speakText: speakText, stop: stopPlaying };
18332
18503
  })();
18333
- `;var pl=`
18504
+ `;var Vl=`
18334
18505
  (function () {
18335
18506
  var panel = document.getElementById('panel-chat'), C = window.AXChat, IO = window.AXVoiceIO, O = window.AXOrb;
18336
18507
  if (!panel || !C || !IO || !O) return;
@@ -18543,7 +18714,7 @@ window.AXVoiceIO = (function () {
18543
18714
  idle();
18544
18715
  window.AXVoice = { show: show, orb: orb, state: function () { return v.state; }, queued: function () { return speech.length; } };
18545
18716
  })();
18546
- `;var ul=`
18717
+ `;var Yl=`
18547
18718
  .vx {
18548
18719
  position: sticky; bottom: -16px; z-index: 1; display: grid; justify-items: center; gap: 4px;
18549
18720
  margin: 0 0 -16px; padding: 8px 0 12px; background: var(--ax-bg);
@@ -18579,7 +18750,7 @@ window.AXVoiceIO = (function () {
18579
18750
  .cx-typing-on .vx-orb { width: 88px; height: 88px; }
18580
18751
  .cx-typing-on .vx-row { gap: 16px; }
18581
18752
  @media (prefers-reduced-motion: reduce) { .vx-orb { transition: none; } }
18582
- `;var ml=`
18753
+ `;var Ql=`
18583
18754
  <main class="card">
18584
18755
  <h1>This phone isn't paired</h1>
18585
18756
  <p>On the computer running AgentX, open a terminal in the folder that holds <code>agentx.json</code> and run <code>agentx app pair</code>. Scan the QR code it shows, or type the code under it.</p>
@@ -18593,7 +18764,7 @@ window.AXVoiceIO = (function () {
18593
18764
  <p id="pair-msg" class="pair-msg" role="status" aria-live="polite"></p>
18594
18765
  </form>
18595
18766
  <p class="muted">If this phone was paired before, it may have been removed with <code>agentx app revoke</code>.</p>
18596
- </main>`,fl=`
18767
+ </main>`,Zl=`
18597
18768
  .pair-form { display: grid; gap: 10px; margin: 20px 0 24px; }
18598
18769
  .pair-form label { font-weight: 600; }
18599
18770
  .pair-form input {
@@ -18615,7 +18786,7 @@ window.AXVoiceIO = (function () {
18615
18786
  margin: 0; padding: 8px 12px; border-radius: var(--ax-radius-sm); font-size: var(--ax-fs-sm);
18616
18787
  background: var(--ax-amber-t); color: var(--ax-amber-ink); border: 1px solid var(--ax-amber-e);
18617
18788
  }
18618
- `,hl=`
18789
+ `,ec=`
18619
18790
  (function () {
18620
18791
  var form = document.getElementById('pair-form');
18621
18792
  var input = document.getElementById('pair-code');
@@ -18707,7 +18878,7 @@ window.AXVoiceIO = (function () {
18707
18878
  navigator.serviceWorker.register('/app/sw.js', { scope: '/app' }).catch(function () {});
18708
18879
  }
18709
18880
  })();
18710
- `;var gl=`
18881
+ `;var tc=`
18711
18882
  <div id="scan" class="scan" role="dialog" aria-modal="true" aria-labelledby="scan-title" hidden>
18712
18883
  <video id="scan-video" playsinline muted autoplay></video>
18713
18884
  <div class="scan-frame" aria-hidden="true"></div>
@@ -18716,7 +18887,7 @@ window.AXVoiceIO = (function () {
18716
18887
  <button type="button" id="scan-close" class="scan-close">Close</button>
18717
18888
  </div>
18718
18889
  <p id="scan-msg" class="scan-msg" role="status" aria-live="polite">Point the camera at the QR code shown by agentx app pair.</p>
18719
- </div>`,xl=`
18890
+ </div>`,ac=`
18720
18891
  .pair-form .scan-btn {
18721
18892
  color: var(--ax-accent-2, var(--ax-accent)); background: transparent; border: 2px solid var(--ax-accent);
18722
18893
  }
@@ -18745,7 +18916,7 @@ window.AXVoiceIO = (function () {
18745
18916
  }
18746
18917
  .scan-msg.bad { color: #ffd0cc; font-weight: 600; }
18747
18918
  body.scanning { overflow: hidden; }
18748
- `,vl=`
18919
+ `,nc=`
18749
18920
  (function () {
18750
18921
  var openBtn = document.getElementById('scan-btn');
18751
18922
  var box = document.getElementById('scan');
@@ -18911,7 +19082,7 @@ body.scanning { overflow: hidden; }
18911
19082
  document.addEventListener('visibilitychange', function () { if (document.hidden) close(); });
18912
19083
  window.addEventListener('pagehide', close);
18913
19084
  })();
18914
- `;var an=`
19085
+ `;var un=`
18915
19086
  .cam { position: fixed; inset: 0; z-index: 50; display: flex; flex-direction: column; background: var(--ax-bg); }
18916
19087
  .cam[hidden] { display: none; }
18917
19088
  .cam-live {
@@ -18953,7 +19124,24 @@ body.scanning { overflow: hidden; }
18953
19124
  border: var(--ax-border-w) solid var(--ax-border); line-height: 1.5; max-height: 30vh; overflow: auto;
18954
19125
  }
18955
19126
  .cam-reply strong { display: block; font-size: 13px; color: var(--ax-text-2); margin-bottom: 4px; }
18956
- `;var bl='<button type="button" id="cam-btn" class="icon-btn" aria-label="Share camera" aria-haspopup="dialog"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6h12v12H3zM15 10l6-3v10l-6-3"/></svg><span>Share camera</span></button>',yl=`
19127
+ /* Talk: the way to ask by default (#687). Big, one thumb, its state in colour and words. */
19128
+ .cam-talk[hidden] { display: none; }
19129
+ .cam-talk {
19130
+ display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; min-height: 64px; margin: 0 0 12px;
19131
+ border-radius: var(--ax-radius-pill); border: 2px solid var(--ax-accent); background: var(--ax-accent); color: #fff;
19132
+ font: inherit; font-size: 18px; font-weight: 700; cursor: pointer;
19133
+ touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
19134
+ }
19135
+ .cam-talk.is-on { background: var(--ax-red); border-color: var(--ax-red); }
19136
+ .cam-talk[disabled] { opacity: .6; cursor: default; }
19137
+ .cam-talk:focus-visible { outline: 3px solid var(--ax-text); outline-offset: 2px; }
19138
+ .cam-mic { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; flex: none; }
19139
+ /* Keep watching is on: the red bar says so with a second countdown. */
19140
+ .cam-live.is-stream .cam-dot { animation: cam-pulse 1s ease-in-out infinite; }
19141
+ @keyframes cam-pulse { 50% { opacity: .3; } }
19142
+ @media (prefers-reduced-motion: reduce) { .cam-live.is-stream .cam-dot { animation: none; } }
19143
+ #cam-stream[aria-pressed="true"] { border-color: var(--ax-red); color: var(--ax-red-ink); }
19144
+ `;var rc='<button type="button" id="cam-btn" class="icon-btn" aria-label="Share camera" aria-haspopup="dialog"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6h12v12H3zM15 10l6-3v10l-6-3"/></svg><span>Share camera</span></button>',oc=`
18957
19145
  <div id="cam" class="cam" role="dialog" aria-modal="true" aria-labelledby="cam-title" hidden>
18958
19146
  <div class="cam-live" id="cam-live" role="status" aria-live="polite" hidden>
18959
19147
  <span class="cam-dot" aria-hidden="true"></span>
@@ -18968,17 +19156,21 @@ body.scanning { overflow: hidden; }
18968
19156
  <select id="cam-peer"></select>
18969
19157
  </label>
18970
19158
  <div id="cam-reply" class="cam-reply" role="log" aria-live="polite" hidden></div>
19159
+ <button type="button" id="cam-talk" class="cam-talk" aria-describedby="cam-msg" hidden><svg class="cam-mic" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V6a3 3 0 0 0-3-3ZM5.5 11a6.5 6.5 0 0 0 13 0M12 17.5V21"/></svg><span id="cam-talk-label">Hold to talk</span></button>
18971
19160
  <label class="cam-field" id="cam-ask" hidden>Ask the agent something (optional)
18972
19161
  <input id="cam-note" type="text" maxlength="300" autocomplete="off" placeholder="What is this cable for?">
18973
19162
  </label>
18974
19163
  <div class="cam-row">
18975
19164
  <button type="button" id="cam-start" class="cam-primary" hidden>Start camera</button>
18976
19165
  <button type="button" id="cam-look" class="cam-primary" hidden>Look now</button>
19166
+ <button type="button" id="cam-stream" class="cam-secondary" aria-pressed="false" hidden>Keep watching</button>
19167
+ <button type="button" id="cam-type" class="cam-secondary" aria-pressed="false" hidden>Type instead</button>
19168
+ <button type="button" id="cam-speaker" class="cam-secondary" aria-pressed="true" hidden>Answers aloud: on</button>
18977
19169
  <button type="button" id="cam-flip" class="cam-secondary" hidden>Flip camera</button>
18978
19170
  <button type="button" id="cam-close" class="cam-secondary">Close</button>
18979
19171
  </div>
18980
19172
  </div>
18981
- </div>`,wl=`
19173
+ </div>`,sc=`
18982
19174
  (function () {
18983
19175
  var btn = document.getElementById('cam-btn');
18984
19176
  var sheet = document.getElementById('cam');
@@ -18996,8 +19188,16 @@ body.scanning { overflow: hidden; }
18996
19188
  var replyBox = document.getElementById('cam-reply');
18997
19189
  var ask = document.getElementById('cam-ask');
18998
19190
  var note = document.getElementById('cam-note');
19191
+ var talkBtn = document.getElementById('cam-talk');
19192
+ var talkLabel = document.getElementById('cam-talk-label');
19193
+ var streamBtn = document.getElementById('cam-stream');
19194
+ var typeBtn = document.getElementById('cam-type');
19195
+ var speakBtn = document.getElementById('cam-speaker');
19196
+ var IO = window.AXVoiceIO || null;
18999
19197
  var cfg = null;
19000
- var s = null; // the live share: { callId, peer, agent, stream, pc, es, facing, until, timer, tick, poll, shown }
19198
+ var s = null; // the live share: { callId, peer, agent, stream, pc, es, facing, until, timer, tick, poll, shown, asking, streamUntil, lastAsk }
19199
+ var talk = { rec: null, arming: false, pressed: false, t0: 0, mode: null, timer: null };
19200
+ var speaking = Promise.resolve(), speakGen = 0;
19001
19201
 
19002
19202
  function norm(x) { return String(x || '').toLowerCase().replace(/[^a-z0-9]/g, ''); }
19003
19203
  function say(text, bad) { msg.textContent = text; msg.className = 'cam-msg' + (bad ? ' bad' : ''); }
@@ -19011,6 +19211,15 @@ body.scanning { overflow: hidden; }
19011
19211
  // keepalive lets the hangup leave while the page unloads (pagehide).
19012
19212
  function post(body, keepalive) { return api('POST', '/api/app/camera/signal', body, keepalive); }
19013
19213
  function agentOf(value) { return value && value.indexOf('bot:') === 0 ? value.slice(4) : null; }
19214
+ // Per-phone choices: the text box instead of Talk, answers said aloud.
19215
+ function pref(k, d) { try { var v = localStorage.getItem(k); return v === null ? d : v === '1'; } catch (e) { return d; } }
19216
+ function setPref(k, v) { try { localStorage.setItem(k, v ? '1' : '0'); } catch (e) {} }
19217
+ function camCfg() { return (cfg && cfg.camera) || {}; }
19218
+ function canTalk() { return camCfg().voiceInput !== false && !!IO && IO.canRecord(); }
19219
+ function typing() { return !canTalk() || pref('ax.cam.type', false); }
19220
+ function speakOn() { return !!IO && pref('ax.cam.speak', camCfg().speakAnswers !== false); }
19221
+ function streamSeconds() { var b = camCfg().bot; return (b && b.streamMaxSeconds) || 60; }
19222
+ function streaming() { return !!(s && s.streamUntil && s.streamUntil > Date.now()); }
19014
19223
  function agentName(id) {
19015
19224
  var a = cfg && cfg.agents ? cfg.agents.filter(function (x) { return x.id === id; })[0] : null;
19016
19225
  return a ? a.name : id;
@@ -19076,7 +19285,7 @@ body.scanning { overflow: hidden; }
19076
19285
  video.srcObject = stream; video.hidden = false;
19077
19286
  sheet.classList.add('is-live');
19078
19287
  live.hidden = false; flipBtn.hidden = false; startBtn.hidden = true; pick.hidden = true; closeBtn.hidden = true;
19079
- if (agent) { lookBtn.hidden = false; ask.hidden = false; replyBox.hidden = true; replyBox.innerHTML = ''; }
19288
+ if (agent) { lookBtn.hidden = false; streamBtn.hidden = false; speakBtn.hidden = false; replyBox.hidden = true; replyBox.innerHTML = ''; layoutAsk(); paintStream(); }
19080
19289
  document.title = '\u25CF Camera live \xB7 AgentX';
19081
19290
  paintLive();
19082
19291
  s.tick = setInterval(paintLive, 1000);
@@ -19093,7 +19302,13 @@ body.scanning { overflow: hidden; }
19093
19302
  function who() { return s.agent ? agentName(s.agent) : s.peer; }
19094
19303
  function paintLive() {
19095
19304
  if (!s) return;
19096
- liveText.textContent = (s.agent ? agentName(s.agent) + ' is watching' : 'Camera live on ' + s.peer) + ' \xB7 ' + shareClock(s.until - Date.now());
19305
+ if (s.streamUntil && !streaming()) {
19306
+ s.streamUntil = null;
19307
+ paintStream();
19308
+ say('Keep watching stopped. ' + who() + ' gets one picture per question again.');
19309
+ }
19310
+ liveText.textContent = (s.agent ? agentName(s.agent) + ' is watching' : 'Camera live on ' + s.peer) + ' \xB7 ' + shareClock(s.until - Date.now()) +
19311
+ (streaming() ? ' \xB7 continuous ' + shareClock(s.streamUntil - Date.now()) : '');
19097
19312
  }
19098
19313
 
19099
19314
  function connect() {
@@ -19110,7 +19325,9 @@ body.scanning { overflow: hidden; }
19110
19325
  pc.onconnectionstatechange = function () {
19111
19326
  if (!s) return;
19112
19327
  if (pc.connectionState === 'connected') {
19113
- say(s.agent ? who() + ' can see the camera. Tap Look now to ask what it sees.' : who() + ' is watching. Tap Stop to end.');
19328
+ say(!s.agent ? who() + ' is watching. Tap Stop to end.'
19329
+ : typing() ? who() + ' can see the camera. Type a question and tap Look now.'
19330
+ : who() + ' can see the camera. Hold Talk and ask, or tap it once to start and again to send.');
19114
19331
  if (s.agent && !s.poll) s.poll = setInterval(pollReplies, 5000);
19115
19332
  }
19116
19333
  if (pc.connectionState === 'failed') stop('The connection to ' + who() + ' failed. Check both are on the tailnet, or add a TURN server.');
@@ -19149,19 +19366,163 @@ body.scanning { overflow: hidden; }
19149
19366
  });
19150
19367
  }
19151
19368
 
19152
- // The owner asks the agent what it sees: one turn, its answer on the sheet.
19153
- function look() {
19154
- if (!s || !s.agent || lookBtn.disabled) return;
19155
- var text = note.value.trim();
19156
- lookBtn.disabled = true;
19157
- say('Asking ' + who() + '\u2026');
19369
+ // The owner asks the agent what it sees: one frame, one turn, its answer
19370
+ // on the sheet and said aloud. spoken is the question from Talk.
19371
+ function look(spoken) {
19372
+ if (!s || !s.agent || s.asking) return;
19373
+ var text = typeof spoken === 'string' ? spoken : note.value.trim();
19374
+ if (IO) IO.unlock();
19375
+ stopSpeaking();
19376
+ s.asking = true; lookBtn.disabled = true; talkBtn.disabled = true;
19377
+ if (text) s.lastAsk = text;
19378
+ say(text ? 'Asking ' + who() + ': \u201C' + text + '\u201D' : 'Asking ' + who() + '\u2026');
19379
+ var mine = s;
19158
19380
  api('POST', '/api/app/camera/look', { callId: s.callId, note: text }).then(function (r) {
19159
- if (!s) return;
19160
- note.value = '';
19381
+ if (s !== mine) return;
19382
+ if (typeof spoken !== 'string') note.value = '';
19161
19383
  showReply(r.reply);
19162
- say('Tap Look now again for a fresh look.');
19163
- }).catch(function (e) { if (s) say(e.message || 'No answer.', true); })
19164
- .then(function () { lookBtn.disabled = false; });
19384
+ speakReply(r.reply);
19385
+ say(typing() ? 'Ask again, or tap Look now for a fresh look.' : 'Hold Talk to ask again.');
19386
+ }).catch(function (e) { if (s === mine) say(e.message || 'No answer.', true); })
19387
+ .then(function () { mine.asking = false; lookBtn.disabled = false; talkBtn.disabled = false; });
19388
+ }
19389
+
19390
+ // --- Talk: hold and let go, or tap to start and tap to send ---
19391
+ function paintTalk(text) {
19392
+ var on = !!(talk.rec || talk.arming);
19393
+ talkLabel.textContent = text || (on ? 'Listening\u2026' : 'Hold to talk');
19394
+ talkBtn.classList.toggle('is-on', on);
19395
+ talkBtn.setAttribute('aria-pressed', on ? 'true' : 'false');
19396
+ }
19397
+ function talkDown() {
19398
+ if (!s || !s.agent || !IO) return;
19399
+ IO.unlock();
19400
+ // A second tap sends what the first one started.
19401
+ if (talk.rec || talk.arming) { if (talk.mode === 'listen') finishTalk(true); return; }
19402
+ if (s.asking) return;
19403
+ stopSpeaking();
19404
+ talk.pressed = true; talk.t0 = Date.now(); talk.mode = null; talk.arming = true;
19405
+ paintTalk();
19406
+ say('Listening\u2026');
19407
+ IO.record().then(function (rec) {
19408
+ talk.arming = false;
19409
+ if (!s) { rec.stop(false); paintTalk(); return; }
19410
+ talk.rec = rec;
19411
+ if (talk.mode === 'send' || talk.mode === 'cancel') { finishTalk(talk.mode === 'send'); return; }
19412
+ talk.timer = setTimeout(function () { finishTalk(true); }, 60000);
19413
+ paintTalk(talk.mode === 'listen' ? 'Listening\u2026 tap to send' : null);
19414
+ }).catch(function (e) {
19415
+ talk.arming = false; talk.pressed = false; talk.mode = null;
19416
+ paintTalk();
19417
+ if (!s) return;
19418
+ var denied = e && (e.name === 'NotAllowedError' || e.name === 'SecurityError');
19419
+ say(denied ? 'The microphone is blocked. Allow it for this app in the phone\u2019s settings, or tap Type instead.'
19420
+ : 'Could not open the microphone. Tap Type instead to write your question.', true);
19421
+ });
19422
+ }
19423
+ function talkUp() {
19424
+ if (!talk.pressed) return;
19425
+ talk.pressed = false;
19426
+ talk.mode = talkRelease(Date.now() - talk.t0);
19427
+ if (talk.mode === 'send') { if (talk.rec) finishTalk(true); return; }
19428
+ paintTalk('Listening\u2026 tap to send');
19429
+ say('Listening. Tap Talk again when you are done.');
19430
+ }
19431
+ function finishTalk(keep) {
19432
+ if (!talk.rec) { if (talk.arming) talk.mode = keep ? 'send' : 'cancel'; return; }
19433
+ var rec = talk.rec;
19434
+ talk.rec = null; talk.mode = null; talk.pressed = false;
19435
+ clearTimeout(talk.timer);
19436
+ paintTalk();
19437
+ rec.stop(keep).then(function (take) {
19438
+ if (!s) return;
19439
+ if (!take) { say(keep ? 'Didn\u2019t catch that. Hold Talk while you speak.' : 'Cancelled.'); return; }
19440
+ transcribe(take);
19441
+ });
19442
+ }
19443
+ function transcribe(take) {
19444
+ var mine = s;
19445
+ mine.asking = true; lookBtn.disabled = true; talkBtn.disabled = true;
19446
+ say('Writing down what you said\u2026');
19447
+ fetch('/api/app/voice/transcribe', {
19448
+ method: 'POST', credentials: 'same-origin', body: take.blob,
19449
+ headers: { 'Content-Type': take.blob.type || 'audio/webm', 'X-Audio-Duration-Ms': String(take.ms) },
19450
+ }).then(function (r) {
19451
+ return r.json().catch(function () { return {}; }).then(function (j) { return { ok: r.ok, status: r.status, j: j }; });
19452
+ }).then(function (x) {
19453
+ mine.asking = false; lookBtn.disabled = false; talkBtn.disabled = false;
19454
+ if (s !== mine) return;
19455
+ if (x.ok && x.j.text) { look(x.j.text); return; }
19456
+ if (x.status === 503 && x.j.hint) { say(x.j.error + ' ' + x.j.hint + ' You can type instead.', true); return; }
19457
+ say(x.j.error || ('Speech to text failed (HTTP ' + x.status + ').'), true);
19458
+ }).catch(function () {
19459
+ mine.asking = false; lookBtn.disabled = false; talkBtn.disabled = false;
19460
+ if (s === mine) say('Could not reach AgentX. Check the connection and try again.', true);
19461
+ });
19462
+ }
19463
+
19464
+ // Talk, or the text box: one or the other shows. An agent's request
19465
+ // (the Show bar) fills the box in, so it shows too, next to Talk.
19466
+ function layoutAsk() {
19467
+ var t = typing();
19468
+ talkBtn.hidden = t;
19469
+ ask.hidden = !t && !note.value.trim();
19470
+ typeBtn.hidden = !canTalk();
19471
+ typeBtn.textContent = t ? 'Talk instead' : 'Type instead';
19472
+ typeBtn.setAttribute('aria-pressed', t ? 'true' : 'false');
19473
+ paintSpeaker();
19474
+ }
19475
+ function paintSpeaker() {
19476
+ var on = speakOn();
19477
+ speakBtn.hidden = !IO || !s || !s.agent;
19478
+ speakBtn.textContent = 'Answers aloud: ' + (on ? 'on' : 'off');
19479
+ speakBtn.setAttribute('aria-pressed', on ? 'true' : 'false');
19480
+ }
19481
+
19482
+ // --- Answers said aloud, one at a time ---
19483
+ function stopSpeaking() { speakGen++; if (IO) IO.stop(); }
19484
+ function sayAloud(text, gen) {
19485
+ return gen === speakGen && text ? IO.speakText(text, function () {}).catch(function () {}) : null;
19486
+ }
19487
+ function speakReply(r) {
19488
+ if (!s || !r || !r.text || !speakOn()) return;
19489
+ var gen = speakGen, callId = s.callId;
19490
+ speaking = speaking.then(function () {
19491
+ if (gen !== speakGen || !s || s.callId !== callId) return null;
19492
+ return fetch('/api/app/camera/speak', {
19493
+ method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' },
19494
+ body: JSON.stringify({ callId: callId, at: r.at }),
19495
+ }).then(function (res) {
19496
+ if (gen !== speakGen) return null;
19497
+ if (res.ok && (res.headers.get('content-type') || '').indexOf('audio/') === 0) {
19498
+ return res.arrayBuffer().then(function (buf) { return gen === speakGen ? IO.playAudio(buf, function () {}) : null; })
19499
+ .catch(function () { return sayAloud(r.text, gen); });
19500
+ }
19501
+ return res.json().catch(function () { return {}; }).then(function (j) { return sayAloud(j.text || r.text, gen); });
19502
+ }).catch(function () { return sayAloud(r.text, gen); });
19503
+ }).catch(function () {});
19504
+ }
19505
+
19506
+ // --- Keep watching: a frame every few seconds, for a short while ---
19507
+ function paintStream() {
19508
+ var on = streaming();
19509
+ streamBtn.textContent = on ? 'Stop watching' : streamLabel(streamSeconds());
19510
+ streamBtn.setAttribute('aria-pressed', on ? 'true' : 'false');
19511
+ live.classList.toggle('is-stream', on);
19512
+ }
19513
+ function toggleStream() {
19514
+ if (!s || !s.agent || streamBtn.disabled) return;
19515
+ if (IO) IO.unlock();
19516
+ var on = streaming(), mine = s;
19517
+ streamBtn.disabled = true;
19518
+ api('POST', '/api/app/camera/stream', { callId: s.callId, seconds: on ? 0 : streamSeconds(), note: on ? '' : (note.value.trim() || s.lastAsk || '') }).then(function (r) {
19519
+ if (s !== mine) return;
19520
+ s.streamUntil = r.watch && r.watch.streamUntil ? r.watch.streamUntil : null;
19521
+ paintStream(); paintLive();
19522
+ say(s.streamUntil ? who() + ' is watching continuously and will speak up. It stops by itself, or tap Stop watching.'
19523
+ : who() + ' gets one picture per question again.');
19524
+ }).catch(function (e) { if (s === mine) say(e.message || 'Could not change watching.', true); })
19525
+ .then(function () { streamBtn.disabled = false; });
19165
19526
  }
19166
19527
 
19167
19528
  function showReply(r) {
@@ -19178,11 +19539,14 @@ body.scanning { overflow: hidden; }
19178
19539
  }
19179
19540
 
19180
19541
  // Answers to frames the agent got by itself (frameIntervalSeconds).
19542
+ // Answers while Keep watching is on come the same way, and are said aloud.
19181
19543
  function pollReplies() {
19182
- if (!s || !s.agent || document.visibilityState !== 'visible') return;
19544
+ if (!s || !s.agent || s.asking || document.visibilityState !== 'visible') return;
19545
+ var mine = s;
19183
19546
  api('GET', '/api/app/camera/watch?callId=' + encodeURIComponent(s.callId)).then(function (r) {
19184
- if (!s || !r.watch) return;
19185
- (r.watch.replies || []).forEach(function (rep) { if (rep.at > (s.shown || 0)) showReply(rep); });
19547
+ if (s !== mine || !r.watch || s.asking) return;
19548
+ (r.watch.replies || []).forEach(function (rep) { if (rep.at > (s.shown || 0)) { showReply(rep); speakReply(rep); } });
19549
+ if (s.streamUntil && !r.watch.streamUntil) { s.streamUntil = null; paintStream(); }
19186
19550
  }).catch(function () {});
19187
19551
  }
19188
19552
 
@@ -19206,6 +19570,8 @@ body.scanning { overflow: hidden; }
19206
19570
  function stop(reason) {
19207
19571
  if (!s) return;
19208
19572
  var was = s;
19573
+ finishTalk(false);
19574
+ stopSpeaking();
19209
19575
  s = null;
19210
19576
  clearInterval(was.tick); clearTimeout(was.timer); clearInterval(was.poll);
19211
19577
  post({ kind: 'hangup', callId: was.callId, to: was.peer }, true).catch(function () {});
@@ -19216,6 +19582,8 @@ body.scanning { overflow: hidden; }
19216
19582
  sheet.classList.remove('is-live');
19217
19583
  live.hidden = true; flipBtn.hidden = true; closeBtn.hidden = false;
19218
19584
  lookBtn.hidden = true; lookBtn.disabled = false; ask.hidden = true;
19585
+ talkBtn.hidden = true; talkBtn.disabled = false; paintTalk();
19586
+ streamBtn.hidden = true; typeBtn.hidden = true; speakBtn.hidden = true; live.classList.remove('is-stream');
19219
19587
  startBtn.hidden = false; startBtn.disabled = false; pick.hidden = false;
19220
19588
  document.title = 'AgentX';
19221
19589
  say(reason || 'Camera stopped.');
@@ -19236,7 +19604,36 @@ body.scanning { overflow: hidden; }
19236
19604
  start(preset);
19237
19605
  });
19238
19606
  });
19239
- lookBtn.addEventListener('click', look);
19607
+ lookBtn.addEventListener('click', function () { look(); });
19608
+ streamBtn.addEventListener('click', toggleStream);
19609
+ typeBtn.addEventListener('click', function () {
19610
+ setPref('ax.cam.type', !typing());
19611
+ layoutAsk();
19612
+ if (typing()) note.focus(); else talkBtn.focus();
19613
+ });
19614
+ speakBtn.addEventListener('click', function () {
19615
+ var on = !speakOn();
19616
+ setPref('ax.cam.speak', on);
19617
+ if (!on) stopSpeaking(); else if (IO) IO.unlock();
19618
+ paintSpeaker();
19619
+ });
19620
+ talkBtn.addEventListener('pointerdown', function (ev) {
19621
+ if (ev.button > 0) return;
19622
+ ev.preventDefault();
19623
+ try { talkBtn.setPointerCapture(ev.pointerId); } catch (e) {}
19624
+ talkDown();
19625
+ });
19626
+ talkBtn.addEventListener('pointerup', talkUp);
19627
+ talkBtn.addEventListener('pointercancel', function () { if (talk.pressed) { talk.pressed = false; finishTalk(false); } });
19628
+ talkBtn.addEventListener('contextmenu', function (ev) { ev.preventDefault(); });
19629
+ talkBtn.addEventListener('click', function (ev) { ev.preventDefault(); });
19630
+ // Keyboard: hold Space or Enter to talk, or press it once to start and
19631
+ // again to send; Escape cancels.
19632
+ talkBtn.addEventListener('keydown', function (ev) {
19633
+ if ((ev.key === ' ' || ev.key === 'Enter') && !ev.repeat) { ev.preventDefault(); talkDown(); }
19634
+ else if (ev.key === 'Escape' && (talk.rec || talk.arming)) { ev.stopPropagation(); talk.pressed = false; finishTalk(false); }
19635
+ });
19636
+ talkBtn.addEventListener('keyup', function (ev) { if (ev.key === ' ' || ev.key === 'Enter') { ev.preventDefault(); talkUp(); } });
19240
19637
  flipBtn.addEventListener('click', flip);
19241
19638
  note.addEventListener('keydown', function (ev) { if (ev.key === 'Enter') { ev.preventDefault(); look(); } });
19242
19639
  document.getElementById('cam-stop').addEventListener('click', function () { stop('Camera stopped.'); });
@@ -19247,7 +19644,7 @@ body.scanning { overflow: hidden; }
19247
19644
  });
19248
19645
  window.addEventListener('pagehide', function () { stop(); });
19249
19646
  })();
19250
- `;var kl=`
19647
+ `;var ic=`
19251
19648
  <div id="cam-ask-bar" class="cam-askbar" role="alert" hidden>
19252
19649
  <div class="cam-askbar-text">
19253
19650
  <strong id="cam-ask-who">An agent</strong> wants to see through your camera
@@ -19257,7 +19654,7 @@ body.scanning { overflow: hidden; }
19257
19654
  <button type="button" id="cam-ask-show" class="cam-askbar-show">Show</button>
19258
19655
  <button type="button" id="cam-ask-no" class="cam-askbar-no">Decline</button>
19259
19656
  </div>
19260
- </div>`,_l=`
19657
+ </div>`,lc=`
19261
19658
  .cam-askbar[hidden] { display: none; }
19262
19659
  .cam-askbar {
19263
19660
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
@@ -19272,7 +19669,7 @@ body.scanning { overflow: hidden; }
19272
19669
  border: 2px solid #fff; background: #fff; color: var(--ax-accent);
19273
19670
  }
19274
19671
  .cam-askbar-no { background: transparent; color: #fff; }
19275
- `,Sl=`
19672
+ `,cc=`
19276
19673
  (function () {
19277
19674
  var bar = document.getElementById('cam-ask-bar');
19278
19675
  if (!bar) return;
@@ -19342,7 +19739,7 @@ body.scanning { overflow: hidden; }
19342
19739
  setInterval(poll, 5000);
19343
19740
  document.addEventListener('visibilitychange', function () { if (document.visibilityState === 'visible') poll(); });
19344
19741
  })();
19345
- `;function El(t,e){let a={width:1280,height:720,frameRate:15},n=t||a;return{audio:!1,video:{facingMode:{ideal:e==="user"?"user":"environment"},width:{ideal:n.width||a.width},height:{ideal:n.height||a.height},frameRate:{ideal:n.frameRate||a.frameRate}}}}function Tl(t){let e=Math.max(0,Math.ceil(t/1e3)),a=Math.floor(e/60),n=e%60;return a+":"+(n<10?"0":"")+n}var Al=`
19742
+ `;function dc(t,e){let a={width:1280,height:720,frameRate:15},n=t||a;return{audio:!1,video:{facingMode:{ideal:e==="user"?"user":"environment"},width:{ideal:n.width||a.width},height:{ideal:n.height||a.height},frameRate:{ideal:n.frameRate||a.frameRate}}}}function pc(t){let e=Math.max(0,Math.ceil(t/1e3)),a=Math.floor(e/60),n=e%60;return a+":"+(n<10?"0":"")+n}function uc(t){return t>=400?"send":"listen"}function mc(t){let e=Math.max(1,Math.round(t||60));return"Keep watching "+(e%60===0?e/60+" min":e+" s")}var fc=`
19346
19743
  (function () {
19347
19744
  var main = document.querySelector('main');
19348
19745
  var tabs = Array.prototype.slice.call(document.querySelectorAll('[role=tab]'));
@@ -19461,7 +19858,7 @@ body.scanning { overflow: hidden; }
19461
19858
  main.addEventListener('touchend', function () { end(false); });
19462
19859
  main.addEventListener('touchcancel', function () { end(true); });
19463
19860
  })();
19464
- `,Cl=`
19861
+ `,hc=`
19465
19862
  main { position: relative; }
19466
19863
  main.sw-on { overflow: hidden; }
19467
19864
  .sw-on > [role=tabpanel] { will-change: transform; }
@@ -19472,8 +19869,8 @@ main > .sw-peek {
19472
19869
  }
19473
19870
  main > #panel-chat.sw-peek { display: flex; flex-direction: column; }
19474
19871
  @media (prefers-reduced-motion: reduce) { .sw-slide > [role=tabpanel] { transition: none; } }
19475
- `;function Il(t){let e=["INPUT","TEXTAREA","SELECT","DIALOG"];return!t.some(a=>a.scrollsX||a.editable||a.touchAction==="none"||a.touchAction==="pan-x"||e.indexOf(a.tag)>=0)}function Ml(t,e){let a=Math.abs(t),n=Math.abs(e);return a<10&&n<10?"":a>n*1.5?"x":"y"}function Ll(t,e,a){return a>0&&t===0||a<0&&t===e-1?a/4:a}function Rl(t,e,a,n,r){if(!(Math.abs(r)>.5?r*a>0&&Math.abs(a)>30:Math.abs(a)>n/3))return t;let i=t+(a<0?1:-1);return i<0||i>=e?t:i}var nn=`
19476
- ${B({afterUnauthorized:ao})}
19872
+ `;function gc(t){let e=["INPUT","TEXTAREA","SELECT","DIALOG"];return!t.some(a=>a.scrollsX||a.editable||a.touchAction==="none"||a.touchAction==="pan-x"||e.indexOf(a.tag)>=0)}function xc(t,e){let a=Math.abs(t),n=Math.abs(e);return a<10&&n<10?"":a>n*1.5?"x":"y"}function bc(t,e,a){return a>0&&t===0||a<0&&t===e-1?a/4:a}function vc(t,e,a,n,r){if(!(Math.abs(r)>.5?r*a>0&&Math.abs(a)>30:Math.abs(a)>n/3))return t;let i=t+(a<0?1:-1);return i<0||i>=e?t:i}var mn=`
19873
+ ${q({afterUnauthorized:_o})}
19477
19874
  var CACHE = 'agentx-app-v3';
19478
19875
  var STATIC = ['/app/manifest.webmanifest', '/app/icon-192.png', '/app/icon-512.png'];
19479
19876
  self.addEventListener('install', function (e) {
@@ -19564,7 +19961,7 @@ self.addEventListener('notificationclick', function (e) {
19564
19961
  return self.clients.openWindow(target);
19565
19962
  }));
19566
19963
  });
19567
- `;var Hm="<script>(function(){var t;try{t=localStorage.getItem('ax-theme')}catch(e){}if(t!=='light'&&t!=='dark'){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)})();</script>";function rn(t){return`<meta charset="utf-8">
19964
+ `;var Ff="<script>(function(){var t;try{t=localStorage.getItem('ax-theme')}catch(e){}if(t!=='light'&&t!=='dark'){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)})();</script>";function fn(t){return`<meta charset="utf-8">
19568
19965
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
19569
19966
  <meta name="theme-color" content="#2979FF">
19570
19967
  <meta name="referrer" content="no-referrer">
@@ -19575,57 +19972,58 @@ self.addEventListener('notificationclick', function (e) {
19575
19972
  <link rel="icon" type="image/png" href="/app/icon-192.png">
19576
19973
  <link rel="apple-touch-icon" href="/app/icon-192.png">
19577
19974
  <title>${t}</title>
19578
- ${Hm}
19579
- <style>${He}${Xi}${Fm}</style>`}var Bm={chat:"M21 11.5a8.5 8.5 0 0 1-8.5 8.5H4l-2 2V11.5a9.5 9.5 0 0 1 19 0Z",fleet:"M3 3h18v13H3zM8 21h8M12 16v5",activity:"M3 12h4l3-8 4 16 3-8h4",alerts:"M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9M10 21h4"},$l=[{id:"chat",label:"Chat",soon:"Loading your conversations\u2026"},{id:"fleet",label:"Fleet",soon:"Loading your machines\u2026"},{id:"activity",label:"Activity",soon:"Loading what your agents are doing\u2026"},{id:"alerts",label:"Alerts",soon:"Loading notifications\u2026"}];function Pl(){let t=$l.map((a,n)=>`<button type="button" role="tab" id="tab-${a.id}" aria-controls="panel-${a.id}" aria-selected="${n===0}" tabindex="${n===0?0:-1}" data-tab="${a.id}"><span class="tab-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="${Bm[a.id]}"/></svg></span><span>${a.label}</span></button>`).join(""),e=$l.map((a,n)=>`<section role="tabpanel" id="panel-${a.id}" aria-labelledby="tab-${a.id}" tabindex="0"${n===0?"":" hidden"}>
19975
+ ${Ff}
19976
+ <style>${Fe}${Ml}${Xf}</style>`}var Uf={chat:"M21 11.5a8.5 8.5 0 0 1-8.5 8.5H4l-2 2V11.5a9.5 9.5 0 0 1 19 0Z",fleet:"M3 3h18v13H3zM8 21h8M12 16v5",activity:"M3 12h4l3-8 4 16 3-8h4",alerts:"M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9M10 21h4"},yc=[{id:"chat",label:"Chat",soon:"Loading your conversations\u2026"},{id:"fleet",label:"Fleet",soon:"Loading your machines\u2026"},{id:"activity",label:"Activity",soon:"Loading what your agents are doing\u2026"},{id:"alerts",label:"Alerts",soon:"Loading notifications\u2026"}];function wc(){let t=yc.map((a,n)=>`<button type="button" role="tab" id="tab-${a.id}" aria-controls="panel-${a.id}" aria-selected="${n===0}" tabindex="${n===0?0:-1}" data-tab="${a.id}"><span class="tab-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="${Uf[a.id]}"/></svg></span><span>${a.label}</span></button>`).join(""),e=yc.map((a,n)=>`<section role="tabpanel" id="panel-${a.id}" aria-labelledby="tab-${a.id}" tabindex="0"${n===0?"":" hidden"}>
19580
19977
  <h2>${a.label}</h2>
19581
19978
  <p class="soon">${a.soon}</p>
19582
19979
  </section>`).join("");return`<!doctype html>
19583
19980
  <html lang="en">
19584
- <head>${rn("AgentX")}<style>${Um}${Yi}${ll}${ol}${ul}${an}${_l}${Cl}${Ki}</style></head>
19981
+ <head>${fn("AgentX")}<style>${Kf}${$l}${Xl}${Ul}${Yl}${un}${lc}${hc}${Nl}${Ll}</style></head>
19585
19982
  <body>
19586
19983
  <header class="bar">
19587
19984
  <div>
19588
19985
  <h1>AgentX</h1>
19589
19986
  <p id="who" class="who">Connecting\u2026</p>
19590
19987
  </div>
19591
- <div class="bar-btns">${bl}<button type="button" id="theme" class="icon-btn" aria-label="Switch to light theme"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 15.5A9 9 0 0 1 8.5 4 9 9 0 1 0 20 15.5Z"/></svg></button></div>
19988
+ <div class="bar-btns">${rc}<button type="button" id="theme" class="icon-btn" aria-label="Switch to light theme"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 15.5A9 9 0 0 1 8.5 4 9 9 0 1 0 20 15.5Z"/></svg></button></div>
19592
19989
  </header>
19593
19990
  <p id="offline" class="offline" role="status" hidden>Offline. Showing the saved app; live data needs a connection.</p>
19594
- ${kl}
19991
+ ${ic}
19595
19992
  <main>${e}</main>
19596
19993
  <nav class="tabs" role="tablist" aria-label="Sections">${t}</nav>
19597
- ${yl}
19598
- <script>${zm}</script>
19599
- <script>${B({swipeMayStart:Il,swipeAxis:Ml,swipeOffset:Ll,swipeLanding:Rl})}${Al}</script>
19600
- <script>${Ji}</script>
19601
- <script>${Vi}</script>
19602
- <script>${Qi}</script>
19603
- <script>${Zi}</script>
19604
- <script>${B({markdownToHtml:Vn})}${tl}${nl}${al}${el}</script>
19605
- <script>${B({queueSpeech:sl,nextSpeech:il})}${cl}${dl}${pl}</script>
19606
- <script>${rl}</script>
19607
- <script>${B({cameraConstraints:El,shareClock:Tl})}${wl}</script>
19608
- <script>${Sl}</script>
19994
+ ${oc}
19995
+ <script>${Wf}</script>
19996
+ <script>${q({swipeMayStart:gc,swipeAxis:xc,swipeOffset:bc,swipeLanding:vc})}${fc}</script>
19997
+ <script>${Rl}</script>
19998
+ <script>${Pl}</script>
19999
+ <script>${jl}</script>
20000
+ <script>${Ol}</script>
20001
+ <script>${Dl}</script>
20002
+ <script>${q({markdownToHtml:ir})}${Bl}${ql}${zl}${Hl}</script>
20003
+ <script>${q({queueSpeech:Wl,nextSpeech:Gl})}${Kl}${Jl}${Vl}</script>
20004
+ <script>${Fl}</script>
20005
+ <script>${q({cameraConstraints:dc,shareClock:pc,streamLabel:mc,talkRelease:uc})}${sc}</script>
20006
+ <script>${cc}</script>
19609
20007
  </body>
19610
- </html>`}function jl(){return`<!doctype html>
20008
+ </html>`}function kc(){return`<!doctype html>
19611
20009
  <html lang="en">
19612
- <head>${rn("Pair \xB7 AgentX")}</head>
20010
+ <head>${fn("Pair \xB7 AgentX")}</head>
19613
20011
  <body>
19614
20012
  <main class="card">
19615
20013
  <h1>Pairing this phone\u2026</h1>
19616
20014
  <p id="msg" role="status">One moment.</p>
19617
20015
  </main>
19618
- <script>${qm}</script>
20016
+ <script>${Gf}</script>
19619
20017
  </body>
19620
- </html>`}function Ol(){return`<!doctype html>
20018
+ </html>`}function _c(){return`<!doctype html>
19621
20019
  <html lang="en">
19622
- <head>${rn("Not paired \xB7 AgentX")}<style>${fl}${xl}</style></head>
19623
- <body>${ml}${gl}
19624
- <script>${B({mayBounce:no,formatPairInput:Dt,parsePairScan:ro})}</script>
19625
- <script>${hl}</script>
19626
- <script>${vl}</script>
20020
+ <head>${fn("Not paired \xB7 AgentX")}<style>${Zl}${ac}</style></head>
20021
+ <body>${Ql}${tc}
20022
+ <script>${q({mayBounce:So,formatPairInput:qt,parsePairScan:Eo})}</script>
20023
+ <script>${ec}</script>
20024
+ <script>${nc}</script>
19627
20025
  </body>
19628
- </html>`}function Nl(){return JSON.stringify({id:"/app",name:"AgentX",short_name:"AgentX",description:"Talk to your agents and watch your fleet.",start_url:"/app",scope:"/app",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/app/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var zm=`
20026
+ </html>`}function Sc(){return JSON.stringify({id:"/app",name:"AgentX",short_name:"AgentX",description:"Talk to your agents and watch your fleet.",start_url:"/app",scope:"/app",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/app/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var Wf=`
19629
20027
  (function () {
19630
20028
  var tabs = Array.prototype.slice.call(document.querySelectorAll('[role=tab]'));
19631
20029
  function select(tab, focus, keepHash) {
@@ -19697,7 +20095,7 @@ ${yl}
19697
20095
  navigator.serviceWorker.register('/app/sw.js', { scope: '/app' }).catch(function () {});
19698
20096
  }
19699
20097
  })();
19700
- `,qm=`
20098
+ `,Gf=`
19701
20099
  (function () {
19702
20100
  var msg = document.getElementById('msg');
19703
20101
  var m = /(?:^#|&)token=([^&]+)/.exec(location.hash);
@@ -19714,7 +20112,7 @@ ${yl}
19714
20112
  : 'Pairing failed (HTTP ' + r.status + '). Try again.';
19715
20113
  }).catch(function () { msg.textContent = 'Could not reach AgentX. Check this phone is on your tailnet, then try again.'; });
19716
20114
  })();
19717
- `,Fm=`
20115
+ `,Xf=`
19718
20116
  html, body { margin: 0; background: var(--ax-bg); color: var(--ax-text); font-family: var(--ax-font); }
19719
20117
  body { min-height: 100dvh; -webkit-text-size-adjust: 100%; }
19720
20118
  code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surface-3); padding: 1px 6px; border-radius: 6px; }
@@ -19726,7 +20124,7 @@ code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surf
19726
20124
  .card h1 { font-size: 22px; margin: 0 0 12px; }
19727
20125
  .muted { color: var(--ax-text-2); }
19728
20126
  :focus-visible { outline: 3px solid var(--ax-accent); outline-offset: 2px; }
19729
- `,Um=`
20127
+ `,Kf=`
19730
20128
  body { display: flex; flex-direction: column; }
19731
20129
  .bar {
19732
20130
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
@@ -19764,8 +20162,122 @@ main h2 { font-size: 20px; margin: 4px 0 8px; }
19764
20162
  }
19765
20163
  .tabs [role=tab][aria-selected=true] { background: var(--ax-accent-t); color: var(--ax-accent-2); }
19766
20164
  [data-theme="dark"] .tabs [role=tab][aria-selected=true] { color: var(--ax-text); }
19767
- `;var aa="agentx_app",Xm=400*86400,Km=new St,Jm=new Te;async function Dl(t,e,a,n,r={}){if(a!=="/app"&&!a.startsWith("/app/")&&!a.startsWith("/api/app/"))return!1;let o=r.tokens??new F;if(n==="GET"){if(a==="/app/manifest.webmanifest")return ve(e,200,"application/manifest+json",Nl());if(a==="/app/sw.js")return e.setHeader("Service-Worker-Allowed","/app"),ve(e,200,"text/javascript; charset=utf-8",nn);if(a==="/app/icon-192.png")return ve(e,200,"image/png",ze(192),"public, max-age=86400");if(a==="/app/icon-512.png")return ve(e,200,"image/png",ze(512),"public, max-age=86400");if(a==="/app/pair")return ve(e,200,"text/html; charset=utf-8",jl());if(a==="/app/qr.js"){let i=Vm();return i?ve(e,200,"text/javascript; charset=utf-8",i,"public, max-age=2592000"):Pe(e,404,{error:"not found"})}}if(n==="POST"&&a==="/api/app/session"){let i=on(nt(t),o);return i?(e.setHeader("Set-Cookie",sn(nt(t))),Pe(e,200,{device:i.name})):Pe(e,401,{error:"invalid or revoked device token"})}if(n==="POST"&&a==="/api/app/pair-code"){let i=await Jn(t,{codes:r.pairCodes??new vt,limiter:r.pairLimiter??Km,verify:l=>on(l,o)?.name??null,minMs:r.pairMinMs});return i.status===200&&e.setHeader("Set-Cookie",sn(i.token)),i.status===429&&e.setHeader("Retry-After",String(i.retryAfter)),Pe(e,i.status,i.body)}let s=on(Ym(t),o);if(!s){let i=nt(t);return(r.rejectLog??Jm).record(a.slice(0,120),Ot(t,Be(ln(t,aa),o),i?Be(i,o):null)),a==="/app"?ve(e,401,"text/html; charset=utf-8",Ol()):Pe(e,401,{error:"this device is not paired",hint:"run: agentx app pair"})}if(n==="GET"&&a==="/app"){let i=ln(t,aa);return i&&!nt(t)&&e.setHeader("Set-Cookie",sn(i)),ve(e,200,"text/html; charset=utf-8",Pl())}return n==="GET"&&a==="/api/app/me"?Pe(e,200,{id:s.id,device:s.name,node:r.nodeName??null}):r.fleet&&await Kn(t,e,a,n,s.name,r.fleet)||r.push&&await _i(t,e,a,n,s,r.push)||r.announce&&await Ti(t,e,a,n,s,r.announce)||r.chat&&await Ni(t,e,a,n,s,r.chat)||r.chat&&await zi(t,e,a,n,s,r.chat)||r.voice&&await Ui(t,e,a,n,s,r.voice)||r.camera&&await Wi(t,e,a,n,r.camera)?!0:Pe(e,404,{error:"not found"})}var at;function Vm(){if(at!==void 0)return at;try{let t=Gm(import.meta.url),{version:e}=t("jsqr/package.json"),a=`/*! jsQR ${e} | Apache-2.0 | https://github.com/cozmo/jsQR */
19768
- `;at=Buffer.concat([Buffer.from(a),Wm(t.resolve("jsqr"))])}catch(t){console.error(`[app] QR decoder unavailable (install the jsqr package): ${t.message}`),at=null}return at}function on(t,e){if(!t)return null;let a=e.verify(t);return a&&_e(a,"app")?a:null}function sn(t){return`${aa}=${t}; Path=/; Max-Age=${Xm}; HttpOnly; Secure; SameSite=Lax`}function Ym(t){return nt(t)??ln(t,aa)}function nt(t){let e=t.headers.authorization||"";return e.toLowerCase().startsWith("bearer ")&&e.slice(7).trim()||null}function ln(t,e){for(let a of(t.headers.cookie||"").split(";")){let n=a.indexOf("=");if(n>0&&a.slice(0,n).trim()===e)return a.slice(n+1).trim()||null}return null}function ve(t,e,a,n,r="no-store"){return t.writeHead(e,{"Content-Type":a,"Cache-Control":r}),t.end(n),!0}function Pe(t,e,a){return ve(t,e,"application/json",JSON.stringify(a))}import{randomBytes as Hl}from"crypto";var je={content:32e3,messagesPerConversation:200,conversationsPerDevice:100,toolsPerMessage:50,filesPerMessage:le.perMessage},Qm=/^[a-f0-9]{32}$/,Zm=/^c[a-z0-9]{8,32}$/,ef=/^#[0-9a-fA-F]{6}$/;function cn(t){return Zm.test(t)}var rt=class{constructor(e){this.db=e;e.exec(`CREATE TABLE IF NOT EXISTS app_chat_conversations (
20165
+ `;var sa="agentx_app",Yf=400*86400,Qf=new At,Zf=new Le;async function Ec(t,e,a,n,r={}){if(a==="/.well-known/assetlinks.json"&&n==="GET"){let i=r.assetLinks?.()??null;return i?fe(e,200,"application/json",JSON.stringify(i),"public, max-age=300"):Ee(e,404,{error:"not found"})}if(a!=="/app"&&!a.startsWith("/app/")&&!a.startsWith("/api/app/"))return!1;let o=r.tokens??new G;if(n==="GET"){if(a==="/app/manifest.webmanifest")return fe(e,200,"application/manifest+json",Sc());if(a==="/app/sw.js")return e.setHeader("Service-Worker-Allowed","/app"),fe(e,200,"text/javascript; charset=utf-8",mn);if(a==="/app/icon-192.png")return fe(e,200,"image/png",We(192),"public, max-age=86400");if(a==="/app/icon-512.png")return fe(e,200,"image/png",We(512),"public, max-age=86400");if(a==="/app/pair")return fe(e,200,"text/html; charset=utf-8",kc());if(a==="/app/qr.js"){let i=eh();return i?fe(e,200,"text/javascript; charset=utf-8",i,"public, max-age=2592000"):Ee(e,404,{error:"not found"})}}if(n==="POST"&&a==="/api/app/session"){let i=hn(it(t),o);return i?(e.setHeader("Set-Cookie",gn(it(t))),Ee(e,200,{device:i.name})):Ee(e,401,{error:"invalid or revoked device token"})}if(n==="POST"&&a==="/api/app/pair-code"){let i=await sr(t,{codes:r.pairCodes??new kt,limiter:r.pairLimiter??Qf,verify:l=>hn(l,o)?.name??null,minMs:r.pairMinMs});return i.status===200&&e.setHeader("Set-Cookie",gn(i.token)),i.status===429&&e.setHeader("Retry-After",String(i.retryAfter)),Ee(e,i.status,i.body)}let s=hn(th(t),o);if(!s){let i=it(t);return(r.rejectLog??Zf).record(a.slice(0,120),Ht(t,Ue(xn(t,sa),o),i?Ue(i,o):null)),a==="/app"?fe(e,401,"text/html; charset=utf-8",_c()):Ee(e,401,{error:"this device is not paired",hint:"run: agentx app pair"})}if(n==="GET"&&a==="/app"){let i=xn(t,sa);return i&&!it(t)&&e.setHeader("Set-Cookie",gn(i)),fe(e,200,"text/html; charset=utf-8",wc())}return n==="GET"&&a==="/api/app/me"?Ee(e,200,{id:s.id,device:s.name,node:r.nodeName??null}):r.fleet&&await or(t,e,a,n,s.name,r.fleet)||r.push&&await Fi(t,e,a,n,s,r.push)||r.announce&&await Gi(t,e,a,n,s,r.announce)||r.chat&&await nl(t,e,a,n,s,r.chat)||r.chat&&await il(t,e,a,n,s,r.chat)||r.voice&&await dl(t,e,a,n,s,r.voice)||r.camera&&await ul(t,e,a,n,r.camera)||r.places&&await El(t,e,a,n,s,r.places)?!0:Ee(e,404,{error:"not found"})}var st;function eh(){if(st!==void 0)return st;try{let t=Vf(import.meta.url),{version:e}=t("jsqr/package.json"),a=`/*! jsQR ${e} | Apache-2.0 | https://github.com/cozmo/jsQR */
20166
+ `;st=Buffer.concat([Buffer.from(a),Jf(t.resolve("jsqr"))])}catch(t){console.error(`[app] QR decoder unavailable (install the jsqr package): ${t.message}`),st=null}return st}function hn(t,e){if(!t)return null;let a=e.verify(t);return a&&Ae(a,"app")?a:null}function gn(t){return`${sa}=${t}; Path=/; Max-Age=${Yf}; HttpOnly; Secure; SameSite=Lax`}function th(t){return it(t)??xn(t,sa)}function it(t){let e=t.headers.authorization||"";return e.toLowerCase().startsWith("bearer ")&&e.slice(7).trim()||null}function xn(t,e){for(let a of(t.headers.cookie||"").split(";")){let n=a.indexOf("=");if(n>0&&a.slice(0,n).trim()===e)return a.slice(n+1).trim()||null}return null}function fe(t,e,a,n,r="no-store"){return t.writeHead(e,{"Content-Type":a,"Cache-Control":r}),t.end(n),!0}function Ee(t,e,a){return fe(t,e,"application/json",JSON.stringify(a))}function Tc(t){let e=ue({kicker:"Phone",title:"Places",lead:"Places your phone watches, and what to remind you of when you arrive or leave. The AgentX Android app on your phone notices the crossing and tells this computer only which place and which way: never where you are."})+`
20167
+ <div class="pl-wrap">
20168
+ <div id="pl-msg" class="pl-msg" role="status" aria-live="polite"></div>
20169
+ <form id="pl-add" class="pl-form" autocomplete="off">
20170
+ <h2>Add a place</h2>
20171
+ <label>Name <input name="name" required maxlength="60" placeholder="School"></label>
20172
+ <label>Coordinates <input name="coords" required placeholder="48.8584, 2.2945" inputmode="decimal" aria-describedby="pl-coords-help"></label>
20173
+ <p id="pl-coords-help" class="pl-help">Latitude, then longitude. In most map apps, long-press the spot and copy the numbers it shows.</p>
20174
+ <label>Radius in metres <input name="radius" type="number" step="10" inputmode="numeric"></label>
20175
+ <button type="submit" class="ax-btn ax-btn--primary">Add place</button>
20176
+ </form>
20177
+ <ol id="pl-list" class="pl-list" aria-label="Places"><li class="pl-empty">Loading\u2026</li></ol>
20178
+ </div>`;return I({title:"AgentX \xB7 Places",activeTab:"admin",subtitle:"Places",peers:t.peers,body:e,css:ah,scripts:`<script>${nh}</script>`})}var ah=`
20179
+ .pl-wrap { max-width: 1040px; margin: 0 auto; padding: 0 24px 96px; box-sizing: border-box; }
20180
+ .pl-msg { min-height: 1.4em; margin: 8px 0 0; }
20181
+ .pl-msg.is-bad { color: var(--ax-red-ink); }
20182
+ .pl-form { margin: 16px 0; padding: 14px 16px; display: grid; gap: 10px; max-width: 520px;
20183
+ border: var(--ax-border-w) solid var(--ax-border); border-radius: var(--ax-radius); background: var(--ax-surface); }
20184
+ .pl-form h2, .pl-item h2 { margin: 0; font-size: 16px; }
20185
+ .pl-form label { display: grid; gap: 4px; font-size: var(--ax-fs-sm); font-weight: 600; }
20186
+ .pl-form input, .pl-form select, .pl-rule-form input, .pl-rule-form select { font: inherit; padding: 8px 10px; min-height: 40px;
20187
+ border: var(--ax-border-w) solid var(--ax-border); border-radius: var(--ax-radius-sm); background: var(--ax-surface-2); color: var(--ax-text); }
20188
+ .pl-help { margin: -4px 0 0; color: var(--ax-text-2); font-size: var(--ax-fs-xs); }
20189
+ .pl-list { list-style: none; margin: 16px 0; padding: 0; display: grid; gap: 12px; }
20190
+ .pl-empty { color: var(--ax-text-2); }
20191
+ .pl-item { padding: 14px 16px; border: var(--ax-border-w) solid var(--ax-border); border-radius: var(--ax-radius); background: var(--ax-surface); }
20192
+ .pl-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 14px; }
20193
+ .pl-meta { margin: 4px 0 0; color: var(--ax-text-2); font-size: var(--ax-fs-sm); }
20194
+ .pl-rules { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
20195
+ .pl-rule { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; font-size: var(--ax-fs-sm); }
20196
+ .pl-rule.is-off { color: var(--ax-text-2); }
20197
+ .pl-rule-text { flex: 1 1 220px; overflow-wrap: anywhere; }
20198
+ .pl-rule-form { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
20199
+ .pl-rule-form input[name=text] { flex: 1 1 240px; }
20200
+ .pl-btns { margin-left: auto; display: flex; gap: 8px; }
20201
+ `,nh=`
20202
+ (function () {
20203
+ var list = document.getElementById('pl-list');
20204
+ var msg = document.getElementById('pl-msg');
20205
+ var form = document.getElementById('pl-add');
20206
+ function field(f, n) { return f.elements.namedItem(n); }
20207
+ var state = null;
20208
+ function esc(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); }
20209
+ function say(t, bad) { msg.textContent = t || ''; msg.className = 'pl-msg' + (bad ? ' is-bad' : ''); }
20210
+ function post(path, body) {
20211
+ return fetch('/api/places' + path, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'agentx-board' }, body: JSON.stringify(body) })
20212
+ .then(function (r) { return r.json().catch(function () { return {}; }).then(function (d) { if (!r.ok) throw new Error(d.error || ('HTTP ' + r.status)); return d; }); });
20213
+ }
20214
+ function ruleLine(r) {
20215
+ var what = (r.on === 'exit' ? 'When I leave: ' : 'When I arrive: ') + r.text;
20216
+ var how = (r.agent ? 'task for ' + r.agent : 'reminder') + (r.repeat ? ', every time' : ', once') + (r.enabled ? '' : (r.repeat ? ', paused' : ', done'));
20217
+ return '<li class="pl-rule' + (r.enabled ? '' : ' is-off') + '"><span class="pl-rule-text">' + esc(what) + ' <small>(' + esc(how) + ')</small></span>' +
20218
+ '<button type="button" class="ax-btn" data-act="toggle" data-id="' + esc(r.id) + '" data-on="' + (r.enabled ? '0' : '1') + '">' + (r.enabled ? 'Pause' : 'Turn on') + '</button>' +
20219
+ '<button type="button" class="ax-btn" data-act="rule-remove" data-id="' + esc(r.id) + '">Remove</button></li>';
20220
+ }
20221
+ function agentOptions() {
20222
+ return '<option value="">Just remind me</option>' + (state.agents || []).map(function (a) { return '<option value="' + esc(a) + '">Ask ' + esc(a) + '</option>'; }).join('');
20223
+ }
20224
+ function placeItem(p) {
20225
+ var rules = (state.rules || []).filter(function (r) { return r.placeId === p.id; });
20226
+ return '<li class="pl-item"><div class="pl-head"><h2>' + esc(p.name) + '</h2>' +
20227
+ '<div class="pl-btns"><button type="button" class="ax-btn" data-act="remove" data-id="' + esc(p.id) + '" data-name="' + esc(p.name) + '">Remove place</button></div></div>' +
20228
+ '<p class="pl-meta">' + esc(p.lat) + ', ' + esc(p.lng) + ' \xB7 ' + esc(p.radius) + ' m</p>' +
20229
+ (rules.length ? '<ul class="pl-rules">' + rules.map(ruleLine).join('') + '</ul>' : '<p class="pl-meta">No reminders yet.</p>') +
20230
+ '<form class="pl-rule-form" data-place="' + esc(p.id) + '">' +
20231
+ '<select name="on" aria-label="When"><option value="enter">When I arrive</option><option value="exit">When I leave</option></select>' +
20232
+ '<input name="text" required maxlength="500" placeholder="Pick up the parcel" aria-label="Reminder">' +
20233
+ '<select name="agent" aria-label="Who">' + agentOptions() + '</select>' +
20234
+ '<label><input type="checkbox" name="repeat"> Every time</label>' +
20235
+ '<button type="submit" class="ax-btn">Add reminder</button></form></li>';
20236
+ }
20237
+ function render() {
20238
+ if (!state.enabled) { list.innerHTML = '<li class="pl-empty">' + esc(state.reason) + '</li>'; form.hidden = true; return; }
20239
+ form.hidden = false;
20240
+ field(form, 'radius').placeholder = String(state.limits.defaultRadiusMeters);
20241
+ field(form, 'radius').min = String(state.limits.minRadiusMeters);
20242
+ field(form, 'radius').max = String(state.limits.maxRadiusMeters);
20243
+ if (!state.pushAvailable && state.pushReason) say('Reminders are saved but not sent: ' + state.pushReason, true);
20244
+ list.innerHTML = state.places.length ? state.places.map(placeItem).join('') : '<li class="pl-empty">No places yet. Add one above, or from the phone app.</li>';
20245
+ }
20246
+ function load() {
20247
+ fetch('/api/places', { credentials: 'same-origin', cache: 'no-store' }).then(function (r) { return r.json(); }).then(function (d) {
20248
+ if (d.error) { say(d.error, true); return; }
20249
+ state = d; render();
20250
+ }).catch(function () { say('Could not read the places. Is the dashboard running?', true); });
20251
+ }
20252
+ form.addEventListener('submit', function (ev) {
20253
+ ev.preventDefault();
20254
+ var parts = field(form, 'coords').value.split(',');
20255
+ if (parts.length !== 2) { say('Type the coordinates as latitude, longitude.', true); return; }
20256
+ post('/add', { name: field(form, 'name').value, lat: parts[0].trim(), lng: parts[1].trim(), radius: field(form, 'radius').value }).then(function (d) {
20257
+ say('Saved ' + d.place.name + '. Your phone picks it up the next time it checks.'); form.reset(); load();
20258
+ }).catch(function (e) { say(e.message, true); });
20259
+ });
20260
+ list.addEventListener('submit', function (ev) {
20261
+ var f = ev.target.closest('form[data-place]');
20262
+ if (!f) return;
20263
+ ev.preventDefault();
20264
+ post('/rules/add', { placeId: f.getAttribute('data-place'), on: field(f, 'on').value, text: field(f, 'text').value, agent: field(f, 'agent').value, repeat: field(f, 'repeat').checked })
20265
+ .then(function () { say('Reminder saved.'); load(); }).catch(function (e) { say(e.message, true); });
20266
+ });
20267
+ list.addEventListener('click', function (ev) {
20268
+ var b = ev.target.closest('button[data-act]');
20269
+ if (!b) return;
20270
+ var act = b.getAttribute('data-act'), id = b.getAttribute('data-id');
20271
+ if (act === 'remove' && !confirm('Remove ' + b.getAttribute('data-name') + ' and its reminders?')) return;
20272
+ var call = act === 'remove' ? post('/remove', { id: id })
20273
+ : act === 'rule-remove' ? post('/rules/remove', { id: id })
20274
+ : post('/rules/enable', { id: id, enabled: b.getAttribute('data-on') === '1' });
20275
+ b.disabled = true;
20276
+ call.then(function () { say(''); load(); }).catch(function (e) { say(e.message, true); b.disabled = false; });
20277
+ });
20278
+ load();
20279
+ })();
20280
+ `;import{randomBytes as Ac}from"crypto";var Be={content:32e3,messagesPerConversation:200,conversationsPerDevice:100,toolsPerMessage:50,filesPerMessage:de.perMessage},rh=/^[a-f0-9]{32}$/,oh=/^c[a-z0-9]{8,32}$/,sh=/^#[0-9a-fA-F]{6}$/;function bn(t){return oh.test(t)}var lt=class{constructor(e){this.db=e;e.exec(`CREATE TABLE IF NOT EXISTS app_chat_conversations (
19769
20281
  id TEXT PRIMARY KEY, device_id TEXT NOT NULL, title TEXT NOT NULL,
19770
20282
  node TEXT NOT NULL, node_name TEXT NOT NULL, agent TEXT NOT NULL, agent_name TEXT,
19771
20283
  created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL);
@@ -19778,39 +20290,39 @@ main h2 { font-size: 20px; margin: 4px 0 8px; }
19778
20290
  id TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, message_id INTEGER NOT NULL,
19779
20291
  path TEXT NOT NULL, name TEXT NOT NULL, mime TEXT NOT NULL, kind TEXT NOT NULL, created_at INTEGER NOT NULL);
19780
20292
  CREATE INDEX IF NOT EXISTS app_chat_files_conversation ON app_chat_files(conversation_id);`),e.prepare("PRAGMA table_info(app_chat_messages)").all().some(r=>r.name==="files")||e.exec("ALTER TABLE app_chat_messages ADD COLUMN files TEXT");let n=e.prepare("PRAGMA table_info(app_chat_conversations)").all();n.some(r=>r.name==="read_at")||e.transaction(()=>{e.prepare("PRAGMA table_info(app_chat_conversations)").all().some(o=>o.name==="read_at")||(e.exec("ALTER TABLE app_chat_conversations ADD COLUMN read_at INTEGER"),e.exec("UPDATE app_chat_conversations SET read_at = updated_at"))}).immediate(),n.some(r=>r.name==="color")||e.exec("ALTER TABLE app_chat_conversations ADD COLUMN color TEXT"),e.exec(`CREATE TABLE IF NOT EXISTS app_chat_delivered (
19781
- key TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, at INTEGER NOT NULL)`)}ownerOf(e){return cn(e)?this.db.prepare("SELECT device_id FROM app_chat_conversations WHERE id = ?").get(e)?.device_id??null:null}appendOnce(e,a,n,r,o=[],s=Date.now()){return!n||n.length>200?null:this.db.transaction(()=>!this.db.prepare("SELECT 1 FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e)||this.db.prepare("INSERT OR IGNORE INTO app_chat_delivered (key, conversation_id, at) VALUES (?, ?, ?)").run(n,a,s).changes===0?null:(this.db.prepare("DELETE FROM app_chat_delivered WHERE at < ?").run(s-30*24*60*6e4),this.appendWithFiles(e,a,r,o))).immediate()}create(e,a,n,r=Date.now()){let o=`c${r.toString(36)}${Hl(4).toString("hex")}`,{color:s,...i}=a,l=s&&ef.test(s)?s:void 0,c={id:o,title:af(n),...i,...l?{color:l}:{},createdAt:r,updatedAt:r,messages:[]};return this.db.prepare(`INSERT INTO app_chat_conversations
19782
- (id, device_id, title, node, node_name, agent, agent_name, color, created_at, updated_at, read_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,e,c.title,c.node,c.nodeName,c.agent,c.agentName??null,l??null,r,r,r),this.pruneDevice(e),c}get(e,a){if(!cn(a))return null;let n=this.db.prepare("SELECT * FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e);if(!n)return null;let r=this.db.prepare("SELECT * FROM app_chat_messages WHERE conversation_id = ? ORDER BY id").all(a).map(tf);return{...Bl(n),messages:r}}list(e,a=je.conversationsPerDevice){return this.db.prepare(`SELECT c.*,
20293
+ key TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, at INTEGER NOT NULL)`)}ownerOf(e){return bn(e)?this.db.prepare("SELECT device_id FROM app_chat_conversations WHERE id = ?").get(e)?.device_id??null:null}appendOnce(e,a,n,r,o=[],s=Date.now()){return!n||n.length>200?null:this.db.transaction(()=>!this.db.prepare("SELECT 1 FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e)||this.db.prepare("INSERT OR IGNORE INTO app_chat_delivered (key, conversation_id, at) VALUES (?, ?, ?)").run(n,a,s).changes===0?null:(this.db.prepare("DELETE FROM app_chat_delivered WHERE at < ?").run(s-30*24*60*6e4),this.appendWithFiles(e,a,r,o))).immediate()}create(e,a,n,r=Date.now()){let o=`c${r.toString(36)}${Ac(4).toString("hex")}`,{color:s,...i}=a,l=s&&sh.test(s)?s:void 0,c={id:o,title:lh(n),...i,...l?{color:l}:{},createdAt:r,updatedAt:r,messages:[]};return this.db.prepare(`INSERT INTO app_chat_conversations
20294
+ (id, device_id, title, node, node_name, agent, agent_name, color, created_at, updated_at, read_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,e,c.title,c.node,c.nodeName,c.agent,c.agentName??null,l??null,r,r,r),this.pruneDevice(e),c}get(e,a){if(!bn(a))return null;let n=this.db.prepare("SELECT * FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e);if(!n)return null;let r=this.db.prepare("SELECT * FROM app_chat_messages WHERE conversation_id = ? ORDER BY id").all(a).map(ih);return{...Cc(n),messages:r}}list(e,a=Be.conversationsPerDevice){return this.db.prepare(`SELECT c.*,
19783
20295
  (SELECT COUNT(*) FROM app_chat_messages m WHERE m.conversation_id = c.id) AS n,
19784
20296
  (SELECT substr(m.content, 1, 240) FROM app_chat_messages m WHERE m.conversation_id = c.id ORDER BY m.id DESC LIMIT 1) AS last
19785
- FROM app_chat_conversations c WHERE c.device_id = ? ORDER BY c.updated_at DESC, c.rowid DESC LIMIT ?`).all(e,Math.max(0,a)).map(r=>{let o=typeof r.last=="string"?r.last.replace(/\s+/g," ").trim().slice(0,120):"";return{...Bl(r),messages:r.n,...o?{last:o}:{}}})}markRead(e,a,n=Date.now()){cn(a)&&this.db.prepare("UPDATE app_chat_conversations SET read_at = MAX(COALESCE(read_at, 0), ?) WHERE id = ? AND device_id = ?").run(n,a,e)}unread(e,a){return this.db.prepare(`SELECT c.id, c.title, c.agent, c.agent_name, c.color,
20297
+ FROM app_chat_conversations c WHERE c.device_id = ? ORDER BY c.updated_at DESC, c.rowid DESC LIMIT ?`).all(e,Math.max(0,a)).map(r=>{let o=typeof r.last=="string"?r.last.replace(/\s+/g," ").trim().slice(0,120):"";return{...Cc(r),messages:r.n,...o?{last:o}:{}}})}markRead(e,a,n=Date.now()){bn(a)&&this.db.prepare("UPDATE app_chat_conversations SET read_at = MAX(COALESCE(read_at, 0), ?) WHERE id = ? AND device_id = ?").run(n,a,e)}unread(e,a){return this.db.prepare(`SELECT c.id, c.title, c.agent, c.agent_name, c.color,
19786
20298
  substr(m.content, 1, 240) AS answer, m.status, m.at
19787
20299
  FROM app_chat_conversations c
19788
20300
  JOIN app_chat_messages m ON m.id = (SELECT MAX(id) FROM app_chat_messages WHERE conversation_id = c.id)
19789
20301
  WHERE c.device_id = ? AND m.role = 'assistant' AND m.at > COALESCE(c.read_at, 0)
19790
- ORDER BY m.at DESC, m.id DESC LIMIT ?`).all(e,Math.max(0,a)).map(r=>({id:r.id,title:r.title,agent:r.agent,...r.agent_name?{agentName:r.agent_name}:{},...r.color?{color:r.color}:{},answer:String(r.answer??"").trim(),status:r.status==="error"||r.status==="stopped"?r.status:"done",at:r.at}))}append(e,a,n){return this.appendWithFiles(e,a,n)!==null}appendWithFiles(e,a,n,r=[]){if(!this.db.prepare("SELECT 1 FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e))return null;let s=n.content.length>je.content?n.content.slice(0,je.content)+`
20302
+ ORDER BY m.at DESC, m.id DESC LIMIT ?`).all(e,Math.max(0,a)).map(r=>({id:r.id,title:r.title,agent:r.agent,...r.agent_name?{agentName:r.agent_name}:{},...r.color?{color:r.color}:{},answer:String(r.answer??"").trim(),status:r.status==="error"||r.status==="stopped"?r.status:"done",at:r.at}))}append(e,a,n){return this.appendWithFiles(e,a,n)!==null}appendWithFiles(e,a,n,r=[]){if(!this.db.prepare("SELECT 1 FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e))return null;let s=n.content.length>Be.content?n.content.slice(0,Be.content)+`
19791
20303
 
19792
- [Cut here: the full answer is in the agent's task history.]`:n.content,i=n.tools?.slice(0,je.toolsPerMessage),l=[];for(let m of r){if(l.length>=je.filesPerMessage)break;let h=m.filename.trim(),_=On(h);if(!_||!h||h.length>le.pathChars||h.includes("\0"))continue;let v=(h.split(/[\\/]/).pop()||h).slice(0,120);l.push({id:Hl(16).toString("hex"),name:v,mime:_.mime,kind:_.kind,path:h})}let c=l.map(m=>({id:m.id,name:m.name,mime:m.mime,kind:m.kind})),p=this.db.prepare(`INSERT INTO app_chat_messages (conversation_id, role, content, status, error, ui, tools, files, at)
19793
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(a,n.role,s,n.status??null,n.error?.slice(0,500)??null,n.ui?JSON.stringify(n.ui):null,i?.length?JSON.stringify(i):null,c.length?JSON.stringify(c):null,n.at),u=this.db.prepare(`INSERT INTO app_chat_files (id, conversation_id, message_id, path, name, mime, kind, created_at)
19794
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);for(let m of l)u.run(m.id,a,Number(p.lastInsertRowid),m.path,m.name,m.mime,m.kind,n.at);return this.db.prepare(`DELETE FROM app_chat_messages WHERE conversation_id = ? AND id NOT IN
19795
- (SELECT id FROM app_chat_messages WHERE conversation_id = ? ORDER BY id DESC LIMIT ?)`).run(a,a,je.messagesPerConversation),this.db.prepare(`DELETE FROM app_chat_files WHERE conversation_id = ? AND message_id NOT IN
19796
- (SELECT id FROM app_chat_messages WHERE conversation_id = ?)`).run(a,a),this.db.prepare("UPDATE app_chat_conversations SET updated_at = ? WHERE id = ?").run(n.at,a),c}getFile(e,a){if(!Qm.test(a))return null;let n=this.db.prepare(`SELECT f.*, c.node, c.agent FROM app_chat_files f
20304
+ [Cut here: the full answer is in the agent's task history.]`:n.content,i=n.tools?.slice(0,Be.toolsPerMessage),l=[];for(let m of r){if(l.length>=Be.filesPerMessage)break;let f=m.filename.trim(),S=Xn(f);if(!S||!f||f.length>de.pathChars||f.includes("\0"))continue;let b=(f.split(/[\\/]/).pop()||f).slice(0,120);l.push({id:Ac(16).toString("hex"),name:b,mime:S.mime,kind:S.kind,path:f})}let c=l.map(m=>({id:m.id,name:m.name,mime:m.mime,kind:m.kind})),d=this.db.prepare(`INSERT INTO app_chat_messages (conversation_id, role, content, status, error, ui, tools, files, at)
20305
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(a,n.role,s,n.status??null,n.error?.slice(0,500)??null,n.ui?JSON.stringify(n.ui):null,i?.length?JSON.stringify(i):null,c.length?JSON.stringify(c):null,n.at),p=this.db.prepare(`INSERT INTO app_chat_files (id, conversation_id, message_id, path, name, mime, kind, created_at)
20306
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);for(let m of l)p.run(m.id,a,Number(d.lastInsertRowid),m.path,m.name,m.mime,m.kind,n.at);return this.db.prepare(`DELETE FROM app_chat_messages WHERE conversation_id = ? AND id NOT IN
20307
+ (SELECT id FROM app_chat_messages WHERE conversation_id = ? ORDER BY id DESC LIMIT ?)`).run(a,a,Be.messagesPerConversation),this.db.prepare(`DELETE FROM app_chat_files WHERE conversation_id = ? AND message_id NOT IN
20308
+ (SELECT id FROM app_chat_messages WHERE conversation_id = ?)`).run(a,a),this.db.prepare("UPDATE app_chat_conversations SET updated_at = ? WHERE id = ?").run(n.at,a),c}getFile(e,a){if(!rh.test(a))return null;let n=this.db.prepare(`SELECT f.*, c.node, c.agent FROM app_chat_files f
19797
20309
  JOIN app_chat_conversations c ON c.id = f.conversation_id WHERE f.id = ? AND c.device_id = ?`).get(a,e);return n?{id:n.id,name:n.name,mime:n.mime,kind:n.kind,path:n.path,conversationId:n.conversation_id,node:n.node,agent:n.agent}:null}pruneDevice(e){let a=this.db.prepare(`SELECT id FROM app_chat_conversations WHERE device_id = ?
19798
- ORDER BY updated_at DESC, rowid DESC LIMIT -1 OFFSET ?`).all(e,je.conversationsPerDevice);for(let{id:n}of a)this.db.prepare("DELETE FROM app_chat_files WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_messages WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_conversations WHERE id = ?").run(n)}};function Bl(t){return{id:t.id,title:t.title,node:t.node,nodeName:t.node_name,agent:t.agent,...t.agent_name?{agentName:t.agent_name}:{},...t.color?{color:t.color}:{},createdAt:t.created_at,updatedAt:t.updated_at}}function tf(t){let e=o=>{if(o)try{return JSON.parse(o)}catch{return}},a=e(t.ui),n=e(t.tools),r=e(t.files);return{role:t.role,content:t.content,at:t.at,...t.status?{status:t.status}:{},...t.error?{error:t.error}:{},...a?{ui:a}:{},...n?{tools:n}:{},...r?{files:r}:{}}}function af(t){let e=t.replace(/\s+/g," ").trim();return(e.length>60?e.slice(0,59)+"\u2026":e)||"Untitled"}var nf=4e3,dn=100,rf=15,zl=t=>t.replace(/\/+$/,""),na=class{constructor(e){this.deps=e}cursor;retry=new Map;timer;running=!1;start(e=nf){this.timer||(this.timer=setInterval(()=>{this.tick()},e),this.timer.unref?.())}stop(){this.timer&&clearInterval(this.timer),this.timer=void 0}async tick(){if(this.running)return 0;this.running=!0;try{let e,a=!1;try{let o=await this.deps.recent(this.cursor,dn);e=Array.isArray(o)?o:o.events,a=!Array.isArray(o)&&o.gap===!0}catch{return 0}this.warnIfSkipped(e.length,a),e.length&&(this.cursor=e[e.length-1].id);let n=[...this.retry.values()].map(o=>o.event);for(let o of e)o.kind==="delegation"&&o.type==="reply"&&typeof o.ref=="string"&&o.ref&&!this.retry.has(o.id)&&n.push(o);let r=0;for(let o of n){let s=await this.file(o).catch(()=>"retry");if(s==="retry"){let i=(this.retry.get(o.id)?.left??rf)-1;i>0?this.retry.set(o.id,{event:o,left:i}):(this.retry.delete(o.id),this.deps.log?.(`[app] callback reply ${o.ref} from ${o.node} could not be read; it stays in the agent's session`))}else this.retry.delete(o.id),s==="filed"&&r++}return r}finally{this.running=!1}}warnIfSkipped(e,a){let n=this.deps.warn??this.deps.log,r=this.cursor?`after event ${this.cursor}`:"on the first read";a&&n?.(`[app] warning: callback event cursor ${this.cursor} is no longer in the daemon's event ring; replies published before the oldest kept event were skipped`),e>=dn&&n?.(`[app] warning: one poll returned ${e} delegation events, the most it reads (${dn}); older replies ${r} may have been skipped`)}async file(e){let a=this.deps.store();if(!a)return"retry";let n=await this.deps.nodeUrl(e.node);if(!n)return"retry";let r=await this.deps.fetchReply(n,e.ref);if(!r||r.taskId!==e.ref||r.channel!=="app"||!r.chatId.startsWith("app:"))return"skip";let o=r.chatId.slice(4),s=a.ownerOf(o);if(!s)return"skip";let i=a.get(s,o);if(!i)return"skip";let l=await this.deps.conversationUrl(i);if(!l||zl(l)!==zl(n)||i.agent!==r.agent)return this.deps.log?.(`[app] callback reply ${r.taskId} from ${e.node} does not match conversation ${o}; ignored`),"skip";let c=of(r,this.deps.now?.()??Date.now());if(a.appendOnce(s,o,`dlg:${e.node}:${r.taskId}`,c.row,c.declared)===null)return"skip";let u=c.row.status,m=!!this.deps.finishAlerts?.(s),h={status:u,attached:!1,appOpen:this.deps.presence.open(s),enabled:m};return this.deps.notifyFinish&&Zt(h)&&this.deps.notifyFinish(ea(s,i,u,c.row.content,c.row.error)).catch(()=>{}),"filed"}};function of(t,e){let a=t.plain?{text:ht(t.text,!1),artifacts:[]}:ft(t.text,le.perMessage,!1),{cleanText:n,ui:r}=xt(a.text),o=t.plain?void 0:Ja(r),s=t.status==="error"?"error":"done";return{row:{role:"assistant",content:n,status:s,...s==="error"?{error:sf(n)}:{},...o?{ui:o}:{},at:e},declared:a.artifacts}}function sf(t){return t.replace(/\s+/g," ").trim().slice(0,300)}Sn();function Ge(){let t=dt();return t&&we(t,"dashboard"),t}function Zw(t){let e=t.dashboard,a=t.boards,n=e.port,r=e.bind,o=e.token,s=new Map;for(let h of a)try{s.set(h.id,bf(h,t))}catch(_){console.error(` Board "${h.id}" failed to initialize: ${_.message}`)}let i=t.node?.id||"local",l=t.workflows?.dir?ot(process.cwd(),t.workflows.dir):void 0,c=new Rn(l?{baseDir:l}:void 0),p=new $n(l?{baseDir:l,nodeId:i}:{nodeId:i}),u=new Pn(l?{baseDir:l}:void 0);qs(t),Ge(),nr({business:t.business?.enabled===!0});let m=lf(async(h,_)=>{try{await hf(h,_,{boards:a,sources:s,token:o,config:t,workflowStore:c,workflowRuns:p,workflowLayouts:u})}catch(v){y(_,500,{error:v.message||"internal error"})}});Of(t).start(),m.listen(n,r,()=>{let h=r==="0.0.0.0"?"localhost":r;a.length===0?(console.log(`
19799
- Live dashboard: http://${h}:${n}
20310
+ ORDER BY updated_at DESC, rowid DESC LIMIT -1 OFFSET ?`).all(e,Be.conversationsPerDevice);for(let{id:n}of a)this.db.prepare("DELETE FROM app_chat_files WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_messages WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_conversations WHERE id = ?").run(n)}};function Cc(t){return{id:t.id,title:t.title,node:t.node,nodeName:t.node_name,agent:t.agent,...t.agent_name?{agentName:t.agent_name}:{},...t.color?{color:t.color}:{},createdAt:t.created_at,updatedAt:t.updated_at}}function ih(t){let e=o=>{if(o)try{return JSON.parse(o)}catch{return}},a=e(t.ui),n=e(t.tools),r=e(t.files);return{role:t.role,content:t.content,at:t.at,...t.status?{status:t.status}:{},...t.error?{error:t.error}:{},...a?{ui:a}:{},...n?{tools:n}:{},...r?{files:r}:{}}}function lh(t){let e=t.replace(/\s+/g," ").trim();return(e.length>60?e.slice(0,59)+"\u2026":e)||"Untitled"}var ch=4e3,vn=100,dh=15,Ic=t=>t.replace(/\/+$/,""),ia=class{constructor(e){this.deps=e}cursor;retry=new Map;timer;running=!1;start(e=ch){this.timer||(this.timer=setInterval(()=>{this.tick()},e),this.timer.unref?.())}stop(){this.timer&&clearInterval(this.timer),this.timer=void 0}async tick(){if(this.running)return 0;this.running=!0;try{let e,a=!1;try{let o=await this.deps.recent(this.cursor,vn);e=Array.isArray(o)?o:o.events,a=!Array.isArray(o)&&o.gap===!0}catch{return 0}this.warnIfSkipped(e.length,a),e.length&&(this.cursor=e[e.length-1].id);let n=[...this.retry.values()].map(o=>o.event);for(let o of e)o.kind==="delegation"&&o.type==="reply"&&typeof o.ref=="string"&&o.ref&&!this.retry.has(o.id)&&n.push(o);let r=0;for(let o of n){let s=await this.file(o).catch(()=>"retry");if(s==="retry"){let i=(this.retry.get(o.id)?.left??dh)-1;i>0?this.retry.set(o.id,{event:o,left:i}):(this.retry.delete(o.id),this.deps.log?.(`[app] callback reply ${o.ref} from ${o.node} could not be read; it stays in the agent's session`))}else this.retry.delete(o.id),s==="filed"&&r++}return r}finally{this.running=!1}}warnIfSkipped(e,a){let n=this.deps.warn??this.deps.log,r=this.cursor?`after event ${this.cursor}`:"on the first read";a&&n?.(`[app] warning: callback event cursor ${this.cursor} is no longer in the daemon's event ring; replies published before the oldest kept event were skipped`),e>=vn&&n?.(`[app] warning: one poll returned ${e} delegation events, the most it reads (${vn}); older replies ${r} may have been skipped`)}async file(e){let a=this.deps.store();if(!a)return"retry";let n=await this.deps.nodeUrl(e.node);if(!n)return"retry";let r=await this.deps.fetchReply(n,e.ref);if(!r||r.taskId!==e.ref||r.channel!=="app"||!r.chatId.startsWith("app:"))return"skip";let o=r.chatId.slice(4),s=a.ownerOf(o);if(!s)return"skip";let i=a.get(s,o);if(!i)return"skip";let l=await this.deps.conversationUrl(i);if(!l||Ic(l)!==Ic(n)||i.agent!==r.agent)return this.deps.log?.(`[app] callback reply ${r.taskId} from ${e.node} does not match conversation ${o}; ignored`),"skip";let c=ph(r,this.deps.now?.()??Date.now());if(a.appendOnce(s,o,`dlg:${e.node}:${r.taskId}`,c.row,c.declared)===null)return"skip";let p=c.row.status,m=!!this.deps.finishAlerts?.(s),f={status:p,attached:!1,appOpen:this.deps.presence.open(s),enabled:m};return this.deps.notifyFinish&&na(f)&&this.deps.notifyFinish(ra(s,i,p,c.row.content,c.row.error)).catch(()=>{}),"filed"}};function ph(t,e){let a=t.plain?{text:vt(t.text,!1),artifacts:[]}:bt(t.text,de.perMessage,!1),{cleanText:n,ui:r}=wt(a.text),o=t.plain?void 0:rn(r),s=t.status==="error"?"error":"done";return{row:{role:"assistant",content:n,status:s,...s==="error"?{error:uh(n)}:{},...o?{ui:o}:{},at:e},declared:a.artifacts}}function uh(t){return t.replace(/\s+/g," ").trim().slice(0,300)}$n();function Ye(){let t=ft();return t&&Se(t,"dashboard"),t}function E0(t){let e=t.dashboard,a=t.boards,n=e.port,r=e.bind,o=e.token,s=new Map;for(let f of a)try{s.set(f.id,Sh(f,t))}catch(S){console.error(` Board "${f.id}" failed to initialize: ${S.message}`)}let i=t.node?.id||"local",l=t.workflows?.dir?ct(process.cwd(),t.workflows.dir):void 0,c=new Fn(l?{baseDir:l}:void 0),d=new Un(l?{baseDir:l,nodeId:i}:{nodeId:i}),p=new Wn(l?{baseDir:l}:void 0);li(t),Ye(),fr({business:t.business?.enabled===!0});let m=mh(async(f,S)=>{try{await yh(f,S,{boards:a,sources:s,token:o,config:t,workflowStore:c,workflowRuns:d,workflowLayouts:p})}catch(b){k(S,500,{error:b.message||"internal error"})}});zh(t).start(),m.listen(n,r,()=>{let f=r==="0.0.0.0"?"localhost":r;a.length===0?(console.log(`
20311
+ Live dashboard: http://${f}:${n}
19800
20312
  `),console.log(" (no boards configured \u2014 '/' serves the live view; add a board with 'agentx board add')")):(console.log(`
19801
- Kanban dashboard: http://${h}:${n}
19802
- `),console.log(` Boards: ${a.map(_=>_.id).join(", ")}`)),r==="127.0.0.1"&&!o?console.log(" (bound to localhost; no auth token \u2014 safe default)"):r!=="127.0.0.1"&&!o&&console.log(" \u26A0 bound to a non-loopback address without a token \u2014 writes are UNAUTHENTICATED")})}var ff=new Set(["/","/live","/mesh","/monitor","/activity","/boards","/glossary","/workflows","/workflows/editor","/procedures","/processes","/graph","/setup","/admin","/admin/graph","/approvals","/people","/admin/health","/admin/observability","/admin/ledger","/admin/cost","/admin/projects","/admin/wiki"]);async function hf(t,e,a){let n=new URL(t.url||"/","http://localhost"),r=n.pathname,o=(t.method||"GET").toUpperCase();if((t.url||"/").split(/[?#]/)[0]!==r){y(e,404,{error:"not found"});return}if(tr(t.headers)==="foreign"&&ar(o)){y(e,403,{error:"Forbidden: request from a page on another origin"});return}if(o==="OPTIONS"){e.writeHead(204),e.end();return}if(await Io(t,e,r,o,{nodeName:a.config.node?.name,root:process.cwd(),people:()=>Ye(a.config.people),members:ql(a.config.members.logRetentionDays),db:()=>Ge(),linkFor:(d,f)=>Vr(d,f,{gitlab:a.config.channels.gitlab?.host})})||await Dl(t,e,r,o,{nodeName:a.config.node?.name,fleet:Kl(a.config),push:Xl(a.config),announce:Ai(a.config),chat:Jl(a.config),voice:Nf(a.config),camera:Df(a.config)}))return;if(o==="GET"&&ff.has(r)&&Nr("page",r),o==="GET"&&r==="/"){let d=_r();if(!d.configExists||d.agentCount===0){e.writeHead(302,{Location:"/setup"}),e.end();return}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Xa({peers:D(a.config)}));return}if(o==="GET"&&r==="/boards"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(fi({peers:D(a.config)}));return}if(o==="GET"&&r==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Xa({peers:D(a.config)}));return}if(o==="POST"&&r.match(/^\/webhook\/n8n\/[A-Za-z0-9._:-]{1,64}$/)){try{let[d]=await ke(a.config);if(!d){y(e,503,{error:"no node available"});return}let f=await new Promise(b=>{let k="";t.on("data",T=>k+=T),t.on("end",()=>b(k)),t.on("error",()=>b(""))}),x=await fetch(d.url+r,{method:"POST",headers:{"Content-Type":"application/json",...d.token?{Authorization:`Bearer ${d.token}`}:{}},body:f||"{}"});e.writeHead(x.status,{"Content-Type":"application/json"}),e.end(await x.text())}catch(d){y(e,502,{error:"could not reach the node",message:String(d?.message||d)})}return}if(r==="/api/assistant"||r.startsWith("/api/assistant/")){try{let d=await ke(a.config),f=o==="POST"?void 0:n.searchParams.get("node"),x=o==="POST"?await pe(t):void 0,b=x?.node??f,k=b?d.find(I=>I.url===b):d[0];if(!k){y(e,400,{error:"unknown node"});return}let T=n.search?n.search.replace(/([?&])node=[^&]*/,"$1").replace(/[?&]$/,""):"",w=await fetch(k.url+r+T,{method:o,headers:{"Content-Type":"application/json",...k.token?{Authorization:`Bearer ${k.token}`}:{}},...o==="POST"?{body:JSON.stringify({...x,node:void 0})}:{}});y(e,w.status,await w.json().catch(()=>({error:`HTTP ${w.status}`})))}catch(d){y(e,502,{error:"could not reach the node",message:d?.message||String(d)})}return}if(o==="POST"&&r==="/api/workflows/editor/chat"){try{let d=await pe(t),f={"Content-Type":"application/json"};a.config.dashboard.token&&(f.Authorization=`Bearer ${a.config.dashboard.token}`);let x=a.config.dashboard.daemonUrl.replace(/\/+$/,""),b=await fetch(`${x}/api/workflows/editor/chat`,{method:"POST",headers:f,body:JSON.stringify(d??{})}),k=await b.json().catch(()=>({error:`HTTP ${b.status}`}));y(e,b.status,k)}catch(d){y(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(o==="GET"&&r==="/api/n8n/workflows"){try{let[d]=await ke(a.config);if(!d){y(e,200,{configured:!1,workflows:[]});return}let f=await fetch(d.url+"/api/n8n/workflows",{headers:d.token?{Authorization:`Bearer ${d.token}`}:{}});y(e,f.status,await f.json().catch(()=>({configured:!1,workflows:[]})))}catch{y(e,200,{configured:!1,workflows:[]})}return}if(o==="GET"&&r==="/workflows/editor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Xr({peers:D(a.config)}));return}if(o==="GET"&&r==="/activity"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Gr({peers:D(a.config),view:n.searchParams.get("view")}));return}if(o==="GET"&&r==="/monitor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(qr({peers:D(a.config)}));return}if(r==="/api/monitor"||r.startsWith("/api/monitor/")){let d=new AbortController,f=setTimeout(()=>d.abort(),8e3);try{let x=Dn(await ke(a.config,d.signal),a.config.mesh.peers);if(o==="GET"&&r==="/api/monitor"){let I=await Promise.all(x.map(async C=>{try{let E=await fetch(C.url+"/monitor",{headers:C.token?{Authorization:`Bearer ${C.token}`}:{},signal:d.signal});if(!E.ok)throw new Error(`HTTP ${E.status}`);return{name:C.name,url:C.url,ok:!0,data:await E.json()}}catch(E){return{name:C.name,url:C.url,ok:!1,error:E.message}}}));y(e,200,{nodes:I});return}let b=x.find(I=>I.url===n.searchParams.get("node"));if(!b){y(e,400,{error:"Select a known node"});return}let k=r.slice(13);if(!(o==="GET"&&["discover","actions","activity"].includes(k)||o==="POST"&&["register","ended","action","retry","clear"].includes(k))){y(e,405,{error:"Unknown monitor operation"});return}let T=o==="POST"?JSON.stringify(await Nn(t)):void 0,w=await fetch(b.url+"/monitor/"+k+(k==="actions"?"?offset="+encodeURIComponent(n.searchParams.get("offset")||"0"):k==="activity"?"?hours="+encodeURIComponent(n.searchParams.get("hours")||"24"):""),{method:o,body:T,signal:d.signal,headers:{"Content-Type":"application/json",...b.token?{Authorization:`Bearer ${b.token}`}:{}}});y(e,w.status,await w.json())}catch(x){y(e,502,{error:x.message})}finally{clearTimeout(f)}return}if(o==="GET"&&r==="/mesh"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ci({peers:D(a.config)}));return}if(o==="GET"&&r==="/guests"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(di({peers:D(a.config)}));return}if(o==="GET"&&r==="/api/guests"||o==="POST"&&/^\/api\/guests\/[^/]+\/(pause|resume|end|update)$/.test(r)){try{let d={"Content-Type":"application/json"};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let f=a.config.dashboard.daemonUrl.replace(/\/+$/,""),x=o==="POST"?await pe(t).catch(()=>({})):void 0,b=await fetch(`${f}${r.replace(/^\/api\/guests/,"/mesh/guests")}`,{method:o,headers:d,...x!==void 0?{body:JSON.stringify(x??{})}:{}});y(e,b.status,await b.json().catch(()=>({error:`HTTP ${b.status}`})))}catch(d){y(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(o==="GET"&&r==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(hi({peers:D(a.config)}));return}if(o==="GET"&&r==="/workflows"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(gi({peers:D(a.config)}));return}if(o==="GET"&&r==="/procedures"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(xi({peers:D(a.config)}));return}if(o==="GET"&&r==="/processes"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(kr({}));return}let i=o==="GET"&&r.match(/^\/tasks\/([^/]+)$/);if(i){let d=n.searchParams.get("agent")||"",f=n.searchParams.get("node")||a.config.dashboard.daemonUrl;if(!d){e.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),e.end("<p>Missing <code>?agent=</code>. Open this task from the Live page.</p>");return}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(vi({taskId:decodeURIComponent(i[1]),agentId:d,agentName:n.searchParams.get("name")||void 0,channel:n.searchParams.get("channel")||void 0,archived:n.searchParams.get("archived")==="1",ask:n.searchParams.get("ask")||void 0,askAt:n.searchParams.get("at")||void 0,nodeUrl:f,peers:D(a.config)}));return}let l=o==="GET"&&r.match(/^\/agents\/([^/]+)\/history$/);if(l){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(bi({agentId:decodeURIComponent(l[1]),agentName:n.searchParams.get("name")||void 0,nodeUrl:n.searchParams.get("node")||a.config.dashboard.daemonUrl,peers:D(a.config)}));return}if(o==="GET"&&r==="/graph"){e.writeHead(302,{Location:"/admin/graph"}),e.end();return}if(o==="GET"&&r==="/setup"){Sr(t,e);return}if(o==="POST"&&r==="/api/setup"){await Er(t,e);return}if(o==="POST"&&r==="/api/setup/start-daemon"){await Tr(t,e);return}if(o==="GET"&&r==="/admin"){Bo(t,e,D(a.config),a.token);return}if(o==="GET"&&r==="/approvals"){ns(e,D(a.config),a.token);return}if(o==="GET"&&r==="/admin/graph"){Xo(t,e,D(a.config),a.token);return}if(o==="GET"&&(r==="/admin/health"||r==="/admin/observability")){if(r==="/admin/observability"){e.writeHead(302,{Location:"/admin/health"}),e.end();return}ms(t,e,D(a.config));return}if(r.startsWith("/api/admin/")||r.startsWith("/api/workflows")||r.startsWith("/api/agents")){let d=n.searchParams.get("peer")==="fleet"?"fleet":String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(d==="fleet"){if(r==="/api/admin/activity-graph"){await Uf(t,e,a);return}if(r==="/api/admin/activity-graph/stream"){await Wa(t,e,r,x=>Yl(x,a.config));return}let f=r.match(/^\/api\/admin\/activity-graph\/dispatch\/(.+)$/);if(f){let x=decodeURIComponent(f[1]),b=x.indexOf("::");if(b>0){let k=x.slice(0,b),T=x.slice(b+2),w=a.config.node?.id||a.config.node?.name||"local";if(k===w)t.url=`/api/admin/activity-graph/dispatch/${encodeURIComponent(T)}`;else{let I=(a.config.dashboard?.daemons||[]).find(C=>(C.name||C.url)===k);if(I){let C=st(I.url.replace(/\/+$/,""),a.config);if(C){await Ul(t,e,C,`/api/admin/activity-graph/dispatch/${encodeURIComponent(T)}`);return}}y(e,404,{error:`unknown node "${k}" in fleet dispatch id`});return}}}}else if(d&&d!=="primary"){let f=st(d,a.config);if(!f){y(e,404,{error:`unknown peer: ${d}`});return}let x=(n.search||"").replace(/[?&]peer=[^&]*/g,k=>k.startsWith("?")?"?":"");await Ul(t,e,f,r+(x==="?"?"":x));return}}if(o==="GET"&&r.startsWith("/api/admin/observability/")&&await fs(t,e,r))return;if(o==="GET"&&r==="/api/admin/logs/stream"){await Wf(t,e);return}if(o==="GET"&&r==="/api/admin/doctor"){try{let{runDoctorChecks:d}=await import("./doctor-AUF5HJPW.js"),x=new URL(t.url||"/","http://_").searchParams.get("running")!=="false",b=await d({running:x});y(e,200,b)}catch(d){y(e,500,{error:d?.message||String(d)})}return}if(o==="GET"&&r==="/admin/ledger"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(vs({peers:D(a.config)}));return}if(o==="GET"&&r.startsWith("/api/admin/ledger/")&&await xs(t,e,r))return;if(o==="GET"&&r==="/admin/cost"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(bs({peers:D(a.config)}));return}if(o==="GET"&&r==="/admin/projects"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ys({peers:D(a.config)}));return}if(o==="GET"&&(r==="/admin/wiki"||r.startsWith("/admin/wiki/"))){if(r==="/admin/wiki"){e.writeHead(302,{Location:"/admin/wiki/"}),e.end();return}await kf(a)(t,e);return}if(o==="GET"&&r==="/admin/activity-graph"){e.writeHead(302,{Location:"/activity?view=map"}),e.end();return}if(o==="GET"&&r==="/api/admin/activity-graph"&&await Fs(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/stream")&&await Wa(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/dispatch/")&&await Ws(t,e,r))return;let c=o==="GET"&&r.match(/^\/admin\/agents\/([a-z0-9][a-z0-9_-]*)$/);if(c){Ks(t,e,c[1],D(a.config),a.token);return}if(r.startsWith("/api/admin/")&&a.token){let d=t.headers.authorization||"",f=d.startsWith("Bearer ")?d.slice(7):"";if(f!==a.token){let x=new F,b=f?x.verify(f):null;if(!b||!_e(b,"dashboard:write")){y(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/admin/config"){await zo(t,e);return}if(o==="GET"&&r==="/api/admin/voice-health"){y(e,200,sr()??{checkedAt:null,missing:[]});return}if(r.startsWith("/api/admin/approvals")){await rs(t,e,r,n);return}if(await ss(t,e,r,{people:()=>Ye(a.config.people),members:ql(a.config.members.logRetentionDays),root:process.cwd(),db:()=>Ge(),peers:D(a.config),localToken:a.token}))return;if(r.startsWith("/api/admin/graph/")){await Ko(t,e,r);return}if(r.startsWith("/api/admin/agent/")){await Js(t,e,r);return}if(r.startsWith("/api/admin/")){await qo(t,e,r);return}if(o==="GET"&&r==="/sortable.min.js"){e.writeHead(200,{"Content-Type":"application/javascript; charset=utf-8","Cache-Control":"public, max-age=86400"}),e.end(Mo);return}if(o==="GET"&&r.startsWith("/assets/")){let d=r.slice(8);if(!/^[a-zA-Z0-9._-]+\.(js|map|css)$/.test(d)){y(e,400,{error:"invalid asset name"});return}let f=qf("web/"+d);try{let x=await Ff(f),b=d.endsWith(".map")?"application/json; charset=utf-8":d.endsWith(".css")?"text/css; charset=utf-8":"application/javascript; charset=utf-8",k=n.searchParams.has("v");e.writeHead(200,{"Content-Type":b,"Cache-Control":k?"public, max-age=31536000, immutable":"public, max-age=60"}),e.end(x)}catch{y(e,404,{error:"asset not found",hint:"run: npm run build:web"})}return}if(o==="GET"&&r==="/api/live"){try{let d=await Xe(a.config);y(e,200,d)}catch(d){y(e,502,{error:d.message})}return}if(o==="GET"&&r==="/api/mesh"){try{let d=n.searchParams.get("date")||new Date().toISOString().slice(0,10),f=n.searchParams.get("timezone")||"UTC",x=await Xe(a.config,{date:d,timezone:f});y(e,200,x)}catch(d){y(e,502,{error:d.message})}return}if(o==="GET"&&r==="/api/mesh/analytics"){let d=(f,x,b,k)=>{let T=parseInt(n.searchParams.get(f)||"",10);return Number.isFinite(T)?Math.max(b,Math.min(k,T)):x};try{let f=await ke(a.config);y(e,200,await pi(f,{days:d("days",30,0,180),tzOffsetMinutes:d("tzOffset",0,-840,840),limit:d("limit",60,1,200)}))}catch(f){y(e,502,{error:f.message})}return}if(o==="GET"&&r==="/api/mesh/day"){let d=n.searchParams.get("day")||"";if(!/^\d{4}-\d{2}-\d{2}$/.test(d)){y(e,400,{error:"day=YYYY-MM-DD query param required"});return}let f=(x,b,k,T)=>{let w=parseInt(n.searchParams.get(x)||"",10);return Number.isFinite(w)?Math.max(k,Math.min(T,w)):b};try{let x=await ke(a.config);y(e,200,await mi(x,{day:d,tzOffsetMinutes:f("tzOffset",0,-840,840),limit:f("limit",40,1,200)}))}catch(x){y(e,502,{error:x.message})}return}if(o==="GET"&&(r==="/api/mesh/thread"||r==="/api/mesh/job"||r==="/api/mesh/run"||r==="/api/mesh/conversation")){let d=n.searchParams.get("node");if(!d){y(e,400,{error:"node query param required"});return}let f=n.searchParams,x;if(r==="/api/mesh/thread"){let[b,k,T]=[f.get("agent"),f.get("channel"),f.get("chat")];if(!b||!k||!T){y(e,400,{error:"agent, channel, chat required"});return}x=`/analytics/thread?agent=${encodeURIComponent(b)}&channel=${encodeURIComponent(k)}&chat=${encodeURIComponent(T)}&limit=${encodeURIComponent(f.get("limit")||"120")}`}else if(r==="/api/mesh/job"){let[b,k]=[f.get("kind"),f.get("key")];if(!b||!k){y(e,400,{error:"kind and key required"});return}x=`/analytics/job?kind=${encodeURIComponent(b)}&key=${encodeURIComponent(k)}&limit=${encodeURIComponent(f.get("limit")||"120")}`}else if(r==="/api/mesh/conversation"){let[b,k,T]=[f.get("agent"),f.get("channel"),f.get("chat")];if(!b||!k||!T){y(e,400,{error:"agent, channel, chat required"});return}x=`/analytics/conversation?agent=${encodeURIComponent(b)}&channel=${encodeURIComponent(k)}&chat=${encodeURIComponent(T)}&tzOffset=${encodeURIComponent(f.get("tzOffset")||"0")}`}else{let b=f.get("task");if(!b){y(e,400,{error:"task required"});return}x=`/analytics/run/${encodeURIComponent(b)}`}try{await ui(e,await ke(a.config),d,x)}catch(b){y(e,502,{error:b.message})}return}if(o==="GET"&&r==="/api/live/stream"){If(t,e,a.config);return}if(o==="GET"&&r==="/api/task/stream"){let d=new URL(t.url||"/","http://localhost"),f=d.searchParams.get("node"),x=d.searchParams.get("agent"),b=d.searchParams.get("task");if(!f||!x||!b){y(e,400,{error:"node, agent, task query params required"});return}await Mf(t,e,a,f,x,b);return}if(o==="GET"&&r==="/api/task/history"){let d=new URL(t.url||"/","http://localhost"),f=d.searchParams.get("node"),x=d.searchParams.get("agent"),b=d.searchParams.get("task"),k=d.searchParams.get("limit")||"50";if(!f||!x){y(e,400,{error:"node and agent query params required"});return}await $f(e,a,f,x,b,k);return}if(o==="POST"&&r==="/api/task/action"){let d=new URL(t.url||"/","http://localhost"),f=d.searchParams.get("node"),x=d.searchParams.get("task"),b=d.searchParams.get("kind");if(!f||!x||b!=="cancel"&&b!=="followup"){y(e,400,{error:"node, task, kind=cancel|followup query params required"});return}await Pf(t,e,a,f,x,b);return}if(o==="POST"&&r==="/api/voice/stop"){let d=new URL(t.url||"/","http://localhost").searchParams.get("node");if(!d){y(e,400,{error:"node query param required"});return}await hn(t,e,a,d,"/voice/stop");return}if(o==="GET"&&r==="/api/agents"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let f=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:d});if(!f.ok)throw new Error(`HTTP ${f.status}`);let x=await f.json();y(e,200,x)}catch(d){y(e,502,{error:d.message||"agents fetch failed"})}return}if(o==="GET"&&r==="/api/business/status"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let f=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/business/status",{headers:d});if(!f.ok){y(e,f.status,{error:`HTTP ${f.status}`});return}y(e,200,await f.json())}catch(d){y(e,502,{error:d.message||"business status fetch failed"})}return}if(o==="POST"&&r==="/api/draft"){let d=await pe(t);try{let f=await Bf(a.config,d);y(e,200,f)}catch(f){y(e,502,{error:f.message||"draft failed"})}return}let p=r.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(p&&o==="POST"){let d=p[1];if(!Lf(t,e,[`agent:${d}`]))return;await Rf(t,e,a.config,d);return}if(o==="GET"&&r==="/api/node/build"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let f=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/health",{headers:d,signal:AbortSignal.timeout(3e3)});if(!f.ok)throw new Error(`HTTP ${f.status}`);y(e,200,or(await f.json()))}catch(d){y(e,502,{error:d.message||"daemon not reachable"})}return}if(r.startsWith("/api/")&&a.token){let d=t.headers.authorization||"",f=d.startsWith("Bearer ")?d.slice(7):"";if(f!==a.token){let x=new F,b=f?x.verify(f):null;if(!b||!_e(b,"dashboard:write")){y(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/mesh/feed"){await _f(e,a.config,n.searchParams);return}if((o==="POST"||o==="PATCH"||o==="DELETE"||o==="PUT")&&r.startsWith("/api/")&&t.headers["x-requested-with"]!=="agentx-board"){y(e,400,{error:"missing X-Requested-With: agentx-board"});return}if(o==="POST"&&(r==="/api/node/restart"||r==="/api/node/restart/cancel")){let d=n.searchParams.get("node");if(!d){y(e,400,{error:"node query param required"});return}await hn(t,e,a,d,r==="/api/node/restart"?"/daemon/restart":"/daemon/restart/cancel");return}if(o==="GET"&&r==="/events"){let f=new URL(t.url||"/","http://localhost").searchParams.toString();e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});let x=[{name:a.config.node.name||"local",url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(w=>({name:w.name,url:w.url,token:w.token}))],b={flag:!1},k=[];t.on("close",()=>{b.flag=!0;for(let w of k)try{w.abort()}catch{}});let T=setInterval(()=>{if(!b.flag)try{e.write(`: ping
20313
+ Kanban dashboard: http://${f}:${n}
20314
+ `),console.log(` Boards: ${a.map(S=>S.id).join(", ")}`)),r==="127.0.0.1"&&!o?console.log(" (bound to localhost; no auth token \u2014 safe default)"):r!=="127.0.0.1"&&!o&&console.log(" \u26A0 bound to a non-loopback address without a token \u2014 writes are UNAUTHENTICATED")})}var vh=new Set(["/","/live","/mesh","/monitor","/activity","/boards","/glossary","/workflows","/workflows/editor","/procedures","/processes","/graph","/setup","/admin","/admin/graph","/approvals","/people","/places","/admin/health","/admin/observability","/admin/ledger","/admin/cost","/admin/projects","/admin/wiki"]);async function yh(t,e,a){let n=new URL(t.url||"/","http://localhost"),r=n.pathname,o=(t.method||"GET").toUpperCase();if((t.url||"/").split(/[?#]/)[0]!==r){k(e,404,{error:"not found"});return}if(ur(t.headers)==="foreign"&&mr(o)){k(e,403,{error:"Forbidden: request from a page on another origin"});return}if(o==="OPTIONS"){e.writeHead(204),e.end();return}if(await Jo(t,e,r,o,{nodeName:a.config.node?.name,root:process.cwd(),people:()=>at(a.config.people),members:Lc(a.config.members.logRetentionDays),db:()=>Ye(),linkFor:(u,h)=>xo(u,h,{gitlab:a.config.channels.gitlab?.host})})||await Ec(t,e,r,o,{nodeName:a.config.node?.name,fleet:Oc(a.config),push:En(a.config),announce:Xi(a.config),chat:Nc(a.config),voice:qh(a.config),camera:Fh(a.config),places:Mc(a.config),assetLinks:()=>Il(a.config)}))return;let s=o==="GET"?fo(r):null;if(s){e.writeHead(200,{"Content-Type":s.type,"Cache-Control":"public, max-age=86400"}),e.end(s.body);return}if(o==="GET"&&vh.has(r)&&Kr("page",r),o==="GET"&&r==="/"){let u=$r();if(!u.configExists||u.agentCount===0){e.writeHead(302,{Location:"/setup"}),e.end();return}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(an({peers:D(a.config)}));return}if(o==="GET"&&r==="/boards"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end($i({peers:D(a.config)}));return}if(o==="GET"&&r==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(an({peers:D(a.config)}));return}if(o==="POST"&&r.match(/^\/webhook\/n8n\/[A-Za-z0-9._:-]{1,64}$/)){try{let[u]=await Te(a.config);if(!u){k(e,503,{error:"no node available"});return}let h=await new Promise(y=>{let T="";t.on("data",v=>T+=v),t.on("end",()=>y(T)),t.on("error",()=>y(""))}),w=await fetch(u.url+r,{method:"POST",headers:{"Content-Type":"application/json",...u.token?{Authorization:`Bearer ${u.token}`}:{}},body:h||"{}"});e.writeHead(w.status,{"Content-Type":"application/json"}),e.end(await w.text())}catch(u){k(e,502,{error:"could not reach the node",message:String(u?.message||u)})}return}if(r==="/api/assistant"||r.startsWith("/api/assistant/")){try{let u=await Te(a.config),h=o==="POST"?void 0:n.searchParams.get("node"),w=o==="POST"?await he(t):void 0,y=w?.node??h,T=y?u.find(R=>R.url===y):u[0];if(!T){k(e,400,{error:"unknown node"});return}let v=n.search?n.search.replace(/([?&])node=[^&]*/,"$1").replace(/[?&]$/,""):"",A=await fetch(T.url+r+v,{method:o,headers:{"Content-Type":"application/json",...T.token?{Authorization:`Bearer ${T.token}`}:{}},...o==="POST"?{body:JSON.stringify({...w,node:void 0})}:{}});k(e,A.status,await A.json().catch(()=>({error:`HTTP ${A.status}`})))}catch(u){k(e,502,{error:"could not reach the node",message:u?.message||String(u)})}return}if(o==="POST"&&r==="/api/workflows/editor/chat"){try{let u=await he(t),h={"Content-Type":"application/json"};a.config.dashboard.token&&(h.Authorization=`Bearer ${a.config.dashboard.token}`);let w=a.config.dashboard.daemonUrl.replace(/\/+$/,""),y=await fetch(`${w}/api/workflows/editor/chat`,{method:"POST",headers:h,body:JSON.stringify(u??{})}),T=await y.json().catch(()=>({error:`HTTP ${y.status}`}));k(e,y.status,T)}catch(u){k(e,502,{error:"daemon unreachable",message:u.message||String(u)})}return}if(o==="GET"&&r==="/api/n8n/workflows"){try{let[u]=await Te(a.config);if(!u){k(e,200,{configured:!1,workflows:[]});return}let h=await fetch(u.url+"/api/n8n/workflows",{headers:u.token?{Authorization:`Bearer ${u.token}`}:{}});k(e,h.status,await h.json().catch(()=>({configured:!1,workflows:[]})))}catch{k(e,200,{configured:!1,workflows:[]})}return}if(o==="GET"&&r==="/workflows/editor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ro({peers:D(a.config)}));return}if(o==="GET"&&r==="/activity"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(no({peers:D(a.config),view:n.searchParams.get("view")}));return}if(o==="GET"&&r==="/monitor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Zr({peers:D(a.config)}));return}if(r==="/api/monitor"||r.startsWith("/api/monitor/")){let u=new AbortController,h=setTimeout(()=>u.abort(),8e3);try{let w=Jn(await Te(a.config,u.signal),a.config.mesh.peers);if(o==="GET"&&r==="/api/monitor"){let R=await Promise.all(w.map(async _=>{try{let L=await fetch(_.url+"/monitor",{headers:_.token?{Authorization:`Bearer ${_.token}`}:{},signal:u.signal});if(!L.ok)throw new Error(`HTTP ${L.status}`);return{name:_.name,url:_.url,ok:!0,data:await L.json()}}catch(L){return{name:_.name,url:_.url,ok:!1,error:L.message}}}));k(e,200,{nodes:R});return}let y=w.find(R=>R.url===n.searchParams.get("node"));if(!y){k(e,400,{error:"Select a known node"});return}let T=r.slice(13);if(!(o==="GET"&&["discover","actions","activity"].includes(T)||o==="POST"&&["register","ended","action","retry","clear"].includes(T))){k(e,405,{error:"Unknown monitor operation"});return}let v=o==="POST"?JSON.stringify(await Kn(t)):void 0,A=await fetch(y.url+"/monitor/"+T+(T==="actions"?"?offset="+encodeURIComponent(n.searchParams.get("offset")||"0"):T==="activity"?"?hours="+encodeURIComponent(n.searchParams.get("hours")||"24"):""),{method:o,body:v,signal:u.signal,headers:{"Content-Type":"application/json",...y.token?{Authorization:`Bearer ${y.token}`}:{}}});k(e,A.status,await A.json())}catch(w){k(e,502,{error:w.message})}finally{clearTimeout(h)}return}if(o==="GET"&&r==="/mesh"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ii({peers:D(a.config)}));return}if(o==="GET"&&r==="/places"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Tc({peers:D(a.config)}));return}if(o==="GET"&&r==="/guests"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Mi({peers:D(a.config)}));return}if(o==="GET"&&r==="/api/guests"||o==="POST"&&/^\/api\/guests\/[^/]+\/(pause|resume|end|update)$/.test(r)){try{let u={"Content-Type":"application/json"};a.config.dashboard.token&&(u.Authorization=`Bearer ${a.config.dashboard.token}`);let h=a.config.dashboard.daemonUrl.replace(/\/+$/,""),w=o==="POST"?await he(t).catch(()=>({})):void 0,y=await fetch(`${h}${r.replace(/^\/api\/guests/,"/mesh/guests")}`,{method:o,headers:u,...w!==void 0?{body:JSON.stringify(w??{})}:{}});k(e,y.status,await y.json().catch(()=>({error:`HTTP ${y.status}`})))}catch(u){k(e,502,{error:"daemon unreachable",message:u.message||String(u)})}return}if(o==="GET"&&r==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ji({peers:D(a.config)}));return}if(o==="GET"&&r==="/workflows"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Oi({peers:D(a.config)}));return}if(o==="GET"&&r==="/procedures"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ni({peers:D(a.config)}));return}if(o==="GET"&&r==="/processes"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pr({}));return}let l=o==="GET"&&r.match(/^\/tasks\/([^/]+)$/);if(l){let u=n.searchParams.get("agent")||"",h=n.searchParams.get("node")||a.config.dashboard.daemonUrl;if(!u){e.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),e.end("<p>Missing <code>?agent=</code>. Open this task from the Live page.</p>");return}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Di({taskId:decodeURIComponent(l[1]),agentId:u,agentName:n.searchParams.get("name")||void 0,channel:n.searchParams.get("channel")||void 0,archived:n.searchParams.get("archived")==="1",ask:n.searchParams.get("ask")||void 0,askAt:n.searchParams.get("at")||void 0,nodeUrl:h,peers:D(a.config)}));return}let c=o==="GET"&&r.match(/^\/agents\/([^/]+)\/history$/);if(c){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Hi({agentId:decodeURIComponent(c[1]),agentName:n.searchParams.get("name")||void 0,nodeUrl:n.searchParams.get("node")||a.config.dashboard.daemonUrl,peers:D(a.config)}));return}if(o==="GET"&&r==="/graph"){e.writeHead(302,{Location:"/admin/graph"}),e.end();return}if(o==="GET"&&r==="/setup"){jr(t,e);return}if(o==="POST"&&r==="/api/setup"){await Or(t,e);return}if(o==="POST"&&r==="/api/setup/start-daemon"){await Nr(t,e);return}if(o==="GET"&&r==="/admin"){ss(t,e,D(a.config),a.token);return}if(o==="GET"&&r==="/approvals"){_s(e,D(a.config),a.token);return}if(o==="GET"&&r==="/admin/graph"){ms(t,e,D(a.config),a.token);return}if(o==="GET"&&(r==="/admin/health"||r==="/admin/observability")){if(r==="/admin/observability"){e.writeHead(302,{Location:"/admin/health"}),e.end();return}Ps(t,e,D(a.config));return}if(r.startsWith("/api/admin/")||r.startsWith("/api/workflows")||r.startsWith("/api/agents")){let u=n.searchParams.get("peer")==="fleet"?"fleet":String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(u==="fleet"){if(r==="/api/admin/activity-graph"){await Jh(t,e,a);return}if(r==="/api/admin/activity-graph/stream"){await en(t,e,r,w=>Hc(w,a.config));return}let h=r.match(/^\/api\/admin\/activity-graph\/dispatch\/(.+)$/);if(h){let w=decodeURIComponent(h[1]),y=w.indexOf("::");if(y>0){let T=w.slice(0,y),v=w.slice(y+2),A=a.config.node?.id||a.config.node?.name||"local";if(T===A)t.url=`/api/admin/activity-graph/dispatch/${encodeURIComponent(v)}`;else{let R=(a.config.dashboard?.daemons||[]).find(_=>(_.name||_.url)===T);if(R){let _=dt(R.url.replace(/\/+$/,""),a.config);if(_){await Pc(t,e,_,`/api/admin/activity-graph/dispatch/${encodeURIComponent(v)}`);return}}k(e,404,{error:`unknown node "${T}" in fleet dispatch id`});return}}}}else if(u&&u!=="primary"){let h=dt(u,a.config);if(!h){k(e,404,{error:`unknown peer: ${u}`});return}let w=(n.search||"").replace(/[?&]peer=[^&]*/g,T=>T.startsWith("?")?"?":"");await Pc(t,e,h,r+(w==="?"?"":w));return}}if(o==="GET"&&r.startsWith("/api/admin/observability/")&&await $s(t,e,r))return;if(o==="GET"&&r==="/api/admin/logs/stream"){await Vh(t,e);return}if(o==="GET"&&r==="/api/admin/doctor"){try{let{runDoctorChecks:u}=await import("./doctor-DO262COW.js"),w=new URL(t.url||"/","http://_").searchParams.get("running")!=="false",y=await u({running:w});k(e,200,y)}catch(u){k(e,500,{error:u?.message||String(u)})}return}if(o==="GET"&&r==="/admin/ledger"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ds({peers:D(a.config)}));return}if(o==="GET"&&r.startsWith("/api/admin/ledger/")&&await Ns(t,e,r))return;if(o==="GET"&&r==="/admin/cost"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Hs({peers:D(a.config)}));return}if(o==="GET"&&r==="/admin/projects"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Bs({peers:D(a.config)}));return}if(o==="GET"&&(r==="/admin/wiki"||r.startsWith("/admin/wiki/"))){if(r==="/admin/wiki"){e.writeHead(302,{Location:"/admin/wiki/"}),e.end();return}await Ah(a)(t,e);return}if(o==="GET"&&r==="/admin/activity-graph"){e.writeHead(302,{Location:"/activity?view=map"}),e.end();return}if(o==="GET"&&r==="/api/admin/activity-graph"&&await ci(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/stream")&&await en(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/dispatch/")&&await pi(t,e,r))return;let d=o==="GET"&&r.match(/^\/admin\/agents\/([a-z0-9][a-z0-9_-]*)$/);if(d){fi(t,e,d[1],D(a.config),a.token);return}if(r.startsWith("/api/admin/")&&a.token){let u=t.headers.authorization||"",h=u.startsWith("Bearer ")?u.slice(7):"";if(h!==a.token){let w=new G,y=h?w.verify(h):null;if(!y||!Ae(y,"dashboard:write")){k(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/admin/config"){await is(t,e);return}if(o==="GET"&&r==="/api/admin/voice-health"){k(e,200,xr()??{checkedAt:null,missing:[]});return}if(r.startsWith("/api/admin/approvals")){await Ss(t,e,r,n);return}if(await Ts(t,e,r,{people:()=>at(a.config.people),members:Lc(a.config.members.logRetentionDays),root:process.cwd(),db:()=>Ye(),peers:D(a.config),localToken:a.token}))return;if(r.startsWith("/api/admin/graph/")){await fs(t,e,r);return}if(r.startsWith("/api/admin/agent/")){await hi(t,e,r);return}if(r.startsWith("/api/admin/")){await ls(t,e,r);return}if(o==="GET"&&r==="/sortable.min.js"){e.writeHead(200,{"Content-Type":"application/javascript; charset=utf-8","Cache-Control":"public, max-age=86400"}),e.end(Vo);return}if(o==="GET"&&r.startsWith("/assets/")){let u=r.slice(8);if(!/^[a-zA-Z0-9._-]+\.(js|map|css)$/.test(u)){k(e,400,{error:"invalid asset name"});return}let h=Xh("web/"+u);try{let w=await Kh(h),y=u.endsWith(".map")?"application/json; charset=utf-8":u.endsWith(".css")?"text/css; charset=utf-8":"application/javascript; charset=utf-8",T=n.searchParams.has("v");e.writeHead(200,{"Content-Type":y,"Cache-Control":T?"public, max-age=31536000, immutable":"public, max-age=60"}),e.end(w)}catch{k(e,404,{error:"asset not found",hint:"run: npm run build:web"})}return}if(o==="GET"&&r==="/api/live"){try{let u=await Qe(a.config);k(e,200,u)}catch(u){k(e,502,{error:u.message})}return}if(o==="GET"&&r==="/api/mesh"){try{let u=n.searchParams.get("date")||new Date().toISOString().slice(0,10),h=n.searchParams.get("timezone")||"UTC",w=await Qe(a.config,{date:u,timezone:h});k(e,200,w)}catch(u){k(e,502,{error:u.message})}return}if(o==="GET"&&r==="/api/mesh/analytics"){let u=(h,w,y,T)=>{let v=parseInt(n.searchParams.get(h)||"",10);return Number.isFinite(v)?Math.max(y,Math.min(T,v)):w};try{let h=await Te(a.config);k(e,200,await Li(h,{days:u("days",30,0,180),tzOffsetMinutes:u("tzOffset",0,-840,840),limit:u("limit",60,1,200)}))}catch(h){k(e,502,{error:h.message})}return}if(o==="GET"&&r==="/api/mesh/day"){let u=n.searchParams.get("day")||"";if(!/^\d{4}-\d{2}-\d{2}$/.test(u)){k(e,400,{error:"day=YYYY-MM-DD query param required"});return}let h=(w,y,T,v)=>{let A=parseInt(n.searchParams.get(w)||"",10);return Number.isFinite(A)?Math.max(T,Math.min(v,A)):y};try{let w=await Te(a.config);k(e,200,await Pi(w,{day:u,tzOffsetMinutes:h("tzOffset",0,-840,840),limit:h("limit",40,1,200)}))}catch(w){k(e,502,{error:w.message})}return}if(o==="GET"&&(r==="/api/mesh/thread"||r==="/api/mesh/job"||r==="/api/mesh/run"||r==="/api/mesh/conversation")){let u=n.searchParams.get("node");if(!u){k(e,400,{error:"node query param required"});return}let h=n.searchParams,w;if(r==="/api/mesh/thread"){let[y,T,v]=[h.get("agent"),h.get("channel"),h.get("chat")];if(!y||!T||!v){k(e,400,{error:"agent, channel, chat required"});return}w=`/analytics/thread?agent=${encodeURIComponent(y)}&channel=${encodeURIComponent(T)}&chat=${encodeURIComponent(v)}&limit=${encodeURIComponent(h.get("limit")||"120")}`}else if(r==="/api/mesh/job"){let[y,T]=[h.get("kind"),h.get("key")];if(!y||!T){k(e,400,{error:"kind and key required"});return}w=`/analytics/job?kind=${encodeURIComponent(y)}&key=${encodeURIComponent(T)}&limit=${encodeURIComponent(h.get("limit")||"120")}`}else if(r==="/api/mesh/conversation"){let[y,T,v]=[h.get("agent"),h.get("channel"),h.get("chat")];if(!y||!T||!v){k(e,400,{error:"agent, channel, chat required"});return}w=`/analytics/conversation?agent=${encodeURIComponent(y)}&channel=${encodeURIComponent(T)}&chat=${encodeURIComponent(v)}&tzOffset=${encodeURIComponent(h.get("tzOffset")||"0")}`}else{let y=h.get("task");if(!y){k(e,400,{error:"task required"});return}w=`/analytics/run/${encodeURIComponent(y)}`}try{await Ri(e,await Te(a.config),u,w)}catch(y){k(e,502,{error:y.message})}return}if(o==="GET"&&r==="/api/live/stream"){$h(t,e,a.config);return}if(o==="GET"&&r==="/api/task/stream"){let u=new URL(t.url||"/","http://localhost"),h=u.searchParams.get("node"),w=u.searchParams.get("agent"),y=u.searchParams.get("task");if(!h||!w||!y){k(e,400,{error:"node, agent, task query params required"});return}await jh(t,e,a,h,w,y);return}if(o==="GET"&&r==="/api/task/history"){let u=new URL(t.url||"/","http://localhost"),h=u.searchParams.get("node"),w=u.searchParams.get("agent"),y=u.searchParams.get("task"),T=u.searchParams.get("limit")||"50";if(!h||!w){k(e,400,{error:"node and agent query params required"});return}await Dh(e,a,h,w,y,T);return}if(o==="POST"&&r==="/api/task/action"){let u=new URL(t.url||"/","http://localhost"),h=u.searchParams.get("node"),w=u.searchParams.get("task"),y=u.searchParams.get("kind");if(!h||!w||y!=="cancel"&&y!=="followup"){k(e,400,{error:"node, task, kind=cancel|followup query params required"});return}await Hh(t,e,a,h,w,y);return}if(o==="POST"&&r==="/api/voice/stop"){let u=new URL(t.url||"/","http://localhost").searchParams.get("node");if(!u){k(e,400,{error:"node query param required"});return}await Sn(t,e,a,u,"/voice/stop");return}if(o==="GET"&&r==="/api/agents"){try{let u={};a.config.dashboard.token&&(u.Authorization=`Bearer ${a.config.dashboard.token}`);let h=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:u});if(!h.ok)throw new Error(`HTTP ${h.status}`);let w=await h.json();k(e,200,w)}catch(u){k(e,502,{error:u.message||"agents fetch failed"})}return}if(o==="GET"&&r==="/api/business/status"){try{let u={};a.config.dashboard.token&&(u.Authorization=`Bearer ${a.config.dashboard.token}`);let h=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/business/status",{headers:u});if(!h.ok){k(e,h.status,{error:`HTTP ${h.status}`});return}k(e,200,await h.json())}catch(u){k(e,502,{error:u.message||"business status fetch failed"})}return}if(o==="POST"&&r==="/api/draft"){let u=await he(t);try{let h=await Wh(a.config,u);k(e,200,h)}catch(h){k(e,502,{error:h.message||"draft failed"})}return}let p=r.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(p&&o==="POST"){let u=p[1];if(!Oh(t,e,[`agent:${u}`]))return;await Nh(t,e,a.config,u);return}if(o==="GET"&&r==="/api/node/build"){try{let u={};a.config.dashboard.token&&(u.Authorization=`Bearer ${a.config.dashboard.token}`);let h=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/health",{headers:u,signal:AbortSignal.timeout(3e3)});if(!h.ok)throw new Error(`HTTP ${h.status}`);k(e,200,gr(await h.json()))}catch(u){k(e,502,{error:u.message||"daemon not reachable"})}return}if(r.startsWith("/api/")&&a.token){let u=t.headers.authorization||"",h=u.startsWith("Bearer ")?u.slice(7):"";if(h!==a.token){let w=new G,y=h?w.verify(h):null;if(!y||!Ae(y,"dashboard:write")){k(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/mesh/feed"){await Ch(e,a.config,n.searchParams);return}if((o==="POST"||o==="PATCH"||o==="DELETE"||o==="PUT")&&r.startsWith("/api/")&&t.headers["x-requested-with"]!=="agentx-board"){k(e,400,{error:"missing X-Requested-With: agentx-board"});return}if(await Tl(t,e,r,o,Mc(a.config)))return;if(o==="POST"&&(r==="/api/node/restart"||r==="/api/node/restart/cancel")){let u=n.searchParams.get("node");if(!u){k(e,400,{error:"node query param required"});return}await Sn(t,e,a,u,r==="/api/node/restart"?"/daemon/restart":"/daemon/restart/cancel");return}if(o==="GET"&&r==="/events"){let h=new URL(t.url||"/","http://localhost").searchParams.toString();e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});let w=[{name:a.config.node.name||"local",url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(A=>({name:A.name,url:A.url,token:A.token}))],y={flag:!1},T=[];t.on("close",()=>{y.flag=!0;for(let A of T)try{A.abort()}catch{}});let v=setInterval(()=>{if(!y.flag)try{e.write(`: ping
19803
20315
 
19804
- `)}catch{}},15e3);t.on("close",()=>clearInterval(T));for(let w of x)(async()=>{let I={Accept:"text/event-stream"};w.token&&(I.Authorization=`Bearer ${w.token}`);let C=new AbortController;k.push(C);try{let E=await fetch(`${w.url.replace(/\/+$/,"")}/events${f?`?${f}`:""}`,{headers:I,signal:C.signal});if(!E.ok||!E.body)return;let $=E.body.getReader(),L=new TextDecoder,j="";for(;!b.flag;){let{done:W,value:q}=await $.read();if(W)break;j+=L.decode(q,{stream:!0});let G;for(;(G=j.indexOf(`
20316
+ `)}catch{}},15e3);t.on("close",()=>clearInterval(v));for(let A of w)(async()=>{let R={Accept:"text/event-stream"};A.token&&(R.Authorization=`Bearer ${A.token}`);let _=new AbortController;T.push(_);try{let L=await fetch(`${A.url.replace(/\/+$/,"")}/events${h?`?${h}`:""}`,{headers:R,signal:_.signal});if(!L.ok||!L.body)return;let j=L.body.getReader(),$=new TextDecoder,O="";for(;!y.flag;){let{done:U,value:ce}=await j.read();if(U)break;O+=$.decode(ce,{stream:!0});let Z;for(;(Z=O.indexOf(`
19805
20317
 
19806
- `))>=0;){let ie=j.slice(0,G);if(j=j.slice(G+2),b.flag)break;try{e.write(ie+`
20318
+ `))>=0;){let oe=O.slice(0,Z);if(O=O.slice(Z+2),y.flag)break;try{e.write(oe+`
19807
20319
 
19808
- `)}catch{b.flag=!0}}}}catch{}})();return}if(o==="GET"&&r==="/api/workflows/runs"){try{let d=new URL(t.url||"/","http://localhost"),f=Math.max(1,Math.min(500,Number(d.searchParams.get("limit")||50))),x=d.searchParams.get("workflowId")||void 0,b=d.searchParams.get("summary")==="1"||d.searchParams.get("summary")==="true",k=a.workflowRuns.list({limit:f,workflowId:x}),T=`?limit=${f}${x?`&workflowId=${encodeURIComponent(x)}`:""}${b?"&summary=1":""}`,w=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(L=>({url:L.url,token:L.token}))],I=await Promise.all(w.map(async L=>{let j={};L.token&&(j.Authorization=`Bearer ${L.token}`);try{let W=new AbortController,q=setTimeout(()=>W.abort(),5e3);try{let G=await fetch(`${L.url.replace(/\/+$/,"")}/api/workflows/runs${T}`,{headers:j,signal:W.signal});if(!G.ok)return[];let ie=await G.json();return Array.isArray(ie.runs)?ie.runs:[]}finally{clearTimeout(q)}}catch{return[]}})),C=new Map;for(let L of k)C.set(L.id,L);for(let L of I)for(let j of L)C.set(j.id,j);let E=Array.from(C.values()).sort((L,j)=>L.updatedAt<j.updatedAt?1:-1).slice(0,f),$=b?E.map(L=>vf(L)):E;y(e,200,{runs:$})}catch(d){y(e,502,{error:"runs fetch failed",message:d.message||String(d)})}return}let m=o==="GET"&&r.match(/^\/api\/workflows\/runs\/([^\/]+)$/);if(m){let d=decodeURIComponent(m[1]),f=a.workflowRuns.get(d);if(f){y(e,200,{run:f});return}let x=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(b=>({url:b.url,token:b.token}))];for(let b of x)try{let k={};b.token&&(k.Authorization=`Bearer ${b.token}`);let T=await fetch(`${b.url.replace(/\/+$/,"")}/api/workflows/runs/${encodeURIComponent(d)}`,{headers:k});if(T.ok){y(e,200,await T.json());return}}catch{}y(e,404,{error:"run not found on any configured peer"});return}if(o==="GET"&&r==="/api/actions/builtin"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let f=a.config.dashboard.daemonUrl.replace(/\/+$/,""),x=await fetch(`${f}/api/actions/builtin`,{headers:d}),b=await x.json().catch(()=>({error:`HTTP ${x.status}`}));y(e,x.status,b)}catch(d){y(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}let h=o==="POST"&&r.match(/^\/workflows\/([^/]+)\/run$/);if(h){try{let d=await pe(t).catch(()=>({})),f={"Content-Type":"application/json"};a.config.dashboard.token&&(f.Authorization=`Bearer ${a.config.dashboard.token}`);let x=a.config.dashboard.daemonUrl.replace(/\/+$/,""),b=await fetch(`${x}/workflows/${encodeURIComponent(h[1])}/run`,{method:"POST",headers:f,body:JSON.stringify(d??{})}),k=await b.json().catch(()=>({error:`HTTP ${b.status}`}));y(e,b.status,k)}catch(d){y(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(r.startsWith("/api/workflows")&&wi(t,e,{store:a.workflowStore,runs:a.workflowRuns,layouts:a.workflowLayouts,requireScope:(f,x,b)=>{if(a.token)return!0;let k=ga(f);if(!k)return!0;let T=new F().verify(k);if(!T)return y(x,401,{error:"invalid or revoked token"}),!1;for(let w of b)if(!_e(T,w))return y(x,403,{error:`token missing scope: ${w}`,scopes:T.scopes}),!1;return!0}}))return;if(o==="GET"&&r==="/api/boards"){y(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 _=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/members$/);if(_&&o==="GET"){let d=a.sources.get(_[1]);if(!d){y(e,404,{error:"unknown board"});return}try{let f=typeof d.listMembers=="function"?await d.listMembers():[];y(e,200,f)}catch(f){y(e,502,{error:f.message})}return}let v=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(v&&o==="GET"){let d=a.sources.get(v[1]);if(!d){y(e,404,{error:"unknown board"});return}try{let f=typeof d.listMilestones=="function"?await d.listMilestones():[];y(e,200,f)}catch(f){y(e,502,{error:f.message})}return}let S=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),g=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(S&&o==="PATCH"){let[,d,f]=S,x=decodeURIComponent(f),b=a.boards.find(C=>C.id===d);if(!b){y(e,404,{error:`unknown board: ${d}`});return}let k=a.sources.get(d);if(!k){y(e,503,{error:`board "${d}" source unavailable`});return}let T=await pe(t),w=b.columns.find(C=>C.id===T.to),I=b.columns.find(C=>C.id===T.from);if(!w){y(e,400,{error:`unknown 'to' column: ${T.to}`});return}try{await xf(k,x,I,w),pn({actor:un(t),action:"move",boardId:d,itemId:x,payload:{from:T.from,to:T.to}}),y(e,200,{ok:!0})}catch(C){y(e,502,{error:C.message||"transition failed"})}return}if(g){let[,d,f]=g,x=f?decodeURIComponent(f):void 0,b=a.boards.find(T=>T.id===d);if(!b){y(e,404,{error:`unknown board: ${d}`});return}let k=a.sources.get(d);if(!k){y(e,503,{error:`board "${d}" source unavailable`});return}if(o==="GET"&&!x){let{columns:T,totals:w}=await gf(b,k,n.searchParams);y(e,200,{columns:T,totals:w});return}if(o==="GET"&&x){try{let T=typeof k.getItem=="function"?await k.getItem(x):null;if(!T){y(e,404,{error:"not found"});return}y(e,200,T)}catch(T){y(e,502,{error:T.message})}return}if(o==="PATCH"&&x){let T=await pe(t);try{let w=typeof k.updateItem=="function"?await k.updateItem(x,T):null;if(!w){y(e,501,{error:"update unsupported"});return}pn({actor:un(t),action:"update",boardId:d,itemId:x,payload:T}),y(e,200,w)}catch(w){y(e,502,{error:w.message})}return}if(o==="POST"&&!x){let T=await pe(t);if(!T.title){y(e,400,{error:"title required"});return}if(!k.capabilities.create||!k.create){y(e,400,{error:`source ${k.type} does not support create`});return}try{let w=await k.create({title:T.title,description:T.description,labels:T.labels,assigneeUsernames:T.assigneeUsernames,milestoneTitle:T.milestoneTitle,projectHint:T.projectHint});pn({actor:un(t),action:"create",boardId:d,itemId:w.id,payload:{title:T.title}}),y(e,201,w)}catch(w){y(e,502,{error:w.message})}return}}if(o==="GET"&&/^\/[a-z][a-z-]*\/?$/.test(r)){let d=r.replace(/^\/+|\/+$/g,""),x={health:"/admin/health",ledger:"/admin/ledger",cost:"/admin/cost",projects:"/admin/projects",graph:"/admin/graph",wiki:"/admin/wiki/",observability:"/admin/health"}[d];if(x){e.writeHead(302,{Location:x}),e.end();return}}y(e,404,{error:"not found",path:r})}async function gf(t,e,a){if(!e.capabilities.listAll||!e.listAll){let d={};for(let f of t.columns)d[f.id]=[];return{columns:d,totals:Object.fromEntries(t.columns.map(f=>[f.id,0]))}}let n=[];t.primaryToolLabel&&n.push(t.primaryToolLabel);let r=a.get("label")||void 0;r&&n.push(r);let o=a.get("q")||void 0,s=a.get("milestone")||void 0,i=a.get("assignee")||void 0,l=parseInt(a.get("days")||String(t.timeRangeDays),10),c=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),p=t.columns.some(d=>d.kind!=="closed"),u=t.columns.some(d=>d.kind==="closed"),m=p?await e.listAll({sinceDays:l,labels:n.length?n:void 0,search:o,milestone:s,state:"opened"}):[],h=u?await e.listAll({sinceDays:c,labels:n.length?n:void 0,search:o,milestone:s,state:"closed"}):[],_={};for(let d of t.columns)_[d.id]=[];let v=t.columns.find(d=>d.kind==="closed");for(let d of h)v&&_[v.id].push({...d,stage:v.id});let S=t.columns.filter(d=>d.kind!=="closed");for(let d of m){let f=vn(d,S);if(!f)continue;let x=_[f];x&&x.push({...d,stage:f})}if(i)for(let d of Object.keys(_))_[d]=_[d].filter(f=>f.assignee===i);for(let d of Object.keys(_))_[d].sort((f,x)=>{let b=(f.priority??99)-(x.priority??99);return b!==0?b:(x.updatedAt||"").localeCompare(f.updatedAt||"")});let g=Object.fromEntries(Object.entries(_).map(([d,f])=>[d,f.length]));return{columns:_,totals:g}}async function xf(t,e,a,n){let r=bn(a,n),o=t;r.closeIssue&&typeof o.setState=="function"?await o.setState(e,"close"):r.reopen&&typeof o.setState=="function"&&await o.setState(e,"reopen"),(r.addLabels?.length||r.removeLabels?.length)&&typeof o.transitionMany=="function"?await o.transitionMany(e,r.addLabels||[],r.removeLabels||[]):r.addLabels?.length&&t.transition&&await t.transition(e,r.addLabels[0],r.removeLabels?.[0])}function vf(t){return{id:t.id,workflowId:t.workflowId,workflowVersion:t.workflowVersion,homeNode:t.homeNode,status:t.status,pending:t.pending,entityRef:t.entityRef,history:(t.history||[]).slice(-5),parentRunId:t.parentRunId,parentNodeId:t.parentNodeId,rootRunId:t.rootRunId,depth:t.depth,createdAt:t.createdAt,updatedAt:t.updatedAt}}function bf(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 r of a.agentMappings)r.gitlabUsernames.length&&(n[r.agentId]=r.gitlabUsernames);return new pr(a.host,a.token,t.source.projects,n,(...r)=>console.log("[board]",...r))}throw new Error(`unsupported board source: ${t.source.type}`)}function pn(t){try{let e=ot(process.cwd(),".agentx");Wl(e)||df(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
19809
- `;cf(ot(e,"board-audit.jsonl"),a)}catch{}}function un(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}var yf=2e3;async function wf(t,e,a,n){let r={};e&&(r.Authorization=`Bearer ${e}`);let o={id:t,name:t,url:t,reachable:!1,agents:[]};try{let s=n?`?date=${encodeURIComponent(n.date)}&timezone=${encodeURIComponent(n.timezone)}`:"",i=g=>{let d=new AbortController,f=setTimeout(()=>d.abort(),yf),x=()=>d.abort();return a?.addEventListener("abort",x,{once:!0}),fetch(t+g,{headers:r,signal:d.signal}).then(async b=>{let k=b.ok?await b.json().catch(()=>{}):void 0;return{ok:k!==void 0,json:async()=>k}}).catch(()=>null).finally(()=>{clearTimeout(f),a?.removeEventListener("abort",x)})},[l,c,p,u,m,h,_,v]=await Promise.all([i("/health"),fetch(t+"/agents",{headers:r,signal:a}).catch(()=>null),i("/mesh"),i("/crons"),i("/crons/runs"+s),i("/talk"),i("/routines"),i("/attach/sessions")]);if(!c||!c.ok)return o.error=c?`HTTP ${c.status}`:"unreachable",o;let S=await c.json();if(o.agents=S.map(g=>({id:g.id,name:g.name,tier:g.tier,model:g.model,...typeof g.color=="string"&&/^#[0-9a-fA-F]{6}$/.test(g.color)?{color:g.color}:{},skillCount:Number.isFinite(g.skillCount)?g.skillCount:void 0,active:g.active||0,total:g.total||0,errors:g.errors||0,lastActive:g.lastActive,lastSummary:g.lastSummary,hourlyTasks:Array.isArray(g.hourlyTasks)?g.hourlyTasks:void 0,runningTasks:Array.isArray(g.runningTasks)?g.runningTasks:[]})),l&&l.ok){let g=await l.json().catch(()=>({}));o.uptimeSec=g.uptime,typeof g.inflight?.total=="number"&&(o.inflight=g.inflight.total),g.restart&&typeof g.restart.state=="string"&&(o.restart=g.restart),o.name=g.node?.name||g.node?.id||t,o.id=g.node?.id||t,g.usage&&(o.usage=g.usage)}if(u&&u.ok){let g=await u.json().then(d=>Array.isArray(d)?d:[],()=>[]);o.crons=g.map(d=>({id:d.id,enabled:d.enabled===!0,schedule:String(d.schedule||""),timezone:d.timezone,agent:String(d.agent||""),kind:typeof d.command=="string"&&d.command.trim()?"command":"agent",model:d.model,nextRun:d.nextRun,retryPending:d.retryPending===!0,consecutiveErrors:Number(d.consecutiveErrors)||0}))}if(m&&m.ok){let g=await m.json().catch(()=>({}));o.cronRuns=Array.isArray(g.runs)?g.runs:[]}if(_&&_.ok){let g=await _.json().catch(()=>null);g&&Array.isArray(g.routines)&&(o.routines=g.routines.slice(0,zn.routines))}if(h&&h.ok){let g=await h.json().catch(()=>null);g?.active&&g.kind==="lesson"&&(o.lesson={agentId:g.agentId??null,mode:String(g.mode||"teach"),goal:String(g.goal||""),step:Number(g.step)||0,saying:String(g.saying||""),startedAt:String(g.startedAt||"")})}if(v&&v.ok){let g=await v.json().catch(()=>null);g&&Array.isArray(g.sessions)&&Cf(o,g.sessions,g.saved??{})}o.reachable=!0,o._peers=Array.isArray(p?.ok?await p.json():null)?o._peers:void 0}catch(s){o.error=s.message||String(s)}return o}var ra=null;function kf(t){if(ra)return ra;let e=ot(process.cwd(),".agentx/wiki");return ra=Br({wikiDir:e,pathPrefix:"/admin/wiki",mode:"graph"}),ra}async function sa(t,e,a){try{let n={};e&&(n.Authorization=`Bearer ${e}`);let r=await fetch(t+"/mesh",{headers:n,signal:a});return r.ok?(await r.json()).filter(s=>s&&s.peerUrl).map(s=>({url:String(s.peerUrl).replace(/\/+$/,""),name:s.peer||s.peerUrl})):[]}catch{return[]}}async function _f(t,e,a){let n=Math.max(1,Math.min(200,Number(a.get("limit"))||50)),r=e.dashboard.daemonUrl.replace(/\/+$/,""),o=process.env.MESH_TOKEN||U(e.dashboard,r);try{let s=await fetch(`${r}/events/recent?skip=task:step&limit=${n}`,{headers:o?{Authorization:`Bearer ${o}`}:{},signal:AbortSignal.timeout(5e3)});if(!s.ok){y(t,502,{error:`daemon answered ${s.status}`});return}let i=await s.json();y(t,200,{node:e.node.name||e.node.id,events:i.events??[]})}catch(s){y(t,502,{error:s.message||"daemon unreachable"})}}async function ke(t,e){let a=t.dashboard,n=a.daemonUrl.replace(/\/+$/,""),r=U(a,n),o=new Map;o.set(n,{name:"primary",url:n,token:r});for(let i of a.daemons){let l=i.url.replace(/\/+$/,"");o.has(l)||o.set(l,{name:i.name,url:l,token:U(a,l)})}let s=await sa(n,r,e);for(let i of s)o.has(i.url)||o.set(i.url,{...i,token:U(a,i.url)});return[...o.values()]}var Sf=3e3,Ef=6e3,Tf=5*6e4,fn=new Map,oa=new Map;function Xe(t,e){let a=e?`${e.date}|${e.timezone}`:"live",n=oa.get(a);if(n)return n;let r=(async()=>{let o=await ke(t,AbortSignal.timeout(Sf)),s=await Promise.all(o.map(async i=>{let l=await wf(i.url,i.token,AbortSignal.timeout(Ef),e);return e?l:Af(i.url,l)}));return{ts:new Date().toISOString(),nodes:s}})().finally(()=>oa.delete(a));return oa.set(a,r),r}function Af(t,e,a=Date.now()){if(e.reachable&&!e.error)return fn.set(t,{node:e,at:a}),e;let n=fn.get(t);return!n||a-n.at>Tf?e:{...n.node,stale:!0,staleSince:new Date(n.at).toISOString(),error:e.error}}function ek(){fn.clear(),oa.clear()}function Cf(t,e,a){let n=s=>s?s.replace(/\/+$/,"").split("/").pop()||s:"",r=e.map(s=>({session:String(s.sessionId).slice(0,8),project:n(s.cwd),agentIds:Array.isArray(s.agentIds)?s.agentIds:[],mode:String(s.mode||"notify"),lastSeenAt:Number(s.lastSeenAt)||0,pending:Number(s.pending)||0})),o=new Set(e.map(s=>s.sessionId));for(let[s,i]of Object.entries(a))o.has(s)||!Array.isArray(i.agentIds)||i.agentIds.length===0||r.push({session:s.slice(0,8),project:n(i.cwd),agentIds:i.agentIds,mode:String(i.mode||"notify"),lastSeenAt:Number(i.savedAt)||0,pending:0,waiting:!0});t.attachSessions=r;for(let s of t.agents){let i=r.find(l=>l.agentIds.includes(s.id)&&!l.waiting)??r.find(l=>l.agentIds.includes(s.id));i&&(s.attached={session:i.session,project:i.project,mode:i.mode,lastSeenAt:i.lastSeenAt,waiting:i.waiting})}}function If(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,r=(l,c)=>{n||e.write(`event: ${l}
20320
+ `)}catch{y.flag=!0}}}}catch{}})();return}if(o==="GET"&&r==="/api/workflows/runs"){try{let u=new URL(t.url||"/","http://localhost"),h=Math.max(1,Math.min(500,Number(u.searchParams.get("limit")||50))),w=u.searchParams.get("workflowId")||void 0,y=u.searchParams.get("summary")==="1"||u.searchParams.get("summary")==="true",T=a.workflowRuns.list({limit:h,workflowId:w}),v=`?limit=${h}${w?`&workflowId=${encodeURIComponent(w)}`:""}${y?"&summary=1":""}`,A=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map($=>({url:$.url,token:$.token}))],R=await Promise.all(A.map(async $=>{let O={};$.token&&(O.Authorization=`Bearer ${$.token}`);try{let U=new AbortController,ce=setTimeout(()=>U.abort(),5e3);try{let Z=await fetch(`${$.url.replace(/\/+$/,"")}/api/workflows/runs${v}`,{headers:O,signal:U.signal});if(!Z.ok)return[];let oe=await Z.json();return Array.isArray(oe.runs)?oe.runs:[]}finally{clearTimeout(ce)}}catch{return[]}})),_=new Map;for(let $ of T)_.set($.id,$);for(let $ of R)for(let O of $)_.set(O.id,O);let L=Array.from(_.values()).sort(($,O)=>$.updatedAt<O.updatedAt?1:-1).slice(0,h),j=y?L.map($=>_h($)):L;k(e,200,{runs:j})}catch(u){k(e,502,{error:"runs fetch failed",message:u.message||String(u)})}return}let f=o==="GET"&&r.match(/^\/api\/workflows\/runs\/([^\/]+)$/);if(f){let u=decodeURIComponent(f[1]),h=a.workflowRuns.get(u);if(h){k(e,200,{run:h});return}let w=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(y=>({url:y.url,token:y.token}))];for(let y of w)try{let T={};y.token&&(T.Authorization=`Bearer ${y.token}`);let v=await fetch(`${y.url.replace(/\/+$/,"")}/api/workflows/runs/${encodeURIComponent(u)}`,{headers:T});if(v.ok){k(e,200,await v.json());return}}catch{}k(e,404,{error:"run not found on any configured peer"});return}if(o==="GET"&&r==="/api/actions/builtin"){try{let u={};a.config.dashboard.token&&(u.Authorization=`Bearer ${a.config.dashboard.token}`);let h=a.config.dashboard.daemonUrl.replace(/\/+$/,""),w=await fetch(`${h}/api/actions/builtin`,{headers:u}),y=await w.json().catch(()=>({error:`HTTP ${w.status}`}));k(e,w.status,y)}catch(u){k(e,502,{error:"daemon unreachable",message:u.message||String(u)})}return}let S=o==="POST"&&r.match(/^\/workflows\/([^/]+)\/run$/);if(S){try{let u=await he(t).catch(()=>({})),h={"Content-Type":"application/json"};a.config.dashboard.token&&(h.Authorization=`Bearer ${a.config.dashboard.token}`);let w=a.config.dashboard.daemonUrl.replace(/\/+$/,""),y=await fetch(`${w}/workflows/${encodeURIComponent(S[1])}/run`,{method:"POST",headers:h,body:JSON.stringify(u??{})}),T=await y.json().catch(()=>({error:`HTTP ${y.status}`}));k(e,y.status,T)}catch(u){k(e,502,{error:"daemon unreachable",message:u.message||String(u)})}return}if(r.startsWith("/api/workflows")&&zi(t,e,{store:a.workflowStore,runs:a.workflowRuns,layouts:a.workflowLayouts,requireScope:(h,w,y)=>{if(a.token)return!0;let T=wa(h);if(!T)return!0;let v=new G().verify(T);if(!v)return k(w,401,{error:"invalid or revoked token"}),!1;for(let A of y)if(!Ae(v,A))return k(w,403,{error:`token missing scope: ${A}`,scopes:v.scopes}),!1;return!0}}))return;if(o==="GET"&&r==="/api/boards"){k(e,200,a.boards.map(u=>({id:u.id,name:u.name,source:u.source,primaryToolLabel:u.primaryToolLabel,labels:u.labels,columns:u.columns,timeRangeDays:u.timeRangeDays})));return}let b=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/members$/);if(b&&o==="GET"){let u=a.sources.get(b[1]);if(!u){k(e,404,{error:"unknown board"});return}try{let h=typeof u.listMembers=="function"?await u.listMembers():[];k(e,200,h)}catch(h){k(e,502,{error:h.message})}return}let E=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(E&&o==="GET"){let u=a.sources.get(E[1]);if(!u){k(e,404,{error:"unknown board"});return}try{let h=typeof u.listMilestones=="function"?await u.listMilestones():[];k(e,200,h)}catch(h){k(e,502,{error:h.message})}return}let g=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),x=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(g&&o==="PATCH"){let[,u,h]=g,w=decodeURIComponent(h),y=a.boards.find(_=>_.id===u);if(!y){k(e,404,{error:`unknown board: ${u}`});return}let T=a.sources.get(u);if(!T){k(e,503,{error:`board "${u}" source unavailable`});return}let v=await he(t),A=y.columns.find(_=>_.id===v.to),R=y.columns.find(_=>_.id===v.from);if(!A){k(e,400,{error:`unknown 'to' column: ${v.to}`});return}try{await kh(T,w,R,A),yn({actor:wn(t),action:"move",boardId:u,itemId:w,payload:{from:v.from,to:v.to}}),k(e,200,{ok:!0})}catch(_){k(e,502,{error:_.message||"transition failed"})}return}if(x){let[,u,h]=x,w=h?decodeURIComponent(h):void 0,y=a.boards.find(v=>v.id===u);if(!y){k(e,404,{error:`unknown board: ${u}`});return}let T=a.sources.get(u);if(!T){k(e,503,{error:`board "${u}" source unavailable`});return}if(o==="GET"&&!w){let{columns:v,totals:A}=await wh(y,T,n.searchParams);k(e,200,{columns:v,totals:A});return}if(o==="GET"&&w){try{let v=typeof T.getItem=="function"?await T.getItem(w):null;if(!v){k(e,404,{error:"not found"});return}k(e,200,v)}catch(v){k(e,502,{error:v.message})}return}if(o==="PATCH"&&w){let v=await he(t);try{let A=typeof T.updateItem=="function"?await T.updateItem(w,v):null;if(!A){k(e,501,{error:"update unsupported"});return}yn({actor:wn(t),action:"update",boardId:u,itemId:w,payload:v}),k(e,200,A)}catch(A){k(e,502,{error:A.message})}return}if(o==="POST"&&!w){let v=await he(t);if(!v.title){k(e,400,{error:"title required"});return}if(!T.capabilities.create||!T.create){k(e,400,{error:`source ${T.type} does not support create`});return}try{let A=await T.create({title:v.title,description:v.description,labels:v.labels,assigneeUsernames:v.assigneeUsernames,milestoneTitle:v.milestoneTitle,projectHint:v.projectHint});yn({actor:wn(t),action:"create",boardId:u,itemId:A.id,payload:{title:v.title}}),k(e,201,A)}catch(A){k(e,502,{error:A.message})}return}}if(o==="GET"&&/^\/[a-z][a-z-]*\/?$/.test(r)){let u=r.replace(/^\/+|\/+$/g,""),w={health:"/admin/health",ledger:"/admin/ledger",cost:"/admin/cost",projects:"/admin/projects",graph:"/admin/graph",wiki:"/admin/wiki/",observability:"/admin/health"}[u];if(w){e.writeHead(302,{Location:w}),e.end();return}}k(e,404,{error:"not found",path:r})}async function wh(t,e,a){if(!e.capabilities.listAll||!e.listAll){let x={};for(let u of t.columns)x[u.id]=[];return{columns:x,totals:Object.fromEntries(t.columns.map(u=>[u.id,0]))}}let n=[];t.primaryToolLabel&&n.push(t.primaryToolLabel);let r=a.get("label")||void 0;r&&n.push(r);let o=a.get("q")||void 0,s=a.get("milestone")||void 0,i=a.get("assignee")||void 0,l=parseInt(a.get("days")||String(t.timeRangeDays),10),c=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),d=t.columns.some(x=>x.kind!=="closed"),p=t.columns.some(x=>x.kind==="closed"),m=d?await e.listAll({sinceDays:l,labels:n.length?n:void 0,search:o,milestone:s,state:"opened"}):[],f=p?await e.listAll({sinceDays:c,labels:n.length?n:void 0,search:o,milestone:s,state:"closed"}):[],S={};for(let x of t.columns)S[x.id]=[];let b=t.columns.find(x=>x.kind==="closed");for(let x of f)b&&S[b.id].push({...x,stage:b.id});let E=t.columns.filter(x=>x.kind!=="closed");for(let x of m){let u=Cn(x,E);if(!u)continue;let h=S[u];h&&h.push({...x,stage:u})}if(i)for(let x of Object.keys(S))S[x]=S[x].filter(u=>u.assignee===i);for(let x of Object.keys(S))S[x].sort((u,h)=>{let w=(u.priority??99)-(h.priority??99);return w!==0?w:(h.updatedAt||"").localeCompare(u.updatedAt||"")});let g=Object.fromEntries(Object.entries(S).map(([x,u])=>[x,u.length]));return{columns:S,totals:g}}async function kh(t,e,a,n){let r=In(a,n),o=t;r.closeIssue&&typeof o.setState=="function"?await o.setState(e,"close"):r.reopen&&typeof o.setState=="function"&&await o.setState(e,"reopen"),(r.addLabels?.length||r.removeLabels?.length)&&typeof o.transitionMany=="function"?await o.transitionMany(e,r.addLabels||[],r.removeLabels||[]):r.addLabels?.length&&t.transition&&await t.transition(e,r.addLabels[0],r.removeLabels?.[0])}function _h(t){return{id:t.id,workflowId:t.workflowId,workflowVersion:t.workflowVersion,homeNode:t.homeNode,status:t.status,pending:t.pending,entityRef:t.entityRef,history:(t.history||[]).slice(-5),parentRunId:t.parentRunId,parentNodeId:t.parentNodeId,rootRunId:t.rootRunId,depth:t.depth,createdAt:t.createdAt,updatedAt:t.updatedAt}}function Sh(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 r of a.agentMappings)r.gitlabUsernames.length&&(n[r.agentId]=r.gitlabUsernames);return new kr(a.host,a.token,t.source.projects,n,(...r)=>console.log("[board]",...r))}throw new Error(`unsupported board source: ${t.source.type}`)}function yn(t){try{let e=ct(process.cwd(),".agentx");$c(e)||hh(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
20321
+ `;fh(ct(e,"board-audit.jsonl"),a)}catch{}}function wn(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}var Eh=2e3;async function Th(t,e,a,n){let r={};e&&(r.Authorization=`Bearer ${e}`);let o={id:t,name:t,url:t,reachable:!1,agents:[]};try{let s=n?`?date=${encodeURIComponent(n.date)}&timezone=${encodeURIComponent(n.timezone)}`:"",i=g=>{let x=new AbortController,u=setTimeout(()=>x.abort(),Eh),h=()=>x.abort();return a?.addEventListener("abort",h,{once:!0}),fetch(t+g,{headers:r,signal:x.signal}).then(async w=>{let y=w.ok?await w.json().catch(()=>{}):void 0;return{ok:y!==void 0,json:async()=>y}}).catch(()=>null).finally(()=>{clearTimeout(u),a?.removeEventListener("abort",h)})},[l,c,d,p,m,f,S,b]=await Promise.all([i("/health"),fetch(t+"/agents",{headers:r,signal:a}).catch(()=>null),i("/mesh"),i("/crons"),i("/crons/runs"+s),i("/talk"),i("/routines"),i("/attach/sessions")]);if(!c||!c.ok)return o.error=c?`HTTP ${c.status}`:"unreachable",o;let E=await c.json();if(o.agents=E.map(g=>({id:g.id,name:g.name,tier:g.tier,model:g.model,...typeof g.color=="string"&&/^#[0-9a-fA-F]{6}$/.test(g.color)?{color:g.color}:{},skillCount:Number.isFinite(g.skillCount)?g.skillCount:void 0,active:g.active||0,total:g.total||0,errors:g.errors||0,lastActive:g.lastActive,lastSummary:g.lastSummary,hourlyTasks:Array.isArray(g.hourlyTasks)?g.hourlyTasks:void 0,runningTasks:Array.isArray(g.runningTasks)?g.runningTasks:[]})),l&&l.ok){let g=await l.json().catch(()=>({}));o.uptimeSec=g.uptime,typeof g.inflight?.total=="number"&&(o.inflight=g.inflight.total),g.restart&&typeof g.restart.state=="string"&&(o.restart=g.restart),o.name=g.node?.name||g.node?.id||t,o.id=g.node?.id||t,g.usage&&(o.usage=g.usage)}if(p&&p.ok){let g=await p.json().then(x=>Array.isArray(x)?x:[],()=>[]);o.crons=g.map(x=>({id:x.id,enabled:x.enabled===!0,schedule:String(x.schedule||""),timezone:x.timezone,agent:String(x.agent||""),kind:typeof x.command=="string"&&x.command.trim()?"command":"agent",model:x.model,nextRun:x.nextRun,retryPending:x.retryPending===!0,consecutiveErrors:Number(x.consecutiveErrors)||0}))}if(m&&m.ok){let g=await m.json().catch(()=>({}));o.cronRuns=Array.isArray(g.runs)?g.runs:[]}if(S&&S.ok){let g=await S.json().catch(()=>null);g&&Array.isArray(g.routines)&&(o.routines=g.routines.slice(0,Qn.routines))}if(f&&f.ok){let g=await f.json().catch(()=>null);g?.active&&g.kind==="lesson"&&(o.lesson={agentId:g.agentId??null,mode:String(g.mode||"teach"),goal:String(g.goal||""),step:Number(g.step)||0,saying:String(g.saying||""),startedAt:String(g.startedAt||"")})}if(b&&b.ok){let g=await b.json().catch(()=>null);g&&Array.isArray(g.sessions)&&Ph(o,g.sessions,g.saved??{})}o.reachable=!0,o._peers=Array.isArray(d?.ok?await d.json():null)?o._peers:void 0}catch(s){o.error=s.message||String(s)}return o}var la=null;function Ah(t){if(la)return la;let e=ct(process.cwd(),".agentx/wiki");return la=Yr({wikiDir:e,pathPrefix:"/admin/wiki",mode:"graph"}),la}async function da(t,e,a){try{let n={};e&&(n.Authorization=`Bearer ${e}`);let r=await fetch(t+"/mesh",{headers:n,signal:a});return r.ok?(await r.json()).filter(s=>s&&s.peerUrl).map(s=>({url:String(s.peerUrl).replace(/\/+$/,""),name:s.peer||s.peerUrl})):[]}catch{return[]}}async function Ch(t,e,a){let n=Math.max(1,Math.min(200,Number(a.get("limit"))||50)),r=e.dashboard.daemonUrl.replace(/\/+$/,""),o=process.env.MESH_TOKEN||W(e.dashboard,r);try{let s=await fetch(`${r}/events/recent?skip=task:step&limit=${n}`,{headers:o?{Authorization:`Bearer ${o}`}:{},signal:AbortSignal.timeout(5e3)});if(!s.ok){k(t,502,{error:`daemon answered ${s.status}`});return}let i=await s.json();k(t,200,{node:e.node.name||e.node.id,events:i.events??[]})}catch(s){k(t,502,{error:s.message||"daemon unreachable"})}}async function Te(t,e){let a=t.dashboard,n=a.daemonUrl.replace(/\/+$/,""),r=W(a,n),o=new Map;o.set(n,{name:"primary",url:n,token:r});for(let i of a.daemons){let l=i.url.replace(/\/+$/,"");o.has(l)||o.set(l,{name:i.name,url:l,token:W(a,l)})}let s=await da(n,r,e);for(let i of s)o.has(i.url)||o.set(i.url,{...i,token:W(a,i.url)});return[...o.values()]}var Ih=3e3,Mh=6e3,Lh=5*6e4,_n=new Map,ca=new Map;function Qe(t,e){let a=e?`${e.date}|${e.timezone}`:"live",n=ca.get(a);if(n)return n;let r=(async()=>{let o=await Te(t,AbortSignal.timeout(Ih)),s=await Promise.all(o.map(async i=>{let l=await Th(i.url,i.token,AbortSignal.timeout(Mh),e);return e?l:Rh(i.url,l)}));return{ts:new Date().toISOString(),nodes:s}})().finally(()=>ca.delete(a));return ca.set(a,r),r}function Rh(t,e,a=Date.now()){if(e.reachable&&!e.error)return _n.set(t,{node:e,at:a}),e;let n=_n.get(t);return!n||a-n.at>Lh?e:{...n.node,stale:!0,staleSince:new Date(n.at).toISOString(),error:e.error}}function T0(){_n.clear(),ca.clear()}function Ph(t,e,a){let n=s=>s?s.replace(/\/+$/,"").split("/").pop()||s:"",r=e.map(s=>({session:String(s.sessionId).slice(0,8),project:n(s.cwd),agentIds:Array.isArray(s.agentIds)?s.agentIds:[],mode:String(s.mode||"notify"),lastSeenAt:Number(s.lastSeenAt)||0,pending:Number(s.pending)||0})),o=new Set(e.map(s=>s.sessionId));for(let[s,i]of Object.entries(a))o.has(s)||!Array.isArray(i.agentIds)||i.agentIds.length===0||r.push({session:s.slice(0,8),project:n(i.cwd),agentIds:i.agentIds,mode:String(i.mode||"notify"),lastSeenAt:Number(i.savedAt)||0,pending:0,waiting:!0});t.attachSessions=r;for(let s of t.agents){let i=r.find(l=>l.agentIds.includes(s.id)&&!l.waiting)??r.find(l=>l.agentIds.includes(s.id));i&&(s.attached={session:i.session,project:i.project,mode:i.mode,lastSeenAt:i.lastSeenAt,waiting:i.waiting})}}function $h(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,r=(l,c)=>{n||e.write(`event: ${l}
19810
20322
  data: ${JSON.stringify(c)}
19811
20323
 
19812
- `)},o=!1,s=async()=>{if(!o){o=!0;try{let l=await Xe(a);r("snapshot",l)}catch(l){r("error",{message:l.message})}finally{o=!1}}};s();let i=setInterval(s,2e3);t.on("close",()=>{n=!0,clearInterval(i),e.end()})}async function Mf(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),i=new Set;i.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let _ of a.config.dashboard.daemons)i.add(_.url.replace(/\/+$/,""));try{let _=await sa(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let v of _)i.add(v.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){y(e,403,{error:"node not in dashboard allowlist",target:s});return}let l=U(a.config.dashboard,s),c={Accept:"text/event-stream"};l&&(c.Authorization=`Bearer ${l}`);let p=new AbortController,u;try{u=await fetch(`${s}/agents/${encodeURIComponent(r)}/tasks/${encodeURIComponent(o)}/stream`,{headers:c,signal:p.signal})}catch(_){y(e,502,{error:_.message||"upstream connect failed"});return}if(!u.ok||!u.body){y(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","X-Accel-Buffering":"no"});let m=u.body.getReader();(async()=>{try{for(;;){let{value:_,done:v}=await m.read();if(v)break;_&&e.write(_)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{p.abort();try{e.end()}catch{}})}function Lf(t,e,a){let n=ga(t);if(!n)return y(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let r=new F().verify(n);if(!r)return y(e,401,{error:"invalid or revoked token"}),null;for(let o of a)if(!_e(r,o))return y(e,403,{error:`token missing scope: ${o}`,scopes:r.scopes}),null;return r}async function Rf(t,e,a,n){let r=a.agents?.[n];if(!r){y(e,404,{error:"unknown agent"});return}if(r.access!=="public"){y(e,403,{error:"agent is private",hint:`set agents.${n}.access = "public" to expose it`});return}let o;try{o=await pe(t)}catch{y(e,400,{error:"invalid JSON body"});return}let s=o?.message;if(!s||typeof s!="string"){y(e,400,{error:"required: { message: string, context?: {...} }"});return}let i=a.dashboard.daemonUrl.replace(/\/+$/,""),l={"Content-Type":"application/json"};a.dashboard.token&&(l.Authorization=`Bearer ${a.dashboard.token}`);try{let c=await fetch(`${i}/task`,{method:"POST",headers:l,body:JSON.stringify({agent:n,message:s,context:{channel:"public-api",sender:o.context?.sender||"api",...o.context||{}}})}),p=await c.text();e.writeHead(c.status,{"Content-Type":c.headers.get("content-type")||"application/json; charset=utf-8"}),e.end(p)}catch(c){y(e,502,{error:c.message||"upstream call failed"})}}async function $f(t,e,a,n,r,o){let s=a.replace(/\/+$/,""),i=new Set;i.add(e.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let u of e.config.dashboard.daemons)i.add(u.url.replace(/\/+$/,""));try{let u=await sa(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let m of u)i.add(m.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){y(t,403,{error:"node not in dashboard allowlist",target:s});return}let l=U(e.config.dashboard,s),c={Accept:"application/json"};l&&(c.Authorization=`Bearer ${l}`);let p=r?`/agents/${encodeURIComponent(n)}/tasks/${encodeURIComponent(r)}`:`/agents/${encodeURIComponent(n)}/tasks?limit=${encodeURIComponent(o)}`;try{let u=await fetch(`${s}${p}`,{headers:c}),m=await u.text();t.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json; charset=utf-8"}),t.end(m)}catch(u){y(t,502,{error:u.message||"upstream fetch failed"})}}async function Pf(t,e,a,n,r,o){await hn(t,e,a,n,`/api/tasks/${encodeURIComponent(r)}/${o}`)}async function hn(t,e,a,n,r){let o={};try{o=await pe(t)??{}}catch{}let s=await Gl(a.config,n,r,o);e.writeHead(s.status,{"Content-Type":s.contentType}),e.end(s.text)}async function Gl(t,e,a,n){let r=(c,p)=>({status:c,text:JSON.stringify(p),contentType:"application/json"}),o=e.replace(/\/+$/,""),s=new Set;s.add(t.dashboard.daemonUrl.replace(/\/+$/,""));for(let c of t.dashboard.daemons)s.add(c.url.replace(/\/+$/,""));try{let c=await sa(t.dashboard.daemonUrl.replace(/\/+$/,""),t.dashboard.token);for(let p of c)s.add(p.url.replace(/\/+$/,""))}catch{}if(!s.has(o))return r(403,{error:"node not in dashboard allowlist",target:o});let i=U(t.dashboard,o),l={"Content-Type":"application/json",Accept:"application/json"};i&&(l.Authorization=`Bearer ${i}`);try{let c=await fetch(`${o}${a}`,{method:"POST",headers:l,body:JSON.stringify(n??{})});return{status:c.status,text:await c.text(),contentType:c.headers.get("content-type")||"application/json; charset=utf-8"}}catch(c){return r(502,{error:c.message||"upstream fetch failed"})}}function Xl(t){let e=t.channels.push,a=r=>({store:()=>null,publicKey:()=>null,keepRecent:0,allowedHosts:[],reason:r});if(!e.enabled)return a("Notifications are off. On the computer, run: agentx notifications push --enable");if(e.relayTo)return a(`Notifications are set up on ${e.relayTo}. Pair this phone with that computer instead.`);let n=Wn(e.keysFile);return{store:()=>{let r=Ge();return r?new vr(r):null},publicKey:()=>Gn(n)?.publicKey??null,keepRecent:e.keepRecent,allowedHosts:e.allowedHosts,reason:"The database on this computer is unavailable, so notifications can't be saved."}}function Kl(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=n=>{try{return JSON.parse(n)}catch{return{error:n.slice(0,200)}}};return{snapshot:n=>Xe(t,n),async nodePost(n,r,o){let s=await Gl(t,n,r,o);return{status:s.status,body:a(s.text)}},async approvals(){let n={node:e,nodeName:t.node?.name||"this computer",items:[]};try{n.items=wt({root:process.cwd()}).items.map(Fl)}catch(o){n.error=o.message}let r=await Promise.all(t.dashboard.daemons.map(async o=>{let s={node:o.url.replace(/\/+$/,""),nodeName:o.name,items:[]},i=st(o.url,t);if(!i)return s;try{let l=await fetch(`${i.url}/api/admin/approvals`,{headers:{"X-Agentx-Peer":"primary",...i.token?{Authorization:`Bearer ${i.token}`}:{}},signal:AbortSignal.timeout(4e3)});if(!l.ok)return s.error=`HTTP ${l.status}`,s;let c=await l.json();s.items=(c.items??[]).map(Fl)}catch(l){s.error=l.message||"unreachable"}return s}));return[n,...r]},async decide(n,r,o,s){let i=n.replace(/\/+$/,"");if(i===e){let c=Se(),p=await kt({root:process.cwd()},r,o,{laterHours:c.laterHours,by:s});return p.ok?{status:200,body:{ok:!0,message:p.message}}:{status:409,body:{error:p.error}}}let l=st(i,t);if(!l)return{status:403,body:{error:"node not in dashboard allowlist",target:i}};try{let c=await fetch(`${l.url}/api/admin/approvals/decide`,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"agentx-board","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},body:JSON.stringify({key:r,action:o}),signal:AbortSignal.timeout(1e4)});return{status:c.status,body:a(await c.text())}}catch(c){return{status:502,body:{error:c.message||"peer dashboard unreachable"}}}}}}var mn=null;function ql(t){return mn?.days!==t&&(mn={days:t,store:new mt(process.cwd(),Date.now,t)}),mn.store}function Jl(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=U(t.dashboard,e),n=Kl(t);return{store:()=>{let r=Ge();return r?new rt(r):null},daemon:{url:e,token:a,name:t.node?.name,operatorKey:En(process.cwd())??void 0},snapshot:()=>Xe(t),meshPeers:async()=>{let r=await fetch(e+"/mesh",{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(3e3)});return r.ok?await r.json():[]},nodePost:(r,o,s)=>n.nodePost(r,o,s),tokenFor:r=>U(t.dashboard,r.replace(/\/+$/,"")),...jf(t,e,a)}}function jf(t,e,a){let n=Xl(t);return{finishAlerts:r=>{let o=n.store();return!!o&&o.chatFinishOn(r)&&o.list(r).length>0},notifyFinish:async r=>{try{let o=await fetch(e+"/channel/send",{method:"POST",headers:{"Content-Type":"application/json",...a?{Authorization:`Bearer ${a}`}:{}},body:JSON.stringify({channel:"push",chatId:r.deviceId,text:`${r.title}
19813
- ${r.body}`,buttons:[{label:"Open",url:r.url}]}),signal:AbortSignal.timeout(1e4)});o.ok||console.error(`[app] finish notification not sent: HTTP ${o.status} ${(await o.text()).slice(0,160)}`)}catch(o){console.error(`[app] finish notification not sent: ${o?.message||o}`)}}}}function Of(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=o=>U(t.dashboard,o.replace(/\/+$/,"")),n=o=>{let s=a(o);return s?{Authorization:`Bearer ${s}`}:{}},r=Jl(t);return new na({recent:async(o,s)=>{let i=new URLSearchParams({kind:"delegation",limit:String(s)});o&&i.set("since",o);let l=await fetch(`${e}/events/recent?${i}`,{headers:n(e),signal:AbortSignal.timeout(5e3)});if(!l.ok)throw new Error(`the daemon answered ${l.status}`);let c=await l.json();return{events:Array.isArray(c.events)?c.events:[],gap:c.gap===!0}},nodeUrl:async o=>{let i=(await Xe(t)).nodes.find(l=>l.name===o||l.id===o);return i?.url?i.url.replace(/\/+$/,""):null},conversationUrl:async o=>{if(o.node==="local")return e;let s=(await r.meshPeers().catch(()=>[])).find(i=>i.peer===o.node);return s?s.peerUrl.replace(/\/+$/,""):null},fetchReply:async(o,s)=>{let i=await fetch(`${o}/a2a/delegations/${encodeURIComponent(s)}/reply`,{headers:n(o),signal:AbortSignal.timeout(5e3)});if(i.status===404)return null;if(!i.ok)throw new Error(`the node answered ${i.status}`);return await i.json()},store:r.store,presence:Oi(),finishAlerts:r.finishAlerts,notifyFinish:r.notifyFinish,log:o=>console.log(o),warn:o=>console.warn(o)})}function Nf(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,"");return{store:()=>{let a=Ge();return a?new rt(a):null},daemon:{url:e,token:U(t.dashboard,e)}}}function Df(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,"");return{daemon:{url:e,token:U(t.dashboard,e)},nodeName:t.node.name}}function Fl(t){return{key:t.key,title:t.title,ask:t.ask,recommend:t.recommend,yes:t.yes,no:t.no,raisedBy:t.raised_by,expires:t.expires}}var Hf=`
20324
+ `)},o=!1,s=async()=>{if(!o){o=!0;try{let l=await Qe(a);r("snapshot",l)}catch(l){r("error",{message:l.message})}finally{o=!1}}};s();let i=setInterval(s,2e3);t.on("close",()=>{n=!0,clearInterval(i),e.end()})}async function jh(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),i=new Set;i.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let S of a.config.dashboard.daemons)i.add(S.url.replace(/\/+$/,""));try{let S=await da(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let b of S)i.add(b.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){k(e,403,{error:"node not in dashboard allowlist",target:s});return}let l=W(a.config.dashboard,s),c={Accept:"text/event-stream"};l&&(c.Authorization=`Bearer ${l}`);let d=new AbortController,p;try{p=await fetch(`${s}/agents/${encodeURIComponent(r)}/tasks/${encodeURIComponent(o)}/stream`,{headers:c,signal:d.signal})}catch(S){k(e,502,{error:S.message||"upstream connect failed"});return}if(!p.ok||!p.body){k(e,p.status||502,{error:`upstream HTTP ${p.status}`});return}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"});let m=p.body.getReader();(async()=>{try{for(;;){let{value:S,done:b}=await m.read();if(b)break;S&&e.write(S)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{d.abort();try{e.end()}catch{}})}function Oh(t,e,a){let n=wa(t);if(!n)return k(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let r=new G().verify(n);if(!r)return k(e,401,{error:"invalid or revoked token"}),null;for(let o of a)if(!Ae(r,o))return k(e,403,{error:`token missing scope: ${o}`,scopes:r.scopes}),null;return r}async function Nh(t,e,a,n){let r=a.agents?.[n];if(!r){k(e,404,{error:"unknown agent"});return}if(r.access!=="public"){k(e,403,{error:"agent is private",hint:`set agents.${n}.access = "public" to expose it`});return}let o;try{o=await he(t)}catch{k(e,400,{error:"invalid JSON body"});return}let s=o?.message;if(!s||typeof s!="string"){k(e,400,{error:"required: { message: string, context?: {...} }"});return}let i=a.dashboard.daemonUrl.replace(/\/+$/,""),l={"Content-Type":"application/json"};a.dashboard.token&&(l.Authorization=`Bearer ${a.dashboard.token}`);try{let c=await fetch(`${i}/task`,{method:"POST",headers:l,body:JSON.stringify({agent:n,message:s,context:{channel:"public-api",sender:o.context?.sender||"api",...o.context||{}}})}),d=await c.text();e.writeHead(c.status,{"Content-Type":c.headers.get("content-type")||"application/json; charset=utf-8"}),e.end(d)}catch(c){k(e,502,{error:c.message||"upstream call failed"})}}async function Dh(t,e,a,n,r,o){let s=a.replace(/\/+$/,""),i=new Set;i.add(e.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let p of e.config.dashboard.daemons)i.add(p.url.replace(/\/+$/,""));try{let p=await da(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let m of p)i.add(m.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){k(t,403,{error:"node not in dashboard allowlist",target:s});return}let l=W(e.config.dashboard,s),c={Accept:"application/json"};l&&(c.Authorization=`Bearer ${l}`);let d=r?`/agents/${encodeURIComponent(n)}/tasks/${encodeURIComponent(r)}`:`/agents/${encodeURIComponent(n)}/tasks?limit=${encodeURIComponent(o)}`;try{let p=await fetch(`${s}${d}`,{headers:c}),m=await p.text();t.writeHead(p.status,{"Content-Type":p.headers.get("content-type")||"application/json; charset=utf-8"}),t.end(m)}catch(p){k(t,502,{error:p.message||"upstream fetch failed"})}}async function Hh(t,e,a,n,r,o){await Sn(t,e,a,n,`/api/tasks/${encodeURIComponent(r)}/${o}`)}async function Sn(t,e,a,n,r){let o={};try{o=await he(t)??{}}catch{}let s=await jc(a.config,n,r,o);e.writeHead(s.status,{"Content-Type":s.contentType}),e.end(s.text)}async function jc(t,e,a,n){let r=(c,d)=>({status:c,text:JSON.stringify(d),contentType:"application/json"}),o=e.replace(/\/+$/,""),s=new Set;s.add(t.dashboard.daemonUrl.replace(/\/+$/,""));for(let c of t.dashboard.daemons)s.add(c.url.replace(/\/+$/,""));try{let c=await da(t.dashboard.daemonUrl.replace(/\/+$/,""),t.dashboard.token);for(let d of c)s.add(d.url.replace(/\/+$/,""))}catch{}if(!s.has(o))return r(403,{error:"node not in dashboard allowlist",target:o});let i=W(t.dashboard,o),l={"Content-Type":"application/json",Accept:"application/json"};i&&(l.Authorization=`Bearer ${i}`);try{let c=await fetch(`${o}${a}`,{method:"POST",headers:l,body:JSON.stringify(n??{})});return{status:c.status,text:await c.text(),contentType:c.headers.get("content-type")||"application/json; charset=utf-8"}}catch(c){return r(502,{error:c.message||"upstream fetch failed"})}}function En(t){let e=t.channels.push,a=r=>({store:()=>null,publicKey:()=>null,keepRecent:0,allowedHosts:[],reason:r});if(!e.enabled)return a("Notifications are off. On the computer, run: agentx notifications push --enable");if(e.relayTo)return a(`Notifications are set up on ${e.relayTo}. Pair this phone with that computer instead.`);let n=ar(e.keysFile);return{store:()=>{let r=Ye();return r?new Ir(r):null},publicKey:()=>nr(n)?.publicKey??null,keepRecent:e.keepRecent,allowedHosts:e.allowedHosts,reason:"The database on this computer is unavailable, so notifications can't be saved."}}function Mc(t){let e=t.channels.push,a=t.dashboard.daemonUrl.replace(/\/+$/,""),n=e.enabled&&!e.relayTo?Sl({url:a,token:W(t.dashboard,a),operatorKey:ga(process.cwd())??void 0}):null;return Cl(t,process.cwd(),n,En(t).reason)}function Oc(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=n=>{try{return JSON.parse(n)}catch{return{error:n.slice(0,200)}}};return{snapshot:n=>Qe(t,n),async nodePost(n,r,o){let s=await jc(t,n,r,o);return{status:s.status,body:a(s.text)}},async approvals(){let n={node:e,nodeName:t.node?.name||"this computer",items:[]};try{n.items=Et({root:process.cwd()}).items.map(Rc)}catch(o){n.error=o.message}let r=await Promise.all(t.dashboard.daemons.map(async o=>{let s={node:o.url.replace(/\/+$/,""),nodeName:o.name,items:[]},i=dt(o.url,t);if(!i)return s;try{let l=await fetch(`${i.url}/api/admin/approvals`,{headers:{"X-Agentx-Peer":"primary",...i.token?{Authorization:`Bearer ${i.token}`}:{}},signal:AbortSignal.timeout(4e3)});if(!l.ok)return s.error=`HTTP ${l.status}`,s;let c=await l.json();s.items=(c.items??[]).map(Rc)}catch(l){s.error=l.message||"unreachable"}return s}));return[n,...r]},async decide(n,r,o,s){let i=n.replace(/\/+$/,"");if(i===e){let c=Ie(),d=await Tt({root:process.cwd()},r,o,{laterHours:c.laterHours,by:s});return d.ok?{status:200,body:{ok:!0,message:d.message}}:{status:409,body:{error:d.error}}}let l=dt(i,t);if(!l)return{status:403,body:{error:"node not in dashboard allowlist",target:i}};try{let c=await fetch(`${l.url}/api/admin/approvals/decide`,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"agentx-board","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},body:JSON.stringify({key:r,action:o}),signal:AbortSignal.timeout(1e4)});return{status:c.status,body:a(await c.text())}}catch(c){return{status:502,body:{error:c.message||"peer dashboard unreachable"}}}}}}var kn=null;function Lc(t){return kn?.days!==t&&(kn={days:t,store:new xt(process.cwd(),Date.now,t)}),kn.store}function Nc(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=W(t.dashboard,e),n=Oc(t);return{store:()=>{let r=Ye();return r?new lt(r):null},daemon:{url:e,token:a,name:t.node?.name,operatorKey:ga(process.cwd())??void 0},snapshot:()=>Qe(t),meshPeers:async()=>{let r=await fetch(e+"/mesh",{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(3e3)});return r.ok?await r.json():[]},nodePost:(r,o,s)=>n.nodePost(r,o,s),tokenFor:r=>W(t.dashboard,r.replace(/\/+$/,"")),...Bh(t,e,a)}}function Bh(t,e,a){let n=En(t);return{finishAlerts:r=>{let o=n.store();return!!o&&o.chatFinishOn(r)&&o.list(r).length>0},notifyFinish:async r=>{try{let o=await fetch(e+"/channel/send",{method:"POST",headers:{"Content-Type":"application/json",...a?{Authorization:`Bearer ${a}`}:{}},body:JSON.stringify({channel:"push",chatId:r.deviceId,text:`${r.title}
20325
+ ${r.body}`,buttons:[{label:"Open",url:r.url}]}),signal:AbortSignal.timeout(1e4)});o.ok||console.error(`[app] finish notification not sent: HTTP ${o.status} ${(await o.text()).slice(0,160)}`)}catch(o){console.error(`[app] finish notification not sent: ${o?.message||o}`)}}}}function zh(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=o=>W(t.dashboard,o.replace(/\/+$/,"")),n=o=>{let s=a(o);return s?{Authorization:`Bearer ${s}`}:{}},r=Nc(t);return new ia({recent:async(o,s)=>{let i=new URLSearchParams({kind:"delegation",limit:String(s)});o&&i.set("since",o);let l=await fetch(`${e}/events/recent?${i}`,{headers:n(e),signal:AbortSignal.timeout(5e3)});if(!l.ok)throw new Error(`the daemon answered ${l.status}`);let c=await l.json();return{events:Array.isArray(c.events)?c.events:[],gap:c.gap===!0}},nodeUrl:async o=>{let i=(await Qe(t)).nodes.find(l=>l.name===o||l.id===o);return i?.url?i.url.replace(/\/+$/,""):null},conversationUrl:async o=>{if(o.node==="local")return e;let s=(await r.meshPeers().catch(()=>[])).find(i=>i.peer===o.node);return s?s.peerUrl.replace(/\/+$/,""):null},fetchReply:async(o,s)=>{let i=await fetch(`${o}/a2a/delegations/${encodeURIComponent(s)}/reply`,{headers:n(o),signal:AbortSignal.timeout(5e3)});if(i.status===404)return null;if(!i.ok)throw new Error(`the node answered ${i.status}`);return await i.json()},store:r.store,presence:al(),finishAlerts:r.finishAlerts,notifyFinish:r.notifyFinish,log:o=>console.log(o),warn:o=>console.warn(o)})}function qh(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,"");return{store:()=>{let a=Ye();return a?new lt(a):null},daemon:{url:e,token:W(t.dashboard,e)}}}function Fh(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,"");return{daemon:{url:e,token:W(t.dashboard,e)},nodeName:t.node.name}}function Rc(t){return{key:t.key,title:t.title,ask:t.ask,recommend:t.recommend,yes:t.yes,no:t.no,raisedBy:t.raised_by,expires:t.expires}}var Uh=`
19814
20326
  You are helping draft a new GitLab issue. Follow these conventions strictly.
19815
20327
 
19816
20328
  Title pattern:
@@ -19842,16 +20354,16 @@ Return ONLY a single JSON object on one line \u2014 no prose, no code fences, no
19842
20354
  Shape:
19843
20355
  { "title": string, "description": string, "labels": string[], "assigneeUsername": string | null, "kind": string }
19844
20356
  If you don't have enough information to pick a label confidently, omit it rather than guessing.
19845
- `;async function Bf(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 r=e?.context||{},o=["Rough description from the user:",'"""',a,'"""',"",`Board: ${r.boardName||"(unspecified)"}`,r.primaryLabel?`Primary board label (include in labels): ${r.primaryLabel}`:"",r.columnLabel?`Target column label (include in labels): ${r.columnLabel}`:"",r.project?`GitLab project: ${r.project}`:"",r.knownLabels?.length?`Known labels in this project (prefer picking from these when they fit):
20357
+ `;async function Wh(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 r=e?.context||{},o=["Rough description from the user:",'"""',a,'"""',"",`Board: ${r.boardName||"(unspecified)"}`,r.primaryLabel?`Primary board label (include in labels): ${r.primaryLabel}`:"",r.columnLabel?`Target column label (include in labels): ${r.columnLabel}`:"",r.project?`GitLab project: ${r.project}`:"",r.knownLabels?.length?`Known labels in this project (prefer picking from these when they fit):
19846
20358
  - ${r.knownLabels.slice(0,60).join(`
19847
20359
  - `)}`:"",r.members?.length?`Possible assignees (GitLab usernames): ${r.members.slice(0,20).join(", ")}`:"","","Produce the JSON draft now."].filter(Boolean).join(`
19848
- `),s=t.dashboard.daemonUrl.replace(/\/+$/,"")+"/task",i={"Content-Type":"application/json"};t.dashboard.token&&(i.Authorization=`Bearer ${t.dashboard.token}`);let l=await fetch(s,{method:"POST",headers:i,body:JSON.stringify({agent:n,message:o,context:{channel:"a2a",sender:"board-dashboard",systemPrompt:Hf}})});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 p=(c.content||"").toString(),u=zf(p);if(!u||typeof u.title!="string")throw new Error("agent did not return a valid JSON draft. Raw: "+p.slice(0,400));let m=Array.isArray(u.labels)?u.labels.filter(h=>typeof h=="string"):[];return r.primaryLabel&&!m.includes(r.primaryLabel)&&m.unshift(r.primaryLabel),r.columnLabel&&!m.includes(r.columnLabel)&&m.unshift(r.columnLabel),{title:u.title.trim(),description:(u.description||"").toString(),labels:m,assigneeUsername:typeof u.assigneeUsername=="string"?u.assigneeUsername:void 0,kind:typeof u.kind=="string"?u.kind:void 0,raw:p}}function zf(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 r=a;r<t.length;r++){let o=t[r];if(o==="{")n++;else if(o==="}"&&(n--,n===0))try{return JSON.parse(t.slice(a,r+1))}catch{return null}}return null}function qf(t){let e=mf(uf(import.meta.url));return ot(e,t)}async function Ff(t){return pf(t)}function y(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function pe(t){return new Promise((e,a)=>{let n=[];t.on("data",r=>n.push(r)),t.on("end",()=>{try{let r=Buffer.concat(n).toString("utf-8");e(r?JSON.parse(r):{})}catch(r){a(r)}}),t.on("error",a)})}function Vl(t){return t.dashboardUrl?t.dashboardUrl.replace(/\/+$/,""):t.url.replace(/\/+$/,"").replace(/:(?:1[89][89]00|18810)$/,":4202")}function D(t,e){let a=e||t,n={id:"primary",name:a.node?.name||"this daemon",dashboardUrl:"",primary:!0},r=(a.dashboard?.daemons||[]).map(s=>({id:s.url.replace(/\/+$/,""),name:s.name,dashboardUrl:Vl(s),tokenScope:s.dashboardToken||s.token?"proxy-ready":void 0})),o=r.length>0?[{id:"fleet",name:"Fleet (all peers)",dashboardUrl:"",tokenScope:"merged across nodes"}]:[];return[n,...r,...o]}async function Uf(t,e,a){let n=new URL(t.url||"/","http://_"),r=parseInt(n.searchParams.get("hours")||"6",10)||6;y(e,200,await Jt(await Yl(r,a.config)))}async function Yl(t,e){let a=e.node?.id||e.node?.name||"local",n=[],r=Ua(t);r&&n.push({nodeId:a,snap:r});let o=(e.dashboard?.daemons||[]).filter(i=>i.url),s=await Promise.all(o.map(async i=>{let l=st(i.url.replace(/\/+$/,""),e);if(!l)return null;try{let c=new AbortController,p=setTimeout(()=>c.abort(),8e3);try{let u=await fetch(`${l.url}/api/admin/activity-graph?hours=${t}`,{headers:{Accept:"application/json","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},signal:c.signal});return u.ok?{nodeId:i.name||i.url,snap:await u.json()}:null}finally{clearTimeout(p)}}catch{return null}}));for(let i of s)i&&n.push(i);return Bs(n)}async function Wf(t,e){let{spawn:a,execSync:n}=await import("child_process"),r,o;try{n("which journalctl",{stdio:"pipe"}),r="journalctl",o=["-u","agentx","--no-pager","-n","200","-f","-o","cat"]}catch{let u=process.env.HOME||"",m=[u&&`${u}/.agentx/logs/daemon-stdout.log`,"/tmp/agentx-daemon.log"].filter(Boolean),h=m.find(_=>Wl(_));if(!h){e.writeHead(503,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"no log source \u2014 install journalctl, run the daemon under launchd, or run it foreground writing to /tmp/agentx-daemon.log",searched:m}));return}r="tail",o=["-F","-n","200",h]}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`: source=${r}
20360
+ `),s=t.dashboard.daemonUrl.replace(/\/+$/,"")+"/task",i={"Content-Type":"application/json"};t.dashboard.token&&(i.Authorization=`Bearer ${t.dashboard.token}`);let l=await fetch(s,{method:"POST",headers:i,body:JSON.stringify({agent:n,message:o,context:{channel:"a2a",sender:"board-dashboard",systemPrompt:Uh}})});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 d=(c.content||"").toString(),p=Gh(d);if(!p||typeof p.title!="string")throw new Error("agent did not return a valid JSON draft. Raw: "+d.slice(0,400));let m=Array.isArray(p.labels)?p.labels.filter(f=>typeof f=="string"):[];return r.primaryLabel&&!m.includes(r.primaryLabel)&&m.unshift(r.primaryLabel),r.columnLabel&&!m.includes(r.columnLabel)&&m.unshift(r.columnLabel),{title:p.title.trim(),description:(p.description||"").toString(),labels:m,assigneeUsername:typeof p.assigneeUsername=="string"?p.assigneeUsername:void 0,kind:typeof p.kind=="string"?p.kind:void 0,raw:d}}function Gh(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 r=a;r<t.length;r++){let o=t[r];if(o==="{")n++;else if(o==="}"&&(n--,n===0))try{return JSON.parse(t.slice(a,r+1))}catch{return null}}return null}function Xh(t){let e=bh(xh(import.meta.url));return ct(e,t)}async function Kh(t){return gh(t)}function k(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function he(t){return new Promise((e,a)=>{let n=[];t.on("data",r=>n.push(r)),t.on("end",()=>{try{let r=Buffer.concat(n).toString("utf-8");e(r?JSON.parse(r):{})}catch(r){a(r)}}),t.on("error",a)})}function Dc(t){return t.dashboardUrl?t.dashboardUrl.replace(/\/+$/,""):t.url.replace(/\/+$/,"").replace(/:(?:1[89][89]00|18810)$/,":4202")}function D(t,e){let a=e||t,n={id:"primary",name:a.node?.name||"this daemon",dashboardUrl:"",primary:!0},r=(a.dashboard?.daemons||[]).map(s=>({id:s.url.replace(/\/+$/,""),name:s.name,dashboardUrl:Dc(s),tokenScope:s.dashboardToken||s.token?"proxy-ready":void 0})),o=r.length>0?[{id:"fleet",name:"Fleet (all peers)",dashboardUrl:"",tokenScope:"merged across nodes"}]:[];return[n,...r,...o]}async function Jh(t,e,a){let n=new URL(t.url||"/","http://_"),r=parseInt(n.searchParams.get("hours")||"6",10)||6;k(e,200,await Zt(await Hc(r,a.config)))}async function Hc(t,e){let a=e.node?.id||e.node?.name||"local",n=[],r=Za(t);r&&n.push({nodeId:a,snap:r});let o=(e.dashboard?.daemons||[]).filter(i=>i.url),s=await Promise.all(o.map(async i=>{let l=dt(i.url.replace(/\/+$/,""),e);if(!l)return null;try{let c=new AbortController,d=setTimeout(()=>c.abort(),8e3);try{let p=await fetch(`${l.url}/api/admin/activity-graph?hours=${t}`,{headers:{Accept:"application/json","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},signal:c.signal});return p.ok?{nodeId:i.name||i.url,snap:await p.json()}:null}finally{clearTimeout(d)}}catch{return null}}));for(let i of s)i&&n.push(i);return si(n)}async function Vh(t,e){let{spawn:a,execSync:n}=await import("child_process"),r,o;try{n("which journalctl",{stdio:"pipe"}),r="journalctl",o=["-u","agentx","--no-pager","-n","200","-f","-o","cat"]}catch{let p=process.env.HOME||"",m=[p&&`${p}/.agentx/logs/daemon-stdout.log`,"/tmp/agentx-daemon.log"].filter(Boolean),f=m.find(S=>$c(S));if(!f){e.writeHead(503,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"no log source \u2014 install journalctl, run the daemon under launchd, or run it foreground writing to /tmp/agentx-daemon.log",searched:m}));return}r="tail",o=["-F","-n","200",f]}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`: source=${r}
19849
20361
 
19850
- `);let s=a(r,o,{stdio:["ignore","pipe","pipe"]}),i="",l=u=>{i+=u.toString("utf8");let m;for(;(m=i.indexOf(`
19851
- `))>=0;){let h=i.slice(0,m).replace(/\r$/,"");i=i.slice(m+1);try{e.write(`event: line
19852
- data: ${h.replace(/\n/g," ")}
20362
+ `);let s=a(r,o,{stdio:["ignore","pipe","pipe"]}),i="",l=p=>{i+=p.toString("utf8");let m;for(;(m=i.indexOf(`
20363
+ `))>=0;){let f=i.slice(0,m).replace(/\r$/,"");i=i.slice(m+1);try{e.write(`event: line
20364
+ data: ${f.replace(/\n/g," ")}
19853
20365
 
19854
20366
  `)}catch{}}};s.stdout?.on("data",l),s.stderr?.on("data",l);let c=setInterval(()=>{try{e.write(`: hb
19855
20367
 
19856
- `)}catch{}},15e3),p=()=>{clearInterval(c);try{s.kill()}catch{}try{e.end()}catch{}};t.on("close",p),s.on("exit",p),s.on("error",p)}async function Ul(t,e,a,n){let r=a.url+n,o=(t.method||"GET").toUpperCase(),i=o!=="GET"&&o!=="HEAD"?await new Promise((u,m)=>{let h=[];t.on("data",_=>h.push(_)),t.on("end",()=>u(Buffer.concat(h))),t.on("error",m)}):void 0,l={},c=t.headers["content-type"];c&&(l["Content-Type"]=Array.isArray(c)?c[0]:c);let p=t.headers["x-requested-with"];p&&(l["X-Requested-With"]=Array.isArray(p)?p[0]:p),a.token&&(l.Authorization=`Bearer ${a.token}`),l["X-Agentx-Peer"]="primary";try{let u=await fetch(r,{method:o,headers:l,body:i&&i.length>0?i:void 0}),m=Buffer.from(await u.arrayBuffer());e.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json","Cache-Control":"no-store"}),e.end(m)}catch(u){y(e,502,{error:`proxy to peer failed: ${u?.message||u}`,target:r})}}function st(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(r=>r.url.replace(/\/+$/,"")===a);return n?{url:Vl(n),token:n.dashboardToken||n.token}:null}export{Cf as applyAttachSessions,wf as fetchDaemonAgents,hf as handleBoardRequest,ek as resetLiveCaches,ke as resolveNodeTargets,Zw as startBoardDashboard,Af as withLastGood};
19857
- //# sourceMappingURL=board-dashboard-RNWZ3H2T.js.map
20368
+ `)}catch{}},15e3),d=()=>{clearInterval(c);try{s.kill()}catch{}try{e.end()}catch{}};t.on("close",d),s.on("exit",d),s.on("error",d)}async function Pc(t,e,a,n){let r=a.url+n,o=(t.method||"GET").toUpperCase(),i=o!=="GET"&&o!=="HEAD"?await new Promise((p,m)=>{let f=[];t.on("data",S=>f.push(S)),t.on("end",()=>p(Buffer.concat(f))),t.on("error",m)}):void 0,l={},c=t.headers["content-type"];c&&(l["Content-Type"]=Array.isArray(c)?c[0]:c);let d=t.headers["x-requested-with"];d&&(l["X-Requested-With"]=Array.isArray(d)?d[0]:d),a.token&&(l.Authorization=`Bearer ${a.token}`),l["X-Agentx-Peer"]="primary";try{let p=await fetch(r,{method:o,headers:l,body:i&&i.length>0?i:void 0}),m=Buffer.from(await p.arrayBuffer());e.writeHead(p.status,{"Content-Type":p.headers.get("content-type")||"application/json","Cache-Control":"no-store"}),e.end(m)}catch(p){k(e,502,{error:`proxy to peer failed: ${p?.message||p}`,target:r})}}function dt(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(r=>r.url.replace(/\/+$/,"")===a);return n?{url:Dc(n),token:n.dashboardToken||n.token}:null}export{Ph as applyAttachSessions,Th as fetchDaemonAgents,yh as handleBoardRequest,T0 as resetLiveCaches,Te as resolveNodeTargets,E0 as startBoardDashboard,Rh as withLastGood};
20369
+ //# sourceMappingURL=board-dashboard-GGW5ZZLT.js.map