@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.
Files changed (408) hide show
  1. package/README.md +1 -1
  2. package/dist/api-docs.html +6 -6
  3. package/dist/assets/App-BfaNALgf.js +504 -0
  4. package/dist/assets/App-qxJ8_QYu.css +32 -0
  5. package/dist/assets/ReviewApp-DIT2yWk-.js +1 -0
  6. package/dist/assets/_basePickBy-Dz3NcIVK.js +1 -0
  7. package/dist/assets/_baseUniq-DON_Sg7x.js +1 -0
  8. package/dist/assets/abap-BdImnpbu.js +1 -0
  9. package/dist/assets/actionscript-3-CoDkCxhg.js +1 -0
  10. package/dist/assets/ada-bCR0ucgS.js +1 -0
  11. package/dist/assets/andromeeda-C4gqWexZ.js +1 -0
  12. package/dist/assets/angular-html-CU67Zn6k.js +1 -0
  13. package/dist/assets/angular-ts-BwZT4LLn.js +1 -0
  14. package/dist/assets/apache-Pmp26Uib.js +1 -0
  15. package/dist/assets/apex-D8_7TLub.js +1 -0
  16. package/dist/assets/apl-dKokRX4l.js +1 -0
  17. package/dist/assets/applescript-Co6uUVPk.js +1 -0
  18. package/dist/assets/ara-BRHolxvo.js +1 -0
  19. package/dist/assets/arc-Y4G80q-l.js +1 -0
  20. package/dist/assets/architectureDiagram-2XIMDMQ5-D_qR4657.js +36 -0
  21. package/dist/assets/asciidoc-Ve4PFQV2.js +1 -0
  22. package/dist/assets/asm-D_Q5rh1f.js +1 -0
  23. package/dist/assets/astro-CbQHKStN.js +1 -0
  24. package/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
  25. package/dist/assets/awk-DMzUqQB5.js +1 -0
  26. package/dist/assets/ayu-dark-DYE7WIF3.js +1 -0
  27. package/dist/assets/ayu-light-BA47KaF1.js +1 -0
  28. package/dist/assets/ayu-mirage-32ctXXKs.js +1 -0
  29. package/dist/assets/ballerina-BFfxhgS-.js +1 -0
  30. package/dist/assets/bat-BkioyH1T.js +1 -0
  31. package/dist/assets/beancount-k_qm7-4y.js +1 -0
  32. package/dist/assets/berry-uYugtg8r.js +1 -0
  33. package/dist/assets/bibtex-CHM0blh-.js +1 -0
  34. package/dist/assets/bicep-Bmn6On1c.js +1 -0
  35. package/dist/assets/bird2-DPOp833l.js +1 -0
  36. package/dist/assets/blade-D4QpJJKB.js +1 -0
  37. package/dist/assets/blockDiagram-WCTKOSBZ-NsmAlV5_.js +132 -0
  38. package/dist/assets/bsl-BO_Y6i37.js +1 -0
  39. package/dist/assets/c-BIGW1oBm.js +1 -0
  40. package/dist/assets/c3-eo99z4R2.js +1 -0
  41. package/dist/assets/c4Diagram-IC4MRINW-cbOJM4yr.js +10 -0
  42. package/dist/assets/cadence-Bv_4Rxtq.js +1 -0
  43. package/dist/assets/cairo-KRGpt6FW.js +1 -0
  44. package/dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  45. package/dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  46. package/dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  47. package/dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  48. package/dist/assets/channel-C6KNnXlA.js +1 -0
  49. package/dist/assets/chunk-4BX2VUAB-bLBhl74J.js +1 -0
  50. package/dist/assets/chunk-55IACEB6-D8kNkDUO.js +1 -0
  51. package/dist/assets/chunk-FMBD7UC4-BjR6UbXB.js +15 -0
  52. package/dist/assets/chunk-JSJVCQXG-luNqWn64.js +1 -0
  53. package/dist/assets/chunk-KX2RTZJC-CNnKm6dK.js +1 -0
  54. package/dist/assets/chunk-NQ4KR5QH-Cp9gb43u.js +220 -0
  55. package/dist/assets/chunk-QZHKN3VN-HlVYo2Oq.js +1 -0
  56. package/dist/assets/chunk-WL4C6EOR-CjSZoOGO.js +189 -0
  57. package/dist/assets/clarity-D53aC0YG.js +1 -0
  58. package/dist/assets/classDiagram-VBA2DB6C-BQlzzlH7.js +1 -0
  59. package/dist/assets/classDiagram-v2-RAHNMMFH-BQlzzlH7.js +1 -0
  60. package/dist/assets/clojure-P80f7IUj.js +1 -0
  61. package/dist/assets/clone-DMxS3qWP.js +1 -0
  62. package/dist/assets/cmake-D1j8_8rp.js +1 -0
  63. package/dist/assets/cobol-nwyudZeR.js +1 -0
  64. package/dist/assets/codeowners-Bp6g37R7.js +1 -0
  65. package/dist/assets/codeql-DsOJ9woJ.js +1 -0
  66. package/dist/assets/coffee-Ch7k5sss.js +1 -0
  67. package/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
  68. package/dist/assets/coq-DkFqJrB1.js +1 -0
  69. package/dist/assets/cose-bilkent-S5V4N54A-DZWRjeEd.js +1 -0
  70. package/dist/assets/cpp-CofmeUqb.js +1 -0
  71. package/dist/assets/crystal-tKQVLTB8.js +1 -0
  72. package/dist/assets/csharp-COcwbKMJ.js +1 -0
  73. package/dist/assets/css-DPfMkruS.js +1 -0
  74. package/dist/assets/csv-fuZLfV_i.js +1 -0
  75. package/dist/assets/cue-D82EKSYY.js +1 -0
  76. package/dist/assets/cypher-COkxafJQ.js +1 -0
  77. package/dist/assets/cytoscape.esm-2ZfV8NB5.js +331 -0
  78. package/dist/assets/d-85-TOEBH.js +1 -0
  79. package/dist/assets/dagre-KLK3FWXG-yAzUmqI7.js +4 -0
  80. package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  81. package/dist/assets/dart-CF10PKvl.js +1 -0
  82. package/dist/assets/dax-CEL-wOlO.js +1 -0
  83. package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  84. package/dist/assets/desktop-BmXAJ9_W.js +1 -0
  85. package/dist/assets/diagram-E7M64L7V-CvzlIvDJ.js +24 -0
  86. package/dist/assets/diagram-IFDJBPK2-DFMIJpuM.js +43 -0
  87. package/dist/assets/diagram-P4PSJMXO-KL-J3gyb.js +24 -0
  88. package/dist/assets/diff-D97Zzqfu.js +1 -0
  89. package/dist/assets/docker-BcOcwvcX.js +1 -0
  90. package/dist/assets/dotenv-Da5cRb03.js +1 -0
  91. package/dist/assets/dracula-BzJJZx-M.js +1 -0
  92. package/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
  93. package/dist/assets/dream-maker-BtqSS_iP.js +1 -0
  94. package/dist/assets/edge-BkV0erSs.js +1 -0
  95. package/dist/assets/elixir-CDX3lj18.js +1 -0
  96. package/dist/assets/elm-DbKCFpqz.js +1 -0
  97. package/dist/assets/emacs-lisp-C9XAeP06.js +1 -0
  98. package/dist/assets/erDiagram-INFDFZHY-BXszHbTM.js +70 -0
  99. package/dist/assets/erb-B12qg9BL.js +1 -0
  100. package/dist/assets/erlang-DsQrWhSR.js +1 -0
  101. package/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
  102. package/dist/assets/everforest-light-C8M2exoo.js +1 -0
  103. package/dist/assets/fennel-BYunw83y.js +1 -0
  104. package/dist/assets/fish-BvzEVeQv.js +1 -0
  105. package/dist/assets/flowDiagram-PKNHOUZH-Ba43NVp6.js +162 -0
  106. package/dist/assets/fluent-C4IJs8-o.js +1 -0
  107. package/dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  108. package/dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
  109. package/dist/assets/fsharp-CXgrBDvD.js +1 -0
  110. package/dist/assets/ganttDiagram-A5KZAMGK-uLHfhCrg.js +292 -0
  111. package/dist/assets/gdresource-BOOCDP_w.js +1 -0
  112. package/dist/assets/gdscript-C5YyOfLZ.js +1 -0
  113. package/dist/assets/gdshader-DkwncUOv.js +1 -0
  114. package/dist/assets/genie-D0YGMca9.js +1 -0
  115. package/dist/assets/gherkin-DyxjwDmM.js +1 -0
  116. package/dist/assets/git-commit-F4YmCXRG.js +1 -0
  117. package/dist/assets/git-rebase-r7XF79zn.js +1 -0
  118. package/dist/assets/gitGraphDiagram-K3NZZRJ6-BTEuFaiL.js +65 -0
  119. package/dist/assets/github-dark-DHJKELXO.js +1 -0
  120. package/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
  121. package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  122. package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  123. package/dist/assets/github-light-DAi9KRSo.js +1 -0
  124. package/dist/assets/github-light-default-D7oLnXFd.js +1 -0
  125. package/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  126. package/dist/assets/gleam-BspZqrRM.js +1 -0
  127. package/dist/assets/glimmer-js-Rg0-pVw9.js +1 -0
  128. package/dist/assets/glimmer-ts-U6CK756n.js +1 -0
  129. package/dist/assets/glsl-DplSGwfg.js +1 -0
  130. package/dist/assets/gn-n2N0HUVH.js +1 -0
  131. package/dist/assets/gnuplot-DdkO51Og.js +1 -0
  132. package/dist/assets/go-CxLEBnE3.js +1 -0
  133. package/dist/assets/graph-h2nuWjx4.js +1 -0
  134. package/dist/assets/graphql-ChdNCCLP.js +1 -0
  135. package/dist/assets/groovy-gcz8RCvz.js +1 -0
  136. package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  137. package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  138. package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  139. package/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  140. package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  141. package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  142. package/dist/assets/hack-CaT9iCJl.js +1 -0
  143. package/dist/assets/haml-B8DHNrY2.js +1 -0
  144. package/dist/assets/handlebars-BL8al0AC.js +1 -0
  145. package/dist/assets/haskell-Df6bDoY_.js +1 -0
  146. package/dist/assets/haxe-CzTSHFRz.js +1 -0
  147. package/dist/assets/hcl-BWvSN4gD.js +1 -0
  148. package/dist/assets/highlighted-body-TPN3WLV5-C6BY7XZJ.js +1 -0
  149. package/dist/assets/hjson-D5-asLiD.js +1 -0
  150. package/dist/assets/hlsl-D3lLCCz7.js +1 -0
  151. package/dist/assets/horizon-BUw7H-hv.js +1 -0
  152. package/dist/assets/horizon-bright-Cn-bp-IR.js +1 -0
  153. package/dist/assets/houston-DnULxvSX.js +1 -0
  154. package/dist/assets/html-GMplVEZG.js +1 -0
  155. package/dist/assets/html-derivative-BFtXZ54Q.js +1 -0
  156. package/dist/assets/http-jrhK8wxY.js +1 -0
  157. package/dist/assets/hurl-irOxFIW8.js +1 -0
  158. package/dist/assets/hxml-Bvhsp5Yf.js +1 -0
  159. package/dist/assets/hy-DFXneXwc.js +1 -0
  160. package/dist/assets/imba-DGztddWO.js +1 -0
  161. package/dist/assets/index-2198VgsK.css +1 -0
  162. package/dist/assets/index-C6Bb2jGF.js +2 -0
  163. package/dist/assets/infoDiagram-LFFYTUFH-BOLfvCIq.js +2 -0
  164. package/dist/assets/ini-BEwlwnbL.js +1 -0
  165. package/dist/assets/init-Gi6I4Gst.js +1 -0
  166. package/dist/assets/ishikawaDiagram-PHBUUO56-BRzQ1ee5.js +70 -0
  167. package/dist/assets/java-CylS5w8V.js +1 -0
  168. package/dist/assets/javascript-wDzz0qaB.js +1 -0
  169. package/dist/assets/jinja-4LBKfQ-Z.js +1 -0
  170. package/dist/assets/jison-wvAkD_A8.js +1 -0
  171. package/dist/assets/journeyDiagram-4ABVD52K-DXm_VcMy.js +139 -0
  172. package/dist/assets/json-Cp-IABpG.js +1 -0
  173. package/dist/assets/json5-C9tS-k6U.js +1 -0
  174. package/dist/assets/jsonc-Des-eS-w.js +1 -0
  175. package/dist/assets/jsonl-DcaNXYhu.js +1 -0
  176. package/dist/assets/jsonnet-DFQXde-d.js +1 -0
  177. package/dist/assets/jssm-C2t-YnRu.js +1 -0
  178. package/dist/assets/jsx-g9-lgVsj.js +1 -0
  179. package/dist/assets/julia-CxzCAyBv.js +1 -0
  180. package/dist/assets/just-Cw27pwNe.js +1 -0
  181. package/dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  182. package/dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  183. package/dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
  184. package/dist/assets/kanban-definition-K7BYSVSG-D_oyzopl.js +89 -0
  185. package/dist/assets/kdl-DV7GczEv.js +1 -0
  186. package/dist/assets/kotlin-BdnUsdx6.js +1 -0
  187. package/dist/assets/kusto-DZf3V79B.js +1 -0
  188. package/dist/assets/laserwave-DUszq2jm.js +1 -0
  189. package/dist/assets/latex-CWtU0Tv5.js +1 -0
  190. package/dist/assets/layout-Q8YoR_E1.js +1 -0
  191. package/dist/assets/lean-BZvkOJ9d.js +1 -0
  192. package/dist/assets/less-B1dDrJ26.js +1 -0
  193. package/dist/assets/light-plus-B7mTdjB0.js +1 -0
  194. package/dist/assets/linear-B3qNg7di.js +1 -0
  195. package/dist/assets/liquid-DYVedYrR.js +1 -0
  196. package/dist/assets/llvm-DjAJT7YJ.js +1 -0
  197. package/dist/assets/log-2UxHyX5q.js +1 -0
  198. package/dist/assets/logo-BtOb2qkB.js +1 -0
  199. package/dist/assets/lua-BaeVxFsk.js +1 -0
  200. package/dist/assets/luau-C-HG3fhB.js +1 -0
  201. package/dist/assets/make-CHLpvVh8.js +1 -0
  202. package/dist/assets/markdown-Cvjx9yec.js +1 -0
  203. package/dist/assets/marko-CnJfTvn9.js +1 -0
  204. package/dist/assets/material-theme-D5KoaKCx.js +1 -0
  205. package/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
  206. package/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  207. package/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
  208. package/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  209. package/dist/assets/matlab-D7o27uSR.js +1 -0
  210. package/dist/assets/mdc-BMNejdWA.js +1 -0
  211. package/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  212. package/dist/assets/mermaid-O7DHMXV3-BVZ_4MKo.js +988 -0
  213. package/dist/assets/mermaid-mWjccvbQ.js +1 -0
  214. package/dist/assets/min-dark-CafNBF8u.js +1 -0
  215. package/dist/assets/min-light-CTRr51gU.js +1 -0
  216. package/dist/assets/mindmap-definition-YRQLILUH-CjulgYdi.js +68 -0
  217. package/dist/assets/mipsasm-CKIfxQSi.js +1 -0
  218. package/dist/assets/mojo-rZm6bMo-.js +1 -0
  219. package/dist/assets/monokai-D4h5O-jR.js +1 -0
  220. package/dist/assets/moonbit-_H4v1dQx.js +1 -0
  221. package/dist/assets/move-IF9eRakj.js +1 -0
  222. package/dist/assets/narrat-DRg8JJMk.js +1 -0
  223. package/dist/assets/nextflow-Zz6hmt5N.js +1 -0
  224. package/dist/assets/nextflow-groovy-BeH2EWoN.js +1 -0
  225. package/dist/assets/nginx-BpAMiNFr.js +1 -0
  226. package/dist/assets/night-owl-C39BiMTA.js +1 -0
  227. package/dist/assets/night-owl-light-CMTm3GFP.js +1 -0
  228. package/dist/assets/nim-CVrawwO9.js +1 -0
  229. package/dist/assets/nix-CwoSXNpI.js +1 -0
  230. package/dist/assets/nord-Ddv68eIx.js +1 -0
  231. package/dist/assets/nushell-Cz2AlsmD.js +1 -0
  232. package/dist/assets/objective-c-DXmwc3jG.js +1 -0
  233. package/dist/assets/objective-cpp-CLxacb5B.js +1 -0
  234. package/dist/assets/ocaml-C0hk2d4L.js +1 -0
  235. package/dist/assets/odin-BBf5iR-q.js +1 -0
  236. package/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  237. package/dist/assets/one-light-C3Wv6jpd.js +1 -0
  238. package/dist/assets/openscad-C4EeE6gA.js +1 -0
  239. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  240. package/dist/assets/pascal-D93ZcfNL.js +1 -0
  241. package/dist/assets/perl-C0TMdlhV.js +1 -0
  242. package/dist/assets/php-Dhbhpdrm.js +1 -0
  243. package/dist/assets/pieDiagram-SKSYHLDU-8VzrefxA.js +30 -0
  244. package/dist/assets/pkl-u5AG7uiY.js +1 -0
  245. package/dist/assets/plastic-3e1v2bzS.js +1 -0
  246. package/dist/assets/plsql-ChMvpjG-.js +1 -0
  247. package/dist/assets/po-BTJTHyun.js +1 -0
  248. package/dist/assets/poimandres-CS3Unz2-.js +1 -0
  249. package/dist/assets/polar-C0HS_06l.js +1 -0
  250. package/dist/assets/postcss-CXtECtnM.js +1 -0
  251. package/dist/assets/powerquery-CEu0bR-o.js +1 -0
  252. package/dist/assets/powershell-Dpen1YoG.js +1 -0
  253. package/dist/assets/prisma-Dd19v3D-.js +1 -0
  254. package/dist/assets/prolog-CbFg5uaA.js +1 -0
  255. package/dist/assets/proto-C7zT0LnQ.js +1 -0
  256. package/dist/assets/pug-CGlum2m_.js +1 -0
  257. package/dist/assets/puppet-BMWR74SV.js +1 -0
  258. package/dist/assets/purescript-CklMAg4u.js +1 -0
  259. package/dist/assets/python-B6aJPvgy.js +1 -0
  260. package/dist/assets/qml-3beO22l8.js +1 -0
  261. package/dist/assets/qmldir-C8lEn-DE.js +1 -0
  262. package/dist/assets/qss-IeuSbFQv.js +1 -0
  263. package/dist/assets/quadrantDiagram-337W2JSQ-CFh-ijm2.js +7 -0
  264. package/dist/assets/r-Dspwwk_N.js +1 -0
  265. package/dist/assets/racket-BqYA7rlc.js +1 -0
  266. package/dist/assets/raku-DXvB9xmW.js +1 -0
  267. package/dist/assets/razor-Uh8Bk_45.js +1 -0
  268. package/dist/assets/red-bN70gL4F.js +1 -0
  269. package/dist/assets/reg-C-SQnVFl.js +1 -0
  270. package/dist/assets/regexp-CDVJQ6XC.js +1 -0
  271. package/dist/assets/rel-C3B-1QV4.js +1 -0
  272. package/dist/assets/requirementDiagram-Z7DCOOCP-BNPlTs5Q.js +73 -0
  273. package/dist/assets/riscv-BM1_JUlF.js +1 -0
  274. package/dist/assets/ron-D8l8udqQ.js +1 -0
  275. package/dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  276. package/dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  277. package/dist/assets/rose-pine-qdsjHGoJ.js +1 -0
  278. package/dist/assets/rosmsg-BJDFO7_C.js +1 -0
  279. package/dist/assets/rst-BrH8l1NY.js +1 -0
  280. package/dist/assets/ruby-Dw2BHqvy.js +1 -0
  281. package/dist/assets/rust-B1yitclQ.js +1 -0
  282. package/dist/assets/sankeyDiagram-WA2Y5GQK-C5l_hYst.js +10 -0
  283. package/dist/assets/sas-cz2c8ADy.js +1 -0
  284. package/dist/assets/sass-Cj5Yp3dK.js +1 -0
  285. package/dist/assets/scala-C151Ov-r.js +1 -0
  286. package/dist/assets/scheme-C98Dy4si.js +1 -0
  287. package/dist/assets/scss-OYdSNvt2.js +1 -0
  288. package/dist/assets/sdbl-DVxCFoDh.js +1 -0
  289. package/dist/assets/sequenceDiagram-2WXFIKYE-B4a_rQw8.js +145 -0
  290. package/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
  291. package/dist/assets/shellscript-Yzrsuije.js +1 -0
  292. package/dist/assets/shellsession-BADoaaVG.js +1 -0
  293. package/dist/assets/slack-dark-BthQWCQV.js +1 -0
  294. package/dist/assets/slack-ochin-DqwNpetd.js +1 -0
  295. package/dist/assets/smalltalk-BERRCDM3.js +1 -0
  296. package/dist/assets/snazzy-light-Bw305WKR.js +1 -0
  297. package/dist/assets/solarized-dark-DXbdFlpD.js +1 -0
  298. package/dist/assets/solarized-light-L9t79GZl.js +1 -0
  299. package/dist/assets/solidity-rGO070M0.js +1 -0
  300. package/dist/assets/soy-Brmx7dQM.js +1 -0
  301. package/dist/assets/sparql-rVzFXLq3.js +1 -0
  302. package/dist/assets/splunk-BtCnVYZw.js +1 -0
  303. package/dist/assets/sql-BLtJtn59.js +1 -0
  304. package/dist/assets/ssh-config-_ykCGR6B.js +1 -0
  305. package/dist/assets/stata-BH5u7GGu.js +1 -0
  306. package/dist/assets/stateDiagram-RAJIS63D-Bt4mMmKB.js +1 -0
  307. package/dist/assets/stateDiagram-v2-FVOUBMTO-6NYMazfq.js +1 -0
  308. package/dist/assets/stylus-BEDo0Tqx.js +1 -0
  309. package/dist/assets/surrealql-Bq5Q-fJD.js +1 -0
  310. package/dist/assets/svelte-C_ipcX3V.js +1 -0
  311. package/dist/assets/swift-D82vCrfD.js +1 -0
  312. package/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
  313. package/dist/assets/system-verilog-CnnmHF94.js +1 -0
  314. package/dist/assets/systemd-4A_iFExJ.js +1 -0
  315. package/dist/assets/talonscript-CkByrt1z.js +1 -0
  316. package/dist/assets/tasl-QIJgUcNo.js +1 -0
  317. package/dist/assets/tcl-dwOrl1Do.js +1 -0
  318. package/dist/assets/templ-P3uqSqPl.js +1 -0
  319. package/dist/assets/terraform-BETggiCN.js +1 -0
  320. package/dist/assets/tex-idrVyKtj.js +1 -0
  321. package/dist/assets/timeline-definition-YZTLITO2-CLYvSw_R.js +61 -0
  322. package/dist/assets/tokyo-night-hegEt444.js +1 -0
  323. package/dist/assets/toml-vGWfd6FD.js +1 -0
  324. package/dist/assets/treemap-KZPCXAKY-ksND0hZK.js +162 -0
  325. package/dist/assets/ts-tags-zn1MmPIZ.js +1 -0
  326. package/dist/assets/tsv-B_m7g4N7.js +1 -0
  327. package/dist/assets/tsx-COt5Ahok.js +1 -0
  328. package/dist/assets/turtle-BsS91CYL.js +1 -0
  329. package/dist/assets/twig-DNn4PbVi.js +1 -0
  330. package/dist/assets/typescript-BPQ3VLAy.js +1 -0
  331. package/dist/assets/typespec-BGHnOYBU.js +1 -0
  332. package/dist/assets/typst-DHCkPAjA.js +1 -0
  333. package/dist/assets/v-BcVCzyr7.js +1 -0
  334. package/dist/assets/vala-CsfeWuGM.js +1 -0
  335. package/dist/assets/vb-D17OF-Vu.js +1 -0
  336. package/dist/assets/{vendor-codemirror-B88_OPWf.js → vendor-codemirror-Dz7_EqNA.js} +3 -3
  337. package/dist/assets/{vendor-react-C3RJLQGO.js → vendor-react-Cpt6D04s.js} +11 -11
  338. package/dist/assets/vennDiagram-LZ73GAT5-CaQg4oZK.js +34 -0
  339. package/dist/assets/verilog-BQ8w6xss.js +1 -0
  340. package/dist/assets/vesper-DU1UobuO.js +1 -0
  341. package/dist/assets/vhdl-CeAyd5Ju.js +1 -0
  342. package/dist/assets/viml-CJc9bBzg.js +1 -0
  343. package/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
  344. package/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
  345. package/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
  346. package/dist/assets/vue-DN_0RTcg.js +1 -0
  347. package/dist/assets/vue-html-AaS7Mt5G.js +1 -0
  348. package/dist/assets/vue-vine-CQOfvN7w.js +1 -0
  349. package/dist/assets/vyper-CDx5xZoG.js +1 -0
  350. package/dist/assets/wasm-CG6Dc4jp.js +1 -0
  351. package/dist/assets/wasm-MzD3tlZU.js +1 -0
  352. package/dist/assets/wenyan-BV7otONQ.js +1 -0
  353. package/dist/assets/wgsl-Dx-B1_4e.js +1 -0
  354. package/dist/assets/wikitext-BhOHFoWU.js +1 -0
  355. package/dist/assets/wit-5i3qLPDT.js +1 -0
  356. package/dist/assets/wolfram-lXgVvXCa.js +1 -0
  357. package/dist/assets/xml-sdJ4AIDG.js +1 -0
  358. package/dist/assets/xsl-CtQFsRM5.js +1 -0
  359. package/dist/assets/xychartDiagram-JWTSCODW-C8dCbTeM.js +7 -0
  360. package/dist/assets/yaml-Buea-lGh.js +1 -0
  361. package/dist/assets/zenscript-DVFEvuxE.js +1 -0
  362. package/dist/assets/zig-VOosw3JB.js +1 -0
  363. package/dist/index.html +35 -21
  364. package/dist/manifest.json +1 -1
  365. package/dist/sw.js +18 -46
  366. package/package.json +12 -8
  367. package/server/bin/codex-sdk-wrapper.js +49 -0
  368. package/server/channels/runtime/AgentRuntimeAdapter.js +2 -5
  369. package/server/channels/store/ChannelStore.js +73 -107
  370. package/server/claude-sdk.js +160 -6
  371. package/server/cli.js +590 -32
  372. package/server/cli.test.js +76 -0
  373. package/server/database/db.js +438 -372
  374. package/server/external-agent/auth.js +88 -0
  375. package/server/external-agent/service.js +1052 -0
  376. package/server/external-agent/service.test.js +41 -0
  377. package/server/external-agent/ws.js +1526 -0
  378. package/server/external-agent/ws.test.js +289 -0
  379. package/server/gemini-cli.js +108 -20
  380. package/server/index.js +115 -121
  381. package/server/load-env.js +16 -13
  382. package/server/openai-codex.js +165 -11
  383. package/server/opencode-cli.js +3 -2
  384. package/server/projects.js +432 -338
  385. package/server/routes/agent.js +347 -459
  386. package/server/routes/auth.js +14 -36
  387. package/server/routes/cli-auth.js +60 -113
  388. package/server/routes/commands.js +16 -26
  389. package/server/routes/git.js +5 -16
  390. package/server/routes/projects.js +2 -7
  391. package/server/routes/session-core.js +177 -0
  392. package/server/session-core/abortSession.js +48 -0
  393. package/server/session-core/eventStore.js +139 -0
  394. package/server/session-core/providerAdapters.js +84 -0
  395. package/server/session-core/providerDiscovery.js +235 -0
  396. package/server/session-core/runtimeState.js +390 -0
  397. package/server/session-core/runtimeWriter.js +59 -0
  398. package/server/utils/agentCallback.js +273 -0
  399. package/server/utils/agentImages.js +253 -0
  400. package/server/utils/codexPath.js +47 -0
  401. package/server/utils/defaultWorkingDirectory.js +34 -0
  402. package/shared/conversationEvents.js +1071 -0
  403. package/shared/modelConstants.js +18 -24
  404. package/dist/assets/index-CVjMty4a.js +0 -902
  405. package/dist/assets/index-eo5scY_Z.css +0 -32
  406. package/server/cursor-cli.js +0 -276
  407. package/server/database/init.sql +0 -98
  408. package/server/routes/cursor.js +0 -795
@@ -7,13 +7,31 @@ import crypto from 'crypto';
7
7
  import { userDb, apiKeysDb, githubTokensDb } from '../database/db.js';
8
8
  import { addProjectManually } from '../projects.js';
9
9
  import { queryClaudeSDK } from '../claude-sdk.js';
10
- import { spawnCursor } from '../cursor-cli.js';
11
10
  import { queryCodex } from '../openai-codex.js';
12
11
  import { queryGemini } from '../gemini-cli.js';
13
12
  import { queryOpencode } from '../opencode-cli.js';
13
+ import { SessionEventMirrorWriter } from '../session-core/runtimeWriter.js';
14
+ import { ABORTABLE_AGENT_PROVIDERS, abortAgentSessionWithWriter, isAbortableAgentProvider } from '../session-core/abortSession.js';
15
+ import {
16
+ buildAgentCallbackPayload,
17
+ createAgentCallbackEventId,
18
+ createEmptyTokenSummary,
19
+ normalizeAgentCallbackConfig,
20
+ scheduleAgentCallbackDelivery,
21
+ shouldDeliverAgentCallback
22
+ } from '../utils/agentCallback.js';
14
23
  import { Octokit } from '@octokit/rest';
15
24
  import { CODEX_MODELS, GEMINI_MODELS, OPENCODE_MODELS } from '../../shared/modelConstants.js';
16
25
  import { IS_PLATFORM } from '../constants/config.js';
26
+ import { validateExternalApiKey as validateExternalAgentApiKey } from '../external-agent/auth.js';
27
+ import {
28
+ NoopWriter as ExternalNoopWriter,
29
+ ResponseCollector as ExternalResponseCollector,
30
+ SSEStreamWriter as ExternalSSEStreamWriter,
31
+ normalizeExternalAgentAbortRequest,
32
+ normalizeExternalAgentRunRequest,
33
+ runExternalAgentRequest
34
+ } from '../external-agent/service.js';
17
35
 
18
36
  const router = express.Router();
19
37
 
@@ -632,6 +650,182 @@ class ResponseCollector {
632
650
  }
633
651
  }
634
652
 
653
+ class AgentSessionAbortedError extends Error {
654
+ constructor(message = 'Session aborted') {
655
+ super(message);
656
+ this.name = 'AgentSessionAbortedError';
657
+ }
658
+ }
659
+
660
+ function extractTerminalErrorMessage(payload) {
661
+ if (!payload || typeof payload !== 'object') {
662
+ return null;
663
+ }
664
+
665
+ if (typeof payload.error === 'string' && payload.error.trim()) {
666
+ return payload.error.trim();
667
+ }
668
+
669
+ if (payload.error && typeof payload.error.message === 'string' && payload.error.message.trim()) {
670
+ return payload.error.message.trim();
671
+ }
672
+
673
+ const nestedData = payload.data;
674
+ if (nestedData && typeof nestedData === 'object') {
675
+ if (typeof nestedData.error === 'string' && nestedData.error.trim()) {
676
+ return nestedData.error.trim();
677
+ }
678
+
679
+ if (nestedData.error && typeof nestedData.error.message === 'string' && nestedData.error.message.trim()) {
680
+ return nestedData.error.message.trim();
681
+ }
682
+
683
+ if (typeof nestedData.message === 'string' && nestedData.message.trim()) {
684
+ return nestedData.message.trim();
685
+ }
686
+ }
687
+
688
+ return null;
689
+ }
690
+
691
+ class CallbackCaptureWriter {
692
+ constructor() {
693
+ this.sessionId = null;
694
+ this.assistantMessages = [];
695
+ this.tokenSummary = createEmptyTokenSummary();
696
+ this.terminalState = null;
697
+ this.terminalErrorMessage = null;
698
+ }
699
+
700
+ send(payload) {
701
+ if (!payload || typeof payload !== 'object') {
702
+ return;
703
+ }
704
+
705
+ if (typeof payload.sessionId === 'string' && payload.sessionId.trim()) {
706
+ this.sessionId = payload.sessionId.trim();
707
+ }
708
+
709
+ if (payload.type === 'session-created' && typeof payload.sessionId === 'string' && payload.sessionId.trim()) {
710
+ this.sessionId = payload.sessionId.trim();
711
+ }
712
+
713
+ if (payload.type === 'token-budget' && payload.data && typeof payload.data === 'object') {
714
+ this.tokenSummary = {
715
+ inputTokens: Number(payload.data.inputTokens) || 0,
716
+ outputTokens: Number(payload.data.outputTokens) || 0,
717
+ cacheReadTokens: Number(payload.data.cacheReadTokens) || 0,
718
+ cacheCreationTokens: Number(payload.data.cacheCreationTokens) || 0,
719
+ totalTokens: Number(payload.data.totalTokens) || 0
720
+ };
721
+ }
722
+
723
+ if (payload.type === 'claude-response' && payload.data?.type === 'assistant') {
724
+ this.assistantMessages.push(payload.data);
725
+ }
726
+
727
+ if (
728
+ payload.type === 'codex-response' &&
729
+ payload.data?.type === 'item_done' &&
730
+ payload.data?.itemType === 'agent_message' &&
731
+ typeof payload.data?.content === 'string' &&
732
+ payload.data.content.trim()
733
+ ) {
734
+ this.assistantMessages.push({
735
+ type: 'assistant',
736
+ message: {
737
+ role: 'assistant',
738
+ content: payload.data.content
739
+ }
740
+ });
741
+ }
742
+
743
+ if (payload.type === 'session-aborted') {
744
+ this.terminalState = 'aborted';
745
+ this.terminalErrorMessage = 'Session aborted';
746
+ return;
747
+ }
748
+
749
+ if (payload.type === 'claude-complete' || payload.type === 'codex-complete') {
750
+ this.terminalState = 'completed';
751
+ this.terminalErrorMessage = null;
752
+ return;
753
+ }
754
+
755
+ if (
756
+ payload.type === 'claude-error' ||
757
+ payload.type === 'codex-error' ||
758
+ payload.type === 'error' ||
759
+ (payload.type === 'codex-response' && payload.data?.type === 'turn_failed')
760
+ ) {
761
+ this.terminalState = 'errored';
762
+ this.terminalErrorMessage = extractTerminalErrorMessage(payload) || this.terminalErrorMessage || 'Agent session failed';
763
+ }
764
+ }
765
+
766
+ end() {}
767
+
768
+ setSessionId(sessionId) {
769
+ if (typeof sessionId === 'string' && sessionId.trim()) {
770
+ this.sessionId = sessionId.trim();
771
+ }
772
+ }
773
+
774
+ getSessionId() {
775
+ return this.sessionId;
776
+ }
777
+
778
+ getAssistantMessages() {
779
+ return this.assistantMessages;
780
+ }
781
+
782
+ getTotalTokens() {
783
+ return this.tokenSummary;
784
+ }
785
+
786
+ getTerminalState() {
787
+ return this.terminalState;
788
+ }
789
+
790
+ getTerminalErrorMessage() {
791
+ return this.terminalErrorMessage;
792
+ }
793
+ }
794
+
795
+ class TeeWriter {
796
+ constructor(primaryWriter, secondaryWriter) {
797
+ this.primaryWriter = primaryWriter;
798
+ this.secondaryWriter = secondaryWriter;
799
+ this.isSSEStreamWriter = !!primaryWriter?.isSSEStreamWriter;
800
+ this.isWebSocketWriter = !!primaryWriter?.isWebSocketWriter;
801
+ }
802
+
803
+ send(payload) {
804
+ this.primaryWriter?.send?.(payload);
805
+ this.secondaryWriter?.send?.(payload);
806
+ }
807
+
808
+ end() {
809
+ this.primaryWriter?.end?.();
810
+ this.secondaryWriter?.end?.();
811
+ }
812
+
813
+ setSessionId(sessionId) {
814
+ this.primaryWriter?.setSessionId?.(sessionId);
815
+ this.secondaryWriter?.setSessionId?.(sessionId);
816
+ }
817
+
818
+ getSessionId() {
819
+ return this.primaryWriter?.getSessionId?.() || this.secondaryWriter?.getSessionId?.() || null;
820
+ }
821
+ }
822
+
823
+ class NoopWriter {
824
+ send() {}
825
+
826
+ end() {}
827
+ }
828
+
635
829
  // ===============================
636
830
  // External API Endpoint
637
831
  // ===============================
@@ -639,25 +833,26 @@ class ResponseCollector {
639
833
  /**
640
834
  * POST /api/agent
641
835
  *
642
- * Trigger an AI agent (Claude, Cursor, Codex, or Gemini) to work on a project.
836
+ * Trigger an AI agent (Claude, Codex, Gemini, or OpenCode) to work on a project.
643
837
  * Supports automatic GitHub branch and pull request creation after successful completion.
644
838
  *
645
839
  * ================================================================================================
646
840
  * REQUEST BODY PARAMETERS
647
841
  * ================================================================================================
648
842
  *
649
- * @param {string} githubUrl - (Conditionally Required) GitHub repository URL to clone.
843
+ * @param {string} githubUrl - (Optional) GitHub repository URL to clone.
650
844
  * Supported formats:
651
845
  * - HTTPS: https://github.com/owner/repo
652
846
  * - HTTPS with .git: https://github.com/owner/repo.git
653
847
  * - SSH: git@github.com:owner/repo
654
848
  * - SSH with .git: git@github.com:owner/repo.git
655
849
  *
656
- * @param {string} projectPath - (Conditionally Required) Path to existing project OR destination for cloning.
850
+ * @param {string} projectPath - (Optional) Path to existing project OR destination for cloning.
657
851
  * Behavior depends on usage:
658
852
  * - If used alone: Must point to existing project directory
659
853
  * - If used with githubUrl: Target location for cloning
660
854
  * - If omitted with githubUrl: Auto-generates temporary path in ~/.claude/external-projects/
855
+ * - If omitted without githubUrl: Falls back to service default working directory, then process cwd
661
856
  *
662
857
  * @param {string} message - (Required) Task description for the AI agent. Used as:
663
858
  * - Instructions for the agent
@@ -667,7 +862,7 @@ class ResponseCollector {
667
862
  * @param {string} sessionId - (Optional) Existing session ID to resume.
668
863
  * If provided, the request continues that session instead of creating a new one.
669
864
  *
670
- * @param {string} provider - (Optional) AI provider to use. Options: 'claude' | 'cursor' | 'codex' | 'gemini'
865
+ * @param {string} provider - (Optional) AI provider to use. Options: 'claude' | 'codex' | 'gemini' | 'opencode'
671
866
  * Default: 'claude'
672
867
  *
673
868
  * @param {boolean} stream - (Optional) Enable Server-Sent Events (SSE) streaming for real-time updates.
@@ -678,8 +873,7 @@ class ResponseCollector {
678
873
  * @param {string} model - (Optional) Model identifier for providers.
679
874
  *
680
875
  * Claude models: 'sonnet' (default), 'opus', 'haiku', 'opusplan', 'sonnet[1m]'
681
- * Cursor models: 'gpt-5' (default), 'gpt-5.2', 'gpt-5.2-high', 'sonnet-4.5', 'opus-4.5',
682
- * 'gemini-3-pro', 'composer-1', 'auto', 'gpt-5.1', 'gpt-5.1-high',
876
+ * * 'gemini-3-pro', 'composer-1', 'auto', 'gpt-5.1', 'gpt-5.1-high',
683
877
  * 'gpt-5.1-codex', 'gpt-5.1-codex-high', 'gpt-5.1-codex-max',
684
878
  * 'gpt-5.1-codex-max-high', 'opus-4.1', 'grok', and thinking variants
685
879
  * Codex models: 'gpt-5.2' (default), 'gpt-5.1-codex-max', 'o3', 'o4-mini'
@@ -733,6 +927,16 @@ class ResponseCollector {
733
927
  * - If PR already exists: GitHub returns error with details
734
928
  * - Requires either githubUrl OR projectPath with GitHub remote
735
929
  *
930
+ * @param {object} callback - (Optional) Terminal webhook configuration for external systems.
931
+ * Behavior:
932
+ * - Sent once when the run ends as completed, errored, or aborted
933
+ * - Delivery is asynchronous and never blocks the main API response
934
+ * - Not supported with openOnly=true
935
+ * Fields:
936
+ * - url: Required HTTP/HTTPS target URL
937
+ * - events: Optional subset of ["completed", "errored", "aborted"]
938
+ * - secret: Optional shared secret for HMAC signing
939
+ *
736
940
  * ================================================================================================
737
941
  * PATH HANDLING BEHAVIOR
738
942
  * ================================================================================================
@@ -784,11 +988,14 @@ class ResponseCollector {
784
988
  * ================================================================================================
785
989
  *
786
990
  * Input Validations (400 Bad Request):
787
- * - Either githubUrl OR projectPath must be provided (not neither)
788
991
  * - message must be non-empty string
789
- * - provider must be 'claude', 'cursor', 'codex', or 'gemini'
790
- * - createBranch/createPR requires githubUrl OR projectPath (not neither)
992
+ * - provider must be 'claude', 'codex', 'gemini', or 'opencode'
993
+ * - createBranch/createPR requires a resolvable working directory or githubUrl
791
994
  * - branchName must pass Git naming rules (if provided)
995
+ * - callback must be an object when provided
996
+ * - callback.url must be a valid HTTP/HTTPS URL
997
+ * - callback.events can only include completed/errored/aborted
998
+ * - callback is not supported when openOnly=true
792
999
  *
793
1000
  * Runtime Validations (500 Internal Server Error or specific error in response):
794
1001
  * - projectPath must exist (if used alone)
@@ -847,6 +1054,14 @@ class ResponseCollector {
847
1054
  * Content-Type: application/json
848
1055
  * { success: false, error: "Error description" }
849
1056
  *
1057
+ * Callback Delivery:
1058
+ * Content-Type: application/json
1059
+ * Headers:
1060
+ * - X-Agent-Event
1061
+ * - X-Agent-Event-Id
1062
+ * - X-Agent-Delivery-Attempt
1063
+ * - X-Agent-Signature (only when callback.secret is provided)
1064
+ *
850
1065
  * ================================================================================================
851
1066
  * EXAMPLES
852
1067
  * ================================================================================================
@@ -874,481 +1089,154 @@ class ResponseCollector {
874
1089
  * "cleanup": false
875
1090
  * }
876
1091
  */
877
- router.post('/', validateExternalApiKey, async (req, res) => {
878
- const { githubUrl, projectPath, message, provider = 'claude', model, githubToken, branchName, sessionId, openOnly } = req.body;
879
-
880
- // Parse stream and cleanup as booleans (handle string "true"/"false" from curl)
881
- const stream = req.body.stream === undefined ? true : (req.body.stream === true || req.body.stream === 'true');
882
- const requestedCleanup = req.body.cleanup === undefined ? true : (req.body.cleanup === true || req.body.cleanup === 'true');
883
-
884
- // If branchName is provided, automatically enable createBranch
885
- const createBranch = branchName ? true : (req.body.createBranch === true || req.body.createBranch === 'true');
886
- const createPR = req.body.createPR === true || req.body.createPR === 'true';
887
- const normalizedSessionId = typeof sessionId === 'string' && sessionId.trim() ? sessionId.trim() : null;
888
- const normalizedMessage = typeof message === 'string' ? message.trim() : '';
889
- const requestedOpenOnly = openOnly === true || openOnly === 'true';
890
- const isOpenOnly = requestedOpenOnly || (!normalizedMessage && !!normalizedSessionId);
891
- // Keep openOnly requests backward-compatible with existing docs/examples:
892
- // cleanup is irrelevant when we only generate session navigation.
893
- const cleanup = isOpenOnly ? false : requestedCleanup;
894
-
895
- // Validate inputs
896
- if (!['claude', 'cursor', 'codex', 'gemini', 'opencode'].includes(provider)) {
897
- return res.status(400).json({ error: 'provider must be "claude", "cursor", "codex", "gemini", or "opencode"' });
898
- }
899
-
900
- if (sessionId !== undefined && (typeof sessionId !== 'string' || !sessionId.trim())) {
901
- return res.status(400).json({ error: 'sessionId must be a non-empty string when provided' });
902
- }
903
-
904
- if (isOpenOnly && !normalizedSessionId) {
905
- return res.status(400).json({ error: 'sessionId is required when message is empty or openOnly=true' });
906
- }
907
-
908
- if (!isOpenOnly && !normalizedMessage) {
909
- return res.status(400).json({ error: 'message is required unless openOnly=true' });
910
- }
911
-
912
- if (!isOpenOnly && !githubUrl && !projectPath) {
913
- return res.status(400).json({ error: 'Either githubUrl or projectPath is required' });
914
- }
915
-
916
- if (isOpenOnly && githubUrl) {
917
- return res.status(400).json({ error: 'githubUrl is not supported when openOnly=true' });
918
- }
919
-
920
- if (isOpenOnly && (createBranch || createPR)) {
921
- return res.status(400).json({ error: 'createBranch and createPR are not supported when openOnly=true' });
922
- }
923
-
924
- // Validate GitHub branch/PR creation requirements
925
- // Allow branch/PR creation with projectPath as long as it has a GitHub remote
926
- if ((createBranch || createPR) && !githubUrl && !projectPath) {
927
- return res.status(400).json({ error: 'createBranch and createPR require either githubUrl or projectPath with a GitHub remote' });
1092
+ router.post('/', validateExternalAgentApiKey, async (req, res) => {
1093
+ let normalized = null;
1094
+ try {
1095
+ normalized = normalizeExternalAgentRunRequest(req.body);
1096
+ } catch (error) {
1097
+ return res.status(error.statusCode || 400).json({
1098
+ error: error.message
1099
+ });
928
1100
  }
929
1101
 
930
- if (isOpenOnly) {
931
- const { sessionPath, sessionUrl } = buildSessionNavigation(normalizedSessionId);
932
- const response = {
933
- success: true,
934
- openOnly: true,
935
- sessionId: normalizedSessionId,
936
- sessionPath,
937
- sessionUrl,
938
- isResumed: true,
939
- message: 'Session link generated. No model call triggered.'
940
- };
1102
+ try {
1103
+ let transportWriter = null;
941
1104
 
942
- if (stream) {
1105
+ if (normalized.stream) {
943
1106
  res.setHeader('Content-Type', 'text/event-stream');
944
1107
  res.setHeader('Cache-Control', 'no-cache');
945
1108
  res.setHeader('Connection', 'keep-alive');
946
1109
  res.setHeader('X-Accel-Buffering', 'no');
947
-
948
- const writer = new SSEStreamWriter(res);
949
- writer.send({
950
- type: 'open-only',
951
- ...response
952
- });
953
- writer.end();
954
- return;
1110
+ transportWriter = new ExternalSSEStreamWriter(res);
1111
+ } else {
1112
+ transportWriter = new ExternalResponseCollector();
955
1113
  }
956
1114
 
957
- return res.json(response);
958
- }
959
-
960
- let finalProjectPath = null;
961
- let writer = null;
962
-
963
- try {
964
- // Determine the final project path
965
- if (githubUrl) {
966
- // Clone repository (to projectPath if provided, otherwise generate path)
967
- const tokenToUse = githubToken || githubTokensDb.getActiveGithubToken(req.user.id);
968
-
969
- let targetPath;
970
- if (projectPath) {
971
- targetPath = projectPath;
972
- } else {
973
- // Generate a unique path for cloning
974
- const repoHash = crypto.createHash('md5').update(githubUrl + Date.now()).digest('hex');
975
- targetPath = path.join(os.homedir(), '.claude', 'external-projects', repoHash);
976
- }
977
-
978
- finalProjectPath = await cloneGitHubRepo(githubUrl.trim(), tokenToUse, targetPath);
979
- } else {
980
- // Use existing project path
981
- finalProjectPath = path.resolve(projectPath);
1115
+ const response = await runExternalAgentRequest({
1116
+ user: req.user,
1117
+ request: normalized,
1118
+ transportWriter,
1119
+ endTransportOnFinish: normalized.stream
1120
+ });
982
1121
 
983
- // Verify the path exists
984
- try {
985
- await fs.access(finalProjectPath);
986
- } catch (error) {
987
- throw new Error(`Project path does not exist: ${finalProjectPath}`);
988
- }
1122
+ if (!normalized.stream) {
1123
+ return res.json(response);
989
1124
  }
1125
+ } catch (error) {
1126
+ console.error('❌ External session error:', error);
990
1127
 
991
- // Register the project (or use existing registration)
992
- let project;
993
- try {
994
- project = await addProjectManually(finalProjectPath);
995
- console.log('📦 Project registered:', project);
996
- } catch (error) {
997
- // If project already exists, that's fine - continue with the existing registration
998
- if (error.message && error.message.includes('Project already configured')) {
999
- console.log('📦 Using existing project registration for:', finalProjectPath);
1000
- project = { path: finalProjectPath };
1001
- } else {
1002
- throw error;
1128
+ if (normalized?.stream) {
1129
+ if (!res.headersSent) {
1130
+ res.setHeader('Content-Type', 'text/event-stream');
1131
+ res.setHeader('Cache-Control', 'no-cache');
1132
+ res.setHeader('Connection', 'keep-alive');
1133
+ res.setHeader('X-Accel-Buffering', 'no');
1003
1134
  }
1004
- }
1005
-
1006
- // Set up writer based on streaming mode
1007
- const statusMessage = normalizedSessionId
1008
- ? (githubUrl ? 'Repository cloned and session resumed' : 'Session resumed')
1009
- : (githubUrl ? 'Repository cloned and session started' : 'Session started');
1010
1135
 
1011
- if (stream) {
1012
- // Set up SSE headers for streaming
1013
- res.setHeader('Content-Type', 'text/event-stream');
1014
- res.setHeader('Cache-Control', 'no-cache');
1015
- res.setHeader('Connection', 'keep-alive');
1016
- res.setHeader('X-Accel-Buffering', 'no'); // Disable nginx buffering
1017
-
1018
- writer = new SSEStreamWriter(res);
1019
-
1020
- // Send initial status
1136
+ const writer = new ExternalSSEStreamWriter(res);
1021
1137
  writer.send({
1022
- type: 'status',
1023
- message: statusMessage,
1024
- projectPath: finalProjectPath
1138
+ type: 'error',
1139
+ error: error.message,
1140
+ message: `Failed: ${error.message}`
1025
1141
  });
1026
- } else {
1027
- // Non-streaming mode: collect messages
1028
- writer = new ResponseCollector();
1029
-
1030
- // Collect initial status message
1031
- writer.send({
1032
- type: 'status',
1033
- message: statusMessage,
1034
- projectPath: finalProjectPath
1035
- });
1036
- }
1037
-
1038
- // Start the appropriate session
1039
- if (provider === 'claude') {
1040
- console.log('🤖 Starting Claude SDK session');
1041
-
1042
- await queryClaudeSDK(normalizedMessage, {
1043
- projectPath: finalProjectPath,
1044
- cwd: finalProjectPath,
1045
- sessionId: normalizedSessionId,
1046
- model: model,
1047
- permissionMode: 'bypassPermissions' // Bypass all permissions for API calls
1048
- }, writer);
1049
-
1050
- } else if (provider === 'cursor') {
1051
- console.log('🖱️ Starting Cursor CLI session');
1052
-
1053
- await spawnCursor(normalizedMessage, {
1054
- projectPath: finalProjectPath,
1055
- cwd: finalProjectPath,
1056
- sessionId: normalizedSessionId,
1057
- resume: !!normalizedSessionId,
1058
- model: model || undefined,
1059
- skipPermissions: true // Bypass permissions for Cursor
1060
- }, writer);
1061
- } else if (provider === 'codex') {
1062
- console.log('🤖 Starting Codex SDK session');
1063
-
1064
- await queryCodex(normalizedMessage, {
1065
- projectPath: finalProjectPath,
1066
- cwd: finalProjectPath,
1067
- sessionId: normalizedSessionId,
1068
- model: model || CODEX_MODELS.DEFAULT,
1069
- permissionMode: 'bypassPermissions'
1070
- }, writer);
1071
- } else if (provider === 'gemini') {
1072
- console.log('💎 Starting Gemini CLI session');
1073
-
1074
- await queryGemini(normalizedMessage, {
1075
- projectPath: finalProjectPath,
1076
- cwd: finalProjectPath,
1077
- sessionId: normalizedSessionId,
1078
- resume: !!normalizedSessionId,
1079
- model: model || GEMINI_MODELS.DEFAULT,
1080
- permissionMode: 'bypassPermissions'
1081
- }, writer);
1082
- } else if (provider === 'opencode') {
1083
- console.log('🧠 Starting OpenCode CLI session');
1084
-
1085
- await queryOpencode(normalizedMessage, {
1086
- projectPath: finalProjectPath,
1087
- cwd: finalProjectPath,
1088
- sessionId: normalizedSessionId,
1089
- resume: !!normalizedSessionId,
1090
- model: model || OPENCODE_MODELS.DEFAULT,
1091
- permissionMode: 'bypassPermissions'
1092
- }, writer);
1093
- }
1094
-
1095
- // Handle GitHub branch and PR creation after successful agent completion
1096
- let branchInfo = null;
1097
- let prInfo = null;
1098
-
1099
- if (createBranch || createPR) {
1100
- try {
1101
- console.log('🔄 Starting GitHub branch/PR creation workflow...');
1102
-
1103
- // Get GitHub token
1104
- const tokenToUse = githubToken || githubTokensDb.getActiveGithubToken(req.user.id);
1105
-
1106
- if (!tokenToUse) {
1107
- throw new Error('GitHub token required for branch/PR creation. Please configure a GitHub token in settings.');
1108
- }
1109
-
1110
- // Initialize Octokit
1111
- const octokit = new Octokit({ auth: tokenToUse });
1112
-
1113
- // Get GitHub URL - either from parameter or from git remote
1114
- let repoUrl = githubUrl;
1115
- if (!repoUrl) {
1116
- console.log('🔍 Getting GitHub URL from git remote...');
1117
- try {
1118
- repoUrl = await getGitRemoteUrl(finalProjectPath);
1119
- if (!repoUrl.includes('github.com')) {
1120
- throw new Error('Project does not have a GitHub remote configured');
1121
- }
1122
- console.log(`✅ Found GitHub remote: ${repoUrl}`);
1123
- } catch (error) {
1124
- throw new Error(`Failed to get GitHub remote URL: ${error.message}`);
1125
- }
1126
- }
1127
-
1128
- // Parse GitHub URL to get owner and repo
1129
- const { owner, repo } = parseGitHubUrl(repoUrl);
1130
- console.log(`📦 Repository: ${owner}/${repo}`);
1131
-
1132
- // Use provided branch name or auto-generate from message
1133
- const finalBranchName = branchName || autogenerateBranchName(message);
1134
- if (branchName) {
1135
- console.log(`🌿 Using provided branch name: ${finalBranchName}`);
1136
-
1137
- // Validate custom branch name
1138
- const validation = validateBranchName(finalBranchName);
1139
- if (!validation.valid) {
1140
- throw new Error(`Invalid branch name: ${validation.error}`);
1141
- }
1142
- } else {
1143
- console.log(`🌿 Auto-generated branch name: ${finalBranchName}`);
1144
- }
1145
-
1146
- if (createBranch) {
1147
- // Create and checkout the new branch locally
1148
- console.log('🔄 Creating local branch...');
1149
- const checkoutProcess = spawn('git', ['checkout', '-b', finalBranchName], {
1150
- cwd: finalProjectPath,
1151
- stdio: 'pipe'
1152
- });
1153
-
1154
- await new Promise((resolve, reject) => {
1155
- let stderr = '';
1156
- checkoutProcess.stderr.on('data', (data) => { stderr += data.toString(); });
1157
- checkoutProcess.on('close', (code) => {
1158
- if (code === 0) {
1159
- console.log(`✅ Created and checked out local branch '${finalBranchName}'`);
1160
- resolve();
1161
- } else {
1162
- // Branch might already exist locally, try to checkout
1163
- if (stderr.includes('already exists')) {
1164
- console.log(`ℹ️ Branch '${finalBranchName}' already exists locally, checking out...`);
1165
- const checkoutExisting = spawn('git', ['checkout', finalBranchName], {
1166
- cwd: finalProjectPath,
1167
- stdio: 'pipe'
1168
- });
1169
- checkoutExisting.on('close', (checkoutCode) => {
1170
- if (checkoutCode === 0) {
1171
- console.log(`✅ Checked out existing branch '${finalBranchName}'`);
1172
- resolve();
1173
- } else {
1174
- reject(new Error(`Failed to checkout existing branch: ${stderr}`));
1175
- }
1176
- });
1177
- } else {
1178
- reject(new Error(`Failed to create branch: ${stderr}`));
1179
- }
1180
- }
1181
- });
1182
- });
1183
-
1184
- // Push the branch to remote
1185
- console.log('🔄 Pushing branch to remote...');
1186
- const pushProcess = spawn('git', ['push', '-u', 'origin', finalBranchName], {
1187
- cwd: finalProjectPath,
1188
- stdio: 'pipe'
1189
- });
1190
-
1191
- await new Promise((resolve, reject) => {
1192
- let stderr = '';
1193
- let stdout = '';
1194
- pushProcess.stdout.on('data', (data) => { stdout += data.toString(); });
1195
- pushProcess.stderr.on('data', (data) => { stderr += data.toString(); });
1196
- pushProcess.on('close', (code) => {
1197
- if (code === 0) {
1198
- console.log(`✅ Pushed branch '${finalBranchName}' to remote`);
1199
- resolve();
1200
- } else {
1201
- // Check if branch exists on remote but has different commits
1202
- if (stderr.includes('already exists') || stderr.includes('up-to-date')) {
1203
- console.log(`ℹ️ Branch '${finalBranchName}' already exists on remote, using existing branch`);
1204
- resolve();
1205
- } else {
1206
- reject(new Error(`Failed to push branch: ${stderr}`));
1207
- }
1208
- }
1209
- });
1210
- });
1211
-
1212
- branchInfo = {
1213
- name: finalBranchName,
1214
- url: `https://github.com/${owner}/${repo}/tree/${finalBranchName}`
1215
- };
1216
- }
1217
-
1218
- if (createPR) {
1219
- // Get commit messages to generate PR description
1220
- console.log('🔄 Generating PR title and description...');
1221
- const commitMessages = await getCommitMessages(finalProjectPath, 5);
1222
-
1223
- // Use the first commit message as the PR title, or fallback to the agent message
1224
- const prTitle = commitMessages.length > 0 ? commitMessages[0] : message;
1225
-
1226
- // Generate PR body from commit messages
1227
- let prBody = '## Changes\n\n';
1228
- if (commitMessages.length > 0) {
1229
- prBody += commitMessages.map(msg => `- ${msg}`).join('\n');
1230
- } else {
1231
- prBody += `Agent task: ${message}`;
1232
- }
1233
- prBody += '\n\n---\n*This pull request was automatically created by Axhub Genie Agent.*';
1234
-
1235
- console.log(`📝 PR Title: ${prTitle}`);
1236
-
1237
- // Create the pull request
1238
- console.log('🔄 Creating pull request...');
1239
- prInfo = await createGitHubPR(octokit, owner, repo, finalBranchName, prTitle, prBody, 'main');
1240
- }
1241
-
1242
- // Send branch/PR info in response
1243
- if (stream) {
1244
- if (branchInfo) {
1245
- writer.send({
1246
- type: 'github-branch',
1247
- branch: branchInfo
1248
- });
1249
- }
1250
- if (prInfo) {
1251
- writer.send({
1252
- type: 'github-pr',
1253
- pullRequest: prInfo
1254
- });
1255
- }
1256
- }
1257
-
1258
- } catch (error) {
1259
- console.error('❌ GitHub branch/PR creation error:', error);
1260
-
1261
- // Send error but don't fail the entire request
1262
- if (stream) {
1263
- writer.send({
1264
- type: 'github-error',
1265
- error: error.message
1266
- });
1267
- }
1268
- // Store error info for non-streaming response
1269
- if (!stream) {
1270
- branchInfo = { error: error.message };
1271
- prInfo = { error: error.message };
1272
- }
1273
- }
1274
- }
1275
-
1276
- // Handle response based on streaming mode
1277
- if (stream) {
1278
- // Streaming mode: end the SSE stream
1279
1142
  writer.end();
1280
- } else {
1281
- // Non-streaming mode: send filtered messages and token summary as JSON
1282
- const assistantMessages = writer.getAssistantMessages();
1283
- const tokenSummary = writer.getTotalTokens();
1284
- const resolvedSessionId = writer.getSessionId() || normalizedSessionId;
1285
- const { sessionPath, sessionUrl } = buildSessionNavigation(resolvedSessionId);
1286
-
1287
- const response = {
1288
- success: true,
1289
- sessionId: resolvedSessionId,
1290
- sessionPath,
1291
- sessionUrl,
1292
- isResumed: !!normalizedSessionId,
1293
- messages: assistantMessages,
1294
- tokens: tokenSummary,
1295
- projectPath: finalProjectPath
1296
- };
1297
-
1298
- // Add branch/PR info if created
1299
- if (branchInfo) {
1300
- response.branch = branchInfo;
1301
- }
1302
- if (prInfo) {
1303
- response.pullRequest = prInfo;
1304
- }
1305
-
1306
- res.json(response);
1143
+ return;
1307
1144
  }
1308
1145
 
1309
- // Clean up if requested
1310
- if (cleanup && githubUrl) {
1311
- // Only cleanup if we cloned a repo (not for existing project paths)
1312
- const sessionIdForCleanup = writer.getSessionId();
1313
- setTimeout(() => {
1314
- cleanupProject(finalProjectPath, sessionIdForCleanup);
1315
- }, 5000);
1316
- }
1146
+ return res.status(error.statusCode || 500).json({
1147
+ success: false,
1148
+ error: error.message
1149
+ });
1150
+ }
1151
+ });
1317
1152
 
1153
+ /**
1154
+ * POST /api/agent/abort
1155
+ *
1156
+ * Interrupt an active AI agent session.
1157
+ *
1158
+ * ================================================================================================
1159
+ * REQUEST BODY PARAMETERS
1160
+ * ================================================================================================
1161
+ *
1162
+ * @param {string} sessionId - (Required) Session ID to interrupt.
1163
+ * @param {string} provider - (Optional) AI provider for the active session.
1164
+ * Options: 'claude' | 'codex' | 'gemini' | 'opencode'
1165
+ * Default: 'claude'
1166
+ *
1167
+ * ================================================================================================
1168
+ * VALIDATION & ERROR HANDLING
1169
+ * ================================================================================================
1170
+ *
1171
+ * Input Validations (400 Bad Request):
1172
+ * - sessionId must be a non-empty string
1173
+ * - provider must be 'claude', 'codex', 'gemini', or 'opencode' when provided
1174
+ *
1175
+ * Success Response (200 OK):
1176
+ * {
1177
+ * success: true,
1178
+ * aborted: true,
1179
+ * sessionId: "session-123",
1180
+ * provider: "claude",
1181
+ * message: "Session aborted"
1182
+ * }
1183
+ *
1184
+ * Not Found Response (200 OK):
1185
+ * {
1186
+ * success: false,
1187
+ * aborted: false,
1188
+ * sessionId: "session-123",
1189
+ * provider: "claude",
1190
+ * error: "Active session not found"
1191
+ * }
1192
+ *
1193
+ * Error Response:
1194
+ * HTTP Status: 400, 401, 500
1195
+ * Content-Type: application/json
1196
+ * { success: false, error: "Error description" }
1197
+ */
1198
+ router.post('/abort', validateExternalAgentApiKey, async (req, res) => {
1199
+ let normalized = null;
1200
+ try {
1201
+ normalized = normalizeExternalAgentAbortRequest(req.body);
1318
1202
  } catch (error) {
1319
- console.error('❌ External session error:', error);
1320
-
1321
- // Clean up on error
1322
- if (finalProjectPath && cleanup && githubUrl) {
1323
- const sessionIdForCleanup = writer ? writer.getSessionId() : null;
1324
- cleanupProject(finalProjectPath, sessionIdForCleanup);
1325
- }
1203
+ return res.status(error.statusCode || 400).json({
1204
+ success: false,
1205
+ error: error.message
1206
+ });
1207
+ }
1326
1208
 
1327
- if (stream) {
1328
- // For streaming, send error event and stop
1329
- if (!writer) {
1330
- // Set up SSE headers if not already done
1331
- res.setHeader('Content-Type', 'text/event-stream');
1332
- res.setHeader('Cache-Control', 'no-cache');
1333
- res.setHeader('Connection', 'keep-alive');
1334
- res.setHeader('X-Accel-Buffering', 'no');
1335
- writer = new SSEStreamWriter(res);
1336
- }
1209
+ try {
1210
+ const writer = new SessionEventMirrorWriter(new ExternalNoopWriter(), normalized.provider);
1211
+ const { success } = await abortAgentSessionWithWriter({
1212
+ provider: normalized.provider,
1213
+ sessionId: normalized.sessionId,
1214
+ writer
1215
+ });
1337
1216
 
1338
- if (!res.writableEnded) {
1339
- writer.send({
1340
- type: 'error',
1341
- error: error.message,
1342
- message: `Failed: ${error.message}`
1343
- });
1344
- writer.end();
1345
- }
1346
- } else if (!res.headersSent) {
1347
- res.status(500).json({
1217
+ if (!success) {
1218
+ return res.json({
1348
1219
  success: false,
1349
- error: error.message
1220
+ aborted: false,
1221
+ sessionId: normalized.sessionId,
1222
+ provider: normalized.provider,
1223
+ error: 'Active session not found'
1350
1224
  });
1351
1225
  }
1226
+
1227
+ return res.json({
1228
+ success: true,
1229
+ aborted: true,
1230
+ sessionId: normalized.sessionId,
1231
+ provider: normalized.provider,
1232
+ message: 'Session aborted'
1233
+ });
1234
+ } catch (error) {
1235
+ console.error('❌ External abort session error:', error);
1236
+ return res.status(500).json({
1237
+ success: false,
1238
+ error: error.message
1239
+ });
1352
1240
  }
1353
1241
  });
1354
1242