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
@@ -0,0 +1,220 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { derivePrAction, getActionPrompt, getStatusCssVar, shouldUseDarkText } from '../frontend/src/lib/pr-state.js';
4
+ describe('derivePrAction', () => {
5
+ it('returns none when no commits ahead and no PR', () => {
6
+ const input = {
7
+ commitsAhead: 0,
8
+ prState: null,
9
+ ciPassing: 0, ciFailing: 0, ciPending: 0, ciTotal: 0,
10
+ mergeable: null, unresolvedCommentCount: 0,
11
+ };
12
+ const action = derivePrAction(input);
13
+ assert.equal(action.type, 'none');
14
+ assert.equal(action.color, 'none');
15
+ assert.equal(action.label, '');
16
+ });
17
+ it('returns create-pr when commits ahead but no PR', () => {
18
+ const input = {
19
+ commitsAhead: 3,
20
+ prState: null,
21
+ ciPassing: 0, ciFailing: 0, ciPending: 0, ciTotal: 0,
22
+ mergeable: null, unresolvedCommentCount: 0,
23
+ };
24
+ const action = derivePrAction(input);
25
+ assert.equal(action.type, 'create-pr');
26
+ assert.equal(action.color, 'accent');
27
+ assert.equal(action.label, 'Create PR');
28
+ });
29
+ it('returns ready-for-review for draft PR', () => {
30
+ const input = {
31
+ commitsAhead: 5,
32
+ prState: 'DRAFT',
33
+ ciPassing: 0, ciFailing: 0, ciPending: 0, ciTotal: 0,
34
+ mergeable: null, unresolvedCommentCount: 0,
35
+ };
36
+ const action = derivePrAction(input);
37
+ assert.equal(action.type, 'ready-for-review');
38
+ assert.equal(action.color, 'muted');
39
+ assert.equal(action.label, 'Ready for Review');
40
+ });
41
+ it('returns review-pr for open PR with all CI passing', () => {
42
+ const input = {
43
+ commitsAhead: 2,
44
+ prState: 'OPEN',
45
+ ciPassing: 5, ciFailing: 0, ciPending: 0, ciTotal: 5,
46
+ mergeable: 'MERGEABLE', unresolvedCommentCount: 0,
47
+ };
48
+ const action = derivePrAction(input);
49
+ assert.equal(action.type, 'review-pr');
50
+ assert.equal(action.color, 'success');
51
+ assert.equal(action.label, 'Review PR');
52
+ });
53
+ it('returns review-pr for open PR with no CI checks', () => {
54
+ const input = {
55
+ commitsAhead: 1,
56
+ prState: 'OPEN',
57
+ ciPassing: 0, ciFailing: 0, ciPending: 0, ciTotal: 0,
58
+ mergeable: 'MERGEABLE', unresolvedCommentCount: 0,
59
+ };
60
+ const action = derivePrAction(input);
61
+ assert.equal(action.type, 'review-pr');
62
+ assert.equal(action.color, 'success');
63
+ });
64
+ it('returns fix-errors for open PR with failing CI', () => {
65
+ const input = {
66
+ commitsAhead: 2,
67
+ prState: 'OPEN',
68
+ ciPassing: 6, ciFailing: 2, ciPending: 0, ciTotal: 8,
69
+ mergeable: 'MERGEABLE', unresolvedCommentCount: 0,
70
+ };
71
+ const action = derivePrAction(input);
72
+ assert.equal(action.type, 'fix-errors');
73
+ assert.equal(action.color, 'error');
74
+ assert.equal(action.label, 'Fix Errors 2/8');
75
+ });
76
+ it('returns checks-running for open PR with pending CI', () => {
77
+ const input = {
78
+ commitsAhead: 1,
79
+ prState: 'OPEN',
80
+ ciPassing: 3, ciFailing: 0, ciPending: 2, ciTotal: 5,
81
+ mergeable: 'MERGEABLE', unresolvedCommentCount: 0,
82
+ };
83
+ const action = derivePrAction(input);
84
+ assert.equal(action.type, 'checks-running');
85
+ assert.equal(action.color, 'warning');
86
+ assert.equal(action.label, 'Checks Running...');
87
+ });
88
+ it('prioritizes failing over pending CI', () => {
89
+ const input = {
90
+ commitsAhead: 1,
91
+ prState: 'OPEN',
92
+ ciPassing: 3, ciFailing: 1, ciPending: 1, ciTotal: 5,
93
+ mergeable: 'MERGEABLE', unresolvedCommentCount: 0,
94
+ };
95
+ const action = derivePrAction(input);
96
+ assert.equal(action.type, 'fix-errors');
97
+ assert.equal(action.label, 'Fix Errors 1/5');
98
+ });
99
+ it('returns archive-merged for merged PR', () => {
100
+ const input = {
101
+ commitsAhead: 0,
102
+ prState: 'MERGED',
103
+ ciPassing: 5, ciFailing: 0, ciPending: 0, ciTotal: 5,
104
+ mergeable: null, unresolvedCommentCount: 0,
105
+ };
106
+ const action = derivePrAction(input);
107
+ assert.equal(action.type, 'archive-merged');
108
+ assert.equal(action.color, 'merged');
109
+ assert.equal(action.label, 'Archive');
110
+ });
111
+ it('returns archive-closed for closed PR', () => {
112
+ const input = {
113
+ commitsAhead: 0,
114
+ prState: 'CLOSED',
115
+ ciPassing: 0, ciFailing: 0, ciPending: 0, ciTotal: 0,
116
+ mergeable: null, unresolvedCommentCount: 0,
117
+ };
118
+ const action = derivePrAction(input);
119
+ assert.equal(action.type, 'archive-closed');
120
+ assert.equal(action.color, 'muted');
121
+ assert.equal(action.label, 'Archive');
122
+ });
123
+ it('returns fix-conflicts for open PR with CONFLICTING mergeable', () => {
124
+ const input = {
125
+ commitsAhead: 2,
126
+ prState: 'OPEN',
127
+ ciPassing: 0, ciFailing: 0, ciPending: 0, ciTotal: 0,
128
+ mergeable: 'CONFLICTING', unresolvedCommentCount: 0,
129
+ };
130
+ const action = derivePrAction(input);
131
+ assert.equal(action.type, 'fix-conflicts');
132
+ assert.equal(action.color, 'error');
133
+ assert.equal(action.label, 'Fix Conflicts');
134
+ });
135
+ it('prioritizes fix-conflicts over fix-errors', () => {
136
+ const input = {
137
+ commitsAhead: 2,
138
+ prState: 'OPEN',
139
+ ciPassing: 0, ciFailing: 3, ciPending: 0, ciTotal: 3,
140
+ mergeable: 'CONFLICTING', unresolvedCommentCount: 0,
141
+ };
142
+ const action = derivePrAction(input);
143
+ assert.equal(action.type, 'fix-conflicts');
144
+ });
145
+ it('returns resolve-comments when unresolved comments > 0 and CI passing', () => {
146
+ const input = {
147
+ commitsAhead: 1,
148
+ prState: 'OPEN',
149
+ ciPassing: 5, ciFailing: 0, ciPending: 0, ciTotal: 5,
150
+ mergeable: 'MERGEABLE', unresolvedCommentCount: 3,
151
+ };
152
+ const action = derivePrAction(input);
153
+ assert.equal(action.type, 'resolve-comments');
154
+ assert.equal(action.color, 'accent');
155
+ assert.equal(action.label, 'Resolve Comments (3)');
156
+ });
157
+ });
158
+ describe('getActionPrompt', () => {
159
+ it('returns prompt for create-pr', () => {
160
+ const prompt = getActionPrompt({ type: 'create-pr', color: 'accent', label: 'Create PR' }, { branchName: 'feat/my-feature' });
161
+ assert.ok(prompt);
162
+ assert.ok(prompt.includes('feat/my-feature'));
163
+ assert.ok(prompt.includes('pull request'));
164
+ });
165
+ it('returns prompt for fix-errors', () => {
166
+ const prompt = getActionPrompt({ type: 'fix-errors', color: 'error', label: 'Fix Errors 2/8' }, { branchName: 'bugfix/auth' });
167
+ assert.ok(prompt);
168
+ assert.ok(prompt.includes('bugfix/auth'));
169
+ assert.ok(prompt.includes('failing'));
170
+ });
171
+ it('returns prompt for review-pr', () => {
172
+ const prompt = getActionPrompt({ type: 'review-pr', color: 'success', label: 'Review PR' }, { branchName: 'main', prNumber: 42 });
173
+ assert.ok(prompt);
174
+ assert.ok(prompt.includes('Review'));
175
+ });
176
+ it('returns prompt for fix-conflicts', () => {
177
+ const prompt = getActionPrompt({ type: 'fix-conflicts', color: 'error', label: 'Fix Conflicts' }, { branchName: 'feat/foo', baseBranch: 'main' });
178
+ assert.ok(prompt);
179
+ assert.ok(prompt.includes('main'));
180
+ assert.ok(prompt.includes('conflict'));
181
+ });
182
+ it('returns prompt for resolve-comments', () => {
183
+ const prompt = getActionPrompt({ type: 'resolve-comments', color: 'accent', label: 'Resolve Comments (3)' }, { branchName: 'feat/foo', prNumber: 7, unresolvedCommentCount: 3 });
184
+ assert.ok(prompt);
185
+ assert.ok(prompt.includes('3'));
186
+ assert.ok(prompt.includes('#7'));
187
+ });
188
+ it('returns null for archive actions', () => {
189
+ assert.equal(getActionPrompt({ type: 'archive-merged', color: 'merged', label: 'Archive' }, { branchName: 'main' }), null);
190
+ assert.equal(getActionPrompt({ type: 'archive-closed', color: 'muted', label: 'Archive' }, { branchName: 'main' }), null);
191
+ });
192
+ it('returns null for none and checks-running', () => {
193
+ assert.equal(getActionPrompt({ type: 'none', color: 'none', label: '' }, { branchName: 'main' }), null);
194
+ assert.equal(getActionPrompt({ type: 'checks-running', color: 'warning', label: 'Checks Running...' }, { branchName: 'main' }), null);
195
+ });
196
+ });
197
+ describe('getStatusCssVar', () => {
198
+ it('maps all colors correctly', () => {
199
+ assert.equal(getStatusCssVar('accent'), 'var(--accent)');
200
+ assert.equal(getStatusCssVar('success'), 'var(--status-success)');
201
+ assert.equal(getStatusCssVar('error'), 'var(--status-error)');
202
+ assert.equal(getStatusCssVar('warning'), 'var(--status-warning)');
203
+ assert.equal(getStatusCssVar('merged'), 'var(--status-merged)');
204
+ assert.equal(getStatusCssVar('muted'), 'var(--border)');
205
+ assert.equal(getStatusCssVar('none'), 'transparent');
206
+ });
207
+ });
208
+ describe('shouldUseDarkText', () => {
209
+ it('returns true for success and warning (light backgrounds)', () => {
210
+ assert.equal(shouldUseDarkText('success'), true);
211
+ assert.equal(shouldUseDarkText('warning'), true);
212
+ });
213
+ it('returns false for dark backgrounds', () => {
214
+ assert.equal(shouldUseDarkText('accent'), false);
215
+ assert.equal(shouldUseDarkText('error'), false);
216
+ assert.equal(shouldUseDarkText('merged'), false);
217
+ assert.equal(shouldUseDarkText('muted'), false);
218
+ assert.equal(shouldUseDarkText('none'), false);
219
+ });
220
+ });
@@ -0,0 +1,67 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ describe('PullRequest types', () => {
4
+ it('constructs a valid author PR', () => {
5
+ const pr = {
6
+ number: 42,
7
+ title: 'Fix bug',
8
+ url: 'https://github.com/owner/repo/pull/42',
9
+ headRefName: 'fix/bug',
10
+ baseRefName: 'main',
11
+ state: 'OPEN',
12
+ author: 'testuser',
13
+ role: 'author',
14
+ updatedAt: '2026-02-24T00:00:00Z',
15
+ additions: 10,
16
+ deletions: 5,
17
+ reviewDecision: 'APPROVED', mergeable: 'MERGEABLE',
18
+ };
19
+ assert.equal(pr.role, 'author');
20
+ assert.equal(pr.state, 'OPEN');
21
+ });
22
+ it('constructs a valid reviewer PR', () => {
23
+ const pr = {
24
+ number: 43,
25
+ title: 'Add feature',
26
+ url: 'https://github.com/owner/repo/pull/43',
27
+ headRefName: 'feat/new',
28
+ baseRefName: 'main',
29
+ state: 'OPEN',
30
+ author: 'otheruser',
31
+ role: 'reviewer',
32
+ updatedAt: '2026-02-24T00:00:00Z',
33
+ additions: 50,
34
+ deletions: 20,
35
+ reviewDecision: null, mergeable: null,
36
+ };
37
+ assert.equal(pr.role, 'reviewer');
38
+ });
39
+ it('constructs a valid response with error', () => {
40
+ const response = {
41
+ prs: [],
42
+ error: 'gh_not_authenticated',
43
+ };
44
+ assert.equal(response.prs.length, 0);
45
+ assert.equal(response.error, 'gh_not_authenticated');
46
+ });
47
+ it('constructs a valid response without error', () => {
48
+ const response = {
49
+ prs: [{
50
+ number: 1,
51
+ title: 'Test',
52
+ url: 'https://github.com/o/r/pull/1',
53
+ headRefName: 'test',
54
+ baseRefName: 'main',
55
+ state: 'OPEN',
56
+ author: 'user',
57
+ role: 'author',
58
+ updatedAt: '2026-02-24T00:00:00Z',
59
+ additions: 0,
60
+ deletions: 0,
61
+ reviewDecision: null, mergeable: null,
62
+ }],
63
+ };
64
+ assert.equal(response.prs.length, 1);
65
+ assert.equal(response.error, undefined);
66
+ });
67
+ });
@@ -0,0 +1,235 @@
1
+ import { test, before, after, afterEach } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import os from 'node:os';
6
+ import { startPolling, stopPolling, isPolling } from '../server/review-poller.js';
7
+ import { saveConfig, DEFAULTS } from '../server/config.js';
8
+ // ─── Shared fixtures ──────────────────────────────────────────────────────────
9
+ let tmpDir;
10
+ let configPath;
11
+ const WORKSPACE_PATH = '/fake/workspace/my-repo';
12
+ before(() => {
13
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'review-poller-test-'));
14
+ configPath = path.join(tmpDir, 'config.json');
15
+ });
16
+ after(() => {
17
+ fs.rmSync(tmpDir, { recursive: true, force: true });
18
+ });
19
+ afterEach(() => {
20
+ // Guarantee no timer leaks between tests
21
+ stopPolling();
22
+ });
23
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
24
+ /** Builds a minimal GhNotification JSON string suitable for mock exec stdout. */
25
+ function makeNotificationLine(overrides) {
26
+ const { id = 'notif-1', reason = 'review_requested', prNumber = 42, ownerRepo = 'owner/my-repo', updatedAt = new Date().toISOString(), title = 'Test PR', } = overrides;
27
+ return JSON.stringify({
28
+ id,
29
+ reason,
30
+ subject: {
31
+ title,
32
+ url: `https://api.github.com/repos/${ownerRepo}/pulls/${prNumber}`,
33
+ type: 'PullRequest',
34
+ },
35
+ repository: { full_name: ownerRepo },
36
+ updated_at: updatedAt,
37
+ });
38
+ }
39
+ /**
40
+ * Creates a mock execAsync. Routes by command:
41
+ * - `gh api /notifications` → returns notification lines joined by newline
42
+ * - `git remote get-url origin` → returns the configured remote URL
43
+ * - `git fetch ...` → resolves with empty output
44
+ * - `git worktree add ...` → resolves with empty output (unless worktreeError is set)
45
+ */
46
+ function makeMockExec(opts) {
47
+ return async (cmd, args) => {
48
+ const command = cmd;
49
+ const argv = args;
50
+ opts.onExec?.(command, argv);
51
+ if (command === 'gh' && argv[0] === 'api') {
52
+ if (opts.ghError)
53
+ throw opts.ghError;
54
+ const lines = opts.notificationLines ?? [];
55
+ return { stdout: lines.join('\n'), stderr: '' };
56
+ }
57
+ if (command === 'git' && argv[0] === 'remote') {
58
+ if (opts.gitRemoteError)
59
+ throw opts.gitRemoteError;
60
+ const url = opts.remoteUrl ?? 'https://github.com/owner/my-repo.git';
61
+ return { stdout: url + '\n', stderr: '' };
62
+ }
63
+ if (command === 'git' && argv[0] === 'fetch') {
64
+ return { stdout: '', stderr: '' };
65
+ }
66
+ if (command === 'git' && argv[0] === 'worktree') {
67
+ if (opts.worktreeError)
68
+ throw opts.worktreeError;
69
+ return { stdout: '', stderr: '' };
70
+ }
71
+ throw new Error(`Unexpected exec call: ${command} ${argv.join(' ')}`);
72
+ };
73
+ }
74
+ /** Returns a deps object with sensible defaults. Override individual fields as needed. */
75
+ function makeDeps(overrides = {}) {
76
+ return {
77
+ configPath,
78
+ getWorkspacePaths: () => [WORKSPACE_PATH],
79
+ getWorkspaceSettings: () => undefined,
80
+ createSession: async () => { },
81
+ broadcastEvent: () => { },
82
+ execAsync: makeMockExec({}),
83
+ ...overrides,
84
+ };
85
+ }
86
+ /** Waits for at least one poll cycle to complete given the interval. */
87
+ function waitForCycles(intervalMs, cycles = 1) {
88
+ return new Promise((resolve) => setTimeout(resolve, intervalMs * cycles + 20));
89
+ }
90
+ // ─── Tests ────────────────────────────────────────────────────────────────────
91
+ test('isPolling() returns false initially', () => {
92
+ assert.equal(isPolling(), false);
93
+ });
94
+ test('startPolling() sets isPolling() to true', () => {
95
+ saveConfig(configPath, {
96
+ ...DEFAULTS,
97
+ automations: { pollIntervalMs: 60_000 },
98
+ });
99
+ startPolling(makeDeps());
100
+ assert.equal(isPolling(), true);
101
+ });
102
+ test('stopPolling() sets isPolling() to false', () => {
103
+ saveConfig(configPath, {
104
+ ...DEFAULTS,
105
+ automations: { pollIntervalMs: 60_000 },
106
+ });
107
+ startPolling(makeDeps());
108
+ assert.equal(isPolling(), true);
109
+ stopPolling();
110
+ assert.equal(isPolling(), false);
111
+ });
112
+ test('startPolling() is idempotent — calling twice does not create two timers', async () => {
113
+ const INTERVAL = 50;
114
+ let callCount = 0;
115
+ saveConfig(configPath, {
116
+ ...DEFAULTS,
117
+ automations: {
118
+ autoCheckoutReviewRequests: true,
119
+ pollIntervalMs: INTERVAL,
120
+ lastPollTimestamp: new Date().toISOString(),
121
+ },
122
+ });
123
+ const exec = makeMockExec({
124
+ onExec: (cmd, argv) => {
125
+ if (cmd === 'gh' && argv[0] === 'api')
126
+ callCount++;
127
+ },
128
+ });
129
+ const deps = makeDeps({ execAsync: exec });
130
+ startPolling(deps);
131
+ startPolling(deps); // second call must be a no-op
132
+ await waitForCycles(INTERVAL, 2);
133
+ // Two timer cycles elapsed. If only one timer exists, gh was called ~2 times.
134
+ // If startPolling were NOT idempotent (two timers), we would see ~4 calls.
135
+ assert.ok(callCount <= 3, `Expected at most 3 gh calls (got ${callCount}) — suggests only one timer running`);
136
+ });
137
+ test('first-run guard — when lastPollTimestamp is absent, no notifications are processed', async () => {
138
+ const INTERVAL = 50;
139
+ // Config without lastPollTimestamp — first-run scenario
140
+ saveConfig(configPath, {
141
+ ...DEFAULTS,
142
+ automations: {
143
+ autoCheckoutReviewRequests: true,
144
+ pollIntervalMs: INTERVAL,
145
+ // No lastPollTimestamp — module will default to "now"
146
+ },
147
+ });
148
+ const broadcastedEvents = [];
149
+ let fetchCallCount = 0;
150
+ const exec = makeMockExec({
151
+ // Notification is old (well before "now"), so it should NOT be processed
152
+ notificationLines: [
153
+ makeNotificationLine({
154
+ updatedAt: new Date(Date.now() - 60_000).toISOString(), // 1 minute ago
155
+ ownerRepo: 'owner/my-repo',
156
+ }),
157
+ ],
158
+ remoteUrl: 'https://github.com/owner/my-repo.git',
159
+ onExec: (cmd, argv) => {
160
+ if (cmd === 'git' && argv[0] === 'fetch')
161
+ fetchCallCount++;
162
+ },
163
+ });
164
+ const deps = makeDeps({
165
+ execAsync: exec,
166
+ broadcastEvent: (event, data) => broadcastedEvents.push({ event, data }),
167
+ });
168
+ startPolling(deps);
169
+ await waitForCycles(INTERVAL);
170
+ // The notification predates the first-run "now" baseline, so no checkout should occur
171
+ assert.equal(fetchCallCount, 0, 'git fetch should not be called for historical notifications');
172
+ assert.equal(broadcastedEvents.length, 0, 'No review-checkout events should be broadcast');
173
+ });
174
+ test('JSON parse safety — non-JSON lines in gh output do not crash', async () => {
175
+ const INTERVAL = 50;
176
+ saveConfig(configPath, {
177
+ ...DEFAULTS,
178
+ automations: {
179
+ autoCheckoutReviewRequests: true,
180
+ pollIntervalMs: INTERVAL,
181
+ lastPollTimestamp: new Date(Date.now() - 120_000).toISOString(), // 2 min ago
182
+ },
183
+ });
184
+ // Mix valid JSON with non-JSON warning lines that gh sometimes emits
185
+ const validNotification = makeNotificationLine({
186
+ updatedAt: new Date().toISOString(),
187
+ ownerRepo: 'owner/my-repo',
188
+ prNumber: 7,
189
+ });
190
+ const exec = makeMockExec({
191
+ notificationLines: [
192
+ 'Warning: some gh warning message',
193
+ validNotification,
194
+ 'another non-JSON line',
195
+ ],
196
+ remoteUrl: 'https://github.com/owner/my-repo.git',
197
+ });
198
+ // Just verify it doesn't throw — if parsing crashes, startPolling's setInterval
199
+ // would log an unhandled rejection. We capture broadcastEvent to confirm the
200
+ // valid notification was still processed.
201
+ const broadcastedEvents = [];
202
+ const deps = makeDeps({
203
+ execAsync: exec,
204
+ broadcastEvent: (event, data) => broadcastedEvents.push({ event, data }),
205
+ });
206
+ // Should not throw
207
+ startPolling(deps);
208
+ await waitForCycles(INTERVAL);
209
+ // The valid notification was newer than lastPollTimestamp — should be processed
210
+ const checkoutEvents = broadcastedEvents.filter((e) => e.event === 'review-checkout');
211
+ assert.equal(checkoutEvents.length, 1, 'Valid notification should still be processed despite surrounding non-JSON lines');
212
+ });
213
+ test('poll skips processing when autoCheckoutReviewRequests is disabled', async () => {
214
+ const INTERVAL = 50;
215
+ saveConfig(configPath, {
216
+ ...DEFAULTS,
217
+ automations: {
218
+ autoCheckoutReviewRequests: false,
219
+ pollIntervalMs: INTERVAL,
220
+ lastPollTimestamp: new Date(Date.now() - 120_000).toISOString(),
221
+ },
222
+ });
223
+ let ghCallCount = 0;
224
+ const exec = makeMockExec({
225
+ notificationLines: [makeNotificationLine({ updatedAt: new Date().toISOString() })],
226
+ onExec: (cmd, argv) => {
227
+ if (cmd === 'gh' && argv[0] === 'api')
228
+ ghCallCount++;
229
+ },
230
+ });
231
+ startPolling(makeDeps({ execAsync: exec }));
232
+ await waitForCycles(INTERVAL);
233
+ // pollOnce returns early when the flag is off — gh should not even be called
234
+ assert.equal(ghCallCount, 0, 'gh should not be called when autoCheckoutReviewRequests is false');
235
+ });
@@ -0,0 +1,43 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import * as service from '../server/service.js';
4
+ test('getPlatform returns macos or linux', () => {
5
+ const platform = service.getPlatform();
6
+ assert.ok(platform === 'macos' || platform === 'linux', 'Expected macos or linux, got ' + platform);
7
+ });
8
+ test('getServicePaths returns expected keys', () => {
9
+ const paths = service.getServicePaths();
10
+ assert.ok(paths.servicePath, 'missing servicePath');
11
+ assert.equal(typeof paths.label, 'string', 'label should be a string');
12
+ assert.ok('logDir' in paths, 'missing logDir key');
13
+ });
14
+ test('generateServiceFile for macos contains plist XML', () => {
15
+ const content = service.generateServiceFile('macos', {
16
+ nodePath: '/usr/local/bin/node',
17
+ scriptPath: '/usr/local/lib/node_modules/claude-remote-cli/bin/claude-remote-cli.js',
18
+ configPath: '/Users/test/.config/claude-remote-cli/config.json',
19
+ port: '3456',
20
+ host: '0.0.0.0',
21
+ logDir: '/Users/test/.config/claude-remote-cli/logs',
22
+ });
23
+ assert.match(content, /<!DOCTYPE plist/, 'should be plist XML');
24
+ assert.match(content, /com\.claude-remote-cli/, 'should have label');
25
+ assert.match(content, /RunAtLoad/, 'should have RunAtLoad');
26
+ assert.match(content, /KeepAlive/, 'should have KeepAlive');
27
+ assert.match(content, /3456/, 'should include port');
28
+ });
29
+ test('generateServiceFile for linux contains systemd unit', () => {
30
+ const content = service.generateServiceFile('linux', {
31
+ nodePath: '/usr/bin/node',
32
+ scriptPath: '/usr/lib/node_modules/claude-remote-cli/bin/claude-remote-cli.js',
33
+ configPath: '/home/test/.config/claude-remote-cli/config.json',
34
+ port: '3456',
35
+ host: '0.0.0.0',
36
+ logDir: null,
37
+ });
38
+ assert.match(content, /\[Unit\]/, 'should have Unit section');
39
+ assert.match(content, /\[Service\]/, 'should have Service section');
40
+ assert.match(content, /\[Install\]/, 'should have Install section');
41
+ assert.match(content, /Restart=on-failure/, 'should restart on failure');
42
+ assert.match(content, /3456/, 'should include port');
43
+ });