@juspay/shooter 1.1.0 → 1.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 (330) hide show
  1. package/build/client/_app/immutable/assets/{0.DC5pAwP3.css → 0.BhZOCxO4.css} +1 -1
  2. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.br +0 -0
  3. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.gz +0 -0
  4. package/build/client/_app/immutable/assets/1.BYutk3aU.css +1 -0
  5. package/build/client/_app/immutable/assets/1.BYutk3aU.css.br +0 -0
  6. package/build/client/_app/immutable/assets/1.BYutk3aU.css.gz +0 -0
  7. package/build/client/_app/immutable/assets/{3.BoXp0JoS.css → 3.DGDHCVnW.css} +1 -1
  8. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.br +0 -0
  9. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.gz +0 -0
  10. package/build/client/_app/immutable/assets/4.BFUut--w.css +1 -0
  11. package/build/client/_app/immutable/assets/4.BFUut--w.css.br +0 -0
  12. package/build/client/_app/immutable/assets/4.BFUut--w.css.gz +0 -0
  13. package/build/client/_app/immutable/assets/5.BTOx7yt7.css +1 -0
  14. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.br +0 -0
  15. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.gz +0 -0
  16. package/build/client/_app/immutable/assets/{7.PyEFVv_s.css → 7.DwS5ZHBh.css} +1 -1
  17. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.br +0 -0
  18. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.gz +0 -0
  19. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css +1 -0
  20. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.br +0 -0
  21. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.gz +0 -0
  22. package/build/client/_app/immutable/chunks/B-K5Sh65.js +1 -0
  23. package/build/client/_app/immutable/chunks/B-K5Sh65.js.br +0 -0
  24. package/build/client/_app/immutable/chunks/B-K5Sh65.js.gz +0 -0
  25. package/build/client/_app/immutable/chunks/B5NAKyil.js +20 -0
  26. package/build/client/_app/immutable/chunks/B5NAKyil.js.br +0 -0
  27. package/build/client/_app/immutable/chunks/B5NAKyil.js.gz +0 -0
  28. package/build/client/_app/immutable/chunks/B8XegpSE.js +1 -0
  29. package/build/client/_app/immutable/chunks/B8XegpSE.js.br +0 -0
  30. package/build/client/_app/immutable/chunks/B8XegpSE.js.gz +0 -0
  31. package/build/client/_app/immutable/chunks/{50RPd5u3.js → B8zoBsv3.js} +1 -1
  32. package/build/client/_app/immutable/chunks/B8zoBsv3.js.br +0 -0
  33. package/build/client/_app/immutable/chunks/B8zoBsv3.js.gz +0 -0
  34. package/build/client/_app/immutable/chunks/BLszSzTT.js +1 -0
  35. package/build/client/_app/immutable/chunks/BLszSzTT.js.br +0 -0
  36. package/build/client/_app/immutable/chunks/BLszSzTT.js.gz +0 -0
  37. package/build/client/_app/immutable/chunks/BOYo8yTr.js +1 -0
  38. package/build/client/_app/immutable/chunks/BOYo8yTr.js.br +0 -0
  39. package/build/client/_app/immutable/chunks/BOYo8yTr.js.gz +0 -0
  40. package/build/client/_app/immutable/chunks/{CdL99jkG.js → BYqGCrTe.js} +1 -1
  41. package/build/client/_app/immutable/chunks/BYqGCrTe.js.br +0 -0
  42. package/build/client/_app/immutable/chunks/BYqGCrTe.js.gz +0 -0
  43. package/build/client/_app/immutable/chunks/Bu1aqm5j.js +1 -0
  44. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.br +0 -0
  45. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.gz +0 -0
  46. package/build/client/_app/immutable/chunks/C4mLaWWx.js +1 -0
  47. package/build/client/_app/immutable/chunks/C4mLaWWx.js.br +0 -0
  48. package/build/client/_app/immutable/chunks/C4mLaWWx.js.gz +0 -0
  49. package/build/client/_app/immutable/chunks/{ClK4wZbC.js → CQjSATpv.js} +16 -16
  50. package/build/client/_app/immutable/chunks/CQjSATpv.js.br +0 -0
  51. package/build/client/_app/immutable/chunks/CQjSATpv.js.gz +0 -0
  52. package/build/client/_app/immutable/chunks/{CojFyTPp.js → CSoRdFvv.js} +1 -1
  53. package/build/client/_app/immutable/chunks/CSoRdFvv.js.br +0 -0
  54. package/build/client/_app/immutable/chunks/CSoRdFvv.js.gz +0 -0
  55. package/build/client/_app/immutable/chunks/{tjbnEgXP.js → CZHsSL_X.js} +1 -1
  56. package/build/client/_app/immutable/chunks/CZHsSL_X.js.br +0 -0
  57. package/build/client/_app/immutable/chunks/CZHsSL_X.js.gz +0 -0
  58. package/build/client/_app/immutable/chunks/DVkn4r72.js +1 -0
  59. package/build/client/_app/immutable/chunks/DVkn4r72.js.br +0 -0
  60. package/build/client/_app/immutable/chunks/DVkn4r72.js.gz +0 -0
  61. package/build/client/_app/immutable/chunks/DjsDGxCa.js +41 -0
  62. package/build/client/_app/immutable/chunks/DjsDGxCa.js.br +0 -0
  63. package/build/client/_app/immutable/chunks/DjsDGxCa.js.gz +0 -0
  64. package/build/client/_app/immutable/chunks/UJOiqIYE.js +1 -0
  65. package/build/client/_app/immutable/chunks/UJOiqIYE.js.br +0 -0
  66. package/build/client/_app/immutable/chunks/UJOiqIYE.js.gz +0 -0
  67. package/build/client/_app/immutable/chunks/r0JawsZc.js +2 -0
  68. package/build/client/_app/immutable/chunks/r0JawsZc.js.br +0 -0
  69. package/build/client/_app/immutable/chunks/r0JawsZc.js.gz +0 -0
  70. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js +2 -0
  71. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.br +0 -0
  72. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.gz +0 -0
  73. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js +1 -0
  74. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.br +2 -0
  75. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.gz +0 -0
  76. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js +1 -0
  77. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.br +0 -0
  78. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.gz +0 -0
  79. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js +1 -0
  80. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.br +0 -0
  81. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.gz +0 -0
  82. package/build/client/_app/immutable/nodes/2.CyRB2euU.js +1 -0
  83. package/build/client/_app/immutable/nodes/2.CyRB2euU.js.br +0 -0
  84. package/build/client/_app/immutable/nodes/2.CyRB2euU.js.gz +0 -0
  85. package/build/client/_app/immutable/nodes/3.3yohCM25.js +3 -0
  86. package/build/client/_app/immutable/nodes/3.3yohCM25.js.br +0 -0
  87. package/build/client/_app/immutable/nodes/3.3yohCM25.js.gz +0 -0
  88. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js +1 -0
  89. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.br +0 -0
  90. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.gz +0 -0
  91. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js +4 -0
  92. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.br +0 -0
  93. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.gz +0 -0
  94. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js +2 -0
  95. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.br +0 -0
  96. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.gz +0 -0
  97. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js +2 -0
  98. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.br +0 -0
  99. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.gz +0 -0
  100. package/build/client/_app/version.json +1 -1
  101. package/build/client/_app/version.json.br +0 -0
  102. package/build/client/_app/version.json.gz +0 -0
  103. package/build/client/manifest.json +13 -0
  104. package/build/client/manifest.json.br +0 -0
  105. package/build/client/manifest.json.gz +0 -0
  106. package/build/server/chunks/0-Vk38tI2J.js +9 -0
  107. package/build/server/chunks/0-Vk38tI2J.js.map +1 -0
  108. package/build/server/chunks/1-BvYQX5MR.js +9 -0
  109. package/build/server/chunks/1-BvYQX5MR.js.map +1 -0
  110. package/build/server/chunks/2-Cl7R4Qk2.js +9 -0
  111. package/build/server/chunks/2-Cl7R4Qk2.js.map +1 -0
  112. package/build/server/chunks/3-Ck7ewhOX.js +9 -0
  113. package/build/server/chunks/3-Ck7ewhOX.js.map +1 -0
  114. package/build/server/chunks/4-CnDeRm2Z.js +9 -0
  115. package/build/server/chunks/4-CnDeRm2Z.js.map +1 -0
  116. package/build/server/chunks/5-IxitzEvN.js +9 -0
  117. package/build/server/chunks/{5-D0wB7nfE.js.map → 5-IxitzEvN.js.map} +1 -1
  118. package/build/server/chunks/6-CyZ3r1iS.js +9 -0
  119. package/build/server/chunks/6-CyZ3r1iS.js.map +1 -0
  120. package/build/server/chunks/7-BmI7du46.js +9 -0
  121. package/build/server/chunks/7-BmI7du46.js.map +1 -0
  122. package/build/server/chunks/{Button-C7D5W6wV.js → Button-Cs1aE6ka.js} +2 -2
  123. package/build/server/chunks/{Button-C7D5W6wV.js.map → Button-Cs1aE6ka.js.map} +1 -1
  124. package/build/server/chunks/{EmptyState-Ci4pSpmY.js → EmptyState-DDFH1K8g.js} +10 -4
  125. package/build/server/chunks/EmptyState-DDFH1K8g.js.map +1 -0
  126. package/build/server/chunks/{Icon-DyrkHVnV.js → Icon-CEUrotA6.js} +3 -3
  127. package/build/server/chunks/{Icon-DyrkHVnV.js.map → Icon-CEUrotA6.js.map} +1 -1
  128. package/build/server/chunks/{Shimmer-BITK6wrm.js → Shimmer-DB8W1zt6.js} +2 -2
  129. package/build/server/chunks/{Shimmer-BITK6wrm.js.map → Shimmer-DB8W1zt6.js.map} +1 -1
  130. package/build/server/chunks/_error.svelte-uCOJNxvr.js +39 -0
  131. package/build/server/chunks/_error.svelte-uCOJNxvr.js.map +1 -0
  132. package/build/server/chunks/{_layout.svelte-CO4f8UD7.js → _layout.svelte-CtWmEJwe.js} +5 -25
  133. package/build/server/chunks/_layout.svelte-CtWmEJwe.js.map +1 -0
  134. package/build/server/chunks/{_page.svelte-C6bns9aQ.js → _page.svelte-BcZaKdX9.js} +13 -9
  135. package/build/server/chunks/_page.svelte-BcZaKdX9.js.map +1 -0
  136. package/build/server/chunks/{_page.svelte-3Cc3NMAP.js → _page.svelte-BdYynOck.js} +18 -14
  137. package/build/server/chunks/_page.svelte-BdYynOck.js.map +1 -0
  138. package/build/server/chunks/{_page.svelte-CFCONiDK.js → _page.svelte-BgevQjq1.js} +16 -12
  139. package/build/server/chunks/_page.svelte-BgevQjq1.js.map +1 -0
  140. package/build/server/chunks/{_page.svelte-DskND_G9.js → _page.svelte-CVq6tRb3.js} +8 -8
  141. package/build/server/chunks/_page.svelte-CVq6tRb3.js.map +1 -0
  142. package/build/server/chunks/{_page.svelte-rTrWmhOp.js → _page.svelte-CxWcQ0Am.js} +8 -8
  143. package/build/server/chunks/_page.svelte-CxWcQ0Am.js.map +1 -0
  144. package/build/server/chunks/{_page.svelte-C0p3HsIW.js → _page.svelte-DO4oa_LY.js} +11 -13
  145. package/build/server/chunks/_page.svelte-DO4oa_LY.js.map +1 -0
  146. package/build/server/chunks/{_server.ts-CS5H5klP.js → _server.ts-CAxsWKvS.js} +14 -10
  147. package/build/server/chunks/_server.ts-CAxsWKvS.js.map +1 -0
  148. package/build/server/chunks/{_server.ts-C8slOHB0.js → _server.ts-CTpcLUH8.js} +3 -2
  149. package/build/server/chunks/_server.ts-CTpcLUH8.js.map +1 -0
  150. package/build/server/chunks/_server.ts-CtH0dhUp.js +71 -0
  151. package/build/server/chunks/_server.ts-CtH0dhUp.js.map +1 -0
  152. package/build/server/chunks/{_server.ts-DhTrdlWH.js → _server.ts-DB_Kg97c.js} +14 -3
  153. package/build/server/chunks/_server.ts-DB_Kg97c.js.map +1 -0
  154. package/build/server/chunks/_server.ts-DYpJImqd.js +99 -0
  155. package/build/server/chunks/_server.ts-DYpJImqd.js.map +1 -0
  156. package/build/server/chunks/{_server.ts-DpEVfp8W.js → _server.ts-Deok2y88.js} +58 -40
  157. package/build/server/chunks/_server.ts-Deok2y88.js.map +1 -0
  158. package/build/server/chunks/{_server.ts-uHUi-4cd.js → _server.ts-vekTmWAx.js} +3 -2
  159. package/build/server/chunks/_server.ts-vekTmWAx.js.map +1 -0
  160. package/build/server/chunks/{client2-BjxIYuno.js → client-BdGHe_hY.js} +4 -4
  161. package/build/server/chunks/client-BdGHe_hY.js.map +1 -0
  162. package/build/server/chunks/client2-CCBGA-2V.js +7 -0
  163. package/build/server/chunks/client2-CCBGA-2V.js.map +1 -0
  164. package/build/server/chunks/{index-Cnl871UW.js → index-DwaY1cAm.js} +2 -2
  165. package/build/server/chunks/{index-Cnl871UW.js.map → index-DwaY1cAm.js.map} +1 -1
  166. package/build/server/chunks/{index-server-CUC9Jt7r.js → index-server-CrDaL06Y.js} +2 -2
  167. package/build/server/chunks/{index-server-CUC9Jt7r.js.map → index-server-CrDaL06Y.js.map} +1 -1
  168. package/build/server/chunks/{index2-HA3VTH7y.js → index2-CgclKpUj.js} +2 -2
  169. package/build/server/chunks/{index2-HA3VTH7y.js.map → index2-CgclKpUj.js.map} +1 -1
  170. package/build/server/chunks/opencode-db-path-DcfhJtJy.js +15 -0
  171. package/build/server/chunks/opencode-db-path-DcfhJtJy.js.map +1 -0
  172. package/build/server/chunks/{pty-manager-DR0Wt2Ac.js → pty-manager-BQVB7IVj.js} +17 -15
  173. package/build/server/chunks/pty-manager-BQVB7IVj.js.map +1 -0
  174. package/build/server/chunks/{root-DhswcH6o.js → root-DDSnEAZv.js} +2 -2
  175. package/build/server/chunks/{root-DhswcH6o.js.map → root-DDSnEAZv.js.map} +1 -1
  176. package/build/server/chunks/{state.svelte-2Lellg7t.js → state.svelte-hBbXlUak.js} +3 -3
  177. package/build/server/chunks/{state.svelte-2Lellg7t.js.map → state.svelte-hBbXlUak.js.map} +1 -1
  178. package/build/server/chunks/stores-DHNzYNpX.js +28 -0
  179. package/build/server/chunks/stores-DHNzYNpX.js.map +1 -0
  180. package/build/server/index.js +5 -5
  181. package/build/server/index.js.map +1 -1
  182. package/build/server/manifest.js +30 -16
  183. package/build/server/manifest.js.map +1 -1
  184. package/package.json +1 -1
  185. package/scripts/setup.cjs +87 -13
  186. package/server.ts +3 -0
  187. package/src/app.html +3 -0
  188. package/src/lib/modules/client/common/cache.ts +10 -2
  189. package/src/lib/modules/client/common/index.ts +1 -1
  190. package/src/lib/modules/client/common/markdown.ts +22 -1
  191. package/src/lib/modules/client/common/time.ts +13 -11
  192. package/src/lib/modules/client/terminal/ChatView.svelte +324 -67
  193. package/src/lib/modules/client/terminal/ConnectionStatus.svelte +1 -0
  194. package/src/lib/modules/client/terminal/xterm-wrapper.ts +4 -1
  195. package/src/lib/modules/server/sessions/jsonl-reader.ts +43 -28
  196. package/src/lib/modules/server/sessions/opencode-db-path.ts +26 -0
  197. package/src/lib/modules/server/sessions/opencode-reader.ts +13 -15
  198. package/src/lib/modules/server/sessions/process-detector.ts +103 -0
  199. package/src/lib/modules/server/terminal/opencode-watcher.ts +3 -14
  200. package/src/lib/modules/server/terminal/pty-manager.ts +20 -8
  201. package/src/lib/modules/server/ws/session-handler.ts +282 -104
  202. package/src/lib/theme.css +30 -0
  203. package/src/routes/+error.svelte +94 -0
  204. package/src/routes/+page.svelte +18 -8
  205. package/src/routes/api/health/+server.ts +14 -2
  206. package/src/routes/api/sessions/+server.ts +12 -4
  207. package/src/routes/api/sessions/connect/+server.ts +125 -0
  208. package/src/routes/api/sessions/detect/+server.ts +27 -0
  209. package/src/routes/api/terminals/+server.ts +12 -9
  210. package/src/routes/config/+page.svelte +22 -1
  211. package/src/routes/project/+page.svelte +159 -8
  212. package/src/routes/session/[id]/+page.svelte +477 -299
  213. package/src/routes/terminals/+page.svelte +14 -3
  214. package/src/routes/terminals/[id]/+page.svelte +25 -0
  215. package/build/client/_app/immutable/assets/0.DC5pAwP3.css.br +0 -0
  216. package/build/client/_app/immutable/assets/0.DC5pAwP3.css.gz +0 -0
  217. package/build/client/_app/immutable/assets/3.BoXp0JoS.css.br +0 -0
  218. package/build/client/_app/immutable/assets/3.BoXp0JoS.css.gz +0 -0
  219. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +0 -1
  220. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
  221. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
  222. package/build/client/_app/immutable/assets/5.DRjApZQW.css +0 -1
  223. package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
  224. package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
  225. package/build/client/_app/immutable/assets/7.PyEFVv_s.css.br +0 -0
  226. package/build/client/_app/immutable/assets/7.PyEFVv_s.css.gz +0 -0
  227. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +0 -1
  228. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
  229. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
  230. package/build/client/_app/immutable/chunks/50RPd5u3.js.br +0 -0
  231. package/build/client/_app/immutable/chunks/50RPd5u3.js.gz +0 -0
  232. package/build/client/_app/immutable/chunks/BDC7XD4o.js +0 -1
  233. package/build/client/_app/immutable/chunks/BDC7XD4o.js.br +0 -0
  234. package/build/client/_app/immutable/chunks/BDC7XD4o.js.gz +0 -0
  235. package/build/client/_app/immutable/chunks/BeONA6_G.js +0 -2
  236. package/build/client/_app/immutable/chunks/BeONA6_G.js.br +0 -0
  237. package/build/client/_app/immutable/chunks/BeONA6_G.js.gz +0 -0
  238. package/build/client/_app/immutable/chunks/BygiiMA0.js +0 -1
  239. package/build/client/_app/immutable/chunks/BygiiMA0.js.br +0 -0
  240. package/build/client/_app/immutable/chunks/BygiiMA0.js.gz +0 -0
  241. package/build/client/_app/immutable/chunks/CGLrx-H5.js +0 -1
  242. package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
  243. package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
  244. package/build/client/_app/immutable/chunks/CHvUpVYv.js +0 -1
  245. package/build/client/_app/immutable/chunks/CHvUpVYv.js.br +0 -0
  246. package/build/client/_app/immutable/chunks/CHvUpVYv.js.gz +0 -0
  247. package/build/client/_app/immutable/chunks/CbqC9BW7.js +0 -1
  248. package/build/client/_app/immutable/chunks/CbqC9BW7.js.br +0 -2
  249. package/build/client/_app/immutable/chunks/CbqC9BW7.js.gz +0 -0
  250. package/build/client/_app/immutable/chunks/CdL99jkG.js.br +0 -0
  251. package/build/client/_app/immutable/chunks/CdL99jkG.js.gz +0 -0
  252. package/build/client/_app/immutable/chunks/ClK4wZbC.js.br +0 -0
  253. package/build/client/_app/immutable/chunks/ClK4wZbC.js.gz +0 -0
  254. package/build/client/_app/immutable/chunks/CojFyTPp.js.br +0 -0
  255. package/build/client/_app/immutable/chunks/CojFyTPp.js.gz +0 -0
  256. package/build/client/_app/immutable/chunks/DREFAyhX.js +0 -60
  257. package/build/client/_app/immutable/chunks/DREFAyhX.js.br +0 -0
  258. package/build/client/_app/immutable/chunks/DREFAyhX.js.gz +0 -0
  259. package/build/client/_app/immutable/chunks/K_aHH2KN.js +0 -1
  260. package/build/client/_app/immutable/chunks/K_aHH2KN.js.br +0 -0
  261. package/build/client/_app/immutable/chunks/K_aHH2KN.js.gz +0 -0
  262. package/build/client/_app/immutable/chunks/Ona8oofC.js +0 -1
  263. package/build/client/_app/immutable/chunks/Ona8oofC.js.br +0 -0
  264. package/build/client/_app/immutable/chunks/Ona8oofC.js.gz +0 -0
  265. package/build/client/_app/immutable/chunks/tjbnEgXP.js.br +0 -0
  266. package/build/client/_app/immutable/chunks/tjbnEgXP.js.gz +0 -0
  267. package/build/client/_app/immutable/entry/app.anqwe7ZL.js +0 -2
  268. package/build/client/_app/immutable/entry/app.anqwe7ZL.js.br +0 -0
  269. package/build/client/_app/immutable/entry/app.anqwe7ZL.js.gz +0 -0
  270. package/build/client/_app/immutable/entry/start.BV2VRv6h.js +0 -1
  271. package/build/client/_app/immutable/entry/start.BV2VRv6h.js.br +0 -2
  272. package/build/client/_app/immutable/entry/start.BV2VRv6h.js.gz +0 -0
  273. package/build/client/_app/immutable/nodes/0.D0i5MqcI.js +0 -1
  274. package/build/client/_app/immutable/nodes/0.D0i5MqcI.js.br +0 -0
  275. package/build/client/_app/immutable/nodes/0.D0i5MqcI.js.gz +0 -0
  276. package/build/client/_app/immutable/nodes/1.DN5n5c6F.js +0 -1
  277. package/build/client/_app/immutable/nodes/1.DN5n5c6F.js.br +0 -0
  278. package/build/client/_app/immutable/nodes/1.DN5n5c6F.js.gz +0 -0
  279. package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js +0 -1
  280. package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js.br +0 -0
  281. package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js.gz +0 -0
  282. package/build/client/_app/immutable/nodes/3.CEkigHDv.js +0 -3
  283. package/build/client/_app/immutable/nodes/3.CEkigHDv.js.br +0 -0
  284. package/build/client/_app/immutable/nodes/3.CEkigHDv.js.gz +0 -0
  285. package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js +0 -1
  286. package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js.br +0 -0
  287. package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js.gz +0 -0
  288. package/build/client/_app/immutable/nodes/5.shitbtHc.js +0 -1
  289. package/build/client/_app/immutable/nodes/5.shitbtHc.js.br +0 -0
  290. package/build/client/_app/immutable/nodes/5.shitbtHc.js.gz +0 -0
  291. package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js +0 -2
  292. package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js.br +0 -0
  293. package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js.gz +0 -0
  294. package/build/client/_app/immutable/nodes/7.D0CrR6pl.js +0 -2
  295. package/build/client/_app/immutable/nodes/7.D0CrR6pl.js.br +0 -0
  296. package/build/client/_app/immutable/nodes/7.D0CrR6pl.js.gz +0 -0
  297. package/build/server/chunks/0-Cs1dzfRz.js +0 -9
  298. package/build/server/chunks/0-Cs1dzfRz.js.map +0 -1
  299. package/build/server/chunks/1-BCSX7oED.js +0 -9
  300. package/build/server/chunks/1-BCSX7oED.js.map +0 -1
  301. package/build/server/chunks/2-6gkeO8b4.js +0 -9
  302. package/build/server/chunks/2-6gkeO8b4.js.map +0 -1
  303. package/build/server/chunks/3-DH9J9Vsc.js +0 -9
  304. package/build/server/chunks/3-DH9J9Vsc.js.map +0 -1
  305. package/build/server/chunks/4-Rzy5TYjl.js +0 -9
  306. package/build/server/chunks/4-Rzy5TYjl.js.map +0 -1
  307. package/build/server/chunks/5-D0wB7nfE.js +0 -9
  308. package/build/server/chunks/6-DR2ABDPq.js +0 -9
  309. package/build/server/chunks/6-DR2ABDPq.js.map +0 -1
  310. package/build/server/chunks/7-D-oQJsia.js +0 -9
  311. package/build/server/chunks/7-D-oQJsia.js.map +0 -1
  312. package/build/server/chunks/EmptyState-Ci4pSpmY.js.map +0 -1
  313. package/build/server/chunks/_layout.svelte-CO4f8UD7.js.map +0 -1
  314. package/build/server/chunks/_page.svelte-3Cc3NMAP.js.map +0 -1
  315. package/build/server/chunks/_page.svelte-C0p3HsIW.js.map +0 -1
  316. package/build/server/chunks/_page.svelte-C6bns9aQ.js.map +0 -1
  317. package/build/server/chunks/_page.svelte-CFCONiDK.js.map +0 -1
  318. package/build/server/chunks/_page.svelte-DskND_G9.js.map +0 -1
  319. package/build/server/chunks/_page.svelte-rTrWmhOp.js.map +0 -1
  320. package/build/server/chunks/_server.ts-C8slOHB0.js.map +0 -1
  321. package/build/server/chunks/_server.ts-CS5H5klP.js.map +0 -1
  322. package/build/server/chunks/_server.ts-DhTrdlWH.js.map +0 -1
  323. package/build/server/chunks/_server.ts-DpEVfp8W.js.map +0 -1
  324. package/build/server/chunks/_server.ts-uHUi-4cd.js.map +0 -1
  325. package/build/server/chunks/client-BYT9c0ig.js +0 -7
  326. package/build/server/chunks/client-BYT9c0ig.js.map +0 -1
  327. package/build/server/chunks/client2-BjxIYuno.js.map +0 -1
  328. package/build/server/chunks/error.svelte-BG_yE-Wt.js +0 -27
  329. package/build/server/chunks/error.svelte-BG_yE-Wt.js.map +0 -1
  330. package/build/server/chunks/pty-manager-DR0Wt2Ac.js.map +0 -1
@@ -5,6 +5,7 @@
5
5
  ToolUsePart,
6
6
  } from '$lib/modules/server/sessions/types';
7
7
 
8
+ import { browser } from '$app/environment';
8
9
  import { getToolDescription, renderMarkdown } from '$lib/modules/client/common';
9
10
  import { Accordion, Avatar, Button, Input, Pill } from '@juspay/svelte-ui-components';
10
11
  import { tick } from 'svelte';
@@ -14,27 +15,110 @@
14
15
  const {
15
16
  connectionState = 'idle',
16
17
  messages,
18
+ newestFirst = false,
17
19
  onCancel,
18
20
  onSendInput,
21
+ sendDisabled,
19
22
  sessionEnded = false,
20
23
  showHeader = false,
21
24
  showInput = true,
22
25
  }: {
23
26
  connectionState?: 'connected' | 'connecting' | 'disconnected' | 'idle' | 'reconnecting';
24
27
  messages: ConversationMessage[];
28
+ newestFirst?: boolean;
25
29
  onCancel?: () => void;
26
30
  onSendInput?: (text: string) => void;
31
+ sendDisabled?: boolean;
27
32
  sessionEnded?: boolean;
28
33
  showHeader?: boolean;
29
34
  showInput?: boolean;
30
35
  } = $props();
31
36
 
37
+ // When sendDisabled is explicitly provided, it overrides the connectionState check.
38
+ // Otherwise fall back to the existing behaviour (disabled when not connected).
39
+ const isInputDisabled = $derived(
40
+ sessionEnded ||
41
+ (sendDisabled !== undefined ? sendDisabled : connectionState !== 'connected')
42
+ );
43
+
32
44
  // --- Local state ---
33
45
  let inputText = $state('');
34
46
  let chatContainerEl = $state<HTMLElement | null>(null);
35
47
  let shouldAutoScroll = $state(true);
36
48
 
37
49
  const expandedTools = new SvelteSet<string>();
50
+ const expandedGroups = new SvelteSet<string>();
51
+
52
+ // --- Show Details toggle (persisted in localStorage) ---
53
+ const SHOW_DETAILS_KEY = 'shooter:chatview:showDetails';
54
+ let showDetails = $state(
55
+ browser ? localStorage.getItem(SHOW_DETAILS_KEY) === 'true' : false,
56
+ );
57
+
58
+ function toggleShowDetails(): void {
59
+ showDetails = !showDetails;
60
+ if (browser) {
61
+ localStorage.setItem(SHOW_DETAILS_KEY, String(showDetails));
62
+ }
63
+ }
64
+
65
+ // --- Tool grouping ---
66
+ interface ToolGroup {
67
+ groupId: string;
68
+ summary: string;
69
+ tools: ToolUsePart[];
70
+ type: 'tool_group';
71
+ }
72
+
73
+ type GroupedPart = MessagePart | ToolGroup;
74
+
75
+ function groupMessageParts(parts: MessagePart[], messageId: string): GroupedPart[] {
76
+ const result: GroupedPart[] = [];
77
+ let currentToolGroup: ToolUsePart[] = [];
78
+ let groupIndex = 0;
79
+
80
+ function flushToolGroup(): void {
81
+ if (currentToolGroup.length === 0) {return;}
82
+
83
+ if (currentToolGroup.length === 1) {
84
+ // Single tool -- render as normal tool card, no group wrapper
85
+ result.push(currentToolGroup[0]);
86
+ } else {
87
+ const toolNames = currentToolGroup.map((t) => t.toolName);
88
+ // Deduplicate tool names while preserving order
89
+ const uniqueNames = [...new Set(toolNames)];
90
+ const summary = `Used ${currentToolGroup.length} tools: ${uniqueNames.join(', ')}`;
91
+ result.push({
92
+ groupId: `toolgroup-${messageId}-${groupIndex}`,
93
+ summary,
94
+ tools: currentToolGroup,
95
+ type: 'tool_group',
96
+ });
97
+ groupIndex++;
98
+ }
99
+ currentToolGroup = [];
100
+ }
101
+
102
+ for (const part of parts) {
103
+ if (part.type === 'tool_use') {
104
+ currentToolGroup.push(part);
105
+ } else {
106
+ flushToolGroup();
107
+ result.push(part);
108
+ }
109
+ }
110
+ flushToolGroup();
111
+
112
+ return result;
113
+ }
114
+
115
+ function isToolGroup(part: GroupedPart): part is ToolGroup {
116
+ return (part as ToolGroup).type === 'tool_group';
117
+ }
118
+
119
+ function hasOnlyToolResults(message: ConversationMessage): boolean {
120
+ return message.parts.every((p) => p.type === 'tool_result');
121
+ }
38
122
 
39
123
  // --- Auto-scroll ---
40
124
  // Re-scroll whenever the messages array identity changes
@@ -49,7 +133,11 @@
49
133
  return;
50
134
  }
51
135
  await tick();
52
- chatContainerEl.scrollTop = chatContainerEl.scrollHeight;
136
+ if (newestFirst) {
137
+ chatContainerEl.scrollTop = 0;
138
+ } else {
139
+ chatContainerEl.scrollTop = chatContainerEl.scrollHeight;
140
+ }
53
141
  }
54
142
 
55
143
  function handleScroll(): void {
@@ -57,7 +145,11 @@
57
145
  return;
58
146
  }
59
147
  const { clientHeight, scrollHeight, scrollTop } = chatContainerEl;
60
- shouldAutoScroll = scrollHeight - scrollTop - clientHeight < 100;
148
+ if (newestFirst) {
149
+ shouldAutoScroll = scrollTop < 100;
150
+ } else {
151
+ shouldAutoScroll = scrollHeight - scrollTop - clientHeight < 100;
152
+ }
61
153
  }
62
154
 
63
155
  // --- Input handling ---
@@ -86,6 +178,14 @@
86
178
  }
87
179
  }
88
180
 
181
+ function toggleGroup(id: string): void {
182
+ if (expandedGroups.has(id)) {
183
+ expandedGroups.delete(id);
184
+ } else {
185
+ expandedGroups.add(id);
186
+ }
187
+ }
188
+
89
189
  function formatTime(ts: string): string {
90
190
  return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
91
191
  }
@@ -140,6 +240,19 @@
140
240
  <p class="chatview-empty-text">Waiting for session messages...</p>
141
241
  </div>
142
242
  {:else}
243
+ <!-- Show details toggle -->
244
+ <div class="chatview-details-toggle">
245
+ <button
246
+ class="chatview-details-btn"
247
+ class:active={showDetails}
248
+ onclick={toggleShowDetails}
249
+ type="button"
250
+ >
251
+ <span class="chatview-details-icon">{showDetails ? '&#9660;' : '&#9654;'}</span>
252
+ {showDetails ? 'Hide details' : 'Show details'}
253
+ </button>
254
+ </div>
255
+
143
256
  {#each messages as message (message.id)}
144
257
  {#if message.role === 'user'}
145
258
  <div class="chat-message chat-message-user">
@@ -160,21 +273,71 @@
160
273
  <div class="chat-message chat-message-assistant">
161
274
  <Avatar alt="Claude" name="Claude" size="small" classes="avatar-assistant" />
162
275
  <div>
163
- {#each message.parts as part, partIdx (partIdx)}
164
- {#if part.type === 'text'}
276
+ {#each groupMessageParts(message.parts, message.id) as gpart, partIdx (partIdx)}
277
+ {#if isToolGroup(gpart)}
278
+ <!-- Collapsed tool group summary -->
279
+ {@const groupExpanded = showDetails || expandedGroups.has(gpart.groupId)}
280
+ <div class="chat-tool-group">
281
+ <div
282
+ class="chat-tool-group-header"
283
+ onclick={() => { toggleGroup(gpart.groupId); }}
284
+ onkeydown={(e) => {
285
+ if (e.key === 'Enter' || e.key === ' ') {
286
+ e.preventDefault();
287
+ toggleGroup(gpart.groupId);
288
+ }
289
+ }}
290
+ role="button"
291
+ tabindex="0"
292
+ >
293
+ <span class="chat-tool-group-chevron" class:expanded={groupExpanded}>&#9654;</span>
294
+ <span class="chat-tool-group-summary">{gpart.summary}</span>
295
+ </div>
296
+ {#if groupExpanded}
297
+ <div class="chat-tool-group-body">
298
+ {#each gpart.tools as tool (tool.id)}
299
+ {@const toolId = tool.id}
300
+ {@const isExpanded = showDetails || expandedTools.has(toolId)}
301
+ <div class="chat-tool-card">
302
+ <div
303
+ class="chat-tool-header"
304
+ onclick={() => { toggleTool(toolId); }}
305
+ onkeydown={(e) => {
306
+ if (e.key === 'Enter' || e.key === ' ') {
307
+ e.preventDefault();
308
+ toggleTool(toolId);
309
+ }
310
+ }}
311
+ role="button"
312
+ tabindex="0"
313
+ >
314
+ <span class="chat-tool-chevron" class:expanded={isExpanded}>&#9654;</span>
315
+ <Pill text={tool.toolName} classes="pill-tool-name" />
316
+ <span class="chat-tool-description">{getToolDescriptionFromPart(tool)}</span>
317
+ </div>
318
+ <Accordion expand={isExpanded}>
319
+ {#if isExpanded}
320
+ <div class="chat-tool-body">{formatInput(tool.input)}</div>
321
+ {/if}
322
+ </Accordion>
323
+ </div>
324
+ {/each}
325
+ </div>
326
+ {/if}
327
+ </div>
328
+ {:else if gpart.type === 'text'}
165
329
  <div class="chat-bubble chat-bubble-assistant">
166
330
  <!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitized markdown -->
167
- {@html renderMarkdown(part.content)}
331
+ {@html renderMarkdown(gpart.content)}
168
332
  </div>
169
- {:else if isToolUsePart(part)}
170
- {@const toolId = part.id}
171
- {@const isExpanded = expandedTools.has(toolId)}
333
+ {:else if isToolUsePart(gpart)}
334
+ <!-- Single tool (not grouped) -->
335
+ {@const toolId = gpart.id}
336
+ {@const isExpanded = showDetails || expandedTools.has(toolId)}
172
337
  <div class="chat-tool-card">
173
338
  <div
174
339
  class="chat-tool-header"
175
- onclick={() => {
176
- toggleTool(toolId);
177
- }}
340
+ onclick={() => { toggleTool(toolId); }}
178
341
  onkeydown={(e) => {
179
342
  if (e.key === 'Enter' || e.key === ' ') {
180
343
  e.preventDefault();
@@ -185,24 +348,22 @@
185
348
  tabindex="0"
186
349
  >
187
350
  <span class="chat-tool-chevron" class:expanded={isExpanded}>&#9654;</span>
188
- <Pill text={part.toolName} classes="pill-tool-name" />
189
- <span class="chat-tool-description">{getToolDescriptionFromPart(part)}</span>
351
+ <Pill text={gpart.toolName} classes="pill-tool-name" />
352
+ <span class="chat-tool-description">{getToolDescriptionFromPart(gpart)}</span>
190
353
  </div>
191
354
  <Accordion expand={isExpanded}>
192
355
  {#if isExpanded}
193
- <div class="chat-tool-body">{formatInput(part.input)}</div>
356
+ <div class="chat-tool-body">{formatInput(gpart.input)}</div>
194
357
  {/if}
195
358
  </Accordion>
196
359
  </div>
197
- {:else if part.type === 'thinking'}
360
+ {:else if gpart.type === 'thinking'}
198
361
  {@const thinkId = `thinking-${message.id}`}
199
- {@const isThinkExpanded = expandedTools.has(thinkId)}
362
+ {@const isThinkExpanded = showDetails || expandedTools.has(thinkId)}
200
363
  <div class="chat-thinking">
201
364
  <div
202
365
  class="chat-thinking-header"
203
- onclick={() => {
204
- toggleTool(thinkId);
205
- }}
366
+ onclick={() => { toggleTool(thinkId); }}
206
367
  onkeydown={(e) => {
207
368
  if (e.key === 'Enter' || e.key === ' ') {
208
369
  e.preventDefault();
@@ -217,7 +378,7 @@
217
378
  <Accordion expand={isThinkExpanded}>
218
379
  {#if isThinkExpanded}
219
380
  <!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitized markdown -->
220
- <div class="chat-thinking-body">{@html renderMarkdown(part.content)}</div>
381
+ <div class="chat-thinking-body">{@html renderMarkdown(gpart.content)}</div>
221
382
  {/if}
222
383
  </Accordion>
223
384
  </div>
@@ -227,55 +388,58 @@
227
388
  </div>
228
389
  </div>
229
390
  {:else if message.role === 'system'}
230
- {#each message.parts as part, partIdx (partIdx)}
231
- {#if part.type === 'tool_result'}
232
- {@const resultId = `result-${part.toolUseId}`}
233
- {@const isResultExpanded = expandedTools.has(resultId)}
234
- <div class="chat-message chat-message-system">
235
- <div class="chat-tool-card">
236
- <div
237
- class="chat-tool-header"
238
- onclick={() => {
239
- toggleTool(resultId);
240
- }}
241
- onkeydown={(e) => {
242
- if (e.key === 'Enter' || e.key === ' ') {
243
- e.preventDefault();
244
- toggleTool(resultId);
245
- }
246
- }}
247
- role="button"
248
- tabindex="0"
249
- >
250
- <span class="chat-tool-chevron" class:expanded={isResultExpanded}>&#9654;</span>
251
- <Pill
252
- text={part.isError ? '\u274C Tool Error' : '\u2705 Tool Result'}
253
- classes={part.isError ? 'pill-tool-error' : 'pill-tool-success'}
254
- />
255
- </div>
256
- <Accordion expand={isResultExpanded}>
257
- {#if isResultExpanded}
391
+ <!-- Hide system messages with only tool_result when details are off -->
392
+ {#if showDetails || !hasOnlyToolResults(message)}
393
+ {#each message.parts as part, partIdx (partIdx)}
394
+ {#if part.type === 'tool_result'}
395
+ {#if showDetails}
396
+ {@const resultId = `result-${part.toolUseId}`}
397
+ {@const isResultExpanded = expandedTools.has(resultId)}
398
+ <div class="chat-message chat-message-system">
399
+ <div class="chat-tool-card">
258
400
  <div
259
- class="chat-tool-result"
260
- class:chat-tool-result-success={!part.isError}
261
- class:chat-tool-result-error={part.isError}
401
+ class="chat-tool-header"
402
+ onclick={() => { toggleTool(resultId); }}
403
+ onkeydown={(e) => {
404
+ if (e.key === 'Enter' || e.key === ' ') {
405
+ e.preventDefault();
406
+ toggleTool(resultId);
407
+ }
408
+ }}
409
+ role="button"
410
+ tabindex="0"
262
411
  >
263
- {part.output}
412
+ <span class="chat-tool-chevron" class:expanded={isResultExpanded}>&#9654;</span>
413
+ <Pill
414
+ text={part.isError ? '\u274C Tool Error' : '\u2705 Tool Result'}
415
+ classes={part.isError ? 'pill-tool-error' : 'pill-tool-success'}
416
+ />
264
417
  </div>
265
- {/if}
266
- </Accordion>
267
- </div>
268
- </div>
269
- {:else if part.type === 'text'}
270
- <!-- System text messages (e.g. error messages displayed inline) -->
271
- <div class="chat-message chat-message-system">
272
- <div class="chat-bubble chat-bubble-system">
273
- <!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitized markdown -->
274
- {@html renderMarkdown(part.content)}
418
+ <Accordion expand={isResultExpanded}>
419
+ {#if isResultExpanded}
420
+ <div
421
+ class="chat-tool-result"
422
+ class:chat-tool-result-success={!part.isError}
423
+ class:chat-tool-result-error={part.isError}
424
+ >
425
+ {part.output}
426
+ </div>
427
+ {/if}
428
+ </Accordion>
429
+ </div>
430
+ </div>
431
+ {/if}
432
+ {:else if part.type === 'text'}
433
+ <!-- System text messages (e.g. error messages displayed inline) -->
434
+ <div class="chat-message chat-message-system">
435
+ <div class="chat-bubble chat-bubble-system">
436
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitized markdown -->
437
+ {@html renderMarkdown(part.content)}
438
+ </div>
275
439
  </div>
276
- </div>
277
- {/if}
278
- {/each}
440
+ {/if}
441
+ {/each}
442
+ {/if}
279
443
  {/if}
280
444
  {/each}
281
445
 
@@ -297,13 +461,13 @@
297
461
  dataType="text"
298
462
  useTextArea={true}
299
463
  placeholder={sessionEnded ? 'Session ended' : 'Send a message... (Shift+Enter for new line)'}
300
- disable={sessionEnded || connectionState !== 'connected'}
464
+ disable={isInputDisabled}
301
465
  onKeyDown={handleKeydown}
302
466
  classes="chat-input-field"
303
467
  />
304
468
  <Button
305
469
  classes="btn-primary btn-sm"
306
- disabled={sessionEnded || connectionState !== 'connected' || !inputText.trim()}
470
+ disabled={isInputDisabled || !inputText.trim()}
307
471
  onclick={handleSend}
308
472
  text="Send"
309
473
  />
@@ -398,6 +562,99 @@
398
562
  color: var(--text-tertiary, #7d7d7d);
399
563
  }
400
564
 
565
+ /* Show details toggle */
566
+ .chatview-details-toggle {
567
+ display: flex;
568
+ justify-content: flex-end;
569
+ padding: 0 0 var(--space-2, 0.5rem) 0;
570
+ position: sticky;
571
+ top: 0;
572
+ z-index: 5;
573
+ }
574
+
575
+ .chatview-details-btn {
576
+ display: inline-flex;
577
+ align-items: center;
578
+ gap: var(--space-1, 0.25rem);
579
+ padding: 4px 10px;
580
+ border: 1px solid var(--border, #2a2a2a);
581
+ border-radius: var(--radius-sm, 4px);
582
+ background: var(--bg-secondary, #141414);
583
+ color: var(--text-tertiary, #7d7d7d);
584
+ font-size: 0.7rem;
585
+ cursor: pointer;
586
+ user-select: none;
587
+ transition:
588
+ color var(--transition-fast, 150ms),
589
+ border-color var(--transition-fast, 150ms);
590
+ }
591
+
592
+ .chatview-details-btn:hover {
593
+ color: var(--text-secondary, #a3a3a3);
594
+ border-color: var(--text-tertiary, #7d7d7d);
595
+ }
596
+
597
+ .chatview-details-btn.active {
598
+ color: var(--text-secondary, #a3a3a3);
599
+ border-color: var(--text-tertiary, #7d7d7d);
600
+ }
601
+
602
+ .chatview-details-icon {
603
+ font-size: 0.55rem;
604
+ line-height: 1;
605
+ }
606
+
607
+ /* Tool group (collapsed N tools) */
608
+ .chat-tool-group {
609
+ background: var(--bg-secondary, #141414);
610
+ border: 1px solid var(--border, #2a2a2a);
611
+ border-radius: var(--radius-md, 8px);
612
+ overflow: hidden;
613
+ margin: var(--space-2, 0.5rem) 0;
614
+ max-width: 90%;
615
+ align-self: flex-start;
616
+ }
617
+
618
+ .chat-tool-group-header {
619
+ display: flex;
620
+ align-items: center;
621
+ gap: var(--space-2, 0.5rem);
622
+ padding: var(--space-2, 0.5rem) var(--space-3, 0.75rem);
623
+ cursor: pointer;
624
+ user-select: none;
625
+ transition: background var(--transition-fast, 150ms);
626
+ }
627
+
628
+ .chat-tool-group-header:hover {
629
+ background: rgba(255, 255, 255, 0.03);
630
+ }
631
+
632
+ .chat-tool-group-chevron {
633
+ font-size: 0.7rem;
634
+ color: var(--text-tertiary, #737373);
635
+ transition: transform 0.2s ease;
636
+ }
637
+
638
+ .chat-tool-group-chevron.expanded {
639
+ transform: rotate(90deg);
640
+ }
641
+
642
+ .chat-tool-group-summary {
643
+ font-size: 0.8rem;
644
+ color: var(--text-tertiary, #737373);
645
+ font-weight: 500;
646
+ }
647
+
648
+ .chat-tool-group-body {
649
+ border-top: 1px solid var(--border, #2a2a2a);
650
+ padding: var(--space-2, 0.5rem);
651
+ }
652
+
653
+ .chat-tool-group-body .chat-tool-card {
654
+ margin: var(--space-1, 0.25rem) 0;
655
+ max-width: 100%;
656
+ }
657
+
401
658
  /* Mobile responsive */
402
659
  @media (max-width: 768px) {
403
660
  .chatview-header {
@@ -22,6 +22,7 @@
22
22
  class:reconnecting={status === 'reconnecting'}
23
23
  class:disconnected={status === 'disconnected'}
24
24
  class:connected={status === 'connected'}
25
+ aria-label="Connection: {status}"
25
26
  >
26
27
  <span class="status-dot {status}"></span>
27
28
  <span class="status-label">{label}</span>
@@ -230,8 +230,11 @@ export async function createTerminal(options: TerminalOptions): Promise<Terminal
230
230
  }
231
231
  });
232
232
 
233
- // Handle resize
233
+ // Handle resize — skip when container is hidden (display:none → size 0)
234
234
  const resizeObserver = new ResizeObserver(() => {
235
+ if (!options.container.offsetWidth || !options.container.offsetHeight) {
236
+ return;
237
+ }
235
238
  fitAddon.fit();
236
239
  if (ws?.readyState === WebSocket.OPEN) {
237
240
  ws.send(JSON.stringify({ cols: term.cols, rows: term.rows, type: 'resize' }));
@@ -44,6 +44,15 @@ export function getSessionConversation(
44
44
  }
45
45
  }
46
46
 
47
+ // If no explicit offset, return the LAST `limit` messages (most recent conversation)
48
+ if (offset === 0 && messages.length > limit) {
49
+ let startIdx = messages.length - limit;
50
+ // Adjust to start at a 'user' message boundary so we don't clip mid-turn
51
+ while (startIdx > 0 && startIdx < messages.length && messages[startIdx].role !== 'user') {
52
+ startIdx--;
53
+ }
54
+ return messages.slice(startIdx);
55
+ }
47
56
  return messages.slice(offset, offset + limit);
48
57
  } catch (error) {
49
58
  console.error('[sessions] Failed to parse session JSONL:', error);
@@ -218,22 +227,20 @@ function listSessionsForProject(projectDir: string): SessionInfo[] {
218
227
  let messageCount = 0;
219
228
  try {
220
229
  const content = fs.readFileSync(filePath, 'utf-8');
221
- // Count user + assistant messages for the message count
222
- const lines = content.split('\n');
223
- for (const line of lines) {
224
- if (!line.trim()) {
225
- continue;
226
- }
227
- try {
228
- const entry = JSON.parse(line);
229
- if (entry.type === 'user' || entry.type === 'assistant') {
230
- messageCount++;
231
- }
232
- } catch {
233
- // skip malformed lines
234
- }
230
+ // Count user + assistant messages by searching each line for the type field.
231
+ // The type field may appear anywhere on the line (after parentUuid, isSidechain, etc.)
232
+ // so a prefix-only check is not reliable with the current JSONL format.
233
+ let countPos = 0;
234
+ while (countPos < content.length) {
235
+ const nl = content.indexOf('\n', countPos);
236
+ const lineEnd = nl === -1 ? content.length : nl;
237
+ const line = content.substring(countPos, lineEnd);
238
+ if (line.includes('"type":"user"') || line.includes('"type":"assistant"')) {messageCount++;}
239
+ if (nl === -1) {break;}
240
+ countPos = nl + 1;
235
241
  }
236
242
  // Find the first real user message (skip system caveats, commands, tool results)
243
+ const lines = content.split('\n');
237
244
  for (const line of lines) {
238
245
  if (!line.trim()) {
239
246
  continue;
@@ -320,23 +327,31 @@ function listSessionsForProject(projectDir: string): SessionInfo[] {
320
327
  function readCwdFromProjectDir(projectDir: string, sessions: SessionInfo[]): string {
321
328
  for (const session of sessions) {
322
329
  try {
323
- const jsonlPath = path.join(projectDir, `${session.id}.jsonl`);
324
- if (!fs.existsSync(jsonlPath)) {
330
+ const filePath = path.join(projectDir, `${session.id}.jsonl`);
331
+ if (!fs.existsSync(filePath)) {
325
332
  continue;
326
333
  }
327
- const content = fs.readFileSync(jsonlPath, 'utf-8');
328
- for (const line of content.split('\n')) {
329
- if (!line.trim()) {
330
- continue;
331
- }
332
- try {
333
- const entry = JSON.parse(line) as Record<string, unknown>;
334
- if (typeof entry.cwd === 'string' && entry.cwd) {
335
- return entry.cwd;
336
- }
337
- } catch {
338
- // skip malformed lines
334
+ // Only read the first 4KB — cwd appears on line 1
335
+ const fd = fs.openSync(filePath, 'r');
336
+ let firstChunk: string;
337
+ try {
338
+ const buf = Buffer.alloc(4096);
339
+ const bytesRead = fs.readSync(fd, buf, 0, 4096, 0);
340
+ firstChunk = buf.toString('utf-8', 0, bytesRead);
341
+ } finally {
342
+ fs.closeSync(fd);
343
+ }
344
+ const firstLine = firstChunk.split('\n')[0];
345
+ if (!firstLine.trim()) {
346
+ continue;
347
+ }
348
+ try {
349
+ const entry = JSON.parse(firstLine) as Record<string, unknown>;
350
+ if (typeof entry.cwd === 'string' && entry.cwd) {
351
+ return entry.cwd;
339
352
  }
353
+ } catch {
354
+ // skip malformed first line
340
355
  }
341
356
  } catch {
342
357
  // skip unreadable files
@@ -0,0 +1,26 @@
1
+ import * as path from 'path';
2
+
3
+ /**
4
+ * Resolve the path to the OpenCode SQLite database.
5
+ *
6
+ * Checks in this order:
7
+ * 1. XDG_DATA_HOME/opencode/opencode.db (honours XDG override)
8
+ * 2. ~/Library/Application Support/opencode/opencode.db (legacy macOS path)
9
+ * 3. ~/.local/share/opencode/opencode.db (XDG default)
10
+ */
11
+ export function resolveOpenCodeDbPath(): string {
12
+ const home = process.env.HOME || '';
13
+
14
+ // 1. If XDG_DATA_HOME is explicitly set, use it
15
+ if (process.env.XDG_DATA_HOME) {
16
+ return path.join(process.env.XDG_DATA_HOME, 'opencode', 'opencode.db');
17
+ }
18
+
19
+ // 2. Legacy macOS path (~/Library/Application Support/opencode/)
20
+ if (process.platform === 'darwin') {
21
+ return path.join(home, 'Library', 'Application Support', 'opencode', 'opencode.db');
22
+ }
23
+
24
+ // 3. XDG default (~/.local/share/opencode/)
25
+ return path.join(home, '.local', 'share', 'opencode', 'opencode.db');
26
+ }