agentix-cli 0.26.0 → 0.28.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 (300) hide show
  1. package/README.md +67 -118
  2. package/apps/mac-helper/Sources/AgentXHelper/AXTree.swift +159 -0
  3. package/apps/mac-helper/Sources/AgentXHelper/Brand.swift +63 -0
  4. package/apps/mac-helper/Sources/AgentXHelper/Focus.swift +97 -0
  5. package/apps/mac-helper/Sources/AgentXHelper/HUD.swift +179 -0
  6. package/apps/mac-helper/Sources/AgentXHelper/OCR.swift +117 -0
  7. package/apps/mac-helper/Sources/AgentXHelper/Pointer.swift +309 -0
  8. package/apps/mac-helper/Sources/AgentXHelper/Screens.swift +67 -0
  9. package/apps/mac-helper/Sources/AgentXHelper/Typer.swift +185 -0
  10. package/apps/mac-helper/Sources/AgentXHelper/Vision.swift +201 -0
  11. package/apps/mac-helper/Sources/AgentXHelper/main.swift +265 -0
  12. package/apps/mac-helper/build.sh +39 -0
  13. package/apps/mac-voice/Resources/Info.plist +18 -0
  14. package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +108 -0
  15. package/apps/mac-voice/Sources/AgentXVoice/Brand.swift +123 -0
  16. package/apps/mac-voice/Sources/AgentXVoice/Config.swift +68 -0
  17. package/apps/mac-voice/Sources/AgentXVoice/Hold.swift +74 -0
  18. package/apps/mac-voice/Sources/AgentXVoice/Hotkey.swift +76 -0
  19. package/apps/mac-voice/Sources/AgentXVoice/Markdown.swift +140 -0
  20. package/apps/mac-voice/Sources/AgentXVoice/Panel.swift +275 -0
  21. package/apps/mac-voice/Sources/AgentXVoice/Progress.swift +147 -0
  22. package/apps/mac-voice/Sources/AgentXVoice/Recorder.swift +139 -0
  23. package/apps/mac-voice/Sources/AgentXVoice/ResultCard.swift +162 -0
  24. package/apps/mac-voice/Sources/AgentXVoice/SmartPaste.swift +72 -0
  25. package/apps/mac-voice/Sources/AgentXVoice/Speech.swift +192 -0
  26. package/apps/mac-voice/Sources/AgentXVoice/StepLabel.swift +159 -0
  27. package/apps/mac-voice/Sources/AgentXVoice/main.swift +380 -0
  28. package/apps/mac-voice/build.sh +32 -0
  29. package/dist/{App-BPNHIGUX.js → App-CKPH3HHF.js} +2 -2
  30. package/dist/{ChatApp-6XSSZB4U.js → ChatApp-MX7IG4K2.js} +2 -2
  31. package/dist/agent-2U574KBZ.js +2 -0
  32. package/dist/article-fields-L4D2BOGY.js +2 -0
  33. package/dist/article-quality-44ONVGLN.js +3 -0
  34. package/dist/article-quality-44ONVGLN.js.map +1 -0
  35. package/dist/{audit-JU3HWISB.js → audit-4245CX6P.js} +2 -2
  36. package/dist/backfill-MTD2B62I.js +6 -0
  37. package/dist/backfill-MTD2B62I.js.map +1 -0
  38. package/dist/{board-dashboard-M3372FLO.js → board-dashboard-QR7CVTKA.js} +1411 -453
  39. package/dist/board-dashboard-QR7CVTKA.js.map +1 -0
  40. package/dist/{builtin-FRKAQMFS.js → builtin-B67DMJ3M.js} +2 -2
  41. package/dist/calibration-ILS5OI44.js +2 -0
  42. package/dist/{chunk-V3U4OF7L.js → chunk-3LYM22IV.js} +46 -48
  43. package/dist/chunk-3LYM22IV.js.map +1 -0
  44. package/dist/chunk-3SCPRYJB.js +5 -0
  45. package/dist/chunk-3SCPRYJB.js.map +1 -0
  46. package/dist/chunk-4BR7D2OU.js +36 -0
  47. package/dist/chunk-4BR7D2OU.js.map +1 -0
  48. package/dist/{chunk-P4VWIVKN.js → chunk-52ZPELD2.js} +403 -29
  49. package/dist/chunk-52ZPELD2.js.map +1 -0
  50. package/dist/chunk-5IA2CYHN.js +5 -0
  51. package/dist/{chunk-O6YPEOQF.js.map → chunk-5IA2CYHN.js.map} +1 -1
  52. package/dist/chunk-64CAIB3C.js +9 -0
  53. package/dist/chunk-64CAIB3C.js.map +1 -0
  54. package/dist/{chunk-5U35WAZF.js → chunk-77OV7346.js} +6 -6
  55. package/dist/chunk-77OV7346.js.map +1 -0
  56. package/dist/chunk-AJ5RMU7X.js +2 -0
  57. package/dist/chunk-AJ5RMU7X.js.map +1 -0
  58. package/dist/chunk-AJONZWLT.js +2 -0
  59. package/dist/chunk-AJONZWLT.js.map +1 -0
  60. package/dist/chunk-BH3GTCZ6.js +2 -0
  61. package/dist/chunk-BH3GTCZ6.js.map +1 -0
  62. package/dist/chunk-E3UJHQGN.js +1189 -0
  63. package/dist/chunk-E3UJHQGN.js.map +1 -0
  64. package/dist/chunk-EVWEG3VD.js +3 -0
  65. package/dist/chunk-EVWEG3VD.js.map +1 -0
  66. package/dist/chunk-F4HZTZHW.js +2 -0
  67. package/dist/chunk-F4HZTZHW.js.map +1 -0
  68. package/dist/chunk-F6CNF7V3.js +25 -0
  69. package/dist/chunk-F6CNF7V3.js.map +1 -0
  70. package/dist/chunk-FIOB3MEX.js +2 -0
  71. package/dist/{chunk-H5D7ATXS.js → chunk-FKBGJYWQ.js} +5 -5
  72. package/dist/chunk-FKBGJYWQ.js.map +1 -0
  73. package/dist/{chunk-BVGJSPW4.js → chunk-G2HMRDUQ.js} +7 -7
  74. package/dist/chunk-G2HMRDUQ.js.map +1 -0
  75. package/dist/chunk-H2QQU2XV.js +109 -0
  76. package/dist/chunk-H2QQU2XV.js.map +1 -0
  77. package/dist/{chunk-LDHPMJ7M.js → chunk-IWMW5432.js} +3 -3
  78. package/dist/chunk-IWMW5432.js.map +1 -0
  79. package/dist/chunk-K33GIBSE.js +2 -0
  80. package/dist/chunk-K33GIBSE.js.map +1 -0
  81. package/dist/chunk-L2WSPY6S.js +2 -0
  82. package/dist/chunk-L2WSPY6S.js.map +1 -0
  83. package/dist/chunk-LCIREYTD.js +54 -0
  84. package/dist/chunk-LCIREYTD.js.map +1 -0
  85. package/dist/chunk-MHIMGM4G.js +126 -0
  86. package/dist/chunk-MHIMGM4G.js.map +1 -0
  87. package/dist/chunk-P5ZBBEPL.js +13 -0
  88. package/dist/chunk-P5ZBBEPL.js.map +1 -0
  89. package/dist/{chunk-JTJIPNXY.js → chunk-PNWNVOEZ.js} +1 -1
  90. package/dist/chunk-PNWNVOEZ.js.map +1 -0
  91. package/dist/chunk-QHTQPBHU.js +45 -0
  92. package/dist/chunk-QHTQPBHU.js.map +1 -0
  93. package/dist/chunk-S2MNL5V6.js +2 -0
  94. package/dist/chunk-S2MNL5V6.js.map +1 -0
  95. package/dist/chunk-SCTIUFL4.js +5 -0
  96. package/dist/{chunk-K2CAPYES.js.map → chunk-SCTIUFL4.js.map} +1 -1
  97. package/dist/chunk-ULLAE6LE.js +157 -0
  98. package/dist/chunk-ULLAE6LE.js.map +1 -0
  99. package/dist/{chunk-DJEZ2HVU.js → chunk-VDMYBPYB.js} +1 -1
  100. package/dist/chunk-VDMYBPYB.js.map +1 -0
  101. package/dist/chunk-VIH7ARPF.js +547 -0
  102. package/dist/chunk-VIH7ARPF.js.map +1 -0
  103. package/dist/chunk-W5C2GDNC.js +32 -0
  104. package/dist/{chunk-JP5IEXR7.js.map → chunk-W5C2GDNC.js.map} +1 -1
  105. package/dist/chunk-WPMX3VGI.js +3 -0
  106. package/dist/chunk-WPMX3VGI.js.map +1 -0
  107. package/dist/chunk-YLBERT7N.js +24 -0
  108. package/dist/chunk-YLBERT7N.js.map +1 -0
  109. package/dist/chunk-YLGIZRHV.js +114 -0
  110. package/dist/chunk-YLGIZRHV.js.map +1 -0
  111. package/dist/chunk-ZMYGXHPT.js +121 -0
  112. package/dist/chunk-ZMYGXHPT.js.map +1 -0
  113. package/dist/chunk-ZTEU5JVQ.js +2 -0
  114. package/dist/chunk-ZTEU5JVQ.js.map +1 -0
  115. package/dist/{chunk-2WVX3LEC.js → chunk-ZVP6GB4G.js} +1 -1
  116. package/dist/chunk-ZVP6GB4G.js.map +1 -0
  117. package/dist/cli.js +1 -1
  118. package/dist/cli.js.map +1 -1
  119. package/dist/client-ZLSXGPTV.js +2 -0
  120. package/dist/{compaction-NWEMOSHA.js → compaction-FD4R23HZ.js} +4 -4
  121. package/dist/config-HMW3EBZL.js +2 -0
  122. package/dist/config-mutator-4SZ5YEVD.js +2 -0
  123. package/dist/{conflict-detector-D7VIYPDI.js → conflict-detector-ZPOT3M2C.js} +2 -2
  124. package/dist/conflict-detector-ZPOT3M2C.js.map +1 -0
  125. package/dist/context-planner-AQHJMVY2.js +17 -0
  126. package/dist/context-planner-AQHJMVY2.js.map +1 -0
  127. package/dist/debug-3MEUO2P2.js +2 -0
  128. package/dist/{discover-XJXQXXIO.js → discover-D4VVRNAI.js} +2 -2
  129. package/dist/discover-D4VVRNAI.js.map +1 -0
  130. package/dist/doctor-LRYV3QLK.js +2 -0
  131. package/dist/editor-chat-OB7IQOB5.js +137 -0
  132. package/dist/editor-chat-OB7IQOB5.js.map +1 -0
  133. package/dist/entry-triage-LK34TSQD.js +2 -0
  134. package/dist/entry-triage-LK34TSQD.js.map +1 -0
  135. package/dist/facts-YVEJOM7O.js +22 -0
  136. package/dist/facts-YVEJOM7O.js.map +1 -0
  137. package/dist/heal-FVLBHYP7.js +2 -0
  138. package/dist/index.d.ts +1040 -64
  139. package/dist/index.js +12 -19
  140. package/dist/index.js.map +1 -1
  141. package/dist/{ingest-whatsapp-LZE62INA.js → ingest-whatsapp-NS4OWDOU.js} +2 -2
  142. package/dist/loader-4ZGTK7LD.js +2 -0
  143. package/dist/loader-BOKE5M5S.js +2 -0
  144. package/dist/memory-extract-F5ZHWY5E.js +2 -0
  145. package/dist/{migrate-v2-QO7SLKIM.js → migrate-v2-V4WN2VVM.js} +2 -2
  146. package/dist/ntfy-X7EPB3TG.js +4 -0
  147. package/dist/ntfy-X7EPB3TG.js.map +1 -0
  148. package/dist/processes-WU23U2OJ.js +2 -0
  149. package/dist/program-GSZ5AYAM.js +2 -0
  150. package/dist/{projects-api-KRME2YKZ.js → projects-api-QE6L65SK.js} +2 -2
  151. package/dist/{projects-mutate-3NHVG437.js → projects-mutate-MY7JTLSZ.js} +2 -2
  152. package/dist/providers-KO2DODIO.js +2 -0
  153. package/dist/query-SQDHE4HV.js +2 -0
  154. package/dist/questions-4B4KSPXG.js +3 -0
  155. package/dist/questions-4B4KSPXG.js.map +1 -0
  156. package/dist/recipes-7S4MC5OJ.js +2 -0
  157. package/dist/registry-LE6FWYZC.js +2 -0
  158. package/dist/review-candidates-RQU5KNZM.js +4 -0
  159. package/dist/review-candidates-RQU5KNZM.js.map +1 -0
  160. package/dist/review-store-B4YE3EFK.js +4 -0
  161. package/dist/review-store-B4YE3EFK.js.map +1 -0
  162. package/dist/{rotation-memo-B3EXXSEH.js → rotation-memo-7T75BLEX.js} +2 -2
  163. package/dist/routing-ILERJXB6.js +2 -0
  164. package/dist/runner-YRBVNYTY.js +2 -0
  165. package/dist/scheduler-BFM3EINS.js +2 -0
  166. package/dist/seat-7WM7II2B.js +2 -0
  167. package/dist/select-X4KVMOP5.js +2 -0
  168. package/dist/select-X4KVMOP5.js.map +1 -0
  169. package/dist/store-MCOA6N4F.js +2 -0
  170. package/dist/{subagent-WV7QKQ3L.js → subagent-2SJHSSJS.js} +2 -2
  171. package/dist/{surface-usage-PRL6Z4U3.js → surface-usage-NS74AXSE.js} +2 -2
  172. package/dist/timers-PCB4ZIBD.js +2 -0
  173. package/dist/triage-backtest-JNO7RKX7.js +2 -0
  174. package/dist/triage-backtest-JNO7RKX7.js.map +1 -0
  175. package/dist/types-H5ENIUIT.js +2 -0
  176. package/dist/types-OIFU3KSQ.js +2 -0
  177. package/dist/types-OIFU3KSQ.js.map +1 -0
  178. package/dist/web/workflow-editor.global.js +1542 -0
  179. package/dist/web/workflow-editor.global.js.map +1 -0
  180. package/dist/{whatsapp-state-XMTCSRXU.js → whatsapp-state-6D6FHHD2.js} +2 -2
  181. package/dist/wiki-2AUFSIKO.js +2 -0
  182. package/dist/wiki-2AUFSIKO.js.map +1 -0
  183. package/dist/workflows/templates/branching.yaml +1 -1
  184. package/dist/{workspace-setup-TBQAHYHJ.js → workspace-setup-B3F3TUDE.js} +2 -2
  185. package/dist/workspace-setup-B3F3TUDE.js.map +1 -0
  186. package/package.json +14 -3
  187. package/scripts/postinstall.mjs +80 -0
  188. package/dist/agent-5QMITZT6.js +0 -2
  189. package/dist/architect-SEPWMWS4.js +0 -2
  190. package/dist/board-dashboard-M3372FLO.js.map +0 -1
  191. package/dist/chunk-2WVX3LEC.js.map +0 -1
  192. package/dist/chunk-3WQFCIB6.js +0 -24
  193. package/dist/chunk-3WQFCIB6.js.map +0 -1
  194. package/dist/chunk-4YCH6IZV.js +0 -2
  195. package/dist/chunk-53NRX2NA.js +0 -2
  196. package/dist/chunk-53NRX2NA.js.map +0 -1
  197. package/dist/chunk-5U35WAZF.js.map +0 -1
  198. package/dist/chunk-BFXONUUN.js +0 -108
  199. package/dist/chunk-BFXONUUN.js.map +0 -1
  200. package/dist/chunk-BFZUG66X.js +0 -45
  201. package/dist/chunk-BFZUG66X.js.map +0 -1
  202. package/dist/chunk-BTHHSY7D.js +0 -13
  203. package/dist/chunk-BTHHSY7D.js.map +0 -1
  204. package/dist/chunk-BVGJSPW4.js.map +0 -1
  205. package/dist/chunk-D46VZ7K7.js +0 -116
  206. package/dist/chunk-D46VZ7K7.js.map +0 -1
  207. package/dist/chunk-DJEZ2HVU.js.map +0 -1
  208. package/dist/chunk-E5CXCI33.js +0 -155
  209. package/dist/chunk-E5CXCI33.js.map +0 -1
  210. package/dist/chunk-FDWOECJY.js +0 -54
  211. package/dist/chunk-FDWOECJY.js.map +0 -1
  212. package/dist/chunk-H5D7ATXS.js.map +0 -1
  213. package/dist/chunk-HR4JSRZS.js +0 -3
  214. package/dist/chunk-HR4JSRZS.js.map +0 -1
  215. package/dist/chunk-ISEBLHWX.js +0 -118
  216. package/dist/chunk-ISEBLHWX.js.map +0 -1
  217. package/dist/chunk-JP5IEXR7.js +0 -32
  218. package/dist/chunk-JTJIPNXY.js.map +0 -1
  219. package/dist/chunk-K2CAPYES.js +0 -5
  220. package/dist/chunk-LDHPMJ7M.js.map +0 -1
  221. package/dist/chunk-METYYZKQ.js +0 -1115
  222. package/dist/chunk-METYYZKQ.js.map +0 -1
  223. package/dist/chunk-MTAPOCGA.js +0 -47
  224. package/dist/chunk-MTAPOCGA.js.map +0 -1
  225. package/dist/chunk-O6YPEOQF.js +0 -5
  226. package/dist/chunk-P4VWIVKN.js.map +0 -1
  227. package/dist/chunk-SR3X25TN.js +0 -3
  228. package/dist/chunk-SR3X25TN.js.map +0 -1
  229. package/dist/chunk-UHE5FCPB.js +0 -431
  230. package/dist/chunk-UHE5FCPB.js.map +0 -1
  231. package/dist/chunk-V3U4OF7L.js.map +0 -1
  232. package/dist/chunk-VJUTQAPJ.js +0 -2
  233. package/dist/chunk-VJUTQAPJ.js.map +0 -1
  234. package/dist/chunk-VT5XYFDD.js +0 -126
  235. package/dist/chunk-VT5XYFDD.js.map +0 -1
  236. package/dist/client-HGKAC6VP.js +0 -2
  237. package/dist/config-A4RWEJHV.js +0 -2
  238. package/dist/config-mutator-MNSFUN7D.js +0 -2
  239. package/dist/conflict-detector-D7VIYPDI.js.map +0 -1
  240. package/dist/context-planner-45GEWKGL.js +0 -17
  241. package/dist/context-planner-45GEWKGL.js.map +0 -1
  242. package/dist/debug-N3B5NVJU.js +0 -2
  243. package/dist/discover-XJXQXXIO.js.map +0 -1
  244. package/dist/doctor-3Q36ZFE6.js +0 -2
  245. package/dist/heal-HZ3EQD52.js +0 -2
  246. package/dist/loader-5CA3O5GM.js +0 -2
  247. package/dist/loader-6IHUCPVO.js +0 -2
  248. package/dist/memory-extract-AENFVVO5.js +0 -2
  249. package/dist/processes-UIC4XXA6.js +0 -2
  250. package/dist/program-SAUNRCCD.js +0 -2
  251. package/dist/providers-L27BJ5A6.js +0 -2
  252. package/dist/query-HZYYRCLU.js +0 -2
  253. package/dist/recipes-EPLE2SNT.js +0 -2
  254. package/dist/registry-HK3WQ7BS.js +0 -2
  255. package/dist/runner-BFYDWPUO.js +0 -2
  256. package/dist/scheduler-6T2SU5ST.js +0 -2
  257. package/dist/store-I3HEWVLQ.js +0 -2
  258. package/dist/timers-5LPZN55J.js +0 -2
  259. package/dist/types-VECTMYTO.js +0 -2
  260. package/dist/types-Y6ZCZ52Z.js +0 -2
  261. package/dist/wiki-M6YNRFC4.js +0 -2
  262. /package/dist/{App-BPNHIGUX.js.map → App-CKPH3HHF.js.map} +0 -0
  263. /package/dist/{ChatApp-6XSSZB4U.js.map → ChatApp-MX7IG4K2.js.map} +0 -0
  264. /package/dist/{agent-5QMITZT6.js.map → agent-2U574KBZ.js.map} +0 -0
  265. /package/dist/{architect-SEPWMWS4.js.map → article-fields-L4D2BOGY.js.map} +0 -0
  266. /package/dist/{audit-JU3HWISB.js.map → audit-4245CX6P.js.map} +0 -0
  267. /package/dist/{builtin-FRKAQMFS.js.map → builtin-B67DMJ3M.js.map} +0 -0
  268. /package/dist/{chunk-4YCH6IZV.js.map → calibration-ILS5OI44.js.map} +0 -0
  269. /package/dist/{client-HGKAC6VP.js.map → chunk-FIOB3MEX.js.map} +0 -0
  270. /package/dist/{config-A4RWEJHV.js.map → client-ZLSXGPTV.js.map} +0 -0
  271. /package/dist/{compaction-NWEMOSHA.js.map → compaction-FD4R23HZ.js.map} +0 -0
  272. /package/dist/{config-mutator-MNSFUN7D.js.map → config-HMW3EBZL.js.map} +0 -0
  273. /package/dist/{debug-N3B5NVJU.js.map → config-mutator-4SZ5YEVD.js.map} +0 -0
  274. /package/dist/{doctor-3Q36ZFE6.js.map → debug-3MEUO2P2.js.map} +0 -0
  275. /package/dist/{heal-HZ3EQD52.js.map → doctor-LRYV3QLK.js.map} +0 -0
  276. /package/dist/{loader-5CA3O5GM.js.map → heal-FVLBHYP7.js.map} +0 -0
  277. /package/dist/{ingest-whatsapp-LZE62INA.js.map → ingest-whatsapp-NS4OWDOU.js.map} +0 -0
  278. /package/dist/{loader-6IHUCPVO.js.map → loader-4ZGTK7LD.js.map} +0 -0
  279. /package/dist/{memory-extract-AENFVVO5.js.map → loader-BOKE5M5S.js.map} +0 -0
  280. /package/dist/{processes-UIC4XXA6.js.map → memory-extract-F5ZHWY5E.js.map} +0 -0
  281. /package/dist/{migrate-v2-QO7SLKIM.js.map → migrate-v2-V4WN2VVM.js.map} +0 -0
  282. /package/dist/{program-SAUNRCCD.js.map → processes-WU23U2OJ.js.map} +0 -0
  283. /package/dist/{providers-L27BJ5A6.js.map → program-GSZ5AYAM.js.map} +0 -0
  284. /package/dist/{projects-api-KRME2YKZ.js.map → projects-api-QE6L65SK.js.map} +0 -0
  285. /package/dist/{projects-mutate-3NHVG437.js.map → projects-mutate-MY7JTLSZ.js.map} +0 -0
  286. /package/dist/{query-HZYYRCLU.js.map → providers-KO2DODIO.js.map} +0 -0
  287. /package/dist/{recipes-EPLE2SNT.js.map → query-SQDHE4HV.js.map} +0 -0
  288. /package/dist/{registry-HK3WQ7BS.js.map → recipes-7S4MC5OJ.js.map} +0 -0
  289. /package/dist/{runner-BFYDWPUO.js.map → registry-LE6FWYZC.js.map} +0 -0
  290. /package/dist/{rotation-memo-B3EXXSEH.js.map → rotation-memo-7T75BLEX.js.map} +0 -0
  291. /package/dist/{scheduler-6T2SU5ST.js.map → routing-ILERJXB6.js.map} +0 -0
  292. /package/dist/{store-I3HEWVLQ.js.map → runner-YRBVNYTY.js.map} +0 -0
  293. /package/dist/{surface-usage-PRL6Z4U3.js.map → scheduler-BFM3EINS.js.map} +0 -0
  294. /package/dist/{timers-5LPZN55J.js.map → seat-7WM7II2B.js.map} +0 -0
  295. /package/dist/{types-VECTMYTO.js.map → store-MCOA6N4F.js.map} +0 -0
  296. /package/dist/{subagent-WV7QKQ3L.js.map → subagent-2SJHSSJS.js.map} +0 -0
  297. /package/dist/{types-Y6ZCZ52Z.js.map → surface-usage-NS74AXSE.js.map} +0 -0
  298. /package/dist/{wiki-M6YNRFC4.js.map → timers-PCB4ZIBD.js.map} +0 -0
  299. /package/dist/{workspace-setup-TBQAHYHJ.js.map → types-H5ENIUIT.js.map} +0 -0
  300. /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-3LYM22IV.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-YLBERT7N.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-64CAIB3C.js";import"./chunk-M4AMWP3H.js";import"./chunk-4BR7D2OU.js";import"./chunk-AFRHKA7B.js";import"./chunk-ZMYGXHPT.js";import"./chunk-SCTIUFL4.js";import{b as gt}from"./chunk-H2QQU2XV.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-AJ5RMU7X.js";import"./chunk-EVWEG3VD.js";import"./chunk-YLGIZRHV.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-P5ZBBEPL.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() {
@@ -13,7 +1025,7 @@ ${Qa}</script>`})}var Ka=`
13
1025
  const cfg = await r.json();
14
1026
  const agents = Object.keys(cfg.agents || {});
15
1027
  const channels = cfg.channels || {};
16
- const channelDefs = ['telegram','whatsapp','slack','discord','gitlab','github'];
1028
+ const channelDefs = ['telegram','whatsapp','gitlab','github'];
17
1029
  const enabled = channelDefs.filter(c => channels[c] && channels[c].enabled).length;
18
1030
  const crons = Object.keys(cfg.crons || {}).length;
19
1031
  const webhooks = Object.keys(cfg.webhooks || {}).length;
@@ -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,15 +1241,15 @@ ${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."})}
233
- ${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.`})}
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."})}
1245
+ ${X({persistKey:"channels",bodyHtml:"<b>How does this work?</b> Connect Telegram with a bot token or pair WhatsApp with a QR code. For webhook sources (GitHub, GitLab), use the URL shown in setup. Slack and Discord adapters are not supported in this build."})}
234
1246
 
235
1247
  <details class="add-form" style="margin-top:14px;margin-bottom:18px" id="notif-section">
236
1248
  <summary class="primary">\u2699 Notifications routing</summary>
237
1249
  <div style="margin-top:10px">
238
1250
  <p style="font-size:11px;color:var(--ax-muted);margin:0 0 10px">Where AgentX pings you when a task finishes, errors, or runs long. Mirrors <code>agentx notifications</code>.</p>
239
1251
  <div id="notif-current" style="font-size:12px;margin-bottom:10px;padding:8px 10px;background:var(--ax-surface);border-radius:4px;color:var(--ax-muted)">\u2014</div>
240
- <label>Channel<span class="hint">(telegram | whatsapp | slack | discord \u2014 leave blank to clear)</span></label>
1252
+ <label>Channel<span class="hint">(telegram | whatsapp \u2014 leave blank to clear)</span></label>
241
1253
  <input id="notif-channel" placeholder="telegram" />
242
1254
  <label>Chat id</label>
243
1255
  <input id="notif-chat-id" placeholder="-1001234567890" />
@@ -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,36 +1469,58 @@ ${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>
473
1507
  <details class="add-form" style="margin-top:10px">
474
1508
  <summary class="primary">+ Add contact mapping</summary>
475
1509
  <div style="margin-top:10px">
476
- <label>Channel <span class="hint">(telegram | whatsapp | slack | discord \u2014 optional)</span></label>
1510
+ <label>Channel <span class="hint">(telegram | whatsapp \u2014 optional)</span></label>
477
1511
  <input id="bc-channel" placeholder="telegram" />
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" />' +
@@ -1977,8 +3064,6 @@ function renderChannels() {
1977
3064
  const CHANNEL_DEFS = [
1978
3065
  { id: 'telegram', icon: 'TG', label: 'Telegram' },
1979
3066
  { id: 'whatsapp', icon: 'WA', label: 'WhatsApp' },
1980
- { id: 'slack', icon: 'SL', label: 'Slack' },
1981
- { id: 'discord', icon: 'DC', label: 'Discord' },
1982
3067
  { id: 'gitlab', icon: 'GL', label: 'GitLab' },
1983
3068
  { id: 'github', icon: 'GH', label: 'GitHub' },
1984
3069
  { id: 'webrtc', icon: '\u260E', label: 'Calls (WebRTC)' },
@@ -3501,11 +4586,11 @@ for (const btn of document.querySelectorAll('nav.tabs button')) {
3501
4586
  })();
3502
4587
 
3503
4588
  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}
4589
+ `;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
4590
 
3506
4591
  ${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>
4592
+ `)}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-BFM3EINS.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)+`
4593
+ `,"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
4594
 
3510
4595
  <div id="disabled-banner" class="banner warn" style="display:none">
3511
4596
  <b>Graph is disabled.</b> Set <code class="mono">graph.enabled: true</code>
@@ -3535,7 +4620,7 @@ ${s||"You are "+a+"."}
3535
4620
  <summary>Add node</summary>
3536
4621
  <div class="row" style="margin-top:10px">
3537
4622
  <select id="n-level"></select>
3538
- <input id="n-id" placeholder="node id (e.g. noqta-devops)" />
4623
+ <input id="n-id" placeholder="node id (e.g. acme-devops)" />
3539
4624
  <select id="n-parent"><option value="">\u2014 no parent \u2014</option></select>
3540
4625
  </div>
3541
4626
  <div class="row" style="margin-top:6px">
@@ -3560,7 +4645,7 @@ ${s||"You are "+a+"."}
3560
4645
  <h2>Recent classifications</h2>
3561
4646
  <p class="muted">Last 25 log rows, newest first \u2014 approved / pending / rejected.</p>
3562
4647
  <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=`
4648
+ </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
4649
  main { max-width: 1200px; margin: 0 auto; padding: 24px 20px 60px; }
3565
4650
  h2 { margin: 0 0 12px; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
3566
4651
  .grid { display: grid; gap: 20px; grid-template-columns: 1fr; }
@@ -3664,7 +4749,7 @@ details {
3664
4749
  border-radius: 4px; padding: 8px 12px; margin-top: 8px;
3665
4750
  }
3666
4751
  details summary { cursor: pointer; font-size: 11px; color: var(--ax-muted); user-select: none; }
3667
- details[open] summary { margin-bottom: 8px; }`,sr=`
4752
+ details[open] summary { margin-bottom: 8px; }`,Dr=`
3668
4753
  const $ = (id) => document.getElementById(id);
3669
4754
  const state = { schema: null, nodes: [], pending: [], recent: [] };
3670
4755
 
@@ -3884,7 +4969,7 @@ $('btn-save-schema').addEventListener('click', async () => {
3884
4969
  $('btn-reload-schema').addEventListener('click', refresh);
3885
4970
 
3886
4971
  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">
4972
+ `;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
4973
  <header class="ax-obs__head">
3889
4974
  <h1>Health</h1>
3890
4975
  <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 +5091,7 @@ refresh();
4006
5091
  </div>
4007
5092
  <div id="obs-doctor-body" class="ax-obs__doctor-body"></div>
4008
5093
  </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=`
5094
+ </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
5095
  .ax-obs { padding: 16px 24px; }
4011
5096
  .ax-obs__head { margin-bottom: 16px; }
4012
5097
  .ax-obs__head h1 { margin: 0 0 4px; font-size: 18px; }
@@ -4099,17 +5184,17 @@ refresh();
4099
5184
  .ax-obs__pill--idle { background: rgba(218, 119, 6, 0.15); color: #bf8700; }
4100
5185
  .ax-obs__empty { color: var(--ax-muted); font-style: italic; padding: 18px 0; margin: 0; }
4101
5186
  .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; }
5187
+ .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); }
5188
+ .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
5189
  .ax-obs__logs-toolbar button:hover { background: var(--ax-surface); }
4105
5190
  .ax-obs__inline { font-size: 11px; color: var(--ax-muted); display: inline-flex; align-items: center; gap: 4px; }
4106
5191
  .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
5192
  .ax-obs__logs-body .err { color: var(--ax-err, #e74c3c); }
4108
5193
  .ax-obs__logs-body .warn { color: #d4ac0d; }
4109
- .ax-obs__logs-body .info { color: var(--ax-fg); }
5194
+ .ax-obs__logs-body .info { color: var(--ax-text); }
4110
5195
  .ax-obs__logs-body .dim { color: var(--ax-muted); }
4111
5196
  .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; }
5197
+ .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
5198
  .ax-obs__doctor-toolbar button:hover { background: var(--ax-surface); }
4114
5199
  .ax-obs__doctor-body { display: flex; flex-direction: column; gap: 10px; }
4115
5200
  .ax-obs__doctor-group { background: var(--ax-bg-elev); border: 1px solid var(--ax-border); border-radius: 6px; padding: 10px 14px; }
@@ -4123,7 +5208,7 @@ refresh();
4123
5208
  .ax-obs__doctor-title { font-size: 12px; font-weight: 500; }
4124
5209
  .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
5210
  .ax-obs__doctor-fix { font-size: 11px; color: var(--ax-accent, #3a7bd5); margin-top: 2px; }
4126
- `,vr=`
5211
+ `,Kr=`
4127
5212
  (function(){
4128
5213
  var panes = document.querySelectorAll('.ax-obs__pane');
4129
5214
  var tabs = document.querySelectorAll('.ax-obs__tab');
@@ -4507,23 +5592,23 @@ refresh();
4507
5592
 
4508
5593
  load(current);
4509
5594
  })();
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=`
5595
+ `;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
5596
  SELECT at, channel, chat_id, account_id, kind, deciding_stage, agent_id, reason
4512
5597
  FROM route_traces
4513
- ${i.length?"WHERE "+i.join(" AND "):""}
5598
+ ${l.length?"WHERE "+l.join(" AND "):""}
4514
5599
  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=`
5600
+ `,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
5601
  SELECT rotated_at, agent_id, channel, reason, last_turn_input_tokens
4517
5602
  FROM rotations
4518
- ${i.length?"WHERE "+i.join(" AND "):""}
5603
+ ${l.length?"WHERE "+l.join(" AND "):""}
4519
5604
  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=`
5605
+ `,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
5606
  SELECT started_at, agent_id, channel, message_preview, error
4522
5607
  FROM task_history
4523
- WHERE ${i.join(" AND ")}
5608
+ WHERE ${l.join(" AND ")}
4524
5609
  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(`
5610
+ `,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(`
5611
+ `)[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
5612
  SELECT agent_id,
4528
5613
  COUNT(*) AS tasks,
4529
5614
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors,
@@ -4533,7 +5618,7 @@ refresh();
4533
5618
  WHERE started_at >= ?
4534
5619
  GROUP BY agent_id
4535
5620
  ORDER BY tasks DESC LIMIT 10
4536
- `).all(a),c=t.prepare(`
5621
+ `).all(a),d=t.prepare(`
4537
5622
  SELECT COALESCE(channel, 'unknown') AS channel,
4538
5623
  COUNT(*) AS tasks,
4539
5624
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -4541,12 +5626,12 @@ refresh();
4541
5626
  WHERE started_at >= ?
4542
5627
  GROUP BY channel
4543
5628
  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(`
5629
+ `).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
5630
  SELECT started_at, agent_id, channel, message_preview, error
4546
5631
  FROM task_history
4547
5632
  WHERE status='error' AND started_at >= ?
4548
5633
  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(`
5634
+ `).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
5635
  SELECT strftime('%Y-%m-%dT%H:00', started_at) AS hour,
4551
5636
  COUNT(*) AS tasks,
4552
5637
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -4554,7 +5639,7 @@ refresh();
4554
5639
  WHERE started_at >= @since ${r}
4555
5640
  GROUP BY hour
4556
5641
  ORDER BY hour
4557
- `).all({since:a,...o}),i=t.prepare(`
5642
+ `).all({since:a,...o}),l=t.prepare(`
4558
5643
  SELECT date(started_at) AS day,
4559
5644
  COUNT(*) AS tasks,
4560
5645
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -4562,7 +5647,7 @@ refresh();
4562
5647
  WHERE started_at >= @since ${r}
4563
5648
  GROUP BY day
4564
5649
  ORDER BY day
4565
- `).all({since:n,...o}),l=t.prepare(`
5650
+ `).all({since:n,...o}),i=t.prepare(`
4566
5651
  SELECT agent_id,
4567
5652
  COUNT(*) AS tasks_7d,
4568
5653
  SUM(CASE WHEN started_at >= @last24 THEN 1 ELSE 0 END) AS tasks_24h,
@@ -4573,7 +5658,7 @@ refresh();
4573
5658
  WHERE started_at >= @since
4574
5659
  GROUP BY agent_id
4575
5660
  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(`
5661
+ `).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
5662
  SELECT day, agent_id, model,
4578
5663
  input_tokens, output_tokens, cache_read_tokens, cache_create_tokens,
4579
5664
  tier2_input_tokens, tier2_output_tokens, tier2_cache_read_tokens, tier2_cache_create_tokens,
@@ -4581,37 +5666,37 @@ refresh();
4581
5666
  FROM usage_daily
4582
5667
  ${a}
4583
5668
  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+`
5669
+ `).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
5670
  `+a.join(`
4586
5671
  `)+`
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(`
5672
+ `}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
5673
  SELECT COUNT(*) AS n FROM intent_decisions d
4589
5674
  LEFT JOIN intent_resolutions r
4590
5675
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
4591
5676
  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=`
5677
+ `).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
5678
  SELECT id, ts, source, source_event_id, project, subject, intent
4594
5679
  FROM intent_events
4595
- ${u.length?"WHERE "+u.join(" AND "):""}
5680
+ ${m.length?"WHERE "+m.join(" AND "):""}
4596
5681
  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=`
5682
+ `;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
5683
  SELECT ts, source, decided_by,
4599
5684
  legacy_agent_id, legacy_outcome, legacy_reason,
4600
5685
  ledger_agent_id, ledger_outcome, ledger_reason,
4601
5686
  event_id
4602
5687
  FROM intent_divergences
4603
- ${u.length?"WHERE "+u.join(" AND "):""}
5688
+ ${m.length?"WHERE "+m.join(" AND "):""}
4604
5689
  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=`
5690
+ `;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
5691
  SELECT e.id AS event_id, e.ts, e.source, e.project, e.subject, e.intent,
4607
5692
  d.decided_by, d.decided_at, d.agent_id, d.reason
4608
5693
  FROM intent_decisions d
4609
5694
  JOIN intent_events e ON e.id = d.event_id
4610
5695
  LEFT JOIN intent_resolutions r
4611
5696
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
4612
- WHERE ${u.join(" AND ")}
5697
+ WHERE ${m.join(" AND ")}
4613
5698
  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">
5699
+ `;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
5700
  <header class="ax-led__head">
4616
5701
  <h1>Intent ledger</h1>
4617
5702
  <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 +5901,7 @@ refresh();
4816
5901
  }
4817
5902
  load();
4818
5903
  })();
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">
5904
+ </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
5905
  <header class="ax-cost__head">
4821
5906
  <div>
4822
5907
  <h1>Cost</h1>
@@ -5389,7 +6474,7 @@ refresh();
5389
6474
  load();
5390
6475
  setInterval(load, 30000);
5391
6476
  })();
5392
- </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function ta(t={}){let e=`<div class="ax-pj__root">
6477
+ </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function va(t={}){let e=`<div class="ax-pj__root">
5393
6478
  <aside class="ax-pj__list">
5394
6479
  <header>
5395
6480
  <h2>Projects</h2>
@@ -5416,7 +6501,7 @@ refresh();
5416
6501
  </header>
5417
6502
  <div id="pj-detail-body" class="ax-pj__detail-body"></div>
5418
6503
  </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=`
6504
+ </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
6505
  .ax-pj__root {
5421
6506
  display: grid;
5422
6507
  grid-template-columns: 360px 1fr;
@@ -5435,7 +6520,7 @@ refresh();
5435
6520
  }
5436
6521
  .ax-pj__list > header h2 { margin: 0; font-size: 14px; }
5437
6522
  .ax-pj__icon {
5438
- background: transparent; color: var(--ax-fg-muted, var(--ax-fg));
6523
+ background: transparent; color: var(--ax-fg-muted, var(--ax-text));
5439
6524
  border: 1px solid transparent; border-radius: 4px;
5440
6525
  padding: 4px 8px; cursor: pointer; font-size: 14px;
5441
6526
  }
@@ -5444,7 +6529,7 @@ refresh();
5444
6529
  .ax-pj__search input {
5445
6530
  width: 100%; font: inherit; font-size: 12px;
5446
6531
  padding: 6px 8px; border: 1px solid var(--ax-border);
5447
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6532
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5448
6533
  }
5449
6534
  .ax-pj__cards {
5450
6535
  list-style: none; margin: 0; padding: 0;
@@ -5459,7 +6544,7 @@ refresh();
5459
6544
  .ax-pj__card-title { font-weight: 500; font-size: 13px; margin-bottom: 4px; }
5460
6545
  .ax-pj__card-meta {
5461
6546
  display: flex; gap: 6px; flex-wrap: wrap;
5462
- font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg));
6547
+ font-size: 11px; color: var(--ax-fg-muted, var(--ax-text));
5463
6548
  }
5464
6549
  .ax-pj__card-meta .stat { padding: 1px 6px; border-radius: 3px; background: var(--ax-bg); border: 1px solid var(--ax-border); }
5465
6550
  .ax-pj__card-meta .stat.zero { opacity: 0.4; }
@@ -5480,11 +6565,11 @@ refresh();
5480
6565
  .ax-pj__kind--github { color: #c9d1d9; background: rgba(110, 118, 129, 0.2); border-color: rgba(110, 118, 129, 0.4); }
5481
6566
  .ax-pj__kind--jira { color: #2684ff; background: rgba(38, 132, 255, 0.1); border-color: rgba(38, 132, 255, 0.3); }
5482
6567
  .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); }
6568
+ .ax-pj__kind--other { color: var(--ax-fg-muted, var(--ax-text)); background: var(--ax-bg); border-color: var(--ax-border); }
6569
+ .ax-pj__keyhint { font-size: 12px; font-weight: normal; color: var(--ax-fg-muted, var(--ax-text)); font-family: var(--ax-mono, monospace); }
5485
6570
  .ax-pj__home {
5486
6571
  font-size: 12px; text-decoration: none; padding: 2px 6px;
5487
- color: var(--ax-fg-muted, var(--ax-fg)); border: 1px solid var(--ax-border);
6572
+ color: var(--ax-fg-muted, var(--ax-text)); border: 1px solid var(--ax-border);
5488
6573
  border-radius: 3px;
5489
6574
  }
5490
6575
  .ax-pj__home:hover { color: var(--ax-accent); border-color: var(--ax-accent); }
@@ -5494,7 +6579,7 @@ refresh();
5494
6579
  .ax-pj__btn {
5495
6580
  font: inherit; font-size: 11px;
5496
6581
  padding: 3px 8px; border: 1px solid var(--ax-border);
5497
- border-radius: 3px; background: var(--ax-bg); color: var(--ax-fg);
6582
+ border-radius: 3px; background: var(--ax-bg); color: var(--ax-text);
5498
6583
  cursor: pointer; text-transform: none; letter-spacing: 0;
5499
6584
  margin-left: auto;
5500
6585
  }
@@ -5502,7 +6587,7 @@ refresh();
5502
6587
  .ax-pj__unlink {
5503
6588
  margin-left: auto;
5504
6589
  background: transparent; border: 1px solid transparent;
5505
- color: var(--ax-fg-muted, var(--ax-fg));
6590
+ color: var(--ax-fg-muted, var(--ax-text));
5506
6591
  cursor: pointer; font-size: 14px; padding: 0 6px; border-radius: 3px;
5507
6592
  }
5508
6593
  .ax-pj__unlink:hover { color: var(--ax-err, #ef4444); border-color: var(--ax-err, #ef4444); }
@@ -5525,7 +6610,7 @@ refresh();
5525
6610
  .ax-pj__modal-search input {
5526
6611
  width: 100%; font: inherit; font-size: 13px;
5527
6612
  padding: 6px 10px; border: 1px solid var(--ax-border);
5528
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6613
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5529
6614
  margin-bottom: 12px;
5530
6615
  }
5531
6616
  .ax-pj__pick {
@@ -5535,7 +6620,7 @@ refresh();
5535
6620
  }
5536
6621
  .ax-pj__pick:hover { background: var(--ax-bg); border-color: var(--ax-border); }
5537
6622
  .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)); }
6623
+ .ax-pj__pick .pmeta { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); }
5539
6624
  .ax-pj__pick .ptag {
5540
6625
  font-size: 11px; padding: 1px 6px; border-radius: 3px;
5541
6626
  background: var(--ax-warn, #facc15); color: #1a1a1a;
@@ -5543,13 +6628,13 @@ refresh();
5543
6628
  /* Form fields */
5544
6629
  .ax-pj__form { display: flex; flex-direction: column; gap: 12px; }
5545
6630
  .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)); }
6631
+ .ax-pj__fld-label { font-size: 12px; font-weight: 500; color: var(--ax-fg-muted, var(--ax-text)); }
5547
6632
  .ax-pj__fld input, .ax-pj__fld select {
5548
6633
  font: inherit; font-size: 13px;
5549
6634
  padding: 6px 10px; border: 1px solid var(--ax-border);
5550
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6635
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5551
6636
  }
5552
- .ax-pj__fld-hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg)); }
6637
+ .ax-pj__fld-hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); }
5553
6638
  .ax-pj__form-actions {
5554
6639
  display: flex; gap: 8px; align-items: center;
5555
6640
  margin-top: 8px; padding-top: 14px;
@@ -5565,7 +6650,7 @@ refresh();
5565
6650
  .ax-pj__fld textarea {
5566
6651
  font: inherit; font-family: var(--ax-mono, monospace); font-size: 12px;
5567
6652
  padding: 6px 10px; border: 1px solid var(--ax-border);
5568
- border-radius: 4px; background: var(--ax-bg); color: var(--ax-fg);
6653
+ border-radius: 4px; background: var(--ax-bg); color: var(--ax-text);
5569
6654
  resize: vertical;
5570
6655
  }
5571
6656
  .ax-pj__clause {
@@ -5587,7 +6672,7 @@ refresh();
5587
6672
  }
5588
6673
  .ax-pj__section h3 {
5589
6674
  font-size: 13px; text-transform: uppercase; letter-spacing: 0.6px;
5590
- color: var(--ax-fg-muted, var(--ax-fg)); margin: 0 0 10px 0;
6675
+ color: var(--ax-fg-muted, var(--ax-text)); margin: 0 0 10px 0;
5591
6676
  }
5592
6677
  .ax-pj__row {
5593
6678
  display: flex; align-items: center; gap: 10px;
@@ -5595,15 +6680,15 @@ refresh();
5595
6680
  border-radius: 4px; margin-bottom: 6px; background: var(--ax-bg);
5596
6681
  }
5597
6682
  .ax-pj__row .name { font-weight: 500; }
5598
- .ax-pj__row .meta { font-size: 11px; color: var(--ax-fg-muted, var(--ax-fg)); }
6683
+ .ax-pj__row .meta { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); }
5599
6684
  .ax-pj__row a { color: var(--ax-accent); text-decoration: none; }
5600
6685
  .ax-pj__row a:hover { text-decoration: underline; }
5601
6686
  .ax-pj__empty, .ax-pj__warn {
5602
- padding: 18px; font-size: 12px; color: var(--ax-fg-muted, var(--ax-fg));
6687
+ padding: 18px; font-size: 12px; color: var(--ax-fg-muted, var(--ax-text));
5603
6688
  }
5604
6689
  .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=`
6690
+ .ax-pj__hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); margin-top: 4px; }
6691
+ `,co=`
5607
6692
  (function(){
5608
6693
  const $ = (sel) => document.querySelector(sel);
5609
6694
  const esc = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({"&":"&amp;","<":"&lt;",">":"&gt;","\\"":"&quot;"}[c]));
@@ -5972,7 +7057,7 @@ refresh();
5972
7057
  // \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
7058
  async function addContact(projectKey) {
5974
7059
  const cid = prompt("Contact id to link to '" + projectKey + "':\\n\\n"
5975
- + "Use the id from .agentx/contacts.json (e.g. 'anis', 'omar').");
7060
+ + "Use the id from .agentx/contacts.json (e.g. 'alex', 'jordan').");
5976
7061
  if (!cid) return;
5977
7062
  try {
5978
7063
  await postJson("/api/admin/projects/contacts/link", { projectKey, contactId: cid.trim() });
@@ -6253,7 +7338,7 @@ refresh();
6253
7338
  load();
6254
7339
  });
6255
7340
  })();
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=`
7341
+ `;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
7342
  html, body { height: 100%; }
6258
7343
  body { margin: 0; }
6259
7344
  #ax-fleet-root { height: calc(100vh - 48px); }
@@ -6265,31 +7350,31 @@ body { margin: 0; }
6265
7350
  font: 13px/1 -apple-system, BlinkMacSystemFont, sans-serif;
6266
7351
  text-align: center;
6267
7352
  }
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}
7353
+ `;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
7354
  ${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(`
7355
+ ${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
7356
  SELECT id, ts, source, project, subject, intent, raw_json
6272
7357
  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(`
7358
+ `).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
7359
  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(`
7360
+ FROM intent_decisions WHERE event_id IN (${y}) ORDER BY decided_at ASC
7361
+ `).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
7362
  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
7363
+ FROM intent_resolutions WHERE decision_event_id IN (${y})
7364
+ `).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
7365
 
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
7366
+ `);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
7367
 
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)}
7368
+ `)}catch{s()}},25e3);try{for(;!o;){let i=Re();if(i)try{let u=ot(i.db,ce,r);e.write(`event: snapshot
7369
+ `),e.write(`data: ${JSON.stringify(u)}
6285
7370
 
6286
- `)}catch(p){e.write(`event: error
6287
- data: ${JSON.stringify({error:p?.message??String(p)})}
7371
+ `)}catch(u){e.write(`event: error
7372
+ data: ${JSON.stringify({error:u?.message??String(u)})}
6288
7373
 
6289
- `)}finally{l.close()}else e.write(`event: error
7374
+ `)}finally{i.close()}else e.write(`event: error
6290
7375
  data: ${JSON.stringify({error:"ledger not available"})}
6291
7376
 
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=`
7377
+ `);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
7378
  <!-- Breadcrumb -->
6294
7379
  <div class="ax-crumb">
6295
7380
  <a href="/admin">Settings</a>
@@ -6662,7 +7747,7 @@ data: ${JSON.stringify({error:"ledger not available"})}
6662
7747
  </div>
6663
7748
  <div class="ax-field">
6664
7749
  <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" />
7750
+ <input class="inp mono" id="ho-chatid" placeholder="1816212449 or +10000000000" />
6666
7751
  </div>
6667
7752
  <div class="ax-field">
6668
7753
  <label class="lbl">Hand off to</label>
@@ -6878,7 +7963,7 @@ data: ${JSON.stringify({error:"ledger not available"})}
6878
7963
  </div>
6879
7964
  </div>
6880
7965
  </div>
6881
- `,Xr=`
7966
+ `,Eo=`
6882
7967
  /* Agent-specific layout + legacy styles for bits the migration left in
6883
7968
  * place (EasyMDE theming, skills tree, plain-editor). Shared chrome + tab
6884
7969
  * primitives live in components.css.ts. */
@@ -6997,7 +8082,7 @@ textarea.inp.mono { font-family: var(--ax-mono); }
6997
8082
 
6998
8083
  /* Agent-specific button variant used in rail context (no ax-btn wrapper) */
6999
8084
  .ax-btn.lg { padding: 9px 16px; font-size: 13px; }
7000
- `,Kr=`
8085
+ `,So=`
7001
8086
  const $ = (id) => document.getElementById(id);
7002
8087
  const state = { agent: null, activeSkill: null, activeSkillFile: null, identityPath: null };
7003
8088
 
@@ -7253,7 +8338,7 @@ async function loadAgent(){
7253
8338
  const msg = document.getElementById('mcp-msg');
7254
8339
  try {
7255
8340
  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)'; }
8341
+ if (msg) { msg.textContent = '\u2713 saved \u2014 agent picks it up at next daemon boot'; msg.style.color = 'var(--ax-ok)'; }
7257
8342
  ['mcp-name','mcp-command','mcp-args','mcp-env'].forEach(function(id){ document.getElementById(id).value = ''; });
7258
8343
  await loadAgent();
7259
8344
  } catch (e) {
@@ -7282,7 +8367,7 @@ async function loadAgent(){
7282
8367
  const msg = document.getElementById('cap-msg');
7283
8368
  try {
7284
8369
  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)'; }
8370
+ if (msg) { msg.textContent = '\u2713 saved \u2014 restart the daemon for changes to take effect'; msg.style.color = 'var(--ax-ok)'; }
7286
8371
  await loadAgent();
7287
8372
  } catch (e) {
7288
8373
  if (msg) { msg.textContent = e.message; msg.style.color = 'var(--ax-err)'; }
@@ -7786,7 +8871,7 @@ async function dispatchTd(text) {
7786
8871
  appendTdTyping();
7787
8872
  const t0 = Date.now();
7788
8873
  try {
7789
- // Use /chat endpoint so test-drive exercises the same path as noqta.tn.
8874
+ // Use /chat endpoint so test-drive exercises the same path as example.com.
7790
8875
  // Falls back to /task reply shape if /chat isn't reachable (no auth configured).
7791
8876
  let reply, queuedTask;
7792
8877
  try {
@@ -7851,15 +8936,15 @@ document.addEventListener('keydown', (e) => {
7851
8936
  /* ===== Boot ===== */
7852
8937
  initOptsToggles();
7853
8938
  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>
8939
+ `;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(`
8940
+ `);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(`
8941
+ `);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
8942
  <span id="conn-dot" class="ax-dot ax-dot--ok ax-dot--pulse" title="connected"></span>
7858
8943
  <span id="conn-label">live</span>`,n=`<div class="ax-app-live">
7859
8944
  <section id="statstrip" class="ax-statstrip"></section>
7860
8945
  <main id="grid" class="ax-live__body"></main>
7861
8946
  </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>
8947
+ `;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
8948
  // rightExtras for the topbar are injected at runtime \u2014 they reference
7864
8949
  // IDs (#ts, #conn-dot) that the script below addresses directly.
7865
8950
  document.addEventListener('DOMContentLoaded', () => {
@@ -7870,7 +8955,7 @@ loadAgent();
7870
8955
  extras.innerHTML = ${JSON.stringify(a)};
7871
8956
  right.insertBefore(extras, right.firstChild);
7872
8957
  });
7873
- </script>`})}var yo=`
8958
+ </script>`})}var Vo=`
7874
8959
  /* --- Page frame --- */
7875
8960
  .ax-app-live { min-height: 100vh; display: flex; flex-direction: column; }
7876
8961
 
@@ -8071,7 +9156,7 @@ loadAgent();
8071
9156
  border-top-color: var(--ax-accent); border-radius: 50%;
8072
9157
  animation: ax-spin 800ms linear infinite; display: inline-block;
8073
9158
  }
8074
- @keyframes ax-spin { to { transform: rotate(360deg); } }`,wo=`
9159
+ @keyframes ax-spin { to { transform: rotate(360deg); } }`,Yo=`
8075
9160
  'use strict';
8076
9161
 
8077
9162
  const ui = { nodes: new Map(), summary: { nodes: 0, agents: 0, busy: 0, errors: 0 } };
@@ -8322,7 +9407,7 @@ function renderAgent(a, node) {
8322
9407
  // The page's job is "who is alive and what are they doing RIGHT NOW". Giving
8323
9408
  // an idle agent the same real estate as a working one \u2014 model, last-reply
8324
9409
  // 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
9410
+ // the more agents you run. On peer (22 agents) the busy ones were lost in a
8326
9411
  // wall of identical idle cards.
8327
9412
  //
8328
9413
  // Collapsed still carries what the question needs: who, engine, and when it
@@ -8543,7 +9628,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
8543
9628
  });
8544
9629
  }
8545
9630
 
8546
- `;var Ta=`
9631
+ `;var za=`
8547
9632
  .mx-content{max-width:1180px;margin:0 auto;padding:0 24px 56px}
8548
9633
  .mx-updated{margin:0;color:var(--ax-muted);font-size:11px;font-family:var(--ax-mono)}
8549
9634
  .mx-section{margin-bottom:28px}.mx-section .ax-section-head{margin-bottom:14px}
@@ -8713,7 +9798,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
8713
9798
  .mx-summary{max-width:56vw}
8714
9799
  }
8715
9800
  @media(prefers-reduced-motion:reduce){.mx-drawer{transition:none}}
8716
- `;var Ca=`<script>
9801
+ `;var qa=`<script>
8717
9802
  window.MX=(function(){
8718
9803
  var ENT={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'};
8719
9804
  function esc(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return ENT[c]})}
@@ -8822,7 +9907,7 @@ window.MX=(function(){
8822
9907
  verdict:verdict,verdictChip:verdictChip,mark:mark,causeLabel:causeLabel,
8823
9908
  setHealth:setHealth,get:get};
8824
9909
  })();
8825
- </script>`;var Aa=`<script>
9910
+ </script>`;var Ua=`<script>
8826
9911
  window.MXD=(function(){
8827
9912
  function el(id){return document.getElementById(id)}
8828
9913
  function tz(){return -new Date().getTimezoneOffset()}
@@ -9036,7 +10121,7 @@ window.MXD=(function(){
9036
10121
 
9037
10122
  return {openDay:openDay,openJob:openJob,openConversation:openConversation};
9038
10123
  })();
9039
- </script>`;var Ma=`<script>
10124
+ </script>`;var Fa=`<script>
9040
10125
  (function(){
9041
10126
  var LANES=[
9042
10127
  {id:'cron',name:'Scheduled',hint:'cron jobs'},
@@ -9352,7 +10437,7 @@ window.MXD=(function(){
9352
10437
  window.addEventListener('scroll',hideTip,{passive:true});
9353
10438
  load();
9354
10439
  })();
9355
- </script>`;var Ia=`<script>
10440
+ </script>`;var Wa=`<script>
9356
10441
  (function(){
9357
10442
  var showAll=document.getElementById('mx-show-all'),expanded=false;
9358
10443
  var esc=MX.esc;
@@ -9499,17 +10584,17 @@ window.MXD=(function(){
9499
10584
  }
9500
10585
  load();setInterval(load,5000);
9501
10586
  })();
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">
10587
+ </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
10588
  <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("")}
10589
+ ${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
10590
  </div>
9506
10591
  <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("")}
10592
+ ${Zo.map(l=>`<button type="button" data-days="${l.days}" aria-pressed="${l.days===30}">${l.label}</button>`).join("")}
9508
10593
  </div>
9509
10594
  </div>
9510
10595
  <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
10596
  <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")}
10597
+ ${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
10598
  <div id="mx-lanes"><div class="mx-empty">Loading activity...</div></div>
9514
10599
  <div class="mx-axis" id="mx-axis"></div>
9515
10600
  <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 +10602,32 @@ window.MXD=(function(){
9517
10602
 
9518
10603
  <div class="mx-two">
9519
10604
  <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")}
10605
+ ${Q(Y.breakage,"Where it breaks","Attempts per origin, with the failed share marked on the same bar.","mx-origins-title")}
9521
10606
  <div class="mx-bars" id="mx-origins"><div class="mx-empty">Loading...</div></div>
9522
10607
  </section>
9523
10608
  <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")}
10609
+ ${Q(Y.breakage,"Why it fails","Failures grouped by cause class, matched from the recorded error text.","mx-causes-title")}
9525
10610
  <div class="mx-bars" id="mx-causes"><div class="mx-empty">Loading...</div></div>
9526
10611
  <p class="mx-note" id="mx-cause-note"></p>
9527
10612
  </section>
9528
10613
  </div>
9529
10614
 
9530
10615
  <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")}
10616
+ ${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
10617
  <div class="mx-scatter" id="mx-scatter"><div class="mx-empty">Loading jobs...</div></div>
9533
10618
  <div class="mx-legend" id="mx-scatter-legend"></div>
9534
10619
  <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
10620
  </section>
9536
10621
  </div>`,r=`<div class="mx-view" id="mx-view-lifetime" role="tabpanel" aria-labelledby="mx-tab-lifetime" hidden>
9537
10622
  <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")}
10623
+ ${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
10624
  <div class="mx-chips" id="mx-thread-chips"></div>
9540
10625
  <div id="mx-threads"><div class="mx-empty">Loading threads...</div></div>
9541
10626
  <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
10627
  </section>
9543
10628
 
9544
10629
  <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")}
10630
+ ${Q(Y.cuts,"Session cuts","Why threads lost their session, across the fleet.","mx-rot-title")}
9546
10631
  <div class="mx-bars" id="mx-rotations"><div class="mx-empty">Loading...</div></div>
9547
10632
  <p class="mx-note" id="mx-rot-note"></p>
9548
10633
  </section>
@@ -9550,23 +10635,23 @@ window.MXD=(function(){
9550
10635
  <p id="mx-updated" class="mx-updated" aria-live="polite">Connecting to the fleet...</p>
9551
10636
 
9552
10637
  <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>')}
10638
+ ${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
10639
  <div class="ax-stack" id="mx-runs"><div class="mx-empty">Loading schedules...</div></div>
9555
10640
  </section>
9556
10641
 
9557
10642
  <div class="mx-columns">
9558
10643
  <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>')}
10644
+ ${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
10645
  <div class="ax-stack" id="mx-active"><div class="mx-empty">No activity loaded.</div></div>
9561
10646
  </section>
9562
10647
  <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>')}
10648
+ ${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
10649
  <div class="ax-stack" id="mx-nodes"><div class="mx-empty">No nodes loaded.</div></div>
9565
10650
  </section>
9566
10651
  </div>
9567
10652
 
9568
10653
  <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>')}
10654
+ ${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
10655
  <div class="mx-agent-grid" id="mx-agents"><div class="mx-empty">No agents loaded.</div></div>
9571
10656
  </section>
9572
10657
  </div>`,s=`${e}<main class="mx-content">
@@ -9582,7 +10667,7 @@ window.MXD=(function(){
9582
10667
  <button class="ax-btn ax-btn--ghost" id="mx-close" type="button" aria-label="Close details">Close</button>
9583
10668
  </header>
9584
10669
  <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>
10670
+ </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
10671
  (function(){
9587
10672
  var tabs=Array.prototype.slice.call(document.querySelectorAll('.mx-tab'));
9588
10673
  var range=document.getElementById('mx-range');
@@ -9610,7 +10695,7 @@ window.MXD=(function(){
9610
10695
  var saved=null;try{saved=localStorage.getItem('mx-view')}catch(e){}
9611
10696
  select(tabs.some(function(t){return t.dataset.view===saved})?saved:'activity');
9612
10697
  })();
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=`
10698
+ </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
10699
  <select id="boardPicker" title="Switch board"></select>
9615
10700
  <div class="search">
9616
10701
  <span class="icon">\u2315</span>
@@ -9711,7 +10796,7 @@ window.MXD=(function(){
9711
10796
  </footer>
9712
10797
  </div>
9713
10798
  </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>
10799
+ <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
10800
  // The boards page has its own connection dot + wants body height:100%
9716
10801
  // for the full-viewport kanban layout. Inject the dot into the topbar
9717
10802
  // and override body height at runtime so the shared shell doesn't
@@ -9727,7 +10812,7 @@ window.MXD=(function(){
9727
10812
  right.insertBefore(dot, right.firstChild);
9728
10813
  }
9729
10814
  });
9730
- </script>`})}var Co=`
10815
+ </script>`})}var ns=`
9731
10816
  /* Kanban subheader \u2014 replaces the legacy toolbar that used to live in <header>. */
9732
10817
  .ax-subheader select, .ax-subheader input, .ax-subheader button {
9733
10818
  background: var(--col); color: var(--text); border: 1px solid var(--border);
@@ -9980,7 +11065,7 @@ header a.link:hover { color: var(--accent); border-color: var(--accent); }
9980
11065
  .draft-box .draft-row .hint { color: var(--muted); font-size: 12px; flex: 1; }
9981
11066
  .draft-box .draft-row .hint.err { color: var(--red); }
9982
11067
  .draft-box .draft-row .hint.ok { color: var(--green); }
9983
- `,Ao=`
11068
+ `,rs=`
9984
11069
  'use strict';
9985
11070
  const state = {
9986
11071
  boards: [], current: null, items: {},
@@ -10916,7 +12001,7 @@ const activity = {
10916
12001
  };
10917
12002
 
10918
12003
  function resolveDaemonUrl() {
10919
- // Allow ?daemon=http://host:port override; fall back to localhost:18800 (MacBook) then 19900 (clawd).
12004
+ // Allow ?daemon=http://host:port override; fall back to localhost:18800 (MacBook) then 19900 (peer).
10920
12005
  const q = new URLSearchParams(window.location.search).get('daemon');
10921
12006
  if (q) return q.replace(/\\/+$/, '');
10922
12007
  return localStorage.getItem('agentx.daemon') || 'http://localhost:18800';
@@ -11039,9 +12124,9 @@ function appendEvents(events) {
11039
12124
  }
11040
12125
 
11041
12126
  loadBoards().catch(e => toast('Init failed: ' + e.message));
11042
- `;function Pa(t={}){let a=`<h1>Plain-English glossary</h1>
12127
+ `;function Ya(t={}){let a=`<h1>Plain-English glossary</h1>
11043
12128
  <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=`
12129
+ ${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
12130
  main { max-width: 760px; margin: 0 auto; padding: 32px 24px 80px; }
11046
12131
  h1 { font-size: 22px; margin: 0 0 6px; font-weight: 600; letter-spacing: -0.01em; }
11047
12132
  .lead {
@@ -11071,11 +12156,12 @@ article.term .alias {
11071
12156
  }
11072
12157
  article.term p {
11073
12158
  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">
12159
+ }`;function Qa(t={}){let e=`<div class="ax-wf__root">
11075
12160
  <aside class="ax-wf__list">
11076
12161
  <header>
11077
12162
  <h2>Workflows</h2>
11078
12163
  <div class="ax-wf__header-actions">
12164
+ <a id="wf-new" class="ax-wf__icon" href="/workflows/editor?new=1" title="Build a new workflow">+</a>
11079
12165
  <button id="wf-refresh" class="ax-wf__icon" title="Refresh (r)">\u21BB</button>
11080
12166
  </div>
11081
12167
  </header>
@@ -11087,16 +12173,36 @@ article.term p {
11087
12173
  </div>
11088
12174
  <ul id="wf-list" class="ax-wf__cards" aria-live="polite"></ul>
11089
12175
  <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>
12176
+ <p><b>No workflows yet.</b></p>
12177
+ <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
12178
  </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>
12179
+ <section class="ax-wf__n8n">
12180
+ <header><h3>Hand work over from n8n</h3></header>
12181
+ <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>
12182
+
12183
+ <ol class="ax-wf__n8n-steps">
12184
+ <li>
12185
+ <b>Name the job.</b> Pick a short word for what n8n is handing over &mdash;
12186
+ <code>invoice-received</code>, <code>lead-signed-up</code>. That word is the
12187
+ <i>topic</i>, and it is the last part of the address below.
12188
+ </li>
12189
+ <li>
12190
+ <b>In n8n</b>, add an <b>HTTP Request</b> node: method <code>POST</code>, this address
12191
+ with your topic on the end, and send whatever JSON the workflow should read.
12192
+ <div class="ax-wf__n8n-url" id="wf-n8n-in">&hellip;</div>
12193
+ <button class="ax-wf__n8n-copy" id="wf-n8n-copy" type="button">Copy address</button>
12194
+ <span class="hint" id="wf-n8n-auth"></span>
12195
+ </li>
12196
+ <li>
12197
+ <b>Here</b>, build a workflow that starts with <b>n8n hands work over</b> and set its
12198
+ topic to the same word. Without that, every workflow listening for n8n runs on
12199
+ every call.
12200
+ </li>
12201
+ </ol>
12202
+
12203
+ <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
12204
  </section>
12205
+
11100
12206
  </aside>
11101
12207
 
11102
12208
  <section class="ax-wf__detail">
@@ -11127,7 +12233,7 @@ article.term p {
11127
12233
  </aside>
11128
12234
  </div>
11129
12235
 
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=`
12236
+ <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
12237
  .ax-wf__root {
11132
12238
  display: grid;
11133
12239
  grid-template-columns: 340px 1fr;
@@ -11171,6 +12277,52 @@ article.term p {
11171
12277
  border: 1px solid var(--ax-border); border-radius: 4px;
11172
12278
  font-family: inherit;
11173
12279
  }
12280
+ .ax-wf__state {
12281
+ font-size: 11.5px; font-weight: 600; margin-top: 4px;
12282
+ display: inline-flex; align-items: center; gap: 5px;
12283
+ }
12284
+ .ax-wf__state::before { content: ""; width: 7px; height: 7px; border-radius: 999px; background: currentColor; }
12285
+ .ax-wf__state--dormant { color: var(--ax-red-ink); }
12286
+ .ax-wf__state--failing { color: var(--ax-amber-ink); }
12287
+ .ax-wf__state--active { color: var(--ax-green-d); }
12288
+ .ax-wf__state--quiet,
12289
+ .ax-wf__state--never { color: var(--ax-text-2); }
12290
+
12291
+ .ax-wf__n8n {
12292
+ border-top: var(--ax-border-w) solid var(--ax-border);
12293
+ padding: 14px 16px; display: flex; flex-direction: column; gap: 8px;
12294
+ }
12295
+ .ax-wf__n8n h3 { font-size: 13px; font-weight: 600; margin: 0; }
12296
+ .ax-wf__n8n-lbl {
12297
+ font-size: 10px; font-family: var(--ax-mono); text-transform: uppercase;
12298
+ letter-spacing: 0.06em; color: var(--ax-text-2); font-weight: 600;
12299
+ }
12300
+ .ax-wf__n8n-steps {
12301
+ margin: 4px 0 0; padding-left: 18px; display: flex; flex-direction: column; gap: 10px;
12302
+ font-size: 12px; line-height: 1.5; color: var(--ax-text-2);
12303
+ }
12304
+ .ax-wf__n8n-steps b { color: var(--ax-text); font-weight: 600; }
12305
+ .ax-wf__n8n-steps i { font-style: normal; color: var(--ax-text); font-weight: 600; }
12306
+ .ax-wf__n8n-steps code {
12307
+ font-family: var(--ax-mono); font-size: 11px; background: var(--ax-surface-2);
12308
+ border: 1px solid var(--ax-border); border-radius: 4px; padding: 0 4px;
12309
+ }
12310
+ .ax-wf__n8n-steps > li { padding-left: 2px; }
12311
+ .ax-wf__n8n-steps .ax-wf__n8n-url { margin: 7px 0 6px; }
12312
+
12313
+ .ax-wf__n8n-url {
12314
+ font-family: var(--ax-mono); font-size: 11px; word-break: break-all;
12315
+ background: var(--ax-surface-2); border: 1px solid var(--ax-border);
12316
+ border-radius: var(--ax-radius-sm); padding: 8px 10px; color: var(--ax-text);
12317
+ }
12318
+ .ax-wf__n8n-copy {
12319
+ align-self: flex-start; font: inherit; font-size: 12px; font-weight: 600;
12320
+ padding: 5px 12px; border-radius: var(--ax-radius-sm);
12321
+ border: var(--ax-border-w) solid var(--ax-border-2);
12322
+ background: var(--ax-surface); color: var(--ax-text); cursor: pointer;
12323
+ }
12324
+ .ax-wf__n8n-copy:hover { background: var(--ax-surface-2); }
12325
+
11174
12326
  .ax-wf__cards {
11175
12327
  list-style: none; margin: 0; padding: 8px 0;
11176
12328
  overflow-y: auto; flex: 1 1 auto; min-height: 140px;
@@ -11201,37 +12353,6 @@ article.term p {
11201
12353
  color: var(--ax-accent);
11202
12354
  border-color: color-mix(in oklch, var(--ax-accent) 50%, transparent);
11203
12355
  }
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
12356
  .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
12357
  .ax-wf__btn.primary { border-color: color-mix(in oklch, var(--ax-accent) 55%, var(--ax-border)); color: var(--ax-accent); }
11237
12358
 
@@ -11398,7 +12519,7 @@ article.term p {
11398
12519
  border: 1px solid var(--ax-border);
11399
12520
  border-radius: 4px;
11400
12521
  background: var(--ax-bg);
11401
- color: var(--ax-fg);
12522
+ color: var(--ax-text);
11402
12523
  margin-top: 6px;
11403
12524
  width: 100%;
11404
12525
  }
@@ -11470,7 +12591,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11470
12591
  .ax-wf__status-pill.completed { color: var(--ax-muted); background: var(--ax-surface); }
11471
12592
  .ax-wf__status-pill.failed { color: var(--ax-err); background: color-mix(in oklch, var(--ax-err) 15%, transparent); }
11472
12593
  .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; }
12594
+ .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
12595
  .ax-wf__run-actions button:hover { background: var(--ax-surface); }
11475
12596
  .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
12597
 
@@ -11496,17 +12617,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11496
12617
  font-size: 12px; z-index: 50;
11497
12618
  }
11498
12619
  .hint { color: var(--ax-muted); font-size: 11px; }
11499
- `,$o=`
12620
+ `,is=`
11500
12621
  (() => {
11501
12622
  const $ = (sel) => document.querySelector(sel)
11502
12623
  const $$ = (sel) => Array.from(document.querySelectorAll(sel))
11503
12624
 
11504
12625
  const state = {
11505
12626
  workflows: [],
11506
- drafts: [],
11507
12627
  runs: [],
11508
12628
  selectedId: null,
11509
- selectedDraftId: null,
11510
12629
  filter: "",
11511
12630
  /** Project filter \u2014 "" = all (incl. workflows without project),
11512
12631
  * "__none__" = only workflows missing the project field,
@@ -11559,11 +12678,46 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11559
12678
  + (hasGlobal ? '<option value="__none__"' + (current === "__none__" ? ' selected' : '') + '>(no project)</option>' : "")
11560
12679
  }
11561
12680
 
12681
+ const FRIENDLY_TRIGGER = { gitlab: "on GitLab activity", github: "on GitHub activity", cron: "on a schedule",
12682
+ manual: "when you run it", hook: "when something calls in", channel: "on a message", form: "from a form", n8n: "when n8n calls" }
12683
+ // Plain words for what the operator needs to know, in the order they care:
12684
+ // has it stopped, is it breaking, is anyone blocked, is it fine.
12685
+ const STATE_LABEL = { dormant: "stopped running", failing: "failing", active: "running normally",
12686
+ quiet: "idle", never: "never run yet" }
12687
+ const STATE_RANK = { dormant: 0, failing: 1, active: 2, quiet: 3, never: 4 }
12688
+ function healthOf(id, myRuns) {
12689
+ const rows = (myRuns || []).map(r => ({ workflowId: id, status: r.status, at: new Date(r.updatedAt).getTime() }))
12690
+ const h = workflowHealth([{ id: id }], rows)[0]
12691
+ return { state: h.state, label: STATE_LABEL[h.state] || h.state, rank: STATE_RANK[h.state] }
12692
+ }
12693
+
12694
+ // The address n8n posts to. Shown, and copyable with a real topic already
12695
+ // in it \u2014 a placeholder like <topic> is not something you can paste.
12696
+ (function n8nPanel() {
12697
+ const el = document.getElementById("wf-n8n-in")
12698
+ if (!el) return
12699
+ const base = location.origin + "/webhook/n8n/"
12700
+ el.textContent = base + "your-topic"
12701
+ // Loopback is exempt from mesh auth; anything else needs the token, and
12702
+ // saying so here saves a silent 401 inside n8n.
12703
+ const local = /^(localhost|127.0.0.1|[::1])$/.test(location.hostname)
12704
+ const auth = document.getElementById("wf-n8n-auth")
12705
+ if (auth) auth.textContent = local
12706
+ ? "n8n on this machine needs no key."
12707
+ : "n8n is off-box, so add the header Authorization: Bearer <your MESH_TOKEN>."
12708
+ const btn = document.getElementById("wf-n8n-copy")
12709
+ if (btn) btn.onclick = async () => {
12710
+ try { await navigator.clipboard.writeText(el.textContent); btn.textContent = "Copied" }
12711
+ catch { btn.textContent = "Copy failed" }
12712
+ setTimeout(() => { btn.textContent = "Copy address" }, 1600)
12713
+ }
12714
+ })()
12715
+
11562
12716
  function renderList() {
11563
12717
  renderProjectFilter()
11564
12718
  const needle = state.filter.toLowerCase()
11565
12719
  const projectFilter = state.projectFilter || ""
11566
- const filtered = state.workflows.filter(wf => {
12720
+ let filtered = state.workflows.filter(wf => {
11567
12721
  const matchesText = !needle || wf.id.toLowerCase().includes(needle) || (wf.title || "").toLowerCase().includes(needle)
11568
12722
  // projectFilter values:
11569
12723
  // "" \u2014 no filter (all projects + global)
@@ -11586,6 +12740,12 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11586
12740
  }
11587
12741
  $("#wf-empty").hidden = true
11588
12742
 
12743
+ // Anything that stopped or is failing comes first: a list sorted by name
12744
+ // hides the one workflow you needed to know about.
12745
+ filtered = filtered.slice().sort((a, b) =>
12746
+ healthOf(a.id, runsByWorkflow[a.id]).rank - healthOf(b.id, runsByWorkflow[b.id]).rank
12747
+ || String(a.title || a.id).localeCompare(String(b.title || b.id)))
12748
+
11589
12749
  $("#wf-list").innerHTML = filtered.map(wf => {
11590
12750
  const myRuns = runsByWorkflow[wf.id] || []
11591
12751
  const live = myRuns.filter(r => r.status === "running").length
@@ -11594,13 +12754,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11594
12754
  // V2: trigger is a node inside wf.nodes, not a workflow-level field.
11595
12755
  const triggerNode = (wf.nodes || []).find(n => n && n.type && n.type.indexOf("trigger.") === 0)
11596
12756
  const triggerSource = triggerNode ? (triggerNode.config && triggerNode.config.source) || triggerNode.type.replace("trigger.", "") : "?"
12757
+ const health = healthOf(wf.id, myRuns)
11597
12758
  return \`
11598
12759
  <li class="ax-wf__card \${isActive ? "is-active" : ""}" data-id="\${wf.id}">
11599
12760
  <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>
12761
+ <div class="ax-wf__card-id">\${esc(wf.id)}</div>
12762
+ <div class="ax-wf__state ax-wf__state--\${health.state}">\${esc(health.label)}</div>
11601
12763
  <div class="ax-wf__card-meta">
11602
12764
  \${wf.project ? \`<span class="tag tag--project" title="Project">\${esc(wf.project)}</span>\` : ""}
11603
- <span class="tag">\${esc(triggerSource)}</span>
12765
+ <span class="tag" title="What starts it">\${esc(FRIENDLY_TRIGGER[triggerSource] || triggerSource)}</span>
11604
12766
  \${live > 0 ? \`<span class="tag live">\${live} running</span>\` : ""}
11605
12767
  \${lastRun
11606
12768
  ? \`<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 +12776,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11614
12776
  })
11615
12777
  }
11616
12778
 
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
12779
  function renderDetail() {
11642
- if (state.selectedDraftId) {
11643
- renderDraftDetail()
11644
- return
11645
- }
11646
12780
  const wf = state.workflows.find(w => w.id === state.selectedId)
11647
12781
  if (!wf) {
11648
12782
  $("#wf-detail-head").innerHTML = \`<span class="hint">Select a workflow to inspect.</span>\`
@@ -11660,6 +12794,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
11660
12794
  $("#wf-detail-head").innerHTML = \`
11661
12795
  <div class="ax-wf__detail-title">
11662
12796
  <h2>\${esc(wf.title || wf.id)}</h2>
12797
+ <a class="ax-wf__btn" href="/workflows/editor?id=\${encodeURIComponent(wf.id)}" title="Open on the canvas">Edit on canvas</a>
11663
12798
  <span class="hint">\${esc(wf.id)} \xB7 v\${wf.version} \xB7 trigger: \${esc(triggerSource)}\${trigFilter ? " \xB7 " + esc(trigFilter) : ""}</span>
11664
12799
  </div>
11665
12800
  <div class="ax-wf__detail-actions">
@@ -12089,69 +13224,6 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12089
13224
  }
12090
13225
  }
12091
13226
 
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
13227
  // --- Run drawer ------------------------------------------------------
12156
13228
 
12157
13229
  async function openRun(runId) {
@@ -12212,22 +13284,11 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12212
13284
 
12213
13285
  async function select(id) {
12214
13286
  state.selectedId = id
12215
- state.selectedDraftId = null
12216
13287
  // Keep URL hash in sync so refreshes and editor deep-links stay on the
12217
13288
  // same workflow. Use replaceState so the browser's back button doesn't
12218
13289
  // accumulate selection history.
12219
13290
  try { history.replaceState(null, "", "#" + encodeURIComponent(id)) } catch (_) { /* */ }
12220
13291
  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
13292
  renderDetail()
12232
13293
  }
12233
13294
 
@@ -12237,126 +13298,23 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12237
13298
  // 10-50KB each \u2014 at limit=100 the listing was multi-MB and gating
12238
13299
  // first paint behind the slowest serialization path). Run-detail
12239
13300
  // and SSE stream still return the full shape unchanged.
12240
- const [workflows, runs, drafts] = await Promise.all([
13301
+ const [workflows, runs] = await Promise.all([
12241
13302
  fetchJSON("/api/workflows"),
12242
13303
  fetchJSON("/api/workflows/runs?limit=100&summary=1"),
12243
- fetchJSON("/api/workflows/drafts"),
12244
13304
  ])
12245
13305
  state.workflows = workflows.workflows || workflows
12246
13306
  state.runs = runs.runs || runs
12247
- state.drafts = drafts.drafts || drafts
12248
13307
  // If the URL hash names a workflow (e.g. /workflows#my-workflow)
12249
13308
  // and nothing is selected yet, auto-select it. Editor's "History"
12250
13309
  // button links here with the hash, so users land on the right detail.
12251
13310
  if (!state.selectedId && location.hash) {
12252
13311
  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
13312
+ if (state.workflows.some(w => w.id === fromHash)) state.selectedId = fromHash
12255
13313
  }
12256
13314
  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
13315
  renderDetail()
12276
13316
  } 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)
13317
+ toast("Failed to load workflows: " + e.message)
12360
13318
  }
12361
13319
  }
12362
13320
 
@@ -12447,7 +13405,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12447
13405
  setInterval(refresh, 15000)
12448
13406
  })
12449
13407
  })();
12450
- `;function Ha(t={}){let e=`<div class="ax-proc__root">
13408
+ `;function Za(t={}){let e=`<div class="ax-proc__root">
12451
13409
  <header class="ax-proc__header">
12452
13410
  <h1>Procedures</h1>
12453
13411
  <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 +13449,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12491
13449
  <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
13450
  <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
13451
  </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=`
13452
+ </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
13453
  .ax-proc__root { padding: 18px 24px 40px; max-width: 1100px; margin: 0 auto; color: var(--ax-text); }
12496
13454
  .ax-proc__header h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
12497
13455
  .ax-proc__header .hint { color: var(--ax-muted); font-size: 12px; margin: 0 0 18px; }
@@ -12517,7 +13475,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12517
13475
  .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
13476
  .ax-proc__link { color: var(--ax-accent, #6366f1); text-decoration: none; font-size: 11px; }
12519
13477
  .ax-proc__link:hover { text-decoration: underline; }
12520
- `,Lo=`
13478
+ `,ds=`
12521
13479
  (function(){
12522
13480
  function $(sel){ return document.querySelector(sel) }
12523
13481
  function esc(s){ return String(s||"").replace(/[&<>"']/g, function(c){ return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c] }) }
@@ -12617,24 +13575,24 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12617
13575
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bootAll)
12618
13576
  else bootAll()
12619
13577
  })();
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)}"
13578
+ `;function en(t){let e=t.agentName||t.agentId,a=`<div class="ax-task-page"
13579
+ data-task-id="${P(t.taskId)}"
13580
+ data-agent-id="${P(t.agentId)}"
13581
+ data-node-url="${P(t.nodeUrl)}"
12624
13582
  data-archived="${t.archived?"1":""}"
12625
- data-ask="${D(t.ask||"")}"
12626
- data-ask-at="${D(t.askAt||"")}">
13583
+ data-ask="${P(t.ask||"")}"
13584
+ data-ask-at="${P(t.askAt||"")}">
12627
13585
 
12628
13586
  <header class="ax-task-page__head">
12629
13587
  <nav class="ax-crumbs" aria-label="Breadcrumb">
12630
13588
  <a href="/live">Live</a>
12631
13589
  <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>
13590
+ <a href="/agents/${P(t.agentId)}/history?node=${encodeURIComponent(t.nodeUrl)}&name=${encodeURIComponent(e)}"><span class="ax-mention">@${P(t.agentId)}</span></a>
12633
13591
  <span class="ax-crumbs__sep">/</span>
12634
13592
  <span class="ax-crumbs__here">Task</span>
12635
13593
  </nav>
12636
13594
  <div class="ax-task-page__meta">
12637
- ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${D(t.channel)}</span>`:""}
13595
+ ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${P(t.channel)}</span>`:""}
12638
13596
  <span class="ax-badge ax-badge--mono" id="task-status">connecting\u2026</span>
12639
13597
  <span class="ax-mono ax-muted" id="task-elapsed"></span>
12640
13598
  </div>
@@ -12660,7 +13618,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12660
13618
  <button type="button" id="task-send" class="ax-btn ax-btn--primary">send \u2192</button>
12661
13619
  </div>
12662
13620
  </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=`
13621
+ </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
13622
  /* The shell gives <main> no padding, so page content butted straight against
12665
13623
  the sticky topbar. Breathe. */
12666
13624
  .ax-task-page {
@@ -12802,7 +13760,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
12802
13760
  line-height: 1.55; text-wrap: pretty; white-space: pre-wrap; word-break: break-word;
12803
13761
  }
12804
13762
 
12805
- `,Do=`
13763
+ `,ps=`
12806
13764
  (function () {
12807
13765
  var root = document.querySelector('.ax-task-page');
12808
13766
  if (!root) return;
@@ -13158,15 +14116,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13158
14116
  if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') { e.preventDefault(); sendBtn.click(); }
13159
14117
  });
13160
14118
  })();
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)}">
14119
+ `;function tn(t){let e=t.agentName||t.agentId,a=`<div class="ax-history"
14120
+ data-agent-id="${P(t.agentId)}"
14121
+ data-agent-name="${P(e)}"
14122
+ data-node-url="${P(t.nodeUrl)}">
13165
14123
  <header class="ax-history__head">
13166
14124
  <nav class="ax-crumbs" aria-label="Breadcrumb">
13167
14125
  <a href="/live">Live</a>
13168
14126
  <span class="ax-crumbs__sep">/</span>
13169
- <span class="ax-mention">@${D(t.agentId)}</span>
14127
+ <span class="ax-mention">@${P(t.agentId)}</span>
13170
14128
  <span class="ax-crumbs__sep">/</span>
13171
14129
  <span class="ax-crumbs__here">History</span>
13172
14130
  </nav>
@@ -13187,7 +14145,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13187
14145
  <div class="ax-history__list" id="hist-list">
13188
14146
  <div class="ax-history__empty">loading\u2026</div>
13189
14147
  </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=`
14148
+ </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
14149
  /* <main> carries no padding in the shell \u2014 without this the breadcrumb sits
13192
14150
  flush against the sticky topbar. */
13193
14151
  .ax-history {
@@ -13239,7 +14197,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13239
14197
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
13240
14198
  }
13241
14199
  .ax-history__foot { margin-top: 6px; font-size: var(--ax-fs-xs); color: var(--ax-muted); font-family: var(--ax-mono); }
13242
- `,Oo=`
14200
+ `,ms=`
13243
14201
  (function () {
13244
14202
  var root = document.querySelector('.ax-history');
13245
14203
  if (!root) return;
@@ -13339,25 +14297,25 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13339
14297
  listEl.innerHTML = '<div class="ax-history__empty" style="color:var(--ax-err)">' + esc(e.message) + '</div>';
13340
14298
  });
13341
14299
  })();
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)}
14300
+ `;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
14301
 
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)}
14302
+ `);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
14303
 
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}
14304
+ `)}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(`
14305
+ Live dashboard: http://${b}:${n}
13348
14306
  `),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
14307
+ Kanban dashboard: http://${b}:${n}
14308
+ `),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-LRYV3QLK.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
14309
 
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(`
14310
+ `)}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
14311
 
13354
- `))>=0;){let K=P.slice(0,R);if(P=P.slice(R+2),x.flag)break;try{e.write(K+`
14312
+ `))>=0;){let J=D.slice(0,R);if(D=D.slice(R+2),f.flag)break;try{e.write(J+`
13355
14313
 
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)}
14314
+ `)}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})+`
14315
+ `;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}
14316
+ data: ${JSON.stringify(i)}
13359
14317
 
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=`
14318
+ `)},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
14319
  You are helping draft a new GitLab issue. Follow these conventions strictly.
13362
14320
 
13363
14321
  Title pattern:
@@ -13389,16 +14347,16 @@ Return ONLY a single JSON object on one line \u2014 no prose, no code fences, no
13389
14347
  Shape:
13390
14348
  { "title": string, "description": string, "labels": string[], "assigneeUsername": string | null, "kind": string }
13391
14349
  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):
14350
+ `;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
14351
  - ${r.knownLabels.slice(0,60).join(`
13394
14352
  - `)}`:"",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}
14353
+ `),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
14354
 
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," ")}
14355
+ `);let s=a(r,o,{stdio:["ignore","pipe","pipe"]}),l="",i=m=>{l+=m.toString("utf8");let x;for(;(x=l.indexOf(`
14356
+ `))>=0;){let b=l.slice(0,x).replace(/\r$/,"");l=l.slice(x+1);try{e.write(`event: line
14357
+ data: ${b.replace(/\n/g," ")}
13400
14358
 
13401
- `)}catch{}}};s.stdout?.on("data",l),s.stderr?.on("data",l);let d=setInterval(()=>{try{e.write(`: hb
14359
+ `)}catch{}}};s.stdout?.on("data",i),s.stderr?.on("data",i);let c=setInterval(()=>{try{e.write(`: hb
13402
14360
 
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
14361
+ `)}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};
14362
+ //# sourceMappingURL=board-dashboard-QR7CVTKA.js.map