agentix-cli 0.26.0 → 0.27.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 (268) hide show
  1. package/dist/{App-BPNHIGUX.js → App-U52IPUK2.js} +2 -2
  2. package/dist/{ChatApp-6XSSZB4U.js → ChatApp-XP4OMHPL.js} +2 -2
  3. package/dist/agent-V2CA4TXD.js +2 -0
  4. package/dist/article-fields-L4D2BOGY.js +2 -0
  5. package/dist/article-quality-44ONVGLN.js +3 -0
  6. package/dist/article-quality-44ONVGLN.js.map +1 -0
  7. package/dist/{audit-JU3HWISB.js → audit-4245CX6P.js} +2 -2
  8. package/dist/backfill-MTD2B62I.js +6 -0
  9. package/dist/backfill-MTD2B62I.js.map +1 -0
  10. package/dist/{board-dashboard-M3372FLO.js → board-dashboard-TTMAYRLG.js} +1407 -447
  11. package/dist/board-dashboard-TTMAYRLG.js.map +1 -0
  12. package/dist/{builtin-FRKAQMFS.js → builtin-B67DMJ3M.js} +2 -2
  13. package/dist/calibration-ILS5OI44.js +2 -0
  14. package/dist/chunk-2T5W3ETS.js +5 -0
  15. package/dist/{chunk-K2CAPYES.js.map → chunk-2T5W3ETS.js.map} +1 -1
  16. package/dist/chunk-3SCPRYJB.js +5 -0
  17. package/dist/chunk-3SCPRYJB.js.map +1 -0
  18. package/dist/chunk-4BR7D2OU.js +36 -0
  19. package/dist/chunk-4BR7D2OU.js.map +1 -0
  20. package/dist/{chunk-P4VWIVKN.js → chunk-52ZPELD2.js} +403 -29
  21. package/dist/chunk-52ZPELD2.js.map +1 -0
  22. package/dist/{chunk-5U35WAZF.js → chunk-77OV7346.js} +6 -6
  23. package/dist/chunk-77OV7346.js.map +1 -0
  24. package/dist/chunk-AJ5RMU7X.js +2 -0
  25. package/dist/chunk-AJ5RMU7X.js.map +1 -0
  26. package/dist/chunk-AJONZWLT.js +2 -0
  27. package/dist/chunk-AJONZWLT.js.map +1 -0
  28. package/dist/chunk-AX2PWSRT.js +114 -0
  29. package/dist/chunk-AX2PWSRT.js.map +1 -0
  30. package/dist/chunk-BH3GTCZ6.js +2 -0
  31. package/dist/chunk-BH3GTCZ6.js.map +1 -0
  32. package/dist/chunk-BPIRO4YD.js +126 -0
  33. package/dist/chunk-BPIRO4YD.js.map +1 -0
  34. package/dist/chunk-CJQQIRPD.js +13 -0
  35. package/dist/chunk-CJQQIRPD.js.map +1 -0
  36. package/dist/chunk-DCDQZR7I.js +24 -0
  37. package/dist/chunk-DCDQZR7I.js.map +1 -0
  38. package/dist/chunk-EVWEG3VD.js +3 -0
  39. package/dist/chunk-EVWEG3VD.js.map +1 -0
  40. package/dist/chunk-F4HZTZHW.js +2 -0
  41. package/dist/chunk-F4HZTZHW.js.map +1 -0
  42. package/dist/chunk-F6CNF7V3.js +25 -0
  43. package/dist/chunk-F6CNF7V3.js.map +1 -0
  44. package/dist/chunk-FIEJDZVC.js +121 -0
  45. package/dist/chunk-FIEJDZVC.js.map +1 -0
  46. package/dist/chunk-FIOB3MEX.js +2 -0
  47. package/dist/{chunk-H5D7ATXS.js → chunk-FKBGJYWQ.js} +5 -5
  48. package/dist/chunk-FKBGJYWQ.js.map +1 -0
  49. package/dist/chunk-GDWJUGB5.js +9 -0
  50. package/dist/chunk-GDWJUGB5.js.map +1 -0
  51. package/dist/{chunk-BVGJSPW4.js → chunk-IB3F7VBE.js} +7 -7
  52. package/dist/{chunk-BVGJSPW4.js.map → chunk-IB3F7VBE.js.map} +1 -1
  53. package/dist/chunk-IBUSGCLQ.js +109 -0
  54. package/dist/chunk-IBUSGCLQ.js.map +1 -0
  55. package/dist/{chunk-LDHPMJ7M.js → chunk-IWMW5432.js} +3 -3
  56. package/dist/chunk-IWMW5432.js.map +1 -0
  57. package/dist/chunk-K33GIBSE.js +2 -0
  58. package/dist/chunk-K33GIBSE.js.map +1 -0
  59. package/dist/chunk-L2IZPR6P.js +45 -0
  60. package/dist/chunk-L2IZPR6P.js.map +1 -0
  61. package/dist/chunk-L2WSPY6S.js +2 -0
  62. package/dist/chunk-L2WSPY6S.js.map +1 -0
  63. package/dist/chunk-LCIREYTD.js +54 -0
  64. package/dist/chunk-LCIREYTD.js.map +1 -0
  65. package/dist/chunk-LNRB5MCU.js +530 -0
  66. package/dist/chunk-LNRB5MCU.js.map +1 -0
  67. package/dist/chunk-OPHIXXGI.js +157 -0
  68. package/dist/chunk-OPHIXXGI.js.map +1 -0
  69. package/dist/{chunk-JTJIPNXY.js → chunk-PNWNVOEZ.js} +1 -1
  70. package/dist/chunk-PNWNVOEZ.js.map +1 -0
  71. package/dist/{chunk-V3U4OF7L.js → chunk-UFAGYX73.js} +45 -47
  72. package/dist/chunk-UFAGYX73.js.map +1 -0
  73. package/dist/{chunk-DJEZ2HVU.js → chunk-VDMYBPYB.js} +1 -1
  74. package/dist/chunk-VDMYBPYB.js.map +1 -0
  75. package/dist/chunk-VTE7L6LO.js +5 -0
  76. package/dist/{chunk-O6YPEOQF.js.map → chunk-VTE7L6LO.js.map} +1 -1
  77. package/dist/chunk-W5C2GDNC.js +32 -0
  78. package/dist/{chunk-JP5IEXR7.js.map → chunk-W5C2GDNC.js.map} +1 -1
  79. package/dist/chunk-WPMX3VGI.js +3 -0
  80. package/dist/chunk-WPMX3VGI.js.map +1 -0
  81. package/dist/chunk-WZ72HX5C.js +1182 -0
  82. package/dist/chunk-WZ72HX5C.js.map +1 -0
  83. package/dist/chunk-ZTEU5JVQ.js +2 -0
  84. package/dist/chunk-ZTEU5JVQ.js.map +1 -0
  85. package/dist/{chunk-2WVX3LEC.js → chunk-ZVP6GB4G.js} +1 -1
  86. package/dist/chunk-ZVP6GB4G.js.map +1 -0
  87. package/dist/cli.js +1 -1
  88. package/dist/cli.js.map +1 -1
  89. package/dist/client-PX25MD47.js +2 -0
  90. package/dist/{compaction-NWEMOSHA.js → compaction-FD4R23HZ.js} +4 -4
  91. package/dist/config-HL5F36V4.js +2 -0
  92. package/dist/config-mutator-HBX53OMJ.js +2 -0
  93. package/dist/{conflict-detector-D7VIYPDI.js → conflict-detector-ZPOT3M2C.js} +2 -2
  94. package/dist/conflict-detector-ZPOT3M2C.js.map +1 -0
  95. package/dist/context-planner-AQHJMVY2.js +17 -0
  96. package/dist/context-planner-AQHJMVY2.js.map +1 -0
  97. package/dist/debug-3MEUO2P2.js +2 -0
  98. package/dist/{discover-XJXQXXIO.js → discover-D4VVRNAI.js} +2 -2
  99. package/dist/discover-D4VVRNAI.js.map +1 -0
  100. package/dist/doctor-PBAH6XL3.js +2 -0
  101. package/dist/editor-chat-OB7IQOB5.js +137 -0
  102. package/dist/editor-chat-OB7IQOB5.js.map +1 -0
  103. package/dist/entry-triage-LK34TSQD.js +2 -0
  104. package/dist/entry-triage-LK34TSQD.js.map +1 -0
  105. package/dist/facts-YVEJOM7O.js +22 -0
  106. package/dist/facts-YVEJOM7O.js.map +1 -0
  107. package/dist/heal-FVLBHYP7.js +2 -0
  108. package/dist/index.d.ts +1016 -65
  109. package/dist/index.js +13 -13
  110. package/dist/index.js.map +1 -1
  111. package/dist/{ingest-whatsapp-LZE62INA.js → ingest-whatsapp-NS4OWDOU.js} +2 -2
  112. package/dist/loader-4ZGTK7LD.js +2 -0
  113. package/dist/loader-BOKE5M5S.js +2 -0
  114. package/dist/memory-extract-F5ZHWY5E.js +2 -0
  115. package/dist/{migrate-v2-QO7SLKIM.js → migrate-v2-V4WN2VVM.js} +2 -2
  116. package/dist/ntfy-X7EPB3TG.js +4 -0
  117. package/dist/ntfy-X7EPB3TG.js.map +1 -0
  118. package/dist/processes-WU23U2OJ.js +2 -0
  119. package/dist/program-YGXVCV2Y.js +2 -0
  120. package/dist/{projects-api-KRME2YKZ.js → projects-api-QE6L65SK.js} +2 -2
  121. package/dist/{projects-mutate-3NHVG437.js → projects-mutate-MY7JTLSZ.js} +2 -2
  122. package/dist/providers-KO2DODIO.js +2 -0
  123. package/dist/query-ZKTFJMNE.js +2 -0
  124. package/dist/questions-4B4KSPXG.js +3 -0
  125. package/dist/questions-4B4KSPXG.js.map +1 -0
  126. package/dist/recipes-7S4MC5OJ.js +2 -0
  127. package/dist/registry-PSZDPFZK.js +2 -0
  128. package/dist/review-candidates-AEUXRQQC.js +4 -0
  129. package/dist/review-candidates-AEUXRQQC.js.map +1 -0
  130. package/dist/review-store-B4YE3EFK.js +4 -0
  131. package/dist/review-store-B4YE3EFK.js.map +1 -0
  132. package/dist/{rotation-memo-B3EXXSEH.js → rotation-memo-7T75BLEX.js} +2 -2
  133. package/dist/routing-4PV66BK6.js +2 -0
  134. package/dist/routing-4PV66BK6.js.map +1 -0
  135. package/dist/runner-YRBVNYTY.js +2 -0
  136. package/dist/scheduler-GZZAN6ZG.js +2 -0
  137. package/dist/seat-VZ7AVO27.js +2 -0
  138. package/dist/select-F5I5PO2O.js +2 -0
  139. package/dist/select-F5I5PO2O.js.map +1 -0
  140. package/dist/store-MCOA6N4F.js +2 -0
  141. package/dist/{subagent-WV7QKQ3L.js → subagent-2SJHSSJS.js} +2 -2
  142. package/dist/{surface-usage-PRL6Z4U3.js → surface-usage-NS74AXSE.js} +2 -2
  143. package/dist/timers-PCB4ZIBD.js +2 -0
  144. package/dist/triage-backtest-JNO7RKX7.js +2 -0
  145. package/dist/triage-backtest-JNO7RKX7.js.map +1 -0
  146. package/dist/types-H5ENIUIT.js +2 -0
  147. package/dist/types-OIFU3KSQ.js +2 -0
  148. package/dist/web/workflow-editor.global.js +1542 -0
  149. package/dist/web/workflow-editor.global.js.map +1 -0
  150. package/dist/{whatsapp-state-XMTCSRXU.js → whatsapp-state-6D6FHHD2.js} +2 -2
  151. package/dist/wiki-N5SMP3DT.js +2 -0
  152. package/dist/wiki-N5SMP3DT.js.map +1 -0
  153. package/dist/workflows/templates/branching.yaml +1 -1
  154. package/dist/{workspace-setup-TBQAHYHJ.js → workspace-setup-B3F3TUDE.js} +2 -2
  155. package/dist/workspace-setup-B3F3TUDE.js.map +1 -0
  156. package/package.json +1 -1
  157. package/dist/agent-5QMITZT6.js +0 -2
  158. package/dist/architect-SEPWMWS4.js +0 -2
  159. package/dist/board-dashboard-M3372FLO.js.map +0 -1
  160. package/dist/chunk-2WVX3LEC.js.map +0 -1
  161. package/dist/chunk-3WQFCIB6.js +0 -24
  162. package/dist/chunk-3WQFCIB6.js.map +0 -1
  163. package/dist/chunk-4YCH6IZV.js +0 -2
  164. package/dist/chunk-53NRX2NA.js +0 -2
  165. package/dist/chunk-53NRX2NA.js.map +0 -1
  166. package/dist/chunk-5U35WAZF.js.map +0 -1
  167. package/dist/chunk-BFXONUUN.js +0 -108
  168. package/dist/chunk-BFXONUUN.js.map +0 -1
  169. package/dist/chunk-BFZUG66X.js +0 -45
  170. package/dist/chunk-BFZUG66X.js.map +0 -1
  171. package/dist/chunk-BTHHSY7D.js +0 -13
  172. package/dist/chunk-BTHHSY7D.js.map +0 -1
  173. package/dist/chunk-D46VZ7K7.js +0 -116
  174. package/dist/chunk-D46VZ7K7.js.map +0 -1
  175. package/dist/chunk-DJEZ2HVU.js.map +0 -1
  176. package/dist/chunk-E5CXCI33.js +0 -155
  177. package/dist/chunk-E5CXCI33.js.map +0 -1
  178. package/dist/chunk-FDWOECJY.js +0 -54
  179. package/dist/chunk-FDWOECJY.js.map +0 -1
  180. package/dist/chunk-H5D7ATXS.js.map +0 -1
  181. package/dist/chunk-HR4JSRZS.js +0 -3
  182. package/dist/chunk-HR4JSRZS.js.map +0 -1
  183. package/dist/chunk-ISEBLHWX.js +0 -118
  184. package/dist/chunk-ISEBLHWX.js.map +0 -1
  185. package/dist/chunk-JP5IEXR7.js +0 -32
  186. package/dist/chunk-JTJIPNXY.js.map +0 -1
  187. package/dist/chunk-K2CAPYES.js +0 -5
  188. package/dist/chunk-LDHPMJ7M.js.map +0 -1
  189. package/dist/chunk-METYYZKQ.js +0 -1115
  190. package/dist/chunk-METYYZKQ.js.map +0 -1
  191. package/dist/chunk-MTAPOCGA.js +0 -47
  192. package/dist/chunk-MTAPOCGA.js.map +0 -1
  193. package/dist/chunk-O6YPEOQF.js +0 -5
  194. package/dist/chunk-P4VWIVKN.js.map +0 -1
  195. package/dist/chunk-SR3X25TN.js +0 -3
  196. package/dist/chunk-SR3X25TN.js.map +0 -1
  197. package/dist/chunk-UHE5FCPB.js +0 -431
  198. package/dist/chunk-UHE5FCPB.js.map +0 -1
  199. package/dist/chunk-V3U4OF7L.js.map +0 -1
  200. package/dist/chunk-VJUTQAPJ.js +0 -2
  201. package/dist/chunk-VJUTQAPJ.js.map +0 -1
  202. package/dist/chunk-VT5XYFDD.js +0 -126
  203. package/dist/chunk-VT5XYFDD.js.map +0 -1
  204. package/dist/client-HGKAC6VP.js +0 -2
  205. package/dist/config-A4RWEJHV.js +0 -2
  206. package/dist/config-mutator-MNSFUN7D.js +0 -2
  207. package/dist/conflict-detector-D7VIYPDI.js.map +0 -1
  208. package/dist/context-planner-45GEWKGL.js +0 -17
  209. package/dist/context-planner-45GEWKGL.js.map +0 -1
  210. package/dist/debug-N3B5NVJU.js +0 -2
  211. package/dist/discover-XJXQXXIO.js.map +0 -1
  212. package/dist/doctor-3Q36ZFE6.js +0 -2
  213. package/dist/heal-HZ3EQD52.js +0 -2
  214. package/dist/loader-5CA3O5GM.js +0 -2
  215. package/dist/loader-6IHUCPVO.js +0 -2
  216. package/dist/memory-extract-AENFVVO5.js +0 -2
  217. package/dist/processes-UIC4XXA6.js +0 -2
  218. package/dist/program-SAUNRCCD.js +0 -2
  219. package/dist/providers-L27BJ5A6.js +0 -2
  220. package/dist/query-HZYYRCLU.js +0 -2
  221. package/dist/recipes-EPLE2SNT.js +0 -2
  222. package/dist/registry-HK3WQ7BS.js +0 -2
  223. package/dist/runner-BFYDWPUO.js +0 -2
  224. package/dist/scheduler-6T2SU5ST.js +0 -2
  225. package/dist/store-I3HEWVLQ.js +0 -2
  226. package/dist/timers-5LPZN55J.js +0 -2
  227. package/dist/types-VECTMYTO.js +0 -2
  228. package/dist/types-Y6ZCZ52Z.js +0 -2
  229. package/dist/wiki-M6YNRFC4.js +0 -2
  230. /package/dist/{App-BPNHIGUX.js.map → App-U52IPUK2.js.map} +0 -0
  231. /package/dist/{ChatApp-6XSSZB4U.js.map → ChatApp-XP4OMHPL.js.map} +0 -0
  232. /package/dist/{agent-5QMITZT6.js.map → agent-V2CA4TXD.js.map} +0 -0
  233. /package/dist/{architect-SEPWMWS4.js.map → article-fields-L4D2BOGY.js.map} +0 -0
  234. /package/dist/{audit-JU3HWISB.js.map → audit-4245CX6P.js.map} +0 -0
  235. /package/dist/{builtin-FRKAQMFS.js.map → builtin-B67DMJ3M.js.map} +0 -0
  236. /package/dist/{chunk-4YCH6IZV.js.map → calibration-ILS5OI44.js.map} +0 -0
  237. /package/dist/{client-HGKAC6VP.js.map → chunk-FIOB3MEX.js.map} +0 -0
  238. /package/dist/{config-A4RWEJHV.js.map → client-PX25MD47.js.map} +0 -0
  239. /package/dist/{compaction-NWEMOSHA.js.map → compaction-FD4R23HZ.js.map} +0 -0
  240. /package/dist/{config-mutator-MNSFUN7D.js.map → config-HL5F36V4.js.map} +0 -0
  241. /package/dist/{debug-N3B5NVJU.js.map → config-mutator-HBX53OMJ.js.map} +0 -0
  242. /package/dist/{doctor-3Q36ZFE6.js.map → debug-3MEUO2P2.js.map} +0 -0
  243. /package/dist/{heal-HZ3EQD52.js.map → doctor-PBAH6XL3.js.map} +0 -0
  244. /package/dist/{loader-5CA3O5GM.js.map → heal-FVLBHYP7.js.map} +0 -0
  245. /package/dist/{ingest-whatsapp-LZE62INA.js.map → ingest-whatsapp-NS4OWDOU.js.map} +0 -0
  246. /package/dist/{loader-6IHUCPVO.js.map → loader-4ZGTK7LD.js.map} +0 -0
  247. /package/dist/{memory-extract-AENFVVO5.js.map → loader-BOKE5M5S.js.map} +0 -0
  248. /package/dist/{processes-UIC4XXA6.js.map → memory-extract-F5ZHWY5E.js.map} +0 -0
  249. /package/dist/{migrate-v2-QO7SLKIM.js.map → migrate-v2-V4WN2VVM.js.map} +0 -0
  250. /package/dist/{program-SAUNRCCD.js.map → processes-WU23U2OJ.js.map} +0 -0
  251. /package/dist/{providers-L27BJ5A6.js.map → program-YGXVCV2Y.js.map} +0 -0
  252. /package/dist/{projects-api-KRME2YKZ.js.map → projects-api-QE6L65SK.js.map} +0 -0
  253. /package/dist/{projects-mutate-3NHVG437.js.map → projects-mutate-MY7JTLSZ.js.map} +0 -0
  254. /package/dist/{query-HZYYRCLU.js.map → providers-KO2DODIO.js.map} +0 -0
  255. /package/dist/{recipes-EPLE2SNT.js.map → query-ZKTFJMNE.js.map} +0 -0
  256. /package/dist/{registry-HK3WQ7BS.js.map → recipes-7S4MC5OJ.js.map} +0 -0
  257. /package/dist/{runner-BFYDWPUO.js.map → registry-PSZDPFZK.js.map} +0 -0
  258. /package/dist/{rotation-memo-B3EXXSEH.js.map → rotation-memo-7T75BLEX.js.map} +0 -0
  259. /package/dist/{scheduler-6T2SU5ST.js.map → runner-YRBVNYTY.js.map} +0 -0
  260. /package/dist/{store-I3HEWVLQ.js.map → scheduler-GZZAN6ZG.js.map} +0 -0
  261. /package/dist/{surface-usage-PRL6Z4U3.js.map → seat-VZ7AVO27.js.map} +0 -0
  262. /package/dist/{timers-5LPZN55J.js.map → store-MCOA6N4F.js.map} +0 -0
  263. /package/dist/{subagent-WV7QKQ3L.js.map → subagent-2SJHSSJS.js.map} +0 -0
  264. /package/dist/{types-VECTMYTO.js.map → surface-usage-NS74AXSE.js.map} +0 -0
  265. /package/dist/{types-Y6ZCZ52Z.js.map → timers-PCB4ZIBD.js.map} +0 -0
  266. /package/dist/{wiki-M6YNRFC4.js.map → types-H5ENIUIT.js.map} +0 -0
  267. /package/dist/{workspace-setup-TBQAHYHJ.js.map → types-OIFU3KSQ.js.map} +0 -0
  268. /package/dist/{whatsapp-state-XMTCSRXU.js.map → whatsapp-state-6D6FHHD2.js.map} +0 -0
@@ -1,7 +1,1019 @@
1
- import{a as kt}from"./chunk-H5D7ATXS.js";import{a as C,b as _t,c as Et,d as St,e as Tt,f as Z,g as me,h as Oe,i as At}from"./chunk-V3U4OF7L.js";import{a as Ct}from"./chunk-UCQ2N3KO.js";import{a as M,b as D,g as Te,h as Ce,i as X,j as N,k as Ae,l as bt,m as yt,n as wt}from"./chunk-P4VWIVKN.js";import{e as gt,g as de,h as we,i as ke,j as _e,k as Ee,l as ft,m as xt,n as vt,o as Se}from"./chunk-3WQFCIB6.js";import{a as nt,e as rt,f as ot,g as st,s as ye,u as dt,v as ct,w as Pe,x as pt,y as ut}from"./chunk-MTAPOCGA.js";import"./chunk-M4AMWP3H.js";import{a as mt,b as ht}from"./chunk-LDHPMJ7M.js";import"./chunk-AFRHKA7B.js";import"./chunk-D46VZ7K7.js";import"./chunk-K2CAPYES.js";import{a as it,b as lt,f as G}from"./chunk-BTHHSY7D.js";import{a as ve,b as be}from"./chunk-ISEBLHWX.js";import{b as at}from"./chunk-BFXONUUN.js";import"./chunk-JTJIPNXY.js";import"./chunk-64P4QHSZ.js";import"./chunk-FDWOECJY.js";import"./chunk-VJUTQAPJ.js";import"./chunk-QOYAX2FT.js";import"./chunk-4YCH6IZV.js";import{createServer as qo}from"http";import{appendFileSync as Uo,existsSync as Fa,mkdirSync as Fo}from"fs";import{readFile as Wo}from"fs/promises";import{fileURLToPath as Go}from"url";import{dirname as Xo,resolve as xe}from"path";var Mt='/*! 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 Me,readFileSync as $t,writeFileSync as jt,rmSync as ws,mkdirSync as Za,copyFileSync as en,readdirSync as tn}from"fs";import{resolve as ce}from"path";var J={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 It(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=Te({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.`})+Ce([{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">');return M({title:"AgentX \xB7 Settings",activeTab:"admin",subtitle:"Settings",peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a+Ja()+bt,css:Ya,scripts:`${e}<script>${yt}
2
- ${wt}
3
- ${Ka}
4
- ${Qa}</script>`})}var Ka=`
1
+ import{a as Lt}from"./chunk-FKBGJYWQ.js";import{a as T,b as Rt,c as Pt,d as Dt,e as Ot,f as ee,g as ve,h as Fe,i as Nt}from"./chunk-UFAGYX73.js";import{a as Ht}from"./chunk-UCQ2N3KO.js";import{a as me,c as C,d as P,i as Ae,j as Me,k as X,l as N,m as Ie,n as It,o as $t,p as jt}from"./chunk-52ZPELD2.js";import{a as kt,c as qe,d as Ue,e as _t,m as Tt,o as ue,p as _e,q as Ee,r as Se,s as Te,t as Ct,u as At,v as Mt,w as Ce}from"./chunk-F6CNF7V3.js";import{g as yt,h as wt}from"./chunk-DCDQZR7I.js";import{a as Et,b as St}from"./chunk-IWMW5432.js";import{a as ft,b as Be,c as ze,g as xt,h as vt,i as bt}from"./chunk-GDWJUGB5.js";import"./chunk-M4AMWP3H.js";import"./chunk-4BR7D2OU.js";import"./chunk-AFRHKA7B.js";import"./chunk-FIEJDZVC.js";import"./chunk-2T5W3ETS.js";import{b as gt}from"./chunk-IBUSGCLQ.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-AJ5RMU7X.js";import"./chunk-EVWEG3VD.js";import"./chunk-AX2PWSRT.js";import"./chunk-AJONZWLT.js";import"./chunk-F4HZTZHW.js";import"./chunk-ZTEU5JVQ.js";import"./chunk-QOYAX2FT.js";import"./chunk-LCIREYTD.js";import"./chunk-L2WSPY6S.js";import{a as mt,b as ht,c as cn,g as G,j as Ne}from"./chunk-CJQQIRPD.js";import"./chunk-BH3GTCZ6.js";import"./chunk-FIOB3MEX.js";function We(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 Bt(t,e,a=Date.now()){return t.map((n,r)=>({i:r,s:We(n,e,a).score})).sort((n,r)=>r.s-n.s||n.i-r.i).map(n=>n.i)}var K={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"/>'},le=(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>",$e=(t,e,a,n="")=>'<div class="ax-sec-label"><h3>'+le(t,13)+e+(a?'<span class="ax-sec-label__n" id="'+a+'"></span>':"")+"</h3>"+n+"</div>";function zt(t={}){return C({title:"AgentX \xB7 Monitor",activeTab:"monitor",subtitle:"Monitor",peers:t.peers,body:`<div class="bf">
2
+
3
+ <div class="bf-head">
4
+ <div>
5
+ <span class="bf-kicker">Your attention, protected</span>
6
+ <h1>What needs you.</h1>
7
+ </div>
8
+ <div class="bf-sync">
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">${le(K.pulse,13)} Activity</a>
11
+ <button class="ax-btn" id="refresh" title="Refresh now">${le(K.refresh)} Refresh</button>
12
+ </div>
13
+ </div>
14
+
15
+ <p id="coverage" class="bf-sr" role="status">Gathering session reviews across your mesh&hellip;</p>
16
+ <div class="bf-strip" id="strip"></div>
17
+ <div id="coverage-note"></div>
18
+ <div id="principals"></div>
19
+
20
+ <p id="notice" role="status" aria-live="polite"></p>
21
+
22
+ <div class="bf-grid">
23
+ <section class="bf-col">
24
+ ${$e(K.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
+ <div id="you" class="bf-col"></div>
26
+
27
+ ${$e(K.plug,"Agents can handle","agents-count",'<span class="bf-why">no human needed &mdash; not yet automatic</span>')}
28
+ <div id="agents" class="bf-col"></div>
29
+ <button class="ax-btn ax-btn--sm" id="more-actions" hidden></button>
30
+
31
+ <div id="handled"></div>
32
+ </section>
33
+ <aside class="bf-col">
34
+ ${$e(K.pulse,"In motion","run-count")}
35
+ <div id="running" class="bf-col"></div>
36
+ </aside>
37
+ </div>
38
+
39
+ ${$e(K.file,"Session briefings","brief-count")}
40
+ <div class="bf-toolbar">
41
+ <div class="bf-search">${le(K.search)}
42
+ <input id="search" type="search" placeholder="Search sessions&hellip;" aria-label="Search sessions">
43
+ </div>
44
+ <div class="bf-filters" id="filters" role="group" aria-label="Filter briefings"></div>
45
+ </div>
46
+ <div id="reviews" class="bf-col"></div>
47
+
48
+ <section class="ax-panel bf-connect">
49
+ <div class="bf-connect__head">${le(K.plug,17)}<h2>Connect a CLI session</h2>
50
+ <span class="bf-connect__note">Daemon-owned processes only</span></div>
51
+ <div class="bf-discover">
52
+ <div class="ax-field"><label for="node">Node</label><select id="node"></select></div>
53
+ <button class="ax-btn" id="discover">${le(K.search)} Discover CLIs</button>
54
+ </div>
55
+ <div class="bf-cli" id="discovered"></div>
56
+ <details class="bf-manual">
57
+ <summary>${le(K.chev,12)} Register manually</summary>
58
+ <div class="bf-forms">
59
+ <form id="register" class="bf-form">
60
+ <div class="ax-sec-label"><h3>Register a session</h3></div>
61
+ <div class="bf-form__row">
62
+ <div class="ax-field"><label for="r-id">Session ID</label>
63
+ <input id="r-id" name="id" required maxlength="200"></div>
64
+ <div class="ax-field"><label for="r-rt">Runtime</label>
65
+ <select id="r-rt" name="runtime"><option>claude</option><option>codex</option>
66
+ <option>gemini</option><option>opencode</option><option>other</option></select></div>
67
+ </div>
68
+ <div class="ax-field"><label for="r-lb">Label</label>
69
+ <input id="r-lb" name="label" required maxlength="200"></div>
70
+ <button class="ax-btn ax-btn--primary">Register session</button>
71
+ </form>
72
+ <form id="ended" class="bf-form">
73
+ <div class="ax-sec-label"><h3>Submit an ended run</h3></div>
74
+ <div class="bf-form__row">
75
+ <div class="ax-field"><label for="registered">Registered session</label>
76
+ <select id="registered" name="sessionId" required></select></div>
77
+ <div class="ax-field"><label for="e-run">Run ID</label>
78
+ <input id="e-run" name="runId" required maxlength="200" placeholder="unique per turn"></div>
79
+ </div>
80
+ <div class="ax-field"><label for="e-tr">Run transcript</label>
81
+ <textarea id="e-tr" name="transcript" required maxlength="100000" rows="3"
82
+ placeholder="Last 90 KB is submitted"></textarea></div>
83
+ <button class="ax-btn ax-btn--primary">Review ended run</button>
84
+ </form>
85
+ </div>
86
+ </details>
87
+ </section>
88
+ </div>`,css:pn,scripts:`<script>${me({decayOf:We,rankByDecay:Bt})}const ICON = ${JSON.stringify(K)};${un}</script>`})}var pn=`
89
+ .bf{max-width:1240px;margin:0 auto;padding:22px 24px 48px}
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
+ .bf :focus-visible{outline:2px solid var(--ax-accent);outline-offset:2px;border-radius:4px}
92
+
93
+ /* Page head */
94
+ .bf-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:16px}
95
+ .bf-kicker{display:inline-block;font-size:10px;letter-spacing:0.1em;color:var(--ax-muted);
96
+ text-transform:uppercase;margin-bottom:6px;font-family:var(--ax-mono)}
97
+ .bf h1{font-size:22px;font-weight:600;letter-spacing:-0.015em;margin:0}
98
+ .bf-sync{display:flex;align-items:center;gap:12px;flex-shrink:0}
99
+ .bf-sync__t{font-size:11px;color:var(--ax-muted);font-family:var(--ax-mono);text-align:right;line-height:1.5}
100
+ .bf .ax-btn{display:inline-flex;align-items:center;gap:7px}
101
+ .bf .ax-btn--sm{padding:5px 12px;font-size:var(--ax-fs-sm);border-radius:var(--ax-radius-sm)}
102
+
103
+ /* Coverage counters */
104
+ .bf-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:16px}
105
+ .bf-si--warn .ax-stat-inline__icon{background:color-mix(in oklch,var(--ax-warn) 14%,var(--ax-surface-2));color:var(--ax-warn)}
106
+ .bf-si--warn .ax-stat-inline__v{color:var(--ax-warn)}
107
+ .bf-si--err .ax-stat-inline__icon{background:color-mix(in oklch,var(--ax-err) 14%,var(--ax-surface-2));color:var(--ax-err)}
108
+ .bf-si--err .ax-stat-inline__v{color:var(--ax-err)}
109
+ #coverage-note:not(:empty){margin-bottom:16px}
110
+ .bf-callout--err{border-color:color-mix(in oklch,var(--ax-err) 30%,var(--ax-border));
111
+ background:color-mix(in oklch,var(--ax-err) 5%,var(--ax-bg-elev))}
112
+ .bf-callout--err .ax-callout__icon{background:color-mix(in oklch,var(--ax-err) 18%,transparent);color:var(--ax-err)}
113
+
114
+ #notice{margin:0 0 14px;font-size:12.5px;color:var(--ax-text-2)}
115
+ #notice:not(:empty){padding:9px 13px;border-radius:var(--ax-radius-sm);background:var(--ax-surface-2);
116
+ border:var(--ax-border-w) solid var(--ax-border)}
117
+
118
+ /* Cost of delay \u2014 replaces the old minutes estimate */
119
+ .bf-cost{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
120
+ color:var(--ax-text-2)}
121
+ .bf-cost--rise{color:var(--ax-err)}
122
+ .bf-cost--rise.is-over{padding:2px 9px;border-radius:var(--ax-radius-pill);
123
+ background:color-mix(in oklch,var(--ax-err) 9%,var(--ax-surface));
124
+ border:1px solid color-mix(in oklch,var(--ax-err) 32%,var(--ax-border))}
125
+ .bf-act.is-snoozed{opacity:0.62}
126
+ .bf-why{font-size:12px;color:var(--ax-text-2);font-weight:400;margin-left:2px}
127
+ .ax-sec-label h3 .bf-why{margin-left:8px}
128
+ /* The hint wraps under the heading on a narrow column instead of running
129
+ beneath the button that used to sit on top of it. */
130
+ .bf .ax-sec-label{flex-wrap:wrap;gap:8px 12px;align-items:baseline}
131
+ .bf .ax-sec-label h3{flex-wrap:wrap;row-gap:2px;min-width:0}
132
+ .bf .ax-sec-label h3 .bf-why{flex:1 1 260px;min-width:0;white-space:normal}
133
+ #clear-actions{flex:none;margin-left:auto}
134
+
135
+ /* Handled \u2014 a count, not a list: it shows the backlog moving, nothing to decide */
136
+ .bf-done{display:flex;align-items:center;gap:10px;margin-top:14px;padding:11px 15px;
137
+ border-radius:var(--ax-radius-lg);border:var(--ax-border-w) solid var(--ax-border);
138
+ background:var(--ax-surface-2);font-size:12.5px;color:var(--ax-text-2)}
139
+ .bf-done b{font-family:var(--ax-mono);font-size:15px;color:var(--ax-text);font-weight:600}
140
+ .bf-done svg{color:var(--ax-ok);flex:none}
141
+ .bf-done span{margin-left:auto}
142
+
143
+ /* Principals */
144
+ .bf-pr{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:14px}
145
+ .bf-pr__c{min-width:0}
146
+ .bf-pr__n,.bf-pr__k,.bf-pr__o{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
147
+ .bf-pr__c{display:flex;flex-direction:column;gap:4px;text-align:left;font:inherit;cursor:pointer;
148
+ background:var(--ax-surface);border:var(--ax-border-w) solid var(--ax-border);
149
+ border-radius:var(--ax-radius-lg);box-shadow:var(--ax-shadow);padding:11px 14px;color:var(--ax-text)}
150
+ .bf-pr__c:hover{background:var(--ax-surface-2)}
151
+ .bf-pr__c.is-on{border-color:var(--ax-accent);box-shadow:var(--ax-shadow-accent)}
152
+ .bf-pr__c--client{border-left:4px solid var(--ax-accent)}
153
+ .bf-pr__n{font-size:13.5px;font-weight:600;letter-spacing:-0.005em}
154
+ .bf-pr__k{font-size:10.5px;color:var(--ax-text-2);font-family:var(--ax-mono)}
155
+ .bf-pr__s{display:flex;align-items:baseline;gap:8px;font-size:11.5px;color:var(--ax-text-2);margin-top:3px}
156
+ .bf-pr__s b{font-family:var(--ax-mono);font-size:17px;font-weight:600;color:var(--ax-text-2)}
157
+ .bf-pr__s b.bf-pr__you{color:var(--ax-err)}
158
+ .bf-pr__s i{font-style:normal}
159
+ .bf-pr__o{font-size:10.5px;color:var(--ax-text-2)}
160
+
161
+ /* Triage columns */
162
+ .bf-grid{display:grid;grid-template-columns:minmax(0,2fr) minmax(300px,1fr);gap:22px;
163
+ align-items:flex-start;margin-bottom:24px}
164
+ .bf-col{display:flex;flex-direction:column;gap:10px;min-width:0}
165
+ .bf .ax-sec-label h3{display:flex;align-items:center;gap:8px}
166
+ .ax-sec-label__n{font-family:var(--ax-mono);font-size:11px;padding:1px 7px;border-radius:var(--ax-radius);
167
+ background:var(--ax-surface-3);color:var(--ax-text-2);letter-spacing:0}
168
+ .ax-sec-label__n:empty{display:none}
169
+
170
+ /* --- Identity: who, and where ------------------------------------------
171
+ Every card leads with the agent avatar and a row of place tags, so the
172
+ question "who did this, and where" is answered before any prose. */
173
+ .bf-id{display:flex;align-items:center;gap:11px;min-width:0}
174
+ .bf-id .ax-avatar{width:32px;height:32px;font-size:12px;text-transform:uppercase}
175
+ .bf-who{flex:1;min-width:0}
176
+ .bf-who__n{font-size:13.5px;font-weight:600;letter-spacing:-0.005em;display:flex;align-items:center;
177
+ gap:7px;flex-wrap:wrap}
178
+ .bf-where{display:flex;align-items:center;gap:5px;flex-wrap:wrap;margin-top:3px}
179
+ .bf-tag{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-family:var(--ax-mono);
180
+ color:var(--ax-muted);background:var(--ax-surface-2);border:1px solid var(--ax-border);
181
+ border-radius:var(--ax-radius-pill);padding:1px 8px;line-height:16px;max-width:100%;
182
+ overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
183
+ button.bf-tag{cursor:pointer;font-weight:600}
184
+ button.bf-tag:hover{border-color:var(--ax-accent);color:var(--ax-accent)}
185
+ button.bf-tag.is-on{background:color-mix(in oklch,var(--ax-accent) 14%,transparent);
186
+ border-color:color-mix(in oklch,var(--ax-accent) 35%,transparent);color:var(--ax-accent)}
187
+ .bf-tag svg{flex-shrink:0}
188
+ .bf-time{font-size:10.5px;color:var(--ax-muted);font-family:var(--ax-mono);white-space:nowrap;
189
+ align-self:flex-start;padding-top:2px}
190
+
191
+ /* --- Quick links: always visible, never buried in a disclosure --------- */
192
+ .bf-links{display:flex;gap:6px;flex-wrap:wrap}
193
+ .bf-lnk{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
194
+ padding:4px 10px;border-radius:var(--ax-radius-sm);border:var(--ax-border-w) solid var(--ax-border);
195
+ background:var(--ax-surface-2);color:var(--ax-text-2);text-decoration:none;max-width:320px;
196
+ overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
197
+ .bf-lnk:hover{border-color:var(--ax-accent);color:var(--ax-accent);text-decoration:none}
198
+ .bf-lnk svg{flex-shrink:0;opacity:0.75}
199
+ .bf-lnk--go{color:var(--ax-accent);border-color:color-mix(in oklch,var(--ax-accent) 32%,var(--ax-border));
200
+ background:color-mix(in oklch,var(--ax-accent) 8%,transparent)}
201
+
202
+ /* Action card */
203
+ .bf-act{background:var(--ax-surface);border:var(--ax-border-w) solid var(--ax-border);
204
+ border-radius:var(--ax-radius-lg);padding:14px 16px;box-shadow:var(--ax-shadow);
205
+ display:flex;flex-direction:column;gap:10px}
206
+ .bf-act--now{border-color:color-mix(in oklch,var(--ax-warn) 34%,var(--ax-border))}
207
+ .bf-act__cost{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--ax-text-2);
208
+ font-family:var(--ax-mono)}
209
+ .bf-act__cost svg{color:var(--ax-muted)}
210
+ /* One job, re-derived by N session reviews. Marking it done clears all N. */
211
+ .bf-dupe{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
212
+ padding:2px 9px;border-radius:var(--ax-radius-pill);color:var(--ax-red);
213
+ background:color-mix(in oklch,var(--ax-err) 8%,var(--ax-surface));
214
+ border:1px solid color-mix(in oklch,var(--ax-err) 30%,var(--ax-border))}
215
+ .bf-eff{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--ax-muted)}
216
+ .bf-eff i{width:4px;height:10px;border-radius:1px;background:var(--ax-border-2);display:block}
217
+ .bf-eff--low i:nth-child(1),.bf-eff--medium i:nth-child(-n+2),.bf-eff--high i{background:var(--ax-text-2)}
218
+ .bf-act__text{font-size:var(--ax-fs);line-height:1.55;color:var(--ax-text);overflow-wrap:anywhere;margin:0}
219
+ .bf-act__foot{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
220
+ .bf-why{margin-top:2px}
221
+ .bf-why summary{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;color:var(--ax-muted);
222
+ cursor:pointer;list-style:none;font-weight:600}
223
+ .bf-why summary::-webkit-details-marker{display:none}
224
+ .bf-why[open] summary svg{transform:rotate(180deg)}
225
+ .bf-ev{margin:8px 0 0;font-size:12px;line-height:1.6;color:var(--ax-text-2);
226
+ border-left:2px solid var(--ax-border-2);padding-left:12px;overflow-wrap:anywhere}
227
+
228
+ /* Deferred band */
229
+ .bf-defer{background:var(--ax-surface-2);border:var(--ax-border-w) solid var(--ax-border);
230
+ border-radius:var(--ax-radius-lg);padding:12px 16px;display:flex;align-items:center;gap:10px;
231
+ flex-wrap:wrap;cursor:pointer}
232
+ .bf-defer:hover{border-color:var(--ax-border-2)}
233
+ .bf-defer__t{font-size:var(--ax-fs-sm);font-weight:600;color:var(--ax-text-2)}
234
+ .bf-defer__n{margin-left:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
235
+ .bf-defer svg{color:var(--ax-muted);transition:transform 140ms ease}
236
+ #later{margin-top:10px}
237
+ #more-actions{align-self:flex-start;margin-top:10px}
238
+
239
+ /* In motion */
240
+ .bf-run{background:var(--ax-surface);border:var(--ax-border-w) solid var(--ax-border);
241
+ border-radius:var(--ax-radius-sm);padding:11px 13px;display:flex;flex-direction:column;gap:8px}
242
+ .bf-run__dot{width:7px;height:7px;border-radius:50%;background:var(--ax-accent);flex-shrink:0;
243
+ box-shadow:0 0 0 3px color-mix(in oklch,var(--ax-accent) 18%,transparent)}
244
+ .bf-run__msg{font-size:12.5px;line-height:1.5;color:var(--ax-text-2);margin:0;overflow:hidden;
245
+ display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
246
+
247
+ /* Briefings toolbar + filters */
248
+ .bf-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}
249
+ .bf-search{position:relative;flex:0 1 300px}
250
+ .bf-search svg{position:absolute;left:12px;top:50%;transform:translateY(-50%);color:var(--ax-muted);
251
+ pointer-events:none}
252
+ .bf-search input{width:100%;background:var(--ax-surface);color:var(--ax-text);
253
+ border:var(--ax-border-w) solid var(--ax-border-2);border-radius:var(--ax-radius);
254
+ padding:8px 14px 8px 34px;font:inherit;font-size:var(--ax-fs-sm)}
255
+ .bf-filters{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
256
+ .bf-filter{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:600;
257
+ padding:5px 11px;border-radius:var(--ax-radius-pill);border:var(--ax-border-w) solid var(--ax-border);
258
+ background:var(--ax-surface);color:var(--ax-text-2);cursor:pointer;font-family:inherit}
259
+ .bf-filter:hover{border-color:var(--ax-border-2);color:var(--ax-text)}
260
+ .bf-filter.is-on{background:color-mix(in oklch,var(--ax-accent) 14%,var(--ax-surface));
261
+ border-color:color-mix(in oklch,var(--ax-accent) 40%,var(--ax-border));color:var(--ax-accent)}
262
+ .bf-filter__n{font-family:var(--ax-mono);font-size:10px;opacity:0.8}
263
+ .bf-filter--clear{color:var(--ax-muted);border-style:dashed}
264
+
265
+ /* Briefing card */
266
+ .bf-brief{background:var(--ax-surface);border:var(--ax-border-w) solid var(--ax-border);
267
+ border-radius:var(--ax-radius-lg);padding:14px 16px;box-shadow:var(--ax-shadow);
268
+ display:flex;flex-direction:column;gap:10px}
269
+ .bf-brief--failed{border-color:color-mix(in oklch,var(--ax-err) 30%,var(--ax-border))}
270
+ .bf-brief__top{display:flex;align-items:flex-start;gap:10px}
271
+ .bf-brief__sum{font-size:13px;line-height:1.6;color:var(--ax-text);margin:0;overflow-wrap:anywhere}
272
+ .bf-brief__fail{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
273
+ .bf-brief__fail .bf-brief__sum{flex:1;min-width:220px;color:var(--ax-text-2)}
274
+
275
+ /* Finding chips */
276
+ .bf-finds{display:flex;gap:6px;flex-wrap:wrap}
277
+ .bf-find{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:600;padding:3px 9px;
278
+ border-radius:var(--ax-radius-pill);border:var(--ax-border-w) solid var(--ax-border);
279
+ background:var(--ax-surface-2);color:var(--ax-muted)}
280
+ .bf-find--warn{color:var(--ax-warn);background:color-mix(in oklch,var(--ax-warn) 12%,transparent);
281
+ border-color:color-mix(in oklch,var(--ax-warn) 32%,transparent)}
282
+ .bf-find--info{color:var(--ax-info);background:color-mix(in oklch,var(--ax-info) 12%,transparent);
283
+ border-color:color-mix(in oklch,var(--ax-info) 32%,transparent)}
284
+ .bf-find--zero{display:none}
285
+ .bf-brief details>summary{cursor:pointer;font-size:11.5px;color:var(--ax-muted);font-weight:600;
286
+ list-style:none;display:inline-flex;align-items:center;gap:5px}
287
+ .bf-brief details>summary::-webkit-details-marker{display:none}
288
+ .bf-brief details[open]>summary svg{transform:rotate(180deg)}
289
+ .bf-detail{border-top:1px dashed var(--ax-border);margin-top:10px;padding-top:12px;
290
+ display:flex;flex-direction:column;gap:13px}
291
+ .bf-fgroup h4{margin:0 0 7px;font-size:10.5px;font-family:var(--ax-mono);text-transform:uppercase;
292
+ letter-spacing:0.06em;color:var(--ax-muted);font-weight:600;display:flex;align-items:center;gap:6px}
293
+ .bf-fgroup--warn h4{color:var(--ax-warn)}
294
+ .bf-fgroup--info h4{color:var(--ax-info)}
295
+ .bf-item{display:flex;flex-direction:column;gap:4px;padding-bottom:9px}
296
+ .bf-item>p{font-size:12.5px;line-height:1.55;color:var(--ax-text);margin:0;overflow-wrap:anywhere}
297
+
298
+ /* Inline trace panel \u2014 a readable summary in place, not a JSON tab */
299
+ .bf-trace{border:var(--ax-border-w) solid var(--ax-border);border-radius:var(--ax-radius-sm);
300
+ background:var(--ax-surface-2);padding:8px 12px}
301
+ .bf-trace>summary{cursor:pointer;font-size:11.5px;color:var(--ax-text-2);font-weight:600;
302
+ list-style:none;display:inline-flex;align-items:center;gap:6px}
303
+ .bf-trace>summary::-webkit-details-marker{display:none}
304
+ .bf-trace>summary:hover{color:var(--ax-accent)}
305
+ .bf-trace[open]>summary{margin-bottom:10px}
306
+ .bf-trace__body{font-size:12px;display:flex;flex-direction:column;gap:10px;align-items:flex-start}
307
+ .bf-kv{display:grid;grid-template-columns:auto 1fr;gap:5px 14px;margin:0;width:100%}
308
+ .bf-kv dt{font-family:var(--ax-mono);font-size:10.5px;text-transform:uppercase;letter-spacing:0.06em;
309
+ color:var(--ax-muted);align-self:center}
310
+ .bf-kv dd{margin:0;font-size:12.5px;color:var(--ax-text);overflow-wrap:anywhere}
311
+
312
+ .bf-tool{display:inline-flex;align-items:center;gap:4px;font-family:var(--ax-mono);font-size:11px;
313
+ background:var(--ax-surface-3);border-radius:var(--ax-radius-sm);padding:1px 7px;margin-right:4px}
314
+
315
+ /* Connect a CLI session */
316
+ .bf-connect{margin-top:24px}
317
+ .bf-connect__head{display:flex;align-items:center;gap:11px;margin-bottom:14px}
318
+ .bf-connect h2{margin:0;font-size:16px;font-weight:600;letter-spacing:-0.01em}
319
+ .bf-connect__note{margin-left:auto;font-size:10.5px;color:var(--ax-muted);font-family:var(--ax-mono)}
320
+ .bf-discover{display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap;margin-bottom:14px}
321
+ .bf-discover .ax-field{min-width:220px;flex:0 1 300px}
322
+ .bf-cli{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:10px}
323
+ .bf-cli:not(:empty){margin-bottom:14px}
324
+ .bf-cli-card{background:var(--ax-surface-2);border:var(--ax-border-w) solid var(--ax-border);
325
+ border-radius:var(--ax-radius-sm);padding:12px 13px;display:flex;flex-direction:column;gap:9px}
326
+ .bf-cli-card__top{display:flex;align-items:center;gap:10px;min-width:0}
327
+ .bf-cli-card__n{font-size:13px;font-weight:600}
328
+ .bf-cli-card__m{font-size:10.5px;color:var(--ax-muted);font-family:var(--ax-mono);margin-top:2px;
329
+ overflow-wrap:anywhere}
330
+ .bf-cli-card .ax-btn{justify-content:center}
331
+ .bf-manual>summary{cursor:pointer;font-size:12px;color:var(--ax-muted);font-weight:600;list-style:none;
332
+ display:inline-flex;align-items:center;gap:6px}
333
+ .bf-manual>summary::-webkit-details-marker{display:none}
334
+ .bf-manual[open]>summary svg{transform:rotate(180deg)}
335
+ .bf-forms{display:grid;grid-template-columns:1fr 1fr;gap:22px;margin-top:14px}
336
+ .bf-form{display:flex;flex-direction:column;gap:12px}
337
+ .bf-form .ax-sec-label{margin:0}
338
+ .bf-form__row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
339
+ .bf-form .ax-btn{align-self:flex-start}
340
+
341
+ /* Empty + loading */
342
+ .bf-empty{text-align:center;padding:30px 22px;background:var(--ax-surface);
343
+ border:var(--ax-border-w) dashed var(--ax-border-2);border-radius:var(--ax-radius-lg);
344
+ color:var(--ax-muted);display:flex;flex-direction:column;align-items:center;gap:7px}
345
+ .bf-empty svg{color:var(--ax-border-2)}
346
+ .bf-empty h4{margin:0;color:var(--ax-text);font-size:14px;font-weight:600}
347
+ .bf-empty p{font-size:12.5px;line-height:1.55;max-width:380px;margin:0}
348
+ .bf-skel{background:var(--ax-surface);border:var(--ax-border-w) solid var(--ax-border);
349
+ border-radius:var(--ax-radius-lg);padding:14px 16px;display:flex;flex-direction:column;gap:10px}
350
+ .bf-bar{display:block;height:10px;border-radius:var(--ax-radius-pill);background:var(--ax-surface-3);
351
+ animation:bf-pulse 1.4s ease-in-out infinite}
352
+ @keyframes bf-pulse{0%,100%{opacity:1}50%{opacity:0.45}}
353
+ @media (prefers-reduced-motion:reduce){.bf-bar{animation:none}}
354
+
355
+ @media(max-width:980px){
356
+ .bf-grid{grid-template-columns:1fr}
357
+ .bf-forms{grid-template-columns:1fr}
358
+ .bf-strip{grid-template-columns:1fr 1fr}
359
+ }
360
+ @media(max-width:600px){
361
+ .bf{padding:16px 14px 36px}
362
+ .bf-head{flex-direction:column;gap:14px;align-items:stretch}
363
+ .bf-sync{justify-content:space-between}
364
+ }`,un=String.raw`
365
+ (function(){
366
+ const $=id=>document.getElementById(id), esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
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>';
368
+ let nodes=[], actions=[], busy=false, expandedActions=false;
369
+ let filter={kind:'all',agent:null,node:null};
370
+ async function api(op,node,body){const r=await fetch('/api/monitor/'+op+'?node='+encodeURIComponent(node),{method:body?'POST':'GET',headers:{'Content-Type':'application/json'},...(body?{body:JSON.stringify(body)}:{})});const data=await r.json();if(!r.ok)throw Error(data.error||'Request failed');return data;}
371
+ function message(s){$('notice').textContent=s;}
372
+ let clientFilter='';
373
+ const PAGE=25;
374
+ let shown={you:PAGE,agents:PAGE};
375
+
376
+ /* --- Who and where ------------------------------------------------------
377
+ session_id is "<agent>:<channel>:<target>" for trace-sourced reviews, e.g.
378
+ "umbrella-coding:gitlab:umbrella-lab/umbrella-v1:issue:94". Native CLI session
379
+ ids carry no place, so the tags simply fall away. */
380
+ const CHANNEL_ICON={gitlab:'branch',github:'branch',telegram:'send',whatsapp:'msg',discord:'msg',slack:'hash',api:'code',cron:'clock',mesh:'route'};
381
+ function place(sessionId){
382
+ const parts=String(sessionId||'').split(':');
383
+ if(parts.length<3)return null;
384
+ const channel=parts[1];
385
+ let target=parts.slice(2).join(':')
386
+ .replace(/:issue:/,' #').replace(/:mr:/,' !').replace(/:pr:/,' #').replace(/:/g,' · ');
387
+ return {channel:channel,target:target};
388
+ }
389
+ function initials(name){const w=String(name||'?').split(/[-_\s.]+/).filter(Boolean);return ((w[0]||'?')[0]+(w[1]?w[1][0]:(w[0]||'?')[1]||'')).slice(0,2);}
390
+ const AV=['blue','teal','amber','coral'];
391
+ function avatarClass(name){let h=0;for(const c of String(name||'')) h=(h*31+c.charCodeAt(0))>>>0;return AV[h%AV.length];}
392
+ function tag(icon,text,attrs){return '<'+(attrs?'button type="button" '+attrs:'span')+' class="bf-tag">'+(icon?ic(icon,11):'')+esc(text)+'</'+(attrs?'button':'span')+'>';}
393
+ function idBlock(agent,nodeName,nodeUrl,sessionId,model,when,whenExact){
394
+ const p=place(sessionId);
395
+ const on=(k,v)=>filter[k]===v?' is-on':'';
396
+ return '<div class="bf-id"><div class="ax-avatar ax-avatar--'+avatarClass(agent)+'">'+esc(initials(agent))+'</div>'
397
+ +'<div class="bf-who"><div class="bf-who__n">'
398
+ +'<button type="button" class="bf-tag'+on('agent',agent)+'" data-fagent="'+esc(agent)+'" style="font-size:13.5px;font-family:inherit;background:none;border:none;padding:0;color:inherit">'+esc(agent)+'</button>'
399
+ +(model?'<span class="ax-badge ax-badge--mono">'+esc(model)+'</span>':'')+'</div>'
400
+ +'<div class="bf-where">'
401
+ +'<button type="button" class="bf-tag'+on('node',nodeName)+'" data-fnode="'+esc(nodeName)+'" title="Filter by node">'+ic('server',11)+esc(nodeName)+'</button>'
402
+ +(p?tag(CHANNEL_ICON[p.channel]||'hash',p.channel):'')
403
+ +(p&&p.target?tag('',p.target):'')
404
+ +'</div></div>'
405
+ +(when?'<span class="bf-time" title="'+esc(whenExact||'')+'">'+esc(when)+'</span>':'')+'</div>';
406
+ }
407
+ function lnk(href,icon,text,go){return '<a class="bf-lnk'+(go?' bf-lnk--go':'')+'" href="'+esc(href)+'" target="_blank" rel="noopener noreferrer" title="'+esc(text)+'">'+ic(icon,12)+esc(text)+'</a>';}
408
+ /* Human-friendly time. Relative on the face, exact on hover. */
409
+ function relTime(ms){
410
+ if(!ms)return '';
411
+ const d=Math.round((Date.now()-ms)/1000);
412
+ if(d<45)return 'just now';
413
+ if(d<90)return 'a minute ago';
414
+ const m=Math.round(d/60);
415
+ if(m<60)return m+' min ago';
416
+ const h=Math.round(m/60);
417
+ if(h<24)return h===1?'an hour ago':h+' hours ago';
418
+ const day=Math.round(h/24);
419
+ if(day===1)return 'yesterday';
420
+ if(day<7)return day+' days ago';
421
+ return new Date(ms).toLocaleDateString([], {month:'short',day:'numeric'});
422
+ }
423
+ function absTime(ms){return ms?new Date(ms).toLocaleString():'';}
424
+ function fmtDur(ms){
425
+ if(ms==null)return '';
426
+ if(ms<1000)return ms+' ms';
427
+ const s=Math.round(ms/1000);
428
+ if(s<60)return s+' s';
429
+ const m=Math.floor(s/60),r=s%60;
430
+ if(m<60)return m+'m'+(r?' '+r+'s':'');
431
+ const h=Math.floor(m/60);
432
+ return h+'h'+(m%60?' '+(m%60)+'m':'');
433
+ }
434
+ function tracePanel(nodeUrl,taskId){
435
+ return '<details class="bf-trace" data-node="'+esc(nodeUrl)+'" data-task="'+esc(taskId)+'">'
436
+ +'<summary>'+ic('trace',12)+'Trace</summary>'
437
+ +'<div class="bf-trace__body"><span class="ax-muted">Loading&hellip;</span></div></details>';
438
+ }
439
+ function renderTrace(el,d){
440
+ if(!d||d.found===false)return '<span class="ax-muted">No trace stored for this run.</span>';
441
+ const kv=[];
442
+ const add=(k,v)=>{if(v!==''&&v!=null)kv.push('<dt>'+k+'</dt><dd>'+v+'</dd>');};
443
+ add('Status','<span class="ax-pill ax-pill--'+(d.status==='ok'?'ok':d.status==='error'?'err':'off')+'"><span class="ax-pill__dot"></span>'+esc(d.status||'unknown')+'</span>');
444
+ add('Agent',esc(d.agent||''));
445
+ if(d.channel)add('Where',esc(d.channel)+(d.chatId?' &middot; '+esc(String(d.chatId).replace(/:issue:/,' #').replace(/:mr:/,' !')):''));
446
+ add('Started',d.startedAt?'<span title="'+esc(absTime(d.startedAt))+'">'+esc(relTime(d.startedAt))+'</span>':'');
447
+ add('Took',d.durationMs!=null?esc(fmtDur(d.durationMs)):'');
448
+ if(d.model)add('Model',esc(d.model));
449
+ if(d.cause)add('Cause',esc(d.cause));
450
+ // Counters are derived from steps; pruned traces report zeros that mean
451
+ // "unknown", not "none". Say so rather than showing a wall of 0s.
452
+ if(d.stepsPruned)kv.push('<dt>Detail</dt><dd class="ax-muted">Step detail was pruned &mdash; tool, token and I/O counters are no longer available.</dd>');
453
+ else{
454
+ add('Steps',String((d.steps||[]).length));
455
+ if(d.tools&&d.tools.length)add('Tools',d.tools.map(t=>{
456
+ const name=esc(typeof t==='string'?t:(t.tool||t.name||'tool'));
457
+ const used=(t&&t.used>1)?' &times;'+t.used:'';
458
+ const failed=(t&&t.failed)?' <span class="ax-pill ax-pill--err" style="padding:0 5px">'+t.failed+' failed</span>':'';
459
+ return '<span class="bf-tool">'+name+used+failed+'</span>';
460
+ }).join(' '));
461
+ if(d.outputTokens)add('Output tokens',String(d.outputTokens));
462
+ const io=[d.reads?d.reads+' read':'',d.writes?d.writes+' write':'',d.sends?d.sends+' send':''].filter(Boolean).join(' &middot; ');
463
+ if(io)add('I/O',io);
464
+ }
465
+ return '<dl class="bf-kv">'+kv.join('')+'</dl>'
466
+ +'<a class="bf-lnk" href="/api/mesh/run?node='+encodeURIComponent(el.dataset.node)+'&task='+encodeURIComponent(el.dataset.task)+'" target="_blank" rel="noopener noreferrer">'+ic('ext',12)+'Raw JSON</a>';
467
+ }
468
+ /* The human task page, not the raw JSON endpoint. archived=1 reads the stored
469
+ record; a live task streams instead. Falls back to the JSON API only when no
470
+ agent can be resolved, because /tasks refuses a request without one. */
471
+ function taskHref(nodeUrl,taskId,agentId,archived){
472
+ return agentId
473
+ ?'/tasks/'+encodeURIComponent(taskId)+'?agent='+encodeURIComponent(agentId)+'&node='+encodeURIComponent(nodeUrl)+(archived?'&archived=1':'')
474
+ :'/api/mesh/run?node='+encodeURIComponent(nodeUrl)+'&task='+encodeURIComponent(taskId);
475
+ }
476
+ /* A related task usually has its own review (or is still running); either one
477
+ tells us which agent owns it. */
478
+ function ownerOf(n,taskId){
479
+ const run=(n.data.running||[]).find(t=>t.taskId===taskId);
480
+ if(run)return run.agentId;
481
+ const rev=(n.data.reviews||[]).find(r=>r.id===taskId);
482
+ return rev?rev.agent:'';
483
+ }
484
+
485
+ /* --- Loading skeleton --------------------------------------------------- */
486
+ function skeleton(){
487
+ const bar=w=>'<i class="bf-bar" style="width:'+w+'"></i>';
488
+ const card='<div class="bf-skel">'+bar('40%')+bar('100%')+bar('64%')+'</div>';
489
+ $('strip').innerHTML=('<div class="ax-stat-inline"><div class="ax-stat-inline__icon"></div>'
490
+ +'<div class="bf-skel" style="flex:1;gap:6px">'+bar('46px')+bar('76px')+'</div></div>').repeat(4);
491
+ $('you').innerHTML=card+card;$('agents').innerHTML=card;$('reviews').innerHTML=card;$('running').innerHTML=card;
492
+ }
493
+
494
+ /* --- Coverage ----------------------------------------------------------- */
495
+ function si(icon,value,label,kind){return '<div class="ax-stat-inline'+(kind?' bf-si--'+kind:'')+'"><div class="ax-stat-inline__icon">'+ic(icon,14)+'</div><div style="min-width:0"><div class="ax-stat-inline__v">'+esc(value)+'</div><div class="ax-stat-inline__l">'+esc(label)+'</div></div></div>';}
496
+ function renderCoverage(){
497
+ const ok=nodes.filter(n=>n.ok), failed=nodes.filter(n=>!n.ok);
498
+ const reviews=ok.reduce((a,n)=>a+(n.data.reviews||[]).length,0);
499
+ const queue=ok.flatMap(n=>n.data.counts||[]);
500
+ const waiting=queue.filter(c=>c.status==='pending'||c.status==='reviewing').reduce((a,c)=>a+c.count,0);
501
+ const failures=queue.filter(c=>c.status==='failed').reduce((a,c)=>a+c.count,0);
502
+ $('strip').innerHTML=si('server',ok.length+' / '+nodes.length,'Nodes reporting',failed.length?'warn':'')
503
+ +si('inbox',String(waiting),'Awaiting review')
504
+ +si('cross',String(failures),failures===1?'Review failed':'Reviews failed',failures?'err':'')
505
+ +si('file',String(reviews),'Recent briefings');
506
+ $('coverage').textContent=reviews+' recent reviews, '+waiting+' awaiting review'+(failures?', '+failures+' review failures':'')+', '+ok.length+' of '+nodes.length+' nodes reporting'+(failed.length?'. Unavailable: '+failed.map(n=>n.name+' ('+n.error+')').join(', '):'');
507
+ $('coverage-note').innerHTML=failed.length
508
+ ?'<div class="ax-callout'+(ok.length?'':' bf-callout--err')+'"><span class="ax-callout__icon">!</span><div><b>'
509
+ +esc(failed.map(n=>n.name).join(', '))+'</b> not reporting &mdash; '
510
+ +failed.map(n=>'<code>'+esc(n.error)+'</code>').join(' ')+'</div></div>':'';
511
+ }
512
+
513
+ /* --- Actions ------------------------------------------------------------ */
514
+ function card(a,i,clocks){
515
+ /* The cost of waiting, not an estimate of the work. A client with a stated
516
+ clock accrues against it; everything else is flat and says so. */
517
+ const d=decayOf(a,clocks||{});
518
+ const age=a.updatedAt?relTime(a.updatedAt).replace(' ago',''):'';
519
+ const cost=d.rising
520
+ ?'<span class="bf-cost bf-cost--rise'+(d.overdue?' is-over':'')+'">'+ic('pulse',12)+esc(age)+(d.overdue?' &middot; past the clock':' &middot; rising')+'</span>'
521
+ :'<span class="bf-cost">'+ic('clock',12)+esc(age)+' &middot; flat</span>';
522
+ const pill=a.needsHuman
523
+ ?'<span class="ax-pill ax-pill--warn"><span class="ax-pill__dot"></span>Needs you</span>'
524
+ :'<span class="ax-pill ax-pill--info"><span class="ax-pill__dot"></span>Agent</span>';
525
+ const done='<button class="ax-btn ax-btn--sm ax-btn--primary" data-action="done" data-index="'+i+'">'+ic('check',13)+' Done</button>';
526
+ const foot=a.snoozed
527
+ ?done+'<button class="ax-btn ax-btn--sm ax-btn--ghost" data-action="open" data-index="'+i+'">Bring back</button>'
528
+ :done+'<button class="ax-btn ax-btn--sm ax-btn--ghost" data-action="later" data-index="'+i+'">Snooze</button>';
529
+ const src=a.sources[0];
530
+ const links=(src && !String(src.reviewId).startsWith('external:'))?tracePanel(src.node,src.reviewId):'';
531
+ return '<article class="bf-act'+(d.overdue&&a.needsHuman?' bf-act--now':'')+(a.snoozed?' is-snoozed':'')+'">'
532
+ +idBlock(a.agent,a.nodes.join(' / '),src?src.node:'',a.sessionId,'',relTime(a.updatedAt),absTime(a.updatedAt))
533
+ +'<p class="bf-act__text">'+esc(a.text)+'</p>'
534
+ +'<div class="bf-links">'+pill
535
+ +(a.sources.length>1?'<span class="bf-dupe" title="Re-derived by this many session reviews">'+ic('loop',12)+'seen '+a.sources.length+'&times;</span>':'')
536
+ +cost
537
+ +(a.snoozed?'<span class="ax-pill ax-pill--off">snoozed</span>':'')+'</div>'
538
+ +links
539
+ +'<div class="bf-act__foot">'+foot+'</div>'
540
+ +(a.evidence?'<details class="bf-why"><summary>'+ic('chev',12)+'Evidence</summary><p class="bf-ev">'+esc(a.evidence)+'</p></details>':'')
541
+ +'</article>';
542
+ }
543
+ /* --- Principals ---------------------------------------------------------- */
544
+ /* Who the work is for. Clients are derived from business.projects and
545
+ business.contactMap, so this fills itself in; it is only empty when no
546
+ project or contact has ever been configured. Clicking one filters the
547
+ action list — the fastest way to answer "what does this client need". */
548
+ const KIND_LABEL={client:'client',own:'own product',internal:'internal'};
549
+ function renderPrincipals(){
550
+ const policy={};
551
+ for(const n of nodes.filter(n=>n.ok))for(const c of n.data.clients||[])policy[c.id]=c;
552
+ const by={};
553
+ for(const a of actions){
554
+ const id=a.clientId||'unmapped';
555
+ const g=by[id]||(by[id]={id:id,you:0,agents:0,oldest:0});
556
+ if(a.needsHuman)g.you++;else g.agents++;
557
+ if(a.updatedAt&&(!g.oldest||a.updatedAt<g.oldest))g.oldest=a.updatedAt;
558
+ }
559
+ const rows=Object.values(by).sort((x,y)=>y.you-x.you||y.agents-x.agents);
560
+ if(!rows.length){$('principals').innerHTML='';return;}
561
+ $('principals').innerHTML='<section class="bf-pr" aria-label="Who the work is for">'
562
+ +rows.map(g=>{
563
+ const p=policy[g.id]||{name:g.id,kind:'internal',declared:false};
564
+ const on=clientFilter===g.id;
565
+ return '<button class="bf-pr__c'+(on?' is-on':'')+(p.kind==='client'?' bf-pr__c--client':'')+'"'
566
+ +' data-client="'+esc(g.id)+'" aria-pressed="'+(on?'true':'false')+'">'
567
+ +'<span class="bf-pr__n">'+esc(p.name||g.id)+'</span>'
568
+ +'<span class="bf-pr__k">'+esc(KIND_LABEL[p.kind]||'internal')+(p.respondWithinMinutes?' &middot; '+p.respondWithinMinutes+'m clock':'')+'</span>'
569
+ +'<span class="bf-pr__s"><b class="'+(g.you?'bf-pr__you':'')+'">'+g.you+'</b> on you'
570
+ +'<i>'+g.agents+' on agents</i></span>'
571
+ +(g.oldest?'<span class="bf-pr__o">oldest '+relTime(g.oldest)+'</span>':'')
572
+ +'</button>';
573
+ }).join('')+'</section>';
574
+ $('principals').querySelectorAll('[data-client]').forEach(b=>b.onclick=()=>{
575
+ clientFilter=clientFilter===b.dataset.client?'':b.dataset.client;shown={you:PAGE,agents:PAGE};renderPrincipals();renderActions();});
576
+ }
577
+
578
+ function renderActions(){
579
+ const merged=new Map();
580
+ for(const n of nodes.filter(n=>n.ok))for(const entry of n.data.actions?.items||[]){
581
+ const a=entry.action,saved=entry.state;const key=entry.key||JSON.stringify([n.url,entry.sessionId,a.text.toLowerCase().replace(/\s+/g,' ').trim()]);const source={node:n.url,reviewId:entry.reviewId,index:entry.actionIndex};
582
+ if(merged.has(key)){const m=merged.get(key);m.sources.push(source);if(!m.nodes.includes(n.name))m.nodes.push(n.name);if(saved==='open')m.snoozed=false;if(entry.updatedAt>m.updatedAt){m.updatedAt=entry.updatedAt;m.text=a.text;m.evidence=a.evidence;}}
583
+ else merged.set(key,{...a,snoozed:saved==='later',sources:[source],nodes:[n.name],agent:entry.agent,sessionId:entry.sessionId,updatedAt:entry.updatedAt,clientId:entry.clientId});
584
+ }
585
+ const unloaded=nodes.filter(n=>n.ok).reduce((s,n)=>s+Math.max(0,(n.data.actions?.total||0)-(n.data.actions?.items.length||0)),0);
586
+ $('more-actions').hidden=!unloaded;$('more-actions').textContent='Load '+unloaded+' older';
587
+ actions=[...merged.values()];
588
+ /* Each client's stated respondWithin is what makes a wait cost something.
589
+ Work for a client with no clock is flat and can never outrank someone who
590
+ is actually waiting. */
591
+ const clocks={};
592
+ for(const n of nodes.filter(n=>n.ok))for(const c of n.data.clients||[])clocks[c.id]=c.respondWithinMinutes;
593
+ const list=clientFilter?actions.filter(a=>(a.clientId||'unmapped')===clientFilter):actions;
594
+ const order=rankByDecay(list,clocks)
595
+ .sort((x,y)=>(list[x].snoozed?1:0)-(list[y].snoozed?1:0));
596
+ const you=[],agents=[];
597
+ for(const i of order)(list[i].needsHuman?you:agents).push(list[i]);
598
+ const page=(items,key)=>items.slice(0,shown[key]).map(a=>card(a,actions.indexOf(a),clocks)).join('')
599
+ +(items.length>shown[key]
600
+ ?'<button class="ax-btn ax-btn--sm bf-more" data-more="'+key+'">Show '+Math.min(PAGE,items.length-shown[key])+' more of '+(items.length-shown[key])+'</button>'
601
+ :'');
602
+ $('you').innerHTML=page(you,'you')||'<div class="bf-empty">'+ic('check',22)+'<h4>Nothing needs you</h4><p>Everything open can be finished without your authority.</p></div>';
603
+ $('you-count').textContent=you.length?String(you.length):'';
604
+ $('agents').innerHTML=page(agents,'agents')||'<div class="bf-empty">'+ic('check',22)+'<h4>Nothing queued for agents</h4><p>No open action was marked as needing no human.</p></div>';
605
+ $('agents-count').innerHTML=String(agents.length)+(unloaded?'<span class="ax-pill ax-pill--off">'+unloaded+' not loaded</span>':'');
606
+ const done=nodes.filter(n=>n.ok).reduce((t,n)=>t+(n.data.doneCount||0),0);
607
+ $('handled').innerHTML=done?'<div class="bf-done">'+ic('check',17)+'<b>'+done+'</b> handled<span>cleared by you or by an agent &mdash; no decision in here</span></div>':'';
608
+ }
609
+
610
+ /* --- Session briefings + filters ---------------------------------------- */
611
+ const GROUPS=[['warnings','Warnings','alert','warn'],['decisions','Decisions on your behalf','gavel','info'],['friction','Avoidable round trips','loop',''],['context','Context maintenance','broom','']];
612
+ function chip(n,icon,kind,one,many){return '<span class="bf-find '+(n?'bf-find--'+kind:'bf-find--zero')+'">'+ic(icon,12)+(n?n+' '+(n===1?one:many):'no '+many)+'</span>';}
613
+ function rows(){return nodes.filter(n=>n.ok).flatMap(n=>(n.data.reviews||[]).map(r=>({n:n,r:r})));}
614
+ function passes(e,ignoreKind){
615
+ const r=e.r,v=r.result;
616
+ if(filter.agent&&r.agent!==filter.agent)return false;
617
+ if(filter.node&&e.n.name!==filter.node)return false;
618
+ if(!ignoreKind){
619
+ if(filter.kind==='failed'&&r.status!=='failed')return false;
620
+ if(filter.kind==='warn'&&!(v&&v.warnings.length))return false;
621
+ if(filter.kind==='needs'&&!(v&&v.actions.some(a=>a.needsHuman)))return false;
622
+ }
623
+ const q=$('search').value.toLowerCase();
624
+ return !q||JSON.stringify(r).toLowerCase().includes(q);
625
+ }
626
+ function renderFilters(){
627
+ const base=rows().filter(e=>passes(e,true));
628
+ const counts={all:base.length,
629
+ needs:base.filter(e=>e.r.result&&e.r.result.actions.some(a=>a.needsHuman)).length,
630
+ warn:base.filter(e=>e.r.result&&e.r.result.warnings.length).length,
631
+ failed:base.filter(e=>e.r.status==='failed').length};
632
+ const defs=[['all','file','All'],['needs','alert','Needs you'],['warn','alert','Warnings'],['failed','cross','Failed']];
633
+ let html=defs.map(([k,icon,label])=>'<button type="button" class="bf-filter'+(filter.kind===k?' is-on':'')+'" data-fkind="'+k+'">'+ic(icon,12)+esc(label)+'<span class="bf-filter__n">'+counts[k]+'</span></button>').join('');
634
+ if(filter.agent)html+='<button type="button" class="bf-filter is-on" data-fagent="'+esc(filter.agent)+'">'+ic('hash',12)+esc(filter.agent)+ic('x',11)+'</button>';
635
+ if(filter.node)html+='<button type="button" class="bf-filter is-on" data-fnode="'+esc(filter.node)+'">'+ic('server',12)+esc(filter.node)+ic('x',11)+'</button>';
636
+ if(filter.kind!=='all'||filter.agent||filter.node)html+='<button type="button" class="bf-filter bf-filter--clear" data-fclear="1">'+ic('x',12)+'Clear</button>';
637
+ $('filters').innerHTML=html;
638
+ }
639
+ function renderReviews(){
640
+ renderFilters();
641
+ const entries=rows().filter(e=>passes(e,false)).sort((a,b)=>b.r.updated_at-a.r.updated_at).map(e=>{
642
+ const n=e.n,r=e.r,v=r.result;
643
+ const head=idBlock(r.agent,n.name,n.url,r.session_id,r.model,relTime(r.updated_at),absTime(r.updated_at));
644
+ if(r.status==='failed')return '<article class="bf-brief bf-brief--failed">'+head
645
+ +'<div class="bf-brief__fail"><span class="ax-badge ax-badge--err">Review failed</span>'
646
+ +'<p class="bf-brief__sum">'+esc(r.error||'Review failed')+'</p>'
647
+ +'<button class="ax-btn ax-btn--sm" data-retry="'+esc(r.id)+'" data-node="'+esc(n.url)+'">Retry</button></div></article>';
648
+ let html='<article class="bf-brief">'+head+'<p class="bf-brief__sum">'+esc(v?v.summary:'Review '+r.status+'…')+'</p>';
649
+ // Quick access: every link the review produced, plus the trace it came from.
650
+ let links=v?v.links.filter(l=>/^https?:\/\//i.test(l.url)||/^\/(?!\/)/.test(l.url))
651
+ .map(l=>lnk(l.url.startsWith('/')?n.url+l.url:l.url,'ext',l.label)).join(''):'';
652
+ if(v)links+=v.relatedTaskIds.map(id=>lnk(taskHref(n.url,id,ownerOf(n,id),true),'route','Related '+String(id).slice(-6))).join('');
653
+
654
+ if(links)html+='<div class="bf-links">'+links+'</div>';
655
+ if(r.source==='trace')html+=tracePanel(n.url,r.id);
656
+ if(v){
657
+ html+='<div class="bf-finds">'+chip(v.warnings.length,'alert','warn','warning','warnings')
658
+ +chip(v.decisions.length,'gavel','info','decision','decisions')
659
+ +chip(v.friction.length,'loop','warn','round trip','round trips')
660
+ +chip(v.context.length,'broom','info','context note','context notes')+'</div>';
661
+ const detail=GROUPS.filter(g=>v[g[0]].length).map(g=>'<div class="bf-fgroup'+(g[3]?' bf-fgroup--'+g[3]:'')+'"><h4>'+ic(g[2],13)+esc(g[1])+'</h4>'
662
+ +v[g[0]].map(x=>'<div class="bf-item"><p>'+esc(x.text)+'</p><p class="bf-ev">'+esc(x.evidence)+'</p></div>').join('')+'</div>').join('');
663
+ if(detail)html+='<details><summary>'+ic('chev',12)+'Findings &amp; evidence</summary><div class="bf-detail">'+detail+'</div></details>';
664
+ }
665
+ return html+'</article>';});
666
+ $('brief-count').textContent=entries.length?String(entries.length):'';
667
+ $('reviews').innerHTML=(entries.slice(0,4).join('')+(entries.length>4?'<details><summary class="bf-defer">'+ic('chevr',14)+'<span class="bf-defer__t">'+(entries.length-4)+' earlier</span></summary><div class="bf-col" style="margin-top:10px">'+entries.slice(4).join('')+'</div></details>':''))
668
+ ||'<div class="bf-empty">'+ic('file',22)+'<h4>Nothing here</h4><p>'+(filter.kind!=='all'||filter.agent||filter.node||$('search').value?'No briefing matches the current filter.':'Runs that finish from now on are reviewed and land here.')+'</p></div>';
669
+ }
670
+ function registrations(){const n=nodes.find(n=>n.url===$('node').value);$('registered').innerHTML=(n?.data?.registrations||[]).map(r=>'<option value="'+esc(r.id)+'">'+esc(r.label)+' · '+esc(r.runtime)+'</option>').join('');}
671
+ function renderRunning(){
672
+ const list=nodes.filter(n=>n.ok).flatMap(n=>(n.data.running||[]).map(t=>'<div class="bf-run">'
673
+ +idBlock(t.agentId,n.name,n.url,t.sessionId||'','','')
674
+ +'<p class="bf-run__msg">'+esc(t.messagePreview||'Running task')+'</p>'
675
+ +tracePanel(n.url,t.taskId)+'</div>'));
676
+ $('run-count').textContent=list.length?String(list.length):'';
677
+ $('running').innerHTML=list.join('')||'<div class="bf-empty">'+ic('pulse',22)+'<h4>Nothing running</h4><p>No active AgentX runs reported.</p></div>';
678
+ }
679
+ async function refresh(){
680
+ if(busy)return;busy=true;$('refresh').disabled=true;$('refresh').setAttribute('aria-busy','true');
681
+ try{
682
+ const r=await fetch('/api/monitor');if(!r.ok)throw Error('Briefing unavailable: HTTP '+r.status);
683
+ const data=await r.json();nodes=data.nodes;expandedActions=false;
684
+ renderCoverage();
685
+ const selected=$('node').value;
686
+ $('node').innerHTML=nodes.map(n=>'<option value="'+esc(n.url)+'">'+esc(n.name)+(n.ok?'':' — unavailable')+'</option>').join('');
687
+ if(nodes.some(n=>n.url===selected))$('node').value=selected;
688
+ registrations();renderActions();renderPrincipals();renderReviews();renderRunning();
689
+ $('synced').textContent='Synced '+new Date().toLocaleTimeString();
690
+ message('');
691
+ }catch(e){$('synced').textContent='Refresh failed';message(e.message);}
692
+ finally{busy=false;$('refresh').disabled=false;$('refresh').removeAttribute('aria-busy');}
693
+ }
694
+ $('more-actions').onclick=async()=>{try{for(const n of nodes.filter(n=>n.ok&&n.data.actions.items.length<n.data.actions.total)){const r=await fetch('/api/monitor/actions?node='+encodeURIComponent(n.url)+'&offset='+n.data.actions.items.length);if(!r.ok)throw Error('Could not load older actions');const d=await r.json();n.data.actions.items.push(...d.items);n.data.actions.total=d.total;}expandedActions=true;renderActions();message('Older actions loaded. Auto-refresh paused until you press Refresh.');}catch(e){message(e.message);}};
695
+ document.addEventListener('click',e=>{const b=e.target.closest('[data-more]');if(!b)return;
696
+ shown[b.dataset.more]+=PAGE;renderActions();});
697
+ /* What this page is showing, for the ask-an-agent drawer. Kept small and
698
+ factual: the filter in force, what the buckets hold, and the handful of
699
+ items actually on screen — not the whole backlog. */
700
+ window.axPageContext=()=>{
701
+ const vis=actions.filter(a=>!clientFilter||(a.clientId||'unmapped')===clientFilter);
702
+ return {
703
+ page:'monitor',
704
+ client:clientFilter||'all',
705
+ onlyYou:vis.filter(a=>a.needsHuman).length,
706
+ forAgents:vis.filter(a=>!a.needsHuman).length,
707
+ topItems:vis.filter(a=>a.needsHuman).slice(0,8).map(a=>({
708
+ text:String(a.text||'').slice(0,140),client:a.clientId||'unmapped',agent:a.agent,
709
+ where:a.sessionId,seen:a.sources?a.sources.length:1})),
710
+ };};
711
+
712
+ $('clear-actions').onclick=async()=>{
713
+ const open=actions.length;
714
+ if(!open){message('Nothing open to clear.');return;}
715
+ if(!confirm('Mark all '+open+' open actions done on every node? The reviews and their findings stay; only the open flags move.'))return;
716
+ try{let n=0;
717
+ for(const nd of nodes.filter(n=>n.ok)){const r=await api('clear',nd.url,{});n+=r.cleared||0;}
718
+ message('Cleared '+n+'. New actions keep arriving as sessions end.');await refresh();
719
+ }catch(e){message(e.message);}};
720
+ $('search').oninput=renderReviews;$('refresh').onclick=refresh;$('node').onchange=registrations;
721
+ document.addEventListener('click',async e=>{
722
+ const tr=e.target.closest('.bf-trace>summary');
723
+ if(tr){
724
+ const el=tr.parentElement;
725
+ if(!el.dataset.loaded){
726
+ el.dataset.loaded='1';
727
+ const body=el.querySelector('.bf-trace__body');
728
+ fetch('/api/mesh/run?node='+encodeURIComponent(el.dataset.node)+'&task='+encodeURIComponent(el.dataset.task))
729
+ .then(r=>r.json()).then(d=>{body.innerHTML=renderTrace(el,d);})
730
+ .catch(err=>{body.innerHTML='<span class="ax-muted">Could not load the trace: '+esc(err.message)+'</span>';el.dataset.loaded='';});
731
+ }
732
+ return;
733
+ }
734
+ const t=e.target.closest('[data-fkind],[data-fagent],[data-fnode],[data-fclear]');
735
+ if(t){
736
+ if(t.dataset.fclear)filter={kind:'all',agent:null,node:null};
737
+ else if(t.dataset.fkind)filter.kind=t.dataset.fkind;
738
+ else if(t.dataset.fagent)filter.agent=filter.agent===t.dataset.fagent?null:t.dataset.fagent;
739
+ else if(t.dataset.fnode)filter.node=filter.node===t.dataset.fnode?null:t.dataset.fnode;
740
+ renderReviews();
741
+ if(t.dataset.fagent||t.dataset.fnode)$('reviews').scrollIntoView({behavior:'smooth',block:'start'});
742
+ return;
743
+ }
744
+ const b=e.target.closest('button');if(!b)return;
745
+ try{
746
+ if(b.dataset.action){b.disabled=true;const a=actions[Number(b.dataset.index)];await Promise.all(a.sources.map(s=>api('action',s.node,{reviewId:s.reviewId,index:s.index,state:b.dataset.action})));await refresh();}
747
+ if(b.dataset.retry){b.disabled=true;await api('retry',b.dataset.node,{id:b.dataset.retry});await refresh();}
748
+ }catch(err){message(err.message);}finally{b.disabled=false;}});
749
+ function cliCard(glyph,name,meta,badge,cta,onclick){
750
+ const el=document.createElement('div');el.className='bf-cli-card';
751
+ el.innerHTML='<div class="bf-cli-card__top"><div class="ax-avatar ax-avatar--'+avatarClass(name)+'" style="width:30px;height:30px;font-size:11px">'+esc(glyph)+'</div>'
752
+ +'<div style="min-width:0"><div class="bf-cli-card__n">'+esc(name)+'</div><div class="bf-cli-card__m">'+esc(meta)+'</div></div></div>'
753
+ +badge+'<button class="ax-btn ax-btn--sm ax-btn--primary">'+esc(cta)+'</button>';
754
+ el.querySelector('button').onclick=onclick;
755
+ return el;
756
+ }
757
+ const NATIVE='<span class="ax-pill ax-pill--ok"><span class="ax-pill__dot"></span>Reports turns natively</span>';
758
+ const PROC='<span class="ax-pill ax-pill--off">Process only</span>';
759
+ $('discover').onclick=async()=>{
760
+ try{
761
+ const node=$('node').value;const data=await api('discover',node);$('discovered').replaceChildren();
762
+ for(const s of data.sessions||[])
763
+ $('discovered').append(cliCard('cl','claude',s.label||s.id,NATIVE,'Monitor session',async()=>{
764
+ try{await api('register',node,{...s,label:s.label||s.id});message('Registered. Attach stop hooks will review future turns.');await refresh();}catch(e){message(e.message);}}));
765
+ for(const p of data.processes)
766
+ $('discovered').append(cliCard(p.runtime.slice(0,2),p.runtime,'PID '+p.pid+' · '+p.started,PROC,'Register',async()=>{
767
+ try{await api('register',node,{id:p.runtime+':'+p.pid+':'+p.started,label:p.runtime+' '+p.pid,runtime:p.runtime,pid:p.pid,started:p.started});message('Registered. Connect a stop hook or submit a transcript.');await refresh();}catch(e){message(e.message);}}));
768
+ if(!data.processes.length&&!(data.sessions||[]).length)
769
+ $('discovered').innerHTML='<div class="bf-empty" style="grid-column:1/-1">'+ic('plug',22)+'<h4>No CLI found</h4><p>Only processes owned by the daemon account are visible. Register others manually.</p></div>';
770
+ }catch(e){message(e.message);}};
771
+ for(const op of ['register','ended'])$(op).onsubmit=async e=>{e.preventDefault();try{const body=Object.fromEntries(new FormData(e.target));await api(op,$('node').value,body);message(op==='ended'?'Run queued for review.':'Session registered.');if(op==='ended')e.target.reset();await refresh();}catch(err){message(err.message);}};
772
+ skeleton();refresh();
773
+ setInterval(()=>{
774
+ if(document.hidden||expandedActions)return;
775
+ if(document.querySelector('form :focus'))return;
776
+ if(document.querySelector('.bf-trace[open]'))return; // don't yank an open trace
777
+ refresh();
778
+ },15000);
779
+ })();`;function Ge(t,e=20*6e4,a=6){let n=[...t].sort((i,c)=>i.startedAt-c.startedAt);if(!n.length)return{bands:[],gaps:[]};let r=[];for(let i of n){let c=i.startedAt+Math.max(i.durationMs||0,0),u=r[r.length-1];u&&i.startedAt-u.to<=e?(u.to=Math.max(u.to,c),u.runs++):r.push({from:i.startedAt,to:c,runs:1})}for(;r.length>a;){let i=0,c=1/0;for(let u=1;u<r.length;u++){let m=r[u].from-r[u-1].to;m<c&&(c=m,i=u)}r[i-1].to=r[i].to,r[i-1].runs+=r[i].runs,r.splice(i,1)}let o=r.reduce((i,c)=>i+c.runs,0)||1,s=r.map(i=>({from:i.from,to:Math.max(i.to,i.from+1),weight:i.runs/o,runs:i.runs})),l=r.slice(1).map((i,c)=>i.from-r[c].to);return{bands:s,gaps:l}}function Xe(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 qt(t,e=[],a){let{bands:n,gaps:r}=Ge(t,a);if(!n.length)return{bands:[],gaps:[],lanes:[],from:0,to:0};let o=new Map;for(let i of e){let c=o.get(i.runId);c?c.push(i):o.set(i.runId,[i])}let s=new Map;for(let i of t){let c=n.findIndex(M=>i.startedAt>=M.from&&i.startedAt<=M.to);if(c===-1)continue;let u=n[c],m=u.to-u.from||1,x=(i.startedAt-u.from)/m*100,b=Math.min(Math.max((i.durationMs||0)/m*100,1.2),100-x),_=s.get(i.laneKey)??{key:i.laneKey,label:i.laneLabel,sub:i.laneSub,tracks:1,runs:[]};_.runs.push({...i,band:c,track:0,left:x,width:b,marks:o.get(i.id)??[]}),s.set(i.laneKey,_)}let l=[...s.values()];for(let i of l)i.tracks=Math.max(...n.map((c,u)=>Xe(i.runs.filter(m=>m.band===u))),1);return l.sort((i,c)=>c.runs.length-i.runs.length||i.label.localeCompare(c.label)),{bands:n,gaps:r,lanes:l,from:n[0].from,to:n[n.length-1].to}}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"/>',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"/>'},Ke=(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>",mn=[["agent","Agent",se.bot],["client","Client",se.user],["project","Project",se.folder],["channel","Channel",se.route],["node","Node",se.mesh]];function Ut(t={}){return C({title:"AgentX \xB7 Activity",activeTab:"activity",subtitle:"Activity",peers:t.peers,body:`<div class="ac">
780
+
781
+ <div class="ac-head">
782
+ <div>
783
+ <div class="ac-kicker">Operations</div>
784
+ <h1>What ran, where, and what it decided</h1>
785
+ <p class="ac-sub">Every run on the mesh, from task traces. The axis breaks over silence &mdash; quiet stretches are labelled, not drawn.</p>
786
+ </div>
787
+ <div class="ac-tools">
788
+ <div class="ac-seg" id="hours" role="radiogroup" aria-label="Window">
789
+ ${[["6","6h"],["24","24h"],["72","3d"],["168","7d"]].map(([e,a],n)=>`<button type="button" role="radio" data-value="${e}" aria-checked="${n===1}"${n===1?' class="is-on"':""}>${a}</button>`).join("")}
790
+ </div>
791
+ <button class="ax-btn ax-btn--sm" id="refresh">${Ke(se.refresh,13)} Refresh</button>
792
+ </div>
793
+ </div>
794
+
795
+ <div class="ac-bar">
796
+ <span class="ac-lbl">Lanes by</span>
797
+ <div class="ac-seg" id="persp" role="radiogroup" aria-label="Perspective">
798
+ ${mn.map(([e,a,n],r)=>`<button type="button" role="radio" data-value="${e}" aria-checked="${r===0}"${r===0?' class="is-on"':""}>${Ke(n,13)}${a}</button>`).join("")}
799
+ </div>
800
+ <div class="ac-key">
801
+ <span class="ac-k"><i class="ac-d ac-d--decision"></i>decision</span>
802
+ <span class="ac-k"><i class="ac-d ac-d--warning"></i>warning</span>
803
+ <span class="ac-k"><i class="ac-d ac-d--recommendation"></i>friction</span>
804
+ <span class="ac-k"><i class="ac-d ac-d--later"></i>do later</span>
805
+ <span class="ac-k">${Ke(se.x,11)}canceled</span>
806
+ </div>
807
+ </div>
808
+
809
+ <p id="notice" role="status" aria-live="polite"></p>
810
+ <div id="tl" class="ac-tl"></div>
811
+ <div id="detail"></div>
812
+
813
+ </div>`,css:hn,scripts:`<script>${me({computeBands:Ge,packTracks:Xe,buildTimeline:qt})}const ICON = ${JSON.stringify(se)};${gn}</script>`})}var hn=`
814
+ .ac{max-width:1440px;margin:0 auto;padding:22px 24px 48px}
815
+ .ac :focus-visible{outline:2px solid var(--ax-accent);outline-offset:2px;border-radius:4px}
816
+ .ac-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:14px}
817
+ .ac-kicker{font-family:var(--ax-mono);font-size:10px;letter-spacing:0.1em;text-transform:uppercase;
818
+ color:var(--ax-text-2);font-weight:600}
819
+ .ac h1{font-size:22px;font-weight:600;letter-spacing:-0.015em;margin:5px 0 0}
820
+ .ac-sub{font-size:13px;color:var(--ax-text-2);margin:5px 0 0;max-width:66ch;line-height:1.5}
821
+ .ac-tools{display:flex;align-items:center;gap:10px;flex:none;padding-top:6px}
822
+ .ac-bar{display:flex;align-items:center;gap:16px;flex-wrap:wrap;background:var(--ax-surface);
823
+ border:var(--ax-border-w) solid var(--ax-border);border-radius:var(--ax-radius-lg);
824
+ padding:11px 16px;box-shadow:var(--ax-shadow);margin-bottom:14px}
825
+ .ac-lbl{font-family:var(--ax-mono);font-size:10px;letter-spacing:0.08em;text-transform:uppercase;
826
+ color:var(--ax-text-2);font-weight:600}
827
+ .ac-seg{display:flex;border:var(--ax-border-w) solid var(--ax-border-2);border-radius:var(--ax-radius);
828
+ overflow:hidden;background:var(--ax-bg)}
829
+ .ac-seg button{background:transparent;border:none;border-right:1px solid var(--ax-border);
830
+ color:var(--ax-text-2);font:inherit;font-size:12.5px;font-weight:600;padding:6px 13px;cursor:pointer;
831
+ white-space:nowrap;display:inline-flex;align-items:center;gap:6px}
832
+ .ac-seg button:last-child{border-right:none}
833
+ .ac-seg button:hover{color:var(--ax-text);background:var(--ax-surface-2)}
834
+ .ac-seg button.is-on{background:var(--ax-blue-t);color:var(--ax-blue-d)}
835
+ .ac-key{display:flex;align-items:center;gap:13px;margin-left:auto;flex-wrap:wrap}
836
+ .ac-k{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;color:var(--ax-text-2)}
837
+ .ac-d{width:9px;height:9px;flex:none}
838
+ .ac-d--decision{background:var(--ax-blue-d);transform:rotate(45deg)}
839
+ .ac-d--warning{background:var(--ax-amber-ink);clip-path:polygon(50% 0,100% 100%,0 100%)}
840
+ .ac-d--recommendation{background:var(--ax-green-d);border-radius:50%}
841
+ .ac-d--later{border:2px solid var(--ax-text-2);border-radius:2px}
842
+
843
+ .ac-tl{background:var(--ax-surface);border:var(--ax-border-w) solid var(--ax-border);
844
+ border-radius:var(--ax-radius-lg);box-shadow:var(--ax-shadow);overflow:hidden}
845
+ .ac-row{display:flex;align-items:stretch;border-bottom:1px solid var(--ax-border);position:relative}
846
+ .ac-row:last-child{border-bottom:none}
847
+ .ac-row--hd{background:var(--ax-surface-2);border-bottom:var(--ax-border-w) solid var(--ax-border)}
848
+ .ac-gut{width:186px;flex:none;display:flex;align-items:center;gap:9px;padding:8px 12px;
849
+ border-right:var(--ax-border-w) solid var(--ax-border);min-width:0}
850
+ .ac-gut b{font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
851
+ .ac-gut i{font-style:normal;font-family:var(--ax-mono);font-size:10px;color:var(--ax-text-2);
852
+ overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
853
+ .ac-bands{flex:1;display:flex;min-width:0}
854
+ .ac-band{position:relative;min-width:0}
855
+ .ac-band--hd{display:flex;align-items:center;justify-content:center;font-family:var(--ax-mono);
856
+ font-size:10px;color:var(--ax-text-2);font-weight:600;padding:7px 0}
857
+ .ac-gap{width:44px;flex:none;
858
+ background-image:repeating-linear-gradient(45deg,var(--ax-surface-2) 0 3px,transparent 3px 7px)}
859
+ .ac-gap--hd{display:flex;align-items:center;justify-content:center;background-image:none;
860
+ border-left:1px dashed var(--ax-border-2);border-right:1px dashed var(--ax-border-2);
861
+ font-family:var(--ax-mono);font-size:9px;color:var(--ax-text-2);font-weight:600}
862
+ .ac-run{position:absolute;height:20px;border-radius:5px;background:var(--ax-blue);
863
+ border:1px solid var(--ax-blue-d);cursor:pointer;padding:0}
864
+ .ac-run:hover{filter:brightness(1.08)}
865
+ .ac-run.is-sel{outline:2px solid var(--ax-text);outline-offset:1px}
866
+ .ac-run--failed{background:var(--ax-red);border-color:var(--ax-red-ink)}
867
+ .ac-run--canceled{background:transparent;border:1.5px dashed var(--ax-red-ink);height:14px;margin-top:3px}
868
+ .ac-run--running{background:var(--ax-green);border-color:var(--ax-green-d)}
869
+ .ac-mk{position:absolute;top:1px;width:9px;height:9px;transform:translateX(-50%);pointer-events:none}
870
+ .ac-empty{padding:40px;text-align:center;color:var(--ax-text-2);font-size:13px}
871
+
872
+ .ac-det{margin-top:14px;background:var(--ax-surface);border:var(--ax-border-w) solid var(--ax-border);
873
+ border-radius:var(--ax-radius-lg);box-shadow:var(--ax-shadow);padding:15px 17px}
874
+ .ac-det__h{display:flex;align-items:center;gap:9px;margin-bottom:11px;flex-wrap:wrap}
875
+ .ac-det__t{font-size:14px;font-weight:600}
876
+ .ac-kv{display:grid;grid-template-columns:80px minmax(0,1fr);gap:5px 12px;font-size:12.5px}
877
+ .ac-kv dt{font-family:var(--ax-mono);font-size:10px;text-transform:uppercase;letter-spacing:0.05em;
878
+ color:var(--ax-text-2);font-weight:600;padding-top:2px}
879
+ .ac-kv dd{margin:0;color:var(--ax-text);min-width:0;overflow-wrap:anywhere}
880
+ .ac-find{display:flex;gap:8px;align-items:flex-start;padding:7px 0;border-top:1px solid var(--ax-border);
881
+ font-size:12.5px;line-height:1.45}
882
+ .ac-chip{display:inline-flex;align-items:center;gap:5px;border-radius:var(--ax-radius-pill);padding:2px 9px;
883
+ font-size:11.5px;font-weight:600;border:1px solid var(--ax-border-2);background:var(--ax-surface-2);
884
+ color:var(--ax-text-2)}
885
+ #notice{margin:0 0 12px;font-size:12.5px;color:var(--ax-text-2)}
886
+ #notice:not(:empty){padding:9px 13px;border-radius:var(--ax-radius-sm);background:var(--ax-surface-2);
887
+ border:var(--ax-border-w) solid var(--ax-border)}
888
+ @media (max-width:900px){.ac-gut{width:120px}.ac-key{display:none}}
889
+ `,gn=String.raw`
890
+ const $=id=>document.getElementById(id);
891
+ const esc=s=>String(s==null?'':s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
892
+ 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>';
893
+ let runs=[],marks=[],persp='agent',hours='24',selected=null,busy=false;
894
+
895
+ function fmtDur(ms){if(!ms)return '0s';if(ms<1000)return ms+'ms';const s=Math.round(ms/1000);
896
+ if(s<60)return s+'s';const m=Math.floor(s/60);return m+'m '+(s%60)+'s';}
897
+ function fmtGap(ms){const m=Math.round(ms/60000);if(m<60)return m+'m';const h=Math.floor(m/60);
898
+ return h+'h'+(m%60?' '+(m%60)+'m':'');}
899
+ function clock(ms){return new Date(ms).toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'});}
900
+
901
+ /* The lane a run hangs from. Only this changes between perspectives — the
902
+ runs themselves are already loaded, so switching never refetches. */
903
+ function lane(r){
904
+ if(persp==='agent')return {key:r.agentId+'|'+(r.channel||''),label:r.agentId,sub:r.channel||''};
905
+ if(persp==='client')return {key:r.clientId||'unmapped',label:r.clientId||'unmapped',sub:''};
906
+ if(persp==='project')return {key:r.project||('('+(r.channel||'none')+')'),label:r.project||('no project'),sub:r.channel||''};
907
+ if(persp==='channel')return {key:r.channel||'none',label:r.channel||'none',sub:''};
908
+ return {key:r.node||'this node',label:r.node||'this node',sub:''};
909
+ }
910
+
911
+ function render(){
912
+ if(!runs.length){$('tl').innerHTML='<div class="ac-empty">Nothing ran in this window.</div>';$('detail').innerHTML='';return;}
913
+ const t=buildTimeline(runs.map(r=>{const l=lane(r);
914
+ return {id:r.id,laneKey:l.key,laneLabel:l.label,laneSub:l.sub,startedAt:r.startedAt,
915
+ durationMs:r.durationMs||0,status:r.status,label:r.preview||''};}),marks);
916
+ const cells=(inner)=>t.bands.map((b,i)=>
917
+ (i?'<div class="ac-gap'+inner.gapCls+'">'+(inner.gap?fmtGap(t.gaps[i-1]):'')+'</div>':'')
918
+ +'<div class="ac-band'+inner.cls+'" style="flex:'+b.weight.toFixed(4)+'">'+inner.body(b,i)+'</div>').join('');
919
+
920
+ let html='<div class="ac-row ac-row--hd"><div class="ac-gut"><i>'+t.lanes.length+' lanes &middot; '+runs.length+' runs</i></div>'
921
+ +'<div class="ac-bands">'+cells({cls:' ac-band--hd',gapCls:' ac-gap--hd',gap:true,
922
+ body:b=>clock(b.from)+' &ndash; '+clock(b.to)})+'</div></div>';
923
+
924
+ for(const ln of t.lanes){
925
+ const h=10+ln.tracks*24;
926
+ html+='<div class="ac-row" style="height:'+h+'px"><div class="ac-gut"><span style="min-width:0"><b>'+esc(ln.label)+'</b>'
927
+ +(ln.sub?'<i>'+esc(ln.sub)+'</i>':'')+'</span></div><div class="ac-bands">'
928
+ +cells({cls:'',gapCls:'',gap:false,body:(b,bi)=>ln.runs.filter(r=>r.band===bi).map(r=>{
929
+ const top=5+r.track*24;
930
+ const cls=r.status==='failed'?' ac-run--failed':r.status==='canceled'?' ac-run--canceled'
931
+ :(r.status==='running'||r.status==='in-flight')?' ac-run--running':'';
932
+ const mk=r.marks.map(m=>'<span class="ac-mk ac-d ac-d--'+m.kind+'" style="left:'+r.left.toFixed(3)+'%;top:'+(top-11)+'px"></span>').join('');
933
+ return mk+'<button class="ac-run'+cls+(selected===r.id?' is-sel':'')+'" data-run="'+esc(r.id)+'"'
934
+ +' style="left:'+r.left.toFixed(3)+'%;width:'+r.width.toFixed(3)+'%;top:'+top+'px"'
935
+ +' title="'+esc(r.laneLabel+' · '+clock(r.startedAt)+' · '+fmtDur(r.durationMs))+'"></button>';
936
+ }).join('')})
937
+ +'</div></div>';
938
+ }
939
+ $('tl').innerHTML=html;
940
+ $('tl').querySelectorAll('[data-run]').forEach(b=>b.onclick=()=>{selected=b.dataset.run;render();detail();});
941
+ detail();
942
+ }
943
+
944
+ const KIND={decision:'Decision taken for you',warning:'Warning',recommendation:'Avoidable round trip',later:'For later'};
945
+ function detail(){
946
+ const r=runs.find(x=>x.id===selected);
947
+ if(!r){$('detail').innerHTML='';return;}
948
+ const found=marks.filter(m=>m.runId===r.id);
949
+ $('detail').innerHTML='<div class="ac-det"><div class="ac-det__h">'
950
+ +'<span class="ac-det__t">'+esc(r.preview||'(no prompt recorded)')+'</span>'
951
+ +'<span class="ac-chip">'+esc(r.status)+'</span></div>'
952
+ +'<dl class="ac-kv">'
953
+ +'<dt>When</dt><dd>'+clock(r.startedAt)+' &middot; took '+fmtDur(r.durationMs||0)+'</dd>'
954
+ +'<dt>Who</dt><dd>'+esc(r.agentId)+(r.node?' on '+esc(r.node):'')+'</dd>'
955
+ +'<dt>Where</dt><dd>'+esc(r.channel||'&mdash;')+(r.chatId?' &middot; '+esc(r.chatId):'')+'</dd>'
956
+ +'<dt>For</dt><dd>'+esc(r.clientId||'unmapped')+'</dd></dl>'
957
+ +(found.length?found.map(m=>'<div class="ac-find"><i class="ac-d ac-d--'+m.kind+'" style="margin-top:4px"></i>'
958
+ +'<span><b>'+esc(KIND[m.kind]||m.kind)+'.</b> '+esc(m.text)+'</span></div>').join('')
959
+ :'<div class="ac-find" style="color:var(--ax-text-2)">No review findings for this run.</div>')
960
+ +'</div>';
961
+ }
962
+
963
+ async function load(){
964
+ if(busy)return;busy=true;$('refresh').disabled=true;
965
+ try{
966
+ const r=await fetch('/api/monitor');if(!r.ok)throw Error('HTTP '+r.status);
967
+ const nodes=(await r.json()).nodes.filter(n=>n.ok);
968
+ runs=[];marks=[];
969
+ for(const n of nodes){
970
+ try{
971
+ const a=await fetch('/api/monitor/activity?node='+encodeURIComponent(n.url)+'&hours='+hours);
972
+ if(!a.ok)continue;
973
+ const d=await a.json();
974
+ for(const run of d.runs||[])runs.push({...run,node:d.node||n.name});
975
+ for(const m of d.marks||[])marks.push(m);
976
+ }catch{}
977
+ }
978
+ $('notice').textContent='';
979
+ render();
980
+ }catch(e){$('notice').textContent=e.message;}
981
+ finally{busy=false;$('refresh').disabled=false;}
982
+ }
983
+
984
+ function paint(id,v){for(const b of $(id).children){const on=b.dataset.value===v;
985
+ b.classList.toggle('is-on',on);b.setAttribute('aria-checked',String(on));}}
986
+ $('persp').addEventListener('click',e=>{const b=e.target.closest('button[data-value]');if(!b)return;
987
+ persp=b.dataset.value;paint('persp',persp);selected=null;render();});
988
+ $('hours').addEventListener('click',e=>{const b=e.target.closest('button[data-value]');if(!b)return;
989
+ hours=b.dataset.value;paint('hours',hours);load();});
990
+ $('refresh').onclick=load;
991
+ load();
992
+ `;import{createHash as fn}from"crypto";import{readFileSync as xn,statSync as vn}from"fs";import{resolve as bn,dirname as yn}from"path";import{fileURLToPath as wn}from"url";var Ft=new Map;function je(t){let e=Ft.get(t);if(e)return e;let a=`/assets/${t}`;try{let n=yn(wn(import.meta.url)),r=bn(n,"web",t),o=vn(r),s=o.size<8e6?fn("sha1").update(xn(r)).digest("hex").slice(0,10):`${o.size}-${Math.floor(o.mtimeMs)}`;a=`/assets/${t}?v=${s}`}catch{}return Ft.set(t,a),a}function Wt(t={}){let e='<div id="wfe-root" style="height:100%"></div>';return C({title:"AgentX \xB7 Workflow editor",activeTab:"workflows",subtitle:"Workflow editor",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:kn,scripts:`<script src="${je("workflow-editor.global.js")}" defer></script>`,noMain:!0})}var kn=`
993
+ /* Preload the fonts the redesign's CSS references. Placed in the shell so
994
+ * they start fetching while the React bundle is still parsing. */
995
+ @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");
996
+
997
+ html, body { height: 100%; }
998
+ body { margin: 0; overflow: hidden; }
999
+ /* The editor takes over the whole viewport except the dashboard topbar. The
1000
+ * topbar still renders via the shell so the Workflows tab highlights and
1001
+ * global nav works. */
1002
+ .ax-topbar { position: relative; z-index: 50; }
1003
+ #wfe-root { width: 100%; height: calc(100vh - 48px); }
1004
+ /* Tiny fallback while the bundle loads \u2014 prevents an empty flash. */
1005
+ #wfe-root:empty::before {
1006
+ content: "Loading editor\u2026";
1007
+ display: block;
1008
+ padding: 40px 24px;
1009
+ color: #94a3b8;
1010
+ font: 13px/1 -apple-system, BlinkMacSystemFont, sans-serif;
1011
+ text-align: center;
1012
+ }
1013
+ `;cn();import{createServer as xs}from"http";import{appendFileSync as vs,existsSync as on,mkdirSync as bs}from"fs";import{readFile as ys}from"fs/promises";import{fileURLToPath as ws}from"url";import{dirname as ks,resolve as ke}from"path";var Gt='/*! 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 Le,readFileSync as Kt,writeFileSync as Jt,rmSync as hi,mkdirSync as An,copyFileSync as Mn,readdirSync as In}from"fs";import{resolve as he}from"path";Ne();var V={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 Xt(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=Ae({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.`})+Me([{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">');return C({title:"AgentX \xB7 Settings",activeTab:"admin",subtitle:"Settings",peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a+En()+It,css:Tn,scripts:`${e}<script>${$t}
1014
+ ${jt}
1015
+ ${_n}
1016
+ ${Cn}</script>`})}var _n=`
5
1017
  (function(){
6
1018
  function fmt(n) { return n == null ? '\u2014' : String(n); }
7
1019
  async function refresh() {
@@ -62,8 +1074,8 @@ ${Qa}</script>`})}var Ka=`
62
1074
  refresh();
63
1075
  // Refresh again after the main admin script has had a chance to mutate config.
64
1076
  document.addEventListener('ax-config-saved', refresh);
65
- })();`;function Ja(){let t=ht().business?`<button data-tab="business">Business</button>
66
- `:"";return Va.replace("__BUSINESS_TABS__",t)}var Va=`
1077
+ })();`;function En(){let t=St().business?`<button data-tab="business">Business</button>
1078
+ `:"";return Sn.replace("__BUSINESS_TABS__",t)}var Sn=`
67
1079
  <div id="peer-banner" class="peer-banner">
68
1080
  <span class="label">Managing</span>
69
1081
  <span class="name" id="peer-banner-name">\u2014</span>
@@ -206,7 +1218,7 @@ ${Qa}</script>`})}var Ka=`
206
1218
  <div id="global-msg" class="msg"></div>
207
1219
 
208
1220
  <section id="tab-agents" class="tab active">
209
- ${N({icon:J.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."})}
1221
+ ${N({icon:V.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."})}
210
1222
  ${X({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>).`})}
211
1223
  <div id="agent-list" class="ax-stack"></div>
212
1224
  <div class="add-form">
@@ -229,7 +1241,7 @@ ${Qa}</script>`})}var Ka=`
229
1241
  </section>
230
1242
 
231
1243
  <section id="tab-channels" class="tab">
232
- ${N({icon:J.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."})}
1244
+ ${N({icon:V.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."})}
233
1245
  ${X({persistKey:"channels",bodyHtml:`<b>How does this work?</b> We give each channel a small "bridge" that forwards messages to AgentX. For chat apps (Telegram, Slack, Discord) you'll paste a bot token \u2014 we keep the value in your <code>.env</code> file and never send it over the network. For webhook-style sources (GitHub, GitLab) we hand you a URL to paste into their dashboard.`})}
234
1246
 
235
1247
  <details class="add-form" style="margin-top:14px;margin-bottom:18px" id="notif-section">
@@ -259,10 +1271,10 @@ ${Qa}</script>`})}var Ka=`
259
1271
  </div>
260
1272
  </details>
261
1273
 
262
- <div id="ch-chatapps-label">${Ae({label:"Chat apps"})}</div>
1274
+ <div id="ch-chatapps-label">${Ie({label:"Chat apps"})}</div>
263
1275
  <div class="ax-connectors" id="ch-chatapps"></div>
264
1276
 
265
- <div id="ch-devtools-label">${Ae({label:"Developer tools",rightHtml:'<span class="ax-pill">Send events from GitHub, GitLab, Sentry, etc.</span>'})}</div>
1277
+ <div id="ch-devtools-label">${Ie({label:"Developer tools",rightHtml:'<span class="ax-pill">Send events from GitHub, GitLab, Sentry, etc.</span>'})}</div>
266
1278
  <div class="ax-connectors" id="ch-devtools"></div>
267
1279
 
268
1280
  <!-- Active-channel configuration panes. One shows at a time; clicking
@@ -280,7 +1292,7 @@ ${Qa}</script>`})}var Ka=`
280
1292
  </section>
281
1293
 
282
1294
  <section id="tab-crons" class="tab">
283
- ${N({icon:J.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."})}
1295
+ ${N({icon:V.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."})}
284
1296
  ${X({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."})}
285
1297
  <div id="cron-list" class="ax-stack" style="margin-bottom:22px"></div>
286
1298
 
@@ -378,13 +1390,13 @@ ${Qa}</script>`})}var Ka=`
378
1390
  </section>
379
1391
 
380
1392
  <section id="tab-webhooks" class="tab">
381
- ${N({icon:J.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."})}
1393
+ ${N({icon:V.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."})}
382
1394
  ${X({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.`})}
383
1395
  <div id="webhook-list" class="ax-stack"></div>
384
1396
  <div class="add-form">
385
1397
  <h3>Add a webhook</h3>
386
1398
  <div class="rowf">
387
- <div><label>Webhook id<span class="hint">(lowercase)</span></label><input id="w-id" placeholder="mtgl-gitlab" /></div>
1399
+ <div><label>Webhook id<span class="hint">(lowercase)</span></label><input id="w-id" placeholder="globex-gitlab" /></div>
388
1400
  <div><label>Source</label><select id="w-source"><option value="gitlab">GitLab \u2713</option><option value="github">GitHub \u2713</option><option value="sentry">Sentry \u2713</option><option value="stripe">Stripe \u2713</option><option value="vercel">Vercel \u2713</option><option value="odoo">Odoo \u2713</option><option value="hubspot">HubSpot \u2713</option><option value="discord">Discord</option><option value="slack">Slack</option><option value="custom">Custom</option></select></div>
389
1401
  </div>
390
1402
  <div class="rowf">
@@ -392,21 +1404,21 @@ ${Qa}</script>`})}var Ka=`
392
1404
  <div><label>Signing secret env-var<span class="hint">(optional)</span></label><input id="w-secret" placeholder="GITLAB_WEBHOOK_SECRET" /></div>
393
1405
  </div>
394
1406
  <label>Description<span class="hint">(optional)</span></label>
395
- <input id="w-desc" placeholder="MTGL main project webhooks" />
1407
+ <input id="w-desc" placeholder="Globex main project webhooks" />
396
1408
  <div class="actions"><button class="primary" onclick="addWebhook()">Add webhook</button><div id="w-msg" class="msg"></div></div>
397
1409
  </div>
398
1410
  </section>
399
1411
 
400
1412
  <section id="tab-mesh" class="tab">
401
- ${N({icon:J.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."})}
1413
+ ${N({icon:V.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."})}
402
1414
  <div id="mesh-hero" class="ax-mesh-hero"></div>
403
1415
  ${X({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."})}
404
- ${Ae({label:"Connected peers"})}
1416
+ ${Ie({label:"Connected peers"})}
405
1417
  <div id="mesh-peers" class="ax-stack"></div>
406
1418
  <div class="add-form">
407
1419
  <h3>Add a peer</h3>
408
1420
  <div class="rowf">
409
- <div><label>Peer name<span class="hint">(human label)</span></label><input id="m-name" placeholder="clawd-server" /></div>
1421
+ <div><label>Peer name<span class="hint">(human label)</span></label><input id="m-name" placeholder="peer-server" /></div>
410
1422
  <div><label>URL</label><input id="m-url" placeholder="http://192.168.1.50:18800" /></div>
411
1423
  </div>
412
1424
  <label>Auth token<span class="hint">(optional \u2014 use a scoped token with <code>mesh:peer</code>)</span></label>
@@ -428,7 +1440,7 @@ ${Qa}</script>`})}var Ka=`
428
1440
  </section>
429
1441
 
430
1442
  <section id="tab-business" class="tab">
431
- ${N({icon:J.tokens,title:"Business layer",lead:"Org chart, projects, and contact map \u2014 the data that drives PM gating and activity-graph attribution. Mirrors <code>agentx business</code>."})}
1443
+ ${N({icon:V.tokens,title:"Business layer",lead:"Org chart, projects, and contact map \u2014 the data that drives PM gating and activity-graph attribution. Mirrors <code>agentx business</code>."})}
432
1444
  ${X({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.'})}
433
1445
 
434
1446
  <div class="ax-stack" style="margin-top:14px">
@@ -457,16 +1469,38 @@ ${Qa}</script>`})}var Ka=`
457
1469
  <summary class="primary">+ Add or update project</summary>
458
1470
  <div style="margin-top:10px">
459
1471
  <label>Project id<span class="hint">(<code>owner/repo</code> for GitLab/GitHub; stable string for internal projects)</span></label>
460
- <input id="bp-id" placeholder="mtgl/system" />
1472
+ <input id="bp-id" placeholder="globex/system" />
461
1473
  <label>PM <span class="hint">(agentId \u2014 drives the PM gate)</span></label>
462
- <input id="bp-pm" placeholder="pm-mtgl" />
1474
+ <input id="bp-pm" placeholder="pm-globex" />
463
1475
  <label>Client <span class="hint">(used by the activity graph to attribute traffic)</span></label>
464
- <input id="bp-client" placeholder="mtgl" />
1476
+ <input id="bp-client" placeholder="globex" />
465
1477
  <div class="actions"><button class="primary" onclick="upsertProject()">Save project</button><div id="bp-msg" class="msg"></div></div>
466
1478
  </div>
467
1479
  </details>
468
1480
  </div>
469
1481
 
1482
+ <div class="ax-stack" style="margin-top:24px">
1483
+ <h3 style="margin:0 0 6px;font-size:13px">Clients</h3>
1484
+ <p class="hint" style="margin:0 0 8px">Clients are derived from projects and the contact map &mdash; one exists as soon as either mentions it. Everything below is optional: set it only when you want the monitor to treat a client differently.</p>
1485
+ <div id="business-client-list"></div>
1486
+ <details class="add-form" style="margin-top:10px">
1487
+ <summary class="primary">+ Configure a client</summary>
1488
+ <div style="margin-top:10px">
1489
+ <label>Client id<span class="hint">(as it already appears on a project or contact)</span></label>
1490
+ <input id="bc-id" placeholder="globex" />
1491
+ <label>Display name <span class="hint">(optional)</span></label>
1492
+ <input id="bc-name" placeholder="Globex" />
1493
+ <label>Kind <span class="hint">(client = someone waiting on you; own = your product; internal = machinery)</span></label>
1494
+ <select id="bc-kind"><option value="">(default)</option><option value="client">client</option><option value="own">own</option><option value="internal">internal</option></select>
1495
+ <label>Respond within <span class="hint">(<code>4h</code>, <code>90m</code>, <code>2d</code> &mdash; blank means no clock, delay stays flat)</span></label>
1496
+ <input id="bc-respond" placeholder="4h" />
1497
+ <label>Standing authorizations <span class="hint">(comma-separated; <code>*</code> for all. Ignored for kind <code>client</code> &mdash; agents never act unattended on a client's work)</span></label>
1498
+ <input id="bc-standing" placeholder="rebase-branch, open-followup-issue" />
1499
+ <div class="actions"><button class="primary" onclick="upsertClient()">Save client</button><div id="bc-msg" class="msg"></div></div>
1500
+ </div>
1501
+ </details>
1502
+ </div>
1503
+
470
1504
  <div class="ax-stack" style="margin-top:24px">
471
1505
  <h3 style="margin:0 0 6px;font-size:13px">Contact map</h3>
472
1506
  <div id="business-contact-list"></div>
@@ -478,15 +1512,15 @@ ${Qa}</script>`})}var Ka=`
478
1512
  <label>Chat id <span class="hint">(e.g. <code>-100\u2026</code>, JID \u2014 pick at least one of these three)</span></label>
479
1513
  <input id="bc-chatId" placeholder="-1003861455814" />
480
1514
  <label>Username</label>
481
- <input id="bc-username" placeholder="anis" />
1515
+ <input id="bc-username" placeholder="alex" />
482
1516
  <label>Sender id</label>
483
1517
  <input id="bc-senderId" placeholder="8500203323" />
484
1518
  <label>Client <span class="hint">(required)</span></label>
485
- <input id="bc-client" placeholder="noqta" />
1519
+ <input id="bc-client" placeholder="acme" />
486
1520
  <label>Project <span class="hint">(optional \u2014 defaults to <code>&lt;client&gt;/_chat</code>)</span></label>
487
- <input id="bc-project" placeholder="noqta/internal" />
1521
+ <input id="bc-project" placeholder="acme/internal" />
488
1522
  <label>Display name <span class="hint">(initiator pill override)</span></label>
489
- <input id="bc-displayName" placeholder="Anis Marrouchi" />
1523
+ <input id="bc-displayName" placeholder="Alex Rivera" />
490
1524
  <div class="actions"><button class="primary" onclick="upsertContact()">Save mapping</button><div id="bc-msg" class="msg"></div></div>
491
1525
  </div>
492
1526
  </details>
@@ -494,7 +1528,7 @@ ${Qa}</script>`})}var Ka=`
494
1528
  </section>
495
1529
 
496
1530
  <section id="tab-boards-cfg" class="tab">
497
- ${N({icon:J.tokens,title:"Kanban boards",lead:"Configure the boards rendered on the home page. Mirrors <code>agentx board add/edit/remove</code> + <code>agentx board column</code>. Source is GitLab today; backlog/wiki sources land when the schema unlocks them."})}
1531
+ ${N({icon:V.tokens,title:"Kanban boards",lead:"Configure the boards rendered on the home page. Mirrors <code>agentx board add/edit/remove</code> + <code>agentx board column</code>. Source is GitLab today; backlog/wiki sources land when the schema unlocks them."})}
498
1532
  ${X({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.'})}
499
1533
 
500
1534
  <div class="ax-stack" style="margin-top:14px">
@@ -503,12 +1537,12 @@ ${Qa}</script>`})}var Ka=`
503
1537
  <details class="add-form" style="margin-top:10px">
504
1538
  <summary class="primary">+ Add or update board</summary>
505
1539
  <div style="margin-top:10px">
506
- <label>Board id<span class="hint">(unique slug, e.g. <code>mtgl</code>)</span></label>
507
- <input id="bd-id" placeholder="mtgl" />
1540
+ <label>Board id<span class="hint">(unique slug, e.g. <code>globex</code>)</span></label>
1541
+ <input id="bd-id" placeholder="globex" />
508
1542
  <label>Display name</label>
509
- <input id="bd-name" placeholder="MTGL System" />
510
- <label>GitLab project paths<span class="hint">(comma-separated, e.g. <code>mtgl/system,mtgl/website</code>)</span></label>
511
- <input id="bd-projects" placeholder="mtgl/system" />
1543
+ <input id="bd-name" placeholder="Globex System" />
1544
+ <label>GitLab project paths<span class="hint">(comma-separated, e.g. <code>globex/system,globex/website</code>)</span></label>
1545
+ <input id="bd-projects" placeholder="globex/system" />
512
1546
  <label>Primary tool label <span class="hint">(optional \u2014 ANDed into every query, e.g. <code>Tool::Claude</code>)</span></label>
513
1547
  <input id="bd-label" placeholder="Tool::Claude" />
514
1548
  <div style="display:flex;gap:6px"><label style="flex:1">Open-window days<input id="bd-days" type="number" min="1" max="365" value="30" /></label><label style="flex:1">Closed-window days<input id="bd-closed-days" type="number" min="1" max="365" value="30" /></label></div>
@@ -519,7 +1553,7 @@ ${Qa}</script>`})}var Ka=`
519
1553
  </section>
520
1554
 
521
1555
  <section id="tab-actions" class="tab">
522
- ${N({icon:J.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. Mirrors <code>agentx actions</code>."})}
1556
+ ${N({icon:V.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. Mirrors <code>agentx actions</code>."})}
523
1557
  ${X({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."})}
524
1558
 
525
1559
  <div class="ax-stack" style="margin-top:14px">
@@ -575,7 +1609,7 @@ ${Qa}</script>`})}var Ka=`
575
1609
  </section>
576
1610
 
577
1611
  <section id="tab-tokens" class="tab">
578
- ${N({icon:J.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."})}
1612
+ ${N({icon:V.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."})}
579
1613
  ${X({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."})}
580
1614
  <div id="token-list" class="ax-stack"></div>
581
1615
  <div class="add-form">
@@ -595,7 +1629,7 @@ ${Qa}</script>`})}var Ka=`
595
1629
  </section>
596
1630
 
597
1631
  <section id="tab-advanced" class="tab">
598
- ${N({icon:J.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."})}
1632
+ ${N({icon:V.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."})}
599
1633
  ${X({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.`})}
600
1634
 
601
1635
  <div class="ax-jv-toolbar">
@@ -622,7 +1656,7 @@ ${Qa}</script>`})}var Ka=`
622
1656
  <div class="hint-block">The schema is documented at <code>docs/reference/config-schema.md</code>. Invalid JSON is refused; schema-level errors only surface after the daemon tries to use the new config.</div>
623
1657
  </section>
624
1658
  </main>
625
- `,Ya=`
1659
+ `,Tn=`
626
1660
 
627
1661
  /* --- Inner tabs (Agents / Channels / Schedules / \u2026) --- */
628
1662
  nav.tabs{display:flex;gap:4px;padding:14px 24px 0;background:var(--ax-bg-elev);
@@ -830,7 +1864,7 @@ textarea.raw{min-height:480px;font-family:var(--ax-mono);font-size:12px;line-hei
830
1864
  .peer-banner button{background:transparent;border:1px solid currentColor;color:var(--ax-accent);
831
1865
  padding:4px 10px;border-radius:4px;font:inherit;font-size:11px;cursor:pointer}
832
1866
  .peer-banner button:hover{background:color-mix(in oklch,var(--ax-accent) 12%,transparent)}
833
- `,Qa=`
1867
+ `,Cn=`
834
1868
  const $ = (id) => document.getElementById(id);
835
1869
  let state = null;
836
1870
 
@@ -1202,6 +2236,37 @@ function renderBusiness() {
1202
2236
  }
1203
2237
  }
1204
2238
 
2239
+ const clientsCfg = (state.business && state.business.clients) || {};
2240
+ // Show every client that resolves, not just the configured ones, so the
2241
+ // operator can see what exists before deciding to override anything.
2242
+ const derived = {};
2243
+ projects.forEach(function(p){ derived[p.client || (p.id.indexOf('/') > 0 ? p.id.slice(0, p.id.indexOf('/')) : p.id)] = true; });
2244
+ ((state.business && state.business.contactMap) || []).forEach(function(c){ if (c.client) derived[c.client] = true; });
2245
+ Object.keys(clientsCfg).forEach(function(id){ derived[id] = true; });
2246
+ const clientIds = Object.keys(derived).sort();
2247
+ const kl = $('business-client-list');
2248
+ if (kl) {
2249
+ if (clientIds.length === 0) {
2250
+ kl.innerHTML = '<div class="ax-empty-card" style="text-align:center;padding:18px;background:var(--ax-surface);border:1px dashed var(--ax-border-2);border-radius:6px;color:var(--ax-muted);font-size:12px">no clients yet &mdash; add a project or a contact mapping</div>';
2251
+ } else {
2252
+ kl.innerHTML = clientIds.map(function(id){
2253
+ const c = clientsCfg[id] || {};
2254
+ const tag = function(t){ return '<span style="font-size:11px;color:var(--ax-muted)">' + t + '</span>'; };
2255
+ const bits = [
2256
+ tag(c.kind ? 'kind=' + escapeHtml(c.kind) : 'kind=client (default)'),
2257
+ c.respondWithin ? tag('within=' + escapeHtml(c.respondWithin)) : '',
2258
+ (c.standing && c.standing.length) ? tag('standing=' + escapeHtml(c.standing.join(' '))) : '',
2259
+ c.name ? tag('"' + escapeHtml(c.name) + '"') : '',
2260
+ clientsCfg[id] ? '' : tag('derived'),
2261
+ ].filter(Boolean).join('');
2262
+ return '<div class="ax-row-card" style="display:flex;align-items:center;gap:10px;padding:8px 12px;border:1px solid var(--ax-border);border-radius:6px;margin-bottom:5px">' +
2263
+ '<div style="flex:1;min-width:0;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap"><code style="font-size:12px">' + escapeHtml(id) + '</code>' + bits + '</div>' +
2264
+ (clientsCfg[id] ? '<button class="ghost danger" data-act="biz-client-rm" data-id="' + escapeHtml(id) + '">Reset</button>' : '') +
2265
+ '</div>';
2266
+ }).join('');
2267
+ }
2268
+ }
2269
+
1205
2270
  const cl = $('business-contact-list');
1206
2271
  if (cl) {
1207
2272
  if (contactMap.length === 0) {
@@ -1240,6 +2305,11 @@ function wireBusinessHandlers() {
1240
2305
  if (!confirm('Remove project ' + id + '?')) return;
1241
2306
  try { await req('DELETE', '/api/admin/business/project', { id }); await load(); }
1242
2307
  catch (e) { showMsg($('global-msg'), 'err', e.message); }
2308
+ } else if (act === 'biz-client-rm') {
2309
+ const id = t.getAttribute('data-id');
2310
+ if (!confirm('Reset ' + id + ' to derived defaults?')) return;
2311
+ try { await req('DELETE', '/api/admin/business/client', { id }); await load(); }
2312
+ catch (e) { showMsg($('global-msg'), 'err', e.message); }
1243
2313
  } else if (act === 'biz-contact-rm') {
1244
2314
  const idx = parseInt(t.getAttribute('data-idx') || '-1', 10);
1245
2315
  const list = (state.business && state.business.contactMap) || [];
@@ -1271,6 +2341,23 @@ window.upsertOrgEntry = async function() {
1271
2341
  } catch (e) { showMsg($('bo-msg'), 'err', e.message); }
1272
2342
  }
1273
2343
 
2344
+ window.upsertClient = async function() {
2345
+ const id = $('bc-id').value.trim();
2346
+ const body = {
2347
+ id: id,
2348
+ name: $('bc-name').value.trim(),
2349
+ kind: $('bc-kind').value,
2350
+ respondWithin: $('bc-respond').value.trim(),
2351
+ standing: $('bc-standing').value.split(',').map(function(s){ return s.trim(); }).filter(Boolean),
2352
+ };
2353
+ try {
2354
+ await req('POST', '/api/admin/business/client', body);
2355
+ $('bc-id').value = ''; $('bc-name').value = ''; $('bc-respond').value = ''; $('bc-standing').value = '';
2356
+ showMsg($('bc-msg'), 'ok', 'Client saved');
2357
+ await load();
2358
+ } catch (e) { showMsg($('bc-msg'), 'err', e.message); }
2359
+ }
2360
+
1274
2361
  window.upsertProject = async function() {
1275
2362
  const id = $('bp-id').value.trim();
1276
2363
  const pm = $('bp-pm').value.trim();
@@ -1879,7 +2966,7 @@ function renderIntegrationsBlock(a) {
1879
2966
  '<div style="margin-top:10px;padding:8px 10px;background:var(--ax-bg);border:1px dashed var(--ax-border-2);border-radius:5px">' +
1880
2967
  '<div style="display:grid;grid-template-columns:1fr 1.5fr;gap:6px">' +
1881
2968
  '<select data-int-kind style="font-size:11px">' + kindOptions + '</select>' +
1882
- '<input data-int-label-add placeholder="Label (e.g. Noqta CRM, @cx_bot)" style="font-size:11px" />' +
2969
+ '<input data-int-label-add placeholder="Label (e.g. Acme CRM, @cx_bot)" style="font-size:11px" />' +
1883
2970
  '</div>' +
1884
2971
  '<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:6px">' +
1885
2972
  '<input data-int-tokenenv placeholder="Token env var (UPPERCASE)" style="font-size:11px" />' +
@@ -3501,11 +4588,11 @@ for (const btn of document.querySelectorAll('nav.tabs button')) {
3501
4588
  })();
3502
4589
 
3503
4590
  refresh();
3504
- `;function Lt(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(It({peers:a,localToken:n}))}async function Rt(t,e){let a=Be();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function Dt(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await fn(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await an(t),r={"GET /api/admin/state":()=>rn(),"POST /api/admin/agents":()=>pn(n),"PATCH /api/admin/agents":()=>un(n),"DELETE /api/admin/agents":()=>mn(n),"POST /api/admin/agents/access":()=>on(n),"POST /api/admin/channels/telegram":()=>hn(n),"DELETE /api/admin/channels/telegram":()=>Hn(n),"POST /api/admin/channels/telegram/toggle":()=>Nn(n),"POST /api/admin/crons":()=>Bn(n),"DELETE /api/admin/crons":()=>zn(n),"POST /api/admin/config/raw":()=>qn(n),"GET /api/admin/tokens":()=>sn(),"POST /api/admin/tokens":()=>ln(n),"DELETE /api/admin/tokens":()=>dn(n),"POST /api/admin/agents/test":()=>cn(n),"POST /api/admin/agents/integrations":()=>kn(n),"DELETE /api/admin/agents/integrations":()=>_n(n),"PATCH /api/admin/agents/integrations":()=>En(n),"PATCH /api/admin/channels/telegram":()=>gn(n),"POST /api/admin/channels/slack":()=>$n(n),"POST /api/admin/channels/slack/toggle":()=>jn(n),"POST /api/admin/channels/discord":()=>Ln(n),"POST /api/admin/channels/discord/toggle":()=>Rn(n),"POST /api/admin/channels/gitlab":()=>Dn(n),"POST /api/admin/channels/gitlab/toggle":()=>Pn(n),"GET /api/admin/channels/whatsapp/state":()=>he("/whatsapp/state"),"GET /api/admin/channels/webrtc/history":()=>he("/webrtc/history"),"POST /api/admin/actions":()=>Zn(n),"DELETE /api/admin/actions":()=>er(n),"POST /api/admin/actions/run":()=>tr(n),"GET /api/admin/channels/whatsapp/chats":()=>he("/whatsapp/chats"),"GET /api/admin/channels/whatsapp/contacts":()=>he("/whatsapp/contacts"),"POST /api/admin/channels/whatsapp/ingest":()=>ee("/whatsapp/ingest",n),"POST /api/admin/crons/preview":()=>On(n),"POST /api/admin/webhooks":()=>Sn(n),"PATCH /api/admin/webhooks":()=>Tn(n),"DELETE /api/admin/webhooks":()=>In(n),"POST /api/admin/mesh/peers":()=>Cn(n),"DELETE /api/admin/mesh/peers":()=>An(n),"POST /api/admin/mesh/toggle":()=>Mn(n),"GET /api/admin/files":()=>xn(t),"GET /api/admin/files/read":()=>vn(t),"PUT /api/admin/files":()=>bn(n),"POST /api/admin/files/skill":()=>yn(n),"DELETE /api/admin/files/skill":()=>wn(n),"POST /api/admin/business/orgchart":()=>Un(n),"DELETE /api/admin/business/orgchart":()=>Fn(n),"POST /api/admin/business/project":()=>Wn(n),"DELETE /api/admin/business/project":()=>Gn(n),"POST /api/admin/business/contact":()=>Xn(n),"DELETE /api/admin/business/contact":()=>Kn(n),"POST /api/admin/boards":()=>Jn(n),"DELETE /api/admin/boards":()=>Vn(n),"POST /api/admin/boards/columns":()=>Yn(n),"DELETE /api/admin/boards/columns":()=>Qn(n),"POST /api/admin/notifications":()=>nr(n),"POST /api/admin/webhooks/triggers":()=>rr(n),"POST /api/admin/mesh/health":()=>ar(n),"GET /api/admin/projects":()=>he("/api/admin/projects"),"POST /api/admin/projects/workflows/link":()=>ee("/api/admin/projects/workflows/link",n),"POST /api/admin/projects/workflows/unlink":()=>ee("/api/admin/projects/workflows/unlink",n),"POST /api/admin/projects/header":()=>ee("/api/admin/projects/header",n),"POST /api/admin/projects/clauses":()=>ee("/api/admin/projects/clauses",n),"POST /api/admin/projects/contacts/link":()=>ee("/api/admin/projects/contacts/link",n),"POST /api/admin/projects/contacts/unlink":()=>ee("/api/admin/projects/contacts/unlink",n),"POST /api/admin/projects/create":()=>ee("/api/admin/projects/create",n),"POST /api/admin/projects/delete":()=>ee("/api/admin/projects/delete",n)},o=`${t.method} ${a}`,s=r[o];if(!s){He(e,404,{error:`unknown admin endpoint: ${o}`});return}let i=await s();He(e,200,i)}catch(n){He(e,400,{error:n.message||"admin op failed"})}}function He(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function an(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 nn(t){let e=ce(process.cwd(),t);if(!Me(e))return[];let a=[];for(let n of tn(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".json")))try{a.push(JSON.parse($t(ce(e,n.name),"utf-8")))}catch{}return a}function Be(){let t=ce(process.cwd(),"agentx.json");return Me(t)?JSON.parse($t(t,"utf-8")):null}function rn(){let t=Be();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([c,m])=>({id:c,name:m.name,tier:m.tier,model:m.model,mentions:m.mentions||[],workspace:m.workspace,access:m.access||"private",systemPrompt:m.systemPrompt||"",maxConcurrent:m.maxConcurrent??1,maxExecutionMinutes:m.maxExecutionMinutes??20,permissionMode:m.permissionMode||"default",integrations:(Array.isArray(m.integrations)?m.integrations:[]).map(g=>{let x=g.credentials||{},h={};for(let[b,_]of Object.entries(x))typeof _=="string"&&/^[A-Z][A-Z0-9_]*$/.test(_)?h[b]=process.env[_]?"set":"unset":typeof _=="string"&&(h[b]="literal");return{kind:g.kind,label:g.label,enabled:g.enabled!==!1,credentials:x,credStatus:h,metadata:g.metadata||{}}})})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([c,m])=>({id:c,botUsername:m.botUsername||"",agentBinding:m.agentBinding||"",botTokenRef:m.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(([c,m])=>({id:c,schedule:m.schedule,agent:m.agent,prompt:(m.prompt||"").slice(0,200),enabled:m.enabled!==!1})),d=Array.isArray(t.webhooks)?t.webhooks.map(c=>({id:c.id,source:c.source,agentId:c.agentId,secretEnv:c.secretEnv||"",description:c.description||"",enabled:c.enabled!==!1,triggers:c.triggers&&typeof c.triggers=="object"?c.triggers:{},defaultWorkflow:c.defaultWorkflow||""})):[],p={enabled:!!t.mesh?.enabled,discovery:t.mesh?.discovery||"static",peers:(t.mesh?.peers||[]).map(c=>({url:c.url,name:c.name,hasToken:!!c.token})),healthCheck:{interval:t.mesh?.healthCheck?.interval??60,timeout:t.mesh?.healthCheck?.timeout??10}},u=t.dashboard?.daemonUrl||"http://localhost:18800",f=t.business||{},v={enabled:!!f.enabled,timezone:f.timezone||"UTC",orgChart:f.orgChart||{},projects:Array.isArray(f.projects)?f.projects:[],contactMap:Array.isArray(f.contactMap)?f.contactMap:[]},k=t.notifications||{},A={longTaskThreshold:k.longTaskThreshold??30,destination:k.destination||null,on:{taskComplete:k.on?.taskComplete!==!1,taskError:k.on?.taskError!==!1,taskQueued:!!k.on?.taskQueued}},E=[];try{E=nn(".agentx/actions").filter(m=>m&&typeof m=="object"&&m.id).map(m=>({id:m.id,title:m.title,kind:m.kind,description:m.description||"",inputs:Array.isArray(m.inputs)?m.inputs:[],timeoutMs:m.timeoutMs??3e4,command:m.kind==="shell"?m.command:void 0,url:m.kind==="http"?m.url:void 0,method:m.kind==="http"?m.method:void 0})).sort((m,g)=>m.id.localeCompare(g.id))}catch{}let S=(Array.isArray(t.boards)?t.boards:[]).map(c=>({id:c.id,name:c.name,source:c.source||{type:"gitlab",projects:[]},primaryToolLabel:c.primaryToolLabel||"",timeRangeDays:c.timeRangeDays??30,closedWindowDays:c.closedWindowDays??30,columns:Array.isArray(c.columns)?c.columns:[]}));return{exists:!0,agents:e,telegram:n,slack:r,discord:o,gitlab:s,whatsapp:i,crons:l,webhooks:d,mesh:p,daemonUrl:u,nodeName:t.node?.name,business:v,boards:S,notifications:A,actions:E}}function on(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 sn(){return new Z().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 ln(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 Z().create({name:e,scopes:a,expiresInDays:n});return{summary:`created token "${e}"`,token:r,record:o}}function dn(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Token id is required.");let a=new Z().revoke(e);if(!a)throw new Error(`Token "${e}" not found.`);return{summary:`revoked token ${e} (${a.name})`}}async function cn(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=G();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(),d;try{d=JSON.parse(l)}catch{d={content:l}}if(!i.ok)throw new Error(d?.error||`daemon HTTP ${i.status}`);return{chatId:n,response:d}}function pn(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=Ot(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=ce(process.cwd(),"agents",e),{summary:l}=C(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}"`}),d=ce(i,"CLAUDE.md");if(!Me(d))try{Za(i,{recursive:!0}),jt(d,`# ${a}
4591
+ `;function Vt(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Xt({peers:a,localToken:n}))}async function Yt(t,e){let a=Ye();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function Qt(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await Fn(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await $n(t),r={"GET /api/admin/state":()=>Ln(),"POST /api/admin/agents":()=>Nn(n),"PATCH /api/admin/agents":()=>Bn(n),"DELETE /api/admin/agents":()=>zn(n),"POST /api/admin/agents/access":()=>Rn(n),"POST /api/admin/channels/telegram":()=>qn(n),"DELETE /api/admin/channels/telegram":()=>ur(n),"POST /api/admin/channels/telegram/toggle":()=>mr(n),"POST /api/admin/crons":()=>hr(n),"DELETE /api/admin/crons":()=>gr(n),"POST /api/admin/config/raw":()=>fr(n),"GET /api/admin/tokens":()=>Pn(),"POST /api/admin/tokens":()=>Dn(n),"DELETE /api/admin/tokens":()=>On(n),"POST /api/admin/agents/test":()=>Hn(n),"POST /api/admin/agents/integrations":()=>Vn(n),"DELETE /api/admin/agents/integrations":()=>Yn(n),"PATCH /api/admin/agents/integrations":()=>Qn(n),"PATCH /api/admin/channels/telegram":()=>Un(n),"POST /api/admin/channels/slack":()=>or(n),"POST /api/admin/channels/slack/toggle":()=>sr(n),"POST /api/admin/channels/discord":()=>ir(n),"POST /api/admin/channels/discord/toggle":()=>lr(n),"POST /api/admin/channels/gitlab":()=>dr(n),"POST /api/admin/channels/gitlab/toggle":()=>cr(n),"GET /api/admin/channels/whatsapp/state":()=>be("/whatsapp/state"),"GET /api/admin/channels/webrtc/history":()=>be("/webrtc/history"),"POST /api/admin/actions":()=>Mr(n),"DELETE /api/admin/actions":()=>Ir(n),"POST /api/admin/actions/run":()=>$r(n),"GET /api/admin/channels/whatsapp/chats":()=>be("/whatsapp/chats"),"GET /api/admin/channels/whatsapp/contacts":()=>be("/whatsapp/contacts"),"POST /api/admin/channels/whatsapp/ingest":()=>te("/whatsapp/ingest",n),"POST /api/admin/crons/preview":()=>pr(n),"POST /api/admin/webhooks":()=>Zn(n),"PATCH /api/admin/webhooks":()=>er(n),"DELETE /api/admin/webhooks":()=>rr(n),"POST /api/admin/mesh/peers":()=>tr(n),"DELETE /api/admin/mesh/peers":()=>ar(n),"POST /api/admin/mesh/toggle":()=>nr(n),"GET /api/admin/files":()=>Wn(t),"GET /api/admin/files/read":()=>Gn(t),"PUT /api/admin/files":()=>Xn(n),"POST /api/admin/files/skill":()=>Kn(n),"DELETE /api/admin/files/skill":()=>Jn(n),"POST /api/admin/business/orgchart":()=>xr(n),"DELETE /api/admin/business/orgchart":()=>vr(n),"POST /api/admin/business/project":()=>br(n),"DELETE /api/admin/business/project":()=>kr(n),"POST /api/admin/business/client":()=>yr(n),"DELETE /api/admin/business/client":()=>wr(n),"POST /api/admin/business/contact":()=>_r(n),"DELETE /api/admin/business/contact":()=>Er(n),"POST /api/admin/boards":()=>Sr(n),"DELETE /api/admin/boards":()=>Tr(n),"POST /api/admin/boards/columns":()=>Cr(n),"DELETE /api/admin/boards/columns":()=>Ar(n),"POST /api/admin/notifications":()=>Lr(n),"POST /api/admin/webhooks/triggers":()=>Rr(n),"POST /api/admin/mesh/health":()=>jr(n),"GET /api/admin/projects":()=>be("/api/admin/projects"),"POST /api/admin/projects/workflows/link":()=>te("/api/admin/projects/workflows/link",n),"POST /api/admin/projects/workflows/unlink":()=>te("/api/admin/projects/workflows/unlink",n),"POST /api/admin/projects/header":()=>te("/api/admin/projects/header",n),"POST /api/admin/projects/clauses":()=>te("/api/admin/projects/clauses",n),"POST /api/admin/projects/contacts/link":()=>te("/api/admin/projects/contacts/link",n),"POST /api/admin/projects/contacts/unlink":()=>te("/api/admin/projects/contacts/unlink",n),"POST /api/admin/projects/create":()=>te("/api/admin/projects/create",n),"POST /api/admin/projects/delete":()=>te("/api/admin/projects/delete",n)},o=`${t.method} ${a}`,s=r[o];if(!s){Je(e,404,{error:`unknown admin endpoint: ${o}`});return}let l=await s();Je(e,200,l)}catch(n){Je(e,400,{error:n.message||"admin op failed"})}}function Je(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function $n(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 jn(t){let e=he(process.cwd(),t);if(!Le(e))return[];let a=[];for(let n of In(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".json")))try{a.push(JSON.parse(Kt(he(e,n.name),"utf-8")))}catch{}return a}function Ye(){let t=he(process.cwd(),"agentx.json");return Le(t)?JSON.parse(Kt(t,"utf-8")):null}function Ln(){let t=Ye();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([d,p])=>({id:d,name:p.name,tier:p.tier,model:p.model,mentions:p.mentions||[],workspace:p.workspace,access:p.access||"private",systemPrompt:p.systemPrompt||"",maxConcurrent:p.maxConcurrent??1,maxExecutionMinutes:p.maxExecutionMinutes??20,permissionMode:p.permissionMode||"default",integrations:(Array.isArray(p.integrations)?p.integrations:[]).map(g=>{let f=g.credentials||{},h={};for(let[y,k]of Object.entries(f))typeof k=="string"&&/^[A-Z][A-Z0-9_]*$/.test(k)?h[y]=process.env[k]?"set":"unset":typeof k=="string"&&(h[y]="literal");return{kind:g.kind,label:g.label,enabled:g.enabled!==!1,credentials:f,credStatus:h,metadata:g.metadata||{}}})})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([d,p])=>({id:d,botUsername:p.botUsername||"",agentBinding:p.agentBinding||"",botTokenRef:p.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},l={enabled:!!t.channels?.whatsapp?.enabled,sessionDir:t.channels?.whatsapp?.sessionDir||".agentx/whatsapp-sessions",routeCount:Array.isArray(t.channels?.whatsapp?.routes)?t.channels.whatsapp.routes.length:0},i=Object.entries(t.crons||{}).map(([d,p])=>({id:d,schedule:p.schedule,agent:p.agent,prompt:(p.prompt||"").slice(0,200),enabled:p.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||""})):[],u={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}},m=t.dashboard?.daemonUrl||"http://localhost:18800",x=t.business||{},b={enabled:!!x.enabled,timezone:x.timezone||"UTC",orgChart:x.orgChart||{},projects:Array.isArray(x.projects)?x.projects:[],contactMap:Array.isArray(x.contactMap)?x.contactMap:[],clients:x.clients&&typeof x.clients=="object"?x.clients:{}},_=t.notifications||{},M={longTaskThreshold:_.longTaskThreshold??30,destination:_.destination||null,on:{taskComplete:_.on?.taskComplete!==!1,taskError:_.on?.taskError!==!1,taskQueued:!!_.on?.taskQueued}},E=[];try{E=jn(".agentx/actions").filter(p=>p&&typeof p=="object"&&p.id).map(p=>({id:p.id,title:p.title,kind:p.kind,description:p.description||"",inputs:Array.isArray(p.inputs)?p.inputs:[],timeoutMs:p.timeoutMs??3e4,command:p.kind==="shell"?p.command:void 0,url:p.kind==="http"?p.url:void 0,method:p.kind==="http"?p.method:void 0})).sort((p,g)=>p.id.localeCompare(g.id))}catch{}let S=(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:l,crons:i,webhooks:c,mesh:u,daemonUrl:m,nodeName:t.node?.name,business:b,boards:S,notifications:M,actions:E}}function Rn(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}=T(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 Pn(){return new ee().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 Dn(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 ee().create({name:e,scopes:a,expiresInDays:n});return{summary:`created token "${e}"`,token:r,record:o}}function On(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Token id is required.");let a=new ee().revoke(e);if(!a)throw new Error(`Token "${e}" not found.`);return{summary:`revoked token ${e} (${a.name})`}}async function Hn(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 u=G();r=u.dashboard.daemonUrl.replace(/\/+$/,"")||r,o=u.dashboard.token}catch{}let s={"Content-Type":"application/json"};o&&(s.Authorization=`Bearer ${o}`);let l=await fetch(`${r}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"test-drive",sender:"admin",chatId:n}})}),i=await l.text(),c;try{c=JSON.parse(i)}catch{c={content:i}}if(!l.ok)throw new Error(c?.error||`daemon HTTP ${l.status}`);return{chatId:n,response:c}}function Nn(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=ea(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 l=he(process.cwd(),"agents",e),{summary:i}=T(u=>{if(u.agents=u.agents||{},u.agents[e])throw new Error(`Agent "${e}" already exists.`);let m={name:a,workspace:l,tier:n,mentions:r,maxConcurrent:2,permissionMode:"default"};return o&&(m.model=o),s&&(m.systemPrompt=s.slice(0,400)),u.agents[e]=m,`added agent "${e}"`}),c=he(l,"CLAUDE.md");if(!Le(c))try{An(l,{recursive:!0}),Jt(c,`# ${a}
3505
4592
 
3506
4593
  ${s||"You are "+a+"."}
3507
- `)}catch{}return{summary:l}}function un(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=Ot(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 mn(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 hn(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 gn(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 he(t){let{url:e,headers:a}=ze(),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 ee(t,e){let{url:a,headers:n}=ze(),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 fn(t,e){try{let{url:a,headers:n}=ze(),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 ze(){let t="http://127.0.0.1:18800",e={};try{let a=G();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function ge(t){let a=Be()?.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 Ne(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function xn(t){let e=Ne(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=de(ge(e));return{agentId:e,...a}}function vn(t){let e=Ne(t,"agent").trim(),a=Ne(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return we(ge(e),a)}function bn(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=ke(ge(e),a,n);return{summary:`saved ${a} (${r.bytes} bytes)`,...r}}function yn(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=_e(ge(e),a,{title:n,content:r});return{summary:`added skill "${a}"`,...o}}function wn(t){let e=String(t?.agent||"").trim(),a=String(t?.slug||"").trim();if(!e||!a)throw new Error("agent and slug are required.");let n=Ee(ge(e),a);return{summary:`removed skill "${a}"`,...n}}function kn(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 d=o[l];if(typeof d=="string"&&d.trim()){if(!/^[A-Z][A-Z0-9_]*$/.test(d.trim()))throw new Error(`${l} must be uppercase identifier (got "${d}")`);r[l]=d.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,d]of Object.entries(t?.metadata||{}))(typeof d=="string"||typeof d=="number"||typeof d=="boolean")&&(s[l]=d);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(d=>d.kind===a&&d.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 _n(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(d=>d.kind===a&&d.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 En(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 d=(i.integrations||[]).find(p=>p.kind===a&&p.label===n);if(!d)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return typeof r.enabled=="boolean"&&(d.enabled=r.enabled),r.metadata&&typeof r.metadata=="object"&&(d.metadata={...d.metadata||{},...r.metadata}),`updated integration (${a}, ${n}) on ${e}`});return{summary:o}}var Pt=["gitlab","github","sentry","stripe","vercel","odoo","hubspot","discord","slack","custom"];function Sn(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(!Pt.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(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 d={id:e,source:a,agentId:n,enabled:!0};return r&&(d.secretEnv=r),o&&(d.description=o),s&&(d.node=s),l.webhooks.push(d),`added webhook "${e}" (${a} \u2192 ${n}${s?` @ ${s}`:""})`});return{summary:i}}function Tn(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"&&Pt.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 Cn(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 An(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 Mn(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 In(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 $n(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 jn(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 Ln(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 Rn(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 Dn(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 Pn(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 On(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-6T2SU5ST.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 Hn(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 Nn(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 Bn(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 zn(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 qn(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=ce(process.cwd(),"agentx.json"),r=`${n}.bak.${Date.now()}`;if(Me(n))try{en(n,r)}catch{}jt(n,JSON.stringify(a,null,2)+`
3508
- `,"utf-8");try{let s=G().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 Ot(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}async function Un(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(d=>(d.business=d.business||{},d.business.orgChart=d.business.orgChart||{},d.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 Fn(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 Wn(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 Gn(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 Xn(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 Kn(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 Jn(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 d=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),d>=0){let u=l.boards[d];return l.boards[d]={...u,...p,columns:u.columns,labels:u.labels},`board "${e}" updated`}return l.boards.push(p),`board "${e}" added`});return{summary:i}}async function Vn(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 Yn(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(u=>u.id===e);if(!l)throw new Error(`board "${e}" not found`);l.columns=Array.isArray(l.columns)?l.columns:[];let d={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");d.scopedLabel=String(t.scopedLabel)}if(r==="label"){if(!t?.mapsToLabel)throw new Error("mapsToLabel required for kind=label");d.mapsToLabel=String(t.mapsToLabel)}t?.accent&&(d.accent=String(t.accent));let p=l.columns.findIndex(u=>u.id===a);return p>=0?(l.columns[p]={...l.columns[p],...d},`column "${a}" updated`):(l.columns.push(d),`column "${a}" added to board "${e}"`)});return{summary:o}}async function Qn(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 Zn(t){let{ActionStore:e}=await import("./store-I3HEWVLQ.js"),{actionSchema:a}=await import("./types-Y6ZCZ52Z.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 er(t){let{ActionStore:e}=await import("./store-I3HEWVLQ.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 tr(t){let{ActionStore:e}=await import("./store-I3HEWVLQ.js"),{runAction:a}=await import("./runner-BFYDWPUO.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 ar(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 nr(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`)}}if(n.length===0)throw new Error("nothing to update");return`notifications updated (${n.join(", ")})`});return{summary:e}}async function rr(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}}import{resolve as ir}from"path";function Ht(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div id="msg" class="msg"></div>
4594
+ `)}catch{}return{summary:i}}function Bn(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let a=t?.patch||{},{summary:n}=T(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=ea(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 zn(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let{summary:a}=T(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 qn(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}=T(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 Un(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let a=t?.patch||{},{summary:n}=T(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 be(t){let{url:e,headers:a}=Qe(),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 te(t,e){let{url:a,headers:n}=Qe(),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 Fn(t,e){try{let{url:a,headers:n}=Qe(),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 Qe(){let t="http://127.0.0.1:18800",e={};try{let a=G();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function ye(t){let a=Ye()?.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 Ve(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function Wn(t){let e=Ve(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=ue(ye(e));return{agentId:e,...a}}function Gn(t){let e=Ve(t,"agent").trim(),a=Ve(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return _e(ye(e),a)}function Xn(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=Ee(ye(e),a,n);return{summary:`saved ${a} (${r.bytes} bytes)`,...r}}function Kn(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=Se(ye(e),a,{title:n,content:r});return{summary:`added skill "${a}"`,...o}}function Jn(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=Te(ye(e),a);return{summary:`removed skill "${a}"`,...n}}function Vn(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 i of["tokenEnv","privateAppTokenEnv","apiKeyEnv","refreshTokenEnv","clientIdEnv","clientSecretEnv"]){let c=o[i];if(typeof c=="string"&&c.trim()){if(!/^[A-Z][A-Z0-9_]*$/.test(c.trim()))throw new Error(`${i} must be uppercase identifier (got "${c}")`);r[i]=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[i,c]of Object.entries(t?.metadata||{}))(typeof c=="string"||typeof c=="number"||typeof c=="boolean")&&(s[i]=c);let{summary:l}=T(i=>{if(!i.agents?.[e])throw new Error(`Unknown agent "${e}"`);if(i.agents[e].integrations=Array.isArray(i.agents[e].integrations)?i.agents[e].integrations:[],i.agents[e].integrations.find(c=>c.kind===a&&c.label===n))throw new Error(`integration (${a}, ${n}) already exists on ${e}`);return i.agents[e].integrations.push({kind:a,label:n,credentials:r,metadata:s,enabled:!0}),`added ${a} integration "${n}" to ${e}`});return{summary:l}}function Yn(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}=T(o=>{let s=o.agents?.[e];if(!s)throw new Error(`Unknown agent "${e}"`);let l=s.integrations||[],i=l.findIndex(c=>c.kind===a&&c.label===n);if(i===-1)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return l.splice(i,1),`removed ${a} integration "${n}" from ${e}`});return{summary:r}}function Qn(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}=T(s=>{let l=s.agents?.[e];if(!l)throw new Error(`Unknown agent "${e}"`);let c=(l.integrations||[]).find(u=>u.kind===a&&u.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 Zt=["gitlab","github","sentry","stripe","vercel","odoo","hubspot","discord","slack","custom"];function Zn(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(!Zt.includes(a))throw new Error(`Unknown source: ${a}`);if(!n)throw new Error("Pick an agent to bind the webhook to.");let{summary:l}=T(i=>{if(s){if(!(i.mesh?.peers||[]).find(m=>m.name===s))throw new Error(`Mesh peer "${s}" not found in mesh.peers. Add the peer first or remove the node field.`)}else if(!i.agents?.[n])throw new Error(`Unknown agent "${n}". Add it locally, or set --node <peer> to forward to a mesh peer.`);if(i.webhooks=Array.isArray(i.webhooks)?i.webhooks:[],i.webhooks.find(u=>u.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),i.webhooks.push(c),`added webhook "${e}" (${a} \u2192 ${n}${s?` @ ${s}`:""})`});return{summary:l}}function er(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let a=t?.patch||{},{summary:n}=T(r=>{let o=(r.webhooks||[]).find(s=>s.id===e);if(!o)throw new Error(`Webhook "${e}" not found.`);if(typeof a.source=="string"&&Zt.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 tr(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}=T(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(l=>l.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 ar(t){let e=String(t?.url||"").trim().replace(/\/+$/,"");if(!e)throw new Error("Peer URL is required.");let{summary:a}=T(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 nr(t){let e=!!t?.enabled,{summary:a}=T(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 rr(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let{summary:a}=T(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 or(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}=T(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 sr(t){let e=!!t?.enabled,{summary:a}=T(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 ir(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}=T(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 lr(t){let e=!!t?.enabled,{summary:a}=T(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 dr(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}=T(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 cr(t){let e=!!t?.enabled,{summary:a}=T(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 pr(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-GZZAN6ZG.js"),n;try{n=(await import("cronstrue")).default.toString(e,{use24HourTimeFormat:!1})}catch(l){throw new Error(`Invalid cron: ${l.message||"unknown"}`)}let r=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC",o=[],s=new Date;try{for(let l=0;l<3;l++)s=a(e,s,r),o.push(s.toISOString())}catch(l){throw new Error(`Cron preview failed: ${l.message}`)}return{human:n,next:o,timezone:r}}function ur(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let{summary:a}=T(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 mr(t){let e=!!t?.enabled,{summary:a}=T(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 hr(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}=T(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 gr(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Cron id is required.");let{summary:a}=T(n=>{if(!n.crons?.[e])throw new Error(`Cron "${e}" not found.`);return delete n.crons[e],`removed cron "${e}"`});return{summary:a}}function fr(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=he(process.cwd(),"agentx.json"),r=`${n}.bak.${Date.now()}`;if(Le(n))try{Mn(n,r)}catch{}Jt(n,JSON.stringify(a,null,2)+`
4595
+ `,"utf-8");try{let s=G().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 ea(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}async function xr(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():"",l=typeof t?.utilizationTarget=="number"?t.utilizationTarget:.8,{summary:i}=T(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:l},`orgChart "${e}" upserted`));return{summary:i}}async function vr(t){let e=String(t?.agentId||"").trim();if(!e)throw new Error("agentId required");let{summary:a}=T(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 br(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}=T(o=>{o.business=o.business||{},o.business.projects=o.business.projects||[];let s=o.business.projects.findIndex(i=>i.id===e),l={id:e,...a?{pm:a}:{},...n?{client:n}:{}};return s>=0?o.business.projects[s]={...o.business.projects[s],...l}:o.business.projects.push(l),s>=0?`project "${e}" updated`:`project "${e}" added`});return{summary:r}}async function yr(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}=T(s=>{s.business=s.business||{},s.business.clients=s.business.clients||{};let l=!!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},l?`client "${e}" updated`:`client "${e}" configured`});return{summary:o}}async function wr(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let{summary:a}=T(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 kr(t){let e=String(t?.id||"").trim();if(!e)throw new Error("project id required");let{summary:a}=T(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 _r(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}=T(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 Er(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}=T(r=>{let o=r.business?.contactMap||[],s=o.length;if(r.business.contactMap=o.filter(l=>{for(let i of a)if(l[i]!==t[i])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 Sr(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=String(t?.projects||"").split(/[,\n]/).map(i=>i.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:l}=T(i=>{i.boards=Array.isArray(i.boards)?i.boards:[];let c=i.boards.findIndex(m=>m.id===e),u={id:e,name:a,source:{type:"gitlab",projects:n},timeRangeDays:o,closedWindowDays:s};if(r&&(u.primaryToolLabel=r),c>=0){let m=i.boards[c];return i.boards[c]={...m,...u,columns:m.columns,labels:m.labels},`board "${e}" updated`}return i.boards.push(u),`board "${e}" added`});return{summary:l}}async function Tr(t){let e=String(t?.id||"").trim();if(!e)throw new Error("id required");let{summary:a}=T(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 Cr(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}=T(s=>{let i=(Array.isArray(s.boards)?s.boards:[]).find(m=>m.id===e);if(!i)throw new Error(`board "${e}" not found`);i.columns=Array.isArray(i.columns)?i.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 u=i.columns.findIndex(m=>m.id===a);return u>=0?(i.columns[u]={...i.columns[u],...c},`column "${a}" updated`):(i.columns.push(c),`column "${a}" added to board "${e}"`)});return{summary:o}}async function Ar(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}=T(r=>{let s=(Array.isArray(r.boards)?r.boards:[]).find(i=>i.id===e);if(!s)throw new Error(`board "${e}" not found`);let l=(s.columns||[]).length;if(s.columns=(s.columns||[]).filter(i=>i.id!==a),s.columns.length===l)throw new Error(`column "${a}" not found`);return`column "${a}" removed from board "${e}"`});return{summary:n}}async function Mr(t){let{ActionStore:e}=await import("./store-MCOA6N4F.js"),{actionSchema:a}=await import("./types-H5ENIUIT.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 Ir(t){let{ActionStore:e}=await import("./store-MCOA6N4F.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 $r(t){let{ActionStore:e}=await import("./store-MCOA6N4F.js"),{runAction:a}=await import("./runner-YRBVNYTY.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 jr(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}=T(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 Lr(t){let{summary:e}=T(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`)}}if(n.length===0)throw new Error("nothing to update");return`notifications updated (${n.join(", ")})`});return{summary:e}}async function Rr(t){let e=String(t?.id||"").trim();if(!e)throw new Error("webhook id required");let{summary:a}=T(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[l,i]of Object.entries(t.triggers))typeof i=="string"&&i.trim()&&(s[String(l)]=i.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}}Ne();import{resolve as Or}from"path";function ta(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div id="msg" class="msg"></div>
3509
4596
 
3510
4597
  <div id="disabled-banner" class="banner warn" style="display:none">
3511
4598
  <b>Graph is disabled.</b> Set <code class="mono">graph.enabled: true</code>
@@ -3535,7 +4622,7 @@ ${s||"You are "+a+"."}
3535
4622
  <summary>Add node</summary>
3536
4623
  <div class="row" style="margin-top:10px">
3537
4624
  <select id="n-level"></select>
3538
- <input id="n-id" placeholder="node id (e.g. noqta-devops)" />
4625
+ <input id="n-id" placeholder="node id (e.g. acme-devops)" />
3539
4626
  <select id="n-parent"><option value="">\u2014 no parent \u2014</option></select>
3540
4627
  </div>
3541
4628
  <div class="row" style="margin-top:6px">
@@ -3560,7 +4647,7 @@ ${s||"You are "+a+"."}
3560
4647
  <h2>Recent classifications</h2>
3561
4648
  <p class="muted">Last 25 log rows, newest first \u2014 approved / pending / rejected.</p>
3562
4649
  <div id="recent"></div>
3563
- </section>`;return M({title:"AgentX \xB7 Intent Graph",activeTab:"graph",subtitle:"Intent Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:or,scripts:`${e}<script>${sr}</script>`})}var or=`
4650
+ </section>`;return C({title:"AgentX \xB7 Intent Graph",activeTab:"graph",subtitle:"Intent Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Pr,scripts:`${e}<script>${Dr}</script>`})}var Pr=`
3564
4651
  main { max-width: 1200px; margin: 0 auto; padding: 24px 20px 60px; }
3565
4652
  h2 { margin: 0 0 12px; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
3566
4653
  .grid { display: grid; gap: 20px; grid-template-columns: 1fr; }
@@ -3664,7 +4751,7 @@ details {
3664
4751
  border-radius: 4px; padding: 8px 12px; margin-top: 8px;
3665
4752
  }
3666
4753
  details summary { cursor: pointer; font-size: 11px; color: var(--ax-muted); user-select: none; }
3667
- details[open] summary { margin-bottom: 8px; }`,sr=`
4754
+ details[open] summary { margin-bottom: 8px; }`,Dr=`
3668
4755
  const $ = (id) => document.getElementById(id);
3669
4756
  const state = { schema: null, nodes: [], pending: [], recent: [] };
3670
4757
 
@@ -3884,7 +4971,7 @@ $('btn-save-schema').addEventListener('click', async () => {
3884
4971
  $('btn-reload-schema').addEventListener('click', refresh);
3885
4972
 
3886
4973
  refresh();
3887
- `;function Bt(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ht({peers:a,localToken:n}))}async function zt(t,e,a){try{let n=t.method==="GET"?void 0:await fr(t),r=lr(),o={"GET /api/admin/graph/state":()=>dr(r),"POST /api/admin/graph/classifications/approve":()=>cr(r,n),"POST /api/admin/graph/classifications/reject":()=>pr(r,n),"POST /api/admin/graph/nodes":()=>ur(r,n),"PATCH /api/admin/graph/nodes":()=>mr(r,n),"DELETE /api/admin/graph/nodes":()=>hr(r,n),"PUT /api/admin/graph/schema":()=>gr(r,n)},s=`${t.method} ${a}`,i=o[s];if(!i){qe(e,404,{error:`unknown graph endpoint: ${s}`});return}let l=await i();qe(e,200,l)}catch(n){qe(e,400,{error:n?.message||"graph op failed"})}}function lr(){let t=G(),e=ir(process.cwd(),t.graph.baseDir);return new at({baseDir:e})}function dr(t){let e=G(),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 cr(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=qt(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=Ue(e.proposedAxes)),t.approveClassification(n),{summary:`Approved ${n.msgHash}`}}function pr(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=qt(t,a);return t.rejectClassification(n),{summary:`Rejected ${n.msgHash}`}}function qt(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 ur(t,e){let a=Nt(String(e?.id||"")),n=String(e?.level||"").trim(),r=e?.parentId?Nt(String(e.parentId)):null,o=Ue({[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 mr(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");let n=Ue({[a]:e?.axes||{}})[a]||{};return{node:t.updateNodeAxes(a,n)}}function hr(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");return t.deleteNode(a),{summary:`Deleted ${a}`}}function gr(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 Ue(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 Nt(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")}function qe(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function fr(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)})}import{resolve as br}from"path";import{existsSync as yr}from"fs";import wr from"better-sqlite3";function Ut(t={}){let e=`<div class="ax-obs">
4974
+ `;function na(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ta({peers:a,localToken:n}))}async function ra(t,e,a){try{let n=t.method==="GET"?void 0:await Gr(t),r=Hr(),o={"GET /api/admin/graph/state":()=>Nr(r),"POST /api/admin/graph/classifications/approve":()=>Br(r,n),"POST /api/admin/graph/classifications/reject":()=>zr(r,n),"POST /api/admin/graph/nodes":()=>qr(r,n),"PATCH /api/admin/graph/nodes":()=>Ur(r,n),"DELETE /api/admin/graph/nodes":()=>Fr(r,n),"PUT /api/admin/graph/schema":()=>Wr(r,n)},s=`${t.method} ${a}`,l=o[s];if(!l){Ze(e,404,{error:`unknown graph endpoint: ${s}`});return}let i=await l();Ze(e,200,i)}catch(n){Ze(e,400,{error:n?.message||"graph op failed"})}}function Hr(){let t=G(),e=Or(process.cwd(),t.graph.baseDir);return new gt({baseDir:e})}function Nr(t){let e=G(),a=t.loadSchema(),n=t.loadNodes().nodes,r=t.readRecentClassifications(100),o=t.loadIndex().entries,s=new Map;for(let i of r)s.has(i.msgHash)||s.set(i.msgHash,i);let l=[];for(let i of s.values())i.status==="pending"&&!o[i.msgHash]&&l.push(i);return{enabled:e.graph.enabled,schema:a,nodes:n,pending:l,recent:r.slice(0,25),counts:{nodes:n.length,pending:l.length,fingerprints:Object.keys(o).length}}}function Br(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=oa(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=et(e.proposedAxes)),t.approveClassification(n),{summary:`Approved ${n.msgHash}`}}function zr(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=oa(t,a);return t.rejectClassification(n),{summary:`Rejected ${n.msgHash}`}}function oa(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 qr(t,e){let a=aa(String(e?.id||"")),n=String(e?.level||"").trim(),r=e?.parentId?aa(String(e.parentId)):null,o=et({[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 Ur(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");let n=et({[a]:e?.axes||{}})[a]||{};return{node:t.updateNodeAxes(a,n)}}function Fr(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");return t.deleteNode(a),{summary:`Deleted ${a}`}}function Wr(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 et(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 aa(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")}function Ze(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Gr(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)})}import{resolve as Jr}from"path";import{existsSync as Vr}from"fs";import Yr from"better-sqlite3";function sa(t={}){let e=`<div class="ax-obs">
3888
4975
  <header class="ax-obs__head">
3889
4976
  <h1>Health</h1>
3890
4977
  <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>
@@ -4006,7 +5093,7 @@ refresh();
4006
5093
  </div>
4007
5094
  <div id="obs-doctor-body" class="ax-obs__doctor-body"></div>
4008
5095
  </section>
4009
- </div>`;return M({title:"AgentX \xB7 Health",activeTab:"health",subtitle:"Health",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:xr,scripts:`<script>${vr}</script>`})}var xr=`
5096
+ </div>`;return C({title:"AgentX \xB7 Health",activeTab:"health",subtitle:"Health",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Xr,scripts:`<script>${Kr}</script>`})}var Xr=`
4010
5097
  .ax-obs { padding: 16px 24px; }
4011
5098
  .ax-obs__head { margin-bottom: 16px; }
4012
5099
  .ax-obs__head h1 { margin: 0 0 4px; font-size: 18px; }
@@ -4099,17 +5186,17 @@ refresh();
4099
5186
  .ax-obs__pill--idle { background: rgba(218, 119, 6, 0.15); color: #bf8700; }
4100
5187
  .ax-obs__empty { color: var(--ax-muted); font-style: italic; padding: 18px 0; margin: 0; }
4101
5188
  .ax-obs__logs-toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; flex-wrap: wrap; }
4102
- .ax-obs__logs-toolbar input[type="text"] { font-family: 'IBM Plex Mono', monospace; font-size: 12px; padding: 5px 9px; min-width: 220px; background: var(--ax-bg-elev); border: 1px solid var(--ax-border); border-radius: 4px; color: var(--ax-fg); }
4103
- .ax-obs__logs-toolbar button { font-size: 11px; padding: 5px 11px; border-radius: 4px; border: 1px solid var(--ax-border); background: var(--ax-bg); color: var(--ax-fg); cursor: pointer; }
5189
+ .ax-obs__logs-toolbar input[type="text"] { font-family: 'IBM Plex Mono', monospace; font-size: 12px; padding: 5px 9px; min-width: 220px; background: var(--ax-bg-elev); border: 1px solid var(--ax-border); border-radius: 4px; color: var(--ax-text); }
5190
+ .ax-obs__logs-toolbar button { font-size: 11px; padding: 5px 11px; border-radius: 4px; border: 1px solid var(--ax-border); background: var(--ax-bg); color: var(--ax-text); cursor: pointer; }
4104
5191
  .ax-obs__logs-toolbar button:hover { background: var(--ax-surface); }
4105
5192
  .ax-obs__inline { font-size: 11px; color: var(--ax-muted); display: inline-flex; align-items: center; gap: 4px; }
4106
5193
  .ax-obs__logs-body { font-family: 'IBM Plex Mono', monospace; font-size: 11px; line-height: 1.45; height: calc(100vh - 320px); min-height: 360px; overflow-y: auto; background: var(--ax-bg-elev); border: 1px solid var(--ax-border); border-radius: 4px; padding: 10px 12px; margin: 0; white-space: pre-wrap; word-break: break-word; }
4107
5194
  .ax-obs__logs-body .err { color: var(--ax-err, #e74c3c); }
4108
5195
  .ax-obs__logs-body .warn { color: #d4ac0d; }
4109
- .ax-obs__logs-body .info { color: var(--ax-fg); }
5196
+ .ax-obs__logs-body .info { color: var(--ax-text); }
4110
5197
  .ax-obs__logs-body .dim { color: var(--ax-muted); }
4111
5198
  .ax-obs__doctor-toolbar { display: flex; gap: 10px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
4112
- .ax-obs__doctor-toolbar button { font-size: 11px; padding: 5px 11px; border-radius: 4px; border: 1px solid var(--ax-border); background: var(--ax-bg); color: var(--ax-fg); cursor: pointer; }
5199
+ .ax-obs__doctor-toolbar button { font-size: 11px; padding: 5px 11px; border-radius: 4px; border: 1px solid var(--ax-border); background: var(--ax-bg); color: var(--ax-text); cursor: pointer; }
4113
5200
  .ax-obs__doctor-toolbar button:hover { background: var(--ax-surface); }
4114
5201
  .ax-obs__doctor-body { display: flex; flex-direction: column; gap: 10px; }
4115
5202
  .ax-obs__doctor-group { background: var(--ax-bg-elev); border: 1px solid var(--ax-border); border-radius: 6px; padding: 10px 14px; }
@@ -4123,7 +5210,7 @@ refresh();
4123
5210
  .ax-obs__doctor-title { font-size: 12px; font-weight: 500; }
4124
5211
  .ax-obs__doctor-detail { font-size: 11px; color: var(--ax-muted); margin-top: 2px; font-family: 'IBM Plex Mono', monospace; word-break: break-word; }
4125
5212
  .ax-obs__doctor-fix { font-size: 11px; color: var(--ax-accent, #3a7bd5); margin-top: 2px; }
4126
- `,vr=`
5213
+ `,Kr=`
4127
5214
  (function(){
4128
5215
  var panes = document.querySelectorAll('.ax-obs__pane');
4129
5216
  var tabs = document.querySelectorAll('.ax-obs__tab');
@@ -4507,23 +5594,23 @@ refresh();
4507
5594
 
4508
5595
  load(current);
4509
5596
  })();
4510
- `;var Gt={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 Xt(t){let e=(t||"").toLowerCase();return e.includes("opus")?"opus":e.includes("haiku")?"haiku":e.includes("sonnet")||e.includes("claude")?"sonnet":"external"}function Fe(t){let e=Gt[Xt(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 kr(){let t=br(process.cwd(),".agentx/db.sqlite");if(!yr(t))return null;try{let e=new wr(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch{return null}}function Kt(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ut({peers:a}))}function _r(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 te(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function Jt(t,e,a){if(!a.startsWith("/api/admin/observability/"))return!1;let n=a.replace(/^\/api\/admin\/observability\//,"").split("?")[0],r=kr();if(!r)return te(e,503,{error:"operational SQLite not available",rows:[]}),!0;try{let{limit:o,agent:s}=_r(t);if(n==="routing"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let d=`
5597
+ `;var da={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 ca(t){let e=(t||"").toLowerCase();return e.includes("opus")?"opus":e.includes("haiku")?"haiku":e.includes("sonnet")||e.includes("claude")?"sonnet":"external"}function tt(t){let e=da[ca(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 Qr(){let t=Jr(process.cwd(),".agentx/db.sqlite");if(!Vr(t))return null;try{let e=new Yr(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch{return null}}function pa(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(sa({peers:a}))}function Zr(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 ae(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function ua(t,e,a){if(!a.startsWith("/api/admin/observability/"))return!1;let n=a.replace(/^\/api\/admin\/observability\//,"").split("?")[0],r=Qr();if(!r)return ae(e,503,{error:"operational SQLite not available",rows:[]}),!0;try{let{limit:o,agent:s}=Zr(t);if(n==="routing"){let l=[],i={limit:o};s&&(l.push("agent_id = @agent"),i.agent=s);let c=`
4511
5598
  SELECT at, channel, chat_id, account_id, kind, deciding_stage, agent_id, reason
4512
5599
  FROM route_traces
4513
- ${i.length?"WHERE "+i.join(" AND "):""}
5600
+ ${l.length?"WHERE "+l.join(" AND "):""}
4514
5601
  ORDER BY at DESC LIMIT @limit
4515
- `,p=r.db.prepare(d).all(l);return te(e,200,{rows:p}),!0}if(n==="rotations"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let d=`
5602
+ `,u=r.db.prepare(c).all(i);return ae(e,200,{rows:u}),!0}if(n==="rotations"){let l=[],i={limit:o};s&&(l.push("agent_id = @agent"),i.agent=s);let c=`
4516
5603
  SELECT rotated_at, agent_id, channel, reason, last_turn_input_tokens
4517
5604
  FROM rotations
4518
- ${i.length?"WHERE "+i.join(" AND "):""}
5605
+ ${l.length?"WHERE "+l.join(" AND "):""}
4519
5606
  ORDER BY rotated_at DESC LIMIT @limit
4520
- `,p=r.db.prepare(d).all(l);return te(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 d=`
5607
+ `,u=r.db.prepare(c).all(i);return ae(e,200,{rows:u}),!0}if(n==="errors"){let l=["status = 'error'"],i={limit:o};s&&(l.push("agent_id = @agent"),i.agent=s);let c=`
4521
5608
  SELECT started_at, agent_id, channel, message_preview, error
4522
5609
  FROM task_history
4523
- WHERE ${i.join(" AND ")}
5610
+ WHERE ${l.join(" AND ")}
4524
5611
  ORDER BY started_at DESC LIMIT @limit
4525
- `,u=r.db.prepare(d).all(l).map(f=>({...f,plain:Vt(f.error)}));return te(e,200,{rows:u}),!0}if(n==="summary"||n==="overview")return te(e,200,Er(r.db)),!0;if(n==="activity")return te(e,200,Sr(r.db,{agent:s})),!0;if(n==="cost"){let i=new URL(t.url||"/","http://_"),l=Ft(i.searchParams.get("range"));return te(e,200,Wt(r.db,l)),!0}if(n==="cost.csv"){let i=new URL(t.url||"/","http://_"),l=Ft(i.searchParams.get("range")),d=Wt(r.db,l),p=Tr(d.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 te(e,404,{error:"unknown observability slice",rows:[]}),!0}catch(o){return te(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function Vt(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(`
4526
- `)[0].slice(0,80)+(e.length>80?"\u2026":""):"unknown failure"}function Er(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,d=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=_=>p.length?p[Math.min(p.length-1,Math.floor(p.length*_))].duration_ms:0,f=u(.5),v=u(.95),A=t.prepare("SELECT * FROM usage_daily WHERE day = date('now')").all().reduce((_,j)=>_+Fe(j),0),E=t.prepare("SELECT * FROM usage_daily WHERE day = date('now', '-1 day')").all().reduce((_,j)=>_+Fe(j),0),S=t.prepare(`
5612
+ `,m=r.db.prepare(c).all(i).map(x=>({...x,plain:ma(x.error)}));return ae(e,200,{rows:m}),!0}if(n==="summary"||n==="overview")return ae(e,200,eo(r.db)),!0;if(n==="activity")return ae(e,200,to(r.db,{agent:s})),!0;if(n==="cost"){let l=new URL(t.url||"/","http://_"),i=ia(l.searchParams.get("range"));return ae(e,200,la(r.db,i)),!0}if(n==="cost.csv"){let l=new URL(t.url||"/","http://_"),i=ia(l.searchParams.get("range")),c=la(r.db,i),u=ao(c.days);return e.writeHead(200,{"Content-Type":"text/csv; charset=utf-8","Content-Disposition":`attachment; filename="agentx-cost-${i||"all"}d-${Date.now()}.csv"`}),e.end(u),!0}return ae(e,404,{error:"unknown observability slice",rows:[]}),!0}catch(o){return ae(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function ma(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(`
5613
+ `)[0].slice(0,80)+(e.length>80?"\u2026":""):"unknown failure"}function eo(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,l=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ? AND started_at < ?").get(r,a).n,i=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,u=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),m=k=>u.length?u[Math.min(u.length-1,Math.floor(u.length*k))].duration_ms:0,x=m(.5),b=m(.95),M=t.prepare("SELECT * FROM usage_daily WHERE day = date('now')").all().reduce((k,$)=>k+tt($),0),E=t.prepare("SELECT * FROM usage_daily WHERE day = date('now', '-1 day')").all().reduce((k,$)=>k+tt($),0),S=t.prepare(`
4527
5614
  SELECT agent_id,
4528
5615
  COUNT(*) AS tasks,
4529
5616
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors,
@@ -4533,7 +5620,7 @@ refresh();
4533
5620
  WHERE started_at >= ?
4534
5621
  GROUP BY agent_id
4535
5622
  ORDER BY tasks DESC LIMIT 10
4536
- `).all(a),c=t.prepare(`
5623
+ `).all(a),d=t.prepare(`
4537
5624
  SELECT COALESCE(channel, 'unknown') AS channel,
4538
5625
  COUNT(*) AS tasks,
4539
5626
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -4541,12 +5628,12 @@ refresh();
4541
5628
  WHERE started_at >= ?
4542
5629
  GROUP BY channel
4543
5630
  ORDER BY tasks DESC
4544
- `).all(a),m=t.prepare("SELECT DISTINCT agent_id FROM usage_daily WHERE day >= date('now', '-7 day')").all().map(_=>_.agent_id),g=new Set(t.prepare("SELECT DISTINCT agent_id FROM task_history WHERE started_at >= ?").all(o).map(_=>_.agent_id)),x=m.filter(_=>!g.has(_)),b=t.prepare(`
5631
+ `).all(a),p=t.prepare("SELECT DISTINCT agent_id FROM usage_daily WHERE day >= date('now', '-7 day')").all().map(k=>k.agent_id),g=new Set(t.prepare("SELECT DISTINCT agent_id FROM task_history WHERE started_at >= ?").all(o).map(k=>k.agent_id)),f=p.filter(k=>!g.has(k)),y=t.prepare(`
4545
5632
  SELECT started_at, agent_id, channel, message_preview, error
4546
5633
  FROM task_history
4547
5634
  WHERE status='error' AND started_at >= ?
4548
5635
  ORDER BY started_at DESC LIMIT 5
4549
- `).all(o).map(_=>({..._,plain:Vt(_.error)}));return{kpis:{tasksToday:s,tasksDelta:s-i,errorsToday:l,errorRate:s>0?l/s:0,avgDurationMs:Math.round(d),p50DurationMs:f,p95DurationMs:v,spendToday:A,spendDelta:A-E,idleAgentCount:x.length},perAgent:S,perChannel:c,idleAgents:x,recentErrors:b}}function Sr(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(`
5636
+ `).all(o).map(k=>({...k,plain:ma(k.error)}));return{kpis:{tasksToday:s,tasksDelta:s-l,errorsToday:i,errorRate:s>0?i/s:0,avgDurationMs:Math.round(c),p50DurationMs:x,p95DurationMs:b,spendToday:M,spendDelta:M-E,idleAgentCount:f.length},perAgent:S,perChannel:d,idleAgents:f,recentErrors:y}}function to(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(`
4550
5637
  SELECT strftime('%Y-%m-%dT%H:00', started_at) AS hour,
4551
5638
  COUNT(*) AS tasks,
4552
5639
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -4554,7 +5641,7 @@ refresh();
4554
5641
  WHERE started_at >= @since ${r}
4555
5642
  GROUP BY hour
4556
5643
  ORDER BY hour
4557
- `).all({since:a,...o}),i=t.prepare(`
5644
+ `).all({since:a,...o}),l=t.prepare(`
4558
5645
  SELECT date(started_at) AS day,
4559
5646
  COUNT(*) AS tasks,
4560
5647
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -4562,7 +5649,7 @@ refresh();
4562
5649
  WHERE started_at >= @since ${r}
4563
5650
  GROUP BY day
4564
5651
  ORDER BY day
4565
- `).all({since:n,...o}),l=t.prepare(`
5652
+ `).all({since:n,...o}),i=t.prepare(`
4566
5653
  SELECT agent_id,
4567
5654
  COUNT(*) AS tasks_7d,
4568
5655
  SUM(CASE WHEN started_at >= @last24 THEN 1 ELSE 0 END) AS tasks_24h,
@@ -4573,7 +5660,7 @@ refresh();
4573
5660
  WHERE started_at >= @since
4574
5661
  GROUP BY agent_id
4575
5662
  ORDER BY tasks_24h DESC, tasks_7d DESC
4576
- `).all({since:n,last24:a});return{hourly:s,daily:i,perAgent:l}}function Ft(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 Wt(t,e){let a=e>0?`WHERE day >= date('now', '-${e} day')`:"",n=t.prepare(`
5663
+ `).all({since:n,last24:a});return{hourly:s,daily:l,perAgent:i}}function ia(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 la(t,e){let a=e>0?`WHERE day >= date('now', '-${e} day')`:"",n=t.prepare(`
4577
5664
  SELECT day, agent_id, model,
4578
5665
  input_tokens, output_tokens, cache_read_tokens, cache_create_tokens,
4579
5666
  tier2_input_tokens, tier2_output_tokens, tier2_cache_read_tokens, tier2_cache_create_tokens,
@@ -4581,37 +5668,37 @@ refresh();
4581
5668
  FROM usage_daily
4582
5669
  ${a}
4583
5670
  ORDER BY day
4584
- `).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,d=0,p=0,u=0,f=0,v=0,k=0,A=0,E=0,S={},c={};for(let w of n){let I=Fe(w),L=Xt(w.model),P=Gt[L],O=(w.tier2_input_tokens||0)/1e6*P.input*.5+(w.tier2_output_tokens||0)/1e6*P.output*.5+(w.tier2_cache_read_tokens||0)/1e6*P.cacheRead*.5+(w.tier2_cache_create_tokens||0)/1e6*P.cacheCreate*.5,Q=(w.input_tokens||0)+(w.tier2_input_tokens||0),R=(w.output_tokens||0)+(w.tier2_output_tokens||0),K=(w.cache_read_tokens||0)+(w.tier2_cache_read_tokens||0),ne=(w.cache_create_tokens||0)+(w.tier2_cache_create_tokens||0);u+=I,w.day>=s&&(p+=I,k+=w.tasks||0),w.day>=i&&w.day<s&&(E+=I,A+=w.tasks||0),w.day===r&&(l+=I),w.day===o&&(d+=I),w.day===r&&(f+=O),w.day>=s&&(v+=O);let q=S[w.day]||(S[w.day]={date:w.day,tasks:0,input:0,output:0,cacheRead:0,cacheCreate:0,cost:0,tier2:0,agents:{}});q.tasks+=w.tasks||0,q.input+=Q,q.output+=R,q.cacheRead+=K,q.cacheCreate+=ne,q.cost+=I,q.tier2+=O;let W=q.agents[w.agent_id]||(q.agents[w.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:w.model});W.tasks+=w.tasks||0,W.cost+=I,W.tier2+=O,W.input+=Q,W.output+=R,W.cacheRead+=K,W.cacheCreate+=ne,w.model&&(W.model=w.model);let U=c[w.agent_id]||(c[w.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:w.model});U.tasks+=w.tasks||0,U.cost+=I,U.tier2+=O,U.input+=Q,U.output+=R,U.cacheRead+=K,U.cacheCreate+=ne,w.model&&(U.model=w.model)}let m=Object.values(S).sort((w,I)=>w.date<I.date?-1:1),g=0,x=0,h=0,b=0,_=0,j=0;for(let w of m)g+=w.tasks,x+=w.input,h+=w.output,b+=w.cacheRead,_+=w.cacheCreate,j+=w.cost;let $=Object.entries(c).map(([w,I])=>({agent_id:w,...I,tokens:I.input+I.output+I.cacheRead+I.cacheCreate})).sort((w,I)=>I.cost-w.cost);return{range:e,generatedAt:new Date().toISOString(),kpis:{spendToday:l,spendYesterday:d,spend7d:p,spend30d:u,tier2Today:f,tier2_7d:v,tier2PctToday:l>0?f/l:0,spendRange:j,avgDailyRange:m.length?j/m.length:0,tasksRange:g,tokensRange:x+h+b+_,cacheHitRange:b+x>0?b/(b+x):0,costPerTaskRange:g>0?j/g:0,spendDeltaWoW:E>0?(p-E)/E:0,tasksDeltaWoW:A>0?(k-A)/A:0},days:m,perAgent:$}}function Tr(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+`
5671
+ `).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),l=new Date(Date.now()-14*864e5).toISOString().slice(0,10),i=0,c=0,u=0,m=0,x=0,b=0,_=0,M=0,E=0,S={},d={};for(let w of n){let j=tt(w),L=ca(w.model),D=da[L],H=(w.tier2_input_tokens||0)/1e6*D.input*.5+(w.tier2_output_tokens||0)/1e6*D.output*.5+(w.tier2_cache_read_tokens||0)/1e6*D.cacheRead*.5+(w.tier2_cache_create_tokens||0)/1e6*D.cacheCreate*.5,Z=(w.input_tokens||0)+(w.tier2_input_tokens||0),R=(w.output_tokens||0)+(w.tier2_output_tokens||0),J=(w.cache_read_tokens||0)+(w.tier2_cache_read_tokens||0),oe=(w.cache_create_tokens||0)+(w.tier2_cache_create_tokens||0);m+=j,w.day>=s&&(u+=j,_+=w.tasks||0),w.day>=l&&w.day<s&&(E+=j,M+=w.tasks||0),w.day===r&&(i+=j),w.day===o&&(c+=j),w.day===r&&(x+=H),w.day>=s&&(b+=H);let q=S[w.day]||(S[w.day]={date:w.day,tasks:0,input:0,output:0,cacheRead:0,cacheCreate:0,cost:0,tier2:0,agents:{}});q.tasks+=w.tasks||0,q.input+=Z,q.output+=R,q.cacheRead+=J,q.cacheCreate+=oe,q.cost+=j,q.tier2+=H;let W=q.agents[w.agent_id]||(q.agents[w.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:w.model});W.tasks+=w.tasks||0,W.cost+=j,W.tier2+=H,W.input+=Z,W.output+=R,W.cacheRead+=J,W.cacheCreate+=oe,w.model&&(W.model=w.model);let U=d[w.agent_id]||(d[w.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:w.model});U.tasks+=w.tasks||0,U.cost+=j,U.tier2+=H,U.input+=Z,U.output+=R,U.cacheRead+=J,U.cacheCreate+=oe,w.model&&(U.model=w.model)}let p=Object.values(S).sort((w,j)=>w.date<j.date?-1:1),g=0,f=0,h=0,y=0,k=0,$=0;for(let w of p)g+=w.tasks,f+=w.input,h+=w.output,y+=w.cacheRead,k+=w.cacheCreate,$+=w.cost;let A=Object.entries(d).map(([w,j])=>({agent_id:w,...j,tokens:j.input+j.output+j.cacheRead+j.cacheCreate})).sort((w,j)=>j.cost-w.cost);return{range:e,generatedAt:new Date().toISOString(),kpis:{spendToday:i,spendYesterday:c,spend7d:u,spend30d:m,tier2Today:x,tier2_7d:b,tier2PctToday:i>0?x/i:0,spendRange:$,avgDailyRange:p.length?$/p.length:0,tasksRange:g,tokensRange:f+h+y+k,cacheHitRange:y+f>0?y/(y+f):0,costPerTaskRange:g>0?$/g:0,spendDeltaWoW:E>0?(u-E)/E:0,tasksDeltaWoW:M>0?(_-M)/M:0},days:p,perAgent:A}}function ao(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+`
4585
5672
  `+a.join(`
4586
5673
  `)+`
4587
- `}import{resolve as Cr}from"path";import{existsSync as Ar}from"fs";import Mr from"better-sqlite3";function Ir(){let t=Cr(process.cwd(),".agentx/intent/ledger.sqlite");if(!Ar(t))return null;try{let e=new Mr(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-Yt>6e4&&(Yt=a,console.error(`[ledger-panel] openReadOnly failed: ${e?.message??e}`)),null}}var Yt=0;function se(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function $r(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 Qt(t,e,a){if(!a.startsWith("/api/admin/ledger/"))return!1;let n=a.replace(/^\/api\/admin\/ledger\//,"").split("?")[0],r=Ir();if(!r)return se(e,503,{error:"intent ledger not available",rows:[]}),!0;try{let o=new URL(t.url||"/","http://_"),s=$r(o.searchParams.get("since")),i=o.searchParams.get("source")||"",l=o.searchParams.get("project")||"",d=parseInt(o.searchParams.get("limit")||"50",10),p=Number.isFinite(d)?Math.max(1,Math.min(500,d)):50;if(n==="stats"){let u=s!==void 0?"WHERE ts >= @since":"",f=s!==void 0?"WHERE decided_at >= @since":"",v=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_events ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),k=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_decisions ${f}`).get({since:s}).n,A=r.db.prepare(`SELECT outcome, COUNT(*) AS n FROM intent_decisions ${f} GROUP BY outcome ORDER BY n DESC`).all({since:s}),E=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_divergences ${u}`).get({since:s}).n,S=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_divergences ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),c=r.db.prepare(`
5674
+ `}import{resolve as no}from"path";import{existsSync as ro}from"fs";import oo from"better-sqlite3";function so(){let t=no(process.cwd(),".agentx/intent/ledger.sqlite");if(!ro(t))return null;try{let e=new oo(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-ha>6e4&&(ha=a,console.error(`[ledger-panel] openReadOnly failed: ${e?.message??e}`)),null}}var ha=0;function de(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function io(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 ga(t,e,a){if(!a.startsWith("/api/admin/ledger/"))return!1;let n=a.replace(/^\/api\/admin\/ledger\//,"").split("?")[0],r=so();if(!r)return de(e,503,{error:"intent ledger not available",rows:[]}),!0;try{let o=new URL(t.url||"/","http://_"),s=io(o.searchParams.get("since")),l=o.searchParams.get("source")||"",i=o.searchParams.get("project")||"",c=parseInt(o.searchParams.get("limit")||"50",10),u=Number.isFinite(c)?Math.max(1,Math.min(500,c)):50;if(n==="stats"){let m=s!==void 0?"WHERE ts >= @since":"",x=s!==void 0?"WHERE decided_at >= @since":"",b=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_events ${m} GROUP BY source ORDER BY n DESC`).all({since:s}),_=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_decisions ${x}`).get({since:s}).n,M=r.db.prepare(`SELECT outcome, COUNT(*) AS n FROM intent_decisions ${x} GROUP BY outcome ORDER BY n DESC`).all({since:s}),E=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_divergences ${m}`).get({since:s}).n,S=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_divergences ${m} GROUP BY source ORDER BY n DESC`).all({since:s}),d=r.db.prepare(`
4588
5675
  SELECT COUNT(*) AS n FROM intent_decisions d
4589
5676
  LEFT JOIN intent_resolutions r
4590
5677
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
4591
5678
  WHERE d.outcome = 'dispatched' AND r.decision_event_id IS NULL
4592
- `).get().n;return se(e,200,{since:s??null,eventsBySource:v,totalDecisions:k,decisionsByOutcome:A,totalDivergences:E,divergencesBySource:S,inFlight:c}),!0}if(n==="events"){let u=[],f={limit:p};s!==void 0&&(u.push("ts >= @since"),f.since=s),i&&(u.push("source = @source"),f.source=i),l&&(u.push("project = @project"),f.project=l);let v=`
5679
+ `).get().n;return de(e,200,{since:s??null,eventsBySource:b,totalDecisions:_,decisionsByOutcome:M,totalDivergences:E,divergencesBySource:S,inFlight:d}),!0}if(n==="events"){let m=[],x={limit:u};s!==void 0&&(m.push("ts >= @since"),x.since=s),l&&(m.push("source = @source"),x.source=l),i&&(m.push("project = @project"),x.project=i);let b=`
4593
5680
  SELECT id, ts, source, source_event_id, project, subject, intent
4594
5681
  FROM intent_events
4595
- ${u.length?"WHERE "+u.join(" AND "):""}
5682
+ ${m.length?"WHERE "+m.join(" AND "):""}
4596
5683
  ORDER BY ts DESC LIMIT @limit
4597
- `;return se(e,200,{rows:r.db.prepare(v).all(f)}),!0}if(n==="divergences"){let u=[],f={limit:p};s!==void 0&&(u.push("ts >= @since"),f.since=s),i&&(u.push("source = @source"),f.source=i);let v=`
5684
+ `;return de(e,200,{rows:r.db.prepare(b).all(x)}),!0}if(n==="divergences"){let m=[],x={limit:u};s!==void 0&&(m.push("ts >= @since"),x.since=s),l&&(m.push("source = @source"),x.source=l);let b=`
4598
5685
  SELECT ts, source, decided_by,
4599
5686
  legacy_agent_id, legacy_outcome, legacy_reason,
4600
5687
  ledger_agent_id, ledger_outcome, ledger_reason,
4601
5688
  event_id
4602
5689
  FROM intent_divergences
4603
- ${u.length?"WHERE "+u.join(" AND "):""}
5690
+ ${m.length?"WHERE "+m.join(" AND "):""}
4604
5691
  ORDER BY ts DESC LIMIT @limit
4605
- `;return se(e,200,{rows:r.db.prepare(v).all(f)}),!0}if(n==="active"){let u=["d.outcome = 'dispatched'","r.decision_event_id IS NULL"],f={limit:p};i&&(u.push("e.source = @source"),f.source=i);let v=`
5692
+ `;return de(e,200,{rows:r.db.prepare(b).all(x)}),!0}if(n==="active"){let m=["d.outcome = 'dispatched'","r.decision_event_id IS NULL"],x={limit:u};l&&(m.push("e.source = @source"),x.source=l);let b=`
4606
5693
  SELECT e.id AS event_id, e.ts, e.source, e.project, e.subject, e.intent,
4607
5694
  d.decided_by, d.decided_at, d.agent_id, d.reason
4608
5695
  FROM intent_decisions d
4609
5696
  JOIN intent_events e ON e.id = d.event_id
4610
5697
  LEFT JOIN intent_resolutions r
4611
5698
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
4612
- WHERE ${u.join(" AND ")}
5699
+ WHERE ${m.join(" AND ")}
4613
5700
  ORDER BY d.decided_at DESC LIMIT @limit
4614
- `;return se(e,200,{rows:r.db.prepare(v).all(f)}),!0}return se(e,404,{error:"unknown ledger slice",rows:[]}),!0}catch(o){return se(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function Zt(t={}){return M({title:"AgentX \xB7 Ledger",activeTab:"graph",subtitle:"Ledger",body:`<div class="ax-led">
5701
+ `;return de(e,200,{rows:r.db.prepare(b).all(x)}),!0}return de(e,404,{error:"unknown ledger slice",rows:[]}),!0}catch(o){return de(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function fa(t={}){return C({title:"AgentX \xB7 Ledger",activeTab:"graph",subtitle:"Ledger",body:`<div class="ax-led">
4615
5702
  <header class="ax-led__head">
4616
5703
  <h1>Intent ledger</h1>
4617
5704
  <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>
@@ -4816,7 +5903,7 @@ refresh();
4816
5903
  }
4817
5904
  load();
4818
5905
  })();
4819
- </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function ea(t={}){return M({title:"AgentX \xB7 Cost",activeTab:"cost",subtitle:"Cost",body:`<div class="ax-cost">
5906
+ </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function xa(t={}){return C({title:"AgentX \xB7 Cost",activeTab:"cost",subtitle:"Cost",body:`<div class="ax-cost">
4820
5907
  <header class="ax-cost__head">
4821
5908
  <div>
4822
5909
  <h1>Cost</h1>
@@ -5389,7 +6476,7 @@ refresh();
5389
6476
  load();
5390
6477
  setInterval(load, 30000);
5391
6478
  })();
5392
- </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function ta(t={}){let e=`<div class="ax-pj__root">
6479
+ </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function va(t={}){let e=`<div class="ax-pj__root">
5393
6480
  <aside class="ax-pj__list">
5394
6481
  <header>
5395
6482
  <h2>Projects</h2>
@@ -5416,7 +6503,7 @@ refresh();
5416
6503
  </header>
5417
6504
  <div id="pj-detail-body" class="ax-pj__detail-body"></div>
5418
6505
  </section>
5419
- </div>`;return M({title:"AgentX \xB7 Projects",activeTab:"projects",subtitle:"Projects",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:jr,scripts:`<script>${Lr}</script>`})}var jr=`
6506
+ </div>`;return C({title:"AgentX \xB7 Projects",activeTab:"projects",subtitle:"Projects",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:lo,scripts:`<script>${co}</script>`})}var lo=`
5420
6507
  .ax-pj__root {
5421
6508
  display: grid;
5422
6509
  grid-template-columns: 360px 1fr;
@@ -5435,7 +6522,7 @@ refresh();
5435
6522
  }
5436
6523
  .ax-pj__list > header h2 { margin: 0; font-size: 14px; }
5437
6524
  .ax-pj__icon {
5438
- background: transparent; color: var(--ax-fg-muted, var(--ax-fg));
6525
+ background: transparent; color: var(--ax-fg-muted, var(--ax-text));
5439
6526
  border: 1px solid transparent; border-radius: 4px;
5440
6527
  padding: 4px 8px; cursor: pointer; font-size: 14px;
5441
6528
  }
@@ -5444,7 +6531,7 @@ refresh();
5444
6531
  .ax-pj__search input {
5445
6532
  width: 100%; font: inherit; font-size: 12px;
5446
6533
  padding: 6px 8px; border: 1px solid var(--ax-border);
5447
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6534
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5448
6535
  }
5449
6536
  .ax-pj__cards {
5450
6537
  list-style: none; margin: 0; padding: 0;
@@ -5459,7 +6546,7 @@ refresh();
5459
6546
  .ax-pj__card-title { font-weight: 500; font-size: 13px; margin-bottom: 4px; }
5460
6547
  .ax-pj__card-meta {
5461
6548
  display: flex; gap: 6px; flex-wrap: wrap;
5462
- font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg));
6549
+ font-size: 11px; color: var(--ax-fg-muted, var(--ax-text));
5463
6550
  }
5464
6551
  .ax-pj__card-meta .stat { padding: 1px 6px; border-radius: 3px; background: var(--ax-bg); border: 1px solid var(--ax-border); }
5465
6552
  .ax-pj__card-meta .stat.zero { opacity: 0.4; }
@@ -5480,11 +6567,11 @@ refresh();
5480
6567
  .ax-pj__kind--github { color: #c9d1d9; background: rgba(110, 118, 129, 0.2); border-color: rgba(110, 118, 129, 0.4); }
5481
6568
  .ax-pj__kind--jira { color: #2684ff; background: rgba(38, 132, 255, 0.1); border-color: rgba(38, 132, 255, 0.3); }
5482
6569
  .ax-pj__kind--linear { color: #5e6ad2; background: rgba(94, 106, 210, 0.1); border-color: rgba(94, 106, 210, 0.3); }
5483
- .ax-pj__kind--other { color: var(--ax-fg-muted, var(--ax-fg)); background: var(--ax-bg); border-color: var(--ax-border); }
5484
- .ax-pj__keyhint { font-size: 12px; font-weight: normal; color: var(--ax-fg-muted, var(--ax-fg)); font-family: var(--ax-mono, monospace); }
6570
+ .ax-pj__kind--other { color: var(--ax-fg-muted, var(--ax-text)); background: var(--ax-bg); border-color: var(--ax-border); }
6571
+ .ax-pj__keyhint { font-size: 12px; font-weight: normal; color: var(--ax-fg-muted, var(--ax-text)); font-family: var(--ax-mono, monospace); }
5485
6572
  .ax-pj__home {
5486
6573
  font-size: 12px; text-decoration: none; padding: 2px 6px;
5487
- color: var(--ax-fg-muted, var(--ax-fg)); border: 1px solid var(--ax-border);
6574
+ color: var(--ax-fg-muted, var(--ax-text)); border: 1px solid var(--ax-border);
5488
6575
  border-radius: 3px;
5489
6576
  }
5490
6577
  .ax-pj__home:hover { color: var(--ax-accent); border-color: var(--ax-accent); }
@@ -5494,7 +6581,7 @@ refresh();
5494
6581
  .ax-pj__btn {
5495
6582
  font: inherit; font-size: 11px;
5496
6583
  padding: 3px 8px; border: 1px solid var(--ax-border);
5497
- border-radius: 3px; background: var(--ax-bg); color: var(--ax-fg);
6584
+ border-radius: 3px; background: var(--ax-bg); color: var(--ax-text);
5498
6585
  cursor: pointer; text-transform: none; letter-spacing: 0;
5499
6586
  margin-left: auto;
5500
6587
  }
@@ -5502,7 +6589,7 @@ refresh();
5502
6589
  .ax-pj__unlink {
5503
6590
  margin-left: auto;
5504
6591
  background: transparent; border: 1px solid transparent;
5505
- color: var(--ax-fg-muted, var(--ax-fg));
6592
+ color: var(--ax-fg-muted, var(--ax-text));
5506
6593
  cursor: pointer; font-size: 14px; padding: 0 6px; border-radius: 3px;
5507
6594
  }
5508
6595
  .ax-pj__unlink:hover { color: var(--ax-err, #ef4444); border-color: var(--ax-err, #ef4444); }
@@ -5525,7 +6612,7 @@ refresh();
5525
6612
  .ax-pj__modal-search input {
5526
6613
  width: 100%; font: inherit; font-size: 13px;
5527
6614
  padding: 6px 10px; border: 1px solid var(--ax-border);
5528
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6615
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5529
6616
  margin-bottom: 12px;
5530
6617
  }
5531
6618
  .ax-pj__pick {
@@ -5535,7 +6622,7 @@ refresh();
5535
6622
  }
5536
6623
  .ax-pj__pick:hover { background: var(--ax-bg); border-color: var(--ax-border); }
5537
6624
  .ax-pj__pick .pname { font-weight: 500; flex: 1; }
5538
- .ax-pj__pick .pmeta { font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg)); }
6625
+ .ax-pj__pick .pmeta { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); }
5539
6626
  .ax-pj__pick .ptag {
5540
6627
  font-size: 11px; padding: 1px 6px; border-radius: 3px;
5541
6628
  background: var(--ax-warn, #facc15); color: #1a1a1a;
@@ -5543,13 +6630,13 @@ refresh();
5543
6630
  /* Form fields */
5544
6631
  .ax-pj__form { display: flex; flex-direction: column; gap: 12px; }
5545
6632
  .ax-pj__fld { display: flex; flex-direction: column; gap: 4px; }
5546
- .ax-pj__fld-label { font-size: 12px; font-weight: 500; color: var(--ax-fg-muted, var(--ax-fg)); }
6633
+ .ax-pj__fld-label { font-size: 12px; font-weight: 500; color: var(--ax-fg-muted, var(--ax-text)); }
5547
6634
  .ax-pj__fld input, .ax-pj__fld select {
5548
6635
  font: inherit; font-size: 13px;
5549
6636
  padding: 6px 10px; border: 1px solid var(--ax-border);
5550
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6637
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5551
6638
  }
5552
- .ax-pj__fld-hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg)); }
6639
+ .ax-pj__fld-hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); }
5553
6640
  .ax-pj__form-actions {
5554
6641
  display: flex; gap: 8px; align-items: center;
5555
6642
  margin-top: 8px; padding-top: 14px;
@@ -5565,7 +6652,7 @@ refresh();
5565
6652
  .ax-pj__fld textarea {
5566
6653
  font: inherit; font-family: var(--ax-mono, monospace); font-size: 12px;
5567
6654
  padding: 6px 10px; border: 1px solid var(--ax-border);
5568
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6655
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5569
6656
  resize: vertical;
5570
6657
  }
5571
6658
  .ax-pj__clause {
@@ -5587,7 +6674,7 @@ refresh();
5587
6674
  }
5588
6675
  .ax-pj__section h3 {
5589
6676
  font-size: 13px; text-transform: uppercase; letter-spacing: 0.6px;
5590
- color: var(--ax-fg-muted, var(--ax-fg)); margin: 0 0 10px 0;
6677
+ color: var(--ax-fg-muted, var(--ax-text)); margin: 0 0 10px 0;
5591
6678
  }
5592
6679
  .ax-pj__row {
5593
6680
  display: flex; align-items: center; gap: 10px;
@@ -5595,15 +6682,15 @@ refresh();
5595
6682
  border-radius: 4px; margin-bottom: 6px; background: var(--ax-bg);
5596
6683
  }
5597
6684
  .ax-pj__row .name { font-weight: 500; }
5598
- .ax-pj__row .meta { font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg)); }
6685
+ .ax-pj__row .meta { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); }
5599
6686
  .ax-pj__row a { color: var(--ax-accent); text-decoration: none; }
5600
6687
  .ax-pj__row a:hover { text-decoration: underline; }
5601
6688
  .ax-pj__empty, .ax-pj__warn {
5602
- padding: 18px; font-size: 12px; color: var(--ax-fg-muted, var(--ax-fg));
6689
+ padding: 18px; font-size: 12px; color: var(--ax-fg-muted, var(--ax-text));
5603
6690
  }
5604
6691
  .ax-pj__warn { color: var(--ax-warn, #facc15); border-top: 1px solid var(--ax-border); }
5605
- .ax-pj__hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg)); margin-top: 4px; }
5606
- `,Lr=`
6692
+ .ax-pj__hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); margin-top: 4px; }
6693
+ `,co=`
5607
6694
  (function(){
5608
6695
  const $ = (sel) => document.querySelector(sel);
5609
6696
  const esc = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({"&":"&amp;","<":"&lt;",">":"&gt;","\\"":"&quot;"}[c]));
@@ -5972,7 +7059,7 @@ refresh();
5972
7059
  // \u2500\u2500 Contact add/remove \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
5973
7060
  async function addContact(projectKey) {
5974
7061
  const cid = prompt("Contact id to link to '" + projectKey + "':\\n\\n"
5975
- + "Use the id from .agentx/contacts.json (e.g. 'anis', 'omar').");
7062
+ + "Use the id from .agentx/contacts.json (e.g. 'alex', 'jordan').");
5976
7063
  if (!cid) return;
5977
7064
  try {
5978
7065
  await postJson("/api/admin/projects/contacts/link", { projectKey, contactId: cid.trim() });
@@ -6253,7 +7340,7 @@ refresh();
6253
7340
  load();
6254
7341
  });
6255
7342
  })();
6256
- `;import{resolve as Ge,join as Dr}from"path";import{existsSync as Xe,readdirSync as Pr,readFileSync as Or}from"fs";import Hr from"better-sqlite3";function aa(t={}){let e='<div id="ax-fleet-root"></div>';return M({title:"AgentX \xB7 Activity Graph",activeTab:"graph",subtitle:"Activity Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Rr,scripts:'<script src="/assets/activity-graph.global.js" defer></script>',noMain:!0})}var Rr=`
7343
+ `;import{resolve as nt,join as uo}from"path";import{existsSync as rt,readdirSync as mo,readFileSync as ho}from"fs";import go from"better-sqlite3";function ba(t={}){let e='<div id="ax-fleet-root"></div>';return C({title:"AgentX \xB7 Activity Graph",activeTab:"graph",subtitle:"Activity Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:po,scripts:`<script src="${je("activity-graph.global.js")}" defer></script>`,noMain:!0})}var po=`
6257
7344
  html, body { height: 100%; }
6258
7345
  body { margin: 0; }
6259
7346
  #ax-fleet-root { height: calc(100vh - 48px); }
@@ -6265,31 +7352,31 @@ body { margin: 0; }
6265
7352
  font: 13px/1 -apple-system, BlinkMacSystemFont, sans-serif;
6266
7353
  text-align: center;
6267
7354
  }
6268
- `;function Ie(){let t=Ge(process.cwd(),".agentx/intent/ledger.sqlite");if(!Xe(t))return null;try{let e=new Hr(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-na>6e4&&(na=a,console.error(`[activity-graph] openLedger failed: ${e?.message??e}`)),null}}var na=0;function ae(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function sa(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(aa({peers:a}))}var pe={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:"API",color:"#3a7bd5"}};function Nr(t,e,a){if(t==="mesh"){let n=a?.context?.channel;if(typeof n=="string"&&n in pe)return n;if(e.startsWith("mesh.")){let r=e.slice(5);if(r==="a2a")return"a2a";if(r in pe)return r}return"mesh"}if(t==="workflow"){let n=a?.event?.payload,r=typeof n?.channel=="string"?n.channel:"";if(r&&r in pe)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 pe)return s}return"workflow"}return t}function Br(t){let e={mtgl:"#e07a3a",ksi:"#3a7bd5",noqta:"#10b981",hasanah:"#bc8cff","hasanah-lab":"#bc8cff",hexastack:"#06b6d4",hackathonat:"#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 zr(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 ia(t,e){if(!t)return"unmapped";if(e){let n=e.find(r=>r.id===t);if(n?.client)return n.client}let a=t.indexOf("/");return a>0?t.slice(0,a):t}function la(t){let e=new Map;if(!t)return e;let a=t.business;if(!a)return e;let n=a.projects??[],r=a.orgChart??{};for(let s of n){if(!s.pm)continue;let i=s.client||(s.id.includes("/")?s.id.slice(0,s.id.indexOf("/")):s.id);e.has(s.pm)||e.set(s.pm,i)}function o(s,i=new Set){if(e.has(s))return e.get(s);if(i.has(s))return;i.add(s);let l=r[s];if(!l?.reportsTo)return;let d=o(l.reportsTo,i);return d&&e.set(s,d),d}for(let s of Object.keys(r))o(s);return e}function da(t,e,a){if(!a.length)return;let n=String(e?.chatId??e?.message?.chat?.id??""),r=String(e?.sender?.username??e?.message?.from?.username??""),o=String(e?.sender?.id??e?.message?.from?.id??""),s=a.filter(i=>!i.channel||i.channel===t);for(let i of s)if(i.chatId&&n&&i.chatId===n)return i;for(let i of s)if(i.username&&r&&i.username===r)return i;for(let i of s)if(i.senderId&&o&&i.senderId===o)return i;for(let i of s)if(!i.chatId&&!i.username&&!i.senderId&&i.channel===t)return i}function qr(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:B(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&&!We(l))return{id:l,name:l,avatar:B(l),kind:"a2a"}}let i=o||r||s;if(i&&!We(r||o||"")){let l=r||o||s,d=e==="mesh.github"?"github":e==="mesh.gitlab"?"gitlab":e==="mesh.a2a"?"a2a":"mesh";return{id:l,name:o||r||l,avatar:B(i),kind:d}}}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,d=i||(s.id!=null?String(s.id):null)||l;if(d&&!We(i||l||"")){let p=typeof n.channel=="string"?n.channel:"",u=ra(p);return{id:d,name:l||i||d,avatar:B(l||i||d),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,d=s.name||s.username;return{id:l,name:d,avatar:B(d),kind:"gitlab"}}let i=o.sender;if(i?.login)return{id:i.login,name:i.login,avatar:B(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:B(i),kind:ra(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:B(o),kind:"gitlab"}}}if(t==="github"){let n=a.sender||a.payload?.sender;if(n?.login)return{id:n.login,name:n.login,avatar:B(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:B(r),kind:"telegram"}}if(n?.id)return{id:String(n.id),name:n.first_name||`tg:${n.id}`,avatar:B(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:B(o),kind:"whatsapp"}}}return null}function ra(t){return t==="telegram"||t==="whatsapp"||t==="slack"||t==="discord"?t:"system"}function We(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 B(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 ca(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}
7355
+ `;function Re(){let t=nt(process.cwd(),".agentx/intent/ledger.sqlite");if(!rt(t))return null;try{let e=new go(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-ya>6e4&&(ya=a,console.error(`[activity-graph] openLedger failed: ${e?.message??e}`)),null}}var ya=0;function ne(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function _a(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ba({peers:a}))}var ge={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:"API",color:"#3a7bd5"}};function fo(t,e,a){if(t==="mesh"){let n=a?.context?.channel;if(typeof n=="string"&&n in ge)return n;if(e.startsWith("mesh.")){let r=e.slice(5);if(r==="a2a")return"a2a";if(r in ge)return r}return"mesh"}if(t==="workflow"){let n=a?.event?.payload,r=typeof n?.channel=="string"?n.channel:"";if(r&&r in ge)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 ge)return s}return"workflow"}return t}function xo(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 vo(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 Ea(t,e,a){return _t(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 bo(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:B(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 i=o.slice(6);if(i&&!at(i))return{id:i,name:i,avatar:B(i),kind:"a2a"}}let l=o||r||s;if(l&&!at(r||o||"")){let i=r||o||s,c=e==="mesh.github"?"github":e==="mesh.gitlab"?"gitlab":e==="mesh.a2a"?"a2a":"mesh";return{id:i,name:o||r||i,avatar:B(l),kind:c}}}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,l=typeof s.username=="string"?s.username:null,i=typeof s.name=="string"?s.name:null,c=l||(s.id!=null?String(s.id):null)||i;if(c&&!at(l||i||"")){let u=typeof n.channel=="string"?n.channel:"",m=wa(u);return{id:c,name:i||l||c,avatar:B(i||l||c),kind:m}}}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 i=s.username||s.name,c=s.name||s.username;return{id:i,name:c,avatar:B(c),kind:"gitlab"}}let l=o.sender;if(l?.login)return{id:l.login,name:l.login,avatar:B(l.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 l=o||r||s;return{id:s,name:l,avatar:B(l),kind:wa(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:B(o),kind:"gitlab"}}}if(t==="github"){let n=a.sender||a.payload?.sender;if(n?.login)return{id:n.login,name:n.login,avatar:B(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:B(r),kind:"telegram"}}if(n?.id)return{id:String(n.id),name:n.first_name||`tg:${n.id}`,avatar:B(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:B(o),kind:"whatsapp"}}}return null}function wa(t){return t==="telegram"||t==="whatsapp"||t==="slack"||t==="discord"?t:"system"}function at(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 B(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 Sa(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}
6269
7356
  ${r}`:n)}e.comment?.body&&a.push(e.comment.body),e.issue?.title&&a.push(e.issue.title+(e.issue.body?`
6270
- ${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 Ur(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 Ke(t,e,a){let n=Date.now(),r=n-a*3600*1e3,o=t.prepare(`
7357
+ ${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 yo(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 ot(t,e,a){let n=Date.now(),r=n-a*3600*1e3,o=t.prepare(`
6271
7358
  SELECT id, ts, source, project, subject, intent, raw_json
6272
7359
  FROM intent_events WHERE ts >= ? ORDER BY ts ASC
6273
- `).all(r),s=new Map,i=new Map;if(o.length>0){let h=o.map(w=>w.id),b=h.map((w,I)=>`@id${I}`).join(","),_=Object.fromEntries(h.map((w,I)=>[`id${I}`,w])),j=t.prepare(`
7360
+ `).all(r),s=new Map,l=new Map;if(o.length>0){let h=o.map(w=>w.id),y=h.map((w,j)=>`@id${j}`).join(","),k=Object.fromEntries(h.map((w,j)=>[`id${j}`,w])),$=t.prepare(`
6274
7361
  SELECT event_id, decided_at, decided_by, agent_id, outcome, reason
6275
- FROM intent_decisions WHERE event_id IN (${b}) ORDER BY decided_at ASC
6276
- `).all(_);for(let w of j)s.has(w.event_id)||s.set(w.event_id,[]),s.get(w.event_id).push(w);let $=t.prepare(`
7362
+ FROM intent_decisions WHERE event_id IN (${y}) ORDER BY decided_at ASC
7363
+ `).all(k);for(let w of $)s.has(w.event_id)||s.set(w.event_id,[]),s.get(w.event_id).push(w);let A=t.prepare(`
6277
7364
  SELECT decision_event_id, decision_decided_by, resolved_at, status, duration_ms, result_summary
6278
- FROM intent_resolutions WHERE decision_event_id IN (${b})
6279
- `).all(_);for(let w of $)i.set(`${w.decision_event_id}|${w.decision_decided_by}`,w)}let l=new Map,d=new Map,p=new Map,u=new Map,f=[],v=e?.business?.projects??[],k=e?.business?.contactMap??[],A=la(e);for(let h of o){let b=null;try{b=JSON.parse(h.raw_json)}catch{}let _=da(h.source,b,k),j=null,$=null;_?(j=_.client,$=_.project||`${_.client}/_chat`):h.project&&(j=ia(h.project,v),$=h.project);let w=Nr(h.source,h.intent||"",b),I=pe[w]||{label:w,color:"#6b7280"};p.has(w)||p.set(w,{id:w,label:I.label,color:I.color});let L="__system",P,O=qr(h.source,h.intent||"",b);if(O){L=O.id,P=O.kind;let R=_?.displayName||O.name;(!u.has(O.id)||_?.displayName)&&u.set(O.id,{id:O.id,name:R,avatar:B(R),kind:O.kind})}else u.has("__system")||u.set("__system",{id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});let Q=ca(h.source,b);for(let R of s.get(h.id)??[]){if(R.outcome!=="dispatched"||!R.agent_id)continue;let K=`${h.id}|${R.decided_by}`,ne=i.get(K),q=R.decided_at,W=ne?.resolved_at??null,U=W===null,Ga=ne?.duration_ms??(U?n-q:0),Xa=U?"active":ne?.status==="error"||ne?.status==="fail"?"error":"completed",F,ue;if(j)F=j,ue=$;else{let De=A.get(R.agent_id);De?(F=De,ue=`${De}/_${h.source}`):(F="unmapped",ue=`unmapped/_${h.source}`)}l.has(F)||l.set(F,{id:F,name:F,color:Br(F),projects:[]}),d.has(F)||d.set(F,new Set),d.get(F).add(ue),f.push({id:`${h.id}|${R.decided_by}`,agentId:R.agent_id,clientId:F,projectId:ue,channelId:w,initiatorId:L,initiatorKind:P,subject:Ur(h.subject),intent:h.intent||"",startedAt:q,resolvedAt:W,duration:Ga,active:U,outcome:Xa,tokens:0,inputPreview:Q,system:zr(R.agent_id,e)})}}let E=[...l.values()].map(h=>({...h,projects:[...d.get(h.id)||[]].sort()})).sort((h,b)=>h.id.localeCompare(b.id)),S=[],c=new Set;if(e)for(let[h,b]of Object.entries(e.agents||{})){let _={id:h,name:b.name||h,tier:b.tier==="claude-code"?"lead":"worker",model:b.model||"",role:b.systemPrompt?b.systemPrompt.split(/[.\n]/)[0].slice(0,60):b.tier||""};S.push(_),c.add(h)}for(let h of f)c.has(h.agentId)||(S.push({id:h.agentId,name:h.agentId,tier:"worker",model:"",role:""}),c.add(h.agentId));S.sort((h,b)=>h.id.localeCompare(b.id));let m=[],g=new Set;for(let[h,b]of Object.entries(pe))m.push({id:h,label:b.label,color:b.color}),g.add(h);for(let h of p.values())g.has(h.id)||m.push(h);let x=[...u.values()];return x.find(h=>h.id==="__system")||x.push({id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"}),{now:n,windowH:a,clients:E,agents:S,channels:m,initiators:x,dispatches:f}}function pa(t){let e=Ie();if(!e)return null;try{return Ke(e.db,ie,t)}finally{e.close()}}function ua(t){let e=new Map,a=new Map,n=new Map,r=new Map,o=[],s=0,i=0;for(let{nodeId:l,snap:d}of t){d.now>s&&(s=d.now),d.windowH>i&&(i=d.windowH);for(let p of d.clients){let u=e.get(p.id);if(!u)e.set(p.id,{...p,projects:[...p.projects]});else{let f=Array.from(new Set([...u.projects,...p.projects])).sort();e.set(p.id,{...u,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)o.push({...p,nodeId:l,id:`${l}::${p.id}`})}return{now:s||Date.now(),windowH:i||6,clients:[...e.values()].sort((l,d)=>l.id.localeCompare(d.id)),agents:[...a.values()].sort((l,d)=>l.id.localeCompare(d.id)),channels:[...n.values()],initiators:[...r.values()],dispatches:o.sort((l,d)=>d.startedAt-l.startedAt)}}var ie=null;function ma(t){ie=t}async function ha(t,e,a){if(a!=="/api/admin/activity-graph"&&!a.startsWith("/api/admin/activity-graph?"))return!1;let n=Ie();if(!n)return ae(e,503,{error:"intent ledger not available",clients:[],agents:[],channels:[],initiators:[],dispatches:[]}),!0;try{let r=new URL(t.url||"/","http://_"),o=fa(parseInt(r.searchParams.get("hours")||"6",10));ae(e,200,Ke(n.db,ie,o))}catch(r){ae(e,500,{error:r?.message??String(r)})}finally{n.close()}return!0}var Fr=5e3;async function ga(t,e,a){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
7365
+ FROM intent_resolutions WHERE decision_event_id IN (${y})
7366
+ `).all(k);for(let w of A)l.set(`${w.decision_event_id}|${w.decision_decided_by}`,w)}let i=new Map,c=new Map,u=new Map,m=new Map,x=[],b=e?.business?.projects??[],_=e?.business?.contactMap??[],M=Ue(e?.business??{});for(let h of o){let y=null;try{y=JSON.parse(h.raw_json)}catch{}let k=Ea(h.source,y,_),$=null,A=null;k?($=k.client,A=k.project||`${k.client}/_chat`):h.project&&($=qe(h.project,b),A=h.project);let w=fo(h.source,h.intent||"",y),j=ge[w]||{label:w,color:"#6b7280"};u.has(w)||u.set(w,{id:w,label:j.label,color:j.color});let L="__system",D,H=bo(h.source,h.intent||"",y);if(H){L=H.id,D=H.kind;let R=k?.displayName||H.name;(!m.has(H.id)||k?.displayName)&&m.set(H.id,{id:H.id,name:R,avatar:B(R),kind:H.kind})}else m.has("__system")||m.set("__system",{id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});let Z=Sa(h.source,y);for(let R of s.get(h.id)??[]){if(R.outcome!=="dispatched"||!R.agent_id)continue;let J=`${h.id}|${R.decided_by}`,oe=l.get(J),q=R.decided_at,W=oe?.resolved_at??null,U=W===null,ln=oe?.duration_ms??(U?n-q:0),dn=U?"active":oe?.status==="error"||oe?.status==="fail"?"error":"completed",F,xe;if($)F=$,xe=A;else{let He=M.get(R.agent_id);He?(F=He,xe=`${He}/_${h.source}`):(F="unmapped",xe=`unmapped/_${h.source}`)}i.has(F)||i.set(F,{id:F,name:F,color:xo(F),projects:[]}),c.has(F)||c.set(F,new Set),c.get(F).add(xe),x.push({id:`${h.id}|${R.decided_by}`,agentId:R.agent_id,clientId:F,projectId:xe,channelId:w,initiatorId:L,initiatorKind:D,subject:yo(h.subject),intent:h.intent||"",startedAt:q,resolvedAt:W,duration:ln,active:U,outcome:dn,tokens:0,inputPreview:Z,system:vo(R.agent_id,e)})}}let E=[...i.values()].map(h=>({...h,projects:[...c.get(h.id)||[]].sort()})).sort((h,y)=>h.id.localeCompare(y.id)),S=[],d=new Set;if(e)for(let[h,y]of Object.entries(e.agents||{})){let k={id:h,name:y.name||h,tier:y.tier==="claude-code"?"lead":"worker",model:y.model||"",role:y.systemPrompt?y.systemPrompt.split(/[.\n]/)[0].slice(0,60):y.tier||""};S.push(k),d.add(h)}for(let h of x)d.has(h.agentId)||(S.push({id:h.agentId,name:h.agentId,tier:"worker",model:"",role:""}),d.add(h.agentId));S.sort((h,y)=>h.id.localeCompare(y.id));let p=[],g=new Set;for(let[h,y]of Object.entries(ge))p.push({id:h,label:y.label,color:y.color}),g.add(h);for(let h of u.values())g.has(h.id)||p.push(h);let f=[...m.values()];return f.find(h=>h.id==="__system")||f.push({id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"}),{now:n,windowH:a,clients:E,agents:S,channels:p,initiators:f,dispatches:x}}function Ta(t){let e=Re();if(!e)return null;try{return ot(e.db,ce,t)}finally{e.close()}}function Ca(t){let e=new Map,a=new Map,n=new Map,r=new Map,o=[],s=0,l=0;for(let{nodeId:i,snap:c}of t){c.now>s&&(s=c.now),c.windowH>l&&(l=c.windowH);for(let u of c.clients){let m=e.get(u.id);if(!m)e.set(u.id,{...u,projects:[...u.projects]});else{let x=Array.from(new Set([...m.projects,...u.projects])).sort();e.set(u.id,{...m,projects:x})}}for(let u of c.agents)a.has(u.id)||a.set(u.id,u);for(let u of c.channels)n.has(u.id)||n.set(u.id,u);for(let u of c.initiators)r.has(u.id)||r.set(u.id,u);for(let u of c.dispatches)o.push({...u,nodeId:i,id:`${i}::${u.id}`})}return{now:s||Date.now(),windowH:l||6,clients:[...e.values()].sort((i,c)=>i.id.localeCompare(c.id)),agents:[...a.values()].sort((i,c)=>i.id.localeCompare(c.id)),channels:[...n.values()],initiators:[...r.values()],dispatches:o.sort((i,c)=>c.startedAt-i.startedAt)}}var ce=null;function Aa(t){ce=t}async function Ma(t,e,a){if(a!=="/api/admin/activity-graph"&&!a.startsWith("/api/admin/activity-graph?"))return!1;let n=Re();if(!n)return ne(e,503,{error:"intent ledger not available",clients:[],agents:[],channels:[],initiators:[],dispatches:[]}),!0;try{let r=new URL(t.url||"/","http://_"),o=$a(parseInt(r.searchParams.get("hours")||"6",10));ne(e,200,ot(n.db,ce,o))}catch(r){ne(e,500,{error:r?.message??String(r)})}finally{n.close()}return!0}var wo=5e3;async function Ia(t,e,a){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
6280
7367
 
6281
- `);let n=new URL(t.url||"/","http://_"),r=fa(parseInt(n.searchParams.get("hours")||"6",10)),o=!1,s=()=>{o=!0};t.on("close",s),t.on("error",s),e.on("close",s),e.on("error",s);let i=setInterval(()=>{if(!o)try{e.write(`: hb
7368
+ `);let n=new URL(t.url||"/","http://_"),r=$a(parseInt(n.searchParams.get("hours")||"6",10)),o=!1,s=()=>{o=!0};t.on("close",s),t.on("error",s),e.on("close",s),e.on("error",s);let l=setInterval(()=>{if(!o)try{e.write(`: hb
6282
7369
 
6283
- `)}catch{s()}},25e3);try{for(;!o;){let l=Ie();if(l)try{let p=Ke(l.db,ie,r);e.write(`event: snapshot
6284
- `),e.write(`data: ${JSON.stringify(p)}
7370
+ `)}catch{s()}},25e3);try{for(;!o;){let i=Re();if(i)try{let u=ot(i.db,ce,r);e.write(`event: snapshot
7371
+ `),e.write(`data: ${JSON.stringify(u)}
6285
7372
 
6286
- `)}catch(p){e.write(`event: error
6287
- data: ${JSON.stringify({error:p?.message??String(p)})}
7373
+ `)}catch(u){e.write(`event: error
7374
+ data: ${JSON.stringify({error:u?.message??String(u)})}
6288
7375
 
6289
- `)}finally{l.close()}else e.write(`event: error
7376
+ `)}finally{i.close()}else e.write(`event: error
6290
7377
  data: ${JSON.stringify({error:"ledger not available"})}
6291
7378
 
6292
- `);let d=Date.now();for(;!o&&Date.now()-d<Fr;)await new Promise(p=>setTimeout(p,200))}}finally{clearInterval(i);try{e.end()}catch{}}return!0}function fa(t){return!Number.isFinite(t)||t<1?6:Math.min(720,Math.max(1,t))}function Wr(t,e,a=5e3){let n=new Date(e).toISOString().slice(0,10),r=Ge(process.cwd(),".agentx/task-history",t,n);if(!Xe(r)){let o=new Date(e-864e5).toISOString().slice(0,10),s=Ge(process.cwd(),".agentx/task-history",t,o);return Xe(s)?oa(s,e,a):null}return oa(r,e,a)}function oa(t,e,a){let n=null,r=1/0;for(let o of Pr(t)){if(!o.endsWith(".json"))continue;let s;try{s=JSON.parse(Or(Dr(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 d=Math.abs(l-e);d<r&&d<=a&&(n=s,r=d)}return n}async function xa(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 ae(e,400,{error:"invalid dispatch id"}),!0;let s=r.slice(0,o),i=r.slice(o+1),l=Ie();if(!l)return ae(e,503,{error:"ledger not available"}),!0;try{let d=l.db.prepare("SELECT id, ts, source, project, subject, intent, raw_json FROM intent_events WHERE id = ?").get(s);if(!d)return ae(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 ae(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),f=null;try{f=JSON.parse(d.raw_json)}catch{}let v=ca(d.source,f),k=f&&typeof f=="object"&&(f.text||f.message?.text||f.message?.caption||f.object_attributes?.note||f.object_attributes?.description||f.comment?.body||f.issue?.body||(typeof f.message=="string"?f.message:null)||(typeof f.prompt=="string"?f.prompt:null)||null)||v,A=null,E=null;if(p.agent_id){let h=Wr(p.agent_id,p.decided_at);if(h){typeof h.responseText=="string"&&(A=h.responseText);let b=h.transcript;Array.isArray(b)&&(E=b.length)}}let S=ie?.business?.projects??[],c=ie?.business?.contactMap??[],m=la(ie),g={client:"unmapped",project:`unmapped/_${d.source}`,via:"fallback"},x=da(d.source,f,c);if(x)g={client:x.client,project:x.project||`${x.client}/_chat`,via:`contactMap (channel=${x.channel??"*"}${x.username?` username=${x.username}`:""}${x.chatId?` chatId=${x.chatId}`:""})`};else if(d.project)g={client:ia(d.project,S),project:d.project,via:`project namespace prefix (${d.project})`};else if(p.agent_id){let h=m.get(p.agent_id);h&&(g={client:h,project:`${h}/_${d.source}`,via:`orgChart fallback (agent ${p.agent_id} reports up to a PM whose project belongs to ${h})`})}ae(e,200,{id:r,eventId:s,source:d.source,subject:d.subject,intent:d.intent,project:d.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:k,response:A,transcriptLen:E,resolutionStatus:u?.status??null,resultSummary:u?.result_summary??null,attribution:g})}catch(d){ae(e,500,{error:d?.message??String(d)})}finally{l.close()}return!0}import{existsSync as Jr,readFileSync as Vr}from"fs";import{resolve as ba}from"path";function va(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=Gr.replace(/__AGENT_ID__/g,D(e));return M({title:`AgentX \xB7 ${D(e)}`,activeTab:"admin",subtitle:`Agent \xB7 ${D(e)}`,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:r,css:Xr,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>${Kr}</script>`})}var Gr=`
7379
+ `);let c=Date.now();for(;!o&&Date.now()-c<wo;)await new Promise(u=>setTimeout(u,200))}}finally{clearInterval(l);try{e.end()}catch{}}return!0}function $a(t){return!Number.isFinite(t)||t<1?6:Math.min(720,Math.max(1,t))}function ko(t,e,a=5e3){let n=new Date(e).toISOString().slice(0,10),r=nt(process.cwd(),".agentx/task-history",t,n);if(!rt(r)){let o=new Date(e-864e5).toISOString().slice(0,10),s=nt(process.cwd(),".agentx/task-history",t,o);return rt(s)?ka(s,e,a):null}return ka(r,e,a)}function ka(t,e,a){let n=null,r=1/0;for(let o of mo(t)){if(!o.endsWith(".json"))continue;let s;try{s=JSON.parse(ho(uo(t,o),"utf-8"))}catch{continue}let l=s.startedAt,i;if(typeof l=="number")i=l;else if(typeof l=="string"){let u=Date.parse(l);if(!Number.isFinite(u))continue;i=u}else continue;let c=Math.abs(i-e);c<r&&c<=a&&(n=s,r=c)}return n}async function ja(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 ne(e,400,{error:"invalid dispatch id"}),!0;let s=r.slice(0,o),l=r.slice(o+1),i=Re();if(!i)return ne(e,503,{error:"ledger not available"}),!0;try{let c=i.db.prepare("SELECT id, ts, source, project, subject, intent, raw_json FROM intent_events WHERE id = ?").get(s);if(!c)return ne(e,404,{error:"event not found"}),!0;let u=i.db.prepare("SELECT decided_at, decided_by, agent_id, outcome, reason FROM intent_decisions WHERE event_id = ? AND decided_by = ?").get(s,l);if(!u)return ne(e,404,{error:"decision not found"}),!0;let m=i.db.prepare("SELECT resolved_at, status, duration_ms, result_summary FROM intent_resolutions WHERE decision_event_id = ? AND decision_decided_by = ?").get(s,l),x=null;try{x=JSON.parse(c.raw_json)}catch{}let b=Sa(c.source,x),_=x&&typeof x=="object"&&(x.text||x.message?.text||x.message?.caption||x.object_attributes?.note||x.object_attributes?.description||x.comment?.body||x.issue?.body||(typeof x.message=="string"?x.message:null)||(typeof x.prompt=="string"?x.prompt:null)||null)||b,M=null,E=null;if(u.agent_id){let h=ko(u.agent_id,u.decided_at);if(h){typeof h.responseText=="string"&&(M=h.responseText);let y=h.transcript;Array.isArray(y)&&(E=y.length)}}let S=ce?.business?.projects??[],d=ce?.business?.contactMap??[],p=Ue(ce?.business??{}),g={client:"unmapped",project:`unmapped/_${c.source}`,via:"fallback"},f=Ea(c.source,x,d);if(f)g={client:f.client,project:f.project||`${f.client}/_chat`,via:`contactMap (channel=${f.channel??"*"}${f.username?` username=${f.username}`:""}${f.chatId?` chatId=${f.chatId}`:""})`};else if(c.project)g={client:qe(c.project,S),project:c.project,via:`project namespace prefix (${c.project})`};else if(u.agent_id){let h=p.get(u.agent_id);h&&(g={client:h,project:`${h}/_${c.source}`,via:`orgChart fallback (agent ${u.agent_id} reports up to a PM whose project belongs to ${h})`})}ne(e,200,{id:r,eventId:s,source:c.source,subject:c.subject,intent:c.intent,project:c.project,decidedBy:u.decided_by,agentId:u.agent_id,outcome:u.outcome,reason:u.reason,startedAt:u.decided_at,resolvedAt:m?.resolved_at??null,durationMs:m?.duration_ms??null,input:_,response:M,transcriptLen:E,resolutionStatus:m?.status??null,resultSummary:m?.result_summary??null,attribution:g})}catch(c){ne(e,500,{error:c?.message??String(c)})}finally{i.close()}return!0}import{existsSync as To,readFileSync as Co}from"fs";import{resolve as Ra}from"path";Ne();function La(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=_o.replace(/__AGENT_ID__/g,P(e));return C({title:`AgentX \xB7 ${P(e)}`,activeTab:"admin",subtitle:`Agent \xB7 ${P(e)}`,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:r,css:Eo,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>${So}</script>`})}var _o=`
6293
7380
  <!-- Breadcrumb -->
6294
7381
  <div class="ax-crumb">
6295
7382
  <a href="/admin">Settings</a>
@@ -6662,7 +7749,7 @@ data: ${JSON.stringify({error:"ledger not available"})}
6662
7749
  </div>
6663
7750
  <div class="ax-field">
6664
7751
  <label class="lbl">Chat id <span class="opt">who's the person?</span></label>
6665
- <input class="inp mono" id="ho-chatid" placeholder="1816212449 or +21612345678" />
7752
+ <input class="inp mono" id="ho-chatid" placeholder="1816212449 or +10000000000" />
6666
7753
  </div>
6667
7754
  <div class="ax-field">
6668
7755
  <label class="lbl">Hand off to</label>
@@ -6878,7 +7965,7 @@ data: ${JSON.stringify({error:"ledger not available"})}
6878
7965
  </div>
6879
7966
  </div>
6880
7967
  </div>
6881
- `,Xr=`
7968
+ `,Eo=`
6882
7969
  /* Agent-specific layout + legacy styles for bits the migration left in
6883
7970
  * place (EasyMDE theming, skills tree, plain-editor). Shared chrome + tab
6884
7971
  * primitives live in components.css.ts. */
@@ -6997,7 +8084,7 @@ textarea.inp.mono { font-family: var(--ax-mono); }
6997
8084
 
6998
8085
  /* Agent-specific button variant used in rail context (no ax-btn wrapper) */
6999
8086
  .ax-btn.lg { padding: 9px 16px; font-size: 13px; }
7000
- `,Kr=`
8087
+ `,So=`
7001
8088
  const $ = (id) => document.getElementById(id);
7002
8089
  const state = { agent: null, activeSkill: null, activeSkillFile: null, identityPath: null };
7003
8090
 
@@ -7253,7 +8340,7 @@ async function loadAgent(){
7253
8340
  const msg = document.getElementById('mcp-msg');
7254
8341
  try {
7255
8342
  await req('POST', '/api/admin/agent/' + AGENT_ID + '/mcp', body);
7256
- if (msg) { msg.textContent = '\u2713 saved \u2014 agent picks it up at next daemon boot'; msg.style.color = 'var(--ax-success)'; }
8343
+ if (msg) { msg.textContent = '\u2713 saved \u2014 agent picks it up at next daemon boot'; msg.style.color = 'var(--ax-ok)'; }
7257
8344
  ['mcp-name','mcp-command','mcp-args','mcp-env'].forEach(function(id){ document.getElementById(id).value = ''; });
7258
8345
  await loadAgent();
7259
8346
  } catch (e) {
@@ -7282,7 +8369,7 @@ async function loadAgent(){
7282
8369
  const msg = document.getElementById('cap-msg');
7283
8370
  try {
7284
8371
  await req('PATCH', '/api/admin/agent/' + AGENT_ID + '/capability', body);
7285
- if (msg) { msg.textContent = '\u2713 saved \u2014 restart the daemon for changes to take effect'; msg.style.color = 'var(--ax-success)'; }
8372
+ if (msg) { msg.textContent = '\u2713 saved \u2014 restart the daemon for changes to take effect'; msg.style.color = 'var(--ax-ok)'; }
7286
8373
  await loadAgent();
7287
8374
  } catch (e) {
7288
8375
  if (msg) { msg.textContent = e.message; msg.style.color = 'var(--ax-err)'; }
@@ -7786,7 +8873,7 @@ async function dispatchTd(text) {
7786
8873
  appendTdTyping();
7787
8874
  const t0 = Date.now();
7788
8875
  try {
7789
- // Use /chat endpoint so test-drive exercises the same path as noqta.tn.
8876
+ // Use /chat endpoint so test-drive exercises the same path as example.com.
7790
8877
  // Falls back to /task reply shape if /chat isn't reachable (no auth configured).
7791
8878
  let reply, queuedTask;
7792
8879
  try {
@@ -7851,15 +8938,15 @@ document.addEventListener('keydown', (e) => {
7851
8938
  /* ===== Boot ===== */
7852
8939
  initOptsToggles();
7853
8940
  loadAgent();
7854
- `;function ya(t,e,a,n=[],r){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(va({agentId:a,peers:n,localToken:r}))}async function wa(t,e,a){try{let n=t.method==="GET"?void 0:await bo(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){$e(e,404,{error:`unknown agent endpoint: ${a}`});return}let i=s[1],l=s[2]||"",d=`${t.method} ${l}`,u={"GET ":()=>fe(i),"PATCH ":()=>Yr(i,n),"PATCH capability":()=>eo(i,n),"POST mcp":()=>Qr(i,n),"DELETE mcp":()=>Zr(i,n),"GET identity":()=>to(i),"GET identity/file":()=>ao(i,String(o.path||"")),"PUT identity/file":()=>no(i,n),"GET skills":()=>ro(i),"POST skills":()=>oo(i,n),"DELETE skills":()=>so(i,n),"GET skills/tree":()=>io(i,String(o.slug||"")),"GET skills/file":()=>lo(i,String(o.slug||""),String(o.path||"")),"PUT skills/file":()=>co(i,n),"GET skills/deps":()=>po(i,String(o.slug||"")),"POST skills/install":()=>uo(i,n,t),"POST skills/deps":()=>mo(i,n,t),"GET channels":()=>ho(i),"GET activity":()=>go(i,t),"GET handovers":()=>fo(i),"POST handovers":()=>xo(i,n),"DELETE handovers":()=>vo(n)}[d];if(!u){$e(e,404,{error:`unknown agent sub-endpoint: ${d}`});return}let f=await u();$e(e,200,f)}catch(n){$e(e,400,{error:n?.message||"agent op failed"})}}function ka(){let t=ba(process.cwd(),"agentx.json");return Jr(t)?JSON.parse(Vr(t,"utf-8")):null}function z(t){let e=ka();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 fe(t){let{def:e,cfg:a}=z(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 Yr(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:fe(t)}}function Qr(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:fe(t)}}function Zr(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:fe(t)}}function eo(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:fe(t)}}function to(t){let{def:e}=z(t);return de(e.workspace)}function ao(t,e){if(!e)throw new Error("path query param required");let{def:a}=z(t);return we(a.workspace,e)}function no(t,e){let a=String(e?.path||"");if(!a)throw new Error("path required");let{def:n}=z(t);return ke(n.workspace,a,String(e?.content??""))}function ro(t){let{def:e}=z(t),a=de(e.workspace);return{skills:a.skills,workspace:a.workspace}}function oo(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=z(t);return _e(n.workspace,a,{title:e?.title,content:e?.content})}function so(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=z(t);return Ee(n.workspace,a)}function io(t,e){if(!e)throw new Error("slug query param required");let{def:a}=z(t),n=ft(a.workspace,e),r=Se(a.workspace,e);return{slug:e,tree:n,deps:r}}function lo(t,e,a){if(!e||!a)throw new Error("slug and path query params required");let{def:n}=z(t);return xt(n.workspace,e,a)}function co(t,e){let a=String(e?.slug||""),n=String(e?.path||"");if(!a||!n)throw new Error("slug and path required");let{def:r}=z(t);return vt(r.workspace,a,n,String(e?.content??""))}function po(t,e){if(!e)throw new Error("slug query param required");let{def:a}=z(t);return Se(a.workspace,e)}async function uo(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=_a(e?.worker),{def:o}=z(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(`
7855
- `);return Ea(a,r,s,`install-${n}:${Date.now()}`)}async function mo(t,e,a){let n=String(e?.slug||"").trim();if(!n)throw new Error("slug required");let r=_a(e?.worker),{def:o}=z(t),s=Se(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=ba(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(`
7856
- `);return Ea(a,r,l,`deps-${t}-${n}:${Date.now()}`)}function _a(t){if(t&&typeof t=="string")return t;let e=G();return e.dashboard?.draftAgent||e.node?.defaultAgent||Object.keys(e.agents).find(a=>a.includes("devops"))||Object.keys(e.agents)[0]}async function Ea(t,e,a,n){let r=G(),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}})}),d=await l.text(),p;try{p=JSON.parse(d)}catch{p={content:d}}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 ho(t){let e=ka(),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 go(t,e){try{let n=(G().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 Je(){return new nt}function fo(t){let e=Je(),{incoming:a,outgoing:n}=e.listByAgent(t);return{incoming:a,outgoing:n}}function xo(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,d=Je().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:d}}function vo(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:Je().remove(e,a,n)?"Released":"No active handover for that chat"}}function $e(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function bo(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 Sa=[{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 Ve(t={}){let e=`<script>window.UI_LABELS = ${JSON.stringify(le)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
8941
+ `;function Pa(t,e,a,n=[],r){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(La({agentId:a,peers:n,localToken:r}))}async function Da(t,e,a){try{let n=t.method==="GET"?void 0:await Jo(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){Pe(e,404,{error:`unknown agent endpoint: ${a}`});return}let l=s[1],i=s[2]||"",c=`${t.method} ${i}`,m={"GET ":()=>we(l),"PATCH ":()=>Ao(l,n),"PATCH capability":()=>$o(l,n),"POST mcp":()=>Mo(l,n),"DELETE mcp":()=>Io(l,n),"GET identity":()=>jo(l),"GET identity/file":()=>Lo(l,String(o.path||"")),"PUT identity/file":()=>Ro(l,n),"GET skills":()=>Po(l),"POST skills":()=>Do(l,n),"DELETE skills":()=>Oo(l,n),"GET skills/tree":()=>Ho(l,String(o.slug||"")),"GET skills/file":()=>No(l,String(o.slug||""),String(o.path||"")),"PUT skills/file":()=>Bo(l,n),"GET skills/deps":()=>zo(l,String(o.slug||"")),"POST skills/install":()=>qo(l,n,t),"POST skills/deps":()=>Uo(l,n,t),"GET channels":()=>Fo(l),"GET activity":()=>Wo(l,t),"GET handovers":()=>Go(l),"POST handovers":()=>Xo(l,n),"DELETE handovers":()=>Ko(n)}[c];if(!m){Pe(e,404,{error:`unknown agent sub-endpoint: ${c}`});return}let x=await m();Pe(e,200,x)}catch(n){Pe(e,400,{error:n?.message||"agent op failed"})}}function Oa(){let t=Ra(process.cwd(),"agentx.json");return To(t)?JSON.parse(Co(t,"utf-8")):null}function z(t){let e=Oa();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 we(t){let{def:e,cfg:a}=z(t),n=e.workspace?ue(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 Ao(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}=T(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:we(t)}}function Mo(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(l=>String(l)):[],o;if(e?.env&&typeof e.env=="object"){o={};for(let[l,i]of Object.entries(e.env))typeof i=="string"&&(o[l]=i);Object.keys(o).length===0&&(o=void 0)}let{summary:s}=T(l=>{if(!l.agents?.[t])throw new Error(`Agent "${t}" not found`);return l.agents[t].mcp=l.agents[t].mcp||{},l.agents[t].mcp[a]={command:n,args:r,...o?{env:o}:{}},`agent "${t}" mcp.${a} upserted`});return{summary:s,agent:we(t)}}function Io(t,e){let a=String(e?.name||"").trim();if(!a)throw new Error("name required");let{summary:n}=T(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:we(t)}}function $o(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}=T(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);let o={...r.agents[t]};for(let[s,l]of Object.entries(a))l===void 0?delete o[s]:o[s]=l;return r.agents[t]=o,`agent "${t}" capability updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:we(t)}}function jo(t){let{def:e}=z(t);return ue(e.workspace)}function Lo(t,e){if(!e)throw new Error("path query param required");let{def:a}=z(t);return _e(a.workspace,e)}function Ro(t,e){let a=String(e?.path||"");if(!a)throw new Error("path required");let{def:n}=z(t);return Ee(n.workspace,a,String(e?.content??""))}function Po(t){let{def:e}=z(t),a=ue(e.workspace);return{skills:a.skills,workspace:a.workspace}}function Do(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=z(t);return Se(n.workspace,a,{title:e?.title,content:e?.content})}function Oo(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=z(t);return Te(n.workspace,a)}function Ho(t,e){if(!e)throw new Error("slug query param required");let{def:a}=z(t),n=Ct(a.workspace,e),r=Ce(a.workspace,e);return{slug:e,tree:n,deps:r}}function No(t,e,a){if(!e||!a)throw new Error("slug and path query params required");let{def:n}=z(t);return At(n.workspace,e,a)}function Bo(t,e){let a=String(e?.slug||""),n=String(e?.path||"");if(!a||!n)throw new Error("slug and path required");let{def:r}=z(t);return Mt(r.workspace,a,n,String(e?.content??""))}function zo(t,e){if(!e)throw new Error("slug query param required");let{def:a}=z(t);return Ce(a.workspace,e)}async function qo(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=Ha(e?.worker),{def:o}=z(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(`
8942
+ `);return Na(a,r,s,`install-${n}:${Date.now()}`)}async function Uo(t,e,a){let n=String(e?.slug||"").trim();if(!n)throw new Error("slug required");let r=Ha(e?.worker),{def:o}=z(t),s=Ce(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 l=Ra(o.workspace,".claude","skills",n),i=[`Install dependencies for skill "${n}" in agent "${t}".`,`cd to: ${l}`,`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(`
8943
+ `);return Na(a,r,i,`deps-${t}-${n}:${Date.now()}`)}function Ha(t){if(t&&typeof t=="string")return t;let e=G();return e.dashboard?.draftAgent||e.node?.defaultAgent||Object.keys(e.agents).find(a=>a.includes("devops"))||Object.keys(e.agents)[0]}async function Na(t,e,a,n){let r=G(),o=(r.dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),s={"Content-Type":"application/json"},l=t.headers.authorization;l?s.Authorization=String(l):r.dashboard.token&&(s.Authorization=`Bearer ${r.dashboard.token}`);let i=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 i.text(),u;try{u=JSON.parse(c)}catch{u={content:c}}if(!i.ok)throw new Error(u?.error||`daemon /task HTTP ${i.status}`);return{worker:e,taskId:u?.taskId,content:u?.content,duration:u?.duration,error:u?.error}}function Fo(t){let e=Oa(),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 Wo(t,e){try{let n=(G().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(l=>l.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 st(){return new ft}function Go(t){let e=st(),{incoming:a,outgoing:n}=e.listByAgent(t);return{incoming:a,outgoing:n}}function Xo(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,l=e?.summary?String(e.summary):void 0,i=e?.expiresAt?String(e.expiresAt):void 0,c=st().set({channel:a,chatId:n,accountId:s,fromAgent:o,toAgent:r,summary:l,expiresAt:i,createdBy:"admin-ui"});return{summary:`Handed off ${a}:${n} from ${o} to ${r}`,record:c}}function Ko(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:st().remove(e,a,n)?"Released":"No active handover for that chat"}}function Pe(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Jo(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 pe={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 Ba=[{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 it(t={}){let e=`<script>window.UI_LABELS = ${JSON.stringify(pe)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
7857
8944
  <span id="conn-dot" class="ax-dot ax-dot--ok ax-dot--pulse" title="connected"></span>
7858
8945
  <span id="conn-label">live</span>`,n=`<div class="ax-app-live">
7859
8946
  <section id="statstrip" class="ax-statstrip"></section>
7860
8947
  <main id="grid" class="ax-live__body"></main>
7861
8948
  </div>
7862
- `;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:yo,scripts:e+`<script>${wo}</script>`,headExtras:`<script>
8949
+ `;return C({title:`${pe.brand} \xB7 ${pe.subtitle}`,activeTab:"live",subtitle:pe.subtitle,peers:t.peers,currentPeerId:t.currentPeerId,customHeader:void 0,noMain:!0,body:n,css:Vo,scripts:e+`<script>${Yo}</script>`,headExtras:`<script>
7863
8950
  // rightExtras for the topbar are injected at runtime \u2014 they reference
7864
8951
  // IDs (#ts, #conn-dot) that the script below addresses directly.
7865
8952
  document.addEventListener('DOMContentLoaded', () => {
@@ -7870,7 +8957,7 @@ loadAgent();
7870
8957
  extras.innerHTML = ${JSON.stringify(a)};
7871
8958
  right.insertBefore(extras, right.firstChild);
7872
8959
  });
7873
- </script>`})}var yo=`
8960
+ </script>`})}var Vo=`
7874
8961
  /* --- Page frame --- */
7875
8962
  .ax-app-live { min-height: 100vh; display: flex; flex-direction: column; }
7876
8963
 
@@ -8071,7 +9158,7 @@ loadAgent();
8071
9158
  border-top-color: var(--ax-accent); border-radius: 50%;
8072
9159
  animation: ax-spin 800ms linear infinite; display: inline-block;
8073
9160
  }
8074
- @keyframes ax-spin { to { transform: rotate(360deg); } }`,wo=`
9161
+ @keyframes ax-spin { to { transform: rotate(360deg); } }`,Yo=`
8075
9162
  'use strict';
8076
9163
 
8077
9164
  const ui = { nodes: new Map(), summary: { nodes: 0, agents: 0, busy: 0, errors: 0 } };
@@ -8322,7 +9409,7 @@ function renderAgent(a, node) {
8322
9409
  // The page's job is "who is alive and what are they doing RIGHT NOW". Giving
8323
9410
  // an idle agent the same real estate as a working one \u2014 model, last-reply
8324
9411
  // excerpt, footer \u2014 is exactly backwards: it makes the answer harder to see
8325
- // the more agents you run. On clawd (22 agents) the busy ones were lost in a
9412
+ // the more agents you run. On peer (22 agents) the busy ones were lost in a
8326
9413
  // wall of identical idle cards.
8327
9414
  //
8328
9415
  // Collapsed still carries what the question needs: who, engine, and when it
@@ -8543,7 +9630,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
8543
9630
  });
8544
9631
  }
8545
9632
 
8546
- `;var Ta=`
9633
+ `;var za=`
8547
9634
  .mx-content{max-width:1180px;margin:0 auto;padding:0 24px 56px}
8548
9635
  .mx-updated{margin:0;color:var(--ax-muted);font-size:11px;font-family:var(--ax-mono)}
8549
9636
  .mx-section{margin-bottom:28px}.mx-section .ax-section-head{margin-bottom:14px}
@@ -8713,7 +9800,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
8713
9800
  .mx-summary{max-width:56vw}
8714
9801
  }
8715
9802
  @media(prefers-reduced-motion:reduce){.mx-drawer{transition:none}}
8716
- `;var Ca=`<script>
9803
+ `;var qa=`<script>
8717
9804
  window.MX=(function(){
8718
9805
  var ENT={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'};
8719
9806
  function esc(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return ENT[c]})}
@@ -8822,7 +9909,7 @@ window.MX=(function(){
8822
9909
  verdict:verdict,verdictChip:verdictChip,mark:mark,causeLabel:causeLabel,
8823
9910
  setHealth:setHealth,get:get};
8824
9911
  })();
8825
- </script>`;var Aa=`<script>
9912
+ </script>`;var Ua=`<script>
8826
9913
  window.MXD=(function(){
8827
9914
  function el(id){return document.getElementById(id)}
8828
9915
  function tz(){return -new Date().getTimezoneOffset()}
@@ -9036,7 +10123,7 @@ window.MXD=(function(){
9036
10123
 
9037
10124
  return {openDay:openDay,openJob:openJob,openConversation:openConversation};
9038
10125
  })();
9039
- </script>`;var Ma=`<script>
10126
+ </script>`;var Fa=`<script>
9040
10127
  (function(){
9041
10128
  var LANES=[
9042
10129
  {id:'cron',name:'Scheduled',hint:'cron jobs'},
@@ -9352,7 +10439,7 @@ window.MXD=(function(){
9352
10439
  window.addEventListener('scroll',hideTip,{passive:true});
9353
10440
  load();
9354
10441
  })();
9355
- </script>`;var Ia=`<script>
10442
+ </script>`;var Wa=`<script>
9356
10443
  (function(){
9357
10444
  var showAll=document.getElementById('mx-show-all'),expanded=false;
9358
10445
  var esc=MX.esc;
@@ -9499,17 +10586,17 @@ window.MXD=(function(){
9499
10586
  }
9500
10587
  load();setInterval(load,5000);
9501
10588
  })();
9502
- </script>`;var V={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>',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>',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 Y(t,e,a,n,r=""){return N({icon:t,title:e,lead:a,actionHtml:r}).replace("<h2>",`<h2 id="${n}">`)}var ko=[{id:"activity",label:"Activity"},{id:"lifetime",label:"Lifetime"},{id:"ops",label:"Operations"}],_o=[{days:0,label:"Today"},{days:7,label:"7d"},{days:30,label:"30d"},{days:90,label:"90d"}];function $a(t){let e=Te({kicker:"Operations",title:"Mesh operations",lead:"What the fleet actually did, how long it lived, and which of it was worth running."})+Ce([{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">
10589
+ </script>`;var Y={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>',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>',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 Q(t,e,a,n,r=""){return N({icon:t,title:e,lead:a,actionHtml:r}).replace("<h2>",`<h2 id="${n}">`)}var Qo=[{id:"activity",label:"Activity"},{id:"lifetime",label:"Lifetime"},{id:"ops",label:"Operations"}],Zo=[{days:0,label:"Today"},{days:7,label:"7d"},{days:30,label:"30d"},{days:90,label:"90d"}];function Ga(t){let e=Ae({kicker:"Operations",title:"Mesh operations",lead:"What the fleet actually did, how long it lived, and which of it was worth running."})+Me([{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">
9503
10590
  <div class="mx-tabs" role="tablist" aria-label="Mesh views">
9504
- ${ko.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("")}
10591
+ ${Qo.map((l,i)=>`<button class="mx-tab" type="button" role="tab" id="mx-tab-${l.id}" aria-controls="mx-view-${l.id}" aria-selected="${i===0}" data-view="${l.id}">${l.label}</button>`).join("")}
9505
10592
  </div>
9506
10593
  <div class="mx-range" id="mx-range" role="group" aria-label="History window">
9507
- ${_o.map(i=>`<button type="button" data-days="${i.days}" aria-pressed="${i.days===30}">${i.label}</button>`).join("")}
10594
+ ${Zo.map(l=>`<button type="button" data-days="${l.days}" aria-pressed="${l.days===30}">${l.label}</button>`).join("")}
9508
10595
  </div>
9509
10596
  </div>
9510
10597
  <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">
9511
10598
  <section class="mx-section" aria-labelledby="mx-lanes-title">
9512
- ${Y(V.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")}
10599
+ ${Q(Y.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")}
9513
10600
  <div id="mx-lanes"><div class="mx-empty">Loading activity...</div></div>
9514
10601
  <div class="mx-axis" id="mx-axis"></div>
9515
10602
  <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>
@@ -9517,32 +10604,32 @@ window.MXD=(function(){
9517
10604
 
9518
10605
  <div class="mx-two">
9519
10606
  <section class="mx-section" aria-labelledby="mx-origins-title">
9520
- ${Y(V.breakage,"Where it breaks","Attempts per origin, with the failed share marked on the same bar.","mx-origins-title")}
10607
+ ${Q(Y.breakage,"Where it breaks","Attempts per origin, with the failed share marked on the same bar.","mx-origins-title")}
9521
10608
  <div class="mx-bars" id="mx-origins"><div class="mx-empty">Loading...</div></div>
9522
10609
  </section>
9523
10610
  <section class="mx-section" aria-labelledby="mx-causes-title">
9524
- ${Y(V.breakage,"Why it fails","Failures grouped by cause class, matched from the recorded error text.","mx-causes-title")}
10611
+ ${Q(Y.breakage,"Why it fails","Failures grouped by cause class, matched from the recorded error text.","mx-causes-title")}
9525
10612
  <div class="mx-bars" id="mx-causes"><div class="mx-empty">Loading...</div></div>
9526
10613
  <p class="mx-note" id="mx-cause-note"></p>
9527
10614
  </section>
9528
10615
  </div>
9529
10616
 
9530
10617
  <section class="mx-section" aria-labelledby="mx-scatter-title">
9531
- ${Y(V.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")}
10618
+ ${Q(Y.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")}
9532
10619
  <div class="mx-scatter" id="mx-scatter"><div class="mx-empty">Loading jobs...</div></div>
9533
10620
  <div class="mx-legend" id="mx-scatter-legend"></div>
9534
10621
  <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>
9535
10622
  </section>
9536
10623
  </div>`,r=`<div class="mx-view" id="mx-view-lifetime" role="tabpanel" aria-labelledby="mx-tab-lifetime" hidden>
9537
10624
  <section class="mx-section" aria-labelledby="mx-threads-title">
9538
- ${Y(V.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")}
10625
+ ${Q(Y.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")}
9539
10626
  <div class="mx-chips" id="mx-thread-chips"></div>
9540
10627
  <div id="mx-threads"><div class="mx-empty">Loading threads...</div></div>
9541
10628
  <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>
9542
10629
  </section>
9543
10630
 
9544
10631
  <section class="mx-section" aria-labelledby="mx-rot-title">
9545
- ${Y(V.cuts,"Session cuts","Why threads lost their session, across the fleet.","mx-rot-title")}
10632
+ ${Q(Y.cuts,"Session cuts","Why threads lost their session, across the fleet.","mx-rot-title")}
9546
10633
  <div class="mx-bars" id="mx-rotations"><div class="mx-empty">Loading...</div></div>
9547
10634
  <p class="mx-note" id="mx-rot-note"></p>
9548
10635
  </section>
@@ -9550,23 +10637,23 @@ window.MXD=(function(){
9550
10637
  <p id="mx-updated" class="mx-updated" aria-live="polite">Connecting to the fleet...</p>
9551
10638
 
9552
10639
  <section class="mx-section" aria-labelledby="mx-auto-title">
9553
- ${Y(V.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>')}
10640
+ ${Q(Y.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>')}
9554
10641
  <div class="ax-stack" id="mx-runs"><div class="mx-empty">Loading schedules...</div></div>
9555
10642
  </section>
9556
10643
 
9557
10644
  <div class="mx-columns">
9558
10645
  <section class="mx-section" aria-labelledby="mx-active-title">
9559
- ${Y(V.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>')}
10646
+ ${Q(Y.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>')}
9560
10647
  <div class="ax-stack" id="mx-active"><div class="mx-empty">No activity loaded.</div></div>
9561
10648
  </section>
9562
10649
  <section class="mx-section" aria-labelledby="mx-nodes-title">
9563
- ${Y(V.nodes,"Nodes","Reachability and capacity across the fleet.","mx-nodes-title",'<span class="ax-tab-count" id="mx-node-count">0 nodes</span>')}
10650
+ ${Q(Y.nodes,"Nodes","Reachability and capacity across the fleet.","mx-nodes-title",'<span class="ax-tab-count" id="mx-node-count">0 nodes</span>')}
9564
10651
  <div class="ax-stack" id="mx-nodes"><div class="mx-empty">No nodes loaded.</div></div>
9565
10652
  </section>
9566
10653
  </div>
9567
10654
 
9568
10655
  <section class="mx-section" aria-labelledby="mx-agents-title">
9569
- ${Y(V.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>')}
10656
+ ${Q(Y.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>')}
9570
10657
  <div class="mx-agent-grid" id="mx-agents"><div class="mx-empty">No agents loaded.</div></div>
9571
10658
  </section>
9572
10659
  </div>`,s=`${e}<main class="mx-content">
@@ -9582,7 +10669,7 @@ window.MXD=(function(){
9582
10669
  <button class="ax-btn ax-btn--ghost" id="mx-close" type="button" aria-label="Close details">Close</button>
9583
10670
  </header>
9584
10671
  <div class="mx-drawer__body" id="mx-drawer-body"></div>
9585
- </aside>`;return M({title:"AgentX \xB7 Mesh Operations",activeTab:"mesh",subtitle:"Operations",peers:t.peers,noMain:!0,body:s,css:Ta,scripts:Ca+Eo+Aa+Ma+Ia})}var Eo=`<script>
10672
+ </aside>`;return C({title:"AgentX \xB7 Mesh Operations",activeTab:"mesh",subtitle:"Operations",peers:t.peers,noMain:!0,body:s,css:za,scripts:qa+es+Ua+Fa+Wa})}var es=`<script>
9586
10673
  (function(){
9587
10674
  var tabs=Array.prototype.slice.call(document.querySelectorAll('.mx-tab'));
9588
10675
  var range=document.getElementById('mx-range');
@@ -9610,7 +10697,7 @@ window.MXD=(function(){
9610
10697
  var saved=null;try{saved=localStorage.getItem('mx-view')}catch(e){}
9611
10698
  select(tabs.some(function(t){return t.dataset.view===saved})?saved:'activity');
9612
10699
  })();
9613
- </script>`;async function ja(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 d=await fetch(i.url+"/analytics/mesh"+o,{headers:l,signal:n.signal});return d.ok?{node:i,data:await d.json()}:{node:i,error:`HTTP ${d.status}`}}catch(d){return{node:i,error:d?.name==="AbortError"?"timeout":d?.message||"unreachable"}}}))}finally{clearTimeout(r)}return So(s,e.days)}function So(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=[],d=0,p=0,u=0,f=0,v=0,k=0;for(let{node:E,data:S}of t)if(S){a.runs+=S.totals.runs,a.errors+=S.totals.errors,a.hours+=S.totals.hours,a.agents+=S.totals.agents,a.threads+=S.totals.threads;for(let c of S.days){let m=n.get(c.day)||{day:c.day,cron:[0,0],workflow:[0,0],direct:[0,0]};for(let g of["cron","workflow","direct"])m[g][0]+=c[g]?.[0]||0,m[g][1]+=c[g]?.[1]||0;n.set(c.day,m)}for(let c of S.origins){let m=r.get(c.channel)||{channel:c.channel,runs:0,errors:0,hours:0};m.runs+=c.runs,m.errors+=c.errors,m.hours+=c.hours,r.set(c.channel,m)}for(let c of S.causes){let m=o.get(c.cause)||{cause:c.cause,count:0,agents:[],example:""};m.count+=c.count;for(let g of c.agents)m.agents.includes(g)||m.agents.push(g);m.example||(m.example=c.example),o.set(c.cause,m)}for(let c of S.rotations.byReason)s.set(c.reason,(s.get(c.reason)||0)+c.count);d+=S.rotations.total,p+=S.rotations.tokenSum||0,u+=S.rotations.tokenSamples||0,f=Math.max(f,S.rotations.maxTokens),v+=S.retention.traces,k+=S.retention.tracesWithSteps;for(let c of S.jobs)i.push({...c,node:E.name,nodeUrl:E.url});for(let c of S.threads)l.push({...c,node:E.name,nodeUrl:E.url})}let A=t.filter(E=>E.data).map(E=>E.data.since).filter(E=>Number.isFinite(E));return{generatedAt:Date.now(),windowDays:e,since:A.length?Math.min(...A):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,S)=>E.day.localeCompare(S.day)),origins:[...r.values()].map(E=>({...E,hours:Math.round(E.hours*100)/100})).sort((E,S)=>S.runs-E.runs),causes:[...o.values()].sort((E,S)=>S.count-E.count),jobs:i.sort((E,S)=>S.hours-E.hours),threads:l.sort((E,S)=>S.lastAt-S.firstAt-(E.lastAt-E.firstAt)||S.runs-E.runs),rotations:{total:d,byReason:[...s.entries()].map(([E,S])=>({reason:E,count:S})).sort((E,S)=>S.count-E.count),tokenSum:p,tokenSamples:u,maxTokens:f},retention:{traces:v,tracesWithSteps:k}}}async function La(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 Ra(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 d=await fetch(i.url+"/analytics/day"+o,{headers:l,signal:n.signal});return d.ok?{node:i,data:await d.json()}:{node:i,error:`HTTP ${d.status}`}}catch(d){return{node:i,error:d?.name==="AbortError"?"timeout":d?.message||"unreachable"}}}))}finally{clearTimeout(r)}return To(s,e.day)}function To(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 d=n.get(l.channel)||{channel:l.channel,runs:0,errors:0,ms:0};d.runs+=l.runs,d.errors+=l.errors,d.ms+=l.ms,n.set(l.channel,d)}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 Da(t={}){let e=`
10700
+ </script>`;async function Xa(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 l=>{let i={Accept:"application/json"};l.token&&(i.Authorization=`Bearer ${l.token}`);try{let c=await fetch(l.url+"/analytics/mesh"+o,{headers:i,signal:n.signal});return c.ok?{node:l,data:await c.json()}:{node:l,error:`HTTP ${c.status}`}}catch(c){return{node:l,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return ts(s,e.days)}function ts(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,l=[],i=[],c=0,u=0,m=0,x=0,b=0,_=0;for(let{node:E,data:S}of t)if(S){a.runs+=S.totals.runs,a.errors+=S.totals.errors,a.hours+=S.totals.hours,a.agents+=S.totals.agents,a.threads+=S.totals.threads;for(let d of S.days){let p=n.get(d.day)||{day:d.day,cron:[0,0],workflow:[0,0],direct:[0,0]};for(let g of["cron","workflow","direct"])p[g][0]+=d[g]?.[0]||0,p[g][1]+=d[g]?.[1]||0;n.set(d.day,p)}for(let d of S.origins){let p=r.get(d.channel)||{channel:d.channel,runs:0,errors:0,hours:0};p.runs+=d.runs,p.errors+=d.errors,p.hours+=d.hours,r.set(d.channel,p)}for(let d of S.causes){let p=o.get(d.cause)||{cause:d.cause,count:0,agents:[],example:""};p.count+=d.count;for(let g of d.agents)p.agents.includes(g)||p.agents.push(g);p.example||(p.example=d.example),o.set(d.cause,p)}for(let d of S.rotations.byReason)s.set(d.reason,(s.get(d.reason)||0)+d.count);c+=S.rotations.total,u+=S.rotations.tokenSum||0,m+=S.rotations.tokenSamples||0,x=Math.max(x,S.rotations.maxTokens),b+=S.retention.traces,_+=S.retention.tracesWithSteps;for(let d of S.jobs)l.push({...d,node:E.name,nodeUrl:E.url});for(let d of S.threads)i.push({...d,node:E.name,nodeUrl:E.url})}let M=t.filter(E=>E.data).map(E=>E.data.since).filter(E=>Number.isFinite(E));return{generatedAt:Date.now(),windowDays:e,since:M.length?Math.min(...M):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,S)=>E.day.localeCompare(S.day)),origins:[...r.values()].map(E=>({...E,hours:Math.round(E.hours*100)/100})).sort((E,S)=>S.runs-E.runs),causes:[...o.values()].sort((E,S)=>S.count-E.count),jobs:l.sort((E,S)=>S.hours-E.hours),threads:i.sort((E,S)=>S.lastAt-S.firstAt-(E.lastAt-E.firstAt)||S.runs-E.runs),rotations:{total:c,byReason:[...s.entries()].map(([E,S])=>({reason:E,count:S})).sort((E,S)=>S.count-E.count),tokenSum:u,tokenSamples:m,maxTokens:x},retention:{traces:b,tracesWithSteps:_}}}async function Ka(t,e,a,n){let r=a.replace(/\/+$/,""),o=e.find(l=>l.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 l=await fetch(r+n,{headers:s}),i=await l.text();t.writeHead(l.status,{"Content-Type":"application/json; charset=utf-8"}),t.end(i)}catch(l){t.writeHead(502,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:l?.message||"upstream fetch failed"}))}}async function Ja(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 l=>{let i={Accept:"application/json"};l.token&&(i.Authorization=`Bearer ${l.token}`);try{let c=await fetch(l.url+"/analytics/day"+o,{headers:i,signal:n.signal});return c.ok?{node:l,data:await c.json()}:{node:l,error:`HTTP ${c.status}`}}catch(c){return{node:l,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return as(s,e.day)}function as(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:l}of t)if(l){a.runs+=l.totals.runs,a.errors+=l.totals.errors,a.ms+=l.totals.ms,a.inputTokens+=l.totals.inputTokens,a.outputTokens+=l.totals.outputTokens;for(let i of l.origins){let c=n.get(i.channel)||{channel:i.channel,runs:0,errors:0,ms:0};c.runs+=i.runs,c.errors+=i.errors,c.ms+=i.ms,n.set(i.channel,c)}for(let i of l.causes)r.set(i.cause,(r.get(i.cause)||0)+i.count);for(let i of l.conversations)o.push({...i,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,l)=>l.runs-s.runs),causes:[...r.entries()].map(([s,l])=>({cause:s,count:l})).sort((s,l)=>l.count-s.count),conversations:o.sort((s,l)=>l.ms-s.ms||l.turns-s.turns)}}function Va(t={}){let e=`
9614
10701
  <select id="boardPicker" title="Switch board"></select>
9615
10702
  <div class="search">
9616
10703
  <span class="icon">\u2315</span>
@@ -9711,7 +10798,7 @@ window.MXD=(function(){
9711
10798
  </footer>
9712
10799
  </div>
9713
10800
  </div>
9714
- <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:Co,scripts:`<script>${Ao}</script>`,headExtras:`<script>
10801
+ <script src="/sortable.min.js"></script>`;return C({title:"AgentX \xB7 Boards",activeTab:"boards",subtitle:"Boards",subheader:e,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a,css:ns,scripts:`<script>${rs}</script>`,headExtras:`<script>
9715
10802
  // The boards page has its own connection dot + wants body height:100%
9716
10803
  // for the full-viewport kanban layout. Inject the dot into the topbar
9717
10804
  // and override body height at runtime so the shared shell doesn't
@@ -9727,7 +10814,7 @@ window.MXD=(function(){
9727
10814
  right.insertBefore(dot, right.firstChild);
9728
10815
  }
9729
10816
  });
9730
- </script>`})}var Co=`
10817
+ </script>`})}var ns=`
9731
10818
  /* Kanban subheader \u2014 replaces the legacy toolbar that used to live in <header>. */
9732
10819
  .ax-subheader select, .ax-subheader input, .ax-subheader button {
9733
10820
  background: var(--col); color: var(--text); border: 1px solid var(--border);
@@ -9980,7 +11067,7 @@ header a.link:hover { color: var(--accent); border-color: var(--accent); }
9980
11067
  .draft-box .draft-row .hint { color: var(--muted); font-size: 12px; flex: 1; }
9981
11068
  .draft-box .draft-row .hint.err { color: var(--red); }
9982
11069
  .draft-box .draft-row .hint.ok { color: var(--green); }
9983
- `,Ao=`
11070
+ `,rs=`
9984
11071
  'use strict';
9985
11072
  const state = {
9986
11073
  boards: [], current: null, items: {},
@@ -10916,7 +12003,7 @@ const activity = {
10916
12003
  };
10917
12004
 
10918
12005
  function resolveDaemonUrl() {
10919
- // Allow ?daemon=http://host:port override; fall back to localhost:18800 (MacBook) then 19900 (clawd).
12006
+ // Allow ?daemon=http://host:port override; fall back to localhost:18800 (MacBook) then 19900 (peer).
10920
12007
  const q = new URLSearchParams(window.location.search).get('daemon');
10921
12008
  if (q) return q.replace(/\\/+$/, '');
10922
12009
  return localStorage.getItem('agentx.daemon') || 'http://localhost:18800';
@@ -11039,9 +12126,9 @@ function appendEvents(events) {
11039
12126
  }
11040
12127
 
11041
12128
  loadBoards().catch(e => toast('Init failed: ' + e.message));
11042
- `;function Pa(t={}){let a=`<h1>Plain-English glossary</h1>
12129
+ `;function Ya(t={}){let a=`<h1>Plain-English glossary</h1>
11043
12130
  <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>
11044
- ${Sa.map(n=>{let r=n.alias?`<span class="alias" title="Schema key">${D(n.alias)}</span>`:"";return`<article class="term"><h3>${D(n.term)}${r}</h3><p>${D(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:Mo})}var Mo=`
12131
+ ${Ba.map(n=>{let r=n.alias?`<span class="alias" title="Schema key">${P(n.alias)}</span>`:"";return`<article class="term"><h3>${P(n.term)}${r}</h3><p>${P(n.definition)}</p></article>`}).join("")}`;return C({title:`${pe.brand} \xB7 Glossary`,activeTab:"glossary",subtitle:"Glossary",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:os})}var os=`
11045
12132
  main { max-width: 760px; margin: 0 auto; padding: 32px 24px 80px; }
11046
12133
  h1 { font-size: 22px; margin: 0 0 6px; font-weight: 600; letter-spacing: -0.01em; }
11047
12134
  .lead {
@@ -11071,11 +12158,12 @@ article.term .alias {
11071
12158
  }
11072
12159
  article.term p {
11073
12160
  margin: 0; color: var(--ax-text-2); font-size: 13px; line-height: 1.6;
11074
- }`;function Oa(t={}){let e=`<div class="ax-wf__root">
12161
+ }`;function Qa(t={}){let e=`<div class="ax-wf__root">
11075
12162
  <aside class="ax-wf__list">
11076
12163
  <header>
11077
12164
  <h2>Workflows</h2>
11078
12165
  <div class="ax-wf__header-actions">
12166
+ <a id="wf-new" class="ax-wf__icon" href="/workflows/editor?new=1" title="Build a new workflow">+</a>
11079
12167
  <button id="wf-refresh" class="ax-wf__icon" title="Refresh (r)">\u21BB</button>
11080
12168
  </div>
11081
12169
  </header>
@@ -11087,16 +12175,36 @@ article.term p {
11087
12175
  </div>
11088
12176
  <ul id="wf-list" class="ax-wf__cards" aria-live="polite"></ul>
11089
12177
  <div id="wf-empty" class="ax-wf__empty" hidden>
11090
- <p>No workflows defined.</p>
11091
- <p class="hint">Add a definition under <code>.agentx/workflows/*.json</code>, validate with <code>agentx workflow validate</code>, and reload.</p>
12178
+ <p><b>No workflows yet.</b></p>
12179
+ <p class="hint">A workflow watches for something &mdash; a merge request, a message, a time of day &mdash; and puts an agent on it. Ask an agent to draft one for you, or connect n8n below and let it hand work over.</p>
11092
12180
  </div>
11093
- <section class="ax-wf__drafts">
11094
- <header>
11095
- <h3>Drafts</h3>
11096
- <span id="wf-draft-count" class="hint">0</span>
11097
- </header>
11098
- <ul id="wf-draft-list" class="ax-wf__draft-list" aria-live="polite"></ul>
12181
+ <section class="ax-wf__n8n">
12182
+ <header><h3>Hand work over from n8n</h3></header>
12183
+ <p class="hint">n8n already talks to hundreds of services. Let it keep doing that, and have it call a workflow here when it needs an agent.</p>
12184
+
12185
+ <ol class="ax-wf__n8n-steps">
12186
+ <li>
12187
+ <b>Name the job.</b> Pick a short word for what n8n is handing over &mdash;
12188
+ <code>invoice-received</code>, <code>lead-signed-up</code>. That word is the
12189
+ <i>topic</i>, and it is the last part of the address below.
12190
+ </li>
12191
+ <li>
12192
+ <b>In n8n</b>, add an <b>HTTP Request</b> node: method <code>POST</code>, this address
12193
+ with your topic on the end, and send whatever JSON the workflow should read.
12194
+ <div class="ax-wf__n8n-url" id="wf-n8n-in">&hellip;</div>
12195
+ <button class="ax-wf__n8n-copy" id="wf-n8n-copy" type="button">Copy address</button>
12196
+ <span class="hint" id="wf-n8n-auth"></span>
12197
+ </li>
12198
+ <li>
12199
+ <b>Here</b>, build a workflow that starts with <b>n8n hands work over</b> and set its
12200
+ topic to the same word. Without that, every workflow listening for n8n runs on
12201
+ every call.
12202
+ </li>
12203
+ </ol>
12204
+
12205
+ <p class="hint">Going the other way is one step: add <b>Call a web address</b> and point it at an n8n webhook &mdash; or connect n8n in Settings and pick one of your n8n workflows straight from the palette.</p>
11099
12206
  </section>
12207
+
11100
12208
  </aside>
11101
12209
 
11102
12210
  <section class="ax-wf__detail">
@@ -11127,7 +12235,7 @@ article.term p {
11127
12235
  </aside>
11128
12236
  </div>
11129
12237
 
11130
- <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:Io,scripts:`<script>${$o}</script>`})}var Io=`
12238
+ <div id="wf-toast" class="ax-wf__toast" hidden></div>`;return C({title:"AgentX \xB7 Workflows",activeTab:"workflows",subtitle:"Workflows",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:ss,scripts:`<script>${me({workflowHealth:kt})}${is}</script>`})}var ss=`
11131
12239
  .ax-wf__root {
11132
12240
  display: grid;
11133
12241
  grid-template-columns: 340px 1fr;
@@ -11171,6 +12279,52 @@ article.term p {
11171
12279
  border: 1px solid var(--ax-border); border-radius: 4px;
11172
12280
  font-family: inherit;
11173
12281
  }
12282
+ .ax-wf__state {
12283
+ font-size: 11.5px; font-weight: 600; margin-top: 4px;
12284
+ display: inline-flex; align-items: center; gap: 5px;
12285
+ }
12286
+ .ax-wf__state::before { content: ""; width: 7px; height: 7px; border-radius: 999px; background: currentColor; }
12287
+ .ax-wf__state--dormant { color: var(--ax-red-ink); }
12288
+ .ax-wf__state--failing { color: var(--ax-amber-ink); }
12289
+ .ax-wf__state--active { color: var(--ax-green-d); }
12290
+ .ax-wf__state--quiet,
12291
+ .ax-wf__state--never { color: var(--ax-text-2); }
12292
+
12293
+ .ax-wf__n8n {
12294
+ border-top: var(--ax-border-w) solid var(--ax-border);
12295
+ padding: 14px 16px; display: flex; flex-direction: column; gap: 8px;
12296
+ }
12297
+ .ax-wf__n8n h3 { font-size: 13px; font-weight: 600; margin: 0; }
12298
+ .ax-wf__n8n-lbl {
12299
+ font-size: 10px; font-family: var(--ax-mono); text-transform: uppercase;
12300
+ letter-spacing: 0.06em; color: var(--ax-text-2); font-weight: 600;
12301
+ }
12302
+ .ax-wf__n8n-steps {
12303
+ margin: 4px 0 0; padding-left: 18px; display: flex; flex-direction: column; gap: 10px;
12304
+ font-size: 12px; line-height: 1.5; color: var(--ax-text-2);
12305
+ }
12306
+ .ax-wf__n8n-steps b { color: var(--ax-text); font-weight: 600; }
12307
+ .ax-wf__n8n-steps i { font-style: normal; color: var(--ax-text); font-weight: 600; }
12308
+ .ax-wf__n8n-steps code {
12309
+ font-family: var(--ax-mono); font-size: 11px; background: var(--ax-surface-2);
12310
+ border: 1px solid var(--ax-border); border-radius: 4px; padding: 0 4px;
12311
+ }
12312
+ .ax-wf__n8n-steps > li { padding-left: 2px; }
12313
+ .ax-wf__n8n-steps .ax-wf__n8n-url { margin: 7px 0 6px; }
12314
+
12315
+ .ax-wf__n8n-url {
12316
+ font-family: var(--ax-mono); font-size: 11px; word-break: break-all;
12317
+ background: var(--ax-surface-2); border: 1px solid var(--ax-border);
12318
+ border-radius: var(--ax-radius-sm); padding: 8px 10px; color: var(--ax-text);
12319
+ }
12320
+ .ax-wf__n8n-copy {
12321
+ align-self: flex-start; font: inherit; font-size: 12px; font-weight: 600;
12322
+ padding: 5px 12px; border-radius: var(--ax-radius-sm);
12323
+ border: var(--ax-border-w) solid var(--ax-border-2);
12324
+ background: var(--ax-surface); color: var(--ax-text); cursor: pointer;
12325
+ }
12326
+ .ax-wf__n8n-copy:hover { background: var(--ax-surface-2); }
12327
+
11174
12328
  .ax-wf__cards {
11175
12329
  list-style: none; margin: 0; padding: 8px 0;
11176
12330
  overflow-y: auto; flex: 1 1 auto; min-height: 140px;
@@ -11201,37 +12355,6 @@ article.term p {
11201
12355
  color: var(--ax-accent);
11202
12356
  border-color: color-mix(in oklch, var(--ax-accent) 50%, transparent);
11203
12357
  }
11204
- .ax-wf__drafts {
11205
- border-top: 1px solid var(--ax-border);
11206
- flex: 0 0 min(34vh, 260px);
11207
- display: flex; flex-direction: column;
11208
- background: color-mix(in oklch, var(--ax-bg-elev) 92%, var(--ax-bg));
11209
- }
11210
- .ax-wf__drafts > header {
11211
- display: flex; align-items: center; justify-content: space-between;
11212
- padding: 10px 18px 8px;
11213
- }
11214
- .ax-wf__drafts h3 {
11215
- margin: 0; font-size: 11px; font-weight: 650;
11216
- letter-spacing: 0.04em; text-transform: uppercase; color: var(--ax-muted);
11217
- }
11218
- .ax-wf__draft-list {
11219
- list-style: none; margin: 0; padding: 0 0 8px;
11220
- overflow: auto;
11221
- }
11222
- .ax-wf__draft {
11223
- padding: 9px 18px; cursor: pointer;
11224
- border-top: 1px solid color-mix(in oklch, var(--ax-border) 55%, transparent);
11225
- }
11226
- .ax-wf__draft:hover { background: var(--ax-surface); }
11227
- .ax-wf__draft.is-active { background: var(--ax-surface); box-shadow: inset 3px 0 0 var(--ax-warn); }
11228
- .ax-wf__draft-title { font-size: 12px; font-weight: 600; color: var(--ax-text); margin-bottom: 2px; }
11229
- .ax-wf__draft-meta {
11230
- display: flex; gap: 6px; flex-wrap: wrap;
11231
- font-family: var(--ax-mono); font-size: 10px; color: var(--ax-muted);
11232
- }
11233
- .ax-wf__draft-empty { padding: 10px 18px 16px; color: var(--ax-muted); font-size: 11px; }
11234
- .ax-wf__draft-actions { display: flex; gap: 6px; flex-wrap: wrap; }
11235
12358
  .ax-wf__btn.danger:hover { background: color-mix(in oklch, var(--ax-err) 13%, transparent); border-color: var(--ax-err); color: var(--ax-err); }
11236
12359
  .ax-wf__btn.primary { border-color: color-mix(in oklch, var(--ax-accent) 55%, var(--ax-border)); color: var(--ax-accent); }
11237
12360
 
@@ -11398,7 +12521,7 @@ article.term p {
11398
12521
  border: 1px solid var(--ax-border);
11399
12522
  border-radius: 4px;
11400
12523
  background: var(--ax-bg);
11401
- color: var(--ax-fg);
12524
+ color: var(--ax-text);
11402
12525
  margin-top: 6px;
11403
12526
  width: 100%;
11404
12527
  }
@@ -11470,7 +12593,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11470
12593
  .ax-wf__status-pill.completed { color: var(--ax-muted); background: var(--ax-surface); }
11471
12594
  .ax-wf__status-pill.failed { color: var(--ax-err); background: color-mix(in oklch, var(--ax-err) 15%, transparent); }
11472
12595
  .ax-wf__run-actions { display: flex; gap: 4px; margin-left: auto; }
11473
- .ax-wf__run-actions button { font-size: 11px; padding: 3px 9px; border-radius: 4px; border: 1px solid var(--ax-border); background: var(--ax-bg); color: var(--ax-fg); cursor: pointer; }
12596
+ .ax-wf__run-actions button { font-size: 11px; padding: 3px 9px; border-radius: 4px; border: 1px solid var(--ax-border); background: var(--ax-bg); color: var(--ax-text); cursor: pointer; }
11474
12597
  .ax-wf__run-actions button:hover { background: var(--ax-surface); }
11475
12598
  .ax-wf__run-actions button.danger:hover { background: color-mix(in oklch, var(--ax-err) 15%, transparent); border-color: var(--ax-err); color: var(--ax-err); }
11476
12599
 
@@ -11496,17 +12619,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11496
12619
  font-size: 12px; z-index: 50;
11497
12620
  }
11498
12621
  .hint { color: var(--ax-muted); font-size: 11px; }
11499
- `,$o=`
12622
+ `,is=`
11500
12623
  (() => {
11501
12624
  const $ = (sel) => document.querySelector(sel)
11502
12625
  const $$ = (sel) => Array.from(document.querySelectorAll(sel))
11503
12626
 
11504
12627
  const state = {
11505
12628
  workflows: [],
11506
- drafts: [],
11507
12629
  runs: [],
11508
12630
  selectedId: null,
11509
- selectedDraftId: null,
11510
12631
  filter: "",
11511
12632
  /** Project filter \u2014 "" = all (incl. workflows without project),
11512
12633
  * "__none__" = only workflows missing the project field,
@@ -11559,11 +12680,46 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11559
12680
  + (hasGlobal ? '<option value="__none__"' + (current === "__none__" ? ' selected' : '') + '>(no project)</option>' : "")
11560
12681
  }
11561
12682
 
12683
+ const FRIENDLY_TRIGGER = { gitlab: "on GitLab activity", github: "on GitHub activity", cron: "on a schedule",
12684
+ manual: "when you run it", hook: "when something calls in", channel: "on a message", form: "from a form", n8n: "when n8n calls" }
12685
+ // Plain words for what the operator needs to know, in the order they care:
12686
+ // has it stopped, is it breaking, is anyone blocked, is it fine.
12687
+ const STATE_LABEL = { dormant: "stopped running", failing: "failing", active: "running normally",
12688
+ quiet: "idle", never: "never run yet" }
12689
+ const STATE_RANK = { dormant: 0, failing: 1, active: 2, quiet: 3, never: 4 }
12690
+ function healthOf(id, myRuns) {
12691
+ const rows = (myRuns || []).map(r => ({ workflowId: id, status: r.status, at: new Date(r.updatedAt).getTime() }))
12692
+ const h = workflowHealth([{ id: id }], rows)[0]
12693
+ return { state: h.state, label: STATE_LABEL[h.state] || h.state, rank: STATE_RANK[h.state] }
12694
+ }
12695
+
12696
+ // The address n8n posts to. Shown, and copyable with a real topic already
12697
+ // in it \u2014 a placeholder like <topic> is not something you can paste.
12698
+ (function n8nPanel() {
12699
+ const el = document.getElementById("wf-n8n-in")
12700
+ if (!el) return
12701
+ const base = location.origin + "/webhook/n8n/"
12702
+ el.textContent = base + "your-topic"
12703
+ // Loopback is exempt from mesh auth; anything else needs the token, and
12704
+ // saying so here saves a silent 401 inside n8n.
12705
+ const local = /^(localhost|127.0.0.1|[::1])$/.test(location.hostname)
12706
+ const auth = document.getElementById("wf-n8n-auth")
12707
+ if (auth) auth.textContent = local
12708
+ ? "n8n on this machine needs no key."
12709
+ : "n8n is off-box, so add the header Authorization: Bearer <your MESH_TOKEN>."
12710
+ const btn = document.getElementById("wf-n8n-copy")
12711
+ if (btn) btn.onclick = async () => {
12712
+ try { await navigator.clipboard.writeText(el.textContent); btn.textContent = "Copied" }
12713
+ catch { btn.textContent = "Copy failed" }
12714
+ setTimeout(() => { btn.textContent = "Copy address" }, 1600)
12715
+ }
12716
+ })()
12717
+
11562
12718
  function renderList() {
11563
12719
  renderProjectFilter()
11564
12720
  const needle = state.filter.toLowerCase()
11565
12721
  const projectFilter = state.projectFilter || ""
11566
- const filtered = state.workflows.filter(wf => {
12722
+ let filtered = state.workflows.filter(wf => {
11567
12723
  const matchesText = !needle || wf.id.toLowerCase().includes(needle) || (wf.title || "").toLowerCase().includes(needle)
11568
12724
  // projectFilter values:
11569
12725
  // "" \u2014 no filter (all projects + global)
@@ -11586,6 +12742,12 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11586
12742
  }
11587
12743
  $("#wf-empty").hidden = true
11588
12744
 
12745
+ // Anything that stopped or is failing comes first: a list sorted by name
12746
+ // hides the one workflow you needed to know about.
12747
+ filtered = filtered.slice().sort((a, b) =>
12748
+ healthOf(a.id, runsByWorkflow[a.id]).rank - healthOf(b.id, runsByWorkflow[b.id]).rank
12749
+ || String(a.title || a.id).localeCompare(String(b.title || b.id)))
12750
+
11589
12751
  $("#wf-list").innerHTML = filtered.map(wf => {
11590
12752
  const myRuns = runsByWorkflow[wf.id] || []
11591
12753
  const live = myRuns.filter(r => r.status === "running").length
@@ -11594,13 +12756,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11594
12756
  // V2: trigger is a node inside wf.nodes, not a workflow-level field.
11595
12757
  const triggerNode = (wf.nodes || []).find(n => n && n.type && n.type.indexOf("trigger.") === 0)
11596
12758
  const triggerSource = triggerNode ? (triggerNode.config && triggerNode.config.source) || triggerNode.type.replace("trigger.", "") : "?"
12759
+ const health = healthOf(wf.id, myRuns)
11597
12760
  return \`
11598
12761
  <li class="ax-wf__card \${isActive ? "is-active" : ""}" data-id="\${wf.id}">
11599
12762
  <div class="ax-wf__card-title">\${esc(wf.title || wf.id)}</div>
11600
- <div class="ax-wf__card-id">\${esc(wf.id)} \xB7 v\${wf.version}</div>
12763
+ <div class="ax-wf__card-id">\${esc(wf.id)}</div>
12764
+ <div class="ax-wf__state ax-wf__state--\${health.state}">\${esc(health.label)}</div>
11601
12765
  <div class="ax-wf__card-meta">
11602
12766
  \${wf.project ? \`<span class="tag tag--project" title="Project">\${esc(wf.project)}</span>\` : ""}
11603
- <span class="tag">\${esc(triggerSource)}</span>
12767
+ <span class="tag" title="What starts it">\${esc(FRIENDLY_TRIGGER[triggerSource] || triggerSource)}</span>
11604
12768
  \${live > 0 ? \`<span class="tag live">\${live} running</span>\` : ""}
11605
12769
  \${lastRun
11606
12770
  ? \`<span class="tag tag--\${esc(lastRun.status)}" title="\${esc(lastRun.id)} \xB7 \${esc(new Date(lastRun.updatedAt).toLocaleString())}">last: \${esc(lastRun.status)} \xB7 \${relTime(lastRun.updatedAt)}</span>\`
@@ -11614,35 +12778,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11614
12778
  })
11615
12779
  }
11616
12780
 
11617
- function renderDraftList() {
11618
- $("#wf-draft-count").textContent = String(state.drafts.length)
11619
- if (!state.drafts.length) {
11620
- $("#wf-draft-list").innerHTML = \`<li class="ax-wf__draft-empty">No drafts pending review.</li>\`
11621
- return
11622
- }
11623
- $("#wf-draft-list").innerHTML = state.drafts.map(d => {
11624
- const wf = d.workflow || {}
11625
- const isActive = state.selectedDraftId === d.id
11626
- const issues = Array.isArray(d.issues) ? d.issues.length : 0
11627
- return \`<li class="ax-wf__draft \${isActive ? "is-active" : ""}" data-draft="\${esc(d.id)}">
11628
- <div class="ax-wf__draft-title">\${esc(wf.title || d.id)}</div>
11629
- <div class="ax-wf__draft-meta">
11630
- <span>\${esc(d.id)}</span>
11631
- <span>confidence=\${wf.confidence == null ? "\u2014" : Number(wf.confidence).toFixed(2)}</span>
11632
- <span>\${issues ? issues + " issue" + (issues === 1 ? "" : "s") : "valid"}</span>
11633
- </div>
11634
- </li>\`
11635
- }).join("")
11636
- $$(".ax-wf__draft").forEach(el => {
11637
- el.addEventListener("click", () => selectDraft(el.dataset.draft))
11638
- })
11639
- }
11640
-
11641
12781
  function renderDetail() {
11642
- if (state.selectedDraftId) {
11643
- renderDraftDetail()
11644
- return
11645
- }
11646
12782
  const wf = state.workflows.find(w => w.id === state.selectedId)
11647
12783
  if (!wf) {
11648
12784
  $("#wf-detail-head").innerHTML = \`<span class="hint">Select a workflow to inspect.</span>\`
@@ -11660,6 +12796,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11660
12796
  $("#wf-detail-head").innerHTML = \`
11661
12797
  <div class="ax-wf__detail-title">
11662
12798
  <h2>\${esc(wf.title || wf.id)}</h2>
12799
+ <a class="ax-wf__btn" href="/workflows/editor?id=\${encodeURIComponent(wf.id)}" title="Open on the canvas">Edit on canvas</a>
11663
12800
  <span class="hint">\${esc(wf.id)} \xB7 v\${wf.version} \xB7 trigger: \${esc(triggerSource)}\${trigFilter ? " \xB7 " + esc(trigFilter) : ""}</span>
11664
12801
  </div>
11665
12802
  <div class="ax-wf__detail-actions">
@@ -12089,69 +13226,6 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12089
13226
  }
12090
13227
  }
12091
13228
 
12092
- function renderDraftDetail() {
12093
- const draft = state.drafts.find(d => d.id === state.selectedDraftId)
12094
- if (!draft) {
12095
- $("#wf-detail-head").innerHTML = \`<span class="hint">Select a workflow to inspect.</span>\`
12096
- $("#wf-detail-body").innerHTML = ""
12097
- return
12098
- }
12099
- const wf = draft.workflow || {}
12100
- const issues = Array.isArray(draft.issues) ? draft.issues : []
12101
- const sourceIds = Array.isArray(wf.sourceTaskIds) ? wf.sourceTaskIds : []
12102
- $("#wf-detail-head").innerHTML = \`
12103
- <div class="ax-wf__detail-title">
12104
- <h2>\${esc(wf.title || draft.id)}</h2>
12105
- <span class="hint">\${esc(draft.id)} \xB7 status=\${esc(wf.status || "draft")} \xB7 state=\${esc(wf.state || "disabled")} \xB7 confidence=\${wf.confidence == null ? "\u2014" : Number(wf.confidence).toFixed(2)}</span>
12106
- </div>
12107
- <div class="ax-wf__detail-actions ax-wf__draft-actions">
12108
- <button class="ax-wf__btn" id="wf-draft-validate" type="button">Validate</button>
12109
- <button class="ax-wf__btn" id="wf-draft-save" type="button">Save</button>
12110
- <button class="ax-wf__btn" id="wf-draft-replay" type="button">Save &amp; Replay</button>
12111
- <button class="ax-wf__btn primary" id="wf-draft-promote" type="button">Promote</button>
12112
- <button class="ax-wf__btn danger" id="wf-draft-reject" type="button">Reject</button>
12113
- </div>\`
12114
-
12115
- const issueHtml = issues.length
12116
- ? issues.map(i => \`<div class="ax-wf__trans"><span class="cond">\${esc(i)}</span></div>\`).join("")
12117
- : \`<span class="hint">Draft validates against the workflow schema and lint rules.</span>\`
12118
- const tags = Array.isArray(wf.tags) ? wf.tags : []
12119
- $("#wf-detail-body").innerHTML = \`
12120
- <div class="ax-wf__panel">
12121
- <h3>Review state</h3>
12122
- <div class="ax-wf__trans">
12123
- <div>owner: \${esc(wf.ownerAgent || "\u2014")}</div>
12124
- <div>entity: \${esc(wf.entity || "\u2014")}</div>
12125
- <div>generatedFrom: \${esc(wf.generatedFrom || "\u2014")}</div>
12126
- <div>path: \${esc(draft.path || "\u2014")}</div>
12127
- </div>
12128
- </div>
12129
- <div class="ax-wf__panel">
12130
- <h3>Signals</h3>
12131
- <div class="ax-wf__states">
12132
- \${tags.length ? tags.map(t => \`<span class="ax-wf__state">\${esc(t)}</span>\`).join("") : \`<span class="hint">No tags.</span>\`}
12133
- </div>
12134
- </div>
12135
- <div class="ax-wf__panel ax-wf__panel--full">
12136
- <h3>Source task ids (\${sourceIds.length})</h3>
12137
- <div class="ax-wf__trans">\${sourceIds.length ? sourceIds.slice(0, 25).map(esc).join("<br>") : \`<span class="hint">No source task ids.</span>\`}</div>
12138
- </div>
12139
- <div class="ax-wf__panel ax-wf__panel--full">
12140
- <h3>Validation</h3>
12141
- \${issueHtml}
12142
- </div>
12143
- <div class="ax-wf__panel ax-wf__panel--full">
12144
- <h3>Definition <span class="hint">(JSON; saved as YAML on disk)</span></h3>
12145
- <textarea id="wf-draft-editor" class="ax-wf__editor" spellcheck="false">\${esc(JSON.stringify(wf, null, 2))}</textarea>
12146
- </div>\`
12147
-
12148
- $("#wf-draft-validate").addEventListener("click", () => validateDraft(draft.id))
12149
- $("#wf-draft-save").addEventListener("click", () => saveDraft(draft.id))
12150
- $("#wf-draft-replay").addEventListener("click", () => replayDraft(draft.id))
12151
- $("#wf-draft-promote").addEventListener("click", () => promoteDraft(draft.id))
12152
- $("#wf-draft-reject").addEventListener("click", () => rejectDraft(draft.id))
12153
- }
12154
-
12155
13229
  // --- Run drawer ------------------------------------------------------
12156
13230
 
12157
13231
  async function openRun(runId) {
@@ -12212,22 +13286,11 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12212
13286
 
12213
13287
  async function select(id) {
12214
13288
  state.selectedId = id
12215
- state.selectedDraftId = null
12216
13289
  // Keep URL hash in sync so refreshes and editor deep-links stay on the
12217
13290
  // same workflow. Use replaceState so the browser's back button doesn't
12218
13291
  // accumulate selection history.
12219
13292
  try { history.replaceState(null, "", "#" + encodeURIComponent(id)) } catch (_) { /* */ }
12220
13293
  renderList()
12221
- renderDraftList()
12222
- renderDetail()
12223
- }
12224
-
12225
- async function selectDraft(id) {
12226
- state.selectedDraftId = id
12227
- state.selectedId = null
12228
- try { history.replaceState(null, "", "#draft:" + encodeURIComponent(id)) } catch (_) { /* */ }
12229
- renderList()
12230
- renderDraftList()
12231
13294
  renderDetail()
12232
13295
  }
12233
13296
 
@@ -12237,126 +13300,23 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12237
13300
  // 10-50KB each \u2014 at limit=100 the listing was multi-MB and gating
12238
13301
  // first paint behind the slowest serialization path). Run-detail
12239
13302
  // and SSE stream still return the full shape unchanged.
12240
- const [workflows, runs, drafts] = await Promise.all([
13303
+ const [workflows, runs] = await Promise.all([
12241
13304
  fetchJSON("/api/workflows"),
12242
13305
  fetchJSON("/api/workflows/runs?limit=100&summary=1"),
12243
- fetchJSON("/api/workflows/drafts"),
12244
13306
  ])
12245
13307
  state.workflows = workflows.workflows || workflows
12246
13308
  state.runs = runs.runs || runs
12247
- state.drafts = drafts.drafts || drafts
12248
13309
  // If the URL hash names a workflow (e.g. /workflows#my-workflow)
12249
13310
  // and nothing is selected yet, auto-select it. Editor's "History"
12250
13311
  // button links here with the hash, so users land on the right detail.
12251
13312
  if (!state.selectedId && location.hash) {
12252
13313
  const fromHash = decodeURIComponent(location.hash.slice(1))
12253
- if (fromHash.startsWith("draft:") && state.drafts.some(d => d.id === fromHash.slice(6))) state.selectedDraftId = fromHash.slice(6)
12254
- else if (state.workflows.some(w => w.id === fromHash)) state.selectedId = fromHash
13314
+ if (state.workflows.some(w => w.id === fromHash)) state.selectedId = fromHash
12255
13315
  }
12256
13316
  renderList()
12257
- renderDraftList()
12258
- // Don't re-render the detail panel when the user is actively editing
12259
- // a draft \u2014 the periodic 15s refresh would otherwise reset their
12260
- // unsaved textarea on every tick. Resume rendering as soon as focus
12261
- // leaves the editor.
12262
- const editing = state.selectedDraftId && document.activeElement && document.activeElement.id === "wf-draft-editor"
12263
- if (!editing) renderDetail()
12264
- } catch (e) {
12265
- toast("Failed to load workflows: " + e.message)
12266
- }
12267
- }
12268
-
12269
- async function validateDraft(id) {
12270
- try {
12271
- const res = await postJSON("/api/workflows/drafts/" + encodeURIComponent(id) + "/validate")
12272
- toast(res.ok ? "draft is valid" : "draft has validation issues")
12273
- await refresh()
12274
- state.selectedDraftId = id
12275
13317
  renderDetail()
12276
13318
  } catch (e) {
12277
- toast("validate failed: " + e.message)
12278
- }
12279
- }
12280
-
12281
- async function promoteDraft(id) {
12282
- if (!confirm("Promote this draft into the active workflow store?")) return
12283
- try {
12284
- await postJSON("/api/workflows/drafts/" + encodeURIComponent(id) + "/promote", { format: "yaml" })
12285
- toast("draft promoted")
12286
- state.selectedDraftId = null
12287
- await refresh()
12288
- } catch (e) {
12289
- toast("promote failed: " + e.message)
12290
- }
12291
- }
12292
-
12293
- async function rejectDraft(id) {
12294
- if (!confirm("Reject and archive this draft?")) return
12295
- try {
12296
- await postJSON("/api/workflows/drafts/" + encodeURIComponent(id) + "/reject")
12297
- toast("draft rejected")
12298
- state.selectedDraftId = null
12299
- await refresh()
12300
- } catch (e) {
12301
- toast("reject failed: " + e.message)
12302
- }
12303
- }
12304
-
12305
- /** Read the textarea, parse as JSON (the editor is JSON; the server
12306
- * re-serialises to YAML on disk), and PUT to the drafts endpoint. */
12307
- async function persistDraftFromEditor(id) {
12308
- const el = $("#wf-draft-editor")
12309
- if (!el) throw new Error("editor not mounted")
12310
- let workflow
12311
- try {
12312
- workflow = JSON.parse(el.value)
12313
- } catch (e) {
12314
- throw new Error("editor JSON is invalid: " + e.message)
12315
- }
12316
- const res = await fetch("/api/workflows/drafts/" + encodeURIComponent(id), {
12317
- method: "PUT",
12318
- headers: { "Content-Type": "application/json", "X-Requested-With": "agentx-board", ...headers() },
12319
- credentials: "same-origin",
12320
- body: JSON.stringify({ workflow }),
12321
- })
12322
- const data = await res.json().catch(() => ({}))
12323
- if (!res.ok) {
12324
- const issues = Array.isArray(data.issues) ? "\\n - " + data.issues.join("\\n - ") : ""
12325
- throw new Error((data.error || "save failed") + issues)
12326
- }
12327
- return data
12328
- }
12329
-
12330
- async function saveDraft(id) {
12331
- try {
12332
- const res = await persistDraftFromEditor(id)
12333
- const lint = Array.isArray(res.issues) && res.issues.length ? \` (\${res.issues.length} lint warning\${res.issues.length === 1 ? "" : "s"})\` : ""
12334
- toast("draft saved" + lint)
12335
- await refresh()
12336
- state.selectedDraftId = id
12337
- renderDetail()
12338
- } catch (e) {
12339
- toast("save failed: " + e.message)
12340
- }
12341
- }
12342
-
12343
- async function replayDraft(id) {
12344
- try {
12345
- await persistDraftFromEditor(id)
12346
- } catch (e) {
12347
- toast("save failed: " + e.message)
12348
- return
12349
- }
12350
- try {
12351
- const res = await postJSON("/api/workflows/drafts/" + encodeURIComponent(id) + "/replay", {})
12352
- toast("replay started: " + (res.runId || "?").slice(0, 8))
12353
- if (res.runId) {
12354
- await openRun(res.runId)
12355
- } else {
12356
- await refresh()
12357
- }
12358
- } catch (e) {
12359
- toast("replay failed: " + e.message)
13319
+ toast("Failed to load workflows: " + e.message)
12360
13320
  }
12361
13321
  }
12362
13322
 
@@ -12447,7 +13407,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12447
13407
  setInterval(refresh, 15000)
12448
13408
  })
12449
13409
  })();
12450
- `;function Ha(t={}){let e=`<div class="ax-proc__root">
13410
+ `;function Za(t={}){let e=`<div class="ax-proc__root">
12451
13411
  <header class="ax-proc__header">
12452
13412
  <h1>Procedures</h1>
12453
13413
  <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>
@@ -12491,7 +13451,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12491
13451
  <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>
12492
13452
  <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>
12493
13453
  </section>
12494
- </div>`;return M({title:"AgentX \xB7 Procedures",activeTab:"procedures",subtitle:"Procedures",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:jo,scripts:`<script>${Lo}</script>`})}var jo=`
13454
+ </div>`;return C({title:"AgentX \xB7 Procedures",activeTab:"procedures",subtitle:"Procedures",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:ls,scripts:`<script>${ds}</script>`})}var ls=`
12495
13455
  .ax-proc__root { padding: 18px 24px 40px; max-width: 1100px; margin: 0 auto; color: var(--ax-text); }
12496
13456
  .ax-proc__header h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
12497
13457
  .ax-proc__header .hint { color: var(--ax-muted); font-size: 12px; margin: 0 0 18px; }
@@ -12517,7 +13477,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12517
13477
  .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); }
12518
13478
  .ax-proc__link { color: var(--ax-accent, #6366f1); text-decoration: none; font-size: 11px; }
12519
13479
  .ax-proc__link:hover { text-decoration: underline; }
12520
- `,Lo=`
13480
+ `,ds=`
12521
13481
  (function(){
12522
13482
  function $(sel){ return document.querySelector(sel) }
12523
13483
  function esc(s){ return String(s||"").replace(/[&<>"']/g, function(c){ return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c] }) }
@@ -12617,24 +13577,24 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12617
13577
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bootAll)
12618
13578
  else bootAll()
12619
13579
  })();
12620
- `;function Na(t){let e=t.agentName||t.agentId,a=`<div class="ax-task-page"
12621
- data-task-id="${D(t.taskId)}"
12622
- data-agent-id="${D(t.agentId)}"
12623
- data-node-url="${D(t.nodeUrl)}"
13580
+ `;function en(t){let e=t.agentName||t.agentId,a=`<div class="ax-task-page"
13581
+ data-task-id="${P(t.taskId)}"
13582
+ data-agent-id="${P(t.agentId)}"
13583
+ data-node-url="${P(t.nodeUrl)}"
12624
13584
  data-archived="${t.archived?"1":""}"
12625
- data-ask="${D(t.ask||"")}"
12626
- data-ask-at="${D(t.askAt||"")}">
13585
+ data-ask="${P(t.ask||"")}"
13586
+ data-ask-at="${P(t.askAt||"")}">
12627
13587
 
12628
13588
  <header class="ax-task-page__head">
12629
13589
  <nav class="ax-crumbs" aria-label="Breadcrumb">
12630
13590
  <a href="/live">Live</a>
12631
13591
  <span class="ax-crumbs__sep">/</span>
12632
- <a href="/agents/${D(t.agentId)}/history?node=${encodeURIComponent(t.nodeUrl)}&name=${encodeURIComponent(e)}"><span class="ax-mention">@${D(t.agentId)}</span></a>
13592
+ <a href="/agents/${P(t.agentId)}/history?node=${encodeURIComponent(t.nodeUrl)}&name=${encodeURIComponent(e)}"><span class="ax-mention">@${P(t.agentId)}</span></a>
12633
13593
  <span class="ax-crumbs__sep">/</span>
12634
13594
  <span class="ax-crumbs__here">Task</span>
12635
13595
  </nav>
12636
13596
  <div class="ax-task-page__meta">
12637
- ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${D(t.channel)}</span>`:""}
13597
+ ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${P(t.channel)}</span>`:""}
12638
13598
  <span class="ax-badge ax-badge--mono" id="task-status">connecting\u2026</span>
12639
13599
  <span class="ax-mono ax-muted" id="task-elapsed"></span>
12640
13600
  </div>
@@ -12660,7 +13620,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12660
13620
  <button type="button" id="task-send" class="ax-btn ax-btn--primary">send \u2192</button>
12661
13621
  </div>
12662
13622
  </footer>
12663
- </div>`;return M({title:`AgentX \xB7 ${e}`,activeTab:"live",subtitle:"Task",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Ro,scripts:`<script>${Do}</script>`})}var Ro=`
13623
+ </div>`;return C({title:`AgentX \xB7 ${e}`,activeTab:"live",subtitle:"Task",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:cs,scripts:`<script>${ps}</script>`})}var cs=`
12664
13624
  /* The shell gives <main> no padding, so page content butted straight against
12665
13625
  the sticky topbar. Breathe. */
12666
13626
  .ax-task-page {
@@ -12802,7 +13762,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12802
13762
  line-height: 1.55; text-wrap: pretty; white-space: pre-wrap; word-break: break-word;
12803
13763
  }
12804
13764
 
12805
- `,Do=`
13765
+ `,ps=`
12806
13766
  (function () {
12807
13767
  var root = document.querySelector('.ax-task-page');
12808
13768
  if (!root) return;
@@ -13158,15 +14118,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13158
14118
  if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') { e.preventDefault(); sendBtn.click(); }
13159
14119
  });
13160
14120
  })();
13161
- `;function Ba(t){let e=t.agentName||t.agentId,a=`<div class="ax-history"
13162
- data-agent-id="${D(t.agentId)}"
13163
- data-agent-name="${D(e)}"
13164
- data-node-url="${D(t.nodeUrl)}">
14121
+ `;function tn(t){let e=t.agentName||t.agentId,a=`<div class="ax-history"
14122
+ data-agent-id="${P(t.agentId)}"
14123
+ data-agent-name="${P(e)}"
14124
+ data-node-url="${P(t.nodeUrl)}">
13165
14125
  <header class="ax-history__head">
13166
14126
  <nav class="ax-crumbs" aria-label="Breadcrumb">
13167
14127
  <a href="/live">Live</a>
13168
14128
  <span class="ax-crumbs__sep">/</span>
13169
- <span class="ax-mention">@${D(t.agentId)}</span>
14129
+ <span class="ax-mention">@${P(t.agentId)}</span>
13170
14130
  <span class="ax-crumbs__sep">/</span>
13171
14131
  <span class="ax-crumbs__here">History</span>
13172
14132
  </nav>
@@ -13187,7 +14147,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13187
14147
  <div class="ax-history__list" id="hist-list">
13188
14148
  <div class="ax-history__empty">loading\u2026</div>
13189
14149
  </div>
13190
- </div>`;return M({title:`AgentX \xB7 ${e} history`,activeTab:"live",subtitle:"History",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Po,scripts:`<script>${Oo}</script>`})}var Po=`
14150
+ </div>`;return C({title:`AgentX \xB7 ${e} history`,activeTab:"live",subtitle:"History",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:us,scripts:`<script>${ms}</script>`})}var us=`
13191
14151
  /* <main> carries no padding in the shell \u2014 without this the breadcrumb sits
13192
14152
  flush against the sticky topbar. */
13193
14153
  .ax-history {
@@ -13239,7 +14199,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13239
14199
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
13240
14200
  }
13241
14201
  .ax-history__foot { margin-top: 6px; font-size: var(--ax-fs-xs); color: var(--ax-muted); font-family: var(--ax-mono); }
13242
- `,Oo=`
14202
+ `,ms=`
13243
14203
  (function () {
13244
14204
  var root = document.querySelector('.ax-history');
13245
14205
  if (!root) return;
@@ -13339,25 +14299,25 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13339
14299
  listEl.innerHTML = '<div class="ax-history__empty" style="color:var(--ax-err)">' + esc(e.message) + '</div>';
13340
14300
  });
13341
14301
  })();
13342
- `;function qa(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"])?T(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 re(t,e,l=>za(e,a,l,{mode:"create",convertFromYaml:i}))}}if(n==="/api/workflows/drafts"||n.startsWith("/api/workflows/drafts?")||n.startsWith("/api/workflows/drafts/"))return Ho(t,e,a,n);if(n.startsWith("/api/workflows/runs"))return r==="GET"&&!a.requireScope(t,e,["dashboard:read"])?!0:Bo(t,e,a,n);if(n.startsWith("/api/workflows/signal/")){if(r!=="POST")return T(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;if(!a.dispatcher)return T(e,501,{error:"dispatcher not enabled"});let s=decodeURIComponent(n.replace(/^\/api\/workflows\/signal\//,"").split("?")[0]);return s?re(t,e,i=>{let l=i,d=a.dispatcher.emitSignal({name:s,scope:l?.scope,workflowId:l?.workflowId,payload:l?.payload});return T(e,200,{ok:!0,emission:d})}):T(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"])?T(e,200,{layout:a.layouts.get(s)}):!0;if(r==="PUT")return a.requireScope(t,e,["dashboard:write"])?re(t,e,l=>{try{let d=a.layouts.save(s,l);return T(e,200,{layout:d})}catch(d){return T(e,400,{error:"invalid layout",message:d.message})}}):!0}if(i==="/validate"&&r==="POST")return a.requireScope(t,e,["dashboard:read"])?re(t,e,l=>{let d=ve.safeParse(l);if(!d.success)return T(e,200,{ok:!1,issues:d.error.issues.map(u=>({path:u.path.join("."),message:u.message}))});let p=be(d.data).map(u=>({path:"",message:u}));return T(e,200,{ok:p.length===0,issues:p,workflow:d.data})}):!0;if(!i){if(r==="GET"){if(!a.requireScope(t,e,["dashboard:read"]))return!0;let l=a.store.get(s);return l?T(e,200,{workflow:l}):T(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,d=l.get("convertFromYaml")==="true"||l.get("convertFromYaml")==="1";return re(t,e,p=>za(e,a,p,{mode:"update",id:s,convertFromYaml:d}))}if(r==="DELETE"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=a.store.delete(s);return a.layouts.delete(s),T(e,l?200:404,l?{ok:!0}:{error:"workflow not found"})}}}return T(e,404,{error:"unknown workflows endpoint",path:n})}function Ho(t,e,a,n){let r=t.method||"GET",o=n.replace(/^\/api\/workflows\/drafts/,""),s=a.store.baseDir;if(o===""||o.startsWith("?")){if(r!=="GET")return T(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:read"]))return!0;let p=ct(process.cwd(),{workflowDir:s}).map(u=>({id:u.id,path:u.path,workflow:u.workflow,issues:ye(u.workflow)}));return T(e,200,{drafts:p})}let i=o.match(/^\/([^\/?]+)(\/validate|\/promote|\/reject)?$/);if(!i)return T(e,404,{error:"unknown drafts endpoint"});let l=decodeURIComponent(i[1]),d=i[2];if(!d&&r==="GET"){if(!a.requireScope(t,e,["dashboard:read"]))return!0;let p=Pe(l,process.cwd(),{workflowDir:s});return p?T(e,200,{draft:p,issues:ye(p.workflow)}):T(e,404,{error:"draft not found"})}if(!d&&r==="PUT")return a.requireScope(t,e,["dashboard:write"])?re(t,e,p=>{try{let u=p?.workflow??p;if(!u||typeof u!="object")return T(e,400,{error:"missing workflow body"});if(u.id&&u.id!==l)return T(e,400,{error:`draft id mismatch: body=${u.id}, url=${l}`});let f=ve.safeParse({...u,id:l});if(!f.success)return T(e,400,{error:"draft schema invalid",issues:f.error.issues.map(A=>`${A.path.join(".")||"<root>"}: ${A.message}`)});let v=be(f.data),k=dt(f.data,{format:"yaml",workflowDir:s,force:!0});return T(e,200,{ok:!0,id:l,path:k,issues:v,workflow:f.data})}catch(u){return T(e,500,{error:u?.message||String(u)})}}):!0;if(d==="/validate"){if(r!=="POST")return T(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:read"]))return!0;let p=Pe(l,process.cwd(),{workflowDir:s});if(!p)return T(e,404,{error:"draft not found"});let u=ye(p.workflow);return T(e,200,{ok:u.length===0,issues:u,draft:p})}if(d==="/promote")return r!=="POST"?T(e,405,{error:"method not allowed"}):a.requireScope(t,e,["dashboard:write"])?re(t,e,p=>{try{let u=!!p?.replace,f=p?.format==="json"?"json":"yaml",v=pt(l,{replace:u,format:f,workflowDir:s});return a.layouts.sync(v.workflow.id,v.workflow.nodes.map(k=>k.id)),T(e,200,{ok:!0,...v})}catch(u){return T(e,400,{error:u?.message||String(u)})}}):!0;if(d==="/reject"){if(r!=="POST")return T(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;try{let p=ut(l,process.cwd(),{workflowDir:s});return T(e,200,{ok:!0,id:l,archived:p})}catch(p){return T(e,400,{error:p?.message||String(p)})}}return T(e,405,{error:"method not allowed"})}var No=["mesh"];function za(t,e,a,n){let r=ve.safeParse(a);if(!r.success)return T(t,400,{error:"invalid workflow",issues:r.error.issues.map(l=>({path:l.path.join("."),message:l.message}))});let o=r.data,s=be(o);if(s.length>0)return T(t,400,{error:"lint errors",issues:s.map(l=>({path:"",message:l}))});if(n.mode==="update"&&o.id!==n.id)return T(t,400,{error:"workflow id does not match path"});if(n.mode==="create"&&e.store.get(o.id))return T(t,409,{error:`workflow "${o.id}" already exists`});if(n.mode==="update"&&a&&typeof a=="object"){let l=a,d=e.store.get(n.id);if(d)for(let p of No)!(p in l)&&p in d&&(o[p]=d[p])}let i;try{i=e.store.save(o,{convertFromYaml:n.convertFromYaml})}catch(l){let d=l?.message||String(l),p=l?.yamlPath,u=!!p||/yaml round-trip failed/.test(d);return T(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).":d,kind:u?"yaml-authored":"save-failed",...p?{path:p}:{}})}return e.layouts.sync(i.id,i.nodes.map(l=>l.id)),T(t,200,{workflow:i})}function Bo(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))),d=r.get("workflowId")||void 0,p=r.get("summary")==="1"||r.get("summary")==="true",u=a.runs.list({workflowId:d,limit:l});if(!p)return T(e,200,{runs:u});let f=u.map(v=>({id:v.id,workflowId:v.workflowId,workflowVersion:v.workflowVersion,homeNode:v.homeNode,status:v.status,pending:v.pending,entityRef:v.entityRef,history:(v.history||[]).slice(-5),parentRunId:v.parentRunId,parentNodeId:v.parentNodeId,rootRunId:v.rootRunId,depth:v.depth,createdAt:v.createdAt,updatedAt:v.updatedAt}));return T(e,200,{runs:f})}let s=o.match(/^\/([^\/?]+)\/status$/);if(s){if((t.method||"GET").toUpperCase()!=="POST")return T(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=decodeURIComponent(s[1]);return re(t,e,d=>{let p=d?.status;return p!=="paused"&&p!=="running"&&p!=="canceled"?T(e,400,{error:"status must be paused|running|canceled"}):a.runs.setStatus(l,p)?T(e,200,{ok:!0,runId:l,status:p}):T(e,404,{error:"run not found"})})}let i=o.match(/^\/([^\/?]+)(\/stream)?$/);if(i){let l=decodeURIComponent(i[1]);if(i[2])return zo(t,e,a,l);let d=a.runs.get(l);return d?T(e,200,{run:d}):T(e,404,{error:"run not found"})}return T(e,404,{error:"unknown runs endpoint"})}function zo(t,e,a,n){let r=a.runs.get(n);if(!r)return T(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)}
14302
+ `;function nn(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"])?I(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,l=s.get("convertFromYaml")==="true"||s.get("convertFromYaml")==="1";return fe(t,e,i=>an(e,a,i,{mode:"create",convertFromYaml:l}))}}if(n.startsWith("/api/workflows/runs"))return r==="GET"&&!a.requireScope(t,e,["dashboard:read"])?!0:gs(t,e,a,n);if(n.startsWith("/api/workflows/signal/")){if(r!=="POST")return I(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;if(!a.dispatcher)return I(e,501,{error:"dispatcher not enabled"});let s=decodeURIComponent(n.replace(/^\/api\/workflows\/signal\//,"").split("?")[0]);return s?fe(t,e,l=>{let i=l,c=a.dispatcher.emitSignal({name:s,scope:i?.scope,workflowId:i?.workflowId,payload:i?.payload});return I(e,200,{ok:!0,emission:c})}):I(e,400,{error:"signal name required"})}let o=n.match(/^\/api\/workflows\/([^\/?]+)(\/layout|\/validate)?(\?.*)?$/);if(o){let s=decodeURIComponent(o[1]),l=o[2];if(l==="/layout"){if(r==="GET")return a.requireScope(t,e,["dashboard:read"])?I(e,200,{layout:a.layouts.get(s)}):!0;if(r==="PUT")return a.requireScope(t,e,["dashboard:write"])?fe(t,e,i=>{try{let c=a.layouts.save(s,i);return I(e,200,{layout:c})}catch(c){return I(e,400,{error:"invalid layout",message:c.message})}}):!0}if(l==="/validate"&&r==="POST")return a.requireScope(t,e,["dashboard:read"])?fe(t,e,i=>{let c=Be.safeParse(i);if(!c.success)return I(e,200,{ok:!1,issues:c.error.issues.map(m=>({path:m.path.join("."),message:m.message}))});let u=ze(c.data).map(m=>({path:"",message:m}));return I(e,200,{ok:u.length===0,issues:u,workflow:c.data})}):!0;if(!l){if(r==="GET"){if(!a.requireScope(t,e,["dashboard:read"]))return!0;let i=a.store.get(s);return i?I(e,200,{workflow:i}):I(e,404,{error:"workflow not found"})}if(r==="PUT"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let i=new URL(n,"http://_").searchParams,c=i.get("convertFromYaml")==="true"||i.get("convertFromYaml")==="1";return fe(t,e,u=>an(e,a,u,{mode:"update",id:s,convertFromYaml:c}))}if(r==="DELETE"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let i=a.store.delete(s);return a.layouts.delete(s),I(e,i?200:404,i?{ok:!0}:{error:"workflow not found"})}}}return I(e,404,{error:"unknown workflows endpoint",path:n})}var hs=["mesh"];function an(t,e,a,n){let r=Be.safeParse(a);if(!r.success)return I(t,400,{error:"invalid workflow",issues:r.error.issues.map(i=>({path:i.path.join("."),message:i.message}))});let o=r.data,s=ze(o);if(s.length>0)return I(t,400,{error:"lint errors",issues:s.map(i=>({path:"",message:i}))});if(n.mode==="update"&&o.id!==n.id)return I(t,400,{error:"workflow id does not match path"});if(n.mode==="create"&&e.store.get(o.id))return I(t,409,{error:`workflow "${o.id}" already exists`});if(n.mode==="update"&&a&&typeof a=="object"){let i=a,c=e.store.get(n.id);if(c)for(let u of hs)!(u in i)&&u in c&&(o[u]=c[u])}let l;try{l=e.store.save(o,{convertFromYaml:n.convertFromYaml})}catch(i){let c=i?.message||String(i),u=i?.yamlPath,m=!!u||/yaml round-trip failed/.test(c);return I(t,m?409:500,{error:m?"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:m?"yaml-authored":"save-failed",...u?{path:u}:{}})}return e.layouts.sync(l.id,l.nodes.map(i=>i.id)),I(t,200,{workflow:l})}function gs(t,e,a,n){let r=new URL(n,"http://_").searchParams,o=n.replace(/^\/api\/workflows\/runs/,"");if(o===""||o.startsWith("?")){let i=Math.max(1,Math.min(500,Number(r.get("limit")||50))),c=r.get("workflowId")||void 0,u=r.get("summary")==="1"||r.get("summary")==="true",m=a.runs.list({workflowId:c,limit:i});if(!u)return I(e,200,{runs:m});let x=m.map(b=>({id:b.id,workflowId:b.workflowId,workflowVersion:b.workflowVersion,homeNode:b.homeNode,status:b.status,pending:b.pending,entityRef:b.entityRef,history:(b.history||[]).slice(-5),parentRunId:b.parentRunId,parentNodeId:b.parentNodeId,rootRunId:b.rootRunId,depth:b.depth,createdAt:b.createdAt,updatedAt:b.updatedAt}));return I(e,200,{runs:x})}let s=o.match(/^\/([^\/?]+)\/status$/);if(s){if((t.method||"GET").toUpperCase()!=="POST")return I(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;let i=decodeURIComponent(s[1]);return fe(t,e,c=>{let u=c?.status;return u!=="paused"&&u!=="running"&&u!=="canceled"?I(e,400,{error:"status must be paused|running|canceled"}):a.runs.setStatus(i,u)?I(e,200,{ok:!0,runId:i,status:u}):I(e,404,{error:"run not found"})})}let l=o.match(/^\/([^\/?]+)(\/stream)?$/);if(l){let i=decodeURIComponent(l[1]);if(l[2])return fs(t,e,a,i);let c=a.runs.get(i);return c?I(e,200,{run:c}):I(e,404,{error:"run not found"})}return I(e,404,{error:"unknown runs endpoint"})}function fs(t,e,a,n){let r=a.runs.get(n);if(!r)return I(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)}
13343
14303
 
13344
- `);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)}
14304
+ `);let o=!1,s=()=>{o=!0,i?.(),clearInterval(u);try{e.end()}catch{}};t.on("close",s);let l=m=>{if(!o)try{e.write(`data: ${JSON.stringify(m)}
13345
14305
 
13346
- `)}catch{s()}},l=a.runEvents?.subscribe(n,i),d=r.updatedAt,p=setInterval(()=>{if(o)return;let u=a.runs.get(n);u&&u.updatedAt!==d&&(d=u.updatedAt,i(u))},2e3);return!0}function re(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){T(e,400,{error:"invalid JSON body",message:s.message});return}let o;try{o=a(r)}catch(s){try{T(e,500,{error:"handler threw (sync)",message:s?.message??String(s)})}catch{}return}Promise.resolve(o).catch(s=>{try{T(e,500,{error:"handler threw",message:s?.message??String(s)})}catch{}})}),t.on("error",r=>T(e,400,{error:"body read failed",message:r.message})),!0}function T(t,e,a){return t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a)),!0}function Rl(t){let e=t.dashboard,a=t.boards,n=e.port,r=e.bind,o=e.token,s=new Map;for(let v of a)try{s.set(v.id,Zo(v,t))}catch(k){console.error(` Board "${v.id}" failed to initialize: ${k.message}`)}let i=t.node?.id||"local",l=t.workflows?.dir?xe(process.cwd(),t.workflows.dir):void 0,d=new rt(l?{baseDir:l}:void 0),p=new ot(l?{baseDir:l,nodeId:i}:{nodeId:i}),u=new st(l?{baseDir:l}:void 0);ma(t),mt({business:t.business?.enabled===!0}),qo(async(v,k)=>{try{await Jo(v,k,{boards:a,sources:s,token:o,config:t,workflowStore:d,workflowRuns:p,workflowLayouts:u})}catch(A){y(k,500,{error:A.message||"internal error"})}}).listen(n,r,()=>{let v=r==="0.0.0.0"?"localhost":r;a.length===0?(console.log(`
13347
- Live dashboard: http://${v}:${n}
14306
+ `)}catch{s()}},i=a.runEvents?.subscribe(n,l),c=r.updatedAt,u=setInterval(()=>{if(o)return;let m=a.runs.get(n);m&&m.updatedAt!==c&&(c=m.updatedAt,l(m))},2e3);return!0}function fe(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){I(e,400,{error:"invalid JSON body",message:s.message});return}let o;try{o=a(r)}catch(s){try{I(e,500,{error:"handler threw (sync)",message:s?.message??String(s)})}catch{}return}Promise.resolve(o).catch(s=>{try{I(e,500,{error:"handler threw",message:s?.message??String(s)})}catch{}})}),t.on("error",r=>I(e,400,{error:"body read failed",message:r.message})),!0}function I(t,e,a){return t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a)),!0}function Rd(t){let e=t.dashboard,a=t.boards,n=e.port,r=e.bind,o=e.token,s=new Map;for(let b of a)try{s.set(b.id,As(b,t))}catch(_){console.error(` Board "${b.id}" failed to initialize: ${_.message}`)}let l=t.node?.id||"local",i=t.workflows?.dir?ke(process.cwd(),t.workflows.dir):void 0,c=new xt(i?{baseDir:i}:void 0),u=new vt(i?{baseDir:i,nodeId:l}:{nodeId:l}),m=new bt(i?{baseDir:i}:void 0);Aa(t),Et({business:t.business?.enabled===!0}),xs(async(b,_)=>{try{await Es(b,_,{boards:a,sources:s,token:o,config:t,workflowStore:c,workflowRuns:u,workflowLayouts:m})}catch(M){v(_,500,{error:M.message||"internal error"})}}).listen(n,r,()=>{let b=r==="0.0.0.0"?"localhost":r;a.length===0?(console.log(`
14307
+ Live dashboard: http://${b}:${n}
13348
14308
  `),console.log(" (no boards configured \u2014 '/' serves the live view; add a board with 'agentx board add')")):(console.log(`
13349
- Kanban dashboard: http://${v}:${n}
13350
- `),console.log(` Boards: ${a.map(k=>k.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 Ko=new Set(["/","/live","/mesh","/boards","/glossary","/workflows","/procedures","/processes","/graph","/setup","/admin","/admin/graph","/admin/health","/admin/observability","/admin/ledger","/admin/cost","/admin/projects","/admin/wiki","/admin/activity-graph"]);async function Jo(t,e,a){let n=new URL(t.url||"/","http://localhost"),r=n.pathname,o=(t.method||"GET").toUpperCase();if(e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, PATCH, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization, X-Requested-With"),o==="OPTIONS"){e.writeHead(204),e.end();return}if(o==="GET"&&Ko.has(r)&&Ct("page",r),o==="GET"&&r==="/"){let c=_t();if(!c.configExists||c.agentCount===0){e.writeHead(302,{Location:"/setup"}),e.end();return}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ve({peers:H(a.config)}));return}if(o==="GET"&&r==="/boards"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Da({peers:H(a.config)}));return}if(o==="GET"&&r==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ve({peers:H(a.config)}));return}if(o==="GET"&&r==="/mesh"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end($a({peers:H(a.config)}));return}if(o==="GET"&&r==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pa({peers:H(a.config)}));return}if(o==="GET"&&r==="/workflows"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Oa({peers:H(a.config)}));return}if(o==="GET"&&r==="/procedures"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ha({peers:H(a.config)}));return}if(o==="GET"&&r==="/processes"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(kt({}));return}let s=o==="GET"&&r.match(/^\/tasks\/([^/]+)$/);if(s){let c=n.searchParams.get("agent")||"",m=n.searchParams.get("node")||a.config.dashboard.daemonUrl;if(!c){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(Na({taskId:decodeURIComponent(s[1]),agentId:c,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:m,peers:H(a.config)}));return}let i=o==="GET"&&r.match(/^\/agents\/([^/]+)\/history$/);if(i){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ba({agentId:decodeURIComponent(i[1]),agentName:n.searchParams.get("name")||void 0,nodeUrl:n.searchParams.get("node")||a.config.dashboard.daemonUrl,peers:H(a.config)}));return}if(o==="GET"&&r==="/graph"){e.writeHead(302,{Location:"/admin/graph"}),e.end();return}if(o==="GET"&&r==="/setup"){Et(t,e);return}if(o==="POST"&&r==="/api/setup"){await St(t,e);return}if(o==="POST"&&r==="/api/setup/start-daemon"){await Tt(t,e);return}if(o==="GET"&&r==="/admin"){Lt(t,e,H(a.config),a.token);return}if(o==="GET"&&r==="/admin/graph"){Bt(t,e,H(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}Kt(t,e,H(a.config));return}if(r.startsWith("/api/admin/")||r.startsWith("/api/workflows")||r.startsWith("/api/agents")){let c=String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(c==="fleet"){if(r==="/api/admin/activity-graph"){await hs(t,e,a);return}let m=r.match(/^\/api\/admin\/activity-graph\/dispatch\/(.+)$/);if(m){let g=decodeURIComponent(m[1]),x=g.indexOf("::");if(x>0){let h=g.slice(0,x),b=g.slice(x+2),_=a.config.node?.id||a.config.node?.name||"local";if(h===_)t.url=`/api/admin/activity-graph/dispatch/${encodeURIComponent(b)}`;else{let j=(a.config.dashboard?.daemons||[]).find($=>($.name||$.url)===h);if(j){let $=tt(j.url.replace(/\/+$/,""),a.config);if($){await Ua(t,e,$,`/api/admin/activity-graph/dispatch/${encodeURIComponent(b)}`);return}}y(e,404,{error:`unknown node "${h}" in fleet dispatch id`});return}}}}else if(c&&c!=="primary"){let m=tt(c,a.config);if(!m){y(e,404,{error:`unknown peer: ${c}`});return}let g=(n.search||"").replace(/[?&]peer=[^&]*/g,h=>h.startsWith("?")?"?":"");await Ua(t,e,m,r+(g==="?"?"":g));return}}if(o==="GET"&&r.startsWith("/api/admin/observability/")&&await Jt(t,e,r))return;if(o==="GET"&&r==="/api/admin/logs/stream"){await gs(t,e);return}if(o==="GET"&&r==="/api/admin/doctor"){try{let{runDoctorChecks:c}=await import("./doctor-3Q36ZFE6.js"),g=new URL(t.url||"/","http://_").searchParams.get("running")!=="false",x=await c({running:g});y(e,200,x)}catch(c){y(e,500,{error:c?.message||String(c)})}return}if(o==="GET"&&r==="/admin/ledger"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Zt({peers:H(a.config)}));return}if(o==="GET"&&r.startsWith("/api/admin/ledger/")&&await Qt(t,e,r))return;if(o==="GET"&&r==="/admin/cost"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ea({peers:H(a.config)}));return}if(o==="GET"&&r==="/admin/projects"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ta({peers:H(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 ts(a)(t,e);return}if(o==="GET"&&r==="/admin/activity-graph"){sa(t,e,H(a.config));return}if(o==="GET"&&r==="/api/admin/activity-graph"&&await ha(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/stream")&&await ga(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/dispatch/")&&await xa(t,e,r))return;let l=o==="GET"&&r.match(/^\/admin\/agents\/([a-z0-9][a-z0-9_-]*)$/);if(l){ya(t,e,l[1],H(a.config),a.token);return}if(r.startsWith("/api/admin/")&&a.token){let c=t.headers.authorization||"",m=c.startsWith("Bearer ")?c.slice(7):"";if(m!==a.token){let g=new Z,x=m?g.verify(m):null;if(!x||!me(x,"dashboard:write")){y(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/admin/config"){await Rt(t,e);return}if(r.startsWith("/api/admin/graph/")){await zt(t,e,r);return}if(r.startsWith("/api/admin/agent/")){await wa(t,e,r);return}if(r.startsWith("/api/admin/")){await Dt(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(Mt);return}if(o==="GET"&&r.startsWith("/assets/")){let c=r.slice(8);if(!/^[a-zA-Z0-9._-]+\.(js|map|css)$/.test(c)){y(e,400,{error:"invalid asset name"});return}let m=us("web/"+c);try{let g=await ms(m),x=c.endsWith(".map")?"application/json; charset=utf-8":c.endsWith(".css")?"text/css; charset=utf-8":"application/javascript; charset=utf-8";e.writeHead(200,{"Content-Type":x,"Cache-Control":"public, max-age=60"}),e.end(g)}catch{y(e,404,{error:"asset not found",hint:"run: npm run build:web"})}return}if(o==="GET"&&r==="/api/live"){try{let c=await et(a.config);y(e,200,c)}catch(c){y(e,502,{error:c.message})}return}if(o==="GET"&&r==="/api/mesh"){try{let c=n.searchParams.get("date")||new Date().toISOString().slice(0,10),m=n.searchParams.get("timezone")||"UTC",g=await et(a.config,{date:c,timezone:m});y(e,200,g)}catch(c){y(e,502,{error:c.message})}return}if(o==="GET"&&r==="/api/mesh/analytics"){let c=(m,g,x,h)=>{let b=parseInt(n.searchParams.get(m)||"",10);return Number.isFinite(b)?Math.max(x,Math.min(h,b)):g};try{let m=await Le(a.config);y(e,200,await ja(m,{days:c("days",30,0,180),tzOffsetMinutes:c("tzOffset",0,-840,840),limit:c("limit",60,1,200)}))}catch(m){y(e,502,{error:m.message})}return}if(o==="GET"&&r==="/api/mesh/day"){let c=n.searchParams.get("day")||"";if(!/^\d{4}-\d{2}-\d{2}$/.test(c)){y(e,400,{error:"day=YYYY-MM-DD query param required"});return}let m=(g,x,h,b)=>{let _=parseInt(n.searchParams.get(g)||"",10);return Number.isFinite(_)?Math.max(h,Math.min(b,_)):x};try{let g=await Le(a.config);y(e,200,await Ra(g,{day:c,tzOffsetMinutes:m("tzOffset",0,-840,840),limit:m("limit",40,1,200)}))}catch(g){y(e,502,{error:g.message})}return}if(o==="GET"&&(r==="/api/mesh/thread"||r==="/api/mesh/job"||r==="/api/mesh/run"||r==="/api/mesh/conversation")){let c=n.searchParams.get("node");if(!c){y(e,400,{error:"node query param required"});return}let m=n.searchParams,g;if(r==="/api/mesh/thread"){let[x,h,b]=[m.get("agent"),m.get("channel"),m.get("chat")];if(!x||!h||!b){y(e,400,{error:"agent, channel, chat required"});return}g=`/analytics/thread?agent=${encodeURIComponent(x)}&channel=${encodeURIComponent(h)}&chat=${encodeURIComponent(b)}&limit=${encodeURIComponent(m.get("limit")||"120")}`}else if(r==="/api/mesh/job"){let[x,h]=[m.get("kind"),m.get("key")];if(!x||!h){y(e,400,{error:"kind and key required"});return}g=`/analytics/job?kind=${encodeURIComponent(x)}&key=${encodeURIComponent(h)}&limit=${encodeURIComponent(m.get("limit")||"120")}`}else if(r==="/api/mesh/conversation"){let[x,h,b]=[m.get("agent"),m.get("channel"),m.get("chat")];if(!x||!h||!b){y(e,400,{error:"agent, channel, chat required"});return}g=`/analytics/conversation?agent=${encodeURIComponent(x)}&channel=${encodeURIComponent(h)}&chat=${encodeURIComponent(b)}&tzOffset=${encodeURIComponent(m.get("tzOffset")||"0")}`}else{let x=m.get("task");if(!x){y(e,400,{error:"task required"});return}g=`/analytics/run/${encodeURIComponent(x)}`}try{await La(e,await Le(a.config),c,g)}catch(x){y(e,502,{error:x.message})}return}if(o==="GET"&&r==="/api/live/stream"){ns(t,e,a.config);return}if(o==="GET"&&r==="/api/task/stream"){let c=new URL(t.url||"/","http://localhost"),m=c.searchParams.get("node"),g=c.searchParams.get("agent"),x=c.searchParams.get("task");if(!m||!g||!x){y(e,400,{error:"node, agent, task query params required"});return}await rs(t,e,a,m,g,x);return}if(o==="GET"&&r==="/api/task/history"){let c=new URL(t.url||"/","http://localhost"),m=c.searchParams.get("node"),g=c.searchParams.get("agent"),x=c.searchParams.get("task"),h=c.searchParams.get("limit")||"50";if(!m||!g){y(e,400,{error:"node and agent query params required"});return}await is(e,a,m,g,x,h);return}if(o==="POST"&&r==="/api/task/action"){let c=new URL(t.url||"/","http://localhost"),m=c.searchParams.get("node"),g=c.searchParams.get("task"),x=c.searchParams.get("kind");if(!m||!g||x!=="cancel"&&x!=="followup"){y(e,400,{error:"node, task, kind=cancel|followup query params required"});return}await ls(t,e,a,m,g,x);return}if(o==="GET"&&r==="/api/agents"){try{let c={};a.config.dashboard.token&&(c.Authorization=`Bearer ${a.config.dashboard.token}`);let m=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:c});if(!m.ok)throw new Error(`HTTP ${m.status}`);let g=await m.json();y(e,200,g)}catch(c){y(e,502,{error:c.message||"agents fetch failed"})}return}if(o==="POST"&&r==="/api/draft"){let c=await oe(t);try{let m=await cs(a.config,c);y(e,200,m)}catch(m){y(e,502,{error:m.message||"draft failed"})}return}let d=r.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(d&&o==="POST"){let c=d[1];if(!os(t,e,[`agent:${c}`]))return;await ss(t,e,a.config,c);return}if(r.startsWith("/api/")&&a.token){let c=t.headers.authorization||"",m=c.startsWith("Bearer ")?c.slice(7):"";if(m!==a.token){let g=new Z,x=m?g.verify(m):null;if(!x||!me(x,"dashboard:write")){y(e,401,{error:"unauthorized"});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==="GET"&&r==="/events"){let m=new URL(t.url||"/","http://localhost").searchParams.toString();e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"});let g=[{name:a.config.node.name||"local",url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(_=>({name:_.name,url:_.url,token:_.token}))],x={flag:!1},h=[];t.on("close",()=>{x.flag=!0;for(let _ of h)try{_.abort()}catch{}});let b=setInterval(()=>{if(!x.flag)try{e.write(`: ping
14309
+ Kanban dashboard: http://${b}:${n}
14310
+ `),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 _s=new Set(["/","/live","/mesh","/monitor","/activity","/boards","/glossary","/workflows","/workflows/editor","/procedures","/processes","/graph","/setup","/admin","/admin/graph","/admin/health","/admin/observability","/admin/ledger","/admin/cost","/admin/projects","/admin/wiki","/admin/activity-graph"]);async function Es(t,e,a){let n=new URL(t.url||"/","http://localhost"),r=n.pathname,o=(t.method||"GET").toUpperCase();if(e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, PATCH, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization, X-Requested-With"),o==="OPTIONS"){e.writeHead(204),e.end();return}if(o==="GET"&&_s.has(r)&&Ht("page",r),o==="GET"&&r==="/"){let d=Rt();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(it({peers:O(a.config)}));return}if(o==="GET"&&r==="/boards"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Va({peers:O(a.config)}));return}if(o==="GET"&&r==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(it({peers:O(a.config)}));return}if(o==="POST"&&r.match(/^\/webhook\/n8n\/[A-Za-z0-9._:-]{1,64}$/)){try{let[d]=await ie(a.config);if(!d){v(e,503,{error:"no node available"});return}let p=await new Promise(f=>{let h="";t.on("data",y=>h+=y),t.on("end",()=>f(h)),t.on("error",()=>f(""))}),g=await fetch(d.url+r,{method:"POST",headers:{"Content-Type":"application/json",...d.token?{Authorization:`Bearer ${d.token}`}:{}},body:p||"{}"});e.writeHead(g.status,{"Content-Type":"application/json"}),e.end(await g.text())}catch(d){v(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 ie(a.config),p=o==="POST"?void 0:n.searchParams.get("node"),g=o==="POST"?await re(t):void 0,f=g?.node??p,h=f?d.find($=>$.url===f):d[0];if(!h){v(e,400,{error:"unknown node"});return}let y=n.search?n.search.replace(/([?&])node=[^&]*/,"$1").replace(/[?&]$/,""):"",k=await fetch(h.url+r+y,{method:o,headers:{"Content-Type":"application/json",...h.token?{Authorization:`Bearer ${h.token}`}:{}},...o==="POST"?{body:JSON.stringify({...g,node:void 0})}:{}});v(e,k.status,await k.json().catch(()=>({error:`HTTP ${k.status}`})))}catch(d){v(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 re(t),p={"Content-Type":"application/json"};a.config.dashboard.token&&(p.Authorization=`Bearer ${a.config.dashboard.token}`);let g=a.config.dashboard.daemonUrl.replace(/\/+$/,""),f=await fetch(`${g}/api/workflows/editor/chat`,{method:"POST",headers:p,body:JSON.stringify(d??{})}),h=await f.json().catch(()=>({error:`HTTP ${f.status}`}));v(e,f.status,h)}catch(d){v(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(o==="GET"&&r==="/api/n8n/workflows"){try{let[d]=await ie(a.config);if(!d){v(e,200,{configured:!1,workflows:[]});return}let p=await fetch(d.url+"/api/n8n/workflows",{headers:d.token?{Authorization:`Bearer ${d.token}`}:{}});v(e,p.status,await p.json().catch(()=>({configured:!1,workflows:[]})))}catch{v(e,200,{configured:!1,workflows:[]})}return}if(o==="GET"&&r==="/workflows/editor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Wt({peers:O(a.config)}));return}if(o==="GET"&&r==="/activity"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ut({peers:O(a.config)}));return}if(o==="GET"&&r==="/monitor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(zt({peers:O(a.config)}));return}if(r==="/api/monitor"||r.startsWith("/api/monitor/")){let d=new AbortController,p=setTimeout(()=>d.abort(),8e3);try{let g=wt(await ie(a.config,d.signal),a.config.mesh.peers);if(o==="GET"&&r==="/api/monitor"){let $=await Promise.all(g.map(async A=>{try{let w=await fetch(A.url+"/monitor",{headers:A.token?{Authorization:`Bearer ${A.token}`}:{},signal:d.signal});if(!w.ok)throw new Error(`HTTP ${w.status}`);return{name:A.name,url:A.url,ok:!0,data:await w.json()}}catch(w){return{name:A.name,url:A.url,ok:!1,error:w.message}}}));v(e,200,{nodes:$});return}let f=g.find($=>$.url===n.searchParams.get("node"));if(!f){v(e,400,{error:"Select a known node"});return}let h=r.slice(13);if(!(o==="GET"&&["discover","actions","activity"].includes(h)||o==="POST"&&["register","ended","action","retry","clear"].includes(h))){v(e,405,{error:"Unknown monitor operation"});return}let y=o==="POST"?JSON.stringify(await yt(t)):void 0,k=await fetch(f.url+"/monitor/"+h+(h==="actions"?"?offset="+encodeURIComponent(n.searchParams.get("offset")||"0"):h==="activity"?"?hours="+encodeURIComponent(n.searchParams.get("hours")||"24"):""),{method:o,body:y,signal:d.signal,headers:{"Content-Type":"application/json",...f.token?{Authorization:`Bearer ${f.token}`}:{}}});v(e,k.status,await k.json())}catch(g){v(e,502,{error:g.message})}finally{clearTimeout(p)}return}if(o==="GET"&&r==="/mesh"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ga({peers:O(a.config)}));return}if(o==="GET"&&r==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ya({peers:O(a.config)}));return}if(o==="GET"&&r==="/workflows"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Qa({peers:O(a.config)}));return}if(o==="GET"&&r==="/procedures"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Za({peers:O(a.config)}));return}if(o==="GET"&&r==="/processes"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Lt({}));return}let l=o==="GET"&&r.match(/^\/tasks\/([^/]+)$/);if(l){let d=n.searchParams.get("agent")||"",p=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(en({taskId:decodeURIComponent(l[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:p,peers:O(a.config)}));return}let i=o==="GET"&&r.match(/^\/agents\/([^/]+)\/history$/);if(i){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(tn({agentId:decodeURIComponent(i[1]),agentName:n.searchParams.get("name")||void 0,nodeUrl:n.searchParams.get("node")||a.config.dashboard.daemonUrl,peers:O(a.config)}));return}if(o==="GET"&&r==="/graph"){e.writeHead(302,{Location:"/admin/graph"}),e.end();return}if(o==="GET"&&r==="/setup"){Pt(t,e);return}if(o==="POST"&&r==="/api/setup"){await Dt(t,e);return}if(o==="POST"&&r==="/api/setup/start-daemon"){await Ot(t,e);return}if(o==="GET"&&r==="/admin"){Vt(t,e,O(a.config),a.token);return}if(o==="GET"&&r==="/admin/graph"){na(t,e,O(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}pa(t,e,O(a.config));return}if(r.startsWith("/api/admin/")||r.startsWith("/api/workflows")||r.startsWith("/api/agents")){let d=String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(d==="fleet"){if(r==="/api/admin/activity-graph"){await Us(t,e,a);return}let p=r.match(/^\/api\/admin\/activity-graph\/dispatch\/(.+)$/);if(p){let g=decodeURIComponent(p[1]),f=g.indexOf("::");if(f>0){let h=g.slice(0,f),y=g.slice(f+2),k=a.config.node?.id||a.config.node?.name||"local";if(h===k)t.url=`/api/admin/activity-graph/dispatch/${encodeURIComponent(y)}`;else{let $=(a.config.dashboard?.daemons||[]).find(A=>(A.name||A.url)===h);if($){let A=ut($.url.replace(/\/+$/,""),a.config);if(A){await rn(t,e,A,`/api/admin/activity-graph/dispatch/${encodeURIComponent(y)}`);return}}v(e,404,{error:`unknown node "${h}" in fleet dispatch id`});return}}}}else if(d&&d!=="primary"){let p=ut(d,a.config);if(!p){v(e,404,{error:`unknown peer: ${d}`});return}let g=(n.search||"").replace(/[?&]peer=[^&]*/g,h=>h.startsWith("?")?"?":"");await rn(t,e,p,r+(g==="?"?"":g));return}}if(o==="GET"&&r.startsWith("/api/admin/observability/")&&await ua(t,e,r))return;if(o==="GET"&&r==="/api/admin/logs/stream"){await Fs(t,e);return}if(o==="GET"&&r==="/api/admin/doctor"){try{let{runDoctorChecks:d}=await import("./doctor-PBAH6XL3.js"),g=new URL(t.url||"/","http://_").searchParams.get("running")!=="false",f=await d({running:g});v(e,200,f)}catch(d){v(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(fa({peers:O(a.config)}));return}if(o==="GET"&&r.startsWith("/api/admin/ledger/")&&await ga(t,e,r))return;if(o==="GET"&&r==="/admin/cost"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(xa({peers:O(a.config)}));return}if(o==="GET"&&r==="/admin/projects"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(va({peers:O(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 Is(a)(t,e);return}if(o==="GET"&&r==="/admin/activity-graph"){_a(t,e,O(a.config));return}if(o==="GET"&&r==="/api/admin/activity-graph"&&await Ma(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/stream")&&await Ia(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/dispatch/")&&await ja(t,e,r))return;let c=o==="GET"&&r.match(/^\/admin\/agents\/([a-z0-9][a-z0-9_-]*)$/);if(c){Pa(t,e,c[1],O(a.config),a.token);return}if(r.startsWith("/api/admin/")&&a.token){let d=t.headers.authorization||"",p=d.startsWith("Bearer ")?d.slice(7):"";if(p!==a.token){let g=new ee,f=p?g.verify(p):null;if(!f||!ve(f,"dashboard:write")){v(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/admin/config"){await Yt(t,e);return}if(r.startsWith("/api/admin/graph/")){await ra(t,e,r);return}if(r.startsWith("/api/admin/agent/")){await Da(t,e,r);return}if(r.startsWith("/api/admin/")){await Qt(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(Gt);return}if(o==="GET"&&r.startsWith("/assets/")){let d=r.slice(8);if(!/^[a-zA-Z0-9._-]+\.(js|map|css)$/.test(d)){v(e,400,{error:"invalid asset name"});return}let p=zs("web/"+d);try{let g=await qs(p),f=d.endsWith(".map")?"application/json; charset=utf-8":d.endsWith(".css")?"text/css; charset=utf-8":"application/javascript; charset=utf-8",h=n.searchParams.has("v");e.writeHead(200,{"Content-Type":f,"Cache-Control":h?"public, max-age=31536000, immutable":"public, max-age=60"}),e.end(g)}catch{v(e,404,{error:"asset not found",hint:"run: npm run build:web"})}return}if(o==="GET"&&r==="/api/live"){try{let d=await pt(a.config);v(e,200,d)}catch(d){v(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),p=n.searchParams.get("timezone")||"UTC",g=await pt(a.config,{date:d,timezone:p});v(e,200,g)}catch(d){v(e,502,{error:d.message})}return}if(o==="GET"&&r==="/api/mesh/analytics"){let d=(p,g,f,h)=>{let y=parseInt(n.searchParams.get(p)||"",10);return Number.isFinite(y)?Math.max(f,Math.min(h,y)):g};try{let p=await ie(a.config);v(e,200,await Xa(p,{days:d("days",30,0,180),tzOffsetMinutes:d("tzOffset",0,-840,840),limit:d("limit",60,1,200)}))}catch(p){v(e,502,{error:p.message})}return}if(o==="GET"&&r==="/api/mesh/day"){let d=n.searchParams.get("day")||"";if(!/^\d{4}-\d{2}-\d{2}$/.test(d)){v(e,400,{error:"day=YYYY-MM-DD query param required"});return}let p=(g,f,h,y)=>{let k=parseInt(n.searchParams.get(g)||"",10);return Number.isFinite(k)?Math.max(h,Math.min(y,k)):f};try{let g=await ie(a.config);v(e,200,await Ja(g,{day:d,tzOffsetMinutes:p("tzOffset",0,-840,840),limit:p("limit",40,1,200)}))}catch(g){v(e,502,{error:g.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){v(e,400,{error:"node query param required"});return}let p=n.searchParams,g;if(r==="/api/mesh/thread"){let[f,h,y]=[p.get("agent"),p.get("channel"),p.get("chat")];if(!f||!h||!y){v(e,400,{error:"agent, channel, chat required"});return}g=`/analytics/thread?agent=${encodeURIComponent(f)}&channel=${encodeURIComponent(h)}&chat=${encodeURIComponent(y)}&limit=${encodeURIComponent(p.get("limit")||"120")}`}else if(r==="/api/mesh/job"){let[f,h]=[p.get("kind"),p.get("key")];if(!f||!h){v(e,400,{error:"kind and key required"});return}g=`/analytics/job?kind=${encodeURIComponent(f)}&key=${encodeURIComponent(h)}&limit=${encodeURIComponent(p.get("limit")||"120")}`}else if(r==="/api/mesh/conversation"){let[f,h,y]=[p.get("agent"),p.get("channel"),p.get("chat")];if(!f||!h||!y){v(e,400,{error:"agent, channel, chat required"});return}g=`/analytics/conversation?agent=${encodeURIComponent(f)}&channel=${encodeURIComponent(h)}&chat=${encodeURIComponent(y)}&tzOffset=${encodeURIComponent(p.get("tzOffset")||"0")}`}else{let f=p.get("task");if(!f){v(e,400,{error:"task required"});return}g=`/analytics/run/${encodeURIComponent(f)}`}try{await Ka(e,await ie(a.config),d,g)}catch(f){v(e,502,{error:f.message})}return}if(o==="GET"&&r==="/api/live/stream"){js(t,e,a.config);return}if(o==="GET"&&r==="/api/task/stream"){let d=new URL(t.url||"/","http://localhost"),p=d.searchParams.get("node"),g=d.searchParams.get("agent"),f=d.searchParams.get("task");if(!p||!g||!f){v(e,400,{error:"node, agent, task query params required"});return}await Ls(t,e,a,p,g,f);return}if(o==="GET"&&r==="/api/task/history"){let d=new URL(t.url||"/","http://localhost"),p=d.searchParams.get("node"),g=d.searchParams.get("agent"),f=d.searchParams.get("task"),h=d.searchParams.get("limit")||"50";if(!p||!g){v(e,400,{error:"node and agent query params required"});return}await Ds(e,a,p,g,f,h);return}if(o==="POST"&&r==="/api/task/action"){let d=new URL(t.url||"/","http://localhost"),p=d.searchParams.get("node"),g=d.searchParams.get("task"),f=d.searchParams.get("kind");if(!p||!g||f!=="cancel"&&f!=="followup"){v(e,400,{error:"node, task, kind=cancel|followup query params required"});return}await Os(t,e,a,p,g,f);return}if(o==="GET"&&r==="/api/agents"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let p=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:d});if(!p.ok)throw new Error(`HTTP ${p.status}`);let g=await p.json();v(e,200,g)}catch(d){v(e,502,{error:d.message||"agents fetch failed"})}return}if(o==="POST"&&r==="/api/draft"){let d=await re(t);try{let p=await Ns(a.config,d);v(e,200,p)}catch(p){v(e,502,{error:p.message||"draft failed"})}return}let u=r.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(u&&o==="POST"){let d=u[1];if(!Rs(t,e,[`agent:${d}`]))return;await Ps(t,e,a.config,d);return}if(r.startsWith("/api/")&&a.token){let d=t.headers.authorization||"",p=d.startsWith("Bearer ")?d.slice(7):"";if(p!==a.token){let g=new ee,f=p?g.verify(p):null;if(!f||!ve(f,"dashboard:write")){v(e,401,{error:"unauthorized"});return}}}if((o==="POST"||o==="PATCH"||o==="DELETE"||o==="PUT")&&r.startsWith("/api/")&&t.headers["x-requested-with"]!=="agentx-board"){v(e,400,{error:"missing X-Requested-With: agentx-board"});return}if(o==="GET"&&r==="/events"){let p=new URL(t.url||"/","http://localhost").searchParams.toString();e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"});let g=[{name:a.config.node.name||"local",url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(k=>({name:k.name,url:k.url,token:k.token}))],f={flag:!1},h=[];t.on("close",()=>{f.flag=!0;for(let k of h)try{k.abort()}catch{}});let y=setInterval(()=>{if(!f.flag)try{e.write(`: ping
13351
14311
 
13352
- `)}catch{}},15e3);t.on("close",()=>clearInterval(b));for(let _ of g)(async()=>{let j={Accept:"text/event-stream"};_.token&&(j.Authorization=`Bearer ${_.token}`);let $=new AbortController;h.push($);try{let w=await fetch(`${_.url.replace(/\/+$/,"")}/events${m?`?${m}`:""}`,{headers:j,signal:$.signal});if(!w.ok||!w.body)return;let I=w.body.getReader(),L=new TextDecoder,P="";for(;!x.flag;){let{done:O,value:Q}=await I.read();if(O)break;P+=L.decode(Q,{stream:!0});let R;for(;(R=P.indexOf(`
14312
+ `)}catch{}},15e3);t.on("close",()=>clearInterval(y));for(let k of g)(async()=>{let $={Accept:"text/event-stream"};k.token&&($.Authorization=`Bearer ${k.token}`);let A=new AbortController;h.push(A);try{let w=await fetch(`${k.url.replace(/\/+$/,"")}/events${p?`?${p}`:""}`,{headers:$,signal:A.signal});if(!w.ok||!w.body)return;let j=w.body.getReader(),L=new TextDecoder,D="";for(;!f.flag;){let{done:H,value:Z}=await j.read();if(H)break;D+=L.decode(Z,{stream:!0});let R;for(;(R=D.indexOf(`
13353
14313
 
13354
- `))>=0;){let K=P.slice(0,R);if(P=P.slice(R+2),x.flag)break;try{e.write(K+`
14314
+ `))>=0;){let J=D.slice(0,R);if(D=D.slice(R+2),f.flag)break;try{e.write(J+`
13355
14315
 
13356
- `)}catch{x.flag=!0}}}}catch{}})();return}if(o==="GET"&&r==="/api/workflows/runs"){try{let c=new URL(t.url||"/","http://localhost"),m=Math.max(1,Math.min(500,Number(c.searchParams.get("limit")||50))),g=c.searchParams.get("workflowId")||void 0,x=c.searchParams.get("summary")==="1"||c.searchParams.get("summary")==="true",h=a.workflowRuns.list({limit:m,workflowId:g}),b=`?limit=${m}${g?`&workflowId=${encodeURIComponent(g)}`:""}${x?"&summary=1":""}`,_=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(L=>({url:L.url,token:L.token}))],j=await Promise.all(_.map(async L=>{let P={};L.token&&(P.Authorization=`Bearer ${L.token}`);try{let O=new AbortController,Q=setTimeout(()=>O.abort(),5e3);try{let R=await fetch(`${L.url.replace(/\/+$/,"")}/api/workflows/runs${b}`,{headers:P,signal:O.signal});if(!R.ok)return[];let K=await R.json();return Array.isArray(K.runs)?K.runs:[]}finally{clearTimeout(Q)}}catch{return[]}})),$=new Map;for(let L of h)$.set(L.id,L);for(let L of j)for(let P of L)$.set(P.id,P);let w=Array.from($.values()).sort((L,P)=>L.updatedAt<P.updatedAt?1:-1).slice(0,m),I=x?w.map(L=>Qo(L)):w;y(e,200,{runs:I})}catch(c){y(e,502,{error:"runs fetch failed",message:c.message||String(c)})}return}let u=o==="GET"&&r.match(/^\/api\/workflows\/runs\/([^\/]+)$/);if(u){let c=decodeURIComponent(u[1]),m=a.workflowRuns.get(c);if(m){y(e,200,{run:m});return}let g=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(x=>({url:x.url,token:x.token}))];for(let x of g)try{let h={};x.token&&(h.Authorization=`Bearer ${x.token}`);let b=await fetch(`${x.url.replace(/\/+$/,"")}/api/workflows/runs/${encodeURIComponent(c)}`,{headers:h});if(b.ok){y(e,200,await b.json());return}}catch{}y(e,404,{error:"run not found on any configured peer"});return}if(o==="GET"&&r==="/api/actions/builtin"){try{let c={};a.config.dashboard.token&&(c.Authorization=`Bearer ${a.config.dashboard.token}`);let m=a.config.dashboard.daemonUrl.replace(/\/+$/,""),g=await fetch(`${m}/api/actions/builtin`,{headers:c}),x=await g.json().catch(()=>({error:`HTTP ${g.status}`}));y(e,g.status,x)}catch(c){y(e,502,{error:"daemon unreachable",message:c.message||String(c)})}return}let f=o==="POST"&&r.match(/^\/workflows\/([^/]+)\/run$/);if(f){try{let c=await oe(t).catch(()=>({})),m={"Content-Type":"application/json"};a.config.dashboard.token&&(m.Authorization=`Bearer ${a.config.dashboard.token}`);let g=a.config.dashboard.daemonUrl.replace(/\/+$/,""),x=await fetch(`${g}/workflows/${encodeURIComponent(f[1])}/run`,{method:"POST",headers:m,body:JSON.stringify(c??{})}),h=await x.json().catch(()=>({error:`HTTP ${x.status}`}));y(e,x.status,h)}catch(c){y(e,502,{error:"daemon unreachable",message:c.message||String(c)})}return}let v=o==="POST"&&r.match(/^\/api\/workflows\/drafts\/([^/]+)\/replay$/);if(v){try{let c=await oe(t).catch(()=>({})),m={"Content-Type":"application/json"};a.config.dashboard.token&&(m.Authorization=`Bearer ${a.config.dashboard.token}`);let g=a.config.dashboard.daemonUrl.replace(/\/+$/,""),x=await fetch(`${g}/api/workflows/drafts/${encodeURIComponent(v[1])}/replay`,{method:"POST",headers:m,body:JSON.stringify(c??{})}),h=await x.json().catch(()=>({error:`HTTP ${x.status}`}));y(e,x.status,h)}catch(c){y(e,502,{error:"daemon unreachable",message:c.message||String(c)})}return}if(r.startsWith("/api/workflows")&&qa(t,e,{store:a.workflowStore,runs:a.workflowRuns,layouts:a.workflowLayouts,requireScope:(m,g,x)=>{if(a.token)return!0;let h=Oe(m);if(!h)return!0;let b=new Z().verify(h);if(!b)return y(g,401,{error:"invalid or revoked token"}),!1;for(let _ of x)if(!me(b,_))return y(g,403,{error:`token missing scope: ${_}`,scopes:b.scopes}),!1;return!0}}))return;if(o==="GET"&&r==="/api/boards"){y(e,200,a.boards.map(c=>({id:c.id,name:c.name,source:c.source,primaryToolLabel:c.primaryToolLabel,labels:c.labels,columns:c.columns,timeRangeDays:c.timeRangeDays})));return}let k=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/members$/);if(k&&o==="GET"){let c=a.sources.get(k[1]);if(!c){y(e,404,{error:"unknown board"});return}try{let m=typeof c.listMembers=="function"?await c.listMembers():[];y(e,200,m)}catch(m){y(e,502,{error:m.message})}return}let A=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(A&&o==="GET"){let c=a.sources.get(A[1]);if(!c){y(e,404,{error:"unknown board"});return}try{let m=typeof c.listMilestones=="function"?await c.listMilestones():[];y(e,200,m)}catch(m){y(e,502,{error:m.message})}return}let E=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),S=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(E&&o==="PATCH"){let[,c,m]=E,g=decodeURIComponent(m),x=a.boards.find($=>$.id===c);if(!x){y(e,404,{error:`unknown board: ${c}`});return}let h=a.sources.get(c);if(!h){y(e,503,{error:`board "${c}" source unavailable`});return}let b=await oe(t),_=x.columns.find($=>$.id===b.to),j=x.columns.find($=>$.id===b.from);if(!_){y(e,400,{error:`unknown 'to' column: ${b.to}`});return}try{await Yo(h,g,j,_),Ye({actor:Qe(t),action:"move",boardId:c,itemId:g,payload:{from:b.from,to:b.to}}),y(e,200,{ok:!0})}catch($){y(e,502,{error:$.message||"transition failed"})}return}if(S){let[,c,m]=S,g=m?decodeURIComponent(m):void 0,x=a.boards.find(b=>b.id===c);if(!x){y(e,404,{error:`unknown board: ${c}`});return}let h=a.sources.get(c);if(!h){y(e,503,{error:`board "${c}" source unavailable`});return}if(o==="GET"&&!g){let{columns:b,totals:_}=await Vo(x,h,n.searchParams);y(e,200,{columns:b,totals:_});return}if(o==="GET"&&g){try{let b=typeof h.getItem=="function"?await h.getItem(g):null;if(!b){y(e,404,{error:"not found"});return}y(e,200,b)}catch(b){y(e,502,{error:b.message})}return}if(o==="PATCH"&&g){let b=await oe(t);try{let _=typeof h.updateItem=="function"?await h.updateItem(g,b):null;if(!_){y(e,501,{error:"update unsupported"});return}Ye({actor:Qe(t),action:"update",boardId:c,itemId:g,payload:b}),y(e,200,_)}catch(_){y(e,502,{error:_.message})}return}if(o==="POST"&&!g){let b=await oe(t);if(!b.title){y(e,400,{error:"title required"});return}if(!h.capabilities.create||!h.create){y(e,400,{error:`source ${h.type} does not support create`});return}try{let _=await h.create({title:b.title,description:b.description,labels:b.labels,assigneeUsernames:b.assigneeUsernames,milestoneTitle:b.milestoneTitle,projectHint:b.projectHint});Ye({actor:Qe(t),action:"create",boardId:c,itemId:_.id,payload:{title:b.title}}),y(e,201,_)}catch(_){y(e,502,{error:_.message})}return}}if(o==="GET"&&/^\/[a-z][a-z-]*\/?$/.test(r)){let c=r.replace(/^\/+|\/+$/g,""),g={health:"/admin/health",activity:"/admin/activity-graph",ledger:"/admin/ledger",cost:"/admin/cost",projects:"/admin/projects",graph:"/admin/graph",wiki:"/admin/wiki/",observability:"/admin/health"}[c];if(g){e.writeHead(302,{Location:g}),e.end();return}}y(e,404,{error:"not found",path:r})}async function Vo(t,e,a){if(!e.capabilities.listAll||!e.listAll){let c={};for(let m of t.columns)c[m.id]=[];return{columns:c,totals:Object.fromEntries(t.columns.map(m=>[m.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),d=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),p=t.columns.some(c=>c.kind!=="closed"),u=t.columns.some(c=>c.kind==="closed"),f=p?await e.listAll({sinceDays:l,labels:n.length?n:void 0,search:o,milestone:s,state:"opened"}):[],v=u?await e.listAll({sinceDays:d,labels:n.length?n:void 0,search:o,milestone:s,state:"closed"}):[],k={};for(let c of t.columns)k[c.id]=[];let A=t.columns.find(c=>c.kind==="closed");for(let c of v)A&&k[A.id].push({...c,stage:A.id});let E=t.columns.filter(c=>c.kind!=="closed");for(let c of f){let m=it(c,E);if(!m)continue;let g=k[m];g&&g.push({...c,stage:m})}if(i)for(let c of Object.keys(k))k[c]=k[c].filter(m=>m.assignee===i);for(let c of Object.keys(k))k[c].sort((m,g)=>{let x=(m.priority??99)-(g.priority??99);return x!==0?x:(g.updatedAt||"").localeCompare(m.updatedAt||"")});let S=Object.fromEntries(Object.entries(k).map(([c,m])=>[c,m.length]));return{columns:k,totals:S}}async function Yo(t,e,a,n){let r=lt(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 Qo(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 Zo(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 gt(a.host,a.token,t.source.projects,n,(...r)=>console.log("[board]",...r))}throw new Error(`unsupported board source: ${t.source.type}`)}function Ye(t){try{let e=xe(process.cwd(),".agentx");Fa(e)||Fo(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
13357
- `;Uo(xe(e,"board-audit.jsonl"),a)}catch{}}function Qe(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}async function es(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,l,d,p,u]=await Promise.all([fetch(t+"/health",{headers:r,signal:a}).catch(()=>null),fetch(t+"/agents",{headers:r,signal:a}).catch(()=>null),fetch(t+"/mesh",{headers:r,signal:a}).catch(()=>null),fetch(t+"/crons",{headers:r,signal:a}).catch(()=>null),fetch(t+"/crons/runs"+s,{headers:r,signal:a}).catch(()=>null)]);if(!l||!l.ok)return o.error=l?`HTTP ${l.status}`:"unreachable",o;let f=await l.json();if(o.agents=f.map(v=>({id:v.id,name:v.name,tier:v.tier,model:v.model,skillCount:Number.isFinite(v.skillCount)?v.skillCount:void 0,active:v.active||0,total:v.total||0,errors:v.errors||0,lastActive:v.lastActive,lastSummary:v.lastSummary,hourlyTasks:Array.isArray(v.hourlyTasks)?v.hourlyTasks:void 0,runningTasks:Array.isArray(v.runningTasks)?v.runningTasks:[]})),i&&i.ok){let v=await i.json();o.uptimeSec=v.uptime,o.name=v.node?.name||v.node?.id||t,o.id=v.node?.id||t,v.usage&&(o.usage=v.usage)}if(p&&p.ok){let v=await p.json();o.crons=v.map(k=>({id:k.id,enabled:k.enabled===!0,schedule:String(k.schedule||""),timezone:k.timezone,agent:String(k.agent||""),model:k.model,nextRun:k.nextRun,retryPending:k.retryPending===!0,consecutiveErrors:Number(k.consecutiveErrors)||0}))}if(u&&u.ok){let v=await u.json();o.cronRuns=Array.isArray(v.runs)?v.runs:[]}o.reachable=!0,o._peers=Array.isArray(d&&await as(d))?o._peers:void 0}catch(s){o.error=s.message||String(s)}return o}var je=null;function ts(t){if(je)return je;let e=xe(process.cwd(),".agentx/wiki");return je=At({wikiDir:e,pathPrefix:"/admin/wiki",mode:"graph"}),je}var Ze=new WeakMap;async function as(t){if(Ze.has(t))return Ze.get(t);try{let e=t.ok?await t.json():null;return Ze.set(t,e),e}catch{return null}}async function Re(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 Le(t,e){let a=t.dashboard,n=a.daemonUrl.replace(/\/+$/,""),r=new Map;r.set(n,{name:"primary",url:n,token:a.token});for(let s of a.daemons){let i=s.url.replace(/\/+$/,"");r.has(i)||r.set(i,{name:s.name,url:i,token:s.token})}let o=await Re(n,a.token,e);for(let s of o)r.has(s.url)||r.set(s.url,s);return[...r.values()]}async function et(t,e){let a=new AbortController,n=setTimeout(()=>a.abort(),3e3);try{let r=await Le(t,a.signal),o=await Promise.all(r.map(s=>es(s.url,s.token,a.signal,e)));return{ts:new Date().toISOString(),nodes:o}}finally{clearTimeout(n)}}function ns(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=(i,l)=>{n||e.write(`event: ${i}
13358
- data: ${JSON.stringify(l)}
14316
+ `)}catch{f.flag=!0}}}}catch{}})();return}if(o==="GET"&&r==="/api/workflows/runs"){try{let d=new URL(t.url||"/","http://localhost"),p=Math.max(1,Math.min(500,Number(d.searchParams.get("limit")||50))),g=d.searchParams.get("workflowId")||void 0,f=d.searchParams.get("summary")==="1"||d.searchParams.get("summary")==="true",h=a.workflowRuns.list({limit:p,workflowId:g}),y=`?limit=${p}${g?`&workflowId=${encodeURIComponent(g)}`:""}${f?"&summary=1":""}`,k=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(L=>({url:L.url,token:L.token}))],$=await Promise.all(k.map(async L=>{let D={};L.token&&(D.Authorization=`Bearer ${L.token}`);try{let H=new AbortController,Z=setTimeout(()=>H.abort(),5e3);try{let R=await fetch(`${L.url.replace(/\/+$/,"")}/api/workflows/runs${y}`,{headers:D,signal:H.signal});if(!R.ok)return[];let J=await R.json();return Array.isArray(J.runs)?J.runs:[]}finally{clearTimeout(Z)}}catch{return[]}})),A=new Map;for(let L of h)A.set(L.id,L);for(let L of $)for(let D of L)A.set(D.id,D);let w=Array.from(A.values()).sort((L,D)=>L.updatedAt<D.updatedAt?1:-1).slice(0,p),j=f?w.map(L=>Cs(L)):w;v(e,200,{runs:j})}catch(d){v(e,502,{error:"runs fetch failed",message:d.message||String(d)})}return}let x=o==="GET"&&r.match(/^\/api\/workflows\/runs\/([^\/]+)$/);if(x){let d=decodeURIComponent(x[1]),p=a.workflowRuns.get(d);if(p){v(e,200,{run:p});return}let g=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(f=>({url:f.url,token:f.token}))];for(let f of g)try{let h={};f.token&&(h.Authorization=`Bearer ${f.token}`);let y=await fetch(`${f.url.replace(/\/+$/,"")}/api/workflows/runs/${encodeURIComponent(d)}`,{headers:h});if(y.ok){v(e,200,await y.json());return}}catch{}v(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 p=a.config.dashboard.daemonUrl.replace(/\/+$/,""),g=await fetch(`${p}/api/actions/builtin`,{headers:d}),f=await g.json().catch(()=>({error:`HTTP ${g.status}`}));v(e,g.status,f)}catch(d){v(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}let b=o==="POST"&&r.match(/^\/workflows\/([^/]+)\/run$/);if(b){try{let d=await re(t).catch(()=>({})),p={"Content-Type":"application/json"};a.config.dashboard.token&&(p.Authorization=`Bearer ${a.config.dashboard.token}`);let g=a.config.dashboard.daemonUrl.replace(/\/+$/,""),f=await fetch(`${g}/workflows/${encodeURIComponent(b[1])}/run`,{method:"POST",headers:p,body:JSON.stringify(d??{})}),h=await f.json().catch(()=>({error:`HTTP ${f.status}`}));v(e,f.status,h)}catch(d){v(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(r.startsWith("/api/workflows")&&nn(t,e,{store:a.workflowStore,runs:a.workflowRuns,layouts:a.workflowLayouts,requireScope:(p,g,f)=>{if(a.token)return!0;let h=Fe(p);if(!h)return!0;let y=new ee().verify(h);if(!y)return v(g,401,{error:"invalid or revoked token"}),!1;for(let k of f)if(!ve(y,k))return v(g,403,{error:`token missing scope: ${k}`,scopes:y.scopes}),!1;return!0}}))return;if(o==="GET"&&r==="/api/boards"){v(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){v(e,404,{error:"unknown board"});return}try{let p=typeof d.listMembers=="function"?await d.listMembers():[];v(e,200,p)}catch(p){v(e,502,{error:p.message})}return}let M=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(M&&o==="GET"){let d=a.sources.get(M[1]);if(!d){v(e,404,{error:"unknown board"});return}try{let p=typeof d.listMilestones=="function"?await d.listMilestones():[];v(e,200,p)}catch(p){v(e,502,{error:p.message})}return}let E=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),S=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(E&&o==="PATCH"){let[,d,p]=E,g=decodeURIComponent(p),f=a.boards.find(A=>A.id===d);if(!f){v(e,404,{error:`unknown board: ${d}`});return}let h=a.sources.get(d);if(!h){v(e,503,{error:`board "${d}" source unavailable`});return}let y=await re(t),k=f.columns.find(A=>A.id===y.to),$=f.columns.find(A=>A.id===y.from);if(!k){v(e,400,{error:`unknown 'to' column: ${y.to}`});return}try{await Ts(h,g,$,k),lt({actor:dt(t),action:"move",boardId:d,itemId:g,payload:{from:y.from,to:y.to}}),v(e,200,{ok:!0})}catch(A){v(e,502,{error:A.message||"transition failed"})}return}if(S){let[,d,p]=S,g=p?decodeURIComponent(p):void 0,f=a.boards.find(y=>y.id===d);if(!f){v(e,404,{error:`unknown board: ${d}`});return}let h=a.sources.get(d);if(!h){v(e,503,{error:`board "${d}" source unavailable`});return}if(o==="GET"&&!g){let{columns:y,totals:k}=await Ss(f,h,n.searchParams);v(e,200,{columns:y,totals:k});return}if(o==="GET"&&g){try{let y=typeof h.getItem=="function"?await h.getItem(g):null;if(!y){v(e,404,{error:"not found"});return}v(e,200,y)}catch(y){v(e,502,{error:y.message})}return}if(o==="PATCH"&&g){let y=await re(t);try{let k=typeof h.updateItem=="function"?await h.updateItem(g,y):null;if(!k){v(e,501,{error:"update unsupported"});return}lt({actor:dt(t),action:"update",boardId:d,itemId:g,payload:y}),v(e,200,k)}catch(k){v(e,502,{error:k.message})}return}if(o==="POST"&&!g){let y=await re(t);if(!y.title){v(e,400,{error:"title required"});return}if(!h.capabilities.create||!h.create){v(e,400,{error:`source ${h.type} does not support create`});return}try{let k=await h.create({title:y.title,description:y.description,labels:y.labels,assigneeUsernames:y.assigneeUsernames,milestoneTitle:y.milestoneTitle,projectHint:y.projectHint});lt({actor:dt(t),action:"create",boardId:d,itemId:k.id,payload:{title:y.title}}),v(e,201,k)}catch(k){v(e,502,{error:k.message})}return}}if(o==="GET"&&/^\/[a-z][a-z-]*\/?$/.test(r)){let d=r.replace(/^\/+|\/+$/g,""),g={health:"/admin/health",activity:"/admin/activity-graph",ledger:"/admin/ledger",cost:"/admin/cost",projects:"/admin/projects",graph:"/admin/graph",wiki:"/admin/wiki/",observability:"/admin/health"}[d];if(g){e.writeHead(302,{Location:g}),e.end();return}}v(e,404,{error:"not found",path:r})}async function Ss(t,e,a){if(!e.capabilities.listAll||!e.listAll){let d={};for(let p of t.columns)d[p.id]=[];return{columns:d,totals:Object.fromEntries(t.columns.map(p=>[p.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,l=a.get("assignee")||void 0,i=parseInt(a.get("days")||String(t.timeRangeDays),10),c=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),u=t.columns.some(d=>d.kind!=="closed"),m=t.columns.some(d=>d.kind==="closed"),x=u?await e.listAll({sinceDays:i,labels:n.length?n:void 0,search:o,milestone:s,state:"opened"}):[],b=m?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 M=t.columns.find(d=>d.kind==="closed");for(let d of b)M&&_[M.id].push({...d,stage:M.id});let E=t.columns.filter(d=>d.kind!=="closed");for(let d of x){let p=mt(d,E);if(!p)continue;let g=_[p];g&&g.push({...d,stage:p})}if(l)for(let d of Object.keys(_))_[d]=_[d].filter(p=>p.assignee===l);for(let d of Object.keys(_))_[d].sort((p,g)=>{let f=(p.priority??99)-(g.priority??99);return f!==0?f:(g.updatedAt||"").localeCompare(p.updatedAt||"")});let S=Object.fromEntries(Object.entries(_).map(([d,p])=>[d,p.length]));return{columns:_,totals:S}}async function Ts(t,e,a,n){let r=ht(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 Cs(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 As(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 Tt(a.host,a.token,t.source.projects,n,(...r)=>console.log("[board]",...r))}throw new Error(`unsupported board source: ${t.source.type}`)}function lt(t){try{let e=ke(process.cwd(),".agentx");on(e)||bs(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
14317
+ `;vs(ke(e,"board-audit.jsonl"),a)}catch{}}function dt(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}async function Ms(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)}`:"",[l,i,c,u,m]=await Promise.all([fetch(t+"/health",{headers:r,signal:a}).catch(()=>null),fetch(t+"/agents",{headers:r,signal:a}).catch(()=>null),fetch(t+"/mesh",{headers:r,signal:a}).catch(()=>null),fetch(t+"/crons",{headers:r,signal:a}).catch(()=>null),fetch(t+"/crons/runs"+s,{headers:r,signal:a}).catch(()=>null)]);if(!i||!i.ok)return o.error=i?`HTTP ${i.status}`:"unreachable",o;let x=await i.json();if(o.agents=x.map(b=>({id:b.id,name:b.name,tier:b.tier,model:b.model,skillCount:Number.isFinite(b.skillCount)?b.skillCount:void 0,active:b.active||0,total:b.total||0,errors:b.errors||0,lastActive:b.lastActive,lastSummary:b.lastSummary,hourlyTasks:Array.isArray(b.hourlyTasks)?b.hourlyTasks:void 0,runningTasks:Array.isArray(b.runningTasks)?b.runningTasks:[]})),l&&l.ok){let b=await l.json();o.uptimeSec=b.uptime,o.name=b.node?.name||b.node?.id||t,o.id=b.node?.id||t,b.usage&&(o.usage=b.usage)}if(u&&u.ok){let b=await u.json();o.crons=b.map(_=>({id:_.id,enabled:_.enabled===!0,schedule:String(_.schedule||""),timezone:_.timezone,agent:String(_.agent||""),model:_.model,nextRun:_.nextRun,retryPending:_.retryPending===!0,consecutiveErrors:Number(_.consecutiveErrors)||0}))}if(m&&m.ok){let b=await m.json();o.cronRuns=Array.isArray(b.runs)?b.runs:[]}o.reachable=!0,o._peers=Array.isArray(c&&await $s(c))?o._peers:void 0}catch(s){o.error=s.message||String(s)}return o}var De=null;function Is(t){if(De)return De;let e=ke(process.cwd(),".agentx/wiki");return De=Nt({wikiDir:e,pathPrefix:"/admin/wiki",mode:"graph"}),De}var ct=new WeakMap;async function $s(t){if(ct.has(t))return ct.get(t);try{let e=t.ok?await t.json():null;return ct.set(t,e),e}catch{return null}}async function Oe(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 ie(t,e){let a=t.dashboard,n=a.daemonUrl.replace(/\/+$/,""),r=new Map;r.set(n,{name:"primary",url:n,token:a.token});for(let s of a.daemons){let l=s.url.replace(/\/+$/,"");r.has(l)||r.set(l,{name:s.name,url:l,token:s.token})}let o=await Oe(n,a.token,e);for(let s of o)r.has(s.url)||r.set(s.url,s);return[...r.values()]}async function pt(t,e){let a=new AbortController,n=setTimeout(()=>a.abort(),3e3);try{let r=await ie(t,a.signal),o=await Promise.all(r.map(s=>Ms(s.url,s.token,a.signal,e)));return{ts:new Date().toISOString(),nodes:o}}finally{clearTimeout(n)}}function js(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,i)=>{n||e.write(`event: ${l}
14318
+ data: ${JSON.stringify(i)}
13359
14319
 
13360
- `)},o=async()=>{try{let i=await et(a);r("snapshot",i)}catch(i){r("error",{message:i.message})}};o();let s=setInterval(o,2e3);t.on("close",()=>{n=!0,clearInterval(s),e.end()})}async function rs(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),i=new Set;i.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let k of a.config.dashboard.daemons)i.add(k.url.replace(/\/+$/,""));try{let k=await Re(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let A of k)i.add(A.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){y(e,403,{error:"node not in dashboard allowlist",target:s});return}let l=s===a.config.dashboard.daemonUrl.replace(/\/+$/,"")?a.config.dashboard.token:a.config.dashboard.daemons.find(k=>k.url.replace(/\/+$/,"")===s)?.token,d={Accept:"text/event-stream"};l&&(d.Authorization=`Bearer ${l}`);let p=new AbortController,u;try{u=await fetch(`${s}/agents/${encodeURIComponent(r)}/tasks/${encodeURIComponent(o)}/stream`,{headers:d,signal:p.signal})}catch(k){y(e,502,{error:k.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","Access-Control-Allow-Origin":"*","X-Accel-Buffering":"no"});let f=u.body.getReader();(async()=>{try{for(;;){let{value:k,done:A}=await f.read();if(A)break;k&&e.write(k)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{p.abort();try{e.end()}catch{}})}function os(t,e,a){let n=Oe(t);if(!n)return y(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let r=new Z().verify(n);if(!r)return y(e,401,{error:"invalid or revoked token"}),null;for(let o of a)if(!me(r,o))return y(e,403,{error:`token missing scope: ${o}`,scopes:r.scopes}),null;return r}async function ss(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 oe(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 d=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 d.text();e.writeHead(d.status,{"Content-Type":d.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),e.end(p)}catch(d){y(e,502,{error:d.message||"upstream call failed"})}}async function is(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 Re(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let f of u)i.add(f.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){y(t,403,{error:"node not in dashboard allowlist",target:s});return}let l=s===e.config.dashboard.daemonUrl.replace(/\/+$/,"")?e.config.dashboard.token:e.config.dashboard.daemons.find(u=>u.url.replace(/\/+$/,"")===s)?.token,d={Accept:"application/json"};l&&(d.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:d}),f=await u.text();t.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),t.end(f)}catch(u){y(t,502,{error:u.message||"upstream fetch failed"})}}async function ls(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),i=new Set;i.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let u of a.config.dashboard.daemons)i.add(u.url.replace(/\/+$/,""));try{let u=await Re(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let f of u)i.add(f.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){y(e,403,{error:"node not in dashboard allowlist",target:s});return}let l=s===a.config.dashboard.daemonUrl.replace(/\/+$/,"")?a.config.dashboard.token:a.config.dashboard.daemons.find(u=>u.url.replace(/\/+$/,"")===s)?.token,d={"Content-Type":"application/json",Accept:"application/json"};l&&(d.Authorization=`Bearer ${l}`);let p="{}";try{let u=await oe(t);p=u?JSON.stringify(u):"{}"}catch{}try{let u=await fetch(`${s}/api/tasks/${encodeURIComponent(r)}/${o}`,{method:"POST",headers:d,body:p}),f=await u.text();e.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),e.end(f)}catch(u){y(e,502,{error:u.message||"upstream fetch failed"})}}var ds=`
14320
+ `)},o=async()=>{try{let l=await pt(a);r("snapshot",l)}catch(l){r("error",{message:l.message})}};o();let s=setInterval(o,2e3);t.on("close",()=>{n=!0,clearInterval(s),e.end()})}async function Ls(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),l=new Set;l.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let _ of a.config.dashboard.daemons)l.add(_.url.replace(/\/+$/,""));try{let _=await Oe(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let M of _)l.add(M.url.replace(/\/+$/,""))}catch{}if(!l.has(s)){v(e,403,{error:"node not in dashboard allowlist",target:s});return}let i=s===a.config.dashboard.daemonUrl.replace(/\/+$/,"")?a.config.dashboard.token:a.config.dashboard.daemons.find(_=>_.url.replace(/\/+$/,"")===s)?.token,c={Accept:"text/event-stream"};i&&(c.Authorization=`Bearer ${i}`);let u=new AbortController,m;try{m=await fetch(`${s}/agents/${encodeURIComponent(r)}/tasks/${encodeURIComponent(o)}/stream`,{headers:c,signal:u.signal})}catch(_){v(e,502,{error:_.message||"upstream connect failed"});return}if(!m.ok||!m.body){v(e,m.status||502,{error:`upstream HTTP ${m.status}`});return}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*","X-Accel-Buffering":"no"});let x=m.body.getReader();(async()=>{try{for(;;){let{value:_,done:M}=await x.read();if(M)break;_&&e.write(_)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{u.abort();try{e.end()}catch{}})}function Rs(t,e,a){let n=Fe(t);if(!n)return v(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let r=new ee().verify(n);if(!r)return v(e,401,{error:"invalid or revoked token"}),null;for(let o of a)if(!ve(r,o))return v(e,403,{error:`token missing scope: ${o}`,scopes:r.scopes}),null;return r}async function Ps(t,e,a,n){let r=a.agents?.[n];if(!r){v(e,404,{error:"unknown agent"});return}if(r.access!=="public"){v(e,403,{error:"agent is private",hint:`set agents.${n}.access = "public" to expose it`});return}let o;try{o=await re(t)}catch{v(e,400,{error:"invalid JSON body"});return}let s=o?.message;if(!s||typeof s!="string"){v(e,400,{error:"required: { message: string, context?: {...} }"});return}let l=a.dashboard.daemonUrl.replace(/\/+$/,""),i={"Content-Type":"application/json"};a.dashboard.token&&(i.Authorization=`Bearer ${a.dashboard.token}`);try{let c=await fetch(`${l}/task`,{method:"POST",headers:i,body:JSON.stringify({agent:n,message:s,context:{channel:"public-api",sender:o.context?.sender||"api",...o.context||{}}})}),u=await c.text();e.writeHead(c.status,{"Content-Type":c.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),e.end(u)}catch(c){v(e,502,{error:c.message||"upstream call failed"})}}async function Ds(t,e,a,n,r,o){let s=a.replace(/\/+$/,""),l=new Set;l.add(e.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let m of e.config.dashboard.daemons)l.add(m.url.replace(/\/+$/,""));try{let m=await Oe(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let x of m)l.add(x.url.replace(/\/+$/,""))}catch{}if(!l.has(s)){v(t,403,{error:"node not in dashboard allowlist",target:s});return}let i=s===e.config.dashboard.daemonUrl.replace(/\/+$/,"")?e.config.dashboard.token:e.config.dashboard.daemons.find(m=>m.url.replace(/\/+$/,"")===s)?.token,c={Accept:"application/json"};i&&(c.Authorization=`Bearer ${i}`);let u=r?`/agents/${encodeURIComponent(n)}/tasks/${encodeURIComponent(r)}`:`/agents/${encodeURIComponent(n)}/tasks?limit=${encodeURIComponent(o)}`;try{let m=await fetch(`${s}${u}`,{headers:c}),x=await m.text();t.writeHead(m.status,{"Content-Type":m.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),t.end(x)}catch(m){v(t,502,{error:m.message||"upstream fetch failed"})}}async function Os(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),l=new Set;l.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let m of a.config.dashboard.daemons)l.add(m.url.replace(/\/+$/,""));try{let m=await Oe(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let x of m)l.add(x.url.replace(/\/+$/,""))}catch{}if(!l.has(s)){v(e,403,{error:"node not in dashboard allowlist",target:s});return}let i=s===a.config.dashboard.daemonUrl.replace(/\/+$/,"")?a.config.dashboard.token:a.config.dashboard.daemons.find(m=>m.url.replace(/\/+$/,"")===s)?.token,c={"Content-Type":"application/json",Accept:"application/json"};i&&(c.Authorization=`Bearer ${i}`);let u="{}";try{let m=await re(t);u=m?JSON.stringify(m):"{}"}catch{}try{let m=await fetch(`${s}/api/tasks/${encodeURIComponent(r)}/${o}`,{method:"POST",headers:c,body:u}),x=await m.text();e.writeHead(m.status,{"Content-Type":m.headers.get("content-type")||"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),e.end(x)}catch(m){v(e,502,{error:m.message||"upstream fetch failed"})}}var Hs=`
13361
14321
  You are helping draft a new GitLab issue. Follow these conventions strictly.
13362
14322
 
13363
14323
  Title pattern:
@@ -13389,16 +14349,16 @@ Return ONLY a single JSON object on one line \u2014 no prose, no code fences, no
13389
14349
  Shape:
13390
14350
  { "title": string, "description": string, "labels": string[], "assigneeUsername": string | null, "kind": string }
13391
14351
  If you don't have enough information to pick a label confidently, omit it rather than guessing.
13392
- `;async function cs(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):
14352
+ `;async function Ns(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):
13393
14353
  - ${r.knownLabels.slice(0,60).join(`
13394
14354
  - `)}`:"",r.members?.length?`Possible assignees (GitLab usernames): ${r.members.slice(0,20).join(", ")}`:"","","Produce the JSON draft now."].filter(Boolean).join(`
13395
- `),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:ds}})});if(!l.ok)throw new Error(`daemon /task HTTP ${l.status}: ${await l.text().catch(()=>"")}`);let d=await l.json();if(d.error)throw new Error(String(d.error));let p=(d.content||"").toString(),u=ps(p);if(!u||typeof u.title!="string")throw new Error("agent did not return a valid JSON draft. Raw: "+p.slice(0,400));let f=Array.isArray(u.labels)?u.labels.filter(v=>typeof v=="string"):[];return r.primaryLabel&&!f.includes(r.primaryLabel)&&f.unshift(r.primaryLabel),r.columnLabel&&!f.includes(r.columnLabel)&&f.unshift(r.columnLabel),{title:u.title.trim(),description:(u.description||"").toString(),labels:f,assigneeUsername:typeof u.assigneeUsername=="string"?u.assigneeUsername:void 0,kind:typeof u.kind=="string"?u.kind:void 0,raw:p}}function ps(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 us(t){let e=Xo(Go(import.meta.url));return xe(e,t)}async function ms(t){return Wo(t)}function y(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function oe(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 Wa(t){return t.dashboardUrl?t.dashboardUrl.replace(/\/+$/,""):t.url.replace(/\/+$/,"").replace(/:(?:1[89][89]00|18810)$/,":4202")}function H(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:Wa(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 hs(t,e,a){let n=new URL(t.url||"/","http://_"),r=parseInt(n.searchParams.get("hours")||"6",10)||6,o=a.config.node?.id||a.config.node?.name||"local",s=[],i=pa(r);i&&s.push({nodeId:o,snap:i});let l=(a.config.dashboard?.daemons||[]).filter(d=>d.url);await Promise.all(l.map(async d=>{let p=tt(d.url.replace(/\/+$/,""),a.config);if(p)try{let u=new AbortController,f=setTimeout(()=>u.abort(),8e3);try{let v=await fetch(`${p.url}/api/admin/activity-graph?hours=${r}`,{headers:{Accept:"application/json","X-Agentx-Peer":"primary",...p.token?{Authorization:`Bearer ${p.token}`}:{}},signal:u.signal});if(!v.ok)return;let k=await v.json();s.push({nodeId:d.name||d.url,snap:k})}finally{clearTimeout(f)}}catch{}})),y(e,200,ua(s))}async function gs(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||"",f=[u&&`${u}/.agentx/logs/daemon-stdout.log`,"/tmp/agentx-daemon.log"].filter(Boolean),v=f.find(k=>Fa(k));if(!v){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:f}));return}r="tail",o=["-F","-n","200",v]}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}
14355
+ `),s=t.dashboard.daemonUrl.replace(/\/+$/,"")+"/task",l={"Content-Type":"application/json"};t.dashboard.token&&(l.Authorization=`Bearer ${t.dashboard.token}`);let i=await fetch(s,{method:"POST",headers:l,body:JSON.stringify({agent:n,message:o,context:{channel:"a2a",sender:"board-dashboard",systemPrompt:Hs}})});if(!i.ok)throw new Error(`daemon /task HTTP ${i.status}: ${await i.text().catch(()=>"")}`);let c=await i.json();if(c.error)throw new Error(String(c.error));let u=(c.content||"").toString(),m=Bs(u);if(!m||typeof m.title!="string")throw new Error("agent did not return a valid JSON draft. Raw: "+u.slice(0,400));let x=Array.isArray(m.labels)?m.labels.filter(b=>typeof b=="string"):[];return r.primaryLabel&&!x.includes(r.primaryLabel)&&x.unshift(r.primaryLabel),r.columnLabel&&!x.includes(r.columnLabel)&&x.unshift(r.columnLabel),{title:m.title.trim(),description:(m.description||"").toString(),labels:x,assigneeUsername:typeof m.assigneeUsername=="string"?m.assigneeUsername:void 0,kind:typeof m.kind=="string"?m.kind:void 0,raw:u}}function Bs(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 zs(t){let e=ks(ws(import.meta.url));return ke(e,t)}async function qs(t){return ys(t)}function v(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function re(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 sn(t){return t.dashboardUrl?t.dashboardUrl.replace(/\/+$/,""):t.url.replace(/\/+$/,"").replace(/:(?:1[89][89]00|18810)$/,":4202")}function O(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:sn(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 Us(t,e,a){let n=new URL(t.url||"/","http://_"),r=parseInt(n.searchParams.get("hours")||"6",10)||6,o=a.config.node?.id||a.config.node?.name||"local",s=[],l=Ta(r);l&&s.push({nodeId:o,snap:l});let i=(a.config.dashboard?.daemons||[]).filter(c=>c.url);await Promise.all(i.map(async c=>{let u=ut(c.url.replace(/\/+$/,""),a.config);if(u)try{let m=new AbortController,x=setTimeout(()=>m.abort(),8e3);try{let b=await fetch(`${u.url}/api/admin/activity-graph?hours=${r}`,{headers:{Accept:"application/json","X-Agentx-Peer":"primary",...u.token?{Authorization:`Bearer ${u.token}`}:{}},signal:m.signal});if(!b.ok)return;let _=await b.json();s.push({nodeId:c.name||c.url,snap:_})}finally{clearTimeout(x)}}catch{}})),v(e,200,Ca(s))}async function Fs(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 m=process.env.HOME||"",x=[m&&`${m}/.agentx/logs/daemon-stdout.log`,"/tmp/agentx-daemon.log"].filter(Boolean),b=x.find(_=>on(_));if(!b){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:x}));return}r="tail",o=["-F","-n","200",b]}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}
13396
14356
 
13397
- `);let s=a(r,o,{stdio:["ignore","pipe","pipe"]}),i="",l=u=>{i+=u.toString("utf8");let f;for(;(f=i.indexOf(`
13398
- `))>=0;){let v=i.slice(0,f).replace(/\r$/,"");i=i.slice(f+1);try{e.write(`event: line
13399
- data: ${v.replace(/\n/g," ")}
14357
+ `);let s=a(r,o,{stdio:["ignore","pipe","pipe"]}),l="",i=m=>{l+=m.toString("utf8");let x;for(;(x=l.indexOf(`
14358
+ `))>=0;){let b=l.slice(0,x).replace(/\r$/,"");l=l.slice(x+1);try{e.write(`event: line
14359
+ data: ${b.replace(/\n/g," ")}
13400
14360
 
13401
- `)}catch{}}};s.stdout?.on("data",l),s.stderr?.on("data",l);let d=setInterval(()=>{try{e.write(`: hb
14361
+ `)}catch{}}};s.stdout?.on("data",i),s.stderr?.on("data",i);let c=setInterval(()=>{try{e.write(`: hb
13402
14362
 
13403
- `)}catch{}},15e3),p=()=>{clearInterval(d);try{s.kill()}catch{}try{e.end()}catch{}};t.on("close",p),s.on("exit",p),s.on("error",p)}async function Ua(t,e,a,n){let r=a.url+n,o=(t.method||"GET").toUpperCase(),i=o!=="GET"&&o!=="HEAD"?await new Promise((u,f)=>{let v=[];t.on("data",k=>v.push(k)),t.on("end",()=>u(Buffer.concat(v))),t.on("error",f)}):void 0,l={},d=t.headers["content-type"];d&&(l["Content-Type"]=Array.isArray(d)?d[0]:d);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}),f=Buffer.from(await u.arrayBuffer());e.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json","Cache-Control":"no-store","Access-Control-Allow-Origin":"*"}),e.end(f)}catch(u){y(e,502,{error:`proxy to peer failed: ${u?.message||u}`,target:r})}}function tt(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(r=>r.url.replace(/\/+$/,"")===a);return n?{url:Wa(n),token:n.dashboardToken||n.token}:null}export{Rl as startBoardDashboard};
13404
- //# sourceMappingURL=board-dashboard-M3372FLO.js.map
14363
+ `)}catch{}},15e3),u=()=>{clearInterval(c);try{s.kill()}catch{}try{e.end()}catch{}};t.on("close",u),s.on("exit",u),s.on("error",u)}async function rn(t,e,a,n){let r=a.url+n,o=(t.method||"GET").toUpperCase(),l=o!=="GET"&&o!=="HEAD"?await new Promise((m,x)=>{let b=[];t.on("data",_=>b.push(_)),t.on("end",()=>m(Buffer.concat(b))),t.on("error",x)}):void 0,i={},c=t.headers["content-type"];c&&(i["Content-Type"]=Array.isArray(c)?c[0]:c);let u=t.headers["x-requested-with"];u&&(i["X-Requested-With"]=Array.isArray(u)?u[0]:u),a.token&&(i.Authorization=`Bearer ${a.token}`),i["X-Agentx-Peer"]="primary";try{let m=await fetch(r,{method:o,headers:i,body:l&&l.length>0?l:void 0}),x=Buffer.from(await m.arrayBuffer());e.writeHead(m.status,{"Content-Type":m.headers.get("content-type")||"application/json","Cache-Control":"no-store","Access-Control-Allow-Origin":"*"}),e.end(x)}catch(m){v(e,502,{error:`proxy to peer failed: ${m?.message||m}`,target:r})}}function ut(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(r=>r.url.replace(/\/+$/,"")===a);return n?{url:sn(n),token:n.dashboardToken||n.token}:null}export{Rd as startBoardDashboard};
14364
+ //# sourceMappingURL=board-dashboard-TTMAYRLG.js.map