@axhub/genie 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api-docs.html +6 -6
- package/dist/assets/App-BfaNALgf.js +504 -0
- package/dist/assets/App-qxJ8_QYu.css +32 -0
- package/dist/assets/ReviewApp-DIT2yWk-.js +1 -0
- package/dist/assets/_basePickBy-Dz3NcIVK.js +1 -0
- package/dist/assets/_baseUniq-DON_Sg7x.js +1 -0
- package/dist/assets/abap-BdImnpbu.js +1 -0
- package/dist/assets/actionscript-3-CoDkCxhg.js +1 -0
- package/dist/assets/ada-bCR0ucgS.js +1 -0
- package/dist/assets/andromeeda-C4gqWexZ.js +1 -0
- package/dist/assets/angular-html-CU67Zn6k.js +1 -0
- package/dist/assets/angular-ts-BwZT4LLn.js +1 -0
- package/dist/assets/apache-Pmp26Uib.js +1 -0
- package/dist/assets/apex-D8_7TLub.js +1 -0
- package/dist/assets/apl-dKokRX4l.js +1 -0
- package/dist/assets/applescript-Co6uUVPk.js +1 -0
- package/dist/assets/ara-BRHolxvo.js +1 -0
- package/dist/assets/arc-Y4G80q-l.js +1 -0
- package/dist/assets/architectureDiagram-2XIMDMQ5-D_qR4657.js +36 -0
- package/dist/assets/asciidoc-Ve4PFQV2.js +1 -0
- package/dist/assets/asm-D_Q5rh1f.js +1 -0
- package/dist/assets/astro-CbQHKStN.js +1 -0
- package/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/dist/assets/awk-DMzUqQB5.js +1 -0
- package/dist/assets/ayu-dark-DYE7WIF3.js +1 -0
- package/dist/assets/ayu-light-BA47KaF1.js +1 -0
- package/dist/assets/ayu-mirage-32ctXXKs.js +1 -0
- package/dist/assets/ballerina-BFfxhgS-.js +1 -0
- package/dist/assets/bat-BkioyH1T.js +1 -0
- package/dist/assets/beancount-k_qm7-4y.js +1 -0
- package/dist/assets/berry-uYugtg8r.js +1 -0
- package/dist/assets/bibtex-CHM0blh-.js +1 -0
- package/dist/assets/bicep-Bmn6On1c.js +1 -0
- package/dist/assets/bird2-DPOp833l.js +1 -0
- package/dist/assets/blade-D4QpJJKB.js +1 -0
- package/dist/assets/blockDiagram-WCTKOSBZ-NsmAlV5_.js +132 -0
- package/dist/assets/bsl-BO_Y6i37.js +1 -0
- package/dist/assets/c-BIGW1oBm.js +1 -0
- package/dist/assets/c3-eo99z4R2.js +1 -0
- package/dist/assets/c4Diagram-IC4MRINW-cbOJM4yr.js +10 -0
- package/dist/assets/cadence-Bv_4Rxtq.js +1 -0
- package/dist/assets/cairo-KRGpt6FW.js +1 -0
- package/dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- package/dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- package/dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- package/dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- package/dist/assets/channel-C6KNnXlA.js +1 -0
- package/dist/assets/chunk-4BX2VUAB-bLBhl74J.js +1 -0
- package/dist/assets/chunk-55IACEB6-D8kNkDUO.js +1 -0
- package/dist/assets/chunk-FMBD7UC4-BjR6UbXB.js +15 -0
- package/dist/assets/chunk-JSJVCQXG-luNqWn64.js +1 -0
- package/dist/assets/chunk-KX2RTZJC-CNnKm6dK.js +1 -0
- package/dist/assets/chunk-NQ4KR5QH-Cp9gb43u.js +220 -0
- package/dist/assets/chunk-QZHKN3VN-HlVYo2Oq.js +1 -0
- package/dist/assets/chunk-WL4C6EOR-CjSZoOGO.js +189 -0
- package/dist/assets/clarity-D53aC0YG.js +1 -0
- package/dist/assets/classDiagram-VBA2DB6C-BQlzzlH7.js +1 -0
- package/dist/assets/classDiagram-v2-RAHNMMFH-BQlzzlH7.js +1 -0
- package/dist/assets/clojure-P80f7IUj.js +1 -0
- package/dist/assets/clone-DMxS3qWP.js +1 -0
- package/dist/assets/cmake-D1j8_8rp.js +1 -0
- package/dist/assets/cobol-nwyudZeR.js +1 -0
- package/dist/assets/codeowners-Bp6g37R7.js +1 -0
- package/dist/assets/codeql-DsOJ9woJ.js +1 -0
- package/dist/assets/coffee-Ch7k5sss.js +1 -0
- package/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/dist/assets/coq-DkFqJrB1.js +1 -0
- package/dist/assets/cose-bilkent-S5V4N54A-DZWRjeEd.js +1 -0
- package/dist/assets/cpp-CofmeUqb.js +1 -0
- package/dist/assets/crystal-tKQVLTB8.js +1 -0
- package/dist/assets/csharp-COcwbKMJ.js +1 -0
- package/dist/assets/css-DPfMkruS.js +1 -0
- package/dist/assets/csv-fuZLfV_i.js +1 -0
- package/dist/assets/cue-D82EKSYY.js +1 -0
- package/dist/assets/cypher-COkxafJQ.js +1 -0
- package/dist/assets/cytoscape.esm-2ZfV8NB5.js +331 -0
- package/dist/assets/d-85-TOEBH.js +1 -0
- package/dist/assets/dagre-KLK3FWXG-yAzUmqI7.js +4 -0
- package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
- package/dist/assets/dart-CF10PKvl.js +1 -0
- package/dist/assets/dax-CEL-wOlO.js +1 -0
- package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/assets/desktop-BmXAJ9_W.js +1 -0
- package/dist/assets/diagram-E7M64L7V-CvzlIvDJ.js +24 -0
- package/dist/assets/diagram-IFDJBPK2-DFMIJpuM.js +43 -0
- package/dist/assets/diagram-P4PSJMXO-KL-J3gyb.js +24 -0
- package/dist/assets/diff-D97Zzqfu.js +1 -0
- package/dist/assets/docker-BcOcwvcX.js +1 -0
- package/dist/assets/dotenv-Da5cRb03.js +1 -0
- package/dist/assets/dracula-BzJJZx-M.js +1 -0
- package/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/dist/assets/dream-maker-BtqSS_iP.js +1 -0
- package/dist/assets/edge-BkV0erSs.js +1 -0
- package/dist/assets/elixir-CDX3lj18.js +1 -0
- package/dist/assets/elm-DbKCFpqz.js +1 -0
- package/dist/assets/emacs-lisp-C9XAeP06.js +1 -0
- package/dist/assets/erDiagram-INFDFZHY-BXszHbTM.js +70 -0
- package/dist/assets/erb-B12qg9BL.js +1 -0
- package/dist/assets/erlang-DsQrWhSR.js +1 -0
- package/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/dist/assets/everforest-light-C8M2exoo.js +1 -0
- package/dist/assets/fennel-BYunw83y.js +1 -0
- package/dist/assets/fish-BvzEVeQv.js +1 -0
- package/dist/assets/flowDiagram-PKNHOUZH-Ba43NVp6.js +162 -0
- package/dist/assets/fluent-C4IJs8-o.js +1 -0
- package/dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- package/dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
- package/dist/assets/fsharp-CXgrBDvD.js +1 -0
- package/dist/assets/ganttDiagram-A5KZAMGK-uLHfhCrg.js +292 -0
- package/dist/assets/gdresource-BOOCDP_w.js +1 -0
- package/dist/assets/gdscript-C5YyOfLZ.js +1 -0
- package/dist/assets/gdshader-DkwncUOv.js +1 -0
- package/dist/assets/genie-D0YGMca9.js +1 -0
- package/dist/assets/gherkin-DyxjwDmM.js +1 -0
- package/dist/assets/git-commit-F4YmCXRG.js +1 -0
- package/dist/assets/git-rebase-r7XF79zn.js +1 -0
- package/dist/assets/gitGraphDiagram-K3NZZRJ6-BTEuFaiL.js +65 -0
- package/dist/assets/github-dark-DHJKELXO.js +1 -0
- package/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/dist/assets/github-light-DAi9KRSo.js +1 -0
- package/dist/assets/github-light-default-D7oLnXFd.js +1 -0
- package/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/dist/assets/gleam-BspZqrRM.js +1 -0
- package/dist/assets/glimmer-js-Rg0-pVw9.js +1 -0
- package/dist/assets/glimmer-ts-U6CK756n.js +1 -0
- package/dist/assets/glsl-DplSGwfg.js +1 -0
- package/dist/assets/gn-n2N0HUVH.js +1 -0
- package/dist/assets/gnuplot-DdkO51Og.js +1 -0
- package/dist/assets/go-CxLEBnE3.js +1 -0
- package/dist/assets/graph-h2nuWjx4.js +1 -0
- package/dist/assets/graphql-ChdNCCLP.js +1 -0
- package/dist/assets/groovy-gcz8RCvz.js +1 -0
- package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/dist/assets/hack-CaT9iCJl.js +1 -0
- package/dist/assets/haml-B8DHNrY2.js +1 -0
- package/dist/assets/handlebars-BL8al0AC.js +1 -0
- package/dist/assets/haskell-Df6bDoY_.js +1 -0
- package/dist/assets/haxe-CzTSHFRz.js +1 -0
- package/dist/assets/hcl-BWvSN4gD.js +1 -0
- package/dist/assets/highlighted-body-TPN3WLV5-C6BY7XZJ.js +1 -0
- package/dist/assets/hjson-D5-asLiD.js +1 -0
- package/dist/assets/hlsl-D3lLCCz7.js +1 -0
- package/dist/assets/horizon-BUw7H-hv.js +1 -0
- package/dist/assets/horizon-bright-Cn-bp-IR.js +1 -0
- package/dist/assets/houston-DnULxvSX.js +1 -0
- package/dist/assets/html-GMplVEZG.js +1 -0
- package/dist/assets/html-derivative-BFtXZ54Q.js +1 -0
- package/dist/assets/http-jrhK8wxY.js +1 -0
- package/dist/assets/hurl-irOxFIW8.js +1 -0
- package/dist/assets/hxml-Bvhsp5Yf.js +1 -0
- package/dist/assets/hy-DFXneXwc.js +1 -0
- package/dist/assets/imba-DGztddWO.js +1 -0
- package/dist/assets/index-2198VgsK.css +1 -0
- package/dist/assets/index-C6Bb2jGF.js +2 -0
- package/dist/assets/infoDiagram-LFFYTUFH-BOLfvCIq.js +2 -0
- package/dist/assets/ini-BEwlwnbL.js +1 -0
- package/dist/assets/init-Gi6I4Gst.js +1 -0
- package/dist/assets/ishikawaDiagram-PHBUUO56-BRzQ1ee5.js +70 -0
- package/dist/assets/java-CylS5w8V.js +1 -0
- package/dist/assets/javascript-wDzz0qaB.js +1 -0
- package/dist/assets/jinja-4LBKfQ-Z.js +1 -0
- package/dist/assets/jison-wvAkD_A8.js +1 -0
- package/dist/assets/journeyDiagram-4ABVD52K-DXm_VcMy.js +139 -0
- package/dist/assets/json-Cp-IABpG.js +1 -0
- package/dist/assets/json5-C9tS-k6U.js +1 -0
- package/dist/assets/jsonc-Des-eS-w.js +1 -0
- package/dist/assets/jsonl-DcaNXYhu.js +1 -0
- package/dist/assets/jsonnet-DFQXde-d.js +1 -0
- package/dist/assets/jssm-C2t-YnRu.js +1 -0
- package/dist/assets/jsx-g9-lgVsj.js +1 -0
- package/dist/assets/julia-CxzCAyBv.js +1 -0
- package/dist/assets/just-Cw27pwNe.js +1 -0
- package/dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/dist/assets/kanban-definition-K7BYSVSG-D_oyzopl.js +89 -0
- package/dist/assets/kdl-DV7GczEv.js +1 -0
- package/dist/assets/kotlin-BdnUsdx6.js +1 -0
- package/dist/assets/kusto-DZf3V79B.js +1 -0
- package/dist/assets/laserwave-DUszq2jm.js +1 -0
- package/dist/assets/latex-CWtU0Tv5.js +1 -0
- package/dist/assets/layout-Q8YoR_E1.js +1 -0
- package/dist/assets/lean-BZvkOJ9d.js +1 -0
- package/dist/assets/less-B1dDrJ26.js +1 -0
- package/dist/assets/light-plus-B7mTdjB0.js +1 -0
- package/dist/assets/linear-B3qNg7di.js +1 -0
- package/dist/assets/liquid-DYVedYrR.js +1 -0
- package/dist/assets/llvm-DjAJT7YJ.js +1 -0
- package/dist/assets/log-2UxHyX5q.js +1 -0
- package/dist/assets/logo-BtOb2qkB.js +1 -0
- package/dist/assets/lua-BaeVxFsk.js +1 -0
- package/dist/assets/luau-C-HG3fhB.js +1 -0
- package/dist/assets/make-CHLpvVh8.js +1 -0
- package/dist/assets/markdown-Cvjx9yec.js +1 -0
- package/dist/assets/marko-CnJfTvn9.js +1 -0
- package/dist/assets/material-theme-D5KoaKCx.js +1 -0
- package/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/dist/assets/matlab-D7o27uSR.js +1 -0
- package/dist/assets/mdc-BMNejdWA.js +1 -0
- package/dist/assets/mdx-Cmh6b_Ma.js +1 -0
- package/dist/assets/mermaid-O7DHMXV3-BVZ_4MKo.js +988 -0
- package/dist/assets/mermaid-mWjccvbQ.js +1 -0
- package/dist/assets/min-dark-CafNBF8u.js +1 -0
- package/dist/assets/min-light-CTRr51gU.js +1 -0
- package/dist/assets/mindmap-definition-YRQLILUH-CjulgYdi.js +68 -0
- package/dist/assets/mipsasm-CKIfxQSi.js +1 -0
- package/dist/assets/mojo-rZm6bMo-.js +1 -0
- package/dist/assets/monokai-D4h5O-jR.js +1 -0
- package/dist/assets/moonbit-_H4v1dQx.js +1 -0
- package/dist/assets/move-IF9eRakj.js +1 -0
- package/dist/assets/narrat-DRg8JJMk.js +1 -0
- package/dist/assets/nextflow-Zz6hmt5N.js +1 -0
- package/dist/assets/nextflow-groovy-BeH2EWoN.js +1 -0
- package/dist/assets/nginx-BpAMiNFr.js +1 -0
- package/dist/assets/night-owl-C39BiMTA.js +1 -0
- package/dist/assets/night-owl-light-CMTm3GFP.js +1 -0
- package/dist/assets/nim-CVrawwO9.js +1 -0
- package/dist/assets/nix-CwoSXNpI.js +1 -0
- package/dist/assets/nord-Ddv68eIx.js +1 -0
- package/dist/assets/nushell-Cz2AlsmD.js +1 -0
- package/dist/assets/objective-c-DXmwc3jG.js +1 -0
- package/dist/assets/objective-cpp-CLxacb5B.js +1 -0
- package/dist/assets/ocaml-C0hk2d4L.js +1 -0
- package/dist/assets/odin-BBf5iR-q.js +1 -0
- package/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/dist/assets/one-light-C3Wv6jpd.js +1 -0
- package/dist/assets/openscad-C4EeE6gA.js +1 -0
- package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/assets/pascal-D93ZcfNL.js +1 -0
- package/dist/assets/perl-C0TMdlhV.js +1 -0
- package/dist/assets/php-Dhbhpdrm.js +1 -0
- package/dist/assets/pieDiagram-SKSYHLDU-8VzrefxA.js +30 -0
- package/dist/assets/pkl-u5AG7uiY.js +1 -0
- package/dist/assets/plastic-3e1v2bzS.js +1 -0
- package/dist/assets/plsql-ChMvpjG-.js +1 -0
- package/dist/assets/po-BTJTHyun.js +1 -0
- package/dist/assets/poimandres-CS3Unz2-.js +1 -0
- package/dist/assets/polar-C0HS_06l.js +1 -0
- package/dist/assets/postcss-CXtECtnM.js +1 -0
- package/dist/assets/powerquery-CEu0bR-o.js +1 -0
- package/dist/assets/powershell-Dpen1YoG.js +1 -0
- package/dist/assets/prisma-Dd19v3D-.js +1 -0
- package/dist/assets/prolog-CbFg5uaA.js +1 -0
- package/dist/assets/proto-C7zT0LnQ.js +1 -0
- package/dist/assets/pug-CGlum2m_.js +1 -0
- package/dist/assets/puppet-BMWR74SV.js +1 -0
- package/dist/assets/purescript-CklMAg4u.js +1 -0
- package/dist/assets/python-B6aJPvgy.js +1 -0
- package/dist/assets/qml-3beO22l8.js +1 -0
- package/dist/assets/qmldir-C8lEn-DE.js +1 -0
- package/dist/assets/qss-IeuSbFQv.js +1 -0
- package/dist/assets/quadrantDiagram-337W2JSQ-CFh-ijm2.js +7 -0
- package/dist/assets/r-Dspwwk_N.js +1 -0
- package/dist/assets/racket-BqYA7rlc.js +1 -0
- package/dist/assets/raku-DXvB9xmW.js +1 -0
- package/dist/assets/razor-Uh8Bk_45.js +1 -0
- package/dist/assets/red-bN70gL4F.js +1 -0
- package/dist/assets/reg-C-SQnVFl.js +1 -0
- package/dist/assets/regexp-CDVJQ6XC.js +1 -0
- package/dist/assets/rel-C3B-1QV4.js +1 -0
- package/dist/assets/requirementDiagram-Z7DCOOCP-BNPlTs5Q.js +73 -0
- package/dist/assets/riscv-BM1_JUlF.js +1 -0
- package/dist/assets/ron-D8l8udqQ.js +1 -0
- package/dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- package/dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- package/dist/assets/rose-pine-qdsjHGoJ.js +1 -0
- package/dist/assets/rosmsg-BJDFO7_C.js +1 -0
- package/dist/assets/rst-BrH8l1NY.js +1 -0
- package/dist/assets/ruby-Dw2BHqvy.js +1 -0
- package/dist/assets/rust-B1yitclQ.js +1 -0
- package/dist/assets/sankeyDiagram-WA2Y5GQK-C5l_hYst.js +10 -0
- package/dist/assets/sas-cz2c8ADy.js +1 -0
- package/dist/assets/sass-Cj5Yp3dK.js +1 -0
- package/dist/assets/scala-C151Ov-r.js +1 -0
- package/dist/assets/scheme-C98Dy4si.js +1 -0
- package/dist/assets/scss-OYdSNvt2.js +1 -0
- package/dist/assets/sdbl-DVxCFoDh.js +1 -0
- package/dist/assets/sequenceDiagram-2WXFIKYE-B4a_rQw8.js +145 -0
- package/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/dist/assets/shellscript-Yzrsuije.js +1 -0
- package/dist/assets/shellsession-BADoaaVG.js +1 -0
- package/dist/assets/slack-dark-BthQWCQV.js +1 -0
- package/dist/assets/slack-ochin-DqwNpetd.js +1 -0
- package/dist/assets/smalltalk-BERRCDM3.js +1 -0
- package/dist/assets/snazzy-light-Bw305WKR.js +1 -0
- package/dist/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/dist/assets/solarized-light-L9t79GZl.js +1 -0
- package/dist/assets/solidity-rGO070M0.js +1 -0
- package/dist/assets/soy-Brmx7dQM.js +1 -0
- package/dist/assets/sparql-rVzFXLq3.js +1 -0
- package/dist/assets/splunk-BtCnVYZw.js +1 -0
- package/dist/assets/sql-BLtJtn59.js +1 -0
- package/dist/assets/ssh-config-_ykCGR6B.js +1 -0
- package/dist/assets/stata-BH5u7GGu.js +1 -0
- package/dist/assets/stateDiagram-RAJIS63D-Bt4mMmKB.js +1 -0
- package/dist/assets/stateDiagram-v2-FVOUBMTO-6NYMazfq.js +1 -0
- package/dist/assets/stylus-BEDo0Tqx.js +1 -0
- package/dist/assets/surrealql-Bq5Q-fJD.js +1 -0
- package/dist/assets/svelte-C_ipcX3V.js +1 -0
- package/dist/assets/swift-D82vCrfD.js +1 -0
- package/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/dist/assets/system-verilog-CnnmHF94.js +1 -0
- package/dist/assets/systemd-4A_iFExJ.js +1 -0
- package/dist/assets/talonscript-CkByrt1z.js +1 -0
- package/dist/assets/tasl-QIJgUcNo.js +1 -0
- package/dist/assets/tcl-dwOrl1Do.js +1 -0
- package/dist/assets/templ-P3uqSqPl.js +1 -0
- package/dist/assets/terraform-BETggiCN.js +1 -0
- package/dist/assets/tex-idrVyKtj.js +1 -0
- package/dist/assets/timeline-definition-YZTLITO2-CLYvSw_R.js +61 -0
- package/dist/assets/tokyo-night-hegEt444.js +1 -0
- package/dist/assets/toml-vGWfd6FD.js +1 -0
- package/dist/assets/treemap-KZPCXAKY-ksND0hZK.js +162 -0
- package/dist/assets/ts-tags-zn1MmPIZ.js +1 -0
- package/dist/assets/tsv-B_m7g4N7.js +1 -0
- package/dist/assets/tsx-COt5Ahok.js +1 -0
- package/dist/assets/turtle-BsS91CYL.js +1 -0
- package/dist/assets/twig-DNn4PbVi.js +1 -0
- package/dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/dist/assets/typespec-BGHnOYBU.js +1 -0
- package/dist/assets/typst-DHCkPAjA.js +1 -0
- package/dist/assets/v-BcVCzyr7.js +1 -0
- package/dist/assets/vala-CsfeWuGM.js +1 -0
- package/dist/assets/vb-D17OF-Vu.js +1 -0
- package/dist/assets/{vendor-codemirror-B88_OPWf.js → vendor-codemirror-Dz7_EqNA.js} +3 -3
- package/dist/assets/{vendor-react-C3RJLQGO.js → vendor-react-Cpt6D04s.js} +11 -11
- package/dist/assets/vennDiagram-LZ73GAT5-CaQg4oZK.js +34 -0
- package/dist/assets/verilog-BQ8w6xss.js +1 -0
- package/dist/assets/vesper-DU1UobuO.js +1 -0
- package/dist/assets/vhdl-CeAyd5Ju.js +1 -0
- package/dist/assets/viml-CJc9bBzg.js +1 -0
- package/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/dist/assets/vue-DN_0RTcg.js +1 -0
- package/dist/assets/vue-html-AaS7Mt5G.js +1 -0
- package/dist/assets/vue-vine-CQOfvN7w.js +1 -0
- package/dist/assets/vyper-CDx5xZoG.js +1 -0
- package/dist/assets/wasm-CG6Dc4jp.js +1 -0
- package/dist/assets/wasm-MzD3tlZU.js +1 -0
- package/dist/assets/wenyan-BV7otONQ.js +1 -0
- package/dist/assets/wgsl-Dx-B1_4e.js +1 -0
- package/dist/assets/wikitext-BhOHFoWU.js +1 -0
- package/dist/assets/wit-5i3qLPDT.js +1 -0
- package/dist/assets/wolfram-lXgVvXCa.js +1 -0
- package/dist/assets/xml-sdJ4AIDG.js +1 -0
- package/dist/assets/xsl-CtQFsRM5.js +1 -0
- package/dist/assets/xychartDiagram-JWTSCODW-C8dCbTeM.js +7 -0
- package/dist/assets/yaml-Buea-lGh.js +1 -0
- package/dist/assets/zenscript-DVFEvuxE.js +1 -0
- package/dist/assets/zig-VOosw3JB.js +1 -0
- package/dist/index.html +35 -21
- package/dist/manifest.json +1 -1
- package/dist/sw.js +18 -46
- package/package.json +12 -8
- package/server/bin/codex-sdk-wrapper.js +49 -0
- package/server/channels/runtime/AgentRuntimeAdapter.js +2 -5
- package/server/channels/store/ChannelStore.js +73 -107
- package/server/claude-sdk.js +160 -6
- package/server/cli.js +590 -32
- package/server/cli.test.js +76 -0
- package/server/database/db.js +438 -372
- package/server/external-agent/auth.js +88 -0
- package/server/external-agent/service.js +1052 -0
- package/server/external-agent/service.test.js +41 -0
- package/server/external-agent/ws.js +1526 -0
- package/server/external-agent/ws.test.js +289 -0
- package/server/gemini-cli.js +108 -20
- package/server/index.js +115 -121
- package/server/load-env.js +16 -13
- package/server/openai-codex.js +165 -11
- package/server/opencode-cli.js +3 -2
- package/server/projects.js +432 -338
- package/server/routes/agent.js +347 -459
- package/server/routes/auth.js +14 -36
- package/server/routes/cli-auth.js +60 -113
- package/server/routes/commands.js +16 -26
- package/server/routes/git.js +5 -16
- package/server/routes/projects.js +2 -7
- package/server/routes/session-core.js +177 -0
- package/server/session-core/abortSession.js +48 -0
- package/server/session-core/eventStore.js +139 -0
- package/server/session-core/providerAdapters.js +84 -0
- package/server/session-core/providerDiscovery.js +235 -0
- package/server/session-core/runtimeState.js +390 -0
- package/server/session-core/runtimeWriter.js +59 -0
- package/server/utils/agentCallback.js +273 -0
- package/server/utils/agentImages.js +253 -0
- package/server/utils/codexPath.js +47 -0
- package/server/utils/defaultWorkingDirectory.js +34 -0
- package/shared/conversationEvents.js +1071 -0
- package/shared/modelConstants.js +18 -24
- package/dist/assets/index-CVjMty4a.js +0 -902
- package/dist/assets/index-eo5scY_Z.css +0 -32
- package/server/cursor-cli.js +0 -276
- package/server/database/init.sql +0 -98
- package/server/routes/cursor.js +0 -795
|
@@ -0,0 +1,1052 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { promises as fs } from 'fs';
|
|
5
|
+
import crypto from 'crypto';
|
|
6
|
+
import { Octokit } from '@octokit/rest';
|
|
7
|
+
|
|
8
|
+
import { githubTokensDb } from '../database/db.js';
|
|
9
|
+
import { addProjectManually } from '../projects.js';
|
|
10
|
+
import { queryClaudeSDK } from '../claude-sdk.js';
|
|
11
|
+
import { queryCodex } from '../openai-codex.js';
|
|
12
|
+
import { queryGemini } from '../gemini-cli.js';
|
|
13
|
+
import { queryOpencode } from '../opencode-cli.js';
|
|
14
|
+
import {
|
|
15
|
+
buildAgentCallbackPayload,
|
|
16
|
+
createAgentCallbackEventId,
|
|
17
|
+
createEmptyTokenSummary,
|
|
18
|
+
normalizeAgentCallbackConfig,
|
|
19
|
+
scheduleAgentCallbackDelivery,
|
|
20
|
+
shouldDeliverAgentCallback
|
|
21
|
+
} from '../utils/agentCallback.js';
|
|
22
|
+
import { normalizeExternalImages } from '../utils/agentImages.js';
|
|
23
|
+
import { resolveWorkingDirectory } from '../utils/defaultWorkingDirectory.js';
|
|
24
|
+
import { CODEX_MODELS, GEMINI_MODELS, OPENCODE_MODELS } from '../../shared/modelConstants.js';
|
|
25
|
+
|
|
26
|
+
export const SUPPORTED_EXTERNAL_AGENT_PROVIDERS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
27
|
+
|
|
28
|
+
function createRequestError(message, statusCode = 400) {
|
|
29
|
+
const error = new Error(message);
|
|
30
|
+
error.statusCode = statusCode;
|
|
31
|
+
return error;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseBoolean(value, fallback) {
|
|
35
|
+
if (value === undefined) {
|
|
36
|
+
return fallback;
|
|
37
|
+
}
|
|
38
|
+
return value === true || value === 'true';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function buildSessionNavigation(sessionId) {
|
|
42
|
+
const normalizedSessionId = typeof sessionId === 'string' && sessionId.trim() ? sessionId.trim() : null;
|
|
43
|
+
const sessionPath = normalizedSessionId ? `/session/${normalizedSessionId}` : null;
|
|
44
|
+
const frontendPort = process.env.VITE_PORT || '5173';
|
|
45
|
+
const configuredFrontendUrl = typeof process.env.FRONTEND_URL === 'string'
|
|
46
|
+
? process.env.FRONTEND_URL.trim().replace(/\/+$/, '')
|
|
47
|
+
: '';
|
|
48
|
+
const frontendBaseUrl = configuredFrontendUrl || `http://localhost:${frontendPort}`;
|
|
49
|
+
const sessionUrl = normalizedSessionId ? `${frontendBaseUrl}${sessionPath}` : null;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
sessionPath,
|
|
53
|
+
sessionUrl
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function normalizeExternalAgentRunRequest(body = {}) {
|
|
58
|
+
const { githubUrl, projectPath, message, model, githubToken, branchName, sessionId, openOnly } = body;
|
|
59
|
+
const provider = typeof body.provider === 'string' ? body.provider.trim() : 'claude';
|
|
60
|
+
const stream = parseBoolean(body.stream, true);
|
|
61
|
+
const requestedCleanup = parseBoolean(body.cleanup, true);
|
|
62
|
+
const createBranch = branchName ? true : parseBoolean(body.createBranch, false);
|
|
63
|
+
const createPR = parseBoolean(body.createPR, false);
|
|
64
|
+
const normalizedSessionId = typeof sessionId === 'string' && sessionId.trim() ? sessionId.trim() : null;
|
|
65
|
+
const normalizedMessage = typeof message === 'string' ? message.trim() : '';
|
|
66
|
+
const requestedOpenOnly = openOnly === true || openOnly === 'true';
|
|
67
|
+
const isOpenOnly = requestedOpenOnly || (!normalizedMessage && !!normalizedSessionId);
|
|
68
|
+
const cleanup = isOpenOnly ? false : requestedCleanup;
|
|
69
|
+
const images = normalizeExternalImages(body.images);
|
|
70
|
+
const resolvedProjectPath = githubUrl ? projectPath : resolveWorkingDirectory({ projectPath });
|
|
71
|
+
|
|
72
|
+
let callbackConfig = null;
|
|
73
|
+
try {
|
|
74
|
+
callbackConfig = normalizeAgentCallbackConfig(body.callback);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw createRequestError(error.message, 400);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!SUPPORTED_EXTERNAL_AGENT_PROVIDERS.includes(provider)) {
|
|
80
|
+
throw createRequestError('provider must be "claude", "codex", "gemini", or "opencode"', 400);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (sessionId !== undefined && (typeof sessionId !== 'string' || !sessionId.trim())) {
|
|
84
|
+
throw createRequestError('sessionId must be a non-empty string when provided', 400);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (isOpenOnly && !normalizedSessionId) {
|
|
88
|
+
throw createRequestError('sessionId is required when message is empty or openOnly=true', 400);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!isOpenOnly && !normalizedMessage) {
|
|
92
|
+
throw createRequestError('message is required unless openOnly=true', 400);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (isOpenOnly && githubUrl) {
|
|
96
|
+
throw createRequestError('githubUrl is not supported when openOnly=true', 400);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (isOpenOnly && (createBranch || createPR)) {
|
|
100
|
+
throw createRequestError('createBranch and createPR are not supported when openOnly=true', 400);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (isOpenOnly && callbackConfig) {
|
|
104
|
+
throw createRequestError('callback is not supported when openOnly=true', 400);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (isOpenOnly && images.length > 0) {
|
|
108
|
+
throw createRequestError('images is not supported when openOnly=true', 400);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (images.length > 0 && provider !== 'claude' && provider !== 'codex') {
|
|
112
|
+
throw createRequestError(`images is not supported for provider "${provider}"`, 400);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
githubUrl,
|
|
117
|
+
projectPath: resolvedProjectPath,
|
|
118
|
+
message,
|
|
119
|
+
normalizedMessage,
|
|
120
|
+
provider,
|
|
121
|
+
model,
|
|
122
|
+
githubToken,
|
|
123
|
+
branchName,
|
|
124
|
+
sessionId,
|
|
125
|
+
normalizedSessionId,
|
|
126
|
+
openOnly,
|
|
127
|
+
requestedOpenOnly,
|
|
128
|
+
isOpenOnly,
|
|
129
|
+
createBranch,
|
|
130
|
+
createPR,
|
|
131
|
+
stream,
|
|
132
|
+
requestedCleanup,
|
|
133
|
+
cleanup,
|
|
134
|
+
callbackConfig,
|
|
135
|
+
images
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function normalizeExternalAgentAbortRequest(body = {}) {
|
|
140
|
+
const normalizedSessionId = typeof body.sessionId === 'string' ? body.sessionId.trim() : '';
|
|
141
|
+
const provider = typeof body.provider === 'string' && body.provider.trim()
|
|
142
|
+
? body.provider.trim().toLowerCase()
|
|
143
|
+
: 'claude';
|
|
144
|
+
|
|
145
|
+
if (!normalizedSessionId) {
|
|
146
|
+
throw createRequestError('sessionId is required', 400);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!SUPPORTED_EXTERNAL_AGENT_PROVIDERS.includes(provider)) {
|
|
150
|
+
throw createRequestError(`provider must be one of: ${SUPPORTED_EXTERNAL_AGENT_PROVIDERS.join(', ')}`, 400);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
sessionId: normalizedSessionId,
|
|
155
|
+
provider
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function getGitRemoteUrl(repoPath) {
|
|
160
|
+
return new Promise((resolve, reject) => {
|
|
161
|
+
const gitProcess = spawn('git', ['config', '--get', 'remote.origin.url'], {
|
|
162
|
+
cwd: repoPath,
|
|
163
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
let stdout = '';
|
|
167
|
+
let stderr = '';
|
|
168
|
+
|
|
169
|
+
gitProcess.stdout.on('data', (data) => {
|
|
170
|
+
stdout += data.toString();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
gitProcess.stderr.on('data', (data) => {
|
|
174
|
+
stderr += data.toString();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
gitProcess.on('close', (code) => {
|
|
178
|
+
if (code === 0) {
|
|
179
|
+
resolve(stdout.trim());
|
|
180
|
+
} else {
|
|
181
|
+
reject(new Error(`Failed to get git remote: ${stderr}`));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
gitProcess.on('error', (error) => {
|
|
186
|
+
reject(new Error(`Failed to execute git: ${error.message}`));
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function normalizeGitHubUrl(url) {
|
|
192
|
+
let normalized = url.replace(/\.git$/, '');
|
|
193
|
+
normalized = normalized.replace(/^git@github\.com:/, 'https://github.com/');
|
|
194
|
+
normalized = normalized.replace(/\/$/, '');
|
|
195
|
+
return normalized.toLowerCase();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function parseGitHubUrl(url) {
|
|
199
|
+
const match = url.match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
200
|
+
if (!match) {
|
|
201
|
+
throw new Error('Invalid GitHub URL format');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
owner: match[1],
|
|
206
|
+
repo: match[2].replace(/\.git$/, '')
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function autogenerateBranchName(message) {
|
|
211
|
+
let branchName = message
|
|
212
|
+
.toLowerCase()
|
|
213
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
214
|
+
.replace(/\s+/g, '-')
|
|
215
|
+
.replace(/-+/g, '-')
|
|
216
|
+
.replace(/^-|-$/g, '');
|
|
217
|
+
|
|
218
|
+
if (!branchName) {
|
|
219
|
+
branchName = 'task';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const timestamp = Date.now().toString(36).slice(-6);
|
|
223
|
+
const suffix = `-${timestamp}`;
|
|
224
|
+
const maxBaseLength = 50 - suffix.length;
|
|
225
|
+
|
|
226
|
+
if (branchName.length > maxBaseLength) {
|
|
227
|
+
branchName = branchName.substring(0, maxBaseLength);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
branchName = branchName.replace(/-$/, '').replace(/^-+/, '');
|
|
231
|
+
|
|
232
|
+
if (!branchName || branchName.startsWith('-')) {
|
|
233
|
+
branchName = 'task';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
branchName = `${branchName}${suffix}`;
|
|
237
|
+
|
|
238
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(branchName)) {
|
|
239
|
+
return `branch-${timestamp}`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return branchName;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function validateBranchName(branchName) {
|
|
246
|
+
if (!branchName || branchName.trim() === '') {
|
|
247
|
+
return { valid: false, error: 'Branch name cannot be empty' };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const invalidPatterns = [
|
|
251
|
+
{ pattern: /^\./, message: 'Branch name cannot start with a dot' },
|
|
252
|
+
{ pattern: /\.$/, message: 'Branch name cannot end with a dot' },
|
|
253
|
+
{ pattern: /\.\./, message: 'Branch name cannot contain consecutive dots (..)' },
|
|
254
|
+
{ pattern: /\s/, message: 'Branch name cannot contain spaces' },
|
|
255
|
+
{ pattern: /[~^:?*\[\\]/, message: 'Branch name cannot contain special characters: ~ ^ : ? * [ \\' },
|
|
256
|
+
{ pattern: /@{/, message: 'Branch name cannot contain @{' },
|
|
257
|
+
{ pattern: /\/$/, message: 'Branch name cannot end with a slash' },
|
|
258
|
+
{ pattern: /^\//, message: 'Branch name cannot start with a slash' },
|
|
259
|
+
{ pattern: /\/\//, message: 'Branch name cannot contain consecutive slashes' },
|
|
260
|
+
{ pattern: /\.lock$/, message: 'Branch name cannot end with .lock' }
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
for (const { pattern, message } of invalidPatterns) {
|
|
264
|
+
if (pattern.test(branchName)) {
|
|
265
|
+
return { valid: false, error: message };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (/[\x00-\x1F\x7F]/.test(branchName)) {
|
|
270
|
+
return { valid: false, error: 'Branch name cannot contain control characters' };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return { valid: true };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async function getCommitMessages(projectPath, limit = 5) {
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
const gitProcess = spawn('git', ['log', `-${limit}`, '--pretty=format:%s'], {
|
|
279
|
+
cwd: projectPath,
|
|
280
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
let stdout = '';
|
|
284
|
+
let stderr = '';
|
|
285
|
+
|
|
286
|
+
gitProcess.stdout.on('data', (data) => {
|
|
287
|
+
stdout += data.toString();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
gitProcess.stderr.on('data', (data) => {
|
|
291
|
+
stderr += data.toString();
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
gitProcess.on('close', (code) => {
|
|
295
|
+
if (code === 0) {
|
|
296
|
+
resolve(stdout.trim().split('\n').filter((msg) => msg.length > 0));
|
|
297
|
+
} else {
|
|
298
|
+
reject(new Error(`Failed to get commit messages: ${stderr}`));
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
gitProcess.on('error', (error) => {
|
|
303
|
+
reject(new Error(`Failed to execute git: ${error.message}`));
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
async function createGitHubPR(octokit, owner, repo, branchName, title, body, baseBranch = 'main') {
|
|
309
|
+
const { data: pr } = await octokit.pulls.create({
|
|
310
|
+
owner,
|
|
311
|
+
repo,
|
|
312
|
+
title,
|
|
313
|
+
head: branchName,
|
|
314
|
+
base: baseBranch,
|
|
315
|
+
body
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
number: pr.number,
|
|
320
|
+
url: pr.html_url
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function cloneGitHubRepo(githubUrl, githubToken = null, projectPath) {
|
|
325
|
+
return new Promise(async (resolve, reject) => {
|
|
326
|
+
try {
|
|
327
|
+
if (!githubUrl || !githubUrl.includes('github.com')) {
|
|
328
|
+
throw new Error('Invalid GitHub URL');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const cloneDir = path.resolve(projectPath);
|
|
332
|
+
let directoryExists = false;
|
|
333
|
+
try {
|
|
334
|
+
await fs.access(cloneDir);
|
|
335
|
+
directoryExists = true;
|
|
336
|
+
} catch {
|
|
337
|
+
directoryExists = false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (directoryExists) {
|
|
341
|
+
try {
|
|
342
|
+
const existingUrl = await getGitRemoteUrl(cloneDir);
|
|
343
|
+
const normalizedExisting = normalizeGitHubUrl(existingUrl);
|
|
344
|
+
const normalizedRequested = normalizeGitHubUrl(githubUrl);
|
|
345
|
+
|
|
346
|
+
if (normalizedExisting === normalizedRequested) {
|
|
347
|
+
return resolve(cloneDir);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
throw new Error(`Directory ${cloneDir} already exists with a different repository (${existingUrl}). Expected: ${githubUrl}`);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
if (error.message && error.message.includes('different repository')) {
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
throw new Error(`Directory ${cloneDir} already exists but is not a valid git repository or git command failed`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
await fs.mkdir(path.dirname(cloneDir), { recursive: true });
|
|
360
|
+
|
|
361
|
+
let cloneUrl = githubUrl;
|
|
362
|
+
if (githubToken) {
|
|
363
|
+
cloneUrl = githubUrl.replace('https://github.com', `https://${githubToken}@github.com`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const gitProcess = spawn('git', ['clone', '--depth', '1', cloneUrl, cloneDir], {
|
|
367
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
let stderr = '';
|
|
371
|
+
|
|
372
|
+
gitProcess.stderr.on('data', (data) => {
|
|
373
|
+
stderr += data.toString();
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
gitProcess.on('close', (code) => {
|
|
377
|
+
if (code === 0) {
|
|
378
|
+
resolve(cloneDir);
|
|
379
|
+
} else {
|
|
380
|
+
reject(new Error(`Git clone failed: ${stderr}`));
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
gitProcess.on('error', (error) => {
|
|
385
|
+
reject(new Error(`Failed to execute git: ${error.message}`));
|
|
386
|
+
});
|
|
387
|
+
} catch (error) {
|
|
388
|
+
reject(error);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async function cleanupProject(projectPath, sessionId = null) {
|
|
394
|
+
try {
|
|
395
|
+
if (!projectPath.includes('.claude/external-projects')) {
|
|
396
|
+
console.warn('Refusing to clean up non-external project:', projectPath);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
await fs.rm(projectPath, { recursive: true, force: true });
|
|
401
|
+
|
|
402
|
+
if (sessionId) {
|
|
403
|
+
try {
|
|
404
|
+
const sessionPath = path.join(os.homedir(), '.claude', 'sessions', sessionId);
|
|
405
|
+
await fs.rm(sessionPath, { recursive: true, force: true });
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.error('Failed to clean up session directory:', error.message);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
} catch (error) {
|
|
411
|
+
console.error('Failed to clean up project:', error);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export class SSEStreamWriter {
|
|
416
|
+
constructor(res) {
|
|
417
|
+
this.res = res;
|
|
418
|
+
this.sessionId = null;
|
|
419
|
+
this.isSSEStreamWriter = true;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
send(data) {
|
|
423
|
+
if (!this.res.writableEnded) {
|
|
424
|
+
this.res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
end() {
|
|
429
|
+
if (!this.res.writableEnded) {
|
|
430
|
+
this.res.write('data: {"type":"done"}\n\n');
|
|
431
|
+
this.res.end();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
setSessionId(sessionId) {
|
|
436
|
+
this.sessionId = sessionId;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
getSessionId() {
|
|
440
|
+
return this.sessionId;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export class ResponseCollector {
|
|
445
|
+
constructor() {
|
|
446
|
+
this.messages = [];
|
|
447
|
+
this.sessionId = null;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
send(data) {
|
|
451
|
+
this.messages.push(data);
|
|
452
|
+
if (data && typeof data === 'object' && data.sessionId) {
|
|
453
|
+
this.sessionId = data.sessionId;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
end() {}
|
|
458
|
+
|
|
459
|
+
setSessionId(sessionId) {
|
|
460
|
+
this.sessionId = sessionId;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
getSessionId() {
|
|
464
|
+
return this.sessionId;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export class AgentSessionAbortedError extends Error {
|
|
469
|
+
constructor(message = 'Session aborted') {
|
|
470
|
+
super(message);
|
|
471
|
+
this.name = 'AgentSessionAbortedError';
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function extractTerminalErrorMessage(payload) {
|
|
476
|
+
if (!payload || typeof payload !== 'object') {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (typeof payload.error === 'string' && payload.error.trim()) {
|
|
481
|
+
return payload.error.trim();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (payload.error && typeof payload.error.message === 'string' && payload.error.message.trim()) {
|
|
485
|
+
return payload.error.message.trim();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const nestedData = payload.data;
|
|
489
|
+
if (nestedData && typeof nestedData === 'object') {
|
|
490
|
+
if (typeof nestedData.error === 'string' && nestedData.error.trim()) {
|
|
491
|
+
return nestedData.error.trim();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (nestedData.error && typeof nestedData.error.message === 'string' && nestedData.error.message.trim()) {
|
|
495
|
+
return nestedData.error.message.trim();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (typeof nestedData.message === 'string' && nestedData.message.trim()) {
|
|
499
|
+
return nestedData.message.trim();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export class CallbackCaptureWriter {
|
|
507
|
+
constructor() {
|
|
508
|
+
this.sessionId = null;
|
|
509
|
+
this.assistantMessages = [];
|
|
510
|
+
this.tokenSummary = createEmptyTokenSummary();
|
|
511
|
+
this.terminalState = null;
|
|
512
|
+
this.terminalErrorMessage = null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
send(payload) {
|
|
516
|
+
if (!payload || typeof payload !== 'object') {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (typeof payload.sessionId === 'string' && payload.sessionId.trim()) {
|
|
521
|
+
this.sessionId = payload.sessionId.trim();
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (payload.type === 'session-created' && typeof payload.sessionId === 'string' && payload.sessionId.trim()) {
|
|
525
|
+
this.sessionId = payload.sessionId.trim();
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (payload.type === 'token-budget' && payload.data && typeof payload.data === 'object') {
|
|
529
|
+
this.tokenSummary = {
|
|
530
|
+
inputTokens: Number(payload.data.inputTokens) || 0,
|
|
531
|
+
outputTokens: Number(payload.data.outputTokens) || 0,
|
|
532
|
+
cacheReadTokens: Number(payload.data.cacheReadTokens) || 0,
|
|
533
|
+
cacheCreationTokens: Number(payload.data.cacheCreationTokens) || 0,
|
|
534
|
+
totalTokens: Number(payload.data.totalTokens) || 0
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (payload.type === 'claude-response' && payload.data?.type === 'assistant') {
|
|
539
|
+
this.assistantMessages.push(payload.data);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (
|
|
543
|
+
payload.type === 'codex-response' &&
|
|
544
|
+
payload.data?.type === 'item_done' &&
|
|
545
|
+
payload.data?.itemType === 'agent_message' &&
|
|
546
|
+
typeof payload.data?.content === 'string' &&
|
|
547
|
+
payload.data.content.trim()
|
|
548
|
+
) {
|
|
549
|
+
this.assistantMessages.push({
|
|
550
|
+
type: 'assistant',
|
|
551
|
+
message: {
|
|
552
|
+
role: 'assistant',
|
|
553
|
+
content: payload.data.content
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (payload.type === 'session-aborted') {
|
|
559
|
+
this.terminalState = 'aborted';
|
|
560
|
+
this.terminalErrorMessage = 'Session aborted';
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (payload.type === 'claude-complete' || payload.type === 'codex-complete') {
|
|
565
|
+
this.terminalState = 'completed';
|
|
566
|
+
this.terminalErrorMessage = null;
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (
|
|
571
|
+
payload.type === 'claude-error' ||
|
|
572
|
+
payload.type === 'codex-error' ||
|
|
573
|
+
payload.type === 'error' ||
|
|
574
|
+
(payload.type === 'codex-response' && payload.data?.type === 'turn_failed')
|
|
575
|
+
) {
|
|
576
|
+
this.terminalState = 'errored';
|
|
577
|
+
this.terminalErrorMessage = extractTerminalErrorMessage(payload) || this.terminalErrorMessage || 'Agent session failed';
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
end() {}
|
|
582
|
+
|
|
583
|
+
setSessionId(sessionId) {
|
|
584
|
+
if (typeof sessionId === 'string' && sessionId.trim()) {
|
|
585
|
+
this.sessionId = sessionId.trim();
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
getSessionId() {
|
|
590
|
+
return this.sessionId;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
getAssistantMessages() {
|
|
594
|
+
return this.assistantMessages;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
getTotalTokens() {
|
|
598
|
+
return this.tokenSummary;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
getTerminalState() {
|
|
602
|
+
return this.terminalState;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
getTerminalErrorMessage() {
|
|
606
|
+
return this.terminalErrorMessage;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export class TeeWriter {
|
|
611
|
+
constructor(primaryWriter, secondaryWriter) {
|
|
612
|
+
this.primaryWriter = primaryWriter;
|
|
613
|
+
this.secondaryWriter = secondaryWriter;
|
|
614
|
+
this.isSSEStreamWriter = !!primaryWriter?.isSSEStreamWriter;
|
|
615
|
+
this.isWebSocketWriter = !!primaryWriter?.isWebSocketWriter;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
send(payload) {
|
|
619
|
+
this.primaryWriter?.send?.(payload);
|
|
620
|
+
this.secondaryWriter?.send?.(payload);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
end() {
|
|
624
|
+
this.primaryWriter?.end?.();
|
|
625
|
+
this.secondaryWriter?.end?.();
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
setSessionId(sessionId) {
|
|
629
|
+
this.primaryWriter?.setSessionId?.(sessionId);
|
|
630
|
+
this.secondaryWriter?.setSessionId?.(sessionId);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
getSessionId() {
|
|
634
|
+
return this.primaryWriter?.getSessionId?.() || this.secondaryWriter?.getSessionId?.() || null;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
export class NoopWriter {
|
|
639
|
+
send() {}
|
|
640
|
+
|
|
641
|
+
end() {}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
async function runProviderSession({ provider, message, images, finalProjectPath, sessionId, model, writer }) {
|
|
645
|
+
if (provider === 'claude') {
|
|
646
|
+
await queryClaudeSDK(message, {
|
|
647
|
+
projectPath: finalProjectPath,
|
|
648
|
+
cwd: finalProjectPath,
|
|
649
|
+
sessionId,
|
|
650
|
+
model,
|
|
651
|
+
permissionMode: 'bypassPermissions',
|
|
652
|
+
images
|
|
653
|
+
}, writer);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (provider === 'codex') {
|
|
658
|
+
await queryCodex(message, {
|
|
659
|
+
projectPath: finalProjectPath,
|
|
660
|
+
cwd: finalProjectPath,
|
|
661
|
+
sessionId,
|
|
662
|
+
model: model || CODEX_MODELS.DEFAULT,
|
|
663
|
+
permissionMode: 'bypassPermissions',
|
|
664
|
+
images
|
|
665
|
+
}, writer);
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (provider === 'gemini') {
|
|
670
|
+
await queryGemini(message, {
|
|
671
|
+
projectPath: finalProjectPath,
|
|
672
|
+
cwd: finalProjectPath,
|
|
673
|
+
sessionId,
|
|
674
|
+
resume: !!sessionId,
|
|
675
|
+
model: model || GEMINI_MODELS.DEFAULT,
|
|
676
|
+
permissionMode: 'bypassPermissions'
|
|
677
|
+
}, writer);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (provider === 'opencode') {
|
|
682
|
+
await queryOpencode(message, {
|
|
683
|
+
projectPath: finalProjectPath,
|
|
684
|
+
cwd: finalProjectPath,
|
|
685
|
+
sessionId,
|
|
686
|
+
resume: !!sessionId,
|
|
687
|
+
model: model || OPENCODE_MODELS.DEFAULT,
|
|
688
|
+
permissionMode: 'bypassPermissions'
|
|
689
|
+
}, writer);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
async function maybeCreateBranchAndPR({
|
|
694
|
+
user,
|
|
695
|
+
githubToken,
|
|
696
|
+
githubUrl,
|
|
697
|
+
finalProjectPath,
|
|
698
|
+
branchName,
|
|
699
|
+
message,
|
|
700
|
+
createBranch,
|
|
701
|
+
createPR,
|
|
702
|
+
transportWriter
|
|
703
|
+
}) {
|
|
704
|
+
let branchInfo = null;
|
|
705
|
+
let prInfo = null;
|
|
706
|
+
|
|
707
|
+
if (!createBranch && !createPR) {
|
|
708
|
+
return { branchInfo, prInfo };
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
try {
|
|
712
|
+
const tokenToUse = githubToken || githubTokensDb.getActiveGithubToken(user?.id);
|
|
713
|
+
if (!tokenToUse) {
|
|
714
|
+
throw new Error('GitHub token required for branch/PR creation. Please configure a GitHub token in settings.');
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const octokit = new Octokit({ auth: tokenToUse });
|
|
718
|
+
let repoUrl = githubUrl;
|
|
719
|
+
|
|
720
|
+
if (!repoUrl) {
|
|
721
|
+
repoUrl = await getGitRemoteUrl(finalProjectPath);
|
|
722
|
+
if (!repoUrl.includes('github.com')) {
|
|
723
|
+
throw new Error('Project does not have a GitHub remote configured');
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const { owner, repo } = parseGitHubUrl(repoUrl);
|
|
728
|
+
const finalBranchName = branchName || autogenerateBranchName(message);
|
|
729
|
+
|
|
730
|
+
if (branchName) {
|
|
731
|
+
const validation = validateBranchName(finalBranchName);
|
|
732
|
+
if (!validation.valid) {
|
|
733
|
+
throw new Error(`Invalid branch name: ${validation.error}`);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (createBranch) {
|
|
738
|
+
await new Promise((resolve, reject) => {
|
|
739
|
+
const checkoutProcess = spawn('git', ['checkout', '-b', finalBranchName], {
|
|
740
|
+
cwd: finalProjectPath,
|
|
741
|
+
stdio: 'pipe'
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
let stderr = '';
|
|
745
|
+
checkoutProcess.stderr.on('data', (data) => {
|
|
746
|
+
stderr += data.toString();
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
checkoutProcess.on('close', (code) => {
|
|
750
|
+
if (code === 0) {
|
|
751
|
+
resolve();
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (stderr.includes('already exists')) {
|
|
756
|
+
const checkoutExisting = spawn('git', ['checkout', finalBranchName], {
|
|
757
|
+
cwd: finalProjectPath,
|
|
758
|
+
stdio: 'pipe'
|
|
759
|
+
});
|
|
760
|
+
checkoutExisting.on('close', (checkoutCode) => {
|
|
761
|
+
if (checkoutCode === 0) {
|
|
762
|
+
resolve();
|
|
763
|
+
} else {
|
|
764
|
+
reject(new Error(`Failed to checkout existing branch: ${stderr}`));
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
reject(new Error(`Failed to create branch: ${stderr}`));
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
await new Promise((resolve, reject) => {
|
|
775
|
+
const pushProcess = spawn('git', ['push', '-u', 'origin', finalBranchName], {
|
|
776
|
+
cwd: finalProjectPath,
|
|
777
|
+
stdio: 'pipe'
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
let stderr = '';
|
|
781
|
+
pushProcess.stderr.on('data', (data) => {
|
|
782
|
+
stderr += data.toString();
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
pushProcess.on('close', (code) => {
|
|
786
|
+
if (code === 0 || stderr.includes('already exists') || stderr.includes('up-to-date')) {
|
|
787
|
+
resolve();
|
|
788
|
+
} else {
|
|
789
|
+
reject(new Error(`Failed to push branch: ${stderr}`));
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
branchInfo = {
|
|
795
|
+
name: finalBranchName,
|
|
796
|
+
url: `https://github.com/${owner}/${repo}/tree/${finalBranchName}`
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
if (createPR) {
|
|
801
|
+
const commitMessages = await getCommitMessages(finalProjectPath, 5);
|
|
802
|
+
const prTitle = commitMessages.length > 0 ? commitMessages[0] : message;
|
|
803
|
+
let prBody = '## Changes\n\n';
|
|
804
|
+
if (commitMessages.length > 0) {
|
|
805
|
+
prBody += commitMessages.map((msg) => `- ${msg}`).join('\n');
|
|
806
|
+
} else {
|
|
807
|
+
prBody += `Agent task: ${message}`;
|
|
808
|
+
}
|
|
809
|
+
prBody += '\n\n---\n*This pull request was automatically created by Axhub Genie Agent.*';
|
|
810
|
+
|
|
811
|
+
prInfo = await createGitHubPR(octokit, owner, repo, finalBranchName, prTitle, prBody, 'main');
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
if (branchInfo) {
|
|
815
|
+
transportWriter?.send?.({
|
|
816
|
+
type: 'github-branch',
|
|
817
|
+
branch: branchInfo
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
if (prInfo) {
|
|
822
|
+
transportWriter?.send?.({
|
|
823
|
+
type: 'github-pr',
|
|
824
|
+
pullRequest: prInfo
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
} catch (error) {
|
|
828
|
+
transportWriter?.send?.({
|
|
829
|
+
type: 'github-error',
|
|
830
|
+
error: error.message
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
branchInfo = { error: error.message };
|
|
834
|
+
prInfo = { error: error.message };
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
return { branchInfo, prInfo };
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
export async function runExternalAgentRequest({
|
|
841
|
+
user,
|
|
842
|
+
request,
|
|
843
|
+
transportWriter,
|
|
844
|
+
endTransportOnFinish = false
|
|
845
|
+
}) {
|
|
846
|
+
const normalized = request?.normalizedMessage !== undefined
|
|
847
|
+
? request
|
|
848
|
+
: normalizeExternalAgentRunRequest(request);
|
|
849
|
+
const startedAt = new Date().toISOString();
|
|
850
|
+
|
|
851
|
+
if (normalized.isOpenOnly) {
|
|
852
|
+
const response = {
|
|
853
|
+
success: true,
|
|
854
|
+
openOnly: true,
|
|
855
|
+
sessionId: normalized.normalizedSessionId,
|
|
856
|
+
...buildSessionNavigation(normalized.normalizedSessionId),
|
|
857
|
+
isResumed: true,
|
|
858
|
+
message: 'Session link generated. No model call triggered.'
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
transportWriter?.send?.({
|
|
862
|
+
type: 'open-only',
|
|
863
|
+
...response
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
if (endTransportOnFinish) {
|
|
867
|
+
transportWriter?.end?.();
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
return response;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
let finalProjectPath = null;
|
|
874
|
+
let branchInfo = null;
|
|
875
|
+
let prInfo = null;
|
|
876
|
+
const callbackCaptureWriter = new CallbackCaptureWriter();
|
|
877
|
+
const writer = new TeeWriter(transportWriter, callbackCaptureWriter);
|
|
878
|
+
let callbackSessionId = normalized.normalizedSessionId;
|
|
879
|
+
let callbackResult = null;
|
|
880
|
+
|
|
881
|
+
try {
|
|
882
|
+
if (normalized.githubUrl) {
|
|
883
|
+
const tokenToUse = normalized.githubToken || githubTokensDb.getActiveGithubToken(user?.id);
|
|
884
|
+
let targetPath = normalized.projectPath;
|
|
885
|
+
if (!targetPath) {
|
|
886
|
+
const repoHash = crypto.createHash('md5').update(normalized.githubUrl + Date.now()).digest('hex');
|
|
887
|
+
targetPath = path.join(os.homedir(), '.claude', 'external-projects', repoHash);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
finalProjectPath = await cloneGitHubRepo(normalized.githubUrl.trim(), tokenToUse, targetPath);
|
|
891
|
+
} else {
|
|
892
|
+
finalProjectPath = resolveWorkingDirectory({ projectPath: normalized.projectPath });
|
|
893
|
+
try {
|
|
894
|
+
await fs.access(finalProjectPath);
|
|
895
|
+
} catch {
|
|
896
|
+
throw new Error(`Project path does not exist: ${finalProjectPath}`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
try {
|
|
901
|
+
await addProjectManually(finalProjectPath);
|
|
902
|
+
} catch (error) {
|
|
903
|
+
if (!(error.message && error.message.includes('Project already configured'))) {
|
|
904
|
+
throw error;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
const statusMessage = normalized.normalizedSessionId
|
|
909
|
+
? (normalized.githubUrl ? 'Repository cloned and session resumed' : 'Session resumed')
|
|
910
|
+
: (normalized.githubUrl ? 'Repository cloned and session started' : 'Session started');
|
|
911
|
+
|
|
912
|
+
transportWriter?.send?.({
|
|
913
|
+
type: 'status',
|
|
914
|
+
message: statusMessage,
|
|
915
|
+
projectPath: finalProjectPath
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
await runProviderSession({
|
|
919
|
+
provider: normalized.provider,
|
|
920
|
+
message: normalized.normalizedMessage,
|
|
921
|
+
images: normalized.images,
|
|
922
|
+
finalProjectPath,
|
|
923
|
+
sessionId: normalized.normalizedSessionId,
|
|
924
|
+
model: normalized.model,
|
|
925
|
+
writer
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
callbackSessionId = writer.getSessionId() || callbackCaptureWriter.getSessionId() || normalized.normalizedSessionId;
|
|
929
|
+
const terminalState = callbackCaptureWriter.getTerminalState();
|
|
930
|
+
|
|
931
|
+
if (terminalState === 'errored') {
|
|
932
|
+
throw new Error(callbackCaptureWriter.getTerminalErrorMessage() || `${normalized.provider} session failed`);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (terminalState !== 'completed') {
|
|
936
|
+
throw new AgentSessionAbortedError();
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
({ branchInfo, prInfo } = await maybeCreateBranchAndPR({
|
|
940
|
+
user,
|
|
941
|
+
githubToken: normalized.githubToken,
|
|
942
|
+
githubUrl: normalized.githubUrl,
|
|
943
|
+
finalProjectPath,
|
|
944
|
+
branchName: normalized.branchName,
|
|
945
|
+
message: normalized.message,
|
|
946
|
+
createBranch: normalized.createBranch,
|
|
947
|
+
createPR: normalized.createPR,
|
|
948
|
+
transportWriter
|
|
949
|
+
}));
|
|
950
|
+
|
|
951
|
+
callbackSessionId = writer.getSessionId() || callbackCaptureWriter.getSessionId() || normalized.normalizedSessionId;
|
|
952
|
+
const navigation = buildSessionNavigation(callbackSessionId);
|
|
953
|
+
const response = {
|
|
954
|
+
success: true,
|
|
955
|
+
sessionId: callbackSessionId,
|
|
956
|
+
...navigation,
|
|
957
|
+
isResumed: !!normalized.normalizedSessionId,
|
|
958
|
+
messages: callbackCaptureWriter.getAssistantMessages(),
|
|
959
|
+
tokens: callbackCaptureWriter.getTotalTokens(),
|
|
960
|
+
projectPath: finalProjectPath
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
if (branchInfo) {
|
|
964
|
+
response.branch = branchInfo;
|
|
965
|
+
}
|
|
966
|
+
if (prInfo) {
|
|
967
|
+
response.pullRequest = prInfo;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
callbackResult = {
|
|
971
|
+
sessionPath: navigation.sessionPath,
|
|
972
|
+
sessionUrl: navigation.sessionUrl,
|
|
973
|
+
messages: response.messages,
|
|
974
|
+
tokens: response.tokens,
|
|
975
|
+
branch: branchInfo,
|
|
976
|
+
pullRequest: prInfo
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
if (normalized.callbackConfig && shouldDeliverAgentCallback(normalized.callbackConfig, 'completed')) {
|
|
980
|
+
const payload = buildAgentCallbackPayload({
|
|
981
|
+
event: 'completed',
|
|
982
|
+
eventId: createAgentCallbackEventId(),
|
|
983
|
+
sessionId: callbackSessionId,
|
|
984
|
+
provider: normalized.provider,
|
|
985
|
+
projectPath: finalProjectPath,
|
|
986
|
+
isResumed: !!normalized.normalizedSessionId,
|
|
987
|
+
startedAt,
|
|
988
|
+
finishedAt: new Date().toISOString(),
|
|
989
|
+
result: callbackResult
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
void scheduleAgentCallbackDelivery({
|
|
993
|
+
callback: normalized.callbackConfig,
|
|
994
|
+
payload
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
if (normalized.cleanup && normalized.githubUrl) {
|
|
999
|
+
const sessionIdForCleanup = writer.getSessionId();
|
|
1000
|
+
setTimeout(() => {
|
|
1001
|
+
cleanupProject(finalProjectPath, sessionIdForCleanup);
|
|
1002
|
+
}, 5000);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
if (endTransportOnFinish) {
|
|
1006
|
+
transportWriter?.end?.();
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
return response;
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
callbackSessionId = writer.getSessionId() || callbackCaptureWriter.getSessionId() || normalized.normalizedSessionId;
|
|
1012
|
+
callbackResult = {
|
|
1013
|
+
...buildSessionNavigation(callbackSessionId),
|
|
1014
|
+
messages: callbackCaptureWriter.getAssistantMessages(),
|
|
1015
|
+
tokens: callbackCaptureWriter.getTotalTokens(),
|
|
1016
|
+
branch: branchInfo,
|
|
1017
|
+
pullRequest: prInfo
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
if (finalProjectPath && normalized.cleanup && normalized.githubUrl) {
|
|
1021
|
+
const sessionIdForCleanup = writer.getSessionId();
|
|
1022
|
+
await cleanupProject(finalProjectPath, sessionIdForCleanup);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
const terminalEvent = error instanceof AgentSessionAbortedError ? 'aborted' : 'errored';
|
|
1026
|
+
if (normalized.callbackConfig && shouldDeliverAgentCallback(normalized.callbackConfig, terminalEvent)) {
|
|
1027
|
+
const callbackError = terminalEvent === 'aborted'
|
|
1028
|
+
? { message: 'Session aborted' }
|
|
1029
|
+
: { message: error.message };
|
|
1030
|
+
|
|
1031
|
+
const payload = buildAgentCallbackPayload({
|
|
1032
|
+
event: terminalEvent,
|
|
1033
|
+
eventId: createAgentCallbackEventId(),
|
|
1034
|
+
sessionId: callbackSessionId,
|
|
1035
|
+
provider: normalized.provider,
|
|
1036
|
+
projectPath: finalProjectPath,
|
|
1037
|
+
isResumed: !!normalized.normalizedSessionId,
|
|
1038
|
+
startedAt,
|
|
1039
|
+
finishedAt: new Date().toISOString(),
|
|
1040
|
+
result: callbackResult,
|
|
1041
|
+
error: callbackError
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
void scheduleAgentCallbackDelivery({
|
|
1045
|
+
callback: normalized.callbackConfig,
|
|
1046
|
+
payload
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
throw error;
|
|
1051
|
+
}
|
|
1052
|
+
}
|