@juspay/shooter 1.0.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 (327) hide show
  1. package/.claude/hooks/notifier.cjs +1431 -0
  2. package/.claude/settings.json +162 -0
  3. package/README.md +515 -0
  4. package/bin/shooter.cjs +141 -0
  5. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css +1 -0
  6. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.br +0 -0
  7. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css +1 -0
  9. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.br +1 -0
  10. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.gz +0 -0
  11. package/build/client/_app/immutable/assets/3.C0uFg0IS.css +1 -0
  12. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.br +0 -0
  13. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.gz +0 -0
  14. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +1 -0
  15. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
  16. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
  17. package/build/client/_app/immutable/assets/5.DRjApZQW.css +1 -0
  18. package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
  19. package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
  20. package/build/client/_app/immutable/assets/6.AraZrY8I.css +1 -0
  21. package/build/client/_app/immutable/assets/6.AraZrY8I.css.br +0 -0
  22. package/build/client/_app/immutable/assets/6.AraZrY8I.css.gz +0 -0
  23. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css +1 -0
  24. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.br +0 -0
  25. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.gz +0 -0
  26. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +1 -0
  27. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
  28. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
  29. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css +1 -0
  30. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.br +0 -0
  31. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.gz +0 -0
  32. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css +1 -0
  33. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.br +0 -0
  34. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.gz +0 -0
  35. package/build/client/_app/immutable/chunks/BNJphC1q.js +56 -0
  36. package/build/client/_app/immutable/chunks/BNJphC1q.js.br +0 -0
  37. package/build/client/_app/immutable/chunks/BNJphC1q.js.gz +0 -0
  38. package/build/client/_app/immutable/chunks/BTGVxaYV.js +9 -0
  39. package/build/client/_app/immutable/chunks/BTGVxaYV.js.br +0 -0
  40. package/build/client/_app/immutable/chunks/BTGVxaYV.js.gz +0 -0
  41. package/build/client/_app/immutable/chunks/BlxrFPDK.js +1 -0
  42. package/build/client/_app/immutable/chunks/BlxrFPDK.js.br +0 -0
  43. package/build/client/_app/immutable/chunks/BlxrFPDK.js.gz +0 -0
  44. package/build/client/_app/immutable/chunks/Bvk7mfPM.js +1 -0
  45. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.br +0 -0
  46. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.gz +0 -0
  47. package/build/client/_app/immutable/chunks/CAokzuPQ.js +1 -0
  48. package/build/client/_app/immutable/chunks/CAokzuPQ.js.br +0 -0
  49. package/build/client/_app/immutable/chunks/CAokzuPQ.js.gz +0 -0
  50. package/build/client/_app/immutable/chunks/CGLrx-H5.js +1 -0
  51. package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
  52. package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
  53. package/build/client/_app/immutable/chunks/CgCpWzEA.js +1 -0
  54. package/build/client/_app/immutable/chunks/CgCpWzEA.js.br +0 -0
  55. package/build/client/_app/immutable/chunks/CgCpWzEA.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/Cjwk_cGO.js +6 -0
  57. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/CtQ8EED1.js +11 -0
  60. package/build/client/_app/immutable/chunks/CtQ8EED1.js.br +0 -0
  61. package/build/client/_app/immutable/chunks/CtQ8EED1.js.gz +0 -0
  62. package/build/client/_app/immutable/chunks/DERQCisl.js +1 -0
  63. package/build/client/_app/immutable/chunks/DERQCisl.js.br +0 -0
  64. package/build/client/_app/immutable/chunks/DERQCisl.js.gz +0 -0
  65. package/build/client/_app/immutable/chunks/DKrg8TQs.js +1 -0
  66. package/build/client/_app/immutable/chunks/DKrg8TQs.js.br +0 -0
  67. package/build/client/_app/immutable/chunks/DKrg8TQs.js.gz +0 -0
  68. package/build/client/_app/immutable/chunks/DLu6yJIZ.js +1 -0
  69. package/build/client/_app/immutable/chunks/DLu6yJIZ.js.br +0 -0
  70. package/build/client/_app/immutable/chunks/DLu6yJIZ.js.gz +0 -0
  71. package/build/client/_app/immutable/chunks/Dkkpz_4D.js +126 -0
  72. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.br +0 -0
  73. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.gz +0 -0
  74. package/build/client/_app/immutable/chunks/DoczjQhA.js +1 -0
  75. package/build/client/_app/immutable/chunks/DoczjQhA.js.br +0 -0
  76. package/build/client/_app/immutable/chunks/DoczjQhA.js.gz +0 -0
  77. package/build/client/_app/immutable/chunks/PPVm8Dsz.js +1 -0
  78. package/build/client/_app/immutable/chunks/PPVm8Dsz.js.br +0 -0
  79. package/build/client/_app/immutable/chunks/PPVm8Dsz.js.gz +0 -0
  80. package/build/client/_app/immutable/chunks/RpcNruLP.js +2 -0
  81. package/build/client/_app/immutable/chunks/RpcNruLP.js.br +0 -0
  82. package/build/client/_app/immutable/chunks/RpcNruLP.js.gz +0 -0
  83. package/build/client/_app/immutable/chunks/a-St0Zwo.js +1 -0
  84. package/build/client/_app/immutable/chunks/a-St0Zwo.js.br +0 -0
  85. package/build/client/_app/immutable/chunks/a-St0Zwo.js.gz +0 -0
  86. package/build/client/_app/immutable/chunks/bo70OQUZ.js +1 -0
  87. package/build/client/_app/immutable/chunks/bo70OQUZ.js.br +0 -0
  88. package/build/client/_app/immutable/chunks/bo70OQUZ.js.gz +0 -0
  89. package/build/client/_app/immutable/entry/app.QvGgdvTI.js +2 -0
  90. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.br +0 -0
  91. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.gz +0 -0
  92. package/build/client/_app/immutable/entry/start.BntDNRMC.js +1 -0
  93. package/build/client/_app/immutable/entry/start.BntDNRMC.js.br +0 -0
  94. package/build/client/_app/immutable/entry/start.BntDNRMC.js.gz +0 -0
  95. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js +1 -0
  96. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.br +0 -0
  97. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.gz +0 -0
  98. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js +1 -0
  99. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.br +0 -0
  100. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.gz +0 -0
  101. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js +1 -0
  102. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.br +0 -0
  103. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.gz +0 -0
  104. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js +3 -0
  105. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.gz +0 -0
  107. package/build/client/_app/immutable/nodes/4.D-cIe70D.js +1 -0
  108. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js +1 -0
  111. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.gz +0 -0
  113. package/build/client/_app/immutable/nodes/6.BB7QE48r.js +2 -0
  114. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.br +0 -0
  115. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.gz +0 -0
  116. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js +2 -0
  117. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.br +0 -0
  118. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.gz +0 -0
  119. package/build/client/_app/version.json +1 -0
  120. package/build/client/_app/version.json.br +0 -0
  121. package/build/client/_app/version.json.gz +0 -0
  122. package/build/client/app-icon.png +0 -0
  123. package/build/client/apple-touch-icon.png +0 -0
  124. package/build/client/favicon.png +0 -0
  125. package/build/client/favicon.svg +10 -0
  126. package/build/client/favicon.svg.br +0 -0
  127. package/build/client/favicon.svg.gz +0 -0
  128. package/build/client/manifest.webmanifest +1 -0
  129. package/build/client/pwa-192x192.png +0 -0
  130. package/build/client/pwa-512x512.png +0 -0
  131. package/build/client/registerSW.js +1 -0
  132. package/build/client/registerSW.js.br +0 -0
  133. package/build/client/registerSW.js.gz +0 -0
  134. package/build/client/sw.js +222 -0
  135. package/build/client/sw.js.br +0 -0
  136. package/build/client/sw.js.gz +0 -0
  137. package/build/client/workbox-5119daf5.js +3395 -0
  138. package/build/client/workbox-5119daf5.js.br +0 -0
  139. package/build/client/workbox-5119daf5.js.gz +0 -0
  140. package/build/env.js +94 -0
  141. package/build/handler.js +1494 -0
  142. package/build/index.js +345 -0
  143. package/build/pty-holder.cjs +510 -0
  144. package/build/server/chunks/0-q2IUp76Y.js +9 -0
  145. package/build/server/chunks/0-q2IUp76Y.js.map +1 -0
  146. package/build/server/chunks/1-CU50G5wZ.js +9 -0
  147. package/build/server/chunks/1-CU50G5wZ.js.map +1 -0
  148. package/build/server/chunks/2-D01t9s8T.js +9 -0
  149. package/build/server/chunks/2-D01t9s8T.js.map +1 -0
  150. package/build/server/chunks/3-5PUQ04wC.js +9 -0
  151. package/build/server/chunks/3-5PUQ04wC.js.map +1 -0
  152. package/build/server/chunks/4-e7gywnSG.js +9 -0
  153. package/build/server/chunks/4-e7gywnSG.js.map +1 -0
  154. package/build/server/chunks/5-CA1SA6KZ.js +9 -0
  155. package/build/server/chunks/5-CA1SA6KZ.js.map +1 -0
  156. package/build/server/chunks/6-71H221sV.js +9 -0
  157. package/build/server/chunks/6-71H221sV.js.map +1 -0
  158. package/build/server/chunks/7-Bo-vmdyz.js +9 -0
  159. package/build/server/chunks/7-Bo-vmdyz.js.map +1 -0
  160. package/build/server/chunks/_layout.svelte-SFHOxs74.js +132 -0
  161. package/build/server/chunks/_layout.svelte-SFHOxs74.js.map +1 -0
  162. package/build/server/chunks/_page.svelte-B4w-2wD-.js +120 -0
  163. package/build/server/chunks/_page.svelte-B4w-2wD-.js.map +1 -0
  164. package/build/server/chunks/_page.svelte-B_qAXjkh.js +213 -0
  165. package/build/server/chunks/_page.svelte-B_qAXjkh.js.map +1 -0
  166. package/build/server/chunks/_page.svelte-CsF1_TRG.js +50 -0
  167. package/build/server/chunks/_page.svelte-CsF1_TRG.js.map +1 -0
  168. package/build/server/chunks/_page.svelte-DJC6U-P0.js +68 -0
  169. package/build/server/chunks/_page.svelte-DJC6U-P0.js.map +1 -0
  170. package/build/server/chunks/_page.svelte-DQ6HBtsz.js +407 -0
  171. package/build/server/chunks/_page.svelte-DQ6HBtsz.js.map +1 -0
  172. package/build/server/chunks/_page.svelte-LbhhjP21.js +148 -0
  173. package/build/server/chunks/_page.svelte-LbhhjP21.js.map +1 -0
  174. package/build/server/chunks/_server.ts-BL2FGb5Z.js +387 -0
  175. package/build/server/chunks/_server.ts-BL2FGb5Z.js.map +1 -0
  176. package/build/server/chunks/_server.ts-BgdjBZco.js +47 -0
  177. package/build/server/chunks/_server.ts-BgdjBZco.js.map +1 -0
  178. package/build/server/chunks/_server.ts-BihKSdj_.js +59 -0
  179. package/build/server/chunks/_server.ts-BihKSdj_.js.map +1 -0
  180. package/build/server/chunks/_server.ts-BjOJsoy4.js +63 -0
  181. package/build/server/chunks/_server.ts-BjOJsoy4.js.map +1 -0
  182. package/build/server/chunks/_server.ts-C29xzfaw.js +77 -0
  183. package/build/server/chunks/_server.ts-C29xzfaw.js.map +1 -0
  184. package/build/server/chunks/_server.ts-CPa6DgIt.js +71 -0
  185. package/build/server/chunks/_server.ts-CPa6DgIt.js.map +1 -0
  186. package/build/server/chunks/_server.ts-CbDRDIoP.js +36 -0
  187. package/build/server/chunks/_server.ts-CbDRDIoP.js.map +1 -0
  188. package/build/server/chunks/_server.ts-Cl1OEWL4.js +54 -0
  189. package/build/server/chunks/_server.ts-Cl1OEWL4.js.map +1 -0
  190. package/build/server/chunks/_server.ts-ColfDHW8.js +60 -0
  191. package/build/server/chunks/_server.ts-ColfDHW8.js.map +1 -0
  192. package/build/server/chunks/_server.ts-Cv_OrRuL.js +494 -0
  193. package/build/server/chunks/_server.ts-Cv_OrRuL.js.map +1 -0
  194. package/build/server/chunks/_server.ts-D4MNi4cD.js +25 -0
  195. package/build/server/chunks/_server.ts-D4MNi4cD.js.map +1 -0
  196. package/build/server/chunks/_server.ts-DRVbgm6k.js +125 -0
  197. package/build/server/chunks/_server.ts-DRVbgm6k.js.map +1 -0
  198. package/build/server/chunks/_server.ts-DfajWaqh.js +39 -0
  199. package/build/server/chunks/_server.ts-DfajWaqh.js.map +1 -0
  200. package/build/server/chunks/_server.ts-y9-WYDMa.js +35 -0
  201. package/build/server/chunks/_server.ts-y9-WYDMa.js.map +1 -0
  202. package/build/server/chunks/auth-CEgFis71.js +32 -0
  203. package/build/server/chunks/auth-CEgFis71.js.map +1 -0
  204. package/build/server/chunks/client-CxCatAKr.js +255 -0
  205. package/build/server/chunks/client-CxCatAKr.js.map +1 -0
  206. package/build/server/chunks/error.svelte-BqdwMWdK.js +26 -0
  207. package/build/server/chunks/error.svelte-BqdwMWdK.js.map +1 -0
  208. package/build/server/chunks/exports-CJ0Q5XmL.js +4081 -0
  209. package/build/server/chunks/exports-CJ0Q5XmL.js.map +1 -0
  210. package/build/server/chunks/index2-DAxIoAO-.js +36 -0
  211. package/build/server/chunks/index2-DAxIoAO-.js.map +1 -0
  212. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js +137 -0
  213. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js.map +1 -0
  214. package/build/server/chunks/library-apns-BHxLmuIx.js +104 -0
  215. package/build/server/chunks/library-apns-BHxLmuIx.js.map +1 -0
  216. package/build/server/chunks/markdown-Bxrl3cCF.js +1241 -0
  217. package/build/server/chunks/markdown-Bxrl3cCF.js.map +1 -0
  218. package/build/server/chunks/pending-requests-D8UiTw7L.js +44 -0
  219. package/build/server/chunks/pending-requests-D8UiTw7L.js.map +1 -0
  220. package/build/server/chunks/pty-manager-C0FhBiVq.js +1697 -0
  221. package/build/server/chunks/pty-manager-C0FhBiVq.js.map +1 -0
  222. package/build/server/chunks/shared-server-BDY8jh20.js +200 -0
  223. package/build/server/chunks/shared-server-BDY8jh20.js.map +1 -0
  224. package/build/server/chunks/stores-D0HorpgL.js +36 -0
  225. package/build/server/chunks/stores-D0HorpgL.js.map +1 -0
  226. package/build/server/index.js +6466 -0
  227. package/build/server/index.js.map +1 -0
  228. package/build/server/manifest.js +184 -0
  229. package/build/server/manifest.js.map +1 -0
  230. package/build/shims.js +32 -0
  231. package/package.json +94 -0
  232. package/scripts/clipboard-shims/wl-paste +48 -0
  233. package/scripts/clipboard-shims/xclip +31 -0
  234. package/scripts/install.sh +477 -0
  235. package/scripts/setup-node-pty.sh +63 -0
  236. package/scripts/setup.cjs +571 -0
  237. package/scripts/test-runner.ts +243 -0
  238. package/scripts/vercel-env-commands.sh +60 -0
  239. package/server.ts +139 -0
  240. package/src/app.css +1835 -0
  241. package/src/app.d.ts +31 -0
  242. package/src/app.html +24 -0
  243. package/src/generated/types/APN.ts +305 -0
  244. package/src/generated/types/CLI.ts +52 -0
  245. package/src/generated/types/JWT.ts +92 -0
  246. package/src/generated/types/Terminal.ts +2736 -0
  247. package/src/generated/types/index.ts +6 -0
  248. package/src/lib/assets/icons/alert-triangle.svg +5 -0
  249. package/src/lib/assets/icons/bell.svg +4 -0
  250. package/src/lib/assets/icons/check-circle.svg +4 -0
  251. package/src/lib/assets/icons/file.svg +4 -0
  252. package/src/lib/assets/icons/folder.svg +3 -0
  253. package/src/lib/assets/icons/play.svg +3 -0
  254. package/src/lib/assets/icons/refresh.svg +4 -0
  255. package/src/lib/assets/icons/settings.svg +4 -0
  256. package/src/lib/assets/icons/terminal.svg +1 -0
  257. package/src/lib/assets/icons/tool.svg +3 -0
  258. package/src/lib/assets/icons/x-circle.svg +5 -0
  259. package/src/lib/modules/client/common/Card.svelte +26 -0
  260. package/src/lib/modules/client/common/EmptyState.svelte +36 -0
  261. package/src/lib/modules/client/common/Icon.svelte +61 -0
  262. package/src/lib/modules/client/common/StatusBadge.svelte +38 -0
  263. package/src/lib/modules/client/common/cache.ts +31 -0
  264. package/src/lib/modules/client/common/config-guard.ts +18 -0
  265. package/src/lib/modules/client/common/index.ts +12 -0
  266. package/src/lib/modules/client/common/markdown.ts +23 -0
  267. package/src/lib/modules/client/common/native-bridge.ts +50 -0
  268. package/src/lib/modules/client/common/time.ts +22 -0
  269. package/src/lib/modules/client/common/tool-title.ts +28 -0
  270. package/src/lib/modules/client/terminal/ChatView.svelte +400 -0
  271. package/src/lib/modules/client/terminal/CommandPalette.svelte +60 -0
  272. package/src/lib/modules/client/terminal/ConnectionStatus.svelte +99 -0
  273. package/src/lib/modules/client/terminal/LaunchSheet.svelte +294 -0
  274. package/src/lib/modules/client/terminal/QuickKeys.svelte +71 -0
  275. package/src/lib/modules/client/terminal/ShortcutsHelp.svelte +79 -0
  276. package/src/lib/modules/client/terminal/keyboard-shortcuts.ts +70 -0
  277. package/src/lib/modules/client/terminal/xterm-wrapper.ts +243 -0
  278. package/src/lib/modules/server/apn/library-apns.ts +137 -0
  279. package/src/lib/modules/server/apn/notification-history.ts +35 -0
  280. package/src/lib/modules/server/apn/notification-sessions.ts +117 -0
  281. package/src/lib/modules/server/apn/pending-requests.ts +65 -0
  282. package/src/lib/modules/server/apn/types.ts +51 -0
  283. package/src/lib/modules/server/auth.ts +34 -0
  284. package/src/lib/modules/server/cli/index.ts +79 -0
  285. package/src/lib/modules/server/cli/runner.ts +162 -0
  286. package/src/lib/modules/server/fcm/fcm-service.ts +72 -0
  287. package/src/lib/modules/server/sessions/jsonl-parser.ts +197 -0
  288. package/src/lib/modules/server/sessions/jsonl-reader.ts +301 -0
  289. package/src/lib/modules/server/sessions/opencode-reader.ts +264 -0
  290. package/src/lib/modules/server/sessions/types.ts +53 -0
  291. package/src/lib/modules/server/terminal/holder-client.ts +273 -0
  292. package/src/lib/modules/server/terminal/opencode-watcher.ts +661 -0
  293. package/src/lib/modules/server/terminal/pty-holder.cjs +510 -0
  294. package/src/lib/modules/server/terminal/pty-manager.ts +1012 -0
  295. package/src/lib/modules/server/terminal/session-watcher.ts +320 -0
  296. package/src/lib/modules/server/terminal/terminal-store.ts +198 -0
  297. package/src/lib/modules/server/ws/events-handler.ts +73 -0
  298. package/src/lib/modules/server/ws/keepalive.ts +108 -0
  299. package/src/lib/modules/server/ws/server.ts +93 -0
  300. package/src/lib/modules/server/ws/session-handler.ts +462 -0
  301. package/src/lib/modules/server/ws/terminal-handler.ts +197 -0
  302. package/src/lib/modules/server/ws/ticket-store.ts +58 -0
  303. package/src/lib/theme.css +529 -0
  304. package/src/lib/types/config.ts +6 -0
  305. package/src/routes/+layout.svelte +218 -0
  306. package/src/routes/+page.svelte +261 -0
  307. package/src/routes/api/debug/+server.ts +33 -0
  308. package/src/routes/api/device-token/+server.ts +85 -0
  309. package/src/routes/api/health/+server.ts +100 -0
  310. package/src/routes/api/notify/+server.ts +418 -0
  311. package/src/routes/api/qr-config/+server.ts +45 -0
  312. package/src/routes/api/response/+server.ts +73 -0
  313. package/src/routes/api/sessions/+server.ts +120 -0
  314. package/src/routes/api/terminals/+server.ts +141 -0
  315. package/src/routes/api/terminals/[id]/+server.ts +75 -0
  316. package/src/routes/api/terminals/[id]/paste-image/+server.ts +61 -0
  317. package/src/routes/api/terminals/[id]/resize/+server.ts +60 -0
  318. package/src/routes/api/webhook/+server.ts +42 -0
  319. package/src/routes/api/ws-status/+server.ts +23 -0
  320. package/src/routes/api/ws-ticket/+server.ts +86 -0
  321. package/src/routes/config/+page.svelte +600 -0
  322. package/src/routes/project/+page.svelte +274 -0
  323. package/src/routes/session/[id]/+page.svelte +434 -0
  324. package/src/routes/terminals/+page.svelte +618 -0
  325. package/src/routes/terminals/[id]/+page.svelte +968 -0
  326. package/svelte.config.js +18 -0
  327. package/tsconfig.json +14 -0
@@ -0,0 +1,571 @@
1
+ #!/usr/bin/env node
2
+ // Interactive setup wizard for Shooter.
3
+ // CommonJS so it runs without a build step: `node scripts/setup.cjs`
4
+
5
+ 'use strict';
6
+
7
+ const readline = require('readline');
8
+ const { execSync, spawn } = require('child_process');
9
+ const crypto = require('crypto');
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const http = require('http');
13
+
14
+ // ── ANSI helpers ─────────────────────────────────────────────────────
15
+ const C = {
16
+ reset: '\x1b[0m',
17
+ bold: '\x1b[1m',
18
+ dim: '\x1b[2m',
19
+ red: '\x1b[31m',
20
+ green: '\x1b[32m',
21
+ yellow: '\x1b[33m',
22
+ blue: '\x1b[34m',
23
+ cyan: '\x1b[36m',
24
+ magenta: '\x1b[35m',
25
+ };
26
+
27
+ function bold(s) { return `${C.bold}${s}${C.reset}`; }
28
+ function green(s) { return `${C.green}${s}${C.reset}`; }
29
+ function red(s) { return `${C.red}${s}${C.reset}`; }
30
+ function yellow(s) { return `${C.yellow}${s}${C.reset}`; }
31
+ function cyan(s) { return `${C.cyan}${s}${C.reset}`; }
32
+ function dim(s) { return `${C.dim}${s}${C.reset}`; }
33
+ function mask(secret) { return secret.slice(0, 4) + '****'; }
34
+
35
+ // ── Globals ──────────────────────────────────────────────────────────
36
+ const ROOT = path.resolve(__dirname, '..');
37
+ const DOT_ENV_PATH = path.join(ROOT, '.env');
38
+
39
+ let rl; // readline interface — created in main()
40
+
41
+ // ── Readline helpers ─────────────────────────────────────────────────
42
+
43
+ function ask(question) {
44
+ return new Promise((resolve) => {
45
+ rl.question(question, (answer) => resolve(answer.trim()));
46
+ });
47
+ }
48
+
49
+ async function confirm(question) {
50
+ const answer = await ask(`${question} ${dim('(y/n)')} `);
51
+ return /^y(es)?$/i.test(answer);
52
+ }
53
+
54
+ async function askRequired(question, validator) {
55
+ while (true) {
56
+ const answer = await ask(question);
57
+ if (!answer) {
58
+ console.log(red(' This field is required.'));
59
+ continue;
60
+ }
61
+ if (validator) {
62
+ const err = validator(answer);
63
+ if (err) {
64
+ console.log(red(` ${err}`));
65
+ continue;
66
+ }
67
+ }
68
+ return answer;
69
+ }
70
+ }
71
+
72
+ async function askMultiline(prompt) {
73
+ console.log(cyan(prompt));
74
+ console.log(dim(' Paste the content, then press Enter on an empty line to finish:'));
75
+ const lines = [];
76
+ while (true) {
77
+ const line = await ask('');
78
+ if (line === '') break;
79
+ lines.push(line);
80
+ }
81
+ return lines.join('\n');
82
+ }
83
+
84
+ // ── Banner ───────────────────────────────────────────────────────────
85
+
86
+ function printBanner() {
87
+ console.log('');
88
+ console.log(`${C.cyan}${C.bold} ____ _ _ `);
89
+ console.log(`${C.cyan}${C.bold} / ___|| |__ ___ ___ | |_ ___ _ __ `);
90
+ console.log(`${C.cyan}${C.bold} \\___ \\| '_ \\ / _ \\ / _ \\| __/ _ \\ '__|`);
91
+ console.log(`${C.cyan}${C.bold} ___) | | | | (_) | (_) | || __/ | `);
92
+ console.log(`${C.cyan}${C.bold} |____/|_| |_|\\___/ \\___/ \\__\\___|_| ${C.reset}`);
93
+ console.log('');
94
+ console.log(bold(' Interactive Setup Wizard'));
95
+ console.log(dim(' Push notifications for your coding sessions'));
96
+ console.log('');
97
+ console.log(dim(' ─────────────────────────────────────────'));
98
+ console.log('');
99
+ }
100
+
101
+ // ── Prerequisite checks ─────────────────────────────────────────────
102
+
103
+ function checkPrerequisites() {
104
+ console.log(bold('1. Checking prerequisites...\n'));
105
+
106
+ // Node.js version
107
+ const nodeVersion = process.versions.node;
108
+ const [major] = nodeVersion.split('.').map(Number);
109
+ if (major < 20) {
110
+ console.log(red(` Node.js >= 20 required, found v${nodeVersion}`));
111
+ process.exit(1);
112
+ }
113
+ console.log(green(` Node.js v${nodeVersion}`));
114
+
115
+ // pnpm
116
+ try {
117
+ const pnpmVersion = execSync('pnpm --version', { encoding: 'utf-8' }).trim();
118
+ console.log(green(` pnpm v${pnpmVersion}`));
119
+ } catch {
120
+ console.log(red(' pnpm is not installed.'));
121
+ console.log(dim(' Install it: npm install -g pnpm'));
122
+ process.exit(1);
123
+ }
124
+
125
+ // dependencies installed?
126
+ const nodeModules = path.join(ROOT, 'node_modules');
127
+ if (!fs.existsSync(nodeModules)) {
128
+ console.log(yellow(' node_modules not found — running pnpm install...'));
129
+ try {
130
+ execSync('pnpm install', { cwd: ROOT, stdio: 'inherit' });
131
+ console.log(green(' Dependencies installed.'));
132
+ } catch {
133
+ console.log(red(' pnpm install failed. Please run it manually.'));
134
+ process.exit(1);
135
+ }
136
+ } else {
137
+ console.log(green(' Dependencies installed'));
138
+ }
139
+
140
+ console.log('');
141
+ }
142
+
143
+ // ── Validators ───────────────────────────────────────────────────────
144
+
145
+ function validateDeviceToken(token) {
146
+ if (!/^[0-9a-fA-F]{64}$/.test(token)) {
147
+ return 'Device token must be exactly 64 hexadecimal characters.';
148
+ }
149
+ return null;
150
+ }
151
+
152
+ function validateAPNsKeyId(id) {
153
+ if (!/^[A-Z0-9]{10}$/.test(id)) {
154
+ return 'APNs Key ID must be exactly 10 alphanumeric characters.';
155
+ }
156
+ return null;
157
+ }
158
+
159
+ function validateTeamId(id) {
160
+ if (!/^[A-Z0-9]{10}$/.test(id)) {
161
+ return 'Team ID must be exactly 10 alphanumeric characters.';
162
+ }
163
+ return null;
164
+ }
165
+
166
+ function validateBundleId(id) {
167
+ if (!/^[a-zA-Z][a-zA-Z0-9.-]*$/.test(id)) {
168
+ return 'Bundle ID should follow reverse-domain format (e.g. com.example.app).';
169
+ }
170
+ return null;
171
+ }
172
+
173
+ function validateEmail(email) {
174
+ if (!email.includes('@')) {
175
+ return 'Must be a valid email address.';
176
+ }
177
+ return null;
178
+ }
179
+
180
+ // ── Collect configuration ────────────────────────────────────────────
181
+
182
+ async function collectConfig() {
183
+ const config = {
184
+ apiKey: '',
185
+ // iOS APNs
186
+ wantIos: false,
187
+ apnsKey: '',
188
+ apnsKeyId: '',
189
+ apnsTeamId: '',
190
+ apnsBundleId: '',
191
+ apnsProduction: false,
192
+ deviceToken: '',
193
+ // Android FCM
194
+ wantAndroid: false,
195
+ fcmProjectId: '',
196
+ fcmClientEmail: '',
197
+ fcmPrivateKey: '',
198
+ androidDeviceToken: '',
199
+ };
200
+
201
+ // ── API Key ──────────────────────────────────────────────────────
202
+ console.log(bold('2. Server authentication\n'));
203
+ const apiKeyAnswer = await ask(
204
+ ` API_KEY ${dim('(press Enter to auto-generate)')}: `
205
+ );
206
+ if (apiKeyAnswer) {
207
+ config.apiKey = apiKeyAnswer;
208
+ } else {
209
+ config.apiKey = crypto.randomBytes(32).toString('hex');
210
+ console.log(green(` Generated: ${mask(config.apiKey)} (saved to .env)`));
211
+ }
212
+ console.log('');
213
+
214
+ // ── iOS Push Notifications ───────────────────────────────────────
215
+ console.log(bold('3. iOS Push Notifications\n'));
216
+ config.wantIos = await confirm(' Do you want iOS push notifications?');
217
+
218
+ if (config.wantIos) {
219
+ console.log('');
220
+
221
+ // APNs key (.p8)
222
+ config.apnsKey = await askMultiline(' APNS_KEY (.p8 private key contents):');
223
+ if (!config.apnsKey.includes('BEGIN PRIVATE KEY')) {
224
+ console.log(yellow(' Warning: Key does not look like a .p8 file. Continuing anyway.'));
225
+ }
226
+ console.log('');
227
+
228
+ config.apnsKeyId = await askRequired(' APNS_KEY_ID (10-char key identifier): ', validateAPNsKeyId);
229
+ config.apnsTeamId = await askRequired(' APNS_TEAM_ID (10-char team identifier): ', validateTeamId);
230
+ config.apnsBundleId = await askRequired(' APNS_BUNDLE_ID (e.g. com.example.shooter): ', validateBundleId);
231
+ config.deviceToken = await askRequired(' DEVICE_TOKEN (64-char hex from iOS device): ', validateDeviceToken);
232
+
233
+ console.log('');
234
+ config.apnsProduction = await confirm(' Use production APNs gateway? (use "yes" for TestFlight/App Store)');
235
+ }
236
+ console.log('');
237
+
238
+ // ── Android Push Notifications ───────────────────────────────────
239
+ console.log(bold('4. Android Push Notifications\n'));
240
+ config.wantAndroid = await confirm(' Do you want Android push notifications?');
241
+
242
+ if (config.wantAndroid) {
243
+ console.log('');
244
+ config.fcmProjectId = await askRequired(' FCM_PROJECT_ID: ');
245
+ config.fcmClientEmail = await askRequired(' FCM_CLIENT_EMAIL: ', validateEmail);
246
+
247
+ config.fcmPrivateKey = await askMultiline(' FCM_PRIVATE_KEY (service account private key):');
248
+ if (!config.fcmPrivateKey.includes('BEGIN')) {
249
+ console.log(yellow(' Warning: Key does not look like a PEM private key. Continuing anyway.'));
250
+ }
251
+ console.log('');
252
+
253
+ const androidTokenAnswer = await ask(` ANDROID_DEVICE_TOKEN ${dim('(optional, press Enter to skip)')}: `);
254
+ if (androidTokenAnswer) {
255
+ config.androidDeviceToken = androidTokenAnswer;
256
+ }
257
+ }
258
+ console.log('');
259
+
260
+ return config;
261
+ }
262
+
263
+ // ── Write .env ───────────────────────────────────────────────────────
264
+
265
+ function buildEnvContent(config) {
266
+ const lines = [
267
+ '# Generated by Shooter setup wizard',
268
+ `# ${new Date().toISOString()}`,
269
+ '',
270
+ '# Authentication',
271
+ `API_KEY=${config.apiKey}`,
272
+ '',
273
+ ];
274
+
275
+ // iOS / APNs
276
+ lines.push('# Apple Push Notification Service');
277
+ if (config.wantIos) {
278
+ // Escape the key for .env — newlines become literal \n inside double quotes
279
+ const escapedKey = config.apnsKey.replace(/\n/g, '\\n');
280
+ lines.push(`APNS_KEY="${escapedKey}"`);
281
+ lines.push(`APNS_KEY_ID=${config.apnsKeyId}`);
282
+ lines.push(`APNS_TEAM_ID=${config.apnsTeamId}`);
283
+ lines.push(`APNS_BUNDLE_ID=${config.apnsBundleId}`);
284
+ lines.push(`APNS_PRODUCTION=${config.apnsProduction}`);
285
+ lines.push('');
286
+ lines.push('# iOS Device');
287
+ lines.push(`DEVICE_TOKEN=${config.deviceToken}`);
288
+ } else {
289
+ lines.push('# (not configured — run setup again to enable)');
290
+ lines.push('# APNS_KEY=');
291
+ lines.push('# APNS_KEY_ID=');
292
+ lines.push('# APNS_TEAM_ID=');
293
+ lines.push('# APNS_BUNDLE_ID=');
294
+ lines.push('# APNS_PRODUCTION=false');
295
+ lines.push('# DEVICE_TOKEN=');
296
+ }
297
+ lines.push('');
298
+
299
+ // Platform preference
300
+ if (config.wantIos && config.wantAndroid) {
301
+ lines.push('# Device platform (ios or android)');
302
+ lines.push('DEVICE_PLATFORM=ios');
303
+ } else if (config.wantAndroid) {
304
+ lines.push('DEVICE_PLATFORM=android');
305
+ } else {
306
+ lines.push('DEVICE_PLATFORM=ios');
307
+ }
308
+ lines.push('');
309
+
310
+ // Android / FCM
311
+ lines.push('# Firebase Cloud Messaging (Android)');
312
+ if (config.wantAndroid) {
313
+ lines.push(`FCM_PROJECT_ID=${config.fcmProjectId}`);
314
+ lines.push(`FCM_CLIENT_EMAIL=${config.fcmClientEmail}`);
315
+ const escapedFcmKey = config.fcmPrivateKey.replace(/\n/g, '\\n');
316
+ lines.push(`FCM_PRIVATE_KEY="${escapedFcmKey}"`);
317
+ if (config.androidDeviceToken) {
318
+ lines.push(`ANDROID_DEVICE_TOKEN=${config.androidDeviceToken}`);
319
+ } else {
320
+ lines.push('# ANDROID_DEVICE_TOKEN=');
321
+ }
322
+ } else {
323
+ lines.push('# (not configured — run setup again to enable)');
324
+ lines.push('# FCM_PROJECT_ID=');
325
+ lines.push('# FCM_CLIENT_EMAIL=');
326
+ lines.push('# FCM_PRIVATE_KEY=');
327
+ lines.push('# ANDROID_DEVICE_TOKEN=');
328
+ }
329
+ lines.push('');
330
+
331
+ // Server
332
+ lines.push('# Server');
333
+ lines.push('# PORT=3000');
334
+ lines.push('');
335
+
336
+ return lines.join('\n') + '\n';
337
+ }
338
+
339
+ async function writeEnv(config) {
340
+ console.log(bold('5. Writing .env file\n'));
341
+
342
+ if (fs.existsSync(DOT_ENV_PATH)) {
343
+ const overwrite = await confirm(' .env already exists. Overwrite it?');
344
+ if (!overwrite) {
345
+ console.log(yellow(' Skipped .env — keeping existing file.'));
346
+ console.log('');
347
+ return false;
348
+ }
349
+ }
350
+
351
+ const content = buildEnvContent(config);
352
+ fs.writeFileSync(DOT_ENV_PATH, content, 'utf-8');
353
+ console.log(green(' .env written successfully.'));
354
+ console.log('');
355
+ return true;
356
+ }
357
+
358
+ // ── Shell profile export ─────────────────────────────────────────────
359
+
360
+ function detectShellProfile() {
361
+ const home = require('os').homedir();
362
+ const shell = process.env.SHELL || '';
363
+
364
+ if (shell.endsWith('/zsh')) {
365
+ return path.join(home, '.zshrc');
366
+ }
367
+ if (shell.endsWith('/bash')) {
368
+ // macOS uses .bash_profile for login shells; Linux uses .bashrc
369
+ const bashProfile = path.join(home, '.bash_profile');
370
+ if (fs.existsSync(bashProfile)) return bashProfile;
371
+ return path.join(home, '.bashrc');
372
+ }
373
+ // Fallback for other shells
374
+ return path.join(home, '.profile');
375
+ }
376
+
377
+ async function offerShellExport(apiKey) {
378
+ console.log(bold('6. Shell environment\n'));
379
+
380
+ const profilePath = detectShellProfile();
381
+ const profileName = path.basename(profilePath);
382
+
383
+ // Check if export already exists
384
+ if (fs.existsSync(profilePath)) {
385
+ const contents = fs.readFileSync(profilePath, 'utf-8');
386
+ if (contents.includes('export API_KEY=')) {
387
+ console.log(green(` export API_KEY is already in ~/${profileName}`));
388
+ console.log('');
389
+ return;
390
+ }
391
+ }
392
+
393
+ console.log(dim(' The Claude Code hooks need API_KEY in your shell environment.'));
394
+ const shouldAdd = await confirm(` Add 'export API_KEY=...' to ~/${profileName}?`);
395
+
396
+ if (shouldAdd) {
397
+ const exportLine = `\nexport API_KEY="${apiKey}"\n`;
398
+ fs.appendFileSync(profilePath, exportLine, 'utf-8');
399
+ console.log(green(` Added to ~/${profileName}`));
400
+ console.log(yellow(` Run ${cyan(`source ~/${profileName}`)} or open a new terminal for hooks to work.`));
401
+ } else {
402
+ console.log(yellow(' Skipped. You will need to set API_KEY manually for hooks to authenticate.'));
403
+ console.log(dim(` Add this to your shell profile: export API_KEY="<your key from .env>"`));
404
+ }
405
+ console.log('');
406
+ }
407
+
408
+ // ── Build ────────────────────────────────────────────────────────────
409
+
410
+ function runBuild() {
411
+ console.log(bold('7. Building the project...\n'));
412
+ try {
413
+ execSync('pnpm build', { cwd: ROOT, stdio: 'inherit' });
414
+ console.log('');
415
+ console.log(green(' Build succeeded.'));
416
+ console.log('');
417
+ return true;
418
+ } catch {
419
+ console.log('');
420
+ console.log(red(' Build failed. Check the errors above.'));
421
+ console.log(dim(' You can retry with: pnpm build'));
422
+ console.log('');
423
+ return false;
424
+ }
425
+ }
426
+
427
+ // ── Health check ─────────────────────────────────────────────────────
428
+
429
+ function testHealth() {
430
+ return new Promise((resolve) => {
431
+ console.log(bold('8. Testing server health...\n'));
432
+
433
+ const port = process.env.PORT || 3000;
434
+ let serverProcess;
435
+ let resolved = false;
436
+
437
+ function finish(ok, msg) {
438
+ if (resolved) return;
439
+ resolved = true;
440
+ if (serverProcess && !serverProcess.killed) {
441
+ serverProcess.kill('SIGTERM');
442
+ }
443
+ if (ok) {
444
+ console.log(green(` ${msg}`));
445
+ } else {
446
+ console.log(yellow(` ${msg}`));
447
+ }
448
+ console.log('');
449
+ resolve(ok);
450
+ }
451
+
452
+ // Start the server
453
+ serverProcess = spawn('node', ['--import', 'tsx', 'server.ts'], {
454
+ cwd: ROOT,
455
+ stdio: 'pipe',
456
+ env: { ...process.env, PORT: String(port) },
457
+ });
458
+
459
+ serverProcess.on('error', (err) => {
460
+ finish(false, `Could not start server: ${err.message}`);
461
+ });
462
+
463
+ serverProcess.on('exit', (code) => {
464
+ if (!resolved) {
465
+ finish(false, `Server exited unexpectedly (code ${code}).`);
466
+ }
467
+ });
468
+
469
+ // Capture stderr/stdout for "listening" signal; try health after delay
470
+ let output = '';
471
+ const collectOutput = (data) => { output += data.toString(); };
472
+ serverProcess.stdout.on('data', collectOutput);
473
+ serverProcess.stderr.on('data', collectOutput);
474
+
475
+ // Give the server up to 15 seconds to start, polling every second
476
+ let attempts = 0;
477
+ const maxAttempts = 15;
478
+
479
+ const poll = setInterval(() => {
480
+ attempts++;
481
+ if (resolved) {
482
+ clearInterval(poll);
483
+ return;
484
+ }
485
+ if (attempts > maxAttempts) {
486
+ clearInterval(poll);
487
+ finish(false, 'Server did not respond within 15 seconds. You can test manually with: curl http://localhost:' + port + '/api/health');
488
+ return;
489
+ }
490
+
491
+ const req = http.get(`http://localhost:${port}/api/health`, (res) => {
492
+ let body = '';
493
+ res.on('data', (chunk) => { body += chunk; });
494
+ res.on('end', () => {
495
+ clearInterval(poll);
496
+ try {
497
+ const data = JSON.parse(body);
498
+ if (data.status === 'healthy') {
499
+ finish(true, `Health check passed: status=${data.status}`);
500
+ } else {
501
+ finish(true, `Server running (status=${data.status}). Some optional features may need configuration.`);
502
+ }
503
+ } catch {
504
+ finish(true, 'Server responded but health response was not JSON.');
505
+ }
506
+ });
507
+ });
508
+ req.on('error', () => {
509
+ // Server not ready yet — will retry
510
+ });
511
+ req.setTimeout(2000, () => req.destroy());
512
+ }, 1000);
513
+ });
514
+ }
515
+
516
+ // ── Main ─────────────────────────────────────────────────────────────
517
+
518
+ async function main() {
519
+ rl = readline.createInterface({
520
+ input: process.stdin,
521
+ output: process.stdout,
522
+ });
523
+
524
+ // Graceful Ctrl+C
525
+ rl.on('close', () => {
526
+ console.log('\n');
527
+ console.log(yellow('Setup cancelled.'));
528
+ process.exit(0);
529
+ });
530
+
531
+ process.on('SIGINT', () => {
532
+ rl.close();
533
+ });
534
+
535
+ printBanner();
536
+ checkPrerequisites();
537
+
538
+ const config = await collectConfig();
539
+ await writeEnv(config);
540
+ await offerShellExport(config.apiKey);
541
+
542
+ const buildOk = runBuild();
543
+
544
+ if (buildOk) {
545
+ await testHealth();
546
+ }
547
+
548
+ // ── Done ───────────────────────────────────────────────────────────
549
+ console.log(dim(' ─────────────────────────────────────────'));
550
+ console.log('');
551
+ console.log(green(bold(' Setup complete!')));
552
+ console.log('');
553
+ console.log(` Start the server: ${cyan('pnpm start')}`);
554
+ console.log(` Dev mode: ${cyan('pnpm dev')}`);
555
+ console.log(` Health check: ${cyan('curl http://localhost:3000/api/health')}`);
556
+ console.log('');
557
+ if (!config.wantIos && !config.wantAndroid) {
558
+ console.log(yellow(' Note: No push notification platform was configured.'));
559
+ console.log(dim(' Run pnpm setup again to add iOS or Android push notifications.'));
560
+ console.log('');
561
+ }
562
+
563
+ rl.close();
564
+ process.exit(0);
565
+ }
566
+
567
+ main().catch((err) => {
568
+ console.error(red(`\nSetup failed: ${err.message}`));
569
+ if (rl) rl.close();
570
+ process.exit(1);
571
+ });