@juspay/shooter 1.5.0 → 1.6.1

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 (478) hide show
  1. package/README.md +24 -20
  2. package/bin/shooter.cjs +68 -17
  3. package/build/client/_app/immutable/assets/2.Dk9NfqnS.css +1 -0
  4. package/build/client/_app/immutable/assets/2.Dk9NfqnS.css.br +0 -0
  5. package/build/client/_app/immutable/assets/2.Dk9NfqnS.css.gz +0 -0
  6. package/build/client/_app/immutable/assets/3.DHxQoulp.css +1 -0
  7. package/build/client/_app/immutable/assets/3.DHxQoulp.css.br +0 -0
  8. package/build/client/_app/immutable/assets/3.DHxQoulp.css.gz +0 -0
  9. package/build/client/_app/immutable/assets/{3.DGDHCVnW.css → 4.D5l1JxgO.css} +1 -1
  10. package/build/client/_app/immutable/assets/4.D5l1JxgO.css.br +0 -0
  11. package/build/client/_app/immutable/assets/4.D5l1JxgO.css.gz +0 -0
  12. package/build/client/_app/immutable/assets/5.C5qz-NeI.css +1 -0
  13. package/build/client/_app/immutable/assets/5.C5qz-NeI.css.br +0 -0
  14. package/build/client/_app/immutable/assets/5.C5qz-NeI.css.gz +0 -0
  15. package/build/client/_app/immutable/chunks/1mEchsPO.js +1 -0
  16. package/build/client/_app/immutable/chunks/1mEchsPO.js.br +0 -0
  17. package/build/client/_app/immutable/chunks/1mEchsPO.js.gz +0 -0
  18. package/build/client/_app/immutable/chunks/B7X-vhXI.js +1 -0
  19. package/build/client/_app/immutable/chunks/B7X-vhXI.js.br +0 -0
  20. package/build/client/_app/immutable/chunks/B7X-vhXI.js.gz +0 -0
  21. package/build/client/_app/immutable/chunks/BRkqKgVG.js +1 -0
  22. package/build/client/_app/immutable/chunks/BRkqKgVG.js.br +0 -0
  23. package/build/client/_app/immutable/chunks/BRkqKgVG.js.gz +0 -0
  24. package/build/client/_app/immutable/chunks/BfJ-f-Tu.js +1 -0
  25. package/build/client/_app/immutable/chunks/BfJ-f-Tu.js.br +2 -0
  26. package/build/client/_app/immutable/chunks/BfJ-f-Tu.js.gz +0 -0
  27. package/build/client/_app/immutable/chunks/CGMJxf7r.js +1 -0
  28. package/build/client/_app/immutable/chunks/CGMJxf7r.js.br +0 -0
  29. package/build/client/_app/immutable/chunks/CGMJxf7r.js.gz +0 -0
  30. package/build/client/_app/immutable/chunks/{CZHsSL_X.js → CJFjKwJ7.js} +1 -1
  31. package/build/client/_app/immutable/chunks/CJFjKwJ7.js.br +0 -0
  32. package/build/client/_app/immutable/chunks/CJFjKwJ7.js.gz +0 -0
  33. package/build/client/_app/immutable/chunks/CNH2HlKj.js +20 -0
  34. package/build/client/_app/immutable/chunks/CNH2HlKj.js.br +0 -0
  35. package/build/client/_app/immutable/chunks/CNH2HlKj.js.gz +0 -0
  36. package/build/client/_app/immutable/chunks/CR6bkGJW.js +6 -0
  37. package/build/client/_app/immutable/chunks/CR6bkGJW.js.br +0 -0
  38. package/build/client/_app/immutable/chunks/CR6bkGJW.js.gz +0 -0
  39. package/build/client/_app/immutable/chunks/CVtJ6yRM.js +1 -0
  40. package/build/client/_app/immutable/chunks/CVtJ6yRM.js.br +0 -0
  41. package/build/client/_app/immutable/chunks/CVtJ6yRM.js.gz +0 -0
  42. package/build/client/_app/immutable/chunks/{CSoRdFvv.js → CaiJSUi3.js} +1 -1
  43. package/build/client/_app/immutable/chunks/CaiJSUi3.js.br +0 -0
  44. package/build/client/_app/immutable/chunks/CaiJSUi3.js.gz +0 -0
  45. package/build/client/_app/immutable/chunks/{DjsDGxCa.js → CmczWE_d.js} +4 -4
  46. package/build/client/_app/immutable/chunks/CmczWE_d.js.br +0 -0
  47. package/build/client/_app/immutable/chunks/CmczWE_d.js.gz +0 -0
  48. package/build/client/_app/immutable/chunks/CsgHjHGZ.js +1 -0
  49. package/build/client/_app/immutable/chunks/CsgHjHGZ.js.br +0 -0
  50. package/build/client/_app/immutable/chunks/CsgHjHGZ.js.gz +0 -0
  51. package/build/client/_app/immutable/chunks/{UJOiqIYE.js → CtrCjGZT.js} +1 -1
  52. package/build/client/_app/immutable/chunks/CtrCjGZT.js.br +0 -0
  53. package/build/client/_app/immutable/chunks/CtrCjGZT.js.gz +0 -0
  54. package/build/client/_app/immutable/chunks/DDiOVAd8.js +61 -0
  55. package/build/client/_app/immutable/chunks/DDiOVAd8.js.br +0 -0
  56. package/build/client/_app/immutable/chunks/DDiOVAd8.js.gz +0 -0
  57. package/build/client/_app/immutable/chunks/DVl0sebP.js +2 -0
  58. package/build/client/_app/immutable/chunks/DVl0sebP.js.br +0 -0
  59. package/build/client/_app/immutable/chunks/DVl0sebP.js.gz +0 -0
  60. package/build/client/_app/immutable/chunks/{CiF38mQq.js → Dc_Gg2H6.js} +1 -1
  61. package/build/client/_app/immutable/chunks/Dc_Gg2H6.js.br +0 -0
  62. package/build/client/_app/immutable/chunks/Dc_Gg2H6.js.gz +0 -0
  63. package/build/client/_app/immutable/chunks/{CRbaG9cv.js → DlnAjkg1.js} +1 -1
  64. package/build/client/_app/immutable/chunks/DlnAjkg1.js.br +0 -0
  65. package/build/client/_app/immutable/chunks/{CRbaG9cv.js.gz → DlnAjkg1.js.gz} +0 -0
  66. package/build/client/_app/immutable/chunks/YKoRJzXZ.js +3 -0
  67. package/build/client/_app/immutable/chunks/YKoRJzXZ.js.br +0 -0
  68. package/build/client/_app/immutable/chunks/YKoRJzXZ.js.gz +0 -0
  69. package/build/client/_app/immutable/chunks/gQJcRhou.js +1 -0
  70. package/build/client/_app/immutable/chunks/gQJcRhou.js.br +0 -0
  71. package/build/client/_app/immutable/chunks/gQJcRhou.js.gz +0 -0
  72. package/build/client/_app/immutable/chunks/pRcLbE0d.js +1 -0
  73. package/build/client/_app/immutable/chunks/pRcLbE0d.js.br +0 -0
  74. package/build/client/_app/immutable/chunks/pRcLbE0d.js.gz +0 -0
  75. package/build/client/_app/immutable/entry/app.CFPgQOa8.js +2 -0
  76. package/build/client/_app/immutable/entry/app.CFPgQOa8.js.br +0 -0
  77. package/build/client/_app/immutable/entry/app.CFPgQOa8.js.gz +0 -0
  78. package/build/client/_app/immutable/entry/start.BnJOVqhI.js +1 -0
  79. package/build/client/_app/immutable/entry/start.BnJOVqhI.js.br +2 -0
  80. package/build/client/_app/immutable/entry/start.BnJOVqhI.js.gz +0 -0
  81. package/build/client/_app/immutable/nodes/0.DR-BBF5r.js +1 -0
  82. package/build/client/_app/immutable/nodes/0.DR-BBF5r.js.br +0 -0
  83. package/build/client/_app/immutable/nodes/0.DR-BBF5r.js.gz +0 -0
  84. package/build/client/_app/immutable/nodes/1.CNm6rAwf.js +1 -0
  85. package/build/client/_app/immutable/nodes/1.CNm6rAwf.js.br +0 -0
  86. package/build/client/_app/immutable/nodes/1.CNm6rAwf.js.gz +0 -0
  87. package/build/client/_app/immutable/nodes/2.B08usYzr.js +13 -0
  88. package/build/client/_app/immutable/nodes/2.B08usYzr.js.br +0 -0
  89. package/build/client/_app/immutable/nodes/2.B08usYzr.js.gz +0 -0
  90. package/build/client/_app/immutable/nodes/3.CsY6J5HS.js +9 -0
  91. package/build/client/_app/immutable/nodes/3.CsY6J5HS.js.br +0 -0
  92. package/build/client/_app/immutable/nodes/3.CsY6J5HS.js.gz +0 -0
  93. package/build/client/_app/immutable/nodes/4.B_pbOZoD.js +4 -0
  94. package/build/client/_app/immutable/nodes/4.B_pbOZoD.js.br +0 -0
  95. package/build/client/_app/immutable/nodes/4.B_pbOZoD.js.gz +0 -0
  96. package/build/client/_app/immutable/nodes/5.CdLPNo5-.js +1 -0
  97. package/build/client/_app/immutable/nodes/5.CdLPNo5-.js.br +0 -0
  98. package/build/client/_app/immutable/nodes/5.CdLPNo5-.js.gz +0 -0
  99. package/build/client/_app/immutable/nodes/6.CbQQ3FtZ.js +1 -0
  100. package/build/client/_app/immutable/nodes/6.CbQQ3FtZ.js.br +0 -0
  101. package/build/client/_app/immutable/nodes/6.CbQQ3FtZ.js.gz +0 -0
  102. package/build/client/_app/immutable/nodes/{5.DIkXVP4q.js → 7.CCKgiNNk.js} +3 -3
  103. package/build/client/_app/immutable/nodes/7.CCKgiNNk.js.br +0 -0
  104. package/build/client/_app/immutable/nodes/7.CCKgiNNk.js.gz +0 -0
  105. package/build/client/_app/immutable/nodes/8.C7AaheUD.js +2 -0
  106. package/build/client/_app/immutable/nodes/8.C7AaheUD.js.br +0 -0
  107. package/build/client/_app/immutable/nodes/8.C7AaheUD.js.gz +0 -0
  108. package/build/client/_app/immutable/nodes/9.DfL9kMC4.js +2 -0
  109. package/build/client/_app/immutable/nodes/9.DfL9kMC4.js.br +0 -0
  110. package/build/client/_app/immutable/nodes/9.DfL9kMC4.js.gz +0 -0
  111. package/build/client/_app/version.json +1 -1
  112. package/build/client/_app/version.json.br +0 -0
  113. package/build/client/_app/version.json.gz +0 -0
  114. package/build/server/chunks/0-DC2VLooL.js +23 -0
  115. package/build/server/chunks/0-DC2VLooL.js.map +1 -0
  116. package/build/server/chunks/1-XJaf8Jvf.js +9 -0
  117. package/build/server/chunks/{1-D0N7vVhH.js.map → 1-XJaf8Jvf.js.map} +1 -1
  118. package/build/server/chunks/2-D4Cx-1QL.js +21 -0
  119. package/build/server/chunks/2-D4Cx-1QL.js.map +1 -0
  120. package/build/server/chunks/3-CVhIEP-u.js +21 -0
  121. package/build/server/chunks/3-CVhIEP-u.js.map +1 -0
  122. package/build/server/chunks/4-0UE_6Ep-.js +23 -0
  123. package/build/server/chunks/4-0UE_6Ep-.js.map +1 -0
  124. package/build/server/chunks/5-BBIP1PzX.js +24 -0
  125. package/build/server/chunks/5-BBIP1PzX.js.map +1 -0
  126. package/build/server/chunks/6-QFSbzRMP.js +9 -0
  127. package/build/server/chunks/6-QFSbzRMP.js.map +1 -0
  128. package/build/server/chunks/7-CZ_YGjMV.js +9 -0
  129. package/build/server/chunks/7-CZ_YGjMV.js.map +1 -0
  130. package/build/server/chunks/8-Xe2Rugb4.js +9 -0
  131. package/build/server/chunks/8-Xe2Rugb4.js.map +1 -0
  132. package/build/server/chunks/9-IwHpC4SO.js +9 -0
  133. package/build/server/chunks/9-IwHpC4SO.js.map +1 -0
  134. package/build/server/chunks/{Button-Cs1aE6ka.js → Button-WKgiLWZI.js} +4 -9
  135. package/build/server/chunks/Button-WKgiLWZI.js.map +1 -0
  136. package/build/server/chunks/{EmptyState-DDFH1K8g.js → EmptyState-BUBqASsp.js} +3 -3
  137. package/build/server/chunks/{EmptyState-DDFH1K8g.js.map → EmptyState-BUBqASsp.js.map} +1 -1
  138. package/build/server/chunks/{Icon-CEUrotA6.js → Icon-BNBAg85a.js} +3 -3
  139. package/build/server/chunks/Icon-BNBAg85a.js.map +1 -0
  140. package/build/server/chunks/{Shimmer-DB8W1zt6.js → Shimmer-C4uBVwxz.js} +2 -2
  141. package/build/server/chunks/{Shimmer-DB8W1zt6.js.map → Shimmer-C4uBVwxz.js.map} +1 -1
  142. package/build/server/chunks/{_error.svelte-uCOJNxvr.js → _error.svelte-DkIwmECt.js} +5 -5
  143. package/build/server/chunks/{_error.svelte-uCOJNxvr.js.map → _error.svelte-DkIwmECt.js.map} +1 -1
  144. package/build/server/chunks/{_layout.svelte-CtWmEJwe.js → _layout.svelte-DllETxmJ.js} +13 -7
  145. package/build/server/chunks/_layout.svelte-DllETxmJ.js.map +1 -0
  146. package/build/server/chunks/_page.svelte-BZSdLKE_.js +118 -0
  147. package/build/server/chunks/_page.svelte-BZSdLKE_.js.map +1 -0
  148. package/build/server/chunks/{_page.svelte-CxWcQ0Am.js → _page.svelte-Cmuco1mC.js} +84 -199
  149. package/build/server/chunks/_page.svelte-Cmuco1mC.js.map +1 -0
  150. package/build/server/chunks/{_page.svelte-BgevQjq1.js → _page.svelte-Co5sF7W-.js} +12 -11
  151. package/build/server/chunks/{_page.svelte-BgevQjq1.js.map → _page.svelte-Co5sF7W-.js.map} +1 -1
  152. package/build/server/chunks/{_page.svelte-DO4oa_LY.js → _page.svelte-CpL3R-VI.js} +8 -8
  153. package/build/server/chunks/{_page.svelte-DO4oa_LY.js.map → _page.svelte-CpL3R-VI.js.map} +1 -1
  154. package/build/server/chunks/_page.svelte-DDSzYLUs.js +137 -0
  155. package/build/server/chunks/_page.svelte-DDSzYLUs.js.map +1 -0
  156. package/build/server/chunks/_page.svelte-JIkgFUFf.js +26 -0
  157. package/build/server/chunks/_page.svelte-JIkgFUFf.js.map +1 -0
  158. package/build/server/chunks/{_page.svelte-CVq6tRb3.js → _page.svelte-Y9-O5a5w.js} +10 -9
  159. package/build/server/chunks/_page.svelte-Y9-O5a5w.js.map +1 -0
  160. package/build/server/chunks/{_page.svelte-BcZaKdX9.js → _page.svelte-fcX09N4d.js} +9 -9
  161. package/build/server/chunks/{_page.svelte-BcZaKdX9.js.map → _page.svelte-fcX09N4d.js.map} +1 -1
  162. package/build/server/chunks/{_server.ts-DYpJImqd.js → _server.ts-0Xr2fWaq.js} +9 -5
  163. package/build/server/chunks/_server.ts-0Xr2fWaq.js.map +1 -0
  164. package/build/server/chunks/{_server.ts-CTpcLUH8.js → _server.ts-2ixC-X3K.js} +20 -5
  165. package/build/server/chunks/_server.ts-2ixC-X3K.js.map +1 -0
  166. package/build/server/chunks/{_server.ts-CAxsWKvS.js → _server.ts-40c_epk8.js} +20 -4
  167. package/build/server/chunks/_server.ts-40c_epk8.js.map +1 -0
  168. package/build/server/chunks/{_server.ts-WhTJBEJy.js → _server.ts-A9_tRR-K.js} +5 -4
  169. package/build/server/chunks/{_server.ts-WhTJBEJy.js.map → _server.ts-A9_tRR-K.js.map} +1 -1
  170. package/build/server/chunks/_server.ts-BRAzC6W1.js +98 -0
  171. package/build/server/chunks/_server.ts-BRAzC6W1.js.map +1 -0
  172. package/build/server/chunks/{_server.ts-DB_Kg97c.js → _server.ts-BScvgttw.js} +24 -4
  173. package/build/server/chunks/_server.ts-BScvgttw.js.map +1 -0
  174. package/build/server/chunks/{_server.ts-tSpgyl1D.js → _server.ts-Bjbr7glm.js} +4 -3
  175. package/build/server/chunks/_server.ts-Bjbr7glm.js.map +1 -0
  176. package/build/server/chunks/{_server.ts-COu0vNpd.js → _server.ts-BrqaMMAa.js} +7 -6
  177. package/build/server/chunks/_server.ts-BrqaMMAa.js.map +1 -0
  178. package/build/server/chunks/{_server.ts-vekTmWAx.js → _server.ts-BuYyCrnF.js} +6 -4
  179. package/build/server/chunks/_server.ts-BuYyCrnF.js.map +1 -0
  180. package/build/server/chunks/{_server.ts-DYvb9ijZ.js → _server.ts-ByPExYfO.js} +4 -3
  181. package/build/server/chunks/{_server.ts-DYvb9ijZ.js.map → _server.ts-ByPExYfO.js.map} +1 -1
  182. package/build/server/chunks/_server.ts-CjpQ10xh.js +123 -0
  183. package/build/server/chunks/_server.ts-CjpQ10xh.js.map +1 -0
  184. package/build/server/chunks/_server.ts-CyjDrcZN.js +21 -0
  185. package/build/server/chunks/_server.ts-CyjDrcZN.js.map +1 -0
  186. package/build/server/chunks/{_server.ts-DV8zTCF9.js → _server.ts-DOGUMzPx.js} +4 -3
  187. package/build/server/chunks/{_server.ts-DV8zTCF9.js.map → _server.ts-DOGUMzPx.js.map} +1 -1
  188. package/build/server/chunks/_server.ts-DZvfyuNj.js +15 -0
  189. package/build/server/chunks/_server.ts-DZvfyuNj.js.map +1 -0
  190. package/build/server/chunks/{_server.ts-XzT2UHM1.js → _server.ts-DkPPTUPo.js} +4 -3
  191. package/build/server/chunks/{_server.ts-XzT2UHM1.js.map → _server.ts-DkPPTUPo.js.map} +1 -1
  192. package/build/server/chunks/{_server.ts-Deok2y88.js → _server.ts-Ds_SUGC3.js} +184 -90
  193. package/build/server/chunks/_server.ts-Ds_SUGC3.js.map +1 -0
  194. package/build/server/chunks/{_server.ts-Ch-6iOHp.js → _server.ts-G8OeADGj.js} +141 -89
  195. package/build/server/chunks/_server.ts-G8OeADGj.js.map +1 -0
  196. package/build/server/chunks/{auth-DeCdZ83n.js → auth-DuunT7Cg.js} +2 -2
  197. package/build/server/chunks/{auth-DeCdZ83n.js.map → auth-DuunT7Cg.js.map} +1 -1
  198. package/build/server/chunks/{client-BdGHe_hY.js → client-DRtPDkMh.js} +4 -4
  199. package/build/server/chunks/{client-BdGHe_hY.js.map → client-DRtPDkMh.js.map} +1 -1
  200. package/build/server/chunks/client2-bqqmu0b7.js +7 -0
  201. package/build/server/chunks/{client2-CCBGA-2V.js.map → client2-bqqmu0b7.js.map} +1 -1
  202. package/build/server/chunks/close-BGlLztTb.js +192 -0
  203. package/build/server/chunks/close-BGlLztTb.js.map +1 -0
  204. package/build/server/chunks/events-handler-Dm1mNPQP.js +20 -0
  205. package/build/server/chunks/events-handler-Dm1mNPQP.js.map +1 -0
  206. package/build/server/chunks/html-FW6Ia4bL.js +8 -0
  207. package/build/server/chunks/html-FW6Ia4bL.js.map +1 -0
  208. package/build/server/chunks/{shared-server-sSGG17Df.js → index-CoD1IJuy.js} +2 -11
  209. package/build/server/chunks/index-CoD1IJuy.js.map +1 -0
  210. package/build/server/chunks/{index-DwaY1cAm.js → index-DP9bWJrR.js} +2 -2
  211. package/build/server/chunks/{index-DwaY1cAm.js.map → index-DP9bWJrR.js.map} +1 -1
  212. package/build/server/chunks/{index-server-CrDaL06Y.js → index-server-BUmV4MIG.js} +2 -2
  213. package/build/server/chunks/index-server-BUmV4MIG.js.map +1 -0
  214. package/build/server/chunks/index-server2-BJrT0wnA.js +5 -0
  215. package/build/server/chunks/index-server2-BJrT0wnA.js.map +1 -0
  216. package/build/server/chunks/{index2-CgclKpUj.js → index2-D5Y19GKR.js} +2 -2
  217. package/build/server/chunks/index2-D5Y19GKR.js.map +1 -0
  218. package/build/server/chunks/{library-apns-BqJbvSKh.js → library-apns-Cf-E-DhM.js} +5 -2
  219. package/build/server/chunks/library-apns-Cf-E-DhM.js.map +1 -0
  220. package/build/server/chunks/providers-DtstoHQ0.js +17 -0
  221. package/build/server/chunks/providers-DtstoHQ0.js.map +1 -0
  222. package/build/server/chunks/{pty-manager-BQVB7IVj.js → pty-manager-TyMUpDA9.js} +41 -9
  223. package/build/server/chunks/pty-manager-TyMUpDA9.js.map +1 -0
  224. package/build/server/chunks/{root-DDSnEAZv.js → root-CATOR_0t.js} +2 -2
  225. package/build/server/chunks/root-CATOR_0t.js.map +1 -0
  226. package/build/server/chunks/shared-server-DaWdgxVh.js +11 -0
  227. package/build/server/chunks/shared-server-DaWdgxVh.js.map +1 -0
  228. package/build/server/chunks/{state.svelte-hBbXlUak.js → state.svelte-CftllyvC.js} +3 -3
  229. package/build/server/chunks/state.svelte-CftllyvC.js.map +1 -0
  230. package/build/server/chunks/{stores-DHNzYNpX.js → stores-BjL57aOK.js} +4 -4
  231. package/build/server/chunks/{stores-DHNzYNpX.js.map → stores-BjL57aOK.js.map} +1 -1
  232. package/build/server/index.js +173 -6
  233. package/build/server/index.js.map +1 -1
  234. package/build/server/manifest.js +53 -30
  235. package/build/server/manifest.js.map +1 -1
  236. package/package.json +24 -6
  237. package/scripts/dev.mjs +361 -0
  238. package/scripts/install.sh +11 -3
  239. package/scripts/{fix-generated-types.sh → postgen-types.sh} +2 -2
  240. package/scripts/setup.cjs +219 -24
  241. package/scripts/vercel-env-commands.sh +3 -3
  242. package/server.ts +3 -3
  243. package/src/app.html +163 -0
  244. package/src/lib/modules/client/activity/ActivityFeed.svelte +279 -0
  245. package/src/lib/modules/client/activity/index.ts +8 -0
  246. package/src/lib/modules/client/activity/store.svelte.ts +478 -0
  247. package/src/lib/modules/client/activity/summarizer.ts +224 -0
  248. package/src/lib/modules/client/common/Card.svelte +2 -9
  249. package/src/lib/modules/client/common/EmptyState.svelte +2 -20
  250. package/src/lib/modules/client/common/Icon.svelte +3 -7
  251. package/src/lib/modules/client/common/StatusBadge.svelte +2 -4
  252. package/src/lib/modules/client/common/config-guard.ts +22 -2
  253. package/src/lib/modules/client/common/index.ts +1 -1
  254. package/src/lib/modules/client/common/time.ts +27 -9
  255. package/src/lib/modules/client/dashboard/DashboardCard.svelte +374 -0
  256. package/src/lib/modules/client/dashboard/DashboardView.svelte +66 -0
  257. package/src/lib/modules/client/dashboard/index.ts +12 -0
  258. package/src/lib/modules/client/dashboard/store.svelte.ts +663 -0
  259. package/src/lib/modules/client/dashboard/summarizer.ts +205 -0
  260. package/src/lib/modules/client/neurolink/fetch-proxy.ts +70 -0
  261. package/src/lib/modules/client/neurolink/provider-config.ts +111 -0
  262. package/src/lib/modules/client/terminal/ChatView.svelte +46 -43
  263. package/src/lib/modules/client/terminal/CommandPalette.svelte +3 -12
  264. package/src/lib/modules/client/terminal/ConnectionStatus.svelte +3 -6
  265. package/src/lib/modules/client/terminal/LaunchSheet.svelte +10 -21
  266. package/src/lib/modules/client/terminal/QuickKeys.svelte +4 -11
  267. package/src/lib/modules/client/terminal/ShortcutsHelp.svelte +3 -6
  268. package/src/lib/modules/client/terminal/keyboard-shortcuts.ts +5 -7
  269. package/src/lib/modules/client/terminal/xterm-wrapper.ts +27 -47
  270. package/src/lib/modules/server/apn/library-apns.ts +6 -3
  271. package/src/lib/modules/server/apn/notification-history.ts +2 -2
  272. package/src/lib/modules/server/apn/notification-sessions.ts +1 -3
  273. package/src/lib/modules/server/apn/pending-requests.ts +1 -1
  274. package/src/lib/modules/server/apn/types.ts +2 -52
  275. package/src/lib/modules/server/cli/index.ts +1 -30
  276. package/src/lib/modules/server/cli/runner.ts +7 -15
  277. package/src/lib/modules/server/fcm/fcm-service.ts +2 -2
  278. package/src/lib/modules/server/sessions/jsonl-parser.ts +97 -42
  279. package/src/lib/modules/server/sessions/jsonl-reader.ts +144 -76
  280. package/src/lib/modules/server/sessions/opencode-reader.ts +1 -1
  281. package/src/lib/modules/server/sessions/process-detector.ts +72 -31
  282. package/src/lib/modules/server/sessions/types.ts +2 -42
  283. package/src/lib/modules/server/terminal/holder-client.ts +11 -35
  284. package/src/lib/modules/server/terminal/opencode-watcher.ts +16 -24
  285. package/src/lib/modules/server/terminal/pty-manager.ts +40 -45
  286. package/src/lib/modules/server/terminal/session-watcher.ts +15 -17
  287. package/src/lib/modules/server/terminal/terminal-store.ts +1 -1
  288. package/src/lib/modules/server/ws/events-handler.ts +1 -16
  289. package/src/lib/modules/server/ws/keepalive.ts +1 -5
  290. package/src/lib/modules/server/ws/server.ts +1 -1
  291. package/src/lib/modules/server/ws/session-handler.ts +20 -86
  292. package/src/lib/modules/server/ws/terminal-handler.ts +28 -51
  293. package/src/lib/modules/server/ws/ticket-store.ts +1 -1
  294. package/src/lib/modules/shared/providers.ts +21 -0
  295. package/src/lib/types/activity.ts +18 -0
  296. package/src/lib/types/apn.ts +43 -0
  297. package/src/lib/types/cli.ts +39 -0
  298. package/src/lib/types/common.ts +39 -0
  299. package/src/lib/types/dashboard.ts +4 -0
  300. package/src/lib/types/generated/Client.ts +1656 -0
  301. package/src/{generated/types → lib/types/generated}/WsProtocol.ts +344 -2
  302. package/src/lib/types/index.ts +28 -0
  303. package/src/lib/types/neurolink.ts +4 -0
  304. package/src/lib/types/server.ts +93 -0
  305. package/src/lib/types/sessions.ts +59 -0
  306. package/src/lib/types/terminal-client.ts +132 -0
  307. package/src/lib/types/ws.ts +161 -0
  308. package/src/routes/+error.svelte +7 -2
  309. package/src/routes/+layout.server.ts +9 -0
  310. package/src/routes/+layout.svelte +36 -7
  311. package/src/routes/+page.server.ts +7 -0
  312. package/src/routes/+page.svelte +85 -35
  313. package/src/routes/activity/+page.server.ts +7 -0
  314. package/src/routes/activity/+page.svelte +58 -0
  315. package/src/routes/api/health/+server.ts +32 -19
  316. package/src/routes/api/neurolink-proxy/+server.ts +136 -0
  317. package/src/routes/api/notify/+server.ts +190 -87
  318. package/src/routes/api/sessions/+server.ts +1 -1
  319. package/src/routes/api/sessions/connect/+server.ts +10 -6
  320. package/src/routes/api/terminals/+server.ts +20 -1
  321. package/src/routes/api/terminals/[id]/+server.ts +16 -2
  322. package/src/routes/api/webhook/+server.ts +5 -33
  323. package/src/routes/api/ws-ticket/+server.ts +4 -4
  324. package/src/routes/config/+page.server.ts +9 -0
  325. package/src/routes/config/+page.svelte +118 -25
  326. package/src/routes/neurolink/+page.server.ts +10 -0
  327. package/src/routes/neurolink/+page.svelte +331 -0
  328. package/src/routes/project/+page.svelte +17 -12
  329. package/src/routes/session/[id]/+page.svelte +146 -62
  330. package/src/routes/terminals/+page.svelte +2 -2
  331. package/src/routes/terminals/[id]/+page.svelte +99 -88
  332. package/svelte.config.js +1 -3
  333. package/tsconfig.json +1 -0
  334. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css +0 -1
  335. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.br +0 -1
  336. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.gz +0 -0
  337. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.br +0 -0
  338. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.gz +0 -0
  339. package/build/client/_app/immutable/chunks/B5NAKyil.js +0 -20
  340. package/build/client/_app/immutable/chunks/B5NAKyil.js.br +0 -0
  341. package/build/client/_app/immutable/chunks/B5NAKyil.js.gz +0 -0
  342. package/build/client/_app/immutable/chunks/B8XegpSE.js +0 -1
  343. package/build/client/_app/immutable/chunks/B8XegpSE.js.br +0 -0
  344. package/build/client/_app/immutable/chunks/B8XegpSE.js.gz +0 -0
  345. package/build/client/_app/immutable/chunks/B8zoBsv3.js +0 -6
  346. package/build/client/_app/immutable/chunks/B8zoBsv3.js.br +0 -0
  347. package/build/client/_app/immutable/chunks/B8zoBsv3.js.gz +0 -0
  348. package/build/client/_app/immutable/chunks/BIaXC2t9.js +0 -1
  349. package/build/client/_app/immutable/chunks/BIaXC2t9.js.br +0 -0
  350. package/build/client/_app/immutable/chunks/BIaXC2t9.js.gz +0 -0
  351. package/build/client/_app/immutable/chunks/BOYo8yTr.js +0 -1
  352. package/build/client/_app/immutable/chunks/BOYo8yTr.js.br +0 -0
  353. package/build/client/_app/immutable/chunks/BOYo8yTr.js.gz +0 -0
  354. package/build/client/_app/immutable/chunks/Bu1aqm5j.js +0 -1
  355. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.br +0 -0
  356. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.gz +0 -0
  357. package/build/client/_app/immutable/chunks/CQjSATpv.js +0 -61
  358. package/build/client/_app/immutable/chunks/CQjSATpv.js.br +0 -0
  359. package/build/client/_app/immutable/chunks/CQjSATpv.js.gz +0 -0
  360. package/build/client/_app/immutable/chunks/CRbaG9cv.js.br +0 -0
  361. package/build/client/_app/immutable/chunks/CSoRdFvv.js.br +0 -0
  362. package/build/client/_app/immutable/chunks/CSoRdFvv.js.gz +0 -0
  363. package/build/client/_app/immutable/chunks/CZHsSL_X.js.br +0 -0
  364. package/build/client/_app/immutable/chunks/CZHsSL_X.js.gz +0 -0
  365. package/build/client/_app/immutable/chunks/CiF38mQq.js.br +0 -0
  366. package/build/client/_app/immutable/chunks/CiF38mQq.js.gz +0 -0
  367. package/build/client/_app/immutable/chunks/DSU1n5N_.js +0 -1
  368. package/build/client/_app/immutable/chunks/DSU1n5N_.js.br +0 -0
  369. package/build/client/_app/immutable/chunks/DSU1n5N_.js.gz +0 -0
  370. package/build/client/_app/immutable/chunks/DVkn4r72.js +0 -1
  371. package/build/client/_app/immutable/chunks/DVkn4r72.js.br +0 -0
  372. package/build/client/_app/immutable/chunks/DVkn4r72.js.gz +0 -0
  373. package/build/client/_app/immutable/chunks/DjsDGxCa.js.br +0 -0
  374. package/build/client/_app/immutable/chunks/DjsDGxCa.js.gz +0 -0
  375. package/build/client/_app/immutable/chunks/UJOiqIYE.js.br +0 -0
  376. package/build/client/_app/immutable/chunks/UJOiqIYE.js.gz +0 -0
  377. package/build/client/_app/immutable/chunks/r0JawsZc.js +0 -2
  378. package/build/client/_app/immutable/chunks/r0JawsZc.js.br +0 -0
  379. package/build/client/_app/immutable/chunks/r0JawsZc.js.gz +0 -0
  380. package/build/client/_app/immutable/entry/app.CU7KVZja.js +0 -2
  381. package/build/client/_app/immutable/entry/app.CU7KVZja.js.br +0 -0
  382. package/build/client/_app/immutable/entry/app.CU7KVZja.js.gz +0 -0
  383. package/build/client/_app/immutable/entry/start.RAMZY19t.js +0 -1
  384. package/build/client/_app/immutable/entry/start.RAMZY19t.js.br +0 -2
  385. package/build/client/_app/immutable/entry/start.RAMZY19t.js.gz +0 -0
  386. package/build/client/_app/immutable/nodes/0.Bi3XYMSu.js +0 -1
  387. package/build/client/_app/immutable/nodes/0.Bi3XYMSu.js.br +0 -0
  388. package/build/client/_app/immutable/nodes/0.Bi3XYMSu.js.gz +0 -0
  389. package/build/client/_app/immutable/nodes/1.DTmfBFmm.js +0 -1
  390. package/build/client/_app/immutable/nodes/1.DTmfBFmm.js.br +0 -0
  391. package/build/client/_app/immutable/nodes/1.DTmfBFmm.js.gz +0 -0
  392. package/build/client/_app/immutable/nodes/2.Cm269yzt.js +0 -1
  393. package/build/client/_app/immutable/nodes/2.Cm269yzt.js.br +0 -0
  394. package/build/client/_app/immutable/nodes/2.Cm269yzt.js.gz +0 -0
  395. package/build/client/_app/immutable/nodes/3.3yohCM25.js +0 -3
  396. package/build/client/_app/immutable/nodes/3.3yohCM25.js.br +0 -0
  397. package/build/client/_app/immutable/nodes/3.3yohCM25.js.gz +0 -0
  398. package/build/client/_app/immutable/nodes/4.C25c5hMg.js +0 -1
  399. package/build/client/_app/immutable/nodes/4.C25c5hMg.js.br +0 -0
  400. package/build/client/_app/immutable/nodes/4.C25c5hMg.js.gz +0 -0
  401. package/build/client/_app/immutable/nodes/5.DIkXVP4q.js.br +0 -0
  402. package/build/client/_app/immutable/nodes/5.DIkXVP4q.js.gz +0 -0
  403. package/build/client/_app/immutable/nodes/6.BPL-HzUX.js +0 -2
  404. package/build/client/_app/immutable/nodes/6.BPL-HzUX.js.br +0 -0
  405. package/build/client/_app/immutable/nodes/6.BPL-HzUX.js.gz +0 -0
  406. package/build/client/_app/immutable/nodes/7.IgEqce53.js +0 -2
  407. package/build/client/_app/immutable/nodes/7.IgEqce53.js.br +0 -0
  408. package/build/client/_app/immutable/nodes/7.IgEqce53.js.gz +0 -0
  409. package/build/server/chunks/0-DiORznXb.js +0 -9
  410. package/build/server/chunks/0-DiORznXb.js.map +0 -1
  411. package/build/server/chunks/1-D0N7vVhH.js +0 -9
  412. package/build/server/chunks/2-DfSav7a7.js +0 -9
  413. package/build/server/chunks/2-DfSav7a7.js.map +0 -1
  414. package/build/server/chunks/3-Ck7ewhOX.js +0 -9
  415. package/build/server/chunks/3-Ck7ewhOX.js.map +0 -1
  416. package/build/server/chunks/4-DV5MZUz_.js +0 -9
  417. package/build/server/chunks/4-DV5MZUz_.js.map +0 -1
  418. package/build/server/chunks/5-DJhoAjb0.js +0 -9
  419. package/build/server/chunks/5-DJhoAjb0.js.map +0 -1
  420. package/build/server/chunks/6-Cp8CzYbr.js +0 -9
  421. package/build/server/chunks/6-Cp8CzYbr.js.map +0 -1
  422. package/build/server/chunks/7-BA4xzUj3.js +0 -9
  423. package/build/server/chunks/7-BA4xzUj3.js.map +0 -1
  424. package/build/server/chunks/Button-Cs1aE6ka.js.map +0 -1
  425. package/build/server/chunks/Icon-CEUrotA6.js.map +0 -1
  426. package/build/server/chunks/_layout.svelte-CtWmEJwe.js.map +0 -1
  427. package/build/server/chunks/_page.svelte-BdYynOck.js +0 -85
  428. package/build/server/chunks/_page.svelte-BdYynOck.js.map +0 -1
  429. package/build/server/chunks/_page.svelte-CVq6tRb3.js.map +0 -1
  430. package/build/server/chunks/_page.svelte-CxWcQ0Am.js.map +0 -1
  431. package/build/server/chunks/_server.ts-BStnNIcq.js +0 -34
  432. package/build/server/chunks/_server.ts-BStnNIcq.js.map +0 -1
  433. package/build/server/chunks/_server.ts-CAxsWKvS.js.map +0 -1
  434. package/build/server/chunks/_server.ts-COu0vNpd.js.map +0 -1
  435. package/build/server/chunks/_server.ts-CTpcLUH8.js.map +0 -1
  436. package/build/server/chunks/_server.ts-Cf84YIaW.js +0 -25
  437. package/build/server/chunks/_server.ts-Cf84YIaW.js.map +0 -1
  438. package/build/server/chunks/_server.ts-Ch-6iOHp.js.map +0 -1
  439. package/build/server/chunks/_server.ts-CtH0dhUp.js +0 -71
  440. package/build/server/chunks/_server.ts-CtH0dhUp.js.map +0 -1
  441. package/build/server/chunks/_server.ts-DB_Kg97c.js.map +0 -1
  442. package/build/server/chunks/_server.ts-DYpJImqd.js.map +0 -1
  443. package/build/server/chunks/_server.ts-Deok2y88.js.map +0 -1
  444. package/build/server/chunks/_server.ts-tSpgyl1D.js.map +0 -1
  445. package/build/server/chunks/_server.ts-vekTmWAx.js.map +0 -1
  446. package/build/server/chunks/client2-CCBGA-2V.js +0 -7
  447. package/build/server/chunks/index-server-CrDaL06Y.js.map +0 -1
  448. package/build/server/chunks/index2-CgclKpUj.js.map +0 -1
  449. package/build/server/chunks/library-apns-BqJbvSKh.js.map +0 -1
  450. package/build/server/chunks/pty-manager-BQVB7IVj.js.map +0 -1
  451. package/build/server/chunks/root-DDSnEAZv.js.map +0 -1
  452. package/build/server/chunks/shared-server-sSGG17Df.js.map +0 -1
  453. package/build/server/chunks/state.svelte-hBbXlUak.js.map +0 -1
  454. package/src/generated/types/Client.ts +0 -589
  455. package/src/lib/types/config.ts +0 -1
  456. /package/build/client/_app/immutable/assets/{4.BFUut--w.css → 6.BFUut--w.css} +0 -0
  457. /package/build/client/_app/immutable/assets/{4.BFUut--w.css.br → 6.BFUut--w.css.br} +0 -0
  458. /package/build/client/_app/immutable/assets/{4.BFUut--w.css.gz → 6.BFUut--w.css.gz} +0 -0
  459. /package/build/client/_app/immutable/assets/{5.BTOx7yt7.css → 7.BTOx7yt7.css} +0 -0
  460. /package/build/client/_app/immutable/assets/{5.BTOx7yt7.css.br → 7.BTOx7yt7.css.br} +0 -0
  461. /package/build/client/_app/immutable/assets/{5.BTOx7yt7.css.gz → 7.BTOx7yt7.css.gz} +0 -0
  462. /package/build/client/_app/immutable/assets/{6.eZGZN-BF.css → 8.eZGZN-BF.css} +0 -0
  463. /package/build/client/_app/immutable/assets/{6.eZGZN-BF.css.br → 8.eZGZN-BF.css.br} +0 -0
  464. /package/build/client/_app/immutable/assets/{6.eZGZN-BF.css.gz → 8.eZGZN-BF.css.gz} +0 -0
  465. /package/build/client/_app/immutable/assets/{7.DwS5ZHBh.css → 9.DwS5ZHBh.css} +0 -0
  466. /package/build/client/_app/immutable/assets/{7.DwS5ZHBh.css.br → 9.DwS5ZHBh.css.br} +0 -0
  467. /package/build/client/_app/immutable/assets/{7.DwS5ZHBh.css.gz → 9.DwS5ZHBh.css.gz} +0 -0
  468. /package/src/{generated/types → lib/types/generated}/API.ts +0 -0
  469. /package/src/{generated/types → lib/types/generated}/APN.ts +0 -0
  470. /package/src/{generated/types → lib/types/generated}/CLI.ts +0 -0
  471. /package/src/{generated/types → lib/types/generated}/Config.ts +0 -0
  472. /package/src/{generated/types → lib/types/generated}/Holder.ts +0 -0
  473. /package/src/{generated/types → lib/types/generated}/JWT.ts +0 -0
  474. /package/src/{generated/types → lib/types/generated}/Notification.ts +0 -0
  475. /package/src/{generated/types → lib/types/generated}/OpenCode.ts +0 -0
  476. /package/src/{generated/types → lib/types/generated}/Sessions.ts +0 -0
  477. /package/src/{generated/types → lib/types/generated}/Terminal.ts +0 -0
  478. /package/src/{generated/types → lib/types/generated}/index.ts +0 -0
@@ -0,0 +1,663 @@
1
+ // Dashboard store — manages per-terminal SessionState, syncs from REST + WebSocket events.
2
+
3
+ import type {
4
+ DashboardCard,
5
+ DashboardTerminalListResponse,
6
+ DashboardTerminalRecord,
7
+ RawEvent,
8
+ SessionEvent,
9
+ SessionState,
10
+ SummaryContext,
11
+ } from '$lib/types';
12
+
13
+ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
14
+
15
+ import { SessionSummarizer } from './summarizer';
16
+
17
+ function nowIso(): string {
18
+ return new Date(Date.now()).toISOString();
19
+ }
20
+
21
+ // -- Constants ------------------------------------------------------------
22
+
23
+ const MAX_EVENTS_PER_SESSION = 100;
24
+ const POLL_INTERVAL_MS = 15_000;
25
+ const ACTIVE_THRESHOLD_MS = 30_000;
26
+
27
+ // Exponential backoff bounds for WS reconnection
28
+ const RECONNECT_BASE_MS = 2_000;
29
+ const RECONNECT_MAX_MS = 30_000;
30
+
31
+ // -- State (Svelte 5 runes) -----------------------------------------------
32
+
33
+ let sessions = $state<SessionState[]>([]);
34
+ let connected = $state(false);
35
+
36
+ let ws: null | WebSocket = null;
37
+ let pollTimer: null | ReturnType<typeof setInterval> = null;
38
+ let reconnectTimer: null | ReturnType<typeof setTimeout> = null;
39
+ let reconnectDelay = RECONNECT_BASE_MS;
40
+ let eventCounter = 0;
41
+
42
+ // Stored api key so polling can reuse it after connect()
43
+ let storedApiKey = '';
44
+
45
+ // Per-terminal summarizer instances
46
+ const summarizers = new SvelteMap<string, SessionSummarizer>();
47
+
48
+ // Per-terminal session WS connections (for goal extraction from conversation)
49
+ const sessionSockets = new SvelteMap<string, WebSocket>();
50
+
51
+ // Terminals currently opening a session socket — reserved synchronously
52
+ // before the async ticket fetch to prevent concurrent pollers from each
53
+ // passing the `sessionSockets.has()` check and opening duplicate sockets.
54
+ const pendingSessionSockets = new SvelteSet<string>();
55
+
56
+ export async function connect(apiKey: string): Promise<void> {
57
+ storedApiKey = apiKey || getApiKey();
58
+ if (!storedApiKey) {
59
+ return;
60
+ }
61
+
62
+ // Initial data load
63
+ await fetchTerminals(storedApiKey);
64
+
65
+ // WebSocket subscription
66
+ await connectWs(storedApiKey);
67
+
68
+ // Start polling for new terminals
69
+ if (pollTimer) {
70
+ clearInterval(pollTimer);
71
+ }
72
+ pollTimer = setInterval(() => {
73
+ void fetchTerminals(storedApiKey);
74
+ }, POLL_INTERVAL_MS);
75
+ }
76
+
77
+ export function disconnect(): void {
78
+ if (ws) {
79
+ ws.onclose = null; // prevent reconnect loop
80
+ ws.close();
81
+ ws = null;
82
+ }
83
+
84
+ if (pollTimer) {
85
+ clearInterval(pollTimer);
86
+ pollTimer = null;
87
+ }
88
+
89
+ if (reconnectTimer) {
90
+ clearTimeout(reconnectTimer);
91
+ reconnectTimer = null;
92
+ }
93
+
94
+ // Close all per-terminal session sockets
95
+ for (const [, sock] of sessionSockets) {
96
+ sock.onclose = null;
97
+ sock.close();
98
+ }
99
+ sessionSockets.clear();
100
+ pendingSessionSockets.clear();
101
+ summarizers.clear();
102
+
103
+ connected = false;
104
+ storedApiKey = '';
105
+ }
106
+
107
+ export function getCards(): DashboardCard[] {
108
+ const now = Date.now();
109
+ return sortSessions(sessions).map((s) => {
110
+ const createdMs = Date.parse(s.createdAt);
111
+ const lastEventTs =
112
+ s.events.length > 0 ? Date.parse(s.events[s.events.length - 1].timestamp) : 0;
113
+
114
+ return {
115
+ ...s,
116
+ duration: now - createdMs,
117
+ goal: s.goal, // Ensure goal is mapped
118
+ isActive: lastEventTs > 0 && now - lastEventTs < ACTIVE_THRESHOLD_MS,
119
+ isSummarizing: s.isSummarizing, // Ensure isSummarizing is mapped
120
+ summary: s.summary, // Ensure summary is mapped
121
+ };
122
+ });
123
+ }
124
+
125
+ export function getSessions(): SessionState[] {
126
+ return sessions;
127
+ }
128
+
129
+ export function isConnected(): boolean {
130
+ return connected;
131
+ }
132
+
133
+ // -- REST: fetch terminal list --------------------------------------------
134
+
135
+ export function updateSessionGoal(terminalId: string, goal: string): void {
136
+ const session = sessions.find((s) => s.terminalId === terminalId);
137
+ if (session) {
138
+ session.goal = goal;
139
+ }
140
+ }
141
+
142
+ export function updateSessionSummary(terminalId: string, summary: string): void {
143
+ const session = sessions.find((s) => s.terminalId === terminalId);
144
+ if (session) {
145
+ session.summary = summary;
146
+ session.summaryUpdatedAt = nowIso();
147
+ session.isSummarizing = false;
148
+ }
149
+ }
150
+
151
+ // -- WebSocket: events channel -------------------------------------------
152
+
153
+ function addEventToSession(
154
+ session: SessionState,
155
+ type: string,
156
+ data: Record<string, unknown>
157
+ ): void {
158
+ const event: SessionEvent = {
159
+ data,
160
+ id: `evt-${++eventCounter}`,
161
+ summarized: false,
162
+ terminalId: session.terminalId,
163
+ timestamp: (data.timestamp as null | string) ?? nowIso(),
164
+ type,
165
+ };
166
+
167
+ // Ring buffer — cap at MAX_EVENTS_PER_SESSION
168
+ const nextEvents =
169
+ session.events.length >= MAX_EVENTS_PER_SESSION
170
+ ? [...session.events.slice(1), event]
171
+ : [...session.events, event];
172
+
173
+ session.events = nextEvents;
174
+ session.eventCount += 1;
175
+ }
176
+
177
+ function basename(path: string): string {
178
+ return path.split('/').filter(Boolean).pop() ?? path;
179
+ }
180
+
181
+ function closeSessionSocket(terminalId: string): void {
182
+ const sock = sessionSockets.get(terminalId);
183
+ if (sock) {
184
+ sock.onclose = null;
185
+ sock.close();
186
+ sessionSockets.delete(terminalId);
187
+ }
188
+ }
189
+
190
+ async function connectWs(apiKey: string): Promise<void> {
191
+ if (ws && ws.readyState <= 1) {
192
+ return;
193
+ } // already open or connecting
194
+
195
+ try {
196
+ const ticketRes = await fetch('/api/ws-ticket', {
197
+ headers: { Authorization: `Bearer ${apiKey}` },
198
+ method: 'POST',
199
+ });
200
+
201
+ if (!ticketRes.ok) {
202
+ scheduleReconnect(apiKey);
203
+ return;
204
+ }
205
+
206
+ const { ticket } = (await ticketRes.json()) as { ticket: string };
207
+ const wsBase = window.location.origin.replace(/^http/, 'ws');
208
+ ws = new WebSocket(`${wsBase}/ws/events?ticket=${ticket}`);
209
+
210
+ ws.onopen = (): void => {
211
+ connected = true;
212
+ reconnectDelay = RECONNECT_BASE_MS; // reset backoff on success
213
+ };
214
+
215
+ ws.onmessage = (msg: MessageEvent): void => {
216
+ try {
217
+ const raw: unknown = JSON.parse(msg.data as string);
218
+ if (raw && typeof raw === 'object') {
219
+ handleWsMessage(raw as RawEvent);
220
+ }
221
+ } catch {
222
+ // ignore malformed messages
223
+ }
224
+ };
225
+
226
+ ws.onclose = (): void => {
227
+ connected = false;
228
+ ws = null;
229
+ scheduleReconnect(apiKey);
230
+ };
231
+
232
+ ws.onerror = (): void => {
233
+ connected = false;
234
+ };
235
+ } catch {
236
+ connected = false;
237
+ scheduleReconnect(apiKey);
238
+ }
239
+ }
240
+
241
+ function extractGoalText(content: string | { content?: string; type: string }[]): string {
242
+ let text = '';
243
+ if (typeof content === 'string') {
244
+ text = content;
245
+ } else if (Array.isArray(content)) {
246
+ const textPart = content.find((p) => p.type === 'text');
247
+ text = textPart?.content ?? '';
248
+ }
249
+ return text.slice(0, 200).trim();
250
+ }
251
+
252
+ async function fetchTerminals(apiKey: string): Promise<void> {
253
+ if (!apiKey) {
254
+ return;
255
+ }
256
+
257
+ try {
258
+ const res = await fetch('/api/terminals', {
259
+ headers: { Authorization: `Bearer ${apiKey}` },
260
+ });
261
+
262
+ if (!res.ok) {
263
+ return;
264
+ }
265
+
266
+ const body: DashboardTerminalListResponse = (await res.json()) as DashboardTerminalListResponse;
267
+ const incoming = body.terminals ?? [];
268
+
269
+ sessions = sortSessions(mergeSessions(sessions, incoming));
270
+ } catch {
271
+ // Network errors are silent — we'll retry on next poll
272
+ }
273
+ }
274
+
275
+ function getApiKey(): string {
276
+ try {
277
+ const saved = localStorage.getItem('shooter_config');
278
+ if (!saved) {
279
+ return '';
280
+ }
281
+ const parsed: unknown = JSON.parse(saved);
282
+ if (parsed && typeof parsed === 'object') {
283
+ const obj = parsed as Record<string, unknown>;
284
+ if (typeof obj.apiKey === 'string') {
285
+ return obj.apiKey;
286
+ }
287
+ }
288
+ } catch {
289
+ // ignore
290
+ }
291
+ return '';
292
+ }
293
+
294
+ // -- Public API -----------------------------------------------------------
295
+
296
+ function handleWsMessage(raw: RawEvent): void {
297
+ const type = raw.type as string | undefined;
298
+ if (!type || type === 'welcome') {
299
+ return;
300
+ }
301
+
302
+ // Resolve terminalId — may come directly, or from a terminal-created event
303
+ const terminalId = (raw.terminalId as null | string) ?? null;
304
+
305
+ if (!terminalId) {
306
+ // Events without terminalId don't map to a session card — skip
307
+ return;
308
+ }
309
+
310
+ const idx = sessions.findIndex((s) => s.terminalId === terminalId);
311
+ if (idx === -1) {
312
+ // Unknown terminal — will be picked up on next poll
313
+ return;
314
+ }
315
+
316
+ const session = sessions[idx];
317
+
318
+ switch (type) {
319
+ case 'agent-idle':
320
+ case 'agent-question': {
321
+ session.status = 'idle';
322
+ addEventToSession(session, type, raw);
323
+ break;
324
+ }
325
+ case 'terminal-exited': {
326
+ session.status = 'exited';
327
+ session.exitedAt = (raw.exitedAt as null | string) ?? nowIso();
328
+ addEventToSession(session, type, raw);
329
+ // Clean up per-terminal session socket and summarizer on exit
330
+ closeSessionSocket(terminalId);
331
+ summarizers.delete(terminalId);
332
+ break;
333
+ }
334
+ case 'tool-completed': {
335
+ addEventToSession(session, type, raw);
336
+ break;
337
+ }
338
+ case 'tool-failed': {
339
+ session.errorCount += 1;
340
+ addEventToSession(session, type, raw);
341
+ break;
342
+ }
343
+ case 'tool-started': {
344
+ session.toolCallCount += 1;
345
+ session.status = 'running';
346
+ addEventToSession(session, type, raw);
347
+ break;
348
+ }
349
+ default: {
350
+ addEventToSession(session, type, raw);
351
+ break;
352
+ }
353
+ }
354
+
355
+ // Trigger AI summarization on significant events or periodically
356
+ const shouldSummarize =
357
+ type === 'tool-failed' ||
358
+ type === 'agent-question' ||
359
+ session.errorCount >= 3 ||
360
+ (session.eventCount > 0 && session.eventCount % 20 === 0);
361
+
362
+ if (shouldSummarize && !session.isSummarizing) {
363
+ triggerSummarization(session);
364
+ }
365
+
366
+ // Re-sort after any status change
367
+ sessions = sortSessions(sessions);
368
+ }
369
+
370
+ function makeSessionState(t: DashboardTerminalRecord): SessionState {
371
+ return {
372
+ command: t.command,
373
+ createdAt: t.createdAt,
374
+ cwd: t.cwd,
375
+ errorCount: 0,
376
+ eventCount: 0,
377
+ events: [],
378
+ exitedAt: t.exitedAt,
379
+ goal: '',
380
+ isSummarizing: false,
381
+ projectName: basename(t.cwd),
382
+ projectPath: t.cwd,
383
+ status: mapStatus(t.status),
384
+ summary: '',
385
+ summaryUpdatedAt: '',
386
+ terminalId: t.id,
387
+ toolCallCount: 0,
388
+ };
389
+ }
390
+
391
+ function mapStatus(raw: string): SessionState['status'] {
392
+ if (raw === 'running') {
393
+ return 'running';
394
+ }
395
+ if (raw === 'idle') {
396
+ return 'idle';
397
+ }
398
+ if (raw === 'exited') {
399
+ return 'exited';
400
+ }
401
+ return 'error';
402
+ }
403
+
404
+ function mergeSessions(
405
+ existing: SessionState[],
406
+ incoming: DashboardTerminalRecord[]
407
+ ): SessionState[] {
408
+ // Drop terminals that disappeared from the API — tear down their sockets
409
+ // and summarizer state so cards don't linger after deletion/cleanup.
410
+ const incomingIds = new Set(incoming.map((t) => t.id));
411
+ for (const s of existing) {
412
+ if (!incomingIds.has(s.terminalId)) {
413
+ closeSessionSocket(s.terminalId);
414
+ summarizers.delete(s.terminalId);
415
+ }
416
+ }
417
+
418
+ const map = new SvelteMap<string, SessionState>();
419
+ for (const s of existing) {
420
+ if (incomingIds.has(s.terminalId)) {
421
+ map.set(s.terminalId, s);
422
+ }
423
+ }
424
+
425
+ for (const t of incoming) {
426
+ const prev = map.get(t.id);
427
+ if (prev) {
428
+ // Preserve accumulated event data; update mutable fields from server
429
+ prev.command = t.command;
430
+ prev.cwd = t.cwd;
431
+ prev.projectName = basename(t.cwd);
432
+ prev.projectPath = t.cwd;
433
+ prev.exitedAt = t.exitedAt;
434
+ // Only update status from server if we don't have a more specific local status
435
+ if (prev.status !== 'error') {
436
+ prev.status = mapStatus(t.status);
437
+ }
438
+ // Schedule goal extraction if still missing
439
+ if (!prev.goal) {
440
+ void openSessionSocket(t.id);
441
+ }
442
+ } else {
443
+ map.set(t.id, makeSessionState(t));
444
+ // Open a session WS for goal extraction on newly discovered terminals
445
+ void openSessionSocket(t.id);
446
+ }
447
+ }
448
+
449
+ return Array.from(map.values());
450
+ }
451
+
452
+ async function openSessionSocket(terminalId: string): Promise<void> {
453
+ if (!storedApiKey) {
454
+ return;
455
+ }
456
+ // Do not open duplicates — check both the open-socket map and the pending
457
+ // set. Reserving the pending slot synchronously (before the async ticket
458
+ // fetch) closes the TOCTOU window where two concurrent calls would each
459
+ // pass `sessionSockets.has()` and open parallel WebSockets.
460
+ if (sessionSockets.has(terminalId) || pendingSessionSockets.has(terminalId)) {
461
+ return;
462
+ }
463
+ pendingSessionSockets.add(terminalId);
464
+
465
+ console.log(`[DashboardStore] Opening session socket for ${terminalId}`);
466
+
467
+ try {
468
+ const ticketRes = await fetch('/api/ws-ticket', {
469
+ headers: { Authorization: `Bearer ${storedApiKey}` },
470
+ method: 'POST',
471
+ });
472
+
473
+ if (!ticketRes.ok) {
474
+ console.warn(`[DashboardStore] Failed to get WS ticket for ${terminalId}:`, ticketRes.status);
475
+ return;
476
+ }
477
+
478
+ const { ticket } = (await ticketRes.json()) as { ticket: string };
479
+ const wsBase = window.location.origin.replace(/^http/, 'ws');
480
+ const wsUrl = `${wsBase}/ws/session/${terminalId}?ticket=${ticket}`;
481
+ console.log(`[DashboardStore] Connecting session socket for ${terminalId}`);
482
+ const sock = new WebSocket(wsUrl);
483
+
484
+ sessionSockets.set(terminalId, sock);
485
+
486
+ sock.onopen = (): void => {
487
+ console.log(`[DashboardStore] Session socket opened for ${terminalId}`);
488
+ };
489
+
490
+ sock.onmessage = (msg: MessageEvent): void => {
491
+ try {
492
+ const raw: unknown = JSON.parse(msg.data as string);
493
+ if (!raw || typeof raw !== 'object') {
494
+ return;
495
+ }
496
+ const data = raw as Record<string, unknown>;
497
+
498
+ // Check if we already have a goal for this terminal
499
+ const currentSession = sessions.find((s) => s.terminalId === terminalId);
500
+ const hasGoal = currentSession?.goal && currentSession.goal.length > 0;
501
+
502
+ if (data.type === 'history') {
503
+ console.log(`[DashboardStore] Received history for ${terminalId}, extracting goal...`);
504
+
505
+ const messages = data.messages as
506
+ | undefined
507
+ | {
508
+ content: string | { content?: string; type: string }[];
509
+ role: string;
510
+ }[];
511
+ if (!Array.isArray(messages)) {
512
+ console.warn(`[DashboardStore] No messages array in history for ${terminalId}`);
513
+ return;
514
+ }
515
+
516
+ console.log(
517
+ `[DashboardStore] Found ${messages.length} messages, looking for first user message...`
518
+ );
519
+
520
+ // Find first user message and extract goal
521
+ for (const m of messages) {
522
+ if (m.role === 'user') {
523
+ const goal = extractGoalText(m.content);
524
+ console.log(
525
+ `[DashboardStore] Extracted goal for ${terminalId}: "${goal.substring(0, 50)}..."`
526
+ );
527
+
528
+ if (goal) {
529
+ updateSessionGoal(terminalId, goal);
530
+ }
531
+ // Goal extracted — close the socket, we no longer need it
532
+ closeSessionSocket(terminalId);
533
+ return;
534
+ }
535
+ }
536
+
537
+ console.log(`[DashboardStore] No user message found in history for ${terminalId}`);
538
+ // No user message yet — keep socket open for incoming messages
539
+ return;
540
+ }
541
+
542
+ // Handle individual message frames — if the socket opened before any
543
+ // user message existed, the goal never gets set from history alone.
544
+ if (data.type === 'message' && data.role === 'user' && !hasGoal) {
545
+ const goal = extractGoalText(
546
+ data.content as string | { content?: string; type: string }[]
547
+ );
548
+ if (goal) {
549
+ console.log(
550
+ `[DashboardStore] Extracted goal from message for ${terminalId}: "${goal.substring(0, 50)}..."`
551
+ );
552
+ updateSessionGoal(terminalId, goal);
553
+ closeSessionSocket(terminalId);
554
+ }
555
+ return;
556
+ }
557
+
558
+ // Ignore other message types while waiting for a goal
559
+ if (!hasGoal) {
560
+ return;
561
+ }
562
+
563
+ // We have a goal already — close the socket
564
+ closeSessionSocket(terminalId);
565
+ } catch (err) {
566
+ console.warn('[DashboardStore] Error processing session message:', err);
567
+ }
568
+ };
569
+
570
+ sock.onclose = (): void => {
571
+ console.log(`[DashboardStore] Session socket closed for ${terminalId}`);
572
+ sessionSockets.delete(terminalId);
573
+ };
574
+
575
+ sock.onerror = (err: Event): void => {
576
+ console.warn(`[DashboardStore] Session socket error for ${terminalId}:`, err);
577
+ sessionSockets.delete(terminalId);
578
+ };
579
+ } catch (err) {
580
+ console.warn('[DashboardStore] Failed to open session socket:', err);
581
+ } finally {
582
+ pendingSessionSockets.delete(terminalId);
583
+ }
584
+ }
585
+
586
+ function scheduleReconnect(apiKey: string): void {
587
+ if (reconnectTimer) {
588
+ return;
589
+ }
590
+
591
+ reconnectTimer = setTimeout(() => {
592
+ reconnectTimer = null;
593
+ void connectWs(apiKey);
594
+ }, reconnectDelay);
595
+
596
+ // Exponential backoff, capped
597
+ reconnectDelay = Math.min(reconnectDelay * 2, RECONNECT_MAX_MS);
598
+ }
599
+
600
+ function sortSessions(list: SessionState[]): SessionState[] {
601
+ return [...list].sort((a, b) => {
602
+ const order: Record<SessionState['status'], number> = {
603
+ error: 2,
604
+ exited: 3,
605
+ idle: 1,
606
+ running: 0,
607
+ };
608
+
609
+ const rankA = order[a.status];
610
+ const rankB = order[b.status];
611
+
612
+ if (rankA !== rankB) {
613
+ return rankA - rankB;
614
+ }
615
+
616
+ // Within running/idle: newest first
617
+ if (a.status !== 'exited' && b.status !== 'exited') {
618
+ return b.createdAt.localeCompare(a.createdAt);
619
+ }
620
+
621
+ // Within exited: most recently exited first
622
+ const exitA = a.exitedAt ?? a.createdAt;
623
+ const exitB = b.exitedAt ?? b.createdAt;
624
+ return exitB.localeCompare(exitA);
625
+ });
626
+ }
627
+
628
+ function triggerSummarization(session: SessionState): void {
629
+ session.isSummarizing = true;
630
+
631
+ let summarizer = summarizers.get(session.terminalId);
632
+ if (!summarizer) {
633
+ summarizer = new SessionSummarizer();
634
+ summarizers.set(session.terminalId, summarizer);
635
+ }
636
+
637
+ const recentEvents = session.events.slice(-10).map((e) => ({
638
+ command: typeof e.data.command === 'string' ? e.data.command : null,
639
+ error: typeof e.data.error === 'string' ? e.data.error : null,
640
+ tool: typeof e.data.tool === 'string' ? e.data.tool : null,
641
+ type: e.type,
642
+ }));
643
+
644
+ const context: SummaryContext = {
645
+ conversationExcerpt: session.goal ?? '',
646
+ errorCount: session.errorCount,
647
+ goal: session.goal,
648
+ recentEvents,
649
+ status: session.status,
650
+ toolCallCount: session.toolCallCount,
651
+ };
652
+
653
+ void (async (): Promise<void> => {
654
+ try {
655
+ const result = await summarizer.summarize(context);
656
+ updateSessionSummary(session.terminalId, result.text);
657
+ } catch (err) {
658
+ console.error(`[dashboard] Summarization failed for ${session.terminalId}:`, err);
659
+ } finally {
660
+ session.isSummarizing = false;
661
+ }
662
+ })();
663
+ }