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.
- package/README.md +259 -0
- package/dist/bin/claude-remote-cli.js +390 -0
- package/dist/bin/relay-ide.js +390 -0
- package/dist/frontend/assets/abap-BdImnpbu.js +1 -0
- package/dist/frontend/assets/actionscript-3-CoDkCxhg.js +1 -0
- package/dist/frontend/assets/ada-bCR0ucgS.js +1 -0
- package/dist/frontend/assets/andromeeda-C4gqWexZ.js +1 -0
- package/dist/frontend/assets/angular-html-DA-rfuFy.js +1 -0
- package/dist/frontend/assets/angular-ts-BrjP3tb8.js +1 -0
- package/dist/frontend/assets/apache-Pmp26Uib.js +1 -0
- package/dist/frontend/assets/apex-D8_7TLub.js +1 -0
- package/dist/frontend/assets/apl-CORt7UWP.js +1 -0
- package/dist/frontend/assets/applescript-Co6uUVPk.js +1 -0
- package/dist/frontend/assets/ara-BRHolxvo.js +1 -0
- package/dist/frontend/assets/asciidoc-Ve4PFQV2.js +1 -0
- package/dist/frontend/assets/asm-D_Q5rh1f.js +1 -0
- package/dist/frontend/assets/astro-HNnZUWAn.js +1 -0
- package/dist/frontend/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/dist/frontend/assets/awk-DMzUqQB5.js +1 -0
- package/dist/frontend/assets/ayu-dark-DYE7WIF3.js +1 -0
- package/dist/frontend/assets/ayu-light-BA47KaF1.js +1 -0
- package/dist/frontend/assets/ayu-mirage-32ctXXKs.js +1 -0
- package/dist/frontend/assets/ballerina-BFfxhgS-.js +1 -0
- package/dist/frontend/assets/bat-BkioyH1T.js +1 -0
- package/dist/frontend/assets/beancount-k_qm7-4y.js +1 -0
- package/dist/frontend/assets/berry-uYugtg8r.js +1 -0
- package/dist/frontend/assets/bibtex-CHM0blh-.js +1 -0
- package/dist/frontend/assets/bicep-Bmn6On1c.js +1 -0
- package/dist/frontend/assets/bird2-BIv1doCn.js +1 -0
- package/dist/frontend/assets/blade-BjGOyj-B.js +1 -0
- package/dist/frontend/assets/bsl-BO_Y6i37.js +1 -0
- package/dist/frontend/assets/c-BIGW1oBm.js +1 -0
- package/dist/frontend/assets/c3-eo99z4R2.js +1 -0
- package/dist/frontend/assets/cadence-Bv_4Rxtq.js +1 -0
- package/dist/frontend/assets/cairo-KRGpt6FW.js +1 -0
- package/dist/frontend/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- package/dist/frontend/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- package/dist/frontend/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- package/dist/frontend/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- package/dist/frontend/assets/clarity-D53aC0YG.js +1 -0
- package/dist/frontend/assets/clojure-P80f7IUj.js +1 -0
- package/dist/frontend/assets/cmake-D1j8_8rp.js +1 -0
- package/dist/frontend/assets/cobol-nBiQ_Alo.js +1 -0
- package/dist/frontend/assets/codeowners-Bp6g37R7.js +1 -0
- package/dist/frontend/assets/codeql-DsOJ9woJ.js +1 -0
- package/dist/frontend/assets/coffee-Ch7k5sss.js +1 -0
- package/dist/frontend/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/dist/frontend/assets/coq-DkFqJrB1.js +1 -0
- package/dist/frontend/assets/cpp-CofmeUqb.js +1 -0
- package/dist/frontend/assets/crystal-DNxU26gB.js +1 -0
- package/dist/frontend/assets/csharp-COcwbKMJ.js +1 -0
- package/dist/frontend/assets/css-CLj8gQPS.js +1 -0
- package/dist/frontend/assets/csv-fuZLfV_i.js +1 -0
- package/dist/frontend/assets/cue-D82EKSYY.js +1 -0
- package/dist/frontend/assets/cypher-COkxafJQ.js +1 -0
- package/dist/frontend/assets/d-85-TOEBH.js +1 -0
- package/dist/frontend/assets/dark-plus-C3mMm8J8.js +1 -0
- package/dist/frontend/assets/dart-bE4Kk8sk.js +1 -0
- package/dist/frontend/assets/dax-CEL-wOlO.js +1 -0
- package/dist/frontend/assets/desktop-BmXAJ9_W.js +1 -0
- package/dist/frontend/assets/diff-D97Zzqfu.js +1 -0
- package/dist/frontend/assets/docker-BcOcwvcX.js +1 -0
- package/dist/frontend/assets/dotenv-Da5cRb03.js +1 -0
- package/dist/frontend/assets/dracula-BzJJZx-M.js +1 -0
- package/dist/frontend/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/dist/frontend/assets/dream-maker-BtqSS_iP.js +1 -0
- package/dist/frontend/assets/edge-FbVlp4U3.js +1 -0
- package/dist/frontend/assets/elixir-CkH2-t6x.js +1 -0
- package/dist/frontend/assets/elm-DbKCFpqz.js +1 -0
- package/dist/frontend/assets/emacs-lisp-CXvaQtF9.js +1 -0
- package/dist/frontend/assets/erb-BYCe7drp.js +1 -0
- package/dist/frontend/assets/erlang-DsQrWhSR.js +1 -0
- package/dist/frontend/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/dist/frontend/assets/everforest-light-C8M2exoo.js +1 -0
- package/dist/frontend/assets/fennel-BYunw83y.js +1 -0
- package/dist/frontend/assets/fish-BvzEVeQv.js +1 -0
- package/dist/frontend/assets/fluent-C4IJs8-o.js +1 -0
- package/dist/frontend/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- package/dist/frontend/assets/fortran-free-form-BxgE0vQu.js +1 -0
- package/dist/frontend/assets/fsharp-CXgrBDvD.js +1 -0
- package/dist/frontend/assets/gdresource-BOOCDP_w.js +1 -0
- package/dist/frontend/assets/gdscript-C5YyOfLZ.js +1 -0
- package/dist/frontend/assets/gdshader-DkwncUOv.js +1 -0
- package/dist/frontend/assets/genie-D0YGMca9.js +1 -0
- package/dist/frontend/assets/gherkin-DyxjwDmM.js +1 -0
- package/dist/frontend/assets/git-commit-F4YmCXRG.js +1 -0
- package/dist/frontend/assets/git-rebase-r7XF79zn.js +1 -0
- package/dist/frontend/assets/github-dark-DHJKELXO.js +1 -0
- package/dist/frontend/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/dist/frontend/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/dist/frontend/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/dist/frontend/assets/github-light-DAi9KRSo.js +1 -0
- package/dist/frontend/assets/github-light-default-D7oLnXFd.js +1 -0
- package/dist/frontend/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/dist/frontend/assets/gleam-BspZqrRM.js +1 -0
- package/dist/frontend/assets/glimmer-js-ByusRIyA.js +1 -0
- package/dist/frontend/assets/glimmer-ts-BfAWNZQY.js +1 -0
- package/dist/frontend/assets/glsl-DplSGwfg.js +1 -0
- package/dist/frontend/assets/gn-n2N0HUVH.js +1 -0
- package/dist/frontend/assets/gnuplot-DdkO51Og.js +1 -0
- package/dist/frontend/assets/go-C27-OAKa.js +1 -0
- package/dist/frontend/assets/graphql-ChdNCCLP.js +1 -0
- package/dist/frontend/assets/groovy-gcz8RCvz.js +1 -0
- package/dist/frontend/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/dist/frontend/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/dist/frontend/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/dist/frontend/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/dist/frontend/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/dist/frontend/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/dist/frontend/assets/hack-i7_Ulhet.js +1 -0
- package/dist/frontend/assets/haml-D5jkg6IW.js +1 -0
- package/dist/frontend/assets/handlebars-BpdQsYii.js +1 -0
- package/dist/frontend/assets/haskell-Df6bDoY_.js +1 -0
- package/dist/frontend/assets/haxe-CzTSHFRz.js +1 -0
- package/dist/frontend/assets/hcl-BWvSN4gD.js +1 -0
- package/dist/frontend/assets/hjson-D5-asLiD.js +1 -0
- package/dist/frontend/assets/hlsl-D3lLCCz7.js +1 -0
- package/dist/frontend/assets/horizon-BUw7H-hv.js +1 -0
- package/dist/frontend/assets/horizon-bright-CUuTKBJd.js +1 -0
- package/dist/frontend/assets/houston-DnULxvSX.js +1 -0
- package/dist/frontend/assets/html-derivative-DlHx6ybY.js +1 -0
- package/dist/frontend/assets/html-pp8916En.js +1 -0
- package/dist/frontend/assets/http-jrhK8wxY.js +1 -0
- package/dist/frontend/assets/hurl-irOxFIW8.js +1 -0
- package/dist/frontend/assets/hxml-Bvhsp5Yf.js +1 -0
- package/dist/frontend/assets/hy-DFXneXwc.js +1 -0
- package/dist/frontend/assets/imba-DGztddWO.js +1 -0
- package/dist/frontend/assets/ini-BEwlwnbL.js +1 -0
- package/dist/frontend/assets/java-CylS5w8V.js +1 -0
- package/dist/frontend/assets/javascript-wDzz0qaB.js +1 -0
- package/dist/frontend/assets/jinja-f2NsQr07.js +1 -0
- package/dist/frontend/assets/jison-wvAkD_A8.js +1 -0
- package/dist/frontend/assets/json-Cp-IABpG.js +1 -0
- package/dist/frontend/assets/json5-C9tS-k6U.js +1 -0
- package/dist/frontend/assets/jsonc-Des-eS-w.js +1 -0
- package/dist/frontend/assets/jsonl-DcaNXYhu.js +1 -0
- package/dist/frontend/assets/jsonnet-DFQXde-d.js +1 -0
- package/dist/frontend/assets/jssm-C2t-YnRu.js +1 -0
- package/dist/frontend/assets/jsx-g9-lgVsj.js +1 -0
- package/dist/frontend/assets/julia-CxzCAyBv.js +1 -0
- package/dist/frontend/assets/just-VxiPbLrw.js +1 -0
- package/dist/frontend/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/dist/frontend/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/dist/frontend/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/dist/frontend/assets/kdl-DV7GczEv.js +1 -0
- package/dist/frontend/assets/kotlin-BdnUsdx6.js +1 -0
- package/dist/frontend/assets/kusto-wEQ09or8.js +1 -0
- package/dist/frontend/assets/laserwave-DUszq2jm.js +1 -0
- package/dist/frontend/assets/latex-CWtU0Tv5.js +1 -0
- package/dist/frontend/assets/lean-BZvkOJ9d.js +1 -0
- package/dist/frontend/assets/less-B1dDrJ26.js +1 -0
- package/dist/frontend/assets/light-plus-B7mTdjB0.js +1 -0
- package/dist/frontend/assets/liquid-C0sCDyMI.js +1 -0
- package/dist/frontend/assets/llvm-DjAJT7YJ.js +1 -0
- package/dist/frontend/assets/log-2UxHyX5q.js +1 -0
- package/dist/frontend/assets/logo-BtOb2qkB.js +1 -0
- package/dist/frontend/assets/lua-BaeVxFsk.js +1 -0
- package/dist/frontend/assets/luau-C-HG3fhB.js +1 -0
- package/dist/frontend/assets/main-CL5_Wlhv.css +32 -0
- package/dist/frontend/assets/main-Czet4Z1x.js +371 -0
- package/dist/frontend/assets/make-CHLpvVh8.js +1 -0
- package/dist/frontend/assets/markdown-Cvjx9yec.js +1 -0
- package/dist/frontend/assets/marko-DjSrsDqO.js +1 -0
- package/dist/frontend/assets/material-theme-D5KoaKCx.js +1 -0
- package/dist/frontend/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/dist/frontend/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/dist/frontend/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/dist/frontend/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/dist/frontend/assets/matlab-D7o27uSR.js +1 -0
- package/dist/frontend/assets/mdc-DTYItulj.js +1 -0
- package/dist/frontend/assets/mdx-Cmh6b_Ma.js +1 -0
- package/dist/frontend/assets/mermaid-mWjccvbQ.js +1 -0
- package/dist/frontend/assets/min-dark-CafNBF8u.js +1 -0
- package/dist/frontend/assets/min-light-CTRr51gU.js +1 -0
- package/dist/frontend/assets/mipsasm-CKIfxQSi.js +1 -0
- package/dist/frontend/assets/mojo-rZm6bMo-.js +1 -0
- package/dist/frontend/assets/monokai-D4h5O-jR.js +1 -0
- package/dist/frontend/assets/moonbit-_H4v1dQx.js +1 -0
- package/dist/frontend/assets/move-IF9eRakj.js +1 -0
- package/dist/frontend/assets/narrat-DRg8JJMk.js +1 -0
- package/dist/frontend/assets/nextflow-C-mBbutL.js +1 -0
- package/dist/frontend/assets/nextflow-groovy-vE_lwT2v.js +1 -0
- package/dist/frontend/assets/nginx-BpAMiNFr.js +1 -0
- package/dist/frontend/assets/night-owl-C39BiMTA.js +1 -0
- package/dist/frontend/assets/night-owl-light-CMTm3GFP.js +1 -0
- package/dist/frontend/assets/nim-BIad80T-.js +1 -0
- package/dist/frontend/assets/nix-CwoSXNpI.js +1 -0
- package/dist/frontend/assets/nord-Ddv68eIx.js +1 -0
- package/dist/frontend/assets/nushell-Cz2AlsmD.js +1 -0
- package/dist/frontend/assets/objective-c-DXmwc3jG.js +1 -0
- package/dist/frontend/assets/objective-cpp-CLxacb5B.js +1 -0
- package/dist/frontend/assets/ocaml-C0hk2d4L.js +1 -0
- package/dist/frontend/assets/odin-BBf5iR-q.js +1 -0
- package/dist/frontend/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/dist/frontend/assets/one-light-C3Wv6jpd.js +1 -0
- package/dist/frontend/assets/openscad-C4EeE6gA.js +1 -0
- package/dist/frontend/assets/pascal-D93ZcfNL.js +1 -0
- package/dist/frontend/assets/perl-NvoQZIq0.js +1 -0
- package/dist/frontend/assets/php-R6g_5hLQ.js +1 -0
- package/dist/frontend/assets/pkl-u5AG7uiY.js +1 -0
- package/dist/frontend/assets/plastic-3e1v2bzS.js +1 -0
- package/dist/frontend/assets/plsql-ChMvpjG-.js +1 -0
- package/dist/frontend/assets/po-BTJTHyun.js +1 -0
- package/dist/frontend/assets/poimandres-CS3Unz2-.js +1 -0
- package/dist/frontend/assets/polar-C0HS_06l.js +1 -0
- package/dist/frontend/assets/postcss-CXtECtnM.js +1 -0
- package/dist/frontend/assets/powerquery-CEu0bR-o.js +1 -0
- package/dist/frontend/assets/powershell-Dpen1YoG.js +1 -0
- package/dist/frontend/assets/prisma-Dd19v3D-.js +1 -0
- package/dist/frontend/assets/prolog-CbFg5uaA.js +1 -0
- package/dist/frontend/assets/proto-C7zT0LnQ.js +1 -0
- package/dist/frontend/assets/pug-DKIMFp6K.js +1 -0
- package/dist/frontend/assets/puppet-BMWR74SV.js +1 -0
- package/dist/frontend/assets/purescript-CklMAg4u.js +1 -0
- package/dist/frontend/assets/python-B6aJPvgy.js +1 -0
- package/dist/frontend/assets/qml-3beO22l8.js +1 -0
- package/dist/frontend/assets/qmldir-C8lEn-DE.js +1 -0
- package/dist/frontend/assets/qss-IeuSbFQv.js +1 -0
- package/dist/frontend/assets/r-Dspwwk_N.js +1 -0
- package/dist/frontend/assets/racket-BqYA7rlc.js +1 -0
- package/dist/frontend/assets/raku-DXvB9xmW.js +1 -0
- package/dist/frontend/assets/razor-BDqjjVU7.js +1 -0
- package/dist/frontend/assets/red-bN70gL4F.js +1 -0
- package/dist/frontend/assets/reg-C-SQnVFl.js +1 -0
- package/dist/frontend/assets/regexp-CDVJQ6XC.js +1 -0
- package/dist/frontend/assets/rel-C3B-1QV4.js +1 -0
- package/dist/frontend/assets/riscv-BM1_JUlF.js +1 -0
- package/dist/frontend/assets/ron-D8l8udqQ.js +1 -0
- package/dist/frontend/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- package/dist/frontend/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- package/dist/frontend/assets/rose-pine-qdsjHGoJ.js +1 -0
- package/dist/frontend/assets/rosmsg-BJDFO7_C.js +1 -0
- package/dist/frontend/assets/rst-CRjBmOyv.js +1 -0
- package/dist/frontend/assets/ruby-Wjq7vjNf.js +1 -0
- package/dist/frontend/assets/rust-B1yitclQ.js +1 -0
- package/dist/frontend/assets/sas-cz2c8ADy.js +1 -0
- package/dist/frontend/assets/sass-Cj5Yp3dK.js +1 -0
- package/dist/frontend/assets/scala-C151Ov-r.js +1 -0
- package/dist/frontend/assets/scheme-C98Dy4si.js +1 -0
- package/dist/frontend/assets/scss-D5BDwBP9.js +1 -0
- package/dist/frontend/assets/sdbl-DVxCFoDh.js +1 -0
- package/dist/frontend/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/dist/frontend/assets/shellscript-Yzrsuije.js +1 -0
- package/dist/frontend/assets/shellsession-BADoaaVG.js +1 -0
- package/dist/frontend/assets/slack-dark-BthQWCQV.js +1 -0
- package/dist/frontend/assets/slack-ochin-DqwNpetd.js +1 -0
- package/dist/frontend/assets/smalltalk-BERRCDM3.js +1 -0
- package/dist/frontend/assets/snazzy-light-Bw305WKR.js +1 -0
- package/dist/frontend/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/dist/frontend/assets/solarized-light-L9t79GZl.js +1 -0
- package/dist/frontend/assets/solidity-rGO070M0.js +1 -0
- package/dist/frontend/assets/soy-8wufbnw4.js +1 -0
- package/dist/frontend/assets/sparql-rVzFXLq3.js +1 -0
- package/dist/frontend/assets/splunk-BtCnVYZw.js +1 -0
- package/dist/frontend/assets/sql-BLtJtn59.js +1 -0
- package/dist/frontend/assets/ssh-config-_ykCGR6B.js +1 -0
- package/dist/frontend/assets/stata-BH5u7GGu.js +1 -0
- package/dist/frontend/assets/stylus-BEDo0Tqx.js +1 -0
- package/dist/frontend/assets/surrealql-Bq5Q-fJD.js +1 -0
- package/dist/frontend/assets/svelte-Cy7k_4gC.js +1 -0
- package/dist/frontend/assets/swift-D82vCrfD.js +1 -0
- package/dist/frontend/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/dist/frontend/assets/system-verilog-CnnmHF94.js +1 -0
- package/dist/frontend/assets/systemd-4A_iFExJ.js +1 -0
- package/dist/frontend/assets/talonscript-CkByrt1z.js +1 -0
- package/dist/frontend/assets/tasl-QIJgUcNo.js +1 -0
- package/dist/frontend/assets/tcl-dwOrl1Do.js +1 -0
- package/dist/frontend/assets/templ-DhtptRzy.js +1 -0
- package/dist/frontend/assets/terraform-BETggiCN.js +1 -0
- package/dist/frontend/assets/tex-idrVyKtj.js +1 -0
- package/dist/frontend/assets/tokyo-night-hegEt444.js +1 -0
- package/dist/frontend/assets/toml-vGWfd6FD.js +1 -0
- package/dist/frontend/assets/ts-tags-DQrlYJgV.js +1 -0
- package/dist/frontend/assets/tsv-B_m7g4N7.js +1 -0
- package/dist/frontend/assets/tsx-COt5Ahok.js +1 -0
- package/dist/frontend/assets/turtle-BsS91CYL.js +1 -0
- package/dist/frontend/assets/twig-xg9kU7Mw.js +1 -0
- package/dist/frontend/assets/typescript-BPQ3VLAy.js +1 -0
- package/dist/frontend/assets/typespec-CAFt9gP4.js +1 -0
- package/dist/frontend/assets/typst-DHCkPAjA.js +1 -0
- package/dist/frontend/assets/v-BcVCzyr7.js +1 -0
- package/dist/frontend/assets/vala-CsfeWuGM.js +1 -0
- package/dist/frontend/assets/vb-D17OF-Vu.js +1 -0
- package/dist/frontend/assets/verilog-BQ8w6xss.js +1 -0
- package/dist/frontend/assets/vesper-DU1UobuO.js +1 -0
- package/dist/frontend/assets/vhdl-CeAyd5Ju.js +1 -0
- package/dist/frontend/assets/viml-CJc9bBzg.js +1 -0
- package/dist/frontend/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/dist/frontend/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/dist/frontend/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/dist/frontend/assets/vue-D2xRrEX4.js +1 -0
- package/dist/frontend/assets/vue-html-AaS7Mt5G.js +1 -0
- package/dist/frontend/assets/vue-vine-BoDAl6tE.js +1 -0
- package/dist/frontend/assets/vyper-CDx5xZoG.js +1 -0
- package/dist/frontend/assets/wasm-CG6Dc4jp.js +1 -0
- package/dist/frontend/assets/wasm-MzD3tlZU.js +1 -0
- package/dist/frontend/assets/wenyan-BV7otONQ.js +1 -0
- package/dist/frontend/assets/wgsl-Dx-B1_4e.js +1 -0
- package/dist/frontend/assets/wikitext-BhOHFoWU.js +1 -0
- package/dist/frontend/assets/wit-5i3qLPDT.js +1 -0
- package/dist/frontend/assets/wolfram-lXgVvXCa.js +1 -0
- package/dist/frontend/assets/xml-sdJ4AIDG.js +1 -0
- package/dist/frontend/assets/xsl-CtQFsRM5.js +1 -0
- package/dist/frontend/assets/yaml-Buea-lGh.js +1 -0
- package/dist/frontend/assets/zenscript-DVFEvuxE.js +1 -0
- package/dist/frontend/assets/zig-VOosw3JB.js +1 -0
- package/dist/frontend/icon-192.png +0 -0
- package/dist/frontend/icon-512.png +0 -0
- package/dist/frontend/icon.svg +8 -0
- package/dist/frontend/index.html +30 -0
- package/dist/frontend/manifest.json +25 -0
- package/dist/frontend/sw.js +66 -0
- package/dist/server/agent-events.js +39 -0
- package/dist/server/analytics.js +885 -0
- package/dist/server/auth.js +65 -0
- package/dist/server/belayer/executor.js +200 -0
- package/dist/server/belayer/intake.js +27 -0
- package/dist/server/belayer/pipeline.js +97 -0
- package/dist/server/belayer/pr-lifecycle.js +69 -0
- package/dist/server/belayer/prompts.js +154 -0
- package/dist/server/belayer/types.js +23 -0
- package/dist/server/branch-linker.js +137 -0
- package/dist/server/browser-content.js +145 -0
- package/dist/server/clipboard.js +63 -0
- package/dist/server/codex-hooks-adapter.js +93 -0
- package/dist/server/config.js +325 -0
- package/dist/server/gh-routes.js +163 -0
- package/dist/server/gh.js +276 -0
- package/dist/server/git-routes.js +154 -0
- package/dist/server/git.js +694 -0
- package/dist/server/github-app.js +218 -0
- package/dist/server/github-graphql.js +178 -0
- package/dist/server/hooks.js +373 -0
- package/dist/server/index.js +1549 -0
- package/dist/server/integration-github.js +137 -0
- package/dist/server/integration-jira.js +210 -0
- package/dist/server/integration-linear.js +176 -0
- package/dist/server/logger.js +18 -0
- package/dist/server/mobile-input-pipeline.js +129 -0
- package/dist/server/opencode-relay.js +53 -0
- package/dist/server/org-dashboard.js +241 -0
- package/dist/server/output-parsers/claude-parser.js +56 -0
- package/dist/server/output-parsers/codex-parser.js +13 -0
- package/dist/server/output-parsers/index.js +14 -0
- package/dist/server/output-parsers/null-parser.js +12 -0
- package/dist/server/output-parsers/opencode-parser.js +77 -0
- package/dist/server/pty-handler.js +586 -0
- package/dist/server/push.js +84 -0
- package/dist/server/review-poller.js +237 -0
- package/dist/server/sdk-handler.js +539 -0
- package/dist/server/service.js +189 -0
- package/dist/server/sessions.js +638 -0
- package/dist/server/telemetry.js +236 -0
- package/dist/server/ticket-transitions.js +166 -0
- package/dist/server/types.js +146 -0
- package/dist/server/utils.js +23 -0
- package/dist/server/watcher.js +661 -0
- package/dist/server/webhook-manager.js +547 -0
- package/dist/server/webhooks.js +73 -0
- package/dist/server/workspace-groups.js +363 -0
- package/dist/server/workspaces.js +1207 -0
- package/dist/server/ws.js +192 -0
- package/dist/test/EmptyState.spec.js +51 -0
- package/dist/test/action-coverage.test.js +139 -0
- package/dist/test/actions/registry.test.js +59 -0
- package/dist/test/actions/shortcuts.test.js +79 -0
- package/dist/test/agent-events.test.js +151 -0
- package/dist/test/analytics.test.js +158 -0
- package/dist/test/attention.test.js +91 -0
- package/dist/test/auth.test.js +105 -0
- package/dist/test/backend-state.test.js +47 -0
- package/dist/test/belayer-executor.test.js +33 -0
- package/dist/test/belayer-intake.test.js +44 -0
- package/dist/test/belayer-pipeline.test.js +113 -0
- package/dist/test/belayer-pr-lifecycle.test.js +26 -0
- package/dist/test/belayer-prompts.test.js +60 -0
- package/dist/test/belayer-types.test.js +69 -0
- package/dist/test/bin/claude-remote-cli.js +214 -0
- package/dist/test/boot-state.test.js +133 -0
- package/dist/test/branch-lifecycle.test.js +75 -0
- package/dist/test/branch-linker.test.js +236 -0
- package/dist/test/branch-rename.test.js +45 -0
- package/dist/test/branch-watcher.test.js +115 -0
- package/dist/test/browser-cli.test.js +91 -0
- package/dist/test/browser-content.test.js +93 -0
- package/dist/test/browser-tabs-ui.test.js +39 -0
- package/dist/test/changed-files-api.test.js +140 -0
- package/dist/test/clipboard.test.js +12 -0
- package/dist/test/codex-hooks-adapter.test.js +237 -0
- package/dist/test/components/EmptyState.spec.js +51 -0
- package/dist/test/components/ErrorToast.spec.js +65 -0
- package/dist/test/components/TuiCheckbox.spec.js +120 -0
- package/dist/test/components/TuiInput.spec.js +186 -0
- package/dist/test/components/leaf-component-migration.spec.js +104 -0
- package/dist/test/config-freshness.test.js +63 -0
- package/dist/test/config.test.js +813 -0
- package/dist/test/diff-summary.test.js +98 -0
- package/dist/test/display-state.test.js +179 -0
- package/dist/test/event-message-types.test.js +32 -0
- package/dist/test/file-tree-utils.test.js +167 -0
- package/dist/test/framework-types.test.js +183 -0
- package/dist/test/frameworks-api.test.js +93 -0
- package/dist/test/frontend/src/lib/pr-state.js +114 -0
- package/dist/test/fs-browse.test.js +246 -0
- package/dist/test/fuzzy-scorer.test.js +145 -0
- package/dist/test/gh-routes.test.js +156 -0
- package/dist/test/git-changed-files.test.js +152 -0
- package/dist/test/git-routes.test.js +146 -0
- package/dist/test/git-utils.test.js +68 -0
- package/dist/test/git-watcher.test.js +110 -0
- package/dist/test/git.test.js +140 -0
- package/dist/test/github-app.test.js +455 -0
- package/dist/test/github-graphql.test.js +301 -0
- package/dist/test/greetings.test.js +83 -0
- package/dist/test/hooks-agent-event.test.js +412 -0
- package/dist/test/hooks.test.js +149 -0
- package/dist/test/integration-github.test.js +220 -0
- package/dist/test/integration-jira.test.js +238 -0
- package/dist/test/integration-linear.test.js +293 -0
- package/dist/test/mobile-input.test.js +235 -0
- package/dist/test/opencode-relay.test.js +107 -0
- package/dist/test/org-dashboard.test.js +349 -0
- package/dist/test/output-parser.test.js +217 -0
- package/dist/test/paths.test.js +32 -0
- package/dist/test/pr-state.test.js +407 -0
- package/dist/test/pr-status.test.js +82 -0
- package/dist/test/presets.test.js +242 -0
- package/dist/test/pty-handler-multi-agent.test.js +149 -0
- package/dist/test/pty-handler.test.js +146 -0
- package/dist/test/pull-requests.test.js +78 -0
- package/dist/test/review-poller.test.js +349 -0
- package/dist/test/server/analytics.js +121 -0
- package/dist/test/server/auth.js +63 -0
- package/dist/test/server/branch-linker.js +124 -0
- package/dist/test/server/clipboard.js +56 -0
- package/dist/test/server/config.js +137 -0
- package/dist/test/server/git.js +308 -0
- package/dist/test/server/hooks.js +196 -0
- package/dist/test/server/index.js +1124 -0
- package/dist/test/server/integration-github.js +117 -0
- package/dist/test/server/integration-jira.js +164 -0
- package/dist/test/server/integration-linear.js +176 -0
- package/dist/test/server/mobile-input-pipeline.js +123 -0
- package/dist/test/server/org-dashboard.js +184 -0
- package/dist/test/server/output-parsers/claude-parser.js +54 -0
- package/dist/test/server/output-parsers/codex-parser.js +13 -0
- package/dist/test/server/output-parsers/index.js +7 -0
- package/dist/test/server/pty-handler.js +310 -0
- package/dist/test/server/push.js +80 -0
- package/dist/test/server/review-poller.js +218 -0
- package/dist/test/server/service.js +169 -0
- package/dist/test/server/sessions.js +434 -0
- package/dist/test/server/ticket-transitions.js +216 -0
- package/dist/test/server/types.js +20 -0
- package/dist/test/server/utils.js +22 -0
- package/dist/test/server/watcher.js +139 -0
- package/dist/test/server/workspaces.js +657 -0
- package/dist/test/server/ws.js +152 -0
- package/dist/test/server-startup.test.js +62 -0
- package/dist/test/service.test.js +43 -0
- package/dist/test/session-analytics-api.test.js +123 -0
- package/dist/test/session-analytics.test.js +425 -0
- package/dist/test/session-intent.test.js +249 -0
- package/dist/test/sessions.test.js +1152 -0
- package/dist/test/sidebar-items.test.js +164 -0
- package/dist/test/stores/boot-state-store.test.js +165 -0
- package/dist/test/stores/sessions-logic.test.js +191 -0
- package/dist/test/stores/toasts-store.test.js +66 -0
- package/dist/test/stores/ui-store.test.js +203 -0
- package/dist/test/stores/unread-store.test.js +97 -0
- package/dist/test/telemetry-api.test.js +54 -0
- package/dist/test/telemetry-sync.test.js +68 -0
- package/dist/test/telemetry.test.js +295 -0
- package/dist/test/terminal-zoom.test.js +102 -0
- package/dist/test/test/analytics.test.js +152 -0
- package/dist/test/test/auth.test.js +95 -0
- package/dist/test/test/branch-linker.test.js +231 -0
- package/dist/test/test/branch-rename.test.js +45 -0
- package/dist/test/test/clipboard.test.js +12 -0
- package/dist/test/test/config.test.js +281 -0
- package/dist/test/test/fs-browse.test.js +202 -0
- package/dist/test/test/git.test.js +67 -0
- package/dist/test/test/hooks.test.js +139 -0
- package/dist/test/test/integration-github.test.js +203 -0
- package/dist/test/test/integration-jira.test.js +294 -0
- package/dist/test/test/integration-linear.test.js +293 -0
- package/dist/test/test/mobile-input.test.js +193 -0
- package/dist/test/test/org-dashboard.test.js +240 -0
- package/dist/test/test/output-parser.test.js +95 -0
- package/dist/test/test/paths.test.js +32 -0
- package/dist/test/test/pr-state.test.js +220 -0
- package/dist/test/test/pull-requests.test.js +67 -0
- package/dist/test/test/review-poller.test.js +235 -0
- package/dist/test/test/service.test.js +43 -0
- package/dist/test/test/sessions.test.js +750 -0
- package/dist/test/test/ticket-transitions.test.js +130 -0
- package/dist/test/test/version.test.js +34 -0
- package/dist/test/test/worktrees.test.js +256 -0
- package/dist/test/ticket-transitions.test.js +312 -0
- package/dist/test/unread.test.js +23 -0
- package/dist/test/version.test.js +34 -0
- package/dist/test/webhook-manager.test.js +484 -0
- package/dist/test/webhooks.test.js +208 -0
- package/dist/test/workspace-groups.test.js +377 -0
- package/dist/test/worktrees.test.js +531 -0
- package/package.json +88 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
/** Source code for the opencode relay plugin — written to opencode's plugin directory */
|
|
5
|
+
const RELAY_PLUGIN_SOURCE = `
|
|
6
|
+
// OpenCode plugin that relays lifecycle events to relay-ide server.
|
|
7
|
+
// Reads CRC_RELAY_URL, CRC_SESSION_ID, CRC_RELAY_TOKEN from env (injected per session by PTY handler).
|
|
8
|
+
export default async () => {
|
|
9
|
+
const relayUrl = process.env.CRC_RELAY_URL;
|
|
10
|
+
const sessionId = process.env.CRC_SESSION_ID;
|
|
11
|
+
const token = process.env.CRC_RELAY_TOKEN;
|
|
12
|
+
|
|
13
|
+
if (!relayUrl || !sessionId || !token) return {};
|
|
14
|
+
|
|
15
|
+
const relay = async (eventType, data = {}) => {
|
|
16
|
+
try {
|
|
17
|
+
await fetch(\`\${relayUrl}/hooks/agent-event\`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: { 'Content-Type': 'application/json' },
|
|
20
|
+
body: JSON.stringify({ sessionId, token, eventType, data, timestamp: new Date().toISOString() }),
|
|
21
|
+
});
|
|
22
|
+
} catch { /* best-effort, don't crash opencode */ }
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
'session.created': async () => relay('session.started'),
|
|
27
|
+
'session.idle': async () => relay('session.idle'),
|
|
28
|
+
'session.status': async (input) => relay('state.changed', { status: input }),
|
|
29
|
+
'session.error': async (input) => relay('state.changed', { status: 'error', error: input }),
|
|
30
|
+
'permission.asked': async (input) => relay('permission.requested', { permission: input }),
|
|
31
|
+
'permission.replied': async (input) => relay('permission.resolved', { reply: input }),
|
|
32
|
+
'tool.execute.before': async (input) => relay('tool.started', { tool: input }),
|
|
33
|
+
'tool.execute.after': async (input, output) => relay('tool.finished', { tool: input, result: output }),
|
|
34
|
+
'message.updated': async (input) => relay('telemetry.updated', { message: input }),
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
`.trim();
|
|
38
|
+
/**
|
|
39
|
+
* Write the relay plugin to opencode's global plugin directory.
|
|
40
|
+
* Idempotent — overwrites the same file each time.
|
|
41
|
+
*
|
|
42
|
+
* @param pluginDir - Override the plugin directory (defaults to ~/.config/opencode/plugins). Used in tests.
|
|
43
|
+
* @returns The path to the written plugin file.
|
|
44
|
+
*/
|
|
45
|
+
export function installOpencodeRelayPlugin(pluginDir) {
|
|
46
|
+
const dir = pluginDir ?? path.join(os.homedir(), '.config', 'opencode', 'plugins');
|
|
47
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
48
|
+
const pluginPath = path.join(dir, 'crc-relay.ts');
|
|
49
|
+
fs.writeFileSync(pluginPath, RELAY_PLUGIN_SOURCE, 'utf-8');
|
|
50
|
+
return pluginPath;
|
|
51
|
+
}
|
|
52
|
+
/** Exported for testing */
|
|
53
|
+
export { RELAY_PLUGIN_SOURCE };
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { Router } from 'express';
|
|
5
|
+
import { loadConfig } from './config.js';
|
|
6
|
+
import { buildRepoMap } from './git.js';
|
|
7
|
+
import { createLogger } from './logger.js';
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
const logger = createLogger('org-dashboard');
|
|
10
|
+
const GH_TIMEOUT_MS = 10_000;
|
|
11
|
+
const CACHE_TTL_MS = 60_000;
|
|
12
|
+
/**
|
|
13
|
+
* Extracts "owner/repo" from a GitHub API repository_url.
|
|
14
|
+
* e.g. "https://api.github.com/repos/owner/repo" → "owner/repo"
|
|
15
|
+
*/
|
|
16
|
+
function repoFromApiUrl(repositoryUrl) {
|
|
17
|
+
const match = repositoryUrl.match(/\/repos\/([^/]+\/[^/]+)$/);
|
|
18
|
+
return match ? (match[1] ?? null) : null;
|
|
19
|
+
}
|
|
20
|
+
// Router factory
|
|
21
|
+
/**
|
|
22
|
+
* Creates and returns an Express Router that handles all /org-dashboard routes.
|
|
23
|
+
*
|
|
24
|
+
* Caller is responsible for mounting and applying auth middleware:
|
|
25
|
+
* app.use('/org-dashboard', requireAuth, createOrgDashboardRouter({ configPath }));
|
|
26
|
+
*/
|
|
27
|
+
export function createOrgDashboardRouter(deps) {
|
|
28
|
+
const { configPath } = deps;
|
|
29
|
+
const exec = deps.execAsync ?? execFileAsync;
|
|
30
|
+
const router = Router();
|
|
31
|
+
// Server-lifetime cache for GitHub user login
|
|
32
|
+
let cachedUser = null;
|
|
33
|
+
// 60s in-memory cache for search results
|
|
34
|
+
let cache = null;
|
|
35
|
+
function getConfig() {
|
|
36
|
+
return loadConfig(configPath);
|
|
37
|
+
}
|
|
38
|
+
// GET /org-dashboard/prs — list all open PRs involving the current user across all workspaces
|
|
39
|
+
router.get('/prs', async (_req, res) => {
|
|
40
|
+
const config = getConfig();
|
|
41
|
+
const workspacePaths = config.repos ?? [];
|
|
42
|
+
if (workspacePaths.length === 0) {
|
|
43
|
+
const response = {
|
|
44
|
+
prs: [],
|
|
45
|
+
error: 'no_workspaces',
|
|
46
|
+
};
|
|
47
|
+
res.json(response);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Return cached results if still fresh
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
if (cache && now - cache.fetchedAt < CACHE_TTL_MS) {
|
|
53
|
+
const response = { prs: cache.prs };
|
|
54
|
+
res.json(response);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Resolve GitHub user (cached for server lifetime)
|
|
58
|
+
if (!cachedUser) {
|
|
59
|
+
try {
|
|
60
|
+
const { stdout } = await exec('gh', ['api', 'user', '--jq', '.login'], {
|
|
61
|
+
timeout: GH_TIMEOUT_MS,
|
|
62
|
+
});
|
|
63
|
+
cachedUser = stdout.trim();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const errCode = err.code;
|
|
67
|
+
if (errCode === 'ENOENT') {
|
|
68
|
+
const response = {
|
|
69
|
+
prs: [],
|
|
70
|
+
error: 'gh_not_in_path',
|
|
71
|
+
};
|
|
72
|
+
res.json(response);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const response = {
|
|
76
|
+
prs: [],
|
|
77
|
+
error: 'gh_not_authenticated',
|
|
78
|
+
};
|
|
79
|
+
res.json(response);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const currentUser = cachedUser;
|
|
84
|
+
// Build repo → workspace path map
|
|
85
|
+
const repoMap = await buildRepoMap(workspacePaths, exec);
|
|
86
|
+
// Check for GraphQL path (GitHub App token)
|
|
87
|
+
const githubToken = config.github?.accessToken;
|
|
88
|
+
if (githubToken && deps.fetchGraphQL) {
|
|
89
|
+
try {
|
|
90
|
+
const result = await deps.fetchGraphQL(githubToken, repoMap);
|
|
91
|
+
cachedUser = result.username;
|
|
92
|
+
const prs = result.prs;
|
|
93
|
+
prs.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
94
|
+
cache = { prs, fetchedAt: now };
|
|
95
|
+
// Fire ticket transitions (same best-effort as below)
|
|
96
|
+
if (deps.checkPrTransitions && deps.getBranchLinks) {
|
|
97
|
+
deps
|
|
98
|
+
.getBranchLinks()
|
|
99
|
+
.then((links) => deps.checkPrTransitions(prs, links))
|
|
100
|
+
.catch(() => { });
|
|
101
|
+
}
|
|
102
|
+
const response = { prs };
|
|
103
|
+
res.json(response);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
logger.warn('[org-dashboard] GraphQL fetch failed, falling back to gh CLI:', err instanceof Error ? err.message : String(err));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Single gh search API call
|
|
111
|
+
let searchResponse;
|
|
112
|
+
try {
|
|
113
|
+
const { stdout } = await exec('gh', ['api', 'search/issues?q=is:pr+is:open+involves:@me&per_page=100'], { timeout: GH_TIMEOUT_MS });
|
|
114
|
+
searchResponse = JSON.parse(stdout);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
118
|
+
const errCode = err.code;
|
|
119
|
+
if (msg.includes('ETIMEDOUT') || msg.includes('timed out')) {
|
|
120
|
+
const response = { prs: [], error: 'gh_timeout' };
|
|
121
|
+
res.json(response);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (errCode === 'ENOENT') {
|
|
125
|
+
const response = {
|
|
126
|
+
prs: [],
|
|
127
|
+
error: 'gh_not_in_path',
|
|
128
|
+
};
|
|
129
|
+
res.json(response);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const response = {
|
|
133
|
+
prs: [],
|
|
134
|
+
error: 'gh_not_authenticated',
|
|
135
|
+
};
|
|
136
|
+
res.json(response);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const items = searchResponse.items ?? [];
|
|
140
|
+
// Filter to only repos matching workspace paths and map to PullRequest
|
|
141
|
+
const prs = [];
|
|
142
|
+
for (const item of items) {
|
|
143
|
+
// The search API can return non-PR issues — skip them
|
|
144
|
+
if (!item.pull_request)
|
|
145
|
+
continue;
|
|
146
|
+
const ownerRepo = repoFromApiUrl(item.repository_url);
|
|
147
|
+
if (!ownerRepo)
|
|
148
|
+
continue;
|
|
149
|
+
const wsPath = repoMap.get(ownerRepo.toLowerCase());
|
|
150
|
+
if (!wsPath)
|
|
151
|
+
continue;
|
|
152
|
+
// Determine role
|
|
153
|
+
const isAuthor = item.user.login === currentUser;
|
|
154
|
+
const isReviewer = !isAuthor &&
|
|
155
|
+
Array.isArray(item.requested_reviewers) &&
|
|
156
|
+
item.requested_reviewers.some((r) => r.login === currentUser);
|
|
157
|
+
if (!isAuthor && !isReviewer)
|
|
158
|
+
continue;
|
|
159
|
+
const role = isAuthor ? 'author' : 'reviewer';
|
|
160
|
+
const repoName = path.basename(wsPath);
|
|
161
|
+
prs.push({
|
|
162
|
+
number: item.number,
|
|
163
|
+
title: item.title,
|
|
164
|
+
url: item.html_url,
|
|
165
|
+
headRefName: item.pull_request?.head?.ref ?? '',
|
|
166
|
+
baseRefName: item.pull_request?.base?.ref ?? '',
|
|
167
|
+
state: 'OPEN',
|
|
168
|
+
author: item.user.login,
|
|
169
|
+
role,
|
|
170
|
+
updatedAt: item.updated_at,
|
|
171
|
+
additions: 0,
|
|
172
|
+
deletions: 0,
|
|
173
|
+
reviewDecision: null,
|
|
174
|
+
mergeable: null,
|
|
175
|
+
isDraft: false,
|
|
176
|
+
ciStatus: null,
|
|
177
|
+
repoName,
|
|
178
|
+
repoPath: wsPath,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// Sort by updatedAt descending
|
|
182
|
+
prs.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
183
|
+
// Update cache
|
|
184
|
+
cache = { prs, fetchedAt: now };
|
|
185
|
+
// Fire ticket transitions check (best-effort, don't block response)
|
|
186
|
+
// Include recently merged PRs for MERGED->ready-for-qa transitions
|
|
187
|
+
if (deps.checkPrTransitions && deps.getBranchLinks) {
|
|
188
|
+
const transitionPrs = [...prs];
|
|
189
|
+
// Fetch recently merged PRs (last 7 days) for transition checks
|
|
190
|
+
try {
|
|
191
|
+
const mergedSince = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
|
|
192
|
+
.toISOString()
|
|
193
|
+
.split('T')[0];
|
|
194
|
+
const { stdout: mergedStdout } = await exec('gh', [
|
|
195
|
+
'api',
|
|
196
|
+
`search/issues?q=is:pr+is:merged+merged:>=${mergedSince}+involves:@me&per_page=50`,
|
|
197
|
+
], { timeout: GH_TIMEOUT_MS });
|
|
198
|
+
const mergedResponse = JSON.parse(mergedStdout);
|
|
199
|
+
for (const item of mergedResponse.items ?? []) {
|
|
200
|
+
if (!item.pull_request)
|
|
201
|
+
continue;
|
|
202
|
+
const ownerRepo = repoFromApiUrl(item.repository_url);
|
|
203
|
+
if (!ownerRepo)
|
|
204
|
+
continue;
|
|
205
|
+
const wsPath = repoMap.get(ownerRepo.toLowerCase());
|
|
206
|
+
if (!wsPath)
|
|
207
|
+
continue;
|
|
208
|
+
transitionPrs.push({
|
|
209
|
+
number: item.number,
|
|
210
|
+
title: item.title,
|
|
211
|
+
url: item.html_url,
|
|
212
|
+
headRefName: item.pull_request?.head?.ref ?? '',
|
|
213
|
+
baseRefName: item.pull_request?.base?.ref ?? '',
|
|
214
|
+
state: 'MERGED',
|
|
215
|
+
author: item.user.login,
|
|
216
|
+
role: 'author',
|
|
217
|
+
updatedAt: item.updated_at,
|
|
218
|
+
additions: 0,
|
|
219
|
+
deletions: 0,
|
|
220
|
+
reviewDecision: null,
|
|
221
|
+
mergeable: null,
|
|
222
|
+
isDraft: false,
|
|
223
|
+
ciStatus: null,
|
|
224
|
+
repoName: path.basename(wsPath),
|
|
225
|
+
repoPath: wsPath,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// Merged PR fetch is best-effort — don't block transitions
|
|
231
|
+
}
|
|
232
|
+
deps
|
|
233
|
+
.getBranchLinks()
|
|
234
|
+
.then((links) => deps.checkPrTransitions(transitionPrs, links))
|
|
235
|
+
.catch(() => { });
|
|
236
|
+
}
|
|
237
|
+
const response = { prs };
|
|
238
|
+
res.json(response);
|
|
239
|
+
});
|
|
240
|
+
return router;
|
|
241
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Duplicated from utils.ts to preserve output-parsers/ module boundary
|
|
2
|
+
const ANSI_RE = /\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\x1b\[\?[0-9;]*[hlm]|\x1b\[[0-9]*[ABCDJKH]/g;
|
|
3
|
+
/**
|
|
4
|
+
* Claude Code output parser.
|
|
5
|
+
*
|
|
6
|
+
* Claude Code uses a React/Ink TUI. This parser detects semantic state
|
|
7
|
+
* transitions by pattern-matching on cleaned terminal output.
|
|
8
|
+
*/
|
|
9
|
+
export class ClaudeOutputParser {
|
|
10
|
+
currentState = 'initializing';
|
|
11
|
+
hasSeenFirstPrompt = false;
|
|
12
|
+
onData(chunk, _recentScrollback) {
|
|
13
|
+
const clean = chunk.replace(ANSI_RE, '');
|
|
14
|
+
if (!clean.trim())
|
|
15
|
+
return null;
|
|
16
|
+
const newState = this.classify(clean);
|
|
17
|
+
if (newState && newState !== this.currentState) {
|
|
18
|
+
this.currentState = newState;
|
|
19
|
+
return { state: newState };
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
reset() {
|
|
24
|
+
this.currentState = 'initializing';
|
|
25
|
+
this.hasSeenFirstPrompt = false;
|
|
26
|
+
}
|
|
27
|
+
get state() {
|
|
28
|
+
return this.currentState;
|
|
29
|
+
}
|
|
30
|
+
classify(clean) {
|
|
31
|
+
// Permission prompt detection (highest priority)
|
|
32
|
+
if (/\bAllow\b/.test(clean) && /\bDeny\b/.test(clean)) {
|
|
33
|
+
return 'permission-prompt';
|
|
34
|
+
}
|
|
35
|
+
// Error detection
|
|
36
|
+
if (/^Error:|^ERROR:|✗\s|error:/m.test(clean)) {
|
|
37
|
+
return 'error';
|
|
38
|
+
}
|
|
39
|
+
// Waiting for input: the ">" prompt on its own line, or initial greeting
|
|
40
|
+
if (/^>\s*$/m.test(clean) ||
|
|
41
|
+
/How can I help/i.test(clean) ||
|
|
42
|
+
/What would you like/i.test(clean)) {
|
|
43
|
+
this.hasSeenFirstPrompt = true;
|
|
44
|
+
return 'waiting-for-input';
|
|
45
|
+
}
|
|
46
|
+
// Processing: substantive output after the first prompt
|
|
47
|
+
if (this.hasSeenFirstPrompt && clean.trim().length > 0) {
|
|
48
|
+
return 'processing';
|
|
49
|
+
}
|
|
50
|
+
// Still initializing if we haven't seen the first prompt
|
|
51
|
+
if (!this.hasSeenFirstPrompt) {
|
|
52
|
+
return 'initializing';
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex output parser — stub.
|
|
3
|
+
*
|
|
4
|
+
* Always returns null, which tells the system to fall back to
|
|
5
|
+
* timer-based idle detection. Replace with real pattern matching
|
|
6
|
+
* when Codex TUI patterns are mapped.
|
|
7
|
+
*/
|
|
8
|
+
export class CodexOutputParser {
|
|
9
|
+
onData(_chunk, _recentScrollback) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
reset() { }
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ClaudeOutputParser } from './claude-parser.js';
|
|
2
|
+
import { CodexOutputParser } from './codex-parser.js';
|
|
3
|
+
import { OpencodeOutputParser } from './opencode-parser.js';
|
|
4
|
+
import { NullOutputParser } from './null-parser.js';
|
|
5
|
+
/**
|
|
6
|
+
* Registry: factory per parser type. Unknown keys return undefined (fall back to timer-based detection).
|
|
7
|
+
* Keys match AgentFramework.parserType values. 'none' is for frameworks that opt out of parsing.
|
|
8
|
+
*/
|
|
9
|
+
export const outputParsers = {
|
|
10
|
+
claude: () => new ClaudeOutputParser(),
|
|
11
|
+
codex: () => new CodexOutputParser(),
|
|
12
|
+
opencode: () => new OpencodeOutputParser(),
|
|
13
|
+
none: () => new NullOutputParser(),
|
|
14
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Null output parser — always returns null.
|
|
3
|
+
*
|
|
4
|
+
* Used for agents with no known output patterns. Falls back to
|
|
5
|
+
* timer-based idle detection in the calling code.
|
|
6
|
+
*/
|
|
7
|
+
export class NullOutputParser {
|
|
8
|
+
onData(_chunk, _recentScrollback) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
reset() { }
|
|
12
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Duplicated from utils.ts to preserve output-parsers/ module boundary
|
|
2
|
+
const ANSI_RE = /\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\x1b\[\?[0-9;]*[hlm]|\x1b\[[0-9]*[ABCDJKH]/g;
|
|
3
|
+
/**
|
|
4
|
+
* OpenCode output parser.
|
|
5
|
+
*
|
|
6
|
+
* OpenCode uses a Bubble Tea TUI. This parser detects semantic state
|
|
7
|
+
* transitions by pattern-matching on cleaned terminal output.
|
|
8
|
+
*
|
|
9
|
+
* Key patterns:
|
|
10
|
+
* Permission prompt: lines starting with `!` followed by "permission"
|
|
11
|
+
* Tool use (processing): `$` bash, `<-` edit, `->` read, `*` glob/grep, `%` webfetch
|
|
12
|
+
* Agent header: `> build . provider/model` — indicates initializing/resuming
|
|
13
|
+
* Waiting for input: bare `>` prompt or "Ready" / "assistant: done" patterns
|
|
14
|
+
*/
|
|
15
|
+
export class OpencodeOutputParser {
|
|
16
|
+
currentState = 'initializing';
|
|
17
|
+
hasSeenFirstPrompt = false;
|
|
18
|
+
onData(chunk, _recentScrollback) {
|
|
19
|
+
const clean = chunk.replace(ANSI_RE, '');
|
|
20
|
+
if (!clean.trim())
|
|
21
|
+
return null;
|
|
22
|
+
const newState = this.classify(clean);
|
|
23
|
+
if (newState && newState !== this.currentState) {
|
|
24
|
+
this.currentState = newState;
|
|
25
|
+
return { state: newState };
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
reset() {
|
|
30
|
+
this.currentState = 'initializing';
|
|
31
|
+
this.hasSeenFirstPrompt = false;
|
|
32
|
+
}
|
|
33
|
+
get state() {
|
|
34
|
+
return this.currentState;
|
|
35
|
+
}
|
|
36
|
+
classify(clean) {
|
|
37
|
+
// Permission prompt: highest priority — line starting with ! followed by "permission"
|
|
38
|
+
if (/^!\s.*permission/im.test(clean)) {
|
|
39
|
+
return 'permission-prompt';
|
|
40
|
+
}
|
|
41
|
+
// Waiting for input: "Ready" or "assistant: done" patterns
|
|
42
|
+
if (/\bReady\b/.test(clean) || /assistant:\s*done/i.test(clean)) {
|
|
43
|
+
this.hasSeenFirstPrompt = true;
|
|
44
|
+
return 'waiting-for-input';
|
|
45
|
+
}
|
|
46
|
+
// Bare `>` prompt on its own line (not followed by provider/model info)
|
|
47
|
+
if (/^>\s*$/m.test(clean)) {
|
|
48
|
+
this.hasSeenFirstPrompt = true;
|
|
49
|
+
return 'waiting-for-input';
|
|
50
|
+
}
|
|
51
|
+
// Agent header: `> build . provider/model` — initializing/resuming
|
|
52
|
+
// Matches `>` followed by typical opencode startup text (not bare >)
|
|
53
|
+
if (/^>\s+\S+.*\//m.test(clean)) {
|
|
54
|
+
this.hasSeenFirstPrompt = true;
|
|
55
|
+
return 'initializing';
|
|
56
|
+
}
|
|
57
|
+
// Tool icons indicating active processing (after first prompt seen)
|
|
58
|
+
if (this.hasSeenFirstPrompt &&
|
|
59
|
+
(/^\$\s/m.test(clean) || // bash/shell
|
|
60
|
+
/^<-\s/m.test(clean) || // file edit
|
|
61
|
+
/^->\s/m.test(clean) || // file read
|
|
62
|
+
/^\*\s/m.test(clean) || // glob/grep
|
|
63
|
+
/^%\s/m.test(clean)) // webfetch
|
|
64
|
+
) {
|
|
65
|
+
return 'processing';
|
|
66
|
+
}
|
|
67
|
+
// General processing: substantive output after first prompt
|
|
68
|
+
if (this.hasSeenFirstPrompt && clean.trim().length > 0) {
|
|
69
|
+
return 'processing';
|
|
70
|
+
}
|
|
71
|
+
// Still initializing before first prompt
|
|
72
|
+
if (!this.hasSeenFirstPrompt) {
|
|
73
|
+
return 'initializing';
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|