@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,510 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // pty-holder.cjs — Standalone detached process that owns a single PTY.
5
+ // Spawned by PtyManager via child_process.fork(). Communicates with the
6
+ // server over a Unix domain socket using ndjson (newline-delimited JSON).
7
+ //
8
+ // argv: id socketPath cwd cols rows command [args...]
9
+
10
+ const net = require('net');
11
+ const fs = require('fs');
12
+ const pty = require('node-pty');
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Parse arguments
16
+ // ---------------------------------------------------------------------------
17
+
18
+ const [,, id, socketPath, cwd, colsStr, rowsStr, command, ...args] = process.argv;
19
+
20
+ if (!id || !socketPath || !cwd || !colsStr || !rowsStr || !command) {
21
+ process.stderr.write('pty-holder: missing required arguments\n');
22
+ process.exit(1);
23
+ }
24
+
25
+ const cols = parseInt(colsStr, 10);
26
+ const rows = parseInt(rowsStr, 10);
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Constants
30
+ // ---------------------------------------------------------------------------
31
+
32
+ const MAX_SCROLLBACK_LINES = 5000;
33
+ const MAX_INPUT_BYTES = 65_536; // 64 KB — cap per-write to prevent memory abuse
34
+ const GRACE_PERIOD_MS = 60_000; // 60 seconds after PTY exit before self-terminating
35
+ const ACTIVITY_IDLE_MS = 5_000; // 5 seconds of no output → idle
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Scrollback ring buffer
39
+ // ---------------------------------------------------------------------------
40
+
41
+ const scrollbackChunks = [];
42
+ let scrollbackLineCount = 0;
43
+
44
+ function pushScrollback(data) {
45
+ const newLines = data.split('\n').length - 1;
46
+ scrollbackChunks.push(data);
47
+ scrollbackLineCount += newLines;
48
+
49
+ while (scrollbackLineCount > MAX_SCROLLBACK_LINES && scrollbackChunks.length > 1) {
50
+ const removed = scrollbackChunks.shift();
51
+ if (removed) {
52
+ scrollbackLineCount -= (removed.split('\n').length - 1);
53
+ }
54
+ }
55
+ }
56
+
57
+ function getScrollback() {
58
+ return scrollbackChunks.join('');
59
+ }
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // Clean up stale socket file
63
+ // ---------------------------------------------------------------------------
64
+
65
+ try {
66
+ if (fs.existsSync(socketPath)) {
67
+ fs.unlinkSync(socketPath);
68
+ }
69
+ } catch {
70
+ // Ignore — may not exist or may be cleaned up already
71
+ }
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Shell hook injection for OSC 7
75
+ // ---------------------------------------------------------------------------
76
+
77
+ const os = require('os');
78
+ const path = require('path');
79
+
80
+ const OSC7_HOOK = `__shooter_osc7() { printf '\\033]7;file://%s%s\\033\\\\' "$(hostname)" "$PWD"; }`;
81
+
82
+ const SHELL_COMMANDS = ['zsh', 'bash', 'sh', 'fish'];
83
+ const commandBase = command.split('/').pop() || command;
84
+ const ptyEnv = { ...process.env };
85
+
86
+ // Clipboard image paste support: per-terminal clipboard directory
87
+ const clipboardDir = path.join(os.tmpdir(), `shooter-clipboard-${id}`);
88
+ try { fs.mkdirSync(clipboardDir, { recursive: true }); } catch { /* best effort */ }
89
+ ptyEnv.SHOOTER_CLIPBOARD_DIR = clipboardDir;
90
+
91
+ // Prepend clipboard shim scripts to PATH so tools find our xclip/wl-paste
92
+ const shimsDir = path.resolve(__dirname, '..', 'scripts', 'clipboard-shims');
93
+ // Also check relative to cwd for dev mode
94
+ const shimsDir2 = path.resolve(process.cwd(), 'scripts', 'clipboard-shims');
95
+ if (fs.existsSync(shimsDir)) {
96
+ ptyEnv.PATH = `${shimsDir}:${ptyEnv.PATH || ''}`;
97
+ } else if (fs.existsSync(shimsDir2)) {
98
+ ptyEnv.PATH = `${shimsDir2}:${ptyEnv.PATH || ''}`;
99
+ }
100
+
101
+ let spawnCommand;
102
+ let spawnArgs;
103
+
104
+ if (SHELL_COMMANDS.includes(commandBase)) {
105
+ if (commandBase === 'zsh' || (commandBase === 'sh' && (process.env.SHELL || '').includes('zsh'))) {
106
+ // zsh: use ZDOTDIR with custom .zshrc
107
+ const zdotdir = path.join(os.tmpdir(), `shooter-zd-${id}`);
108
+ try {
109
+ fs.mkdirSync(zdotdir, { recursive: true });
110
+ const realRc = path.join(process.env.HOME || '', '.zshrc');
111
+ const rcContent = [
112
+ `[ -f "${realRc}" ] && source "${realRc}"`,
113
+ OSC7_HOOK,
114
+ `precmd_functions+=(__shooter_osc7)`,
115
+ '',
116
+ ].join('\n');
117
+ fs.writeFileSync(path.join(zdotdir, '.zshrc'), rcContent, 'utf8');
118
+ ptyEnv.ZDOTDIR = zdotdir;
119
+ } catch {
120
+ // Best effort — shell will work without the hook
121
+ }
122
+ spawnCommand = command;
123
+ spawnArgs = args;
124
+ } else if (commandBase === 'bash') {
125
+ // bash: use --rcfile
126
+ const rcPath = path.join(os.tmpdir(), `shooter-rc-${id}.sh`);
127
+ try {
128
+ const realRc = path.join(process.env.HOME || '', '.bashrc');
129
+ const rcContent = [
130
+ `[ -f "${realRc}" ] && source "${realRc}"`,
131
+ OSC7_HOOK,
132
+ `PROMPT_COMMAND="__shooter_osc7\${PROMPT_COMMAND:+;\$PROMPT_COMMAND}"`,
133
+ '',
134
+ ].join('\n');
135
+ fs.writeFileSync(rcPath, rcContent, 'utf8');
136
+ } catch {
137
+ // Best effort
138
+ }
139
+ spawnCommand = command;
140
+ spawnArgs = ['--rcfile', rcPath, ...args];
141
+ } else {
142
+ // sh/fish: no hook injection
143
+ spawnCommand = command;
144
+ spawnArgs = args;
145
+ }
146
+ } else {
147
+ // Non-shell commands: wrap in login shell
148
+ spawnCommand = null;
149
+ spawnArgs = null;
150
+ }
151
+
152
+ // ---------------------------------------------------------------------------
153
+ // Spawn PTY
154
+ // ---------------------------------------------------------------------------
155
+
156
+ let ptyProcess;
157
+
158
+ if (spawnCommand) {
159
+ // Interactive shell: spawn directly for proper rc injection
160
+ ptyProcess = pty.spawn(spawnCommand, spawnArgs, {
161
+ cols,
162
+ rows,
163
+ cwd,
164
+ env: ptyEnv,
165
+ name: 'xterm-color',
166
+ });
167
+ } else {
168
+ // Non-shell command: wrap in login shell as before
169
+ const shell = process.env.SHELL || '/bin/zsh';
170
+ const shellEscape = (arg) => `'${arg.replace(/'/g, "'\\''")}'`;
171
+ const fullCommand = [command, ...args].map(shellEscape).join(' ');
172
+ ptyProcess = pty.spawn(shell, ['-l', '-c', fullCommand], {
173
+ cols,
174
+ rows,
175
+ cwd,
176
+ env: ptyEnv,
177
+ name: 'xterm-color',
178
+ });
179
+ }
180
+
181
+ let exited = false;
182
+ let exitCode = null;
183
+ let exitSignal = null;
184
+ let gracePeriodTimer = null;
185
+
186
+ // ---------------------------------------------------------------------------
187
+ // Connected clients (multiple concurrent sockets)
188
+ // ---------------------------------------------------------------------------
189
+
190
+ const clients = new Set();
191
+
192
+ function send(socket, msg) {
193
+ try {
194
+ socket.write(JSON.stringify(msg) + '\n');
195
+ } catch {
196
+ // Socket may have been destroyed
197
+ }
198
+ }
199
+
200
+ function broadcast(msg) {
201
+ for (const socket of clients) {
202
+ send(socket, msg);
203
+ }
204
+ }
205
+
206
+ // ---------------------------------------------------------------------------
207
+ // OSC 7 CWD parsing
208
+ // ---------------------------------------------------------------------------
209
+
210
+ // Matches: \x1b]7;file://hostname/path\x1b\\ or \x1b]7;file://hostname/path\x07
211
+ const OSC7_RE = /\x1b\]7;file:\/\/[^/]*([^\x07\x1b]*)\x07|\x1b\]7;file:\/\/[^/]*([^\x07\x1b]*)\x1b\\/g;
212
+
213
+ // Buffer for incomplete OSC 7 sequences split across data chunks
214
+ let osc7PartialBuf = '';
215
+
216
+ let currentCwd = cwd; // Initialize with launch cwd
217
+
218
+ function parseOsc7(data) {
219
+ // Prepend any partial OSC 7 sequence from the previous chunk
220
+ const combined = osc7PartialBuf + data;
221
+ osc7PartialBuf = '';
222
+
223
+ // Check for an incomplete trailing OSC 7 sequence (starts with \x1b]7; but
224
+ // no terminator \x07 or \x1b\\ before end of data)
225
+ const lastEsc = combined.lastIndexOf('\x1b]7;');
226
+ if (lastEsc !== -1) {
227
+ const afterEsc = combined.slice(lastEsc);
228
+ if (!afterEsc.includes('\x07') && !afterEsc.includes('\x1b\\')) {
229
+ // Incomplete sequence — buffer it for the next chunk
230
+ osc7PartialBuf = afterEsc;
231
+ // Only parse the portion before the incomplete sequence
232
+ if (lastEsc === 0) return;
233
+ }
234
+ }
235
+
236
+ const toParse = osc7PartialBuf.length > 0 ? combined.slice(0, -osc7PartialBuf.length) : combined;
237
+
238
+ let match;
239
+ let lastPath = null;
240
+ OSC7_RE.lastIndex = 0;
241
+ while ((match = OSC7_RE.exec(toParse)) !== null) {
242
+ const rawPath = match[1] || match[2] || '';
243
+ let decoded;
244
+ try {
245
+ decoded = decodeURIComponent(rawPath);
246
+ } catch {
247
+ // Malformed percent-encoding — use the raw path as fallback
248
+ decoded = rawPath;
249
+ }
250
+ if (decoded) lastPath = decoded;
251
+ }
252
+ if (lastPath && lastPath !== currentCwd) {
253
+ currentCwd = lastPath;
254
+ broadcast({ type: 'cwd', path: currentCwd });
255
+ }
256
+ }
257
+
258
+ // ---------------------------------------------------------------------------
259
+ // Activity tracking
260
+ // ---------------------------------------------------------------------------
261
+
262
+ let isActive = false;
263
+ let activityTimer = null;
264
+
265
+ function touchActivity() {
266
+ if (!isActive) {
267
+ isActive = true;
268
+ broadcast({ type: 'activity', active: true });
269
+ }
270
+ if (activityTimer) clearTimeout(activityTimer);
271
+ activityTimer = setTimeout(() => {
272
+ isActive = false;
273
+ activityTimer = null;
274
+ broadcast({ type: 'activity', active: false });
275
+ }, ACTIVITY_IDLE_MS);
276
+ }
277
+
278
+ // ---------------------------------------------------------------------------
279
+ // PTY event handlers
280
+ // ---------------------------------------------------------------------------
281
+
282
+ ptyProcess.onData((data) => {
283
+ pushScrollback(data);
284
+ touchActivity();
285
+ parseOsc7(data);
286
+ broadcast({ type: 'output', data });
287
+ });
288
+
289
+ ptyProcess.onExit(({ exitCode: code, signal }) => {
290
+ exited = true;
291
+ exitCode = code ?? null;
292
+ exitSignal = signal != null ? String(signal) : null;
293
+
294
+ broadcast({ type: 'exit', code: exitCode, signal: exitSignal });
295
+
296
+ // Write sidecar exit file so the server can detect exits that happened
297
+ // while it was disconnected.
298
+ try {
299
+ const exitData = JSON.stringify({ code: exitCode, timestamp: Date.now() });
300
+ fs.writeFileSync(socketPath + '.exit', exitData, 'utf8');
301
+ } catch {
302
+ // Best effort
303
+ }
304
+
305
+ // Grace period: stay alive so the server can reconnect and read exit info
306
+ gracePeriodTimer = setTimeout(() => {
307
+ cleanupAndExit();
308
+ }, GRACE_PERIOD_MS);
309
+ });
310
+
311
+ // ---------------------------------------------------------------------------
312
+ // Unix domain socket server
313
+ // ---------------------------------------------------------------------------
314
+
315
+ const server = net.createServer((socket) => {
316
+ clients.add(socket);
317
+
318
+ // On connect: send current state, activity, cwd, and scrollback
319
+ send(socket, { type: 'info', pid: ptyProcess.pid, exited, exitCode });
320
+ send(socket, { type: 'activity', active: isActive });
321
+ if (currentCwd) {
322
+ send(socket, { type: 'cwd', path: currentCwd });
323
+ }
324
+
325
+ const sb = getScrollback();
326
+ if (sb.length > 0) {
327
+ send(socket, { type: 'scrollback', data: sb });
328
+ }
329
+
330
+ // If PTY already exited, send exit message and cancel grace timer
331
+ if (exited) {
332
+ send(socket, { type: 'exit', code: exitCode, signal: exitSignal });
333
+
334
+ // Cancel grace period — server has reconnected and received exit info
335
+ if (gracePeriodTimer) {
336
+ clearTimeout(gracePeriodTimer);
337
+ gracePeriodTimer = null;
338
+ }
339
+
340
+ // Server connected during grace period — it gets exit info via protocol,
341
+ // so delete the sidecar file.
342
+ try {
343
+ const exitFilePath = socketPath + '.exit';
344
+ if (fs.existsSync(exitFilePath)) {
345
+ fs.unlinkSync(exitFilePath);
346
+ }
347
+ } catch {
348
+ // Best effort
349
+ }
350
+ }
351
+
352
+ // ndjson line buffer for incoming messages
353
+ let buffer = '';
354
+
355
+ socket.on('data', (chunk) => {
356
+ buffer += chunk.toString();
357
+ let newlineIdx;
358
+ while ((newlineIdx = buffer.indexOf('\n')) !== -1) {
359
+ const line = buffer.slice(0, newlineIdx);
360
+ buffer = buffer.slice(newlineIdx + 1);
361
+ if (line.length === 0) continue;
362
+
363
+ let msg;
364
+ try {
365
+ msg = JSON.parse(line);
366
+ } catch {
367
+ continue; // Skip malformed messages
368
+ }
369
+
370
+ handleMessage(msg);
371
+ }
372
+ });
373
+
374
+ socket.on('error', () => {
375
+ clients.delete(socket);
376
+ });
377
+
378
+ socket.on('close', () => {
379
+ clients.delete(socket);
380
+ });
381
+ });
382
+
383
+ function handleMessage(msg) {
384
+ if (!msg || !msg.type) return;
385
+
386
+ switch (msg.type) {
387
+ case 'input':
388
+ // Security note: writing user-provided data to PTY stdin IS the intended
389
+ // behaviour — this is a remote terminal, so input by definition comes from
390
+ // the user. We validate type (must be string) and cap size to satisfy
391
+ // static-analysis scanners and prevent memory abuse.
392
+ if (!exited && typeof msg.data === 'string' && msg.data.length > 0) {
393
+ try {
394
+ const input = msg.data.length > MAX_INPUT_BYTES
395
+ ? msg.data.slice(0, MAX_INPUT_BYTES)
396
+ : msg.data;
397
+ ptyProcess.write(input); // CodeQL[js/code-injection] — intentional PTY stdin
398
+ } catch {
399
+ // PTY may have closed between check and write
400
+ }
401
+ }
402
+ break;
403
+
404
+ case 'resize':
405
+ if (!exited && typeof msg.cols === 'number' && typeof msg.rows === 'number') {
406
+ try {
407
+ ptyProcess.resize(msg.cols, msg.rows);
408
+ } catch {
409
+ // PTY may have closed
410
+ }
411
+ }
412
+ break;
413
+
414
+ case 'kill': {
415
+ if (!exited) {
416
+ const sig = msg.signal || 'SIGTERM';
417
+ try {
418
+ process.kill(ptyProcess.pid, sig);
419
+ } catch {
420
+ // Process may already be gone
421
+ }
422
+ }
423
+ break;
424
+ }
425
+ }
426
+ }
427
+
428
+ server.on('error', (err) => {
429
+ process.stderr.write(`pty-holder: socket server error: ${err.message}\n`);
430
+ cleanupAndExit();
431
+ });
432
+
433
+ server.listen(socketPath, () => {
434
+ // Signal parent that the holder is ready
435
+ if (typeof process.send === 'function') {
436
+ process.send({ type: 'ready' });
437
+ }
438
+ });
439
+
440
+ // ---------------------------------------------------------------------------
441
+ // Cleanup
442
+ // ---------------------------------------------------------------------------
443
+
444
+ function cleanupAndExit() {
445
+ // Close all client sockets
446
+ for (const socket of clients) {
447
+ try {
448
+ socket.destroy();
449
+ } catch {
450
+ // Best effort
451
+ }
452
+ }
453
+ clients.clear();
454
+
455
+ // Close the socket server
456
+ try {
457
+ server.close();
458
+ } catch {
459
+ // Best effort
460
+ }
461
+
462
+ // Delete the socket file
463
+ try {
464
+ if (fs.existsSync(socketPath)) {
465
+ fs.unlinkSync(socketPath);
466
+ }
467
+ } catch {
468
+ // Best effort
469
+ }
470
+
471
+ // Clean up shell hook temp files
472
+ try {
473
+ const zdotdir = path.join(os.tmpdir(), `shooter-zd-${id}`);
474
+ const rcPath = path.join(os.tmpdir(), `shooter-rc-${id}.sh`);
475
+ if (fs.existsSync(path.join(zdotdir, '.zshrc'))) {
476
+ fs.unlinkSync(path.join(zdotdir, '.zshrc'));
477
+ fs.rmdirSync(zdotdir);
478
+ }
479
+ if (fs.existsSync(rcPath)) {
480
+ fs.unlinkSync(rcPath);
481
+ }
482
+ } catch {
483
+ // Best effort
484
+ }
485
+
486
+ // Clean up clipboard directory
487
+ try {
488
+ const clipImg = path.join(clipboardDir, 'image.png');
489
+ if (fs.existsSync(clipImg)) fs.unlinkSync(clipImg);
490
+ if (fs.existsSync(clipboardDir)) fs.rmdirSync(clipboardDir);
491
+ } catch {
492
+ // Best effort
493
+ }
494
+
495
+ process.exit(0);
496
+ }
497
+
498
+ // Handle signals for clean shutdown
499
+ process.on('SIGTERM', cleanupAndExit);
500
+ process.on('SIGINT', cleanupAndExit);
501
+
502
+ // Prevent unhandled exceptions from crashing silently
503
+ process.on('uncaughtException', (err) => {
504
+ process.stderr.write(`pty-holder[${id}]: uncaught exception: ${err.message}\n`);
505
+ cleanupAndExit();
506
+ });
507
+
508
+ process.on('unhandledRejection', (err) => {
509
+ process.stderr.write(`pty-holder[${id}]: unhandled rejection: ${err}\n`);
510
+ });