relay-ide 0.1.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 (506) hide show
  1. package/README.md +259 -0
  2. package/dist/bin/claude-remote-cli.js +390 -0
  3. package/dist/bin/relay-ide.js +390 -0
  4. package/dist/frontend/assets/abap-BdImnpbu.js +1 -0
  5. package/dist/frontend/assets/actionscript-3-CoDkCxhg.js +1 -0
  6. package/dist/frontend/assets/ada-bCR0ucgS.js +1 -0
  7. package/dist/frontend/assets/andromeeda-C4gqWexZ.js +1 -0
  8. package/dist/frontend/assets/angular-html-DA-rfuFy.js +1 -0
  9. package/dist/frontend/assets/angular-ts-BrjP3tb8.js +1 -0
  10. package/dist/frontend/assets/apache-Pmp26Uib.js +1 -0
  11. package/dist/frontend/assets/apex-D8_7TLub.js +1 -0
  12. package/dist/frontend/assets/apl-CORt7UWP.js +1 -0
  13. package/dist/frontend/assets/applescript-Co6uUVPk.js +1 -0
  14. package/dist/frontend/assets/ara-BRHolxvo.js +1 -0
  15. package/dist/frontend/assets/asciidoc-Ve4PFQV2.js +1 -0
  16. package/dist/frontend/assets/asm-D_Q5rh1f.js +1 -0
  17. package/dist/frontend/assets/astro-HNnZUWAn.js +1 -0
  18. package/dist/frontend/assets/aurora-x-D-2ljcwZ.js +1 -0
  19. package/dist/frontend/assets/awk-DMzUqQB5.js +1 -0
  20. package/dist/frontend/assets/ayu-dark-DYE7WIF3.js +1 -0
  21. package/dist/frontend/assets/ayu-light-BA47KaF1.js +1 -0
  22. package/dist/frontend/assets/ayu-mirage-32ctXXKs.js +1 -0
  23. package/dist/frontend/assets/ballerina-BFfxhgS-.js +1 -0
  24. package/dist/frontend/assets/bat-BkioyH1T.js +1 -0
  25. package/dist/frontend/assets/beancount-k_qm7-4y.js +1 -0
  26. package/dist/frontend/assets/berry-uYugtg8r.js +1 -0
  27. package/dist/frontend/assets/bibtex-CHM0blh-.js +1 -0
  28. package/dist/frontend/assets/bicep-Bmn6On1c.js +1 -0
  29. package/dist/frontend/assets/bird2-BIv1doCn.js +1 -0
  30. package/dist/frontend/assets/blade-BjGOyj-B.js +1 -0
  31. package/dist/frontend/assets/bsl-BO_Y6i37.js +1 -0
  32. package/dist/frontend/assets/c-BIGW1oBm.js +1 -0
  33. package/dist/frontend/assets/c3-eo99z4R2.js +1 -0
  34. package/dist/frontend/assets/cadence-Bv_4Rxtq.js +1 -0
  35. package/dist/frontend/assets/cairo-KRGpt6FW.js +1 -0
  36. package/dist/frontend/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  37. package/dist/frontend/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  38. package/dist/frontend/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  39. package/dist/frontend/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  40. package/dist/frontend/assets/clarity-D53aC0YG.js +1 -0
  41. package/dist/frontend/assets/clojure-P80f7IUj.js +1 -0
  42. package/dist/frontend/assets/cmake-D1j8_8rp.js +1 -0
  43. package/dist/frontend/assets/cobol-nBiQ_Alo.js +1 -0
  44. package/dist/frontend/assets/codeowners-Bp6g37R7.js +1 -0
  45. package/dist/frontend/assets/codeql-DsOJ9woJ.js +1 -0
  46. package/dist/frontend/assets/coffee-Ch7k5sss.js +1 -0
  47. package/dist/frontend/assets/common-lisp-Cg-RD9OK.js +1 -0
  48. package/dist/frontend/assets/coq-DkFqJrB1.js +1 -0
  49. package/dist/frontend/assets/cpp-CofmeUqb.js +1 -0
  50. package/dist/frontend/assets/crystal-DNxU26gB.js +1 -0
  51. package/dist/frontend/assets/csharp-COcwbKMJ.js +1 -0
  52. package/dist/frontend/assets/css-CLj8gQPS.js +1 -0
  53. package/dist/frontend/assets/csv-fuZLfV_i.js +1 -0
  54. package/dist/frontend/assets/cue-D82EKSYY.js +1 -0
  55. package/dist/frontend/assets/cypher-COkxafJQ.js +1 -0
  56. package/dist/frontend/assets/d-85-TOEBH.js +1 -0
  57. package/dist/frontend/assets/dark-plus-C3mMm8J8.js +1 -0
  58. package/dist/frontend/assets/dart-bE4Kk8sk.js +1 -0
  59. package/dist/frontend/assets/dax-CEL-wOlO.js +1 -0
  60. package/dist/frontend/assets/desktop-BmXAJ9_W.js +1 -0
  61. package/dist/frontend/assets/diff-D97Zzqfu.js +1 -0
  62. package/dist/frontend/assets/docker-BcOcwvcX.js +1 -0
  63. package/dist/frontend/assets/dotenv-Da5cRb03.js +1 -0
  64. package/dist/frontend/assets/dracula-BzJJZx-M.js +1 -0
  65. package/dist/frontend/assets/dracula-soft-BXkSAIEj.js +1 -0
  66. package/dist/frontend/assets/dream-maker-BtqSS_iP.js +1 -0
  67. package/dist/frontend/assets/edge-FbVlp4U3.js +1 -0
  68. package/dist/frontend/assets/elixir-CkH2-t6x.js +1 -0
  69. package/dist/frontend/assets/elm-DbKCFpqz.js +1 -0
  70. package/dist/frontend/assets/emacs-lisp-CXvaQtF9.js +1 -0
  71. package/dist/frontend/assets/erb-BYCe7drp.js +1 -0
  72. package/dist/frontend/assets/erlang-DsQrWhSR.js +1 -0
  73. package/dist/frontend/assets/everforest-dark-BgDCqdQA.js +1 -0
  74. package/dist/frontend/assets/everforest-light-C8M2exoo.js +1 -0
  75. package/dist/frontend/assets/fennel-BYunw83y.js +1 -0
  76. package/dist/frontend/assets/fish-BvzEVeQv.js +1 -0
  77. package/dist/frontend/assets/fluent-C4IJs8-o.js +1 -0
  78. package/dist/frontend/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  79. package/dist/frontend/assets/fortran-free-form-BxgE0vQu.js +1 -0
  80. package/dist/frontend/assets/fsharp-CXgrBDvD.js +1 -0
  81. package/dist/frontend/assets/gdresource-BOOCDP_w.js +1 -0
  82. package/dist/frontend/assets/gdscript-C5YyOfLZ.js +1 -0
  83. package/dist/frontend/assets/gdshader-DkwncUOv.js +1 -0
  84. package/dist/frontend/assets/genie-D0YGMca9.js +1 -0
  85. package/dist/frontend/assets/gherkin-DyxjwDmM.js +1 -0
  86. package/dist/frontend/assets/git-commit-F4YmCXRG.js +1 -0
  87. package/dist/frontend/assets/git-rebase-r7XF79zn.js +1 -0
  88. package/dist/frontend/assets/github-dark-DHJKELXO.js +1 -0
  89. package/dist/frontend/assets/github-dark-default-Cuk6v7N8.js +1 -0
  90. package/dist/frontend/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  91. package/dist/frontend/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  92. package/dist/frontend/assets/github-light-DAi9KRSo.js +1 -0
  93. package/dist/frontend/assets/github-light-default-D7oLnXFd.js +1 -0
  94. package/dist/frontend/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  95. package/dist/frontend/assets/gleam-BspZqrRM.js +1 -0
  96. package/dist/frontend/assets/glimmer-js-ByusRIyA.js +1 -0
  97. package/dist/frontend/assets/glimmer-ts-BfAWNZQY.js +1 -0
  98. package/dist/frontend/assets/glsl-DplSGwfg.js +1 -0
  99. package/dist/frontend/assets/gn-n2N0HUVH.js +1 -0
  100. package/dist/frontend/assets/gnuplot-DdkO51Og.js +1 -0
  101. package/dist/frontend/assets/go-C27-OAKa.js +1 -0
  102. package/dist/frontend/assets/graphql-ChdNCCLP.js +1 -0
  103. package/dist/frontend/assets/groovy-gcz8RCvz.js +1 -0
  104. package/dist/frontend/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  105. package/dist/frontend/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  106. package/dist/frontend/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  107. package/dist/frontend/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  108. package/dist/frontend/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  109. package/dist/frontend/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  110. package/dist/frontend/assets/hack-i7_Ulhet.js +1 -0
  111. package/dist/frontend/assets/haml-D5jkg6IW.js +1 -0
  112. package/dist/frontend/assets/handlebars-BpdQsYii.js +1 -0
  113. package/dist/frontend/assets/haskell-Df6bDoY_.js +1 -0
  114. package/dist/frontend/assets/haxe-CzTSHFRz.js +1 -0
  115. package/dist/frontend/assets/hcl-BWvSN4gD.js +1 -0
  116. package/dist/frontend/assets/hjson-D5-asLiD.js +1 -0
  117. package/dist/frontend/assets/hlsl-D3lLCCz7.js +1 -0
  118. package/dist/frontend/assets/horizon-BUw7H-hv.js +1 -0
  119. package/dist/frontend/assets/horizon-bright-CUuTKBJd.js +1 -0
  120. package/dist/frontend/assets/houston-DnULxvSX.js +1 -0
  121. package/dist/frontend/assets/html-derivative-DlHx6ybY.js +1 -0
  122. package/dist/frontend/assets/html-pp8916En.js +1 -0
  123. package/dist/frontend/assets/http-jrhK8wxY.js +1 -0
  124. package/dist/frontend/assets/hurl-irOxFIW8.js +1 -0
  125. package/dist/frontend/assets/hxml-Bvhsp5Yf.js +1 -0
  126. package/dist/frontend/assets/hy-DFXneXwc.js +1 -0
  127. package/dist/frontend/assets/imba-DGztddWO.js +1 -0
  128. package/dist/frontend/assets/ini-BEwlwnbL.js +1 -0
  129. package/dist/frontend/assets/java-CylS5w8V.js +1 -0
  130. package/dist/frontend/assets/javascript-wDzz0qaB.js +1 -0
  131. package/dist/frontend/assets/jinja-f2NsQr07.js +1 -0
  132. package/dist/frontend/assets/jison-wvAkD_A8.js +1 -0
  133. package/dist/frontend/assets/json-Cp-IABpG.js +1 -0
  134. package/dist/frontend/assets/json5-C9tS-k6U.js +1 -0
  135. package/dist/frontend/assets/jsonc-Des-eS-w.js +1 -0
  136. package/dist/frontend/assets/jsonl-DcaNXYhu.js +1 -0
  137. package/dist/frontend/assets/jsonnet-DFQXde-d.js +1 -0
  138. package/dist/frontend/assets/jssm-C2t-YnRu.js +1 -0
  139. package/dist/frontend/assets/jsx-g9-lgVsj.js +1 -0
  140. package/dist/frontend/assets/julia-CxzCAyBv.js +1 -0
  141. package/dist/frontend/assets/just-VxiPbLrw.js +1 -0
  142. package/dist/frontend/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  143. package/dist/frontend/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  144. package/dist/frontend/assets/kanagawa-wave-DWedfzmr.js +1 -0
  145. package/dist/frontend/assets/kdl-DV7GczEv.js +1 -0
  146. package/dist/frontend/assets/kotlin-BdnUsdx6.js +1 -0
  147. package/dist/frontend/assets/kusto-wEQ09or8.js +1 -0
  148. package/dist/frontend/assets/laserwave-DUszq2jm.js +1 -0
  149. package/dist/frontend/assets/latex-CWtU0Tv5.js +1 -0
  150. package/dist/frontend/assets/lean-BZvkOJ9d.js +1 -0
  151. package/dist/frontend/assets/less-B1dDrJ26.js +1 -0
  152. package/dist/frontend/assets/light-plus-B7mTdjB0.js +1 -0
  153. package/dist/frontend/assets/liquid-C0sCDyMI.js +1 -0
  154. package/dist/frontend/assets/llvm-DjAJT7YJ.js +1 -0
  155. package/dist/frontend/assets/log-2UxHyX5q.js +1 -0
  156. package/dist/frontend/assets/logo-BtOb2qkB.js +1 -0
  157. package/dist/frontend/assets/lua-BaeVxFsk.js +1 -0
  158. package/dist/frontend/assets/luau-C-HG3fhB.js +1 -0
  159. package/dist/frontend/assets/main-CL5_Wlhv.css +32 -0
  160. package/dist/frontend/assets/main-Czet4Z1x.js +371 -0
  161. package/dist/frontend/assets/make-CHLpvVh8.js +1 -0
  162. package/dist/frontend/assets/markdown-Cvjx9yec.js +1 -0
  163. package/dist/frontend/assets/marko-DjSrsDqO.js +1 -0
  164. package/dist/frontend/assets/material-theme-D5KoaKCx.js +1 -0
  165. package/dist/frontend/assets/material-theme-darker-BfHTSMKl.js +1 -0
  166. package/dist/frontend/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  167. package/dist/frontend/assets/material-theme-ocean-CyktbL80.js +1 -0
  168. package/dist/frontend/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  169. package/dist/frontend/assets/matlab-D7o27uSR.js +1 -0
  170. package/dist/frontend/assets/mdc-DTYItulj.js +1 -0
  171. package/dist/frontend/assets/mdx-Cmh6b_Ma.js +1 -0
  172. package/dist/frontend/assets/mermaid-mWjccvbQ.js +1 -0
  173. package/dist/frontend/assets/min-dark-CafNBF8u.js +1 -0
  174. package/dist/frontend/assets/min-light-CTRr51gU.js +1 -0
  175. package/dist/frontend/assets/mipsasm-CKIfxQSi.js +1 -0
  176. package/dist/frontend/assets/mojo-rZm6bMo-.js +1 -0
  177. package/dist/frontend/assets/monokai-D4h5O-jR.js +1 -0
  178. package/dist/frontend/assets/moonbit-_H4v1dQx.js +1 -0
  179. package/dist/frontend/assets/move-IF9eRakj.js +1 -0
  180. package/dist/frontend/assets/narrat-DRg8JJMk.js +1 -0
  181. package/dist/frontend/assets/nextflow-C-mBbutL.js +1 -0
  182. package/dist/frontend/assets/nextflow-groovy-vE_lwT2v.js +1 -0
  183. package/dist/frontend/assets/nginx-BpAMiNFr.js +1 -0
  184. package/dist/frontend/assets/night-owl-C39BiMTA.js +1 -0
  185. package/dist/frontend/assets/night-owl-light-CMTm3GFP.js +1 -0
  186. package/dist/frontend/assets/nim-BIad80T-.js +1 -0
  187. package/dist/frontend/assets/nix-CwoSXNpI.js +1 -0
  188. package/dist/frontend/assets/nord-Ddv68eIx.js +1 -0
  189. package/dist/frontend/assets/nushell-Cz2AlsmD.js +1 -0
  190. package/dist/frontend/assets/objective-c-DXmwc3jG.js +1 -0
  191. package/dist/frontend/assets/objective-cpp-CLxacb5B.js +1 -0
  192. package/dist/frontend/assets/ocaml-C0hk2d4L.js +1 -0
  193. package/dist/frontend/assets/odin-BBf5iR-q.js +1 -0
  194. package/dist/frontend/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  195. package/dist/frontend/assets/one-light-C3Wv6jpd.js +1 -0
  196. package/dist/frontend/assets/openscad-C4EeE6gA.js +1 -0
  197. package/dist/frontend/assets/pascal-D93ZcfNL.js +1 -0
  198. package/dist/frontend/assets/perl-NvoQZIq0.js +1 -0
  199. package/dist/frontend/assets/php-R6g_5hLQ.js +1 -0
  200. package/dist/frontend/assets/pkl-u5AG7uiY.js +1 -0
  201. package/dist/frontend/assets/plastic-3e1v2bzS.js +1 -0
  202. package/dist/frontend/assets/plsql-ChMvpjG-.js +1 -0
  203. package/dist/frontend/assets/po-BTJTHyun.js +1 -0
  204. package/dist/frontend/assets/poimandres-CS3Unz2-.js +1 -0
  205. package/dist/frontend/assets/polar-C0HS_06l.js +1 -0
  206. package/dist/frontend/assets/postcss-CXtECtnM.js +1 -0
  207. package/dist/frontend/assets/powerquery-CEu0bR-o.js +1 -0
  208. package/dist/frontend/assets/powershell-Dpen1YoG.js +1 -0
  209. package/dist/frontend/assets/prisma-Dd19v3D-.js +1 -0
  210. package/dist/frontend/assets/prolog-CbFg5uaA.js +1 -0
  211. package/dist/frontend/assets/proto-C7zT0LnQ.js +1 -0
  212. package/dist/frontend/assets/pug-DKIMFp6K.js +1 -0
  213. package/dist/frontend/assets/puppet-BMWR74SV.js +1 -0
  214. package/dist/frontend/assets/purescript-CklMAg4u.js +1 -0
  215. package/dist/frontend/assets/python-B6aJPvgy.js +1 -0
  216. package/dist/frontend/assets/qml-3beO22l8.js +1 -0
  217. package/dist/frontend/assets/qmldir-C8lEn-DE.js +1 -0
  218. package/dist/frontend/assets/qss-IeuSbFQv.js +1 -0
  219. package/dist/frontend/assets/r-Dspwwk_N.js +1 -0
  220. package/dist/frontend/assets/racket-BqYA7rlc.js +1 -0
  221. package/dist/frontend/assets/raku-DXvB9xmW.js +1 -0
  222. package/dist/frontend/assets/razor-BDqjjVU7.js +1 -0
  223. package/dist/frontend/assets/red-bN70gL4F.js +1 -0
  224. package/dist/frontend/assets/reg-C-SQnVFl.js +1 -0
  225. package/dist/frontend/assets/regexp-CDVJQ6XC.js +1 -0
  226. package/dist/frontend/assets/rel-C3B-1QV4.js +1 -0
  227. package/dist/frontend/assets/riscv-BM1_JUlF.js +1 -0
  228. package/dist/frontend/assets/ron-D8l8udqQ.js +1 -0
  229. package/dist/frontend/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  230. package/dist/frontend/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  231. package/dist/frontend/assets/rose-pine-qdsjHGoJ.js +1 -0
  232. package/dist/frontend/assets/rosmsg-BJDFO7_C.js +1 -0
  233. package/dist/frontend/assets/rst-CRjBmOyv.js +1 -0
  234. package/dist/frontend/assets/ruby-Wjq7vjNf.js +1 -0
  235. package/dist/frontend/assets/rust-B1yitclQ.js +1 -0
  236. package/dist/frontend/assets/sas-cz2c8ADy.js +1 -0
  237. package/dist/frontend/assets/sass-Cj5Yp3dK.js +1 -0
  238. package/dist/frontend/assets/scala-C151Ov-r.js +1 -0
  239. package/dist/frontend/assets/scheme-C98Dy4si.js +1 -0
  240. package/dist/frontend/assets/scss-D5BDwBP9.js +1 -0
  241. package/dist/frontend/assets/sdbl-DVxCFoDh.js +1 -0
  242. package/dist/frontend/assets/shaderlab-Dg9Lc6iA.js +1 -0
  243. package/dist/frontend/assets/shellscript-Yzrsuije.js +1 -0
  244. package/dist/frontend/assets/shellsession-BADoaaVG.js +1 -0
  245. package/dist/frontend/assets/slack-dark-BthQWCQV.js +1 -0
  246. package/dist/frontend/assets/slack-ochin-DqwNpetd.js +1 -0
  247. package/dist/frontend/assets/smalltalk-BERRCDM3.js +1 -0
  248. package/dist/frontend/assets/snazzy-light-Bw305WKR.js +1 -0
  249. package/dist/frontend/assets/solarized-dark-DXbdFlpD.js +1 -0
  250. package/dist/frontend/assets/solarized-light-L9t79GZl.js +1 -0
  251. package/dist/frontend/assets/solidity-rGO070M0.js +1 -0
  252. package/dist/frontend/assets/soy-8wufbnw4.js +1 -0
  253. package/dist/frontend/assets/sparql-rVzFXLq3.js +1 -0
  254. package/dist/frontend/assets/splunk-BtCnVYZw.js +1 -0
  255. package/dist/frontend/assets/sql-BLtJtn59.js +1 -0
  256. package/dist/frontend/assets/ssh-config-_ykCGR6B.js +1 -0
  257. package/dist/frontend/assets/stata-BH5u7GGu.js +1 -0
  258. package/dist/frontend/assets/stylus-BEDo0Tqx.js +1 -0
  259. package/dist/frontend/assets/surrealql-Bq5Q-fJD.js +1 -0
  260. package/dist/frontend/assets/svelte-Cy7k_4gC.js +1 -0
  261. package/dist/frontend/assets/swift-D82vCrfD.js +1 -0
  262. package/dist/frontend/assets/synthwave-84-CbfX1IO0.js +1 -0
  263. package/dist/frontend/assets/system-verilog-CnnmHF94.js +1 -0
  264. package/dist/frontend/assets/systemd-4A_iFExJ.js +1 -0
  265. package/dist/frontend/assets/talonscript-CkByrt1z.js +1 -0
  266. package/dist/frontend/assets/tasl-QIJgUcNo.js +1 -0
  267. package/dist/frontend/assets/tcl-dwOrl1Do.js +1 -0
  268. package/dist/frontend/assets/templ-DhtptRzy.js +1 -0
  269. package/dist/frontend/assets/terraform-BETggiCN.js +1 -0
  270. package/dist/frontend/assets/tex-idrVyKtj.js +1 -0
  271. package/dist/frontend/assets/tokyo-night-hegEt444.js +1 -0
  272. package/dist/frontend/assets/toml-vGWfd6FD.js +1 -0
  273. package/dist/frontend/assets/ts-tags-DQrlYJgV.js +1 -0
  274. package/dist/frontend/assets/tsv-B_m7g4N7.js +1 -0
  275. package/dist/frontend/assets/tsx-COt5Ahok.js +1 -0
  276. package/dist/frontend/assets/turtle-BsS91CYL.js +1 -0
  277. package/dist/frontend/assets/twig-xg9kU7Mw.js +1 -0
  278. package/dist/frontend/assets/typescript-BPQ3VLAy.js +1 -0
  279. package/dist/frontend/assets/typespec-CAFt9gP4.js +1 -0
  280. package/dist/frontend/assets/typst-DHCkPAjA.js +1 -0
  281. package/dist/frontend/assets/v-BcVCzyr7.js +1 -0
  282. package/dist/frontend/assets/vala-CsfeWuGM.js +1 -0
  283. package/dist/frontend/assets/vb-D17OF-Vu.js +1 -0
  284. package/dist/frontend/assets/verilog-BQ8w6xss.js +1 -0
  285. package/dist/frontend/assets/vesper-DU1UobuO.js +1 -0
  286. package/dist/frontend/assets/vhdl-CeAyd5Ju.js +1 -0
  287. package/dist/frontend/assets/viml-CJc9bBzg.js +1 -0
  288. package/dist/frontend/assets/vitesse-black-Bkuqu6BP.js +1 -0
  289. package/dist/frontend/assets/vitesse-dark-D0r3Knsf.js +1 -0
  290. package/dist/frontend/assets/vitesse-light-CVO1_9PV.js +1 -0
  291. package/dist/frontend/assets/vue-D2xRrEX4.js +1 -0
  292. package/dist/frontend/assets/vue-html-AaS7Mt5G.js +1 -0
  293. package/dist/frontend/assets/vue-vine-BoDAl6tE.js +1 -0
  294. package/dist/frontend/assets/vyper-CDx5xZoG.js +1 -0
  295. package/dist/frontend/assets/wasm-CG6Dc4jp.js +1 -0
  296. package/dist/frontend/assets/wasm-MzD3tlZU.js +1 -0
  297. package/dist/frontend/assets/wenyan-BV7otONQ.js +1 -0
  298. package/dist/frontend/assets/wgsl-Dx-B1_4e.js +1 -0
  299. package/dist/frontend/assets/wikitext-BhOHFoWU.js +1 -0
  300. package/dist/frontend/assets/wit-5i3qLPDT.js +1 -0
  301. package/dist/frontend/assets/wolfram-lXgVvXCa.js +1 -0
  302. package/dist/frontend/assets/xml-sdJ4AIDG.js +1 -0
  303. package/dist/frontend/assets/xsl-CtQFsRM5.js +1 -0
  304. package/dist/frontend/assets/yaml-Buea-lGh.js +1 -0
  305. package/dist/frontend/assets/zenscript-DVFEvuxE.js +1 -0
  306. package/dist/frontend/assets/zig-VOosw3JB.js +1 -0
  307. package/dist/frontend/icon-192.png +0 -0
  308. package/dist/frontend/icon-512.png +0 -0
  309. package/dist/frontend/icon.svg +8 -0
  310. package/dist/frontend/index.html +30 -0
  311. package/dist/frontend/manifest.json +25 -0
  312. package/dist/frontend/sw.js +66 -0
  313. package/dist/server/agent-events.js +39 -0
  314. package/dist/server/analytics.js +885 -0
  315. package/dist/server/auth.js +65 -0
  316. package/dist/server/belayer/executor.js +200 -0
  317. package/dist/server/belayer/intake.js +27 -0
  318. package/dist/server/belayer/pipeline.js +97 -0
  319. package/dist/server/belayer/pr-lifecycle.js +69 -0
  320. package/dist/server/belayer/prompts.js +154 -0
  321. package/dist/server/belayer/types.js +23 -0
  322. package/dist/server/branch-linker.js +137 -0
  323. package/dist/server/browser-content.js +145 -0
  324. package/dist/server/clipboard.js +63 -0
  325. package/dist/server/codex-hooks-adapter.js +93 -0
  326. package/dist/server/config.js +325 -0
  327. package/dist/server/gh-routes.js +163 -0
  328. package/dist/server/gh.js +276 -0
  329. package/dist/server/git-routes.js +154 -0
  330. package/dist/server/git.js +694 -0
  331. package/dist/server/github-app.js +218 -0
  332. package/dist/server/github-graphql.js +178 -0
  333. package/dist/server/hooks.js +373 -0
  334. package/dist/server/index.js +1549 -0
  335. package/dist/server/integration-github.js +137 -0
  336. package/dist/server/integration-jira.js +210 -0
  337. package/dist/server/integration-linear.js +176 -0
  338. package/dist/server/logger.js +18 -0
  339. package/dist/server/mobile-input-pipeline.js +129 -0
  340. package/dist/server/opencode-relay.js +53 -0
  341. package/dist/server/org-dashboard.js +241 -0
  342. package/dist/server/output-parsers/claude-parser.js +56 -0
  343. package/dist/server/output-parsers/codex-parser.js +13 -0
  344. package/dist/server/output-parsers/index.js +14 -0
  345. package/dist/server/output-parsers/null-parser.js +12 -0
  346. package/dist/server/output-parsers/opencode-parser.js +77 -0
  347. package/dist/server/pty-handler.js +586 -0
  348. package/dist/server/push.js +84 -0
  349. package/dist/server/review-poller.js +237 -0
  350. package/dist/server/sdk-handler.js +539 -0
  351. package/dist/server/service.js +189 -0
  352. package/dist/server/sessions.js +638 -0
  353. package/dist/server/telemetry.js +236 -0
  354. package/dist/server/ticket-transitions.js +166 -0
  355. package/dist/server/types.js +146 -0
  356. package/dist/server/utils.js +23 -0
  357. package/dist/server/watcher.js +661 -0
  358. package/dist/server/webhook-manager.js +547 -0
  359. package/dist/server/webhooks.js +73 -0
  360. package/dist/server/workspace-groups.js +363 -0
  361. package/dist/server/workspaces.js +1207 -0
  362. package/dist/server/ws.js +192 -0
  363. package/dist/test/EmptyState.spec.js +51 -0
  364. package/dist/test/action-coverage.test.js +139 -0
  365. package/dist/test/actions/registry.test.js +59 -0
  366. package/dist/test/actions/shortcuts.test.js +79 -0
  367. package/dist/test/agent-events.test.js +151 -0
  368. package/dist/test/analytics.test.js +158 -0
  369. package/dist/test/attention.test.js +91 -0
  370. package/dist/test/auth.test.js +105 -0
  371. package/dist/test/backend-state.test.js +47 -0
  372. package/dist/test/belayer-executor.test.js +33 -0
  373. package/dist/test/belayer-intake.test.js +44 -0
  374. package/dist/test/belayer-pipeline.test.js +113 -0
  375. package/dist/test/belayer-pr-lifecycle.test.js +26 -0
  376. package/dist/test/belayer-prompts.test.js +60 -0
  377. package/dist/test/belayer-types.test.js +69 -0
  378. package/dist/test/bin/claude-remote-cli.js +214 -0
  379. package/dist/test/boot-state.test.js +133 -0
  380. package/dist/test/branch-lifecycle.test.js +75 -0
  381. package/dist/test/branch-linker.test.js +236 -0
  382. package/dist/test/branch-rename.test.js +45 -0
  383. package/dist/test/branch-watcher.test.js +115 -0
  384. package/dist/test/browser-cli.test.js +91 -0
  385. package/dist/test/browser-content.test.js +93 -0
  386. package/dist/test/browser-tabs-ui.test.js +39 -0
  387. package/dist/test/changed-files-api.test.js +140 -0
  388. package/dist/test/clipboard.test.js +12 -0
  389. package/dist/test/codex-hooks-adapter.test.js +237 -0
  390. package/dist/test/components/EmptyState.spec.js +51 -0
  391. package/dist/test/components/ErrorToast.spec.js +65 -0
  392. package/dist/test/components/TuiCheckbox.spec.js +120 -0
  393. package/dist/test/components/TuiInput.spec.js +186 -0
  394. package/dist/test/components/leaf-component-migration.spec.js +104 -0
  395. package/dist/test/config-freshness.test.js +63 -0
  396. package/dist/test/config.test.js +813 -0
  397. package/dist/test/diff-summary.test.js +98 -0
  398. package/dist/test/display-state.test.js +179 -0
  399. package/dist/test/event-message-types.test.js +32 -0
  400. package/dist/test/file-tree-utils.test.js +167 -0
  401. package/dist/test/framework-types.test.js +183 -0
  402. package/dist/test/frameworks-api.test.js +93 -0
  403. package/dist/test/frontend/src/lib/pr-state.js +114 -0
  404. package/dist/test/fs-browse.test.js +246 -0
  405. package/dist/test/fuzzy-scorer.test.js +145 -0
  406. package/dist/test/gh-routes.test.js +156 -0
  407. package/dist/test/git-changed-files.test.js +152 -0
  408. package/dist/test/git-routes.test.js +146 -0
  409. package/dist/test/git-utils.test.js +68 -0
  410. package/dist/test/git-watcher.test.js +110 -0
  411. package/dist/test/git.test.js +140 -0
  412. package/dist/test/github-app.test.js +455 -0
  413. package/dist/test/github-graphql.test.js +301 -0
  414. package/dist/test/greetings.test.js +83 -0
  415. package/dist/test/hooks-agent-event.test.js +412 -0
  416. package/dist/test/hooks.test.js +149 -0
  417. package/dist/test/integration-github.test.js +220 -0
  418. package/dist/test/integration-jira.test.js +238 -0
  419. package/dist/test/integration-linear.test.js +293 -0
  420. package/dist/test/mobile-input.test.js +235 -0
  421. package/dist/test/opencode-relay.test.js +107 -0
  422. package/dist/test/org-dashboard.test.js +349 -0
  423. package/dist/test/output-parser.test.js +217 -0
  424. package/dist/test/paths.test.js +32 -0
  425. package/dist/test/pr-state.test.js +407 -0
  426. package/dist/test/pr-status.test.js +82 -0
  427. package/dist/test/presets.test.js +242 -0
  428. package/dist/test/pty-handler-multi-agent.test.js +149 -0
  429. package/dist/test/pty-handler.test.js +146 -0
  430. package/dist/test/pull-requests.test.js +78 -0
  431. package/dist/test/review-poller.test.js +349 -0
  432. package/dist/test/server/analytics.js +121 -0
  433. package/dist/test/server/auth.js +63 -0
  434. package/dist/test/server/branch-linker.js +124 -0
  435. package/dist/test/server/clipboard.js +56 -0
  436. package/dist/test/server/config.js +137 -0
  437. package/dist/test/server/git.js +308 -0
  438. package/dist/test/server/hooks.js +196 -0
  439. package/dist/test/server/index.js +1124 -0
  440. package/dist/test/server/integration-github.js +117 -0
  441. package/dist/test/server/integration-jira.js +164 -0
  442. package/dist/test/server/integration-linear.js +176 -0
  443. package/dist/test/server/mobile-input-pipeline.js +123 -0
  444. package/dist/test/server/org-dashboard.js +184 -0
  445. package/dist/test/server/output-parsers/claude-parser.js +54 -0
  446. package/dist/test/server/output-parsers/codex-parser.js +13 -0
  447. package/dist/test/server/output-parsers/index.js +7 -0
  448. package/dist/test/server/pty-handler.js +310 -0
  449. package/dist/test/server/push.js +80 -0
  450. package/dist/test/server/review-poller.js +218 -0
  451. package/dist/test/server/service.js +169 -0
  452. package/dist/test/server/sessions.js +434 -0
  453. package/dist/test/server/ticket-transitions.js +216 -0
  454. package/dist/test/server/types.js +20 -0
  455. package/dist/test/server/utils.js +22 -0
  456. package/dist/test/server/watcher.js +139 -0
  457. package/dist/test/server/workspaces.js +657 -0
  458. package/dist/test/server/ws.js +152 -0
  459. package/dist/test/server-startup.test.js +62 -0
  460. package/dist/test/service.test.js +43 -0
  461. package/dist/test/session-analytics-api.test.js +123 -0
  462. package/dist/test/session-analytics.test.js +425 -0
  463. package/dist/test/session-intent.test.js +249 -0
  464. package/dist/test/sessions.test.js +1152 -0
  465. package/dist/test/sidebar-items.test.js +164 -0
  466. package/dist/test/stores/boot-state-store.test.js +165 -0
  467. package/dist/test/stores/sessions-logic.test.js +191 -0
  468. package/dist/test/stores/toasts-store.test.js +66 -0
  469. package/dist/test/stores/ui-store.test.js +203 -0
  470. package/dist/test/stores/unread-store.test.js +97 -0
  471. package/dist/test/telemetry-api.test.js +54 -0
  472. package/dist/test/telemetry-sync.test.js +68 -0
  473. package/dist/test/telemetry.test.js +295 -0
  474. package/dist/test/terminal-zoom.test.js +102 -0
  475. package/dist/test/test/analytics.test.js +152 -0
  476. package/dist/test/test/auth.test.js +95 -0
  477. package/dist/test/test/branch-linker.test.js +231 -0
  478. package/dist/test/test/branch-rename.test.js +45 -0
  479. package/dist/test/test/clipboard.test.js +12 -0
  480. package/dist/test/test/config.test.js +281 -0
  481. package/dist/test/test/fs-browse.test.js +202 -0
  482. package/dist/test/test/git.test.js +67 -0
  483. package/dist/test/test/hooks.test.js +139 -0
  484. package/dist/test/test/integration-github.test.js +203 -0
  485. package/dist/test/test/integration-jira.test.js +294 -0
  486. package/dist/test/test/integration-linear.test.js +293 -0
  487. package/dist/test/test/mobile-input.test.js +193 -0
  488. package/dist/test/test/org-dashboard.test.js +240 -0
  489. package/dist/test/test/output-parser.test.js +95 -0
  490. package/dist/test/test/paths.test.js +32 -0
  491. package/dist/test/test/pr-state.test.js +220 -0
  492. package/dist/test/test/pull-requests.test.js +67 -0
  493. package/dist/test/test/review-poller.test.js +235 -0
  494. package/dist/test/test/service.test.js +43 -0
  495. package/dist/test/test/sessions.test.js +750 -0
  496. package/dist/test/test/ticket-transitions.test.js +130 -0
  497. package/dist/test/test/version.test.js +34 -0
  498. package/dist/test/test/worktrees.test.js +256 -0
  499. package/dist/test/ticket-transitions.test.js +312 -0
  500. package/dist/test/unread.test.js +23 -0
  501. package/dist/test/version.test.js +34 -0
  502. package/dist/test/webhook-manager.test.js +484 -0
  503. package/dist/test/webhooks.test.js +208 -0
  504. package/dist/test/workspace-groups.test.js +377 -0
  505. package/dist/test/worktrees.test.js +531 -0
  506. package/package.json +88 -0
package/README.md ADDED
@@ -0,0 +1,259 @@
1
+ # relay-ide
2
+
3
+ Control Claude Code from your phone or any browser — manage multiple terminal sessions across repos and worktrees with a mobile-friendly web UI.
4
+
5
+ ## Prerequisites
6
+
7
+ | Dependency | Why |
8
+ | --------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
9
+ | **[Node.js 24+](https://nodejs.org/)** | Runtime for the server |
10
+ | **[Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code)** | Default coding agent — must be in your `PATH` |
11
+ | **[Codex CLI](https://github.com/openai/codex)** | _Optional_ — alternative coding agent. Install if you want to use Codex sessions |
12
+ | **[GitHub CLI (`gh`)](https://cli.github.com/)** | _Optional_ — required for the **PRs tab**. Run `gh auth login` after installing. |
13
+
14
+ ## Getting Started
15
+
16
+ ### 1. Install
17
+
18
+ ```bash
19
+ npm install -g relay-ide
20
+ ```
21
+
22
+ ### 2. Start the server
23
+
24
+ ```bash
25
+ relay-ide --bg
26
+ ```
27
+
28
+ This installs a persistent background service (launchd on macOS, systemd on Linux) that starts on login and restarts on crash. See [Background Service](#background-service) for more options.
29
+
30
+ Or run in the foreground:
31
+
32
+ ```bash
33
+ relay-ide
34
+ ```
35
+
36
+ ### 3. Set your PIN
37
+
38
+ Open `http://localhost:3456` in your browser. On first visit you'll be prompted to create a PIN that protects access to your Claude sessions.
39
+
40
+ If you started the server in the foreground, you can set the PIN in the terminal instead.
41
+
42
+ ### 4. Add your project directories
43
+
44
+ Click **Settings** in the app to add root directories — these are parent folders that contain your git repos (scanned one level deep).
45
+
46
+ You can also edit `~/.config/relay-ide/config.json` directly:
47
+
48
+ ```json
49
+ {
50
+ "rootDirs": ["/home/you/projects", "/home/you/work"]
51
+ }
52
+ ```
53
+
54
+ ### 5. Access from your phone
55
+
56
+ Relay IDE binds to `0.0.0.0` by default, but you should **not** expose it to the public internet. Use [Tailscale](https://tailscale.com/) for a private encrypted connection between your devices — see [Remote Access](#remote-access) below.
57
+
58
+ ## Remote Access
59
+
60
+ The recommended way to access Relay IDE from another device (phone, tablet, laptop) is [Tailscale](https://tailscale.com/), which creates a private encrypted network using WireGuard.
61
+
62
+ 1. **Install Tailscale** on your computer and on your phone/tablet
63
+ - macOS: `brew install tailscale` or download from [tailscale.com/download](https://tailscale.com/download)
64
+ - Linux: follow the [install guide](https://tailscale.com/download/linux)
65
+ - iOS/Android: install the Tailscale app from your app store
66
+
67
+ 2. **Sign in** to the same Tailscale account on both devices
68
+
69
+ 3. **Find your computer's Tailscale IP** — run `tailscale ip` or check the admin console (looks like `100.x.y.z`)
70
+
71
+ 4. **Open the app** on your phone at `http://100.x.y.z:3456`
72
+
73
+ Your traffic is encrypted end-to-end, no ports are exposed to the internet, and only devices on your Tailscale network can reach the server.
74
+
75
+ > **Alternatives:** [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) or [ngrok](https://ngrok.com/) also work, but they expose your server to the public internet and rely on the PIN as your only defense.
76
+
77
+ ## Platform Support
78
+
79
+ Tested on **macOS** and **Linux**. Windows is not currently tested — file watching and PTY spawning may behave differently.
80
+
81
+ ## CLI Usage
82
+
83
+ ```
84
+ Usage: relay-ide [options]
85
+ relay-ide <command>
86
+
87
+ Commands:
88
+ update Update to the latest version from npm
89
+ install Install as a background service (survives reboot)
90
+ uninstall Stop and remove the background service
91
+ status Show whether the service is running
92
+ worktree Manage git worktrees (wraps git worktree)
93
+ add [path] [-b branch] [--yolo] Create worktree and launch Claude
94
+ remove <path> Forward to git worktree remove
95
+ list Forward to git worktree list
96
+ pin Manage authentication PIN
97
+ reset Reset the PIN (interactive, requires TTY)
98
+
99
+ Options:
100
+ --bg Shortcut: install and start as background service
101
+ --port <port> Override server port (default: 3456)
102
+ --host <host> Override bind address (default: 0.0.0.0)
103
+ --config <path> Path to config.json (default: ~/.config/relay-ide/config.json)
104
+ --yolo With 'worktree add': pass --dangerously-skip-permissions to Claude
105
+ --version, -v Show version
106
+ --help, -h Show this help
107
+ ```
108
+
109
+ ## Background Service
110
+
111
+ Run as a persistent service that starts on login and restarts on crash:
112
+
113
+ ```bash
114
+ relay-ide --bg
115
+ ```
116
+
117
+ Or with custom options:
118
+
119
+ ```bash
120
+ relay-ide install --port 4000
121
+ ```
122
+
123
+ Manage the service:
124
+
125
+ ```bash
126
+ relay-ide status # Check if running
127
+ relay-ide uninstall # Stop and remove
128
+ ```
129
+
130
+ - **macOS**: Uses launchd (`~/Library/LaunchAgents/`)
131
+ - **Linux**: Uses systemd user units (`~/.config/systemd/user/`)
132
+ - **Logs (macOS)**: `~/.config/relay-ide/logs/`
133
+ - **Logs (Linux)**: `journalctl --user -u relay-ide -f`
134
+
135
+ ## Configuration
136
+
137
+ Config is stored at `~/.config/relay-ide/config.json` (created on first run).
138
+
139
+ When running from source, it uses `./config.json` in the project root instead.
140
+
141
+ | Field | Default | Description |
142
+ | --------------- | --------- | -------------------------------------------------------------- |
143
+ | `host` | `0.0.0.0` | Bind address |
144
+ | `port` | `3456` | Server port |
145
+ | `cookieTTL` | `24h` | Auth cookie lifetime (e.g. `30m`, `12h`, `7d`) |
146
+ | `rootDirs` | `[]` | Directories containing your git repos (scanned one level deep) |
147
+ | `claudeCommand` | `claude` | Path to the Claude Code CLI binary |
148
+ | `claudeArgs` | `[]` | Extra arguments passed to every session |
149
+ | `defaultAgent` | `claude` | Default coding agent CLI (`claude` or `codex`) |
150
+
151
+ Root directories can also be managed from the **Settings** button in the app.
152
+
153
+ ### PIN Management
154
+
155
+ The PIN hash is stored in config under `pinHash`.
156
+
157
+ **Reset via CLI** (recommended):
158
+
159
+ ```bash
160
+ relay-ide pin reset
161
+ ```
162
+
163
+ This requires an interactive terminal. You'll be asked to verify your current PIN (if set), then enter a new one.
164
+
165
+ **Reset manually:**
166
+
167
+ 1. Delete the `pinHash` field from `~/.config/relay-ide/config.json`
168
+ 2. Restart the server (`relay-ide uninstall && relay-ide --bg`)
169
+ 3. Open the web UI and set a new PIN
170
+
171
+ ## Features
172
+
173
+ ### Session Management
174
+
175
+ - **Multi-agent support** — choose between Claude Code and Codex as the coding agent per session, with a configurable default in Settings
176
+ - **Repo sessions** — click any idle repo to instantly open Claude with `--continue` (no dialog), or start fresh from the new-session dialog
177
+ - **Branch-aware worktrees** — create worktrees from new or existing branches with a type-to-search branch picker
178
+ - **Worktree isolation** — each worktree session runs in its own git worktree under `.worktrees/`
179
+ - **Resume sessions** — click inactive worktrees to reconnect with `--continue`
180
+ - **Persistent session names** — display names, branch names, and timestamps survive server restarts
181
+ - **Scrollback buffer** — reconnect to a session and see prior output
182
+ - **Yolo mode** — skip permission prompts with `--dangerously-skip-permissions` (per-session pill button)
183
+ - **Worktree cleanup** — delete inactive worktrees via the trash pill button (removes worktree, prunes refs, deletes branch)
184
+
185
+ ### Pull Requests
186
+
187
+ - **Pull requests tab** — view your open PRs (authored and review-requested) via `gh` CLI, organized in collapsible per-repo groups with count badges, Author/Reviewer filter, and one-click session creation from any PR branch
188
+
189
+ ### GitHub Webhooks (real-time PR / CI updates)
190
+
191
+ By default the app polls GitHub every 30 seconds for PR and CI status. Connect a webhook for instant updates instead:
192
+
193
+ 1. **Connect GitHub** — open **Settings → Integrations → GitHub** and authorise the OAuth App. This requests the `repo` and `admin:repo_hook` scopes so the app can manage webhooks on your behalf.
194
+ 2. **Set up webhooks** — open **Settings → Integrations → Webhooks**. Click **Setup Webhook** next to any repo. The app creates a GitHub webhook pointing at a [smee.io](https://smee.io/) proxy channel and starts a local smee client to relay events.
195
+ 3. **Verify** — the webhook panel shows a health indicator (last event timestamp). Once connected, polling stops for that repo and updates arrive in real time.
196
+
197
+ > No public server is required. The smee.io proxy forwards GitHub webhook payloads to your local instance over a persistent SSE connection.
198
+
199
+ ### UI
200
+
201
+ - **Tabbed sidebar** — switch between Repos, Worktrees, and PRs views with shared filters and item counts
202
+ - **Sidebar filters** — filter by root directory, repo, or text search
203
+ - **Inline actions** — pill buttons on session cards for rename, YOLO, worktree creation, and delete (hover on desktop, long-press on mobile)
204
+ - **Resizable sidebar** — drag the sidebar edge to resize; collapse/expand with a button (persisted to localStorage)
205
+ - **Responsive layout** — works on desktop and mobile with slide-out sidebar
206
+ - **Touch toolbar** — mobile-friendly buttons for special keys (hidden on desktop)
207
+ - **Clipboard image paste** — paste screenshots directly into remote terminal sessions (macOS clipboard + xclip on Linux)
208
+
209
+ ### Settings
210
+
211
+ - **Full-screen Settings dialog** — redesigned as a scrollable full-screen modal with a table-of-contents drawer for quick section navigation
212
+ - **GitHub integration** — connect via OAuth App (Device Flow) for PR data, CI status, and webhook management
213
+ - **Webhook management** — self-service webhook CRUD per repo with smee.io proxy, health state, and auto-provision backfill
214
+ - **Jira integration** — connect Jira and configure project mappings for the org dashboard tickets panel
215
+
216
+ ### Operations
217
+
218
+ - **PIN-protected access** with rate limiting
219
+ - **Real-time updates** — worktree changes on disk are pushed to the browser instantly via WebSocket
220
+ - **Smart polling** — falls back to 30-second polling for repos without webhooks; switches off automatically once a webhook is active
221
+ - **Update notifications** — toast notification when a new version is available, with one-click update
222
+ - **CLI self-update** — `relay-ide update` to update from npm
223
+
224
+ ## Architecture
225
+
226
+ TypeScript + ESM backend (Express + node-pty + WebSocket) compiled to `dist/`. Svelte 5 frontend (runes + Vite) compiled to `dist/frontend/`.
227
+
228
+ ```
229
+ relay-ide/
230
+ ├── bin/
231
+ │ └── relay-ide.ts # CLI entry point
232
+ ├── server/
233
+ │ ├── index.ts # Express server, REST API routes
234
+ │ ├── sessions.ts # PTY session manager (node-pty)
235
+ │ ├── ws.ts # WebSocket relay (PTY ↔ browser)
236
+ │ ├── watcher.ts # File watcher for .worktrees/ changes
237
+ │ ├── auth.ts # PIN hashing, verification, rate limiting
238
+ │ ├── config.ts # Config loading/saving, worktree metadata
239
+ │ ├── clipboard.ts # System clipboard operations (image paste)
240
+ │ ├── service.ts # Background service management (launchd/systemd)
241
+ │ └── types.ts # Shared TypeScript interfaces
242
+ ├── frontend/
243
+ │ └── src/
244
+ │ ├── components/ # Svelte 5 components (Sidebar, Terminal, SessionList, etc.)
245
+ │ ├── lib/state/ # Reactive state modules (.svelte.ts)
246
+ │ ├── lib/api.ts # REST API client
247
+ │ ├── lib/ws.ts # WebSocket connection management
248
+ │ ├── lib/types.ts # Frontend TypeScript interfaces
249
+ │ ├── lib/utils.ts # Shared utilities (path display, time formatting, device detection)
250
+ │ └── lib/actions.ts # Svelte actions (scroll-on-hover, longpress-click)
251
+ ├── test/ # Unit tests (node:test)
252
+ ├── dist/ # Compiled output (gitignored)
253
+ ├── config.example.json
254
+ └── package.json
255
+ ```
256
+
257
+ ## License
258
+
259
+ MIT
@@ -0,0 +1,390 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console -- CLI entry point, user-facing stdout/stderr output */
3
+ import path from 'node:path';
4
+ import fs from 'node:fs';
5
+ import { execFile, spawn } from 'node:child_process';
6
+ import { promisify } from 'node:util';
7
+ import { fileURLToPath } from 'node:url';
8
+ import * as service from '../server/service.js';
9
+ import { DEFAULTS } from '../server/config.js';
10
+ import { createLogger } from '../server/logger.js';
11
+ const execFileAsync = promisify(execFile);
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+ const logger = createLogger('cli');
14
+ function execErrorMessage(err, fallback) {
15
+ const e = err;
16
+ return (e.stderr || e.message || fallback).trimEnd();
17
+ }
18
+ // Parse CLI flags
19
+ const args = process.argv.slice(2);
20
+ if (args.includes('--help') || args.includes('-h')) {
21
+ logger.info(`Usage: claude-remote-cli [options]
22
+ claude-remote-cli <command>
23
+
24
+ Commands:
25
+ update Update to the latest version from npm
26
+ install Install as a background service (survives reboot)
27
+ uninstall Stop and remove the background service
28
+ status Show whether the service is running
29
+ worktree Manage git worktrees (wraps git worktree)
30
+ add [path] [-b branch] [--yolo] Create worktree and launch Claude
31
+ remove <path> Forward to git worktree remove
32
+ list Forward to git worktree list
33
+ browser Open an HTML file in the remote viewer
34
+ <path> Path to HTML file
35
+ pin Manage authentication PIN
36
+ reset Reset the PIN (interactive, requires TTY)
37
+
38
+ Options:
39
+ --bg Shortcut: install and start as background service
40
+ --port <port> Override server port (default: 3456)
41
+ --host <host> Override bind address (default: 0.0.0.0)
42
+ --config <path> Path to config.json (default: ~/.config/claude-remote-cli/config.json)
43
+ --debug-log Enable SDK event debug logging to ~/.config/claude-remote-cli/debug/
44
+ --yolo With 'worktree add': pass --dangerously-skip-permissions to Claude
45
+ --version, -v Show version
46
+ --help, -h Show this help`);
47
+ process.exit(0);
48
+ }
49
+ if (args.includes('--version') || args.includes('-v')) {
50
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf-8'));
51
+ console.log(pkg.version);
52
+ process.exit(0);
53
+ }
54
+ function getArg(flag) {
55
+ const idx = args.indexOf(flag);
56
+ if (idx === -1 || idx + 1 >= args.length)
57
+ return undefined;
58
+ return args[idx + 1];
59
+ }
60
+ function resolveConfigPath() {
61
+ const explicit = getArg('--config');
62
+ if (explicit)
63
+ return explicit;
64
+ return path.join(service.CONFIG_DIR, 'config.json');
65
+ }
66
+ function runServiceCommand(fn) {
67
+ try {
68
+ fn();
69
+ }
70
+ catch (e) {
71
+ logger.error(e.message);
72
+ process.exit(1);
73
+ }
74
+ process.exit(0);
75
+ }
76
+ const command = args[0];
77
+ if (command === 'update') {
78
+ try {
79
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf-8'));
80
+ logger.info(`Current version: ${pkg.version}`);
81
+ const configPath = resolveConfigPath();
82
+ let channel = 'stable';
83
+ if (fs.existsSync(configPath)) {
84
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
85
+ if (config.updateChannel === 'nightly' ||
86
+ config.updateChannel === 'stable') {
87
+ channel = config.updateChannel;
88
+ }
89
+ }
90
+ const tag = channel === 'nightly' ? 'nightly' : 'latest';
91
+ logger.info(`Updating claude-remote-cli from ${channel} channel...`);
92
+ await execFileAsync('npm', ['install', '-g', `claude-remote-cli@${tag}`]);
93
+ const updatedPkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf-8'));
94
+ if (updatedPkg.version === pkg.version) {
95
+ logger.info(`Already on the latest version (${pkg.version}).`);
96
+ }
97
+ else {
98
+ logger.info(`Updated to ${updatedPkg.version}.`);
99
+ if (service.isInstalled()) {
100
+ logger.info('Background service detected — restarting...');
101
+ service.uninstall();
102
+ service.install({
103
+ configPath: resolveConfigPath(),
104
+ port: getArg('--port') ?? String(DEFAULTS.port),
105
+ host: getArg('--host') ?? DEFAULTS.host,
106
+ });
107
+ logger.info('Service restarted.');
108
+ }
109
+ }
110
+ }
111
+ catch (e) {
112
+ logger.error(`Update failed: ${e.message}`);
113
+ process.exit(1);
114
+ }
115
+ process.exit(0);
116
+ }
117
+ if (command === 'worktree') {
118
+ const wtArgs = args.slice(1);
119
+ const subCommand = wtArgs[0];
120
+ if (!subCommand) {
121
+ logger.error('Usage: claude-remote-cli worktree <add|remove|list> [options]');
122
+ process.exit(1);
123
+ }
124
+ if (subCommand !== 'add') {
125
+ try {
126
+ const result = await execFileAsync('git', ['worktree', ...wtArgs]);
127
+ if (result.stdout)
128
+ console.log(result.stdout.trimEnd());
129
+ }
130
+ catch (err) {
131
+ logger.error(execErrorMessage(err, 'git worktree failed'));
132
+ process.exit(1);
133
+ }
134
+ process.exit(0);
135
+ }
136
+ // Handle 'add' -- strip --yolo, determine path, forward to git, then launch claude
137
+ const hasYolo = wtArgs.includes('--yolo');
138
+ const gitWtArgs = wtArgs.filter(function (a) {
139
+ return a !== '--yolo';
140
+ });
141
+ const addSubArgs = gitWtArgs.slice(1);
142
+ let targetDir;
143
+ const bIdx = gitWtArgs.indexOf('-b');
144
+ const branchForDefault = bIdx !== -1 && bIdx + 1 < gitWtArgs.length
145
+ ? gitWtArgs[bIdx + 1]
146
+ : undefined;
147
+ if (addSubArgs.length === 0 || addSubArgs[0].startsWith('-')) {
148
+ let repoRoot;
149
+ try {
150
+ const result = await execFileAsync('git', [
151
+ 'rev-parse',
152
+ '--show-toplevel',
153
+ ]);
154
+ repoRoot = result.stdout.trim();
155
+ }
156
+ catch {
157
+ logger.error('Not inside a git repository.');
158
+ process.exit(1);
159
+ }
160
+ const dirName = branchForDefault
161
+ ? branchForDefault.replace(/\//g, '-')
162
+ : 'worktree-' + Date.now().toString(36);
163
+ targetDir = path.join(repoRoot, '.worktrees', dirName);
164
+ gitWtArgs.splice(1, 0, targetDir);
165
+ }
166
+ else {
167
+ targetDir = path.resolve(addSubArgs[0]);
168
+ }
169
+ try {
170
+ const result = await execFileAsync('git', ['worktree', ...gitWtArgs]);
171
+ if (result.stdout)
172
+ console.log(result.stdout.trimEnd());
173
+ }
174
+ catch (err) {
175
+ logger.error(execErrorMessage(err, 'git worktree add failed'));
176
+ process.exit(1);
177
+ }
178
+ logger.info(`Worktree created at ${targetDir}`);
179
+ const claudeArgs = [];
180
+ if (hasYolo)
181
+ claudeArgs.push('--dangerously-skip-permissions');
182
+ logger.info(`Launching claude${hasYolo ? ' (yolo mode)' : ''} in ${targetDir}...`);
183
+ const child = spawn('claude', claudeArgs, {
184
+ cwd: targetDir,
185
+ stdio: 'inherit',
186
+ env: { ...process.env, CLAUDECODE: undefined },
187
+ });
188
+ child.on('exit', (code) => {
189
+ process.exit(code ?? 0);
190
+ });
191
+ // Block until child exits via the handler above
192
+ await new Promise(() => { });
193
+ }
194
+ if (command === 'pin') {
195
+ const subCommand = args[1];
196
+ if (subCommand !== 'reset') {
197
+ logger.error('Usage: claude-remote-cli pin reset');
198
+ process.exit(1);
199
+ }
200
+ if (!process.stdin.isTTY) {
201
+ logger.error('PIN reset requires an interactive terminal.');
202
+ process.exit(1);
203
+ }
204
+ const configPath = resolveConfigPath();
205
+ if (!fs.existsSync(configPath)) {
206
+ logger.error('No config file found. Run claude-remote-cli first to create one.');
207
+ process.exit(1);
208
+ }
209
+ const { loadConfig: loadCfg, saveConfig: saveCfg } = await import('../server/config.js');
210
+ const { hashPin, verifyPin } = await import('../server/auth.js');
211
+ const config = loadCfg(configPath);
212
+ const readline = await import('node:readline');
213
+ function prompt(query, hidden = false) {
214
+ return new Promise((resolve) => {
215
+ if (hidden) {
216
+ process.stdout.write(query);
217
+ const stdin = process.stdin;
218
+ const wasRaw = stdin.isRaw;
219
+ if (stdin.setRawMode)
220
+ stdin.setRawMode(true);
221
+ let value = '';
222
+ const onData = (ch) => {
223
+ const c = ch.toString('utf8');
224
+ if (c === '\n' || c === '\r') {
225
+ if (stdin.setRawMode)
226
+ stdin.setRawMode(wasRaw ?? false);
227
+ stdin.removeListener('data', onData);
228
+ process.stdout.write('\n');
229
+ resolve(value);
230
+ }
231
+ else if (c === '\u007f' || c === '\b') {
232
+ if (value.length > 0) {
233
+ value = value.slice(0, -1);
234
+ process.stdout.write('\b \b');
235
+ }
236
+ }
237
+ else if (c >= ' ') {
238
+ value += c;
239
+ process.stdout.write('*');
240
+ }
241
+ };
242
+ stdin.on('data', onData);
243
+ }
244
+ else {
245
+ const rl = readline.createInterface({
246
+ input: process.stdin,
247
+ output: process.stdout,
248
+ });
249
+ rl.question(query, (answer) => {
250
+ rl.close();
251
+ resolve(answer);
252
+ });
253
+ }
254
+ });
255
+ }
256
+ // If PIN exists, optionally verify current PIN.
257
+ // Skipping is intentional: local shell access is proof of ownership
258
+ // (the user could edit the config file directly to delete pinHash).
259
+ if (config.pinHash) {
260
+ const current = await prompt('Current PIN (press Enter to skip): ', true);
261
+ if (current) {
262
+ const valid = await verifyPin(current, config.pinHash);
263
+ if (!valid) {
264
+ logger.error('Current PIN is incorrect.');
265
+ process.exit(1);
266
+ }
267
+ }
268
+ }
269
+ const newPin = await prompt('New PIN: ', true);
270
+ if (!newPin || newPin.length < 4) {
271
+ logger.error('PIN must be at least 4 characters.');
272
+ process.exit(1);
273
+ }
274
+ const confirmPin = await prompt('Confirm new PIN: ', true);
275
+ if (newPin !== confirmPin) {
276
+ logger.error('PINs do not match.');
277
+ process.exit(1);
278
+ }
279
+ config.pinHash = await hashPin(newPin);
280
+ saveCfg(configPath, config);
281
+ logger.info('PIN updated successfully. All existing sessions will need to re-authenticate.');
282
+ process.exit(0);
283
+ }
284
+ if (command === 'install' ||
285
+ command === 'uninstall' ||
286
+ command === 'status' ||
287
+ args.includes('--bg')) {
288
+ if (command === 'uninstall') {
289
+ runServiceCommand(() => {
290
+ service.uninstall();
291
+ });
292
+ }
293
+ else if (command === 'status') {
294
+ runServiceCommand(() => {
295
+ const st = service.status();
296
+ if (!st.installed) {
297
+ logger.info('Service is not installed.');
298
+ }
299
+ else if (st.running) {
300
+ logger.info('Service is installed and running.');
301
+ }
302
+ else {
303
+ logger.info('Service is installed but not running.');
304
+ }
305
+ });
306
+ }
307
+ else {
308
+ runServiceCommand(() => {
309
+ service.install({
310
+ configPath: resolveConfigPath(),
311
+ port: getArg('--port') ?? String(DEFAULTS.port),
312
+ host: getArg('--host') ?? DEFAULTS.host,
313
+ });
314
+ });
315
+ }
316
+ }
317
+ if (command === 'browser') {
318
+ const browserArgs = args.slice(1);
319
+ if (browserArgs.includes('--help') ||
320
+ browserArgs.includes('-h') ||
321
+ browserArgs.length === 0) {
322
+ logger.error(`Usage: claude-remote-cli browser <path>
323
+
324
+ Opens an HTML file in the remote browser viewer tab.
325
+
326
+ Arguments:
327
+ <path> Path to HTML file (absolute or relative)
328
+
329
+ Environment:
330
+ CLAUDE_REMOTE_PORT Server port (default: 3456)
331
+ CLAUDE_REMOTE_BROWSER_TOKEN Auth token for browser tab API`);
332
+ process.exit(browserArgs.includes('--help') || browserArgs.includes('-h') ? 0 : 1);
333
+ }
334
+ const filePath = path.resolve(browserArgs[0]);
335
+ if (!fs.existsSync(filePath)) {
336
+ logger.error(`Error: file not found: ${filePath}`);
337
+ process.exit(1);
338
+ }
339
+ const port = process.env['CLAUDE_REMOTE_PORT'] ?? String(DEFAULTS.port);
340
+ const token = process.env['CLAUDE_REMOTE_BROWSER_TOKEN'] ?? '';
341
+ if (!token) {
342
+ logger.error('Error: CLAUDE_REMOTE_BROWSER_TOKEN not set. Are you running inside a claude-remote-cli session?');
343
+ process.exit(1);
344
+ }
345
+ try {
346
+ const res = await fetch(`http://127.0.0.1:${port}/browser-tabs`, {
347
+ method: 'POST',
348
+ headers: {
349
+ 'Content-Type': 'application/json',
350
+ Authorization: `Bearer ${token}`,
351
+ },
352
+ body: JSON.stringify({ path: filePath }),
353
+ });
354
+ if (!res.ok) {
355
+ const body = await res.text();
356
+ logger.error(`Error: server returned ${res.status}: ${body}`);
357
+ process.exit(1);
358
+ }
359
+ const data = (await res.json());
360
+ if (data.refreshed) {
361
+ logger.info(`Refreshed: ${filePath}`);
362
+ }
363
+ else {
364
+ logger.info(`Opened: ${filePath}`);
365
+ }
366
+ process.exit(0);
367
+ }
368
+ catch (err) {
369
+ const msg = err instanceof Error ? err.message : String(err);
370
+ logger.error(`Error: could not connect to server on port ${port}: ${msg}`);
371
+ process.exit(1);
372
+ }
373
+ }
374
+ const configPath = resolveConfigPath();
375
+ const configDir = path.dirname(configPath);
376
+ // Ensure config directory exists
377
+ if (!fs.existsSync(configDir)) {
378
+ fs.mkdirSync(configDir, { recursive: true });
379
+ }
380
+ // Pass config path and CLI overrides to the server
381
+ process.env['CLAUDE_REMOTE_CONFIG'] = configPath;
382
+ const portArg = getArg('--port');
383
+ if (portArg !== undefined)
384
+ process.env['CLAUDE_REMOTE_PORT'] = portArg;
385
+ const hostArg = getArg('--host');
386
+ if (hostArg !== undefined)
387
+ process.env['CLAUDE_REMOTE_HOST'] = hostArg;
388
+ if (args.includes('--debug-log'))
389
+ process.env['CLAUDE_REMOTE_DEBUG_LOG'] = '1';
390
+ await import('../server/index.js');