agentix-cli 0.64.0 → 0.66.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 (48) hide show
  1. package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +29 -8
  2. package/apps/mac-voice/Sources/AgentXVoice/MiniOrbs.swift +219 -0
  3. package/apps/mac-voice/Sources/AgentXVoice/Panel.swift +32 -3
  4. package/apps/mac-voice/Sources/AgentXVoice/PillBusy.swift +126 -0
  5. package/apps/mac-voice/Sources/AgentXVoice/StatusMenu.swift +53 -12
  6. package/apps/mac-voice/Sources/AgentXVoice/main.swift +49 -3
  7. package/dist/{agent-3M5EI4S6.js → agent-BQ5CCARE.js} +2 -2
  8. package/dist/{board-dashboard-JBRO26JC.js → board-dashboard-K3P2M7A7.js} +877 -375
  9. package/dist/board-dashboard-K3P2M7A7.js.map +1 -0
  10. package/dist/{chunk-WWMFNLKD.js → chunk-2NYP4OQU.js} +3 -3
  11. package/dist/chunk-2NYP4OQU.js.map +1 -0
  12. package/dist/{chunk-KZDG26LI.js → chunk-6CFAF5CH.js} +2 -2
  13. package/dist/{chunk-VUB6XYWD.js → chunk-AWKZ3BF2.js} +54 -54
  14. package/dist/chunk-AWKZ3BF2.js.map +1 -0
  15. package/dist/{chunk-HYKILAEJ.js → chunk-BBXBSM4R.js} +183 -183
  16. package/dist/chunk-BBXBSM4R.js.map +1 -0
  17. package/dist/{chunk-VVQDKHF5.js → chunk-EPTZ6JMA.js} +4 -4
  18. package/dist/chunk-JWDJMFU6.js +4 -0
  19. package/dist/chunk-JWDJMFU6.js.map +1 -0
  20. package/dist/{chunk-S2VETB7B.js → chunk-YDHI2CJG.js} +26 -26
  21. package/dist/chunk-YDHI2CJG.js.map +1 -0
  22. package/dist/{chunk-NNXHRO7H.js → chunk-ZIEUP56T.js} +17 -17
  23. package/dist/chunk-ZIEUP56T.js.map +1 -0
  24. package/dist/cli.js +1 -1
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.js +1 -1
  27. package/dist/{program-FSRL275V.js → program-4W45H3J2.js} +2 -2
  28. package/dist/push-announce-PM5FZJRW.js +3 -0
  29. package/dist/push-announce-PM5FZJRW.js.map +1 -0
  30. package/dist/push-prefs-YOJNTOJF.js +2 -0
  31. package/dist/push-store-5VJ4FNI4.js +2 -0
  32. package/dist/registry-TERSIHOC.js +2 -0
  33. package/dist/registry-TERSIHOC.js.map +1 -0
  34. package/package.json +1 -1
  35. package/dist/board-dashboard-JBRO26JC.js.map +0 -1
  36. package/dist/chunk-HYKILAEJ.js.map +0 -1
  37. package/dist/chunk-NNXHRO7H.js.map +0 -1
  38. package/dist/chunk-S2VETB7B.js.map +0 -1
  39. package/dist/chunk-VUB6XYWD.js.map +0 -1
  40. package/dist/chunk-WWMFNLKD.js.map +0 -1
  41. package/dist/push-store-LXTYULUF.js +0 -2
  42. package/dist/registry-T4R7LVFZ.js +0 -2
  43. /package/dist/{agent-3M5EI4S6.js.map → agent-BQ5CCARE.js.map} +0 -0
  44. /package/dist/{chunk-KZDG26LI.js.map → chunk-6CFAF5CH.js.map} +0 -0
  45. /package/dist/{chunk-VVQDKHF5.js.map → chunk-EPTZ6JMA.js.map} +0 -0
  46. /package/dist/{program-FSRL275V.js.map → program-4W45H3J2.js.map} +0 -0
  47. /package/dist/{push-store-LXTYULUF.js.map → push-prefs-YOJNTOJF.js.map} +0 -0
  48. /package/dist/{registry-T4R7LVFZ.js.map → push-store-5VJ4FNI4.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import{a as Fa}from"./chunk-WWMFNLKD.js";import{a as Ka}from"./chunk-62EJKQFX.js";import{a as C,b as Ja,c as Va,d as Ya,e as Qa,h as Za,i as Ce,j as en,k as tn,l as nn,m as rn,n as on}from"./chunk-WMDDQVCI.js";import{a as an}from"./chunk-Z3IP66SL.js";import{a as Ua,b as te,c as qa,d as $,e as P,j as Ze,k as et,l as ae,m as U,n as tt,o as Wa,p as Ga,q as Xa}from"./chunk-C4CDVE2E.js";import{A as Ge,B as Xe,Ba as Te,C as Ta,Ca as Ke,D as Ca,Da as Je,Ea as Ve,Fa as Ye,Ga as Na,Ha as Da,Ia as Ha,Ja as Qe,K as ee,L as Aa,La as Ba,M as Ma,Oa as za,X as La,Y as Ra,Z as ja,a as xa,c as We,d as _t,e as va,i as ba,k as ya,m as Z,n as ve,o as _a,p as Et,sa as Pa,ua as St,za as Oa}from"./chunk-S2VETB7B.js";import{g as ha,h as ga}from"./chunk-5QP56S4O.js";import{p as wa,s as ka}from"./chunk-BYJ3A55Y.js";import{a as Ia,b as $a}from"./chunk-LQRBGQIR.js";import"./chunk-I2SD4XZ6.js";import"./chunk-XT3E5MLX.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as Ea,c as Sa}from"./chunk-2D3RYIDU.js";import{a as ca,c as wt,d as kt,h as da,i as pa,j as ua,p as ma,q as he,r as fa}from"./chunk-NNXHRO7H.js";import"./chunk-WP6KLXTP.js";import{a as qe}from"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import"./chunk-BHE5TJSN.js";import"./chunk-EA7H3EUX.js";import"./chunk-AFRHKA7B.js";import"./chunk-QD6IICK7.js";import"./chunk-AZBOYKQA.js";import{b as la}from"./chunk-WGWNVLVW.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import"./chunk-PTB2TPOC.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-FX3D7YON.js";import"./chunk-QOYAX2FT.js";import"./chunk-SZJMS7K4.js";import"./chunk-7I7IEX4S.js";import{a as sa,b as ia,c as Fo,w as Q,z as yt}from"./chunk-OVF37EXJ.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";function Tt(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 sn(t,e,a=Date.now()){return t.map((n,r)=>({i:r,s:Tt(n,e,a).score})).sort((n,r)=>r.s-n.s||n.i-r.i).map(n=>n.i)}var ne={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"/>'},be=(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>",at=(t,e,a,n="")=>'<div class="ax-sec-label"><h3>'+be(t,13)+e+(a?'<span class="ax-sec-label__n" id="'+a+'"></span>':"")+"</h3>"+n+"</div>";function ln(t={}){return $({title:"AgentX \xB7 Monitor",activeTab:"monitor",subtitle:"Monitor",peers:t.peers,body:`<div class="bf">
1
+ import{a as Va}from"./chunk-2NYP4OQU.js";import{a as se,b as Ja}from"./chunk-JWDJMFU6.js";import{a as an}from"./chunk-62EJKQFX.js";import{a as A,b as nn,c as rn,d as on,e as sn,h as ln,i as Ie,j as cn,k as dn,l as un,m as mn,n as fn}from"./chunk-WMDDQVCI.js";import{a as pn}from"./chunk-Z3IP66SL.js";import{a as Ya,b as V,c as Qa,d as L,e as j,j as et,k as tt,l as ne,m as U,n as at,o as Za,p as en,q as tn}from"./chunk-C4CDVE2E.js";import{A as Xe,B as Ke,Ba as Me,C as Ra,Ca as Je,D as Pa,Da as Ve,Ea as Ye,Fa as Qe,Ga as Ua,Ha as Wa,Ia as Ga,Ja as Ze,K as q,L as ja,La as Xa,M as Oa,Oa as Ka,X as Ha,Y as Ba,Z as za,a as Ea,c as Ge,d as St,e as Sa,i as Ta,k as Aa,m as ae,n as be,o as Ia,p as Tt,sa as Fa,ua as At,za as qa}from"./chunk-YDHI2CJG.js";import{g as ka,h as _a}from"./chunk-5QP56S4O.js";import{p as Ca,s as Ma}from"./chunk-BYJ3A55Y.js";import{a as Na,b as Da}from"./chunk-LQRBGQIR.js";import"./chunk-I2SD4XZ6.js";import"./chunk-XT3E5MLX.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as La,c as $a}from"./chunk-2D3RYIDU.js";import{a as ha,c as _t,d as Et,h as ga,i as xa,j as va,p as ba,q as ya,r as ge,s as wa}from"./chunk-ZIEUP56T.js";import{a as Ce}from"./chunk-N6EWZGIX.js";import"./chunk-WP6KLXTP.js";import"./chunk-DP7RTNDM.js";import"./chunk-BHE5TJSN.js";import"./chunk-EA7H3EUX.js";import"./chunk-AFRHKA7B.js";import"./chunk-QD6IICK7.js";import"./chunk-AZBOYKQA.js";import{b as fa}from"./chunk-WGWNVLVW.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import"./chunk-PTB2TPOC.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-FX3D7YON.js";import"./chunk-QOYAX2FT.js";import"./chunk-SZJMS7K4.js";import"./chunk-7I7IEX4S.js";import{a as ua,b as ma,c as xs,w as te,z as kt}from"./chunk-OVF37EXJ.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";function Ct(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 hn(t,e,a=Date.now()){return t.map((n,r)=>({i:r,s:Ct(n,e,a).score})).sort((n,r)=>r.s-n.s||n.i-r.i).map(n=>n.i)}var re={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"/>'},ye=(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>",nt=(t,e,a,n="")=>'<div class="ax-sec-label"><h3>'+ye(t,13)+e+(a?'<span class="ax-sec-label__n" id="'+a+'"></span>':"")+"</h3>"+n+"</div>";function gn(t={}){return L({title:"AgentX \xB7 Monitor",activeTab:"monitor",subtitle:"Monitor",peers:t.peers,body:`<div class="bf">
2
2
 
3
3
  <div class="bf-head">
4
4
  <div>
@@ -7,8 +7,8 @@ import{a as Fa}from"./chunk-WWMFNLKD.js";import{a as Ka}from"./chunk-62EJKQFX.js
7
7
  </div>
8
8
  <div class="bf-sync">
9
9
  <span class="bf-sync__t" id="synced">Gathering&hellip;</span>
10
- <a class="ax-btn ax-btn--sm" href="/activity" title="What ran, and when">${be(ne.pulse,13)} Activity</a>
11
- <button class="ax-btn" id="refresh" title="Refresh now">${be(ne.refresh)} Refresh</button>
10
+ <a class="ax-btn ax-btn--sm" href="/activity" title="What ran, and when">${ye(re.pulse,13)} Activity</a>
11
+ <button class="ax-btn" id="refresh" title="Refresh now">${ye(re.refresh)} Refresh</button>
12
12
  </div>
13
13
  </div>
14
14
 
@@ -21,24 +21,24 @@ import{a as Fa}from"./chunk-WWMFNLKD.js";import{a as Ka}from"./chunk-62EJKQFX.js
21
21
 
22
22
  <div class="bf-grid">
23
23
  <section class="bf-col">
24
- ${at(ne.alert,"Only you","you-count",'<span class="bf-why">needs your authority, your relationship, or something the system cannot know</span><button class="ax-btn ax-btn--sm" id="clear-actions" title="Mark every open action done on every node">Clear all</button>')}
24
+ ${nt(re.alert,"Only you","you-count",'<span class="bf-why">needs your authority, your relationship, or something the system cannot know</span><button class="ax-btn ax-btn--sm" id="clear-actions" title="Mark every open action done on every node">Clear all</button>')}
25
25
  <div id="you" class="bf-col"></div>
26
26
 
27
- ${at(ne.plug,"Agents can handle","agents-count",'<span class="bf-why">no human needed &mdash; not yet automatic</span>')}
27
+ ${nt(re.plug,"Agents can handle","agents-count",'<span class="bf-why">no human needed &mdash; not yet automatic</span>')}
28
28
  <div id="agents" class="bf-col"></div>
29
29
  <button class="ax-btn ax-btn--sm" id="more-actions" hidden></button>
30
30
 
31
31
  <div id="handled"></div>
32
32
  </section>
33
33
  <aside class="bf-col">
34
- ${at(ne.pulse,"In motion","run-count")}
34
+ ${nt(re.pulse,"In motion","run-count")}
35
35
  <div id="running" class="bf-col"></div>
36
36
  </aside>
37
37
  </div>
38
38
 
39
- ${at(ne.file,"Session briefings","brief-count")}
39
+ ${nt(re.file,"Session briefings","brief-count")}
40
40
  <div class="bf-toolbar">
41
- <div class="bf-search">${be(ne.search)}
41
+ <div class="bf-search">${ye(re.search)}
42
42
  <input id="search" type="search" placeholder="Search sessions&hellip;" aria-label="Search sessions">
43
43
  </div>
44
44
  <div class="bf-filters" id="filters" role="group" aria-label="Filter briefings"></div>
@@ -46,15 +46,15 @@ ${at(ne.file,"Session briefings","brief-count")}
46
46
  <div id="reviews" class="bf-col"></div>
47
47
 
48
48
  <section class="ax-panel bf-connect">
49
- <div class="bf-connect__head">${be(ne.plug,17)}<h2>Connect a CLI session</h2>
49
+ <div class="bf-connect__head">${ye(re.plug,17)}<h2>Connect a CLI session</h2>
50
50
  <span class="bf-connect__note">Daemon-owned processes only</span></div>
51
51
  <div class="bf-discover">
52
52
  <div class="ax-field"><label for="node">Node</label><select id="node"></select></div>
53
- <button class="ax-btn" id="discover">${be(ne.search)} Discover CLIs</button>
53
+ <button class="ax-btn" id="discover">${ye(re.search)} Discover CLIs</button>
54
54
  </div>
55
55
  <div class="bf-cli" id="discovered"></div>
56
56
  <details class="bf-manual">
57
- <summary>${be(ne.chev,12)} Register manually</summary>
57
+ <summary>${ye(re.chev,12)} Register manually</summary>
58
58
  <div class="bf-forms">
59
59
  <form id="register" class="bf-form">
60
60
  <div class="ax-sec-label"><h3>Register a session</h3></div>
@@ -85,7 +85,7 @@ ${at(ne.file,"Session briefings","brief-count")}
85
85
  </div>
86
86
  </details>
87
87
  </section>
88
- </div>`,css:Uo,scripts:`<script>${te({decayOf:Tt,rankByDecay:sn})}const ICON = ${JSON.stringify(ne)};${qo}</script>`})}var Uo=`
88
+ </div>`,css:vs,scripts:`<script>${V({decayOf:Ct,rankByDecay:hn})}const ICON = ${JSON.stringify(re)};${bs}</script>`})}var vs=`
89
89
  .bf{max-width:1240px;margin:0 auto;padding:22px 24px 48px}
90
90
  .bf-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
91
91
  .bf :focus-visible{outline:2px solid var(--ax-accent);outline-offset:2px;border-radius:4px}
@@ -361,7 +361,7 @@ button.bf-tag.is-on{background:color-mix(in oklch,var(--ax-accent) 14%,transpare
361
361
  .bf{padding:16px 14px 36px}
362
362
  .bf-head{flex-direction:column;gap:14px;align-items:stretch}
363
363
  .bf-sync{justify-content:space-between}
364
- }`,qo=String.raw`
364
+ }`,bs=String.raw`
365
365
  (function(){
366
366
  const $=id=>document.getElementById(id), esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
367
367
  const ic=(n,s)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+(s||14)+'" height="'+(s||14)+'" aria-hidden="true">'+ICON[n]+'</svg>';
@@ -776,22 +776,22 @@ if(document.querySelector('form :focus'))return;
776
776
  if(document.querySelector('.bf-trace[open]'))return; // don't yank an open trace
777
777
  refresh();
778
778
  },15000);
779
- })();`;function Ct(t,e=20*6e4,a=6){let n=[...t].sort((l,c)=>l.startedAt-c.startedAt);if(!n.length)return{bands:[],gaps:[]};let r=[];for(let l of n){let c=l.startedAt+Math.max(l.durationMs||0,0),p=r[r.length-1];p&&l.startedAt-p.to<=e?(p.to=Math.max(p.to,c),p.runs++):r.push({from:l.startedAt,to:c,runs:1})}for(;r.length>a;){let l=0,c=1/0;for(let p=1;p<r.length;p++){let u=r[p].from-r[p-1].to;u<c&&(c=u,l=p)}r[l-1].to=r[l].to,r[l-1].runs+=r[l].runs,r.splice(l,1)}let o=r.reduce((l,c)=>l+c.runs,0)||1,s=r.map(l=>({from:l.from,to:Math.max(l.to,l.from+1),weight:l.runs/o,runs:l.runs})),i=r.slice(1).map((l,c)=>l.from-r[c].to);return{bands:s,gaps:i}}function At(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 cn(t,e=[],a){let{bands:n,gaps:r}=Ct(t,a);if(!n.length)return{bands:[],gaps:[],lanes:[],from:0,to:0};let o=new Map;for(let l of e){let c=o.get(l.runId);c?c.push(l):o.set(l.runId,[l])}let s=new Map;for(let l of t){let c=n.findIndex(T=>l.startedAt>=T.from&&l.startedAt<=T.to);if(c===-1)continue;let p=n[c],u=p.to-p.from||1,f=(l.startedAt-p.from)/u*100,h=Math.min(Math.max((l.durationMs||0)/u*100,1.2),100-f),y=s.get(l.laneKey)??{key:l.laneKey,label:l.laneLabel,sub:l.laneSub,tracks:1,runs:[]};y.runs.push({...l,band:c,track:0,left:f,width:h,marks:o.get(l.id)??[]}),s.set(l.laneKey,y)}let i=[...s.values()];for(let l of i)l.tracks=Math.max(...n.map((c,p)=>At(l.runs.filter(u=>u.band===p))),1);return i.sort((l,c)=>c.runs.length-l.runs.length||l.label.localeCompare(c.label)),{bands:n,gaps:r,lanes:i,from:n[0].from,to:n[n.length-1].to}}import{createHash as Wo}from"crypto";import{readFileSync as Go,statSync as Xo}from"fs";import{resolve as Ko,dirname as Jo}from"path";import{fileURLToPath as Vo}from"url";var dn=new Map;function nt(t){let e=dn.get(t);if(e)return e;let a=`/assets/${t}`;try{let n=Jo(Vo(import.meta.url)),r=Ko(n,"web",t),o=Xo(r),s=o.size<8e6?Wo("sha1").update(Go(r)).digest("hex").slice(0,10):`${o.size}-${Math.floor(o.mtimeMs)}`;a=`/assets/${t}?v=${s}`}catch{}return dn.set(t,a),a}var oe={refresh:'<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>',bot:'<rect x="4" y="8" width="16" height="12" rx="2"/><path d="M12 8V5M9 14h.01M15 14h.01"/>',user:'<circle cx="12" cy="8" r="3.5"/><path d="M5 21a7 7 0 0 1 14 0"/>',folder:'<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',map:'<path d="M9 4 3 6v14l6-2 6 2 6-2V4l-6 2-6-2z"/><path d="M9 4v14M15 6v14"/>',timeline:'<path d="M3 6h10M7 12h14M3 18h8"/>',mesh:'<circle cx="5" cy="19" r="2.5"/><circle cx="19" cy="19" r="2.5"/><circle cx="12" cy="5" r="2.5"/><path d="M7 17.5l4-10M17 17.5l-4-10"/>',route:'<circle cx="6" cy="6" r="3"/><circle cx="18" cy="18" r="3"/><path d="M9 6h6a3 3 0 0 1 0 6H9a3 3 0 0 0 0 6h6"/>',clock:'<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',x:'<path d="M18 6L6 18M6 6l12 12"/>',alert:'<path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/>'},rt=(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>",Yo=[["agent","Agent",oe.bot],["client","Client",oe.user],["project","Project",oe.folder],["channel","Channel",oe.route],["node","Node",oe.mesh]],pn={timeline:"Every run on the mesh, from task traces. The axis breaks over silence &mdash; quiet stretches are labelled, not drawn.",map:"The fleet as a transit map: projects are lines, agents are stations, work in flight is a train. Live."};function un(t={}){let e=t.view==="map"?"map":"timeline",a=e==="map";return $({title:"AgentX \xB7 Activity",activeTab:"activity",subtitle:"Activity",peers:t.peers,body:`<div class="ac">
779
+ })();`;function Mt(t,e=20*6e4,a=6){let n=[...t].sort((l,c)=>l.startedAt-c.startedAt);if(!n.length)return{bands:[],gaps:[]};let r=[];for(let l of n){let c=l.startedAt+Math.max(l.durationMs||0,0),p=r[r.length-1];p&&l.startedAt-p.to<=e?(p.to=Math.max(p.to,c),p.runs++):r.push({from:l.startedAt,to:c,runs:1})}for(;r.length>a;){let l=0,c=1/0;for(let p=1;p<r.length;p++){let u=r[p].from-r[p-1].to;u<c&&(c=u,l=p)}r[l-1].to=r[l].to,r[l-1].runs+=r[l].runs,r.splice(l,1)}let o=r.reduce((l,c)=>l+c.runs,0)||1,s=r.map(l=>({from:l.from,to:Math.max(l.to,l.from+1),weight:l.runs/o,runs:l.runs})),i=r.slice(1).map((l,c)=>l.from-r[c].to);return{bands:s,gaps:i}}function It(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 xn(t,e=[],a){let{bands:n,gaps:r}=Mt(t,a);if(!n.length)return{bands:[],gaps:[],lanes:[],from:0,to:0};let o=new Map;for(let l of e){let c=o.get(l.runId);c?c.push(l):o.set(l.runId,[l])}let s=new Map;for(let l of t){let c=n.findIndex(T=>l.startedAt>=T.from&&l.startedAt<=T.to);if(c===-1)continue;let p=n[c],u=p.to-p.from||1,f=(l.startedAt-p.from)/u*100,h=Math.min(Math.max((l.durationMs||0)/u*100,1.2),100-f),v=s.get(l.laneKey)??{key:l.laneKey,label:l.laneLabel,sub:l.laneSub,tracks:1,runs:[]};v.runs.push({...l,band:c,track:0,left:f,width:h,marks:o.get(l.id)??[]}),s.set(l.laneKey,v)}let i=[...s.values()];for(let l of i)l.tracks=Math.max(...n.map((c,p)=>It(l.runs.filter(u=>u.band===p))),1);return i.sort((l,c)=>c.runs.length-l.runs.length||l.label.localeCompare(c.label)),{bands:n,gaps:r,lanes:i,from:n[0].from,to:n[n.length-1].to}}import{createHash as ys}from"crypto";import{readFileSync as ws,statSync as ks}from"fs";import{resolve as _s,dirname as Es}from"path";import{fileURLToPath as Ss}from"url";var vn=new Map;function rt(t){let e=vn.get(t);if(e)return e;let a=`/assets/${t}`;try{let n=Es(Ss(import.meta.url)),r=_s(n,"web",t),o=ks(r),s=o.size<8e6?ys("sha1").update(ws(r)).digest("hex").slice(0,10):`${o.size}-${Math.floor(o.mtimeMs)}`;a=`/assets/${t}?v=${s}`}catch{}return vn.set(t,a),a}var ie={refresh:'<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>',bot:'<rect x="4" y="8" width="16" height="12" rx="2"/><path d="M12 8V5M9 14h.01M15 14h.01"/>',user:'<circle cx="12" cy="8" r="3.5"/><path d="M5 21a7 7 0 0 1 14 0"/>',folder:'<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',map:'<path d="M9 4 3 6v14l6-2 6 2 6-2V4l-6 2-6-2z"/><path d="M9 4v14M15 6v14"/>',timeline:'<path d="M3 6h10M7 12h14M3 18h8"/>',mesh:'<circle cx="5" cy="19" r="2.5"/><circle cx="19" cy="19" r="2.5"/><circle cx="12" cy="5" r="2.5"/><path d="M7 17.5l4-10M17 17.5l-4-10"/>',route:'<circle cx="6" cy="6" r="3"/><circle cx="18" cy="18" r="3"/><path d="M9 6h6a3 3 0 0 1 0 6H9a3 3 0 0 0 0 6h6"/>',clock:'<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',x:'<path d="M18 6L6 18M6 6l12 12"/>',alert:'<path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/>'},ot=(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>",Ts=[["agent","Agent",ie.bot],["client","Client",ie.user],["project","Project",ie.folder],["channel","Channel",ie.route],["node","Node",ie.mesh]],bn={timeline:"Every run on the mesh, from task traces. The axis breaks over silence &mdash; quiet stretches are labelled, not drawn.",map:"The fleet as a transit map: projects are lines, agents are stations, work in flight is a train. Live."};function yn(t={}){let e=t.view==="map"?"map":"timeline",a=e==="map";return L({title:"AgentX \xB7 Activity",activeTab:"activity",subtitle:"Activity",peers:t.peers,body:`<div class="ac">
780
780
 
781
781
  <div class="ac-head">
782
782
  <div>
783
783
  <div class="ac-kicker">Operations</div>
784
784
  <h1>What ran, where, and what it decided</h1>
785
- <p class="ac-sub" id="sub">${pn[e]}</p>
785
+ <p class="ac-sub" id="sub">${bn[e]}</p>
786
786
  </div>
787
787
  <div class="ac-tools">
788
788
  <div class="ac-seg" id="view" role="radiogroup" aria-label="View">
789
- ${[["timeline","Timeline",oe.timeline],["map","Map",oe.map]].map(([n,r,o])=>`<button type="button" role="radio" data-value="${n}" aria-checked="${n===e}"${n===e?' class="is-on"':""}>${rt(o,13)}${r}</button>`).join("")}
789
+ ${[["timeline","Timeline",ie.timeline],["map","Map",ie.map]].map(([n,r,o])=>`<button type="button" role="radio" data-value="${n}" aria-checked="${n===e}"${n===e?' class="is-on"':""}>${ot(o,13)}${r}</button>`).join("")}
790
790
  </div>
791
791
  <div class="ac-seg" id="hours" role="radiogroup" aria-label="Window">
792
792
  ${[["6","6h"],["24","24h"],["72","3d"],["168","7d"]].map(([n,r],o)=>`<button type="button" role="radio" data-value="${n}" aria-checked="${o===1}"${o===1?' class="is-on"':""}>${r}</button>`).join("")}
793
793
  </div>
794
- <button class="ax-btn ax-btn--sm" id="refresh"${a?" hidden":""}>${rt(oe.refresh,13)} Refresh</button>
794
+ <button class="ax-btn ax-btn--sm" id="refresh"${a?" hidden":""}>${ot(ie.refresh,13)} Refresh</button>
795
795
  </div>
796
796
  </div>
797
797
 
@@ -799,14 +799,14 @@ refresh();
799
799
  <div class="ac-bar">
800
800
  <span class="ac-lbl">Lanes by</span>
801
801
  <div class="ac-seg" id="persp" role="radiogroup" aria-label="Perspective">
802
- ${Yo.map(([n,r,o],s)=>`<button type="button" role="radio" data-value="${n}" aria-checked="${s===0}"${s===0?' class="is-on"':""}>${rt(o,13)}${r}</button>`).join("")}
802
+ ${Ts.map(([n,r,o],s)=>`<button type="button" role="radio" data-value="${n}" aria-checked="${s===0}"${s===0?' class="is-on"':""}>${ot(o,13)}${r}</button>`).join("")}
803
803
  </div>
804
804
  <div class="ac-key">
805
805
  <span class="ac-k"><i class="ac-d ac-d--decision"></i>decision</span>
806
806
  <span class="ac-k"><i class="ac-d ac-d--warning"></i>warning</span>
807
807
  <span class="ac-k"><i class="ac-d ac-d--recommendation"></i>friction</span>
808
808
  <span class="ac-k"><i class="ac-d ac-d--later"></i>do later</span>
809
- <span class="ac-k">${rt(oe.x,11)}canceled</span>
809
+ <span class="ac-k">${ot(ie.x,11)}canceled</span>
810
810
  </div>
811
811
  </div>
812
812
 
@@ -816,10 +816,10 @@ refresh();
816
816
  </div>
817
817
 
818
818
  <div id="view-map" class="ac-map"${a?"":" hidden"}>
819
- <div id="ax-fleet-root" data-hours="24" data-src="${nt("activity-graph.global.js")}"></div>
819
+ <div id="ax-fleet-root" data-hours="24" data-src="${rt("activity-graph.global.js")}"></div>
820
820
  </div>
821
821
 
822
- </div>`,css:Qo,scripts:`<script>${te({computeBands:Ct,packTracks:At,buildTimeline:cn})}const ICON = ${JSON.stringify(oe)};const SUB = ${JSON.stringify(pn)};${Zo}</script>`})}var Qo=`
822
+ </div>`,css:As,scripts:`<script>${V({computeBands:Mt,packTracks:It,buildTimeline:xn})}const ICON = ${JSON.stringify(ie)};const SUB = ${JSON.stringify(bn)};${Cs}</script>`})}var As=`
823
823
  .ac{max-width:1440px;margin:0 auto;padding:22px 24px 48px}
824
824
  .ac :focus-visible{outline:2px solid var(--ax-accent);outline-offset:2px;border-radius:4px}
825
825
  .ac-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:14px}
@@ -905,7 +905,7 @@ refresh();
905
905
  @media (max-width:640px){.ac{padding:16px 16px 32px}.ac-head{flex-direction:column;gap:10px}
906
906
  .ac-tools{flex-wrap:wrap;padding-top:0}.ac-map{height:calc(100vh - 250px);margin:0 -16px;
907
907
  border-left:none;border-right:none;border-radius:0}}
908
- `,Zo=String.raw`
908
+ `,Cs=String.raw`
909
909
  const $=id=>document.getElementById(id);
910
910
  const esc=s=>String(s==null?'':s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
911
911
  const ic=(n,s)=>'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="'+(s||14)+'" height="'+(s||14)+'" aria-hidden="true">'+ICON[n]+'</svg>';
@@ -1022,7 +1022,7 @@ history.replaceState(null,'',u);
1022
1022
  if(v==='map')ensureMap();else if(!loaded){loaded=true;load();}}
1023
1023
  $('view').addEventListener('click',e=>{const b=e.target.closest('button[data-value]');if(!b||b.dataset.value===view)return;show(b.dataset.value);});
1024
1024
  show(view);
1025
- `;function mn(t={}){let e='<div id="wfe-root" style="height:100%"></div>';return $({title:"AgentX \xB7 Workflow editor",activeTab:"workflows",subtitle:"Workflow editor",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:es,scripts:`<script src="${nt("workflow-editor.global.js")}" defer></script>`,noMain:!0})}var es=`
1025
+ `;function wn(t={}){let e='<div id="wfe-root" style="height:100%"></div>';return L({title:"AgentX \xB7 Workflow editor",activeTab:"workflows",subtitle:"Workflow editor",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Ms,scripts:`<script src="${rt("workflow-editor.global.js")}" defer></script>`,noMain:!0})}var Ms=`
1026
1026
  /* Preload the fonts the redesign's CSS references. Placed in the shell so
1027
1027
  * they start fetching while the React bundle is still parsing. */
1028
1028
  @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");
@@ -1043,10 +1043,10 @@ body { margin: 0; overflow: hidden; }
1043
1043
  font: 13px/1 -apple-system, BlinkMacSystemFont, sans-serif;
1044
1044
  text-align: center;
1045
1045
  }
1046
- `;import{createServer as sd}from"http";import{appendFileSync as id,existsSync as Po,mkdirSync as ld}from"fs";import{readFile as cd}from"fs/promises";import{fileURLToPath as dd}from"url";import{dirname as pd,resolve as ze}from"path";Fo();var fn='/*! 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 ot,readFileSync as gn,writeFileSync as xn,rmSync as mp,mkdirSync as ss,copyFileSync as is,readdirSync as ls}from"fs";import{resolve as Ae}from"path";yt();var se={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 hn(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=Ze({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.`})+et([{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 $({title:"AgentX \xB7 Settings",activeTab:"admin",subtitle:"Settings",peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a+as()+Wa,css:rs,scripts:`${e}<script>${Ga}
1047
- ${Xa}
1048
- ${ts}
1049
- ${os}</script>`})}var ts=`
1046
+ `;import{createServer as zd}from"http";import{appendFileSync as Fd,existsSync as cs,mkdirSync as qd}from"fs";import{readFile as Ud}from"fs/promises";import{fileURLToPath as Wd}from"url";import{dirname as Gd,resolve as qe}from"path";xs();var kn='/*! 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 st,readFileSync as En,writeFileSync as Sn,rmSync as Kp,mkdirSync as js,copyFileSync as Os,readdirSync as Ns}from"fs";import{resolve as Le}from"path";kt();var le={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 _n(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=et({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.`})+tt([{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 L({title:"AgentX \xB7 Settings",activeTab:"admin",subtitle:"Settings",peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a+Ls()+Za,css:Rs,scripts:`${e}<script>${en}
1047
+ ${tn}
1048
+ ${Is}
1049
+ ${Ps}</script>`})}var Is=`
1050
1050
  (function(){
1051
1051
  function fmt(n) { return n == null ? '\u2014' : String(n); }
1052
1052
  async function refresh() {
@@ -1107,8 +1107,8 @@ ${os}</script>`})}var ts=`
1107
1107
  refresh();
1108
1108
  // Refresh again after the main admin script has had a chance to mutate config.
1109
1109
  document.addEventListener('ax-config-saved', refresh);
1110
- })();`;function as(){let t=$a().business?`<button data-tab="business">Business</button>
1111
- `:"";return ns.replace("__BUSINESS_TABS__",t)}var ns=`
1110
+ })();`;function Ls(){let t=Da().business?`<button data-tab="business">Business</button>
1111
+ `:"";return $s.replace("__BUSINESS_TABS__",t)}var $s=`
1112
1112
  <div id="peer-banner" class="peer-banner">
1113
1113
  <span class="label">Managing</span>
1114
1114
  <span class="name" id="peer-banner-name">\u2014</span>
@@ -1251,8 +1251,8 @@ ${os}</script>`})}var ts=`
1251
1251
  <div id="global-msg" class="msg"></div>
1252
1252
 
1253
1253
  <section id="tab-agents" class="tab active">
1254
- ${U({icon:se.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."})}
1255
- ${ae({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>).`})}
1254
+ ${U({icon:le.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."})}
1255
+ ${ne({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>).`})}
1256
1256
  <div id="agent-list" class="ax-stack"></div>
1257
1257
  <div class="add-form">
1258
1258
  <h3>Add a new agent</h3>
@@ -1274,8 +1274,8 @@ ${os}</script>`})}var ts=`
1274
1274
  </section>
1275
1275
 
1276
1276
  <section id="tab-channels" class="tab">
1277
- ${U({icon:se.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."})}
1278
- ${ae({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."})}
1277
+ ${U({icon:le.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."})}
1278
+ ${ne({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."})}
1279
1279
 
1280
1280
  <details class="add-form" style="margin-top:14px;margin-bottom:18px" id="notif-section">
1281
1281
  <summary class="primary">\u2699 Notifications routing</summary>
@@ -1360,10 +1360,10 @@ ${os}</script>`})}var ts=`
1360
1360
  </div>
1361
1361
  </details>
1362
1362
 
1363
- <div id="ch-chatapps-label">${tt({label:"Chat apps"})}</div>
1363
+ <div id="ch-chatapps-label">${at({label:"Chat apps"})}</div>
1364
1364
  <div class="ax-connectors" id="ch-chatapps"></div>
1365
1365
 
1366
- <div id="ch-devtools-label">${tt({label:"Developer tools",rightHtml:'<span class="ax-pill">Send events from GitHub, GitLab, Sentry, etc.</span>'})}</div>
1366
+ <div id="ch-devtools-label">${at({label:"Developer tools",rightHtml:'<span class="ax-pill">Send events from GitHub, GitLab, Sentry, etc.</span>'})}</div>
1367
1367
  <div class="ax-connectors" id="ch-devtools"></div>
1368
1368
 
1369
1369
  <!-- Active-channel configuration panes. One shows at a time; clicking
@@ -1381,8 +1381,8 @@ ${os}</script>`})}var ts=`
1381
1381
  </section>
1382
1382
 
1383
1383
  <section id="tab-crons" class="tab">
1384
- ${U({icon:se.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."})}
1385
- ${ae({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."})}
1384
+ ${U({icon:le.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."})}
1385
+ ${ne({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."})}
1386
1386
  <div id="cron-list" class="ax-stack" style="margin-bottom:22px"></div>
1387
1387
 
1388
1388
  <div class="ax-builder">
@@ -1479,8 +1479,8 @@ ${os}</script>`})}var ts=`
1479
1479
  </section>
1480
1480
 
1481
1481
  <section id="tab-webhooks" class="tab">
1482
- ${U({icon:se.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."})}
1483
- ${ae({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.`})}
1482
+ ${U({icon:le.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."})}
1483
+ ${ne({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.`})}
1484
1484
  <div id="webhook-list" class="ax-stack"></div>
1485
1485
  <div class="add-form">
1486
1486
  <h3>Add a webhook</h3>
@@ -1499,10 +1499,10 @@ ${os}</script>`})}var ts=`
1499
1499
  </section>
1500
1500
 
1501
1501
  <section id="tab-mesh" class="tab">
1502
- ${U({icon:se.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."})}
1502
+ ${U({icon:le.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."})}
1503
1503
  <div id="mesh-hero" class="ax-mesh-hero"></div>
1504
- ${ae({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."})}
1505
- ${tt({label:"Connected peers"})}
1504
+ ${ne({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."})}
1505
+ ${at({label:"Connected peers"})}
1506
1506
  <div id="mesh-peers" class="ax-stack"></div>
1507
1507
  <div class="add-form">
1508
1508
  <h3>Add a peer</h3>
@@ -1529,8 +1529,8 @@ ${os}</script>`})}var ts=`
1529
1529
  </section>
1530
1530
 
1531
1531
  <section id="tab-business" class="tab">
1532
- ${U({icon:se.tokens,title:"Business layer",lead:"Org chart, projects, and contact map \u2014 the data that drives PM gating and activity-graph attribution. Same as agentx business in the terminal."})}
1533
- ${ae({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.'})}
1532
+ ${U({icon:le.tokens,title:"Business layer",lead:"Org chart, projects, and contact map \u2014 the data that drives PM gating and activity-graph attribution. Same as agentx business in the terminal."})}
1533
+ ${ne({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.'})}
1534
1534
 
1535
1535
  <div class="ax-stack" style="margin-top:14px">
1536
1536
  <h3 style="margin:0 0 6px;font-size:13px">Org chart</h3>
@@ -1617,8 +1617,8 @@ ${os}</script>`})}var ts=`
1617
1617
  </section>
1618
1618
 
1619
1619
  <section id="tab-boards-cfg" class="tab">
1620
- ${U({icon:se.tokens,title:"Kanban boards",lead:"Configure the boards rendered on the home page. Same as agentx board add, edit, remove and column in the terminal. Source is GitLab today; backlog/wiki sources land when the schema unlocks them."})}
1621
- ${ae({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.'})}
1620
+ ${U({icon:le.tokens,title:"Kanban boards",lead:"Configure the boards rendered on the home page. Same as agentx board add, edit, remove and column in the terminal. Source is GitLab today; backlog/wiki sources land when the schema unlocks them."})}
1621
+ ${ne({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.'})}
1622
1622
 
1623
1623
  <div class="ax-stack" style="margin-top:14px">
1624
1624
  <h3 style="margin:0 0 6px;font-size:13px">Boards</h3>
@@ -1642,8 +1642,8 @@ ${os}</script>`})}var ts=`
1642
1642
  </section>
1643
1643
 
1644
1644
  <section id="tab-actions" class="tab">
1645
- ${U({icon:se.actions,title:"Action registry",lead:"Reusable shell commands and HTTP calls. Workflows invoke them by id; the dashboard runs them on demand for smoke-tests. Same as agentx actions in the terminal."})}
1646
- ${ae({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."})}
1645
+ ${U({icon:le.actions,title:"Action registry",lead:"Reusable shell commands and HTTP calls. Workflows invoke them by id; the dashboard runs them on demand for smoke-tests. Same as agentx actions in the terminal."})}
1646
+ ${ne({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."})}
1647
1647
 
1648
1648
  <div class="ax-stack" style="margin-top:14px">
1649
1649
  <h3 style="margin:0 0 6px;font-size:13px">Registered actions</h3>
@@ -1698,8 +1698,8 @@ ${os}</script>`})}var ts=`
1698
1698
  </section>
1699
1699
 
1700
1700
  <section id="tab-tokens" class="tab">
1701
- ${U({icon:se.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."})}
1702
- ${ae({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."})}
1701
+ ${U({icon:le.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."})}
1702
+ ${ne({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."})}
1703
1703
  <div id="token-list" class="ax-stack"></div>
1704
1704
  <div class="add-form">
1705
1705
  <h3>Mint a new token</h3>
@@ -1718,8 +1718,8 @@ ${os}</script>`})}var ts=`
1718
1718
  </section>
1719
1719
 
1720
1720
  <section id="tab-advanced" class="tab">
1721
- ${U({icon:se.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."})}
1722
- ${ae({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.`})}
1721
+ ${U({icon:le.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."})}
1722
+ ${ne({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.`})}
1723
1723
 
1724
1724
  <div class="ax-jv-toolbar">
1725
1725
  <input class="ax-jv-search" id="jv-search" placeholder="Search keys & values\u2026" />
@@ -1745,7 +1745,7 @@ ${os}</script>`})}var ts=`
1745
1745
  <div class="hint-block">Every setting is documented in the <code>docs/reference/config.md</code> reference. Invalid JSON is refused; schema-level errors only surface after the daemon tries to use the new config.</div>
1746
1746
  </section>
1747
1747
  </main>
1748
- `,rs=`
1748
+ `,Rs=`
1749
1749
 
1750
1750
  /* --- Inner tabs (Agents / Channels / Schedules / \u2026) --- */
1751
1751
  nav.tabs{display:flex;gap:4px;padding:14px 24px 0;background:var(--ax-bg-elev);
@@ -1953,7 +1953,7 @@ textarea.raw{min-height:480px;font-family:var(--ax-mono);font-size:12px;line-hei
1953
1953
  .peer-banner button{background:transparent;border:1px solid currentColor;color:var(--ax-accent);
1954
1954
  padding:4px 10px;border-radius:4px;font:inherit;font-size:11px;cursor:pointer}
1955
1955
  .peer-banner button:hover{background:color-mix(in oklch,var(--ax-accent) 12%,transparent)}
1956
- `,os=`
1956
+ `,Ps=`
1957
1957
  const $ = (id) => document.getElementById(id);
1958
1958
  let state = null;
1959
1959
 
@@ -4760,11 +4760,11 @@ for (const btn of document.querySelectorAll('nav.tabs button')) {
4760
4760
  })();
4761
4761
 
4762
4762
  refresh();
4763
- `;function vn(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(hn({peers:a,localToken:n}))}async function bn(t,e){let a=$t();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function yn(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await ks(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await cs(t),r={"GET /api/admin/state":()=>ps(),"POST /api/admin/agents":()=>xs(n),"PATCH /api/admin/agents":()=>vs(n),"DELETE /api/admin/agents":()=>bs(n),"POST /api/admin/agents/access":()=>us(n),"POST /api/admin/channels/telegram":()=>ys(n),"DELETE /api/admin/channels/telegram":()=>qs(n),"POST /api/admin/channels/telegram/toggle":()=>Ws(n),"POST /api/admin/crons":()=>Gs(n),"DELETE /api/admin/crons":()=>Xs(n),"POST /api/admin/config/raw":()=>Ks(n),"GET /api/admin/tokens":()=>ms(),"POST /api/admin/tokens":()=>fs(n),"DELETE /api/admin/tokens":()=>hs(n),"POST /api/admin/agents/test":()=>gs(n),"POST /api/admin/agents/integrations":()=>As(n),"DELETE /api/admin/agents/integrations":()=>Ms(n),"PATCH /api/admin/agents/integrations":()=>Is(n),"PATCH /api/admin/channels/telegram":()=>ws(n),"POST /api/admin/channels/slack":()=>Ns(n),"POST /api/admin/channels/slack/toggle":()=>Ds(n),"POST /api/admin/channels/discord":()=>Hs(n),"POST /api/admin/channels/discord/toggle":()=>Bs(n),"POST /api/admin/channels/gitlab":()=>zs(n),"POST /api/admin/channels/gitlab/toggle":()=>Fs(n),"GET /api/admin/channels/whatsapp/state":()=>je("/whatsapp/state"),"GET /api/admin/channels/webrtc/history":()=>je("/webrtc/history"),"POST /api/admin/actions":()=>ii(n),"DELETE /api/admin/actions":()=>li(n),"POST /api/admin/actions/run":()=>ci(n),"GET /api/admin/channels/whatsapp/chats":()=>je("/whatsapp/chats"),"GET /api/admin/channels/whatsapp/contacts":()=>je("/whatsapp/contacts"),"POST /api/admin/channels/whatsapp/ingest":()=>ce("/whatsapp/ingest",n),"POST /api/admin/crons/preview":()=>Us(n),"POST /api/admin/webhooks":()=>$s(n),"PATCH /api/admin/webhooks":()=>Ls(n),"DELETE /api/admin/webhooks":()=>Os(n),"POST /api/admin/mesh/peers":()=>Rs(n),"DELETE /api/admin/mesh/peers":()=>js(n),"POST /api/admin/mesh/toggle":()=>Ps(n),"GET /api/admin/files":()=>_s(t),"GET /api/admin/files/read":()=>Es(t),"PUT /api/admin/files":()=>Ss(n),"POST /api/admin/files/skill":()=>Ts(n),"DELETE /api/admin/files/skill":()=>Cs(n),"POST /api/admin/business/orgchart":()=>Js(n),"DELETE /api/admin/business/orgchart":()=>Vs(n),"POST /api/admin/business/project":()=>Ys(n),"DELETE /api/admin/business/project":()=>ei(n),"POST /api/admin/business/client":()=>Qs(n),"DELETE /api/admin/business/client":()=>Zs(n),"POST /api/admin/business/contact":()=>ti(n),"DELETE /api/admin/business/contact":()=>ai(n),"POST /api/admin/boards":()=>ni(n),"DELETE /api/admin/boards":()=>ri(n),"POST /api/admin/boards/columns":()=>oi(n),"DELETE /api/admin/boards/columns":()=>si(n),"POST /api/admin/notifications":()=>pi(n),"POST /api/admin/screen":()=>ui(n),"POST /api/admin/webhooks/triggers":()=>mi(n),"POST /api/admin/mesh/health":()=>di(n),"GET /api/admin/projects":()=>je("/api/admin/projects"),"POST /api/admin/projects/workflows/link":()=>ce("/api/admin/projects/workflows/link",n),"POST /api/admin/projects/workflows/unlink":()=>ce("/api/admin/projects/workflows/unlink",n),"POST /api/admin/projects/header":()=>ce("/api/admin/projects/header",n),"POST /api/admin/projects/clauses":()=>ce("/api/admin/projects/clauses",n),"POST /api/admin/projects/contacts/link":()=>ce("/api/admin/projects/contacts/link",n),"POST /api/admin/projects/contacts/unlink":()=>ce("/api/admin/projects/contacts/unlink",n),"POST /api/admin/projects/create":()=>ce("/api/admin/projects/create",n),"POST /api/admin/projects/delete":()=>ce("/api/admin/projects/delete",n)},o=`${t.method} ${a}`,s=r[o];if(!s){Mt(e,404,{error:`unknown admin endpoint: ${o}`});return}let i=await s();Mt(e,200,i)}catch(n){Mt(e,400,{error:n.message||"admin op failed"})}}function Mt(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function cs(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 ds(t){let e=Ae(process.cwd(),t);if(!ot(e))return[];let a=[];for(let n of ls(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".json")))try{a.push(JSON.parse(gn(Ae(e,n.name),"utf-8")))}catch{}return a}function $t(){let t=Ae(process.cwd(),"agentx.json");return ot(t)?JSON.parse(gn(t,"utf-8")):null}function ps(){let t=$t();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([d,m])=>({id:d,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 v=g.credentials||{},k={};for(let[b,_]of Object.entries(v))typeof _=="string"&&/^[A-Z][A-Z0-9_]*$/.test(_)?k[b]=process.env[_]?"set":"unset":typeof _=="string"&&(k[b]="literal");return{kind:g.kind,label:g.label,enabled:g.enabled!==!1,credentials:v,credStatus:k,metadata:g.metadata||{}}})})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([d,m])=>({id:d,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(([d,m])=>({id:d,schedule:m.schedule,agent:m.agent,prompt:(m.prompt||"").slice(0,200),enabled:m.enabled!==!1})),c=Array.isArray(t.webhooks)?t.webhooks.map(d=>({id:d.id,source:d.source,agentId:d.agentId,secretEnv:d.secretEnv||"",description:d.description||"",enabled:d.enabled!==!1,triggers:d.triggers&&typeof d.triggers=="object"?d.triggers:{},defaultWorkflow:d.defaultWorkflow||""})):[],p={enabled:!!t.mesh?.enabled,discovery:t.mesh?.discovery||"static",peers:(t.mesh?.peers||[]).map(d=>({url:d.url,name:d.name,hasToken:!!d.token})),healthCheck:{interval:t.mesh?.healthCheck?.interval??60,timeout:t.mesh?.healthCheck?.timeout??10}},u=t.dashboard?.daemonUrl||"http://localhost:18800",f=t.business||{},h={enabled:!!f.enabled,timezone:f.timezone||"UTC",orgChart:f.orgChart||{},projects:Array.isArray(f.projects)?f.projects:[],contactMap:Array.isArray(f.contactMap)?f.contactMap:[],clients:f.clients&&typeof f.clients=="object"?f.clients:{}},y=t.notifications||{},T={longTaskThreshold:y.longTaskThreshold??30,destination:y.destination||null,on:{taskComplete:y.on?.taskComplete!==!1,taskError:y.on?.taskError!==!1,taskQueued:!!y.on?.taskQueued},local:wa(y.local),ntfy:nn(t.channels?.ntfy)},S=[];try{S=ds(".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 x=(Array.isArray(t.boards)?t.boards:[]).map(d=>({id:d.id,name:d.name,source:d.source||{type:"gitlab",projects:[]},primaryToolLabel:d.primaryToolLabel||"",timeRangeDays:d.timeRangeDays??30,closedWindowDays:d.closedWindowDays??30,columns:Array.isArray(d.columns)?d.columns:[]}));return{exists:!0,agents:e,telegram:n,slack:r,discord:o,gitlab:s,whatsapp:i,crons:l,webhooks:c,mesh:p,daemonUrl:u,nodeName:t.node?.name,business:h,boards:x,notifications:T,screen:Ba(t.screen),actions:S}}function us(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 ms(){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 fs(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 hs(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 gs(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=Q();r=p.dashboard.daemonUrl.replace(/\/+$/,"")||r,o=p.dashboard.token}catch{}let s={"Content-Type":"application/json"};o&&(s.Authorization=`Bearer ${o}`);let i=await fetch(`${r}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"test-drive",sender:"admin",chatId:n}})}),l=await i.text(),c;try{c=JSON.parse(l)}catch{c={content:l}}if(!i.ok)throw new Error(c?.error||`daemon HTTP ${i.status}`);return{chatId:n,response:c}}function xs(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=kn(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=Ae(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}"`}),c=Ae(i,"CLAUDE.md");if(!ot(c))try{ss(i,{recursive:!0}),xn(c,`# ${a}
4763
+ `;function Tn(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(_n({peers:a,localToken:n}))}async function An(t,e){let a=Rt();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(a))}async function Cn(t,e,a){try{if(t.method==="GET"&&a==="/api/admin/channels/whatsapp/qr.svg"){await Ys(e,"/whatsapp/qr.svg");return}let n=t.method==="GET"?void 0:await Ds(t),r={"GET /api/admin/state":()=>Bs(),"POST /api/admin/agents":()=>Gs(n),"PATCH /api/admin/agents":()=>Xs(n),"DELETE /api/admin/agents":()=>Ks(n),"POST /api/admin/agents/access":()=>zs(n),"POST /api/admin/channels/telegram":()=>Js(n),"DELETE /api/admin/channels/telegram":()=>bi(n),"POST /api/admin/channels/telegram/toggle":()=>yi(n),"POST /api/admin/crons":()=>wi(n),"DELETE /api/admin/crons":()=>ki(n),"POST /api/admin/config/raw":()=>_i(n),"GET /api/admin/tokens":()=>Fs(),"POST /api/admin/tokens":()=>qs(n),"DELETE /api/admin/tokens":()=>Us(n),"POST /api/admin/agents/test":()=>Ws(n),"POST /api/admin/agents/integrations":()=>ni(n),"DELETE /api/admin/agents/integrations":()=>ri(n),"PATCH /api/admin/agents/integrations":()=>oi(n),"PATCH /api/admin/channels/telegram":()=>Vs(n),"POST /api/admin/channels/slack":()=>ui(n),"POST /api/admin/channels/slack/toggle":()=>mi(n),"POST /api/admin/channels/discord":()=>fi(n),"POST /api/admin/channels/discord/toggle":()=>hi(n),"POST /api/admin/channels/gitlab":()=>gi(n),"POST /api/admin/channels/gitlab/toggle":()=>xi(n),"GET /api/admin/channels/whatsapp/state":()=>Oe("/whatsapp/state"),"GET /api/admin/channels/webrtc/history":()=>Oe("/webrtc/history"),"POST /api/admin/actions":()=>Oi(n),"DELETE /api/admin/actions":()=>Ni(n),"POST /api/admin/actions/run":()=>Di(n),"GET /api/admin/channels/whatsapp/chats":()=>Oe("/whatsapp/chats"),"GET /api/admin/channels/whatsapp/contacts":()=>Oe("/whatsapp/contacts"),"POST /api/admin/channels/whatsapp/ingest":()=>de("/whatsapp/ingest",n),"POST /api/admin/crons/preview":()=>vi(n),"POST /api/admin/webhooks":()=>si(n),"PATCH /api/admin/webhooks":()=>ii(n),"DELETE /api/admin/webhooks":()=>pi(n),"POST /api/admin/mesh/peers":()=>li(n),"DELETE /api/admin/mesh/peers":()=>ci(n),"POST /api/admin/mesh/toggle":()=>di(n),"GET /api/admin/files":()=>Qs(t),"GET /api/admin/files/read":()=>Zs(t),"PUT /api/admin/files":()=>ei(n),"POST /api/admin/files/skill":()=>ti(n),"DELETE /api/admin/files/skill":()=>ai(n),"POST /api/admin/business/orgchart":()=>Ei(n),"DELETE /api/admin/business/orgchart":()=>Si(n),"POST /api/admin/business/project":()=>Ti(n),"DELETE /api/admin/business/project":()=>Mi(n),"POST /api/admin/business/client":()=>Ai(n),"DELETE /api/admin/business/client":()=>Ci(n),"POST /api/admin/business/contact":()=>Ii(n),"DELETE /api/admin/business/contact":()=>Li(n),"POST /api/admin/boards":()=>$i(n),"DELETE /api/admin/boards":()=>Ri(n),"POST /api/admin/boards/columns":()=>Pi(n),"DELETE /api/admin/boards/columns":()=>ji(n),"POST /api/admin/notifications":()=>Bi(n),"POST /api/admin/screen":()=>zi(n),"POST /api/admin/webhooks/triggers":()=>Fi(n),"POST /api/admin/mesh/health":()=>Hi(n),"GET /api/admin/projects":()=>Oe("/api/admin/projects"),"POST /api/admin/projects/workflows/link":()=>de("/api/admin/projects/workflows/link",n),"POST /api/admin/projects/workflows/unlink":()=>de("/api/admin/projects/workflows/unlink",n),"POST /api/admin/projects/header":()=>de("/api/admin/projects/header",n),"POST /api/admin/projects/clauses":()=>de("/api/admin/projects/clauses",n),"POST /api/admin/projects/contacts/link":()=>de("/api/admin/projects/contacts/link",n),"POST /api/admin/projects/contacts/unlink":()=>de("/api/admin/projects/contacts/unlink",n),"POST /api/admin/projects/create":()=>de("/api/admin/projects/create",n),"POST /api/admin/projects/delete":()=>de("/api/admin/projects/delete",n)},o=`${t.method} ${a}`,s=r[o];if(!s){Lt(e,404,{error:`unknown admin endpoint: ${o}`});return}let i=await s();Lt(e,200,i)}catch(n){Lt(e,400,{error:n.message||"admin op failed"})}}function Lt(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Ds(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 Hs(t){let e=Le(process.cwd(),t);if(!st(e))return[];let a=[];for(let n of Ns(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".json")))try{a.push(JSON.parse(En(Le(e,n.name),"utf-8")))}catch{}return a}function Rt(){let t=Le(process.cwd(),"agentx.json");return st(t)?JSON.parse(En(t,"utf-8")):null}function Bs(){let t=Rt();if(!t)return{exists:!1};let e=Object.entries(t.agents||{}).map(([d,m])=>({id:d,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(x=>{let b=x.credentials||{},k={};for(let[y,_]of Object.entries(b))typeof _=="string"&&/^[A-Z][A-Z0-9_]*$/.test(_)?k[y]=process.env[_]?"set":"unset":typeof _=="string"&&(k[y]="literal");return{kind:x.kind,label:x.label,enabled:x.enabled!==!1,credentials:b,credStatus:k,metadata:x.metadata||{}}})})),a=t.channels?.telegram?.accounts||{},n={enabled:!!t.channels?.telegram?.enabled,accounts:Object.entries(a).map(([d,m])=>({id:d,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(([d,m])=>({id:d,schedule:m.schedule,agent:m.agent,prompt:(m.prompt||"").slice(0,200),enabled:m.enabled!==!1})),c=Array.isArray(t.webhooks)?t.webhooks.map(d=>({id:d.id,source:d.source,agentId:d.agentId,secretEnv:d.secretEnv||"",description:d.description||"",enabled:d.enabled!==!1,triggers:d.triggers&&typeof d.triggers=="object"?d.triggers:{},defaultWorkflow:d.defaultWorkflow||""})):[],p={enabled:!!t.mesh?.enabled,discovery:t.mesh?.discovery||"static",peers:(t.mesh?.peers||[]).map(d=>({url:d.url,name:d.name,hasToken:!!d.token})),healthCheck:{interval:t.mesh?.healthCheck?.interval??60,timeout:t.mesh?.healthCheck?.timeout??10}},u=t.dashboard?.daemonUrl||"http://localhost:18800",f=t.business||{},h={enabled:!!f.enabled,timezone:f.timezone||"UTC",orgChart:f.orgChart||{},projects:Array.isArray(f.projects)?f.projects:[],contactMap:Array.isArray(f.contactMap)?f.contactMap:[],clients:f.clients&&typeof f.clients=="object"?f.clients:{}},v=t.notifications||{},T={longTaskThreshold:v.longTaskThreshold??30,destination:v.destination||null,on:{taskComplete:v.on?.taskComplete!==!1,taskError:v.on?.taskError!==!1,taskQueued:!!v.on?.taskQueued},local:Ca(v.local),ntfy:un(t.channels?.ntfy)},E=[];try{E=Hs(".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,x)=>m.id.localeCompare(x.id))}catch{}let g=(Array.isArray(t.boards)?t.boards:[]).map(d=>({id:d.id,name:d.name,source:d.source||{type:"gitlab",projects:[]},primaryToolLabel:d.primaryToolLabel||"",timeRangeDays:d.timeRangeDays??30,closedWindowDays:d.closedWindowDays??30,columns:Array.isArray(d.columns)?d.columns:[]}));return{exists:!0,agents:e,telegram:n,slack:r,discord:o,gitlab:s,whatsapp:i,crons:l,webhooks:c,mesh:p,daemonUrl:u,nodeName:t.node?.name,business:h,boards:g,notifications:T,screen:Xa(t.screen),actions:E}}function zs(t){let e=String(t?.id||"").trim(),a=t?.access==="public"?"public":"private";if(!e)throw new Error("Agent id is required.");let{summary:n}=A(r=>{if(!r.agents?.[e])throw new Error(`Agent "${e}" not found.`);return r.agents[e].access=a,`agent "${e}" is now ${a}`});return{summary:n}}function Fs(){return new ae().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 qs(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 ae().create({name:e,scopes:a,expiresInDays:n});return{summary:`created token "${e}"`,token:r,record:o}}function Us(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Token id is required.");let a=new ae().revoke(e);if(!a)throw new Error(`Token "${e}" not found.`);return{summary:`revoked token ${e} (${a.name})`}}async function Ws(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=te();r=p.dashboard.daemonUrl.replace(/\/+$/,"")||r,o=p.dashboard.token}catch{}let s={"Content-Type":"application/json"};o&&(s.Authorization=`Bearer ${o}`);let i=await fetch(`${r}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"test-drive",sender:"admin",chatId:n}})}),l=await i.text(),c;try{c=JSON.parse(l)}catch{c={content:l}}if(!i.ok)throw new Error(c?.error||`daemon HTTP ${i.status}`);return{chatId:n,response:c}}function Gs(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=In(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=Le(process.cwd(),"agents",e),{summary:l}=A(p=>{if(p.agents=p.agents||{},p.agents[e])throw new Error(`Agent "${e}" already exists.`);let u={name:a,workspace:i,tier:n,mentions:r,maxConcurrent:2,permissionMode:"default"};return o&&(u.model=o),s&&(u.systemPrompt=s.slice(0,400)),p.agents[e]=u,`added agent "${e}"`}),c=Le(i,"CLAUDE.md");if(!st(c))try{js(i,{recursive:!0}),Sn(c,`# ${a}
4764
4764
 
4765
4765
  ${s||"You are "+a+"."}
4766
- `)}catch{}return{summary:l}}function vs(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=kn(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 bs(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 ys(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 ws(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 je(t){let{url:e,headers:a}=Lt(),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 ce(t,e){let{url:a,headers:n}=Lt(),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 ks(t,e){try{let{url:a,headers:n}=Lt(),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 Lt(){let t="http://127.0.0.1:18800",e={};try{let a=Q();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function Pe(t){let a=$t()?.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 It(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function _s(t){let e=It(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=Te(Pe(e));return{agentId:e,...a}}function Es(t){let e=It(t,"agent").trim(),a=It(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return Ke(Pe(e),a)}function Ss(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=Je(Pe(e),a,n);return{summary:`saved ${a} (${r.bytes} bytes)`,...r}}function Ts(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=Ve(Pe(e),a,{title:n,content:r});return{summary:`added skill "${a}"`,...o}}function Cs(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=Ye(Pe(e),a);return{summary:`removed skill "${a}"`,...n}}function As(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a)throw new Error("kind is required");if(!n)throw new Error("label is required");let r={},o=t?.credentials||{};for(let l of["tokenEnv","privateAppTokenEnv","apiKeyEnv","refreshTokenEnv","clientIdEnv","clientSecretEnv"]){let c=o[l];if(typeof c=="string"&&c.trim()){if(!/^[A-Z][A-Z0-9_]*$/.test(c.trim()))throw new Error(`${l} must be uppercase identifier (got "${c}")`);r[l]=c.trim()}}if(o.auth==="keyring"&&(r.auth="keyring"),typeof o.sessionDir=="string"&&o.sessionDir.trim()&&(r.sessionDir=o.sessionDir.trim()),Object.keys(r).length===0)throw new Error("at least one credential field required");let s={};for(let[l,c]of Object.entries(t?.metadata||{}))(typeof c=="string"||typeof c=="number"||typeof c=="boolean")&&(s[l]=c);let{summary:i}=C(l=>{if(!l.agents?.[e])throw new Error(`Unknown agent "${e}"`);if(l.agents[e].integrations=Array.isArray(l.agents[e].integrations)?l.agents[e].integrations:[],l.agents[e].integrations.find(c=>c.kind===a&&c.label===n))throw new Error(`integration (${a}, ${n}) already exists on ${e}`);return l.agents[e].integrations.push({kind:a,label:n,credentials:r,metadata:s,enabled:!0}),`added ${a} integration "${n}" to ${e}`});return{summary:i}}function Ms(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let{summary:r}=C(o=>{let s=o.agents?.[e];if(!s)throw new Error(`Unknown agent "${e}"`);let i=s.integrations||[],l=i.findIndex(c=>c.kind===a&&c.label===n);if(l===-1)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return i.splice(l,1),`removed ${a} integration "${n}" from ${e}`});return{summary:r}}function Is(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let r=t?.patch||{},{summary:o}=C(s=>{let i=s.agents?.[e];if(!i)throw new Error(`Unknown agent "${e}"`);let c=(i.integrations||[]).find(p=>p.kind===a&&p.label===n);if(!c)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return typeof r.enabled=="boolean"&&(c.enabled=r.enabled),r.metadata&&typeof r.metadata=="object"&&(c.metadata={...c.metadata||{},...r.metadata}),`updated integration (${a}, ${n}) on ${e}`});return{summary:o}}var wn=["gitlab","github","sentry","stripe","vercel","odoo","hubspot","discord","slack","custom"];function $s(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(!wn.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 c={id:e,source:a,agentId:n,enabled:!0};return r&&(c.secretEnv=r),o&&(c.description=o),s&&(c.node=s),l.webhooks.push(c),`added webhook "${e}" (${a} \u2192 ${n}${s?` @ ${s}`:""})`});return{summary:i}}function Ls(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"&&wn.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 Rs(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 js(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 Ps(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 Os(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 Ns(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 Ds(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 Hs(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 Bs(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 zs(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 Fs(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 Us(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-VPPKD4FY.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 qs(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 Ws(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 Gs(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 Xs(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 Ks(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=Ae(process.cwd(),"agentx.json"),r=`${n}.bak.${Date.now()}`;if(ot(n))try{is(n,r)}catch{}xn(n,JSON.stringify(a,null,2)+`
4767
- `,"utf-8");try{let s=Q().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 kn(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}async function Js(t){let e=String(t?.agentId||"").trim(),a=String(t?.role||"").trim();if(!e)throw new Error("agentId required");if(!a)throw new Error("role required");let n=Array.isArray(t?.days)&&t.days.length>0?t.days:["mon","tue","wed","thu","fri"],r=String(t?.start||"09:00"),o=String(t?.end||"17:00"),s=t?.reportsTo?String(t.reportsTo).trim():"",i=typeof t?.utilizationTarget=="number"?t.utilizationTarget:.8,{summary:l}=C(c=>(c.business=c.business||{},c.business.orgChart=c.business.orgChart||{},c.business.orgChart[e]={role:a,...s?{reportsTo:s}:{},schedule:{days:n,start:r,end:o},utilizationTarget:i},`orgChart "${e}" upserted`));return{summary:l}}async function Vs(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 Ys(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 Qs(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let a=String(t?.kind||"").trim();if(a&&!["client","internal","own"].includes(a))throw new Error("kind must be client, internal or own");let n=String(t?.respondWithin||"").trim();if(n&&!/^\d+\s*[mhd]$/.test(n))throw new Error('respondWithin must look like "4h", "90m" or "2d"');let r=Array.isArray(t?.standing)?t.standing.map(s=>String(s).trim()).filter(Boolean):String(t?.standing||"").split(",").map(s=>s.trim()).filter(Boolean),{summary:o}=C(s=>{s.business=s.business||{},s.business.clients=s.business.clients||{};let i=!!s.business.clients[e];return s.business.clients[e]={...s.business.clients[e]||{},...t?.name?{name:String(t.name).trim()}:{},...a?{kind:a}:{},...n?{respondWithin:n}:{},standing:r},i?`client "${e}" updated`:`client "${e}" configured`});return{summary:o}}async function Zs(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let{summary:a}=C(n=>{if(!n.business?.clients?.[e])throw new Error(`no client override "${e}"`);return delete n.business.clients[e],`client "${e}" reset to defaults`});return{summary:a}}async function ei(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 ti(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 ai(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 ni(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=String(t?.projects||"").split(/[,\n]/).map(l=>l.trim()).filter(Boolean);if(!e)throw new Error("id required");if(!a)throw new Error("name required");if(n.length===0)throw new Error("at least one project path required");let r=t?.primaryToolLabel?String(t.primaryToolLabel).trim():"",o=Number.isFinite(Number(t?.timeRangeDays))?Number(t.timeRangeDays):30,s=Number.isFinite(Number(t?.closedWindowDays))?Number(t.closedWindowDays):30,{summary:i}=C(l=>{l.boards=Array.isArray(l.boards)?l.boards:[];let c=l.boards.findIndex(u=>u.id===e),p={id:e,name:a,source:{type:"gitlab",projects:n},timeRangeDays:o,closedWindowDays:s};if(r&&(p.primaryToolLabel=r),c>=0){let u=l.boards[c];return l.boards[c]={...u,...p,columns:u.columns,labels:u.labels},`board "${e}" updated`}return l.boards.push(p),`board "${e}" added`});return{summary:i}}async function ri(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 oi(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 c={id:a,title:n,kind:r,scopedPrefix:t?.scopedPrefix||"Status"};if(r==="scoped-label"){if(!t?.scopedLabel)throw new Error("scopedLabel required for kind=scoped-label");c.scopedLabel=String(t.scopedLabel)}if(r==="label"){if(!t?.mapsToLabel)throw new Error("mapsToLabel required for kind=label");c.mapsToLabel=String(t.mapsToLabel)}t?.accent&&(c.accent=String(t.accent));let p=l.columns.findIndex(u=>u.id===a);return p>=0?(l.columns[p]={...l.columns[p],...c},`column "${a}" updated`):(l.columns.push(c),`column "${a}" added to board "${e}"`)});return{summary:o}}async function si(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 ii(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{actionSchema:a}=await import("./types-DO3KLIBS.js");if(!t||typeof t!="object")throw new Error("body required");let n=a.safeParse(t);if(!n.success){let o=n.error.issues[0];throw new Error(`${o.path.join(".")||"<root>"}: ${o.message}`)}let r=new e().save(n.data);return{summary:`action "${r.id}" saved (${r.kind})`,action:r}}async function li(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),a=String(t?.id||"").trim();if(!a)throw new Error("id required");if(!new e().delete(a))throw new Error(`action "${a}" not found`);return{summary:`action "${a}" removed`}}async function ci(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{runAction:a}=await import("./runner-56G3N7M4.js"),n=String(t?.id||"").trim();if(!n)throw new Error("id required");let r=new e().get(n);if(!r)throw new Error(`action "${n}" not found`);let o=t?.inputs&&typeof t.inputs=="object"?t.inputs:{},s=await a(r,o);return{summary:`action "${n}" ${s.ok?"ok":"failed"} (${s.durationMs}ms)`,result:s}}async function di(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 pi(t){let{summary:e}=C(a=>{a.notifications=a.notifications||{};let n=[];if(t&&typeof t=="object"){if("destination"in t)if(!t.destination)delete a.notifications.destination,n.push("destination cleared");else if(t.destination.channel&&t.destination.chatId)a.notifications.destination={channel:String(t.destination.channel),chatId:String(t.destination.chatId),...t.destination.accountId?{accountId:String(t.destination.accountId)}:{}},n.push(`destination=${t.destination.channel}:${t.destination.chatId}`);else throw new Error("destination requires channel + chatId");if("on"in t&&t.on&&typeof t.on=="object"){a.notifications.on=a.notifications.on||{};for(let r of["taskComplete","taskError","taskQueued"])r in t.on&&(a.notifications.on[r]=!!t.on[r]);n.push("on="+JSON.stringify(a.notifications.on))}if("longTaskThreshold"in t){let r=Number(t.longTaskThreshold);if(!Number.isFinite(r)||r<0)throw new Error("longTaskThreshold must be a non-negative number");a.notifications.longTaskThreshold=r,n.push(`threshold=${r}s`)}"local"in t&&t.local&&typeof t.local=="object"&&(a.notifications.local=ka(a.notifications.local,t.local),n.push("local="+JSON.stringify(a.notifications.local))),"ntfy"in t&&t.ntfy&&typeof t.ntfy=="object"&&(a.channels=a.channels||{},a.channels.ntfy=rn(a.channels.ntfy,t.ntfy),n.push(`ntfy ${a.channels.ntfy.enabled?"on":"off"} (restart the daemon to apply)`))}if(n.length===0)throw new Error("nothing to update");return`notifications updated (${n.join(", ")})`});return{summary:e}}async function ui(t){if(!t||typeof t!="object")throw new Error("nothing to update");let{summary:e}=C(a=>(a.screen=za(a.screen,t),`screen updated (buffer ${a.screen.buffer?.enabled?"on":"off"})`));return{summary:e}}async function mi(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}}yt();import{resolve as gi}from"path";function _n(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div id="msg" class="msg"></div>
4766
+ `)}catch{}return{summary:l}}function Xs(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let a=t?.patch||{},{summary:n}=A(r=>{if(!r.agents?.[e])throw new Error(`Agent "${e}" not found.`);let o=r.agents[e];return typeof a.name=="string"&&a.name.trim()&&(o.name=a.name.trim()),typeof a.model=="string"&&(o.model=a.model.trim()||void 0),typeof a.tier=="string"&&["claude-code","codex-cli","opencode","sdk","orchestrator"].includes(a.tier)&&(o.tier=a.tier),typeof a.systemPrompt=="string"&&(o.systemPrompt=a.systemPrompt.trim()||void 0),Array.isArray(a.mentions)?o.mentions=a.mentions.map(s=>String(s).trim()).filter(Boolean):typeof a.triggerWords=="string"&&(o.mentions=In(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 Ks(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Agent id is required.");let{summary:a}=A(n=>{if(!n.agents||!n.agents[e])throw new Error(`Agent "${e}" not found.`);if(delete n.agents[e],n.channels?.telegram?.accounts)for(let r of Object.keys(n.channels.telegram.accounts))n.channels.telegram.accounts[r]?.agentBinding===e&&(n.channels.telegram.accounts[r].agentBinding="");return`removed agent "${e}"`});return{summary:a}}function Js(t){let e=String(t?.id||"").trim(),a=String(t?.agentBinding||"").trim(),n=String(t?.botUsername||"").trim(),r=String(t?.botTokenEnv||"").trim();if(!e)throw new Error("Account id is required.");if(!a)throw new Error("Choose an agent to bind this account to.");if(!r)throw new Error("Bot token env-var name is required (e.g. TG_SUPPORT_BOT_TOKEN).");let{summary:o}=A(s=>{if(s.channels=s.channels||{},s.channels.telegram=s.channels.telegram||{enabled:!0,accounts:{},policy:{dm:"pair",group:"mention-required"}},s.channels.telegram.enabled=!0,s.channels.telegram.accounts=s.channels.telegram.accounts||{},s.channels.telegram.accounts[e])throw new Error(`Telegram account "${e}" already exists.`);if(!s.agents?.[a])throw new Error(`Unknown agent "${a}".`);return s.channels.telegram.accounts[e]={token:"${"+r+"}",agentBinding:a},`added telegram account "${e}"`});return{summary:o,hint:`Add ${r}=<bot-token> to your .env file.`}}function Vs(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let a=t?.patch||{},{summary:n}=A(r=>{let o=r.channels?.telegram?.accounts?.[e];if(!o)throw new Error(`Account "${e}" not found.`);if(typeof a.agentBinding=="string"&&a.agentBinding.trim()){if(!r.agents?.[a.agentBinding])throw new Error(`Unknown agent "${a.agentBinding}".`);o.agentBinding=a.agentBinding.trim()}return typeof a.botUsername=="string"&&(o.botUsername=a.botUsername.trim()),typeof a.botTokenEnv=="string"&&a.botTokenEnv.trim()&&(o.token="${"+a.botTokenEnv.trim()+"}"),`updated telegram account "${e}"`});return{summary:n}}async function Oe(t){let{url:e,headers:a}=Pt(),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 de(t,e){let{url:a,headers:n}=Pt(),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 Ys(t,e){try{let{url:a,headers:n}=Pt(),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 Pt(){let t="http://127.0.0.1:18800",e={};try{let a=te();t=a.dashboard.daemonUrl?.replace(/\/+$/,"")||t,a.dashboard.token&&(e.Authorization=`Bearer ${a.dashboard.token}`)}catch{}return{url:t,headers:e}}function Ne(t){let a=Rt()?.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 $t(t,e){try{return new URL(t.url||"/","http://localhost").searchParams.get(e)||""}catch{return""}}function Qs(t){let e=$t(t,"agent").trim();if(!e)throw new Error("agent= query param is required.");let a=Me(Ne(e));return{agentId:e,...a}}function Zs(t){let e=$t(t,"agent").trim(),a=$t(t,"path").trim();if(!e||!a)throw new Error("agent= and path= query params are required.");return Je(Ne(e),a)}function ei(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=Ve(Ne(e),a,n);return{summary:`saved ${a} (${r.bytes} bytes)`,...r}}function ti(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=Ye(Ne(e),a,{title:n,content:r});return{summary:`added skill "${a}"`,...o}}function ai(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=Qe(Ne(e),a);return{summary:`removed skill "${a}"`,...n}}function ni(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a)throw new Error("kind is required");if(!n)throw new Error("label is required");let r={},o=t?.credentials||{};for(let l of["tokenEnv","privateAppTokenEnv","apiKeyEnv","refreshTokenEnv","clientIdEnv","clientSecretEnv"]){let c=o[l];if(typeof c=="string"&&c.trim()){if(!/^[A-Z][A-Z0-9_]*$/.test(c.trim()))throw new Error(`${l} must be uppercase identifier (got "${c}")`);r[l]=c.trim()}}if(o.auth==="keyring"&&(r.auth="keyring"),typeof o.sessionDir=="string"&&o.sessionDir.trim()&&(r.sessionDir=o.sessionDir.trim()),Object.keys(r).length===0)throw new Error("at least one credential field required");let s={};for(let[l,c]of Object.entries(t?.metadata||{}))(typeof c=="string"||typeof c=="number"||typeof c=="boolean")&&(s[l]=c);let{summary:i}=A(l=>{if(!l.agents?.[e])throw new Error(`Unknown agent "${e}"`);if(l.agents[e].integrations=Array.isArray(l.agents[e].integrations)?l.agents[e].integrations:[],l.agents[e].integrations.find(c=>c.kind===a&&c.label===n))throw new Error(`integration (${a}, ${n}) already exists on ${e}`);return l.agents[e].integrations.push({kind:a,label:n,credentials:r,metadata:s,enabled:!0}),`added ${a} integration "${n}" to ${e}`});return{summary:i}}function ri(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let{summary:r}=A(o=>{let s=o.agents?.[e];if(!s)throw new Error(`Unknown agent "${e}"`);let i=s.integrations||[],l=i.findIndex(c=>c.kind===a&&c.label===n);if(l===-1)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return i.splice(l,1),`removed ${a} integration "${n}" from ${e}`});return{summary:r}}function oi(t){let e=String(t?.agentId||"").trim(),a=String(t?.kind||"").trim(),n=String(t?.label||"").trim();if(!e)throw new Error("agentId is required");if(!a||!n)throw new Error("kind and label are required");let r=t?.patch||{},{summary:o}=A(s=>{let i=s.agents?.[e];if(!i)throw new Error(`Unknown agent "${e}"`);let c=(i.integrations||[]).find(p=>p.kind===a&&p.label===n);if(!c)throw new Error(`integration (${a}, ${n}) not found on ${e}`);return typeof r.enabled=="boolean"&&(c.enabled=r.enabled),r.metadata&&typeof r.metadata=="object"&&(c.metadata={...c.metadata||{},...r.metadata}),`updated integration (${a}, ${n}) on ${e}`});return{summary:o}}var Mn=["gitlab","github","sentry","stripe","vercel","odoo","hubspot","discord","slack","custom"];function si(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(!Mn.includes(a))throw new Error(`Unknown source: ${a}`);if(!n)throw new Error("Pick an agent to bind the webhook to.");let{summary:i}=A(l=>{if(s){if(!(l.mesh?.peers||[]).find(u=>u.name===s))throw new Error(`Mesh peer "${s}" not found in mesh.peers. Add the peer first or remove the node field.`)}else if(!l.agents?.[n])throw new Error(`Unknown agent "${n}". Add it locally, or set --node <peer> to forward to a mesh peer.`);if(l.webhooks=Array.isArray(l.webhooks)?l.webhooks:[],l.webhooks.find(p=>p.id===e))throw new Error(`Webhook "${e}" already exists.`);let c={id:e,source:a,agentId:n,enabled:!0};return r&&(c.secretEnv=r),o&&(c.description=o),s&&(c.node=s),l.webhooks.push(c),`added webhook "${e}" (${a} \u2192 ${n}${s?` @ ${s}`:""})`});return{summary:i}}function ii(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let a=t?.patch||{},{summary:n}=A(r=>{let o=(r.webhooks||[]).find(s=>s.id===e);if(!o)throw new Error(`Webhook "${e}" not found.`);if(typeof a.source=="string"&&Mn.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 li(t){let e=String(t?.url||"").trim().replace(/\/+$/,""),a=String(t?.name||"").trim(),n=String(t?.token||"").trim()||void 0;if(!e||!/^https?:\/\//.test(e))throw new Error("Peer URL must start with http:// or https://");if(!a)throw new Error("Peer name is required.");let{summary:r}=A(o=>{if(o.mesh=o.mesh||{enabled:!0,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},o.mesh.enabled=!0,o.mesh.peers=Array.isArray(o.mesh.peers)?o.mesh.peers:[],o.mesh.peers.find(i=>i.url===e))throw new Error(`Peer at ${e} already registered.`);let s={url:e,name:a};return n&&(s.token=n),o.mesh.peers.push(s),`added mesh peer "${a}"`});return{summary:r}}function ci(t){let e=String(t?.url||"").trim().replace(/\/+$/,"");if(!e)throw new Error("Peer URL is required.");let{summary:a}=A(n=>{let r=(n.mesh?.peers||[]).length;if(n.mesh=n.mesh||{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},n.mesh.peers=(n.mesh.peers||[]).filter(o=>o.url.replace(/\/+$/,"")!==e),n.mesh.peers.length===r)throw new Error(`Peer at ${e} not found.`);return`removed mesh peer ${e}`});return{summary:a}}function di(t){let e=!!t?.enabled,{summary:a}=A(n=>(n.mesh=n.mesh||{enabled:e,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},n.mesh.enabled=e,`mesh ${e?"enabled":"disabled"}`));return{summary:a}}function pi(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Webhook id is required.");let{summary:a}=A(n=>{let r=(n.webhooks||[]).length;if(n.webhooks=(n.webhooks||[]).filter(o=>o.id!==e),n.webhooks.length===r)throw new Error(`Webhook "${e}" not found.`);return`removed webhook "${e}"`});return{summary:a}}function ui(t){let e=String(t?.botTokenEnv||"").trim(),a=String(t?.appTokenEnv||"").trim(),n=String(t?.agentBinding||"").trim();if(!e)throw new Error("Bot token env-var name is required (e.g. SLACK_BOT_TOKEN).");if(!a)throw new Error("App-level token env-var name is required (e.g. SLACK_APP_TOKEN).");let{summary:r}=A(o=>{if(o.channels=o.channels||{},o.channels.slack=o.channels.slack||{enabled:!1},o.channels.slack.enabled=!0,o.channels.slack.botToken="${"+e+"}",o.channels.slack.appToken="${"+a+"}",n){if(!o.agents?.[n])throw new Error(`Unknown agent "${n}".`);o.channels.slack.agentBinding=n}return"configured slack connector"});return{summary:r,hint:`Add ${e}=xoxb-\u2026 and ${a}=xapp-\u2026 to your .env.`}}function mi(t){let e=!!t?.enabled,{summary:a}=A(n=>(n.channels=n.channels||{},n.channels.slack=n.channels.slack||{enabled:!1},n.channels.slack.enabled=e,`slack ${e?"enabled":"disabled"}`));return{summary:a}}function fi(t){let e=String(t?.tokenEnv||"").trim(),a=String(t?.agentBinding||"").trim();if(!e)throw new Error("Bot token env-var name is required (e.g. DISCORD_BOT_TOKEN).");let{summary:n}=A(r=>{if(r.channels=r.channels||{},r.channels.discord=r.channels.discord||{enabled:!1},r.channels.discord.enabled=!0,r.channels.discord.token="${"+e+"}",a){if(!r.agents?.[a])throw new Error(`Unknown agent "${a}".`);r.channels.discord.agentBinding=a}return"configured discord connector"});return{summary:n,hint:`Add ${e}=<bot-token> to your .env.`}}function hi(t){let e=!!t?.enabled,{summary:a}=A(n=>(n.channels=n.channels||{},n.channels.discord=n.channels.discord||{enabled:!1},n.channels.discord.enabled=e,`discord ${e?"enabled":"disabled"}`));return{summary:a}}function gi(t){let e=String(t?.host||"").trim().replace(/\/+$/,""),a=String(t?.tokenEnv||"").trim(),n=parseInt(String(t?.webhookPort||"18810"),10);if(!e||!/^https?:\/\//.test(e))throw new Error("Host must start with http:// or https://");if(!a)throw new Error("Admin token env-var name is required (e.g. GITLAB_TOKEN).");if(!Number.isFinite(n)||n<1||n>65535)throw new Error("Webhook port must be between 1 and 65535.");let{summary:r}=A(o=>(o.channels=o.channels||{},o.channels.gitlab=o.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},o.channels.gitlab.enabled=!0,o.channels.gitlab.host=e,o.channels.gitlab.token="${"+a+"}",o.channels.gitlab.webhookPort=n,"configured gitlab connector"));return{summary:r,hint:`Add ${a}=<personal-access-token> to your .env. Per-project routes + per-agent tokens stay in the Advanced JSON editor.`}}function xi(t){let e=!!t?.enabled,{summary:a}=A(n=>(n.channels=n.channels||{},n.channels.gitlab=n.channels.gitlab||{enabled:!1,routes:[],agentMappings:[]},n.channels.gitlab.enabled=e,`gitlab ${e?"enabled":"disabled"}`));return{summary:a}}async function vi(t){let e=String(t?.schedule||"").trim();if(!e)throw new Error("schedule is required");let{getNextCronDate:a}=await import("./scheduler-VPPKD4FY.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 bi(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Account id is required.");let{summary:a}=A(n=>{if(!n.channels?.telegram?.accounts?.[e])throw new Error(`Account "${e}" not found.`);return delete n.channels.telegram.accounts[e],`removed telegram account "${e}"`});return{summary:a}}function yi(t){let e=!!t?.enabled,{summary:a}=A(n=>(n.channels=n.channels||{},n.channels.telegram=n.channels.telegram||{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},n.channels.telegram.enabled=e,`telegram ${e?"enabled":"disabled"}`));return{summary:a}}function wi(t){let e=String(t?.id||"").trim(),a=String(t?.schedule||"").trim(),n=String(t?.agent||"").trim(),r=String(t?.prompt||"").trim();if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Cron id must be lowercase (letters, digits, -, _).");if(!a)throw new Error("Cron expression is required (e.g. '0 9 * * 1' for Mondays at 9am).");if(!n)throw new Error("Pick an agent to run this schedule.");if(!r)throw new Error("A prompt is required (what should the agent do?).");let{summary:o}=A(s=>{if(s.crons=s.crons||{},s.crons[e])throw new Error(`Cron "${e}" already exists.`);if(!s.agents?.[n])throw new Error(`Unknown agent "${n}".`);return s.crons[e]={schedule:a,agent:n,prompt:r,enabled:!0},`added cron "${e}"`});return{summary:o}}function ki(t){let e=String(t?.id||"").trim();if(!e)throw new Error("Cron id is required.");let{summary:a}=A(n=>{if(!n.crons?.[e])throw new Error(`Cron "${e}" not found.`);return delete n.crons[e],`removed cron "${e}"`});return{summary:a}}function _i(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=Le(process.cwd(),"agentx.json"),r=`${n}.bak.${Date.now()}`;if(st(n))try{Os(n,r)}catch{}Sn(n,JSON.stringify(a,null,2)+`
4767
+ `,"utf-8");try{let s=te().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 In(t){return String(t||"").split(/[,\s]+/).map(e=>e.trim()).filter(Boolean).filter((e,a,n)=>n.indexOf(e)===a)}async function Ei(t){let e=String(t?.agentId||"").trim(),a=String(t?.role||"").trim();if(!e)throw new Error("agentId required");if(!a)throw new Error("role required");let n=Array.isArray(t?.days)&&t.days.length>0?t.days:["mon","tue","wed","thu","fri"],r=String(t?.start||"09:00"),o=String(t?.end||"17:00"),s=t?.reportsTo?String(t.reportsTo).trim():"",i=typeof t?.utilizationTarget=="number"?t.utilizationTarget:.8,{summary:l}=A(c=>(c.business=c.business||{},c.business.orgChart=c.business.orgChart||{},c.business.orgChart[e]={role:a,...s?{reportsTo:s}:{},schedule:{days:n,start:r,end:o},utilizationTarget:i},`orgChart "${e}" upserted`));return{summary:l}}async function Si(t){let e=String(t?.agentId||"").trim();if(!e)throw new Error("agentId required");let{summary:a}=A(n=>{if(!n.business?.orgChart||!(e in n.business.orgChart))throw new Error(`no orgChart entry for "${e}"`);return delete n.business.orgChart[e],`orgChart "${e}" removed`});return{summary:a}}async function Ti(t){let e=String(t?.id||"").trim();if(!e)throw new Error("project id required");let a=t?.pm?String(t.pm).trim():"",n=t?.client?String(t.client).trim():"",{summary:r}=A(o=>{o.business=o.business||{},o.business.projects=o.business.projects||[];let s=o.business.projects.findIndex(l=>l.id===e),i={id:e,...a?{pm:a}:{},...n?{client:n}:{}};return s>=0?o.business.projects[s]={...o.business.projects[s],...i}:o.business.projects.push(i),s>=0?`project "${e}" updated`:`project "${e}" added`});return{summary:r}}async function Ai(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let a=String(t?.kind||"").trim();if(a&&!["client","internal","own"].includes(a))throw new Error("kind must be client, internal or own");let n=String(t?.respondWithin||"").trim();if(n&&!/^\d+\s*[mhd]$/.test(n))throw new Error('respondWithin must look like "4h", "90m" or "2d"');let r=Array.isArray(t?.standing)?t.standing.map(s=>String(s).trim()).filter(Boolean):String(t?.standing||"").split(",").map(s=>s.trim()).filter(Boolean),{summary:o}=A(s=>{s.business=s.business||{},s.business.clients=s.business.clients||{};let i=!!s.business.clients[e];return s.business.clients[e]={...s.business.clients[e]||{},...t?.name?{name:String(t.name).trim()}:{},...a?{kind:a}:{},...n?{respondWithin:n}:{},standing:r},i?`client "${e}" updated`:`client "${e}" configured`});return{summary:o}}async function Ci(t){let e=String(t?.id||"").trim();if(!e)throw new Error("client id required");let{summary:a}=A(n=>{if(!n.business?.clients?.[e])throw new Error(`no client override "${e}"`);return delete n.business.clients[e],`client "${e}" reset to defaults`});return{summary:a}}async function Mi(t){let e=String(t?.id||"").trim();if(!e)throw new Error("project id required");let{summary:a}=A(n=>{let r=n.business?.projects||[],o=r.length;if(n.business.projects=r.filter(s=>s.id!==e),n.business.projects.length===o)throw new Error(`no project "${e}"`);return`project "${e}" removed`});return{summary:a}}async function Ii(t){let e=String(t?.client||"").trim();if(!e)throw new Error("client required");if(!t?.chatId&&!t?.username&&!t?.senderId)throw new Error("one of chatId / username / senderId required");let{summary:a}=A(n=>{n.business=n.business||{},n.business.contactMap=n.business.contactMap||[];let r={client:e};t?.channel&&(r.channel=String(t.channel)),t?.chatId&&(r.chatId=String(t.chatId)),t?.username&&(r.username=String(t.username)),t?.senderId&&(r.senderId=String(t.senderId)),t?.project&&(r.project=String(t.project)),t?.displayName&&(r.displayName=String(t.displayName)),n.business.contactMap.push(r);let o=r.chatId||r.username||r.senderId;return`contact ${r.channel?r.channel+"/":""}${o} \u2192 ${e} added`});return{summary:a}}async function Li(t){let a=["channel","chatId","username","senderId"].filter(r=>t?.[r]);if(a.length===0)throw new Error("at least one filter (channel/chatId/username/senderId) required");let{summary:n}=A(r=>{let o=r.business?.contactMap||[],s=o.length;if(r.business.contactMap=o.filter(i=>{for(let l of a)if(i[l]!==t[l])return!0;return!1}),r.business.contactMap.length===s)throw new Error("no matching contact entry");return`${s-r.business.contactMap.length} contact entry/entries removed`});return{summary:n}}async function $i(t){let e=String(t?.id||"").trim(),a=String(t?.name||"").trim(),n=String(t?.projects||"").split(/[,\n]/).map(l=>l.trim()).filter(Boolean);if(!e)throw new Error("id required");if(!a)throw new Error("name required");if(n.length===0)throw new Error("at least one project path required");let r=t?.primaryToolLabel?String(t.primaryToolLabel).trim():"",o=Number.isFinite(Number(t?.timeRangeDays))?Number(t.timeRangeDays):30,s=Number.isFinite(Number(t?.closedWindowDays))?Number(t.closedWindowDays):30,{summary:i}=A(l=>{l.boards=Array.isArray(l.boards)?l.boards:[];let c=l.boards.findIndex(u=>u.id===e),p={id:e,name:a,source:{type:"gitlab",projects:n},timeRangeDays:o,closedWindowDays:s};if(r&&(p.primaryToolLabel=r),c>=0){let u=l.boards[c];return l.boards[c]={...u,...p,columns:u.columns,labels:u.labels},`board "${e}" updated`}return l.boards.push(p),`board "${e}" added`});return{summary:i}}async function Ri(t){let e=String(t?.id||"").trim();if(!e)throw new Error("id required");let{summary:a}=A(n=>{let r=Array.isArray(n.boards)?n.boards:[],o=r.length;if(n.boards=r.filter(s=>s.id!==e),n.boards.length===o)throw new Error(`board "${e}" not found`);return`board "${e}" removed`});return{summary:a}}async function Pi(t){let e=String(t?.boardId||"").trim(),a=String(t?.columnId||"").trim().toLowerCase().replace(/[^a-z0-9_-]/g,"-"),n=String(t?.title||"").trim(),r=String(t?.kind||"scoped-label");if(!e)throw new Error("boardId required");if(!a)throw new Error("columnId required");if(!n)throw new Error("title required");if(!["open-backlog","scoped-label","closed","label"].includes(r))throw new Error("kind must be open-backlog | scoped-label | closed | label");let{summary:o}=A(s=>{let l=(Array.isArray(s.boards)?s.boards:[]).find(u=>u.id===e);if(!l)throw new Error(`board "${e}" not found`);l.columns=Array.isArray(l.columns)?l.columns:[];let c={id:a,title:n,kind:r,scopedPrefix:t?.scopedPrefix||"Status"};if(r==="scoped-label"){if(!t?.scopedLabel)throw new Error("scopedLabel required for kind=scoped-label");c.scopedLabel=String(t.scopedLabel)}if(r==="label"){if(!t?.mapsToLabel)throw new Error("mapsToLabel required for kind=label");c.mapsToLabel=String(t.mapsToLabel)}t?.accent&&(c.accent=String(t.accent));let p=l.columns.findIndex(u=>u.id===a);return p>=0?(l.columns[p]={...l.columns[p],...c},`column "${a}" updated`):(l.columns.push(c),`column "${a}" added to board "${e}"`)});return{summary:o}}async function ji(t){let e=String(t?.boardId||"").trim(),a=String(t?.columnId||"").trim();if(!e||!a)throw new Error("boardId and columnId required");let{summary:n}=A(r=>{let s=(Array.isArray(r.boards)?r.boards:[]).find(l=>l.id===e);if(!s)throw new Error(`board "${e}" not found`);let i=(s.columns||[]).length;if(s.columns=(s.columns||[]).filter(l=>l.id!==a),s.columns.length===i)throw new Error(`column "${a}" not found`);return`column "${a}" removed from board "${e}"`});return{summary:n}}async function Oi(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{actionSchema:a}=await import("./types-DO3KLIBS.js");if(!t||typeof t!="object")throw new Error("body required");let n=a.safeParse(t);if(!n.success){let o=n.error.issues[0];throw new Error(`${o.path.join(".")||"<root>"}: ${o.message}`)}let r=new e().save(n.data);return{summary:`action "${r.id}" saved (${r.kind})`,action:r}}async function Ni(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),a=String(t?.id||"").trim();if(!a)throw new Error("id required");if(!new e().delete(a))throw new Error(`action "${a}" not found`);return{summary:`action "${a}" removed`}}async function Di(t){let{ActionStore:e}=await import("./store-TWQPEM5V.js"),{runAction:a}=await import("./runner-56G3N7M4.js"),n=String(t?.id||"").trim();if(!n)throw new Error("id required");let r=new e().get(n);if(!r)throw new Error(`action "${n}" not found`);let o=t?.inputs&&typeof t.inputs=="object"?t.inputs:{},s=await a(r,o);return{summary:`action "${n}" ${s.ok?"ok":"failed"} (${s.durationMs}ms)`,result:s}}async function Hi(t){let e=t?.interval!==void 0?Number(t.interval):void 0,a=t?.timeout!==void 0?Number(t.timeout):void 0;if(e!==void 0&&(!Number.isFinite(e)||e<5||e>3600))throw new Error("interval must be 5..3600 seconds");if(a!==void 0&&(!Number.isFinite(a)||a<1||a>60))throw new Error("timeout must be 1..60 seconds");if(e===void 0&&a===void 0)throw new Error("nothing to update");let{summary:n}=A(r=>(r.mesh=r.mesh||{},r.mesh.healthCheck=r.mesh.healthCheck||{},e!==void 0&&(r.mesh.healthCheck.interval=e),a!==void 0&&(r.mesh.healthCheck.timeout=a),`mesh.healthCheck updated (interval=${r.mesh.healthCheck.interval}s, timeout=${r.mesh.healthCheck.timeout}s)`));return{summary:n}}async function Bi(t){let{summary:e}=A(a=>{a.notifications=a.notifications||{};let n=[];if(t&&typeof t=="object"){if("destination"in t)if(!t.destination)delete a.notifications.destination,n.push("destination cleared");else if(t.destination.channel&&t.destination.chatId)a.notifications.destination={channel:String(t.destination.channel),chatId:String(t.destination.chatId),...t.destination.accountId?{accountId:String(t.destination.accountId)}:{}},n.push(`destination=${t.destination.channel}:${t.destination.chatId}`);else throw new Error("destination requires channel + chatId");if("on"in t&&t.on&&typeof t.on=="object"){a.notifications.on=a.notifications.on||{};for(let r of["taskComplete","taskError","taskQueued"])r in t.on&&(a.notifications.on[r]=!!t.on[r]);n.push("on="+JSON.stringify(a.notifications.on))}if("longTaskThreshold"in t){let r=Number(t.longTaskThreshold);if(!Number.isFinite(r)||r<0)throw new Error("longTaskThreshold must be a non-negative number");a.notifications.longTaskThreshold=r,n.push(`threshold=${r}s`)}"local"in t&&t.local&&typeof t.local=="object"&&(a.notifications.local=Ma(a.notifications.local,t.local),n.push("local="+JSON.stringify(a.notifications.local))),"ntfy"in t&&t.ntfy&&typeof t.ntfy=="object"&&(a.channels=a.channels||{},a.channels.ntfy=mn(a.channels.ntfy,t.ntfy),n.push(`ntfy ${a.channels.ntfy.enabled?"on":"off"} (restart the daemon to apply)`))}if(n.length===0)throw new Error("nothing to update");return`notifications updated (${n.join(", ")})`});return{summary:e}}async function zi(t){if(!t||typeof t!="object")throw new Error("nothing to update");let{summary:e}=A(a=>(a.screen=Ka(a.screen,t),`screen updated (buffer ${a.screen.buffer?.enabled?"on":"off"})`));return{summary:e}}async function Fi(t){let e=String(t?.id||"").trim();if(!e)throw new Error("webhook id required");let{summary:a}=A(n=>{let o=(Array.isArray(n.webhooks)?n.webhooks:[]).find(s=>s.id===e);if(!o)throw new Error(`webhook "${e}" not found`);if("triggers"in t){if(t.triggers===null||typeof t.triggers=="object"&&Object.keys(t.triggers).length===0)delete o.triggers;else if(typeof t.triggers=="object"){let s={};for(let[i,l]of Object.entries(t.triggers))typeof l=="string"&&l.trim()&&(s[String(i)]=l.trim());Object.keys(s).length===0?delete o.triggers:o.triggers=s}}return"defaultWorkflow"in t&&(t.defaultWorkflow?o.defaultWorkflow=String(t.defaultWorkflow).trim():delete o.defaultWorkflow),`webhook "${e}" triggers/defaultWorkflow updated`});return{summary:a}}kt();import{resolve as Wi}from"path";function Ln(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div id="msg" class="msg"></div>
4768
4768
 
4769
4769
  <div id="disabled-banner" class="banner warn" style="display:none">
4770
4770
  <b>Graph is disabled.</b> Set <code class="mono">graph.enabled: true</code>
@@ -4819,7 +4819,7 @@ ${s||"You are "+a+"."}
4819
4819
  <h2>Recent classifications</h2>
4820
4820
  <p class="muted">Last 25 log rows, newest first \u2014 approved / pending / rejected.</p>
4821
4821
  <div id="recent"></div>
4822
- </section>`;return $({title:"AgentX \xB7 Intent Graph",activeTab:"graph",subtitle:"Intent Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:fi,scripts:`${e}<script>${hi}</script>`})}var fi=`
4822
+ </section>`;return L({title:"AgentX \xB7 Intent Graph",activeTab:"graph",subtitle:"Intent Graph",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:qi,scripts:`${e}<script>${Ui}</script>`})}var qi=`
4823
4823
  main { max-width: 1200px; margin: 0 auto; padding: 24px 20px 60px; }
4824
4824
  h2 { margin: 0 0 12px; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
4825
4825
  .grid { display: grid; gap: 20px; grid-template-columns: 1fr; }
@@ -4923,7 +4923,7 @@ details {
4923
4923
  border-radius: 4px; padding: 8px 12px; margin-top: 8px;
4924
4924
  }
4925
4925
  details summary { cursor: pointer; font-size: 11px; color: var(--ax-muted); user-select: none; }
4926
- details[open] summary { margin-bottom: 8px; }`,hi=`
4926
+ details[open] summary { margin-bottom: 8px; }`,Ui=`
4927
4927
  const $ = (id) => document.getElementById(id);
4928
4928
  const state = { schema: null, nodes: [], pending: [], recent: [] };
4929
4929
 
@@ -5143,7 +5143,7 @@ $('btn-save-schema').addEventListener('click', async () => {
5143
5143
  $('btn-reload-schema').addEventListener('click', refresh);
5144
5144
 
5145
5145
  refresh();
5146
- `;function Sn(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(_n({peers:a,localToken:n}))}async function Tn(t,e,a){try{let n=t.method==="GET"?void 0:await Si(t),r=xi(),o={"GET /api/admin/graph/state":()=>vi(r),"POST /api/admin/graph/classifications/approve":()=>bi(r,n),"POST /api/admin/graph/classifications/reject":()=>yi(r,n),"POST /api/admin/graph/nodes":()=>wi(r,n),"PATCH /api/admin/graph/nodes":()=>ki(r,n),"DELETE /api/admin/graph/nodes":()=>_i(r,n),"PUT /api/admin/graph/schema":()=>Ei(r,n)},s=`${t.method} ${a}`,i=o[s];if(!i){Rt(e,404,{error:`unknown graph endpoint: ${s}`});return}let l=await i();Rt(e,200,l)}catch(n){Rt(e,400,{error:n?.message||"graph op failed"})}}function xi(){let t=Q(),e=gi(process.cwd(),t.graph.baseDir);return new la({baseDir:e})}function vi(t){let e=Q(),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 bi(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=Cn(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=jt(e.proposedAxes)),t.approveClassification(n),{summary:`Approved ${n.msgHash}`}}function yi(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=Cn(t,a);return t.rejectClassification(n),{summary:`Rejected ${n.msgHash}`}}function Cn(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 wi(t,e){let a=En(String(e?.id||"")),n=String(e?.level||"").trim(),r=e?.parentId?En(String(e.parentId)):null,o=jt({[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 ki(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");let n=jt({[a]:e?.axes||{}})[a]||{};return{node:t.updateNodeAxes(a,n)}}function _i(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");return t.deleteNode(a),{summary:`Deleted ${a}`}}function Ei(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 jt(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 En(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")}function Rt(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Si(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 An(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div class="apv">
5146
+ `;function Rn(t,e,a=[],n){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ln({peers:a,localToken:n}))}async function Pn(t,e,a){try{let n=t.method==="GET"?void 0:await el(t),r=Gi(),o={"GET /api/admin/graph/state":()=>Xi(r),"POST /api/admin/graph/classifications/approve":()=>Ki(r,n),"POST /api/admin/graph/classifications/reject":()=>Ji(r,n),"POST /api/admin/graph/nodes":()=>Vi(r,n),"PATCH /api/admin/graph/nodes":()=>Yi(r,n),"DELETE /api/admin/graph/nodes":()=>Qi(r,n),"PUT /api/admin/graph/schema":()=>Zi(r,n)},s=`${t.method} ${a}`,i=o[s];if(!i){jt(e,404,{error:`unknown graph endpoint: ${s}`});return}let l=await i();jt(e,200,l)}catch(n){jt(e,400,{error:n?.message||"graph op failed"})}}function Gi(){let t=te(),e=Wi(process.cwd(),t.graph.baseDir);return new fa({baseDir:e})}function Xi(t){let e=te(),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 Ki(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=jn(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=Ot(e.proposedAxes)),t.approveClassification(n),{summary:`Approved ${n.msgHash}`}}function Ji(t,e){let a=String(e?.msgHash||"").trim();if(!a)throw new Error("msgHash is required");let n=jn(t,a);return t.rejectClassification(n),{summary:`Rejected ${n.msgHash}`}}function jn(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 Vi(t,e){let a=$n(String(e?.id||"")),n=String(e?.level||"").trim(),r=e?.parentId?$n(String(e.parentId)):null,o=Ot({[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 Yi(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");let n=Ot({[a]:e?.axes||{}})[a]||{};return{node:t.updateNodeAxes(a,n)}}function Qi(t,e){let a=String(e?.id||"").trim();if(!a)throw new Error("id is required");return t.deleteNode(a),{summary:`Deleted ${a}`}}function Zi(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 Ot(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 $n(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")}function jt(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function el(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 On(t={}){let e=t.localToken?`<script>window.AX_LOCAL_TOKEN = ${JSON.stringify(t.localToken)};</script>`:"",a=`<div class="apv">
5147
5147
  <header class="apv__head">
5148
5148
  <div>
5149
5149
  <h1>Approvals</h1>
@@ -5176,7 +5176,7 @@ refresh();
5176
5176
  <div><button type="submit" class="ax-btn ax-btn--primary">Save settings</button></div>
5177
5177
  </form>
5178
5178
  </details>
5179
- </div>`;return $({title:"AgentX \xB7 Approvals",activeTab:"approvals",subtitle:"Approvals",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Ti,scripts:`${e}<script>${Ci}</script>`})}var Ti=`
5179
+ </div>`;return L({title:"AgentX \xB7 Approvals",activeTab:"approvals",subtitle:"Approvals",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:tl,scripts:`${e}<script>${al}</script>`})}var tl=`
5180
5180
  .apv { max-width: 860px; margin: 0 auto; padding: 20px 16px 64px; color: var(--ax-text); }
5181
5181
  .apv__head { display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; align-items: flex-end; margin-bottom: 14px; }
5182
5182
  .apv__head h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
@@ -5225,7 +5225,7 @@ refresh();
5225
5225
  @media (max-width: 560px) {
5226
5226
  .apv__acts .ax-btn { flex: 1 1 0; }
5227
5227
  }
5228
- `,Ci=`
5228
+ `,al=`
5229
5229
  (function(){
5230
5230
  var state = { items: [], snoozed: 0, kind: '', showAll: false };
5231
5231
  var LABEL = { card: 'Card', schedule: 'Schedule', memory: 'Memory fact', wiki: 'Wiki lesson' };
@@ -5376,7 +5376,7 @@ $('apv-form').addEventListener('submit', async function(ev){
5376
5376
  load();
5377
5377
  setInterval(function(){ if (document.visibilityState === 'visible' && !document.querySelector('.apv__item:focus-within')) load(); }, 60000);
5378
5378
  })();
5379
- `;var Ai=["yes","no","later"];function de(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function Mn(t,e=64*1024){let a=0,n=[];for await(let s of t){if(a+=s.length,a>e)throw new Error("body too large");n.push(s)}let r=Buffer.concat(n).toString("utf-8");if(!r.trim())return{};let o=JSON.parse(r);if(!o||typeof o!="object"||Array.isArray(o))throw new Error("expected a JSON object");return o}function In(t,e,a){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(An({peers:e,localToken:a}))}async function $n(t,e,a,n,r={}){if(!a.startsWith("/api/admin/approvals"))return!1;let o=(t.method||"GET").toUpperCase(),s=r.ctx??{root:process.cwd(),configPath:r.configPath,reload:r.reload};if(o!=="GET"&&t.headers["x-requested-with"]!=="agentx-board")return de(e,400,{error:"missing X-Requested-With: agentx-board"}),!0;try{if(o==="GET"&&a==="/api/admin/approvals"){let i=Ge(s,{includeSnoozed:n.searchParams.get("all")==="1"});return de(e,200,{...i,settings:Ce(s.configPath)}),!0}if(o==="POST"&&a==="/api/admin/approvals/decide"){let i=await Mn(t),l=typeof i.key=="string"?i.key:"",c=i.action;if(!l||!Ai.includes(c))return de(e,400,{error:"send { key, action: yes | no | later }"}),!0;let p=Ce(s.configPath),u=await Xe(s,l,c,{note:typeof i.note=="string"?i.note:void 0,force:i.force===!0,laterHours:p.laterHours,by:"operator (dashboard)"});return u.ok?(de(e,200,{ok:!0,message:u.message}),!0):(de(e,409,{error:u.error}),!0)}if(o==="POST"&&a==="/api/admin/approvals/settings"){let i=await Mn(t),l={},c=u=>{let f=i[u];if(f!==void 0){if(typeof f!="number"||!(f>0))throw new Error(`${u} must be a positive number`);return f}};if(l.defaultExpiryDays=c("defaultExpiryDays"),l.maxExpiryDays=c("maxExpiryDays"),l.laterHours=c("laterHours"),typeof i.notifyAgent=="boolean"&&(l.notifyAgent=i.notifyAgent),typeof i.digestEnabled=="boolean"&&(l.digestEnabled=i.digestEnabled),typeof i.digestTime=="string"&&(l.digestTime=i.digestTime),typeof i.destination=="string"){let u=i.destination.trim();if(!u)l.destination=null;else{let f=en(u);if(!f)throw new Error("digest destination takes channel:chat id, for example telegram:123456");l.destination=f}}let p=await tn(l,{configPath:s.configPath,reload:s.reload});return p.success?(de(e,200,{ok:!0,settings:Ce(s.configPath)}),!0):(de(e,400,{error:p.error}),!0)}}catch(i){return de(e,400,{error:String(i?.message??i).slice(0,300)}),!0}return de(e,404,{error:"Not found"}),!0}import{resolve as $i}from"path";import{existsSync as Li}from"fs";import Ri from"better-sqlite3";function Ln(t={}){let e=`<div class="ax-obs">
5379
+ `;var nl=["yes","no","later"];function pe(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function Nn(t,e=64*1024){let a=0,n=[];for await(let s of t){if(a+=s.length,a>e)throw new Error("body too large");n.push(s)}let r=Buffer.concat(n).toString("utf-8");if(!r.trim())return{};let o=JSON.parse(r);if(!o||typeof o!="object"||Array.isArray(o))throw new Error("expected a JSON object");return o}function Dn(t,e,a){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(On({peers:e,localToken:a}))}async function Hn(t,e,a,n,r={}){if(!a.startsWith("/api/admin/approvals"))return!1;let o=(t.method||"GET").toUpperCase(),s=r.ctx??{root:process.cwd(),configPath:r.configPath,reload:r.reload};if(o!=="GET"&&t.headers["x-requested-with"]!=="agentx-board")return pe(e,400,{error:"missing X-Requested-With: agentx-board"}),!0;try{if(o==="GET"&&a==="/api/admin/approvals"){let i=Xe(s,{includeSnoozed:n.searchParams.get("all")==="1"});return pe(e,200,{...i,settings:Ie(s.configPath)}),!0}if(o==="POST"&&a==="/api/admin/approvals/decide"){let i=await Nn(t),l=typeof i.key=="string"?i.key:"",c=i.action;if(!l||!nl.includes(c))return pe(e,400,{error:"send { key, action: yes | no | later }"}),!0;let p=Ie(s.configPath),u=await Ke(s,l,c,{note:typeof i.note=="string"?i.note:void 0,force:i.force===!0,laterHours:p.laterHours,by:"operator (dashboard)"});return u.ok?(pe(e,200,{ok:!0,message:u.message}),!0):(pe(e,409,{error:u.error}),!0)}if(o==="POST"&&a==="/api/admin/approvals/settings"){let i=await Nn(t),l={},c=u=>{let f=i[u];if(f!==void 0){if(typeof f!="number"||!(f>0))throw new Error(`${u} must be a positive number`);return f}};if(l.defaultExpiryDays=c("defaultExpiryDays"),l.maxExpiryDays=c("maxExpiryDays"),l.laterHours=c("laterHours"),typeof i.notifyAgent=="boolean"&&(l.notifyAgent=i.notifyAgent),typeof i.digestEnabled=="boolean"&&(l.digestEnabled=i.digestEnabled),typeof i.digestTime=="string"&&(l.digestTime=i.digestTime),typeof i.destination=="string"){let u=i.destination.trim();if(!u)l.destination=null;else{let f=cn(u);if(!f)throw new Error("digest destination takes channel:chat id, for example telegram:123456");l.destination=f}}let p=await dn(l,{configPath:s.configPath,reload:s.reload});return p.success?(pe(e,200,{ok:!0,settings:Ie(s.configPath)}),!0):(pe(e,400,{error:p.error}),!0)}}catch(i){return pe(e,400,{error:String(i?.message??i).slice(0,300)}),!0}return pe(e,404,{error:"Not found"}),!0}import{resolve as sl}from"path";import{existsSync as il}from"fs";import ll from"better-sqlite3";function Bn(t={}){let e=`<div class="ax-obs">
5380
5380
  <header class="ax-obs__head">
5381
5381
  <h1>Health</h1>
5382
5382
  <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>
@@ -5498,7 +5498,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
5498
5498
  </div>
5499
5499
  <div id="obs-doctor-body" class="ax-obs__doctor-body"></div>
5500
5500
  </section>
5501
- </div>`;return $({title:"AgentX \xB7 Health",activeTab:"health",subtitle:"Health",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Mi,scripts:`<script>${Ii}</script>`})}var Mi=`
5501
+ </div>`;return L({title:"AgentX \xB7 Health",activeTab:"health",subtitle:"Health",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:rl,scripts:`<script>${ol}</script>`})}var rl=`
5502
5502
  .ax-obs { padding: 16px 24px; }
5503
5503
  .ax-obs__head { margin-bottom: 16px; }
5504
5504
  .ax-obs__head h1 { margin: 0 0 4px; font-size: 18px; }
@@ -5615,7 +5615,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
5615
5615
  .ax-obs__doctor-title { font-size: 12px; font-weight: 500; }
5616
5616
  .ax-obs__doctor-detail { font-size: 11px; color: var(--ax-muted); margin-top: 2px; font-family: 'IBM Plex Mono', monospace; word-break: break-word; }
5617
5617
  .ax-obs__doctor-fix { font-size: 11px; color: var(--ax-accent, #3a7bd5); margin-top: 2px; }
5618
- `,Ii=`
5618
+ `,ol=`
5619
5619
  (function(){
5620
5620
  var panes = document.querySelectorAll('.ax-obs__pane');
5621
5621
  var tabs = document.querySelectorAll('.ax-obs__tab');
@@ -5999,23 +5999,23 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
5999
5999
 
6000
6000
  load(current);
6001
6001
  })();
6002
- `;var Pn={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 On(t){let e=(t||"").toLowerCase();return e.includes("opus")?"opus":e.includes("haiku")?"haiku":e.includes("sonnet")||e.includes("claude")?"sonnet":"external"}function Pt(t){let e=Pn[On(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 ji(){let t=$i(process.cwd(),".agentx/db.sqlite");if(!Li(t))return null;try{let e=new Ri(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch{return null}}function Nn(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ln({peers:a}))}function Pi(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 pe(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function Dn(t,e,a){if(!a.startsWith("/api/admin/observability/"))return!1;let n=a.replace(/^\/api\/admin\/observability\//,"").split("?")[0],r=ji();if(!r)return pe(e,503,{error:"operational SQLite not available",rows:[]}),!0;try{let{limit:o,agent:s}=Pi(t);if(n==="routing"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
6002
+ `;var qn={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 Un(t){let e=(t||"").toLowerCase();return e.includes("opus")?"opus":e.includes("haiku")?"haiku":e.includes("sonnet")||e.includes("claude")?"sonnet":"external"}function Nt(t){let e=qn[Un(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 cl(){let t=sl(process.cwd(),".agentx/db.sqlite");if(!il(t))return null;try{let e=new ll(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch{return null}}function Wn(t,e,a=[]){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Bn({peers:a}))}function dl(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 ue(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}async function Gn(t,e,a){if(!a.startsWith("/api/admin/observability/"))return!1;let n=a.replace(/^\/api\/admin\/observability\//,"").split("?")[0],r=cl();if(!r)return ue(e,503,{error:"operational SQLite not available",rows:[]}),!0;try{let{limit:o,agent:s}=dl(t);if(n==="routing"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
6003
6003
  SELECT at, channel, chat_id, account_id, kind, deciding_stage, agent_id, reason
6004
6004
  FROM route_traces
6005
6005
  ${i.length?"WHERE "+i.join(" AND "):""}
6006
6006
  ORDER BY at DESC LIMIT @limit
6007
- `,p=r.db.prepare(c).all(l);return pe(e,200,{rows:p}),!0}if(n==="rotations"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
6007
+ `,p=r.db.prepare(c).all(l);return ue(e,200,{rows:p}),!0}if(n==="rotations"){let i=[],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
6008
6008
  SELECT rotated_at, agent_id, channel, reason, last_turn_input_tokens
6009
6009
  FROM rotations
6010
6010
  ${i.length?"WHERE "+i.join(" AND "):""}
6011
6011
  ORDER BY rotated_at DESC LIMIT @limit
6012
- `,p=r.db.prepare(c).all(l);return pe(e,200,{rows:p}),!0}if(n==="errors"){let i=["status = 'error'"],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
6012
+ `,p=r.db.prepare(c).all(l);return ue(e,200,{rows:p}),!0}if(n==="errors"){let i=["status = 'error'"],l={limit:o};s&&(i.push("agent_id = @agent"),l.agent=s);let c=`
6013
6013
  SELECT started_at, agent_id, channel, message_preview, error
6014
6014
  FROM task_history
6015
6015
  WHERE ${i.join(" AND ")}
6016
6016
  ORDER BY started_at DESC LIMIT @limit
6017
- `,u=r.db.prepare(c).all(l).map(f=>({...f,plain:Hn(f.error)}));return pe(e,200,{rows:u}),!0}if(n==="summary"||n==="overview")return pe(e,200,Oi(r.db)),!0;if(n==="activity")return pe(e,200,Ni(r.db,{agent:s})),!0;if(n==="cost"){let i=new URL(t.url||"/","http://_"),l=Rn(i.searchParams.get("range"));return pe(e,200,jn(r.db,l)),!0}if(n==="cost.csv"){let i=new URL(t.url||"/","http://_"),l=Rn(i.searchParams.get("range")),c=jn(r.db,l),p=Di(c.days);return e.writeHead(200,{"Content-Type":"text/csv; charset=utf-8","Content-Disposition":`attachment; filename="agentx-cost-${l||"all"}d-${Date.now()}.csv"`}),e.end(p),!0}return pe(e,404,{error:"unknown observability slice",rows:[]}),!0}catch(o){return pe(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function Hn(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(`
6018
- `)[0].slice(0,80)+(e.length>80?"\u2026":""):"unknown failure"}function Oi(t){let e=new Date,a=new Date(e.getFullYear(),e.getMonth(),e.getDate()).toISOString(),n=new Date(e.getTime()-864e5),r=new Date(n.getFullYear(),n.getMonth(),n.getDate()).toISOString(),o=new Date(e.getTime()-864e5).toISOString(),s=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ?").get(a).n,i=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ? AND started_at < ?").get(r,a).n,l=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE status='error' AND started_at >= ?").get(a).n,c=t.prepare("SELECT AVG(duration_ms) AS d FROM task_history WHERE status='ok' AND started_at >= ?").get(a).d??0,p=t.prepare("SELECT duration_ms FROM task_history WHERE status='ok' AND started_at >= ? AND duration_ms IS NOT NULL ORDER BY duration_ms ASC").all(a),u=_=>p.length?p[Math.min(p.length-1,Math.floor(p.length*_))].duration_ms:0,f=u(.5),h=u(.95),T=t.prepare("SELECT * FROM usage_daily WHERE day = date('now')").all().reduce((_,M)=>_+Pt(M),0),S=t.prepare("SELECT * FROM usage_daily WHERE day = date('now', '-1 day')").all().reduce((_,M)=>_+Pt(M),0),x=t.prepare(`
6017
+ `,u=r.db.prepare(c).all(l).map(f=>({...f,plain:Xn(f.error)}));return ue(e,200,{rows:u}),!0}if(n==="summary"||n==="overview")return ue(e,200,pl(r.db)),!0;if(n==="activity")return ue(e,200,ul(r.db,{agent:s})),!0;if(n==="cost"){let i=new URL(t.url||"/","http://_"),l=zn(i.searchParams.get("range"));return ue(e,200,Fn(r.db,l)),!0}if(n==="cost.csv"){let i=new URL(t.url||"/","http://_"),l=zn(i.searchParams.get("range")),c=Fn(r.db,l),p=ml(c.days);return e.writeHead(200,{"Content-Type":"text/csv; charset=utf-8","Content-Disposition":`attachment; filename="agentx-cost-${l||"all"}d-${Date.now()}.csv"`}),e.end(p),!0}return ue(e,404,{error:"unknown observability slice",rows:[]}),!0}catch(o){return ue(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function Xn(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(`
6018
+ `)[0].slice(0,80)+(e.length>80?"\u2026":""):"unknown failure"}function pl(t){let e=new Date,a=new Date(e.getFullYear(),e.getMonth(),e.getDate()).toISOString(),n=new Date(e.getTime()-864e5),r=new Date(n.getFullYear(),n.getMonth(),n.getDate()).toISOString(),o=new Date(e.getTime()-864e5).toISOString(),s=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ?").get(a).n,i=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE started_at >= ? AND started_at < ?").get(r,a).n,l=t.prepare("SELECT COUNT(*) AS n FROM task_history WHERE status='error' AND started_at >= ?").get(a).n,c=t.prepare("SELECT AVG(duration_ms) AS d FROM task_history WHERE status='ok' AND started_at >= ?").get(a).d??0,p=t.prepare("SELECT duration_ms FROM task_history WHERE status='ok' AND started_at >= ? AND duration_ms IS NOT NULL ORDER BY duration_ms ASC").all(a),u=_=>p.length?p[Math.min(p.length-1,Math.floor(p.length*_))].duration_ms:0,f=u(.5),h=u(.95),T=t.prepare("SELECT * FROM usage_daily WHERE day = date('now')").all().reduce((_,M)=>_+Nt(M),0),E=t.prepare("SELECT * FROM usage_daily WHERE day = date('now', '-1 day')").all().reduce((_,M)=>_+Nt(M),0),g=t.prepare(`
6019
6019
  SELECT agent_id,
6020
6020
  COUNT(*) AS tasks,
6021
6021
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors,
@@ -6033,12 +6033,12 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6033
6033
  WHERE started_at >= ?
6034
6034
  GROUP BY channel
6035
6035
  ORDER BY tasks DESC
6036
- `).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)),v=m.filter(_=>!g.has(_)),b=t.prepare(`
6036
+ `).all(a),m=t.prepare("SELECT DISTINCT agent_id FROM usage_daily WHERE day >= date('now', '-7 day')").all().map(_=>_.agent_id),x=new Set(t.prepare("SELECT DISTINCT agent_id FROM task_history WHERE started_at >= ?").all(o).map(_=>_.agent_id)),b=m.filter(_=>!x.has(_)),y=t.prepare(`
6037
6037
  SELECT started_at, agent_id, channel, message_preview, error
6038
6038
  FROM task_history
6039
6039
  WHERE status='error' AND started_at >= ?
6040
6040
  ORDER BY started_at DESC LIMIT 5
6041
- `).all(o).map(_=>({..._,plain:Hn(_.error)}));return{kpis:{tasksToday:s,tasksDelta:s-i,errorsToday:l,errorRate:s>0?l/s:0,avgDurationMs:Math.round(c),p50DurationMs:f,p95DurationMs:h,spendToday:T,spendDelta:T-S,idleAgentCount:v.length},perAgent:x,perChannel:d,idleAgents:v,recentErrors:b}}function Ni(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(`
6041
+ `).all(o).map(_=>({..._,plain:Xn(_.error)}));return{kpis:{tasksToday:s,tasksDelta:s-i,errorsToday:l,errorRate:s>0?l/s:0,avgDurationMs:Math.round(c),p50DurationMs:f,p95DurationMs:h,spendToday:T,spendDelta:T-E,idleAgentCount:b.length},perAgent:g,perChannel:d,idleAgents:b,recentErrors:y}}function ul(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(`
6042
6042
  SELECT strftime('%Y-%m-%dT%H:00', started_at) AS hour,
6043
6043
  COUNT(*) AS tasks,
6044
6044
  SUM(CASE WHEN status='error' THEN 1 ELSE 0 END) AS errors
@@ -6065,7 +6065,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6065
6065
  WHERE started_at >= @since
6066
6066
  GROUP BY agent_id
6067
6067
  ORDER BY tasks_24h DESC, tasks_7d DESC
6068
- `).all({since:n,last24:a});return{hourly:s,daily:i,perAgent:l}}function Rn(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 jn(t,e){let a=e>0?`WHERE day >= date('now', '-${e} day')`:"",n=t.prepare(`
6068
+ `).all({since:n,last24:a});return{hourly:s,daily:i,perAgent:l}}function zn(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 Fn(t,e){let a=e>0?`WHERE day >= date('now', '-${e} day')`:"",n=t.prepare(`
6069
6069
  SELECT day, agent_id, model,
6070
6070
  input_tokens, output_tokens, cache_read_tokens, cache_create_tokens,
6071
6071
  tier2_input_tokens, tier2_output_tokens, tier2_cache_read_tokens, tier2_cache_create_tokens,
@@ -6073,20 +6073,20 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6073
6073
  FROM usage_daily
6074
6074
  ${a}
6075
6075
  ORDER BY day
6076
- `).all(),r=new Date().toISOString().slice(0,10),o=new Date(Date.now()-864e5).toISOString().slice(0,10),s=new Date(Date.now()-7*864e5).toISOString().slice(0,10),i=new Date(Date.now()-14*864e5).toISOString().slice(0,10),l=0,c=0,p=0,u=0,f=0,h=0,y=0,T=0,S=0,x={},d={};for(let E of n){let I=Pt(E),R=On(E.model),j=Pn[R],B=(E.tier2_input_tokens||0)/1e6*j.input*.5+(E.tier2_output_tokens||0)/1e6*j.output*.5+(E.tier2_cache_read_tokens||0)/1e6*j.cacheRead*.5+(E.tier2_cache_create_tokens||0)/1e6*j.cacheCreate*.5,re=(E.input_tokens||0)+(E.tier2_input_tokens||0),z=(E.output_tokens||0)+(E.tier2_output_tokens||0),D=(E.cache_read_tokens||0)+(E.tier2_cache_read_tokens||0),H=(E.cache_create_tokens||0)+(E.tier2_cache_create_tokens||0);u+=I,E.day>=s&&(p+=I,y+=E.tasks||0),E.day>=i&&E.day<s&&(S+=I,T+=E.tasks||0),E.day===r&&(l+=I),E.day===o&&(c+=I),E.day===r&&(f+=B),E.day>=s&&(h+=B);let V=x[E.day]||(x[E.day]={date:E.day,tasks:0,input:0,output:0,cacheRead:0,cacheCreate:0,cost:0,tier2:0,agents:{}});V.tasks+=E.tasks||0,V.input+=re,V.output+=z,V.cacheRead+=D,V.cacheCreate+=H,V.cost+=I,V.tier2+=B;let F=V.agents[E.agent_id]||(V.agents[E.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:E.model});F.tasks+=E.tasks||0,F.cost+=I,F.tier2+=B,F.input+=re,F.output+=z,F.cacheRead+=D,F.cacheCreate+=H,E.model&&(F.model=E.model);let Y=d[E.agent_id]||(d[E.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:E.model});Y.tasks+=E.tasks||0,Y.cost+=I,Y.tier2+=B,Y.input+=re,Y.output+=z,Y.cacheRead+=D,Y.cacheCreate+=H,E.model&&(Y.model=E.model)}let m=Object.values(x).sort((E,I)=>E.date<I.date?-1:1),g=0,v=0,k=0,b=0,_=0,M=0;for(let E of m)g+=E.tasks,v+=E.input,k+=E.output,b+=E.cacheRead,_+=E.cacheCreate,M+=E.cost;let A=Object.entries(d).map(([E,I])=>({agent_id:E,...I,tokens:I.input+I.output+I.cacheRead+I.cacheCreate})).sort((E,I)=>I.cost-E.cost);return{range:e,generatedAt:new Date().toISOString(),kpis:{spendToday:l,spendYesterday:c,spend7d:p,spend30d:u,tier2Today:f,tier2_7d:h,tier2PctToday:l>0?f/l:0,spendRange:M,avgDailyRange:m.length?M/m.length:0,tasksRange:g,tokensRange:v+k+b+_,cacheHitRange:b+v>0?b/(b+v):0,costPerTaskRange:g>0?M/g:0,spendDeltaWoW:S>0?(p-S)/S:0,tasksDeltaWoW:T>0?(y-T)/T:0},days:m,perAgent:A}}function Di(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+`
6076
+ `).all(),r=new Date().toISOString().slice(0,10),o=new Date(Date.now()-864e5).toISOString().slice(0,10),s=new Date(Date.now()-7*864e5).toISOString().slice(0,10),i=new Date(Date.now()-14*864e5).toISOString().slice(0,10),l=0,c=0,p=0,u=0,f=0,h=0,v=0,T=0,E=0,g={},d={};for(let S of n){let I=Nt(S),R=Un(S.model),P=qn[R],B=(S.tier2_input_tokens||0)/1e6*P.input*.5+(S.tier2_output_tokens||0)/1e6*P.output*.5+(S.tier2_cache_read_tokens||0)/1e6*P.cacheRead*.5+(S.tier2_cache_create_tokens||0)/1e6*P.cacheCreate*.5,oe=(S.input_tokens||0)+(S.tier2_input_tokens||0),z=(S.output_tokens||0)+(S.tier2_output_tokens||0),D=(S.cache_read_tokens||0)+(S.tier2_cache_read_tokens||0),H=(S.cache_create_tokens||0)+(S.tier2_cache_create_tokens||0);u+=I,S.day>=s&&(p+=I,v+=S.tasks||0),S.day>=i&&S.day<s&&(E+=I,T+=S.tasks||0),S.day===r&&(l+=I),S.day===o&&(c+=I),S.day===r&&(f+=B),S.day>=s&&(h+=B);let Z=g[S.day]||(g[S.day]={date:S.day,tasks:0,input:0,output:0,cacheRead:0,cacheCreate:0,cost:0,tier2:0,agents:{}});Z.tasks+=S.tasks||0,Z.input+=oe,Z.output+=z,Z.cacheRead+=D,Z.cacheCreate+=H,Z.cost+=I,Z.tier2+=B;let F=Z.agents[S.agent_id]||(Z.agents[S.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:S.model});F.tasks+=S.tasks||0,F.cost+=I,F.tier2+=B,F.input+=oe,F.output+=z,F.cacheRead+=D,F.cacheCreate+=H,S.model&&(F.model=S.model);let ee=d[S.agent_id]||(d[S.agent_id]={tasks:0,cost:0,input:0,output:0,cacheRead:0,cacheCreate:0,tier2:0,model:S.model});ee.tasks+=S.tasks||0,ee.cost+=I,ee.tier2+=B,ee.input+=oe,ee.output+=z,ee.cacheRead+=D,ee.cacheCreate+=H,S.model&&(ee.model=S.model)}let m=Object.values(g).sort((S,I)=>S.date<I.date?-1:1),x=0,b=0,k=0,y=0,_=0,M=0;for(let S of m)x+=S.tasks,b+=S.input,k+=S.output,y+=S.cacheRead,_+=S.cacheCreate,M+=S.cost;let C=Object.entries(d).map(([S,I])=>({agent_id:S,...I,tokens:I.input+I.output+I.cacheRead+I.cacheCreate})).sort((S,I)=>I.cost-S.cost);return{range:e,generatedAt:new Date().toISOString(),kpis:{spendToday:l,spendYesterday:c,spend7d:p,spend30d:u,tier2Today:f,tier2_7d:h,tier2PctToday:l>0?f/l:0,spendRange:M,avgDailyRange:m.length?M/m.length:0,tasksRange:x,tokensRange:b+k+y+_,cacheHitRange:y+b>0?y/(y+b):0,costPerTaskRange:x>0?M/x:0,spendDeltaWoW:E>0?(p-E)/E:0,tasksDeltaWoW:T>0?(v-T)/T:0},days:m,perAgent:C}}function ml(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+`
6077
6077
  `+a.join(`
6078
6078
  `)+`
6079
- `}import{resolve as Hi}from"path";import{existsSync as Bi}from"fs";import zi from"better-sqlite3";function Fi(){let t=Hi(process.cwd(),".agentx/intent/ledger.sqlite");if(!Bi(t))return null;try{let e=new zi(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-Bn>6e4&&(Bn=a,console.error(`[ledger-panel] openReadOnly failed: ${e?.message??e}`)),null}}var Bn=0;function ye(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Ui(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 zn(t,e,a){if(!a.startsWith("/api/admin/ledger/"))return!1;let n=a.replace(/^\/api\/admin\/ledger\//,"").split("?")[0],r=Fi();if(!r)return ye(e,503,{error:"intent ledger not available",rows:[]}),!0;try{let o=new URL(t.url||"/","http://_"),s=Ui(o.searchParams.get("since")),i=o.searchParams.get("source")||"",l=o.searchParams.get("project")||"",c=parseInt(o.searchParams.get("limit")||"50",10),p=Number.isFinite(c)?Math.max(1,Math.min(500,c)):50;if(n==="stats"){let u=s!==void 0?"WHERE ts >= @since":"",f=s!==void 0?"WHERE decided_at >= @since":"",h=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_events ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),y=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_decisions ${f}`).get({since:s}).n,T=r.db.prepare(`SELECT outcome, COUNT(*) AS n FROM intent_decisions ${f} GROUP BY outcome ORDER BY n DESC`).all({since:s}),S=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_divergences ${u}`).get({since:s}).n,x=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_divergences ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),d=r.db.prepare(`
6079
+ `}import{resolve as fl}from"path";import{existsSync as hl}from"fs";import gl from"better-sqlite3";function xl(){let t=fl(process.cwd(),".agentx/intent/ledger.sqlite");if(!hl(t))return null;try{let e=new gl(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-Kn>6e4&&(Kn=a,console.error(`[ledger-panel] openReadOnly failed: ${e?.message??e}`)),null}}var Kn=0;function we(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function vl(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 Jn(t,e,a){if(!a.startsWith("/api/admin/ledger/"))return!1;let n=a.replace(/^\/api\/admin\/ledger\//,"").split("?")[0],r=xl();if(!r)return we(e,503,{error:"intent ledger not available",rows:[]}),!0;try{let o=new URL(t.url||"/","http://_"),s=vl(o.searchParams.get("since")),i=o.searchParams.get("source")||"",l=o.searchParams.get("project")||"",c=parseInt(o.searchParams.get("limit")||"50",10),p=Number.isFinite(c)?Math.max(1,Math.min(500,c)):50;if(n==="stats"){let u=s!==void 0?"WHERE ts >= @since":"",f=s!==void 0?"WHERE decided_at >= @since":"",h=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_events ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),v=r.db.prepare(`SELECT COUNT(*) AS n FROM intent_decisions ${f}`).get({since:s}).n,T=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,g=r.db.prepare(`SELECT source, COUNT(*) AS n FROM intent_divergences ${u} GROUP BY source ORDER BY n DESC`).all({since:s}),d=r.db.prepare(`
6080
6080
  SELECT COUNT(*) AS n FROM intent_decisions d
6081
6081
  LEFT JOIN intent_resolutions r
6082
6082
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
6083
6083
  WHERE d.outcome = 'dispatched' AND r.decision_event_id IS NULL
6084
- `).get().n;return ye(e,200,{since:s??null,eventsBySource:h,totalDecisions:y,decisionsByOutcome:T,totalDivergences:S,divergencesBySource:x,inFlight:d}),!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 h=`
6084
+ `).get().n;return we(e,200,{since:s??null,eventsBySource:h,totalDecisions:v,decisionsByOutcome:T,totalDivergences:E,divergencesBySource:g,inFlight:d}),!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 h=`
6085
6085
  SELECT id, ts, source, source_event_id, project, subject, intent
6086
6086
  FROM intent_events
6087
6087
  ${u.length?"WHERE "+u.join(" AND "):""}
6088
6088
  ORDER BY ts DESC LIMIT @limit
6089
- `;return ye(e,200,{rows:r.db.prepare(h).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 h=`
6089
+ `;return we(e,200,{rows:r.db.prepare(h).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 h=`
6090
6090
  SELECT ts, source, decided_by,
6091
6091
  legacy_agent_id, legacy_outcome, legacy_reason,
6092
6092
  ledger_agent_id, ledger_outcome, ledger_reason,
@@ -6094,7 +6094,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6094
6094
  FROM intent_divergences
6095
6095
  ${u.length?"WHERE "+u.join(" AND "):""}
6096
6096
  ORDER BY ts DESC LIMIT @limit
6097
- `;return ye(e,200,{rows:r.db.prepare(h).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 h=`
6097
+ `;return we(e,200,{rows:r.db.prepare(h).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 h=`
6098
6098
  SELECT e.id AS event_id, e.ts, e.source, e.project, e.subject, e.intent,
6099
6099
  d.decided_by, d.decided_at, d.agent_id, d.reason
6100
6100
  FROM intent_decisions d
@@ -6103,7 +6103,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6103
6103
  ON r.decision_event_id = d.event_id AND r.decision_decided_by = d.decided_by
6104
6104
  WHERE ${u.join(" AND ")}
6105
6105
  ORDER BY d.decided_at DESC LIMIT @limit
6106
- `;return ye(e,200,{rows:r.db.prepare(h).all(f)}),!0}return ye(e,404,{error:"unknown ledger slice",rows:[]}),!0}catch(o){return ye(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function Fn(t={}){return $({title:"AgentX \xB7 Ledger",activeTab:"graph",subtitle:"Ledger",body:`<div class="ax-led">
6106
+ `;return we(e,200,{rows:r.db.prepare(h).all(f)}),!0}return we(e,404,{error:"unknown ledger slice",rows:[]}),!0}catch(o){return we(e,500,{error:o?.message??String(o),rows:[]}),!0}finally{r.close()}}function Vn(t={}){return L({title:"AgentX \xB7 Ledger",activeTab:"graph",subtitle:"Ledger",body:`<div class="ax-led">
6107
6107
  <header class="ax-led__head">
6108
6108
  <h1>Intent ledger</h1>
6109
6109
  <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>
@@ -6308,7 +6308,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6308
6308
  }
6309
6309
  load();
6310
6310
  })();
6311
- </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function Un(t={}){return $({title:"AgentX \xB7 Cost",activeTab:"cost",subtitle:"Cost",body:`<div class="ax-cost">
6311
+ </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function Yn(t={}){return L({title:"AgentX \xB7 Cost",activeTab:"cost",subtitle:"Cost",body:`<div class="ax-cost">
6312
6312
  <header class="ax-cost__head">
6313
6313
  <div>
6314
6314
  <h1>Cost</h1>
@@ -6881,7 +6881,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6881
6881
  load();
6882
6882
  setInterval(load, 30000);
6883
6883
  })();
6884
- </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function qn(t={}){let e=`<div class="ax-pj__root">
6884
+ </script>`,peers:t.peers,currentPeerId:t.currentPeerId})}function Qn(t={}){let e=`<div class="ax-pj__root">
6885
6885
  <aside class="ax-pj__list">
6886
6886
  <header>
6887
6887
  <h2>Projects</h2>
@@ -6908,7 +6908,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
6908
6908
  </header>
6909
6909
  <div id="pj-detail-body" class="ax-pj__detail-body"></div>
6910
6910
  </section>
6911
- </div>`;return $({title:"AgentX \xB7 Projects",activeTab:"projects",subtitle:"Projects",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:qi,scripts:`<script>${Wi}</script>`})}var qi=`
6911
+ </div>`;return L({title:"AgentX \xB7 Projects",activeTab:"projects",subtitle:"Projects",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:bl,scripts:`<script>${yl}</script>`})}var bl=`
6912
6912
  .ax-pj__root {
6913
6913
  display: grid;
6914
6914
  grid-template-columns: 360px 1fr;
@@ -7095,7 +7095,7 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7095
7095
  }
7096
7096
  .ax-pj__warn { color: var(--ax-warn, #facc15); border-top: 1px solid var(--ax-border); }
7097
7097
  .ax-pj__hint { font-size: 11px; color: var(--ax-fg-muted, var(--ax-text)); margin-top: 4px; }
7098
- `,Wi=`
7098
+ `,yl=`
7099
7099
  (function(){
7100
7100
  const $ = (sel) => document.querySelector(sel);
7101
7101
  const esc = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({"&":"&amp;","<":"&lt;",">":"&gt;","\\"":"&quot;"}[c]));
@@ -7745,22 +7745,22 @@ setInterval(function(){ if (document.visibilityState === 'visible' && !document.
7745
7745
  load();
7746
7746
  });
7747
7747
  })();
7748
- `;import{resolve as Dt,join as ol}from"path";import{existsSync as Ht,readdirSync as sl,readFileSync as il}from"fs";import ll from"better-sqlite3";var Gn=String.raw`[\w.-]+(?:/[\w.-]+)+`,Gi=new RegExp(`^(?:chat:)?(${Gn}):(?:issue|issues|merge_request|mr|pull|pr)s?:\\d+`),Xi=new RegExp(`^\\[(?:GitLab|GitHub) (${Gn}) `);function Wn(t){if(!t)return null;let e=t.match(Gi);return e?e[1]:null}function Ot(t){if(!t)return null;let e=t.trimStart().match(Xi);return e?e[1]:null}function st(t,e,a){let n=t&&typeof t=="object"?t.context:null;return n&&typeof n.project=="string"&&n.project.trim()?n.project.trim():Wn(typeof n?.chatId=="string"?n.chatId:null)??Wn(e)??Ot(a)}function Ki(t){let[e,...a]=t.split("/");return!a.length||e==="unmapped"||a[0].startsWith("_")?null:t}function it(t,e){return`${t}${e.kind==="mr"?"!":"#"}${e.n}`}var Ji=/\b(issue|merge_request|pull|MR|Issue)s?[:\s]+[#!]?(\d+)/,Vi=/^\[(?:GitLab|GitHub) \S+ (issue|merge_request|pull|MR|Issue)s? [#!]?(\d+)/i,Yi=t=>/^issue/i.test(t)?"issue":"mr";function Qi(t){let e=t.subject.match(Ji)??t.inputPreview.trimStart().match(Vi);return e?{kind:Yi(e[1]),n:Number(e[2])}:null}function Zi(t,e=8){let a=[],n=new Set;for(let r of t.matchAll(/(?:^|[\s(,])!(\d{1,6})\b/g)){let o=Number(r[1]);if(!n.has(o)&&(n.add(o),a.push({kind:"mr",n:o}),a.length>=e))break}return a}function Xn(t){if(!Ki(t.projectId))return[];let e=Qi(t);return e?[e]:Zi(t.inputPreview)}var el=6e4,tl=5*6e4,al=40,Kn=6,Jn=new Map;function Vn(t){let e=new Map,a=[...t].sort((n,r)=>r.startedAt-n.startedAt);for(let n of a){let r=n.channelId==="github"||/\bpull:\d+/.test(n.subject);for(let o of Xn(n)){let s=it(n.projectId,o);if(e.has(s)||e.set(s,{project:n.projectId,ref:o,github:r}),e.size>=al)return[...e.values()]}}return[...e.values()]}async function Yn(t,e,a=fetch,n=Date.now()){let r={},o=[];for(let s of t){let i=it(s.project,s.ref),l=Jn.get(i);l&&n-l.at<(s.github?tl:el)?l.item&&(r[i]=l.item):o.push(s)}for(let s=0;s<o.length;s+=Kn)await Promise.all(o.slice(s,s+Kn).map(async i=>{let l=it(i.project,i.ref),c=null;try{c=i.github?await rl(i,e,a):await nl(i,e,a)}catch{}Jn.set(l,{at:n,item:c}),c&&(r[l]=c)}));return r}async function Qn(t,e,a){let n=new AbortController,r=setTimeout(()=>n.abort(),5e3);try{let o=await a(t,{headers:e,signal:n.signal});return o.ok?await o.json():null}finally{clearTimeout(r)}}async function nl(t,e,a){let n=e.gitlab;if(!n?.host||!n.token)return null;let r=`${n.host.replace(/\/+$/,"")}/api/v4/projects/${encodeURIComponent(t.project)}`,o=t.ref.kind==="mr"?`merge_requests/${t.ref.n}`:`issues/${t.ref.n}`,s=await Qn(`${r}/${o}`,{"PRIVATE-TOKEN":n.token},a);if(!s)return null;let i=s.head_pipeline??s.pipeline;return{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(s.title??""),state:String(s.state??"opened"),draft:!!(s.draft??s.work_in_progress),url:String(s.web_url??""),pipeline:i&&typeof i.status=="string"?{status:i.status,url:String(i.web_url??"")}:null,mergedAt:s.merged_at?Date.parse(s.merged_at):null}}async function rl(t,e,a){let n=t.ref.kind==="mr"?`pulls/${t.ref.n}`:`issues/${t.ref.n}`,r={Accept:"application/vnd.github+json","User-Agent":"agentx-dashboard"};e.githubToken&&(r.Authorization=`Bearer ${e.githubToken}`);let o=await Qn(`https://api.github.com/repos/${t.project}/${n}`,r,a);return o?{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(o.title??""),state:o.merged_at?"merged":o.state==="open"?"opened":String(o.state??"opened"),draft:!!o.draft,url:String(o.html_url??""),pipeline:null,mergedAt:o.merged_at?Date.parse(o.merged_at):null}:null}function Bt(){let t=Dt(process.cwd(),".agentx/intent/ledger.sqlite");if(!Ht(t))return null;try{let e=new ll(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-Zn>6e4&&(Zn=a,console.error(`[activity-graph] openLedger failed: ${e?.message??e}`)),null}}var Zn=0;function ue(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}var Me={gitlab:{label:"GitLab",color:"#fc6d26"},github:{label:"GitHub",color:"#6e7681"},telegram:{label:"Telegram",color:"#0088cc"},whatsapp:{label:"WhatsApp",color:"#25d366"},slack:{label:"Slack",color:"#4a154b"},discord:{label:"Discord",color:"#5865f2"},mesh:{label:"Mesh (a2a)",color:"#bf8700"},a2a:{label:"Agent \u2192 Agent",color:"#bf8700"},cron:{label:"Cron",color:"#6b7280"},workflow:{label:"Workflow",color:"#9333ea"},api:{label:"Web API",color:"#3a7bd5"},mcp:{label:"Agent tools (MCP)",color:"#bf8700"},voice:{label:"Voice",color:"#e5534b"},desktop:{label:"Desktop assistant",color:"#8957e5"},opencode:{label:"OpenCode",color:"#57606a"}};function cl(t,e,a){if(t==="mesh"){let n=a?.context?.channel;if(typeof n=="string"&&n in Me)return n;if(e.startsWith("mesh.")){let r=e.slice(5);if(r==="a2a")return"a2a";if(r in Me)return r}return"mesh"}if(t==="workflow"){let n=a?.event?.payload,r=typeof n?.channel=="string"?n.channel:"";if(r&&r in Me)return r;let o=n?.issueEvent||n?.webhookEvent;if(o){if(o.user?.username||o.project?.path_with_namespace)return"gitlab";if(o.sender?.login)return"github"}if(e.startsWith("workflow.")){let s=e.slice(9).split("-")[0];if(s in Me)return s}return"workflow"}return t}function ar(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 dl(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 nr(t,e,a){return va(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 pl(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:q(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&&!Nt(l))return{id:l,name:l,avatar:q(l),kind:"a2a"}}let i=o||r||s;if(i&&!Nt(r||o||"")){let l=r||o||s,c=e==="mesh.github"?"github":e==="mesh.gitlab"?"gitlab":e==="mesh.a2a"?"a2a":e==="mesh.voice"?"voice":e==="mesh.desktop"?"desktop":"mesh";return{id:l,name:o||r||l,avatar:q(i),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,i=typeof s.username=="string"?s.username:null,l=typeof s.name=="string"?s.name:null,c=i||(s.id!=null?String(s.id):null)||l;if(c&&!Nt(i||l||"")){let p=typeof n.channel=="string"?n.channel:"",u=er(p);return{id:c,name:l||i||c,avatar:q(l||i||c),kind:u}}}let o=n.issueEvent||n.webhookEvent;if(o&&typeof o=="object"){let s=o.user;if(s&&typeof s=="object"&&(s.username||s.name)){let l=s.username||s.name,c=s.name||s.username;return{id:l,name:c,avatar:q(c),kind:"gitlab"}}let i=o.sender;if(i?.login)return{id:i.login,name:i.login,avatar:q(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:q(i),kind:er(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:q(o),kind:"gitlab"}}}if(t==="github"){let n=a.sender||a.payload?.sender;if(n?.login)return{id:n.login,name:n.login,avatar:q(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:q(r),kind:"telegram"}}if(n?.id)return{id:String(n.id),name:n.first_name||`tg:${n.id}`,avatar:q(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:q(o),kind:"whatsapp"}}}return null}function er(t){return t==="telegram"||t==="whatsapp"||t==="slack"||t==="discord"?t:"system"}function Nt(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 q(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 rr(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}
7748
+ `;import{resolve as Bt,join as Pl}from"path";import{existsSync as zt,readdirSync as jl,readFileSync as Ol}from"fs";import Nl from"better-sqlite3";var er=String.raw`[\w.-]+(?:/[\w.-]+)+`,wl=new RegExp(`^(?:chat:)?(${er}):(?:issue|issues|merge_request|mr|pull|pr)s?:\\d+`),kl=new RegExp(`^\\[(?:GitLab|GitHub) (${er}) `);function Zn(t){if(!t)return null;let e=t.match(wl);return e?e[1]:null}function Dt(t){if(!t)return null;let e=t.trimStart().match(kl);return e?e[1]:null}function it(t,e,a){let n=t&&typeof t=="object"?t.context:null;return n&&typeof n.project=="string"&&n.project.trim()?n.project.trim():Zn(typeof n?.chatId=="string"?n.chatId:null)??Zn(e)??Dt(a)}function _l(t){let[e,...a]=t.split("/");return!a.length||e==="unmapped"||a[0].startsWith("_")?null:t}function lt(t,e){return`${t}${e.kind==="mr"?"!":"#"}${e.n}`}var El=/\b(issue|merge_request|pull|MR|Issue)s?[:\s]+[#!]?(\d+)/,Sl=/^\[(?:GitLab|GitHub) \S+ (issue|merge_request|pull|MR|Issue)s? [#!]?(\d+)/i,Tl=t=>/^issue/i.test(t)?"issue":"mr";function Al(t){let e=t.subject.match(El)??t.inputPreview.trimStart().match(Sl);return e?{kind:Tl(e[1]),n:Number(e[2])}:null}function Cl(t,e=8){let a=[],n=new Set;for(let r of t.matchAll(/(?:^|[\s(,])!(\d{1,6})\b/g)){let o=Number(r[1]);if(!n.has(o)&&(n.add(o),a.push({kind:"mr",n:o}),a.length>=e))break}return a}function tr(t){if(!_l(t.projectId))return[];let e=Al(t);return e?[e]:Cl(t.inputPreview)}var Ml=6e4,Il=5*6e4,Ll=40,ar=6,nr=new Map;function rr(t){let e=new Map,a=[...t].sort((n,r)=>r.startedAt-n.startedAt);for(let n of a){let r=n.channelId==="github"||/\bpull:\d+/.test(n.subject);for(let o of tr(n)){let s=lt(n.projectId,o);if(e.has(s)||e.set(s,{project:n.projectId,ref:o,github:r}),e.size>=Ll)return[...e.values()]}}return[...e.values()]}async function or(t,e,a=fetch,n=Date.now()){let r={},o=[];for(let s of t){let i=lt(s.project,s.ref),l=nr.get(i);l&&n-l.at<(s.github?Il:Ml)?l.item&&(r[i]=l.item):o.push(s)}for(let s=0;s<o.length;s+=ar)await Promise.all(o.slice(s,s+ar).map(async i=>{let l=lt(i.project,i.ref),c=null;try{c=i.github?await Rl(i,e,a):await $l(i,e,a)}catch{}nr.set(l,{at:n,item:c}),c&&(r[l]=c)}));return r}async function sr(t,e,a){let n=new AbortController,r=setTimeout(()=>n.abort(),5e3);try{let o=await a(t,{headers:e,signal:n.signal});return o.ok?await o.json():null}finally{clearTimeout(r)}}async function $l(t,e,a){let n=e.gitlab;if(!n?.host||!n.token)return null;let r=`${n.host.replace(/\/+$/,"")}/api/v4/projects/${encodeURIComponent(t.project)}`,o=t.ref.kind==="mr"?`merge_requests/${t.ref.n}`:`issues/${t.ref.n}`,s=await sr(`${r}/${o}`,{"PRIVATE-TOKEN":n.token},a);if(!s)return null;let i=s.head_pipeline??s.pipeline;return{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(s.title??""),state:String(s.state??"opened"),draft:!!(s.draft??s.work_in_progress),url:String(s.web_url??""),pipeline:i&&typeof i.status=="string"?{status:i.status,url:String(i.web_url??"")}:null,mergedAt:s.merged_at?Date.parse(s.merged_at):null}}async function Rl(t,e,a){let n=t.ref.kind==="mr"?`pulls/${t.ref.n}`:`issues/${t.ref.n}`,r={Accept:"application/vnd.github+json","User-Agent":"agentx-dashboard"};e.githubToken&&(r.Authorization=`Bearer ${e.githubToken}`);let o=await sr(`https://api.github.com/repos/${t.project}/${n}`,r,a);return o?{kind:t.ref.kind,project:t.project,n:t.ref.n,title:String(o.title??""),state:o.merged_at?"merged":o.state==="open"?"opened":String(o.state??"opened"),draft:!!o.draft,url:String(o.html_url??""),pipeline:null,mergedAt:o.merged_at?Date.parse(o.merged_at):null}:null}function Ft(){let t=Bt(process.cwd(),".agentx/intent/ledger.sqlite");if(!zt(t))return null;try{let e=new Nl(t,{readonly:!0,fileMustExist:!0});return{db:e,close:()=>e.close()}}catch(e){let a=Date.now();return a-ir>6e4&&(ir=a,console.error(`[activity-graph] openLedger failed: ${e?.message??e}`)),null}}var ir=0;function me(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}var $e={gitlab:{label:"GitLab",color:"#fc6d26"},github:{label:"GitHub",color:"#6e7681"},telegram:{label:"Telegram",color:"#0088cc"},whatsapp:{label:"WhatsApp",color:"#25d366"},slack:{label:"Slack",color:"#4a154b"},discord:{label:"Discord",color:"#5865f2"},mesh:{label:"Mesh (a2a)",color:"#bf8700"},a2a:{label:"Agent \u2192 Agent",color:"#bf8700"},cron:{label:"Cron",color:"#6b7280"},workflow:{label:"Workflow",color:"#9333ea"},api:{label:"Web API",color:"#3a7bd5"},mcp:{label:"Agent tools (MCP)",color:"#bf8700"},voice:{label:"Voice",color:"#e5534b"},desktop:{label:"Desktop assistant",color:"#8957e5"},opencode:{label:"OpenCode",color:"#57606a"}};function Dl(t,e,a){if(t==="mesh"){let n=a?.context?.channel;if(typeof n=="string"&&n in $e)return n;if(e.startsWith("mesh.")){let r=e.slice(5);if(r==="a2a")return"a2a";if(r in $e)return r}return"mesh"}if(t==="workflow"){let n=a?.event?.payload,r=typeof n?.channel=="string"?n.channel:"";if(r&&r in $e)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 $e)return s}return"workflow"}return t}function dr(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 Hl(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 pr(t,e,a){return Sa(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 Bl(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:W(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&&!Ht(l))return{id:l,name:l,avatar:W(l),kind:"a2a"}}let i=o||r||s;if(i&&!Ht(r||o||"")){let l=r||o||s,c=e==="mesh.github"?"github":e==="mesh.gitlab"?"gitlab":e==="mesh.a2a"?"a2a":e==="mesh.voice"?"voice":e==="mesh.desktop"?"desktop":"mesh";return{id:l,name:o||r||l,avatar:W(i),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,i=typeof s.username=="string"?s.username:null,l=typeof s.name=="string"?s.name:null,c=i||(s.id!=null?String(s.id):null)||l;if(c&&!Ht(i||l||"")){let p=typeof n.channel=="string"?n.channel:"",u=lr(p);return{id:c,name:l||i||c,avatar:W(l||i||c),kind:u}}}let o=n.issueEvent||n.webhookEvent;if(o&&typeof o=="object"){let s=o.user;if(s&&typeof s=="object"&&(s.username||s.name)){let l=s.username||s.name,c=s.name||s.username;return{id:l,name:c,avatar:W(c),kind:"gitlab"}}let i=o.sender;if(i?.login)return{id:i.login,name:i.login,avatar:W(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:W(i),kind:lr(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:W(o),kind:"gitlab"}}}if(t==="github"){let n=a.sender||a.payload?.sender;if(n?.login)return{id:n.login,name:n.login,avatar:W(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:W(r),kind:"telegram"}}if(n?.id)return{id:String(n.id),name:n.first_name||`tg:${n.id}`,avatar:W(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:W(o),kind:"whatsapp"}}}return null}function lr(t){return t==="telegram"||t==="whatsapp"||t==="slack"||t==="discord"?t:"system"}function Ht(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 W(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 ur(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}
7749
7749
  ${r}`:n)}e.comment?.body&&a.push(e.comment.body),e.issue?.title&&a.push(e.issue.title+(e.issue.body?`
7750
- ${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 ul(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 or(t,e,a){let n=Date.now(),r=n-a*3600*1e3,o=t.prepare(`
7750
+ ${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 zl(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 mr(t,e,a){let n=Date.now(),r=n-a*3600*1e3,o=t.prepare(`
7751
7751
  SELECT id, ts, source, project, subject, intent, raw_json
7752
7752
  FROM intent_events WHERE ts >= ? ORDER BY ts ASC
7753
- `).all(r),s=new Map,i=new Map;if(o.length>0){let b=o.map(I=>I.id),_=b.map((I,R)=>`@id${R}`).join(","),M=Object.fromEntries(b.map((I,R)=>[`id${R}`,I])),A=t.prepare(`
7753
+ `).all(r),s=new Map,i=new Map;if(o.length>0){let y=o.map(I=>I.id),_=y.map((I,R)=>`@id${R}`).join(","),M=Object.fromEntries(y.map((I,R)=>[`id${R}`,I])),C=t.prepare(`
7754
7754
  SELECT event_id, decided_at, decided_by, agent_id, outcome, reason
7755
7755
  FROM intent_decisions WHERE event_id IN (${_}) ORDER BY decided_at ASC
7756
- `).all(M);for(let I of A)s.has(I.event_id)||s.set(I.event_id,[]),s.get(I.event_id).push(I);let E=t.prepare(`
7756
+ `).all(M);for(let I of C)s.has(I.event_id)||s.set(I.event_id,[]),s.get(I.event_id).push(I);let S=t.prepare(`
7757
7757
  SELECT decision_event_id, decision_decided_by, resolved_at, status, duration_ms, result_summary
7758
7758
  FROM intent_resolutions WHERE decision_event_id IN (${_})
7759
- `).all(M);for(let I of E)i.set(`${I.decision_event_id}|${I.decision_decided_by}`,I)}let l=new Map,c=new Map,p=new Map,u=new Map,f=[],h=e?.business?.projects??[],y=e?.business?.contactMap??[],T=_t(e?.business??{});for(let b of o){let _=null;try{_=JSON.parse(b.raw_json)}catch{}let M=nr(b.source,_,y),A=rr(b.source,_),E=b.project??st(_,b.subject,A),I=null,R=null;M?(I=M.client,R=M.project||`${M.client}/_chat`):E&&(I=We(E,h),R=E);let j=cl(b.source,b.intent||"",_),B=Me[j]||{label:j,color:"#6b7280"};p.has(j)||p.set(j,{id:j,label:B.label,color:B.color});let re="__system",z,D=pl(b.source,b.intent||"",_);if(D){re=D.id,z=D.kind;let H=M?.displayName||D.name;(!u.has(D.id)||M?.displayName)&&u.set(D.id,{id:D.id,name:H,avatar:q(H),kind:D.kind})}else u.has("__system")||u.set("__system",{id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});for(let H of s.get(b.id)??[]){if(H.outcome!=="dispatched"||!H.agent_id)continue;let V=`${b.id}|${H.decided_by}`,F=i.get(V),Y=H.decided_at,oa=F?.resolved_at??null,vt=oa===null,Bo=F?.duration_ms??(vt?n-Y:0),zo=vt?"active":F?.status==="error"||F?.status==="fail"?"error":"completed",X,Re;if(I)X=I,Re=R;else{let bt=T.get(H.agent_id);bt?(X=bt,Re=`${bt}/_${b.source}`):(X="unmapped",Re=`unmapped/_${b.source}`)}l.has(X)||l.set(X,{id:X,name:X,color:ar(X),projects:[]}),c.has(X)||c.set(X,new Set),c.get(X).add(Re),f.push({id:`${b.id}|${H.decided_by}`,agentId:H.agent_id,clientId:X,projectId:Re,channelId:j,initiatorId:re,initiatorKind:z,subject:ul(b.subject),intent:b.intent||"",startedAt:Y,resolvedAt:oa,duration:Bo,active:vt,outcome:zo,tokens:0,inputPreview:A,system:dl(H.agent_id,e)})}}let S=[...l.values()].map(b=>({...b,projects:[...c.get(b.id)||[]].sort()})).sort((b,_)=>b.id.localeCompare(_.id)),x=[],d=new Set;if(e){let b=e.business??{},_=M=>{let A=b.orgChart?.[M]?.role,E=A?b.roles?.[A]?.title:void 0;return typeof E=="string"&&E.trim()?E.trim():void 0};for(let[M,A]of Object.entries(e.agents||{})){let E={id:M,name:A.name||M,tier:A.tier==="claude-code"?"lead":"worker",model:A.model||"",role:A.systemPrompt?A.systemPrompt.split(/[.\n]/)[0].slice(0,60):A.tier||"",title:_(M)};x.push(E),d.add(M)}}for(let b of f)d.has(b.agentId)||(x.push({id:b.agentId,name:b.agentId,tier:"worker",model:"",role:""}),d.add(b.agentId));x.sort((b,_)=>b.id.localeCompare(_.id));let m=[],g=new Set;for(let[b,_]of Object.entries(Me))m.push({id:b,label:_.label,color:_.color}),g.add(b);for(let b of p.values())g.has(b.id)||m.push(b);let v=[...u.values()];v.find(b=>b.id==="__system")||v.push({id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});let k=e?.channels?.gitlab?.host;return{now:n,windowH:a,clients:S,agents:x,channels:m,initiators:v,dispatches:f,forges:{gitlab:typeof k=="string"?k:void 0,github:"https://github.com"}}}function zt(t){let e=Bt();if(!e)return null;try{return or(e.db,ge,t)}finally{e.close()}}function sr(t){let e=new Map,a=new Map,n=new Map,r=new Map,o=[],s=0,i=0,l={};for(let{nodeId:c,snap:p}of t){l.gitlab??=p.forges?.gitlab,l.github??=p.forges?.github,p.now>s&&(s=p.now),p.windowH>i&&(i=p.windowH);for(let u of p.clients){let f=e.get(u.id);if(!f)e.set(u.id,{...u,projects:[...u.projects]});else{let h=Array.from(new Set([...f.projects,...u.projects])).sort();e.set(u.id,{...f,projects:h})}}for(let u of p.agents)a.has(u.id)||a.set(u.id,u);for(let u of p.channels)n.has(u.id)||n.set(u.id,u);for(let u of p.initiators)r.has(u.id)||r.set(u.id,u);for(let u of p.dispatches){let f=ml(u);if(f.clientId!==u.clientId&&!e.has(f.clientId)&&e.set(f.clientId,{id:f.clientId,name:f.clientId,color:ar(f.clientId),projects:[]}),f.projectId!==u.projectId){let h=e.get(f.clientId);h.projects.includes(f.projectId)||e.set(f.clientId,{...h,projects:[...h.projects,f.projectId].sort()})}o.push({...f,nodeId:c,id:`${c}::${f.id}`})}}return{now:s||Date.now(),windowH:i||6,localNodeId:t[0]?.nodeId,forges:l,clients:[...e.values()].sort((c,p)=>c.id.localeCompare(p.id)),agents:[...a.values()].sort((c,p)=>c.id.localeCompare(p.id)),channels:[...n.values()],initiators:[...r.values()],dispatches:o.sort((c,p)=>p.startedAt-c.startedAt)}}function ml(t){if(t.clientId!=="unmapped")return t;let e=Ot(t.inputPreview);if(!e)return t;let a=ge?.business?.projects??[];return{...t,projectId:e,clientId:We(e,a)}}async function lt(t){let e=ge?.channels?.gitlab,a=await Yn(Vn(t.dispatches),{gitlab:e?.host&&e?.token?{host:e.host,token:e.token}:void 0,githubToken:process.env.GITHUB_TOKEN||void 0});return{...t,forge:a}}var ge=null;function ir(t){ge=t}async function lr(t,e,a){if(a!=="/api/admin/activity-graph"&&!a.startsWith("/api/admin/activity-graph?"))return!1;let n=Bt();if(!n)return ue(e,503,{error:"intent ledger not available",clients:[],agents:[],channels:[],initiators:[],dispatches:[]}),!0;try{let r=new URL(t.url||"/","http://_"),o=cr(parseInt(r.searchParams.get("hours")||"6",10));ue(e,200,await lt(or(n.db,ge,o)))}catch(r){ue(e,500,{error:r?.message??String(r)})}finally{n.close()}return!0}var fl=5e3;async function Ft(t,e,a,n=zt){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
7759
+ `).all(M);for(let I of S)i.set(`${I.decision_event_id}|${I.decision_decided_by}`,I)}let l=new Map,c=new Map,p=new Map,u=new Map,f=[],h=e?.business?.projects??[],v=e?.business?.contactMap??[],T=St(e?.business??{});for(let y of o){let _=null;try{_=JSON.parse(y.raw_json)}catch{}let M=pr(y.source,_,v),C=ur(y.source,_),S=y.project??it(_,y.subject,C),I=null,R=null;M?(I=M.client,R=M.project||`${M.client}/_chat`):S&&(I=Ge(S,h),R=S);let P=Dl(y.source,y.intent||"",_),B=$e[P]||{label:P,color:"#6b7280"};p.has(P)||p.set(P,{id:P,label:B.label,color:B.color});let oe="__system",z,D=Bl(y.source,y.intent||"",_);if(D){oe=D.id,z=D.kind;let H=M?.displayName||D.name;(!u.has(D.id)||M?.displayName)&&u.set(D.id,{id:D.id,name:H,avatar:W(H),kind:D.kind})}else u.has("__system")||u.set("__system",{id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});for(let H of s.get(y.id)??[]){if(H.outcome!=="dispatched"||!H.agent_id)continue;let Z=`${y.id}|${H.decided_by}`,F=i.get(Z),ee=H.decided_at,pa=F?.resolved_at??null,yt=pa===null,hs=F?.duration_ms??(yt?n-ee:0),gs=yt?"active":F?.status==="error"||F?.status==="fail"?"error":"completed",J,je;if(I)J=I,je=R;else{let wt=T.get(H.agent_id);wt?(J=wt,je=`${wt}/_${y.source}`):(J="unmapped",je=`unmapped/_${y.source}`)}l.has(J)||l.set(J,{id:J,name:J,color:dr(J),projects:[]}),c.has(J)||c.set(J,new Set),c.get(J).add(je),f.push({id:`${y.id}|${H.decided_by}`,agentId:H.agent_id,clientId:J,projectId:je,channelId:P,initiatorId:oe,initiatorKind:z,subject:zl(y.subject),intent:y.intent||"",startedAt:ee,resolvedAt:pa,duration:hs,active:yt,outcome:gs,tokens:0,inputPreview:C,system:Hl(H.agent_id,e)})}}let E=[...l.values()].map(y=>({...y,projects:[...c.get(y.id)||[]].sort()})).sort((y,_)=>y.id.localeCompare(_.id)),g=[],d=new Set;if(e){let y=e.business??{},_=M=>{let C=y.orgChart?.[M]?.role,S=C?y.roles?.[C]?.title:void 0;return typeof S=="string"&&S.trim()?S.trim():void 0};for(let[M,C]of Object.entries(e.agents||{})){let S={id:M,name:C.name||M,tier:C.tier==="claude-code"?"lead":"worker",model:C.model||"",role:C.systemPrompt?C.systemPrompt.split(/[.\n]/)[0].slice(0,60):C.tier||"",title:_(M)};g.push(S),d.add(M)}}for(let y of f)d.has(y.agentId)||(g.push({id:y.agentId,name:y.agentId,tier:"worker",model:"",role:""}),d.add(y.agentId));g.sort((y,_)=>y.id.localeCompare(_.id));let m=[],x=new Set;for(let[y,_]of Object.entries($e))m.push({id:y,label:_.label,color:_.color}),x.add(y);for(let y of p.values())x.has(y.id)||m.push(y);let b=[...u.values()];b.find(y=>y.id==="__system")||b.push({id:"__system",name:"Schedule",avatar:"\u23F1",kind:"system"});let k=e?.channels?.gitlab?.host;return{now:n,windowH:a,clients:E,agents:g,channels:m,initiators:b,dispatches:f,forges:{gitlab:typeof k=="string"?k:void 0,github:"https://github.com"}}}function qt(t){let e=Ft();if(!e)return null;try{return mr(e.db,xe,t)}finally{e.close()}}function fr(t){let e=new Map,a=new Map,n=new Map,r=new Map,o=[],s=0,i=0,l={};for(let{nodeId:c,snap:p}of t){l.gitlab??=p.forges?.gitlab,l.github??=p.forges?.github,p.now>s&&(s=p.now),p.windowH>i&&(i=p.windowH);for(let u of p.clients){let f=e.get(u.id);if(!f)e.set(u.id,{...u,projects:[...u.projects]});else{let h=Array.from(new Set([...f.projects,...u.projects])).sort();e.set(u.id,{...f,projects:h})}}for(let u of p.agents)a.has(u.id)||a.set(u.id,u);for(let u of p.channels)n.has(u.id)||n.set(u.id,u);for(let u of p.initiators)r.has(u.id)||r.set(u.id,u);for(let u of p.dispatches){let f=Fl(u);if(f.clientId!==u.clientId&&!e.has(f.clientId)&&e.set(f.clientId,{id:f.clientId,name:f.clientId,color:dr(f.clientId),projects:[]}),f.projectId!==u.projectId){let h=e.get(f.clientId);h.projects.includes(f.projectId)||e.set(f.clientId,{...h,projects:[...h.projects,f.projectId].sort()})}o.push({...f,nodeId:c,id:`${c}::${f.id}`})}}return{now:s||Date.now(),windowH:i||6,localNodeId:t[0]?.nodeId,forges:l,clients:[...e.values()].sort((c,p)=>c.id.localeCompare(p.id)),agents:[...a.values()].sort((c,p)=>c.id.localeCompare(p.id)),channels:[...n.values()],initiators:[...r.values()],dispatches:o.sort((c,p)=>p.startedAt-c.startedAt)}}function Fl(t){if(t.clientId!=="unmapped")return t;let e=Dt(t.inputPreview);if(!e)return t;let a=xe?.business?.projects??[];return{...t,projectId:e,clientId:Ge(e,a)}}async function ct(t){let e=xe?.channels?.gitlab,a=await or(rr(t.dispatches),{gitlab:e?.host&&e?.token?{host:e.host,token:e.token}:void 0,githubToken:process.env.GITHUB_TOKEN||void 0});return{...t,forge:a}}var xe=null;function hr(t){xe=t}async function gr(t,e,a){if(a!=="/api/admin/activity-graph"&&!a.startsWith("/api/admin/activity-graph?"))return!1;let n=Ft();if(!n)return me(e,503,{error:"intent ledger not available",clients:[],agents:[],channels:[],initiators:[],dispatches:[]}),!0;try{let r=new URL(t.url||"/","http://_"),o=xr(parseInt(r.searchParams.get("hours")||"6",10));me(e,200,await ct(mr(n.db,xe,o)))}catch(r){me(e,500,{error:r?.message??String(r)})}finally{n.close()}return!0}var ql=5e3;async function Ut(t,e,a,n=qt){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
7760
7760
 
7761
- `);let r=new URL(t.url||"/","http://_"),o=cr(parseInt(r.searchParams.get("hours")||"6",10)),s=!1,i=()=>{s=!0};t.on("close",i),t.on("error",i),e.on("close",i),e.on("error",i);let l=setInterval(()=>{if(!s)try{e.write(`: hb
7761
+ `);let r=new URL(t.url||"/","http://_"),o=xr(parseInt(r.searchParams.get("hours")||"6",10)),s=!1,i=()=>{s=!0};t.on("close",i),t.on("error",i),e.on("close",i),e.on("error",i);let l=setInterval(()=>{if(!s)try{e.write(`: hb
7762
7762
 
7763
- `)}catch{i()}},25e3);try{for(;!s;){try{let p=await n(o),u=p&&await lt(p);if(s)break;u?(e.write(`event: snapshot
7763
+ `)}catch{i()}},25e3);try{for(;!s;){try{let p=await n(o),u=p&&await ct(p);if(s)break;u?(e.write(`event: snapshot
7764
7764
  `),e.write(`data: ${JSON.stringify(u)}
7765
7765
 
7766
7766
  `)):e.write(`event: error
@@ -7769,7 +7769,7 @@ data: ${JSON.stringify({error:"ledger not available"})}
7769
7769
  `)}catch(p){e.write(`event: error
7770
7770
  data: ${JSON.stringify({error:p?.message??String(p)})}
7771
7771
 
7772
- `)}let c=Date.now();for(;!s&&Date.now()-c<fl;)await new Promise(p=>setTimeout(p,200))}}finally{clearInterval(l);try{e.end()}catch{}}return!0}function cr(t){return!Number.isFinite(t)||t<1?6:Math.min(720,Math.max(1,t))}function hl(t,e,a=5e3){let n=new Date(e).toISOString().slice(0,10),r=Dt(process.cwd(),".agentx/task-history",t,n);if(!Ht(r)){let o=new Date(e-864e5).toISOString().slice(0,10),s=Dt(process.cwd(),".agentx/task-history",t,o);return Ht(s)?tr(s,e,a):null}return tr(r,e,a)}function tr(t,e,a){let n=null,r=1/0;for(let o of sl(t)){if(!o.endsWith(".json"))continue;let s;try{s=JSON.parse(il(ol(t,o),"utf-8"))}catch{continue}let i=s.startedAt,l;if(typeof i=="number")l=i;else if(typeof i=="string"){let p=Date.parse(i);if(!Number.isFinite(p))continue;l=p}else continue;let c=Math.abs(l-e);c<r&&c<=a&&(n=s,r=c)}return n}async function dr(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 ue(e,400,{error:"invalid dispatch id"}),!0;let s=r.slice(0,o),i=r.slice(o+1),l=Bt();if(!l)return ue(e,503,{error:"ledger not available"}),!0;try{let c=l.db.prepare("SELECT id, ts, source, project, subject, intent, raw_json FROM intent_events WHERE id = ?").get(s);if(!c)return ue(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 ue(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(c.raw_json)}catch{}let h=rr(c.source,f),y=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)||h,T=null,S=null;if(p.agent_id){let k=hl(p.agent_id,p.decided_at);if(k){typeof k.responseText=="string"&&(T=k.responseText);let b=k.transcript;Array.isArray(b)&&(S=b.length)}}let x=ge?.business?.projects??[],d=ge?.business?.contactMap??[],m=_t(ge?.business??{}),g={client:"unmapped",project:`unmapped/_${c.source}`,via:"fallback"},v=nr(c.source,f,d);if(v)g={client:v.client,project:v.project||`${v.client}/_chat`,via:`contactMap (channel=${v.channel??"*"}${v.username?` username=${v.username}`:""}${v.chatId?` chatId=${v.chatId}`:""})`};else if(c.project||st(f,c.subject,h)){let k=c.project||st(f,c.subject,h);g={client:We(k,x),project:k,via:c.project?`project namespace prefix (${k})`:`forge path in chat id / message (${k})`}}else if(p.agent_id){let k=m.get(p.agent_id);k&&(g={client:k,project:`${k}/_${c.source}`,via:`orgChart fallback (agent ${p.agent_id} reports up to a PM whose project belongs to ${k})`})}ue(e,200,{id:r,eventId:s,source:c.source,subject:c.subject,intent:c.intent,project:c.project,decidedBy:p.decided_by,agentId:p.agent_id,outcome:p.outcome,reason:p.reason,startedAt:p.decided_at,resolvedAt:u?.resolved_at??null,durationMs:u?.duration_ms??null,input:y,response:T,transcriptLen:S,resolutionStatus:u?.status??null,resultSummary:u?.result_summary??null,attribution:g})}catch(c){ue(e,500,{error:c?.message??String(c)})}finally{l.close()}return!0}import{existsSync as bl,readFileSync as yl}from"fs";import{resolve as ur}from"path";yt();function pr(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=gl.replace(/__AGENT_ID__/g,P(e));return $({title:`AgentX \xB7 ${P(e)}`,activeTab:"admin",subtitle:`Agent \xB7 ${P(e)}`,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:r,css:xl,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>${vl}</script>`})}var gl=`
7772
+ `)}let c=Date.now();for(;!s&&Date.now()-c<ql;)await new Promise(p=>setTimeout(p,200))}}finally{clearInterval(l);try{e.end()}catch{}}return!0}function xr(t){return!Number.isFinite(t)||t<1?6:Math.min(720,Math.max(1,t))}function Ul(t,e,a=5e3){let n=new Date(e).toISOString().slice(0,10),r=Bt(process.cwd(),".agentx/task-history",t,n);if(!zt(r)){let o=new Date(e-864e5).toISOString().slice(0,10),s=Bt(process.cwd(),".agentx/task-history",t,o);return zt(s)?cr(s,e,a):null}return cr(r,e,a)}function cr(t,e,a){let n=null,r=1/0;for(let o of jl(t)){if(!o.endsWith(".json"))continue;let s;try{s=JSON.parse(Ol(Pl(t,o),"utf-8"))}catch{continue}let i=s.startedAt,l;if(typeof i=="number")l=i;else if(typeof i=="string"){let p=Date.parse(i);if(!Number.isFinite(p))continue;l=p}else continue;let c=Math.abs(l-e);c<r&&c<=a&&(n=s,r=c)}return n}async function vr(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 me(e,400,{error:"invalid dispatch id"}),!0;let s=r.slice(0,o),i=r.slice(o+1),l=Ft();if(!l)return me(e,503,{error:"ledger not available"}),!0;try{let c=l.db.prepare("SELECT id, ts, source, project, subject, intent, raw_json FROM intent_events WHERE id = ?").get(s);if(!c)return me(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 me(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(c.raw_json)}catch{}let h=ur(c.source,f),v=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)||h,T=null,E=null;if(p.agent_id){let k=Ul(p.agent_id,p.decided_at);if(k){typeof k.responseText=="string"&&(T=k.responseText);let y=k.transcript;Array.isArray(y)&&(E=y.length)}}let g=xe?.business?.projects??[],d=xe?.business?.contactMap??[],m=St(xe?.business??{}),x={client:"unmapped",project:`unmapped/_${c.source}`,via:"fallback"},b=pr(c.source,f,d);if(b)x={client:b.client,project:b.project||`${b.client}/_chat`,via:`contactMap (channel=${b.channel??"*"}${b.username?` username=${b.username}`:""}${b.chatId?` chatId=${b.chatId}`:""})`};else if(c.project||it(f,c.subject,h)){let k=c.project||it(f,c.subject,h);x={client:Ge(k,g),project:k,via:c.project?`project namespace prefix (${k})`:`forge path in chat id / message (${k})`}}else if(p.agent_id){let k=m.get(p.agent_id);k&&(x={client:k,project:`${k}/_${c.source}`,via:`orgChart fallback (agent ${p.agent_id} reports up to a PM whose project belongs to ${k})`})}me(e,200,{id:r,eventId:s,source:c.source,subject:c.subject,intent:c.intent,project:c.project,decidedBy:p.decided_by,agentId:p.agent_id,outcome:p.outcome,reason:p.reason,startedAt:p.decided_at,resolvedAt:u?.resolved_at??null,durationMs:u?.duration_ms??null,input:v,response:T,transcriptLen:E,resolutionStatus:u?.status??null,resultSummary:u?.result_summary??null,attribution:x})}catch(c){me(e,500,{error:c?.message??String(c)})}finally{l.close()}return!0}import{existsSync as Kl,readFileSync as Jl}from"fs";import{resolve as yr}from"path";kt();function br(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=Wl.replace(/__AGENT_ID__/g,j(e));return L({title:`AgentX \xB7 ${j(e)}`,activeTab:"admin",subtitle:`Agent \xB7 ${j(e)}`,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:r,css:Gl,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>${Xl}</script>`})}var Wl=`
7773
7773
  <!-- Breadcrumb -->
7774
7774
  <div class="ax-crumb">
7775
7775
  <a href="/admin">Settings</a>
@@ -8358,7 +8358,7 @@ data: ${JSON.stringify({error:p?.message??String(p)})}
8358
8358
  </div>
8359
8359
  </div>
8360
8360
  </div>
8361
- `,xl=`
8361
+ `,Gl=`
8362
8362
  /* Agent-specific layout + legacy styles for bits the migration left in
8363
8363
  * place (EasyMDE theming, skills tree, plain-editor). Shared chrome + tab
8364
8364
  * primitives live in components.css.ts. */
@@ -8477,7 +8477,7 @@ textarea.inp.mono { font-family: var(--ax-mono); }
8477
8477
 
8478
8478
  /* Agent-specific button variant used in rail context (no ax-btn wrapper) */
8479
8479
  .ax-btn.lg { padding: 9px 16px; font-size: 13px; }
8480
- `,vl=`
8480
+ `,Xl=`
8481
8481
  const $ = (id) => document.getElementById(id);
8482
8482
  const state = { agent: null, activeSkill: null, activeSkillFile: null, identityPath: null };
8483
8483
 
@@ -9333,15 +9333,15 @@ document.addEventListener('keydown', (e) => {
9333
9333
  /* ===== Boot ===== */
9334
9334
  initOptsToggles();
9335
9335
  loadAgent();
9336
- `;function mr(t,e,a,n=[],r){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(pr({agentId:a,peers:n,localToken:r}))}async function fr(t,e,a){try{let n=t.method==="GET"?void 0:await Fl(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){ct(e,404,{error:`unknown agent endpoint: ${a}`});return}let i=s[1],l=s[2]||"",c=`${t.method} ${l}`,u={"GET ":()=>Oe(i),"PATCH ":()=>wl(i,n),"PATCH capability":()=>El(i,n),"POST mcp":()=>kl(i,n),"DELETE mcp":()=>_l(i,n),"GET identity":()=>Sl(i),"GET identity/file":()=>Tl(i,String(o.path||"")),"PUT identity/file":()=>Cl(i,n),"GET skills":()=>Al(i),"POST skills":()=>Ml(i,n),"DELETE skills":()=>Il(i,n),"GET skills/tree":()=>$l(i,String(o.slug||"")),"GET skills/file":()=>Ll(i,String(o.slug||""),String(o.path||"")),"PUT skills/file":()=>Rl(i,n),"GET skills/deps":()=>jl(i,String(o.slug||"")),"POST skills/install":()=>Pl(i,n,t),"POST skills/deps":()=>Ol(i,n,t),"GET channels":()=>Nl(i),"GET activity":()=>Dl(i,t),"GET handovers":()=>Hl(i),"POST handovers":()=>Bl(i,n),"DELETE handovers":()=>zl(n)}[c];if(!u){ct(e,404,{error:`unknown agent sub-endpoint: ${c}`});return}let f=await u();ct(e,200,f)}catch(n){ct(e,400,{error:n?.message||"agent op failed"})}}function hr(){let t=ur(process.cwd(),"agentx.json");return bl(t)?JSON.parse(yl(t,"utf-8")):null}function W(t){let e=hr();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 Oe(t){let{def:e,cfg:a}=W(t),n=e.workspace?Te(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 wl(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:Oe(t)}}function kl(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:Oe(t)}}function _l(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:Oe(t)}}function El(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:Oe(t)}}function Sl(t){let{def:e}=W(t);return Te(e.workspace)}function Tl(t,e){if(!e)throw new Error("path query param required");let{def:a}=W(t);return Ke(a.workspace,e)}function Cl(t,e){let a=String(e?.path||"");if(!a)throw new Error("path required");let{def:n}=W(t);return Je(n.workspace,a,String(e?.content??""))}function Al(t){let{def:e}=W(t),a=Te(e.workspace);return{skills:a.skills,workspace:a.workspace}}function Ml(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=W(t);return Ve(n.workspace,a,{title:e?.title,content:e?.content})}function Il(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=W(t);return Ye(n.workspace,a)}function $l(t,e){if(!e)throw new Error("slug query param required");let{def:a}=W(t),n=Na(a.workspace,e),r=Qe(a.workspace,e);return{slug:e,tree:n,deps:r}}function Ll(t,e,a){if(!e||!a)throw new Error("slug and path query params required");let{def:n}=W(t);return Da(n.workspace,e,a)}function Rl(t,e){let a=String(e?.slug||""),n=String(e?.path||"");if(!a||!n)throw new Error("slug and path required");let{def:r}=W(t);return Ha(r.workspace,a,n,String(e?.content??""))}function jl(t,e){if(!e)throw new Error("slug query param required");let{def:a}=W(t);return Qe(a.workspace,e)}async function Pl(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=gr(e?.worker),{def:o}=W(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(`
9337
- `);return xr(a,r,s,`install-${n}:${Date.now()}`)}async function Ol(t,e,a){let n=String(e?.slug||"").trim();if(!n)throw new Error("slug required");let r=gr(e?.worker),{def:o}=W(t),s=Qe(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=ur(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(`
9338
- `);return xr(a,r,l,`deps-${t}-${n}:${Date.now()}`)}function gr(t){if(t&&typeof t=="string")return t;let e=Q();return e.dashboard?.draftAgent||e.node?.defaultAgent||Object.keys(e.agents).find(a=>a.includes("devops"))||Object.keys(e.agents)[0]}async function xr(t,e,a,n){let r=Q(),o=(r.dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),s={"Content-Type":"application/json"},i=t.headers.authorization;i?s.Authorization=String(i):r.dashboard.token&&(s.Authorization=`Bearer ${r.dashboard.token}`);let l=await fetch(`${o}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"admin",sender:"admin-ui",chatId:n}})}),c=await l.text(),p;try{p=JSON.parse(c)}catch{p={content:c}}if(!l.ok)throw new Error(p?.error||`daemon /task HTTP ${l.status}`);return{worker:e,taskId:p?.taskId,content:p?.content,duration:p?.duration,error:p?.error}}function Nl(t){let e=hr(),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 Dl(t,e){try{let n=(Q().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 Ut(){return new ca}function Hl(t){let e=Ut(),{incoming:a,outgoing:n}=e.listByAgent(t);return{incoming:a,outgoing:n}}function Bl(t,e){let a=String(e?.channel||"").trim(),n=String(e?.chatId||"").trim(),r=String(e?.toAgent||"").trim();if(!a||!n||!r)throw new Error("channel, chatId, toAgent required");let o=String(e?.fromAgent||t||"").trim()||t,s=e?.accountId?String(e.accountId):void 0,i=e?.summary?String(e.summary):void 0,l=e?.expiresAt?String(e.expiresAt):void 0,c=Ut().set({channel:a,chatId:n,accountId:s,fromAgent:o,toAgent:r,summary:i,expiresAt:l,createdBy:"admin-ui"});return{summary:`Handed off ${a}:${n} from ${o} to ${r}`,record:c}}function zl(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:Ut().remove(e,a,n)?"Released":"No active handover for that chat"}}function ct(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function Fl(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 we={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 vr=[{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 qt(t={}){let e=`<script>window.UI_LABELS = ${JSON.stringify(we)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
9336
+ `;function wr(t,e,a,n=[],r){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(br({agentId:a,peers:n,localToken:r}))}async function kr(t,e,a){try{let n=t.method==="GET"?void 0:await xc(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){dt(e,404,{error:`unknown agent endpoint: ${a}`});return}let i=s[1],l=s[2]||"",c=`${t.method} ${l}`,u={"GET ":()=>De(i),"PATCH ":()=>Vl(i,n),"PATCH capability":()=>Zl(i,n),"POST mcp":()=>Yl(i,n),"DELETE mcp":()=>Ql(i,n),"GET identity":()=>ec(i),"GET identity/file":()=>tc(i,String(o.path||"")),"PUT identity/file":()=>ac(i,n),"GET skills":()=>nc(i),"POST skills":()=>rc(i,n),"DELETE skills":()=>oc(i,n),"GET skills/tree":()=>sc(i,String(o.slug||"")),"GET skills/file":()=>ic(i,String(o.slug||""),String(o.path||"")),"PUT skills/file":()=>lc(i,n),"GET skills/deps":()=>cc(i,String(o.slug||"")),"POST skills/install":()=>dc(i,n,t),"POST skills/deps":()=>pc(i,n,t),"GET channels":()=>uc(i),"GET activity":()=>mc(i,t),"GET handovers":()=>fc(i),"POST handovers":()=>hc(i,n),"DELETE handovers":()=>gc(n)}[c];if(!u){dt(e,404,{error:`unknown agent sub-endpoint: ${c}`});return}let f=await u();dt(e,200,f)}catch(n){dt(e,400,{error:n?.message||"agent op failed"})}}function _r(){let t=yr(process.cwd(),"agentx.json");return Kl(t)?JSON.parse(Jl(t,"utf-8")):null}function G(t){let e=_r();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 De(t){let{def:e,cfg:a}=G(t),n=e.workspace?Me(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 Vl(t,e){let a={};for(let r of["name","tier","model","systemPrompt","mentions","access","maxConcurrent","maxExecutionMinutes","permissionMode"])e?.[r]!==void 0&&(a[r]=e[r]);let{summary:n}=A(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);return r.agents[t]={...r.agents[t],...a},`agent "${t}" updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:De(t)}}function Yl(t,e){let a=String(e?.name||"").trim(),n=String(e?.command||"").trim();if(!a)throw new Error("name required");if(!/^[a-zA-Z0-9_-]+$/.test(a))throw new Error("name must be identifier-safe (alnum, _, -)");if(!n)throw new Error("command required");let r=Array.isArray(e?.args)?e.args.map(i=>String(i)):[],o;if(e?.env&&typeof e.env=="object"){o={};for(let[i,l]of Object.entries(e.env))typeof l=="string"&&(o[i]=l);Object.keys(o).length===0&&(o=void 0)}let{summary:s}=A(i=>{if(!i.agents?.[t])throw new Error(`Agent "${t}" not found`);return i.agents[t].mcp=i.agents[t].mcp||{},i.agents[t].mcp[a]={command:n,args:r,...o?{env:o}:{}},`agent "${t}" mcp.${a} upserted`});return{summary:s,agent:De(t)}}function Ql(t,e){let a=String(e?.name||"").trim();if(!a)throw new Error("name required");let{summary:n}=A(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);if(!r.agents[t].mcp||!(a in r.agents[t].mcp))throw new Error(`no mcp.${a} on "${t}"`);return delete r.agents[t].mcp[a],Object.keys(r.agents[t].mcp).length===0&&delete r.agents[t].mcp,`agent "${t}" mcp.${a} removed`});return{summary:n,agent:De(t)}}function Zl(t,e){let a={};if(Array.isArray(e?.intents)&&(a.intents=e.intents.map(r=>String(r)).filter(Boolean)),e?.maxDelegationDepth!==void 0){let r=Number(e.maxDelegationDepth);if(!Number.isFinite(r)||r<0||r>50)throw new Error("maxDelegationDepth must be 0..50");a.maxDelegationDepth=r}if(e?.contextReferences!==void 0&&(a.contextReferences=!!e.contextReferences),e?.contextStrategy!==void 0){if(e.contextStrategy&&!["layered","planner"].includes(e.contextStrategy))throw new Error("contextStrategy must be layered|planner|empty");e.contextStrategy?a.contextStrategy=e.contextStrategy:a.contextStrategy=void 0}if(e?.maxExecutionMinutes!==void 0){let r=Number(e.maxExecutionMinutes);if(!Number.isFinite(r)||r<1||r>240)throw new Error("maxExecutionMinutes must be 1..240");a.maxExecutionMinutes=r}if(Object.keys(a).length===0)throw new Error("nothing to update");let{summary:n}=A(r=>{if(!r.agents?.[t])throw new Error(`Agent "${t}" not found`);let o={...r.agents[t]};for(let[s,i]of Object.entries(a))i===void 0?delete o[s]:o[s]=i;return r.agents[t]=o,`agent "${t}" capability updated (${Object.keys(a).join(", ")})`});return{summary:n,agent:De(t)}}function ec(t){let{def:e}=G(t);return Me(e.workspace)}function tc(t,e){if(!e)throw new Error("path query param required");let{def:a}=G(t);return Je(a.workspace,e)}function ac(t,e){let a=String(e?.path||"");if(!a)throw new Error("path required");let{def:n}=G(t);return Ve(n.workspace,a,String(e?.content??""))}function nc(t){let{def:e}=G(t),a=Me(e.workspace);return{skills:a.skills,workspace:a.workspace}}function rc(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=G(t);return Ye(n.workspace,a,{title:e?.title,content:e?.content})}function oc(t,e){let a=String(e?.slug||"").trim();if(!a)throw new Error("slug required");let{def:n}=G(t);return Qe(n.workspace,a)}function sc(t,e){if(!e)throw new Error("slug query param required");let{def:a}=G(t),n=Ua(a.workspace,e),r=Ze(a.workspace,e);return{slug:e,tree:n,deps:r}}function ic(t,e,a){if(!e||!a)throw new Error("slug and path query params required");let{def:n}=G(t);return Wa(n.workspace,e,a)}function lc(t,e){let a=String(e?.slug||""),n=String(e?.path||"");if(!a||!n)throw new Error("slug and path required");let{def:r}=G(t);return Ga(r.workspace,a,n,String(e?.content??""))}function cc(t,e){if(!e)throw new Error("slug query param required");let{def:a}=G(t);return Ze(a.workspace,e)}async function dc(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=Er(e?.worker),{def:o}=G(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(`
9337
+ `);return Sr(a,r,s,`install-${n}:${Date.now()}`)}async function pc(t,e,a){let n=String(e?.slug||"").trim();if(!n)throw new Error("slug required");let r=Er(e?.worker),{def:o}=G(t),s=Ze(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=yr(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(`
9338
+ `);return Sr(a,r,l,`deps-${t}-${n}:${Date.now()}`)}function Er(t){if(t&&typeof t=="string")return t;let e=te();return e.dashboard?.draftAgent||e.node?.defaultAgent||Object.keys(e.agents).find(a=>a.includes("devops"))||Object.keys(e.agents)[0]}async function Sr(t,e,a,n){let r=te(),o=(r.dashboard.daemonUrl||"http://localhost:18800").replace(/\/+$/,""),s={"Content-Type":"application/json"},i=t.headers.authorization;i?s.Authorization=String(i):r.dashboard.token&&(s.Authorization=`Bearer ${r.dashboard.token}`);let l=await fetch(`${o}/task`,{method:"POST",headers:s,body:JSON.stringify({agent:e,message:a,context:{channel:"admin",sender:"admin-ui",chatId:n}})}),c=await l.text(),p;try{p=JSON.parse(c)}catch{p={content:c}}if(!l.ok)throw new Error(p?.error||`daemon /task HTTP ${l.status}`);return{worker:e,taskId:p?.taskId,content:p?.content,duration:p?.duration,error:p?.error}}function uc(t){let e=_r(),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 mc(t,e){try{let n=(te().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 Wt(){return new ha}function fc(t){let e=Wt(),{incoming:a,outgoing:n}=e.listByAgent(t);return{incoming:a,outgoing:n}}function hc(t,e){let a=String(e?.channel||"").trim(),n=String(e?.chatId||"").trim(),r=String(e?.toAgent||"").trim();if(!a||!n||!r)throw new Error("channel, chatId, toAgent required");let o=String(e?.fromAgent||t||"").trim()||t,s=e?.accountId?String(e.accountId):void 0,i=e?.summary?String(e.summary):void 0,l=e?.expiresAt?String(e.expiresAt):void 0,c=Wt().set({channel:a,chatId:n,accountId:s,fromAgent:o,toAgent:r,summary:i,expiresAt:l,createdBy:"admin-ui"});return{summary:`Handed off ${a}:${n} from ${o} to ${r}`,record:c}}function gc(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:Wt().remove(e,a,n)?"Released":"No active handover for that chat"}}function dt(t,e,a){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}function xc(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 ke={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 Tr=[{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 Gt(t={}){let e=`<script>window.UI_LABELS = ${JSON.stringify(ke)};</script>`,a=`<span id="ts" class="ax-mono" title="Last update">\u2014</span>
9339
9339
  <span id="conn-dot" class="ax-dot ax-dot--ok ax-dot--pulse" title="connected"></span>
9340
9340
  <span id="conn-label">live</span>`,n=`<div class="ax-app-live">
9341
9341
  <section id="statstrip" class="ax-statstrip"></section>
9342
9342
  <main id="grid" class="ax-live__body"></main>
9343
9343
  </div>
9344
- `;return $({title:`${we.brand} \xB7 ${we.subtitle}`,activeTab:"live",subtitle:we.subtitle,peers:t.peers,currentPeerId:t.currentPeerId,customHeader:void 0,noMain:!0,body:n,css:Ul,scripts:e+`<script>${ql}</script>`,headExtras:`<script>
9344
+ `;return L({title:`${ke.brand} \xB7 ${ke.subtitle}`,activeTab:"live",subtitle:ke.subtitle,peers:t.peers,currentPeerId:t.currentPeerId,customHeader:void 0,noMain:!0,body:n,css:vc,scripts:e+`<script>${bc}</script>`,headExtras:`<script>
9345
9345
  // rightExtras for the topbar are injected at runtime \u2014 they reference
9346
9346
  // IDs (#ts, #conn-dot) that the script below addresses directly.
9347
9347
  document.addEventListener('DOMContentLoaded', () => {
@@ -9352,7 +9352,7 @@ loadAgent();
9352
9352
  extras.innerHTML = ${JSON.stringify(a)};
9353
9353
  right.insertBefore(extras, right.firstChild);
9354
9354
  });
9355
- </script>`})}var Ul=`
9355
+ </script>`})}var vc=`
9356
9356
  /* --- Page frame --- */
9357
9357
  .ax-app-live { min-height: 100vh; display: flex; flex-direction: column; }
9358
9358
 
@@ -9559,7 +9559,7 @@ loadAgent();
9559
9559
  border-top-color: var(--ax-accent); border-radius: 50%;
9560
9560
  animation: ax-spin 800ms linear infinite; display: inline-block;
9561
9561
  }
9562
- @keyframes ax-spin { to { transform: rotate(360deg); } }`,ql=`
9562
+ @keyframes ax-spin { to { transform: rotate(360deg); } }`,bc=`
9563
9563
  'use strict';
9564
9564
 
9565
9565
  const ui = { nodes: new Map(), summary: { nodes: 0, agents: 0, busy: 0, errors: 0 } };
@@ -10130,7 +10130,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
10130
10130
  });
10131
10131
  }
10132
10132
 
10133
- `;var br=`
10133
+ `;var Ar=`
10134
10134
  .mx-content{max-width:1180px;margin:0 auto;padding:0 24px 56px}
10135
10135
  .mx-updated{margin:0;color:var(--ax-muted);font-size:11px;font-family:var(--ax-mono)}
10136
10136
  .mx-section{margin-bottom:28px}.mx-section .ax-section-head{margin-bottom:14px}
@@ -10304,7 +10304,7 @@ function taskAction(nodeUrl, taskId, kind, body, hooks) {
10304
10304
  .mx-summary{max-width:56vw}
10305
10305
  }
10306
10306
  @media(prefers-reduced-motion:reduce){.mx-drawer{transition:none}}
10307
- `;var yr=`<script>
10307
+ `;var Cr=`<script>
10308
10308
  window.MX=(function(){
10309
10309
  var ENT={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'};
10310
10310
  function esc(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return ENT[c]})}
@@ -10413,7 +10413,7 @@ window.MX=(function(){
10413
10413
  verdict:verdict,verdictChip:verdictChip,mark:mark,causeLabel:causeLabel,
10414
10414
  setHealth:setHealth,get:get};
10415
10415
  })();
10416
- </script>`;var wr=`<script>
10416
+ </script>`;var Mr=`<script>
10417
10417
  window.MXD=(function(){
10418
10418
  function el(id){return document.getElementById(id)}
10419
10419
  function tz(){return -new Date().getTimezoneOffset()}
@@ -10627,7 +10627,7 @@ window.MXD=(function(){
10627
10627
 
10628
10628
  return {openDay:openDay,openJob:openJob,openConversation:openConversation};
10629
10629
  })();
10630
- </script>`;var kr=`<script>
10630
+ </script>`;var Ir=`<script>
10631
10631
  (function(){
10632
10632
  var LANES=[
10633
10633
  {id:'cron',name:'Scheduled',hint:'cron jobs'},
@@ -10943,7 +10943,7 @@ window.MXD=(function(){
10943
10943
  window.addEventListener('scroll',hideTip,{passive:true});
10944
10944
  load();
10945
10945
  })();
10946
- </script>`;var _r=`<script>
10946
+ </script>`;var Lr=`<script>
10947
10947
  (function(){
10948
10948
  var showAll=document.getElementById('mx-show-all'),expanded=false;
10949
10949
  var esc=MX.esc;
@@ -11121,7 +11121,7 @@ window.MXD=(function(){
11121
11121
  }
11122
11122
  load();setInterval(load,5000);
11123
11123
  })();
11124
- </script>`;var Er=`
11124
+ </script>`;var $r=`
11125
11125
  .mx-rt-bar{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:12px}
11126
11126
  .mx-rt-wrap{border:var(--ax-border-w) solid var(--ax-border);border-radius:var(--ax-radius-lg);background:var(--ax-surface);overflow-x:auto}
11127
11127
  .mx-rt-wrap > .mx-empty{border:0}
@@ -11162,7 +11162,7 @@ window.MXD=(function(){
11162
11162
  .mx-rt-msg td{display:block}.mx-rt-msg td::before{content:none}
11163
11163
  .mx-rt-name{max-width:100%}
11164
11164
  }
11165
- `,Sr=`<script>
11165
+ `,Rr=`<script>
11166
11166
  (function(){
11167
11167
  var root=document.getElementById('mx-routines');
11168
11168
  var bar=document.getElementById('mx-rt-filter');
@@ -11289,7 +11289,7 @@ window.MXD=(function(){
11289
11289
  syncBar();
11290
11290
  document.addEventListener('mx:snapshot',function(e){render(e.detail||{})});
11291
11291
  })();
11292
- </script>`;var Tr=[{id:"all",label:"All"},{id:"peers",label:"Other machines"},{id:"announce",label:"Announcements"},{id:"problems",label:"Problems"}],Cr=`<script>
11292
+ </script>`;var Pr=[{id:"all",label:"All"},{id:"peers",label:"Other machines"},{id:"announce",label:"Announcements"},{id:"problems",label:"Problems"}],jr=`<script>
11293
11293
  (function(){
11294
11294
  var root=document.getElementById('mx-feed');
11295
11295
  if(!root)return;
@@ -11364,17 +11364,17 @@ window.MXD=(function(){
11364
11364
  }
11365
11365
  load();setInterval(load,5000);
11366
11366
  })();
11367
- </script>`;var K={activity:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h3l2-6 4 12 2-6h5"/></svg>',breakage:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v6l-3 3 3 3v6"/><path d="M5 5l14 14"/></svg>',effort:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20V4M4 20h16"/><circle cx="9" cy="15" r="2"/><circle cx="15" cy="8" r="2"/></svg>',lifetime:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h18"/><path d="M7 8v8M13 8v8M19 8v8"/></svg>',cuts:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><path d="M8 8l12 10M8 16L20 6"/></svg>',schedules:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>',routines:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h11M4 12h7M4 17h9"/><path d="M17 5l3 3-3 3M16 14l4 4M20 14l-4 4"/></svg>',nodes:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M8 6h8M7 8l4 8M17 8l-4 8"/></svg>',feed:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1.5"/></svg>',agents:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4M8 16h.01M16 16h.01"/></svg>'};function J(t,e,a,n,r=""){return U({icon:t,title:e,lead:a,actionHtml:r}).replace("<h2>",`<h2 id="${n}">`)}var Wl=[{id:"all",label:"All"},{id:"attention",label:"Flagged"},{id:"schedule",label:"Schedules"},{id:"event",label:"Events"}],Gl=[{id:"activity",label:"Activity"},{id:"lifetime",label:"Lifetime"},{id:"ops",label:"Operations"}],Xl=[{days:0,label:"Today"},{days:7,label:"7d"},{days:30,label:"30d"},{days:90,label:"90d"}];function Ar(t){let e=Ze({kicker:"Operations",title:"Mesh operations",lead:"What the fleet actually did, how long it lived, and which of it was worth running."})+et([{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">
11367
+ </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>',routines:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h11M4 12h7M4 17h9"/><path d="M17 5l3 3-3 3M16 14l4 4M20 14l-4 4"/></svg>',nodes:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M8 6h8M7 8l4 8M17 8l-4 8"/></svg>',feed:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1.5"/></svg>',agents:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4M8 16h.01M16 16h.01"/></svg>'};function Q(t,e,a,n,r=""){return U({icon:t,title:e,lead:a,actionHtml:r}).replace("<h2>",`<h2 id="${n}">`)}var yc=[{id:"all",label:"All"},{id:"attention",label:"Flagged"},{id:"schedule",label:"Schedules"},{id:"event",label:"Events"}],wc=[{id:"activity",label:"Activity"},{id:"lifetime",label:"Lifetime"},{id:"ops",label:"Operations"}],kc=[{days:0,label:"Today"},{days:7,label:"7d"},{days:30,label:"30d"},{days:90,label:"90d"}];function Or(t){let e=et({kicker:"Operations",title:"Mesh operations",lead:"What the fleet actually did, how long it lived, and which of it was worth running."})+tt([{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">
11368
11368
  <div class="mx-tabs" role="tablist" aria-label="Mesh views">
11369
- ${Gl.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("")}
11369
+ ${wc.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("")}
11370
11370
  </div>
11371
11371
  <div class="mx-range" id="mx-range" role="group" aria-label="History window">
11372
- ${Xl.map(i=>`<button type="button" data-days="${i.days}" aria-pressed="${i.days===30}">${i.label}</button>`).join("")}
11372
+ ${kc.map(i=>`<button type="button" data-days="${i.days}" aria-pressed="${i.days===30}">${i.label}</button>`).join("")}
11373
11373
  </div>
11374
11374
  </div>
11375
11375
  <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">
11376
11376
  <section class="mx-section" aria-labelledby="mx-lanes-title">
11377
- ${J(K.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")}
11377
+ ${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")}
11378
11378
  <div id="mx-lanes"><div class="mx-empty">Loading activity...</div></div>
11379
11379
  <div class="mx-axis" id="mx-axis"></div>
11380
11380
  <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>
@@ -11382,32 +11382,32 @@ window.MXD=(function(){
11382
11382
 
11383
11383
  <div class="mx-two">
11384
11384
  <section class="mx-section" aria-labelledby="mx-origins-title">
11385
- ${J(K.breakage,"Where it breaks","Attempts per origin, with the failed share marked on the same bar.","mx-origins-title")}
11385
+ ${Q(Y.breakage,"Where it breaks","Attempts per origin, with the failed share marked on the same bar.","mx-origins-title")}
11386
11386
  <div class="mx-bars" id="mx-origins"><div class="mx-empty">Loading...</div></div>
11387
11387
  </section>
11388
11388
  <section class="mx-section" aria-labelledby="mx-causes-title">
11389
- ${J(K.breakage,"Why it fails","Failures grouped by cause class, matched from the recorded error text.","mx-causes-title")}
11389
+ ${Q(Y.breakage,"Why it fails","Failures grouped by cause class, matched from the recorded error text.","mx-causes-title")}
11390
11390
  <div class="mx-bars" id="mx-causes"><div class="mx-empty">Loading...</div></div>
11391
11391
  <p class="mx-note" id="mx-cause-note"></p>
11392
11392
  </section>
11393
11393
  </div>
11394
11394
 
11395
11395
  <section class="mx-section" aria-labelledby="mx-scatter-title">
11396
- ${J(K.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")}
11396
+ ${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")}
11397
11397
  <div class="mx-scatter" id="mx-scatter"><div class="mx-empty">Loading jobs...</div></div>
11398
11398
  <div class="mx-legend" id="mx-scatter-legend"></div>
11399
11399
  <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>
11400
11400
  </section>
11401
11401
  </div>`,r=`<div class="mx-view" id="mx-view-lifetime" role="tabpanel" aria-labelledby="mx-tab-lifetime" hidden>
11402
11402
  <section class="mx-section" aria-labelledby="mx-threads-title">
11403
- ${J(K.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")}
11403
+ ${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")}
11404
11404
  <div class="mx-chips" id="mx-thread-chips"></div>
11405
11405
  <div id="mx-threads"><div class="mx-empty">Loading threads...</div></div>
11406
11406
  <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>
11407
11407
  </section>
11408
11408
 
11409
11409
  <section class="mx-section" aria-labelledby="mx-rot-title">
11410
- ${J(K.cuts,"Session cuts","Why threads lost their session, across the fleet.","mx-rot-title")}
11410
+ ${Q(Y.cuts,"Session cuts","Why threads lost their session, across the fleet.","mx-rot-title")}
11411
11411
  <div class="mx-bars" id="mx-rotations"><div class="mx-empty">Loading...</div></div>
11412
11412
  <p class="mx-note" id="mx-rot-note"></p>
11413
11413
  </section>
@@ -11415,39 +11415,39 @@ window.MXD=(function(){
11415
11415
  <p id="mx-updated" class="mx-updated" aria-live="polite">Connecting to the fleet...</p>
11416
11416
 
11417
11417
  <section class="mx-section" aria-labelledby="mx-auto-title">
11418
- ${J(K.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>')}
11418
+ ${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>')}
11419
11419
  <div class="ax-stack" id="mx-runs"><div class="mx-empty">Loading schedules...</div></div>
11420
11420
  </section>
11421
11421
 
11422
11422
  <section class="mx-section" aria-labelledby="mx-routines-title">
11423
- ${J(K.routines,"Routines","Everything that runs on its own: schedules and cron- or event-triggered workflows, per node. Flags mark routines that keep failing, went quiet, never ran, or sat disabled.","mx-routines-title",'<span class="ax-tab-count" id="mx-rt-count">0 routines</span>')}
11423
+ ${Q(Y.routines,"Routines","Everything that runs on its own: schedules and cron- or event-triggered workflows, per node. Flags mark routines that keep failing, went quiet, never ran, or sat disabled.","mx-routines-title",'<span class="ax-tab-count" id="mx-rt-count">0 routines</span>')}
11424
11424
  <div class="mx-rt-bar" id="mx-rt-filter" role="group" aria-label="Filter routines">
11425
- ${Wl.map(i=>`<button class="mx-chip" type="button" data-rt-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
11425
+ ${yc.map(i=>`<button class="mx-chip" type="button" data-rt-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
11426
11426
  </div>
11427
11427
  <div class="mx-rt-wrap" id="mx-routines"><div class="mx-empty">Loading routines...</div></div>
11428
11428
  </section>
11429
11429
 
11430
11430
  <section class="mx-section" aria-labelledby="mx-feed-title">
11431
- ${J(K.feed,"Mesh feed","The newest events from this machine and every machine it follows. Unreachable machines and announcements show here too. Select an event for its details.","mx-feed-title",'<div class="mx-section-actions"><span class="ax-tab-count" id="mx-feed-count">0 events</span><button class="ax-btn ax-btn--ghost" id="mx-feed-more" type="button" hidden>Show all</button></div>')}
11431
+ ${Q(Y.feed,"Mesh feed","The newest events from this machine and every machine it follows. Unreachable machines and announcements show here too. Select an event for its details.","mx-feed-title",'<div class="mx-section-actions"><span class="ax-tab-count" id="mx-feed-count">0 events</span><button class="ax-btn ax-btn--ghost" id="mx-feed-more" type="button" hidden>Show all</button></div>')}
11432
11432
  <div class="mx-rt-bar" role="group" aria-label="Filter the mesh feed">
11433
- ${Tr.map(i=>`<button class="mx-chip" type="button" data-feed-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
11433
+ ${Pr.map(i=>`<button class="mx-chip" type="button" data-feed-filter="${i.id}" aria-pressed="${i.id==="all"}">${i.label}</button>`).join("")}
11434
11434
  </div>
11435
11435
  <div class="ax-stack" id="mx-feed" aria-live="polite"><div class="mx-empty">Loading the mesh feed...</div></div>
11436
11436
  </section>
11437
11437
 
11438
11438
  <div class="mx-columns">
11439
11439
  <section class="mx-section" aria-labelledby="mx-active-title">
11440
- ${J(K.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>')}
11440
+ ${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>')}
11441
11441
  <div class="ax-stack" id="mx-active"><div class="mx-empty">No activity loaded.</div></div>
11442
11442
  </section>
11443
11443
  <section class="mx-section" aria-labelledby="mx-nodes-title">
11444
- ${J(K.nodes,"Nodes","Reachability and capacity across the fleet.","mx-nodes-title",'<span class="ax-tab-count" id="mx-node-count">0 nodes</span>')}
11444
+ ${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>')}
11445
11445
  <div class="ax-stack" id="mx-nodes"><div class="mx-empty">No nodes loaded.</div></div>
11446
11446
  </section>
11447
11447
  </div>
11448
11448
 
11449
11449
  <section class="mx-section" aria-labelledby="mx-agents-title">
11450
- ${J(K.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>')}
11450
+ ${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>')}
11451
11451
  <div class="mx-agent-grid" id="mx-agents"><div class="mx-empty">No agents loaded.</div></div>
11452
11452
  </section>
11453
11453
  </div>`,s=`${e}<main class="mx-content">
@@ -11463,7 +11463,7 @@ window.MXD=(function(){
11463
11463
  <button class="ax-btn ax-btn--ghost" id="mx-close" type="button" aria-label="Close details">Close</button>
11464
11464
  </header>
11465
11465
  <div class="mx-drawer__body" id="mx-drawer-body"></div>
11466
- </aside>`;return $({title:"AgentX \xB7 Mesh Operations",activeTab:"mesh",subtitle:"Operations",peers:t.peers,noMain:!0,body:s,css:br+Er,scripts:yr+Kl+wr+kr+Sr+_r+Cr})}var Kl=`<script>
11466
+ </aside>`;return L({title:"AgentX \xB7 Mesh Operations",activeTab:"mesh",subtitle:"Operations",peers:t.peers,noMain:!0,body:s,css:Ar+$r,scripts:Cr+_c+Mr+Ir+Rr+Lr+jr})}var _c=`<script>
11467
11467
  (function(){
11468
11468
  var tabs=Array.prototype.slice.call(document.querySelectorAll('.mx-tab'));
11469
11469
  var range=document.getElementById('mx-range');
@@ -11491,7 +11491,7 @@ window.MXD=(function(){
11491
11491
  var saved=null;try{saved=localStorage.getItem('mx-view')}catch(e){}
11492
11492
  select(tabs.some(function(t){return t.dataset.view===saved})?saved:'activity');
11493
11493
  })();
11494
- </script>`;async function Mr(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?days=${e.days}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/mesh"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return Jl(s,e.days)}function Jl(t,e){let a={runs:0,errors:0,hours:0,agents:0,threads:0},n=new Map,r=new Map,o=new Map,s=new Map,i=[],l=[],c=0,p=0,u=0,f=0,h=0,y=0;for(let{node:S,data:x}of t)if(x){a.runs+=x.totals.runs,a.errors+=x.totals.errors,a.hours+=x.totals.hours,a.agents+=x.totals.agents,a.threads+=x.totals.threads;for(let d of x.days){let m=n.get(d.day)||{day:d.day,cron:[0,0],workflow:[0,0],direct:[0,0]};for(let g of["cron","workflow","direct"])m[g][0]+=d[g]?.[0]||0,m[g][1]+=d[g]?.[1]||0;n.set(d.day,m)}for(let d of x.origins){let m=r.get(d.channel)||{channel:d.channel,runs:0,errors:0,hours:0};m.runs+=d.runs,m.errors+=d.errors,m.hours+=d.hours,r.set(d.channel,m)}for(let d of x.causes){let m=o.get(d.cause)||{cause:d.cause,count:0,agents:[],example:""};m.count+=d.count;for(let g of d.agents)m.agents.includes(g)||m.agents.push(g);m.example||(m.example=d.example),o.set(d.cause,m)}for(let d of x.rotations.byReason)s.set(d.reason,(s.get(d.reason)||0)+d.count);c+=x.rotations.total,p+=x.rotations.tokenSum||0,u+=x.rotations.tokenSamples||0,f=Math.max(f,x.rotations.maxTokens),h+=x.retention.traces,y+=x.retention.tracesWithSteps;for(let d of x.jobs)i.push({...d,node:S.name,nodeUrl:S.url});for(let d of x.threads)l.push({...d,node:S.name,nodeUrl:S.url})}let T=t.filter(S=>S.data).map(S=>S.data.since).filter(S=>Number.isFinite(S));return{generatedAt:Date.now(),windowDays:e,since:T.length?Math.min(...T):Date.now()-e*864e5,nodes:t.map(S=>({name:S.node.name,url:S.node.url,ok:!!S.data,error:S.error,runs:S.data?.totals.runs||0})),totals:{...a,hours:Math.round(a.hours*100)/100},days:[...n.values()].sort((S,x)=>S.day.localeCompare(x.day)),origins:[...r.values()].map(S=>({...S,hours:Math.round(S.hours*100)/100})).sort((S,x)=>x.runs-S.runs),causes:[...o.values()].sort((S,x)=>x.count-S.count),jobs:i.sort((S,x)=>x.hours-S.hours),threads:l.sort((S,x)=>x.lastAt-x.firstAt-(S.lastAt-S.firstAt)||x.runs-S.runs),rotations:{total:c,byReason:[...s.entries()].map(([S,x])=>({reason:S,count:x})).sort((S,x)=>x.count-S.count),tokenSum:p,tokenSamples:u,maxTokens:f},retention:{traces:h,tracesWithSteps:y}}}async function Ir(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 $r(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?day=${encodeURIComponent(e.day)}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/day"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return Vl(s,e.day)}function Vl(t,e){let a={runs:0,errors:0,ms:0,inputTokens:0,outputTokens:0},n=new Map,r=new Map,o=[];for(let{node:s,data:i}of t)if(i){a.runs+=i.totals.runs,a.errors+=i.totals.errors,a.ms+=i.totals.ms,a.inputTokens+=i.totals.inputTokens,a.outputTokens+=i.totals.outputTokens;for(let l of i.origins){let c=n.get(l.channel)||{channel:l.channel,runs:0,errors:0,ms:0};c.runs+=l.runs,c.errors+=l.errors,c.ms+=l.ms,n.set(l.channel,c)}for(let l of i.causes)r.set(l.cause,(r.get(l.cause)||0)+l.count);for(let l of i.conversations)o.push({...l,node:s.name,nodeUrl:s.url})}return{day:e,nodes:t.map(s=>({name:s.node.name,url:s.node.url,ok:!!s.data,error:s.error,runs:s.data?.totals.runs||0})),totals:a,origins:[...n.values()].sort((s,i)=>i.runs-s.runs),causes:[...r.entries()].map(([s,i])=>({cause:s,count:i})).sort((s,i)=>i.count-s.count),conversations:o.sort((s,i)=>i.ms-s.ms||i.turns-s.turns)}}function Lr(t={}){let e=`
11494
+ </script>`;async function Nr(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?days=${e.days}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/mesh"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return Ec(s,e.days)}function Ec(t,e){let a={runs:0,errors:0,hours:0,agents:0,threads:0},n=new Map,r=new Map,o=new Map,s=new Map,i=[],l=[],c=0,p=0,u=0,f=0,h=0,v=0;for(let{node:E,data:g}of t)if(g){a.runs+=g.totals.runs,a.errors+=g.totals.errors,a.hours+=g.totals.hours,a.agents+=g.totals.agents,a.threads+=g.totals.threads;for(let d of g.days){let m=n.get(d.day)||{day:d.day,cron:[0,0],workflow:[0,0],direct:[0,0]};for(let x of["cron","workflow","direct"])m[x][0]+=d[x]?.[0]||0,m[x][1]+=d[x]?.[1]||0;n.set(d.day,m)}for(let d of g.origins){let m=r.get(d.channel)||{channel:d.channel,runs:0,errors:0,hours:0};m.runs+=d.runs,m.errors+=d.errors,m.hours+=d.hours,r.set(d.channel,m)}for(let d of g.causes){let m=o.get(d.cause)||{cause:d.cause,count:0,agents:[],example:""};m.count+=d.count;for(let x of d.agents)m.agents.includes(x)||m.agents.push(x);m.example||(m.example=d.example),o.set(d.cause,m)}for(let d of g.rotations.byReason)s.set(d.reason,(s.get(d.reason)||0)+d.count);c+=g.rotations.total,p+=g.rotations.tokenSum||0,u+=g.rotations.tokenSamples||0,f=Math.max(f,g.rotations.maxTokens),h+=g.retention.traces,v+=g.retention.tracesWithSteps;for(let d of g.jobs)i.push({...d,node:E.name,nodeUrl:E.url});for(let d of g.threads)l.push({...d,node:E.name,nodeUrl:E.url})}let T=t.filter(E=>E.data).map(E=>E.data.since).filter(E=>Number.isFinite(E));return{generatedAt:Date.now(),windowDays:e,since:T.length?Math.min(...T):Date.now()-e*864e5,nodes:t.map(E=>({name:E.node.name,url:E.node.url,ok:!!E.data,error:E.error,runs:E.data?.totals.runs||0})),totals:{...a,hours:Math.round(a.hours*100)/100},days:[...n.values()].sort((E,g)=>E.day.localeCompare(g.day)),origins:[...r.values()].map(E=>({...E,hours:Math.round(E.hours*100)/100})).sort((E,g)=>g.runs-E.runs),causes:[...o.values()].sort((E,g)=>g.count-E.count),jobs:i.sort((E,g)=>g.hours-E.hours),threads:l.sort((E,g)=>g.lastAt-g.firstAt-(E.lastAt-E.firstAt)||g.runs-E.runs),rotations:{total:c,byReason:[...s.entries()].map(([E,g])=>({reason:E,count:g})).sort((E,g)=>g.count-E.count),tokenSum:p,tokenSamples:u,maxTokens:f},retention:{traces:h,tracesWithSteps:v}}}async function Dr(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 Hr(t,e,a=6e3){let n=new AbortController,r=setTimeout(()=>n.abort(),a),o=`?day=${encodeURIComponent(e.day)}&tzOffset=${e.tzOffsetMinutes}&limit=${e.limit}`,s;try{s=await Promise.all(t.map(async i=>{let l={Accept:"application/json"};i.token&&(l.Authorization=`Bearer ${i.token}`);try{let c=await fetch(i.url+"/analytics/day"+o,{headers:l,signal:n.signal});return c.ok?{node:i,data:await c.json()}:{node:i,error:`HTTP ${c.status}`}}catch(c){return{node:i,error:c?.name==="AbortError"?"timeout":c?.message||"unreachable"}}}))}finally{clearTimeout(r)}return Sc(s,e.day)}function Sc(t,e){let a={runs:0,errors:0,ms:0,inputTokens:0,outputTokens:0},n=new Map,r=new Map,o=[];for(let{node:s,data:i}of t)if(i){a.runs+=i.totals.runs,a.errors+=i.totals.errors,a.ms+=i.totals.ms,a.inputTokens+=i.totals.inputTokens,a.outputTokens+=i.totals.outputTokens;for(let l of i.origins){let c=n.get(l.channel)||{channel:l.channel,runs:0,errors:0,ms:0};c.runs+=l.runs,c.errors+=l.errors,c.ms+=l.ms,n.set(l.channel,c)}for(let l of i.causes)r.set(l.cause,(r.get(l.cause)||0)+l.count);for(let l of i.conversations)o.push({...l,node:s.name,nodeUrl:s.url})}return{day:e,nodes:t.map(s=>({name:s.node.name,url:s.node.url,ok:!!s.data,error:s.error,runs:s.data?.totals.runs||0})),totals:a,origins:[...n.values()].sort((s,i)=>i.runs-s.runs),causes:[...r.entries()].map(([s,i])=>({cause:s,count:i})).sort((s,i)=>i.count-s.count),conversations:o.sort((s,i)=>i.ms-s.ms||i.turns-s.turns)}}function Br(t={}){let e=`
11495
11495
  <select id="boardPicker" title="Switch board"></select>
11496
11496
  <div class="search">
11497
11497
  <span class="icon">\u2315</span>
@@ -11592,7 +11592,7 @@ window.MXD=(function(){
11592
11592
  </footer>
11593
11593
  </div>
11594
11594
  </div>
11595
- <script src="/sortable.min.js"></script>`;return $({title:"AgentX \xB7 Boards",activeTab:"boards",subtitle:"Boards",subheader:e,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a,css:Yl,scripts:`<script>${Ql}</script>`,headExtras:`<script>
11595
+ <script src="/sortable.min.js"></script>`;return L({title:"AgentX \xB7 Boards",activeTab:"boards",subtitle:"Boards",subheader:e,peers:t.peers,currentPeerId:t.currentPeerId,noMain:!0,body:a,css:Tc,scripts:`<script>${Ac}</script>`,headExtras:`<script>
11596
11596
  // The boards page has its own connection dot + wants body height:100%
11597
11597
  // for the full-viewport kanban layout. Inject the dot into the topbar
11598
11598
  // and override body height at runtime so the shared shell doesn't
@@ -11608,7 +11608,7 @@ window.MXD=(function(){
11608
11608
  right.insertBefore(dot, right.firstChild);
11609
11609
  }
11610
11610
  });
11611
- </script>`})}var Yl=`
11611
+ </script>`})}var Tc=`
11612
11612
  /* Kanban subheader \u2014 replaces the legacy toolbar that used to live in <header>. */
11613
11613
  .ax-subheader select, .ax-subheader input, .ax-subheader button {
11614
11614
  background: var(--col); color: var(--text); border: 1px solid var(--border);
@@ -11861,7 +11861,7 @@ header a.link:hover { color: var(--accent); border-color: var(--accent); }
11861
11861
  .draft-box .draft-row .hint { color: var(--muted); font-size: 12px; flex: 1; }
11862
11862
  .draft-box .draft-row .hint.err { color: var(--red); }
11863
11863
  .draft-box .draft-row .hint.ok { color: var(--green); }
11864
- `,Ql=`
11864
+ `,Ac=`
11865
11865
  'use strict';
11866
11866
  const state = {
11867
11867
  boards: [], current: null, items: {},
@@ -12914,9 +12914,9 @@ function appendEvents(events) {
12914
12914
  }
12915
12915
 
12916
12916
  loadBoards().catch(e => toast('Init failed: ' + e.message));
12917
- `;function Rr(t={}){let a=`<h1>Plain-English glossary</h1>
12917
+ `;function zr(t={}){let a=`<h1>Plain-English glossary</h1>
12918
12918
  <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>
12919
- ${vr.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 $({title:`${we.brand} \xB7 Glossary`,activeTab:"glossary",subtitle:"Glossary",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Zl})}var Zl=`
12919
+ ${Tr.map(n=>{let r=n.alias?`<span class="alias" title="Schema key">${j(n.alias)}</span>`:"";return`<article class="term"><h3>${j(n.term)}${r}</h3><p>${j(n.definition)}</p></article>`}).join("")}`;return L({title:`${ke.brand} \xB7 Glossary`,activeTab:"glossary",subtitle:"Glossary",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Cc})}var Cc=`
12920
12920
  main { max-width: 760px; margin: 0 auto; padding: 32px 24px 80px; }
12921
12921
  h1 { font-size: 22px; margin: 0 0 6px; font-weight: 600; letter-spacing: -0.01em; }
12922
12922
  .lead {
@@ -12946,7 +12946,7 @@ article.term .alias {
12946
12946
  }
12947
12947
  article.term p {
12948
12948
  margin: 0; color: var(--ax-text-2); font-size: 13px; line-height: 1.6;
12949
- }`;function jr(t={}){let e=`<div class="ax-wf__root">
12949
+ }`;function Fr(t={}){let e=`<div class="ax-wf__root">
12950
12950
  <aside class="ax-wf__list">
12951
12951
  <header>
12952
12952
  <h2>Workflows</h2>
@@ -13023,7 +13023,7 @@ article.term p {
13023
13023
  </aside>
13024
13024
  </div>
13025
13025
 
13026
- <div id="wf-toast" class="ax-wf__toast" hidden></div>`;return $({title:"AgentX \xB7 Workflows",activeTab:"workflows",subtitle:"Workflows",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:ec,scripts:`<script>${te({workflowHealth:xa})}${tc}</script>`})}var ec=`
13026
+ <div id="wf-toast" class="ax-wf__toast" hidden></div>`;return L({title:"AgentX \xB7 Workflows",activeTab:"workflows",subtitle:"Workflows",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Mc,scripts:`<script>${V({workflowHealth:Ea})}${Ic}</script>`})}var Mc=`
13027
13027
  .ax-wf__root {
13028
13028
  display: grid;
13029
13029
  grid-template-columns: 340px 1fr;
@@ -13407,7 +13407,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
13407
13407
  font-size: 12px; z-index: 50;
13408
13408
  }
13409
13409
  .hint { color: var(--ax-muted); font-size: 11px; }
13410
- `,tc=`
13410
+ `,Ic=`
13411
13411
  (() => {
13412
13412
  const $ = (sel) => document.querySelector(sel)
13413
13413
  const $$ = (sel) => Array.from(document.querySelectorAll(sel))
@@ -14196,7 +14196,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14196
14196
  setInterval(refresh, 15000)
14197
14197
  })
14198
14198
  })();
14199
- `;function Pr(t={}){let e=`<div class="ax-proc__root">
14199
+ `;function qr(t={}){let e=`<div class="ax-proc__root">
14200
14200
  <header class="ax-proc__header">
14201
14201
  <h1>Procedures</h1>
14202
14202
  <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>
@@ -14240,7 +14240,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14240
14240
  <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>
14241
14241
  <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>
14242
14242
  </section>
14243
- </div>`;return $({title:"AgentX \xB7 Procedures",activeTab:"procedures",subtitle:"Procedures",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:ac,scripts:`<script>${nc}</script>`})}var ac=`
14243
+ </div>`;return L({title:"AgentX \xB7 Procedures",activeTab:"procedures",subtitle:"Procedures",peers:t.peers,currentPeerId:t.currentPeerId,body:e,css:Lc,scripts:`<script>${$c}</script>`})}var Lc=`
14244
14244
  .ax-proc__root { padding: 18px 24px 40px; max-width: 1100px; margin: 0 auto; color: var(--ax-text); }
14245
14245
  .ax-proc__header h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
14246
14246
  .ax-proc__header .hint { color: var(--ax-muted); font-size: 12px; margin: 0 0 18px; }
@@ -14266,7 +14266,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14266
14266
  .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); }
14267
14267
  .ax-proc__link { color: var(--ax-accent, #6366f1); text-decoration: none; font-size: 11px; }
14268
14268
  .ax-proc__link:hover { text-decoration: underline; }
14269
- `,nc=`
14269
+ `,$c=`
14270
14270
  (function(){
14271
14271
  function $(sel){ return document.querySelector(sel) }
14272
14272
  function esc(s){ return String(s||"").replace(/[&<>"']/g, function(c){ return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c] }) }
@@ -14366,24 +14366,24 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14366
14366
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bootAll)
14367
14367
  else bootAll()
14368
14368
  })();
14369
- `;function Or(t){let e=t.agentName||t.agentId,a=`<div class="ax-task-page"
14370
- data-task-id="${P(t.taskId)}"
14371
- data-agent-id="${P(t.agentId)}"
14372
- data-node-url="${P(t.nodeUrl)}"
14369
+ `;function Ur(t){let e=t.agentName||t.agentId,a=`<div class="ax-task-page"
14370
+ data-task-id="${j(t.taskId)}"
14371
+ data-agent-id="${j(t.agentId)}"
14372
+ data-node-url="${j(t.nodeUrl)}"
14373
14373
  data-archived="${t.archived?"1":""}"
14374
- data-ask="${P(t.ask||"")}"
14375
- data-ask-at="${P(t.askAt||"")}">
14374
+ data-ask="${j(t.ask||"")}"
14375
+ data-ask-at="${j(t.askAt||"")}">
14376
14376
 
14377
14377
  <header class="ax-task-page__head">
14378
14378
  <nav class="ax-crumbs" aria-label="Breadcrumb">
14379
14379
  <a href="/live">Live</a>
14380
14380
  <span class="ax-crumbs__sep">/</span>
14381
- <a href="/agents/${P(t.agentId)}/history?node=${encodeURIComponent(t.nodeUrl)}&name=${encodeURIComponent(e)}"><span class="ax-mention">@${P(t.agentId)}</span></a>
14381
+ <a href="/agents/${j(t.agentId)}/history?node=${encodeURIComponent(t.nodeUrl)}&name=${encodeURIComponent(e)}"><span class="ax-mention">@${j(t.agentId)}</span></a>
14382
14382
  <span class="ax-crumbs__sep">/</span>
14383
14383
  <span class="ax-crumbs__here">Task</span>
14384
14384
  </nav>
14385
14385
  <div class="ax-task-page__meta">
14386
- ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${P(t.channel)}</span>`:""}
14386
+ ${t.channel?`<span class="ax-badge ax-badge--mono ax-badge--ghost">${j(t.channel)}</span>`:""}
14387
14387
  <span class="ax-badge ax-badge--mono" id="task-status">connecting\u2026</span>
14388
14388
  <span class="ax-mono ax-muted" id="task-elapsed"></span>
14389
14389
  </div>
@@ -14409,7 +14409,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14409
14409
  <button type="button" id="task-send" class="ax-btn ax-btn--primary">send \u2192</button>
14410
14410
  </div>
14411
14411
  </footer>
14412
- </div>`;return $({title:`AgentX \xB7 ${e}`,activeTab:"live",subtitle:"Task",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:rc,scripts:`<script>${oc}</script>`})}var rc=`
14412
+ </div>`;return L({title:`AgentX \xB7 ${e}`,activeTab:"live",subtitle:"Task",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:Rc,scripts:`<script>${Pc}</script>`})}var Rc=`
14413
14413
  /* The shell gives <main> no padding, so page content butted straight against
14414
14414
  the sticky topbar. Breathe. */
14415
14415
  .ax-task-page {
@@ -14551,7 +14551,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14551
14551
  line-height: 1.55; text-wrap: pretty; white-space: pre-wrap; word-break: break-word;
14552
14552
  }
14553
14553
 
14554
- `,oc=`
14554
+ `,Pc=`
14555
14555
  (function () {
14556
14556
  var root = document.querySelector('.ax-task-page');
14557
14557
  if (!root) return;
@@ -14936,15 +14936,15 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14936
14936
  });
14937
14937
 
14938
14938
  })();
14939
- `;function Nr(t){let e=t.agentName||t.agentId,a=`<div class="ax-history"
14940
- data-agent-id="${P(t.agentId)}"
14941
- data-agent-name="${P(e)}"
14942
- data-node-url="${P(t.nodeUrl)}">
14939
+ `;function Wr(t){let e=t.agentName||t.agentId,a=`<div class="ax-history"
14940
+ data-agent-id="${j(t.agentId)}"
14941
+ data-agent-name="${j(e)}"
14942
+ data-node-url="${j(t.nodeUrl)}">
14943
14943
  <header class="ax-history__head">
14944
14944
  <nav class="ax-crumbs" aria-label="Breadcrumb">
14945
14945
  <a href="/live">Live</a>
14946
14946
  <span class="ax-crumbs__sep">/</span>
14947
- <span class="ax-mention">@${P(t.agentId)}</span>
14947
+ <span class="ax-mention">@${j(t.agentId)}</span>
14948
14948
  <span class="ax-crumbs__sep">/</span>
14949
14949
  <span class="ax-crumbs__here">History</span>
14950
14950
  </nav>
@@ -14965,7 +14965,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
14965
14965
  <div class="ax-history__list" id="hist-list">
14966
14966
  <div class="ax-history__empty">loading\u2026</div>
14967
14967
  </div>
14968
- </div>`;return $({title:`AgentX \xB7 ${e} history`,activeTab:"live",subtitle:"History",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:sc,scripts:`<script>${ic}</script>`})}var sc=`
14968
+ </div>`;return L({title:`AgentX \xB7 ${e} history`,activeTab:"live",subtitle:"History",peers:t.peers,currentPeerId:t.currentPeerId,body:a,css:jc,scripts:`<script>${Oc}</script>`})}var jc=`
14969
14969
  /* <main> carries no padding in the shell \u2014 without this the breadcrumb sits
14970
14970
  flush against the sticky topbar. */
14971
14971
  .ax-history {
@@ -15017,7 +15017,7 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15017
15017
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
15018
15018
  }
15019
15019
  .ax-history__foot { margin-top: 6px; font-size: var(--ax-fs-xs); color: var(--ax-muted); font-family: var(--ax-mono); }
15020
- `,ic=`
15020
+ `,Oc=`
15021
15021
  (function () {
15022
15022
  var root = document.querySelector('.ax-history');
15023
15023
  if (!root) return;
@@ -15117,24 +15117,26 @@ details.ax-wf__panel pre { margin: 0; padding: 10px 14px; }
15117
15117
  listEl.innerHTML = '<div class="ax-history__empty" style="color:var(--ax-err)">' + esc(e.message) + '</div>';
15118
15118
  });
15119
15119
  })();
15120
- `;function Hr(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"])?L(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 Ie(t,e,l=>Dr(e,a,l,{mode:"create",convertFromYaml:i}))}}if(n.startsWith("/api/workflows/runs"))return r==="GET"&&!a.requireScope(t,e,["dashboard:read"])?!0:cc(t,e,a,n);if(n.startsWith("/api/workflows/signal/")){if(r!=="POST")return L(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;if(!a.dispatcher)return L(e,501,{error:"dispatcher not enabled"});let s=decodeURIComponent(n.replace(/^\/api\/workflows\/signal\//,"").split("?")[0]);return s?Ie(t,e,i=>{let l=i,c=a.dispatcher.emitSignal({name:s,scope:l?.scope,workflowId:l?.workflowId,payload:l?.payload});return L(e,200,{ok:!0,emission:c})}):L(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"])?L(e,200,{layout:a.layouts.get(s)}):!0;if(r==="PUT")return a.requireScope(t,e,["dashboard:write"])?Ie(t,e,l=>{try{let c=a.layouts.save(s,l);return L(e,200,{layout:c})}catch(c){return L(e,400,{error:"invalid layout",message:c.message})}}):!0}if(i==="/validate"&&r==="POST")return a.requireScope(t,e,["dashboard:read"])?Ie(t,e,l=>{let c=wt.safeParse(l);if(!c.success)return L(e,200,{ok:!1,issues:c.error.issues.map(u=>({path:u.path.join("."),message:u.message}))});let p=kt(c.data).map(u=>({path:"",message:u}));return L(e,200,{ok:p.length===0,issues:p,workflow:c.data})}):!0;if(!i){if(r==="GET"){if(!a.requireScope(t,e,["dashboard:read"]))return!0;let l=a.store.get(s);return l?L(e,200,{workflow:l}):L(e,404,{error:"workflow not found"})}if(r==="PUT"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=new URL(n,"http://_").searchParams,c=l.get("convertFromYaml")==="true"||l.get("convertFromYaml")==="1";return Ie(t,e,p=>Dr(e,a,p,{mode:"update",id:s,convertFromYaml:c}))}if(r==="DELETE"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=a.store.delete(s);return a.layouts.delete(s),L(e,l?200:404,l?{ok:!0}:{error:"workflow not found"})}}}return L(e,404,{error:"unknown workflows endpoint",path:n})}var lc=["mesh"];function Dr(t,e,a,n){let r=wt.safeParse(a);if(!r.success)return L(t,400,{error:"invalid workflow",issues:r.error.issues.map(l=>({path:l.path.join("."),message:l.message}))});let o=r.data,s=kt(o);if(s.length>0)return L(t,400,{error:"lint errors",issues:s.map(l=>({path:"",message:l}))});if(n.mode==="update"&&o.id!==n.id)return L(t,400,{error:"workflow id does not match path"});if(n.mode==="create"&&e.store.get(o.id))return L(t,409,{error:`workflow "${o.id}" already exists`});if(n.mode==="update"&&a&&typeof a=="object"){let l=a,c=e.store.get(n.id);if(c)for(let p of lc)!(p in l)&&p in c&&(o[p]=c[p])}let i;try{i=e.store.save(o,{convertFromYaml:n.convertFromYaml})}catch(l){let c=l?.message||String(l),p=l?.yamlPath,u=!!p||/yaml round-trip failed/.test(c);return L(t,u?409:500,{error:u?"couldn't preserve comments while saving back to the YAML file. Re-submit with ?convertFromYaml=true to convert this workflow to JSON (comments will be lost).":c,kind:u?"yaml-authored":"save-failed",...p?{path:p}:{}})}return e.layouts.sync(i.id,i.nodes.map(l=>l.id)),L(t,200,{workflow:i})}function cc(t,e,a,n){let r=new URL(n,"http://_").searchParams,o=n.replace(/^\/api\/workflows\/runs/,"");if(o===""||o.startsWith("?")){let l=Math.max(1,Math.min(500,Number(r.get("limit")||50))),c=r.get("workflowId")||void 0,p=r.get("summary")==="1"||r.get("summary")==="true",u=a.runs.list({workflowId:c,limit:l});if(!p)return L(e,200,{runs:u});let f=u.map(h=>({id:h.id,workflowId:h.workflowId,workflowVersion:h.workflowVersion,homeNode:h.homeNode,status:h.status,pending:h.pending,entityRef:h.entityRef,history:(h.history||[]).slice(-5),parentRunId:h.parentRunId,parentNodeId:h.parentNodeId,rootRunId:h.rootRunId,depth:h.depth,createdAt:h.createdAt,updatedAt:h.updatedAt}));return L(e,200,{runs:f})}let s=o.match(/^\/([^\/?]+)\/status$/);if(s){if((t.method||"GET").toUpperCase()!=="POST")return L(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=decodeURIComponent(s[1]);return Ie(t,e,c=>{let p=c?.status;return p!=="paused"&&p!=="running"&&p!=="canceled"?L(e,400,{error:"status must be paused|running|canceled"}):a.runs.setStatus(l,p)?L(e,200,{ok:!0,runId:l,status:p}):L(e,404,{error:"run not found"})})}let i=o.match(/^\/([^\/?]+)(\/stream)?$/);if(i){let l=decodeURIComponent(i[1]);if(i[2])return dc(t,e,a,l);let c=a.runs.get(l);return c?L(e,200,{run:c}):L(e,404,{error:"run not found"})}return L(e,404,{error:"unknown runs endpoint"})}function dc(t,e,a,n){let r=a.runs.get(n);if(!r)return L(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)}
15120
+ `;function Xr(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"])?$(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=>Gr(e,a,l,{mode:"create",convertFromYaml:i}))}}if(n.startsWith("/api/workflows/runs"))return r==="GET"&&!a.requireScope(t,e,["dashboard:read"])?!0:Dc(t,e,a,n);if(n.startsWith("/api/workflows/signal/")){if(r!=="POST")return $(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;if(!a.dispatcher)return $(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,c=a.dispatcher.emitSignal({name:s,scope:l?.scope,workflowId:l?.workflowId,payload:l?.payload});return $(e,200,{ok:!0,emission:c})}):$(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"])?$(e,200,{layout:a.layouts.get(s)}):!0;if(r==="PUT")return a.requireScope(t,e,["dashboard:write"])?Re(t,e,l=>{try{let c=a.layouts.save(s,l);return $(e,200,{layout:c})}catch(c){return $(e,400,{error:"invalid layout",message:c.message})}}):!0}if(i==="/validate"&&r==="POST")return a.requireScope(t,e,["dashboard:read"])?Re(t,e,l=>{let c=_t.safeParse(l);if(!c.success)return $(e,200,{ok:!1,issues:c.error.issues.map(u=>({path:u.path.join("."),message:u.message}))});let p=Et(c.data).map(u=>({path:"",message:u}));return $(e,200,{ok:p.length===0,issues:p,workflow:c.data})}):!0;if(!i){if(r==="GET"){if(!a.requireScope(t,e,["dashboard:read"]))return!0;let l=a.store.get(s);return l?$(e,200,{workflow:l}):$(e,404,{error:"workflow not found"})}if(r==="PUT"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=new URL(n,"http://_").searchParams,c=l.get("convertFromYaml")==="true"||l.get("convertFromYaml")==="1";return Re(t,e,p=>Gr(e,a,p,{mode:"update",id:s,convertFromYaml:c}))}if(r==="DELETE"){if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=a.store.delete(s);return a.layouts.delete(s),$(e,l?200:404,l?{ok:!0}:{error:"workflow not found"})}}}return $(e,404,{error:"unknown workflows endpoint",path:n})}var Nc=["mesh"];function Gr(t,e,a,n){let r=_t.safeParse(a);if(!r.success)return $(t,400,{error:"invalid workflow",issues:r.error.issues.map(l=>({path:l.path.join("."),message:l.message}))});let o=r.data,s=Et(o);if(s.length>0)return $(t,400,{error:"lint errors",issues:s.map(l=>({path:"",message:l}))});if(n.mode==="update"&&o.id!==n.id)return $(t,400,{error:"workflow id does not match path"});if(n.mode==="create"&&e.store.get(o.id))return $(t,409,{error:`workflow "${o.id}" already exists`});if(n.mode==="update"&&a&&typeof a=="object"){let l=a,c=e.store.get(n.id);if(c)for(let p of Nc)!(p in l)&&p in c&&(o[p]=c[p])}let i;try{i=e.store.save(o,{convertFromYaml:n.convertFromYaml})}catch(l){let c=l?.message||String(l),p=l?.yamlPath,u=!!p||/yaml round-trip failed/.test(c);return $(t,u?409:500,{error:u?"couldn't preserve comments while saving back to the YAML file. Re-submit with ?convertFromYaml=true to convert this workflow to JSON (comments will be lost).":c,kind:u?"yaml-authored":"save-failed",...p?{path:p}:{}})}return e.layouts.sync(i.id,i.nodes.map(l=>l.id)),$(t,200,{workflow:i})}function Dc(t,e,a,n){let r=new URL(n,"http://_").searchParams,o=n.replace(/^\/api\/workflows\/runs/,"");if(o===""||o.startsWith("?")){let l=Math.max(1,Math.min(500,Number(r.get("limit")||50))),c=r.get("workflowId")||void 0,p=r.get("summary")==="1"||r.get("summary")==="true",u=a.runs.list({workflowId:c,limit:l});if(!p)return $(e,200,{runs:u});let f=u.map(h=>({id:h.id,workflowId:h.workflowId,workflowVersion:h.workflowVersion,homeNode:h.homeNode,status:h.status,pending:h.pending,entityRef:h.entityRef,history:(h.history||[]).slice(-5),parentRunId:h.parentRunId,parentNodeId:h.parentNodeId,rootRunId:h.rootRunId,depth:h.depth,createdAt:h.createdAt,updatedAt:h.updatedAt}));return $(e,200,{runs:f})}let s=o.match(/^\/([^\/?]+)\/status$/);if(s){if((t.method||"GET").toUpperCase()!=="POST")return $(e,405,{error:"method not allowed"});if(!a.requireScope(t,e,["dashboard:write"]))return!0;let l=decodeURIComponent(s[1]);return Re(t,e,c=>{let p=c?.status;return p!=="paused"&&p!=="running"&&p!=="canceled"?$(e,400,{error:"status must be paused|running|canceled"}):a.runs.setStatus(l,p)?$(e,200,{ok:!0,runId:l,status:p}):$(e,404,{error:"run not found"})})}let i=o.match(/^\/([^\/?]+)(\/stream)?$/);if(i){let l=decodeURIComponent(i[1]);if(i[2])return Hc(t,e,a,l);let c=a.runs.get(l);return c?$(e,200,{run:c}):$(e,404,{error:"run not found"})}return $(e,404,{error:"unknown runs endpoint"})}function Hc(t,e,a,n){let r=a.runs.get(n);if(!r)return $(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)}
15121
15121
 
15122
15122
  `);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)}
15123
15123
 
15124
- `)}catch{s()}},l=a.runEvents?.subscribe(n,i),c=r.updatedAt,p=setInterval(()=>{if(o)return;let u=a.runs.get(n);u&&u.updatedAt!==c&&(c=u.updatedAt,i(u))},2e3);return!0}function Ie(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){L(e,400,{error:"invalid JSON body",message:s.message});return}let o;try{o=a(r)}catch(s){try{L(e,500,{error:"handler threw (sync)",message:s?.message??String(s)})}catch{}return}Promise.resolve(o).catch(s=>{try{L(e,500,{error:"handler threw",message:s?.message??String(s)})}catch{}})}),t.on("error",r=>L(e,400,{error:"body read failed",message:r.message})),!0}function L(t,e,a){return t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a)),!0}import{readFileSync as Kc}from"fs";import{createRequire as Jc}from"module";import{deflateSync as pc}from"zlib";var uc=[41,121,255],mc=[255,255,255],Br=new Map;function Gt(t){let e=Br.get(t);return e||(e=hc(t,fc(t)),Br.set(t,e)),e}function fc(t){let e=1+t*3,a=Buffer.alloc(e*t),n=t/2,r=t*.22;for(let o=0;o<t;o++)for(let s=0;s<t;s++){let i=s+.5-n,l=o+.5-n,c=i*i+l*l<=r*r?mc:uc;a.set(c,o*e+1+s*3)}return a}function hc(t,e){let a=Buffer.alloc(13);return a.writeUInt32BE(t,0),a.writeUInt32BE(t,4),a[8]=8,a[9]=2,Buffer.concat([Buffer.from([137,80,78,71,13,10,26,10]),Wt("IHDR",a),Wt("IDAT",pc(e)),Wt("IEND",Buffer.alloc(0))])}function Wt(t,e){let a=Buffer.alloc(4);a.writeUInt32BE(e.length);let n=Buffer.concat([Buffer.from(t,"ascii"),e]),r=Buffer.alloc(4);return r.writeUInt32BE(xc(n)),Buffer.concat([a,n,r])}var gc=Array.from({length:256},(t,e)=>{let a=e;for(let n=0;n<8;n++)a=a&1?3988292384^a>>>1:a>>>1;return a>>>0});function xc(t){let e=4294967295;for(let a of t)e=gc[(e^a)&255]^e>>>8;return(e^4294967295)>>>0}function dt(t,e=160){if(!t)return t;let a=t.replace(/\s+/g," ").trim();return a.length>e?a.slice(0,e-1)+"\u2026":a}function vc(t){let e=new Map;for(let n of t.cronRuns??[]){let r=e.get(n.jobId);(!r||r.startedAt<n.startedAt)&&e.set(n.jobId,n)}let a={success:0,failed:0};for(let n of t.cronRuns??[])n.status==="success"?a.success++:a.failed++;return{id:t.id,name:t.name,url:t.url,reachable:t.reachable,error:dt(t.error),uptimeSec:t.uptimeSec,inflight:t.inflight,restart:t.restart?.state&&t.restart.state!=="none"?t.restart:void 0,agents:t.agents.map(n=>({id:n.id,name:n.name,tier:n.tier,active:n.active,errors:n.errors,lastActive:n.lastActive,last:n.lastSummary?{text:dt(n.lastSummary.text),at:n.lastSummary.at,ok:n.lastSummary.ok}:void 0})),crons:{today:a,items:(t.crons??[]).map(n=>{let r=e.get(n.id);return{id:n.id,enabled:n.enabled,schedule:n.schedule,agent:n.agent,nextRun:n.nextRun,consecutiveErrors:n.consecutiveErrors,last:r?{status:r.status,at:r.startedAt,text:dt(r.status==="success"?r.responseSummary:r.errorSummary)}:void 0}})}}}function bc(t){let e=[];for(let a of t)for(let n of a.agents)for(let r of n.runningTasks??[])e.push({node:a.url,nodeName:a.name,agentId:n.id,agentName:n.name,taskId:r.id,preview:dt(r.messagePreview),channel:r.channel,startedAt:r.startedAt});return e.sort((a,n)=>a.startedAt<n.startedAt?1:-1)}var yc=/^\/api\/app\/tasks\/(cancel|followup)$/;async function zr(t,e,a,n,r,o){let s=new URL(t.url||a,"http://localhost");if(n==="GET"&&(a==="/api/app/fleet"||a==="/api/app/activity")){let h=wc(s.searchParams.get("timezone")),y=await o.snapshot({date:kc(h),timezone:h});return a==="/api/app/activity"?ie(e,200,{ts:y.ts,tasks:bc(y.nodes)}):ie(e,200,{ts:y.ts,nodes:y.nodes.map(vc)})}if(n==="GET"&&a==="/api/app/approvals")return ie(e,200,{nodes:await o.approvals()});if(n!=="POST")return!1;let i=a.match(yc);if(!(i||["/api/app/nodes/restart","/api/app/nodes/reload","/api/app/crons/toggle","/api/app/approvals/decide"].includes(a)))return!1;let c;try{c=await ke(t)}catch(h){return ie(e,400,{error:h.message})}let p=Ne(c.node);if(!p)return ie(e,400,{error:"node is required"});let u=`operator (phone: ${r})`,f;if(i){let h=Ne(c.taskId);if(!h)return ie(e,400,{error:"taskId is required"});let y=`/api/tasks/${encodeURIComponent(h)}/${i[1]}`;if(i[1]==="cancel")f=await o.nodePost(p,y,{reason:`cancelled by ${u}`});else{let T=Ne(c.message);if(!T)return ie(e,400,{error:"message is required"});f=await o.nodePost(p,y,{message:T,sender:u})}}else if(a==="/api/app/nodes/restart")f=await o.nodePost(p,c.cancel===!0?"/daemon/restart/cancel":"/daemon/restart",{});else if(a==="/api/app/nodes/reload")f=await o.nodePost(p,"/reload",{});else if(a==="/api/app/crons/toggle"){let h=Ne(c.cronId);if(!h||typeof c.enabled!="boolean")return ie(e,400,{error:"cronId and enabled (true or false) are required"});f=await o.nodePost(p,`/crons/${encodeURIComponent(h)}/enabled`,{enabled:c.enabled})}else{let h=Ne(c.key),y=c.action;if(!h||y!=="yes"&&y!=="no"&&y!=="later")return ie(e,400,{error:"key and action (yes, no or later) are required"});f=await o.decide(p,h,y,u)}return ie(e,f.status,f.body)}function Ne(t){return typeof t=="string"?t.trim():""}function wc(t){if(!t)return"UTC";try{return new Intl.DateTimeFormat("en-US",{timeZone:t}),t}catch{return"UTC"}}function kc(t,e=new Date){return new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit"}).format(e)}async function ke(t,e=16*1024){let a=0,n=[];for await(let s of t){if(a+=s.length,a>e)throw new Error("body too large");n.push(s)}let r=Buffer.concat(n).toString("utf-8").trim();if(!r)return{};let o=JSON.parse(r);if(!o||typeof o!="object"||Array.isArray(o))throw new Error("expected a JSON object");return o}function ie(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var _c=2048,Fr=/^[A-Za-z0-9_-]{8,256}$/;async function Ur(t,e,a,n,r,o){if(a!=="/api/app/push"&&!a.startsWith("/api/app/push/")&&a!=="/api/app/alerts")return!1;let s=o.store(),i=s?o.publicKey():null,l=s?i?void 0:"This computer has no push keys yet. On it, run: agentx app push-keys":o.reason??"Notifications are not set up on this computer.";if(n==="GET"&&a==="/api/app/push")return le(e,200,{available:!l,reason:l??null,publicKey:i,subscriptions:s&&i?s.list(r.id).filter(h=>h.publicKey===i).length:0});if(n==="GET"&&a==="/api/app/alerts")return le(e,200,{items:s?s.recent(o.keepRecent,r.id):[]});if(n!=="POST"||a!=="/api/app/push/subscribe"&&a!=="/api/app/push/unsubscribe")return le(e,404,{error:"not found"});if(!s||l)return le(e,503,{error:l});let c;try{c=await ke(t)}catch(h){return le(e,400,{error:h.message})}let p=Ec(c.endpoint,o.allowedHosts);if(!p){let h="";try{h=new URL(String(c.endpoint)).hostname}catch{}return le(e,400,{error:`not a known push service${h?`: ${h}`:""} (see channels.push.allowedHosts)`})}if(a==="/api/app/push/unsubscribe")return le(e,200,{ok:!0,removed:s.unsubscribe(p,r.id)});let u=c.keys?.p256dh,f=c.keys?.auth;return typeof u!="string"||!Fr.test(u)||typeof f!="string"||!Fr.test(f)?le(e,400,{error:"keys.p256dh and keys.auth are required"}):c.publicKey!==void 0&&c.publicKey!==i?le(e,409,{error:"this computer's push keys changed; turn notifications on again"}):(s.subscribe({endpoint:p,p256dh:u,auth:f,deviceId:r.id,deviceName:r.name,publicKey:i}),le(e,200,{ok:!0}))}function Ec(t,e){if(typeof t!="string"||t.length>_c)return null;try{let a=new URL(t);if(a.protocol!=="https:"||a.port||a.username||a.password)return null;let n=a.hostname.toLowerCase();return e.some(o=>{let s=o.toLowerCase().replace(/^\.+|\.+$/g,"");return!!s&&(n===s||n.endsWith("."+s))})?t:null}catch{return null}}function le(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var Sc=50;function Tc(t){let e={channel:"app",chatId:t.chatId};return t.node==="local"?{path:"/task",body:{agent:t.agent,message:t.message,stream:!0,context:e}}:{path:"/mesh/task",body:{peer:t.node,agent:t.agent,message:t.message,stream:!0,context:e}}}async function qr(t,e,a,n){let{path:r,body:o}=Tc(e),s="",i=[],l=new Map,c=(p,u,f)=>{let h=ma(u,he.perMessage),{cleanText:y,ui:T}=p==="done"?ba(h.text):{cleanText:h.text,ui:void 0},S=Ac(T);return{status:p,text:y,tools:i,files:h.artifacts,...S?{ui:S}:{},...f?{error:f}:{}}};try{let p=await fetch(t.url.replace(/\/+$/,"")+r,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream",...t.token?{Authorization:`Bearer ${t.token}`}:{}},body:JSON.stringify(o),signal:a});if(!p.ok||!p.body){let u=await p.json().then(f=>f?.error).catch(()=>"");return c("error",s,u||`AgentX answered HTTP ${p.status}.`)}for await(let u of Mc(p.body)){n(u.event,u.data);let f=u.data??{};if(u.event==="text"&&typeof f.text=="string")s+=f.text;else if(u.event==="tool"&&f.status==="start"&&i.length<Sc){let h={name:String(f.name||"tool").slice(0,80),...f.arg?{arg:String(f.arg).slice(0,80)}:{}};i.push(h),f.id&&l.set(String(f.id),h)}else if(u.event==="tool"&&f.status==="result"&&f.error===!0&&l.has(String(f.id)))l.get(String(f.id)).error=!0;else{if(u.event==="done")return c("done",typeof f.content=="string"&&f.content?f.content:s);if(u.event==="error")return c("error",s,Cc(f.error))}}return a.aborted?c("stopped",s):c("error",s,"The connection to the agent closed before it answered.")}catch(p){return a.aborted?c("stopped",s):c("error",s,`Could not reach AgentX: ${p?.message||p}`)}}function Cc(t){let e=String(t||"The agent could not answer.");return e.startsWith("__queued__")?"The agent is busy with other work. Send the message again when it is free.":e.slice(0,500)}function Ac(t){if(!t)return;let e=r=>/^https?:\/\//i.test(r)&&r.length<=2048,a={},n=(t.buttons??[]).filter(r=>e(r.url)).slice(0,8).map(r=>({label:r.label.slice(0,80),url:r.url}));return n.length&&(a.buttons=n),t.poll&&(a.poll={question:t.poll.question.slice(0,300),options:t.poll.options.slice(0,10).map(r=>r.slice(0,100)),multiple:t.poll.multiple===!0}),t.media&&e(t.media.url)&&(a.media={type:t.media.type,url:t.media.url,...t.media.caption?{caption:t.media.caption.slice(0,300)}:{}}),Object.keys(a).length?a:void 0}async function*Mc(t){let e=t.getReader(),a=new TextDecoder,n="";try{for(;;){let{done:r,value:o}=await e.read();if(r)break;n+=a.decode(o,{stream:!0}).replace(/\r\n/g,`
15124
+ `)}catch{s()}},l=a.runEvents?.subscribe(n,i),c=r.updatedAt,p=setInterval(()=>{if(o)return;let u=a.runs.get(n);u&&u.updatedAt!==c&&(c=u.updatedAt,i(u))},2e3);return!0}function 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){$(e,400,{error:"invalid JSON body",message:s.message});return}let o;try{o=a(r)}catch(s){try{$(e,500,{error:"handler threw (sync)",message:s?.message??String(s)})}catch{}return}Promise.resolve(o).catch(s=>{try{$(e,500,{error:"handler threw",message:s?.message??String(s)})}catch{}})}),t.on("error",r=>$(e,400,{error:"body read failed",message:r.message})),!0}function $(t,e,a){return t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(a)),!0}import{readFileSync as Md}from"fs";import{createRequire as Id}from"module";import{deflateSync as Bc}from"zlib";var zc=[41,121,255],Fc=[255,255,255],Kr=new Map;function Kt(t){let e=Kr.get(t);return e||(e=Uc(t,qc(t)),Kr.set(t,e)),e}function qc(t){let e=1+t*3,a=Buffer.alloc(e*t),n=t/2,r=t*.22;for(let o=0;o<t;o++)for(let s=0;s<t;s++){let i=s+.5-n,l=o+.5-n,c=i*i+l*l<=r*r?Fc:zc;a.set(c,o*e+1+s*3)}return a}function Uc(t,e){let a=Buffer.alloc(13);return a.writeUInt32BE(t,0),a.writeUInt32BE(t,4),a[8]=8,a[9]=2,Buffer.concat([Buffer.from([137,80,78,71,13,10,26,10]),Xt("IHDR",a),Xt("IDAT",Bc(e)),Xt("IEND",Buffer.alloc(0))])}function Xt(t,e){let a=Buffer.alloc(4);a.writeUInt32BE(e.length);let n=Buffer.concat([Buffer.from(t,"ascii"),e]),r=Buffer.alloc(4);return r.writeUInt32BE(Gc(n)),Buffer.concat([a,n,r])}var Wc=Array.from({length:256},(t,e)=>{let a=e;for(let n=0;n<8;n++)a=a&1?3988292384^a>>>1:a>>>1;return a>>>0});function Gc(t){let e=4294967295;for(let a of t)e=Wc[(e^a)&255]^e>>>8;return(e^4294967295)>>>0}function pt(t,e=160){if(!t)return t;let a=t.replace(/\s+/g," ").trim();return a.length>e?a.slice(0,e-1)+"\u2026":a}function Xc(t){let e=new Map;for(let n of t.cronRuns??[]){let r=e.get(n.jobId);(!r||r.startedAt<n.startedAt)&&e.set(n.jobId,n)}let a={success:0,failed:0};for(let n of t.cronRuns??[])n.status==="success"?a.success++:a.failed++;return{id:t.id,name:t.name,url:t.url,reachable:t.reachable,error:pt(t.error),uptimeSec:t.uptimeSec,inflight:t.inflight,restart:t.restart?.state&&t.restart.state!=="none"?t.restart:void 0,agents:t.agents.map(n=>({id:n.id,name:n.name,tier:n.tier,active:n.active,errors:n.errors,lastActive:n.lastActive,last:n.lastSummary?{text:pt(n.lastSummary.text),at:n.lastSummary.at,ok:n.lastSummary.ok}:void 0})),crons:{today:a,items:(t.crons??[]).map(n=>{let r=e.get(n.id);return{id:n.id,enabled:n.enabled,schedule:n.schedule,agent:n.agent,nextRun:n.nextRun,consecutiveErrors:n.consecutiveErrors,last:r?{status:r.status,at:r.startedAt,text:pt(r.status==="success"?r.responseSummary:r.errorSummary)}:void 0}})}}}function Kc(t){let e=[];for(let a of t)for(let n of a.agents)for(let r of n.runningTasks??[])e.push({node:a.url,nodeName:a.name,agentId:n.id,agentName:n.name,taskId:r.id,preview:pt(r.messagePreview),channel:r.channel,startedAt:r.startedAt});return e.sort((a,n)=>a.startedAt<n.startedAt?1:-1)}var Jc=/^\/api\/app\/tasks\/(cancel|followup)$/;async function Jr(t,e,a,n,r,o){let s=new URL(t.url||a,"http://localhost");if(n==="GET"&&(a==="/api/app/fleet"||a==="/api/app/activity")){let h=Vc(s.searchParams.get("timezone")),v=await o.snapshot({date:Yc(h),timezone:h});return a==="/api/app/activity"?ce(e,200,{ts:v.ts,tasks:Kc(v.nodes)}):ce(e,200,{ts:v.ts,nodes:v.nodes.map(Xc)})}if(n==="GET"&&a==="/api/app/approvals")return ce(e,200,{nodes:await o.approvals()});if(n!=="POST")return!1;let i=a.match(Jc);if(!(i||["/api/app/nodes/restart","/api/app/nodes/reload","/api/app/crons/toggle","/api/app/approvals/decide"].includes(a)))return!1;let c;try{c=await _e(t)}catch(h){return ce(e,400,{error:h.message})}let p=He(c.node);if(!p)return ce(e,400,{error:"node is required"});let u=`operator (phone: ${r})`,f;if(i){let h=He(c.taskId);if(!h)return ce(e,400,{error:"taskId is required"});let v=`/api/tasks/${encodeURIComponent(h)}/${i[1]}`;if(i[1]==="cancel")f=await o.nodePost(p,v,{reason:`cancelled by ${u}`});else{let T=He(c.message);if(!T)return ce(e,400,{error:"message is required"});f=await o.nodePost(p,v,{message:T,sender:u})}}else if(a==="/api/app/nodes/restart")f=await o.nodePost(p,c.cancel===!0?"/daemon/restart/cancel":"/daemon/restart",{});else if(a==="/api/app/nodes/reload")f=await o.nodePost(p,"/reload",{});else if(a==="/api/app/crons/toggle"){let h=He(c.cronId);if(!h||typeof c.enabled!="boolean")return ce(e,400,{error:"cronId and enabled (true or false) are required"});f=await o.nodePost(p,`/crons/${encodeURIComponent(h)}/enabled`,{enabled:c.enabled})}else{let h=He(c.key),v=c.action;if(!h||v!=="yes"&&v!=="no"&&v!=="later")return ce(e,400,{error:"key and action (yes, no or later) are required"});f=await o.decide(p,h,v,u)}return ce(e,f.status,f.body)}function He(t){return typeof t=="string"?t.trim():""}function Vc(t){if(!t)return"UTC";try{return new Intl.DateTimeFormat("en-US",{timeZone:t}),t}catch{return"UTC"}}function Yc(t,e=new Date){return new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit"}).format(e)}async function _e(t,e=16*1024){let a=0,n=[];for await(let s of t){if(a+=s.length,a>e)throw new Error("body too large");n.push(s)}let r=Buffer.concat(n).toString("utf-8").trim();if(!r)return{};let o=JSON.parse(r);if(!o||typeof o!="object"||Array.isArray(o))throw new Error("expected a JSON object");return o}function ce(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var Qc=2048,Vr=/^[A-Za-z0-9_-]{8,256}$/;async function Yr(t,e,a,n,r,o){if(a!=="/api/app/push"&&!a.startsWith("/api/app/push/")&&a!=="/api/app/alerts")return!1;let s=o.store(),i=s?o.publicKey():null,l=s?i?void 0:"This computer has no push keys yet. On it, run: agentx app push-keys":o.reason??"Notifications are not set up on this computer.";if(n==="GET"&&a==="/api/app/push")return X(e,200,{available:!l,reason:l??null,publicKey:i,subscriptions:s&&i?s.list(r.id).filter(h=>h.publicKey===i).length:0,...s?s.prefs.all(r.id):Zc()});if(n==="GET"&&a==="/api/app/alerts")return X(e,200,{items:s?s.recent(o.keepRecent,r.id):[]});if(n!=="POST"||a!=="/api/app/push/subscribe"&&a!=="/api/app/push/unsubscribe"&&a!=="/api/app/push/prefs")return X(e,404,{error:"not found"});if(!s||l)return X(e,503,{error:l});let c;try{c=await _e(t)}catch(h){return X(e,400,{error:h.message})}if(a==="/api/app/push/prefs"){let h=Object.keys(se).filter(g=>c[se[g].field]!==void 0),v=h.map(g=>se[g].field).join(", "),T=Object.values(se).map(g=>g.field).join(" or ");if(h.length===0)return X(e,400,{error:`send ${T}, true or false`});if(h.some(g=>typeof c[se[g].field]!="boolean"))return X(e,400,{error:`${v} must be true or false`});let E={};for(let g of h)s.prefs.set(r.id,g,c[se[g].field]),E[se[g].field]=c[se[g].field];return X(e,200,{ok:!0,...E})}let p=ed(c.endpoint,o.allowedHosts);if(!p){let h="";try{h=new URL(String(c.endpoint)).hostname}catch{}return X(e,400,{error:`not a known push service${h?`: ${h}`:""} (see channels.push.allowedHosts)`})}if(a==="/api/app/push/unsubscribe")return X(e,200,{ok:!0,removed:s.unsubscribe(p,r.id)});let u=c.keys?.p256dh,f=c.keys?.auth;return typeof u!="string"||!Vr.test(u)||typeof f!="string"||!Vr.test(f)?X(e,400,{error:"keys.p256dh and keys.auth are required"}):c.publicKey!==void 0&&c.publicKey!==i?X(e,409,{error:"this computer's push keys changed; turn notifications on again"}):(s.subscribe({endpoint:p,p256dh:u,auth:f,deviceId:r.id,deviceName:r.name,publicKey:i}),X(e,200,{ok:!0}))}function Zc(){let t={};for(let e of Object.values(se))t[e.field]=e.default;return t}function ed(t,e){if(typeof t!="string"||t.length>Qc)return null;try{let a=new URL(t);if(a.protocol!=="https:"||a.port||a.username||a.password)return null;let n=a.hostname.toLowerCase();return e.some(o=>{let s=o.toLowerCase().replace(/^\.+|\.+$/g,"");return!!s&&(n===s||n.endsWith("."+s))})?t:null}catch{return null}}function X(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var Zr=50,td=280;async function eo(t,e,a,n,r,o){if(a!=="/api/app/announcements")return!1;if(n==="GET"){let s=o.prefs(),i=[],l=null;try{i=ad(await o.recent(Zr))}catch(c){l=String(c?.message||"unreachable").slice(0,200)}return Qr(e,200,{items:i,error:l,notify:s?s.on(r.id,"announce"):!1,notifyAvailable:!!s})}return Qr(e,404,{error:"not found"})}function to(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=process.env.MESH_TOKEN||q(t.dashboard,e),n=t.channels.push;return{async recent(r){let o=await fetch(`${e}/events/recent?kind=announce&limit=${r}`,{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(5e3)});if(!o.ok)throw new Error(`the daemon answered ${o.status}`);return(await o.json()).events??[]},prefs:()=>{if(!n.enabled||n.relayTo)return null;let r=Ce();return r?new Ja(r):null}}}function ad(t){let e=[];for(let a of Array.isArray(t)?t:[]){let n=a;!n||n.kind!=="announce"||typeof n.id!="string"||typeof n.at!="string"||e.push({id:n.id.slice(0,64),text:Jt(typeof n.summary=="string"?n.summary:"",td),by:typeof n.agentId=="string"?Jt(n.agentId,100):null,node:Jt(typeof n.node=="string"?n.node:"",100),at:n.at.slice(0,40)})}return e.sort((a,n)=>(Date.parse(n.at)||0)-(Date.parse(a.at)||0)),e.slice(0,Zr)}function Jt(t,e){let a=[...t];return a.length>e?a.slice(0,e-1).join("")+"\u2026":t}function Qr(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}var nd=50,ao=4,no=500;function rd(t){let e={channel:"app",chatId:t.chatId};return t.node==="local"?{path:"/task",body:{agent:t.agent,message:t.message,stream:!0,context:e}}:{path:"/mesh/task",body:{peer:t.node,agent:t.agent,message:t.message,stream:!0,context:e}}}async function ro(t,e,a,n){let{path:r,body:o}=rd(e),s="",i=!1,l=[],c=new Map,p=(u,f,h)=>{let v=u!=="done",T=i?{text:ya(f,v),artifacts:[]}:ba(f,ge.perMessage,v),{cleanText:E,ui:g}=u==="done"?Ta(T.text):{cleanText:T.text,ui:void 0},d=i?void 0:sd(g);return{status:u,text:E,tools:l,files:T.artifacts,...d?{ui:d}:{},...h?{error:h}:{}}};try{let u=await fetch(t.url.replace(/\/+$/,"")+r,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream",...t.token?{Authorization:`Bearer ${t.token}`}:{}},body:JSON.stringify(o),signal:a});if(!u.ok||!u.body){let f=await u.json().then(h=>h?.error).catch(()=>"");return p("error",s,f||`AgentX answered HTTP ${u.status}.`)}for await(let f of id(u.body)){n(f.event,f.data);let h=f.data??{};if(f.event==="start")i=h.rich===!1;else if(f.event==="text"&&typeof h.text=="string")s+=h.text;else if(f.event==="tool"&&h.status==="start"&&l.length<nd){let v={name:String(h.name||"tool").slice(0,80),...h.arg?{arg:String(h.arg).slice(0,80)}:{}};l.push(v),h.id&&c.set(String(h.id),v)}else if(f.event==="tool"&&h.status==="result"&&h.error===!0&&c.has(String(h.id)))c.get(String(h.id)).error=!0;else{if(f.event==="done")return p("done",typeof h.content=="string"&&h.content?h.content:s);if(f.event==="error")return p("error",s,od(h.error))}}return a.aborted?p("stopped",s):p("error",s,"The connection to the agent closed before it answered.")}catch(u){return a.aborted?p("stopped",s):p("error",s,`Could not reach AgentX: ${u?.message||u}`)}}function od(t){let e=String(t||"The agent could not answer.");return e.startsWith("__queued__")?"The agent is busy with other work. Send the message again when it is free.":e.slice(0,500)}function sd(t){if(!t)return;let e=s=>/^https?:\/\//i.test(s)&&s.length<=2048,a={},n=(t.buttons??[]).filter(s=>e(s.url)).slice(0,8).map(s=>({label:s.label.slice(0,80),url:s.url}));n.length&&(a.buttons=n),t.poll&&(a.poll={question:t.poll.question.slice(0,300),options:t.poll.options.slice(0,10).map(s=>s.slice(0,100)),multiple:t.poll.multiple===!0}),t.media&&e(t.media.url)&&(a.media={type:t.media.type,url:t.media.url,...t.media.caption?{caption:t.media.caption.slice(0,300)}:{}});let r=(t.quickReplies??[]).slice(0,ao).map(s=>s.slice(0,no));r.length&&(a.quickReplies=r);let o=(t.replies??[]).slice(0,ao).map(s=>({label:s.label.slice(0,80),reply:s.reply.slice(0,no)}));return o.length&&(a.replies=o),Object.keys(a).length?a:void 0}async function*id(t){let e=t.getReader(),a=new TextDecoder,n="";try{for(;;){let{done:r,value:o}=await e.read();if(r)break;n+=a.decode(o,{stream:!0}).replace(/\r\n/g,`
15125
15125
  `);let s;for(;(s=n.indexOf(`
15126
15126
 
15127
15127
  `))!==-1;){let i=n.slice(0,s);n=n.slice(s+2);let l="message",c=[];for(let p of i.split(`
15128
15128
  `))p.startsWith("event:")?l=p.slice(6).trim():p.startsWith("data:")&&c.push(p.slice(5).replace(/^ /,""));if(c.length)try{yield{event:l,data:JSON.parse(c.join(`
15129
- `))}}catch{}}}}finally{e.releaseLock()}}var pt=class{constructor(e){this.orphanLimitMs=e}ac=new AbortController;text="";tools=[];orphaned=!1;listeners=new Map;orphanTimer=null;done=!1;broadcast(e,a){e==="text"&&typeof a?.text=="string"&&(this.text+=a.text),e==="tool"&&a?.status==="start"&&this.tools.length<50&&this.tools.push({name:String(a.name||"tool"),...a.arg?{arg:String(a.arg)}:{}});for(let n of this.listeners.keys())n(e,a)}attach(e){let a=()=>!e.writableEnded&&!e.destroyed,n=(o,s)=>{a()&&e.write(`event: ${o}
15129
+ `))}}catch{}}}}finally{e.releaseLock()}}var ut=class{constructor(e){this.orphanLimitMs=e}ac=new AbortController;text="";tools=[];plain=!1;orphaned=!1;startedAt=Date.now();listeners=new Map;orphanTimer=null;done=!1;broadcast(e,a){e==="start"&&(this.plain=a?.rich===!1),e==="text"&&typeof a?.text=="string"&&(this.text+=a.text),e==="tool"&&a?.status==="start"&&this.tools.length<50&&this.tools.push({name:String(a.name||"tool"),...a.arg?{arg:String(a.arg)}:{}});for(let n of this.listeners.keys())n(e,a)}watched(){return this.listeners.size>0}attach(e){let a=()=>!e.writableEnded&&!e.destroyed,n=(o,s)=>{a()&&e.write(`event: ${o}
15130
15130
  data: ${JSON.stringify(s)}
15131
15131
 
15132
15132
  `)},r=setInterval(()=>{a()&&e.write(`: ping
15133
15133
 
15134
- `)},15e3);r.unref?.(),this.listeners.set(n,e),this.orphanTimer&&(clearTimeout(this.orphanTimer),this.orphanTimer=null),e.on("close",()=>{clearInterval(r),this.listeners.delete(n),!this.done&&!this.listeners.size&&!this.ac.signal.aborted&&!this.orphanTimer&&(this.orphanTimer=setTimeout(()=>{this.orphaned=!0,this.ac.abort()},this.orphanLimitMs),this.orphanTimer.unref?.())})}finish(){this.done=!0,this.orphanTimer&&clearTimeout(this.orphanTimer);for(let e of this.listeners.values())e.writableEnded||e.end();this.listeners.clear()}};var Gr=8e3,Ic=/^[A-Za-z0-9_.:-]{1,64}$/,$e=new Map;async function Xr(t,e,a,n,r,o){if(a!=="/api/app/agents"&&a!=="/api/app/chat"&&a!=="/api/app/chat/stop"&&a!=="/api/app/chat/attach"&&a!=="/api/app/conversations"&&!a.startsWith("/api/app/conversations/"))return!1;if(n==="GET"&&a==="/api/app/agents")return N(e,200,{nodes:await Kr(o)});let s=o.store();if(!s)return N(e,503,{error:"The database on this computer is unavailable, so chats can't be saved."});if(n==="GET"&&a==="/api/app/conversations")return N(e,200,{conversations:s.list(r.id)});let i=n==="GET"?/^\/api\/app\/conversations\/([^/]+)$/.exec(a):null;if(i){let c=s.get(r.id,decodeURIComponent(i[1]));if(!c)return N(e,404,{error:"no such conversation"});let p=$e.get(c.id);return N(e,200,{...c,running:!!p,...p?{partial:{text:p.text,tools:p.tools}}:{}})}if(n==="GET"&&a==="/api/app/chat/attach"){let c=s.get(r.id,new URL(t.url||a,"http://x").searchParams.get("conversationId")||""),p=c&&$e.get(c.id);if(!c||!p)return N(e,404,{error:"nothing is running in this conversation"});Jr(e);let{id:u,title:f,node:h,nodeName:y,agent:T,agentName:S}=c;return e.write(Xt("conversation",{id:u,title:f,node:h,nodeName:y,agent:T,agentName:S})),e.write(Xt("resume",{text:p.text,tools:p.tools})),p.attach(e),!0}if(n!=="POST"||a!=="/api/app/chat"&&a!=="/api/app/chat/stop")return N(e,404,{error:"not found"});let l;try{l=await ke(t,64*1024)}catch(c){return N(e,400,{error:c.message})}if(a==="/api/app/chat/stop"){let c=s.get(r.id,String(l.conversationId??""));if(!c)return N(e,404,{error:"no such conversation"});let p=$e.get(c.id);return p?(p.ac.abort(),Kt(c,o,r.name),N(e,200,{stopped:!0})):await Kt(c,o,r.name)?N(e,200,{stopped:!0}):N(e,404,{error:"nothing is running in this conversation"})}return await Lc(e,l,r,s,o),!0}function $c(t,e,a){let n=Le(e.url),r=new Set,o=[];for(let s of t){let i=Le(s.url),l=a.find(u=>Le(u.peerUrl)===i);l&&r.add(l.peer);let c=i===n,p=s.agents.length?s.agents:l?.skills??[];o.push({target:c?"local":l?l.peer:null,name:s.reachable?s.name:(c?e.name:l?.peer)||s.name,online:c?s.reachable:l?l.healthy:!1,agents:p.map(u=>{let f=Array.isArray(u.runningTasks)?u.runningTasks.length:0;return{id:u.id,name:u.name||u.id,busy:f>0||(u.active??0)>0,running:f,...u.color?{color:u.color}:{}}})})}for(let s of a)r.has(s.peer)||o.push({target:s.peer,name:s.peer,online:s.healthy,agents:(s.skills??[]).map(i=>({id:i.id,name:i.name||i.id,busy:!1,running:0}))});return o}async function Kr(t){let[e,a]=await Promise.all([t.snapshot().catch(()=>({nodes:[]})),t.meshPeers().catch(()=>[])]);return $c(e.nodes,t.daemon,a)}async function Lc(t,e,a,n,r){let o=typeof e.message=="string"?e.message.trim():"";if(!o||o.length>Gr){N(t,400,{error:`message must be 1\u2013${Gr} characters`});return}let s;if(e.conversationId!=null){if(s=n.get(a.id,String(e.conversationId)),!s){N(t,404,{error:"no such conversation"});return}}else{let y=typeof e.node=="string"?e.node:"",T=typeof e.agent=="string"?e.agent:"";if(!Ic.test(T)){N(t,400,{error:"pick an agent"});return}let S=(await Kr(r)).find(d=>d.target===y);if(!S){N(t,400,{error:`unknown node "${y}"`});return}if(!S.online){N(t,409,{error:`${S.name} is offline`});return}let x=S.agents.find(d=>d.id===T);if(!x){N(t,400,{error:`no agent "${T}" on ${S.name}`});return}s=n.create(a.id,{node:y,nodeName:S.name,agent:T,agentName:x.name},o)}if($e.has(s.id)){N(t,409,{error:"The agent is still answering in this conversation."});return}let i=new pt(r.orphanLimitMs??18e5);$e.set(s.id,i),n.append(a.id,s.id,{role:"user",content:o,at:Date.now()});let{id:l,title:c,node:p,nodeName:u,agent:f,agentName:h}=s;Jr(t),t.write(Xt("conversation",{id:l,title:c,node:p,nodeName:u,agent:f,agentName:h})),i.attach(t);try{let y=await qr(r.daemon,{node:p,agent:f,message:o,chatId:`app:${l}`},i.ac.signal,(S,x)=>i.broadcast(S,x));i.orphaned&&(y.error=`Stopped: the phone was away for more than ${Math.round((r.orphanLimitMs??18e5)/6e4)} minutes.`,Kt(s,r,a.name));let T=n.appendWithFiles(a.id,l,{role:"assistant",content:y.text,status:y.status,at:Date.now(),...y.error?{error:y.error}:{},...y.ui?{ui:y.ui}:{},...y.tools.length?{tools:y.tools}:{}},y.files)??[];i.broadcast("final",{status:y.status,content:y.text,...y.error?{error:y.error}:{},...y.ui?{ui:y.ui}:{},...T.length?{files:T}:{}})}finally{$e.delete(l),i.finish()}}function Jr(t){t.writeHead(200,{"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-store","X-Accel-Buffering":"no"})}function Xt(t,e){return`event: ${t}
15134
+ `)},15e3);r.unref?.(),this.listeners.set(n,e),this.orphanTimer&&(clearTimeout(this.orphanTimer),this.orphanTimer=null),e.on("close",()=>{clearInterval(r),this.listeners.delete(n),!this.done&&!this.listeners.size&&!this.ac.signal.aborted&&!this.orphanTimer&&(this.orphanTimer=setTimeout(()=>{this.orphaned=!0,this.ac.abort()},this.orphanLimitMs),this.orphanTimer.unref?.())})}finish(){this.done=!0,this.orphanTimer&&clearTimeout(this.orphanTimer);for(let e of this.listeners.values())e.writableEnded||e.end();this.listeners.clear()}};function so(t,e,a,n=12){let r=[],o=new Set,s=e.filter(i=>i.deviceId===t).sort((i,l)=>i.startedAt-l.startedAt);for(let i of s){if(r.length>=n)break;o.add(i.id);let l=ld(i.text);r.push({id:i.id,title:i.title,agent:i.agent,agentName:i.agentName||i.agent,...i.color?{color:i.color}:{},state:l?"answering":"thinking",preview:l||i.title.slice(0,120),updatedAt:i.startedAt})}for(let i of a){if(r.length>=n)break;o.has(i.id)||(o.add(i.id),r.push({id:i.id,title:i.title,agent:i.agent,agentName:i.agentName||i.agent,...i.color?{color:i.color}:{},state:"done",status:i.status,preview:Vt(i.answer)||(i.status==="done"?"Answered.":i.status==="stopped"?"Stopped.":"The agent could not answer."),updatedAt:i.at}))}return r}function Vt(t,e=120){for(let a of t.split(`
15135
+ `)){let n=io(a);if(n)return Yt(n,e)}return""}function ld(t,e=120){let a=t.split(`
15136
+ `).map(io).filter(Boolean);return a.length?Yt(a[a.length-1],e):""}function io(t){return t.replace(/^\s*(?:[#>]+|[-*+]\s|\d+\.\s)\s*/,"").replace(/[*_`]+/g,"").replace(/\s+/g," ").trim()}function Yt(t,e){let a=[...t];return a.length>e?a.slice(0,e-1).join("")+"\u2026":t}var mt=class{constructor(e=15e3){this.windowMs=e}seen=new Map;poll(e,a=Date.now()){this.seen.set(e,a)}away(e){this.seen.delete(e)}open(e,a=Date.now()){let n=this.seen.get(e);return n!==void 0&&a-n<=this.windowMs}};function lo(t){return t.enabled&&!t.attached&&!t.appOpen&&t.status!=="stopped"}var oo=140;function co(t,e,a,n,r){let o=a==="error"?`Could not answer: ${Vt(r||"",oo-18)||"something went wrong."}`:Vt(n,oo)||"Answered.";return{deviceId:t,title:Yt(e.agentName||e.agent,80),body:o,url:`/app#chat=${e.id}`}}var uo=8e3,dd=/^[A-Za-z0-9_.:-]{1,64}$/,Ee=new Map,Qt=new Map,mo=new mt;async function fo(t,e,a,n,r,o){if(a!=="/api/app/agents"&&a!=="/api/app/chat"&&a!=="/api/app/chat/stop"&&a!=="/api/app/chat/attach"&&a!=="/api/app/chat/active"&&a!=="/api/app/chat/away"&&a!=="/api/app/conversations"&&!a.startsWith("/api/app/conversations/"))return!1;let s=o.presence??mo;if(n==="GET"&&a==="/api/app/agents")return O(e,200,{nodes:await ho(o)});let i=o.store();if(!i)return O(e,503,{error:"The database on this computer is unavailable, so chats can't be saved."});if(n==="GET"&&a==="/api/app/chat/active")return s.poll(r.id),O(e,200,{conversations:so(r.id,md(),i.unread(r.id,12))});if(n==="POST"&&a==="/api/app/chat/away")return s.away(r.id),O(e,200,{ok:!0});if(n==="GET"&&a==="/api/app/conversations")return O(e,200,{conversations:i.list(r.id)});let l=n==="GET"?/^\/api\/app\/conversations\/([^/]+)$/.exec(a):null;if(l){let p=i.get(r.id,decodeURIComponent(l[1]));if(!p)return O(e,404,{error:"no such conversation"});new URL(t.url||a,"http://x").searchParams.get("peek")!=="1"&&i.markRead(r.id,p.id);let u=Ee.get(p.id);return O(e,200,{...p,running:!!u,...u?{partial:{text:u.text,tools:u.tools,...u.plain?{plain:!0}:{}}}:{}})}if(n==="GET"&&a==="/api/app/chat/attach"){let p=i.get(r.id,new URL(t.url||a,"http://x").searchParams.get("conversationId")||""),u=p&&Ee.get(p.id);if(!p||!u)return O(e,404,{error:"nothing is running in this conversation"});i.markRead(r.id,p.id),go(e);let{id:f,title:h,node:v,nodeName:T,agent:E,agentName:g}=p;return e.write(Zt("conversation",{id:f,title:h,node:v,nodeName:T,agent:E,agentName:g})),e.write(Zt("resume",{text:u.text,tools:u.tools,...u.plain?{plain:!0}:{}})),u.attach(e),!0}if(n!=="POST"||a!=="/api/app/chat"&&a!=="/api/app/chat/stop")return O(e,404,{error:"not found"});let c;try{c=await _e(t,64*1024)}catch(p){return O(e,400,{error:p.message})}if(a==="/api/app/chat/stop"){let p=i.get(r.id,String(c.conversationId??""));if(!p)return O(e,404,{error:"no such conversation"});let u=Ee.get(p.id);return u?(u.ac.abort(),ea(p,o,r.name),O(e,200,{stopped:!0})):await ea(p,o,r.name)?O(e,200,{stopped:!0}):O(e,404,{error:"nothing is running in this conversation"})}return await ud(e,c,r,i,o),!0}function pd(t,e,a){let n=Pe(e.url),r=new Set,o=[];for(let s of t){let i=Pe(s.url),l=a.find(u=>Pe(u.peerUrl)===i);l&&r.add(l.peer);let c=i===n,p=s.agents.length?s.agents:l?.skills??[];o.push({target:c?"local":l?l.peer:null,name:s.reachable?s.name:(c?e.name:l?.peer)||s.name,online:c?s.reachable:l?l.healthy:!1,agents:p.map(u=>{let f=Array.isArray(u.runningTasks)?u.runningTasks.length:0;return{id:u.id,name:u.name||u.id,busy:f>0||(u.active??0)>0,running:f,...u.color?{color:u.color}:{}}})})}for(let s of a)r.has(s.peer)||o.push({target:s.peer,name:s.peer,online:s.healthy,agents:(s.skills??[]).map(i=>({id:i.id,name:i.name||i.id,busy:!1,running:0}))});return o}async function ho(t){let[e,a]=await Promise.all([t.snapshot().catch(()=>({nodes:[]})),t.meshPeers().catch(()=>[])]);return pd(e.nodes,t.daemon,a)}async function ud(t,e,a,n,r){let o=typeof e.message=="string"?e.message.trim():"";if(!o||o.length>uo){O(t,400,{error:`message must be 1\u2013${uo} characters`});return}let s;if(e.conversationId!=null){if(s=n.get(a.id,String(e.conversationId)),!s){O(t,404,{error:"no such conversation"});return}}else{let v=typeof e.node=="string"?e.node:"",T=typeof e.agent=="string"?e.agent:"";if(!dd.test(T)){O(t,400,{error:"pick an agent"});return}let E=(await ho(r)).find(d=>d.target===v);if(!E){O(t,400,{error:`unknown node "${v}"`});return}if(!E.online){O(t,409,{error:`${E.name} is offline`});return}let g=E.agents.find(d=>d.id===T);if(!g){O(t,400,{error:`no agent "${T}" on ${E.name}`});return}s=n.create(a.id,{node:v,nodeName:E.name,agent:T,agentName:g.name,...g.color?{color:g.color}:{}},o)}if(Ee.has(s.id)){O(t,409,{error:"The agent is still answering in this conversation."});return}let i=new ut(r.orphanLimitMs??18e5);Ee.set(s.id,i);let{id:l,title:c,node:p,nodeName:u,agent:f,agentName:h}=s;Qt.set(l,{id:l,deviceId:a.id,title:c,agent:f,...h?{agentName:h}:{},...s.color?{color:s.color}:{}}),n.append(a.id,s.id,{role:"user",content:o,at:Date.now()}),go(t),t.write(Zt("conversation",{id:l,title:c,node:p,nodeName:u,agent:f,agentName:h})),i.attach(t);try{let v=await ro(r.daemon,{node:p,agent:f,message:o,chatId:`app:${l}`},i.ac.signal,(d,m)=>i.broadcast(d,m));i.orphaned&&(v.error=`Stopped: the phone was away for more than ${Math.round((r.orphanLimitMs??18e5)/6e4)} minutes.`,ea(s,r,a.name));let T=n.appendWithFiles(a.id,l,{role:"assistant",content:v.text,status:v.status,at:Date.now(),...v.error?{error:v.error}:{},...v.ui?{ui:v.ui}:{},...v.tools.length?{tools:v.tools}:{}},v.files)??[];i.broadcast("final",{status:v.status,content:v.text,...v.error?{error:v.error}:{},...v.ui?{ui:v.ui}:{},...T.length?{files:T}:{}});let E=i.watched();E&&n.markRead(a.id,l);let g={status:v.status,attached:E,appOpen:(r.presence??mo).open(a.id),enabled:!!r.finishAlerts?.(a.id)};r.notifyFinish&&lo(g)&&r.notifyFinish(co(a.id,s,v.status,v.text,v.error)).catch(()=>{})}finally{Ee.delete(l),Qt.delete(l),i.finish()}}function md(){let t=[];for(let[e,a]of Qt){let n=Ee.get(e);n&&t.push({...a,text:n.text,startedAt:n.startedAt})}return t}function go(t){t.writeHead(200,{"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-store","X-Accel-Buffering":"no"})}function Zt(t,e){return`event: ${t}
15135
15137
  data: ${JSON.stringify(e)}
15136
15138
 
15137
- `}async function Kt(t,e,a){try{let n=Le(e.daemon.url);if(t.node!=="local"){let l=(await e.meshPeers()).find(c=>c.peer===t.node);if(!l)return 0;n=Le(l.peerUrl)}let s=(await e.snapshot()).nodes.find(l=>Le(l.url)===n)?.agents.find(l=>l.id===t.agent)?.runningTasks?.filter(l=>l.chatId===`app:${t.id}`)??[],i=0;for(let l of s)(await e.nodePost(n,`/api/tasks/${encodeURIComponent(l.id)}/cancel`,{reason:`cancelled by operator (phone: ${a})`})).status<300&&i++;return i}catch{return 0}}function Le(t){return t.replace(/\/+$/,"")}function N(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}import{Readable as Rc}from"stream";var jc=/^\/api\/app\/files\/([^/]+)$/,Pc=15e3;async function Yr(t,e,a,n,r,o){let s=jc.exec(a);if(!s)return!1;if(n!=="GET"&&n!=="HEAD")return _e(e,405,{error:"GET only"});let i=o.store();if(!i)return _e(e,503,{error:"The database on this computer is unavailable."});let l="";try{l=decodeURIComponent(s[1])}catch{}let c=i.getFile(r.id,l);if(!c)return _e(e,404,{error:"no such file"});let p=await Oc(c.node,o);if(!p)return _e(e,502,{error:`${c.node} is not linked to this computer's mesh any more.`});let u=new AbortController;e.on("close",()=>u.abort());let f=setTimeout(()=>u.abort(),Pc),h;try{let d=new URLSearchParams({agent:c.agent,file:c.path});h=await fetch(`${p.url}${Ta}?${d}`,{method:n,headers:{...p.token?{Authorization:`Bearer ${p.token}`}:{},...typeof t.headers.range=="string"?{Range:t.headers.range}:{}},signal:u.signal})}catch{return _e(e,502,{error:"The computer that made this file did not answer."})}finally{clearTimeout(f)}if(h.status!==200&&h.status!==206){let d=await h.json().then(g=>g?.error).catch(()=>""),m=[403,404,413,415,416].includes(h.status)?h.status:502;return _e(e,m,{error:d||`The computer that made this file answered HTTP ${h.status}.`})}let y=Number(h.headers.get("content-length")||0);if(y>he.bytes)return u.abort(),_e(e,413,{error:"the file is too large"});let T=h.headers.get("content-range");if(e.writeHead(h.status,{...Ca(c.mime,c.name,c.kind),...h.headers.get("content-length")?{"Content-Length":String(y)}:{},...h.status===206&&T?{"Content-Range":T}:{}}),n==="HEAD"||!h.body)return e.end(),!0;let S=0,x=Rc.fromWeb(h.body);return x.on("data",d=>{S+=d.length,S>he.bytes&&(x.destroy(),e.destroy())}),x.on("error",()=>e.destroy()),x.pipe(e),!0}async function Oc(t,e){if(t==="local")return{url:Vr(e.daemon.url),token:e.daemon.token};let a=(await e.meshPeers().catch(()=>[])).find(r=>r.peer===t);if(!a)return null;let n=Vr(a.peerUrl);return{url:n,token:e.tokenFor?.(n)}}function Vr(t){return t.replace(/\/+$/,"")}function _e(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store","X-Content-Type-Options":"nosniff"}),t.end(JSON.stringify(a)),!0}var Zr=8e3;async function eo(t,e,a,n,r,o){if(a!=="/api/app/voice/transcribe"&&a!=="/api/app/voice/speak")return!1;if(n!=="POST")return G(e,405,{error:"POST"});if(a==="/api/app/voice/transcribe"){let f=String(t.headers["content-type"]||"");if(!ja(f))return G(e,415,{error:"Send the recording as audio (webm, mp4, ogg, mp3 or wav)."});let h=Ra(t.headers["x-audio-duration-ms"]);if(h)return t.resume(),G(e,h.status,{error:h.error});let y=await St(t,La.bytes);if(!y)return G(e,413,{error:Pa()});if(!y.length)return G(e,400,{error:"The recording is empty."});let T={"Content-Type":f,"X-Audio-Duration-Ms":String(t.headers["x-audio-duration-ms"]).trim()};return Qr(e,o.daemon,"/voice/transcribe",y,T,18e4)}let s,i=await St(t,64*1024);if(!i)return G(e,413,{error:"request too large"});try{s=JSON.parse(i.toString("utf8")||"{}")}catch{return G(e,400,{error:"expected JSON"})}let l=o.store();if(!l)return G(e,503,{error:"The database on this computer is unavailable."});let c=l.get(r.id,String(s?.conversationId??""));if(!c)return G(e,404,{error:"no such conversation"});let p=typeof s?.text=="string"?s.text.slice(0,Zr):"";if(!p.trim())return G(e,400,{error:"text is required"});if(!Dc(c.messages,p))return G(e,404,{error:"no such answer in this conversation"});let u={agent:c.agent,text:p,...c.node!=="local"?{peer:c.node}:{}};return Qr(e,o.daemon,"/voice/speak",Buffer.from(JSON.stringify(u)),{"Content-Type":"application/json"},9e4)}async function Qr(t,e,a,n,r,o){try{let s=await fetch(e.url.replace(/\/+$/,"")+a,{method:"POST",headers:{...r,...e.token?{Authorization:`Bearer ${e.token}`}:{}},body:new Uint8Array(n),signal:AbortSignal.timeout(o)}),i=s.headers.get("content-type")||"",l=Buffer.from(await s.arrayBuffer());return s.ok&&i.startsWith("audio/")?(t.writeHead(200,{"Content-Type":i,"Content-Length":l.length,"Cache-Control":"no-store"}),t.end(l),!0):s.status===404&&Array.isArray(Nc(l)?.endpoints)?G(t,503,{error:"AgentX on this computer is too old for voice. Update it."}):(t.writeHead(s.status,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(i.includes("json")?l:JSON.stringify({error:`AgentX answered HTTP ${s.status}.`})),!0)}catch(s){return G(t,502,{error:s?.name==="TimeoutError"?"AgentX took too long to answer.":"Could not reach AgentX on this computer."})}}function G(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}function Nc(t){try{return JSON.parse(t.toString("utf8"))}catch{return null}}function Dc(t,e){return t.some(a=>a.role==="assistant"&&(a.content===e||e.length===Zr&&a.content.startsWith(e)))}var Hc={perClient:5,global:10,windowMs:10*60*1e3,lockoutMs:5*60*1e3},ut=class{constructor(e=Hc,a=Date.now){this.opts=e;this.now=a}clients=new Map;all={failures:[],lockedUntil:0};retryAfter(e){let a=this.now(),n=Math.max(this.all.lockedUntil,this.clients.get(e)?.lockedUntil??0);return n>a?Math.ceil((n-a)/1e3):0}fail(e){let a=this.clients.get(e);a||this.clients.set(e,a={failures:[],lockedUntil:0}),this.bump(a,this.opts.perClient),this.bump(this.all,this.opts.global)}succeed(e){this.clients.delete(e)}bump(e,a){let n=this.now();e.failures=e.failures.filter(r=>n-r<this.opts.windowMs),e.failures.push(n),e.failures.length>=a&&(e.lockedUntil=n+this.opts.lockoutMs)}},Bc="That code didn't work. Check it, or run agentx app pair for a new one.",zc=400;async function to(t,e){let a=Date.now(),n=e.log??(c=>console.log(c)),r=t.socket.remoteAddress||"unknown",o=e.limiter.retryAfter(r);if(o>0)return n(`[app] pair-code refused from ${r}: locked out for ${o}s more`),{status:429,body:{error:"too many attempts",retryAfter:o},retryAfter:o};let s=null;try{s=(await ke(t,1024)).code}catch{}let i=e.codes.redeem(s),l=i?e.verify(i.token):null;return await Fc(a,e.minMs??zc),!i||!l?(e.limiter.fail(r),n(`[app] pair-code failed from ${r}`),{status:401,body:{error:Bc}}):(e.limiter.succeed(r),n(`[app] pair-code paired ${i.tokenId} (${l}) from ${r}`),{status:200,body:{device:l},token:i.token})}async function Fc(t,e){let a=t+e-Date.now();a>0&&await new Promise(n=>setTimeout(n,a))}function Jt(t,e){if(!t)return"absent";let a=_a(t),n=e.list().find(r=>r.hash===a);return n&&(n.revokedAt||n.expiresAt&&Date.parse(n.expiresAt)<Date.now())?"revoked":"invalid"}var mt=class{constructor(e=r=>console.log(r),a=Date.now,n=6e4){this.log=e;this.now=a;this.everyMs=n}last=new Map;record(e,a){let n=Object.entries(a).map(([i,l])=>`${i}=${l}`).join(" "),r=`${e} ${a.cookie??""} ${a.bearer??""}`,o=this.now(),s=this.last.get(r);s!==void 0&&o-s<this.everyMs||(this.last.size>500&&this.prune(o),this.last.set(r,o),this.log(`[app] unauthenticated ${e} ${n}`))}prune(e){for(let[a,n]of this.last)e-n>=this.everyMs&&this.last.delete(a);this.last.size>500&&this.last.clear()}};function no(t,e,a){let n={cookie:e};return a&&(n.bearer=a),n.mode=ao(t.headers["sec-fetch-mode"]),n.site=ao(t.headers["sec-fetch-site"]),n}function ao(t){let e=Array.isArray(t)?t[0]:t;return e&&/^[a-z-]{1,20}$/.test(e)?e:"-"}var ro=`
15139
+ `}async function ea(t,e,a){try{let n=Pe(e.daemon.url);if(t.node!=="local"){let l=(await e.meshPeers()).find(c=>c.peer===t.node);if(!l)return 0;n=Pe(l.peerUrl)}let s=(await e.snapshot()).nodes.find(l=>Pe(l.url)===n)?.agents.find(l=>l.id===t.agent)?.runningTasks?.filter(l=>l.chatId===`app:${t.id}`)??[],i=0;for(let l of s)(await e.nodePost(n,`/api/tasks/${encodeURIComponent(l.id)}/cancel`,{reason:`cancelled by operator (phone: ${a})`})).status<300&&i++;return i}catch{return 0}}function Pe(t){return t.replace(/\/+$/,"")}function O(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}import{Readable as fd}from"stream";var hd=/^\/api\/app\/files\/([^/]+)$/,gd=15e3;async function vo(t,e,a,n,r,o){let s=hd.exec(a);if(!s)return!1;if(n!=="GET"&&n!=="HEAD")return Se(e,405,{error:"GET only"});let i=o.store();if(!i)return Se(e,503,{error:"The database on this computer is unavailable."});let l="";try{l=decodeURIComponent(s[1])}catch{}let c=i.getFile(r.id,l);if(!c)return Se(e,404,{error:"no such file"});let p=await xd(c.node,o);if(!p)return Se(e,502,{error:`${c.node} is not linked to this computer's mesh any more.`});let u=new AbortController;e.on("close",()=>u.abort());let f=setTimeout(()=>u.abort(),gd),h;try{let d=new URLSearchParams({agent:c.agent,file:c.path});h=await fetch(`${p.url}${Ra}?${d}`,{method:n,headers:{...p.token?{Authorization:`Bearer ${p.token}`}:{},...typeof t.headers.range=="string"?{Range:t.headers.range}:{}},signal:u.signal})}catch{return Se(e,502,{error:"The computer that made this file did not answer."})}finally{clearTimeout(f)}if(h.status!==200&&h.status!==206){let d=await h.json().then(x=>x?.error).catch(()=>""),m=[403,404,413,415,416].includes(h.status)?h.status:502;return Se(e,m,{error:d||`The computer that made this file answered HTTP ${h.status}.`})}let v=Number(h.headers.get("content-length")||0);if(v>ge.bytes)return u.abort(),Se(e,413,{error:"the file is too large"});let T=h.headers.get("content-range");if(e.writeHead(h.status,{...Pa(c.mime,c.name,c.kind),...h.headers.get("content-length")?{"Content-Length":String(v)}:{},...h.status===206&&T?{"Content-Range":T}:{}}),n==="HEAD"||!h.body)return e.end(),!0;let E=0,g=fd.fromWeb(h.body);return g.on("data",d=>{E+=d.length,E>ge.bytes&&(g.destroy(),e.destroy())}),g.on("error",()=>e.destroy()),g.pipe(e),!0}async function xd(t,e){if(t==="local")return{url:xo(e.daemon.url),token:e.daemon.token};let a=(await e.meshPeers().catch(()=>[])).find(r=>r.peer===t);if(!a)return null;let n=xo(a.peerUrl);return{url:n,token:e.tokenFor?.(n)}}function xo(t){return t.replace(/\/+$/,"")}function Se(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store","X-Content-Type-Options":"nosniff"}),t.end(JSON.stringify(a)),!0}var yo=8e3;async function wo(t,e,a,n,r,o){if(a!=="/api/app/voice/transcribe"&&a!=="/api/app/voice/speak")return!1;if(n!=="POST")return K(e,405,{error:"POST"});if(a==="/api/app/voice/transcribe"){let h=String(t.headers["content-type"]||"");if(!za(h))return K(e,415,{error:"Send the recording as audio (webm, mp4, ogg, mp3 or wav)."});let v=Ba(t.headers["x-audio-duration-ms"]);if(v)return t.resume(),K(e,v.status,{error:v.error});let T=await At(t,Ha.bytes);if(!T)return K(e,413,{error:Fa()});if(!T.length)return K(e,400,{error:"The recording is empty."});let E={"Content-Type":h,"X-Audio-Duration-Ms":String(t.headers["x-audio-duration-ms"]).trim()};return bo(e,o.daemon,"/voice/transcribe",T,E,18e4)}let s,i=await At(t,64*1024);if(!i)return K(e,413,{error:"request too large"});try{s=JSON.parse(i.toString("utf8")||"{}")}catch{return K(e,400,{error:"expected JSON"})}let l=o.store();if(!l)return K(e,503,{error:"The database on this computer is unavailable."});let c=l.get(r.id,String(s?.conversationId??""));if(!c)return K(e,404,{error:"no such conversation"});let p=typeof s?.text=="string"?s.text.slice(0,yo):"";if(!p.trim())return K(e,400,{error:"text is required"});if(!bd(c.messages,p))return K(e,404,{error:"no such answer in this conversation"});let u=s?.announce===!0?`${c.agentName||c.agent}: ${p}`:p,f={agent:c.agent,text:u,...c.node!=="local"?{peer:c.node}:{}};return bo(e,o.daemon,"/voice/speak",Buffer.from(JSON.stringify(f)),{"Content-Type":"application/json"},9e4)}async function bo(t,e,a,n,r,o){try{let s=await fetch(e.url.replace(/\/+$/,"")+a,{method:"POST",headers:{...r,...e.token?{Authorization:`Bearer ${e.token}`}:{}},body:new Uint8Array(n),signal:AbortSignal.timeout(o)}),i=s.headers.get("content-type")||"",l=Buffer.from(await s.arrayBuffer());return s.ok&&i.startsWith("audio/")?(t.writeHead(200,{"Content-Type":i,"Content-Length":l.length,"Cache-Control":"no-store"}),t.end(l),!0):s.status===404&&Array.isArray(vd(l)?.endpoints)?K(t,503,{error:"AgentX on this computer is too old for voice. Update it."}):(t.writeHead(s.status,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(i.includes("json")?l:JSON.stringify({error:`AgentX answered HTTP ${s.status}.`})),!0)}catch(s){return K(t,502,{error:s?.name==="TimeoutError"?"AgentX took too long to answer.":"Could not reach AgentX on this computer."})}}function K(t,e,a){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(a)),!0}function vd(t){try{return JSON.parse(t.toString("utf8"))}catch{return null}}function bd(t,e){return t.some(a=>a.role==="assistant"&&(a.content===e||e.length===yo&&a.content.startsWith(e)))}var yd={perClient:5,global:10,windowMs:10*60*1e3,lockoutMs:5*60*1e3},ft=class{constructor(e=yd,a=Date.now){this.opts=e;this.now=a}clients=new Map;all={failures:[],lockedUntil:0};retryAfter(e){let a=this.now(),n=Math.max(this.all.lockedUntil,this.clients.get(e)?.lockedUntil??0);return n>a?Math.ceil((n-a)/1e3):0}fail(e){let a=this.clients.get(e);a||this.clients.set(e,a={failures:[],lockedUntil:0}),this.bump(a,this.opts.perClient),this.bump(this.all,this.opts.global)}succeed(e){this.clients.delete(e)}bump(e,a){let n=this.now();e.failures=e.failures.filter(r=>n-r<this.opts.windowMs),e.failures.push(n),e.failures.length>=a&&(e.lockedUntil=n+this.opts.lockoutMs)}},wd="That code didn't work. Check it, or run agentx app pair for a new one.",kd=400;async function ko(t,e){let a=Date.now(),n=e.log??(c=>console.log(c)),r=t.socket.remoteAddress||"unknown",o=e.limiter.retryAfter(r);if(o>0)return n(`[app] pair-code refused from ${r}: locked out for ${o}s more`),{status:429,body:{error:"too many attempts",retryAfter:o},retryAfter:o};let s=null;try{s=(await _e(t,1024)).code}catch{}let i=e.codes.redeem(s),l=i?e.verify(i.token):null;return await _d(a,e.minMs??kd),!i||!l?(e.limiter.fail(r),n(`[app] pair-code failed from ${r}`),{status:401,body:{error:wd}}):(e.limiter.succeed(r),n(`[app] pair-code paired ${i.tokenId} (${l}) from ${r}`),{status:200,body:{device:l},token:i.token})}async function _d(t,e){let a=t+e-Date.now();a>0&&await new Promise(n=>setTimeout(n,a))}function ta(t,e){if(!t)return"absent";let a=Ia(t),n=e.list().find(r=>r.hash===a);return n&&(n.revokedAt||n.expiresAt&&Date.parse(n.expiresAt)<Date.now())?"revoked":"invalid"}var ht=class{constructor(e=r=>console.log(r),a=Date.now,n=6e4){this.log=e;this.now=a;this.everyMs=n}last=new Map;record(e,a){let n=Object.entries(a).map(([i,l])=>`${i}=${l}`).join(" "),r=`${e} ${a.cookie??""} ${a.bearer??""}`,o=this.now(),s=this.last.get(r);s!==void 0&&o-s<this.everyMs||(this.last.size>500&&this.prune(o),this.last.set(r,o),this.log(`[app] unauthenticated ${e} ${n}`))}prune(e){for(let[a,n]of this.last)e-n>=this.everyMs&&this.last.delete(a);this.last.size>500&&this.last.clear()}};function Eo(t,e,a){let n={cookie:e};return a&&(n.bearer=a),n.mode=_o(t.headers["sec-fetch-mode"]),n.site=_o(t.headers["sec-fetch-site"]),n}function _o(t){let e=Array.isArray(t)?t[0]:t;return e&&/^[a-z-]{1,20}$/.test(e)?e:"-"}var So=`
15138
15140
  (function () {
15139
15141
  var fleetPanel = document.getElementById('panel-fleet');
15140
15142
  var activityPanel = document.getElementById('panel-activity');
@@ -15378,7 +15380,7 @@ data: ${JSON.stringify(e)}
15378
15380
  setInterval(refresh, 15000);
15379
15381
  refresh();
15380
15382
  })();
15381
- `;var oo=`
15383
+ `;var To=`
15382
15384
  .fx-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
15383
15385
  .fx-head h2 { margin: 4px 0 0; }
15384
15386
  .fx-sub { font-size: 15px; margin: 18px 0 8px; color: var(--ax-text-2); }
@@ -15435,7 +15437,7 @@ details[open] > summary::before { transform: rotate(90deg); }
15435
15437
  }
15436
15438
  .fx-error:empty { display: none; }
15437
15439
  .fx-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
15438
- `;var so=`
15440
+ `;var Ao=`
15439
15441
  (function () {
15440
15442
  var panel = document.getElementById('panel-alerts');
15441
15443
  if (!panel) return;
@@ -15443,6 +15445,8 @@ details[open] > summary::before { transform: rotate(90deg); }
15443
15445
  '<div class="fx-card"><div class="fx-row"><h3>Notifications on this phone</h3><span id="al-pill" class="fx-pill"></span></div>' +
15444
15446
  '<p id="al-text" class="fx-muted">Checking\u2026</p>' +
15445
15447
  '<div class="fx-row fx-gap"><button type="button" id="al-btn" class="fx-btn fx-primary" hidden></button></div>' +
15448
+ '<div id="al-finish" class="fx-row al-finish" hidden><p id="al-finish-l">When a chat answer finishes<small>Only for conversations you are not looking at</small></p>' +
15449
+ '<button type="button" id="al-finish-sw" class="fx-switch" role="switch" aria-checked="true" aria-labelledby="al-finish-l"><span></span></button></div>' +
15446
15450
  '<p id="al-error" class="fx-error fx-bad" role="alert"></p></div>' +
15447
15451
  '<h3 class="fx-sub">Recent</h3><ul id="al-list" class="fx-list"></ul>';
15448
15452
  var pill = document.getElementById('al-pill');
@@ -15450,6 +15454,8 @@ details[open] > summary::before { transform: rotate(90deg); }
15450
15454
  var btn = document.getElementById('al-btn');
15451
15455
  var err = document.getElementById('al-error');
15452
15456
  var list = document.getElementById('al-list');
15457
+ var finishRow = document.getElementById('al-finish');
15458
+ var finishSw = document.getElementById('al-finish-sw');
15453
15459
  var server = null;
15454
15460
  var busy = false;
15455
15461
 
@@ -15509,6 +15515,9 @@ details[open] > summary::before { transform: rotate(90deg); }
15509
15515
  pill.className = 'fx-pill ' + (state === 'on' ? 'fx-on' : state === 'off' ? 'fx-warn' : 'fx-off');
15510
15516
  text.textContent = message;
15511
15517
  btn.hidden = !action;
15518
+ // Settable before notifications are turned on, so it is ready then.
15519
+ finishRow.hidden = state === 'na';
15520
+ if (server) finishSw.setAttribute('aria-checked', server.chatFinish === false ? 'false' : 'true');
15512
15521
  if (action) { btn.textContent = action; btn.className = 'fx-btn ' + (action === 'Turn off' ? 'fx-danger-o' : 'fx-primary'); }
15513
15522
  }
15514
15523
 
@@ -15572,14 +15581,26 @@ details[open] > summary::before { transform: rotate(90deg); }
15572
15581
  .then(function () { busy = false; btn.disabled = false; });
15573
15582
  });
15574
15583
 
15584
+ finishSw.addEventListener('click', function () {
15585
+ var on = finishSw.getAttribute('aria-checked') !== 'true';
15586
+ finishSw.disabled = true;
15587
+ err.textContent = '';
15588
+ api('POST', '/api/app/push/prefs', { chatFinish: on }).then(function (b) {
15589
+ if (server) server.chatFinish = b.chatFinish;
15590
+ finishSw.setAttribute('aria-checked', b.chatFinish ? 'true' : 'false');
15591
+ }).catch(function (e) { err.textContent = e.message; }).then(function () { finishSw.disabled = false; });
15592
+ });
15593
+
15575
15594
  function loadRecent() {
15576
15595
  return api('GET', '/api/app/alerts').then(function (b) {
15577
15596
  var items = b.items || [];
15578
15597
  if (!items.length) { list.innerHTML = '<li class="fx-muted">No notifications yet.</li>'; return; }
15579
15598
  list.innerHTML = items.map(function (it) {
15580
15599
  // Only web links: a button URL comes from an agent's message.
15600
+ // A finished chat answer links back into the app (/app#chat=<id>).
15581
15601
  var link = /^https?:/i.test(it.url || '')
15582
- ? ' <a href="' + esc(it.url) + '" target="_blank" rel="noopener noreferrer">Open</a>' : '';
15602
+ ? ' <a href="' + esc(it.url) + '" target="_blank" rel="noopener noreferrer">Open</a>'
15603
+ : /^[/]app#chat=c[a-z0-9]+$/.test(it.url || '') ? ' <a href="' + esc(it.url) + '">Open</a>' : '';
15583
15604
  return '<li><div class="fx-row"><strong>' + esc(it.title) + '</strong><span class="fx-muted">' + esc(ago(it.at)) + '</span></div>' +
15584
15605
  '<p>' + esc(it.body) + link + '</p></li>';
15585
15606
  }).join('');
@@ -15597,11 +15618,124 @@ details[open] > summary::before { transform: rotate(90deg); }
15597
15618
  refresh();
15598
15619
  loadRecent();
15599
15620
  })();
15600
- `;var io=`
15621
+ `;var Co=`
15622
+ (function () {
15623
+ var panel = document.getElementById('panel-alerts');
15624
+ if (!panel) return;
15625
+ function el(tag, cls, text) {
15626
+ var n = document.createElement(tag);
15627
+ if (cls) n.className = cls;
15628
+ if (text != null) n.textContent = text;
15629
+ return n;
15630
+ }
15631
+ function ago(iso) {
15632
+ var t = Date.parse(iso);
15633
+ if (!isFinite(t)) return '';
15634
+ var s = Math.max(0, (Date.now() - t) / 1000);
15635
+ if (s < 60) return 'just now';
15636
+ if (s < 3600) return Math.round(s / 60) + ' min ago';
15637
+ if (s < 86400) return Math.round(s / 3600) + ' h ago';
15638
+ return Math.round(s / 86400) + ' d ago';
15639
+ }
15640
+
15641
+ var card = el('div', 'fx-card');
15642
+ card.id = 'an-card';
15643
+ var head = el('div', 'fx-row');
15644
+ head.appendChild(el('h3', null, 'Announcements'));
15645
+ var sw = el('button', 'fx-switch');
15646
+ sw.type = 'button';
15647
+ sw.id = 'an-notify';
15648
+ sw.setAttribute('role', 'switch');
15649
+ sw.setAttribute('aria-checked', 'false');
15650
+ sw.setAttribute('aria-labelledby', 'an-notify-label');
15651
+ sw.appendChild(el('span'));
15652
+ // Same look as the chat-finish switch above it (.al-finish).
15653
+ var row = el('div', 'fx-row al-finish');
15654
+ var label = el('p', null, 'Notify me of announcements');
15655
+ label.appendChild(el('small', null, 'A notification for each new one'));
15656
+ label.id = 'an-notify-label';
15657
+ row.appendChild(label);
15658
+ row.appendChild(sw);
15659
+ row.style.display = 'none';
15660
+ var err = el('p', 'fx-error fx-bad');
15661
+ err.setAttribute('role', 'alert');
15662
+ var list = el('ul', 'fx-list');
15663
+ list.id = 'an-list';
15664
+ list.setAttribute('aria-live', 'polite');
15665
+ card.appendChild(head);
15666
+ card.appendChild(row);
15667
+ card.appendChild(err);
15668
+ card.appendChild(list);
15669
+ // Above "Recent", under the notifications card.
15670
+ var recent = panel.querySelector('h3.fx-sub');
15671
+ if (recent) panel.insertBefore(card, recent); else panel.appendChild(card);
15672
+
15673
+ var busy = false;
15674
+ function api(method, path, body) {
15675
+ return fetch(path, {
15676
+ method: method,
15677
+ credentials: 'same-origin',
15678
+ headers: body ? { 'Content-Type': 'application/json' } : {},
15679
+ body: body ? JSON.stringify(body) : undefined,
15680
+ }).then(function (r) {
15681
+ if (r.status === 401) { location.reload(); throw new Error('not paired'); }
15682
+ return r.json().catch(function () { return {}; }).then(function (b) {
15683
+ if (!r.ok) throw new Error(b.error || ('HTTP ' + r.status));
15684
+ return b;
15685
+ });
15686
+ });
15687
+ }
15688
+ function setSwitch(on) {
15689
+ sw.setAttribute('aria-checked', on ? 'true' : 'false');
15690
+ }
15691
+ function render(items) {
15692
+ list.replaceChildren();
15693
+ if (!items.length) { list.appendChild(el('li', 'fx-muted', 'No announcements yet.')); return; }
15694
+ items.forEach(function (it) {
15695
+ var li = el('li');
15696
+ li.appendChild(el('p', null, it.text));
15697
+ var meta = [it.by, it.node, ago(it.at)].filter(function (x) { return x; }).join(' \xB7 ');
15698
+ li.appendChild(el('p', 'fx-muted', meta));
15699
+ list.appendChild(li);
15700
+ });
15701
+ }
15702
+ function load() {
15703
+ return api('GET', '/api/app/announcements').then(function (b) {
15704
+ err.textContent = b.error ? 'Could not load announcements: ' + b.error : '';
15705
+ row.style.display = b.notifyAvailable ? '' : 'none';
15706
+ if (!busy) setSwitch(!!b.notify);
15707
+ render(b.items || []);
15708
+ }).catch(function (e) { err.textContent = 'Could not load announcements: ' + e.message; });
15709
+ }
15710
+ sw.addEventListener('click', function () {
15711
+ if (busy) return;
15712
+ busy = true;
15713
+ var on = sw.getAttribute('aria-checked') !== 'true';
15714
+ setSwitch(on);
15715
+ err.textContent = '';
15716
+ api('POST', '/api/app/push/prefs', { announce: on })
15717
+ .catch(function (e) { setSwitch(!on); err.textContent = e.message; })
15718
+ .then(function () { busy = false; });
15719
+ });
15720
+
15721
+ function visible() { return !document.hidden && !panel.hidden; }
15722
+ setInterval(function () { if (visible()) load(); }, 5000);
15723
+ document.addEventListener('visibilitychange', function () { if (visible()) load(); });
15724
+ // The tab bar un-hides the panel; load as soon as it shows.
15725
+ new MutationObserver(function () { if (visible()) load(); })
15726
+ .observe(panel, { attributes: true, attributeFilter: ['hidden'] });
15727
+ if ('serviceWorker' in navigator) {
15728
+ navigator.serviceWorker.addEventListener('message', function (ev) {
15729
+ if ((ev.data || {}).type === 'agentx-push') load();
15730
+ });
15731
+ }
15732
+ load();
15733
+ })();
15734
+ `;var Mo=`
15601
15735
  (function () {
15602
15736
  var panel = document.getElementById('panel-chat');
15603
15737
  var V = window.AXChatView;
15604
- if (!panel || !V) return;
15738
+ if (!panel || !V || !window.AXChatSheets || !window.AXChatLog) return;
15605
15739
  // The head (agent, History, New) and its two sheets stay pinned at the top
15606
15740
  // of a long conversation, as the composer stays at the bottom.
15607
15741
  panel.innerHTML = '<h2 class="cx-sr">Chat</h2><div class="cx"><div class="cx-top">' +
@@ -15621,7 +15755,11 @@ details[open] > summary::before { transform: rotate(90deg); }
15621
15755
  function $(id) { return document.getElementById(id); }
15622
15756
  var log = $('cx-log'), empty = $('cx-empty'), form = $('cx-form'), input = $('cx-input'), stopBtn = $('cx-stop');
15623
15757
  var pickBtn = $('cx-pick'), picker = $('cx-picker'), hist = $('cx-history'), histBtn = $('cx-history-btn'), newBtn = $('cx-new');
15624
- var state = { conv: null, target: null, busy: false, queue: [], stopWanted: false, view: 0 };
15758
+ // flow: the stream this view follows; a stream from before a switch is ignored.
15759
+ var state = { conv: null, target: null, busy: false, queue: [], stopWanted: false, view: 0, flow: 0, ac: null };
15760
+ // Follow-ups typed for a conversation the phone switched away from, and
15761
+ // the conversations sent from this phone (their answers are read out).
15762
+ var held = {}, sentHere = {};
15625
15763
  var NOTES = { stopped: 'Stopped. What the agent wrote so far is kept.', error: 'The agent could not answer.',
15626
15764
  running: 'Still answering. The answer appears here when it is ready.',
15627
15765
  lost: 'Connection lost. The agent keeps answering; the answer appears here when the phone is back online.' };
@@ -15639,63 +15777,20 @@ details[open] > summary::before { transform: rotate(90deg); }
15639
15777
  return api(path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), signal: signal });
15640
15778
  }
15641
15779
 
15642
- // --- The log ---
15643
- function scrollDown() { var m = document.querySelector('main'); if (m) m.scrollTop = m.scrollHeight; }
15644
- function clearLog() { log.innerHTML = ''; empty.hidden = false; }
15645
- function bubble(cls) {
15646
- var el = document.createElement('div');
15647
- el.className = 'cx-msg ' + cls;
15648
- log.appendChild(el);
15649
- empty.hidden = true;
15650
- return el;
15651
- }
15652
- function userMsg(text) { var el = bubble('cx-user'); el.textContent = text; return el; }
15653
- function agentMsg() {
15654
- var el = bubble('cx-agent');
15655
- el.innerHTML = '<div class="md cx-typing">Thinking\u2026</div><div class="cx-files"></div><div class="cx-ui"></div><p class="cx-note" hidden></p>';
15656
- return el;
15657
- }
15658
- function setBody(el, text) { el.replaceChild(V.md(text), el.querySelector('.md')); }
15659
- function setNote(el, text, bad) {
15660
- var n = el.querySelector('.cx-note');
15661
- n.hidden = !text; n.textContent = text || ''; n.className = 'cx-note' + (bad ? ' cx-bad' : '');
15662
- }
15663
- function renderUi(el, ui) { V.renderUi(el.querySelector('.cx-ui'), ui, send); }
15664
- function renderFiles(el, files) { V.renderFiles(el.querySelector('.cx-files'), files); }
15665
- function renderConversation(conv) {
15666
- clearLog();
15667
- (conv.messages || []).forEach(function (m) {
15668
- if (m.role === 'user') { userMsg(m.content); return; }
15669
- var el = agentMsg();
15670
- setBody(el, m.content || '');
15671
- V.setTools(el, m.tools);
15672
- renderFiles(el, m.files);
15673
- renderUi(el, m.ui);
15674
- if (m.status && m.status !== 'done') setNote(el, m.error || NOTES[m.status] || '', m.status === 'error');
15675
- });
15676
- var live = null;
15677
- if (conv.running) {
15678
- // What the agent has written so far; the live stream carries on from it.
15679
- live = agentMsg();
15680
- if (conv.partial && conv.partial.text) setBody(live, V.preview(conv.partial.text));
15681
- V.setTools(live, conv.partial && conv.partial.tools);
15682
- setNote(live, NOTES.running);
15683
- }
15684
- // Follow-ups typed while it answers stay below, waiting to be sent.
15685
- state.queue.forEach(function (x) { log.appendChild(x.el); });
15686
- scrollDown();
15687
- return live;
15688
- }
15780
+ // --- The log (app-chat-log.client.ts) ---
15781
+ var L = window.AXChatLog({ V: V, log: log, empty: empty, notes: NOTES, send: function (t) { return send(t); }, queue: function () { return state.queue; } });
15782
+ var scrollDown = L.scrollDown, clearLog = L.clear, userMsg = L.userMsg, queuedMsg = L.queuedMsg, agentMsg = L.agentMsg;
15783
+ var setBody = L.setBody, setNote = L.setNote, renderUi = L.renderUi, renderFiles = L.renderFiles, renderConversation = L.renderConversation, flash = L.flash;
15689
15784
 
15690
15785
  // --- Agent, conversation and the sheets ---
15691
15786
  function showTarget(t) {
15692
15787
  pickBtn.querySelector('.cx-pick-label').textContent = t ? (t.agentName || t.agent) : 'Choose an agent';
15693
15788
  pickBtn.querySelector('.cx-pick-sub').textContent = t ? 'on ' + t.nodeName : 'Tap to see the agents on your machines';
15694
- emit('target', { target: t });
15789
+ emit('target', { target: t, conversationId: state.conv && state.conv.id });
15695
15790
  }
15696
15791
  function useConversation(conv) {
15697
15792
  state.conv = conv;
15698
- var color = state.target && state.target.agent === conv.agent ? state.target.color : undefined;
15793
+ var color = conv.color || (state.target && state.target.agent === conv.agent ? state.target.color : undefined);
15699
15794
  state.target = { node: conv.node, nodeName: conv.nodeName, agent: conv.agent, agentName: conv.agentName, color: color };
15700
15795
  showTarget(state.target);
15701
15796
  remember('ax-chat-conv', conv.id);
@@ -15707,35 +15802,24 @@ details[open] > summary::before { transform: rotate(90deg); }
15707
15802
  p[0].hidden = !on; p[1].setAttribute('aria-expanded', on ? 'true' : 'false');
15708
15803
  });
15709
15804
  }
15710
- function loadPicker() {
15711
- picker.innerHTML = '<p class="cx-note">Looking for agents\u2026</p>';
15712
- api('/api/app/agents').then(function (r) { return r.json(); }).then(function (data) {
15713
- var nodes = picker._data = data.nodes || [];
15714
- if (!nodes.length) { picker.innerHTML = '<p class="cx-note">No machines answered. Check that AgentX is running.</p>'; return; }
15715
- picker.innerHTML = nodes.map(function (n, i) {
15716
- var can = n.target && n.online;
15717
- var why = !n.target ? 'Not linked to this computer\u2019s mesh' : n.online ? 'Online' : 'Offline';
15718
- var rows = n.agents.length ? n.agents.map(function (a, j) {
15719
- return '<li><button type="button" data-n="' + i + '" data-a="' + j + '"' + (can ? '' : ' disabled') + '>' +
15720
- '<span>' + V.esc(a.name) + '<span class="cx-sub">' + V.esc(a.id) + '</span></span>' +
15721
- '<span class="cx-state' + (a.busy ? ' cx-busy' : '') + '">' + (a.busy ? 'busy' + (a.running > 1 ? ' \xB7 ' + a.running : '') : 'idle') + '</span></button></li>';
15722
- }).join('') : '<li class="cx-note">No agents</li>';
15723
- return '<h3><span class="cx-dot' + (n.online ? ' cx-on' : '') + '"></span>' + V.esc(n.name) + ' <span class="cx-sub">' + V.esc(why) + '</span></h3><ul>' + rows + '</ul>';
15724
- }).join('');
15725
- }).catch(function () { picker.innerHTML = '<p class="cx-note cx-bad">Could not load agents. Check the connection and try again.</p>'; });
15805
+ var sheets = window.AXChatSheets({ V: V, api: api, picker: picker, hist: hist,
15806
+ onPick: function (t) { state.target = t; remember('ax-chat-target', t); startNew(); toggle(picker, false); input.focus(); },
15807
+ onOpen: function (id) { toggle(hist, false); openConversation(id); } });
15808
+
15809
+ // Lets go of the stream being followed; the computer keeps the turn going.
15810
+ // Follow-ups typed for it stay held until it is done.
15811
+ function detach() {
15812
+ if (!state.busy) return;
15813
+ var id = state.conv && state.conv.id;
15814
+ if (id && state.queue.length) held[id] = (held[id] || []).concat(state.queue.map(function (x) { return x.text; }));
15815
+ state.queue = [];
15816
+ state.flow++;
15817
+ if (state.ac) { try { state.ac.abort(); } catch (e) {} }
15818
+ setBusy(false);
15819
+ if (id) emit('detached', { conversationId: id });
15726
15820
  }
15727
- picker.addEventListener('click', function (ev) {
15728
- var b = ev.target.closest('button[data-a]');
15729
- if (!b || !picker._data) return;
15730
- var n = picker._data[+b.getAttribute('data-n')], a = n.agents[+b.getAttribute('data-a')];
15731
- state.target = { node: n.target, nodeName: n.name, agent: a.id, agentName: a.name, color: a.color };
15732
- remember('ax-chat-target', state.target);
15733
- startNew();
15734
- toggle(picker, false);
15735
- input.focus();
15736
- });
15737
15821
  function startNew() {
15738
- if (state.busy) return;
15822
+ detach();
15739
15823
  state.view++;
15740
15824
  clearTimeout(pollTimer);
15741
15825
  state.conv = null;
@@ -15744,34 +15828,18 @@ details[open] > summary::before { transform: rotate(90deg); }
15744
15828
  clearLog();
15745
15829
  setBusy(false);
15746
15830
  }
15747
- function when(ms) { var d = new Date(ms); return isNaN(d.getTime()) ? '' : d.toLocaleString(); }
15748
- function loadHistory() {
15749
- hist.innerHTML = '<p class="cx-note">Loading\u2026</p>';
15750
- api('/api/app/conversations').then(function (r) { if (!r.ok) throw new Error(); return r.json(); })
15751
- .then(function (d) { paintHistory(d.conversations || [], false); })
15752
- .catch(function () { V.cacheAll().then(function (all) { paintHistory(all, true); }); });
15753
- }
15754
- function paintHistory(list, offline) {
15755
- if (!list.length) { hist.innerHTML = '<p class="cx-note">' + (offline ? 'Offline, and nothing is saved on this phone yet.' : 'No conversations yet.') + '</p>'; return; }
15756
- hist.innerHTML = (offline ? '<p class="cx-note">Offline: showing the conversations saved on this phone.</p>' : '') + '<ul>' + list.map(function (c) {
15757
- return '<li><button type="button" data-c="' + V.esc(c.id) + '"><span>' + V.esc(c.title) +
15758
- '<span class="cx-sub">' + V.esc((c.agentName || c.agent) + ' \xB7 ' + c.nodeName + ' \xB7 ' + when(c.updatedAt)) + '</span></span></button></li>';
15759
- }).join('') + '</ul>';
15760
- }
15761
- hist.addEventListener('click', function (ev) {
15762
- var b = ev.target.closest('button[data-c]');
15763
- if (!b) return;
15764
- toggle(hist, false);
15765
- openConversation(b.getAttribute('data-c'));
15766
- });
15767
15831
  var pollTimer = 0;
15768
15832
  function openConversation(id) {
15769
- if (state.busy) return;
15833
+ if (state.busy && state.conv && state.conv.id === id) return;
15834
+ detach();
15770
15835
  clearTimeout(pollTimer);
15771
15836
  // The phone's copy first, so it opens at once and offline; the server's
15772
15837
  // copy replaces it when it arrives. A load that finishes after the user
15773
15838
  // moved on (New, another conversation, a send) is dropped.
15774
15839
  var mine = ++state.view, fromServer = false;
15840
+ // Held follow-ups come back as waiting bubbles.
15841
+ state.queue = (held[id] || []).map(queuedMsg);
15842
+ delete held[id];
15775
15843
  V.cacheGet(id).then(function (c) { if (c && !fromServer && mine === state.view) { useConversation(c); renderConversation(c); } });
15776
15844
  return api('/api/app/conversations/' + encodeURIComponent(id)).then(function (r) {
15777
15845
  if (mine !== state.view) return null;
@@ -15782,9 +15850,9 @@ details[open] > summary::before { transform: rotate(90deg); }
15782
15850
  fromServer = true;
15783
15851
  useConversation(c);
15784
15852
  var live = renderConversation(c);
15785
- if (!c.running) { V.cachePut(c); return; }
15853
+ if (!c.running) { V.cachePut(c); sendQueued(); return; }
15786
15854
  // Still running: pick the live stream up where it is.
15787
- follow(api('/api/app/chat/attach?conversationId=' + encodeURIComponent(id)), live, c.partial || {});
15855
+ follow(function (signal) { return api('/api/app/chat/attach?conversationId=' + encodeURIComponent(id), { signal: signal }); }, live, c.partial || {});
15788
15856
  }).catch(function () {});
15789
15857
  }
15790
15858
 
@@ -15792,32 +15860,44 @@ details[open] > summary::before { transform: rotate(90deg); }
15792
15860
  function setBusy(on) {
15793
15861
  state.busy = on;
15794
15862
  stopBtn.hidden = !on;
15795
- newBtn.disabled = on;
15796
15863
  log.setAttribute('aria-busy', on ? 'true' : 'false');
15797
15864
  emit('busy', { on: on });
15798
15865
  }
15866
+ // Empties the box only for the text it held: a tapped quick reply keeps
15867
+ // a half-typed draft.
15868
+ function clearInput(sent) {
15869
+ if (input.value.trim() !== sent) return;
15870
+ input.value = ''; input.style.height = '';
15871
+ }
15872
+ // False when the text was neither sent nor queued, so a quick reply
15873
+ // stays tappable.
15799
15874
  function send(text) {
15800
15875
  text = String(text || '').trim();
15801
- if (!text) return;
15876
+ if (!text) return false;
15802
15877
  if (state.busy) {
15803
15878
  // A follow-up while the agent answers: shown now, sent as the next
15804
15879
  // turn so its answer streams here as well.
15805
- var q = userMsg(text);
15806
- q.classList.add('cx-queued');
15807
- state.queue.push({ text: text, el: q });
15808
- input.value = ''; input.style.height = '';
15880
+ state.queue.push(queuedMsg(text));
15881
+ clearInput(text);
15809
15882
  scrollDown();
15810
- return;
15883
+ return true;
15811
15884
  }
15812
- if (!navigator.onLine) { flash('Offline. Messages can be sent once the phone is connected again.'); return; }
15813
- if (!state.conv && !state.target) { toggle(picker, true); loadPicker(); return; }
15885
+ if (!navigator.onLine) { flash('Offline. Messages can be sent once the phone is connected again.'); return false; }
15886
+ if (!state.conv && !state.target) { toggle(picker, true); sheets.loadPicker(); return false; }
15814
15887
  var body = state.conv
15815
15888
  ? { conversationId: state.conv.id, message: text }
15816
15889
  : { node: state.target.node, agent: state.target.agent, message: text };
15817
15890
  state.stopWanted = false;
15818
15891
  userMsg(text);
15819
- input.value = ''; input.style.height = '';
15820
- follow(post('/api/app/chat', body), agentMsg(), null);
15892
+ clearInput(text);
15893
+ follow(function (signal) { return post('/api/app/chat', body, signal); }, agentMsg(), null);
15894
+ return true;
15895
+ }
15896
+ function sendQueued() {
15897
+ if (!state.queue.length || state.busy) return;
15898
+ var next = state.queue.splice(0);
15899
+ next.forEach(function (x) { x.el.remove(); });
15900
+ send(next.map(function (x) { return x.text; }).join(V.NL + V.NL));
15821
15901
  }
15822
15902
  // Streams one turn into the bubble el, from a send or from attaching
15823
15903
  // to a turn that is still running. The phone losing its connection does
@@ -15825,8 +15905,10 @@ details[open] > summary::before { transform: rotate(90deg); }
15825
15905
  function follow(request, el, partial) {
15826
15906
  clearTimeout(pollTimer);
15827
15907
  state.view++;
15828
- var raw = (partial && partial.text) || '', tools = ((partial && partial.tools) || []).slice(), ended = false, frame = 0;
15829
- function paint() { frame = 0; if (!ended && raw) { setBody(el, V.preview(raw)); scrollDown(); } }
15908
+ var flow = ++state.flow, ac = state.ac = window.AbortController ? new AbortController() : null;
15909
+ var raw = (partial && partial.text) || '', plain = !!(partial && partial.plain), tools = ((partial && partial.tools) || []).slice(), ended = false, frame = 0;
15910
+ function mine() { return flow === state.flow; }
15911
+ function paint() { frame = 0; if (!ended && raw && mine()) { setBody(el, V.preview(raw, plain)); scrollDown(); } }
15830
15912
  function finish(content, note, bad, ui, files) {
15831
15913
  ended = true;
15832
15914
  setBody(el, content || '');
@@ -15834,24 +15916,29 @@ details[open] > summary::before { transform: rotate(90deg); }
15834
15916
  renderUi(el, ui);
15835
15917
  setNote(el, note, bad);
15836
15918
  scrollDown();
15837
- // own: a turn this phone sent now, not one it came back to.
15838
- emit('final', { own: !partial, ok: !note, content: content || '', conversationId: state.conv && state.conv.id });
15919
+ var id = state.conv && state.conv.id;
15920
+ // own: a turn sent from this phone, not one it only came back to.
15921
+ emit('final', { own: !partial || !!sentHere[id], ok: !note, content: content || '', conversationId: id });
15839
15922
  }
15840
15923
  setBusy(true);
15841
15924
  scrollDown();
15842
- return request.then(function (r) {
15925
+ return request(ac && ac.signal).then(function (r) {
15843
15926
  // Attaching just after the turn ended: reload the saved answer.
15844
15927
  if (r.status === 404 && partial) { ended = true; return; }
15845
- if (!r.ok) return r.json().catch(function () { return {}; }).then(function (j) { finish(raw, j.error || ('Failed (HTTP ' + r.status + ')'), true); });
15928
+ if (!r.ok) return r.json().catch(function () { return {}; }).then(function (j) { if (mine()) finish(raw, j.error || ('Failed (HTTP ' + r.status + ')'), true); });
15846
15929
  return V.readStream(r.body, function (ev, d) {
15847
- if (ev === 'conversation') { useConversation(d); if (state.stopWanted) { state.stopWanted = false; stop(); } }
15848
- else if (ev === 'resume') { raw = d.text || ''; tools = (d.tools || []).slice(); V.setTools(el, tools); setNote(el, ''); paint(); }
15930
+ if (!mine()) return;
15931
+ if (ev === 'conversation') { useConversation(d); if (!partial) sentHere[d.id] = 1; if (state.stopWanted) { state.stopWanted = false; stop(); } }
15932
+ else if (ev === 'start') plain = d.rich === false;
15933
+ else if (ev === 'resume') { raw = d.text || ''; plain = !!d.plain; tools = (d.tools || []).slice(); V.setTools(el, tools); setNote(el, ''); paint(); }
15849
15934
  else if (ev === 'text' && typeof d.text === 'string') { raw += d.text; if (!frame) frame = requestAnimationFrame(paint); }
15850
15935
  else if (ev === 'tool' && d.status === 'start') { tools.push({ id: d.id, name: d.name, arg: d.arg }); V.setTools(el, tools); }
15851
15936
  else if (ev === 'tool' && d.error) { tools.forEach(function (t) { if (t.id === d.id) t.error = true; }); V.setTools(el, tools); }
15852
15937
  else if (ev === 'final') finish(d.content, d.status === 'done' ? '' : (d.error || NOTES[d.status]), d.status === 'error', d.ui, d.files);
15853
15938
  });
15854
15939
  }).catch(function () {}).then(function () {
15940
+ // Switched to another conversation: this stream is no longer shown.
15941
+ if (!mine()) return;
15855
15942
  setBusy(false);
15856
15943
  if (!ended) {
15857
15944
  // The stream broke before the answer: the agent carries on.
@@ -15859,11 +15946,8 @@ details[open] > summary::before { transform: rotate(90deg); }
15859
15946
  if (state.conv) { var id = state.conv.id; pollTimer = setTimeout(function () { if (state.conv && state.conv.id === id) openConversation(id); }, 5000); }
15860
15947
  return;
15861
15948
  }
15862
- if (state.queue.length) {
15863
- var next = state.queue.splice(0);
15864
- next.forEach(function (x) { x.el.remove(); });
15865
- send(next.map(function (x) { return x.text; }).join(V.NL + V.NL));
15866
- } else if (state.conv) openConversation(state.conv.id);
15949
+ if (state.queue.length) sendQueued();
15950
+ else if (state.conv) openConversation(state.conv.id);
15867
15951
  });
15868
15952
  }
15869
15953
  function stop() {
@@ -15871,11 +15955,18 @@ details[open] > summary::before { transform: rotate(90deg); }
15871
15955
  if (!state.conv) { state.stopWanted = true; return; }
15872
15956
  post('/api/app/chat/stop', { conversationId: state.conv.id }).catch(function () {});
15873
15957
  }
15874
- function flash(text) {
15875
- var el = bubble('cx-agent');
15876
- el.innerHTML = '<p class="cx-note cx-bad"></p>';
15877
- el.firstChild.textContent = text;
15878
- scrollDown();
15958
+ // Follow-ups held for a conversation that finished while the phone was
15959
+ // elsewhere go as its next turn now; its answer shows up in the strip.
15960
+ function flushHeld(id) {
15961
+ var texts = held[id];
15962
+ if (!texts || !texts.length || (state.conv && state.conv.id === id)) return;
15963
+ delete held[id];
15964
+ post('/api/app/chat', { conversationId: id, message: texts.join(V.NL + V.NL) }).then(function (r) {
15965
+ if (r.status === 409) { held[id] = texts.concat(held[id] || []); return; }
15966
+ sentHere[id] = 1;
15967
+ // The computer keeps the turn going without the phone reading it.
15968
+ if (r.body && r.body.cancel) r.body.cancel().catch(function () {});
15969
+ }).catch(function () { held[id] = texts.concat(held[id] || []); });
15879
15970
  }
15880
15971
 
15881
15972
  form.addEventListener('submit', function (e) { e.preventDefault(); send(input.value); });
@@ -15884,28 +15975,46 @@ details[open] > summary::before { transform: rotate(90deg); }
15884
15975
  });
15885
15976
  input.addEventListener('input', function () { input.style.height = ''; input.style.height = Math.min(input.scrollHeight, 240) + 'px'; });
15886
15977
  stopBtn.addEventListener('click', stop);
15887
- pickBtn.addEventListener('click', function () { var open = picker.hidden; toggle(picker, open); if (open) loadPicker(); });
15888
- histBtn.addEventListener('click', function () { var open = hist.hidden; toggle(hist, open); if (open) loadHistory(); });
15978
+ pickBtn.addEventListener('click', function () { var open = picker.hidden; toggle(picker, open); if (open) sheets.loadPicker(); });
15979
+ histBtn.addEventListener('click', function () { var open = hist.hidden; toggle(hist, open); if (open) sheets.loadHistory(); });
15889
15980
  newBtn.addEventListener('click', function () { startNew(); input.focus(); });
15890
15981
 
15982
+ // A notification opens /app#chat=<id>.
15983
+ function fromHash() {
15984
+ var m = /^#chat=(c[a-z0-9]{8,32})$/.exec(location.hash);
15985
+ if (!m) return false;
15986
+ try { history.replaceState(null, '', '#chat'); } catch (e) {}
15987
+ openConversation(m[1]);
15988
+ return true;
15989
+ }
15990
+ window.addEventListener('hashchange', fromHash);
15891
15991
  window.addEventListener('online', function () { if (state.conv && !state.busy) openConversation(state.conv.id); });
15892
15992
  window.AXChat = { send: send, busy: function () { return state.busy; }, target: function () { return state.target; },
15893
- pick: function () { toggle(picker, true); loadPicker(); } };
15993
+ pick: function () { toggle(picker, true); sheets.loadPicker(); },
15994
+ open: openConversation, current: function () { return state.conv && state.conv.id; },
15995
+ held: function (id) { return (held[id] || []).length; }, flushHeld: flushHeld, sentHere: function (id) { return !!sentHere[id]; } };
15894
15996
  state.target = recall('ax-chat-target');
15895
15997
  showTarget(state.target);
15896
15998
  var last = recall('ax-chat-conv');
15897
- if (last) openConversation(last);
15999
+ if (!fromHash() && last) openConversation(last);
15898
16000
  })();
15899
- `;var lo=`
16001
+ `;var Io=`
15900
16002
  window.AXChatView = (function () {
15901
16003
  var NL = String.fromCharCode(10), TAB = String.fromCharCode(9), FENCE = String.fromCharCode(96, 96, 96);
15902
16004
  // Cut a half-written agentx:ui block from a streaming reply so its raw
15903
16005
  // JSON never flashes; the finished reply arrives with it parsed.
15904
16006
  var PREVIEW_CUT = new RegExp('(^|' + NL + ')[ ' + TAB + ']*' + FENCE + '[ ' + TAB + ']*agentx:ui', 'i');
15905
16007
  var KEEP = 100;
16008
+ // A fenced block, inline code, or a picture ![alt](src): the same pattern
16009
+ // as plainAnswer (artifact-sentinel.ts), spelled with char codes.
16010
+ var BS = String.fromCharCode(92), BT = String.fromCharCode(96);
16011
+ var PLAIN_PICS = FENCE + '[' + BS + 's' + BS + 'S]*?' + FENCE + '|' + BT + '[^' + BT + BS + 'n]*' + BT +
16012
+ '|!' + BS + '[([^' + BS + ']' + BS + 'n]*)' + BS + ']' + BS + '(([^)' + BS + 's]+)' + BS + ')';
15906
16013
  // Pictures shown inline in one answer; more stay links.
15907
16014
  var MAX_PICS = 8;
15908
16015
  var FILE_ID = /^[a-f0-9]{32}$/;
16016
+ // A quick reply's label on screen; the full text is what a tap sends.
16017
+ var CHIP_LABEL = 40;
15909
16018
 
15910
16019
  function esc(v) {
15911
16020
  return String(v == null ? '' : v).replace(/[&<>"']/g, function (c) {
@@ -15916,10 +16025,14 @@ window.AXChatView = (function () {
15916
16025
  try { var x = new URL(String(u || ''), location.href); return x.protocol === 'https:' || x.protocol === 'http:' ? x.href : ''; } catch (e) { return ''; }
15917
16026
  }
15918
16027
  // Also cuts the file lines (<agentx-artifact>) the finished reply lists
15919
- // below it.
15920
- function preview(text) {
16028
+ // below it. plain: the agent has rich messages off, so its pictures are
16029
+ // links, as in its finished reply (plainAnswer, artifact-sentinel.ts).
16030
+ function preview(text, plain) {
15921
16031
  var m = PREVIEW_CUT.exec(text), t = m ? text.slice(0, m.index) : text, k = t.indexOf('<agentx-artifact');
15922
- return k >= 0 ? t.slice(0, k) : t;
16032
+ t = k >= 0 ? t.slice(0, k) : t;
16033
+ return !plain ? t : t.replace(new RegExp(PLAIN_PICS, 'g'), function (s, alt, src) {
16034
+ return src === undefined ? s : '[' + (alt || src) + '](' + src + ')';
16035
+ });
15923
16036
  }
15924
16037
 
15925
16038
  // --- Full-screen pictures: one viewer, built once ---
@@ -16045,6 +16158,29 @@ window.AXChatView = (function () {
16045
16158
  btns.forEach(function (b) { row.appendChild(link(httpUrl(b.url), b.label)); });
16046
16159
  box.appendChild(row);
16047
16160
  }
16161
+ // Quick replies and reply buttons: a tap is the same as typing the text.
16162
+ // Once one is sent, none of them can be tapped again.
16163
+ var chips = (ui.quickReplies || []).map(function (q) { return { label: q, reply: q }; }).concat(ui.replies || [])
16164
+ .filter(function (c) { return c && c.label && c.reply; }).slice(0, 8);
16165
+ if (chips.length) {
16166
+ var crow = document.createElement('div');
16167
+ crow.className = 'cx-ui-row cx-chips';
16168
+ chips.forEach(function (c) {
16169
+ var b = document.createElement('button'), label = String(c.label), reply = String(c.reply);
16170
+ b.type = 'button'; b.className = 'cx-ui-btn cx-reply';
16171
+ b.textContent = clip(label);
16172
+ // A reply button that sends other words shows them too, so a tap is honest.
16173
+ if (reply !== label) {
16174
+ var said = document.createElement('small');
16175
+ said.textContent = clip(reply);
16176
+ b.appendChild(said);
16177
+ }
16178
+ if (clip(label) !== reply) b.title = reply;
16179
+ b.addEventListener('click', function () { if (send(c.reply) !== false) retire(crow); });
16180
+ crow.appendChild(b);
16181
+ });
16182
+ box.appendChild(crow);
16183
+ }
16048
16184
  if (ui.poll && ui.poll.options) {
16049
16185
  // A poll answer is simply the next message in the conversation.
16050
16186
  var fs = document.createElement('fieldset'), lg = document.createElement('legend'), opts = document.createElement('div');
@@ -16074,6 +16210,13 @@ window.AXChatView = (function () {
16074
16210
  }
16075
16211
  }
16076
16212
 
16213
+ function clip(t) { return t.length > CHIP_LABEL ? t.slice(0, CHIP_LABEL - 1) + '\u2026' : t; }
16214
+
16215
+ // Quick replies under el can't be tapped any more.
16216
+ function retire(el) {
16217
+ Array.prototype.slice.call(el.querySelectorAll('.cx-reply')).forEach(function (b) { b.disabled = true; });
16218
+ }
16219
+
16077
16220
  // Reads the agentx SSE wire from a fetch body: event: <kind>, data: <json>.
16078
16221
  function readStream(body, onEvent) {
16079
16222
  var reader = body.getReader(), dec = new TextDecoder(), buf = '';
@@ -16132,11 +16275,326 @@ window.AXChatView = (function () {
16132
16275
  function cacheGet(id) { return idb('readonly', function (s) { return s.get(id); }); }
16133
16276
  function cacheDrop(id) { return idb('readwrite', function (s) { s.delete(id); }); }
16134
16277
 
16135
- return { NL: NL, esc: esc, httpUrl: httpUrl, md: md, preview: preview, setTools: setTools, renderUi: renderUi, renderFiles: renderFiles,
16278
+ return { NL: NL, esc: esc, httpUrl: httpUrl, md: md, preview: preview, setTools: setTools, renderUi: renderUi, retire: retire, renderFiles: renderFiles,
16136
16279
  openViewer: openViewer, closeViewer: closeViewer, readStream: readStream,
16137
16280
  cachePut: cachePut, cacheGet: cacheGet, cacheAll: cacheAll, cacheDrop: cacheDrop };
16138
16281
  })();
16139
- `;var co=`
16282
+ `;var Lo=`
16283
+ window.AXChatSheets = function (o) {
16284
+ var V = o.V, picker = o.picker, hist = o.hist;
16285
+ function loadPicker() {
16286
+ picker.innerHTML = '<p class="cx-note">Looking for agents\u2026</p>';
16287
+ o.api('/api/app/agents').then(function (r) { return r.json(); }).then(function (data) {
16288
+ var nodes = picker._data = data.nodes || [];
16289
+ if (!nodes.length) { picker.innerHTML = '<p class="cx-note">No machines answered. Check that AgentX is running.</p>'; return; }
16290
+ picker.innerHTML = nodes.map(function (n, i) {
16291
+ var can = n.target && n.online;
16292
+ var why = !n.target ? 'Not linked to this computer\u2019s mesh' : n.online ? 'Online' : 'Offline';
16293
+ var rows = n.agents.length ? n.agents.map(function (a, j) {
16294
+ return '<li><button type="button" data-n="' + i + '" data-a="' + j + '"' + (can ? '' : ' disabled') + '>' +
16295
+ '<span>' + V.esc(a.name) + '<span class="cx-sub">' + V.esc(a.id) + '</span></span>' +
16296
+ '<span class="cx-state' + (a.busy ? ' cx-busy' : '') + '">' + (a.busy ? 'busy' + (a.running > 1 ? ' \xB7 ' + a.running : '') : 'idle') + '</span></button></li>';
16297
+ }).join('') : '<li class="cx-note">No agents</li>';
16298
+ return '<h3><span class="cx-dot' + (n.online ? ' cx-on' : '') + '"></span>' + V.esc(n.name) + ' <span class="cx-sub">' + V.esc(why) + '</span></h3><ul>' + rows + '</ul>';
16299
+ }).join('');
16300
+ }).catch(function () { picker.innerHTML = '<p class="cx-note cx-bad">Could not load agents. Check the connection and try again.</p>'; });
16301
+ }
16302
+ picker.addEventListener('click', function (ev) {
16303
+ var b = ev.target.closest('button[data-a]');
16304
+ if (!b || !picker._data) return;
16305
+ var n = picker._data[+b.getAttribute('data-n')], a = n.agents[+b.getAttribute('data-a')];
16306
+ o.onPick({ node: n.target, nodeName: n.name, agent: a.id, agentName: a.name, color: a.color });
16307
+ });
16308
+ function when(ms) { var d = new Date(ms); return isNaN(d.getTime()) ? '' : d.toLocaleString(); }
16309
+ function loadHistory() {
16310
+ hist.innerHTML = '<p class="cx-note">Loading\u2026</p>';
16311
+ o.api('/api/app/conversations').then(function (r) { if (!r.ok) throw new Error(); return r.json(); })
16312
+ .then(function (d) { paintHistory(d.conversations || [], false); })
16313
+ .catch(function () { V.cacheAll().then(function (all) { paintHistory(all, true); }); });
16314
+ }
16315
+ function paintHistory(list, offline) {
16316
+ if (!list.length) { hist.innerHTML = '<p class="cx-note">' + (offline ? 'Offline, and nothing is saved on this phone yet.' : 'No conversations yet.') + '</p>'; return; }
16317
+ hist.innerHTML = (offline ? '<p class="cx-note">Offline: showing the conversations saved on this phone.</p>' : '') + '<ul>' + list.map(function (c) {
16318
+ return '<li><button type="button" data-c="' + V.esc(c.id) + '"><span>' + V.esc(c.title) +
16319
+ '<span class="cx-sub">' + V.esc((c.agentName || c.agent) + ' \xB7 ' + c.nodeName + ' \xB7 ' + when(c.updatedAt)) + '</span></span></button></li>';
16320
+ }).join('') + '</ul>';
16321
+ }
16322
+ hist.addEventListener('click', function (ev) {
16323
+ var b = ev.target.closest('button[data-c]');
16324
+ if (b) o.onOpen(b.getAttribute('data-c'));
16325
+ });
16326
+ return { loadPicker: loadPicker, loadHistory: loadHistory };
16327
+ };
16328
+ `;var $o=`
16329
+ window.AXChatLog = function (o) {
16330
+ var V = o.V, log = o.log, empty = o.empty, NOTES = o.notes;
16331
+ function scrollDown() { var m = document.querySelector('main'); if (m) m.scrollTop = m.scrollHeight; }
16332
+ function clear() { log.innerHTML = ''; empty.hidden = false; }
16333
+ function bubble(cls) {
16334
+ var el = document.createElement('div');
16335
+ el.className = 'cx-msg ' + cls;
16336
+ log.appendChild(el);
16337
+ empty.hidden = true;
16338
+ return el;
16339
+ }
16340
+ // A newer message ends the quick replies of the answers above it.
16341
+ function userMsg(text) { V.retire(log); var el = bubble('cx-user'); el.textContent = text; return el; }
16342
+ // A follow-up that waits for the agent to finish.
16343
+ function queuedMsg(text) { var q = userMsg(text); q.classList.add('cx-queued'); return { text: text, el: q }; }
16344
+ function agentMsg() {
16345
+ V.retire(log);
16346
+ var el = bubble('cx-agent');
16347
+ el.innerHTML = '<div class="md cx-typing">Thinking\u2026</div><div class="cx-files"></div><div class="cx-ui"></div><p class="cx-note" hidden></p>';
16348
+ return el;
16349
+ }
16350
+ function setBody(el, text) { el.replaceChild(V.md(text), el.querySelector('.md')); }
16351
+ function setNote(el, text, bad) {
16352
+ var n = el.querySelector('.cx-note');
16353
+ n.hidden = !text; n.textContent = text || ''; n.className = 'cx-note' + (bad ? ' cx-bad' : '');
16354
+ }
16355
+ function renderUi(el, ui) { V.renderUi(el.querySelector('.cx-ui'), ui, o.send); }
16356
+ function renderFiles(el, files) { V.renderFiles(el.querySelector('.cx-files'), files); }
16357
+ // Returns the bubble a running turn streams into, or null.
16358
+ function renderConversation(conv) {
16359
+ clear();
16360
+ (conv.messages || []).forEach(function (m) {
16361
+ if (m.role === 'user') { userMsg(m.content); return; }
16362
+ var el = agentMsg();
16363
+ setBody(el, m.content || '');
16364
+ V.setTools(el, m.tools);
16365
+ renderFiles(el, m.files);
16366
+ renderUi(el, m.ui);
16367
+ if (m.status && m.status !== 'done') setNote(el, m.error || NOTES[m.status] || '', m.status === 'error');
16368
+ });
16369
+ var live = null;
16370
+ if (conv.running) {
16371
+ // What the agent has written so far; the live stream carries on from it.
16372
+ live = agentMsg();
16373
+ if (conv.partial && conv.partial.text) setBody(live, V.preview(conv.partial.text, conv.partial.plain));
16374
+ V.setTools(live, conv.partial && conv.partial.tools);
16375
+ setNote(live, NOTES.running);
16376
+ }
16377
+ // Follow-ups typed while it answers stay below, waiting to be sent.
16378
+ o.queue().forEach(function (x) { log.appendChild(x.el); });
16379
+ scrollDown();
16380
+ return live;
16381
+ }
16382
+ function flash(text) {
16383
+ var el = bubble('cx-agent');
16384
+ el.innerHTML = '<p class="cx-note cx-bad"></p>';
16385
+ el.firstChild.textContent = text;
16386
+ scrollDown();
16387
+ }
16388
+ return { scrollDown: scrollDown, clear: clear, userMsg: userMsg, queuedMsg: queuedMsg, agentMsg: agentMsg, setBody: setBody,
16389
+ setNote: setNote, renderUi: renderUi, renderFiles: renderFiles, renderConversation: renderConversation, flash: flash };
16390
+ };
16391
+ `;var Ro=`
16392
+ (function () {
16393
+ var panel = document.getElementById('panel-chat'), C = window.AXChat, V = window.AXChatView, O = window.AXOrb;
16394
+ var top = panel && panel.querySelector('.cx-top');
16395
+ if (!top || !C || !V) return;
16396
+ var nav = document.createElement('nav');
16397
+ nav.className = 'cs'; nav.hidden = true;
16398
+ nav.setAttribute('aria-label', 'Conversations');
16399
+ nav.innerHTML = '<ul class="cs-list"></ul>';
16400
+ top.insertBefore(nav, top.firstChild);
16401
+ var list = nav.firstChild;
16402
+ var shelf = document.createElement('div');
16403
+ shelf.className = 'cs-banners';
16404
+ shelf.setAttribute('aria-live', 'polite');
16405
+ document.body.appendChild(shelf);
16406
+
16407
+ var HEX = /^#[0-9a-fA-F]{6}$/, ON_CHAT = 4000, ELSEWHERE = 10000, BANNER_MS = 6000;
16408
+ var SAY = { thinking: 'thinking', answering: 'answering', done: 'new answer', open: 'on screen' };
16409
+ // prev: each conversation's state at the last poll. watch: ones this phone
16410
+ // let go of while they ran, so a finish is noticed even between polls.
16411
+ var items = [], prev = {}, watch = {}, timer = 0, inflight = false, drawn = '';
16412
+ var waiting = [], shown = null, hideTimer = 0;
16413
+
16414
+ function colorOf(c) { var x = O ? O.colorFor(c.agent, c.color) : c.color; return HEX.test(x || '') ? x : '#2563EB'; }
16415
+ function nameOf(c) { return c.agentName || c.agent || 'Agent'; }
16416
+
16417
+ // --- The strip ---
16418
+ function render() {
16419
+ var cur = C.current(), all = items.slice();
16420
+ // The conversation on screen keeps a chip, so there is a way back to it.
16421
+ if (cur && !all.some(function (c) { return c.id === cur; })) {
16422
+ var t = C.target() || {};
16423
+ all.unshift({ id: cur, agent: t.agent, agentName: t.agentName, color: t.color, state: 'open', preview: '' });
16424
+ }
16425
+ nav.hidden = !all.some(function (c) { return c.id !== cur; });
16426
+ var html = nav.hidden ? '' : all.map(function (c) {
16427
+ var here = c.id === cur, fresh = c.state === 'done' && !here, label = nameOf(c) + ', ' + SAY[c.state] + (c.preview ? ': ' + c.preview : '');
16428
+ return '<li><button type="button" class="cs-chip cs-' + c.state + '" data-id="' + V.esc(c.id) + '" style="--cs-c:' + colorOf(c) + '"' +
16429
+ (here ? ' aria-current="true"' : '') + ' aria-label="' + V.esc(label) + '" title="' + V.esc(c.preview || '') + '">' +
16430
+ '<span class="cs-dot" aria-hidden="true"></span><span class="cs-name">' + V.esc(nameOf(c)) + '</span>' +
16431
+ (fresh ? '<span class="cs-new" aria-hidden="true">New</span>' : '') + '</button></li>';
16432
+ }).join('');
16433
+ // Redrawn only when something changed, so a poll never steals focus
16434
+ // or a tap; a focused chip keeps focus across a redraw.
16435
+ if (html === drawn) return;
16436
+ var had = document.activeElement && list.contains(document.activeElement) ? document.activeElement.getAttribute('data-id') : null;
16437
+ list.innerHTML = drawn = html;
16438
+ var again = had && list.querySelector('button[data-id="' + had + '"]');
16439
+ if (again) again.focus();
16440
+ }
16441
+ list.addEventListener('click', function (ev) {
16442
+ var b = ev.target.closest('button[data-id]');
16443
+ if (b && b.getAttribute('data-id') !== C.current()) C.open(b.getAttribute('data-id'));
16444
+ });
16445
+ // Arrow keys move along the strip; Tab leaves it.
16446
+ list.addEventListener('keydown', function (ev) {
16447
+ if (ev.key !== 'ArrowRight' && ev.key !== 'ArrowLeft' && ev.key !== 'Home' && ev.key !== 'End') return;
16448
+ var bs = Array.prototype.slice.call(list.querySelectorAll('button')), i = bs.indexOf(document.activeElement);
16449
+ if (i < 0) return;
16450
+ ev.preventDefault();
16451
+ var j = ev.key === 'Home' ? 0 : ev.key === 'End' ? bs.length - 1 : (i + (ev.key === 'ArrowRight' ? 1 : -1) + bs.length) % bs.length;
16452
+ bs[j].focus();
16453
+ bs[j].scrollIntoView({ block: 'nearest', inline: 'nearest' });
16454
+ });
16455
+
16456
+ // --- Polling ---
16457
+ function schedule(ms) { clearTimeout(timer); timer = setTimeout(poll, ms); }
16458
+ function poll() {
16459
+ clearTimeout(timer);
16460
+ if (document.hidden) return;
16461
+ schedule(panel.hidden ? ELSEWHERE : ON_CHAT);
16462
+ if (inflight) return;
16463
+ inflight = true;
16464
+ fetch('/api/app/chat/active', { credentials: 'same-origin', cache: 'no-store' })
16465
+ .then(function (r) { return r.ok ? r.json() : null; })
16466
+ .then(function (d) { if (d) update(d.conversations || []); })
16467
+ .catch(function () {}).then(function () { inflight = false; });
16468
+ }
16469
+ function update(next) {
16470
+ var now = {}, cur = C.current();
16471
+ delete watch[cur];
16472
+ next.forEach(function (c) {
16473
+ now[c.id] = c.state;
16474
+ var was = prev[c.id] || (watch[c.id] ? 'thinking' : null);
16475
+ if (c.state === 'done') { delete watch[c.id]; if (was === 'thinking' || was === 'answering') finished(c, cur); }
16476
+ });
16477
+ prev = now; items = next;
16478
+ render();
16479
+ }
16480
+ function finished(c, cur) {
16481
+ // On screen: the chat shows the answer (and says it) itself.
16482
+ if (c.id === cur) return;
16483
+ // Follow-ups typed for it while it ran go now.
16484
+ if (C.held(c.id)) C.flushHeld(c.id);
16485
+ banner(c);
16486
+ if (c.status === 'done') {
16487
+ document.dispatchEvent(new CustomEvent('ax-chat', { detail: { type: 'background', conversationId: c.id, agentName: nameOf(c), at: c.updatedAt } }));
16488
+ }
16489
+ }
16490
+
16491
+ // --- Banners, one at a time ---
16492
+ function banner(c) { waiting.push(c); if (!shown) nextBanner(); }
16493
+ function nextBanner() {
16494
+ var c = waiting.shift();
16495
+ if (!c) return;
16496
+ var b = document.createElement('div');
16497
+ b.className = 'cs-banner';
16498
+ b.style.setProperty('--cs-c', colorOf(c));
16499
+ b.innerHTML = '<button type="button" class="cs-banner-open"><strong></strong><span></span></button>' +
16500
+ '<button type="button" class="cs-banner-x" aria-label="Dismiss">\xD7</button>';
16501
+ b.querySelector('strong').textContent = nameOf(c) + (c.status === 'error' ? ' could not answer' : ' finished');
16502
+ b.querySelector('span').textContent = c.preview || '';
16503
+ b.querySelector('.cs-banner-open').addEventListener('click', function () {
16504
+ hide();
16505
+ var tab = document.getElementById('tab-chat');
16506
+ if (tab && panel.hidden) tab.click();
16507
+ C.open(c.id);
16508
+ });
16509
+ b.querySelector('.cs-banner-x').addEventListener('click', hide);
16510
+ // Held open while a finger or the keyboard is on it.
16511
+ b.addEventListener('focusin', function () { clearTimeout(hideTimer); });
16512
+ b.addEventListener('focusout', function () { hideTimer = setTimeout(hide, BANNER_MS); });
16513
+ shown = b;
16514
+ shelf.appendChild(b);
16515
+ hideTimer = setTimeout(hide, BANNER_MS);
16516
+ }
16517
+ function hide() {
16518
+ clearTimeout(hideTimer);
16519
+ if (shown) shown.remove();
16520
+ shown = null;
16521
+ if (waiting.length) setTimeout(nextBanner, 250);
16522
+ }
16523
+
16524
+ document.addEventListener('ax-chat', function (ev) {
16525
+ var d = ev.detail || {};
16526
+ if (d.type === 'detached' && d.conversationId) { watch[d.conversationId] = 1; render(); }
16527
+ else if (d.type === 'target') render();
16528
+ // A new turn: show its chip soon rather than at the next tick.
16529
+ else if (d.type === 'busy' && d.on) schedule(800);
16530
+ });
16531
+ document.addEventListener('visibilitychange', function () {
16532
+ if (!document.hidden) { poll(); return; }
16533
+ clearTimeout(timer);
16534
+ try { fetch('/api/app/chat/away', { method: 'POST', credentials: 'same-origin', keepalive: true }).catch(function () {}); } catch (e) {}
16535
+ });
16536
+ var tabs = document.querySelector('.tabs');
16537
+ if (tabs) tabs.addEventListener('click', function () { schedule(0); });
16538
+ window.AXStrip = { poll: poll, update: update, banner: banner };
16539
+ poll();
16540
+ })();
16541
+ `;var Po=`
16542
+ .cs { margin: 0 -2px; }
16543
+ .cs[hidden] { display: none; }
16544
+ .cs-list {
16545
+ list-style: none; margin: 0; padding: 2px; display: flex; gap: 6px;
16546
+ overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; scroll-snap-type: x proximity;
16547
+ }
16548
+ .cs-list::-webkit-scrollbar { display: none; }
16549
+ .cs-list li { flex: none; scroll-snap-align: start; }
16550
+ .cs-chip {
16551
+ display: inline-flex; align-items: center; gap: 7px; min-height: 44px; max-width: 62vw; padding: 0 12px;
16552
+ font: inherit; font-size: var(--ax-fs-sm); font-weight: 600; color: var(--ax-text); cursor: pointer; white-space: nowrap;
16553
+ border: 1.5px solid color-mix(in oklch, var(--cs-c) 45%, var(--ax-border)); border-radius: var(--ax-radius-pill);
16554
+ background: color-mix(in oklch, var(--cs-c) 9%, var(--ax-surface));
16555
+ }
16556
+ .cs-chip[aria-current="true"] { border-color: var(--cs-c); background: color-mix(in oklch, var(--cs-c) 22%, var(--ax-surface)); }
16557
+ .cs-name { overflow: hidden; text-overflow: ellipsis; }
16558
+ .cs-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--cs-c); }
16559
+ .cs-thinking .cs-dot { animation: cs-pulse 1.4s ease-in-out infinite; }
16560
+ .cs-answering .cs-dot { box-shadow: 0 0 0 3px color-mix(in oklch, var(--cs-c) 30%, transparent); animation: cs-pulse 0.8s ease-in-out infinite; }
16561
+ .cs-open .cs-dot { background: transparent; border: 2px solid var(--cs-c); width: 7px; height: 7px; }
16562
+ .cs-new {
16563
+ font-size: var(--ax-fs-xs); font-weight: 700; line-height: 1; padding: 3px 7px;
16564
+ border-radius: var(--ax-radius-pill); background: var(--ax-text); color: var(--ax-bg);
16565
+ }
16566
+ @keyframes cs-pulse { 50% { opacity: 0.3; } }
16567
+ .cs-banners {
16568
+ position: fixed; z-index: 40; left: 0; right: 0; top: calc(8px + env(safe-area-inset-top));
16569
+ display: grid; justify-items: center; padding: 0 calc(12px + env(safe-area-inset-right)) 0 calc(12px + env(safe-area-inset-left));
16570
+ pointer-events: none;
16571
+ }
16572
+ .cs-banner {
16573
+ pointer-events: auto; width: 100%; max-width: 520px; box-sizing: border-box; display: flex; align-items: stretch;
16574
+ background: var(--ax-surface); color: var(--ax-text); border: var(--ax-border-w) solid var(--ax-border);
16575
+ border-left: 5px solid var(--cs-c); border-radius: var(--ax-radius); box-shadow: var(--ax-shadow-lg);
16576
+ animation: cs-in 0.2s ease-out;
16577
+ }
16578
+ .cs-banner-open {
16579
+ flex: 1; min-width: 0; min-height: 56px; display: grid; gap: 2px; align-content: center; padding: 8px 12px;
16580
+ text-align: left; font: inherit; color: inherit; background: none; border: 0; cursor: pointer;
16581
+ }
16582
+ .cs-banner-open strong { font-size: var(--ax-fs-sm); }
16583
+ .cs-banner-open span {
16584
+ font-size: var(--ax-fs-xs); color: var(--ax-text-2); overflow: hidden;
16585
+ display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
16586
+ }
16587
+ .cs-banner-open span:empty { display: none; }
16588
+ .cs-banner-x { min-width: 44px; min-height: 44px; font: inherit; font-size: 20px; color: var(--ax-text-2); background: none; border: 0; cursor: pointer; }
16589
+ @keyframes cs-in { from { transform: translateY(-12px); opacity: 0; } }
16590
+ .al-finish { margin-top: 12px; min-height: 48px; }
16591
+ .al-finish p { margin: 0; font-weight: 600; }
16592
+ .al-finish small { display: block; font-weight: 400; font-size: var(--ax-fs-xs); color: var(--ax-text-2); }
16593
+ .al-finish .fx-switch::after { content: ""; position: absolute; inset: -8px; }
16594
+ @media (prefers-reduced-motion: reduce) {
16595
+ .cs-thinking .cs-dot, .cs-answering .cs-dot, .cs-banner { animation: none; }
16596
+ }
16597
+ `;function jo(t,e,a=5){if(t.some(o=>o.key===e.key))return{queue:t.slice(),dropped:[]};let n=t.concat([e]),r=Math.max(0,n.length-Math.max(1,a));return{queue:n.slice(r),dropped:n.slice(0,r)}}function Oo(t,e){return e||!t.length?{item:null,queue:t.slice()}:{item:t[0],queue:t.slice(1)}}var No=`
16140
16598
  body { height: 100dvh; }
16141
16599
  main { min-height: 0; }
16142
16600
  #panel-chat:not([hidden]) { display: flex; flex-direction: column; min-height: 100%; }
@@ -16230,6 +16688,8 @@ main { min-height: 0; }
16230
16688
  border: var(--ax-border-w) solid color-mix(in oklch, var(--ax-accent) 50%, var(--ax-border)); border-radius: var(--ax-radius-pill);
16231
16689
  background: color-mix(in oklch, var(--ax-accent) 12%, var(--ax-surface)); color: var(--ax-accent); text-decoration: none;
16232
16690
  }
16691
+ .cx-reply small { display: block; font-size: 0.8em; opacity: 0.75; }
16692
+ .cx-reply:disabled { cursor: default; opacity: 0.5; }
16233
16693
  .cx-ui fieldset { border: var(--ax-border-w) solid var(--ax-border); border-radius: var(--ax-radius-sm); margin: 0; padding: 8px 10px; display: grid; gap: 8px; }
16234
16694
  .cx-ui legend { font-weight: 600; padding: 0 4px; }
16235
16695
  .cx-ui label { display: flex; align-items: center; gap: 8px; min-height: 44px; }
@@ -16244,7 +16704,7 @@ main { min-height: 0; }
16244
16704
  background: color-mix(in oklch, var(--ax-accent) 15%, var(--ax-surface)); color: var(--ax-accent);
16245
16705
  }
16246
16706
  .cx-composer .fx-btn { border-radius: var(--ax-radius); }
16247
- `;var po=`
16707
+ `;var Do=`
16248
16708
  window.AXOrb = (function () {
16249
16709
  // Same list, order and hash as presenceLook (src/voice/presence.ts) and
16250
16710
  // OrbMath.colorHex, for an agent whose colour did not come with it.
@@ -16374,7 +16834,7 @@ window.AXOrb = (function () {
16374
16834
  }
16375
16835
  return { create: create, colorFor: colorFor, levelFromRms: levelFromRms, speakingEnvelope: speakingEnvelope };
16376
16836
  })();
16377
- `;var uo=`
16837
+ `;var Ho=`
16378
16838
  window.AXVoiceIO = (function () {
16379
16839
  var TYPES = ['audio/webm;codecs=opus', 'audio/mp4', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/aac'];
16380
16840
  var ac = null, playing = null;
@@ -16492,7 +16952,7 @@ window.AXVoiceIO = (function () {
16492
16952
 
16493
16953
  return { canRecord: canRecord, mimeType: mimeType, unlock: unlock, record: record, playAudio: playAudio, speakText: speakText, stop: stopPlaying };
16494
16954
  })();
16495
- `;var mo=`
16955
+ `;var Bo=`
16496
16956
  (function () {
16497
16957
  var panel = document.getElementById('panel-chat'), C = window.AXChat, IO = window.AXVoiceIO, O = window.AXOrb;
16498
16958
  if (!panel || !C || !IO || !O) return;
@@ -16516,7 +16976,9 @@ window.AXVoiceIO = (function () {
16516
16976
 
16517
16977
  function recall(k, d) { try { var v = localStorage.getItem(k); return v == null ? d : v === '1'; } catch (e) { return d; } }
16518
16978
  function remember(k, on) { try { localStorage.setItem(k, on ? '1' : '0'); } catch (e) {} }
16519
- var v = { state: 'idle', rec: null, pressed: false, cancel: false, t0: 0, timer: 0, speakOn: recall('ax-voice-speaker', true), typing: recall('ax-voice-typing', false) };
16979
+ var v = { state: 'idle', rec: null, pressed: false, cancel: false, t0: 0, timer: 0, speakOn: recall('ax-voice-speaker', true), typing: recall('ax-voice-typing', false), said: 0 };
16980
+ // Answers waiting to be said, oldest first.
16981
+ var speech = [], SPEECH_MAX = 5;
16520
16982
 
16521
16983
  var TEXT = {
16522
16984
  idle: 'Hold to talk', arming: 'Opening the microphone\u2026', listening: 'Listening\u2026 let go to send, slide away to cancel',
@@ -16532,7 +16994,7 @@ window.AXVoiceIO = (function () {
16532
16994
  status.classList.toggle('vx-bad', !!bad);
16533
16995
  orbBtn.querySelector('.cx-sr').textContent = state === 'speaking' ? 'Stop speaking' : 'Hold to talk';
16534
16996
  }
16535
- function idle(msg, bad) { show(C.busy() ? 'thinking' : 'idle', msg, bad); }
16997
+ function idle(msg, bad) { show(C.busy() ? 'thinking' : 'idle', msg, bad); setTimeout(pump, 0); }
16536
16998
  function tint() { var t = C.target(); orb.tint(O.colorFor(t && t.agent, t && t.color)); }
16537
16999
  function buzz(ms) { try { if (navigator.vibrate) navigator.vibrate(ms); } catch (e) {} }
16538
17000
 
@@ -16549,7 +17011,7 @@ window.AXVoiceIO = (function () {
16549
17011
  spkBtn.setAttribute('aria-pressed', on ? 'true' : 'false');
16550
17012
  spkBtn.setAttribute('aria-label', on ? 'Answers are read aloud. Tap to turn off.' : 'Answers are not read aloud. Tap to turn on.');
16551
17013
  spkBtn.classList.toggle('vx-off', !on);
16552
- if (!on && v.state === 'speaking') stopSpeaking();
17014
+ if (!on) { speech = []; if (v.state === 'speaking') stopSpeaking(); }
16553
17015
  }
16554
17016
  keysBtn.addEventListener('click', function () { setTyping(!v.typing, true); });
16555
17017
  spkBtn.addEventListener('click', function () { IO.unlock(); setSpeaker(!v.speakOn); });
@@ -16630,24 +17092,52 @@ window.AXVoiceIO = (function () {
16630
17092
  orbBtn.addEventListener('click', function (ev) { ev.preventDefault(); });
16631
17093
  document.addEventListener('visibilitychange', function () { if (document.hidden && v.rec) { v.cancel = true; release(false); } });
16632
17094
 
16633
- // --- Speaking the answer ---
16634
- function stopSpeaking() { IO.stop(); idle(); }
16635
- function speak(conversationId, text) {
17095
+ // --- Speaking answers, one at a time ---
17096
+ function stopSpeaking() { IO.stop(); speech = []; v.said++; idle(); }
17097
+ function enqueue(item) {
17098
+ if (!v.speakOn) return;
17099
+ var r = queueSpeech(speech, item, SPEECH_MAX);
17100
+ speech = r.queue;
17101
+ if (r.dropped.length) {
17102
+ var who = r.dropped.map(function (x) { return x.announce || 'this conversation'; }).join(', ');
17103
+ status.textContent = (v.state === 'speaking' ? TEXT.speaking + ' ' : '') + 'Too many answers waiting: skipped the oldest (' + who + ').';
17104
+ }
17105
+ pump();
17106
+ }
17107
+ function pump() {
17108
+ if (!v.speakOn) { speech = []; return; }
17109
+ var r = nextSpeech(speech, v.state !== 'idle' && v.state !== 'thinking');
17110
+ speech = r.queue;
17111
+ if (r.item) speak(r.item);
17112
+ }
17113
+ function speak(item) {
17114
+ var mine = ++v.said;
17115
+ var live = function () { return v.state === 'speaking' && mine === v.said; };
16636
17116
  show('speaking', null, false, null);
16637
- var began = function (meter) { if (v.state === 'speaking') show('speaking', null, false, meter); };
16638
- var done = function () { if (v.state === 'speaking') idle(); };
17117
+ var began = function (meter) { if (live()) show('speaking', null, false, meter); };
17118
+ var done = function () { if (live()) idle(); };
16639
17119
  var fallback = function (t) { return IO.speakText(t, began).catch(function () {}); };
16640
17120
  fetch('/api/app/voice/speak', {
16641
17121
  method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' },
16642
- body: JSON.stringify({ conversationId: conversationId, text: text }),
17122
+ body: JSON.stringify({ conversationId: item.conversationId, text: item.text, announce: !!item.announce }),
16643
17123
  }).then(function (r) {
16644
- if (v.state !== 'speaking') return null;
17124
+ if (!live()) return null;
16645
17125
  if (r.ok && (r.headers.get('content-type') || '').indexOf('audio/') === 0) {
16646
- return r.arrayBuffer().then(function (buf) { return v.state === 'speaking' ? IO.playAudio(buf, began) : null; });
17126
+ return r.arrayBuffer().then(function (buf) { return live() ? IO.playAudio(buf, began) : null; });
16647
17127
  }
16648
- return r.json().catch(function () { return {}; }).then(function (j) { return j.text && v.state === 'speaking' ? fallback(j.text) : null; });
17128
+ return r.json().catch(function () { return {}; }).then(function (j) { return j.text && live() ? fallback(j.text) : null; });
16649
17129
  }).catch(function () {}).then(done);
16650
17130
  }
17131
+ // A background answer: read the saved text without marking it read.
17132
+ function background(d) {
17133
+ if (!v.speakOn || !d.conversationId) return;
17134
+ fetch('/api/app/conversations/' + encodeURIComponent(d.conversationId) + '?peek=1', { credentials: 'same-origin' })
17135
+ .then(function (r) { return r.ok ? r.json() : null; }).then(function (c) {
17136
+ var last = c && (c.messages || []).filter(function (m) { return m.role === 'assistant'; }).pop();
17137
+ if (!last || last.status !== 'done' || !last.content) return;
17138
+ enqueue({ key: d.conversationId + ':' + last.at, conversationId: d.conversationId, text: last.content.slice(0, 8000), announce: d.agentName || c.agentName || c.agent });
17139
+ }).catch(function () {});
17140
+ }
16651
17141
 
16652
17142
  document.addEventListener('ax-chat', function (ev) {
16653
17143
  var d = ev.detail || {};
@@ -16658,8 +17148,8 @@ window.AXVoiceIO = (function () {
16658
17148
  } else if (d.type === 'final') {
16659
17149
  // Answers to what this phone just sent, spoken or typed; not one it
16660
17150
  // came back to later.
16661
- if (d.own && d.ok && d.content && d.conversationId && v.speakOn && v.state !== 'listening' && v.state !== 'cancel') speak(d.conversationId, d.content);
16662
- }
17151
+ if (d.own && d.ok && d.content && d.conversationId) enqueue({ key: d.conversationId + ':f' + Date.now(), conversationId: d.conversationId, text: d.content.slice(0, 8000) });
17152
+ } else if (d.type === 'background') background(d);
16663
17153
  });
16664
17154
  // Any tap in Chat unlocks audio, so a typed message's answer can play too.
16665
17155
  panel.addEventListener('pointerdown', function () { IO.unlock(); });
@@ -16668,9 +17158,9 @@ window.AXVoiceIO = (function () {
16668
17158
  setSpeaker(v.speakOn);
16669
17159
  tint();
16670
17160
  idle();
16671
- window.AXVoice = { show: show, orb: orb, state: function () { return v.state; } };
17161
+ window.AXVoice = { show: show, orb: orb, state: function () { return v.state; }, queued: function () { return speech.length; } };
16672
17162
  })();
16673
- `;var fo=`
17163
+ `;var zo=`
16674
17164
  .vx {
16675
17165
  position: sticky; bottom: -16px; z-index: 1; display: grid; justify-items: center; gap: 4px;
16676
17166
  margin: 0 0 -16px; padding: 8px 0 12px; background: var(--ax-bg);
@@ -16706,7 +17196,7 @@ window.AXVoiceIO = (function () {
16706
17196
  .cx-typing-on .vx-orb { width: 88px; height: 88px; }
16707
17197
  .cx-typing-on .vx-row { gap: 16px; }
16708
17198
  @media (prefers-reduced-motion: reduce) { .vx-orb { transition: none; } }
16709
- `;var ho=`
17199
+ `;var Fo=`
16710
17200
  <main class="card">
16711
17201
  <h1>This phone isn't paired</h1>
16712
17202
  <p>On the computer running AgentX, open a terminal in the folder that holds <code>agentx.json</code> and run <code>agentx app pair</code>. Scan the QR code it shows, or type the code under it.</p>
@@ -16720,7 +17210,7 @@ window.AXVoiceIO = (function () {
16720
17210
  <p id="pair-msg" class="pair-msg" role="status" aria-live="polite"></p>
16721
17211
  </form>
16722
17212
  <p class="muted">If this phone was paired before, it may have been removed with <code>agentx app revoke</code>.</p>
16723
- </main>`,go=`
17213
+ </main>`,qo=`
16724
17214
  .pair-form { display: grid; gap: 10px; margin: 20px 0 24px; }
16725
17215
  .pair-form label { font-weight: 600; }
16726
17216
  .pair-form input {
@@ -16742,7 +17232,7 @@ window.AXVoiceIO = (function () {
16742
17232
  margin: 0; padding: 8px 12px; border-radius: var(--ax-radius-sm); font-size: var(--ax-fs-sm);
16743
17233
  background: var(--ax-amber-t); color: var(--ax-amber-ink); border: 1px solid var(--ax-amber-e);
16744
17234
  }
16745
- `,xo=`
17235
+ `,Uo=`
16746
17236
  (function () {
16747
17237
  var form = document.getElementById('pair-form');
16748
17238
  var input = document.getElementById('pair-code');
@@ -16834,7 +17324,7 @@ window.AXVoiceIO = (function () {
16834
17324
  navigator.serviceWorker.register('/app/sw.js', { scope: '/app' }).catch(function () {});
16835
17325
  }
16836
17326
  })();
16837
- `;function vo(t){return t>=200&&t<300?"retry":t===401?"lock":"keep"}function bo(t,e){return!t||e-t>=3e4||t>e}function yo(t,e){let a="23456789ABCDEFGHJKMNPQRSTUVWXYZ",n=String(t||"").toUpperCase(),r=Math.max(0,Math.min(Number(e)||0,n.length)),o="",s=0;for(let l=0;l<n.length&&o.length<8;l++)a.indexOf(n.charAt(l))<0||(o+=n.charAt(l),l<r&&s++);let i=o.length>4?o.slice(0,4)+"-"+o.slice(4):o;return{value:i,caret:Math.min(s>4?s+1:s,i.length)}}function wo(t){let e=String(t||"").trim(),a=/^https?:[/][/][^/#?]+[/]app[/]pair[/]?#(.*)$/i.exec(e);if(a){let r=a[1].split("&");for(let o=0;o<r.length;o++){if(r[o].indexOf("token=")!==0)continue;let s="";try{s=decodeURIComponent(r[o].slice(6))}catch{return{kind:"none"}}return/^agx_live_[0-9a-f]{64}$/.test(s)?{kind:"token",token:s}:{kind:"none"}}return{kind:"none"}}let n=e.toUpperCase();return/^[A-Z0-9]{4}-?[A-Z0-9]{4}$/.test(n)?{kind:"code",code:n.slice(0,4)+"-"+n.slice(-4)}:{kind:"none"}}var ko=`
17327
+ `;function Wo(t){return t>=200&&t<300?"retry":t===401?"lock":"keep"}function Go(t,e){return!t||e-t>=3e4||t>e}function Xo(t,e){let a="23456789ABCDEFGHJKMNPQRSTUVWXYZ",n=String(t||"").toUpperCase(),r=Math.max(0,Math.min(Number(e)||0,n.length)),o="",s=0;for(let l=0;l<n.length&&o.length<8;l++)a.indexOf(n.charAt(l))<0||(o+=n.charAt(l),l<r&&s++);let i=o.length>4?o.slice(0,4)+"-"+o.slice(4):o;return{value:i,caret:Math.min(s>4?s+1:s,i.length)}}function Ko(t){let e=String(t||"").trim(),a=/^https?:[/][/][^/#?]+[/]app[/]pair[/]?#(.*)$/i.exec(e);if(a){let r=a[1].split("&");for(let o=0;o<r.length;o++){if(r[o].indexOf("token=")!==0)continue;let s="";try{s=decodeURIComponent(r[o].slice(6))}catch{return{kind:"none"}}return/^agx_live_[0-9a-f]{64}$/.test(s)?{kind:"token",token:s}:{kind:"none"}}return{kind:"none"}}let n=e.toUpperCase();return/^[A-Z0-9]{4}-?[A-Z0-9]{4}$/.test(n)?{kind:"code",code:n.slice(0,4)+"-"+n.slice(-4)}:{kind:"none"}}var Jo=`
16838
17328
  <div id="scan" class="scan" role="dialog" aria-modal="true" aria-labelledby="scan-title" hidden>
16839
17329
  <video id="scan-video" playsinline muted autoplay></video>
16840
17330
  <div class="scan-frame" aria-hidden="true"></div>
@@ -16843,7 +17333,7 @@ window.AXVoiceIO = (function () {
16843
17333
  <button type="button" id="scan-close" class="scan-close">Close</button>
16844
17334
  </div>
16845
17335
  <p id="scan-msg" class="scan-msg" role="status" aria-live="polite">Point the camera at the QR code shown by agentx app pair.</p>
16846
- </div>`,_o=`
17336
+ </div>`,Vo=`
16847
17337
  .pair-form .scan-btn {
16848
17338
  color: var(--ax-accent-2, var(--ax-accent)); background: transparent; border: 2px solid var(--ax-accent);
16849
17339
  }
@@ -16872,7 +17362,7 @@ window.AXVoiceIO = (function () {
16872
17362
  }
16873
17363
  .scan-msg.bad { color: #ffd0cc; font-weight: 600; }
16874
17364
  body.scanning { overflow: hidden; }
16875
- `,Eo=`
17365
+ `,Yo=`
16876
17366
  (function () {
16877
17367
  var openBtn = document.getElementById('scan-btn');
16878
17368
  var box = document.getElementById('scan');
@@ -17038,8 +17528,8 @@ body.scanning { overflow: hidden; }
17038
17528
  document.addEventListener('visibilitychange', function () { if (document.hidden) close(); });
17039
17529
  window.addEventListener('pagehide', close);
17040
17530
  })();
17041
- `;var Vt=`
17042
- ${te({afterUnauthorized:vo})}
17531
+ `;var aa=`
17532
+ ${V({afterUnauthorized:Wo})}
17043
17533
  var CACHE = 'agentx-app-v3';
17044
17534
  var STATIC = ['/app/manifest.webmanifest', '/app/icon-192.png', '/app/icon-512.png'];
17045
17535
  self.addEventListener('install', function (e) {
@@ -17130,7 +17620,7 @@ self.addEventListener('notificationclick', function (e) {
17130
17620
  return self.clients.openWindow(target);
17131
17621
  }));
17132
17622
  });
17133
- `;var Uc="<script>(function(){var t;try{t=localStorage.getItem('ax-theme')}catch(e){}if(t!=='light'&&t!=='dark'){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)})();</script>";function Yt(t){return`<meta charset="utf-8">
17623
+ `;var Ed="<script>(function(){var t;try{t=localStorage.getItem('ax-theme')}catch(e){}if(t!=='light'&&t!=='dark'){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)})();</script>";function na(t){return`<meta charset="utf-8">
17134
17624
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
17135
17625
  <meta name="theme-color" content="#2979FF">
17136
17626
  <meta name="referrer" content="no-referrer">
@@ -17141,13 +17631,13 @@ self.addEventListener('notificationclick', function (e) {
17141
17631
  <link rel="icon" type="image/png" href="/app/icon-192.png">
17142
17632
  <link rel="apple-touch-icon" href="/app/icon-192.png">
17143
17633
  <title>${t}</title>
17144
- ${Uc}
17145
- <style>${Ua}${Gc}</style>`}var So=[{id:"chat",label:"Chat",soon:"Loading your conversations\u2026"},{id:"fleet",label:"Fleet",soon:"Loading your machines\u2026"},{id:"activity",label:"Activity",soon:"Loading what your agents are doing\u2026"},{id:"alerts",label:"Alerts",soon:"Loading notifications\u2026"}];function To(){let t=So.map((a,n)=>`<button type="button" role="tab" id="tab-${a.id}" aria-controls="panel-${a.id}" aria-selected="${n===0}" tabindex="${n===0?0:-1}" data-tab="${a.id}">${a.label}</button>`).join(""),e=So.map((a,n)=>`<section role="tabpanel" id="panel-${a.id}" aria-labelledby="tab-${a.id}" tabindex="0"${n===0?"":" hidden"}>
17634
+ ${Ed}
17635
+ <style>${Ya}${Ad}</style>`}var Qo=[{id:"chat",label:"Chat",soon:"Loading your conversations\u2026"},{id:"fleet",label:"Fleet",soon:"Loading your machines\u2026"},{id:"activity",label:"Activity",soon:"Loading what your agents are doing\u2026"},{id:"alerts",label:"Alerts",soon:"Loading notifications\u2026"}];function Zo(){let t=Qo.map((a,n)=>`<button type="button" role="tab" id="tab-${a.id}" aria-controls="panel-${a.id}" aria-selected="${n===0}" tabindex="${n===0?0:-1}" data-tab="${a.id}">${a.label}</button>`).join(""),e=Qo.map((a,n)=>`<section role="tabpanel" id="panel-${a.id}" aria-labelledby="tab-${a.id}" tabindex="0"${n===0?"":" hidden"}>
17146
17636
  <h2>${a.label}</h2>
17147
17637
  <p class="soon">${a.soon}</p>
17148
17638
  </section>`).join("");return`<!doctype html>
17149
17639
  <html lang="en">
17150
- <head>${Yt("AgentX")}<style>${Xc}${oo}${co}${fo}</style></head>
17640
+ <head>${na("AgentX")}<style>${Cd}${To}${No}${Po}${zo}</style></head>
17151
17641
  <body>
17152
17642
  <header class="bar">
17153
17643
  <div>
@@ -17159,34 +17649,36 @@ ${Uc}
17159
17649
  <p id="offline" class="offline" role="status" hidden>Offline. Showing the saved app; live data needs a connection.</p>
17160
17650
  <main>${e}</main>
17161
17651
  <nav class="tabs" role="tablist" aria-label="Sections">${t}</nav>
17162
- <script>${qc}</script>
17163
- <script>${ro}</script>
17164
- <script>${so}</script>
17165
- <script>${te({markdownToHtml:qa})}${lo}${io}</script>
17166
- <script>${po}${uo}${mo}</script>
17652
+ <script>${Sd}</script>
17653
+ <script>${So}</script>
17654
+ <script>${Ao}</script>
17655
+ <script>${Co}</script>
17656
+ <script>${V({markdownToHtml:Qa})}${Io}${$o}${Lo}${Mo}</script>
17657
+ <script>${V({queueSpeech:jo,nextSpeech:Oo})}${Do}${Ho}${Bo}</script>
17658
+ <script>${Ro}</script>
17167
17659
  </body>
17168
- </html>`}function Co(){return`<!doctype html>
17660
+ </html>`}function es(){return`<!doctype html>
17169
17661
  <html lang="en">
17170
- <head>${Yt("Pair \xB7 AgentX")}</head>
17662
+ <head>${na("Pair \xB7 AgentX")}</head>
17171
17663
  <body>
17172
17664
  <main class="card">
17173
17665
  <h1>Pairing this phone\u2026</h1>
17174
17666
  <p id="msg" role="status">One moment.</p>
17175
17667
  </main>
17176
- <script>${Wc}</script>
17668
+ <script>${Td}</script>
17177
17669
  </body>
17178
- </html>`}function Ao(){return`<!doctype html>
17670
+ </html>`}function ts(){return`<!doctype html>
17179
17671
  <html lang="en">
17180
- <head>${Yt("Not paired \xB7 AgentX")}<style>${go}${_o}</style></head>
17181
- <body>${ho}${ko}
17182
- <script>${te({mayBounce:bo,formatPairInput:yo,parsePairScan:wo})}</script>
17183
- <script>${xo}</script>
17184
- <script>${Eo}</script>
17672
+ <head>${na("Not paired \xB7 AgentX")}<style>${qo}${Vo}</style></head>
17673
+ <body>${Fo}${Jo}
17674
+ <script>${V({mayBounce:Go,formatPairInput:Xo,parsePairScan:Ko})}</script>
17675
+ <script>${Uo}</script>
17676
+ <script>${Yo}</script>
17185
17677
  </body>
17186
- </html>`}function Mo(){return JSON.stringify({id:"/app",name:"AgentX",short_name:"AgentX",description:"Talk to your agents and watch your fleet.",start_url:"/app",scope:"/app",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/app/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var qc=`
17678
+ </html>`}function as(){return JSON.stringify({id:"/app",name:"AgentX",short_name:"AgentX",description:"Talk to your agents and watch your fleet.",start_url:"/app",scope:"/app",display:"standalone",background_color:"#2979FF",theme_color:"#2979FF",icons:[{src:"/app/icon-192.png",sizes:"192x192",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"any"},{src:"/app/icon-512.png",sizes:"512x512",type:"image/png",purpose:"maskable"}]})}var Sd=`
17187
17679
  (function () {
17188
17680
  var tabs = Array.prototype.slice.call(document.querySelectorAll('[role=tab]'));
17189
- function select(tab, focus) {
17681
+ function select(tab, focus, keepHash) {
17190
17682
  tabs.forEach(function (t) {
17191
17683
  var on = t === tab;
17192
17684
  t.setAttribute('aria-selected', on ? 'true' : 'false');
@@ -17194,6 +17686,7 @@ ${Uc}
17194
17686
  document.getElementById(t.getAttribute('aria-controls')).hidden = !on;
17195
17687
  });
17196
17688
  if (focus) tab.focus();
17689
+ if (keepHash) return;
17197
17690
  try { history.replaceState(null, '', '#' + tab.dataset.tab); } catch (e) {}
17198
17691
  }
17199
17692
  tabs.forEach(function (t, i) {
@@ -17207,9 +17700,12 @@ ${Uc}
17207
17700
  if (next) { ev.preventDefault(); select(next, true); }
17208
17701
  });
17209
17702
  });
17703
+ // #chat=<id> (a notification's link) opens Chat; the Chat script reads
17704
+ // the id, so the hash is left as it is.
17210
17705
  function fromHash() {
17211
- var t = tabs.filter(function (t) { return '#' + t.dataset.tab === location.hash; })[0];
17212
- if (t) select(t, false);
17706
+ var name = location.hash.split('=')[0];
17707
+ var t = tabs.filter(function (t) { return '#' + t.dataset.tab === name; })[0];
17708
+ if (t) select(t, false, true);
17213
17709
  }
17214
17710
  fromHash();
17215
17711
  window.addEventListener('hashchange', fromHash);
@@ -17249,7 +17745,7 @@ ${Uc}
17249
17745
  navigator.serviceWorker.register('/app/sw.js', { scope: '/app' }).catch(function () {});
17250
17746
  }
17251
17747
  })();
17252
- `,Wc=`
17748
+ `,Td=`
17253
17749
  (function () {
17254
17750
  var msg = document.getElementById('msg');
17255
17751
  var m = /(?:^#|&)token=([^&]+)/.exec(location.hash);
@@ -17266,7 +17762,7 @@ ${Uc}
17266
17762
  : 'Pairing failed (HTTP ' + r.status + '). Try again.';
17267
17763
  }).catch(function () { msg.textContent = 'Could not reach AgentX. Check this phone is on your tailnet, then try again.'; });
17268
17764
  })();
17269
- `,Gc=`
17765
+ `,Ad=`
17270
17766
  html, body { margin: 0; background: var(--ax-bg); color: var(--ax-text); font-family: var(--ax-font); }
17271
17767
  body { min-height: 100dvh; -webkit-text-size-adjust: 100%; }
17272
17768
  code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surface-3); padding: 1px 6px; border-radius: 6px; }
@@ -17278,7 +17774,7 @@ code { font-family: var(--ax-mono); font-size: 0.92em; background: var(--ax-surf
17278
17774
  .card h1 { font-size: 22px; margin: 0 0 12px; }
17279
17775
  .muted { color: var(--ax-text-2); }
17280
17776
  :focus-visible { outline: 3px solid var(--ax-accent); outline-offset: 2px; }
17281
- `,Xc=`
17777
+ `,Cd=`
17282
17778
  body { display: flex; flex-direction: column; }
17283
17779
  .bar {
17284
17780
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
@@ -17315,8 +17811,8 @@ main h2 { font-size: 20px; margin: 4px 0 8px; }
17315
17811
  }
17316
17812
  .tabs [role=tab][aria-selected=true] { background: var(--ax-accent-t); color: var(--ax-accent-2); }
17317
17813
  [data-theme="dark"] .tabs [role=tab][aria-selected=true] { color: var(--ax-text); }
17318
- `;var ft="agentx_app",Vc=400*86400,Yc=new ut,Qc=new mt;async function Io(t,e,a,n,r={}){if(a!=="/app"&&!a.startsWith("/app/")&&!a.startsWith("/api/app/"))return!1;let o=r.tokens??new Z;if(n==="GET"){if(a==="/app/manifest.webmanifest")return me(e,200,"application/manifest+json",Mo());if(a==="/app/sw.js")return e.setHeader("Service-Worker-Allowed","/app"),me(e,200,"text/javascript; charset=utf-8",Vt);if(a==="/app/icon-192.png")return me(e,200,"image/png",Gt(192),"public, max-age=86400");if(a==="/app/icon-512.png")return me(e,200,"image/png",Gt(512),"public, max-age=86400");if(a==="/app/pair")return me(e,200,"text/html; charset=utf-8",Co());if(a==="/app/qr.js"){let i=Zc();return i?me(e,200,"text/javascript; charset=utf-8",i,"public, max-age=2592000"):Ee(e,404,{error:"not found"})}}if(n==="POST"&&a==="/api/app/session"){let i=Qt(He(t),o);return i?(e.setHeader("Set-Cookie",Zt(He(t))),Ee(e,200,{device:i.name})):Ee(e,401,{error:"invalid or revoked device token"})}if(n==="POST"&&a==="/api/app/pair-code"){let i=await to(t,{codes:r.pairCodes??new Za,limiter:r.pairLimiter??Yc,verify:l=>Qt(l,o)?.name??null,minMs:r.pairMinMs});return i.status===200&&e.setHeader("Set-Cookie",Zt(i.token)),i.status===429&&e.setHeader("Retry-After",String(i.retryAfter)),Ee(e,i.status,i.body)}let s=Qt(ed(t),o);if(!s){let i=He(t);return(r.rejectLog??Qc).record(a.slice(0,120),no(t,Jt(ea(t,ft),o),i?Jt(i,o):null)),a==="/app"?me(e,401,"text/html; charset=utf-8",Ao()):Ee(e,401,{error:"this device is not paired",hint:"run: agentx app pair"})}if(n==="GET"&&a==="/app"){let i=ea(t,ft);return i&&!He(t)&&e.setHeader("Set-Cookie",Zt(i)),me(e,200,"text/html; charset=utf-8",To())}return n==="GET"&&a==="/api/app/me"?Ee(e,200,{id:s.id,device:s.name,node:r.nodeName??null}):r.fleet&&await zr(t,e,a,n,s.name,r.fleet)||r.push&&await Ur(t,e,a,n,s,r.push)||r.chat&&await Xr(t,e,a,n,s,r.chat)||r.chat&&await Yr(t,e,a,n,s,r.chat)||r.voice&&await eo(t,e,a,n,s,r.voice)?!0:Ee(e,404,{error:"not found"})}var De;function Zc(){if(De!==void 0)return De;try{let t=Jc(import.meta.url),{version:e}=t("jsqr/package.json"),a=`/*! jsQR ${e} | Apache-2.0 | https://github.com/cozmo/jsQR */
17319
- `;De=Buffer.concat([Buffer.from(a),Kc(t.resolve("jsqr"))])}catch(t){console.error(`[app] QR decoder unavailable (install the jsqr package): ${t.message}`),De=null}return De}function Qt(t,e){if(!t)return null;let a=e.verify(t);return a&&ve(a,"app")?a:null}function Zt(t){return`${ft}=${t}; Path=/; Max-Age=${Vc}; HttpOnly; Secure; SameSite=Lax`}function ed(t){return He(t)??ea(t,ft)}function He(t){let e=t.headers.authorization||"";return e.toLowerCase().startsWith("bearer ")&&e.slice(7).trim()||null}function ea(t,e){for(let a of(t.headers.cookie||"").split(";")){let n=a.indexOf("=");if(n>0&&a.slice(0,n).trim()===e)return a.slice(n+1).trim()||null}return null}function me(t,e,a,n,r="no-store"){return t.writeHead(e,{"Content-Type":a,"Cache-Control":r}),t.end(n),!0}function Ee(t,e,a){return me(t,e,"application/json",JSON.stringify(a))}import{randomBytes as $o}from"crypto";var Se={content:32e3,messagesPerConversation:200,conversationsPerDevice:100,toolsPerMessage:50,filesPerMessage:he.perMessage},td=/^[a-f0-9]{32}$/,ad=/^c[a-z0-9]{8,32}$/;function nd(t){return ad.test(t)}var Be=class{constructor(e){this.db=e;e.exec(`CREATE TABLE IF NOT EXISTS app_chat_conversations (
17814
+ `;var gt="agentx_app",Ld=400*86400,$d=new ft,Rd=new ht;async function ns(t,e,a,n,r={}){if(a!=="/app"&&!a.startsWith("/app/")&&!a.startsWith("/api/app/"))return!1;let o=r.tokens??new ae;if(n==="GET"){if(a==="/app/manifest.webmanifest")return fe(e,200,"application/manifest+json",as());if(a==="/app/sw.js")return e.setHeader("Service-Worker-Allowed","/app"),fe(e,200,"text/javascript; charset=utf-8",aa);if(a==="/app/icon-192.png")return fe(e,200,"image/png",Kt(192),"public, max-age=86400");if(a==="/app/icon-512.png")return fe(e,200,"image/png",Kt(512),"public, max-age=86400");if(a==="/app/pair")return fe(e,200,"text/html; charset=utf-8",es());if(a==="/app/qr.js"){let i=Pd();return i?fe(e,200,"text/javascript; charset=utf-8",i,"public, max-age=2592000"):Te(e,404,{error:"not found"})}}if(n==="POST"&&a==="/api/app/session"){let i=ra(ze(t),o);return i?(e.setHeader("Set-Cookie",oa(ze(t))),Te(e,200,{device:i.name})):Te(e,401,{error:"invalid or revoked device token"})}if(n==="POST"&&a==="/api/app/pair-code"){let i=await ko(t,{codes:r.pairCodes??new ln,limiter:r.pairLimiter??$d,verify:l=>ra(l,o)?.name??null,minMs:r.pairMinMs});return i.status===200&&e.setHeader("Set-Cookie",oa(i.token)),i.status===429&&e.setHeader("Retry-After",String(i.retryAfter)),Te(e,i.status,i.body)}let s=ra(jd(t),o);if(!s){let i=ze(t);return(r.rejectLog??Rd).record(a.slice(0,120),Eo(t,ta(sa(t,gt),o),i?ta(i,o):null)),a==="/app"?fe(e,401,"text/html; charset=utf-8",ts()):Te(e,401,{error:"this device is not paired",hint:"run: agentx app pair"})}if(n==="GET"&&a==="/app"){let i=sa(t,gt);return i&&!ze(t)&&e.setHeader("Set-Cookie",oa(i)),fe(e,200,"text/html; charset=utf-8",Zo())}return n==="GET"&&a==="/api/app/me"?Te(e,200,{id:s.id,device:s.name,node:r.nodeName??null}):r.fleet&&await Jr(t,e,a,n,s.name,r.fleet)||r.push&&await Yr(t,e,a,n,s,r.push)||r.announce&&await eo(t,e,a,n,s,r.announce)||r.chat&&await fo(t,e,a,n,s,r.chat)||r.chat&&await vo(t,e,a,n,s,r.chat)||r.voice&&await wo(t,e,a,n,s,r.voice)?!0:Te(e,404,{error:"not found"})}var Be;function Pd(){if(Be!==void 0)return Be;try{let t=Id(import.meta.url),{version:e}=t("jsqr/package.json"),a=`/*! jsQR ${e} | Apache-2.0 | https://github.com/cozmo/jsQR */
17815
+ `;Be=Buffer.concat([Buffer.from(a),Md(t.resolve("jsqr"))])}catch(t){console.error(`[app] QR decoder unavailable (install the jsqr package): ${t.message}`),Be=null}return Be}function ra(t,e){if(!t)return null;let a=e.verify(t);return a&&be(a,"app")?a:null}function oa(t){return`${gt}=${t}; Path=/; Max-Age=${Ld}; HttpOnly; Secure; SameSite=Lax`}function jd(t){return ze(t)??sa(t,gt)}function ze(t){let e=t.headers.authorization||"";return e.toLowerCase().startsWith("bearer ")&&e.slice(7).trim()||null}function sa(t,e){for(let a of(t.headers.cookie||"").split(";")){let n=a.indexOf("=");if(n>0&&a.slice(0,n).trim()===e)return a.slice(n+1).trim()||null}return null}function fe(t,e,a,n,r="no-store"){return t.writeHead(e,{"Content-Type":a,"Cache-Control":r}),t.end(n),!0}function Te(t,e,a){return fe(t,e,"application/json",JSON.stringify(a))}import{randomBytes as rs}from"crypto";var Ae={content:32e3,messagesPerConversation:200,conversationsPerDevice:100,toolsPerMessage:50,filesPerMessage:ge.perMessage},Od=/^[a-f0-9]{32}$/,Nd=/^c[a-z0-9]{8,32}$/,Dd=/^#[0-9a-fA-F]{6}$/;function os(t){return Nd.test(t)}var Fe=class{constructor(e){this.db=e;e.exec(`CREATE TABLE IF NOT EXISTS app_chat_conversations (
17320
17816
  id TEXT PRIMARY KEY, device_id TEXT NOT NULL, title TEXT NOT NULL,
17321
17817
  node TEXT NOT NULL, node_name TEXT NOT NULL, agent TEXT NOT NULL, agent_name TEXT,
17322
17818
  created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL);
@@ -17328,33 +17824,39 @@ main h2 { font-size: 20px; margin: 4px 0 8px; }
17328
17824
  CREATE TABLE IF NOT EXISTS app_chat_files (
17329
17825
  id TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, message_id INTEGER NOT NULL,
17330
17826
  path TEXT NOT NULL, name TEXT NOT NULL, mime TEXT NOT NULL, kind TEXT NOT NULL, created_at INTEGER NOT NULL);
17331
- CREATE INDEX IF NOT EXISTS app_chat_files_conversation ON app_chat_files(conversation_id);`),e.prepare("PRAGMA table_info(app_chat_messages)").all().some(n=>n.name==="files")||e.exec("ALTER TABLE app_chat_messages ADD COLUMN files TEXT")}create(e,a,n,r=Date.now()){let o=`c${r.toString(36)}${$o(4).toString("hex")}`,s={id:o,title:od(n),...a,createdAt:r,updatedAt:r,messages:[]};return this.db.prepare(`INSERT INTO app_chat_conversations
17332
- (id, device_id, title, node, node_name, agent, agent_name, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,e,s.title,s.node,s.nodeName,s.agent,s.agentName??null,r,r),this.pruneDevice(e),s}get(e,a){if(!nd(a))return null;let n=this.db.prepare("SELECT * FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e);if(!n)return null;let r=this.db.prepare("SELECT * FROM app_chat_messages WHERE conversation_id = ? ORDER BY id").all(a).map(rd);return{...Lo(n),messages:r}}list(e,a=Se.conversationsPerDevice){return this.db.prepare(`SELECT c.*,
17827
+ CREATE INDEX IF NOT EXISTS app_chat_files_conversation ON app_chat_files(conversation_id);`),e.prepare("PRAGMA table_info(app_chat_messages)").all().some(r=>r.name==="files")||e.exec("ALTER TABLE app_chat_messages ADD COLUMN files TEXT");let n=e.prepare("PRAGMA table_info(app_chat_conversations)").all();n.some(r=>r.name==="read_at")||e.transaction(()=>{e.prepare("PRAGMA table_info(app_chat_conversations)").all().some(o=>o.name==="read_at")||(e.exec("ALTER TABLE app_chat_conversations ADD COLUMN read_at INTEGER"),e.exec("UPDATE app_chat_conversations SET read_at = updated_at"))}).immediate(),n.some(r=>r.name==="color")||e.exec("ALTER TABLE app_chat_conversations ADD COLUMN color TEXT")}create(e,a,n,r=Date.now()){let o=`c${r.toString(36)}${rs(4).toString("hex")}`,{color:s,...i}=a,l=s&&Dd.test(s)?s:void 0,c={id:o,title:Bd(n),...i,...l?{color:l}:{},createdAt:r,updatedAt:r,messages:[]};return this.db.prepare(`INSERT INTO app_chat_conversations
17828
+ (id, device_id, title, node, node_name, agent, agent_name, color, created_at, updated_at, read_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,e,c.title,c.node,c.nodeName,c.agent,c.agentName??null,l??null,r,r,r),this.pruneDevice(e),c}get(e,a){if(!os(a))return null;let n=this.db.prepare("SELECT * FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e);if(!n)return null;let r=this.db.prepare("SELECT * FROM app_chat_messages WHERE conversation_id = ? ORDER BY id").all(a).map(Hd);return{...ss(n),messages:r}}list(e,a=Ae.conversationsPerDevice){return this.db.prepare(`SELECT c.*,
17333
17829
  (SELECT COUNT(*) FROM app_chat_messages m WHERE m.conversation_id = c.id) AS n,
17334
17830
  (SELECT substr(m.content, 1, 240) FROM app_chat_messages m WHERE m.conversation_id = c.id ORDER BY m.id DESC LIMIT 1) AS last
17335
- FROM app_chat_conversations c WHERE c.device_id = ? ORDER BY c.updated_at DESC, c.rowid DESC LIMIT ?`).all(e,Math.max(0,a)).map(r=>{let o=typeof r.last=="string"?r.last.replace(/\s+/g," ").trim().slice(0,120):"";return{...Lo(r),messages:r.n,...o?{last:o}:{}}})}append(e,a,n){return this.appendWithFiles(e,a,n)!==null}appendWithFiles(e,a,n,r=[]){if(!this.db.prepare("SELECT 1 FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e))return null;let s=n.content.length>Se.content?n.content.slice(0,Se.content)+`
17336
-
17337
- [Cut here: the full answer is in the agent's task history.]`:n.content,i=n.tools?.slice(0,Se.toolsPerMessage),l=[];for(let f of r){if(l.length>=Se.filesPerMessage)break;let h=f.filename.trim(),y=fa(h);if(!y||!h||h.length>he.pathChars||h.includes("\0"))continue;let T=(h.split(/[\\/]/).pop()||h).slice(0,120);l.push({id:$o(16).toString("hex"),name:T,mime:y.mime,kind:y.kind,path:h})}let c=l.map(f=>({id:f.id,name:f.name,mime:f.mime,kind:f.kind})),p=this.db.prepare(`INSERT INTO app_chat_messages (conversation_id, role, content, status, error, ui, tools, files, at)
17831
+ FROM app_chat_conversations c WHERE c.device_id = ? ORDER BY c.updated_at DESC, c.rowid DESC LIMIT ?`).all(e,Math.max(0,a)).map(r=>{let o=typeof r.last=="string"?r.last.replace(/\s+/g," ").trim().slice(0,120):"";return{...ss(r),messages:r.n,...o?{last:o}:{}}})}markRead(e,a,n=Date.now()){os(a)&&this.db.prepare("UPDATE app_chat_conversations SET read_at = MAX(COALESCE(read_at, 0), ?) WHERE id = ? AND device_id = ?").run(n,a,e)}unread(e,a){return this.db.prepare(`SELECT c.id, c.title, c.agent, c.agent_name, c.color,
17832
+ substr(m.content, 1, 240) AS answer, m.status, m.at
17833
+ FROM app_chat_conversations c
17834
+ JOIN app_chat_messages m ON m.id = (SELECT MAX(id) FROM app_chat_messages WHERE conversation_id = c.id)
17835
+ WHERE c.device_id = ? AND m.role = 'assistant' AND m.at > COALESCE(c.read_at, 0)
17836
+ ORDER BY m.at DESC, m.id DESC LIMIT ?`).all(e,Math.max(0,a)).map(r=>({id:r.id,title:r.title,agent:r.agent,...r.agent_name?{agentName:r.agent_name}:{},...r.color?{color:r.color}:{},answer:String(r.answer??"").trim(),status:r.status==="error"||r.status==="stopped"?r.status:"done",at:r.at}))}append(e,a,n){return this.appendWithFiles(e,a,n)!==null}appendWithFiles(e,a,n,r=[]){if(!this.db.prepare("SELECT 1 FROM app_chat_conversations WHERE id = ? AND device_id = ?").get(a,e))return null;let s=n.content.length>Ae.content?n.content.slice(0,Ae.content)+`
17837
+
17838
+ [Cut here: the full answer is in the agent's task history.]`:n.content,i=n.tools?.slice(0,Ae.toolsPerMessage),l=[];for(let f of r){if(l.length>=Ae.filesPerMessage)break;let h=f.filename.trim(),v=wa(h);if(!v||!h||h.length>ge.pathChars||h.includes("\0"))continue;let T=(h.split(/[\\/]/).pop()||h).slice(0,120);l.push({id:rs(16).toString("hex"),name:T,mime:v.mime,kind:v.kind,path:h})}let c=l.map(f=>({id:f.id,name:f.name,mime:f.mime,kind:f.kind})),p=this.db.prepare(`INSERT INTO app_chat_messages (conversation_id, role, content, status, error, ui, tools, files, at)
17338
17839
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(a,n.role,s,n.status??null,n.error?.slice(0,500)??null,n.ui?JSON.stringify(n.ui):null,i?.length?JSON.stringify(i):null,c.length?JSON.stringify(c):null,n.at),u=this.db.prepare(`INSERT INTO app_chat_files (id, conversation_id, message_id, path, name, mime, kind, created_at)
17339
17840
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);for(let f of l)u.run(f.id,a,Number(p.lastInsertRowid),f.path,f.name,f.mime,f.kind,n.at);return this.db.prepare(`DELETE FROM app_chat_messages WHERE conversation_id = ? AND id NOT IN
17340
- (SELECT id FROM app_chat_messages WHERE conversation_id = ? ORDER BY id DESC LIMIT ?)`).run(a,a,Se.messagesPerConversation),this.db.prepare(`DELETE FROM app_chat_files WHERE conversation_id = ? AND message_id NOT IN
17341
- (SELECT id FROM app_chat_messages WHERE conversation_id = ?)`).run(a,a),this.db.prepare("UPDATE app_chat_conversations SET updated_at = ? WHERE id = ?").run(n.at,a),c}getFile(e,a){if(!td.test(a))return null;let n=this.db.prepare(`SELECT f.*, c.node, c.agent FROM app_chat_files f
17841
+ (SELECT id FROM app_chat_messages WHERE conversation_id = ? ORDER BY id DESC LIMIT ?)`).run(a,a,Ae.messagesPerConversation),this.db.prepare(`DELETE FROM app_chat_files WHERE conversation_id = ? AND message_id NOT IN
17842
+ (SELECT id FROM app_chat_messages WHERE conversation_id = ?)`).run(a,a),this.db.prepare("UPDATE app_chat_conversations SET updated_at = ? WHERE id = ?").run(n.at,a),c}getFile(e,a){if(!Od.test(a))return null;let n=this.db.prepare(`SELECT f.*, c.node, c.agent FROM app_chat_files f
17342
17843
  JOIN app_chat_conversations c ON c.id = f.conversation_id WHERE f.id = ? AND c.device_id = ?`).get(a,e);return n?{id:n.id,name:n.name,mime:n.mime,kind:n.kind,path:n.path,conversationId:n.conversation_id,node:n.node,agent:n.agent}:null}pruneDevice(e){let a=this.db.prepare(`SELECT id FROM app_chat_conversations WHERE device_id = ?
17343
- ORDER BY updated_at DESC, rowid DESC LIMIT -1 OFFSET ?`).all(e,Se.conversationsPerDevice);for(let{id:n}of a)this.db.prepare("DELETE FROM app_chat_files WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_messages WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_conversations WHERE id = ?").run(n)}};function Lo(t){return{id:t.id,title:t.title,node:t.node,nodeName:t.node_name,agent:t.agent,...t.agent_name?{agentName:t.agent_name}:{},createdAt:t.created_at,updatedAt:t.updated_at}}function rd(t){let e=o=>{if(o)try{return JSON.parse(o)}catch{return}},a=e(t.ui),n=e(t.tools),r=e(t.files);return{role:t.role,content:t.content,at:t.at,...t.status?{status:t.status}:{},...t.error?{error:t.error}:{},...a?{ui:a}:{},...n?{tools:n}:{},...r?{files:r}:{}}}function od(t){let e=t.replace(/\s+/g," ").trim();return(e.length>60?e.slice(0,59)+"\u2026":e)||"Untitled"}function Th(t){let e=t.dashboard,a=t.boards,n=e.port,r=e.bind,o=e.token,s=new Map;for(let h of a)try{s.set(h.id,xd(h,t))}catch(y){console.error(` Board "${h.id}" failed to initialize: ${y.message}`)}let i=t.node?.id||"local",l=t.workflows?.dir?ze(process.cwd(),t.workflows.dir):void 0,c=new da(l?{baseDir:l}:void 0),p=new pa(l?{baseDir:l,nodeId:i}:{nodeId:i}),u=new ua(l?{baseDir:l}:void 0);ir(t),Ia({business:t.business?.enabled===!0}),sd(async(h,y)=>{try{await md(h,y,{boards:a,sources:s,token:o,config:t,workflowStore:c,workflowRuns:p,workflowLayouts:u})}catch(T){w(y,500,{error:T.message||"internal error"})}}).listen(n,r,()=>{let h=r==="0.0.0.0"?"localhost":r;a.length===0?(console.log(`
17844
+ ORDER BY updated_at DESC, rowid DESC LIMIT -1 OFFSET ?`).all(e,Ae.conversationsPerDevice);for(let{id:n}of a)this.db.prepare("DELETE FROM app_chat_files WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_messages WHERE conversation_id = ?").run(n),this.db.prepare("DELETE FROM app_chat_conversations WHERE id = ?").run(n)}};function ss(t){return{id:t.id,title:t.title,node:t.node,nodeName:t.node_name,agent:t.agent,...t.agent_name?{agentName:t.agent_name}:{},...t.color?{color:t.color}:{},createdAt:t.created_at,updatedAt:t.updated_at}}function Hd(t){let e=o=>{if(o)try{return JSON.parse(o)}catch{return}},a=e(t.ui),n=e(t.tools),r=e(t.files);return{role:t.role,content:t.content,at:t.at,...t.status?{status:t.status}:{},...t.error?{error:t.error}:{},...a?{ui:a}:{},...n?{tools:n}:{},...r?{files:r}:{}}}function Bd(t){let e=t.replace(/\s+/g," ").trim();return(e.length>60?e.slice(0,59)+"\u2026":e)||"Untitled"}function Cg(t){let e=t.dashboard,a=t.boards,n=e.port,r=e.bind,o=e.token,s=new Map;for(let h of a)try{s.set(h.id,Qd(h,t))}catch(v){console.error(` Board "${h.id}" failed to initialize: ${v.message}`)}let i=t.node?.id||"local",l=t.workflows?.dir?qe(process.cwd(),t.workflows.dir):void 0,c=new ga(l?{baseDir:l}:void 0),p=new xa(l?{baseDir:l,nodeId:i}:{nodeId:i}),u=new va(l?{baseDir:l}:void 0);hr(t),Na({business:t.business?.enabled===!0}),zd(async(h,v)=>{try{await Kd(h,v,{boards:a,sources:s,token:o,config:t,workflowStore:c,workflowRuns:p,workflowLayouts:u})}catch(T){w(v,500,{error:T.message||"internal error"})}}).listen(n,r,()=>{let h=r==="0.0.0.0"?"localhost":r;a.length===0?(console.log(`
17344
17845
  Live dashboard: http://${h}:${n}
17345
17846
  `),console.log(" (no boards configured \u2014 '/' serves the live view; add a board with 'agentx board add')")):(console.log(`
17346
17847
  Kanban dashboard: http://${h}:${n}
17347
- `),console.log(` Boards: ${a.map(y=>y.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 ud=new Set(["/","/live","/mesh","/monitor","/activity","/boards","/glossary","/workflows","/workflows/editor","/procedures","/processes","/graph","/setup","/admin","/admin/graph","/approvals","/admin/health","/admin/observability","/admin/ledger","/admin/cost","/admin/projects","/admin/wiki"]);async function md(t,e,a){let n=new URL(t.url||"/","http://localhost"),r=n.pathname,o=(t.method||"GET").toUpperCase();if(Aa(t.headers)==="foreign"&&Ma(o)){w(e,403,{error:"Forbidden: request from a page on another origin"});return}if(o==="OPTIONS"){e.writeHead(204),e.end();return}if(await Io(t,e,r,o,{nodeName:a.config.node?.name,fleet:No(a.config),push:Rd(a.config),chat:jd(a.config),voice:Pd(a.config)}))return;if(o==="GET"&&ud.has(r)&&an("page",r),o==="GET"&&r==="/"){let d=Ja();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(qt({peers:O(a.config)}));return}if(o==="GET"&&r==="/boards"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Lr({peers:O(a.config)}));return}if(o==="GET"&&r==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(qt({peers:O(a.config)}));return}if(o==="POST"&&r.match(/^\/webhook\/n8n\/[A-Za-z0-9._:-]{1,64}$/)){try{let[d]=await xe(a.config);if(!d){w(e,503,{error:"no node available"});return}let m=await new Promise(v=>{let k="";t.on("data",b=>k+=b),t.on("end",()=>v(k)),t.on("error",()=>v(""))}),g=await fetch(d.url+r,{method:"POST",headers:{"Content-Type":"application/json",...d.token?{Authorization:`Bearer ${d.token}`}:{}},body:m||"{}"});e.writeHead(g.status,{"Content-Type":"application/json"}),e.end(await g.text())}catch(d){w(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 xe(a.config),m=o==="POST"?void 0:n.searchParams.get("node"),g=o==="POST"?await fe(t):void 0,v=g?.node??m,k=v?d.find(M=>M.url===v):d[0];if(!k){w(e,400,{error:"unknown node"});return}let b=n.search?n.search.replace(/([?&])node=[^&]*/,"$1").replace(/[?&]$/,""):"",_=await fetch(k.url+r+b,{method:o,headers:{"Content-Type":"application/json",...k.token?{Authorization:`Bearer ${k.token}`}:{}},...o==="POST"?{body:JSON.stringify({...g,node:void 0})}:{}});w(e,_.status,await _.json().catch(()=>({error:`HTTP ${_.status}`})))}catch(d){w(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 fe(t),m={"Content-Type":"application/json"};a.config.dashboard.token&&(m.Authorization=`Bearer ${a.config.dashboard.token}`);let g=a.config.dashboard.daemonUrl.replace(/\/+$/,""),v=await fetch(`${g}/api/workflows/editor/chat`,{method:"POST",headers:m,body:JSON.stringify(d??{})}),k=await v.json().catch(()=>({error:`HTTP ${v.status}`}));w(e,v.status,k)}catch(d){w(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(o==="GET"&&r==="/api/n8n/workflows"){try{let[d]=await xe(a.config);if(!d){w(e,200,{configured:!1,workflows:[]});return}let m=await fetch(d.url+"/api/n8n/workflows",{headers:d.token?{Authorization:`Bearer ${d.token}`}:{}});w(e,m.status,await m.json().catch(()=>({configured:!1,workflows:[]})))}catch{w(e,200,{configured:!1,workflows:[]})}return}if(o==="GET"&&r==="/workflows/editor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(mn({peers:O(a.config)}));return}if(o==="GET"&&r==="/activity"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(un({peers:O(a.config),view:n.searchParams.get("view")}));return}if(o==="GET"&&r==="/monitor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(ln({peers:O(a.config)}));return}if(r==="/api/monitor"||r.startsWith("/api/monitor/")){let d=new AbortController,m=setTimeout(()=>d.abort(),8e3);try{let g=ga(await xe(a.config,d.signal),a.config.mesh.peers);if(o==="GET"&&r==="/api/monitor"){let M=await Promise.all(g.map(async A=>{try{let E=await fetch(A.url+"/monitor",{headers:A.token?{Authorization:`Bearer ${A.token}`}:{},signal:d.signal});if(!E.ok)throw new Error(`HTTP ${E.status}`);return{name:A.name,url:A.url,ok:!0,data:await E.json()}}catch(E){return{name:A.name,url:A.url,ok:!1,error:E.message}}}));w(e,200,{nodes:M});return}let v=g.find(M=>M.url===n.searchParams.get("node"));if(!v){w(e,400,{error:"Select a known node"});return}let k=r.slice(13);if(!(o==="GET"&&["discover","actions","activity"].includes(k)||o==="POST"&&["register","ended","action","retry","clear"].includes(k))){w(e,405,{error:"Unknown monitor operation"});return}let b=o==="POST"?JSON.stringify(await ha(t)):void 0,_=await fetch(v.url+"/monitor/"+k+(k==="actions"?"?offset="+encodeURIComponent(n.searchParams.get("offset")||"0"):k==="activity"?"?hours="+encodeURIComponent(n.searchParams.get("hours")||"24"):""),{method:o,body:b,signal:d.signal,headers:{"Content-Type":"application/json",...v.token?{Authorization:`Bearer ${v.token}`}:{}}});w(e,_.status,await _.json())}catch(g){w(e,502,{error:g.message})}finally{clearTimeout(m)}return}if(o==="GET"&&r==="/mesh"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ar({peers:O(a.config)}));return}if(o==="GET"&&r==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Rr({peers:O(a.config)}));return}if(o==="GET"&&r==="/workflows"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(jr({peers:O(a.config)}));return}if(o==="GET"&&r==="/procedures"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pr({peers:O(a.config)}));return}if(o==="GET"&&r==="/processes"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Ka({}));return}let i=o==="GET"&&r.match(/^\/tasks\/([^/]+)$/);if(i){let d=n.searchParams.get("agent")||"",m=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(Or({taskId:decodeURIComponent(i[1]),agentId:d,agentName:n.searchParams.get("name")||void 0,channel:n.searchParams.get("channel")||void 0,archived:n.searchParams.get("archived")==="1",ask:n.searchParams.get("ask")||void 0,askAt:n.searchParams.get("at")||void 0,nodeUrl:m,peers:O(a.config)}));return}let l=o==="GET"&&r.match(/^\/agents\/([^/]+)\/history$/);if(l){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Nr({agentId:decodeURIComponent(l[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"){Va(t,e);return}if(o==="POST"&&r==="/api/setup"){await Ya(t,e);return}if(o==="POST"&&r==="/api/setup/start-daemon"){await Qa(t,e);return}if(o==="GET"&&r==="/admin"){vn(t,e,O(a.config),a.token);return}if(o==="GET"&&r==="/approvals"){In(e,O(a.config),a.token);return}if(o==="GET"&&r==="/admin/graph"){Sn(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}Nn(t,e,O(a.config));return}if(r.startsWith("/api/admin/")||r.startsWith("/api/workflows")||r.startsWith("/api/agents")){let d=n.searchParams.get("peer")==="fleet"?"fleet":String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(d==="fleet"){if(r==="/api/admin/activity-graph"){await zd(t,e,a);return}if(r==="/api/admin/activity-graph/stream"){await Ft(t,e,r,g=>Ho(g,a.config));return}let m=r.match(/^\/api\/admin\/activity-graph\/dispatch\/(.+)$/);if(m){let g=decodeURIComponent(m[1]),v=g.indexOf("::");if(v>0){let k=g.slice(0,v),b=g.slice(v+2),_=a.config.node?.id||a.config.node?.name||"local";if(k===_)t.url=`/api/admin/activity-graph/dispatch/${encodeURIComponent(b)}`;else{let M=(a.config.dashboard?.daemons||[]).find(A=>(A.name||A.url)===k);if(M){let A=Ue(M.url.replace(/\/+$/,""),a.config);if(A){await jo(t,e,A,`/api/admin/activity-graph/dispatch/${encodeURIComponent(b)}`);return}}w(e,404,{error:`unknown node "${k}" in fleet dispatch id`});return}}}}else if(d&&d!=="primary"){let m=Ue(d,a.config);if(!m){w(e,404,{error:`unknown peer: ${d}`});return}let g=(n.search||"").replace(/[?&]peer=[^&]*/g,k=>k.startsWith("?")?"?":"");await jo(t,e,m,r+(g==="?"?"":g));return}}if(o==="GET"&&r.startsWith("/api/admin/observability/")&&await Dn(t,e,r))return;if(o==="GET"&&r==="/api/admin/logs/stream"){await Fd(t,e);return}if(o==="GET"&&r==="/api/admin/doctor"){try{let{runDoctorChecks:d}=await import("./doctor-IITNYJU5.js"),g=new URL(t.url||"/","http://_").searchParams.get("running")!=="false",v=await d({running:g});w(e,200,v)}catch(d){w(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(Fn({peers:O(a.config)}));return}if(o==="GET"&&r.startsWith("/api/admin/ledger/")&&await zn(t,e,r))return;if(o==="GET"&&r==="/admin/cost"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Un({peers:O(a.config)}));return}if(o==="GET"&&r==="/admin/projects"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(qn({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 yd(a)(t,e);return}if(o==="GET"&&r==="/admin/activity-graph"){e.writeHead(302,{Location:"/activity?view=map"}),e.end();return}if(o==="GET"&&r==="/api/admin/activity-graph"&&await lr(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/stream")&&await Ft(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/dispatch/")&&await dr(t,e,r))return;let c=o==="GET"&&r.match(/^\/admin\/agents\/([a-z0-9][a-z0-9_-]*)$/);if(c){mr(t,e,c[1],O(a.config),a.token);return}if(r.startsWith("/api/admin/")&&a.token){let d=t.headers.authorization||"",m=d.startsWith("Bearer ")?d.slice(7):"";if(m!==a.token){let g=new Z,v=m?g.verify(m):null;if(!v||!ve(v,"dashboard:write")){w(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/admin/config"){await bn(t,e);return}if(r.startsWith("/api/admin/approvals")){await $n(t,e,r,n);return}if(r.startsWith("/api/admin/graph/")){await Tn(t,e,r);return}if(r.startsWith("/api/admin/agent/")){await fr(t,e,r);return}if(r.startsWith("/api/admin/")){await yn(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(fn);return}if(o==="GET"&&r.startsWith("/assets/")){let d=r.slice(8);if(!/^[a-zA-Z0-9._-]+\.(js|map|css)$/.test(d)){w(e,400,{error:"invalid asset name"});return}let m=Hd("web/"+d);try{let g=await Bd(m),v=d.endsWith(".map")?"application/json; charset=utf-8":d.endsWith(".css")?"text/css; charset=utf-8":"application/javascript; charset=utf-8",k=n.searchParams.has("v");e.writeHead(200,{"Content-Type":v,"Cache-Control":k?"public, max-age=31536000, immutable":"public, max-age=60"}),e.end(g)}catch{w(e,404,{error:"asset not found",hint:"run: npm run build:web"})}return}if(o==="GET"&&r==="/api/live"){try{let d=await Fe(a.config);w(e,200,d)}catch(d){w(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),m=n.searchParams.get("timezone")||"UTC",g=await Fe(a.config,{date:d,timezone:m});w(e,200,g)}catch(d){w(e,502,{error:d.message})}return}if(o==="GET"&&r==="/api/mesh/analytics"){let d=(m,g,v,k)=>{let b=parseInt(n.searchParams.get(m)||"",10);return Number.isFinite(b)?Math.max(v,Math.min(k,b)):g};try{let m=await xe(a.config);w(e,200,await Mr(m,{days:d("days",30,0,180),tzOffsetMinutes:d("tzOffset",0,-840,840),limit:d("limit",60,1,200)}))}catch(m){w(e,502,{error:m.message})}return}if(o==="GET"&&r==="/api/mesh/day"){let d=n.searchParams.get("day")||"";if(!/^\d{4}-\d{2}-\d{2}$/.test(d)){w(e,400,{error:"day=YYYY-MM-DD query param required"});return}let m=(g,v,k,b)=>{let _=parseInt(n.searchParams.get(g)||"",10);return Number.isFinite(_)?Math.max(k,Math.min(b,_)):v};try{let g=await xe(a.config);w(e,200,await $r(g,{day:d,tzOffsetMinutes:m("tzOffset",0,-840,840),limit:m("limit",40,1,200)}))}catch(g){w(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){w(e,400,{error:"node query param required"});return}let m=n.searchParams,g;if(r==="/api/mesh/thread"){let[v,k,b]=[m.get("agent"),m.get("channel"),m.get("chat")];if(!v||!k||!b){w(e,400,{error:"agent, channel, chat required"});return}g=`/analytics/thread?agent=${encodeURIComponent(v)}&channel=${encodeURIComponent(k)}&chat=${encodeURIComponent(b)}&limit=${encodeURIComponent(m.get("limit")||"120")}`}else if(r==="/api/mesh/job"){let[v,k]=[m.get("kind"),m.get("key")];if(!v||!k){w(e,400,{error:"kind and key required"});return}g=`/analytics/job?kind=${encodeURIComponent(v)}&key=${encodeURIComponent(k)}&limit=${encodeURIComponent(m.get("limit")||"120")}`}else if(r==="/api/mesh/conversation"){let[v,k,b]=[m.get("agent"),m.get("channel"),m.get("chat")];if(!v||!k||!b){w(e,400,{error:"agent, channel, chat required"});return}g=`/analytics/conversation?agent=${encodeURIComponent(v)}&channel=${encodeURIComponent(k)}&chat=${encodeURIComponent(b)}&tzOffset=${encodeURIComponent(m.get("tzOffset")||"0")}`}else{let v=m.get("task");if(!v){w(e,400,{error:"task required"});return}g=`/analytics/run/${encodeURIComponent(v)}`}try{await Ir(e,await xe(a.config),d,g)}catch(v){w(e,502,{error:v.message})}return}if(o==="GET"&&r==="/api/live/stream"){Cd(t,e,a.config);return}if(o==="GET"&&r==="/api/task/stream"){let d=new URL(t.url||"/","http://localhost"),m=d.searchParams.get("node"),g=d.searchParams.get("agent"),v=d.searchParams.get("task");if(!m||!g||!v){w(e,400,{error:"node, agent, task query params required"});return}await Ad(t,e,a,m,g,v);return}if(o==="GET"&&r==="/api/task/history"){let d=new URL(t.url||"/","http://localhost"),m=d.searchParams.get("node"),g=d.searchParams.get("agent"),v=d.searchParams.get("task"),k=d.searchParams.get("limit")||"50";if(!m||!g){w(e,400,{error:"node and agent query params required"});return}await $d(e,a,m,g,v,k);return}if(o==="POST"&&r==="/api/task/action"){let d=new URL(t.url||"/","http://localhost"),m=d.searchParams.get("node"),g=d.searchParams.get("task"),v=d.searchParams.get("kind");if(!m||!g||v!=="cancel"&&v!=="followup"){w(e,400,{error:"node, task, kind=cancel|followup query params required"});return}await Ld(t,e,a,m,g,v);return}if(o==="POST"&&r==="/api/voice/stop"){let d=new URL(t.url||"/","http://localhost").searchParams.get("node");if(!d){w(e,400,{error:"node query param required"});return}await ra(t,e,a,d,"/voice/stop");return}if(o==="GET"&&r==="/api/agents"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let m=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:d});if(!m.ok)throw new Error(`HTTP ${m.status}`);let g=await m.json();w(e,200,g)}catch(d){w(e,502,{error:d.message||"agents fetch failed"})}return}if(o==="GET"&&r==="/api/business/status"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let m=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/business/status",{headers:d});if(!m.ok){w(e,m.status,{error:`HTTP ${m.status}`});return}w(e,200,await m.json())}catch(d){w(e,502,{error:d.message||"business status fetch failed"})}return}if(o==="POST"&&r==="/api/draft"){let d=await fe(t);try{let m=await Nd(a.config,d);w(e,200,m)}catch(m){w(e,502,{error:m.message||"draft failed"})}return}let p=r.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(p&&o==="POST"){let d=p[1];if(!Md(t,e,[`agent:${d}`]))return;await Id(t,e,a.config,d);return}if(r.startsWith("/api/")&&a.token){let d=t.headers.authorization||"",m=d.startsWith("Bearer ")?d.slice(7):"";if(m!==a.token){let g=new Z,v=m?g.verify(m):null;if(!v||!ve(v,"dashboard:write")){w(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/mesh/feed"){await wd(e,a.config,n.searchParams);return}if((o==="POST"||o==="PATCH"||o==="DELETE"||o==="PUT")&&r.startsWith("/api/")&&t.headers["x-requested-with"]!=="agentx-board"){w(e,400,{error:"missing X-Requested-With: agentx-board"});return}if(o==="POST"&&(r==="/api/node/restart"||r==="/api/node/restart/cancel")){let d=n.searchParams.get("node");if(!d){w(e,400,{error:"node query param required"});return}await ra(t,e,a,d,r==="/api/node/restart"?"/daemon/restart":"/daemon/restart/cancel");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"});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}))],v={flag:!1},k=[];t.on("close",()=>{v.flag=!0;for(let _ of k)try{_.abort()}catch{}});let b=setInterval(()=>{if(!v.flag)try{e.write(`: ping
17848
+ `),console.log(` Boards: ${a.map(v=>v.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 Xd=new Set(["/","/live","/mesh","/monitor","/activity","/boards","/glossary","/workflows","/workflows/editor","/procedures","/processes","/graph","/setup","/admin","/admin/graph","/approvals","/admin/health","/admin/observability","/admin/ledger","/admin/cost","/admin/projects","/admin/wiki"]);async function Kd(t,e,a){let n=new URL(t.url||"/","http://localhost"),r=n.pathname,o=(t.method||"GET").toUpperCase();if(ja(t.headers)==="foreign"&&Oa(o)){w(e,403,{error:"Forbidden: request from a page on another origin"});return}if(o==="OPTIONS"){e.writeHead(204),e.end();return}if(await ns(t,e,r,o,{nodeName:a.config.node?.name,fleet:us(a.config),push:ps(a.config),announce:to(a.config),chat:fp(a.config),voice:gp(a.config)}))return;if(o==="GET"&&Xd.has(r)&&pn("page",r),o==="GET"&&r==="/"){let d=nn();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(Gt({peers:N(a.config)}));return}if(o==="GET"&&r==="/boards"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Br({peers:N(a.config)}));return}if(o==="GET"&&r==="/live"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Gt({peers:N(a.config)}));return}if(o==="POST"&&r.match(/^\/webhook\/n8n\/[A-Za-z0-9._:-]{1,64}$/)){try{let[d]=await ve(a.config);if(!d){w(e,503,{error:"no node available"});return}let m=await new Promise(b=>{let k="";t.on("data",y=>k+=y),t.on("end",()=>b(k)),t.on("error",()=>b(""))}),x=await fetch(d.url+r,{method:"POST",headers:{"Content-Type":"application/json",...d.token?{Authorization:`Bearer ${d.token}`}:{}},body:m||"{}"});e.writeHead(x.status,{"Content-Type":"application/json"}),e.end(await x.text())}catch(d){w(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 ve(a.config),m=o==="POST"?void 0:n.searchParams.get("node"),x=o==="POST"?await he(t):void 0,b=x?.node??m,k=b?d.find(M=>M.url===b):d[0];if(!k){w(e,400,{error:"unknown node"});return}let y=n.search?n.search.replace(/([?&])node=[^&]*/,"$1").replace(/[?&]$/,""):"",_=await fetch(k.url+r+y,{method:o,headers:{"Content-Type":"application/json",...k.token?{Authorization:`Bearer ${k.token}`}:{}},...o==="POST"?{body:JSON.stringify({...x,node:void 0})}:{}});w(e,_.status,await _.json().catch(()=>({error:`HTTP ${_.status}`})))}catch(d){w(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 he(t),m={"Content-Type":"application/json"};a.config.dashboard.token&&(m.Authorization=`Bearer ${a.config.dashboard.token}`);let x=a.config.dashboard.daemonUrl.replace(/\/+$/,""),b=await fetch(`${x}/api/workflows/editor/chat`,{method:"POST",headers:m,body:JSON.stringify(d??{})}),k=await b.json().catch(()=>({error:`HTTP ${b.status}`}));w(e,b.status,k)}catch(d){w(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(o==="GET"&&r==="/api/n8n/workflows"){try{let[d]=await ve(a.config);if(!d){w(e,200,{configured:!1,workflows:[]});return}let m=await fetch(d.url+"/api/n8n/workflows",{headers:d.token?{Authorization:`Bearer ${d.token}`}:{}});w(e,m.status,await m.json().catch(()=>({configured:!1,workflows:[]})))}catch{w(e,200,{configured:!1,workflows:[]})}return}if(o==="GET"&&r==="/workflows/editor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(wn({peers:N(a.config)}));return}if(o==="GET"&&r==="/activity"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(yn({peers:N(a.config),view:n.searchParams.get("view")}));return}if(o==="GET"&&r==="/monitor"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(gn({peers:N(a.config)}));return}if(r==="/api/monitor"||r.startsWith("/api/monitor/")){let d=new AbortController,m=setTimeout(()=>d.abort(),8e3);try{let x=_a(await ve(a.config,d.signal),a.config.mesh.peers);if(o==="GET"&&r==="/api/monitor"){let M=await Promise.all(x.map(async C=>{try{let S=await fetch(C.url+"/monitor",{headers:C.token?{Authorization:`Bearer ${C.token}`}:{},signal:d.signal});if(!S.ok)throw new Error(`HTTP ${S.status}`);return{name:C.name,url:C.url,ok:!0,data:await S.json()}}catch(S){return{name:C.name,url:C.url,ok:!1,error:S.message}}}));w(e,200,{nodes:M});return}let b=x.find(M=>M.url===n.searchParams.get("node"));if(!b){w(e,400,{error:"Select a known node"});return}let k=r.slice(13);if(!(o==="GET"&&["discover","actions","activity"].includes(k)||o==="POST"&&["register","ended","action","retry","clear"].includes(k))){w(e,405,{error:"Unknown monitor operation"});return}let y=o==="POST"?JSON.stringify(await ka(t)):void 0,_=await fetch(b.url+"/monitor/"+k+(k==="actions"?"?offset="+encodeURIComponent(n.searchParams.get("offset")||"0"):k==="activity"?"?hours="+encodeURIComponent(n.searchParams.get("hours")||"24"):""),{method:o,body:y,signal:d.signal,headers:{"Content-Type":"application/json",...b.token?{Authorization:`Bearer ${b.token}`}:{}}});w(e,_.status,await _.json())}catch(x){w(e,502,{error:x.message})}finally{clearTimeout(m)}return}if(o==="GET"&&r==="/mesh"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Or({peers:N(a.config)}));return}if(o==="GET"&&r==="/glossary"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(zr({peers:N(a.config)}));return}if(o==="GET"&&r==="/workflows"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Fr({peers:N(a.config)}));return}if(o==="GET"&&r==="/procedures"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(qr({peers:N(a.config)}));return}if(o==="GET"&&r==="/processes"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(an({}));return}let i=o==="GET"&&r.match(/^\/tasks\/([^/]+)$/);if(i){let d=n.searchParams.get("agent")||"",m=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(Ur({taskId:decodeURIComponent(i[1]),agentId:d,agentName:n.searchParams.get("name")||void 0,channel:n.searchParams.get("channel")||void 0,archived:n.searchParams.get("archived")==="1",ask:n.searchParams.get("ask")||void 0,askAt:n.searchParams.get("at")||void 0,nodeUrl:m,peers:N(a.config)}));return}let l=o==="GET"&&r.match(/^\/agents\/([^/]+)\/history$/);if(l){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Wr({agentId:decodeURIComponent(l[1]),agentName:n.searchParams.get("name")||void 0,nodeUrl:n.searchParams.get("node")||a.config.dashboard.daemonUrl,peers:N(a.config)}));return}if(o==="GET"&&r==="/graph"){e.writeHead(302,{Location:"/admin/graph"}),e.end();return}if(o==="GET"&&r==="/setup"){rn(t,e);return}if(o==="POST"&&r==="/api/setup"){await on(t,e);return}if(o==="POST"&&r==="/api/setup/start-daemon"){await sn(t,e);return}if(o==="GET"&&r==="/admin"){Tn(t,e,N(a.config),a.token);return}if(o==="GET"&&r==="/approvals"){Dn(e,N(a.config),a.token);return}if(o==="GET"&&r==="/admin/graph"){Rn(t,e,N(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}Wn(t,e,N(a.config));return}if(r.startsWith("/api/admin/")||r.startsWith("/api/workflows")||r.startsWith("/api/agents")){let d=n.searchParams.get("peer")==="fleet"?"fleet":String(t.headers["x-agentx-peer"]||"").trim()||n.searchParams.get("peer")||"";if(d==="fleet"){if(r==="/api/admin/activity-graph"){await kp(t,e,a);return}if(r==="/api/admin/activity-graph/stream"){await Ut(t,e,r,x=>fs(x,a.config));return}let m=r.match(/^\/api\/admin\/activity-graph\/dispatch\/(.+)$/);if(m){let x=decodeURIComponent(m[1]),b=x.indexOf("::");if(b>0){let k=x.slice(0,b),y=x.slice(b+2),_=a.config.node?.id||a.config.node?.name||"local";if(k===_)t.url=`/api/admin/activity-graph/dispatch/${encodeURIComponent(y)}`;else{let M=(a.config.dashboard?.daemons||[]).find(C=>(C.name||C.url)===k);if(M){let C=We(M.url.replace(/\/+$/,""),a.config);if(C){await ls(t,e,C,`/api/admin/activity-graph/dispatch/${encodeURIComponent(y)}`);return}}w(e,404,{error:`unknown node "${k}" in fleet dispatch id`});return}}}}else if(d&&d!=="primary"){let m=We(d,a.config);if(!m){w(e,404,{error:`unknown peer: ${d}`});return}let x=(n.search||"").replace(/[?&]peer=[^&]*/g,k=>k.startsWith("?")?"?":"");await ls(t,e,m,r+(x==="?"?"":x));return}}if(o==="GET"&&r.startsWith("/api/admin/observability/")&&await Gn(t,e,r))return;if(o==="GET"&&r==="/api/admin/logs/stream"){await _p(t,e);return}if(o==="GET"&&r==="/api/admin/doctor"){try{let{runDoctorChecks:d}=await import("./doctor-IITNYJU5.js"),x=new URL(t.url||"/","http://_").searchParams.get("running")!=="false",b=await d({running:x});w(e,200,b)}catch(d){w(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(Vn({peers:N(a.config)}));return}if(o==="GET"&&r.startsWith("/api/admin/ledger/")&&await Jn(t,e,r))return;if(o==="GET"&&r==="/admin/cost"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Yn({peers:N(a.config)}));return}if(o==="GET"&&r==="/admin/projects"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Qn({peers:N(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 tp(a)(t,e);return}if(o==="GET"&&r==="/admin/activity-graph"){e.writeHead(302,{Location:"/activity?view=map"}),e.end();return}if(o==="GET"&&r==="/api/admin/activity-graph"&&await gr(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/stream")&&await Ut(t,e,r)||o==="GET"&&r.startsWith("/api/admin/activity-graph/dispatch/")&&await vr(t,e,r))return;let c=o==="GET"&&r.match(/^\/admin\/agents\/([a-z0-9][a-z0-9_-]*)$/);if(c){wr(t,e,c[1],N(a.config),a.token);return}if(r.startsWith("/api/admin/")&&a.token){let d=t.headers.authorization||"",m=d.startsWith("Bearer ")?d.slice(7):"";if(m!==a.token){let x=new ae,b=m?x.verify(m):null;if(!b||!be(b,"dashboard:write")){w(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/admin/config"){await An(t,e);return}if(r.startsWith("/api/admin/approvals")){await Hn(t,e,r,n);return}if(r.startsWith("/api/admin/graph/")){await Pn(t,e,r);return}if(r.startsWith("/api/admin/agent/")){await kr(t,e,r);return}if(r.startsWith("/api/admin/")){await Cn(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(kn);return}if(o==="GET"&&r.startsWith("/assets/")){let d=r.slice(8);if(!/^[a-zA-Z0-9._-]+\.(js|map|css)$/.test(d)){w(e,400,{error:"invalid asset name"});return}let m=yp("web/"+d);try{let x=await wp(m),b=d.endsWith(".map")?"application/json; charset=utf-8":d.endsWith(".css")?"text/css; charset=utf-8":"application/javascript; charset=utf-8",k=n.searchParams.has("v");e.writeHead(200,{"Content-Type":b,"Cache-Control":k?"public, max-age=31536000, immutable":"public, max-age=60"}),e.end(x)}catch{w(e,404,{error:"asset not found",hint:"run: npm run build:web"})}return}if(o==="GET"&&r==="/api/live"){try{let d=await Ue(a.config);w(e,200,d)}catch(d){w(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),m=n.searchParams.get("timezone")||"UTC",x=await Ue(a.config,{date:d,timezone:m});w(e,200,x)}catch(d){w(e,502,{error:d.message})}return}if(o==="GET"&&r==="/api/mesh/analytics"){let d=(m,x,b,k)=>{let y=parseInt(n.searchParams.get(m)||"",10);return Number.isFinite(y)?Math.max(b,Math.min(k,y)):x};try{let m=await ve(a.config);w(e,200,await Nr(m,{days:d("days",30,0,180),tzOffsetMinutes:d("tzOffset",0,-840,840),limit:d("limit",60,1,200)}))}catch(m){w(e,502,{error:m.message})}return}if(o==="GET"&&r==="/api/mesh/day"){let d=n.searchParams.get("day")||"";if(!/^\d{4}-\d{2}-\d{2}$/.test(d)){w(e,400,{error:"day=YYYY-MM-DD query param required"});return}let m=(x,b,k,y)=>{let _=parseInt(n.searchParams.get(x)||"",10);return Number.isFinite(_)?Math.max(k,Math.min(y,_)):b};try{let x=await ve(a.config);w(e,200,await Hr(x,{day:d,tzOffsetMinutes:m("tzOffset",0,-840,840),limit:m("limit",40,1,200)}))}catch(x){w(e,502,{error:x.message})}return}if(o==="GET"&&(r==="/api/mesh/thread"||r==="/api/mesh/job"||r==="/api/mesh/run"||r==="/api/mesh/conversation")){let d=n.searchParams.get("node");if(!d){w(e,400,{error:"node query param required"});return}let m=n.searchParams,x;if(r==="/api/mesh/thread"){let[b,k,y]=[m.get("agent"),m.get("channel"),m.get("chat")];if(!b||!k||!y){w(e,400,{error:"agent, channel, chat required"});return}x=`/analytics/thread?agent=${encodeURIComponent(b)}&channel=${encodeURIComponent(k)}&chat=${encodeURIComponent(y)}&limit=${encodeURIComponent(m.get("limit")||"120")}`}else if(r==="/api/mesh/job"){let[b,k]=[m.get("kind"),m.get("key")];if(!b||!k){w(e,400,{error:"kind and key required"});return}x=`/analytics/job?kind=${encodeURIComponent(b)}&key=${encodeURIComponent(k)}&limit=${encodeURIComponent(m.get("limit")||"120")}`}else if(r==="/api/mesh/conversation"){let[b,k,y]=[m.get("agent"),m.get("channel"),m.get("chat")];if(!b||!k||!y){w(e,400,{error:"agent, channel, chat required"});return}x=`/analytics/conversation?agent=${encodeURIComponent(b)}&channel=${encodeURIComponent(k)}&chat=${encodeURIComponent(y)}&tzOffset=${encodeURIComponent(m.get("tzOffset")||"0")}`}else{let b=m.get("task");if(!b){w(e,400,{error:"task required"});return}x=`/analytics/run/${encodeURIComponent(b)}`}try{await Dr(e,await ve(a.config),d,x)}catch(b){w(e,502,{error:b.message})}return}if(o==="GET"&&r==="/api/live/stream"){lp(t,e,a.config);return}if(o==="GET"&&r==="/api/task/stream"){let d=new URL(t.url||"/","http://localhost"),m=d.searchParams.get("node"),x=d.searchParams.get("agent"),b=d.searchParams.get("task");if(!m||!x||!b){w(e,400,{error:"node, agent, task query params required"});return}await cp(t,e,a,m,x,b);return}if(o==="GET"&&r==="/api/task/history"){let d=new URL(t.url||"/","http://localhost"),m=d.searchParams.get("node"),x=d.searchParams.get("agent"),b=d.searchParams.get("task"),k=d.searchParams.get("limit")||"50";if(!m||!x){w(e,400,{error:"node and agent query params required"});return}await up(e,a,m,x,b,k);return}if(o==="POST"&&r==="/api/task/action"){let d=new URL(t.url||"/","http://localhost"),m=d.searchParams.get("node"),x=d.searchParams.get("task"),b=d.searchParams.get("kind");if(!m||!x||b!=="cancel"&&b!=="followup"){w(e,400,{error:"node, task, kind=cancel|followup query params required"});return}await mp(t,e,a,m,x,b);return}if(o==="POST"&&r==="/api/voice/stop"){let d=new URL(t.url||"/","http://localhost").searchParams.get("node");if(!d){w(e,400,{error:"node query param required"});return}await da(t,e,a,d,"/voice/stop");return}if(o==="GET"&&r==="/api/agents"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let m=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/agents",{headers:d});if(!m.ok)throw new Error(`HTTP ${m.status}`);let x=await m.json();w(e,200,x)}catch(d){w(e,502,{error:d.message||"agents fetch failed"})}return}if(o==="GET"&&r==="/api/business/status"){try{let d={};a.config.dashboard.token&&(d.Authorization=`Bearer ${a.config.dashboard.token}`);let m=await fetch(a.config.dashboard.daemonUrl.replace(/\/+$/,"")+"/business/status",{headers:d});if(!m.ok){w(e,m.status,{error:`HTTP ${m.status}`});return}w(e,200,await m.json())}catch(d){w(e,502,{error:d.message||"business status fetch failed"})}return}if(o==="POST"&&r==="/api/draft"){let d=await he(t);try{let m=await vp(a.config,d);w(e,200,m)}catch(m){w(e,502,{error:m.message||"draft failed"})}return}let p=r.match(/^\/api\/public\/agents\/([^/]+)\/messages$/);if(p&&o==="POST"){let d=p[1];if(!dp(t,e,[`agent:${d}`]))return;await pp(t,e,a.config,d);return}if(r.startsWith("/api/")&&a.token){let d=t.headers.authorization||"",m=d.startsWith("Bearer ")?d.slice(7):"";if(m!==a.token){let x=new ae,b=m?x.verify(m):null;if(!b||!be(b,"dashboard:write")){w(e,401,{error:"unauthorized"});return}}}if(o==="GET"&&r==="/api/mesh/feed"){await ap(e,a.config,n.searchParams);return}if((o==="POST"||o==="PATCH"||o==="DELETE"||o==="PUT")&&r.startsWith("/api/")&&t.headers["x-requested-with"]!=="agentx-board"){w(e,400,{error:"missing X-Requested-With: agentx-board"});return}if(o==="POST"&&(r==="/api/node/restart"||r==="/api/node/restart/cancel")){let d=n.searchParams.get("node");if(!d){w(e,400,{error:"node query param required"});return}await da(t,e,a,d,r==="/api/node/restart"?"/daemon/restart":"/daemon/restart/cancel");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"});let x=[{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}))],b={flag:!1},k=[];t.on("close",()=>{b.flag=!0;for(let _ of k)try{_.abort()}catch{}});let y=setInterval(()=>{if(!b.flag)try{e.write(`: ping
17348
17849
 
17349
- `)}catch{}},15e3);t.on("close",()=>clearInterval(b));for(let _ of g)(async()=>{let M={Accept:"text/event-stream"};_.token&&(M.Authorization=`Bearer ${_.token}`);let A=new AbortController;k.push(A);try{let E=await fetch(`${_.url.replace(/\/+$/,"")}/events${m?`?${m}`:""}`,{headers:M,signal:A.signal});if(!E.ok||!E.body)return;let I=E.body.getReader(),R=new TextDecoder,j="";for(;!v.flag;){let{done:B,value:re}=await I.read();if(B)break;j+=R.decode(re,{stream:!0});let z;for(;(z=j.indexOf(`
17850
+ `)}catch{}},15e3);t.on("close",()=>clearInterval(y));for(let _ of x)(async()=>{let M={Accept:"text/event-stream"};_.token&&(M.Authorization=`Bearer ${_.token}`);let C=new AbortController;k.push(C);try{let S=await fetch(`${_.url.replace(/\/+$/,"")}/events${m?`?${m}`:""}`,{headers:M,signal:C.signal});if(!S.ok||!S.body)return;let I=S.body.getReader(),R=new TextDecoder,P="";for(;!b.flag;){let{done:B,value:oe}=await I.read();if(B)break;P+=R.decode(oe,{stream:!0});let z;for(;(z=P.indexOf(`
17350
17851
 
17351
- `))>=0;){let D=j.slice(0,z);if(j=j.slice(z+2),v.flag)break;try{e.write(D+`
17852
+ `))>=0;){let D=P.slice(0,z);if(P=P.slice(z+2),b.flag)break;try{e.write(D+`
17352
17853
 
17353
- `)}catch{v.flag=!0}}}}catch{}})();return}if(o==="GET"&&r==="/api/workflows/runs"){try{let d=new URL(t.url||"/","http://localhost"),m=Math.max(1,Math.min(500,Number(d.searchParams.get("limit")||50))),g=d.searchParams.get("workflowId")||void 0,v=d.searchParams.get("summary")==="1"||d.searchParams.get("summary")==="true",k=a.workflowRuns.list({limit:m,workflowId:g}),b=`?limit=${m}${g?`&workflowId=${encodeURIComponent(g)}`:""}${v?"&summary=1":""}`,_=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(R=>({url:R.url,token:R.token}))],M=await Promise.all(_.map(async R=>{let j={};R.token&&(j.Authorization=`Bearer ${R.token}`);try{let B=new AbortController,re=setTimeout(()=>B.abort(),5e3);try{let z=await fetch(`${R.url.replace(/\/+$/,"")}/api/workflows/runs${b}`,{headers:j,signal:B.signal});if(!z.ok)return[];let D=await z.json();return Array.isArray(D.runs)?D.runs:[]}finally{clearTimeout(re)}}catch{return[]}})),A=new Map;for(let R of k)A.set(R.id,R);for(let R of M)for(let j of R)A.set(j.id,j);let E=Array.from(A.values()).sort((R,j)=>R.updatedAt<j.updatedAt?1:-1).slice(0,m),I=v?E.map(R=>gd(R)):E;w(e,200,{runs:I})}catch(d){w(e,502,{error:"runs fetch failed",message:d.message||String(d)})}return}let f=o==="GET"&&r.match(/^\/api\/workflows\/runs\/([^\/]+)$/);if(f){let d=decodeURIComponent(f[1]),m=a.workflowRuns.get(d);if(m){w(e,200,{run:m});return}let g=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(v=>({url:v.url,token:v.token}))];for(let v of g)try{let k={};v.token&&(k.Authorization=`Bearer ${v.token}`);let b=await fetch(`${v.url.replace(/\/+$/,"")}/api/workflows/runs/${encodeURIComponent(d)}`,{headers:k});if(b.ok){w(e,200,await b.json());return}}catch{}w(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 m=a.config.dashboard.daemonUrl.replace(/\/+$/,""),g=await fetch(`${m}/api/actions/builtin`,{headers:d}),v=await g.json().catch(()=>({error:`HTTP ${g.status}`}));w(e,g.status,v)}catch(d){w(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}let h=o==="POST"&&r.match(/^\/workflows\/([^/]+)\/run$/);if(h){try{let d=await fe(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(/\/+$/,""),v=await fetch(`${g}/workflows/${encodeURIComponent(h[1])}/run`,{method:"POST",headers:m,body:JSON.stringify(d??{})}),k=await v.json().catch(()=>({error:`HTTP ${v.status}`}));w(e,v.status,k)}catch(d){w(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(r.startsWith("/api/workflows")&&Hr(t,e,{store:a.workflowStore,runs:a.workflowRuns,layouts:a.workflowLayouts,requireScope:(m,g,v)=>{if(a.token)return!0;let k=Et(m);if(!k)return!0;let b=new Z().verify(k);if(!b)return w(g,401,{error:"invalid or revoked token"}),!1;for(let _ of v)if(!ve(b,_))return w(g,403,{error:`token missing scope: ${_}`,scopes:b.scopes}),!1;return!0}}))return;if(o==="GET"&&r==="/api/boards"){w(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 y=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/members$/);if(y&&o==="GET"){let d=a.sources.get(y[1]);if(!d){w(e,404,{error:"unknown board"});return}try{let m=typeof d.listMembers=="function"?await d.listMembers():[];w(e,200,m)}catch(m){w(e,502,{error:m.message})}return}let T=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(T&&o==="GET"){let d=a.sources.get(T[1]);if(!d){w(e,404,{error:"unknown board"});return}try{let m=typeof d.listMilestones=="function"?await d.listMilestones():[];w(e,200,m)}catch(m){w(e,502,{error:m.message})}return}let S=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),x=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(S&&o==="PATCH"){let[,d,m]=S,g=decodeURIComponent(m),v=a.boards.find(A=>A.id===d);if(!v){w(e,404,{error:`unknown board: ${d}`});return}let k=a.sources.get(d);if(!k){w(e,503,{error:`board "${d}" source unavailable`});return}let b=await fe(t),_=v.columns.find(A=>A.id===b.to),M=v.columns.find(A=>A.id===b.from);if(!_){w(e,400,{error:`unknown 'to' column: ${b.to}`});return}try{await hd(k,g,M,_),ta({actor:aa(t),action:"move",boardId:d,itemId:g,payload:{from:b.from,to:b.to}}),w(e,200,{ok:!0})}catch(A){w(e,502,{error:A.message||"transition failed"})}return}if(x){let[,d,m]=x,g=m?decodeURIComponent(m):void 0,v=a.boards.find(b=>b.id===d);if(!v){w(e,404,{error:`unknown board: ${d}`});return}let k=a.sources.get(d);if(!k){w(e,503,{error:`board "${d}" source unavailable`});return}if(o==="GET"&&!g){let{columns:b,totals:_}=await fd(v,k,n.searchParams);w(e,200,{columns:b,totals:_});return}if(o==="GET"&&g){try{let b=typeof k.getItem=="function"?await k.getItem(g):null;if(!b){w(e,404,{error:"not found"});return}w(e,200,b)}catch(b){w(e,502,{error:b.message})}return}if(o==="PATCH"&&g){let b=await fe(t);try{let _=typeof k.updateItem=="function"?await k.updateItem(g,b):null;if(!_){w(e,501,{error:"update unsupported"});return}ta({actor:aa(t),action:"update",boardId:d,itemId:g,payload:b}),w(e,200,_)}catch(_){w(e,502,{error:_.message})}return}if(o==="POST"&&!g){let b=await fe(t);if(!b.title){w(e,400,{error:"title required"});return}if(!k.capabilities.create||!k.create){w(e,400,{error:`source ${k.type} does not support create`});return}try{let _=await k.create({title:b.title,description:b.description,labels:b.labels,assigneeUsernames:b.assigneeUsernames,milestoneTitle:b.milestoneTitle,projectHint:b.projectHint});ta({actor:aa(t),action:"create",boardId:d,itemId:_.id,payload:{title:b.title}}),w(e,201,_)}catch(_){w(e,502,{error:_.message})}return}}if(o==="GET"&&/^\/[a-z][a-z-]*\/?$/.test(r)){let d=r.replace(/^\/+|\/+$/g,""),g={health:"/admin/health",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}}w(e,404,{error:"not found",path:r})}async function fd(t,e,a){if(!e.capabilities.listAll||!e.listAll){let d={};for(let m of t.columns)d[m.id]=[];return{columns:d,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),c=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),p=t.columns.some(d=>d.kind!=="closed"),u=t.columns.some(d=>d.kind==="closed"),f=p?await e.listAll({sinceDays:l,labels:n.length?n:void 0,search:o,milestone:s,state:"opened"}):[],h=u?await e.listAll({sinceDays:c,labels:n.length?n:void 0,search:o,milestone:s,state:"closed"}):[],y={};for(let d of t.columns)y[d.id]=[];let T=t.columns.find(d=>d.kind==="closed");for(let d of h)T&&y[T.id].push({...d,stage:T.id});let S=t.columns.filter(d=>d.kind!=="closed");for(let d of f){let m=sa(d,S);if(!m)continue;let g=y[m];g&&g.push({...d,stage:m})}if(i)for(let d of Object.keys(y))y[d]=y[d].filter(m=>m.assignee===i);for(let d of Object.keys(y))y[d].sort((m,g)=>{let v=(m.priority??99)-(g.priority??99);return v!==0?v:(g.updatedAt||"").localeCompare(m.updatedAt||"")});let x=Object.fromEntries(Object.entries(y).map(([d,m])=>[d,m.length]));return{columns:y,totals:x}}async function hd(t,e,a,n){let r=ia(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 gd(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 xd(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 Oa(a.host,a.token,t.source.projects,n,(...r)=>console.log("[board]",...r))}throw new Error(`unsupported board source: ${t.source.type}`)}function ta(t){try{let e=ze(process.cwd(),".agentx");Po(e)||ld(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
17354
- `;id(ze(e,"board-audit.jsonl"),a)}catch{}}function aa(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}var vd=2e3;async function bd(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=x=>{let d=new AbortController,m=setTimeout(()=>d.abort(),vd),g=()=>d.abort();return a?.addEventListener("abort",g,{once:!0}),fetch(t+x,{headers:r,signal:d.signal}).then(async v=>{let k=v.ok?await v.json().catch(()=>{}):void 0;return{ok:k!==void 0,json:async()=>k}}).catch(()=>null).finally(()=>{clearTimeout(m),a?.removeEventListener("abort",g)})},[l,c,p,u,f,h,y,T]=await Promise.all([i("/health"),fetch(t+"/agents",{headers:r,signal:a}).catch(()=>null),i("/mesh"),i("/crons"),i("/crons/runs"+s),i("/talk"),i("/routines"),i("/attach/sessions")]);if(!c||!c.ok)return o.error=c?`HTTP ${c.status}`:"unreachable",o;let S=await c.json();if(o.agents=S.map(x=>({id:x.id,name:x.name,tier:x.tier,model:x.model,...typeof x.color=="string"&&/^#[0-9a-fA-F]{6}$/.test(x.color)?{color:x.color}:{},skillCount:Number.isFinite(x.skillCount)?x.skillCount:void 0,active:x.active||0,total:x.total||0,errors:x.errors||0,lastActive:x.lastActive,lastSummary:x.lastSummary,hourlyTasks:Array.isArray(x.hourlyTasks)?x.hourlyTasks:void 0,runningTasks:Array.isArray(x.runningTasks)?x.runningTasks:[]})),l&&l.ok){let x=await l.json().catch(()=>({}));o.uptimeSec=x.uptime,typeof x.inflight?.total=="number"&&(o.inflight=x.inflight.total),x.restart&&typeof x.restart.state=="string"&&(o.restart=x.restart),o.name=x.node?.name||x.node?.id||t,o.id=x.node?.id||t,x.usage&&(o.usage=x.usage)}if(u&&u.ok){let x=await u.json().then(d=>Array.isArray(d)?d:[],()=>[]);o.crons=x.map(d=>({id:d.id,enabled:d.enabled===!0,schedule:String(d.schedule||""),timezone:d.timezone,agent:String(d.agent||""),kind:typeof d.command=="string"&&d.command.trim()?"command":"agent",model:d.model,nextRun:d.nextRun,retryPending:d.retryPending===!0,consecutiveErrors:Number(d.consecutiveErrors)||0}))}if(f&&f.ok){let x=await f.json().catch(()=>({}));o.cronRuns=Array.isArray(x.runs)?x.runs:[]}if(y&&y.ok){let x=await y.json().catch(()=>null);x&&Array.isArray(x.routines)&&(o.routines=x.routines.slice(0,ya.routines))}if(h&&h.ok){let x=await h.json().catch(()=>null);x?.active&&x.kind==="lesson"&&(o.lesson={agentId:x.agentId??null,mode:String(x.mode||"teach"),goal:String(x.goal||""),step:Number(x.step)||0,saying:String(x.saying||""),startedAt:String(x.startedAt||"")})}if(T&&T.ok){let x=await T.json().catch(()=>null);x&&Array.isArray(x.sessions)&&Td(o,x.sessions,x.saved??{})}o.reachable=!0,o._peers=Array.isArray(p?.ok?await p.json():null)?o._peers:void 0}catch(s){o.error=s.message||String(s)}return o}var ht=null;function yd(t){if(ht)return ht;let e=ze(process.cwd(),".agentx/wiki");return ht=on({wikiDir:e,pathPrefix:"/admin/wiki",mode:"graph"}),ht}async function xt(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 wd(t,e,a){let n=Math.max(1,Math.min(200,Number(a.get("limit"))||50)),r=e.dashboard.daemonUrl.replace(/\/+$/,""),o=process.env.MESH_TOKEN||ee(e.dashboard,r);try{let s=await fetch(`${r}/events/recent?skip=task:step&limit=${n}`,{headers:o?{Authorization:`Bearer ${o}`}:{},signal:AbortSignal.timeout(5e3)});if(!s.ok){w(t,502,{error:`daemon answered ${s.status}`});return}let i=await s.json();w(t,200,{node:e.node.name||e.node.id,events:i.events??[]})}catch(s){w(t,502,{error:s.message||"daemon unreachable"})}}async function xe(t,e){let a=t.dashboard,n=a.daemonUrl.replace(/\/+$/,""),r=ee(a,n),o=new Map;o.set(n,{name:"primary",url:n,token:r});for(let i of a.daemons){let l=i.url.replace(/\/+$/,"");o.has(l)||o.set(l,{name:i.name,url:l,token:ee(a,l)})}let s=await xt(n,r,e);for(let i of s)o.has(i.url)||o.set(i.url,{...i,token:ee(a,i.url)});return[...o.values()]}var kd=3e3,_d=6e3,Ed=5*6e4,na=new Map,gt=new Map;function Fe(t,e){let a=e?`${e.date}|${e.timezone}`:"live",n=gt.get(a);if(n)return n;let r=(async()=>{let o=await xe(t,AbortSignal.timeout(kd)),s=await Promise.all(o.map(async i=>{let l=await bd(i.url,i.token,AbortSignal.timeout(_d),e);return e?l:Sd(i.url,l)}));return{ts:new Date().toISOString(),nodes:s}})().finally(()=>gt.delete(a));return gt.set(a,r),r}function Sd(t,e,a=Date.now()){if(e.reachable&&!e.error)return na.set(t,{node:e,at:a}),e;let n=na.get(t);return!n||a-n.at>Ed?e:{...n.node,stale:!0,staleSince:new Date(n.at).toISOString(),error:e.error}}function Ch(){na.clear(),gt.clear()}function Td(t,e,a){let n=s=>s?s.replace(/\/+$/,"").split("/").pop()||s:"",r=e.map(s=>({session:String(s.sessionId).slice(0,8),project:n(s.cwd),agentIds:Array.isArray(s.agentIds)?s.agentIds:[],mode:String(s.mode||"notify"),lastSeenAt:Number(s.lastSeenAt)||0,pending:Number(s.pending)||0})),o=new Set(e.map(s=>s.sessionId));for(let[s,i]of Object.entries(a))o.has(s)||!Array.isArray(i.agentIds)||i.agentIds.length===0||r.push({session:s.slice(0,8),project:n(i.cwd),agentIds:i.agentIds,mode:String(i.mode||"notify"),lastSeenAt:Number(i.savedAt)||0,pending:0,waiting:!0});t.attachSessions=r;for(let s of t.agents){let i=r.find(l=>l.agentIds.includes(s.id)&&!l.waiting)??r.find(l=>l.agentIds.includes(s.id));i&&(s.attached={session:i.session,project:i.project,mode:i.mode,lastSeenAt:i.lastSeenAt,waiting:i.waiting})}}function Cd(t,e,a){e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"});let n=!1,r=(l,c)=>{n||e.write(`event: ${l}
17854
+ `)}catch{b.flag=!0}}}}catch{}})();return}if(o==="GET"&&r==="/api/workflows/runs"){try{let d=new URL(t.url||"/","http://localhost"),m=Math.max(1,Math.min(500,Number(d.searchParams.get("limit")||50))),x=d.searchParams.get("workflowId")||void 0,b=d.searchParams.get("summary")==="1"||d.searchParams.get("summary")==="true",k=a.workflowRuns.list({limit:m,workflowId:x}),y=`?limit=${m}${x?`&workflowId=${encodeURIComponent(x)}`:""}${b?"&summary=1":""}`,_=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(R=>({url:R.url,token:R.token}))],M=await Promise.all(_.map(async R=>{let P={};R.token&&(P.Authorization=`Bearer ${R.token}`);try{let B=new AbortController,oe=setTimeout(()=>B.abort(),5e3);try{let z=await fetch(`${R.url.replace(/\/+$/,"")}/api/workflows/runs${y}`,{headers:P,signal:B.signal});if(!z.ok)return[];let D=await z.json();return Array.isArray(D.runs)?D.runs:[]}finally{clearTimeout(oe)}}catch{return[]}})),C=new Map;for(let R of k)C.set(R.id,R);for(let R of M)for(let P of R)C.set(P.id,P);let S=Array.from(C.values()).sort((R,P)=>R.updatedAt<P.updatedAt?1:-1).slice(0,m),I=b?S.map(R=>Yd(R)):S;w(e,200,{runs:I})}catch(d){w(e,502,{error:"runs fetch failed",message:d.message||String(d)})}return}let f=o==="GET"&&r.match(/^\/api\/workflows\/runs\/([^\/]+)$/);if(f){let d=decodeURIComponent(f[1]),m=a.workflowRuns.get(d);if(m){w(e,200,{run:m});return}let x=[{url:a.config.dashboard.daemonUrl,token:a.config.dashboard.token},...(a.config.dashboard.daemons||[]).map(b=>({url:b.url,token:b.token}))];for(let b of x)try{let k={};b.token&&(k.Authorization=`Bearer ${b.token}`);let y=await fetch(`${b.url.replace(/\/+$/,"")}/api/workflows/runs/${encodeURIComponent(d)}`,{headers:k});if(y.ok){w(e,200,await y.json());return}}catch{}w(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 m=a.config.dashboard.daemonUrl.replace(/\/+$/,""),x=await fetch(`${m}/api/actions/builtin`,{headers:d}),b=await x.json().catch(()=>({error:`HTTP ${x.status}`}));w(e,x.status,b)}catch(d){w(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}let h=o==="POST"&&r.match(/^\/workflows\/([^/]+)\/run$/);if(h){try{let d=await he(t).catch(()=>({})),m={"Content-Type":"application/json"};a.config.dashboard.token&&(m.Authorization=`Bearer ${a.config.dashboard.token}`);let x=a.config.dashboard.daemonUrl.replace(/\/+$/,""),b=await fetch(`${x}/workflows/${encodeURIComponent(h[1])}/run`,{method:"POST",headers:m,body:JSON.stringify(d??{})}),k=await b.json().catch(()=>({error:`HTTP ${b.status}`}));w(e,b.status,k)}catch(d){w(e,502,{error:"daemon unreachable",message:d.message||String(d)})}return}if(r.startsWith("/api/workflows")&&Xr(t,e,{store:a.workflowStore,runs:a.workflowRuns,layouts:a.workflowLayouts,requireScope:(m,x,b)=>{if(a.token)return!0;let k=Tt(m);if(!k)return!0;let y=new ae().verify(k);if(!y)return w(x,401,{error:"invalid or revoked token"}),!1;for(let _ of b)if(!be(y,_))return w(x,403,{error:`token missing scope: ${_}`,scopes:y.scopes}),!1;return!0}}))return;if(o==="GET"&&r==="/api/boards"){w(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 v=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/members$/);if(v&&o==="GET"){let d=a.sources.get(v[1]);if(!d){w(e,404,{error:"unknown board"});return}try{let m=typeof d.listMembers=="function"?await d.listMembers():[];w(e,200,m)}catch(m){w(e,502,{error:m.message})}return}let T=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/milestones$/);if(T&&o==="GET"){let d=a.sources.get(T[1]);if(!d){w(e,404,{error:"unknown board"});return}try{let m=typeof d.listMilestones=="function"?await d.listMilestones():[];w(e,200,m)}catch(m){w(e,502,{error:m.message})}return}let E=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items\/(.+?)\/move$/),g=r.match(/^\/api\/boards\/([a-z0-9_-]+)\/items(?:\/(.+))?$/);if(E&&o==="PATCH"){let[,d,m]=E,x=decodeURIComponent(m),b=a.boards.find(C=>C.id===d);if(!b){w(e,404,{error:`unknown board: ${d}`});return}let k=a.sources.get(d);if(!k){w(e,503,{error:`board "${d}" source unavailable`});return}let y=await he(t),_=b.columns.find(C=>C.id===y.to),M=b.columns.find(C=>C.id===y.from);if(!_){w(e,400,{error:`unknown 'to' column: ${y.to}`});return}try{await Vd(k,x,M,_),ia({actor:la(t),action:"move",boardId:d,itemId:x,payload:{from:y.from,to:y.to}}),w(e,200,{ok:!0})}catch(C){w(e,502,{error:C.message||"transition failed"})}return}if(g){let[,d,m]=g,x=m?decodeURIComponent(m):void 0,b=a.boards.find(y=>y.id===d);if(!b){w(e,404,{error:`unknown board: ${d}`});return}let k=a.sources.get(d);if(!k){w(e,503,{error:`board "${d}" source unavailable`});return}if(o==="GET"&&!x){let{columns:y,totals:_}=await Jd(b,k,n.searchParams);w(e,200,{columns:y,totals:_});return}if(o==="GET"&&x){try{let y=typeof k.getItem=="function"?await k.getItem(x):null;if(!y){w(e,404,{error:"not found"});return}w(e,200,y)}catch(y){w(e,502,{error:y.message})}return}if(o==="PATCH"&&x){let y=await he(t);try{let _=typeof k.updateItem=="function"?await k.updateItem(x,y):null;if(!_){w(e,501,{error:"update unsupported"});return}ia({actor:la(t),action:"update",boardId:d,itemId:x,payload:y}),w(e,200,_)}catch(_){w(e,502,{error:_.message})}return}if(o==="POST"&&!x){let y=await he(t);if(!y.title){w(e,400,{error:"title required"});return}if(!k.capabilities.create||!k.create){w(e,400,{error:`source ${k.type} does not support create`});return}try{let _=await k.create({title:y.title,description:y.description,labels:y.labels,assigneeUsernames:y.assigneeUsernames,milestoneTitle:y.milestoneTitle,projectHint:y.projectHint});ia({actor:la(t),action:"create",boardId:d,itemId:_.id,payload:{title:y.title}}),w(e,201,_)}catch(_){w(e,502,{error:_.message})}return}}if(o==="GET"&&/^\/[a-z][a-z-]*\/?$/.test(r)){let d=r.replace(/^\/+|\/+$/g,""),x={health:"/admin/health",ledger:"/admin/ledger",cost:"/admin/cost",projects:"/admin/projects",graph:"/admin/graph",wiki:"/admin/wiki/",observability:"/admin/health"}[d];if(x){e.writeHead(302,{Location:x}),e.end();return}}w(e,404,{error:"not found",path:r})}async function Jd(t,e,a){if(!e.capabilities.listAll||!e.listAll){let d={};for(let m of t.columns)d[m.id]=[];return{columns:d,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),c=parseInt(a.get("closedDays")||String(t.closedWindowDays??30),10),p=t.columns.some(d=>d.kind!=="closed"),u=t.columns.some(d=>d.kind==="closed"),f=p?await e.listAll({sinceDays:l,labels:n.length?n:void 0,search:o,milestone:s,state:"opened"}):[],h=u?await e.listAll({sinceDays:c,labels:n.length?n:void 0,search:o,milestone:s,state:"closed"}):[],v={};for(let d of t.columns)v[d.id]=[];let T=t.columns.find(d=>d.kind==="closed");for(let d of h)T&&v[T.id].push({...d,stage:T.id});let E=t.columns.filter(d=>d.kind!=="closed");for(let d of f){let m=ua(d,E);if(!m)continue;let x=v[m];x&&x.push({...d,stage:m})}if(i)for(let d of Object.keys(v))v[d]=v[d].filter(m=>m.assignee===i);for(let d of Object.keys(v))v[d].sort((m,x)=>{let b=(m.priority??99)-(x.priority??99);return b!==0?b:(x.updatedAt||"").localeCompare(m.updatedAt||"")});let g=Object.fromEntries(Object.entries(v).map(([d,m])=>[d,m.length]));return{columns:v,totals:g}}async function Vd(t,e,a,n){let r=ma(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 Yd(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 Qd(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 qa(a.host,a.token,t.source.projects,n,(...r)=>console.log("[board]",...r))}throw new Error(`unsupported board source: ${t.source.type}`)}function ia(t){try{let e=qe(process.cwd(),".agentx");cs(e)||qd(e,{recursive:!0});let a=JSON.stringify({ts:new Date().toISOString(),...t})+`
17855
+ `;Fd(qe(e,"board-audit.jsonl"),a)}catch{}}function la(t){let e=t.headers["x-forwarded-for"];return(Array.isArray(e)?e[0]:e?.split(",")[0])||t.socket.remoteAddress||"unknown"}var Zd=2e3;async function ep(t,e,a,n){let r={};e&&(r.Authorization=`Bearer ${e}`);let o={id:t,name:t,url:t,reachable:!1,agents:[]};try{let s=n?`?date=${encodeURIComponent(n.date)}&timezone=${encodeURIComponent(n.timezone)}`:"",i=g=>{let d=new AbortController,m=setTimeout(()=>d.abort(),Zd),x=()=>d.abort();return a?.addEventListener("abort",x,{once:!0}),fetch(t+g,{headers:r,signal:d.signal}).then(async b=>{let k=b.ok?await b.json().catch(()=>{}):void 0;return{ok:k!==void 0,json:async()=>k}}).catch(()=>null).finally(()=>{clearTimeout(m),a?.removeEventListener("abort",x)})},[l,c,p,u,f,h,v,T]=await Promise.all([i("/health"),fetch(t+"/agents",{headers:r,signal:a}).catch(()=>null),i("/mesh"),i("/crons"),i("/crons/runs"+s),i("/talk"),i("/routines"),i("/attach/sessions")]);if(!c||!c.ok)return o.error=c?`HTTP ${c.status}`:"unreachable",o;let E=await c.json();if(o.agents=E.map(g=>({id:g.id,name:g.name,tier:g.tier,model:g.model,...typeof g.color=="string"&&/^#[0-9a-fA-F]{6}$/.test(g.color)?{color:g.color}:{},skillCount:Number.isFinite(g.skillCount)?g.skillCount:void 0,active:g.active||0,total:g.total||0,errors:g.errors||0,lastActive:g.lastActive,lastSummary:g.lastSummary,hourlyTasks:Array.isArray(g.hourlyTasks)?g.hourlyTasks:void 0,runningTasks:Array.isArray(g.runningTasks)?g.runningTasks:[]})),l&&l.ok){let g=await l.json().catch(()=>({}));o.uptimeSec=g.uptime,typeof g.inflight?.total=="number"&&(o.inflight=g.inflight.total),g.restart&&typeof g.restart.state=="string"&&(o.restart=g.restart),o.name=g.node?.name||g.node?.id||t,o.id=g.node?.id||t,g.usage&&(o.usage=g.usage)}if(u&&u.ok){let g=await u.json().then(d=>Array.isArray(d)?d:[],()=>[]);o.crons=g.map(d=>({id:d.id,enabled:d.enabled===!0,schedule:String(d.schedule||""),timezone:d.timezone,agent:String(d.agent||""),kind:typeof d.command=="string"&&d.command.trim()?"command":"agent",model:d.model,nextRun:d.nextRun,retryPending:d.retryPending===!0,consecutiveErrors:Number(d.consecutiveErrors)||0}))}if(f&&f.ok){let g=await f.json().catch(()=>({}));o.cronRuns=Array.isArray(g.runs)?g.runs:[]}if(v&&v.ok){let g=await v.json().catch(()=>null);g&&Array.isArray(g.routines)&&(o.routines=g.routines.slice(0,Aa.routines))}if(h&&h.ok){let g=await h.json().catch(()=>null);g?.active&&g.kind==="lesson"&&(o.lesson={agentId:g.agentId??null,mode:String(g.mode||"teach"),goal:String(g.goal||""),step:Number(g.step)||0,saying:String(g.saying||""),startedAt:String(g.startedAt||"")})}if(T&&T.ok){let g=await T.json().catch(()=>null);g&&Array.isArray(g.sessions)&&ip(o,g.sessions,g.saved??{})}o.reachable=!0,o._peers=Array.isArray(p?.ok?await p.json():null)?o._peers:void 0}catch(s){o.error=s.message||String(s)}return o}var xt=null;function tp(t){if(xt)return xt;let e=qe(process.cwd(),".agentx/wiki");return xt=fn({wikiDir:e,pathPrefix:"/admin/wiki",mode:"graph"}),xt}async function bt(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 ap(t,e,a){let n=Math.max(1,Math.min(200,Number(a.get("limit"))||50)),r=e.dashboard.daemonUrl.replace(/\/+$/,""),o=process.env.MESH_TOKEN||q(e.dashboard,r);try{let s=await fetch(`${r}/events/recent?skip=task:step&limit=${n}`,{headers:o?{Authorization:`Bearer ${o}`}:{},signal:AbortSignal.timeout(5e3)});if(!s.ok){w(t,502,{error:`daemon answered ${s.status}`});return}let i=await s.json();w(t,200,{node:e.node.name||e.node.id,events:i.events??[]})}catch(s){w(t,502,{error:s.message||"daemon unreachable"})}}async function ve(t,e){let a=t.dashboard,n=a.daemonUrl.replace(/\/+$/,""),r=q(a,n),o=new Map;o.set(n,{name:"primary",url:n,token:r});for(let i of a.daemons){let l=i.url.replace(/\/+$/,"");o.has(l)||o.set(l,{name:i.name,url:l,token:q(a,l)})}let s=await bt(n,r,e);for(let i of s)o.has(i.url)||o.set(i.url,{...i,token:q(a,i.url)});return[...o.values()]}var np=3e3,rp=6e3,op=5*6e4,ca=new Map,vt=new Map;function Ue(t,e){let a=e?`${e.date}|${e.timezone}`:"live",n=vt.get(a);if(n)return n;let r=(async()=>{let o=await ve(t,AbortSignal.timeout(np)),s=await Promise.all(o.map(async i=>{let l=await ep(i.url,i.token,AbortSignal.timeout(rp),e);return e?l:sp(i.url,l)}));return{ts:new Date().toISOString(),nodes:s}})().finally(()=>vt.delete(a));return vt.set(a,r),r}function sp(t,e,a=Date.now()){if(e.reachable&&!e.error)return ca.set(t,{node:e,at:a}),e;let n=ca.get(t);return!n||a-n.at>op?e:{...n.node,stale:!0,staleSince:new Date(n.at).toISOString(),error:e.error}}function Mg(){ca.clear(),vt.clear()}function ip(t,e,a){let n=s=>s?s.replace(/\/+$/,"").split("/").pop()||s:"",r=e.map(s=>({session:String(s.sessionId).slice(0,8),project:n(s.cwd),agentIds:Array.isArray(s.agentIds)?s.agentIds:[],mode:String(s.mode||"notify"),lastSeenAt:Number(s.lastSeenAt)||0,pending:Number(s.pending)||0})),o=new Set(e.map(s=>s.sessionId));for(let[s,i]of Object.entries(a))o.has(s)||!Array.isArray(i.agentIds)||i.agentIds.length===0||r.push({session:s.slice(0,8),project:n(i.cwd),agentIds:i.agentIds,mode:String(i.mode||"notify"),lastSeenAt:Number(i.savedAt)||0,pending:0,waiting:!0});t.attachSessions=r;for(let s of t.agents){let i=r.find(l=>l.agentIds.includes(s.id)&&!l.waiting)??r.find(l=>l.agentIds.includes(s.id));i&&(s.attached={session:i.session,project:i.project,mode:i.mode,lastSeenAt:i.lastSeenAt,waiting:i.waiting})}}function lp(t,e,a){e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"});let n=!1,r=(l,c)=>{n||e.write(`event: ${l}
17355
17856
  data: ${JSON.stringify(c)}
17356
17857
 
17357
- `)},o=!1,s=async()=>{if(!o){o=!0;try{let l=await Fe(a);r("snapshot",l)}catch(l){r("error",{message:l.message})}finally{o=!1}}};s();let i=setInterval(s,2e3);t.on("close",()=>{n=!0,clearInterval(i),e.end()})}async function Ad(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),i=new Set;i.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let y of a.config.dashboard.daemons)i.add(y.url.replace(/\/+$/,""));try{let y=await xt(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let T of y)i.add(T.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){w(e,403,{error:"node not in dashboard allowlist",target:s});return}let l=ee(a.config.dashboard,s),c={Accept:"text/event-stream"};l&&(c.Authorization=`Bearer ${l}`);let p=new AbortController,u;try{u=await fetch(`${s}/agents/${encodeURIComponent(r)}/tasks/${encodeURIComponent(o)}/stream`,{headers:c,signal:p.signal})}catch(y){w(e,502,{error:y.message||"upstream connect failed"});return}if(!u.ok||!u.body){w(e,u.status||502,{error:`upstream HTTP ${u.status}`});return}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"});let f=u.body.getReader();(async()=>{try{for(;;){let{value:y,done:T}=await f.read();if(T)break;y&&e.write(y)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{p.abort();try{e.end()}catch{}})}function Md(t,e,a){let n=Et(t);if(!n)return w(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let r=new Z().verify(n);if(!r)return w(e,401,{error:"invalid or revoked token"}),null;for(let o of a)if(!ve(r,o))return w(e,403,{error:`token missing scope: ${o}`,scopes:r.scopes}),null;return r}async function Id(t,e,a,n){let r=a.agents?.[n];if(!r){w(e,404,{error:"unknown agent"});return}if(r.access!=="public"){w(e,403,{error:"agent is private",hint:`set agents.${n}.access = "public" to expose it`});return}let o;try{o=await fe(t)}catch{w(e,400,{error:"invalid JSON body"});return}let s=o?.message;if(!s||typeof s!="string"){w(e,400,{error:"required: { message: string, context?: {...} }"});return}let i=a.dashboard.daemonUrl.replace(/\/+$/,""),l={"Content-Type":"application/json"};a.dashboard.token&&(l.Authorization=`Bearer ${a.dashboard.token}`);try{let c=await fetch(`${i}/task`,{method:"POST",headers:l,body:JSON.stringify({agent:n,message:s,context:{channel:"public-api",sender:o.context?.sender||"api",...o.context||{}}})}),p=await c.text();e.writeHead(c.status,{"Content-Type":c.headers.get("content-type")||"application/json; charset=utf-8"}),e.end(p)}catch(c){w(e,502,{error:c.message||"upstream call failed"})}}async function $d(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 xt(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let f of u)i.add(f.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){w(t,403,{error:"node not in dashboard allowlist",target:s});return}let l=ee(e.config.dashboard,s),c={Accept:"application/json"};l&&(c.Authorization=`Bearer ${l}`);let p=r?`/agents/${encodeURIComponent(n)}/tasks/${encodeURIComponent(r)}`:`/agents/${encodeURIComponent(n)}/tasks?limit=${encodeURIComponent(o)}`;try{let u=await fetch(`${s}${p}`,{headers:c}),f=await u.text();t.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json; charset=utf-8"}),t.end(f)}catch(u){w(t,502,{error:u.message||"upstream fetch failed"})}}async function Ld(t,e,a,n,r,o){await ra(t,e,a,n,`/api/tasks/${encodeURIComponent(r)}/${o}`)}async function ra(t,e,a,n,r){let o={};try{o=await fe(t)??{}}catch{}let s=await Oo(a.config,n,r,o);e.writeHead(s.status,{"Content-Type":s.contentType}),e.end(s.text)}async function Oo(t,e,a,n){let r=(c,p)=>({status:c,text:JSON.stringify(p),contentType:"application/json"}),o=e.replace(/\/+$/,""),s=new Set;s.add(t.dashboard.daemonUrl.replace(/\/+$/,""));for(let c of t.dashboard.daemons)s.add(c.url.replace(/\/+$/,""));try{let c=await xt(t.dashboard.daemonUrl.replace(/\/+$/,""),t.dashboard.token);for(let p of c)s.add(p.url.replace(/\/+$/,""))}catch{}if(!s.has(o))return r(403,{error:"node not in dashboard allowlist",target:o});let i=ee(t.dashboard,o),l={"Content-Type":"application/json",Accept:"application/json"};i&&(l.Authorization=`Bearer ${i}`);try{let c=await fetch(`${o}${a}`,{method:"POST",headers:l,body:JSON.stringify(n??{})});return{status:c.status,text:await c.text(),contentType:c.headers.get("content-type")||"application/json; charset=utf-8"}}catch(c){return r(502,{error:c.message||"upstream fetch failed"})}}function Rd(t){let e=t.channels.push,a=r=>({store:()=>null,publicKey:()=>null,keepRecent:0,allowedHosts:[],reason:r});if(!e.enabled)return a("Notifications are off. On the computer, run: agentx notifications push --enable");if(e.relayTo)return a(`Notifications are set up on ${e.relayTo}. Pair this phone with that computer instead.`);let n=Ea(e.keysFile);return{store:()=>{let r=qe();return r?new Fa(r):null},publicKey:()=>Sa(n)?.publicKey??null,keepRecent:e.keepRecent,allowedHosts:e.allowedHosts,reason:"The database on this computer is unavailable, so notifications can't be saved."}}function No(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=n=>{try{return JSON.parse(n)}catch{return{error:n.slice(0,200)}}};return{snapshot:n=>Fe(t,n),async nodePost(n,r,o){let s=await Oo(t,n,r,o);return{status:s.status,body:a(s.text)}},async approvals(){let n={node:e,nodeName:t.node?.name||"this computer",items:[]};try{n.items=Ge({root:process.cwd()}).items.map(Ro)}catch(o){n.error=o.message}let r=await Promise.all(t.dashboard.daemons.map(async o=>{let s={node:o.url.replace(/\/+$/,""),nodeName:o.name,items:[]},i=Ue(o.url,t);if(!i)return s;try{let l=await fetch(`${i.url}/api/admin/approvals`,{headers:{"X-Agentx-Peer":"primary",...i.token?{Authorization:`Bearer ${i.token}`}:{}},signal:AbortSignal.timeout(4e3)});if(!l.ok)return s.error=`HTTP ${l.status}`,s;let c=await l.json();s.items=(c.items??[]).map(Ro)}catch(l){s.error=l.message||"unreachable"}return s}));return[n,...r]},async decide(n,r,o,s){let i=n.replace(/\/+$/,"");if(i===e){let c=Ce(),p=await Xe({root:process.cwd()},r,o,{laterHours:c.laterHours,by:s});return p.ok?{status:200,body:{ok:!0,message:p.message}}:{status:409,body:{error:p.error}}}let l=Ue(i,t);if(!l)return{status:403,body:{error:"node not in dashboard allowlist",target:i}};try{let c=await fetch(`${l.url}/api/admin/approvals/decide`,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"agentx-board","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},body:JSON.stringify({key:r,action:o}),signal:AbortSignal.timeout(1e4)});return{status:c.status,body:a(await c.text())}}catch(c){return{status:502,body:{error:c.message||"peer dashboard unreachable"}}}}}}function jd(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=ee(t.dashboard,e),n=No(t);return{store:()=>{let r=qe();return r?new Be(r):null},daemon:{url:e,token:a,name:t.node?.name},snapshot:()=>Fe(t),meshPeers:async()=>{let r=await fetch(e+"/mesh",{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(3e3)});return r.ok?await r.json():[]},nodePost:(r,o,s)=>n.nodePost(r,o,s),tokenFor:r=>ee(t.dashboard,r.replace(/\/+$/,""))}}function Pd(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,"");return{store:()=>{let a=qe();return a?new Be(a):null},daemon:{url:e,token:ee(t.dashboard,e)}}}function Ro(t){return{key:t.key,title:t.title,ask:t.ask,recommend:t.recommend,yes:t.yes,no:t.no,raisedBy:t.raised_by,expires:t.expires}}var Od=`
17858
+ `)},o=!1,s=async()=>{if(!o){o=!0;try{let l=await Ue(a);r("snapshot",l)}catch(l){r("error",{message:l.message})}finally{o=!1}}};s();let i=setInterval(s,2e3);t.on("close",()=>{n=!0,clearInterval(i),e.end()})}async function cp(t,e,a,n,r,o){let s=n.replace(/\/+$/,""),i=new Set;i.add(a.config.dashboard.daemonUrl.replace(/\/+$/,""));for(let v of a.config.dashboard.daemons)i.add(v.url.replace(/\/+$/,""));try{let v=await bt(a.config.dashboard.daemonUrl.replace(/\/+$/,""),a.config.dashboard.token);for(let T of v)i.add(T.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){w(e,403,{error:"node not in dashboard allowlist",target:s});return}let l=q(a.config.dashboard,s),c={Accept:"text/event-stream"};l&&(c.Authorization=`Bearer ${l}`);let p=new AbortController,u;try{u=await fetch(`${s}/agents/${encodeURIComponent(r)}/tasks/${encodeURIComponent(o)}/stream`,{headers:c,signal:p.signal})}catch(v){w(e,502,{error:v.message||"upstream connect failed"});return}if(!u.ok||!u.body){w(e,u.status||502,{error:`upstream HTTP ${u.status}`});return}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"});let f=u.body.getReader();(async()=>{try{for(;;){let{value:v,done:T}=await f.read();if(T)break;v&&e.write(v)}}catch{}finally{try{e.end()}catch{}}})(),t.on("close",()=>{p.abort();try{e.end()}catch{}})}function dp(t,e,a){let n=Tt(t);if(!n)return w(e,401,{error:"missing token",hint:"pass Authorization: Bearer <token> (agentx token create)"}),null;let r=new ae().verify(n);if(!r)return w(e,401,{error:"invalid or revoked token"}),null;for(let o of a)if(!be(r,o))return w(e,403,{error:`token missing scope: ${o}`,scopes:r.scopes}),null;return r}async function pp(t,e,a,n){let r=a.agents?.[n];if(!r){w(e,404,{error:"unknown agent"});return}if(r.access!=="public"){w(e,403,{error:"agent is private",hint:`set agents.${n}.access = "public" to expose it`});return}let o;try{o=await he(t)}catch{w(e,400,{error:"invalid JSON body"});return}let s=o?.message;if(!s||typeof s!="string"){w(e,400,{error:"required: { message: string, context?: {...} }"});return}let i=a.dashboard.daemonUrl.replace(/\/+$/,""),l={"Content-Type":"application/json"};a.dashboard.token&&(l.Authorization=`Bearer ${a.dashboard.token}`);try{let c=await fetch(`${i}/task`,{method:"POST",headers:l,body:JSON.stringify({agent:n,message:s,context:{channel:"public-api",sender:o.context?.sender||"api",...o.context||{}}})}),p=await c.text();e.writeHead(c.status,{"Content-Type":c.headers.get("content-type")||"application/json; charset=utf-8"}),e.end(p)}catch(c){w(e,502,{error:c.message||"upstream call failed"})}}async function up(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 bt(e.config.dashboard.daemonUrl.replace(/\/+$/,""),e.config.dashboard.token);for(let f of u)i.add(f.url.replace(/\/+$/,""))}catch{}if(!i.has(s)){w(t,403,{error:"node not in dashboard allowlist",target:s});return}let l=q(e.config.dashboard,s),c={Accept:"application/json"};l&&(c.Authorization=`Bearer ${l}`);let p=r?`/agents/${encodeURIComponent(n)}/tasks/${encodeURIComponent(r)}`:`/agents/${encodeURIComponent(n)}/tasks?limit=${encodeURIComponent(o)}`;try{let u=await fetch(`${s}${p}`,{headers:c}),f=await u.text();t.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json; charset=utf-8"}),t.end(f)}catch(u){w(t,502,{error:u.message||"upstream fetch failed"})}}async function mp(t,e,a,n,r,o){await da(t,e,a,n,`/api/tasks/${encodeURIComponent(r)}/${o}`)}async function da(t,e,a,n,r){let o={};try{o=await he(t)??{}}catch{}let s=await ds(a.config,n,r,o);e.writeHead(s.status,{"Content-Type":s.contentType}),e.end(s.text)}async function ds(t,e,a,n){let r=(c,p)=>({status:c,text:JSON.stringify(p),contentType:"application/json"}),o=e.replace(/\/+$/,""),s=new Set;s.add(t.dashboard.daemonUrl.replace(/\/+$/,""));for(let c of t.dashboard.daemons)s.add(c.url.replace(/\/+$/,""));try{let c=await bt(t.dashboard.daemonUrl.replace(/\/+$/,""),t.dashboard.token);for(let p of c)s.add(p.url.replace(/\/+$/,""))}catch{}if(!s.has(o))return r(403,{error:"node not in dashboard allowlist",target:o});let i=q(t.dashboard,o),l={"Content-Type":"application/json",Accept:"application/json"};i&&(l.Authorization=`Bearer ${i}`);try{let c=await fetch(`${o}${a}`,{method:"POST",headers:l,body:JSON.stringify(n??{})});return{status:c.status,text:await c.text(),contentType:c.headers.get("content-type")||"application/json; charset=utf-8"}}catch(c){return r(502,{error:c.message||"upstream fetch failed"})}}function ps(t){let e=t.channels.push,a=r=>({store:()=>null,publicKey:()=>null,keepRecent:0,allowedHosts:[],reason:r});if(!e.enabled)return a("Notifications are off. On the computer, run: agentx notifications push --enable");if(e.relayTo)return a(`Notifications are set up on ${e.relayTo}. Pair this phone with that computer instead.`);let n=La(e.keysFile);return{store:()=>{let r=Ce();return r?new Va(r):null},publicKey:()=>$a(n)?.publicKey??null,keepRecent:e.keepRecent,allowedHosts:e.allowedHosts,reason:"The database on this computer is unavailable, so notifications can't be saved."}}function us(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=n=>{try{return JSON.parse(n)}catch{return{error:n.slice(0,200)}}};return{snapshot:n=>Ue(t,n),async nodePost(n,r,o){let s=await ds(t,n,r,o);return{status:s.status,body:a(s.text)}},async approvals(){let n={node:e,nodeName:t.node?.name||"this computer",items:[]};try{n.items=Xe({root:process.cwd()}).items.map(is)}catch(o){n.error=o.message}let r=await Promise.all(t.dashboard.daemons.map(async o=>{let s={node:o.url.replace(/\/+$/,""),nodeName:o.name,items:[]},i=We(o.url,t);if(!i)return s;try{let l=await fetch(`${i.url}/api/admin/approvals`,{headers:{"X-Agentx-Peer":"primary",...i.token?{Authorization:`Bearer ${i.token}`}:{}},signal:AbortSignal.timeout(4e3)});if(!l.ok)return s.error=`HTTP ${l.status}`,s;let c=await l.json();s.items=(c.items??[]).map(is)}catch(l){s.error=l.message||"unreachable"}return s}));return[n,...r]},async decide(n,r,o,s){let i=n.replace(/\/+$/,"");if(i===e){let c=Ie(),p=await Ke({root:process.cwd()},r,o,{laterHours:c.laterHours,by:s});return p.ok?{status:200,body:{ok:!0,message:p.message}}:{status:409,body:{error:p.error}}}let l=We(i,t);if(!l)return{status:403,body:{error:"node not in dashboard allowlist",target:i}};try{let c=await fetch(`${l.url}/api/admin/approvals/decide`,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"agentx-board","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},body:JSON.stringify({key:r,action:o}),signal:AbortSignal.timeout(1e4)});return{status:c.status,body:a(await c.text())}}catch(c){return{status:502,body:{error:c.message||"peer dashboard unreachable"}}}}}}function fp(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,""),a=q(t.dashboard,e),n=us(t);return{store:()=>{let r=Ce();return r?new Fe(r):null},daemon:{url:e,token:a,name:t.node?.name},snapshot:()=>Ue(t),meshPeers:async()=>{let r=await fetch(e+"/mesh",{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(3e3)});return r.ok?await r.json():[]},nodePost:(r,o,s)=>n.nodePost(r,o,s),tokenFor:r=>q(t.dashboard,r.replace(/\/+$/,"")),...hp(t,e,a)}}function hp(t,e,a){let n=ps(t);return{finishAlerts:r=>{let o=n.store();return!!o&&o.chatFinishOn(r)&&o.list(r).length>0},notifyFinish:async r=>{try{let o=await fetch(e+"/channel/send",{method:"POST",headers:{"Content-Type":"application/json",...a?{Authorization:`Bearer ${a}`}:{}},body:JSON.stringify({channel:"push",chatId:r.deviceId,text:`${r.title}
17859
+ ${r.body}`,buttons:[{label:"Open",url:r.url}]}),signal:AbortSignal.timeout(1e4)});o.ok||console.error(`[app] finish notification not sent: HTTP ${o.status} ${(await o.text()).slice(0,160)}`)}catch(o){console.error(`[app] finish notification not sent: ${o?.message||o}`)}}}}function gp(t){let e=t.dashboard.daemonUrl.replace(/\/+$/,"");return{store:()=>{let a=Ce();return a?new Fe(a):null},daemon:{url:e,token:q(t.dashboard,e)}}}function is(t){return{key:t.key,title:t.title,ask:t.ask,recommend:t.recommend,yes:t.yes,no:t.no,raisedBy:t.raised_by,expires:t.expires}}var xp=`
17358
17860
  You are helping draft a new GitLab issue. Follow these conventions strictly.
17359
17861
 
17360
17862
  Title pattern:
@@ -17386,10 +17888,10 @@ Return ONLY a single JSON object on one line \u2014 no prose, no code fences, no
17386
17888
  Shape:
17387
17889
  { "title": string, "description": string, "labels": string[], "assigneeUsername": string | null, "kind": string }
17388
17890
  If you don't have enough information to pick a label confidently, omit it rather than guessing.
17389
- `;async function Nd(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):
17891
+ `;async function vp(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):
17390
17892
  - ${r.knownLabels.slice(0,60).join(`
17391
17893
  - `)}`:"",r.members?.length?`Possible assignees (GitLab usernames): ${r.members.slice(0,20).join(", ")}`:"","","Produce the JSON draft now."].filter(Boolean).join(`
17392
- `),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:Od}})});if(!l.ok)throw new Error(`daemon /task HTTP ${l.status}: ${await l.text().catch(()=>"")}`);let c=await l.json();if(c.error)throw new Error(String(c.error));let p=(c.content||"").toString(),u=Dd(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(h=>typeof h=="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 Dd(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 Hd(t){let e=pd(dd(import.meta.url));return ze(e,t)}async function Bd(t){return cd(t)}function w(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function fe(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 Do(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:Do(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 zd(t,e,a){let n=new URL(t.url||"/","http://_"),r=parseInt(n.searchParams.get("hours")||"6",10)||6;w(e,200,await lt(await Ho(r,a.config)))}async function Ho(t,e){let a=e.node?.id||e.node?.name||"local",n=[],r=zt(t);r&&n.push({nodeId:a,snap:r});let o=(e.dashboard?.daemons||[]).filter(i=>i.url),s=await Promise.all(o.map(async i=>{let l=Ue(i.url.replace(/\/+$/,""),e);if(!l)return null;try{let c=new AbortController,p=setTimeout(()=>c.abort(),8e3);try{let u=await fetch(`${l.url}/api/admin/activity-graph?hours=${t}`,{headers:{Accept:"application/json","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},signal:c.signal});return u.ok?{nodeId:i.name||i.url,snap:await u.json()}:null}finally{clearTimeout(p)}}catch{return null}}));for(let i of s)i&&n.push(i);return sr(n)}async function Fd(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),h=f.find(y=>Po(y));if(!h){e.writeHead(503,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"no log source \u2014 install journalctl, run the daemon under launchd, or run it foreground writing to /tmp/agentx-daemon.log",searched:f}));return}r="tail",o=["-F","-n","200",h]}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`: source=${r}
17894
+ `),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:xp}})});if(!l.ok)throw new Error(`daemon /task HTTP ${l.status}: ${await l.text().catch(()=>"")}`);let c=await l.json();if(c.error)throw new Error(String(c.error));let p=(c.content||"").toString(),u=bp(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(h=>typeof h=="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 bp(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 yp(t){let e=Gd(Wd(import.meta.url));return qe(e,t)}async function wp(t){return Ud(t)}function w(t,e,a){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a))}async function he(t){return new Promise((e,a)=>{let n=[];t.on("data",r=>n.push(r)),t.on("end",()=>{try{let r=Buffer.concat(n).toString("utf-8");e(r?JSON.parse(r):{})}catch(r){a(r)}}),t.on("error",a)})}function ms(t){return t.dashboardUrl?t.dashboardUrl.replace(/\/+$/,""):t.url.replace(/\/+$/,"").replace(/:(?:1[89][89]00|18810)$/,":4202")}function N(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:ms(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 kp(t,e,a){let n=new URL(t.url||"/","http://_"),r=parseInt(n.searchParams.get("hours")||"6",10)||6;w(e,200,await ct(await fs(r,a.config)))}async function fs(t,e){let a=e.node?.id||e.node?.name||"local",n=[],r=qt(t);r&&n.push({nodeId:a,snap:r});let o=(e.dashboard?.daemons||[]).filter(i=>i.url),s=await Promise.all(o.map(async i=>{let l=We(i.url.replace(/\/+$/,""),e);if(!l)return null;try{let c=new AbortController,p=setTimeout(()=>c.abort(),8e3);try{let u=await fetch(`${l.url}/api/admin/activity-graph?hours=${t}`,{headers:{Accept:"application/json","X-Agentx-Peer":"primary",...l.token?{Authorization:`Bearer ${l.token}`}:{}},signal:c.signal});return u.ok?{nodeId:i.name||i.url,snap:await u.json()}:null}finally{clearTimeout(p)}}catch{return null}}));for(let i of s)i&&n.push(i);return fr(n)}async function _p(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),h=f.find(v=>cs(v));if(!h){e.writeHead(503,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"no log source \u2014 install journalctl, run the daemon under launchd, or run it foreground writing to /tmp/agentx-daemon.log",searched:f}));return}r="tail",o=["-F","-n","200",h]}e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),e.write(`: source=${r}
17393
17895
 
17394
17896
  `);let s=a(r,o,{stdio:["ignore","pipe","pipe"]}),i="",l=u=>{i+=u.toString("utf8");let f;for(;(f=i.indexOf(`
17395
17897
  `))>=0;){let h=i.slice(0,f).replace(/\r$/,"");i=i.slice(f+1);try{e.write(`event: line
@@ -17397,5 +17899,5 @@ data: ${h.replace(/\n/g," ")}
17397
17899
 
17398
17900
  `)}catch{}}};s.stdout?.on("data",l),s.stderr?.on("data",l);let c=setInterval(()=>{try{e.write(`: hb
17399
17901
 
17400
- `)}catch{}},15e3),p=()=>{clearInterval(c);try{s.kill()}catch{}try{e.end()}catch{}};t.on("close",p),s.on("exit",p),s.on("error",p)}async function jo(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 h=[];t.on("data",y=>h.push(y)),t.on("end",()=>u(Buffer.concat(h))),t.on("error",f)}):void 0,l={},c=t.headers["content-type"];c&&(l["Content-Type"]=Array.isArray(c)?c[0]:c);let p=t.headers["x-requested-with"];p&&(l["X-Requested-With"]=Array.isArray(p)?p[0]:p),a.token&&(l.Authorization=`Bearer ${a.token}`),l["X-Agentx-Peer"]="primary";try{let u=await fetch(r,{method:o,headers:l,body:i&&i.length>0?i:void 0}),f=Buffer.from(await u.arrayBuffer());e.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json","Cache-Control":"no-store"}),e.end(f)}catch(u){w(e,502,{error:`proxy to peer failed: ${u?.message||u}`,target:r})}}function Ue(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(r=>r.url.replace(/\/+$/,"")===a);return n?{url:Do(n),token:n.dashboardToken||n.token}:null}export{Td as applyAttachSessions,bd as fetchDaemonAgents,md as handleBoardRequest,Ch as resetLiveCaches,xe as resolveNodeTargets,Th as startBoardDashboard,Sd as withLastGood};
17401
- //# sourceMappingURL=board-dashboard-JBRO26JC.js.map
17902
+ `)}catch{}},15e3),p=()=>{clearInterval(c);try{s.kill()}catch{}try{e.end()}catch{}};t.on("close",p),s.on("exit",p),s.on("error",p)}async function ls(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 h=[];t.on("data",v=>h.push(v)),t.on("end",()=>u(Buffer.concat(h))),t.on("error",f)}):void 0,l={},c=t.headers["content-type"];c&&(l["Content-Type"]=Array.isArray(c)?c[0]:c);let p=t.headers["x-requested-with"];p&&(l["X-Requested-With"]=Array.isArray(p)?p[0]:p),a.token&&(l.Authorization=`Bearer ${a.token}`),l["X-Agentx-Peer"]="primary";try{let u=await fetch(r,{method:o,headers:l,body:i&&i.length>0?i:void 0}),f=Buffer.from(await u.arrayBuffer());e.writeHead(u.status,{"Content-Type":u.headers.get("content-type")||"application/json","Cache-Control":"no-store"}),e.end(f)}catch(u){w(e,502,{error:`proxy to peer failed: ${u?.message||u}`,target:r})}}function We(t,e){let a=t.replace(/\/+$/,""),n=(e.dashboard?.daemons||[]).find(r=>r.url.replace(/\/+$/,"")===a);return n?{url:ms(n),token:n.dashboardToken||n.token}:null}export{ip as applyAttachSessions,ep as fetchDaemonAgents,Kd as handleBoardRequest,Mg as resetLiveCaches,ve as resolveNodeTargets,Cg as startBoardDashboard,sp as withLastGood};
17903
+ //# sourceMappingURL=board-dashboard-K3P2M7A7.js.map