@axhub/genie 0.1.7 → 0.1.9

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 (411) hide show
  1. package/README.md +1 -1
  2. package/dist/api-docs.html +2 -2
  3. package/dist/assets/App-IUhj6pRQ.js +546 -0
  4. package/dist/assets/App-qxJ8_QYu.css +32 -0
  5. package/dist/assets/ReviewApp-B8aNlXpI.js +1 -0
  6. package/dist/assets/_basePickBy-DF_C8v-X.js +1 -0
  7. package/dist/assets/_baseUniq-Dl8X6bvw.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-TwO_Ni8v.js +1 -0
  20. package/dist/assets/architectureDiagram-2XIMDMQ5-Dgm9kjQy.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-BhTxXYHE.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-D3xrrPyf.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-D6xYGBae.js +1 -0
  49. package/dist/assets/chunk-4BX2VUAB-Fb3wkGSX.js +1 -0
  50. package/dist/assets/chunk-55IACEB6-CQwPJLM_.js +1 -0
  51. package/dist/assets/chunk-FMBD7UC4-B3SocdK3.js +15 -0
  52. package/dist/assets/chunk-JSJVCQXG-4LjhKVWX.js +1 -0
  53. package/dist/assets/chunk-KX2RTZJC-B5NX8jxL.js +1 -0
  54. package/dist/assets/chunk-NQ4KR5QH-6puKzw3k.js +220 -0
  55. package/dist/assets/chunk-QZHKN3VN-CxscPgdC.js +1 -0
  56. package/dist/assets/chunk-WL4C6EOR-uBFUeI3B.js +189 -0
  57. package/dist/assets/clarity-D53aC0YG.js +1 -0
  58. package/dist/assets/classDiagram-VBA2DB6C-CAq2xBD7.js +1 -0
  59. package/dist/assets/classDiagram-v2-RAHNMMFH-CAq2xBD7.js +1 -0
  60. package/dist/assets/clojure-P80f7IUj.js +1 -0
  61. package/dist/assets/clone-Ci5Ji0hp.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-DlbARPn2.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-D5rHdqja.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-1UmM7jTs.js +24 -0
  86. package/dist/assets/diagram-IFDJBPK2-BiB8xLQb.js +43 -0
  87. package/dist/assets/diagram-P4PSJMXO-D0DHiPZv.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-CnRJ2Jix.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-CEgo6QRr.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-BIuQLJvD.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-BgM4MazK.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-CAfp4sq_.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-qMmmT5JC.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-DIJsxqXa.css +1 -0
  162. package/dist/assets/index-DLN_-tVh.js +2 -0
  163. package/dist/assets/infoDiagram-LFFYTUFH-CWSerJ0x.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-CzeVsiJ6.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-D_NYt9lf.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-CX7AUuup.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-DSvVDs_y.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-CVh3kWAl.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-CrPRD2Zy.js +964 -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-w_orDc4B.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-Ddit1h2q.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-DVw1s8Ut.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-DQPZpp_9.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-CfbFynOx.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-BO9n1wra.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-CRL3ceNd.js +1 -0
  307. package/dist/assets/stateDiagram-v2-FVOUBMTO-CZOgjDCg.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-BR7smGEM.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-DkR8x0Kw.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-D5if-Qdt.js} +3 -3
  337. package/dist/assets/{vendor-react-C3RJLQGO.js → vendor-react-CSz7XC90.js} +11 -11
  338. package/dist/assets/vennDiagram-LZ73GAT5-DS7XpPV_.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-BgjSBvNS.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 +37 -23
  364. package/dist/manifest.json +2 -2
  365. package/dist/sw.js +18 -46
  366. package/package.json +12 -7
  367. package/server/bin/codex-sdk-wrapper.js +49 -0
  368. package/server/channels/core/ChannelManager.js +399 -0
  369. package/server/channels/core/PluginManager.js +59 -0
  370. package/server/channels/index.js +3 -0
  371. package/server/channels/plugins/BasePlugin.js +46 -0
  372. package/server/channels/plugins/dingtalk/DingTalkAdapter.js +156 -0
  373. package/server/channels/plugins/dingtalk/DingTalkPlugin.js +592 -0
  374. package/server/channels/plugins/dingtalk/index.js +2 -0
  375. package/server/channels/plugins/lark/LarkAdapter.js +100 -0
  376. package/server/channels/plugins/lark/LarkCards.js +43 -0
  377. package/server/channels/plugins/lark/LarkPlugin.js +260 -0
  378. package/server/channels/runtime/AgentRuntimeAdapter.js +176 -0
  379. package/server/channels/runtime/DingTalkStreamWriter.js +105 -0
  380. package/server/channels/runtime/LarkStreamWriter.js +99 -0
  381. package/server/channels/store/ChannelStore.js +202 -0
  382. package/server/claude-sdk.js +151 -3
  383. package/server/cli.js +21 -21
  384. package/server/database/db.js +449 -275
  385. package/server/gemini-cli.js +106 -19
  386. package/server/index.js +87 -108
  387. package/server/load-env.js +16 -13
  388. package/server/openai-codex.js +146 -10
  389. package/server/projects.js +340 -331
  390. package/server/routes/agent.js +429 -30
  391. package/server/routes/auth.js +14 -36
  392. package/server/routes/channels.js +221 -0
  393. package/server/routes/cli-auth.js +117 -124
  394. package/server/routes/commands.js +16 -26
  395. package/server/routes/git.js +5 -16
  396. package/server/routes/projects.js +2 -7
  397. package/server/routes/session-core.js +177 -0
  398. package/server/session-core/abortSession.js +48 -0
  399. package/server/session-core/eventStore.js +139 -0
  400. package/server/session-core/providerAdapters.js +84 -0
  401. package/server/session-core/providerDiscovery.js +235 -0
  402. package/server/session-core/runtimeWriter.js +55 -0
  403. package/server/utils/agentCallback.js +273 -0
  404. package/server/utils/codexPath.js +47 -0
  405. package/shared/conversationEvents.js +1031 -0
  406. package/shared/modelConstants.js +18 -24
  407. package/dist/assets/index-C2r-Jzfw.js +0 -897
  408. package/dist/assets/index-COkoBQi5.css +0 -32
  409. package/server/cursor-cli.js +0 -276
  410. package/server/database/init.sql +0 -52
  411. package/server/routes/cursor.js +0 -795
@@ -2,7 +2,7 @@
2
2
  * PROJECT DISCOVERY AND MANAGEMENT SYSTEM
3
3
  * ========================================
4
4
  *
5
- * This module manages project discovery for both Claude CLI and Cursor CLI sessions.
5
+ * This module manages project discovery for Claude CLI and local agent sessions.
6
6
  *
7
7
  * ## Architecture Overview
8
8
  *
@@ -11,11 +11,9 @@
11
11
  * - Contains .jsonl files with conversation history including 'cwd' field
12
12
  * - Project metadata stored in ~/.claude/project-config.json
13
13
  *
14
- * 2. **Cursor Projects** (stored in ~/.cursor/chats/)
15
- * - Each project directory is named with MD5 hash of the absolute project path
16
- * - Example: /Users/john/myproject -> MD5 -> a1b2c3d4e5f6...
17
- * - Contains session directories with SQLite databases (store.db)
18
- * - Project path is NOT stored in the database - only in the MD5 hash
14
+ * 2. **Manual project metadata**
15
+ * - Project metadata is stored in ~/.claude/project-config.json
16
+ * - Manually added workspaces remain visible even without existing sessions
19
17
  *
20
18
  * ## Project Discovery Strategy
21
19
  *
@@ -24,25 +22,15 @@
24
22
  * - Extract actual project path from .jsonl files (cwd field)
25
23
  * - Fall back to decoded directory name if no sessions exist
26
24
  *
27
- * 2. **Cursor Sessions Discovery**:
28
- * - For each KNOWN project (from Claude or manually added)
29
- * - Compute MD5 hash of the project's absolute path
30
- * - Check if ~/.cursor/chats/{md5_hash}/ directory exists
31
- * - Read session metadata from SQLite store.db files
32
- *
33
- * 3. **Manual Project Addition**:
25
+ * 2. **Manual Project Addition**:
34
26
  * - Users can manually add project paths via UI
35
27
  * - Stored in ~/.claude/project-config.json with 'manuallyAdded' flag
36
- * - Allows discovering Cursor sessions for projects without Claude sessions
28
+ * - Allows discovering additional local provider sessions without Claude sessions
37
29
  *
38
30
  * ## Critical Limitations
39
31
  *
40
- * - **CANNOT discover Cursor-only projects**: From a quick check, there was no mention of
41
- * the cwd of each project. if someone has the time, you can try to reverse engineer it.
42
- *
43
32
  * - **Project relocation breaks history**: If a project directory is moved or renamed,
44
- * the MD5 hash changes, making old Cursor sessions inaccessible unless the old
45
- * path is known and manually added.
33
+ * existing local session history may no longer align with the new path.
46
34
  *
47
35
  * ## Error Handling
48
36
  *
@@ -59,12 +47,10 @@
59
47
 
60
48
  import { promises as fs } from 'fs';
61
49
  import fsSync from 'fs';
50
+ import os from 'os';
62
51
  import path from 'path';
63
52
  import readline from 'readline';
64
53
  import crypto from 'crypto';
65
- import sqlite3 from 'sqlite3';
66
- import { open } from 'sqlite';
67
- import os from 'os';
68
54
  import { parseCodexTokenCountInfo } from './utils/codexTokenUsage.js';
69
55
 
70
56
  // Import TaskMaster detection functions
@@ -197,12 +183,131 @@ async function detectTaskMasterFolder(projectPath) {
197
183
 
198
184
  // Cache for extracted project directories
199
185
  const projectDirectoryCache = new Map();
186
+ const PROVIDER_SESSION_LOOKUP_CACHE_TTL_MS = 5000;
187
+ const providerSessionLookupCache = {
188
+ codex: { key: null, data: null, promise: null, expiresAt: 0 },
189
+ gemini: { key: null, data: null, promise: null, expiresAt: 0 },
190
+ opencode: { key: null, data: null, promise: null, expiresAt: 0 }
191
+ };
192
+
193
+ function normalizeComparableProjectPath(projectPath) {
194
+ if (typeof projectPath !== 'string' || !projectPath.trim()) {
195
+ return '';
196
+ }
197
+
198
+ const withoutWindowsLongPathPrefix = projectPath.startsWith('\\\\?\\')
199
+ ? projectPath.slice(4)
200
+ : projectPath;
201
+
202
+ return path.normalize(withoutWindowsLongPathPrefix);
203
+ }
204
+
205
+ function groupSessionsByNormalizedProjectPath(projectPaths, sessions, limit = 5) {
206
+ const groupedSessions = new Map();
207
+ const trackedPaths = new Set(
208
+ (projectPaths || [])
209
+ .map(normalizeComparableProjectPath)
210
+ .filter(Boolean)
211
+ );
212
+
213
+ for (const normalizedPath of trackedPaths) {
214
+ groupedSessions.set(normalizedPath, []);
215
+ }
216
+
217
+ for (const session of sessions) {
218
+ const normalizedCwd = normalizeComparableProjectPath(session?.cwd);
219
+ if (!normalizedCwd || !trackedPaths.has(normalizedCwd)) {
220
+ continue;
221
+ }
222
+
223
+ groupedSessions.get(normalizedCwd).push(session);
224
+ }
225
+
226
+ for (const [normalizedPath, grouped] of groupedSessions.entries()) {
227
+ grouped.sort((a, b) => new Date(b.lastActivity || 0) - new Date(a.lastActivity || 0));
228
+ groupedSessions.set(normalizedPath, limit > 0 ? grouped.slice(0, limit) : grouped);
229
+ }
230
+
231
+ return groupedSessions;
232
+ }
233
+
234
+ async function findFilesRecursively(rootDir, matcher) {
235
+ const discoveredFiles = [];
236
+
237
+ const walk = async (dir) => {
238
+ try {
239
+ const entries = await fs.readdir(dir, { withFileTypes: true });
240
+ for (const entry of entries) {
241
+ const fullPath = path.join(dir, entry.name);
242
+ if (entry.isDirectory()) {
243
+ await walk(fullPath);
244
+ } else if (matcher(entry.name, fullPath, entry)) {
245
+ discoveredFiles.push(fullPath);
246
+ }
247
+ }
248
+ } catch (_) {
249
+ // Skip unreadable directories without failing the whole discovery pass.
250
+ }
251
+ };
252
+
253
+ try {
254
+ await fs.access(rootDir);
255
+ } catch (_) {
256
+ return [];
257
+ }
258
+
259
+ await walk(rootDir);
260
+ return discoveredFiles;
261
+ }
200
262
 
201
263
  // Clear cache when needed (called when project files change)
202
264
  function clearProjectDirectoryCache() {
203
265
  projectDirectoryCache.clear();
204
266
  }
205
267
 
268
+ function clearProviderSessionLookupCaches() {
269
+ for (const cacheEntry of Object.values(providerSessionLookupCache)) {
270
+ cacheEntry.key = null;
271
+ cacheEntry.data = null;
272
+ cacheEntry.promise = null;
273
+ cacheEntry.expiresAt = 0;
274
+ }
275
+ }
276
+
277
+ async function getCachedProviderSessionLookup(providerName, cacheKey, buildLookup) {
278
+ const cacheEntry = providerSessionLookupCache[providerName];
279
+
280
+ if (!cacheEntry) {
281
+ return buildLookup();
282
+ }
283
+
284
+ if (
285
+ cacheEntry.key === cacheKey &&
286
+ cacheEntry.data &&
287
+ cacheEntry.expiresAt > Date.now()
288
+ ) {
289
+ return cacheEntry.data;
290
+ }
291
+
292
+ if (cacheEntry.key === cacheKey && cacheEntry.promise) {
293
+ return cacheEntry.promise;
294
+ }
295
+
296
+ cacheEntry.key = cacheKey;
297
+ cacheEntry.promise = Promise.resolve()
298
+ .then(buildLookup)
299
+ .then((lookup) => {
300
+ cacheEntry.data = lookup;
301
+ cacheEntry.expiresAt = Date.now() + PROVIDER_SESSION_LOOKUP_CACHE_TTL_MS;
302
+ return lookup;
303
+ })
304
+ .finally(() => {
305
+ cacheEntry.promise = null;
306
+ });
307
+
308
+ return cacheEntry.promise;
309
+ }
310
+
206
311
  // Load project configuration file
207
312
  async function loadProjectConfig() {
208
313
  const configPath = path.join(os.homedir(), '.claude', 'project-config.json');
@@ -385,6 +490,7 @@ async function getProjects(progressCallback = null) {
385
490
  const config = await loadProjectConfig();
386
491
  const projects = [];
387
492
  const existingProjects = new Set();
493
+ const projectDefinitions = [];
388
494
  let totalProjects = 0;
389
495
  let processedProjects = 0;
390
496
  let directories = [];
@@ -420,8 +526,6 @@ async function getProjects(progressCallback = null) {
420
526
  });
421
527
  }
422
528
 
423
- const projectPath = path.join(claudeDir, entry.name);
424
-
425
529
  // Extract actual project directory from JSONL sessions
426
530
  const actualProjectDir = await extractProjectDirectory(entry.name);
427
531
 
@@ -430,81 +534,14 @@ async function getProjects(progressCallback = null) {
430
534
  const autoDisplayName = await generateDisplayName(entry.name, actualProjectDir);
431
535
  const fullPath = actualProjectDir;
432
536
 
433
- const project = {
537
+ projectDefinitions.push({
434
538
  name: entry.name,
435
539
  path: actualProjectDir,
436
540
  displayName: customName || autoDisplayName,
437
541
  fullPath: fullPath,
438
542
  isCustomName: !!customName,
439
- sessions: [],
440
- cursorSessions: [],
441
- codexSessions: [],
442
- opencodeSessions: [],
443
- geminiSessions: []
444
- };
445
-
446
- // Try to get sessions for this project (just first 5 for performance)
447
- try {
448
- const sessionResult = await getSessions(entry.name, 5, 0);
449
- project.sessions = sessionResult.sessions || [];
450
- project.sessionMeta = {
451
- hasMore: sessionResult.hasMore,
452
- total: sessionResult.total
453
- };
454
- } catch (e) {
455
- console.warn(`Could not load sessions for project ${entry.name}:`, e.message);
456
- }
457
-
458
- // Also fetch Cursor sessions for this project
459
- try {
460
- project.cursorSessions = await getCursorSessions(actualProjectDir);
461
- } catch (e) {
462
- console.warn(`Could not load Cursor sessions for project ${entry.name}:`, e.message);
463
- project.cursorSessions = [];
464
- }
465
-
466
- // Also fetch Codex sessions for this project
467
- try {
468
- project.codexSessions = await getCodexSessions(actualProjectDir);
469
- } catch (e) {
470
- console.warn(`Could not load Codex sessions for project ${entry.name}:`, e.message);
471
- project.codexSessions = [];
472
- }
473
-
474
- try {
475
- project.geminiSessions = await getGeminiSessions(actualProjectDir);
476
- } catch (e) {
477
- console.warn(`Could not load Gemini sessions for project ${entry.name}:`, e.message);
478
- project.geminiSessions = [];
479
- }
480
-
481
- try {
482
- project.opencodeSessions = await getOpencodeSessions(actualProjectDir);
483
- } catch (e) {
484
- console.warn(`Could not load OpenCode sessions for project ${entry.name}:`, e.message);
485
- project.opencodeSessions = [];
486
- }
487
-
488
- // Add TaskMaster detection
489
- try {
490
- const taskMasterResult = await detectTaskMasterFolder(actualProjectDir);
491
- project.taskmaster = {
492
- hasTaskmaster: taskMasterResult.hasTaskmaster,
493
- hasEssentialFiles: taskMasterResult.hasEssentialFiles,
494
- metadata: taskMasterResult.metadata,
495
- status: taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles ? 'configured' : 'not-configured'
496
- };
497
- } catch (e) {
498
- console.warn(`Could not detect TaskMaster for project ${entry.name}:`, e.message);
499
- project.taskmaster = {
500
- hasTaskmaster: false,
501
- hasEssentialFiles: false,
502
- metadata: null,
503
- status: 'error'
504
- };
505
- }
506
-
507
- projects.push(project);
543
+ isManuallyAdded: false
544
+ });
508
545
  }
509
546
  } catch (error) {
510
547
  // If the directory doesn't exist (ENOENT), that's okay - just continue with empty projects
@@ -544,74 +581,80 @@ async function getProjects(progressCallback = null) {
544
581
  }
545
582
  }
546
583
 
547
- const project = {
584
+ projectDefinitions.push({
548
585
  name: projectName,
549
586
  path: actualProjectDir,
550
587
  displayName: projectConfig.displayName || await generateDisplayName(projectName, actualProjectDir),
551
588
  fullPath: actualProjectDir,
552
589
  isCustomName: !!projectConfig.displayName,
553
- isManuallyAdded: true,
554
- sessions: [],
555
- cursorSessions: [],
556
- codexSessions: [],
557
- opencodeSessions: [],
558
- geminiSessions: []
559
- };
560
-
561
- // Try to fetch Cursor sessions for manual projects too
562
- try {
563
- project.cursorSessions = await getCursorSessions(actualProjectDir);
564
- } catch (e) {
565
- console.warn(`Could not load Cursor sessions for manual project ${projectName}:`, e.message);
566
- }
567
-
568
- // Try to fetch Codex sessions for manual projects too
569
- try {
570
- project.codexSessions = await getCodexSessions(actualProjectDir);
571
- } catch (e) {
572
- console.warn(`Could not load Codex sessions for manual project ${projectName}:`, e.message);
573
- }
590
+ isManuallyAdded: true
591
+ });
592
+ }
593
+ }
574
594
 
575
- try {
576
- project.geminiSessions = await getGeminiSessions(actualProjectDir);
577
- } catch (e) {
578
- console.warn(`Could not load Gemini sessions for manual project ${projectName}:`, e.message);
579
- }
595
+ const uniqueProjectPaths = Array.from(new Set(
596
+ projectDefinitions
597
+ .map((definition) => normalizeComparableProjectPath(definition.fullPath))
598
+ .filter(Boolean)
599
+ ));
600
+
601
+ const [codexSessionsByProjectPath, geminiSessionsByProjectPath, opencodeSessionsByProjectPath] = await Promise.all([
602
+ buildCodexSessionsLookup(uniqueProjectPaths, { limit: 5 }),
603
+ buildGeminiSessionsLookup(uniqueProjectPaths, { limit: 5 }),
604
+ buildOpencodeSessionsLookup(uniqueProjectPaths, { limit: 5 })
605
+ ]);
606
+
607
+ for (const definition of projectDefinitions) {
608
+ const normalizedProjectPath = normalizeComparableProjectPath(definition.fullPath);
609
+ const project = {
610
+ name: definition.name,
611
+ path: definition.path,
612
+ displayName: definition.displayName,
613
+ fullPath: definition.fullPath,
614
+ isCustomName: definition.isCustomName,
615
+ isManuallyAdded: !!definition.isManuallyAdded,
616
+ sessions: [],
617
+ codexSessions: codexSessionsByProjectPath.get(normalizedProjectPath) || [],
618
+ opencodeSessions: opencodeSessionsByProjectPath.get(normalizedProjectPath) || [],
619
+ geminiSessions: geminiSessionsByProjectPath.get(normalizedProjectPath) || []
620
+ };
580
621
 
622
+ if (!definition.isManuallyAdded) {
581
623
  try {
582
- project.opencodeSessions = await getOpencodeSessions(actualProjectDir);
624
+ const sessionResult = await getSessions(definition.name, 5, 0);
625
+ project.sessions = sessionResult.sessions || [];
626
+ project.sessionMeta = {
627
+ hasMore: sessionResult.hasMore,
628
+ total: sessionResult.total
629
+ };
583
630
  } catch (e) {
584
- console.warn(`Could not load OpenCode sessions for manual project ${projectName}:`, e.message);
631
+ console.warn(`Could not load sessions for project ${definition.name}:`, e.message);
585
632
  }
633
+ }
586
634
 
587
- // Add TaskMaster detection for manual projects
588
- try {
589
- const taskMasterResult = await detectTaskMasterFolder(actualProjectDir);
590
-
591
- // Determine TaskMaster status
592
- let taskMasterStatus = 'not-configured';
593
- if (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles) {
594
- taskMasterStatus = 'taskmaster-only'; // We don't check MCP for manual projects in bulk
595
- }
596
-
597
- project.taskmaster = {
598
- status: taskMasterStatus,
599
- hasTaskmaster: taskMasterResult.hasTaskmaster,
600
- hasEssentialFiles: taskMasterResult.hasEssentialFiles,
601
- metadata: taskMasterResult.metadata
602
- };
603
- } catch (error) {
604
- console.warn(`TaskMaster detection failed for manual project ${projectName}:`, error.message);
605
- project.taskmaster = {
606
- status: 'error',
607
- hasTaskmaster: false,
608
- hasEssentialFiles: false,
609
- error: error.message
610
- };
611
- }
612
-
613
- projects.push(project);
635
+ try {
636
+ const taskMasterResult = await detectTaskMasterFolder(definition.fullPath);
637
+ const taskMasterStatus = definition.isManuallyAdded
638
+ ? (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles ? 'taskmaster-only' : 'not-configured')
639
+ : (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles ? 'configured' : 'not-configured');
640
+
641
+ project.taskmaster = {
642
+ status: taskMasterStatus,
643
+ hasTaskmaster: taskMasterResult.hasTaskmaster,
644
+ hasEssentialFiles: taskMasterResult.hasEssentialFiles,
645
+ metadata: taskMasterResult.metadata
646
+ };
647
+ } catch (error) {
648
+ console.warn(`TaskMaster detection failed for project ${definition.name}:`, error.message);
649
+ project.taskmaster = {
650
+ status: 'error',
651
+ hasTaskmaster: false,
652
+ hasEssentialFiles: false,
653
+ error: error.message
654
+ };
614
655
  }
656
+
657
+ projects.push(project);
615
658
  }
616
659
 
617
660
  // Emit completion after all projects (including manual) are processed
@@ -1094,15 +1137,6 @@ async function deleteProject(projectName, force = false) {
1094
1137
  } catch (err) {
1095
1138
  console.warn('Failed to delete Codex sessions:', err.message);
1096
1139
  }
1097
-
1098
- // Delete Cursor sessions directory if it exists
1099
- try {
1100
- const hash = crypto.createHash('md5').update(projectPath).digest('hex');
1101
- const cursorProjectDir = path.join(os.homedir(), '.cursor', 'chats', hash);
1102
- await fs.rm(cursorProjectDir, { recursive: true, force: true });
1103
- } catch (err) {
1104
- // Cursor dir may not exist, ignore
1105
- }
1106
1140
  }
1107
1141
 
1108
1142
  // Remove from project config
@@ -1139,7 +1173,7 @@ async function addProjectManually(projectPath, displayName = null) {
1139
1173
  }
1140
1174
 
1141
1175
  // Allow adding projects even if the directory exists - this enables tracking
1142
- // existing Claude Code or Cursor projects in the UI
1176
+ // existing Claude Code projects in the UI
1143
1177
 
1144
1178
  // Add to config as manually added project
1145
1179
  config[projectName] = {
@@ -1160,174 +1194,28 @@ async function addProjectManually(projectPath, displayName = null) {
1160
1194
  fullPath: absolutePath,
1161
1195
  displayName: displayName || await generateDisplayName(projectName, absolutePath),
1162
1196
  isManuallyAdded: true,
1163
- sessions: [],
1164
- cursorSessions: [],
1165
- codexSessions: [],
1197
+ sessions: [], codexSessions: [],
1166
1198
  opencodeSessions: [],
1167
1199
  geminiSessions: []
1168
1200
  };
1169
1201
  }
1170
1202
 
1171
- // Fetch Cursor sessions for a given project path
1172
- async function getCursorSessions(projectPath) {
1173
- try {
1174
- // Calculate cwdID hash for the project path (Cursor uses MD5 hash)
1175
- const cwdId = crypto.createHash('md5').update(projectPath).digest('hex');
1176
- const cursorChatsPath = path.join(os.homedir(), '.cursor', 'chats', cwdId);
1177
-
1178
- // Check if the directory exists
1179
- try {
1180
- await fs.access(cursorChatsPath);
1181
- } catch (error) {
1182
- // No sessions for this project
1183
- return [];
1184
- }
1185
-
1186
- // List all session directories
1187
- const sessionDirs = await fs.readdir(cursorChatsPath);
1188
- const sessions = [];
1189
-
1190
- for (const sessionId of sessionDirs) {
1191
- const sessionPath = path.join(cursorChatsPath, sessionId);
1192
- const storeDbPath = path.join(sessionPath, 'store.db');
1193
-
1194
- try {
1195
- // Check if store.db exists
1196
- await fs.access(storeDbPath);
1197
-
1198
- // Capture store.db mtime as a reliable fallback timestamp
1199
- let dbStatMtimeMs = null;
1200
- try {
1201
- const stat = await fs.stat(storeDbPath);
1202
- dbStatMtimeMs = stat.mtimeMs;
1203
- } catch (_) {}
1204
-
1205
- // Open SQLite database
1206
- const db = await open({
1207
- filename: storeDbPath,
1208
- driver: sqlite3.Database,
1209
- mode: sqlite3.OPEN_READONLY
1210
- });
1211
-
1212
- // Get metadata from meta table
1213
- const metaRows = await db.all(`
1214
- SELECT key, value FROM meta
1215
- `);
1216
-
1217
- // Parse metadata
1218
- let metadata = {};
1219
- for (const row of metaRows) {
1220
- if (row.value) {
1221
- try {
1222
- // Try to decode as hex-encoded JSON
1223
- const hexMatch = row.value.toString().match(/^[0-9a-fA-F]+$/);
1224
- if (hexMatch) {
1225
- const jsonStr = Buffer.from(row.value, 'hex').toString('utf8');
1226
- metadata[row.key] = JSON.parse(jsonStr);
1227
- } else {
1228
- metadata[row.key] = row.value.toString();
1229
- }
1230
- } catch (e) {
1231
- metadata[row.key] = row.value.toString();
1232
- }
1233
- }
1234
- }
1235
-
1236
- // Get message count
1237
- const messageCountResult = await db.get(`
1238
- SELECT COUNT(*) as count FROM blobs
1239
- `);
1240
-
1241
- await db.close();
1242
-
1243
- // Extract session info
1244
- const sessionName = metadata.title || metadata.sessionTitle || 'Untitled Session';
1245
-
1246
- // Determine timestamp - prefer createdAt from metadata, fall back to db file mtime
1247
- let createdAt = null;
1248
- if (metadata.createdAt) {
1249
- createdAt = new Date(metadata.createdAt).toISOString();
1250
- } else if (dbStatMtimeMs) {
1251
- createdAt = new Date(dbStatMtimeMs).toISOString();
1252
- } else {
1253
- createdAt = new Date().toISOString();
1254
- }
1255
-
1256
- sessions.push({
1257
- id: sessionId,
1258
- name: sessionName,
1259
- createdAt: createdAt,
1260
- lastActivity: createdAt, // For compatibility with Claude sessions
1261
- messageCount: messageCountResult.count || 0,
1262
- projectPath: projectPath
1263
- });
1264
-
1265
- } catch (error) {
1266
- console.warn(`Could not read Cursor session ${sessionId}:`, error.message);
1267
- }
1268
- }
1269
-
1270
- // Sort sessions by creation time (newest first)
1271
- sessions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
1272
-
1273
- // Return only the first 5 sessions for performance
1274
- return sessions.slice(0, 5);
1275
-
1276
- } catch (error) {
1277
- console.error('Error fetching Cursor sessions:', error);
1278
- return [];
1279
- }
1280
- }
1281
-
1282
-
1283
- // Fetch Codex sessions for a given project path
1284
1203
  async function getCodexSessions(projectPath, options = {}) {
1285
1204
  const { limit = 5 } = options;
1286
1205
  try {
1287
- const codexSessionsDir = path.join(os.homedir(), '.codex', 'sessions');
1288
1206
  const sessions = [];
1289
-
1290
- // Check if the directory exists
1291
- try {
1292
- await fs.access(codexSessionsDir);
1293
- } catch (error) {
1294
- // No Codex sessions directory
1295
- return [];
1296
- }
1297
-
1298
- // Recursively find all .jsonl files in the sessions directory
1299
- const findJsonlFiles = async (dir) => {
1300
- const files = [];
1301
- try {
1302
- const entries = await fs.readdir(dir, { withFileTypes: true });
1303
- for (const entry of entries) {
1304
- const fullPath = path.join(dir, entry.name);
1305
- if (entry.isDirectory()) {
1306
- files.push(...await findJsonlFiles(fullPath));
1307
- } else if (entry.name.endsWith('.jsonl')) {
1308
- files.push(fullPath);
1309
- }
1310
- }
1311
- } catch (error) {
1312
- // Skip directories we can't read
1313
- }
1314
- return files;
1315
- };
1316
-
1317
- const jsonlFiles = await findJsonlFiles(codexSessionsDir);
1207
+ const normalizedProjectPath = normalizeComparableProjectPath(projectPath);
1208
+ const jsonlFiles = await findFilesRecursively(
1209
+ path.join(os.homedir(), '.codex', 'sessions'),
1210
+ (entryName) => entryName.endsWith('.jsonl')
1211
+ );
1318
1212
 
1319
1213
  // Process each file to find sessions matching the project path
1320
1214
  for (const filePath of jsonlFiles) {
1321
1215
  try {
1322
1216
  const sessionData = await parseCodexSessionFile(filePath);
1323
1217
 
1324
- // Check if this session matches the project path
1325
- // Handle Windows long paths with \\?\ prefix
1326
- const sessionCwd = sessionData?.cwd || '';
1327
- const cleanSessionCwd = sessionCwd.startsWith('\\\\?\\') ? sessionCwd.slice(4) : sessionCwd;
1328
- const cleanProjectPath = projectPath.startsWith('\\\\?\\') ? projectPath.slice(4) : projectPath;
1329
-
1330
- if (sessionData && (sessionData.cwd === projectPath || cleanSessionCwd === cleanProjectPath || path.relative(cleanSessionCwd, cleanProjectPath) === '')) {
1218
+ if (sessionData && normalizeComparableProjectPath(sessionData.cwd) === normalizedProjectPath) {
1331
1219
  sessions.push({
1332
1220
  id: sessionData.id,
1333
1221
  summary: sessionData.summary || 'Codex Session',
@@ -1364,25 +1252,12 @@ const OPENCODE_SESSION_DIR_CANDIDATES = [
1364
1252
  async function findOpencodeSessionFiles() {
1365
1253
  const files = [];
1366
1254
 
1367
- const walk = async (dirPath) => {
1368
- try {
1369
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
1370
- for (const entry of entries) {
1371
- const fullPath = path.join(dirPath, entry.name);
1372
- if (entry.isDirectory()) {
1373
- await walk(fullPath);
1374
- } else if (entry.isFile() && entry.name.endsWith('.jsonl')) {
1375
- files.push(fullPath);
1376
- }
1377
- }
1378
- } catch (_) {}
1379
- };
1380
-
1381
1255
  for (const baseDir of OPENCODE_SESSION_DIR_CANDIDATES) {
1382
- try {
1383
- await fs.access(baseDir);
1384
- await walk(baseDir);
1385
- } catch (_) {}
1256
+ const discovered = await findFilesRecursively(
1257
+ baseDir,
1258
+ (entryName, _fullPath, entry) => entry.isFile() && entryName.endsWith('.jsonl')
1259
+ );
1260
+ files.push(...discovered);
1386
1261
  }
1387
1262
 
1388
1263
  return Array.from(new Set(files));
@@ -1852,6 +1727,120 @@ async function parseGeminiSessionFile(filePath) {
1852
1727
  };
1853
1728
  }
1854
1729
 
1730
+ async function buildCodexSessionsLookup(projectPaths, options = {}) {
1731
+ const { limit = 5 } = options;
1732
+ const normalizedProjectPaths = Array.from(new Set(
1733
+ (projectPaths || []).map(normalizeComparableProjectPath).filter(Boolean)
1734
+ ));
1735
+
1736
+ if (normalizedProjectPaths.length === 0) {
1737
+ return new Map();
1738
+ }
1739
+
1740
+ const cacheKey = JSON.stringify({ projectPaths: normalizedProjectPaths, limit });
1741
+ return getCachedProviderSessionLookup('codex', cacheKey, async () => {
1742
+ const jsonlFiles = await findFilesRecursively(
1743
+ path.join(os.homedir(), '.codex', 'sessions'),
1744
+ (entryName) => entryName.endsWith('.jsonl')
1745
+ );
1746
+
1747
+ const sessions = [];
1748
+ for (const filePath of jsonlFiles) {
1749
+ try {
1750
+ const sessionData = await parseCodexSessionFile(filePath);
1751
+ if (sessionData?.id) {
1752
+ sessions.push({
1753
+ id: sessionData.id,
1754
+ summary: sessionData.summary || 'Codex Session',
1755
+ messageCount: sessionData.messageCount || 0,
1756
+ lastActivity: sessionData.timestamp ? new Date(sessionData.timestamp) : new Date(),
1757
+ cwd: sessionData.cwd,
1758
+ model: sessionData.model,
1759
+ filePath,
1760
+ provider: 'codex'
1761
+ });
1762
+ }
1763
+ } catch (error) {
1764
+ console.warn(`Could not parse Codex session file ${filePath}:`, error.message);
1765
+ }
1766
+ }
1767
+
1768
+ return groupSessionsByNormalizedProjectPath(normalizedProjectPaths, sessions, limit);
1769
+ });
1770
+ }
1771
+
1772
+ async function buildOpencodeSessionsLookup(projectPaths, options = {}) {
1773
+ const { limit = 5 } = options;
1774
+ const normalizedProjectPaths = Array.from(new Set(
1775
+ (projectPaths || []).map(normalizeComparableProjectPath).filter(Boolean)
1776
+ ));
1777
+
1778
+ if (normalizedProjectPaths.length === 0) {
1779
+ return new Map();
1780
+ }
1781
+
1782
+ const cacheKey = JSON.stringify({ projectPaths: normalizedProjectPaths, limit });
1783
+ return getCachedProviderSessionLookup('opencode', cacheKey, async () => {
1784
+ const sessionFiles = await findOpencodeSessionFiles();
1785
+ const sessions = [];
1786
+
1787
+ for (const filePath of sessionFiles) {
1788
+ const sessionData = await parseOpencodeSessionFile(filePath);
1789
+ if (sessionData?.id) {
1790
+ sessions.push(sessionData);
1791
+ }
1792
+ }
1793
+
1794
+ return groupSessionsByNormalizedProjectPath(normalizedProjectPaths, sessions, limit);
1795
+ });
1796
+ }
1797
+
1798
+ async function buildGeminiSessionsLookup(projectPaths, options = {}) {
1799
+ const { limit = 5 } = options;
1800
+ const normalizedProjectPaths = Array.from(new Set(
1801
+ (projectPaths || []).map(normalizeComparableProjectPath).filter(Boolean)
1802
+ ));
1803
+
1804
+ const cacheKey = JSON.stringify({ projectPaths: normalizedProjectPaths, limit });
1805
+ return getCachedProviderSessionLookup('gemini', cacheKey, async () => {
1806
+ const sessionsByProjectPath = new Map();
1807
+
1808
+ for (const normalizedProjectPath of normalizedProjectPaths) {
1809
+ const projectHash = crypto.createHash('sha256').update(normalizedProjectPath).digest('hex');
1810
+ const chatsDir = path.join(os.homedir(), '.gemini', 'tmp', projectHash, 'chats');
1811
+
1812
+ try {
1813
+ const entries = await fs.readdir(chatsDir, { withFileTypes: true });
1814
+ const sessionFiles = entries
1815
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.json'))
1816
+ .map((entry) => path.join(chatsDir, entry.name));
1817
+
1818
+ const sessions = [];
1819
+ for (const filePath of sessionFiles) {
1820
+ try {
1821
+ const sessionData = await parseGeminiSessionFile(filePath);
1822
+ if (sessionData?.id) {
1823
+ sessions.push(sessionData);
1824
+ }
1825
+ } catch (error) {
1826
+ console.warn(`Could not parse Gemini session file ${filePath}:`, error.message);
1827
+ }
1828
+ }
1829
+
1830
+ sessions.sort((a, b) => new Date(b.lastActivity || 0) - new Date(a.lastActivity || 0));
1831
+ sessionsByProjectPath.set(
1832
+ normalizedProjectPath,
1833
+ limit > 0 ? sessions.slice(0, limit) : sessions
1834
+ );
1835
+ } catch (_) {
1836
+ sessionsByProjectPath.set(normalizedProjectPath, []);
1837
+ }
1838
+ }
1839
+
1840
+ return sessionsByProjectPath;
1841
+ });
1842
+ }
1843
+
1855
1844
  async function getGeminiSessionMessages(sessionId, limit = null, offset = 0) {
1856
1845
  try {
1857
1846
  const geminiTmpDir = path.join(os.homedir(), '.gemini', 'tmp');
@@ -1966,9 +1955,16 @@ async function parseCodexSessionFile(filePath) {
1966
1955
  crlfDelay: Infinity
1967
1956
  });
1968
1957
 
1958
+ const isUsableCodexModel = (value) => {
1959
+ if (typeof value !== 'string') return false;
1960
+ const normalized = value.trim().toLowerCase();
1961
+ return normalized.length > 0 && normalized !== 'custom' && normalized !== 'default';
1962
+ };
1963
+
1969
1964
  let sessionMeta = null;
1970
1965
  let lastTimestamp = null;
1971
1966
  let lastUserMessage = null;
1967
+ let lastResolvedModel = null;
1972
1968
  let messageCount = 0;
1973
1969
 
1974
1970
  for await (const line of rl) {
@@ -1990,6 +1986,16 @@ async function parseCodexSessionFile(filePath) {
1990
1986
  timestamp: entry.timestamp,
1991
1987
  git: entry.payload.git
1992
1988
  };
1989
+
1990
+ if (isUsableCodexModel(entry.payload.model)) {
1991
+ lastResolvedModel = entry.payload.model;
1992
+ } else if (isUsableCodexModel(entry.payload.model_provider)) {
1993
+ lastResolvedModel = entry.payload.model_provider;
1994
+ }
1995
+ }
1996
+
1997
+ if (entry.type === 'turn_context' && isUsableCodexModel(entry.payload?.model)) {
1998
+ lastResolvedModel = entry.payload.model;
1993
1999
  }
1994
2000
 
1995
2001
  // Count messages and extract user messages for summary
@@ -2013,6 +2019,7 @@ async function parseCodexSessionFile(filePath) {
2013
2019
  if (sessionMeta) {
2014
2020
  return {
2015
2021
  ...sessionMeta,
2022
+ model: lastResolvedModel || sessionMeta.model || null,
2016
2023
  timestamp: lastTimestamp || sessionMeta.timestamp,
2017
2024
  summary: lastUserMessage ?
2018
2025
  (lastUserMessage.length > 50 ? lastUserMessage.substring(0, 50) + '...' : lastUserMessage) :
@@ -2309,10 +2316,12 @@ export {
2309
2316
  saveProjectConfig,
2310
2317
  extractProjectDirectory,
2311
2318
  clearProjectDirectoryCache,
2319
+ clearProviderSessionLookupCaches,
2312
2320
  getCodexSessions,
2313
2321
  getCodexSessionMessages,
2314
2322
  getOpencodeSessions,
2315
2323
  getOpencodeSessionMessages,
2324
+ getGeminiSessions,
2316
2325
  getGeminiSessionMessages,
2317
2326
  deleteCodexSession,
2318
2327
  deleteOpencodeSession