@juspay/shooter 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (488) hide show
  1. package/.claude/hooks/notifier.cjs +117 -33
  2. package/.claude/settings.json +14 -14
  3. package/README.md +116 -84
  4. package/bin/shooter.cjs +471 -102
  5. package/build/client/_app/immutable/assets/{0.CM9Hl6d-.css → 0.BhZOCxO4.css} +1 -1
  6. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.br +0 -0
  7. package/build/client/_app/immutable/assets/0.BhZOCxO4.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/1.BYutk3aU.css +1 -0
  9. package/build/client/_app/immutable/assets/1.BYutk3aU.css.br +0 -0
  10. package/build/client/_app/immutable/assets/1.BYutk3aU.css.gz +0 -0
  11. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.gz +0 -0
  12. package/build/client/_app/immutable/assets/3.DGDHCVnW.css +1 -0
  13. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.br +0 -0
  14. package/build/client/_app/immutable/assets/3.DGDHCVnW.css.gz +0 -0
  15. package/build/client/_app/immutable/assets/4.BFUut--w.css +1 -0
  16. package/build/client/_app/immutable/assets/4.BFUut--w.css.br +0 -0
  17. package/build/client/_app/immutable/assets/4.BFUut--w.css.gz +0 -0
  18. package/build/client/_app/immutable/assets/5.BTOx7yt7.css +1 -0
  19. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.br +0 -0
  20. package/build/client/_app/immutable/assets/5.BTOx7yt7.css.gz +0 -0
  21. package/build/client/_app/immutable/assets/6.eZGZN-BF.css +1 -0
  22. package/build/client/_app/immutable/assets/6.eZGZN-BF.css.br +0 -0
  23. package/build/client/_app/immutable/assets/6.eZGZN-BF.css.gz +0 -0
  24. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css +1 -0
  25. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.br +0 -0
  26. package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.gz +0 -0
  27. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css +1 -0
  28. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.br +0 -0
  29. package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.gz +0 -0
  30. package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css +1 -0
  31. package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css.br +0 -0
  32. package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css.gz +0 -0
  33. package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css +1 -0
  34. package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css.br +0 -0
  35. package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css.gz +0 -0
  36. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.gz +0 -0
  37. package/build/client/_app/immutable/chunks/B-K5Sh65.js +1 -0
  38. package/build/client/_app/immutable/chunks/B-K5Sh65.js.br +0 -0
  39. package/build/client/_app/immutable/chunks/B-K5Sh65.js.gz +0 -0
  40. package/build/client/_app/immutable/chunks/B5NAKyil.js +20 -0
  41. package/build/client/_app/immutable/chunks/B5NAKyil.js.br +0 -0
  42. package/build/client/_app/immutable/chunks/B5NAKyil.js.gz +0 -0
  43. package/build/client/_app/immutable/chunks/B8XegpSE.js +1 -0
  44. package/build/client/_app/immutable/chunks/B8XegpSE.js.br +0 -0
  45. package/build/client/_app/immutable/chunks/B8XegpSE.js.gz +0 -0
  46. package/build/client/_app/immutable/chunks/B8zoBsv3.js +6 -0
  47. package/build/client/_app/immutable/chunks/B8zoBsv3.js.br +0 -0
  48. package/build/client/_app/immutable/chunks/B8zoBsv3.js.gz +0 -0
  49. package/build/client/_app/immutable/chunks/BLszSzTT.js +1 -0
  50. package/build/client/_app/immutable/chunks/BLszSzTT.js.br +0 -0
  51. package/build/client/_app/immutable/chunks/BLszSzTT.js.gz +0 -0
  52. package/build/client/_app/immutable/chunks/BOYo8yTr.js +1 -0
  53. package/build/client/_app/immutable/chunks/BOYo8yTr.js.br +0 -0
  54. package/build/client/_app/immutable/chunks/BOYo8yTr.js.gz +0 -0
  55. package/build/client/_app/immutable/chunks/BTGVxaYV.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/BYqGCrTe.js +1 -0
  57. package/build/client/_app/immutable/chunks/BYqGCrTe.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/BYqGCrTe.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/BlxrFPDK.js.gz +0 -0
  60. package/build/client/_app/immutable/chunks/Bu1aqm5j.js +1 -0
  61. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.br +0 -0
  62. package/build/client/_app/immutable/chunks/Bu1aqm5j.js.gz +0 -0
  63. package/build/client/_app/immutable/chunks/C4mLaWWx.js +1 -0
  64. package/build/client/_app/immutable/chunks/C4mLaWWx.js.br +0 -0
  65. package/build/client/_app/immutable/chunks/C4mLaWWx.js.gz +0 -0
  66. package/build/client/_app/immutable/chunks/CQjSATpv.js +61 -0
  67. package/build/client/_app/immutable/chunks/CQjSATpv.js.br +0 -0
  68. package/build/client/_app/immutable/chunks/CQjSATpv.js.gz +0 -0
  69. package/build/client/_app/immutable/chunks/CSoRdFvv.js +1 -0
  70. package/build/client/_app/immutable/chunks/CSoRdFvv.js.br +0 -0
  71. package/build/client/_app/immutable/chunks/CSoRdFvv.js.gz +0 -0
  72. package/build/client/_app/immutable/chunks/CZHsSL_X.js +1 -0
  73. package/build/client/_app/immutable/chunks/CZHsSL_X.js.br +0 -0
  74. package/build/client/_app/immutable/chunks/CZHsSL_X.js.gz +0 -0
  75. package/build/client/_app/immutable/chunks/DLu6yJIZ.js.gz +0 -0
  76. package/build/client/_app/immutable/chunks/DSU1n5N_.js +1 -0
  77. package/build/client/_app/immutable/chunks/DSU1n5N_.js.br +0 -0
  78. package/build/client/_app/immutable/chunks/DSU1n5N_.js.gz +0 -0
  79. package/build/client/_app/immutable/chunks/DVkn4r72.js +1 -0
  80. package/build/client/_app/immutable/chunks/DVkn4r72.js.br +0 -0
  81. package/build/client/_app/immutable/chunks/DVkn4r72.js.gz +0 -0
  82. package/build/client/_app/immutable/chunks/DjsDGxCa.js +41 -0
  83. package/build/client/_app/immutable/chunks/DjsDGxCa.js.br +0 -0
  84. package/build/client/_app/immutable/chunks/DjsDGxCa.js.gz +0 -0
  85. package/build/client/_app/immutable/chunks/PPVm8Dsz.js.gz +0 -0
  86. package/build/client/_app/immutable/chunks/UJOiqIYE.js +1 -0
  87. package/build/client/_app/immutable/chunks/UJOiqIYE.js.br +0 -0
  88. package/build/client/_app/immutable/chunks/UJOiqIYE.js.gz +0 -0
  89. package/build/client/_app/immutable/chunks/r0JawsZc.js +2 -0
  90. package/build/client/_app/immutable/chunks/r0JawsZc.js.br +0 -0
  91. package/build/client/_app/immutable/chunks/r0JawsZc.js.gz +0 -0
  92. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js +2 -0
  93. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.br +0 -0
  94. package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.gz +0 -0
  95. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js +1 -0
  96. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.br +2 -0
  97. package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.gz +0 -0
  98. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js +1 -0
  99. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.br +0 -0
  100. package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.gz +0 -0
  101. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js +1 -0
  102. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.br +0 -0
  103. package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.gz +0 -0
  104. package/build/client/_app/immutable/nodes/2.CyRB2euU.js +1 -0
  105. package/build/client/_app/immutable/nodes/2.CyRB2euU.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/2.CyRB2euU.js.gz +0 -0
  107. package/build/client/_app/immutable/nodes/3.3yohCM25.js +3 -0
  108. package/build/client/_app/immutable/nodes/3.3yohCM25.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/3.3yohCM25.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js +1 -0
  111. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.gz +0 -0
  113. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js +4 -0
  114. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.br +0 -0
  115. package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.gz +0 -0
  116. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js +2 -0
  117. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.br +0 -0
  118. package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.gz +0 -0
  119. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js +2 -0
  120. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.br +0 -0
  121. package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.gz +0 -0
  122. package/build/client/_app/version.json +1 -1
  123. package/build/client/_app/version.json.br +0 -0
  124. package/build/client/_app/version.json.gz +0 -0
  125. package/build/client/favicon.svg.gz +0 -0
  126. package/build/client/manifest.json +13 -0
  127. package/build/client/manifest.json.br +0 -0
  128. package/build/client/manifest.json.gz +0 -0
  129. package/build/pty-holder.cjs +37 -8
  130. package/build/server/chunks/0-Vk38tI2J.js +9 -0
  131. package/build/server/chunks/0-Vk38tI2J.js.map +1 -0
  132. package/build/server/chunks/1-BvYQX5MR.js +9 -0
  133. package/build/server/chunks/1-BvYQX5MR.js.map +1 -0
  134. package/build/server/chunks/2-Cl7R4Qk2.js +9 -0
  135. package/build/server/chunks/2-Cl7R4Qk2.js.map +1 -0
  136. package/build/server/chunks/3-Ck7ewhOX.js +9 -0
  137. package/build/server/chunks/3-Ck7ewhOX.js.map +1 -0
  138. package/build/server/chunks/4-CnDeRm2Z.js +9 -0
  139. package/build/server/chunks/4-CnDeRm2Z.js.map +1 -0
  140. package/build/server/chunks/5-IxitzEvN.js +9 -0
  141. package/build/server/chunks/5-IxitzEvN.js.map +1 -0
  142. package/build/server/chunks/6-CyZ3r1iS.js +9 -0
  143. package/build/server/chunks/6-CyZ3r1iS.js.map +1 -0
  144. package/build/server/chunks/7-BmI7du46.js +9 -0
  145. package/build/server/chunks/7-BmI7du46.js.map +1 -0
  146. package/build/server/chunks/Button-Cs1aE6ka.js +80 -0
  147. package/build/server/chunks/Button-Cs1aE6ka.js.map +1 -0
  148. package/build/server/chunks/EmptyState-DDFH1K8g.js +26 -0
  149. package/build/server/chunks/EmptyState-DDFH1K8g.js.map +1 -0
  150. package/build/server/chunks/Icon-CEUrotA6.js +36 -0
  151. package/build/server/chunks/Icon-CEUrotA6.js.map +1 -0
  152. package/build/server/chunks/Shimmer-DB8W1zt6.js +10 -0
  153. package/build/server/chunks/Shimmer-DB8W1zt6.js.map +1 -0
  154. package/build/server/chunks/_error.svelte-uCOJNxvr.js +39 -0
  155. package/build/server/chunks/_error.svelte-uCOJNxvr.js.map +1 -0
  156. package/build/server/chunks/_layout.svelte-CtWmEJwe.js +56 -0
  157. package/build/server/chunks/_layout.svelte-CtWmEJwe.js.map +1 -0
  158. package/build/server/chunks/_page.svelte-BcZaKdX9.js +45 -0
  159. package/build/server/chunks/_page.svelte-BcZaKdX9.js.map +1 -0
  160. package/build/server/chunks/_page.svelte-BdYynOck.js +85 -0
  161. package/build/server/chunks/_page.svelte-BdYynOck.js.map +1 -0
  162. package/build/server/chunks/_page.svelte-BgevQjq1.js +101 -0
  163. package/build/server/chunks/_page.svelte-BgevQjq1.js.map +1 -0
  164. package/build/server/chunks/_page.svelte-CVq6tRb3.js +550 -0
  165. package/build/server/chunks/_page.svelte-CVq6tRb3.js.map +1 -0
  166. package/build/server/chunks/_page.svelte-CxWcQ0Am.js +651 -0
  167. package/build/server/chunks/_page.svelte-CxWcQ0Am.js.map +1 -0
  168. package/build/server/chunks/_page.svelte-DO4oa_LY.js +44 -0
  169. package/build/server/chunks/_page.svelte-DO4oa_LY.js.map +1 -0
  170. package/build/server/chunks/{_server.ts-CbDRDIoP.js → _server.ts-BStnNIcq.js} +9 -11
  171. package/build/server/chunks/_server.ts-BStnNIcq.js.map +1 -0
  172. package/build/server/chunks/{_server.ts-DRVbgm6k.js → _server.ts-CAxsWKvS.js} +22 -25
  173. package/build/server/chunks/_server.ts-CAxsWKvS.js.map +1 -0
  174. package/build/server/chunks/{_server.ts-CPa6DgIt.js → _server.ts-COu0vNpd.js} +6 -6
  175. package/build/server/chunks/_server.ts-COu0vNpd.js.map +1 -0
  176. package/build/server/chunks/{_server.ts-C29xzfaw.js → _server.ts-CTpcLUH8.js} +10 -10
  177. package/build/server/chunks/_server.ts-CTpcLUH8.js.map +1 -0
  178. package/build/server/chunks/{_server.ts-D4MNi4cD.js → _server.ts-Cf84YIaW.js} +3 -3
  179. package/build/server/chunks/{_server.ts-D4MNi4cD.js.map → _server.ts-Cf84YIaW.js.map} +1 -1
  180. package/build/server/chunks/{_server.ts-BL2FGb5Z.js → _server.ts-Ch-6iOHp.js} +99 -53
  181. package/build/server/chunks/_server.ts-Ch-6iOHp.js.map +1 -0
  182. package/build/server/chunks/_server.ts-CtH0dhUp.js +71 -0
  183. package/build/server/chunks/_server.ts-CtH0dhUp.js.map +1 -0
  184. package/build/server/chunks/_server.ts-DB_Kg97c.js +73 -0
  185. package/build/server/chunks/_server.ts-DB_Kg97c.js.map +1 -0
  186. package/build/server/chunks/{_server.ts-DfajWaqh.js → _server.ts-DV8zTCF9.js} +7 -9
  187. package/build/server/chunks/_server.ts-DV8zTCF9.js.map +1 -0
  188. package/build/server/chunks/_server.ts-DYpJImqd.js +99 -0
  189. package/build/server/chunks/_server.ts-DYpJImqd.js.map +1 -0
  190. package/build/server/chunks/{_server.ts-ColfDHW8.js → _server.ts-DYvb9ijZ.js} +21 -10
  191. package/build/server/chunks/_server.ts-DYvb9ijZ.js.map +1 -0
  192. package/build/server/chunks/{_server.ts-Cv_OrRuL.js → _server.ts-Deok2y88.js} +209 -34
  193. package/build/server/chunks/_server.ts-Deok2y88.js.map +1 -0
  194. package/build/server/chunks/{_server.ts-y9-WYDMa.js → _server.ts-WhTJBEJy.js} +5 -4
  195. package/build/server/chunks/{_server.ts-y9-WYDMa.js.map → _server.ts-WhTJBEJy.js.map} +1 -1
  196. package/build/server/chunks/{_server.ts-BjOJsoy4.js → _server.ts-XzT2UHM1.js} +6 -5
  197. package/build/server/chunks/_server.ts-XzT2UHM1.js.map +1 -0
  198. package/build/server/chunks/{_server.ts-BgdjBZco.js → _server.ts-tSpgyl1D.js} +7 -5
  199. package/build/server/chunks/_server.ts-tSpgyl1D.js.map +1 -0
  200. package/build/server/chunks/{_server.ts-BihKSdj_.js → _server.ts-vekTmWAx.js} +8 -8
  201. package/build/server/chunks/_server.ts-vekTmWAx.js.map +1 -0
  202. package/build/server/chunks/{auth-CEgFis71.js → auth-DeCdZ83n.js} +2 -2
  203. package/build/server/chunks/{auth-CEgFis71.js.map → auth-DeCdZ83n.js.map} +1 -1
  204. package/build/server/chunks/client-BdGHe_hY.js +25 -0
  205. package/build/server/chunks/client-BdGHe_hY.js.map +1 -0
  206. package/build/server/chunks/client2-CCBGA-2V.js +7 -0
  207. package/build/server/chunks/client2-CCBGA-2V.js.map +1 -0
  208. package/build/server/chunks/error-DDXB3duW.js +12 -0
  209. package/build/server/chunks/error-DDXB3duW.js.map +1 -0
  210. package/build/server/chunks/{exports-CJ0Q5XmL.js → index-DwaY1cAm.js} +1111 -1634
  211. package/build/server/chunks/index-DwaY1cAm.js.map +1 -0
  212. package/build/server/chunks/index-server-CrDaL06Y.js +9 -0
  213. package/build/server/chunks/index-server-CrDaL06Y.js.map +1 -0
  214. package/build/server/chunks/index2-CgclKpUj.js +58 -0
  215. package/build/server/chunks/index2-CgclKpUj.js.map +1 -0
  216. package/build/server/chunks/{library-apns-BHxLmuIx.js → library-apns-BqJbvSKh.js} +4 -4
  217. package/build/server/chunks/library-apns-BqJbvSKh.js.map +1 -0
  218. package/build/server/chunks/markdown-W_mTBct0.js +8 -0
  219. package/build/server/chunks/markdown-W_mTBct0.js.map +1 -0
  220. package/build/server/chunks/opencode-db-path-DcfhJtJy.js +15 -0
  221. package/build/server/chunks/opencode-db-path-DcfhJtJy.js.map +1 -0
  222. package/build/server/chunks/{pty-manager-C0FhBiVq.js → pty-manager-BQVB7IVj.js} +155 -326
  223. package/build/server/chunks/pty-manager-BQVB7IVj.js.map +1 -0
  224. package/build/server/chunks/root-DDSnEAZv.js +1171 -0
  225. package/build/server/chunks/root-DDSnEAZv.js.map +1 -0
  226. package/build/server/chunks/{shared-server-BDY8jh20.js → shared-server-sSGG17Df.js} +2 -3
  227. package/build/server/chunks/{shared-server-BDY8jh20.js.map → shared-server-sSGG17Df.js.map} +1 -1
  228. package/build/server/chunks/state.svelte-hBbXlUak.js +11 -0
  229. package/build/server/chunks/state.svelte-hBbXlUak.js.map +1 -0
  230. package/build/server/chunks/stores-DHNzYNpX.js +28 -0
  231. package/build/server/chunks/stores-DHNzYNpX.js.map +1 -0
  232. package/build/server/index.js +1085 -2242
  233. package/build/server/index.js.map +1 -1
  234. package/build/server/manifest.js +39 -25
  235. package/build/server/manifest.js.map +1 -1
  236. package/package.json +32 -9
  237. package/scripts/fix-generated-types.sh +37 -0
  238. package/scripts/homebrew/shooter.rb +51 -0
  239. package/scripts/install.sh +348 -186
  240. package/scripts/setup.cjs +215 -45
  241. package/server.ts +114 -71
  242. package/src/app.css +12 -3
  243. package/src/app.d.ts +13 -20
  244. package/src/app.html +3 -2
  245. package/src/generated/types/API.ts +280 -0
  246. package/src/generated/types/APN.ts +186 -203
  247. package/src/generated/types/CLI.ts +18 -25
  248. package/src/generated/types/Client.ts +589 -0
  249. package/src/generated/types/Config.ts +53 -0
  250. package/src/generated/types/Holder.ts +638 -0
  251. package/src/generated/types/JWT.ts +39 -50
  252. package/src/generated/types/Notification.ts +426 -0
  253. package/src/generated/types/OpenCode.ts +356 -0
  254. package/src/generated/types/Sessions.ts +570 -0
  255. package/src/generated/types/Terminal.ts +2184 -2071
  256. package/src/generated/types/WsProtocol.ts +2004 -0
  257. package/src/generated/types/index.ts +9 -3
  258. package/src/lib/env.ts +29 -0
  259. package/src/lib/modules/client/common/cache.ts +10 -2
  260. package/src/lib/modules/client/common/config-guard.ts +37 -5
  261. package/src/lib/modules/client/common/error.ts +10 -0
  262. package/src/lib/modules/client/common/index.ts +6 -5
  263. package/src/lib/modules/client/common/markdown.ts +22 -1
  264. package/src/lib/modules/client/common/native-bridge.ts +28 -20
  265. package/src/lib/modules/client/common/time.ts +13 -11
  266. package/src/lib/modules/client/terminal/ChatView.svelte +354 -74
  267. package/src/lib/modules/client/terminal/CommandPalette.svelte +3 -2
  268. package/src/lib/modules/client/terminal/ConnectionStatus.svelte +7 -1
  269. package/src/lib/modules/client/terminal/LaunchSheet.svelte +147 -84
  270. package/src/lib/modules/client/terminal/QuickKeys.svelte +3 -1
  271. package/src/lib/modules/client/terminal/ShortcutsHelp.svelte +2 -5
  272. package/src/lib/modules/client/terminal/keyboard-shortcuts.ts +27 -24
  273. package/src/lib/modules/client/terminal/xterm-wrapper.ts +74 -45
  274. package/src/lib/modules/server/apn/library-apns.ts +3 -2
  275. package/src/lib/modules/server/apn/notification-history.ts +2 -13
  276. package/src/lib/modules/server/apn/notification-sessions.ts +3 -13
  277. package/src/lib/modules/server/apn/pending-requests.ts +3 -8
  278. package/src/lib/modules/server/apn/types.ts +5 -4
  279. package/src/lib/modules/server/cli/index.ts +3 -2
  280. package/src/lib/modules/server/fcm/fcm-service.ts +8 -6
  281. package/src/lib/modules/server/sessions/jsonl-parser.ts +3 -3
  282. package/src/lib/modules/server/sessions/jsonl-reader.ts +86 -26
  283. package/src/lib/modules/server/sessions/opencode-db-path.ts +26 -0
  284. package/src/lib/modules/server/sessions/opencode-reader.ts +13 -15
  285. package/src/lib/modules/server/sessions/process-detector.ts +103 -0
  286. package/src/lib/modules/server/sessions/types.ts +11 -22
  287. package/src/lib/modules/server/terminal/holder-client.ts +272 -248
  288. package/src/lib/modules/server/terminal/opencode-watcher.ts +547 -556
  289. package/src/lib/modules/server/terminal/pty-holder.cjs +37 -8
  290. package/src/lib/modules/server/terminal/pty-manager.ts +157 -115
  291. package/src/lib/modules/server/terminal/session-watcher.ts +6 -4
  292. package/src/lib/modules/server/terminal/terminal-store.ts +131 -128
  293. package/src/lib/modules/server/utils/error.ts +9 -0
  294. package/src/lib/modules/server/ws/events-handler.ts +12 -6
  295. package/src/lib/modules/server/ws/keepalive.ts +86 -69
  296. package/src/lib/modules/server/ws/server.ts +43 -37
  297. package/src/lib/modules/server/ws/session-handler.ts +332 -147
  298. package/src/lib/modules/server/ws/terminal-handler.ts +29 -17
  299. package/src/lib/modules/server/ws/ticket-store.ts +29 -26
  300. package/src/lib/theme.css +30 -0
  301. package/src/lib/types/config.ts +1 -6
  302. package/src/routes/+error.svelte +94 -0
  303. package/src/routes/+layout.svelte +66 -31
  304. package/src/routes/+page.svelte +25 -22
  305. package/src/routes/api/debug/+server.ts +3 -1
  306. package/src/routes/api/device-token/+server.ts +60 -60
  307. package/src/routes/api/health/+server.ts +81 -73
  308. package/src/routes/api/notify/+server.ts +115 -68
  309. package/src/routes/api/qr-config/+server.ts +30 -32
  310. package/src/routes/api/response/+server.ts +9 -4
  311. package/src/routes/api/sessions/+server.ts +15 -5
  312. package/src/routes/api/sessions/connect/+server.ts +125 -0
  313. package/src/routes/api/sessions/detect/+server.ts +27 -0
  314. package/src/routes/api/terminals/+server.ts +26 -24
  315. package/src/routes/api/terminals/[id]/+server.ts +13 -7
  316. package/src/routes/api/terminals/[id]/paste-image/+server.ts +54 -52
  317. package/src/routes/api/terminals/[id]/resize/+server.ts +6 -3
  318. package/src/routes/api/webhook/+server.ts +8 -10
  319. package/src/routes/api/ws-status/+server.ts +7 -5
  320. package/src/routes/api/ws-ticket/+server.ts +42 -41
  321. package/src/routes/config/+page.svelte +149 -75
  322. package/src/routes/project/+page.svelte +165 -35
  323. package/src/routes/session/[id]/+page.svelte +479 -283
  324. package/src/routes/terminals/+page.svelte +58 -45
  325. package/src/routes/terminals/[id]/+page.svelte +223 -91
  326. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.br +0 -0
  327. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.gz +0 -0
  328. package/build/client/_app/immutable/assets/3.C0uFg0IS.css +0 -1
  329. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.br +0 -0
  330. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.gz +0 -0
  331. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +0 -1
  332. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
  333. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
  334. package/build/client/_app/immutable/assets/5.DRjApZQW.css +0 -1
  335. package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
  336. package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
  337. package/build/client/_app/immutable/assets/6.AraZrY8I.css +0 -1
  338. package/build/client/_app/immutable/assets/6.AraZrY8I.css.br +0 -0
  339. package/build/client/_app/immutable/assets/6.AraZrY8I.css.gz +0 -0
  340. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css +0 -1
  341. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.br +0 -0
  342. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.gz +0 -0
  343. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +0 -1
  344. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
  345. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
  346. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css +0 -1
  347. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.br +0 -0
  348. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.gz +0 -0
  349. package/build/client/_app/immutable/chunks/BNJphC1q.js +0 -56
  350. package/build/client/_app/immutable/chunks/BNJphC1q.js.br +0 -0
  351. package/build/client/_app/immutable/chunks/BNJphC1q.js.gz +0 -0
  352. package/build/client/_app/immutable/chunks/Bvk7mfPM.js +0 -1
  353. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.br +0 -0
  354. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.gz +0 -0
  355. package/build/client/_app/immutable/chunks/CAokzuPQ.js +0 -1
  356. package/build/client/_app/immutable/chunks/CAokzuPQ.js.br +0 -0
  357. package/build/client/_app/immutable/chunks/CAokzuPQ.js.gz +0 -0
  358. package/build/client/_app/immutable/chunks/CGLrx-H5.js +0 -1
  359. package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
  360. package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
  361. package/build/client/_app/immutable/chunks/CgCpWzEA.js +0 -1
  362. package/build/client/_app/immutable/chunks/CgCpWzEA.js.br +0 -0
  363. package/build/client/_app/immutable/chunks/CgCpWzEA.js.gz +0 -0
  364. package/build/client/_app/immutable/chunks/Cjwk_cGO.js +0 -6
  365. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.br +0 -0
  366. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.gz +0 -0
  367. package/build/client/_app/immutable/chunks/CtQ8EED1.js +0 -11
  368. package/build/client/_app/immutable/chunks/CtQ8EED1.js.br +0 -0
  369. package/build/client/_app/immutable/chunks/CtQ8EED1.js.gz +0 -0
  370. package/build/client/_app/immutable/chunks/DERQCisl.js +0 -1
  371. package/build/client/_app/immutable/chunks/DERQCisl.js.br +0 -0
  372. package/build/client/_app/immutable/chunks/DERQCisl.js.gz +0 -0
  373. package/build/client/_app/immutable/chunks/DKrg8TQs.js +0 -1
  374. package/build/client/_app/immutable/chunks/DKrg8TQs.js.br +0 -0
  375. package/build/client/_app/immutable/chunks/DKrg8TQs.js.gz +0 -0
  376. package/build/client/_app/immutable/chunks/Dkkpz_4D.js +0 -126
  377. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.br +0 -0
  378. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.gz +0 -0
  379. package/build/client/_app/immutable/chunks/DoczjQhA.js +0 -1
  380. package/build/client/_app/immutable/chunks/DoczjQhA.js.br +0 -0
  381. package/build/client/_app/immutable/chunks/DoczjQhA.js.gz +0 -0
  382. package/build/client/_app/immutable/chunks/RpcNruLP.js +0 -2
  383. package/build/client/_app/immutable/chunks/RpcNruLP.js.br +0 -0
  384. package/build/client/_app/immutable/chunks/RpcNruLP.js.gz +0 -0
  385. package/build/client/_app/immutable/chunks/a-St0Zwo.js +0 -1
  386. package/build/client/_app/immutable/chunks/a-St0Zwo.js.br +0 -0
  387. package/build/client/_app/immutable/chunks/a-St0Zwo.js.gz +0 -0
  388. package/build/client/_app/immutable/chunks/bo70OQUZ.js +0 -1
  389. package/build/client/_app/immutable/chunks/bo70OQUZ.js.br +0 -0
  390. package/build/client/_app/immutable/chunks/bo70OQUZ.js.gz +0 -0
  391. package/build/client/_app/immutable/entry/app.QvGgdvTI.js +0 -2
  392. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.br +0 -0
  393. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.gz +0 -0
  394. package/build/client/_app/immutable/entry/start.BntDNRMC.js +0 -1
  395. package/build/client/_app/immutable/entry/start.BntDNRMC.js.br +0 -0
  396. package/build/client/_app/immutable/entry/start.BntDNRMC.js.gz +0 -0
  397. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js +0 -1
  398. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.br +0 -0
  399. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.gz +0 -0
  400. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js +0 -1
  401. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.br +0 -0
  402. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.gz +0 -0
  403. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js +0 -1
  404. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.br +0 -0
  405. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.gz +0 -0
  406. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js +0 -3
  407. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.br +0 -0
  408. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.gz +0 -0
  409. package/build/client/_app/immutable/nodes/4.D-cIe70D.js +0 -1
  410. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.br +0 -0
  411. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.gz +0 -0
  412. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js +0 -1
  413. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.br +0 -0
  414. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.gz +0 -0
  415. package/build/client/_app/immutable/nodes/6.BB7QE48r.js +0 -2
  416. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.br +0 -0
  417. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.gz +0 -0
  418. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js +0 -2
  419. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.br +0 -0
  420. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.gz +0 -0
  421. package/build/client/manifest.webmanifest +0 -1
  422. package/build/client/registerSW.js +0 -1
  423. package/build/client/registerSW.js.br +0 -0
  424. package/build/client/registerSW.js.gz +0 -0
  425. package/build/client/sw.js +0 -222
  426. package/build/client/sw.js.br +0 -0
  427. package/build/client/sw.js.gz +0 -0
  428. package/build/client/workbox-5119daf5.js +0 -3395
  429. package/build/client/workbox-5119daf5.js.br +0 -0
  430. package/build/client/workbox-5119daf5.js.gz +0 -0
  431. package/build/server/chunks/0-q2IUp76Y.js +0 -9
  432. package/build/server/chunks/0-q2IUp76Y.js.map +0 -1
  433. package/build/server/chunks/1-CU50G5wZ.js +0 -9
  434. package/build/server/chunks/1-CU50G5wZ.js.map +0 -1
  435. package/build/server/chunks/2-D01t9s8T.js +0 -9
  436. package/build/server/chunks/2-D01t9s8T.js.map +0 -1
  437. package/build/server/chunks/3-5PUQ04wC.js +0 -9
  438. package/build/server/chunks/3-5PUQ04wC.js.map +0 -1
  439. package/build/server/chunks/4-e7gywnSG.js +0 -9
  440. package/build/server/chunks/4-e7gywnSG.js.map +0 -1
  441. package/build/server/chunks/5-CA1SA6KZ.js +0 -9
  442. package/build/server/chunks/5-CA1SA6KZ.js.map +0 -1
  443. package/build/server/chunks/6-71H221sV.js +0 -9
  444. package/build/server/chunks/6-71H221sV.js.map +0 -1
  445. package/build/server/chunks/7-Bo-vmdyz.js +0 -9
  446. package/build/server/chunks/7-Bo-vmdyz.js.map +0 -1
  447. package/build/server/chunks/_layout.svelte-SFHOxs74.js +0 -132
  448. package/build/server/chunks/_layout.svelte-SFHOxs74.js.map +0 -1
  449. package/build/server/chunks/_page.svelte-B4w-2wD-.js +0 -120
  450. package/build/server/chunks/_page.svelte-B4w-2wD-.js.map +0 -1
  451. package/build/server/chunks/_page.svelte-B_qAXjkh.js +0 -213
  452. package/build/server/chunks/_page.svelte-B_qAXjkh.js.map +0 -1
  453. package/build/server/chunks/_page.svelte-CsF1_TRG.js +0 -50
  454. package/build/server/chunks/_page.svelte-CsF1_TRG.js.map +0 -1
  455. package/build/server/chunks/_page.svelte-DJC6U-P0.js +0 -68
  456. package/build/server/chunks/_page.svelte-DJC6U-P0.js.map +0 -1
  457. package/build/server/chunks/_page.svelte-DQ6HBtsz.js +0 -407
  458. package/build/server/chunks/_page.svelte-DQ6HBtsz.js.map +0 -1
  459. package/build/server/chunks/_page.svelte-LbhhjP21.js +0 -148
  460. package/build/server/chunks/_page.svelte-LbhhjP21.js.map +0 -1
  461. package/build/server/chunks/_server.ts-BL2FGb5Z.js.map +0 -1
  462. package/build/server/chunks/_server.ts-BgdjBZco.js.map +0 -1
  463. package/build/server/chunks/_server.ts-BihKSdj_.js.map +0 -1
  464. package/build/server/chunks/_server.ts-BjOJsoy4.js.map +0 -1
  465. package/build/server/chunks/_server.ts-C29xzfaw.js.map +0 -1
  466. package/build/server/chunks/_server.ts-CPa6DgIt.js.map +0 -1
  467. package/build/server/chunks/_server.ts-CbDRDIoP.js.map +0 -1
  468. package/build/server/chunks/_server.ts-Cl1OEWL4.js +0 -54
  469. package/build/server/chunks/_server.ts-Cl1OEWL4.js.map +0 -1
  470. package/build/server/chunks/_server.ts-ColfDHW8.js.map +0 -1
  471. package/build/server/chunks/_server.ts-Cv_OrRuL.js.map +0 -1
  472. package/build/server/chunks/_server.ts-DRVbgm6k.js.map +0 -1
  473. package/build/server/chunks/_server.ts-DfajWaqh.js.map +0 -1
  474. package/build/server/chunks/client-CxCatAKr.js +0 -255
  475. package/build/server/chunks/client-CxCatAKr.js.map +0 -1
  476. package/build/server/chunks/error.svelte-BqdwMWdK.js +0 -26
  477. package/build/server/chunks/error.svelte-BqdwMWdK.js.map +0 -1
  478. package/build/server/chunks/exports-CJ0Q5XmL.js.map +0 -1
  479. package/build/server/chunks/index2-DAxIoAO-.js +0 -36
  480. package/build/server/chunks/index2-DAxIoAO-.js.map +0 -1
  481. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js +0 -137
  482. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js.map +0 -1
  483. package/build/server/chunks/library-apns-BHxLmuIx.js.map +0 -1
  484. package/build/server/chunks/markdown-Bxrl3cCF.js +0 -1241
  485. package/build/server/chunks/markdown-Bxrl3cCF.js.map +0 -1
  486. package/build/server/chunks/pty-manager-C0FhBiVq.js.map +0 -1
  487. package/build/server/chunks/stores-D0HorpgL.js +0 -36
  488. package/build/server/chunks/stores-D0HorpgL.js.map +0 -1
package/bin/shooter.cjs CHANGED
@@ -2,140 +2,509 @@
2
2
 
3
3
  // CLI entry point for the Shooter server.
4
4
  // Usage: shooter [command]
5
- // shooter start — Start the server (default)
6
- // shooter setup — Interactive setup wizard
7
- // shooter version — Show version
8
- // shooter help — Show usage
9
5
 
10
6
  'use strict';
11
7
 
8
+ const os = require('os');
12
9
  const path = require('path');
13
- const { spawn } = require('child_process');
10
+ const { spawn, execSync } = require('child_process');
14
11
  const fs = require('fs');
15
12
 
16
- // ── Resolve the package root ────────────────────────────────────────
17
- // Whether installed globally via npm or run from a local clone, the
18
- // package root is always one directory above this bin/ script.
13
+ // ── Resolve paths ───────────────────────────────────────────────────
19
14
  const PKG_ROOT = path.resolve(__dirname, '..');
15
+ const SHOOTER_HOME = process.env.SHOOTER_HOME || path.join(os.homedir(), '.shooter');
16
+ const PID_FILE = path.join(SHOOTER_HOME, 'shooter.pid');
17
+ const LOG_DIR = path.join(SHOOTER_HOME, 'logs');
18
+ const LOG_FILE = path.join(LOG_DIR, 'shooter.log');
19
+ const DEFAULT_PORT = 54007;
20
+ const LAUNCHD_LABEL = 'com.juspay.shooter';
21
+ const LAUNCHD_PLIST = path.join(os.homedir(), 'Library', 'LaunchAgents', `${LAUNCHD_LABEL}.plist`);
22
+ const SYSTEMD_UNIT = path.join(os.homedir(), '.config', 'systemd', 'user', 'shooter.service');
20
23
 
21
24
  const pkg = require(path.join(PKG_ROOT, 'package.json'));
22
25
 
26
+ // ── Signal Helpers ──────────────────────────────────────────────────
27
+ function signalCode(sig) {
28
+ return os.constants.signals[sig] || 0;
29
+ }
30
+
31
+ // ── PID helpers ─────────────────────────────────────────────────────
32
+ function readPid() {
33
+ try {
34
+ const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
35
+ if (isNaN(pid)) return null;
36
+ // Check if process is alive
37
+ process.kill(pid, 0);
38
+ // Verify it's actually a node/shooter process (prevent PID reuse attacks)
39
+ try {
40
+ const cmdline = execSync(`ps -p ${pid} -o command= 2>/dev/null`, { encoding: 'utf8' }).trim();
41
+ if (!cmdline.includes('shooter') && !cmdline.includes('server.ts') && !cmdline.includes('tsx')) {
42
+ // PID was reused by a different process — stale pidfile
43
+ fs.unlinkSync(PID_FILE);
44
+ return null;
45
+ }
46
+ } catch {
47
+ // ps failed — process may have exited between kill(0) and ps
48
+ return null;
49
+ }
50
+ return pid;
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ function writePid(pid) {
57
+ fs.mkdirSync(SHOOTER_HOME, { recursive: true });
58
+ fs.writeFileSync(PID_FILE, String(pid));
59
+ }
60
+
61
+ function removePid() {
62
+ try { fs.unlinkSync(PID_FILE); } catch {}
63
+ }
64
+
23
65
  // ── CLI argument parsing ────────────────────────────────────────────
24
66
  const args = process.argv.slice(2);
25
67
  const command = args[0] || 'start';
26
68
 
27
69
  switch (command) {
28
- case 'start':
29
- startServer();
30
- break;
31
- case 'setup':
32
- runSetup();
33
- break;
34
- case 'version':
35
- case '--version':
36
- case '-v':
37
- console.log(`shooter v${pkg.version}`);
38
- break;
39
- case 'help':
40
- case '--help':
41
- case '-h':
42
- showHelp();
43
- break;
44
- default:
45
- console.error(`Unknown command: ${command}\n`);
46
- showHelp();
47
- process.exit(1);
48
- }
49
-
50
- // ── Commands ────────────────────────────────────────────────────────
70
+ case 'start':
71
+ startServer();
72
+ break;
73
+ case 'stop':
74
+ stopServer();
75
+ break;
76
+ case 'status':
77
+ showStatus();
78
+ break;
79
+ case 'autostart':
80
+ manageAutostart(args[1]);
81
+ break;
82
+ case 'logs':
83
+ showLogs();
84
+ break;
85
+ case 'setup':
86
+ runSetup();
87
+ break;
88
+ case 'version':
89
+ case '--version':
90
+ case '-v':
91
+ console.log(`shooter v${pkg.version}`);
92
+ break;
93
+ case 'help':
94
+ case '--help':
95
+ case '-h':
96
+ showHelp();
97
+ break;
98
+ default:
99
+ console.error(`Unknown command: ${command}\n`);
100
+ showHelp();
101
+ process.exit(1);
102
+ }
103
+
104
+ // ── start ───────────────────────────────────────────────────────────
51
105
 
52
106
  function startServer() {
53
- const serverEntry = path.join(PKG_ROOT, 'server.ts');
54
-
55
- if (!fs.existsSync(serverEntry)) {
56
- console.error('Error: server.ts not found at', serverEntry);
57
- console.error('The Shooter package may not be installed correctly.');
58
- process.exit(1);
59
- }
60
-
61
- // Spawn tsx with the server entry point, inheriting stdio so the
62
- // user sees logs directly. Run from PKG_ROOT so relative imports
63
- // (like ./build/handler.js) resolve correctly.
64
- const child = spawn(
65
- process.execPath,
66
- ['--import', 'tsx', serverEntry, ...args.slice(1)],
67
- {
68
- cwd: PKG_ROOT,
69
- stdio: 'inherit',
70
- env: {
71
- ...process.env,
72
- // If the user has a .env in their cwd, dotenv in server.ts
73
- // will pick it up. But also hint where the package lives so
74
- // the server can find its own assets if needed.
75
- SHOOTER_PKG_ROOT: PKG_ROOT,
76
- },
77
- }
78
- );
79
-
80
- child.on('error', (err) => {
81
- console.error('Failed to start Shooter server:', err.message);
82
- process.exit(1);
83
- });
84
-
85
- child.on('exit', (code) => {
86
- process.exit(code ?? 0);
87
- });
88
-
89
- // Forward signals to the child so graceful shutdown works
90
- for (const sig of ['SIGTERM', 'SIGINT', 'SIGHUP']) {
91
- process.on(sig, () => child.kill(sig));
92
- }
107
+ const serverEntry = path.join(PKG_ROOT, 'server.ts');
108
+
109
+ if (!fs.existsSync(serverEntry)) {
110
+ console.error('Error: server.ts not found at', serverEntry);
111
+ console.error('The Shooter package may not be installed correctly.');
112
+ process.exit(1);
113
+ }
114
+
115
+ // Check if already running
116
+ const existingPid = readPid();
117
+ if (existingPid) {
118
+ console.log(`Shooter is already running (PID ${existingPid}).`);
119
+ console.log('Run "shooter stop" first, or "shooter status" for details.');
120
+ process.exit(0);
121
+ }
122
+
123
+ const child = spawn(process.execPath, ['--import', 'tsx', serverEntry, ...args.slice(1)], {
124
+ cwd: PKG_ROOT,
125
+ stdio: 'inherit',
126
+ env: {
127
+ ...process.env,
128
+ SHOOTER_PKG_ROOT: PKG_ROOT,
129
+ SHOOTER_HOME,
130
+ },
131
+ });
132
+
133
+ // Write PID file for status/stop commands
134
+ writePid(child.pid);
135
+
136
+ child.on('error', (err) => {
137
+ removePid();
138
+ console.error('Failed to start Shooter server:', err.message);
139
+ process.exit(1);
140
+ });
141
+
142
+ child.on('exit', (code, signal) => {
143
+ removePid();
144
+ if (signal) {
145
+ process.exit(128 + (signalCode(signal) || 1));
146
+ }
147
+ process.exit(code ?? 1);
148
+ });
149
+
150
+ // Forward signals to the child so graceful shutdown works
151
+ for (const sig of ['SIGTERM', 'SIGINT', 'SIGHUP']) {
152
+ process.on(sig, () => child.kill(sig));
153
+ }
93
154
  }
94
155
 
156
+ // ── stop ────────────────────────────────────────────────────────────
157
+
158
+ function stopServer() {
159
+ const pid = readPid();
160
+ if (!pid) {
161
+ console.log('Shooter is not running.');
162
+ process.exit(0);
163
+ }
164
+
165
+ console.log(`Stopping Shooter (PID ${pid})...`);
166
+ try {
167
+ process.kill(pid, 'SIGTERM');
168
+ // Wait briefly for clean shutdown
169
+ let waited = 0;
170
+ const check = setInterval(() => {
171
+ try {
172
+ process.kill(pid, 0);
173
+ waited += 100;
174
+ if (waited > 5000) {
175
+ clearInterval(check);
176
+ console.log('Force-killing...');
177
+ try { process.kill(pid, 'SIGKILL'); } catch {}
178
+ removePid();
179
+ console.log('Shooter stopped.');
180
+ }
181
+ } catch {
182
+ clearInterval(check);
183
+ removePid();
184
+ console.log('Shooter stopped.');
185
+ }
186
+ }, 100);
187
+ } catch (err) {
188
+ removePid();
189
+ console.log('Shooter is not running (stale PID file removed).');
190
+ }
191
+ }
192
+
193
+ // ── status ──────────────────────────────────────────────────────────
194
+
195
+ function resolvePort() {
196
+ // Read PORT from ~/.shooter/.env if not in environment
197
+ if (process.env.PORT) return process.env.PORT;
198
+ const envFile = path.join(SHOOTER_HOME, '.env');
199
+ try {
200
+ const contents = fs.readFileSync(envFile, 'utf8');
201
+ const match = contents.match(/^PORT=(\d+)/m);
202
+ if (match) return match[1];
203
+ } catch {}
204
+ return DEFAULT_PORT;
205
+ }
206
+
207
+ function showStatus() {
208
+ const pid = readPid();
209
+ const port = resolvePort();
210
+ const autostartEnabled = isAutostartInstalled();
211
+
212
+ if (pid) {
213
+ console.log(`Shooter is running`);
214
+ console.log(` PID: ${pid}`);
215
+ console.log(` URL: http://localhost:${port}`);
216
+ console.log(` Autostart: ${autostartEnabled ? 'enabled' : 'disabled'}`);
217
+ console.log(` Logs: ${LOG_FILE}`);
218
+ console.log(` Home: ${SHOOTER_HOME}`);
219
+ } else {
220
+ console.log('Shooter is not running.');
221
+ console.log(` Autostart: ${autostartEnabled ? 'enabled' : 'disabled'}`);
222
+ console.log(` Home: ${SHOOTER_HOME}`);
223
+ console.log('\nRun "shooter start" to start the server.');
224
+ }
225
+ }
226
+
227
+ // ── autostart ───────────────────────────────────────────────────────
228
+
229
+ function isAutostartInstalled() {
230
+ if (os.platform() === 'darwin') {
231
+ return fs.existsSync(LAUNCHD_PLIST);
232
+ } else if (os.platform() === 'linux') {
233
+ return fs.existsSync(SYSTEMD_UNIT);
234
+ }
235
+ return false;
236
+ }
237
+
238
+ function manageAutostart(action) {
239
+ if (!action || (action !== 'on' && action !== 'off')) {
240
+ const status = isAutostartInstalled() ? 'enabled' : 'disabled';
241
+ console.log(`Autostart is currently ${status}.`);
242
+ console.log('\nUsage:');
243
+ console.log(' shooter autostart on Enable autostart on login');
244
+ console.log(' shooter autostart off Disable autostart');
245
+ return;
246
+ }
247
+
248
+ if (action === 'on') {
249
+ enableAutostart();
250
+ } else {
251
+ disableAutostart();
252
+ }
253
+ }
254
+
255
+ function enableAutostart() {
256
+ const platform = os.platform();
257
+
258
+ if (platform === 'darwin') {
259
+ enableLaunchAgent();
260
+ } else if (platform === 'linux') {
261
+ enableSystemdUnit();
262
+ } else {
263
+ console.error(`Autostart is not supported on ${platform}.`);
264
+ console.log('You can add "shooter start" to your system startup scripts manually.');
265
+ process.exit(1);
266
+ }
267
+ }
268
+
269
+ function disableAutostart() {
270
+ const platform = os.platform();
271
+
272
+ if (platform === 'darwin') {
273
+ disableLaunchAgent();
274
+ } else if (platform === 'linux') {
275
+ disableSystemdUnit();
276
+ } else {
277
+ console.error(`Autostart is not supported on ${platform}.`);
278
+ process.exit(1);
279
+ }
280
+ }
281
+
282
+ // ── macOS LaunchAgent ───────────────────────────────────────────────
283
+
284
+ function enableLaunchAgent() {
285
+ const shooterBin = resolveShooterBin();
286
+ const nodeBin = process.execPath;
287
+
288
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
289
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
290
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
291
+ <plist version="1.0">
292
+ <dict>
293
+ <key>Label</key>
294
+ <string>${LAUNCHD_LABEL}</string>
295
+ <key>ProgramArguments</key>
296
+ <array>
297
+ <string>${nodeBin}</string>
298
+ <string>${shooterBin}</string>
299
+ <string>start</string>
300
+ </array>
301
+ <key>WorkingDirectory</key>
302
+ <string>${PKG_ROOT}</string>
303
+ <key>EnvironmentVariables</key>
304
+ <dict>
305
+ <key>PATH</key>
306
+ <string>${path.dirname(nodeBin)}:/usr/local/bin:/usr/bin:/bin</string>
307
+ <key>SHOOTER_HOME</key>
308
+ <string>${SHOOTER_HOME}</string>
309
+ </dict>
310
+ <key>KeepAlive</key>
311
+ <dict>
312
+ <key>SuccessfulExit</key>
313
+ <false/>
314
+ </dict>
315
+ <key>RunAtLoad</key>
316
+ <true/>
317
+ <key>StandardOutPath</key>
318
+ <string>${LOG_FILE}</string>
319
+ <key>StandardErrorPath</key>
320
+ <string>${LOG_FILE}</string>
321
+ <key>ThrottleInterval</key>
322
+ <integer>10</integer>
323
+ </dict>
324
+ </plist>`;
325
+
326
+ // Ensure directories exist
327
+ fs.mkdirSync(path.dirname(LAUNCHD_PLIST), { recursive: true });
328
+ fs.mkdirSync(LOG_DIR, { recursive: true });
329
+
330
+ // Unload existing if present
331
+ if (fs.existsSync(LAUNCHD_PLIST)) {
332
+ try { execSync(`launchctl unload "${LAUNCHD_PLIST}" 2>/dev/null`); } catch {}
333
+ }
334
+
335
+ fs.writeFileSync(LAUNCHD_PLIST, plist);
336
+ execSync(`launchctl load "${LAUNCHD_PLIST}"`);
337
+
338
+ console.log('Autostart enabled (macOS LaunchAgent).');
339
+ console.log(` Plist: ${LAUNCHD_PLIST}`);
340
+ console.log(` Logs: ${LOG_FILE}`);
341
+ console.log('\nShooter will start automatically on login.');
342
+ console.log('To start now: shooter start');
343
+ }
344
+
345
+ function disableLaunchAgent() {
346
+ if (!fs.existsSync(LAUNCHD_PLIST)) {
347
+ console.log('Autostart is not enabled.');
348
+ return;
349
+ }
350
+
351
+ try { execSync(`launchctl unload "${LAUNCHD_PLIST}" 2>/dev/null`); } catch {}
352
+ fs.unlinkSync(LAUNCHD_PLIST);
353
+ console.log('Autostart disabled. LaunchAgent removed.');
354
+ }
355
+
356
+ // ── Linux systemd user unit ─────────────────────────────────────────
357
+
358
+ function enableSystemdUnit() {
359
+ const shooterBin = resolveShooterBin();
360
+
361
+ const unit = `[Unit]
362
+ Description=Shooter — Mobile dev notifications & remote terminal
363
+ After=network.target
364
+
365
+ [Service]
366
+ Type=simple
367
+ ExecStart=${process.execPath} ${shooterBin} start
368
+ WorkingDirectory=${PKG_ROOT}
369
+ Environment=SHOOTER_HOME=${SHOOTER_HOME}
370
+ Restart=on-failure
371
+ RestartSec=10
372
+
373
+ [Install]
374
+ WantedBy=default.target
375
+ `;
376
+
377
+ fs.mkdirSync(path.dirname(SYSTEMD_UNIT), { recursive: true });
378
+ fs.mkdirSync(LOG_DIR, { recursive: true });
379
+ fs.writeFileSync(SYSTEMD_UNIT, unit);
380
+
381
+ execSync('systemctl --user daemon-reload');
382
+ execSync('systemctl --user enable shooter.service');
383
+ execSync('systemctl --user start shooter.service');
384
+
385
+ console.log('Autostart enabled (systemd user unit).');
386
+ console.log(` Unit: ${SYSTEMD_UNIT}`);
387
+ console.log(` Logs: journalctl --user -u shooter.service`);
388
+ console.log('\nShooter is now running and will start automatically on login.');
389
+ }
390
+
391
+ function disableSystemdUnit() {
392
+ if (!fs.existsSync(SYSTEMD_UNIT)) {
393
+ console.log('Autostart is not enabled.');
394
+ return;
395
+ }
396
+
397
+ try { execSync('systemctl --user stop shooter.service 2>/dev/null'); } catch {}
398
+ try { execSync('systemctl --user disable shooter.service 2>/dev/null'); } catch {}
399
+ fs.unlinkSync(SYSTEMD_UNIT);
400
+ try { execSync('systemctl --user daemon-reload'); } catch {}
401
+ console.log('Autostart disabled. systemd unit removed.');
402
+ }
403
+
404
+ // ── logs ────────────────────────────────────────────────────────────
405
+
406
+ function showLogs() {
407
+ const platform = os.platform();
408
+
409
+ // For systemd on Linux, use journalctl
410
+ if (platform === 'linux' && fs.existsSync(SYSTEMD_UNIT)) {
411
+ const child = spawn('journalctl', ['--user', '-u', 'shooter.service', '-f', '--no-pager', '-n', '50'], {
412
+ stdio: 'inherit',
413
+ });
414
+ child.on('exit', (code) => process.exit(code ?? 0));
415
+ for (const sig of ['SIGTERM', 'SIGINT']) {
416
+ process.on(sig, () => child.kill(sig));
417
+ }
418
+ return;
419
+ }
420
+
421
+ // For macOS LaunchAgent or manual runs, tail the log file
422
+ if (!fs.existsSync(LOG_FILE)) {
423
+ console.log('No log file found.');
424
+ console.log(`Expected at: ${LOG_FILE}`);
425
+ console.log('\nLogs are only written when running via autostart.');
426
+ console.log('For foreground runs, logs are printed directly to the terminal.');
427
+ return;
428
+ }
429
+
430
+ const child = spawn('tail', ['-f', '-n', '50', LOG_FILE], {
431
+ stdio: 'inherit',
432
+ });
433
+ child.on('exit', (code) => process.exit(code ?? 0));
434
+ for (const sig of ['SIGTERM', 'SIGINT']) {
435
+ process.on(sig, () => child.kill(sig));
436
+ }
437
+ }
438
+
439
+ // ── setup ───────────────────────────────────────────────────────────
440
+
95
441
  function runSetup() {
96
- const setupScript = path.join(PKG_ROOT, 'scripts', 'setup.cjs');
442
+ const setupScript = path.join(PKG_ROOT, 'scripts', 'setup.cjs');
97
443
 
98
- if (!fs.existsSync(setupScript)) {
99
- console.error('Error: Setup wizard not found at', setupScript);
100
- console.error('The setup script (scripts/setup.cjs) has not been created yet.');
101
- process.exit(1);
102
- }
444
+ if (!fs.existsSync(setupScript)) {
445
+ console.error('Error: Setup wizard not found at', setupScript);
446
+ console.error('The setup script (scripts/setup.cjs) has not been created yet.');
447
+ process.exit(1);
448
+ }
103
449
 
104
- const child = spawn(process.execPath, [setupScript, ...args.slice(1)], {
105
- cwd: process.cwd(),
106
- stdio: 'inherit',
107
- env: {
108
- ...process.env,
109
- SHOOTER_PKG_ROOT: PKG_ROOT,
110
- },
111
- });
450
+ const child = spawn(process.execPath, [setupScript, ...args.slice(1)], {
451
+ cwd: process.cwd(),
452
+ stdio: 'inherit',
453
+ env: {
454
+ ...process.env,
455
+ SHOOTER_PKG_ROOT: PKG_ROOT,
456
+ },
457
+ });
112
458
 
113
- child.on('error', (err) => {
114
- console.error('Failed to run setup wizard:', err.message);
115
- process.exit(1);
116
- });
459
+ child.on('error', (err) => {
460
+ console.error('Failed to run setup wizard:', err.message);
461
+ process.exit(1);
462
+ });
117
463
 
118
- child.on('exit', (code) => {
119
- process.exit(code ?? 0);
120
- });
464
+ child.on('exit', (code, signal) => {
465
+ if (signal) {
466
+ process.exit(128 + (signalCode(signal) || 1));
467
+ }
468
+ process.exit(code ?? 1);
469
+ });
121
470
  }
122
471
 
472
+ // ── help ────────────────────────────────────────────────────────────
473
+
123
474
  function showHelp() {
124
- console.log(`
475
+ console.log(
476
+ `
125
477
  Shooter v${pkg.version}
126
478
 
127
479
  Usage: shooter [command]
128
480
 
129
481
  Commands:
130
- start Start the Shooter server (default)
131
- setup Run the interactive setup wizard
132
- version Show version number
133
- help Show this help message
482
+ start Start the server (default)
483
+ stop Stop the running server
484
+ status Show server status
485
+ autostart on Start automatically on login (macOS/Linux)
486
+ autostart off Disable autostart
487
+ logs Tail server logs
488
+ setup Run the interactive setup wizard
489
+ version Show version number
490
+ help Show this help message
134
491
 
135
492
  Examples:
136
- shooter Start the server
137
- shooter start Start the server (explicit)
138
- shooter setup Run setup wizard
139
- shooter --version Show version
140
- `.trim());
493
+ shooter Start the server
494
+ shooter status Check if server is running
495
+ shooter autostart on Enable autostart on login
496
+ shooter logs Follow server logs
497
+ shooter setup Configure credentials
498
+ `.trim()
499
+ );
500
+ }
501
+
502
+ // ── Resolve shooter binary path ─────────────────────────────────────
503
+
504
+ function resolveShooterBin() {
505
+ // Prefer the global symlink if it exists
506
+ const globalBin = path.join(os.homedir(), '.local', 'bin', 'shooter');
507
+ if (fs.existsSync(globalBin)) return globalBin;
508
+ // Fall back to this script
509
+ return path.join(PKG_ROOT, 'bin', 'shooter.cjs');
141
510
  }