@poncho-ai/cli 0.2.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 (516) hide show
  1. package/.turbo/turbo-build.log +19 -0
  2. package/.turbo/turbo-test.log +389 -0
  3. package/CHANGELOG.md +17 -0
  4. package/LICENSE +21 -0
  5. package/dist/chunk-22OMLQUR.js +1249 -0
  6. package/dist/chunk-24JFN5RM.js +1887 -0
  7. package/dist/chunk-24TAT3US.js +2137 -0
  8. package/dist/chunk-26YBLT7G.js +997 -0
  9. package/dist/chunk-2EJIC6UW.js +1893 -0
  10. package/dist/chunk-2JNCF37R.js +1156 -0
  11. package/dist/chunk-2LVMUHJX.js +1874 -0
  12. package/dist/chunk-2OVSD65B.js +1269 -0
  13. package/dist/chunk-2RQ45LI6.js +1251 -0
  14. package/dist/chunk-2SMIRDLI.js +1854 -0
  15. package/dist/chunk-2UXPHBFI.js +1862 -0
  16. package/dist/chunk-2VFM7SSZ.js +1135 -0
  17. package/dist/chunk-2ZAUADNG.js +1456 -0
  18. package/dist/chunk-2ZNUT5WA.js +1862 -0
  19. package/dist/chunk-33ZQ7WTP.js +1834 -0
  20. package/dist/chunk-34ARQX3O.js +1156 -0
  21. package/dist/chunk-3BEWSRFW.js +1893 -0
  22. package/dist/chunk-3DVE5AG6.js +1862 -0
  23. package/dist/chunk-3KE6MHO6.js +1608 -0
  24. package/dist/chunk-3MOLPB7Z.js +997 -0
  25. package/dist/chunk-3OZZOYAZ.js +1884 -0
  26. package/dist/chunk-3VJYNZEF.js +2181 -0
  27. package/dist/chunk-3W27LOUH.js +997 -0
  28. package/dist/chunk-3WMAW74D.js +1163 -0
  29. package/dist/chunk-3Z4AHBPF.js +1569 -0
  30. package/dist/chunk-43NK6MB4.js +1977 -0
  31. package/dist/chunk-4E5M2IGA.js +1300 -0
  32. package/dist/chunk-4FVI4LVI.js +1862 -0
  33. package/dist/chunk-4GNQQJUP.js +1156 -0
  34. package/dist/chunk-4PGZFTVC.js +1234 -0
  35. package/dist/chunk-4QE2HDNC.js +1355 -0
  36. package/dist/chunk-4S2EL4ED.js +1135 -0
  37. package/dist/chunk-536SSOJ3.js +1797 -0
  38. package/dist/chunk-5CNEGIC5.js +997 -0
  39. package/dist/chunk-5CWN43YL.js +1147 -0
  40. package/dist/chunk-5HZCYTUZ.js +997 -0
  41. package/dist/chunk-5ICNG6RX.js +1885 -0
  42. package/dist/chunk-5OUIRXMN.js +997 -0
  43. package/dist/chunk-5T34JOWH.js +1460 -0
  44. package/dist/chunk-5XBAIQX3.js +1862 -0
  45. package/dist/chunk-65AIX3CS.js +1441 -0
  46. package/dist/chunk-67NBW4NG.js +1355 -0
  47. package/dist/chunk-6AFIL35M.js +1414 -0
  48. package/dist/chunk-6B3XMBKA.js +1716 -0
  49. package/dist/chunk-6CEJO4OM.js +1242 -0
  50. package/dist/chunk-6DQZUP3B.js +1460 -0
  51. package/dist/chunk-6ET624OE.js +1441 -0
  52. package/dist/chunk-6I7WFMAU.js +1862 -0
  53. package/dist/chunk-6MOKAYCL.js +1449 -0
  54. package/dist/chunk-6RFUALWB.js +1845 -0
  55. package/dist/chunk-73E57JUS.js +1231 -0
  56. package/dist/chunk-73SU7GT4.js +816 -0
  57. package/dist/chunk-74IRETUF.js +997 -0
  58. package/dist/chunk-77BYFMUN.js +1924 -0
  59. package/dist/chunk-7DAC2XE5.js +1460 -0
  60. package/dist/chunk-7GBQ4YSB.js +1024 -0
  61. package/dist/chunk-7TOJGUQ5.js +1803 -0
  62. package/dist/chunk-7W7KPLEG.js +1163 -0
  63. package/dist/chunk-7Y7ZXEN2.js +817 -0
  64. package/dist/chunk-A5WKH7H2.js +852 -0
  65. package/dist/chunk-A775UYQB.js +1886 -0
  66. package/dist/chunk-AC4OGTSK.js +1313 -0
  67. package/dist/chunk-ACCRUQ6J.js +1271 -0
  68. package/dist/chunk-AEAZZFTT.js +1886 -0
  69. package/dist/chunk-AIAC5Z55.js +1147 -0
  70. package/dist/chunk-AN34PI2R.js +1238 -0
  71. package/dist/chunk-APIA7MHJ.js +1355 -0
  72. package/dist/chunk-AQGIIT7R.js +1347 -0
  73. package/dist/chunk-ATXKV2NH.js +2111 -0
  74. package/dist/chunk-AVBKQZYR.js +1010 -0
  75. package/dist/chunk-AWIXDCZF.js +1329 -0
  76. package/dist/chunk-AXFHQBKT.js +2128 -0
  77. package/dist/chunk-AYDSTU4P.js +1156 -0
  78. package/dist/chunk-AZ35PK7E.js +1271 -0
  79. package/dist/chunk-BE6HB4IO.js +2155 -0
  80. package/dist/chunk-BIX2FI3S.js +1625 -0
  81. package/dist/chunk-BPPM5YPG.js +997 -0
  82. package/dist/chunk-BRCIVYKE.js +1420 -0
  83. package/dist/chunk-BRK2KKTF.js +1236 -0
  84. package/dist/chunk-BU7R2TVT.js +1862 -0
  85. package/dist/chunk-BXJQ4G5F.js +1901 -0
  86. package/dist/chunk-C3KTCROR.js +1128 -0
  87. package/dist/chunk-C42IGDJW.js +1032 -0
  88. package/dist/chunk-CBRPO2FE.js +1886 -0
  89. package/dist/chunk-CDNITKC6.js +1163 -0
  90. package/dist/chunk-CDVWUDFM.js +1389 -0
  91. package/dist/chunk-CH2IE453.js +1147 -0
  92. package/dist/chunk-CIHC46FS.js +1010 -0
  93. package/dist/chunk-CIYO754K.js +1687 -0
  94. package/dist/chunk-CJFNJ7U3.js +918 -0
  95. package/dist/chunk-CJN66CJY.js +1024 -0
  96. package/dist/chunk-CLJFTDJQ.js +1667 -0
  97. package/dist/chunk-CLNCOQNI.js +997 -0
  98. package/dist/chunk-CN4AUQL4.js +1460 -0
  99. package/dist/chunk-CQYGUBY6.js +1854 -0
  100. package/dist/chunk-CRJUMKVB.js +1862 -0
  101. package/dist/chunk-CZHUYI2J.js +997 -0
  102. package/dist/chunk-DIBSIWSR.js +1256 -0
  103. package/dist/chunk-DJGC3R4O.js +1836 -0
  104. package/dist/chunk-DJR2PEAQ.js +1884 -0
  105. package/dist/chunk-DKE7NWBK.js +1862 -0
  106. package/dist/chunk-DXYDN2OS.js +1147 -0
  107. package/dist/chunk-DZ3FEUJ7.js +1147 -0
  108. package/dist/chunk-EC47SFY3.js +1113 -0
  109. package/dist/chunk-ECAALEAK.js +1239 -0
  110. package/dist/chunk-ECEYIAQZ.js +997 -0
  111. package/dist/chunk-EKX7AV7O.js +1024 -0
  112. package/dist/chunk-EN6CTYUN.js +634 -0
  113. package/dist/chunk-EXCH47WX.js +1460 -0
  114. package/dist/chunk-EY2JOCTM.js +1862 -0
  115. package/dist/chunk-EYHB3LTH.js +1818 -0
  116. package/dist/chunk-F2AC5PKU.js +1446 -0
  117. package/dist/chunk-F5RCUJ62.js +1156 -0
  118. package/dist/chunk-F6OM65VA.js +1460 -0
  119. package/dist/chunk-FAEJ5CQU.js +997 -0
  120. package/dist/chunk-FB7X4KBF.js +1460 -0
  121. package/dist/chunk-FBSEEW3H.js +1862 -0
  122. package/dist/chunk-FBYY3TE5.js +1862 -0
  123. package/dist/chunk-FEA3GBGG.js +997 -0
  124. package/dist/chunk-FHPRGTOJ.js +1131 -0
  125. package/dist/chunk-FLAY6YWY.js +1389 -0
  126. package/dist/chunk-FNXIVJ3B.js +997 -0
  127. package/dist/chunk-FWRVG7RM.js +2160 -0
  128. package/dist/chunk-G47UW452.js +916 -0
  129. package/dist/chunk-G6V5O5AV.js +997 -0
  130. package/dist/chunk-GACQBIOO.js +1613 -0
  131. package/dist/chunk-GBFHLBWT.js +881 -0
  132. package/dist/chunk-GLJLTQMZ.js +997 -0
  133. package/dist/chunk-GN7DDBAT.js +1872 -0
  134. package/dist/chunk-GPTI42MM.js +1355 -0
  135. package/dist/chunk-GPXGCPVY.js +1834 -0
  136. package/dist/chunk-GRASQSCU.js +1886 -0
  137. package/dist/chunk-GU2WWG5C.js +1314 -0
  138. package/dist/chunk-GW3SAYT3.js +1679 -0
  139. package/dist/chunk-GZ4F2VI5.js +1447 -0
  140. package/dist/chunk-GZYXND4U.js +1322 -0
  141. package/dist/chunk-H27BRPVI.js +1862 -0
  142. package/dist/chunk-H4JRTOW7.js +1862 -0
  143. package/dist/chunk-HDS72SRU.js +1138 -0
  144. package/dist/chunk-HEUGSUL5.js +757 -0
  145. package/dist/chunk-HMZN5GPS.js +1024 -0
  146. package/dist/chunk-HN5SVGQO.js +1163 -0
  147. package/dist/chunk-HN6VQ5FI.js +242 -0
  148. package/dist/chunk-HNTQ66EL.js +2054 -0
  149. package/dist/chunk-HSDL3YK5.js +1134 -0
  150. package/dist/chunk-HVMIMERW.js +997 -0
  151. package/dist/chunk-HVWCQS2B.js +1834 -0
  152. package/dist/chunk-HVYMSOXQ.js +2156 -0
  153. package/dist/chunk-HYQITTK3.js +1862 -0
  154. package/dist/chunk-I4CCYPAI.js +1239 -0
  155. package/dist/chunk-IDG3X4UL.js +1229 -0
  156. package/dist/chunk-IDVRTQJ3.js +1514 -0
  157. package/dist/chunk-IEER23NN.js +1862 -0
  158. package/dist/chunk-IKLRYA4W.js +785 -0
  159. package/dist/chunk-IQBUSFBY.js +1270 -0
  160. package/dist/chunk-IUXQDZIR.js +1862 -0
  161. package/dist/chunk-IV74RJFV.js +1862 -0
  162. package/dist/chunk-IVEMIXXO.js +1854 -0
  163. package/dist/chunk-J4PNCGSP.js +1460 -0
  164. package/dist/chunk-J7ULLJUI.js +1862 -0
  165. package/dist/chunk-J7WHTBOM.js +983 -0
  166. package/dist/chunk-JBN6D7EG.js +1757 -0
  167. package/dist/chunk-JDKSD54C.js +1366 -0
  168. package/dist/chunk-JGWTOS7A.js +1507 -0
  169. package/dist/chunk-JHJ6FMSI.js +1804 -0
  170. package/dist/chunk-JJSHCP32.js +1282 -0
  171. package/dist/chunk-JLMAMC3V.js +1625 -0
  172. package/dist/chunk-JMTF7VV5.js +1919 -0
  173. package/dist/chunk-JO56GKTV.js +1133 -0
  174. package/dist/chunk-JRN3P6CS.js +1441 -0
  175. package/dist/chunk-JTKPRRSM.js +1024 -0
  176. package/dist/chunk-JVTFCTGO.js +1868 -0
  177. package/dist/chunk-JXH452LK.js +956 -0
  178. package/dist/chunk-K4SW5SP4.js +1147 -0
  179. package/dist/chunk-KANVHOQK.js +1880 -0
  180. package/dist/chunk-KBJZJWPZ.js +1143 -0
  181. package/dist/chunk-KFC4ZVRH.js +1798 -0
  182. package/dist/chunk-KHG6MSLS.js +1885 -0
  183. package/dist/chunk-KJJE6V5N.js +1886 -0
  184. package/dist/chunk-KKLEILZP.js +1868 -0
  185. package/dist/chunk-KW5QXXEN.js +1641 -0
  186. package/dist/chunk-KWMTK4N7.js +1147 -0
  187. package/dist/chunk-KYOW6LIV.js +1231 -0
  188. package/dist/chunk-KYWIUH3M.js +1355 -0
  189. package/dist/chunk-KZEA3HJL.js +1833 -0
  190. package/dist/chunk-L3KONBJE.js +1355 -0
  191. package/dist/chunk-L47B3OMM.js +1156 -0
  192. package/dist/chunk-LCQFWI6S.js +997 -0
  193. package/dist/chunk-LFIUZUI5.js +1138 -0
  194. package/dist/chunk-LHSLPQR4.js +1854 -0
  195. package/dist/chunk-LJGVAOFP.js +647 -0
  196. package/dist/chunk-LKJDYQPA.js +1687 -0
  197. package/dist/chunk-LOY6PWTR.js +1336 -0
  198. package/dist/chunk-LPFN3GNV.js +1147 -0
  199. package/dist/chunk-LPM7AN7S.js +1147 -0
  200. package/dist/chunk-LU6ES63L.js +1249 -0
  201. package/dist/chunk-M73DE7AU.js +1389 -0
  202. package/dist/chunk-M7OJ52WK.js +1448 -0
  203. package/dist/chunk-MCSM3DAE.js +1024 -0
  204. package/dist/chunk-MEP7OYUL.js +1417 -0
  205. package/dist/chunk-MFH6MVWX.js +1441 -0
  206. package/dist/chunk-MIHU3TFJ.js +1156 -0
  207. package/dist/chunk-MIU5FMSV.js +1329 -0
  208. package/dist/chunk-MJQMHH7Z.js +1976 -0
  209. package/dist/chunk-MLR2HUUY.js +1255 -0
  210. package/dist/chunk-MSBZHMUV.js +997 -0
  211. package/dist/chunk-MV4DZQRB.js +1163 -0
  212. package/dist/chunk-MWBLZDYK.js +1854 -0
  213. package/dist/chunk-N2MEPDSA.js +675 -0
  214. package/dist/chunk-N36ATUZM.js +1863 -0
  215. package/dist/chunk-NEHLM4WN.js +1610 -0
  216. package/dist/chunk-NHOJZ7FZ.js +1138 -0
  217. package/dist/chunk-NLPQBHHH.js +1282 -0
  218. package/dist/chunk-NMY3FWV7.js +1236 -0
  219. package/dist/chunk-NN2WDNCO.js +1138 -0
  220. package/dist/chunk-NNC7LH2Y.js +1258 -0
  221. package/dist/chunk-NQRWXPJ5.js +1275 -0
  222. package/dist/chunk-NR3G3D6Q.js +1238 -0
  223. package/dist/chunk-NRUAFOL3.js +2121 -0
  224. package/dist/chunk-NSCG7F6H.js +1862 -0
  225. package/dist/chunk-NXHVG7ZI.js +1113 -0
  226. package/dist/chunk-NYKPTBXA.js +1258 -0
  227. package/dist/chunk-O4AE4MFX.js +920 -0
  228. package/dist/chunk-O7GTMG3C.js +1467 -0
  229. package/dist/chunk-OBUP5UIM.js +997 -0
  230. package/dist/chunk-ONI2DTTL.js +1156 -0
  231. package/dist/chunk-OQHLTSVD.js +1776 -0
  232. package/dist/chunk-OVV6SHTA.js +997 -0
  233. package/dist/chunk-PAPAMVNI.js +1156 -0
  234. package/dist/chunk-PH7OXFMJ.js +997 -0
  235. package/dist/chunk-PHFLPSZU.js +1608 -0
  236. package/dist/chunk-PTVSK5DV.js +1854 -0
  237. package/dist/chunk-PUHWX6PD.js +1156 -0
  238. package/dist/chunk-PYDU2HN2.js +1803 -0
  239. package/dist/chunk-Q2AMIXBY.js +1250 -0
  240. package/dist/chunk-Q2EARVB7.js +1414 -0
  241. package/dist/chunk-Q4HFSYSN.js +1024 -0
  242. package/dist/chunk-Q65PNALY.js +1024 -0
  243. package/dist/chunk-QBQNHCYH.js +1791 -0
  244. package/dist/chunk-QGI55HK3.js +1433 -0
  245. package/dist/chunk-QIAODEAT.js +1862 -0
  246. package/dist/chunk-QLRJ2X3B.js +1800 -0
  247. package/dist/chunk-QTLVBIBL.js +1147 -0
  248. package/dist/chunk-QUPLQ7O4.js +1862 -0
  249. package/dist/chunk-QZGUSWLN.js +1415 -0
  250. package/dist/chunk-R7N3T7YR.js +1130 -0
  251. package/dist/chunk-RFS3GC46.js +239 -0
  252. package/dist/chunk-RJA7HIQO.js +1823 -0
  253. package/dist/chunk-RJLU3F7G.js +1156 -0
  254. package/dist/chunk-RLBXW5AY.js +1156 -0
  255. package/dist/chunk-RMKHLIMU.js +1147 -0
  256. package/dist/chunk-RS7F3BLO.js +1255 -0
  257. package/dist/chunk-RYLDHQQT.js +997 -0
  258. package/dist/chunk-RYYTEAQ7.js +1147 -0
  259. package/dist/chunk-S2KNKYQJ.js +1815 -0
  260. package/dist/chunk-S5R5IZJH.js +2056 -0
  261. package/dist/chunk-S5S7OBDZ.js +1355 -0
  262. package/dist/chunk-S6YKNJQG.js +1868 -0
  263. package/dist/chunk-SBDVWSWM.js +1251 -0
  264. package/dist/chunk-SBXSREFV.js +1237 -0
  265. package/dist/chunk-SDZJV47M.js +1238 -0
  266. package/dist/chunk-SMBILO75.js +1024 -0
  267. package/dist/chunk-SUSLSP3P.js +1456 -0
  268. package/dist/chunk-T4GPZ2AG.js +1128 -0
  269. package/dist/chunk-TA7EDJXT.js +1460 -0
  270. package/dist/chunk-TAW2ISST.js +1024 -0
  271. package/dist/chunk-TB6KKWS2.js +1138 -0
  272. package/dist/chunk-TBZCEX5O.js +1355 -0
  273. package/dist/chunk-TDOPKFNW.js +756 -0
  274. package/dist/chunk-TGY3JSDQ.js +1460 -0
  275. package/dist/chunk-THOIGUSY.js +666 -0
  276. package/dist/chunk-TLSGQKLO.js +1836 -0
  277. package/dist/chunk-TQ2QEU3G.js +1460 -0
  278. package/dist/chunk-TRJODOZM.js +1232 -0
  279. package/dist/chunk-TSBMRYLQ.js +1717 -0
  280. package/dist/chunk-TUL3R6KB.js +1024 -0
  281. package/dist/chunk-TWCD6YPP.js +2129 -0
  282. package/dist/chunk-TWQDGVLI.js +1323 -0
  283. package/dist/chunk-TZQLWQTW.js +769 -0
  284. package/dist/chunk-U22K555L.js +1803 -0
  285. package/dist/chunk-U3VXLQTW.js +1707 -0
  286. package/dist/chunk-U5QM4SRB.js +2054 -0
  287. package/dist/chunk-UCZLOOAW.js +997 -0
  288. package/dist/chunk-UDA2OZLK.js +1242 -0
  289. package/dist/chunk-UDASJ4IC.js +1355 -0
  290. package/dist/chunk-UGU2KSOQ.js +1113 -0
  291. package/dist/chunk-UJHB3CLA.js +1130 -0
  292. package/dist/chunk-UNUTAECX.js +1238 -0
  293. package/dist/chunk-UUUJVWXA.js +1806 -0
  294. package/dist/chunk-UV4WM7Q5.js +2039 -0
  295. package/dist/chunk-UXPGPOQ3.js +2113 -0
  296. package/dist/chunk-UYVWNYFB.js +1434 -0
  297. package/dist/chunk-UYWI4MPU.js +1460 -0
  298. package/dist/chunk-V2FNBN3P.js +997 -0
  299. package/dist/chunk-V6CF5XXG.js +1862 -0
  300. package/dist/chunk-V6UUV2SZ.js +1156 -0
  301. package/dist/chunk-VARTDMWQ.js +1862 -0
  302. package/dist/chunk-VC7ZYKMP.js +1156 -0
  303. package/dist/chunk-VCJNX77B.js +2038 -0
  304. package/dist/chunk-VDE2I72J.js +650 -0
  305. package/dist/chunk-VEO7FKEL.js +1156 -0
  306. package/dist/chunk-VIJYIU7E.js +2124 -0
  307. package/dist/chunk-VJX4WETG.js +1136 -0
  308. package/dist/chunk-VO3QDFU2.js +1276 -0
  309. package/dist/chunk-VOX2Q2V2.js +1933 -0
  310. package/dist/chunk-W7J5XM2X.js +1862 -0
  311. package/dist/chunk-WONM6P4N.js +1862 -0
  312. package/dist/chunk-WW576PYD.js +1862 -0
  313. package/dist/chunk-XCZCCA2D.js +997 -0
  314. package/dist/chunk-XHQOG4X6.js +1871 -0
  315. package/dist/chunk-XIYLHBWA.js +1163 -0
  316. package/dist/chunk-XKZ6XWSE.js +1907 -0
  317. package/dist/chunk-XLHKOBSF.js +1815 -0
  318. package/dist/chunk-XMMFUBB5.js +1270 -0
  319. package/dist/chunk-XQLK777K.js +1442 -0
  320. package/dist/chunk-XRN47M65.js +997 -0
  321. package/dist/chunk-XVBKUEXA.js +1441 -0
  322. package/dist/chunk-XY4ISIAV.js +1639 -0
  323. package/dist/chunk-Y2SOII6F.js +1156 -0
  324. package/dist/chunk-Y5TJU6YZ.js +1163 -0
  325. package/dist/chunk-YBPCMSUU.js +1147 -0
  326. package/dist/chunk-YDAZ3YZT.js +1004 -0
  327. package/dist/chunk-YH2QPUWO.js +1621 -0
  328. package/dist/chunk-YJX4O5CY.js +1355 -0
  329. package/dist/chunk-YNJMS3VK.js +997 -0
  330. package/dist/chunk-YNRZMOC3.js +997 -0
  331. package/dist/chunk-YNUF5JNP.js +1163 -0
  332. package/dist/chunk-YO7TJ6SG.js +2135 -0
  333. package/dist/chunk-YTUUFYVS.js +1842 -0
  334. package/dist/chunk-YXCOG54V.js +997 -0
  335. package/dist/chunk-Z7V254BA.js +1432 -0
  336. package/dist/chunk-ZBHRR3RS.js +1256 -0
  337. package/dist/chunk-ZM47X5PT.js +1236 -0
  338. package/dist/chunk-ZO6JUCLC.js +917 -0
  339. package/dist/chunk-ZOF4ERNI.js +2039 -0
  340. package/dist/chunk-ZOTRZN3T.js +1238 -0
  341. package/dist/chunk-ZPBA4JGE.js +1234 -0
  342. package/dist/chunk-ZTKGRHNV.js +1138 -0
  343. package/dist/chunk-ZW2JM2OY.js +997 -0
  344. package/dist/chunk-ZXYHUC7C.js +1722 -0
  345. package/dist/cli.d.ts +1 -0
  346. package/dist/cli.js +8 -0
  347. package/dist/index.d.ts +47 -0
  348. package/dist/index.js +37 -0
  349. package/dist/run-interactive-ink-2CDKFV6C.js +783 -0
  350. package/dist/run-interactive-ink-2JULLCIS.js +461 -0
  351. package/dist/run-interactive-ink-2KIHEGXT.js +451 -0
  352. package/dist/run-interactive-ink-2LX2NZRL.js +737 -0
  353. package/dist/run-interactive-ink-2OH6AV3C.js +756 -0
  354. package/dist/run-interactive-ink-2PLJ5XST.js +423 -0
  355. package/dist/run-interactive-ink-2ZI75VMK.js +462 -0
  356. package/dist/run-interactive-ink-3BHGPZ4B.js +423 -0
  357. package/dist/run-interactive-ink-3IUV3456.js +777 -0
  358. package/dist/run-interactive-ink-3QZK5PWY.js +168 -0
  359. package/dist/run-interactive-ink-3VLL4FNN.js +423 -0
  360. package/dist/run-interactive-ink-47Y2KAFZ.js +668 -0
  361. package/dist/run-interactive-ink-4CBTS636.js +423 -0
  362. package/dist/run-interactive-ink-4CHDJRAK.js +423 -0
  363. package/dist/run-interactive-ink-4E6GM5ST.js +423 -0
  364. package/dist/run-interactive-ink-4EKHIHGU.js +462 -0
  365. package/dist/run-interactive-ink-4NO7O233.js +744 -0
  366. package/dist/run-interactive-ink-55IZU2EZ.js +741 -0
  367. package/dist/run-interactive-ink-5A7BER6J.js +423 -0
  368. package/dist/run-interactive-ink-5NEFKF3R.js +423 -0
  369. package/dist/run-interactive-ink-5TCBH3Z4.js +462 -0
  370. package/dist/run-interactive-ink-5WOLWMGH.js +747 -0
  371. package/dist/run-interactive-ink-66JFIG2P.js +462 -0
  372. package/dist/run-interactive-ink-6R77DKEV.js +744 -0
  373. package/dist/run-interactive-ink-7B6HI7XT.js +679 -0
  374. package/dist/run-interactive-ink-7ICZH4E3.js +423 -0
  375. package/dist/run-interactive-ink-7LWBJYQE.js +423 -0
  376. package/dist/run-interactive-ink-7Y7MVKPA.js +438 -0
  377. package/dist/run-interactive-ink-A264MR35.js +423 -0
  378. package/dist/run-interactive-ink-A3NCKFFM.js +423 -0
  379. package/dist/run-interactive-ink-A4FBMTZ5.js +563 -0
  380. package/dist/run-interactive-ink-A7YPXRXR.js +462 -0
  381. package/dist/run-interactive-ink-AAER2EXR.js +451 -0
  382. package/dist/run-interactive-ink-ADVQJ2GF.js +423 -0
  383. package/dist/run-interactive-ink-ALV34HZF.js +451 -0
  384. package/dist/run-interactive-ink-ARDK3CO6.js +462 -0
  385. package/dist/run-interactive-ink-AVMVDBQK.js +462 -0
  386. package/dist/run-interactive-ink-AWV7ZOTC.js +423 -0
  387. package/dist/run-interactive-ink-AWZLJJLH.js +423 -0
  388. package/dist/run-interactive-ink-B25V52JO.js +462 -0
  389. package/dist/run-interactive-ink-BC6RGDCH.js +451 -0
  390. package/dist/run-interactive-ink-BMWLPUEU.js +451 -0
  391. package/dist/run-interactive-ink-BRT2MMN6.js +423 -0
  392. package/dist/run-interactive-ink-CB42OWV4.js +572 -0
  393. package/dist/run-interactive-ink-COZSBQND.js +777 -0
  394. package/dist/run-interactive-ink-CQFV44HM.js +451 -0
  395. package/dist/run-interactive-ink-CQMG45KQ.js +462 -0
  396. package/dist/run-interactive-ink-CQP3B7JM.js +669 -0
  397. package/dist/run-interactive-ink-CUCLNJCF.js +451 -0
  398. package/dist/run-interactive-ink-DEEZYQK5.js +423 -0
  399. package/dist/run-interactive-ink-DF5P6WZX.js +423 -0
  400. package/dist/run-interactive-ink-DFITKRY4.js +423 -0
  401. package/dist/run-interactive-ink-DG6TTEQQ.js +462 -0
  402. package/dist/run-interactive-ink-DH7ECECB.js +438 -0
  403. package/dist/run-interactive-ink-DMTUJHP6.js +423 -0
  404. package/dist/run-interactive-ink-DNSBSWLT.js +451 -0
  405. package/dist/run-interactive-ink-DV3TZEM3.js +742 -0
  406. package/dist/run-interactive-ink-E4AYCUDK.js +451 -0
  407. package/dist/run-interactive-ink-E4GPBTSL.js +462 -0
  408. package/dist/run-interactive-ink-ECVTPOIE.js +462 -0
  409. package/dist/run-interactive-ink-ELPCCGT3.js +423 -0
  410. package/dist/run-interactive-ink-ELWVRJZS.js +451 -0
  411. package/dist/run-interactive-ink-ENBMPAV7.js +462 -0
  412. package/dist/run-interactive-ink-EOVWUC3C.js +451 -0
  413. package/dist/run-interactive-ink-EVHWEXM4.js +451 -0
  414. package/dist/run-interactive-ink-F7SBCWE3.js +423 -0
  415. package/dist/run-interactive-ink-FCHXZ3JW.js +423 -0
  416. package/dist/run-interactive-ink-G27WWB5V.js +423 -0
  417. package/dist/run-interactive-ink-GDFTNYRC.js +462 -0
  418. package/dist/run-interactive-ink-GHGZAYSM.js +533 -0
  419. package/dist/run-interactive-ink-GK4IVHVT.js +684 -0
  420. package/dist/run-interactive-ink-GNCZNR6W.js +423 -0
  421. package/dist/run-interactive-ink-GQ53M5SW.js +605 -0
  422. package/dist/run-interactive-ink-GT7R7X2P.js +762 -0
  423. package/dist/run-interactive-ink-GWZTEIEZ.js +462 -0
  424. package/dist/run-interactive-ink-HA45VNUD.js +703 -0
  425. package/dist/run-interactive-ink-HB44RGFJ.js +423 -0
  426. package/dist/run-interactive-ink-HCVGKG23.js +462 -0
  427. package/dist/run-interactive-ink-HYKJ4PZ3.js +462 -0
  428. package/dist/run-interactive-ink-IGEBXARA.js +423 -0
  429. package/dist/run-interactive-ink-IGU7UVL5.js +462 -0
  430. package/dist/run-interactive-ink-JNVKOJRV.js +462 -0
  431. package/dist/run-interactive-ink-JYON5JQQ.js +461 -0
  432. package/dist/run-interactive-ink-K47CRELE.js +423 -0
  433. package/dist/run-interactive-ink-KCHMEHVH.js +547 -0
  434. package/dist/run-interactive-ink-KEB6ENSZ.js +423 -0
  435. package/dist/run-interactive-ink-KEWSKPTE.js +451 -0
  436. package/dist/run-interactive-ink-KJUHMADH.js +423 -0
  437. package/dist/run-interactive-ink-KW5NPJ32.js +423 -0
  438. package/dist/run-interactive-ink-L3EDWKF6.js +687 -0
  439. package/dist/run-interactive-ink-L4BCC6WG.js +462 -0
  440. package/dist/run-interactive-ink-LQPEZ6PR.js +520 -0
  441. package/dist/run-interactive-ink-LQXS5GMO.js +253 -0
  442. package/dist/run-interactive-ink-M4SOBC5E.js +817 -0
  443. package/dist/run-interactive-ink-MJGAQA2R.js +423 -0
  444. package/dist/run-interactive-ink-MPJB6PCJ.js +451 -0
  445. package/dist/run-interactive-ink-MXWZBG3F.js +461 -0
  446. package/dist/run-interactive-ink-N4XIVCWV.js +562 -0
  447. package/dist/run-interactive-ink-ND3PWHDU.js +462 -0
  448. package/dist/run-interactive-ink-NJTAWS3L.js +462 -0
  449. package/dist/run-interactive-ink-OBWWSIZ5.js +423 -0
  450. package/dist/run-interactive-ink-OD7YJBYI.js +423 -0
  451. package/dist/run-interactive-ink-OE23JGIN.js +451 -0
  452. package/dist/run-interactive-ink-OJ4EUMR5.js +462 -0
  453. package/dist/run-interactive-ink-OOC74RCY.js +423 -0
  454. package/dist/run-interactive-ink-P2PHTOX6.js +462 -0
  455. package/dist/run-interactive-ink-PE3XWCVU.js +423 -0
  456. package/dist/run-interactive-ink-PJBWWQF3.js +423 -0
  457. package/dist/run-interactive-ink-PLLZW6BV.js +678 -0
  458. package/dist/run-interactive-ink-PTXNQZ57.js +451 -0
  459. package/dist/run-interactive-ink-PWN5Q6T6.js +423 -0
  460. package/dist/run-interactive-ink-PZK4RD77.js +423 -0
  461. package/dist/run-interactive-ink-QBSXVTCG.js +462 -0
  462. package/dist/run-interactive-ink-QHOQB55Q.js +727 -0
  463. package/dist/run-interactive-ink-QIAC6ZMT.js +451 -0
  464. package/dist/run-interactive-ink-QLLGPIUL.js +462 -0
  465. package/dist/run-interactive-ink-R5W3ZEMY.js +818 -0
  466. package/dist/run-interactive-ink-RHDW3EHS.js +462 -0
  467. package/dist/run-interactive-ink-RLRKPNTS.js +668 -0
  468. package/dist/run-interactive-ink-RORQKBWV.js +425 -0
  469. package/dist/run-interactive-ink-RS6OZ66I.js +423 -0
  470. package/dist/run-interactive-ink-RVGRYBNQ.js +684 -0
  471. package/dist/run-interactive-ink-S35BKUZB.js +423 -0
  472. package/dist/run-interactive-ink-SS6RAQDE.js +423 -0
  473. package/dist/run-interactive-ink-SVP37E33.js +451 -0
  474. package/dist/run-interactive-ink-T53KH7FU.js +423 -0
  475. package/dist/run-interactive-ink-TCQUCJVS.js +423 -0
  476. package/dist/run-interactive-ink-TLUBKTTN.js +423 -0
  477. package/dist/run-interactive-ink-U2BAAHUU.js +438 -0
  478. package/dist/run-interactive-ink-U2KXGJ5S.js +451 -0
  479. package/dist/run-interactive-ink-U73PEMAO.js +423 -0
  480. package/dist/run-interactive-ink-UFTOTXIX.js +669 -0
  481. package/dist/run-interactive-ink-UJNQ54ZU.js +451 -0
  482. package/dist/run-interactive-ink-V63D5IV5.js +423 -0
  483. package/dist/run-interactive-ink-VLBITT4H.js +451 -0
  484. package/dist/run-interactive-ink-VSAX3XFR.js +462 -0
  485. package/dist/run-interactive-ink-WBJOY622.js +729 -0
  486. package/dist/run-interactive-ink-WERR64KP.js +451 -0
  487. package/dist/run-interactive-ink-WHTQ5OV6.js +732 -0
  488. package/dist/run-interactive-ink-WJBK4XIO.js +423 -0
  489. package/dist/run-interactive-ink-WQLCJ34D.js +462 -0
  490. package/dist/run-interactive-ink-WRKQJIAG.js +733 -0
  491. package/dist/run-interactive-ink-XG3P25DM.js +423 -0
  492. package/dist/run-interactive-ink-XPVJ22HP.js +462 -0
  493. package/dist/run-interactive-ink-XS5I2CGI.js +423 -0
  494. package/dist/run-interactive-ink-XVK7DXPB.js +785 -0
  495. package/dist/run-interactive-ink-YB3USTSB.js +706 -0
  496. package/dist/run-interactive-ink-YCBRQCG2.js +423 -0
  497. package/dist/run-interactive-ink-YOPSMTYJ.js +423 -0
  498. package/dist/run-interactive-ink-YYPCL65X.js +665 -0
  499. package/dist/run-interactive-ink-YYZT5L4Z.js +462 -0
  500. package/dist/run-interactive-ink-ZBPYRTJK.js +462 -0
  501. package/dist/run-interactive-ink-ZCCKFR2A.js +451 -0
  502. package/dist/run-interactive-ink-ZKYQ4CJW.js +423 -0
  503. package/dist/run-interactive-ink-ZMO2352Q.js +685 -0
  504. package/dist/run-interactive-ink-ZTDQ773P.js +423 -0
  505. package/dist/run-interactive-ink-ZWH74XDY.js +674 -0
  506. package/package.json +50 -0
  507. package/src/cli.ts +4 -0
  508. package/src/index.ts +1800 -0
  509. package/src/init-feature-context.ts +153 -0
  510. package/src/init-onboarding.ts +529 -0
  511. package/src/interactive-ink.tsx +5 -0
  512. package/src/run-interactive-ink.ts +618 -0
  513. package/src/web-ui.ts +1975 -0
  514. package/test/cli.test.ts +587 -0
  515. package/test/init-onboarding.contract.test.ts +48 -0
  516. package/tsconfig.json +9 -0
@@ -0,0 +1,2056 @@
1
+ // src/web-ui.ts
2
+ import { createHash, randomUUID, timingSafeEqual } from "crypto";
3
+ import { mkdir, readFile, writeFile } from "fs/promises";
4
+ import { basename, dirname, resolve } from "path";
5
+ import { homedir } from "os";
6
+ var DEFAULT_OWNER = "local-owner";
7
+ var SessionStore = class {
8
+ sessions = /* @__PURE__ */ new Map();
9
+ ttlMs;
10
+ constructor(ttlMs = 1e3 * 60 * 60 * 8) {
11
+ this.ttlMs = ttlMs;
12
+ }
13
+ create(ownerId = DEFAULT_OWNER) {
14
+ const now = Date.now();
15
+ const session = {
16
+ sessionId: randomUUID(),
17
+ ownerId,
18
+ csrfToken: randomUUID(),
19
+ createdAt: now,
20
+ expiresAt: now + this.ttlMs,
21
+ lastSeenAt: now
22
+ };
23
+ this.sessions.set(session.sessionId, session);
24
+ return session;
25
+ }
26
+ get(sessionId) {
27
+ const session = this.sessions.get(sessionId);
28
+ if (!session) {
29
+ return void 0;
30
+ }
31
+ if (Date.now() > session.expiresAt) {
32
+ this.sessions.delete(sessionId);
33
+ return void 0;
34
+ }
35
+ session.lastSeenAt = Date.now();
36
+ return session;
37
+ }
38
+ delete(sessionId) {
39
+ this.sessions.delete(sessionId);
40
+ }
41
+ };
42
+ var LoginRateLimiter = class {
43
+ constructor(maxAttempts = 5, windowMs = 1e3 * 60 * 5, lockoutMs = 1e3 * 60 * 10) {
44
+ this.maxAttempts = maxAttempts;
45
+ this.windowMs = windowMs;
46
+ this.lockoutMs = lockoutMs;
47
+ }
48
+ attempts = /* @__PURE__ */ new Map();
49
+ canAttempt(key) {
50
+ const current = this.attempts.get(key);
51
+ if (!current) {
52
+ return { allowed: true };
53
+ }
54
+ if (current.lockedUntil && Date.now() < current.lockedUntil) {
55
+ return {
56
+ allowed: false,
57
+ retryAfterSeconds: Math.ceil((current.lockedUntil - Date.now()) / 1e3)
58
+ };
59
+ }
60
+ return { allowed: true };
61
+ }
62
+ registerFailure(key) {
63
+ const now = Date.now();
64
+ const current = this.attempts.get(key);
65
+ if (!current || now - current.firstFailureAt > this.windowMs) {
66
+ this.attempts.set(key, { count: 1, firstFailureAt: now });
67
+ return { locked: false };
68
+ }
69
+ const count = current.count + 1;
70
+ const next = {
71
+ ...current,
72
+ count
73
+ };
74
+ if (count >= this.maxAttempts) {
75
+ next.lockedUntil = now + this.lockoutMs;
76
+ this.attempts.set(key, next);
77
+ return { locked: true, retryAfterSeconds: Math.ceil(this.lockoutMs / 1e3) };
78
+ }
79
+ this.attempts.set(key, next);
80
+ return { locked: false };
81
+ }
82
+ registerSuccess(key) {
83
+ this.attempts.delete(key);
84
+ }
85
+ };
86
+ var parseCookies = (request) => {
87
+ const cookieHeader = request.headers.cookie ?? "";
88
+ const pairs = cookieHeader.split(";").map((part) => part.trim()).filter(Boolean);
89
+ const cookies = {};
90
+ for (const pair of pairs) {
91
+ const index = pair.indexOf("=");
92
+ if (index <= 0) {
93
+ continue;
94
+ }
95
+ const key = pair.slice(0, index);
96
+ const value = pair.slice(index + 1);
97
+ try {
98
+ cookies[key] = decodeURIComponent(value);
99
+ } catch {
100
+ cookies[key] = value;
101
+ }
102
+ }
103
+ return cookies;
104
+ };
105
+ var setCookie = (response, name, value, options) => {
106
+ const segments = [`${name}=${encodeURIComponent(value)}`];
107
+ segments.push(`Path=${options.path ?? "/"}`);
108
+ if (typeof options.maxAge === "number") {
109
+ segments.push(`Max-Age=${Math.max(0, Math.floor(options.maxAge))}`);
110
+ }
111
+ if (options.httpOnly) {
112
+ segments.push("HttpOnly");
113
+ }
114
+ if (options.secure) {
115
+ segments.push("Secure");
116
+ }
117
+ if (options.sameSite) {
118
+ segments.push(`SameSite=${options.sameSite}`);
119
+ }
120
+ const previous = response.getHeader("Set-Cookie");
121
+ const serialized = segments.join("; ");
122
+ if (!previous) {
123
+ response.setHeader("Set-Cookie", serialized);
124
+ return;
125
+ }
126
+ if (Array.isArray(previous)) {
127
+ response.setHeader("Set-Cookie", [...previous, serialized]);
128
+ return;
129
+ }
130
+ response.setHeader("Set-Cookie", [String(previous), serialized]);
131
+ };
132
+ var verifyPassphrase = (provided, expected) => {
133
+ const providedBuffer = Buffer.from(provided);
134
+ const expectedBuffer = Buffer.from(expected);
135
+ if (providedBuffer.length !== expectedBuffer.length) {
136
+ const zero = Buffer.alloc(expectedBuffer.length);
137
+ return timingSafeEqual(expectedBuffer, zero) && false;
138
+ }
139
+ return timingSafeEqual(providedBuffer, expectedBuffer);
140
+ };
141
+ var getRequestIp = (request) => {
142
+ return request.socket.remoteAddress ?? "unknown";
143
+ };
144
+ var inferConversationTitle = (text) => {
145
+ const normalized = text.trim().replace(/\s+/g, " ");
146
+ if (!normalized) {
147
+ return "New conversation";
148
+ }
149
+ return normalized.length <= 48 ? normalized : `${normalized.slice(0, 48)}...`;
150
+ };
151
+ var renderManifest = (options) => {
152
+ const name = options?.agentName ?? "Agent";
153
+ return JSON.stringify({
154
+ name,
155
+ short_name: name,
156
+ description: `${name} \u2014 AI agent powered by AgentL`,
157
+ start_url: "/",
158
+ display: "standalone",
159
+ background_color: "#000000",
160
+ theme_color: "#000000",
161
+ icons: [
162
+ { src: "/icon.svg", sizes: "any", type: "image/svg+xml" },
163
+ { src: "/icon-192.png", sizes: "192x192", type: "image/png" },
164
+ { src: "/icon-512.png", sizes: "512x512", type: "image/png" }
165
+ ]
166
+ });
167
+ };
168
+ var renderIconSvg = (options) => {
169
+ const letter = (options?.agentName ?? "A").charAt(0).toUpperCase();
170
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
171
+ <rect width="512" height="512" rx="96" fill="#000"/>
172
+ <text x="256" y="256" dy=".35em" text-anchor="middle"
173
+ font-family="-apple-system,BlinkMacSystemFont,sans-serif"
174
+ font-size="280" font-weight="700" fill="#fff">${letter}</text>
175
+ </svg>`;
176
+ };
177
+ var renderServiceWorker = () => `
178
+ const CACHE_NAME = "agentl-shell-v1";
179
+ const SHELL_URLS = ["/"];
180
+
181
+ self.addEventListener("install", (event) => {
182
+ event.waitUntil(
183
+ caches.open(CACHE_NAME).then((cache) => cache.addAll(SHELL_URLS))
184
+ );
185
+ self.skipWaiting();
186
+ });
187
+
188
+ self.addEventListener("activate", (event) => {
189
+ event.waitUntil(
190
+ caches.keys().then((keys) =>
191
+ Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)))
192
+ )
193
+ );
194
+ self.clients.claim();
195
+ });
196
+
197
+ self.addEventListener("fetch", (event) => {
198
+ const url = new URL(event.request.url);
199
+ // Only cache GET requests for the app shell; let API calls pass through
200
+ if (event.request.method !== "GET" || url.pathname.startsWith("/api/")) {
201
+ return;
202
+ }
203
+ event.respondWith(
204
+ fetch(event.request)
205
+ .then((response) => {
206
+ const clone = response.clone();
207
+ caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
208
+ return response;
209
+ })
210
+ .catch(() => caches.match(event.request))
211
+ );
212
+ });
213
+ `;
214
+ var renderWebUiHtml = (options) => {
215
+ const agentInitial = (options?.agentName ?? "A").charAt(0).toUpperCase();
216
+ const agentName = options?.agentName ?? "Agent";
217
+ return `<!doctype html>
218
+ <html lang="en">
219
+ <head>
220
+ <meta charset="utf-8">
221
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
222
+ <meta name="theme-color" content="#000000">
223
+ <meta name="apple-mobile-web-app-capable" content="yes">
224
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
225
+ <meta name="apple-mobile-web-app-title" content="${agentName}">
226
+ <link rel="manifest" href="/manifest.json">
227
+ <link rel="icon" href="/icon.svg" type="image/svg+xml">
228
+ <link rel="apple-touch-icon" href="/icon-192.png">
229
+ <title>${agentName}</title>
230
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inconsolata:400,700">
231
+ <style>
232
+ * { box-sizing: border-box; margin: 0; padding: 0; }
233
+ html, body { height: 100%; overflow: hidden; }
234
+ body {
235
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", sans-serif;
236
+ background: #000;
237
+ color: #ededed;
238
+ font-size: 14px;
239
+ line-height: 1.5;
240
+ -webkit-font-smoothing: antialiased;
241
+ -moz-osx-font-smoothing: grayscale;
242
+ }
243
+ button, input, textarea { font: inherit; color: inherit; }
244
+ .hidden { display: none !important; }
245
+ a { color: #ededed; }
246
+
247
+ /* Auth */
248
+ .auth {
249
+ min-height: 100vh;
250
+ display: grid;
251
+ place-items: center;
252
+ padding: 20px;
253
+ background: #000;
254
+ }
255
+ .auth-card {
256
+ width: min(380px, 90vw);
257
+ background: #0a0a0a;
258
+ border: 1px solid rgba(255,255,255,0.08);
259
+ border-radius: 12px;
260
+ padding: 32px;
261
+ display: grid;
262
+ gap: 20px;
263
+ }
264
+ .auth-brand {
265
+ display: flex;
266
+ align-items: center;
267
+ gap: 8px;
268
+ }
269
+ .auth-brand svg { width: 20px; height: 20px; }
270
+ .auth-title {
271
+ font-size: 16px;
272
+ font-weight: 500;
273
+ letter-spacing: -0.01em;
274
+ }
275
+ .auth-text { color: #666; font-size: 13px; line-height: 1.5; }
276
+ .auth-input {
277
+ width: 100%;
278
+ background: #000;
279
+ border: 1px solid rgba(255,255,255,0.12);
280
+ border-radius: 6px;
281
+ color: #ededed;
282
+ padding: 10px 12px;
283
+ font-size: 14px;
284
+ outline: none;
285
+ transition: border-color 0.15s;
286
+ }
287
+ .auth-input:focus { border-color: rgba(255,255,255,0.3); }
288
+ .auth-input::placeholder { color: #555; }
289
+ .auth-submit {
290
+ background: #ededed;
291
+ color: #000;
292
+ border: 0;
293
+ border-radius: 6px;
294
+ padding: 10px 16px;
295
+ font-size: 14px;
296
+ font-weight: 500;
297
+ cursor: pointer;
298
+ transition: background 0.15s;
299
+ }
300
+ .auth-submit:hover { background: #fff; }
301
+ .error { color: #ff4444; font-size: 13px; min-height: 16px; }
302
+ .message-error {
303
+ background: rgba(255,68,68,0.08);
304
+ border: 1px solid rgba(255,68,68,0.25);
305
+ border-radius: 10px;
306
+ color: #ff6b6b;
307
+ padding: 12px 16px;
308
+ font-size: 13px;
309
+ line-height: 1.5;
310
+ max-width: 600px;
311
+ }
312
+ .message-error strong { color: #ff4444; }
313
+
314
+ /* Layout */
315
+ .shell { height: 100vh; height: 100dvh; height: var(--app-height, 100dvh); display: flex; overflow: hidden; }
316
+ .sidebar {
317
+ width: 260px;
318
+ background: #000;
319
+ border-right: 1px solid rgba(255,255,255,0.06);
320
+ display: flex;
321
+ flex-direction: column;
322
+ padding: 12px 8px;
323
+ }
324
+ .new-chat-btn {
325
+ background: transparent;
326
+ border: 0;
327
+ color: #888;
328
+ border-radius: 12px;
329
+ height: 36px;
330
+ padding: 0 10px;
331
+ display: flex;
332
+ align-items: center;
333
+ gap: 8px;
334
+ font-size: 13px;
335
+ cursor: pointer;
336
+ transition: background 0.15s, color 0.15s;
337
+ }
338
+ .new-chat-btn:hover { color: #ededed; }
339
+ .new-chat-btn svg { width: 16px; height: 16px; }
340
+ .conversation-list {
341
+ flex: 1;
342
+ overflow-y: auto;
343
+ margin-top: 12px;
344
+ display: flex;
345
+ flex-direction: column;
346
+ gap: 2px;
347
+ }
348
+ .conversation-item {
349
+ padding: 7px 28px 7px 10px;
350
+ border-radius: 12px;
351
+ cursor: pointer;
352
+ font-size: 13px;
353
+ color: #555;
354
+ white-space: nowrap;
355
+ overflow: hidden;
356
+ text-overflow: ellipsis;
357
+ position: relative;
358
+ transition: color 0.15s;
359
+ }
360
+ .conversation-item:hover { color: #999; }
361
+ .conversation-item.active {
362
+ color: #ededed;
363
+ }
364
+ .conversation-item .delete-btn {
365
+ position: absolute;
366
+ right: 0;
367
+ top: 0;
368
+ bottom: 0;
369
+ opacity: 0;
370
+ background: #000;
371
+ border: 0;
372
+ color: #444;
373
+ padding: 0 8px;
374
+ border-radius: 0 4px 4px 0;
375
+ cursor: pointer;
376
+ font-size: 16px;
377
+ line-height: 1;
378
+ display: grid;
379
+ place-items: center;
380
+ transition: opacity 0.15s, color 0.15s;
381
+ }
382
+ .conversation-item:hover .delete-btn { opacity: 1; }
383
+ .conversation-item.active .delete-btn { background: rgba(0,0,0,1); }
384
+ .conversation-item .delete-btn::before {
385
+ content: "";
386
+ position: absolute;
387
+ right: 100%;
388
+ top: 0;
389
+ bottom: 0;
390
+ width: 24px;
391
+ background: linear-gradient(to right, transparent, #000);
392
+ pointer-events: none;
393
+ }
394
+ .conversation-item.active .delete-btn::before {
395
+ background: linear-gradient(to right, transparent, rgba(0,0,0,1));
396
+ }
397
+ .conversation-item .delete-btn:hover { color: #888; }
398
+ .conversation-item .delete-btn.confirming {
399
+ opacity: 1;
400
+ width: auto;
401
+ padding: 0 8px;
402
+ font-size: 11px;
403
+ color: #ff4444;
404
+ border-radius: 3px;
405
+ }
406
+ .conversation-item .delete-btn.confirming:hover {
407
+ color: #ff6666;
408
+ }
409
+ .sidebar-footer {
410
+ margin-top: auto;
411
+ padding-top: 8px;
412
+ }
413
+ .logout-btn {
414
+ background: transparent;
415
+ border: 0;
416
+ color: #555;
417
+ width: 100%;
418
+ padding: 8px 10px;
419
+ text-align: left;
420
+ border-radius: 6px;
421
+ cursor: pointer;
422
+ font-size: 13px;
423
+ transition: color 0.15s, background 0.15s;
424
+ }
425
+ .logout-btn:hover { color: #888; }
426
+
427
+ /* Main */
428
+ .main { flex: 1; display: flex; flex-direction: column; min-width: 0; background: #000; }
429
+ .topbar {
430
+ height: 52px;
431
+ padding-top: env(safe-area-inset-top, 0px);
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ font-size: 13px;
436
+ font-weight: 500;
437
+ color: #888;
438
+ border-bottom: 1px solid rgba(255,255,255,0.06);
439
+ position: relative;
440
+ flex-shrink: 0;
441
+ }
442
+ .topbar-title {
443
+ max-width: 400px;
444
+ overflow: hidden;
445
+ text-overflow: ellipsis;
446
+ white-space: nowrap;
447
+ letter-spacing: -0.01em;
448
+ }
449
+ .sidebar-toggle {
450
+ display: none;
451
+ position: absolute;
452
+ left: 12px;
453
+ background: transparent;
454
+ border: 0;
455
+ color: #666;
456
+ width: 32px;
457
+ height: 32px;
458
+ border-radius: 6px;
459
+ cursor: pointer;
460
+ transition: color 0.15s, background 0.15s;
461
+ font-size: 18px;
462
+ }
463
+ .sidebar-toggle:hover { color: #ededed; }
464
+
465
+ /* Messages */
466
+ .messages { flex: 1; overflow-y: auto; padding: 24px 24px; }
467
+ .messages-column { max-width: 680px; margin: 0 auto; }
468
+ .message-row { margin-bottom: 24px; display: flex; }
469
+ .message-row.user { justify-content: flex-end; }
470
+ .assistant-wrap { display: flex; gap: 12px; max-width: 100%; }
471
+ .assistant-avatar {
472
+ width: 24px;
473
+ height: 24px;
474
+ background: #ededed;
475
+ color: #000;
476
+ border-radius: 6px;
477
+ display: grid;
478
+ place-items: center;
479
+ font-size: 11px;
480
+ font-weight: 600;
481
+ flex-shrink: 0;
482
+ margin-top: 2px;
483
+ }
484
+ .assistant-content {
485
+ line-height: 1.65;
486
+ color: #ededed;
487
+ font-size: 14px;
488
+ min-width: 0;
489
+ margin-top: 2px;
490
+ }
491
+ .assistant-content p { margin: 0 0 12px; }
492
+ .assistant-content p:last-child { margin-bottom: 0; }
493
+ .assistant-content ul, .assistant-content ol { margin: 8px 0; padding-left: 20px; }
494
+ .assistant-content li { margin: 4px 0; }
495
+ .assistant-content strong { font-weight: 600; color: #fff; }
496
+ .assistant-content h2 {
497
+ font-size: 16px;
498
+ font-weight: 600;
499
+ letter-spacing: -0.02em;
500
+ margin: 20px 0 8px;
501
+ color: #fff;
502
+ }
503
+ .assistant-content h3 {
504
+ font-size: 14px;
505
+ font-weight: 600;
506
+ letter-spacing: -0.01em;
507
+ margin: 16px 0 6px;
508
+ color: #fff;
509
+ }
510
+ .assistant-content code {
511
+ background: rgba(255,255,255,0.06);
512
+ border: 1px solid rgba(255,255,255,0.06);
513
+ padding: 2px 5px;
514
+ border-radius: 4px;
515
+ font-family: ui-monospace, "SF Mono", "Fira Code", monospace;
516
+ font-size: 0.88em;
517
+ }
518
+ .assistant-content pre {
519
+ background: #0a0a0a;
520
+ border: 1px solid rgba(255,255,255,0.06);
521
+ padding: 14px 16px;
522
+ border-radius: 8px;
523
+ overflow-x: auto;
524
+ margin: 14px 0;
525
+ }
526
+ .assistant-content pre code {
527
+ background: none;
528
+ border: 0;
529
+ padding: 0;
530
+ font-size: 13px;
531
+ line-height: 1.5;
532
+ }
533
+ .tool-activity {
534
+ margin-top: 12px;
535
+ border: 1px solid rgba(255,255,255,0.08);
536
+ background: rgba(255,255,255,0.03);
537
+ border-radius: 10px;
538
+ font-size: 12px;
539
+ line-height: 1.45;
540
+ color: #bcbcbc;
541
+ max-width: 300px;
542
+ }
543
+ .tool-activity-disclosure {
544
+ display: block;
545
+ }
546
+ .tool-activity-summary {
547
+ list-style: none;
548
+ display: flex;
549
+ align-items: center;
550
+ gap: 8px;
551
+ cursor: pointer;
552
+ padding: 10px 12px;
553
+ user-select: none;
554
+ }
555
+ .tool-activity-summary::-webkit-details-marker {
556
+ display: none;
557
+ }
558
+ .tool-activity-label {
559
+ font-size: 11px;
560
+ text-transform: uppercase;
561
+ letter-spacing: 0.06em;
562
+ color: #8a8a8a;
563
+ font-weight: 600;
564
+ }
565
+ .tool-activity-caret {
566
+ margin-left: auto;
567
+ color: #8a8a8a;
568
+ display: inline-flex;
569
+ align-items: center;
570
+ justify-content: center;
571
+ transition: transform 120ms ease;
572
+ transform: rotate(0deg);
573
+ }
574
+ .tool-activity-caret svg {
575
+ width: 14px;
576
+ height: 14px;
577
+ display: block;
578
+ }
579
+ .tool-activity-disclosure[open] .tool-activity-caret {
580
+ transform: rotate(90deg);
581
+ }
582
+ .tool-activity-list {
583
+ display: grid;
584
+ gap: 6px;
585
+ padding: 0 12px 10px;
586
+ }
587
+ .tool-activity-item {
588
+ font-family: ui-monospace, "SF Mono", "Fira Code", monospace;
589
+ background: rgba(255,255,255,0.04);
590
+ border-radius: 6px;
591
+ padding: 4px 7px;
592
+ color: #d6d6d6;
593
+ }
594
+ .user-bubble {
595
+ background: #111;
596
+ border: 1px solid rgba(255,255,255,0.08);
597
+ padding: 10px 16px;
598
+ border-radius: 18px;
599
+ max-width: 70%;
600
+ font-size: 14px;
601
+ line-height: 1.5;
602
+ }
603
+ .empty-state {
604
+ display: flex;
605
+ flex-direction: column;
606
+ align-items: center;
607
+ justify-content: center;
608
+ height: 100%;
609
+ gap: 16px;
610
+ color: #555;
611
+ }
612
+ .empty-state .assistant-avatar {
613
+ width: 36px;
614
+ height: 36px;
615
+ font-size: 14px;
616
+ border-radius: 8px;
617
+ }
618
+ .empty-state-text {
619
+ font-size: 14px;
620
+ color: #555;
621
+ }
622
+ .thinking-indicator {
623
+ display: inline-block;
624
+ font-family: Inconsolata, monospace;
625
+ font-size: 20px;
626
+ line-height: 1;
627
+ vertical-align: middle;
628
+ color: #ededed;
629
+ opacity: 0.5;
630
+ }
631
+
632
+ /* Composer */
633
+ .composer {
634
+ padding: 12px 24px calc(24px + env(safe-area-inset-bottom, 0px));
635
+ position: relative;
636
+ }
637
+ .composer::before {
638
+ content: "";
639
+ position: absolute;
640
+ left: 0;
641
+ right: 0;
642
+ bottom: 100%;
643
+ height: 48px;
644
+ background: linear-gradient(to top, #000 0%, transparent 100%);
645
+ pointer-events: none;
646
+ }
647
+ .composer-inner { max-width: 680px; margin: 0 auto; }
648
+ .composer-shell {
649
+ background: #0a0a0a;
650
+ border: 1px solid rgba(255,255,255,0.1);
651
+ border-radius: 9999px;
652
+ display: flex;
653
+ align-items: center;
654
+ padding: 4px 6px 4px 18px;
655
+ transition: border-color 0.15s;
656
+ }
657
+ .composer-shell:focus-within { border-color: rgba(255,255,255,0.2); }
658
+ .composer-input {
659
+ flex: 1;
660
+ background: transparent;
661
+ border: 0;
662
+ outline: none;
663
+ color: #ededed;
664
+ min-height: 40px;
665
+ max-height: 200px;
666
+ resize: none;
667
+ padding: 10px 0 8px;
668
+ font-size: 14px;
669
+ line-height: 1.5;
670
+ }
671
+ .composer-input::placeholder { color: #444; }
672
+ .send-btn {
673
+ width: 32px;
674
+ height: 32px;
675
+ background: #ededed;
676
+ border: 0;
677
+ border-radius: 50%;
678
+ color: #000;
679
+ cursor: pointer;
680
+ display: grid;
681
+ place-items: center;
682
+ flex-shrink: 0;
683
+ margin-bottom: 2px;
684
+ transition: background 0.15s, opacity 0.15s;
685
+ }
686
+ .send-btn:hover { background: #fff; }
687
+ .send-btn:disabled { opacity: 0.2; cursor: default; }
688
+ .send-btn:disabled:hover { background: #ededed; }
689
+ .disclaimer {
690
+ text-align: center;
691
+ color: #333;
692
+ font-size: 12px;
693
+ margin-top: 10px;
694
+ }
695
+
696
+ /* Scrollbar */
697
+ ::-webkit-scrollbar { width: 6px; }
698
+ ::-webkit-scrollbar-track { background: transparent; }
699
+ ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 3px; }
700
+ ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.16); }
701
+
702
+ /* Mobile */
703
+ @media (max-width: 768px) {
704
+ .sidebar {
705
+ position: fixed;
706
+ inset: 0 auto 0 0;
707
+ z-index: 100;
708
+ transform: translateX(-100%);
709
+ transition: transform 0.2s ease;
710
+ }
711
+ .shell.sidebar-open .sidebar { transform: translateX(0); }
712
+ .sidebar-toggle { display: grid; place-items: center; }
713
+ .sidebar-backdrop {
714
+ position: fixed;
715
+ inset: 0;
716
+ background: rgba(0,0,0,0.6);
717
+ z-index: 50;
718
+ backdrop-filter: blur(2px);
719
+ -webkit-backdrop-filter: blur(2px);
720
+ }
721
+ .shell:not(.sidebar-open) .sidebar-backdrop { display: none; }
722
+ .messages { padding: 16px; }
723
+ .composer { padding: 8px 16px 16px; }
724
+ }
725
+
726
+ /* Reduced motion */
727
+ @media (prefers-reduced-motion: reduce) {
728
+ *, *::before, *::after {
729
+ animation-duration: 0.01ms !important;
730
+ transition-duration: 0.01ms !important;
731
+ }
732
+ }
733
+ </style>
734
+ </head>
735
+ <body data-agent-initial="${agentInitial}" data-agent-name="${agentName}">
736
+ <div id="auth" class="auth hidden">
737
+ <form id="login-form" class="auth-card">
738
+ <div class="auth-brand">
739
+ <svg viewBox="0 0 24 24" fill="none"><path d="M12 2L2 19.5h20L12 2z" fill="currentColor"/></svg>
740
+ <h2 class="auth-title">AgentL</h2>
741
+ </div>
742
+ <p class="auth-text">Enter the passphrase to continue.</p>
743
+ <input id="passphrase" class="auth-input" type="password" placeholder="Passphrase" required>
744
+ <button class="auth-submit" type="submit">Continue</button>
745
+ <div id="login-error" class="error"></div>
746
+ </form>
747
+ </div>
748
+
749
+ <div id="app" class="shell hidden">
750
+ <aside class="sidebar">
751
+ <button id="new-chat" class="new-chat-btn">
752
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
753
+ </button>
754
+ <div id="conversation-list" class="conversation-list"></div>
755
+ <div class="sidebar-footer">
756
+ <button id="logout" class="logout-btn">Log out</button>
757
+ </div>
758
+ </aside>
759
+ <div id="sidebar-backdrop" class="sidebar-backdrop"></div>
760
+ <main class="main">
761
+ <div class="topbar">
762
+ <button id="sidebar-toggle" class="sidebar-toggle">&#9776;</button>
763
+ <div id="chat-title" class="topbar-title"></div>
764
+ </div>
765
+ <div id="messages" class="messages">
766
+ <div class="empty-state">
767
+ <div class="assistant-avatar">${agentInitial}</div>
768
+ <div class="empty-state-text">How can I help you today?</div>
769
+ </div>
770
+ </div>
771
+ <form id="composer" class="composer">
772
+ <div class="composer-inner">
773
+ <div class="composer-shell">
774
+ <textarea id="prompt" class="composer-input" placeholder="Send a message..." rows="1"></textarea>
775
+ <button id="send" class="send-btn" type="submit">
776
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 12V4M4 7l4-4 4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
777
+ </button>
778
+ </div>
779
+ </div>
780
+ </form>
781
+ </main>
782
+ </div>
783
+
784
+ <script>
785
+ const state = {
786
+ csrfToken: "",
787
+ conversations: [],
788
+ activeConversationId: null,
789
+ isStreaming: false,
790
+ confirmDeleteId: null
791
+ };
792
+
793
+ const agentInitial = document.body.dataset.agentInitial || "A";
794
+ const $ = (id) => document.getElementById(id);
795
+ const elements = {
796
+ auth: $("auth"),
797
+ app: $("app"),
798
+ loginForm: $("login-form"),
799
+ passphrase: $("passphrase"),
800
+ loginError: $("login-error"),
801
+ list: $("conversation-list"),
802
+ newChat: $("new-chat"),
803
+ messages: $("messages"),
804
+ chatTitle: $("chat-title"),
805
+ logout: $("logout"),
806
+ composer: $("composer"),
807
+ prompt: $("prompt"),
808
+ send: $("send"),
809
+ shell: $("app"),
810
+ sidebarToggle: $("sidebar-toggle"),
811
+ sidebarBackdrop: $("sidebar-backdrop")
812
+ };
813
+
814
+ const pushConversationUrl = (conversationId) => {
815
+ const target = conversationId ? "/c/" + encodeURIComponent(conversationId) : "/";
816
+ if (window.location.pathname !== target) {
817
+ history.pushState({ conversationId: conversationId || null }, "", target);
818
+ }
819
+ };
820
+
821
+ const replaceConversationUrl = (conversationId) => {
822
+ const target = conversationId ? "/c/" + encodeURIComponent(conversationId) : "/";
823
+ if (window.location.pathname !== target) {
824
+ history.replaceState({ conversationId: conversationId || null }, "", target);
825
+ }
826
+ };
827
+
828
+ const getConversationIdFromUrl = () => {
829
+ const match = window.location.pathname.match(/^\\/c\\/([^\\/]+)/);
830
+ return match ? decodeURIComponent(match[1]) : null;
831
+ };
832
+
833
+ const mutatingMethods = new Set(["POST", "PATCH", "PUT", "DELETE"]);
834
+
835
+ const api = async (path, options = {}) => {
836
+ const method = (options.method || "GET").toUpperCase();
837
+ const headers = { ...(options.headers || {}) };
838
+ if (mutatingMethods.has(method) && state.csrfToken) {
839
+ headers["x-csrf-token"] = state.csrfToken;
840
+ }
841
+ if (options.body && !headers["Content-Type"]) {
842
+ headers["Content-Type"] = "application/json";
843
+ }
844
+ const response = await fetch(path, { credentials: "include", ...options, method, headers });
845
+ if (!response.ok) {
846
+ let payload = {};
847
+ try { payload = await response.json(); } catch {}
848
+ const error = new Error(payload.message || ("Request failed: " + response.status));
849
+ error.status = response.status;
850
+ error.payload = payload;
851
+ throw error;
852
+ }
853
+ const contentType = response.headers.get("content-type") || "";
854
+ if (contentType.includes("application/json")) {
855
+ return await response.json();
856
+ }
857
+ return await response.text();
858
+ };
859
+
860
+ const escapeHtml = (value) =>
861
+ String(value || "")
862
+ .replace(/&/g, "&amp;")
863
+ .replace(/</g, "&lt;")
864
+ .replace(/>/g, "&gt;")
865
+ .replace(/"/g, "&quot;")
866
+ .replace(/'/g, "&#39;");
867
+
868
+ const renderInlineMarkdown = (value) => {
869
+ let html = escapeHtml(value);
870
+ html = html.replace(/\\*\\*([^*]+)\\*\\*/g, "<strong>$1</strong>");
871
+ html = html.replace(/\\x60([^\\x60]+)\\x60/g, "<code>$1</code>");
872
+ return html;
873
+ };
874
+
875
+ const renderMarkdownBlock = (value) => {
876
+ const lines = String(value || "").split("\\n");
877
+ let html = "";
878
+ let inList = false;
879
+
880
+ for (const rawLine of lines) {
881
+ const line = rawLine.trimEnd();
882
+ const trimmed = line.trim();
883
+ const headingMatch = trimmed.match(/^(#{1,3})\\s+(.+)$/);
884
+
885
+ if (headingMatch) {
886
+ if (inList) {
887
+ html += "</ul>";
888
+ inList = false;
889
+ }
890
+ const level = Math.min(3, headingMatch[1].length);
891
+ const tag = level === 1 ? "h2" : level === 2 ? "h3" : "p";
892
+ html += "<" + tag + ">" + renderInlineMarkdown(headingMatch[2]) + "</" + tag + ">";
893
+ continue;
894
+ }
895
+
896
+ if (/^\\s*-\\s+/.test(line)) {
897
+ if (!inList) {
898
+ html += "<ul>";
899
+ inList = true;
900
+ }
901
+ html += "<li>" + renderInlineMarkdown(line.replace(/^\\s*-\\s+/, "")) + "</li>";
902
+ continue;
903
+ }
904
+ if (inList) {
905
+ html += "</ul>";
906
+ inList = false;
907
+ }
908
+ if (trimmed.length === 0) {
909
+ continue;
910
+ }
911
+ html += "<p>" + renderInlineMarkdown(line) + "</p>";
912
+ }
913
+
914
+ if (inList) {
915
+ html += "</ul>";
916
+ }
917
+ return html;
918
+ };
919
+
920
+ const renderAssistantMarkdown = (value) => {
921
+ const source = String(value || "");
922
+ const fenceRegex = /\\x60\\x60\\x60([\\s\\S]*?)\\x60\\x60\\x60/g;
923
+ let html = "";
924
+ let lastIndex = 0;
925
+ let match;
926
+
927
+ while ((match = fenceRegex.exec(source))) {
928
+ const before = source.slice(lastIndex, match.index);
929
+ html += renderMarkdownBlock(before);
930
+ const codeText = String(match[1] || "").replace(/^\\n+|\\n+$/g, "");
931
+ html += "<pre><code>" + escapeHtml(codeText) + "</code></pre>";
932
+ lastIndex = match.index + match[0].length;
933
+ }
934
+
935
+ html += renderMarkdownBlock(source.slice(lastIndex));
936
+ return html || "<p></p>";
937
+ };
938
+
939
+ const extractToolActivity = (value) => {
940
+ const source = String(value || "");
941
+ let markerIndex = source.lastIndexOf("\\n### Tool activity\\n");
942
+ if (markerIndex < 0 && source.startsWith("### Tool activity\\n")) {
943
+ markerIndex = 0;
944
+ }
945
+ if (markerIndex < 0) {
946
+ return { content: source, activities: [] };
947
+ }
948
+ const content = markerIndex === 0 ? "" : source.slice(0, markerIndex).trimEnd();
949
+ const rawSection = markerIndex === 0 ? source : source.slice(markerIndex + 1);
950
+ const afterHeading = rawSection.replace(/^### Tool activity\\s*\\n?/, "");
951
+ const activities = afterHeading
952
+ .split("\\n")
953
+ .map((line) => line.trim())
954
+ .filter((line) => line.startsWith("- "))
955
+ .map((line) => line.slice(2).trim())
956
+ .filter(Boolean);
957
+ return { content, activities };
958
+ };
959
+
960
+ const renderToolActivity = (items) => {
961
+ if (!items || !items.length) {
962
+ return "";
963
+ }
964
+ const chips = items
965
+ .map((item) => '<div class="tool-activity-item">' + escapeHtml(item) + "</div>")
966
+ .join("");
967
+ return (
968
+ '<div class="tool-activity">' +
969
+ '<details class="tool-activity-disclosure">' +
970
+ '<summary class="tool-activity-summary">' +
971
+ '<span class="tool-activity-label">Tool activity</span>' +
972
+ '<span class="tool-activity-caret" aria-hidden="true"><svg viewBox="0 0 12 12" fill="none"><path d="M4.5 2.75L8 6L4.5 9.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg></span>' +
973
+ "</summary>" +
974
+ '<div class="tool-activity-list">' +
975
+ chips +
976
+ "</div>" +
977
+ "</details>" +
978
+ "</div>"
979
+ );
980
+ };
981
+
982
+ const formatDate = (epoch) => {
983
+ try {
984
+ const date = new Date(epoch);
985
+ const now = new Date();
986
+ const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
987
+ const startOfDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
988
+ const dayDiff = Math.floor((startOfToday - startOfDate) / 86400000);
989
+ if (dayDiff === 0) {
990
+ return "Today";
991
+ }
992
+ if (dayDiff === 1) {
993
+ return "Yesterday";
994
+ }
995
+ if (dayDiff < 7 && dayDiff > 1) {
996
+ return date.toLocaleDateString(undefined, { weekday: "short" });
997
+ }
998
+ return date.toLocaleDateString(undefined, { month: "short", day: "numeric" });
999
+ } catch {
1000
+ return "";
1001
+ }
1002
+ };
1003
+
1004
+ const isMobile = () => window.matchMedia("(max-width: 900px)").matches;
1005
+
1006
+ const setSidebarOpen = (open) => {
1007
+ if (!isMobile()) {
1008
+ elements.shell.classList.remove("sidebar-open");
1009
+ return;
1010
+ }
1011
+ elements.shell.classList.toggle("sidebar-open", open);
1012
+ };
1013
+
1014
+ const renderConversationList = () => {
1015
+ elements.list.innerHTML = "";
1016
+ for (const c of state.conversations) {
1017
+ const item = document.createElement("div");
1018
+ item.className = "conversation-item" + (c.conversationId === state.activeConversationId ? " active" : "");
1019
+ item.textContent = c.title;
1020
+
1021
+ const isConfirming = state.confirmDeleteId === c.conversationId;
1022
+ const deleteBtn = document.createElement("button");
1023
+ deleteBtn.className = "delete-btn" + (isConfirming ? " confirming" : "");
1024
+ deleteBtn.textContent = isConfirming ? "sure?" : "\\u00d7";
1025
+ deleteBtn.onclick = async (e) => {
1026
+ e.stopPropagation();
1027
+ if (!isConfirming) {
1028
+ state.confirmDeleteId = c.conversationId;
1029
+ renderConversationList();
1030
+ return;
1031
+ }
1032
+ await api("/api/conversations/" + c.conversationId, { method: "DELETE" });
1033
+ if (state.activeConversationId === c.conversationId) {
1034
+ state.activeConversationId = null;
1035
+ pushConversationUrl(null);
1036
+ elements.chatTitle.textContent = "";
1037
+ renderMessages([]);
1038
+ }
1039
+ state.confirmDeleteId = null;
1040
+ await loadConversations();
1041
+ };
1042
+ item.appendChild(deleteBtn);
1043
+
1044
+ item.onclick = async () => {
1045
+ if (state.confirmDeleteId) {
1046
+ state.confirmDeleteId = null;
1047
+ renderConversationList();
1048
+ return;
1049
+ }
1050
+ state.activeConversationId = c.conversationId;
1051
+ pushConversationUrl(c.conversationId);
1052
+ renderConversationList();
1053
+ await loadConversation(c.conversationId);
1054
+ if (isMobile()) setSidebarOpen(false);
1055
+ };
1056
+
1057
+ elements.list.appendChild(item);
1058
+ }
1059
+ };
1060
+
1061
+ const renderMessages = (messages, isStreaming = false) => {
1062
+ elements.messages.innerHTML = "";
1063
+ if (!messages || !messages.length) {
1064
+ elements.messages.innerHTML = '<div class="empty-state"><div class="assistant-avatar">' + agentInitial + '</div><div>How can I help you today?</div></div>';
1065
+ return;
1066
+ }
1067
+ const col = document.createElement("div");
1068
+ col.className = "messages-column";
1069
+ messages.forEach((m, i) => {
1070
+ const row = document.createElement("div");
1071
+ row.className = "message-row " + m.role;
1072
+ if (m.role === "assistant") {
1073
+ const wrap = document.createElement("div");
1074
+ wrap.className = "assistant-wrap";
1075
+ wrap.innerHTML = '<div class="assistant-avatar">' + agentInitial + '</div>';
1076
+ const content = document.createElement("div");
1077
+ content.className = "assistant-content";
1078
+ const text = String(m.content || "");
1079
+ const parsed = extractToolActivity(text);
1080
+ const metadataToolActivity =
1081
+ m.metadata && Array.isArray(m.metadata.toolActivity)
1082
+ ? m.metadata.toolActivity
1083
+ : [];
1084
+ const toolActivity =
1085
+ Array.isArray(m._toolActivity) && m._toolActivity.length > 0
1086
+ ? m._toolActivity
1087
+ : metadataToolActivity.length > 0
1088
+ ? metadataToolActivity
1089
+ : parsed.activities;
1090
+ if (m._error) {
1091
+ const errorEl = document.createElement("div");
1092
+ errorEl.className = "message-error";
1093
+ errorEl.innerHTML = "<strong>Error</strong><br>" + escapeHtml(m._error);
1094
+ content.appendChild(errorEl);
1095
+ } else if (isStreaming && i === messages.length - 1 && !parsed.content) {
1096
+ const spinner = document.createElement("span");
1097
+ spinner.className = "thinking-indicator";
1098
+ const starFrames = ["\u2736","\u2738","\u2739","\u273A","\u2739","\u2737"];
1099
+ let frame = 0;
1100
+ spinner.textContent = starFrames[0];
1101
+ spinner._interval = setInterval(() => { frame = (frame + 1) % starFrames.length; spinner.textContent = starFrames[frame]; }, 70);
1102
+ content.appendChild(spinner);
1103
+ } else {
1104
+ content.innerHTML = renderAssistantMarkdown(parsed.content);
1105
+ }
1106
+ if (toolActivity.length > 0) {
1107
+ content.insertAdjacentHTML("beforeend", renderToolActivity(toolActivity));
1108
+ }
1109
+ wrap.appendChild(content);
1110
+ row.appendChild(wrap);
1111
+ } else {
1112
+ row.innerHTML = '<div class="user-bubble">' + escapeHtml(m.content) + '</div>';
1113
+ }
1114
+ col.appendChild(row);
1115
+ });
1116
+ elements.messages.appendChild(col);
1117
+ elements.messages.scrollTop = elements.messages.scrollHeight;
1118
+ };
1119
+
1120
+ const loadConversations = async () => {
1121
+ const payload = await api("/api/conversations");
1122
+ state.conversations = payload.conversations || [];
1123
+ renderConversationList();
1124
+ };
1125
+
1126
+ const loadConversation = async (conversationId) => {
1127
+ const payload = await api("/api/conversations/" + encodeURIComponent(conversationId));
1128
+ elements.chatTitle.textContent = payload.conversation.title;
1129
+ renderMessages(payload.conversation.messages);
1130
+ elements.prompt.focus();
1131
+ };
1132
+
1133
+ const createConversation = async (title) => {
1134
+ const payload = await api("/api/conversations", {
1135
+ method: "POST",
1136
+ body: JSON.stringify(title ? { title } : {})
1137
+ });
1138
+ state.activeConversationId = payload.conversation.conversationId;
1139
+ state.confirmDeleteId = null;
1140
+ pushConversationUrl(state.activeConversationId);
1141
+ await loadConversations();
1142
+ await loadConversation(state.activeConversationId);
1143
+ return state.activeConversationId;
1144
+ };
1145
+
1146
+ const parseSseChunk = (buffer, onEvent) => {
1147
+ let rest = buffer;
1148
+ while (true) {
1149
+ const index = rest.indexOf("\\n\\n");
1150
+ if (index < 0) {
1151
+ return rest;
1152
+ }
1153
+ const raw = rest.slice(0, index);
1154
+ rest = rest.slice(index + 2);
1155
+ const lines = raw.split("\\n");
1156
+ let eventName = "message";
1157
+ let data = "";
1158
+ for (const line of lines) {
1159
+ if (line.startsWith("event:")) {
1160
+ eventName = line.slice(6).trim();
1161
+ } else if (line.startsWith("data:")) {
1162
+ data += line.slice(5).trim();
1163
+ }
1164
+ }
1165
+ if (data) {
1166
+ try {
1167
+ onEvent(eventName, JSON.parse(data));
1168
+ } catch {}
1169
+ }
1170
+ }
1171
+ };
1172
+
1173
+ const setStreaming = (value) => {
1174
+ state.isStreaming = value;
1175
+ elements.send.disabled = value;
1176
+ };
1177
+
1178
+ const pushToolActivity = (assistantMessage, line) => {
1179
+ if (!line) {
1180
+ return;
1181
+ }
1182
+ if (
1183
+ !assistantMessage.metadata ||
1184
+ !Array.isArray(assistantMessage.metadata.toolActivity)
1185
+ ) {
1186
+ assistantMessage.metadata = {
1187
+ ...(assistantMessage.metadata || {}),
1188
+ toolActivity: [],
1189
+ };
1190
+ }
1191
+ assistantMessage.metadata.toolActivity.push(line);
1192
+ };
1193
+
1194
+ const autoResizePrompt = () => {
1195
+ const el = elements.prompt;
1196
+ el.style.height = "auto";
1197
+ const scrollHeight = el.scrollHeight;
1198
+ const nextHeight = Math.min(scrollHeight, 200);
1199
+ el.style.height = nextHeight + "px";
1200
+ el.style.overflowY = scrollHeight > 200 ? "auto" : "hidden";
1201
+ };
1202
+
1203
+ const sendMessage = async (text) => {
1204
+ const messageText = (text || "").trim();
1205
+ if (!messageText || state.isStreaming) {
1206
+ return;
1207
+ }
1208
+ let conversationId = state.activeConversationId;
1209
+ if (!conversationId) {
1210
+ conversationId = await createConversation(messageText);
1211
+ }
1212
+ const existingPayload = await api("/api/conversations/" + encodeURIComponent(conversationId));
1213
+ const localMessages = [...(existingPayload.conversation.messages || []), { role: "user", content: messageText }];
1214
+ let assistantMessage = { role: "assistant", content: "", metadata: { toolActivity: [] } };
1215
+ localMessages.push(assistantMessage);
1216
+ renderMessages(localMessages, true);
1217
+ setStreaming(true);
1218
+ try {
1219
+ const response = await fetch("/api/conversations/" + encodeURIComponent(conversationId) + "/messages", {
1220
+ method: "POST",
1221
+ credentials: "include",
1222
+ headers: { "Content-Type": "application/json", "x-csrf-token": state.csrfToken },
1223
+ body: JSON.stringify({ message: messageText })
1224
+ });
1225
+ if (!response.ok || !response.body) {
1226
+ throw new Error("Failed to stream response");
1227
+ }
1228
+ const reader = response.body.getReader();
1229
+ const decoder = new TextDecoder();
1230
+ let buffer = "";
1231
+ while (true) {
1232
+ const { value, done } = await reader.read();
1233
+ if (done) {
1234
+ break;
1235
+ }
1236
+ buffer += decoder.decode(value, { stream: true });
1237
+ buffer = parseSseChunk(buffer, (eventName, payload) => {
1238
+ if (eventName === "model:chunk") {
1239
+ assistantMessage.content += String(payload.content || "");
1240
+ renderMessages(localMessages, true);
1241
+ }
1242
+ if (eventName === "tool:started") {
1243
+ pushToolActivity(assistantMessage, "start " + (payload.tool || "tool"));
1244
+ renderMessages(localMessages, true);
1245
+ }
1246
+ if (eventName === "tool:completed") {
1247
+ const duration = typeof payload.duration === "number" ? payload.duration : null;
1248
+ pushToolActivity(
1249
+ assistantMessage,
1250
+ "done " +
1251
+ (payload.tool || "tool") +
1252
+ (duration !== null ? " (" + duration + "ms)" : ""),
1253
+ );
1254
+ renderMessages(localMessages, true);
1255
+ }
1256
+ if (eventName === "tool:error") {
1257
+ pushToolActivity(
1258
+ assistantMessage,
1259
+ "error " + (payload.tool || "tool") + ": " + (payload.error || "unknown error"),
1260
+ );
1261
+ renderMessages(localMessages, true);
1262
+ }
1263
+ if (eventName === "tool:approval:required") {
1264
+ pushToolActivity(assistantMessage, "approval required for " + (payload.tool || "tool"));
1265
+ renderMessages(localMessages, true);
1266
+ }
1267
+ if (eventName === "tool:approval:granted") {
1268
+ pushToolActivity(assistantMessage, "approval granted");
1269
+ renderMessages(localMessages, true);
1270
+ }
1271
+ if (eventName === "tool:approval:denied") {
1272
+ pushToolActivity(assistantMessage, "approval denied");
1273
+ renderMessages(localMessages, true);
1274
+ }
1275
+ if (eventName === "run:completed" && (!assistantMessage.content || assistantMessage.content.length === 0)) {
1276
+ assistantMessage.content = String(payload.result?.response || "");
1277
+ renderMessages(localMessages, false);
1278
+ }
1279
+ if (eventName === "run:error") {
1280
+ const errMsg = payload.error?.message || "Something went wrong";
1281
+ assistantMessage.content = "";
1282
+ assistantMessage._error = errMsg;
1283
+ renderMessages(localMessages, false);
1284
+ }
1285
+ });
1286
+ }
1287
+ await loadConversations();
1288
+ await loadConversation(conversationId);
1289
+ } finally {
1290
+ setStreaming(false);
1291
+ elements.prompt.focus();
1292
+ }
1293
+ };
1294
+
1295
+ const requireAuth = async () => {
1296
+ try {
1297
+ const session = await api("/api/auth/session");
1298
+ if (!session.authenticated) {
1299
+ elements.auth.classList.remove("hidden");
1300
+ elements.app.classList.add("hidden");
1301
+ return false;
1302
+ }
1303
+ state.csrfToken = session.csrfToken || "";
1304
+ elements.auth.classList.add("hidden");
1305
+ elements.app.classList.remove("hidden");
1306
+ return true;
1307
+ } catch {
1308
+ elements.auth.classList.remove("hidden");
1309
+ elements.app.classList.add("hidden");
1310
+ return false;
1311
+ }
1312
+ };
1313
+
1314
+ elements.loginForm.addEventListener("submit", async (event) => {
1315
+ event.preventDefault();
1316
+ elements.loginError.textContent = "";
1317
+ try {
1318
+ const result = await api("/api/auth/login", {
1319
+ method: "POST",
1320
+ body: JSON.stringify({ passphrase: elements.passphrase.value || "" })
1321
+ });
1322
+ state.csrfToken = result.csrfToken || "";
1323
+ elements.passphrase.value = "";
1324
+ elements.auth.classList.add("hidden");
1325
+ elements.app.classList.remove("hidden");
1326
+ await loadConversations();
1327
+ const urlConversationId = getConversationIdFromUrl();
1328
+ if (urlConversationId) {
1329
+ state.activeConversationId = urlConversationId;
1330
+ renderConversationList();
1331
+ try {
1332
+ await loadConversation(urlConversationId);
1333
+ } catch {
1334
+ state.activeConversationId = null;
1335
+ replaceConversationUrl(null);
1336
+ renderMessages([]);
1337
+ renderConversationList();
1338
+ }
1339
+ }
1340
+ } catch (error) {
1341
+ elements.loginError.textContent = error.message || "Login failed";
1342
+ }
1343
+ });
1344
+
1345
+ elements.newChat.addEventListener("click", () => {
1346
+ state.activeConversationId = null;
1347
+ state.confirmDeleteId = null;
1348
+ pushConversationUrl(null);
1349
+ elements.chatTitle.textContent = "";
1350
+ renderMessages([]);
1351
+ renderConversationList();
1352
+ elements.prompt.focus();
1353
+ if (isMobile()) {
1354
+ setSidebarOpen(false);
1355
+ }
1356
+ });
1357
+
1358
+ elements.prompt.addEventListener("input", () => {
1359
+ autoResizePrompt();
1360
+ });
1361
+
1362
+ elements.prompt.addEventListener("keydown", (event) => {
1363
+ if (event.key === "Enter" && !event.shiftKey) {
1364
+ event.preventDefault();
1365
+ elements.composer.requestSubmit();
1366
+ }
1367
+ });
1368
+
1369
+ elements.sidebarToggle.addEventListener("click", () => {
1370
+ if (isMobile()) setSidebarOpen(!elements.shell.classList.contains("sidebar-open"));
1371
+ });
1372
+
1373
+ elements.sidebarBackdrop.addEventListener("click", () => setSidebarOpen(false));
1374
+
1375
+ elements.logout.addEventListener("click", async () => {
1376
+ await api("/api/auth/logout", { method: "POST" });
1377
+ state.activeConversationId = null;
1378
+ state.confirmDeleteId = null;
1379
+ state.conversations = [];
1380
+ state.csrfToken = "";
1381
+ await requireAuth();
1382
+ });
1383
+
1384
+ elements.composer.addEventListener("submit", async (event) => {
1385
+ event.preventDefault();
1386
+ const value = elements.prompt.value;
1387
+ elements.prompt.value = "";
1388
+ autoResizePrompt();
1389
+ await sendMessage(value);
1390
+ });
1391
+
1392
+ document.addEventListener("click", (event) => {
1393
+ if (!(event.target instanceof Node)) {
1394
+ return;
1395
+ }
1396
+ if (!event.target.closest(".conversation-item") && state.confirmDeleteId) {
1397
+ state.confirmDeleteId = null;
1398
+ renderConversationList();
1399
+ }
1400
+ });
1401
+
1402
+ window.addEventListener("resize", () => {
1403
+ setSidebarOpen(false);
1404
+ });
1405
+
1406
+ const navigateToConversation = async (conversationId) => {
1407
+ if (conversationId) {
1408
+ state.activeConversationId = conversationId;
1409
+ renderConversationList();
1410
+ try {
1411
+ await loadConversation(conversationId);
1412
+ } catch {
1413
+ // Conversation not found \u2013 fall back to empty state
1414
+ state.activeConversationId = null;
1415
+ replaceConversationUrl(null);
1416
+ elements.chatTitle.textContent = "";
1417
+ renderMessages([]);
1418
+ renderConversationList();
1419
+ }
1420
+ } else {
1421
+ state.activeConversationId = null;
1422
+ elements.chatTitle.textContent = "";
1423
+ renderMessages([]);
1424
+ renderConversationList();
1425
+ }
1426
+ };
1427
+
1428
+ window.addEventListener("popstate", async () => {
1429
+ if (state.isStreaming) return;
1430
+ const conversationId = getConversationIdFromUrl();
1431
+ await navigateToConversation(conversationId);
1432
+ });
1433
+
1434
+ (async () => {
1435
+ const authenticated = await requireAuth();
1436
+ if (!authenticated) {
1437
+ return;
1438
+ }
1439
+ await loadConversations();
1440
+ const urlConversationId = getConversationIdFromUrl();
1441
+ if (urlConversationId) {
1442
+ state.activeConversationId = urlConversationId;
1443
+ replaceConversationUrl(urlConversationId);
1444
+ renderConversationList();
1445
+ try {
1446
+ await loadConversation(urlConversationId);
1447
+ } catch {
1448
+ // URL pointed to a conversation that no longer exists
1449
+ state.activeConversationId = null;
1450
+ replaceConversationUrl(null);
1451
+ elements.chatTitle.textContent = "";
1452
+ renderMessages([]);
1453
+ renderConversationList();
1454
+ }
1455
+ }
1456
+ autoResizePrompt();
1457
+ elements.prompt.focus();
1458
+ })();
1459
+
1460
+ if ("serviceWorker" in navigator) {
1461
+ navigator.serviceWorker.register("/sw.js").catch(() => {});
1462
+ }
1463
+
1464
+ // iOS keyboard: use visualViewport to set the real visible height
1465
+ // and prevent the page from scrolling behind the keyboard.
1466
+ (function() {
1467
+ const setHeight = () => {
1468
+ const h = window.visualViewport ? window.visualViewport.height : window.innerHeight;
1469
+ document.documentElement.style.setProperty("--app-height", h + "px");
1470
+ };
1471
+ if (window.visualViewport) {
1472
+ window.visualViewport.addEventListener("resize", setHeight);
1473
+ }
1474
+ window.addEventListener("resize", setHeight);
1475
+ setHeight();
1476
+
1477
+ // Prevent iOS from scrolling the page when the keyboard opens.
1478
+ // Keep scroll pinned to 0 whenever an input is focused.
1479
+ var inputFocused = false;
1480
+ var pinScroll = function() { if (inputFocused && window.scrollY !== 0) window.scrollTo(0, 0); };
1481
+ document.addEventListener("focusin", function(e) {
1482
+ if (e.target && (e.target.tagName === "TEXTAREA" || e.target.tagName === "INPUT")) {
1483
+ inputFocused = true;
1484
+ }
1485
+ });
1486
+ document.addEventListener("focusout", function() {
1487
+ inputFocused = false;
1488
+ window.scrollTo(0, 0);
1489
+ });
1490
+ if (window.visualViewport) {
1491
+ window.visualViewport.addEventListener("scroll", pinScroll);
1492
+ window.visualViewport.addEventListener("resize", pinScroll);
1493
+ }
1494
+ document.addEventListener("scroll", pinScroll);
1495
+ })();
1496
+
1497
+ </script>
1498
+ </body>
1499
+ </html>`;
1500
+ };
1501
+
1502
+ // src/init-onboarding.ts
1503
+ import { createInterface } from "readline/promises";
1504
+ import { clearLine, cursorTo, emitKeypressEvents, moveCursor } from "readline";
1505
+ import { stdin, stdout } from "process";
1506
+ import {
1507
+ fieldsForScope
1508
+ } from "@agentl/sdk";
1509
+ var SELECTED_MARKER = "->";
1510
+ var BORDER = "------------------------------------------------------------";
1511
+ var shouldAskField = (field, answers) => {
1512
+ if (!field.dependsOn) {
1513
+ return true;
1514
+ }
1515
+ const value = answers[field.dependsOn.fieldId];
1516
+ if (typeof field.dependsOn.equals !== "undefined") {
1517
+ return value === field.dependsOn.equals;
1518
+ }
1519
+ if (field.dependsOn.oneOf) {
1520
+ return field.dependsOn.oneOf.includes(value);
1521
+ }
1522
+ return true;
1523
+ };
1524
+ var parsePromptValue = (field, answer) => {
1525
+ if (field.kind === "boolean") {
1526
+ const normalized = answer.trim().toLowerCase();
1527
+ if (normalized === "y" || normalized === "yes" || normalized === "true") {
1528
+ return true;
1529
+ }
1530
+ if (normalized === "n" || normalized === "no" || normalized === "false") {
1531
+ return false;
1532
+ }
1533
+ return Boolean(field.defaultValue);
1534
+ }
1535
+ if (field.kind === "number") {
1536
+ const parsed = Number.parseInt(answer.trim(), 10);
1537
+ if (Number.isFinite(parsed)) {
1538
+ return parsed;
1539
+ }
1540
+ return Number(field.defaultValue);
1541
+ }
1542
+ if (field.kind === "select") {
1543
+ const trimmed2 = answer.trim();
1544
+ if (field.options && field.options.some((option) => option.value === trimmed2)) {
1545
+ return trimmed2;
1546
+ }
1547
+ const asNumber = Number.parseInt(trimmed2, 10);
1548
+ if (Number.isFinite(asNumber) && field.options && asNumber >= 1 && asNumber <= field.options.length) {
1549
+ return field.options[asNumber - 1]?.value ?? String(field.defaultValue);
1550
+ }
1551
+ return String(field.defaultValue);
1552
+ }
1553
+ const trimmed = answer.trim();
1554
+ if (trimmed.length === 0) {
1555
+ return String(field.defaultValue);
1556
+ }
1557
+ return trimmed;
1558
+ };
1559
+ var buildPrompt = (field) => {
1560
+ if (field.kind === "select" && field.options) {
1561
+ return `${field.prompt}
1562
+ Choice (or Enter for default): `;
1563
+ }
1564
+ if (field.kind === "boolean") {
1565
+ const yesNo = field.defaultValue ? "Y/n" : "y/N";
1566
+ return `${field.prompt} [${yesNo}] `;
1567
+ }
1568
+ return `${field.prompt}: `;
1569
+ };
1570
+ var askSelectWithArrowKeys = async (field, io) => {
1571
+ if (!field.options || field.options.length === 0) {
1572
+ return void 0;
1573
+ }
1574
+ const options = field.options;
1575
+ if (!stdin.isTTY || typeof stdin.setRawMode !== "function") {
1576
+ return void 0;
1577
+ }
1578
+ let selectedIndex = Math.max(
1579
+ 0,
1580
+ options.findIndex((option) => option.value === String(field.defaultValue))
1581
+ );
1582
+ let renderedLines = 0;
1583
+ const render = () => {
1584
+ if (renderedLines > 0) {
1585
+ moveCursor(stdout, 0, -renderedLines);
1586
+ }
1587
+ const lines = [
1588
+ BORDER,
1589
+ `? ${field.prompt}`,
1590
+ ...options.map(
1591
+ (option, index) => index === selectedIndex ? `${SELECTED_MARKER} ${option.label}` : ` ${option.label}`
1592
+ ),
1593
+ BORDER,
1594
+ "Use Up/Down, Enter to confirm."
1595
+ ];
1596
+ for (const line of lines) {
1597
+ clearLine(stdout, 0);
1598
+ cursorTo(stdout, 0);
1599
+ stdout.write(`${line}
1600
+ `);
1601
+ }
1602
+ renderedLines = lines.length;
1603
+ };
1604
+ return await new Promise((resolveChoice, rejectChoice) => {
1605
+ const onKeypress = (_str, key) => {
1606
+ if (key.ctrl && key.name === "c") {
1607
+ cleanup();
1608
+ rejectChoice(new Error("Onboarding cancelled"));
1609
+ return;
1610
+ }
1611
+ if (key.name === "up") {
1612
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length;
1613
+ render();
1614
+ return;
1615
+ }
1616
+ if (key.name === "down") {
1617
+ selectedIndex = (selectedIndex + 1) % options.length;
1618
+ render();
1619
+ return;
1620
+ }
1621
+ if (key.name === "return" || key.name === "enter") {
1622
+ const selected = options[selectedIndex]?.value ?? String(field.defaultValue);
1623
+ cleanup();
1624
+ resolveChoice(selected);
1625
+ }
1626
+ };
1627
+ const cleanup = () => {
1628
+ stdin.off("keypress", onKeypress);
1629
+ stdin.setRawMode(false);
1630
+ io?.resume();
1631
+ stdout.write("\n");
1632
+ };
1633
+ io?.pause();
1634
+ emitKeypressEvents(stdin);
1635
+ stdin.setRawMode(true);
1636
+ stdin.resume();
1637
+ render();
1638
+ stdin.on("keypress", onKeypress);
1639
+ });
1640
+ };
1641
+ var askBooleanWithArrowKeys = async (field, io) => {
1642
+ if (!stdin.isTTY || typeof stdin.setRawMode !== "function") {
1643
+ return void 0;
1644
+ }
1645
+ const options = [
1646
+ { value: "true", label: "Yes" },
1647
+ { value: "false", label: "No" }
1648
+ ];
1649
+ let selectedIndex = field.defaultValue ? 0 : 1;
1650
+ let renderedLines = 0;
1651
+ const render = () => {
1652
+ if (renderedLines > 0) {
1653
+ moveCursor(stdout, 0, -renderedLines);
1654
+ }
1655
+ const lines = [
1656
+ BORDER,
1657
+ `? ${field.prompt}`,
1658
+ ...options.map(
1659
+ (option, index) => index === selectedIndex ? `${SELECTED_MARKER} ${option.label}` : ` ${option.label}`
1660
+ ),
1661
+ BORDER,
1662
+ "Use Left/Right or Up/Down, Enter to confirm."
1663
+ ];
1664
+ for (const line of lines) {
1665
+ clearLine(stdout, 0);
1666
+ cursorTo(stdout, 0);
1667
+ stdout.write(`${line}
1668
+ `);
1669
+ }
1670
+ renderedLines = lines.length;
1671
+ };
1672
+ return await new Promise((resolveChoice, rejectChoice) => {
1673
+ const onKeypress = (_str, key) => {
1674
+ if (key.ctrl && key.name === "c") {
1675
+ cleanup();
1676
+ rejectChoice(new Error("Onboarding cancelled"));
1677
+ return;
1678
+ }
1679
+ if (key.name === "up" || key.name === "left" || key.name === "down" || key.name === "right") {
1680
+ selectedIndex = selectedIndex === 0 ? 1 : 0;
1681
+ render();
1682
+ return;
1683
+ }
1684
+ if (key.name === "return" || key.name === "enter") {
1685
+ const selected = options[selectedIndex]?.value ?? String(field.defaultValue);
1686
+ cleanup();
1687
+ resolveChoice(selected);
1688
+ }
1689
+ };
1690
+ const cleanup = () => {
1691
+ stdin.off("keypress", onKeypress);
1692
+ stdin.setRawMode(false);
1693
+ io?.resume();
1694
+ stdout.write("\n");
1695
+ };
1696
+ io?.pause();
1697
+ emitKeypressEvents(stdin);
1698
+ stdin.setRawMode(true);
1699
+ stdin.resume();
1700
+ render();
1701
+ stdin.on("keypress", onKeypress);
1702
+ });
1703
+ };
1704
+ var buildDefaultAnswers = (mode) => {
1705
+ const answers = {};
1706
+ for (const field of fieldsForScope(mode)) {
1707
+ answers[field.id] = field.defaultValue;
1708
+ }
1709
+ return answers;
1710
+ };
1711
+ var askOnboardingQuestions = async (mode, options) => {
1712
+ const answers = buildDefaultAnswers(mode);
1713
+ const interactive = options.yes === true ? false : options.interactive ?? (stdin.isTTY === true && stdout.isTTY === true);
1714
+ if (!interactive) {
1715
+ return answers;
1716
+ }
1717
+ const rl = createInterface({ input: stdin, output: stdout });
1718
+ try {
1719
+ stdout.write(`${BORDER}
1720
+ `);
1721
+ stdout.write(
1722
+ `AgentL onboarding (${mode === "full" ? "full" : "light"} mode)
1723
+ `
1724
+ );
1725
+ stdout.write(`${BORDER}
1726
+
1727
+ `);
1728
+ const fields = fieldsForScope(mode);
1729
+ for (const field of fields) {
1730
+ if (!shouldAskField(field, answers)) {
1731
+ continue;
1732
+ }
1733
+ const value = field.kind === "select" ? await askSelectWithArrowKeys(field, rl) ?? await rl.question(buildPrompt(field)) : field.kind === "boolean" ? await askBooleanWithArrowKeys(field, rl) ?? await rl.question(buildPrompt(field)) : await rl.question(buildPrompt(field));
1734
+ if (value.trim().length === 0) {
1735
+ continue;
1736
+ }
1737
+ answers[field.id] = parsePromptValue(field, value);
1738
+ }
1739
+ } finally {
1740
+ rl.close();
1741
+ }
1742
+ return answers;
1743
+ };
1744
+ var getProviderModelName = (provider) => provider === "openai" ? "gpt-4.1" : "claude-opus-4-5";
1745
+ var maybeSet = (target, key, value) => {
1746
+ if (typeof value === "string" && value.trim().length === 0) {
1747
+ return;
1748
+ }
1749
+ if (typeof value === "undefined") {
1750
+ return;
1751
+ }
1752
+ target[key] = value;
1753
+ };
1754
+ var buildConfigFromOnboardingAnswers = (answers) => {
1755
+ const storageProvider = String(answers["storage.provider"] ?? "local");
1756
+ const memoryEnabled = Boolean(answers["storage.memory.enabled"] ?? true);
1757
+ const maxRecallConversations = Number(
1758
+ answers["storage.memory.maxRecallConversations"] ?? 20
1759
+ );
1760
+ const storage = {
1761
+ provider: storageProvider,
1762
+ memory: {
1763
+ enabled: memoryEnabled,
1764
+ maxRecallConversations
1765
+ }
1766
+ };
1767
+ maybeSet(storage, "url", answers["storage.url"]);
1768
+ maybeSet(storage, "token", answers["storage.token"]);
1769
+ maybeSet(storage, "table", answers["storage.table"]);
1770
+ maybeSet(storage, "region", answers["storage.region"]);
1771
+ const authRequired = Boolean(answers["auth.required"] ?? false);
1772
+ const authType = answers["auth.type"] ?? "bearer";
1773
+ const auth = {
1774
+ required: authRequired,
1775
+ type: authType
1776
+ };
1777
+ if (authType === "header") {
1778
+ maybeSet(auth, "headerName", answers["auth.headerName"]);
1779
+ }
1780
+ const telemetryEnabled = Boolean(answers["telemetry.enabled"] ?? true);
1781
+ const telemetry = {
1782
+ enabled: telemetryEnabled
1783
+ };
1784
+ maybeSet(telemetry, "otlp", answers["telemetry.otlp"]);
1785
+ return {
1786
+ mcp: [],
1787
+ auth,
1788
+ storage,
1789
+ telemetry
1790
+ };
1791
+ };
1792
+ var isDefaultOnboardingConfig = (config) => {
1793
+ if (!config) {
1794
+ return true;
1795
+ }
1796
+ const topLevelKeys = Object.keys(config);
1797
+ const allowedTopLevel = /* @__PURE__ */ new Set(["mcp", "auth", "storage", "telemetry"]);
1798
+ if (topLevelKeys.some((key) => !allowedTopLevel.has(key))) {
1799
+ return false;
1800
+ }
1801
+ if ((config.mcp ?? []).length > 0) {
1802
+ return false;
1803
+ }
1804
+ const authRequired = config.auth?.required ?? false;
1805
+ const authType = config.auth?.type ?? "bearer";
1806
+ if (authRequired || authType !== "bearer" || typeof config.auth?.headerName !== "undefined") {
1807
+ return false;
1808
+ }
1809
+ const provider = config.storage?.provider ?? "local";
1810
+ if (provider !== "local") {
1811
+ return false;
1812
+ }
1813
+ if (typeof config.storage?.url !== "undefined" || typeof config.storage?.token !== "undefined" || typeof config.storage?.table !== "undefined" || typeof config.storage?.region !== "undefined") {
1814
+ return false;
1815
+ }
1816
+ const memoryEnabled = config.storage?.memory?.enabled ?? true;
1817
+ const maxRecallConversations = config.storage?.memory?.maxRecallConversations ?? 20;
1818
+ if (!memoryEnabled || maxRecallConversations !== 20) {
1819
+ return false;
1820
+ }
1821
+ const telemetryEnabled = config.telemetry?.enabled ?? true;
1822
+ const telemetryHasExtra = typeof config.telemetry?.otlp !== "undefined" || typeof config.telemetry?.latitude !== "undefined" || typeof config.telemetry?.handler !== "undefined";
1823
+ if (!telemetryEnabled || telemetryHasExtra) {
1824
+ return false;
1825
+ }
1826
+ return true;
1827
+ };
1828
+ var collectEnvVars = (answers) => {
1829
+ const envVars = /* @__PURE__ */ new Set();
1830
+ const provider = String(answers["model.provider"] ?? "anthropic");
1831
+ if (provider === "openai") {
1832
+ envVars.add("OPENAI_API_KEY=sk-...");
1833
+ } else {
1834
+ envVars.add("ANTHROPIC_API_KEY=sk-ant-...");
1835
+ }
1836
+ const storageProvider = String(answers["storage.provider"] ?? "local");
1837
+ if (storageProvider === "redis") {
1838
+ envVars.add("REDIS_URL=redis://localhost:6379");
1839
+ }
1840
+ if (storageProvider === "upstash") {
1841
+ envVars.add("UPSTASH_REDIS_REST_URL=https://...");
1842
+ envVars.add("UPSTASH_REDIS_REST_TOKEN=...");
1843
+ }
1844
+ if (storageProvider === "dynamodb") {
1845
+ envVars.add("AGENTL_DYNAMODB_TABLE=agentl-conversations");
1846
+ envVars.add("AWS_REGION=us-east-1");
1847
+ }
1848
+ return Array.from(envVars);
1849
+ };
1850
+ var runInitOnboarding = async (options) => {
1851
+ const answers = await askOnboardingQuestions(options.mode, options);
1852
+ const provider = String(answers["model.provider"] ?? "anthropic");
1853
+ const config = buildConfigFromOnboardingAnswers(answers);
1854
+ const envLines = collectEnvVars(answers);
1855
+ return {
1856
+ answers,
1857
+ config,
1858
+ envExample: `${envLines.join("\n")}
1859
+ `,
1860
+ agentModel: {
1861
+ provider: provider === "openai" ? "openai" : "anthropic",
1862
+ name: getProviderModelName(provider)
1863
+ }
1864
+ };
1865
+ };
1866
+
1867
+ // src/init-feature-context.ts
1868
+ import { access, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
1869
+ import { dirname as dirname2, resolve as resolve2 } from "path";
1870
+ import {
1871
+ FEATURE_DOMAIN_ORDER,
1872
+ ONBOARDING_FIELDS as ONBOARDING_FIELDS2
1873
+ } from "@agentl/sdk";
1874
+ var ONBOARDING_VERSION = 1;
1875
+ var ONBOARDING_MARKER_RELATIVE_PATH = ".agentl/state/onboarding.json";
1876
+ var FEATURE_DOMAIN_LABELS = {
1877
+ model: "Model",
1878
+ storage: "Storage",
1879
+ memory: "Memory",
1880
+ auth: "Auth",
1881
+ telemetry: "Telemetry",
1882
+ mcp: "MCP"
1883
+ };
1884
+ var summarizeConfig = (config) => {
1885
+ const provider = config?.storage?.provider ?? config?.state?.provider ?? "local";
1886
+ const memoryEnabled = config?.storage?.memory?.enabled ?? config?.memory?.enabled ?? false;
1887
+ const authRequired = config?.auth?.required ?? false;
1888
+ const telemetryEnabled = config?.telemetry?.enabled ?? true;
1889
+ return [
1890
+ `storage: ${provider}`,
1891
+ `memory tools: ${memoryEnabled ? "enabled" : "disabled"}`,
1892
+ `auth: ${authRequired ? "required" : "not required"}`,
1893
+ `telemetry: ${telemetryEnabled ? "enabled" : "disabled"}`
1894
+ ];
1895
+ };
1896
+ var collectFeatureSummary = () => {
1897
+ const grouped = {
1898
+ model: [],
1899
+ storage: [],
1900
+ memory: [],
1901
+ auth: [],
1902
+ telemetry: [],
1903
+ mcp: []
1904
+ };
1905
+ for (const field of ONBOARDING_FIELDS2) {
1906
+ const existing = grouped[field.domain].find((item) => item.title === field.label);
1907
+ const detail = `path: ${field.path}`;
1908
+ if (existing) {
1909
+ if (!existing.details.includes(detail)) {
1910
+ existing.details.push(detail);
1911
+ }
1912
+ continue;
1913
+ }
1914
+ grouped[field.domain].push({
1915
+ title: field.label,
1916
+ details: [detail]
1917
+ });
1918
+ }
1919
+ grouped.mcp.push({
1920
+ title: "MCP integrations",
1921
+ details: ["path: mcp[] (add/remove via CLI or chat-driven config edits)"]
1922
+ });
1923
+ return grouped;
1924
+ };
1925
+ var buildOnboardingFeatureGuidance = () => {
1926
+ const grouped = collectFeatureSummary();
1927
+ const lines = [
1928
+ "## Configuration Assistant Context",
1929
+ "",
1930
+ "You can help users configure this project by editing `agentl.config.js` when write tools are enabled.",
1931
+ "",
1932
+ "When users ask for config changes:",
1933
+ "- Keep config-edit guidance available, but only provide onboarding overview proactively on first run.",
1934
+ "- First summarize intended edits and affected keys.",
1935
+ "- Apply minimal edits only to requested keys.",
1936
+ "- Preserve unrelated config keys and custom code.",
1937
+ "- Confirm what changed and what environment variables are required.",
1938
+ "",
1939
+ "Feature catalog:"
1940
+ ];
1941
+ for (const domain of FEATURE_DOMAIN_ORDER) {
1942
+ const items = grouped[domain];
1943
+ if (items.length === 0) {
1944
+ continue;
1945
+ }
1946
+ lines.push(`- ${FEATURE_DOMAIN_LABELS[domain]}:`);
1947
+ for (const item of items) {
1948
+ lines.push(` - ${item.title} (${item.details.join(", ")})`);
1949
+ }
1950
+ }
1951
+ return `${lines.join("\n")}
1952
+ `;
1953
+ };
1954
+ var getOnboardingMarkerPath = (workingDir) => resolve2(workingDir, ONBOARDING_MARKER_RELATIVE_PATH);
1955
+ var readMarker = async (workingDir) => {
1956
+ const markerPath = getOnboardingMarkerPath(workingDir);
1957
+ try {
1958
+ await access(markerPath);
1959
+ } catch {
1960
+ return void 0;
1961
+ }
1962
+ try {
1963
+ const raw = await readFile2(markerPath, "utf8");
1964
+ return JSON.parse(raw);
1965
+ } catch {
1966
+ return void 0;
1967
+ }
1968
+ };
1969
+ var writeMarker = async (workingDir, state) => {
1970
+ const markerPath = getOnboardingMarkerPath(workingDir);
1971
+ await mkdir2(dirname2(markerPath), { recursive: true });
1972
+ await writeFile2(markerPath, JSON.stringify(state, null, 2), "utf8");
1973
+ };
1974
+ var initializeOnboardingMarker = async (workingDir, options) => {
1975
+ const current = await readMarker(workingDir);
1976
+ if (current) {
1977
+ return;
1978
+ }
1979
+ const allowIntro = options?.allowIntro ?? true;
1980
+ await writeMarker(workingDir, {
1981
+ introduced: allowIntro ? false : true,
1982
+ allowIntro,
1983
+ onboardingVersion: ONBOARDING_VERSION,
1984
+ createdAt: Date.now()
1985
+ });
1986
+ };
1987
+ var consumeFirstRunIntro = async (workingDir, input) => {
1988
+ const marker = await readMarker(workingDir);
1989
+ if (marker?.allowIntro === false) {
1990
+ return void 0;
1991
+ }
1992
+ if (!isDefaultOnboardingConfig(input.config)) {
1993
+ await writeMarker(workingDir, {
1994
+ introduced: true,
1995
+ allowIntro: false,
1996
+ onboardingVersion: ONBOARDING_VERSION,
1997
+ createdAt: marker?.createdAt ?? Date.now(),
1998
+ introducedAt: marker?.introducedAt ?? Date.now()
1999
+ });
2000
+ return void 0;
2001
+ }
2002
+ const shouldShow = !marker || marker.introduced === false;
2003
+ if (!shouldShow) {
2004
+ return void 0;
2005
+ }
2006
+ await writeMarker(workingDir, {
2007
+ introduced: true,
2008
+ allowIntro: true,
2009
+ onboardingVersion: ONBOARDING_VERSION,
2010
+ createdAt: marker?.createdAt ?? Date.now(),
2011
+ introducedAt: Date.now()
2012
+ });
2013
+ const summary = summarizeConfig(input.config);
2014
+ const featureGroups = [
2015
+ "model/provider",
2016
+ "storage and memory",
2017
+ "auth/security",
2018
+ "telemetry",
2019
+ "MCP integrations"
2020
+ ].join(", ");
2021
+ return [
2022
+ "============================================================",
2023
+ `Hi! I'm ${input.agentName}.`,
2024
+ "I can help configure this agent directly by chat.",
2025
+ "------------------------------------------------------------",
2026
+ `Model: ${input.provider}/${input.model}`,
2027
+ `Current setup: ${summary.join(" | ")}`,
2028
+ `Configurable areas: ${featureGroups}`,
2029
+ "------------------------------------------------------------",
2030
+ "Try:",
2031
+ ' - "Switch storage to Upstash"',
2032
+ ' - "Enable auth with bearer token validation"',
2033
+ ' - "Turn on telemetry and set OTLP endpoint"',
2034
+ "Note: I will summarize changes before editing config.",
2035
+ "============================================================"
2036
+ ].join("\n");
2037
+ };
2038
+
2039
+ export {
2040
+ SessionStore,
2041
+ LoginRateLimiter,
2042
+ parseCookies,
2043
+ setCookie,
2044
+ verifyPassphrase,
2045
+ getRequestIp,
2046
+ inferConversationTitle,
2047
+ renderManifest,
2048
+ renderIconSvg,
2049
+ renderServiceWorker,
2050
+ renderWebUiHtml,
2051
+ isDefaultOnboardingConfig,
2052
+ runInitOnboarding,
2053
+ buildOnboardingFeatureGuidance,
2054
+ initializeOnboardingMarker,
2055
+ consumeFirstRunIntro
2056
+ };