reviewdeck 0.2.2

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 (315) hide show
  1. package/README.md +75 -0
  2. package/dist/reviewdeck.mjs +1084 -0
  3. package/dist/web/assets/abap-CkQ0tsz-.js +1 -0
  4. package/dist/web/assets/actionscript-3-DHm0ZfF4.js +1 -0
  5. package/dist/web/assets/ada-DK_ua92Z.js +1 -0
  6. package/dist/web/assets/andromeeda-D2ccw8v4.js +1 -0
  7. package/dist/web/assets/angular-html-BW6jlb6j.js +1 -0
  8. package/dist/web/assets/angular-ts-DWBNOji_.js +1 -0
  9. package/dist/web/assets/apache-DXtpFu7o.js +1 -0
  10. package/dist/web/assets/apex-DlnRRWpl.js +1 -0
  11. package/dist/web/assets/apl-uRKDN2p3.js +1 -0
  12. package/dist/web/assets/applescript-CShk62ad.js +1 -0
  13. package/dist/web/assets/ara-CWN-FDkm.js +1 -0
  14. package/dist/web/assets/asciidoc-Bg-PM9Vn.js +1 -0
  15. package/dist/web/assets/asm-DKOhR24S.js +1 -0
  16. package/dist/web/assets/astro-BiNvR4wU.js +1 -0
  17. package/dist/web/assets/aurora-x-DpaEirL8.js +1 -0
  18. package/dist/web/assets/awk-3ibKHffv.js +1 -0
  19. package/dist/web/assets/ayu-dark-ursiSH5k.js +1 -0
  20. package/dist/web/assets/ayu-light-DMjlrKmx.js +1 -0
  21. package/dist/web/assets/ayu-mirage-DZEMb75h.js +1 -0
  22. package/dist/web/assets/ballerina-xx7VNGxs.js +1 -0
  23. package/dist/web/assets/bat-DGYsZ5wR.js +1 -0
  24. package/dist/web/assets/beancount-D_ATR1UV.js +1 -0
  25. package/dist/web/assets/berry-BqYMORfH.js +1 -0
  26. package/dist/web/assets/bibtex-CQTBDajW.js +1 -0
  27. package/dist/web/assets/bicep-CfNtxPrK.js +1 -0
  28. package/dist/web/assets/bird2-C0dUPe3I.js +1 -0
  29. package/dist/web/assets/blade-CogPuRcD.js +1 -0
  30. package/dist/web/assets/bsl-Dx5tFn3i.js +1 -0
  31. package/dist/web/assets/c-c6mXMDpL.js +1 -0
  32. package/dist/web/assets/c3-BUwZ5e3k.js +1 -0
  33. package/dist/web/assets/cadence-C3OKDYrr.js +1 -0
  34. package/dist/web/assets/cairo-wCCQTdA9.js +1 -0
  35. package/dist/web/assets/catppuccin-frappe-CMnRXVZP.js +1 -0
  36. package/dist/web/assets/catppuccin-latte-CqhXSjCC.js +1 -0
  37. package/dist/web/assets/catppuccin-macchiato-B6kneE0C.js +1 -0
  38. package/dist/web/assets/catppuccin-mocha-CP8YZpvj.js +1 -0
  39. package/dist/web/assets/clarity-Crxe8gSr.js +1 -0
  40. package/dist/web/assets/clojure-BuzOUPMr.js +1 -0
  41. package/dist/web/assets/cmake-CCpZLdLI.js +1 -0
  42. package/dist/web/assets/cobol-BBFZi1TD.js +1 -0
  43. package/dist/web/assets/codeowners-Bo1VYpHz.js +1 -0
  44. package/dist/web/assets/codeql-Db01hzHE.js +1 -0
  45. package/dist/web/assets/coffee-CoyNl-Vr.js +1 -0
  46. package/dist/web/assets/common-lisp-CMlJIc6Y.js +1 -0
  47. package/dist/web/assets/coq-BlzBYp3f.js +1 -0
  48. package/dist/web/assets/cpp-BhZISK2o.js +1 -0
  49. package/dist/web/assets/crystal-DARwJIth.js +1 -0
  50. package/dist/web/assets/csharp-kfNshAa7.js +1 -0
  51. package/dist/web/assets/css-BFlkO4hH.js +1 -0
  52. package/dist/web/assets/csv-Dr8ri5Nd.js +1 -0
  53. package/dist/web/assets/cue-jXfhyOwY.js +1 -0
  54. package/dist/web/assets/cypher-CayLeiaR.js +1 -0
  55. package/dist/web/assets/d-BMZQ0mAy.js +1 -0
  56. package/dist/web/assets/dark-plus-B__q47Nr.js +1 -0
  57. package/dist/web/assets/dart-gMOEMyuz.js +1 -0
  58. package/dist/web/assets/dax-C3t5LadU.js +1 -0
  59. package/dist/web/assets/desktop-DmhXLwLR.js +1 -0
  60. package/dist/web/assets/diff-togOXQX6.js +1 -0
  61. package/dist/web/assets/docker--6N01olR.js +1 -0
  62. package/dist/web/assets/dotenv-Bq930Yx8.js +1 -0
  63. package/dist/web/assets/dracula-CBkSghcw.js +1 -0
  64. package/dist/web/assets/dracula-soft-CCSYeoxL.js +1 -0
  65. package/dist/web/assets/dream-maker-BiMf3DHl.js +1 -0
  66. package/dist/web/assets/edge-1uDQap2l.js +1 -0
  67. package/dist/web/assets/elixir-B630FsAX.js +1 -0
  68. package/dist/web/assets/elm-B0CYJExx.js +1 -0
  69. package/dist/web/assets/emacs-lisp-Dhht7he2.js +1 -0
  70. package/dist/web/assets/erb-BCuuvlI8.js +1 -0
  71. package/dist/web/assets/erlang-CtK0kQ6z.js +1 -0
  72. package/dist/web/assets/everforest-dark-NqSz4oHS.js +1 -0
  73. package/dist/web/assets/everforest-light-a3Yzs_lT.js +1 -0
  74. package/dist/web/assets/fennel-BExc9TZf.js +1 -0
  75. package/dist/web/assets/fish-C2p-AJmZ.js +1 -0
  76. package/dist/web/assets/fluent-CeYzs8Qy.js +1 -0
  77. package/dist/web/assets/fortran-fixed-form-DBM4e0_k.js +1 -0
  78. package/dist/web/assets/fortran-free-form-BIQEK2Jw.js +1 -0
  79. package/dist/web/assets/fsharp-CmzzGQLe.js +1 -0
  80. package/dist/web/assets/gdresource-B_wbPqHd.js +1 -0
  81. package/dist/web/assets/gdscript-B5JQPh_-.js +1 -0
  82. package/dist/web/assets/gdshader-vVjJ_Qr8.js +1 -0
  83. package/dist/web/assets/genie-DGl5rqC8.js +1 -0
  84. package/dist/web/assets/gherkin-CY_VLUnD.js +1 -0
  85. package/dist/web/assets/git-commit-1z4D6NzL.js +1 -0
  86. package/dist/web/assets/git-rebase-CMGqxEzO.js +1 -0
  87. package/dist/web/assets/github-dark-ClO4AStc.js +1 -0
  88. package/dist/web/assets/github-dark-default-CM0dPco8.js +1 -0
  89. package/dist/web/assets/github-dark-dimmed-Cb6xxpXY.js +1 -0
  90. package/dist/web/assets/github-dark-high-contrast-BpYtx2-M.js +1 -0
  91. package/dist/web/assets/github-light-CeOVFgf_.js +1 -0
  92. package/dist/web/assets/github-light-default-BmnCWL6x.js +1 -0
  93. package/dist/web/assets/github-light-high-contrast-rpagNF5O.js +1 -0
  94. package/dist/web/assets/gleam-BarIG9kQ.js +1 -0
  95. package/dist/web/assets/glimmer-js-CwCQsT5O.js +1 -0
  96. package/dist/web/assets/glimmer-ts-CDiy87zB.js +1 -0
  97. package/dist/web/assets/glsl-KkJIjOyq.js +1 -0
  98. package/dist/web/assets/gn-DhYsTPYc.js +1 -0
  99. package/dist/web/assets/gnuplot-CucLlTBc.js +1 -0
  100. package/dist/web/assets/go-toi-uWvg.js +1 -0
  101. package/dist/web/assets/graphql-MKTYUDMa.js +1 -0
  102. package/dist/web/assets/groovy-Ds4dis_k.js +1 -0
  103. package/dist/web/assets/gruvbox-dark-hard-aPiW8pQh.js +1 -0
  104. package/dist/web/assets/gruvbox-dark-medium-2HJCvzsS.js +1 -0
  105. package/dist/web/assets/gruvbox-dark-soft-Da97ODX9.js +1 -0
  106. package/dist/web/assets/gruvbox-light-hard-BXlEipFe.js +1 -0
  107. package/dist/web/assets/gruvbox-light-medium-Cun-GjGk.js +1 -0
  108. package/dist/web/assets/gruvbox-light-soft-Bd3qiiSw.js +1 -0
  109. package/dist/web/assets/hack-Bwo3McIF.js +1 -0
  110. package/dist/web/assets/haml-D88Ucy2e.js +1 -0
  111. package/dist/web/assets/handlebars-BU0LZwZ1.js +1 -0
  112. package/dist/web/assets/haskell-B_jvz5Po.js +1 -0
  113. package/dist/web/assets/haxe-BRbuo5UO.js +1 -0
  114. package/dist/web/assets/hcl-BzNUCtsK.js +1 -0
  115. package/dist/web/assets/hjson-BxVo3sS2.js +1 -0
  116. package/dist/web/assets/hlsl-C8Wes1nf.js +1 -0
  117. package/dist/web/assets/horizon-D54PjLAY.js +1 -0
  118. package/dist/web/assets/horizon-bright-D9RccdIr.js +1 -0
  119. package/dist/web/assets/houston-CMu1N_4K.js +1 -0
  120. package/dist/web/assets/html-DrMQJsXw.js +1 -0
  121. package/dist/web/assets/html-derivative-0WBbZowl.js +1 -0
  122. package/dist/web/assets/http-DbEAkxXN.js +1 -0
  123. package/dist/web/assets/hurl-CqJXynMd.js +1 -0
  124. package/dist/web/assets/hxml-DC4KwKt2.js +1 -0
  125. package/dist/web/assets/hy-dMrJKKU_.js +1 -0
  126. package/dist/web/assets/imba-DG_oO8tg.js +1 -0
  127. package/dist/web/assets/index-BPtNzy1Q.js +1934 -0
  128. package/dist/web/assets/index-BkEoZ-nI.css +2 -0
  129. package/dist/web/assets/ini-geHw79Aj.js +1 -0
  130. package/dist/web/assets/java-BRVCc-Q1.js +1 -0
  131. package/dist/web/assets/javascript-BD4fYJEn.js +1 -0
  132. package/dist/web/assets/jinja-CelQ23ws.js +1 -0
  133. package/dist/web/assets/jison-DBS-9n7v.js +1 -0
  134. package/dist/web/assets/json-DZDuupM6.js +1 -0
  135. package/dist/web/assets/json5-CDUsNqz6.js +1 -0
  136. package/dist/web/assets/jsonc-D48xcwyD.js +1 -0
  137. package/dist/web/assets/jsonl-cpIYDXEe.js +1 -0
  138. package/dist/web/assets/jsonnet-Da1lhszN.js +1 -0
  139. package/dist/web/assets/jssm-B8BLrEGL.js +1 -0
  140. package/dist/web/assets/jsx-BZOBrdrR.js +1 -0
  141. package/dist/web/assets/julia-BCQpMN0P.js +1 -0
  142. package/dist/web/assets/just-C3xXABnW.js +1 -0
  143. package/dist/web/assets/kanagawa-dragon-2Sk8Rx83.js +1 -0
  144. package/dist/web/assets/kanagawa-lotus-CQVSWfJp.js +1 -0
  145. package/dist/web/assets/kanagawa-wave-BKWNioLX.js +1 -0
  146. package/dist/web/assets/kdl-B-2tSRmp.js +1 -0
  147. package/dist/web/assets/kotlin-DepsEzh3.js +1 -0
  148. package/dist/web/assets/kusto-BcCtXIb8.js +1 -0
  149. package/dist/web/assets/laserwave-BUqkO46F.js +1 -0
  150. package/dist/web/assets/latex-OIm821Jq.js +1 -0
  151. package/dist/web/assets/lean-CNO9ffpX.js +1 -0
  152. package/dist/web/assets/less-Dj0T9pWC.js +1 -0
  153. package/dist/web/assets/light-plus-C9Hnuc1T.js +1 -0
  154. package/dist/web/assets/liquid-CtRnMjLR.js +1 -0
  155. package/dist/web/assets/llvm-DbV9b66l.js +1 -0
  156. package/dist/web/assets/log-BMblmPyH.js +1 -0
  157. package/dist/web/assets/logo-B78qMxws.js +1 -0
  158. package/dist/web/assets/lua-C4GAsLLv.js +1 -0
  159. package/dist/web/assets/luau-BUd8xsdE.js +1 -0
  160. package/dist/web/assets/make-Ev-6cJrd.js +1 -0
  161. package/dist/web/assets/markdown-CS4LI6sN.js +1 -0
  162. package/dist/web/assets/marko-BzBo2m_h.js +1 -0
  163. package/dist/web/assets/material-theme-5rA1zn0D.js +1 -0
  164. package/dist/web/assets/material-theme-darker-DGOEiL65.js +1 -0
  165. package/dist/web/assets/material-theme-lighter-CULfFRX0.js +1 -0
  166. package/dist/web/assets/material-theme-ocean-LQZ9CleP.js +1 -0
  167. package/dist/web/assets/material-theme-palenight-Di_f5oks.js +1 -0
  168. package/dist/web/assets/matlab-C0qEtAx9.js +1 -0
  169. package/dist/web/assets/mdc-Diez5J4p.js +1 -0
  170. package/dist/web/assets/mdx-CzvnbLXb.js +1 -0
  171. package/dist/web/assets/mermaid-BPquZaKt.js +1 -0
  172. package/dist/web/assets/min-dark-rkuIbtJV.js +1 -0
  173. package/dist/web/assets/min-light-Dj_HOGsr.js +1 -0
  174. package/dist/web/assets/mipsasm-k5DQoS6j.js +1 -0
  175. package/dist/web/assets/mojo-sTTDuNnR.js +1 -0
  176. package/dist/web/assets/monokai-D5p-u2ij.js +1 -0
  177. package/dist/web/assets/moonbit-j5ChFtBC.js +1 -0
  178. package/dist/web/assets/move-Dj0Gmn6R.js +1 -0
  179. package/dist/web/assets/narrat-DJgMz2oW.js +1 -0
  180. package/dist/web/assets/nextflow-CApkvBGW.js +1 -0
  181. package/dist/web/assets/nextflow-groovy-eDLuZ_oi.js +1 -0
  182. package/dist/web/assets/nginx-B-O05-Ip.js +1 -0
  183. package/dist/web/assets/night-owl-CEdtPl3A.js +1 -0
  184. package/dist/web/assets/night-owl-light-GdSldewm.js +1 -0
  185. package/dist/web/assets/nim-DYodfN_j.js +1 -0
  186. package/dist/web/assets/nix-CxIPS3pb.js +1 -0
  187. package/dist/web/assets/nord-3WFAz5H9.js +1 -0
  188. package/dist/web/assets/nushell-GDfBmoBU.js +1 -0
  189. package/dist/web/assets/objective-c-MFQ_MGUa.js +1 -0
  190. package/dist/web/assets/objective-cpp-Y83LcBE7.js +1 -0
  191. package/dist/web/assets/ocaml-FxYfaJxu.js +1 -0
  192. package/dist/web/assets/odin-CprihY3z.js +1 -0
  193. package/dist/web/assets/one-dark-pro-BB6mpmmA.js +1 -0
  194. package/dist/web/assets/one-light-BYLoxNtg.js +1 -0
  195. package/dist/web/assets/openscad-Bc1FbpOi.js +1 -0
  196. package/dist/web/assets/pascal-Bb4d8cUL.js +1 -0
  197. package/dist/web/assets/perl-BajmpJw1.js +1 -0
  198. package/dist/web/assets/php-GbSlF-ma.js +1 -0
  199. package/dist/web/assets/pierre-dark-DbQedTMH.js +1 -0
  200. package/dist/web/assets/pierre-light-DxtrzyCi.js +1 -0
  201. package/dist/web/assets/pkl-tM25Sq0w.js +1 -0
  202. package/dist/web/assets/plastic-D3k2Xp_5.js +1 -0
  203. package/dist/web/assets/plsql-CLEfFhSj.js +1 -0
  204. package/dist/web/assets/po-CaAzdrrh.js +1 -0
  205. package/dist/web/assets/poimandres-bPTvT4Da.js +1 -0
  206. package/dist/web/assets/polar-TG7aTGdK.js +1 -0
  207. package/dist/web/assets/postcss-8kqfa9f0.js +1 -0
  208. package/dist/web/assets/powerquery-CtSu1Nfd.js +1 -0
  209. package/dist/web/assets/powershell-87lLBHMy.js +1 -0
  210. package/dist/web/assets/prisma-Dnf694DZ.js +1 -0
  211. package/dist/web/assets/prolog-C0XbHTWa.js +1 -0
  212. package/dist/web/assets/proto-BZP-HLIb.js +1 -0
  213. package/dist/web/assets/pug-B3pftVq7.js +1 -0
  214. package/dist/web/assets/puppet-CJYWgYC5.js +1 -0
  215. package/dist/web/assets/purescript-B95Q6BAd.js +1 -0
  216. package/dist/web/assets/python-CqTCsi7P.js +1 -0
  217. package/dist/web/assets/qml-CU7fIqWl.js +1 -0
  218. package/dist/web/assets/qmldir-DlIL4hls.js +1 -0
  219. package/dist/web/assets/qss-BW72E0q_.js +1 -0
  220. package/dist/web/assets/r-VFD3g93S.js +1 -0
  221. package/dist/web/assets/racket-CCAimEsC.js +1 -0
  222. package/dist/web/assets/raku-mSuqElkM.js +1 -0
  223. package/dist/web/assets/razor-YJmCxoz7.js +1 -0
  224. package/dist/web/assets/red-C-DA4yBI.js +1 -0
  225. package/dist/web/assets/reg-CGwMBJ2c.js +1 -0
  226. package/dist/web/assets/regexp-xQImVJyz.js +1 -0
  227. package/dist/web/assets/rel-JwrbYgX4.js +1 -0
  228. package/dist/web/assets/riscv-CoYyE75b.js +1 -0
  229. package/dist/web/assets/ron-C5wrhnmJ.js +1 -0
  230. package/dist/web/assets/rose-pine-DlrMPYYd.js +1 -0
  231. package/dist/web/assets/rose-pine-dawn-DBHFtZD2.js +1 -0
  232. package/dist/web/assets/rose-pine-moon-BBfrpe5q.js +1 -0
  233. package/dist/web/assets/rosmsg-DlimTR9t.js +1 -0
  234. package/dist/web/assets/rst-C-l1vIhG.js +1 -0
  235. package/dist/web/assets/ruby-ClXcG6Uc.js +1 -0
  236. package/dist/web/assets/rust-Cxnkxx3h.js +1 -0
  237. package/dist/web/assets/sas-UbdvwYYC.js +1 -0
  238. package/dist/web/assets/sass-DEyqUIpU.js +1 -0
  239. package/dist/web/assets/scala-i3RN3yAN.js +1 -0
  240. package/dist/web/assets/scheme-BcKdjYkO.js +1 -0
  241. package/dist/web/assets/scss-BSFxtSCj.js +1 -0
  242. package/dist/web/assets/sdbl-Be_XWc3n.js +1 -0
  243. package/dist/web/assets/shaderlab-DXAhMdPo.js +1 -0
  244. package/dist/web/assets/shellscript-DipAQUtx.js +1 -0
  245. package/dist/web/assets/shellsession-4iJrG6C5.js +1 -0
  246. package/dist/web/assets/slack-dark-3PDtm74m.js +1 -0
  247. package/dist/web/assets/slack-ochin-CwiuFRJD.js +1 -0
  248. package/dist/web/assets/smalltalk-BdBlL6ks.js +1 -0
  249. package/dist/web/assets/snazzy-light-Dyqc8Is2.js +1 -0
  250. package/dist/web/assets/solarized-dark-DZiTscIX.js +1 -0
  251. package/dist/web/assets/solarized-light-DBcfxrfG.js +1 -0
  252. package/dist/web/assets/solidity-DH-yUSWc.js +1 -0
  253. package/dist/web/assets/soy-DbrU_Nxg.js +1 -0
  254. package/dist/web/assets/sparql-BdcL8cbr.js +1 -0
  255. package/dist/web/assets/splunk-CIjc4kxs.js +1 -0
  256. package/dist/web/assets/sql-5eAwe7x9.js +1 -0
  257. package/dist/web/assets/ssh-config-BKVd4drG.js +1 -0
  258. package/dist/web/assets/stata-DPzpuJuP.js +1 -0
  259. package/dist/web/assets/stylus-tqAsmugv.js +1 -0
  260. package/dist/web/assets/surrealql-BFHjstCU.js +1 -0
  261. package/dist/web/assets/svelte-DEFiloGp.js +1 -0
  262. package/dist/web/assets/swift-CdDBQ3_Z.js +1 -0
  263. package/dist/web/assets/synthwave-84-CbbRs73K.js +1 -0
  264. package/dist/web/assets/system-verilog-CBqEY-9v.js +1 -0
  265. package/dist/web/assets/systemd-khRP5zwK.js +1 -0
  266. package/dist/web/assets/talonscript-D_lneH-6.js +1 -0
  267. package/dist/web/assets/tasl-CLymawGe.js +1 -0
  268. package/dist/web/assets/tcl-BRY1S87U.js +1 -0
  269. package/dist/web/assets/templ-B3axXApj.js +1 -0
  270. package/dist/web/assets/terraform-BqohMo2f.js +1 -0
  271. package/dist/web/assets/tex-DhbFB_y0.js +1 -0
  272. package/dist/web/assets/tokyo-night-BWUONxad.js +1 -0
  273. package/dist/web/assets/toml-C4c85Lwg.js +1 -0
  274. package/dist/web/assets/ts-tags-BN89t81C.js +1 -0
  275. package/dist/web/assets/tsv-DsZq9HBQ.js +1 -0
  276. package/dist/web/assets/tsx-LzmugIB3.js +1 -0
  277. package/dist/web/assets/turtle-Dpr8zLlw.js +1 -0
  278. package/dist/web/assets/twig-BcvJvETg.js +1 -0
  279. package/dist/web/assets/typescript-vZfgIWhk.js +1 -0
  280. package/dist/web/assets/typespec-DcqgATB-.js +1 -0
  281. package/dist/web/assets/typst-CeVxmuPg.js +1 -0
  282. package/dist/web/assets/v-C2Qsh2-1.js +1 -0
  283. package/dist/web/assets/vala-CvZ3yL7c.js +1 -0
  284. package/dist/web/assets/vb-B_p4qDw4.js +1 -0
  285. package/dist/web/assets/verilog-D8MGjxD7.js +1 -0
  286. package/dist/web/assets/vesper-DossXiE1.js +1 -0
  287. package/dist/web/assets/vhdl-MLyYh_Gz.js +1 -0
  288. package/dist/web/assets/viml-BuYIArcz.js +1 -0
  289. package/dist/web/assets/vitesse-black-C3kc1227.js +1 -0
  290. package/dist/web/assets/vitesse-dark-kWOu5V36.js +1 -0
  291. package/dist/web/assets/vitesse-light-DMtiL8bK.js +1 -0
  292. package/dist/web/assets/vue-DTJd19mx.js +1 -0
  293. package/dist/web/assets/vue-html-DN1O1Gud.js +1 -0
  294. package/dist/web/assets/vue-vine-CPt4e1Kz.js +1 -0
  295. package/dist/web/assets/vyper-CNqG09-_.js +1 -0
  296. package/dist/web/assets/wasm-BsQDV7Y0.js +1 -0
  297. package/dist/web/assets/wasm-DFVlQlgd.js +1 -0
  298. package/dist/web/assets/wenyan-BmOQge13.js +1 -0
  299. package/dist/web/assets/wgsl-CgWrmvIg.js +1 -0
  300. package/dist/web/assets/wikitext-DkwckXCk.js +1 -0
  301. package/dist/web/assets/wit-CtyVFGe7.js +1 -0
  302. package/dist/web/assets/wolfram-CXE4FrKz.js +1 -0
  303. package/dist/web/assets/xml-fA_cpwGb.js +1 -0
  304. package/dist/web/assets/xsl-3f3GC_Uf.js +1 -0
  305. package/dist/web/assets/yaml-Ca1_GRr1.js +1 -0
  306. package/dist/web/assets/zenscript-DH15wJt0.js +1 -0
  307. package/dist/web/assets/zig-CqXN9brD.js +1 -0
  308. package/dist/web/index.html +13 -0
  309. package/dist/web-inline/assets/index-BkEoZ-nI.css +2 -0
  310. package/dist/web-inline/assets/index-Qzj-BIcs.js +1933 -0
  311. package/dist/web-inline/index.html +13 -0
  312. package/package.json +65 -0
  313. package/skills/reviewdeck/SKILL.md +121 -0
  314. package/skills/reviewdeck/assets/prompt-template.md +111 -0
  315. package/skills/reviewdeck/references/get-diff.md +24 -0
@@ -0,0 +1,1084 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/cli/render.ts
13
+ var render_exports = {};
14
+ __export(render_exports, {
15
+ generateStaticHtml: () => generateStaticHtml,
16
+ parseSubPatchesFromDir: () => parseSubPatchesFromDir,
17
+ parseSubPatchesFromStdin: () => parseSubPatchesFromStdin,
18
+ startReviewServer: () => startReviewServer
19
+ });
20
+ import { createServer } from "node:http";
21
+ import { resolve, extname } from "node:path";
22
+ import { readFile, readdir, stat } from "node:fs/promises";
23
+ async function findDir(candidates) {
24
+ for (const dir of candidates) {
25
+ try {
26
+ const s = await stat(dir);
27
+ if (s.isDirectory()) return dir;
28
+ } catch {
29
+ }
30
+ }
31
+ return null;
32
+ }
33
+ async function resolveDistDir() {
34
+ const candidates = [
35
+ resolve(import.meta.dirname, "web"),
36
+ resolve(import.meta.dirname, "../../dist/web")
37
+ ];
38
+ const dir = await findDir(candidates);
39
+ if (!dir) {
40
+ console.error(`ERROR: Web UI not built. Run "npm run build:web" first.`);
41
+ process.exit(1);
42
+ }
43
+ return dir;
44
+ }
45
+ async function generateStaticHtml(subPatches) {
46
+ const candidates = [
47
+ resolve(import.meta.dirname, "web-inline"),
48
+ resolve(import.meta.dirname, "../../dist/web-inline")
49
+ ];
50
+ const distDir = await findDir(candidates) ?? await resolveDistDir();
51
+ const indexHtml = await readFile(resolve(distDir, "index.html"), "utf-8");
52
+ const cssMatch = indexHtml.match(/href="(\/assets\/[^"]+\.css)"/);
53
+ const jsMatch = indexHtml.match(/src="(\/assets\/[^"]+\.js)"/);
54
+ let css = "";
55
+ let js = "";
56
+ if (cssMatch) {
57
+ css = await readFile(resolve(distDir, cssMatch[1].slice(1)), "utf-8");
58
+ }
59
+ if (jsMatch) {
60
+ js = await readFile(resolve(distDir, jsMatch[1].slice(1)), "utf-8");
61
+ }
62
+ const dataScript = `<script>window.__PATCHES__=${JSON.stringify(subPatches)};</script>`;
63
+ return `<!doctype html>
64
+ <html lang="en" class="dark">
65
+ <head>
66
+ <meta charset="UTF-8" />
67
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
68
+ <title>Stacked Diff Review</title>
69
+ <style>${css}</style>
70
+ </head>
71
+ <body>
72
+ <div id="root"></div>
73
+ ${dataScript}
74
+ <script type="module">${js}</script>
75
+ </body>
76
+ </html>`;
77
+ }
78
+ async function startReviewServer(subPatches, opts = {}) {
79
+ const port = opts.port ?? 3847;
80
+ const distDir = await resolveDistDir();
81
+ return new Promise((resolveComments) => {
82
+ const httpServer = createServer(async (req, res) => {
83
+ const url = req.url ?? "/";
84
+ if (url === "/api/patches" && req.method === "GET") {
85
+ res.writeHead(200, { "Content-Type": "application/json" });
86
+ res.end(JSON.stringify(subPatches));
87
+ return;
88
+ }
89
+ if (url === "/api/submit" && req.method === "POST") {
90
+ const chunks = [];
91
+ req.on("data", (chunk) => chunks.push(chunk));
92
+ req.on("end", () => {
93
+ const submission = JSON.parse(Buffer.concat(chunks).toString("utf-8"));
94
+ res.writeHead(200, { "Content-Type": "application/json" });
95
+ res.end(JSON.stringify({ ok: true }));
96
+ setTimeout(() => {
97
+ httpServer.close(() => resolveComments(submission));
98
+ }, 500);
99
+ });
100
+ return;
101
+ }
102
+ await serveStatic(distDir, url, res);
103
+ });
104
+ httpServer.listen(port, () => {
105
+ const url = `http://localhost:${port}`;
106
+ console.error(`Review server running at ${url}`);
107
+ console.error("Waiting for review submission...\n");
108
+ import("node:child_process").then(({ exec }) => {
109
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
110
+ exec(`${cmd} ${url}`);
111
+ });
112
+ });
113
+ });
114
+ }
115
+ async function serveStatic(distDir, url, res) {
116
+ const pathname = url.split("?")[0];
117
+ let filePath = resolve(distDir, pathname === "/" ? "index.html" : `.${pathname}`);
118
+ try {
119
+ const fileStat = await stat(filePath);
120
+ if (fileStat.isDirectory()) {
121
+ filePath = resolve(filePath, "index.html");
122
+ }
123
+ } catch {
124
+ filePath = resolve(distDir, "index.html");
125
+ }
126
+ try {
127
+ const content = await readFile(filePath);
128
+ const ext = extname(filePath);
129
+ const mime = MIME_TYPES[ext] ?? "application/octet-stream";
130
+ res.writeHead(200, { "Content-Type": mime });
131
+ res.end(content);
132
+ } catch {
133
+ res.writeHead(404);
134
+ res.end("Not found");
135
+ }
136
+ }
137
+ function parseSubPatchesFromStdin(input, separator) {
138
+ if (input.trimStart().startsWith(separator)) {
139
+ return parseHeaderedSubPatches(input, separator);
140
+ }
141
+ return parseLegacySubPatches(input, separator);
142
+ }
143
+ function parseHeaderedSubPatches(input, separator) {
144
+ const regex = new RegExp(`^${escapeRegex(separator)}(?: (.+))?$`, "gm");
145
+ const matches = [...input.matchAll(regex)];
146
+ const results = [];
147
+ for (let i = 0; i < matches.length; i++) {
148
+ const match = matches[i];
149
+ const next = matches[i + 1];
150
+ const metadataRaw = match[1]?.trim();
151
+ const start = match.index + match[0].length + 1;
152
+ const end = next ? next.index : input.length;
153
+ const diff = input.slice(start, end).trim();
154
+ if (!diff) continue;
155
+ const metadata = parseSeparatorMetadata(metadataRaw, results.length);
156
+ results.push({
157
+ index: metadata.index ?? results.length,
158
+ description: metadata.description,
159
+ draftComments: metadata.draftComments ?? [],
160
+ diff
161
+ });
162
+ }
163
+ return results;
164
+ }
165
+ function parseLegacySubPatches(input, separator) {
166
+ const separatorRegex = new RegExp(`
167
+ ${escapeRegex(separator)}(?: (.+))?
168
+ `);
169
+ const parts = input.split(separatorRegex);
170
+ const results = [];
171
+ for (let i = 0; i < parts.length; i += 2) {
172
+ const diff = parts[i].trim();
173
+ if (!diff) continue;
174
+ const desc = i > 0 ? parts[i - 1] : void 0;
175
+ const fileMatch = diff.match(/^diff --git a\/(.+?) b\//m);
176
+ const description = desc?.trim() ?? (fileMatch ? `Changes to ${fileMatch[1]}` : `Sub-patch ${results.length + 1}`);
177
+ results.push({ index: results.length, description, draftComments: [], diff });
178
+ }
179
+ return results;
180
+ }
181
+ function parseSeparatorMetadata(raw, fallbackIndex) {
182
+ if (!raw) return { index: fallbackIndex, description: `Sub-patch ${fallbackIndex + 1}` };
183
+ try {
184
+ const parsed = JSON.parse(raw);
185
+ return {
186
+ index: parsed.index ?? fallbackIndex,
187
+ description: parsed.description?.trim() || `Sub-patch ${fallbackIndex + 1}`,
188
+ draftComments: parsed.draftComments ?? []
189
+ };
190
+ } catch {
191
+ return { index: fallbackIndex, description: raw.trim(), draftComments: [] };
192
+ }
193
+ }
194
+ function escapeRegex(s) {
195
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
196
+ }
197
+ async function parseSubPatchesFromDir(dir) {
198
+ const files = (await readdir(dir)).filter((f) => f.endsWith(".diff")).sort((a, b) => {
199
+ const na = parseInt(a.match(/(\d+)/)?.[1] ?? "0");
200
+ const nb = parseInt(b.match(/(\d+)/)?.[1] ?? "0");
201
+ return na - nb || a.localeCompare(b);
202
+ });
203
+ let metaRecords = [];
204
+ try {
205
+ const raw = await readFile(resolve(dir, "meta.json"), "utf-8");
206
+ const meta = JSON.parse(raw);
207
+ metaRecords = meta.sort((a, b) => a.index - b.index);
208
+ } catch {
209
+ }
210
+ const patches = [];
211
+ for (let i = 0; i < files.length; i++) {
212
+ const diff = await readFile(resolve(dir, files[i]), "utf-8");
213
+ const meta = metaRecords[i];
214
+ const description = meta?.description ?? diff.match(/^diff --git a\/(.+?) b\//m)?.[1] ?? `Sub-patch ${i + 1}`;
215
+ patches.push({
216
+ index: i,
217
+ description,
218
+ draftComments: meta?.draftComments ?? [],
219
+ diff: diff.trim()
220
+ });
221
+ }
222
+ return patches;
223
+ }
224
+ var MIME_TYPES;
225
+ var init_render = __esm({
226
+ "src/cli/render.ts"() {
227
+ "use strict";
228
+ MIME_TYPES = {
229
+ ".html": "text/html",
230
+ ".js": "application/javascript",
231
+ ".css": "text/css",
232
+ ".json": "application/json",
233
+ ".svg": "image/svg+xml",
234
+ ".png": "image/png",
235
+ ".woff2": "font/woff2"
236
+ };
237
+ }
238
+ });
239
+
240
+ // src/cli/main.ts
241
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
242
+ import { readFile as readFile2 } from "node:fs/promises";
243
+ import { parseArgs } from "node:util";
244
+
245
+ // src/core/types.ts
246
+ var PatchError = class extends Error {
247
+ /** The file state at the time of failure */
248
+ fileSnapshot;
249
+ /** Which line in the file the error occurred at (1-indexed) */
250
+ errorLine;
251
+ constructor(message) {
252
+ super(message);
253
+ this.name = "PatchError";
254
+ }
255
+ };
256
+
257
+ // src/core/patch.ts
258
+ function parsePatch(text) {
259
+ const patches = [];
260
+ const lines = text.split("\n");
261
+ let i = 0;
262
+ while (i < lines.length) {
263
+ if (!lines[i].startsWith("diff --git ")) {
264
+ i++;
265
+ continue;
266
+ }
267
+ const m = lines[i].match(/^diff --git a\/(.*) b\/(.*)/);
268
+ const srcName = m?.[1] ?? "";
269
+ const dstName = m?.[2] ?? "";
270
+ i++;
271
+ let isNew = false;
272
+ let isDelete = false;
273
+ while (i < lines.length && !lines[i].startsWith("--- ") && !lines[i].startsWith("diff --git ")) {
274
+ if (lines[i].startsWith("new file")) isNew = true;
275
+ if (lines[i].startsWith("deleted file")) isDelete = true;
276
+ i++;
277
+ }
278
+ if (i >= lines.length || lines[i].startsWith("diff --git ")) {
279
+ patches.push({ srcFile: srcName, dstFile: dstName, hunks: [], isNew, isDelete });
280
+ continue;
281
+ }
282
+ let srcFile = srcName;
283
+ if (lines[i].startsWith("--- ")) {
284
+ const raw = lines[i].slice(4).trim();
285
+ if (raw.startsWith("a/")) srcFile = raw.slice(2);
286
+ else if (raw === "/dev/null") srcFile = dstName;
287
+ else srcFile = raw;
288
+ i++;
289
+ }
290
+ let dstFile = dstName;
291
+ if (i < lines.length && lines[i].startsWith("+++ ")) {
292
+ const raw = lines[i].slice(4).trim();
293
+ if (raw.startsWith("b/")) dstFile = raw.slice(2);
294
+ else if (raw === "/dev/null") dstFile = srcFile;
295
+ else dstFile = raw;
296
+ i++;
297
+ }
298
+ const hunks = [];
299
+ while (i < lines.length && lines[i].startsWith("@@")) {
300
+ const [hunk, nextI] = parseHunk(lines, i);
301
+ hunks.push(hunk);
302
+ i = nextI;
303
+ }
304
+ patches.push({ srcFile, dstFile, hunks, isNew, isDelete });
305
+ }
306
+ return patches;
307
+ }
308
+ function parseHunk(lines, i) {
309
+ const m = lines[i].match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
310
+ if (!m) throw new PatchError(`Invalid hunk header: ${lines[i]}`);
311
+ const srcStart = parseInt(m[1]);
312
+ const srcCount = m[2] !== void 0 ? parseInt(m[2]) : 1;
313
+ const dstStart = parseInt(m[3]);
314
+ const dstCount = m[4] !== void 0 ? parseInt(m[4]) : 1;
315
+ i++;
316
+ const hunkLines = [];
317
+ let srcSeen = 0;
318
+ let dstSeen = 0;
319
+ while (i < lines.length) {
320
+ const line = lines[i];
321
+ if (line.startsWith("@@") || line.startsWith("diff --git ")) break;
322
+ if (line.startsWith("-")) {
323
+ hunkLines.push({ type: "-", content: line.slice(1) });
324
+ srcSeen++;
325
+ } else if (line.startsWith("+")) {
326
+ hunkLines.push({ type: "+", content: line.slice(1) });
327
+ dstSeen++;
328
+ } else if (line.startsWith(" ")) {
329
+ hunkLines.push({ type: " ", content: line.slice(1) });
330
+ srcSeen++;
331
+ dstSeen++;
332
+ } else if (line === "\") {
333
+ hunkLines.push({ type: "\\", content: "" });
334
+ } else if (line === "") {
335
+ if (srcSeen < srcCount && dstSeen < dstCount) {
336
+ hunkLines.push({ type: " ", content: "" });
337
+ srcSeen++;
338
+ dstSeen++;
339
+ } else {
340
+ break;
341
+ }
342
+ } else {
343
+ break;
344
+ }
345
+ i++;
346
+ if (srcSeen >= srcCount && dstSeen >= dstCount) {
347
+ if (i < lines.length && lines[i] === "\") {
348
+ hunkLines.push({ type: "\\", content: "" });
349
+ i++;
350
+ }
351
+ break;
352
+ }
353
+ }
354
+ return [{ srcStart, srcCount, dstStart, dstCount, lines: hunkLines }, i];
355
+ }
356
+ function applyPatch(fileContents, patches) {
357
+ const result = /* @__PURE__ */ new Map();
358
+ for (const [k, v] of fileContents) {
359
+ result.set(k, [...v]);
360
+ }
361
+ for (const fp of patches) {
362
+ if (fp.isNew) {
363
+ const newLines = [];
364
+ for (const hunk of fp.hunks) {
365
+ for (const hl of hunk.lines) {
366
+ if (hl.type === "+") newLines.push(hl.content);
367
+ }
368
+ }
369
+ result.set(fp.dstFile, newLines);
370
+ continue;
371
+ }
372
+ if (fp.isDelete) {
373
+ result.delete(fp.srcFile);
374
+ continue;
375
+ }
376
+ if (!result.has(fp.dstFile) && result.has(fp.srcFile)) {
377
+ result.set(fp.dstFile, result.get(fp.srcFile));
378
+ result.delete(fp.srcFile);
379
+ }
380
+ const target = fp.dstFile;
381
+ if (!result.has(target)) {
382
+ throw new PatchError(`File not found: ${target}`);
383
+ }
384
+ const content = result.get(target);
385
+ for (let h = fp.hunks.length - 1; h >= 0; h--) {
386
+ const hunk = fp.hunks[h];
387
+ const start = hunk.srcStart - 1;
388
+ const oldLines = hunk.lines.filter((l) => l.type === " " || l.type === "-").map((l) => l.content);
389
+ const newLines = hunk.lines.filter((l) => l.type === " " || l.type === "+").map((l) => l.content);
390
+ for (let j = 0; j < oldLines.length; j++) {
391
+ const idx = start + j;
392
+ if (idx >= content.length) {
393
+ const err = new PatchError(
394
+ `${target}:${idx + 1}: unexpected EOF, expected: ${JSON.stringify(oldLines[j])}`
395
+ );
396
+ err.fileSnapshot = [...content];
397
+ err.errorLine = idx + 1;
398
+ throw err;
399
+ }
400
+ if (content[idx] !== oldLines[j]) {
401
+ const err = new PatchError(
402
+ `${target}:${idx + 1}: context mismatch
403
+ expected: ${JSON.stringify(oldLines[j])}
404
+ actual: ${JSON.stringify(content[idx])}`
405
+ );
406
+ err.fileSnapshot = [...content];
407
+ err.errorLine = idx + 1;
408
+ throw err;
409
+ }
410
+ }
411
+ content.splice(start, oldLines.length, ...newLines);
412
+ }
413
+ }
414
+ return result;
415
+ }
416
+ function reconstructBase(patches) {
417
+ const base = /* @__PURE__ */ new Map();
418
+ for (const fp of patches) {
419
+ if (fp.isNew) continue;
420
+ if (fp.hunks.length === 0) {
421
+ if (!base.has(fp.srcFile)) {
422
+ base.set(fp.srcFile, []);
423
+ }
424
+ continue;
425
+ }
426
+ const lastHunk = fp.hunks[fp.hunks.length - 1];
427
+ const lastCoveredLine = lastHunk.srcStart + lastHunk.srcCount - 1;
428
+ const fileLines = Array.from({ length: lastCoveredLine }).fill("");
429
+ const known = /* @__PURE__ */ new Set();
430
+ for (const hunk of fp.hunks) {
431
+ let srcLine = hunk.srcStart - 1;
432
+ for (const hl of hunk.lines) {
433
+ if (hl.type === " " || hl.type === "-") {
434
+ fileLines[srcLine] = hl.content;
435
+ known.add(srcLine);
436
+ srcLine++;
437
+ }
438
+ }
439
+ }
440
+ for (let i = 0; i < fileLines.length; i++) {
441
+ if (!known.has(i)) {
442
+ fileLines[i] = `__PLACEHOLDER_LINE_${i + 1}__`;
443
+ }
444
+ }
445
+ base.set(fp.srcFile, fileLines);
446
+ }
447
+ return base;
448
+ }
449
+
450
+ // src/core/split.ts
451
+ function expandItem(item) {
452
+ if (typeof item === "number") return [item];
453
+ const m = item.match(/^(\d+)-(\d+)$/);
454
+ if (!m) throw new Error(`Invalid change item: ${JSON.stringify(item)}`);
455
+ const start = parseInt(m[1]);
456
+ const end = parseInt(m[2]);
457
+ if (start > end) throw new Error(`Invalid range: ${item} (start > end)`);
458
+ const result = [];
459
+ for (let i = start; i <= end; i++) result.push(i);
460
+ return result;
461
+ }
462
+ function expandChanges(items) {
463
+ return items.flatMap(expandItem);
464
+ }
465
+ function indexChanges(patches) {
466
+ const result = [];
467
+ let idx = 0;
468
+ for (const fp of patches) {
469
+ if (fp.hunks.length === 0) continue;
470
+ for (const hunk of fp.hunks) {
471
+ let srcLine = hunk.srcStart;
472
+ let dstLine = hunk.dstStart;
473
+ for (const hl of hunk.lines) {
474
+ if (hl.type === "-") {
475
+ result.push({
476
+ index: idx++,
477
+ file: fp.srcFile,
478
+ type: "-",
479
+ content: hl.content,
480
+ lineNo: srcLine
481
+ });
482
+ srcLine++;
483
+ } else if (hl.type === "+") {
484
+ result.push({
485
+ index: idx++,
486
+ file: fp.dstFile,
487
+ type: "+",
488
+ content: hl.content,
489
+ lineNo: dstLine
490
+ });
491
+ dstLine++;
492
+ } else if (hl.type === " ") {
493
+ srcLine++;
494
+ dstLine++;
495
+ }
496
+ }
497
+ }
498
+ }
499
+ return result;
500
+ }
501
+ function formatIndexedChanges(changes) {
502
+ const lines = [];
503
+ let currentFile = "";
504
+ for (const c of changes) {
505
+ if (c.file !== currentFile) {
506
+ if (currentFile) lines.push("");
507
+ lines.push(`## ${c.file}`);
508
+ currentFile = c.file;
509
+ }
510
+ lines.push(` [${c.index}] ${c.type} L${c.lineNo}: ${c.content}`);
511
+ }
512
+ return lines.join("\n");
513
+ }
514
+ function validateMeta(meta, totalChanges) {
515
+ const errors = [];
516
+ const assigned = /* @__PURE__ */ new Set();
517
+ for (let g = 0; g < meta.groups.length; g++) {
518
+ const group = meta.groups[g];
519
+ if (!group.description) {
520
+ errors.push(`Group ${g + 1}: missing description`);
521
+ }
522
+ let expanded;
523
+ try {
524
+ expanded = expandChanges(group.changes);
525
+ } catch (e) {
526
+ errors.push(`Group ${g + 1}: ${e.message}`);
527
+ continue;
528
+ }
529
+ for (const idx of expanded) {
530
+ if (idx < 0 || idx >= totalChanges) {
531
+ errors.push(`Group ${g + 1}: index ${idx} out of range [0, ${totalChanges - 1}]`);
532
+ }
533
+ if (assigned.has(idx)) {
534
+ errors.push(`Group ${g + 1}: index ${idx} already assigned to another group`);
535
+ }
536
+ assigned.add(idx);
537
+ }
538
+ const groupChanges = new Set(expanded);
539
+ for (let c = 0; c < (group.draftComments?.length ?? 0); c++) {
540
+ const comment = group.draftComments[c];
541
+ if (!comment.body?.trim()) {
542
+ errors.push(`Group ${g + 1}: draft comment ${c + 1} is missing body`);
543
+ }
544
+ if (comment.change < 0 || comment.change >= totalChanges) {
545
+ errors.push(
546
+ `Group ${g + 1}: draft comment ${c + 1} change ${comment.change} out of range [0, ${totalChanges - 1}]`
547
+ );
548
+ continue;
549
+ }
550
+ if (!groupChanges.has(comment.change)) {
551
+ errors.push(
552
+ `Group ${g + 1}: draft comment ${c + 1} change ${comment.change} is not assigned to this group`
553
+ );
554
+ }
555
+ }
556
+ }
557
+ for (let i = 0; i < totalChanges; i++) {
558
+ if (!assigned.has(i)) {
559
+ errors.push(`Change ${i} is not assigned to any group`);
560
+ }
561
+ }
562
+ return errors;
563
+ }
564
+ function resolveSplitGroupMeta(meta, changes) {
565
+ return meta.groups.map((group, groupIndex) => ({
566
+ index: groupIndex,
567
+ description: group.description,
568
+ draftComments: (group.draftComments ?? []).map((comment, commentIndex) => {
569
+ const change = changes[comment.change];
570
+ return {
571
+ id: `g${groupIndex + 1}-draft${commentIndex + 1}`,
572
+ sub: groupIndex,
573
+ change: comment.change,
574
+ file: change.file,
575
+ line: change.lineNo,
576
+ side: change.type === "+" ? "additions" : "deletions",
577
+ body: comment.body.trim(),
578
+ source: "agent"
579
+ };
580
+ })
581
+ }));
582
+ }
583
+ function buildAlignments(patches) {
584
+ const result = [];
585
+ let changeIdx = 0;
586
+ for (const fp of patches) {
587
+ const isPureRename = fp.srcFile !== fp.dstFile && fp.hunks.length === 0;
588
+ if (fp.hunks.length === 0) {
589
+ result.push({
590
+ srcFile: fp.srcFile,
591
+ dstFile: fp.dstFile,
592
+ hunks: [],
593
+ isNew: fp.isNew,
594
+ isDelete: fp.isDelete,
595
+ isPureRename
596
+ });
597
+ continue;
598
+ }
599
+ const hunks = [];
600
+ for (const hunk of fp.hunks) {
601
+ const entries = [];
602
+ for (const hl of hunk.lines) {
603
+ if (hl.type === " ") {
604
+ entries.push({ kind: "context", content: hl.content });
605
+ } else if (hl.type === "-") {
606
+ entries.push({ kind: "delete", content: hl.content, changeIndex: changeIdx++ });
607
+ } else if (hl.type === "+") {
608
+ entries.push({ kind: "add", content: hl.content, changeIndex: changeIdx++ });
609
+ }
610
+ }
611
+ hunks.push({ srcStart: hunk.srcStart, srcCount: hunk.srcCount, entries });
612
+ }
613
+ result.push({
614
+ srcFile: fp.srcFile,
615
+ dstFile: fp.dstFile,
616
+ hunks,
617
+ isNew: fp.isNew,
618
+ isDelete: fp.isDelete,
619
+ isPureRename: false
620
+ });
621
+ }
622
+ return result;
623
+ }
624
+ function generateHunkForGroup(ha, groupOf, g) {
625
+ const diffLines = [];
626
+ for (const e of ha.entries) {
627
+ if (e.kind === "context") {
628
+ diffLines.push({ type: " ", content: e.content });
629
+ } else if (e.kind === "delete") {
630
+ const assignedGroup = groupOf.get(e.changeIndex) ?? 0;
631
+ if (assignedGroup === g) {
632
+ diffLines.push({ type: "-", content: e.content });
633
+ } else if (assignedGroup > g) {
634
+ diffLines.push({ type: " ", content: e.content });
635
+ }
636
+ } else if (e.kind === "add") {
637
+ const assignedGroup = groupOf.get(e.changeIndex) ?? 0;
638
+ if (assignedGroup === g) {
639
+ diffLines.push({ type: "+", content: e.content });
640
+ } else if (assignedGroup < g) {
641
+ diffLines.push({ type: " ", content: e.content });
642
+ }
643
+ }
644
+ }
645
+ const hasChanges = diffLines.some((d) => d.type !== " ");
646
+ if (!hasChanges) return null;
647
+ const lines = [];
648
+ for (const d of diffLines) {
649
+ lines.push(`${d.type}${d.content}`);
650
+ }
651
+ const CONTEXT = 3;
652
+ let trimStart = 0;
653
+ let trimEnd = 0;
654
+ for (let i = 0; i < lines.length; i++) {
655
+ if (lines[i].startsWith(" ")) trimStart++;
656
+ else break;
657
+ }
658
+ for (let i = lines.length - 1; i >= 0; i--) {
659
+ if (lines[i].startsWith(" ")) trimEnd++;
660
+ else break;
661
+ }
662
+ const leadTrim = Math.max(0, trimStart - CONTEXT);
663
+ const tailTrim = Math.max(0, trimEnd - CONTEXT);
664
+ const trimmed = lines.slice(leadTrim, lines.length - tailTrim || void 0);
665
+ const trimmedBeforeCount = trimmed.filter((l) => l.startsWith(" ") || l.startsWith("-")).length;
666
+ const trimmedAfterCount = trimmed.filter((l) => l.startsWith(" ") || l.startsWith("+")).length;
667
+ const hunkText = trimmed.join("\n");
668
+ return {
669
+ hunkText,
670
+ beforeCount: trimmedBeforeCount,
671
+ afterCount: trimmedAfterCount,
672
+ leadTrim
673
+ };
674
+ }
675
+ function computeBeforeStart(ha, fileHunks, hunkIndex, groupOf, g) {
676
+ let lineNo = ha.srcStart;
677
+ for (let h = 0; h < hunkIndex; h++) {
678
+ const priorHunk = fileHunks[h];
679
+ for (const e of priorHunk.entries) {
680
+ if (e.kind === "delete" && (groupOf.get(e.changeIndex) ?? 0) < g) {
681
+ lineNo--;
682
+ } else if (e.kind === "add" && (groupOf.get(e.changeIndex) ?? 0) < g) {
683
+ lineNo++;
684
+ }
685
+ }
686
+ }
687
+ return lineNo;
688
+ }
689
+ function generateSubPatches(originalText, meta) {
690
+ const patches = parsePatch(originalText);
691
+ const changes = indexChanges(patches);
692
+ const errors = validateMeta(meta, changes.length);
693
+ if (errors.length > 0) {
694
+ throw new Error(`Invalid split meta:
695
+ ${errors.join("\n")}`);
696
+ }
697
+ const groupOf = /* @__PURE__ */ new Map();
698
+ for (let g = 0; g < meta.groups.length; g++) {
699
+ for (const idx of expandChanges(meta.groups[g].changes)) {
700
+ groupOf.set(idx, g);
701
+ }
702
+ }
703
+ const alignments = buildAlignments(patches);
704
+ const fileInfo = alignments.map((fa) => {
705
+ const allAdds = fa.isNew ? fa.hunks.flatMap((h) => h.entries.filter((e) => e.kind === "add")) : [];
706
+ const allDeletes = fa.isDelete ? fa.hunks.flatMap((h) => h.entries.filter((e) => e.kind === "delete")) : [];
707
+ const firstAddGroup = allAdds.length > 0 ? Math.min(...allAdds.map((e) => groupOf.get(e.changeIndex) ?? 0)) : -1;
708
+ const lastDeleteGroup = allDeletes.length > 0 ? Math.max(...allDeletes.map((e) => groupOf.get(e.changeIndex) ?? 0)) : -1;
709
+ return { allAdds, allDeletes, firstAddGroup, lastDeleteGroup };
710
+ });
711
+ const subPatches = [];
712
+ for (let g = 0; g < meta.groups.length; g++) {
713
+ const parts = [];
714
+ for (let fi = 0; fi < alignments.length; fi++) {
715
+ const fa = alignments[fi];
716
+ const info = fileInfo[fi];
717
+ if (fa.isPureRename) {
718
+ if (g === 0) {
719
+ parts.push(`diff --git a/${fa.srcFile} b/${fa.dstFile}`);
720
+ parts.push("similarity index 100%");
721
+ parts.push(`rename from ${fa.srcFile}`);
722
+ parts.push(`rename to ${fa.dstFile}`);
723
+ }
724
+ continue;
725
+ }
726
+ const fileHunks = [];
727
+ let isFileNew = false;
728
+ let isFileDelete = false;
729
+ if (fa.isNew) {
730
+ const inThisGroup = info.allAdds.some((e) => (groupOf.get(e.changeIndex) ?? 0) === g);
731
+ if (!inThisGroup) continue;
732
+ if (g === info.firstAddGroup) isFileNew = true;
733
+ }
734
+ if (fa.isDelete) {
735
+ const inThisGroup = info.allDeletes.some((e) => (groupOf.get(e.changeIndex) ?? 0) === g);
736
+ if (!inThisGroup) continue;
737
+ if (g === info.lastDeleteGroup) isFileDelete = true;
738
+ }
739
+ for (let h = 0; h < fa.hunks.length; h++) {
740
+ const ha = fa.hunks[h];
741
+ const result = generateHunkForGroup(ha, groupOf, g);
742
+ if (!result) continue;
743
+ let beforeStart = computeBeforeStart(ha, fa.hunks, h, groupOf, g) + result.leadTrim;
744
+ if (fa.isNew && g > info.firstAddGroup) {
745
+ beforeStart += 1;
746
+ }
747
+ fileHunks.push(
748
+ `@@ -${beforeStart},${result.beforeCount} +${beforeStart},${result.afterCount} @@
749
+ ${result.hunkText}`
750
+ );
751
+ }
752
+ if (fileHunks.length === 0) continue;
753
+ const fixedHunks = fixHunkLineNumbers(fileHunks);
754
+ const srcPath = fa.srcFile;
755
+ const dstPath = fa.dstFile;
756
+ parts.push(`diff --git a/${srcPath} b/${dstPath}`);
757
+ if (isFileNew) {
758
+ parts.push("new file mode 100644");
759
+ parts.push("--- /dev/null");
760
+ parts.push(`+++ b/${dstPath}`);
761
+ } else if (isFileDelete) {
762
+ parts.push("deleted file mode 100644");
763
+ parts.push(`--- a/${srcPath}`);
764
+ parts.push("+++ /dev/null");
765
+ } else {
766
+ parts.push(`--- a/${srcPath}`);
767
+ parts.push(`+++ b/${dstPath}`);
768
+ }
769
+ parts.push(...fixedHunks);
770
+ }
771
+ subPatches.push(parts.join("\n") + "\n");
772
+ }
773
+ return subPatches;
774
+ }
775
+ function fixHunkLineNumbers(hunks) {
776
+ let dstOffset = 0;
777
+ const result = [];
778
+ for (const hunk of hunks) {
779
+ const lines = hunk.split("\n");
780
+ const header = lines[0];
781
+ const m = header.match(/^@@ -(\d+),(\d+) \+(\d+),(\d+) @@/);
782
+ if (!m) {
783
+ result.push(hunk);
784
+ continue;
785
+ }
786
+ const srcStart = parseInt(m[1]);
787
+ const srcCount = parseInt(m[2]);
788
+ const afterCount = parseInt(m[4]);
789
+ const dstStart = srcStart + dstOffset;
790
+ lines[0] = `@@ -${srcStart},${srcCount} +${dstStart},${afterCount} @@`;
791
+ result.push(lines.join("\n"));
792
+ dstOffset += afterCount - srcCount;
793
+ }
794
+ return result;
795
+ }
796
+
797
+ // src/cli/main.ts
798
+ var SUB_PATCH_SEPARATOR = "===SUB_PATCH===";
799
+ var args = process.argv.slice(2);
800
+ var subcommand = args[0];
801
+ if (wantsHelp(args)) {
802
+ printUsage();
803
+ process.exit(0);
804
+ }
805
+ if (!subcommand) {
806
+ printUsage();
807
+ process.exit(2);
808
+ }
809
+ switch (subcommand) {
810
+ case "index":
811
+ await cmdIndex(args.slice(1));
812
+ break;
813
+ case "split":
814
+ await cmdSplit(args.slice(1));
815
+ break;
816
+ case "render":
817
+ await cmdRender(args.slice(1));
818
+ break;
819
+ default:
820
+ console.error(`Unknown subcommand: ${subcommand}`);
821
+ printUsage();
822
+ process.exit(2);
823
+ }
824
+ function printUsage() {
825
+ console.error(`Usage:
826
+ reviewdeck index <patch> [-o <file>]
827
+ Generate a numbered change index from a PR diff for the LLM to group.
828
+
829
+ reviewdeck split <patch> <meta | -> [-o <dir>]
830
+ Generate and verify ordered sub-patches from the split metadata.
831
+ This proves the split composes back to the original diff.
832
+ Split metadata may also include draft review comments for render.
833
+
834
+ reviewdeck render [<dir> | -] [-p <port>]
835
+ Start the human review UI for the generated sub-patches.
836
+ Use this after "split" when the goal is to let a person review the stack.
837
+ It opens a browser and prints a submission JSON object to stdout.
838
+
839
+ reviewdeck render [<dir> | -] --html
840
+ Output a self-contained HTML artifact for human review instead of starting a server.
841
+
842
+ Examples:
843
+ gh pr diff 123 > pr.diff
844
+ reviewdeck index pr.diff > pr.index.txt
845
+ cat split.json | reviewdeck split pr.diff - -o output/
846
+ reviewdeck render output/
847
+ cat split.json | reviewdeck split pr.diff - | reviewdeck render - --html > review.html`);
848
+ }
849
+ function wantsHelp(args2) {
850
+ return args2.length > 0 && (args2[0] === "-h" || args2[0] === "--help" || args2[0] === "help");
851
+ }
852
+ function printIndexUsage() {
853
+ console.error(`Usage:
854
+ reviewdeck index <diff-file> [-o <output-file>]
855
+
856
+ Generate a numbered change index from a PR diff.
857
+ The index output is intended to be read by an LLM when producing split metadata.`);
858
+ }
859
+ function printSplitUsage() {
860
+ console.error(`Usage:
861
+ reviewdeck split <diff-file> <split-json | -> [-o <dir>]
862
+
863
+ Generate ordered sub-patches from split metadata and verify they compose
864
+ back to the original diff.
865
+
866
+ Split metadata can optionally include group-level "draftComments" so the
867
+ review UI can render agent findings inline for accept/reject.
868
+
869
+ After a successful split, continue with "reviewdeck render" when the goal
870
+ is to hand the proposed sub-patches to a human reviewer or collect comments.`);
871
+ }
872
+ function printRenderUsage() {
873
+ console.error(`Usage:
874
+ reviewdeck render [<dir> | -] [-p <port>]
875
+ reviewdeck render [<dir> | -] --html
876
+
877
+ Prepare generated sub-patches for human review.
878
+
879
+ - Input can be a directory from "split -o" or stdin from "split"
880
+ - Server mode opens a browser and waits for human review submission
881
+ - Submission JSON includes final comments plus agent-draft accept/reject status
882
+ - HTML mode emits a self-contained review file for sharing or manual review
883
+
884
+ Examples:
885
+ reviewdeck render output/
886
+ cat split.json | reviewdeck split pr.diff - | reviewdeck render -
887
+ cat split.json | reviewdeck split pr.diff - | reviewdeck render - --html > review.html`);
888
+ }
889
+ function readStdin() {
890
+ return new Promise((resolve2, reject) => {
891
+ const chunks = [];
892
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
893
+ process.stdin.on("end", () => resolve2(Buffer.concat(chunks).toString("utf-8")));
894
+ process.stdin.on("error", reject);
895
+ });
896
+ }
897
+ async function readFileOrStdin(path) {
898
+ return path === "-" ? readStdin() : readFile2(path, "utf-8");
899
+ }
900
+ function writeSubs(subs, groups, outDir) {
901
+ if (outDir) {
902
+ mkdirSync(outDir, { recursive: true });
903
+ for (let i = 0; i < subs.length; i++) {
904
+ const outPath = `${outDir}/sub${i + 1}.diff`;
905
+ writeFileSync(outPath, subs[i]);
906
+ const lineCount = subs[i].split("\n").length;
907
+ console.error(` Wrote ${outPath} (${lineCount} lines)`);
908
+ }
909
+ const meta = groups.map((group) => ({
910
+ index: group.index,
911
+ description: group.description,
912
+ draftComments: group.draftComments
913
+ }));
914
+ writeFileSync(`${outDir}/meta.json`, JSON.stringify(meta, null, 2) + "\n");
915
+ console.error(` Wrote ${outDir}/meta.json`);
916
+ } else {
917
+ for (let i = 0; i < subs.length; i++) {
918
+ const meta = JSON.stringify(groups[i]);
919
+ process.stdout.write(`${i > 0 ? "\n" : ""}${SUB_PATCH_SEPARATOR} ${meta}
920
+ `);
921
+ process.stdout.write(subs[i]);
922
+ }
923
+ }
924
+ }
925
+ async function cmdIndex(args2) {
926
+ if (wantsHelp(args2)) {
927
+ printIndexUsage();
928
+ return;
929
+ }
930
+ const { values, positionals } = parseArgs({
931
+ args: args2,
932
+ options: { output: { type: "string", short: "o" } },
933
+ allowPositionals: true
934
+ });
935
+ const diffFile = positionals[0];
936
+ if (!diffFile) {
937
+ printIndexUsage();
938
+ process.exit(1);
939
+ }
940
+ const text = await readFile2(diffFile, "utf-8");
941
+ const patches = parsePatch(text);
942
+ const changes = indexChanges(patches);
943
+ const output = formatIndexedChanges(changes) + `
944
+
945
+ Total: ${changes.length} change lines
946
+ `;
947
+ if (values.output) {
948
+ writeFileSync(values.output, output);
949
+ console.error(`Wrote ${values.output} (${changes.length} changes)`);
950
+ } else {
951
+ process.stdout.write(output);
952
+ }
953
+ }
954
+ async function cmdSplit(args2) {
955
+ if (wantsHelp(args2)) {
956
+ printSplitUsage();
957
+ return;
958
+ }
959
+ const { values, positionals } = parseArgs({
960
+ args: args2,
961
+ options: { output: { type: "string", short: "o" } },
962
+ allowPositionals: true
963
+ });
964
+ const [diffFile, splitFile] = positionals;
965
+ if (!diffFile || !splitFile) {
966
+ printSplitUsage();
967
+ process.exit(1);
968
+ }
969
+ const diffText = readFileSync(diffFile, "utf-8");
970
+ let meta;
971
+ const metaRaw = await readFileOrStdin(splitFile);
972
+ try {
973
+ meta = JSON.parse(metaRaw);
974
+ } catch {
975
+ console.error(`ERROR: Invalid JSON in split metadata.
976
+ The input must be a valid JSON object with this structure:
977
+ {
978
+ "groups": [
979
+ { "description": "...", "changes": [0, 1, "2-5"] }
980
+ ]
981
+ }
982
+
983
+ Received: ${metaRaw.slice(0, 200)}${metaRaw.length > 200 ? "..." : ""}`);
984
+ process.exit(1);
985
+ }
986
+ const patches = parsePatch(diffText);
987
+ const changes = indexChanges(patches);
988
+ const errors = validateMeta(meta, changes.length);
989
+ if (errors.length > 0) {
990
+ console.error(`ERROR: Invalid split metadata (${errors.length} issue${errors.length > 1 ? "s" : ""}):
991
+ ${errors.map((e) => ` - ${e}`).join("\n")}
992
+
993
+ Total change indices in this diff: 0-${changes.length - 1} (${changes.length} changes).
994
+ Every index must appear in exactly one group. Fix the meta JSON and retry.`);
995
+ process.exit(1);
996
+ }
997
+ console.error(`Split: ${meta.groups.length} groups, ${changes.length} changes`);
998
+ for (let i = 0; i < meta.groups.length; i++) {
999
+ const g = meta.groups[i];
1000
+ console.error(` ${i + 1}. ${g.description} (${g.changes.length} items)`);
1001
+ }
1002
+ const subs = generateSubPatches(diffText, meta);
1003
+ const base = reconstructBase(patches);
1004
+ const expected = applyPatch(base, patches);
1005
+ let state = base;
1006
+ for (let i = 0; i < subs.length; i++) {
1007
+ try {
1008
+ state = applyPatch(state, parsePatch(subs[i]));
1009
+ } catch (e) {
1010
+ console.error(`ERROR: Sub-patch #${i + 1} ("${meta.groups[i].description}") failed to apply: ${e.message}
1011
+
1012
+ This usually means the changes in group ${i + 1} conflict with earlier groups.
1013
+ Check that the change indices in this group are correct and don't depend on changes in later groups.`);
1014
+ process.exit(1);
1015
+ }
1016
+ }
1017
+ const allFiles = [.../* @__PURE__ */ new Set([...expected.keys(), ...state.keys()])].sort();
1018
+ const mismatches = [];
1019
+ for (const f of allFiles) {
1020
+ const exp = expected.get(f) ?? [];
1021
+ const act = state.get(f) ?? [];
1022
+ if (exp.length !== act.length || !exp.every((l, i) => l === act[i])) {
1023
+ mismatches.push(f);
1024
+ }
1025
+ }
1026
+ if (mismatches.length > 0) {
1027
+ console.error(`ERROR: Composition mismatch \u2014 sub-patches do NOT reproduce the original diff.
1028
+ ${mismatches.length} file(s) differ after applying all sub-patches sequentially:
1029
+ ${mismatches.map((f) => ` - ${f}`).join("\n")}
1030
+
1031
+ This is likely a bug in the splitting algorithm. Please report it.`);
1032
+ process.exit(1);
1033
+ }
1034
+ console.error("OK: Verified \u2014 sub-patches compose to equal the original diff.");
1035
+ const groupMeta = resolveSplitGroupMeta(meta, changes);
1036
+ writeSubs(subs, groupMeta, values.output);
1037
+ if (values.output) {
1038
+ console.error(`Next: run "reviewdeck render ${values.output}" to review these sub-patches.`);
1039
+ } else {
1040
+ console.error('Next: pipe this output into "reviewdeck render -" to launch review.');
1041
+ }
1042
+ }
1043
+ async function cmdRender(args2) {
1044
+ if (wantsHelp(args2)) {
1045
+ printRenderUsage();
1046
+ return;
1047
+ }
1048
+ const { values, positionals } = parseArgs({
1049
+ args: args2,
1050
+ options: {
1051
+ port: { type: "string", short: "p" },
1052
+ html: { type: "boolean" }
1053
+ },
1054
+ allowPositionals: true
1055
+ });
1056
+ const {
1057
+ startReviewServer: startReviewServer2,
1058
+ generateStaticHtml: generateStaticHtml2,
1059
+ parseSubPatchesFromStdin: parseSubPatchesFromStdin2,
1060
+ parseSubPatchesFromDir: parseSubPatchesFromDir2
1061
+ } = await Promise.resolve().then(() => (init_render(), render_exports));
1062
+ const source = positionals[0] ?? "-";
1063
+ let subPatches;
1064
+ if (source === "-") {
1065
+ const input = await readStdin();
1066
+ subPatches = parseSubPatchesFromStdin2(input, SUB_PATCH_SEPARATOR);
1067
+ } else {
1068
+ subPatches = await parseSubPatchesFromDir2(source);
1069
+ }
1070
+ if (subPatches.length === 0) {
1071
+ console.error("ERROR: No sub-patches to review.");
1072
+ process.exit(1);
1073
+ }
1074
+ console.error(`Loaded ${subPatches.length} sub-patches for review.`);
1075
+ if (values.html) {
1076
+ const html = await generateStaticHtml2(subPatches);
1077
+ process.stdout.write(html);
1078
+ return;
1079
+ }
1080
+ const port = values.port ? parseInt(values.port, 10) : void 0;
1081
+ const submission = await startReviewServer2(subPatches, { port });
1082
+ process.stdout.write(JSON.stringify(submission, null, 2));
1083
+ process.stdout.write("\n");
1084
+ }