@juspay/shooter 1.0.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 (488) hide show
  1. package/.claude/hooks/notifier.cjs +117 -33
  2. package/.claude/settings.json +14 -14
  3. package/README.md +116 -84
  4. package/bin/shooter.cjs +471 -102
  5. package/build/client/_app/immutable/assets/{0.CM9Hl6d-.css → 0.BhZOCxO4.css} +1 -1
  6. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.br +0 -0
  7. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/1.BYutk3aU.css +1 -0
  9. package/build/client/_app/immutable/assets/1.BYutk3aU.css.br +0 -0
  10. package/build/client/_app/immutable/assets/1.BYutk3aU.css.gz +0 -0
  11. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.gz +0 -0
  12. package/build/client/_app/immutable/assets/3.DGDHCVnW.css +1 -0
  13. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.br +0 -0
  14. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.gz +0 -0
  15. package/build/client/_app/immutable/assets/4.BFUut--w.css +1 -0
  16. package/build/client/_app/immutable/assets/4.BFUut--w.css.br +0 -0
  17. package/build/client/_app/immutable/assets/4.BFUut--w.css.gz +0 -0
  18. package/build/client/_app/immutable/assets/5.BTOx7yt7.css +1 -0
  19. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.br +0 -0
  20. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.gz +0 -0
  21. package/build/client/_app/immutable/assets/6.eZGZN-BF.css +1 -0
  22. package/build/client/_app/immutable/assets/6.eZGZN-BF.css.br +0 -0
  23. package/build/client/_app/immutable/assets/6.eZGZN-BF.css.gz +0 -0
  24. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css +1 -0
  25. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.br +0 -0
  26. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.gz +0 -0
  27. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css +1 -0
  28. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.br +0 -0
  29. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.gz +0 -0
  30. package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css +1 -0
  31. package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css.br +0 -0
  32. package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css.gz +0 -0
  33. package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css +1 -0
  34. package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css.br +0 -0
  35. package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css.gz +0 -0
  36. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.gz +0 -0
  37. package/build/client/_app/immutable/chunks/B-K5Sh65.js +1 -0
  38. package/build/client/_app/immutable/chunks/B-K5Sh65.js.br +0 -0
  39. package/build/client/_app/immutable/chunks/B-K5Sh65.js.gz +0 -0
  40. package/build/client/_app/immutable/chunks/B5NAKyil.js +20 -0
  41. package/build/client/_app/immutable/chunks/B5NAKyil.js.br +0 -0
  42. package/build/client/_app/immutable/chunks/B5NAKyil.js.gz +0 -0
  43. package/build/client/_app/immutable/chunks/B8XegpSE.js +1 -0
  44. package/build/client/_app/immutable/chunks/B8XegpSE.js.br +0 -0
  45. package/build/client/_app/immutable/chunks/B8XegpSE.js.gz +0 -0
  46. package/build/client/_app/immutable/chunks/B8zoBsv3.js +6 -0
  47. package/build/client/_app/immutable/chunks/B8zoBsv3.js.br +0 -0
  48. package/build/client/_app/immutable/chunks/B8zoBsv3.js.gz +0 -0
  49. package/build/client/_app/immutable/chunks/BLszSzTT.js +1 -0
  50. package/build/client/_app/immutable/chunks/BLszSzTT.js.br +0 -0
  51. package/build/client/_app/immutable/chunks/BLszSzTT.js.gz +0 -0
  52. package/build/client/_app/immutable/chunks/BOYo8yTr.js +1 -0
  53. package/build/client/_app/immutable/chunks/BOYo8yTr.js.br +0 -0
  54. package/build/client/_app/immutable/chunks/BOYo8yTr.js.gz +0 -0
  55. package/build/client/_app/immutable/chunks/BTGVxaYV.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/BYqGCrTe.js +1 -0
  57. package/build/client/_app/immutable/chunks/BYqGCrTe.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/BYqGCrTe.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/BlxrFPDK.js.gz +0 -0
  60. package/build/client/_app/immutable/chunks/Bu1aqm5j.js +1 -0
  61. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.br +0 -0
  62. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.gz +0 -0
  63. package/build/client/_app/immutable/chunks/C4mLaWWx.js +1 -0
  64. package/build/client/_app/immutable/chunks/C4mLaWWx.js.br +0 -0
  65. package/build/client/_app/immutable/chunks/C4mLaWWx.js.gz +0 -0
  66. package/build/client/_app/immutable/chunks/CQjSATpv.js +61 -0
  67. package/build/client/_app/immutable/chunks/CQjSATpv.js.br +0 -0
  68. package/build/client/_app/immutable/chunks/CQjSATpv.js.gz +0 -0
  69. package/build/client/_app/immutable/chunks/CSoRdFvv.js +1 -0
  70. package/build/client/_app/immutable/chunks/CSoRdFvv.js.br +0 -0
  71. package/build/client/_app/immutable/chunks/CSoRdFvv.js.gz +0 -0
  72. package/build/client/_app/immutable/chunks/CZHsSL_X.js +1 -0
  73. package/build/client/_app/immutable/chunks/CZHsSL_X.js.br +0 -0
  74. package/build/client/_app/immutable/chunks/CZHsSL_X.js.gz +0 -0
  75. package/build/client/_app/immutable/chunks/DLu6yJIZ.js.gz +0 -0
  76. package/build/client/_app/immutable/chunks/DSU1n5N_.js +1 -0
  77. package/build/client/_app/immutable/chunks/DSU1n5N_.js.br +0 -0
  78. package/build/client/_app/immutable/chunks/DSU1n5N_.js.gz +0 -0
  79. package/build/client/_app/immutable/chunks/DVkn4r72.js +1 -0
  80. package/build/client/_app/immutable/chunks/DVkn4r72.js.br +0 -0
  81. package/build/client/_app/immutable/chunks/DVkn4r72.js.gz +0 -0
  82. package/build/client/_app/immutable/chunks/DjsDGxCa.js +41 -0
  83. package/build/client/_app/immutable/chunks/DjsDGxCa.js.br +0 -0
  84. package/build/client/_app/immutable/chunks/DjsDGxCa.js.gz +0 -0
  85. package/build/client/_app/immutable/chunks/PPVm8Dsz.js.gz +0 -0
  86. package/build/client/_app/immutable/chunks/UJOiqIYE.js +1 -0
  87. package/build/client/_app/immutable/chunks/UJOiqIYE.js.br +0 -0
  88. package/build/client/_app/immutable/chunks/UJOiqIYE.js.gz +0 -0
  89. package/build/client/_app/immutable/chunks/r0JawsZc.js +2 -0
  90. package/build/client/_app/immutable/chunks/r0JawsZc.js.br +0 -0
  91. package/build/client/_app/immutable/chunks/r0JawsZc.js.gz +0 -0
  92. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js +2 -0
  93. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.br +0 -0
  94. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.gz +0 -0
  95. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js +1 -0
  96. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.br +2 -0
  97. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.gz +0 -0
  98. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js +1 -0
  99. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.br +0 -0
  100. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.gz +0 -0
  101. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js +1 -0
  102. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.br +0 -0
  103. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.gz +0 -0
  104. package/build/client/_app/immutable/nodes/2.CyRB2euU.js +1 -0
  105. package/build/client/_app/immutable/nodes/2.CyRB2euU.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/2.CyRB2euU.js.gz +0 -0
  107. package/build/client/_app/immutable/nodes/3.3yohCM25.js +3 -0
  108. package/build/client/_app/immutable/nodes/3.3yohCM25.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/3.3yohCM25.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js +1 -0
  111. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.gz +0 -0
  113. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js +4 -0
  114. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.br +0 -0
  115. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.gz +0 -0
  116. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js +2 -0
  117. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.br +0 -0
  118. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.gz +0 -0
  119. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js +2 -0
  120. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.br +0 -0
  121. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.gz +0 -0
  122. package/build/client/_app/version.json +1 -1
  123. package/build/client/_app/version.json.br +0 -0
  124. package/build/client/_app/version.json.gz +0 -0
  125. package/build/client/favicon.svg.gz +0 -0
  126. package/build/client/manifest.json +13 -0
  127. package/build/client/manifest.json.br +0 -0
  128. package/build/client/manifest.json.gz +0 -0
  129. package/build/pty-holder.cjs +37 -8
  130. package/build/server/chunks/0-Vk38tI2J.js +9 -0
  131. package/build/server/chunks/0-Vk38tI2J.js.map +1 -0
  132. package/build/server/chunks/1-BvYQX5MR.js +9 -0
  133. package/build/server/chunks/1-BvYQX5MR.js.map +1 -0
  134. package/build/server/chunks/2-Cl7R4Qk2.js +9 -0
  135. package/build/server/chunks/2-Cl7R4Qk2.js.map +1 -0
  136. package/build/server/chunks/3-Ck7ewhOX.js +9 -0
  137. package/build/server/chunks/3-Ck7ewhOX.js.map +1 -0
  138. package/build/server/chunks/4-CnDeRm2Z.js +9 -0
  139. package/build/server/chunks/4-CnDeRm2Z.js.map +1 -0
  140. package/build/server/chunks/5-IxitzEvN.js +9 -0
  141. package/build/server/chunks/5-IxitzEvN.js.map +1 -0
  142. package/build/server/chunks/6-CyZ3r1iS.js +9 -0
  143. package/build/server/chunks/6-CyZ3r1iS.js.map +1 -0
  144. package/build/server/chunks/7-BmI7du46.js +9 -0
  145. package/build/server/chunks/7-BmI7du46.js.map +1 -0
  146. package/build/server/chunks/Button-Cs1aE6ka.js +80 -0
  147. package/build/server/chunks/Button-Cs1aE6ka.js.map +1 -0
  148. package/build/server/chunks/EmptyState-DDFH1K8g.js +26 -0
  149. package/build/server/chunks/EmptyState-DDFH1K8g.js.map +1 -0
  150. package/build/server/chunks/Icon-CEUrotA6.js +36 -0
  151. package/build/server/chunks/Icon-CEUrotA6.js.map +1 -0
  152. package/build/server/chunks/Shimmer-DB8W1zt6.js +10 -0
  153. package/build/server/chunks/Shimmer-DB8W1zt6.js.map +1 -0
  154. package/build/server/chunks/_error.svelte-uCOJNxvr.js +39 -0
  155. package/build/server/chunks/_error.svelte-uCOJNxvr.js.map +1 -0
  156. package/build/server/chunks/_layout.svelte-CtWmEJwe.js +56 -0
  157. package/build/server/chunks/_layout.svelte-CtWmEJwe.js.map +1 -0
  158. package/build/server/chunks/_page.svelte-BcZaKdX9.js +45 -0
  159. package/build/server/chunks/_page.svelte-BcZaKdX9.js.map +1 -0
  160. package/build/server/chunks/_page.svelte-BdYynOck.js +85 -0
  161. package/build/server/chunks/_page.svelte-BdYynOck.js.map +1 -0
  162. package/build/server/chunks/_page.svelte-BgevQjq1.js +101 -0
  163. package/build/server/chunks/_page.svelte-BgevQjq1.js.map +1 -0
  164. package/build/server/chunks/_page.svelte-CVq6tRb3.js +550 -0
  165. package/build/server/chunks/_page.svelte-CVq6tRb3.js.map +1 -0
  166. package/build/server/chunks/_page.svelte-CxWcQ0Am.js +651 -0
  167. package/build/server/chunks/_page.svelte-CxWcQ0Am.js.map +1 -0
  168. package/build/server/chunks/_page.svelte-DO4oa_LY.js +44 -0
  169. package/build/server/chunks/_page.svelte-DO4oa_LY.js.map +1 -0
  170. package/build/server/chunks/{_server.ts-CbDRDIoP.js → _server.ts-BStnNIcq.js} +9 -11
  171. package/build/server/chunks/_server.ts-BStnNIcq.js.map +1 -0
  172. package/build/server/chunks/{_server.ts-DRVbgm6k.js → _server.ts-CAxsWKvS.js} +22 -25
  173. package/build/server/chunks/_server.ts-CAxsWKvS.js.map +1 -0
  174. package/build/server/chunks/{_server.ts-CPa6DgIt.js → _server.ts-COu0vNpd.js} +6 -6
  175. package/build/server/chunks/_server.ts-COu0vNpd.js.map +1 -0
  176. package/build/server/chunks/{_server.ts-C29xzfaw.js → _server.ts-CTpcLUH8.js} +10 -10
  177. package/build/server/chunks/_server.ts-CTpcLUH8.js.map +1 -0
  178. package/build/server/chunks/{_server.ts-D4MNi4cD.js → _server.ts-Cf84YIaW.js} +3 -3
  179. package/build/server/chunks/{_server.ts-D4MNi4cD.js.map → _server.ts-Cf84YIaW.js.map} +1 -1
  180. package/build/server/chunks/{_server.ts-BL2FGb5Z.js → _server.ts-Ch-6iOHp.js} +99 -53
  181. package/build/server/chunks/_server.ts-Ch-6iOHp.js.map +1 -0
  182. package/build/server/chunks/_server.ts-CtH0dhUp.js +71 -0
  183. package/build/server/chunks/_server.ts-CtH0dhUp.js.map +1 -0
  184. package/build/server/chunks/_server.ts-DB_Kg97c.js +73 -0
  185. package/build/server/chunks/_server.ts-DB_Kg97c.js.map +1 -0
  186. package/build/server/chunks/{_server.ts-DfajWaqh.js → _server.ts-DV8zTCF9.js} +7 -9
  187. package/build/server/chunks/_server.ts-DV8zTCF9.js.map +1 -0
  188. package/build/server/chunks/_server.ts-DYpJImqd.js +99 -0
  189. package/build/server/chunks/_server.ts-DYpJImqd.js.map +1 -0
  190. package/build/server/chunks/{_server.ts-ColfDHW8.js → _server.ts-DYvb9ijZ.js} +21 -10
  191. package/build/server/chunks/_server.ts-DYvb9ijZ.js.map +1 -0
  192. package/build/server/chunks/{_server.ts-Cv_OrRuL.js → _server.ts-Deok2y88.js} +209 -34
  193. package/build/server/chunks/_server.ts-Deok2y88.js.map +1 -0
  194. package/build/server/chunks/{_server.ts-y9-WYDMa.js → _server.ts-WhTJBEJy.js} +5 -4
  195. package/build/server/chunks/{_server.ts-y9-WYDMa.js.map → _server.ts-WhTJBEJy.js.map} +1 -1
  196. package/build/server/chunks/{_server.ts-BjOJsoy4.js → _server.ts-XzT2UHM1.js} +6 -5
  197. package/build/server/chunks/_server.ts-XzT2UHM1.js.map +1 -0
  198. package/build/server/chunks/{_server.ts-BgdjBZco.js → _server.ts-tSpgyl1D.js} +7 -5
  199. package/build/server/chunks/_server.ts-tSpgyl1D.js.map +1 -0
  200. package/build/server/chunks/{_server.ts-BihKSdj_.js → _server.ts-vekTmWAx.js} +8 -8
  201. package/build/server/chunks/_server.ts-vekTmWAx.js.map +1 -0
  202. package/build/server/chunks/{auth-CEgFis71.js → auth-DeCdZ83n.js} +2 -2
  203. package/build/server/chunks/{auth-CEgFis71.js.map → auth-DeCdZ83n.js.map} +1 -1
  204. package/build/server/chunks/client-BdGHe_hY.js +25 -0
  205. package/build/server/chunks/client-BdGHe_hY.js.map +1 -0
  206. package/build/server/chunks/client2-CCBGA-2V.js +7 -0
  207. package/build/server/chunks/client2-CCBGA-2V.js.map +1 -0
  208. package/build/server/chunks/error-DDXB3duW.js +12 -0
  209. package/build/server/chunks/error-DDXB3duW.js.map +1 -0
  210. package/build/server/chunks/{exports-CJ0Q5XmL.js → index-DwaY1cAm.js} +1111 -1634
  211. package/build/server/chunks/index-DwaY1cAm.js.map +1 -0
  212. package/build/server/chunks/index-server-CrDaL06Y.js +9 -0
  213. package/build/server/chunks/index-server-CrDaL06Y.js.map +1 -0
  214. package/build/server/chunks/index2-CgclKpUj.js +58 -0
  215. package/build/server/chunks/index2-CgclKpUj.js.map +1 -0
  216. package/build/server/chunks/{library-apns-BHxLmuIx.js → library-apns-BqJbvSKh.js} +4 -4
  217. package/build/server/chunks/library-apns-BqJbvSKh.js.map +1 -0
  218. package/build/server/chunks/markdown-W_mTBct0.js +8 -0
  219. package/build/server/chunks/markdown-W_mTBct0.js.map +1 -0
  220. package/build/server/chunks/opencode-db-path-DcfhJtJy.js +15 -0
  221. package/build/server/chunks/opencode-db-path-DcfhJtJy.js.map +1 -0
  222. package/build/server/chunks/{pty-manager-C0FhBiVq.js → pty-manager-BQVB7IVj.js} +155 -326
  223. package/build/server/chunks/pty-manager-BQVB7IVj.js.map +1 -0
  224. package/build/server/chunks/root-DDSnEAZv.js +1171 -0
  225. package/build/server/chunks/root-DDSnEAZv.js.map +1 -0
  226. package/build/server/chunks/{shared-server-BDY8jh20.js → shared-server-sSGG17Df.js} +2 -3
  227. package/build/server/chunks/{shared-server-BDY8jh20.js.map → shared-server-sSGG17Df.js.map} +1 -1
  228. package/build/server/chunks/state.svelte-hBbXlUak.js +11 -0
  229. package/build/server/chunks/state.svelte-hBbXlUak.js.map +1 -0
  230. package/build/server/chunks/stores-DHNzYNpX.js +28 -0
  231. package/build/server/chunks/stores-DHNzYNpX.js.map +1 -0
  232. package/build/server/index.js +1085 -2242
  233. package/build/server/index.js.map +1 -1
  234. package/build/server/manifest.js +39 -25
  235. package/build/server/manifest.js.map +1 -1
  236. package/package.json +32 -9
  237. package/scripts/fix-generated-types.sh +37 -0
  238. package/scripts/homebrew/shooter.rb +51 -0
  239. package/scripts/install.sh +348 -186
  240. package/scripts/setup.cjs +215 -45
  241. package/server.ts +114 -71
  242. package/src/app.css +12 -3
  243. package/src/app.d.ts +13 -20
  244. package/src/app.html +3 -2
  245. package/src/generated/types/API.ts +280 -0
  246. package/src/generated/types/APN.ts +186 -203
  247. package/src/generated/types/CLI.ts +18 -25
  248. package/src/generated/types/Client.ts +589 -0
  249. package/src/generated/types/Config.ts +53 -0
  250. package/src/generated/types/Holder.ts +638 -0
  251. package/src/generated/types/JWT.ts +39 -50
  252. package/src/generated/types/Notification.ts +426 -0
  253. package/src/generated/types/OpenCode.ts +356 -0
  254. package/src/generated/types/Sessions.ts +570 -0
  255. package/src/generated/types/Terminal.ts +2184 -2071
  256. package/src/generated/types/WsProtocol.ts +2004 -0
  257. package/src/generated/types/index.ts +9 -3
  258. package/src/lib/env.ts +29 -0
  259. package/src/lib/modules/client/common/cache.ts +10 -2
  260. package/src/lib/modules/client/common/config-guard.ts +37 -5
  261. package/src/lib/modules/client/common/error.ts +10 -0
  262. package/src/lib/modules/client/common/index.ts +6 -5
  263. package/src/lib/modules/client/common/markdown.ts +22 -1
  264. package/src/lib/modules/client/common/native-bridge.ts +28 -20
  265. package/src/lib/modules/client/common/time.ts +13 -11
  266. package/src/lib/modules/client/terminal/ChatView.svelte +354 -74
  267. package/src/lib/modules/client/terminal/CommandPalette.svelte +3 -2
  268. package/src/lib/modules/client/terminal/ConnectionStatus.svelte +7 -1
  269. package/src/lib/modules/client/terminal/LaunchSheet.svelte +147 -84
  270. package/src/lib/modules/client/terminal/QuickKeys.svelte +3 -1
  271. package/src/lib/modules/client/terminal/ShortcutsHelp.svelte +2 -5
  272. package/src/lib/modules/client/terminal/keyboard-shortcuts.ts +27 -24
  273. package/src/lib/modules/client/terminal/xterm-wrapper.ts +74 -45
  274. package/src/lib/modules/server/apn/library-apns.ts +3 -2
  275. package/src/lib/modules/server/apn/notification-history.ts +2 -13
  276. package/src/lib/modules/server/apn/notification-sessions.ts +3 -13
  277. package/src/lib/modules/server/apn/pending-requests.ts +3 -8
  278. package/src/lib/modules/server/apn/types.ts +5 -4
  279. package/src/lib/modules/server/cli/index.ts +3 -2
  280. package/src/lib/modules/server/fcm/fcm-service.ts +8 -6
  281. package/src/lib/modules/server/sessions/jsonl-parser.ts +3 -3
  282. package/src/lib/modules/server/sessions/jsonl-reader.ts +86 -26
  283. package/src/lib/modules/server/sessions/opencode-db-path.ts +26 -0
  284. package/src/lib/modules/server/sessions/opencode-reader.ts +13 -15
  285. package/src/lib/modules/server/sessions/process-detector.ts +103 -0
  286. package/src/lib/modules/server/sessions/types.ts +11 -22
  287. package/src/lib/modules/server/terminal/holder-client.ts +272 -248
  288. package/src/lib/modules/server/terminal/opencode-watcher.ts +547 -556
  289. package/src/lib/modules/server/terminal/pty-holder.cjs +37 -8
  290. package/src/lib/modules/server/terminal/pty-manager.ts +157 -115
  291. package/src/lib/modules/server/terminal/session-watcher.ts +6 -4
  292. package/src/lib/modules/server/terminal/terminal-store.ts +131 -128
  293. package/src/lib/modules/server/utils/error.ts +9 -0
  294. package/src/lib/modules/server/ws/events-handler.ts +12 -6
  295. package/src/lib/modules/server/ws/keepalive.ts +86 -69
  296. package/src/lib/modules/server/ws/server.ts +43 -37
  297. package/src/lib/modules/server/ws/session-handler.ts +332 -147
  298. package/src/lib/modules/server/ws/terminal-handler.ts +29 -17
  299. package/src/lib/modules/server/ws/ticket-store.ts +29 -26
  300. package/src/lib/theme.css +30 -0
  301. package/src/lib/types/config.ts +1 -6
  302. package/src/routes/+error.svelte +94 -0
  303. package/src/routes/+layout.svelte +66 -31
  304. package/src/routes/+page.svelte +25 -22
  305. package/src/routes/api/debug/+server.ts +3 -1
  306. package/src/routes/api/device-token/+server.ts +60 -60
  307. package/src/routes/api/health/+server.ts +81 -73
  308. package/src/routes/api/notify/+server.ts +115 -68
  309. package/src/routes/api/qr-config/+server.ts +30 -32
  310. package/src/routes/api/response/+server.ts +9 -4
  311. package/src/routes/api/sessions/+server.ts +15 -5
  312. package/src/routes/api/sessions/connect/+server.ts +125 -0
  313. package/src/routes/api/sessions/detect/+server.ts +27 -0
  314. package/src/routes/api/terminals/+server.ts +26 -24
  315. package/src/routes/api/terminals/[id]/+server.ts +13 -7
  316. package/src/routes/api/terminals/[id]/paste-image/+server.ts +54 -52
  317. package/src/routes/api/terminals/[id]/resize/+server.ts +6 -3
  318. package/src/routes/api/webhook/+server.ts +8 -10
  319. package/src/routes/api/ws-status/+server.ts +7 -5
  320. package/src/routes/api/ws-ticket/+server.ts +42 -41
  321. package/src/routes/config/+page.svelte +149 -75
  322. package/src/routes/project/+page.svelte +165 -35
  323. package/src/routes/session/[id]/+page.svelte +479 -283
  324. package/src/routes/terminals/+page.svelte +58 -45
  325. package/src/routes/terminals/[id]/+page.svelte +223 -91
  326. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.br +0 -0
  327. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.gz +0 -0
  328. package/build/client/_app/immutable/assets/3.C0uFg0IS.css +0 -1
  329. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.br +0 -0
  330. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.gz +0 -0
  331. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +0 -1
  332. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
  333. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
  334. package/build/client/_app/immutable/assets/5.DRjApZQW.css +0 -1
  335. package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
  336. package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
  337. package/build/client/_app/immutable/assets/6.AraZrY8I.css +0 -1
  338. package/build/client/_app/immutable/assets/6.AraZrY8I.css.br +0 -0
  339. package/build/client/_app/immutable/assets/6.AraZrY8I.css.gz +0 -0
  340. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css +0 -1
  341. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.br +0 -0
  342. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.gz +0 -0
  343. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +0 -1
  344. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
  345. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
  346. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css +0 -1
  347. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.br +0 -0
  348. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.gz +0 -0
  349. package/build/client/_app/immutable/chunks/BNJphC1q.js +0 -56
  350. package/build/client/_app/immutable/chunks/BNJphC1q.js.br +0 -0
  351. package/build/client/_app/immutable/chunks/BNJphC1q.js.gz +0 -0
  352. package/build/client/_app/immutable/chunks/Bvk7mfPM.js +0 -1
  353. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.br +0 -0
  354. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.gz +0 -0
  355. package/build/client/_app/immutable/chunks/CAokzuPQ.js +0 -1
  356. package/build/client/_app/immutable/chunks/CAokzuPQ.js.br +0 -0
  357. package/build/client/_app/immutable/chunks/CAokzuPQ.js.gz +0 -0
  358. package/build/client/_app/immutable/chunks/CGLrx-H5.js +0 -1
  359. package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
  360. package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
  361. package/build/client/_app/immutable/chunks/CgCpWzEA.js +0 -1
  362. package/build/client/_app/immutable/chunks/CgCpWzEA.js.br +0 -0
  363. package/build/client/_app/immutable/chunks/CgCpWzEA.js.gz +0 -0
  364. package/build/client/_app/immutable/chunks/Cjwk_cGO.js +0 -6
  365. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.br +0 -0
  366. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.gz +0 -0
  367. package/build/client/_app/immutable/chunks/CtQ8EED1.js +0 -11
  368. package/build/client/_app/immutable/chunks/CtQ8EED1.js.br +0 -0
  369. package/build/client/_app/immutable/chunks/CtQ8EED1.js.gz +0 -0
  370. package/build/client/_app/immutable/chunks/DERQCisl.js +0 -1
  371. package/build/client/_app/immutable/chunks/DERQCisl.js.br +0 -0
  372. package/build/client/_app/immutable/chunks/DERQCisl.js.gz +0 -0
  373. package/build/client/_app/immutable/chunks/DKrg8TQs.js +0 -1
  374. package/build/client/_app/immutable/chunks/DKrg8TQs.js.br +0 -0
  375. package/build/client/_app/immutable/chunks/DKrg8TQs.js.gz +0 -0
  376. package/build/client/_app/immutable/chunks/Dkkpz_4D.js +0 -126
  377. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.br +0 -0
  378. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.gz +0 -0
  379. package/build/client/_app/immutable/chunks/DoczjQhA.js +0 -1
  380. package/build/client/_app/immutable/chunks/DoczjQhA.js.br +0 -0
  381. package/build/client/_app/immutable/chunks/DoczjQhA.js.gz +0 -0
  382. package/build/client/_app/immutable/chunks/RpcNruLP.js +0 -2
  383. package/build/client/_app/immutable/chunks/RpcNruLP.js.br +0 -0
  384. package/build/client/_app/immutable/chunks/RpcNruLP.js.gz +0 -0
  385. package/build/client/_app/immutable/chunks/a-St0Zwo.js +0 -1
  386. package/build/client/_app/immutable/chunks/a-St0Zwo.js.br +0 -0
  387. package/build/client/_app/immutable/chunks/a-St0Zwo.js.gz +0 -0
  388. package/build/client/_app/immutable/chunks/bo70OQUZ.js +0 -1
  389. package/build/client/_app/immutable/chunks/bo70OQUZ.js.br +0 -0
  390. package/build/client/_app/immutable/chunks/bo70OQUZ.js.gz +0 -0
  391. package/build/client/_app/immutable/entry/app.QvGgdvTI.js +0 -2
  392. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.br +0 -0
  393. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.gz +0 -0
  394. package/build/client/_app/immutable/entry/start.BntDNRMC.js +0 -1
  395. package/build/client/_app/immutable/entry/start.BntDNRMC.js.br +0 -0
  396. package/build/client/_app/immutable/entry/start.BntDNRMC.js.gz +0 -0
  397. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js +0 -1
  398. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.br +0 -0
  399. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.gz +0 -0
  400. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js +0 -1
  401. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.br +0 -0
  402. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.gz +0 -0
  403. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js +0 -1
  404. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.br +0 -0
  405. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.gz +0 -0
  406. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js +0 -3
  407. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.br +0 -0
  408. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.gz +0 -0
  409. package/build/client/_app/immutable/nodes/4.D-cIe70D.js +0 -1
  410. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.br +0 -0
  411. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.gz +0 -0
  412. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js +0 -1
  413. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.br +0 -0
  414. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.gz +0 -0
  415. package/build/client/_app/immutable/nodes/6.BB7QE48r.js +0 -2
  416. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.br +0 -0
  417. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.gz +0 -0
  418. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js +0 -2
  419. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.br +0 -0
  420. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.gz +0 -0
  421. package/build/client/manifest.webmanifest +0 -1
  422. package/build/client/registerSW.js +0 -1
  423. package/build/client/registerSW.js.br +0 -0
  424. package/build/client/registerSW.js.gz +0 -0
  425. package/build/client/sw.js +0 -222
  426. package/build/client/sw.js.br +0 -0
  427. package/build/client/sw.js.gz +0 -0
  428. package/build/client/workbox-5119daf5.js +0 -3395
  429. package/build/client/workbox-5119daf5.js.br +0 -0
  430. package/build/client/workbox-5119daf5.js.gz +0 -0
  431. package/build/server/chunks/0-q2IUp76Y.js +0 -9
  432. package/build/server/chunks/0-q2IUp76Y.js.map +0 -1
  433. package/build/server/chunks/1-CU50G5wZ.js +0 -9
  434. package/build/server/chunks/1-CU50G5wZ.js.map +0 -1
  435. package/build/server/chunks/2-D01t9s8T.js +0 -9
  436. package/build/server/chunks/2-D01t9s8T.js.map +0 -1
  437. package/build/server/chunks/3-5PUQ04wC.js +0 -9
  438. package/build/server/chunks/3-5PUQ04wC.js.map +0 -1
  439. package/build/server/chunks/4-e7gywnSG.js +0 -9
  440. package/build/server/chunks/4-e7gywnSG.js.map +0 -1
  441. package/build/server/chunks/5-CA1SA6KZ.js +0 -9
  442. package/build/server/chunks/5-CA1SA6KZ.js.map +0 -1
  443. package/build/server/chunks/6-71H221sV.js +0 -9
  444. package/build/server/chunks/6-71H221sV.js.map +0 -1
  445. package/build/server/chunks/7-Bo-vmdyz.js +0 -9
  446. package/build/server/chunks/7-Bo-vmdyz.js.map +0 -1
  447. package/build/server/chunks/_layout.svelte-SFHOxs74.js +0 -132
  448. package/build/server/chunks/_layout.svelte-SFHOxs74.js.map +0 -1
  449. package/build/server/chunks/_page.svelte-B4w-2wD-.js +0 -120
  450. package/build/server/chunks/_page.svelte-B4w-2wD-.js.map +0 -1
  451. package/build/server/chunks/_page.svelte-B_qAXjkh.js +0 -213
  452. package/build/server/chunks/_page.svelte-B_qAXjkh.js.map +0 -1
  453. package/build/server/chunks/_page.svelte-CsF1_TRG.js +0 -50
  454. package/build/server/chunks/_page.svelte-CsF1_TRG.js.map +0 -1
  455. package/build/server/chunks/_page.svelte-DJC6U-P0.js +0 -68
  456. package/build/server/chunks/_page.svelte-DJC6U-P0.js.map +0 -1
  457. package/build/server/chunks/_page.svelte-DQ6HBtsz.js +0 -407
  458. package/build/server/chunks/_page.svelte-DQ6HBtsz.js.map +0 -1
  459. package/build/server/chunks/_page.svelte-LbhhjP21.js +0 -148
  460. package/build/server/chunks/_page.svelte-LbhhjP21.js.map +0 -1
  461. package/build/server/chunks/_server.ts-BL2FGb5Z.js.map +0 -1
  462. package/build/server/chunks/_server.ts-BgdjBZco.js.map +0 -1
  463. package/build/server/chunks/_server.ts-BihKSdj_.js.map +0 -1
  464. package/build/server/chunks/_server.ts-BjOJsoy4.js.map +0 -1
  465. package/build/server/chunks/_server.ts-C29xzfaw.js.map +0 -1
  466. package/build/server/chunks/_server.ts-CPa6DgIt.js.map +0 -1
  467. package/build/server/chunks/_server.ts-CbDRDIoP.js.map +0 -1
  468. package/build/server/chunks/_server.ts-Cl1OEWL4.js +0 -54
  469. package/build/server/chunks/_server.ts-Cl1OEWL4.js.map +0 -1
  470. package/build/server/chunks/_server.ts-ColfDHW8.js.map +0 -1
  471. package/build/server/chunks/_server.ts-Cv_OrRuL.js.map +0 -1
  472. package/build/server/chunks/_server.ts-DRVbgm6k.js.map +0 -1
  473. package/build/server/chunks/_server.ts-DfajWaqh.js.map +0 -1
  474. package/build/server/chunks/client-CxCatAKr.js +0 -255
  475. package/build/server/chunks/client-CxCatAKr.js.map +0 -1
  476. package/build/server/chunks/error.svelte-BqdwMWdK.js +0 -26
  477. package/build/server/chunks/error.svelte-BqdwMWdK.js.map +0 -1
  478. package/build/server/chunks/exports-CJ0Q5XmL.js.map +0 -1
  479. package/build/server/chunks/index2-DAxIoAO-.js +0 -36
  480. package/build/server/chunks/index2-DAxIoAO-.js.map +0 -1
  481. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js +0 -137
  482. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js.map +0 -1
  483. package/build/server/chunks/library-apns-BHxLmuIx.js.map +0 -1
  484. package/build/server/chunks/markdown-Bxrl3cCF.js +0 -1241
  485. package/build/server/chunks/markdown-Bxrl3cCF.js.map +0 -1
  486. package/build/server/chunks/pty-manager-C0FhBiVq.js.map +0 -1
  487. package/build/server/chunks/stores-D0HorpgL.js +0 -36
  488. package/build/server/chunks/stores-D0HorpgL.js.map +0 -1
@@ -1,19 +1,8 @@
1
1
  // In-memory notification history store.
2
2
  // Same pattern as pending-requests.ts — suitable for single-instance deployments.
3
3
 
4
- export interface NotificationRecord {
5
- category?: string;
6
- data?: Record<string, unknown>;
7
- error?: string;
8
- id: string;
9
- message: string;
10
- project?: string;
11
- source?: string;
12
- status: 'failed' | 'filtered' | 'sent';
13
- timestamp: string;
14
- title: string;
15
- tool?: string;
16
- }
4
+ export type { NotificationRecord } from '$generated/types';
5
+ import type { NotificationRecord } from '$generated/types';
17
6
 
18
7
  const MAX_HISTORY = 100;
19
8
 
@@ -1,18 +1,8 @@
1
+ import type { NotificationSession } from '$generated/types';
2
+
1
3
  import { getNotifications, type NotificationRecord } from './notification-history';
2
4
 
3
- export interface Session {
4
- duration: number; // seconds
5
- endTime: string;
6
- eventCount: number;
7
- events: NotificationRecord[];
8
- filesModified: string[];
9
- id: string;
10
- project: string;
11
- runtime: string;
12
- startTime: string;
13
- status: 'active' | 'complete';
14
- toolsUsed: string[];
15
- }
5
+ export type Session = NotificationSession;
16
6
 
17
7
  const SESSION_GAP_MS = 30 * 60 * 1000; // 30 min gap = new session
18
8
  const ACTIVE_THRESHOLD_MS = 5 * 60 * 1000; // active if last event < 5 min ago
@@ -1,14 +1,9 @@
1
1
  // Shared in-memory store for pending permission requests.
2
2
  // Used by /api/notify (creates entries) and /api/response (reads/updates).
3
3
 
4
- export interface PendingRequest {
5
- createdAt: number;
6
- decidedAt: null | number;
7
- decision: 'allow' | 'deny' | null;
8
- sessionId: string;
9
- toolInput: Record<string, unknown>;
10
- toolName: string;
11
- }
4
+ import type { PendingRequest } from '$generated/types';
5
+
6
+ export type { PendingRequest };
12
7
 
13
8
  const MAX_AGE_MS = 5 * 60 * 1000; // 5 minutes
14
9
 
@@ -7,12 +7,13 @@ import type {
7
7
  SentDetail,
8
8
  } from '$generated/types';
9
9
 
10
- // Types not yet generated by type-crafter (contain $ref/arrays/oneOf)
11
- // TODO: Remove these once type-crafter generates them
10
+ // Composite types built from generated primitives. These use arrays and
11
+ // union constructs that type-crafter does not emit, so they stay as local
12
+ // definitions.
12
13
 
13
14
  export interface LibraryResult {
14
- failed: LibraryFailedItem[] | null;
15
- sent: LibrarySentItem[] | null;
15
+ failed: LibraryFailedItem[];
16
+ sent: LibrarySentItem[];
16
17
  }
17
18
 
18
19
  export interface NotificationPayload {
@@ -6,8 +6,9 @@ export type { ExitCallback, OutputCallback } from './runner';
6
6
  // Types generated by type-crafter
7
7
  export type { CLIOptions };
8
8
 
9
- // Types not yet generated by type-crafter (contain $ref/arrays)
10
- // TODO: Remove these once type-crafter generates them
9
+ // Types defined in YAML spec (cli.yaml) but not generated by type-crafter
10
+ // because they contain $ref or array constructs.
11
+ // TODO: Remove once type-crafter supports these constructs.
11
12
  export interface CLICommand {
12
13
  args: string[];
13
14
  name: string;
@@ -30,15 +30,17 @@ export async function sendFCMNotification(
30
30
  },
31
31
  data: {
32
32
  body: payload.body || payload.message || '',
33
- category: payload.category ? String(payload.category) : (payload.data?.category ? String(payload.data.category) : ''),
34
- project: payload.data?.project ? String(payload.data.project) : '',
35
- requestId: payload.data?.requestId ? String(payload.data.requestId) : '',
36
- source: payload.data?.source ? String(payload.data.source) : '',
33
+ category:
34
+ payload.category ??
35
+ (typeof payload.data?.category === 'string' ? payload.data.category : ''),
36
+ project: typeof payload.data?.project === 'string' ? payload.data.project : '',
37
+ requestId: typeof payload.data?.requestId === 'string' ? payload.data.requestId : '',
38
+ source: typeof payload.data?.source === 'string' ? payload.data.source : '',
37
39
  timestamp: new Date().toISOString(),
38
40
  title: payload.title,
39
41
  toolInput: payload.data?.toolInput ? JSON.stringify(payload.data.toolInput) : '',
40
- toolName: payload.data?.toolName ? String(payload.data.toolName) : '',
41
- type: payload.data?.type ? String(payload.data.type) : '',
42
+ toolName: typeof payload.data?.toolName === 'string' ? payload.data.toolName : '',
43
+ type: typeof payload.data?.type === 'string' ? payload.data.type : '',
42
44
  },
43
45
  token: deviceToken,
44
46
  };
@@ -14,12 +14,12 @@ import type { ConversationMessage, MessagePart } from './types';
14
14
  * These are control/metadata entries that don't represent conversation content.
15
15
  */
16
16
  export const SKIP_EVENT_TYPES = new Set([
17
- 'system',
18
17
  'config',
19
- 'summary',
20
- 'result',
21
18
  'heartbeat',
22
19
  'metadata',
20
+ 'result',
21
+ 'summary',
22
+ 'system',
23
23
  ]);
24
24
 
25
25
  /**
@@ -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);
@@ -74,8 +83,6 @@ export function listProjectsWithSessions(): ProjectGroup[] {
74
83
 
75
84
  for (const dir of projectDirs) {
76
85
  const projectDir = path.join(CLAUDE_PROJECTS_DIR, dir);
77
- // Decode project path (fallback, prefer session's projectPath)
78
- const decodedPath = dir.startsWith('-') ? dir.replace(/-/g, '/') : `/${dir.replace(/-/g, '/')}`;
79
86
 
80
87
  // Get sessions for this project
81
88
  const sessions = listSessionsForProject(projectDir);
@@ -86,10 +93,12 @@ export function listProjectsWithSessions(): ProjectGroup[] {
86
93
  // Sort sessions by modified desc
87
94
  sessions.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
88
95
 
89
- // Get real project path from session data instead of decoding directory name
96
+ // Prefer projectPath from session index, then cwd from JSONL, then decoded dir name
90
97
  const realPath =
91
98
  sessions.find((s) => s.projectPath && !s.projectPath.includes('.claude/projects'))
92
- ?.projectPath || decodedPath;
99
+ ?.projectPath ||
100
+ readCwdFromProjectDir(projectDir, sessions) ||
101
+ (dir.startsWith('-') ? dir.replace(/-/g, '/') : `/${dir.replace(/-/g, '/')}`);
93
102
  const pathSegments = realPath.split('/').filter(Boolean);
94
103
  const projectName = pathSegments.slice(-2).join('/');
95
104
 
@@ -122,7 +131,8 @@ function cleanTitle(prompt: string): string {
122
131
  .replace(/<command-args>.*?<\/command-args>/gs, '')
123
132
  .replace(/<local-command-caveat>.*?<\/local-command-caveat>/gs, '')
124
133
  .replace(/<local-command-stdout>.*?<\/local-command-stdout>/gs, '')
125
- .replace(/<system-reminder>.*?<\/system-reminder>/gs, '');
134
+ .replace(/<system-reminder>.*?<\/system-reminder>/gs, '')
135
+ .replace(/<task-notification>.*?<\/task-notification>/gs, '');
126
136
 
127
137
  // Iteratively strip tags until none remain (prevents reconstructed tags like "<scr" + "ipt>")
128
138
  let prev = '';
@@ -217,27 +227,33 @@ function listSessionsForProject(projectDir: string): SessionInfo[] {
217
227
  let messageCount = 0;
218
228
  try {
219
229
  const content = fs.readFileSync(filePath, 'utf-8');
220
- // Count user + assistant messages for the message count
221
- const lines = content.split('\n');
222
- for (const line of lines) {
223
- if (!line.trim()) { continue; }
224
- try {
225
- const entry = JSON.parse(line);
226
- if (entry.type === 'user' || entry.type === 'assistant') {
227
- messageCount++;
228
- }
229
- } catch {
230
- // skip malformed lines
231
- }
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;
232
241
  }
233
242
  // Find the first real user message (skip system caveats, commands, tool results)
243
+ const lines = content.split('\n');
234
244
  for (const line of lines) {
235
- if (!line.trim()) { continue; }
245
+ if (!line.trim()) {
246
+ continue;
247
+ }
236
248
  try {
237
249
  const entry = JSON.parse(line);
238
- if (entry.type !== 'user') { continue; }
250
+ if (entry.type !== 'user') {
251
+ continue;
252
+ }
239
253
  const msg = entry.message;
240
- if (!msg?.content) { continue; }
254
+ if (!msg?.content) {
255
+ continue;
256
+ }
241
257
 
242
258
  // Extract text from content (can be string or array of blocks)
243
259
  let text = '';
@@ -256,14 +272,22 @@ function listSessionsForProject(projectDir: string): SessionInfo[] {
256
272
  }
257
273
  }
258
274
 
259
- if (!text) { continue; }
275
+ if (!text) {
276
+ continue;
277
+ }
260
278
 
261
279
  // Skip system-injected caveats and command outputs
262
- if (text.startsWith('<local-command') ||
263
- text.startsWith('<command-name>') ||
264
- text.startsWith('<local-command-stdout>') ||
265
- text.startsWith('<system-reminder>') ||
266
- text.startsWith('<task-notification>')) {
280
+ // Keep aligned with cleanTitle() tag stripping
281
+ if (
282
+ text.startsWith('<local-command') ||
283
+ text.startsWith('<command-name>') ||
284
+ text.startsWith('<command-message>') ||
285
+ text.startsWith('<command-args>') ||
286
+ text.startsWith('<local-command-stdout>') ||
287
+ text.startsWith('<local-command-caveat>') ||
288
+ text.startsWith('<system-reminder>') ||
289
+ text.startsWith('<task-notification>')
290
+ ) {
267
291
  continue;
268
292
  }
269
293
 
@@ -299,3 +323,39 @@ function listSessionsForProject(projectDir: string): SessionInfo[] {
299
323
  return [];
300
324
  }
301
325
  }
326
+
327
+ function readCwdFromProjectDir(projectDir: string, sessions: SessionInfo[]): string {
328
+ for (const session of sessions) {
329
+ try {
330
+ const filePath = path.join(projectDir, `${session.id}.jsonl`);
331
+ if (!fs.existsSync(filePath)) {
332
+ continue;
333
+ }
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;
352
+ }
353
+ } catch {
354
+ // skip malformed first line
355
+ }
356
+ } catch {
357
+ // skip unreadable files
358
+ }
359
+ }
360
+ return '';
361
+ }
@@ -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
+ }
@@ -1,7 +1,6 @@
1
1
  import Database from 'better-sqlite3';
2
2
  import * as crypto from 'crypto';
3
3
  import * as fs from 'fs';
4
- import * as path from 'path';
5
4
 
6
5
  function shortHash(input: string): string {
7
6
  return crypto.createHash('sha256').update(input).digest('hex').slice(0, 8);
@@ -9,18 +8,14 @@ function shortHash(input: string): string {
9
8
 
10
9
  import type { ConversationMessage, MessagePart, ProjectGroup, SessionInfo } from './types';
11
10
 
12
- const OPENCODE_DB_PATH = path.join(
13
- process.env.HOME || '',
14
- '.local',
15
- 'share',
16
- 'opencode',
17
- 'opencode.db'
18
- );
11
+ import { resolveOpenCodeDbPath } from './opencode-db-path';
12
+
13
+ const OPENCODE_DB_PATH = resolveOpenCodeDbPath();
19
14
 
20
15
  export function getOpenCodeConversation(
21
16
  sessionId: string,
22
17
  offset = 0,
23
- limit = 100
18
+ limit = 200
24
19
  ): ConversationMessage[] {
25
20
  const db = getDb();
26
21
  if (!db) {
@@ -28,15 +23,18 @@ export function getOpenCodeConversation(
28
23
  }
29
24
 
30
25
  try {
31
- // Get messages for this session
26
+ // Get the LAST `limit` messages (most recent conversation)
27
+ // by using a subquery to reverse the order
32
28
  const messages = db
33
29
  .prepare(
34
30
  `
35
- SELECT id, session_id, time_created, data
36
- FROM message
37
- WHERE session_id = ?
38
- ORDER BY time_created ASC
39
- LIMIT ? OFFSET ?
31
+ SELECT id, session_id, time_created, data FROM (
32
+ SELECT id, session_id, time_created, data
33
+ FROM message
34
+ WHERE session_id = ?
35
+ ORDER BY time_created DESC
36
+ LIMIT ? OFFSET ?
37
+ ) ORDER BY time_created ASC
40
38
  `
41
39
  )
42
40
  .all(sessionId, limit, offset) as {
@@ -0,0 +1,103 @@
1
+ import { readdirSync, readFileSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join } from 'path';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Types
7
+ // ---------------------------------------------------------------------------
8
+
9
+ export interface DetectedProcess {
10
+ command: 'claude' | 'opencode';
11
+ cwd: string;
12
+ kind: string;
13
+ pid: number;
14
+ projectPath: string;
15
+ sessionId: string;
16
+ startedAt: number;
17
+ }
18
+
19
+ interface ClaudeSessionFile {
20
+ cwd: string;
21
+ entrypoint: string;
22
+ kind: string;
23
+ pid: number;
24
+ sessionId: string;
25
+ startedAt: number;
26
+ }
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Helpers
30
+ // ---------------------------------------------------------------------------
31
+
32
+ /** Encode a cwd path to the Claude Code project directory format. */
33
+ function cwdToProjectPath(cwd: string): string {
34
+ return cwd.replace(/\//g, '-');
35
+ }
36
+
37
+ /** Check if a process with the given PID is alive. */
38
+ function isProcessAlive(pid: number): boolean {
39
+ try {
40
+ process.kill(pid, 0);
41
+ return true;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // Main detector
49
+ // ---------------------------------------------------------------------------
50
+
51
+ const CLAUDE_SESSIONS_DIR = join(homedir(), '.claude', 'sessions');
52
+
53
+ /**
54
+ * Scan ~/.claude/sessions/*.json to find running Claude Code processes.
55
+ * Each file is named <PID>.json and contains:
56
+ * { pid, sessionId, cwd, startedAt, kind, entrypoint }
57
+ *
58
+ * For each file we verify the PID is still alive via process.kill(pid, 0).
59
+ */
60
+ export function detectRunningAISessions(): DetectedProcess[] {
61
+ const results: DetectedProcess[] = [];
62
+
63
+ // --- Claude Code sessions ---
64
+ try {
65
+ const files = readdirSync(CLAUDE_SESSIONS_DIR).filter((f) => f.endsWith('.json'));
66
+
67
+ for (const file of files) {
68
+ try {
69
+ const raw = readFileSync(join(CLAUDE_SESSIONS_DIR, file), 'utf-8');
70
+ const data = JSON.parse(raw) as ClaudeSessionFile;
71
+
72
+ if (!data.pid || !data.sessionId || !data.cwd) {
73
+ continue;
74
+ }
75
+
76
+ if (!isProcessAlive(data.pid)) {
77
+ continue;
78
+ }
79
+
80
+ results.push({
81
+ command: 'claude',
82
+ cwd: data.cwd,
83
+ kind: data.kind || 'interactive',
84
+ pid: data.pid,
85
+ projectPath: cwdToProjectPath(data.cwd),
86
+ sessionId: data.sessionId,
87
+ startedAt: data.startedAt || 0,
88
+ });
89
+ } catch {
90
+ // Skip malformed or unreadable files
91
+ }
92
+ }
93
+ } catch {
94
+ // ~/.claude/sessions/ may not exist — that's fine
95
+ }
96
+
97
+ // Sort by startedAt descending (most recent first)
98
+ results.sort((a, b) => b.startedAt - a.startedAt);
99
+
100
+ // TODO: Add OpenCode process detection (check running opencode processes or query SQLite DB)
101
+
102
+ return results;
103
+ }
@@ -1,33 +1,22 @@
1
+ // Re-export generated types that match 1:1
2
+ export type { MessageRole, ProjectGroup, SessionInfo } from '$generated/types';
3
+ import type { MessageRole } from '$generated/types';
4
+
5
+ // ── Local interfaces ─────────────────────────────────────────────────
6
+ // These remain local because the generated versions differ structurally:
7
+ // generated MessagePart uses wrapper classes (CMessagePartTextPart, etc.)
8
+ // and part types use `type: string` instead of string literals needed
9
+ // for discriminated unions. Declared as interfaces per ESLint rules.
10
+
1
11
  export interface ConversationMessage {
2
12
  id: string;
3
13
  parts: MessagePart[];
4
- role: 'assistant' | 'system' | 'user';
14
+ role: MessageRole;
5
15
  timestamp: string;
6
16
  }
7
17
 
8
18
  export type MessagePart = TextPart | ThinkingPart | ToolResultPart | ToolUsePart;
9
19
 
10
- export interface ProjectGroup {
11
- fullPath: string;
12
- id: string;
13
- lastModified: string;
14
- name: string;
15
- sessionCount: number;
16
- sessions: SessionInfo[];
17
- }
18
-
19
- export interface SessionInfo {
20
- created: string;
21
- gitBranch: string;
22
- id: string;
23
- messageCount: number;
24
- modified: string;
25
- projectPath: string;
26
- source: 'claude-code' | 'opencode';
27
- summary: string;
28
- title: string;
29
- }
30
-
31
20
  export interface TextPart {
32
21
  content: string;
33
22
  type: 'text';