@sanurb/ringi 0.2.0 → 0.3.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 (423) hide show
  1. package/dist/cli.mjs +2132 -0
  2. package/dist/cli.mjs.map +1 -0
  3. package/dist/mcp.mjs +1057 -0
  4. package/dist/mcp.mjs.map +1 -0
  5. package/dist/runtime.mjs +3116 -0
  6. package/dist/runtime.mjs.map +1 -0
  7. package/package.json +15 -14
  8. package/server/nitro.json +17 -0
  9. package/server/public/assets/ClientOnly-QdfAxyFs.js +1 -0
  10. package/server/public/assets/_reviewId-CmXHvWLn.js +1 -0
  11. package/server/public/assets/_reviewId-DdOpDx4U.js +1 -0
  12. package/server/public/assets/abap-B1dkBSPn.js +1 -0
  13. package/server/public/assets/action-bar-DLRNvLjj.js +45 -0
  14. package/server/public/assets/actionscript-3-BT4ibYlP.js +1 -0
  15. package/server/public/assets/ada-CD92zeps.js +1 -0
  16. package/server/public/assets/andromeeda-DqSmgxi0.js +1 -0
  17. package/server/public/assets/angular-html-BDC0PfKr.js +1 -0
  18. package/server/public/assets/angular-ts-B9yoQMtj.js +1 -0
  19. package/server/public/assets/apache-D5suuoa_.js +1 -0
  20. package/server/public/assets/apex-BL-m4VHy.js +1 -0
  21. package/server/public/assets/apl-CldhY0Pn.js +1 -0
  22. package/server/public/assets/applescript-CLiBqvKT.js +1 -0
  23. package/server/public/assets/ara-LdDF8cmv.js +1 -0
  24. package/server/public/assets/asciidoc-2DZ9hC2N.js +1 -0
  25. package/server/public/assets/asm-0ZPGRSUy.js +1 -0
  26. package/server/public/assets/astro-DR6labZJ.js +1 -0
  27. package/server/public/assets/aurora-x-Da7Zfvbg.js +1 -0
  28. package/server/public/assets/awk-Bn0gn_B_.js +1 -0
  29. package/server/public/assets/ayu-dark-bqYKoqpM.js +1 -0
  30. package/server/public/assets/ayu-light-C45jTIzZ.js +1 -0
  31. package/server/public/assets/ayu-mirage-BV_FCTQi.js +1 -0
  32. package/server/public/assets/ballerina-D2nw_w8Q.js +1 -0
  33. package/server/public/assets/bat-ByUBN5gS.js +1 -0
  34. package/server/public/assets/beancount-BTb2W6Mp.js +1 -0
  35. package/server/public/assets/berry-5SO2uITG.js +1 -0
  36. package/server/public/assets/bibtex-CDBTNfUI.js +1 -0
  37. package/server/public/assets/bicep-fgxG_4rP.js +1 -0
  38. package/server/public/assets/bird2-BCwzDhwX.js +1 -0
  39. package/server/public/assets/blade-BBTRu2-g.js +1 -0
  40. package/server/public/assets/bsl-CG-fq4sc.js +1 -0
  41. package/server/public/assets/c-CEvNj7xl.js +1 -0
  42. package/server/public/assets/c3-Dlaci63_.js +1 -0
  43. package/server/public/assets/cadence-DHbRuEmm.js +1 -0
  44. package/server/public/assets/cairo-Ds0kTeYT.js +1 -0
  45. package/server/public/assets/catppuccin-frappe-DrL1fUuH.js +1 -0
  46. package/server/public/assets/catppuccin-latte-C0REgVjl.js +1 -0
  47. package/server/public/assets/catppuccin-macchiato-ChQpylWO.js +1 -0
  48. package/server/public/assets/catppuccin-mocha-Dd0JU1T0.js +1 -0
  49. package/server/public/assets/clarity-DMoTOm4G.js +1 -0
  50. package/server/public/assets/clojure-DBhE3PpS.js +1 -0
  51. package/server/public/assets/cmake-DwMc40Or.js +1 -0
  52. package/server/public/assets/cobol-BdNJSMRt.js +1 -0
  53. package/server/public/assets/codeowners-1lVr8wqV.js +1 -0
  54. package/server/public/assets/codeql-DWflolvo.js +1 -0
  55. package/server/public/assets/coffee-RA4xA24H.js +1 -0
  56. package/server/public/assets/common-lisp-CrVQ5xT-.js +1 -0
  57. package/server/public/assets/compiler-runtime-DZXZ41-q.js +1 -0
  58. package/server/public/assets/coq-CjfoyYSh.js +1 -0
  59. package/server/public/assets/cpp-BoW7e2Ow.js +1 -0
  60. package/server/public/assets/createServerFn-DTk395iP.js +9 -0
  61. package/server/public/assets/crystal-CYKRo3F9.js +1 -0
  62. package/server/public/assets/csharp-C7bIWP5y.js +1 -0
  63. package/server/public/assets/css-Ck2tii2d.js +1 -0
  64. package/server/public/assets/csv-DsAkDVtA.js +1 -0
  65. package/server/public/assets/cue-BWmQgbOB.js +1 -0
  66. package/server/public/assets/cypher-D-jVC50Q.js +1 -0
  67. package/server/public/assets/d-CaviyOrm.js +1 -0
  68. package/server/public/assets/dark-plus-DIrnwZt9.js +1 -0
  69. package/server/public/assets/dart-CZEi7JgC.js +1 -0
  70. package/server/public/assets/dax-BK-8zffy.js +1 -0
  71. package/server/public/assets/desktop-D3cjbL4D.js +1 -0
  72. package/server/public/assets/diff-sHAzLvlp.js +1 -0
  73. package/server/public/assets/docker--xs2Ng3w.js +1 -0
  74. package/server/public/assets/dotenv-Cm4nwcJ7.js +1 -0
  75. package/server/public/assets/dracula-CAUSusef.js +1 -0
  76. package/server/public/assets/dracula-soft-cjNkMFza.js +1 -0
  77. package/server/public/assets/dream-maker-fjmWTFCO.js +1 -0
  78. package/server/public/assets/edge-DxycC9wl.js +1 -0
  79. package/server/public/assets/elixir-B-50Er3p.js +1 -0
  80. package/server/public/assets/elm-B4-ygIVo.js +1 -0
  81. package/server/public/assets/emacs-lisp-CJzqStIa.js +1 -0
  82. package/server/public/assets/erb-DJvYE1L1.js +1 -0
  83. package/server/public/assets/erlang-C-m_88FN.js +1 -0
  84. package/server/public/assets/everforest-dark-DBpaSMx1.js +1 -0
  85. package/server/public/assets/everforest-light-CiGrXwia.js +1 -0
  86. package/server/public/assets/fennel-DRaXF7k8.js +1 -0
  87. package/server/public/assets/file-tree-CI3Xwwid.js +1907 -0
  88. package/server/public/assets/fish-Bn-Yh3Jj.js +1 -0
  89. package/server/public/assets/fluent-DF5F8Ks_.js +1 -0
  90. package/server/public/assets/fortran-fixed-form-Cx1lv7HN.js +1 -0
  91. package/server/public/assets/fortran-free-form-hCQHRqew.js +1 -0
  92. package/server/public/assets/fsharp-DC5k9sy2.js +1 -0
  93. package/server/public/assets/gdresource-D0EsKdgH.js +1 -0
  94. package/server/public/assets/gdscript-_C9_Hi_w.js +1 -0
  95. package/server/public/assets/gdshader-BW7b1X1Y.js +1 -0
  96. package/server/public/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
  97. package/server/public/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
  98. package/server/public/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
  99. package/server/public/assets/genie-Ch_6TCHd.js +1 -0
  100. package/server/public/assets/gherkin-CaNUsmTq.js +1 -0
  101. package/server/public/assets/git-commit-BcFsuO5E.js +1 -0
  102. package/server/public/assets/git-rebase-ChGA-z50.js +1 -0
  103. package/server/public/assets/github-dark-B9ygjgg6.js +1 -0
  104. package/server/public/assets/github-dark-default-Br2bgYSx.js +1 -0
  105. package/server/public/assets/github-dark-dimmed-CmtqpPJ-.js +1 -0
  106. package/server/public/assets/github-dark-high-contrast-fSfmrZcC.js +1 -0
  107. package/server/public/assets/github-light-BZjUqfZl.js +1 -0
  108. package/server/public/assets/github-light-default-lIytXXhR.js +1 -0
  109. package/server/public/assets/github-light-high-contrast-BRrjFb7n.js +1 -0
  110. package/server/public/assets/gleam-DALMDpNs.js +1 -0
  111. package/server/public/assets/glimmer-js-maLb6ysA.js +1 -0
  112. package/server/public/assets/glimmer-ts-DGNr-OBA.js +1 -0
  113. package/server/public/assets/glsl-CmplqyQ1.js +1 -0
  114. package/server/public/assets/gn-DGjqrYN9.js +1 -0
  115. package/server/public/assets/gnuplot-BYckvgQI.js +1 -0
  116. package/server/public/assets/go-JycvP538.js +1 -0
  117. package/server/public/assets/graphql-VhP7n4--.js +1 -0
  118. package/server/public/assets/groovy-D5qMRONT.js +1 -0
  119. package/server/public/assets/gruvbox-dark-hard-M1dj1e6V.js +1 -0
  120. package/server/public/assets/gruvbox-dark-medium-cqq_ncQu.js +1 -0
  121. package/server/public/assets/gruvbox-dark-soft-B4QwL2a9.js +1 -0
  122. package/server/public/assets/gruvbox-light-hard-DLayMKOQ.js +1 -0
  123. package/server/public/assets/gruvbox-light-medium-D52XgPKf.js +1 -0
  124. package/server/public/assets/gruvbox-light-soft-Dola3KdD.js +1 -0
  125. package/server/public/assets/hack-BVSQ2bxM.js +1 -0
  126. package/server/public/assets/haml-CwTtRHoj.js +1 -0
  127. package/server/public/assets/handlebars-CcO01SVo.js +1 -0
  128. package/server/public/assets/haskell-ys7wPPEd.js +1 -0
  129. package/server/public/assets/haxe-94kiChn7.js +1 -0
  130. package/server/public/assets/hcl-DmHt_-wq.js +1 -0
  131. package/server/public/assets/hjson-xMmoJ0Gx.js +1 -0
  132. package/server/public/assets/hlsl-b-Pskdze.js +1 -0
  133. package/server/public/assets/horizon-BKMqttiR.js +1 -0
  134. package/server/public/assets/horizon-bright-HNkBlnm5.js +1 -0
  135. package/server/public/assets/houston-BkBSBSOQ.js +1 -0
  136. package/server/public/assets/html-derivative-Cz-cKMi2.js +1 -0
  137. package/server/public/assets/html-zQbUS8Is.js +1 -0
  138. package/server/public/assets/http-CaGQ9BgA.js +1 -0
  139. package/server/public/assets/hurl-BBoki9bg.js +1 -0
  140. package/server/public/assets/hxml-iQTOTWpM.js +1 -0
  141. package/server/public/assets/hy-DKl1XhBq.js +1 -0
  142. package/server/public/assets/imba-DPxkOTAg.js +1 -0
  143. package/server/public/assets/ini-lkLGq_1x.js +1 -0
  144. package/server/public/assets/java-LAx6oszV.js +1 -0
  145. package/server/public/assets/javascript-COqx-gKX.js +1 -0
  146. package/server/public/assets/jinja-x-G_qSCP.js +1 -0
  147. package/server/public/assets/jison-7oSeVkKJ.js +1 -0
  148. package/server/public/assets/json-sTLOVXhc.js +1 -0
  149. package/server/public/assets/json5-Cy6ypJuJ.js +1 -0
  150. package/server/public/assets/jsonc-Cw2ugYAK.js +1 -0
  151. package/server/public/assets/jsonl-Dp5_qBVH.js +1 -0
  152. package/server/public/assets/jsonnet-BTbmg_-u.js +1 -0
  153. package/server/public/assets/jssm-CnT7nPea.js +1 -0
  154. package/server/public/assets/jsx-zXeIBQLI.js +1 -0
  155. package/server/public/assets/julia-E-6Xm9nd.js +1 -0
  156. package/server/public/assets/just-D9n74gZy.js +1 -0
  157. package/server/public/assets/kanagawa-dragon-CxsBnuhV.js +1 -0
  158. package/server/public/assets/kanagawa-lotus-vHdxDDOS.js +1 -0
  159. package/server/public/assets/kanagawa-wave-CIkfTKWk.js +1 -0
  160. package/server/public/assets/kdl-BwK60g80.js +1 -0
  161. package/server/public/assets/kotlin-Dbd9Vi-v.js +1 -0
  162. package/server/public/assets/kusto-BuTk9usc.js +1 -0
  163. package/server/public/assets/laserwave-C0wf_d3o.js +1 -0
  164. package/server/public/assets/latex-D0t4RtEU.js +1 -0
  165. package/server/public/assets/lean-CYAW8bRN.js +1 -0
  166. package/server/public/assets/less-D4uen21c.js +1 -0
  167. package/server/public/assets/light-plus-oqYyWKEE.js +1 -0
  168. package/server/public/assets/liquid-BzXN12F6.js +1 -0
  169. package/server/public/assets/llvm-Z1xJzteV.js +1 -0
  170. package/server/public/assets/log-BGUxlsk3.js +1 -0
  171. package/server/public/assets/logo-wVUhvQ1b.js +1 -0
  172. package/server/public/assets/lua-B0Cg8RP4.js +1 -0
  173. package/server/public/assets/luau-rPFZzCmq.js +1 -0
  174. package/server/public/assets/main-FvxVz-kD.js +15 -0
  175. package/server/public/assets/make-BmPf6m0P.js +1 -0
  176. package/server/public/assets/markdown-AseU6zcW.js +1 -0
  177. package/server/public/assets/marko-BlRPXWOe.js +1 -0
  178. package/server/public/assets/material-theme-6_W6rQhR.js +1 -0
  179. package/server/public/assets/material-theme-darker-VPEo3Sem.js +1 -0
  180. package/server/public/assets/material-theme-lighter-CUhzCcZ9.js +1 -0
  181. package/server/public/assets/material-theme-ocean-B2JdsaGb.js +1 -0
  182. package/server/public/assets/material-theme-palenight-DhY-sklA.js +1 -0
  183. package/server/public/assets/matlab-BOj_BDQv.js +1 -0
  184. package/server/public/assets/mdc-FiVDZSZ4.js +1 -0
  185. package/server/public/assets/mdx-Cm6cDkDI.js +1 -0
  186. package/server/public/assets/mermaid-DLO-R4hv.js +1 -0
  187. package/server/public/assets/min-dark-D34a_pX7.js +1 -0
  188. package/server/public/assets/min-light-Cdd4KORE.js +1 -0
  189. package/server/public/assets/mipsasm-DYpHF-GA.js +1 -0
  190. package/server/public/assets/mojo-DqYVFv_G.js +1 -0
  191. package/server/public/assets/monokai-CDR4sQ2n.js +1 -0
  192. package/server/public/assets/moonbit-DRKee9wk.js +1 -0
  193. package/server/public/assets/move-DbRk6Vn9.js +1 -0
  194. package/server/public/assets/narrat-IOfmaXfb.js +1 -0
  195. package/server/public/assets/new-DOyplRwM.js +1 -0
  196. package/server/public/assets/nextflow-D-Ec_bsY.js +1 -0
  197. package/server/public/assets/nextflow-groovy-EYl0c2BQ.js +1 -0
  198. package/server/public/assets/nginx-3JLAqmJa.js +1 -0
  199. package/server/public/assets/night-owl-light-Bedht9b4.js +1 -0
  200. package/server/public/assets/night-owl-yQJ3-I0I.js +1 -0
  201. package/server/public/assets/nim-DyjFVMzT.js +1 -0
  202. package/server/public/assets/nix-C2IovEl2.js +1 -0
  203. package/server/public/assets/nord-BjZ63GNL.js +1 -0
  204. package/server/public/assets/nushell-BflTrRB5.js +1 -0
  205. package/server/public/assets/objective-c-GRClK1S7.js +1 -0
  206. package/server/public/assets/objective-cpp-l3qYw-v5.js +1 -0
  207. package/server/public/assets/ocaml-BBDyhyMH.js +1 -0
  208. package/server/public/assets/odin-jCJ7Js99.js +1 -0
  209. package/server/public/assets/one-dark-pro-PIx2Diul.js +1 -0
  210. package/server/public/assets/one-light-BFMEz49S.js +1 -0
  211. package/server/public/assets/openscad-Drf0LgCX.js +1 -0
  212. package/server/public/assets/pascal-BT2XAUTl.js +1 -0
  213. package/server/public/assets/perl-Dr47G_2Q.js +1 -0
  214. package/server/public/assets/php-BhBDWTJe.js +1 -0
  215. package/server/public/assets/pierre-dark-CTXzTLfO.js +1 -0
  216. package/server/public/assets/pierre-light-C_5rlJRo.js +1 -0
  217. package/server/public/assets/pkl-ML-dWShO.js +1 -0
  218. package/server/public/assets/plastic-BFI-Z5Z2.js +1 -0
  219. package/server/public/assets/plsql-0vd5cLro.js +1 -0
  220. package/server/public/assets/po-CbZ_uqQA.js +1 -0
  221. package/server/public/assets/poimandres-Cayhd01L.js +1 -0
  222. package/server/public/assets/polar-C4hfV8Nc.js +1 -0
  223. package/server/public/assets/postcss-osFUbTLw.js +1 -0
  224. package/server/public/assets/powerquery-CTlGUQPj.js +1 -0
  225. package/server/public/assets/powershell-DyZsOmuq.js +1 -0
  226. package/server/public/assets/preload-helper-D7oT-Xwl.js +20 -0
  227. package/server/public/assets/prisma-SS92PO_I.js +1 -0
  228. package/server/public/assets/prolog-B1O1NNVC.js +1 -0
  229. package/server/public/assets/proto-BWu3eZTs.js +1 -0
  230. package/server/public/assets/pug-Dij_IK5w.js +1 -0
  231. package/server/public/assets/puppet-tvtRVdr6.js +1 -0
  232. package/server/public/assets/purescript-Dtbpb7D-.js +1 -0
  233. package/server/public/assets/python-Dlk0Acio.js +1 -0
  234. package/server/public/assets/qml-qUwk3nhh.js +1 -0
  235. package/server/public/assets/qmldir-B-iEOngH.js +1 -0
  236. package/server/public/assets/qss-Ba0p-aHw.js +1 -0
  237. package/server/public/assets/r-WmtNicKM.js +1 -0
  238. package/server/public/assets/racket-BXDsxf2U.js +1 -0
  239. package/server/public/assets/raku-Dw1WWFXK.js +1 -0
  240. package/server/public/assets/razor-DaqiVx3Q.js +1 -0
  241. package/server/public/assets/red-BC3Ds49b.js +1 -0
  242. package/server/public/assets/reg-DXFHGaM4.js +1 -0
  243. package/server/public/assets/regexp-CiSWN5Ne.js +1 -0
  244. package/server/public/assets/rel-Dc5_Ytx2.js +1 -0
  245. package/server/public/assets/reviews-CJvVXRLH.js +1 -0
  246. package/server/public/assets/reviews-CfbuF6ib.js +1 -0
  247. package/server/public/assets/riscv-ZgswiWij.js +1 -0
  248. package/server/public/assets/ron-YghabWAH.js +1 -0
  249. package/server/public/assets/rose-pine-ByWLnVr3.js +1 -0
  250. package/server/public/assets/rose-pine-dawn-DBmeySrz.js +1 -0
  251. package/server/public/assets/rose-pine-moon-B9J-N3nK.js +1 -0
  252. package/server/public/assets/rosmsg-DTKmAsVH.js +1 -0
  253. package/server/public/assets/routes-DNxq1Fba.js +1 -0
  254. package/server/public/assets/routes-Dp0ODZ55.js +2 -0
  255. package/server/public/assets/rst-CP6xOYlY.js +1 -0
  256. package/server/public/assets/ruby-BXYLc1CM.js +1 -0
  257. package/server/public/assets/rust-nfXwuE6F.js +1 -0
  258. package/server/public/assets/sas-CFdtZutF.js +1 -0
  259. package/server/public/assets/sass-CbRjkld3.js +1 -0
  260. package/server/public/assets/scala-BzD3eypx.js +1 -0
  261. package/server/public/assets/scheme-D4d1PV1y.js +1 -0
  262. package/server/public/assets/scss-D8KhdObH.js +1 -0
  263. package/server/public/assets/sdbl-Cf-Ydnvx.js +1 -0
  264. package/server/public/assets/shaderlab-DGohHMiF.js +1 -0
  265. package/server/public/assets/shellscript-BHdEbumI.js +1 -0
  266. package/server/public/assets/shellsession-Dh-bxrap.js +1 -0
  267. package/server/public/assets/slack-dark-MszIyPZ2.js +1 -0
  268. package/server/public/assets/slack-ochin-tQ3Q0gE9.js +1 -0
  269. package/server/public/assets/smalltalk-_uWoArwn.js +1 -0
  270. package/server/public/assets/snazzy-light-9sniMEk5.js +1 -0
  271. package/server/public/assets/solarized-dark-CdD0Hxzv.js +1 -0
  272. package/server/public/assets/solarized-light-C-nsEdqF.js +1 -0
  273. package/server/public/assets/solidity-D6uC-xwP.js +1 -0
  274. package/server/public/assets/soy-cDuODfbT.js +1 -0
  275. package/server/public/assets/sparql-BgU2QITA.js +1 -0
  276. package/server/public/assets/splunk-LQYHRu14.js +1 -0
  277. package/server/public/assets/sql-CKZpK620.js +1 -0
  278. package/server/public/assets/ssh-config-B7BUl8Rd.js +1 -0
  279. package/server/public/assets/stata-BLJTbKOO.js +1 -0
  280. package/server/public/assets/styles-UDowwF7S.css +2 -0
  281. package/server/public/assets/stylus-Byjxdx_q.js +1 -0
  282. package/server/public/assets/surrealql-C96KvYaj.js +1 -0
  283. package/server/public/assets/svelte-Qnbj2GWx.js +1 -0
  284. package/server/public/assets/swift-BexLlMrU.js +1 -0
  285. package/server/public/assets/synthwave-84-BxMBwQMS.js +1 -0
  286. package/server/public/assets/system-verilog-DVGwm0mw.js +1 -0
  287. package/server/public/assets/systemd-H2IT3-p5.js +1 -0
  288. package/server/public/assets/talonscript-mKZIGM8n.js +1 -0
  289. package/server/public/assets/tasl-B7he_Ugr.js +1 -0
  290. package/server/public/assets/tcl-5mT3RxHH.js +1 -0
  291. package/server/public/assets/templ-CQPDll3D.js +1 -0
  292. package/server/public/assets/terraform-BZP0GLsT.js +1 -0
  293. package/server/public/assets/test-D7JRfog1.js +1 -0
  294. package/server/public/assets/tex-97QNLoBJ.js +1 -0
  295. package/server/public/assets/tokyo-night-CTPVdZt9.js +1 -0
  296. package/server/public/assets/toml-CTFA98he.js +1 -0
  297. package/server/public/assets/ts-tags-B8zlXe2n.js +1 -0
  298. package/server/public/assets/tsv-BayJtYdY.js +1 -0
  299. package/server/public/assets/tsx-VqRU8NCz.js +1 -0
  300. package/server/public/assets/turtle-TVCBh_kY.js +1 -0
  301. package/server/public/assets/twig-FTTF8rVk.js +1 -0
  302. package/server/public/assets/typescript-CuX0hIVY.js +1 -0
  303. package/server/public/assets/typespec-BUvaJDLF.js +1 -0
  304. package/server/public/assets/typst-8NBaY7Ec.js +1 -0
  305. package/server/public/assets/useStore-M3H8PB1v.js +1 -0
  306. package/server/public/assets/utils-DElCu2hq.js +1 -0
  307. package/server/public/assets/v-VihyTigi.js +1 -0
  308. package/server/public/assets/vala-DyFAPyX6.js +1 -0
  309. package/server/public/assets/vb-Dg1Iqi4J.js +1 -0
  310. package/server/public/assets/verilog-D2Xc-vhD.js +1 -0
  311. package/server/public/assets/vesper-DJbtqYNr.js +1 -0
  312. package/server/public/assets/vhdl-CU3BVeE7.js +1 -0
  313. package/server/public/assets/viml-hG2shuOW.js +1 -0
  314. package/server/public/assets/vitesse-black-DbG2gsc0.js +1 -0
  315. package/server/public/assets/vitesse-dark-B6WV4xXH.js +1 -0
  316. package/server/public/assets/vitesse-light-DC1pdD02.js +1 -0
  317. package/server/public/assets/vue-DXwaEU0U.js +1 -0
  318. package/server/public/assets/vue-html-QD7AJ6JJ.js +1 -0
  319. package/server/public/assets/vue-vine-Bh2m1D2Z.js +1 -0
  320. package/server/public/assets/vyper-C1wojIuk.js +1 -0
  321. package/server/public/assets/wasm-C6Y0s02M.js +1 -0
  322. package/server/public/assets/wasm-qTvCOSHz.js +1 -0
  323. package/server/public/assets/wenyan-BG5vPQF0.js +1 -0
  324. package/server/public/assets/wgsl-DrVb-Cub.js +1 -0
  325. package/server/public/assets/wikitext-PRC4s8sH.js +1 -0
  326. package/server/public/assets/wit-ChW5qvg_.js +1 -0
  327. package/server/public/assets/wolfram-B8mKuZSQ.js +1 -0
  328. package/server/public/assets/xml-BK-rcb5a.js +1 -0
  329. package/server/public/assets/xsl-dt-d2R7p.js +1 -0
  330. package/server/public/assets/yaml-UiXU3hGj.js +1 -0
  331. package/server/public/assets/zenscript-C-jEPC9j.js +1 -0
  332. package/server/public/assets/zig-EbnRGjcz.js +1 -0
  333. package/server/public/favicon.ico +0 -0
  334. package/server/public/logo192.png +0 -0
  335. package/server/public/logo512.png +0 -0
  336. package/server/public/manifest.json +25 -0
  337. package/server/public/robots.txt +3 -0
  338. package/server/public/tanstack-circle-logo.png +0 -0
  339. package/server/public/tanstack-word-logo-white.svg +1 -0
  340. package/server/server/_chunks/ssr-renderer.mjs +15 -0
  341. package/server/server/_libs/@floating-ui/core+[...].mjs +698 -0
  342. package/server/server/_libs/@floating-ui/dom+[...].mjs +644 -0
  343. package/server/server/_libs/@floating-ui/react-dom+[...].mjs +839 -0
  344. package/server/server/_libs/@pierre/diffs+[...].mjs +18578 -0
  345. package/server/server/_libs/@radix-ui/react-arrow+[...].mjs +174 -0
  346. package/server/server/_libs/@radix-ui/react-collection+[...].mjs +162 -0
  347. package/server/server/_libs/@radix-ui/react-dialog+[...].mjs +1666 -0
  348. package/server/server/_libs/@radix-ui/react-popper+[...].mjs +289 -0
  349. package/server/server/_libs/@radix-ui/react-radio-group+[...].mjs +420 -0
  350. package/server/server/_libs/@radix-ui/react-select+[...].mjs +990 -0
  351. package/server/server/_libs/@tanstack/react-router+[...].mjs +14113 -0
  352. package/server/server/_libs/_.mjs +2 -0
  353. package/server/server/_libs/chokidar+readdirp.mjs +1599 -0
  354. package/server/server/_libs/class-variance-authority+clsx.mjs +69 -0
  355. package/server/server/_libs/effect+[...].mjs +34047 -0
  356. package/server/server/_libs/h3+rou3+srvx.mjs +1195 -0
  357. package/server/server/_libs/hookable.mjs +41 -0
  358. package/server/server/_libs/lucide-react.mjs +298 -0
  359. package/server/server/_libs/pierre__theme.mjs +2668 -0
  360. package/server/server/_libs/radix-ui__number.mjs +6 -0
  361. package/server/server/_libs/radix-ui__primitive.mjs +9 -0
  362. package/server/server/_libs/radix-ui__react-direction.mjs +11 -0
  363. package/server/server/_libs/shiki.mjs +16 -0
  364. package/server/server/_libs/shikijs__langs.mjs +1355 -0
  365. package/server/server/_libs/shikijs__themes.mjs +262 -0
  366. package/server/server/_libs/tailwind-merge.mjs +1962 -0
  367. package/server/server/_libs/tanstack__history.mjs +342 -0
  368. package/server/server/_libs/tanstack__router-core.mjs +6 -0
  369. package/server/server/_libs/ufo.mjs +64 -0
  370. package/server/server/_reviewId-AWnOGz5k.mjs +33 -0
  371. package/server/server/_reviewId-Com4yOlc.mjs +29 -0
  372. package/server/server/_reviewId-DAhmekJ2.mjs +277 -0
  373. package/server/server/_reviewId-p9mhYVwa.mjs +18 -0
  374. package/server/server/_runtime.mjs +35 -0
  375. package/server/server/_ssr/action-bar-C68xGnWW.mjs +592 -0
  376. package/server/server/_ssr/api-handler-CstW2n82.mjs +189 -0
  377. package/server/server/_ssr/client-runtime-BoPuAEoA.mjs +245 -0
  378. package/server/server/_ssr/createServerRpc--0mcGlWK.mjs +12 -0
  379. package/server/server/_ssr/createSsrRpc-AwdiLXmF.mjs +16 -0
  380. package/server/server/_ssr/domain-rpc-3Ds9DPr0.mjs +287 -0
  381. package/server/server/_ssr/file-tree-CQ5w2GHh.mjs +1951 -0
  382. package/server/server/_ssr/load-scoped-diff-NL2XAcdz.mjs +45 -0
  383. package/server/server/_ssr/new-BKl_G2Ks.mjs +37 -0
  384. package/server/server/_ssr/new-BREdMFAM.mjs +12 -0
  385. package/server/server/_ssr/new-DCz5eHkb.mjs +137 -0
  386. package/server/server/_ssr/reviews-BL5Nsgst.mjs +7 -0
  387. package/server/server/_ssr/reviews-BoaEgGKs.mjs +100 -0
  388. package/server/server/_ssr/reviews-C7_NIhY8.mjs +19 -0
  389. package/server/server/_ssr/reviews-Dd69YBDa.mjs +12 -0
  390. package/server/server/_ssr/router-DLxN8FOm.mjs +415 -0
  391. package/server/server/_ssr/routes-D25G8OuS.mjs +80 -0
  392. package/server/server/_ssr/routes-lz0AN75A.mjs +929 -0
  393. package/server/server/_ssr/runtime-D9IbnMlF.mjs +1401 -0
  394. package/server/server/_ssr/server-runtime-D99qpmma.mjs +12 -0
  395. package/server/server/_ssr/ssr.mjs +5318 -0
  396. package/server/server/_ssr/start-BIQfOZtj.mjs +4 -0
  397. package/server/server/_ssr/test-CQdMYlqa.mjs +6 -0
  398. package/server/server/_ssr/todo-m_uUvxca.mjs +88 -0
  399. package/server/server/_ssr/use-keyboard-shortcuts-D5b1Mxpq.mjs +25 -0
  400. package/server/server/_ssr/utils-BuOt9_LA.mjs +8 -0
  401. package/server/server/_tanstack-start-manifest_v-CnL10NRH.mjs +71 -0
  402. package/server/server/index.mjs +2615 -0
  403. package/server/server/node_modules/detect-libc/lib/detect-libc.js +313 -0
  404. package/server/server/node_modules/detect-libc/lib/elf.js +39 -0
  405. package/server/server/node_modules/detect-libc/lib/filesystem.js +51 -0
  406. package/server/server/node_modules/detect-libc/lib/process.js +24 -0
  407. package/server/server/node_modules/detect-libc/package.json +44 -0
  408. package/server/server/node_modules/msgpackr-extract/index.js +1 -0
  409. package/server/server/node_modules/msgpackr-extract/package.json +50 -0
  410. package/server/server/node_modules/node-gyp-build-optional-packages/index.js +6 -0
  411. package/server/server/node_modules/node-gyp-build-optional-packages/node-gyp-build.js +236 -0
  412. package/server/server/node_modules/node-gyp-build-optional-packages/package.json +32 -0
  413. package/server/server/node_modules/tslib/modules/index.js +70 -0
  414. package/server/server/node_modules/tslib/modules/package.json +3 -0
  415. package/server/server/node_modules/tslib/package.json +47 -0
  416. package/server/server/node_modules/tslib/tslib.js +484 -0
  417. package/server/server/package.json +12 -0
  418. package/dist/chunk-KMYSGMD3.js +0 -3526
  419. package/dist/chunk-KMYSGMD3.js.map +0 -1
  420. package/dist/cli.js +0 -1839
  421. package/dist/cli.js.map +0 -1
  422. package/dist/mcp.js +0 -1228
  423. package/dist/mcp.js.map +0 -1
@@ -0,0 +1,929 @@
1
+ import { i as __toESM } from "../_runtime.mjs";
2
+ import { u as require_react } from "../_libs/@floating-ui/react-dom+[...].mjs";
3
+ import { d as useNavigate, f as useLoaderData, p as useRouter } from "../_libs/@tanstack/react-router+[...].mjs";
4
+ import { n as require_jsx_runtime } from "../_libs/@pierre/diffs+[...].mjs";
5
+ import { Ct as tap, H as Struct, Ht as none, L as Literals, Ot as void_, Vt as map, W as Unknown, X as optionalKey, dt as gen, it as catchCause, q as decodeUnknownOption, vt as promise, z as Number$1 } from "../_libs/effect+[...].mjs";
6
+ import { s as DIFF_SCOPES } from "./todo-m_uUvxca.mjs";
7
+ import { i as clientRuntime, t as ApiClient } from "./client-runtime-BoPuAEoA.mjs";
8
+ import { t as cn } from "./utils-BuOt9_LA.mjs";
9
+ import { _ as ChevronUp, b as Check, g as CircleCheckBig, h as CircleDot, m as Circle, o as LoaderCircle, s as GitCommitHorizontal, y as ChevronDown } from "../_libs/lucide-react.mjs";
10
+ import { a as ItemIndicator, c as Root2, d as Trigger, f as Viewport, i as Item, l as ScrollDownButton, n as Group, o as ItemText, r as Icon, s as Portal, t as Content2, u as ScrollUpButton } from "../_libs/@radix-ui/react-select+[...].mjs";
11
+ import { a as DialogFooter, i as DialogDescription, n as Dialog$1, o as DialogHeader, r as DialogContent, s as DialogTitle, t as ActionBar } from "./action-bar-C68xGnWW.mjs";
12
+ import { a as formatReviewFeedback, i as FileTree, n as DiffView, r as ExportFeedbackModal, t as DiffSummary } from "./file-tree-CQ5w2GHh.mjs";
13
+ import { t as useKeyboardShortcuts } from "./use-keyboard-shortcuts-D5b1Mxpq.mjs";
14
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-lz0AN75A.js
15
+ var import_react = /* @__PURE__ */ __toESM(require_react());
16
+ var import_jsx_runtime = require_jsx_runtime();
17
+ var Select$1 = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Root2, {
18
+ "data-slot": "select",
19
+ ...props
20
+ });
21
+ var SelectGroup = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Group, {
22
+ "data-slot": "select-group",
23
+ className: cn("scroll-my-1 p-1", className),
24
+ ...props
25
+ });
26
+ var SelectTrigger = ({ className, size = "default", children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Trigger, {
27
+ "data-slot": "select-trigger",
28
+ "data-size": size,
29
+ className: cn("flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
30
+ ...props,
31
+ children: [children, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, {
32
+ asChild: true,
33
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: "pointer-events-none size-4 text-muted-foreground" })
34
+ })]
35
+ });
36
+ var SelectContent = ({ className, children, position = "item-aligned", align = "center", ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Content2, {
37
+ "data-slot": "select-content",
38
+ "data-align-trigger": position === "item-aligned",
39
+ className: cn("relative z-50 max-h-(--radix-select-content-available-height) min-w-36 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className),
40
+ position,
41
+ align,
42
+ ...props,
43
+ children: [
44
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectScrollUpButton, {}),
45
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Viewport, {
46
+ "data-position": position,
47
+ className: cn("data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)", position === "popper" && ""),
48
+ children
49
+ }),
50
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectScrollDownButton, {})
51
+ ]
52
+ }) });
53
+ var SelectItem = ({ className, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Item, {
54
+ "data-slot": "select-item",
55
+ className: cn("relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className),
56
+ ...props,
57
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
58
+ className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center",
59
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "pointer-events-none" }) })
60
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ItemText, { children })]
61
+ });
62
+ var SelectScrollUpButton = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollUpButton, {
63
+ "data-slot": "select-scroll-up-button",
64
+ className: cn("z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4", className),
65
+ ...props,
66
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronUp, {})
67
+ });
68
+ var SelectScrollDownButton = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollDownButton, {
69
+ "data-slot": "select-scroll-down-button",
70
+ className: cn("z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4", className),
71
+ ...props,
72
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, {})
73
+ });
74
+ var DIFF_SCOPE_LABELS = {
75
+ "last-commit": "Last Commit",
76
+ staged: "Staged",
77
+ uncommitted: "Uncommitted",
78
+ unstaged: "Unstaged"
79
+ };
80
+ var DIFF_SCOPE_EMPTY_MESSAGES = {
81
+ "last-commit": "No previous commit found",
82
+ staged: "No staged changes — stage files with git add",
83
+ uncommitted: "Working tree clean — no uncommitted changes",
84
+ unstaged: "No unstaged changes — all modifications are staged"
85
+ };
86
+ var DIFF_SCOPE_ICONS = {
87
+ "last-commit": GitCommitHorizontal,
88
+ staged: CircleCheckBig,
89
+ uncommitted: CircleDot,
90
+ unstaged: Circle
91
+ };
92
+ var CountBadge = ({ fileCount, isLoading }) => {
93
+ if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
94
+ className: "inline-flex h-5 min-w-5 items-center justify-center rounded-full border border-border-default bg-surface-overlay px-1.5 text-[10px] text-text-tertiary motion-reduce:animate-none",
95
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "size-3 animate-spin motion-reduce:animate-none" })
96
+ });
97
+ if (typeof fileCount !== "number") return null;
98
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
99
+ className: "inline-flex h-5 min-w-5 items-center justify-center rounded-full border border-border-default bg-surface-overlay px-1.5 text-[10px] font-medium tabular-nums text-text-secondary",
100
+ children: fileCount
101
+ });
102
+ };
103
+ var DiffScopeSelector = ({ value, onChange, fileCount, isLoading = false }) => {
104
+ const SelectedIcon = isLoading ? LoaderCircle : DIFF_SCOPE_ICONS[value];
105
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
106
+ disabled: isLoading,
107
+ onValueChange: (0, import_react.useCallback)((scope) => {
108
+ onChange(scope);
109
+ }, [onChange]),
110
+ value,
111
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectTrigger, {
112
+ "aria-label": "Diff scope",
113
+ className: cn("h-7 min-w-0 gap-1.5 rounded-[10px] border-border-subtle bg-surface-primary px-2 text-[11px] font-medium text-text-secondary shadow-none transition-[color,background-color,border-color,box-shadow,transform,opacity] duration-150 [transition-timing-function:cubic-bezier(0.23,1,0.32,1)] focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 active:scale-[0.97] motion-reduce:transform-none motion-reduce:transition-[color,background-color,border-color,box-shadow,opacity] [&_svg]:text-text-tertiary"),
114
+ size: "sm",
115
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
116
+ className: "flex min-w-0 items-center gap-1.5",
117
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectedIcon, { className: cn("size-3.5 shrink-0", isLoading && "animate-spin motion-reduce:animate-none") }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
118
+ className: "truncate",
119
+ children: DIFF_SCOPE_LABELS[value]
120
+ })]
121
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CountBadge, {
122
+ fileCount,
123
+ isLoading
124
+ })]
125
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, {
126
+ align: "end",
127
+ className: cn("min-w-44 rounded-xl border border-border-default bg-surface-elevated p-1 shadow-[0_18px_40px_-24px_rgba(0,0,0,0.7)] transition-[opacity,transform] duration-150 [transition-timing-function:cubic-bezier(0.23,1,0.32,1)] data-[state=closed]:scale-95 data-[state=closed]:opacity-0 data-[state=open]:scale-100 data-[state=open]:opacity-100 motion-reduce:transform-none motion-reduce:transition-opacity"),
128
+ position: "popper",
129
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectGroup, { children: DIFF_SCOPES.map((scope) => {
130
+ const Icon = DIFF_SCOPE_ICONS[scope];
131
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
132
+ className: "rounded-lg px-2 py-1.5 text-xs text-text-secondary focus:bg-surface-overlay focus:text-text-primary",
133
+ value: scope,
134
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
135
+ className: "flex min-w-0 items-center gap-2",
136
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: "size-3.5 shrink-0" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
137
+ className: "truncate",
138
+ children: DIFF_SCOPE_LABELS[scope]
139
+ })]
140
+ })
141
+ }, scope);
142
+ }) })
143
+ })]
144
+ });
145
+ };
146
+ var STORAGE_KEY = "ringi.session-draft.v1";
147
+ var MAX_AGE_MS = 1800 * 1e3;
148
+ var clearDraft = () => {
149
+ if (typeof window === "undefined") return;
150
+ try {
151
+ localStorage.removeItem(STORAGE_KEY);
152
+ } catch {}
153
+ };
154
+ var saveDraft = (draft) => {
155
+ if (typeof window === "undefined") return;
156
+ const payload = {
157
+ ...draft,
158
+ savedAt: Date.now()
159
+ };
160
+ try {
161
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(payload));
162
+ } catch {}
163
+ };
164
+ var loadDraft = () => {
165
+ if (typeof window === "undefined") return null;
166
+ try {
167
+ const raw = localStorage.getItem(STORAGE_KEY);
168
+ if (!raw) return null;
169
+ const data = JSON.parse(raw);
170
+ if (typeof data.savedAt !== "number" || !Array.isArray(data.viewedFiles) || typeof data.scope !== "string") return null;
171
+ if (Date.now() - data.savedAt > MAX_AGE_MS) {
172
+ clearDraft();
173
+ return null;
174
+ }
175
+ return {
176
+ savedAt: data.savedAt,
177
+ scope: data.scope,
178
+ selectedFile: typeof data.selectedFile === "string" ? data.selectedFile : null,
179
+ viewedFiles: data.viewedFiles.filter((v) => typeof v === "string")
180
+ };
181
+ } catch {
182
+ return null;
183
+ }
184
+ };
185
+ /**
186
+ * Human-friendly relative time label for the recovery modal.
187
+ *
188
+ * Examples: "just now", "1 minute ago", "5 minutes ago", "1 hour ago"
189
+ */
190
+ var formatRelativeTime$1 = (savedAt) => {
191
+ const diffMs = Date.now() - savedAt;
192
+ const diffSeconds = Math.floor(diffMs / 1e3);
193
+ const diffMinutes = Math.floor(diffSeconds / 60);
194
+ const diffHours = Math.floor(diffMinutes / 60);
195
+ if (diffSeconds < 30) return "just now";
196
+ if (diffMinutes < 1) return "less than a minute ago";
197
+ if (diffMinutes === 1) return "1 minute ago";
198
+ if (diffMinutes < 60) return `${diffMinutes} minutes ago`;
199
+ if (diffHours === 1) return "1 hour ago";
200
+ return `${diffHours} hours ago`;
201
+ };
202
+ var isDraftRecoverable = (draft, currentScope) => draft !== null && draft.scope === currentScope && draft.viewedFiles.length > 0;
203
+ var buttonMotionClass = "transition-[transform,background-color,color,border-color,box-shadow,opacity] duration-150 [transition-timing-function:cubic-bezier(0.23,1,0.32,1)] motion-reduce:transform-none";
204
+ var DraftRecoveryModal = ({ open, draft, onRestore, onDismiss }) => {
205
+ const fileCount = draft.viewedFiles.length;
206
+ const timeLabel = formatRelativeTime$1(draft.savedAt);
207
+ const handleRestore = (0, import_react.useCallback)(() => {
208
+ onRestore();
209
+ }, [onRestore]);
210
+ const handleDismiss = (0, import_react.useCallback)(() => {
211
+ onDismiss();
212
+ }, [onDismiss]);
213
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
214
+ open,
215
+ onOpenChange: (0, import_react.useCallback)((v) => {
216
+ if (!v) onDismiss();
217
+ }, [onDismiss]),
218
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogContent, {
219
+ className: "max-w-sm gap-0",
220
+ showCloseButton: false,
221
+ children: [
222
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: "Draft Recovered" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogDescription, { children: `Found ${fileCount} viewed file${fileCount === 1 ? "" : "s"} from ${timeLabel}.` })] }),
223
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
224
+ className: "px-5 py-3",
225
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", {
226
+ className: "flex flex-col gap-1",
227
+ children: [draft.viewedFiles.slice(0, 5).map((filePath) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", {
228
+ className: "truncate font-mono text-xs text-text-secondary",
229
+ children: filePath
230
+ }, filePath)), fileCount > 5 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", {
231
+ className: "text-xs text-text-tertiary",
232
+ children: `… and ${fileCount - 5} more`
233
+ }) : null]
234
+ })
235
+ }),
236
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogFooter, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
237
+ type: "button",
238
+ onClick: handleDismiss,
239
+ className: cn("rounded-lg border border-border-default bg-surface-elevated px-3 py-1.5 text-xs text-text-secondary hover:bg-surface-overlay hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 active:scale-[0.97]", buttonMotionClass),
240
+ children: "Dismiss"
241
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
242
+ type: "button",
243
+ onClick: handleRestore,
244
+ className: cn("rounded-lg bg-accent-primary px-3 py-1.5 text-xs font-medium text-white hover:bg-accent-primary-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-primary/40 active:scale-[0.97]", buttonMotionClass),
245
+ children: "Restore"
246
+ })] })
247
+ ]
248
+ })
249
+ });
250
+ };
251
+ var EASE_OUT = "[transition-timing-function:cubic-bezier(0.23,1,0.32,1)]";
252
+ var pressScale = "active:scale-[0.97]";
253
+ var formatRelativeTime = (iso) => {
254
+ const date = new Date(iso);
255
+ if (Number.isNaN(date.getTime())) return "";
256
+ const diffMs = Date.now() - date.getTime();
257
+ const diffMin = Math.floor(diffMs / 6e4);
258
+ if (diffMin < 1) return "just now";
259
+ if (diffMin < 60) return `${diffMin}m ago`;
260
+ const diffHours = Math.floor(diffMin / 60);
261
+ if (diffHours < 24) return `${diffHours}h ago`;
262
+ return new Intl.DateTimeFormat(void 0, {
263
+ day: "numeric",
264
+ month: "short"
265
+ }).format(date);
266
+ };
267
+ var getFileName = (filePath) => {
268
+ return filePath.split("/").at(-1) ?? filePath;
269
+ };
270
+ var getDirPath = (filePath) => {
271
+ const parts = filePath.split("/");
272
+ if (parts.length <= 1) return "";
273
+ return parts.slice(0, -1).join("/");
274
+ };
275
+ var DeleteButton = ({ onDelete, annotationId }) => {
276
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
277
+ type: "button",
278
+ onClick: (0, import_react.useCallback)((e) => {
279
+ e.stopPropagation();
280
+ onDelete(annotationId);
281
+ }, [onDelete, annotationId]),
282
+ onKeyDown: (0, import_react.useCallback)((e) => {
283
+ if (e.key === "Enter" || e.key === " ") {
284
+ e.preventDefault();
285
+ e.stopPropagation();
286
+ onDelete(annotationId);
287
+ }
288
+ }, [onDelete, annotationId]),
289
+ "aria-label": "Delete annotation",
290
+ tabIndex: 0,
291
+ className: cn("ml-auto shrink-0 rounded px-1 py-0.5 text-text-quaternary", "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100", "transition-[opacity,color,background-color] duration-100", EASE_OUT, "hover:bg-status-error/10 hover:text-status-error", "focus-visible:bg-status-error/10 focus-visible:text-status-error focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-status-error/30", "active:scale-[0.93]", "motion-reduce:transform-none"),
292
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
293
+ width: "11",
294
+ height: "11",
295
+ viewBox: "0 0 12 12",
296
+ fill: "none",
297
+ stroke: "currentColor",
298
+ strokeWidth: "1.25",
299
+ strokeLinecap: "round",
300
+ className: "shrink-0",
301
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 3h8M4.5 3V2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v1M5 5.5v3M7 5.5v3M3 3l.5 7a1 1 0 0 0 1 .9h3a1 1 0 0 0 1-.9L9 3" })
302
+ })
303
+ });
304
+ };
305
+ var AnnotationCard = ({ entry, onClick, onDelete }) => {
306
+ const handleClick = (0, import_react.useCallback)(() => onClick(entry), [entry, onClick]);
307
+ const handleKeyDown = (0, import_react.useCallback)((e) => {
308
+ if (e.key === "Enter" || e.key === " ") {
309
+ e.preventDefault();
310
+ onClick(entry);
311
+ }
312
+ }, [entry, onClick]);
313
+ const linePrefix = entry.lineType === "added" ? "+" : "-";
314
+ const lineColor = entry.lineType === "added" ? "text-diff-add-text" : "text-diff-remove-text";
315
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
316
+ type: "button",
317
+ onClick: handleClick,
318
+ onKeyDown: handleKeyDown,
319
+ className: cn("group flex w-full cursor-pointer flex-col rounded-md px-2.5 py-2 text-left", "transition-[background-color,transform] duration-150", EASE_OUT, pressScale, "hover:bg-surface-overlay/60", "focus-visible:bg-surface-overlay/60 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent-primary/40", "motion-reduce:transform-none"),
320
+ children: [
321
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
322
+ className: "flex items-center gap-1.5",
323
+ children: [
324
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
325
+ className: cn("rounded bg-surface-primary/80 px-1 py-px font-mono text-[10px] font-medium tabular-nums", lineColor),
326
+ children: [
327
+ linePrefix,
328
+ "L",
329
+ entry.lineNumber
330
+ ]
331
+ }),
332
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeleteButton, {
333
+ onDelete,
334
+ annotationId: entry.id
335
+ }),
336
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
337
+ className: "text-[10px] text-text-quaternary",
338
+ children: formatRelativeTime(entry.createdAt)
339
+ })
340
+ ]
341
+ }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
343
+ className: "mt-1 line-clamp-2 text-[11px] leading-[16px] text-text-secondary group-hover:text-text-primary",
344
+ children: entry.content
345
+ }),
346
+ entry.suggestion ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
347
+ className: "mt-1 flex items-center text-[10px] text-accent-primary/70",
348
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
349
+ width: "10",
350
+ height: "10",
351
+ viewBox: "0 0 14 14",
352
+ fill: "none",
353
+ className: "shrink-0",
354
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
355
+ d: "M3 5l2.5 2.5L11 2M3 9h8",
356
+ stroke: "currentColor",
357
+ strokeWidth: "1.25",
358
+ strokeLinecap: "round",
359
+ strokeLinejoin: "round"
360
+ })
361
+ })
362
+ }) : null
363
+ ]
364
+ });
365
+ };
366
+ var FileGroup = ({ group, onAnnotationClick, onDeleteAnnotation }) => {
367
+ const fileName = getFileName(group.filePath);
368
+ const dirPath = getDirPath(group.filePath);
369
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
370
+ className: "py-1",
371
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
372
+ className: "flex items-center gap-1.5 px-3 py-1.5",
373
+ children: [
374
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
375
+ width: "12",
376
+ height: "12",
377
+ viewBox: "0 0 16 16",
378
+ fill: "currentColor",
379
+ className: "shrink-0 text-text-quaternary",
380
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 3.5A1.5 1.5 0 0 1 3.5 2h3.379a1.5 1.5 0 0 1 1.06.44l.622.621a.5.5 0 0 0 .353.146H12.5A1.5 1.5 0 0 1 14 4.707V12.5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 12.5V3.5Z" })
381
+ }),
382
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
383
+ className: "min-w-0 truncate font-mono text-[11px] font-medium text-text-primary",
384
+ children: fileName
385
+ }),
386
+ dirPath ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
387
+ className: "min-w-0 truncate font-mono text-[10px] text-text-quaternary",
388
+ children: dirPath
389
+ }) : null,
390
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
391
+ className: "ml-auto shrink-0 rounded-full bg-surface-overlay px-1.5 py-px text-[10px] tabular-nums text-text-tertiary",
392
+ children: group.annotations.length
393
+ })
394
+ ]
395
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
396
+ className: "space-y-0.5 px-1",
397
+ children: group.annotations.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnnotationCard, {
398
+ entry,
399
+ onClick: onAnnotationClick,
400
+ onDelete: onDeleteAnnotation
401
+ }, entry.id))
402
+ })]
403
+ });
404
+ };
405
+ var EmptyState = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
406
+ className: "flex flex-col items-center justify-center px-4 py-12 text-center",
407
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
408
+ width: "28",
409
+ height: "28",
410
+ viewBox: "0 0 16 16",
411
+ fill: "currentColor",
412
+ className: "text-text-quaternary/40",
413
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M1 3.5A2.5 2.5 0 0 1 3.5 1h9A2.5 2.5 0 0 1 15 3.5v6a2.5 2.5 0 0 1-2.5 2.5H9l-3.5 3v-3H3.5A2.5 2.5 0 0 1 1 9.5v-6Z" })
414
+ })
415
+ });
416
+ var ClipboardIcon$1 = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
417
+ width: "12",
418
+ height: "12",
419
+ viewBox: "0 0 16 16",
420
+ fill: "none",
421
+ stroke: "currentColor",
422
+ strokeWidth: "1.25",
423
+ strokeLinecap: "round",
424
+ strokeLinejoin: "round",
425
+ className: "shrink-0",
426
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
427
+ x: "5",
428
+ y: "5",
429
+ width: "8",
430
+ height: "8",
431
+ rx: "1.5"
432
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 11H4.5A1.5 1.5 0 0 1 3 9.5V4.5A1.5 1.5 0 0 1 4.5 3H9.5A1.5 1.5 0 0 1 11 4.5V5" })]
433
+ });
434
+ var CheckIcon$1 = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
435
+ width: "12",
436
+ height: "12",
437
+ viewBox: "0 0 12 12",
438
+ fill: "none",
439
+ stroke: "currentColor",
440
+ strokeWidth: "1.5",
441
+ strokeLinecap: "round",
442
+ strokeLinejoin: "round",
443
+ className: "shrink-0 text-status-success",
444
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2.5 6.5L5 9l4.5-6" })
445
+ });
446
+ var ErrorIcon = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
447
+ width: "12",
448
+ height: "12",
449
+ viewBox: "0 0 12 12",
450
+ fill: "none",
451
+ stroke: "currentColor",
452
+ strokeWidth: "1.5",
453
+ strokeLinecap: "round",
454
+ className: "shrink-0 text-status-error",
455
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 3l6 6M9 3l-6 6" })
456
+ });
457
+ var COPY_LABELS = {
458
+ copied: "Copied!",
459
+ error: "Failed",
460
+ idle: "Copy Feedback"
461
+ };
462
+ var COPY_STATUS_STYLES = {
463
+ copied: "text-status-success",
464
+ error: "text-status-error",
465
+ idle: "text-text-secondary hover:bg-surface-overlay hover:text-text-primary"
466
+ };
467
+ var CopyStatusIcon = ({ status }) => {
468
+ if (status === "copied") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckIcon$1, {});
469
+ if (status === "error") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorIcon, {});
470
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClipboardIcon$1, {});
471
+ };
472
+ var CopyFeedbackButton = ({ copyStatus, onCopyFeedback }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
473
+ type: "button",
474
+ onClick: onCopyFeedback,
475
+ disabled: copyStatus !== "idle",
476
+ className: cn("inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-[11px] font-medium", "transition-[background-color,color,transform,opacity] duration-150", EASE_OUT, pressScale, COPY_STATUS_STYLES[copyStatus], copyStatus !== "idle" && "pointer-events-none", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent-primary/40", "motion-reduce:transform-none"),
477
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyStatusIcon, { status: copyStatus }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: COPY_LABELS[copyStatus] })]
478
+ });
479
+ var AnnotationsPanel = ({ isOpen, onClose, groups, totalCount, copyStatus, onAnnotationClick, onDeleteAnnotation, onCopyFeedback }) => {
480
+ const panelRef = (0, import_react.useRef)(null);
481
+ (0, import_react.useEffect)(() => {
482
+ if (!isOpen) return;
483
+ const handleKeyDown = (e) => {
484
+ if (e.key === "Escape") {
485
+ e.stopPropagation();
486
+ onClose();
487
+ }
488
+ };
489
+ document.addEventListener("keydown", handleKeyDown);
490
+ return () => document.removeEventListener("keydown", handleKeyDown);
491
+ }, [isOpen, onClose]);
492
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
493
+ ref: panelRef,
494
+ role: "complementary",
495
+ "aria-label": "Annotations",
496
+ className: cn("flex h-full flex-col border-l border-border-default bg-surface-secondary", "transition-[width,opacity] duration-200", EASE_OUT, "motion-reduce:transition-none", isOpen ? "w-72 opacity-100" : "w-0 opacity-0 overflow-hidden"),
497
+ children: [
498
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
499
+ className: "flex h-10 shrink-0 items-center justify-end border-b border-border-default px-3",
500
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
501
+ type: "button",
502
+ onClick: onClose,
503
+ "aria-label": "Close annotations panel",
504
+ className: cn("inline-flex h-6 w-6 items-center justify-center rounded-md text-text-tertiary", "transition-[background-color,color,transform] duration-150", EASE_OUT, pressScale, "hover:bg-surface-overlay hover:text-text-primary", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent-primary/40", "motion-reduce:transform-none"),
505
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
506
+ width: "12",
507
+ height: "12",
508
+ viewBox: "0 0 12 12",
509
+ fill: "none",
510
+ stroke: "currentColor",
511
+ strokeWidth: "1.5",
512
+ strokeLinecap: "round",
513
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 3l6 6M9 3l-6 6" })
514
+ })
515
+ })
516
+ }),
517
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
518
+ className: "flex-1 overflow-y-auto overflow-x-hidden py-1",
519
+ children: groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyState, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
520
+ className: "divide-y divide-border-subtle",
521
+ children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileGroup, {
522
+ group,
523
+ onAnnotationClick,
524
+ onDeleteAnnotation
525
+ }, group.filePath))
526
+ })
527
+ }),
528
+ totalCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
529
+ className: "flex items-center border-t border-border-subtle px-3 py-1.5",
530
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyFeedbackButton, {
531
+ copyStatus,
532
+ onCopyFeedback
533
+ })
534
+ }) : null
535
+ ]
536
+ });
537
+ };
538
+ var formatAnnotationFeedback = (groups) => {
539
+ const comments = [];
540
+ for (const group of groups) for (const entry of group.annotations) comments.push({
541
+ content: entry.content,
542
+ filePath: entry.filePath,
543
+ lineNumber: entry.lineNumber,
544
+ lineType: entry.lineType === "context" ? "context" : entry.lineType,
545
+ suggestion: entry.suggestion
546
+ });
547
+ return formatReviewFeedback(comments);
548
+ };
549
+ var useAnnotationsPanel = ({ getLocalComments, onNavigate, onDeleteAnnotation }) => {
550
+ const [isOpen, setIsOpen] = (0, import_react.useState)(false);
551
+ const [copyStatus, setCopyStatus] = (0, import_react.useState)("idle");
552
+ const handleToggle = (0, import_react.useCallback)(() => setIsOpen((prev) => !prev), []);
553
+ const handleClose = (0, import_react.useCallback)(() => setIsOpen(false), []);
554
+ const handleAnnotationClick = (0, import_react.useCallback)((entry) => {
555
+ onNavigate(entry.filePath, entry.lineNumber);
556
+ }, [onNavigate]);
557
+ const handleDeleteAnnotation = (0, import_react.useCallback)((id) => {
558
+ onDeleteAnnotation?.(id);
559
+ }, [onDeleteAnnotation]);
560
+ return {
561
+ buildGroups: (0, import_react.useCallback)(() => {
562
+ const commentsMap = getLocalComments();
563
+ const groups = [];
564
+ for (const [filePath, comments] of commentsMap) {
565
+ if (comments.length === 0) continue;
566
+ const annotations = comments.map((c) => ({
567
+ content: c.content,
568
+ createdAt: c.createdAt,
569
+ filePath: c.filePath,
570
+ id: c.id,
571
+ lineNumber: c.lineNumber,
572
+ lineType: c.lineType,
573
+ suggestion: c.suggestion
574
+ }));
575
+ groups.push({
576
+ annotations,
577
+ filePath
578
+ });
579
+ }
580
+ groups.sort((a, b) => a.filePath.localeCompare(b.filePath));
581
+ return groups;
582
+ }, [getLocalComments]),
583
+ copyStatus,
584
+ handleAnnotationClick,
585
+ handleClose,
586
+ handleCopyFeedback: (0, import_react.useCallback)(async (groups) => {
587
+ const markdown = formatAnnotationFeedback(groups);
588
+ if (!markdown) return;
589
+ try {
590
+ await navigator.clipboard.writeText(markdown);
591
+ setCopyStatus("copied");
592
+ } catch {
593
+ setCopyStatus("error");
594
+ }
595
+ setTimeout(() => setCopyStatus("idle"), 1500);
596
+ }, []),
597
+ handleDeleteAnnotation,
598
+ handleToggle,
599
+ isOpen,
600
+ totalCount: (0, import_react.useMemo)(() => {
601
+ const commentsMap = getLocalComments();
602
+ let count = 0;
603
+ for (const comments of commentsMap.values()) count += comments.length;
604
+ return count;
605
+ }, [getLocalComments])
606
+ };
607
+ };
608
+ var SSEEventSchema = Struct({
609
+ data: Unknown.pipe(optionalKey),
610
+ timestamp: Number$1,
611
+ type: Literals([
612
+ "todos",
613
+ "reviews",
614
+ "comments",
615
+ "files"
616
+ ])
617
+ });
618
+ var decodeSSEEvent = (raw) => {
619
+ try {
620
+ const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
621
+ return decodeUnknownOption(SSEEventSchema)(parsed);
622
+ } catch {
623
+ return none();
624
+ }
625
+ };
626
+ function useEventSource(options = {}) {
627
+ const { url = "/api/events", onEvent, enabled = true } = options;
628
+ const [connected, setConnected] = (0, import_react.useState)(false);
629
+ const onEventRef = (0, import_react.useRef)(onEvent);
630
+ onEventRef.current = onEvent;
631
+ const reconnectTimeoutRef = (0, import_react.useRef)(null);
632
+ const esRef = (0, import_react.useRef)(null);
633
+ (0, import_react.useEffect)(() => {
634
+ if (!enabled || typeof window === "undefined") return;
635
+ function connect() {
636
+ const es = new EventSource(url);
637
+ esRef.current = es;
638
+ es.onopen = () => setConnected(true);
639
+ es.onerror = () => {
640
+ setConnected(false);
641
+ es.close();
642
+ esRef.current = null;
643
+ if (reconnectTimeoutRef.current === null) reconnectTimeoutRef.current = setTimeout(() => {
644
+ reconnectTimeoutRef.current = null;
645
+ connect();
646
+ }, 1e3);
647
+ };
648
+ es.onmessage = (event) => {
649
+ map(decodeSSEEvent(event.data), (data) => onEventRef.current?.(data));
650
+ };
651
+ }
652
+ connect();
653
+ return () => {
654
+ if (reconnectTimeoutRef.current !== null) {
655
+ clearTimeout(reconnectTimeoutRef.current);
656
+ reconnectTimeoutRef.current = null;
657
+ }
658
+ esRef.current?.close();
659
+ esRef.current = null;
660
+ setConnected(false);
661
+ };
662
+ }, [url, enabled]);
663
+ return { connected };
664
+ }
665
+ /** Pick the first non-binary, commentable file. */
666
+ var pickDefaultFile = (files) => {
667
+ for (const file of files) if (file.hunks.length > 0) return file.newPath;
668
+ return files[0]?.newPath ?? null;
669
+ };
670
+ var EmptyDiffState = ({ message }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
671
+ className: "rounded-sm border border-border-default bg-surface-elevated p-8 text-center",
672
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
673
+ className: "text-sm text-text-tertiary",
674
+ children: message
675
+ })
676
+ });
677
+ var DiffContent = ({ hasFiles, emptyMessage, file, diffMode, summary, onLocalCommentsChange, viewed, onToggleViewed, pendingDeleteId, onPendingDeleteHandled }) => {
678
+ if (!hasFiles) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyDiffState, { message: emptyMessage });
679
+ if (!file) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyDiffState, { message: "Select a file to view its diff." });
680
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
681
+ className: "space-y-3",
682
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DiffSummary, { summary }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DiffView, {
683
+ file,
684
+ diffMode,
685
+ onLocalCommentsChange,
686
+ viewed,
687
+ onToggleViewed,
688
+ pendingDeleteId,
689
+ onPendingDeleteHandled
690
+ })]
691
+ });
692
+ };
693
+ var ChangesPage = () => {
694
+ const data = useLoaderData({ from: "/" });
695
+ const navigate = useNavigate();
696
+ const router = useRouter();
697
+ useEventSource({ onEvent: () => router.invalidate() });
698
+ const [selectedFile, setSelectedFile] = (0, import_react.useState)(() => pickDefaultFile(data.files));
699
+ const [viewedFiles, setViewedFiles] = (0, import_react.useState)(/* @__PURE__ */ new Set());
700
+ const [diffMode, setDiffMode] = (0, import_react.useState)("split");
701
+ const [pendingScope, setPendingScope] = (0, import_react.useState)(null);
702
+ const [exportOpen, setExportOpen] = (0, import_react.useState)(false);
703
+ const localCommentsRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
704
+ const [localCommentSnapshot, setLocalCommentSnapshot] = (0, import_react.useState)([]);
705
+ const [annotationVersion, setAnnotationVersion] = (0, import_react.useState)(0);
706
+ const [recoveryDraft, setRecoveryDraft] = (0, import_react.useState)(() => {
707
+ const draft = loadDraft();
708
+ return isDraftRecoverable(draft, data.scope) ? draft : null;
709
+ });
710
+ const selectedFileData = (0, import_react.useMemo)(() => data.files.find((f) => f.newPath === selectedFile) ?? null, [data.files, selectedFile]);
711
+ const getLocalComments = (0, import_react.useCallback)(() => localCommentsRef.current, []);
712
+ const handleAnnotationNavigate = (0, import_react.useCallback)((filePath, _lineNumber) => {
713
+ setSelectedFile(filePath);
714
+ requestAnimationFrame(() => {
715
+ const anchorId = `diff-file-${filePath.replaceAll("/", "-")}`;
716
+ const el = document.querySelector(`#${anchorId}`);
717
+ if (el) el.scrollIntoView({
718
+ behavior: "smooth",
719
+ block: "start"
720
+ });
721
+ });
722
+ }, []);
723
+ const [pendingDeleteId, setPendingDeleteId] = (0, import_react.useState)(null);
724
+ const handleClearPendingDelete = (0, import_react.useCallback)(() => {
725
+ setPendingDeleteId(null);
726
+ }, []);
727
+ const annotationsPanel = useAnnotationsPanel({
728
+ getLocalComments,
729
+ onDeleteAnnotation: (0, import_react.useCallback)((id) => {
730
+ if ((selectedFile ? localCommentsRef.current.get(selectedFile) : void 0)?.some((c) => c.id === id)) setPendingDeleteId(id);
731
+ else {
732
+ for (const [filePath, comments] of localCommentsRef.current) {
733
+ const filtered = comments.filter((c) => c.id !== id);
734
+ if (filtered.length !== comments.length) {
735
+ if (filtered.length === 0) localCommentsRef.current.delete(filePath);
736
+ else localCommentsRef.current.set(filePath, filtered);
737
+ break;
738
+ }
739
+ }
740
+ setAnnotationVersion((v) => v + 1);
741
+ }
742
+ }, [selectedFile]),
743
+ onNavigate: handleAnnotationNavigate
744
+ });
745
+ const { buildGroups: buildAnnotationGroups } = annotationsPanel;
746
+ const annotationGroups = (0, import_react.useMemo)(() => buildAnnotationGroups(), [buildAnnotationGroups, annotationVersion]);
747
+ (0, import_react.useEffect)(() => {
748
+ setSelectedFile(pickDefaultFile(data.files));
749
+ setViewedFiles(/* @__PURE__ */ new Set());
750
+ setPendingScope(null);
751
+ }, [data.scope, data.files]);
752
+ const handleToggleViewed = (0, import_react.useCallback)((filePath) => {
753
+ setViewedFiles((prev) => {
754
+ const next = new Set(prev);
755
+ if (next.has(filePath)) next.delete(filePath);
756
+ else next.add(filePath);
757
+ return next;
758
+ });
759
+ }, []);
760
+ (0, import_react.useEffect)(() => {
761
+ if (viewedFiles.size === 0) return;
762
+ saveDraft({
763
+ scope: data.scope,
764
+ selectedFile,
765
+ viewedFiles: [...viewedFiles]
766
+ });
767
+ }, [
768
+ viewedFiles,
769
+ selectedFile,
770
+ data.scope
771
+ ]);
772
+ useKeyboardShortcuts((0, import_react.useMemo)(() => [{
773
+ description: "New review",
774
+ handler: () => {
775
+ window.location.href = "/reviews/new";
776
+ },
777
+ key: "n"
778
+ }, {
779
+ description: "Go to Reviews",
780
+ handler: () => navigate({ to: "/reviews" }),
781
+ key: "r"
782
+ }], [navigate]));
783
+ const handleSelectFile = (0, import_react.useCallback)((path) => {
784
+ setSelectedFile(path);
785
+ }, []);
786
+ const handleLocalCommentsChange = (0, import_react.useCallback)((filePath, comments) => {
787
+ if (comments.length === 0) localCommentsRef.current.delete(filePath);
788
+ else localCommentsRef.current.set(filePath, comments);
789
+ setAnnotationVersion((v) => v + 1);
790
+ }, []);
791
+ const handleExport = (0, import_react.useCallback)(() => {
792
+ const all = [];
793
+ for (const comments of localCommentsRef.current.values()) for (const c of comments) all.push({
794
+ content: c.content,
795
+ filePath: c.filePath,
796
+ lineNumber: c.lineNumber,
797
+ lineType: c.lineType,
798
+ suggestion: c.suggestion
799
+ });
800
+ setLocalCommentSnapshot(all);
801
+ setExportOpen(true);
802
+ }, []);
803
+ const { handleCopyFeedback } = annotationsPanel;
804
+ const handleCopyAnnotationFeedback = (0, import_react.useCallback)(() => {
805
+ handleCopyFeedback(annotationGroups);
806
+ }, [handleCopyFeedback, annotationGroups]);
807
+ const toggleDiffMode = (0, import_react.useCallback)(() => {
808
+ setDiffMode((prev) => prev === "split" ? "unified" : "split");
809
+ }, []);
810
+ const handleScopeChange = (0, import_react.useCallback)(async (scope) => {
811
+ if (scope === data.scope) return;
812
+ setPendingScope(scope);
813
+ setSelectedFile(null);
814
+ try {
815
+ await navigate({
816
+ search: (previous) => ({
817
+ ...previous,
818
+ scope
819
+ }),
820
+ to: "/"
821
+ });
822
+ } finally {
823
+ setPendingScope(null);
824
+ }
825
+ }, [data.scope, navigate]);
826
+ const showStageAction = data.scope === "unstaged" || data.scope === "uncommitted";
827
+ const handleStageFile = (0, import_react.useCallback)((filePath) => {
828
+ clientRuntime.runFork(gen(function* stageFile() {
829
+ const { http } = yield* ApiClient;
830
+ return yield* http.git.stage({ payload: { files: [filePath] } });
831
+ }).pipe(tap(() => promise(() => router.invalidate())), catchCause(() => void_)));
832
+ }, [router]);
833
+ const handleCopyFileDiff = (0, import_react.useCallback)(async () => {
834
+ if (!selectedFileData) return;
835
+ const text = selectedFileData.hunks.flatMap((hunk) => hunk.lines.map((line) => line.content)).join("\n");
836
+ await navigator.clipboard.writeText(text);
837
+ }, [selectedFileData]);
838
+ const handleRestoreDraft = (0, import_react.useCallback)(() => {
839
+ if (!recoveryDraft) return;
840
+ setViewedFiles(new Set(recoveryDraft.viewedFiles));
841
+ if (recoveryDraft.selectedFile && data.files.some((f) => f.newPath === recoveryDraft.selectedFile)) setSelectedFile(recoveryDraft.selectedFile);
842
+ setRecoveryDraft(null);
843
+ clearDraft();
844
+ }, [recoveryDraft, data.files]);
845
+ const handleDismissDraft = (0, import_react.useCallback)(() => {
846
+ setRecoveryDraft(null);
847
+ clearDraft();
848
+ }, []);
849
+ const displayedScope = pendingScope ?? data.scope;
850
+ const isScopePending = pendingScope !== null && pendingScope !== data.scope;
851
+ const emptyStateMessage = DIFF_SCOPE_EMPTY_MESSAGES[data.scope];
852
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
853
+ className: "flex h-full flex-col",
854
+ children: [
855
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActionBar, {
856
+ repoName: data.repository.name,
857
+ branchName: data.repository.branch,
858
+ scopeLabel: `${DIFF_SCOPE_LABELS[data.scope]} changes`,
859
+ diffMode,
860
+ onToggleDiffMode: toggleDiffMode,
861
+ onExport: handleExport,
862
+ onCopyDiff: handleCopyFileDiff,
863
+ reviewedFileCount: viewedFiles.size,
864
+ totalFileCount: data.files.length,
865
+ unresolvedCount: annotationsPanel.totalCount,
866
+ isAnnotationsOpen: annotationsPanel.isOpen,
867
+ onToggleAnnotations: annotationsPanel.handleToggle
868
+ }),
869
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
870
+ className: "flex min-h-0 flex-1",
871
+ children: [
872
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileTree, {
873
+ emptyStateMessage,
874
+ files: data.files,
875
+ headerAction: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DiffScopeSelector, {
876
+ fileCount: isScopePending ? void 0 : data.files.length,
877
+ isLoading: isScopePending,
878
+ onChange: handleScopeChange,
879
+ value: displayedScope
880
+ }),
881
+ onSelectFile: handleSelectFile,
882
+ selectedFile,
883
+ reviewedFiles: viewedFiles,
884
+ onToggleViewed: handleToggleViewed,
885
+ onStageFile: showStageAction ? handleStageFile : void 0
886
+ }, data.scope),
887
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
888
+ className: "flex-1 overflow-y-auto bg-surface-primary p-4",
889
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DiffContent, {
890
+ hasFiles: data.files.length > 0,
891
+ emptyMessage: emptyStateMessage,
892
+ file: selectedFileData,
893
+ diffMode,
894
+ summary: data.summary,
895
+ onLocalCommentsChange: handleLocalCommentsChange,
896
+ viewed: selectedFile ? viewedFiles.has(selectedFile) : false,
897
+ onToggleViewed: handleToggleViewed,
898
+ pendingDeleteId,
899
+ onPendingDeleteHandled: handleClearPendingDelete
900
+ })
901
+ }),
902
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnnotationsPanel, {
903
+ isOpen: annotationsPanel.isOpen,
904
+ onClose: annotationsPanel.handleClose,
905
+ groups: annotationGroups,
906
+ totalCount: annotationsPanel.totalCount,
907
+ copyStatus: annotationsPanel.copyStatus,
908
+ onAnnotationClick: annotationsPanel.handleAnnotationClick,
909
+ onDeleteAnnotation: annotationsPanel.handleDeleteAnnotation,
910
+ onCopyFeedback: handleCopyAnnotationFeedback
911
+ })
912
+ ]
913
+ }),
914
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ExportFeedbackModal, {
915
+ open: exportOpen,
916
+ onOpenChange: setExportOpen,
917
+ localComments: localCommentSnapshot
918
+ }),
919
+ recoveryDraft ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DraftRecoveryModal, {
920
+ open: true,
921
+ draft: recoveryDraft,
922
+ onRestore: handleRestoreDraft,
923
+ onDismiss: handleDismissDraft
924
+ }) : null
925
+ ]
926
+ });
927
+ };
928
+ //#endregion
929
+ export { ChangesPage as component };