@juspay/shooter 1.1.0 → 1.3.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 (332) hide show
  1. package/bin/shooter.cjs +182 -31
  2. package/build/client/_app/immutable/assets/{0.DC5pAwP3.css → 0.BhZOCxO4.css} +1 -1
  3. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.br +0 -0
  4. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.gz +0 -0
  5. package/build/client/_app/immutable/assets/1.BYutk3aU.css +1 -0
  6. package/build/client/_app/immutable/assets/1.BYutk3aU.css.br +0 -0
  7. package/build/client/_app/immutable/assets/1.BYutk3aU.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/{3.BoXp0JoS.css → 3.DGDHCVnW.css} +1 -1
  9. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.br +0 -0
  10. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.gz +0 -0
  11. package/build/client/_app/immutable/assets/4.BFUut--w.css +1 -0
  12. package/build/client/_app/immutable/assets/4.BFUut--w.css.br +0 -0
  13. package/build/client/_app/immutable/assets/4.BFUut--w.css.gz +0 -0
  14. package/build/client/_app/immutable/assets/5.BTOx7yt7.css +1 -0
  15. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.br +0 -0
  16. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.gz +0 -0
  17. package/build/client/_app/immutable/assets/{7.PyEFVv_s.css → 7.DwS5ZHBh.css} +1 -1
  18. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.br +0 -0
  19. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.gz +0 -0
  20. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css +1 -0
  21. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.br +0 -0
  22. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.gz +0 -0
  23. package/build/client/_app/immutable/chunks/B5NAKyil.js +20 -0
  24. package/build/client/_app/immutable/chunks/B5NAKyil.js.br +0 -0
  25. package/build/client/_app/immutable/chunks/B5NAKyil.js.gz +0 -0
  26. package/build/client/_app/immutable/chunks/B8XegpSE.js +1 -0
  27. package/build/client/_app/immutable/chunks/B8XegpSE.js.br +0 -0
  28. package/build/client/_app/immutable/chunks/B8XegpSE.js.gz +0 -0
  29. package/build/client/_app/immutable/chunks/{50RPd5u3.js → B8zoBsv3.js} +1 -1
  30. package/build/client/_app/immutable/chunks/B8zoBsv3.js.br +0 -0
  31. package/build/client/_app/immutable/chunks/B8zoBsv3.js.gz +0 -0
  32. package/build/client/_app/immutable/chunks/BLszSzTT.js +1 -0
  33. package/build/client/_app/immutable/chunks/BLszSzTT.js.br +0 -0
  34. package/build/client/_app/immutable/chunks/BLszSzTT.js.gz +0 -0
  35. package/build/client/_app/immutable/chunks/BOYo8yTr.js +1 -0
  36. package/build/client/_app/immutable/chunks/BOYo8yTr.js.br +0 -0
  37. package/build/client/_app/immutable/chunks/BOYo8yTr.js.gz +0 -0
  38. package/build/client/_app/immutable/chunks/Bu1aqm5j.js +1 -0
  39. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.br +0 -0
  40. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.gz +0 -0
  41. package/build/client/_app/immutable/chunks/{CdL99jkG.js → CNmDAqoQ.js} +1 -1
  42. package/build/client/_app/immutable/chunks/CNmDAqoQ.js.br +0 -0
  43. package/build/client/_app/immutable/chunks/CNmDAqoQ.js.gz +0 -0
  44. package/build/client/_app/immutable/chunks/{ClK4wZbC.js → CQjSATpv.js} +16 -16
  45. package/build/client/_app/immutable/chunks/CQjSATpv.js.br +0 -0
  46. package/build/client/_app/immutable/chunks/CQjSATpv.js.gz +0 -0
  47. package/build/client/_app/immutable/chunks/{CojFyTPp.js → CSoRdFvv.js} +1 -1
  48. package/build/client/_app/immutable/chunks/CSoRdFvv.js.br +0 -0
  49. package/build/client/_app/immutable/chunks/CSoRdFvv.js.gz +0 -0
  50. package/build/client/_app/immutable/chunks/{tjbnEgXP.js → CZHsSL_X.js} +1 -1
  51. package/build/client/_app/immutable/chunks/CZHsSL_X.js.br +0 -0
  52. package/build/client/_app/immutable/chunks/CZHsSL_X.js.gz +0 -0
  53. package/build/client/_app/immutable/chunks/CrVuYlkB.js +1 -0
  54. package/build/client/_app/immutable/chunks/CrVuYlkB.js.br +0 -0
  55. package/build/client/_app/immutable/chunks/CrVuYlkB.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/D3Vl-Qqr.js +1 -0
  57. package/build/client/_app/immutable/chunks/D3Vl-Qqr.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/D3Vl-Qqr.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/DVkn4r72.js +1 -0
  60. package/build/client/_app/immutable/chunks/DVkn4r72.js.br +0 -0
  61. package/build/client/_app/immutable/chunks/DVkn4r72.js.gz +0 -0
  62. package/build/client/_app/immutable/chunks/DjsDGxCa.js +41 -0
  63. package/build/client/_app/immutable/chunks/DjsDGxCa.js.br +0 -0
  64. package/build/client/_app/immutable/chunks/DjsDGxCa.js.gz +0 -0
  65. package/build/client/_app/immutable/chunks/UJOiqIYE.js +1 -0
  66. package/build/client/_app/immutable/chunks/UJOiqIYE.js.br +0 -0
  67. package/build/client/_app/immutable/chunks/UJOiqIYE.js.gz +0 -0
  68. package/build/client/_app/immutable/chunks/r0JawsZc.js +2 -0
  69. package/build/client/_app/immutable/chunks/r0JawsZc.js.br +0 -0
  70. package/build/client/_app/immutable/chunks/r0JawsZc.js.gz +0 -0
  71. package/build/client/_app/immutable/entry/app.CWzZbNpA.js +2 -0
  72. package/build/client/_app/immutable/entry/app.CWzZbNpA.js.br +0 -0
  73. package/build/client/_app/immutable/entry/app.CWzZbNpA.js.gz +0 -0
  74. package/build/client/_app/immutable/entry/start.t0E4BXrO.js +1 -0
  75. package/build/client/_app/immutable/entry/start.t0E4BXrO.js.br +2 -0
  76. package/build/client/_app/immutable/entry/start.t0E4BXrO.js.gz +0 -0
  77. package/build/client/_app/immutable/nodes/0.5I21KR7K.js +1 -0
  78. package/build/client/_app/immutable/nodes/0.5I21KR7K.js.br +0 -0
  79. package/build/client/_app/immutable/nodes/0.5I21KR7K.js.gz +0 -0
  80. package/build/client/_app/immutable/nodes/1.BDCm0X_6.js +1 -0
  81. package/build/client/_app/immutable/nodes/1.BDCm0X_6.js.br +0 -0
  82. package/build/client/_app/immutable/nodes/1.BDCm0X_6.js.gz +0 -0
  83. package/build/client/_app/immutable/nodes/2.CKjSEOom.js +1 -0
  84. package/build/client/_app/immutable/nodes/2.CKjSEOom.js.br +0 -0
  85. package/build/client/_app/immutable/nodes/2.CKjSEOom.js.gz +0 -0
  86. package/build/client/_app/immutable/nodes/3.3yohCM25.js +3 -0
  87. package/build/client/_app/immutable/nodes/3.3yohCM25.js.br +0 -0
  88. package/build/client/_app/immutable/nodes/3.3yohCM25.js.gz +0 -0
  89. package/build/client/_app/immutable/nodes/4.pRflZhvu.js +1 -0
  90. package/build/client/_app/immutable/nodes/4.pRflZhvu.js.br +0 -0
  91. package/build/client/_app/immutable/nodes/4.pRflZhvu.js.gz +0 -0
  92. package/build/client/_app/immutable/nodes/5.Co1ngwGh.js +4 -0
  93. package/build/client/_app/immutable/nodes/5.Co1ngwGh.js.br +0 -0
  94. package/build/client/_app/immutable/nodes/5.Co1ngwGh.js.gz +0 -0
  95. package/build/client/_app/immutable/nodes/6.CUnGGKik.js +2 -0
  96. package/build/client/_app/immutable/nodes/6.CUnGGKik.js.br +0 -0
  97. package/build/client/_app/immutable/nodes/6.CUnGGKik.js.gz +0 -0
  98. package/build/client/_app/immutable/nodes/7.CgvPBG9m.js +2 -0
  99. package/build/client/_app/immutable/nodes/7.CgvPBG9m.js.br +0 -0
  100. package/build/client/_app/immutable/nodes/7.CgvPBG9m.js.gz +0 -0
  101. package/build/client/_app/version.json +1 -1
  102. package/build/client/_app/version.json.br +0 -0
  103. package/build/client/_app/version.json.gz +0 -0
  104. package/build/client/manifest.json +13 -0
  105. package/build/client/manifest.json.br +0 -0
  106. package/build/client/manifest.json.gz +0 -0
  107. package/build/server/chunks/0-CYsoSMA0.js +9 -0
  108. package/build/server/chunks/0-CYsoSMA0.js.map +1 -0
  109. package/build/server/chunks/1-BSsLbzC1.js +9 -0
  110. package/build/server/chunks/1-BSsLbzC1.js.map +1 -0
  111. package/build/server/chunks/2-De1V922H.js +9 -0
  112. package/build/server/chunks/2-De1V922H.js.map +1 -0
  113. package/build/server/chunks/3-Ck7ewhOX.js +9 -0
  114. package/build/server/chunks/3-Ck7ewhOX.js.map +1 -0
  115. package/build/server/chunks/4-Dl1IrE-x.js +9 -0
  116. package/build/server/chunks/4-Dl1IrE-x.js.map +1 -0
  117. package/build/server/chunks/5-CkT7yrsJ.js +9 -0
  118. package/build/server/chunks/{5-D0wB7nfE.js.map → 5-CkT7yrsJ.js.map} +1 -1
  119. package/build/server/chunks/6-DMkV5QEZ.js +9 -0
  120. package/build/server/chunks/6-DMkV5QEZ.js.map +1 -0
  121. package/build/server/chunks/7-b4mtbSZL.js +9 -0
  122. package/build/server/chunks/7-b4mtbSZL.js.map +1 -0
  123. package/build/server/chunks/{Button-C7D5W6wV.js → Button-Cs1aE6ka.js} +2 -2
  124. package/build/server/chunks/{Button-C7D5W6wV.js.map → Button-Cs1aE6ka.js.map} +1 -1
  125. package/build/server/chunks/{EmptyState-Ci4pSpmY.js → EmptyState-DDFH1K8g.js} +10 -4
  126. package/build/server/chunks/EmptyState-DDFH1K8g.js.map +1 -0
  127. package/build/server/chunks/{Icon-DyrkHVnV.js → Icon-CEUrotA6.js} +3 -3
  128. package/build/server/chunks/{Icon-DyrkHVnV.js.map → Icon-CEUrotA6.js.map} +1 -1
  129. package/build/server/chunks/{Shimmer-BITK6wrm.js → Shimmer-DB8W1zt6.js} +2 -2
  130. package/build/server/chunks/{Shimmer-BITK6wrm.js.map → Shimmer-DB8W1zt6.js.map} +1 -1
  131. package/build/server/chunks/_error.svelte-uCOJNxvr.js +39 -0
  132. package/build/server/chunks/_error.svelte-uCOJNxvr.js.map +1 -0
  133. package/build/server/chunks/{_layout.svelte-CO4f8UD7.js → _layout.svelte-CtWmEJwe.js} +5 -25
  134. package/build/server/chunks/_layout.svelte-CtWmEJwe.js.map +1 -0
  135. package/build/server/chunks/{_page.svelte-C6bns9aQ.js → _page.svelte-BcZaKdX9.js} +13 -9
  136. package/build/server/chunks/_page.svelte-BcZaKdX9.js.map +1 -0
  137. package/build/server/chunks/{_page.svelte-3Cc3NMAP.js → _page.svelte-BdYynOck.js} +18 -14
  138. package/build/server/chunks/_page.svelte-BdYynOck.js.map +1 -0
  139. package/build/server/chunks/{_page.svelte-CFCONiDK.js → _page.svelte-BgevQjq1.js} +16 -12
  140. package/build/server/chunks/_page.svelte-BgevQjq1.js.map +1 -0
  141. package/build/server/chunks/{_page.svelte-DskND_G9.js → _page.svelte-CVq6tRb3.js} +8 -8
  142. package/build/server/chunks/_page.svelte-CVq6tRb3.js.map +1 -0
  143. package/build/server/chunks/{_page.svelte-rTrWmhOp.js → _page.svelte-CxWcQ0Am.js} +8 -8
  144. package/build/server/chunks/_page.svelte-CxWcQ0Am.js.map +1 -0
  145. package/build/server/chunks/{_page.svelte-C0p3HsIW.js → _page.svelte-DO4oa_LY.js} +11 -13
  146. package/build/server/chunks/_page.svelte-DO4oa_LY.js.map +1 -0
  147. package/build/server/chunks/{_server.ts-CS5H5klP.js → _server.ts-CAxsWKvS.js} +14 -10
  148. package/build/server/chunks/_server.ts-CAxsWKvS.js.map +1 -0
  149. package/build/server/chunks/{_server.ts-C8slOHB0.js → _server.ts-CTpcLUH8.js} +3 -2
  150. package/build/server/chunks/_server.ts-CTpcLUH8.js.map +1 -0
  151. package/build/server/chunks/_server.ts-CtH0dhUp.js +71 -0
  152. package/build/server/chunks/_server.ts-CtH0dhUp.js.map +1 -0
  153. package/build/server/chunks/{_server.ts-DhTrdlWH.js → _server.ts-DB_Kg97c.js} +14 -3
  154. package/build/server/chunks/_server.ts-DB_Kg97c.js.map +1 -0
  155. package/build/server/chunks/_server.ts-DYpJImqd.js +99 -0
  156. package/build/server/chunks/_server.ts-DYpJImqd.js.map +1 -0
  157. package/build/server/chunks/{_server.ts-DpEVfp8W.js → _server.ts-Deok2y88.js} +58 -40
  158. package/build/server/chunks/_server.ts-Deok2y88.js.map +1 -0
  159. package/build/server/chunks/{_server.ts-uHUi-4cd.js → _server.ts-vekTmWAx.js} +3 -2
  160. package/build/server/chunks/_server.ts-vekTmWAx.js.map +1 -0
  161. package/build/server/chunks/{client2-BjxIYuno.js → client-BdGHe_hY.js} +4 -4
  162. package/build/server/chunks/client-BdGHe_hY.js.map +1 -0
  163. package/build/server/chunks/client2-CCBGA-2V.js +7 -0
  164. package/build/server/chunks/client2-CCBGA-2V.js.map +1 -0
  165. package/build/server/chunks/{index-Cnl871UW.js → index-DwaY1cAm.js} +2 -2
  166. package/build/server/chunks/{index-Cnl871UW.js.map → index-DwaY1cAm.js.map} +1 -1
  167. package/build/server/chunks/{index-server-CUC9Jt7r.js → index-server-CrDaL06Y.js} +2 -2
  168. package/build/server/chunks/{index-server-CUC9Jt7r.js.map → index-server-CrDaL06Y.js.map} +1 -1
  169. package/build/server/chunks/{index2-HA3VTH7y.js → index2-CgclKpUj.js} +2 -2
  170. package/build/server/chunks/{index2-HA3VTH7y.js.map → index2-CgclKpUj.js.map} +1 -1
  171. package/build/server/chunks/opencode-db-path-DcfhJtJy.js +15 -0
  172. package/build/server/chunks/opencode-db-path-DcfhJtJy.js.map +1 -0
  173. package/build/server/chunks/{pty-manager-DR0Wt2Ac.js → pty-manager-BQVB7IVj.js} +17 -15
  174. package/build/server/chunks/pty-manager-BQVB7IVj.js.map +1 -0
  175. package/build/server/chunks/{root-DhswcH6o.js → root-DDSnEAZv.js} +2 -2
  176. package/build/server/chunks/{root-DhswcH6o.js.map → root-DDSnEAZv.js.map} +1 -1
  177. package/build/server/chunks/{state.svelte-2Lellg7t.js → state.svelte-hBbXlUak.js} +3 -3
  178. package/build/server/chunks/{state.svelte-2Lellg7t.js.map → state.svelte-hBbXlUak.js.map} +1 -1
  179. package/build/server/chunks/stores-DHNzYNpX.js +28 -0
  180. package/build/server/chunks/stores-DHNzYNpX.js.map +1 -0
  181. package/build/server/index.js +5 -5
  182. package/build/server/index.js.map +1 -1
  183. package/build/server/manifest.js +30 -16
  184. package/build/server/manifest.js.map +1 -1
  185. package/package.json +1 -1
  186. package/scripts/setup.cjs +87 -13
  187. package/server.ts +3 -0
  188. package/src/app.html +3 -0
  189. package/src/lib/modules/client/common/cache.ts +10 -2
  190. package/src/lib/modules/client/common/index.ts +1 -1
  191. package/src/lib/modules/client/common/markdown.ts +22 -1
  192. package/src/lib/modules/client/common/time.ts +13 -11
  193. package/src/lib/modules/client/terminal/ChatView.svelte +324 -67
  194. package/src/lib/modules/client/terminal/ConnectionStatus.svelte +1 -0
  195. package/src/lib/modules/client/terminal/xterm-wrapper.ts +4 -1
  196. package/src/lib/modules/server/sessions/jsonl-reader.ts +43 -28
  197. package/src/lib/modules/server/sessions/opencode-db-path.ts +26 -0
  198. package/src/lib/modules/server/sessions/opencode-reader.ts +13 -15
  199. package/src/lib/modules/server/sessions/process-detector.ts +103 -0
  200. package/src/lib/modules/server/terminal/opencode-watcher.ts +3 -14
  201. package/src/lib/modules/server/terminal/pty-manager.ts +20 -8
  202. package/src/lib/modules/server/ws/session-handler.ts +282 -104
  203. package/src/lib/theme.css +30 -0
  204. package/src/routes/+error.svelte +94 -0
  205. package/src/routes/+page.svelte +18 -8
  206. package/src/routes/api/health/+server.ts +14 -2
  207. package/src/routes/api/sessions/+server.ts +12 -4
  208. package/src/routes/api/sessions/connect/+server.ts +125 -0
  209. package/src/routes/api/sessions/detect/+server.ts +27 -0
  210. package/src/routes/api/terminals/+server.ts +12 -9
  211. package/src/routes/config/+page.svelte +22 -1
  212. package/src/routes/project/+page.svelte +159 -8
  213. package/src/routes/session/[id]/+page.svelte +477 -299
  214. package/src/routes/terminals/+page.svelte +14 -3
  215. package/src/routes/terminals/[id]/+page.svelte +25 -0
  216. package/svelte.config.js +1 -1
  217. package/build/client/_app/immutable/assets/0.DC5pAwP3.css.br +0 -0
  218. package/build/client/_app/immutable/assets/0.DC5pAwP3.css.gz +0 -0
  219. package/build/client/_app/immutable/assets/3.BoXp0JoS.css.br +0 -0
  220. package/build/client/_app/immutable/assets/3.BoXp0JoS.css.gz +0 -0
  221. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +0 -1
  222. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
  223. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
  224. package/build/client/_app/immutable/assets/5.DRjApZQW.css +0 -1
  225. package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
  226. package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
  227. package/build/client/_app/immutable/assets/7.PyEFVv_s.css.br +0 -0
  228. package/build/client/_app/immutable/assets/7.PyEFVv_s.css.gz +0 -0
  229. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +0 -1
  230. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
  231. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
  232. package/build/client/_app/immutable/chunks/50RPd5u3.js.br +0 -0
  233. package/build/client/_app/immutable/chunks/50RPd5u3.js.gz +0 -0
  234. package/build/client/_app/immutable/chunks/BDC7XD4o.js +0 -1
  235. package/build/client/_app/immutable/chunks/BDC7XD4o.js.br +0 -0
  236. package/build/client/_app/immutable/chunks/BDC7XD4o.js.gz +0 -0
  237. package/build/client/_app/immutable/chunks/BeONA6_G.js +0 -2
  238. package/build/client/_app/immutable/chunks/BeONA6_G.js.br +0 -0
  239. package/build/client/_app/immutable/chunks/BeONA6_G.js.gz +0 -0
  240. package/build/client/_app/immutable/chunks/BygiiMA0.js +0 -1
  241. package/build/client/_app/immutable/chunks/BygiiMA0.js.br +0 -0
  242. package/build/client/_app/immutable/chunks/BygiiMA0.js.gz +0 -0
  243. package/build/client/_app/immutable/chunks/CGLrx-H5.js +0 -1
  244. package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
  245. package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
  246. package/build/client/_app/immutable/chunks/CHvUpVYv.js +0 -1
  247. package/build/client/_app/immutable/chunks/CHvUpVYv.js.br +0 -0
  248. package/build/client/_app/immutable/chunks/CHvUpVYv.js.gz +0 -0
  249. package/build/client/_app/immutable/chunks/CbqC9BW7.js +0 -1
  250. package/build/client/_app/immutable/chunks/CbqC9BW7.js.br +0 -2
  251. package/build/client/_app/immutable/chunks/CbqC9BW7.js.gz +0 -0
  252. package/build/client/_app/immutable/chunks/CdL99jkG.js.br +0 -0
  253. package/build/client/_app/immutable/chunks/CdL99jkG.js.gz +0 -0
  254. package/build/client/_app/immutable/chunks/ClK4wZbC.js.br +0 -0
  255. package/build/client/_app/immutable/chunks/ClK4wZbC.js.gz +0 -0
  256. package/build/client/_app/immutable/chunks/CojFyTPp.js.br +0 -0
  257. package/build/client/_app/immutable/chunks/CojFyTPp.js.gz +0 -0
  258. package/build/client/_app/immutable/chunks/DREFAyhX.js +0 -60
  259. package/build/client/_app/immutable/chunks/DREFAyhX.js.br +0 -0
  260. package/build/client/_app/immutable/chunks/DREFAyhX.js.gz +0 -0
  261. package/build/client/_app/immutable/chunks/K_aHH2KN.js +0 -1
  262. package/build/client/_app/immutable/chunks/K_aHH2KN.js.br +0 -0
  263. package/build/client/_app/immutable/chunks/K_aHH2KN.js.gz +0 -0
  264. package/build/client/_app/immutable/chunks/Ona8oofC.js +0 -1
  265. package/build/client/_app/immutable/chunks/Ona8oofC.js.br +0 -0
  266. package/build/client/_app/immutable/chunks/Ona8oofC.js.gz +0 -0
  267. package/build/client/_app/immutable/chunks/tjbnEgXP.js.br +0 -0
  268. package/build/client/_app/immutable/chunks/tjbnEgXP.js.gz +0 -0
  269. package/build/client/_app/immutable/entry/app.anqwe7ZL.js +0 -2
  270. package/build/client/_app/immutable/entry/app.anqwe7ZL.js.br +0 -0
  271. package/build/client/_app/immutable/entry/app.anqwe7ZL.js.gz +0 -0
  272. package/build/client/_app/immutable/entry/start.BV2VRv6h.js +0 -1
  273. package/build/client/_app/immutable/entry/start.BV2VRv6h.js.br +0 -2
  274. package/build/client/_app/immutable/entry/start.BV2VRv6h.js.gz +0 -0
  275. package/build/client/_app/immutable/nodes/0.D0i5MqcI.js +0 -1
  276. package/build/client/_app/immutable/nodes/0.D0i5MqcI.js.br +0 -0
  277. package/build/client/_app/immutable/nodes/0.D0i5MqcI.js.gz +0 -0
  278. package/build/client/_app/immutable/nodes/1.DN5n5c6F.js +0 -1
  279. package/build/client/_app/immutable/nodes/1.DN5n5c6F.js.br +0 -0
  280. package/build/client/_app/immutable/nodes/1.DN5n5c6F.js.gz +0 -0
  281. package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js +0 -1
  282. package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js.br +0 -0
  283. package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js.gz +0 -0
  284. package/build/client/_app/immutable/nodes/3.CEkigHDv.js +0 -3
  285. package/build/client/_app/immutable/nodes/3.CEkigHDv.js.br +0 -0
  286. package/build/client/_app/immutable/nodes/3.CEkigHDv.js.gz +0 -0
  287. package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js +0 -1
  288. package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js.br +0 -0
  289. package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js.gz +0 -0
  290. package/build/client/_app/immutable/nodes/5.shitbtHc.js +0 -1
  291. package/build/client/_app/immutable/nodes/5.shitbtHc.js.br +0 -0
  292. package/build/client/_app/immutable/nodes/5.shitbtHc.js.gz +0 -0
  293. package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js +0 -2
  294. package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js.br +0 -0
  295. package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js.gz +0 -0
  296. package/build/client/_app/immutable/nodes/7.D0CrR6pl.js +0 -2
  297. package/build/client/_app/immutable/nodes/7.D0CrR6pl.js.br +0 -0
  298. package/build/client/_app/immutable/nodes/7.D0CrR6pl.js.gz +0 -0
  299. package/build/server/chunks/0-Cs1dzfRz.js +0 -9
  300. package/build/server/chunks/0-Cs1dzfRz.js.map +0 -1
  301. package/build/server/chunks/1-BCSX7oED.js +0 -9
  302. package/build/server/chunks/1-BCSX7oED.js.map +0 -1
  303. package/build/server/chunks/2-6gkeO8b4.js +0 -9
  304. package/build/server/chunks/2-6gkeO8b4.js.map +0 -1
  305. package/build/server/chunks/3-DH9J9Vsc.js +0 -9
  306. package/build/server/chunks/3-DH9J9Vsc.js.map +0 -1
  307. package/build/server/chunks/4-Rzy5TYjl.js +0 -9
  308. package/build/server/chunks/4-Rzy5TYjl.js.map +0 -1
  309. package/build/server/chunks/5-D0wB7nfE.js +0 -9
  310. package/build/server/chunks/6-DR2ABDPq.js +0 -9
  311. package/build/server/chunks/6-DR2ABDPq.js.map +0 -1
  312. package/build/server/chunks/7-D-oQJsia.js +0 -9
  313. package/build/server/chunks/7-D-oQJsia.js.map +0 -1
  314. package/build/server/chunks/EmptyState-Ci4pSpmY.js.map +0 -1
  315. package/build/server/chunks/_layout.svelte-CO4f8UD7.js.map +0 -1
  316. package/build/server/chunks/_page.svelte-3Cc3NMAP.js.map +0 -1
  317. package/build/server/chunks/_page.svelte-C0p3HsIW.js.map +0 -1
  318. package/build/server/chunks/_page.svelte-C6bns9aQ.js.map +0 -1
  319. package/build/server/chunks/_page.svelte-CFCONiDK.js.map +0 -1
  320. package/build/server/chunks/_page.svelte-DskND_G9.js.map +0 -1
  321. package/build/server/chunks/_page.svelte-rTrWmhOp.js.map +0 -1
  322. package/build/server/chunks/_server.ts-C8slOHB0.js.map +0 -1
  323. package/build/server/chunks/_server.ts-CS5H5klP.js.map +0 -1
  324. package/build/server/chunks/_server.ts-DhTrdlWH.js.map +0 -1
  325. package/build/server/chunks/_server.ts-DpEVfp8W.js.map +0 -1
  326. package/build/server/chunks/_server.ts-uHUi-4cd.js.map +0 -1
  327. package/build/server/chunks/client-BYT9c0ig.js +0 -7
  328. package/build/server/chunks/client-BYT9c0ig.js.map +0 -1
  329. package/build/server/chunks/client2-BjxIYuno.js.map +0 -1
  330. package/build/server/chunks/error.svelte-BG_yE-Wt.js +0 -27
  331. package/build/server/chunks/error.svelte-BG_yE-Wt.js.map +0 -1
  332. package/build/server/chunks/pty-manager-DR0Wt2Ac.js.map +0 -1
@@ -6,6 +6,9 @@
6
6
  import type { MessageRole, TextContentBlock } from '$generated/types';
7
7
  import type { WebSocket } from 'ws';
8
8
 
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+
9
12
  import type { ConversationMessage, MessagePart } from '../sessions/types';
10
13
 
11
14
  // ── Types ────────────────────────────────────────────────────────────
@@ -42,6 +45,11 @@ interface ManagedTerminal {
42
45
  status: 'exited' | 'running';
43
46
  }
44
47
 
48
+ /** Extended PTY manager interface with list() for UUID-based terminal search. */
49
+ interface PtyManagerFullLike extends PtyManagerLike {
50
+ list: () => ManagedTerminal[];
51
+ }
52
+
45
53
  interface PtyManagerLike {
46
54
  getTerminal: (id: string) => ManagedTerminal | undefined;
47
55
  }
@@ -75,10 +83,13 @@ interface SessionWatcherLike {
75
83
  // ── Module-level references ──────────────────────────────────────────
76
84
 
77
85
  let _ptyManager: null | PtyManagerLike = null;
86
+ let _ptyManagerFull: null | PtyManagerFullLike = null;
78
87
  let _sessionWatcher: null | SessionWatcherLike = null;
79
88
 
80
89
  /** Per-connection state tracked for cleanup. */
81
90
  interface ConnectionState {
91
+ /** True when the session is file-only (no terminal backing it). */
92
+ isExternalSession: boolean;
82
93
  retryInterval: null | ReturnType<typeof setInterval>;
83
94
  terminalId: string;
84
95
  unsubscribe: (() => void) | null;
@@ -86,120 +97,69 @@ interface ConnectionState {
86
97
 
87
98
  /**
88
99
  * Handle a new WebSocket connection on the `/ws/session/:id` channel.
89
- * Sends full conversation history on connect, then streams new entries
90
- * as they appear in the session file.
100
+ * Accepts BOTH Shooter terminal IDs and external Claude Code session UUIDs.
101
+ *
102
+ * Resolution order:
103
+ * 1. Try `_ptyManager.getTerminal(id)` — works for Shooter terminal IDs.
104
+ * 2. Search all terminals for one whose `sessionFile` contains the UUID.
105
+ * 3. If still no terminal, treat as an external session — find the JSONL
106
+ * file directly and stream it via the session watcher.
91
107
  */
92
- export function handleSessionConnection(ws: WebSocket, terminalId: string): void {
93
- const state: ConnectionState = { retryInterval: null, terminalId, unsubscribe: null };
108
+ export function handleSessionConnection(ws: WebSocket, id: string): void {
109
+ const state: ConnectionState = {
110
+ isExternalSession: false,
111
+ retryInterval: null,
112
+ terminalId: id,
113
+ unsubscribe: null,
114
+ };
94
115
 
95
- // ── 1. Look up the terminal ──────────────────────────────────────
96
- if (!_ptyManager) {
97
- safeSend(ws, { message: 'PTY manager not initialised', type: 'error' });
98
- ws.close(1011, 'PTY manager not initialised');
99
- return;
100
- }
116
+ // ── 1. Try to resolve to a terminal ──────────────────────────────
117
+ let terminal: ManagedTerminal | undefined;
101
118
 
102
- const terminal = _ptyManager.getTerminal(terminalId);
103
- if (!terminal) {
104
- safeSend(ws, { message: `Terminal not found: ${terminalId}`, type: 'error' });
105
- ws.close(1008, 'Terminal not found');
106
- return;
107
- }
108
-
109
- // ── 2. Subscribe to session file ─────────────────────────────────
110
- subscribeToSession(ws, state, terminal);
119
+ if (_ptyManager) {
120
+ // 1a. Direct terminal ID lookup
121
+ terminal = _ptyManager.getTerminal(id);
111
122
 
112
- // ── 3. Handle messages from the client ───────────────────────────
113
- ws.on('message', (raw: Buffer | string) => {
114
- const data = typeof raw === 'string' ? raw : raw.toString('utf-8');
115
- const msg = parseClientMessage(data);
116
- if (!msg) {
117
- return;
123
+ // 1b. Search by session UUID in sessionFile paths
124
+ if (!terminal) {
125
+ terminal = findTerminalBySessionUuid(id);
118
126
  }
127
+ }
119
128
 
120
- try {
121
- switch (msg.type) {
122
- case 'cancel': {
123
- // Send SIGINT to the terminal process.
124
- const currentTerminal = _ptyManager?.getTerminal(state.terminalId);
125
- if (!currentTerminal || currentTerminal.status === 'exited') {
126
- safeSend(ws, { message: 'Terminal has exited', type: 'error' });
127
- return;
128
- }
129
- currentTerminal.pty.write('\x03');
130
- break;
131
- }
132
-
133
- case 'send-input': {
134
- // Write text + newline to PTY stdin (the Chat view sends complete
135
- // messages, not raw keystrokes).
136
- const currentTerminal = _ptyManager?.getTerminal(state.terminalId);
137
- if (!currentTerminal || currentTerminal.status === 'exited') {
138
- safeSend(ws, { message: 'Terminal has exited', type: 'error' });
139
- return;
140
- }
141
- currentTerminal.pty.write(`${msg.text}\n`);
142
- break;
143
- }
144
-
145
- case 'subscribe': {
146
- // (Re)subscribe to a different session. Clean up the old subscription
147
- // and attach to the new terminal.
148
- const newTerminal = _ptyManager?.getTerminal(msg.sessionId);
149
- if (!newTerminal) {
150
- safeSend(ws, {
151
- message: `Terminal not found: ${msg.sessionId}`,
152
- type: 'error',
153
- });
154
- return;
155
- }
156
-
157
- // Tear down old subscription and retry interval.
158
- if (state.retryInterval) {
159
- clearInterval(state.retryInterval);
160
- state.retryInterval = null;
161
- }
162
- if (state.unsubscribe) {
163
- state.unsubscribe();
164
- state.unsubscribe = null;
165
- }
166
-
167
- state.terminalId = msg.sessionId;
168
- subscribeToSession(ws, state, newTerminal);
169
- break;
170
- }
171
- }
172
- } catch (err) {
173
- const errMsg = err instanceof Error ? err.message : String(err);
174
- console.error(`[ws/session] Error handling ${msg.type} for ${state.terminalId}:`, errMsg);
175
- safeSend(ws, { message: `Failed to handle ${msg.type}: ${errMsg}`, type: 'error' });
176
- }
177
- });
129
+ // ── 2. If we found a terminal, use the normal flow ───────────────
130
+ if (terminal) {
131
+ state.terminalId = terminal.id;
132
+ subscribeToSession(ws, state, terminal);
133
+ wireClientMessages(ws, state);
134
+ wireCleanup(ws, state);
135
+ return;
136
+ }
178
137
 
179
- // ── 4. Cleanup on disconnect ─────────────────────────────────────
180
- ws.on('close', () => {
181
- if (state.retryInterval) {
182
- clearInterval(state.retryInterval);
183
- state.retryInterval = null;
184
- }
185
- if (state.unsubscribe) {
186
- state.unsubscribe();
187
- state.unsubscribe = null;
188
- }
189
- });
138
+ // ── 3. External session find JSONL file directly ───────────────
139
+ const jsonlPath = findJsonlFileForSession(id);
140
+ if (jsonlPath) {
141
+ state.isExternalSession = true;
142
+ subscribeToExternalSession(ws, state, jsonlPath);
143
+ wireClientMessages(ws, state);
144
+ wireCleanup(ws, state);
145
+ return;
146
+ }
190
147
 
191
- ws.on('error', () => {
192
- // Errors are followed by 'close', which handles cleanup.
193
- });
148
+ // Nothing found at all
149
+ safeSend(ws, { message: `Session not found: ${id}`, type: 'error' });
150
+ ws.close(1008, 'Session not found');
194
151
  }
195
152
 
196
- // ── Helpers ──────────────────────────────────────────────────────────
197
-
198
153
  /**
199
154
  * Register the PTY manager instance. Called once during server bootstrap.
155
+ * If the manager also exposes a `list()` method, it is stored as the full
156
+ * reference for UUID-based terminal search.
200
157
  */
201
158
  export function setPtyManager(manager: PtyManagerLike): void {
202
159
  _ptyManager = manager;
160
+ if ('list' in manager && typeof (manager as PtyManagerFullLike).list === 'function') {
161
+ _ptyManagerFull = manager as PtyManagerFullLike;
162
+ }
203
163
  }
204
164
 
205
165
  /**
@@ -209,8 +169,6 @@ export function setSessionWatcher(watcher: SessionWatcherLike): void {
209
169
  _sessionWatcher = watcher;
210
170
  }
211
171
 
212
- // ── Conversion: ConversationMessage → wire format ────────────────────
213
-
214
172
  /**
215
173
  * Convert ConversationMessage[] into HistoryMessage[] for the initial
216
174
  * `history` payload sent when a client connects.
@@ -275,6 +233,66 @@ function conversationToLive(msg: ConversationMessage): ServerMessage[] {
275
233
  return messages;
276
234
  }
277
235
 
236
+ /**
237
+ * Scan ~/.claude/projects/ for a JSONL file matching the given session UUID.
238
+ * Returns the absolute path if found, or null.
239
+ */
240
+ function findJsonlFileForSession(sessionId: string): null | string {
241
+ const claudeProjectsDir = path.join(process.env.HOME || '', '.claude', 'projects');
242
+
243
+ if (!fs.existsSync(claudeProjectsDir)) {
244
+ return null;
245
+ }
246
+
247
+ try {
248
+ const projectDirs = fs.readdirSync(claudeProjectsDir);
249
+ for (const dir of projectDirs) {
250
+ const fullDir = path.join(claudeProjectsDir, dir);
251
+ try {
252
+ if (!fs.statSync(fullDir).isDirectory()) {
253
+ continue;
254
+ }
255
+ } catch {
256
+ continue;
257
+ }
258
+
259
+ const jsonlPath = path.join(fullDir, `${sessionId}.jsonl`);
260
+ if (fs.existsSync(jsonlPath)) {
261
+ return jsonlPath;
262
+ }
263
+ }
264
+ } catch {
265
+ // Ignore filesystem errors
266
+ }
267
+
268
+ return null;
269
+ }
270
+
271
+ // ── Helpers ──────────────────────────────────────────────────────────
272
+
273
+ /**
274
+ * Search all managed terminals for one whose sessionFile contains the
275
+ * given session UUID. Returns the first match or undefined.
276
+ */
277
+ function findTerminalBySessionUuid(uuid: string): ManagedTerminal | undefined {
278
+ if (!_ptyManager) {
279
+ return undefined;
280
+ }
281
+
282
+ // getTerminal only takes an ID — we need to probe. The PtyManager
283
+ // exposes a list() method via its adapter, but the handler only has
284
+ // the PtyManagerLike interface with getTerminal(). We'll use the
285
+ // module-level _ptyManagerFull reference if available.
286
+ if (_ptyManagerFull) {
287
+ for (const t of _ptyManagerFull.list()) {
288
+ if (t.sessionFile && t.sessionFile.includes(`${uuid}.jsonl`)) {
289
+ return _ptyManager.getTerminal(t.id);
290
+ }
291
+ }
292
+ }
293
+ return undefined;
294
+ }
295
+
278
296
  /** Parse and validate an inbound client message. */
279
297
  function parseClientMessage(raw: string): ClientMessage | null {
280
298
  try {
@@ -308,7 +326,7 @@ function parseClientMessage(raw: string): ClientMessage | null {
308
326
  }
309
327
  }
310
328
 
311
- // ── Connection state ─────────────────────────────────────────────────
329
+ // ── Conversion: ConversationMessage → wire format ────────────────────
312
330
 
313
331
  /**
314
332
  * Map a single MessagePart to the HistoryPart wire format.
@@ -331,8 +349,6 @@ function partToHistoryPart(part: MessagePart): HistoryPart {
331
349
  }
332
350
  }
333
351
 
334
- // ── Main handler ─────────────────────────────────────────────────────
335
-
336
352
  /** Safely send a JSON message over a WebSocket. */
337
353
  function safeSend(ws: WebSocket, msg: ServerMessage): boolean {
338
354
  try {
@@ -346,6 +362,54 @@ function safeSend(ws: WebSocket, msg: ServerMessage): boolean {
346
362
  }
347
363
  }
348
364
 
365
+ /**
366
+ * Subscribe to an external session (one with no Shooter terminal).
367
+ * Reads history from the JSONL file and streams live updates via
368
+ * the session watcher.
369
+ */
370
+ function subscribeToExternalSession(
371
+ ws: WebSocket,
372
+ state: ConnectionState,
373
+ jsonlPath: string
374
+ ): void {
375
+ if (!_sessionWatcher) {
376
+ safeSend(ws, { message: 'Session watcher not initialised', type: 'error' });
377
+ safeSend(ws, { messages: [], type: 'history' });
378
+ return;
379
+ }
380
+
381
+ // Send full history
382
+ try {
383
+ const allMessages = _sessionWatcher.getHistory(jsonlPath);
384
+ const historyMessages = conversationToHistory(allMessages);
385
+ safeSend(ws, { messages: historyMessages, type: 'history' });
386
+ } catch (err) {
387
+ console.error(`[ws/session] Failed to read external history for ${state.terminalId}:`, err);
388
+ safeSend(ws, { messages: [], type: 'history' });
389
+ }
390
+
391
+ // Stream live updates
392
+ try {
393
+ const unsubscribe = _sessionWatcher.subscribe(jsonlPath, (messages: ConversationMessage[]) => {
394
+ if (ws.readyState !== 1 /* OPEN */) {
395
+ return;
396
+ }
397
+ for (const msg of messages) {
398
+ const liveMessages = conversationToLive(msg);
399
+ for (const liveMsg of liveMessages) {
400
+ safeSend(ws, liveMsg);
401
+ }
402
+ }
403
+ });
404
+ state.unsubscribe = unsubscribe;
405
+ } catch (err) {
406
+ console.error(`[ws/session] Failed to subscribe to external session ${state.terminalId}:`, err);
407
+ safeSend(ws, { message: 'Failed to subscribe to session updates', type: 'error' });
408
+ }
409
+ }
410
+
411
+ // ── Connection state ─────────────────────────────────────────────────
412
+
349
413
  /**
350
414
  * Subscribe to a terminal's session file. Sends the full history as a
351
415
  * `history` message, then streams new entries as they appear.
@@ -413,6 +477,8 @@ function subscribeToSession(
413
477
  subscribeWithSessionKey(ws, state, terminal, sessionKey);
414
478
  }
415
479
 
480
+ // ── Main handler ─────────────────────────────────────────────────────
481
+
416
482
  /**
417
483
  * Subscribe to a session using an already-known session key. Sends history
418
484
  * and starts streaming new entries. Extracted so both the normal path and
@@ -467,3 +533,115 @@ function subscribeWithSessionKey(
467
533
  safeSend(ws, { type: 'session-end' });
468
534
  }
469
535
  }
536
+
537
+ /**
538
+ * Wire up cleanup handlers for WebSocket close and error events.
539
+ */
540
+ function wireCleanup(ws: WebSocket, state: ConnectionState): void {
541
+ ws.on('close', () => {
542
+ if (state.retryInterval) {
543
+ clearInterval(state.retryInterval);
544
+ state.retryInterval = null;
545
+ }
546
+ if (state.unsubscribe) {
547
+ state.unsubscribe();
548
+ state.unsubscribe = null;
549
+ }
550
+ });
551
+
552
+ ws.on('error', () => {
553
+ // Errors are followed by 'close', which handles cleanup.
554
+ });
555
+ }
556
+
557
+ /**
558
+ * Wire up client message handling (send-input, cancel, subscribe).
559
+ * Extracted so both terminal-backed and external sessions share the same
560
+ * message loop.
561
+ */
562
+ function wireClientMessages(ws: WebSocket, state: ConnectionState): void {
563
+ ws.on('message', (raw: Buffer | string) => {
564
+ const data = typeof raw === 'string' ? raw : raw.toString('utf-8');
565
+ const msg = parseClientMessage(data);
566
+ if (!msg) {
567
+ return;
568
+ }
569
+
570
+ try {
571
+ switch (msg.type) {
572
+ case 'cancel': {
573
+ if (state.isExternalSession) {
574
+ safeSend(ws, {
575
+ message: 'Cannot cancel — this is a read-only session. Connect to a terminal first.',
576
+ type: 'error',
577
+ });
578
+ return;
579
+ }
580
+ const currentTerminal = _ptyManager?.getTerminal(state.terminalId);
581
+ if (!currentTerminal || currentTerminal.status === 'exited') {
582
+ safeSend(ws, { message: 'Terminal has exited', type: 'error' });
583
+ return;
584
+ }
585
+ currentTerminal.pty.write('\x03');
586
+ break;
587
+ }
588
+
589
+ case 'send-input': {
590
+ if (state.isExternalSession) {
591
+ safeSend(ws, {
592
+ message: 'Cannot send input — this is a read-only session. Connect to a terminal first.',
593
+ type: 'error',
594
+ });
595
+ return;
596
+ }
597
+ const currentTerminal = _ptyManager?.getTerminal(state.terminalId);
598
+ if (!currentTerminal || currentTerminal.status === 'exited') {
599
+ safeSend(ws, { message: 'Terminal has exited', type: 'error' });
600
+ return;
601
+ }
602
+ currentTerminal.pty.write(`${msg.text}\n`);
603
+ break;
604
+ }
605
+
606
+ case 'subscribe': {
607
+ // (Re)subscribe to a different session. Clean up the old subscription.
608
+ if (state.retryInterval) {
609
+ clearInterval(state.retryInterval);
610
+ state.retryInterval = null;
611
+ }
612
+ if (state.unsubscribe) {
613
+ state.unsubscribe();
614
+ state.unsubscribe = null;
615
+ }
616
+
617
+ // Try terminal first, then external
618
+ const newTerminal = _ptyManager?.getTerminal(msg.sessionId)
619
+ ?? findTerminalBySessionUuid(msg.sessionId);
620
+
621
+ if (newTerminal) {
622
+ state.terminalId = newTerminal.id;
623
+ state.isExternalSession = false;
624
+ subscribeToSession(ws, state, newTerminal);
625
+ } else {
626
+ const jsonlPath = findJsonlFileForSession(msg.sessionId);
627
+ if (jsonlPath) {
628
+ state.terminalId = msg.sessionId;
629
+ state.isExternalSession = true;
630
+ subscribeToExternalSession(ws, state, jsonlPath);
631
+ } else {
632
+ safeSend(ws, {
633
+ message: `Session not found: ${msg.sessionId}`,
634
+ type: 'error',
635
+ });
636
+ }
637
+ }
638
+ break;
639
+ }
640
+ }
641
+ } catch (err) {
642
+ const errMsg = err instanceof Error ? err.message : String(err);
643
+ console.error(`[ws/session] Error handling ${msg.type} for ${state.terminalId}:`, errMsg);
644
+ safeSend(ws, { message: `Failed to handle ${msg.type}: ${errMsg}`, type: 'error' });
645
+ }
646
+ });
647
+ }
package/src/lib/theme.css CHANGED
@@ -276,12 +276,37 @@
276
276
  --button-hover-text-color: var(--ds-background-100);
277
277
  }
278
278
 
279
+ .btn-connect {
280
+ --button-color: #0d9488;
281
+ --button-text-color: #fff;
282
+ --button-hover-color: #14b8a6;
283
+ --button-hover-text-color: #fff;
284
+ --button-border: 1px solid #0d9488;
285
+ --button-hover-border: 1px solid #14b8a6;
286
+ }
287
+
288
+ .btn-resume {
289
+ --button-color: transparent;
290
+ --button-text-color: var(--ds-gray-900);
291
+ --button-border: 1px solid var(--ds-gray-400);
292
+ --button-hover-color: var(--ds-gray-100);
293
+ --button-hover-text-color: var(--ds-gray-1000);
294
+ --button-hover-border: 1px solid var(--ds-gray-600);
295
+ }
296
+
279
297
  .btn-sm {
280
298
  --button-height: 32px;
281
299
  --button-padding: 0 10px;
282
300
  --button-font-size: var(--text-base);
283
301
  }
284
302
 
303
+ .btn-xs {
304
+ --button-height: 28px;
305
+ --button-padding: 0 8px;
306
+ --button-font-size: var(--text-xs);
307
+ --button-border-radius: var(--radius-sm);
308
+ }
309
+
285
310
  .btn-lg {
286
311
  --button-height: 48px;
287
312
  --button-padding: 0 20px;
@@ -526,4 +551,9 @@
526
551
  .shimmer-card {
527
552
  --shimmer-height: 90px;
528
553
  }
554
+
555
+ .btn-xs {
556
+ min-height: 36px;
557
+ padding: 6px 12px;
558
+ }
529
559
  }
@@ -0,0 +1,94 @@
1
+ <script lang="ts">
2
+ import { goto } from '$app/navigation';
3
+ import { page } from '$app/stores';
4
+ </script>
5
+
6
+ <svelte:head>
7
+ <title>Error - Shooter</title>
8
+ </svelte:head>
9
+
10
+ <main class="error-page">
11
+ <div class="error-content">
12
+ <div class="error-code">{$page.status}</div>
13
+ <h1 class="error-title">
14
+ {#if $page.status === 404}
15
+ Page not found
16
+ {:else}
17
+ Something went wrong
18
+ {/if}
19
+ </h1>
20
+ <p class="error-message">
21
+ {#if $page.error?.message}
22
+ {$page.error.message}
23
+ {:else if $page.status === 404}
24
+ The page you're looking for doesn't exist or has been moved.
25
+ {:else}
26
+ An unexpected error occurred. Try refreshing or going back.
27
+ {/if}
28
+ </p>
29
+ <div class="error-actions">
30
+ <button class="error-btn" onclick={() => goto('/')}>Go Home</button>
31
+ <button class="error-btn error-btn-secondary" onclick={() => { history.back(); }}>Go Back</button>
32
+ </div>
33
+ </div>
34
+ </main>
35
+
36
+ <style>
37
+ .error-page {
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ min-height: 60vh;
42
+ padding: var(--space-6);
43
+ }
44
+
45
+ .error-content {
46
+ text-align: center;
47
+ max-width: 400px;
48
+ }
49
+
50
+ .error-code {
51
+ font-size: 4rem;
52
+ font-weight: 700;
53
+ color: var(--color-text-tertiary, #555);
54
+ line-height: 1;
55
+ margin-bottom: var(--space-2);
56
+ }
57
+
58
+ .error-title {
59
+ font-size: 1.25rem;
60
+ font-weight: 600;
61
+ margin-bottom: var(--space-3);
62
+ }
63
+
64
+ .error-message {
65
+ color: var(--color-text-secondary, #888);
66
+ font-size: 0.875rem;
67
+ line-height: 1.5;
68
+ margin-bottom: var(--space-5);
69
+ }
70
+
71
+ .error-actions {
72
+ display: flex;
73
+ gap: var(--space-3);
74
+ justify-content: center;
75
+ }
76
+
77
+ .error-btn {
78
+ padding: 10px 20px;
79
+ border-radius: 8px;
80
+ font-size: 0.875rem;
81
+ font-weight: 500;
82
+ cursor: pointer;
83
+ border: none;
84
+ background: var(--color-accent, #0d9488);
85
+ color: white;
86
+ min-height: 44px;
87
+ }
88
+
89
+ .error-btn-secondary {
90
+ background: transparent;
91
+ border: 1px solid var(--border, #333);
92
+ color: var(--color-text-secondary, #888);
93
+ }
94
+ </style>